summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/lz4_compression.h2
-rw-r--r--src/common/zstd_compression.h2
-rw-r--r--src/core/arm/arm_interface.h14
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp23
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h6
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h2
-rw-r--r--src/core/core.cpp33
-rw-r--r--src/core/cpu_core_manager.cpp6
-rw-r--r--src/core/cpu_core_manager.h7
-rw-r--r--src/core/hle/kernel/kernel.cpp7
-rw-r--r--src/core/hle/kernel/process.cpp22
-rw-r--r--src/core/hle/kernel/process.h7
-rw-r--r--src/core/hle/kernel/svc.cpp160
-rw-r--r--src/core/hle/kernel/svc_wrap.h7
-rw-r--r--src/core/hle/kernel/thread.cpp5
-rw-r--r--src/core/hle/kernel/thread.h18
-rw-r--r--src/core/hle/kernel/vm_manager.cpp80
-rw-r--r--src/core/hle/kernel/vm_manager.h49
-rw-r--r--src/core/hle/kernel/wait_object.cpp2
-rw-r--r--src/core/hle/kernel/wait_object.h2
-rw-r--r--src/core/hle/service/acc/acc.cpp4
-rw-r--r--src/core/hle/service/acc/acc_su.cpp6
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp8
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp6
-rw-r--r--src/core/hle/service/am/am.cpp16
-rw-r--r--src/core/hle/service/am/applet_ae.cpp8
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp4
-rw-r--r--src/core/hle/service/apm/interface.cpp2
-rw-r--r--src/core/hle/service/audio/audin_u.cpp1
-rw-r--r--src/core/hle/service/audio/audout_u.cpp5
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp3
-rw-r--r--src/core/hle/service/caps/caps.cpp89
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp7
-rw-r--r--src/core/hle/service/friend/friend.cpp5
-rw-r--r--src/core/hle/service/hid/hid.cpp15
-rw-r--r--src/core/hle/service/ldn/ldn.cpp54
-rw-r--r--src/core/hle/service/ldr/ldr.cpp1
-rw-r--r--src/core/hle/service/nifm/nifm.cpp4
-rw-r--r--src/core/hle/service/npns/npns.cpp3
-rw-r--r--src/core/hle/service/pctl/module.cpp7
-rw-r--r--src/core/hle/service/pm/pm.cpp21
-rw-r--r--src/core/hle/service/set/set.cpp4
-rw-r--r--src/core/hle/service/set/set_cal.cpp2
-rw-r--r--src/core/hle/service/set/set_sys.cpp27
-rw-r--r--src/core/hle/service/sockets/bsd.cpp5
-rw-r--r--src/core/hle/service/ssl/ssl.cpp2
-rw-r--r--src/core/hle/service/time/interface.cpp10
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp40
-rw-r--r--src/core/loader/deconstructed_rom_directory.h2
-rw-r--r--src/core/loader/elf.cpp15
-rw-r--r--src/core/loader/elf.h2
-rw-r--r--src/core/loader/loader.h8
-rw-r--r--src/core/loader/nax.cpp30
-rw-r--r--src/core/loader/nax.h2
-rw-r--r--src/core/loader/nca.cpp26
-rw-r--r--src/core/loader/nca.h2
-rw-r--r--src/core/loader/nro.cpp14
-rw-r--r--src/core/loader/nro.h2
-rw-r--r--src/core/loader/nso.cpp11
-rw-r--r--src/core/loader/nso.h2
-rw-r--r--src/core/loader/nsp.cpp38
-rw-r--r--src/core/loader/nsp.h2
-rw-r--r--src/core/loader/xci.cpp28
-rw-r--r--src/core/loader/xci.h2
-rw-r--r--src/core/memory.cpp16
-rw-r--r--src/core/memory.h5
-rw-r--r--src/video_core/CMakeLists.txt4
-rw-r--r--src/video_core/engines/maxwell_3d.cpp39
-rw-r--r--src/video_core/engines/maxwell_3d.h6
-rw-r--r--src/video_core/engines/shader_bytecode.h58
-rw-r--r--src/video_core/gpu.h5
-rw-r--r--src/video_core/gpu_asynch.cpp6
-rw-r--r--src/video_core/gpu_asynch.h5
-rw-r--r--src/video_core/gpu_synch.cpp4
-rw-r--r--src/video_core/gpu_synch.h1
-rw-r--r--src/video_core/gpu_thread.cpp17
-rw-r--r--src/video_core/gpu_thread.h6
-rw-r--r--src/video_core/renderer_opengl/gl_global_cache.cpp42
-rw-r--r--src/video_core/renderer_opengl/gl_global_cache.h16
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp116
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h36
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_sampler_cache.cpp52
-rw-r--r--src/video_core/renderer_opengl/gl_sampler_cache.h25
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp36
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.h18
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp27
-rw-r--r--src/video_core/renderer_vulkan/vk_sampler_cache.cpp40
-rw-r--r--src/video_core/renderer_vulkan/vk_sampler_cache.h36
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp14
-rw-r--r--src/video_core/sampler_cache.cpp21
-rw-r--r--src/video_core/sampler_cache.h60
-rw-r--r--src/video_core/shader/decode/memory.cpp118
-rw-r--r--src/video_core/shader/decode/texture.cpp113
-rw-r--r--src/video_core/shader/shader_ir.h56
-rw-r--r--src/video_core/video_core.cpp10
-rw-r--r--src/video_core/video_core.h7
-rw-r--r--src/yuzu/CMakeLists.txt6
-rw-r--r--src/yuzu/bootmanager.cpp7
-rw-r--r--src/yuzu/bootmanager.h1
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp2
-rw-r--r--src/yuzu/configuration/configure_hotkeys.cpp19
-rw-r--r--src/yuzu/configuration/configure_hotkeys.h3
-rw-r--r--src/yuzu/game_list_p.h2
104 files changed, 1446 insertions, 613 deletions
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/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
10namespace Common {
11struct PageTable;
12}
13
10namespace Kernel { 14namespace Kernel {
11enum class VMAPermission : u8; 15enum 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
132std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { 131std::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
186ARM_Dynarmic::~ARM_Dynarmic() = default; 178ARM_Dynarmic::~ARM_Dynarmic() = default;
187 179
@@ -276,8 +268,9 @@ void ARM_Dynarmic::ClearExclusiveState() {
276 jit->ClearExclusiveState(); 268 jit->ClearExclusiveState();
277} 269}
278 270
279void ARM_Dynarmic::PageTableChanged() { 271void 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
283DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {} 276DynarmicExclusiveMonitor::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
53private: 54private:
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
47private: 47private:
diff --git a/src/core/core.cpp b/src/core/core.cpp
index bc9e887b6..175a5f2ea 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"
@@ -38,8 +36,6 @@
38#include "frontend/applets/software_keyboard.h" 36#include "frontend/applets/software_keyboard.h"
39#include "frontend/applets/web_browser.h" 37#include "frontend/applets/web_browser.h"
40#include "video_core/debug_utils/debug_utils.h" 38#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" 39#include "video_core/renderer_base.h"
44#include "video_core/video_core.h" 40#include "video_core/video_core.h"
45 41
@@ -81,7 +77,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
81 return vfs->OpenFile(path, FileSys::Mode::Read); 77 return vfs->OpenFile(path, FileSys::Mode::Read);
82} 78}
83struct System::Impl { 79struct System::Impl {
84 explicit Impl(System& system) : kernel{system} {} 80 explicit Impl(System& system) : kernel{system}, cpu_core_manager{system} {}
85 81
86 Cpu& CurrentCpuCore() { 82 Cpu& CurrentCpuCore() {
87 return cpu_core_manager.GetCurrentCore(); 83 return cpu_core_manager.GetCurrentCore();
@@ -99,6 +95,7 @@ struct System::Impl {
99 LOG_DEBUG(HW_Memory, "initialized OK"); 95 LOG_DEBUG(HW_Memory, "initialized OK");
100 96
101 core_timing.Initialize(); 97 core_timing.Initialize();
98 cpu_core_manager.Initialize();
102 kernel.Initialize(); 99 kernel.Initialize();
103 100
104 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( 101 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
@@ -120,9 +117,6 @@ struct System::Impl {
120 if (web_browser == nullptr) 117 if (web_browser == nullptr)
121 web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); 118 web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
122 119
123 auto main_process = Kernel::Process::Create(system, "main");
124 kernel.MakeCurrentProcess(main_process.get());
125
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>();
128 122
@@ -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
139 if (Settings::values.use_asynchronous_gpu_emulation) {
140 gpu_core = std::make_unique<VideoCommon::GPUAsynch>(system, *renderer);
141 } else {
142 gpu_core = std::make_unique<VideoCommon::GPUSynch>(system, *renderer);
143 }
144 132
145 cpu_core_manager.Initialize(system); 133 is_powered_on = true;
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;
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
22CpuCoreManager::CpuCoreManager() = default; 22CpuCoreManager::CpuCoreManager(System& system) : system{system} {}
23CpuCoreManager::~CpuCoreManager() = default; 23CpuCoreManager::~CpuCoreManager() = default;
24 24
25void CpuCoreManager::Initialize(System& system) { 25void 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
34void 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
19class CpuCoreManager { 19class CpuCoreManager {
20public: 20public:
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/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4d58e7c69..8539fabe4 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -182,7 +182,12 @@ void KernelCore::AppendNewProcess(SharedPtr<Process> process) {
182 182
183void KernelCore::MakeCurrentProcess(Process* process) { 183void KernelCore::MakeCurrentProcess(Process* process) {
184 impl->current_process = process; 184 impl->current_process = process;
185 Memory::SetCurrentPageTable(&process->VMManager().page_table); 185
186 if (process == nullptr) {
187 return;
188 }
189
190 Memory::SetCurrentPageTable(*process);
186} 191}
187 192
188Process* KernelCore::CurrentProcess() { 193Process* KernelCore::CurrentProcess() {
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 4e94048da..6d7a7e754 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 */
34void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_point, u32 priority) { 33void 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
122void Process::Run(VAddr entry_point, s32 main_thread_priority, u64 stack_size) { 119void 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
141void Process::PrepareForTermination() { 138void Process::PrepareForTermination() {
@@ -242,9 +239,6 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
242 MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeData); 239 MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeData);
243 240
244 code_memory_size += module_.memory.size(); 241 code_memory_size += module_.memory.size();
245
246 // Clear instruction cache in CPU JIT
247 system.InvalidateCpuInstructionCaches();
248} 242}
249 243
250Process::Process(Core::System& system) 244Process::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..4c763b288 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1189,6 +1189,142 @@ static ResultCode QueryMemory(Core::System& system, VAddr memory_info_address,
1189 query_address); 1189 query_address);
1190} 1190}
1191 1191
1192static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
1193 u64 src_address, u64 size) {
1194 LOG_DEBUG(Kernel_SVC,
1195 "called. process_handle=0x{:08X}, dst_address=0x{:016X}, "
1196 "src_address=0x{:016X}, size=0x{:016X}",
1197 process_handle, dst_address, src_address, size);
1198
1199 if (!Common::Is4KBAligned(src_address)) {
1200 LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
1201 src_address);
1202 return ERR_INVALID_ADDRESS;
1203 }
1204
1205 if (!Common::Is4KBAligned(dst_address)) {
1206 LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
1207 dst_address);
1208 return ERR_INVALID_ADDRESS;
1209 }
1210
1211 if (size == 0 || !Common::Is4KBAligned(size)) {
1212 LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X})", size);
1213 return ERR_INVALID_SIZE;
1214 }
1215
1216 if (!IsValidAddressRange(dst_address, size)) {
1217 LOG_ERROR(Kernel_SVC,
1218 "Destination address range overflows the address space (dst_address=0x{:016X}, "
1219 "size=0x{:016X}).",
1220 dst_address, size);
1221 return ERR_INVALID_ADDRESS_STATE;
1222 }
1223
1224 if (!IsValidAddressRange(src_address, size)) {
1225 LOG_ERROR(Kernel_SVC,
1226 "Source address range overflows the address space (src_address=0x{:016X}, "
1227 "size=0x{:016X}).",
1228 src_address, size);
1229 return ERR_INVALID_ADDRESS_STATE;
1230 }
1231
1232 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1233 auto process = handle_table.Get<Process>(process_handle);
1234 if (!process) {
1235 LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
1236 process_handle);
1237 return ERR_INVALID_HANDLE;
1238 }
1239
1240 auto& vm_manager = process->VMManager();
1241 if (!vm_manager.IsWithinAddressSpace(src_address, size)) {
1242 LOG_ERROR(Kernel_SVC,
1243 "Source address range is not within the address space (src_address=0x{:016X}, "
1244 "size=0x{:016X}).",
1245 src_address, size);
1246 return ERR_INVALID_ADDRESS_STATE;
1247 }
1248
1249 if (!vm_manager.IsWithinASLRRegion(dst_address, size)) {
1250 LOG_ERROR(Kernel_SVC,
1251 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
1252 "size=0x{:016X}).",
1253 dst_address, size);
1254 return ERR_INVALID_MEMORY_RANGE;
1255 }
1256
1257 return vm_manager.MapCodeMemory(dst_address, src_address, size);
1258}
1259
1260ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
1261 u64 src_address, u64 size) {
1262 LOG_DEBUG(Kernel_SVC,
1263 "called. process_handle=0x{:08X}, dst_address=0x{:016X}, src_address=0x{:016X}, "
1264 "size=0x{:016X}",
1265 process_handle, dst_address, src_address, size);
1266
1267 if (!Common::Is4KBAligned(dst_address)) {
1268 LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
1269 dst_address);
1270 return ERR_INVALID_ADDRESS;
1271 }
1272
1273 if (!Common::Is4KBAligned(src_address)) {
1274 LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
1275 src_address);
1276 return ERR_INVALID_ADDRESS;
1277 }
1278
1279 if (size == 0 || Common::Is4KBAligned(size)) {
1280 LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size);
1281 return ERR_INVALID_SIZE;
1282 }
1283
1284 if (!IsValidAddressRange(dst_address, size)) {
1285 LOG_ERROR(Kernel_SVC,
1286 "Destination address range overflows the address space (dst_address=0x{:016X}, "
1287 "size=0x{:016X}).",
1288 dst_address, size);
1289 return ERR_INVALID_ADDRESS_STATE;
1290 }
1291
1292 if (!IsValidAddressRange(src_address, size)) {
1293 LOG_ERROR(Kernel_SVC,
1294 "Source address range overflows the address space (src_address=0x{:016X}, "
1295 "size=0x{:016X}).",
1296 src_address, size);
1297 return ERR_INVALID_ADDRESS_STATE;
1298 }
1299
1300 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1301 auto process = handle_table.Get<Process>(process_handle);
1302 if (!process) {
1303 LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
1304 process_handle);
1305 return ERR_INVALID_HANDLE;
1306 }
1307
1308 auto& vm_manager = process->VMManager();
1309 if (!vm_manager.IsWithinAddressSpace(src_address, size)) {
1310 LOG_ERROR(Kernel_SVC,
1311 "Source address range is not within the address space (src_address=0x{:016X}, "
1312 "size=0x{:016X}).",
1313 src_address, size);
1314 return ERR_INVALID_ADDRESS_STATE;
1315 }
1316
1317 if (!vm_manager.IsWithinASLRRegion(dst_address, size)) {
1318 LOG_ERROR(Kernel_SVC,
1319 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
1320 "size=0x{:016X}).",
1321 dst_address, size);
1322 return ERR_INVALID_MEMORY_RANGE;
1323 }
1324
1325 return vm_manager.UnmapCodeMemory(dst_address, src_address, size);
1326}
1327
1192/// Exits the current process 1328/// Exits the current process
1193static void ExitProcess(Core::System& system) { 1329static void ExitProcess(Core::System& system) {
1194 auto* current_process = system.Kernel().CurrentProcess(); 1330 auto* current_process = system.Kernel().CurrentProcess();
@@ -1244,20 +1380,22 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
1244 return ERR_INVALID_THREAD_PRIORITY; 1380 return ERR_INVALID_THREAD_PRIORITY;
1245 } 1381 }
1246 1382
1247 const std::string name = fmt::format("thread-{:X}", entry_point);
1248 auto& kernel = system.Kernel(); 1383 auto& kernel = system.Kernel();
1249 CASCADE_RESULT(SharedPtr<Thread> thread, 1384 CASCADE_RESULT(SharedPtr<Thread> thread,
1250 Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top, 1385 Thread::Create(kernel, "", entry_point, priority, arg, processor_id, stack_top,
1251 *current_process)); 1386 *current_process));
1252 1387
1253 const auto new_guest_handle = current_process->GetHandleTable().Create(thread); 1388 const auto new_thread_handle = current_process->GetHandleTable().Create(thread);
1254 if (new_guest_handle.Failed()) { 1389 if (new_thread_handle.Failed()) {
1255 LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", 1390 LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}",
1256 new_guest_handle.Code().raw); 1391 new_thread_handle.Code().raw);
1257 return new_guest_handle.Code(); 1392 return new_thread_handle.Code();
1258 } 1393 }
1259 thread->SetGuestHandle(*new_guest_handle); 1394 *out_handle = *new_thread_handle;
1260 *out_handle = *new_guest_handle; 1395
1396 // Set the thread name for debugging purposes.
1397 thread->SetName(
1398 fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle));
1261 1399
1262 system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); 1400 system.CpuCore(thread->GetProcessorID()).PrepareReschedule();
1263 1401
@@ -2152,7 +2290,7 @@ static const FunctionDef SVC_Table[] = {
2152 {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, 2290 {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
2153 {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, 2291 {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"},
2154 {0x35, SvcWrap<SignalToAddress>, "SignalToAddress"}, 2292 {0x35, SvcWrap<SignalToAddress>, "SignalToAddress"},
2155 {0x36, nullptr, "Unknown"}, 2293 {0x36, nullptr, "SynchronizePreemptionState"},
2156 {0x37, nullptr, "Unknown"}, 2294 {0x37, nullptr, "Unknown"},
2157 {0x38, nullptr, "Unknown"}, 2295 {0x38, nullptr, "Unknown"},
2158 {0x39, nullptr, "Unknown"}, 2296 {0x39, nullptr, "Unknown"},
@@ -2217,8 +2355,8 @@ static const FunctionDef SVC_Table[] = {
2217 {0x74, nullptr, "MapProcessMemory"}, 2355 {0x74, nullptr, "MapProcessMemory"},
2218 {0x75, nullptr, "UnmapProcessMemory"}, 2356 {0x75, nullptr, "UnmapProcessMemory"},
2219 {0x76, SvcWrap<QueryProcessMemory>, "QueryProcessMemory"}, 2357 {0x76, SvcWrap<QueryProcessMemory>, "QueryProcessMemory"},
2220 {0x77, nullptr, "MapProcessCodeMemory"}, 2358 {0x77, SvcWrap<MapProcessCodeMemory>, "MapProcessCodeMemory"},
2221 {0x78, nullptr, "UnmapProcessCodeMemory"}, 2359 {0x78, SvcWrap<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"},
2222 {0x79, nullptr, "CreateProcess"}, 2360 {0x79, nullptr, "CreateProcess"},
2223 {0x7A, nullptr, "StartProcess"}, 2361 {0x7A, nullptr, "StartProcess"},
2224 {0x7B, nullptr, "TerminateProcess"}, 2362 {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
47template <ResultCode func(Core::System&, u32, u64, u64, u64)>
48void 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
47template <ResultCode func(Core::System&, u32*)> 54template <ResultCode func(Core::System&, u32*)>
48void SvcWrap(Core::System& system) { 55void 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..ca52267b2 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -220,11 +220,6 @@ void Thread::SetPriority(u32 priority) {
220 UpdatePriority(); 220 UpdatePriority();
221} 221}
222 222
223void Thread::BoostPriority(u32 priority) {
224 scheduler->SetThreadPriority(this, priority);
225 current_priority = priority;
226}
227
228void Thread::SetWaitSynchronizationResult(ResultCode result) { 223void Thread::SetWaitSynchronizationResult(ResultCode result) {
229 context.cpu_registers[0] = result.raw; 224 context.cpu_registers[0] = result.raw;
230} 225}
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 83c83e45a..411a73b49 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -102,6 +102,11 @@ public:
102 std::string GetName() const override { 102 std::string GetName() const override {
103 return name; 103 return name;
104 } 104 }
105
106 void SetName(std::string new_name) {
107 name = std::move(new_name);
108 }
109
105 std::string GetTypeName() const override { 110 std::string GetTypeName() const override {
106 return "Thread"; 111 return "Thread";
107 } 112 }
@@ -136,12 +141,6 @@ public:
136 */ 141 */
137 void SetPriority(u32 priority); 142 void SetPriority(u32 priority);
138 143
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. 144 /// Adds a thread to the list of threads that are waiting for a lock held by this thread.
146 void AddMutexWaiter(SharedPtr<Thread> thread); 145 void AddMutexWaiter(SharedPtr<Thread> thread);
147 146
@@ -345,10 +344,6 @@ public:
345 arb_wait_address = address; 344 arb_wait_address = address;
346 } 345 }
347 346
348 void SetGuestHandle(Handle handle) {
349 guest_handle = handle;
350 }
351
352 bool HasWakeupCallback() const { 347 bool HasWakeupCallback() const {
353 return wakeup_callback != nullptr; 348 return wakeup_callback != nullptr;
354 } 349 }
@@ -442,9 +437,6 @@ private:
442 /// If waiting for an AddressArbiter, this is the address being waited on. 437 /// If waiting for an AddressArbiter, this is the address being waited on.
443 VAddr arb_wait_address{0}; 438 VAddr arb_wait_address{0};
444 439
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. 440 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
449 Handle callback_handle = 0; 441 Handle callback_handle = 0;
450 442
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
305ResultCode 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
334ResultCode 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
305MemoryInfo VMManager::QueryMemory(VAddr address) const { 385MemoryInfo 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
48constexpr VMAPermission operator|(VMAPermission lhs, VMAPermission rhs) { 51constexpr 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..c8eaf9488 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
33SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { 33SharedPtr<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
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:
137class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { 137class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
138public: 138public:
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
9ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager) 9ACC_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
9ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager) 9ACC_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
9ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager) 9ACC_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..1aa4ce1ac 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -224,6 +224,7 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {
224 {20, nullptr, "InvalidateTransitionLayer"}, 224 {20, nullptr, "InvalidateTransitionLayer"},
225 {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"}, 225 {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
226 {40, nullptr, "GetAppletResourceUsageInfo"}, 226 {40, nullptr, "GetAppletResourceUsageInfo"},
227 {41, nullptr, "SetCpuBoostModeForApplet"},
227 }; 228 };
228 // clang-format on 229 // clang-format on
229 230
@@ -256,6 +257,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
256 {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, 257 {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
257 {41, nullptr, "IsSystemBufferSharingEnabled"}, 258 {41, nullptr, "IsSystemBufferSharingEnabled"},
258 {42, nullptr, "GetSystemSharedLayerHandle"}, 259 {42, nullptr, "GetSystemSharedLayerHandle"},
260 {43, nullptr, "GetSystemSharedBufferHandle"},
259 {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, 261 {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
260 {51, nullptr, "ApproveToDisplay"}, 262 {51, nullptr, "ApproveToDisplay"},
261 {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, 263 {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
@@ -269,9 +271,11 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
269 {68, nullptr, "SetAutoSleepDisabled"}, 271 {68, nullptr, "SetAutoSleepDisabled"},
270 {69, nullptr, "IsAutoSleepDisabled"}, 272 {69, nullptr, "IsAutoSleepDisabled"},
271 {70, nullptr, "ReportMultimediaError"}, 273 {70, nullptr, "ReportMultimediaError"},
274 {71, nullptr, "GetCurrentIlluminanceEx"},
272 {80, nullptr, "SetWirelessPriorityMode"}, 275 {80, nullptr, "SetWirelessPriorityMode"},
273 {90, nullptr, "GetAccumulatedSuspendedTickValue"}, 276 {90, nullptr, "GetAccumulatedSuspendedTickValue"},
274 {91, nullptr, "GetAccumulatedSuspendedTickChangedEvent"}, 277 {91, nullptr, "GetAccumulatedSuspendedTickChangedEvent"},
278 {100, nullptr, "SetAlbumImageTakenNotificationEnabled"},
275 {1000, nullptr, "GetDebugStorageChannel"}, 279 {1000, nullptr, "GetDebugStorageChannel"},
276 }; 280 };
277 // clang-format on 281 // clang-format on
@@ -516,11 +520,20 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q
516 {50, nullptr, "IsVrModeEnabled"}, 520 {50, nullptr, "IsVrModeEnabled"},
517 {51, nullptr, "SetVrModeEnabled"}, 521 {51, nullptr, "SetVrModeEnabled"},
518 {52, nullptr, "SwitchLcdBacklight"}, 522 {52, nullptr, "SwitchLcdBacklight"},
523 {53, nullptr, "BeginVrModeEx"},
524 {54, nullptr, "EndVrModeEx"},
519 {55, nullptr, "IsInControllerFirmwareUpdateSection"}, 525 {55, nullptr, "IsInControllerFirmwareUpdateSection"},
520 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, 526 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
521 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, 527 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
522 {62, nullptr, "GetHdcpAuthenticationState"}, 528 {62, nullptr, "GetHdcpAuthenticationState"},
523 {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"}, 529 {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
530 {64, nullptr, "SetTvPowerStateMatchingMode"},
531 {65, nullptr, "GetApplicationIdByContentActionName"},
532 {66, nullptr, "SetCpuBoostMode"},
533 {80, nullptr, "PerformSystemButtonPressingIfInFocus"},
534 {90, nullptr, "SetPerformanceConfigurationChangedNotification"},
535 {91, nullptr, "GetCurrentPerformanceConfiguration"},
536 {200, nullptr, "GetOperationModeSystemInfo"},
524 }; 537 };
525 // clang-format on 538 // clang-format on
526 539
@@ -960,6 +973,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
960 {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"}, 973 {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
961 {12, nullptr, "CreateApplicationAndRequestToStart"}, 974 {12, nullptr, "CreateApplicationAndRequestToStart"},
962 {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"}, 975 {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"},
976 {14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
977 {15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
963 {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"}, 978 {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"},
964 {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"}, 979 {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"},
965 {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, 980 {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
@@ -1233,6 +1248,7 @@ IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStat
1233 {2, nullptr, "StartSleepSequence"}, 1248 {2, nullptr, "StartSleepSequence"},
1234 {3, nullptr, "StartShutdownSequence"}, 1249 {3, nullptr, "StartShutdownSequence"},
1235 {4, nullptr, "StartRebootSequence"}, 1250 {4, nullptr, "StartRebootSequence"},
1251 {9, nullptr, "IsAutoPowerDownRequested"},
1236 {10, nullptr, "LoadAndApplyIdlePolicySettings"}, 1252 {10, nullptr, "LoadAndApplyIdlePolicySettings"},
1237 {11, nullptr, "NotifyCecSettingsChanged"}, 1253 {11, nullptr, "NotifyCecSettingsChanged"},
1238 {12, nullptr, "SetDefaultHomeButtonLongPressTime"}, 1254 {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/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
52AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs()) { 52AOC_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/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 {
12class IFriendService final : public ServiceFramework<IFriendService> { 12class IFriendService final : public ServiceFramework<IFriendService> {
13public: 13public:
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
55class ILocalCommunicationService final : public ServiceFramework<ILocalCommunicationService> { 55class ISystemLocalCommunicationService final
56 : public ServiceFramework<ISystemLocalCommunicationService> {
56public: 57public:
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
98class IUserLocalCommunicationService final
99 : public ServiceFramework<IUserLocalCommunicationService> {
100public:
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 {
15class IScanRequest final : public ServiceFramework<IScanRequest> { 15class IScanRequest final : public ServiceFramework<IScanRequest> {
16public: 16public:
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 {
12class IParentalControlService final : public ServiceFramework<IParentalControlService> { 12class IParentalControlService final : public ServiceFramework<IParentalControlService> {
13public: 13public:
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:
42class DebugMonitor final : public ServiceFramework<DebugMonitor> { 42class DebugMonitor final : public ServiceFramework<DebugMonitor> {
43public: 43public:
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:
68class Shell final : public ServiceFramework<Shell> { 71class Shell final : public ServiceFramework<Shell> {
69public: 72public:
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
118SET::SET() : ServiceFramework("set") { 118SET::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
106SET_SYS::SET_SYS() : ServiceFramework("set:sys") { 106SET_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
75BSD::BSD(const char* name) : ServiceFramework(name) { 75BSD::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
9Time::Time(std::shared_ptr<Module> time, const char* name) 9Time::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
89ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) { 89AppLoader_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
181ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& dir) { 185ResultStatus 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
385ResultStatus AppLoader_ELF::Load(Kernel::Process& process) { 385AppLoader_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
132class AppLoader : NonCopyable { 132class AppLoader : NonCopyable {
133public: 133public:
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
44ResultStatus AppLoader_NAX::Load(Kernel::Process& process) { 44AppLoader_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
71ResultStatus AppLoader_NAX::ReadRomFS(FileSys::VirtualFile& dir) { 77ResultStatus 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
33ResultStatus AppLoader_NCA::Load(Kernel::Process& process) { 33AppLoader_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
65ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { 67ResultStatus 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
204ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { 204AppLoader_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
225ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) { 225ResultStatus 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
172ResultStatus AppLoader_NSO::Load(Kernel::Process& process) { 172AppLoader_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
75ResultStatus AppLoader_NSP::Load(Kernel::Process& process) { 75AppLoader_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
108ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& file) { 116ResultStatus 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
51ResultStatus AppLoader_XCI::Load(Kernel::Process& process) { 51AppLoader_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
78ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& file) { 82ResultStatus 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
27static Common::PageTable* current_page_table = nullptr; 27static Common::PageTable* current_page_table = nullptr;
28 28
29void SetCurrentPageTable(Common::PageTable* page_table) { 29void 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
41static void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory, 41static 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
44void SetCurrentPageTable(Common::PageTable* page_table); 44/// the given process instance.
45void 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.
47bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); 48bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 114bed20d..1e31a2900 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -46,6 +46,8 @@ add_library(video_core STATIC
46 renderer_opengl/gl_rasterizer_cache.h 46 renderer_opengl/gl_rasterizer_cache.h
47 renderer_opengl/gl_resource_manager.cpp 47 renderer_opengl/gl_resource_manager.cpp
48 renderer_opengl/gl_resource_manager.h 48 renderer_opengl/gl_resource_manager.h
49 renderer_opengl/gl_sampler_cache.cpp
50 renderer_opengl/gl_sampler_cache.h
49 renderer_opengl/gl_shader_cache.cpp 51 renderer_opengl/gl_shader_cache.cpp
50 renderer_opengl/gl_shader_cache.h 52 renderer_opengl/gl_shader_cache.h
51 renderer_opengl/gl_shader_decompiler.cpp 53 renderer_opengl/gl_shader_decompiler.cpp
@@ -67,6 +69,8 @@ add_library(video_core STATIC
67 renderer_opengl/renderer_opengl.h 69 renderer_opengl/renderer_opengl.h
68 renderer_opengl/utils.cpp 70 renderer_opengl/utils.cpp
69 renderer_opengl/utils.h 71 renderer_opengl/utils.h
72 sampler_cache.cpp
73 sampler_cache.h
70 shader/decode/arithmetic.cpp 74 shader/decode/arithmetic.cpp
71 shader/decode/arithmetic_immediate.cpp 75 shader/decode/arithmetic_immediate.cpp
72 shader/decode/bfe.cpp 76 shader/decode/bfe.cpp
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 74403eed4..b198793bc 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -482,19 +482,8 @@ std::vector<Texture::FullTextureInfo> Maxwell3D::GetStageTextures(Regs::ShaderSt
482 return textures; 482 return textures;
483} 483}
484 484
485Texture::FullTextureInfo Maxwell3D::GetStageTexture(Regs::ShaderStage stage, 485Texture::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
503Texture::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
514u32 Maxwell3D::GetRegisterValue(u32 method) const { 519u32 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
532u32 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 321af3297..cc2424d38 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -1131,12 +1131,18 @@ public:
1131 /// Write the value to the register identified by method. 1131 /// Write the value to the register identified by method.
1132 void CallMethod(const GPU::MethodCall& method_call); 1132 void CallMethod(const GPU::MethodCall& method_call);
1133 1133
1134 /// Given a Texture Handle, returns the TSC and TIC entries.
1135 Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle,
1136 std::size_t offset) const;
1137
1134 /// Returns a list of enabled textures for the specified shader stage. 1138 /// Returns a list of enabled textures for the specified shader stage.
1135 std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const; 1139 std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const;
1136 1140
1137 /// Returns the texture information for a specific texture in a specific shader stage. 1141 /// Returns the texture information for a specific texture in a specific shader stage.
1138 Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const; 1142 Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const;
1139 1143
1144 u32 AccessConstBuffer32(Regs::ShaderStage stage, u64 const_buffer, u64 offset) const;
1145
1140 /// Memory for macro code - it's undetermined how big this is, however 1MB is much larger than 1146 /// Memory for macro code - it's undetermined how big this is, however 1MB is much larger than
1141 /// we've seen used. 1147 /// we've seen used.
1142 using MacroMemory = std::array<u32, 0x40000>; 1148 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..fce9733b9 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
390enum class LmemLoadCacheManagement : u64 {
391 Default = 0,
392 LU = 1,
393 CI = 2,
394 CV = 3,
395};
396
397enum class LmemStoreCacheManagement : u64 {
398 Default = 0,
399 CG = 1,
400 CS = 2,
401 WT = 3,
402};
403
390struct IpaMode { 404struct 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;
@@ -967,6 +987,38 @@ union Instruction {
967 } tex; 987 } tex;
968 988
969 union { 989 union {
990 BitField<28, 1, u64> array;
991 BitField<29, 2, TextureType> texture_type;
992 BitField<31, 4, u64> component_mask;
993 BitField<49, 1, u64> nodep_flag;
994 BitField<50, 1, u64> dc_flag;
995 BitField<36, 1, u64> aoffi_flag;
996 BitField<37, 3, TextureProcessMode> process_mode;
997
998 bool IsComponentEnabled(std::size_t component) const {
999 return ((1ULL << component) & component_mask) != 0;
1000 }
1001
1002 TextureProcessMode GetTextureProcessMode() const {
1003 return process_mode;
1004 }
1005
1006 bool UsesMiscMode(TextureMiscMode mode) const {
1007 switch (mode) {
1008 case TextureMiscMode::DC:
1009 return dc_flag != 0;
1010 case TextureMiscMode::NODEP:
1011 return nodep_flag != 0;
1012 case TextureMiscMode::AOFFI:
1013 return aoffi_flag != 0;
1014 default:
1015 break;
1016 }
1017 return false;
1018 }
1019 } tex_b;
1020
1021 union {
970 BitField<22, 6, TextureQueryType> query_type; 1022 BitField<22, 6, TextureQueryType> query_type;
971 BitField<31, 4, u64> component_mask; 1023 BitField<31, 4, u64> component_mask;
972 BitField<49, 1, u64> nodep_flag; 1024 BitField<49, 1, u64> nodep_flag;
@@ -1312,7 +1364,9 @@ public:
1312 LDG, // Load from global memory 1364 LDG, // Load from global memory
1313 STG, // Store in global memory 1365 STG, // Store in global memory
1314 TEX, 1366 TEX,
1367 TEX_B, // Texture Load Bindless
1315 TXQ, // Texture Query 1368 TXQ, // Texture Query
1369 TXQ_B, // Texture Query Bindless
1316 TEXS, // Texture Fetch with scalar/non-vec4 source/destinations 1370 TEXS, // Texture Fetch with scalar/non-vec4 source/destinations
1317 TLDS, // Texture Load with scalar/non-vec4 source/destinations 1371 TLDS, // Texture Load with scalar/non-vec4 source/destinations
1318 TLD4, // Texture Load 4 1372 TLD4, // Texture Load 4
@@ -1580,7 +1634,9 @@ private:
1580 INST("1110111011010---", Id::LDG, Type::Memory, "LDG"), 1634 INST("1110111011010---", Id::LDG, Type::Memory, "LDG"),
1581 INST("1110111011011---", Id::STG, Type::Memory, "STG"), 1635 INST("1110111011011---", Id::STG, Type::Memory, "STG"),
1582 INST("110000----111---", Id::TEX, Type::Texture, "TEX"), 1636 INST("110000----111---", Id::TEX, Type::Texture, "TEX"),
1637 INST("1101111010111---", Id::TEX_B, Type::Texture, "TEX_B"),
1583 INST("1101111101001---", Id::TXQ, Type::Texture, "TXQ"), 1638 INST("1101111101001---", Id::TXQ, Type::Texture, "TXQ"),
1639 INST("1101111101010---", Id::TXQ_B, Type::Texture, "TXQ_B"),
1584 INST("1101-00---------", Id::TEXS, Type::Texture, "TEXS"), 1640 INST("1101-00---------", Id::TEXS, Type::Texture, "TEXS"),
1585 INST("1101101---------", Id::TLDS, Type::Texture, "TLDS"), 1641 INST("1101101---------", Id::TLDS, Type::Texture, "TLDS"),
1586 INST("110010----111---", Id::TLD4, Type::Texture, "TLD4"), 1642 INST("110010----111---", Id::TLD4, Type::Texture, "TLD4"),
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 @@
9namespace VideoCommon { 9namespace VideoCommon {
10 10
11GPUAsynch::GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer) 11GPUAsynch::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
14GPUAsynch::~GPUAsynch() = default; 14GPUAsynch::~GPUAsynch() = default;
15 15
16void GPUAsynch::Start() {
17 gpu_thread.StartThread(renderer, *dma_pusher);
18}
19
16void GPUAsynch::PushGPUEntries(Tegra::CommandList&& entries) { 20void 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
14namespace VideoCommon { 14namespace VideoCommon {
15 15
16namespace GPUThread {
17class 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
21class GPUAsynch : public Tegra::GPU { 17class GPUAsynch : public Tegra::GPU {
22public: 18public:
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 @@
8namespace VideoCommon { 8namespace VideoCommon {
9 9
10GPUSynch::GPUSynch(Core::System& system, VideoCore::RendererBase& renderer) 10GPUSynch::GPUSynch(Core::System& system, VideoCore::RendererBase& renderer)
11 : Tegra::GPU(system, renderer) {} 11 : GPU(system, renderer) {}
12 12
13GPUSynch::~GPUSynch() = default; 13GPUSynch::~GPUSynch() = default;
14 14
15void GPUSynch::Start() {}
16
15void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { 17void 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
58ThreadManager::ThreadManager(Core::System& system, VideoCore::RendererBase& renderer, 58ThreadManager::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
65ThreadManager::~ThreadManager() { 60ThreadManager::~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
70void 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
71void ThreadManager::SubmitList(Tegra::CommandList&& entries) { 76void 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
139class ThreadManager final { 139class ThreadManager final {
140public: 140public:
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/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
15namespace OpenGL { 15namespace OpenGL {
16 16
17CachedGlobalRegion::CachedGlobalRegion(VAddr cpu_addr, u32 size, u8* host_ptr) 17CachedGlobalRegion::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
26void CachedGlobalRegion::Reload(u32 size_) { 24CachedGlobalRegion::~CachedGlobalRegion() = default;
27 constexpr auto max_size = static_cast<u32>(RasterizerOpenGL::MaxGlobalMemorySize);
28 25
26void 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 36void 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
41GlobalRegion GlobalRegionCacheOpenGL::TryGetReservedGlobalRegion(CacheAddr addr, u32 size) const { 41GlobalRegion 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
49GlobalRegion GlobalRegionCacheOpenGL::GetUncachedGlobalRegion(GPUVAddr addr, u32 size, 49GlobalRegion 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
67GlobalRegionCacheOpenGL::GlobalRegionCacheOpenGL(RasterizerOpenGL& rasterizer) 69GlobalRegionCacheOpenGL::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
70GlobalRegion GlobalRegionCacheOpenGL::GetGlobalRegion( 76GlobalRegion 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
20namespace GLShader { 20namespace GLShader {
21class GlobalMemoryEntry; 21class GlobalMemoryEntry;
22} // namespace GLShader 22}
23 23
24class RasterizerOpenGL; 24class RasterizerOpenGL;
25class CachedGlobalRegion; 25class CachedGlobalRegion;
@@ -27,7 +27,8 @@ using GlobalRegion = std::shared_ptr<CachedGlobalRegion>;
27 27
28class CachedGlobalRegion final : public RasterizerCacheObject { 28class CachedGlobalRegion final : public RasterizerCacheObject {
29public: 29public:
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
53private: 51private:
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
67private: 68private:
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 d250d5cbb..6034dc489 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -101,12 +101,6 @@ struct FramebufferCacheKey {
101RasterizerOpenGL::RasterizerOpenGL(Core::System& system, ScreenInfo& info) 101RasterizerOpenGL::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}, 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>();
@@ -582,9 +576,6 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
582} 576}
583 577
584void RasterizerOpenGL::Clear() { 578void RasterizerOpenGL::Clear() {
585 const auto prev_state{state};
586 SCOPE_EXIT({ prev_state.Apply(); });
587
588 const auto& regs = system.GPU().Maxwell3D().regs; 579 const auto& regs = system.GPU().Maxwell3D().regs;
589 bool use_color{}; 580 bool use_color{};
590 bool use_depth{}; 581 bool use_depth{};
@@ -656,7 +647,10 @@ void RasterizerOpenGL::Clear() {
656 clear_state.EmulateViewportWithScissor(); 647 clear_state.EmulateViewportWithScissor();
657 } 648 }
658 649
659 clear_state.Apply(); 650 clear_state.ApplyColorMask();
651 clear_state.ApplyDepth();
652 clear_state.ApplyStencilTest();
653 clear_state.ApplyViewport();
660 654
661 if (use_color) { 655 if (use_color) {
662 glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color); 656 glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color);
@@ -756,6 +750,7 @@ void RasterizerOpenGL::FlushRegion(CacheAddr addr, u64 size) {
756 return; 750 return;
757 } 751 }
758 res_cache.FlushRegion(addr, size); 752 res_cache.FlushRegion(addr, size);
753 global_cache.FlushRegion(addr, size);
759} 754}
760 755
761void RasterizerOpenGL::InvalidateRegion(CacheAddr addr, u64 size) { 756void RasterizerOpenGL::InvalidateRegion(CacheAddr addr, u64 size) {
@@ -812,92 +807,6 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
812 return true; 807 return true;
813} 808}
814 809
815void RasterizerOpenGL::SamplerInfo::Create() {
816 sampler.Create();
817 mag_filter = Tegra::Texture::TextureFilter::Linear;
818 min_filter = Tegra::Texture::TextureFilter::Linear;
819 wrap_u = Tegra::Texture::WrapMode::Wrap;
820 wrap_v = Tegra::Texture::WrapMode::Wrap;
821 wrap_p = Tegra::Texture::WrapMode::Wrap;
822 use_depth_compare = false;
823 depth_compare_func = Tegra::Texture::DepthCompareFunc::Never;
824
825 // OpenGL's default is GL_LINEAR_MIPMAP_LINEAR
826 glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
827 glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER);
828
829 // Other attributes have correct defaults
830}
831
832void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) {
833 const GLuint sampler_id = sampler.handle;
834 if (mag_filter != config.mag_filter) {
835 mag_filter = config.mag_filter;
836 glSamplerParameteri(
837 sampler_id, GL_TEXTURE_MAG_FILTER,
838 MaxwellToGL::TextureFilterMode(mag_filter, Tegra::Texture::TextureMipmapFilter::None));
839 }
840 if (min_filter != config.min_filter || mipmap_filter != config.mipmap_filter) {
841 min_filter = config.min_filter;
842 mipmap_filter = config.mipmap_filter;
843 glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER,
844 MaxwellToGL::TextureFilterMode(min_filter, mipmap_filter));
845 }
846
847 if (wrap_u != config.wrap_u) {
848 wrap_u = config.wrap_u;
849 glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, MaxwellToGL::WrapMode(wrap_u));
850 }
851 if (wrap_v != config.wrap_v) {
852 wrap_v = config.wrap_v;
853 glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v));
854 }
855 if (wrap_p != config.wrap_p) {
856 wrap_p = config.wrap_p;
857 glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(wrap_p));
858 }
859
860 if (const bool enabled = config.depth_compare_enabled == 1; use_depth_compare != enabled) {
861 use_depth_compare = enabled;
862 glSamplerParameteri(sampler_id, GL_TEXTURE_COMPARE_MODE,
863 use_depth_compare ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE);
864 }
865
866 if (depth_compare_func != config.depth_compare_func) {
867 depth_compare_func = config.depth_compare_func;
868 glSamplerParameteri(sampler_id, GL_TEXTURE_COMPARE_FUNC,
869 MaxwellToGL::DepthCompareFunc(depth_compare_func));
870 }
871
872 if (const auto new_border_color = config.GetBorderColor(); border_color != new_border_color) {
873 border_color = new_border_color;
874 glSamplerParameterfv(sampler_id, GL_TEXTURE_BORDER_COLOR, border_color.data());
875 }
876
877 if (const float anisotropic = config.GetMaxAnisotropy(); max_anisotropic != anisotropic) {
878 max_anisotropic = anisotropic;
879 if (GLAD_GL_ARB_texture_filter_anisotropic) {
880 glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY, max_anisotropic);
881 } else if (GLAD_GL_EXT_texture_filter_anisotropic) {
882 glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropic);
883 }
884 }
885
886 if (const float min = config.GetMinLod(); min_lod != min) {
887 min_lod = min;
888 glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, min_lod);
889 }
890 if (const float max = config.GetMaxLod(); max_lod != max) {
891 max_lod = max;
892 glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, max_lod);
893 }
894
895 if (const float bias = config.GetLodBias(); lod_bias != bias) {
896 lod_bias = bias;
897 glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, lod_bias);
898 }
899}
900
901void RasterizerOpenGL::SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, 810void RasterizerOpenGL::SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
902 const Shader& shader, GLuint program_handle, 811 const Shader& shader, GLuint program_handle,
903 BaseBindings base_bindings) { 812 BaseBindings base_bindings) {
@@ -953,6 +862,9 @@ void RasterizerOpenGL::SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::Shade
953 for (std::size_t bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { 862 for (std::size_t bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
954 const auto& entry{entries[bindpoint]}; 863 const auto& entry{entries[bindpoint]};
955 const auto& region{global_cache.GetGlobalRegion(entry, stage)}; 864 const auto& region{global_cache.GetGlobalRegion(entry, stage)};
865 if (entry.IsWritten()) {
866 region->MarkAsModified(true, global_cache);
867 }
956 bind_ssbo_pushbuffer.Push(region->GetBufferHandle(), 0, 868 bind_ssbo_pushbuffer.Push(region->GetBufferHandle(), 0,
957 static_cast<GLsizeiptr>(region->GetSizeInBytes())); 869 static_cast<GLsizeiptr>(region->GetSizeInBytes()));
958 } 870 }
@@ -970,10 +882,18 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s
970 882
971 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { 883 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
972 const auto& entry = entries[bindpoint]; 884 const auto& entry = entries[bindpoint];
973 const auto texture = maxwell3d.GetStageTexture(stage, entry.GetOffset()); 885 Tegra::Texture::FullTextureInfo texture;
886 if (entry.IsBindless()) {
887 const auto cbuf = entry.GetBindlessCBuf();
888 Tegra::Texture::TextureHandle tex_handle;
889 tex_handle.raw = maxwell3d.AccessConstBuffer32(stage, cbuf.first, cbuf.second);
890 texture = maxwell3d.GetTextureInfo(tex_handle, entry.GetOffset());
891 } else {
892 texture = maxwell3d.GetStageTexture(stage, entry.GetOffset());
893 }
974 const u32 current_bindpoint = base_bindings.sampler + bindpoint; 894 const u32 current_bindpoint = base_bindings.sampler + bindpoint;
975 895
976 texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); 896 state.texture_units[current_bindpoint].sampler = sampler_cache.GetSampler(texture.tsc);
977 897
978 if (Surface surface = res_cache.GetTextureSurface(texture, entry); surface) { 898 if (Surface surface = res_cache.GetTextureSurface(texture, entry); surface) {
979 state.texture_units[current_bindpoint].texture = 899 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..a0e056142 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -25,6 +25,7 @@
25#include "video_core/renderer_opengl/gl_primitive_assembler.h" 25#include "video_core/renderer_opengl/gl_primitive_assembler.h"
26#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 26#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
27#include "video_core/renderer_opengl/gl_resource_manager.h" 27#include "video_core/renderer_opengl/gl_resource_manager.h"
28#include "video_core/renderer_opengl/gl_sampler_cache.h"
28#include "video_core/renderer_opengl/gl_shader_cache.h" 29#include "video_core/renderer_opengl/gl_shader_cache.h"
29#include "video_core/renderer_opengl/gl_shader_manager.h" 30#include "video_core/renderer_opengl/gl_shader_manager.h"
30#include "video_core/renderer_opengl/gl_state.h" 31#include "video_core/renderer_opengl/gl_state.h"
@@ -71,39 +72,7 @@ public:
71 static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0, 72 static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0,
72 "The maximum size of a constbuffer must be a multiple of the size of GLvec4"); 73 "The maximum size of a constbuffer must be a multiple of the size of GLvec4");
73 74
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
78private: 75private:
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 { 76 struct FramebufferConfigState {
108 bool using_color_fb{}; 77 bool using_color_fb{};
109 bool using_depth_fb{}; 78 bool using_depth_fb{};
@@ -208,6 +177,7 @@ private:
208 RasterizerCacheOpenGL res_cache; 177 RasterizerCacheOpenGL res_cache;
209 ShaderCacheOpenGL shader_cache; 178 ShaderCacheOpenGL shader_cache;
210 GlobalRegionCacheOpenGL global_cache; 179 GlobalRegionCacheOpenGL global_cache;
180 SamplerCacheOpenGL sampler_cache;
211 181
212 Core::System& system; 182 Core::System& system;
213 183
@@ -223,8 +193,6 @@ private:
223 FramebufferConfigState current_framebuffer_config_state; 193 FramebufferConfigState current_framebuffer_config_state;
224 std::pair<bool, bool> current_depth_stencil_usage{}; 194 std::pair<bool, bool> current_depth_stencil_usage{};
225 195
226 std::array<SamplerInfo, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_samplers;
227
228 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; 196 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
229 OGLBufferCache buffer_cache; 197 OGLBufferCache buffer_cache;
230 PrimitiveAssembler primitive_assembler{buffer_cache}; 198 PrimitiveAssembler primitive_assembler{buffer_cache};
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index f2ffc4710..7a68b8738 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;
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
10namespace OpenGL {
11
12SamplerCacheOpenGL::SamplerCacheOpenGL() = default;
13
14SamplerCacheOpenGL::~SamplerCacheOpenGL() = default;
15
16OGLSampler 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
48GLuint 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
12namespace OpenGL {
13
14class SamplerCacheOpenGL final : public VideoCommon::SamplerCache<GLuint, OGLSampler> {
15public:
16 explicit SamplerCacheOpenGL();
17 ~SamplerCacheOpenGL();
18
19protected:
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_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 44ad21b7f..cd462621d 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -45,8 +45,6 @@ using TextureIR = std::variant<TextureAoffi, TextureArgument>;
45enum : u32 { POSITION_VARYING_LOCATION = 0, GENERIC_VARYING_START_LOCATION = 1 }; 45enum : u32 { POSITION_VARYING_LOCATION = 0, GENERIC_VARYING_START_LOCATION = 1 };
46constexpr u32 MAX_CONSTBUFFER_ELEMENTS = 46constexpr u32 MAX_CONSTBUFFER_ELEMENTS =
47 static_cast<u32>(RasterizerOpenGL::MaxConstbufferSize) / (4 * sizeof(float)); 47 static_cast<u32>(RasterizerOpenGL::MaxConstbufferSize) / (4 * sizeof(float));
48constexpr u32 MAX_GLOBALMEMORY_ELEMENTS =
49 static_cast<u32>(RasterizerOpenGL::MaxGlobalMemorySize) / sizeof(float);
50 48
51class ShaderWriter { 49class ShaderWriter {
52public: 50public:
@@ -204,8 +202,10 @@ public:
204 for (const auto& sampler : ir.GetSamplers()) { 202 for (const auto& sampler : ir.GetSamplers()) {
205 entries.samplers.emplace_back(sampler); 203 entries.samplers.emplace_back(sampler);
206 } 204 }
207 for (const auto& gmem : ir.GetGlobalMemoryBases()) { 205 for (const auto& gmem_pair : ir.GetGlobalMemory()) {
208 entries.global_memory_entries.emplace_back(gmem.cbuf_index, gmem.cbuf_offset); 206 const auto& [base, usage] = gmem_pair;
207 entries.global_memory_entries.emplace_back(base.cbuf_index, base.cbuf_offset,
208 usage.is_read, usage.is_written);
209 } 209 }
210 entries.clip_distances = ir.GetClipDistances(); 210 entries.clip_distances = ir.GetClipDistances();
211 entries.shader_length = ir.GetLength(); 211 entries.shader_length = ir.GetLength();
@@ -376,12 +376,22 @@ private:
376 } 376 }
377 377
378 void DeclareGlobalMemory() { 378 void DeclareGlobalMemory() {
379 for (const auto& entry : ir.GetGlobalMemoryBases()) { 379 for (const auto& gmem : ir.GetGlobalMemory()) {
380 const auto& [base, usage] = gmem;
381
382 // Since we don't know how the shader will use the shader, hint the driver to disable as
383 // much optimizations as possible
384 std::string qualifier = "coherent volatile";
385 if (usage.is_read && !usage.is_written)
386 qualifier += " readonly";
387 else if (usage.is_written && !usage.is_read)
388 qualifier += " writeonly";
389
380 const std::string binding = 390 const std::string binding =
381 fmt::format("GMEM_BINDING_{}_{}", entry.cbuf_index, entry.cbuf_offset); 391 fmt::format("GMEM_BINDING_{}_{}", base.cbuf_index, base.cbuf_offset);
382 code.AddLine("layout (std430, binding = " + binding + ") buffer " + 392 code.AddLine("layout (std430, binding = " + binding + ") " + qualifier + " buffer " +
383 GetGlobalMemoryBlock(entry) + " {"); 393 GetGlobalMemoryBlock(base) + " {");
384 code.AddLine(" float " + GetGlobalMemory(entry) + "[MAX_GLOBALMEMORY_ELEMENTS];"); 394 code.AddLine(" float " + GetGlobalMemory(base) + "[];");
385 code.AddLine("};"); 395 code.AddLine("};");
386 code.AddNewLine(); 396 code.AddNewLine();
387 } 397 }
@@ -841,6 +851,12 @@ private:
841 } else if (const auto lmem = std::get_if<LmemNode>(dest)) { 851 } else if (const auto lmem = std::get_if<LmemNode>(dest)) {
842 target = GetLocalMemory() + "[ftou(" + Visit(lmem->GetAddress()) + ") / 4]"; 852 target = GetLocalMemory() + "[ftou(" + Visit(lmem->GetAddress()) + ") / 4]";
843 853
854 } else if (const auto gmem = std::get_if<GmemNode>(dest)) {
855 const std::string real = Visit(gmem->GetRealAddress());
856 const std::string base = Visit(gmem->GetBaseAddress());
857 const std::string final_offset = "(ftou(" + real + ") - ftou(" + base + ")) / 4";
858 target = fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset);
859
844 } else { 860 } else {
845 UNREACHABLE_MSG("Assign called without a proper target"); 861 UNREACHABLE_MSG("Assign called without a proper target");
846 } 862 }
@@ -1641,9 +1657,7 @@ private:
1641 1657
1642std::string GetCommonDeclarations() { 1658std::string GetCommonDeclarations() {
1643 const auto cbuf = std::to_string(MAX_CONSTBUFFER_ELEMENTS); 1659 const auto cbuf = std::to_string(MAX_CONSTBUFFER_ELEMENTS);
1644 const auto gmem = std::to_string(MAX_GLOBALMEMORY_ELEMENTS);
1645 return "#define MAX_CONSTBUFFER_ELEMENTS " + cbuf + "\n" + 1660 return "#define MAX_CONSTBUFFER_ELEMENTS " + cbuf + "\n" +
1646 "#define MAX_GLOBALMEMORY_ELEMENTS " + gmem + "\n" +
1647 "#define ftoi floatBitsToInt\n" 1661 "#define ftoi floatBitsToInt\n"
1648 "#define ftou floatBitsToUint\n" 1662 "#define ftou floatBitsToUint\n"
1649 "#define itof intBitsToFloat\n" 1663 "#define itof intBitsToFloat\n"
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h
index 4e04ab2f8..74032d237 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.h
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h
@@ -39,8 +39,9 @@ private:
39 39
40class GlobalMemoryEntry { 40class GlobalMemoryEntry {
41public: 41public:
42 explicit GlobalMemoryEntry(u32 cbuf_index, u32 cbuf_offset) 42 explicit GlobalMemoryEntry(u32 cbuf_index, u32 cbuf_offset, bool is_read, bool is_written)
43 : cbuf_index{cbuf_index}, cbuf_offset{cbuf_offset} {} 43 : cbuf_index{cbuf_index}, cbuf_offset{cbuf_offset}, is_read{is_read}, is_written{
44 is_written} {}
44 45
45 u32 GetCbufIndex() const { 46 u32 GetCbufIndex() const {
46 return cbuf_index; 47 return cbuf_index;
@@ -50,14 +51,25 @@ public:
50 return cbuf_offset; 51 return cbuf_offset;
51 } 52 }
52 53
54 bool IsRead() const {
55 return is_read;
56 }
57
58 bool IsWritten() const {
59 return is_written;
60 }
61
53private: 62private:
54 u32 cbuf_index{}; 63 u32 cbuf_index{};
55 u32 cbuf_offset{}; 64 u32 cbuf_offset{};
65 bool is_read{};
66 bool is_written{};
56}; 67};
57 68
58struct ShaderEntries { 69struct ShaderEntries {
59 std::vector<ConstBufferEntry> const_buffers; 70 std::vector<ConstBufferEntry> const_buffers;
60 std::vector<SamplerEntry> samplers; 71 std::vector<SamplerEntry> samplers;
72 std::vector<SamplerEntry> bindless_samplers;
61 std::vector<GlobalMemoryEntry> global_memory_entries; 73 std::vector<GlobalMemoryEntry> global_memory_entries;
62 std::array<bool, Maxwell::NumClipDistances> clip_distances{}; 74 std::array<bool, Maxwell::NumClipDistances> clip_distances{};
63 std::size_t shader_length{}; 75 std::size_t shader_length{};
@@ -68,4 +80,4 @@ std::string GetCommonDeclarations();
68ProgramResult Decompile(const VideoCommon::Shader::ShaderIR& ir, Maxwell::ShaderStage stage, 80ProgramResult Decompile(const VideoCommon::Shader::ShaderIR& ir, Maxwell::ShaderStage stage,
69 const std::string& suffix); 81 const std::string& suffix);
70 82
71} // namespace OpenGL::GLShader \ No newline at end of file 83} // 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_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
31std::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
37bool SamplerCacheKey::operator==(const SamplerCacheKey& rhs) const {
38 return raw == rhs.raw;
39}
40
41VKSamplerCache::VKSamplerCache(const VKDevice& device) : device{device} {} 30VKSamplerCache::VKSamplerCache(const VKDevice& device) : device{device} {}
42 31
43VKSamplerCache::~VKSamplerCache() = default; 32VKSamplerCache::~VKSamplerCache() = default;
44 33
45vk::Sampler VKSamplerCache::GetSampler(const Tegra::Texture::TSCEntry& tsc) { 34UniqueSampler 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
54UniqueSampler 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
61vk::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
13namespace Vulkan { 14namespace Vulkan {
14 15
15class VKDevice; 16class VKDevice;
16 17
17struct SamplerCacheKey final : public Tegra::Texture::TSCEntry { 18class 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
29namespace std {
30
31template <>
32struct 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
40namespace Vulkan {
41
42class VKSamplerCache {
43public: 19public:
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); 23protected:
24 UniqueSampler CreateSampler(const Tegra::Texture::TSCEntry& tsc) const;
48 25
49private: 26 vk::Sampler ToSamplerType(const UniqueSampler& sampler) const;
50 UniqueSampler CreateSampler(const Tegra::Texture::TSCEntry& tsc);
51 27
28private:
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 f50aae00d..23d9b10db 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -187,8 +187,9 @@ public:
187 for (const auto& cbuf : ir.GetConstantBuffers()) { 187 for (const auto& cbuf : ir.GetConstantBuffers()) {
188 entries.const_buffers.emplace_back(cbuf.second, cbuf.first); 188 entries.const_buffers.emplace_back(cbuf.second, cbuf.first);
189 } 189 }
190 for (const auto& gmem : ir.GetGlobalMemoryBases()) { 190 for (const auto& gmem_pair : ir.GetGlobalMemory()) {
191 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);
192 } 193 }
193 for (const auto& sampler : ir.GetSamplers()) { 194 for (const auto& sampler : ir.GetSamplers()) {
194 entries.samplers.emplace_back(sampler); 195 entries.samplers.emplace_back(sampler);
@@ -221,7 +222,7 @@ private:
221 return current_binding; 222 return current_binding;
222 }; 223 };
223 const_buffers_base_binding = Allocate(ir.GetConstantBuffers().size()); 224 const_buffers_base_binding = Allocate(ir.GetConstantBuffers().size());
224 global_buffers_base_binding = Allocate(ir.GetGlobalMemoryBases().size()); 225 global_buffers_base_binding = Allocate(ir.GetGlobalMemory().size());
225 samplers_base_binding = Allocate(ir.GetSamplers().size()); 226 samplers_base_binding = Allocate(ir.GetSamplers().size());
226 227
227 ASSERT_MSG(binding_iterator - binding_base < STAGE_BINDING_STRIDE, 228 ASSERT_MSG(binding_iterator - binding_base < STAGE_BINDING_STRIDE,
@@ -386,14 +387,15 @@ private:
386 387
387 void DeclareGlobalBuffers() { 388 void DeclareGlobalBuffers() {
388 u32 binding = global_buffers_base_binding; 389 u32 binding = global_buffers_base_binding;
389 for (const auto& entry : ir.GetGlobalMemoryBases()) { 390 for (const auto& entry : ir.GetGlobalMemory()) {
391 const auto [base, usage] = entry;
390 const Id id = OpVariable(t_gmem_ssbo, spv::StorageClass::StorageBuffer); 392 const Id id = OpVariable(t_gmem_ssbo, spv::StorageClass::StorageBuffer);
391 AddGlobalVariable( 393 AddGlobalVariable(
392 Name(id, fmt::format("gmem_{}_{}", entry.cbuf_index, entry.cbuf_offset))); 394 Name(id, fmt::format("gmem_{}_{}", base.cbuf_index, base.cbuf_offset)));
393 395
394 Decorate(id, spv::Decoration::Binding, binding++); 396 Decorate(id, spv::Decoration::Binding, binding++);
395 Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET); 397 Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET);
396 global_buffers.emplace(entry, id); 398 global_buffers.emplace(base, id);
397 } 399 }
398 } 400 }
399 401
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
9namespace VideoCommon {
10
11std::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
17bool 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
12namespace VideoCommon {
13
14struct 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
26namespace std {
27
28template <>
29struct 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
37namespace VideoCommon {
38
39template <typename SamplerType, typename SamplerStorageType>
40class SamplerCache {
41public:
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
51protected:
52 virtual SamplerStorageType CreateSampler(const Tegra::Texture::TSCEntry& tsc) const = 0;
53
54 virtual SamplerType ToSamplerType(const SamplerStorageType& sampler) const = 0;
55
56private:
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/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;
18using Tegra::Shader::OpCode; 19using Tegra::Shader::OpCode;
19using Tegra::Shader::Register; 20using Tegra::Shader::Register;
20 21
22namespace {
23u32 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
21u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { 39u32 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
249std::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) {
40u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { 40u32 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
289const 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
257void ShaderIR::WriteTexInstructionFloat(NodeBlock& bb, Instruction instr, const Node4& components) { 317void 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,
326Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, 386Node4 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
385Node4 ShaderIR::GetTexCode(Instruction instr, TextureType texture_type, 451Node4 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
429Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, 503Node4 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
465Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare, 540Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare,
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index 88957e970..81278fb33 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -204,9 +204,23 @@ enum class ExitMethod {
204 204
205class Sampler { 205class Sampler {
206public: 206public:
207 // Use this constructor for bounded Samplers
207 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,
208 bool is_array, bool is_shadow) 209 bool is_array, bool is_shadow)
209 : 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} {}
210 224
211 std::size_t GetOffset() const { 225 std::size_t GetOffset() const {
212 return offset; 226 return offset;
@@ -228,6 +242,14 @@ public:
228 return is_shadow; 242 return is_shadow;
229 } 243 }
230 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
231 bool operator<(const Sampler& rhs) const { 253 bool operator<(const Sampler& rhs) const {
232 return std::tie(offset, index, type, is_array, is_shadow) < 254 return std::tie(offset, index, type, is_array, is_shadow) <
233 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);
@@ -239,8 +261,9 @@ private:
239 std::size_t offset{}; 261 std::size_t offset{};
240 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.
241 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)
242 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.
243 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.
244}; 267};
245 268
246class ConstBuffer { 269class ConstBuffer {
@@ -284,6 +307,11 @@ struct GlobalMemoryBase {
284 } 307 }
285}; 308};
286 309
310struct GlobalMemoryUsage {
311 bool is_read{};
312 bool is_written{};
313};
314
287struct MetaArithmetic { 315struct MetaArithmetic {
288 bool precise{}; 316 bool precise{};
289}; 317};
@@ -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 {
@@ -733,6 +761,11 @@ private:
733 const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler, 761 const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler,
734 Tegra::Shader::TextureType type, bool is_array, bool is_shadow); 762 Tegra::Shader::TextureType type, bool is_array, bool is_shadow);
735 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
736 /// Extracts a sequence of bits from a node 769 /// Extracts a sequence of bits from a node
737 Node BitfieldExtract(Node value, u32 offset, u32 bits); 770 Node BitfieldExtract(Node value, u32 offset, u32 bits);
738 771
@@ -746,7 +779,8 @@ private:
746 779
747 Node4 GetTexCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, 780 Node4 GetTexCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type,
748 Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, 781 Tegra::Shader::TextureProcessMode process_mode, bool depth_compare,
749 bool is_array, bool is_aoffi); 782 bool is_array, bool is_aoffi,
783 std::optional<Tegra::Shader::Register> bindless_reg);
750 784
751 Node4 GetTexsCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, 785 Node4 GetTexsCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type,
752 Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, 786 Tegra::Shader::TextureProcessMode process_mode, bool depth_compare,
@@ -766,7 +800,8 @@ private:
766 800
767 Node4 GetTextureCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, 801 Node4 GetTextureCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type,
768 Tegra::Shader::TextureProcessMode process_mode, std::vector<Node> coords, 802 Tegra::Shader::TextureProcessMode process_mode, std::vector<Node> coords,
769 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);
770 805
771 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,
772 u64 byte_height); 807 u64 byte_height);
@@ -784,6 +819,11 @@ private:
784 819
785 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);
786 821
822 std::tuple<Node, Node, GlobalMemoryBase> TrackAndGetGlobalMemory(NodeBlock& bb,
823 Node addr_register,
824 u32 immediate_offset,
825 bool is_write);
826
787 template <typename... T> 827 template <typename... T>
788 Node Operation(OperationCode code, const T*... operands) { 828 Node Operation(OperationCode code, const T*... operands) {
789 return StoreNode(OperationNode(code, operands...)); 829 return StoreNode(OperationNode(code, operands...));
@@ -837,7 +877,7 @@ private:
837 std::map<u32, ConstBuffer> used_cbufs; 877 std::map<u32, ConstBuffer> used_cbufs;
838 std::set<Sampler> used_samplers; 878 std::set<Sampler> used_samplers;
839 std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; 879 std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{};
840 std::set<GlobalMemoryBase> used_global_memory_bases; 880 std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory;
841 881
842 Tegra::Shader::Header header; 882 Tegra::Shader::Header header;
843}; 883};
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
21std::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
19u16 GetResolutionScaleFactor(const RendererBase& renderer) { 29u16 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 {
14class EmuWindow; 14class EmuWindow;
15} 15}
16 16
17namespace Tegra {
18class GPU;
19}
20
17namespace VideoCore { 21namespace VideoCore {
18 22
19class RendererBase; 23class RendererBase;
@@ -27,6 +31,9 @@ class RendererBase;
27std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window, 31std::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.
35std::unique_ptr<Tegra::GPU> CreateGPU(Core::System& system);
36
30u16 GetResolutionScaleFactor(const RendererBase& renderer); 37u16 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..31b65c04c 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -151,6 +151,12 @@ target_link_libraries(yuzu PRIVATE common core input_common video_core)
151target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::OpenGL Qt5::Widgets) 151target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::OpenGL Qt5::Widgets)
152target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) 152target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
153 153
154target_compile_definitions(yuzu PRIVATE
155 # Use QStringBuilder for string concatenation to reduce
156 # the overall number of temporary strings created.
157 -DQT_USE_QSTRINGBUILDER
158)
159
154if (YUZU_ENABLE_COMPATIBILITY_REPORTING) 160if (YUZU_ENABLE_COMPATIBILITY_REPORTING)
155 target_compile_definitions(yuzu PRIVATE -DYUZU_ENABLE_COMPATIBILITY_REPORTING) 161 target_compile_definitions(yuzu PRIVATE -DYUZU_ENABLE_COMPATIBILITY_REPORTING)
156endif() 162endif()
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index c29f2d2dc..7eed9fcf3 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -91,8 +91,8 @@ void EmuThread::run() {
91 91
92class GGLContext : public Core::Frontend::GraphicsContext { 92class GGLContext : public Core::Frontend::GraphicsContext {
93public: 93public:
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
188GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) 188GRenderWindow::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);
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/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
14ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry) 14ConfigureDialog::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_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
68void ConfigureHotkeys::Configure(QModelIndex index) { 68void 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
93bool ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) { 94bool 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
11namespace Ui { 10namespace Ui {
12class ConfigureHotkeys; 11class ConfigureHotkeys;
@@ -39,7 +38,7 @@ signals:
39 38
40private: 39private:
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/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);