early-access version 3032
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| yuzu emulator early access | ||||
| ============= | ||||
|  | ||||
| This is the source code for early-access 3031. | ||||
| This is the source code for early-access 3032. | ||||
|  | ||||
| ## Legal Notice | ||||
|  | ||||
|   | ||||
| @@ -230,7 +230,9 @@ std::vector<std::string> ListSDLSinkDevices(bool capture) { | ||||
|  | ||||
|     const int device_count = SDL_GetNumAudioDevices(capture); | ||||
|     for (int i = 0; i < device_count; ++i) { | ||||
|         device_list.emplace_back(SDL_GetAudioDeviceName(i, 0)); | ||||
|         if (const char* name = SDL_GetAudioDeviceName(i, capture)) { | ||||
|             device_list.emplace_back(name); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return device_list; | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/uuid.h" | ||||
| #include "core/core.h" | ||||
| #include "core/file_sys/savedata_factory.h" | ||||
| #include "core/file_sys/vfs.h" | ||||
| @@ -59,6 +60,36 @@ bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataA | ||||
|             attr.title_id == 0 && attr.save_id == 0); | ||||
| } | ||||
|  | ||||
| std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id, | ||||
|                                   u128 user_id) { | ||||
|     // Only detect nand user saves. | ||||
|     const auto space_id_path = [space_id]() -> std::string_view { | ||||
|         switch (space_id) { | ||||
|         case SaveDataSpaceId::NandUser: | ||||
|             return "/user/save"; | ||||
|         default: | ||||
|             return ""; | ||||
|         } | ||||
|     }(); | ||||
|  | ||||
|     if (space_id_path.empty()) { | ||||
|         return ""; | ||||
|     } | ||||
|  | ||||
|     Common::UUID uuid; | ||||
|     std::memcpy(uuid.uuid.data(), user_id.data(), sizeof(Common::UUID)); | ||||
|  | ||||
|     // Only detect account/device saves from the future location. | ||||
|     switch (type) { | ||||
|     case SaveDataType::SaveData: | ||||
|         return fmt::format("{}/account/{}/{:016X}/1", space_id_path, uuid.RawString(), title_id); | ||||
|     case SaveDataType::DeviceSaveData: | ||||
|         return fmt::format("{}/device/{:016X}/1", space_id_path, title_id); | ||||
|     default: | ||||
|         return ""; | ||||
|     } | ||||
| } | ||||
|  | ||||
| } // Anonymous namespace | ||||
|  | ||||
| std::string SaveDataAttribute::DebugInfo() const { | ||||
| @@ -82,7 +113,7 @@ ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space, | ||||
|     PrintSaveDataAttributeWarnings(meta); | ||||
|  | ||||
|     const auto save_directory = | ||||
|         GetFullPath(system, space, meta.type, meta.title_id, meta.user_id, meta.save_id); | ||||
|         GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); | ||||
|  | ||||
|     auto out = dir->CreateDirectoryRelative(save_directory); | ||||
|  | ||||
| @@ -99,7 +130,7 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, | ||||
|                                             const SaveDataAttribute& meta) const { | ||||
|  | ||||
|     const auto save_directory = | ||||
|         GetFullPath(system, space, meta.type, meta.title_id, meta.user_id, meta.save_id); | ||||
|         GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); | ||||
|  | ||||
|     auto out = dir->GetDirectoryRelative(save_directory); | ||||
|  | ||||
| @@ -134,9 +165,9 @@ std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId space, | ||||
|                                          SaveDataType type, u64 title_id, u128 user_id, | ||||
|                                          u64 save_id) { | ||||
| std::string SaveDataFactory::GetFullPath(Core::System& system, VirtualDir dir, | ||||
|                                          SaveDataSpaceId space, SaveDataType type, u64 title_id, | ||||
|                                          u128 user_id, u64 save_id) { | ||||
|     // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should | ||||
|     // be interpreted as the title id of the current process. | ||||
|     if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { | ||||
| @@ -145,6 +176,17 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId s | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // For compat with a future impl. | ||||
|     if (std::string future_path = | ||||
|             GetFutureSaveDataPath(space, type, title_id & ~(0xFFULL), user_id); | ||||
|         !future_path.empty()) { | ||||
|         // Check if this location exists, and prefer it over the old. | ||||
|         if (const auto future_dir = dir->GetDirectoryRelative(future_path); future_dir != nullptr) { | ||||
|             LOG_INFO(Service_FS, "Using save at new location: {}", future_path); | ||||
|             return future_path; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     std::string out = GetSaveDataSpaceIdPath(space); | ||||
|  | ||||
|     switch (type) { | ||||
| @@ -167,7 +209,8 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId s | ||||
|  | ||||
| SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, | ||||
|                                                u128 user_id) const { | ||||
|     const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); | ||||
|     const auto path = | ||||
|         GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); | ||||
|     const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); | ||||
|  | ||||
|     const auto size_file = relative_dir->GetFile(SAVE_DATA_SIZE_FILENAME); | ||||
| @@ -185,7 +228,8 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, | ||||
|  | ||||
| void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, | ||||
|                                         SaveDataSize new_value) const { | ||||
|     const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); | ||||
|     const auto path = | ||||
|         GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); | ||||
|     const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); | ||||
|  | ||||
|     const auto size_file = relative_dir->CreateFile(SAVE_DATA_SIZE_FILENAME); | ||||
|   | ||||
| @@ -95,8 +95,8 @@ public: | ||||
|     VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; | ||||
|  | ||||
|     static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); | ||||
|     static std::string GetFullPath(Core::System& system, SaveDataSpaceId space, SaveDataType type, | ||||
|                                    u64 title_id, u128 user_id, u64 save_id); | ||||
|     static std::string GetFullPath(Core::System& system, VirtualDir dir, SaveDataSpaceId space, | ||||
|                                    SaveDataType type, u64 title_id, u128 user_id, u64 save_id); | ||||
|  | ||||
|     SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const; | ||||
|     void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, | ||||
|   | ||||
| @@ -14,7 +14,7 @@ enum class CameraAmbientNoiseLevel : u32 { | ||||
|     Low, | ||||
|     Medium, | ||||
|     High, | ||||
|     Unkown3, // This level can't be reached | ||||
|     Unknown3, // This level can't be reached | ||||
| }; | ||||
|  | ||||
| // This is nn::irsensor::CameraLightTarget | ||||
| @@ -75,9 +75,9 @@ enum class IrCameraStatus : u32 { | ||||
| enum class IrCameraInternalStatus : u32 { | ||||
|     Stopped, | ||||
|     FirmwareUpdateNeeded, | ||||
|     Unkown2, | ||||
|     Unkown3, | ||||
|     Unkown4, | ||||
|     Unknown2, | ||||
|     Unknown3, | ||||
|     Unknown4, | ||||
|     FirmwareVersionRequested, | ||||
|     FirmwareVersionIsInvalid, | ||||
|     Ready, | ||||
| @@ -121,20 +121,20 @@ enum class IrSensorFunctionLevel : u8 { | ||||
|  | ||||
| // This is nn::irsensor::MomentProcessorPreprocess | ||||
| enum class MomentProcessorPreprocess : u32 { | ||||
|     Unkown0, | ||||
|     Unkown1, | ||||
|     Unknown0, | ||||
|     Unknown1, | ||||
| }; | ||||
|  | ||||
| // This is nn::irsensor::PackedMomentProcessorPreprocess | ||||
| enum class PackedMomentProcessorPreprocess : u8 { | ||||
|     Unkown0, | ||||
|     Unkown1, | ||||
|     Unknown0, | ||||
|     Unknown1, | ||||
| }; | ||||
|  | ||||
| // This is nn::irsensor::PointingStatus | ||||
| enum class PointingStatus : u32 { | ||||
|     Unkown0, | ||||
|     Unkown1, | ||||
|     Unknown0, | ||||
|     Unknown1, | ||||
| }; | ||||
|  | ||||
| struct IrsRect { | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/spin_lock.h" | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| @@ -36,28 +37,30 @@ public: | ||||
|     } | ||||
|  | ||||
|     void* Allocate() { | ||||
|         Node* ret = m_head.load(); | ||||
|         m_lock.lock(); | ||||
|  | ||||
|         do { | ||||
|             if (ret == nullptr) { | ||||
|                 break; | ||||
|             } | ||||
|         } while (!m_head.compare_exchange_weak(ret, ret->next)); | ||||
|         Node* ret = m_head; | ||||
|         if (ret != nullptr) [[likely]] { | ||||
|             m_head = ret->next; | ||||
|         } | ||||
|  | ||||
|         m_lock.unlock(); | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     void Free(void* obj) { | ||||
|         Node* node = static_cast<Node*>(obj); | ||||
|         m_lock.lock(); | ||||
|  | ||||
|         Node* cur_head = m_head.load(); | ||||
|         do { | ||||
|             node->next = cur_head; | ||||
|         } while (!m_head.compare_exchange_weak(cur_head, node)); | ||||
|         Node* node = static_cast<Node*>(obj); | ||||
|         node->next = m_head; | ||||
|         m_head = node; | ||||
|  | ||||
|         m_lock.unlock(); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     std::atomic<Node*> m_head{}; | ||||
|     Common::SpinLock m_lock; | ||||
| }; | ||||
|  | ||||
| } // namespace impl | ||||
|   | ||||
| @@ -2118,7 +2118,7 @@ void Hid::WritePalmaWaveEntry(Kernel::HLERequestContext& ctx) { | ||||
|     ASSERT_MSG(t_mem->GetSize() == 0x3000, "t_mem has incorrect size"); | ||||
|  | ||||
|     LOG_WARNING(Service_HID, | ||||
|                 "(STUBBED) called, connection_handle={}, wave_set={}, unkown={}, " | ||||
|                 "(STUBBED) called, connection_handle={}, wave_set={}, unknown={}, " | ||||
|                 "t_mem_handle=0x{:08X}, t_mem_size={}, size={}", | ||||
|                 connection_handle.npad_id, wave_set, unknown, t_mem_handle, t_mem_size, size); | ||||
|  | ||||
|   | ||||
| @@ -37,10 +37,10 @@ private: | ||||
|         u8 pointing_status; | ||||
|         INSERT_PADDING_BYTES(3); | ||||
|         u32 unknown; | ||||
|         float unkown_float1; | ||||
|         float unknown_float1; | ||||
|         float position_x; | ||||
|         float position_y; | ||||
|         float unkown_float2; | ||||
|         float unknown_float2; | ||||
|         Core::IrSensor::IrsRect window_of_interest; | ||||
|     }; | ||||
|     static_assert(sizeof(PointingProcessorMarkerData) == 0x20, | ||||
|   | ||||
| @@ -272,14 +272,14 @@ IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b | ||||
| void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& runtime_info) { | ||||
|     auto& stores = program.info.stores; | ||||
|     if (stores.Legacy()) { | ||||
|         std::queue<IR::Attribute> ununsed_output_generics{}; | ||||
|         std::queue<IR::Attribute> unused_output_generics{}; | ||||
|         for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { | ||||
|             if (!stores.Generic(index)) { | ||||
|                 ununsed_output_generics.push(IR::Attribute::Generic0X + index * 4); | ||||
|                 unused_output_generics.push(IR::Attribute::Generic0X + index * 4); | ||||
|             } | ||||
|         } | ||||
|         program.info.legacy_stores_mapping = | ||||
|             GenerateLegacyToGenericMappings(stores, ununsed_output_generics, {}); | ||||
|             GenerateLegacyToGenericMappings(stores, unused_output_generics, {}); | ||||
|         for (IR::Block* const block : program.post_order_blocks) { | ||||
|             for (IR::Inst& inst : block->Instructions()) { | ||||
|                 switch (inst.GetOpcode()) { | ||||
| @@ -300,16 +300,16 @@ void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& run | ||||
|  | ||||
|     auto& loads = program.info.loads; | ||||
|     if (loads.Legacy()) { | ||||
|         std::queue<IR::Attribute> ununsed_input_generics{}; | ||||
|         std::queue<IR::Attribute> unused_input_generics{}; | ||||
|         for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { | ||||
|             const AttributeType input_type{runtime_info.generic_input_types[index]}; | ||||
|             if (!runtime_info.previous_stage_stores.Generic(index) || !loads.Generic(index) || | ||||
|                 input_type == AttributeType::Disabled) { | ||||
|                 ununsed_input_generics.push(IR::Attribute::Generic0X + index * 4); | ||||
|                 unused_input_generics.push(IR::Attribute::Generic0X + index * 4); | ||||
|             } | ||||
|         } | ||||
|         auto mappings = GenerateLegacyToGenericMappings( | ||||
|             loads, ununsed_input_generics, runtime_info.previous_stage_legacy_stores_mapping); | ||||
|             loads, unused_input_generics, runtime_info.previous_stage_legacy_stores_mapping); | ||||
|         for (IR::Block* const block : program.post_order_blocks) { | ||||
|             for (IR::Inst& inst : block->Instructions()) { | ||||
|                 switch (inst.GetOpcode()) { | ||||
|   | ||||
| @@ -18,7 +18,7 @@ class DescriptorTable { | ||||
| public: | ||||
|     explicit DescriptorTable(Tegra::MemoryManager& gpu_memory_) : gpu_memory{gpu_memory_} {} | ||||
|  | ||||
|     [[nodiscard]] bool Synchornize(GPUVAddr gpu_addr, u32 limit) { | ||||
|     [[nodiscard]] bool Synchronize(GPUVAddr gpu_addr, u32 limit) { | ||||
|         [[likely]] if (current_gpu_addr == gpu_addr && current_limit == limit) { | ||||
|             return false; | ||||
|         } | ||||
|   | ||||
| @@ -193,11 +193,11 @@ void TextureCache<P>::SynchronizeGraphicsDescriptors() { | ||||
|     const bool linked_tsc = maxwell3d->regs.sampler_binding == SamplerBinding::ViaHeaderBinding; | ||||
|     const u32 tic_limit = maxwell3d->regs.tex_header.limit; | ||||
|     const u32 tsc_limit = linked_tsc ? tic_limit : maxwell3d->regs.tex_sampler.limit; | ||||
|     if (channel_state->graphics_sampler_table.Synchornize(maxwell3d->regs.tex_sampler.Address(), | ||||
|     if (channel_state->graphics_sampler_table.Synchronize(maxwell3d->regs.tex_sampler.Address(), | ||||
|                                                           tsc_limit)) { | ||||
|         channel_state->graphics_sampler_ids.resize(tsc_limit + 1, CORRUPT_ID); | ||||
|     } | ||||
|     if (channel_state->graphics_image_table.Synchornize(maxwell3d->regs.tex_header.Address(), | ||||
|     if (channel_state->graphics_image_table.Synchronize(maxwell3d->regs.tex_header.Address(), | ||||
|                                                         tic_limit)) { | ||||
|         channel_state->graphics_image_view_ids.resize(tic_limit + 1, CORRUPT_ID); | ||||
|     } | ||||
| @@ -209,10 +209,10 @@ void TextureCache<P>::SynchronizeComputeDescriptors() { | ||||
|     const u32 tic_limit = kepler_compute->regs.tic.limit; | ||||
|     const u32 tsc_limit = linked_tsc ? tic_limit : kepler_compute->regs.tsc.limit; | ||||
|     const GPUVAddr tsc_gpu_addr = kepler_compute->regs.tsc.Address(); | ||||
|     if (channel_state->compute_sampler_table.Synchornize(tsc_gpu_addr, tsc_limit)) { | ||||
|     if (channel_state->compute_sampler_table.Synchronize(tsc_gpu_addr, tsc_limit)) { | ||||
|         channel_state->compute_sampler_ids.resize(tsc_limit + 1, CORRUPT_ID); | ||||
|     } | ||||
|     if (channel_state->compute_image_table.Synchornize(kepler_compute->regs.tic.Address(), | ||||
|     if (channel_state->compute_image_table.Synchronize(kepler_compute->regs.tic.Address(), | ||||
|                                                        tic_limit)) { | ||||
|         channel_state->compute_image_view_ids.resize(tic_limit + 1, CORRUPT_ID); | ||||
|     } | ||||
|   | ||||
| @@ -1895,6 +1895,8 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target | ||||
|     case GameListOpenTarget::SaveData: { | ||||
|         open_target = tr("Save Data"); | ||||
|         const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir); | ||||
|         auto vfs_nand_dir = | ||||
|             vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); | ||||
|  | ||||
|         if (has_user_save) { | ||||
|             // User save data | ||||
| @@ -1921,15 +1923,15 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target | ||||
|             ASSERT(user_id); | ||||
|  | ||||
|             const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( | ||||
|                 *system, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, | ||||
|                 program_id, user_id->AsU128(), 0); | ||||
|                 *system, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, | ||||
|                 FileSys::SaveDataType::SaveData, program_id, user_id->AsU128(), 0); | ||||
|  | ||||
|             path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); | ||||
|         } else { | ||||
|             // Device save data | ||||
|             const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath( | ||||
|                 *system, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, | ||||
|                 program_id, {}, 0); | ||||
|                 *system, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, | ||||
|                 FileSys::SaveDataType::SaveData, program_id, {}, 0); | ||||
|  | ||||
|             path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path); | ||||
|         } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user