summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.cpp84
-rw-r--r--src/core/hle/service/am/am.h30
-rw-r--r--src/core/hle/service/am/applets/applets.cpp2
-rw-r--r--src/core/hle/service/am/applets/error.cpp2
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp4
-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/prepo/prepo.cpp30
-rw-r--r--src/video_core/engines/shader_bytecode.h20
-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/shader/decode/shift.cpp113
20 files changed, 415 insertions, 242 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..c1550013a 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) {
@@ -825,17 +856,16 @@ 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 }
@@ -857,17 +887,16 @@ 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 }
@@ -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..3e97ba218 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -56,6 +56,7 @@ std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
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
@@ -74,6 +75,7 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
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
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp
index eab0d42c9..e6c4e8b87 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(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..fe8400a15 100644
--- a/src/core/hle/service/am/applets/general_backend.cpp
+++ b/src/core/hle/service/am/applets/general_backend.cpp
@@ -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(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(IStorage{std::vector<u8>{}});
202 broker.SignalStateChanged(); 202 broker.SignalStateChanged();
203} 203}
204 204
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp
index 3eba696ca..91d00f72a 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(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(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..964c67202 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(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(IStorage{std::move(output_main)});
148 broker.SignalStateChanged(); 149 broker.SignalStateChanged();
149 } else { 150 } else {
150 broker.PushInteractiveDataFromApplet(IStorage{output_sub}); 151 broker.PushInteractiveDataFromApplet(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(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..05d6b3a19 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(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/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/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 81b6d9eff..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;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 362942e09..46a7433ea 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/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: