diff options
Diffstat (limited to 'src')
159 files changed, 2948 insertions, 1068 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6c99dd5e2..9aea4af87 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt | |||
| @@ -18,6 +18,9 @@ if (MSVC) | |||
| 18 | # Avoid windows.h from including some usually unused libs like winsocks.h, since this might cause some redefinition errors. | 18 | # Avoid windows.h from including some usually unused libs like winsocks.h, since this might cause some redefinition errors. |
| 19 | add_definitions(-DWIN32_LEAN_AND_MEAN) | 19 | add_definitions(-DWIN32_LEAN_AND_MEAN) |
| 20 | 20 | ||
| 21 | # Ensure that projects build with Unicode support. | ||
| 22 | add_definitions(-DUNICODE -D_UNICODE) | ||
| 23 | |||
| 21 | # /W3 - Level 3 warnings | 24 | # /W3 - Level 3 warnings |
| 22 | # /MP - Multi-threaded compilation | 25 | # /MP - Multi-threaded compilation |
| 23 | # /Zi - Output debugging information | 26 | # /Zi - Output debugging information |
diff --git a/src/common/lz4_compression.h b/src/common/lz4_compression.h index fe2231a6c..4c16f6e03 100644 --- a/src/common/lz4_compression.h +++ b/src/common/lz4_compression.h | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #pragma once | ||
| 6 | |||
| 5 | #include <vector> | 7 | #include <vector> |
| 6 | 8 | ||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
diff --git a/src/common/zstd_compression.h b/src/common/zstd_compression.h index e0a64b035..e9de941c8 100644 --- a/src/common/zstd_compression.h +++ b/src/common/zstd_compression.h | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #pragma once | ||
| 6 | |||
| 5 | #include <vector> | 7 | #include <vector> |
| 6 | 8 | ||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c59107102..2ace866ee 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -88,6 +88,10 @@ add_library(core STATIC | |||
| 88 | file_sys/vfs_vector.h | 88 | file_sys/vfs_vector.h |
| 89 | file_sys/xts_archive.cpp | 89 | file_sys/xts_archive.cpp |
| 90 | file_sys/xts_archive.h | 90 | file_sys/xts_archive.h |
| 91 | frontend/applets/error.cpp | ||
| 92 | frontend/applets/error.h | ||
| 93 | frontend/applets/general_frontend.cpp | ||
| 94 | frontend/applets/general_frontend.h | ||
| 91 | frontend/applets/profile_select.cpp | 95 | frontend/applets/profile_select.cpp |
| 92 | frontend/applets/profile_select.h | 96 | frontend/applets/profile_select.h |
| 93 | frontend/applets/software_keyboard.cpp | 97 | frontend/applets/software_keyboard.cpp |
| @@ -177,12 +181,14 @@ add_library(core STATIC | |||
| 177 | hle/service/am/applet_oe.h | 181 | hle/service/am/applet_oe.h |
| 178 | hle/service/am/applets/applets.cpp | 182 | hle/service/am/applets/applets.cpp |
| 179 | hle/service/am/applets/applets.h | 183 | hle/service/am/applets/applets.h |
| 184 | hle/service/am/applets/error.cpp | ||
| 185 | hle/service/am/applets/error.h | ||
| 186 | hle/service/am/applets/general_backend.cpp | ||
| 187 | hle/service/am/applets/general_backend.h | ||
| 180 | hle/service/am/applets/profile_select.cpp | 188 | hle/service/am/applets/profile_select.cpp |
| 181 | hle/service/am/applets/profile_select.h | 189 | hle/service/am/applets/profile_select.h |
| 182 | hle/service/am/applets/software_keyboard.cpp | 190 | hle/service/am/applets/software_keyboard.cpp |
| 183 | hle/service/am/applets/software_keyboard.h | 191 | hle/service/am/applets/software_keyboard.h |
| 184 | hle/service/am/applets/stub_applet.cpp | ||
| 185 | hle/service/am/applets/stub_applet.h | ||
| 186 | hle/service/am/applets/web_browser.cpp | 192 | hle/service/am/applets/web_browser.cpp |
| 187 | hle/service/am/applets/web_browser.h | 193 | hle/service/am/applets/web_browser.h |
| 188 | hle/service/am/idle.cpp | 194 | hle/service/am/idle.cpp |
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 4dfd41b43..978b1518f 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -7,6 +7,10 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | 9 | ||
| 10 | namespace Common { | ||
| 11 | struct PageTable; | ||
| 12 | } | ||
| 13 | |||
| 10 | namespace Kernel { | 14 | namespace Kernel { |
| 11 | enum class VMAPermission : u8; | 15 | enum class VMAPermission : u8; |
| 12 | } | 16 | } |
| @@ -49,8 +53,14 @@ public: | |||
| 49 | /// Clear all instruction cache | 53 | /// Clear all instruction cache |
| 50 | virtual void ClearInstructionCache() = 0; | 54 | virtual void ClearInstructionCache() = 0; |
| 51 | 55 | ||
| 52 | /// Notify CPU emulation that page tables have changed | 56 | /// Notifies CPU emulation that the current page table has changed. |
| 53 | virtual void PageTableChanged() = 0; | 57 | /// |
| 58 | /// @param new_page_table The new page table. | ||
| 59 | /// @param new_address_space_size_in_bits The new usable size of the address space in bits. | ||
| 60 | /// This can be either 32, 36, or 39 on official software. | ||
| 61 | /// | ||
| 62 | virtual void PageTableChanged(Common::PageTable& new_page_table, | ||
| 63 | std::size_t new_address_space_size_in_bits) = 0; | ||
| 54 | 64 | ||
| 55 | /** | 65 | /** |
| 56 | * Set the Program Counter to an address | 66 | * Set the Program Counter to an address |
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index dc96e35d5..44307fa19 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | #include "core/core_timing.h" | 14 | #include "core/core_timing.h" |
| 15 | #include "core/core_timing_util.h" | 15 | #include "core/core_timing_util.h" |
| 16 | #include "core/gdbstub/gdbstub.h" | 16 | #include "core/gdbstub/gdbstub.h" |
| 17 | #include "core/hle/kernel/kernel.h" | ||
| 18 | #include "core/hle/kernel/process.h" | 17 | #include "core/hle/kernel/process.h" |
| 19 | #include "core/hle/kernel/svc.h" | 18 | #include "core/hle/kernel/svc.h" |
| 20 | #include "core/hle/kernel/vm_manager.h" | 19 | #include "core/hle/kernel/vm_manager.h" |
| @@ -129,18 +128,16 @@ public: | |||
| 129 | u64 tpidr_el0 = 0; | 128 | u64 tpidr_el0 = 0; |
| 130 | }; | 129 | }; |
| 131 | 130 | ||
| 132 | std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { | 131 | std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit(Common::PageTable& page_table, |
| 133 | auto* current_process = system.Kernel().CurrentProcess(); | 132 | std::size_t address_space_bits) const { |
| 134 | auto** const page_table = current_process->VMManager().page_table.pointers.data(); | ||
| 135 | |||
| 136 | Dynarmic::A64::UserConfig config; | 133 | Dynarmic::A64::UserConfig config; |
| 137 | 134 | ||
| 138 | // Callbacks | 135 | // Callbacks |
| 139 | config.callbacks = cb.get(); | 136 | config.callbacks = cb.get(); |
| 140 | 137 | ||
| 141 | // Memory | 138 | // Memory |
| 142 | config.page_table = reinterpret_cast<void**>(page_table); | 139 | config.page_table = reinterpret_cast<void**>(page_table.pointers.data()); |
| 143 | config.page_table_address_space_bits = current_process->VMManager().GetAddressSpaceWidth(); | 140 | config.page_table_address_space_bits = address_space_bits; |
| 144 | config.silently_mirror_page_table = false; | 141 | config.silently_mirror_page_table = false; |
| 145 | 142 | ||
| 146 | // Multi-process state | 143 | // Multi-process state |
| @@ -176,12 +173,7 @@ ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, | |||
| 176 | std::size_t core_index) | 173 | std::size_t core_index) |
| 177 | : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system}, | 174 | : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system}, |
| 178 | core_index{core_index}, system{system}, | 175 | core_index{core_index}, system{system}, |
| 179 | exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} { | 176 | exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} |
| 180 | ThreadContext ctx{}; | ||
| 181 | inner_unicorn.SaveContext(ctx); | ||
| 182 | PageTableChanged(); | ||
| 183 | LoadContext(ctx); | ||
| 184 | } | ||
| 185 | 177 | ||
| 186 | ARM_Dynarmic::~ARM_Dynarmic() = default; | 178 | ARM_Dynarmic::~ARM_Dynarmic() = default; |
| 187 | 179 | ||
| @@ -276,8 +268,9 @@ void ARM_Dynarmic::ClearExclusiveState() { | |||
| 276 | jit->ClearExclusiveState(); | 268 | jit->ClearExclusiveState(); |
| 277 | } | 269 | } |
| 278 | 270 | ||
| 279 | void ARM_Dynarmic::PageTableChanged() { | 271 | void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table, |
| 280 | jit = MakeJit(); | 272 | std::size_t new_address_space_size_in_bits) { |
| 273 | jit = MakeJit(page_table, new_address_space_size_in_bits); | ||
| 281 | } | 274 | } |
| 282 | 275 | ||
| 283 | DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {} | 276 | DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {} |
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index c1db254e8..b701e97a3 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h | |||
| @@ -48,10 +48,12 @@ public: | |||
| 48 | void ClearExclusiveState() override; | 48 | void ClearExclusiveState() override; |
| 49 | 49 | ||
| 50 | void ClearInstructionCache() override; | 50 | void ClearInstructionCache() override; |
| 51 | void PageTableChanged() override; | 51 | void PageTableChanged(Common::PageTable& new_page_table, |
| 52 | std::size_t new_address_space_size_in_bits) override; | ||
| 52 | 53 | ||
| 53 | private: | 54 | private: |
| 54 | std::unique_ptr<Dynarmic::A64::Jit> MakeJit() const; | 55 | std::unique_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable& page_table, |
| 56 | std::size_t address_space_bits) const; | ||
| 55 | 57 | ||
| 56 | friend class ARM_Dynarmic_Callbacks; | 58 | friend class ARM_Dynarmic_Callbacks; |
| 57 | std::unique_ptr<ARM_Dynarmic_Callbacks> cb; | 59 | std::unique_ptr<ARM_Dynarmic_Callbacks> cb; |
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index 209fc16ad..34e974b4d 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h | |||
| @@ -41,7 +41,7 @@ public: | |||
| 41 | void Run() override; | 41 | void Run() override; |
| 42 | void Step() override; | 42 | void Step() override; |
| 43 | void ClearInstructionCache() override; | 43 | void ClearInstructionCache() override; |
| 44 | void PageTableChanged() override{}; | 44 | void PageTableChanged(Common::PageTable&, std::size_t) override {} |
| 45 | void RecordBreak(GDBStub::BreakpointAddress bkpt); | 45 | void RecordBreak(GDBStub::BreakpointAddress bkpt); |
| 46 | 46 | ||
| 47 | private: | 47 | private: |
diff --git a/src/core/core.cpp b/src/core/core.cpp index bc9e887b6..7106151bd 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -3,9 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <array> | 5 | #include <array> |
| 6 | #include <map> | ||
| 7 | #include <memory> | 6 | #include <memory> |
| 8 | #include <thread> | ||
| 9 | #include <utility> | 7 | #include <utility> |
| 10 | 8 | ||
| 11 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| @@ -20,13 +18,18 @@ | |||
| 20 | #include "core/file_sys/registered_cache.h" | 18 | #include "core/file_sys/registered_cache.h" |
| 21 | #include "core/file_sys/vfs_concat.h" | 19 | #include "core/file_sys/vfs_concat.h" |
| 22 | #include "core/file_sys/vfs_real.h" | 20 | #include "core/file_sys/vfs_real.h" |
| 21 | #include "core/frontend/applets/error.h" | ||
| 22 | #include "core/frontend/applets/general_frontend.h" | ||
| 23 | #include "core/frontend/applets/profile_select.h" | ||
| 24 | #include "core/frontend/applets/software_keyboard.h" | ||
| 25 | #include "core/frontend/applets/web_browser.h" | ||
| 23 | #include "core/gdbstub/gdbstub.h" | 26 | #include "core/gdbstub/gdbstub.h" |
| 24 | #include "core/hle/kernel/client_port.h" | 27 | #include "core/hle/kernel/client_port.h" |
| 25 | #include "core/hle/kernel/kernel.h" | 28 | #include "core/hle/kernel/kernel.h" |
| 26 | #include "core/hle/kernel/process.h" | 29 | #include "core/hle/kernel/process.h" |
| 27 | #include "core/hle/kernel/scheduler.h" | 30 | #include "core/hle/kernel/scheduler.h" |
| 28 | #include "core/hle/kernel/thread.h" | 31 | #include "core/hle/kernel/thread.h" |
| 29 | #include "core/hle/service/am/applets/software_keyboard.h" | 32 | #include "core/hle/service/am/applets/applets.h" |
| 30 | #include "core/hle/service/service.h" | 33 | #include "core/hle/service/service.h" |
| 31 | #include "core/hle/service/sm/sm.h" | 34 | #include "core/hle/service/sm/sm.h" |
| 32 | #include "core/loader/loader.h" | 35 | #include "core/loader/loader.h" |
| @@ -38,8 +41,6 @@ | |||
| 38 | #include "frontend/applets/software_keyboard.h" | 41 | #include "frontend/applets/software_keyboard.h" |
| 39 | #include "frontend/applets/web_browser.h" | 42 | #include "frontend/applets/web_browser.h" |
| 40 | #include "video_core/debug_utils/debug_utils.h" | 43 | #include "video_core/debug_utils/debug_utils.h" |
| 41 | #include "video_core/gpu_asynch.h" | ||
| 42 | #include "video_core/gpu_synch.h" | ||
| 43 | #include "video_core/renderer_base.h" | 44 | #include "video_core/renderer_base.h" |
| 44 | #include "video_core/video_core.h" | 45 | #include "video_core/video_core.h" |
| 45 | 46 | ||
| @@ -81,7 +82,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, | |||
| 81 | return vfs->OpenFile(path, FileSys::Mode::Read); | 82 | return vfs->OpenFile(path, FileSys::Mode::Read); |
| 82 | } | 83 | } |
| 83 | struct System::Impl { | 84 | struct System::Impl { |
| 84 | explicit Impl(System& system) : kernel{system} {} | 85 | explicit Impl(System& system) : kernel{system}, cpu_core_manager{system} {} |
| 85 | 86 | ||
| 86 | Cpu& CurrentCpuCore() { | 87 | Cpu& CurrentCpuCore() { |
| 87 | return cpu_core_manager.GetCurrentCore(); | 88 | return cpu_core_manager.GetCurrentCore(); |
| @@ -99,6 +100,7 @@ struct System::Impl { | |||
| 99 | LOG_DEBUG(HW_Memory, "initialized OK"); | 100 | LOG_DEBUG(HW_Memory, "initialized OK"); |
| 100 | 101 | ||
| 101 | core_timing.Initialize(); | 102 | core_timing.Initialize(); |
| 103 | cpu_core_manager.Initialize(); | ||
| 102 | kernel.Initialize(); | 104 | kernel.Initialize(); |
| 103 | 105 | ||
| 104 | const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( | 106 | const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( |
| @@ -113,15 +115,7 @@ struct System::Impl { | |||
| 113 | content_provider = std::make_unique<FileSys::ContentProviderUnion>(); | 115 | content_provider = std::make_unique<FileSys::ContentProviderUnion>(); |
| 114 | 116 | ||
| 115 | /// Create default implementations of applets if one is not provided. | 117 | /// Create default implementations of applets if one is not provided. |
| 116 | if (profile_selector == nullptr) | 118 | applet_manager.SetDefaultAppletsIfMissing(); |
| 117 | profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); | ||
| 118 | if (software_keyboard == nullptr) | ||
| 119 | software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); | ||
| 120 | if (web_browser == nullptr) | ||
| 121 | web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); | ||
| 122 | |||
| 123 | auto main_process = Kernel::Process::Create(system, "main"); | ||
| 124 | kernel.MakeCurrentProcess(main_process.get()); | ||
| 125 | 119 | ||
| 126 | telemetry_session = std::make_unique<Core::TelemetrySession>(); | 120 | telemetry_session = std::make_unique<Core::TelemetrySession>(); |
| 127 | service_manager = std::make_shared<Service::SM::ServiceManager>(); | 121 | service_manager = std::make_shared<Service::SM::ServiceManager>(); |
| @@ -134,15 +128,9 @@ struct System::Impl { | |||
| 134 | return ResultStatus::ErrorVideoCore; | 128 | return ResultStatus::ErrorVideoCore; |
| 135 | } | 129 | } |
| 136 | 130 | ||
| 137 | is_powered_on = true; | 131 | gpu_core = VideoCore::CreateGPU(system); |
| 138 | 132 | ||
| 139 | if (Settings::values.use_asynchronous_gpu_emulation) { | 133 | is_powered_on = true; |
| 140 | gpu_core = std::make_unique<VideoCommon::GPUAsynch>(system, *renderer); | ||
| 141 | } else { | ||
| 142 | gpu_core = std::make_unique<VideoCommon::GPUSynch>(system, *renderer); | ||
| 143 | } | ||
| 144 | |||
| 145 | cpu_core_manager.Initialize(system); | ||
| 146 | 134 | ||
| 147 | LOG_DEBUG(Core, "Initialized OK"); | 135 | LOG_DEBUG(Core, "Initialized OK"); |
| 148 | 136 | ||
| @@ -179,7 +167,8 @@ struct System::Impl { | |||
| 179 | return init_result; | 167 | return init_result; |
| 180 | } | 168 | } |
| 181 | 169 | ||
| 182 | const Loader::ResultStatus load_result{app_loader->Load(*kernel.CurrentProcess())}; | 170 | auto main_process = Kernel::Process::Create(system, "main"); |
| 171 | const auto [load_result, load_parameters] = app_loader->Load(*main_process); | ||
| 183 | if (load_result != Loader::ResultStatus::Success) { | 172 | if (load_result != Loader::ResultStatus::Success) { |
| 184 | LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); | 173 | LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); |
| 185 | Shutdown(); | 174 | Shutdown(); |
| @@ -187,6 +176,16 @@ struct System::Impl { | |||
| 187 | return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) + | 176 | return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) + |
| 188 | static_cast<u32>(load_result)); | 177 | static_cast<u32>(load_result)); |
| 189 | } | 178 | } |
| 179 | kernel.MakeCurrentProcess(main_process.get()); | ||
| 180 | |||
| 181 | // Main process has been loaded and been made current. | ||
| 182 | // Begin GPU and CPU execution. | ||
| 183 | gpu_core->Start(); | ||
| 184 | cpu_core_manager.StartThreads(); | ||
| 185 | |||
| 186 | // All threads are started, begin main process execution, now that we're in the clear. | ||
| 187 | main_process->Run(load_parameters->main_thread_priority, | ||
| 188 | load_parameters->main_thread_stack_size); | ||
| 190 | 189 | ||
| 191 | status = ResultStatus::Success; | 190 | status = ResultStatus::Success; |
| 192 | return status; | 191 | return status; |
| @@ -224,9 +223,7 @@ struct System::Impl { | |||
| 224 | app_loader.reset(); | 223 | app_loader.reset(); |
| 225 | 224 | ||
| 226 | // Clear all applets | 225 | // Clear all applets |
| 227 | profile_selector.reset(); | 226 | applet_manager.ClearAll(); |
| 228 | software_keyboard.reset(); | ||
| 229 | web_browser.reset(); | ||
| 230 | 227 | ||
| 231 | LOG_DEBUG(Core, "Shutdown OK"); | 228 | LOG_DEBUG(Core, "Shutdown OK"); |
| 232 | } | 229 | } |
| @@ -265,9 +262,7 @@ struct System::Impl { | |||
| 265 | std::unique_ptr<FileSys::CheatEngine> cheat_engine; | 262 | std::unique_ptr<FileSys::CheatEngine> cheat_engine; |
| 266 | 263 | ||
| 267 | /// Frontend applets | 264 | /// Frontend applets |
| 268 | std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector; | 265 | Service::AM::Applets::AppletManager applet_manager; |
| 269 | std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; | ||
| 270 | std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser; | ||
| 271 | 266 | ||
| 272 | /// Service manager | 267 | /// Service manager |
| 273 | std::shared_ptr<Service::SM::ServiceManager> service_manager; | 268 | std::shared_ptr<Service::SM::ServiceManager> service_manager; |
| @@ -477,20 +472,20 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const { | |||
| 477 | return impl->virtual_filesystem; | 472 | return impl->virtual_filesystem; |
| 478 | } | 473 | } |
| 479 | 474 | ||
| 480 | void System::SetProfileSelector(std::unique_ptr<Frontend::ProfileSelectApplet> applet) { | 475 | void System::SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set) { |
| 481 | impl->profile_selector = std::move(applet); | 476 | impl->applet_manager.SetAppletFrontendSet(std::move(set)); |
| 482 | } | 477 | } |
| 483 | 478 | ||
| 484 | const Frontend::ProfileSelectApplet& System::GetProfileSelector() const { | 479 | void System::SetDefaultAppletFrontendSet() { |
| 485 | return *impl->profile_selector; | 480 | impl->applet_manager.SetDefaultAppletFrontendSet(); |
| 486 | } | 481 | } |
| 487 | 482 | ||
| 488 | void System::SetSoftwareKeyboard(std::unique_ptr<Frontend::SoftwareKeyboardApplet> applet) { | 483 | Service::AM::Applets::AppletManager& System::GetAppletManager() { |
| 489 | impl->software_keyboard = std::move(applet); | 484 | return impl->applet_manager; |
| 490 | } | 485 | } |
| 491 | 486 | ||
| 492 | const Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const { | 487 | const Service::AM::Applets::AppletManager& System::GetAppletManager() const { |
| 493 | return *impl->software_keyboard; | 488 | return impl->applet_manager; |
| 494 | } | 489 | } |
| 495 | 490 | ||
| 496 | void System::SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider) { | 491 | void System::SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider) { |
| @@ -514,18 +509,6 @@ void System::ClearContentProvider(FileSys::ContentProviderUnionSlot slot) { | |||
| 514 | impl->content_provider->ClearSlot(slot); | 509 | impl->content_provider->ClearSlot(slot); |
| 515 | } | 510 | } |
| 516 | 511 | ||
| 517 | void System::SetWebBrowser(std::unique_ptr<Frontend::WebBrowserApplet> applet) { | ||
| 518 | impl->web_browser = std::move(applet); | ||
| 519 | } | ||
| 520 | |||
| 521 | Frontend::WebBrowserApplet& System::GetWebBrowser() { | ||
| 522 | return *impl->web_browser; | ||
| 523 | } | ||
| 524 | |||
| 525 | const Frontend::WebBrowserApplet& System::GetWebBrowser() const { | ||
| 526 | return *impl->web_browser; | ||
| 527 | } | ||
| 528 | |||
| 529 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | 512 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { |
| 530 | return impl->Init(*this, emu_window); | 513 | return impl->Init(*this, emu_window); |
| 531 | } | 514 | } |
diff --git a/src/core/core.h b/src/core/core.h index 82b2e087e..a9a756a4c 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -14,9 +14,6 @@ | |||
| 14 | 14 | ||
| 15 | namespace Core::Frontend { | 15 | namespace Core::Frontend { |
| 16 | class EmuWindow; | 16 | class EmuWindow; |
| 17 | class ProfileSelectApplet; | ||
| 18 | class SoftwareKeyboardApplet; | ||
| 19 | class WebBrowserApplet; | ||
| 20 | } // namespace Core::Frontend | 17 | } // namespace Core::Frontend |
| 21 | 18 | ||
| 22 | namespace FileSys { | 19 | namespace FileSys { |
| @@ -38,9 +35,18 @@ class AppLoader; | |||
| 38 | enum class ResultStatus : u16; | 35 | enum class ResultStatus : u16; |
| 39 | } // namespace Loader | 36 | } // namespace Loader |
| 40 | 37 | ||
| 41 | namespace Service::SM { | 38 | namespace Service { |
| 39 | |||
| 40 | namespace AM::Applets { | ||
| 41 | struct AppletFrontendSet; | ||
| 42 | class AppletManager; | ||
| 43 | } // namespace AM::Applets | ||
| 44 | |||
| 45 | namespace SM { | ||
| 42 | class ServiceManager; | 46 | class ServiceManager; |
| 43 | } // namespace Service::SM | 47 | } // namespace SM |
| 48 | |||
| 49 | } // namespace Service | ||
| 44 | 50 | ||
| 45 | namespace Tegra { | 51 | namespace Tegra { |
| 46 | class DebugContext; | 52 | class DebugContext; |
| @@ -260,18 +266,13 @@ public: | |||
| 260 | void RegisterCheatList(const std::vector<FileSys::CheatList>& list, const std::string& build_id, | 266 | void RegisterCheatList(const std::vector<FileSys::CheatList>& list, const std::string& build_id, |
| 261 | VAddr code_region_start, VAddr code_region_end); | 267 | VAddr code_region_start, VAddr code_region_end); |
| 262 | 268 | ||
| 263 | void SetProfileSelector(std::unique_ptr<Frontend::ProfileSelectApplet> applet); | 269 | void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); |
| 264 | |||
| 265 | const Frontend::ProfileSelectApplet& GetProfileSelector() const; | ||
| 266 | |||
| 267 | void SetSoftwareKeyboard(std::unique_ptr<Frontend::SoftwareKeyboardApplet> applet); | ||
| 268 | 270 | ||
| 269 | const Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const; | 271 | void SetDefaultAppletFrontendSet(); |
| 270 | 272 | ||
| 271 | void SetWebBrowser(std::unique_ptr<Frontend::WebBrowserApplet> applet); | 273 | Service::AM::Applets::AppletManager& GetAppletManager(); |
| 272 | 274 | ||
| 273 | Frontend::WebBrowserApplet& GetWebBrowser(); | 275 | const Service::AM::Applets::AppletManager& GetAppletManager() const; |
| 274 | const Frontend::WebBrowserApplet& GetWebBrowser() const; | ||
| 275 | 276 | ||
| 276 | void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); | 277 | void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); |
| 277 | 278 | ||
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp index 93bc5619c..8fcb4eeb1 100644 --- a/src/core/cpu_core_manager.cpp +++ b/src/core/cpu_core_manager.cpp | |||
| @@ -19,17 +19,19 @@ void RunCpuCore(const System& system, Cpu& cpu_state) { | |||
| 19 | } | 19 | } |
| 20 | } // Anonymous namespace | 20 | } // Anonymous namespace |
| 21 | 21 | ||
| 22 | CpuCoreManager::CpuCoreManager() = default; | 22 | CpuCoreManager::CpuCoreManager(System& system) : system{system} {} |
| 23 | CpuCoreManager::~CpuCoreManager() = default; | 23 | CpuCoreManager::~CpuCoreManager() = default; |
| 24 | 24 | ||
| 25 | void CpuCoreManager::Initialize(System& system) { | 25 | void CpuCoreManager::Initialize() { |
| 26 | barrier = std::make_unique<CpuBarrier>(); | 26 | barrier = std::make_unique<CpuBarrier>(); |
| 27 | exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); | 27 | exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); |
| 28 | 28 | ||
| 29 | for (std::size_t index = 0; index < cores.size(); ++index) { | 29 | for (std::size_t index = 0; index < cores.size(); ++index) { |
| 30 | cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index); | 30 | cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index); |
| 31 | } | 31 | } |
| 32 | } | ||
| 32 | 33 | ||
| 34 | void CpuCoreManager::StartThreads() { | ||
| 33 | // Create threads for CPU cores 1-3, and build thread_to_cpu map | 35 | // Create threads for CPU cores 1-3, and build thread_to_cpu map |
| 34 | // CPU core 0 is run on the main thread | 36 | // CPU core 0 is run on the main thread |
| 35 | thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); | 37 | thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); |
diff --git a/src/core/cpu_core_manager.h b/src/core/cpu_core_manager.h index a4d70ec56..2cbbf8216 100644 --- a/src/core/cpu_core_manager.h +++ b/src/core/cpu_core_manager.h | |||
| @@ -18,7 +18,7 @@ class System; | |||
| 18 | 18 | ||
| 19 | class CpuCoreManager { | 19 | class CpuCoreManager { |
| 20 | public: | 20 | public: |
| 21 | CpuCoreManager(); | 21 | explicit CpuCoreManager(System& system); |
| 22 | CpuCoreManager(const CpuCoreManager&) = delete; | 22 | CpuCoreManager(const CpuCoreManager&) = delete; |
| 23 | CpuCoreManager(CpuCoreManager&&) = delete; | 23 | CpuCoreManager(CpuCoreManager&&) = delete; |
| 24 | 24 | ||
| @@ -27,7 +27,8 @@ public: | |||
| 27 | CpuCoreManager& operator=(const CpuCoreManager&) = delete; | 27 | CpuCoreManager& operator=(const CpuCoreManager&) = delete; |
| 28 | CpuCoreManager& operator=(CpuCoreManager&&) = delete; | 28 | CpuCoreManager& operator=(CpuCoreManager&&) = delete; |
| 29 | 29 | ||
| 30 | void Initialize(System& system); | 30 | void Initialize(); |
| 31 | void StartThreads(); | ||
| 31 | void Shutdown(); | 32 | void Shutdown(); |
| 32 | 33 | ||
| 33 | Cpu& GetCore(std::size_t index); | 34 | Cpu& GetCore(std::size_t index); |
| @@ -54,6 +55,8 @@ private: | |||
| 54 | 55 | ||
| 55 | /// Map of guest threads to CPU cores | 56 | /// Map of guest threads to CPU cores |
| 56 | std::map<std::thread::id, Cpu*> thread_to_cpu; | 57 | std::map<std::thread::id, Cpu*> thread_to_cpu; |
| 58 | |||
| 59 | System& system; | ||
| 57 | }; | 60 | }; |
| 58 | 61 | ||
| 59 | } // namespace Core | 62 | } // namespace Core |
diff --git a/src/core/frontend/applets/error.cpp b/src/core/frontend/applets/error.cpp new file mode 100644 index 000000000..4002a9211 --- /dev/null +++ b/src/core/frontend/applets/error.cpp | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/frontend/applets/error.h" | ||
| 6 | |||
| 7 | namespace Core::Frontend { | ||
| 8 | |||
| 9 | ErrorApplet::~ErrorApplet() = default; | ||
| 10 | |||
| 11 | void DefaultErrorApplet::ShowError(ResultCode error, std::function<void()> finished) const { | ||
| 12 | LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})", | ||
| 13 | static_cast<u32>(error.module.Value()), error.description.Value(), error.raw); | ||
| 14 | } | ||
| 15 | |||
| 16 | void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, | ||
| 17 | std::function<void()> finished) const { | ||
| 18 | LOG_CRITICAL( | ||
| 19 | Service_Fatal, | ||
| 20 | "Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}", | ||
| 21 | static_cast<u32>(error.module.Value()), error.description.Value(), error.raw, time.count()); | ||
| 22 | } | ||
| 23 | |||
| 24 | void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_text, | ||
| 25 | std::string detail_text, | ||
| 26 | std::function<void()> finished) const { | ||
| 27 | LOG_CRITICAL(Service_Fatal, | ||
| 28 | "Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})", | ||
| 29 | static_cast<u32>(error.module.Value()), error.description.Value(), error.raw); | ||
| 30 | LOG_CRITICAL(Service_Fatal, " Main Text: {}", main_text); | ||
| 31 | LOG_CRITICAL(Service_Fatal, " Detail Text: {}", detail_text); | ||
| 32 | } | ||
| 33 | |||
| 34 | } // namespace Core::Frontend | ||
diff --git a/src/core/frontend/applets/error.h b/src/core/frontend/applets/error.h new file mode 100644 index 000000000..699df940d --- /dev/null +++ b/src/core/frontend/applets/error.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <chrono> | ||
| 8 | #include <functional> | ||
| 9 | |||
| 10 | #include "core/hle/result.h" | ||
| 11 | |||
| 12 | namespace Core::Frontend { | ||
| 13 | |||
| 14 | class ErrorApplet { | ||
| 15 | public: | ||
| 16 | virtual ~ErrorApplet(); | ||
| 17 | |||
| 18 | virtual void ShowError(ResultCode error, std::function<void()> finished) const = 0; | ||
| 19 | |||
| 20 | virtual void ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, | ||
| 21 | std::function<void()> finished) const = 0; | ||
| 22 | |||
| 23 | virtual void ShowCustomErrorText(ResultCode error, std::string dialog_text, | ||
| 24 | std::string fullscreen_text, | ||
| 25 | std::function<void()> finished) const = 0; | ||
| 26 | }; | ||
| 27 | |||
| 28 | class DefaultErrorApplet final : public ErrorApplet { | ||
| 29 | public: | ||
| 30 | void ShowError(ResultCode error, std::function<void()> finished) const override; | ||
| 31 | void ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, | ||
| 32 | std::function<void()> finished) const override; | ||
| 33 | void ShowCustomErrorText(ResultCode error, std::string main_text, std::string detail_text, | ||
| 34 | std::function<void()> finished) const override; | ||
| 35 | }; | ||
| 36 | |||
| 37 | } // namespace Core::Frontend | ||
diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general_frontend.cpp new file mode 100644 index 000000000..b974f2289 --- /dev/null +++ b/src/core/frontend/applets/general_frontend.cpp | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/frontend/applets/general_frontend.h" | ||
| 7 | |||
| 8 | namespace Core::Frontend { | ||
| 9 | |||
| 10 | PhotoViewerApplet::~PhotoViewerApplet() = default; | ||
| 11 | |||
| 12 | DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() {} | ||
| 13 | |||
| 14 | void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id, | ||
| 15 | std::function<void()> finished) const { | ||
| 16 | LOG_INFO(Service_AM, | ||
| 17 | "Application requested frontend to display stored photos for title_id={:016X}", | ||
| 18 | title_id); | ||
| 19 | finished(); | ||
| 20 | } | ||
| 21 | |||
| 22 | void DefaultPhotoViewerApplet::ShowAllPhotos(std::function<void()> finished) const { | ||
| 23 | LOG_INFO(Service_AM, "Application requested frontend to display all stored photos."); | ||
| 24 | finished(); | ||
| 25 | } | ||
| 26 | |||
| 27 | } // namespace Core::Frontend | ||
diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general_frontend.h new file mode 100644 index 000000000..d4506c999 --- /dev/null +++ b/src/core/frontend/applets/general_frontend.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <functional> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | namespace Core::Frontend { | ||
| 11 | |||
| 12 | class PhotoViewerApplet { | ||
| 13 | public: | ||
| 14 | virtual ~PhotoViewerApplet(); | ||
| 15 | |||
| 16 | virtual void ShowPhotosForApplication(u64 title_id, std::function<void()> finished) const = 0; | ||
| 17 | virtual void ShowAllPhotos(std::function<void()> finished) const = 0; | ||
| 18 | }; | ||
| 19 | |||
| 20 | class DefaultPhotoViewerApplet final : public PhotoViewerApplet { | ||
| 21 | public: | ||
| 22 | ~DefaultPhotoViewerApplet() override; | ||
| 23 | |||
| 24 | void ShowPhotosForApplication(u64 title_id, std::function<void()> finished) const override; | ||
| 25 | void ShowAllPhotos(std::function<void()> finished) const override; | ||
| 26 | }; | ||
| 27 | |||
| 28 | } // namespace Core::Frontend | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 4d58e7c69..757e5f21f 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -46,8 +46,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ | |||
| 46 | 46 | ||
| 47 | bool resume = true; | 47 | bool resume = true; |
| 48 | 48 | ||
| 49 | if (thread->GetStatus() == ThreadStatus::WaitSynchAny || | 49 | if (thread->GetStatus() == ThreadStatus::WaitSynch || |
| 50 | thread->GetStatus() == ThreadStatus::WaitSynchAll || | ||
| 51 | thread->GetStatus() == ThreadStatus::WaitHLEEvent) { | 50 | thread->GetStatus() == ThreadStatus::WaitHLEEvent) { |
| 52 | // Remove the thread from each of its waiting objects' waitlists | 51 | // Remove the thread from each of its waiting objects' waitlists |
| 53 | for (const auto& object : thread->GetWaitObjects()) { | 52 | for (const auto& object : thread->GetWaitObjects()) { |
| @@ -182,7 +181,12 @@ void KernelCore::AppendNewProcess(SharedPtr<Process> process) { | |||
| 182 | 181 | ||
| 183 | void KernelCore::MakeCurrentProcess(Process* process) { | 182 | void KernelCore::MakeCurrentProcess(Process* process) { |
| 184 | impl->current_process = process; | 183 | impl->current_process = process; |
| 185 | Memory::SetCurrentPageTable(&process->VMManager().page_table); | 184 | |
| 185 | if (process == nullptr) { | ||
| 186 | return; | ||
| 187 | } | ||
| 188 | |||
| 189 | Memory::SetCurrentPageTable(*process); | ||
| 186 | } | 190 | } |
| 187 | 191 | ||
| 188 | Process* KernelCore::CurrentProcess() { | 192 | Process* KernelCore::CurrentProcess() { |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 4e94048da..20d01fc88 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -28,21 +28,20 @@ namespace { | |||
| 28 | * | 28 | * |
| 29 | * @param owner_process The parent process for the main thread | 29 | * @param owner_process The parent process for the main thread |
| 30 | * @param kernel The kernel instance to create the main thread under. | 30 | * @param kernel The kernel instance to create the main thread under. |
| 31 | * @param entry_point The address at which the thread should start execution | ||
| 32 | * @param priority The priority to give the main thread | 31 | * @param priority The priority to give the main thread |
| 33 | */ | 32 | */ |
| 34 | void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_point, u32 priority) { | 33 | void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority) { |
| 35 | // Initialize new "main" thread | 34 | const auto& vm_manager = owner_process.VMManager(); |
| 36 | const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress(); | 35 | const VAddr entry_point = vm_manager.GetCodeRegionBaseAddress(); |
| 36 | const VAddr stack_top = vm_manager.GetTLSIORegionEndAddress(); | ||
| 37 | auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, | 37 | auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, |
| 38 | owner_process.GetIdealCore(), stack_top, owner_process); | 38 | owner_process.GetIdealCore(), stack_top, owner_process); |
| 39 | 39 | ||
| 40 | SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); | 40 | SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); |
| 41 | 41 | ||
| 42 | // Register 1 must be a handle to the main thread | 42 | // Register 1 must be a handle to the main thread |
| 43 | const Handle guest_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); | 43 | const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); |
| 44 | thread->SetGuestHandle(guest_handle); | 44 | thread->GetContext().cpu_registers[1] = thread_handle; |
| 45 | thread->GetContext().cpu_registers[1] = guest_handle; | ||
| 46 | 45 | ||
| 47 | // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires | 46 | // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires |
| 48 | thread->ResumeFromWait(); | 47 | thread->ResumeFromWait(); |
| @@ -106,8 +105,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { | |||
| 106 | is_64bit_process = metadata.Is64BitProgram(); | 105 | is_64bit_process = metadata.Is64BitProgram(); |
| 107 | 106 | ||
| 108 | vm_manager.Reset(metadata.GetAddressSpaceType()); | 107 | vm_manager.Reset(metadata.GetAddressSpaceType()); |
| 109 | // Ensure that the potentially resized page table is seen by CPU backends. | ||
| 110 | Memory::SetCurrentPageTable(&vm_manager.page_table); | ||
| 111 | 108 | ||
| 112 | const auto& caps = metadata.GetKernelCapabilities(); | 109 | const auto& caps = metadata.GetKernelCapabilities(); |
| 113 | const auto capability_init_result = | 110 | const auto capability_init_result = |
| @@ -119,7 +116,7 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { | |||
| 119 | return handle_table.SetSize(capabilities.GetHandleTableSize()); | 116 | return handle_table.SetSize(capabilities.GetHandleTableSize()); |
| 120 | } | 117 | } |
| 121 | 118 | ||
| 122 | void Process::Run(VAddr entry_point, s32 main_thread_priority, u64 stack_size) { | 119 | void Process::Run(s32 main_thread_priority, u64 stack_size) { |
| 123 | // The kernel always ensures that the given stack size is page aligned. | 120 | // The kernel always ensures that the given stack size is page aligned. |
| 124 | main_thread_stack_size = Common::AlignUp(stack_size, Memory::PAGE_SIZE); | 121 | main_thread_stack_size = Common::AlignUp(stack_size, Memory::PAGE_SIZE); |
| 125 | 122 | ||
| @@ -135,7 +132,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u64 stack_size) { | |||
| 135 | vm_manager.LogLayout(); | 132 | vm_manager.LogLayout(); |
| 136 | ChangeStatus(ProcessStatus::Running); | 133 | ChangeStatus(ProcessStatus::Running); |
| 137 | 134 | ||
| 138 | SetupMainThread(*this, kernel, entry_point, main_thread_priority); | 135 | SetupMainThread(*this, kernel, main_thread_priority); |
| 139 | } | 136 | } |
| 140 | 137 | ||
| 141 | void Process::PrepareForTermination() { | 138 | void Process::PrepareForTermination() { |
| @@ -150,8 +147,7 @@ void Process::PrepareForTermination() { | |||
| 150 | continue; | 147 | continue; |
| 151 | 148 | ||
| 152 | // TODO(Subv): When are the other running/ready threads terminated? | 149 | // TODO(Subv): When are the other running/ready threads terminated? |
| 153 | ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynchAny || | 150 | ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynch, |
| 154 | thread->GetStatus() == ThreadStatus::WaitSynchAll, | ||
| 155 | "Exiting processes with non-waiting threads is currently unimplemented"); | 151 | "Exiting processes with non-waiting threads is currently unimplemented"); |
| 156 | 152 | ||
| 157 | thread->Stop(); | 153 | thread->Stop(); |
| @@ -242,9 +238,6 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { | |||
| 242 | MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeData); | 238 | MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeData); |
| 243 | 239 | ||
| 244 | code_memory_size += module_.memory.size(); | 240 | code_memory_size += module_.memory.size(); |
| 245 | |||
| 246 | // Clear instruction cache in CPU JIT | ||
| 247 | system.InvalidateCpuInstructionCaches(); | ||
| 248 | } | 241 | } |
| 249 | 242 | ||
| 250 | Process::Process(Core::System& system) | 243 | Process::Process(Core::System& system) |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index dda52f4c0..bf3b7eef3 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -225,9 +225,12 @@ public: | |||
| 225 | ResultCode LoadFromMetadata(const FileSys::ProgramMetadata& metadata); | 225 | ResultCode LoadFromMetadata(const FileSys::ProgramMetadata& metadata); |
| 226 | 226 | ||
| 227 | /** | 227 | /** |
| 228 | * Applies address space changes and launches the process main thread. | 228 | * Starts the main application thread for this process. |
| 229 | * | ||
| 230 | * @param main_thread_priority The priority for the main thread. | ||
| 231 | * @param stack_size The stack size for the main thread in bytes. | ||
| 229 | */ | 232 | */ |
| 230 | void Run(VAddr entry_point, s32 main_thread_priority, u64 stack_size); | 233 | void Run(s32 main_thread_priority, u64 stack_size); |
| 231 | 234 | ||
| 232 | /** | 235 | /** |
| 233 | * Prepares a process for termination by stopping all of its threads | 236 | * Prepares a process for termination by stopping all of its threads |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index e5d4d6b55..2dcf174c5 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -424,7 +424,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han | |||
| 424 | /// Default thread wakeup callback for WaitSynchronization | 424 | /// Default thread wakeup callback for WaitSynchronization |
| 425 | static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, | 425 | static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, |
| 426 | SharedPtr<WaitObject> object, std::size_t index) { | 426 | SharedPtr<WaitObject> object, std::size_t index) { |
| 427 | ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny); | 427 | ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); |
| 428 | 428 | ||
| 429 | if (reason == ThreadWakeupReason::Timeout) { | 429 | if (reason == ThreadWakeupReason::Timeout) { |
| 430 | thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); | 430 | thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); |
| @@ -502,7 +502,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr | |||
| 502 | } | 502 | } |
| 503 | 503 | ||
| 504 | thread->SetWaitObjects(std::move(objects)); | 504 | thread->SetWaitObjects(std::move(objects)); |
| 505 | thread->SetStatus(ThreadStatus::WaitSynchAny); | 505 | thread->SetStatus(ThreadStatus::WaitSynch); |
| 506 | 506 | ||
| 507 | // Create an event to wake the thread up after the specified nanosecond delay has passed | 507 | // Create an event to wake the thread up after the specified nanosecond delay has passed |
| 508 | thread->WakeAfterDelay(nano_seconds); | 508 | thread->WakeAfterDelay(nano_seconds); |
| @@ -518,16 +518,14 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand | |||
| 518 | LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); | 518 | LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); |
| 519 | 519 | ||
| 520 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 520 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 521 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 521 | SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| 522 | if (!thread) { | 522 | if (!thread) { |
| 523 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | 523 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", |
| 524 | thread_handle); | 524 | thread_handle); |
| 525 | return ERR_INVALID_HANDLE; | 525 | return ERR_INVALID_HANDLE; |
| 526 | } | 526 | } |
| 527 | 527 | ||
| 528 | ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny); | 528 | thread->CancelWait(); |
| 529 | thread->SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); | ||
| 530 | thread->ResumeFromWait(); | ||
| 531 | return RESULT_SUCCESS; | 529 | return RESULT_SUCCESS; |
| 532 | } | 530 | } |
| 533 | 531 | ||
| @@ -1189,6 +1187,142 @@ static ResultCode QueryMemory(Core::System& system, VAddr memory_info_address, | |||
| 1189 | query_address); | 1187 | query_address); |
| 1190 | } | 1188 | } |
| 1191 | 1189 | ||
| 1190 | static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address, | ||
| 1191 | u64 src_address, u64 size) { | ||
| 1192 | LOG_DEBUG(Kernel_SVC, | ||
| 1193 | "called. process_handle=0x{:08X}, dst_address=0x{:016X}, " | ||
| 1194 | "src_address=0x{:016X}, size=0x{:016X}", | ||
| 1195 | process_handle, dst_address, src_address, size); | ||
| 1196 | |||
| 1197 | if (!Common::Is4KBAligned(src_address)) { | ||
| 1198 | LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).", | ||
| 1199 | src_address); | ||
| 1200 | return ERR_INVALID_ADDRESS; | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | if (!Common::Is4KBAligned(dst_address)) { | ||
| 1204 | LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).", | ||
| 1205 | dst_address); | ||
| 1206 | return ERR_INVALID_ADDRESS; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | if (size == 0 || !Common::Is4KBAligned(size)) { | ||
| 1210 | LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X})", size); | ||
| 1211 | return ERR_INVALID_SIZE; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | if (!IsValidAddressRange(dst_address, size)) { | ||
| 1215 | LOG_ERROR(Kernel_SVC, | ||
| 1216 | "Destination address range overflows the address space (dst_address=0x{:016X}, " | ||
| 1217 | "size=0x{:016X}).", | ||
| 1218 | dst_address, size); | ||
| 1219 | return ERR_INVALID_ADDRESS_STATE; | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | if (!IsValidAddressRange(src_address, size)) { | ||
| 1223 | LOG_ERROR(Kernel_SVC, | ||
| 1224 | "Source address range overflows the address space (src_address=0x{:016X}, " | ||
| 1225 | "size=0x{:016X}).", | ||
| 1226 | src_address, size); | ||
| 1227 | return ERR_INVALID_ADDRESS_STATE; | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | ||
| 1231 | auto process = handle_table.Get<Process>(process_handle); | ||
| 1232 | if (!process) { | ||
| 1233 | LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", | ||
| 1234 | process_handle); | ||
| 1235 | return ERR_INVALID_HANDLE; | ||
| 1236 | } | ||
| 1237 | |||
| 1238 | auto& vm_manager = process->VMManager(); | ||
| 1239 | if (!vm_manager.IsWithinAddressSpace(src_address, size)) { | ||
| 1240 | LOG_ERROR(Kernel_SVC, | ||
| 1241 | "Source address range is not within the address space (src_address=0x{:016X}, " | ||
| 1242 | "size=0x{:016X}).", | ||
| 1243 | src_address, size); | ||
| 1244 | return ERR_INVALID_ADDRESS_STATE; | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | if (!vm_manager.IsWithinASLRRegion(dst_address, size)) { | ||
| 1248 | LOG_ERROR(Kernel_SVC, | ||
| 1249 | "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " | ||
| 1250 | "size=0x{:016X}).", | ||
| 1251 | dst_address, size); | ||
| 1252 | return ERR_INVALID_MEMORY_RANGE; | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | return vm_manager.MapCodeMemory(dst_address, src_address, size); | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address, | ||
| 1259 | u64 src_address, u64 size) { | ||
| 1260 | LOG_DEBUG(Kernel_SVC, | ||
| 1261 | "called. process_handle=0x{:08X}, dst_address=0x{:016X}, src_address=0x{:016X}, " | ||
| 1262 | "size=0x{:016X}", | ||
| 1263 | process_handle, dst_address, src_address, size); | ||
| 1264 | |||
| 1265 | if (!Common::Is4KBAligned(dst_address)) { | ||
| 1266 | LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).", | ||
| 1267 | dst_address); | ||
| 1268 | return ERR_INVALID_ADDRESS; | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | if (!Common::Is4KBAligned(src_address)) { | ||
| 1272 | LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).", | ||
| 1273 | src_address); | ||
| 1274 | return ERR_INVALID_ADDRESS; | ||
| 1275 | } | ||
| 1276 | |||
| 1277 | if (size == 0 || Common::Is4KBAligned(size)) { | ||
| 1278 | LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size); | ||
| 1279 | return ERR_INVALID_SIZE; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | if (!IsValidAddressRange(dst_address, size)) { | ||
| 1283 | LOG_ERROR(Kernel_SVC, | ||
| 1284 | "Destination address range overflows the address space (dst_address=0x{:016X}, " | ||
| 1285 | "size=0x{:016X}).", | ||
| 1286 | dst_address, size); | ||
| 1287 | return ERR_INVALID_ADDRESS_STATE; | ||
| 1288 | } | ||
| 1289 | |||
| 1290 | if (!IsValidAddressRange(src_address, size)) { | ||
| 1291 | LOG_ERROR(Kernel_SVC, | ||
| 1292 | "Source address range overflows the address space (src_address=0x{:016X}, " | ||
| 1293 | "size=0x{:016X}).", | ||
| 1294 | src_address, size); | ||
| 1295 | return ERR_INVALID_ADDRESS_STATE; | ||
| 1296 | } | ||
| 1297 | |||
| 1298 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | ||
| 1299 | auto process = handle_table.Get<Process>(process_handle); | ||
| 1300 | if (!process) { | ||
| 1301 | LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", | ||
| 1302 | process_handle); | ||
| 1303 | return ERR_INVALID_HANDLE; | ||
| 1304 | } | ||
| 1305 | |||
| 1306 | auto& vm_manager = process->VMManager(); | ||
| 1307 | if (!vm_manager.IsWithinAddressSpace(src_address, size)) { | ||
| 1308 | LOG_ERROR(Kernel_SVC, | ||
| 1309 | "Source address range is not within the address space (src_address=0x{:016X}, " | ||
| 1310 | "size=0x{:016X}).", | ||
| 1311 | src_address, size); | ||
| 1312 | return ERR_INVALID_ADDRESS_STATE; | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | if (!vm_manager.IsWithinASLRRegion(dst_address, size)) { | ||
| 1316 | LOG_ERROR(Kernel_SVC, | ||
| 1317 | "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " | ||
| 1318 | "size=0x{:016X}).", | ||
| 1319 | dst_address, size); | ||
| 1320 | return ERR_INVALID_MEMORY_RANGE; | ||
| 1321 | } | ||
| 1322 | |||
| 1323 | return vm_manager.UnmapCodeMemory(dst_address, src_address, size); | ||
| 1324 | } | ||
| 1325 | |||
| 1192 | /// Exits the current process | 1326 | /// Exits the current process |
| 1193 | static void ExitProcess(Core::System& system) { | 1327 | static void ExitProcess(Core::System& system) { |
| 1194 | auto* current_process = system.Kernel().CurrentProcess(); | 1328 | auto* current_process = system.Kernel().CurrentProcess(); |
| @@ -1244,20 +1378,22 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e | |||
| 1244 | return ERR_INVALID_THREAD_PRIORITY; | 1378 | return ERR_INVALID_THREAD_PRIORITY; |
| 1245 | } | 1379 | } |
| 1246 | 1380 | ||
| 1247 | const std::string name = fmt::format("thread-{:X}", entry_point); | ||
| 1248 | auto& kernel = system.Kernel(); | 1381 | auto& kernel = system.Kernel(); |
| 1249 | CASCADE_RESULT(SharedPtr<Thread> thread, | 1382 | CASCADE_RESULT(SharedPtr<Thread> thread, |
| 1250 | Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top, | 1383 | Thread::Create(kernel, "", entry_point, priority, arg, processor_id, stack_top, |
| 1251 | *current_process)); | 1384 | *current_process)); |
| 1252 | 1385 | ||
| 1253 | const auto new_guest_handle = current_process->GetHandleTable().Create(thread); | 1386 | const auto new_thread_handle = current_process->GetHandleTable().Create(thread); |
| 1254 | if (new_guest_handle.Failed()) { | 1387 | if (new_thread_handle.Failed()) { |
| 1255 | LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", | 1388 | LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", |
| 1256 | new_guest_handle.Code().raw); | 1389 | new_thread_handle.Code().raw); |
| 1257 | return new_guest_handle.Code(); | 1390 | return new_thread_handle.Code(); |
| 1258 | } | 1391 | } |
| 1259 | thread->SetGuestHandle(*new_guest_handle); | 1392 | *out_handle = *new_thread_handle; |
| 1260 | *out_handle = *new_guest_handle; | 1393 | |
| 1394 | // Set the thread name for debugging purposes. | ||
| 1395 | thread->SetName( | ||
| 1396 | fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); | ||
| 1261 | 1397 | ||
| 1262 | system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); | 1398 | system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); |
| 1263 | 1399 | ||
| @@ -2152,7 +2288,7 @@ static const FunctionDef SVC_Table[] = { | |||
| 2152 | {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, | 2288 | {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, |
| 2153 | {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, | 2289 | {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, |
| 2154 | {0x35, SvcWrap<SignalToAddress>, "SignalToAddress"}, | 2290 | {0x35, SvcWrap<SignalToAddress>, "SignalToAddress"}, |
| 2155 | {0x36, nullptr, "Unknown"}, | 2291 | {0x36, nullptr, "SynchronizePreemptionState"}, |
| 2156 | {0x37, nullptr, "Unknown"}, | 2292 | {0x37, nullptr, "Unknown"}, |
| 2157 | {0x38, nullptr, "Unknown"}, | 2293 | {0x38, nullptr, "Unknown"}, |
| 2158 | {0x39, nullptr, "Unknown"}, | 2294 | {0x39, nullptr, "Unknown"}, |
| @@ -2217,8 +2353,8 @@ static const FunctionDef SVC_Table[] = { | |||
| 2217 | {0x74, nullptr, "MapProcessMemory"}, | 2353 | {0x74, nullptr, "MapProcessMemory"}, |
| 2218 | {0x75, nullptr, "UnmapProcessMemory"}, | 2354 | {0x75, nullptr, "UnmapProcessMemory"}, |
| 2219 | {0x76, SvcWrap<QueryProcessMemory>, "QueryProcessMemory"}, | 2355 | {0x76, SvcWrap<QueryProcessMemory>, "QueryProcessMemory"}, |
| 2220 | {0x77, nullptr, "MapProcessCodeMemory"}, | 2356 | {0x77, SvcWrap<MapProcessCodeMemory>, "MapProcessCodeMemory"}, |
| 2221 | {0x78, nullptr, "UnmapProcessCodeMemory"}, | 2357 | {0x78, SvcWrap<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"}, |
| 2222 | {0x79, nullptr, "CreateProcess"}, | 2358 | {0x79, nullptr, "CreateProcess"}, |
| 2223 | {0x7A, nullptr, "StartProcess"}, | 2359 | {0x7A, nullptr, "StartProcess"}, |
| 2224 | {0x7B, nullptr, "TerminateProcess"}, | 2360 | {0x7B, nullptr, "TerminateProcess"}, |
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index b3690b5f3..865473c6f 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -44,6 +44,13 @@ void SvcWrap(Core::System& system) { | |||
| 44 | func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw); | 44 | func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw); |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | template <ResultCode func(Core::System&, u32, u64, u64, u64)> | ||
| 48 | void SvcWrap(Core::System& system) { | ||
| 49 | FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), | ||
| 50 | Param(system, 2), Param(system, 3)) | ||
| 51 | .raw); | ||
| 52 | } | ||
| 53 | |||
| 47 | template <ResultCode func(Core::System&, u32*)> | 54 | template <ResultCode func(Core::System&, u32*)> |
| 48 | void SvcWrap(Core::System& system) { | 55 | void SvcWrap(Core::System& system) { |
| 49 | u32 param = 0; | 56 | u32 param = 0; |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 1b891f632..2abf9efca 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -101,8 +101,7 @@ void Thread::ResumeFromWait() { | |||
| 101 | ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); | 101 | ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); |
| 102 | 102 | ||
| 103 | switch (status) { | 103 | switch (status) { |
| 104 | case ThreadStatus::WaitSynchAll: | 104 | case ThreadStatus::WaitSynch: |
| 105 | case ThreadStatus::WaitSynchAny: | ||
| 106 | case ThreadStatus::WaitHLEEvent: | 105 | case ThreadStatus::WaitHLEEvent: |
| 107 | case ThreadStatus::WaitSleep: | 106 | case ThreadStatus::WaitSleep: |
| 108 | case ThreadStatus::WaitIPC: | 107 | case ThreadStatus::WaitIPC: |
| @@ -142,6 +141,12 @@ void Thread::ResumeFromWait() { | |||
| 142 | ChangeScheduler(); | 141 | ChangeScheduler(); |
| 143 | } | 142 | } |
| 144 | 143 | ||
| 144 | void Thread::CancelWait() { | ||
| 145 | ASSERT(GetStatus() == ThreadStatus::WaitSynch); | ||
| 146 | SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); | ||
| 147 | ResumeFromWait(); | ||
| 148 | } | ||
| 149 | |||
| 145 | /** | 150 | /** |
| 146 | * Resets a thread context, making it ready to be scheduled and run by the CPU | 151 | * Resets a thread context, making it ready to be scheduled and run by the CPU |
| 147 | * @param context Thread context to reset | 152 | * @param context Thread context to reset |
| @@ -220,11 +225,6 @@ void Thread::SetPriority(u32 priority) { | |||
| 220 | UpdatePriority(); | 225 | UpdatePriority(); |
| 221 | } | 226 | } |
| 222 | 227 | ||
| 223 | void Thread::BoostPriority(u32 priority) { | ||
| 224 | scheduler->SetThreadPriority(this, priority); | ||
| 225 | current_priority = priority; | ||
| 226 | } | ||
| 227 | |||
| 228 | void Thread::SetWaitSynchronizationResult(ResultCode result) { | 228 | void Thread::SetWaitSynchronizationResult(ResultCode result) { |
| 229 | context.cpu_registers[0] = result.raw; | 229 | context.cpu_registers[0] = result.raw; |
| 230 | } | 230 | } |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 83c83e45a..f07332f02 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -49,8 +49,7 @@ enum class ThreadStatus { | |||
| 49 | WaitHLEEvent, ///< Waiting for hle event to finish | 49 | WaitHLEEvent, ///< Waiting for hle event to finish |
| 50 | WaitSleep, ///< Waiting due to a SleepThread SVC | 50 | WaitSleep, ///< Waiting due to a SleepThread SVC |
| 51 | WaitIPC, ///< Waiting for the reply from an IPC request | 51 | WaitIPC, ///< Waiting for the reply from an IPC request |
| 52 | WaitSynchAny, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false | 52 | WaitSynch, ///< Waiting due to WaitSynchronization |
| 53 | WaitSynchAll, ///< Waiting due to WaitSynchronizationN with wait_all = true | ||
| 54 | WaitMutex, ///< Waiting due to an ArbitrateLock svc | 53 | WaitMutex, ///< Waiting due to an ArbitrateLock svc |
| 55 | WaitCondVar, ///< Waiting due to an WaitProcessWideKey svc | 54 | WaitCondVar, ///< Waiting due to an WaitProcessWideKey svc |
| 56 | WaitArb, ///< Waiting due to a SignalToAddress/WaitForAddress svc | 55 | WaitArb, ///< Waiting due to a SignalToAddress/WaitForAddress svc |
| @@ -102,6 +101,11 @@ public: | |||
| 102 | std::string GetName() const override { | 101 | std::string GetName() const override { |
| 103 | return name; | 102 | return name; |
| 104 | } | 103 | } |
| 104 | |||
| 105 | void SetName(std::string new_name) { | ||
| 106 | name = std::move(new_name); | ||
| 107 | } | ||
| 108 | |||
| 105 | std::string GetTypeName() const override { | 109 | std::string GetTypeName() const override { |
| 106 | return "Thread"; | 110 | return "Thread"; |
| 107 | } | 111 | } |
| @@ -136,12 +140,6 @@ public: | |||
| 136 | */ | 140 | */ |
| 137 | void SetPriority(u32 priority); | 141 | void SetPriority(u32 priority); |
| 138 | 142 | ||
| 139 | /** | ||
| 140 | * Temporarily boosts the thread's priority until the next time it is scheduled | ||
| 141 | * @param priority The new priority | ||
| 142 | */ | ||
| 143 | void BoostPriority(u32 priority); | ||
| 144 | |||
| 145 | /// Adds a thread to the list of threads that are waiting for a lock held by this thread. | 143 | /// Adds a thread to the list of threads that are waiting for a lock held by this thread. |
| 146 | void AddMutexWaiter(SharedPtr<Thread> thread); | 144 | void AddMutexWaiter(SharedPtr<Thread> thread); |
| 147 | 145 | ||
| @@ -170,11 +168,17 @@ public: | |||
| 170 | return tls_memory; | 168 | return tls_memory; |
| 171 | } | 169 | } |
| 172 | 170 | ||
| 173 | /** | 171 | /// Resumes a thread from waiting |
| 174 | * Resumes a thread from waiting | ||
| 175 | */ | ||
| 176 | void ResumeFromWait(); | 172 | void ResumeFromWait(); |
| 177 | 173 | ||
| 174 | /// Cancels a waiting operation that this thread may or may not be within. | ||
| 175 | /// | ||
| 176 | /// When the thread is within a waiting state, this will set the thread's | ||
| 177 | /// waiting result to signal a canceled wait. The function will then resume | ||
| 178 | /// this thread. | ||
| 179 | /// | ||
| 180 | void CancelWait(); | ||
| 181 | |||
| 178 | /** | 182 | /** |
| 179 | * Schedules an event to wake up the specified thread after the specified delay | 183 | * Schedules an event to wake up the specified thread after the specified delay |
| 180 | * @param nanoseconds The time this thread will be allowed to sleep for | 184 | * @param nanoseconds The time this thread will be allowed to sleep for |
| @@ -185,24 +189,27 @@ public: | |||
| 185 | void CancelWakeupTimer(); | 189 | void CancelWakeupTimer(); |
| 186 | 190 | ||
| 187 | /** | 191 | /** |
| 188 | * Sets the result after the thread awakens (from either WaitSynchronization SVC) | 192 | * Sets the result after the thread awakens (from svcWaitSynchronization) |
| 189 | * @param result Value to set to the returned result | 193 | * @param result Value to set to the returned result |
| 190 | */ | 194 | */ |
| 191 | void SetWaitSynchronizationResult(ResultCode result); | 195 | void SetWaitSynchronizationResult(ResultCode result); |
| 192 | 196 | ||
| 193 | /** | 197 | /** |
| 194 | * Sets the output parameter value after the thread awakens (from WaitSynchronizationN SVC only) | 198 | * Sets the output parameter value after the thread awakens (from svcWaitSynchronization) |
| 195 | * @param output Value to set to the output parameter | 199 | * @param output Value to set to the output parameter |
| 196 | */ | 200 | */ |
| 197 | void SetWaitSynchronizationOutput(s32 output); | 201 | void SetWaitSynchronizationOutput(s32 output); |
| 198 | 202 | ||
| 199 | /** | 203 | /** |
| 200 | * Retrieves the index that this particular object occupies in the list of objects | 204 | * Retrieves the index that this particular object occupies in the list of objects |
| 201 | * that the thread passed to WaitSynchronizationN, starting the search from the last element. | 205 | * that the thread passed to WaitSynchronization, starting the search from the last element. |
| 202 | * It is used to set the output value of WaitSynchronizationN when the thread is awakened. | 206 | * |
| 207 | * It is used to set the output index of WaitSynchronization when the thread is awakened. | ||
| 208 | * | ||
| 203 | * When a thread wakes up due to an object signal, the kernel will use the index of the last | 209 | * When a thread wakes up due to an object signal, the kernel will use the index of the last |
| 204 | * matching object in the wait objects list in case of having multiple instances of the same | 210 | * matching object in the wait objects list in case of having multiple instances of the same |
| 205 | * object in the list. | 211 | * object in the list. |
| 212 | * | ||
| 206 | * @param object Object to query the index of. | 213 | * @param object Object to query the index of. |
| 207 | */ | 214 | */ |
| 208 | s32 GetWaitObjectIndex(const WaitObject* object) const; | 215 | s32 GetWaitObjectIndex(const WaitObject* object) const; |
| @@ -239,13 +246,9 @@ public: | |||
| 239 | */ | 246 | */ |
| 240 | VAddr GetCommandBufferAddress() const; | 247 | VAddr GetCommandBufferAddress() const; |
| 241 | 248 | ||
| 242 | /** | 249 | /// Returns whether this thread is waiting on objects from a WaitSynchronization call. |
| 243 | * Returns whether this thread is waiting for all the objects in | 250 | bool IsSleepingOnWait() const { |
| 244 | * its wait list to become ready, as a result of a WaitSynchronizationN call | 251 | return status == ThreadStatus::WaitSynch; |
| 245 | * with wait_all = true. | ||
| 246 | */ | ||
| 247 | bool IsSleepingOnWaitAll() const { | ||
| 248 | return status == ThreadStatus::WaitSynchAll; | ||
| 249 | } | 252 | } |
| 250 | 253 | ||
| 251 | ThreadContext& GetContext() { | 254 | ThreadContext& GetContext() { |
| @@ -345,10 +348,6 @@ public: | |||
| 345 | arb_wait_address = address; | 348 | arb_wait_address = address; |
| 346 | } | 349 | } |
| 347 | 350 | ||
| 348 | void SetGuestHandle(Handle handle) { | ||
| 349 | guest_handle = handle; | ||
| 350 | } | ||
| 351 | |||
| 352 | bool HasWakeupCallback() const { | 351 | bool HasWakeupCallback() const { |
| 353 | return wakeup_callback != nullptr; | 352 | return wakeup_callback != nullptr; |
| 354 | } | 353 | } |
| @@ -423,7 +422,7 @@ private: | |||
| 423 | Process* owner_process; | 422 | Process* owner_process; |
| 424 | 423 | ||
| 425 | /// Objects that the thread is waiting on, in the same order as they were | 424 | /// Objects that the thread is waiting on, in the same order as they were |
| 426 | /// passed to WaitSynchronization1/N. | 425 | /// passed to WaitSynchronization. |
| 427 | ThreadWaitObjects wait_objects; | 426 | ThreadWaitObjects wait_objects; |
| 428 | 427 | ||
| 429 | /// List of threads that are waiting for a mutex that is held by this thread. | 428 | /// List of threads that are waiting for a mutex that is held by this thread. |
| @@ -442,14 +441,11 @@ private: | |||
| 442 | /// If waiting for an AddressArbiter, this is the address being waited on. | 441 | /// If waiting for an AddressArbiter, this is the address being waited on. |
| 443 | VAddr arb_wait_address{0}; | 442 | VAddr arb_wait_address{0}; |
| 444 | 443 | ||
| 445 | /// Handle used by guest emulated application to access this thread | ||
| 446 | Handle guest_handle = 0; | ||
| 447 | |||
| 448 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. | 444 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. |
| 449 | Handle callback_handle = 0; | 445 | Handle callback_handle = 0; |
| 450 | 446 | ||
| 451 | /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread | 447 | /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread |
| 452 | /// was waiting via WaitSynchronizationN then the object will be the last object that became | 448 | /// was waiting via WaitSynchronization then the object will be the last object that became |
| 453 | /// available. In case of a timeout, the object will be nullptr. | 449 | /// available. In case of a timeout, the object will be nullptr. |
| 454 | WakeupCallback wakeup_callback; | 450 | WakeupCallback wakeup_callback; |
| 455 | 451 | ||
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index ec0a480ce..f0c0c12fc 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -302,6 +302,86 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) { | |||
| 302 | return MakeResult<VAddr>(heap_region_base); | 302 | return MakeResult<VAddr>(heap_region_base); |
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | ResultCode VMManager::MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) { | ||
| 306 | constexpr auto ignore_attribute = MemoryAttribute::LockedForIPC | MemoryAttribute::DeviceMapped; | ||
| 307 | const auto src_check_result = CheckRangeState( | ||
| 308 | src_address, size, MemoryState::All, MemoryState::Heap, VMAPermission::All, | ||
| 309 | VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None, ignore_attribute); | ||
| 310 | |||
| 311 | if (src_check_result.Failed()) { | ||
| 312 | return src_check_result.Code(); | ||
| 313 | } | ||
| 314 | |||
| 315 | const auto mirror_result = | ||
| 316 | MirrorMemory(dst_address, src_address, size, MemoryState::ModuleCode); | ||
| 317 | if (mirror_result.IsError()) { | ||
| 318 | return mirror_result; | ||
| 319 | } | ||
| 320 | |||
| 321 | // Ensure we lock the source memory region. | ||
| 322 | const auto src_vma_result = CarveVMARange(src_address, size); | ||
| 323 | if (src_vma_result.Failed()) { | ||
| 324 | return src_vma_result.Code(); | ||
| 325 | } | ||
| 326 | auto src_vma_iter = *src_vma_result; | ||
| 327 | src_vma_iter->second.attribute = MemoryAttribute::Locked; | ||
| 328 | Reprotect(src_vma_iter, VMAPermission::Read); | ||
| 329 | |||
| 330 | // The destination memory region is fine as is, however we need to make it read-only. | ||
| 331 | return ReprotectRange(dst_address, size, VMAPermission::Read); | ||
| 332 | } | ||
| 333 | |||
| 334 | ResultCode VMManager::UnmapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) { | ||
| 335 | constexpr auto ignore_attribute = MemoryAttribute::LockedForIPC | MemoryAttribute::DeviceMapped; | ||
| 336 | const auto src_check_result = CheckRangeState( | ||
| 337 | src_address, size, MemoryState::All, MemoryState::Heap, VMAPermission::None, | ||
| 338 | VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked, ignore_attribute); | ||
| 339 | |||
| 340 | if (src_check_result.Failed()) { | ||
| 341 | return src_check_result.Code(); | ||
| 342 | } | ||
| 343 | |||
| 344 | // Yes, the kernel only checks the first page of the region. | ||
| 345 | const auto dst_check_result = | ||
| 346 | CheckRangeState(dst_address, Memory::PAGE_SIZE, MemoryState::FlagModule, | ||
| 347 | MemoryState::FlagModule, VMAPermission::None, VMAPermission::None, | ||
| 348 | MemoryAttribute::Mask, MemoryAttribute::None, ignore_attribute); | ||
| 349 | |||
| 350 | if (dst_check_result.Failed()) { | ||
| 351 | return dst_check_result.Code(); | ||
| 352 | } | ||
| 353 | |||
| 354 | const auto dst_memory_state = std::get<MemoryState>(*dst_check_result); | ||
| 355 | const auto dst_contiguous_check_result = CheckRangeState( | ||
| 356 | dst_address, size, MemoryState::All, dst_memory_state, VMAPermission::None, | ||
| 357 | VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::None, ignore_attribute); | ||
| 358 | |||
| 359 | if (dst_contiguous_check_result.Failed()) { | ||
| 360 | return dst_contiguous_check_result.Code(); | ||
| 361 | } | ||
| 362 | |||
| 363 | const auto unmap_result = UnmapRange(dst_address, size); | ||
| 364 | if (unmap_result.IsError()) { | ||
| 365 | return unmap_result; | ||
| 366 | } | ||
| 367 | |||
| 368 | // With the mirrored portion unmapped, restore the original region's traits. | ||
| 369 | const auto src_vma_result = CarveVMARange(src_address, size); | ||
| 370 | if (src_vma_result.Failed()) { | ||
| 371 | return src_vma_result.Code(); | ||
| 372 | } | ||
| 373 | auto src_vma_iter = *src_vma_result; | ||
| 374 | src_vma_iter->second.state = MemoryState::Heap; | ||
| 375 | src_vma_iter->second.attribute = MemoryAttribute::None; | ||
| 376 | Reprotect(src_vma_iter, VMAPermission::ReadWrite); | ||
| 377 | |||
| 378 | if (dst_memory_state == MemoryState::ModuleCode) { | ||
| 379 | Core::System::GetInstance().InvalidateCpuInstructionCaches(); | ||
| 380 | } | ||
| 381 | |||
| 382 | return unmap_result; | ||
| 383 | } | ||
| 384 | |||
| 305 | MemoryInfo VMManager::QueryMemory(VAddr address) const { | 385 | MemoryInfo VMManager::QueryMemory(VAddr address) const { |
| 306 | const auto vma = FindVMA(address); | 386 | const auto vma = FindVMA(address); |
| 307 | MemoryInfo memory_info{}; | 387 | MemoryInfo memory_info{}; |
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 6f484b7bf..288eb9450 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -43,6 +43,9 @@ enum class VMAPermission : u8 { | |||
| 43 | ReadExecute = Read | Execute, | 43 | ReadExecute = Read | Execute, |
| 44 | WriteExecute = Write | Execute, | 44 | WriteExecute = Write | Execute, |
| 45 | ReadWriteExecute = Read | Write | Execute, | 45 | ReadWriteExecute = Read | Write | Execute, |
| 46 | |||
| 47 | // Used as a wildcard when checking permissions across memory ranges | ||
| 48 | All = 0xFF, | ||
| 46 | }; | 49 | }; |
| 47 | 50 | ||
| 48 | constexpr VMAPermission operator|(VMAPermission lhs, VMAPermission rhs) { | 51 | constexpr VMAPermission operator|(VMAPermission lhs, VMAPermission rhs) { |
| @@ -152,6 +155,9 @@ enum class MemoryState : u32 { | |||
| 152 | FlagUncached = 1U << 24, | 155 | FlagUncached = 1U << 24, |
| 153 | FlagCodeMemory = 1U << 25, | 156 | FlagCodeMemory = 1U << 25, |
| 154 | 157 | ||
| 158 | // Wildcard used in range checking to indicate all states. | ||
| 159 | All = 0xFFFFFFFF, | ||
| 160 | |||
| 155 | // Convenience flag sets to reduce repetition | 161 | // Convenience flag sets to reduce repetition |
| 156 | IPCFlags = FlagIPC0 | FlagIPC3 | FlagIPC1, | 162 | IPCFlags = FlagIPC0 | FlagIPC3 | FlagIPC1, |
| 157 | 163 | ||
| @@ -415,6 +421,49 @@ public: | |||
| 415 | /// | 421 | /// |
| 416 | ResultVal<VAddr> SetHeapSize(u64 size); | 422 | ResultVal<VAddr> SetHeapSize(u64 size); |
| 417 | 423 | ||
| 424 | /// Maps a region of memory as code memory. | ||
| 425 | /// | ||
| 426 | /// @param dst_address The base address of the region to create the aliasing memory region. | ||
| 427 | /// @param src_address The base address of the region to be aliased. | ||
| 428 | /// @param size The total amount of memory to map in bytes. | ||
| 429 | /// | ||
| 430 | /// @pre Both memory regions lie within the actual addressable address space. | ||
| 431 | /// | ||
| 432 | /// @post After this function finishes execution, assuming success, then the address range | ||
| 433 | /// [dst_address, dst_address+size) will alias the memory region, | ||
| 434 | /// [src_address, src_address+size). | ||
| 435 | /// <p> | ||
| 436 | /// What this also entails is as follows: | ||
| 437 | /// 1. The aliased region gains the Locked memory attribute. | ||
| 438 | /// 2. The aliased region becomes read-only. | ||
| 439 | /// 3. The aliasing region becomes read-only. | ||
| 440 | /// 4. The aliasing region is created with a memory state of MemoryState::CodeModule. | ||
| 441 | /// | ||
| 442 | ResultCode MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size); | ||
| 443 | |||
| 444 | /// Unmaps a region of memory designated as code module memory. | ||
| 445 | /// | ||
| 446 | /// @param dst_address The base address of the memory region aliasing the source memory region. | ||
| 447 | /// @param src_address The base address of the memory region being aliased. | ||
| 448 | /// @param size The size of the memory region to unmap in bytes. | ||
| 449 | /// | ||
| 450 | /// @pre Both memory ranges lie within the actual addressable address space. | ||
| 451 | /// | ||
| 452 | /// @pre The memory region being unmapped has been previously been mapped | ||
| 453 | /// by a call to MapCodeMemory. | ||
| 454 | /// | ||
| 455 | /// @post After execution of the function, if successful. the aliasing memory region | ||
| 456 | /// will be unmapped and the aliased region will have various traits about it | ||
| 457 | /// restored to what they were prior to the original mapping call preceding | ||
| 458 | /// this function call. | ||
| 459 | /// <p> | ||
| 460 | /// What this also entails is as follows: | ||
| 461 | /// 1. The state of the memory region will now indicate a general heap region. | ||
| 462 | /// 2. All memory attributes for the memory region are cleared. | ||
| 463 | /// 3. Memory permissions for the region are restored to user read/write. | ||
| 464 | /// | ||
| 465 | ResultCode UnmapCodeMemory(VAddr dst_address, VAddr src_address, u64 size); | ||
| 466 | |||
| 418 | /// Queries the memory manager for information about the given address. | 467 | /// Queries the memory manager for information about the given address. |
| 419 | /// | 468 | /// |
| 420 | /// @param address The address to query the memory manager about for information. | 469 | /// @param address The address to query the memory manager about for information. |
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index 90580ed93..0e96ba872 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp | |||
| @@ -30,7 +30,7 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { | |||
| 30 | waiting_threads.erase(itr); | 30 | waiting_threads.erase(itr); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { | 33 | SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() const { |
| 34 | Thread* candidate = nullptr; | 34 | Thread* candidate = nullptr; |
| 35 | u32 candidate_priority = THREADPRIO_LOWEST + 1; | 35 | u32 candidate_priority = THREADPRIO_LOWEST + 1; |
| 36 | 36 | ||
| @@ -38,8 +38,7 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { | |||
| 38 | const ThreadStatus thread_status = thread->GetStatus(); | 38 | const ThreadStatus thread_status = thread->GetStatus(); |
| 39 | 39 | ||
| 40 | // The list of waiting threads must not contain threads that are not waiting to be awakened. | 40 | // The list of waiting threads must not contain threads that are not waiting to be awakened. |
| 41 | ASSERT_MSG(thread_status == ThreadStatus::WaitSynchAny || | 41 | ASSERT_MSG(thread_status == ThreadStatus::WaitSynch || |
| 42 | thread_status == ThreadStatus::WaitSynchAll || | ||
| 43 | thread_status == ThreadStatus::WaitHLEEvent, | 42 | thread_status == ThreadStatus::WaitHLEEvent, |
| 44 | "Inconsistent thread statuses in waiting_threads"); | 43 | "Inconsistent thread statuses in waiting_threads"); |
| 45 | 44 | ||
| @@ -49,10 +48,10 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { | |||
| 49 | if (ShouldWait(thread.get())) | 48 | if (ShouldWait(thread.get())) |
| 50 | continue; | 49 | continue; |
| 51 | 50 | ||
| 52 | // A thread is ready to run if it's either in ThreadStatus::WaitSynchAny or | 51 | // A thread is ready to run if it's either in ThreadStatus::WaitSynch |
| 53 | // in ThreadStatus::WaitSynchAll and the rest of the objects it is waiting on are ready. | 52 | // and the rest of the objects it is waiting on are ready. |
| 54 | bool ready_to_run = true; | 53 | bool ready_to_run = true; |
| 55 | if (thread_status == ThreadStatus::WaitSynchAll) { | 54 | if (thread_status == ThreadStatus::WaitSynch) { |
| 56 | ready_to_run = thread->AllWaitObjectsReady(); | 55 | ready_to_run = thread->AllWaitObjectsReady(); |
| 57 | } | 56 | } |
| 58 | 57 | ||
| @@ -68,33 +67,35 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { | |||
| 68 | void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) { | 67 | void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) { |
| 69 | ASSERT(!ShouldWait(thread.get())); | 68 | ASSERT(!ShouldWait(thread.get())); |
| 70 | 69 | ||
| 71 | if (!thread) | 70 | if (!thread) { |
| 72 | return; | 71 | return; |
| 72 | } | ||
| 73 | 73 | ||
| 74 | if (!thread->IsSleepingOnWaitAll()) { | 74 | if (thread->IsSleepingOnWait()) { |
| 75 | Acquire(thread.get()); | ||
| 76 | } else { | ||
| 77 | for (const auto& object : thread->GetWaitObjects()) { | 75 | for (const auto& object : thread->GetWaitObjects()) { |
| 78 | ASSERT(!object->ShouldWait(thread.get())); | 76 | ASSERT(!object->ShouldWait(thread.get())); |
| 79 | object->Acquire(thread.get()); | 77 | object->Acquire(thread.get()); |
| 80 | } | 78 | } |
| 79 | } else { | ||
| 80 | Acquire(thread.get()); | ||
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | const std::size_t index = thread->GetWaitObjectIndex(this); | 83 | const std::size_t index = thread->GetWaitObjectIndex(this); |
| 84 | 84 | ||
| 85 | for (const auto& object : thread->GetWaitObjects()) | 85 | for (const auto& object : thread->GetWaitObjects()) { |
| 86 | object->RemoveWaitingThread(thread.get()); | 86 | object->RemoveWaitingThread(thread.get()); |
| 87 | } | ||
| 87 | thread->ClearWaitObjects(); | 88 | thread->ClearWaitObjects(); |
| 88 | 89 | ||
| 89 | thread->CancelWakeupTimer(); | 90 | thread->CancelWakeupTimer(); |
| 90 | 91 | ||
| 91 | bool resume = true; | 92 | bool resume = true; |
| 92 | 93 | if (thread->HasWakeupCallback()) { | |
| 93 | if (thread->HasWakeupCallback()) | ||
| 94 | resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, this, index); | 94 | resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, this, index); |
| 95 | 95 | } | |
| 96 | if (resume) | 96 | if (resume) { |
| 97 | thread->ResumeFromWait(); | 97 | thread->ResumeFromWait(); |
| 98 | } | ||
| 98 | } | 99 | } |
| 99 | 100 | ||
| 100 | void WaitObject::WakeupAllWaitingThreads() { | 101 | void WaitObject::WakeupAllWaitingThreads() { |
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h index 04464a51a..3271a30a7 100644 --- a/src/core/hle/kernel/wait_object.h +++ b/src/core/hle/kernel/wait_object.h | |||
| @@ -54,7 +54,7 @@ public: | |||
| 54 | void WakeupWaitingThread(SharedPtr<Thread> thread); | 54 | void WakeupWaitingThread(SharedPtr<Thread> thread); |
| 55 | 55 | ||
| 56 | /// Obtains the highest priority thread that is ready to run from this object's waiting list. | 56 | /// Obtains the highest priority thread that is ready to run from this object's waiting list. |
| 57 | SharedPtr<Thread> GetHighestPriorityReadyThread(); | 57 | SharedPtr<Thread> GetHighestPriorityReadyThread() const; |
| 58 | 58 | ||
| 59 | /// Get a const reference to the waiting threads list for debug use | 59 | /// Get a const reference to the waiting threads list for debug use |
| 60 | const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const; | 60 | const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const; |
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 1f8ed265e..ba7d7acbd 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -137,6 +137,7 @@ private: | |||
| 137 | class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { | 137 | class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { |
| 138 | public: | 138 | public: |
| 139 | IManagerForApplication() : ServiceFramework("IManagerForApplication") { | 139 | IManagerForApplication() : ServiceFramework("IManagerForApplication") { |
| 140 | // clang-format off | ||
| 140 | static const FunctionInfo functions[] = { | 141 | static const FunctionInfo functions[] = { |
| 141 | {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"}, | 142 | {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"}, |
| 142 | {1, &IManagerForApplication::GetAccountId, "GetAccountId"}, | 143 | {1, &IManagerForApplication::GetAccountId, "GetAccountId"}, |
| @@ -145,7 +146,10 @@ public: | |||
| 145 | {130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"}, | 146 | {130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"}, |
| 146 | {150, nullptr, "CreateAuthorizationRequest"}, | 147 | {150, nullptr, "CreateAuthorizationRequest"}, |
| 147 | {160, nullptr, "StoreOpenContext"}, | 148 | {160, nullptr, "StoreOpenContext"}, |
| 149 | {170, nullptr, "LoadNetworkServiceLicenseKindAsync"}, | ||
| 148 | }; | 150 | }; |
| 151 | // clang-format on | ||
| 152 | |||
| 149 | RegisterHandlers(functions); | 153 | RegisterHandlers(functions); |
| 150 | } | 154 | } |
| 151 | 155 | ||
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index 5e2030355..d66233cad 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp | |||
| @@ -8,6 +8,7 @@ namespace Service::Account { | |||
| 8 | 8 | ||
| 9 | ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager) | 9 | ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager) |
| 10 | : Module::Interface(std::move(module), std::move(profile_manager), "acc:su") { | 10 | : Module::Interface(std::move(module), std::move(profile_manager), "acc:su") { |
| 11 | // clang-format off | ||
| 11 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 12 | {0, &ACC_SU::GetUserCount, "GetUserCount"}, | 13 | {0, &ACC_SU::GetUserCount, "GetUserCount"}, |
| 13 | {1, &ACC_SU::GetUserExistence, "GetUserExistence"}, | 14 | {1, &ACC_SU::GetUserExistence, "GetUserExistence"}, |
| @@ -19,6 +20,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 19 | {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, | 20 | {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, |
| 20 | {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, | 21 | {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, |
| 21 | {60, nullptr, "ListOpenContextStoredUsers"}, | 22 | {60, nullptr, "ListOpenContextStoredUsers"}, |
| 23 | {99, nullptr, "DebugActivateOpenContextRetention"}, | ||
| 22 | {100, nullptr, "GetUserRegistrationNotifier"}, | 24 | {100, nullptr, "GetUserRegistrationNotifier"}, |
| 23 | {101, nullptr, "GetUserStateChangeNotifier"}, | 25 | {101, nullptr, "GetUserStateChangeNotifier"}, |
| 24 | {102, nullptr, "GetBaasAccountManagerForSystemService"}, | 26 | {102, nullptr, "GetBaasAccountManagerForSystemService"}, |
| @@ -29,6 +31,8 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 29 | {111, nullptr, "ClearSaveDataThumbnail"}, | 31 | {111, nullptr, "ClearSaveDataThumbnail"}, |
| 30 | {112, nullptr, "LoadSaveDataThumbnail"}, | 32 | {112, nullptr, "LoadSaveDataThumbnail"}, |
| 31 | {113, nullptr, "GetSaveDataThumbnailExistence"}, | 33 | {113, nullptr, "GetSaveDataThumbnailExistence"}, |
| 34 | {130, nullptr, "ActivateOpenContextRetention"}, | ||
| 35 | {140, nullptr, "ListQualifiedUsers"}, | ||
| 32 | {190, nullptr, "GetUserLastOpenedApplication"}, | 36 | {190, nullptr, "GetUserLastOpenedApplication"}, |
| 33 | {191, nullptr, "ActivateOpenContextHolder"}, | 37 | {191, nullptr, "ActivateOpenContextHolder"}, |
| 34 | {200, nullptr, "BeginUserRegistration"}, | 38 | {200, nullptr, "BeginUserRegistration"}, |
| @@ -48,6 +52,8 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 48 | {998, nullptr, "DebugSetUserStateClose"}, | 52 | {998, nullptr, "DebugSetUserStateClose"}, |
| 49 | {999, nullptr, "DebugSetUserStateOpen"}, | 53 | {999, nullptr, "DebugSetUserStateOpen"}, |
| 50 | }; | 54 | }; |
| 55 | // clang-format on | ||
| 56 | |||
| 51 | RegisterHandlers(functions); | 57 | RegisterHandlers(functions); |
| 52 | } | 58 | } |
| 53 | 59 | ||
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index a4d705b45..182f7c7e5 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp | |||
| @@ -8,6 +8,7 @@ namespace Service::Account { | |||
| 8 | 8 | ||
| 9 | ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager) | 9 | ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager) |
| 10 | : Module::Interface(std::move(module), std::move(profile_manager), "acc:u0") { | 10 | : Module::Interface(std::move(module), std::move(profile_manager), "acc:u0") { |
| 11 | // clang-format off | ||
| 11 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 12 | {0, &ACC_U0::GetUserCount, "GetUserCount"}, | 13 | {0, &ACC_U0::GetUserCount, "GetUserCount"}, |
| 13 | {1, &ACC_U0::GetUserExistence, "GetUserExistence"}, | 14 | {1, &ACC_U0::GetUserExistence, "GetUserExistence"}, |
| @@ -19,6 +20,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 19 | {50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, | 20 | {50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, |
| 20 | {51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, | 21 | {51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, |
| 21 | {60, nullptr, "ListOpenContextStoredUsers"}, | 22 | {60, nullptr, "ListOpenContextStoredUsers"}, |
| 23 | {99, nullptr, "DebugActivateOpenContextRetention"}, | ||
| 22 | {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"}, | 24 | {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"}, |
| 23 | {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"}, | 25 | {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"}, |
| 24 | {102, nullptr, "AuthenticateApplicationAsync"}, | 26 | {102, nullptr, "AuthenticateApplicationAsync"}, |
| @@ -27,7 +29,13 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 27 | {111, nullptr, "ClearSaveDataThumbnail"}, | 29 | {111, nullptr, "ClearSaveDataThumbnail"}, |
| 28 | {120, nullptr, "CreateGuestLoginRequest"}, | 30 | {120, nullptr, "CreateGuestLoginRequest"}, |
| 29 | {130, nullptr, "LoadOpenContext"}, | 31 | {130, nullptr, "LoadOpenContext"}, |
| 32 | {131, nullptr, "ListOpenContextStoredUsers"}, | ||
| 33 | {140, nullptr, "InitializeApplicationInfo"}, | ||
| 34 | {141, nullptr, "ListQualifiedUsers"}, | ||
| 35 | {150, nullptr, "IsUserAccountSwitchLocked"}, | ||
| 30 | }; | 36 | }; |
| 37 | // clang-format on | ||
| 38 | |||
| 31 | RegisterHandlers(functions); | 39 | RegisterHandlers(functions); |
| 32 | } | 40 | } |
| 33 | 41 | ||
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index 8fffc93b5..2dd17d935 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp | |||
| @@ -8,6 +8,7 @@ namespace Service::Account { | |||
| 8 | 8 | ||
| 9 | ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager) | 9 | ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager) |
| 10 | : Module::Interface(std::move(module), std::move(profile_manager), "acc:u1") { | 10 | : Module::Interface(std::move(module), std::move(profile_manager), "acc:u1") { |
| 11 | // clang-format off | ||
| 11 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 12 | {0, &ACC_U1::GetUserCount, "GetUserCount"}, | 13 | {0, &ACC_U1::GetUserCount, "GetUserCount"}, |
| 13 | {1, &ACC_U1::GetUserExistence, "GetUserExistence"}, | 14 | {1, &ACC_U1::GetUserExistence, "GetUserExistence"}, |
| @@ -19,6 +20,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 19 | {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, | 20 | {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, |
| 20 | {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, | 21 | {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, |
| 21 | {60, nullptr, "ListOpenContextStoredUsers"}, | 22 | {60, nullptr, "ListOpenContextStoredUsers"}, |
| 23 | {99, nullptr, "DebugActivateOpenContextRetention"}, | ||
| 22 | {100, nullptr, "GetUserRegistrationNotifier"}, | 24 | {100, nullptr, "GetUserRegistrationNotifier"}, |
| 23 | {101, nullptr, "GetUserStateChangeNotifier"}, | 25 | {101, nullptr, "GetUserStateChangeNotifier"}, |
| 24 | {102, nullptr, "GetBaasAccountManagerForSystemService"}, | 26 | {102, nullptr, "GetBaasAccountManagerForSystemService"}, |
| @@ -29,12 +31,16 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 29 | {111, nullptr, "ClearSaveDataThumbnail"}, | 31 | {111, nullptr, "ClearSaveDataThumbnail"}, |
| 30 | {112, nullptr, "LoadSaveDataThumbnail"}, | 32 | {112, nullptr, "LoadSaveDataThumbnail"}, |
| 31 | {113, nullptr, "GetSaveDataThumbnailExistence"}, | 33 | {113, nullptr, "GetSaveDataThumbnailExistence"}, |
| 34 | {130, nullptr, "ActivateOpenContextRetention"}, | ||
| 35 | {140, nullptr, "ListQualifiedUsers"}, | ||
| 32 | {190, nullptr, "GetUserLastOpenedApplication"}, | 36 | {190, nullptr, "GetUserLastOpenedApplication"}, |
| 33 | {191, nullptr, "ActivateOpenContextHolder"}, | 37 | {191, nullptr, "ActivateOpenContextHolder"}, |
| 34 | {997, nullptr, "DebugInvalidateTokenCacheForUser"}, | 38 | {997, nullptr, "DebugInvalidateTokenCacheForUser"}, |
| 35 | {998, nullptr, "DebugSetUserStateClose"}, | 39 | {998, nullptr, "DebugSetUserStateClose"}, |
| 36 | {999, nullptr, "DebugSetUserStateOpen"}, | 40 | {999, nullptr, "DebugSetUserStateOpen"}, |
| 37 | }; | 41 | }; |
| 42 | // clang-format on | ||
| 43 | |||
| 38 | RegisterHandlers(functions); | 44 | RegisterHandlers(functions); |
| 39 | } | 45 | } |
| 40 | 46 | ||
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 85271d418..26a665bfd 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -22,7 +22,6 @@ | |||
| 22 | #include "core/hle/service/am/applets/applets.h" | 22 | #include "core/hle/service/am/applets/applets.h" |
| 23 | #include "core/hle/service/am/applets/profile_select.h" | 23 | #include "core/hle/service/am/applets/profile_select.h" |
| 24 | #include "core/hle/service/am/applets/software_keyboard.h" | 24 | #include "core/hle/service/am/applets/software_keyboard.h" |
| 25 | #include "core/hle/service/am/applets/stub_applet.h" | ||
| 26 | #include "core/hle/service/am/applets/web_browser.h" | 25 | #include "core/hle/service/am/applets/web_browser.h" |
| 27 | #include "core/hle/service/am/idle.h" | 26 | #include "core/hle/service/am/idle.h" |
| 28 | #include "core/hle/service/am/omm.h" | 27 | #include "core/hle/service/am/omm.h" |
| @@ -42,12 +41,6 @@ constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2}; | |||
| 42 | constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3}; | 41 | constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3}; |
| 43 | constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; | 42 | constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; |
| 44 | 43 | ||
| 45 | enum class AppletId : u32 { | ||
| 46 | ProfileSelect = 0x10, | ||
| 47 | SoftwareKeyboard = 0x11, | ||
| 48 | LibAppletOff = 0x17, | ||
| 49 | }; | ||
| 50 | |||
| 51 | constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; | 44 | constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; |
| 52 | 45 | ||
| 53 | struct LaunchParameters { | 46 | struct LaunchParameters { |
| @@ -224,6 +217,7 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} { | |||
| 224 | {20, nullptr, "InvalidateTransitionLayer"}, | 217 | {20, nullptr, "InvalidateTransitionLayer"}, |
| 225 | {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"}, | 218 | {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"}, |
| 226 | {40, nullptr, "GetAppletResourceUsageInfo"}, | 219 | {40, nullptr, "GetAppletResourceUsageInfo"}, |
| 220 | {41, nullptr, "SetCpuBoostModeForApplet"}, | ||
| 227 | }; | 221 | }; |
| 228 | // clang-format on | 222 | // clang-format on |
| 229 | 223 | ||
| @@ -256,6 +250,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger | |||
| 256 | {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, | 250 | {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, |
| 257 | {41, nullptr, "IsSystemBufferSharingEnabled"}, | 251 | {41, nullptr, "IsSystemBufferSharingEnabled"}, |
| 258 | {42, nullptr, "GetSystemSharedLayerHandle"}, | 252 | {42, nullptr, "GetSystemSharedLayerHandle"}, |
| 253 | {43, nullptr, "GetSystemSharedBufferHandle"}, | ||
| 259 | {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, | 254 | {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, |
| 260 | {51, nullptr, "ApproveToDisplay"}, | 255 | {51, nullptr, "ApproveToDisplay"}, |
| 261 | {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, | 256 | {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, |
| @@ -269,9 +264,11 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger | |||
| 269 | {68, nullptr, "SetAutoSleepDisabled"}, | 264 | {68, nullptr, "SetAutoSleepDisabled"}, |
| 270 | {69, nullptr, "IsAutoSleepDisabled"}, | 265 | {69, nullptr, "IsAutoSleepDisabled"}, |
| 271 | {70, nullptr, "ReportMultimediaError"}, | 266 | {70, nullptr, "ReportMultimediaError"}, |
| 267 | {71, nullptr, "GetCurrentIlluminanceEx"}, | ||
| 272 | {80, nullptr, "SetWirelessPriorityMode"}, | 268 | {80, nullptr, "SetWirelessPriorityMode"}, |
| 273 | {90, nullptr, "GetAccumulatedSuspendedTickValue"}, | 269 | {90, nullptr, "GetAccumulatedSuspendedTickValue"}, |
| 274 | {91, nullptr, "GetAccumulatedSuspendedTickChangedEvent"}, | 270 | {91, nullptr, "GetAccumulatedSuspendedTickChangedEvent"}, |
| 271 | {100, nullptr, "SetAlbumImageTakenNotificationEnabled"}, | ||
| 275 | {1000, nullptr, "GetDebugStorageChannel"}, | 272 | {1000, nullptr, "GetDebugStorageChannel"}, |
| 276 | }; | 273 | }; |
| 277 | // clang-format on | 274 | // clang-format on |
| @@ -516,11 +513,20 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q | |||
| 516 | {50, nullptr, "IsVrModeEnabled"}, | 513 | {50, nullptr, "IsVrModeEnabled"}, |
| 517 | {51, nullptr, "SetVrModeEnabled"}, | 514 | {51, nullptr, "SetVrModeEnabled"}, |
| 518 | {52, nullptr, "SwitchLcdBacklight"}, | 515 | {52, nullptr, "SwitchLcdBacklight"}, |
| 516 | {53, nullptr, "BeginVrModeEx"}, | ||
| 517 | {54, nullptr, "EndVrModeEx"}, | ||
| 519 | {55, nullptr, "IsInControllerFirmwareUpdateSection"}, | 518 | {55, nullptr, "IsInControllerFirmwareUpdateSection"}, |
| 520 | {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, | 519 | {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, |
| 521 | {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, | 520 | {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, |
| 522 | {62, nullptr, "GetHdcpAuthenticationState"}, | 521 | {62, nullptr, "GetHdcpAuthenticationState"}, |
| 523 | {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"}, | 522 | {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"}, |
| 523 | {64, nullptr, "SetTvPowerStateMatchingMode"}, | ||
| 524 | {65, nullptr, "GetApplicationIdByContentActionName"}, | ||
| 525 | {66, nullptr, "SetCpuBoostMode"}, | ||
| 526 | {80, nullptr, "PerformSystemButtonPressingIfInFocus"}, | ||
| 527 | {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, | ||
| 528 | {91, nullptr, "GetCurrentPerformanceConfiguration"}, | ||
| 529 | {200, nullptr, "GetOperationModeSystemInfo"}, | ||
| 524 | }; | 530 | }; |
| 525 | // clang-format on | 531 | // clang-format on |
| 526 | 532 | ||
| @@ -873,30 +879,16 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple | |||
| 873 | 879 | ||
| 874 | ILibraryAppletCreator::~ILibraryAppletCreator() = default; | 880 | ILibraryAppletCreator::~ILibraryAppletCreator() = default; |
| 875 | 881 | ||
| 876 | static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) { | ||
| 877 | switch (id) { | ||
| 878 | case AppletId::ProfileSelect: | ||
| 879 | return std::make_shared<Applets::ProfileSelect>(); | ||
| 880 | case AppletId::SoftwareKeyboard: | ||
| 881 | return std::make_shared<Applets::SoftwareKeyboard>(); | ||
| 882 | case AppletId::LibAppletOff: | ||
| 883 | return std::make_shared<Applets::WebBrowser>(); | ||
| 884 | default: | ||
| 885 | LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!", | ||
| 886 | static_cast<u32>(id)); | ||
| 887 | return std::make_shared<Applets::StubApplet>(); | ||
| 888 | } | ||
| 889 | } | ||
| 890 | |||
| 891 | void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { | 882 | void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { |
| 892 | IPC::RequestParser rp{ctx}; | 883 | IPC::RequestParser rp{ctx}; |
| 893 | const auto applet_id = rp.PopRaw<AppletId>(); | 884 | const auto applet_id = rp.PopRaw<Applets::AppletId>(); |
| 894 | const auto applet_mode = rp.PopRaw<u32>(); | 885 | const auto applet_mode = rp.PopRaw<u32>(); |
| 895 | 886 | ||
| 896 | LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", | 887 | LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", |
| 897 | static_cast<u32>(applet_id), applet_mode); | 888 | static_cast<u32>(applet_id), applet_mode); |
| 898 | 889 | ||
| 899 | const auto applet = GetAppletFromId(applet_id); | 890 | const auto& applet_manager{Core::System::GetInstance().GetAppletManager()}; |
| 891 | const auto applet = applet_manager.GetApplet(applet_id); | ||
| 900 | 892 | ||
| 901 | if (applet == nullptr) { | 893 | if (applet == nullptr) { |
| 902 | LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); | 894 | LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); |
| @@ -960,6 +952,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF | |||
| 960 | {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"}, | 952 | {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"}, |
| 961 | {12, nullptr, "CreateApplicationAndRequestToStart"}, | 953 | {12, nullptr, "CreateApplicationAndRequestToStart"}, |
| 962 | {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"}, | 954 | {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"}, |
| 955 | {14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"}, | ||
| 956 | {15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"}, | ||
| 963 | {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"}, | 957 | {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"}, |
| 964 | {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"}, | 958 | {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"}, |
| 965 | {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, | 959 | {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, |
| @@ -1233,6 +1227,7 @@ IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStat | |||
| 1233 | {2, nullptr, "StartSleepSequence"}, | 1227 | {2, nullptr, "StartSleepSequence"}, |
| 1234 | {3, nullptr, "StartShutdownSequence"}, | 1228 | {3, nullptr, "StartShutdownSequence"}, |
| 1235 | {4, nullptr, "StartRebootSequence"}, | 1229 | {4, nullptr, "StartRebootSequence"}, |
| 1230 | {9, nullptr, "IsAutoPowerDownRequested"}, | ||
| 1236 | {10, nullptr, "LoadAndApplyIdlePolicySettings"}, | 1231 | {10, nullptr, "LoadAndApplyIdlePolicySettings"}, |
| 1237 | {11, nullptr, "NotifyCecSettingsChanged"}, | 1232 | {11, nullptr, "NotifyCecSettingsChanged"}, |
| 1238 | {12, nullptr, "SetDefaultHomeButtonLongPressTime"}, | 1233 | {12, nullptr, "SetDefaultHomeButtonLongPressTime"}, |
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index b888f861d..488add8e7 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp | |||
| @@ -16,6 +16,7 @@ public: | |||
| 16 | std::shared_ptr<AppletMessageQueue> msg_queue) | 16 | std::shared_ptr<AppletMessageQueue> msg_queue) |
| 17 | : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)), | 17 | : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)), |
| 18 | msg_queue(std::move(msg_queue)) { | 18 | msg_queue(std::move(msg_queue)) { |
| 19 | // clang-format off | ||
| 19 | static const FunctionInfo functions[] = { | 20 | static const FunctionInfo functions[] = { |
| 20 | {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, | 21 | {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, |
| 21 | {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"}, | 22 | {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"}, |
| @@ -25,8 +26,11 @@ public: | |||
| 25 | {10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"}, | 26 | {10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"}, |
| 26 | {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, | 27 | {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, |
| 27 | {20, &ILibraryAppletProxy::GetApplicationFunctions, "GetApplicationFunctions"}, | 28 | {20, &ILibraryAppletProxy::GetApplicationFunctions, "GetApplicationFunctions"}, |
| 29 | {21, nullptr, "GetAppletCommonFunctions"}, | ||
| 28 | {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, | 30 | {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, |
| 29 | }; | 31 | }; |
| 32 | // clang-format on | ||
| 33 | |||
| 30 | RegisterHandlers(functions); | 34 | RegisterHandlers(functions); |
| 31 | } | 35 | } |
| 32 | 36 | ||
| @@ -113,6 +117,7 @@ public: | |||
| 113 | std::shared_ptr<AppletMessageQueue> msg_queue) | 117 | std::shared_ptr<AppletMessageQueue> msg_queue) |
| 114 | : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)), | 118 | : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)), |
| 115 | msg_queue(std::move(msg_queue)) { | 119 | msg_queue(std::move(msg_queue)) { |
| 120 | // clang-format off | ||
| 116 | static const FunctionInfo functions[] = { | 121 | static const FunctionInfo functions[] = { |
| 117 | {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, | 122 | {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, |
| 118 | {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"}, | 123 | {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"}, |
| @@ -124,8 +129,11 @@ public: | |||
| 124 | {20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, | 129 | {20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, |
| 125 | {21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, | 130 | {21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, |
| 126 | {22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"}, | 131 | {22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"}, |
| 132 | {23, nullptr, "GetAppletCommonFunctions"}, | ||
| 127 | {1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, | 133 | {1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, |
| 128 | }; | 134 | }; |
| 135 | // clang-format on | ||
| 136 | |||
| 129 | RegisterHandlers(functions); | 137 | RegisterHandlers(functions); |
| 130 | } | 138 | } |
| 131 | 139 | ||
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index a6064c63f..7f70b10df 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp | |||
| @@ -5,11 +5,21 @@ | |||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/frontend/applets/error.h" | ||
| 9 | #include "core/frontend/applets/general_frontend.h" | ||
| 10 | #include "core/frontend/applets/profile_select.h" | ||
| 11 | #include "core/frontend/applets/software_keyboard.h" | ||
| 12 | #include "core/frontend/applets/web_browser.h" | ||
| 8 | #include "core/hle/kernel/readable_event.h" | 13 | #include "core/hle/kernel/readable_event.h" |
| 9 | #include "core/hle/kernel/server_session.h" | 14 | #include "core/hle/kernel/server_session.h" |
| 10 | #include "core/hle/kernel/writable_event.h" | 15 | #include "core/hle/kernel/writable_event.h" |
| 11 | #include "core/hle/service/am/am.h" | 16 | #include "core/hle/service/am/am.h" |
| 12 | #include "core/hle/service/am/applets/applets.h" | 17 | #include "core/hle/service/am/applets/applets.h" |
| 18 | #include "core/hle/service/am/applets/error.h" | ||
| 19 | #include "core/hle/service/am/applets/general_backend.h" | ||
| 20 | #include "core/hle/service/am/applets/profile_select.h" | ||
| 21 | #include "core/hle/service/am/applets/software_keyboard.h" | ||
| 22 | #include "core/hle/service/am/applets/web_browser.h" | ||
| 13 | 23 | ||
| 14 | namespace Service::AM::Applets { | 24 | namespace Service::AM::Applets { |
| 15 | 25 | ||
| @@ -111,4 +121,76 @@ void Applet::Initialize() { | |||
| 111 | initialized = true; | 121 | initialized = true; |
| 112 | } | 122 | } |
| 113 | 123 | ||
| 124 | AppletManager::AppletManager() = default; | ||
| 125 | |||
| 126 | AppletManager::~AppletManager() = default; | ||
| 127 | |||
| 128 | void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { | ||
| 129 | if (set.error != nullptr) | ||
| 130 | frontend.error = std::move(set.error); | ||
| 131 | if (set.photo_viewer != nullptr) | ||
| 132 | frontend.photo_viewer = std::move(set.photo_viewer); | ||
| 133 | if (set.profile_select != nullptr) | ||
| 134 | frontend.profile_select = std::move(set.profile_select); | ||
| 135 | if (set.software_keyboard != nullptr) | ||
| 136 | frontend.software_keyboard = std::move(set.software_keyboard); | ||
| 137 | if (set.web_browser != nullptr) | ||
| 138 | frontend.web_browser = std::move(set.web_browser); | ||
| 139 | } | ||
| 140 | |||
| 141 | void AppletManager::SetDefaultAppletFrontendSet() { | ||
| 142 | frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); | ||
| 143 | frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); | ||
| 144 | frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); | ||
| 145 | frontend.software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); | ||
| 146 | frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); | ||
| 147 | } | ||
| 148 | |||
| 149 | void AppletManager::SetDefaultAppletsIfMissing() { | ||
| 150 | if (frontend.error == nullptr) { | ||
| 151 | frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); | ||
| 152 | } | ||
| 153 | |||
| 154 | if (frontend.photo_viewer == nullptr) { | ||
| 155 | frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); | ||
| 156 | } | ||
| 157 | |||
| 158 | if (frontend.profile_select == nullptr) { | ||
| 159 | frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); | ||
| 160 | } | ||
| 161 | |||
| 162 | if (frontend.software_keyboard == nullptr) { | ||
| 163 | frontend.software_keyboard = | ||
| 164 | std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); | ||
| 165 | } | ||
| 166 | |||
| 167 | if (frontend.web_browser == nullptr) { | ||
| 168 | frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | void AppletManager::ClearAll() { | ||
| 173 | frontend = {}; | ||
| 174 | } | ||
| 175 | |||
| 176 | std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { | ||
| 177 | switch (id) { | ||
| 178 | case AppletId::Error: | ||
| 179 | return std::make_shared<Error>(*frontend.error); | ||
| 180 | case AppletId::ProfileSelect: | ||
| 181 | return std::make_shared<ProfileSelect>(*frontend.profile_select); | ||
| 182 | case AppletId::SoftwareKeyboard: | ||
| 183 | return std::make_shared<SoftwareKeyboard>(*frontend.software_keyboard); | ||
| 184 | case AppletId::PhotoViewer: | ||
| 185 | return std::make_shared<PhotoViewer>(*frontend.photo_viewer); | ||
| 186 | case AppletId::LibAppletOff: | ||
| 187 | return std::make_shared<WebBrowser>(*frontend.web_browser); | ||
| 188 | default: | ||
| 189 | UNIMPLEMENTED_MSG( | ||
| 190 | "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", | ||
| 191 | static_cast<u8>(id)); | ||
| 192 | return std::make_shared<StubApplet>(); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 114 | } // namespace Service::AM::Applets | 196 | } // namespace Service::AM::Applets |
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 37424c379..7f932672c 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h | |||
| @@ -12,12 +12,43 @@ | |||
| 12 | 12 | ||
| 13 | union ResultCode; | 13 | union ResultCode; |
| 14 | 14 | ||
| 15 | namespace Core::Frontend { | ||
| 16 | class ErrorApplet; | ||
| 17 | class PhotoViewerApplet; | ||
| 18 | class ProfileSelectApplet; | ||
| 19 | class SoftwareKeyboardApplet; | ||
| 20 | class WebBrowserApplet; | ||
| 21 | } // namespace Core::Frontend | ||
| 22 | |||
| 15 | namespace Service::AM { | 23 | namespace Service::AM { |
| 16 | 24 | ||
| 17 | class IStorage; | 25 | class IStorage; |
| 18 | 26 | ||
| 19 | namespace Applets { | 27 | namespace Applets { |
| 20 | 28 | ||
| 29 | enum class AppletId : u32 { | ||
| 30 | OverlayDisplay = 0x02, | ||
| 31 | QLaunch = 0x03, | ||
| 32 | Starter = 0x04, | ||
| 33 | Auth = 0x0A, | ||
| 34 | Cabinet = 0x0B, | ||
| 35 | Controller = 0x0C, | ||
| 36 | DataErase = 0x0D, | ||
| 37 | Error = 0x0E, | ||
| 38 | NetConnect = 0x0F, | ||
| 39 | ProfileSelect = 0x10, | ||
| 40 | SoftwareKeyboard = 0x11, | ||
| 41 | MiiEdit = 0x12, | ||
| 42 | LibAppletWeb = 0x13, | ||
| 43 | LibAppletShop = 0x14, | ||
| 44 | PhotoViewer = 0x15, | ||
| 45 | Settings = 0x16, | ||
| 46 | LibAppletOff = 0x17, | ||
| 47 | LibAppletWhitelisted = 0x18, | ||
| 48 | LibAppletAuth = 0x19, | ||
| 49 | MyPage = 0x1A, | ||
| 50 | }; | ||
| 51 | |||
| 21 | class AppletDataBroker final { | 52 | class AppletDataBroker final { |
| 22 | public: | 53 | public: |
| 23 | AppletDataBroker(); | 54 | AppletDataBroker(); |
| @@ -105,5 +136,29 @@ protected: | |||
| 105 | bool initialized = false; | 136 | bool initialized = false; |
| 106 | }; | 137 | }; |
| 107 | 138 | ||
| 139 | struct AppletFrontendSet { | ||
| 140 | std::unique_ptr<Core::Frontend::ErrorApplet> error; | ||
| 141 | std::unique_ptr<Core::Frontend::PhotoViewerApplet> photo_viewer; | ||
| 142 | std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_select; | ||
| 143 | std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; | ||
| 144 | std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser; | ||
| 145 | }; | ||
| 146 | |||
| 147 | class AppletManager { | ||
| 148 | public: | ||
| 149 | AppletManager(); | ||
| 150 | ~AppletManager(); | ||
| 151 | |||
| 152 | void SetAppletFrontendSet(AppletFrontendSet set); | ||
| 153 | void SetDefaultAppletFrontendSet(); | ||
| 154 | void SetDefaultAppletsIfMissing(); | ||
| 155 | void ClearAll(); | ||
| 156 | |||
| 157 | std::shared_ptr<Applet> GetApplet(AppletId id) const; | ||
| 158 | |||
| 159 | private: | ||
| 160 | AppletFrontendSet frontend; | ||
| 161 | }; | ||
| 162 | |||
| 108 | } // namespace Applets | 163 | } // namespace Applets |
| 109 | } // namespace Service::AM | 164 | } // namespace Service::AM |
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp new file mode 100644 index 000000000..04774bedc --- /dev/null +++ b/src/core/hle/service/am/applets/error.cpp | |||
| @@ -0,0 +1,182 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include <cstring> | ||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "common/string_util.h" | ||
| 10 | #include "core/core.h" | ||
| 11 | #include "core/frontend/applets/error.h" | ||
| 12 | #include "core/hle/service/am/am.h" | ||
| 13 | #include "core/hle/service/am/applets/error.h" | ||
| 14 | |||
| 15 | namespace Service::AM::Applets { | ||
| 16 | |||
| 17 | #pragma pack(push, 4) | ||
| 18 | struct ShowError { | ||
| 19 | u8 mode; | ||
| 20 | bool jump; | ||
| 21 | INSERT_PADDING_BYTES(4); | ||
| 22 | bool use_64bit_error_code; | ||
| 23 | INSERT_PADDING_BYTES(1); | ||
| 24 | u64 error_code_64; | ||
| 25 | u32 error_code_32; | ||
| 26 | }; | ||
| 27 | static_assert(sizeof(ShowError) == 0x14, "ShowError has incorrect size."); | ||
| 28 | #pragma pack(pop) | ||
| 29 | |||
| 30 | struct ShowErrorRecord { | ||
| 31 | u8 mode; | ||
| 32 | bool jump; | ||
| 33 | INSERT_PADDING_BYTES(6); | ||
| 34 | u64 error_code_64; | ||
| 35 | u64 posix_time; | ||
| 36 | }; | ||
| 37 | static_assert(sizeof(ShowErrorRecord) == 0x18, "ShowErrorRecord has incorrect size."); | ||
| 38 | |||
| 39 | struct SystemErrorArg { | ||
| 40 | u8 mode; | ||
| 41 | bool jump; | ||
| 42 | INSERT_PADDING_BYTES(6); | ||
| 43 | u64 error_code_64; | ||
| 44 | std::array<char, 8> language_code; | ||
| 45 | std::array<char, 0x800> main_text; | ||
| 46 | std::array<char, 0x800> detail_text; | ||
| 47 | }; | ||
| 48 | static_assert(sizeof(SystemErrorArg) == 0x1018, "SystemErrorArg has incorrect size."); | ||
| 49 | |||
| 50 | struct ApplicationErrorArg { | ||
| 51 | u8 mode; | ||
| 52 | bool jump; | ||
| 53 | INSERT_PADDING_BYTES(6); | ||
| 54 | u32 error_code; | ||
| 55 | std::array<char, 8> language_code; | ||
| 56 | std::array<char, 0x800> main_text; | ||
| 57 | std::array<char, 0x800> detail_text; | ||
| 58 | }; | ||
| 59 | static_assert(sizeof(ApplicationErrorArg) == 0x1014, "ApplicationErrorArg has incorrect size."); | ||
| 60 | |||
| 61 | union Error::ErrorArguments { | ||
| 62 | ShowError error; | ||
| 63 | ShowErrorRecord error_record; | ||
| 64 | SystemErrorArg system_error; | ||
| 65 | ApplicationErrorArg application_error; | ||
| 66 | }; | ||
| 67 | |||
| 68 | namespace { | ||
| 69 | template <typename T> | ||
| 70 | void CopyArgumentData(const std::vector<u8>& data, T& variable) { | ||
| 71 | ASSERT(data.size() >= sizeof(T)); | ||
| 72 | std::memcpy(&variable, data.data(), sizeof(T)); | ||
| 73 | } | ||
| 74 | |||
| 75 | ResultCode Decode64BitError(u64 error) { | ||
| 76 | const auto description = (error >> 32) & 0x1FFF; | ||
| 77 | auto module = error & 0x3FF; | ||
| 78 | if (module >= 2000) | ||
| 79 | module -= 2000; | ||
| 80 | module &= 0x1FF; | ||
| 81 | return {static_cast<ErrorModule>(module), static_cast<u32>(description)}; | ||
| 82 | } | ||
| 83 | |||
| 84 | } // Anonymous namespace | ||
| 85 | |||
| 86 | Error::Error(const Core::Frontend::ErrorApplet& frontend) : frontend(frontend) {} | ||
| 87 | |||
| 88 | Error::~Error() = default; | ||
| 89 | |||
| 90 | void Error::Initialize() { | ||
| 91 | Applet::Initialize(); | ||
| 92 | args = std::make_unique<ErrorArguments>(); | ||
| 93 | complete = false; | ||
| 94 | |||
| 95 | const auto storage = broker.PopNormalDataToApplet(); | ||
| 96 | ASSERT(storage != nullptr); | ||
| 97 | const auto data = storage->GetData(); | ||
| 98 | |||
| 99 | ASSERT(!data.empty()); | ||
| 100 | std::memcpy(&mode, data.data(), sizeof(ErrorAppletMode)); | ||
| 101 | |||
| 102 | switch (mode) { | ||
| 103 | case ErrorAppletMode::ShowError: | ||
| 104 | CopyArgumentData(data, args->error); | ||
| 105 | if (args->error.use_64bit_error_code) { | ||
| 106 | error_code = Decode64BitError(args->error.error_code_64); | ||
| 107 | } else { | ||
| 108 | error_code = ResultCode(args->error.error_code_32); | ||
| 109 | } | ||
| 110 | break; | ||
| 111 | case ErrorAppletMode::ShowSystemError: | ||
| 112 | CopyArgumentData(data, args->system_error); | ||
| 113 | error_code = ResultCode(Decode64BitError(args->system_error.error_code_64)); | ||
| 114 | break; | ||
| 115 | case ErrorAppletMode::ShowApplicationError: | ||
| 116 | CopyArgumentData(data, args->application_error); | ||
| 117 | error_code = ResultCode(args->application_error.error_code); | ||
| 118 | break; | ||
| 119 | case ErrorAppletMode::ShowErrorRecord: | ||
| 120 | CopyArgumentData(data, args->error_record); | ||
| 121 | error_code = Decode64BitError(args->error_record.error_code_64); | ||
| 122 | break; | ||
| 123 | default: | ||
| 124 | UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", static_cast<u8>(mode)); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | bool Error::TransactionComplete() const { | ||
| 129 | return complete; | ||
| 130 | } | ||
| 131 | |||
| 132 | ResultCode Error::GetStatus() const { | ||
| 133 | return RESULT_SUCCESS; | ||
| 134 | } | ||
| 135 | |||
| 136 | void Error::ExecuteInteractive() { | ||
| 137 | UNREACHABLE_MSG("Unexpected interactive applet data!"); | ||
| 138 | } | ||
| 139 | |||
| 140 | void Error::Execute() { | ||
| 141 | if (complete) { | ||
| 142 | return; | ||
| 143 | } | ||
| 144 | |||
| 145 | const auto callback = [this] { DisplayCompleted(); }; | ||
| 146 | |||
| 147 | switch (mode) { | ||
| 148 | case ErrorAppletMode::ShowError: | ||
| 149 | frontend.ShowError(error_code, callback); | ||
| 150 | break; | ||
| 151 | case ErrorAppletMode::ShowSystemError: | ||
| 152 | case ErrorAppletMode::ShowApplicationError: { | ||
| 153 | const auto system = mode == ErrorAppletMode::ShowSystemError; | ||
| 154 | const auto& main_text = | ||
| 155 | system ? args->system_error.main_text : args->application_error.main_text; | ||
| 156 | const auto& detail_text = | ||
| 157 | system ? args->system_error.detail_text : args->application_error.detail_text; | ||
| 158 | |||
| 159 | frontend.ShowCustomErrorText( | ||
| 160 | error_code, | ||
| 161 | Common::StringFromFixedZeroTerminatedBuffer(main_text.data(), main_text.size()), | ||
| 162 | Common::StringFromFixedZeroTerminatedBuffer(detail_text.data(), detail_text.size()), | ||
| 163 | callback); | ||
| 164 | break; | ||
| 165 | } | ||
| 166 | case ErrorAppletMode::ShowErrorRecord: | ||
| 167 | frontend.ShowErrorWithTimestamp( | ||
| 168 | error_code, std::chrono::seconds{args->error_record.posix_time}, callback); | ||
| 169 | break; | ||
| 170 | default: | ||
| 171 | UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", static_cast<u8>(mode)); | ||
| 172 | DisplayCompleted(); | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | void Error::DisplayCompleted() { | ||
| 177 | complete = true; | ||
| 178 | broker.PushNormalDataFromApplet(IStorage{{}}); | ||
| 179 | broker.SignalStateChanged(); | ||
| 180 | } | ||
| 181 | |||
| 182 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/applets/error.h b/src/core/hle/service/am/applets/error.h new file mode 100644 index 000000000..a3590d181 --- /dev/null +++ b/src/core/hle/service/am/applets/error.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/result.h" | ||
| 8 | #include "core/hle/service/am/applets/applets.h" | ||
| 9 | |||
| 10 | namespace Service::AM::Applets { | ||
| 11 | |||
| 12 | enum class ErrorAppletMode : u8 { | ||
| 13 | ShowError = 0, | ||
| 14 | ShowSystemError = 1, | ||
| 15 | ShowApplicationError = 2, | ||
| 16 | ShowEula = 3, | ||
| 17 | ShowErrorPctl = 4, | ||
| 18 | ShowErrorRecord = 5, | ||
| 19 | ShowUpdateEula = 8, | ||
| 20 | }; | ||
| 21 | |||
| 22 | class Error final : public Applet { | ||
| 23 | public: | ||
| 24 | explicit Error(const Core::Frontend::ErrorApplet& frontend); | ||
| 25 | ~Error() override; | ||
| 26 | |||
| 27 | void Initialize() override; | ||
| 28 | |||
| 29 | bool TransactionComplete() const override; | ||
| 30 | ResultCode GetStatus() const override; | ||
| 31 | void ExecuteInteractive() override; | ||
| 32 | void Execute() override; | ||
| 33 | |||
| 34 | void DisplayCompleted(); | ||
| 35 | |||
| 36 | private: | ||
| 37 | union ErrorArguments; | ||
| 38 | |||
| 39 | const Core::Frontend::ErrorApplet& frontend; | ||
| 40 | ResultCode error_code = RESULT_SUCCESS; | ||
| 41 | ErrorAppletMode mode = ErrorAppletMode::ShowError; | ||
| 42 | std::unique_ptr<ErrorArguments> args; | ||
| 43 | |||
| 44 | bool complete = false; | ||
| 45 | }; | ||
| 46 | |||
| 47 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/applets/stub_applet.cpp b/src/core/hle/service/am/applets/general_backend.cpp index ed166b87d..c591b9ac2 100644 --- a/src/core/hle/service/am/applets/stub_applet.cpp +++ b/src/core/hle/service/am/applets/general_backend.cpp | |||
| @@ -4,11 +4,15 @@ | |||
| 4 | 4 | ||
| 5 | #include <string> | 5 | #include <string> |
| 6 | 6 | ||
| 7 | #include "common/assert.h" | ||
| 7 | #include "common/hex_util.h" | 8 | #include "common/hex_util.h" |
| 8 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "core/core.h" | ||
| 11 | #include "core/frontend/applets/general_frontend.h" | ||
| 12 | #include "core/hle/kernel/process.h" | ||
| 9 | #include "core/hle/result.h" | 13 | #include "core/hle/result.h" |
| 10 | #include "core/hle/service/am/am.h" | 14 | #include "core/hle/service/am/am.h" |
| 11 | #include "core/hle/service/am/applets/stub_applet.h" | 15 | #include "core/hle/service/am/applets/general_backend.h" |
| 12 | 16 | ||
| 13 | namespace Service::AM::Applets { | 17 | namespace Service::AM::Applets { |
| 14 | 18 | ||
| @@ -30,6 +34,55 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string prefix) { | |||
| 30 | } | 34 | } |
| 31 | } | 35 | } |
| 32 | 36 | ||
| 37 | PhotoViewer::PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend) : frontend(frontend) {} | ||
| 38 | |||
| 39 | PhotoViewer::~PhotoViewer() = default; | ||
| 40 | |||
| 41 | void PhotoViewer::Initialize() { | ||
| 42 | Applet::Initialize(); | ||
| 43 | complete = false; | ||
| 44 | |||
| 45 | const auto storage = broker.PopNormalDataToApplet(); | ||
| 46 | ASSERT(storage != nullptr); | ||
| 47 | const auto data = storage->GetData(); | ||
| 48 | ASSERT(!data.empty()); | ||
| 49 | mode = static_cast<PhotoViewerAppletMode>(data[0]); | ||
| 50 | } | ||
| 51 | |||
| 52 | bool PhotoViewer::TransactionComplete() const { | ||
| 53 | return complete; | ||
| 54 | } | ||
| 55 | |||
| 56 | ResultCode PhotoViewer::GetStatus() const { | ||
| 57 | return RESULT_SUCCESS; | ||
| 58 | } | ||
| 59 | |||
| 60 | void PhotoViewer::ExecuteInteractive() { | ||
| 61 | UNREACHABLE_MSG("Unexpected interactive applet data."); | ||
| 62 | } | ||
| 63 | |||
| 64 | void PhotoViewer::Execute() { | ||
| 65 | if (complete) | ||
| 66 | return; | ||
| 67 | |||
| 68 | const auto callback = [this] { ViewFinished(); }; | ||
| 69 | switch (mode) { | ||
| 70 | case PhotoViewerAppletMode::CurrentApp: | ||
| 71 | frontend.ShowPhotosForApplication(Core::CurrentProcess()->GetTitleID(), callback); | ||
| 72 | break; | ||
| 73 | case PhotoViewerAppletMode::AllApps: | ||
| 74 | frontend.ShowAllPhotos(callback); | ||
| 75 | break; | ||
| 76 | default: | ||
| 77 | UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", static_cast<u8>(mode)); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | void PhotoViewer::ViewFinished() { | ||
| 82 | broker.PushNormalDataFromApplet(IStorage{{}}); | ||
| 83 | broker.SignalStateChanged(); | ||
| 84 | } | ||
| 85 | |||
| 33 | StubApplet::StubApplet() = default; | 86 | StubApplet::StubApplet() = default; |
| 34 | 87 | ||
| 35 | StubApplet::~StubApplet() = default; | 88 | StubApplet::~StubApplet() = default; |
| @@ -67,4 +120,5 @@ void StubApplet::Execute() { | |||
| 67 | broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)}); | 120 | broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)}); |
| 68 | broker.SignalStateChanged(); | 121 | broker.SignalStateChanged(); |
| 69 | } | 122 | } |
| 123 | |||
| 70 | } // namespace Service::AM::Applets | 124 | } // namespace Service::AM::Applets |
diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h new file mode 100644 index 000000000..2dd255d7c --- /dev/null +++ b/src/core/hle/service/am/applets/general_backend.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/am/applets/applets.h" | ||
| 8 | |||
| 9 | namespace Service::AM::Applets { | ||
| 10 | |||
| 11 | enum class PhotoViewerAppletMode : u8 { | ||
| 12 | CurrentApp = 0, | ||
| 13 | AllApps = 1, | ||
| 14 | }; | ||
| 15 | |||
| 16 | class PhotoViewer final : public Applet { | ||
| 17 | public: | ||
| 18 | explicit PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend); | ||
| 19 | ~PhotoViewer() override; | ||
| 20 | |||
| 21 | void Initialize() override; | ||
| 22 | bool TransactionComplete() const override; | ||
| 23 | ResultCode GetStatus() const override; | ||
| 24 | void ExecuteInteractive() override; | ||
| 25 | void Execute() override; | ||
| 26 | |||
| 27 | void ViewFinished(); | ||
| 28 | |||
| 29 | private: | ||
| 30 | const Core::Frontend::PhotoViewerApplet& frontend; | ||
| 31 | bool complete = false; | ||
| 32 | PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; | ||
| 33 | }; | ||
| 34 | |||
| 35 | class StubApplet final : public Applet { | ||
| 36 | public: | ||
| 37 | StubApplet(); | ||
| 38 | ~StubApplet() override; | ||
| 39 | |||
| 40 | void Initialize() override; | ||
| 41 | |||
| 42 | bool TransactionComplete() const override; | ||
| 43 | ResultCode GetStatus() const override; | ||
| 44 | void ExecuteInteractive() override; | ||
| 45 | void Execute() override; | ||
| 46 | }; | ||
| 47 | |||
| 48 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp index 14e2a1fee..d113bd2eb 100644 --- a/src/core/hle/service/am/applets/profile_select.cpp +++ b/src/core/hle/service/am/applets/profile_select.cpp | |||
| @@ -15,7 +15,9 @@ namespace Service::AM::Applets { | |||
| 15 | 15 | ||
| 16 | constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; | 16 | constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; |
| 17 | 17 | ||
| 18 | ProfileSelect::ProfileSelect() = default; | 18 | ProfileSelect::ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend) |
| 19 | : frontend(frontend) {} | ||
| 20 | |||
| 19 | ProfileSelect::~ProfileSelect() = default; | 21 | ProfileSelect::~ProfileSelect() = default; |
| 20 | 22 | ||
| 21 | void ProfileSelect::Initialize() { | 23 | void ProfileSelect::Initialize() { |
| @@ -51,8 +53,6 @@ void ProfileSelect::Execute() { | |||
| 51 | return; | 53 | return; |
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | const auto& frontend{Core::System::GetInstance().GetProfileSelector()}; | ||
| 55 | |||
| 56 | frontend.SelectProfile([this](std::optional<Account::UUID> uuid) { SelectionComplete(uuid); }); | 56 | frontend.SelectProfile([this](std::optional<Account::UUID> uuid) { SelectionComplete(uuid); }); |
| 57 | } | 57 | } |
| 58 | 58 | ||
diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h index 787485f22..a2ac6cf50 100644 --- a/src/core/hle/service/am/applets/profile_select.h +++ b/src/core/hle/service/am/applets/profile_select.h | |||
| @@ -28,7 +28,7 @@ static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has inco | |||
| 28 | 28 | ||
| 29 | class ProfileSelect final : public Applet { | 29 | class ProfileSelect final : public Applet { |
| 30 | public: | 30 | public: |
| 31 | ProfileSelect(); | 31 | explicit ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend); |
| 32 | ~ProfileSelect() override; | 32 | ~ProfileSelect() override; |
| 33 | 33 | ||
| 34 | void Initialize() override; | 34 | void Initialize() override; |
| @@ -41,6 +41,8 @@ public: | |||
| 41 | void SelectionComplete(std::optional<Account::UUID> uuid); | 41 | void SelectionComplete(std::optional<Account::UUID> uuid); |
| 42 | 42 | ||
| 43 | private: | 43 | private: |
| 44 | const Core::Frontend::ProfileSelectApplet& frontend; | ||
| 45 | |||
| 44 | UserSelectionConfig config; | 46 | UserSelectionConfig config; |
| 45 | bool complete = false; | 47 | bool complete = false; |
| 46 | ResultCode status = RESULT_SUCCESS; | 48 | ResultCode status = RESULT_SUCCESS; |
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 8c5bd6059..e197990f7 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp | |||
| @@ -39,7 +39,8 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( | |||
| 39 | return params; | 39 | return params; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | SoftwareKeyboard::SoftwareKeyboard() = default; | 42 | SoftwareKeyboard::SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend) |
| 43 | : frontend(frontend) {} | ||
| 43 | 44 | ||
| 44 | SoftwareKeyboard::~SoftwareKeyboard() = default; | 45 | SoftwareKeyboard::~SoftwareKeyboard() = default; |
| 45 | 46 | ||
| @@ -90,8 +91,6 @@ void SoftwareKeyboard::ExecuteInteractive() { | |||
| 90 | if (status == INTERACTIVE_STATUS_OK) { | 91 | if (status == INTERACTIVE_STATUS_OK) { |
| 91 | complete = true; | 92 | complete = true; |
| 92 | } else { | 93 | } else { |
| 93 | const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()}; | ||
| 94 | |||
| 95 | std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; | 94 | std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; |
| 96 | std::memcpy(string.data(), data.data() + 4, string.size() * 2); | 95 | std::memcpy(string.data(), data.data() + 4, string.size() * 2); |
| 97 | frontend.SendTextCheckDialog( | 96 | frontend.SendTextCheckDialog( |
| @@ -106,8 +105,6 @@ void SoftwareKeyboard::Execute() { | |||
| 106 | return; | 105 | return; |
| 107 | } | 106 | } |
| 108 | 107 | ||
| 109 | const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()}; | ||
| 110 | |||
| 111 | const auto parameters = ConvertToFrontendParameters(config, initial_text); | 108 | const auto parameters = ConvertToFrontendParameters(config, initial_text); |
| 112 | 109 | ||
| 113 | frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); }, | 110 | frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); }, |
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index b93a30d28..0fbc43e51 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h | |||
| @@ -55,7 +55,7 @@ static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect siz | |||
| 55 | 55 | ||
| 56 | class SoftwareKeyboard final : public Applet { | 56 | class SoftwareKeyboard final : public Applet { |
| 57 | public: | 57 | public: |
| 58 | SoftwareKeyboard(); | 58 | explicit SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend); |
| 59 | ~SoftwareKeyboard() override; | 59 | ~SoftwareKeyboard() override; |
| 60 | 60 | ||
| 61 | void Initialize() override; | 61 | void Initialize() override; |
| @@ -68,6 +68,8 @@ public: | |||
| 68 | void WriteText(std::optional<std::u16string> text); | 68 | void WriteText(std::optional<std::u16string> text); |
| 69 | 69 | ||
| 70 | private: | 70 | private: |
| 71 | const Core::Frontend::SoftwareKeyboardApplet& frontend; | ||
| 72 | |||
| 71 | KeyboardConfig config; | 73 | KeyboardConfig config; |
| 72 | std::u16string initial_text; | 74 | std::u16string initial_text; |
| 73 | bool complete = false; | 75 | bool complete = false; |
diff --git a/src/core/hle/service/am/applets/stub_applet.h b/src/core/hle/service/am/applets/stub_applet.h deleted file mode 100644 index 7d8dc968d..000000000 --- a/src/core/hle/service/am/applets/stub_applet.h +++ /dev/null | |||
| @@ -1,24 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/am/applets/applets.h" | ||
| 8 | |||
| 9 | namespace Service::AM::Applets { | ||
| 10 | |||
| 11 | class StubApplet final : public Applet { | ||
| 12 | public: | ||
| 13 | StubApplet(); | ||
| 14 | ~StubApplet() override; | ||
| 15 | |||
| 16 | void Initialize() override; | ||
| 17 | |||
| 18 | bool TransactionComplete() const override; | ||
| 19 | ResultCode GetStatus() const override; | ||
| 20 | void ExecuteInteractive() override; | ||
| 21 | void Execute() override; | ||
| 22 | }; | ||
| 23 | |||
| 24 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 7e17df98a..7878f5136 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp | |||
| @@ -95,7 +95,7 @@ static FileSys::VirtualFile GetManualRomFS() { | |||
| 95 | return nullptr; | 95 | return nullptr; |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | WebBrowser::WebBrowser() = default; | 98 | WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend) : frontend(frontend) {} |
| 99 | 99 | ||
| 100 | WebBrowser::~WebBrowser() = default; | 100 | WebBrowser::~WebBrowser() = default; |
| 101 | 101 | ||
| @@ -152,8 +152,6 @@ void WebBrowser::Execute() { | |||
| 152 | return; | 152 | return; |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | auto& frontend{Core::System::GetInstance().GetWebBrowser()}; | ||
| 156 | |||
| 157 | frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); | 155 | frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); |
| 158 | } | 156 | } |
| 159 | 157 | ||
diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index b9e228fac..7e0f34c7d 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h | |||
| @@ -12,7 +12,7 @@ namespace Service::AM::Applets { | |||
| 12 | 12 | ||
| 13 | class WebBrowser final : public Applet { | 13 | class WebBrowser final : public Applet { |
| 14 | public: | 14 | public: |
| 15 | WebBrowser(); | 15 | WebBrowser(Core::Frontend::WebBrowserApplet& frontend); |
| 16 | ~WebBrowser() override; | 16 | ~WebBrowser() override; |
| 17 | 17 | ||
| 18 | void Initialize() override; | 18 | void Initialize() override; |
| @@ -32,6 +32,8 @@ public: | |||
| 32 | void Finalize(); | 32 | void Finalize(); |
| 33 | 33 | ||
| 34 | private: | 34 | private: |
| 35 | Core::Frontend::WebBrowserApplet& frontend; | ||
| 36 | |||
| 35 | bool complete = false; | 37 | bool complete = false; |
| 36 | bool unpacked = false; | 38 | bool unpacked = false; |
| 37 | ResultCode status = RESULT_SUCCESS; | 39 | ResultCode status = RESULT_SUCCESS; |
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 2d768d9fc..51d8c26b4 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp | |||
| @@ -50,6 +50,7 @@ static std::vector<u64> AccumulateAOCTitleIDs() { | |||
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs()) { | 52 | AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs()) { |
| 53 | // clang-format off | ||
| 53 | static const FunctionInfo functions[] = { | 54 | static const FunctionInfo functions[] = { |
| 54 | {0, nullptr, "CountAddOnContentByApplicationId"}, | 55 | {0, nullptr, "CountAddOnContentByApplicationId"}, |
| 55 | {1, nullptr, "ListAddOnContentByApplicationId"}, | 56 | {1, nullptr, "ListAddOnContentByApplicationId"}, |
| @@ -60,7 +61,10 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs | |||
| 60 | {6, nullptr, "PrepareAddOnContentByApplicationId"}, | 61 | {6, nullptr, "PrepareAddOnContentByApplicationId"}, |
| 61 | {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"}, | 62 | {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"}, |
| 62 | {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"}, | 63 | {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"}, |
| 64 | {100, nullptr, "CreateEcPurchasedEventManager"}, | ||
| 63 | }; | 65 | }; |
| 66 | // clang-format on | ||
| 67 | |||
| 64 | RegisterHandlers(functions); | 68 | RegisterHandlers(functions); |
| 65 | 69 | ||
| 66 | auto& kernel = Core::System::GetInstance().Kernel(); | 70 | auto& kernel = Core::System::GetInstance().Kernel(); |
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp index fcacbab72..d058c0245 100644 --- a/src/core/hle/service/apm/interface.cpp +++ b/src/core/hle/service/apm/interface.cpp | |||
| @@ -87,6 +87,8 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { | |||
| 87 | {3, nullptr, "GetLastThrottlingState"}, | 87 | {3, nullptr, "GetLastThrottlingState"}, |
| 88 | {4, nullptr, "ClearLastThrottlingState"}, | 88 | {4, nullptr, "ClearLastThrottlingState"}, |
| 89 | {5, nullptr, "LoadAndApplySettings"}, | 89 | {5, nullptr, "LoadAndApplySettings"}, |
| 90 | {6, nullptr, "SetCpuBoostMode"}, | ||
| 91 | {7, nullptr, "GetCurrentPerformanceConfiguration"}, | ||
| 90 | }; | 92 | }; |
| 91 | // clang-format on | 93 | // clang-format on |
| 92 | 94 | ||
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp index b6b71f966..f43e512e9 100644 --- a/src/core/hle/service/audio/audctl.cpp +++ b/src/core/hle/service/audio/audctl.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | ||
| 5 | #include "core/hle/service/audio/audctl.h" | 7 | #include "core/hle/service/audio/audctl.h" |
| 6 | 8 | ||
| 7 | namespace Service::Audio { | 9 | namespace Service::Audio { |
| @@ -11,8 +13,8 @@ AudCtl::AudCtl() : ServiceFramework{"audctl"} { | |||
| 11 | static const FunctionInfo functions[] = { | 13 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "GetTargetVolume"}, | 14 | {0, nullptr, "GetTargetVolume"}, |
| 13 | {1, nullptr, "SetTargetVolume"}, | 15 | {1, nullptr, "SetTargetVolume"}, |
| 14 | {2, nullptr, "GetTargetVolumeMin"}, | 16 | {2, &AudCtl::GetTargetVolumeMin, "GetTargetVolumeMin"}, |
| 15 | {3, nullptr, "GetTargetVolumeMax"}, | 17 | {3, &AudCtl::GetTargetVolumeMax, "GetTargetVolumeMax"}, |
| 16 | {4, nullptr, "IsTargetMute"}, | 18 | {4, nullptr, "IsTargetMute"}, |
| 17 | {5, nullptr, "SetTargetMute"}, | 19 | {5, nullptr, "SetTargetMute"}, |
| 18 | {6, nullptr, "IsTargetConnected"}, | 20 | {6, nullptr, "IsTargetConnected"}, |
| @@ -44,4 +46,28 @@ AudCtl::AudCtl() : ServiceFramework{"audctl"} { | |||
| 44 | 46 | ||
| 45 | AudCtl::~AudCtl() = default; | 47 | AudCtl::~AudCtl() = default; |
| 46 | 48 | ||
| 49 | void AudCtl::GetTargetVolumeMin(Kernel::HLERequestContext& ctx) { | ||
| 50 | LOG_DEBUG(Audio, "called."); | ||
| 51 | |||
| 52 | // This service function is currently hardcoded on the | ||
| 53 | // actual console to this value (as of 6.0.0). | ||
| 54 | constexpr s32 target_min_volume = 0; | ||
| 55 | |||
| 56 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 57 | rb.Push(RESULT_SUCCESS); | ||
| 58 | rb.Push(target_min_volume); | ||
| 59 | } | ||
| 60 | |||
| 61 | void AudCtl::GetTargetVolumeMax(Kernel::HLERequestContext& ctx) { | ||
| 62 | LOG_DEBUG(Audio, "called."); | ||
| 63 | |||
| 64 | // This service function is currently hardcoded on the | ||
| 65 | // actual console to this value (as of 6.0.0). | ||
| 66 | constexpr s32 target_max_volume = 15; | ||
| 67 | |||
| 68 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 69 | rb.Push(RESULT_SUCCESS); | ||
| 70 | rb.Push(target_max_volume); | ||
| 71 | } | ||
| 72 | |||
| 47 | } // namespace Service::Audio | 73 | } // namespace Service::Audio |
diff --git a/src/core/hle/service/audio/audctl.h b/src/core/hle/service/audio/audctl.h index 9d2d9e83b..c7fafc02e 100644 --- a/src/core/hle/service/audio/audctl.h +++ b/src/core/hle/service/audio/audctl.h | |||
| @@ -12,6 +12,10 @@ class AudCtl final : public ServiceFramework<AudCtl> { | |||
| 12 | public: | 12 | public: |
| 13 | explicit AudCtl(); | 13 | explicit AudCtl(); |
| 14 | ~AudCtl() override; | 14 | ~AudCtl() override; |
| 15 | |||
| 16 | private: | ||
| 17 | void GetTargetVolumeMin(Kernel::HLERequestContext& ctx); | ||
| 18 | void GetTargetVolumeMax(Kernel::HLERequestContext& ctx); | ||
| 15 | }; | 19 | }; |
| 16 | 20 | ||
| 17 | } // namespace Service::Audio | 21 | } // namespace Service::Audio |
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index e5daefdde..d7f1d348d 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp | |||
| @@ -25,6 +25,7 @@ public: | |||
| 25 | {11, nullptr, "GetAudioInBufferCount"}, | 25 | {11, nullptr, "GetAudioInBufferCount"}, |
| 26 | {12, nullptr, "SetAudioInDeviceGain"}, | 26 | {12, nullptr, "SetAudioInDeviceGain"}, |
| 27 | {13, nullptr, "GetAudioInDeviceGain"}, | 27 | {13, nullptr, "GetAudioInDeviceGain"}, |
| 28 | {14, nullptr, "FlushAudioInBuffers"}, | ||
| 28 | }; | 29 | }; |
| 29 | // clang-format on | 30 | // clang-format on |
| 30 | 31 | ||
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 39acb7b23..12875fb42 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp | |||
| @@ -44,7 +44,7 @@ public: | |||
| 44 | std::string&& unique_name) | 44 | std::string&& unique_name) |
| 45 | : ServiceFramework("IAudioOut"), audio_core(audio_core), | 45 | : ServiceFramework("IAudioOut"), audio_core(audio_core), |
| 46 | device_name(std::move(device_name)), audio_params(audio_params) { | 46 | device_name(std::move(device_name)), audio_params(audio_params) { |
| 47 | 47 | // clang-format off | |
| 48 | static const FunctionInfo functions[] = { | 48 | static const FunctionInfo functions[] = { |
| 49 | {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, | 49 | {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, |
| 50 | {1, &IAudioOut::StartAudioOut, "StartAudioOut"}, | 50 | {1, &IAudioOut::StartAudioOut, "StartAudioOut"}, |
| @@ -58,7 +58,10 @@ public: | |||
| 58 | {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"}, | 58 | {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"}, |
| 59 | {10, nullptr, "GetAudioOutPlayedSampleCount"}, | 59 | {10, nullptr, "GetAudioOutPlayedSampleCount"}, |
| 60 | {11, nullptr, "FlushAudioOutBuffers"}, | 60 | {11, nullptr, "FlushAudioOutBuffers"}, |
| 61 | {12, nullptr, "SetAudioOutVolume"}, | ||
| 62 | {13, nullptr, "GetAudioOutVolume"}, | ||
| 61 | }; | 63 | }; |
| 64 | // clang-format on | ||
| 62 | RegisterHandlers(functions); | 65 | RegisterHandlers(functions); |
| 63 | 66 | ||
| 64 | // This is the event handle used to check if the audio buffer was released | 67 | // This is the event handle used to check if the audio buffer was released |
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index 59ef603e1..974ff8e1a 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp | |||
| @@ -154,7 +154,8 @@ public: | |||
| 154 | {96, nullptr, "GetLeHidEventInfo"}, | 154 | {96, nullptr, "GetLeHidEventInfo"}, |
| 155 | {97, nullptr, "RegisterBleHidEvent"}, | 155 | {97, nullptr, "RegisterBleHidEvent"}, |
| 156 | {98, nullptr, "SetLeScanParameter"}, | 156 | {98, nullptr, "SetLeScanParameter"}, |
| 157 | {256, nullptr, "GetIsManufacturingMode"} | 157 | {256, nullptr, "GetIsManufacturingMode"}, |
| 158 | {257, nullptr, "EmulateBluetoothCrash"}, | ||
| 158 | }; | 159 | }; |
| 159 | // clang-format on | 160 | // clang-format on |
| 160 | 161 | ||
diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp index ae7b0720b..907f464ab 100644 --- a/src/core/hle/service/caps/caps.cpp +++ b/src/core/hle/service/caps/caps.cpp | |||
| @@ -15,32 +15,41 @@ public: | |||
| 15 | explicit CAPS_A() : ServiceFramework{"caps:a"} { | 15 | explicit CAPS_A() : ServiceFramework{"caps:a"} { |
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {0, nullptr, "Unknown1"}, | 18 | {0, nullptr, "GetAlbumFileCount"}, |
| 19 | {1, nullptr, "Unknown2"}, | 19 | {1, nullptr, "GetAlbumFileList"}, |
| 20 | {2, nullptr, "Unknown3"}, | 20 | {2, nullptr, "LoadAlbumFile"}, |
| 21 | {3, nullptr, "Unknown4"}, | 21 | {3, nullptr, "DeleteAlbumFile"}, |
| 22 | {4, nullptr, "Unknown5"}, | 22 | {4, nullptr, "StorageCopyAlbumFile"}, |
| 23 | {5, nullptr, "Unknown6"}, | 23 | {5, nullptr, "IsAlbumMounted"}, |
| 24 | {6, nullptr, "Unknown7"}, | 24 | {6, nullptr, "GetAlbumUsage"}, |
| 25 | {7, nullptr, "Unknown8"}, | 25 | {7, nullptr, "GetAlbumFileSize"}, |
| 26 | {8, nullptr, "Unknown9"}, | 26 | {8, nullptr, "LoadAlbumFileThumbnail"}, |
| 27 | {9, nullptr, "Unknown10"}, | 27 | {9, nullptr, "LoadAlbumScreenShotImage"}, |
| 28 | {10, nullptr, "Unknown11"}, | 28 | {10, nullptr, "LoadAlbumScreenShotThumbnailImage"}, |
| 29 | {11, nullptr, "Unknown12"}, | 29 | {11, nullptr, "GetAlbumEntryFromApplicationAlbumEntry"}, |
| 30 | {12, nullptr, "Unknown13"}, | 30 | {12, nullptr, "Unknown12"}, |
| 31 | {13, nullptr, "Unknown14"}, | 31 | {13, nullptr, "Unknown13"}, |
| 32 | {14, nullptr, "Unknown15"}, | 32 | {14, nullptr, "Unknown14"}, |
| 33 | {301, nullptr, "Unknown16"}, | 33 | {15, nullptr, "Unknown15"}, |
| 34 | {401, nullptr, "Unknown17"}, | 34 | {16, nullptr, "Unknown16"}, |
| 35 | {501, nullptr, "Unknown18"}, | 35 | {17, nullptr, "Unknown17"}, |
| 36 | {1001, nullptr, "Unknown19"}, | 36 | {18, nullptr, "Unknown18"}, |
| 37 | {1002, nullptr, "Unknown20"}, | 37 | {202, nullptr, "SaveEditedScreenShot"}, |
| 38 | {8001, nullptr, "Unknown21"}, | 38 | {301, nullptr, "GetLastThumbnail"}, |
| 39 | {8002, nullptr, "Unknown22"}, | 39 | {401, nullptr, "GetAutoSavingStorage"}, |
| 40 | {8011, nullptr, "Unknown23"}, | 40 | {501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"}, |
| 41 | {8012, nullptr, "Unknown24"}, | 41 | {1001, nullptr, "Unknown1001"}, |
| 42 | {8021, nullptr, "Unknown25"}, | 42 | {1002, nullptr, "Unknown1002"}, |
| 43 | {10011, nullptr, "Unknown26"}, | 43 | {1003, nullptr, "Unknown1003"}, |
| 44 | {8001, nullptr, "ForceAlbumUnmounted"}, | ||
| 45 | {8002, nullptr, "ResetAlbumMountStatus"}, | ||
| 46 | {8011, nullptr, "RefreshAlbumCache"}, | ||
| 47 | {8012, nullptr, "GetAlbumCache"}, | ||
| 48 | {8013, nullptr, "Unknown8013"}, | ||
| 49 | {8021, nullptr, "GetAlbumEntryFromApplicationAlbumEntryAruid"}, | ||
| 50 | {10011, nullptr, "SetInternalErrorConversionEnabled"}, | ||
| 51 | {50000, nullptr, "Unknown50000"}, | ||
| 52 | {60002, nullptr, "Unknown60002"}, | ||
| 44 | }; | 53 | }; |
| 45 | // clang-format on | 54 | // clang-format on |
| 46 | 55 | ||
| @@ -53,16 +62,17 @@ public: | |||
| 53 | explicit CAPS_C() : ServiceFramework{"caps:c"} { | 62 | explicit CAPS_C() : ServiceFramework{"caps:c"} { |
| 54 | // clang-format off | 63 | // clang-format off |
| 55 | static const FunctionInfo functions[] = { | 64 | static const FunctionInfo functions[] = { |
| 56 | {2001, nullptr, "Unknown1"}, | 65 | {33, nullptr, "Unknown33"}, |
| 57 | {2002, nullptr, "Unknown2"}, | 66 | {2001, nullptr, "Unknown2001"}, |
| 58 | {2011, nullptr, "Unknown3"}, | 67 | {2002, nullptr, "Unknown2002"}, |
| 59 | {2012, nullptr, "Unknown4"}, | 68 | {2011, nullptr, "Unknown2011"}, |
| 60 | {2013, nullptr, "Unknown5"}, | 69 | {2012, nullptr, "Unknown2012"}, |
| 61 | {2014, nullptr, "Unknown6"}, | 70 | {2013, nullptr, "Unknown2013"}, |
| 62 | {2101, nullptr, "Unknown7"}, | 71 | {2014, nullptr, "Unknown2014"}, |
| 63 | {2102, nullptr, "Unknown8"}, | 72 | {2101, nullptr, "Unknown2101"}, |
| 64 | {2201, nullptr, "Unknown9"}, | 73 | {2102, nullptr, "Unknown2102"}, |
| 65 | {2301, nullptr, "Unknown10"}, | 74 | {2201, nullptr, "Unknown2201"}, |
| 75 | {2301, nullptr, "Unknown2301"}, | ||
| 66 | }; | 76 | }; |
| 67 | // clang-format on | 77 | // clang-format on |
| 68 | 78 | ||
| @@ -127,11 +137,18 @@ public: | |||
| 127 | explicit CAPS_U() : ServiceFramework{"caps:u"} { | 137 | explicit CAPS_U() : ServiceFramework{"caps:u"} { |
| 128 | // clang-format off | 138 | // clang-format off |
| 129 | static const FunctionInfo functions[] = { | 139 | static const FunctionInfo functions[] = { |
| 140 | {32, nullptr, "SetShimLibraryVersion"}, | ||
| 130 | {102, nullptr, "GetAlbumFileListByAruid"}, | 141 | {102, nullptr, "GetAlbumFileListByAruid"}, |
| 131 | {103, nullptr, "DeleteAlbumFileByAruid"}, | 142 | {103, nullptr, "DeleteAlbumFileByAruid"}, |
| 132 | {104, nullptr, "GetAlbumFileSizeByAruid"}, | 143 | {104, nullptr, "GetAlbumFileSizeByAruid"}, |
| 144 | {105, nullptr, "DeleteAlbumFileByAruidForDebug"}, | ||
| 133 | {110, nullptr, "LoadAlbumScreenShotImageByAruid"}, | 145 | {110, nullptr, "LoadAlbumScreenShotImageByAruid"}, |
| 134 | {120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"}, | 146 | {120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"}, |
| 147 | {130, nullptr, "PrecheckToCreateContentsByAruid"}, | ||
| 148 | {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, | ||
| 149 | {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, | ||
| 150 | {142, nullptr, "GetAlbumFileList3AaeAruid"}, | ||
| 151 | {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, | ||
| 135 | {60002, nullptr, "OpenAccessorSessionForApplication"}, | 152 | {60002, nullptr, "OpenAccessorSessionForApplication"}, |
| 136 | }; | 153 | }; |
| 137 | // clang-format on | 154 | // clang-format on |
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 0249b6992..e7df8fd98 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -664,10 +664,13 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { | |||
| 664 | {100, nullptr, "OpenImageDirectoryFileSystem"}, | 664 | {100, nullptr, "OpenImageDirectoryFileSystem"}, |
| 665 | {110, nullptr, "OpenContentStorageFileSystem"}, | 665 | {110, nullptr, "OpenContentStorageFileSystem"}, |
| 666 | {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"}, | 666 | {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"}, |
| 667 | {130, nullptr, "OpenCustomStorageFileSystem"}, | ||
| 667 | {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, | 668 | {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, |
| 668 | {201, nullptr, "OpenDataStorageByProgramId"}, | 669 | {201, nullptr, "OpenDataStorageByProgramId"}, |
| 669 | {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"}, | 670 | {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"}, |
| 670 | {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, | 671 | {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, |
| 672 | {204, nullptr, "OpenDataFileSystemByProgramIndex"}, | ||
| 673 | {205, nullptr, "OpenDataStorageByProgramIndex"}, | ||
| 671 | {400, nullptr, "OpenDeviceOperator"}, | 674 | {400, nullptr, "OpenDeviceOperator"}, |
| 672 | {500, nullptr, "OpenSdCardDetectionEventNotifier"}, | 675 | {500, nullptr, "OpenSdCardDetectionEventNotifier"}, |
| 673 | {501, nullptr, "OpenGameCardDetectionEventNotifier"}, | 676 | {501, nullptr, "OpenGameCardDetectionEventNotifier"}, |
| @@ -691,6 +694,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { | |||
| 691 | {614, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId"}, | 694 | {614, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId"}, |
| 692 | {615, nullptr, "QuerySaveDataInternalStorageTotalSize"}, | 695 | {615, nullptr, "QuerySaveDataInternalStorageTotalSize"}, |
| 693 | {616, nullptr, "GetSaveDataCommitId"}, | 696 | {616, nullptr, "GetSaveDataCommitId"}, |
| 697 | {617, nullptr, "UnregisterExternalKey"}, | ||
| 694 | {620, nullptr, "SetSdCardEncryptionSeed"}, | 698 | {620, nullptr, "SetSdCardEncryptionSeed"}, |
| 695 | {630, nullptr, "SetSdCardAccessibility"}, | 699 | {630, nullptr, "SetSdCardAccessibility"}, |
| 696 | {631, nullptr, "IsSdCardAccessible"}, | 700 | {631, nullptr, "IsSdCardAccessible"}, |
| @@ -701,6 +705,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { | |||
| 701 | {710, nullptr, "ResolveAccessFailure"}, | 705 | {710, nullptr, "ResolveAccessFailure"}, |
| 702 | {720, nullptr, "AbandonAccessFailure"}, | 706 | {720, nullptr, "AbandonAccessFailure"}, |
| 703 | {800, nullptr, "GetAndClearFileSystemProxyErrorInfo"}, | 707 | {800, nullptr, "GetAndClearFileSystemProxyErrorInfo"}, |
| 708 | {810, nullptr, "RegisterProgramIndexMapInfo"}, | ||
| 704 | {1000, nullptr, "SetBisRootForHost"}, | 709 | {1000, nullptr, "SetBisRootForHost"}, |
| 705 | {1001, nullptr, "SetSaveDataSize"}, | 710 | {1001, nullptr, "SetSaveDataSize"}, |
| 706 | {1002, nullptr, "SetSaveDataRootPath"}, | 711 | {1002, nullptr, "SetSaveDataRootPath"}, |
| @@ -711,6 +716,8 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { | |||
| 711 | {1007, nullptr, "RegisterUpdatePartition"}, | 716 | {1007, nullptr, "RegisterUpdatePartition"}, |
| 712 | {1008, nullptr, "OpenRegisteredUpdatePartition"}, | 717 | {1008, nullptr, "OpenRegisteredUpdatePartition"}, |
| 713 | {1009, nullptr, "GetAndClearMemoryReportInfo"}, | 718 | {1009, nullptr, "GetAndClearMemoryReportInfo"}, |
| 719 | {1010, nullptr, "SetDataStorageRedirectTarget"}, | ||
| 720 | {1011, nullptr, "OutputAccessLogToSdCard2"}, | ||
| 714 | {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, | 721 | {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, |
| 715 | {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, | 722 | {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, |
| 716 | {1200, nullptr, "OpenMultiCommitManager"}, | 723 | {1200, nullptr, "OpenMultiCommitManager"}, |
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index d9225d624..5100e376c 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -12,6 +12,7 @@ namespace Service::Friend { | |||
| 12 | class IFriendService final : public ServiceFramework<IFriendService> { | 12 | class IFriendService final : public ServiceFramework<IFriendService> { |
| 13 | public: | 13 | public: |
| 14 | IFriendService() : ServiceFramework("IFriendService") { | 14 | IFriendService() : ServiceFramework("IFriendService") { |
| 15 | // clang-format off | ||
| 15 | static const FunctionInfo functions[] = { | 16 | static const FunctionInfo functions[] = { |
| 16 | {0, nullptr, "GetCompletionEvent"}, | 17 | {0, nullptr, "GetCompletionEvent"}, |
| 17 | {1, nullptr, "Cancel"}, | 18 | {1, nullptr, "Cancel"}, |
| @@ -24,8 +25,7 @@ public: | |||
| 24 | {10400, nullptr, "GetBlockedUserListIds"}, | 25 | {10400, nullptr, "GetBlockedUserListIds"}, |
| 25 | {10500, nullptr, "GetProfileList"}, | 26 | {10500, nullptr, "GetProfileList"}, |
| 26 | {10600, nullptr, "DeclareOpenOnlinePlaySession"}, | 27 | {10600, nullptr, "DeclareOpenOnlinePlaySession"}, |
| 27 | {10601, &IFriendService::DeclareCloseOnlinePlaySession, | 28 | {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"}, |
| 28 | "DeclareCloseOnlinePlaySession"}, | ||
| 29 | {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"}, | 29 | {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"}, |
| 30 | {10700, nullptr, "GetPlayHistoryRegistrationKey"}, | 30 | {10700, nullptr, "GetPlayHistoryRegistrationKey"}, |
| 31 | {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"}, | 31 | {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"}, |
| @@ -88,6 +88,7 @@ public: | |||
| 88 | {30830, nullptr, "ClearPlayLog"}, | 88 | {30830, nullptr, "ClearPlayLog"}, |
| 89 | {49900, nullptr, "DeleteNetworkServiceAccountCache"}, | 89 | {49900, nullptr, "DeleteNetworkServiceAccountCache"}, |
| 90 | }; | 90 | }; |
| 91 | // clang-format on | ||
| 91 | 92 | ||
| 92 | RegisterHandlers(functions); | 93 | RegisterHandlers(functions); |
| 93 | } | 94 | } |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 63b55758b..a4ad95d96 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -210,6 +210,7 @@ Hid::Hid() : ServiceFramework("hid") { | |||
| 210 | {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"}, | 210 | {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"}, |
| 211 | {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, | 211 | {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, |
| 212 | {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, | 212 | {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, |
| 213 | {134, nullptr, "SetNpadAnalogStickUseCenterClamp"}, | ||
| 213 | {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, | 214 | {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, |
| 214 | {201, &Hid::SendVibrationValue, "SendVibrationValue"}, | 215 | {201, &Hid::SendVibrationValue, "SendVibrationValue"}, |
| 215 | {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, | 216 | {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, |
| @@ -221,6 +222,7 @@ Hid::Hid() : ServiceFramework("hid") { | |||
| 221 | {208, nullptr, "GetActualVibrationGcErmCommand"}, | 222 | {208, nullptr, "GetActualVibrationGcErmCommand"}, |
| 222 | {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, | 223 | {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, |
| 223 | {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, | 224 | {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, |
| 225 | {211, nullptr, "IsVibrationDeviceMounted"}, | ||
| 224 | {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, | 226 | {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, |
| 225 | {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, | 227 | {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, |
| 226 | {302, nullptr, "StopConsoleSixAxisSensor"}, | 228 | {302, nullptr, "StopConsoleSixAxisSensor"}, |
| @@ -265,6 +267,7 @@ Hid::Hid() : ServiceFramework("hid") { | |||
| 265 | {523, nullptr, "SetIsPalmaPairedConnectable"}, | 267 | {523, nullptr, "SetIsPalmaPairedConnectable"}, |
| 266 | {524, nullptr, "PairPalma"}, | 268 | {524, nullptr, "PairPalma"}, |
| 267 | {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"}, | 269 | {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"}, |
| 270 | {526, nullptr, "CancelWritePalmaWaveEntry"}, | ||
| 268 | {1000, nullptr, "SetNpadCommunicationMode"}, | 271 | {1000, nullptr, "SetNpadCommunicationMode"}, |
| 269 | {1001, nullptr, "GetNpadCommunicationMode"}, | 272 | {1001, nullptr, "GetNpadCommunicationMode"}, |
| 270 | }; | 273 | }; |
| @@ -797,12 +800,22 @@ public: | |||
| 797 | {232, nullptr, "EnableShipmentMode"}, | 800 | {232, nullptr, "EnableShipmentMode"}, |
| 798 | {233, nullptr, "ClearPairingInfo"}, | 801 | {233, nullptr, "ClearPairingInfo"}, |
| 799 | {234, nullptr, "GetUniquePadDeviceTypeSetInternal"}, | 802 | {234, nullptr, "GetUniquePadDeviceTypeSetInternal"}, |
| 803 | {235, nullptr, "EnableAnalogStickPower"}, | ||
| 800 | {301, nullptr, "GetAbstractedPadHandles"}, | 804 | {301, nullptr, "GetAbstractedPadHandles"}, |
| 801 | {302, nullptr, "GetAbstractedPadState"}, | 805 | {302, nullptr, "GetAbstractedPadState"}, |
| 802 | {303, nullptr, "GetAbstractedPadsState"}, | 806 | {303, nullptr, "GetAbstractedPadsState"}, |
| 803 | {321, nullptr, "SetAutoPilotVirtualPadState"}, | 807 | {321, nullptr, "SetAutoPilotVirtualPadState"}, |
| 804 | {322, nullptr, "UnsetAutoPilotVirtualPadState"}, | 808 | {322, nullptr, "UnsetAutoPilotVirtualPadState"}, |
| 805 | {323, nullptr, "UnsetAllAutoPilotVirtualPadState"}, | 809 | {323, nullptr, "UnsetAllAutoPilotVirtualPadState"}, |
| 810 | {324, nullptr, "AttachHdlsWorkBuffer"}, | ||
| 811 | {325, nullptr, "ReleaseHdlsWorkBuffer"}, | ||
| 812 | {326, nullptr, "DumpHdlsNpadAssignmentState"}, | ||
| 813 | {327, nullptr, "DumpHdlsStates"}, | ||
| 814 | {328, nullptr, "ApplyHdlsNpadAssignmentState"}, | ||
| 815 | {329, nullptr, "ApplyHdlsStateList"}, | ||
| 816 | {330, nullptr, "AttachHdlsVirtualDevice"}, | ||
| 817 | {331, nullptr, "DetachHdlsVirtualDevice"}, | ||
| 818 | {332, nullptr, "SetHdlsState"}, | ||
| 806 | {350, nullptr, "AddRegisteredDevice"}, | 819 | {350, nullptr, "AddRegisteredDevice"}, |
| 807 | {400, nullptr, "DisableExternalMcuOnNxDevice"}, | 820 | {400, nullptr, "DisableExternalMcuOnNxDevice"}, |
| 808 | {401, nullptr, "DisableRailDeviceFiltering"}, | 821 | {401, nullptr, "DisableRailDeviceFiltering"}, |
| @@ -825,6 +838,7 @@ public: | |||
| 825 | {131, nullptr, "ActivateSleepButton"}, | 838 | {131, nullptr, "ActivateSleepButton"}, |
| 826 | {141, nullptr, "AcquireCaptureButtonEventHandle"}, | 839 | {141, nullptr, "AcquireCaptureButtonEventHandle"}, |
| 827 | {151, nullptr, "ActivateCaptureButton"}, | 840 | {151, nullptr, "ActivateCaptureButton"}, |
| 841 | {161, nullptr, "GetPlatformConfig"}, | ||
| 828 | {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"}, | 842 | {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"}, |
| 829 | {211, nullptr, "GetNpadsWithNfc"}, | 843 | {211, nullptr, "GetNpadsWithNfc"}, |
| 830 | {212, nullptr, "AcquireNfcActivateEventHandle"}, | 844 | {212, nullptr, "AcquireNfcActivateEventHandle"}, |
| @@ -894,6 +908,7 @@ public: | |||
| 894 | {827, nullptr, "IsAnalogStickButtonPressed"}, | 908 | {827, nullptr, "IsAnalogStickButtonPressed"}, |
| 895 | {828, nullptr, "IsAnalogStickInReleasePosition"}, | 909 | {828, nullptr, "IsAnalogStickInReleasePosition"}, |
| 896 | {829, nullptr, "IsAnalogStickInCircumference"}, | 910 | {829, nullptr, "IsAnalogStickInCircumference"}, |
| 911 | {830, nullptr, "SetNotificationLedPattern"}, | ||
| 897 | {850, nullptr, "IsUsbFullKeyControllerEnabled"}, | 912 | {850, nullptr, "IsUsbFullKeyControllerEnabled"}, |
| 898 | {851, nullptr, "EnableUsbFullKeyController"}, | 913 | {851, nullptr, "EnableUsbFullKeyController"}, |
| 899 | {852, nullptr, "IsUsbConnected"}, | 914 | {852, nullptr, "IsUsbConnected"}, |
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index e250595e3..ed5059047 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp | |||
| @@ -52,9 +52,11 @@ public: | |||
| 52 | } | 52 | } |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | class ILocalCommunicationService final : public ServiceFramework<ILocalCommunicationService> { | 55 | class ISystemLocalCommunicationService final |
| 56 | : public ServiceFramework<ISystemLocalCommunicationService> { | ||
| 56 | public: | 57 | public: |
| 57 | explicit ILocalCommunicationService(const char* name) : ServiceFramework{name} { | 58 | explicit ISystemLocalCommunicationService() |
| 59 | : ServiceFramework{"ISystemLocalCommunicationService"} { | ||
| 58 | // clang-format off | 60 | // clang-format off |
| 59 | static const FunctionInfo functions[] = { | 61 | static const FunctionInfo functions[] = { |
| 60 | {0, nullptr, "GetState"}, | 62 | {0, nullptr, "GetState"}, |
| @@ -84,6 +86,50 @@ public: | |||
| 84 | {304, nullptr, "Disconnect"}, | 86 | {304, nullptr, "Disconnect"}, |
| 85 | {400, nullptr, "InitializeSystem"}, | 87 | {400, nullptr, "InitializeSystem"}, |
| 86 | {401, nullptr, "FinalizeSystem"}, | 88 | {401, nullptr, "FinalizeSystem"}, |
| 89 | {402, nullptr, "SetOperationMode"}, | ||
| 90 | {403, nullptr, "InitializeSystem2"}, | ||
| 91 | }; | ||
| 92 | // clang-format on | ||
| 93 | |||
| 94 | RegisterHandlers(functions); | ||
| 95 | } | ||
| 96 | }; | ||
| 97 | |||
| 98 | class IUserLocalCommunicationService final | ||
| 99 | : public ServiceFramework<IUserLocalCommunicationService> { | ||
| 100 | public: | ||
| 101 | explicit IUserLocalCommunicationService() : ServiceFramework{"IUserLocalCommunicationService"} { | ||
| 102 | // clang-format off | ||
| 103 | static const FunctionInfo functions[] = { | ||
| 104 | {0, nullptr, "GetState"}, | ||
| 105 | {1, nullptr, "GetNetworkInfo"}, | ||
| 106 | {2, nullptr, "GetIpv4Address"}, | ||
| 107 | {3, nullptr, "GetDisconnectReason"}, | ||
| 108 | {4, nullptr, "GetSecurityParameter"}, | ||
| 109 | {5, nullptr, "GetNetworkConfig"}, | ||
| 110 | {100, nullptr, "AttachStateChangeEvent"}, | ||
| 111 | {101, nullptr, "GetNetworkInfoLatestUpdate"}, | ||
| 112 | {102, nullptr, "Scan"}, | ||
| 113 | {103, nullptr, "ScanPrivate"}, | ||
| 114 | {104, nullptr, "SetWirelessControllerRestriction"}, | ||
| 115 | {200, nullptr, "OpenAccessPoint"}, | ||
| 116 | {201, nullptr, "CloseAccessPoint"}, | ||
| 117 | {202, nullptr, "CreateNetwork"}, | ||
| 118 | {203, nullptr, "CreateNetworkPrivate"}, | ||
| 119 | {204, nullptr, "DestroyNetwork"}, | ||
| 120 | {205, nullptr, "Reject"}, | ||
| 121 | {206, nullptr, "SetAdvertiseData"}, | ||
| 122 | {207, nullptr, "SetStationAcceptPolicy"}, | ||
| 123 | {208, nullptr, "AddAcceptFilterEntry"}, | ||
| 124 | {209, nullptr, "ClearAcceptFilter"}, | ||
| 125 | {300, nullptr, "OpenStation"}, | ||
| 126 | {301, nullptr, "CloseStation"}, | ||
| 127 | {302, nullptr, "Connect"}, | ||
| 128 | {303, nullptr, "ConnectPrivate"}, | ||
| 129 | {304, nullptr, "Disconnect"}, | ||
| 130 | {400, nullptr, "Initialize"}, | ||
| 131 | {401, nullptr, "Finalize"}, | ||
| 132 | {402, nullptr, "SetOperationMode"}, | ||
| 87 | }; | 133 | }; |
| 88 | // clang-format on | 134 | // clang-format on |
| 89 | 135 | ||
| @@ -108,7 +154,7 @@ public: | |||
| 108 | 154 | ||
| 109 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 155 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 110 | rb.Push(RESULT_SUCCESS); | 156 | rb.Push(RESULT_SUCCESS); |
| 111 | rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService"); | 157 | rb.PushIpcInterface<ISystemLocalCommunicationService>(); |
| 112 | } | 158 | } |
| 113 | }; | 159 | }; |
| 114 | 160 | ||
| @@ -129,7 +175,7 @@ public: | |||
| 129 | 175 | ||
| 130 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 176 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 131 | rb.Push(RESULT_SUCCESS); | 177 | rb.Push(RESULT_SUCCESS); |
| 132 | rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService"); | 178 | rb.PushIpcInterface<IUserLocalCommunicationService>(); |
| 133 | } | 179 | } |
| 134 | }; | 180 | }; |
| 135 | 181 | ||
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 609102f2c..5af925515 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -86,6 +86,7 @@ public: | |||
| 86 | {2, &RelocatableObject::LoadNrr, "LoadNrr"}, | 86 | {2, &RelocatableObject::LoadNrr, "LoadNrr"}, |
| 87 | {3, &RelocatableObject::UnloadNrr, "UnloadNrr"}, | 87 | {3, &RelocatableObject::UnloadNrr, "UnloadNrr"}, |
| 88 | {4, &RelocatableObject::Initialize, "Initialize"}, | 88 | {4, &RelocatableObject::Initialize, "Initialize"}, |
| 89 | {10, nullptr, "LoadNrrEx"}, | ||
| 89 | }; | 90 | }; |
| 90 | // clang-format on | 91 | // clang-format on |
| 91 | 92 | ||
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 60479bb45..f92571008 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp | |||
| @@ -15,12 +15,16 @@ namespace Service::NIFM { | |||
| 15 | class IScanRequest final : public ServiceFramework<IScanRequest> { | 15 | class IScanRequest final : public ServiceFramework<IScanRequest> { |
| 16 | public: | 16 | public: |
| 17 | explicit IScanRequest() : ServiceFramework("IScanRequest") { | 17 | explicit IScanRequest() : ServiceFramework("IScanRequest") { |
| 18 | // clang-format off | ||
| 18 | static const FunctionInfo functions[] = { | 19 | static const FunctionInfo functions[] = { |
| 19 | {0, nullptr, "Submit"}, | 20 | {0, nullptr, "Submit"}, |
| 20 | {1, nullptr, "IsProcessing"}, | 21 | {1, nullptr, "IsProcessing"}, |
| 21 | {2, nullptr, "GetResult"}, | 22 | {2, nullptr, "GetResult"}, |
| 22 | {3, nullptr, "GetSystemEventReadableHandle"}, | 23 | {3, nullptr, "GetSystemEventReadableHandle"}, |
| 24 | {4, nullptr, "SetChannels"}, | ||
| 23 | }; | 25 | }; |
| 26 | // clang-format on | ||
| 27 | |||
| 24 | RegisterHandlers(functions); | 28 | RegisterHandlers(functions); |
| 25 | } | 29 | } |
| 26 | }; | 30 | }; |
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp index ccb6f9da9..8751522ca 100644 --- a/src/core/hle/service/npns/npns.cpp +++ b/src/core/hle/service/npns/npns.cpp | |||
| @@ -45,7 +45,7 @@ public: | |||
| 45 | {114, nullptr, "AttachJid"}, | 45 | {114, nullptr, "AttachJid"}, |
| 46 | {115, nullptr, "DetachJid"}, | 46 | {115, nullptr, "DetachJid"}, |
| 47 | {201, nullptr, "RequestChangeStateForceTimed"}, | 47 | {201, nullptr, "RequestChangeStateForceTimed"}, |
| 48 | {102, nullptr, "RequestChangeStateForceAsync"}, | 48 | {202, nullptr, "RequestChangeStateForceAsync"}, |
| 49 | }; | 49 | }; |
| 50 | // clang-format on | 50 | // clang-format on |
| 51 | 51 | ||
| @@ -73,6 +73,7 @@ public: | |||
| 73 | {103, nullptr, "GetState"}, | 73 | {103, nullptr, "GetState"}, |
| 74 | {104, nullptr, "GetStatistics"}, | 74 | {104, nullptr, "GetStatistics"}, |
| 75 | {111, nullptr, "GetJid"}, | 75 | {111, nullptr, "GetJid"}, |
| 76 | {120, nullptr, "CreateNotificationReceiver"}, | ||
| 76 | }; | 77 | }; |
| 77 | // clang-format on | 78 | // clang-format on |
| 78 | 79 | ||
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp index 6081f41e1..c75b4ee34 100644 --- a/src/core/hle/service/pctl/module.cpp +++ b/src/core/hle/service/pctl/module.cpp | |||
| @@ -12,10 +12,10 @@ namespace Service::PCTL { | |||
| 12 | class IParentalControlService final : public ServiceFramework<IParentalControlService> { | 12 | class IParentalControlService final : public ServiceFramework<IParentalControlService> { |
| 13 | public: | 13 | public: |
| 14 | IParentalControlService() : ServiceFramework("IParentalControlService") { | 14 | IParentalControlService() : ServiceFramework("IParentalControlService") { |
| 15 | // clang-format off | ||
| 15 | static const FunctionInfo functions[] = { | 16 | static const FunctionInfo functions[] = { |
| 16 | {1, &IParentalControlService::Initialize, "Initialize"}, | 17 | {1, &IParentalControlService::Initialize, "Initialize"}, |
| 17 | {1001, &IParentalControlService::CheckFreeCommunicationPermission, | 18 | {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"}, |
| 18 | "CheckFreeCommunicationPermission"}, | ||
| 19 | {1002, nullptr, "ConfirmLaunchApplicationPermission"}, | 19 | {1002, nullptr, "ConfirmLaunchApplicationPermission"}, |
| 20 | {1003, nullptr, "ConfirmResumeApplicationPermission"}, | 20 | {1003, nullptr, "ConfirmResumeApplicationPermission"}, |
| 21 | {1004, nullptr, "ConfirmSnsPostPermission"}, | 21 | {1004, nullptr, "ConfirmSnsPostPermission"}, |
| @@ -30,6 +30,7 @@ public: | |||
| 30 | {1013, nullptr, "ConfirmStereoVisionPermission"}, | 30 | {1013, nullptr, "ConfirmStereoVisionPermission"}, |
| 31 | {1014, nullptr, "ConfirmPlayableApplicationVideoOld"}, | 31 | {1014, nullptr, "ConfirmPlayableApplicationVideoOld"}, |
| 32 | {1015, nullptr, "ConfirmPlayableApplicationVideo"}, | 32 | {1015, nullptr, "ConfirmPlayableApplicationVideo"}, |
| 33 | {1016, nullptr, "ConfirmShowNewsPermission"}, | ||
| 33 | {1031, nullptr, "IsRestrictionEnabled"}, | 34 | {1031, nullptr, "IsRestrictionEnabled"}, |
| 34 | {1032, nullptr, "GetSafetyLevel"}, | 35 | {1032, nullptr, "GetSafetyLevel"}, |
| 35 | {1033, nullptr, "SetSafetyLevel"}, | 36 | {1033, nullptr, "SetSafetyLevel"}, |
| @@ -45,6 +46,7 @@ public: | |||
| 45 | {1045, nullptr, "UpdateFreeCommunicationApplicationList"}, | 46 | {1045, nullptr, "UpdateFreeCommunicationApplicationList"}, |
| 46 | {1046, nullptr, "DisableFeaturesForReset"}, | 47 | {1046, nullptr, "DisableFeaturesForReset"}, |
| 47 | {1047, nullptr, "NotifyApplicationDownloadStarted"}, | 48 | {1047, nullptr, "NotifyApplicationDownloadStarted"}, |
| 49 | {1048, nullptr, "NotifyNetworkProfileCreated"}, | ||
| 48 | {1061, nullptr, "ConfirmStereoVisionRestrictionConfigurable"}, | 50 | {1061, nullptr, "ConfirmStereoVisionRestrictionConfigurable"}, |
| 49 | {1062, nullptr, "GetStereoVisionRestriction"}, | 51 | {1062, nullptr, "GetStereoVisionRestriction"}, |
| 50 | {1063, nullptr, "SetStereoVisionRestriction"}, | 52 | {1063, nullptr, "SetStereoVisionRestriction"}, |
| @@ -63,6 +65,7 @@ public: | |||
| 63 | {1411, nullptr, "GetPairingAccountInfo"}, | 65 | {1411, nullptr, "GetPairingAccountInfo"}, |
| 64 | {1421, nullptr, "GetAccountNickname"}, | 66 | {1421, nullptr, "GetAccountNickname"}, |
| 65 | {1424, nullptr, "GetAccountState"}, | 67 | {1424, nullptr, "GetAccountState"}, |
| 68 | {1425, nullptr, "RequestPostEvents"}, | ||
| 66 | {1432, nullptr, "GetSynchronizationEvent"}, | 69 | {1432, nullptr, "GetSynchronizationEvent"}, |
| 67 | {1451, nullptr, "StartPlayTimer"}, | 70 | {1451, nullptr, "StartPlayTimer"}, |
| 68 | {1452, nullptr, "StopPlayTimer"}, | 71 | {1452, nullptr, "StopPlayTimer"}, |
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index 6b27dc4a3..ebcc41a43 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp | |||
| @@ -42,15 +42,18 @@ private: | |||
| 42 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { | 42 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { |
| 43 | public: | 43 | public: |
| 44 | explicit DebugMonitor() : ServiceFramework{"pm:dmnt"} { | 44 | explicit DebugMonitor() : ServiceFramework{"pm:dmnt"} { |
| 45 | // clang-format off | ||
| 45 | static const FunctionInfo functions[] = { | 46 | static const FunctionInfo functions[] = { |
| 46 | {0, nullptr, "IsDebugMode"}, | 47 | {0, nullptr, "GetDebugProcesses"}, |
| 47 | {1, nullptr, "GetDebugProcesses"}, | 48 | {1, nullptr, "StartDebugProcess"}, |
| 48 | {2, nullptr, "StartDebugProcess"}, | 49 | {2, nullptr, "GetTitlePid"}, |
| 49 | {3, nullptr, "GetTitlePid"}, | 50 | {3, nullptr, "EnableDebugForTitleId"}, |
| 50 | {4, nullptr, "EnableDebugForTitleId"}, | 51 | {4, nullptr, "GetApplicationPid"}, |
| 51 | {5, nullptr, "GetApplicationPid"}, | 52 | {5, nullptr, "EnableDebugForApplication"}, |
| 52 | {6, nullptr, "EnableDebugForApplication"}, | 53 | {6, nullptr, "DisableDebug"}, |
| 53 | }; | 54 | }; |
| 55 | // clang-format on | ||
| 56 | |||
| 54 | RegisterHandlers(functions); | 57 | RegisterHandlers(functions); |
| 55 | } | 58 | } |
| 56 | }; | 59 | }; |
| @@ -68,6 +71,7 @@ public: | |||
| 68 | class Shell final : public ServiceFramework<Shell> { | 71 | class Shell final : public ServiceFramework<Shell> { |
| 69 | public: | 72 | public: |
| 70 | explicit Shell() : ServiceFramework{"pm:shell"} { | 73 | explicit Shell() : ServiceFramework{"pm:shell"} { |
| 74 | // clang-format off | ||
| 71 | static const FunctionInfo functions[] = { | 75 | static const FunctionInfo functions[] = { |
| 72 | {0, nullptr, "LaunchProcess"}, | 76 | {0, nullptr, "LaunchProcess"}, |
| 73 | {1, nullptr, "TerminateProcessByPid"}, | 77 | {1, nullptr, "TerminateProcessByPid"}, |
| @@ -77,7 +81,10 @@ public: | |||
| 77 | {5, nullptr, "NotifyBootFinished"}, | 81 | {5, nullptr, "NotifyBootFinished"}, |
| 78 | {6, nullptr, "GetApplicationPid"}, | 82 | {6, nullptr, "GetApplicationPid"}, |
| 79 | {7, nullptr, "BoostSystemMemoryResourceLimit"}, | 83 | {7, nullptr, "BoostSystemMemoryResourceLimit"}, |
| 84 | {8, nullptr, "EnableAdditionalSystemThreads"}, | ||
| 80 | }; | 85 | }; |
| 86 | // clang-format on | ||
| 87 | |||
| 81 | RegisterHandlers(functions); | 88 | RegisterHandlers(functions); |
| 82 | } | 89 | } |
| 83 | }; | 90 | }; |
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 1afc43f75..4ecb6bcef 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp | |||
| @@ -116,6 +116,7 @@ void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) { | |||
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | SET::SET() : ServiceFramework("set") { | 118 | SET::SET() : ServiceFramework("set") { |
| 119 | // clang-format off | ||
| 119 | static const FunctionInfo functions[] = { | 120 | static const FunctionInfo functions[] = { |
| 120 | {0, &SET::GetLanguageCode, "GetLanguageCode"}, | 121 | {0, &SET::GetLanguageCode, "GetLanguageCode"}, |
| 121 | {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, | 122 | {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, |
| @@ -126,7 +127,10 @@ SET::SET() : ServiceFramework("set") { | |||
| 126 | {6, &SET::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"}, | 127 | {6, &SET::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"}, |
| 127 | {7, nullptr, "GetKeyCodeMap"}, | 128 | {7, nullptr, "GetKeyCodeMap"}, |
| 128 | {8, nullptr, "GetQuestFlag"}, | 129 | {8, nullptr, "GetQuestFlag"}, |
| 130 | {9, nullptr, "GetKeyCodeMap2"}, | ||
| 129 | }; | 131 | }; |
| 132 | // clang-format on | ||
| 133 | |||
| 130 | RegisterHandlers(functions); | 134 | RegisterHandlers(functions); |
| 131 | } | 135 | } |
| 132 | 136 | ||
diff --git a/src/core/hle/service/set/set_cal.cpp b/src/core/hle/service/set/set_cal.cpp index 34654bb07..5981c575c 100644 --- a/src/core/hle/service/set/set_cal.cpp +++ b/src/core/hle/service/set/set_cal.cpp | |||
| @@ -40,7 +40,7 @@ SET_CAL::SET_CAL() : ServiceFramework("set:cal") { | |||
| 40 | {30, nullptr, "GetAmiiboEcqvBlsCertificate"}, | 40 | {30, nullptr, "GetAmiiboEcqvBlsCertificate"}, |
| 41 | {31, nullptr, "GetAmiiboEcqvBlsRootCertificate"}, | 41 | {31, nullptr, "GetAmiiboEcqvBlsRootCertificate"}, |
| 42 | {32, nullptr, "GetUsbTypeCPowerSourceCircuitVersion"}, | 42 | {32, nullptr, "GetUsbTypeCPowerSourceCircuitVersion"}, |
| 43 | {33, nullptr, "GetBatteryVersion"}, | 43 | {41, nullptr, "GetBatteryVersion"}, |
| 44 | }; | 44 | }; |
| 45 | RegisterHandlers(functions); | 45 | RegisterHandlers(functions); |
| 46 | } | 46 | } |
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index ecee554bf..98d0cfdfd 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp | |||
| @@ -104,6 +104,7 @@ void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) { | |||
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | SET_SYS::SET_SYS() : ServiceFramework("set:sys") { | 106 | SET_SYS::SET_SYS() : ServiceFramework("set:sys") { |
| 107 | // clang-format off | ||
| 107 | static const FunctionInfo functions[] = { | 108 | static const FunctionInfo functions[] = { |
| 108 | {0, nullptr, "SetLanguageCode"}, | 109 | {0, nullptr, "SetLanguageCode"}, |
| 109 | {1, nullptr, "SetNetworkSettings"}, | 110 | {1, nullptr, "SetNetworkSettings"}, |
| @@ -252,7 +253,33 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") { | |||
| 252 | {147, nullptr, "GetConsoleSixAxisSensorAngularAcceleration"}, | 253 | {147, nullptr, "GetConsoleSixAxisSensorAngularAcceleration"}, |
| 253 | {148, nullptr, "SetConsoleSixAxisSensorAngularAcceleration"}, | 254 | {148, nullptr, "SetConsoleSixAxisSensorAngularAcceleration"}, |
| 254 | {149, nullptr, "GetRebootlessSystemUpdateVersion"}, | 255 | {149, nullptr, "GetRebootlessSystemUpdateVersion"}, |
| 256 | {150, nullptr, "GetDeviceTimeZoneLocationUpdatedTime"}, | ||
| 257 | {151, nullptr, "SetDeviceTimeZoneLocationUpdatedTime"}, | ||
| 258 | {152, nullptr, "GetUserSystemClockAutomaticCorrectionUpdatedTime"}, | ||
| 259 | {153, nullptr, "SetUserSystemClockAutomaticCorrectionUpdatedTime"}, | ||
| 260 | {154, nullptr, "GetAccountOnlineStorageSettings"}, | ||
| 261 | {155, nullptr, "SetAccountOnlineStorageSettings"}, | ||
| 262 | {156, nullptr, "GetPctlReadyFlag"}, | ||
| 263 | {157, nullptr, "SetPctlReadyFlag"}, | ||
| 264 | {162, nullptr, "GetPtmBatteryVersion"}, | ||
| 265 | {163, nullptr, "SetPtmBatteryVersion"}, | ||
| 266 | {164, nullptr, "GetUsb30HostEnableFlag"}, | ||
| 267 | {165, nullptr, "SetUsb30HostEnableFlag"}, | ||
| 268 | {166, nullptr, "GetUsb30DeviceEnableFlag"}, | ||
| 269 | {167, nullptr, "SetUsb30DeviceEnableFlag"}, | ||
| 270 | {168, nullptr, "GetThemeId"}, | ||
| 271 | {169, nullptr, "SetThemeId"}, | ||
| 272 | {170, nullptr, "GetChineseTraditionalInputMethod"}, | ||
| 273 | {171, nullptr, "SetChineseTraditionalInputMethod"}, | ||
| 274 | {172, nullptr, "GetPtmCycleCountReliability"}, | ||
| 275 | {173, nullptr, "SetPtmCycleCountReliability"}, | ||
| 276 | {175, nullptr, "GetThemeSettings"}, | ||
| 277 | {176, nullptr, "SetThemeSettings"}, | ||
| 278 | {177, nullptr, "GetThemeKey"}, | ||
| 279 | {178, nullptr, "SetThemeKey"}, | ||
| 255 | }; | 280 | }; |
| 281 | // clang-format on | ||
| 282 | |||
| 256 | RegisterHandlers(functions); | 283 | RegisterHandlers(functions); |
| 257 | } | 284 | } |
| 258 | 285 | ||
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 4342f3b2d..884ad173b 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp | |||
| @@ -73,6 +73,7 @@ void BSD::Close(Kernel::HLERequestContext& ctx) { | |||
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | BSD::BSD(const char* name) : ServiceFramework(name) { | 75 | BSD::BSD(const char* name) : ServiceFramework(name) { |
| 76 | // clang-format off | ||
| 76 | static const FunctionInfo functions[] = { | 77 | static const FunctionInfo functions[] = { |
| 77 | {0, &BSD::RegisterClient, "RegisterClient"}, | 78 | {0, &BSD::RegisterClient, "RegisterClient"}, |
| 78 | {1, &BSD::StartMonitoring, "StartMonitoring"}, | 79 | {1, &BSD::StartMonitoring, "StartMonitoring"}, |
| @@ -105,7 +106,11 @@ BSD::BSD(const char* name) : ServiceFramework(name) { | |||
| 105 | {28, nullptr, "GetResourceStatistics"}, | 106 | {28, nullptr, "GetResourceStatistics"}, |
| 106 | {29, nullptr, "RecvMMsg"}, | 107 | {29, nullptr, "RecvMMsg"}, |
| 107 | {30, nullptr, "SendMMsg"}, | 108 | {30, nullptr, "SendMMsg"}, |
| 109 | {31, nullptr, "EventFd"}, | ||
| 110 | {32, nullptr, "RegisterResourceStatisticsName"}, | ||
| 108 | }; | 111 | }; |
| 112 | // clang-format on | ||
| 113 | |||
| 109 | RegisterHandlers(functions); | 114 | RegisterHandlers(functions); |
| 110 | } | 115 | } |
| 111 | 116 | ||
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index f7f87a958..65040c077 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp | |||
| @@ -103,6 +103,8 @@ public: | |||
| 103 | {4, nullptr, "DebugIoctl"}, | 103 | {4, nullptr, "DebugIoctl"}, |
| 104 | {5, &SSL::SetInterfaceVersion, "SetInterfaceVersion"}, | 104 | {5, &SSL::SetInterfaceVersion, "SetInterfaceVersion"}, |
| 105 | {6, nullptr, "FlushSessionCache"}, | 105 | {6, nullptr, "FlushSessionCache"}, |
| 106 | {7, nullptr, "SetDebugOption"}, | ||
| 107 | {8, nullptr, "GetDebugOption"}, | ||
| 106 | }; | 108 | }; |
| 107 | // clang-format on | 109 | // clang-format on |
| 108 | 110 | ||
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp index b3a196f65..8d122ae33 100644 --- a/src/core/hle/service/time/interface.cpp +++ b/src/core/hle/service/time/interface.cpp | |||
| @@ -8,6 +8,7 @@ namespace Service::Time { | |||
| 8 | 8 | ||
| 9 | Time::Time(std::shared_ptr<Module> time, const char* name) | 9 | Time::Time(std::shared_ptr<Module> time, const char* name) |
| 10 | : Module::Interface(std::move(time), name) { | 10 | : Module::Interface(std::move(time), name) { |
| 11 | // clang-format off | ||
| 11 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 12 | {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, | 13 | {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, |
| 13 | {1, &Time::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, | 14 | {1, &Time::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, |
| @@ -15,18 +16,23 @@ Time::Time(std::shared_ptr<Module> time, const char* name) | |||
| 15 | {3, &Time::GetTimeZoneService, "GetTimeZoneService"}, | 16 | {3, &Time::GetTimeZoneService, "GetTimeZoneService"}, |
| 16 | {4, &Time::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, | 17 | {4, &Time::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, |
| 17 | {5, nullptr, "GetEphemeralNetworkSystemClock"}, | 18 | {5, nullptr, "GetEphemeralNetworkSystemClock"}, |
| 19 | {20, nullptr, "GetSharedMemoryNativeHandle"}, | ||
| 20 | {30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"}, | ||
| 21 | {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"}, | ||
| 18 | {50, nullptr, "SetStandardSteadyClockInternalOffset"}, | 22 | {50, nullptr, "SetStandardSteadyClockInternalOffset"}, |
| 19 | {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, | 23 | {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, |
| 20 | {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, | 24 | {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, |
| 21 | {102, nullptr, "GetStandardUserSystemClockInitialYear"}, | 25 | {102, nullptr, "GetStandardUserSystemClockInitialYear"}, |
| 22 | {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"}, | 26 | {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"}, |
| 27 | {201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, | ||
| 23 | {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"}, | 28 | {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"}, |
| 24 | {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, | 29 | {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, |
| 25 | {401, nullptr, "GetClockSnapshotFromSystemClockContext"}, | 30 | {401, nullptr, "GetClockSnapshotFromSystemClockContext"}, |
| 26 | {500, &Time::CalculateStandardUserSystemClockDifferenceByUser, | 31 | {500, &Time::CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, |
| 27 | "CalculateStandardUserSystemClockDifferenceByUser"}, | ||
| 28 | {501, nullptr, "CalculateSpanBetween"}, | 32 | {501, nullptr, "CalculateSpanBetween"}, |
| 29 | }; | 33 | }; |
| 34 | // clang-format on | ||
| 35 | |||
| 30 | RegisterHandlers(functions); | 36 | RegisterHandlers(functions); |
| 31 | } | 37 | } |
| 32 | 38 | ||
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 07aa7a1cd..10b13fb1d 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -86,25 +86,29 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::Virtua | |||
| 86 | return FileType::Error; | 86 | return FileType::Error; |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) { | 89 | AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirectory::Load( |
| 90 | Kernel::Process& process) { | ||
| 90 | if (is_loaded) { | 91 | if (is_loaded) { |
| 91 | return ResultStatus::ErrorAlreadyLoaded; | 92 | return {ResultStatus::ErrorAlreadyLoaded, {}}; |
| 92 | } | 93 | } |
| 93 | 94 | ||
| 94 | if (dir == nullptr) { | 95 | if (dir == nullptr) { |
| 95 | if (file == nullptr) | 96 | if (file == nullptr) { |
| 96 | return ResultStatus::ErrorNullFile; | 97 | return {ResultStatus::ErrorNullFile, {}}; |
| 98 | } | ||
| 99 | |||
| 97 | dir = file->GetContainingDirectory(); | 100 | dir = file->GetContainingDirectory(); |
| 98 | } | 101 | } |
| 99 | 102 | ||
| 100 | // Read meta to determine title ID | 103 | // Read meta to determine title ID |
| 101 | FileSys::VirtualFile npdm = dir->GetFile("main.npdm"); | 104 | FileSys::VirtualFile npdm = dir->GetFile("main.npdm"); |
| 102 | if (npdm == nullptr) | 105 | if (npdm == nullptr) { |
| 103 | return ResultStatus::ErrorMissingNPDM; | 106 | return {ResultStatus::ErrorMissingNPDM, {}}; |
| 107 | } | ||
| 104 | 108 | ||
| 105 | ResultStatus result = metadata.Load(npdm); | 109 | const ResultStatus result = metadata.Load(npdm); |
| 106 | if (result != ResultStatus::Success) { | 110 | if (result != ResultStatus::Success) { |
| 107 | return result; | 111 | return {result, {}}; |
| 108 | } | 112 | } |
| 109 | 113 | ||
| 110 | if (override_update) { | 114 | if (override_update) { |
| @@ -114,23 +118,24 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) | |||
| 114 | 118 | ||
| 115 | // Reread in case PatchExeFS affected the main.npdm | 119 | // Reread in case PatchExeFS affected the main.npdm |
| 116 | npdm = dir->GetFile("main.npdm"); | 120 | npdm = dir->GetFile("main.npdm"); |
| 117 | if (npdm == nullptr) | 121 | if (npdm == nullptr) { |
| 118 | return ResultStatus::ErrorMissingNPDM; | 122 | return {ResultStatus::ErrorMissingNPDM, {}}; |
| 123 | } | ||
| 119 | 124 | ||
| 120 | ResultStatus result2 = metadata.Load(npdm); | 125 | const ResultStatus result2 = metadata.Load(npdm); |
| 121 | if (result2 != ResultStatus::Success) { | 126 | if (result2 != ResultStatus::Success) { |
| 122 | return result2; | 127 | return {result2, {}}; |
| 123 | } | 128 | } |
| 124 | metadata.Print(); | 129 | metadata.Print(); |
| 125 | 130 | ||
| 126 | const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; | 131 | const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; |
| 127 | if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit || | 132 | if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit || |
| 128 | arch_bits == FileSys::ProgramAddressSpaceType::Is32BitNoMap) { | 133 | arch_bits == FileSys::ProgramAddressSpaceType::Is32BitNoMap) { |
| 129 | return ResultStatus::Error32BitISA; | 134 | return {ResultStatus::Error32BitISA, {}}; |
| 130 | } | 135 | } |
| 131 | 136 | ||
| 132 | if (process.LoadFromMetadata(metadata).IsError()) { | 137 | if (process.LoadFromMetadata(metadata).IsError()) { |
| 133 | return ResultStatus::ErrorUnableToParseKernelMetadata; | 138 | return {ResultStatus::ErrorUnableToParseKernelMetadata, {}}; |
| 134 | } | 139 | } |
| 135 | 140 | ||
| 136 | const FileSys::PatchManager pm(metadata.GetTitleID()); | 141 | const FileSys::PatchManager pm(metadata.GetTitleID()); |
| @@ -150,7 +155,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) | |||
| 150 | const auto tentative_next_load_addr = | 155 | const auto tentative_next_load_addr = |
| 151 | AppLoader_NSO::LoadModule(process, *module_file, load_addr, should_pass_arguments, pm); | 156 | AppLoader_NSO::LoadModule(process, *module_file, load_addr, should_pass_arguments, pm); |
| 152 | if (!tentative_next_load_addr) { | 157 | if (!tentative_next_load_addr) { |
| 153 | return ResultStatus::ErrorLoadingNSO; | 158 | return {ResultStatus::ErrorLoadingNSO, {}}; |
| 154 | } | 159 | } |
| 155 | 160 | ||
| 156 | next_load_addr = *tentative_next_load_addr; | 161 | next_load_addr = *tentative_next_load_addr; |
| @@ -159,8 +164,6 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) | |||
| 159 | GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); | 164 | GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); |
| 160 | } | 165 | } |
| 161 | 166 | ||
| 162 | process.Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()); | ||
| 163 | |||
| 164 | // Find the RomFS by searching for a ".romfs" file in this directory | 167 | // Find the RomFS by searching for a ".romfs" file in this directory |
| 165 | const auto& files = dir->GetFiles(); | 168 | const auto& files = dir->GetFiles(); |
| 166 | const auto romfs_iter = | 169 | const auto romfs_iter = |
| @@ -175,7 +178,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) | |||
| 175 | } | 178 | } |
| 176 | 179 | ||
| 177 | is_loaded = true; | 180 | is_loaded = true; |
| 178 | return ResultStatus::Success; | 181 | return {ResultStatus::Success, |
| 182 | LoadParameters{metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()}}; | ||
| 179 | } | 183 | } |
| 180 | 184 | ||
| 181 | ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& dir) { | 185 | ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& dir) { |
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 1615cb5a8..1a65c16a4 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h | |||
| @@ -37,7 +37,7 @@ public: | |||
| 37 | return IdentifyType(file); | 37 | return IdentifyType(file); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | ResultStatus Load(Kernel::Process& process) override; | 40 | LoadResult Load(Kernel::Process& process) override; |
| 41 | 41 | ||
| 42 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 42 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 43 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | 43 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 46ac372f6..6d4b02375 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -382,13 +382,15 @@ FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& file) { | |||
| 382 | return FileType::Error; | 382 | return FileType::Error; |
| 383 | } | 383 | } |
| 384 | 384 | ||
| 385 | ResultStatus AppLoader_ELF::Load(Kernel::Process& process) { | 385 | AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process) { |
| 386 | if (is_loaded) | 386 | if (is_loaded) { |
| 387 | return ResultStatus::ErrorAlreadyLoaded; | 387 | return {ResultStatus::ErrorAlreadyLoaded, {}}; |
| 388 | } | ||
| 388 | 389 | ||
| 389 | std::vector<u8> buffer = file->ReadAllBytes(); | 390 | std::vector<u8> buffer = file->ReadAllBytes(); |
| 390 | if (buffer.size() != file->GetSize()) | 391 | if (buffer.size() != file->GetSize()) { |
| 391 | return ResultStatus::ErrorIncorrectELFFileSize; | 392 | return {ResultStatus::ErrorIncorrectELFFileSize, {}}; |
| 393 | } | ||
| 392 | 394 | ||
| 393 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); | 395 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 394 | ElfReader elf_reader(&buffer[0]); | 396 | ElfReader elf_reader(&buffer[0]); |
| @@ -396,10 +398,9 @@ ResultStatus AppLoader_ELF::Load(Kernel::Process& process) { | |||
| 396 | const VAddr entry_point = codeset.entrypoint; | 398 | const VAddr entry_point = codeset.entrypoint; |
| 397 | 399 | ||
| 398 | process.LoadModule(std::move(codeset), entry_point); | 400 | process.LoadModule(std::move(codeset), entry_point); |
| 399 | process.Run(entry_point, 48, Memory::DEFAULT_STACK_SIZE); | ||
| 400 | 401 | ||
| 401 | is_loaded = true; | 402 | is_loaded = true; |
| 402 | return ResultStatus::Success; | 403 | return {ResultStatus::Success, LoadParameters{48, Memory::DEFAULT_STACK_SIZE}}; |
| 403 | } | 404 | } |
| 404 | 405 | ||
| 405 | } // namespace Loader | 406 | } // namespace Loader |
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h index a2d33021c..7ef7770a6 100644 --- a/src/core/loader/elf.h +++ b/src/core/loader/elf.h | |||
| @@ -26,7 +26,7 @@ public: | |||
| 26 | return IdentifyType(file); | 26 | return IdentifyType(file); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | ResultStatus Load(Kernel::Process& process) override; | 29 | LoadResult Load(Kernel::Process& process) override; |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | } // namespace Loader | 32 | } // namespace Loader |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index bb925f4a6..f7846db52 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -131,6 +131,12 @@ std::ostream& operator<<(std::ostream& os, ResultStatus status); | |||
| 131 | /// Interface for loading an application | 131 | /// Interface for loading an application |
| 132 | class AppLoader : NonCopyable { | 132 | class AppLoader : NonCopyable { |
| 133 | public: | 133 | public: |
| 134 | struct LoadParameters { | ||
| 135 | s32 main_thread_priority; | ||
| 136 | u64 main_thread_stack_size; | ||
| 137 | }; | ||
| 138 | using LoadResult = std::pair<ResultStatus, std::optional<LoadParameters>>; | ||
| 139 | |||
| 134 | explicit AppLoader(FileSys::VirtualFile file); | 140 | explicit AppLoader(FileSys::VirtualFile file); |
| 135 | virtual ~AppLoader(); | 141 | virtual ~AppLoader(); |
| 136 | 142 | ||
| @@ -145,7 +151,7 @@ public: | |||
| 145 | * @param process The newly created process. | 151 | * @param process The newly created process. |
| 146 | * @return The status result of the operation. | 152 | * @return The status result of the operation. |
| 147 | */ | 153 | */ |
| 148 | virtual ResultStatus Load(Kernel::Process& process) = 0; | 154 | virtual LoadResult Load(Kernel::Process& process) = 0; |
| 149 | 155 | ||
| 150 | /** | 156 | /** |
| 151 | * Loads the system mode that this application needs. | 157 | * Loads the system mode that this application needs. |
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp index 93a970d10..34efef09a 100644 --- a/src/core/loader/nax.cpp +++ b/src/core/loader/nax.cpp | |||
| @@ -41,31 +41,37 @@ FileType AppLoader_NAX::GetFileType() const { | |||
| 41 | return IdentifyTypeImpl(*nax); | 41 | return IdentifyTypeImpl(*nax); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | ResultStatus AppLoader_NAX::Load(Kernel::Process& process) { | 44 | AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::Process& process) { |
| 45 | if (is_loaded) { | 45 | if (is_loaded) { |
| 46 | return ResultStatus::ErrorAlreadyLoaded; | 46 | return {ResultStatus::ErrorAlreadyLoaded, {}}; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | if (nax->GetStatus() != ResultStatus::Success) | 49 | const auto nax_status = nax->GetStatus(); |
| 50 | return nax->GetStatus(); | 50 | if (nax_status != ResultStatus::Success) { |
| 51 | return {nax_status, {}}; | ||
| 52 | } | ||
| 51 | 53 | ||
| 52 | const auto nca = nax->AsNCA(); | 54 | const auto nca = nax->AsNCA(); |
| 53 | if (nca == nullptr) { | 55 | if (nca == nullptr) { |
| 54 | if (!Core::Crypto::KeyManager::KeyFileExists(false)) | 56 | if (!Core::Crypto::KeyManager::KeyFileExists(false)) { |
| 55 | return ResultStatus::ErrorMissingProductionKeyFile; | 57 | return {ResultStatus::ErrorMissingProductionKeyFile, {}}; |
| 56 | return ResultStatus::ErrorNAXInconvertibleToNCA; | 58 | } |
| 59 | |||
| 60 | return {ResultStatus::ErrorNAXInconvertibleToNCA, {}}; | ||
| 57 | } | 61 | } |
| 58 | 62 | ||
| 59 | if (nca->GetStatus() != ResultStatus::Success) | 63 | const auto nca_status = nca->GetStatus(); |
| 60 | return nca->GetStatus(); | 64 | if (nca_status != ResultStatus::Success) { |
| 65 | return {nca_status, {}}; | ||
| 66 | } | ||
| 61 | 67 | ||
| 62 | const auto result = nca_loader->Load(process); | 68 | const auto result = nca_loader->Load(process); |
| 63 | if (result != ResultStatus::Success) | 69 | if (result.first != ResultStatus::Success) { |
| 64 | return result; | 70 | return result; |
| 71 | } | ||
| 65 | 72 | ||
| 66 | is_loaded = true; | 73 | is_loaded = true; |
| 67 | 74 | return result; | |
| 68 | return ResultStatus::Success; | ||
| 69 | } | 75 | } |
| 70 | 76 | ||
| 71 | ResultStatus AppLoader_NAX::ReadRomFS(FileSys::VirtualFile& dir) { | 77 | ResultStatus AppLoader_NAX::ReadRomFS(FileSys::VirtualFile& dir) { |
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h index f40079574..00f1659c1 100644 --- a/src/core/loader/nax.h +++ b/src/core/loader/nax.h | |||
| @@ -33,7 +33,7 @@ public: | |||
| 33 | 33 | ||
| 34 | FileType GetFileType() const override; | 34 | FileType GetFileType() const override; |
| 35 | 35 | ||
| 36 | ResultStatus Load(Kernel::Process& process) override; | 36 | LoadResult Load(Kernel::Process& process) override; |
| 37 | 37 | ||
| 38 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 38 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 39 | u64 ReadRomFSIVFCOffset() const override; | 39 | u64 ReadRomFSIVFCOffset() const override; |
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index ce8196fcf..b3f8f1083 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp | |||
| @@ -30,36 +30,38 @@ FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) { | |||
| 30 | return FileType::Error; | 30 | return FileType::Error; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | ResultStatus AppLoader_NCA::Load(Kernel::Process& process) { | 33 | AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process) { |
| 34 | if (is_loaded) { | 34 | if (is_loaded) { |
| 35 | return ResultStatus::ErrorAlreadyLoaded; | 35 | return {ResultStatus::ErrorAlreadyLoaded, {}}; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | const auto result = nca->GetStatus(); | 38 | const auto result = nca->GetStatus(); |
| 39 | if (result != ResultStatus::Success) { | 39 | if (result != ResultStatus::Success) { |
| 40 | return result; | 40 | return {result, {}}; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | if (nca->GetType() != FileSys::NCAContentType::Program) | 43 | if (nca->GetType() != FileSys::NCAContentType::Program) { |
| 44 | return ResultStatus::ErrorNCANotProgram; | 44 | return {ResultStatus::ErrorNCANotProgram, {}}; |
| 45 | } | ||
| 45 | 46 | ||
| 46 | const auto exefs = nca->GetExeFS(); | 47 | const auto exefs = nca->GetExeFS(); |
| 47 | 48 | if (exefs == nullptr) { | |
| 48 | if (exefs == nullptr) | 49 | return {ResultStatus::ErrorNoExeFS, {}}; |
| 49 | return ResultStatus::ErrorNoExeFS; | 50 | } |
| 50 | 51 | ||
| 51 | directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs, true); | 52 | directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs, true); |
| 52 | 53 | ||
| 53 | const auto load_result = directory_loader->Load(process); | 54 | const auto load_result = directory_loader->Load(process); |
| 54 | if (load_result != ResultStatus::Success) | 55 | if (load_result.first != ResultStatus::Success) { |
| 55 | return load_result; | 56 | return load_result; |
| 57 | } | ||
| 56 | 58 | ||
| 57 | if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0) | 59 | if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0) { |
| 58 | Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this)); | 60 | Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this)); |
| 61 | } | ||
| 59 | 62 | ||
| 60 | is_loaded = true; | 63 | is_loaded = true; |
| 61 | 64 | return load_result; | |
| 62 | return ResultStatus::Success; | ||
| 63 | } | 65 | } |
| 64 | 66 | ||
| 65 | ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { | 67 | ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { |
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index b9f077468..94f0ed677 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h | |||
| @@ -33,7 +33,7 @@ public: | |||
| 33 | return IdentifyType(file); | 33 | return IdentifyType(file); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | ResultStatus Load(Kernel::Process& process) override; | 36 | LoadResult Load(Kernel::Process& process) override; |
| 37 | 37 | ||
| 38 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 38 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 39 | u64 ReadRomFSIVFCOffset() const override; | 39 | u64 ReadRomFSIVFCOffset() const override; |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 31e4a0c84..6a0ca389b 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -201,25 +201,25 @@ bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& fi | |||
| 201 | return LoadNroImpl(process, file.ReadAllBytes(), file.GetName(), load_base); | 201 | return LoadNroImpl(process, file.ReadAllBytes(), file.GetName(), load_base); |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { | 204 | AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) { |
| 205 | if (is_loaded) { | 205 | if (is_loaded) { |
| 206 | return ResultStatus::ErrorAlreadyLoaded; | 206 | return {ResultStatus::ErrorAlreadyLoaded, {}}; |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | // Load NRO | 209 | // Load NRO |
| 210 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); | 210 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 211 | 211 | ||
| 212 | if (!LoadNro(process, *file, base_address)) { | 212 | if (!LoadNro(process, *file, base_address)) { |
| 213 | return ResultStatus::ErrorLoadingNRO; | 213 | return {ResultStatus::ErrorLoadingNRO, {}}; |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | if (romfs != nullptr) | 216 | if (romfs != nullptr) { |
| 217 | Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this)); | 217 | Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this)); |
| 218 | 218 | } | |
| 219 | process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); | ||
| 220 | 219 | ||
| 221 | is_loaded = true; | 220 | is_loaded = true; |
| 222 | return ResultStatus::Success; | 221 | return {ResultStatus::Success, |
| 222 | LoadParameters{Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE}}; | ||
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) { | 225 | ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) { |
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 85b0ed644..1ffdae805 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h | |||
| @@ -37,7 +37,7 @@ public: | |||
| 37 | return IdentifyType(file); | 37 | return IdentifyType(file); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | ResultStatus Load(Kernel::Process& process) override; | 40 | LoadResult Load(Kernel::Process& process) override; |
| 41 | 41 | ||
| 42 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | 42 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; |
| 43 | ResultStatus ReadProgramId(u64& out_program_id) override; | 43 | ResultStatus ReadProgramId(u64& out_program_id) override; |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index d7c47c197..a86653204 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -169,22 +169,21 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, | |||
| 169 | return load_base + image_size; | 169 | return load_base + image_size; |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | ResultStatus AppLoader_NSO::Load(Kernel::Process& process) { | 172 | AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process) { |
| 173 | if (is_loaded) { | 173 | if (is_loaded) { |
| 174 | return ResultStatus::ErrorAlreadyLoaded; | 174 | return {ResultStatus::ErrorAlreadyLoaded, {}}; |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | // Load module | 177 | // Load module |
| 178 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); | 178 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 179 | if (!LoadModule(process, *file, base_address, true)) { | 179 | if (!LoadModule(process, *file, base_address, true)) { |
| 180 | return ResultStatus::ErrorLoadingNSO; | 180 | return {ResultStatus::ErrorLoadingNSO, {}}; |
| 181 | } | 181 | } |
| 182 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); | 182 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); |
| 183 | 183 | ||
| 184 | process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); | ||
| 185 | |||
| 186 | is_loaded = true; | 184 | is_loaded = true; |
| 187 | return ResultStatus::Success; | 185 | return {ResultStatus::Success, |
| 186 | LoadParameters{Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE}}; | ||
| 188 | } | 187 | } |
| 189 | 188 | ||
| 190 | } // namespace Loader | 189 | } // namespace Loader |
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 4674c3724..fdce9191c 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h | |||
| @@ -84,7 +84,7 @@ public: | |||
| 84 | VAddr load_base, bool should_pass_arguments, | 84 | VAddr load_base, bool should_pass_arguments, |
| 85 | std::optional<FileSys::PatchManager> pm = {}); | 85 | std::optional<FileSys::PatchManager> pm = {}); |
| 86 | 86 | ||
| 87 | ResultStatus Load(Kernel::Process& process) override; | 87 | LoadResult Load(Kernel::Process& process) override; |
| 88 | }; | 88 | }; |
| 89 | 89 | ||
| 90 | } // namespace Loader | 90 | } // namespace Loader |
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 7da1f8960..ad56bbb38 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp | |||
| @@ -72,37 +72,45 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) { | |||
| 72 | return FileType::Error; | 72 | return FileType::Error; |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | ResultStatus AppLoader_NSP::Load(Kernel::Process& process) { | 75 | AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process) { |
| 76 | if (is_loaded) { | 76 | if (is_loaded) { |
| 77 | return ResultStatus::ErrorAlreadyLoaded; | 77 | return {ResultStatus::ErrorAlreadyLoaded, {}}; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | if (title_id == 0) | 80 | if (title_id == 0) { |
| 81 | return ResultStatus::ErrorNSPMissingProgramNCA; | 81 | return {ResultStatus::ErrorNSPMissingProgramNCA, {}}; |
| 82 | } | ||
| 82 | 83 | ||
| 83 | if (nsp->GetStatus() != ResultStatus::Success) | 84 | const auto nsp_status = nsp->GetStatus(); |
| 84 | return nsp->GetStatus(); | 85 | if (nsp_status != ResultStatus::Success) { |
| 86 | return {nsp_status, {}}; | ||
| 87 | } | ||
| 85 | 88 | ||
| 86 | if (nsp->GetProgramStatus(title_id) != ResultStatus::Success) | 89 | const auto nsp_program_status = nsp->GetProgramStatus(title_id); |
| 87 | return nsp->GetProgramStatus(title_id); | 90 | if (nsp_program_status != ResultStatus::Success) { |
| 91 | return {nsp_program_status, {}}; | ||
| 92 | } | ||
| 88 | 93 | ||
| 89 | if (nsp->GetNCA(title_id, FileSys::ContentRecordType::Program) == nullptr) { | 94 | if (nsp->GetNCA(title_id, FileSys::ContentRecordType::Program) == nullptr) { |
| 90 | if (!Core::Crypto::KeyManager::KeyFileExists(false)) | 95 | if (!Core::Crypto::KeyManager::KeyFileExists(false)) { |
| 91 | return ResultStatus::ErrorMissingProductionKeyFile; | 96 | return {ResultStatus::ErrorMissingProductionKeyFile, {}}; |
| 92 | return ResultStatus::ErrorNSPMissingProgramNCA; | 97 | } |
| 98 | |||
| 99 | return {ResultStatus::ErrorNSPMissingProgramNCA, {}}; | ||
| 93 | } | 100 | } |
| 94 | 101 | ||
| 95 | const auto result = secondary_loader->Load(process); | 102 | const auto result = secondary_loader->Load(process); |
| 96 | if (result != ResultStatus::Success) | 103 | if (result.first != ResultStatus::Success) { |
| 97 | return result; | 104 | return result; |
| 105 | } | ||
| 98 | 106 | ||
| 99 | FileSys::VirtualFile update_raw; | 107 | FileSys::VirtualFile update_raw; |
| 100 | if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) | 108 | if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { |
| 101 | Service::FileSystem::SetPackedUpdate(std::move(update_raw)); | 109 | Service::FileSystem::SetPackedUpdate(std::move(update_raw)); |
| 110 | } | ||
| 102 | 111 | ||
| 103 | is_loaded = true; | 112 | is_loaded = true; |
| 104 | 113 | return result; | |
| 105 | return ResultStatus::Success; | ||
| 106 | } | 114 | } |
| 107 | 115 | ||
| 108 | ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& file) { | 116 | ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& file) { |
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index 953a1b508..85e870bdf 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h | |||
| @@ -35,7 +35,7 @@ public: | |||
| 35 | return IdentifyType(file); | 35 | return IdentifyType(file); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | ResultStatus Load(Kernel::Process& process) override; | 38 | LoadResult Load(Kernel::Process& process) override; |
| 39 | 39 | ||
| 40 | ResultStatus ReadRomFS(FileSys::VirtualFile& file) override; | 40 | ResultStatus ReadRomFS(FileSys::VirtualFile& file) override; |
| 41 | u64 ReadRomFSIVFCOffset() const override; | 41 | u64 ReadRomFSIVFCOffset() const override; |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 89f7bbf77..1e285a053 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -48,31 +48,35 @@ FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) { | |||
| 48 | return FileType::Error; | 48 | return FileType::Error; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | ResultStatus AppLoader_XCI::Load(Kernel::Process& process) { | 51 | AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process) { |
| 52 | if (is_loaded) { | 52 | if (is_loaded) { |
| 53 | return ResultStatus::ErrorAlreadyLoaded; | 53 | return {ResultStatus::ErrorAlreadyLoaded, {}}; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | if (xci->GetStatus() != ResultStatus::Success) | 56 | if (xci->GetStatus() != ResultStatus::Success) { |
| 57 | return xci->GetStatus(); | 57 | return {xci->GetStatus(), {}}; |
| 58 | } | ||
| 58 | 59 | ||
| 59 | if (xci->GetProgramNCAStatus() != ResultStatus::Success) | 60 | if (xci->GetProgramNCAStatus() != ResultStatus::Success) { |
| 60 | return xci->GetProgramNCAStatus(); | 61 | return {xci->GetProgramNCAStatus(), {}}; |
| 62 | } | ||
| 61 | 63 | ||
| 62 | if (!xci->HasProgramNCA() && !Core::Crypto::KeyManager::KeyFileExists(false)) | 64 | if (!xci->HasProgramNCA() && !Core::Crypto::KeyManager::KeyFileExists(false)) { |
| 63 | return ResultStatus::ErrorMissingProductionKeyFile; | 65 | return {ResultStatus::ErrorMissingProductionKeyFile, {}}; |
| 66 | } | ||
| 64 | 67 | ||
| 65 | const auto result = nca_loader->Load(process); | 68 | const auto result = nca_loader->Load(process); |
| 66 | if (result != ResultStatus::Success) | 69 | if (result.first != ResultStatus::Success) { |
| 67 | return result; | 70 | return result; |
| 71 | } | ||
| 68 | 72 | ||
| 69 | FileSys::VirtualFile update_raw; | 73 | FileSys::VirtualFile update_raw; |
| 70 | if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) | 74 | if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { |
| 71 | Service::FileSystem::SetPackedUpdate(std::move(update_raw)); | 75 | Service::FileSystem::SetPackedUpdate(std::move(update_raw)); |
| 76 | } | ||
| 72 | 77 | ||
| 73 | is_loaded = true; | 78 | is_loaded = true; |
| 74 | 79 | return result; | |
| 75 | return ResultStatus::Success; | ||
| 76 | } | 80 | } |
| 77 | 81 | ||
| 78 | ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& file) { | 82 | ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& file) { |
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 436f7387c..ae7145b14 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h | |||
| @@ -35,7 +35,7 @@ public: | |||
| 35 | return IdentifyType(file); | 35 | return IdentifyType(file); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | ResultStatus Load(Kernel::Process& process) override; | 38 | LoadResult Load(Kernel::Process& process) override; |
| 39 | 39 | ||
| 40 | ResultStatus ReadRomFS(FileSys::VirtualFile& file) override; | 40 | ResultStatus ReadRomFS(FileSys::VirtualFile& file) override; |
| 41 | u64 ReadRomFSIVFCOffset() const override; | 41 | u64 ReadRomFSIVFCOffset() const override; |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 4e0538bc2..f18f6226b 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -26,16 +26,16 @@ namespace Memory { | |||
| 26 | 26 | ||
| 27 | static Common::PageTable* current_page_table = nullptr; | 27 | static Common::PageTable* current_page_table = nullptr; |
| 28 | 28 | ||
| 29 | void SetCurrentPageTable(Common::PageTable* page_table) { | 29 | void SetCurrentPageTable(Kernel::Process& process) { |
| 30 | current_page_table = page_table; | 30 | current_page_table = &process.VMManager().page_table; |
| 31 | |||
| 32 | const std::size_t address_space_width = process.VMManager().GetAddressSpaceWidth(); | ||
| 31 | 33 | ||
| 32 | auto& system = Core::System::GetInstance(); | 34 | auto& system = Core::System::GetInstance(); |
| 33 | if (system.IsPoweredOn()) { | 35 | system.ArmInterface(0).PageTableChanged(*current_page_table, address_space_width); |
| 34 | system.ArmInterface(0).PageTableChanged(); | 36 | system.ArmInterface(1).PageTableChanged(*current_page_table, address_space_width); |
| 35 | system.ArmInterface(1).PageTableChanged(); | 37 | system.ArmInterface(2).PageTableChanged(*current_page_table, address_space_width); |
| 36 | system.ArmInterface(2).PageTableChanged(); | 38 | system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width); |
| 37 | system.ArmInterface(3).PageTableChanged(); | ||
| 38 | } | ||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | static void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory, | 41 | static void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory, |
diff --git a/src/core/memory.h b/src/core/memory.h index 6845f5fe1..b9fa18b1d 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -40,8 +40,9 @@ enum : VAddr { | |||
| 40 | KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE, | 40 | KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE, |
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | /// Changes the currently active page table. | 43 | /// Changes the currently active page table to that of |
| 44 | void SetCurrentPageTable(Common::PageTable* page_table); | 44 | /// the given process instance. |
| 45 | void SetCurrentPageTable(Kernel::Process& process); | ||
| 45 | 46 | ||
| 46 | /// Determines if the given VAddr is valid for the specified process. | 47 | /// Determines if the given VAddr is valid for the specified process. |
| 47 | bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); | 48 | bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); |
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 6d32ebea3..c1365879b 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -90,6 +90,7 @@ void LogSettings() { | |||
| 90 | LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor); | 90 | LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor); |
| 91 | LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit); | 91 | LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit); |
| 92 | LogSetting("Renderer_FrameLimit", Settings::values.frame_limit); | 92 | LogSetting("Renderer_FrameLimit", Settings::values.frame_limit); |
| 93 | LogSetting("Renderer_UseCompatibilityProfile", Settings::values.use_compatibility_profile); | ||
| 93 | LogSetting("Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache); | 94 | LogSetting("Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache); |
| 94 | LogSetting("Renderer_UseAccurateGpuEmulation", Settings::values.use_accurate_gpu_emulation); | 95 | LogSetting("Renderer_UseAccurateGpuEmulation", Settings::values.use_accurate_gpu_emulation); |
| 95 | LogSetting("Renderer_UseAsynchronousGpuEmulation", | 96 | LogSetting("Renderer_UseAsynchronousGpuEmulation", |
diff --git a/src/core/settings.h b/src/core/settings.h index b84390745..5ff3634aa 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -390,6 +390,7 @@ struct Values { | |||
| 390 | float resolution_factor; | 390 | float resolution_factor; |
| 391 | bool use_frame_limit; | 391 | bool use_frame_limit; |
| 392 | u16 frame_limit; | 392 | u16 frame_limit; |
| 393 | bool use_compatibility_profile; | ||
| 393 | bool use_disk_shader_cache; | 394 | bool use_disk_shader_cache; |
| 394 | bool use_accurate_gpu_emulation; | 395 | bool use_accurate_gpu_emulation; |
| 395 | bool use_asynchronous_gpu_emulation; | 396 | bool use_asynchronous_gpu_emulation; |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 114bed20d..6821f275d 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -36,6 +36,8 @@ add_library(video_core STATIC | |||
| 36 | renderer_base.h | 36 | renderer_base.h |
| 37 | renderer_opengl/gl_buffer_cache.cpp | 37 | renderer_opengl/gl_buffer_cache.cpp |
| 38 | renderer_opengl/gl_buffer_cache.h | 38 | renderer_opengl/gl_buffer_cache.h |
| 39 | renderer_opengl/gl_device.cpp | ||
| 40 | renderer_opengl/gl_device.h | ||
| 39 | renderer_opengl/gl_global_cache.cpp | 41 | renderer_opengl/gl_global_cache.cpp |
| 40 | renderer_opengl/gl_global_cache.h | 42 | renderer_opengl/gl_global_cache.h |
| 41 | renderer_opengl/gl_primitive_assembler.cpp | 43 | renderer_opengl/gl_primitive_assembler.cpp |
| @@ -46,6 +48,8 @@ add_library(video_core STATIC | |||
| 46 | renderer_opengl/gl_rasterizer_cache.h | 48 | renderer_opengl/gl_rasterizer_cache.h |
| 47 | renderer_opengl/gl_resource_manager.cpp | 49 | renderer_opengl/gl_resource_manager.cpp |
| 48 | renderer_opengl/gl_resource_manager.h | 50 | renderer_opengl/gl_resource_manager.h |
| 51 | renderer_opengl/gl_sampler_cache.cpp | ||
| 52 | renderer_opengl/gl_sampler_cache.h | ||
| 49 | renderer_opengl/gl_shader_cache.cpp | 53 | renderer_opengl/gl_shader_cache.cpp |
| 50 | renderer_opengl/gl_shader_cache.h | 54 | renderer_opengl/gl_shader_cache.h |
| 51 | renderer_opengl/gl_shader_decompiler.cpp | 55 | renderer_opengl/gl_shader_decompiler.cpp |
| @@ -67,6 +71,8 @@ add_library(video_core STATIC | |||
| 67 | renderer_opengl/renderer_opengl.h | 71 | renderer_opengl/renderer_opengl.h |
| 68 | renderer_opengl/utils.cpp | 72 | renderer_opengl/utils.cpp |
| 69 | renderer_opengl/utils.h | 73 | renderer_opengl/utils.h |
| 74 | sampler_cache.cpp | ||
| 75 | sampler_cache.h | ||
| 70 | shader/decode/arithmetic.cpp | 76 | shader/decode/arithmetic.cpp |
| 71 | shader/decode/arithmetic_immediate.cpp | 77 | shader/decode/arithmetic_immediate.cpp |
| 72 | shader/decode/bfe.cpp | 78 | shader/decode/bfe.cpp |
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp index 12828d926..036e66f05 100644 --- a/src/video_core/dma_pusher.cpp +++ b/src/video_core/dma_pusher.cpp | |||
| @@ -57,8 +57,8 @@ bool DmaPusher::Step() { | |||
| 57 | 57 | ||
| 58 | // Push buffer non-empty, read a word | 58 | // Push buffer non-empty, read a word |
| 59 | command_headers.resize(command_list_header.size); | 59 | command_headers.resize(command_list_header.size); |
| 60 | gpu.MemoryManager().ReadBlock(dma_get, command_headers.data(), | 60 | gpu.MemoryManager().ReadBlockUnsafe(dma_get, command_headers.data(), |
| 61 | command_list_header.size * sizeof(u32)); | 61 | command_list_header.size * sizeof(u32)); |
| 62 | 62 | ||
| 63 | for (const CommandHeader& command_header : command_headers) { | 63 | for (const CommandHeader& command_header : command_headers) { |
| 64 | 64 | ||
diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp index cd51a31d7..7387886a3 100644 --- a/src/video_core/engines/kepler_memory.cpp +++ b/src/video_core/engines/kepler_memory.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "video_core/memory_manager.h" | 10 | #include "video_core/memory_manager.h" |
| 11 | #include "video_core/rasterizer_interface.h" | 11 | #include "video_core/rasterizer_interface.h" |
| 12 | #include "video_core/renderer_base.h" | 12 | #include "video_core/renderer_base.h" |
| 13 | #include "video_core/textures/decoders.h" | ||
| 13 | 14 | ||
| 14 | namespace Tegra::Engines { | 15 | namespace Tegra::Engines { |
| 15 | 16 | ||
| @@ -27,30 +28,46 @@ void KeplerMemory::CallMethod(const GPU::MethodCall& method_call) { | |||
| 27 | 28 | ||
| 28 | switch (method_call.method) { | 29 | switch (method_call.method) { |
| 29 | case KEPLERMEMORY_REG_INDEX(exec): { | 30 | case KEPLERMEMORY_REG_INDEX(exec): { |
| 30 | state.write_offset = 0; | 31 | ProcessExec(); |
| 31 | break; | 32 | break; |
| 32 | } | 33 | } |
| 33 | case KEPLERMEMORY_REG_INDEX(data): { | 34 | case KEPLERMEMORY_REG_INDEX(data): { |
| 34 | ProcessData(method_call.argument); | 35 | ProcessData(method_call.argument, method_call.IsLastCall()); |
| 35 | break; | 36 | break; |
| 36 | } | 37 | } |
| 37 | } | 38 | } |
| 38 | } | 39 | } |
| 39 | 40 | ||
| 40 | void KeplerMemory::ProcessData(u32 data) { | 41 | void KeplerMemory::ProcessExec() { |
| 41 | ASSERT_MSG(regs.exec.linear, "Non-linear uploads are not supported"); | 42 | state.write_offset = 0; |
| 42 | ASSERT(regs.dest.x == 0 && regs.dest.y == 0 && regs.dest.z == 0); | 43 | state.copy_size = regs.line_length_in * regs.line_count; |
| 43 | 44 | state.inner_buffer.resize(state.copy_size); | |
| 44 | // We have to invalidate the destination region to evict any outdated surfaces from the cache. | 45 | } |
| 45 | // We do this before actually writing the new data because the destination address might | ||
| 46 | // contain a dirty surface that will have to be written back to memory. | ||
| 47 | const GPUVAddr address{regs.dest.Address() + state.write_offset * sizeof(u32)}; | ||
| 48 | rasterizer.InvalidateRegion(ToCacheAddr(memory_manager.GetPointer(address)), sizeof(u32)); | ||
| 49 | memory_manager.Write<u32>(address, data); | ||
| 50 | |||
| 51 | system.GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); | ||
| 52 | 46 | ||
| 53 | state.write_offset++; | 47 | void KeplerMemory::ProcessData(u32 data, bool is_last_call) { |
| 48 | const u32 sub_copy_size = std::min(4U, state.copy_size - state.write_offset); | ||
| 49 | std::memcpy(&state.inner_buffer[state.write_offset], ®s.data, sub_copy_size); | ||
| 50 | state.write_offset += sub_copy_size; | ||
| 51 | if (is_last_call) { | ||
| 52 | const GPUVAddr address{regs.dest.Address()}; | ||
| 53 | if (regs.exec.linear != 0) { | ||
| 54 | memory_manager.WriteBlock(address, state.inner_buffer.data(), state.copy_size); | ||
| 55 | } else { | ||
| 56 | UNIMPLEMENTED_IF(regs.dest.z != 0); | ||
| 57 | UNIMPLEMENTED_IF(regs.dest.depth != 1); | ||
| 58 | UNIMPLEMENTED_IF(regs.dest.BlockWidth() != 1); | ||
| 59 | UNIMPLEMENTED_IF(regs.dest.BlockDepth() != 1); | ||
| 60 | const std::size_t dst_size = Tegra::Texture::CalculateSize( | ||
| 61 | true, 1, regs.dest.width, regs.dest.height, 1, regs.dest.BlockHeight(), 1); | ||
| 62 | std::vector<u8> tmp_buffer(dst_size); | ||
| 63 | memory_manager.ReadBlock(address, tmp_buffer.data(), dst_size); | ||
| 64 | Tegra::Texture::SwizzleKepler(regs.dest.width, regs.dest.height, regs.dest.x, | ||
| 65 | regs.dest.y, regs.dest.BlockHeight(), state.copy_size, | ||
| 66 | state.inner_buffer.data(), tmp_buffer.data()); | ||
| 67 | memory_manager.WriteBlock(address, tmp_buffer.data(), dst_size); | ||
| 68 | } | ||
| 69 | system.GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); | ||
| 70 | } | ||
| 54 | } | 71 | } |
| 55 | 72 | ||
| 56 | } // namespace Tegra::Engines | 73 | } // namespace Tegra::Engines |
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h index 78b6c3e45..5f892ddad 100644 --- a/src/video_core/engines/kepler_memory.h +++ b/src/video_core/engines/kepler_memory.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include <vector> | ||
| 9 | #include "common/bit_field.h" | 10 | #include "common/bit_field.h" |
| 10 | #include "common/common_funcs.h" | 11 | #include "common/common_funcs.h" |
| 11 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| @@ -51,7 +52,11 @@ public: | |||
| 51 | u32 address_high; | 52 | u32 address_high; |
| 52 | u32 address_low; | 53 | u32 address_low; |
| 53 | u32 pitch; | 54 | u32 pitch; |
| 54 | u32 block_dimensions; | 55 | union { |
| 56 | BitField<0, 4, u32> block_width; | ||
| 57 | BitField<4, 4, u32> block_height; | ||
| 58 | BitField<8, 4, u32> block_depth; | ||
| 59 | }; | ||
| 55 | u32 width; | 60 | u32 width; |
| 56 | u32 height; | 61 | u32 height; |
| 57 | u32 depth; | 62 | u32 depth; |
| @@ -63,6 +68,18 @@ public: | |||
| 63 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | | 68 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | |
| 64 | address_low); | 69 | address_low); |
| 65 | } | 70 | } |
| 71 | |||
| 72 | u32 BlockWidth() const { | ||
| 73 | return 1U << block_width.Value(); | ||
| 74 | } | ||
| 75 | |||
| 76 | u32 BlockHeight() const { | ||
| 77 | return 1U << block_height.Value(); | ||
| 78 | } | ||
| 79 | |||
| 80 | u32 BlockDepth() const { | ||
| 81 | return 1U << block_depth.Value(); | ||
| 82 | } | ||
| 66 | } dest; | 83 | } dest; |
| 67 | 84 | ||
| 68 | struct { | 85 | struct { |
| @@ -81,6 +98,8 @@ public: | |||
| 81 | 98 | ||
| 82 | struct { | 99 | struct { |
| 83 | u32 write_offset = 0; | 100 | u32 write_offset = 0; |
| 101 | u32 copy_size = 0; | ||
| 102 | std::vector<u8> inner_buffer; | ||
| 84 | } state{}; | 103 | } state{}; |
| 85 | 104 | ||
| 86 | private: | 105 | private: |
| @@ -88,7 +107,8 @@ private: | |||
| 88 | VideoCore::RasterizerInterface& rasterizer; | 107 | VideoCore::RasterizerInterface& rasterizer; |
| 89 | MemoryManager& memory_manager; | 108 | MemoryManager& memory_manager; |
| 90 | 109 | ||
| 91 | void ProcessData(u32 data); | 110 | void ProcessExec(); |
| 111 | void ProcessData(u32 data, bool is_last_call); | ||
| 92 | }; | 112 | }; |
| 93 | 113 | ||
| 94 | #define ASSERT_REG_POSITION(field_name, position) \ | 114 | #define ASSERT_REG_POSITION(field_name, position) \ |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 74403eed4..9780417f2 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -418,7 +418,7 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { | |||
| 418 | const GPUVAddr tic_address_gpu{regs.tic.TICAddress() + tic_index * sizeof(Texture::TICEntry)}; | 418 | const GPUVAddr tic_address_gpu{regs.tic.TICAddress() + tic_index * sizeof(Texture::TICEntry)}; |
| 419 | 419 | ||
| 420 | Texture::TICEntry tic_entry; | 420 | Texture::TICEntry tic_entry; |
| 421 | memory_manager.ReadBlock(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry)); | 421 | memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry)); |
| 422 | 422 | ||
| 423 | ASSERT_MSG(tic_entry.header_version == Texture::TICHeaderVersion::BlockLinear || | 423 | ASSERT_MSG(tic_entry.header_version == Texture::TICHeaderVersion::BlockLinear || |
| 424 | tic_entry.header_version == Texture::TICHeaderVersion::Pitch, | 424 | tic_entry.header_version == Texture::TICHeaderVersion::Pitch, |
| @@ -439,7 +439,7 @@ Texture::TSCEntry Maxwell3D::GetTSCEntry(u32 tsc_index) const { | |||
| 439 | const GPUVAddr tsc_address_gpu{regs.tsc.TSCAddress() + tsc_index * sizeof(Texture::TSCEntry)}; | 439 | const GPUVAddr tsc_address_gpu{regs.tsc.TSCAddress() + tsc_index * sizeof(Texture::TSCEntry)}; |
| 440 | 440 | ||
| 441 | Texture::TSCEntry tsc_entry; | 441 | Texture::TSCEntry tsc_entry; |
| 442 | memory_manager.ReadBlock(tsc_address_gpu, &tsc_entry, sizeof(Texture::TSCEntry)); | 442 | memory_manager.ReadBlockUnsafe(tsc_address_gpu, &tsc_entry, sizeof(Texture::TSCEntry)); |
| 443 | return tsc_entry; | 443 | return tsc_entry; |
| 444 | } | 444 | } |
| 445 | 445 | ||
| @@ -482,19 +482,8 @@ std::vector<Texture::FullTextureInfo> Maxwell3D::GetStageTextures(Regs::ShaderSt | |||
| 482 | return textures; | 482 | return textures; |
| 483 | } | 483 | } |
| 484 | 484 | ||
| 485 | Texture::FullTextureInfo Maxwell3D::GetStageTexture(Regs::ShaderStage stage, | 485 | Texture::FullTextureInfo Maxwell3D::GetTextureInfo(const Texture::TextureHandle tex_handle, |
| 486 | std::size_t offset) const { | 486 | std::size_t offset) const { |
| 487 | auto& shader = state.shader_stages[static_cast<std::size_t>(stage)]; | ||
| 488 | auto& tex_info_buffer = shader.const_buffers[regs.tex_cb_index]; | ||
| 489 | ASSERT(tex_info_buffer.enabled && tex_info_buffer.address != 0); | ||
| 490 | |||
| 491 | const GPUVAddr tex_info_address = | ||
| 492 | tex_info_buffer.address + offset * sizeof(Texture::TextureHandle); | ||
| 493 | |||
| 494 | ASSERT(tex_info_address < tex_info_buffer.address + tex_info_buffer.size); | ||
| 495 | |||
| 496 | const Texture::TextureHandle tex_handle{memory_manager.Read<u32>(tex_info_address)}; | ||
| 497 | |||
| 498 | Texture::FullTextureInfo tex_info{}; | 487 | Texture::FullTextureInfo tex_info{}; |
| 499 | tex_info.index = static_cast<u32>(offset); | 488 | tex_info.index = static_cast<u32>(offset); |
| 500 | 489 | ||
| @@ -511,6 +500,22 @@ Texture::FullTextureInfo Maxwell3D::GetStageTexture(Regs::ShaderStage stage, | |||
| 511 | return tex_info; | 500 | return tex_info; |
| 512 | } | 501 | } |
| 513 | 502 | ||
| 503 | Texture::FullTextureInfo Maxwell3D::GetStageTexture(Regs::ShaderStage stage, | ||
| 504 | std::size_t offset) const { | ||
| 505 | const auto& shader = state.shader_stages[static_cast<std::size_t>(stage)]; | ||
| 506 | const auto& tex_info_buffer = shader.const_buffers[regs.tex_cb_index]; | ||
| 507 | ASSERT(tex_info_buffer.enabled && tex_info_buffer.address != 0); | ||
| 508 | |||
| 509 | const GPUVAddr tex_info_address = | ||
| 510 | tex_info_buffer.address + offset * sizeof(Texture::TextureHandle); | ||
| 511 | |||
| 512 | ASSERT(tex_info_address < tex_info_buffer.address + tex_info_buffer.size); | ||
| 513 | |||
| 514 | const Texture::TextureHandle tex_handle{memory_manager.Read<u32>(tex_info_address)}; | ||
| 515 | |||
| 516 | return GetTextureInfo(tex_handle, offset); | ||
| 517 | } | ||
| 518 | |||
| 514 | u32 Maxwell3D::GetRegisterValue(u32 method) const { | 519 | u32 Maxwell3D::GetRegisterValue(u32 method) const { |
| 515 | ASSERT_MSG(method < Regs::NUM_REGS, "Invalid Maxwell3D register"); | 520 | ASSERT_MSG(method < Regs::NUM_REGS, "Invalid Maxwell3D register"); |
| 516 | return regs.reg_array[method]; | 521 | return regs.reg_array[method]; |
| @@ -524,4 +529,12 @@ void Maxwell3D::ProcessClearBuffers() { | |||
| 524 | rasterizer.Clear(); | 529 | rasterizer.Clear(); |
| 525 | } | 530 | } |
| 526 | 531 | ||
| 532 | u32 Maxwell3D::AccessConstBuffer32(Regs::ShaderStage stage, u64 const_buffer, u64 offset) const { | ||
| 533 | const auto& shader_stage = state.shader_stages[static_cast<std::size_t>(stage)]; | ||
| 534 | const auto& buffer = shader_stage.const_buffers[const_buffer]; | ||
| 535 | u32 result; | ||
| 536 | std::memcpy(&result, memory_manager.GetPointer(buffer.address + offset), sizeof(u32)); | ||
| 537 | return result; | ||
| 538 | } | ||
| 539 | |||
| 527 | } // namespace Tegra::Engines | 540 | } // namespace Tegra::Engines |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index a47d5607c..85d309d9b 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -1132,12 +1132,18 @@ public: | |||
| 1132 | /// Write the value to the register identified by method. | 1132 | /// Write the value to the register identified by method. |
| 1133 | void CallMethod(const GPU::MethodCall& method_call); | 1133 | void CallMethod(const GPU::MethodCall& method_call); |
| 1134 | 1134 | ||
| 1135 | /// Given a Texture Handle, returns the TSC and TIC entries. | ||
| 1136 | Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle, | ||
| 1137 | std::size_t offset) const; | ||
| 1138 | |||
| 1135 | /// Returns a list of enabled textures for the specified shader stage. | 1139 | /// Returns a list of enabled textures for the specified shader stage. |
| 1136 | std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const; | 1140 | std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const; |
| 1137 | 1141 | ||
| 1138 | /// Returns the texture information for a specific texture in a specific shader stage. | 1142 | /// Returns the texture information for a specific texture in a specific shader stage. |
| 1139 | Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const; | 1143 | Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const; |
| 1140 | 1144 | ||
| 1145 | u32 AccessConstBuffer32(Regs::ShaderStage stage, u64 const_buffer, u64 offset) const; | ||
| 1146 | |||
| 1141 | /// Memory for macro code - it's undetermined how big this is, however 1MB is much larger than | 1147 | /// Memory for macro code - it's undetermined how big this is, however 1MB is much larger than |
| 1142 | /// we've seen used. | 1148 | /// we've seen used. |
| 1143 | using MacroMemory = std::array<u32, 0x40000>; | 1149 | using MacroMemory = std::array<u32, 0x40000>; |
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 2e1e96c81..e5b4eadea 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -387,6 +387,20 @@ enum class IpaSampleMode : u64 { | |||
| 387 | Offset = 2, | 387 | Offset = 2, |
| 388 | }; | 388 | }; |
| 389 | 389 | ||
| 390 | enum class LmemLoadCacheManagement : u64 { | ||
| 391 | Default = 0, | ||
| 392 | LU = 1, | ||
| 393 | CI = 2, | ||
| 394 | CV = 3, | ||
| 395 | }; | ||
| 396 | |||
| 397 | enum class LmemStoreCacheManagement : u64 { | ||
| 398 | Default = 0, | ||
| 399 | CG = 1, | ||
| 400 | CS = 2, | ||
| 401 | WT = 3, | ||
| 402 | }; | ||
| 403 | |||
| 390 | struct IpaMode { | 404 | struct IpaMode { |
| 391 | IpaInterpMode interpolation_mode; | 405 | IpaInterpMode interpolation_mode; |
| 392 | IpaSampleMode sampling_mode; | 406 | IpaSampleMode sampling_mode; |
| @@ -782,7 +796,7 @@ union Instruction { | |||
| 782 | } ld_l; | 796 | } ld_l; |
| 783 | 797 | ||
| 784 | union { | 798 | union { |
| 785 | BitField<44, 2, u64> unknown; | 799 | BitField<44, 2, LmemStoreCacheManagement> cache_management; |
| 786 | } st_l; | 800 | } st_l; |
| 787 | 801 | ||
| 788 | union { | 802 | union { |
| @@ -792,6 +806,12 @@ union Instruction { | |||
| 792 | } ldg; | 806 | } ldg; |
| 793 | 807 | ||
| 794 | union { | 808 | union { |
| 809 | BitField<48, 3, UniformType> type; | ||
| 810 | BitField<46, 2, u64> cache_mode; | ||
| 811 | BitField<20, 24, s64> immediate_offset; | ||
| 812 | } stg; | ||
| 813 | |||
| 814 | union { | ||
| 795 | BitField<0, 3, u64> pred0; | 815 | BitField<0, 3, u64> pred0; |
| 796 | BitField<3, 3, u64> pred3; | 816 | BitField<3, 3, u64> pred3; |
| 797 | BitField<7, 1, u64> abs_a; | 817 | BitField<7, 1, u64> abs_a; |
| @@ -917,21 +937,34 @@ union Instruction { | |||
| 917 | } iset; | 937 | } iset; |
| 918 | 938 | ||
| 919 | union { | 939 | union { |
| 920 | BitField<8, 2, Register::Size> dest_size; | 940 | BitField<41, 2, u64> selector; // i2i and i2f only |
| 921 | BitField<10, 2, Register::Size> src_size; | ||
| 922 | BitField<12, 1, u64> is_output_signed; | ||
| 923 | BitField<13, 1, u64> is_input_signed; | ||
| 924 | BitField<41, 2, u64> selector; | ||
| 925 | BitField<45, 1, u64> negate_a; | 941 | BitField<45, 1, u64> negate_a; |
| 926 | BitField<49, 1, u64> abs_a; | 942 | BitField<49, 1, u64> abs_a; |
| 943 | BitField<10, 2, Register::Size> src_size; | ||
| 944 | BitField<13, 1, u64> is_input_signed; | ||
| 945 | BitField<8, 2, Register::Size> dst_size; | ||
| 946 | BitField<12, 1, u64> is_output_signed; | ||
| 947 | |||
| 948 | union { | ||
| 949 | BitField<39, 2, u64> tab5cb8_2; | ||
| 950 | } i2f; | ||
| 927 | 951 | ||
| 928 | union { | 952 | union { |
| 929 | BitField<39, 2, F2iRoundingOp> rounding; | 953 | BitField<39, 2, F2iRoundingOp> rounding; |
| 930 | } f2i; | 954 | } f2i; |
| 931 | 955 | ||
| 932 | union { | 956 | union { |
| 933 | BitField<39, 4, F2fRoundingOp> rounding; | 957 | BitField<8, 2, Register::Size> src_size; |
| 958 | BitField<10, 2, Register::Size> dst_size; | ||
| 959 | BitField<39, 4, u64> rounding; | ||
| 960 | // H0, H1 extract for F16 missing | ||
| 961 | BitField<41, 1, u64> selector; // Guessed as some games set it, TODO: reverse this value | ||
| 962 | F2fRoundingOp GetRoundingMode() const { | ||
| 963 | constexpr u64 rounding_mask = 0x0B; | ||
| 964 | return static_cast<F2fRoundingOp>(rounding.Value() & rounding_mask); | ||
| 965 | } | ||
| 934 | } f2f; | 966 | } f2f; |
| 967 | |||
| 935 | } conversion; | 968 | } conversion; |
| 936 | 969 | ||
| 937 | union { | 970 | union { |
| @@ -967,6 +1000,38 @@ union Instruction { | |||
| 967 | } tex; | 1000 | } tex; |
| 968 | 1001 | ||
| 969 | union { | 1002 | union { |
| 1003 | BitField<28, 1, u64> array; | ||
| 1004 | BitField<29, 2, TextureType> texture_type; | ||
| 1005 | BitField<31, 4, u64> component_mask; | ||
| 1006 | BitField<49, 1, u64> nodep_flag; | ||
| 1007 | BitField<50, 1, u64> dc_flag; | ||
| 1008 | BitField<36, 1, u64> aoffi_flag; | ||
| 1009 | BitField<37, 3, TextureProcessMode> process_mode; | ||
| 1010 | |||
| 1011 | bool IsComponentEnabled(std::size_t component) const { | ||
| 1012 | return ((1ULL << component) & component_mask) != 0; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | TextureProcessMode GetTextureProcessMode() const { | ||
| 1016 | return process_mode; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | bool UsesMiscMode(TextureMiscMode mode) const { | ||
| 1020 | switch (mode) { | ||
| 1021 | case TextureMiscMode::DC: | ||
| 1022 | return dc_flag != 0; | ||
| 1023 | case TextureMiscMode::NODEP: | ||
| 1024 | return nodep_flag != 0; | ||
| 1025 | case TextureMiscMode::AOFFI: | ||
| 1026 | return aoffi_flag != 0; | ||
| 1027 | default: | ||
| 1028 | break; | ||
| 1029 | } | ||
| 1030 | return false; | ||
| 1031 | } | ||
| 1032 | } tex_b; | ||
| 1033 | |||
| 1034 | union { | ||
| 970 | BitField<22, 6, TextureQueryType> query_type; | 1035 | BitField<22, 6, TextureQueryType> query_type; |
| 971 | BitField<31, 4, u64> component_mask; | 1036 | BitField<31, 4, u64> component_mask; |
| 972 | BitField<49, 1, u64> nodep_flag; | 1037 | BitField<49, 1, u64> nodep_flag; |
| @@ -1312,7 +1377,9 @@ public: | |||
| 1312 | LDG, // Load from global memory | 1377 | LDG, // Load from global memory |
| 1313 | STG, // Store in global memory | 1378 | STG, // Store in global memory |
| 1314 | TEX, | 1379 | TEX, |
| 1380 | TEX_B, // Texture Load Bindless | ||
| 1315 | TXQ, // Texture Query | 1381 | TXQ, // Texture Query |
| 1382 | TXQ_B, // Texture Query Bindless | ||
| 1316 | TEXS, // Texture Fetch with scalar/non-vec4 source/destinations | 1383 | TEXS, // Texture Fetch with scalar/non-vec4 source/destinations |
| 1317 | TLDS, // Texture Load with scalar/non-vec4 source/destinations | 1384 | TLDS, // Texture Load with scalar/non-vec4 source/destinations |
| 1318 | TLD4, // Texture Load 4 | 1385 | TLD4, // Texture Load 4 |
| @@ -1580,7 +1647,9 @@ private: | |||
| 1580 | INST("1110111011010---", Id::LDG, Type::Memory, "LDG"), | 1647 | INST("1110111011010---", Id::LDG, Type::Memory, "LDG"), |
| 1581 | INST("1110111011011---", Id::STG, Type::Memory, "STG"), | 1648 | INST("1110111011011---", Id::STG, Type::Memory, "STG"), |
| 1582 | INST("110000----111---", Id::TEX, Type::Texture, "TEX"), | 1649 | INST("110000----111---", Id::TEX, Type::Texture, "TEX"), |
| 1650 | INST("1101111010111---", Id::TEX_B, Type::Texture, "TEX_B"), | ||
| 1583 | INST("1101111101001---", Id::TXQ, Type::Texture, "TXQ"), | 1651 | INST("1101111101001---", Id::TXQ, Type::Texture, "TXQ"), |
| 1652 | INST("1101111101010---", Id::TXQ_B, Type::Texture, "TXQ_B"), | ||
| 1584 | INST("1101-00---------", Id::TEXS, Type::Texture, "TEXS"), | 1653 | INST("1101-00---------", Id::TEXS, Type::Texture, "TEXS"), |
| 1585 | INST("1101101---------", Id::TLDS, Type::Texture, "TLDS"), | 1654 | INST("1101101---------", Id::TLDS, Type::Texture, "TLDS"), |
| 1586 | INST("110010----111---", Id::TLD4, Type::Texture, "TLD4"), | 1655 | INST("110010----111---", Id::TLD4, Type::Texture, "TLD4"), |
| @@ -1678,7 +1747,7 @@ private: | |||
| 1678 | INST("0011100-00101---", Id::SHR_IMM, Type::Shift, "SHR_IMM"), | 1747 | INST("0011100-00101---", Id::SHR_IMM, Type::Shift, "SHR_IMM"), |
| 1679 | INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"), | 1748 | INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"), |
| 1680 | INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"), | 1749 | INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"), |
| 1681 | INST("01110001-1000---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"), | 1750 | INST("0011101-11100---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"), |
| 1682 | INST("0100110010111---", Id::I2F_C, Type::Conversion, "I2F_C"), | 1751 | INST("0100110010111---", Id::I2F_C, Type::Conversion, "I2F_C"), |
| 1683 | INST("0101110010111---", Id::I2F_R, Type::Conversion, "I2F_R"), | 1752 | INST("0101110010111---", Id::I2F_R, Type::Conversion, "I2F_R"), |
| 1684 | INST("0011100-10111---", Id::I2F_IMM, Type::Conversion, "I2F_IMM"), | 1753 | INST("0011100-10111---", Id::I2F_IMM, Type::Conversion, "I2F_IMM"), |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index de30ea354..fe6628923 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -207,6 +207,11 @@ public: | |||
| 207 | }; | 207 | }; |
| 208 | } regs{}; | 208 | } regs{}; |
| 209 | 209 | ||
| 210 | /// Performs any additional setup necessary in order to begin GPU emulation. | ||
| 211 | /// This can be used to launch any necessary threads and register any necessary | ||
| 212 | /// core timing events. | ||
| 213 | virtual void Start() = 0; | ||
| 214 | |||
| 210 | /// Push GPU command entries to be processed | 215 | /// Push GPU command entries to be processed |
| 211 | virtual void PushGPUEntries(Tegra::CommandList&& entries) = 0; | 216 | virtual void PushGPUEntries(Tegra::CommandList&& entries) = 0; |
| 212 | 217 | ||
diff --git a/src/video_core/gpu_asynch.cpp b/src/video_core/gpu_asynch.cpp index db507cf04..d4e2553a9 100644 --- a/src/video_core/gpu_asynch.cpp +++ b/src/video_core/gpu_asynch.cpp | |||
| @@ -9,10 +9,14 @@ | |||
| 9 | namespace VideoCommon { | 9 | namespace VideoCommon { |
| 10 | 10 | ||
| 11 | GPUAsynch::GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer) | 11 | GPUAsynch::GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer) |
| 12 | : Tegra::GPU(system, renderer), gpu_thread{system, renderer, *dma_pusher} {} | 12 | : GPU(system, renderer), gpu_thread{system} {} |
| 13 | 13 | ||
| 14 | GPUAsynch::~GPUAsynch() = default; | 14 | GPUAsynch::~GPUAsynch() = default; |
| 15 | 15 | ||
| 16 | void GPUAsynch::Start() { | ||
| 17 | gpu_thread.StartThread(renderer, *dma_pusher); | ||
| 18 | } | ||
| 19 | |||
| 16 | void GPUAsynch::PushGPUEntries(Tegra::CommandList&& entries) { | 20 | void GPUAsynch::PushGPUEntries(Tegra::CommandList&& entries) { |
| 17 | gpu_thread.SubmitList(std::move(entries)); | 21 | gpu_thread.SubmitList(std::move(entries)); |
| 18 | } | 22 | } |
diff --git a/src/video_core/gpu_asynch.h b/src/video_core/gpu_asynch.h index 1dcc61a6c..30be74cba 100644 --- a/src/video_core/gpu_asynch.h +++ b/src/video_core/gpu_asynch.h | |||
| @@ -13,16 +13,13 @@ class RendererBase; | |||
| 13 | 13 | ||
| 14 | namespace VideoCommon { | 14 | namespace VideoCommon { |
| 15 | 15 | ||
| 16 | namespace GPUThread { | ||
| 17 | class ThreadManager; | ||
| 18 | } // namespace GPUThread | ||
| 19 | |||
| 20 | /// Implementation of GPU interface that runs the GPU asynchronously | 16 | /// Implementation of GPU interface that runs the GPU asynchronously |
| 21 | class GPUAsynch : public Tegra::GPU { | 17 | class GPUAsynch : public Tegra::GPU { |
| 22 | public: | 18 | public: |
| 23 | explicit GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer); | 19 | explicit GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer); |
| 24 | ~GPUAsynch() override; | 20 | ~GPUAsynch() override; |
| 25 | 21 | ||
| 22 | void Start() override; | ||
| 26 | void PushGPUEntries(Tegra::CommandList&& entries) override; | 23 | void PushGPUEntries(Tegra::CommandList&& entries) override; |
| 27 | void SwapBuffers( | 24 | void SwapBuffers( |
| 28 | std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) override; | 25 | std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) override; |
diff --git a/src/video_core/gpu_synch.cpp b/src/video_core/gpu_synch.cpp index 2cfc900ed..45e43b1dc 100644 --- a/src/video_core/gpu_synch.cpp +++ b/src/video_core/gpu_synch.cpp | |||
| @@ -8,10 +8,12 @@ | |||
| 8 | namespace VideoCommon { | 8 | namespace VideoCommon { |
| 9 | 9 | ||
| 10 | GPUSynch::GPUSynch(Core::System& system, VideoCore::RendererBase& renderer) | 10 | GPUSynch::GPUSynch(Core::System& system, VideoCore::RendererBase& renderer) |
| 11 | : Tegra::GPU(system, renderer) {} | 11 | : GPU(system, renderer) {} |
| 12 | 12 | ||
| 13 | GPUSynch::~GPUSynch() = default; | 13 | GPUSynch::~GPUSynch() = default; |
| 14 | 14 | ||
| 15 | void GPUSynch::Start() {} | ||
| 16 | |||
| 15 | void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { | 17 | void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { |
| 16 | dma_pusher->Push(std::move(entries)); | 18 | dma_pusher->Push(std::move(entries)); |
| 17 | dma_pusher->DispatchCalls(); | 19 | dma_pusher->DispatchCalls(); |
diff --git a/src/video_core/gpu_synch.h b/src/video_core/gpu_synch.h index 766b5631c..3031fcf72 100644 --- a/src/video_core/gpu_synch.h +++ b/src/video_core/gpu_synch.h | |||
| @@ -18,6 +18,7 @@ public: | |||
| 18 | explicit GPUSynch(Core::System& system, VideoCore::RendererBase& renderer); | 18 | explicit GPUSynch(Core::System& system, VideoCore::RendererBase& renderer); |
| 19 | ~GPUSynch() override; | 19 | ~GPUSynch() override; |
| 20 | 20 | ||
| 21 | void Start() override; | ||
| 21 | void PushGPUEntries(Tegra::CommandList&& entries) override; | 22 | void PushGPUEntries(Tegra::CommandList&& entries) override; |
| 22 | void SwapBuffers( | 23 | void SwapBuffers( |
| 23 | std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) override; | 24 | std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) override; |
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index cc56cf467..c9a2077de 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp | |||
| @@ -55,19 +55,24 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p | |||
| 55 | } | 55 | } |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | ThreadManager::ThreadManager(Core::System& system, VideoCore::RendererBase& renderer, | 58 | ThreadManager::ThreadManager(Core::System& system) : system{system} {} |
| 59 | Tegra::DmaPusher& dma_pusher) | ||
| 60 | : system{system}, thread{RunThread, std::ref(renderer), std::ref(dma_pusher), std::ref(state)} { | ||
| 61 | synchronization_event = system.CoreTiming().RegisterEvent( | ||
| 62 | "GPUThreadSynch", [this](u64 fence, s64) { state.WaitForSynchronization(fence); }); | ||
| 63 | } | ||
| 64 | 59 | ||
| 65 | ThreadManager::~ThreadManager() { | 60 | ThreadManager::~ThreadManager() { |
| 61 | if (!thread.joinable()) { | ||
| 62 | return; | ||
| 63 | } | ||
| 64 | |||
| 66 | // Notify GPU thread that a shutdown is pending | 65 | // Notify GPU thread that a shutdown is pending |
| 67 | PushCommand(EndProcessingCommand()); | 66 | PushCommand(EndProcessingCommand()); |
| 68 | thread.join(); | 67 | thread.join(); |
| 69 | } | 68 | } |
| 70 | 69 | ||
| 70 | void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher) { | ||
| 71 | thread = std::thread{RunThread, std::ref(renderer), std::ref(dma_pusher), std::ref(state)}; | ||
| 72 | synchronization_event = system.CoreTiming().RegisterEvent( | ||
| 73 | "GPUThreadSynch", [this](u64 fence, s64) { state.WaitForSynchronization(fence); }); | ||
| 74 | } | ||
| 75 | |||
| 71 | void ThreadManager::SubmitList(Tegra::CommandList&& entries) { | 76 | void ThreadManager::SubmitList(Tegra::CommandList&& entries) { |
| 72 | const u64 fence{PushCommand(SubmitListCommand(std::move(entries)))}; | 77 | const u64 fence{PushCommand(SubmitListCommand(std::move(entries)))}; |
| 73 | const s64 synchronization_ticks{Core::Timing::usToCycles(9000)}; | 78 | const s64 synchronization_ticks{Core::Timing::usToCycles(9000)}; |
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h index 62bcea5bb..cc14527c7 100644 --- a/src/video_core/gpu_thread.h +++ b/src/video_core/gpu_thread.h | |||
| @@ -138,10 +138,12 @@ struct SynchState final { | |||
| 138 | /// Class used to manage the GPU thread | 138 | /// Class used to manage the GPU thread |
| 139 | class ThreadManager final { | 139 | class ThreadManager final { |
| 140 | public: | 140 | public: |
| 141 | explicit ThreadManager(Core::System& system, VideoCore::RendererBase& renderer, | 141 | explicit ThreadManager(Core::System& system); |
| 142 | Tegra::DmaPusher& dma_pusher); | ||
| 143 | ~ThreadManager(); | 142 | ~ThreadManager(); |
| 144 | 143 | ||
| 144 | /// Creates and starts the GPU thread. | ||
| 145 | void StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher); | ||
| 146 | |||
| 145 | /// Push GPU command entries to be processed | 147 | /// Push GPU command entries to be processed |
| 146 | void SubmitList(Tegra::CommandList&& entries); | 148 | void SubmitList(Tegra::CommandList&& entries); |
| 147 | 149 | ||
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 0f4e820aa..6c98c6701 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp | |||
| @@ -199,7 +199,15 @@ const u8* MemoryManager::GetPointer(GPUVAddr addr) const { | |||
| 199 | return {}; | 199 | return {}; |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const { | 202 | bool MemoryManager::IsBlockContinous(const GPUVAddr start, const std::size_t size) { |
| 203 | const GPUVAddr end = start + size; | ||
| 204 | const auto host_ptr_start = reinterpret_cast<std::uintptr_t>(GetPointer(start)); | ||
| 205 | const auto host_ptr_end = reinterpret_cast<std::uintptr_t>(GetPointer(end)); | ||
| 206 | const std::size_t range = static_cast<std::size_t>(host_ptr_end - host_ptr_start); | ||
| 207 | return range == size; | ||
| 208 | } | ||
| 209 | |||
| 210 | void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, const std::size_t size) const { | ||
| 203 | std::size_t remaining_size{size}; | 211 | std::size_t remaining_size{size}; |
| 204 | std::size_t page_index{src_addr >> page_bits}; | 212 | std::size_t page_index{src_addr >> page_bits}; |
| 205 | std::size_t page_offset{src_addr & page_mask}; | 213 | std::size_t page_offset{src_addr & page_mask}; |
| @@ -226,7 +234,30 @@ void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t | |||
| 226 | } | 234 | } |
| 227 | } | 235 | } |
| 228 | 236 | ||
| 229 | void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size) { | 237 | void MemoryManager::ReadBlockUnsafe(GPUVAddr src_addr, void* dest_buffer, |
| 238 | const std::size_t size) const { | ||
| 239 | std::size_t remaining_size{size}; | ||
| 240 | std::size_t page_index{src_addr >> page_bits}; | ||
| 241 | std::size_t page_offset{src_addr & page_mask}; | ||
| 242 | |||
| 243 | while (remaining_size > 0) { | ||
| 244 | const std::size_t copy_amount{ | ||
| 245 | std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)}; | ||
| 246 | const u8* page_pointer = page_table.pointers[page_index]; | ||
| 247 | if (page_pointer) { | ||
| 248 | const u8* src_ptr{page_pointer + page_offset}; | ||
| 249 | std::memcpy(dest_buffer, src_ptr, copy_amount); | ||
| 250 | } else { | ||
| 251 | std::memset(dest_buffer, 0, copy_amount); | ||
| 252 | } | ||
| 253 | page_index++; | ||
| 254 | page_offset = 0; | ||
| 255 | dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; | ||
| 256 | remaining_size -= copy_amount; | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, const std::size_t size) { | ||
| 230 | std::size_t remaining_size{size}; | 261 | std::size_t remaining_size{size}; |
| 231 | std::size_t page_index{dest_addr >> page_bits}; | 262 | std::size_t page_index{dest_addr >> page_bits}; |
| 232 | std::size_t page_offset{dest_addr & page_mask}; | 263 | std::size_t page_offset{dest_addr & page_mask}; |
| @@ -253,7 +284,28 @@ void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std:: | |||
| 253 | } | 284 | } |
| 254 | } | 285 | } |
| 255 | 286 | ||
| 256 | void MemoryManager::CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size) { | 287 | void MemoryManager::WriteBlockUnsafe(GPUVAddr dest_addr, const void* src_buffer, |
| 288 | const std::size_t size) { | ||
| 289 | std::size_t remaining_size{size}; | ||
| 290 | std::size_t page_index{dest_addr >> page_bits}; | ||
| 291 | std::size_t page_offset{dest_addr & page_mask}; | ||
| 292 | |||
| 293 | while (remaining_size > 0) { | ||
| 294 | const std::size_t copy_amount{ | ||
| 295 | std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)}; | ||
| 296 | u8* page_pointer = page_table.pointers[page_index]; | ||
| 297 | if (page_pointer) { | ||
| 298 | u8* dest_ptr{page_pointer + page_offset}; | ||
| 299 | std::memcpy(dest_ptr, src_buffer, copy_amount); | ||
| 300 | } | ||
| 301 | page_index++; | ||
| 302 | page_offset = 0; | ||
| 303 | src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; | ||
| 304 | remaining_size -= copy_amount; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | void MemoryManager::CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, const std::size_t size) { | ||
| 257 | std::size_t remaining_size{size}; | 309 | std::size_t remaining_size{size}; |
| 258 | std::size_t page_index{src_addr >> page_bits}; | 310 | std::size_t page_index{src_addr >> page_bits}; |
| 259 | std::size_t page_offset{src_addr & page_mask}; | 311 | std::size_t page_offset{src_addr & page_mask}; |
| @@ -281,6 +333,12 @@ void MemoryManager::CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t | |||
| 281 | } | 333 | } |
| 282 | } | 334 | } |
| 283 | 335 | ||
| 336 | void MemoryManager::CopyBlockUnsafe(GPUVAddr dest_addr, GPUVAddr src_addr, const std::size_t size) { | ||
| 337 | std::vector<u8> tmp_buffer(size); | ||
| 338 | ReadBlockUnsafe(src_addr, tmp_buffer.data(), size); | ||
| 339 | WriteBlockUnsafe(dest_addr, tmp_buffer.data(), size); | ||
| 340 | } | ||
| 341 | |||
| 284 | void MemoryManager::MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type, | 342 | void MemoryManager::MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type, |
| 285 | VAddr backing_addr) { | 343 | VAddr backing_addr) { |
| 286 | LOG_DEBUG(HW_GPU, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * page_size, | 344 | LOG_DEBUG(HW_GPU, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * page_size, |
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 647cbf93a..e4f0c4bd6 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h | |||
| @@ -65,9 +65,32 @@ public: | |||
| 65 | u8* GetPointer(GPUVAddr addr); | 65 | u8* GetPointer(GPUVAddr addr); |
| 66 | const u8* GetPointer(GPUVAddr addr) const; | 66 | const u8* GetPointer(GPUVAddr addr) const; |
| 67 | 67 | ||
| 68 | void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const; | 68 | // Returns true if the block is continous in host memory, false otherwise |
| 69 | void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size); | 69 | bool IsBlockContinous(const GPUVAddr start, const std::size_t size); |
| 70 | void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size); | 70 | |
| 71 | /** | ||
| 72 | * ReadBlock and WriteBlock are full read and write operations over virtual | ||
| 73 | * GPU Memory. It's important to use these when GPU memory may not be continous | ||
| 74 | * in the Host Memory counterpart. Note: This functions cause Host GPU Memory | ||
| 75 | * Flushes and Invalidations, respectively to each operation. | ||
| 76 | */ | ||
| 77 | void ReadBlock(GPUVAddr src_addr, void* dest_buffer, const std::size_t size) const; | ||
| 78 | void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, const std::size_t size); | ||
| 79 | void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, const std::size_t size); | ||
| 80 | |||
| 81 | /** | ||
| 82 | * ReadBlockUnsafe and WriteBlockUnsafe are special versions of ReadBlock and | ||
| 83 | * WriteBlock respectively. In this versions, no flushing or invalidation is actually | ||
| 84 | * done and their performance is similar to a memcpy. This functions can be used | ||
| 85 | * on either of this 2 scenarios instead of their safe counterpart: | ||
| 86 | * - Memory which is sure to never be represented in the Host GPU. | ||
| 87 | * - Memory Managed by a Cache Manager. Example: Texture Flushing should use | ||
| 88 | * WriteBlockUnsafe instead of WriteBlock since it shouldn't invalidate the texture | ||
| 89 | * being flushed. | ||
| 90 | */ | ||
| 91 | void ReadBlockUnsafe(GPUVAddr src_addr, void* dest_buffer, const std::size_t size) const; | ||
| 92 | void WriteBlockUnsafe(GPUVAddr dest_addr, const void* src_buffer, const std::size_t size); | ||
| 93 | void CopyBlockUnsafe(GPUVAddr dest_addr, GPUVAddr src_addr, const std::size_t size); | ||
| 71 | 94 | ||
| 72 | private: | 95 | private: |
| 73 | using VMAMap = std::map<GPUVAddr, VirtualMemoryArea>; | 96 | using VMAMap = std::map<GPUVAddr, VirtualMemoryArea>; |
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp new file mode 100644 index 000000000..b6d9e0ddb --- /dev/null +++ b/src/video_core/renderer_opengl/gl_device.cpp | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstddef> | ||
| 6 | #include <glad/glad.h> | ||
| 7 | |||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "video_core/renderer_opengl/gl_device.h" | ||
| 10 | |||
| 11 | namespace OpenGL { | ||
| 12 | |||
| 13 | namespace { | ||
| 14 | template <typename T> | ||
| 15 | T GetInteger(GLenum pname) { | ||
| 16 | GLint temporary; | ||
| 17 | glGetIntegerv(pname, &temporary); | ||
| 18 | return static_cast<T>(temporary); | ||
| 19 | } | ||
| 20 | } // Anonymous namespace | ||
| 21 | |||
| 22 | Device::Device() { | ||
| 23 | uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); | ||
| 24 | has_variable_aoffi = TestVariableAoffi(); | ||
| 25 | } | ||
| 26 | |||
| 27 | bool Device::TestVariableAoffi() { | ||
| 28 | const GLchar* AOFFI_TEST = R"(#version 430 core | ||
| 29 | uniform sampler2D tex; | ||
| 30 | uniform ivec2 variable_offset; | ||
| 31 | void main() { | ||
| 32 | gl_Position = textureOffset(tex, vec2(0), variable_offset); | ||
| 33 | } | ||
| 34 | )"; | ||
| 35 | const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &AOFFI_TEST)}; | ||
| 36 | GLint link_status{}; | ||
| 37 | glGetProgramiv(shader, GL_LINK_STATUS, &link_status); | ||
| 38 | glDeleteProgram(shader); | ||
| 39 | |||
| 40 | const bool supported{link_status == GL_TRUE}; | ||
| 41 | LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", supported); | ||
| 42 | return supported; | ||
| 43 | } | ||
| 44 | |||
| 45 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h new file mode 100644 index 000000000..78ff5ee58 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_device.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <cstddef> | ||
| 8 | |||
| 9 | namespace OpenGL { | ||
| 10 | |||
| 11 | class Device { | ||
| 12 | public: | ||
| 13 | Device(); | ||
| 14 | |||
| 15 | std::size_t GetUniformBufferAlignment() const { | ||
| 16 | return uniform_buffer_alignment; | ||
| 17 | } | ||
| 18 | |||
| 19 | bool HasVariableAoffi() const { | ||
| 20 | return has_variable_aoffi; | ||
| 21 | } | ||
| 22 | |||
| 23 | private: | ||
| 24 | static bool TestVariableAoffi(); | ||
| 25 | |||
| 26 | std::size_t uniform_buffer_alignment{}; | ||
| 27 | bool has_variable_aoffi{}; | ||
| 28 | }; | ||
| 29 | |||
| 30 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/gl_global_cache.cpp b/src/video_core/renderer_opengl/gl_global_cache.cpp index 8d9ee81f1..ea4a593af 100644 --- a/src/video_core/renderer_opengl/gl_global_cache.cpp +++ b/src/video_core/renderer_opengl/gl_global_cache.cpp | |||
| @@ -14,28 +14,28 @@ | |||
| 14 | 14 | ||
| 15 | namespace OpenGL { | 15 | namespace OpenGL { |
| 16 | 16 | ||
| 17 | CachedGlobalRegion::CachedGlobalRegion(VAddr cpu_addr, u32 size, u8* host_ptr) | 17 | CachedGlobalRegion::CachedGlobalRegion(VAddr cpu_addr, u8* host_ptr, u32 size, u32 max_size) |
| 18 | : RasterizerCacheObject{host_ptr}, cpu_addr{cpu_addr}, size{size} { | 18 | : RasterizerCacheObject{host_ptr}, cpu_addr{cpu_addr}, host_ptr{host_ptr}, size{size}, |
| 19 | max_size{max_size} { | ||
| 19 | buffer.Create(); | 20 | buffer.Create(); |
| 20 | // Bind and unbind the buffer so it gets allocated by the driver | ||
| 21 | glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer.handle); | ||
| 22 | glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); | ||
| 23 | LabelGLObject(GL_BUFFER, buffer.handle, cpu_addr, "GlobalMemory"); | 21 | LabelGLObject(GL_BUFFER, buffer.handle, cpu_addr, "GlobalMemory"); |
| 24 | } | 22 | } |
| 25 | 23 | ||
| 26 | void CachedGlobalRegion::Reload(u32 size_) { | 24 | CachedGlobalRegion::~CachedGlobalRegion() = default; |
| 27 | constexpr auto max_size = static_cast<u32>(RasterizerOpenGL::MaxGlobalMemorySize); | ||
| 28 | 25 | ||
| 26 | void CachedGlobalRegion::Reload(u32 size_) { | ||
| 29 | size = size_; | 27 | size = size_; |
| 30 | if (size > max_size) { | 28 | if (size > max_size) { |
| 31 | size = max_size; | 29 | size = max_size; |
| 32 | LOG_CRITICAL(HW_GPU, "Global region size {} exceeded the expected size {}!", size_, | 30 | LOG_CRITICAL(HW_GPU, "Global region size {} exceeded the supported size {}!", size_, |
| 33 | max_size); | 31 | max_size); |
| 34 | } | 32 | } |
| 33 | glNamedBufferData(buffer.handle, size, host_ptr, GL_STREAM_DRAW); | ||
| 34 | } | ||
| 35 | 35 | ||
| 36 | // TODO(Rodrigo): Get rid of Memory::GetPointer with a staging buffer | 36 | void CachedGlobalRegion::Flush() { |
| 37 | glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer.handle); | 37 | LOG_DEBUG(Render_OpenGL, "Flushing {} bytes to CPU memory address 0x{:16}", size, cpu_addr); |
| 38 | glBufferData(GL_SHADER_STORAGE_BUFFER, size, GetHostPtr(), GL_DYNAMIC_DRAW); | 38 | glGetNamedBufferSubData(buffer.handle, 0, static_cast<GLsizeiptr>(size), host_ptr); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | GlobalRegion GlobalRegionCacheOpenGL::TryGetReservedGlobalRegion(CacheAddr addr, u32 size) const { | 41 | GlobalRegion GlobalRegionCacheOpenGL::TryGetReservedGlobalRegion(CacheAddr addr, u32 size) const { |
| @@ -46,14 +46,16 @@ GlobalRegion GlobalRegionCacheOpenGL::TryGetReservedGlobalRegion(CacheAddr addr, | |||
| 46 | return search->second; | 46 | return search->second; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | GlobalRegion GlobalRegionCacheOpenGL::GetUncachedGlobalRegion(GPUVAddr addr, u32 size, | 49 | GlobalRegion GlobalRegionCacheOpenGL::GetUncachedGlobalRegion(GPUVAddr addr, u8* host_ptr, |
| 50 | u8* host_ptr) { | 50 | u32 size) { |
| 51 | GlobalRegion region{TryGetReservedGlobalRegion(ToCacheAddr(host_ptr), size)}; | 51 | GlobalRegion region{TryGetReservedGlobalRegion(ToCacheAddr(host_ptr), size)}; |
| 52 | if (!region) { | 52 | if (!region) { |
| 53 | // No reserved surface available, create a new one and reserve it | 53 | // No reserved surface available, create a new one and reserve it |
| 54 | auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()}; | 54 | auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()}; |
| 55 | const auto cpu_addr = *memory_manager.GpuToCpuAddress(addr); | 55 | const auto cpu_addr{memory_manager.GpuToCpuAddress(addr)}; |
| 56 | region = std::make_shared<CachedGlobalRegion>(cpu_addr, size, host_ptr); | 56 | ASSERT(cpu_addr); |
| 57 | |||
| 58 | region = std::make_shared<CachedGlobalRegion>(*cpu_addr, host_ptr, size, max_ssbo_size); | ||
| 57 | ReserveGlobalRegion(region); | 59 | ReserveGlobalRegion(region); |
| 58 | } | 60 | } |
| 59 | region->Reload(size); | 61 | region->Reload(size); |
| @@ -65,7 +67,11 @@ void GlobalRegionCacheOpenGL::ReserveGlobalRegion(GlobalRegion region) { | |||
| 65 | } | 67 | } |
| 66 | 68 | ||
| 67 | GlobalRegionCacheOpenGL::GlobalRegionCacheOpenGL(RasterizerOpenGL& rasterizer) | 69 | GlobalRegionCacheOpenGL::GlobalRegionCacheOpenGL(RasterizerOpenGL& rasterizer) |
| 68 | : RasterizerCache{rasterizer} {} | 70 | : RasterizerCache{rasterizer} { |
| 71 | GLint max_ssbo_size_; | ||
| 72 | glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &max_ssbo_size_); | ||
| 73 | max_ssbo_size = static_cast<u32>(max_ssbo_size_); | ||
| 74 | } | ||
| 69 | 75 | ||
| 70 | GlobalRegion GlobalRegionCacheOpenGL::GetGlobalRegion( | 76 | GlobalRegion GlobalRegionCacheOpenGL::GetGlobalRegion( |
| 71 | const GLShader::GlobalMemoryEntry& global_region, | 77 | const GLShader::GlobalMemoryEntry& global_region, |
| @@ -73,7 +79,7 @@ GlobalRegion GlobalRegionCacheOpenGL::GetGlobalRegion( | |||
| 73 | 79 | ||
| 74 | auto& gpu{Core::System::GetInstance().GPU()}; | 80 | auto& gpu{Core::System::GetInstance().GPU()}; |
| 75 | auto& memory_manager{gpu.MemoryManager()}; | 81 | auto& memory_manager{gpu.MemoryManager()}; |
| 76 | const auto cbufs{gpu.Maxwell3D().state.shader_stages[static_cast<u64>(stage)]}; | 82 | const auto cbufs{gpu.Maxwell3D().state.shader_stages[static_cast<std::size_t>(stage)]}; |
| 77 | const auto addr{cbufs.const_buffers[global_region.GetCbufIndex()].address + | 83 | const auto addr{cbufs.const_buffers[global_region.GetCbufIndex()].address + |
| 78 | global_region.GetCbufOffset()}; | 84 | global_region.GetCbufOffset()}; |
| 79 | const auto actual_addr{memory_manager.Read<u64>(addr)}; | 85 | const auto actual_addr{memory_manager.Read<u64>(addr)}; |
| @@ -85,7 +91,7 @@ GlobalRegion GlobalRegionCacheOpenGL::GetGlobalRegion( | |||
| 85 | 91 | ||
| 86 | if (!region) { | 92 | if (!region) { |
| 87 | // No global region found - create a new one | 93 | // No global region found - create a new one |
| 88 | region = GetUncachedGlobalRegion(actual_addr, size, host_ptr); | 94 | region = GetUncachedGlobalRegion(actual_addr, host_ptr, size); |
| 89 | Register(region); | 95 | Register(region); |
| 90 | } | 96 | } |
| 91 | 97 | ||
diff --git a/src/video_core/renderer_opengl/gl_global_cache.h b/src/video_core/renderer_opengl/gl_global_cache.h index 5a21ab66f..196e6e278 100644 --- a/src/video_core/renderer_opengl/gl_global_cache.h +++ b/src/video_core/renderer_opengl/gl_global_cache.h | |||
| @@ -19,7 +19,7 @@ namespace OpenGL { | |||
| 19 | 19 | ||
| 20 | namespace GLShader { | 20 | namespace GLShader { |
| 21 | class GlobalMemoryEntry; | 21 | class GlobalMemoryEntry; |
| 22 | } // namespace GLShader | 22 | } |
| 23 | 23 | ||
| 24 | class RasterizerOpenGL; | 24 | class RasterizerOpenGL; |
| 25 | class CachedGlobalRegion; | 25 | class CachedGlobalRegion; |
| @@ -27,7 +27,8 @@ using GlobalRegion = std::shared_ptr<CachedGlobalRegion>; | |||
| 27 | 27 | ||
| 28 | class CachedGlobalRegion final : public RasterizerCacheObject { | 28 | class CachedGlobalRegion final : public RasterizerCacheObject { |
| 29 | public: | 29 | public: |
| 30 | explicit CachedGlobalRegion(VAddr cpu_addr, u32 size, u8* host_ptr); | 30 | explicit CachedGlobalRegion(VAddr cpu_addr, u8* host_ptr, u32 size, u32 max_size); |
| 31 | ~CachedGlobalRegion(); | ||
| 31 | 32 | ||
| 32 | VAddr GetCpuAddr() const override { | 33 | VAddr GetCpuAddr() const override { |
| 33 | return cpu_addr; | 34 | return cpu_addr; |
| @@ -45,14 +46,14 @@ public: | |||
| 45 | /// Reloads the global region from guest memory | 46 | /// Reloads the global region from guest memory |
| 46 | void Reload(u32 size_); | 47 | void Reload(u32 size_); |
| 47 | 48 | ||
| 48 | // TODO(Rodrigo): When global memory is written (STG), implement flushing | 49 | void Flush() override; |
| 49 | void Flush() override { | ||
| 50 | UNIMPLEMENTED(); | ||
| 51 | } | ||
| 52 | 50 | ||
| 53 | private: | 51 | private: |
| 54 | VAddr cpu_addr{}; | 52 | VAddr cpu_addr{}; |
| 53 | u8* host_ptr{}; | ||
| 55 | u32 size{}; | 54 | u32 size{}; |
| 55 | u32 max_size{}; | ||
| 56 | |||
| 56 | OGLBuffer buffer; | 57 | OGLBuffer buffer; |
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| @@ -66,10 +67,11 @@ public: | |||
| 66 | 67 | ||
| 67 | private: | 68 | private: |
| 68 | GlobalRegion TryGetReservedGlobalRegion(CacheAddr addr, u32 size) const; | 69 | GlobalRegion TryGetReservedGlobalRegion(CacheAddr addr, u32 size) const; |
| 69 | GlobalRegion GetUncachedGlobalRegion(GPUVAddr addr, u32 size, u8* host_ptr); | 70 | GlobalRegion GetUncachedGlobalRegion(GPUVAddr addr, u8* host_ptr, u32 size); |
| 70 | void ReserveGlobalRegion(GlobalRegion region); | 71 | void ReserveGlobalRegion(GlobalRegion region); |
| 71 | 72 | ||
| 72 | std::unordered_map<CacheAddr, GlobalRegion> reserve; | 73 | std::unordered_map<CacheAddr, GlobalRegion> reserve; |
| 74 | u32 max_ssbo_size{}; | ||
| 73 | }; | 75 | }; |
| 74 | 76 | ||
| 75 | } // namespace OpenGL | 77 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 416955a7b..db73e746c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -99,22 +99,14 @@ struct FramebufferCacheKey { | |||
| 99 | }; | 99 | }; |
| 100 | 100 | ||
| 101 | RasterizerOpenGL::RasterizerOpenGL(Core::System& system, ScreenInfo& info) | 101 | RasterizerOpenGL::RasterizerOpenGL(Core::System& system, ScreenInfo& info) |
| 102 | : res_cache{*this}, shader_cache{*this, system}, global_cache{*this}, system{system}, | 102 | : res_cache{*this}, shader_cache{*this, system, device}, global_cache{*this}, system{system}, |
| 103 | screen_info{info}, buffer_cache(*this, STREAM_BUFFER_SIZE) { | 103 | screen_info{info}, buffer_cache(*this, STREAM_BUFFER_SIZE) { |
| 104 | // Create sampler objects | ||
| 105 | for (std::size_t i = 0; i < texture_samplers.size(); ++i) { | ||
| 106 | texture_samplers[i].Create(); | ||
| 107 | state.texture_units[i].sampler = texture_samplers[i].sampler.handle; | ||
| 108 | } | ||
| 109 | |||
| 110 | OpenGLState::ApplyDefaultState(); | 104 | OpenGLState::ApplyDefaultState(); |
| 111 | 105 | ||
| 112 | shader_program_manager = std::make_unique<GLShader::ProgramManager>(); | 106 | shader_program_manager = std::make_unique<GLShader::ProgramManager>(); |
| 113 | state.draw.shader_program = 0; | 107 | state.draw.shader_program = 0; |
| 114 | state.Apply(); | 108 | state.Apply(); |
| 115 | 109 | ||
| 116 | glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); | ||
| 117 | |||
| 118 | LOG_DEBUG(Render_OpenGL, "Sync fixed function OpenGL state here"); | 110 | LOG_DEBUG(Render_OpenGL, "Sync fixed function OpenGL state here"); |
| 119 | CheckExtensions(); | 111 | CheckExtensions(); |
| 120 | } | 112 | } |
| @@ -323,8 +315,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { | |||
| 323 | 315 | ||
| 324 | GLShader::MaxwellUniformData ubo{}; | 316 | GLShader::MaxwellUniformData ubo{}; |
| 325 | ubo.SetFromRegs(gpu, stage); | 317 | ubo.SetFromRegs(gpu, stage); |
| 326 | const GLintptr offset = buffer_cache.UploadHostMemory( | 318 | const GLintptr offset = |
| 327 | &ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment)); | 319 | buffer_cache.UploadHostMemory(&ubo, sizeof(ubo), device.GetUniformBufferAlignment()); |
| 328 | 320 | ||
| 329 | // Bind the emulation info buffer | 321 | // Bind the emulation info buffer |
| 330 | bind_ubo_pushbuffer.Push(buffer_cache.GetHandle(), offset, | 322 | bind_ubo_pushbuffer.Push(buffer_cache.GetHandle(), offset, |
| @@ -584,9 +576,6 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( | |||
| 584 | } | 576 | } |
| 585 | 577 | ||
| 586 | void RasterizerOpenGL::Clear() { | 578 | void RasterizerOpenGL::Clear() { |
| 587 | const auto prev_state{state}; | ||
| 588 | SCOPE_EXIT({ prev_state.Apply(); }); | ||
| 589 | |||
| 590 | const auto& regs = system.GPU().Maxwell3D().regs; | 579 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 591 | bool use_color{}; | 580 | bool use_color{}; |
| 592 | bool use_depth{}; | 581 | bool use_depth{}; |
| @@ -658,7 +647,10 @@ void RasterizerOpenGL::Clear() { | |||
| 658 | clear_state.EmulateViewportWithScissor(); | 647 | clear_state.EmulateViewportWithScissor(); |
| 659 | } | 648 | } |
| 660 | 649 | ||
| 661 | clear_state.Apply(); | 650 | clear_state.ApplyColorMask(); |
| 651 | clear_state.ApplyDepth(); | ||
| 652 | clear_state.ApplyStencilTest(); | ||
| 653 | clear_state.ApplyViewport(); | ||
| 662 | 654 | ||
| 663 | if (use_color) { | 655 | if (use_color) { |
| 664 | glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color); | 656 | glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color); |
| @@ -708,23 +700,24 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 708 | // Add space for index buffer (keeping in mind non-core primitives) | 700 | // Add space for index buffer (keeping in mind non-core primitives) |
| 709 | switch (regs.draw.topology) { | 701 | switch (regs.draw.topology) { |
| 710 | case Maxwell::PrimitiveTopology::Quads: | 702 | case Maxwell::PrimitiveTopology::Quads: |
| 711 | buffer_size = Common::AlignUp<std::size_t>(buffer_size, 4) + | 703 | buffer_size = Common::AlignUp(buffer_size, 4) + |
| 712 | primitive_assembler.CalculateQuadSize(regs.vertex_buffer.count); | 704 | primitive_assembler.CalculateQuadSize(regs.vertex_buffer.count); |
| 713 | break; | 705 | break; |
| 714 | default: | 706 | default: |
| 715 | if (is_indexed) { | 707 | if (is_indexed) { |
| 716 | buffer_size = Common::AlignUp<std::size_t>(buffer_size, 4) + CalculateIndexBufferSize(); | 708 | buffer_size = Common::AlignUp(buffer_size, 4) + CalculateIndexBufferSize(); |
| 717 | } | 709 | } |
| 718 | break; | 710 | break; |
| 719 | } | 711 | } |
| 720 | 712 | ||
| 721 | // Uniform space for the 5 shader stages | 713 | // Uniform space for the 5 shader stages |
| 722 | buffer_size = | 714 | buffer_size = Common::AlignUp<std::size_t>(buffer_size, 4) + |
| 723 | Common::AlignUp<std::size_t>(buffer_size, 4) + | 715 | (sizeof(GLShader::MaxwellUniformData) + device.GetUniformBufferAlignment()) * |
| 724 | (sizeof(GLShader::MaxwellUniformData) + uniform_buffer_alignment) * Maxwell::MaxShaderStage; | 716 | Maxwell::MaxShaderStage; |
| 725 | 717 | ||
| 726 | // Add space for at least 18 constant buffers | 718 | // Add space for at least 18 constant buffers |
| 727 | buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment); | 719 | buffer_size += |
| 720 | Maxwell::MaxConstBuffers * (MaxConstbufferSize + device.GetUniformBufferAlignment()); | ||
| 728 | 721 | ||
| 729 | const bool invalidate = buffer_cache.Map(buffer_size); | 722 | const bool invalidate = buffer_cache.Map(buffer_size); |
| 730 | if (invalidate) { | 723 | if (invalidate) { |
| @@ -758,6 +751,7 @@ void RasterizerOpenGL::FlushRegion(CacheAddr addr, u64 size) { | |||
| 758 | return; | 751 | return; |
| 759 | } | 752 | } |
| 760 | res_cache.FlushRegion(addr, size); | 753 | res_cache.FlushRegion(addr, size); |
| 754 | global_cache.FlushRegion(addr, size); | ||
| 761 | } | 755 | } |
| 762 | 756 | ||
| 763 | void RasterizerOpenGL::InvalidateRegion(CacheAddr addr, u64 size) { | 757 | void RasterizerOpenGL::InvalidateRegion(CacheAddr addr, u64 size) { |
| @@ -814,92 +808,6 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, | |||
| 814 | return true; | 808 | return true; |
| 815 | } | 809 | } |
| 816 | 810 | ||
| 817 | void RasterizerOpenGL::SamplerInfo::Create() { | ||
| 818 | sampler.Create(); | ||
| 819 | mag_filter = Tegra::Texture::TextureFilter::Linear; | ||
| 820 | min_filter = Tegra::Texture::TextureFilter::Linear; | ||
| 821 | wrap_u = Tegra::Texture::WrapMode::Wrap; | ||
| 822 | wrap_v = Tegra::Texture::WrapMode::Wrap; | ||
| 823 | wrap_p = Tegra::Texture::WrapMode::Wrap; | ||
| 824 | use_depth_compare = false; | ||
| 825 | depth_compare_func = Tegra::Texture::DepthCompareFunc::Never; | ||
| 826 | |||
| 827 | // OpenGL's default is GL_LINEAR_MIPMAP_LINEAR | ||
| 828 | glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
| 829 | glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER); | ||
| 830 | |||
| 831 | // Other attributes have correct defaults | ||
| 832 | } | ||
| 833 | |||
| 834 | void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) { | ||
| 835 | const GLuint sampler_id = sampler.handle; | ||
| 836 | if (mag_filter != config.mag_filter) { | ||
| 837 | mag_filter = config.mag_filter; | ||
| 838 | glSamplerParameteri( | ||
| 839 | sampler_id, GL_TEXTURE_MAG_FILTER, | ||
| 840 | MaxwellToGL::TextureFilterMode(mag_filter, Tegra::Texture::TextureMipmapFilter::None)); | ||
| 841 | } | ||
| 842 | if (min_filter != config.min_filter || mipmap_filter != config.mipmap_filter) { | ||
| 843 | min_filter = config.min_filter; | ||
| 844 | mipmap_filter = config.mipmap_filter; | ||
| 845 | glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, | ||
| 846 | MaxwellToGL::TextureFilterMode(min_filter, mipmap_filter)); | ||
| 847 | } | ||
| 848 | |||
| 849 | if (wrap_u != config.wrap_u) { | ||
| 850 | wrap_u = config.wrap_u; | ||
| 851 | glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, MaxwellToGL::WrapMode(wrap_u)); | ||
| 852 | } | ||
| 853 | if (wrap_v != config.wrap_v) { | ||
| 854 | wrap_v = config.wrap_v; | ||
| 855 | glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v)); | ||
| 856 | } | ||
| 857 | if (wrap_p != config.wrap_p) { | ||
| 858 | wrap_p = config.wrap_p; | ||
| 859 | glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(wrap_p)); | ||
| 860 | } | ||
| 861 | |||
| 862 | if (const bool enabled = config.depth_compare_enabled == 1; use_depth_compare != enabled) { | ||
| 863 | use_depth_compare = enabled; | ||
| 864 | glSamplerParameteri(sampler_id, GL_TEXTURE_COMPARE_MODE, | ||
| 865 | use_depth_compare ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE); | ||
| 866 | } | ||
| 867 | |||
| 868 | if (depth_compare_func != config.depth_compare_func) { | ||
| 869 | depth_compare_func = config.depth_compare_func; | ||
| 870 | glSamplerParameteri(sampler_id, GL_TEXTURE_COMPARE_FUNC, | ||
| 871 | MaxwellToGL::DepthCompareFunc(depth_compare_func)); | ||
| 872 | } | ||
| 873 | |||
| 874 | if (const auto new_border_color = config.GetBorderColor(); border_color != new_border_color) { | ||
| 875 | border_color = new_border_color; | ||
| 876 | glSamplerParameterfv(sampler_id, GL_TEXTURE_BORDER_COLOR, border_color.data()); | ||
| 877 | } | ||
| 878 | |||
| 879 | if (const float anisotropic = config.GetMaxAnisotropy(); max_anisotropic != anisotropic) { | ||
| 880 | max_anisotropic = anisotropic; | ||
| 881 | if (GLAD_GL_ARB_texture_filter_anisotropic) { | ||
| 882 | glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY, max_anisotropic); | ||
| 883 | } else if (GLAD_GL_EXT_texture_filter_anisotropic) { | ||
| 884 | glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropic); | ||
| 885 | } | ||
| 886 | } | ||
| 887 | |||
| 888 | if (const float min = config.GetMinLod(); min_lod != min) { | ||
| 889 | min_lod = min; | ||
| 890 | glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, min_lod); | ||
| 891 | } | ||
| 892 | if (const float max = config.GetMaxLod(); max_lod != max) { | ||
| 893 | max_lod = max; | ||
| 894 | glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, max_lod); | ||
| 895 | } | ||
| 896 | |||
| 897 | if (const float bias = config.GetLodBias(); lod_bias != bias) { | ||
| 898 | lod_bias = bias; | ||
| 899 | glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, lod_bias); | ||
| 900 | } | ||
| 901 | } | ||
| 902 | |||
| 903 | void RasterizerOpenGL::SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, | 811 | void RasterizerOpenGL::SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, |
| 904 | const Shader& shader, GLuint program_handle, | 812 | const Shader& shader, GLuint program_handle, |
| 905 | BaseBindings base_bindings) { | 813 | BaseBindings base_bindings) { |
| @@ -941,8 +849,8 @@ void RasterizerOpenGL::SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::Shader | |||
| 941 | size = Common::AlignUp(size, sizeof(GLvec4)); | 849 | size = Common::AlignUp(size, sizeof(GLvec4)); |
| 942 | ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big"); | 850 | ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big"); |
| 943 | 851 | ||
| 944 | const GLintptr const_buffer_offset = buffer_cache.UploadMemory( | 852 | const GLintptr const_buffer_offset = |
| 945 | buffer.address, size, static_cast<std::size_t>(uniform_buffer_alignment)); | 853 | buffer_cache.UploadMemory(buffer.address, size, device.GetUniformBufferAlignment()); |
| 946 | 854 | ||
| 947 | bind_ubo_pushbuffer.Push(buffer_cache.GetHandle(), const_buffer_offset, size); | 855 | bind_ubo_pushbuffer.Push(buffer_cache.GetHandle(), const_buffer_offset, size); |
| 948 | } | 856 | } |
| @@ -955,6 +863,9 @@ void RasterizerOpenGL::SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::Shade | |||
| 955 | for (std::size_t bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { | 863 | for (std::size_t bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { |
| 956 | const auto& entry{entries[bindpoint]}; | 864 | const auto& entry{entries[bindpoint]}; |
| 957 | const auto& region{global_cache.GetGlobalRegion(entry, stage)}; | 865 | const auto& region{global_cache.GetGlobalRegion(entry, stage)}; |
| 866 | if (entry.IsWritten()) { | ||
| 867 | region->MarkAsModified(true, global_cache); | ||
| 868 | } | ||
| 958 | bind_ssbo_pushbuffer.Push(region->GetBufferHandle(), 0, | 869 | bind_ssbo_pushbuffer.Push(region->GetBufferHandle(), 0, |
| 959 | static_cast<GLsizeiptr>(region->GetSizeInBytes())); | 870 | static_cast<GLsizeiptr>(region->GetSizeInBytes())); |
| 960 | } | 871 | } |
| @@ -972,10 +883,18 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s | |||
| 972 | 883 | ||
| 973 | for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { | 884 | for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { |
| 974 | const auto& entry = entries[bindpoint]; | 885 | const auto& entry = entries[bindpoint]; |
| 975 | const auto texture = maxwell3d.GetStageTexture(stage, entry.GetOffset()); | 886 | Tegra::Texture::FullTextureInfo texture; |
| 887 | if (entry.IsBindless()) { | ||
| 888 | const auto cbuf = entry.GetBindlessCBuf(); | ||
| 889 | Tegra::Texture::TextureHandle tex_handle; | ||
| 890 | tex_handle.raw = maxwell3d.AccessConstBuffer32(stage, cbuf.first, cbuf.second); | ||
| 891 | texture = maxwell3d.GetTextureInfo(tex_handle, entry.GetOffset()); | ||
| 892 | } else { | ||
| 893 | texture = maxwell3d.GetStageTexture(stage, entry.GetOffset()); | ||
| 894 | } | ||
| 976 | const u32 current_bindpoint = base_bindings.sampler + bindpoint; | 895 | const u32 current_bindpoint = base_bindings.sampler + bindpoint; |
| 977 | 896 | ||
| 978 | texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); | 897 | state.texture_units[current_bindpoint].sampler = sampler_cache.GetSampler(texture.tsc); |
| 979 | 898 | ||
| 980 | if (Surface surface = res_cache.GetTextureSurface(texture, entry); surface) { | 899 | if (Surface surface = res_cache.GetTextureSurface(texture, entry); surface) { |
| 981 | state.texture_units[current_bindpoint].texture = | 900 | state.texture_units[current_bindpoint].texture = |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index e4c64ae71..71b9c5ead 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -21,10 +21,12 @@ | |||
| 21 | #include "video_core/rasterizer_cache.h" | 21 | #include "video_core/rasterizer_cache.h" |
| 22 | #include "video_core/rasterizer_interface.h" | 22 | #include "video_core/rasterizer_interface.h" |
| 23 | #include "video_core/renderer_opengl/gl_buffer_cache.h" | 23 | #include "video_core/renderer_opengl/gl_buffer_cache.h" |
| 24 | #include "video_core/renderer_opengl/gl_device.h" | ||
| 24 | #include "video_core/renderer_opengl/gl_global_cache.h" | 25 | #include "video_core/renderer_opengl/gl_global_cache.h" |
| 25 | #include "video_core/renderer_opengl/gl_primitive_assembler.h" | 26 | #include "video_core/renderer_opengl/gl_primitive_assembler.h" |
| 26 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | 27 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" |
| 27 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 28 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 29 | #include "video_core/renderer_opengl/gl_sampler_cache.h" | ||
| 28 | #include "video_core/renderer_opengl/gl_shader_cache.h" | 30 | #include "video_core/renderer_opengl/gl_shader_cache.h" |
| 29 | #include "video_core/renderer_opengl/gl_shader_manager.h" | 31 | #include "video_core/renderer_opengl/gl_shader_manager.h" |
| 30 | #include "video_core/renderer_opengl/gl_state.h" | 32 | #include "video_core/renderer_opengl/gl_state.h" |
| @@ -71,39 +73,7 @@ public: | |||
| 71 | static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0, | 73 | static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0, |
| 72 | "The maximum size of a constbuffer must be a multiple of the size of GLvec4"); | 74 | "The maximum size of a constbuffer must be a multiple of the size of GLvec4"); |
| 73 | 75 | ||
| 74 | static constexpr std::size_t MaxGlobalMemorySize = 0x10000; | ||
| 75 | static_assert(MaxGlobalMemorySize % sizeof(float) == 0, | ||
| 76 | "The maximum size of a global memory must be a multiple of the size of float"); | ||
| 77 | |||
| 78 | private: | 76 | private: |
| 79 | class SamplerInfo { | ||
| 80 | public: | ||
| 81 | OGLSampler sampler; | ||
| 82 | |||
| 83 | /// Creates the sampler object, initializing its state so that it's in sync with the | ||
| 84 | /// SamplerInfo struct. | ||
| 85 | void Create(); | ||
| 86 | /// Syncs the sampler object with the config, updating any necessary state. | ||
| 87 | void SyncWithConfig(const Tegra::Texture::TSCEntry& info); | ||
| 88 | |||
| 89 | private: | ||
| 90 | Tegra::Texture::TextureFilter mag_filter = Tegra::Texture::TextureFilter::Nearest; | ||
| 91 | Tegra::Texture::TextureFilter min_filter = Tegra::Texture::TextureFilter::Nearest; | ||
| 92 | Tegra::Texture::TextureMipmapFilter mipmap_filter = | ||
| 93 | Tegra::Texture::TextureMipmapFilter::None; | ||
| 94 | Tegra::Texture::WrapMode wrap_u = Tegra::Texture::WrapMode::ClampToEdge; | ||
| 95 | Tegra::Texture::WrapMode wrap_v = Tegra::Texture::WrapMode::ClampToEdge; | ||
| 96 | Tegra::Texture::WrapMode wrap_p = Tegra::Texture::WrapMode::ClampToEdge; | ||
| 97 | bool use_depth_compare = false; | ||
| 98 | Tegra::Texture::DepthCompareFunc depth_compare_func = | ||
| 99 | Tegra::Texture::DepthCompareFunc::Always; | ||
| 100 | GLvec4 border_color = {}; | ||
| 101 | float min_lod = 0.0f; | ||
| 102 | float max_lod = 16.0f; | ||
| 103 | float lod_bias = 0.0f; | ||
| 104 | float max_anisotropic = 1.0f; | ||
| 105 | }; | ||
| 106 | |||
| 107 | struct FramebufferConfigState { | 77 | struct FramebufferConfigState { |
| 108 | bool using_color_fb{}; | 78 | bool using_color_fb{}; |
| 109 | bool using_depth_fb{}; | 79 | bool using_depth_fb{}; |
| @@ -203,14 +173,15 @@ private: | |||
| 203 | /// but are needed for correct emulation | 173 | /// but are needed for correct emulation |
| 204 | void CheckExtensions(); | 174 | void CheckExtensions(); |
| 205 | 175 | ||
| 176 | const Device device; | ||
| 206 | OpenGLState state; | 177 | OpenGLState state; |
| 207 | 178 | ||
| 208 | RasterizerCacheOpenGL res_cache; | 179 | RasterizerCacheOpenGL res_cache; |
| 209 | ShaderCacheOpenGL shader_cache; | 180 | ShaderCacheOpenGL shader_cache; |
| 210 | GlobalRegionCacheOpenGL global_cache; | 181 | GlobalRegionCacheOpenGL global_cache; |
| 182 | SamplerCacheOpenGL sampler_cache; | ||
| 211 | 183 | ||
| 212 | Core::System& system; | 184 | Core::System& system; |
| 213 | |||
| 214 | ScreenInfo& screen_info; | 185 | ScreenInfo& screen_info; |
| 215 | 186 | ||
| 216 | std::unique_ptr<GLShader::ProgramManager> shader_program_manager; | 187 | std::unique_ptr<GLShader::ProgramManager> shader_program_manager; |
| @@ -223,12 +194,9 @@ private: | |||
| 223 | FramebufferConfigState current_framebuffer_config_state; | 194 | FramebufferConfigState current_framebuffer_config_state; |
| 224 | std::pair<bool, bool> current_depth_stencil_usage{}; | 195 | std::pair<bool, bool> current_depth_stencil_usage{}; |
| 225 | 196 | ||
| 226 | std::array<SamplerInfo, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_samplers; | ||
| 227 | |||
| 228 | static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; | 197 | static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; |
| 229 | OGLBufferCache buffer_cache; | 198 | OGLBufferCache buffer_cache; |
| 230 | PrimitiveAssembler primitive_assembler{buffer_cache}; | 199 | PrimitiveAssembler primitive_assembler{buffer_cache}; |
| 231 | GLint uniform_buffer_alignment; | ||
| 232 | 200 | ||
| 233 | BindBuffersRangePushBuffer bind_ubo_pushbuffer{GL_UNIFORM_BUFFER}; | 201 | BindBuffersRangePushBuffer bind_ubo_pushbuffer{GL_UNIFORM_BUFFER}; |
| 234 | BindBuffersRangePushBuffer bind_ssbo_pushbuffer{GL_SHADER_STORAGE_BUFFER}; | 202 | BindBuffersRangePushBuffer bind_ssbo_pushbuffer{GL_SHADER_STORAGE_BUFFER}; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index f2ffc4710..5a25f5b37 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -281,10 +281,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only, | |||
| 281 | params.component_type = ComponentTypeFromRenderTarget(config.format); | 281 | params.component_type = ComponentTypeFromRenderTarget(config.format); |
| 282 | params.type = GetFormatType(params.pixel_format); | 282 | params.type = GetFormatType(params.pixel_format); |
| 283 | params.width = config.width; | 283 | params.width = config.width; |
| 284 | if (!params.is_tiled) { | 284 | params.pitch = config.pitch; |
| 285 | const u32 bpp = params.GetFormatBpp() / 8; | ||
| 286 | params.pitch = config.width * bpp; | ||
| 287 | } | ||
| 288 | params.height = config.height; | 285 | params.height = config.height; |
| 289 | params.unaligned_height = config.height; | 286 | params.unaligned_height = config.height; |
| 290 | params.target = SurfaceTarget::Texture2D; | 287 | params.target = SurfaceTarget::Texture2D; |
| @@ -643,13 +640,16 @@ void CachedSurface::LoadGLBuffer() { | |||
| 643 | SwizzleFunc(MortonSwizzleMode::MortonToLinear, params, gl_buffer[i], i); | 640 | SwizzleFunc(MortonSwizzleMode::MortonToLinear, params, gl_buffer[i], i); |
| 644 | } else { | 641 | } else { |
| 645 | const u32 bpp = params.GetFormatBpp() / 8; | 642 | const u32 bpp = params.GetFormatBpp() / 8; |
| 646 | const u32 copy_size = params.width * bpp; | 643 | const u32 copy_size = (params.width * bpp + GetDefaultBlockWidth(params.pixel_format) - 1) / |
| 644 | GetDefaultBlockWidth(params.pixel_format); | ||
| 647 | if (params.pitch == copy_size) { | 645 | if (params.pitch == copy_size) { |
| 648 | std::memcpy(gl_buffer[0].data(), params.host_ptr, params.size_in_bytes_gl); | 646 | std::memcpy(gl_buffer[0].data(), params.host_ptr, params.size_in_bytes_gl); |
| 649 | } else { | 647 | } else { |
| 648 | const u32 height = (params.height + GetDefaultBlockHeight(params.pixel_format) - 1) / | ||
| 649 | GetDefaultBlockHeight(params.pixel_format); | ||
| 650 | const u8* start{params.host_ptr}; | 650 | const u8* start{params.host_ptr}; |
| 651 | u8* write_to = gl_buffer[0].data(); | 651 | u8* write_to = gl_buffer[0].data(); |
| 652 | for (u32 h = params.height; h > 0; h--) { | 652 | for (u32 h = height; h > 0; h--) { |
| 653 | std::memcpy(write_to, start, copy_size); | 653 | std::memcpy(write_to, start, copy_size); |
| 654 | start += params.pitch; | 654 | start += params.pitch; |
| 655 | write_to += copy_size; | 655 | write_to += copy_size; |
diff --git a/src/video_core/renderer_opengl/gl_sampler_cache.cpp b/src/video_core/renderer_opengl/gl_sampler_cache.cpp new file mode 100644 index 000000000..3ded5ecea --- /dev/null +++ b/src/video_core/renderer_opengl/gl_sampler_cache.cpp | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "video_core/renderer_opengl/gl_resource_manager.h" | ||
| 7 | #include "video_core/renderer_opengl/gl_sampler_cache.h" | ||
| 8 | #include "video_core/renderer_opengl/maxwell_to_gl.h" | ||
| 9 | |||
| 10 | namespace OpenGL { | ||
| 11 | |||
| 12 | SamplerCacheOpenGL::SamplerCacheOpenGL() = default; | ||
| 13 | |||
| 14 | SamplerCacheOpenGL::~SamplerCacheOpenGL() = default; | ||
| 15 | |||
| 16 | OGLSampler SamplerCacheOpenGL::CreateSampler(const Tegra::Texture::TSCEntry& tsc) const { | ||
| 17 | OGLSampler sampler; | ||
| 18 | sampler.Create(); | ||
| 19 | |||
| 20 | const GLuint sampler_id{sampler.handle}; | ||
| 21 | glSamplerParameteri( | ||
| 22 | sampler_id, GL_TEXTURE_MAG_FILTER, | ||
| 23 | MaxwellToGL::TextureFilterMode(tsc.mag_filter, Tegra::Texture::TextureMipmapFilter::None)); | ||
| 24 | glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, | ||
| 25 | MaxwellToGL::TextureFilterMode(tsc.min_filter, tsc.mipmap_filter)); | ||
| 26 | glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, MaxwellToGL::WrapMode(tsc.wrap_u)); | ||
| 27 | glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(tsc.wrap_v)); | ||
| 28 | glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(tsc.wrap_p)); | ||
| 29 | glSamplerParameteri(sampler_id, GL_TEXTURE_COMPARE_MODE, | ||
| 30 | tsc.depth_compare_enabled == 1 ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE); | ||
| 31 | glSamplerParameteri(sampler_id, GL_TEXTURE_COMPARE_FUNC, | ||
| 32 | MaxwellToGL::DepthCompareFunc(tsc.depth_compare_func)); | ||
| 33 | glSamplerParameterfv(sampler_id, GL_TEXTURE_BORDER_COLOR, tsc.GetBorderColor().data()); | ||
| 34 | glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, tsc.GetMinLod()); | ||
| 35 | glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, tsc.GetMaxLod()); | ||
| 36 | glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, tsc.GetLodBias()); | ||
| 37 | if (GLAD_GL_ARB_texture_filter_anisotropic) { | ||
| 38 | glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY, tsc.GetMaxAnisotropy()); | ||
| 39 | } else if (GLAD_GL_EXT_texture_filter_anisotropic) { | ||
| 40 | glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, tsc.GetMaxAnisotropy()); | ||
| 41 | } else if (tsc.GetMaxAnisotropy() != 1) { | ||
| 42 | LOG_WARNING(Render_OpenGL, "Anisotropy not supported by host GPU driver"); | ||
| 43 | } | ||
| 44 | |||
| 45 | return sampler; | ||
| 46 | } | ||
| 47 | |||
| 48 | GLuint SamplerCacheOpenGL::ToSamplerType(const OGLSampler& sampler) const { | ||
| 49 | return sampler.handle; | ||
| 50 | } | ||
| 51 | |||
| 52 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/gl_sampler_cache.h b/src/video_core/renderer_opengl/gl_sampler_cache.h new file mode 100644 index 000000000..defbc2d81 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_sampler_cache.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <glad/glad.h> | ||
| 8 | |||
| 9 | #include "video_core/renderer_opengl/gl_resource_manager.h" | ||
| 10 | #include "video_core/sampler_cache.h" | ||
| 11 | |||
| 12 | namespace OpenGL { | ||
| 13 | |||
| 14 | class SamplerCacheOpenGL final : public VideoCommon::SamplerCache<GLuint, OGLSampler> { | ||
| 15 | public: | ||
| 16 | explicit SamplerCacheOpenGL(); | ||
| 17 | ~SamplerCacheOpenGL(); | ||
| 18 | |||
| 19 | protected: | ||
| 20 | OGLSampler CreateSampler(const Tegra::Texture::TSCEntry& tsc) const; | ||
| 21 | |||
| 22 | GLuint ToSamplerType(const OGLSampler& sampler) const; | ||
| 23 | }; | ||
| 24 | |||
| 25 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 99f67494c..2a81b1169 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -38,13 +38,15 @@ GPUVAddr GetShaderAddress(Maxwell::ShaderProgram program) { | |||
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | /// Gets the shader program code from memory for the specified address | 40 | /// Gets the shader program code from memory for the specified address |
| 41 | ProgramCode GetShaderCode(const u8* host_ptr) { | 41 | ProgramCode GetShaderCode(Tegra::MemoryManager& memory_manager, const GPUVAddr gpu_addr, |
| 42 | const u8* host_ptr) { | ||
| 42 | ProgramCode program_code(VideoCommon::Shader::MAX_PROGRAM_LENGTH); | 43 | ProgramCode program_code(VideoCommon::Shader::MAX_PROGRAM_LENGTH); |
| 43 | ASSERT_OR_EXECUTE(host_ptr != nullptr, { | 44 | ASSERT_OR_EXECUTE(host_ptr != nullptr, { |
| 44 | std::fill(program_code.begin(), program_code.end(), 0); | 45 | std::fill(program_code.begin(), program_code.end(), 0); |
| 45 | return program_code; | 46 | return program_code; |
| 46 | }); | 47 | }); |
| 47 | std::memcpy(program_code.data(), host_ptr, program_code.size() * sizeof(u64)); | 48 | memory_manager.ReadBlockUnsafe(gpu_addr, program_code.data(), |
| 49 | program_code.size() * sizeof(u64)); | ||
| 48 | return program_code; | 50 | return program_code; |
| 49 | } | 51 | } |
| 50 | 52 | ||
| @@ -134,8 +136,8 @@ u64 GetUniqueIdentifier(Maxwell::ShaderProgram program_type, const ProgramCode& | |||
| 134 | } | 136 | } |
| 135 | 137 | ||
| 136 | /// Creates an unspecialized program from code streams | 138 | /// Creates an unspecialized program from code streams |
| 137 | GLShader::ProgramResult CreateProgram(Maxwell::ShaderProgram program_type, ProgramCode program_code, | 139 | GLShader::ProgramResult CreateProgram(const Device& device, Maxwell::ShaderProgram program_type, |
| 138 | ProgramCode program_code_b) { | 140 | ProgramCode program_code, ProgramCode program_code_b) { |
| 139 | GLShader::ShaderSetup setup(program_code); | 141 | GLShader::ShaderSetup setup(program_code); |
| 140 | if (program_type == Maxwell::ShaderProgram::VertexA) { | 142 | if (program_type == Maxwell::ShaderProgram::VertexA) { |
| 141 | // VertexB is always enabled, so when VertexA is enabled, we have two vertex shaders. | 143 | // VertexB is always enabled, so when VertexA is enabled, we have two vertex shaders. |
| @@ -149,11 +151,11 @@ GLShader::ProgramResult CreateProgram(Maxwell::ShaderProgram program_type, Progr | |||
| 149 | switch (program_type) { | 151 | switch (program_type) { |
| 150 | case Maxwell::ShaderProgram::VertexA: | 152 | case Maxwell::ShaderProgram::VertexA: |
| 151 | case Maxwell::ShaderProgram::VertexB: | 153 | case Maxwell::ShaderProgram::VertexB: |
| 152 | return GLShader::GenerateVertexShader(setup); | 154 | return GLShader::GenerateVertexShader(device, setup); |
| 153 | case Maxwell::ShaderProgram::Geometry: | 155 | case Maxwell::ShaderProgram::Geometry: |
| 154 | return GLShader::GenerateGeometryShader(setup); | 156 | return GLShader::GenerateGeometryShader(device, setup); |
| 155 | case Maxwell::ShaderProgram::Fragment: | 157 | case Maxwell::ShaderProgram::Fragment: |
| 156 | return GLShader::GenerateFragmentShader(setup); | 158 | return GLShader::GenerateFragmentShader(device, setup); |
| 157 | default: | 159 | default: |
| 158 | LOG_CRITICAL(HW_GPU, "Unimplemented program_type={}", static_cast<u32>(program_type)); | 160 | LOG_CRITICAL(HW_GPU, "Unimplemented program_type={}", static_cast<u32>(program_type)); |
| 159 | UNREACHABLE(); | 161 | UNREACHABLE(); |
| @@ -212,22 +214,20 @@ std::set<GLenum> GetSupportedFormats() { | |||
| 212 | return supported_formats; | 214 | return supported_formats; |
| 213 | } | 215 | } |
| 214 | 216 | ||
| 215 | } // namespace | 217 | } // Anonymous namespace |
| 216 | 218 | ||
| 217 | CachedShader::CachedShader(VAddr cpu_addr, u64 unique_identifier, | 219 | CachedShader::CachedShader(const Device& device, VAddr cpu_addr, u64 unique_identifier, |
| 218 | Maxwell::ShaderProgram program_type, ShaderDiskCacheOpenGL& disk_cache, | 220 | Maxwell::ShaderProgram program_type, ShaderDiskCacheOpenGL& disk_cache, |
| 219 | const PrecompiledPrograms& precompiled_programs, | 221 | const PrecompiledPrograms& precompiled_programs, |
| 220 | ProgramCode&& program_code, ProgramCode&& program_code_b, u8* host_ptr) | 222 | ProgramCode&& program_code, ProgramCode&& program_code_b, u8* host_ptr) |
| 221 | : RasterizerCacheObject{host_ptr}, host_ptr{host_ptr}, cpu_addr{cpu_addr}, | 223 | : RasterizerCacheObject{host_ptr}, host_ptr{host_ptr}, cpu_addr{cpu_addr}, |
| 222 | unique_identifier{unique_identifier}, program_type{program_type}, disk_cache{disk_cache}, | 224 | unique_identifier{unique_identifier}, program_type{program_type}, disk_cache{disk_cache}, |
| 223 | precompiled_programs{precompiled_programs} { | 225 | precompiled_programs{precompiled_programs} { |
| 224 | 226 | const std::size_t code_size{CalculateProgramSize(program_code)}; | |
| 225 | const std::size_t code_size = CalculateProgramSize(program_code); | 227 | const std::size_t code_size_b{program_code_b.empty() ? 0 |
| 226 | const std::size_t code_size_b = | 228 | : CalculateProgramSize(program_code_b)}; |
| 227 | program_code_b.empty() ? 0 : CalculateProgramSize(program_code_b); | 229 | GLShader::ProgramResult program_result{ |
| 228 | 230 | CreateProgram(device, program_type, program_code, program_code_b)}; | |
| 229 | GLShader::ProgramResult program_result = | ||
| 230 | CreateProgram(program_type, program_code, program_code_b); | ||
| 231 | if (program_result.first.empty()) { | 231 | if (program_result.first.empty()) { |
| 232 | // TODO(Rodrigo): Unimplemented shader stages hit here, avoid using these for now | 232 | // TODO(Rodrigo): Unimplemented shader stages hit here, avoid using these for now |
| 233 | return; | 233 | return; |
| @@ -251,7 +251,6 @@ CachedShader::CachedShader(VAddr cpu_addr, u64 unique_identifier, | |||
| 251 | : RasterizerCacheObject{host_ptr}, cpu_addr{cpu_addr}, unique_identifier{unique_identifier}, | 251 | : RasterizerCacheObject{host_ptr}, cpu_addr{cpu_addr}, unique_identifier{unique_identifier}, |
| 252 | program_type{program_type}, disk_cache{disk_cache}, precompiled_programs{ | 252 | program_type{program_type}, disk_cache{disk_cache}, precompiled_programs{ |
| 253 | precompiled_programs} { | 253 | precompiled_programs} { |
| 254 | |||
| 255 | code = std::move(result.first); | 254 | code = std::move(result.first); |
| 256 | entries = result.second; | 255 | entries = result.second; |
| 257 | shader_length = entries.shader_length; | 256 | shader_length = entries.shader_length; |
| @@ -344,8 +343,9 @@ ShaderDiskCacheUsage CachedShader::GetUsage(GLenum primitive_mode, | |||
| 344 | return {unique_identifier, base_bindings, primitive_mode}; | 343 | return {unique_identifier, base_bindings, primitive_mode}; |
| 345 | } | 344 | } |
| 346 | 345 | ||
| 347 | ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system) | 346 | ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system, |
| 348 | : RasterizerCache{rasterizer}, disk_cache{system} {} | 347 | const Device& device) |
| 348 | : RasterizerCache{rasterizer}, disk_cache{system}, device{device} {} | ||
| 349 | 349 | ||
| 350 | void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, | 350 | void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, |
| 351 | const VideoCore::DiskResourceLoadCallback& callback) { | 351 | const VideoCore::DiskResourceLoadCallback& callback) { |
| @@ -439,17 +439,18 @@ std::unordered_map<u64, UnspecializedShader> ShaderCacheOpenGL::GenerateUnspecia | |||
| 439 | const std::unordered_map<u64, ShaderDiskCacheDecompiled>& decompiled) { | 439 | const std::unordered_map<u64, ShaderDiskCacheDecompiled>& decompiled) { |
| 440 | std::unordered_map<u64, UnspecializedShader> unspecialized; | 440 | std::unordered_map<u64, UnspecializedShader> unspecialized; |
| 441 | 441 | ||
| 442 | if (callback) | 442 | if (callback) { |
| 443 | callback(VideoCore::LoadCallbackStage::Decompile, 0, raws.size()); | 443 | callback(VideoCore::LoadCallbackStage::Decompile, 0, raws.size()); |
| 444 | } | ||
| 444 | 445 | ||
| 445 | for (std::size_t i = 0; i < raws.size(); ++i) { | 446 | for (std::size_t i = 0; i < raws.size(); ++i) { |
| 446 | if (stop_loading) | 447 | if (stop_loading) { |
| 447 | return {}; | 448 | return {}; |
| 448 | 449 | } | |
| 449 | const auto& raw{raws[i]}; | 450 | const auto& raw{raws[i]}; |
| 450 | const u64 unique_identifier = raw.GetUniqueIdentifier(); | 451 | const u64 unique_identifier{raw.GetUniqueIdentifier()}; |
| 451 | const u64 calculated_hash = | 452 | const u64 calculated_hash{ |
| 452 | GetUniqueIdentifier(raw.GetProgramType(), raw.GetProgramCode(), raw.GetProgramCodeB()); | 453 | GetUniqueIdentifier(raw.GetProgramType(), raw.GetProgramCode(), raw.GetProgramCodeB())}; |
| 453 | if (unique_identifier != calculated_hash) { | 454 | if (unique_identifier != calculated_hash) { |
| 454 | LOG_ERROR( | 455 | LOG_ERROR( |
| 455 | Render_OpenGL, | 456 | Render_OpenGL, |
| @@ -466,8 +467,8 @@ std::unordered_map<u64, UnspecializedShader> ShaderCacheOpenGL::GenerateUnspecia | |||
| 466 | result = {stored_decompiled.code, stored_decompiled.entries}; | 467 | result = {stored_decompiled.code, stored_decompiled.entries}; |
| 467 | } else { | 468 | } else { |
| 468 | // Otherwise decompile the shader at boot and save the result to the decompiled file | 469 | // Otherwise decompile the shader at boot and save the result to the decompiled file |
| 469 | result = | 470 | result = CreateProgram(device, raw.GetProgramType(), raw.GetProgramCode(), |
| 470 | CreateProgram(raw.GetProgramType(), raw.GetProgramCode(), raw.GetProgramCodeB()); | 471 | raw.GetProgramCodeB()); |
| 471 | disk_cache.SaveDecompiled(unique_identifier, result.first, result.second); | 472 | disk_cache.SaveDecompiled(unique_identifier, result.first, result.second); |
| 472 | } | 473 | } |
| 473 | 474 | ||
| @@ -477,8 +478,9 @@ std::unordered_map<u64, UnspecializedShader> ShaderCacheOpenGL::GenerateUnspecia | |||
| 477 | {raw.GetUniqueIdentifier(), | 478 | {raw.GetUniqueIdentifier(), |
| 478 | {std::move(result.first), std::move(result.second), raw.GetProgramType()}}); | 479 | {std::move(result.first), std::move(result.second), raw.GetProgramType()}}); |
| 479 | 480 | ||
| 480 | if (callback) | 481 | if (callback) { |
| 481 | callback(VideoCore::LoadCallbackStage::Decompile, i, raws.size()); | 482 | callback(VideoCore::LoadCallbackStage::Decompile, i, raws.size()); |
| 483 | } | ||
| 482 | } | 484 | } |
| 483 | return unspecialized; | 485 | return unspecialized; |
| 484 | } | 486 | } |
| @@ -497,11 +499,12 @@ Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { | |||
| 497 | 499 | ||
| 498 | if (!shader) { | 500 | if (!shader) { |
| 499 | // No shader found - create a new one | 501 | // No shader found - create a new one |
| 500 | ProgramCode program_code{GetShaderCode(host_ptr)}; | 502 | ProgramCode program_code{GetShaderCode(memory_manager, program_addr, host_ptr)}; |
| 501 | ProgramCode program_code_b; | 503 | ProgramCode program_code_b; |
| 502 | if (program == Maxwell::ShaderProgram::VertexA) { | 504 | if (program == Maxwell::ShaderProgram::VertexA) { |
| 503 | program_code_b = GetShaderCode( | 505 | const GPUVAddr program_addr_b{GetShaderAddress(Maxwell::ShaderProgram::VertexB)}; |
| 504 | memory_manager.GetPointer(GetShaderAddress(Maxwell::ShaderProgram::VertexB))); | 506 | program_code_b = GetShaderCode(memory_manager, program_addr_b, |
| 507 | memory_manager.GetPointer(program_addr_b)); | ||
| 505 | } | 508 | } |
| 506 | const u64 unique_identifier = GetUniqueIdentifier(program, program_code, program_code_b); | 509 | const u64 unique_identifier = GetUniqueIdentifier(program, program_code, program_code_b); |
| 507 | const VAddr cpu_addr{*memory_manager.GpuToCpuAddress(program_addr)}; | 510 | const VAddr cpu_addr{*memory_manager.GpuToCpuAddress(program_addr)}; |
| @@ -512,7 +515,7 @@ Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { | |||
| 512 | precompiled_programs, found->second, host_ptr); | 515 | precompiled_programs, found->second, host_ptr); |
| 513 | } else { | 516 | } else { |
| 514 | shader = std::make_shared<CachedShader>( | 517 | shader = std::make_shared<CachedShader>( |
| 515 | cpu_addr, unique_identifier, program, disk_cache, precompiled_programs, | 518 | device, cpu_addr, unique_identifier, program, disk_cache, precompiled_programs, |
| 516 | std::move(program_code), std::move(program_code_b), host_ptr); | 519 | std::move(program_code), std::move(program_code_b), host_ptr); |
| 517 | } | 520 | } |
| 518 | Register(shader); | 521 | Register(shader); |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 0cf8e0b3d..a332087f8 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h | |||
| @@ -27,6 +27,7 @@ class System; | |||
| 27 | namespace OpenGL { | 27 | namespace OpenGL { |
| 28 | 28 | ||
| 29 | class CachedShader; | 29 | class CachedShader; |
| 30 | class Device; | ||
| 30 | class RasterizerOpenGL; | 31 | class RasterizerOpenGL; |
| 31 | struct UnspecializedShader; | 32 | struct UnspecializedShader; |
| 32 | 33 | ||
| @@ -38,7 +39,7 @@ using PrecompiledShaders = std::unordered_map<u64, GLShader::ProgramResult>; | |||
| 38 | 39 | ||
| 39 | class CachedShader final : public RasterizerCacheObject { | 40 | class CachedShader final : public RasterizerCacheObject { |
| 40 | public: | 41 | public: |
| 41 | explicit CachedShader(VAddr cpu_addr, u64 unique_identifier, | 42 | explicit CachedShader(const Device& device, VAddr cpu_addr, u64 unique_identifier, |
| 42 | Maxwell::ShaderProgram program_type, ShaderDiskCacheOpenGL& disk_cache, | 43 | Maxwell::ShaderProgram program_type, ShaderDiskCacheOpenGL& disk_cache, |
| 43 | const PrecompiledPrograms& precompiled_programs, | 44 | const PrecompiledPrograms& precompiled_programs, |
| 44 | ProgramCode&& program_code, ProgramCode&& program_code_b, u8* host_ptr); | 45 | ProgramCode&& program_code, ProgramCode&& program_code_b, u8* host_ptr); |
| @@ -112,7 +113,8 @@ private: | |||
| 112 | 113 | ||
| 113 | class ShaderCacheOpenGL final : public RasterizerCache<Shader> { | 114 | class ShaderCacheOpenGL final : public RasterizerCache<Shader> { |
| 114 | public: | 115 | public: |
| 115 | explicit ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system); | 116 | explicit ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system, |
| 117 | const Device& device); | ||
| 116 | 118 | ||
| 117 | /// Loads disk cache for the current game | 119 | /// Loads disk cache for the current game |
| 118 | void LoadDiskCache(const std::atomic_bool& stop_loading, | 120 | void LoadDiskCache(const std::atomic_bool& stop_loading, |
| @@ -130,6 +132,8 @@ private: | |||
| 130 | CachedProgram GeneratePrecompiledProgram(const ShaderDiskCacheDump& dump, | 132 | CachedProgram GeneratePrecompiledProgram(const ShaderDiskCacheDump& dump, |
| 131 | const std::set<GLenum>& supported_formats); | 133 | const std::set<GLenum>& supported_formats); |
| 132 | 134 | ||
| 135 | const Device& device; | ||
| 136 | |||
| 133 | std::array<Shader, Maxwell::MaxShaderProgram> last_shaders; | 137 | std::array<Shader, Maxwell::MaxShaderProgram> last_shaders; |
| 134 | 138 | ||
| 135 | ShaderDiskCacheOpenGL disk_cache; | 139 | ShaderDiskCacheOpenGL disk_cache; |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 28e490b3c..ef1a1995f 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "common/assert.h" | 15 | #include "common/assert.h" |
| 16 | #include "common/common_types.h" | 16 | #include "common/common_types.h" |
| 17 | #include "video_core/engines/maxwell_3d.h" | 17 | #include "video_core/engines/maxwell_3d.h" |
| 18 | #include "video_core/renderer_opengl/gl_device.h" | ||
| 18 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 19 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 19 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" | 20 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" |
| 20 | #include "video_core/shader/shader_ir.h" | 21 | #include "video_core/shader/shader_ir.h" |
| @@ -45,8 +46,6 @@ using TextureIR = std::variant<TextureAoffi, TextureArgument>; | |||
| 45 | enum : u32 { POSITION_VARYING_LOCATION = 0, GENERIC_VARYING_START_LOCATION = 1 }; | 46 | enum : u32 { POSITION_VARYING_LOCATION = 0, GENERIC_VARYING_START_LOCATION = 1 }; |
| 46 | constexpr u32 MAX_CONSTBUFFER_ELEMENTS = | 47 | constexpr u32 MAX_CONSTBUFFER_ELEMENTS = |
| 47 | static_cast<u32>(RasterizerOpenGL::MaxConstbufferSize) / (4 * sizeof(float)); | 48 | static_cast<u32>(RasterizerOpenGL::MaxConstbufferSize) / (4 * sizeof(float)); |
| 48 | constexpr u32 MAX_GLOBALMEMORY_ELEMENTS = | ||
| 49 | static_cast<u32>(RasterizerOpenGL::MaxGlobalMemorySize) / sizeof(float); | ||
| 50 | 49 | ||
| 51 | class ShaderWriter { | 50 | class ShaderWriter { |
| 52 | public: | 51 | public: |
| @@ -121,14 +120,10 @@ std::string GetTopologyName(Tegra::Shader::OutputTopology topology) { | |||
| 121 | 120 | ||
| 122 | /// Returns true if an object has to be treated as precise | 121 | /// Returns true if an object has to be treated as precise |
| 123 | bool IsPrecise(Operation operand) { | 122 | bool IsPrecise(Operation operand) { |
| 124 | const auto& meta = operand.GetMeta(); | 123 | const auto& meta{operand.GetMeta()}; |
| 125 | |||
| 126 | if (const auto arithmetic = std::get_if<MetaArithmetic>(&meta)) { | 124 | if (const auto arithmetic = std::get_if<MetaArithmetic>(&meta)) { |
| 127 | return arithmetic->precise; | 125 | return arithmetic->precise; |
| 128 | } | 126 | } |
| 129 | if (const auto half_arithmetic = std::get_if<MetaHalfArithmetic>(&meta)) { | ||
| 130 | return half_arithmetic->precise; | ||
| 131 | } | ||
| 132 | return false; | 127 | return false; |
| 133 | } | 128 | } |
| 134 | 129 | ||
| @@ -141,8 +136,9 @@ bool IsPrecise(Node node) { | |||
| 141 | 136 | ||
| 142 | class GLSLDecompiler final { | 137 | class GLSLDecompiler final { |
| 143 | public: | 138 | public: |
| 144 | explicit GLSLDecompiler(const ShaderIR& ir, ShaderStage stage, std::string suffix) | 139 | explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, ShaderStage stage, |
| 145 | : ir{ir}, stage{stage}, suffix{suffix}, header{ir.GetHeader()} {} | 140 | std::string suffix) |
| 141 | : device{device}, ir{ir}, stage{stage}, suffix{suffix}, header{ir.GetHeader()} {} | ||
| 146 | 142 | ||
| 147 | void Decompile() { | 143 | void Decompile() { |
| 148 | DeclareVertex(); | 144 | DeclareVertex(); |
| @@ -208,8 +204,10 @@ public: | |||
| 208 | for (const auto& sampler : ir.GetSamplers()) { | 204 | for (const auto& sampler : ir.GetSamplers()) { |
| 209 | entries.samplers.emplace_back(sampler); | 205 | entries.samplers.emplace_back(sampler); |
| 210 | } | 206 | } |
| 211 | for (const auto& gmem : ir.GetGlobalMemoryBases()) { | 207 | for (const auto& gmem_pair : ir.GetGlobalMemory()) { |
| 212 | entries.global_memory_entries.emplace_back(gmem.cbuf_index, gmem.cbuf_offset); | 208 | const auto& [base, usage] = gmem_pair; |
| 209 | entries.global_memory_entries.emplace_back(base.cbuf_index, base.cbuf_offset, | ||
| 210 | usage.is_read, usage.is_written); | ||
| 213 | } | 211 | } |
| 214 | entries.clip_distances = ir.GetClipDistances(); | 212 | entries.clip_distances = ir.GetClipDistances(); |
| 215 | entries.shader_length = ir.GetLength(); | 213 | entries.shader_length = ir.GetLength(); |
| @@ -380,12 +378,22 @@ private: | |||
| 380 | } | 378 | } |
| 381 | 379 | ||
| 382 | void DeclareGlobalMemory() { | 380 | void DeclareGlobalMemory() { |
| 383 | for (const auto& entry : ir.GetGlobalMemoryBases()) { | 381 | for (const auto& gmem : ir.GetGlobalMemory()) { |
| 382 | const auto& [base, usage] = gmem; | ||
| 383 | |||
| 384 | // Since we don't know how the shader will use the shader, hint the driver to disable as | ||
| 385 | // much optimizations as possible | ||
| 386 | std::string qualifier = "coherent volatile"; | ||
| 387 | if (usage.is_read && !usage.is_written) | ||
| 388 | qualifier += " readonly"; | ||
| 389 | else if (usage.is_written && !usage.is_read) | ||
| 390 | qualifier += " writeonly"; | ||
| 391 | |||
| 384 | const std::string binding = | 392 | const std::string binding = |
| 385 | fmt::format("GMEM_BINDING_{}_{}", entry.cbuf_index, entry.cbuf_offset); | 393 | fmt::format("GMEM_BINDING_{}_{}", base.cbuf_index, base.cbuf_offset); |
| 386 | code.AddLine("layout (std430, binding = " + binding + ") buffer " + | 394 | code.AddLine("layout (std430, binding = " + binding + ") " + qualifier + " buffer " + |
| 387 | GetGlobalMemoryBlock(entry) + " {"); | 395 | GetGlobalMemoryBlock(base) + " {"); |
| 388 | code.AddLine(" float " + GetGlobalMemory(entry) + "[MAX_GLOBALMEMORY_ELEMENTS];"); | 396 | code.AddLine(" float " + GetGlobalMemory(base) + "[];"); |
| 389 | code.AddLine("};"); | 397 | code.AddLine("};"); |
| 390 | code.AddNewLine(); | 398 | code.AddNewLine(); |
| 391 | } | 399 | } |
| @@ -617,28 +625,7 @@ private: | |||
| 617 | } | 625 | } |
| 618 | 626 | ||
| 619 | std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) { | 627 | std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) { |
| 620 | std::string value = VisitOperand(operation, operand_index); | 628 | return CastOperand(VisitOperand(operation, operand_index), type); |
| 621 | switch (type) { | ||
| 622 | case Type::HalfFloat: { | ||
| 623 | const auto half_meta = std::get_if<MetaHalfArithmetic>(&operation.GetMeta()); | ||
| 624 | if (!half_meta) { | ||
| 625 | value = "toHalf2(" + value + ')'; | ||
| 626 | } | ||
| 627 | |||
| 628 | switch (half_meta->types.at(operand_index)) { | ||
| 629 | case Tegra::Shader::HalfType::H0_H1: | ||
| 630 | return "toHalf2(" + value + ')'; | ||
| 631 | case Tegra::Shader::HalfType::F32: | ||
| 632 | return "vec2(" + value + ')'; | ||
| 633 | case Tegra::Shader::HalfType::H0_H0: | ||
| 634 | return "vec2(toHalf2(" + value + ")[0])"; | ||
| 635 | case Tegra::Shader::HalfType::H1_H1: | ||
| 636 | return "vec2(toHalf2(" + value + ")[1])"; | ||
| 637 | } | ||
| 638 | } | ||
| 639 | default: | ||
| 640 | return CastOperand(value, type); | ||
| 641 | } | ||
| 642 | } | 629 | } |
| 643 | 630 | ||
| 644 | std::string CastOperand(const std::string& value, Type type) const { | 631 | std::string CastOperand(const std::string& value, Type type) const { |
| @@ -652,9 +639,7 @@ private: | |||
| 652 | case Type::Uint: | 639 | case Type::Uint: |
| 653 | return "ftou(" + value + ')'; | 640 | return "ftou(" + value + ')'; |
| 654 | case Type::HalfFloat: | 641 | case Type::HalfFloat: |
| 655 | // Can't be handled as a stand-alone value | 642 | return "toHalf2(" + value + ')'; |
| 656 | UNREACHABLE(); | ||
| 657 | return value; | ||
| 658 | } | 643 | } |
| 659 | UNREACHABLE(); | 644 | UNREACHABLE(); |
| 660 | return value; | 645 | return value; |
| @@ -819,8 +804,12 @@ private: | |||
| 819 | // Inline the string as an immediate integer in GLSL (AOFFI arguments are required | 804 | // Inline the string as an immediate integer in GLSL (AOFFI arguments are required |
| 820 | // to be constant by the standard). | 805 | // to be constant by the standard). |
| 821 | expr += std::to_string(static_cast<s32>(immediate->GetValue())); | 806 | expr += std::to_string(static_cast<s32>(immediate->GetValue())); |
| 822 | } else { | 807 | } else if (device.HasVariableAoffi()) { |
| 808 | // Avoid using variable AOFFI on unsupported devices. | ||
| 823 | expr += "ftoi(" + Visit(operand) + ')'; | 809 | expr += "ftoi(" + Visit(operand) + ')'; |
| 810 | } else { | ||
| 811 | // Insert 0 on devices not supporting variable AOFFI. | ||
| 812 | expr += '0'; | ||
| 824 | } | 813 | } |
| 825 | if (index + 1 < aoffi.size()) { | 814 | if (index + 1 < aoffi.size()) { |
| 826 | expr += ", "; | 815 | expr += ", "; |
| @@ -868,6 +857,12 @@ private: | |||
| 868 | } else if (const auto lmem = std::get_if<LmemNode>(dest)) { | 857 | } else if (const auto lmem = std::get_if<LmemNode>(dest)) { |
| 869 | target = GetLocalMemory() + "[ftou(" + Visit(lmem->GetAddress()) + ") / 4]"; | 858 | target = GetLocalMemory() + "[ftou(" + Visit(lmem->GetAddress()) + ") / 4]"; |
| 870 | 859 | ||
| 860 | } else if (const auto gmem = std::get_if<GmemNode>(dest)) { | ||
| 861 | const std::string real = Visit(gmem->GetRealAddress()); | ||
| 862 | const std::string base = Visit(gmem->GetBaseAddress()); | ||
| 863 | const std::string final_offset = "(ftou(" + real + ") - ftou(" + base + ")) / 4"; | ||
| 864 | target = fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); | ||
| 865 | |||
| 871 | } else { | 866 | } else { |
| 872 | UNREACHABLE_MSG("Assign called without a proper target"); | 867 | UNREACHABLE_MSG("Assign called without a proper target"); |
| 873 | } | 868 | } |
| @@ -1067,13 +1062,40 @@ private: | |||
| 1067 | return BitwiseCastResult(value, Type::HalfFloat); | 1062 | return BitwiseCastResult(value, Type::HalfFloat); |
| 1068 | } | 1063 | } |
| 1069 | 1064 | ||
| 1065 | std::string HClamp(Operation operation) { | ||
| 1066 | const std::string value = VisitOperand(operation, 0, Type::HalfFloat); | ||
| 1067 | const std::string min = VisitOperand(operation, 1, Type::Float); | ||
| 1068 | const std::string max = VisitOperand(operation, 2, Type::Float); | ||
| 1069 | const std::string clamped = "clamp(" + value + ", vec2(" + min + "), vec2(" + max + "))"; | ||
| 1070 | return ApplyPrecise(operation, BitwiseCastResult(clamped, Type::HalfFloat)); | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | std::string HUnpack(Operation operation) { | ||
| 1074 | const std::string operand{VisitOperand(operation, 0, Type::HalfFloat)}; | ||
| 1075 | const auto value = [&]() -> std::string { | ||
| 1076 | switch (std::get<Tegra::Shader::HalfType>(operation.GetMeta())) { | ||
| 1077 | case Tegra::Shader::HalfType::H0_H1: | ||
| 1078 | return operand; | ||
| 1079 | case Tegra::Shader::HalfType::F32: | ||
| 1080 | return "vec2(fromHalf2(" + operand + "))"; | ||
| 1081 | case Tegra::Shader::HalfType::H0_H0: | ||
| 1082 | return "vec2(" + operand + "[0])"; | ||
| 1083 | case Tegra::Shader::HalfType::H1_H1: | ||
| 1084 | return "vec2(" + operand + "[1])"; | ||
| 1085 | } | ||
| 1086 | UNREACHABLE(); | ||
| 1087 | return "0"; | ||
| 1088 | }(); | ||
| 1089 | return "fromHalf2(" + value + ')'; | ||
| 1090 | } | ||
| 1091 | |||
| 1070 | std::string HMergeF32(Operation operation) { | 1092 | std::string HMergeF32(Operation operation) { |
| 1071 | return "float(toHalf2(" + Visit(operation[0]) + ")[0])"; | 1093 | return "float(toHalf2(" + Visit(operation[0]) + ")[0])"; |
| 1072 | } | 1094 | } |
| 1073 | 1095 | ||
| 1074 | std::string HMergeH0(Operation operation) { | 1096 | std::string HMergeH0(Operation operation) { |
| 1075 | return "fromHalf2(vec2(toHalf2(" + Visit(operation[0]) + ")[1], toHalf2(" + | 1097 | return "fromHalf2(vec2(toHalf2(" + Visit(operation[1]) + ")[0], toHalf2(" + |
| 1076 | Visit(operation[1]) + ")[0]))"; | 1098 | Visit(operation[0]) + ")[1]))"; |
| 1077 | } | 1099 | } |
| 1078 | 1100 | ||
| 1079 | std::string HMergeH1(Operation operation) { | 1101 | std::string HMergeH1(Operation operation) { |
| @@ -1173,34 +1195,46 @@ private: | |||
| 1173 | return GenerateUnary(operation, "any", Type::Bool, Type::Bool2); | 1195 | return GenerateUnary(operation, "any", Type::Bool, Type::Bool2); |
| 1174 | } | 1196 | } |
| 1175 | 1197 | ||
| 1198 | template <bool with_nan> | ||
| 1199 | std::string GenerateHalfComparison(Operation operation, std::string compare_op) { | ||
| 1200 | std::string comparison{GenerateBinaryCall(operation, compare_op, Type::Bool2, | ||
| 1201 | Type::HalfFloat, Type::HalfFloat)}; | ||
| 1202 | if constexpr (!with_nan) { | ||
| 1203 | return comparison; | ||
| 1204 | } | ||
| 1205 | return "halfFloatNanComparison(" + comparison + ", " + | ||
| 1206 | VisitOperand(operation, 0, Type::HalfFloat) + ", " + | ||
| 1207 | VisitOperand(operation, 1, Type::HalfFloat) + ')'; | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | template <bool with_nan> | ||
| 1176 | std::string Logical2HLessThan(Operation operation) { | 1211 | std::string Logical2HLessThan(Operation operation) { |
| 1177 | return GenerateBinaryCall(operation, "lessThan", Type::Bool2, Type::HalfFloat, | 1212 | return GenerateHalfComparison<with_nan>(operation, "lessThan"); |
| 1178 | Type::HalfFloat); | ||
| 1179 | } | 1213 | } |
| 1180 | 1214 | ||
| 1215 | template <bool with_nan> | ||
| 1181 | std::string Logical2HEqual(Operation operation) { | 1216 | std::string Logical2HEqual(Operation operation) { |
| 1182 | return GenerateBinaryCall(operation, "equal", Type::Bool2, Type::HalfFloat, | 1217 | return GenerateHalfComparison<with_nan>(operation, "equal"); |
| 1183 | Type::HalfFloat); | ||
| 1184 | } | 1218 | } |
| 1185 | 1219 | ||
| 1220 | template <bool with_nan> | ||
| 1186 | std::string Logical2HLessEqual(Operation operation) { | 1221 | std::string Logical2HLessEqual(Operation operation) { |
| 1187 | return GenerateBinaryCall(operation, "lessThanEqual", Type::Bool2, Type::HalfFloat, | 1222 | return GenerateHalfComparison<with_nan>(operation, "lessThanEqual"); |
| 1188 | Type::HalfFloat); | ||
| 1189 | } | 1223 | } |
| 1190 | 1224 | ||
| 1225 | template <bool with_nan> | ||
| 1191 | std::string Logical2HGreaterThan(Operation operation) { | 1226 | std::string Logical2HGreaterThan(Operation operation) { |
| 1192 | return GenerateBinaryCall(operation, "greaterThan", Type::Bool2, Type::HalfFloat, | 1227 | return GenerateHalfComparison<with_nan>(operation, "greaterThan"); |
| 1193 | Type::HalfFloat); | ||
| 1194 | } | 1228 | } |
| 1195 | 1229 | ||
| 1230 | template <bool with_nan> | ||
| 1196 | std::string Logical2HNotEqual(Operation operation) { | 1231 | std::string Logical2HNotEqual(Operation operation) { |
| 1197 | return GenerateBinaryCall(operation, "notEqual", Type::Bool2, Type::HalfFloat, | 1232 | return GenerateHalfComparison<with_nan>(operation, "notEqual"); |
| 1198 | Type::HalfFloat); | ||
| 1199 | } | 1233 | } |
| 1200 | 1234 | ||
| 1235 | template <bool with_nan> | ||
| 1201 | std::string Logical2HGreaterEqual(Operation operation) { | 1236 | std::string Logical2HGreaterEqual(Operation operation) { |
| 1202 | return GenerateBinaryCall(operation, "greaterThanEqual", Type::Bool2, Type::HalfFloat, | 1237 | return GenerateHalfComparison<with_nan>(operation, "greaterThanEqual"); |
| 1203 | Type::HalfFloat); | ||
| 1204 | } | 1238 | } |
| 1205 | 1239 | ||
| 1206 | std::string Texture(Operation operation) { | 1240 | std::string Texture(Operation operation) { |
| @@ -1489,6 +1523,8 @@ private: | |||
| 1489 | &GLSLDecompiler::Fma<Type::HalfFloat>, | 1523 | &GLSLDecompiler::Fma<Type::HalfFloat>, |
| 1490 | &GLSLDecompiler::Absolute<Type::HalfFloat>, | 1524 | &GLSLDecompiler::Absolute<Type::HalfFloat>, |
| 1491 | &GLSLDecompiler::HNegate, | 1525 | &GLSLDecompiler::HNegate, |
| 1526 | &GLSLDecompiler::HClamp, | ||
| 1527 | &GLSLDecompiler::HUnpack, | ||
| 1492 | &GLSLDecompiler::HMergeF32, | 1528 | &GLSLDecompiler::HMergeF32, |
| 1493 | &GLSLDecompiler::HMergeH0, | 1529 | &GLSLDecompiler::HMergeH0, |
| 1494 | &GLSLDecompiler::HMergeH1, | 1530 | &GLSLDecompiler::HMergeH1, |
| @@ -1525,12 +1561,18 @@ private: | |||
| 1525 | &GLSLDecompiler::LogicalNotEqual<Type::Uint>, | 1561 | &GLSLDecompiler::LogicalNotEqual<Type::Uint>, |
| 1526 | &GLSLDecompiler::LogicalGreaterEqual<Type::Uint>, | 1562 | &GLSLDecompiler::LogicalGreaterEqual<Type::Uint>, |
| 1527 | 1563 | ||
| 1528 | &GLSLDecompiler::Logical2HLessThan, | 1564 | &GLSLDecompiler::Logical2HLessThan<false>, |
| 1529 | &GLSLDecompiler::Logical2HEqual, | 1565 | &GLSLDecompiler::Logical2HEqual<false>, |
| 1530 | &GLSLDecompiler::Logical2HLessEqual, | 1566 | &GLSLDecompiler::Logical2HLessEqual<false>, |
| 1531 | &GLSLDecompiler::Logical2HGreaterThan, | 1567 | &GLSLDecompiler::Logical2HGreaterThan<false>, |
| 1532 | &GLSLDecompiler::Logical2HNotEqual, | 1568 | &GLSLDecompiler::Logical2HNotEqual<false>, |
| 1533 | &GLSLDecompiler::Logical2HGreaterEqual, | 1569 | &GLSLDecompiler::Logical2HGreaterEqual<false>, |
| 1570 | &GLSLDecompiler::Logical2HLessThan<true>, | ||
| 1571 | &GLSLDecompiler::Logical2HEqual<true>, | ||
| 1572 | &GLSLDecompiler::Logical2HLessEqual<true>, | ||
| 1573 | &GLSLDecompiler::Logical2HGreaterThan<true>, | ||
| 1574 | &GLSLDecompiler::Logical2HNotEqual<true>, | ||
| 1575 | &GLSLDecompiler::Logical2HGreaterEqual<true>, | ||
| 1534 | 1576 | ||
| 1535 | &GLSLDecompiler::Texture, | 1577 | &GLSLDecompiler::Texture, |
| 1536 | &GLSLDecompiler::TextureLod, | 1578 | &GLSLDecompiler::TextureLod, |
| @@ -1609,6 +1651,7 @@ private: | |||
| 1609 | return name + '_' + std::to_string(index) + '_' + suffix; | 1651 | return name + '_' + std::to_string(index) + '_' + suffix; |
| 1610 | } | 1652 | } |
| 1611 | 1653 | ||
| 1654 | const Device& device; | ||
| 1612 | const ShaderIR& ir; | 1655 | const ShaderIR& ir; |
| 1613 | const ShaderStage stage; | 1656 | const ShaderStage stage; |
| 1614 | const std::string suffix; | 1657 | const std::string suffix; |
| @@ -1621,9 +1664,7 @@ private: | |||
| 1621 | 1664 | ||
| 1622 | std::string GetCommonDeclarations() { | 1665 | std::string GetCommonDeclarations() { |
| 1623 | const auto cbuf = std::to_string(MAX_CONSTBUFFER_ELEMENTS); | 1666 | const auto cbuf = std::to_string(MAX_CONSTBUFFER_ELEMENTS); |
| 1624 | const auto gmem = std::to_string(MAX_GLOBALMEMORY_ELEMENTS); | ||
| 1625 | return "#define MAX_CONSTBUFFER_ELEMENTS " + cbuf + "\n" + | 1667 | return "#define MAX_CONSTBUFFER_ELEMENTS " + cbuf + "\n" + |
| 1626 | "#define MAX_GLOBALMEMORY_ELEMENTS " + gmem + "\n" + | ||
| 1627 | "#define ftoi floatBitsToInt\n" | 1668 | "#define ftoi floatBitsToInt\n" |
| 1628 | "#define ftou floatBitsToUint\n" | 1669 | "#define ftou floatBitsToUint\n" |
| 1629 | "#define itof intBitsToFloat\n" | 1670 | "#define itof intBitsToFloat\n" |
| @@ -1633,11 +1674,18 @@ std::string GetCommonDeclarations() { | |||
| 1633 | "}\n\n" | 1674 | "}\n\n" |
| 1634 | "vec2 toHalf2(float value) {\n" | 1675 | "vec2 toHalf2(float value) {\n" |
| 1635 | " return unpackHalf2x16(ftou(value));\n" | 1676 | " return unpackHalf2x16(ftou(value));\n" |
| 1677 | "}\n\n" | ||
| 1678 | "bvec2 halfFloatNanComparison(bvec2 comparison, vec2 pair1, vec2 pair2) {\n" | ||
| 1679 | " bvec2 is_nan1 = isnan(pair1);\n" | ||
| 1680 | " bvec2 is_nan2 = isnan(pair2);\n" | ||
| 1681 | " return bvec2(comparison.x || is_nan1.x || is_nan2.x, comparison.y || is_nan1.y || " | ||
| 1682 | "is_nan2.y);\n" | ||
| 1636 | "}\n"; | 1683 | "}\n"; |
| 1637 | } | 1684 | } |
| 1638 | 1685 | ||
| 1639 | ProgramResult Decompile(const ShaderIR& ir, Maxwell::ShaderStage stage, const std::string& suffix) { | 1686 | ProgramResult Decompile(const Device& device, const ShaderIR& ir, Maxwell::ShaderStage stage, |
| 1640 | GLSLDecompiler decompiler(ir, stage, suffix); | 1687 | const std::string& suffix) { |
| 1688 | GLSLDecompiler decompiler(device, ir, stage, suffix); | ||
| 1641 | decompiler.Decompile(); | 1689 | decompiler.Decompile(); |
| 1642 | return {decompiler.GetResult(), decompiler.GetShaderEntries()}; | 1690 | return {decompiler.GetResult(), decompiler.GetShaderEntries()}; |
| 1643 | } | 1691 | } |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h index 4e04ab2f8..c1569e737 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.h +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h | |||
| @@ -12,6 +12,10 @@ | |||
| 12 | #include "video_core/engines/maxwell_3d.h" | 12 | #include "video_core/engines/maxwell_3d.h" |
| 13 | #include "video_core/shader/shader_ir.h" | 13 | #include "video_core/shader/shader_ir.h" |
| 14 | 14 | ||
| 15 | namespace OpenGL { | ||
| 16 | class Device; | ||
| 17 | } | ||
| 18 | |||
| 15 | namespace VideoCommon::Shader { | 19 | namespace VideoCommon::Shader { |
| 16 | class ShaderIR; | 20 | class ShaderIR; |
| 17 | } | 21 | } |
| @@ -39,8 +43,9 @@ private: | |||
| 39 | 43 | ||
| 40 | class GlobalMemoryEntry { | 44 | class GlobalMemoryEntry { |
| 41 | public: | 45 | public: |
| 42 | explicit GlobalMemoryEntry(u32 cbuf_index, u32 cbuf_offset) | 46 | explicit GlobalMemoryEntry(u32 cbuf_index, u32 cbuf_offset, bool is_read, bool is_written) |
| 43 | : cbuf_index{cbuf_index}, cbuf_offset{cbuf_offset} {} | 47 | : cbuf_index{cbuf_index}, cbuf_offset{cbuf_offset}, is_read{is_read}, is_written{ |
| 48 | is_written} {} | ||
| 44 | 49 | ||
| 45 | u32 GetCbufIndex() const { | 50 | u32 GetCbufIndex() const { |
| 46 | return cbuf_index; | 51 | return cbuf_index; |
| @@ -50,14 +55,25 @@ public: | |||
| 50 | return cbuf_offset; | 55 | return cbuf_offset; |
| 51 | } | 56 | } |
| 52 | 57 | ||
| 58 | bool IsRead() const { | ||
| 59 | return is_read; | ||
| 60 | } | ||
| 61 | |||
| 62 | bool IsWritten() const { | ||
| 63 | return is_written; | ||
| 64 | } | ||
| 65 | |||
| 53 | private: | 66 | private: |
| 54 | u32 cbuf_index{}; | 67 | u32 cbuf_index{}; |
| 55 | u32 cbuf_offset{}; | 68 | u32 cbuf_offset{}; |
| 69 | bool is_read{}; | ||
| 70 | bool is_written{}; | ||
| 56 | }; | 71 | }; |
| 57 | 72 | ||
| 58 | struct ShaderEntries { | 73 | struct ShaderEntries { |
| 59 | std::vector<ConstBufferEntry> const_buffers; | 74 | std::vector<ConstBufferEntry> const_buffers; |
| 60 | std::vector<SamplerEntry> samplers; | 75 | std::vector<SamplerEntry> samplers; |
| 76 | std::vector<SamplerEntry> bindless_samplers; | ||
| 61 | std::vector<GlobalMemoryEntry> global_memory_entries; | 77 | std::vector<GlobalMemoryEntry> global_memory_entries; |
| 62 | std::array<bool, Maxwell::NumClipDistances> clip_distances{}; | 78 | std::array<bool, Maxwell::NumClipDistances> clip_distances{}; |
| 63 | std::size_t shader_length{}; | 79 | std::size_t shader_length{}; |
| @@ -65,7 +81,7 @@ struct ShaderEntries { | |||
| 65 | 81 | ||
| 66 | std::string GetCommonDeclarations(); | 82 | std::string GetCommonDeclarations(); |
| 67 | 83 | ||
| 68 | ProgramResult Decompile(const VideoCommon::Shader::ShaderIR& ir, Maxwell::ShaderStage stage, | 84 | ProgramResult Decompile(const Device& device, const VideoCommon::Shader::ShaderIR& ir, |
| 69 | const std::string& suffix); | 85 | Maxwell::ShaderStage stage, const std::string& suffix); |
| 70 | 86 | ||
| 71 | } // namespace OpenGL::GLShader \ No newline at end of file | 87 | } // namespace OpenGL::GLShader |
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp index 8a43eb157..53752b38d 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | |||
| @@ -319,16 +319,19 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn | |||
| 319 | u32 type{}; | 319 | u32 type{}; |
| 320 | u8 is_array{}; | 320 | u8 is_array{}; |
| 321 | u8 is_shadow{}; | 321 | u8 is_shadow{}; |
| 322 | u8 is_bindless{}; | ||
| 322 | if (file.ReadBytes(&offset, sizeof(u64)) != sizeof(u64) || | 323 | if (file.ReadBytes(&offset, sizeof(u64)) != sizeof(u64) || |
| 323 | file.ReadBytes(&index, sizeof(u64)) != sizeof(u64) || | 324 | file.ReadBytes(&index, sizeof(u64)) != sizeof(u64) || |
| 324 | file.ReadBytes(&type, sizeof(u32)) != sizeof(u32) || | 325 | file.ReadBytes(&type, sizeof(u32)) != sizeof(u32) || |
| 325 | file.ReadBytes(&is_array, sizeof(u8)) != sizeof(u8) || | 326 | file.ReadBytes(&is_array, sizeof(u8)) != sizeof(u8) || |
| 326 | file.ReadBytes(&is_shadow, sizeof(u8)) != sizeof(u8)) { | 327 | file.ReadBytes(&is_shadow, sizeof(u8)) != sizeof(u8) || |
| 328 | file.ReadBytes(&is_bindless, sizeof(u8)) != sizeof(u8)) { | ||
| 327 | return {}; | 329 | return {}; |
| 328 | } | 330 | } |
| 329 | entry.entries.samplers.emplace_back( | 331 | entry.entries.samplers.emplace_back(static_cast<std::size_t>(offset), |
| 330 | static_cast<std::size_t>(offset), static_cast<std::size_t>(index), | 332 | static_cast<std::size_t>(index), |
| 331 | static_cast<Tegra::Shader::TextureType>(type), is_array != 0, is_shadow != 0); | 333 | static_cast<Tegra::Shader::TextureType>(type), |
| 334 | is_array != 0, is_shadow != 0, is_bindless != 0); | ||
| 332 | } | 335 | } |
| 333 | 336 | ||
| 334 | u32 global_memory_count{}; | 337 | u32 global_memory_count{}; |
| @@ -337,11 +340,16 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn | |||
| 337 | for (u32 i = 0; i < global_memory_count; ++i) { | 340 | for (u32 i = 0; i < global_memory_count; ++i) { |
| 338 | u32 cbuf_index{}; | 341 | u32 cbuf_index{}; |
| 339 | u32 cbuf_offset{}; | 342 | u32 cbuf_offset{}; |
| 343 | u8 is_read{}; | ||
| 344 | u8 is_written{}; | ||
| 340 | if (file.ReadBytes(&cbuf_index, sizeof(u32)) != sizeof(u32) || | 345 | if (file.ReadBytes(&cbuf_index, sizeof(u32)) != sizeof(u32) || |
| 341 | file.ReadBytes(&cbuf_offset, sizeof(u32)) != sizeof(u32)) { | 346 | file.ReadBytes(&cbuf_offset, sizeof(u32)) != sizeof(u32) || |
| 347 | file.ReadBytes(&is_read, sizeof(u8)) != sizeof(u8) || | ||
| 348 | file.ReadBytes(&is_written, sizeof(u8)) != sizeof(u8)) { | ||
| 342 | return {}; | 349 | return {}; |
| 343 | } | 350 | } |
| 344 | entry.entries.global_memory_entries.emplace_back(cbuf_index, cbuf_offset); | 351 | entry.entries.global_memory_entries.emplace_back(cbuf_index, cbuf_offset, is_read != 0, |
| 352 | is_written != 0); | ||
| 345 | } | 353 | } |
| 346 | 354 | ||
| 347 | for (auto& clip_distance : entry.entries.clip_distances) { | 355 | for (auto& clip_distance : entry.entries.clip_distances) { |
| @@ -388,7 +396,8 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(FileUtil::IOFile& file, u64 uniqu | |||
| 388 | file.WriteObject(static_cast<u64>(sampler.GetIndex())) != 1 || | 396 | file.WriteObject(static_cast<u64>(sampler.GetIndex())) != 1 || |
| 389 | file.WriteObject(static_cast<u32>(sampler.GetType())) != 1 || | 397 | file.WriteObject(static_cast<u32>(sampler.GetType())) != 1 || |
| 390 | file.WriteObject(static_cast<u8>(sampler.IsArray() ? 1 : 0)) != 1 || | 398 | file.WriteObject(static_cast<u8>(sampler.IsArray() ? 1 : 0)) != 1 || |
| 391 | file.WriteObject(static_cast<u8>(sampler.IsShadow() ? 1 : 0)) != 1) { | 399 | file.WriteObject(static_cast<u8>(sampler.IsShadow() ? 1 : 0)) != 1 || |
| 400 | file.WriteObject(static_cast<u8>(sampler.IsBindless() ? 1 : 0)) != 1) { | ||
| 392 | return false; | 401 | return false; |
| 393 | } | 402 | } |
| 394 | } | 403 | } |
| @@ -397,7 +406,9 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(FileUtil::IOFile& file, u64 uniqu | |||
| 397 | return false; | 406 | return false; |
| 398 | for (const auto& gmem : entries.global_memory_entries) { | 407 | for (const auto& gmem : entries.global_memory_entries) { |
| 399 | if (file.WriteObject(static_cast<u32>(gmem.GetCbufIndex())) != 1 || | 408 | if (file.WriteObject(static_cast<u32>(gmem.GetCbufIndex())) != 1 || |
| 400 | file.WriteObject(static_cast<u32>(gmem.GetCbufOffset())) != 1) { | 409 | file.WriteObject(static_cast<u32>(gmem.GetCbufOffset())) != 1 || |
| 410 | file.WriteObject(static_cast<u8>(gmem.IsRead() ? 1 : 0)) != 1 || | ||
| 411 | file.WriteObject(static_cast<u8>(gmem.IsWritten() ? 1 : 0)) != 1) { | ||
| 401 | return false; | 412 | return false; |
| 402 | } | 413 | } |
| 403 | } | 414 | } |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 8763d9c71..6abf948f8 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -16,7 +16,7 @@ using VideoCommon::Shader::ShaderIR; | |||
| 16 | 16 | ||
| 17 | static constexpr u32 PROGRAM_OFFSET{10}; | 17 | static constexpr u32 PROGRAM_OFFSET{10}; |
| 18 | 18 | ||
| 19 | ProgramResult GenerateVertexShader(const ShaderSetup& setup) { | 19 | ProgramResult GenerateVertexShader(const Device& device, const ShaderSetup& setup) { |
| 20 | const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); | 20 | const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); |
| 21 | 21 | ||
| 22 | std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n"; | 22 | std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n"; |
| @@ -34,14 +34,15 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config { | |||
| 34 | 34 | ||
| 35 | )"; | 35 | )"; |
| 36 | ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); | 36 | ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); |
| 37 | ProgramResult program = Decompile(program_ir, Maxwell3D::Regs::ShaderStage::Vertex, "vertex"); | 37 | ProgramResult program = |
| 38 | Decompile(device, program_ir, Maxwell3D::Regs::ShaderStage::Vertex, "vertex"); | ||
| 38 | 39 | ||
| 39 | out += program.first; | 40 | out += program.first; |
| 40 | 41 | ||
| 41 | if (setup.IsDualProgram()) { | 42 | if (setup.IsDualProgram()) { |
| 42 | ShaderIR program_ir_b(setup.program.code_b, PROGRAM_OFFSET); | 43 | ShaderIR program_ir_b(setup.program.code_b, PROGRAM_OFFSET); |
| 43 | ProgramResult program_b = | 44 | ProgramResult program_b = |
| 44 | Decompile(program_ir_b, Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b"); | 45 | Decompile(device, program_ir_b, Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b"); |
| 45 | 46 | ||
| 46 | out += program_b.first; | 47 | out += program_b.first; |
| 47 | } | 48 | } |
| @@ -57,6 +58,9 @@ void main() { | |||
| 57 | } | 58 | } |
| 58 | 59 | ||
| 59 | out += R"( | 60 | out += R"( |
| 61 | |||
| 62 | // Set Position Y direction | ||
| 63 | position.y *= utof(config_pack[2]); | ||
| 60 | // Check if the flip stage is VertexB | 64 | // Check if the flip stage is VertexB |
| 61 | // Config pack's second value is flip_stage | 65 | // Config pack's second value is flip_stage |
| 62 | if (config_pack[1] == 1) { | 66 | if (config_pack[1] == 1) { |
| @@ -75,7 +79,7 @@ void main() { | |||
| 75 | return {out, program.second}; | 79 | return {out, program.second}; |
| 76 | } | 80 | } |
| 77 | 81 | ||
| 78 | ProgramResult GenerateGeometryShader(const ShaderSetup& setup) { | 82 | ProgramResult GenerateGeometryShader(const Device& device, const ShaderSetup& setup) { |
| 79 | const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); | 83 | const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); |
| 80 | 84 | ||
| 81 | std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n"; | 85 | std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n"; |
| @@ -95,7 +99,7 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config { | |||
| 95 | )"; | 99 | )"; |
| 96 | ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); | 100 | ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); |
| 97 | ProgramResult program = | 101 | ProgramResult program = |
| 98 | Decompile(program_ir, Maxwell3D::Regs::ShaderStage::Geometry, "geometry"); | 102 | Decompile(device, program_ir, Maxwell3D::Regs::ShaderStage::Geometry, "geometry"); |
| 99 | out += program.first; | 103 | out += program.first; |
| 100 | 104 | ||
| 101 | out += R"( | 105 | out += R"( |
| @@ -106,7 +110,7 @@ void main() { | |||
| 106 | return {out, program.second}; | 110 | return {out, program.second}; |
| 107 | } | 111 | } |
| 108 | 112 | ||
| 109 | ProgramResult GenerateFragmentShader(const ShaderSetup& setup) { | 113 | ProgramResult GenerateFragmentShader(const Device& device, const ShaderSetup& setup) { |
| 110 | const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); | 114 | const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); |
| 111 | 115 | ||
| 112 | std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n"; | 116 | std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n"; |
| @@ -158,7 +162,7 @@ bool AlphaFunc(in float value) { | |||
| 158 | )"; | 162 | )"; |
| 159 | ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); | 163 | ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); |
| 160 | ProgramResult program = | 164 | ProgramResult program = |
| 161 | Decompile(program_ir, Maxwell3D::Regs::ShaderStage::Fragment, "fragment"); | 165 | Decompile(device, program_ir, Maxwell3D::Regs::ShaderStage::Fragment, "fragment"); |
| 162 | 166 | ||
| 163 | out += program.first; | 167 | out += program.first; |
| 164 | 168 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index fad346b48..0536c8a03 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h | |||
| @@ -10,6 +10,10 @@ | |||
| 10 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" | 10 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" |
| 11 | #include "video_core/shader/shader_ir.h" | 11 | #include "video_core/shader/shader_ir.h" |
| 12 | 12 | ||
| 13 | namespace OpenGL { | ||
| 14 | class Device; | ||
| 15 | } | ||
| 16 | |||
| 13 | namespace OpenGL::GLShader { | 17 | namespace OpenGL::GLShader { |
| 14 | 18 | ||
| 15 | using VideoCommon::Shader::ProgramCode; | 19 | using VideoCommon::Shader::ProgramCode; |
| @@ -39,22 +43,13 @@ private: | |||
| 39 | bool has_program_b{}; | 43 | bool has_program_b{}; |
| 40 | }; | 44 | }; |
| 41 | 45 | ||
| 42 | /** | 46 | /// Generates the GLSL vertex shader program source code for the given VS program |
| 43 | * Generates the GLSL vertex shader program source code for the given VS program | 47 | ProgramResult GenerateVertexShader(const Device& device, const ShaderSetup& setup); |
| 44 | * @returns String of the shader source code | 48 | |
| 45 | */ | 49 | /// Generates the GLSL geometry shader program source code for the given GS program |
| 46 | ProgramResult GenerateVertexShader(const ShaderSetup& setup); | 50 | ProgramResult GenerateGeometryShader(const Device& device, const ShaderSetup& setup); |
| 47 | 51 | ||
| 48 | /** | 52 | /// Generates the GLSL fragment shader program source code for the given FS program |
| 49 | * Generates the GLSL geometry shader program source code for the given GS program | 53 | ProgramResult GenerateFragmentShader(const Device& device, const ShaderSetup& setup); |
| 50 | * @returns String of the shader source code | ||
| 51 | */ | ||
| 52 | ProgramResult GenerateGeometryShader(const ShaderSetup& setup); | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Generates the GLSL fragment shader program source code for the given FS program | ||
| 56 | * @returns String of the shader source code | ||
| 57 | */ | ||
| 58 | ProgramResult GenerateFragmentShader(const ShaderSetup& setup); | ||
| 59 | 54 | ||
| 60 | } // namespace OpenGL::GLShader | 55 | } // namespace OpenGL::GLShader |
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 52d569a1b..7425fbe5d 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -471,8 +471,9 @@ void OpenGLState::ApplyTextures() const { | |||
| 471 | const auto& texture_unit = texture_units[i]; | 471 | const auto& texture_unit = texture_units[i]; |
| 472 | auto& cur_state_texture_unit = cur_state.texture_units[i]; | 472 | auto& cur_state_texture_unit = cur_state.texture_units[i]; |
| 473 | textures[i] = texture_unit.texture; | 473 | textures[i] = texture_unit.texture; |
| 474 | if (cur_state_texture_unit.texture == textures[i]) | 474 | if (cur_state_texture_unit.texture == textures[i]) { |
| 475 | continue; | 475 | continue; |
| 476 | } | ||
| 476 | cur_state_texture_unit.texture = textures[i]; | 477 | cur_state_texture_unit.texture = textures[i]; |
| 477 | if (!has_delta) { | 478 | if (!has_delta) { |
| 478 | first = i; | 479 | first = i; |
| @@ -493,10 +494,11 @@ void OpenGLState::ApplySamplers() const { | |||
| 493 | std::array<GLuint, Maxwell::NumTextureSamplers> samplers; | 494 | std::array<GLuint, Maxwell::NumTextureSamplers> samplers; |
| 494 | 495 | ||
| 495 | for (std::size_t i = 0; i < std::size(samplers); ++i) { | 496 | for (std::size_t i = 0; i < std::size(samplers); ++i) { |
| 496 | if (cur_state.texture_units[i].sampler == texture_units[i].sampler) | 497 | samplers[i] = texture_units[i].sampler; |
| 498 | if (cur_state.texture_units[i].sampler == texture_units[i].sampler) { | ||
| 497 | continue; | 499 | continue; |
| 500 | } | ||
| 498 | cur_state.texture_units[i].sampler = texture_units[i].sampler; | 501 | cur_state.texture_units[i].sampler = texture_units[i].sampler; |
| 499 | samplers[i] = texture_units[i].sampler; | ||
| 500 | if (!has_delta) { | 502 | if (!has_delta) { |
| 501 | first = i; | 503 | first = i; |
| 502 | has_delta = true; | 504 | has_delta = true; |
diff --git a/src/video_core/renderer_vulkan/vk_sampler_cache.cpp b/src/video_core/renderer_vulkan/vk_sampler_cache.cpp index ed3178f09..801826d3d 100644 --- a/src/video_core/renderer_vulkan/vk_sampler_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_sampler_cache.cpp | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include <unordered_map> | 7 | #include <unordered_map> |
| 8 | 8 | ||
| 9 | #include "common/assert.h" | 9 | #include "common/assert.h" |
| 10 | #include "common/cityhash.h" | ||
| 11 | #include "video_core/renderer_vulkan/declarations.h" | 10 | #include "video_core/renderer_vulkan/declarations.h" |
| 12 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 11 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 13 | #include "video_core/renderer_vulkan/vk_sampler_cache.h" | 12 | #include "video_core/renderer_vulkan/vk_sampler_cache.h" |
| @@ -28,39 +27,20 @@ static std::optional<vk::BorderColor> TryConvertBorderColor(std::array<float, 4> | |||
| 28 | } | 27 | } |
| 29 | } | 28 | } |
| 30 | 29 | ||
| 31 | std::size_t SamplerCacheKey::Hash() const { | ||
| 32 | static_assert(sizeof(raw) % sizeof(u64) == 0); | ||
| 33 | return static_cast<std::size_t>( | ||
| 34 | Common::CityHash64(reinterpret_cast<const char*>(raw.data()), sizeof(raw) / sizeof(u64))); | ||
| 35 | } | ||
| 36 | |||
| 37 | bool SamplerCacheKey::operator==(const SamplerCacheKey& rhs) const { | ||
| 38 | return raw == rhs.raw; | ||
| 39 | } | ||
| 40 | |||
| 41 | VKSamplerCache::VKSamplerCache(const VKDevice& device) : device{device} {} | 30 | VKSamplerCache::VKSamplerCache(const VKDevice& device) : device{device} {} |
| 42 | 31 | ||
| 43 | VKSamplerCache::~VKSamplerCache() = default; | 32 | VKSamplerCache::~VKSamplerCache() = default; |
| 44 | 33 | ||
| 45 | vk::Sampler VKSamplerCache::GetSampler(const Tegra::Texture::TSCEntry& tsc) { | 34 | UniqueSampler VKSamplerCache::CreateSampler(const Tegra::Texture::TSCEntry& tsc) const { |
| 46 | const auto [entry, is_cache_miss] = cache.try_emplace(SamplerCacheKey{tsc}); | 35 | const float max_anisotropy{tsc.GetMaxAnisotropy()}; |
| 47 | auto& sampler = entry->second; | 36 | const bool has_anisotropy{max_anisotropy > 1.0f}; |
| 48 | if (is_cache_miss) { | ||
| 49 | sampler = CreateSampler(tsc); | ||
| 50 | } | ||
| 51 | return *sampler; | ||
| 52 | } | ||
| 53 | |||
| 54 | UniqueSampler VKSamplerCache::CreateSampler(const Tegra::Texture::TSCEntry& tsc) { | ||
| 55 | const float max_anisotropy = tsc.GetMaxAnisotropy(); | ||
| 56 | const bool has_anisotropy = max_anisotropy > 1.0f; | ||
| 57 | 37 | ||
| 58 | const auto border_color = tsc.GetBorderColor(); | 38 | const auto border_color{tsc.GetBorderColor()}; |
| 59 | const auto vk_border_color = TryConvertBorderColor(border_color); | 39 | const auto vk_border_color{TryConvertBorderColor(border_color)}; |
| 60 | UNIMPLEMENTED_IF_MSG(!vk_border_color, "Unimplemented border color {} {} {} {}", | 40 | UNIMPLEMENTED_IF_MSG(!vk_border_color, "Unimplemented border color {} {} {} {}", |
| 61 | border_color[0], border_color[1], border_color[2], border_color[3]); | 41 | border_color[0], border_color[1], border_color[2], border_color[3]); |
| 62 | 42 | ||
| 63 | constexpr bool unnormalized_coords = false; | 43 | constexpr bool unnormalized_coords{false}; |
| 64 | 44 | ||
| 65 | const vk::SamplerCreateInfo sampler_ci( | 45 | const vk::SamplerCreateInfo sampler_ci( |
| 66 | {}, MaxwellToVK::Sampler::Filter(tsc.mag_filter), | 46 | {}, MaxwellToVK::Sampler::Filter(tsc.mag_filter), |
| @@ -73,9 +53,13 @@ UniqueSampler VKSamplerCache::CreateSampler(const Tegra::Texture::TSCEntry& tsc) | |||
| 73 | tsc.GetMaxLod(), vk_border_color.value_or(vk::BorderColor::eFloatTransparentBlack), | 53 | tsc.GetMaxLod(), vk_border_color.value_or(vk::BorderColor::eFloatTransparentBlack), |
| 74 | unnormalized_coords); | 54 | unnormalized_coords); |
| 75 | 55 | ||
| 76 | const auto& dld = device.GetDispatchLoader(); | 56 | const auto& dld{device.GetDispatchLoader()}; |
| 77 | const auto dev = device.GetLogical(); | 57 | const auto dev{device.GetLogical()}; |
| 78 | return dev.createSamplerUnique(sampler_ci, nullptr, dld); | 58 | return dev.createSamplerUnique(sampler_ci, nullptr, dld); |
| 79 | } | 59 | } |
| 80 | 60 | ||
| 61 | vk::Sampler VKSamplerCache::ToSamplerType(const UniqueSampler& sampler) const { | ||
| 62 | return *sampler; | ||
| 63 | } | ||
| 64 | |||
| 81 | } // namespace Vulkan | 65 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_sampler_cache.h b/src/video_core/renderer_vulkan/vk_sampler_cache.h index c6394dc87..771b05c73 100644 --- a/src/video_core/renderer_vulkan/vk_sampler_cache.h +++ b/src/video_core/renderer_vulkan/vk_sampler_cache.h | |||
| @@ -8,49 +8,25 @@ | |||
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "video_core/renderer_vulkan/declarations.h" | 10 | #include "video_core/renderer_vulkan/declarations.h" |
| 11 | #include "video_core/sampler_cache.h" | ||
| 11 | #include "video_core/textures/texture.h" | 12 | #include "video_core/textures/texture.h" |
| 12 | 13 | ||
| 13 | namespace Vulkan { | 14 | namespace Vulkan { |
| 14 | 15 | ||
| 15 | class VKDevice; | 16 | class VKDevice; |
| 16 | 17 | ||
| 17 | struct SamplerCacheKey final : public Tegra::Texture::TSCEntry { | 18 | class VKSamplerCache final : public VideoCommon::SamplerCache<vk::Sampler, UniqueSampler> { |
| 18 | std::size_t Hash() const; | ||
| 19 | |||
| 20 | bool operator==(const SamplerCacheKey& rhs) const; | ||
| 21 | |||
| 22 | bool operator!=(const SamplerCacheKey& rhs) const { | ||
| 23 | return !operator==(rhs); | ||
| 24 | } | ||
| 25 | }; | ||
| 26 | |||
| 27 | } // namespace Vulkan | ||
| 28 | |||
| 29 | namespace std { | ||
| 30 | |||
| 31 | template <> | ||
| 32 | struct hash<Vulkan::SamplerCacheKey> { | ||
| 33 | std::size_t operator()(const Vulkan::SamplerCacheKey& k) const noexcept { | ||
| 34 | return k.Hash(); | ||
| 35 | } | ||
| 36 | }; | ||
| 37 | |||
| 38 | } // namespace std | ||
| 39 | |||
| 40 | namespace Vulkan { | ||
| 41 | |||
| 42 | class VKSamplerCache { | ||
| 43 | public: | 19 | public: |
| 44 | explicit VKSamplerCache(const VKDevice& device); | 20 | explicit VKSamplerCache(const VKDevice& device); |
| 45 | ~VKSamplerCache(); | 21 | ~VKSamplerCache(); |
| 46 | 22 | ||
| 47 | vk::Sampler GetSampler(const Tegra::Texture::TSCEntry& tsc); | 23 | protected: |
| 24 | UniqueSampler CreateSampler(const Tegra::Texture::TSCEntry& tsc) const; | ||
| 48 | 25 | ||
| 49 | private: | 26 | vk::Sampler ToSamplerType(const UniqueSampler& sampler) const; |
| 50 | UniqueSampler CreateSampler(const Tegra::Texture::TSCEntry& tsc); | ||
| 51 | 27 | ||
| 28 | private: | ||
| 52 | const VKDevice& device; | 29 | const VKDevice& device; |
| 53 | std::unordered_map<SamplerCacheKey, UniqueSampler> cache; | ||
| 54 | }; | 30 | }; |
| 55 | 31 | ||
| 56 | } // namespace Vulkan | 32 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index e0a6f5e87..23d9b10db 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -76,14 +76,10 @@ constexpr u32 GetGenericAttributeLocation(Attribute::Index attribute) { | |||
| 76 | 76 | ||
| 77 | /// Returns true if an object has to be treated as precise | 77 | /// Returns true if an object has to be treated as precise |
| 78 | bool IsPrecise(Operation operand) { | 78 | bool IsPrecise(Operation operand) { |
| 79 | const auto& meta = operand.GetMeta(); | 79 | const auto& meta{operand.GetMeta()}; |
| 80 | |||
| 81 | if (std::holds_alternative<MetaArithmetic>(meta)) { | 80 | if (std::holds_alternative<MetaArithmetic>(meta)) { |
| 82 | return std::get<MetaArithmetic>(meta).precise; | 81 | return std::get<MetaArithmetic>(meta).precise; |
| 83 | } | 82 | } |
| 84 | if (std::holds_alternative<MetaHalfArithmetic>(meta)) { | ||
| 85 | return std::get<MetaHalfArithmetic>(meta).precise; | ||
| 86 | } | ||
| 87 | return false; | 83 | return false; |
| 88 | } | 84 | } |
| 89 | 85 | ||
| @@ -191,8 +187,9 @@ public: | |||
| 191 | for (const auto& cbuf : ir.GetConstantBuffers()) { | 187 | for (const auto& cbuf : ir.GetConstantBuffers()) { |
| 192 | entries.const_buffers.emplace_back(cbuf.second, cbuf.first); | 188 | entries.const_buffers.emplace_back(cbuf.second, cbuf.first); |
| 193 | } | 189 | } |
| 194 | for (const auto& gmem : ir.GetGlobalMemoryBases()) { | 190 | for (const auto& gmem_pair : ir.GetGlobalMemory()) { |
| 195 | entries.global_buffers.emplace_back(gmem.cbuf_index, gmem.cbuf_offset); | 191 | const auto& [base, usage] = gmem_pair; |
| 192 | entries.global_buffers.emplace_back(base.cbuf_index, base.cbuf_offset); | ||
| 196 | } | 193 | } |
| 197 | for (const auto& sampler : ir.GetSamplers()) { | 194 | for (const auto& sampler : ir.GetSamplers()) { |
| 198 | entries.samplers.emplace_back(sampler); | 195 | entries.samplers.emplace_back(sampler); |
| @@ -225,7 +222,7 @@ private: | |||
| 225 | return current_binding; | 222 | return current_binding; |
| 226 | }; | 223 | }; |
| 227 | const_buffers_base_binding = Allocate(ir.GetConstantBuffers().size()); | 224 | const_buffers_base_binding = Allocate(ir.GetConstantBuffers().size()); |
| 228 | global_buffers_base_binding = Allocate(ir.GetGlobalMemoryBases().size()); | 225 | global_buffers_base_binding = Allocate(ir.GetGlobalMemory().size()); |
| 229 | samplers_base_binding = Allocate(ir.GetSamplers().size()); | 226 | samplers_base_binding = Allocate(ir.GetSamplers().size()); |
| 230 | 227 | ||
| 231 | ASSERT_MSG(binding_iterator - binding_base < STAGE_BINDING_STRIDE, | 228 | ASSERT_MSG(binding_iterator - binding_base < STAGE_BINDING_STRIDE, |
| @@ -390,14 +387,15 @@ private: | |||
| 390 | 387 | ||
| 391 | void DeclareGlobalBuffers() { | 388 | void DeclareGlobalBuffers() { |
| 392 | u32 binding = global_buffers_base_binding; | 389 | u32 binding = global_buffers_base_binding; |
| 393 | for (const auto& entry : ir.GetGlobalMemoryBases()) { | 390 | for (const auto& entry : ir.GetGlobalMemory()) { |
| 391 | const auto [base, usage] = entry; | ||
| 394 | const Id id = OpVariable(t_gmem_ssbo, spv::StorageClass::StorageBuffer); | 392 | const Id id = OpVariable(t_gmem_ssbo, spv::StorageClass::StorageBuffer); |
| 395 | AddGlobalVariable( | 393 | AddGlobalVariable( |
| 396 | Name(id, fmt::format("gmem_{}_{}", entry.cbuf_index, entry.cbuf_offset))); | 394 | Name(id, fmt::format("gmem_{}_{}", base.cbuf_index, base.cbuf_offset))); |
| 397 | 395 | ||
| 398 | Decorate(id, spv::Decoration::Binding, binding++); | 396 | Decorate(id, spv::Decoration::Binding, binding++); |
| 399 | Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET); | 397 | Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET); |
| 400 | global_buffers.emplace(entry, id); | 398 | global_buffers.emplace(base, id); |
| 401 | } | 399 | } |
| 402 | } | 400 | } |
| 403 | 401 | ||
| @@ -744,6 +742,16 @@ private: | |||
| 744 | return {}; | 742 | return {}; |
| 745 | } | 743 | } |
| 746 | 744 | ||
| 745 | Id HClamp(Operation operation) { | ||
| 746 | UNIMPLEMENTED(); | ||
| 747 | return {}; | ||
| 748 | } | ||
| 749 | |||
| 750 | Id HUnpack(Operation operation) { | ||
| 751 | UNIMPLEMENTED(); | ||
| 752 | return {}; | ||
| 753 | } | ||
| 754 | |||
| 747 | Id HMergeF32(Operation operation) { | 755 | Id HMergeF32(Operation operation) { |
| 748 | UNIMPLEMENTED(); | 756 | UNIMPLEMENTED(); |
| 749 | return {}; | 757 | return {}; |
| @@ -1216,6 +1224,8 @@ private: | |||
| 1216 | &SPIRVDecompiler::Ternary<&Module::OpFma, Type::HalfFloat>, | 1224 | &SPIRVDecompiler::Ternary<&Module::OpFma, Type::HalfFloat>, |
| 1217 | &SPIRVDecompiler::Unary<&Module::OpFAbs, Type::HalfFloat>, | 1225 | &SPIRVDecompiler::Unary<&Module::OpFAbs, Type::HalfFloat>, |
| 1218 | &SPIRVDecompiler::HNegate, | 1226 | &SPIRVDecompiler::HNegate, |
| 1227 | &SPIRVDecompiler::HClamp, | ||
| 1228 | &SPIRVDecompiler::HUnpack, | ||
| 1219 | &SPIRVDecompiler::HMergeF32, | 1229 | &SPIRVDecompiler::HMergeF32, |
| 1220 | &SPIRVDecompiler::HMergeH0, | 1230 | &SPIRVDecompiler::HMergeH0, |
| 1221 | &SPIRVDecompiler::HMergeH1, | 1231 | &SPIRVDecompiler::HMergeH1, |
| @@ -1258,6 +1268,13 @@ private: | |||
| 1258 | &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThan, Type::Bool, Type::HalfFloat>, | 1268 | &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThan, Type::Bool, Type::HalfFloat>, |
| 1259 | &SPIRVDecompiler::Binary<&Module::OpFOrdNotEqual, Type::Bool, Type::HalfFloat>, | 1269 | &SPIRVDecompiler::Binary<&Module::OpFOrdNotEqual, Type::Bool, Type::HalfFloat>, |
| 1260 | &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThanEqual, Type::Bool, Type::HalfFloat>, | 1270 | &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThanEqual, Type::Bool, Type::HalfFloat>, |
| 1271 | // TODO(Rodrigo): Should these use the OpFUnord* variants? | ||
| 1272 | &SPIRVDecompiler::Binary<&Module::OpFOrdLessThan, Type::Bool, Type::HalfFloat>, | ||
| 1273 | &SPIRVDecompiler::Binary<&Module::OpFOrdEqual, Type::Bool, Type::HalfFloat>, | ||
| 1274 | &SPIRVDecompiler::Binary<&Module::OpFOrdLessThanEqual, Type::Bool, Type::HalfFloat>, | ||
| 1275 | &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThan, Type::Bool, Type::HalfFloat>, | ||
| 1276 | &SPIRVDecompiler::Binary<&Module::OpFOrdNotEqual, Type::Bool, Type::HalfFloat>, | ||
| 1277 | &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThanEqual, Type::Bool, Type::HalfFloat>, | ||
| 1261 | 1278 | ||
| 1262 | &SPIRVDecompiler::Texture, | 1279 | &SPIRVDecompiler::Texture, |
| 1263 | &SPIRVDecompiler::TextureLod, | 1280 | &SPIRVDecompiler::TextureLod, |
diff --git a/src/video_core/sampler_cache.cpp b/src/video_core/sampler_cache.cpp new file mode 100644 index 000000000..53c7ef12d --- /dev/null +++ b/src/video_core/sampler_cache.cpp | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/cityhash.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "video_core/sampler_cache.h" | ||
| 8 | |||
| 9 | namespace VideoCommon { | ||
| 10 | |||
| 11 | std::size_t SamplerCacheKey::Hash() const { | ||
| 12 | static_assert(sizeof(raw) % sizeof(u64) == 0); | ||
| 13 | return static_cast<std::size_t>( | ||
| 14 | Common::CityHash64(reinterpret_cast<const char*>(raw.data()), sizeof(raw) / sizeof(u64))); | ||
| 15 | } | ||
| 16 | |||
| 17 | bool SamplerCacheKey::operator==(const SamplerCacheKey& rhs) const { | ||
| 18 | return raw == rhs.raw; | ||
| 19 | } | ||
| 20 | |||
| 21 | } // namespace VideoCommon | ||
diff --git a/src/video_core/sampler_cache.h b/src/video_core/sampler_cache.h new file mode 100644 index 000000000..cbe3ad071 --- /dev/null +++ b/src/video_core/sampler_cache.h | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <cstddef> | ||
| 8 | #include <unordered_map> | ||
| 9 | |||
| 10 | #include "video_core/textures/texture.h" | ||
| 11 | |||
| 12 | namespace VideoCommon { | ||
| 13 | |||
| 14 | struct SamplerCacheKey final : public Tegra::Texture::TSCEntry { | ||
| 15 | std::size_t Hash() const; | ||
| 16 | |||
| 17 | bool operator==(const SamplerCacheKey& rhs) const; | ||
| 18 | |||
| 19 | bool operator!=(const SamplerCacheKey& rhs) const { | ||
| 20 | return !operator==(rhs); | ||
| 21 | } | ||
| 22 | }; | ||
| 23 | |||
| 24 | } // namespace VideoCommon | ||
| 25 | |||
| 26 | namespace std { | ||
| 27 | |||
| 28 | template <> | ||
| 29 | struct hash<VideoCommon::SamplerCacheKey> { | ||
| 30 | std::size_t operator()(const VideoCommon::SamplerCacheKey& k) const noexcept { | ||
| 31 | return k.Hash(); | ||
| 32 | } | ||
| 33 | }; | ||
| 34 | |||
| 35 | } // namespace std | ||
| 36 | |||
| 37 | namespace VideoCommon { | ||
| 38 | |||
| 39 | template <typename SamplerType, typename SamplerStorageType> | ||
| 40 | class SamplerCache { | ||
| 41 | public: | ||
| 42 | SamplerType GetSampler(const Tegra::Texture::TSCEntry& tsc) { | ||
| 43 | const auto [entry, is_cache_miss] = cache.try_emplace(SamplerCacheKey{tsc}); | ||
| 44 | auto& sampler = entry->second; | ||
| 45 | if (is_cache_miss) { | ||
| 46 | sampler = CreateSampler(tsc); | ||
| 47 | } | ||
| 48 | return ToSamplerType(sampler); | ||
| 49 | } | ||
| 50 | |||
| 51 | protected: | ||
| 52 | virtual SamplerStorageType CreateSampler(const Tegra::Texture::TSCEntry& tsc) const = 0; | ||
| 53 | |||
| 54 | virtual SamplerType ToSamplerType(const SamplerStorageType& sampler) const = 0; | ||
| 55 | |||
| 56 | private: | ||
| 57 | std::unordered_map<SamplerCacheKey, SamplerStorageType> cache; | ||
| 58 | }; | ||
| 59 | |||
| 60 | } // namespace VideoCommon \ No newline at end of file | ||
diff --git a/src/video_core/shader/decode/arithmetic_half.cpp b/src/video_core/shader/decode/arithmetic_half.cpp index baee89107..2098c1170 100644 --- a/src/video_core/shader/decode/arithmetic_half.cpp +++ b/src/video_core/shader/decode/arithmetic_half.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | namespace VideoCommon::Shader { | 10 | namespace VideoCommon::Shader { |
| 11 | 11 | ||
| 12 | using Tegra::Shader::HalfType; | ||
| 12 | using Tegra::Shader::Instruction; | 13 | using Tegra::Shader::Instruction; |
| 13 | using Tegra::Shader::OpCode; | 14 | using Tegra::Shader::OpCode; |
| 14 | 15 | ||
| @@ -18,48 +19,50 @@ u32 ShaderIR::DecodeArithmeticHalf(NodeBlock& bb, u32 pc) { | |||
| 18 | 19 | ||
| 19 | if (opcode->get().GetId() == OpCode::Id::HADD2_C || | 20 | if (opcode->get().GetId() == OpCode::Id::HADD2_C || |
| 20 | opcode->get().GetId() == OpCode::Id::HADD2_R) { | 21 | opcode->get().GetId() == OpCode::Id::HADD2_R) { |
| 21 | UNIMPLEMENTED_IF(instr.alu_half.ftz != 0); | 22 | if (instr.alu_half.ftz != 0) { |
| 23 | LOG_WARNING(HW_GPU, "{} FTZ not implemented", opcode->get().GetName()); | ||
| 24 | } | ||
| 22 | } | 25 | } |
| 23 | UNIMPLEMENTED_IF_MSG(instr.alu_half.saturate != 0, "Half float saturation not implemented"); | ||
| 24 | 26 | ||
| 25 | const bool negate_a = | 27 | const bool negate_a = |
| 26 | opcode->get().GetId() != OpCode::Id::HMUL2_R && instr.alu_half.negate_a != 0; | 28 | opcode->get().GetId() != OpCode::Id::HMUL2_R && instr.alu_half.negate_a != 0; |
| 27 | const bool negate_b = | 29 | const bool negate_b = |
| 28 | opcode->get().GetId() != OpCode::Id::HMUL2_C && instr.alu_half.negate_b != 0; | 30 | opcode->get().GetId() != OpCode::Id::HMUL2_C && instr.alu_half.negate_b != 0; |
| 29 | 31 | ||
| 30 | const Node op_a = GetOperandAbsNegHalf(GetRegister(instr.gpr8), instr.alu_half.abs_a, negate_a); | 32 | Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.alu_half.type_a); |
| 31 | 33 | op_a = GetOperandAbsNegHalf(op_a, instr.alu_half.abs_a, negate_a); | |
| 32 | // instr.alu_half.type_a | ||
| 33 | 34 | ||
| 34 | Node op_b = [&]() { | 35 | auto [type_b, op_b] = [&]() -> std::tuple<HalfType, Node> { |
| 35 | switch (opcode->get().GetId()) { | 36 | switch (opcode->get().GetId()) { |
| 36 | case OpCode::Id::HADD2_C: | 37 | case OpCode::Id::HADD2_C: |
| 37 | case OpCode::Id::HMUL2_C: | 38 | case OpCode::Id::HMUL2_C: |
| 38 | return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()); | 39 | return {HalfType::F32, GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset())}; |
| 39 | case OpCode::Id::HADD2_R: | 40 | case OpCode::Id::HADD2_R: |
| 40 | case OpCode::Id::HMUL2_R: | 41 | case OpCode::Id::HMUL2_R: |
| 41 | return GetRegister(instr.gpr20); | 42 | return {instr.alu_half.type_b, GetRegister(instr.gpr20)}; |
| 42 | default: | 43 | default: |
| 43 | UNREACHABLE(); | 44 | UNREACHABLE(); |
| 44 | return Immediate(0); | 45 | return {HalfType::F32, Immediate(0)}; |
| 45 | } | 46 | } |
| 46 | }(); | 47 | }(); |
| 47 | op_b = GetOperandAbsNegHalf(op_b, instr.alu_half.abs_b, negate_b); | 48 | op_b = UnpackHalfFloat(op_b, type_b); |
| 49 | // redeclaration to avoid a bug in clang with reusing local bindings in lambdas | ||
| 50 | Node op_b_alt = GetOperandAbsNegHalf(op_b, instr.alu_half.abs_b, negate_b); | ||
| 48 | 51 | ||
| 49 | Node value = [&]() { | 52 | Node value = [&]() { |
| 50 | MetaHalfArithmetic meta{true, {instr.alu_half_imm.type_a, instr.alu_half.type_b}}; | ||
| 51 | switch (opcode->get().GetId()) { | 53 | switch (opcode->get().GetId()) { |
| 52 | case OpCode::Id::HADD2_C: | 54 | case OpCode::Id::HADD2_C: |
| 53 | case OpCode::Id::HADD2_R: | 55 | case OpCode::Id::HADD2_R: |
| 54 | return Operation(OperationCode::HAdd, meta, op_a, op_b); | 56 | return Operation(OperationCode::HAdd, PRECISE, op_a, op_b_alt); |
| 55 | case OpCode::Id::HMUL2_C: | 57 | case OpCode::Id::HMUL2_C: |
| 56 | case OpCode::Id::HMUL2_R: | 58 | case OpCode::Id::HMUL2_R: |
| 57 | return Operation(OperationCode::HMul, meta, op_a, op_b); | 59 | return Operation(OperationCode::HMul, PRECISE, op_a, op_b_alt); |
| 58 | default: | 60 | default: |
| 59 | UNIMPLEMENTED_MSG("Unhandled half float instruction: {}", opcode->get().GetName()); | 61 | UNIMPLEMENTED_MSG("Unhandled half float instruction: {}", opcode->get().GetName()); |
| 60 | return Immediate(0); | 62 | return Immediate(0); |
| 61 | } | 63 | } |
| 62 | }(); | 64 | }(); |
| 65 | value = GetSaturatedHalfFloat(value, instr.alu_half.saturate); | ||
| 63 | value = HalfMerge(GetRegister(instr.gpr0), value, instr.alu_half.merge); | 66 | value = HalfMerge(GetRegister(instr.gpr0), value, instr.alu_half.merge); |
| 64 | 67 | ||
| 65 | SetRegister(bb, instr.gpr0, value); | 68 | SetRegister(bb, instr.gpr0, value); |
| @@ -67,4 +70,4 @@ u32 ShaderIR::DecodeArithmeticHalf(NodeBlock& bb, u32 pc) { | |||
| 67 | return pc; | 70 | return pc; |
| 68 | } | 71 | } |
| 69 | 72 | ||
| 70 | } // namespace VideoCommon::Shader \ No newline at end of file | 73 | } // namespace VideoCommon::Shader |
diff --git a/src/video_core/shader/decode/arithmetic_half_immediate.cpp b/src/video_core/shader/decode/arithmetic_half_immediate.cpp index c2164ba50..fbcd35b18 100644 --- a/src/video_core/shader/decode/arithmetic_half_immediate.cpp +++ b/src/video_core/shader/decode/arithmetic_half_immediate.cpp | |||
| @@ -17,34 +17,33 @@ u32 ShaderIR::DecodeArithmeticHalfImmediate(NodeBlock& bb, u32 pc) { | |||
| 17 | const auto opcode = OpCode::Decode(instr); | 17 | const auto opcode = OpCode::Decode(instr); |
| 18 | 18 | ||
| 19 | if (opcode->get().GetId() == OpCode::Id::HADD2_IMM) { | 19 | if (opcode->get().GetId() == OpCode::Id::HADD2_IMM) { |
| 20 | UNIMPLEMENTED_IF(instr.alu_half_imm.ftz != 0); | 20 | if (instr.alu_half_imm.ftz != 0) { |
| 21 | LOG_WARNING(HW_GPU, "{} FTZ not implemented", opcode->get().GetName()); | ||
| 22 | } | ||
| 21 | } else { | 23 | } else { |
| 22 | UNIMPLEMENTED_IF(instr.alu_half_imm.precision != Tegra::Shader::HalfPrecision::None); | 24 | UNIMPLEMENTED_IF(instr.alu_half_imm.precision != Tegra::Shader::HalfPrecision::None); |
| 23 | } | 25 | } |
| 24 | UNIMPLEMENTED_IF_MSG(instr.alu_half_imm.saturate != 0, | ||
| 25 | "Half float immediate saturation not implemented"); | ||
| 26 | 26 | ||
| 27 | Node op_a = GetRegister(instr.gpr8); | 27 | Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.alu_half_imm.type_a); |
| 28 | op_a = GetOperandAbsNegHalf(op_a, instr.alu_half_imm.abs_a, instr.alu_half_imm.negate_a); | 28 | op_a = GetOperandAbsNegHalf(op_a, instr.alu_half_imm.abs_a, instr.alu_half_imm.negate_a); |
| 29 | 29 | ||
| 30 | const Node op_b = UnpackHalfImmediate(instr, true); | 30 | const Node op_b = UnpackHalfImmediate(instr, true); |
| 31 | 31 | ||
| 32 | Node value = [&]() { | 32 | Node value = [&]() { |
| 33 | MetaHalfArithmetic meta{true, {instr.alu_half_imm.type_a}}; | ||
| 34 | switch (opcode->get().GetId()) { | 33 | switch (opcode->get().GetId()) { |
| 35 | case OpCode::Id::HADD2_IMM: | 34 | case OpCode::Id::HADD2_IMM: |
| 36 | return Operation(OperationCode::HAdd, meta, op_a, op_b); | 35 | return Operation(OperationCode::HAdd, PRECISE, op_a, op_b); |
| 37 | case OpCode::Id::HMUL2_IMM: | 36 | case OpCode::Id::HMUL2_IMM: |
| 38 | return Operation(OperationCode::HMul, meta, op_a, op_b); | 37 | return Operation(OperationCode::HMul, PRECISE, op_a, op_b); |
| 39 | default: | 38 | default: |
| 40 | UNREACHABLE(); | 39 | UNREACHABLE(); |
| 41 | return Immediate(0); | 40 | return Immediate(0); |
| 42 | } | 41 | } |
| 43 | }(); | 42 | }(); |
| 44 | value = HalfMerge(GetRegister(instr.gpr0), value, instr.alu_half_imm.merge); | ||
| 45 | 43 | ||
| 44 | value = GetSaturatedHalfFloat(value, instr.alu_half_imm.saturate); | ||
| 45 | value = HalfMerge(GetRegister(instr.gpr0), value, instr.alu_half_imm.merge); | ||
| 46 | SetRegister(bb, instr.gpr0, value); | 46 | SetRegister(bb, instr.gpr0, value); |
| 47 | |||
| 48 | return pc; | 47 | return pc; |
| 49 | } | 48 | } |
| 50 | 49 | ||
diff --git a/src/video_core/shader/decode/conversion.cpp b/src/video_core/shader/decode/conversion.cpp index da26489a0..b5ec9a6f5 100644 --- a/src/video_core/shader/decode/conversion.cpp +++ b/src/video_core/shader/decode/conversion.cpp | |||
| @@ -18,13 +18,29 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) { | |||
| 18 | const auto opcode = OpCode::Decode(instr); | 18 | const auto opcode = OpCode::Decode(instr); |
| 19 | 19 | ||
| 20 | switch (opcode->get().GetId()) { | 20 | switch (opcode->get().GetId()) { |
| 21 | case OpCode::Id::I2I_R: { | 21 | case OpCode::Id::I2I_R: |
| 22 | case OpCode::Id::I2I_C: | ||
| 23 | case OpCode::Id::I2I_IMM: { | ||
| 22 | UNIMPLEMENTED_IF(instr.conversion.selector); | 24 | UNIMPLEMENTED_IF(instr.conversion.selector); |
| 25 | UNIMPLEMENTED_IF(instr.conversion.dst_size != Register::Size::Word); | ||
| 26 | UNIMPLEMENTED_IF(instr.alu.saturate_d); | ||
| 23 | 27 | ||
| 24 | const bool input_signed = instr.conversion.is_input_signed; | 28 | const bool input_signed = instr.conversion.is_input_signed; |
| 25 | const bool output_signed = instr.conversion.is_output_signed; | 29 | const bool output_signed = instr.conversion.is_output_signed; |
| 26 | 30 | ||
| 27 | Node value = GetRegister(instr.gpr20); | 31 | Node value = [&]() { |
| 32 | switch (opcode->get().GetId()) { | ||
| 33 | case OpCode::Id::I2I_R: | ||
| 34 | return GetRegister(instr.gpr20); | ||
| 35 | case OpCode::Id::I2I_C: | ||
| 36 | return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()); | ||
| 37 | case OpCode::Id::I2I_IMM: | ||
| 38 | return Immediate(instr.alu.GetSignedImm20_20()); | ||
| 39 | default: | ||
| 40 | UNREACHABLE(); | ||
| 41 | return Immediate(0); | ||
| 42 | } | ||
| 43 | }(); | ||
| 28 | value = ConvertIntegerSize(value, instr.conversion.src_size, input_signed); | 44 | value = ConvertIntegerSize(value, instr.conversion.src_size, input_signed); |
| 29 | 45 | ||
| 30 | value = GetOperandAbsNegInteger(value, instr.conversion.abs_a, instr.conversion.negate_a, | 46 | value = GetOperandAbsNegInteger(value, instr.conversion.abs_a, instr.conversion.negate_a, |
| @@ -38,17 +54,24 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) { | |||
| 38 | break; | 54 | break; |
| 39 | } | 55 | } |
| 40 | case OpCode::Id::I2F_R: | 56 | case OpCode::Id::I2F_R: |
| 41 | case OpCode::Id::I2F_C: { | 57 | case OpCode::Id::I2F_C: |
| 42 | UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word); | 58 | case OpCode::Id::I2F_IMM: { |
| 59 | UNIMPLEMENTED_IF(instr.conversion.dst_size != Register::Size::Word); | ||
| 43 | UNIMPLEMENTED_IF(instr.conversion.selector); | 60 | UNIMPLEMENTED_IF(instr.conversion.selector); |
| 44 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | 61 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 45 | "Condition codes generation in I2F is not implemented"); | 62 | "Condition codes generation in I2F is not implemented"); |
| 46 | 63 | ||
| 47 | Node value = [&]() { | 64 | Node value = [&]() { |
| 48 | if (instr.is_b_gpr) { | 65 | switch (opcode->get().GetId()) { |
| 66 | case OpCode::Id::I2F_R: | ||
| 49 | return GetRegister(instr.gpr20); | 67 | return GetRegister(instr.gpr20); |
| 50 | } else { | 68 | case OpCode::Id::I2F_C: |
| 51 | return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()); | 69 | return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()); |
| 70 | case OpCode::Id::I2F_IMM: | ||
| 71 | return Immediate(instr.alu.GetSignedImm20_20()); | ||
| 72 | default: | ||
| 73 | UNREACHABLE(); | ||
| 74 | return Immediate(0); | ||
| 52 | } | 75 | } |
| 53 | }(); | 76 | }(); |
| 54 | const bool input_signed = instr.conversion.is_input_signed; | 77 | const bool input_signed = instr.conversion.is_input_signed; |
| @@ -62,24 +85,31 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) { | |||
| 62 | break; | 85 | break; |
| 63 | } | 86 | } |
| 64 | case OpCode::Id::F2F_R: | 87 | case OpCode::Id::F2F_R: |
| 65 | case OpCode::Id::F2F_C: { | 88 | case OpCode::Id::F2F_C: |
| 66 | UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word); | 89 | case OpCode::Id::F2F_IMM: { |
| 67 | UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); | 90 | UNIMPLEMENTED_IF(instr.conversion.f2f.dst_size != Register::Size::Word); |
| 91 | UNIMPLEMENTED_IF(instr.conversion.f2f.src_size != Register::Size::Word); | ||
| 68 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | 92 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 69 | "Condition codes generation in F2F is not implemented"); | 93 | "Condition codes generation in F2F is not implemented"); |
| 70 | 94 | ||
| 71 | Node value = [&]() { | 95 | Node value = [&]() { |
| 72 | if (instr.is_b_gpr) { | 96 | switch (opcode->get().GetId()) { |
| 97 | case OpCode::Id::F2F_R: | ||
| 73 | return GetRegister(instr.gpr20); | 98 | return GetRegister(instr.gpr20); |
| 74 | } else { | 99 | case OpCode::Id::F2F_C: |
| 75 | return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()); | 100 | return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()); |
| 101 | case OpCode::Id::F2F_IMM: | ||
| 102 | return GetImmediate19(instr); | ||
| 103 | default: | ||
| 104 | UNREACHABLE(); | ||
| 105 | return Immediate(0); | ||
| 76 | } | 106 | } |
| 77 | }(); | 107 | }(); |
| 78 | 108 | ||
| 79 | value = GetOperandAbsNegFloat(value, instr.conversion.abs_a, instr.conversion.negate_a); | 109 | value = GetOperandAbsNegFloat(value, instr.conversion.abs_a, instr.conversion.negate_a); |
| 80 | 110 | ||
| 81 | value = [&]() { | 111 | value = [&]() { |
| 82 | switch (instr.conversion.f2f.rounding) { | 112 | switch (instr.conversion.f2f.GetRoundingMode()) { |
| 83 | case Tegra::Shader::F2fRoundingOp::None: | 113 | case Tegra::Shader::F2fRoundingOp::None: |
| 84 | return value; | 114 | return value; |
| 85 | case Tegra::Shader::F2fRoundingOp::Round: | 115 | case Tegra::Shader::F2fRoundingOp::Round: |
| @@ -103,15 +133,22 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) { | |||
| 103 | break; | 133 | break; |
| 104 | } | 134 | } |
| 105 | case OpCode::Id::F2I_R: | 135 | case OpCode::Id::F2I_R: |
| 106 | case OpCode::Id::F2I_C: { | 136 | case OpCode::Id::F2I_C: |
| 137 | case OpCode::Id::F2I_IMM: { | ||
| 107 | UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); | 138 | UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); |
| 108 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | 139 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 109 | "Condition codes generation in F2I is not implemented"); | 140 | "Condition codes generation in F2I is not implemented"); |
| 110 | Node value = [&]() { | 141 | Node value = [&]() { |
| 111 | if (instr.is_b_gpr) { | 142 | switch (opcode->get().GetId()) { |
| 143 | case OpCode::Id::F2I_R: | ||
| 112 | return GetRegister(instr.gpr20); | 144 | return GetRegister(instr.gpr20); |
| 113 | } else { | 145 | case OpCode::Id::F2I_C: |
| 114 | return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()); | 146 | return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()); |
| 147 | case OpCode::Id::F2I_IMM: | ||
| 148 | return GetImmediate19(instr); | ||
| 149 | default: | ||
| 150 | UNREACHABLE(); | ||
| 151 | return Immediate(0); | ||
| 115 | } | 152 | } |
| 116 | }(); | 153 | }(); |
| 117 | 154 | ||
| @@ -135,7 +172,7 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) { | |||
| 135 | }(); | 172 | }(); |
| 136 | const bool is_signed = instr.conversion.is_output_signed; | 173 | const bool is_signed = instr.conversion.is_output_signed; |
| 137 | value = SignedOperation(OperationCode::ICastFloat, is_signed, PRECISE, value); | 174 | value = SignedOperation(OperationCode::ICastFloat, is_signed, PRECISE, value); |
| 138 | value = ConvertIntegerSize(value, instr.conversion.dest_size, is_signed); | 175 | value = ConvertIntegerSize(value, instr.conversion.dst_size, is_signed); |
| 139 | 176 | ||
| 140 | SetRegister(bb, instr.gpr0, value); | 177 | SetRegister(bb, instr.gpr0, value); |
| 141 | break; | 178 | break; |
diff --git a/src/video_core/shader/decode/half_set.cpp b/src/video_core/shader/decode/half_set.cpp index 748368555..1dd94bf9d 100644 --- a/src/video_core/shader/decode/half_set.cpp +++ b/src/video_core/shader/decode/half_set.cpp | |||
| @@ -18,11 +18,13 @@ u32 ShaderIR::DecodeHalfSet(NodeBlock& bb, u32 pc) { | |||
| 18 | const Instruction instr = {program_code[pc]}; | 18 | const Instruction instr = {program_code[pc]}; |
| 19 | const auto opcode = OpCode::Decode(instr); | 19 | const auto opcode = OpCode::Decode(instr); |
| 20 | 20 | ||
| 21 | UNIMPLEMENTED_IF(instr.hset2.ftz != 0); | 21 | if (instr.hset2.ftz != 0) { |
| 22 | LOG_WARNING(HW_GPU, "{} FTZ not implemented", opcode->get().GetName()); | ||
| 23 | } | ||
| 24 | |||
| 25 | Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.hset2.type_a); | ||
| 26 | op_a = GetOperandAbsNegHalf(op_a, instr.hset2.abs_a, instr.hset2.negate_a); | ||
| 22 | 27 | ||
| 23 | // instr.hset2.type_a | ||
| 24 | // instr.hset2.type_b | ||
| 25 | Node op_a = GetRegister(instr.gpr8); | ||
| 26 | Node op_b = [&]() { | 28 | Node op_b = [&]() { |
| 27 | switch (opcode->get().GetId()) { | 29 | switch (opcode->get().GetId()) { |
| 28 | case OpCode::Id::HSET2_R: | 30 | case OpCode::Id::HSET2_R: |
| @@ -32,14 +34,12 @@ u32 ShaderIR::DecodeHalfSet(NodeBlock& bb, u32 pc) { | |||
| 32 | return Immediate(0); | 34 | return Immediate(0); |
| 33 | } | 35 | } |
| 34 | }(); | 36 | }(); |
| 35 | 37 | op_b = UnpackHalfFloat(op_b, instr.hset2.type_b); | |
| 36 | op_a = GetOperandAbsNegHalf(op_a, instr.hset2.abs_a, instr.hset2.negate_a); | ||
| 37 | op_b = GetOperandAbsNegHalf(op_b, instr.hset2.abs_b, instr.hset2.negate_b); | 38 | op_b = GetOperandAbsNegHalf(op_b, instr.hset2.abs_b, instr.hset2.negate_b); |
| 38 | 39 | ||
| 39 | const Node second_pred = GetPredicate(instr.hset2.pred39, instr.hset2.neg_pred); | 40 | const Node second_pred = GetPredicate(instr.hset2.pred39, instr.hset2.neg_pred); |
| 40 | 41 | ||
| 41 | MetaHalfArithmetic meta{false, {instr.hset2.type_a, instr.hset2.type_b}}; | 42 | const Node comparison_pair = GetPredicateComparisonHalf(instr.hset2.cond, op_a, op_b); |
| 42 | const Node comparison_pair = GetPredicateComparisonHalf(instr.hset2.cond, meta, op_a, op_b); | ||
| 43 | 43 | ||
| 44 | const OperationCode combiner = GetPredicateCombiner(instr.hset2.op); | 44 | const OperationCode combiner = GetPredicateCombiner(instr.hset2.op); |
| 45 | 45 | ||
diff --git a/src/video_core/shader/decode/half_set_predicate.cpp b/src/video_core/shader/decode/half_set_predicate.cpp index e68512692..6e59eb650 100644 --- a/src/video_core/shader/decode/half_set_predicate.cpp +++ b/src/video_core/shader/decode/half_set_predicate.cpp | |||
| @@ -19,10 +19,10 @@ u32 ShaderIR::DecodeHalfSetPredicate(NodeBlock& bb, u32 pc) { | |||
| 19 | 19 | ||
| 20 | UNIMPLEMENTED_IF(instr.hsetp2.ftz != 0); | 20 | UNIMPLEMENTED_IF(instr.hsetp2.ftz != 0); |
| 21 | 21 | ||
| 22 | Node op_a = GetRegister(instr.gpr8); | 22 | Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.hsetp2.type_a); |
| 23 | op_a = GetOperandAbsNegHalf(op_a, instr.hsetp2.abs_a, instr.hsetp2.negate_a); | 23 | op_a = GetOperandAbsNegHalf(op_a, instr.hsetp2.abs_a, instr.hsetp2.negate_a); |
| 24 | 24 | ||
| 25 | const Node op_b = [&]() { | 25 | Node op_b = [&]() { |
| 26 | switch (opcode->get().GetId()) { | 26 | switch (opcode->get().GetId()) { |
| 27 | case OpCode::Id::HSETP2_R: | 27 | case OpCode::Id::HSETP2_R: |
| 28 | return GetOperandAbsNegHalf(GetRegister(instr.gpr20), instr.hsetp2.abs_a, | 28 | return GetOperandAbsNegHalf(GetRegister(instr.gpr20), instr.hsetp2.abs_a, |
| @@ -32,6 +32,7 @@ u32 ShaderIR::DecodeHalfSetPredicate(NodeBlock& bb, u32 pc) { | |||
| 32 | return Immediate(0); | 32 | return Immediate(0); |
| 33 | } | 33 | } |
| 34 | }(); | 34 | }(); |
| 35 | op_b = UnpackHalfFloat(op_b, instr.hsetp2.type_b); | ||
| 35 | 36 | ||
| 36 | // We can't use the constant predicate as destination. | 37 | // We can't use the constant predicate as destination. |
| 37 | ASSERT(instr.hsetp2.pred3 != static_cast<u64>(Pred::UnusedIndex)); | 38 | ASSERT(instr.hsetp2.pred3 != static_cast<u64>(Pred::UnusedIndex)); |
| @@ -42,8 +43,7 @@ u32 ShaderIR::DecodeHalfSetPredicate(NodeBlock& bb, u32 pc) { | |||
| 42 | const OperationCode pair_combiner = | 43 | const OperationCode pair_combiner = |
| 43 | instr.hsetp2.h_and ? OperationCode::LogicalAll2 : OperationCode::LogicalAny2; | 44 | instr.hsetp2.h_and ? OperationCode::LogicalAll2 : OperationCode::LogicalAny2; |
| 44 | 45 | ||
| 45 | MetaHalfArithmetic meta = {false, {instr.hsetp2.type_a, instr.hsetp2.type_b}}; | 46 | const Node comparison = GetPredicateComparisonHalf(instr.hsetp2.cond, op_a, op_b); |
| 46 | const Node comparison = GetPredicateComparisonHalf(instr.hsetp2.cond, meta, op_a, op_b); | ||
| 47 | const Node first_pred = Operation(pair_combiner, comparison); | 47 | const Node first_pred = Operation(pair_combiner, comparison); |
| 48 | 48 | ||
| 49 | // Set the primary predicate to the result of Predicate OP SecondPredicate | 49 | // Set the primary predicate to the result of Predicate OP SecondPredicate |
diff --git a/src/video_core/shader/decode/hfma2.cpp b/src/video_core/shader/decode/hfma2.cpp index 7a07c5ec6..a425f9eb7 100644 --- a/src/video_core/shader/decode/hfma2.cpp +++ b/src/video_core/shader/decode/hfma2.cpp | |||
| @@ -27,10 +27,6 @@ u32 ShaderIR::DecodeHfma2(NodeBlock& bb, u32 pc) { | |||
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | constexpr auto identity = HalfType::H0_H1; | 29 | constexpr auto identity = HalfType::H0_H1; |
| 30 | |||
| 31 | const HalfType type_a = instr.hfma2.type_a; | ||
| 32 | const Node op_a = GetRegister(instr.gpr8); | ||
| 33 | |||
| 34 | bool neg_b{}, neg_c{}; | 30 | bool neg_b{}, neg_c{}; |
| 35 | auto [saturate, type_b, op_b, type_c, | 31 | auto [saturate, type_b, op_b, type_c, |
| 36 | op_c] = [&]() -> std::tuple<bool, HalfType, Node, HalfType, Node> { | 32 | op_c] = [&]() -> std::tuple<bool, HalfType, Node, HalfType, Node> { |
| @@ -38,15 +34,14 @@ u32 ShaderIR::DecodeHfma2(NodeBlock& bb, u32 pc) { | |||
| 38 | case OpCode::Id::HFMA2_CR: | 34 | case OpCode::Id::HFMA2_CR: |
| 39 | neg_b = instr.hfma2.negate_b; | 35 | neg_b = instr.hfma2.negate_b; |
| 40 | neg_c = instr.hfma2.negate_c; | 36 | neg_c = instr.hfma2.negate_c; |
| 41 | return {instr.hfma2.saturate, instr.hfma2.type_b, | 37 | return {instr.hfma2.saturate, HalfType::F32, |
| 42 | GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()), | 38 | GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()), |
| 43 | instr.hfma2.type_reg39, GetRegister(instr.gpr39)}; | 39 | instr.hfma2.type_reg39, GetRegister(instr.gpr39)}; |
| 44 | case OpCode::Id::HFMA2_RC: | 40 | case OpCode::Id::HFMA2_RC: |
| 45 | neg_b = instr.hfma2.negate_b; | 41 | neg_b = instr.hfma2.negate_b; |
| 46 | neg_c = instr.hfma2.negate_c; | 42 | neg_c = instr.hfma2.negate_c; |
| 47 | return {instr.hfma2.saturate, instr.hfma2.type_reg39, GetRegister(instr.gpr39), | 43 | return {instr.hfma2.saturate, instr.hfma2.type_reg39, GetRegister(instr.gpr39), |
| 48 | instr.hfma2.type_b, | 44 | HalfType::F32, GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset())}; |
| 49 | GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset())}; | ||
| 50 | case OpCode::Id::HFMA2_RR: | 45 | case OpCode::Id::HFMA2_RR: |
| 51 | neg_b = instr.hfma2.rr.negate_b; | 46 | neg_b = instr.hfma2.rr.negate_b; |
| 52 | neg_c = instr.hfma2.rr.negate_c; | 47 | neg_c = instr.hfma2.rr.negate_c; |
| @@ -60,13 +55,13 @@ u32 ShaderIR::DecodeHfma2(NodeBlock& bb, u32 pc) { | |||
| 60 | return {false, identity, Immediate(0), identity, Immediate(0)}; | 55 | return {false, identity, Immediate(0), identity, Immediate(0)}; |
| 61 | } | 56 | } |
| 62 | }(); | 57 | }(); |
| 63 | UNIMPLEMENTED_IF_MSG(saturate, "HFMA2 saturation is not implemented"); | ||
| 64 | 58 | ||
| 65 | op_b = GetOperandAbsNegHalf(op_b, false, neg_b); | 59 | const Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.hfma2.type_a); |
| 66 | op_c = GetOperandAbsNegHalf(op_c, false, neg_c); | 60 | op_b = GetOperandAbsNegHalf(UnpackHalfFloat(op_b, type_b), false, neg_b); |
| 61 | op_c = GetOperandAbsNegHalf(UnpackHalfFloat(op_c, type_c), false, neg_c); | ||
| 67 | 62 | ||
| 68 | MetaHalfArithmetic meta{true, {type_a, type_b, type_c}}; | 63 | Node value = Operation(OperationCode::HFma, PRECISE, op_a, op_b, op_c); |
| 69 | Node value = Operation(OperationCode::HFma, meta, op_a, op_b, op_c); | 64 | value = GetSaturatedHalfFloat(value, saturate); |
| 70 | value = HalfMerge(GetRegister(instr.gpr0), value, instr.hfma2.merge); | 65 | value = HalfMerge(GetRegister(instr.gpr0), value, instr.hfma2.merge); |
| 71 | 66 | ||
| 72 | SetRegister(bb, instr.gpr0, value); | 67 | SetRegister(bb, instr.gpr0, value); |
| @@ -74,4 +69,4 @@ u32 ShaderIR::DecodeHfma2(NodeBlock& bb, u32 pc) { | |||
| 74 | return pc; | 69 | return pc; |
| 75 | } | 70 | } |
| 76 | 71 | ||
| 77 | } // namespace VideoCommon::Shader \ No newline at end of file | 72 | } // namespace VideoCommon::Shader |
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp index ea3c71eed..ea1092db1 100644 --- a/src/video_core/shader/decode/memory.cpp +++ b/src/video_core/shader/decode/memory.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | #include "common/assert.h" | 9 | #include "common/assert.h" |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/logging/log.h" | ||
| 11 | #include "video_core/engines/shader_bytecode.h" | 12 | #include "video_core/engines/shader_bytecode.h" |
| 12 | #include "video_core/shader/shader_ir.h" | 13 | #include "video_core/shader/shader_ir.h" |
| 13 | 14 | ||
| @@ -18,6 +19,23 @@ using Tegra::Shader::Instruction; | |||
| 18 | using Tegra::Shader::OpCode; | 19 | using Tegra::Shader::OpCode; |
| 19 | using Tegra::Shader::Register; | 20 | using Tegra::Shader::Register; |
| 20 | 21 | ||
| 22 | namespace { | ||
| 23 | u32 GetUniformTypeElementsCount(Tegra::Shader::UniformType uniform_type) { | ||
| 24 | switch (uniform_type) { | ||
| 25 | case Tegra::Shader::UniformType::Single: | ||
| 26 | return 1; | ||
| 27 | case Tegra::Shader::UniformType::Double: | ||
| 28 | return 2; | ||
| 29 | case Tegra::Shader::UniformType::Quad: | ||
| 30 | case Tegra::Shader::UniformType::UnsignedQuad: | ||
| 31 | return 4; | ||
| 32 | default: | ||
| 33 | UNIMPLEMENTED_MSG("Unimplemented size={}!", static_cast<u32>(uniform_type)); | ||
| 34 | return 1; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } // namespace | ||
| 38 | |||
| 21 | u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | 39 | u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { |
| 22 | const Instruction instr = {program_code[pc]}; | 40 | const Instruction instr = {program_code[pc]}; |
| 23 | const auto opcode = OpCode::Decode(instr); | 41 | const auto opcode = OpCode::Decode(instr); |
| @@ -85,8 +103,8 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 85 | break; | 103 | break; |
| 86 | } | 104 | } |
| 87 | case OpCode::Id::LD_L: { | 105 | case OpCode::Id::LD_L: { |
| 88 | UNIMPLEMENTED_IF_MSG(instr.ld_l.unknown == 1, "LD_L Unhandled mode: {}", | 106 | LOG_DEBUG(HW_GPU, "LD_L cache management mode: {}", |
| 89 | static_cast<u32>(instr.ld_l.unknown.Value())); | 107 | static_cast<u64>(instr.ld_l.unknown.Value())); |
| 90 | 108 | ||
| 91 | const auto GetLmem = [&](s32 offset) { | 109 | const auto GetLmem = [&](s32 offset) { |
| 92 | ASSERT(offset % 4 == 0); | 110 | ASSERT(offset % 4 == 0); |
| @@ -126,45 +144,15 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 126 | break; | 144 | break; |
| 127 | } | 145 | } |
| 128 | case OpCode::Id::LDG: { | 146 | case OpCode::Id::LDG: { |
| 129 | const u32 count = [&]() { | 147 | const auto [real_address_base, base_address, descriptor] = |
| 130 | switch (instr.ldg.type) { | 148 | TrackAndGetGlobalMemory(bb, GetRegister(instr.gpr8), |
| 131 | case Tegra::Shader::UniformType::Single: | 149 | static_cast<u32>(instr.ldg.immediate_offset.Value()), false); |
| 132 | return 1; | ||
| 133 | case Tegra::Shader::UniformType::Double: | ||
| 134 | return 2; | ||
| 135 | case Tegra::Shader::UniformType::Quad: | ||
| 136 | case Tegra::Shader::UniformType::UnsignedQuad: | ||
| 137 | return 4; | ||
| 138 | default: | ||
| 139 | UNIMPLEMENTED_MSG("Unimplemented LDG size!"); | ||
| 140 | return 1; | ||
| 141 | } | ||
| 142 | }(); | ||
| 143 | |||
| 144 | const Node addr_register = GetRegister(instr.gpr8); | ||
| 145 | const Node base_address = | ||
| 146 | TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size())); | ||
| 147 | const auto cbuf = std::get_if<CbufNode>(base_address); | ||
| 148 | ASSERT(cbuf != nullptr); | ||
| 149 | const auto cbuf_offset_imm = std::get_if<ImmediateNode>(cbuf->GetOffset()); | ||
| 150 | ASSERT(cbuf_offset_imm != nullptr); | ||
| 151 | const auto cbuf_offset = cbuf_offset_imm->GetValue(); | ||
| 152 | |||
| 153 | bb.push_back(Comment( | ||
| 154 | fmt::format("Base address is c[0x{:x}][0x{:x}]", cbuf->GetIndex(), cbuf_offset))); | ||
| 155 | |||
| 156 | const GlobalMemoryBase descriptor{cbuf->GetIndex(), cbuf_offset}; | ||
| 157 | used_global_memory_bases.insert(descriptor); | ||
| 158 | |||
| 159 | const Node immediate_offset = | ||
| 160 | Immediate(static_cast<u32>(instr.ldg.immediate_offset.Value())); | ||
| 161 | const Node base_real_address = | ||
| 162 | Operation(OperationCode::UAdd, NO_PRECISE, immediate_offset, addr_register); | ||
| 163 | 150 | ||
| 151 | const u32 count = GetUniformTypeElementsCount(instr.ldg.type); | ||
| 164 | for (u32 i = 0; i < count; ++i) { | 152 | for (u32 i = 0; i < count; ++i) { |
| 165 | const Node it_offset = Immediate(i * 4); | 153 | const Node it_offset = Immediate(i * 4); |
| 166 | const Node real_address = | 154 | const Node real_address = |
| 167 | Operation(OperationCode::UAdd, NO_PRECISE, base_real_address, it_offset); | 155 | Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset); |
| 168 | const Node gmem = StoreNode(GmemNode(real_address, base_address, descriptor)); | 156 | const Node gmem = StoreNode(GmemNode(real_address, base_address, descriptor)); |
| 169 | 157 | ||
| 170 | SetTemporal(bb, i, gmem); | 158 | SetTemporal(bb, i, gmem); |
| @@ -174,6 +162,28 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 174 | } | 162 | } |
| 175 | break; | 163 | break; |
| 176 | } | 164 | } |
| 165 | case OpCode::Id::STG: { | ||
| 166 | const auto [real_address_base, base_address, descriptor] = | ||
| 167 | TrackAndGetGlobalMemory(bb, GetRegister(instr.gpr8), | ||
| 168 | static_cast<u32>(instr.stg.immediate_offset.Value()), true); | ||
| 169 | |||
| 170 | // Encode in temporary registers like this: real_base_address, {registers_to_be_written...} | ||
| 171 | SetTemporal(bb, 0, real_address_base); | ||
| 172 | |||
| 173 | const u32 count = GetUniformTypeElementsCount(instr.stg.type); | ||
| 174 | for (u32 i = 0; i < count; ++i) { | ||
| 175 | SetTemporal(bb, i + 1, GetRegister(instr.gpr0.Value() + i)); | ||
| 176 | } | ||
| 177 | for (u32 i = 0; i < count; ++i) { | ||
| 178 | const Node it_offset = Immediate(i * 4); | ||
| 179 | const Node real_address = | ||
| 180 | Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset); | ||
| 181 | const Node gmem = StoreNode(GmemNode(real_address, base_address, descriptor)); | ||
| 182 | |||
| 183 | bb.push_back(Operation(OperationCode::Assign, gmem, GetTemporal(i + 1))); | ||
| 184 | } | ||
| 185 | break; | ||
| 186 | } | ||
| 177 | case OpCode::Id::ST_A: { | 187 | case OpCode::Id::ST_A: { |
| 178 | UNIMPLEMENTED_IF_MSG(instr.gpr8.Value() != Register::ZeroIndex, | 188 | UNIMPLEMENTED_IF_MSG(instr.gpr8.Value() != Register::ZeroIndex, |
| 179 | "Indirect attribute loads are not supported"); | 189 | "Indirect attribute loads are not supported"); |
| @@ -205,8 +215,8 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 205 | break; | 215 | break; |
| 206 | } | 216 | } |
| 207 | case OpCode::Id::ST_L: { | 217 | case OpCode::Id::ST_L: { |
| 208 | UNIMPLEMENTED_IF_MSG(instr.st_l.unknown == 0, "ST_L Unhandled mode: {}", | 218 | LOG_DEBUG(HW_GPU, "ST_L cache management mode: {}", |
| 209 | static_cast<u32>(instr.st_l.unknown.Value())); | 219 | static_cast<u64>(instr.st_l.cache_management.Value())); |
| 210 | 220 | ||
| 211 | const auto GetLmemAddr = [&](s32 offset) { | 221 | const auto GetLmemAddr = [&](s32 offset) { |
| 212 | ASSERT(offset % 4 == 0); | 222 | ASSERT(offset % 4 == 0); |
| @@ -236,4 +246,34 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 236 | return pc; | 246 | return pc; |
| 237 | } | 247 | } |
| 238 | 248 | ||
| 249 | std::tuple<Node, Node, GlobalMemoryBase> ShaderIR::TrackAndGetGlobalMemory(NodeBlock& bb, | ||
| 250 | Node addr_register, | ||
| 251 | u32 immediate_offset, | ||
| 252 | bool is_write) { | ||
| 253 | const Node base_address{ | ||
| 254 | TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size()))}; | ||
| 255 | const auto cbuf = std::get_if<CbufNode>(base_address); | ||
| 256 | ASSERT(cbuf != nullptr); | ||
| 257 | const auto cbuf_offset_imm = std::get_if<ImmediateNode>(cbuf->GetOffset()); | ||
| 258 | ASSERT(cbuf_offset_imm != nullptr); | ||
| 259 | const auto cbuf_offset = cbuf_offset_imm->GetValue(); | ||
| 260 | |||
| 261 | bb.push_back( | ||
| 262 | Comment(fmt::format("Base address is c[0x{:x}][0x{:x}]", cbuf->GetIndex(), cbuf_offset))); | ||
| 263 | |||
| 264 | const GlobalMemoryBase descriptor{cbuf->GetIndex(), cbuf_offset}; | ||
| 265 | const auto& [entry, is_new] = used_global_memory.try_emplace(descriptor); | ||
| 266 | auto& usage = entry->second; | ||
| 267 | if (is_write) { | ||
| 268 | usage.is_written = true; | ||
| 269 | } else { | ||
| 270 | usage.is_read = true; | ||
| 271 | } | ||
| 272 | |||
| 273 | const auto real_address = | ||
| 274 | Operation(OperationCode::UAdd, NO_PRECISE, Immediate(immediate_offset), addr_register); | ||
| 275 | |||
| 276 | return {real_address, base_address, descriptor}; | ||
| 277 | } | ||
| 278 | |||
| 239 | } // namespace VideoCommon::Shader | 279 | } // namespace VideoCommon::Shader |
diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp index a775b402b..fa65ac9a9 100644 --- a/src/video_core/shader/decode/texture.cpp +++ b/src/video_core/shader/decode/texture.cpp | |||
| @@ -40,7 +40,7 @@ static std::size_t GetCoordCount(TextureType texture_type) { | |||
| 40 | u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { | 40 | u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { |
| 41 | const Instruction instr = {program_code[pc]}; | 41 | const Instruction instr = {program_code[pc]}; |
| 42 | const auto opcode = OpCode::Decode(instr); | 42 | const auto opcode = OpCode::Decode(instr); |
| 43 | 43 | bool is_bindless = false; | |
| 44 | switch (opcode->get().GetId()) { | 44 | switch (opcode->get().GetId()) { |
| 45 | case OpCode::Id::TEX: { | 45 | case OpCode::Id::TEX: { |
| 46 | if (instr.tex.UsesMiscMode(TextureMiscMode::NODEP)) { | 46 | if (instr.tex.UsesMiscMode(TextureMiscMode::NODEP)) { |
| @@ -54,7 +54,25 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { | |||
| 54 | const auto process_mode = instr.tex.GetTextureProcessMode(); | 54 | const auto process_mode = instr.tex.GetTextureProcessMode(); |
| 55 | WriteTexInstructionFloat( | 55 | WriteTexInstructionFloat( |
| 56 | bb, instr, | 56 | bb, instr, |
| 57 | GetTexCode(instr, texture_type, process_mode, depth_compare, is_array, is_aoffi)); | 57 | GetTexCode(instr, texture_type, process_mode, depth_compare, is_array, is_aoffi, {})); |
| 58 | break; | ||
| 59 | } | ||
| 60 | case OpCode::Id::TEX_B: { | ||
| 61 | UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(TextureMiscMode::AOFFI), | ||
| 62 | "AOFFI is not implemented"); | ||
| 63 | |||
| 64 | if (instr.tex.UsesMiscMode(TextureMiscMode::NODEP)) { | ||
| 65 | LOG_WARNING(HW_GPU, "TEX.NODEP implementation is incomplete"); | ||
| 66 | } | ||
| 67 | |||
| 68 | const TextureType texture_type{instr.tex_b.texture_type}; | ||
| 69 | const bool is_array = instr.tex_b.array != 0; | ||
| 70 | const bool is_aoffi = instr.tex.UsesMiscMode(TextureMiscMode::AOFFI); | ||
| 71 | const bool depth_compare = instr.tex_b.UsesMiscMode(TextureMiscMode::DC); | ||
| 72 | const auto process_mode = instr.tex_b.GetTextureProcessMode(); | ||
| 73 | WriteTexInstructionFloat(bb, instr, | ||
| 74 | GetTexCode(instr, texture_type, process_mode, depth_compare, | ||
| 75 | is_array, is_aoffi, {instr.gpr20})); | ||
| 58 | break; | 76 | break; |
| 59 | } | 77 | } |
| 60 | case OpCode::Id::TEXS: { | 78 | case OpCode::Id::TEXS: { |
| @@ -134,6 +152,9 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { | |||
| 134 | WriteTexsInstructionFloat(bb, instr, values); | 152 | WriteTexsInstructionFloat(bb, instr, values); |
| 135 | break; | 153 | break; |
| 136 | } | 154 | } |
| 155 | case OpCode::Id::TXQ_B: | ||
| 156 | is_bindless = true; | ||
| 157 | [[fallthrough]]; | ||
| 137 | case OpCode::Id::TXQ: { | 158 | case OpCode::Id::TXQ: { |
| 138 | if (instr.txq.UsesMiscMode(TextureMiscMode::NODEP)) { | 159 | if (instr.txq.UsesMiscMode(TextureMiscMode::NODEP)) { |
| 139 | LOG_WARNING(HW_GPU, "TXQ.NODEP implementation is incomplete"); | 160 | LOG_WARNING(HW_GPU, "TXQ.NODEP implementation is incomplete"); |
| @@ -143,7 +164,10 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { | |||
| 143 | // Sadly, not all texture instructions specify the type of texture their sampler | 164 | // Sadly, not all texture instructions specify the type of texture their sampler |
| 144 | // uses. This must be fixed at a later instance. | 165 | // uses. This must be fixed at a later instance. |
| 145 | const auto& sampler = | 166 | const auto& sampler = |
| 146 | GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false); | 167 | is_bindless |
| 168 | ? GetBindlessSampler(instr.gpr8, Tegra::Shader::TextureType::Texture2D, false, | ||
| 169 | false) | ||
| 170 | : GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false); | ||
| 147 | 171 | ||
| 148 | u32 indexer = 0; | 172 | u32 indexer = 0; |
| 149 | switch (instr.txq.query_type) { | 173 | switch (instr.txq.query_type) { |
| @@ -154,7 +178,8 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { | |||
| 154 | } | 178 | } |
| 155 | MetaTexture meta{sampler, {}, {}, {}, {}, {}, {}, element}; | 179 | MetaTexture meta{sampler, {}, {}, {}, {}, {}, {}, element}; |
| 156 | const Node value = | 180 | const Node value = |
| 157 | Operation(OperationCode::TextureQueryDimensions, meta, GetRegister(instr.gpr8)); | 181 | Operation(OperationCode::TextureQueryDimensions, meta, |
| 182 | GetRegister(instr.gpr8.Value() + (is_bindless ? 1 : 0))); | ||
| 158 | SetTemporal(bb, indexer++, value); | 183 | SetTemporal(bb, indexer++, value); |
| 159 | } | 184 | } |
| 160 | for (u32 i = 0; i < indexer; ++i) { | 185 | for (u32 i = 0; i < indexer; ++i) { |
| @@ -168,6 +193,9 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { | |||
| 168 | } | 193 | } |
| 169 | break; | 194 | break; |
| 170 | } | 195 | } |
| 196 | case OpCode::Id::TMML_B: | ||
| 197 | is_bindless = true; | ||
| 198 | [[fallthrough]]; | ||
| 171 | case OpCode::Id::TMML: { | 199 | case OpCode::Id::TMML: { |
| 172 | UNIMPLEMENTED_IF_MSG(instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), | 200 | UNIMPLEMENTED_IF_MSG(instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), |
| 173 | "NDV is not implemented"); | 201 | "NDV is not implemented"); |
| @@ -178,7 +206,9 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { | |||
| 178 | 206 | ||
| 179 | auto texture_type = instr.tmml.texture_type.Value(); | 207 | auto texture_type = instr.tmml.texture_type.Value(); |
| 180 | const bool is_array = instr.tmml.array != 0; | 208 | const bool is_array = instr.tmml.array != 0; |
| 181 | const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, false); | 209 | const auto& sampler = is_bindless |
| 210 | ? GetBindlessSampler(instr.gpr20, texture_type, is_array, false) | ||
| 211 | : GetSampler(instr.sampler, texture_type, is_array, false); | ||
| 182 | 212 | ||
| 183 | std::vector<Node> coords; | 213 | std::vector<Node> coords; |
| 184 | 214 | ||
| @@ -199,17 +229,19 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { | |||
| 199 | coords.push_back(GetRegister(instr.gpr8.Value() + 1)); | 229 | coords.push_back(GetRegister(instr.gpr8.Value() + 1)); |
| 200 | texture_type = TextureType::Texture2D; | 230 | texture_type = TextureType::Texture2D; |
| 201 | } | 231 | } |
| 202 | 232 | u32 indexer = 0; | |
| 203 | for (u32 element = 0; element < 2; ++element) { | 233 | for (u32 element = 0; element < 2; ++element) { |
| 234 | if (!instr.tmml.IsComponentEnabled(element)) { | ||
| 235 | continue; | ||
| 236 | } | ||
| 204 | auto params = coords; | 237 | auto params = coords; |
| 205 | MetaTexture meta{sampler, {}, {}, {}, {}, {}, {}, element}; | 238 | MetaTexture meta{sampler, {}, {}, {}, {}, {}, {}, element}; |
| 206 | const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params)); | 239 | const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params)); |
| 207 | SetTemporal(bb, element, value); | 240 | SetTemporal(bb, indexer++, value); |
| 208 | } | 241 | } |
| 209 | for (u32 element = 0; element < 2; ++element) { | 242 | for (u32 i = 0; i < indexer; ++i) { |
| 210 | SetRegister(bb, instr.gpr0.Value() + element, GetTemporal(element)); | 243 | SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i)); |
| 211 | } | 244 | } |
| 212 | |||
| 213 | break; | 245 | break; |
| 214 | } | 246 | } |
| 215 | case OpCode::Id::TLDS: { | 247 | case OpCode::Id::TLDS: { |
| @@ -254,6 +286,34 @@ const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler, Textu | |||
| 254 | return *used_samplers.emplace(entry).first; | 286 | return *used_samplers.emplace(entry).first; |
| 255 | } | 287 | } |
| 256 | 288 | ||
| 289 | const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg, TextureType type, | ||
| 290 | bool is_array, bool is_shadow) { | ||
| 291 | const Node sampler_register = GetRegister(reg); | ||
| 292 | const Node base_sampler = | ||
| 293 | TrackCbuf(sampler_register, global_code, static_cast<s64>(global_code.size())); | ||
| 294 | const auto cbuf = std::get_if<CbufNode>(base_sampler); | ||
| 295 | const auto cbuf_offset_imm = std::get_if<ImmediateNode>(cbuf->GetOffset()); | ||
| 296 | ASSERT(cbuf_offset_imm != nullptr); | ||
| 297 | const auto cbuf_offset = cbuf_offset_imm->GetValue(); | ||
| 298 | const auto cbuf_index = cbuf->GetIndex(); | ||
| 299 | const u64 cbuf_key = (cbuf_index << 32) | cbuf_offset; | ||
| 300 | |||
| 301 | // If this sampler has already been used, return the existing mapping. | ||
| 302 | const auto itr = | ||
| 303 | std::find_if(used_samplers.begin(), used_samplers.end(), | ||
| 304 | [&](const Sampler& entry) { return entry.GetOffset() == cbuf_key; }); | ||
| 305 | if (itr != used_samplers.end()) { | ||
| 306 | ASSERT(itr->GetType() == type && itr->IsArray() == is_array && | ||
| 307 | itr->IsShadow() == is_shadow); | ||
| 308 | return *itr; | ||
| 309 | } | ||
| 310 | |||
| 311 | // Otherwise create a new mapping for this sampler | ||
| 312 | const std::size_t next_index = used_samplers.size(); | ||
| 313 | const Sampler entry{cbuf_index, cbuf_offset, next_index, type, is_array, is_shadow}; | ||
| 314 | return *used_samplers.emplace(entry).first; | ||
| 315 | } | ||
| 316 | |||
| 257 | void ShaderIR::WriteTexInstructionFloat(NodeBlock& bb, Instruction instr, const Node4& components) { | 317 | void ShaderIR::WriteTexInstructionFloat(NodeBlock& bb, Instruction instr, const Node4& components) { |
| 258 | u32 dest_elem = 0; | 318 | u32 dest_elem = 0; |
| 259 | for (u32 elem = 0; elem < 4; ++elem) { | 319 | for (u32 elem = 0; elem < 4; ++elem) { |
| @@ -326,22 +386,27 @@ void ShaderIR::WriteTexsInstructionHalfFloat(NodeBlock& bb, Instruction instr, | |||
| 326 | Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, | 386 | Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, |
| 327 | TextureProcessMode process_mode, std::vector<Node> coords, | 387 | TextureProcessMode process_mode, std::vector<Node> coords, |
| 328 | Node array, Node depth_compare, u32 bias_offset, | 388 | Node array, Node depth_compare, u32 bias_offset, |
| 329 | std::vector<Node> aoffi) { | 389 | std::vector<Node> aoffi, |
| 390 | std::optional<Tegra::Shader::Register> bindless_reg) { | ||
| 330 | const bool is_array = array; | 391 | const bool is_array = array; |
| 331 | const bool is_shadow = depth_compare; | 392 | const bool is_shadow = depth_compare; |
| 393 | const bool is_bindless = bindless_reg.has_value(); | ||
| 332 | 394 | ||
| 333 | UNIMPLEMENTED_IF_MSG((texture_type == TextureType::Texture3D && (is_array || is_shadow)) || | 395 | UNIMPLEMENTED_IF_MSG((texture_type == TextureType::Texture3D && (is_array || is_shadow)) || |
| 334 | (texture_type == TextureType::TextureCube && is_array && is_shadow), | 396 | (texture_type == TextureType::TextureCube && is_array && is_shadow), |
| 335 | "This method is not supported."); | 397 | "This method is not supported."); |
| 336 | 398 | ||
| 337 | const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, is_shadow); | 399 | const auto& sampler = is_bindless |
| 400 | ? GetBindlessSampler(*bindless_reg, texture_type, is_array, is_shadow) | ||
| 401 | : GetSampler(instr.sampler, texture_type, is_array, is_shadow); | ||
| 338 | 402 | ||
| 339 | const bool lod_needed = process_mode == TextureProcessMode::LZ || | 403 | const bool lod_needed = process_mode == TextureProcessMode::LZ || |
| 340 | process_mode == TextureProcessMode::LL || | 404 | process_mode == TextureProcessMode::LL || |
| 341 | process_mode == TextureProcessMode::LLA; | 405 | process_mode == TextureProcessMode::LLA; |
| 342 | 406 | ||
| 343 | // LOD selection (either via bias or explicit textureLod) not supported in GL for | 407 | // LOD selection (either via bias or explicit textureLod) not |
| 344 | // sampler2DArrayShadow and samplerCubeArrayShadow. | 408 | // supported in GL for sampler2DArrayShadow and |
| 409 | // samplerCubeArrayShadow. | ||
| 345 | const bool gl_lod_supported = | 410 | const bool gl_lod_supported = |
| 346 | !((texture_type == Tegra::Shader::TextureType::Texture2D && is_array && is_shadow) || | 411 | !((texture_type == Tegra::Shader::TextureType::Texture2D && is_array && is_shadow) || |
| 347 | (texture_type == Tegra::Shader::TextureType::TextureCube && is_array && is_shadow)); | 412 | (texture_type == Tegra::Shader::TextureType::TextureCube && is_array && is_shadow)); |
| @@ -359,8 +424,9 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, | |||
| 359 | lod = Immediate(0.0f); | 424 | lod = Immediate(0.0f); |
| 360 | break; | 425 | break; |
| 361 | case TextureProcessMode::LB: | 426 | case TextureProcessMode::LB: |
| 362 | // If present, lod or bias are always stored in the register indexed by the gpr20 | 427 | // If present, lod or bias are always stored in the register |
| 363 | // field with an offset depending on the usage of the other registers | 428 | // indexed by the gpr20 field with an offset depending on the |
| 429 | // usage of the other registers | ||
| 364 | bias = GetRegister(instr.gpr20.Value() + bias_offset); | 430 | bias = GetRegister(instr.gpr20.Value() + bias_offset); |
| 365 | break; | 431 | break; |
| 366 | case TextureProcessMode::LL: | 432 | case TextureProcessMode::LL: |
| @@ -384,11 +450,18 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, | |||
| 384 | 450 | ||
| 385 | Node4 ShaderIR::GetTexCode(Instruction instr, TextureType texture_type, | 451 | Node4 ShaderIR::GetTexCode(Instruction instr, TextureType texture_type, |
| 386 | TextureProcessMode process_mode, bool depth_compare, bool is_array, | 452 | TextureProcessMode process_mode, bool depth_compare, bool is_array, |
| 387 | bool is_aoffi) { | 453 | bool is_aoffi, std::optional<Tegra::Shader::Register> bindless_reg) { |
| 388 | const bool lod_bias_enabled{ | 454 | const bool lod_bias_enabled{ |
| 389 | (process_mode != TextureProcessMode::None && process_mode != TextureProcessMode::LZ)}; | 455 | (process_mode != TextureProcessMode::None && process_mode != TextureProcessMode::LZ)}; |
| 390 | 456 | ||
| 457 | const bool is_bindless = bindless_reg.has_value(); | ||
| 458 | |||
| 391 | u64 parameter_register = instr.gpr20.Value(); | 459 | u64 parameter_register = instr.gpr20.Value(); |
| 460 | if (is_bindless) { | ||
| 461 | ++parameter_register; | ||
| 462 | } | ||
| 463 | |||
| 464 | const u32 bias_lod_offset = (is_bindless ? 1 : 0); | ||
| 392 | if (lod_bias_enabled) { | 465 | if (lod_bias_enabled) { |
| 393 | ++parameter_register; | 466 | ++parameter_register; |
| 394 | } | 467 | } |
| @@ -423,7 +496,8 @@ Node4 ShaderIR::GetTexCode(Instruction instr, TextureType texture_type, | |||
| 423 | dc = GetRegister(parameter_register++); | 496 | dc = GetRegister(parameter_register++); |
| 424 | } | 497 | } |
| 425 | 498 | ||
| 426 | return GetTextureCode(instr, texture_type, process_mode, coords, array, dc, 0, aoffi); | 499 | return GetTextureCode(instr, texture_type, process_mode, coords, array, dc, bias_lod_offset, |
| 500 | aoffi, bindless_reg); | ||
| 427 | } | 501 | } |
| 428 | 502 | ||
| 429 | Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, | 503 | Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, |
| @@ -459,7 +533,8 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, | |||
| 459 | dc = GetRegister(depth_register); | 533 | dc = GetRegister(depth_register); |
| 460 | } | 534 | } |
| 461 | 535 | ||
| 462 | return GetTextureCode(instr, texture_type, process_mode, coords, array, dc, bias_offset, {}); | 536 | return GetTextureCode(instr, texture_type, process_mode, coords, array, dc, bias_offset, {}, |
| 537 | {}); | ||
| 463 | } | 538 | } |
| 464 | 539 | ||
| 465 | Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare, | 540 | Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare, |
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index cb60b8886..e4eb0dfd9 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp | |||
| @@ -189,7 +189,11 @@ Node ShaderIR::UnpackHalfImmediate(Instruction instr, bool has_negation) { | |||
| 189 | const Node first_negate = GetPredicate(instr.half_imm.first_negate != 0); | 189 | const Node first_negate = GetPredicate(instr.half_imm.first_negate != 0); |
| 190 | const Node second_negate = GetPredicate(instr.half_imm.second_negate != 0); | 190 | const Node second_negate = GetPredicate(instr.half_imm.second_negate != 0); |
| 191 | 191 | ||
| 192 | return Operation(OperationCode::HNegate, HALF_NO_PRECISE, value, first_negate, second_negate); | 192 | return Operation(OperationCode::HNegate, NO_PRECISE, value, first_negate, second_negate); |
| 193 | } | ||
| 194 | |||
| 195 | Node ShaderIR::UnpackHalfFloat(Node value, Tegra::Shader::HalfType type) { | ||
| 196 | return Operation(OperationCode::HUnpack, type, value); | ||
| 193 | } | 197 | } |
| 194 | 198 | ||
| 195 | Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) { | 199 | Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) { |
| @@ -209,17 +213,26 @@ Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) { | |||
| 209 | 213 | ||
| 210 | Node ShaderIR::GetOperandAbsNegHalf(Node value, bool absolute, bool negate) { | 214 | Node ShaderIR::GetOperandAbsNegHalf(Node value, bool absolute, bool negate) { |
| 211 | if (absolute) { | 215 | if (absolute) { |
| 212 | value = Operation(OperationCode::HAbsolute, HALF_NO_PRECISE, value); | 216 | value = Operation(OperationCode::HAbsolute, NO_PRECISE, value); |
| 213 | } | 217 | } |
| 214 | if (negate) { | 218 | if (negate) { |
| 215 | value = Operation(OperationCode::HNegate, HALF_NO_PRECISE, value, GetPredicate(true), | 219 | value = Operation(OperationCode::HNegate, NO_PRECISE, value, GetPredicate(true), |
| 216 | GetPredicate(true)); | 220 | GetPredicate(true)); |
| 217 | } | 221 | } |
| 218 | return value; | 222 | return value; |
| 219 | } | 223 | } |
| 220 | 224 | ||
| 225 | Node ShaderIR::GetSaturatedHalfFloat(Node value, bool saturate) { | ||
| 226 | if (!saturate) { | ||
| 227 | return value; | ||
| 228 | } | ||
| 229 | const Node positive_zero = Immediate(std::copysignf(0, 1)); | ||
| 230 | const Node positive_one = Immediate(1.0f); | ||
| 231 | return Operation(OperationCode::HClamp, NO_PRECISE, value, positive_zero, positive_one); | ||
| 232 | } | ||
| 233 | |||
| 221 | Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) { | 234 | Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) { |
| 222 | static const std::unordered_map<PredCondition, OperationCode> PredicateComparisonTable = { | 235 | const std::unordered_map<PredCondition, OperationCode> PredicateComparisonTable = { |
| 223 | {PredCondition::LessThan, OperationCode::LogicalFLessThan}, | 236 | {PredCondition::LessThan, OperationCode::LogicalFLessThan}, |
| 224 | {PredCondition::Equal, OperationCode::LogicalFEqual}, | 237 | {PredCondition::Equal, OperationCode::LogicalFEqual}, |
| 225 | {PredCondition::LessEqual, OperationCode::LogicalFLessEqual}, | 238 | {PredCondition::LessEqual, OperationCode::LogicalFLessEqual}, |
| @@ -255,7 +268,7 @@ Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, N | |||
| 255 | 268 | ||
| 256 | Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_signed, Node op_a, | 269 | Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_signed, Node op_a, |
| 257 | Node op_b) { | 270 | Node op_b) { |
| 258 | static const std::unordered_map<PredCondition, OperationCode> PredicateComparisonTable = { | 271 | const std::unordered_map<PredCondition, OperationCode> PredicateComparisonTable = { |
| 259 | {PredCondition::LessThan, OperationCode::LogicalILessThan}, | 272 | {PredCondition::LessThan, OperationCode::LogicalILessThan}, |
| 260 | {PredCondition::Equal, OperationCode::LogicalIEqual}, | 273 | {PredCondition::Equal, OperationCode::LogicalIEqual}, |
| 261 | {PredCondition::LessEqual, OperationCode::LogicalILessEqual}, | 274 | {PredCondition::LessEqual, OperationCode::LogicalILessEqual}, |
| @@ -283,40 +296,32 @@ Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_si | |||
| 283 | return predicate; | 296 | return predicate; |
| 284 | } | 297 | } |
| 285 | 298 | ||
| 286 | Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, | 299 | Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a, |
| 287 | const MetaHalfArithmetic& meta, Node op_a, Node op_b) { | 300 | Node op_b) { |
| 288 | 301 | const std::unordered_map<PredCondition, OperationCode> PredicateComparisonTable = { | |
| 289 | UNIMPLEMENTED_IF_MSG(condition == PredCondition::LessThanWithNan || | ||
| 290 | condition == PredCondition::NotEqualWithNan || | ||
| 291 | condition == PredCondition::LessEqualWithNan || | ||
| 292 | condition == PredCondition::GreaterThanWithNan || | ||
| 293 | condition == PredCondition::GreaterEqualWithNan, | ||
| 294 | "Unimplemented NaN comparison for half floats"); | ||
| 295 | |||
| 296 | static const std::unordered_map<PredCondition, OperationCode> PredicateComparisonTable = { | ||
| 297 | {PredCondition::LessThan, OperationCode::Logical2HLessThan}, | 302 | {PredCondition::LessThan, OperationCode::Logical2HLessThan}, |
| 298 | {PredCondition::Equal, OperationCode::Logical2HEqual}, | 303 | {PredCondition::Equal, OperationCode::Logical2HEqual}, |
| 299 | {PredCondition::LessEqual, OperationCode::Logical2HLessEqual}, | 304 | {PredCondition::LessEqual, OperationCode::Logical2HLessEqual}, |
| 300 | {PredCondition::GreaterThan, OperationCode::Logical2HGreaterThan}, | 305 | {PredCondition::GreaterThan, OperationCode::Logical2HGreaterThan}, |
| 301 | {PredCondition::NotEqual, OperationCode::Logical2HNotEqual}, | 306 | {PredCondition::NotEqual, OperationCode::Logical2HNotEqual}, |
| 302 | {PredCondition::GreaterEqual, OperationCode::Logical2HGreaterEqual}, | 307 | {PredCondition::GreaterEqual, OperationCode::Logical2HGreaterEqual}, |
| 303 | {PredCondition::LessThanWithNan, OperationCode::Logical2HLessThan}, | 308 | {PredCondition::LessThanWithNan, OperationCode::Logical2HLessThanWithNan}, |
| 304 | {PredCondition::NotEqualWithNan, OperationCode::Logical2HNotEqual}, | 309 | {PredCondition::NotEqualWithNan, OperationCode::Logical2HNotEqualWithNan}, |
| 305 | {PredCondition::LessEqualWithNan, OperationCode::Logical2HLessEqual}, | 310 | {PredCondition::LessEqualWithNan, OperationCode::Logical2HLessEqualWithNan}, |
| 306 | {PredCondition::GreaterThanWithNan, OperationCode::Logical2HGreaterThan}, | 311 | {PredCondition::GreaterThanWithNan, OperationCode::Logical2HGreaterThanWithNan}, |
| 307 | {PredCondition::GreaterEqualWithNan, OperationCode::Logical2HGreaterEqual}}; | 312 | {PredCondition::GreaterEqualWithNan, OperationCode::Logical2HGreaterEqualWithNan}}; |
| 308 | 313 | ||
| 309 | const auto comparison{PredicateComparisonTable.find(condition)}; | 314 | const auto comparison{PredicateComparisonTable.find(condition)}; |
| 310 | UNIMPLEMENTED_IF_MSG(comparison == PredicateComparisonTable.end(), | 315 | UNIMPLEMENTED_IF_MSG(comparison == PredicateComparisonTable.end(), |
| 311 | "Unknown predicate comparison operation"); | 316 | "Unknown predicate comparison operation"); |
| 312 | 317 | ||
| 313 | const Node predicate = Operation(comparison->second, meta, op_a, op_b); | 318 | const Node predicate = Operation(comparison->second, NO_PRECISE, op_a, op_b); |
| 314 | 319 | ||
| 315 | return predicate; | 320 | return predicate; |
| 316 | } | 321 | } |
| 317 | 322 | ||
| 318 | OperationCode ShaderIR::GetPredicateCombiner(PredOperation operation) { | 323 | OperationCode ShaderIR::GetPredicateCombiner(PredOperation operation) { |
| 319 | static const std::unordered_map<PredOperation, OperationCode> PredicateOperationTable = { | 324 | const std::unordered_map<PredOperation, OperationCode> PredicateOperationTable = { |
| 320 | {PredOperation::And, OperationCode::LogicalAnd}, | 325 | {PredOperation::And, OperationCode::LogicalAnd}, |
| 321 | {PredOperation::Or, OperationCode::LogicalOr}, | 326 | {PredOperation::Or, OperationCode::LogicalOr}, |
| 322 | {PredOperation::Xor, OperationCode::LogicalXor}, | 327 | {PredOperation::Xor, OperationCode::LogicalXor}, |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 4888998d3..81278fb33 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -109,11 +109,13 @@ enum class OperationCode { | |||
| 109 | UBitfieldExtract, /// (MetaArithmetic, uint value, int offset, int offset) -> uint | 109 | UBitfieldExtract, /// (MetaArithmetic, uint value, int offset, int offset) -> uint |
| 110 | UBitCount, /// (MetaArithmetic, uint) -> uint | 110 | UBitCount, /// (MetaArithmetic, uint) -> uint |
| 111 | 111 | ||
| 112 | HAdd, /// (MetaHalfArithmetic, f16vec2 a, f16vec2 b) -> f16vec2 | 112 | HAdd, /// (MetaArithmetic, f16vec2 a, f16vec2 b) -> f16vec2 |
| 113 | HMul, /// (MetaHalfArithmetic, f16vec2 a, f16vec2 b) -> f16vec2 | 113 | HMul, /// (MetaArithmetic, f16vec2 a, f16vec2 b) -> f16vec2 |
| 114 | HFma, /// (MetaHalfArithmetic, f16vec2 a, f16vec2 b, f16vec2 c) -> f16vec2 | 114 | HFma, /// (MetaArithmetic, f16vec2 a, f16vec2 b, f16vec2 c) -> f16vec2 |
| 115 | HAbsolute, /// (f16vec2 a) -> f16vec2 | 115 | HAbsolute, /// (f16vec2 a) -> f16vec2 |
| 116 | HNegate, /// (f16vec2 a, bool first, bool second) -> f16vec2 | 116 | HNegate, /// (f16vec2 a, bool first, bool second) -> f16vec2 |
| 117 | HClamp, /// (f16vec2 src, float min, float max) -> f16vec2 | ||
| 118 | HUnpack, /// (Tegra::Shader::HalfType, T value) -> f16vec2 | ||
| 117 | HMergeF32, /// (f16vec2 src) -> float | 119 | HMergeF32, /// (f16vec2 src) -> float |
| 118 | HMergeH0, /// (f16vec2 dest, f16vec2 src) -> f16vec2 | 120 | HMergeH0, /// (f16vec2 dest, f16vec2 src) -> f16vec2 |
| 119 | HMergeH1, /// (f16vec2 dest, f16vec2 src) -> f16vec2 | 121 | HMergeH1, /// (f16vec2 dest, f16vec2 src) -> f16vec2 |
| @@ -150,12 +152,18 @@ enum class OperationCode { | |||
| 150 | LogicalUNotEqual, /// (uint a, uint b) -> bool | 152 | LogicalUNotEqual, /// (uint a, uint b) -> bool |
| 151 | LogicalUGreaterEqual, /// (uint a, uint b) -> bool | 153 | LogicalUGreaterEqual, /// (uint a, uint b) -> bool |
| 152 | 154 | ||
| 153 | Logical2HLessThan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | 155 | Logical2HLessThan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 |
| 154 | Logical2HEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | 156 | Logical2HEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 |
| 155 | Logical2HLessEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | 157 | Logical2HLessEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 |
| 156 | Logical2HGreaterThan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | 158 | Logical2HGreaterThan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 |
| 157 | Logical2HNotEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | 159 | Logical2HNotEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 |
| 158 | Logical2HGreaterEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | 160 | Logical2HGreaterEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 |
| 161 | Logical2HLessThanWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | ||
| 162 | Logical2HEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | ||
| 163 | Logical2HLessEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | ||
| 164 | Logical2HGreaterThanWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | ||
| 165 | Logical2HNotEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | ||
| 166 | Logical2HGreaterEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | ||
| 159 | 167 | ||
| 160 | Texture, /// (MetaTexture, float[N] coords) -> float4 | 168 | Texture, /// (MetaTexture, float[N] coords) -> float4 |
| 161 | TextureLod, /// (MetaTexture, float[N] coords) -> float4 | 169 | TextureLod, /// (MetaTexture, float[N] coords) -> float4 |
| @@ -196,9 +204,23 @@ enum class ExitMethod { | |||
| 196 | 204 | ||
| 197 | class Sampler { | 205 | class Sampler { |
| 198 | public: | 206 | public: |
| 207 | // Use this constructor for bounded Samplers | ||
| 199 | explicit Sampler(std::size_t offset, std::size_t index, Tegra::Shader::TextureType type, | 208 | explicit Sampler(std::size_t offset, std::size_t index, Tegra::Shader::TextureType type, |
| 200 | bool is_array, bool is_shadow) | 209 | bool is_array, bool is_shadow) |
| 201 | : offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow} {} | 210 | : offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow}, |
| 211 | is_bindless{false} {} | ||
| 212 | |||
| 213 | // Use this constructor for bindless Samplers | ||
| 214 | explicit Sampler(u32 cbuf_index, u32 cbuf_offset, std::size_t index, | ||
| 215 | Tegra::Shader::TextureType type, bool is_array, bool is_shadow) | ||
| 216 | : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, | ||
| 217 | is_array{is_array}, is_shadow{is_shadow}, is_bindless{true} {} | ||
| 218 | |||
| 219 | // Use this only for serialization/deserialization | ||
| 220 | explicit Sampler(std::size_t offset, std::size_t index, Tegra::Shader::TextureType type, | ||
| 221 | bool is_array, bool is_shadow, bool is_bindless) | ||
| 222 | : offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow}, | ||
| 223 | is_bindless{is_bindless} {} | ||
| 202 | 224 | ||
| 203 | std::size_t GetOffset() const { | 225 | std::size_t GetOffset() const { |
| 204 | return offset; | 226 | return offset; |
| @@ -220,6 +242,14 @@ public: | |||
| 220 | return is_shadow; | 242 | return is_shadow; |
| 221 | } | 243 | } |
| 222 | 244 | ||
| 245 | bool IsBindless() const { | ||
| 246 | return is_bindless; | ||
| 247 | } | ||
| 248 | |||
| 249 | std::pair<u32, u32> GetBindlessCBuf() const { | ||
| 250 | return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; | ||
| 251 | } | ||
| 252 | |||
| 223 | bool operator<(const Sampler& rhs) const { | 253 | bool operator<(const Sampler& rhs) const { |
| 224 | return std::tie(offset, index, type, is_array, is_shadow) < | 254 | return std::tie(offset, index, type, is_array, is_shadow) < |
| 225 | std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_array, rhs.is_shadow); | 255 | std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_array, rhs.is_shadow); |
| @@ -231,8 +261,9 @@ private: | |||
| 231 | std::size_t offset{}; | 261 | std::size_t offset{}; |
| 232 | std::size_t index{}; ///< Value used to index into the generated GLSL sampler array. | 262 | std::size_t index{}; ///< Value used to index into the generated GLSL sampler array. |
| 233 | Tegra::Shader::TextureType type{}; ///< The type used to sample this texture (Texture2D, etc) | 263 | Tegra::Shader::TextureType type{}; ///< The type used to sample this texture (Texture2D, etc) |
| 234 | bool is_array{}; ///< Whether the texture is being sampled as an array texture or not. | 264 | bool is_array{}; ///< Whether the texture is being sampled as an array texture or not. |
| 235 | bool is_shadow{}; ///< Whether the texture is being sampled as a depth texture or not. | 265 | bool is_shadow{}; ///< Whether the texture is being sampled as a depth texture or not. |
| 266 | bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not. | ||
| 236 | }; | 267 | }; |
| 237 | 268 | ||
| 238 | class ConstBuffer { | 269 | class ConstBuffer { |
| @@ -276,15 +307,13 @@ struct GlobalMemoryBase { | |||
| 276 | } | 307 | } |
| 277 | }; | 308 | }; |
| 278 | 309 | ||
| 279 | struct MetaArithmetic { | 310 | struct GlobalMemoryUsage { |
| 280 | bool precise{}; | 311 | bool is_read{}; |
| 312 | bool is_written{}; | ||
| 281 | }; | 313 | }; |
| 282 | 314 | ||
| 283 | struct MetaHalfArithmetic { | 315 | struct MetaArithmetic { |
| 284 | bool precise{}; | 316 | bool precise{}; |
| 285 | std::array<Tegra::Shader::HalfType, 3> types = {Tegra::Shader::HalfType::H0_H1, | ||
| 286 | Tegra::Shader::HalfType::H0_H1, | ||
| 287 | Tegra::Shader::HalfType::H0_H1}; | ||
| 288 | }; | 317 | }; |
| 289 | 318 | ||
| 290 | struct MetaTexture { | 319 | struct MetaTexture { |
| @@ -298,11 +327,10 @@ struct MetaTexture { | |||
| 298 | u32 element{}; | 327 | u32 element{}; |
| 299 | }; | 328 | }; |
| 300 | 329 | ||
| 301 | constexpr MetaArithmetic PRECISE = {true}; | 330 | inline constexpr MetaArithmetic PRECISE = {true}; |
| 302 | constexpr MetaArithmetic NO_PRECISE = {false}; | 331 | inline constexpr MetaArithmetic NO_PRECISE = {false}; |
| 303 | constexpr MetaHalfArithmetic HALF_NO_PRECISE = {false}; | ||
| 304 | 332 | ||
| 305 | using Meta = std::variant<MetaArithmetic, MetaHalfArithmetic, MetaTexture>; | 333 | using Meta = std::variant<MetaArithmetic, MetaTexture, Tegra::Shader::HalfType>; |
| 306 | 334 | ||
| 307 | /// Holds any kind of operation that can be done in the IR | 335 | /// Holds any kind of operation that can be done in the IR |
| 308 | class OperationNode final { | 336 | class OperationNode final { |
| @@ -578,8 +606,8 @@ public: | |||
| 578 | return used_clip_distances; | 606 | return used_clip_distances; |
| 579 | } | 607 | } |
| 580 | 608 | ||
| 581 | const std::set<GlobalMemoryBase>& GetGlobalMemoryBases() const { | 609 | const std::map<GlobalMemoryBase, GlobalMemoryUsage>& GetGlobalMemory() const { |
| 582 | return used_global_memory_bases; | 610 | return used_global_memory; |
| 583 | } | 611 | } |
| 584 | 612 | ||
| 585 | std::size_t GetLength() const { | 613 | std::size_t GetLength() const { |
| @@ -706,10 +734,14 @@ private: | |||
| 706 | 734 | ||
| 707 | /// Unpacks a half immediate from an instruction | 735 | /// Unpacks a half immediate from an instruction |
| 708 | Node UnpackHalfImmediate(Tegra::Shader::Instruction instr, bool has_negation); | 736 | Node UnpackHalfImmediate(Tegra::Shader::Instruction instr, bool has_negation); |
| 737 | /// Unpacks a binary value into a half float pair with a type format | ||
| 738 | Node UnpackHalfFloat(Node value, Tegra::Shader::HalfType type); | ||
| 709 | /// Merges a half pair into another value | 739 | /// Merges a half pair into another value |
| 710 | Node HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge); | 740 | Node HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge); |
| 711 | /// Conditionally absolute/negated half float pair. Absolute is applied first | 741 | /// Conditionally absolute/negated half float pair. Absolute is applied first |
| 712 | Node GetOperandAbsNegHalf(Node value, bool absolute, bool negate); | 742 | Node GetOperandAbsNegHalf(Node value, bool absolute, bool negate); |
| 743 | /// Conditionally saturates a half float pair | ||
| 744 | Node GetSaturatedHalfFloat(Node value, bool saturate = true); | ||
| 713 | 745 | ||
| 714 | /// Returns a predicate comparing two floats | 746 | /// Returns a predicate comparing two floats |
| 715 | Node GetPredicateComparisonFloat(Tegra::Shader::PredCondition condition, Node op_a, Node op_b); | 747 | Node GetPredicateComparisonFloat(Tegra::Shader::PredCondition condition, Node op_a, Node op_b); |
| @@ -717,8 +749,7 @@ private: | |||
| 717 | Node GetPredicateComparisonInteger(Tegra::Shader::PredCondition condition, bool is_signed, | 749 | Node GetPredicateComparisonInteger(Tegra::Shader::PredCondition condition, bool is_signed, |
| 718 | Node op_a, Node op_b); | 750 | Node op_a, Node op_b); |
| 719 | /// Returns a predicate comparing two half floats. meta consumes how both pairs will be compared | 751 | /// Returns a predicate comparing two half floats. meta consumes how both pairs will be compared |
| 720 | Node GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, | 752 | Node GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a, Node op_b); |
| 721 | const MetaHalfArithmetic& meta, Node op_a, Node op_b); | ||
| 722 | 753 | ||
| 723 | /// Returns a predicate combiner operation | 754 | /// Returns a predicate combiner operation |
| 724 | OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation); | 755 | OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation); |
| @@ -730,6 +761,11 @@ private: | |||
| 730 | const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler, | 761 | const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler, |
| 731 | Tegra::Shader::TextureType type, bool is_array, bool is_shadow); | 762 | Tegra::Shader::TextureType type, bool is_array, bool is_shadow); |
| 732 | 763 | ||
| 764 | // Accesses a texture sampler for a bindless texture. | ||
| 765 | const Sampler& GetBindlessSampler(const Tegra::Shader::Register& reg, | ||
| 766 | Tegra::Shader::TextureType type, bool is_array, | ||
| 767 | bool is_shadow); | ||
| 768 | |||
| 733 | /// Extracts a sequence of bits from a node | 769 | /// Extracts a sequence of bits from a node |
| 734 | Node BitfieldExtract(Node value, u32 offset, u32 bits); | 770 | Node BitfieldExtract(Node value, u32 offset, u32 bits); |
| 735 | 771 | ||
| @@ -743,7 +779,8 @@ private: | |||
| 743 | 779 | ||
| 744 | Node4 GetTexCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, | 780 | Node4 GetTexCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, |
| 745 | Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, | 781 | Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, |
| 746 | bool is_array, bool is_aoffi); | 782 | bool is_array, bool is_aoffi, |
| 783 | std::optional<Tegra::Shader::Register> bindless_reg); | ||
| 747 | 784 | ||
| 748 | Node4 GetTexsCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, | 785 | Node4 GetTexsCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, |
| 749 | Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, | 786 | Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, |
| @@ -763,7 +800,8 @@ private: | |||
| 763 | 800 | ||
| 764 | Node4 GetTextureCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, | 801 | Node4 GetTextureCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, |
| 765 | Tegra::Shader::TextureProcessMode process_mode, std::vector<Node> coords, | 802 | Tegra::Shader::TextureProcessMode process_mode, std::vector<Node> coords, |
| 766 | Node array, Node depth_compare, u32 bias_offset, std::vector<Node> aoffi); | 803 | Node array, Node depth_compare, u32 bias_offset, std::vector<Node> aoffi, |
| 804 | std::optional<Tegra::Shader::Register> bindless_reg); | ||
| 767 | 805 | ||
| 768 | Node GetVideoOperand(Node op, bool is_chunk, bool is_signed, Tegra::Shader::VideoType type, | 806 | Node GetVideoOperand(Node op, bool is_chunk, bool is_signed, Tegra::Shader::VideoType type, |
| 769 | u64 byte_height); | 807 | u64 byte_height); |
| @@ -781,6 +819,11 @@ private: | |||
| 781 | 819 | ||
| 782 | std::pair<Node, s64> TrackRegister(const GprNode* tracked, const NodeBlock& code, s64 cursor); | 820 | std::pair<Node, s64> TrackRegister(const GprNode* tracked, const NodeBlock& code, s64 cursor); |
| 783 | 821 | ||
| 822 | std::tuple<Node, Node, GlobalMemoryBase> TrackAndGetGlobalMemory(NodeBlock& bb, | ||
| 823 | Node addr_register, | ||
| 824 | u32 immediate_offset, | ||
| 825 | bool is_write); | ||
| 826 | |||
| 784 | template <typename... T> | 827 | template <typename... T> |
| 785 | Node Operation(OperationCode code, const T*... operands) { | 828 | Node Operation(OperationCode code, const T*... operands) { |
| 786 | return StoreNode(OperationNode(code, operands...)); | 829 | return StoreNode(OperationNode(code, operands...)); |
| @@ -834,7 +877,7 @@ private: | |||
| 834 | std::map<u32, ConstBuffer> used_cbufs; | 877 | std::map<u32, ConstBuffer> used_cbufs; |
| 835 | std::set<Sampler> used_samplers; | 878 | std::set<Sampler> used_samplers; |
| 836 | std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; | 879 | std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; |
| 837 | std::set<GlobalMemoryBase> used_global_memory_bases; | 880 | std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory; |
| 838 | 881 | ||
| 839 | Tegra::Shader::Header header; | 882 | Tegra::Shader::Header header; |
| 840 | }; | 883 | }; |
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 995d0e068..217805386 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp | |||
| @@ -288,6 +288,29 @@ void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 | |||
| 288 | } | 288 | } |
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32 dst_y, | ||
| 292 | const u32 block_height, const std::size_t copy_size, const u8* source_data, | ||
| 293 | u8* swizzle_data) { | ||
| 294 | const u32 image_width_in_gobs{(width + gob_size_x - 1) / gob_size_x}; | ||
| 295 | std::size_t count = 0; | ||
| 296 | for (std::size_t y = dst_y; y < height && count < copy_size; ++y) { | ||
| 297 | const std::size_t gob_address_y = | ||
| 298 | (y / (gob_size_y * block_height)) * gob_size * block_height * image_width_in_gobs + | ||
| 299 | ((y % (gob_size_y * block_height)) / gob_size_y) * gob_size; | ||
| 300 | const auto& table = legacy_swizzle_table[y % gob_size_y]; | ||
| 301 | for (std::size_t x = dst_x; x < width && count < copy_size; ++x) { | ||
| 302 | const std::size_t gob_address = | ||
| 303 | gob_address_y + (x / gob_size_x) * gob_size * block_height; | ||
| 304 | const std::size_t swizzled_offset = gob_address + table[x % gob_size_x]; | ||
| 305 | const u8* source_line = source_data + count; | ||
| 306 | u8* dest_addr = swizzle_data + swizzled_offset; | ||
| 307 | count++; | ||
| 308 | |||
| 309 | std::memcpy(dest_addr, source_line, 1); | ||
| 310 | } | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 291 | std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat format, u32 width, | 314 | std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat format, u32 width, |
| 292 | u32 height) { | 315 | u32 height) { |
| 293 | std::vector<u8> rgba_data; | 316 | std::vector<u8> rgba_data; |
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h index e078fa274..e072d8401 100644 --- a/src/video_core/textures/decoders.h +++ b/src/video_core/textures/decoders.h | |||
| @@ -51,4 +51,8 @@ void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 | |||
| 51 | u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height, | 51 | u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height, |
| 52 | u32 offset_x, u32 offset_y); | 52 | u32 offset_x, u32 offset_y); |
| 53 | 53 | ||
| 54 | void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32 dst_y, | ||
| 55 | const u32 block_height, const std::size_t copy_size, const u8* source_data, | ||
| 56 | u8* swizzle_data); | ||
| 57 | |||
| 54 | } // namespace Tegra::Texture | 58 | } // namespace Tegra::Texture |
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index cb82ecf3f..60cda0ca3 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/settings.h" | 7 | #include "core/settings.h" |
| 8 | #include "video_core/gpu_asynch.h" | ||
| 9 | #include "video_core/gpu_synch.h" | ||
| 8 | #include "video_core/renderer_base.h" | 10 | #include "video_core/renderer_base.h" |
| 9 | #include "video_core/renderer_opengl/renderer_opengl.h" | 11 | #include "video_core/renderer_opengl/renderer_opengl.h" |
| 10 | #include "video_core/video_core.h" | 12 | #include "video_core/video_core.h" |
| @@ -16,6 +18,14 @@ std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_wind | |||
| 16 | return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system); | 18 | return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system); |
| 17 | } | 19 | } |
| 18 | 20 | ||
| 21 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::System& system) { | ||
| 22 | if (Settings::values.use_asynchronous_gpu_emulation) { | ||
| 23 | return std::make_unique<VideoCommon::GPUAsynch>(system, system.Renderer()); | ||
| 24 | } | ||
| 25 | |||
| 26 | return std::make_unique<VideoCommon::GPUSynch>(system, system.Renderer()); | ||
| 27 | } | ||
| 28 | |||
| 19 | u16 GetResolutionScaleFactor(const RendererBase& renderer) { | 29 | u16 GetResolutionScaleFactor(const RendererBase& renderer) { |
| 20 | return static_cast<u16>( | 30 | return static_cast<u16>( |
| 21 | Settings::values.resolution_factor | 31 | Settings::values.resolution_factor |
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index 3c583f195..b8e0ac372 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h | |||
| @@ -14,6 +14,10 @@ namespace Core::Frontend { | |||
| 14 | class EmuWindow; | 14 | class EmuWindow; |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | namespace Tegra { | ||
| 18 | class GPU; | ||
| 19 | } | ||
| 20 | |||
| 17 | namespace VideoCore { | 21 | namespace VideoCore { |
| 18 | 22 | ||
| 19 | class RendererBase; | 23 | class RendererBase; |
| @@ -27,6 +31,9 @@ class RendererBase; | |||
| 27 | std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window, | 31 | std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window, |
| 28 | Core::System& system); | 32 | Core::System& system); |
| 29 | 33 | ||
| 34 | /// Creates an emulated GPU instance using the given system context. | ||
| 35 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::System& system); | ||
| 36 | |||
| 30 | u16 GetResolutionScaleFactor(const RendererBase& renderer); | 37 | u16 GetResolutionScaleFactor(const RendererBase& renderer); |
| 31 | 38 | ||
| 32 | } // namespace VideoCore | 39 | } // namespace VideoCore |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 2eb86d6e5..5138bd9a3 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -7,6 +7,8 @@ add_executable(yuzu | |||
| 7 | Info.plist | 7 | Info.plist |
| 8 | about_dialog.cpp | 8 | about_dialog.cpp |
| 9 | about_dialog.h | 9 | about_dialog.h |
| 10 | applets/error.cpp | ||
| 11 | applets/error.h | ||
| 10 | applets/profile_select.cpp | 12 | applets/profile_select.cpp |
| 11 | applets/profile_select.h | 13 | applets/profile_select.h |
| 12 | applets/software_keyboard.cpp | 14 | applets/software_keyboard.cpp |
| @@ -151,6 +153,12 @@ target_link_libraries(yuzu PRIVATE common core input_common video_core) | |||
| 151 | target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::OpenGL Qt5::Widgets) | 153 | target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::OpenGL Qt5::Widgets) |
| 152 | target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) | 154 | target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) |
| 153 | 155 | ||
| 156 | target_compile_definitions(yuzu PRIVATE | ||
| 157 | # Use QStringBuilder for string concatenation to reduce | ||
| 158 | # the overall number of temporary strings created. | ||
| 159 | -DQT_USE_QSTRINGBUILDER | ||
| 160 | ) | ||
| 161 | |||
| 154 | if (YUZU_ENABLE_COMPATIBILITY_REPORTING) | 162 | if (YUZU_ENABLE_COMPATIBILITY_REPORTING) |
| 155 | target_compile_definitions(yuzu PRIVATE -DYUZU_ENABLE_COMPATIBILITY_REPORTING) | 163 | target_compile_definitions(yuzu PRIVATE -DYUZU_ENABLE_COMPATIBILITY_REPORTING) |
| 156 | endif() | 164 | endif() |
diff --git a/src/yuzu/applets/error.cpp b/src/yuzu/applets/error.cpp new file mode 100644 index 000000000..1fb2fe277 --- /dev/null +++ b/src/yuzu/applets/error.cpp | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <QDateTime> | ||
| 6 | #include "core/hle/lock.h" | ||
| 7 | #include "yuzu/applets/error.h" | ||
| 8 | #include "yuzu/main.h" | ||
| 9 | |||
| 10 | QtErrorDisplay::QtErrorDisplay(GMainWindow& parent) { | ||
| 11 | connect(this, &QtErrorDisplay::MainWindowDisplayError, &parent, | ||
| 12 | &GMainWindow::ErrorDisplayDisplayError, Qt::QueuedConnection); | ||
| 13 | connect(&parent, &GMainWindow::ErrorDisplayFinished, this, | ||
| 14 | &QtErrorDisplay::MainWindowFinishedError, Qt::DirectConnection); | ||
| 15 | } | ||
| 16 | |||
| 17 | QtErrorDisplay::~QtErrorDisplay() = default; | ||
| 18 | |||
| 19 | void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished) const { | ||
| 20 | this->callback = std::move(finished); | ||
| 21 | emit MainWindowDisplayError( | ||
| 22 | tr("An error has occured.\nPlease try again or contact the developer of the " | ||
| 23 | "software.\n\nError Code: %1-%2 (0x%3)") | ||
| 24 | .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) | ||
| 25 | .arg(error.description, 4, 10, QChar::fromLatin1('0')) | ||
| 26 | .arg(error.raw, 8, 16, QChar::fromLatin1('0'))); | ||
| 27 | } | ||
| 28 | |||
| 29 | void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, | ||
| 30 | std::function<void()> finished) const { | ||
| 31 | this->callback = std::move(finished); | ||
| 32 | emit MainWindowDisplayError( | ||
| 33 | tr("An error occured on %1 at %2.\nPlease try again or contact the " | ||
| 34 | "developer of the software.\n\nError Code: %3-%4 (0x%5)") | ||
| 35 | .arg(QDateTime::fromSecsSinceEpoch(time.count()).toString("dddd, MMMM d, yyyy")) | ||
| 36 | .arg(QDateTime::fromSecsSinceEpoch(time.count()).toString("h:mm:ss A")) | ||
| 37 | .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) | ||
| 38 | .arg(error.description, 4, 10, QChar::fromLatin1('0')) | ||
| 39 | .arg(error.raw, 8, 16, QChar::fromLatin1('0'))); | ||
| 40 | } | ||
| 41 | |||
| 42 | void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_text, | ||
| 43 | std::string fullscreen_text, | ||
| 44 | std::function<void()> finished) const { | ||
| 45 | this->callback = std::move(finished); | ||
| 46 | emit MainWindowDisplayError( | ||
| 47 | tr("An error has occured.\nError Code: %1-%2 (0x%3)\n\n%4\n\n%5") | ||
| 48 | .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) | ||
| 49 | .arg(error.description, 4, 10, QChar::fromLatin1('0')) | ||
| 50 | .arg(error.raw, 8, 16, QChar::fromLatin1('0')) | ||
| 51 | .arg(QString::fromStdString(dialog_text)) | ||
| 52 | .arg(QString::fromStdString(fullscreen_text))); | ||
| 53 | } | ||
| 54 | |||
| 55 | void QtErrorDisplay::MainWindowFinishedError() { | ||
| 56 | // Acquire the HLE mutex | ||
| 57 | std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||
| 58 | callback(); | ||
| 59 | } | ||
diff --git a/src/yuzu/applets/error.h b/src/yuzu/applets/error.h new file mode 100644 index 000000000..b0932d895 --- /dev/null +++ b/src/yuzu/applets/error.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <QObject> | ||
| 8 | |||
| 9 | #include "core/frontend/applets/error.h" | ||
| 10 | |||
| 11 | class GMainWindow; | ||
| 12 | |||
| 13 | class QtErrorDisplay final : public QObject, public Core::Frontend::ErrorApplet { | ||
| 14 | Q_OBJECT | ||
| 15 | |||
| 16 | public: | ||
| 17 | explicit QtErrorDisplay(GMainWindow& parent); | ||
| 18 | ~QtErrorDisplay() override; | ||
| 19 | |||
| 20 | void ShowError(ResultCode error, std::function<void()> finished) const override; | ||
| 21 | void ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, | ||
| 22 | std::function<void()> finished) const override; | ||
| 23 | void ShowCustomErrorText(ResultCode error, std::string dialog_text, std::string fullscreen_text, | ||
| 24 | std::function<void()> finished) const override; | ||
| 25 | |||
| 26 | signals: | ||
| 27 | void MainWindowDisplayError(QString error) const; | ||
| 28 | |||
| 29 | private: | ||
| 30 | void MainWindowFinishedError(); | ||
| 31 | |||
| 32 | mutable std::function<void()> callback; | ||
| 33 | }; | ||
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index c29f2d2dc..5c98636c5 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -91,8 +91,8 @@ void EmuThread::run() { | |||
| 91 | 91 | ||
| 92 | class GGLContext : public Core::Frontend::GraphicsContext { | 92 | class GGLContext : public Core::Frontend::GraphicsContext { |
| 93 | public: | 93 | public: |
| 94 | explicit GGLContext(QOpenGLContext* shared_context) : surface() { | 94 | explicit GGLContext(QOpenGLContext* shared_context) |
| 95 | context = std::make_unique<QOpenGLContext>(shared_context); | 95 | : context{std::make_unique<QOpenGLContext>(shared_context)} { |
| 96 | surface.setFormat(shared_context->format()); | 96 | surface.setFormat(shared_context->format()); |
| 97 | surface.create(); | 97 | surface.create(); |
| 98 | } | 98 | } |
| @@ -186,8 +186,7 @@ private: | |||
| 186 | }; | 186 | }; |
| 187 | 187 | ||
| 188 | GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) | 188 | GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) |
| 189 | : QWidget(parent), child(nullptr), context(nullptr), emu_thread(emu_thread) { | 189 | : QWidget(parent), emu_thread(emu_thread) { |
| 190 | |||
| 191 | setWindowTitle(QStringLiteral("yuzu %1 | %2-%3") | 190 | setWindowTitle(QStringLiteral("yuzu %1 | %2-%3") |
| 192 | .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); | 191 | .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); |
| 193 | setAttribute(Qt::WA_AcceptTouchEvents); | 192 | setAttribute(Qt::WA_AcceptTouchEvents); |
| @@ -378,7 +377,11 @@ void GRenderWindow::InitRenderTarget() { | |||
| 378 | // WA_DontShowOnScreen, WA_DeleteOnClose | 377 | // WA_DontShowOnScreen, WA_DeleteOnClose |
| 379 | QSurfaceFormat fmt; | 378 | QSurfaceFormat fmt; |
| 380 | fmt.setVersion(4, 3); | 379 | fmt.setVersion(4, 3); |
| 381 | fmt.setProfile(QSurfaceFormat::CoreProfile); | 380 | if (Settings::values.use_compatibility_profile) { |
| 381 | fmt.setProfile(QSurfaceFormat::CompatibilityProfile); | ||
| 382 | } else { | ||
| 383 | fmt.setProfile(QSurfaceFormat::CoreProfile); | ||
| 384 | } | ||
| 382 | // TODO: expose a setting for buffer value (ie default/single/double/triple) | 385 | // TODO: expose a setting for buffer value (ie default/single/double/triple) |
| 383 | fmt.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior); | 386 | fmt.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior); |
| 384 | shared_context = std::make_unique<QOpenGLContext>(); | 387 | shared_context = std::make_unique<QOpenGLContext>(); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 9608b959f..3df33aca1 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include <QImage> | 10 | #include <QImage> |
| 11 | #include <QThread> | 11 | #include <QThread> |
| 12 | #include <QWidget> | 12 | #include <QWidget> |
| 13 | #include "common/thread.h" | ||
| 14 | #include "core/core.h" | 13 | #include "core/core.h" |
| 15 | #include "core/frontend/emu_window.h" | 14 | #include "core/frontend/emu_window.h" |
| 16 | 15 | ||
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 8725a78dc..6c6f047d8 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -389,6 +389,8 @@ void Config::ReadValues() { | |||
| 389 | Settings::values.resolution_factor = ReadSetting("resolution_factor", 1.0).toFloat(); | 389 | Settings::values.resolution_factor = ReadSetting("resolution_factor", 1.0).toFloat(); |
| 390 | Settings::values.use_frame_limit = ReadSetting("use_frame_limit", true).toBool(); | 390 | Settings::values.use_frame_limit = ReadSetting("use_frame_limit", true).toBool(); |
| 391 | Settings::values.frame_limit = ReadSetting("frame_limit", 100).toInt(); | 391 | Settings::values.frame_limit = ReadSetting("frame_limit", 100).toInt(); |
| 392 | Settings::values.use_compatibility_profile = | ||
| 393 | ReadSetting("use_compatibility_profile", true).toBool(); | ||
| 392 | Settings::values.use_disk_shader_cache = ReadSetting("use_disk_shader_cache", true).toBool(); | 394 | Settings::values.use_disk_shader_cache = ReadSetting("use_disk_shader_cache", true).toBool(); |
| 393 | Settings::values.use_accurate_gpu_emulation = | 395 | Settings::values.use_accurate_gpu_emulation = |
| 394 | ReadSetting("use_accurate_gpu_emulation", false).toBool(); | 396 | ReadSetting("use_accurate_gpu_emulation", false).toBool(); |
| @@ -661,6 +663,7 @@ void Config::SaveValues() { | |||
| 661 | WriteSetting("resolution_factor", (double)Settings::values.resolution_factor, 1.0); | 663 | WriteSetting("resolution_factor", (double)Settings::values.resolution_factor, 1.0); |
| 662 | WriteSetting("use_frame_limit", Settings::values.use_frame_limit, true); | 664 | WriteSetting("use_frame_limit", Settings::values.use_frame_limit, true); |
| 663 | WriteSetting("frame_limit", Settings::values.frame_limit, 100); | 665 | WriteSetting("frame_limit", Settings::values.frame_limit, 100); |
| 666 | WriteSetting("use_compatibility_profile", Settings::values.use_compatibility_profile, true); | ||
| 664 | WriteSetting("use_disk_shader_cache", Settings::values.use_disk_shader_cache, true); | 667 | WriteSetting("use_disk_shader_cache", Settings::values.use_disk_shader_cache, true); |
| 665 | WriteSetting("use_accurate_gpu_emulation", Settings::values.use_accurate_gpu_emulation, false); | 668 | WriteSetting("use_accurate_gpu_emulation", Settings::values.use_accurate_gpu_emulation, false); |
| 666 | WriteSetting("use_asynchronous_gpu_emulation", Settings::values.use_asynchronous_gpu_emulation, | 669 | WriteSetting("use_asynchronous_gpu_emulation", Settings::values.use_asynchronous_gpu_emulation, |
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 51bd1f121..a5218b051 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | #include "yuzu/hotkeys.h" | 12 | #include "yuzu/hotkeys.h" |
| 13 | 13 | ||
| 14 | ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry) | 14 | ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry) |
| 15 | : QDialog(parent), registry(registry), ui(new Ui::ConfigureDialog) { | 15 | : QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) { |
| 16 | ui->setupUi(this); | 16 | ui->setupUi(this); |
| 17 | ui->hotkeysTab->Populate(registry); | 17 | ui->hotkeysTab->Populate(registry); |
| 18 | this->setConfiguration(); | 18 | this->setConfiguration(); |
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 0a9883d37..c299c0b5b 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp | |||
| @@ -73,6 +73,7 @@ void ConfigureGraphics::setConfiguration() { | |||
| 73 | static_cast<int>(FromResolutionFactor(Settings::values.resolution_factor))); | 73 | static_cast<int>(FromResolutionFactor(Settings::values.resolution_factor))); |
| 74 | ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); | 74 | ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); |
| 75 | ui->frame_limit->setValue(Settings::values.frame_limit); | 75 | ui->frame_limit->setValue(Settings::values.frame_limit); |
| 76 | ui->use_compatibility_profile->setChecked(Settings::values.use_compatibility_profile); | ||
| 76 | ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache); | 77 | ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache); |
| 77 | ui->use_accurate_gpu_emulation->setChecked(Settings::values.use_accurate_gpu_emulation); | 78 | ui->use_accurate_gpu_emulation->setChecked(Settings::values.use_accurate_gpu_emulation); |
| 78 | ui->use_asynchronous_gpu_emulation->setEnabled(!Core::System::GetInstance().IsPoweredOn()); | 79 | ui->use_asynchronous_gpu_emulation->setEnabled(!Core::System::GetInstance().IsPoweredOn()); |
| @@ -88,6 +89,7 @@ void ConfigureGraphics::applyConfiguration() { | |||
| 88 | ToResolutionFactor(static_cast<Resolution>(ui->resolution_factor_combobox->currentIndex())); | 89 | ToResolutionFactor(static_cast<Resolution>(ui->resolution_factor_combobox->currentIndex())); |
| 89 | Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); | 90 | Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); |
| 90 | Settings::values.frame_limit = ui->frame_limit->value(); | 91 | Settings::values.frame_limit = ui->frame_limit->value(); |
| 92 | Settings::values.use_compatibility_profile = ui->use_compatibility_profile->isChecked(); | ||
| 91 | Settings::values.use_disk_shader_cache = ui->use_disk_shader_cache->isChecked(); | 93 | Settings::values.use_disk_shader_cache = ui->use_disk_shader_cache->isChecked(); |
| 92 | Settings::values.use_accurate_gpu_emulation = ui->use_accurate_gpu_emulation->isChecked(); | 94 | Settings::values.use_accurate_gpu_emulation = ui->use_accurate_gpu_emulation->isChecked(); |
| 93 | Settings::values.use_asynchronous_gpu_emulation = | 95 | Settings::values.use_asynchronous_gpu_emulation = |
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 15ab18ecd..0f6f6c003 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui | |||
| @@ -50,6 +50,13 @@ | |||
| 50 | </layout> | 50 | </layout> |
| 51 | </item> | 51 | </item> |
| 52 | <item> | 52 | <item> |
| 53 | <widget class="QCheckBox" name="use_compatibility_profile"> | ||
| 54 | <property name="text"> | ||
| 55 | <string>Use OpenGL compatibility profile</string> | ||
| 56 | </property> | ||
| 57 | </widget> | ||
| 58 | </item> | ||
| 59 | <item> | ||
| 53 | <widget class="QCheckBox" name="use_disk_shader_cache"> | 60 | <widget class="QCheckBox" name="use_disk_shader_cache"> |
| 54 | <property name="text"> | 61 | <property name="text"> |
| 55 | <string>Use disk shader cache</string> | 62 | <string>Use disk shader cache</string> |
diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index bfb562535..a7a8752e5 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp | |||
| @@ -66,20 +66,21 @@ void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { | |||
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | void ConfigureHotkeys::Configure(QModelIndex index) { | 68 | void ConfigureHotkeys::Configure(QModelIndex index) { |
| 69 | if (index.parent() == QModelIndex()) | 69 | if (!index.parent().isValid()) { |
| 70 | return; | 70 | return; |
| 71 | } | ||
| 71 | 72 | ||
| 72 | index = index.sibling(index.row(), 1); | 73 | index = index.sibling(index.row(), 1); |
| 73 | auto* model = ui->hotkey_list->model(); | 74 | auto* const model = ui->hotkey_list->model(); |
| 74 | auto previous_key = model->data(index); | 75 | const auto previous_key = model->data(index); |
| 75 | |||
| 76 | auto* hotkey_dialog = new SequenceDialog; | ||
| 77 | int return_code = hotkey_dialog->exec(); | ||
| 78 | 76 | ||
| 79 | auto key_sequence = hotkey_dialog->GetSequence(); | 77 | SequenceDialog hotkey_dialog{this}; |
| 80 | 78 | ||
| 81 | if (return_code == QDialog::Rejected || key_sequence.isEmpty()) | 79 | const int return_code = hotkey_dialog.exec(); |
| 80 | const auto key_sequence = hotkey_dialog.GetSequence(); | ||
| 81 | if (return_code == QDialog::Rejected || key_sequence.isEmpty()) { | ||
| 82 | return; | 82 | return; |
| 83 | } | ||
| 83 | 84 | ||
| 84 | if (IsUsedKey(key_sequence) && key_sequence != QKeySequence(previous_key.toString())) { | 85 | if (IsUsedKey(key_sequence) && key_sequence != QKeySequence(previous_key.toString())) { |
| 85 | QMessageBox::critical(this, tr("Error in inputted key"), | 86 | QMessageBox::critical(this, tr("Error in inputted key"), |
| @@ -90,7 +91,7 @@ void ConfigureHotkeys::Configure(QModelIndex index) { | |||
| 90 | } | 91 | } |
| 91 | } | 92 | } |
| 92 | 93 | ||
| 93 | bool ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) { | 94 | bool ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) const { |
| 94 | return GetUsedKeyList().contains(key_sequence); | 95 | return GetUsedKeyList().contains(key_sequence); |
| 95 | } | 96 | } |
| 96 | 97 | ||
diff --git a/src/yuzu/configuration/configure_hotkeys.h b/src/yuzu/configuration/configure_hotkeys.h index cd203aad6..73fb8a175 100644 --- a/src/yuzu/configuration/configure_hotkeys.h +++ b/src/yuzu/configuration/configure_hotkeys.h | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <QWidget> | 8 | #include <QWidget> |
| 9 | #include "core/settings.h" | ||
| 10 | 9 | ||
| 11 | namespace Ui { | 10 | namespace Ui { |
| 12 | class ConfigureHotkeys; | 11 | class ConfigureHotkeys; |
| @@ -39,7 +38,7 @@ signals: | |||
| 39 | 38 | ||
| 40 | private: | 39 | private: |
| 41 | void Configure(QModelIndex index); | 40 | void Configure(QModelIndex index); |
| 42 | bool IsUsedKey(QKeySequence key_sequence); | 41 | bool IsUsedKey(QKeySequence key_sequence) const; |
| 43 | QList<QKeySequence> GetUsedKeyList() const; | 42 | QList<QKeySequence> GetUsedKeyList() const; |
| 44 | 43 | ||
| 45 | std::unique_ptr<Ui::ConfigureHotkeys> ui; | 44 | std::unique_ptr<Ui::ConfigureHotkeys> ui; |
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 593bb681f..85b095688 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp | |||
| @@ -227,8 +227,7 @@ QString WaitTreeThread::GetText() const { | |||
| 227 | case Kernel::ThreadStatus::WaitIPC: | 227 | case Kernel::ThreadStatus::WaitIPC: |
| 228 | status = tr("waiting for IPC reply"); | 228 | status = tr("waiting for IPC reply"); |
| 229 | break; | 229 | break; |
| 230 | case Kernel::ThreadStatus::WaitSynchAll: | 230 | case Kernel::ThreadStatus::WaitSynch: |
| 231 | case Kernel::ThreadStatus::WaitSynchAny: | ||
| 232 | status = tr("waiting for objects"); | 231 | status = tr("waiting for objects"); |
| 233 | break; | 232 | break; |
| 234 | case Kernel::ThreadStatus::WaitMutex: | 233 | case Kernel::ThreadStatus::WaitMutex: |
| @@ -269,8 +268,7 @@ QColor WaitTreeThread::GetColor() const { | |||
| 269 | return QColor(Qt::GlobalColor::darkRed); | 268 | return QColor(Qt::GlobalColor::darkRed); |
| 270 | case Kernel::ThreadStatus::WaitSleep: | 269 | case Kernel::ThreadStatus::WaitSleep: |
| 271 | return QColor(Qt::GlobalColor::darkYellow); | 270 | return QColor(Qt::GlobalColor::darkYellow); |
| 272 | case Kernel::ThreadStatus::WaitSynchAll: | 271 | case Kernel::ThreadStatus::WaitSynch: |
| 273 | case Kernel::ThreadStatus::WaitSynchAny: | ||
| 274 | case Kernel::ThreadStatus::WaitMutex: | 272 | case Kernel::ThreadStatus::WaitMutex: |
| 275 | case Kernel::ThreadStatus::WaitCondVar: | 273 | case Kernel::ThreadStatus::WaitCondVar: |
| 276 | case Kernel::ThreadStatus::WaitArb: | 274 | case Kernel::ThreadStatus::WaitArb: |
| @@ -325,10 +323,9 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { | |||
| 325 | list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); | 323 | list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); |
| 326 | } | 324 | } |
| 327 | 325 | ||
| 328 | if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynchAny || | 326 | if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) { |
| 329 | thread.GetStatus() == Kernel::ThreadStatus::WaitSynchAll) { | ||
| 330 | list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjects(), | 327 | list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjects(), |
| 331 | thread.IsSleepingOnWaitAll())); | 328 | thread.IsSleepingOnWait())); |
| 332 | } | 329 | } |
| 333 | 330 | ||
| 334 | list.push_back(std::make_unique<WaitTreeCallstack>(thread)); | 331 | list.push_back(std::make_unique<WaitTreeCallstack>(thread)); |
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index 3db0e90da..2cf5c58a0 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h | |||
| @@ -95,7 +95,7 @@ public: | |||
| 95 | if (row2.isEmpty()) | 95 | if (row2.isEmpty()) |
| 96 | return row1; | 96 | return row1; |
| 97 | 97 | ||
| 98 | return row1 + "\n " + row2; | 98 | return QString(row1 + "\n " + row2); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | return GameListItem::data(role); | 101 | return GameListItem::data(role); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index bdee44b04..e33e3aaaf 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <thread> | 8 | #include <thread> |
| 9 | 9 | ||
| 10 | // VFS includes must be before glad as they will conflict with Windows file api, which uses defines. | 10 | // VFS includes must be before glad as they will conflict with Windows file api, which uses defines. |
| 11 | #include "applets/error.h" | ||
| 11 | #include "applets/profile_select.h" | 12 | #include "applets/profile_select.h" |
| 12 | #include "applets/software_keyboard.h" | 13 | #include "applets/software_keyboard.h" |
| 13 | #include "applets/web_browser.h" | 14 | #include "applets/web_browser.h" |
| @@ -15,6 +16,7 @@ | |||
| 15 | #include "configuration/configure_per_general.h" | 16 | #include "configuration/configure_per_general.h" |
| 16 | #include "core/file_sys/vfs.h" | 17 | #include "core/file_sys/vfs.h" |
| 17 | #include "core/file_sys/vfs_real.h" | 18 | #include "core/file_sys/vfs_real.h" |
| 19 | #include "core/frontend/applets/general_frontend.h" | ||
| 18 | #include "core/frontend/scope_acquire_window_context.h" | 20 | #include "core/frontend/scope_acquire_window_context.h" |
| 19 | #include "core/hle/service/acc/profile_manager.h" | 21 | #include "core/hle/service/acc/profile_manager.h" |
| 20 | #include "core/hle/service/am/applets/applets.h" | 22 | #include "core/hle/service/am/applets/applets.h" |
| @@ -795,9 +797,13 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 795 | 797 | ||
| 796 | system.SetGPUDebugContext(debug_context); | 798 | system.SetGPUDebugContext(debug_context); |
| 797 | 799 | ||
| 798 | system.SetProfileSelector(std::make_unique<QtProfileSelector>(*this)); | 800 | system.SetAppletFrontendSet({ |
| 799 | system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this)); | 801 | std::make_unique<QtErrorDisplay>(*this), |
| 800 | system.SetWebBrowser(std::make_unique<QtWebBrowser>(*this)); | 802 | nullptr, |
| 803 | std::make_unique<QtProfileSelector>(*this), | ||
| 804 | std::make_unique<QtSoftwareKeyboard>(*this), | ||
| 805 | std::make_unique<QtWebBrowser>(*this), | ||
| 806 | }); | ||
| 801 | 807 | ||
| 802 | const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; | 808 | const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; |
| 803 | 809 | ||
| @@ -1583,6 +1589,11 @@ void GMainWindow::OnLoadComplete() { | |||
| 1583 | loading_screen->OnLoadComplete(); | 1589 | loading_screen->OnLoadComplete(); |
| 1584 | } | 1590 | } |
| 1585 | 1591 | ||
| 1592 | void GMainWindow::ErrorDisplayDisplayError(QString body) { | ||
| 1593 | QMessageBox::critical(this, tr("Error Display"), body); | ||
| 1594 | emit ErrorDisplayFinished(); | ||
| 1595 | } | ||
| 1596 | |||
| 1586 | void GMainWindow::OnMenuReportCompatibility() { | 1597 | void GMainWindow::OnMenuReportCompatibility() { |
| 1587 | if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) { | 1598 | if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) { |
| 1588 | CompatDB compatdb{this}; | 1599 | CompatDB compatdb{this}; |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index ce5045819..fb2a193cb 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -102,6 +102,8 @@ signals: | |||
| 102 | // Signal that tells widgets to update icons to use the current theme | 102 | // Signal that tells widgets to update icons to use the current theme |
| 103 | void UpdateThemedIcons(); | 103 | void UpdateThemedIcons(); |
| 104 | 104 | ||
| 105 | void ErrorDisplayFinished(); | ||
| 106 | |||
| 105 | void ProfileSelectorFinishedSelection(std::optional<Service::Account::UUID> uuid); | 107 | void ProfileSelectorFinishedSelection(std::optional<Service::Account::UUID> uuid); |
| 106 | void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); | 108 | void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); |
| 107 | void SoftwareKeyboardFinishedCheckDialog(); | 109 | void SoftwareKeyboardFinishedCheckDialog(); |
| @@ -111,6 +113,7 @@ signals: | |||
| 111 | 113 | ||
| 112 | public slots: | 114 | public slots: |
| 113 | void OnLoadComplete(); | 115 | void OnLoadComplete(); |
| 116 | void ErrorDisplayDisplayError(QString body); | ||
| 114 | void ProfileSelectorSelectProfile(); | 117 | void ProfileSelectorSelectProfile(); |
| 115 | void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); | 118 | void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); |
| 116 | void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); | 119 | void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); |
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index f24cc77fe..d0ae058fd 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp | |||
| @@ -349,6 +349,8 @@ void Config::ReadValues() { | |||
| 349 | Settings::values.use_frame_limit = sdl2_config->GetBoolean("Renderer", "use_frame_limit", true); | 349 | Settings::values.use_frame_limit = sdl2_config->GetBoolean("Renderer", "use_frame_limit", true); |
| 350 | Settings::values.frame_limit = | 350 | Settings::values.frame_limit = |
| 351 | static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100)); | 351 | static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100)); |
| 352 | Settings::values.use_compatibility_profile = | ||
| 353 | sdl2_config->GetBoolean("Renderer", "use_compatibility_profile", true); | ||
| 352 | Settings::values.use_disk_shader_cache = | 354 | Settings::values.use_disk_shader_cache = |
| 353 | sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false); | 355 | sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false); |
| 354 | Settings::values.use_accurate_gpu_emulation = | 356 | Settings::values.use_accurate_gpu_emulation = |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 7ea4a1b18..a1d7879b1 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -32,11 +32,7 @@ | |||
| 32 | #include "yuzu_cmd/config.h" | 32 | #include "yuzu_cmd/config.h" |
| 33 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" | 33 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" |
| 34 | 34 | ||
| 35 | #include <getopt.h> | ||
| 36 | #include "core/file_sys/registered_cache.h" | 35 | #include "core/file_sys/registered_cache.h" |
| 37 | #ifndef _MSC_VER | ||
| 38 | #include <unistd.h> | ||
| 39 | #endif | ||
| 40 | 36 | ||
| 41 | #ifdef _WIN32 | 37 | #ifdef _WIN32 |
| 42 | // windows.h needs to be included before shellapi.h | 38 | // windows.h needs to be included before shellapi.h |
| @@ -45,6 +41,12 @@ | |||
| 45 | #include <shellapi.h> | 41 | #include <shellapi.h> |
| 46 | #endif | 42 | #endif |
| 47 | 43 | ||
| 44 | #undef _UNICODE | ||
| 45 | #include <getopt.h> | ||
| 46 | #ifndef _MSC_VER | ||
| 47 | #include <unistd.h> | ||
| 48 | #endif | ||
| 49 | |||
| 48 | #ifdef _WIN32 | 50 | #ifdef _WIN32 |
| 49 | extern "C" { | 51 | extern "C" { |
| 50 | // tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable | 52 | // tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable |