Compare commits
42 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9db1d125e | ||
|
|
8a5794c4db | ||
|
|
3b98fab850 | ||
|
|
65774084fd | ||
|
|
b83eb4dd18 | ||
|
|
8c016b02e7 | ||
|
|
716285fab8 | ||
|
|
dde074eaab | ||
|
|
875183e7c5 | ||
|
|
a50133fc5e | ||
|
|
e274e38205 | ||
|
|
a35717b245 | ||
|
|
538f097f97 | ||
|
|
afa4bcbb3b | ||
|
|
2e85ee250d | ||
|
|
cb48ed2e1a | ||
|
|
4aa8189328 | ||
|
|
ec514a4d1b | ||
|
|
e1f7938a3b | ||
|
|
ab102787fa | ||
|
|
8441094ba3 | ||
|
|
0687a8370d | ||
|
|
df9899eed6 | ||
|
|
824e53149d | ||
|
|
9761618a8d | ||
|
|
d3a4a192fe | ||
|
|
3b85ac2ac4 | ||
|
|
4735d18bb9 | ||
|
|
a9d24b0df3 | ||
|
|
5dae45b958 | ||
|
|
827dcad26e | ||
|
|
4439801c0f | ||
|
|
ad653550eb | ||
|
|
59173ff7a7 | ||
|
|
2490ffbbce | ||
|
|
cd7abba1a9 | ||
|
|
41e94b7b99 | ||
|
|
4bcc5bacff | ||
|
|
1f228c51ca | ||
|
|
50ee9c46ab | ||
|
|
6ab839462c | ||
|
|
94da1e8a7e |
5
externals/libusb/CMakeLists.txt
vendored
5
externals/libusb/CMakeLists.txt
vendored
@@ -1,3 +1,8 @@
|
||||
# Ensure libusb compiles with UTF-8 encoding on MSVC
|
||||
if(MSVC)
|
||||
add_compile_options(/utf-8)
|
||||
endif()
|
||||
|
||||
add_library(usb STATIC EXCLUDE_FROM_ALL
|
||||
libusb/libusb/core.c
|
||||
libusb/libusb/core.c
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
constexpr std::size_t default_stack_size = 256 * 1024;
|
||||
constexpr std::size_t default_stack_size = 512 * 1024;
|
||||
|
||||
struct Fiber::FiberImpl {
|
||||
FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {}
|
||||
|
||||
@@ -306,13 +306,18 @@ void ARM_Dynarmic_32::ClearExclusiveState() {
|
||||
|
||||
void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
|
||||
std::size_t new_address_space_size_in_bits) {
|
||||
ThreadContext32 ctx{};
|
||||
SaveContext(ctx);
|
||||
|
||||
auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
|
||||
auto iter = jit_cache.find(key);
|
||||
if (iter != jit_cache.end()) {
|
||||
jit = iter->second;
|
||||
LoadContext(ctx);
|
||||
return;
|
||||
}
|
||||
jit = MakeJit(page_table, new_address_space_size_in_bits);
|
||||
LoadContext(ctx);
|
||||
jit_cache.emplace(key, jit);
|
||||
}
|
||||
|
||||
|
||||
@@ -348,13 +348,18 @@ void ARM_Dynarmic_64::ClearExclusiveState() {
|
||||
|
||||
void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
|
||||
std::size_t new_address_space_size_in_bits) {
|
||||
ThreadContext64 ctx{};
|
||||
SaveContext(ctx);
|
||||
|
||||
auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
|
||||
auto iter = jit_cache.find(key);
|
||||
if (iter != jit_cache.end()) {
|
||||
jit = iter->second;
|
||||
LoadContext(ctx);
|
||||
return;
|
||||
}
|
||||
jit = MakeJit(page_table, new_address_space_size_in_bits);
|
||||
LoadContext(ctx);
|
||||
jit_cache.emplace(key, jit);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace NgWord1Data {
|
||||
constexpr std::size_t NUMBER_WORD_TXT_FILES = 0x10;
|
||||
|
||||
// Should this archive replacement mysteriously not work on a future game, consider updating.
|
||||
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x19}; // 5.1.0 System Version
|
||||
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x20}; // 11.0.1 System Version
|
||||
|
||||
constexpr std::array<u8, 30> WORD_TXT{
|
||||
0xFE, 0xFF, 0x00, 0x5E, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x79, 0x00, 0x62, 0x00,
|
||||
@@ -43,7 +43,7 @@ namespace NgWord2Data {
|
||||
constexpr std::size_t NUMBER_AC_NX_FILES = 0x10;
|
||||
|
||||
// Should this archive replacement mysteriously not work on a future game, consider updating.
|
||||
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x15}; // 5.1.0 System Version
|
||||
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x1A}; // 11.0.1 System Version
|
||||
|
||||
constexpr std::array<u8, 0x2C> AC_NX_DATA{
|
||||
0x1F, 0x8B, 0x08, 0x08, 0xD5, 0x2C, 0x09, 0x5C, 0x04, 0x00, 0x61, 0x63, 0x72, 0x61, 0x77,
|
||||
|
||||
@@ -14,15 +14,15 @@ namespace SystemVersionData {
|
||||
|
||||
constexpr u8 VERSION_MAJOR = 11;
|
||||
constexpr u8 VERSION_MINOR = 0;
|
||||
constexpr u8 VERSION_MICRO = 0;
|
||||
constexpr u8 VERSION_MICRO = 1;
|
||||
|
||||
constexpr u8 REVISION_MAJOR = 5;
|
||||
constexpr u8 REVISION_MAJOR = 1;
|
||||
constexpr u8 REVISION_MINOR = 0;
|
||||
|
||||
constexpr char PLATFORM_STRING[] = "NX";
|
||||
constexpr char VERSION_HASH[] = "34197eba8810e2edd5e9dfcfbde7b340882e856d";
|
||||
constexpr char DISPLAY_VERSION[] = "11.0.0";
|
||||
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.0-5.0";
|
||||
constexpr char VERSION_HASH[] = "69103fcb2004dace877094c2f8c29e6113be5dbf";
|
||||
constexpr char DISPLAY_VERSION[] = "11.0.1";
|
||||
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.1-1.0";
|
||||
|
||||
} // namespace SystemVersionData
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ private:
|
||||
void GetBlockedUserListIds(Kernel::HLERequestContext& ctx) {
|
||||
// This is safe to stub, as there should be no adverse consequences from reporting no
|
||||
// blocked users.
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
LOG_WARNING(Service_Friend, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0); // Indicates there are no blocked users
|
||||
@@ -141,14 +141,14 @@ private:
|
||||
|
||||
void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
|
||||
// Stub used by Splatoon 2
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
LOG_WARNING(Service_Friend, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void UpdateUserPresence(Kernel::HLERequestContext& ctx) {
|
||||
// Stub used by Retro City Rampage
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
LOG_WARNING(Service_Friend, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
@@ -159,7 +159,7 @@ private:
|
||||
const auto uuid = rp.PopRaw<Common::UUID>();
|
||||
[[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
|
||||
const auto pid = rp.Pop<u64>();
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset,
|
||||
LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset,
|
||||
uuid.Format(), pid);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
@@ -191,7 +191,7 @@ public:
|
||||
|
||||
private:
|
||||
void GetEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
LOG_DEBUG(Service_Friend, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -199,7 +199,7 @@ private:
|
||||
}
|
||||
|
||||
void Clear(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
LOG_DEBUG(Service_Friend, "called");
|
||||
while (!notifications.empty()) {
|
||||
notifications.pop();
|
||||
}
|
||||
@@ -210,10 +210,10 @@ private:
|
||||
}
|
||||
|
||||
void Pop(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
LOG_DEBUG(Service_Friend, "called");
|
||||
|
||||
if (notifications.empty()) {
|
||||
LOG_ERROR(Service_ACC, "No notifications in queue!");
|
||||
LOG_ERROR(Service_Friend, "No notifications in queue!");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_NO_NOTIFICATIONS);
|
||||
return;
|
||||
@@ -231,7 +231,8 @@ private:
|
||||
break;
|
||||
default:
|
||||
// HOS seems not have an error case for an unknown notification
|
||||
LOG_WARNING(Service_ACC, "Unknown notification {:08X}", notification.notification_type);
|
||||
LOG_WARNING(Service_Friend, "Unknown notification {:08X}",
|
||||
notification.notification_type);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -269,14 +270,14 @@ void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IFriendService>(system);
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
LOG_DEBUG(Service_Friend, "called");
|
||||
}
|
||||
|
||||
void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto uuid = rp.PopRaw<Common::UUID>();
|
||||
|
||||
LOG_DEBUG(Service_ACC, "called, uuid={}", uuid.Format());
|
||||
LOG_DEBUG(Service_Friend, "called, uuid={}", uuid.Format());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -39,7 +39,7 @@ NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||
case 0x8:
|
||||
return GetVARegions(input, output);
|
||||
case 0x9:
|
||||
return InitalizeEx(input, output);
|
||||
return AllocAsEx(input, output);
|
||||
case 0x14:
|
||||
return Remap(input, output);
|
||||
default:
|
||||
@@ -78,11 +78,16 @@ NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std:
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlInitalizeEx params{};
|
||||
NvResult nvhost_as_gpu::AllocAsEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlAllocAsEx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
|
||||
if (params.big_page_size == 0) {
|
||||
params.big_page_size = DEFAULT_BIG_PAGE_SIZE;
|
||||
}
|
||||
|
||||
big_page_size = params.big_page_size;
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
@@ -276,13 +281,18 @@ NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u
|
||||
params.buf_size);
|
||||
|
||||
params.buf_size = 0x30;
|
||||
params.regions[0].offset = 0x04000000;
|
||||
params.regions[0].page_size = 0x1000;
|
||||
params.regions[0].pages = 0x3fbfff;
|
||||
|
||||
params.regions[1].offset = 0x04000000;
|
||||
params.regions[1].page_size = 0x10000;
|
||||
params.regions[1].pages = 0x1bffff;
|
||||
params.small = IoctlVaRegion{
|
||||
.offset = 0x04000000,
|
||||
.page_size = DEFAULT_SMALL_PAGE_SIZE,
|
||||
.pages = 0x3fbfff,
|
||||
};
|
||||
|
||||
params.big = IoctlVaRegion{
|
||||
.offset = 0x04000000,
|
||||
.page_size = big_page_size,
|
||||
.pages = 0x1bffff,
|
||||
};
|
||||
|
||||
// TODO(ogniK): This probably can stay stubbed but should add support way way later
|
||||
|
||||
@@ -299,18 +309,25 @@ NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u
|
||||
params.buf_size);
|
||||
|
||||
params.buf_size = 0x30;
|
||||
params.regions[0].offset = 0x04000000;
|
||||
params.regions[0].page_size = 0x1000;
|
||||
params.regions[0].pages = 0x3fbfff;
|
||||
|
||||
params.regions[1].offset = 0x04000000;
|
||||
params.regions[1].page_size = 0x10000;
|
||||
params.regions[1].pages = 0x1bffff;
|
||||
params.small = IoctlVaRegion{
|
||||
.offset = 0x04000000,
|
||||
.page_size = 0x1000,
|
||||
.pages = 0x3fbfff,
|
||||
};
|
||||
|
||||
params.big = IoctlVaRegion{
|
||||
.offset = 0x04000000,
|
||||
.page_size = big_page_size,
|
||||
.pages = 0x1bffff,
|
||||
};
|
||||
|
||||
// TODO(ogniK): This probably can stay stubbed but should add support way way later
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
std::memcpy(inline_output.data(), ¶ms.regions, inline_output.size());
|
||||
std::memcpy(inline_output.data(), ¶ms.small, sizeof(IoctlVaRegion));
|
||||
std::memcpy(inline_output.data() + sizeof(IoctlVaRegion), ¶ms.big, sizeof(IoctlVaRegion));
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
namespace Service::Nvidia::Devices {
|
||||
|
||||
constexpr u32 DEFAULT_BIG_PAGE_SIZE = 1 << 16;
|
||||
constexpr u32 DEFAULT_SMALL_PAGE_SIZE = 1 << 12;
|
||||
|
||||
class nvmap;
|
||||
|
||||
enum class AddressSpaceFlags : u32 {
|
||||
@@ -76,16 +79,16 @@ private:
|
||||
bool is_allocated{};
|
||||
};
|
||||
|
||||
struct IoctlInitalizeEx {
|
||||
u32_le big_page_size{}; // depends on GPU's available_big_page_sizes; 0=default
|
||||
s32_le as_fd{}; // ignored; passes 0
|
||||
u32_le flags{}; // passes 0
|
||||
u32_le reserved{}; // ignored; passes 0
|
||||
u64_le unk0{};
|
||||
u64_le unk1{};
|
||||
u64_le unk2{};
|
||||
struct IoctlAllocAsEx {
|
||||
u32_le flags{}; // usually passes 1
|
||||
s32_le as_fd{}; // ignored; passes 0
|
||||
u32_le big_page_size{};
|
||||
u32_le reserved{}; // ignored; passes 0
|
||||
u64_le va_range_start{};
|
||||
u64_le va_range_end{};
|
||||
u64_le va_range_split{};
|
||||
};
|
||||
static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size");
|
||||
static_assert(sizeof(IoctlAllocAsEx) == 40, "IoctlAllocAsEx is incorrect size");
|
||||
|
||||
struct IoctlAllocSpace {
|
||||
u32_le pages{};
|
||||
@@ -149,14 +152,16 @@ private:
|
||||
u64_le buf_addr{}; // (contained output user ptr on linux, ignored)
|
||||
u32_le buf_size{}; // forced to 2*sizeof(struct va_region)
|
||||
u32_le reserved{};
|
||||
IoctlVaRegion regions[2]{};
|
||||
IoctlVaRegion small{};
|
||||
IoctlVaRegion big{};
|
||||
};
|
||||
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,
|
||||
"IoctlGetVaRegions is incorrect size");
|
||||
|
||||
s32 channel{};
|
||||
u32 big_page_size{DEFAULT_BIG_PAGE_SIZE};
|
||||
|
||||
NvResult InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult AllocAsEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
||||
@@ -42,7 +42,9 @@ void BSD::PollWork::Execute(BSD* bsd) {
|
||||
}
|
||||
|
||||
void BSD::PollWork::Response(Kernel::HLERequestContext& ctx) {
|
||||
ctx.WriteBuffer(write_buffer);
|
||||
if (write_buffer.size() > 0) {
|
||||
ctx.WriteBuffer(write_buffer);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -55,7 +57,9 @@ void BSD::AcceptWork::Execute(BSD* bsd) {
|
||||
}
|
||||
|
||||
void BSD::AcceptWork::Response(Kernel::HLERequestContext& ctx) {
|
||||
ctx.WriteBuffer(write_buffer);
|
||||
if (write_buffer.size() > 0) {
|
||||
ctx.WriteBuffer(write_buffer);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -43,6 +43,11 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system
|
||||
auto module = std::make_shared<Module>();
|
||||
std::make_shared<CSRNG>(system, module)->InstallAsService(service_manager);
|
||||
std::make_shared<SPL>(system, module)->InstallAsService(service_manager);
|
||||
std::make_shared<SPL_MIG>(system, module)->InstallAsService(service_manager);
|
||||
std::make_shared<SPL_FS>(system, module)->InstallAsService(service_manager);
|
||||
std::make_shared<SPL_SSL>(system, module)->InstallAsService(service_manager);
|
||||
std::make_shared<SPL_ES>(system, module)->InstallAsService(service_manager);
|
||||
std::make_shared<SPL_MANU>(system, module)->InstallAsService(service_manager);
|
||||
}
|
||||
|
||||
} // namespace Service::SPL
|
||||
|
||||
@@ -8,6 +8,79 @@ namespace Service::SPL {
|
||||
|
||||
SPL::SPL(Core::System& system_, std::shared_ptr<Module> module_)
|
||||
: Interface(system_, std::move(module_), "spl:") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetConfig"},
|
||||
{1, nullptr, "ModularExponentiate"},
|
||||
{5, nullptr, "SetConfig"},
|
||||
{7, &SPL::GetRandomBytes, "GetRandomBytes"},
|
||||
{11, nullptr, "IsDevelopment"},
|
||||
{24, nullptr, "SetBootReason"},
|
||||
{25, nullptr, "GetBootReason"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
SPL_MIG::SPL_MIG(Core::System& system_, std::shared_ptr<Module> module_)
|
||||
: Interface(system_, std::move(module_), "spl:mig") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetConfig"},
|
||||
{1, nullptr, "ModularExponentiate"},
|
||||
{2, nullptr, "GenerateAesKek"},
|
||||
{3, nullptr, "LoadAesKey"},
|
||||
{4, nullptr, "GenerateAesKey"},
|
||||
{5, nullptr, "SetConfig"},
|
||||
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
|
||||
{11, nullptr, "IsDevelopment"},
|
||||
{14, nullptr, "DecryptAesKey"},
|
||||
{15, nullptr, "CryptAesCtr"},
|
||||
{16, nullptr, "ComputeCmac"},
|
||||
{21, nullptr, "AllocateAesKeyslot"},
|
||||
{22, nullptr, "DeallocateAesKeySlot"},
|
||||
{23, nullptr, "GetAesKeyslotAvailableEvent"},
|
||||
{24, nullptr, "SetBootReason"},
|
||||
{25, nullptr, "GetBootReason"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
SPL_FS::SPL_FS(Core::System& system_, std::shared_ptr<Module> module_)
|
||||
: Interface(system_, std::move(module_), "spl:fs") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetConfig"},
|
||||
{1, nullptr, "ModularExponentiate"},
|
||||
{2, nullptr, "GenerateAesKek"},
|
||||
{3, nullptr, "LoadAesKey"},
|
||||
{4, nullptr, "GenerateAesKey"},
|
||||
{5, nullptr, "SetConfig"},
|
||||
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
|
||||
{11, nullptr, "IsDevelopment"},
|
||||
{12, nullptr, "GenerateSpecificAesKey"},
|
||||
{14, nullptr, "DecryptAesKey"},
|
||||
{15, nullptr, "CryptAesCtr"},
|
||||
{16, nullptr, "ComputeCmac"},
|
||||
{19, nullptr, "LoadTitleKey"},
|
||||
{21, nullptr, "AllocateAesKeyslot"},
|
||||
{22, nullptr, "DeallocateAesKeySlot"},
|
||||
{23, nullptr, "GetAesKeyslotAvailableEvent"},
|
||||
{24, nullptr, "SetBootReason"},
|
||||
{25, nullptr, "GetBootReason"},
|
||||
{31, nullptr, "GetPackage2Hash"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
SPL_SSL::SPL_SSL(Core::System& system_, std::shared_ptr<Module> module_)
|
||||
: Interface(system_, std::move(module_), "spl:ssl") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetConfig"},
|
||||
{1, nullptr, "ModularExponentiate"},
|
||||
@@ -16,18 +89,11 @@ SPL::SPL(Core::System& system_, std::shared_ptr<Module> module_)
|
||||
{4, nullptr, "GenerateAesKey"},
|
||||
{5, nullptr, "SetConfig"},
|
||||
{7, &SPL::GetRandomBytes, "GetRandomBytes"},
|
||||
{9, nullptr, "ImportLotusKey"},
|
||||
{10, nullptr, "DecryptLotusMessage"},
|
||||
{11, nullptr, "IsDevelopment"},
|
||||
{12, nullptr, "GenerateSpecificAesKey"},
|
||||
{13, nullptr, "DecryptDeviceUniqueData"},
|
||||
{14, nullptr, "DecryptAesKey"},
|
||||
{15, nullptr, "CryptAesCtr"},
|
||||
{16, nullptr, "ComputeCmac"},
|
||||
{17, nullptr, "ImportEsKey"},
|
||||
{18, nullptr, "UnwrapTitleKey"},
|
||||
{19, nullptr, "LoadTitleKey"},
|
||||
{20, nullptr, "PrepareEsCommonKey"},
|
||||
{21, nullptr, "AllocateAesKeyslot"},
|
||||
{22, nullptr, "DeallocateAesKeySlot"},
|
||||
{23, nullptr, "GetAesKeyslotAvailableEvent"},
|
||||
@@ -35,15 +101,83 @@ SPL::SPL(Core::System& system_, std::shared_ptr<Module> module_)
|
||||
{25, nullptr, "GetBootReason"},
|
||||
{26, nullptr, "DecryptAndStoreSslClientCertKey"},
|
||||
{27, nullptr, "ModularExponentiateWithSslClientCertKey"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
SPL_ES::SPL_ES(Core::System& system_, std::shared_ptr<Module> module_)
|
||||
: Interface(system_, std::move(module_), "spl:es") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetConfig"},
|
||||
{1, nullptr, "ModularExponentiate"},
|
||||
{2, nullptr, "GenerateAesKek"},
|
||||
{3, nullptr, "LoadAesKey"},
|
||||
{4, nullptr, "GenerateAesKey"},
|
||||
{5, nullptr, "SetConfig"},
|
||||
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
|
||||
{11, nullptr, "IsDevelopment"},
|
||||
{13, nullptr, "DecryptDeviceUniqueData"},
|
||||
{14, nullptr, "DecryptAesKey"},
|
||||
{15, nullptr, "CryptAesCtr"},
|
||||
{16, nullptr, "ComputeCmac"},
|
||||
{18, nullptr, "UnwrapTitleKey"},
|
||||
{20, nullptr, "PrepareEsCommonKey"},
|
||||
{21, nullptr, "AllocateAesKeyslot"},
|
||||
{22, nullptr, "DeallocateAesKeySlot"},
|
||||
{23, nullptr, "GetAesKeyslotAvailableEvent"},
|
||||
{24, nullptr, "SetBootReason"},
|
||||
{25, nullptr, "GetBootReason"},
|
||||
{28, nullptr, "DecryptAndStoreDrmDeviceCertKey"},
|
||||
{29, nullptr, "ModularExponentiateWithDrmDeviceCertKey"},
|
||||
{30, nullptr, "ReencryptDeviceUniqueData "},
|
||||
{31, nullptr, "PrepareEsArchiveKey"}, // This is also GetPackage2Hash?
|
||||
{31, nullptr, "PrepareEsArchiveKey"},
|
||||
{32, nullptr, "LoadPreparedAesKey"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
SPL_MANU::SPL_MANU(Core::System& system_, std::shared_ptr<Module> module_)
|
||||
: Interface(system_, std::move(module_), "spl:manu") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetConfig"},
|
||||
{1, nullptr, "ModularExponentiate"},
|
||||
{2, nullptr, "GenerateAesKek"},
|
||||
{3, nullptr, "LoadAesKey"},
|
||||
{4, nullptr, "GenerateAesKey"},
|
||||
{5, nullptr, "SetConfig"},
|
||||
{7, &SPL::GetRandomBytes, "GetRandomBytes"},
|
||||
{11, nullptr, "IsDevelopment"},
|
||||
{13, nullptr, "DecryptDeviceUniqueData"},
|
||||
{14, nullptr, "DecryptAesKey"},
|
||||
{15, nullptr, "CryptAesCtr"},
|
||||
{16, nullptr, "ComputeCmac"},
|
||||
{21, nullptr, "AllocateAesKeyslot"},
|
||||
{22, nullptr, "DeallocateAesKeySlot"},
|
||||
{23, nullptr, "GetAesKeyslotAvailableEvent"},
|
||||
{24, nullptr, "SetBootReason"},
|
||||
{25, nullptr, "GetBootReason"},
|
||||
{30, nullptr, "ReencryptDeviceUniqueData"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
SPL::~SPL() = default;
|
||||
|
||||
SPL_MIG::~SPL_MIG() = default;
|
||||
|
||||
SPL_FS::~SPL_FS() = default;
|
||||
|
||||
SPL_SSL::~SPL_SSL() = default;
|
||||
|
||||
SPL_ES::~SPL_ES() = default;
|
||||
|
||||
SPL_MANU::~SPL_MANU() = default;
|
||||
|
||||
} // namespace Service::SPL
|
||||
|
||||
@@ -18,4 +18,34 @@ public:
|
||||
~SPL() override;
|
||||
};
|
||||
|
||||
class SPL_MIG final : public Module::Interface {
|
||||
public:
|
||||
explicit SPL_MIG(Core::System& system_, std::shared_ptr<Module> module_);
|
||||
~SPL_MIG() override;
|
||||
};
|
||||
|
||||
class SPL_FS final : public Module::Interface {
|
||||
public:
|
||||
explicit SPL_FS(Core::System& system_, std::shared_ptr<Module> module_);
|
||||
~SPL_FS() override;
|
||||
};
|
||||
|
||||
class SPL_SSL final : public Module::Interface {
|
||||
public:
|
||||
explicit SPL_SSL(Core::System& system_, std::shared_ptr<Module> module_);
|
||||
~SPL_SSL() override;
|
||||
};
|
||||
|
||||
class SPL_ES final : public Module::Interface {
|
||||
public:
|
||||
explicit SPL_ES(Core::System& system_, std::shared_ptr<Module> module_);
|
||||
~SPL_ES() override;
|
||||
};
|
||||
|
||||
class SPL_MANU final : public Module::Interface {
|
||||
public:
|
||||
explicit SPL_MANU(Core::System& system_, std::shared_ptr<Module> module_);
|
||||
~SPL_MANU() override;
|
||||
};
|
||||
|
||||
} // namespace Service::SPL
|
||||
|
||||
@@ -140,6 +140,8 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
|
||||
|
||||
const auto current_time_point{
|
||||
time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
|
||||
clock_snapshot.steady_clock_time_point = current_time_point;
|
||||
|
||||
if (const ResultCode result{Clock::ClockSnapshot::GetCurrentTime(
|
||||
clock_snapshot.user_time, current_time_point, clock_snapshot.user_context)};
|
||||
result != RESULT_SUCCESS) {
|
||||
|
||||
@@ -1217,6 +1217,32 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void GetIndirectLayerImageMap(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto width = rp.Pop<s64>();
|
||||
const auto height = rp.Pop<s64>();
|
||||
const auto indirect_layer_consumer_handle = rp.Pop<u64>();
|
||||
const auto applet_resource_user_id = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_VI,
|
||||
"(STUBBED) called, width={}, height={}, indirect_layer_consumer_handle={}, "
|
||||
"applet_resource_user_id={}",
|
||||
width, height, indirect_layer_consumer_handle, applet_resource_user_id);
|
||||
|
||||
std::vector<u8> out_buffer(0x46);
|
||||
ctx.WriteBuffer(out_buffer);
|
||||
|
||||
// TODO: Figure out what these are
|
||||
|
||||
constexpr s64 unknown_result_1 = 0;
|
||||
constexpr s64 unknown_result_2 = 0;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(unknown_result_1);
|
||||
rb.Push(unknown_result_2);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetIndirectLayerImageRequiredMemoryInfo(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto width = rp.Pop<u64>();
|
||||
@@ -1276,7 +1302,7 @@ IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
|
||||
{2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
|
||||
{2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
|
||||
{2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
|
||||
{2450, nullptr, "GetIndirectLayerImageMap"},
|
||||
{2450, &IApplicationDisplayService::GetIndirectLayerImageMap, "GetIndirectLayerImageMap"},
|
||||
{2451, nullptr, "GetIndirectLayerImageCropMap"},
|
||||
{2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo,
|
||||
"GetIndirectLayerImageRequiredMemoryInfo"},
|
||||
|
||||
@@ -12,20 +12,39 @@ namespace InputCommon {
|
||||
|
||||
class KeyButton final : public Input::ButtonDevice {
|
||||
public:
|
||||
explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_)
|
||||
: key_button_list(std::move(key_button_list_)) {}
|
||||
explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_, bool toggle_)
|
||||
: key_button_list(std::move(key_button_list_)), toggle(toggle_) {}
|
||||
|
||||
~KeyButton() override;
|
||||
|
||||
bool GetStatus() const override {
|
||||
if (toggle) {
|
||||
return toggled_status.load(std::memory_order_relaxed);
|
||||
}
|
||||
return status.load();
|
||||
}
|
||||
|
||||
void ToggleButton() {
|
||||
if (lock) {
|
||||
return;
|
||||
}
|
||||
lock = true;
|
||||
const bool old_toggle_status = toggled_status.load();
|
||||
toggled_status.store(!old_toggle_status);
|
||||
}
|
||||
|
||||
void UnlockButton() {
|
||||
lock = false;
|
||||
}
|
||||
|
||||
friend class KeyButtonList;
|
||||
|
||||
private:
|
||||
std::shared_ptr<KeyButtonList> key_button_list;
|
||||
std::atomic<bool> status{false};
|
||||
std::atomic<bool> toggled_status{false};
|
||||
bool lock{false};
|
||||
const bool toggle;
|
||||
};
|
||||
|
||||
struct KeyButtonPair {
|
||||
@@ -51,6 +70,11 @@ public:
|
||||
for (const KeyButtonPair& pair : list) {
|
||||
if (pair.key_code == key_code) {
|
||||
pair.key_button->status.store(pressed);
|
||||
if (pressed) {
|
||||
pair.key_button->ToggleButton();
|
||||
} else {
|
||||
pair.key_button->UnlockButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +99,8 @@ KeyButton::~KeyButton() {
|
||||
|
||||
std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage& params) {
|
||||
const int key_code = params.Get("code", 0);
|
||||
std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list);
|
||||
const bool toggle = params.Get("toggle", false);
|
||||
std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list, toggle);
|
||||
key_button_list->AddKeyButton(key_code, button.get());
|
||||
return button;
|
||||
}
|
||||
|
||||
@@ -162,6 +162,42 @@ void Mouse::EndConfiguration() {
|
||||
configuring = false;
|
||||
}
|
||||
|
||||
bool Mouse::ToggleButton(std::size_t button_) {
|
||||
if (button_ >= mouse_info.size()) {
|
||||
return false;
|
||||
}
|
||||
const auto button = 1U << button_;
|
||||
const bool button_state = (toggle_buttons & button) != 0;
|
||||
const bool button_lock = (lock_buttons & button) != 0;
|
||||
|
||||
if (button_lock) {
|
||||
return button_state;
|
||||
}
|
||||
|
||||
lock_buttons |= static_cast<u16>(button);
|
||||
|
||||
if (button_state) {
|
||||
toggle_buttons &= static_cast<u16>(0xFF - button);
|
||||
} else {
|
||||
toggle_buttons |= static_cast<u16>(button);
|
||||
}
|
||||
|
||||
return !button_state;
|
||||
}
|
||||
|
||||
bool Mouse::UnlockButton(std::size_t button_) {
|
||||
if (button_ >= mouse_info.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto button = 1U << button_;
|
||||
const bool button_state = (toggle_buttons & button) != 0;
|
||||
|
||||
lock_buttons &= static_cast<u16>(0xFF - button);
|
||||
|
||||
return button_state;
|
||||
}
|
||||
|
||||
Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() {
|
||||
return mouse_queue;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,9 @@ public:
|
||||
*/
|
||||
void ReleaseButton(MouseButton button_);
|
||||
|
||||
[[nodiscard]] bool ToggleButton(std::size_t button_);
|
||||
[[nodiscard]] bool UnlockButton(std::size_t button_);
|
||||
|
||||
[[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue();
|
||||
[[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const;
|
||||
|
||||
@@ -94,6 +97,8 @@ private:
|
||||
};
|
||||
|
||||
u16 buttons{};
|
||||
u16 toggle_buttons{};
|
||||
u16 lock_buttons{};
|
||||
std::thread update_thread;
|
||||
MouseButton last_button{MouseButton::Undefined};
|
||||
std::array<MouseInfo, 7> mouse_info;
|
||||
|
||||
@@ -14,16 +14,25 @@ namespace InputCommon {
|
||||
|
||||
class MouseButton final : public Input::ButtonDevice {
|
||||
public:
|
||||
explicit MouseButton(u32 button_, const MouseInput::Mouse* mouse_input_)
|
||||
: button(button_), mouse_input(mouse_input_) {}
|
||||
explicit MouseButton(u32 button_, bool toggle_, MouseInput::Mouse* mouse_input_)
|
||||
: button(button_), toggle(toggle_), mouse_input(mouse_input_) {}
|
||||
|
||||
bool GetStatus() const override {
|
||||
return mouse_input->GetMouseState(button).pressed;
|
||||
const bool button_state = mouse_input->GetMouseState(button).pressed;
|
||||
if (!toggle) {
|
||||
return button_state;
|
||||
}
|
||||
|
||||
if (button_state) {
|
||||
return mouse_input->ToggleButton(button);
|
||||
}
|
||||
return mouse_input->UnlockButton(button);
|
||||
}
|
||||
|
||||
private:
|
||||
const u32 button;
|
||||
const MouseInput::Mouse* mouse_input;
|
||||
const bool toggle;
|
||||
MouseInput::Mouse* mouse_input;
|
||||
};
|
||||
|
||||
MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
|
||||
@@ -32,8 +41,9 @@ MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_
|
||||
std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create(
|
||||
const Common::ParamPackage& params) {
|
||||
const auto button_id = params.Get("button", 0);
|
||||
const auto toggle = params.Get("toggle", false);
|
||||
|
||||
return std::make_unique<MouseButton>(button_id, mouse_input.get());
|
||||
return std::make_unique<MouseButton>(button_id, toggle, mouse_input.get());
|
||||
}
|
||||
|
||||
Common::ParamPackage MouseButtonFactory::GetNextInput() const {
|
||||
|
||||
@@ -761,7 +761,7 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
|
||||
for (const auto& joystick : value) {
|
||||
if (auto* const controller = joystick->GetSDLGameController()) {
|
||||
std::string name =
|
||||
fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
|
||||
fmt::format("{} {}", GetControllerName(controller), joystick->GetPort());
|
||||
devices.emplace_back(Common::ParamPackage{
|
||||
{"class", "sdl"},
|
||||
{"display", std::move(name)},
|
||||
@@ -782,6 +782,17 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
|
||||
return devices;
|
||||
}
|
||||
|
||||
std::string SDLState::GetControllerName(SDL_GameController* controller) const {
|
||||
switch (SDL_GameControllerGetType(controller)) {
|
||||
case SDL_CONTROLLER_TYPE_XBOX360:
|
||||
return "XBox 360 Controller";
|
||||
case SDL_CONTROLLER_TYPE_XBOXONE:
|
||||
return "XBox One Controller";
|
||||
default:
|
||||
return SDL_GameControllerName(controller);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
|
||||
float value = 0.1f) {
|
||||
@@ -930,16 +941,19 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa
|
||||
return {};
|
||||
}
|
||||
|
||||
const bool invert =
|
||||
SDL_GameControllerGetType(controller) != SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
|
||||
|
||||
// This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
|
||||
// We will add those afterwards
|
||||
// This list also excludes Screenshot since theres not really a mapping for that
|
||||
using ButtonBindings =
|
||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
|
||||
static constexpr ButtonBindings switch_to_sdl_button{{
|
||||
{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
|
||||
{Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
|
||||
{Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
|
||||
{Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
|
||||
const ButtonBindings switch_to_sdl_button{{
|
||||
{Settings::NativeButton::A, invert ? SDL_CONTROLLER_BUTTON_B : SDL_CONTROLLER_BUTTON_A},
|
||||
{Settings::NativeButton::B, invert ? SDL_CONTROLLER_BUTTON_A : SDL_CONTROLLER_BUTTON_B},
|
||||
{Settings::NativeButton::X, invert ? SDL_CONTROLLER_BUTTON_Y : SDL_CONTROLLER_BUTTON_X},
|
||||
{Settings::NativeButton::Y, invert ? SDL_CONTROLLER_BUTTON_X : SDL_CONTROLLER_BUTTON_Y},
|
||||
{Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
|
||||
{Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
|
||||
{Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "input_common/sdl/sdl.h"
|
||||
|
||||
union SDL_Event;
|
||||
using SDL_GameController = struct _SDL_GameController;
|
||||
using SDL_Joystick = struct _SDL_Joystick;
|
||||
using SDL_JoystickID = s32;
|
||||
|
||||
@@ -64,6 +65,9 @@ private:
|
||||
/// Needs to be called before SDL_QuitSubSystem.
|
||||
void CloseJoysticks();
|
||||
|
||||
/// Returns a custom name for specific controllers because the default name is not correct
|
||||
std::string GetControllerName(SDL_GameController* controller) const;
|
||||
|
||||
// Set to true if SDL supports game controller subsystem
|
||||
bool has_gamecontroller = false;
|
||||
|
||||
|
||||
@@ -2,63 +2,43 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/div_ceil.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/rasterizer_accelerated.h"
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename Map, typename Interval>
|
||||
constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
|
||||
return boost::make_iterator_range(map.equal_range(interval));
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
RasterizerAccelerated::RasterizerAccelerated(Core::Memory::Memory& cpu_memory_)
|
||||
: cpu_memory{cpu_memory_} {}
|
||||
|
||||
RasterizerAccelerated::~RasterizerAccelerated() = default;
|
||||
|
||||
void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
|
||||
std::lock_guard lock{pages_mutex};
|
||||
const u64 page_start{addr >> Core::Memory::PAGE_BITS};
|
||||
const u64 page_end{(addr + size + Core::Memory::PAGE_SIZE - 1) >> Core::Memory::PAGE_BITS};
|
||||
const auto page_end = Common::DivCeil(addr + size, Core::Memory::PAGE_SIZE);
|
||||
for (auto page = addr >> Core::Memory::PAGE_BITS; page != page_end; ++page) {
|
||||
auto& count = cached_pages.at(page >> 3).Count(page);
|
||||
|
||||
// Interval maps will erase segments if count reaches 0, so if delta is negative we have to
|
||||
// subtract after iterating
|
||||
const auto pages_interval = CachedPageMap::interval_type::right_open(page_start, page_end);
|
||||
if (delta > 0) {
|
||||
cached_pages.add({pages_interval, delta});
|
||||
}
|
||||
|
||||
for (const auto& pair : RangeFromInterval(cached_pages, pages_interval)) {
|
||||
const auto interval = pair.first & pages_interval;
|
||||
const int count = pair.second;
|
||||
|
||||
const VAddr interval_start_addr = boost::icl::first(interval) << Core::Memory::PAGE_BITS;
|
||||
const VAddr interval_end_addr = boost::icl::last_next(interval) << Core::Memory::PAGE_BITS;
|
||||
const u64 interval_size = interval_end_addr - interval_start_addr;
|
||||
|
||||
if (delta > 0 && count == delta) {
|
||||
cpu_memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
|
||||
} else if (delta < 0 && count == -delta) {
|
||||
cpu_memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
|
||||
if (delta > 0) {
|
||||
ASSERT_MSG(count < UINT8_MAX, "Count may overflow!");
|
||||
} else if (delta < 0) {
|
||||
ASSERT_MSG(count > 0, "Count may underflow!");
|
||||
} else {
|
||||
ASSERT(count >= 0);
|
||||
ASSERT_MSG(true, "Delta must be non-zero!");
|
||||
}
|
||||
}
|
||||
|
||||
if (delta < 0) {
|
||||
cached_pages.add({pages_interval, delta});
|
||||
// Adds or subtracts 1, as count is a unsigned 8-bit value
|
||||
count += static_cast<u8>(delta);
|
||||
|
||||
// Assume delta is either -1 or 1
|
||||
if (count == 0) {
|
||||
cpu_memory.RasterizerMarkRegionCached(page << Core::Memory::PAGE_BITS,
|
||||
Core::Memory::PAGE_SIZE, false);
|
||||
} else if (count == 1 && delta > 0) {
|
||||
cpu_memory.RasterizerMarkRegionCached(page << Core::Memory::PAGE_BITS,
|
||||
Core::Memory::PAGE_SIZE, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
@@ -26,10 +25,24 @@ public:
|
||||
void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
|
||||
|
||||
private:
|
||||
using CachedPageMap = boost::icl::interval_map<u64, int>;
|
||||
CachedPageMap cached_pages;
|
||||
std::mutex pages_mutex;
|
||||
class CacheEntry final {
|
||||
public:
|
||||
CacheEntry() = default;
|
||||
|
||||
std::atomic_uint8_t& Count(std::size_t page) {
|
||||
return values[page & 7];
|
||||
}
|
||||
|
||||
const std::atomic_uint8_t& Count(std::size_t page) const {
|
||||
return values[page & 7];
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<std::atomic_uint8_t, 8> values{};
|
||||
};
|
||||
static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!");
|
||||
|
||||
std::array<CacheEntry, 0x800000> cached_pages;
|
||||
Core::Memory::Memory& cpu_memory;
|
||||
};
|
||||
|
||||
|
||||
@@ -210,6 +210,12 @@ Device::Device() {
|
||||
const bool is_amd = vendor == "ATI Technologies Inc.";
|
||||
const bool is_intel = vendor == "Intel";
|
||||
|
||||
#ifdef __unix__
|
||||
const bool is_linux = true;
|
||||
#else
|
||||
const bool is_linux = false;
|
||||
#endif
|
||||
|
||||
bool disable_fast_buffer_sub_data = false;
|
||||
if (is_nvidia && version == "4.6.0 NVIDIA 443.24") {
|
||||
LOG_WARNING(
|
||||
@@ -249,7 +255,9 @@ Device::Device() {
|
||||
GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 &&
|
||||
GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2;
|
||||
|
||||
use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue();
|
||||
// Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation.
|
||||
use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue() &&
|
||||
!(is_amd || (is_intel && !is_linux));
|
||||
use_driver_cache = is_nvidia;
|
||||
|
||||
LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
|
||||
@@ -261,6 +269,10 @@ Device::Device() {
|
||||
if (Settings::values.use_assembly_shaders.GetValue() && !use_assembly_shaders) {
|
||||
LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported");
|
||||
}
|
||||
|
||||
if (Settings::values.use_asynchronous_shaders.GetValue() && !use_asynchronous_shaders) {
|
||||
LOG_WARNING(Render_OpenGL, "Asynchronous shader compilation enabled but not supported");
|
||||
}
|
||||
}
|
||||
|
||||
Device::Device(std::nullptr_t) {
|
||||
|
||||
@@ -376,11 +376,15 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
|
||||
}
|
||||
|
||||
void GRenderWindow::keyPressEvent(QKeyEvent* event) {
|
||||
input_subsystem->GetKeyboard()->PressKey(event->key());
|
||||
if (!event->isAutoRepeat()) {
|
||||
input_subsystem->GetKeyboard()->PressKey(event->key());
|
||||
}
|
||||
}
|
||||
|
||||
void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
|
||||
input_subsystem->GetKeyboard()->ReleaseKey(event->key());
|
||||
if (!event->isAutoRepeat()) {
|
||||
input_subsystem->GetKeyboard()->ReleaseKey(event->key());
|
||||
}
|
||||
}
|
||||
|
||||
MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) {
|
||||
|
||||
@@ -103,7 +103,10 @@ void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit)
|
||||
str = QFileDialog::getOpenFileName(this, caption, QFileInfo(edit->text()).dir().path(),
|
||||
QStringLiteral("NX Gamecard;*.xci"));
|
||||
} else {
|
||||
str = QFileDialog::getExistingDirectory(this, caption, edit->text()) + QDir::separator();
|
||||
str = QFileDialog::getExistingDirectory(this, caption, edit->text());
|
||||
if (!str.isNull() && str.back() != QDir::separator()) {
|
||||
str.append(QDir::separator());
|
||||
}
|
||||
}
|
||||
|
||||
if (str.isEmpty())
|
||||
|
||||
@@ -105,7 +105,9 @@ QString ButtonToText(const Common::ParamPackage& param) {
|
||||
}
|
||||
|
||||
if (param.Get("engine", "") == "keyboard") {
|
||||
return GetKeyName(param.Get("code", 0));
|
||||
const QString button_str = GetKeyName(param.Get("code", 0));
|
||||
const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : "");
|
||||
return QObject::tr("%1%2").arg(toggle, button_str);
|
||||
}
|
||||
|
||||
if (param.Get("engine", "") == "gcpad") {
|
||||
@@ -157,7 +159,8 @@ QString ButtonToText(const Common::ParamPackage& param) {
|
||||
if (param.Get("engine", "") == "mouse") {
|
||||
if (param.Has("button")) {
|
||||
const QString button_str = QString::number(int(param.Get("button", 0)));
|
||||
return QObject::tr("Click %1").arg(button_str);
|
||||
const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : "");
|
||||
return QObject::tr("%1Click %2").arg(toggle, button_str);
|
||||
}
|
||||
return GetKeyName(param.Get("code", 0));
|
||||
}
|
||||
@@ -301,6 +304,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||
buttons_param[button_id].Clear();
|
||||
button_map[button_id]->setText(tr("[not set]"));
|
||||
});
|
||||
context_menu.addAction(tr("Toggle button"), [&] {
|
||||
const bool toggle_value = !buttons_param[button_id].Get("toggle", false);
|
||||
buttons_param[button_id].Set("toggle", toggle_value);
|
||||
button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
|
||||
});
|
||||
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
|
||||
ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
|
||||
});
|
||||
@@ -413,6 +421,15 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||
analogs_param[analog_id].Set("modifier", "");
|
||||
analog_map_modifier_button[analog_id]->setText(tr("[not set]"));
|
||||
});
|
||||
context_menu.addAction(tr("Toggle button"), [&] {
|
||||
Common::ParamPackage modifier_param =
|
||||
Common::ParamPackage{analogs_param[analog_id].Get("modifier", "")};
|
||||
const bool toggle_value = !modifier_param.Get("toggle", false);
|
||||
modifier_param.Set("toggle", toggle_value);
|
||||
analogs_param[analog_id].Set("modifier", modifier_param.Serialize());
|
||||
analog_map_modifier_button[analog_id]->setText(
|
||||
ButtonToText(modifier_param));
|
||||
});
|
||||
context_menu.exec(
|
||||
analog_map_modifier_button[analog_id]->mapToGlobal(menu_location));
|
||||
});
|
||||
|
||||
@@ -60,6 +60,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
||||
#include <QPushButton>
|
||||
#include <QShortcut>
|
||||
#include <QStatusBar>
|
||||
#include <QString>
|
||||
#include <QSysInfo>
|
||||
#include <QUrl>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
@@ -3061,6 +3062,14 @@ int main(int argc, char* argv[]) {
|
||||
chdir(bin_path.c_str());
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
// Set the DISPLAY variable in order to open web browsers
|
||||
// TODO (lat9nq): Find a better solution for AppImages to start external applications
|
||||
if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) {
|
||||
qputenv("DISPLAY", ":0");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Enables the core to make the qt created contexts current on std::threads
|
||||
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
|
||||
QApplication app(argc, argv);
|
||||
|
||||
Reference in New Issue
Block a user