Compare commits
33 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b80c348b09 | ||
|
|
37f1cf8cbd | ||
|
|
84ea9c2b42 | ||
|
|
21c3f48279 | ||
|
|
fcf3425b1b | ||
|
|
a952fbc5b3 | ||
|
|
e210835dd0 | ||
|
|
6536cc9741 | ||
|
|
7b07e521ca | ||
|
|
b5c13ee0eb | ||
|
|
7cacb08cdf | ||
|
|
90bda66028 | ||
|
|
90df4b8e2b | ||
|
|
aa3f9b9606 | ||
|
|
09d766d357 | ||
|
|
1b01c3036d | ||
|
|
ba53543da6 | ||
|
|
7a547b9342 | ||
|
|
3a0c1e79f8 | ||
|
|
77da74e17a | ||
|
|
84e895cdd6 | ||
|
|
3557fa25d0 | ||
|
|
be5fcffb89 | ||
|
|
2245c24e21 | ||
|
|
9751ccc5e0 | ||
|
|
8bb9eef97b | ||
|
|
c81c361e82 | ||
|
|
a0b4be4262 | ||
|
|
7da52673d0 | ||
|
|
4eed744277 | ||
|
|
729ca120e3 | ||
|
|
017474c3f8 | ||
|
|
b69321650e |
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -474,7 +474,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
|
||||
if (GetSchedulingStatus() != ThreadSchedStatus::Runnable) {
|
||||
return;
|
||||
}
|
||||
auto& scheduler = Core::System::GetInstance().GlobalScheduler();
|
||||
auto& scheduler = kernel.GlobalScheduler();
|
||||
if (processor_id >= 0) {
|
||||
scheduler.Unschedule(old_priority, static_cast<u32>(processor_id), this);
|
||||
}
|
||||
@@ -506,7 +506,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
|
||||
}
|
||||
|
||||
void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) {
|
||||
auto& scheduler = Core::System::GetInstance().GlobalScheduler();
|
||||
auto& scheduler = kernel.GlobalScheduler();
|
||||
if (GetSchedulingStatus() != ThreadSchedStatus::Runnable ||
|
||||
current_priority >= THREADPRIO_COUNT) {
|
||||
return;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
@@ -816,7 +847,7 @@ private:
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
|
||||
applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -825,26 +856,25 @@ 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));
|
||||
rb.PushIpcInterface<IStorage>(std::move(storage));
|
||||
}
|
||||
|
||||
void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
|
||||
applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>());
|
||||
|
||||
ASSERT(applet->IsInitialized());
|
||||
applet->ExecuteInteractive();
|
||||
@@ -857,19 +887,18 @@ 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));
|
||||
rb.PushIpcInterface<IStorage>(std::move(storage));
|
||||
}
|
||||
|
||||
void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
|
||||
@@ -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(), ¶ms, buffer.size());
|
||||
|
||||
rb.PushIpcInterface<AM::IStorage>(buffer);
|
||||
rb.PushIpcInterface<IStorage>(std::move(buffer));
|
||||
launch_popped_account_preselect = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -50,16 +50,17 @@ AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() co
|
||||
return {std::move(out_normal), std::move(out_interactive)};
|
||||
}
|
||||
|
||||
std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
|
||||
std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
|
||||
if (out_channel.empty())
|
||||
return nullptr;
|
||||
|
||||
auto out = std::move(out_channel.front());
|
||||
out_channel.pop_front();
|
||||
pop_out_data_event.writable->Clear();
|
||||
return out;
|
||||
}
|
||||
|
||||
std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
|
||||
std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
|
||||
if (in_channel.empty())
|
||||
return nullptr;
|
||||
|
||||
@@ -68,16 +69,17 @@ std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
|
||||
std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
|
||||
if (out_interactive_channel.empty())
|
||||
return nullptr;
|
||||
|
||||
auto out = std::move(out_interactive_channel.front());
|
||||
out_interactive_channel.pop_front();
|
||||
pop_interactive_out_data_event.writable->Clear();
|
||||
return out;
|
||||
}
|
||||
|
||||
std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
|
||||
std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
|
||||
if (in_interactive_channel.empty())
|
||||
return nullptr;
|
||||
|
||||
@@ -86,21 +88,21 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
|
||||
return out;
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
|
||||
in_channel.push_back(std::make_unique<IStorage>(storage));
|
||||
void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage) {
|
||||
in_channel.emplace_back(std::move(storage));
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
|
||||
out_channel.push_back(std::make_unique<IStorage>(storage));
|
||||
void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
|
||||
out_channel.emplace_back(std::move(storage));
|
||||
pop_out_data_event.writable->Signal();
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
|
||||
in_interactive_channel.push_back(std::make_unique<IStorage>(storage));
|
||||
void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
|
||||
in_interactive_channel.emplace_back(std::move(storage));
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
|
||||
out_interactive_channel.push_back(std::make_unique<IStorage>(storage));
|
||||
void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
|
||||
out_interactive_channel.emplace_back(std::move(storage));
|
||||
pop_interactive_out_data_event.writable->Signal();
|
||||
}
|
||||
|
||||
|
||||
@@ -72,17 +72,17 @@ public:
|
||||
// Retrieves but does not pop the data sent to applet.
|
||||
RawChannelData PeekDataToAppletForDebug() const;
|
||||
|
||||
std::unique_ptr<IStorage> PopNormalDataToGame();
|
||||
std::unique_ptr<IStorage> PopNormalDataToApplet();
|
||||
std::shared_ptr<IStorage> PopNormalDataToGame();
|
||||
std::shared_ptr<IStorage> PopNormalDataToApplet();
|
||||
|
||||
std::unique_ptr<IStorage> PopInteractiveDataToGame();
|
||||
std::unique_ptr<IStorage> PopInteractiveDataToApplet();
|
||||
std::shared_ptr<IStorage> PopInteractiveDataToGame();
|
||||
std::shared_ptr<IStorage> PopInteractiveDataToApplet();
|
||||
|
||||
void PushNormalDataFromGame(IStorage storage);
|
||||
void PushNormalDataFromApplet(IStorage storage);
|
||||
void PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage);
|
||||
void PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage);
|
||||
|
||||
void PushInteractiveDataFromGame(IStorage storage);
|
||||
void PushInteractiveDataFromApplet(IStorage storage);
|
||||
void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage);
|
||||
void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage);
|
||||
|
||||
void SignalStateChanged() const;
|
||||
|
||||
@@ -94,16 +94,16 @@ private:
|
||||
// Queues are named from applet's perspective
|
||||
|
||||
// PopNormalDataToApplet and PushNormalDataFromGame
|
||||
std::deque<std::unique_ptr<IStorage>> in_channel;
|
||||
std::deque<std::shared_ptr<IStorage>> in_channel;
|
||||
|
||||
// PopNormalDataToGame and PushNormalDataFromApplet
|
||||
std::deque<std::unique_ptr<IStorage>> out_channel;
|
||||
std::deque<std::shared_ptr<IStorage>> out_channel;
|
||||
|
||||
// PopInteractiveDataToApplet and PushInteractiveDataFromGame
|
||||
std::deque<std::unique_ptr<IStorage>> in_interactive_channel;
|
||||
std::deque<std::shared_ptr<IStorage>> in_interactive_channel;
|
||||
|
||||
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
|
||||
std::deque<std::unique_ptr<IStorage>> out_interactive_channel;
|
||||
std::deque<std::shared_ptr<IStorage>> out_interactive_channel;
|
||||
|
||||
Kernel::EventPair state_changed_event;
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ void Error::Execute() {
|
||||
|
||||
void Error::DisplayCompleted() {
|
||||
complete = true;
|
||||
broker.PushNormalDataFromApplet(IStorage{{}});
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{}));
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Service::AM::Applets {
|
||||
constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
|
||||
|
||||
static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) {
|
||||
std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();
|
||||
std::shared_ptr<IStorage> storage = broker.PopNormalDataToApplet();
|
||||
for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
|
||||
const auto data = storage->GetData();
|
||||
LOG_INFO(Service_AM,
|
||||
@@ -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(std::make_shared<IStorage>(std::move(out)));
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ void PhotoViewer::Execute() {
|
||||
}
|
||||
|
||||
void PhotoViewer::ViewFinished() {
|
||||
broker.PushNormalDataFromApplet(IStorage{{}});
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{}));
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
@@ -234,8 +234,8 @@ void StubApplet::ExecuteInteractive() {
|
||||
LOG_WARNING(Service_AM, "called (STUBBED)");
|
||||
LogCurrentStorage(broker, "ExecuteInteractive");
|
||||
|
||||
broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
|
||||
broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
@@ -243,8 +243,8 @@ void StubApplet::Execute() {
|
||||
LOG_WARNING(Service_AM, "called (STUBBED)");
|
||||
LogCurrentStorage(broker, "Execute");
|
||||
|
||||
broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
|
||||
broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ void ProfileSelect::ExecuteInteractive() {
|
||||
|
||||
void ProfileSelect::Execute() {
|
||||
if (complete) {
|
||||
broker.PushNormalDataFromApplet(IStorage{final_data});
|
||||
broker.PushNormalDataFromApplet(std::make_shared<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(std::make_shared<IStorage>(std::move(final_data)));
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,8 @@ void SoftwareKeyboard::ExecuteInteractive() {
|
||||
|
||||
void SoftwareKeyboard::Execute() {
|
||||
if (complete) {
|
||||
broker.PushNormalDataFromApplet(IStorage{final_data});
|
||||
broker.PushNormalDataFromApplet(std::make_shared<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(std::make_shared<IStorage>(std::move(output_main)));
|
||||
broker.SignalStateChanged();
|
||||
} else {
|
||||
broker.PushInteractiveDataFromApplet(IStorage{output_sub});
|
||||
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::move(output_sub)));
|
||||
}
|
||||
} else {
|
||||
output_main[0] = 1;
|
||||
complete = true;
|
||||
broker.PushNormalDataFromApplet(IStorage{output_main});
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(output_main)));
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(std::make_shared<IStorage>(std::move(data)));
|
||||
broker.SignalStateChanged();
|
||||
|
||||
if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) {
|
||||
|
||||
@@ -420,7 +420,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
IFile file(result.Unwrap());
|
||||
auto file = std::make_shared<IFile>(result.Unwrap());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -445,7 +445,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
IDirectory directory(result.Unwrap());
|
||||
auto directory = std::make_shared<IDirectory>(result.Unwrap());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -794,8 +794,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
|
||||
void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called");
|
||||
|
||||
IFileSystem filesystem(fsc.OpenSDMC().Unwrap(),
|
||||
SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
|
||||
auto filesystem = std::make_shared<IFileSystem>(
|
||||
fsc.OpenSDMC().Unwrap(), SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -846,7 +846,8 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
id = FileSys::StorageId::NandSystem;
|
||||
}
|
||||
|
||||
IFileSystem filesystem(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id));
|
||||
auto filesystem =
|
||||
std::make_shared<IFileSystem>(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -898,7 +899,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
IStorage storage(std::move(romfs.Unwrap()));
|
||||
auto storage = std::make_shared<IStorage>(std::move(romfs.Unwrap()));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -937,7 +938,8 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
FileSys::PatchManager pm{title_id};
|
||||
|
||||
IStorage storage(pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
|
||||
auto storage = std::make_shared<IStorage>(
|
||||
pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -704,8 +704,8 @@ public:
|
||||
INSERT_UNION_PADDING_WORDS(0x15);
|
||||
|
||||
s32 stencil_back_func_ref;
|
||||
u32 stencil_back_func_mask;
|
||||
u32 stencil_back_mask;
|
||||
u32 stencil_back_func_mask;
|
||||
|
||||
INSERT_UNION_PADDING_WORDS(0xC);
|
||||
|
||||
@@ -862,7 +862,11 @@ public:
|
||||
|
||||
float point_size;
|
||||
|
||||
INSERT_UNION_PADDING_WORDS(0x7);
|
||||
INSERT_UNION_PADDING_WORDS(0x1);
|
||||
|
||||
u32 point_sprite_enable;
|
||||
|
||||
INSERT_UNION_PADDING_WORDS(0x5);
|
||||
|
||||
u32 zeta_enable;
|
||||
|
||||
@@ -1458,8 +1462,8 @@ ASSERT_REG_POSITION(polygon_offset_fill_enable, 0x372);
|
||||
ASSERT_REG_POSITION(patch_vertices, 0x373);
|
||||
ASSERT_REG_POSITION(scissor_test, 0x380);
|
||||
ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
|
||||
ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D6);
|
||||
ASSERT_REG_POSITION(stencil_back_mask, 0x3D7);
|
||||
ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
|
||||
ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
|
||||
ASSERT_REG_POSITION(color_mask_common, 0x3E4);
|
||||
ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
|
||||
ASSERT_REG_POSITION(depth_bounds, 0x3E7);
|
||||
@@ -1494,6 +1498,7 @@ ASSERT_REG_POSITION(vb_element_base, 0x50D);
|
||||
ASSERT_REG_POSITION(vb_base_instance, 0x50E);
|
||||
ASSERT_REG_POSITION(clip_distance_enabled, 0x544);
|
||||
ASSERT_REG_POSITION(point_size, 0x546);
|
||||
ASSERT_REG_POSITION(point_sprite_enable, 0x548);
|
||||
ASSERT_REG_POSITION(zeta_enable, 0x54E);
|
||||
ASSERT_REG_POSITION(multisample_control, 0x54F);
|
||||
ASSERT_REG_POSITION(condition, 0x554);
|
||||
|
||||
@@ -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;
|
||||
@@ -775,6 +788,13 @@ union Instruction {
|
||||
BitField<39, 1, u64> wrap;
|
||||
} 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;
|
||||
|
||||
@@ -23,7 +23,7 @@ MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
|
||||
GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async)
|
||||
: system{system}, renderer{renderer}, is_async{is_async} {
|
||||
auto& rasterizer{renderer.Rasterizer()};
|
||||
memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer);
|
||||
memory_manager = std::make_unique<Tegra::MemoryManager>(system);
|
||||
dma_pusher = std::make_unique<Tegra::DmaPusher>(*this);
|
||||
maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager);
|
||||
fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer);
|
||||
|
||||
@@ -86,7 +86,7 @@ struct CommandDataContainer {
|
||||
struct SynchState final {
|
||||
std::atomic_bool is_running{true};
|
||||
|
||||
using CommandQueue = Common::SPSCQueue<CommandDataContainer>;
|
||||
using CommandQueue = Common::MPSCQueue<CommandDataContainer>;
|
||||
CommandQueue queue;
|
||||
u64 last_fence{};
|
||||
std::atomic<u64> signaled_fence{};
|
||||
|
||||
@@ -9,13 +9,12 @@
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/vm_manager.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
MemoryManager::MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
|
||||
: rasterizer{rasterizer}, system{system} {
|
||||
MemoryManager::MemoryManager(Core::System& system) : system{system} {
|
||||
std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
|
||||
std::fill(page_table.attributes.begin(), page_table.attributes.end(),
|
||||
Common::PageType::Unmapped);
|
||||
@@ -84,7 +83,8 @@ GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
|
||||
const auto cpu_addr = GpuToCpuAddress(gpu_addr);
|
||||
ASSERT(cpu_addr);
|
||||
|
||||
rasterizer.FlushAndInvalidateRegion(cache_addr, aligned_size);
|
||||
system.GPU().FlushAndInvalidateRegion(cache_addr, aligned_size);
|
||||
|
||||
UnmapRange(gpu_addr, aligned_size);
|
||||
ASSERT(system.CurrentProcess()
|
||||
->VMManager()
|
||||
@@ -242,7 +242,7 @@ void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, const std::s
|
||||
switch (page_table.attributes[page_index]) {
|
||||
case Common::PageType::Memory: {
|
||||
const u8* src_ptr{page_table.pointers[page_index] + page_offset};
|
||||
rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount);
|
||||
system.GPU().FlushRegion(ToCacheAddr(src_ptr), copy_amount);
|
||||
std::memcpy(dest_buffer, src_ptr, copy_amount);
|
||||
break;
|
||||
}
|
||||
@@ -292,7 +292,7 @@ void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, const
|
||||
switch (page_table.attributes[page_index]) {
|
||||
case Common::PageType::Memory: {
|
||||
u8* dest_ptr{page_table.pointers[page_index] + page_offset};
|
||||
rasterizer.InvalidateRegion(ToCacheAddr(dest_ptr), copy_amount);
|
||||
system.GPU().InvalidateRegion(ToCacheAddr(dest_ptr), copy_amount);
|
||||
std::memcpy(dest_ptr, src_buffer, copy_amount);
|
||||
break;
|
||||
}
|
||||
@@ -340,7 +340,7 @@ void MemoryManager::CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, const std::
|
||||
switch (page_table.attributes[page_index]) {
|
||||
case Common::PageType::Memory: {
|
||||
const u8* src_ptr{page_table.pointers[page_index] + page_offset};
|
||||
rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount);
|
||||
system.GPU().FlushRegion(ToCacheAddr(src_ptr), copy_amount);
|
||||
WriteBlock(dest_addr, src_ptr, copy_amount);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/page_table.h"
|
||||
|
||||
namespace VideoCore {
|
||||
class RasterizerInterface;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
@@ -51,7 +47,7 @@ struct VirtualMemoryArea {
|
||||
|
||||
class MemoryManager final {
|
||||
public:
|
||||
explicit MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer);
|
||||
explicit MemoryManager(Core::System& system);
|
||||
~MemoryManager();
|
||||
|
||||
GPUVAddr AllocateSpace(u64 size, u64 align);
|
||||
@@ -176,7 +172,6 @@ private:
|
||||
|
||||
Common::PageTable page_table{page_bits};
|
||||
VMAMap vma_map;
|
||||
VideoCore::RasterizerInterface& rasterizer;
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
} 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, 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;
|
||||
}
|
||||
|
||||
@@ -1293,6 +1220,7 @@ void RasterizerOpenGL::SyncPointState() {
|
||||
// Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid
|
||||
// in OpenGL).
|
||||
state.point.program_control = regs.vp_point_size.enable != 0;
|
||||
state.point.sprite = regs.point_sprite_enable != 0;
|
||||
state.point.size = std::max(1.0f, regs.point_size);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -128,6 +128,7 @@ void OpenGLState::ApplyClipDistances() {
|
||||
|
||||
void OpenGLState::ApplyPointSize() {
|
||||
Enable(GL_PROGRAM_POINT_SIZE, cur_state.point.program_control, point.program_control);
|
||||
Enable(GL_POINT_SPRITE, cur_state.point.sprite, point.sprite);
|
||||
if (UpdateValue(cur_state.point.size, point.size)) {
|
||||
glPointSize(point.size);
|
||||
}
|
||||
|
||||
@@ -132,6 +132,7 @@ public:
|
||||
|
||||
struct {
|
||||
bool program_control = false; // GL_PROGRAM_POINT_SIZE
|
||||
bool sprite = false; // GL_POINT_SPRITE
|
||||
GLfloat size = 1.0f; // GL_POINT_SIZE
|
||||
} point;
|
||||
|
||||
|
||||
@@ -47,8 +47,7 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
|
||||
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
|
||||
return GL_UNSIGNED_INT_2_10_10_10_REV;
|
||||
default:
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
|
||||
UNREACHABLE();
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
|
||||
return {};
|
||||
}
|
||||
case Maxwell::VertexAttribute::Type::SignedInt:
|
||||
@@ -72,8 +71,7 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
|
||||
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
|
||||
return GL_INT_2_10_10_10_REV;
|
||||
default:
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
|
||||
UNREACHABLE();
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
|
||||
return {};
|
||||
}
|
||||
case Maxwell::VertexAttribute::Type::Float:
|
||||
@@ -89,13 +87,19 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
|
||||
case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
|
||||
return GL_FLOAT;
|
||||
default:
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
|
||||
UNREACHABLE();
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
|
||||
return {};
|
||||
}
|
||||
case Maxwell::VertexAttribute::Type::UnsignedScaled:
|
||||
switch (attrib.size) {
|
||||
case Maxwell::VertexAttribute::Size::Size_8_8:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
default:
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
|
||||
return {};
|
||||
}
|
||||
default:
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString());
|
||||
UNREACHABLE();
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString());
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -742,7 +742,6 @@ void Config::ReadUIValues() {
|
||||
void Config::ReadUIGamelistValues() {
|
||||
qt_config->beginGroup(QStringLiteral("UIGameList"));
|
||||
|
||||
UISettings::values.show_unknown = ReadSetting(QStringLiteral("show_unknown"), true).toBool();
|
||||
UISettings::values.show_add_ons = ReadSetting(QStringLiteral("show_add_ons"), true).toBool();
|
||||
UISettings::values.icon_size = ReadSetting(QStringLiteral("icon_size"), 64).toUInt();
|
||||
UISettings::values.row_1_text_id = ReadSetting(QStringLiteral("row_1_text_id"), 3).toUInt();
|
||||
@@ -1159,7 +1158,6 @@ void Config::SaveUIValues() {
|
||||
void Config::SaveUIGamelistValues() {
|
||||
qt_config->beginGroup(QStringLiteral("UIGameList"));
|
||||
|
||||
WriteSetting(QStringLiteral("show_unknown"), UISettings::values.show_unknown, true);
|
||||
WriteSetting(QStringLiteral("show_add_ons"), UISettings::values.show_add_ons, true);
|
||||
WriteSetting(QStringLiteral("icon_size"), UISettings::values.icon_size, 64);
|
||||
WriteSetting(QStringLiteral("row_1_text_id"), UISettings::values.row_1_text_id, 3);
|
||||
|
||||
@@ -40,7 +40,6 @@ ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::Configur
|
||||
SetConfiguration();
|
||||
|
||||
// Force game list reload if any of the relevant settings are changed.
|
||||
connect(ui->show_unknown, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
|
||||
connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&ConfigureUi::RequestGameListUpdate);
|
||||
connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
@@ -60,7 +59,6 @@ ConfigureUi::~ConfigureUi() = default;
|
||||
void ConfigureUi::ApplyConfiguration() {
|
||||
UISettings::values.theme =
|
||||
ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
|
||||
UISettings::values.show_unknown = ui->show_unknown->isChecked();
|
||||
UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
|
||||
UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
|
||||
UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
|
||||
@@ -74,7 +72,6 @@ void ConfigureUi::RequestGameListUpdate() {
|
||||
|
||||
void ConfigureUi::SetConfiguration() {
|
||||
ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
|
||||
ui->show_unknown->setChecked(UISettings::values.show_unknown);
|
||||
ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
|
||||
ui->icon_size_combobox->setCurrentIndex(
|
||||
ui->icon_size_combobox->findData(UISettings::values.icon_size));
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
<layout class="QHBoxLayout" name="GameListHorizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="GeneralVerticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="show_unknown">
|
||||
<property name="text">
|
||||
<string>Show files with type 'Unknown'</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="show_add_ons">
|
||||
<property name="text">
|
||||
|
||||
@@ -298,8 +298,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
|
||||
}
|
||||
|
||||
const auto file_type = loader->GetFileType();
|
||||
if ((file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) &&
|
||||
!UISettings::values.show_unknown) {
|
||||
if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,6 @@ struct Values {
|
||||
int profile_index;
|
||||
|
||||
// Game List
|
||||
bool show_unknown;
|
||||
bool show_add_ons;
|
||||
uint32_t icon_size;
|
||||
uint8_t row_1_text_id;
|
||||
|
||||
Reference in New Issue
Block a user