summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/assert.cpp3
-rw-r--r--src/common/logging/backend.cpp17
-rw-r--r--src/common/logging/backend.h3
-rw-r--r--src/common/ring_buffer.h2
-rw-r--r--src/core/hle/kernel/k_auto_object_container.cpp9
-rw-r--r--src/core/hle/kernel/k_auto_object_container.h31
-rw-r--r--src/core/hle/kernel/k_handle_table.h7
-rw-r--r--src/core/hle/kernel/k_process.h2
-rw-r--r--src/core/hle/kernel/k_server_session.cpp3
-rw-r--r--src/core/hle/kernel/k_transfer_memory.h1
-rw-r--r--src/core/hle/service/am/am.cpp12
-rw-r--r--src/core/hle/service/audio/audren_u.cpp6
-rw-r--r--src/core/hle/service/audio/hwopus.cpp16
-rw-r--r--src/core/hle/service/hid/hid_server.cpp9
-rw-r--r--src/core/hle/service/hid/hidbus.cpp3
-rw-r--r--src/core/hle/service/hid/irs.cpp6
-rw-r--r--src/core/hle/service/hle_ipc.cpp20
-rw-r--r--src/core/hle/service/hle_ipc.h20
-rw-r--r--src/core/hle/service/jit/jit.cpp14
-rw-r--r--src/core/hle/service/ro/ro.cpp12
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp60
-rw-r--r--src/video_core/macro/macro_hle.cpp7
-rw-r--r--src/video_core/rasterizer_interface.h8
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h6
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.cpp17
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h27
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp16
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp4
-rw-r--r--src/yuzu/main.h8
33 files changed, 228 insertions, 150 deletions
diff --git a/src/common/assert.cpp b/src/common/assert.cpp
index 6026b7dc2..e2c2cade3 100644
--- a/src/common/assert.cpp
+++ b/src/common/assert.cpp
@@ -3,16 +3,19 @@
3 3
4#include "common/assert.h" 4#include "common/assert.h"
5#include "common/common_funcs.h" 5#include "common/common_funcs.h"
6#include "common/logging/backend.h"
6 7
7#include "common/settings.h" 8#include "common/settings.h"
8 9
9void assert_fail_impl() { 10void assert_fail_impl() {
10 if (Settings::values.use_debug_asserts) { 11 if (Settings::values.use_debug_asserts) {
12 Common::Log::Stop();
11 Crash(); 13 Crash();
12 } 14 }
13} 15}
14 16
15[[noreturn]] void unreachable_impl() { 17[[noreturn]] void unreachable_impl() {
18 Common::Log::Stop();
16 Crash(); 19 Crash();
17 throw std::runtime_error("Unreachable code"); 20 throw std::runtime_error("Unreachable code");
18} 21}
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index d4f27197c..7a267f8c0 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -208,6 +208,10 @@ public:
208 instance->StartBackendThread(); 208 instance->StartBackendThread();
209 } 209 }
210 210
211 static void Stop() {
212 instance->StopBackendThread();
213 }
214
211 Impl(const Impl&) = delete; 215 Impl(const Impl&) = delete;
212 Impl& operator=(const Impl&) = delete; 216 Impl& operator=(const Impl&) = delete;
213 217
@@ -259,6 +263,15 @@ private:
259 }); 263 });
260 } 264 }
261 265
266 void StopBackendThread() {
267 backend_thread.request_stop();
268 if (backend_thread.joinable()) {
269 backend_thread.join();
270 }
271
272 ForEachBackend([](Backend& backend) { backend.Flush(); });
273 }
274
262 Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, 275 Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
263 const char* function, std::string&& message) const { 276 const char* function, std::string&& message) const {
264 using std::chrono::duration_cast; 277 using std::chrono::duration_cast;
@@ -313,6 +326,10 @@ void Start() {
313 Impl::Start(); 326 Impl::Start();
314} 327}
315 328
329void Stop() {
330 Impl::Stop();
331}
332
316void DisableLoggingInTests() { 333void DisableLoggingInTests() {
317 initialization_in_progress_suppress_logging = true; 334 initialization_in_progress_suppress_logging = true;
318} 335}
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index 12e5e2498..2a9926e9e 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -14,6 +14,9 @@ void Initialize();
14 14
15void Start(); 15void Start();
16 16
17/// Explicitly stops the logger thread and flushes the buffers
18void Stop();
19
17void DisableLoggingInTests(); 20void DisableLoggingInTests();
18 21
19/** 22/**
diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h
index 5c961b202..e7e9fdb38 100644
--- a/src/common/ring_buffer.h
+++ b/src/common/ring_buffer.h
@@ -103,7 +103,7 @@ private:
103 // Having them on the same cache-line would result in false-sharing between them. 103 // Having them on the same cache-line would result in false-sharing between them.
104 // TODO: Remove this ifdef whenever clang and GCC support 104 // TODO: Remove this ifdef whenever clang and GCC support
105 // std::hardware_destructive_interference_size. 105 // std::hardware_destructive_interference_size.
106#if defined(_MSC_VER) && _MSC_VER >= 1911 106#ifdef __cpp_lib_hardware_interference_size
107 alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0}; 107 alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0};
108 alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0}; 108 alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0};
109#else 109#else
diff --git a/src/core/hle/kernel/k_auto_object_container.cpp b/src/core/hle/kernel/k_auto_object_container.cpp
index 636b3f993..7bea1a1c2 100644
--- a/src/core/hle/kernel/k_auto_object_container.cpp
+++ b/src/core/hle/kernel/k_auto_object_container.cpp
@@ -8,19 +8,22 @@
8namespace Kernel { 8namespace Kernel {
9 9
10void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) { 10void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
11 KScopedLightLock lk(m_lock); 11 // KScopedInterruptDisable di;
12 KScopedSpinLock lk(m_lock);
12 13
13 m_object_list.insert_unique(*obj); 14 m_object_list.insert_unique(*obj);
14} 15}
15 16
16void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) { 17void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
17 KScopedLightLock lk(m_lock); 18 // KScopedInterruptDisable di;
19 KScopedSpinLock lk(m_lock);
18 20
19 m_object_list.erase(*obj); 21 m_object_list.erase(*obj);
20} 22}
21 23
22size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) { 24size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
23 KScopedLightLock lk(m_lock); 25 // KScopedInterruptDisable di;
26 KScopedSpinLock lk(m_lock);
24 27
25 return std::count_if(m_object_list.begin(), m_object_list.end(), 28 return std::count_if(m_object_list.begin(), m_object_list.end(),
26 [&](const auto& obj) { return obj.GetOwner() == owner; }); 29 [&](const auto& obj) { return obj.GetOwner() == owner; });
diff --git a/src/core/hle/kernel/k_auto_object_container.h b/src/core/hle/kernel/k_auto_object_container.h
index badd75d2a..770743d21 100644
--- a/src/core/hle/kernel/k_auto_object_container.h
+++ b/src/core/hle/kernel/k_auto_object_container.h
@@ -7,7 +7,7 @@
7 7
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "core/hle/kernel/k_auto_object.h" 9#include "core/hle/kernel/k_auto_object.h"
10#include "core/hle/kernel/k_light_lock.h" 10#include "core/hle/kernel/k_spin_lock.h"
11 11
12namespace Kernel { 12namespace Kernel {
13 13
@@ -21,32 +21,7 @@ public:
21 21
22 using ListType = boost::intrusive::rbtree<KAutoObjectWithList>; 22 using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
23 23
24 class ListAccessor : public KScopedLightLock { 24 KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(), m_object_list() {}
25 public:
26 explicit ListAccessor(KAutoObjectWithListContainer* container)
27 : KScopedLightLock(container->m_lock), m_list(container->m_object_list) {}
28 explicit ListAccessor(KAutoObjectWithListContainer& container)
29 : KScopedLightLock(container.m_lock), m_list(container.m_object_list) {}
30
31 typename ListType::iterator begin() const {
32 return m_list.begin();
33 }
34
35 typename ListType::iterator end() const {
36 return m_list.end();
37 }
38
39 typename ListType::iterator find(typename ListType::const_reference ref) const {
40 return m_list.find(ref);
41 }
42
43 private:
44 ListType& m_list;
45 };
46
47 friend class ListAccessor;
48
49 KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {}
50 25
51 void Initialize() {} 26 void Initialize() {}
52 void Finalize() {} 27 void Finalize() {}
@@ -56,7 +31,7 @@ public:
56 size_t GetOwnedCount(KProcess* owner); 31 size_t GetOwnedCount(KProcess* owner);
57 32
58private: 33private:
59 KLightLock m_lock; 34 KSpinLock m_lock;
60 ListType m_object_list; 35 ListType m_object_list;
61}; 36};
62 37
diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h
index 4e6dcd66b..1bf68e6b0 100644
--- a/src/core/hle/kernel/k_handle_table.h
+++ b/src/core/hle/kernel/k_handle_table.h
@@ -30,7 +30,7 @@ public:
30public: 30public:
31 explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {} 31 explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {}
32 32
33 Result Initialize(KProcess* owner, s32 size) { 33 Result Initialize(s32 size) {
34 // Check that the table size is valid. 34 // Check that the table size is valid.
35 R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory); 35 R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
36 36
@@ -44,7 +44,6 @@ public:
44 m_next_linear_id = MinLinearId; 44 m_next_linear_id = MinLinearId;
45 m_count = 0; 45 m_count = 0;
46 m_free_head_index = -1; 46 m_free_head_index = -1;
47 m_owner = owner;
48 47
49 // Free all entries. 48 // Free all entries.
50 for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) { 49 for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
@@ -91,8 +90,7 @@ public:
91 // Handle pseudo-handles. 90 // Handle pseudo-handles.
92 if constexpr (std::derived_from<KProcess, T>) { 91 if constexpr (std::derived_from<KProcess, T>) {
93 if (handle == Svc::PseudoHandle::CurrentProcess) { 92 if (handle == Svc::PseudoHandle::CurrentProcess) {
94 // TODO: this should be the current process 93 auto* const cur_process = GetCurrentProcessPointer(m_kernel);
95 auto* const cur_process = m_owner;
96 ASSERT(cur_process != nullptr); 94 ASSERT(cur_process != nullptr);
97 return cur_process; 95 return cur_process;
98 } 96 }
@@ -302,7 +300,6 @@ private:
302 300
303private: 301private:
304 KernelCore& m_kernel; 302 KernelCore& m_kernel;
305 KProcess* m_owner{};
306 std::array<EntryInfo, MaxTableSize> m_entry_infos{}; 303 std::array<EntryInfo, MaxTableSize> m_entry_infos{};
307 std::array<KAutoObject*, MaxTableSize> m_objects{}; 304 std::array<KAutoObject*, MaxTableSize> m_objects{};
308 mutable KSpinLock m_lock; 305 mutable KSpinLock m_lock;
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index b5c6867a1..53c0e3316 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -552,7 +552,7 @@ private:
552 552
553 Result InitializeHandleTable(s32 size) { 553 Result InitializeHandleTable(s32 size) {
554 // Try to initialize the handle table. 554 // Try to initialize the handle table.
555 R_TRY(m_handle_table.Initialize(this, size)); 555 R_TRY(m_handle_table.Initialize(size));
556 556
557 // We succeeded, so note that we did. 557 // We succeeded, so note that we did.
558 m_is_handle_table_initialized = true; 558 m_is_handle_table_initialized = true;
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index f6ca3dc48..adaabdd6d 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -1147,8 +1147,7 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
1147 *out_context = 1147 *out_context =
1148 std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread); 1148 std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread);
1149 (*out_context)->SetSessionRequestManager(manager); 1149 (*out_context)->SetSessionRequestManager(manager);
1150 (*out_context) 1150 (*out_context)->PopulateFromIncomingCommandBuffer(cmd_buf);
1151 ->PopulateFromIncomingCommandBuffer(*client_thread->GetOwnerProcess(), cmd_buf);
1152 // We succeeded. 1151 // We succeeded.
1153 R_SUCCEED(); 1152 R_SUCCEED();
1154 } else { 1153 } else {
diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h
index 8a0b08761..530b45218 100644
--- a/src/core/hle/kernel/k_transfer_memory.h
+++ b/src/core/hle/kernel/k_transfer_memory.h
@@ -5,6 +5,7 @@
5 5
6#include <optional> 6#include <optional>
7 7
8#include "core/hle/kernel/k_light_lock.h"
8#include "core/hle/kernel/k_page_group.h" 9#include "core/hle/kernel/k_page_group.h"
9#include "core/hle/kernel/slab_helpers.h" 10#include "core/hle/kernel/slab_helpers.h"
10#include "core/hle/kernel/svc_types.h" 11#include "core/hle/kernel/svc_types.h"
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index a266d7c21..97eb56ff0 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1513,8 +1513,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
1513 return; 1513 return;
1514 } 1514 }
1515 1515
1516 auto transfer_mem = 1516 auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
1517 system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
1518 1517
1519 if (transfer_mem.IsNull()) { 1518 if (transfer_mem.IsNull()) {
1520 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); 1519 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
@@ -1524,8 +1523,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
1524 } 1523 }
1525 1524
1526 std::vector<u8> memory(transfer_mem->GetSize()); 1525 std::vector<u8> memory(transfer_mem->GetSize());
1527 system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), 1526 ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
1528 memory.size());
1529 1527
1530 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1528 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1531 rb.Push(ResultSuccess); 1529 rb.Push(ResultSuccess);
@@ -1547,8 +1545,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
1547 return; 1545 return;
1548 } 1546 }
1549 1547
1550 auto transfer_mem = 1548 auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
1551 system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
1552 1549
1553 if (transfer_mem.IsNull()) { 1550 if (transfer_mem.IsNull()) {
1554 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); 1551 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
@@ -1558,8 +1555,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
1558 } 1555 }
1559 1556
1560 std::vector<u8> memory(transfer_mem->GetSize()); 1557 std::vector<u8> memory(transfer_mem->GetSize());
1561 system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), 1558 ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
1562 memory.size());
1563 1559
1564 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1560 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1565 rb.Push(ResultSuccess); 1561 rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 23e56c77a..bd4ca753b 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -454,10 +454,8 @@ void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
454 return; 454 return;
455 } 455 }
456 456
457 const auto& handle_table{system.ApplicationProcess()->GetHandleTable()}; 457 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
458 auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)}; 458 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
459 auto transfer_memory{
460 process->GetHandleTable().GetObject<Kernel::KTransferMemory>(transfer_memory_handle)};
461 459
462 const auto session_id{impl->GetSessionId()}; 460 const auto session_id{impl->GetSessionId()};
463 if (session_id == -1) { 461 if (session_id == -1) {
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 6a7bf9416..91f33aabd 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -278,9 +278,7 @@ void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) {
278 auto params = rp.PopRaw<OpusParameters>(); 278 auto params = rp.PopRaw<OpusParameters>();
279 auto transfer_memory_size{rp.Pop<u32>()}; 279 auto transfer_memory_size{rp.Pop<u32>()};
280 auto transfer_memory_handle{ctx.GetCopyHandle(0)}; 280 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
281 auto transfer_memory{ 281 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
282 system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
283 transfer_memory_handle)};
284 282
285 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", 283 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
286 params.sample_rate, params.channel_count, transfer_memory_size); 284 params.sample_rate, params.channel_count, transfer_memory_size);
@@ -323,9 +321,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) {
323 321
324 auto transfer_memory_size{rp.Pop<u32>()}; 322 auto transfer_memory_size{rp.Pop<u32>()};
325 auto transfer_memory_handle{ctx.GetCopyHandle(0)}; 323 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
326 auto transfer_memory{ 324 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
327 system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
328 transfer_memory_handle)};
329 325
330 LOG_DEBUG(Service_Audio, 326 LOG_DEBUG(Service_Audio,
331 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " 327 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
@@ -374,9 +370,7 @@ void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
374 auto params = rp.PopRaw<OpusParametersEx>(); 370 auto params = rp.PopRaw<OpusParametersEx>();
375 auto transfer_memory_size{rp.Pop<u32>()}; 371 auto transfer_memory_size{rp.Pop<u32>()};
376 auto transfer_memory_handle{ctx.GetCopyHandle(0)}; 372 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
377 auto transfer_memory{ 373 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
378 system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
379 transfer_memory_handle)};
380 374
381 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", 375 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
382 params.sample_rate, params.channel_count, transfer_memory_size); 376 params.sample_rate, params.channel_count, transfer_memory_size);
@@ -414,9 +408,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
414 408
415 auto transfer_memory_size{rp.Pop<u32>()}; 409 auto transfer_memory_size{rp.Pop<u32>()};
416 auto transfer_memory_handle{ctx.GetCopyHandle(0)}; 410 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
417 auto transfer_memory{ 411 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
418 system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
419 transfer_memory_handle)};
420 412
421 LOG_DEBUG(Service_Audio, 413 LOG_DEBUG(Service_Audio,
422 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " 414 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index 06a01c02c..3174672af 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -1850,8 +1850,7 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
1850 ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes"); 1850 ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes");
1851 ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes"); 1851 ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes");
1852 1852
1853 auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( 1853 auto t_mem_1 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_1_handle);
1854 t_mem_1_handle);
1855 1854
1856 if (t_mem_1.IsNull()) { 1855 if (t_mem_1.IsNull()) {
1857 LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle); 1856 LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle);
@@ -1860,8 +1859,7 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
1860 return; 1859 return;
1861 } 1860 }
1862 1861
1863 auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( 1862 auto t_mem_2 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_2_handle);
1864 t_mem_2_handle);
1865 1863
1866 if (t_mem_2.IsNull()) { 1864 if (t_mem_2.IsNull()) {
1867 LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle); 1865 LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle);
@@ -2142,8 +2140,7 @@ void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) {
2142 2140
2143 ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes"); 2141 ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes");
2144 2142
2145 auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( 2143 auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
2146 t_mem_handle);
2147 2144
2148 if (t_mem.IsNull()) { 2145 if (t_mem.IsNull()) {
2149 LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); 2146 LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp
index 80aac221b..d12f9beb0 100644
--- a/src/core/hle/service/hid/hidbus.cpp
+++ b/src/core/hle/service/hid/hidbus.cpp
@@ -448,8 +448,7 @@ void HidBus::EnableJoyPollingReceiveMode(HLERequestContext& ctx) {
448 448
449 ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes"); 449 ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes");
450 450
451 auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( 451 auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
452 t_mem_handle);
453 452
454 if (t_mem.IsNull()) { 453 if (t_mem.IsNull()) {
455 LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); 454 LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index 39b9a4474..008debfd1 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -197,8 +197,7 @@ void IRS::RunImageTransferProcessor(HLERequestContext& ctx) {
197 const auto parameters{rp.PopRaw<Parameters>()}; 197 const auto parameters{rp.PopRaw<Parameters>()};
198 const auto t_mem_handle{ctx.GetCopyHandle(0)}; 198 const auto t_mem_handle{ctx.GetCopyHandle(0)};
199 199
200 auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( 200 auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
201 t_mem_handle);
202 201
203 if (t_mem.IsNull()) { 202 if (t_mem.IsNull()) {
204 LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); 203 LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
@@ -444,8 +443,7 @@ void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) {
444 const auto parameters{rp.PopRaw<Parameters>()}; 443 const auto parameters{rp.PopRaw<Parameters>()};
445 const auto t_mem_handle{ctx.GetCopyHandle(0)}; 444 const auto t_mem_handle{ctx.GetCopyHandle(0)};
446 445
447 auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( 446 auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
448 t_mem_handle);
449 447
450 LOG_INFO(Service_IRS, 448 LOG_INFO(Service_IRS,
451 "called, npad_type={}, npad_id={}, transfer_memory_size={}, " 449 "called, npad_type={}, npad_id={}, transfer_memory_size={}, "
diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp
index 38955932c..39df77e43 100644
--- a/src/core/hle/service/hle_ipc.cpp
+++ b/src/core/hle/service/hle_ipc.cpp
@@ -146,10 +146,7 @@ HLERequestContext::HLERequestContext(Kernel::KernelCore& kernel_, Core::Memory::
146 146
147HLERequestContext::~HLERequestContext() = default; 147HLERequestContext::~HLERequestContext() = default;
148 148
149void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, 149void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
150 bool incoming) {
151 client_handle_table = &process.GetHandleTable();
152
153 IPC::RequestParser rp(src_cmdbuf); 150 IPC::RequestParser rp(src_cmdbuf);
154 command_header = rp.PopRaw<IPC::CommandHeader>(); 151 command_header = rp.PopRaw<IPC::CommandHeader>();
155 152
@@ -162,7 +159,7 @@ void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* sr
162 if (command_header->enable_handle_descriptor) { 159 if (command_header->enable_handle_descriptor) {
163 handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); 160 handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>();
164 if (handle_descriptor_header->send_current_pid) { 161 if (handle_descriptor_header->send_current_pid) {
165 pid = process.GetProcessId(); 162 pid = thread->GetOwnerProcess()->GetProcessId();
166 rp.Skip(2, false); 163 rp.Skip(2, false);
167 } 164 }
168 if (incoming) { 165 if (incoming) {
@@ -270,9 +267,10 @@ void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* sr
270 rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. 267 rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
271} 268}
272 269
273Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, 270Result HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf) {
274 u32_le* src_cmdbuf) { 271 client_handle_table = &thread->GetOwnerProcess()->GetHandleTable();
275 ParseCommandBuffer(process, src_cmdbuf, true); 272
273 ParseCommandBuffer(src_cmdbuf, true);
276 274
277 if (command_header->IsCloseCommand()) { 275 if (command_header->IsCloseCommand()) {
278 // Close does not populate the rest of the IPC header 276 // Close does not populate the rest of the IPC header
@@ -284,9 +282,9 @@ Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& pr
284 return ResultSuccess; 282 return ResultSuccess;
285} 283}
286 284
287Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread) { 285Result HLERequestContext::WriteToOutgoingCommandBuffer() {
288 auto current_offset = handles_offset; 286 auto current_offset = handles_offset;
289 auto& owner_process = *requesting_thread.GetOwnerProcess(); 287 auto& owner_process = *thread->GetOwnerProcess();
290 auto& handle_table = owner_process.GetHandleTable(); 288 auto& handle_table = owner_process.GetHandleTable();
291 289
292 for (auto& object : outgoing_copy_objects) { 290 for (auto& object : outgoing_copy_objects) {
@@ -319,7 +317,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesti
319 } 317 }
320 318
321 // Copy the translated command buffer back into the thread's command buffer area. 319 // Copy the translated command buffer back into the thread's command buffer area.
322 memory.WriteBlock(requesting_thread.GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32)); 320 memory.WriteBlock(thread->GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32));
323 321
324 return ResultSuccess; 322 return ResultSuccess;
325} 323}
diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h
index 18d464c63..40d86943e 100644
--- a/src/core/hle/service/hle_ipc.h
+++ b/src/core/hle/service/hle_ipc.h
@@ -17,6 +17,7 @@
17#include "common/concepts.h" 17#include "common/concepts.h"
18#include "common/swap.h" 18#include "common/swap.h"
19#include "core/hle/ipc.h" 19#include "core/hle/ipc.h"
20#include "core/hle/kernel/k_handle_table.h"
20#include "core/hle/kernel/svc_common.h" 21#include "core/hle/kernel/svc_common.h"
21 22
22union Result; 23union Result;
@@ -196,10 +197,10 @@ public:
196 } 197 }
197 198
198 /// Populates this context with data from the requesting process/thread. 199 /// Populates this context with data from the requesting process/thread.
199 Result PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf); 200 Result PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf);
200 201
201 /// Writes data from this context back to the requesting process/thread. 202 /// Writes data from this context back to the requesting process/thread.
202 Result WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread); 203 Result WriteToOutgoingCommandBuffer();
203 204
204 [[nodiscard]] u32_le GetHipcCommand() const { 205 [[nodiscard]] u32_le GetHipcCommand() const {
205 return command; 206 return command;
@@ -359,8 +360,17 @@ public:
359 return *thread; 360 return *thread;
360 } 361 }
361 362
362 Kernel::KHandleTable& GetClientHandleTable() { 363 [[nodiscard]] Core::Memory::Memory& GetMemory() const {
363 return *client_handle_table; 364 return memory;
365 }
366
367 template <typename T>
368 Kernel::KScopedAutoObject<T> GetObjectFromHandle(u32 handle) {
369 auto obj = client_handle_table->GetObjectForIpc(handle, thread);
370 if (obj.IsNotNull()) {
371 return obj->DynamicCast<T*>();
372 }
373 return nullptr;
364 } 374 }
365 375
366 [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const { 376 [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const {
@@ -378,7 +388,7 @@ public:
378private: 388private:
379 friend class IPC::ResponseBuilder; 389 friend class IPC::ResponseBuilder;
380 390
381 void ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, bool incoming); 391 void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);
382 392
383 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; 393 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
384 Kernel::KServerSession* server_session{}; 394 Kernel::KServerSession* server_session{};
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp
index 65851fc05..a94d05e19 100644
--- a/src/core/hle/service/jit/jit.cpp
+++ b/src/core/hle/service/jit/jit.cpp
@@ -26,7 +26,7 @@ public:
26 explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx, 26 explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx,
27 CodeRange user_ro) 27 CodeRange user_ro)
28 : ServiceFramework{system_, "IJitEnvironment"}, process{&process_}, 28 : ServiceFramework{system_, "IJitEnvironment"}, process{&process_},
29 context{system_.ApplicationMemory()} { 29 context{process->GetMemory()} {
30 // clang-format off 30 // clang-format off
31 static const FunctionInfo functions[] = { 31 static const FunctionInfo functions[] = {
32 {0, &IJitEnvironment::GenerateCode, "GenerateCode"}, 32 {0, &IJitEnvironment::GenerateCode, "GenerateCode"},
@@ -188,7 +188,7 @@ public:
188 return; 188 return;
189 } 189 }
190 190
191 auto tmem{process->GetHandleTable().GetObject<Kernel::KTransferMemory>(tmem_handle)}; 191 auto tmem{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(tmem_handle)};
192 if (tmem.IsNull()) { 192 if (tmem.IsNull()) {
193 LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle"); 193 LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle");
194 IPC::ResponseBuilder rb{ctx, 2}; 194 IPC::ResponseBuilder rb{ctx, 2};
@@ -356,11 +356,7 @@ public:
356 return; 356 return;
357 } 357 }
358 358
359 // Fetch using the handle table for the application process here, 359 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
360 // since we are not multiprocess yet.
361 const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
362
363 auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
364 if (process.IsNull()) { 360 if (process.IsNull()) {
365 LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle); 361 LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle);
366 IPC::ResponseBuilder rb{ctx, 2}; 362 IPC::ResponseBuilder rb{ctx, 2};
@@ -368,7 +364,7 @@ public:
368 return; 364 return;
369 } 365 }
370 366
371 auto rx_mem{handle_table.GetObject<Kernel::KCodeMemory>(rx_mem_handle)}; 367 auto rx_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(rx_mem_handle)};
372 if (rx_mem.IsNull()) { 368 if (rx_mem.IsNull()) {
373 LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle); 369 LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle);
374 IPC::ResponseBuilder rb{ctx, 2}; 370 IPC::ResponseBuilder rb{ctx, 2};
@@ -376,7 +372,7 @@ public:
376 return; 372 return;
377 } 373 }
378 374
379 auto ro_mem{handle_table.GetObject<Kernel::KCodeMemory>(ro_mem_handle)}; 375 auto ro_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(ro_mem_handle)};
380 if (ro_mem.IsNull()) { 376 if (ro_mem.IsNull()) {
381 LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle); 377 LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle);
382 IPC::ResponseBuilder rb{ctx, 2}; 378 IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp
index 17110d3f1..f0658bb5d 100644
--- a/src/core/hle/service/ro/ro.cpp
+++ b/src/core/hle/service/ro/ro.cpp
@@ -651,10 +651,9 @@ private:
651 void RegisterProcessHandle(HLERequestContext& ctx) { 651 void RegisterProcessHandle(HLERequestContext& ctx) {
652 LOG_DEBUG(Service_LDR, "(called)"); 652 LOG_DEBUG(Service_LDR, "(called)");
653 653
654 auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0)); 654 auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
655 auto client_pid = ctx.GetPID(); 655 auto client_pid = ctx.GetPID();
656 auto result = interface.RegisterProcessHandle(client_pid, 656 auto result = interface.RegisterProcessHandle(client_pid, process.GetPointerUnsafe());
657 process_h->DynamicCast<Kernel::KProcess*>());
658 657
659 IPC::ResponseBuilder rb{ctx, 2}; 658 IPC::ResponseBuilder rb{ctx, 2};
660 rb.Push(result); 659 rb.Push(result);
@@ -671,12 +670,11 @@ private:
671 670
672 IPC::RequestParser rp{ctx}; 671 IPC::RequestParser rp{ctx};
673 auto params = rp.PopRaw<InputParameters>(); 672 auto params = rp.PopRaw<InputParameters>();
674 auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0)); 673 auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
675 674
676 auto client_pid = ctx.GetPID(); 675 auto client_pid = ctx.GetPID();
677 auto result = 676 auto result = interface.RegisterProcessModuleInfo(
678 interface.RegisterProcessModuleInfo(client_pid, params.nrr_address, params.nrr_size, 677 client_pid, params.nrr_address, params.nrr_size, process.GetPointerUnsafe());
679 process_h->DynamicCast<Kernel::KProcess*>());
680 678
681 IPC::ResponseBuilder rb{ctx, 2}; 679 IPC::ResponseBuilder rb{ctx, 2};
682 rb.Push(result); 680 rb.Push(result);
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 00531b021..39124c5fd 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -203,7 +203,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
203 // If emulation was shutdown, we are closing service threads, do not write the response back to 203 // If emulation was shutdown, we are closing service threads, do not write the response back to
204 // memory that may be shutting down as well. 204 // memory that may be shutting down as well.
205 if (system.IsPoweredOn()) { 205 if (system.IsPoweredOn()) {
206 ctx.WriteToOutgoingCommandBuffer(ctx.GetThread()); 206 ctx.WriteToOutgoingCommandBuffer();
207 } 207 }
208 208
209 return result; 209 return result;
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index ed023fcfe..89ebab08e 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -96,9 +96,9 @@ Id ImageType(EmitContext& ctx, const ImageDescriptor& desc, Id sampled_type) {
96} 96}
97 97
98Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin, 98Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin,
99 spv::StorageClass storage_class) { 99 spv::StorageClass storage_class, std::optional<Id> initializer = std::nullopt) {
100 const Id pointer_type{ctx.TypePointer(storage_class, type)}; 100 const Id pointer_type{ctx.TypePointer(storage_class, type)};
101 const Id id{ctx.AddGlobalVariable(pointer_type, storage_class)}; 101 const Id id{ctx.AddGlobalVariable(pointer_type, storage_class, initializer)};
102 if (builtin) { 102 if (builtin) {
103 ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin); 103 ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin);
104 } 104 }
@@ -144,11 +144,12 @@ Id DefineInput(EmitContext& ctx, Id type, bool per_invocation,
144} 144}
145 145
146Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations, 146Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations,
147 std::optional<spv::BuiltIn> builtin = std::nullopt) { 147 std::optional<spv::BuiltIn> builtin = std::nullopt,
148 std::optional<Id> initializer = std::nullopt) {
148 if (invocations && ctx.stage == Stage::TessellationControl) { 149 if (invocations && ctx.stage == Stage::TessellationControl) {
149 type = ctx.TypeArray(type, ctx.Const(*invocations)); 150 type = ctx.TypeArray(type, ctx.Const(*invocations));
150 } 151 }
151 return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); 152 return DefineVariable(ctx, type, builtin, spv::StorageClass::Output, initializer);
152} 153}
153 154
154void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) { 155void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) {
@@ -811,10 +812,14 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
811 labels.push_back(OpLabel()); 812 labels.push_back(OpLabel());
812 } 813 }
813 if (info.stores.ClipDistances()) { 814 if (info.stores.ClipDistances()) {
814 literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2); 815 if (profile.max_user_clip_distances >= 4) {
815 labels.push_back(OpLabel()); 816 literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2);
816 literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2); 817 labels.push_back(OpLabel());
817 labels.push_back(OpLabel()); 818 }
819 if (profile.max_user_clip_distances >= 8) {
820 literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2);
821 labels.push_back(OpLabel());
822 }
818 } 823 }
819 OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); 824 OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone);
820 OpSwitch(compare_index, default_label, literals, labels); 825 OpSwitch(compare_index, default_label, literals, labels);
@@ -843,17 +848,21 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
843 ++label_index; 848 ++label_index;
844 } 849 }
845 if (info.stores.ClipDistances()) { 850 if (info.stores.ClipDistances()) {
846 AddLabel(labels[label_index]); 851 if (profile.max_user_clip_distances >= 4) {
847 const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)}; 852 AddLabel(labels[label_index]);
848 OpStore(pointer, store_value); 853 const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)};
849 OpReturn(); 854 OpStore(pointer, store_value);
850 ++label_index; 855 OpReturn();
851 AddLabel(labels[label_index]); 856 ++label_index;
852 const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))}; 857 }
853 const Id pointer2{OpAccessChain(output_f32, clip_distances, fixed_index)}; 858 if (profile.max_user_clip_distances >= 8) {
854 OpStore(pointer2, store_value); 859 AddLabel(labels[label_index]);
855 OpReturn(); 860 const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))};
856 ++label_index; 861 const Id pointer{OpAccessChain(output_f32, clip_distances, fixed_index)};
862 OpStore(pointer, store_value);
863 OpReturn();
864 ++label_index;
865 }
857 } 866 }
858 AddLabel(end_block); 867 AddLabel(end_block);
859 OpUnreachable(); 868 OpUnreachable();
@@ -1532,9 +1541,16 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
1532 if (stage == Stage::Fragment) { 1541 if (stage == Stage::Fragment) {
1533 throw NotImplementedException("Storing ClipDistance in fragment stage"); 1542 throw NotImplementedException("Storing ClipDistance in fragment stage");
1534 } 1543 }
1535 const Id type{TypeArray( 1544 if (profile.max_user_clip_distances > 0) {
1536 F32[1], Const(std::min(info.used_clip_distances, profile.max_user_clip_distances)))}; 1545 const u32 used{std::min(profile.max_user_clip_distances, 8u)};
1537 clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance); 1546 const std::array<Id, 8> zero{f32_zero_value, f32_zero_value, f32_zero_value,
1547 f32_zero_value, f32_zero_value, f32_zero_value,
1548 f32_zero_value, f32_zero_value};
1549 const Id type{TypeArray(F32[1], Const(used))};
1550 const Id initializer{ConstantComposite(type, std::span(zero).subspan(0, used))};
1551 clip_distances =
1552 DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance, initializer);
1553 }
1538 } 1554 }
1539 if (info.stores[IR::Attribute::Layer] && 1555 if (info.stores[IR::Attribute::Layer] &&
1540 (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { 1556 (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) {
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp
index 046c8085e..46e853e04 100644
--- a/src/video_core/macro/macro_hle.cpp
+++ b/src/video_core/macro/macro_hle.cpp
@@ -327,12 +327,13 @@ public:
327 explicit HLE_DrawIndirectByteCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} 327 explicit HLE_DrawIndirectByteCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
328 328
329 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override { 329 void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
330 const bool force = maxwell3d.Rasterizer().HasDrawTransformFeedback();
331
330 auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0xFFFFU); 332 auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0xFFFFU);
331 if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) { 333 if (!force && (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology))) {
332 Fallback(parameters); 334 Fallback(parameters);
333 return; 335 return;
334 } 336 }
335
336 auto& params = maxwell3d.draw_manager->GetIndirectParams(); 337 auto& params = maxwell3d.draw_manager->GetIndirectParams();
337 params.is_byte_count = true; 338 params.is_byte_count = true;
338 params.is_indexed = false; 339 params.is_indexed = false;
@@ -503,6 +504,8 @@ public:
503 maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true); 504 maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true);
504 maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(inline_data)), 505 maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(inline_data)),
505 regs.transform_feedback.controls[0].stride, true); 506 regs.transform_feedback.controls[0].stride, true);
507
508 maxwell3d.Rasterizer().RegisterTransformFeedback(regs.upload.dest.Address());
506 } 509 }
507}; 510};
508 511
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index af1469147..49224ca85 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -173,5 +173,13 @@ public:
173 virtual void BindChannel(Tegra::Control::ChannelState& channel) {} 173 virtual void BindChannel(Tegra::Control::ChannelState& channel) {}
174 174
175 virtual void ReleaseChannel(s32 channel_id) {} 175 virtual void ReleaseChannel(s32 channel_id) {}
176
177 /// Register the address as a Transform Feedback Object
178 virtual void RegisterTransformFeedback(GPUVAddr tfb_object_addr) {}
179
180 /// Returns true when the rasterizer has Draw Transform Feedback capabilities
181 virtual bool HasDrawTransformFeedback() {
182 return false;
183 }
176}; 184};
177} // namespace VideoCore 185} // namespace VideoCore
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index b787b6994..517ac14dd 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -376,4 +376,15 @@ void BufferCacheRuntime::BindImageBuffer(Buffer& buffer, u32 offset, u32 size, P
376 *image_handles++ = buffer.View(offset, size, format); 376 *image_handles++ = buffer.View(offset, size, format);
377} 377}
378 378
379void BufferCacheRuntime::BindTransformFeedbackObject(GPUVAddr tfb_object_addr) {
380 OGLTransformFeedback& tfb_object = tfb_objects[tfb_object_addr];
381 tfb_object.Create();
382 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb_object.handle);
383}
384
385GLuint BufferCacheRuntime::GetTransformFeedbackObject(GPUVAddr tfb_object_addr) {
386 ASSERT(tfb_objects.contains(tfb_object_addr));
387 return tfb_objects[tfb_object_addr].handle;
388}
389
379} // namespace OpenGL 390} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index 1e8708f59..2c18de166 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -5,6 +5,7 @@
5 5
6#include <array> 6#include <array>
7#include <span> 7#include <span>
8#include <unordered_map>
8 9
9#include "common/common_types.h" 10#include "common/common_types.h"
10#include "video_core/buffer_cache/buffer_cache_base.h" 11#include "video_core/buffer_cache/buffer_cache_base.h"
@@ -121,6 +122,9 @@ public:
121 void BindImageBuffer(Buffer& buffer, u32 offset, u32 size, 122 void BindImageBuffer(Buffer& buffer, u32 offset, u32 size,
122 VideoCore::Surface::PixelFormat format); 123 VideoCore::Surface::PixelFormat format);
123 124
125 void BindTransformFeedbackObject(GPUVAddr tfb_object_addr);
126 GLuint GetTransformFeedbackObject(GPUVAddr tfb_object_addr);
127
124 u64 GetDeviceMemoryUsage() const; 128 u64 GetDeviceMemoryUsage() const;
125 129
126 void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) { 130 void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) {
@@ -233,6 +237,7 @@ private:
233 u32 index_buffer_offset = 0; 237 u32 index_buffer_offset = 0;
234 238
235 u64 device_access_memory; 239 u64 device_access_memory;
240 std::unordered_map<GPUVAddr, OGLTransformFeedback> tfb_objects;
236}; 241};
237 242
238struct BufferCacheParams { 243struct BufferCacheParams {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 339950d2e..7a5fad735 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -309,6 +309,13 @@ void RasterizerOpenGL::DrawIndirect() {
309 const auto& params = maxwell3d->draw_manager->GetIndirectParams(); 309 const auto& params = maxwell3d->draw_manager->GetIndirectParams();
310 buffer_cache.SetDrawIndirect(&params); 310 buffer_cache.SetDrawIndirect(&params);
311 PrepareDraw(params.is_indexed, [this, &params](GLenum primitive_mode) { 311 PrepareDraw(params.is_indexed, [this, &params](GLenum primitive_mode) {
312 if (params.is_byte_count) {
313 const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U;
314 const GLuint tfb_object =
315 buffer_cache_runtime.GetTransformFeedbackObject(tfb_object_base_addr);
316 glDrawTransformFeedback(primitive_mode, tfb_object);
317 return;
318 }
312 const auto [buffer, offset] = buffer_cache.GetDrawIndirectBuffer(); 319 const auto [buffer, offset] = buffer_cache.GetDrawIndirectBuffer();
313 const GLvoid* const gl_offset = 320 const GLvoid* const gl_offset =
314 reinterpret_cast<const GLvoid*>(static_cast<uintptr_t>(offset)); 321 reinterpret_cast<const GLvoid*>(static_cast<uintptr_t>(offset));
@@ -1371,6 +1378,10 @@ void RasterizerOpenGL::ReleaseChannel(s32 channel_id) {
1371 query_cache.EraseChannel(channel_id); 1378 query_cache.EraseChannel(channel_id);
1372} 1379}
1373 1380
1381void RasterizerOpenGL::RegisterTransformFeedback(GPUVAddr tfb_object_addr) {
1382 buffer_cache_runtime.BindTransformFeedbackObject(tfb_object_addr);
1383}
1384
1374AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_) 1385AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_)
1375 : buffer_cache{buffer_cache_}, texture_cache{texture_cache_} {} 1386 : buffer_cache{buffer_cache_}, texture_cache{texture_cache_} {}
1376 1387
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index b79d7a70c..ce3460938 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -139,6 +139,12 @@ public:
139 139
140 void ReleaseChannel(s32 channel_id) override; 140 void ReleaseChannel(s32 channel_id) override;
141 141
142 void RegisterTransformFeedback(GPUVAddr tfb_object_addr) override;
143
144 bool HasDrawTransformFeedback() override {
145 return true;
146 }
147
142private: 148private:
143 static constexpr size_t MAX_TEXTURES = 192; 149 static constexpr size_t MAX_TEXTURES = 192;
144 static constexpr size_t MAX_IMAGES = 48; 150 static constexpr size_t MAX_IMAGES = 48;
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp
index eae8fd110..1d2c9b70a 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp
@@ -207,4 +207,21 @@ void OGLQuery::Release() {
207 handle = 0; 207 handle = 0;
208} 208}
209 209
210void OGLTransformFeedback::Create() {
211 if (handle != 0)
212 return;
213
214 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
215 glCreateTransformFeedbacks(1, &handle);
216}
217
218void OGLTransformFeedback::Release() {
219 if (handle == 0)
220 return;
221
222 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
223 glDeleteTransformFeedbacks(1, &handle);
224 handle = 0;
225}
226
210} // namespace OpenGL 227} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index 77362acd2..6ca8227bd 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -323,4 +323,31 @@ public:
323 GLuint handle = 0; 323 GLuint handle = 0;
324}; 324};
325 325
326class OGLTransformFeedback final {
327public:
328 YUZU_NON_COPYABLE(OGLTransformFeedback);
329
330 OGLTransformFeedback() = default;
331
332 OGLTransformFeedback(OGLTransformFeedback&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
333
334 ~OGLTransformFeedback() {
335 Release();
336 }
337
338 OGLTransformFeedback& operator=(OGLTransformFeedback&& o) noexcept {
339 Release();
340 handle = std::exchange(o.handle, 0);
341 return *this;
342 }
343
344 /// Creates a new internal OpenGL resource and stores the handle
345 void Create();
346
347 /// Deletes the internal OpenGL resource
348 void Release();
349
350 GLuint handle = 0;
351};
352
326} // namespace OpenGL 353} // namespace OpenGL
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index a6fbca69e..727bbd98d 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -755,10 +755,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags
755 // The wanted format is not supported by hardware, search for alternatives 755 // The wanted format is not supported by hardware, search for alternatives
756 const VkFormat* alternatives = GetFormatAlternatives(wanted_format); 756 const VkFormat* alternatives = GetFormatAlternatives(wanted_format);
757 if (alternatives == nullptr) { 757 if (alternatives == nullptr) {
758 ASSERT_MSG(false, 758 LOG_ERROR(Render_Vulkan,
759 "Format={} with usage={} and type={} has no defined alternatives and host " 759 "Format={} with usage={} and type={} has no defined alternatives and host "
760 "hardware does not support it", 760 "hardware does not support it",
761 wanted_format, wanted_usage, format_type); 761 wanted_format, wanted_usage, format_type);
762 return wanted_format; 762 return wanted_format;
763 } 763 }
764 764
@@ -774,10 +774,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags
774 } 774 }
775 775
776 // No alternatives found, panic 776 // No alternatives found, panic
777 ASSERT_MSG(false, 777 LOG_ERROR(Render_Vulkan,
778 "Format={} with usage={} and type={} is not supported by the host hardware and " 778 "Format={} with usage={} and type={} is not supported by the host hardware and "
779 "doesn't support any of the alternatives", 779 "doesn't support any of the alternatives",
780 wanted_format, wanted_usage, format_type); 780 wanted_format, wanted_usage, format_type);
781 return wanted_format; 781 return wanted_format;
782} 782}
783 783
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 2f78b8af0..074aed964 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -246,7 +246,9 @@ void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjec
246 .objectHandle = reinterpret_cast<u64>(handle), 246 .objectHandle = reinterpret_cast<u64>(handle),
247 .pObjectName = name, 247 .pObjectName = name,
248 }; 248 };
249 Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info)); 249 if (dld->vkSetDebugUtilsObjectNameEXT) {
250 Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info));
251 }
250} 252}
251 253
252} // Anonymous namespace 254} // Anonymous namespace
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 530e445f9..366e806d5 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -168,14 +168,6 @@ class GMainWindow : public QMainWindow {
168 /// Max number of recently loaded items to keep track of 168 /// Max number of recently loaded items to keep track of
169 static const int max_recent_files_item = 10; 169 static const int max_recent_files_item = 10;
170 170
171 // TODO: Make use of this!
172 enum {
173 UI_IDLE,
174 UI_EMU_BOOTING,
175 UI_EMU_RUNNING,
176 UI_EMU_STOPPING,
177 };
178
179 enum { 171 enum {
180 CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, 172 CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES,
181 CREATE_SHORTCUT_MSGBOX_SUCCESS, 173 CREATE_SHORTCUT_MSGBOX_SUCCESS,