summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/common/logging/filter.cpp1
-rw-r--r--src/common/logging/types.h1
-rw-r--r--src/common/settings.h3
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp52
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp52
-rw-r--r--src/core/file_sys/registered_cache.cpp6
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp11
-rw-r--r--src/core/hle/kernel/hle_ipc.h8
-rw-r--r--src/core/hle/kernel/kernel.cpp14
-rw-r--r--src/core/hle/kernel/kernel.h16
-rw-r--r--src/core/hle/service/am/am.cpp9
-rw-r--r--src/core/hle/service/am/am.h1
-rw-r--r--src/core/hle/service/audio/audout_u.cpp7
-rw-r--r--src/core/hle/service/audio/audren_u.cpp3
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp13
-rw-r--r--src/core/hle/service/hid/hid.cpp4
-rw-r--r--src/core/hle/service/jit/jit.cpp53
-rw-r--r--src/core/hle/service/jit/jit.h20
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.cpp2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_consumer.cpp44
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_consumer.h4
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.cpp1
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.h2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.cpp101
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.h2
-rw-r--r--src/core/hle/service/nvflinger/consumer_base.cpp29
-rw-r--r--src/core/hle/service/nvflinger/consumer_base.h3
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp4
-rw-r--r--src/core/hle/service/service.cpp7
-rw-r--r--src/core/hle/service/service.h14
-rw-r--r--src/core/hle/service/sm/sm.cpp2
-rw-r--r--src/core/hle/service/sockets/bsd.cpp3
-rw-r--r--src/core/hle/service/vi/vi.cpp3
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp25
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.cpp19
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.h1
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp21
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp9
-rw-r--r--src/shader_recompiler/shader_info.h1
-rw-r--r--src/yuzu/configuration/configure_cpu.ui5
42 files changed, 387 insertions, 197 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1bdf70b76..3ad2c0950 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -103,12 +103,6 @@ else()
103 -Wno-unused-parameter 103 -Wno-unused-parameter
104 ) 104 )
105 105
106 # TODO: Remove when we update to a GCC compiler that enables this
107 # by default (i.e. GCC 10 or newer).
108 if (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
109 add_compile_options(-fconcepts)
110 endif()
111
112 if (ARCHITECTURE_x86_64) 106 if (ARCHITECTURE_x86_64)
113 add_compile_options("-mcx16") 107 add_compile_options("-mcx16")
114 endif() 108 endif()
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 9120cc178..4acbff649 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -101,6 +101,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
101 SUB(Service, GRC) \ 101 SUB(Service, GRC) \
102 SUB(Service, HID) \ 102 SUB(Service, HID) \
103 SUB(Service, IRS) \ 103 SUB(Service, IRS) \
104 SUB(Service, JIT) \
104 SUB(Service, LBL) \ 105 SUB(Service, LBL) \
105 SUB(Service, LDN) \ 106 SUB(Service, LDN) \
106 SUB(Service, LDR) \ 107 SUB(Service, LDR) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index f803ab796..99c15fa96 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -69,6 +69,7 @@ enum class Class : u8 {
69 Service_GRC, ///< The game recording service 69 Service_GRC, ///< The game recording service
70 Service_HID, ///< The HID (Human interface device) service 70 Service_HID, ///< The HID (Human interface device) service
71 Service_IRS, ///< The IRS service 71 Service_IRS, ///< The IRS service
72 Service_JIT, ///< The JIT service
72 Service_LBL, ///< The LBL (LCD backlight) service 73 Service_LBL, ///< The LBL (LCD backlight) service
73 Service_LDN, ///< The LDN (Local domain network) service 74 Service_LDN, ///< The LDN (Local domain network) service
74 Service_LDR, ///< The loader service 75 Service_LDR, ///< The loader service
diff --git a/src/common/settings.h b/src/common/settings.h
index a37d83fb3..86e0fa140 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -38,6 +38,7 @@ enum class CPUAccuracy : u32 {
38 Auto = 0, 38 Auto = 0,
39 Accurate = 1, 39 Accurate = 1,
40 Unsafe = 2, 40 Unsafe = 2,
41 Paranoid = 3,
41}; 42};
42 43
43enum class FullscreenMode : u32 { 44enum class FullscreenMode : u32 {
@@ -470,7 +471,7 @@ struct Values {
470 471
471 // Cpu 472 // Cpu
472 RangedSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto, 473 RangedSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
473 CPUAccuracy::Unsafe, "cpu_accuracy"}; 474 CPUAccuracy::Paranoid, "cpu_accuracy"};
474 // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021 475 // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
475 BasicSetting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"}; 476 BasicSetting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
476 BasicSetting<bool> cpu_debug_mode{false, "cpu_debug_mode"}; 477 BasicSetting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 6536d0544..81eaf0942 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -458,6 +458,8 @@ add_library(core STATIC
458 hle/service/hid/controllers/touchscreen.h 458 hle/service/hid/controllers/touchscreen.h
459 hle/service/hid/controllers/xpad.cpp 459 hle/service/hid/controllers/xpad.cpp
460 hle/service/hid/controllers/xpad.h 460 hle/service/hid/controllers/xpad.h
461 hle/service/jit/jit.cpp
462 hle/service/jit/jit.h
461 hle/service/lbl/lbl.cpp 463 hle/service/lbl/lbl.cpp
462 hle/service/lbl/lbl.h 464 hle/service/lbl/lbl.h
463 hle/service/ldn/errors.h 465 hle/service/ldn/errors.h
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 286976623..054572445 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -70,11 +70,13 @@ public:
70 } 70 }
71 71
72 void InterpreterFallback(u32 pc, std::size_t num_instructions) override { 72 void InterpreterFallback(u32 pc, std::size_t num_instructions) override {
73 parent.LogBacktrace();
73 UNIMPLEMENTED_MSG("This should never happen, pc = {:08X}, code = {:08X}", pc, 74 UNIMPLEMENTED_MSG("This should never happen, pc = {:08X}, code = {:08X}", pc,
74 MemoryReadCode(pc)); 75 MemoryReadCode(pc));
75 } 76 }
76 77
77 void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { 78 void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
79 parent.LogBacktrace();
78 LOG_CRITICAL(Core_ARM, 80 LOG_CRITICAL(Core_ARM,
79 "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", 81 "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
80 exception, pc, MemoryReadCode(pc), parent.IsInThumbMode()); 82 exception, pc, MemoryReadCode(pc), parent.IsInThumbMode());
@@ -186,35 +188,41 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
186 if (!Settings::values.cpuopt_recompile_exclusives) { 188 if (!Settings::values.cpuopt_recompile_exclusives) {
187 config.recompile_on_exclusive_fastmem_failure = false; 189 config.recompile_on_exclusive_fastmem_failure = false;
188 } 190 }
189 } 191 } else {
192 // Unsafe optimizations
193 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
194 config.unsafe_optimizations = true;
195 if (Settings::values.cpuopt_unsafe_unfuse_fma) {
196 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
197 }
198 if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
199 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
200 }
201 if (Settings::values.cpuopt_unsafe_ignore_standard_fpcr) {
202 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
203 }
204 if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
205 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
206 }
207 if (Settings::values.cpuopt_unsafe_ignore_global_monitor) {
208 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
209 }
210 }
190 211
191 // Unsafe optimizations 212 // Curated optimizations
192 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) { 213 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
193 config.unsafe_optimizations = true; 214 config.unsafe_optimizations = true;
194 if (Settings::values.cpuopt_unsafe_unfuse_fma) {
195 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 215 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
196 }
197 if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
198 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
199 }
200 if (Settings::values.cpuopt_unsafe_ignore_standard_fpcr) {
201 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; 216 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
202 }
203 if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
204 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; 217 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
205 }
206 if (Settings::values.cpuopt_unsafe_ignore_global_monitor) {
207 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; 218 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
208 } 219 }
209 }
210 220
211 // Curated optimizations 221 // Paranoia mode for debugging optimizations
212 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) { 222 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Paranoid) {
213 config.unsafe_optimizations = true; 223 config.unsafe_optimizations = false;
214 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 224 config.optimizations = Dynarmic::no_optimizations;
215 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; 225 }
216 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
217 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
218 } 226 }
219 227
220 return std::make_unique<Dynarmic::A32::Jit>(config); 228 return std::make_unique<Dynarmic::A32::Jit>(config);
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 24107f9f6..7ff8f9495 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -81,6 +81,7 @@ public:
81 } 81 }
82 82
83 void InterpreterFallback(u64 pc, std::size_t num_instructions) override { 83 void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
84 parent.LogBacktrace();
84 LOG_ERROR(Core_ARM, 85 LOG_ERROR(Core_ARM,
85 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, 86 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
86 num_instructions, MemoryReadCode(pc)); 87 num_instructions, MemoryReadCode(pc));
@@ -118,6 +119,7 @@ public:
118 return; 119 return;
119 case Dynarmic::A64::Exception::Breakpoint: 120 case Dynarmic::A64::Exception::Breakpoint:
120 default: 121 default:
122 parent.LogBacktrace();
121 ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", 123 ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
122 static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); 124 static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
123 } 125 }
@@ -248,35 +250,41 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
248 if (!Settings::values.cpuopt_recompile_exclusives) { 250 if (!Settings::values.cpuopt_recompile_exclusives) {
249 config.recompile_on_exclusive_fastmem_failure = false; 251 config.recompile_on_exclusive_fastmem_failure = false;
250 } 252 }
251 } 253 } else {
254 // Unsafe optimizations
255 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
256 config.unsafe_optimizations = true;
257 if (Settings::values.cpuopt_unsafe_unfuse_fma) {
258 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
259 }
260 if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
261 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
262 }
263 if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
264 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
265 }
266 if (Settings::values.cpuopt_unsafe_fastmem_check) {
267 config.fastmem_address_space_bits = 64;
268 }
269 if (Settings::values.cpuopt_unsafe_ignore_global_monitor) {
270 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
271 }
272 }
252 273
253 // Unsafe optimizations 274 // Curated optimizations
254 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) { 275 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
255 config.unsafe_optimizations = true; 276 config.unsafe_optimizations = true;
256 if (Settings::values.cpuopt_unsafe_unfuse_fma) {
257 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 277 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
258 }
259 if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
260 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
261 }
262 if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
263 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; 278 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
264 }
265 if (Settings::values.cpuopt_unsafe_fastmem_check) {
266 config.fastmem_address_space_bits = 64; 279 config.fastmem_address_space_bits = 64;
267 }
268 if (Settings::values.cpuopt_unsafe_ignore_global_monitor) {
269 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; 280 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
270 } 281 }
271 }
272 282
273 // Curated optimizations 283 // Paranoia mode for debugging optimizations
274 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) { 284 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Paranoid) {
275 config.unsafe_optimizations = true; 285 config.unsafe_optimizations = false;
276 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 286 config.optimizations = Dynarmic::no_optimizations;
277 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; 287 }
278 config.fastmem_address_space_bits = 64;
279 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
280 } 288 }
281 289
282 return std::make_shared<Dynarmic::A64::Jit>(config); 290 return std::make_shared<Dynarmic::A64::Jit>(config);
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 7a646b5f1..4ada4a69b 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -387,15 +387,17 @@ std::vector<NcaID> RegisteredCache::AccumulateFiles() const {
387 continue; 387 continue;
388 388
389 for (const auto& nca_dir : d2_dir->GetSubdirectories()) { 389 for (const auto& nca_dir : d2_dir->GetSubdirectories()) {
390 if (!FollowsNcaIdFormat(nca_dir->GetName())) 390 if (nca_dir == nullptr || !FollowsNcaIdFormat(nca_dir->GetName())) {
391 continue; 391 continue;
392 }
392 393
393 ids.push_back(Common::HexStringToArray<0x10, true>(nca_dir->GetName().substr(0, 0x20))); 394 ids.push_back(Common::HexStringToArray<0x10, true>(nca_dir->GetName().substr(0, 0x20)));
394 } 395 }
395 396
396 for (const auto& nca_file : d2_dir->GetFiles()) { 397 for (const auto& nca_file : d2_dir->GetFiles()) {
397 if (!FollowsNcaIdFormat(nca_file->GetName())) 398 if (nca_file == nullptr || !FollowsNcaIdFormat(nca_file->GetName())) {
398 continue; 399 continue;
400 }
399 401
400 ids.push_back( 402 ids.push_back(
401 Common::HexStringToArray<0x10, true>(nca_file->GetName().substr(0, 0x20))); 403 Common::HexStringToArray<0x10, true>(nca_file->GetName().substr(0, 0x20)));
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 42d1b0e31..b547a3463 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -24,8 +24,15 @@
24 24
25namespace Kernel { 25namespace Kernel {
26 26
27SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_) 27SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
28 : kernel{kernel_}, service_thread{kernel.CreateServiceThread(service_name_)} {} 28 ServiceThreadType thread_type)
29 : kernel{kernel_} {
30 if (thread_type == ServiceThreadType::CreateNew) {
31 service_thread = kernel.CreateServiceThread(service_name_);
32 } else {
33 service_thread = kernel.GetDefaultServiceThread();
34 }
35}
29 36
30SessionRequestHandler::~SessionRequestHandler() { 37SessionRequestHandler::~SessionRequestHandler() {
31 kernel.ReleaseServiceThread(service_thread); 38 kernel.ReleaseServiceThread(service_thread);
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 670cc741c..640146137 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -33,6 +33,11 @@ namespace Service {
33class ServiceFrameworkBase; 33class ServiceFrameworkBase;
34} 34}
35 35
36enum class ServiceThreadType {
37 Default,
38 CreateNew,
39};
40
36namespace Kernel { 41namespace Kernel {
37 42
38class Domain; 43class Domain;
@@ -57,7 +62,8 @@ enum class ThreadWakeupReason;
57 */ 62 */
58class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { 63class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
59public: 64public:
60 SessionRequestHandler(KernelCore& kernel, const char* service_name_); 65 SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
66 ServiceThreadType thread_type);
61 virtual ~SessionRequestHandler(); 67 virtual ~SessionRequestHandler();
62 68
63 /** 69 /**
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 34da7c23b..6387d0c29 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -61,6 +61,7 @@ struct KernelCore::Impl {
61 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); 61 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
62 global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); 62 global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
63 global_handle_table->Initialize(KHandleTable::MaxTableSize); 63 global_handle_table->Initialize(KHandleTable::MaxTableSize);
64 default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
64 65
65 is_phantom_mode_for_singlecore = false; 66 is_phantom_mode_for_singlecore = false;
66 67
@@ -677,6 +678,12 @@ struct KernelCore::Impl {
677 678
678 void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) { 679 void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
679 if (auto strong_ptr = service_thread.lock()) { 680 if (auto strong_ptr = service_thread.lock()) {
681 if (strong_ptr == default_service_thread.lock()) {
682 // Nothing to do here, the service is using default_service_thread, which will be
683 // released on shutdown.
684 return;
685 }
686
680 service_threads_manager.QueueWork( 687 service_threads_manager.QueueWork(
681 [this, strong_ptr{std::move(strong_ptr)}]() { service_threads.erase(strong_ptr); }); 688 [this, strong_ptr{std::move(strong_ptr)}]() { service_threads.erase(strong_ptr); });
682 } 689 }
@@ -739,7 +746,8 @@ struct KernelCore::Impl {
739 std::unique_ptr<KMemoryLayout> memory_layout; 746 std::unique_ptr<KMemoryLayout> memory_layout;
740 747
741 // Threads used for services 748 // Threads used for services
742 std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads; 749 std::unordered_set<std::shared_ptr<ServiceThread>> service_threads;
750 std::weak_ptr<ServiceThread> default_service_thread;
743 Common::ThreadWorker service_threads_manager; 751 Common::ThreadWorker service_threads_manager;
744 752
745 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads; 753 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads;
@@ -1065,6 +1073,10 @@ std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::
1065 return impl->CreateServiceThread(*this, name); 1073 return impl->CreateServiceThread(*this, name);
1066} 1074}
1067 1075
1076std::weak_ptr<Kernel::ServiceThread> KernelCore::GetDefaultServiceThread() const {
1077 return impl->default_service_thread;
1078}
1079
1068void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) { 1080void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
1069 impl->ReleaseServiceThread(service_thread); 1081 impl->ReleaseServiceThread(service_thread);
1070} 1082}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 4c68e96df..24e26fa44 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -271,9 +271,11 @@ public:
271 void ExitSVCProfile(); 271 void ExitSVCProfile();
272 272
273 /** 273 /**
274 * Creates an HLE service thread, which are used to execute service routines asynchronously. 274 * Creates a host thread to execute HLE service requests, which are used to execute service
275 * While these are allocated per ServerSession, these need to be owned and managed outside 275 * routines asynchronously. While these are allocated per ServerSession, these need to be owned
276 * of ServerSession to avoid a circular dependency. 276 * and managed outside of ServerSession to avoid a circular dependency. In general, most
277 * services can just use the default service thread, and not need their own host service thread.
278 * See GetDefaultServiceThread.
277 * @param name String name for the ServerSession creating this thread, used for debug 279 * @param name String name for the ServerSession creating this thread, used for debug
278 * purposes. 280 * purposes.
279 * @returns The a weak pointer newly created service thread. 281 * @returns The a weak pointer newly created service thread.
@@ -281,6 +283,14 @@ public:
281 std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name); 283 std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name);
282 284
283 /** 285 /**
286 * Gets the default host service thread, which executes HLE service requests. Unless service
287 * requests need to block on the host, the default service thread should be used in favor of
288 * creating a new service thread.
289 * @returns The a weak pointer for the default service thread.
290 */
291 std::weak_ptr<Kernel::ServiceThread> GetDefaultServiceThread() const;
292
293 /**
284 * Releases a HLE service thread, instructing KernelCore to free it. This should be called when 294 * Releases a HLE service thread, instructing KernelCore to free it. This should be called when
285 * the ServerSession associated with the thread is destroyed. 295 * the ServerSession associated with the thread is destroyed.
286 * @param service_thread Service thread to release. 296 * @param service_thread Service thread to release.
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 420de3c54..4d7e5ecd3 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1337,7 +1337,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1337 {200, nullptr, "GetLastApplicationExitReason"}, 1337 {200, nullptr, "GetLastApplicationExitReason"},
1338 {500, nullptr, "StartContinuousRecordingFlushForDebug"}, 1338 {500, nullptr, "StartContinuousRecordingFlushForDebug"},
1339 {1000, nullptr, "CreateMovieMaker"}, 1339 {1000, nullptr, "CreateMovieMaker"},
1340 {1001, nullptr, "PrepareForJit"}, 1340 {1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"},
1341 }; 1341 };
1342 // clang-format on 1342 // clang-format on
1343 1343
@@ -1787,6 +1787,13 @@ void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERe
1787 rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent()); 1787 rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent());
1788} 1788}
1789 1789
1790void IApplicationFunctions::PrepareForJit(Kernel::HLERequestContext& ctx) {
1791 LOG_WARNING(Service_AM, "(STUBBED) called");
1792
1793 IPC::ResponseBuilder rb{ctx, 2};
1794 rb.Push(ResultSuccess);
1795}
1796
1790void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, 1797void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
1791 Core::System& system) { 1798 Core::System& system) {
1792 auto message_queue = std::make_shared<AppletMessageQueue>(system); 1799 auto message_queue = std::make_shared<AppletMessageQueue>(system);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index fdd937b82..11a3c0459 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -336,6 +336,7 @@ private:
336 void TryPopFromFriendInvitationStorageChannel(Kernel::HLERequestContext& ctx); 336 void TryPopFromFriendInvitationStorageChannel(Kernel::HLERequestContext& ctx);
337 void GetNotificationStorageChannelEvent(Kernel::HLERequestContext& ctx); 337 void GetNotificationStorageChannelEvent(Kernel::HLERequestContext& ctx);
338 void GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx); 338 void GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx);
339 void PrepareForJit(Kernel::HLERequestContext& ctx);
339 340
340 KernelHelpers::ServiceContext service_context; 341 KernelHelpers::ServiceContext service_context;
341 342
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index affa7971c..a72956a28 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -41,9 +41,10 @@ public:
41 explicit IAudioOut(Core::System& system_, AudoutParams audio_params_, 41 explicit IAudioOut(Core::System& system_, AudoutParams audio_params_,
42 AudioCore::AudioOut& audio_core_, std::string&& device_name_, 42 AudioCore::AudioOut& audio_core_, std::string&& device_name_,
43 std::string&& unique_name) 43 std::string&& unique_name)
44 : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_}, 44 : ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew},
45 device_name{std::move(device_name_)}, audio_params{audio_params_}, 45 audio_core{audio_core_}, device_name{std::move(device_name_)},
46 main_memory{system.Memory()}, service_context{system_, "IAudioOut"} { 46 audio_params{audio_params_}, main_memory{system.Memory()}, service_context{system_,
47 "IAudioOut"} {
47 // clang-format off 48 // clang-format off
48 static const FunctionInfo functions[] = { 49 static const FunctionInfo functions[] = {
49 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 50 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index f45e5cecc..d4ffeb21d 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -24,7 +24,8 @@ public:
24 explicit IAudioRenderer(Core::System& system_, 24 explicit IAudioRenderer(Core::System& system_,
25 const AudioCommon::AudioRendererParameter& audren_params, 25 const AudioCommon::AudioRendererParameter& audren_params,
26 const std::size_t instance_number) 26 const std::size_t instance_number)
27 : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"} { 27 : ServiceFramework{system_, "IAudioRenderer", ServiceThreadType::CreateNew},
28 service_context{system_, "IAudioRenderer"} {
28 // clang-format off 29 // clang-format off
29 static const FunctionInfo functions[] = { 30 static const FunctionInfo functions[] = {
30 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, 31 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index b087e7bba..c07929ab8 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -58,7 +58,8 @@ enum class FileSystemType : u8 {
58class IStorage final : public ServiceFramework<IStorage> { 58class IStorage final : public ServiceFramework<IStorage> {
59public: 59public:
60 explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_) 60 explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_)
61 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { 61 : ServiceFramework{system_, "IStorage", ServiceThreadType::CreateNew},
62 backend(std::move(backend_)) {
62 static const FunctionInfo functions[] = { 63 static const FunctionInfo functions[] = {
63 {0, &IStorage::Read, "Read"}, 64 {0, &IStorage::Read, "Read"},
64 {1, nullptr, "Write"}, 65 {1, nullptr, "Write"},
@@ -116,7 +117,8 @@ private:
116class IFile final : public ServiceFramework<IFile> { 117class IFile final : public ServiceFramework<IFile> {
117public: 118public:
118 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_) 119 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
119 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { 120 : ServiceFramework{system_, "IFile", ServiceThreadType::CreateNew},
121 backend(std::move(backend_)) {
120 static const FunctionInfo functions[] = { 122 static const FunctionInfo functions[] = {
121 {0, &IFile::Read, "Read"}, 123 {0, &IFile::Read, "Read"},
122 {1, &IFile::Write, "Write"}, 124 {1, &IFile::Write, "Write"},
@@ -252,7 +254,8 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec
252class IDirectory final : public ServiceFramework<IDirectory> { 254class IDirectory final : public ServiceFramework<IDirectory> {
253public: 255public:
254 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_) 256 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_)
255 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { 257 : ServiceFramework{system_, "IDirectory", ServiceThreadType::CreateNew},
258 backend(std::move(backend_)) {
256 static const FunctionInfo functions[] = { 259 static const FunctionInfo functions[] = {
257 {0, &IDirectory::Read, "Read"}, 260 {0, &IDirectory::Read, "Read"},
258 {1, &IDirectory::GetEntryCount, "GetEntryCount"}, 261 {1, &IDirectory::GetEntryCount, "GetEntryCount"},
@@ -308,8 +311,8 @@ private:
308class IFileSystem final : public ServiceFramework<IFileSystem> { 311class IFileSystem final : public ServiceFramework<IFileSystem> {
309public: 312public:
310 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) 313 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
311 : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( 314 : ServiceFramework{system_, "IFileSystem", ServiceThreadType::CreateNew},
312 size_)} { 315 backend{std::move(backend_)}, size{std::move(size_)} {
313 static const FunctionInfo functions[] = { 316 static const FunctionInfo functions[] = {
314 {0, &IFileSystem::CreateFile, "CreateFile"}, 317 {0, &IFileSystem::CreateFile, "CreateFile"},
315 {1, &IFileSystem::DeleteFile, "DeleteFile"}, 318 {1, &IFileSystem::DeleteFile, "DeleteFile"},
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 92e6bf889..b2cec2253 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -63,6 +63,10 @@ IAppletResource::IAppletResource(Core::System& system_,
63 MakeController<Controller_Gesture>(HidController::Gesture); 63 MakeController<Controller_Gesture>(HidController::Gesture);
64 MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor); 64 MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor);
65 65
66 // Homebrew doesn't try to activate some controllers, so we activate them by default
67 GetController<Controller_NPad>(HidController::NPad).ActivateController();
68 GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController();
69
66 GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00); 70 GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
67 GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00); 71 GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
68 GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000); 72 GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp
new file mode 100644
index 000000000..c8ebd2e3f
--- /dev/null
+++ b/src/core/hle/service/jit/jit.cpp
@@ -0,0 +1,53 @@
1// Copyright 2022 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/ipc_helpers.h"
6#include "core/hle/result.h"
7#include "core/hle/service/jit/jit.h"
8#include "core/hle/service/service.h"
9
10namespace Service::JIT {
11
12class IJitEnvironment final : public ServiceFramework<IJitEnvironment> {
13public:
14 explicit IJitEnvironment(Core::System& system_) : ServiceFramework{system_, "IJitEnvironment"} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, nullptr, "GenerateCode"},
18 {1, nullptr, "Control"},
19 {1000, nullptr, "LoadPlugin"},
20 {1001, nullptr, "GetCodeAddress"},
21 };
22 // clang-format on
23
24 RegisterHandlers(functions);
25 }
26};
27
28class JITU final : public ServiceFramework<JITU> {
29public:
30 explicit JITU(Core::System& system_) : ServiceFramework{system_, "jit:u"} {
31 // clang-format off
32 static const FunctionInfo functions[] = {
33 {0, &JITU::CreateJitEnvironment, "CreateJitEnvironment"},
34 };
35 // clang-format on
36
37 RegisterHandlers(functions);
38 }
39
40 void CreateJitEnvironment(Kernel::HLERequestContext& ctx) {
41 LOG_DEBUG(Service_JIT, "called");
42
43 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
44 rb.Push(ResultSuccess);
45 rb.PushIpcInterface<IJitEnvironment>(system);
46 }
47};
48
49void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
50 std::make_shared<JITU>(system)->InstallAsService(sm);
51}
52
53} // namespace Service::JIT
diff --git a/src/core/hle/service/jit/jit.h b/src/core/hle/service/jit/jit.h
new file mode 100644
index 000000000..8fbf504a1
--- /dev/null
+++ b/src/core/hle/service/jit/jit.h
@@ -0,0 +1,20 @@
1// Copyright 2022 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7namespace Core {
8class System;
9}
10
11namespace Service::SM {
12class ServiceManager;
13}
14
15namespace Service::JIT {
16
17/// Registers all JIT services with the specified service manager.
18void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
19
20} // namespace Service::JIT
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
index 1ce2a856b..8467b50e4 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
@@ -230,7 +230,7 @@ void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
230} 230}
231 231
232NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name) 232NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name)
233 : ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} { 233 : ServiceFramework{system_, name, ServiceThreadType::CreateNew}, nvdrv{std::move(nvdrv_)} {
234 static const FunctionInfo functions[] = { 234 static const FunctionInfo functions[] = {
235 {0, &NVDRV::Open, "Open"}, 235 {0, &NVDRV::Open, "Open"},
236 {1, &NVDRV::Ioctl1, "Ioctl"}, 236 {1, &NVDRV::Ioctl1, "Ioctl"},
diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
index 41fbba219..c527c577e 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
@@ -18,8 +18,7 @@ BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_)
18BufferQueueConsumer::~BufferQueueConsumer() = default; 18BufferQueueConsumer::~BufferQueueConsumer() = default;
19 19
20Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, 20Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
21 std::chrono::nanoseconds expected_present, 21 std::chrono::nanoseconds expected_present) {
22 u64 max_frame_number) {
23 std::scoped_lock lock(core->mutex); 22 std::scoped_lock lock(core->mutex);
24 23
25 // Check that the consumer doesn't currently have the maximum number of buffers acquired. 24 // Check that the consumer doesn't currently have the maximum number of buffers acquired.
@@ -50,12 +49,6 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
50 while (core->queue.size() > 1 && !core->queue[0].is_auto_timestamp) { 49 while (core->queue.size() > 1 && !core->queue[0].is_auto_timestamp) {
51 const auto& buffer_item{core->queue[1]}; 50 const auto& buffer_item{core->queue[1]};
52 51
53 // If dropping entry[0] would leave us with a buffer that the consumer is not yet ready
54 // for, don't drop it.
55 if (max_frame_number && buffer_item.frame_number > max_frame_number) {
56 break;
57 }
58
59 // If entry[1] is timely, drop entry[0] (and repeat). 52 // If entry[1] is timely, drop entry[0] (and repeat).
60 const auto desired_present = buffer_item.timestamp; 53 const auto desired_present = buffer_item.timestamp;
61 if (desired_present < expected_present.count() - MAX_REASONABLE_NSEC || 54 if (desired_present < expected_present.count() - MAX_REASONABLE_NSEC ||
@@ -200,4 +193,39 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_
200 return Status::NoError; 193 return Status::NoError;
201} 194}
202 195
196Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
197 if (out_slot_mask == nullptr) {
198 LOG_ERROR(Service_NVFlinger, "out_slot_mask may not be nullptr");
199 return Status::BadValue;
200 }
201
202 std::scoped_lock lock(core->mutex);
203
204 if (core->is_abandoned) {
205 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
206 return Status::NoInit;
207 }
208
209 u64 mask = 0;
210 for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
211 if (!slots[s].acquire_called) {
212 mask |= (1ULL << s);
213 }
214 }
215
216 // Remove from the mask queued buffers for which acquire has been called, since the consumer
217 // will not receive their buffer addresses and so must retain their cached information
218 auto current(core->queue.begin());
219 while (current != core->queue.end()) {
220 if (current->acquire_called) {
221 mask &= ~(1ULL << current->slot);
222 }
223 ++current;
224 }
225
226 LOG_DEBUG(Service_NVFlinger, "returning mask {}", mask);
227 *out_slot_mask = mask;
228 return Status::NoError;
229}
230
203} // namespace Service::android 231} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.h b/src/core/hle/service/nvflinger/buffer_queue_consumer.h
index f22854394..8a047fe06 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_consumer.h
+++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.h
@@ -24,10 +24,10 @@ public:
24 explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_); 24 explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_);
25 ~BufferQueueConsumer(); 25 ~BufferQueueConsumer();
26 26
27 Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present, 27 Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present);
28 u64 max_frame_number = 0);
29 Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); 28 Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
30 Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app); 29 Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app);
30 Status GetReleasedBuffers(u64* out_slot_mask);
31 31
32private: 32private:
33 std::shared_ptr<BufferQueueCore> core; 33 std::shared_ptr<BufferQueueCore> core;
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
index 6082610e0..3a0481786 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
@@ -95,7 +95,6 @@ void BufferQueueCore::FreeBufferLocked(s32 slot) {
95} 95}
96 96
97void BufferQueueCore::FreeAllBuffersLocked() { 97void BufferQueueCore::FreeAllBuffersLocked() {
98 queue.clear();
99 buffer_has_been_queued = false; 98 buffer_has_been_queued = false;
100 99
101 for (s32 slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { 100 for (s32 slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h
index 4dfd53387..e4e0937cb 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_core.h
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.h
@@ -73,8 +73,6 @@ private:
73 u32 transform_hint{}; 73 u32 transform_hint{};
74 bool is_allocating{}; 74 bool is_allocating{};
75 mutable std::condition_variable_any is_allocating_condition; 75 mutable std::condition_variable_any is_allocating_condition;
76 bool allow_allocation{true};
77 u64 buffer_age{};
78 bool is_shutting_down{}; 76 bool is_shutting_down{};
79}; 77};
80 78
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
index 0833be57a..3d6e990c3 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
@@ -62,11 +62,12 @@ Status BufferQueueProducer::RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffe
62 62
63Status BufferQueueProducer::SetBufferCount(s32 buffer_count) { 63Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
64 LOG_DEBUG(Service_NVFlinger, "count = {}", buffer_count); 64 LOG_DEBUG(Service_NVFlinger, "count = {}", buffer_count);
65 std::shared_ptr<IConsumerListener> listener;
66 65
66 std::shared_ptr<IConsumerListener> listener;
67 { 67 {
68 std::scoped_lock lock(core->mutex); 68 std::scoped_lock lock(core->mutex);
69 core->WaitWhileAllocatingLocked(); 69 core->WaitWhileAllocatingLocked();
70
70 if (core->is_abandoned) { 71 if (core->is_abandoned) {
71 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); 72 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
72 return Status::NoInit; 73 return Status::NoInit;
@@ -120,7 +121,7 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
120} 121}
121 122
122Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, 123Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found,
123 Status* returnFlags) const { 124 Status* return_flags) const {
124 bool try_again = true; 125 bool try_again = true;
125 126
126 while (try_again) { 127 while (try_again) {
@@ -142,10 +143,12 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found,
142 ASSERT(slots[s].buffer_state == BufferState::Free); 143 ASSERT(slots[s].buffer_state == BufferState::Free);
143 if (slots[s].graphic_buffer != nullptr) { 144 if (slots[s].graphic_buffer != nullptr) {
144 core->FreeBufferLocked(s); 145 core->FreeBufferLocked(s);
145 *returnFlags |= Status::ReleaseAllBuffers; 146 *return_flags |= Status::ReleaseAllBuffers;
146 } 147 }
147 } 148 }
148 149
150 // Look for a free buffer to give to the client
151 *found = BufferQueueCore::INVALID_BUFFER_SLOT;
149 s32 dequeued_count{}; 152 s32 dequeued_count{};
150 s32 acquired_count{}; 153 s32 acquired_count{};
151 for (s32 s{}; s < max_buffer_count; ++s) { 154 for (s32 s{}; s < max_buffer_count; ++s) {
@@ -235,68 +238,50 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
235 { 238 {
236 std::scoped_lock lock(core->mutex); 239 std::scoped_lock lock(core->mutex);
237 core->WaitWhileAllocatingLocked(); 240 core->WaitWhileAllocatingLocked();
241
238 if (format == PixelFormat::NoFormat) { 242 if (format == PixelFormat::NoFormat) {
239 format = core->default_buffer_format; 243 format = core->default_buffer_format;
240 } 244 }
241 245
242 // Enable the usage bits the consumer requested 246 // Enable the usage bits the consumer requested
243 usage |= core->consumer_usage_bit; 247 usage |= core->consumer_usage_bit;
244 const bool use_default_size = !width && !height; 248
245 if (use_default_size) { 249 s32 found{};
246 width = core->default_width; 250 Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags);
247 height = core->default_height; 251 if (status != Status::NoError) {
252 return status;
248 } 253 }
249 254
250 s32 found = BufferItem::INVALID_BUFFER_SLOT; 255 // This should not happen
251 while (found == BufferItem::INVALID_BUFFER_SLOT) { 256 if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
252 Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags); 257 LOG_ERROR(Service_NVFlinger, "no available buffer slots");
253 if (status != Status::NoError) { 258 return Status::Busy;
254 return status; 259 }
255 }
256 260
257 // This should not happen 261 *out_slot = found;
258 if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
259 LOG_DEBUG(Service_NVFlinger, "no available buffer slots");
260 return Status::Busy;
261 }
262 262
263 const std::shared_ptr<GraphicBuffer>& buffer(slots[found].graphic_buffer); 263 attached_by_consumer = slots[found].attached_by_consumer;
264 264
265 // If we are not allowed to allocate new buffers, WaitForFreeSlotThenRelock must have 265 const bool use_default_size = !width && !height;
266 // returned a slot containing a buffer. If this buffer would require reallocation to 266 if (use_default_size) {
267 // meet the requested attributes, we free it and attempt to get another one. 267 width = core->default_width;
268 if (!core->allow_allocation) { 268 height = core->default_height;
269 if (buffer->NeedsReallocation(width, height, format, usage)) {
270 core->FreeBufferLocked(found);
271 found = BufferItem::INVALID_BUFFER_SLOT;
272 continue;
273 }
274 }
275 } 269 }
276 270
277 *out_slot = found;
278 attached_by_consumer = slots[found].attached_by_consumer;
279 slots[found].buffer_state = BufferState::Dequeued; 271 slots[found].buffer_state = BufferState::Dequeued;
280 272
281 const std::shared_ptr<GraphicBuffer>& buffer(slots[found].graphic_buffer); 273 const std::shared_ptr<GraphicBuffer>& buffer(slots[found].graphic_buffer);
282 274 if ((buffer == nullptr) || (buffer->Width() != width) || (buffer->Height() != height) ||
283 if ((buffer == nullptr) || buffer->NeedsReallocation(width, height, format, usage)) { 275 (buffer->Format() != format) || ((buffer->Usage() & usage) != usage)) {
284 slots[found].acquire_called = false; 276 slots[found].acquire_called = false;
285 slots[found].graphic_buffer = nullptr; 277 slots[found].graphic_buffer = nullptr;
286 slots[found].request_buffer_called = false; 278 slots[found].request_buffer_called = false;
287 slots[found].fence = Fence::NoFence(); 279 slots[found].fence = Fence::NoFence();
288 core->buffer_age = 0; 280
289 return_flags |= Status::BufferNeedsReallocation; 281 return_flags |= Status::BufferNeedsReallocation;
290 } else {
291 // We add 1 because that will be the frame number when this buffer
292 // is queued
293 core->buffer_age = core->frame_counter + 1 - slots[found].frame_number;
294 } 282 }
295 283
296 LOG_DEBUG(Service_NVFlinger, "setting buffer age to {}", core->buffer_age);
297
298 *out_fence = slots[found].fence; 284 *out_fence = slots[found].fence;
299
300 slots[found].fence = Fence::NoFence(); 285 slots[found].fence = Fence::NoFence();
301 } 286 }
302 287
@@ -311,6 +296,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
311 296
312 { 297 {
313 std::scoped_lock lock(core->mutex); 298 std::scoped_lock lock(core->mutex);
299
314 if (core->is_abandoned) { 300 if (core->is_abandoned) {
315 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); 301 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
316 return Status::NoInit; 302 return Status::NoInit;
@@ -327,6 +313,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
327 313
328 LOG_DEBUG(Service_NVFlinger, "returning slot={} frame={}, flags={}", *out_slot, 314 LOG_DEBUG(Service_NVFlinger, "returning slot={} frame={}, flags={}", *out_slot,
329 slots[*out_slot].frame_number, return_flags); 315 slots[*out_slot].frame_number, return_flags);
316
330 return return_flags; 317 return return_flags;
331} 318}
332 319
@@ -334,6 +321,7 @@ Status BufferQueueProducer::DetachBuffer(s32 slot) {
334 LOG_DEBUG(Service_NVFlinger, "slot {}", slot); 321 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
335 322
336 std::scoped_lock lock(core->mutex); 323 std::scoped_lock lock(core->mutex);
324
337 if (core->is_abandoned) { 325 if (core->is_abandoned) {
338 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); 326 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
339 return Status::NoInit; 327 return Status::NoInit;
@@ -369,7 +357,6 @@ Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out
369 } 357 }
370 358
371 std::scoped_lock lock(core->mutex); 359 std::scoped_lock lock(core->mutex);
372
373 core->WaitWhileAllocatingLocked(); 360 core->WaitWhileAllocatingLocked();
374 361
375 if (core->is_abandoned) { 362 if (core->is_abandoned) {
@@ -423,6 +410,7 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot,
423 return status; 410 return status;
424 } 411 }
425 412
413 // This should not happen
426 if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { 414 if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
427 LOG_ERROR(Service_NVFlinger, "No available buffer slots"); 415 LOG_ERROR(Service_NVFlinger, "No available buffer slots");
428 return Status::Busy; 416 return Status::Busy;
@@ -466,8 +454,8 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
466 return Status::BadValue; 454 return Status::BadValue;
467 } 455 }
468 456
469 std::shared_ptr<IConsumerListener> frameAvailableListener; 457 std::shared_ptr<IConsumerListener> frame_available_listener;
470 std::shared_ptr<IConsumerListener> frameReplacedListener; 458 std::shared_ptr<IConsumerListener> frame_replaced_listener;
471 s32 callback_ticket{}; 459 s32 callback_ticket{};
472 BufferItem item; 460 BufferItem item;
473 461
@@ -541,12 +529,13 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
541 item.fence = fence; 529 item.fence = fence;
542 item.is_droppable = core->dequeue_buffer_cannot_block || async; 530 item.is_droppable = core->dequeue_buffer_cannot_block || async;
543 item.swap_interval = swap_interval; 531 item.swap_interval = swap_interval;
532
544 sticky_transform = sticky_transform_; 533 sticky_transform = sticky_transform_;
545 534
546 if (core->queue.empty()) { 535 if (core->queue.empty()) {
547 // When the queue is empty, we can simply queue this buffer 536 // When the queue is empty, we can simply queue this buffer
548 core->queue.push_back(item); 537 core->queue.push_back(item);
549 frameAvailableListener = core->consumer_listener; 538 frame_available_listener = core->consumer_listener;
550 } else { 539 } else {
551 // When the queue is not empty, we need to look at the front buffer 540 // When the queue is not empty, we need to look at the front buffer
552 // state to see if we need to replace it 541 // state to see if we need to replace it
@@ -563,10 +552,10 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
563 } 552 }
564 // Overwrite the droppable buffer with the incoming one 553 // Overwrite the droppable buffer with the incoming one
565 *front = item; 554 *front = item;
566 frameReplacedListener = core->consumer_listener; 555 frame_replaced_listener = core->consumer_listener;
567 } else { 556 } else {
568 core->queue.push_back(item); 557 core->queue.push_back(item);
569 frameAvailableListener = core->consumer_listener; 558 frame_available_listener = core->consumer_listener;
570 } 559 }
571 } 560 }
572 561
@@ -592,10 +581,10 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
592 callback_condition.wait(callback_mutex); 581 callback_condition.wait(callback_mutex);
593 } 582 }
594 583
595 if (frameAvailableListener != nullptr) { 584 if (frame_available_listener != nullptr) {
596 frameAvailableListener->OnFrameAvailable(item); 585 frame_available_listener->OnFrameAvailable(item);
597 } else if (frameReplacedListener != nullptr) { 586 } else if (frame_replaced_listener != nullptr) {
598 frameReplacedListener->OnFrameReplaced(item); 587 frame_replaced_listener->OnFrameReplaced(item);
599 } 588 }
600 589
601 ++current_callback_ticket; 590 ++current_callback_ticket;
@@ -669,13 +658,6 @@ Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) {
669 case NativeWindow::ConsumerUsageBits: 658 case NativeWindow::ConsumerUsageBits:
670 value = core->consumer_usage_bit; 659 value = core->consumer_usage_bit;
671 break; 660 break;
672 case NativeWindow::BufferAge:
673 if (core->buffer_age > INT32_MAX) {
674 value = 0;
675 } else {
676 value = static_cast<u32>(core->buffer_age);
677 }
678 break;
679 default: 661 default:
680 UNREACHABLE(); 662 UNREACHABLE();
681 return Status::BadValue; 663 return Status::BadValue;
@@ -737,7 +719,6 @@ Status BufferQueueProducer::Connect(const std::shared_ptr<IProducerListener>& li
737 core->buffer_has_been_queued = false; 719 core->buffer_has_been_queued = false;
738 core->dequeue_buffer_cannot_block = 720 core->dequeue_buffer_cannot_block =
739 core->consumer_controlled_by_app && producer_controlled_by_app; 721 core->consumer_controlled_by_app && producer_controlled_by_app;
740 core->allow_allocation = true;
741 722
742 return status; 723 return status;
743} 724}
@@ -770,7 +751,7 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
770 core->SignalDequeueCondition(); 751 core->SignalDequeueCondition();
771 buffer_wait_event->GetWritableEvent().Signal(); 752 buffer_wait_event->GetWritableEvent().Signal();
772 listener = core->consumer_listener; 753 listener = core->consumer_listener;
773 } else if (core->connected_api != NativeWindowApi::NoConnectedApi) { 754 } else {
774 LOG_ERROR(Service_NVFlinger, "still connected to another api (cur = {} req = {})", 755 LOG_ERROR(Service_NVFlinger, "still connected to another api (cur = {} req = {})",
775 core->connected_api, api); 756 core->connected_api, api);
776 status = Status::BadValue; 757 status = Status::BadValue;
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h
index 77fdcae8e..c4ca68fd3 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.h
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h
@@ -66,7 +66,7 @@ public:
66private: 66private:
67 BufferQueueProducer(const BufferQueueProducer&) = delete; 67 BufferQueueProducer(const BufferQueueProducer&) = delete;
68 68
69 Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* returnFlags) const; 69 Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags) const;
70 70
71 Kernel::KEvent* buffer_wait_event{}; 71 Kernel::KEvent* buffer_wait_event{};
72 Service::KernelHelpers::ServiceContext& service_context; 72 Service::KernelHelpers::ServiceContext& service_context;
diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp
index be65a3f88..c2c80832c 100644
--- a/src/core/hle/service/nvflinger/consumer_base.cpp
+++ b/src/core/hle/service/nvflinger/consumer_base.cpp
@@ -36,38 +36,41 @@ void ConsumerBase::FreeBufferLocked(s32 slot_index) {
36} 36}
37 37
38void ConsumerBase::OnFrameAvailable(const BufferItem& item) { 38void ConsumerBase::OnFrameAvailable(const BufferItem& item) {
39 std::scoped_lock lock(mutex);
40 LOG_DEBUG(Service_NVFlinger, "called"); 39 LOG_DEBUG(Service_NVFlinger, "called");
41} 40}
42 41
43void ConsumerBase::OnFrameReplaced(const BufferItem& item) { 42void ConsumerBase::OnFrameReplaced(const BufferItem& item) {
44 std::scoped_lock lock(mutex);
45 LOG_DEBUG(Service_NVFlinger, "called"); 43 LOG_DEBUG(Service_NVFlinger, "called");
46} 44}
47 45
48void ConsumerBase::OnBuffersReleased() { 46void ConsumerBase::OnBuffersReleased() {
49 std::scoped_lock lock(mutex); 47 std::scoped_lock lock(mutex);
50 LOG_DEBUG(Service_NVFlinger, "called");
51}
52 48
53void ConsumerBase::OnSidebandStreamChanged() {} 49 LOG_DEBUG(Service_NVFlinger, "called");
54 50
55Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when,
56 u64 max_frame_number) {
57 if (is_abandoned) { 51 if (is_abandoned) {
58 LOG_ERROR(Service_NVFlinger, "consumer is abandoned!"); 52 // Nothing to do if we're already abandoned.
59 return Status::NoInit; 53 return;
60 } 54 }
61 55
62 Status err = consumer->AcquireBuffer(item, present_when, max_frame_number); 56 u64 mask = 0;
57 consumer->GetReleasedBuffers(&mask);
58 for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) {
59 if (mask & (1ULL << i)) {
60 FreeBufferLocked(i);
61 }
62 }
63}
64
65void ConsumerBase::OnSidebandStreamChanged() {}
66
67Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when) {
68 Status err = consumer->AcquireBuffer(item, present_when);
63 if (err != Status::NoError) { 69 if (err != Status::NoError) {
64 return err; 70 return err;
65 } 71 }
66 72
67 if (item->graphic_buffer != nullptr) { 73 if (item->graphic_buffer != nullptr) {
68 if (slots[item->slot].graphic_buffer != nullptr) {
69 FreeBufferLocked(item->slot);
70 }
71 slots[item->slot].graphic_buffer = item->graphic_buffer; 74 slots[item->slot].graphic_buffer = item->graphic_buffer;
72 } 75 }
73 76
diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h
index 9ab949420..736080e3a 100644
--- a/src/core/hle/service/nvflinger/consumer_base.h
+++ b/src/core/hle/service/nvflinger/consumer_base.h
@@ -35,8 +35,7 @@ protected:
35 virtual void OnSidebandStreamChanged() override; 35 virtual void OnSidebandStreamChanged() override;
36 36
37 void FreeBufferLocked(s32 slot_index); 37 void FreeBufferLocked(s32 slot_index);
38 Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when, 38 Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when);
39 u64 max_frame_number = 0);
40 Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer); 39 Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer);
41 bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer) const; 40 bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer) const;
42 Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer, 41 Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer,
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 76ce1fbfd..6fb2cdff1 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -104,7 +104,7 @@ void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
104std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { 104std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
105 const auto lock_guard = Lock(); 105 const auto lock_guard = Lock();
106 106
107 LOG_DEBUG(Service, "Opening \"{}\" display", name); 107 LOG_DEBUG(Service_NVFlinger, "Opening \"{}\" display", name);
108 108
109 const auto itr = 109 const auto itr =
110 std::find_if(displays.begin(), displays.end(), 110 std::find_if(displays.begin(), displays.end(),
@@ -219,7 +219,7 @@ VI::Layer* NVFlinger::FindOrCreateLayer(u64 display_id, u64 layer_id) {
219 auto* layer = display->FindLayer(layer_id); 219 auto* layer = display->FindLayer(layer_id);
220 220
221 if (layer == nullptr) { 221 if (layer == nullptr) {
222 LOG_DEBUG(Service, "Layer at id {} not found. Trying to create it.", layer_id); 222 LOG_DEBUG(Service_NVFlinger, "Layer at id {} not found. Trying to create it.", layer_id);
223 CreateLayerAtId(*display, layer_id); 223 CreateLayerAtId(*display, layer_id);
224 return display->FindLayer(layer_id); 224 return display->FindLayer(layer_id);
225 } 225 }
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index ab3286db9..0f59a03c5 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -32,6 +32,7 @@
32#include "core/hle/service/glue/glue.h" 32#include "core/hle/service/glue/glue.h"
33#include "core/hle/service/grc/grc.h" 33#include "core/hle/service/grc/grc.h"
34#include "core/hle/service/hid/hid.h" 34#include "core/hle/service/hid/hid.h"
35#include "core/hle/service/jit/jit.h"
35#include "core/hle/service/lbl/lbl.h" 36#include "core/hle/service/lbl/lbl.h"
36#include "core/hle/service/ldn/ldn.h" 37#include "core/hle/service/ldn/ldn.h"
37#include "core/hle/service/ldr/ldr.h" 38#include "core/hle/service/ldr/ldr.h"
@@ -91,8 +92,9 @@ namespace Service {
91} 92}
92 93
93ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_, 94ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
94 u32 max_sessions_, InvokerFn* handler_invoker_) 95 ServiceThreadType thread_type, u32 max_sessions_,
95 : SessionRequestHandler(system_.Kernel(), service_name_), system{system_}, 96 InvokerFn* handler_invoker_)
97 : SessionRequestHandler(system_.Kernel(), service_name_, thread_type), system{system_},
96 service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {} 98 service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {}
97 99
98ServiceFrameworkBase::~ServiceFrameworkBase() { 100ServiceFrameworkBase::~ServiceFrameworkBase() {
@@ -261,6 +263,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
261 Glue::InstallInterfaces(system); 263 Glue::InstallInterfaces(system);
262 GRC::InstallInterfaces(*sm, system); 264 GRC::InstallInterfaces(*sm, system);
263 HID::InstallInterfaces(*sm, system); 265 HID::InstallInterfaces(*sm, system);
266 JIT::InstallInterfaces(*sm, system);
264 LBL::InstallInterfaces(*sm, system); 267 LBL::InstallInterfaces(*sm, system);
265 LDN::InstallInterfaces(*sm, system); 268 LDN::InstallInterfaces(*sm, system);
266 LDR::InstallInterfaces(*sm, system); 269 LDR::InstallInterfaces(*sm, system);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index b9ab2c465..c78b2baeb 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -114,7 +114,8 @@ private:
114 Kernel::HLERequestContext& ctx); 114 Kernel::HLERequestContext& ctx);
115 115
116 explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_, 116 explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_,
117 u32 max_sessions_, InvokerFn* handler_invoker_); 117 ServiceThreadType thread_type, u32 max_sessions_,
118 InvokerFn* handler_invoker_);
118 ~ServiceFrameworkBase() override; 119 ~ServiceFrameworkBase() override;
119 120
120 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); 121 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
@@ -176,14 +177,17 @@ protected:
176 /** 177 /**
177 * Initializes the handler with no functions installed. 178 * Initializes the handler with no functions installed.
178 * 179 *
179 * @param system_ The system context to construct this service under. 180 * @param system_ The system context to construct this service under.
180 * @param service_name_ Name of the service. 181 * @param service_name_ Name of the service.
181 * @param max_sessions_ Maximum number of sessions that can be 182 * @param thread_type Specifies the thread type for this service. If this is set to CreateNew,
182 * connected to this service at the same time. 183 * it creates a new thread for it, otherwise this uses the default thread.
184 * @param max_sessions_ Maximum number of sessions that can be connected to this service at the
185 * same time.
183 */ 186 */
184 explicit ServiceFramework(Core::System& system_, const char* service_name_, 187 explicit ServiceFramework(Core::System& system_, const char* service_name_,
188 ServiceThreadType thread_type = ServiceThreadType::Default,
185 u32 max_sessions_ = ServerSessionCountMax) 189 u32 max_sessions_ = ServerSessionCountMax)
186 : ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {} 190 : ServiceFrameworkBase(system_, service_name_, thread_type, max_sessions_, Invoker) {}
187 191
188 /// Registers handlers in the service. 192 /// Registers handlers in the service.
189 template <std::size_t N> 193 template <std::size_t N>
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 695a1faa6..97f895852 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -206,7 +206,7 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
206} 206}
207 207
208SM::SM(ServiceManager& service_manager_, Core::System& system_) 208SM::SM(ServiceManager& service_manager_, Core::System& system_)
209 : ServiceFramework{system_, "sm:", 4}, 209 : ServiceFramework{system_, "sm:", ServiceThreadType::Default, 4},
210 service_manager{service_manager_}, kernel{system_.Kernel()} { 210 service_manager{service_manager_}, kernel{system_.Kernel()} {
211 RegisterHandlers({ 211 RegisterHandlers({
212 {0, &SM::Initialize, "Initialize"}, 212 {0, &SM::Initialize, "Initialize"},
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index fc93fb743..d6702e4e1 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -837,7 +837,8 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co
837 rb.PushEnum(bsd_errno); 837 rb.PushEnum(bsd_errno);
838} 838}
839 839
840BSD::BSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} { 840BSD::BSD(Core::System& system_, const char* name)
841 : ServiceFramework{system_, name, ServiceThreadType::CreateNew} {
841 // clang-format off 842 // clang-format off
842 static const FunctionInfo functions[] = { 843 static const FunctionInfo functions[] = {
843 {0, &BSD::RegisterClient, "RegisterClient"}, 844 {0, &BSD::RegisterClient, "RegisterClient"},
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 430cbc546..a3436c8ea 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -77,7 +77,8 @@ static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size");
77class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { 77class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
78public: 78public:
79 explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_) 79 explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_)
80 : ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) { 80 : ServiceFramework{system_, "IHOSBinderDriver", ServiceThreadType::CreateNew},
81 server(server_) {
81 static const FunctionInfo functions[] = { 82 static const FunctionInfo functions[] = {
82 {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, 83 {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
83 {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, 84 {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
index 0c1fbc7b1..282668b36 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
@@ -35,6 +35,15 @@ std::string_view OutputVertexIndex(EmitContext& ctx) {
35 return ctx.stage == Stage::TessellationControl ? "[gl_InvocationID]" : ""; 35 return ctx.stage == Stage::TessellationControl ? "[gl_InvocationID]" : "";
36} 36}
37 37
38std::string ChooseCbuf(EmitContext& ctx, const IR::Value& binding, std::string_view index) {
39 if (binding.IsImmediate()) {
40 return fmt::format("{}_cbuf{}[{}]", ctx.stage_name, binding.U32(), index);
41 } else {
42 const auto binding_var{ctx.var_alloc.Consume(binding)};
43 return fmt::format("GetCbufIndirect({},{})", binding_var, index);
44 }
45}
46
38void GetCbuf(EmitContext& ctx, std::string_view ret, const IR::Value& binding, 47void GetCbuf(EmitContext& ctx, std::string_view ret, const IR::Value& binding,
39 const IR::Value& offset, u32 num_bits, std::string_view cast = {}, 48 const IR::Value& offset, u32 num_bits, std::string_view cast = {},
40 std::string_view bit_offset = {}) { 49 std::string_view bit_offset = {}) {
@@ -55,8 +64,8 @@ void GetCbuf(EmitContext& ctx, std::string_view ret, const IR::Value& binding,
55 const auto swizzle{is_immediate ? fmt::format(".{}", OffsetSwizzle(offset.U32())) 64 const auto swizzle{is_immediate ? fmt::format(".{}", OffsetSwizzle(offset.U32()))
56 : fmt::format("[({}>>2)%4]", offset_var)}; 65 : fmt::format("[({}>>2)%4]", offset_var)};
57 66
58 const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())}; 67 const auto cbuf{ChooseCbuf(ctx, binding, index)};
59 const auto cbuf_cast{fmt::format("{}({}[{}]{{}})", cast, cbuf, index)}; 68 const auto cbuf_cast{fmt::format("{}({}{{}})", cast, cbuf)};
60 const auto extraction{num_bits == 32 ? cbuf_cast 69 const auto extraction{num_bits == 32 ? cbuf_cast
61 : fmt::format("bitfieldExtract({},int({}),{})", cbuf_cast, 70 : fmt::format("bitfieldExtract({},int({}),{})", cbuf_cast,
62 bit_offset, num_bits)}; 71 bit_offset, num_bits)};
@@ -140,9 +149,9 @@ void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
140 149
141void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, 150void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
142 const IR::Value& offset) { 151 const IR::Value& offset) {
143 const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())};
144 const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"}; 152 const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
145 if (offset.IsImmediate()) { 153 if (offset.IsImmediate()) {
154 const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())};
146 static constexpr u32 cbuf_size{0x10000}; 155 static constexpr u32 cbuf_size{0x10000};
147 const u32 u32_offset{offset.U32()}; 156 const u32 u32_offset{offset.U32()};
148 const s32 signed_offset{static_cast<s32>(offset.U32())}; 157 const s32 signed_offset{static_cast<s32>(offset.U32())};
@@ -162,17 +171,17 @@ void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding
162 return; 171 return;
163 } 172 }
164 const auto offset_var{ctx.var_alloc.Consume(offset)}; 173 const auto offset_var{ctx.var_alloc.Consume(offset)};
174 const auto cbuf{ChooseCbuf(ctx, binding, fmt::format("{}>>4", offset_var))};
165 if (!ctx.profile.has_gl_component_indexing_bug) { 175 if (!ctx.profile.has_gl_component_indexing_bug) {
166 ctx.AddU32x2("{}=uvec2({}({}[{}>>4][({}>>2)%4]),{}({}[({}+4)>>4][(({}+4)>>2)%4]));", inst, 176 ctx.AddU32x2("{}=uvec2({}({}[({}>>2)%4]),{}({}[(({}+4)>>2)%4]));", inst, cast, cbuf,
167 cast, cbuf, offset_var, offset_var, cast, cbuf, offset_var, offset_var); 177 offset_var, cast, cbuf, offset_var);
168 return; 178 return;
169 } 179 }
170 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x2)}; 180 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x2)};
171 const auto cbuf_offset{fmt::format("{}>>2", offset_var)}; 181 const auto cbuf_offset{fmt::format("{}>>2", offset_var)};
172 for (u32 swizzle = 0; swizzle < 4; ++swizzle) { 182 for (u32 swizzle = 0; swizzle < 4; ++swizzle) {
173 ctx.Add("if(({}&3)=={}){}=uvec2({}({}[{}>>4].{}),{}({}[({}+4)>>4].{}));", cbuf_offset, 183 ctx.Add("if(({}&3)=={}){}=uvec2({}({}.{}),{}({}.{}));", cbuf_offset, swizzle, ret, cast,
174 swizzle, ret, cast, cbuf, offset_var, "xyzw"[swizzle], cast, cbuf, offset_var, 184 cbuf, "xyzw"[swizzle], cast, cbuf, "xyzw"[(swizzle + 1) % 4]);
175 "xyzw"[(swizzle + 1) % 4]);
176 } 185 }
177} 186}
178 187
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
index e816a93ec..17266f40d 100644
--- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
@@ -359,6 +359,7 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
359 header += "layout(location=0) uniform vec4 scaling;"; 359 header += "layout(location=0) uniform vec4 scaling;";
360 } 360 }
361 DefineConstantBuffers(bindings); 361 DefineConstantBuffers(bindings);
362 DefineConstantBufferIndirect();
362 DefineStorageBuffers(bindings); 363 DefineStorageBuffers(bindings);
363 SetupImages(bindings); 364 SetupImages(bindings);
364 SetupTextures(bindings); 365 SetupTextures(bindings);
@@ -436,6 +437,24 @@ void EmitContext::DefineConstantBuffers(Bindings& bindings) {
436 } 437 }
437} 438}
438 439
440void EmitContext::DefineConstantBufferIndirect() {
441 if (!info.uses_cbuf_indirect) {
442 return;
443 }
444
445 header += profile.has_gl_cbuf_ftou_bug ? "uvec4 " : "vec4 ";
446 header += "GetCbufIndirect(uint binding, uint offset){"
447 "switch(binding){"
448 "default:";
449
450 for (const auto& desc : info.constant_buffer_descriptors) {
451 header +=
452 fmt::format("case {}:return {}_cbuf{}[offset];", desc.index, stage_name, desc.index);
453 }
454
455 header += "}}";
456}
457
439void EmitContext::DefineStorageBuffers(Bindings& bindings) { 458void EmitContext::DefineStorageBuffers(Bindings& bindings) {
440 if (info.storage_buffers_descriptors.empty()) { 459 if (info.storage_buffers_descriptors.empty()) {
441 return; 460 return;
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.h b/src/shader_recompiler/backend/glsl/glsl_emit_context.h
index d9b639d29..2b13db6e6 100644
--- a/src/shader_recompiler/backend/glsl/glsl_emit_context.h
+++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.h
@@ -162,6 +162,7 @@ public:
162private: 162private:
163 void SetupExtensions(); 163 void SetupExtensions();
164 void DefineConstantBuffers(Bindings& bindings); 164 void DefineConstantBuffers(Bindings& bindings);
165 void DefineConstantBufferIndirect();
165 void DefineStorageBuffers(Bindings& bindings); 166 void DefineStorageBuffers(Bindings& bindings);
166 void DefineGenericOutput(size_t index, u32 invocations); 167 void DefineGenericOutput(size_t index, u32 invocations);
167 void DefineHelperFunctions(); 168 void DefineHelperFunctions();
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index 28f6a6184..9c83cd2e4 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -1043,15 +1043,15 @@ void EmitContext::DefineConstantBufferIndirectFunctions(const Info& info) {
1043 const Id merge_label{OpLabel()}; 1043 const Id merge_label{OpLabel()};
1044 const Id uniform_type{uniform_types.*member_ptr}; 1044 const Id uniform_type{uniform_types.*member_ptr};
1045 1045
1046 std::array<Id, Info::MAX_CBUFS> buf_labels; 1046 std::array<Id, Info::MAX_INDIRECT_CBUFS> buf_labels;
1047 std::array<Sirit::Literal, Info::MAX_CBUFS> buf_literals; 1047 std::array<Sirit::Literal, Info::MAX_INDIRECT_CBUFS> buf_literals;
1048 for (u32 i = 0; i < Info::MAX_CBUFS; i++) { 1048 for (u32 i = 0; i < Info::MAX_INDIRECT_CBUFS; i++) {
1049 buf_labels[i] = OpLabel(); 1049 buf_labels[i] = OpLabel();
1050 buf_literals[i] = Sirit::Literal{i}; 1050 buf_literals[i] = Sirit::Literal{i};
1051 } 1051 }
1052 OpSelectionMerge(merge_label, spv::SelectionControlMask::MaskNone); 1052 OpSelectionMerge(merge_label, spv::SelectionControlMask::MaskNone);
1053 OpSwitch(binding, buf_labels[0], buf_literals, buf_labels); 1053 OpSwitch(binding, buf_labels[0], buf_literals, buf_labels);
1054 for (u32 i = 0; i < Info::MAX_CBUFS; i++) { 1054 for (u32 i = 0; i < Info::MAX_INDIRECT_CBUFS; i++) {
1055 AddLabel(buf_labels[i]); 1055 AddLabel(buf_labels[i]);
1056 const Id cbuf{cbufs[i].*member_ptr}; 1056 const Id cbuf{cbufs[i].*member_ptr};
1057 const Id access_chain{OpAccessChain(uniform_type, cbuf, u32_zero_value, offset)}; 1057 const Id access_chain{OpAccessChain(uniform_type, cbuf, u32_zero_value, offset)};
@@ -1064,22 +1064,23 @@ void EmitContext::DefineConstantBufferIndirectFunctions(const Info& info) {
1064 return func; 1064 return func;
1065 }}; 1065 }};
1066 IR::Type types{info.used_indirect_cbuf_types}; 1066 IR::Type types{info.used_indirect_cbuf_types};
1067 if (True(types & IR::Type::U8)) { 1067 bool supports_aliasing = profile.support_descriptor_aliasing;
1068 if (supports_aliasing && True(types & IR::Type::U8)) {
1068 load_const_func_u8 = make_accessor(U8, &UniformDefinitions::U8); 1069 load_const_func_u8 = make_accessor(U8, &UniformDefinitions::U8);
1069 } 1070 }
1070 if (True(types & IR::Type::U16)) { 1071 if (supports_aliasing && True(types & IR::Type::U16)) {
1071 load_const_func_u16 = make_accessor(U16, &UniformDefinitions::U16); 1072 load_const_func_u16 = make_accessor(U16, &UniformDefinitions::U16);
1072 } 1073 }
1073 if (True(types & IR::Type::F32)) { 1074 if (supports_aliasing && True(types & IR::Type::F32)) {
1074 load_const_func_f32 = make_accessor(F32[1], &UniformDefinitions::F32); 1075 load_const_func_f32 = make_accessor(F32[1], &UniformDefinitions::F32);
1075 } 1076 }
1076 if (True(types & IR::Type::U32)) { 1077 if (supports_aliasing && True(types & IR::Type::U32)) {
1077 load_const_func_u32 = make_accessor(U32[1], &UniformDefinitions::U32); 1078 load_const_func_u32 = make_accessor(U32[1], &UniformDefinitions::U32);
1078 } 1079 }
1079 if (True(types & IR::Type::U32x2)) { 1080 if (supports_aliasing && True(types & IR::Type::U32x2)) {
1080 load_const_func_u32x2 = make_accessor(U32[2], &UniformDefinitions::U32x2); 1081 load_const_func_u32x2 = make_accessor(U32[2], &UniformDefinitions::U32x2);
1081 } 1082 }
1082 if (True(types & IR::Type::U32x4)) { 1083 if (!supports_aliasing || True(types & IR::Type::U32x4)) {
1083 load_const_func_u32x4 = make_accessor(U32[4], &UniformDefinitions::U32x4); 1084 load_const_func_u32x4 = make_accessor(U32[4], &UniformDefinitions::U32x4);
1084 } 1085 }
1085} 1086}
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
index 0b2c60842..16278faab 100644
--- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
+++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
@@ -32,13 +32,8 @@ void AddConstantBufferDescriptor(Info& info, u32 index, u32 count) {
32void AddRegisterIndexedLdc(Info& info) { 32void AddRegisterIndexedLdc(Info& info) {
33 info.uses_cbuf_indirect = true; 33 info.uses_cbuf_indirect = true;
34 34
35 // The shader can use any possible constant buffer 35 for (u32 i = 0; i < Info::MAX_INDIRECT_CBUFS; i++) {
36 info.constant_buffer_mask = (1 << Info::MAX_CBUFS) - 1; 36 AddConstantBufferDescriptor(info, i, 1);
37
38 auto& cbufs{info.constant_buffer_descriptors};
39 cbufs.clear();
40 for (u32 i = 0; i < Info::MAX_CBUFS; i++) {
41 cbufs.push_back(ConstantBufferDescriptor{.index = i, .count = 1});
42 37
43 // The shader can use any possible access size 38 // The shader can use any possible access size
44 info.constant_buffer_used_sizes[i] = 0x10'000; 39 info.constant_buffer_used_sizes[i] = 0x10'000;
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h
index 9d36bd9eb..a3a09c71c 100644
--- a/src/shader_recompiler/shader_info.h
+++ b/src/shader_recompiler/shader_info.h
@@ -105,6 +105,7 @@ struct ImageDescriptor {
105using ImageDescriptors = boost::container::small_vector<ImageDescriptor, 4>; 105using ImageDescriptors = boost::container::small_vector<ImageDescriptor, 4>;
106 106
107struct Info { 107struct Info {
108 static constexpr size_t MAX_INDIRECT_CBUFS{14};
108 static constexpr size_t MAX_CBUFS{18}; 109 static constexpr size_t MAX_CBUFS{18};
109 static constexpr size_t MAX_SSBOS{32}; 110 static constexpr size_t MAX_SSBOS{32};
110 111
diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui
index 5d80a8c91..8ae569ee6 100644
--- a/src/yuzu/configuration/configure_cpu.ui
+++ b/src/yuzu/configuration/configure_cpu.ui
@@ -52,6 +52,11 @@
52 <string>Unsafe</string> 52 <string>Unsafe</string>
53 </property> 53 </property>
54 </item> 54 </item>
55 <item>
56 <property name="text">
57 <string>Paranoid (disables most optimizations)</string>
58 </property>
59 </item>
55 </widget> 60 </widget>
56 </item> 61 </item>
57 </layout> 62 </layout>