summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp50
-rw-r--r--src/core/hle/kernel/svc.cpp8
-rw-r--r--src/core/hle/kernel/transfer_memory.cpp66
-rw-r--r--src/core/hle/kernel/transfer_memory.h19
-rw-r--r--src/core/hle/kernel/vm_manager.cpp3
-rw-r--r--src/core/hle/kernel/vm_manager.h60
-rw-r--r--src/core/hle/kernel/wait_object.cpp13
-rw-r--r--src/core/hle/service/am/am.cpp92
-rw-r--r--src/core/hle/service/am/am.h30
-rw-r--r--src/core/hle/service/am/applets/applets.cpp26
-rw-r--r--src/core/hle/service/am/applets/applets.h24
-rw-r--r--src/core/hle/service/am/applets/error.cpp2
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp14
-rw-r--r--src/core/hle/service/am/applets/profile_select.cpp4
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp13
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp16
-rw-r--r--src/core/hle/service/prepo/prepo.cpp30
-rw-r--r--src/video_core/engines/maxwell_3d.h6
-rw-r--r--src/video_core/engines/shader_bytecode.h22
-rw-r--r--src/video_core/gpu.cpp2
-rw-r--r--src/video_core/gpu_thread.h2
-rw-r--r--src/video_core/memory_manager.cpp14
-rw-r--r--src/video_core/memory_manager.h7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp127
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h7
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h20
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp9
-rw-r--r--src/video_core/shader/decode/bfi.cpp7
-rw-r--r--src/video_core/shader/decode/shift.cpp113
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/configuration/configure_ui.cpp3
-rw-r--r--src/yuzu/configuration/configure_ui.ui7
-rw-r--r--src/yuzu/game_list_worker.cpp3
-rw-r--r--src/yuzu/uisettings.h1
35 files changed, 495 insertions, 329 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 2db28dcf0..ab05788d7 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -284,13 +284,18 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
284 284
285std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const { 285std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const {
286 std::vector<u8> buffer; 286 std::vector<u8> buffer;
287 const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; 287 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
288 BufferDescriptorA()[buffer_index].Size()};
288 auto& memory = Core::System::GetInstance().Memory(); 289 auto& memory = Core::System::GetInstance().Memory();
289 290
290 if (is_buffer_a) { 291 if (is_buffer_a) {
292 ASSERT_MSG(BufferDescriptorA().size() > buffer_index,
293 "BufferDescriptorA invalid buffer_index {}", buffer_index);
291 buffer.resize(BufferDescriptorA()[buffer_index].Size()); 294 buffer.resize(BufferDescriptorA()[buffer_index].Size());
292 memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); 295 memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size());
293 } else { 296 } else {
297 ASSERT_MSG(BufferDescriptorX().size() > buffer_index,
298 "BufferDescriptorX invalid buffer_index {}", buffer_index);
294 buffer.resize(BufferDescriptorX()[buffer_index].Size()); 299 buffer.resize(BufferDescriptorX()[buffer_index].Size());
295 memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); 300 memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size());
296 } 301 }
@@ -305,7 +310,8 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
305 return 0; 310 return 0;
306 } 311 }
307 312
308 const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; 313 const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
314 BufferDescriptorB()[buffer_index].Size()};
309 const std::size_t buffer_size{GetWriteBufferSize(buffer_index)}; 315 const std::size_t buffer_size{GetWriteBufferSize(buffer_index)};
310 if (size > buffer_size) { 316 if (size > buffer_size) {
311 LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, 317 LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size,
@@ -315,8 +321,16 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
315 321
316 auto& memory = Core::System::GetInstance().Memory(); 322 auto& memory = Core::System::GetInstance().Memory();
317 if (is_buffer_b) { 323 if (is_buffer_b) {
324 ASSERT_MSG(BufferDescriptorB().size() > buffer_index,
325 "BufferDescriptorB invalid buffer_index {}", buffer_index);
326 ASSERT_MSG(BufferDescriptorB()[buffer_index].Size() >= size,
327 "BufferDescriptorB buffer_index {} is not large enough", buffer_index);
318 memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); 328 memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
319 } else { 329 } else {
330 ASSERT_MSG(BufferDescriptorC().size() > buffer_index,
331 "BufferDescriptorC invalid buffer_index {}", buffer_index);
332 ASSERT_MSG(BufferDescriptorC()[buffer_index].Size() >= size,
333 "BufferDescriptorC buffer_index {} is not large enough", buffer_index);
320 memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); 334 memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
321 } 335 }
322 336
@@ -324,15 +338,35 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
324} 338}
325 339
326std::size_t HLERequestContext::GetReadBufferSize(int buffer_index) const { 340std::size_t HLERequestContext::GetReadBufferSize(int buffer_index) const {
327 const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; 341 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
328 return is_buffer_a ? BufferDescriptorA()[buffer_index].Size() 342 BufferDescriptorA()[buffer_index].Size()};
329 : BufferDescriptorX()[buffer_index].Size(); 343 if (is_buffer_a) {
344 ASSERT_MSG(BufferDescriptorA().size() > buffer_index,
345 "BufferDescriptorA invalid buffer_index {}", buffer_index);
346 ASSERT_MSG(BufferDescriptorA()[buffer_index].Size() > 0,
347 "BufferDescriptorA buffer_index {} is empty", buffer_index);
348 return BufferDescriptorA()[buffer_index].Size();
349 } else {
350 ASSERT_MSG(BufferDescriptorX().size() > buffer_index,
351 "BufferDescriptorX invalid buffer_index {}", buffer_index);
352 ASSERT_MSG(BufferDescriptorX()[buffer_index].Size() > 0,
353 "BufferDescriptorX buffer_index {} is empty", buffer_index);
354 return BufferDescriptorX()[buffer_index].Size();
355 }
330} 356}
331 357
332std::size_t HLERequestContext::GetWriteBufferSize(int buffer_index) const { 358std::size_t HLERequestContext::GetWriteBufferSize(int buffer_index) const {
333 const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; 359 const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
334 return is_buffer_b ? BufferDescriptorB()[buffer_index].Size() 360 BufferDescriptorB()[buffer_index].Size()};
335 : BufferDescriptorC()[buffer_index].Size(); 361 if (is_buffer_b) {
362 ASSERT_MSG(BufferDescriptorB().size() > buffer_index,
363 "BufferDescriptorB invalid buffer_index {}", buffer_index);
364 return BufferDescriptorB()[buffer_index].Size();
365 } else {
366 ASSERT_MSG(BufferDescriptorC().size() > buffer_index,
367 "BufferDescriptorC invalid buffer_index {}", buffer_index);
368 return BufferDescriptorC()[buffer_index].Size();
369 }
336} 370}
337 371
338std::string HLERequestContext::Description() const { 372std::string HLERequestContext::Description() const {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 1d99bf7a2..9cae5c73d 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1863,10 +1863,14 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd
1863 } 1863 }
1864 1864
1865 auto& kernel = system.Kernel(); 1865 auto& kernel = system.Kernel();
1866 auto transfer_mem_handle = TransferMemory::Create(kernel, addr, size, perms); 1866 auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms);
1867
1868 if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) {
1869 return reserve_result;
1870 }
1867 1871
1868 auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); 1872 auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
1869 const auto result = handle_table.Create(std::move(transfer_mem_handle)); 1873 const auto result{handle_table.Create(std::move(transfer_mem_handle))};
1870 if (result.Failed()) { 1874 if (result.Failed()) {
1871 return result.Code(); 1875 return result.Code();
1872 } 1876 }
diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp
index f0e73f57b..f2d3f8b49 100644
--- a/src/core/hle/kernel/transfer_memory.cpp
+++ b/src/core/hle/kernel/transfer_memory.cpp
@@ -8,15 +8,23 @@
8#include "core/hle/kernel/shared_memory.h" 8#include "core/hle/kernel/shared_memory.h"
9#include "core/hle/kernel/transfer_memory.h" 9#include "core/hle/kernel/transfer_memory.h"
10#include "core/hle/result.h" 10#include "core/hle/result.h"
11#include "core/memory.h"
11 12
12namespace Kernel { 13namespace Kernel {
13 14
14TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {} 15TransferMemory::TransferMemory(KernelCore& kernel, Memory::Memory& memory)
15TransferMemory::~TransferMemory() = default; 16 : Object{kernel}, memory{memory} {}
16 17
17std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, 18TransferMemory::~TransferMemory() {
18 u64 size, MemoryPermission permissions) { 19 // Release memory region when transfer memory is destroyed
19 std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)}; 20 Reset();
21}
22
23std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, Memory::Memory& memory,
24 VAddr base_address, u64 size,
25 MemoryPermission permissions) {
26 std::shared_ptr<TransferMemory> transfer_memory{
27 std::make_shared<TransferMemory>(kernel, memory)};
20 28
21 transfer_memory->base_address = base_address; 29 transfer_memory->base_address = base_address;
22 transfer_memory->memory_size = size; 30 transfer_memory->memory_size = size;
@@ -27,7 +35,7 @@ std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr
27} 35}
28 36
29const u8* TransferMemory::GetPointer() const { 37const u8* TransferMemory::GetPointer() const {
30 return backing_block.get()->data(); 38 return memory.GetPointer(base_address);
31} 39}
32 40
33u64 TransferMemory::GetSize() const { 41u64 TransferMemory::GetSize() const {
@@ -62,6 +70,52 @@ ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission p
62 return RESULT_SUCCESS; 70 return RESULT_SUCCESS;
63} 71}
64 72
73ResultCode TransferMemory::Reserve() {
74 auto& vm_manager{owner_process->VMManager()};
75 const auto check_range_result{vm_manager.CheckRangeState(
76 base_address, memory_size, MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated,
77 MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::All,
78 VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None,
79 MemoryAttribute::IpcAndDeviceMapped)};
80
81 if (check_range_result.Failed()) {
82 return check_range_result.Code();
83 }
84
85 auto [state_, permissions_, attribute] = *check_range_result;
86
87 if (const auto result{vm_manager.ReprotectRange(
88 base_address, memory_size, SharedMemory::ConvertPermissions(owner_permissions))};
89 result.IsError()) {
90 return result;
91 }
92
93 return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask,
94 attribute | MemoryAttribute::Locked);
95}
96
97ResultCode TransferMemory::Reset() {
98 auto& vm_manager{owner_process->VMManager()};
99 if (const auto result{vm_manager.CheckRangeState(
100 base_address, memory_size,
101 MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated,
102 MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::None,
103 VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked,
104 MemoryAttribute::IpcAndDeviceMapped)};
105 result.Failed()) {
106 return result.Code();
107 }
108
109 if (const auto result{
110 vm_manager.ReprotectRange(base_address, memory_size, VMAPermission::ReadWrite)};
111 result.IsError()) {
112 return result;
113 }
114
115 return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask,
116 MemoryAttribute::None);
117}
118
65ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) { 119ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) {
66 if (memory_size != size) { 120 if (memory_size != size) {
67 return ERR_INVALID_SIZE; 121 return ERR_INVALID_SIZE;
diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h
index 0a6e15d18..6e388536a 100644
--- a/src/core/hle/kernel/transfer_memory.h
+++ b/src/core/hle/kernel/transfer_memory.h
@@ -11,6 +11,10 @@
11 11
12union ResultCode; 12union ResultCode;
13 13
14namespace Memory {
15class Memory;
16}
17
14namespace Kernel { 18namespace Kernel {
15 19
16class KernelCore; 20class KernelCore;
@@ -26,12 +30,13 @@ enum class MemoryPermission : u32;
26/// 30///
27class TransferMemory final : public Object { 31class TransferMemory final : public Object {
28public: 32public:
29 explicit TransferMemory(KernelCore& kernel); 33 explicit TransferMemory(KernelCore& kernel, Memory::Memory& memory);
30 ~TransferMemory() override; 34 ~TransferMemory() override;
31 35
32 static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; 36 static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
33 37
34 static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size, 38 static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Memory::Memory& memory,
39 VAddr base_address, u64 size,
35 MemoryPermission permissions); 40 MemoryPermission permissions);
36 41
37 TransferMemory(const TransferMemory&) = delete; 42 TransferMemory(const TransferMemory&) = delete;
@@ -80,6 +85,14 @@ public:
80 /// 85 ///
81 ResultCode UnmapMemory(VAddr address, u64 size); 86 ResultCode UnmapMemory(VAddr address, u64 size);
82 87
88 /// Reserves the region to be used for the transfer memory, called after the transfer memory is
89 /// created.
90 ResultCode Reserve();
91
92 /// Resets the region previously used for the transfer memory, called after the transfer memory
93 /// is closed.
94 ResultCode Reset();
95
83private: 96private:
84 /// Memory block backing this instance. 97 /// Memory block backing this instance.
85 std::shared_ptr<PhysicalMemory> backing_block; 98 std::shared_ptr<PhysicalMemory> backing_block;
@@ -98,6 +111,8 @@ private:
98 111
99 /// Whether or not this transfer memory instance has mapped memory. 112 /// Whether or not this transfer memory instance has mapped memory.
100 bool is_mapped = false; 113 bool is_mapped = false;
114
115 Memory::Memory& memory;
101}; 116};
102 117
103} // namespace Kernel 118} // namespace Kernel
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 0b3500fce..024c22901 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -544,7 +544,8 @@ MemoryInfo VMManager::QueryMemory(VAddr address) const {
544 544
545ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask, 545ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask,
546 MemoryAttribute attribute) { 546 MemoryAttribute attribute) {
547 constexpr auto ignore_mask = MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped; 547 constexpr auto ignore_mask =
548 MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped | MemoryAttribute::Locked;
548 constexpr auto attribute_mask = ~ignore_mask; 549 constexpr auto attribute_mask = ~ignore_mask;
549 550
550 const auto result = CheckRangeState( 551 const auto result = CheckRangeState(
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 850a7ebc3..90b4b006a 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -98,6 +98,8 @@ enum class MemoryAttribute : u32 {
98 DeviceMapped = 4, 98 DeviceMapped = 4,
99 /// Uncached memory 99 /// Uncached memory
100 Uncached = 8, 100 Uncached = 8,
101
102 IpcAndDeviceMapped = LockedForIPC | DeviceMapped,
101}; 103};
102 104
103constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) { 105constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) {
@@ -654,6 +656,35 @@ public:
654 /// is scheduled. 656 /// is scheduled.
655 Common::PageTable page_table{Memory::PAGE_BITS}; 657 Common::PageTable page_table{Memory::PAGE_BITS};
656 658
659 using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>;
660
661 /// Checks if an address range adheres to the specified states provided.
662 ///
663 /// @param address The starting address of the address range.
664 /// @param size The size of the address range.
665 /// @param state_mask The memory state mask.
666 /// @param state The state to compare the individual VMA states against,
667 /// which is done in the form of: (vma.state & state_mask) != state.
668 /// @param permission_mask The memory permissions mask.
669 /// @param permissions The permission to compare the individual VMA permissions against,
670 /// which is done in the form of:
671 /// (vma.permission & permission_mask) != permission.
672 /// @param attribute_mask The memory attribute mask.
673 /// @param attribute The memory attributes to compare the individual VMA attributes
674 /// against, which is done in the form of:
675 /// (vma.attributes & attribute_mask) != attribute.
676 /// @param ignore_mask The memory attributes to ignore during the check.
677 ///
678 /// @returns If successful, returns a tuple containing the memory attributes
679 /// (with ignored bits specified by ignore_mask unset), memory permissions, and
680 /// memory state across the memory range.
681 /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE.
682 ///
683 CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state,
684 VMAPermission permission_mask, VMAPermission permissions,
685 MemoryAttribute attribute_mask, MemoryAttribute attribute,
686 MemoryAttribute ignore_mask) const;
687
657private: 688private:
658 using VMAIter = VMAMap::iterator; 689 using VMAIter = VMAMap::iterator;
659 690
@@ -707,35 +738,6 @@ private:
707 /// Clears out the page table 738 /// Clears out the page table
708 void ClearPageTable(); 739 void ClearPageTable();
709 740
710 using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>;
711
712 /// Checks if an address range adheres to the specified states provided.
713 ///
714 /// @param address The starting address of the address range.
715 /// @param size The size of the address range.
716 /// @param state_mask The memory state mask.
717 /// @param state The state to compare the individual VMA states against,
718 /// which is done in the form of: (vma.state & state_mask) != state.
719 /// @param permission_mask The memory permissions mask.
720 /// @param permissions The permission to compare the individual VMA permissions against,
721 /// which is done in the form of:
722 /// (vma.permission & permission_mask) != permission.
723 /// @param attribute_mask The memory attribute mask.
724 /// @param attribute The memory attributes to compare the individual VMA attributes
725 /// against, which is done in the form of:
726 /// (vma.attributes & attribute_mask) != attribute.
727 /// @param ignore_mask The memory attributes to ignore during the check.
728 ///
729 /// @returns If successful, returns a tuple containing the memory attributes
730 /// (with ignored bits specified by ignore_mask unset), memory permissions, and
731 /// memory state across the memory range.
732 /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE.
733 ///
734 CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state,
735 VMAPermission permission_mask, VMAPermission permissions,
736 MemoryAttribute attribute_mask, MemoryAttribute attribute,
737 MemoryAttribute ignore_mask) const;
738
739 /// Gets the amount of memory currently mapped (state != Unmapped) in a range. 741 /// Gets the amount of memory currently mapped (state != Unmapped) in a range.
740 ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const; 742 ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const;
741 743
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp
index a0c806e8f..1838260fd 100644
--- a/src/core/hle/kernel/wait_object.cpp
+++ b/src/core/hle/kernel/wait_object.cpp
@@ -50,17 +50,8 @@ std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const {
50 if (ShouldWait(thread.get())) 50 if (ShouldWait(thread.get()))
51 continue; 51 continue;
52 52
53 // A thread is ready to run if it's either in ThreadStatus::WaitSynch 53 candidate = thread.get();
54 // and the rest of the objects it is waiting on are ready. 54 candidate_priority = thread->GetPriority();
55 bool ready_to_run = true;
56 if (thread_status == ThreadStatus::WaitSynch) {
57 ready_to_run = thread->AllWaitObjectsReady();
58 }
59
60 if (ready_to_run) {
61 candidate = thread.get();
62 candidate_priority = thread->GetPriority();
63 }
64 } 55 }
65 56
66 return SharedFrom(candidate); 57 return SharedFrom(candidate);
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 95aa5d23d..cc978713b 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -709,8 +709,34 @@ void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
709 apm_sys->SetCpuBoostMode(ctx); 709 apm_sys->SetCpuBoostMode(ctx);
710} 710}
711 711
712IStorage::IStorage(std::vector<u8> buffer) 712IStorageImpl::~IStorageImpl() = default;
713 : ServiceFramework("IStorage"), buffer(std::move(buffer)) { 713
714class StorageDataImpl final : public IStorageImpl {
715public:
716 explicit StorageDataImpl(std::vector<u8>&& buffer) : buffer{std::move(buffer)} {}
717
718 std::vector<u8>& GetData() override {
719 return buffer;
720 }
721
722 const std::vector<u8>& GetData() const override {
723 return buffer;
724 }
725
726 std::size_t GetSize() const override {
727 return buffer.size();
728 }
729
730private:
731 std::vector<u8> buffer;
732};
733
734IStorage::IStorage(std::vector<u8>&& buffer)
735 : ServiceFramework("IStorage"), impl{std::make_shared<StorageDataImpl>(std::move(buffer))} {
736 Register();
737}
738
739void IStorage::Register() {
714 // clang-format off 740 // clang-format off
715 static const FunctionInfo functions[] = { 741 static const FunctionInfo functions[] = {
716 {0, &IStorage::Open, "Open"}, 742 {0, &IStorage::Open, "Open"},
@@ -723,8 +749,13 @@ IStorage::IStorage(std::vector<u8> buffer)
723 749
724IStorage::~IStorage() = default; 750IStorage::~IStorage() = default;
725 751
726const std::vector<u8>& IStorage::GetData() const { 752void IStorage::Open(Kernel::HLERequestContext& ctx) {
727 return buffer; 753 LOG_DEBUG(Service_AM, "called");
754
755 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
756
757 rb.Push(RESULT_SUCCESS);
758 rb.PushIpcInterface<IStorageAccessor>(*this);
728} 759}
729 760
730void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { 761void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
@@ -816,7 +847,7 @@ private:
816 LOG_DEBUG(Service_AM, "called"); 847 LOG_DEBUG(Service_AM, "called");
817 848
818 IPC::RequestParser rp{ctx}; 849 IPC::RequestParser rp{ctx};
819 applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>()); 850 applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>());
820 851
821 IPC::ResponseBuilder rb{ctx, 2}; 852 IPC::ResponseBuilder rb{ctx, 2};
822 rb.Push(RESULT_SUCCESS); 853 rb.Push(RESULT_SUCCESS);
@@ -825,26 +856,25 @@ private:
825 void PopOutData(Kernel::HLERequestContext& ctx) { 856 void PopOutData(Kernel::HLERequestContext& ctx) {
826 LOG_DEBUG(Service_AM, "called"); 857 LOG_DEBUG(Service_AM, "called");
827 858
828 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
829
830 const auto storage = applet->GetBroker().PopNormalDataToGame(); 859 const auto storage = applet->GetBroker().PopNormalDataToGame();
831 if (storage == nullptr) { 860 if (storage == nullptr) {
832 LOG_ERROR(Service_AM, 861 LOG_ERROR(Service_AM,
833 "storage is a nullptr. There is no data in the current normal channel"); 862 "storage is a nullptr. There is no data in the current normal channel");
834 863 IPC::ResponseBuilder rb{ctx, 2};
835 rb.Push(ERR_NO_DATA_IN_CHANNEL); 864 rb.Push(ERR_NO_DATA_IN_CHANNEL);
836 return; 865 return;
837 } 866 }
838 867
868 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
839 rb.Push(RESULT_SUCCESS); 869 rb.Push(RESULT_SUCCESS);
840 rb.PushIpcInterface<IStorage>(std::move(*storage)); 870 rb.PushIpcInterface<IStorage>(std::move(storage));
841 } 871 }
842 872
843 void PushInteractiveInData(Kernel::HLERequestContext& ctx) { 873 void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
844 LOG_DEBUG(Service_AM, "called"); 874 LOG_DEBUG(Service_AM, "called");
845 875
846 IPC::RequestParser rp{ctx}; 876 IPC::RequestParser rp{ctx};
847 applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>()); 877 applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>());
848 878
849 ASSERT(applet->IsInitialized()); 879 ASSERT(applet->IsInitialized());
850 applet->ExecuteInteractive(); 880 applet->ExecuteInteractive();
@@ -857,19 +887,18 @@ private:
857 void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { 887 void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
858 LOG_DEBUG(Service_AM, "called"); 888 LOG_DEBUG(Service_AM, "called");
859 889
860 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
861
862 const auto storage = applet->GetBroker().PopInteractiveDataToGame(); 890 const auto storage = applet->GetBroker().PopInteractiveDataToGame();
863 if (storage == nullptr) { 891 if (storage == nullptr) {
864 LOG_ERROR(Service_AM, 892 LOG_ERROR(Service_AM,
865 "storage is a nullptr. There is no data in the current interactive channel"); 893 "storage is a nullptr. There is no data in the current interactive channel");
866 894 IPC::ResponseBuilder rb{ctx, 2};
867 rb.Push(ERR_NO_DATA_IN_CHANNEL); 895 rb.Push(ERR_NO_DATA_IN_CHANNEL);
868 return; 896 return;
869 } 897 }
870 898
899 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
871 rb.Push(RESULT_SUCCESS); 900 rb.Push(RESULT_SUCCESS);
872 rb.PushIpcInterface<IStorage>(std::move(*storage)); 901 rb.PushIpcInterface<IStorage>(std::move(storage));
873 } 902 }
874 903
875 void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) { 904 void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
@@ -891,15 +920,6 @@ private:
891 std::shared_ptr<Applets::Applet> applet; 920 std::shared_ptr<Applets::Applet> applet;
892}; 921};
893 922
894void IStorage::Open(Kernel::HLERequestContext& ctx) {
895 LOG_DEBUG(Service_AM, "called");
896
897 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
898
899 rb.Push(RESULT_SUCCESS);
900 rb.PushIpcInterface<IStorageAccessor>(*this);
901}
902
903IStorageAccessor::IStorageAccessor(IStorage& storage) 923IStorageAccessor::IStorageAccessor(IStorage& storage)
904 : ServiceFramework("IStorageAccessor"), backing(storage) { 924 : ServiceFramework("IStorageAccessor"), backing(storage) {
905 // clang-format off 925 // clang-format off
@@ -921,7 +941,7 @@ void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) {
921 IPC::ResponseBuilder rb{ctx, 4}; 941 IPC::ResponseBuilder rb{ctx, 4};
922 942
923 rb.Push(RESULT_SUCCESS); 943 rb.Push(RESULT_SUCCESS);
924 rb.Push(static_cast<u64>(backing.buffer.size())); 944 rb.Push(static_cast<u64>(backing.GetSize()));
925} 945}
926 946
927void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { 947void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
@@ -932,17 +952,17 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
932 952
933 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); 953 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size());
934 954
935 if (data.size() > backing.buffer.size() - offset) { 955 if (data.size() > backing.GetSize() - offset) {
936 LOG_ERROR(Service_AM, 956 LOG_ERROR(Service_AM,
937 "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", 957 "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
938 backing.buffer.size(), data.size(), offset); 958 backing.GetSize(), data.size(), offset);
939 959
940 IPC::ResponseBuilder rb{ctx, 2}; 960 IPC::ResponseBuilder rb{ctx, 2};
941 rb.Push(ERR_SIZE_OUT_OF_BOUNDS); 961 rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
942 return; 962 return;
943 } 963 }
944 964
945 std::memcpy(backing.buffer.data() + offset, data.data(), data.size()); 965 std::memcpy(backing.GetData().data() + offset, data.data(), data.size());
946 966
947 IPC::ResponseBuilder rb{ctx, 2}; 967 IPC::ResponseBuilder rb{ctx, 2};
948 rb.Push(RESULT_SUCCESS); 968 rb.Push(RESULT_SUCCESS);
@@ -956,16 +976,16 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
956 976
957 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); 977 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
958 978
959 if (size > backing.buffer.size() - offset) { 979 if (size > backing.GetSize() - offset) {
960 LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", 980 LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
961 backing.buffer.size(), size, offset); 981 backing.GetSize(), size, offset);
962 982
963 IPC::ResponseBuilder rb{ctx, 2}; 983 IPC::ResponseBuilder rb{ctx, 2};
964 rb.Push(ERR_SIZE_OUT_OF_BOUNDS); 984 rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
965 return; 985 return;
966 } 986 }
967 987
968 ctx.WriteBuffer(backing.buffer.data() + offset, size); 988 ctx.WriteBuffer(backing.GetData().data() + offset, size);
969 989
970 IPC::ResponseBuilder rb{ctx, 2}; 990 IPC::ResponseBuilder rb{ctx, 2};
971 rb.Push(RESULT_SUCCESS); 991 rb.Push(RESULT_SUCCESS);
@@ -1031,7 +1051,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
1031 rp.SetCurrentOffset(3); 1051 rp.SetCurrentOffset(3);
1032 const auto handle{rp.Pop<Kernel::Handle>()}; 1052 const auto handle{rp.Pop<Kernel::Handle>()};
1033 1053
1034 const auto transfer_mem = 1054 auto transfer_mem =
1035 system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); 1055 system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
1036 1056
1037 if (transfer_mem == nullptr) { 1057 if (transfer_mem == nullptr) {
@@ -1047,7 +1067,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
1047 1067
1048 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1068 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1049 rb.Push(RESULT_SUCCESS); 1069 rb.Push(RESULT_SUCCESS);
1050 rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory))); 1070 rb.PushIpcInterface<IStorage>(std::move(memory));
1051} 1071}
1052 1072
1053IApplicationFunctions::IApplicationFunctions(Core::System& system_) 1073IApplicationFunctions::IApplicationFunctions(Core::System& system_)
@@ -1189,13 +1209,11 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
1189 u64 build_id{}; 1209 u64 build_id{};
1190 std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); 1210 std::memcpy(&build_id, build_id_full.data(), sizeof(u64));
1191 1211
1192 const auto data = 1212 auto data = backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id});
1193 backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id});
1194
1195 if (data.has_value()) { 1213 if (data.has_value()) {
1196 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1214 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1197 rb.Push(RESULT_SUCCESS); 1215 rb.Push(RESULT_SUCCESS);
1198 rb.PushIpcInterface<AM::IStorage>(*data); 1216 rb.PushIpcInterface<IStorage>(std::move(*data));
1199 launch_popped_application_specific = true; 1217 launch_popped_application_specific = true;
1200 return; 1218 return;
1201 } 1219 }
@@ -1218,7 +1236,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
1218 std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); 1236 std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
1219 std::memcpy(buffer.data(), &params, buffer.size()); 1237 std::memcpy(buffer.data(), &params, buffer.size());
1220 1238
1221 rb.PushIpcInterface<AM::IStorage>(buffer); 1239 rb.PushIpcInterface<IStorage>(std::move(buffer));
1222 launch_popped_account_preselect = true; 1240 launch_popped_account_preselect = true;
1223 return; 1241 return;
1224 } 1242 }
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 448817be9..0b9a4332d 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -12,7 +12,8 @@
12 12
13namespace Kernel { 13namespace Kernel {
14class KernelCore; 14class KernelCore;
15} 15class TransferMemory;
16} // namespace Kernel
16 17
17namespace Service::NVFlinger { 18namespace Service::NVFlinger {
18class NVFlinger; 19class NVFlinger;
@@ -188,19 +189,36 @@ private:
188 std::shared_ptr<AppletMessageQueue> msg_queue; 189 std::shared_ptr<AppletMessageQueue> msg_queue;
189}; 190};
190 191
192class IStorageImpl {
193public:
194 virtual ~IStorageImpl();
195 virtual std::vector<u8>& GetData() = 0;
196 virtual const std::vector<u8>& GetData() const = 0;
197 virtual std::size_t GetSize() const = 0;
198};
199
191class IStorage final : public ServiceFramework<IStorage> { 200class IStorage final : public ServiceFramework<IStorage> {
192public: 201public:
193 explicit IStorage(std::vector<u8> buffer); 202 explicit IStorage(std::vector<u8>&& buffer);
194 ~IStorage() override; 203 ~IStorage() override;
195 204
196 const std::vector<u8>& GetData() const; 205 std::vector<u8>& GetData() {
206 return impl->GetData();
207 }
208
209 const std::vector<u8>& GetData() const {
210 return impl->GetData();
211 }
212
213 std::size_t GetSize() const {
214 return impl->GetSize();
215 }
197 216
198private: 217private:
218 void Register();
199 void Open(Kernel::HLERequestContext& ctx); 219 void Open(Kernel::HLERequestContext& ctx);
200 220
201 std::vector<u8> buffer; 221 std::shared_ptr<IStorageImpl> impl;
202
203 friend class IStorageAccessor;
204}; 222};
205 223
206class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { 224class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 92f995f8f..c3261f3e6 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -50,16 +50,17 @@ AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() co
50 return {std::move(out_normal), std::move(out_interactive)}; 50 return {std::move(out_normal), std::move(out_interactive)};
51} 51}
52 52
53std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() { 53std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
54 if (out_channel.empty()) 54 if (out_channel.empty())
55 return nullptr; 55 return nullptr;
56 56
57 auto out = std::move(out_channel.front()); 57 auto out = std::move(out_channel.front());
58 out_channel.pop_front(); 58 out_channel.pop_front();
59 pop_out_data_event.writable->Clear();
59 return out; 60 return out;
60} 61}
61 62
62std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() { 63std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
63 if (in_channel.empty()) 64 if (in_channel.empty())
64 return nullptr; 65 return nullptr;
65 66
@@ -68,16 +69,17 @@ std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
68 return out; 69 return out;
69} 70}
70 71
71std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() { 72std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
72 if (out_interactive_channel.empty()) 73 if (out_interactive_channel.empty())
73 return nullptr; 74 return nullptr;
74 75
75 auto out = std::move(out_interactive_channel.front()); 76 auto out = std::move(out_interactive_channel.front());
76 out_interactive_channel.pop_front(); 77 out_interactive_channel.pop_front();
78 pop_interactive_out_data_event.writable->Clear();
77 return out; 79 return out;
78} 80}
79 81
80std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() { 82std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
81 if (in_interactive_channel.empty()) 83 if (in_interactive_channel.empty())
82 return nullptr; 84 return nullptr;
83 85
@@ -86,21 +88,21 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
86 return out; 88 return out;
87} 89}
88 90
89void AppletDataBroker::PushNormalDataFromGame(IStorage storage) { 91void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage) {
90 in_channel.push_back(std::make_unique<IStorage>(storage)); 92 in_channel.emplace_back(std::move(storage));
91} 93}
92 94
93void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) { 95void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
94 out_channel.push_back(std::make_unique<IStorage>(storage)); 96 out_channel.emplace_back(std::move(storage));
95 pop_out_data_event.writable->Signal(); 97 pop_out_data_event.writable->Signal();
96} 98}
97 99
98void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) { 100void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
99 in_interactive_channel.push_back(std::make_unique<IStorage>(storage)); 101 in_interactive_channel.emplace_back(std::move(storage));
100} 102}
101 103
102void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) { 104void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
103 out_interactive_channel.push_back(std::make_unique<IStorage>(storage)); 105 out_interactive_channel.emplace_back(std::move(storage));
104 pop_interactive_out_data_event.writable->Signal(); 106 pop_interactive_out_data_event.writable->Signal();
105} 107}
106 108
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 16e61fc6f..e75be86a2 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -72,17 +72,17 @@ public:
72 // Retrieves but does not pop the data sent to applet. 72 // Retrieves but does not pop the data sent to applet.
73 RawChannelData PeekDataToAppletForDebug() const; 73 RawChannelData PeekDataToAppletForDebug() const;
74 74
75 std::unique_ptr<IStorage> PopNormalDataToGame(); 75 std::shared_ptr<IStorage> PopNormalDataToGame();
76 std::unique_ptr<IStorage> PopNormalDataToApplet(); 76 std::shared_ptr<IStorage> PopNormalDataToApplet();
77 77
78 std::unique_ptr<IStorage> PopInteractiveDataToGame(); 78 std::shared_ptr<IStorage> PopInteractiveDataToGame();
79 std::unique_ptr<IStorage> PopInteractiveDataToApplet(); 79 std::shared_ptr<IStorage> PopInteractiveDataToApplet();
80 80
81 void PushNormalDataFromGame(IStorage storage); 81 void PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage);
82 void PushNormalDataFromApplet(IStorage storage); 82 void PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage);
83 83
84 void PushInteractiveDataFromGame(IStorage storage); 84 void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage);
85 void PushInteractiveDataFromApplet(IStorage storage); 85 void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage);
86 86
87 void SignalStateChanged() const; 87 void SignalStateChanged() const;
88 88
@@ -94,16 +94,16 @@ private:
94 // Queues are named from applet's perspective 94 // Queues are named from applet's perspective
95 95
96 // PopNormalDataToApplet and PushNormalDataFromGame 96 // PopNormalDataToApplet and PushNormalDataFromGame
97 std::deque<std::unique_ptr<IStorage>> in_channel; 97 std::deque<std::shared_ptr<IStorage>> in_channel;
98 98
99 // PopNormalDataToGame and PushNormalDataFromApplet 99 // PopNormalDataToGame and PushNormalDataFromApplet
100 std::deque<std::unique_ptr<IStorage>> out_channel; 100 std::deque<std::shared_ptr<IStorage>> out_channel;
101 101
102 // PopInteractiveDataToApplet and PushInteractiveDataFromGame 102 // PopInteractiveDataToApplet and PushInteractiveDataFromGame
103 std::deque<std::unique_ptr<IStorage>> in_interactive_channel; 103 std::deque<std::shared_ptr<IStorage>> in_interactive_channel;
104 104
105 // PopInteractiveDataToGame and PushInteractiveDataFromApplet 105 // PopInteractiveDataToGame and PushInteractiveDataFromApplet
106 std::deque<std::unique_ptr<IStorage>> out_interactive_channel; 106 std::deque<std::shared_ptr<IStorage>> out_interactive_channel;
107 107
108 Kernel::EventPair state_changed_event; 108 Kernel::EventPair state_changed_event;
109 109
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp
index eab0d42c9..f12fd7f89 100644
--- a/src/core/hle/service/am/applets/error.cpp
+++ b/src/core/hle/service/am/applets/error.cpp
@@ -186,7 +186,7 @@ void Error::Execute() {
186 186
187void Error::DisplayCompleted() { 187void Error::DisplayCompleted() {
188 complete = true; 188 complete = true;
189 broker.PushNormalDataFromApplet(IStorage{{}}); 189 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{}));
190 broker.SignalStateChanged(); 190 broker.SignalStateChanged();
191} 191}
192 192
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp
index 328438a1d..104501ac5 100644
--- a/src/core/hle/service/am/applets/general_backend.cpp
+++ b/src/core/hle/service/am/applets/general_backend.cpp
@@ -20,7 +20,7 @@ namespace Service::AM::Applets {
20constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221}; 20constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
21 21
22static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) { 22static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) {
23 std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet(); 23 std::shared_ptr<IStorage> storage = broker.PopNormalDataToApplet();
24 for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { 24 for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
25 const auto data = storage->GetData(); 25 const auto data = storage->GetData();
26 LOG_INFO(Service_AM, 26 LOG_INFO(Service_AM,
@@ -148,7 +148,7 @@ void Auth::AuthFinished(bool successful) {
148 std::vector<u8> out(sizeof(Return)); 148 std::vector<u8> out(sizeof(Return));
149 std::memcpy(out.data(), &return_, sizeof(Return)); 149 std::memcpy(out.data(), &return_, sizeof(Return));
150 150
151 broker.PushNormalDataFromApplet(IStorage{out}); 151 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out)));
152 broker.SignalStateChanged(); 152 broker.SignalStateChanged();
153} 153}
154 154
@@ -198,7 +198,7 @@ void PhotoViewer::Execute() {
198} 198}
199 199
200void PhotoViewer::ViewFinished() { 200void PhotoViewer::ViewFinished() {
201 broker.PushNormalDataFromApplet(IStorage{{}}); 201 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{}));
202 broker.SignalStateChanged(); 202 broker.SignalStateChanged();
203} 203}
204 204
@@ -234,8 +234,8 @@ void StubApplet::ExecuteInteractive() {
234 LOG_WARNING(Service_AM, "called (STUBBED)"); 234 LOG_WARNING(Service_AM, "called (STUBBED)");
235 LogCurrentStorage(broker, "ExecuteInteractive"); 235 LogCurrentStorage(broker, "ExecuteInteractive");
236 236
237 broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)}); 237 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
238 broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)}); 238 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
239 broker.SignalStateChanged(); 239 broker.SignalStateChanged();
240} 240}
241 241
@@ -243,8 +243,8 @@ void StubApplet::Execute() {
243 LOG_WARNING(Service_AM, "called (STUBBED)"); 243 LOG_WARNING(Service_AM, "called (STUBBED)");
244 LogCurrentStorage(broker, "Execute"); 244 LogCurrentStorage(broker, "Execute");
245 245
246 broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)}); 246 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
247 broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)}); 247 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
248 broker.SignalStateChanged(); 248 broker.SignalStateChanged();
249} 249}
250 250
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp
index 3eba696ca..70cc23552 100644
--- a/src/core/hle/service/am/applets/profile_select.cpp
+++ b/src/core/hle/service/am/applets/profile_select.cpp
@@ -50,7 +50,7 @@ void ProfileSelect::ExecuteInteractive() {
50 50
51void ProfileSelect::Execute() { 51void ProfileSelect::Execute() {
52 if (complete) { 52 if (complete) {
53 broker.PushNormalDataFromApplet(IStorage{final_data}); 53 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data)));
54 return; 54 return;
55 } 55 }
56 56
@@ -71,7 +71,7 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
71 71
72 final_data = std::vector<u8>(sizeof(UserSelectionOutput)); 72 final_data = std::vector<u8>(sizeof(UserSelectionOutput));
73 std::memcpy(final_data.data(), &output, final_data.size()); 73 std::memcpy(final_data.data(), &output, final_data.size());
74 broker.PushNormalDataFromApplet(IStorage{final_data}); 74 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data)));
75 broker.SignalStateChanged(); 75 broker.SignalStateChanged();
76} 76}
77 77
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index 748559cd0..54e63c138 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -102,7 +102,8 @@ void SoftwareKeyboard::ExecuteInteractive() {
102 102
103void SoftwareKeyboard::Execute() { 103void SoftwareKeyboard::Execute() {
104 if (complete) { 104 if (complete) {
105 broker.PushNormalDataFromApplet(IStorage{final_data}); 105 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data)));
106 broker.SignalStateChanged();
106 return; 107 return;
107 } 108 }
108 109
@@ -119,7 +120,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
119 std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE); 120 std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE);
120 121
121 if (config.utf_8) { 122 if (config.utf_8) {
122 const u64 size = text->size() + 8; 123 const u64 size = text->size() + sizeof(u64);
123 const auto new_text = Common::UTF16ToUTF8(*text); 124 const auto new_text = Common::UTF16ToUTF8(*text);
124 125
125 std::memcpy(output_sub.data(), &size, sizeof(u64)); 126 std::memcpy(output_sub.data(), &size, sizeof(u64));
@@ -130,7 +131,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
130 std::memcpy(output_main.data() + 4, new_text.data(), 131 std::memcpy(output_main.data() + 4, new_text.data(),
131 std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4)); 132 std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4));
132 } else { 133 } else {
133 const u64 size = text->size() * 2 + 8; 134 const u64 size = text->size() * 2 + sizeof(u64);
134 std::memcpy(output_sub.data(), &size, sizeof(u64)); 135 std::memcpy(output_sub.data(), &size, sizeof(u64));
135 std::memcpy(output_sub.data() + 8, text->data(), 136 std::memcpy(output_sub.data() + 8, text->data(),
136 std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); 137 std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8));
@@ -144,15 +145,15 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
144 final_data = output_main; 145 final_data = output_main;
145 146
146 if (complete) { 147 if (complete) {
147 broker.PushNormalDataFromApplet(IStorage{output_main}); 148 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(output_main)));
148 broker.SignalStateChanged(); 149 broker.SignalStateChanged();
149 } else { 150 } else {
150 broker.PushInteractiveDataFromApplet(IStorage{output_sub}); 151 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::move(output_sub)));
151 } 152 }
152 } else { 153 } else {
153 output_main[0] = 1; 154 output_main[0] = 1;
154 complete = true; 155 complete = true;
155 broker.PushNormalDataFromApplet(IStorage{output_main}); 156 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(output_main)));
156 broker.SignalStateChanged(); 157 broker.SignalStateChanged();
157 } 158 }
158} 159}
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 5546ef6e8..12443c910 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -284,7 +284,7 @@ void WebBrowser::Finalize() {
284 std::vector<u8> data(sizeof(WebCommonReturnValue)); 284 std::vector<u8> data(sizeof(WebCommonReturnValue));
285 std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue)); 285 std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue));
286 286
287 broker.PushNormalDataFromApplet(IStorage{data}); 287 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(data)));
288 broker.SignalStateChanged(); 288 broker.SignalStateChanged();
289 289
290 if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) { 290 if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) {
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 55d62fc5e..e6811d5b5 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -420,7 +420,7 @@ public:
420 return; 420 return;
421 } 421 }
422 422
423 IFile file(result.Unwrap()); 423 auto file = std::make_shared<IFile>(result.Unwrap());
424 424
425 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 425 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
426 rb.Push(RESULT_SUCCESS); 426 rb.Push(RESULT_SUCCESS);
@@ -445,7 +445,7 @@ public:
445 return; 445 return;
446 } 446 }
447 447
448 IDirectory directory(result.Unwrap()); 448 auto directory = std::make_shared<IDirectory>(result.Unwrap());
449 449
450 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 450 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
451 rb.Push(RESULT_SUCCESS); 451 rb.Push(RESULT_SUCCESS);
@@ -794,8 +794,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
794void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) { 794void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
795 LOG_DEBUG(Service_FS, "called"); 795 LOG_DEBUG(Service_FS, "called");
796 796
797 IFileSystem filesystem(fsc.OpenSDMC().Unwrap(), 797 auto filesystem = std::make_shared<IFileSystem>(
798 SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard)); 798 fsc.OpenSDMC().Unwrap(), SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
799 799
800 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 800 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
801 rb.Push(RESULT_SUCCESS); 801 rb.Push(RESULT_SUCCESS);
@@ -846,7 +846,8 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
846 id = FileSys::StorageId::NandSystem; 846 id = FileSys::StorageId::NandSystem;
847 } 847 }
848 848
849 IFileSystem filesystem(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id)); 849 auto filesystem =
850 std::make_shared<IFileSystem>(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id));
850 851
851 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 852 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
852 rb.Push(RESULT_SUCCESS); 853 rb.Push(RESULT_SUCCESS);
@@ -898,7 +899,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
898 return; 899 return;
899 } 900 }
900 901
901 IStorage storage(std::move(romfs.Unwrap())); 902 auto storage = std::make_shared<IStorage>(std::move(romfs.Unwrap()));
902 903
903 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 904 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
904 rb.Push(RESULT_SUCCESS); 905 rb.Push(RESULT_SUCCESS);
@@ -937,7 +938,8 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
937 938
938 FileSys::PatchManager pm{title_id}; 939 FileSys::PatchManager pm{title_id};
939 940
940 IStorage storage(pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data)); 941 auto storage = std::make_shared<IStorage>(
942 pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
941 943
942 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 944 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
943 rb.Push(RESULT_SUCCESS); 945 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index 5eb26caf8..8f1be0e48 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -50,16 +50,16 @@ private:
50 IPC::RequestParser rp{ctx}; 50 IPC::RequestParser rp{ctx};
51 const auto process_id = rp.PopRaw<u64>(); 51 const auto process_id = rp.PopRaw<u64>();
52 52
53 const auto data1 = ctx.ReadBuffer(0); 53 std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)};
54 const auto data2 = ctx.ReadBuffer(1); 54 if (Type == Core::Reporter::PlayReportType::New) {
55 data.emplace_back(ctx.ReadBuffer(1));
56 }
55 57
56 LOG_DEBUG(Service_PREPO, 58 LOG_DEBUG(Service_PREPO, "called, type={:02X}, process_id={:016X}, data1_size={:016X}",
57 "called, type={:02X}, process_id={:016X}, data1_size={:016X}, data2_size={:016X}", 59 static_cast<u8>(Type), process_id, data[0].size());
58 static_cast<u8>(Type), process_id, data1.size(), data2.size());
59 60
60 const auto& reporter{system.GetReporter()}; 61 const auto& reporter{system.GetReporter()};
61 reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2}, 62 reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id);
62 process_id);
63 63
64 IPC::ResponseBuilder rb{ctx, 2}; 64 IPC::ResponseBuilder rb{ctx, 2};
65 rb.Push(RESULT_SUCCESS); 65 rb.Push(RESULT_SUCCESS);
@@ -70,19 +70,19 @@ private:
70 IPC::RequestParser rp{ctx}; 70 IPC::RequestParser rp{ctx};
71 const auto user_id = rp.PopRaw<u128>(); 71 const auto user_id = rp.PopRaw<u128>();
72 const auto process_id = rp.PopRaw<u64>(); 72 const auto process_id = rp.PopRaw<u64>();
73 73 std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)};
74 const auto data1 = ctx.ReadBuffer(0); 74 if (Type == Core::Reporter::PlayReportType::New) {
75 const auto data2 = ctx.ReadBuffer(1); 75 data.emplace_back(ctx.ReadBuffer(1));
76 }
76 77
77 LOG_DEBUG( 78 LOG_DEBUG(
78 Service_PREPO, 79 Service_PREPO,
79 "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}, " 80 "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}",
80 "data2_size={:016X}", 81 static_cast<u8>(Type), user_id[1], user_id[0], process_id, data[0].size());
81 static_cast<u8>(Type), user_id[1], user_id[0], process_id, data1.size(), data2.size());
82 82
83 const auto& reporter{system.GetReporter()}; 83 const auto& reporter{system.GetReporter()};
84 reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2}, 84 reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id,
85 process_id, user_id); 85 user_id);
86 86
87 IPC::ResponseBuilder rb{ctx, 2}; 87 IPC::ResponseBuilder rb{ctx, 2};
88 rb.Push(RESULT_SUCCESS); 88 rb.Push(RESULT_SUCCESS);
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index ab9bbf2e7..7b1912a66 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -704,8 +704,8 @@ public:
704 INSERT_UNION_PADDING_WORDS(0x15); 704 INSERT_UNION_PADDING_WORDS(0x15);
705 705
706 s32 stencil_back_func_ref; 706 s32 stencil_back_func_ref;
707 u32 stencil_back_func_mask;
708 u32 stencil_back_mask; 707 u32 stencil_back_mask;
708 u32 stencil_back_func_mask;
709 709
710 INSERT_UNION_PADDING_WORDS(0xC); 710 INSERT_UNION_PADDING_WORDS(0xC);
711 711
@@ -1462,8 +1462,8 @@ ASSERT_REG_POSITION(polygon_offset_fill_enable, 0x372);
1462ASSERT_REG_POSITION(patch_vertices, 0x373); 1462ASSERT_REG_POSITION(patch_vertices, 0x373);
1463ASSERT_REG_POSITION(scissor_test, 0x380); 1463ASSERT_REG_POSITION(scissor_test, 0x380);
1464ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); 1464ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
1465ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D6); 1465ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
1466ASSERT_REG_POSITION(stencil_back_mask, 0x3D7); 1466ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
1467ASSERT_REG_POSITION(color_mask_common, 0x3E4); 1467ASSERT_REG_POSITION(color_mask_common, 0x3E4);
1468ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); 1468ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
1469ASSERT_REG_POSITION(depth_bounds, 0x3E7); 1469ASSERT_REG_POSITION(depth_bounds, 0x3E7);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index cbb201114..402869fde 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -624,6 +624,19 @@ enum class ShuffleOperation : u64 {
624 Bfly = 3, // shuffleXorNV 624 Bfly = 3, // shuffleXorNV
625}; 625};
626 626
627enum class ShfType : u64 {
628 Bits32 = 0,
629 U64 = 2,
630 S64 = 3,
631};
632
633enum class ShfXmode : u64 {
634 None = 0,
635 HI = 1,
636 X = 2,
637 XHI = 3,
638};
639
627union Instruction { 640union Instruction {
628 constexpr Instruction& operator=(const Instruction& instr) { 641 constexpr Instruction& operator=(const Instruction& instr) {
629 value = instr.value; 642 value = instr.value;
@@ -776,6 +789,13 @@ union Instruction {
776 } shr; 789 } shr;
777 790
778 union { 791 union {
792 BitField<37, 2, ShfType> type;
793 BitField<48, 2, ShfXmode> xmode;
794 BitField<50, 1, u64> wrap;
795 BitField<20, 6, u64> immediate;
796 } shf;
797
798 union {
779 BitField<39, 5, u64> shift_amount; 799 BitField<39, 5, u64> shift_amount;
780 BitField<48, 1, u64> negate_b; 800 BitField<48, 1, u64> negate_b;
781 BitField<49, 1, u64> negate_a; 801 BitField<49, 1, u64> negate_a;
@@ -1708,6 +1728,7 @@ public:
1708 BFE_C, 1728 BFE_C,
1709 BFE_R, 1729 BFE_R,
1710 BFE_IMM, 1730 BFE_IMM,
1731 BFI_RC,
1711 BFI_IMM_R, 1732 BFI_IMM_R,
1712 BRA, 1733 BRA,
1713 BRX, 1734 BRX,
@@ -2135,6 +2156,7 @@ private:
2135 INST("0100110000000---", Id::BFE_C, Type::Bfe, "BFE_C"), 2156 INST("0100110000000---", Id::BFE_C, Type::Bfe, "BFE_C"),
2136 INST("0101110000000---", Id::BFE_R, Type::Bfe, "BFE_R"), 2157 INST("0101110000000---", Id::BFE_R, Type::Bfe, "BFE_R"),
2137 INST("0011100-00000---", Id::BFE_IMM, Type::Bfe, "BFE_IMM"), 2158 INST("0011100-00000---", Id::BFE_IMM, Type::Bfe, "BFE_IMM"),
2159 INST("0101001111110---", Id::BFI_RC, Type::Bfi, "BFI_RC"),
2138 INST("0011011-11110---", Id::BFI_IMM_R, Type::Bfi, "BFI_IMM_R"), 2160 INST("0011011-11110---", Id::BFI_IMM_R, Type::Bfi, "BFI_IMM_R"),
2139 INST("0100110001000---", Id::LOP_C, Type::ArithmeticInteger, "LOP_C"), 2161 INST("0100110001000---", Id::LOP_C, Type::ArithmeticInteger, "LOP_C"),
2140 INST("0101110001000---", Id::LOP_R, Type::ArithmeticInteger, "LOP_R"), 2162 INST("0101110001000---", Id::LOP_R, Type::ArithmeticInteger, "LOP_R"),
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index b9c5c41a2..062ca83b8 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -23,7 +23,7 @@ MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
23GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async) 23GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async)
24 : system{system}, renderer{renderer}, is_async{is_async} { 24 : system{system}, renderer{renderer}, is_async{is_async} {
25 auto& rasterizer{renderer.Rasterizer()}; 25 auto& rasterizer{renderer.Rasterizer()};
26 memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer); 26 memory_manager = std::make_unique<Tegra::MemoryManager>(system);
27 dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); 27 dma_pusher = std::make_unique<Tegra::DmaPusher>(*this);
28 maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager); 28 maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager);
29 fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer); 29 fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer);
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index 08dc96bb3..882e2d9c7 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -86,7 +86,7 @@ struct CommandDataContainer {
86struct SynchState final { 86struct SynchState final {
87 std::atomic_bool is_running{true}; 87 std::atomic_bool is_running{true};
88 88
89 using CommandQueue = Common::SPSCQueue<CommandDataContainer>; 89 using CommandQueue = Common::MPSCQueue<CommandDataContainer>;
90 CommandQueue queue; 90 CommandQueue queue;
91 u64 last_fence{}; 91 u64 last_fence{};
92 std::atomic<u64> signaled_fence{}; 92 std::atomic<u64> signaled_fence{};
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 11848fbce..f1d50be3e 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -9,13 +9,12 @@
9#include "core/hle/kernel/process.h" 9#include "core/hle/kernel/process.h"
10#include "core/hle/kernel/vm_manager.h" 10#include "core/hle/kernel/vm_manager.h"
11#include "core/memory.h" 11#include "core/memory.h"
12#include "video_core/gpu.h"
12#include "video_core/memory_manager.h" 13#include "video_core/memory_manager.h"
13#include "video_core/rasterizer_interface.h"
14 14
15namespace Tegra { 15namespace Tegra {
16 16
17MemoryManager::MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer) 17MemoryManager::MemoryManager(Core::System& system) : system{system} {
18 : rasterizer{rasterizer}, system{system} {
19 std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr); 18 std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
20 std::fill(page_table.attributes.begin(), page_table.attributes.end(), 19 std::fill(page_table.attributes.begin(), page_table.attributes.end(),
21 Common::PageType::Unmapped); 20 Common::PageType::Unmapped);
@@ -84,7 +83,8 @@ GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
84 const auto cpu_addr = GpuToCpuAddress(gpu_addr); 83 const auto cpu_addr = GpuToCpuAddress(gpu_addr);
85 ASSERT(cpu_addr); 84 ASSERT(cpu_addr);
86 85
87 rasterizer.FlushAndInvalidateRegion(cache_addr, aligned_size); 86 system.GPU().FlushAndInvalidateRegion(cache_addr, aligned_size);
87
88 UnmapRange(gpu_addr, aligned_size); 88 UnmapRange(gpu_addr, aligned_size);
89 ASSERT(system.CurrentProcess() 89 ASSERT(system.CurrentProcess()
90 ->VMManager() 90 ->VMManager()
@@ -242,7 +242,7 @@ void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, const std::s
242 switch (page_table.attributes[page_index]) { 242 switch (page_table.attributes[page_index]) {
243 case Common::PageType::Memory: { 243 case Common::PageType::Memory: {
244 const u8* src_ptr{page_table.pointers[page_index] + page_offset}; 244 const u8* src_ptr{page_table.pointers[page_index] + page_offset};
245 rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount); 245 system.GPU().FlushRegion(ToCacheAddr(src_ptr), copy_amount);
246 std::memcpy(dest_buffer, src_ptr, copy_amount); 246 std::memcpy(dest_buffer, src_ptr, copy_amount);
247 break; 247 break;
248 } 248 }
@@ -292,7 +292,7 @@ void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, const
292 switch (page_table.attributes[page_index]) { 292 switch (page_table.attributes[page_index]) {
293 case Common::PageType::Memory: { 293 case Common::PageType::Memory: {
294 u8* dest_ptr{page_table.pointers[page_index] + page_offset}; 294 u8* dest_ptr{page_table.pointers[page_index] + page_offset};
295 rasterizer.InvalidateRegion(ToCacheAddr(dest_ptr), copy_amount); 295 system.GPU().InvalidateRegion(ToCacheAddr(dest_ptr), copy_amount);
296 std::memcpy(dest_ptr, src_buffer, copy_amount); 296 std::memcpy(dest_ptr, src_buffer, copy_amount);
297 break; 297 break;
298 } 298 }
@@ -340,7 +340,7 @@ void MemoryManager::CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, const std::
340 switch (page_table.attributes[page_index]) { 340 switch (page_table.attributes[page_index]) {
341 case Common::PageType::Memory: { 341 case Common::PageType::Memory: {
342 const u8* src_ptr{page_table.pointers[page_index] + page_offset}; 342 const u8* src_ptr{page_table.pointers[page_index] + page_offset};
343 rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount); 343 system.GPU().FlushRegion(ToCacheAddr(src_ptr), copy_amount);
344 WriteBlock(dest_addr, src_ptr, copy_amount); 344 WriteBlock(dest_addr, src_ptr, copy_amount);
345 break; 345 break;
346 } 346 }
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index aea010087..393447eb4 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -10,10 +10,6 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/page_table.h" 11#include "common/page_table.h"
12 12
13namespace VideoCore {
14class RasterizerInterface;
15}
16
17namespace Core { 13namespace Core {
18class System; 14class System;
19} 15}
@@ -51,7 +47,7 @@ struct VirtualMemoryArea {
51 47
52class MemoryManager final { 48class MemoryManager final {
53public: 49public:
54 explicit MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer); 50 explicit MemoryManager(Core::System& system);
55 ~MemoryManager(); 51 ~MemoryManager();
56 52
57 GPUVAddr AllocateSpace(u64 size, u64 align); 53 GPUVAddr AllocateSpace(u64 size, u64 align);
@@ -176,7 +172,6 @@ private:
176 172
177 Common::PageTable page_table{page_bits}; 173 Common::PageTable page_table{page_bits};
178 VMAMap vma_map; 174 VMAMap vma_map;
179 VideoCore::RasterizerInterface& rasterizer;
180 175
181 Core::System& system; 176 Core::System& system;
182}; 177};
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 0537a2abe..b0eb14c8b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -248,9 +248,6 @@ void RasterizerOpenGL::SetupVertexInstances(GLuint vao) {
248} 248}
249 249
250GLintptr RasterizerOpenGL::SetupIndexBuffer() { 250GLintptr RasterizerOpenGL::SetupIndexBuffer() {
251 if (accelerate_draw != AccelDraw::Indexed) {
252 return 0;
253 }
254 MICROPROFILE_SCOPE(OpenGL_Index); 251 MICROPROFILE_SCOPE(OpenGL_Index);
255 const auto& regs = system.GPU().Maxwell3D().regs; 252 const auto& regs = system.GPU().Maxwell3D().regs;
256 const std::size_t size = CalculateIndexBufferSize(); 253 const std::size_t size = CalculateIndexBufferSize();
@@ -546,7 +543,8 @@ void RasterizerOpenGL::Clear() {
546 } 543 }
547} 544}
548 545
549void RasterizerOpenGL::DrawPrelude() { 546void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
547 MICROPROFILE_SCOPE(OpenGL_Drawing);
550 auto& gpu = system.GPU().Maxwell3D(); 548 auto& gpu = system.GPU().Maxwell3D();
551 549
552 SyncRasterizeEnable(state); 550 SyncRasterizeEnable(state);
@@ -567,9 +565,6 @@ void RasterizerOpenGL::DrawPrelude() {
567 565
568 buffer_cache.Acquire(); 566 buffer_cache.Acquire();
569 567
570 // Draw the vertex batch
571 const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
572
573 std::size_t buffer_size = CalculateVertexArraysSize(); 568 std::size_t buffer_size = CalculateVertexArraysSize();
574 569
575 // Add space for index buffer 570 // Add space for index buffer
@@ -596,7 +591,11 @@ void RasterizerOpenGL::DrawPrelude() {
596 // Upload vertex and index data. 591 // Upload vertex and index data.
597 SetupVertexBuffer(vao); 592 SetupVertexBuffer(vao);
598 SetupVertexInstances(vao); 593 SetupVertexInstances(vao);
599 index_buffer_offset = SetupIndexBuffer(); 594
595 GLintptr index_buffer_offset;
596 if (is_indexed) {
597 index_buffer_offset = SetupIndexBuffer();
598 }
600 599
601 // Prepare packed bindings. 600 // Prepare packed bindings.
602 bind_ubo_pushbuffer.Setup(); 601 bind_ubo_pushbuffer.Setup();
@@ -630,6 +629,7 @@ void RasterizerOpenGL::DrawPrelude() {
630 // As all cached buffers are invalidated, we need to recheck their state. 629 // As all cached buffers are invalidated, we need to recheck their state.
631 gpu.dirty.ResetVertexArrays(); 630 gpu.dirty.ResetVertexArrays();
632 } 631 }
632 gpu.dirty.memory_general = false;
633 633
634 shader_program_manager->ApplyTo(state); 634 shader_program_manager->ApplyTo(state);
635 state.Apply(); 635 state.Apply();
@@ -637,106 +637,33 @@ void RasterizerOpenGL::DrawPrelude() {
637 if (texture_cache.TextureBarrier()) { 637 if (texture_cache.TextureBarrier()) {
638 glTextureBarrier(); 638 glTextureBarrier();
639 } 639 }
640}
641
642struct DrawParams {
643 bool is_indexed{};
644 bool is_instanced{};
645 GLenum primitive_mode{};
646 GLint count{};
647 GLint base_vertex{};
648
649 // Indexed settings
650 GLenum index_format{};
651 GLintptr index_buffer_offset{};
652
653 // Instanced setting
654 GLint num_instances{};
655 GLint base_instance{};
656
657 void DispatchDraw() {
658 if (is_indexed) {
659 const auto index_buffer_ptr = reinterpret_cast<const void*>(index_buffer_offset);
660 if (is_instanced) {
661 glDrawElementsInstancedBaseVertexBaseInstance(primitive_mode, count, index_format,
662 index_buffer_ptr, num_instances,
663 base_vertex, base_instance);
664 } else {
665 glDrawElementsBaseVertex(primitive_mode, count, index_format, index_buffer_ptr,
666 base_vertex);
667 }
668 } else {
669 if (is_instanced) {
670 glDrawArraysInstancedBaseInstance(primitive_mode, base_vertex, count, num_instances,
671 base_instance);
672 } else {
673 glDrawArrays(primitive_mode, base_vertex, count);
674 }
675 }
676 }
677};
678
679bool RasterizerOpenGL::DrawBatch(bool is_indexed) {
680 accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
681 640
682 MICROPROFILE_SCOPE(OpenGL_Drawing); 641 const GLuint base_instance = static_cast<GLuint>(gpu.regs.vb_base_instance);
683 642 const GLsizei num_instances =
684 DrawPrelude(); 643 static_cast<GLsizei>(is_instanced ? gpu.mme_draw.instance_count : 1);
685 644 if (is_indexed) {
686 auto& maxwell3d = system.GPU().Maxwell3D(); 645 const GLenum index_format = MaxwellToGL::IndexFormat(gpu.regs.index_array.format);
687 const auto& regs = maxwell3d.regs; 646 const GLint base_vertex = static_cast<GLint>(gpu.regs.vb_element_base);
688 const auto current_instance = maxwell3d.state.current_instance; 647 const GLsizei num_vertices = static_cast<GLsizei>(gpu.regs.index_array.count);
689 DrawParams draw_call{}; 648 glDrawElementsInstancedBaseVertexBaseInstance(
690 draw_call.is_indexed = is_indexed; 649 primitive_mode, num_vertices, index_format,
691 draw_call.num_instances = static_cast<GLint>(1); 650 reinterpret_cast<const void*>(index_buffer_offset), num_instances, base_vertex,
692 draw_call.base_instance = static_cast<GLint>(current_instance); 651 base_instance);
693 draw_call.is_instanced = current_instance > 0;
694 draw_call.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
695 if (draw_call.is_indexed) {
696 draw_call.count = static_cast<GLint>(regs.index_array.count);
697 draw_call.base_vertex = static_cast<GLint>(regs.vb_element_base);
698 draw_call.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
699 draw_call.index_buffer_offset = index_buffer_offset;
700 } else { 652 } else {
701 draw_call.count = static_cast<GLint>(regs.vertex_buffer.count); 653 const GLint base_vertex = static_cast<GLint>(gpu.regs.vertex_buffer.first);
702 draw_call.base_vertex = static_cast<GLint>(regs.vertex_buffer.first); 654 const GLsizei num_vertices = static_cast<GLsizei>(gpu.regs.vertex_buffer.count);
655 glDrawArraysInstancedBaseInstance(primitive_mode, base_vertex, num_vertices, num_instances,
656 base_instance);
703 } 657 }
704 draw_call.DispatchDraw(); 658}
705 659
706 maxwell3d.dirty.memory_general = false; 660bool RasterizerOpenGL::DrawBatch(bool is_indexed) {
707 accelerate_draw = AccelDraw::Disabled; 661 Draw(is_indexed, false);
708 return true; 662 return true;
709} 663}
710 664
711bool RasterizerOpenGL::DrawMultiBatch(bool is_indexed) { 665bool RasterizerOpenGL::DrawMultiBatch(bool is_indexed) {
712 accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays; 666 Draw(is_indexed, true);
713
714 MICROPROFILE_SCOPE(OpenGL_Drawing);
715
716 DrawPrelude();
717
718 auto& maxwell3d = system.GPU().Maxwell3D();
719 const auto& regs = maxwell3d.regs;
720 const auto& draw_setup = maxwell3d.mme_draw;
721 DrawParams draw_call{};
722 draw_call.is_indexed = is_indexed;
723 draw_call.num_instances = static_cast<GLint>(draw_setup.instance_count);
724 draw_call.base_instance = static_cast<GLint>(regs.vb_base_instance);
725 draw_call.is_instanced = draw_setup.instance_count > 1;
726 draw_call.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
727 if (draw_call.is_indexed) {
728 draw_call.count = static_cast<GLint>(regs.index_array.count);
729 draw_call.base_vertex = static_cast<GLint>(regs.vb_element_base);
730 draw_call.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
731 draw_call.index_buffer_offset = index_buffer_offset;
732 } else {
733 draw_call.count = static_cast<GLint>(regs.vertex_buffer.count);
734 draw_call.base_vertex = static_cast<GLint>(regs.vertex_buffer.first);
735 }
736 draw_call.DispatchDraw();
737
738 maxwell3d.dirty.memory_general = false;
739 accelerate_draw = AccelDraw::Disabled;
740 return true; 667 return true;
741} 668}
742 669
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 6a27cf497..0501f3828 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -103,7 +103,7 @@ private:
103 std::size_t size); 103 std::size_t size);
104 104
105 /// Syncs all the state, shaders, render targets and textures setting before a draw call. 105 /// Syncs all the state, shaders, render targets and textures setting before a draw call.
106 void DrawPrelude(); 106 void Draw(bool is_indexed, bool is_instanced);
107 107
108 /// Configures the current textures to use for the draw command. 108 /// Configures the current textures to use for the draw command.
109 void SetupDrawTextures(std::size_t stage_index, const Shader& shader); 109 void SetupDrawTextures(std::size_t stage_index, const Shader& shader);
@@ -220,12 +220,7 @@ private:
220 220
221 GLintptr SetupIndexBuffer(); 221 GLintptr SetupIndexBuffer();
222 222
223 GLintptr index_buffer_offset;
224
225 void SetupShaders(GLenum primitive_mode); 223 void SetupShaders(GLenum primitive_mode);
226
227 enum class AccelDraw { Disabled, Arrays, Indexed };
228 AccelDraw accelerate_draw = AccelDraw::Disabled;
229}; 224};
230 225
231} // namespace OpenGL 226} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index ea4f35663..7ed505628 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -47,8 +47,7 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
47 case Maxwell::VertexAttribute::Size::Size_10_10_10_2: 47 case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
48 return GL_UNSIGNED_INT_2_10_10_10_REV; 48 return GL_UNSIGNED_INT_2_10_10_10_REV;
49 default: 49 default:
50 LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); 50 LOG_ERROR(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
51 UNREACHABLE();
52 return {}; 51 return {};
53 } 52 }
54 case Maxwell::VertexAttribute::Type::SignedInt: 53 case Maxwell::VertexAttribute::Type::SignedInt:
@@ -72,8 +71,7 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
72 case Maxwell::VertexAttribute::Size::Size_10_10_10_2: 71 case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
73 return GL_INT_2_10_10_10_REV; 72 return GL_INT_2_10_10_10_REV;
74 default: 73 default:
75 LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); 74 LOG_ERROR(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
76 UNREACHABLE();
77 return {}; 75 return {};
78 } 76 }
79 case Maxwell::VertexAttribute::Type::Float: 77 case Maxwell::VertexAttribute::Type::Float:
@@ -89,13 +87,19 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
89 case Maxwell::VertexAttribute::Size::Size_32_32_32_32: 87 case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
90 return GL_FLOAT; 88 return GL_FLOAT;
91 default: 89 default:
92 LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); 90 LOG_ERROR(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
93 UNREACHABLE(); 91 return {};
92 }
93 case Maxwell::VertexAttribute::Type::UnsignedScaled:
94 switch (attrib.size) {
95 case Maxwell::VertexAttribute::Size::Size_8_8:
96 return GL_UNSIGNED_BYTE;
97 default:
98 LOG_ERROR(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
94 return {}; 99 return {};
95 } 100 }
96 default: 101 default:
97 LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString()); 102 LOG_ERROR(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString());
98 UNREACHABLE();
99 return {}; 103 return {};
100 } 104 }
101} 105}
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index d2c6b1189..aada38702 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -571,7 +571,7 @@ RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() {
571 color_attachments[rt] = texture_cache.GetColorBufferSurface(rt, true); 571 color_attachments[rt] = texture_cache.GetColorBufferSurface(rt, true);
572 } 572 }
573 if (color_attachments[rt] && WalkAttachmentOverlaps(*color_attachments[rt])) { 573 if (color_attachments[rt] && WalkAttachmentOverlaps(*color_attachments[rt])) {
574 texceptions.set(rt); 574 texceptions[rt] = true;
575 } 575 }
576 } 576 }
577 577
@@ -579,7 +579,7 @@ RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() {
579 zeta_attachment = texture_cache.GetDepthBufferSurface(true); 579 zeta_attachment = texture_cache.GetDepthBufferSurface(true);
580 } 580 }
581 if (zeta_attachment && WalkAttachmentOverlaps(*zeta_attachment)) { 581 if (zeta_attachment && WalkAttachmentOverlaps(*zeta_attachment)) {
582 texceptions.set(ZETA_TEXCEPTION_INDEX); 582 texceptions[ZETA_TEXCEPTION_INDEX] = true;
583 } 583 }
584 584
585 texture_cache.GuardRenderTargets(false); 585 texture_cache.GuardRenderTargets(false);
@@ -1122,11 +1122,12 @@ RenderPassParams RasterizerVulkan::GetRenderPassParams(Texceptions texceptions)
1122 1122
1123 for (std::size_t rt = 0; rt < static_cast<std::size_t>(regs.rt_control.count); ++rt) { 1123 for (std::size_t rt = 0; rt < static_cast<std::size_t>(regs.rt_control.count); ++rt) {
1124 const auto& rendertarget = regs.rt[rt]; 1124 const auto& rendertarget = regs.rt[rt];
1125 if (rendertarget.Address() == 0 || rendertarget.format == Tegra::RenderTargetFormat::NONE) 1125 if (rendertarget.Address() == 0 || rendertarget.format == Tegra::RenderTargetFormat::NONE) {
1126 continue; 1126 continue;
1127 }
1127 renderpass_params.color_attachments.push_back(RenderPassParams::ColorAttachment{ 1128 renderpass_params.color_attachments.push_back(RenderPassParams::ColorAttachment{
1128 static_cast<u32>(rt), PixelFormatFromRenderTargetFormat(rendertarget.format), 1129 static_cast<u32>(rt), PixelFormatFromRenderTargetFormat(rendertarget.format),
1129 texceptions.test(rt)}); 1130 texceptions[rt]});
1130 } 1131 }
1131 1132
1132 renderpass_params.has_zeta = regs.zeta_enable; 1133 renderpass_params.has_zeta = regs.zeta_enable;
diff --git a/src/video_core/shader/decode/bfi.cpp b/src/video_core/shader/decode/bfi.cpp
index 8be1119df..f992bbe2a 100644
--- a/src/video_core/shader/decode/bfi.cpp
+++ b/src/video_core/shader/decode/bfi.cpp
@@ -17,10 +17,13 @@ u32 ShaderIR::DecodeBfi(NodeBlock& bb, u32 pc) {
17 const Instruction instr = {program_code[pc]}; 17 const Instruction instr = {program_code[pc]};
18 const auto opcode = OpCode::Decode(instr); 18 const auto opcode = OpCode::Decode(instr);
19 19
20 const auto [base, packed_shift] = [&]() -> std::tuple<Node, Node> { 20 const auto [packed_shift, base] = [&]() -> std::pair<Node, Node> {
21 switch (opcode->get().GetId()) { 21 switch (opcode->get().GetId()) {
22 case OpCode::Id::BFI_RC:
23 return {GetRegister(instr.gpr39),
24 GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset)};
22 case OpCode::Id::BFI_IMM_R: 25 case OpCode::Id::BFI_IMM_R:
23 return {GetRegister(instr.gpr39), Immediate(instr.alu.GetSignedImm20_20())}; 26 return {Immediate(instr.alu.GetSignedImm20_20()), GetRegister(instr.gpr39)};
24 default: 27 default:
25 UNREACHABLE(); 28 UNREACHABLE();
26 return {Immediate(0), Immediate(0)}; 29 return {Immediate(0), Immediate(0)};
diff --git a/src/video_core/shader/decode/shift.cpp b/src/video_core/shader/decode/shift.cpp
index d419e9c45..3b391d3e6 100644
--- a/src/video_core/shader/decode/shift.cpp
+++ b/src/video_core/shader/decode/shift.cpp
@@ -10,8 +10,80 @@
10 10
11namespace VideoCommon::Shader { 11namespace VideoCommon::Shader {
12 12
13using std::move;
13using Tegra::Shader::Instruction; 14using Tegra::Shader::Instruction;
14using Tegra::Shader::OpCode; 15using Tegra::Shader::OpCode;
16using Tegra::Shader::ShfType;
17using Tegra::Shader::ShfXmode;
18
19namespace {
20
21Node IsFull(Node shift) {
22 return Operation(OperationCode::LogicalIEqual, move(shift), Immediate(32));
23}
24
25Node Shift(OperationCode opcode, Node value, Node shift) {
26 Node is_full = Operation(OperationCode::LogicalIEqual, shift, Immediate(32));
27 Node shifted = Operation(opcode, move(value), shift);
28 return Operation(OperationCode::Select, IsFull(move(shift)), Immediate(0), move(shifted));
29}
30
31Node ClampShift(Node shift, s32 size = 32) {
32 shift = Operation(OperationCode::IMax, move(shift), Immediate(0));
33 return Operation(OperationCode::IMin, move(shift), Immediate(size));
34}
35
36Node WrapShift(Node shift, s32 size = 32) {
37 return Operation(OperationCode::UBitwiseAnd, move(shift), Immediate(size - 1));
38}
39
40Node ShiftRight(Node low, Node high, Node shift, Node low_shift, ShfType type) {
41 // These values are used when the shift value is less than 32
42 Node less_low = Shift(OperationCode::ILogicalShiftRight, low, shift);
43 Node less_high = Shift(OperationCode::ILogicalShiftLeft, high, low_shift);
44 Node less = Operation(OperationCode::IBitwiseOr, move(less_high), move(less_low));
45
46 if (type == ShfType::Bits32) {
47 // On 32 bit shifts we are either full (shifting 32) or shifting less than 32 bits
48 return Operation(OperationCode::Select, IsFull(move(shift)), move(high), move(less));
49 }
50
51 // And these when it's larger than or 32
52 const bool is_signed = type == ShfType::S64;
53 const auto opcode = SignedToUnsignedCode(OperationCode::IArithmeticShiftRight, is_signed);
54 Node reduced = Operation(OperationCode::IAdd, shift, Immediate(-32));
55 Node greater = Shift(opcode, high, move(reduced));
56
57 Node is_less = Operation(OperationCode::LogicalILessThan, shift, Immediate(32));
58 Node is_zero = Operation(OperationCode::LogicalIEqual, move(shift), Immediate(0));
59
60 Node value = Operation(OperationCode::Select, move(is_less), move(less), move(greater));
61 return Operation(OperationCode::Select, move(is_zero), move(high), move(value));
62}
63
64Node ShiftLeft(Node low, Node high, Node shift, Node low_shift, ShfType type) {
65 // These values are used when the shift value is less than 32
66 Node less_low = Operation(OperationCode::ILogicalShiftRight, low, low_shift);
67 Node less_high = Operation(OperationCode::ILogicalShiftLeft, high, shift);
68 Node less = Operation(OperationCode::IBitwiseOr, move(less_low), move(less_high));
69
70 if (type == ShfType::Bits32) {
71 // On 32 bit shifts we are either full (shifting 32) or shifting less than 32 bits
72 return Operation(OperationCode::Select, IsFull(move(shift)), move(low), move(less));
73 }
74
75 // And these when it's larger than or 32
76 Node reduced = Operation(OperationCode::IAdd, shift, Immediate(-32));
77 Node greater = Shift(OperationCode::ILogicalShiftLeft, move(low), move(reduced));
78
79 Node is_less = Operation(OperationCode::LogicalILessThan, shift, Immediate(32));
80 Node is_zero = Operation(OperationCode::LogicalIEqual, move(shift), Immediate(0));
81
82 Node value = Operation(OperationCode::Select, move(is_less), move(less), move(greater));
83 return Operation(OperationCode::Select, move(is_zero), move(high), move(value));
84}
85
86} // Anonymous namespace
15 87
16u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) { 88u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) {
17 const Instruction instr = {program_code[pc]}; 89 const Instruction instr = {program_code[pc]};
@@ -28,29 +100,48 @@ u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) {
28 } 100 }
29 }(); 101 }();
30 102
31 switch (opcode->get().GetId()) { 103 switch (const auto opid = opcode->get().GetId(); opid) {
32 case OpCode::Id::SHR_C: 104 case OpCode::Id::SHR_C:
33 case OpCode::Id::SHR_R: 105 case OpCode::Id::SHR_R:
34 case OpCode::Id::SHR_IMM: { 106 case OpCode::Id::SHR_IMM: {
35 if (instr.shr.wrap) { 107 op_b = instr.shr.wrap ? WrapShift(move(op_b)) : ClampShift(move(op_b));
36 op_b = Operation(OperationCode::UBitwiseAnd, std::move(op_b), Immediate(0x1f));
37 } else {
38 op_b = Operation(OperationCode::IMax, std::move(op_b), Immediate(0));
39 op_b = Operation(OperationCode::IMin, std::move(op_b), Immediate(31));
40 }
41 108
42 Node value = SignedOperation(OperationCode::IArithmeticShiftRight, instr.shift.is_signed, 109 Node value = SignedOperation(OperationCode::IArithmeticShiftRight, instr.shift.is_signed,
43 std::move(op_a), std::move(op_b)); 110 move(op_a), move(op_b));
44 SetInternalFlagsFromInteger(bb, value, instr.generates_cc); 111 SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
45 SetRegister(bb, instr.gpr0, std::move(value)); 112 SetRegister(bb, instr.gpr0, move(value));
46 break; 113 break;
47 } 114 }
48 case OpCode::Id::SHL_C: 115 case OpCode::Id::SHL_C:
49 case OpCode::Id::SHL_R: 116 case OpCode::Id::SHL_R:
50 case OpCode::Id::SHL_IMM: { 117 case OpCode::Id::SHL_IMM: {
51 const Node value = Operation(OperationCode::ILogicalShiftLeft, op_a, op_b); 118 Node value = Operation(OperationCode::ILogicalShiftLeft, op_a, op_b);
52 SetInternalFlagsFromInteger(bb, value, instr.generates_cc); 119 SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
53 SetRegister(bb, instr.gpr0, value); 120 SetRegister(bb, instr.gpr0, move(value));
121 break;
122 }
123 case OpCode::Id::SHF_RIGHT_R:
124 case OpCode::Id::SHF_RIGHT_IMM:
125 case OpCode::Id::SHF_LEFT_R:
126 case OpCode::Id::SHF_LEFT_IMM: {
127 UNIMPLEMENTED_IF(instr.generates_cc);
128 UNIMPLEMENTED_IF_MSG(instr.shf.xmode != ShfXmode::None, "xmode={}",
129 static_cast<int>(instr.shf.xmode.Value()));
130
131 if (instr.is_b_imm) {
132 op_b = Immediate(static_cast<u32>(instr.shf.immediate));
133 }
134 const s32 size = instr.shf.type == ShfType::Bits32 ? 32 : 64;
135 Node shift = instr.shf.wrap ? WrapShift(move(op_b), size) : ClampShift(move(op_b), size);
136
137 Node negated_shift = Operation(OperationCode::INegate, shift);
138 Node low_shift = Operation(OperationCode::IAdd, move(negated_shift), Immediate(32));
139
140 const bool is_right = opid == OpCode::Id::SHF_RIGHT_R || opid == OpCode::Id::SHF_RIGHT_IMM;
141 Node value = (is_right ? ShiftRight : ShiftLeft)(
142 move(op_a), GetRegister(instr.gpr39), move(shift), move(low_shift), instr.shf.type);
143
144 SetRegister(bb, instr.gpr0, move(value));
54 break; 145 break;
55 } 146 }
56 default: 147 default:
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 280d81ba9..cd94693c1 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -742,7 +742,6 @@ void Config::ReadUIValues() {
742void Config::ReadUIGamelistValues() { 742void Config::ReadUIGamelistValues() {
743 qt_config->beginGroup(QStringLiteral("UIGameList")); 743 qt_config->beginGroup(QStringLiteral("UIGameList"));
744 744
745 UISettings::values.show_unknown = ReadSetting(QStringLiteral("show_unknown"), true).toBool();
746 UISettings::values.show_add_ons = ReadSetting(QStringLiteral("show_add_ons"), true).toBool(); 745 UISettings::values.show_add_ons = ReadSetting(QStringLiteral("show_add_ons"), true).toBool();
747 UISettings::values.icon_size = ReadSetting(QStringLiteral("icon_size"), 64).toUInt(); 746 UISettings::values.icon_size = ReadSetting(QStringLiteral("icon_size"), 64).toUInt();
748 UISettings::values.row_1_text_id = ReadSetting(QStringLiteral("row_1_text_id"), 3).toUInt(); 747 UISettings::values.row_1_text_id = ReadSetting(QStringLiteral("row_1_text_id"), 3).toUInt();
@@ -1159,7 +1158,6 @@ void Config::SaveUIValues() {
1159void Config::SaveUIGamelistValues() { 1158void Config::SaveUIGamelistValues() {
1160 qt_config->beginGroup(QStringLiteral("UIGameList")); 1159 qt_config->beginGroup(QStringLiteral("UIGameList"));
1161 1160
1162 WriteSetting(QStringLiteral("show_unknown"), UISettings::values.show_unknown, true);
1163 WriteSetting(QStringLiteral("show_add_ons"), UISettings::values.show_add_ons, true); 1161 WriteSetting(QStringLiteral("show_add_ons"), UISettings::values.show_add_ons, true);
1164 WriteSetting(QStringLiteral("icon_size"), UISettings::values.icon_size, 64); 1162 WriteSetting(QStringLiteral("icon_size"), UISettings::values.icon_size, 64);
1165 WriteSetting(QStringLiteral("row_1_text_id"), UISettings::values.row_1_text_id, 3); 1163 WriteSetting(QStringLiteral("row_1_text_id"), UISettings::values.row_1_text_id, 3);
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index c4a84cc67..94424ee44 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -40,7 +40,6 @@ ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::Configur
40 SetConfiguration(); 40 SetConfiguration();
41 41
42 // Force game list reload if any of the relevant settings are changed. 42 // Force game list reload if any of the relevant settings are changed.
43 connect(ui->show_unknown, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
44 connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, 43 connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
45 &ConfigureUi::RequestGameListUpdate); 44 &ConfigureUi::RequestGameListUpdate);
46 connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, 45 connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
@@ -60,7 +59,6 @@ ConfigureUi::~ConfigureUi() = default;
60void ConfigureUi::ApplyConfiguration() { 59void ConfigureUi::ApplyConfiguration() {
61 UISettings::values.theme = 60 UISettings::values.theme =
62 ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); 61 ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
63 UISettings::values.show_unknown = ui->show_unknown->isChecked();
64 UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); 62 UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
65 UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt(); 63 UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
66 UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); 64 UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
@@ -74,7 +72,6 @@ void ConfigureUi::RequestGameListUpdate() {
74 72
75void ConfigureUi::SetConfiguration() { 73void ConfigureUi::SetConfiguration() {
76 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); 74 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
77 ui->show_unknown->setChecked(UISettings::values.show_unknown);
78 ui->show_add_ons->setChecked(UISettings::values.show_add_ons); 75 ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
79 ui->icon_size_combobox->setCurrentIndex( 76 ui->icon_size_combobox->setCurrentIndex(
80 ui->icon_size_combobox->findData(UISettings::values.icon_size)); 77 ui->icon_size_combobox->findData(UISettings::values.icon_size));
diff --git a/src/yuzu/configuration/configure_ui.ui b/src/yuzu/configuration/configure_ui.ui
index aa36bd112..bd5c5d3c2 100644
--- a/src/yuzu/configuration/configure_ui.ui
+++ b/src/yuzu/configuration/configure_ui.ui
@@ -52,13 +52,6 @@
52 <item> 52 <item>
53 <layout class="QVBoxLayout" name="GeneralVerticalLayout"> 53 <layout class="QVBoxLayout" name="GeneralVerticalLayout">
54 <item> 54 <item>
55 <widget class="QCheckBox" name="show_unknown">
56 <property name="text">
57 <string>Show files with type 'Unknown'</string>
58 </property>
59 </widget>
60 </item>
61 <item>
62 <widget class="QCheckBox" name="show_add_ons"> 55 <widget class="QCheckBox" name="show_add_ons">
63 <property name="text"> 56 <property name="text">
64 <string>Show Add-Ons Column</string> 57 <string>Show Add-Ons Column</string>
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 4c81ef12b..da2c27aa2 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -298,8 +298,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
298 } 298 }
299 299
300 const auto file_type = loader->GetFileType(); 300 const auto file_type = loader->GetFileType();
301 if ((file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) && 301 if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
302 !UISettings::values.show_unknown) {
303 return true; 302 return true;
304 } 303 }
305 304
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index bc7725a01..a675ecf4d 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -89,7 +89,6 @@ struct Values {
89 int profile_index; 89 int profile_index;
90 90
91 // Game List 91 // Game List
92 bool show_unknown;
93 bool show_add_ons; 92 bool show_add_ons;
94 uint32_t icon_size; 93 uint32_t icon_size;
95 uint8_t row_1_text_id; 94 uint8_t row_1_text_id;