summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-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) {
std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const {
std::vector<u8> buffer;
- const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()};
+ const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
+ BufferDescriptorA()[buffer_index].Size()};
auto& memory = Core::System::GetInstance().Memory();
if (is_buffer_a) {
+ ASSERT_MSG(BufferDescriptorA().size() > buffer_index,
+ "BufferDescriptorA invalid buffer_index {}", buffer_index);
buffer.resize(BufferDescriptorA()[buffer_index].Size());
memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size());
} else {
+ ASSERT_MSG(BufferDescriptorX().size() > buffer_index,
+ "BufferDescriptorX invalid buffer_index {}", buffer_index);
buffer.resize(BufferDescriptorX()[buffer_index].Size());
memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size());
}
@@ -305,7 +310,8 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
return 0;
}
- const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()};
+ const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
+ BufferDescriptorB()[buffer_index].Size()};
const std::size_t buffer_size{GetWriteBufferSize(buffer_index)};
if (size > buffer_size) {
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,
auto& memory = Core::System::GetInstance().Memory();
if (is_buffer_b) {
+ ASSERT_MSG(BufferDescriptorB().size() > buffer_index,
+ "BufferDescriptorB invalid buffer_index {}", buffer_index);
+ ASSERT_MSG(BufferDescriptorB()[buffer_index].Size() >= size,
+ "BufferDescriptorB buffer_index {} is not large enough", buffer_index);
memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
} else {
+ ASSERT_MSG(BufferDescriptorC().size() > buffer_index,
+ "BufferDescriptorC invalid buffer_index {}", buffer_index);
+ ASSERT_MSG(BufferDescriptorC()[buffer_index].Size() >= size,
+ "BufferDescriptorC buffer_index {} is not large enough", buffer_index);
memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
}
@@ -324,15 +338,35 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
}
std::size_t HLERequestContext::GetReadBufferSize(int buffer_index) const {
- const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()};
- return is_buffer_a ? BufferDescriptorA()[buffer_index].Size()
- : BufferDescriptorX()[buffer_index].Size();
+ const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
+ BufferDescriptorA()[buffer_index].Size()};
+ if (is_buffer_a) {
+ ASSERT_MSG(BufferDescriptorA().size() > buffer_index,
+ "BufferDescriptorA invalid buffer_index {}", buffer_index);
+ ASSERT_MSG(BufferDescriptorA()[buffer_index].Size() > 0,
+ "BufferDescriptorA buffer_index {} is empty", buffer_index);
+ return BufferDescriptorA()[buffer_index].Size();
+ } else {
+ ASSERT_MSG(BufferDescriptorX().size() > buffer_index,
+ "BufferDescriptorX invalid buffer_index {}", buffer_index);
+ ASSERT_MSG(BufferDescriptorX()[buffer_index].Size() > 0,
+ "BufferDescriptorX buffer_index {} is empty", buffer_index);
+ return BufferDescriptorX()[buffer_index].Size();
+ }
}
std::size_t HLERequestContext::GetWriteBufferSize(int buffer_index) const {
- const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()};
- return is_buffer_b ? BufferDescriptorB()[buffer_index].Size()
- : BufferDescriptorC()[buffer_index].Size();
+ const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
+ BufferDescriptorB()[buffer_index].Size()};
+ if (is_buffer_b) {
+ ASSERT_MSG(BufferDescriptorB().size() > buffer_index,
+ "BufferDescriptorB invalid buffer_index {}", buffer_index);
+ return BufferDescriptorB()[buffer_index].Size();
+ } else {
+ ASSERT_MSG(BufferDescriptorC().size() > buffer_index,
+ "BufferDescriptorC invalid buffer_index {}", buffer_index);
+ return BufferDescriptorC()[buffer_index].Size();
+ }
}
std::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
}
auto& kernel = system.Kernel();
- auto transfer_mem_handle = TransferMemory::Create(kernel, addr, size, perms);
+ auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms);
+
+ if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) {
+ return reserve_result;
+ }
auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
- const auto result = handle_table.Create(std::move(transfer_mem_handle));
+ const auto result{handle_table.Create(std::move(transfer_mem_handle))};
if (result.Failed()) {
return result.Code();
}
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 @@
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/transfer_memory.h"
#include "core/hle/result.h"
+#include "core/memory.h"
namespace Kernel {
-TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {}
-TransferMemory::~TransferMemory() = default;
+TransferMemory::TransferMemory(KernelCore& kernel, Memory::Memory& memory)
+ : Object{kernel}, memory{memory} {}
-std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address,
- u64 size, MemoryPermission permissions) {
- std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)};
+TransferMemory::~TransferMemory() {
+ // Release memory region when transfer memory is destroyed
+ Reset();
+}
+
+std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, Memory::Memory& memory,
+ VAddr base_address, u64 size,
+ MemoryPermission permissions) {
+ std::shared_ptr<TransferMemory> transfer_memory{
+ std::make_shared<TransferMemory>(kernel, memory)};
transfer_memory->base_address = base_address;
transfer_memory->memory_size = size;
@@ -27,7 +35,7 @@ std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr
}
const u8* TransferMemory::GetPointer() const {
- return backing_block.get()->data();
+ return memory.GetPointer(base_address);
}
u64 TransferMemory::GetSize() const {
@@ -62,6 +70,52 @@ ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission p
return RESULT_SUCCESS;
}
+ResultCode TransferMemory::Reserve() {
+ auto& vm_manager{owner_process->VMManager()};
+ const auto check_range_result{vm_manager.CheckRangeState(
+ base_address, memory_size, MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated,
+ MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::All,
+ VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None,
+ MemoryAttribute::IpcAndDeviceMapped)};
+
+ if (check_range_result.Failed()) {
+ return check_range_result.Code();
+ }
+
+ auto [state_, permissions_, attribute] = *check_range_result;
+
+ if (const auto result{vm_manager.ReprotectRange(
+ base_address, memory_size, SharedMemory::ConvertPermissions(owner_permissions))};
+ result.IsError()) {
+ return result;
+ }
+
+ return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask,
+ attribute | MemoryAttribute::Locked);
+}
+
+ResultCode TransferMemory::Reset() {
+ auto& vm_manager{owner_process->VMManager()};
+ if (const auto result{vm_manager.CheckRangeState(
+ base_address, memory_size,
+ MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated,
+ MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::None,
+ VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked,
+ MemoryAttribute::IpcAndDeviceMapped)};
+ result.Failed()) {
+ return result.Code();
+ }
+
+ if (const auto result{
+ vm_manager.ReprotectRange(base_address, memory_size, VMAPermission::ReadWrite)};
+ result.IsError()) {
+ return result;
+ }
+
+ return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask,
+ MemoryAttribute::None);
+}
+
ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) {
if (memory_size != size) {
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 @@
union ResultCode;
+namespace Memory {
+class Memory;
+}
+
namespace Kernel {
class KernelCore;
@@ -26,12 +30,13 @@ enum class MemoryPermission : u32;
///
class TransferMemory final : public Object {
public:
- explicit TransferMemory(KernelCore& kernel);
+ explicit TransferMemory(KernelCore& kernel, Memory::Memory& memory);
~TransferMemory() override;
static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
- static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size,
+ static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Memory::Memory& memory,
+ VAddr base_address, u64 size,
MemoryPermission permissions);
TransferMemory(const TransferMemory&) = delete;
@@ -80,6 +85,14 @@ public:
///
ResultCode UnmapMemory(VAddr address, u64 size);
+ /// Reserves the region to be used for the transfer memory, called after the transfer memory is
+ /// created.
+ ResultCode Reserve();
+
+ /// Resets the region previously used for the transfer memory, called after the transfer memory
+ /// is closed.
+ ResultCode Reset();
+
private:
/// Memory block backing this instance.
std::shared_ptr<PhysicalMemory> backing_block;
@@ -98,6 +111,8 @@ private:
/// Whether or not this transfer memory instance has mapped memory.
bool is_mapped = false;
+
+ Memory::Memory& memory;
};
} // 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 {
ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask,
MemoryAttribute attribute) {
- constexpr auto ignore_mask = MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped;
+ constexpr auto ignore_mask =
+ MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped | MemoryAttribute::Locked;
constexpr auto attribute_mask = ~ignore_mask;
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 {
DeviceMapped = 4,
/// Uncached memory
Uncached = 8,
+
+ IpcAndDeviceMapped = LockedForIPC | DeviceMapped,
};
constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) {
@@ -654,6 +656,35 @@ public:
/// is scheduled.
Common::PageTable page_table{Memory::PAGE_BITS};
+ using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>;
+
+ /// Checks if an address range adheres to the specified states provided.
+ ///
+ /// @param address The starting address of the address range.
+ /// @param size The size of the address range.
+ /// @param state_mask The memory state mask.
+ /// @param state The state to compare the individual VMA states against,
+ /// which is done in the form of: (vma.state & state_mask) != state.
+ /// @param permission_mask The memory permissions mask.
+ /// @param permissions The permission to compare the individual VMA permissions against,
+ /// which is done in the form of:
+ /// (vma.permission & permission_mask) != permission.
+ /// @param attribute_mask The memory attribute mask.
+ /// @param attribute The memory attributes to compare the individual VMA attributes
+ /// against, which is done in the form of:
+ /// (vma.attributes & attribute_mask) != attribute.
+ /// @param ignore_mask The memory attributes to ignore during the check.
+ ///
+ /// @returns If successful, returns a tuple containing the memory attributes
+ /// (with ignored bits specified by ignore_mask unset), memory permissions, and
+ /// memory state across the memory range.
+ /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE.
+ ///
+ CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state,
+ VMAPermission permission_mask, VMAPermission permissions,
+ MemoryAttribute attribute_mask, MemoryAttribute attribute,
+ MemoryAttribute ignore_mask) const;
+
private:
using VMAIter = VMAMap::iterator;
@@ -707,35 +738,6 @@ private:
/// Clears out the page table
void ClearPageTable();
- using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>;
-
- /// Checks if an address range adheres to the specified states provided.
- ///
- /// @param address The starting address of the address range.
- /// @param size The size of the address range.
- /// @param state_mask The memory state mask.
- /// @param state The state to compare the individual VMA states against,
- /// which is done in the form of: (vma.state & state_mask) != state.
- /// @param permission_mask The memory permissions mask.
- /// @param permissions The permission to compare the individual VMA permissions against,
- /// which is done in the form of:
- /// (vma.permission & permission_mask) != permission.
- /// @param attribute_mask The memory attribute mask.
- /// @param attribute The memory attributes to compare the individual VMA attributes
- /// against, which is done in the form of:
- /// (vma.attributes & attribute_mask) != attribute.
- /// @param ignore_mask The memory attributes to ignore during the check.
- ///
- /// @returns If successful, returns a tuple containing the memory attributes
- /// (with ignored bits specified by ignore_mask unset), memory permissions, and
- /// memory state across the memory range.
- /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE.
- ///
- CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state,
- VMAPermission permission_mask, VMAPermission permissions,
- MemoryAttribute attribute_mask, MemoryAttribute attribute,
- MemoryAttribute ignore_mask) const;
-
/// Gets the amount of memory currently mapped (state != Unmapped) in a range.
ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const;
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 {
if (ShouldWait(thread.get()))
continue;
- // A thread is ready to run if it's either in ThreadStatus::WaitSynch
- // and the rest of the objects it is waiting on are ready.
- bool ready_to_run = true;
- if (thread_status == ThreadStatus::WaitSynch) {
- ready_to_run = thread->AllWaitObjectsReady();
- }
-
- if (ready_to_run) {
- candidate = thread.get();
- candidate_priority = thread->GetPriority();
- }
+ candidate = thread.get();
+ candidate_priority = thread->GetPriority();
}
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) {
apm_sys->SetCpuBoostMode(ctx);
}
-IStorage::IStorage(std::vector<u8> buffer)
- : ServiceFramework("IStorage"), buffer(std::move(buffer)) {
+IStorageImpl::~IStorageImpl() = default;
+
+class StorageDataImpl final : public IStorageImpl {
+public:
+ explicit StorageDataImpl(std::vector<u8>&& buffer) : buffer{std::move(buffer)} {}
+
+ std::vector<u8>& GetData() override {
+ return buffer;
+ }
+
+ const std::vector<u8>& GetData() const override {
+ return buffer;
+ }
+
+ std::size_t GetSize() const override {
+ return buffer.size();
+ }
+
+private:
+ std::vector<u8> buffer;
+};
+
+IStorage::IStorage(std::vector<u8>&& buffer)
+ : ServiceFramework("IStorage"), impl{std::make_shared<StorageDataImpl>(std::move(buffer))} {
+ Register();
+}
+
+void IStorage::Register() {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IStorage::Open, "Open"},
@@ -723,8 +749,13 @@ IStorage::IStorage(std::vector<u8> buffer)
IStorage::~IStorage() = default;
-const std::vector<u8>& IStorage::GetData() const {
- return buffer;
+void IStorage::Open(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IStorageAccessor>(*this);
}
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
@@ -825,17 +856,16 @@ private:
void PopOutData(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-
const auto storage = applet->GetBroker().PopNormalDataToGame();
if (storage == nullptr) {
LOG_ERROR(Service_AM,
"storage is a nullptr. There is no data in the current normal channel");
-
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NO_DATA_IN_CHANNEL);
return;
}
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IStorage>(std::move(*storage));
}
@@ -857,17 +887,16 @@ private:
void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-
const auto storage = applet->GetBroker().PopInteractiveDataToGame();
if (storage == nullptr) {
LOG_ERROR(Service_AM,
"storage is a nullptr. There is no data in the current interactive channel");
-
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NO_DATA_IN_CHANNEL);
return;
}
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IStorage>(std::move(*storage));
}
@@ -891,15 +920,6 @@ private:
std::shared_ptr<Applets::Applet> applet;
};
-void IStorage::Open(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_AM, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-
- rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IStorageAccessor>(*this);
-}
-
IStorageAccessor::IStorageAccessor(IStorage& storage)
: ServiceFramework("IStorageAccessor"), backing(storage) {
// clang-format off
@@ -921,7 +941,7 @@ void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u64>(backing.buffer.size()));
+ rb.Push(static_cast<u64>(backing.GetSize()));
}
void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
@@ -932,17 +952,17 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size());
- if (data.size() > backing.buffer.size() - offset) {
+ if (data.size() > backing.GetSize() - offset) {
LOG_ERROR(Service_AM,
"offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
- backing.buffer.size(), data.size(), offset);
+ backing.GetSize(), data.size(), offset);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
return;
}
- std::memcpy(backing.buffer.data() + offset, data.data(), data.size());
+ std::memcpy(backing.GetData().data() + offset, data.data(), data.size());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -956,16 +976,16 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
- if (size > backing.buffer.size() - offset) {
+ if (size > backing.GetSize() - offset) {
LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
- backing.buffer.size(), size, offset);
+ backing.GetSize(), size, offset);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
return;
}
- ctx.WriteBuffer(backing.buffer.data() + offset, size);
+ ctx.WriteBuffer(backing.GetData().data() + offset, size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -1031,7 +1051,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
rp.SetCurrentOffset(3);
const auto handle{rp.Pop<Kernel::Handle>()};
- const auto transfer_mem =
+ auto transfer_mem =
system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
if (transfer_mem == nullptr) {
@@ -1047,7 +1067,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory)));
+ rb.PushIpcInterface<IStorage>(std::move(memory));
}
IApplicationFunctions::IApplicationFunctions(Core::System& system_)
@@ -1189,13 +1209,11 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
u64 build_id{};
std::memcpy(&build_id, build_id_full.data(), sizeof(u64));
- const auto data =
- backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id});
-
+ auto data = backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id});
if (data.has_value()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<AM::IStorage>(*data);
+ rb.PushIpcInterface<IStorage>(std::move(*data));
launch_popped_application_specific = true;
return;
}
@@ -1218,7 +1236,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
std::memcpy(buffer.data(), &params, buffer.size());
- rb.PushIpcInterface<AM::IStorage>(buffer);
+ rb.PushIpcInterface<IStorage>(std::move(buffer));
launch_popped_account_preselect = true;
return;
}
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 @@
namespace Kernel {
class KernelCore;
-}
+class TransferMemory;
+} // namespace Kernel
namespace Service::NVFlinger {
class NVFlinger;
@@ -188,19 +189,36 @@ private:
std::shared_ptr<AppletMessageQueue> msg_queue;
};
+class IStorageImpl {
+public:
+ virtual ~IStorageImpl();
+ virtual std::vector<u8>& GetData() = 0;
+ virtual const std::vector<u8>& GetData() const = 0;
+ virtual std::size_t GetSize() const = 0;
+};
+
class IStorage final : public ServiceFramework<IStorage> {
public:
- explicit IStorage(std::vector<u8> buffer);
+ explicit IStorage(std::vector<u8>&& buffer);
~IStorage() override;
- const std::vector<u8>& GetData() const;
+ std::vector<u8>& GetData() {
+ return impl->GetData();
+ }
+
+ const std::vector<u8>& GetData() const {
+ return impl->GetData();
+ }
+
+ std::size_t GetSize() const {
+ return impl->GetSize();
+ }
private:
+ void Register();
void Open(Kernel::HLERequestContext& ctx);
- std::vector<u8> buffer;
-
- friend class IStorageAccessor;
+ std::shared_ptr<IStorageImpl> impl;
};
class 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() {
auto out = std::move(out_channel.front());
out_channel.pop_front();
+ pop_out_data_event.writable->Clear();
return out;
}
@@ -74,6 +75,7 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
auto out = std::move(out_interactive_channel.front());
out_interactive_channel.pop_front();
+ pop_interactive_out_data_event.writable->Clear();
return out;
}
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() {
void Error::DisplayCompleted() {
complete = true;
- broker.PushNormalDataFromApplet(IStorage{{}});
+ broker.PushNormalDataFromApplet(IStorage{std::vector<u8>{}});
broker.SignalStateChanged();
}
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) {
std::vector<u8> out(sizeof(Return));
std::memcpy(out.data(), &return_, sizeof(Return));
- broker.PushNormalDataFromApplet(IStorage{out});
+ broker.PushNormalDataFromApplet(IStorage{std::move(out)});
broker.SignalStateChanged();
}
@@ -198,7 +198,7 @@ void PhotoViewer::Execute() {
}
void PhotoViewer::ViewFinished() {
- broker.PushNormalDataFromApplet(IStorage{{}});
+ broker.PushNormalDataFromApplet(IStorage{std::vector<u8>{}});
broker.SignalStateChanged();
}
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() {
void ProfileSelect::Execute() {
if (complete) {
- broker.PushNormalDataFromApplet(IStorage{final_data});
+ broker.PushNormalDataFromApplet(IStorage{std::move(final_data)});
return;
}
@@ -71,7 +71,7 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
final_data = std::vector<u8>(sizeof(UserSelectionOutput));
std::memcpy(final_data.data(), &output, final_data.size());
- broker.PushNormalDataFromApplet(IStorage{final_data});
+ broker.PushNormalDataFromApplet(IStorage{std::move(final_data)});
broker.SignalStateChanged();
}
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() {
void SoftwareKeyboard::Execute() {
if (complete) {
- broker.PushNormalDataFromApplet(IStorage{final_data});
+ broker.PushNormalDataFromApplet(IStorage{std::move(final_data)});
+ broker.SignalStateChanged();
return;
}
@@ -119,7 +120,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE);
if (config.utf_8) {
- const u64 size = text->size() + 8;
+ const u64 size = text->size() + sizeof(u64);
const auto new_text = Common::UTF16ToUTF8(*text);
std::memcpy(output_sub.data(), &size, sizeof(u64));
@@ -130,7 +131,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
std::memcpy(output_main.data() + 4, new_text.data(),
std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4));
} else {
- const u64 size = text->size() * 2 + 8;
+ const u64 size = text->size() * 2 + sizeof(u64);
std::memcpy(output_sub.data(), &size, sizeof(u64));
std::memcpy(output_sub.data() + 8, text->data(),
std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8));
@@ -144,15 +145,15 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
final_data = output_main;
if (complete) {
- broker.PushNormalDataFromApplet(IStorage{output_main});
+ broker.PushNormalDataFromApplet(IStorage{std::move(output_main)});
broker.SignalStateChanged();
} else {
- broker.PushInteractiveDataFromApplet(IStorage{output_sub});
+ broker.PushInteractiveDataFromApplet(IStorage{std::move(output_sub)});
}
} else {
output_main[0] = 1;
complete = true;
- broker.PushNormalDataFromApplet(IStorage{output_main});
+ broker.PushNormalDataFromApplet(IStorage{std::move(output_main)});
broker.SignalStateChanged();
}
}
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() {
std::vector<u8> data(sizeof(WebCommonReturnValue));
std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue));
- broker.PushNormalDataFromApplet(IStorage{data});
+ broker.PushNormalDataFromApplet(IStorage{std::move(data)});
broker.SignalStateChanged();
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:
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
- const auto data1 = ctx.ReadBuffer(0);
- const auto data2 = ctx.ReadBuffer(1);
+ std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)};
+ if (Type == Core::Reporter::PlayReportType::New) {
+ data.emplace_back(ctx.ReadBuffer(1));
+ }
- LOG_DEBUG(Service_PREPO,
- "called, type={:02X}, process_id={:016X}, data1_size={:016X}, data2_size={:016X}",
- static_cast<u8>(Type), process_id, data1.size(), data2.size());
+ LOG_DEBUG(Service_PREPO, "called, type={:02X}, process_id={:016X}, data1_size={:016X}",
+ static_cast<u8>(Type), process_id, data[0].size());
const auto& reporter{system.GetReporter()};
- reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2},
- process_id);
+ reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -70,19 +70,19 @@ private:
IPC::RequestParser rp{ctx};
const auto user_id = rp.PopRaw<u128>();
const auto process_id = rp.PopRaw<u64>();
-
- const auto data1 = ctx.ReadBuffer(0);
- const auto data2 = ctx.ReadBuffer(1);
+ std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)};
+ if (Type == Core::Reporter::PlayReportType::New) {
+ data.emplace_back(ctx.ReadBuffer(1));
+ }
LOG_DEBUG(
Service_PREPO,
- "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}, "
- "data2_size={:016X}",
- static_cast<u8>(Type), user_id[1], user_id[0], process_id, data1.size(), data2.size());
+ "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}",
+ static_cast<u8>(Type), user_id[1], user_id[0], process_id, data[0].size());
const auto& reporter{system.GetReporter()};
- reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2},
- process_id, user_id);
+ reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id,
+ user_id);
IPC::ResponseBuilder rb{ctx, 2};
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 {
Bfly = 3, // shuffleXorNV
};
+enum class ShfType : u64 {
+ Bits32 = 0,
+ U64 = 2,
+ S64 = 3,
+};
+
+enum class ShfXmode : u64 {
+ None = 0,
+ HI = 1,
+ X = 2,
+ XHI = 3,
+};
+
union Instruction {
constexpr Instruction& operator=(const Instruction& instr) {
value = instr.value;
@@ -776,6 +789,13 @@ union Instruction {
} shr;
union {
+ BitField<37, 2, ShfType> type;
+ BitField<48, 2, ShfXmode> xmode;
+ BitField<50, 1, u64> wrap;
+ BitField<20, 6, u64> immediate;
+ } shf;
+
+ union {
BitField<39, 5, u64> shift_amount;
BitField<48, 1, u64> negate_b;
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) {
}
GLintptr RasterizerOpenGL::SetupIndexBuffer() {
- if (accelerate_draw != AccelDraw::Indexed) {
- return 0;
- }
MICROPROFILE_SCOPE(OpenGL_Index);
const auto& regs = system.GPU().Maxwell3D().regs;
const std::size_t size = CalculateIndexBufferSize();
@@ -546,7 +543,8 @@ void RasterizerOpenGL::Clear() {
}
}
-void RasterizerOpenGL::DrawPrelude() {
+void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
+ MICROPROFILE_SCOPE(OpenGL_Drawing);
auto& gpu = system.GPU().Maxwell3D();
SyncRasterizeEnable(state);
@@ -567,9 +565,6 @@ void RasterizerOpenGL::DrawPrelude() {
buffer_cache.Acquire();
- // Draw the vertex batch
- const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
-
std::size_t buffer_size = CalculateVertexArraysSize();
// Add space for index buffer
@@ -596,7 +591,11 @@ void RasterizerOpenGL::DrawPrelude() {
// Upload vertex and index data.
SetupVertexBuffer(vao);
SetupVertexInstances(vao);
- index_buffer_offset = SetupIndexBuffer();
+
+ GLintptr index_buffer_offset;
+ if (is_indexed) {
+ index_buffer_offset = SetupIndexBuffer();
+ }
// Prepare packed bindings.
bind_ubo_pushbuffer.Setup();
@@ -630,6 +629,7 @@ void RasterizerOpenGL::DrawPrelude() {
// As all cached buffers are invalidated, we need to recheck their state.
gpu.dirty.ResetVertexArrays();
}
+ gpu.dirty.memory_general = false;
shader_program_manager->ApplyTo(state);
state.Apply();
@@ -637,106 +637,33 @@ void RasterizerOpenGL::DrawPrelude() {
if (texture_cache.TextureBarrier()) {
glTextureBarrier();
}
-}
-
-struct DrawParams {
- bool is_indexed{};
- bool is_instanced{};
- GLenum primitive_mode{};
- GLint count{};
- GLint base_vertex{};
-
- // Indexed settings
- GLenum index_format{};
- GLintptr index_buffer_offset{};
-
- // Instanced setting
- GLint num_instances{};
- GLint base_instance{};
-
- void DispatchDraw() {
- if (is_indexed) {
- const auto index_buffer_ptr = reinterpret_cast<const void*>(index_buffer_offset);
- if (is_instanced) {
- glDrawElementsInstancedBaseVertexBaseInstance(primitive_mode, count, index_format,
- index_buffer_ptr, num_instances,
- base_vertex, base_instance);
- } else {
- glDrawElementsBaseVertex(primitive_mode, count, index_format, index_buffer_ptr,
- base_vertex);
- }
- } else {
- if (is_instanced) {
- glDrawArraysInstancedBaseInstance(primitive_mode, base_vertex, count, num_instances,
- base_instance);
- } else {
- glDrawArrays(primitive_mode, base_vertex, count);
- }
- }
- }
-};
-
-bool RasterizerOpenGL::DrawBatch(bool is_indexed) {
- accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
- MICROPROFILE_SCOPE(OpenGL_Drawing);
-
- DrawPrelude();
-
- auto& maxwell3d = system.GPU().Maxwell3D();
- const auto& regs = maxwell3d.regs;
- const auto current_instance = maxwell3d.state.current_instance;
- DrawParams draw_call{};
- draw_call.is_indexed = is_indexed;
- draw_call.num_instances = static_cast<GLint>(1);
- draw_call.base_instance = static_cast<GLint>(current_instance);
- draw_call.is_instanced = current_instance > 0;
- draw_call.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
- if (draw_call.is_indexed) {
- draw_call.count = static_cast<GLint>(regs.index_array.count);
- draw_call.base_vertex = static_cast<GLint>(regs.vb_element_base);
- draw_call.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
- draw_call.index_buffer_offset = index_buffer_offset;
+ const GLuint base_instance = static_cast<GLuint>(gpu.regs.vb_base_instance);
+ const GLsizei num_instances =
+ static_cast<GLsizei>(is_instanced ? gpu.mme_draw.instance_count : 1);
+ if (is_indexed) {
+ const GLenum index_format = MaxwellToGL::IndexFormat(gpu.regs.index_array.format);
+ const GLint base_vertex = static_cast<GLint>(gpu.regs.vb_element_base);
+ const GLsizei num_vertices = static_cast<GLsizei>(gpu.regs.index_array.count);
+ glDrawElementsInstancedBaseVertexBaseInstance(
+ primitive_mode, num_vertices, index_format,
+ reinterpret_cast<const void*>(index_buffer_offset), num_instances, base_vertex,
+ base_instance);
} else {
- draw_call.count = static_cast<GLint>(regs.vertex_buffer.count);
- draw_call.base_vertex = static_cast<GLint>(regs.vertex_buffer.first);
+ const GLint base_vertex = static_cast<GLint>(gpu.regs.vertex_buffer.first);
+ const GLsizei num_vertices = static_cast<GLsizei>(gpu.regs.vertex_buffer.count);
+ glDrawArraysInstancedBaseInstance(primitive_mode, base_vertex, num_vertices, num_instances,
+ base_instance);
}
- draw_call.DispatchDraw();
+}
- maxwell3d.dirty.memory_general = false;
- accelerate_draw = AccelDraw::Disabled;
+bool RasterizerOpenGL::DrawBatch(bool is_indexed) {
+ Draw(is_indexed, false);
return true;
}
bool RasterizerOpenGL::DrawMultiBatch(bool is_indexed) {
- accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
-
- MICROPROFILE_SCOPE(OpenGL_Drawing);
-
- DrawPrelude();
-
- auto& maxwell3d = system.GPU().Maxwell3D();
- const auto& regs = maxwell3d.regs;
- const auto& draw_setup = maxwell3d.mme_draw;
- DrawParams draw_call{};
- draw_call.is_indexed = is_indexed;
- draw_call.num_instances = static_cast<GLint>(draw_setup.instance_count);
- draw_call.base_instance = static_cast<GLint>(regs.vb_base_instance);
- draw_call.is_instanced = draw_setup.instance_count > 1;
- draw_call.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
- if (draw_call.is_indexed) {
- draw_call.count = static_cast<GLint>(regs.index_array.count);
- draw_call.base_vertex = static_cast<GLint>(regs.vb_element_base);
- draw_call.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
- draw_call.index_buffer_offset = index_buffer_offset;
- } else {
- draw_call.count = static_cast<GLint>(regs.vertex_buffer.count);
- draw_call.base_vertex = static_cast<GLint>(regs.vertex_buffer.first);
- }
- draw_call.DispatchDraw();
-
- maxwell3d.dirty.memory_general = false;
- accelerate_draw = AccelDraw::Disabled;
+ Draw(is_indexed, true);
return true;
}
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:
std::size_t size);
/// Syncs all the state, shaders, render targets and textures setting before a draw call.
- void DrawPrelude();
+ void Draw(bool is_indexed, bool is_instanced);
/// Configures the current textures to use for the draw command.
void SetupDrawTextures(std::size_t stage_index, const Shader& shader);
@@ -220,12 +220,7 @@ private:
GLintptr SetupIndexBuffer();
- GLintptr index_buffer_offset;
-
void SetupShaders(GLenum primitive_mode);
-
- enum class AccelDraw { Disabled, Arrays, Indexed };
- AccelDraw accelerate_draw = AccelDraw::Disabled;
};
} // 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 @@
namespace VideoCommon::Shader {
+using std::move;
using Tegra::Shader::Instruction;
using Tegra::Shader::OpCode;
+using Tegra::Shader::ShfType;
+using Tegra::Shader::ShfXmode;
+
+namespace {
+
+Node IsFull(Node shift) {
+ return Operation(OperationCode::LogicalIEqual, move(shift), Immediate(32));
+}
+
+Node Shift(OperationCode opcode, Node value, Node shift) {
+ Node is_full = Operation(OperationCode::LogicalIEqual, shift, Immediate(32));
+ Node shifted = Operation(opcode, move(value), shift);
+ return Operation(OperationCode::Select, IsFull(move(shift)), Immediate(0), move(shifted));
+}
+
+Node ClampShift(Node shift, s32 size = 32) {
+ shift = Operation(OperationCode::IMax, move(shift), Immediate(0));
+ return Operation(OperationCode::IMin, move(shift), Immediate(size));
+}
+
+Node WrapShift(Node shift, s32 size = 32) {
+ return Operation(OperationCode::UBitwiseAnd, move(shift), Immediate(size - 1));
+}
+
+Node ShiftRight(Node low, Node high, Node shift, Node low_shift, ShfType type) {
+ // These values are used when the shift value is less than 32
+ Node less_low = Shift(OperationCode::ILogicalShiftRight, low, shift);
+ Node less_high = Shift(OperationCode::ILogicalShiftLeft, high, low_shift);
+ Node less = Operation(OperationCode::IBitwiseOr, move(less_high), move(less_low));
+
+ if (type == ShfType::Bits32) {
+ // On 32 bit shifts we are either full (shifting 32) or shifting less than 32 bits
+ return Operation(OperationCode::Select, IsFull(move(shift)), move(high), move(less));
+ }
+
+ // And these when it's larger than or 32
+ const bool is_signed = type == ShfType::S64;
+ const auto opcode = SignedToUnsignedCode(OperationCode::IArithmeticShiftRight, is_signed);
+ Node reduced = Operation(OperationCode::IAdd, shift, Immediate(-32));
+ Node greater = Shift(opcode, high, move(reduced));
+
+ Node is_less = Operation(OperationCode::LogicalILessThan, shift, Immediate(32));
+ Node is_zero = Operation(OperationCode::LogicalIEqual, move(shift), Immediate(0));
+
+ Node value = Operation(OperationCode::Select, move(is_less), move(less), move(greater));
+ return Operation(OperationCode::Select, move(is_zero), move(high), move(value));
+}
+
+Node ShiftLeft(Node low, Node high, Node shift, Node low_shift, ShfType type) {
+ // These values are used when the shift value is less than 32
+ Node less_low = Operation(OperationCode::ILogicalShiftRight, low, low_shift);
+ Node less_high = Operation(OperationCode::ILogicalShiftLeft, high, shift);
+ Node less = Operation(OperationCode::IBitwiseOr, move(less_low), move(less_high));
+
+ if (type == ShfType::Bits32) {
+ // On 32 bit shifts we are either full (shifting 32) or shifting less than 32 bits
+ return Operation(OperationCode::Select, IsFull(move(shift)), move(low), move(less));
+ }
+
+ // And these when it's larger than or 32
+ Node reduced = Operation(OperationCode::IAdd, shift, Immediate(-32));
+ Node greater = Shift(OperationCode::ILogicalShiftLeft, move(low), move(reduced));
+
+ Node is_less = Operation(OperationCode::LogicalILessThan, shift, Immediate(32));
+ Node is_zero = Operation(OperationCode::LogicalIEqual, move(shift), Immediate(0));
+
+ Node value = Operation(OperationCode::Select, move(is_less), move(less), move(greater));
+ return Operation(OperationCode::Select, move(is_zero), move(high), move(value));
+}
+
+} // Anonymous namespace
u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) {
const Instruction instr = {program_code[pc]};
@@ -28,29 +100,48 @@ u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) {
}
}();
- switch (opcode->get().GetId()) {
+ switch (const auto opid = opcode->get().GetId(); opid) {
case OpCode::Id::SHR_C:
case OpCode::Id::SHR_R:
case OpCode::Id::SHR_IMM: {
- if (instr.shr.wrap) {
- op_b = Operation(OperationCode::UBitwiseAnd, std::move(op_b), Immediate(0x1f));
- } else {
- op_b = Operation(OperationCode::IMax, std::move(op_b), Immediate(0));
- op_b = Operation(OperationCode::IMin, std::move(op_b), Immediate(31));
- }
+ op_b = instr.shr.wrap ? WrapShift(move(op_b)) : ClampShift(move(op_b));
Node value = SignedOperation(OperationCode::IArithmeticShiftRight, instr.shift.is_signed,
- std::move(op_a), std::move(op_b));
+ move(op_a), move(op_b));
SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
- SetRegister(bb, instr.gpr0, std::move(value));
+ SetRegister(bb, instr.gpr0, move(value));
break;
}
case OpCode::Id::SHL_C:
case OpCode::Id::SHL_R:
case OpCode::Id::SHL_IMM: {
- const Node value = Operation(OperationCode::ILogicalShiftLeft, op_a, op_b);
+ Node value = Operation(OperationCode::ILogicalShiftLeft, op_a, op_b);
SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
- SetRegister(bb, instr.gpr0, value);
+ SetRegister(bb, instr.gpr0, move(value));
+ break;
+ }
+ case OpCode::Id::SHF_RIGHT_R:
+ case OpCode::Id::SHF_RIGHT_IMM:
+ case OpCode::Id::SHF_LEFT_R:
+ case OpCode::Id::SHF_LEFT_IMM: {
+ UNIMPLEMENTED_IF(instr.generates_cc);
+ UNIMPLEMENTED_IF_MSG(instr.shf.xmode != ShfXmode::None, "xmode={}",
+ static_cast<int>(instr.shf.xmode.Value()));
+
+ if (instr.is_b_imm) {
+ op_b = Immediate(static_cast<u32>(instr.shf.immediate));
+ }
+ const s32 size = instr.shf.type == ShfType::Bits32 ? 32 : 64;
+ Node shift = instr.shf.wrap ? WrapShift(move(op_b), size) : ClampShift(move(op_b), size);
+
+ Node negated_shift = Operation(OperationCode::INegate, shift);
+ Node low_shift = Operation(OperationCode::IAdd, move(negated_shift), Immediate(32));
+
+ const bool is_right = opid == OpCode::Id::SHF_RIGHT_R || opid == OpCode::Id::SHF_RIGHT_IMM;
+ Node value = (is_right ? ShiftRight : ShiftLeft)(
+ move(op_a), GetRegister(instr.gpr39), move(shift), move(low_shift), instr.shf.type);
+
+ SetRegister(bb, instr.gpr0, move(value));
break;
}
default: