Compare commits
122 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 23515e0ccc | |||
| 6205965df9 | |||
| 9eaccac674 | |||
| 6f16f54f10 | |||
| a91f92a89d | |||
| 705cccb1e4 | |||
| efef7b1517 | |||
| b32b7c6e74 | |||
| 2d82b7f1a1 | |||
| 7c07941882 | |||
| bc51a9365b | |||
| 0b23ce6ef2 | |||
| 032b7d490d | |||
| 6e14edbcc2 | |||
| e6fee39ae7 | |||
| ca25a3845e | |||
| b5d54619cc | |||
| 98bbab8030 | |||
| a6b5528e9c | |||
| 0f4a611129 | |||
| 3828aa4927 | |||
| d3e9b45ce0 | |||
| 3579db425e | |||
| 78d3b54ea7 | |||
| 72f14ae21f | |||
| 3017be7855 | |||
| 02a33feef4 | |||
| 3eb8efc095 | |||
| c4fe83a7bc | |||
| 5872fc21fe | |||
| a980b4cbc1 | |||
| ae1f709658 | |||
| d11baf8bf8 | |||
| a927d8be52 | |||
| 38868e5750 | |||
| 2c9308954c | |||
| 0e1268e507 | |||
| 2f2df9a4a7 | |||
| 510838759f | |||
| 32343d820d | |||
| 82ecdd0104 | |||
| 32a2dcd415 | |||
| 39c97f1b65 | |||
| 41a4090320 | |||
| 32485917ba | |||
| 73fb3a304b | |||
| 00c66a7289 | |||
| da79ec9565 | |||
| b66ccaa376 | |||
| f5e2aec422 | |||
| 52340e94ac | |||
| fabdf5d385 | |||
| 74b4334d51 | |||
| 6ce5f3120b | |||
| 3bab5a5e4a | |||
| 9f54cd4dad | |||
| 1d1489da80 | |||
| bfe2e40882 | |||
| 15aeae3dd3 | |||
| 60da57b518 | |||
| 2ce3aedda8 | |||
| b8798a995b | |||
| 45dac6bc5c | |||
| 39ab33ee1c | |||
| e193aa3f53 | |||
| 25174afa79 | |||
| 544b15e8e4 | |||
| f2df941e8d | |||
| e0af4cdf98 | |||
| 406d298457 | |||
| 14a1181a97 | |||
| c27c76ed43 | |||
| e8855ed0fc | |||
| 0235915baa | |||
| 409fedaf97 | |||
| 182ac8a504 | |||
| 23d57ed4f7 | |||
| d11b04ed46 | |||
| 606e833d26 | |||
| b81af6ae9b | |||
| f77c897b8d | |||
| 1e65da971b | |||
| f98bf1025f | |||
| 20ed33b53b | |||
| a8674a7b86 | |||
| c6ba7a228d | |||
| c12eb814b4 | |||
| ef53b2fd08 | |||
| 928e9c09aa | |||
| 2bd903e021 | |||
| a5ed0c3df7 | |||
| 9bb5bf0b2b | |||
| 97ba520434 | |||
| d6474b4aca | |||
| 480e1fa987 | |||
| 7d1dca4c98 | |||
| 5865a10885 | |||
| a6e5b84d1f | |||
| 8ea749c1ca | |||
| 479605b3e5 | |||
| 9c5ed4408d | |||
| a7fe6dc232 | |||
| 811bff009e | |||
| 4514b80b3e | |||
| 7daea551c0 | |||
| 8434630dcc | |||
| c6a963c48e | |||
| 8272f53cf9 | |||
| 7236393114 | |||
| c7ed7d9427 | |||
| 977ceb4056 | |||
| cf137ea40b | |||
| 7d763f060e | |||
| 778f86989a | |||
| b19fe55f84 | |||
| 4f09f0aea4 | |||
| 69f38355ed | |||
| b1eada6079 | |||
| 442e48ef4c | |||
| 8ae7154541 | |||
| 44f10d9b9f | |||
| 7a59eeb5be |
Vendored
+57
-23
@@ -1,24 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
|
||||
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
<assembly manifestVersion="1.0"
|
||||
xmlns="urn:schemas-microsoft-com:asm.v1"
|
||||
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings>
|
||||
<!-- Windows 7/8/8.1/10 -->
|
||||
<dpiAware
|
||||
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
|
||||
true/pm
|
||||
</dpiAware>
|
||||
<!-- Windows 10, version 1607 or later -->
|
||||
<dpiAwareness
|
||||
xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||
PerMonitorV2
|
||||
</dpiAwareness>
|
||||
<!-- Windows 10, version 1703 or later -->
|
||||
<gdiScaling
|
||||
xmlns="http://schemas.microsoft.com/SMI/2017/WindowsSettings">
|
||||
true
|
||||
</gdiScaling>
|
||||
<ws2:longPathAware
|
||||
xmlns:ws3="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||
true
|
||||
</ws2:longPathAware>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
<compatibility
|
||||
xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
<!-- Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<!-- Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<!-- Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
<trustInfo
|
||||
xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<!--
|
||||
UAC settings:
|
||||
- app should run at same integrity level as calling process
|
||||
- app does not need to manipulate windows belonging to
|
||||
higher-integrity-level processes
|
||||
-->
|
||||
<requestedExecutionLevel
|
||||
level="asInvoker"
|
||||
uiAccess="false"
|
||||
/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</assembly>
|
||||
|
||||
@@ -67,7 +67,7 @@ s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
|
||||
}
|
||||
|
||||
static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) {
|
||||
const float volume{std::clamp(Settings::values.volume - (1.0f - game_volume), 0.0f, 1.0f)};
|
||||
const float volume{std::clamp(Settings::Volume() - (1.0f - game_volume), 0.0f, 1.0f)};
|
||||
|
||||
if (volume == 1.0f) {
|
||||
return;
|
||||
|
||||
@@ -60,6 +60,7 @@ void AppendCPUInfo(FieldCollection& fc) {
|
||||
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AES", Common::GetCPUCaps().aes);
|
||||
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX", Common::GetCPUCaps().avx);
|
||||
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX2", Common::GetCPUCaps().avx2);
|
||||
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX512", Common::GetCPUCaps().avx512);
|
||||
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_BMI1", Common::GetCPUCaps().bmi1);
|
||||
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_BMI2", Common::GetCPUCaps().bmi2);
|
||||
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_FMA", Common::GetCPUCaps().fma);
|
||||
|
||||
@@ -110,6 +110,11 @@ static CPUCaps Detect() {
|
||||
caps.bmi1 = true;
|
||||
if ((cpu_id[1] >> 8) & 1)
|
||||
caps.bmi2 = true;
|
||||
// Checks for AVX512F, AVX512CD, AVX512VL, AVX512DQ, AVX512BW (Intel Skylake-X/SP)
|
||||
if ((cpu_id[1] >> 16) & 1 && (cpu_id[1] >> 28) & 1 && (cpu_id[1] >> 31) & 1 &&
|
||||
(cpu_id[1] >> 17) & 1 && (cpu_id[1] >> 30) & 1) {
|
||||
caps.avx512 = caps.avx2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ struct CPUCaps {
|
||||
bool lzcnt;
|
||||
bool avx;
|
||||
bool avx2;
|
||||
bool avx512;
|
||||
bool bmi1;
|
||||
bool bmi2;
|
||||
bool fma;
|
||||
|
||||
@@ -606,11 +606,11 @@ endif()
|
||||
create_target_directory_groups(core)
|
||||
|
||||
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
|
||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus unicorn)
|
||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus unicorn zip)
|
||||
|
||||
if (YUZU_ENABLE_BOXCAT)
|
||||
target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT)
|
||||
target_link_libraries(core PRIVATE httplib nlohmann_json::nlohmann_json zip)
|
||||
target_link_libraries(core PRIVATE httplib nlohmann_json::nlohmann_json)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
case Dynarmic::A32::Exception::Breakpoint:
|
||||
break;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
|
||||
LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
|
||||
static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@@ -98,8 +98,8 @@ public:
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})",
|
||||
static_cast<std::size_t>(exception), pc);
|
||||
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
|
||||
static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ VirtualDir MiiModel() {
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_MID.size()>>(
|
||||
MiiModelData::SHAPE_MID, "ShapeMid.dat"));
|
||||
|
||||
return std::move(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace FileSys::SystemArchive
|
||||
|
||||
@@ -23,7 +23,7 @@ VirtualFile PackBFTTF(const std::array<u8, Size>& data, const std::string& name)
|
||||
|
||||
std::vector<u8> bfttf(Size + sizeof(u64));
|
||||
|
||||
u64 offset = 0;
|
||||
size_t offset = 0;
|
||||
Service::NS::EncryptSharedFont(vec, bfttf, offset);
|
||||
return std::make_shared<VectorVfsFile>(std::move(bfttf), name);
|
||||
}
|
||||
|
||||
@@ -282,18 +282,18 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
|
||||
}
|
||||
|
||||
std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
|
||||
std::vector<u8> buffer;
|
||||
std::vector<u8> buffer{};
|
||||
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_OR_EXECUTE_MSG(BufferDescriptorA().size() > buffer_index, { return buffer; },
|
||||
"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);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorX().size() > buffer_index, { return buffer; },
|
||||
"BufferDescriptorX invalid buffer_index {}", buffer_index);
|
||||
buffer.resize(BufferDescriptorX()[buffer_index].Size());
|
||||
memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size());
|
||||
}
|
||||
@@ -318,16 +318,16 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
|
||||
}
|
||||
|
||||
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);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorB().size() > buffer_index &&
|
||||
BufferDescriptorB()[buffer_index].Size() >= size,
|
||||
{ return 0; }, "BufferDescriptorB is invalid, index={}, size={}",
|
||||
buffer_index, size);
|
||||
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);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorC().size() > buffer_index &&
|
||||
BufferDescriptorC()[buffer_index].Size() >= size,
|
||||
{ return 0; }, "BufferDescriptorC is invalid, index={}, size={}",
|
||||
buffer_index, size);
|
||||
memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
|
||||
}
|
||||
|
||||
@@ -338,16 +338,12 @@ std::size_t HLERequestContext::GetReadBufferSize(std::size_t buffer_index) const
|
||||
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);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorA().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorA invalid buffer_index {}", 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);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorX().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorX invalid buffer_index {}", buffer_index);
|
||||
return BufferDescriptorX()[buffer_index].Size();
|
||||
}
|
||||
}
|
||||
@@ -356,14 +352,15 @@ std::size_t HLERequestContext::GetWriteBufferSize(std::size_t buffer_index) cons
|
||||
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);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorB().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorB invalid buffer_index {}", buffer_index);
|
||||
return BufferDescriptorB()[buffer_index].Size();
|
||||
} else {
|
||||
ASSERT_MSG(BufferDescriptorC().size() > buffer_index,
|
||||
"BufferDescriptorC invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorC().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorC invalid buffer_index {}", buffer_index);
|
||||
return BufferDescriptorC()[buffer_index].Size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string HLERequestContext::Description() const {
|
||||
|
||||
@@ -104,7 +104,7 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa
|
||||
// Ensure that we don't leave anything un-freed
|
||||
auto group_guard = detail::ScopeExit([&] {
|
||||
for (const auto& it : page_list.Nodes()) {
|
||||
const auto min_num_pages{std::min(
|
||||
const auto min_num_pages{std::min<size_t>(
|
||||
it.GetNumPages(), (chosen_manager.GetEndAddress() - it.GetAddress()) / PageSize)};
|
||||
chosen_manager.Free(it.GetAddress(), min_num_pages);
|
||||
}
|
||||
@@ -139,7 +139,6 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa
|
||||
}
|
||||
|
||||
// Only succeed if we allocated as many pages as we wanted
|
||||
ASSERT(num_pages >= 0);
|
||||
if (num_pages) {
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
@@ -165,7 +164,7 @@ ResultCode MemoryManager::Free(PageLinkedList& page_list, std::size_t num_pages,
|
||||
|
||||
// Free all of the pages
|
||||
for (const auto& it : page_list.Nodes()) {
|
||||
const auto min_num_pages{std::min(
|
||||
const auto min_num_pages{std::min<size_t>(
|
||||
it.GetNumPages(), (chosen_manager.GetEndAddress() - it.GetAddress()) / PageSize)};
|
||||
chosen_manager.Free(it.GetAddress(), min_num_pages);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,218 @@ static constexpr u32 SanitizeJPEGSize(std::size_t size) {
|
||||
return static_cast<u32>(std::min(size, max_jpeg_image_size));
|
||||
}
|
||||
|
||||
class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> {
|
||||
public:
|
||||
explicit IManagerForSystemService(Common::UUID user_id)
|
||||
: ServiceFramework("IManagerForSystemService") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "CheckAvailability"},
|
||||
{1, nullptr, "GetAccountId"},
|
||||
{2, nullptr, "EnsureIdTokenCacheAsync"},
|
||||
{3, nullptr, "LoadIdTokenCache"},
|
||||
{100, nullptr, "SetSystemProgramIdentification"},
|
||||
{101, nullptr, "RefreshNotificationTokenAsync"}, // 7.0.0+
|
||||
{110, nullptr, "GetServiceEntryRequirementCache"}, // 4.0.0+
|
||||
{111, nullptr, "InvalidateServiceEntryRequirementCache"}, // 4.0.0+
|
||||
{112, nullptr, "InvalidateTokenCache"}, // 4.0.0 - 6.2.0
|
||||
{113, nullptr, "GetServiceEntryRequirementCacheForOnlinePlay"}, // 6.1.0+
|
||||
{120, nullptr, "GetNintendoAccountId"},
|
||||
{121, nullptr, "CalculateNintendoAccountAuthenticationFingerprint"}, // 9.0.0+
|
||||
{130, nullptr, "GetNintendoAccountUserResourceCache"},
|
||||
{131, nullptr, "RefreshNintendoAccountUserResourceCacheAsync"},
|
||||
{132, nullptr, "RefreshNintendoAccountUserResourceCacheAsyncIfSecondsElapsed"},
|
||||
{133, nullptr, "GetNintendoAccountVerificationUrlCache"}, // 9.0.0+
|
||||
{134, nullptr, "RefreshNintendoAccountVerificationUrlCache"}, // 9.0.0+
|
||||
{135, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsyncIfSecondsElapsed"}, // 9.0.0+
|
||||
{140, nullptr, "GetNetworkServiceLicenseCache"}, // 5.0.0+
|
||||
{141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+
|
||||
{142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+
|
||||
{150, nullptr, "CreateAuthorizationRequest"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
// 3.0.0+
|
||||
class IFloatingRegistrationRequest final : public ServiceFramework<IFloatingRegistrationRequest> {
|
||||
public:
|
||||
explicit IFloatingRegistrationRequest(Common::UUID user_id)
|
||||
: ServiceFramework("IFloatingRegistrationRequest") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetSessionId"},
|
||||
{12, nullptr, "GetAccountId"},
|
||||
{13, nullptr, "GetLinkedNintendoAccountId"},
|
||||
{14, nullptr, "GetNickname"},
|
||||
{15, nullptr, "GetProfileImage"},
|
||||
{21, nullptr, "LoadIdTokenCache"},
|
||||
{100, nullptr, "RegisterUser"}, // [1.0.0-3.0.2] RegisterAsync
|
||||
{101, nullptr, "RegisterUserWithUid"}, // [1.0.0-3.0.2] RegisterWithUidAsync
|
||||
{102, nullptr, "RegisterNetworkServiceAccountAsync"}, // 4.0.0+
|
||||
{103, nullptr, "RegisterNetworkServiceAccountWithUidAsync"}, // 4.0.0+
|
||||
{110, nullptr, "SetSystemProgramIdentification"},
|
||||
{111, nullptr, "EnsureIdTokenCacheAsync"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class IAdministrator final : public ServiceFramework<IAdministrator> {
|
||||
public:
|
||||
explicit IAdministrator(Common::UUID user_id) : ServiceFramework("IAdministrator") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "CheckAvailability"},
|
||||
{1, nullptr, "GetAccountId"},
|
||||
{2, nullptr, "EnsureIdTokenCacheAsync"},
|
||||
{3, nullptr, "LoadIdTokenCache"},
|
||||
{100, nullptr, "SetSystemProgramIdentification"},
|
||||
{101, nullptr, "RefreshNotificationTokenAsync"}, // 7.0.0+
|
||||
{110, nullptr, "GetServiceEntryRequirementCache"}, // 4.0.0+
|
||||
{111, nullptr, "InvalidateServiceEntryRequirementCache"}, // 4.0.0+
|
||||
{112, nullptr, "InvalidateTokenCache"}, // 4.0.0 - 6.2.0
|
||||
{113, nullptr, "GetServiceEntryRequirementCacheForOnlinePlay"}, // 6.1.0+
|
||||
{120, nullptr, "GetNintendoAccountId"},
|
||||
{121, nullptr, "CalculateNintendoAccountAuthenticationFingerprint"}, // 9.0.0+
|
||||
{130, nullptr, "GetNintendoAccountUserResourceCache"},
|
||||
{131, nullptr, "RefreshNintendoAccountUserResourceCacheAsync"},
|
||||
{132, nullptr, "RefreshNintendoAccountUserResourceCacheAsyncIfSecondsElapsed"},
|
||||
{133, nullptr, "GetNintendoAccountVerificationUrlCache"}, // 9.0.0+
|
||||
{134, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsync"}, // 9.0.0+
|
||||
{135, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsyncIfSecondsElapsed"}, // 9.0.0+
|
||||
{140, nullptr, "GetNetworkServiceLicenseCache"}, // 5.0.0+
|
||||
{141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+
|
||||
{142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+
|
||||
{150, nullptr, "CreateAuthorizationRequest"},
|
||||
{200, nullptr, "IsRegistered"},
|
||||
{201, nullptr, "RegisterAsync"},
|
||||
{202, nullptr, "UnregisterAsync"},
|
||||
{203, nullptr, "DeleteRegistrationInfoLocally"},
|
||||
{220, nullptr, "SynchronizeProfileAsync"},
|
||||
{221, nullptr, "UploadProfileAsync"},
|
||||
{222, nullptr, "SynchronizaProfileAsyncIfSecondsElapsed"},
|
||||
{250, nullptr, "IsLinkedWithNintendoAccount"},
|
||||
{251, nullptr, "CreateProcedureToLinkWithNintendoAccount"},
|
||||
{252, nullptr, "ResumeProcedureToLinkWithNintendoAccount"},
|
||||
{255, nullptr, "CreateProcedureToUpdateLinkageStateOfNintendoAccount"},
|
||||
{256, nullptr, "ResumeProcedureToUpdateLinkageStateOfNintendoAccount"},
|
||||
{260, nullptr, "CreateProcedureToLinkNnidWithNintendoAccount"}, // 3.0.0+
|
||||
{261, nullptr, "ResumeProcedureToLinkNnidWithNintendoAccount"}, // 3.0.0+
|
||||
{280, nullptr, "ProxyProcedureToAcquireApplicationAuthorizationForNintendoAccount"},
|
||||
{290, nullptr, "GetRequestForNintendoAccountUserResourceView"}, // 8.0.0+
|
||||
{300, nullptr, "TryRecoverNintendoAccountUserStateAsync"}, // 6.0.0+
|
||||
{400, nullptr, "IsServiceEntryRequirementCacheRefreshRequiredForOnlinePlay"}, // 6.1.0+
|
||||
{401, nullptr, "RefreshServiceEntryRequirementCacheForOnlinePlayAsync"}, // 6.1.0+
|
||||
{900, nullptr, "GetAuthenticationInfoForWin"}, // 9.0.0+
|
||||
{901, nullptr, "ImportAsyncForWin"}, // 9.0.0+
|
||||
{997, nullptr, "DebugUnlinkNintendoAccountAsync"},
|
||||
{998, nullptr, "DebugSetAvailabilityErrorDetail"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class IAuthorizationRequest final : public ServiceFramework<IAuthorizationRequest> {
|
||||
public:
|
||||
explicit IAuthorizationRequest(Common::UUID user_id)
|
||||
: ServiceFramework("IAuthorizationRequest") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetSessionId"},
|
||||
{10, nullptr, "InvokeWithoutInteractionAsync"},
|
||||
{19, nullptr, "IsAuthorized"},
|
||||
{20, nullptr, "GetAuthorizationCode"},
|
||||
{21, nullptr, "GetIdToken"},
|
||||
{22, nullptr, "GetState"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class IOAuthProcedure final : public ServiceFramework<IOAuthProcedure> {
|
||||
public:
|
||||
explicit IOAuthProcedure(Common::UUID user_id) : ServiceFramework("IOAuthProcedure") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "PrepareAsync"},
|
||||
{1, nullptr, "GetRequest"},
|
||||
{2, nullptr, "ApplyResponse"},
|
||||
{3, nullptr, "ApplyResponseAsync"},
|
||||
{10, nullptr, "Suspend"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
// 3.0.0+
|
||||
class IOAuthProcedureForExternalNsa final : public ServiceFramework<IOAuthProcedureForExternalNsa> {
|
||||
public:
|
||||
explicit IOAuthProcedureForExternalNsa(Common::UUID user_id)
|
||||
: ServiceFramework("IOAuthProcedureForExternalNsa") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "PrepareAsync"},
|
||||
{1, nullptr, "GetRequest"},
|
||||
{2, nullptr, "ApplyResponse"},
|
||||
{3, nullptr, "ApplyResponseAsync"},
|
||||
{10, nullptr, "Suspend"},
|
||||
{100, nullptr, "GetAccountId"},
|
||||
{101, nullptr, "GetLinkedNintendoAccountId"},
|
||||
{102, nullptr, "GetNickname"},
|
||||
{103, nullptr, "GetProfileImage"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class IOAuthProcedureForNintendoAccountLinkage final
|
||||
: public ServiceFramework<IOAuthProcedureForNintendoAccountLinkage> {
|
||||
public:
|
||||
explicit IOAuthProcedureForNintendoAccountLinkage(Common::UUID user_id)
|
||||
: ServiceFramework("IOAuthProcedureForNintendoAccountLinkage") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "PrepareAsync"},
|
||||
{1, nullptr, "GetRequest"},
|
||||
{2, nullptr, "ApplyResponse"},
|
||||
{3, nullptr, "ApplyResponseAsync"},
|
||||
{10, nullptr, "Suspend"},
|
||||
{100, nullptr, "GetRequestWithTheme"},
|
||||
{101, nullptr, "IsNetworkServiceAccountReplaced"},
|
||||
{199, nullptr, "GetUrlForIntroductionOfExtraMembership"}, // 2.0.0 - 5.1.0
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class INotifier final : public ServiceFramework<INotifier> {
|
||||
public:
|
||||
explicit INotifier(Common::UUID user_id) : ServiceFramework("INotifier") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetSystemEvent"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class IProfileCommon : public ServiceFramework<IProfileCommon> {
|
||||
public:
|
||||
explicit IProfileCommon(const char* name, bool editor_commands, Common::UUID user_id,
|
||||
@@ -226,6 +438,54 @@ public:
|
||||
: IProfileCommon("IProfileEditor", true, user_id, profile_manager) {}
|
||||
};
|
||||
|
||||
class IAsyncContext final : public ServiceFramework<IAsyncContext> {
|
||||
public:
|
||||
explicit IAsyncContext(Common::UUID user_id) : ServiceFramework("IAsyncContext") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetSystemEvent"},
|
||||
{1, nullptr, "Cancel"},
|
||||
{2, nullptr, "HasDone"},
|
||||
{3, nullptr, "GetResult"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class ISessionObject final : public ServiceFramework<ISessionObject> {
|
||||
public:
|
||||
explicit ISessionObject(Common::UUID user_id) : ServiceFramework("ISessionObject") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{999, nullptr, "Dummy"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class IGuestLoginRequest final : public ServiceFramework<IGuestLoginRequest> {
|
||||
public:
|
||||
explicit IGuestLoginRequest(Common::UUID) : ServiceFramework("IGuestLoginRequest") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetSessionId"},
|
||||
{11, nullptr, "Unknown"}, // 1.0.0 - 2.3.0 (the name is blank on Switchbrew)
|
||||
{12, nullptr, "GetAccountId"},
|
||||
{13, nullptr, "GetLinkedNintendoAccountId"},
|
||||
{14, nullptr, "GetNickname"},
|
||||
{15, nullptr, "GetProfileImage"},
|
||||
{21, nullptr, "LoadIdTokenCache"}, // 3.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
|
||||
public:
|
||||
explicit IManagerForApplication(Common::UUID user_id)
|
||||
@@ -265,6 +525,87 @@ private:
|
||||
Common::UUID user_id;
|
||||
};
|
||||
|
||||
// 6.0.0+
|
||||
class IAsyncNetworkServiceLicenseKindContext final
|
||||
: public ServiceFramework<IAsyncNetworkServiceLicenseKindContext> {
|
||||
public:
|
||||
explicit IAsyncNetworkServiceLicenseKindContext(Common::UUID user_id)
|
||||
: ServiceFramework("IAsyncNetworkServiceLicenseKindContext") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetSystemEvent"},
|
||||
{1, nullptr, "Cancel"},
|
||||
{2, nullptr, "HasDone"},
|
||||
{3, nullptr, "GetResult"},
|
||||
{4, nullptr, "GetNetworkServiceLicenseKind"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
// 8.0.0+
|
||||
class IOAuthProcedureForUserRegistration final
|
||||
: public ServiceFramework<IOAuthProcedureForUserRegistration> {
|
||||
public:
|
||||
explicit IOAuthProcedureForUserRegistration(Common::UUID user_id)
|
||||
: ServiceFramework("IOAuthProcedureForUserRegistration") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "PrepareAsync"},
|
||||
{1, nullptr, "GetRequest"},
|
||||
{2, nullptr, "ApplyResponse"},
|
||||
{3, nullptr, "ApplyResponseAsync"},
|
||||
{10, nullptr, "Suspend"},
|
||||
{100, nullptr, "GetAccountId"},
|
||||
{101, nullptr, "GetLinkedNintendoAccountId"},
|
||||
{102, nullptr, "GetNickname"},
|
||||
{103, nullptr, "GetProfileImage"},
|
||||
{110, nullptr, "RegisterUserAsync"},
|
||||
{111, nullptr, "GetUid"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class DAUTH_O final : public ServiceFramework<DAUTH_O> {
|
||||
public:
|
||||
explicit DAUTH_O(Common::UUID) : ServiceFramework("dauth:o") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "EnsureAuthenticationTokenCacheAsync"}, // [5.0.0-5.1.0] GeneratePostData
|
||||
{1, nullptr, "LoadAuthenticationTokenCache"}, // 6.0.0+
|
||||
{2, nullptr, "InvalidateAuthenticationTokenCache"}, // 6.0.0+
|
||||
{10, nullptr, "EnsureEdgeTokenCacheAsync"}, // 6.0.0+
|
||||
{11, nullptr, "LoadEdgeTokenCache"}, // 6.0.0+
|
||||
{12, nullptr, "InvalidateEdgeTokenCache"}, // 6.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
// 6.0.0+
|
||||
class IAsyncResult final : public ServiceFramework<IAsyncResult> {
|
||||
public:
|
||||
explicit IAsyncResult(Common::UUID user_id) : ServiceFramework("IAsyncResult") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetResult"},
|
||||
{1, nullptr, "Cancel"},
|
||||
{2, nullptr, "IsAvailable"},
|
||||
{3, nullptr, "GetSystemEvent"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
|
||||
@@ -13,8 +13,8 @@ ACC_AA::ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{0, nullptr, "EnsureCacheAsync"},
|
||||
{1, nullptr, "LoadCache"},
|
||||
{2, nullptr, "GetDeviceAccountId"},
|
||||
{50, nullptr, "RegisterNotificationTokenAsync"},
|
||||
{51, nullptr, "UnregisterNotificationTokenAsync"},
|
||||
{50, nullptr, "RegisterNotificationTokenAsync"}, // 1.0.0 - 6.2.0
|
||||
{51, nullptr, "UnregisterNotificationTokenAsync"}, // 1.0.0 - 6.2.0
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -17,28 +17,28 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{3, &ACC_SU::ListOpenUsers, "ListOpenUsers"},
|
||||
{4, &ACC_SU::GetLastOpenedUser, "GetLastOpenedUser"},
|
||||
{5, &ACC_SU::GetProfile, "GetProfile"},
|
||||
{6, nullptr, "GetProfileDigest"},
|
||||
{6, nullptr, "GetProfileDigest"}, // 3.0.0+
|
||||
{50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
|
||||
{51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
|
||||
{60, nullptr, "ListOpenContextStoredUsers"},
|
||||
{99, nullptr, "DebugActivateOpenContextRetention"},
|
||||
{60, nullptr, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0
|
||||
{99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+
|
||||
{100, nullptr, "GetUserRegistrationNotifier"},
|
||||
{101, nullptr, "GetUserStateChangeNotifier"},
|
||||
{102, nullptr, "GetBaasAccountManagerForSystemService"},
|
||||
{103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
|
||||
{104, nullptr, "GetProfileUpdateNotifier"},
|
||||
{105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
|
||||
{106, nullptr, "GetProfileSyncNotifier"},
|
||||
{105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+
|
||||
{106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+
|
||||
{110, nullptr, "StoreSaveDataThumbnail"},
|
||||
{111, nullptr, "ClearSaveDataThumbnail"},
|
||||
{112, nullptr, "LoadSaveDataThumbnail"},
|
||||
{113, nullptr, "GetSaveDataThumbnailExistence"},
|
||||
{120, nullptr, "ListOpenUsersInApplication"},
|
||||
{130, nullptr, "ActivateOpenContextRetention"},
|
||||
{140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"},
|
||||
{150, nullptr, "AuthenticateApplicationAsync"},
|
||||
{190, nullptr, "GetUserLastOpenedApplication"},
|
||||
{191, nullptr, "ActivateOpenContextHolder"},
|
||||
{113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+
|
||||
{120, nullptr, "ListOpenUsersInApplication"}, // 10.0.0+
|
||||
{130, nullptr, "ActivateOpenContextRetention"}, // 6.0.0+
|
||||
{140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+
|
||||
{150, nullptr, "AuthenticateApplicationAsync"}, // 10.0.0+
|
||||
{190, nullptr, "GetUserLastOpenedApplication"}, // 1.0.0 - 9.2.0
|
||||
{191, nullptr, "ActivateOpenContextHolder"}, // 7.0.0+
|
||||
{200, nullptr, "BeginUserRegistration"},
|
||||
{201, nullptr, "CompleteUserRegistration"},
|
||||
{202, nullptr, "CancelUserRegistration"},
|
||||
@@ -46,15 +46,15 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{204, nullptr, "SetUserPosition"},
|
||||
{205, &ACC_SU::GetProfileEditor, "GetProfileEditor"},
|
||||
{206, nullptr, "CompleteUserRegistrationForcibly"},
|
||||
{210, nullptr, "CreateFloatingRegistrationRequest"},
|
||||
{211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"},
|
||||
{212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"},
|
||||
{210, nullptr, "CreateFloatingRegistrationRequest"}, // 3.0.0+
|
||||
{211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"}, // 8.0.0+
|
||||
{212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"}, // 8.0.0+
|
||||
{230, nullptr, "AuthenticateServiceAsync"},
|
||||
{250, nullptr, "GetBaasAccountAdministrator"},
|
||||
{290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"},
|
||||
{291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"},
|
||||
{291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"}, // 3.0.0+
|
||||
{299, nullptr, "SuspendBackgroundDaemon"},
|
||||
{997, nullptr, "DebugInvalidateTokenCacheForUser"},
|
||||
{997, nullptr, "DebugInvalidateTokenCacheForUser"}, // 3.0.0+
|
||||
{998, nullptr, "DebugSetUserStateClose"},
|
||||
{999, nullptr, "DebugSetUserStateOpen"},
|
||||
};
|
||||
|
||||
@@ -17,23 +17,23 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{3, &ACC_U0::ListOpenUsers, "ListOpenUsers"},
|
||||
{4, &ACC_U0::GetLastOpenedUser, "GetLastOpenedUser"},
|
||||
{5, &ACC_U0::GetProfile, "GetProfile"},
|
||||
{6, nullptr, "GetProfileDigest"},
|
||||
{6, nullptr, "GetProfileDigest"}, // 3.0.0+
|
||||
{50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
|
||||
{51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
|
||||
{60, nullptr, "ListOpenContextStoredUsers"},
|
||||
{99, nullptr, "DebugActivateOpenContextRetention"},
|
||||
{60, nullptr, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0
|
||||
{99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+
|
||||
{100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"},
|
||||
{101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"},
|
||||
{102, nullptr, "AuthenticateApplicationAsync"},
|
||||
{103, nullptr, "CheckNetworkServiceAvailabilityAsync"},
|
||||
{103, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+
|
||||
{110, nullptr, "StoreSaveDataThumbnail"},
|
||||
{111, nullptr, "ClearSaveDataThumbnail"},
|
||||
{120, nullptr, "CreateGuestLoginRequest"},
|
||||
{130, nullptr, "LoadOpenContext"},
|
||||
{131, nullptr, "ListOpenContextStoredUsers"},
|
||||
{140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"},
|
||||
{141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"},
|
||||
{150, &ACC_U0::IsUserAccountSwitchLocked, "IsUserAccountSwitchLocked"},
|
||||
{130, nullptr, "LoadOpenContext"}, // 5.0.0+
|
||||
{131, nullptr, "ListOpenContextStoredUsers"}, // 6.0.0+
|
||||
{140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+
|
||||
{141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+
|
||||
{150, &ACC_U0::IsUserAccountSwitchLocked, "IsUserAccountSwitchLocked"}, // 6.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -17,28 +17,29 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{3, &ACC_U1::ListOpenUsers, "ListOpenUsers"},
|
||||
{4, &ACC_U1::GetLastOpenedUser, "GetLastOpenedUser"},
|
||||
{5, &ACC_U1::GetProfile, "GetProfile"},
|
||||
{6, nullptr, "GetProfileDigest"},
|
||||
{6, nullptr, "GetProfileDigest"}, // 3.0.0+
|
||||
{50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
|
||||
{51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
|
||||
{60, nullptr, "ListOpenContextStoredUsers"},
|
||||
{99, nullptr, "DebugActivateOpenContextRetention"},
|
||||
{60, nullptr, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0
|
||||
{99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+
|
||||
{100, nullptr, "GetUserRegistrationNotifier"},
|
||||
{101, nullptr, "GetUserStateChangeNotifier"},
|
||||
{102, nullptr, "GetBaasAccountManagerForSystemService"},
|
||||
{103, nullptr, "GetProfileUpdateNotifier"},
|
||||
{104, nullptr, "CheckNetworkServiceAvailabilityAsync"},
|
||||
{105, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
|
||||
{106, nullptr, "GetProfileSyncNotifier"},
|
||||
{103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
|
||||
{104, nullptr, "GetProfileUpdateNotifier"},
|
||||
{105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+
|
||||
{106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+
|
||||
{110, nullptr, "StoreSaveDataThumbnail"},
|
||||
{111, nullptr, "ClearSaveDataThumbnail"},
|
||||
{112, nullptr, "LoadSaveDataThumbnail"},
|
||||
{113, nullptr, "GetSaveDataThumbnailExistence"},
|
||||
{130, nullptr, "ActivateOpenContextRetention"},
|
||||
{140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"},
|
||||
{150, nullptr, "AuthenticateApplicationAsync"},
|
||||
{190, nullptr, "GetUserLastOpenedApplication"},
|
||||
{191, nullptr, "ActivateOpenContextHolder"},
|
||||
{997, nullptr, "DebugInvalidateTokenCacheForUser"},
|
||||
{113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+
|
||||
{120, nullptr, "ListOpenUsersInApplication"}, // 10.0.0+
|
||||
{130, nullptr, "ActivateOpenContextRetention"}, // 6.0.0+
|
||||
{140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+
|
||||
{150, nullptr, "AuthenticateApplicationAsync"}, // 10.0.0+
|
||||
{190, nullptr, "GetUserLastOpenedApplication"}, // 1.0.0 - 9.2.0
|
||||
{191, nullptr, "ActivateOpenContextHolder"}, // 7.0.0+
|
||||
{997, nullptr, "DebugInvalidateTokenCacheForUser"}, // 3.0.0+
|
||||
{998, nullptr, "DebugSetUserStateClose"},
|
||||
{999, nullptr, "DebugSetUserStateOpen"},
|
||||
};
|
||||
|
||||
@@ -68,6 +68,7 @@ IWindowController::IWindowController(Core::System& system_)
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "CreateWindow"},
|
||||
{1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"},
|
||||
{2, nullptr, "GetAppletResourceUserIdOfCallerApplet"},
|
||||
{10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"},
|
||||
{11, nullptr, "ReleaseForegroundRights"},
|
||||
{12, nullptr, "RejectToChangeIntoBackground"},
|
||||
@@ -189,8 +190,8 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController"
|
||||
{5, nullptr, "GetLastForegroundCaptureImageEx"},
|
||||
{6, nullptr, "GetLastApplicationCaptureImageEx"},
|
||||
{7, nullptr, "GetCallerAppletCaptureImageEx"},
|
||||
{8, nullptr, "TakeScreenShotOfOwnLayer"}, // 2.0.0+
|
||||
{9, nullptr, "CopyBetweenCaptureBuffers"}, // 5.0.0+
|
||||
{8, nullptr, "TakeScreenShotOfOwnLayer"},
|
||||
{9, nullptr, "CopyBetweenCaptureBuffers"},
|
||||
{10, nullptr, "AcquireLastApplicationCaptureBuffer"},
|
||||
{11, nullptr, "ReleaseLastApplicationCaptureBuffer"},
|
||||
{12, nullptr, "AcquireLastForegroundCaptureBuffer"},
|
||||
@@ -200,17 +201,14 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController"
|
||||
{16, nullptr, "AcquireLastApplicationCaptureBufferEx"},
|
||||
{17, nullptr, "AcquireLastForegroundCaptureBufferEx"},
|
||||
{18, nullptr, "AcquireCallerAppletCaptureBufferEx"},
|
||||
// 2.0.0+
|
||||
{20, nullptr, "ClearCaptureBuffer"},
|
||||
{21, nullptr, "ClearAppletTransitionBuffer"},
|
||||
// 4.0.0+
|
||||
{22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"},
|
||||
{23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"},
|
||||
{24, nullptr, "AcquireLastForegroundCaptureSharedBuffer"},
|
||||
{25, nullptr, "ReleaseLastForegroundCaptureSharedBuffer"},
|
||||
{26, nullptr, "AcquireCallerAppletCaptureSharedBuffer"},
|
||||
{27, nullptr, "ReleaseCallerAppletCaptureSharedBuffer"},
|
||||
// 6.0.0+
|
||||
{28, nullptr, "TakeScreenShotOfOwnLayerEx"},
|
||||
};
|
||||
// clang-format on
|
||||
@@ -225,7 +223,7 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "NotifyMessageToHomeMenuForDebug"},
|
||||
{1, nullptr, "OpenMainApplication"},
|
||||
{10, nullptr, "EmulateButtonEvent"},
|
||||
{10, nullptr, "PerformSystemButtonPressing"},
|
||||
{20, nullptr, "InvalidateTransitionLayer"},
|
||||
{30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
|
||||
{40, nullptr, "GetAppletResourceUsageInfo"},
|
||||
@@ -267,7 +265,7 @@ ISelfController::ISelfController(Core::System& system,
|
||||
{16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"},
|
||||
{17, nullptr, "SetControllerFirmwareUpdateSection"},
|
||||
{18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
|
||||
{19, &ISelfController::SetScreenShotImageOrientation, "SetScreenShotImageOrientation"},
|
||||
{19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"},
|
||||
{20, nullptr, "SetDesirableKeyboardLayout"},
|
||||
{40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
|
||||
{41, nullptr, "IsSystemBufferSharingEnabled"},
|
||||
@@ -443,7 +441,7 @@ void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext&
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) {
|
||||
void ISelfController::SetAlbumImageOrientation(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -607,6 +605,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system,
|
||||
{20, nullptr, "PushToGeneralChannel"},
|
||||
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
|
||||
{31, nullptr, "GetReaderLockAccessorEx"},
|
||||
{32, nullptr, "GetWriterLockAccessorEx"},
|
||||
{40, nullptr, "GetCradleFwVersion"},
|
||||
{50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
|
||||
{51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"},
|
||||
@@ -1132,6 +1131,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
{24, nullptr, "GetLaunchStorageInfoForDebug"},
|
||||
{25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
|
||||
{26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
|
||||
{27, nullptr, "CreateCacheStorage"},
|
||||
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
|
||||
{31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
|
||||
{32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
|
||||
@@ -1157,6 +1157,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
{120, nullptr, "ExecuteProgram"},
|
||||
{121, nullptr, "ClearUserChannel"},
|
||||
{122, nullptr, "UnpopToUserChannel"},
|
||||
{123, nullptr, "GetPreviousProgramIndex"},
|
||||
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
|
||||
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
|
||||
{140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
|
||||
{141, nullptr, "TryPopFromFriendInvitationStorageChannel"},
|
||||
|
||||
@@ -138,7 +138,7 @@ private:
|
||||
void SetFocusHandlingMode(Kernel::HLERequestContext& ctx);
|
||||
void SetRestartMessageEnabled(Kernel::HLERequestContext& ctx);
|
||||
void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx);
|
||||
void SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx);
|
||||
void SetAlbumImageOrientation(Kernel::HLERequestContext& ctx);
|
||||
void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx);
|
||||
void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);
|
||||
void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -30,7 +30,7 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
|
||||
config.sub_text.size());
|
||||
params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(),
|
||||
config.guide_text.size());
|
||||
params.initial_text = initial_text;
|
||||
params.initial_text = std::move(initial_text);
|
||||
params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit;
|
||||
params.password = static_cast<bool>(config.is_password);
|
||||
params.cursor_at_beginning = static_cast<bool>(config.initial_cursor_position);
|
||||
@@ -60,7 +60,7 @@ void SoftwareKeyboard::Initialize() {
|
||||
std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
|
||||
|
||||
const auto work_buffer_storage = broker.PopNormalDataToApplet();
|
||||
ASSERT(work_buffer_storage != nullptr);
|
||||
ASSERT_OR_EXECUTE(work_buffer_storage != nullptr, { return; });
|
||||
const auto& work_buffer = work_buffer_storage->GetData();
|
||||
|
||||
if (config.initial_string_size == 0)
|
||||
@@ -109,7 +109,7 @@ void SoftwareKeyboard::Execute() {
|
||||
|
||||
const auto parameters = ConvertToFrontendParameters(config, initial_text);
|
||||
|
||||
frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); },
|
||||
frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(std::move(text)); },
|
||||
parameters);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,17 +10,17 @@ SPSM::SPSM() : ServiceFramework{"spsm"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetState"},
|
||||
{1, nullptr, "SleepSystemAndWaitAwake"},
|
||||
{2, nullptr, "Unknown1"},
|
||||
{3, nullptr, "Unknown2"},
|
||||
{1, nullptr, "EnterSleep"},
|
||||
{2, nullptr, "GetLastWakeReason"},
|
||||
{3, nullptr, "Shutdown"},
|
||||
{4, nullptr, "GetNotificationMessageEventHandle"},
|
||||
{5, nullptr, "Unknown3"},
|
||||
{6, nullptr, "Unknown4"},
|
||||
{7, nullptr, "Unknown5"},
|
||||
{5, nullptr, "ReceiveNotificationMessage"},
|
||||
{6, nullptr, "AnalyzeLogForLastSleepWakeSequence"},
|
||||
{7, nullptr, "ResetEventLog"},
|
||||
{8, nullptr, "AnalyzePerformanceLogForLastSleepWakeSequence"},
|
||||
{9, nullptr, "ChangeHomeButtonLongPressingTime"},
|
||||
{10, nullptr, "Unknown6"},
|
||||
{11, nullptr, "Unknown7"},
|
||||
{10, nullptr, "PutErrorState"},
|
||||
{11, nullptr, "InvalidateCurrentHomeButtonPressing"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ AOC_U::AOC_U(Core::System& system)
|
||||
{6, nullptr, "PrepareAddOnContentByApplicationId"},
|
||||
{7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
|
||||
{8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
|
||||
{9, nullptr, "GetAddOnContentLostErrorCode"},
|
||||
{100, nullptr, "CreateEcPurchasedEventManager"},
|
||||
{101, nullptr, "CreatePermanentEcPurchasedEventManager"},
|
||||
};
|
||||
|
||||
@@ -14,6 +14,8 @@ BCAT::BCAT(Core::System& system, std::shared_ptr<Module> module,
|
||||
{0, &BCAT::CreateBcatService, "CreateBcatService"},
|
||||
{1, &BCAT::CreateDeliveryCacheStorageService, "CreateDeliveryCacheStorageService"},
|
||||
{2, &BCAT::CreateDeliveryCacheStorageServiceWithApplicationId, "CreateDeliveryCacheStorageServiceWithApplicationId"},
|
||||
{3, nullptr, "CreateDeliveryCacheProgressService"},
|
||||
{4, nullptr, "CreateDeliveryCacheProgressServiceWithApplicationId"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
|
||||
@@ -143,10 +143,13 @@ public:
|
||||
{20401, nullptr, "UnregisterSystemApplicationDeliveryTask"},
|
||||
{20410, nullptr, "SetSystemApplicationDeliveryTaskTimer"},
|
||||
{30100, &IBcatService::SetPassphrase, "SetPassphrase"},
|
||||
{30101, nullptr, "Unknown"},
|
||||
{30102, nullptr, "Unknown2"},
|
||||
{30200, nullptr, "RegisterBackgroundDeliveryTask"},
|
||||
{30201, nullptr, "UnregisterBackgroundDeliveryTask"},
|
||||
{30202, nullptr, "BlockDeliveryTask"},
|
||||
{30203, nullptr, "UnblockDeliveryTask"},
|
||||
{30210, nullptr, "SetDeliveryTaskTimer"},
|
||||
{30300, nullptr, "RegisterSystemApplicationDeliveryTasks"},
|
||||
{90100, nullptr, "EnumerateBackgroundDeliveryTask"},
|
||||
{90200, nullptr, "GetDeliveryList"},
|
||||
|
||||
@@ -23,9 +23,14 @@ public:
|
||||
{5, nullptr, "GetBoardPowerControlEvent"},
|
||||
{6, nullptr, "GetSleepButtonState"},
|
||||
{7, nullptr, "GetPowerEvent"},
|
||||
{8, nullptr, "Unknown1"},
|
||||
{9, nullptr, "Unknown2"},
|
||||
{10, nullptr, "Unknown3"},
|
||||
{8, nullptr, "CreateWakeupTimer"},
|
||||
{9, nullptr, "CancelWakeupTimer"},
|
||||
{10, nullptr, "EnableWakeupTimerOnDevice"},
|
||||
{11, nullptr, "CreateWakeupTimerEx"},
|
||||
{12, nullptr, "GetLastEnabledWakeupTimerType"},
|
||||
{13, nullptr, "CleanAllWakeupTimers"},
|
||||
{14, nullptr, "Unknown"},
|
||||
{15, nullptr, "Unknown2"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -38,10 +43,11 @@ public:
|
||||
explicit BPC_R() : ServiceFramework{"bpc:r"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetExternalRtcValue"},
|
||||
{1, nullptr, "SetExternalRtcValue"},
|
||||
{2, nullptr, "ReadExternalRtcResetFlag"},
|
||||
{3, nullptr, "ClearExternalRtcResetFlag"},
|
||||
{0, nullptr, "GetRtcTime"},
|
||||
{1, nullptr, "SetRtcTime"},
|
||||
{2, nullptr, "GetRtcResetDetected"},
|
||||
{3, nullptr, "ClearRtcResetDetected"},
|
||||
{4, nullptr, "SetUpRtcResetOnShutdown"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -58,102 +58,103 @@ public:
|
||||
{1, nullptr, "InitializeBluetooth"},
|
||||
{2, nullptr, "EnableBluetooth"},
|
||||
{3, nullptr, "DisableBluetooth"},
|
||||
{4, nullptr, "CleanupBluetooth"},
|
||||
{4, nullptr, "FinalizeBluetooth"},
|
||||
{5, nullptr, "GetAdapterProperties"},
|
||||
{6, nullptr, "GetAdapterProperty"},
|
||||
{7, nullptr, "SetAdapterProperty"},
|
||||
{8, nullptr, "StartDiscovery"},
|
||||
{9, nullptr, "CancelDiscovery"},
|
||||
{8, nullptr, "StartInquiry"},
|
||||
{9, nullptr, "StopInquiry"},
|
||||
{10, nullptr, "CreateBond"},
|
||||
{11, nullptr, "RemoveBond"},
|
||||
{12, nullptr, "CancelBond"},
|
||||
{13, nullptr, "PinReply"},
|
||||
{14, nullptr, "SspReply"},
|
||||
{13, nullptr, "RespondToPinRequest"},
|
||||
{14, nullptr, "RespondToSspRequest"},
|
||||
{15, nullptr, "GetEventInfo"},
|
||||
{16, nullptr, "InitializeHid"},
|
||||
{17, nullptr, "HidConnect"},
|
||||
{18, nullptr, "HidDisconnect"},
|
||||
{19, nullptr, "HidSendData"},
|
||||
{20, nullptr, "HidSendData2"},
|
||||
{21, nullptr, "HidSetReport"},
|
||||
{22, nullptr, "HidGetReport"},
|
||||
{23, nullptr, "HidWakeController"},
|
||||
{24, nullptr, "HidAddPairedDevice"},
|
||||
{25, nullptr, "HidGetPairedDevice"},
|
||||
{26, nullptr, "CleanupHid"},
|
||||
{27, nullptr, "HidGetEventInfo"},
|
||||
{28, nullptr, "ExtSetTsi"},
|
||||
{29, nullptr, "ExtSetBurstMode"},
|
||||
{30, nullptr, "ExtSetZeroRetran"},
|
||||
{31, nullptr, "ExtSetMcMode"},
|
||||
{32, nullptr, "ExtStartLlrMode"},
|
||||
{33, nullptr, "ExtExitLlrMode"},
|
||||
{34, nullptr, "ExtSetRadio"},
|
||||
{35, nullptr, "ExtSetVisibility"},
|
||||
{36, nullptr, "ExtSetTbfcScan"},
|
||||
{17, nullptr, "OpenHidConnection"},
|
||||
{18, nullptr, "CloseHidConnection"},
|
||||
{19, nullptr, "WriteHidData"},
|
||||
{20, nullptr, "WriteHidData2"},
|
||||
{21, nullptr, "SetHidReport"},
|
||||
{22, nullptr, "GetHidReport"},
|
||||
{23, nullptr, "TriggerConnection"},
|
||||
{24, nullptr, "AddPairedDeviceInfo"},
|
||||
{25, nullptr, "GetPairedDeviceInfo"},
|
||||
{26, nullptr, "FinalizeHid"},
|
||||
{27, nullptr, "GetHidEventInfo"},
|
||||
{28, nullptr, "SetTsi"},
|
||||
{29, nullptr, "EnableBurstMode"},
|
||||
{30, nullptr, "SetZeroRetransmission"},
|
||||
{31, nullptr, "EnableMcMode"},
|
||||
{32, nullptr, "EnableLlrScan"},
|
||||
{33, nullptr, "DisableLlrScan"},
|
||||
{34, nullptr, "EnableRadio"},
|
||||
{35, nullptr, "SetVisibility"},
|
||||
{36, nullptr, "EnableTbfcScan"},
|
||||
{37, nullptr, "RegisterHidReportEvent"},
|
||||
{38, nullptr, "HidGetReportEventInfo"},
|
||||
{38, nullptr, "GetHidReportEventInfo"},
|
||||
{39, nullptr, "GetLatestPlr"},
|
||||
{40, nullptr, "ExtGetPendingConnections"},
|
||||
{40, nullptr, "GetPendingConnections"},
|
||||
{41, nullptr, "GetChannelMap"},
|
||||
{42, nullptr, "EnableBluetoothBoostSetting"},
|
||||
{43, nullptr, "IsBluetoothBoostSettingEnabled"},
|
||||
{44, nullptr, "EnableBluetoothAfhSetting"},
|
||||
{45, nullptr, "IsBluetoothAfhSettingEnabled"},
|
||||
{46, nullptr, "InitializeBluetoothLe"},
|
||||
{47, nullptr, "EnableBluetoothLe"},
|
||||
{48, nullptr, "DisableBluetoothLe"},
|
||||
{49, nullptr, "CleanupBluetoothLe"},
|
||||
{50, nullptr, "SetLeVisibility"},
|
||||
{51, nullptr, "SetLeConnectionParameter"},
|
||||
{52, nullptr, "SetLeDefaultConnectionParameter"},
|
||||
{53, nullptr, "SetLeAdvertiseData"},
|
||||
{54, nullptr, "SetLeAdvertiseParameter"},
|
||||
{55, nullptr, "StartLeScan"},
|
||||
{56, nullptr, "StopLeScan"},
|
||||
{57, nullptr, "AddLeScanFilterCondition"},
|
||||
{58, nullptr, "DeleteLeScanFilterCondition"},
|
||||
{59, nullptr, "DeleteLeScanFilter"},
|
||||
{60, nullptr, "ClearLeScanFilters"},
|
||||
{61, nullptr, "EnableLeScanFilter"},
|
||||
{62, nullptr, "RegisterLeClient"},
|
||||
{63, nullptr, "UnregisterLeClient"},
|
||||
{64, nullptr, "UnregisterLeClientAll"},
|
||||
{65, nullptr, "LeClientConnect"},
|
||||
{66, nullptr, "LeClientCancelConnection"},
|
||||
{67, nullptr, "LeClientDisconnect"},
|
||||
{68, nullptr, "LeClientGetAttributes"},
|
||||
{69, nullptr, "LeClientDiscoverService"},
|
||||
{70, nullptr, "LeClientConfigureMtu"},
|
||||
{71, nullptr, "RegisterLeServer"},
|
||||
{72, nullptr, "UnregisterLeServer"},
|
||||
{73, nullptr, "LeServerConnect"},
|
||||
{74, nullptr, "LeServerDisconnect"},
|
||||
{75, nullptr, "CreateLeService"},
|
||||
{76, nullptr, "StartLeService"},
|
||||
{77, nullptr, "AddLeCharacteristic"},
|
||||
{78, nullptr, "AddLeDescriptor"},
|
||||
{79, nullptr, "GetLeCoreEventInfo"},
|
||||
{80, nullptr, "LeGetFirstCharacteristic"},
|
||||
{81, nullptr, "LeGetNextCharacteristic"},
|
||||
{82, nullptr, "LeGetFirstDescriptor"},
|
||||
{83, nullptr, "LeGetNextDescriptor"},
|
||||
{84, nullptr, "RegisterLeCoreDataPath"},
|
||||
{85, nullptr, "UnregisterLeCoreDataPath"},
|
||||
{86, nullptr, "RegisterLeHidDataPath"},
|
||||
{87, nullptr, "UnregisterLeHidDataPath"},
|
||||
{88, nullptr, "RegisterLeDataPath"},
|
||||
{89, nullptr, "UnregisterLeDataPath"},
|
||||
{90, nullptr, "LeClientReadCharacteristic"},
|
||||
{91, nullptr, "LeClientReadDescriptor"},
|
||||
{92, nullptr, "LeClientWriteCharacteristic"},
|
||||
{93, nullptr, "LeClientWriteDescriptor"},
|
||||
{94, nullptr, "LeClientRegisterNotification"},
|
||||
{95, nullptr, "LeClientDeregisterNotification"},
|
||||
{42, nullptr, "EnableTxPowerBoostSetting"},
|
||||
{43, nullptr, "IsTxPowerBoostSettingEnabled"},
|
||||
{44, nullptr, "EnableAfhSetting"},
|
||||
{45, nullptr, "IsAfhSettingEnabled"},
|
||||
{46, nullptr, "InitializeBle"},
|
||||
{47, nullptr, "EnableBle"},
|
||||
{48, nullptr, "DisableBle"},
|
||||
{49, nullptr, "FinalizeBle"},
|
||||
{50, nullptr, "SetBleVisibility"},
|
||||
{51, nullptr, "SetBleConnectionParameter"},
|
||||
{52, nullptr, "SetBleDefaultConnectionParameter"},
|
||||
{53, nullptr, "SetBleAdvertiseData"},
|
||||
{54, nullptr, "SetBleAdvertiseParameter"},
|
||||
{55, nullptr, "StartBleScan"},
|
||||
{56, nullptr, "StopBleScan"},
|
||||
{57, nullptr, "AddBleScanFilterCondition"},
|
||||
{58, nullptr, "DeleteBleScanFilterCondition"},
|
||||
{59, nullptr, "DeleteBleScanFilter"},
|
||||
{60, nullptr, "ClearBleScanFilters"},
|
||||
{61, nullptr, "EnableBleScanFilter"},
|
||||
{62, nullptr, "RegisterGattClient"},
|
||||
{63, nullptr, "UnregisterGattClient"},
|
||||
{64, nullptr, "UnregisterAllGattClients"},
|
||||
{65, nullptr, "ConnectGattServer"},
|
||||
{66, nullptr, "CancelConnectGattServer"},
|
||||
{67, nullptr, "DisconnectGattServer"},
|
||||
{68, nullptr, "GetGattAttribute"},
|
||||
{69, nullptr, "GetGattService"},
|
||||
{70, nullptr, "ConfigureAttMtu"},
|
||||
{71, nullptr, "RegisterGattServer"},
|
||||
{72, nullptr, "UnregisterGattServer"},
|
||||
{73, nullptr, "ConnectGattClient"},
|
||||
{74, nullptr, "DisconnectGattClient"},
|
||||
{75, nullptr, "AddGattService"},
|
||||
{76, nullptr, "EnableGattService"},
|
||||
{77, nullptr, "AddGattCharacteristic"},
|
||||
{78, nullptr, "AddGattDescriptor"},
|
||||
{79, nullptr, "GetBleManagedEventInfo"},
|
||||
{80, nullptr, "GetGattFirstCharacteristic"},
|
||||
{81, nullptr, "GetGattNextCharacteristic"},
|
||||
{82, nullptr, "GetGattFirstDescriptor"},
|
||||
{83, nullptr, "GetGattNextDescriptor"},
|
||||
{84, nullptr, "RegisterGattManagedDataPath"},
|
||||
{85, nullptr, "UnregisterGattManagedDataPath"},
|
||||
{86, nullptr, "RegisterGattHidDataPath"},
|
||||
{87, nullptr, "UnregisterGattHidDataPath"},
|
||||
{88, nullptr, "RegisterGattDataPath"},
|
||||
{89, nullptr, "UnregisterGattDataPath"},
|
||||
{90, nullptr, "ReadGattCharacteristic"},
|
||||
{91, nullptr, "ReadGattDescriptor"},
|
||||
{92, nullptr, "WriteGattCharacteristic"},
|
||||
{93, nullptr, "WriteGattDescriptor"},
|
||||
{94, nullptr, "RegisterGattNotification"},
|
||||
{95, nullptr, "UnregisterGattNotification"},
|
||||
{96, nullptr, "GetLeHidEventInfo"},
|
||||
{97, nullptr, "RegisterBleHidEvent"},
|
||||
{98, nullptr, "SetLeScanParameter"},
|
||||
{256, nullptr, "GetIsManufacturingMode"},
|
||||
{98, nullptr, "SetBleScanParameter"},
|
||||
{99, nullptr, "MoveToSecondaryPiconet"},
|
||||
{256, nullptr, "IsManufacturingMode"},
|
||||
{257, nullptr, "EmulateBluetoothCrash"},
|
||||
{258, nullptr, "GetBleChannelMap"},
|
||||
};
|
||||
|
||||
@@ -132,66 +132,71 @@ public:
|
||||
explicit BTM() : ServiceFramework{"btm"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown1"},
|
||||
{1, nullptr, "Unknown2"},
|
||||
{2, nullptr, "RegisterSystemEventForConnectedDeviceCondition"},
|
||||
{3, nullptr, "Unknown3"},
|
||||
{4, nullptr, "Unknown4"},
|
||||
{5, nullptr, "Unknown5"},
|
||||
{6, nullptr, "Unknown6"},
|
||||
{7, nullptr, "Unknown7"},
|
||||
{8, nullptr, "RegisterSystemEventForRegisteredDeviceInfo"},
|
||||
{9, nullptr, "Unknown8"},
|
||||
{10, nullptr, "Unknown9"},
|
||||
{11, nullptr, "Unknown10"},
|
||||
{12, nullptr, "Unknown11"},
|
||||
{13, nullptr, "Unknown12"},
|
||||
{0, nullptr, "GetState"},
|
||||
{1, nullptr, "GetHostDeviceProperty"},
|
||||
{2, nullptr, "AcquireDeviceConditionEvent"},
|
||||
{3, nullptr, "GetDeviceCondition"},
|
||||
{4, nullptr, "SetBurstMode"},
|
||||
{5, nullptr, "SetSlotMode"},
|
||||
{6, nullptr, "SetBluetoothMode"},
|
||||
{7, nullptr, "SetWlanMode"},
|
||||
{8, nullptr, "AcquireDeviceInfoEvent"},
|
||||
{9, nullptr, "GetDeviceInfo"},
|
||||
{10, nullptr, "AddDeviceInfo"},
|
||||
{11, nullptr, "RemoveDeviceInfo"},
|
||||
{12, nullptr, "IncreaseDeviceInfoOrder"},
|
||||
{13, nullptr, "LlrNotify"},
|
||||
{14, nullptr, "EnableRadio"},
|
||||
{15, nullptr, "DisableRadio"},
|
||||
{16, nullptr, "Unknown13"},
|
||||
{17, nullptr, "Unknown14"},
|
||||
{18, nullptr, "Unknown15"},
|
||||
{19, nullptr, "Unknown16"},
|
||||
{20, nullptr, "Unknown17"},
|
||||
{21, nullptr, "Unknown18"},
|
||||
{22, nullptr, "Unknown19"},
|
||||
{23, nullptr, "Unknown20"},
|
||||
{24, nullptr, "Unknown21"},
|
||||
{25, nullptr, "Unknown22"},
|
||||
{26, nullptr, "Unknown23"},
|
||||
{27, nullptr, "Unknown24"},
|
||||
{28, nullptr, "Unknown25"},
|
||||
{29, nullptr, "Unknown26"},
|
||||
{30, nullptr, "Unknown27"},
|
||||
{31, nullptr, "Unknown28"},
|
||||
{32, nullptr, "Unknown29"},
|
||||
{33, nullptr, "Unknown30"},
|
||||
{34, nullptr, "Unknown31"},
|
||||
{35, nullptr, "Unknown32"},
|
||||
{36, nullptr, "Unknown33"},
|
||||
{37, nullptr, "Unknown34"},
|
||||
{38, nullptr, "Unknown35"},
|
||||
{39, nullptr, "Unknown36"},
|
||||
{40, nullptr, "Unknown37"},
|
||||
{41, nullptr, "Unknown38"},
|
||||
{42, nullptr, "Unknown39"},
|
||||
{43, nullptr, "Unknown40"},
|
||||
{44, nullptr, "Unknown41"},
|
||||
{45, nullptr, "Unknown42"},
|
||||
{46, nullptr, "Unknown43"},
|
||||
{47, nullptr, "Unknown44"},
|
||||
{48, nullptr, "Unknown45"},
|
||||
{49, nullptr, "Unknown46"},
|
||||
{50, nullptr, "Unknown47"},
|
||||
{51, nullptr, "Unknown48"},
|
||||
{52, nullptr, "Unknown49"},
|
||||
{53, nullptr, "Unknown50"},
|
||||
{54, nullptr, "Unknown51"},
|
||||
{55, nullptr, "Unknown52"},
|
||||
{56, nullptr, "Unknown53"},
|
||||
{57, nullptr, "Unknown54"},
|
||||
{58, nullptr, "Unknown55"},
|
||||
{59, nullptr, "Unknown56"},
|
||||
{16, nullptr, "HidDisconnect"},
|
||||
{17, nullptr, "HidSetRetransmissionMode"},
|
||||
{18, nullptr, "AcquireAwakeReqEvent"},
|
||||
{19, nullptr, "AcquireLlrStateEvent"},
|
||||
{20, nullptr, "IsLlrStarted"},
|
||||
{21, nullptr, "EnableSlotSaving"},
|
||||
{22, nullptr, "ProtectDeviceInfo"},
|
||||
{23, nullptr, "AcquireBleScanEvent"},
|
||||
{24, nullptr, "GetBleScanParameterGeneral"},
|
||||
{25, nullptr, "GetBleScanParameterSmartDevice"},
|
||||
{26, nullptr, "StartBleScanForGeneral"},
|
||||
{27, nullptr, "StopBleScanForGeneral"},
|
||||
{28, nullptr, "GetBleScanResultsForGeneral"},
|
||||
{29, nullptr, "StartBleScanForPairedDevice"},
|
||||
{30, nullptr, "StopBleScanForPairedDevice"},
|
||||
{31, nullptr, "StartBleScanForSmartDevice"},
|
||||
{32, nullptr, "StopBleScanForSmartDevice"},
|
||||
{33, nullptr, "GetBleScanResultsForSmartDevice"},
|
||||
{34, nullptr, "AcquireBleConnectionEvent"},
|
||||
{35, nullptr, "BleConnect"},
|
||||
{36, nullptr, "BleOverrideConnection"},
|
||||
{37, nullptr, "BleDisconnect"},
|
||||
{38, nullptr, "BleGetConnectionState"},
|
||||
{39, nullptr, "BleGetGattClientConditionList"},
|
||||
{40, nullptr, "AcquireBlePairingEvent"},
|
||||
{41, nullptr, "BlePairDevice"},
|
||||
{42, nullptr, "BleUnpairDeviceOnBoth"},
|
||||
{43, nullptr, "BleUnpairDevice"},
|
||||
{44, nullptr, "BleGetPairedAddresses"},
|
||||
{45, nullptr, "AcquireBleServiceDiscoveryEvent"},
|
||||
{46, nullptr, "GetGattServices"},
|
||||
{47, nullptr, "GetGattService"},
|
||||
{48, nullptr, "GetGattIncludedServices"},
|
||||
{49, nullptr, "GetBelongingService"},
|
||||
{50, nullptr, "GetGattCharacteristics"},
|
||||
{51, nullptr, "GetGattDescriptors"},
|
||||
{52, nullptr, "AcquireBleMtuConfigEvent"},
|
||||
{53, nullptr, "ConfigureBleMtu"},
|
||||
{54, nullptr, "GetBleMtu"},
|
||||
{55, nullptr, "RegisterBleGattDataPath"},
|
||||
{56, nullptr, "UnregisterBleGattDataPath"},
|
||||
{57, nullptr, "RegisterAppletResourceUserId"},
|
||||
{58, nullptr, "UnregisterAppletResourceUserId"},
|
||||
{59, nullptr, "SetAppletResourceUserId"},
|
||||
{60, nullptr, "Unknown60"},
|
||||
{61, nullptr, "Unknown61"},
|
||||
{62, nullptr, "Unknown62"},
|
||||
{63, nullptr, "Unknown63"},
|
||||
{64, nullptr, "Unknown64"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -204,19 +209,19 @@ public:
|
||||
explicit BTM_DBG() : ServiceFramework{"btm:dbg"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "RegisterSystemEventForDiscovery"},
|
||||
{1, nullptr, "Unknown1"},
|
||||
{2, nullptr, "Unknown2"},
|
||||
{3, nullptr, "Unknown3"},
|
||||
{4, nullptr, "Unknown4"},
|
||||
{5, nullptr, "Unknown5"},
|
||||
{6, nullptr, "Unknown6"},
|
||||
{7, nullptr, "Unknown7"},
|
||||
{8, nullptr, "Unknown8"},
|
||||
{9, nullptr, "Unknown9"},
|
||||
{10, nullptr, "Unknown10"},
|
||||
{11, nullptr, "Unknown11"},
|
||||
{12, nullptr, "Unknown11"},
|
||||
{0, nullptr, "AcquireDiscoveryEvent"},
|
||||
{1, nullptr, "StartDiscovery"},
|
||||
{2, nullptr, "CancelDiscovery"},
|
||||
{3, nullptr, "GetDeviceProperty"},
|
||||
{4, nullptr, "CreateBond"},
|
||||
{5, nullptr, "CancelBond"},
|
||||
{6, nullptr, "SetTsiMode"},
|
||||
{7, nullptr, "GeneralTest"},
|
||||
{8, nullptr, "HidConnect"},
|
||||
{9, nullptr, "GeneralGet"},
|
||||
{10, nullptr, "GetGattClientDisconnectionReason"},
|
||||
{11, nullptr, "GetBleConnectionParameter"},
|
||||
{12, nullptr, "GetBleConnectionParameterRequest"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Copyright 2018 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Copyright 2018 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@@ -12,73 +12,79 @@ class ServiceManager;
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
enum AlbumImageOrientation {
|
||||
enum class AlbumImageOrientation {
|
||||
Orientation0 = 0,
|
||||
Orientation1 = 1,
|
||||
Orientation2 = 2,
|
||||
Orientation3 = 3,
|
||||
};
|
||||
|
||||
enum AlbumReportOption {
|
||||
enum class AlbumReportOption {
|
||||
Disable = 0,
|
||||
Enable = 1,
|
||||
};
|
||||
|
||||
enum ContentType : u8 {
|
||||
enum class ContentType : u8 {
|
||||
Screenshot = 0,
|
||||
Movie = 1,
|
||||
ExtraMovie = 3,
|
||||
};
|
||||
|
||||
enum AlbumStorage : u8 {
|
||||
enum class AlbumStorage : u8 {
|
||||
NAND = 0,
|
||||
SD = 1,
|
||||
};
|
||||
|
||||
struct AlbumFileDateTime {
|
||||
u16 year;
|
||||
u8 month;
|
||||
u8 day;
|
||||
u8 hour;
|
||||
u8 minute;
|
||||
u8 second;
|
||||
u8 uid;
|
||||
s16 year{};
|
||||
s8 month{};
|
||||
s8 day{};
|
||||
s8 hour{};
|
||||
s8 minute{};
|
||||
s8 second{};
|
||||
s8 uid{};
|
||||
};
|
||||
static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size.");
|
||||
|
||||
struct AlbumEntry {
|
||||
u64 size;
|
||||
u64 application_id;
|
||||
AlbumFileDateTime datetime;
|
||||
AlbumStorage storage;
|
||||
ContentType content;
|
||||
u8 padding[6];
|
||||
u64 size{};
|
||||
u64 application_id{};
|
||||
AlbumFileDateTime datetime{};
|
||||
AlbumStorage storage{};
|
||||
ContentType content{};
|
||||
INSERT_PADDING_BYTES(6);
|
||||
};
|
||||
static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size.");
|
||||
|
||||
struct AlbumFileEntry {
|
||||
u64 size;
|
||||
u64 hash;
|
||||
AlbumFileDateTime datetime;
|
||||
AlbumStorage storage;
|
||||
ContentType content;
|
||||
u8 padding[5];
|
||||
u8 unknown;
|
||||
u64 size{}; // Size of the entry
|
||||
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
|
||||
AlbumFileDateTime datetime{};
|
||||
AlbumStorage storage{};
|
||||
ContentType content{};
|
||||
INSERT_PADDING_BYTES(5);
|
||||
u8 unknown{1}; // Set to 1 on official SW
|
||||
};
|
||||
static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size.");
|
||||
|
||||
struct ApplicationAlbumEntry {
|
||||
u64 size;
|
||||
u64 hash;
|
||||
AlbumFileDateTime datetime;
|
||||
AlbumStorage storage;
|
||||
ContentType content;
|
||||
u8 padding[5];
|
||||
u8 unknown;
|
||||
u64 size{}; // Size of the entry
|
||||
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
|
||||
AlbumFileDateTime datetime{};
|
||||
AlbumStorage storage{};
|
||||
ContentType content{};
|
||||
INSERT_PADDING_BYTES(5);
|
||||
u8 unknown{1}; // Set to 1 on official SW
|
||||
};
|
||||
static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size.");
|
||||
|
||||
struct ApplicationAlbumFileEntry {
|
||||
ApplicationAlbumEntry entry;
|
||||
AlbumFileDateTime datetime;
|
||||
u64 unknown;
|
||||
ApplicationAlbumEntry entry{};
|
||||
AlbumFileDateTime datetime{};
|
||||
u64 unknown{};
|
||||
};
|
||||
static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30,
|
||||
"ApplicationAlbumFileEntry has incorrect size.");
|
||||
|
||||
/// Registers all Capture services with the specified service manager.
|
||||
void InstallInterfaces(SM::ServiceManager& sm);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@@ -58,19 +58,25 @@ void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& c
|
||||
// u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total
|
||||
// output entries (which is copied to a s32 by official SW).
|
||||
IPC::RequestParser rp{ctx};
|
||||
[[maybe_unused]] const auto application_album_file_entries = rp.PopRaw<std::array<u8, 0x30>>();
|
||||
const auto pid = rp.Pop<s32>();
|
||||
const auto content_type = rp.PopRaw<ContentType>();
|
||||
[[maybe_unused]] const auto start_datetime = rp.PopRaw<AlbumFileDateTime>();
|
||||
[[maybe_unused]] const auto end_datetime = rp.PopRaw<AlbumFileDateTime>();
|
||||
const auto applet_resource_user_id = rp.Pop<u64>();
|
||||
const auto pid{rp.Pop<s32>()};
|
||||
const auto content_type{rp.PopEnum<ContentType>()};
|
||||
const auto start_posix_time{rp.Pop<s64>()};
|
||||
const auto end_posix_time{rp.Pop<s64>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
// TODO: Update this when we implement the album.
|
||||
// Currently we do not have a method of accessing album entries, set this to 0 for now.
|
||||
constexpr s32 total_entries{0};
|
||||
|
||||
LOG_WARNING(Service_Capture,
|
||||
"(STUBBED) called. pid={}, content_type={}, applet_resource_user_id={}", pid,
|
||||
content_type, applet_resource_user_id);
|
||||
"(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
|
||||
"end_posix_time={}, applet_resource_user_id={}, total_entries={}",
|
||||
pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id,
|
||||
total_entries);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<s32>(0);
|
||||
rb.Push(total_entries);
|
||||
}
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ public:
|
||||
{8, &ETicket::GetTitleKey, "GetTitleKey"},
|
||||
{9, &ETicket::CountCommonTicket, "CountCommonTicket"},
|
||||
{10, &ETicket::CountPersonalizedTicket, "CountPersonalizedTicket"},
|
||||
{11, &ETicket::ListCommonTicket, "ListCommonTicket"},
|
||||
{12, &ETicket::ListPersonalizedTicket, "ListPersonalizedTicket"},
|
||||
{11, &ETicket::ListCommonTicketRightsIds, "ListCommonTicketRightsIds"},
|
||||
{12, &ETicket::ListPersonalizedTicketRightsIds, "ListPersonalizedTicketRightsIds"},
|
||||
{13, nullptr, "ListMissingPersonalizedTicket"},
|
||||
{14, &ETicket::GetCommonTicketSize, "GetCommonTicketSize"},
|
||||
{15, &ETicket::GetPersonalizedTicketSize, "GetPersonalizedTicketSize"},
|
||||
@@ -55,7 +55,46 @@ public:
|
||||
{36, nullptr, "DeleteAllInactiveELicenseRequiredPersonalizedTicket"},
|
||||
{37, nullptr, "OwnTicket2"},
|
||||
{38, nullptr, "OwnTicket3"},
|
||||
{501, nullptr, "Unknown501"},
|
||||
{502, nullptr, "Unknown502"},
|
||||
{503, nullptr, "GetTitleKey"},
|
||||
{504, nullptr, "Unknown504"},
|
||||
{508, nullptr, "Unknown508"},
|
||||
{509, nullptr, "Unknown509"},
|
||||
{510, nullptr, "Unknown510"},
|
||||
{511, nullptr, "Unknown511"},
|
||||
{1001, nullptr, "Unknown1001"},
|
||||
{1002, nullptr, "Unknown1001"},
|
||||
{1003, nullptr, "Unknown1003"},
|
||||
{1004, nullptr, "Unknown1004"},
|
||||
{1005, nullptr, "Unknown1005"},
|
||||
{1006, nullptr, "Unknown1006"},
|
||||
{1007, nullptr, "Unknown1007"},
|
||||
{1009, nullptr, "Unknown1009"},
|
||||
{1010, nullptr, "Unknown1010"},
|
||||
{1011, nullptr, "Unknown1011"},
|
||||
{1012, nullptr, "Unknown1012"},
|
||||
{1013, nullptr, "Unknown1013"},
|
||||
{1014, nullptr, "Unknown1014"},
|
||||
{1015, nullptr, "Unknown1015"},
|
||||
{1016, nullptr, "Unknown1016"},
|
||||
{1017, nullptr, "Unknown1017"},
|
||||
{1018, nullptr, "Unknown1018"},
|
||||
{1019, nullptr, "Unknown1019"},
|
||||
{1020, nullptr, "Unknown1020"},
|
||||
{1021, nullptr, "Unknown1021"},
|
||||
{1501, nullptr, "Unknown1501"},
|
||||
{1502, nullptr, "Unknown1502"},
|
||||
{1503, nullptr, "Unknown1503"},
|
||||
{1504, nullptr, "Unknown1504"},
|
||||
{1505, nullptr, "Unknown1505"},
|
||||
{2000, nullptr, "Unknown2000"},
|
||||
{2001, nullptr, "Unknown2001"},
|
||||
{2100, nullptr, "Unknown2100"},
|
||||
{2501, nullptr, "Unknown2501"},
|
||||
{2502, nullptr, "Unknown2502"},
|
||||
{3001, nullptr, "Unknown3001"},
|
||||
{3002, nullptr, "Unknown3002"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
@@ -147,7 +186,7 @@ private:
|
||||
rb.Push<u32>(count);
|
||||
}
|
||||
|
||||
void ListCommonTicket(Kernel::HLERequestContext& ctx) {
|
||||
void ListCommonTicketRightsIds(Kernel::HLERequestContext& ctx) {
|
||||
u32 out_entries;
|
||||
if (keys.GetCommonTickets().empty())
|
||||
out_entries = 0;
|
||||
@@ -170,7 +209,7 @@ private:
|
||||
rb.Push<u32>(out_entries);
|
||||
}
|
||||
|
||||
void ListPersonalizedTicket(Kernel::HLERequestContext& ctx) {
|
||||
void ListPersonalizedTicketRightsIds(Kernel::HLERequestContext& ctx) {
|
||||
u32 out_entries;
|
||||
if (keys.GetPersonalizedTickets().empty())
|
||||
out_entries = 0;
|
||||
|
||||
@@ -19,6 +19,7 @@ public:
|
||||
{1, nullptr, "ImportCrt"},
|
||||
{2, nullptr, "ImportPki"},
|
||||
{3, nullptr, "SetAutoUpload"},
|
||||
{4, nullptr, "GetAutoUpload"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -566,6 +566,14 @@ void Controller_NPad::DisconnectNPad(u32 npad_id) {
|
||||
connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;
|
||||
}
|
||||
|
||||
void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
|
||||
gyroscope_zero_drift_mode = drift_mode;
|
||||
}
|
||||
|
||||
Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMode() const {
|
||||
return gyroscope_zero_drift_mode;
|
||||
}
|
||||
|
||||
void Controller_NPad::StartLRAssignmentMode() {
|
||||
// Nothing internally is used for lr assignment mode. Since we have the ability to set the
|
||||
// controller types from boot, it doesn't really matter about showing a selection screen
|
||||
|
||||
@@ -58,6 +58,12 @@ public:
|
||||
};
|
||||
static_assert(sizeof(Vibration) == 0x10, "Vibration is an invalid size");
|
||||
|
||||
enum class GyroscopeZeroDriftMode : u32 {
|
||||
Loose = 0,
|
||||
Standard = 1,
|
||||
Tight = 2,
|
||||
};
|
||||
|
||||
enum class NpadHoldType : u64 {
|
||||
Vertical = 0,
|
||||
Horizontal = 1,
|
||||
@@ -117,6 +123,8 @@ public:
|
||||
|
||||
void ConnectNPad(u32 npad_id);
|
||||
void DisconnectNPad(u32 npad_id);
|
||||
void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
|
||||
GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
|
||||
LedPattern GetLedPattern(u32 npad_id);
|
||||
void SetVibrationEnabled(bool can_vibrate);
|
||||
bool IsVibrationEnabled() const;
|
||||
@@ -324,8 +332,8 @@ private:
|
||||
std::array<Kernel::EventPair, 10> styleset_changed_events;
|
||||
Vibration last_processed_vibration{};
|
||||
std::array<ControllerHolder, 10> connected_controllers{};
|
||||
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
|
||||
bool can_controllers_vibrate{true};
|
||||
|
||||
std::array<ControllerPad, 10> npad_pad_states{};
|
||||
bool is_in_lr_assignment_mode{false};
|
||||
Core::System& system;
|
||||
|
||||
@@ -185,8 +185,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
|
||||
{77, nullptr, "GetAccelerometerPlayMode"},
|
||||
{78, nullptr, "ResetAccelerometerPlayMode"},
|
||||
{79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
|
||||
{80, nullptr, "GetGyroscopeZeroDriftMode"},
|
||||
{81, nullptr, "ResetGyroscopeZeroDriftMode"},
|
||||
{80, &Hid::GetGyroscopeZeroDriftMode, "GetGyroscopeZeroDriftMode"},
|
||||
{81, &Hid::ResetGyroscopeZeroDriftMode, "ResetGyroscopeZeroDriftMode"},
|
||||
{82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
|
||||
{83, nullptr, "IsFirmwareUpdateAvailableForSixAxisSensor"},
|
||||
{91, &Hid::ActivateGesture, "ActivateGesture"},
|
||||
@@ -230,15 +230,15 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
|
||||
{211, nullptr, "IsVibrationDeviceMounted"},
|
||||
{300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
|
||||
{301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
|
||||
{302, nullptr, "StopConsoleSixAxisSensor"},
|
||||
{303, nullptr, "ActivateSevenSixAxisSensor"},
|
||||
{304, nullptr, "StartSevenSixAxisSensor"},
|
||||
{302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
|
||||
{303, &Hid::ActivateSevenSixAxisSensor, "ActivateSevenSixAxisSensor"},
|
||||
{304, &Hid::StartSevenSixAxisSensor, "StartSevenSixAxisSensor"},
|
||||
{305, &Hid::StopSevenSixAxisSensor, "StopSevenSixAxisSensor"},
|
||||
{306, &Hid::InitializeSevenSixAxisSensor, "InitializeSevenSixAxisSensor"},
|
||||
{307, nullptr, "FinalizeSevenSixAxisSensor"},
|
||||
{307, &Hid::FinalizeSevenSixAxisSensor, "FinalizeSevenSixAxisSensor"},
|
||||
{308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
|
||||
{309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
|
||||
{310, nullptr, "ResetSevenSixAxisSensorTimestamp"},
|
||||
{310, &Hid::ResetSevenSixAxisSensorTimestamp, "ResetSevenSixAxisSensorTimestamp"},
|
||||
{400, nullptr, "IsUsbFullKeyControllerEnabled"},
|
||||
{401, nullptr, "EnableUsbFullKeyController"},
|
||||
{402, nullptr, "IsUsbFullKeyControllerConnected"},
|
||||
@@ -374,6 +374,15 @@ void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto flags{rp.Pop<u32>()};
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto unknown{rp.Pop<u32>()};
|
||||
@@ -413,15 +422,59 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto handle{rp.Pop<u32>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto handle{rp.Pop<u32>()};
|
||||
const auto drift_mode{rp.Pop<u32>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID,
|
||||
"(STUBBED) called, handle={}, drift_mode={}, applet_resource_user_id={}", handle,
|
||||
drift_mode, applet_resource_user_id);
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode{drift_mode});
|
||||
|
||||
LOG_DEBUG(Service_HID, "called, handle={}, drift_mode={}, applet_resource_user_id={}", handle,
|
||||
drift_mode, applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto handle{rp.Pop<u32>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(
|
||||
static_cast<u32>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.GetGyroscopeZeroDriftMode()));
|
||||
}
|
||||
|
||||
void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto handle{rp.Pop<u32>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard);
|
||||
|
||||
LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -832,33 +885,35 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto handle{rp.Pop<u32>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, handle={}", handle);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
|
||||
void Hid::ActivateSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
const auto unknown{rp.Pop<u32>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, unknown={}",
|
||||
applet_resource_user_id, unknown);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
|
||||
void Hid::StartSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto unknown{rp.Pop<u32>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}", unknown);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -882,10 +937,46 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) {
|
||||
void Hid::FinalizeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto flags{rp.Pop<u32>()};
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags);
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
const auto is_palma_all_connectable{rp.Pop<bool>()};
|
||||
|
||||
LOG_WARNING(Service_HID,
|
||||
"(STUBBED) called, applet_resource_user_id={}, is_palma_all_connectable={}",
|
||||
applet_resource_user_id, is_palma_all_connectable);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto palma_boost_mode{rp.Pop<bool>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, palma_boost_mode={}", palma_boost_mode);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -91,10 +91,14 @@ private:
|
||||
void ActivateTouchScreen(Kernel::HLERequestContext& ctx);
|
||||
void ActivateMouse(Kernel::HLERequestContext& ctx);
|
||||
void ActivateKeyboard(Kernel::HLERequestContext& ctx);
|
||||
void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx);
|
||||
void ActivateGesture(Kernel::HLERequestContext& ctx);
|
||||
void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);
|
||||
void StartSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
|
||||
void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
|
||||
void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
|
||||
void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx);
|
||||
void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
|
||||
void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
|
||||
@@ -126,12 +130,15 @@ private:
|
||||
void IsVibrationPermitted(Kernel::HLERequestContext& ctx);
|
||||
void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
|
||||
void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
|
||||
void StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void ActivateSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void StartSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void StopSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx);
|
||||
void FinalizeSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx);
|
||||
void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
|
||||
void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<IAppletResource> applet_resource;
|
||||
Core::System& system;
|
||||
|
||||
@@ -86,7 +86,8 @@ std::string FormatField(Field type, const std::vector<u8>& data) {
|
||||
return Common::StringFromFixedZeroTerminatedBuffer(
|
||||
reinterpret_cast<const char*>(data.data()), data.size());
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
UNIMPLEMENTED_MSG("Unimplemented field type={}", type);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -198,9 +198,9 @@ public:
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Initialize"},
|
||||
{1, nullptr, "Finalize"},
|
||||
{2, nullptr, "GetState"},
|
||||
{3, nullptr, "IsNfcEnabled"},
|
||||
{100, nullptr, "SetNfcEnabled"},
|
||||
{2, nullptr, "GetStateOld"},
|
||||
{3, nullptr, "IsNfcEnabledOld"},
|
||||
{100, nullptr, "SetNfcEnabledOld"},
|
||||
{400, nullptr, "InitializeSystem"},
|
||||
{401, nullptr, "FinalizeSystem"},
|
||||
{402, nullptr, "GetState"},
|
||||
|
||||
@@ -127,6 +127,13 @@ void LogSettings() {
|
||||
LogSetting("Services_BCATBoxcatLocal", Settings::values.bcat_boxcat_local);
|
||||
}
|
||||
|
||||
float Volume() {
|
||||
if (values.audio_muted) {
|
||||
return 0.0f;
|
||||
}
|
||||
return values.volume;
|
||||
}
|
||||
|
||||
bool IsGPULevelExtreme() {
|
||||
return values.gpu_accuracy == GPUAccuracy::Extreme;
|
||||
}
|
||||
|
||||
@@ -459,6 +459,7 @@ struct Values {
|
||||
bool use_dev_keys;
|
||||
|
||||
// Audio
|
||||
bool audio_muted;
|
||||
std::string sink_id;
|
||||
bool enable_audio_stretching;
|
||||
std::string audio_device_id;
|
||||
@@ -490,6 +491,8 @@ struct Values {
|
||||
std::map<u64, std::vector<std::string>> disabled_addons;
|
||||
} extern values;
|
||||
|
||||
float Volume();
|
||||
|
||||
bool IsGPULevelExtreme();
|
||||
bool IsGPULevelHigh();
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage
|
||||
int key_code = params.Get("code", 0);
|
||||
std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list);
|
||||
key_button_list->AddKeyButton(key_code, button.get());
|
||||
return std::move(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
void Keyboard::PressKey(int key_code) {
|
||||
|
||||
@@ -145,7 +145,7 @@ std::unique_ptr<Input::MotionDevice> MotionEmu::Create(const Common::ParamPackag
|
||||
// Previously created device is disconnected here. Having two motion devices for 3DS is not
|
||||
// expected.
|
||||
current_device = device_wrapper->device;
|
||||
return std::move(device_wrapper);
|
||||
return device_wrapper;
|
||||
}
|
||||
|
||||
void MotionEmu::BeginTilt(int x, int y) {
|
||||
|
||||
@@ -27,6 +27,8 @@ add_library(video_core STATIC
|
||||
engines/shader_type.h
|
||||
macro/macro.cpp
|
||||
macro/macro.h
|
||||
macro/macro_hle.cpp
|
||||
macro/macro_hle.h
|
||||
macro/macro_interpreter.cpp
|
||||
macro/macro_interpreter.h
|
||||
macro/macro_jit_x64.cpp
|
||||
|
||||
@@ -41,16 +41,20 @@ class BufferCache {
|
||||
static constexpr u64 BLOCK_PAGE_SIZE = 1ULL << BLOCK_PAGE_BITS;
|
||||
|
||||
public:
|
||||
using BufferInfo = std::pair<BufferType, u64>;
|
||||
struct BufferInfo {
|
||||
BufferType handle;
|
||||
u64 offset;
|
||||
u64 address;
|
||||
};
|
||||
|
||||
BufferInfo UploadMemory(GPUVAddr gpu_addr, std::size_t size, std::size_t alignment = 4,
|
||||
bool is_written = false, bool use_fast_cbuf = false) {
|
||||
std::lock_guard lock{mutex};
|
||||
|
||||
const auto& memory_manager = system.GPU().MemoryManager();
|
||||
auto& memory_manager = system.GPU().MemoryManager();
|
||||
const std::optional<VAddr> cpu_addr_opt = memory_manager.GpuToCpuAddress(gpu_addr);
|
||||
if (!cpu_addr_opt) {
|
||||
return {GetEmptyBuffer(size), 0};
|
||||
return GetEmptyBuffer(size);
|
||||
}
|
||||
const VAddr cpu_addr = *cpu_addr_opt;
|
||||
|
||||
@@ -59,7 +63,6 @@ public:
|
||||
constexpr std::size_t max_stream_size = 0x800;
|
||||
if (use_fast_cbuf || size < max_stream_size) {
|
||||
if (!is_written && !IsRegionWritten(cpu_addr, cpu_addr + size - 1)) {
|
||||
auto& memory_manager = system.GPU().MemoryManager();
|
||||
const bool is_granular = memory_manager.IsGranularRange(gpu_addr, size);
|
||||
if (use_fast_cbuf) {
|
||||
u8* dest;
|
||||
@@ -89,7 +92,7 @@ public:
|
||||
Buffer* const block = GetBlock(cpu_addr, size);
|
||||
MapInterval* const map = MapAddress(block, gpu_addr, cpu_addr, size);
|
||||
if (!map) {
|
||||
return {GetEmptyBuffer(size), 0};
|
||||
return GetEmptyBuffer(size);
|
||||
}
|
||||
if (is_written) {
|
||||
map->MarkAsModified(true, GetModifiedTicks());
|
||||
@@ -102,7 +105,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
return {block->Handle(), static_cast<u64>(block->Offset(cpu_addr))};
|
||||
return BufferInfo{block->Handle(), block->Offset(cpu_addr), block->Address()};
|
||||
}
|
||||
|
||||
/// Uploads from a host memory. Returns the OpenGL buffer where it's located and its offset.
|
||||
@@ -255,27 +258,17 @@ public:
|
||||
committed_flushes.pop_front();
|
||||
}
|
||||
|
||||
virtual BufferType GetEmptyBuffer(std::size_t size) = 0;
|
||||
virtual BufferInfo GetEmptyBuffer(std::size_t size) = 0;
|
||||
|
||||
protected:
|
||||
explicit BufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
|
||||
std::unique_ptr<StreamBuffer> stream_buffer_)
|
||||
: rasterizer{rasterizer}, system{system}, stream_buffer{std::move(stream_buffer_)},
|
||||
stream_buffer_handle{stream_buffer->Handle()} {}
|
||||
std::unique_ptr<StreamBuffer> stream_buffer)
|
||||
: rasterizer{rasterizer}, system{system}, stream_buffer{std::move(stream_buffer)} {}
|
||||
|
||||
~BufferCache() = default;
|
||||
|
||||
virtual std::shared_ptr<Buffer> CreateBlock(VAddr cpu_addr, std::size_t size) = 0;
|
||||
|
||||
virtual void UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||
const u8* data) = 0;
|
||||
|
||||
virtual void DownloadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||
u8* data) = 0;
|
||||
|
||||
virtual void CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
|
||||
std::size_t dst_offset, std::size_t size) = 0;
|
||||
|
||||
virtual BufferInfo ConstBufferUpload(const void* raw_pointer, std::size_t size) {
|
||||
return {};
|
||||
}
|
||||
@@ -337,11 +330,11 @@ private:
|
||||
const VAddr cpu_addr_end = cpu_addr + size;
|
||||
if (memory_manager.IsGranularRange(gpu_addr, size)) {
|
||||
u8* host_ptr = memory_manager.GetPointer(gpu_addr);
|
||||
UploadBlockData(*block, block->Offset(cpu_addr), size, host_ptr);
|
||||
block->Upload(block->Offset(cpu_addr), size, host_ptr);
|
||||
} else {
|
||||
staging_buffer.resize(size);
|
||||
memory_manager.ReadBlockUnsafe(gpu_addr, staging_buffer.data(), size);
|
||||
UploadBlockData(*block, block->Offset(cpu_addr), size, staging_buffer.data());
|
||||
block->Upload(block->Offset(cpu_addr), size, staging_buffer.data());
|
||||
}
|
||||
return Register(MapInterval(cpu_addr, cpu_addr_end, gpu_addr));
|
||||
}
|
||||
@@ -400,7 +393,7 @@ private:
|
||||
}
|
||||
staging_buffer.resize(size);
|
||||
system.Memory().ReadBlockUnsafe(interval.lower(), staging_buffer.data(), size);
|
||||
UploadBlockData(*block, block->Offset(interval.lower()), size, staging_buffer.data());
|
||||
block->Upload(block->Offset(interval.lower()), size, staging_buffer.data());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,7 +430,7 @@ private:
|
||||
|
||||
const std::size_t size = map->end - map->start;
|
||||
staging_buffer.resize(size);
|
||||
DownloadBlockData(*block, block->Offset(map->start), size, staging_buffer.data());
|
||||
block->Download(block->Offset(map->start), size, staging_buffer.data());
|
||||
system.Memory().WriteBlockUnsafe(map->start, staging_buffer.data(), size);
|
||||
map->MarkAsModified(false, 0);
|
||||
}
|
||||
@@ -450,7 +443,7 @@ private:
|
||||
|
||||
buffer_ptr += size;
|
||||
buffer_offset += size;
|
||||
return {stream_buffer_handle, uploaded_offset};
|
||||
return BufferInfo{stream_buffer->Handle(), uploaded_offset, stream_buffer->Address()};
|
||||
}
|
||||
|
||||
void AlignBuffer(std::size_t alignment) {
|
||||
@@ -465,7 +458,7 @@ private:
|
||||
const std::size_t new_size = old_size + BLOCK_PAGE_SIZE;
|
||||
const VAddr cpu_addr = buffer->CpuAddr();
|
||||
std::shared_ptr<Buffer> new_buffer = CreateBlock(cpu_addr, new_size);
|
||||
CopyBlock(*buffer, *new_buffer, 0, 0, old_size);
|
||||
new_buffer->CopyFrom(*buffer, 0, 0, old_size);
|
||||
QueueDestruction(std::move(buffer));
|
||||
|
||||
const VAddr cpu_addr_end = cpu_addr + new_size - 1;
|
||||
@@ -487,8 +480,8 @@ private:
|
||||
const std::size_t new_size = size_1 + size_2;
|
||||
|
||||
std::shared_ptr<Buffer> new_buffer = CreateBlock(new_addr, new_size);
|
||||
CopyBlock(*first, *new_buffer, 0, new_buffer->Offset(first_addr), size_1);
|
||||
CopyBlock(*second, *new_buffer, 0, new_buffer->Offset(second_addr), size_2);
|
||||
new_buffer->CopyFrom(*first, 0, new_buffer->Offset(first_addr), size_1);
|
||||
new_buffer->CopyFrom(*second, 0, new_buffer->Offset(second_addr), size_2);
|
||||
QueueDestruction(std::move(first));
|
||||
QueueDestruction(std::move(second));
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters)
|
||||
((method - MacroRegistersStart) >> 1) % static_cast<u32>(macro_positions.size());
|
||||
|
||||
// Execute the current macro.
|
||||
macro_engine->Execute(macro_positions[entry], parameters);
|
||||
macro_engine->Execute(*this, macro_positions[entry], parameters);
|
||||
if (mme_draw.current_mode != MMEDrawMode::Undefined) {
|
||||
FlushMMEInlineDraw();
|
||||
}
|
||||
|
||||
@@ -1418,6 +1418,14 @@ public:
|
||||
return execute_on;
|
||||
}
|
||||
|
||||
VideoCore::RasterizerInterface& GetRasterizer() {
|
||||
return rasterizer;
|
||||
}
|
||||
|
||||
const VideoCore::RasterizerInterface& GetRasterizer() const {
|
||||
return rasterizer;
|
||||
}
|
||||
|
||||
/// Notify a memory write has happened.
|
||||
void OnMemoryWrite() {
|
||||
dirty.flags |= dirty.on_write_stores;
|
||||
|
||||
@@ -661,6 +661,10 @@ union Instruction {
|
||||
constexpr Instruction(u64 value) : value{value} {}
|
||||
constexpr Instruction(const Instruction& instr) : value(instr.value) {}
|
||||
|
||||
constexpr bool Bit(u64 offset) const {
|
||||
return ((value >> offset) & 1) != 0;
|
||||
}
|
||||
|
||||
BitField<0, 8, Register> gpr0;
|
||||
BitField<8, 8, Register> gpr8;
|
||||
union {
|
||||
@@ -1874,7 +1878,9 @@ public:
|
||||
HSETP2_C,
|
||||
HSETP2_R,
|
||||
HSETP2_IMM,
|
||||
HSET2_C,
|
||||
HSET2_R,
|
||||
HSET2_IMM,
|
||||
POPC_C,
|
||||
POPC_R,
|
||||
POPC_IMM,
|
||||
@@ -2194,7 +2200,9 @@ private:
|
||||
INST("0111111-1-------", Id::HSETP2_C, Type::HalfSetPredicate, "HSETP2_C"),
|
||||
INST("0101110100100---", Id::HSETP2_R, Type::HalfSetPredicate, "HSETP2_R"),
|
||||
INST("0111111-0-------", Id::HSETP2_IMM, Type::HalfSetPredicate, "HSETP2_IMM"),
|
||||
INST("0111110-1-------", Id::HSET2_C, Type::HalfSet, "HSET2_C"),
|
||||
INST("0101110100011---", Id::HSET2_R, Type::HalfSet, "HSET2_R"),
|
||||
INST("0111110-0-------", Id::HSET2_IMM, Type::HalfSet, "HSET2_IMM"),
|
||||
INST("010110111010----", Id::FCMP_RR, Type::Arithmetic, "FCMP_RR"),
|
||||
INST("010010111010----", Id::FCMP_RC, Type::Arithmetic, "FCMP_RC"),
|
||||
INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"),
|
||||
|
||||
@@ -2,23 +2,37 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/settings.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/macro/macro.h"
|
||||
#include "video_core/macro/macro_hle.h"
|
||||
#include "video_core/macro/macro_interpreter.h"
|
||||
#include "video_core/macro/macro_jit_x64.h"
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
MacroEngine::MacroEngine(Engines::Maxwell3D& maxwell3d)
|
||||
: hle_macros{std::make_unique<Tegra::HLEMacro>(maxwell3d)} {}
|
||||
|
||||
MacroEngine::~MacroEngine() = default;
|
||||
|
||||
void MacroEngine::AddCode(u32 method, u32 data) {
|
||||
uploaded_macro_code[method].push_back(data);
|
||||
}
|
||||
|
||||
void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
|
||||
void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method,
|
||||
const std::vector<u32>& parameters) {
|
||||
auto compiled_macro = macro_cache.find(method);
|
||||
if (compiled_macro != macro_cache.end()) {
|
||||
compiled_macro->second->Execute(parameters, method);
|
||||
const auto& cache_info = compiled_macro->second;
|
||||
if (cache_info.has_hle_program) {
|
||||
cache_info.hle_program->Execute(parameters, method);
|
||||
} else {
|
||||
cache_info.lle_program->Execute(parameters, method);
|
||||
}
|
||||
} else {
|
||||
// Macro not compiled, check if it's uploaded and if so, compile it
|
||||
auto macro_code = uploaded_macro_code.find(method);
|
||||
@@ -26,8 +40,21 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
|
||||
UNREACHABLE_MSG("Macro 0x{0:x} was not uploaded", method);
|
||||
return;
|
||||
}
|
||||
macro_cache[method] = Compile(macro_code->second);
|
||||
macro_cache[method]->Execute(parameters, method);
|
||||
auto& cache_info = macro_cache[method];
|
||||
cache_info.hash = boost::hash_value(macro_code->second);
|
||||
cache_info.lle_program = Compile(macro_code->second);
|
||||
|
||||
auto hle_program = hle_macros->GetHLEProgram(cache_info.hash);
|
||||
if (hle_program.has_value()) {
|
||||
cache_info.has_hle_program = true;
|
||||
cache_info.hle_program = std::move(hle_program.value());
|
||||
}
|
||||
|
||||
if (cache_info.has_hle_program) {
|
||||
cache_info.hle_program->Execute(parameters, method);
|
||||
} else {
|
||||
cache_info.lle_program->Execute(parameters, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
namespace Engines {
|
||||
class Maxwell3D;
|
||||
}
|
||||
|
||||
namespace Macro {
|
||||
constexpr std::size_t NUM_MACRO_REGISTERS = 8;
|
||||
enum class Operation : u32 {
|
||||
@@ -94,6 +96,8 @@ union MethodAddress {
|
||||
|
||||
} // namespace Macro
|
||||
|
||||
class HLEMacro;
|
||||
|
||||
class CachedMacro {
|
||||
public:
|
||||
virtual ~CachedMacro() = default;
|
||||
@@ -107,20 +111,29 @@ public:
|
||||
|
||||
class MacroEngine {
|
||||
public:
|
||||
virtual ~MacroEngine() = default;
|
||||
explicit MacroEngine(Engines::Maxwell3D& maxwell3d);
|
||||
virtual ~MacroEngine();
|
||||
|
||||
// Store the uploaded macro code to compile them when they're called.
|
||||
void AddCode(u32 method, u32 data);
|
||||
|
||||
// Compiles the macro if its not in the cache, and executes the compiled macro
|
||||
void Execute(u32 method, const std::vector<u32>& parameters);
|
||||
void Execute(Engines::Maxwell3D& maxwell3d, u32 method, const std::vector<u32>& parameters);
|
||||
|
||||
protected:
|
||||
virtual std::unique_ptr<CachedMacro> Compile(const std::vector<u32>& code) = 0;
|
||||
|
||||
private:
|
||||
std::unordered_map<u32, std::unique_ptr<CachedMacro>> macro_cache;
|
||||
struct CacheInfo {
|
||||
std::unique_ptr<CachedMacro> lle_program{};
|
||||
std::unique_ptr<CachedMacro> hle_program{};
|
||||
u64 hash{};
|
||||
bool has_hle_program{};
|
||||
};
|
||||
|
||||
std::unordered_map<u32, CacheInfo> macro_cache;
|
||||
std::unordered_map<u32, std::vector<u32>> uploaded_macro_code;
|
||||
std::unique_ptr<HLEMacro> hle_macros;
|
||||
};
|
||||
|
||||
std::unique_ptr<MacroEngine> GetMacroEngine(Engines::Maxwell3D& maxwell3d);
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/macro/macro_hle.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
namespace {
|
||||
// HLE'd functions
|
||||
static void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d,
|
||||
const std::vector<u32>& parameters) {
|
||||
const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B);
|
||||
|
||||
maxwell3d.regs.draw.topology.Assign(
|
||||
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] &
|
||||
~(0x3ffffff << 26)));
|
||||
maxwell3d.regs.vb_base_instance = parameters[5];
|
||||
maxwell3d.mme_draw.instance_count = instance_count;
|
||||
maxwell3d.regs.vb_element_base = parameters[3];
|
||||
maxwell3d.regs.index_array.count = parameters[1];
|
||||
maxwell3d.regs.index_array.first = parameters[4];
|
||||
|
||||
if (maxwell3d.ShouldExecute()) {
|
||||
maxwell3d.GetRasterizer().Draw(true, true);
|
||||
}
|
||||
maxwell3d.regs.index_array.count = 0;
|
||||
maxwell3d.mme_draw.instance_count = 0;
|
||||
maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
|
||||
}
|
||||
|
||||
static void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d,
|
||||
const std::vector<u32>& parameters) {
|
||||
const u32 count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
|
||||
|
||||
maxwell3d.regs.vertex_buffer.first = parameters[3];
|
||||
maxwell3d.regs.vertex_buffer.count = parameters[1];
|
||||
maxwell3d.regs.vb_base_instance = parameters[4];
|
||||
maxwell3d.regs.draw.topology.Assign(
|
||||
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
|
||||
maxwell3d.mme_draw.instance_count = count;
|
||||
|
||||
if (maxwell3d.ShouldExecute()) {
|
||||
maxwell3d.GetRasterizer().Draw(false, true);
|
||||
}
|
||||
maxwell3d.regs.vertex_buffer.count = 0;
|
||||
maxwell3d.mme_draw.instance_count = 0;
|
||||
maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
|
||||
}
|
||||
|
||||
static void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d,
|
||||
const std::vector<u32>& parameters) {
|
||||
const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
|
||||
const u32 element_base = parameters[4];
|
||||
const u32 base_instance = parameters[5];
|
||||
maxwell3d.regs.index_array.first = parameters[3];
|
||||
maxwell3d.regs.reg_array[0x446] = element_base; // vertex id base?
|
||||
maxwell3d.regs.index_array.count = parameters[1];
|
||||
maxwell3d.regs.vb_element_base = element_base;
|
||||
maxwell3d.regs.vb_base_instance = base_instance;
|
||||
maxwell3d.mme_draw.instance_count = instance_count;
|
||||
maxwell3d.CallMethodFromMME(0x8e3, 0x640);
|
||||
maxwell3d.CallMethodFromMME(0x8e4, element_base);
|
||||
maxwell3d.CallMethodFromMME(0x8e5, base_instance);
|
||||
maxwell3d.regs.draw.topology.Assign(
|
||||
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
|
||||
if (maxwell3d.ShouldExecute()) {
|
||||
maxwell3d.GetRasterizer().Draw(true, true);
|
||||
}
|
||||
maxwell3d.regs.reg_array[0x446] = 0x0; // vertex id base?
|
||||
maxwell3d.regs.index_array.count = 0;
|
||||
maxwell3d.regs.vb_element_base = 0x0;
|
||||
maxwell3d.regs.vb_base_instance = 0x0;
|
||||
maxwell3d.mme_draw.instance_count = 0;
|
||||
maxwell3d.CallMethodFromMME(0x8e3, 0x640);
|
||||
maxwell3d.CallMethodFromMME(0x8e4, 0x0);
|
||||
maxwell3d.CallMethodFromMME(0x8e5, 0x0);
|
||||
maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
constexpr std::array<std::pair<u64, HLEFunction>, 3> hle_funcs{{
|
||||
std::make_pair<u64, HLEFunction>(0x771BB18C62444DA0, &HLE_771BB18C62444DA0),
|
||||
std::make_pair<u64, HLEFunction>(0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD),
|
||||
std::make_pair<u64, HLEFunction>(0x0217920100488FF7, &HLE_0217920100488FF7),
|
||||
}};
|
||||
|
||||
HLEMacro::HLEMacro(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
|
||||
HLEMacro::~HLEMacro() = default;
|
||||
|
||||
std::optional<std::unique_ptr<CachedMacro>> HLEMacro::GetHLEProgram(u64 hash) const {
|
||||
const auto it = std::find_if(hle_funcs.cbegin(), hle_funcs.cend(),
|
||||
[hash](const auto& pair) { return pair.first == hash; });
|
||||
if (it == hle_funcs.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::make_unique<HLEMacroImpl>(maxwell3d, it->second);
|
||||
}
|
||||
|
||||
HLEMacroImpl::~HLEMacroImpl() = default;
|
||||
|
||||
HLEMacroImpl::HLEMacroImpl(Engines::Maxwell3D& maxwell3d, HLEFunction func)
|
||||
: maxwell3d(maxwell3d), func(func) {}
|
||||
|
||||
void HLEMacroImpl::Execute(const std::vector<u32>& parameters, u32 method) {
|
||||
func(maxwell3d, parameters);
|
||||
}
|
||||
|
||||
} // namespace Tegra
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/macro/macro.h"
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
namespace Engines {
|
||||
class Maxwell3D;
|
||||
}
|
||||
|
||||
using HLEFunction = void (*)(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters);
|
||||
|
||||
class HLEMacro {
|
||||
public:
|
||||
explicit HLEMacro(Engines::Maxwell3D& maxwell3d);
|
||||
~HLEMacro();
|
||||
|
||||
std::optional<std::unique_ptr<CachedMacro>> GetHLEProgram(u64 hash) const;
|
||||
|
||||
private:
|
||||
Engines::Maxwell3D& maxwell3d;
|
||||
};
|
||||
|
||||
class HLEMacroImpl : public CachedMacro {
|
||||
public:
|
||||
explicit HLEMacroImpl(Engines::Maxwell3D& maxwell3d, HLEFunction func);
|
||||
~HLEMacroImpl();
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, u32 method) override;
|
||||
|
||||
private:
|
||||
Engines::Maxwell3D& maxwell3d;
|
||||
HLEFunction func;
|
||||
};
|
||||
|
||||
} // namespace Tegra
|
||||
@@ -11,7 +11,8 @@
|
||||
MICROPROFILE_DEFINE(MacroInterp, "GPU", "Execute macro interpreter", MP_RGB(128, 128, 192));
|
||||
|
||||
namespace Tegra {
|
||||
MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
|
||||
MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d)
|
||||
: MacroEngine::MacroEngine(maxwell3d), maxwell3d(maxwell3d) {}
|
||||
|
||||
std::unique_ptr<CachedMacro> MacroInterpreter::Compile(const std::vector<u32>& code) {
|
||||
return std::make_unique<MacroInterpreterImpl>(maxwell3d, code);
|
||||
|
||||
@@ -28,7 +28,8 @@ static const std::bitset<32> PERSISTENT_REGISTERS = Common::X64::BuildRegSet({
|
||||
BRANCH_HOLDER,
|
||||
});
|
||||
|
||||
MacroJITx64::MacroJITx64(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
|
||||
MacroJITx64::MacroJITx64(Engines::Maxwell3D& maxwell3d)
|
||||
: MacroEngine::MacroEngine(maxwell3d), maxwell3d(maxwell3d) {}
|
||||
|
||||
std::unique_ptr<CachedMacro> MacroJITx64::Compile(const std::vector<u32>& code) {
|
||||
return std::make_unique<MacroJITx64Impl>(maxwell3d, code);
|
||||
@@ -54,7 +55,7 @@ void MacroJITx64Impl::Compile_ALU(Macro::Opcode opcode) {
|
||||
const bool is_a_zero = opcode.src_a == 0;
|
||||
const bool is_b_zero = opcode.src_b == 0;
|
||||
const bool valid_operation = !is_a_zero && !is_b_zero;
|
||||
const bool is_move_operation = !is_a_zero && is_b_zero;
|
||||
[[maybe_unused]] const bool is_move_operation = !is_a_zero && is_b_zero;
|
||||
const bool has_zero_register = is_a_zero || is_b_zero;
|
||||
const bool no_zero_reg_skip = opcode.alu_operation == Macro::ALUOperation::AddWithCarry ||
|
||||
opcode.alu_operation == Macro::ALUOperation::SubtractWithBorrow;
|
||||
@@ -73,7 +74,6 @@ void MacroJITx64Impl::Compile_ALU(Macro::Opcode opcode) {
|
||||
src_b = Compile_GetRegister(opcode.src_b, eax);
|
||||
}
|
||||
}
|
||||
Xbyak::Label skip_carry{};
|
||||
|
||||
bool has_emitted = false;
|
||||
|
||||
@@ -240,7 +240,7 @@ void MacroJITx64Impl::Compile_ExtractInsert(Macro::Opcode opcode) {
|
||||
}
|
||||
|
||||
void MacroJITx64Impl::Compile_ExtractShiftLeftImmediate(Macro::Opcode opcode) {
|
||||
const auto dst = Compile_GetRegister(opcode.src_a, eax);
|
||||
const auto dst = Compile_GetRegister(opcode.src_a, ecx);
|
||||
const auto src = Compile_GetRegister(opcode.src_b, RESULT);
|
||||
|
||||
shr(src, dst.cvt8());
|
||||
@@ -259,7 +259,7 @@ void MacroJITx64Impl::Compile_ExtractShiftLeftImmediate(Macro::Opcode opcode) {
|
||||
}
|
||||
|
||||
void MacroJITx64Impl::Compile_ExtractShiftLeftRegister(Macro::Opcode opcode) {
|
||||
const auto dst = Compile_GetRegister(opcode.src_a, eax);
|
||||
const auto dst = Compile_GetRegister(opcode.src_a, ecx);
|
||||
const auto src = Compile_GetRegister(opcode.src_b, RESULT);
|
||||
|
||||
if (opcode.bf_src_bit != 0) {
|
||||
@@ -274,14 +274,6 @@ void MacroJITx64Impl::Compile_ExtractShiftLeftRegister(Macro::Opcode opcode) {
|
||||
Compile_ProcessResult(opcode.result_operation, opcode.dst);
|
||||
}
|
||||
|
||||
static u32 Read(Engines::Maxwell3D* maxwell3d, u32 method) {
|
||||
return maxwell3d->GetRegisterValue(method);
|
||||
}
|
||||
|
||||
static void Send(Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) {
|
||||
maxwell3d->CallMethodFromMME(method_address.address, value);
|
||||
}
|
||||
|
||||
void MacroJITx64Impl::Compile_Read(Macro::Opcode opcode) {
|
||||
if (optimizer.zero_reg_skip && opcode.src_a == 0) {
|
||||
if (opcode.immediate == 0) {
|
||||
@@ -299,15 +291,27 @@ void MacroJITx64Impl::Compile_Read(Macro::Opcode opcode) {
|
||||
sub(result, opcode.immediate * -1);
|
||||
}
|
||||
}
|
||||
Common::X64::ABI_PushRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
|
||||
mov(Common::X64::ABI_PARAM1, qword[STATE]);
|
||||
mov(Common::X64::ABI_PARAM2, RESULT);
|
||||
Common::X64::CallFarFunction(*this, &Read);
|
||||
Common::X64::ABI_PopRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
|
||||
mov(RESULT, Common::X64::ABI_RETURN.cvt32());
|
||||
|
||||
// Equivalent to Engines::Maxwell3D::GetRegisterValue:
|
||||
if (optimizer.enable_asserts) {
|
||||
Xbyak::Label pass_range_check;
|
||||
cmp(RESULT, static_cast<u32>(Engines::Maxwell3D::Regs::NUM_REGS));
|
||||
jb(pass_range_check);
|
||||
int3();
|
||||
L(pass_range_check);
|
||||
}
|
||||
mov(rax, qword[STATE]);
|
||||
mov(RESULT,
|
||||
dword[rax + offsetof(Engines::Maxwell3D, regs) +
|
||||
offsetof(Engines::Maxwell3D::Regs, reg_array) + RESULT.cvt64() * sizeof(u32)]);
|
||||
|
||||
Compile_ProcessResult(opcode.result_operation, opcode.dst);
|
||||
}
|
||||
|
||||
static void Send(Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) {
|
||||
maxwell3d->CallMethodFromMME(method_address.address, value);
|
||||
}
|
||||
|
||||
void Tegra::MacroJITx64Impl::Compile_Send(Xbyak::Reg32 value) {
|
||||
Common::X64::ABI_PushRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
|
||||
mov(Common::X64::ABI_PARAM1, qword[STATE]);
|
||||
@@ -439,6 +443,9 @@ void MacroJITx64Impl::Compile() {
|
||||
// one if our register isn't "dirty"
|
||||
optimizer.optimize_for_method_move = true;
|
||||
|
||||
// Enable run-time assertions in JITted code
|
||||
optimizer.enable_asserts = false;
|
||||
|
||||
// Check to see if we can skip emitting certain instructions
|
||||
Optimizer_ScanFlags();
|
||||
|
||||
@@ -547,7 +554,7 @@ Xbyak::Reg32 MacroJITx64Impl::Compile_GetRegister(u32 index, Xbyak::Reg32 dst) {
|
||||
}
|
||||
|
||||
void MacroJITx64Impl::Compile_ProcessResult(Macro::ResultOperation operation, u32 reg) {
|
||||
auto SetRegister = [=](u32 reg, Xbyak::Reg32 result) {
|
||||
const auto SetRegister = [this](u32 reg, const Xbyak::Reg32& result) {
|
||||
// Register 0 is supposed to always return 0. NOP is implemented as a store to the zero
|
||||
// register.
|
||||
if (reg == 0) {
|
||||
@@ -555,7 +562,7 @@ void MacroJITx64Impl::Compile_ProcessResult(Macro::ResultOperation operation, u3
|
||||
}
|
||||
mov(dword[STATE + offsetof(JITState, registers) + reg * sizeof(u32)], result);
|
||||
};
|
||||
auto SetMethodAddress = [=](Xbyak::Reg32 reg) { mov(METHOD_ADDRESS, reg); };
|
||||
const auto SetMethodAddress = [this](const Xbyak::Reg32& reg) { mov(METHOD_ADDRESS, reg); };
|
||||
|
||||
switch (operation) {
|
||||
case Macro::ResultOperation::IgnoreAndFetch:
|
||||
|
||||
@@ -76,6 +76,7 @@ private:
|
||||
bool zero_reg_skip{};
|
||||
bool skip_dummy_addimmediate{};
|
||||
bool optimize_for_method_move{};
|
||||
bool enable_asserts{};
|
||||
};
|
||||
OptimizerState optimizer{};
|
||||
|
||||
|
||||
@@ -210,10 +210,11 @@ bool MemoryManager::IsBlockContinuous(const GPUVAddr start, const std::size_t si
|
||||
return range == inner_size;
|
||||
}
|
||||
|
||||
void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, const std::size_t size) const {
|
||||
void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer,
|
||||
const std::size_t size) const {
|
||||
std::size_t remaining_size{size};
|
||||
std::size_t page_index{src_addr >> page_bits};
|
||||
std::size_t page_offset{src_addr & page_mask};
|
||||
std::size_t page_index{gpu_src_addr >> page_bits};
|
||||
std::size_t page_offset{gpu_src_addr & page_mask};
|
||||
|
||||
auto& memory = system.Memory();
|
||||
|
||||
@@ -234,11 +235,11 @@ void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, const std::s
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::ReadBlockUnsafe(GPUVAddr src_addr, void* dest_buffer,
|
||||
void MemoryManager::ReadBlockUnsafe(GPUVAddr gpu_src_addr, void* dest_buffer,
|
||||
const std::size_t size) const {
|
||||
std::size_t remaining_size{size};
|
||||
std::size_t page_index{src_addr >> page_bits};
|
||||
std::size_t page_offset{src_addr & page_mask};
|
||||
std::size_t page_index{gpu_src_addr >> page_bits};
|
||||
std::size_t page_offset{gpu_src_addr & page_mask};
|
||||
|
||||
auto& memory = system.Memory();
|
||||
|
||||
@@ -259,10 +260,11 @@ void MemoryManager::ReadBlockUnsafe(GPUVAddr src_addr, void* dest_buffer,
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, const std::size_t size) {
|
||||
void MemoryManager::WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer,
|
||||
const std::size_t size) {
|
||||
std::size_t remaining_size{size};
|
||||
std::size_t page_index{dest_addr >> page_bits};
|
||||
std::size_t page_offset{dest_addr & page_mask};
|
||||
std::size_t page_index{gpu_dest_addr >> page_bits};
|
||||
std::size_t page_offset{gpu_dest_addr & page_mask};
|
||||
|
||||
auto& memory = system.Memory();
|
||||
|
||||
@@ -283,11 +285,11 @@ void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, const
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::WriteBlockUnsafe(GPUVAddr dest_addr, const void* src_buffer,
|
||||
void MemoryManager::WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buffer,
|
||||
const std::size_t size) {
|
||||
std::size_t remaining_size{size};
|
||||
std::size_t page_index{dest_addr >> page_bits};
|
||||
std::size_t page_offset{dest_addr & page_mask};
|
||||
std::size_t page_index{gpu_dest_addr >> page_bits};
|
||||
std::size_t page_offset{gpu_dest_addr & page_mask};
|
||||
|
||||
auto& memory = system.Memory();
|
||||
|
||||
@@ -306,16 +308,18 @@ void MemoryManager::WriteBlockUnsafe(GPUVAddr dest_addr, const void* src_buffer,
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, const std::size_t size) {
|
||||
void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr,
|
||||
const std::size_t size) {
|
||||
std::vector<u8> tmp_buffer(size);
|
||||
ReadBlock(src_addr, tmp_buffer.data(), size);
|
||||
WriteBlock(dest_addr, tmp_buffer.data(), size);
|
||||
ReadBlock(gpu_src_addr, tmp_buffer.data(), size);
|
||||
WriteBlock(gpu_dest_addr, tmp_buffer.data(), size);
|
||||
}
|
||||
|
||||
void MemoryManager::CopyBlockUnsafe(GPUVAddr dest_addr, GPUVAddr src_addr, const std::size_t size) {
|
||||
void MemoryManager::CopyBlockUnsafe(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr,
|
||||
const std::size_t size) {
|
||||
std::vector<u8> tmp_buffer(size);
|
||||
ReadBlockUnsafe(src_addr, tmp_buffer.data(), size);
|
||||
WriteBlockUnsafe(dest_addr, tmp_buffer.data(), size);
|
||||
ReadBlockUnsafe(gpu_src_addr, tmp_buffer.data(), size);
|
||||
WriteBlockUnsafe(gpu_dest_addr, tmp_buffer.data(), size);
|
||||
}
|
||||
|
||||
bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) {
|
||||
|
||||
@@ -79,9 +79,9 @@ public:
|
||||
* in the Host Memory counterpart. Note: This functions cause Host GPU Memory
|
||||
* Flushes and Invalidations, respectively to each operation.
|
||||
*/
|
||||
void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const;
|
||||
void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size);
|
||||
void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size);
|
||||
void ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const;
|
||||
void WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size);
|
||||
void CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size);
|
||||
|
||||
/**
|
||||
* ReadBlockUnsafe and WriteBlockUnsafe are special versions of ReadBlock and
|
||||
@@ -93,9 +93,9 @@ public:
|
||||
* WriteBlockUnsafe instead of WriteBlock since it shouldn't invalidate the texture
|
||||
* being flushed.
|
||||
*/
|
||||
void ReadBlockUnsafe(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const;
|
||||
void WriteBlockUnsafe(GPUVAddr dest_addr, const void* src_buffer, std::size_t size);
|
||||
void CopyBlockUnsafe(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size);
|
||||
void ReadBlockUnsafe(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const;
|
||||
void WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size);
|
||||
void CopyBlockUnsafe(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size);
|
||||
|
||||
/**
|
||||
* IsGranularRange checks if a gpu region can be simply read with a pointer
|
||||
|
||||
@@ -220,8 +220,8 @@ private:
|
||||
return cache_begin < addr_end && addr_begin < cache_end;
|
||||
};
|
||||
|
||||
const u64 page_end = addr_end >> PAGE_SHIFT;
|
||||
for (u64 page = addr_begin >> PAGE_SHIFT; page <= page_end; ++page) {
|
||||
const u64 page_end = addr_end >> PAGE_BITS;
|
||||
for (u64 page = addr_begin >> PAGE_BITS; page <= page_end; ++page) {
|
||||
const auto& it = cached_queries.find(page);
|
||||
if (it == std::end(cached_queries)) {
|
||||
continue;
|
||||
@@ -242,14 +242,14 @@ private:
|
||||
/// Registers the passed parameters as cached and returns a pointer to the stored cached query.
|
||||
CachedQuery* Register(VideoCore::QueryType type, VAddr cpu_addr, u8* host_ptr, bool timestamp) {
|
||||
rasterizer.UpdatePagesCachedCount(cpu_addr, CachedQuery::SizeInBytes(timestamp), 1);
|
||||
const u64 page = static_cast<u64>(cpu_addr) >> PAGE_SHIFT;
|
||||
const u64 page = static_cast<u64>(cpu_addr) >> PAGE_BITS;
|
||||
return &cached_queries[page].emplace_back(static_cast<QueryCache&>(*this), type, cpu_addr,
|
||||
host_ptr);
|
||||
}
|
||||
|
||||
/// Tries to a get a cached query. Returns nullptr on failure.
|
||||
CachedQuery* TryGet(VAddr addr) {
|
||||
const u64 page = static_cast<u64>(addr) >> PAGE_SHIFT;
|
||||
const u64 page = static_cast<u64>(addr) >> PAGE_BITS;
|
||||
const auto it = cached_queries.find(page);
|
||||
if (it == std::end(cached_queries)) {
|
||||
return nullptr;
|
||||
@@ -268,7 +268,7 @@ private:
|
||||
}
|
||||
|
||||
static constexpr std::uintptr_t PAGE_SIZE = 4096;
|
||||
static constexpr unsigned PAGE_SHIFT = 12;
|
||||
static constexpr unsigned PAGE_BITS = 12;
|
||||
|
||||
Core::System& system;
|
||||
VideoCore::RasterizerInterface& rasterizer;
|
||||
|
||||
@@ -281,14 +281,14 @@ private:
|
||||
|
||||
template <const std::string_view& op>
|
||||
std::string Unary(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("{}{} {}, {};", op, Modifiers(operation), temporary, Visit(operation[0]));
|
||||
return temporary;
|
||||
}
|
||||
|
||||
template <const std::string_view& op>
|
||||
std::string Binary(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("{}{} {}, {}, {};", op, Modifiers(operation), temporary, Visit(operation[0]),
|
||||
Visit(operation[1]));
|
||||
return temporary;
|
||||
@@ -296,7 +296,7 @@ private:
|
||||
|
||||
template <const std::string_view& op>
|
||||
std::string Trinary(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("{}{} {}, {}, {}, {};", op, Modifiers(operation), temporary, Visit(operation[0]),
|
||||
Visit(operation[1]), Visit(operation[2]));
|
||||
return temporary;
|
||||
@@ -304,7 +304,7 @@ private:
|
||||
|
||||
template <const std::string_view& op, bool unordered>
|
||||
std::string FloatComparison(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("TRUNC.U.CC RC.x, {};", Binary<op>(operation));
|
||||
AddLine("MOV.S {}, 0;", temporary);
|
||||
AddLine("MOV.S {} (NE.x), -1;", temporary);
|
||||
@@ -331,7 +331,7 @@ private:
|
||||
|
||||
template <const std::string_view& op, bool is_nan>
|
||||
std::string HalfComparison(Operation operation) {
|
||||
const std::string tmp1 = AllocVectorTemporary();
|
||||
std::string tmp1 = AllocVectorTemporary();
|
||||
const std::string tmp2 = AllocVectorTemporary();
|
||||
const std::string op_a = Visit(operation[0]);
|
||||
const std::string op_b = Visit(operation[1]);
|
||||
@@ -367,15 +367,14 @@ private:
|
||||
AddLine("MOV.F {}.{}, {};", value, Swizzle(i), Visit(meta.values[i]));
|
||||
}
|
||||
|
||||
const std::string result = coord;
|
||||
AddLine("ATOMIM.{}.{} {}.x, {}, {}, image[{}], {};", op, type, result, value, coord,
|
||||
AddLine("ATOMIM.{}.{} {}.x, {}, {}, image[{}], {};", op, type, coord, value, coord,
|
||||
image_id, ImageType(meta.image.type));
|
||||
return fmt::format("{}.x", result);
|
||||
return fmt::format("{}.x", coord);
|
||||
}
|
||||
|
||||
template <const std::string_view& op, const std::string_view& type>
|
||||
std::string Atomic(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
std::string address;
|
||||
std::string_view opname;
|
||||
if (const auto gmem = std::get_if<GmemNode>(&*operation[0])) {
|
||||
@@ -396,7 +395,7 @@ private:
|
||||
|
||||
template <char type>
|
||||
std::string Negate(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
if constexpr (type == 'F') {
|
||||
AddLine("MOV.F32 {}, -{};", temporary, Visit(operation[0]));
|
||||
} else {
|
||||
@@ -407,7 +406,7 @@ private:
|
||||
|
||||
template <char type>
|
||||
std::string Absolute(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("MOV.{} {}, |{}|;", type, temporary, Visit(operation[0]));
|
||||
return temporary;
|
||||
}
|
||||
@@ -1156,20 +1155,20 @@ void ARBDecompiler::VisitAST(const ASTNode& node) {
|
||||
}
|
||||
|
||||
std::string ARBDecompiler::VisitExpression(const Expr& node) {
|
||||
const std::string result = AllocTemporary();
|
||||
if (const auto expr = std::get_if<ExprAnd>(&*node)) {
|
||||
std::string result = AllocTemporary();
|
||||
AddLine("AND.U {}, {}, {};", result, VisitExpression(expr->operand1),
|
||||
VisitExpression(expr->operand2));
|
||||
return result;
|
||||
}
|
||||
if (const auto expr = std::get_if<ExprOr>(&*node)) {
|
||||
const std::string result = AllocTemporary();
|
||||
std::string result = AllocTemporary();
|
||||
AddLine("OR.U {}, {}, {};", result, VisitExpression(expr->operand1),
|
||||
VisitExpression(expr->operand2));
|
||||
return result;
|
||||
}
|
||||
if (const auto expr = std::get_if<ExprNot>(&*node)) {
|
||||
const std::string result = AllocTemporary();
|
||||
std::string result = AllocTemporary();
|
||||
AddLine("CMP.S {}, {}, 0, -1;", result, VisitExpression(expr->operand1));
|
||||
return result;
|
||||
}
|
||||
@@ -1186,7 +1185,7 @@ std::string ARBDecompiler::VisitExpression(const Expr& node) {
|
||||
return expr->value ? "0xffffffff" : "0";
|
||||
}
|
||||
if (const auto expr = std::get_if<ExprGprEqual>(&*node)) {
|
||||
const std::string result = AllocTemporary();
|
||||
std::string result = AllocTemporary();
|
||||
AddLine("SEQ.U {}, R{}.x, {};", result, expr->gpr, expr->value);
|
||||
return result;
|
||||
}
|
||||
@@ -1231,13 +1230,13 @@ std::string ARBDecompiler::Visit(const Node& node) {
|
||||
}
|
||||
|
||||
if (const auto immediate = std::get_if<ImmediateNode>(&*node)) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("MOV.U {}, {};", temporary, immediate->GetValue());
|
||||
return temporary;
|
||||
}
|
||||
|
||||
if (const auto predicate = std::get_if<PredicateNode>(&*node)) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
switch (const auto index = predicate->GetIndex(); index) {
|
||||
case Tegra::Shader::Pred::UnusedIndex:
|
||||
AddLine("MOV.S {}, -1;", temporary);
|
||||
@@ -1333,13 +1332,13 @@ std::string ARBDecompiler::Visit(const Node& node) {
|
||||
} else {
|
||||
offset_string = Visit(offset);
|
||||
}
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("LDC.F32 {}, cbuf{}[{}];", temporary, cbuf->GetIndex(), offset_string);
|
||||
return temporary;
|
||||
}
|
||||
|
||||
if (const auto gmem = std::get_if<GmemNode>(&*node)) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem->GetRealAddress()),
|
||||
Visit(gmem->GetBaseAddress()));
|
||||
AddLine("LDB.U32 {}, {}[{}];", temporary, GlobalMemoryName(gmem->GetDescriptor()),
|
||||
@@ -1348,14 +1347,14 @@ std::string ARBDecompiler::Visit(const Node& node) {
|
||||
}
|
||||
|
||||
if (const auto lmem = std::get_if<LmemNode>(&*node)) {
|
||||
const std::string temporary = Visit(lmem->GetAddress());
|
||||
std::string temporary = Visit(lmem->GetAddress());
|
||||
AddLine("SHR.U {}, {}, 2;", temporary, temporary);
|
||||
AddLine("MOV.U {}, lmem[{}].x;", temporary, temporary);
|
||||
return temporary;
|
||||
}
|
||||
|
||||
if (const auto smem = std::get_if<SmemNode>(&*node)) {
|
||||
const std::string temporary = Visit(smem->GetAddress());
|
||||
std::string temporary = Visit(smem->GetAddress());
|
||||
AddLine("LDS.U32 {}, shared_mem[{}];", temporary, temporary);
|
||||
return temporary;
|
||||
}
|
||||
@@ -1535,7 +1534,7 @@ std::string ARBDecompiler::Assign(Operation operation) {
|
||||
}
|
||||
|
||||
std::string ARBDecompiler::Select(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("CMP.S {}, {}, {}, {};", temporary, Visit(operation[0]), Visit(operation[1]),
|
||||
Visit(operation[2]));
|
||||
return temporary;
|
||||
@@ -1545,12 +1544,12 @@ std::string ARBDecompiler::FClamp(Operation operation) {
|
||||
// 1.0f in hex, replace with std::bit_cast on C++20
|
||||
static constexpr u32 POSITIVE_ONE = 0x3f800000;
|
||||
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
const Node& value = operation[0];
|
||||
const Node& low = operation[1];
|
||||
const Node& high = operation[2];
|
||||
const auto imm_low = std::get_if<ImmediateNode>(&*low);
|
||||
const auto imm_high = std::get_if<ImmediateNode>(&*high);
|
||||
const auto* const imm_low = std::get_if<ImmediateNode>(&*low);
|
||||
const auto* const imm_high = std::get_if<ImmediateNode>(&*high);
|
||||
if (imm_low && imm_high && imm_low->GetValue() == 0 && imm_high->GetValue() == POSITIVE_ONE) {
|
||||
AddLine("MOV.F32.SAT {}, {};", temporary, Visit(value));
|
||||
} else {
|
||||
@@ -1574,7 +1573,7 @@ std::string ARBDecompiler::FCastHalf1(Operation operation) {
|
||||
}
|
||||
|
||||
std::string ARBDecompiler::FSqrt(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("RSQ.F32 {}, {};", temporary, Visit(operation[0]));
|
||||
AddLine("RCP.F32 {}, {};", temporary, temporary);
|
||||
return temporary;
|
||||
@@ -1588,7 +1587,7 @@ std::string ARBDecompiler::FSwizzleAdd(Operation operation) {
|
||||
AddLine("ADD.F {}.x, {}, {};", temporary, Visit(operation[0]), Visit(operation[1]));
|
||||
return fmt::format("{}.x", temporary);
|
||||
}
|
||||
const std::string lut = AllocVectorTemporary();
|
||||
|
||||
AddLine("AND.U {}.z, {}.threadid, 3;", temporary, StageInputName(stage));
|
||||
AddLine("SHL.U {}.z, {}.z, 1;", temporary, temporary);
|
||||
AddLine("SHR.U {}.z, {}, {}.z;", temporary, Visit(operation[2]), temporary);
|
||||
@@ -1766,21 +1765,21 @@ std::string ARBDecompiler::LogicalAssign(Operation operation) {
|
||||
}
|
||||
|
||||
std::string ARBDecompiler::LogicalPick2(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
const u32 index = std::get<ImmediateNode>(*operation[1]).GetValue();
|
||||
AddLine("MOV.U {}, {}.{};", temporary, Visit(operation[0]), Swizzle(index));
|
||||
return temporary;
|
||||
}
|
||||
|
||||
std::string ARBDecompiler::LogicalAnd2(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
const std::string op = Visit(operation[0]);
|
||||
AddLine("AND.U {}, {}.x, {}.y;", temporary, op, op);
|
||||
return temporary;
|
||||
}
|
||||
|
||||
std::string ARBDecompiler::FloatOrdered(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("MOVC.F32 RC.x, {};", Visit(operation[0]));
|
||||
AddLine("MOVC.F32 RC.y, {};", Visit(operation[1]));
|
||||
AddLine("MOV.S {}, -1;", temporary);
|
||||
@@ -1790,7 +1789,7 @@ std::string ARBDecompiler::FloatOrdered(Operation operation) {
|
||||
}
|
||||
|
||||
std::string ARBDecompiler::FloatUnordered(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("MOVC.F32 RC.x, {};", Visit(operation[0]));
|
||||
AddLine("MOVC.F32 RC.y, {};", Visit(operation[1]));
|
||||
AddLine("MOV.S {}, 0;", temporary);
|
||||
@@ -1800,7 +1799,7 @@ std::string ARBDecompiler::FloatUnordered(Operation operation) {
|
||||
}
|
||||
|
||||
std::string ARBDecompiler::LogicalAddCarry(Operation operation) {
|
||||
const std::string temporary = AllocTemporary();
|
||||
std::string temporary = AllocTemporary();
|
||||
AddLine("ADDC.U RC, {}, {};", Visit(operation[0]), Visit(operation[1]));
|
||||
AddLine("MOV.S {}, 0;", temporary);
|
||||
AddLine("IF CF.x;");
|
||||
|
||||
@@ -22,21 +22,46 @@ using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_Buffer_Download, "OpenGL", "Buffer Download", MP_RGB(192, 192, 128));
|
||||
|
||||
Buffer::Buffer(VAddr cpu_addr, const std::size_t size) : VideoCommon::BufferBlock{cpu_addr, size} {
|
||||
Buffer::Buffer(const Device& device, VAddr cpu_addr, std::size_t size)
|
||||
: VideoCommon::BufferBlock{cpu_addr, size} {
|
||||
gl_buffer.Create();
|
||||
glNamedBufferData(gl_buffer.handle, static_cast<GLsizeiptr>(size), nullptr, GL_DYNAMIC_DRAW);
|
||||
if (device.HasVertexBufferUnifiedMemory()) {
|
||||
glMakeNamedBufferResidentNV(gl_buffer.handle, GL_READ_WRITE);
|
||||
glGetNamedBufferParameterui64vNV(gl_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, &gpu_address);
|
||||
}
|
||||
}
|
||||
|
||||
Buffer::~Buffer() = default;
|
||||
|
||||
void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) const {
|
||||
glNamedBufferSubData(Handle(), static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size),
|
||||
data);
|
||||
}
|
||||
|
||||
void Buffer::Download(std::size_t offset, std::size_t size, u8* data) const {
|
||||
MICROPROFILE_SCOPE(OpenGL_Buffer_Download);
|
||||
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
|
||||
glGetNamedBufferSubData(Handle(), static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size),
|
||||
data);
|
||||
}
|
||||
|
||||
void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset,
|
||||
std::size_t size) const {
|
||||
glCopyNamedBufferSubData(src.Handle(), Handle(), static_cast<GLintptr>(src_offset),
|
||||
static_cast<GLintptr>(dst_offset), static_cast<GLsizeiptr>(size));
|
||||
}
|
||||
|
||||
OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
|
||||
const Device& device, std::size_t stream_size)
|
||||
: GenericBufferCache{rasterizer, system, std::make_unique<OGLStreamBuffer>(stream_size, true)} {
|
||||
const Device& device_, std::size_t stream_size)
|
||||
: GenericBufferCache{rasterizer, system,
|
||||
std::make_unique<OGLStreamBuffer>(device_, stream_size, true)},
|
||||
device{device_} {
|
||||
if (!device.HasFastBufferSubData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
static constexpr auto size = static_cast<GLsizeiptr>(Maxwell::MaxConstBufferSize);
|
||||
static constexpr GLsizeiptr size = static_cast<GLsizeiptr>(Maxwell::MaxConstBufferSize);
|
||||
glCreateBuffers(static_cast<GLsizei>(std::size(cbufs)), std::data(cbufs));
|
||||
for (const GLuint cbuf : cbufs) {
|
||||
glNamedBufferData(cbuf, size, nullptr, GL_STREAM_DRAW);
|
||||
@@ -48,39 +73,20 @@ OGLBufferCache::~OGLBufferCache() {
|
||||
}
|
||||
|
||||
std::shared_ptr<Buffer> OGLBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) {
|
||||
return std::make_shared<Buffer>(cpu_addr, size);
|
||||
return std::make_shared<Buffer>(device, cpu_addr, size);
|
||||
}
|
||||
|
||||
GLuint OGLBufferCache::GetEmptyBuffer(std::size_t) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OGLBufferCache::UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||
const u8* data) {
|
||||
glNamedBufferSubData(buffer.Handle(), static_cast<GLintptr>(offset),
|
||||
static_cast<GLsizeiptr>(size), data);
|
||||
}
|
||||
|
||||
void OGLBufferCache::DownloadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||
u8* data) {
|
||||
MICROPROFILE_SCOPE(OpenGL_Buffer_Download);
|
||||
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
|
||||
glGetNamedBufferSubData(buffer.Handle(), static_cast<GLintptr>(offset),
|
||||
static_cast<GLsizeiptr>(size), data);
|
||||
}
|
||||
|
||||
void OGLBufferCache::CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
|
||||
std::size_t dst_offset, std::size_t size) {
|
||||
glCopyNamedBufferSubData(src.Handle(), dst.Handle(), static_cast<GLintptr>(src_offset),
|
||||
static_cast<GLintptr>(dst_offset), static_cast<GLsizeiptr>(size));
|
||||
OGLBufferCache::BufferInfo OGLBufferCache::GetEmptyBuffer(std::size_t) {
|
||||
return {0, 0, 0};
|
||||
}
|
||||
|
||||
OGLBufferCache::BufferInfo OGLBufferCache::ConstBufferUpload(const void* raw_pointer,
|
||||
std::size_t size) {
|
||||
DEBUG_ASSERT(cbuf_cursor < std::size(cbufs));
|
||||
const GLuint cbuf = cbufs[cbuf_cursor++];
|
||||
|
||||
glNamedBufferSubData(cbuf, 0, static_cast<GLsizeiptr>(size), raw_pointer);
|
||||
return {cbuf, 0};
|
||||
return {cbuf, 0, 0};
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
||||
@@ -25,15 +25,27 @@ class RasterizerOpenGL;
|
||||
|
||||
class Buffer : public VideoCommon::BufferBlock {
|
||||
public:
|
||||
explicit Buffer(VAddr cpu_addr, const std::size_t size);
|
||||
explicit Buffer(const Device& device, VAddr cpu_addr, std::size_t size);
|
||||
~Buffer();
|
||||
|
||||
GLuint Handle() const {
|
||||
void Upload(std::size_t offset, std::size_t size, const u8* data) const;
|
||||
|
||||
void Download(std::size_t offset, std::size_t size, u8* data) const;
|
||||
|
||||
void CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset,
|
||||
std::size_t size) const;
|
||||
|
||||
GLuint Handle() const noexcept {
|
||||
return gl_buffer.handle;
|
||||
}
|
||||
|
||||
u64 Address() const noexcept {
|
||||
return gpu_address;
|
||||
}
|
||||
|
||||
private:
|
||||
OGLBuffer gl_buffer;
|
||||
u64 gpu_address = 0;
|
||||
};
|
||||
|
||||
using GenericBufferCache = VideoCommon::BufferCache<Buffer, GLuint, OGLStreamBuffer>;
|
||||
@@ -43,7 +55,7 @@ public:
|
||||
const Device& device, std::size_t stream_size);
|
||||
~OGLBufferCache();
|
||||
|
||||
GLuint GetEmptyBuffer(std::size_t) override;
|
||||
BufferInfo GetEmptyBuffer(std::size_t) override;
|
||||
|
||||
void Acquire() noexcept {
|
||||
cbuf_cursor = 0;
|
||||
@@ -52,22 +64,16 @@ public:
|
||||
protected:
|
||||
std::shared_ptr<Buffer> CreateBlock(VAddr cpu_addr, std::size_t size) override;
|
||||
|
||||
void UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||
const u8* data) override;
|
||||
|
||||
void DownloadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||
u8* data) override;
|
||||
|
||||
void CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
|
||||
std::size_t dst_offset, std::size_t size) override;
|
||||
|
||||
BufferInfo ConstBufferUpload(const void* raw_pointer, std::size_t size) override;
|
||||
|
||||
private:
|
||||
static constexpr std::size_t NUM_CBUFS = Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers *
|
||||
Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram;
|
||||
|
||||
const Device& device;
|
||||
|
||||
std::size_t cbuf_cursor = 0;
|
||||
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers *
|
||||
Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram>
|
||||
cbufs;
|
||||
std::array<GLuint, NUM_CBUFS> cbufs{};
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
||||
|
||||
@@ -178,7 +178,7 @@ bool IsASTCSupported() {
|
||||
for (const GLenum format : formats) {
|
||||
for (const GLenum support : required_support) {
|
||||
GLint value;
|
||||
glGetInternalformativ(GL_TEXTURE_2D, format, support, 1, &value);
|
||||
glGetInternalformativ(target, format, support, 1, &value);
|
||||
if (value != GL_FULL_SUPPORT) {
|
||||
return false;
|
||||
}
|
||||
@@ -188,16 +188,32 @@ bool IsASTCSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Returns true when a GL_RENDERER is a Turing GPU
|
||||
/// @param renderer GL_RENDERER string
|
||||
bool IsTuring(std::string_view renderer) {
|
||||
static constexpr std::array<std::string_view, 12> TURING_GPUS = {
|
||||
"GTX 1650", "GTX 1660", "RTX 2060", "RTX 2070",
|
||||
"RTX 2080", "TITAN RTX", "Quadro RTX 3000", "Quadro RTX 4000",
|
||||
"Quadro RTX 5000", "Quadro RTX 6000", "Quadro RTX 8000", "Tesla T4",
|
||||
};
|
||||
return std::any_of(TURING_GPUS.begin(), TURING_GPUS.end(),
|
||||
[renderer](std::string_view candidate) {
|
||||
return renderer.find(candidate) != std::string_view::npos;
|
||||
});
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
Device::Device()
|
||||
: max_uniform_buffers{BuildMaxUniformBuffers()}, base_bindings{BuildBaseBindings()} {
|
||||
const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||
const std::string_view renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
|
||||
const std::string_view version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
|
||||
const std::vector extensions = GetExtensions();
|
||||
|
||||
const bool is_nvidia = vendor == "NVIDIA Corporation";
|
||||
const bool is_amd = vendor == "ATI Technologies Inc.";
|
||||
const bool is_turing = is_nvidia && IsTuring(renderer);
|
||||
|
||||
bool disable_fast_buffer_sub_data = false;
|
||||
if (is_nvidia && version == "4.6.0 NVIDIA 443.24") {
|
||||
@@ -216,12 +232,21 @@ Device::Device()
|
||||
has_shader_ballot = GLAD_GL_ARB_shader_ballot;
|
||||
has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
|
||||
has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted");
|
||||
has_texture_shadow_lod = HasExtension(extensions, "GL_EXT_texture_shadow_lod");
|
||||
has_astc = IsASTCSupported();
|
||||
has_variable_aoffi = TestVariableAoffi();
|
||||
has_component_indexing_bug = is_amd;
|
||||
has_precise_bug = TestPreciseBug();
|
||||
has_fast_buffer_sub_data = is_nvidia && !disable_fast_buffer_sub_data;
|
||||
has_nv_viewport_array2 = GLAD_GL_NV_viewport_array2;
|
||||
|
||||
// At the moment of writing this, only Nvidia's driver optimizes BufferSubData on exclusive
|
||||
// uniform buffers as "push constants"
|
||||
has_fast_buffer_sub_data = is_nvidia && !disable_fast_buffer_sub_data;
|
||||
|
||||
// Nvidia's driver on Turing GPUs randomly crashes when the buffer is made resident, or on
|
||||
// DeleteBuffers. Disable unified memory on these devices.
|
||||
has_vertex_buffer_unified_memory = GLAD_GL_NV_vertex_buffer_unified_memory && !is_turing;
|
||||
|
||||
use_assembly_shaders = Settings::values.use_assembly_shaders && GLAD_GL_NV_gpu_program5 &&
|
||||
GLAD_GL_NV_compute_program5 && GLAD_GL_NV_transform_feedback &&
|
||||
GLAD_GL_NV_transform_feedback2;
|
||||
@@ -245,6 +270,7 @@ Device::Device(std::nullptr_t) {
|
||||
has_shader_ballot = true;
|
||||
has_vertex_viewport_layer = true;
|
||||
has_image_load_formatted = true;
|
||||
has_texture_shadow_lod = true;
|
||||
has_variable_aoffi = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,14 @@ public:
|
||||
return has_image_load_formatted;
|
||||
}
|
||||
|
||||
bool HasTextureShadowLod() const {
|
||||
return has_texture_shadow_lod;
|
||||
}
|
||||
|
||||
bool HasVertexBufferUnifiedMemory() const {
|
||||
return has_vertex_buffer_unified_memory;
|
||||
}
|
||||
|
||||
bool HasASTC() const {
|
||||
return has_astc;
|
||||
}
|
||||
@@ -110,6 +118,8 @@ private:
|
||||
bool has_shader_ballot{};
|
||||
bool has_vertex_viewport_layer{};
|
||||
bool has_image_load_formatted{};
|
||||
bool has_texture_shadow_lod{};
|
||||
bool has_vertex_buffer_unified_memory{};
|
||||
bool has_astc{};
|
||||
bool has_variable_aoffi{};
|
||||
bool has_component_indexing_bug{};
|
||||
|
||||
@@ -61,7 +61,8 @@ constexpr std::size_t NUM_CONST_BUFFERS_BYTES_PER_STAGE =
|
||||
constexpr std::size_t TOTAL_CONST_BUFFER_BYTES =
|
||||
NUM_CONST_BUFFERS_BYTES_PER_STAGE * Maxwell::MaxShaderStage;
|
||||
|
||||
constexpr std::size_t NumSupportedVertexAttributes = 16;
|
||||
constexpr std::size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16;
|
||||
constexpr std::size_t NUM_SUPPORTED_VERTEX_BINDINGS = 16;
|
||||
|
||||
template <typename Engine, typename Entry>
|
||||
Tegra::Texture::FullTextureInfo GetTextureInfo(const Engine& engine, const Entry& entry,
|
||||
@@ -193,7 +194,7 @@ void RasterizerOpenGL::SetupVertexFormat() {
|
||||
// avoid OpenGL errors.
|
||||
// TODO(Subv): Analyze the shader to identify which attributes are actually used and don't
|
||||
// assume every shader uses them all.
|
||||
for (std::size_t index = 0; index < NumSupportedVertexAttributes; ++index) {
|
||||
for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_ATTRIBUTES; ++index) {
|
||||
if (!flags[Dirty::VertexFormat0 + index]) {
|
||||
continue;
|
||||
}
|
||||
@@ -231,9 +232,11 @@ void RasterizerOpenGL::SetupVertexBuffer() {
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_VB);
|
||||
|
||||
const bool use_unified_memory = device.HasVertexBufferUnifiedMemory();
|
||||
|
||||
// Upload all guest vertex arrays sequentially to our buffer
|
||||
const auto& regs = gpu.regs;
|
||||
for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
|
||||
for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_BINDINGS; ++index) {
|
||||
if (!flags[Dirty::VertexBuffer0 + index]) {
|
||||
continue;
|
||||
}
|
||||
@@ -246,16 +249,25 @@ void RasterizerOpenGL::SetupVertexBuffer() {
|
||||
|
||||
const GPUVAddr start = vertex_array.StartAddress();
|
||||
const GPUVAddr end = regs.vertex_array_limit[index].LimitAddress();
|
||||
|
||||
ASSERT(end >= start);
|
||||
|
||||
const GLuint gl_index = static_cast<GLuint>(index);
|
||||
const u64 size = end - start;
|
||||
if (size == 0) {
|
||||
glBindVertexBuffer(static_cast<GLuint>(index), 0, 0, vertex_array.stride);
|
||||
glBindVertexBuffer(gl_index, 0, 0, vertex_array.stride);
|
||||
if (use_unified_memory) {
|
||||
glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, gl_index, 0, 0);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const auto [vertex_buffer, vertex_buffer_offset] = buffer_cache.UploadMemory(start, size);
|
||||
glBindVertexBuffer(static_cast<GLuint>(index), vertex_buffer, vertex_buffer_offset,
|
||||
vertex_array.stride);
|
||||
const auto info = buffer_cache.UploadMemory(start, size);
|
||||
if (use_unified_memory) {
|
||||
glBindVertexBuffer(gl_index, 0, 0, vertex_array.stride);
|
||||
glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, gl_index,
|
||||
info.address + info.offset, size);
|
||||
} else {
|
||||
glBindVertexBuffer(gl_index, info.handle, info.offset, vertex_array.stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +280,7 @@ void RasterizerOpenGL::SetupVertexInstances() {
|
||||
flags[Dirty::VertexInstances] = false;
|
||||
|
||||
const auto& regs = gpu.regs;
|
||||
for (std::size_t index = 0; index < NumSupportedVertexAttributes; ++index) {
|
||||
for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_ATTRIBUTES; ++index) {
|
||||
if (!flags[Dirty::VertexInstance0 + index]) {
|
||||
continue;
|
||||
}
|
||||
@@ -285,9 +297,9 @@ GLintptr RasterizerOpenGL::SetupIndexBuffer() {
|
||||
MICROPROFILE_SCOPE(OpenGL_Index);
|
||||
const auto& regs = system.GPU().Maxwell3D().regs;
|
||||
const std::size_t size = CalculateIndexBufferSize();
|
||||
const auto [buffer, offset] = buffer_cache.UploadMemory(regs.index_array.IndexStart(), size);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
|
||||
return offset;
|
||||
const auto info = buffer_cache.UploadMemory(regs.index_array.IndexStart(), size);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, info.handle);
|
||||
return info.offset;
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
||||
@@ -643,9 +655,9 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
|
||||
if (!device.UseAssemblyShaders()) {
|
||||
MaxwellUniformData ubo;
|
||||
ubo.SetFromRegs(gpu);
|
||||
const auto [buffer, offset] =
|
||||
const auto info =
|
||||
buffer_cache.UploadHostMemory(&ubo, sizeof(ubo), device.GetUniformBufferAlignment());
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, EmulationUniformBlockBinding, buffer, offset,
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, EmulationUniformBlockBinding, info.handle, info.offset,
|
||||
static_cast<GLsizeiptr>(sizeof(ubo)));
|
||||
}
|
||||
|
||||
@@ -956,8 +968,7 @@ void RasterizerOpenGL::SetupConstBuffer(GLenum stage, u32 binding,
|
||||
if (device.UseAssemblyShaders()) {
|
||||
glBindBufferRangeNV(stage, entry.GetIndex(), 0, 0, 0);
|
||||
} else {
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, binding,
|
||||
buffer_cache.GetEmptyBuffer(sizeof(float)), 0, sizeof(float));
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, binding, 0, 0, sizeof(float));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -970,24 +981,25 @@ void RasterizerOpenGL::SetupConstBuffer(GLenum stage, u32 binding,
|
||||
|
||||
const std::size_t alignment = use_unified ? 4 : device.GetUniformBufferAlignment();
|
||||
const GPUVAddr gpu_addr = buffer.address;
|
||||
auto [cbuf, offset] = buffer_cache.UploadMemory(gpu_addr, size, alignment, false, fast_upload);
|
||||
auto info = buffer_cache.UploadMemory(gpu_addr, size, alignment, false, fast_upload);
|
||||
|
||||
if (device.UseAssemblyShaders()) {
|
||||
UNIMPLEMENTED_IF(use_unified);
|
||||
if (offset != 0) {
|
||||
if (info.offset != 0) {
|
||||
const GLuint staging_cbuf = staging_cbufs[current_cbuf++];
|
||||
glCopyNamedBufferSubData(cbuf, staging_cbuf, offset, 0, size);
|
||||
cbuf = staging_cbuf;
|
||||
offset = 0;
|
||||
glCopyNamedBufferSubData(info.handle, staging_cbuf, info.offset, 0, size);
|
||||
info.handle = staging_cbuf;
|
||||
info.offset = 0;
|
||||
}
|
||||
glBindBufferRangeNV(stage, binding, cbuf, offset, size);
|
||||
glBindBufferRangeNV(stage, binding, info.handle, info.offset, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (use_unified) {
|
||||
glCopyNamedBufferSubData(cbuf, unified_uniform_buffer.handle, offset, unified_offset, size);
|
||||
glCopyNamedBufferSubData(info.handle, unified_uniform_buffer.handle, info.offset,
|
||||
unified_offset, size);
|
||||
} else {
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, binding, cbuf, offset, size);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, binding, info.handle, info.offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1023,9 +1035,8 @@ void RasterizerOpenGL::SetupComputeGlobalMemory(Shader* kernel) {
|
||||
void RasterizerOpenGL::SetupGlobalMemory(u32 binding, const GlobalMemoryEntry& entry,
|
||||
GPUVAddr gpu_addr, std::size_t size) {
|
||||
const auto alignment{device.GetShaderStorageBufferAlignment()};
|
||||
const auto [ssbo, buffer_offset] =
|
||||
buffer_cache.UploadMemory(gpu_addr, size, alignment, entry.is_written);
|
||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, binding, ssbo, buffer_offset,
|
||||
const auto info = buffer_cache.UploadMemory(gpu_addr, size, alignment, entry.is_written);
|
||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, binding, info.handle, info.offset,
|
||||
static_cast<GLsizeiptr>(size));
|
||||
}
|
||||
|
||||
@@ -1712,8 +1723,9 @@ void RasterizerOpenGL::EndTransformFeedback() {
|
||||
const GLuint handle = transform_feedback_buffers[index].handle;
|
||||
const GPUVAddr gpu_addr = binding.Address();
|
||||
const std::size_t size = binding.buffer_size;
|
||||
const auto [dest_buffer, offset] = buffer_cache.UploadMemory(gpu_addr, size, 4, true);
|
||||
glCopyNamedBufferSubData(handle, dest_buffer, 0, offset, static_cast<GLsizeiptr>(size));
|
||||
const auto info = buffer_cache.UploadMemory(gpu_addr, size, 4, true);
|
||||
glCopyNamedBufferSubData(handle, info.handle, 0, info.offset,
|
||||
static_cast<GLsizeiptr>(size));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -460,8 +460,9 @@ Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
|
||||
const u8* host_ptr_b = memory_manager.GetPointer(address_b);
|
||||
code_b = GetShaderCode(memory_manager, address_b, host_ptr_b, false);
|
||||
}
|
||||
const std::size_t code_size = code.size() * sizeof(u64);
|
||||
|
||||
const auto unique_identifier = GetUniqueIdentifier(
|
||||
const u64 unique_identifier = GetUniqueIdentifier(
|
||||
GetShaderType(program), program == Maxwell::ShaderProgram::VertexA, code, code_b);
|
||||
|
||||
const ShaderParameters params{system, disk_cache, device,
|
||||
@@ -477,7 +478,7 @@ Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
|
||||
|
||||
Shader* const result = shader.get();
|
||||
if (cpu_addr) {
|
||||
Register(std::move(shader), *cpu_addr, code.size() * sizeof(u64));
|
||||
Register(std::move(shader), *cpu_addr, code_size);
|
||||
} else {
|
||||
null_shader = std::move(shader);
|
||||
}
|
||||
@@ -495,8 +496,9 @@ Shader* ShaderCacheOpenGL::GetComputeKernel(GPUVAddr code_addr) {
|
||||
|
||||
const auto host_ptr{memory_manager.GetPointer(code_addr)};
|
||||
// No kernel found, create a new one
|
||||
auto code{GetShaderCode(memory_manager, code_addr, host_ptr, true)};
|
||||
const auto unique_identifier{GetUniqueIdentifier(ShaderType::Compute, false, code)};
|
||||
ProgramCode code{GetShaderCode(memory_manager, code_addr, host_ptr, true)};
|
||||
const std::size_t code_size{code.size() * sizeof(u64)};
|
||||
const u64 unique_identifier{GetUniqueIdentifier(ShaderType::Compute, false, code)};
|
||||
|
||||
const ShaderParameters params{system, disk_cache, device,
|
||||
*cpu_addr, host_ptr, unique_identifier};
|
||||
@@ -511,7 +513,7 @@ Shader* ShaderCacheOpenGL::GetComputeKernel(GPUVAddr code_addr) {
|
||||
|
||||
Shader* const result = kernel.get();
|
||||
if (cpu_addr) {
|
||||
Register(std::move(kernel), *cpu_addr, code.size() * sizeof(u64));
|
||||
Register(std::move(kernel), *cpu_addr, code_size);
|
||||
} else {
|
||||
null_kernel = std::move(kernel);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ namespace OpenGL {
|
||||
|
||||
class Device;
|
||||
class RasterizerOpenGL;
|
||||
struct UnspecializedShader;
|
||||
|
||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ using Tegra::Shader::IpaMode;
|
||||
using Tegra::Shader::IpaSampleMode;
|
||||
using Tegra::Shader::PixelImap;
|
||||
using Tegra::Shader::Register;
|
||||
using Tegra::Shader::TextureType;
|
||||
using VideoCommon::Shader::BuildTransformFeedback;
|
||||
using VideoCommon::Shader::Registry;
|
||||
|
||||
@@ -526,6 +527,9 @@ private:
|
||||
if (device.HasImageLoadFormatted()) {
|
||||
code.AddLine("#extension GL_EXT_shader_image_load_formatted : require");
|
||||
}
|
||||
if (device.HasTextureShadowLod()) {
|
||||
code.AddLine("#extension GL_EXT_texture_shadow_lod : require");
|
||||
}
|
||||
if (device.HasWarpIntrinsics()) {
|
||||
code.AddLine("#extension GL_NV_gpu_shader5 : require");
|
||||
code.AddLine("#extension GL_NV_shader_thread_group : require");
|
||||
@@ -909,13 +913,13 @@ private:
|
||||
return "samplerBuffer";
|
||||
}
|
||||
switch (sampler.type) {
|
||||
case Tegra::Shader::TextureType::Texture1D:
|
||||
case TextureType::Texture1D:
|
||||
return "sampler1D";
|
||||
case Tegra::Shader::TextureType::Texture2D:
|
||||
case TextureType::Texture2D:
|
||||
return "sampler2D";
|
||||
case Tegra::Shader::TextureType::Texture3D:
|
||||
case TextureType::Texture3D:
|
||||
return "sampler3D";
|
||||
case Tegra::Shader::TextureType::TextureCube:
|
||||
case TextureType::TextureCube:
|
||||
return "samplerCube";
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@@ -1380,8 +1384,19 @@ private:
|
||||
const std::size_t count = operation.GetOperandsCount();
|
||||
const bool has_array = meta->sampler.is_array;
|
||||
const bool has_shadow = meta->sampler.is_shadow;
|
||||
const bool workaround_lod_array_shadow_as_grad =
|
||||
!device.HasTextureShadowLod() && function_suffix == "Lod" && meta->sampler.is_shadow &&
|
||||
((meta->sampler.type == TextureType::Texture2D && meta->sampler.is_array) ||
|
||||
meta->sampler.type == TextureType::TextureCube);
|
||||
|
||||
std::string expr = "texture";
|
||||
|
||||
if (workaround_lod_array_shadow_as_grad) {
|
||||
expr += "Grad";
|
||||
} else {
|
||||
expr += function_suffix;
|
||||
}
|
||||
|
||||
std::string expr = "texture" + function_suffix;
|
||||
if (!meta->aoffi.empty()) {
|
||||
expr += "Offset";
|
||||
} else if (!meta->ptp.empty()) {
|
||||
@@ -1415,6 +1430,16 @@ private:
|
||||
expr += ')';
|
||||
}
|
||||
|
||||
if (workaround_lod_array_shadow_as_grad) {
|
||||
switch (meta->sampler.type) {
|
||||
case TextureType::Texture2D:
|
||||
return expr + ", vec2(0.0), vec2(0.0))";
|
||||
case TextureType::TextureCube:
|
||||
return expr + ", vec3(0.0), vec3(0.0))";
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
for (const auto& variant : extras) {
|
||||
if (const auto argument = std::get_if<TextureArgument>(&variant)) {
|
||||
expr += GenerateTextureArgument(*argument);
|
||||
@@ -2041,8 +2066,19 @@ private:
|
||||
const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
|
||||
ASSERT(meta);
|
||||
|
||||
std::string expr = GenerateTexture(
|
||||
operation, "Lod", {TextureArgument{Type::Float, meta->lod}, TextureOffset{}});
|
||||
std::string expr{};
|
||||
|
||||
if (!device.HasTextureShadowLod() && meta->sampler.is_shadow &&
|
||||
((meta->sampler.type == TextureType::Texture2D && meta->sampler.is_array) ||
|
||||
meta->sampler.type == TextureType::TextureCube)) {
|
||||
LOG_ERROR(Render_OpenGL,
|
||||
"Device lacks GL_EXT_texture_shadow_lod, using textureGrad as a workaround");
|
||||
expr = GenerateTexture(operation, "Lod", {});
|
||||
} else {
|
||||
expr = GenerateTexture(operation, "Lod",
|
||||
{TextureArgument{Type::Float, meta->lod}, TextureOffset{}});
|
||||
}
|
||||
|
||||
if (meta->sampler.is_shadow) {
|
||||
expr = "vec4(" + expr + ')';
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <deque>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "video_core/renderer_opengl/gl_device.h"
|
||||
#include "video_core/renderer_opengl/gl_stream_buffer.h"
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning",
|
||||
@@ -14,8 +16,7 @@ MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning",
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
OGLStreamBuffer::OGLStreamBuffer(GLsizeiptr size, bool vertex_data_usage, bool prefer_coherent,
|
||||
bool use_persistent)
|
||||
OGLStreamBuffer::OGLStreamBuffer(const Device& device, GLsizeiptr size, bool vertex_data_usage)
|
||||
: buffer_size(size) {
|
||||
gl_buffer.Create();
|
||||
|
||||
@@ -29,23 +30,19 @@ OGLStreamBuffer::OGLStreamBuffer(GLsizeiptr size, bool vertex_data_usage, bool p
|
||||
allocate_size *= 2;
|
||||
}
|
||||
|
||||
if (use_persistent) {
|
||||
persistent = true;
|
||||
coherent = prefer_coherent;
|
||||
const GLbitfield flags =
|
||||
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0);
|
||||
glNamedBufferStorage(gl_buffer.handle, allocate_size, nullptr, flags);
|
||||
mapped_ptr = static_cast<u8*>(glMapNamedBufferRange(
|
||||
gl_buffer.handle, 0, buffer_size, flags | (coherent ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT)));
|
||||
} else {
|
||||
glNamedBufferData(gl_buffer.handle, allocate_size, nullptr, GL_STREAM_DRAW);
|
||||
static constexpr GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
|
||||
glNamedBufferStorage(gl_buffer.handle, allocate_size, nullptr, flags);
|
||||
mapped_ptr = static_cast<u8*>(
|
||||
glMapNamedBufferRange(gl_buffer.handle, 0, buffer_size, flags | GL_MAP_FLUSH_EXPLICIT_BIT));
|
||||
|
||||
if (device.HasVertexBufferUnifiedMemory()) {
|
||||
glMakeNamedBufferResidentNV(gl_buffer.handle, GL_READ_ONLY);
|
||||
glGetNamedBufferParameterui64vNV(gl_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, &gpu_address);
|
||||
}
|
||||
}
|
||||
|
||||
OGLStreamBuffer::~OGLStreamBuffer() {
|
||||
if (persistent) {
|
||||
glUnmapNamedBuffer(gl_buffer.handle);
|
||||
}
|
||||
glUnmapNamedBuffer(gl_buffer.handle);
|
||||
gl_buffer.Release();
|
||||
}
|
||||
|
||||
@@ -60,36 +57,21 @@ std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr a
|
||||
|
||||
bool invalidate = false;
|
||||
if (buffer_pos + size > buffer_size) {
|
||||
MICROPROFILE_SCOPE(OpenGL_StreamBuffer);
|
||||
glInvalidateBufferData(gl_buffer.handle);
|
||||
|
||||
buffer_pos = 0;
|
||||
invalidate = true;
|
||||
|
||||
if (persistent) {
|
||||
glUnmapNamedBuffer(gl_buffer.handle);
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidate || !persistent) {
|
||||
MICROPROFILE_SCOPE(OpenGL_StreamBuffer);
|
||||
GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) |
|
||||
(coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) |
|
||||
(invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
mapped_ptr = static_cast<u8*>(
|
||||
glMapNamedBufferRange(gl_buffer.handle, buffer_pos, buffer_size - buffer_pos, flags));
|
||||
mapped_offset = buffer_pos;
|
||||
}
|
||||
|
||||
return std::make_tuple(mapped_ptr + buffer_pos - mapped_offset, buffer_pos, invalidate);
|
||||
return std::make_tuple(mapped_ptr + buffer_pos, buffer_pos, invalidate);
|
||||
}
|
||||
|
||||
void OGLStreamBuffer::Unmap(GLsizeiptr size) {
|
||||
ASSERT(size <= mapped_size);
|
||||
|
||||
if (!coherent && size > 0) {
|
||||
glFlushMappedNamedBufferRange(gl_buffer.handle, buffer_pos - mapped_offset, size);
|
||||
}
|
||||
|
||||
if (!persistent) {
|
||||
glUnmapNamedBuffer(gl_buffer.handle);
|
||||
if (size > 0) {
|
||||
glFlushMappedNamedBufferRange(gl_buffer.handle, buffer_pos, size);
|
||||
}
|
||||
|
||||
buffer_pos += size;
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class Device;
|
||||
|
||||
class OGLStreamBuffer : private NonCopyable {
|
||||
public:
|
||||
explicit OGLStreamBuffer(GLsizeiptr size, bool vertex_data_usage, bool prefer_coherent = false,
|
||||
bool use_persistent = true);
|
||||
explicit OGLStreamBuffer(const Device& device, GLsizeiptr size, bool vertex_data_usage);
|
||||
~OGLStreamBuffer();
|
||||
|
||||
/*
|
||||
@@ -33,19 +34,20 @@ public:
|
||||
return gl_buffer.handle;
|
||||
}
|
||||
|
||||
GLsizeiptr Size() const {
|
||||
u64 Address() const {
|
||||
return gpu_address;
|
||||
}
|
||||
|
||||
GLsizeiptr Size() const noexcept {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
private:
|
||||
OGLBuffer gl_buffer;
|
||||
|
||||
bool coherent = false;
|
||||
bool persistent = false;
|
||||
|
||||
GLuint64EXT gpu_address = 0;
|
||||
GLintptr buffer_pos = 0;
|
||||
GLsizeiptr buffer_size = 0;
|
||||
GLintptr mapped_offset = 0;
|
||||
GLsizeiptr mapped_size = 0;
|
||||
u8* mapped_ptr = nullptr;
|
||||
};
|
||||
|
||||
@@ -488,6 +488,15 @@ void RendererOpenGL::InitOpenGLObjects() {
|
||||
|
||||
// Clear screen to black
|
||||
LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture);
|
||||
|
||||
// Enable unified vertex attributes and query vertex buffer address when the driver supports it
|
||||
if (device.HasVertexBufferUnifiedMemory()) {
|
||||
glEnableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV);
|
||||
|
||||
glMakeNamedBufferResidentNV(vertex_buffer.handle, GL_READ_ONLY);
|
||||
glGetNamedBufferParameterui64vNV(vertex_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV,
|
||||
&vertex_buffer_address);
|
||||
}
|
||||
}
|
||||
|
||||
void RendererOpenGL::AddTelemetryFields() {
|
||||
@@ -656,7 +665,13 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
||||
offsetof(ScreenRectVertex, tex_coord));
|
||||
glVertexAttribBinding(PositionLocation, 0);
|
||||
glVertexAttribBinding(TexCoordLocation, 0);
|
||||
glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex));
|
||||
if (device.HasVertexBufferUnifiedMemory()) {
|
||||
glBindVertexBuffer(0, 0, 0, sizeof(ScreenRectVertex));
|
||||
glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 0, vertex_buffer_address,
|
||||
sizeof(vertices));
|
||||
} else {
|
||||
glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex));
|
||||
}
|
||||
|
||||
glBindTextureUnit(0, screen_info.display_texture);
|
||||
glBindSampler(0, 0);
|
||||
|
||||
@@ -107,6 +107,9 @@ private:
|
||||
OGLPipeline pipeline;
|
||||
OGLFramebuffer screenshot_framebuffer;
|
||||
|
||||
// GPU address of the vertex buffer
|
||||
GLuint64EXT vertex_buffer_address = 0;
|
||||
|
||||
/// Display information for Switch screen
|
||||
ScreenInfo screen_info;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "common/dynamic_library.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/telemetry.h"
|
||||
#include "core/core.h"
|
||||
@@ -76,7 +77,8 @@ Common::DynamicLibrary OpenVulkanLibrary() {
|
||||
char* libvulkan_env = getenv("LIBVULKAN_PATH");
|
||||
if (!libvulkan_env || !library.Open(libvulkan_env)) {
|
||||
// Use the libvulkan.dylib from the application bundle.
|
||||
std::string filename = File::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib";
|
||||
const std::string filename =
|
||||
FileUtil::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib";
|
||||
library.Open(filename.c_str());
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -37,9 +37,9 @@ std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const VKDevice& device, VKSch
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VAddr cpu_addr,
|
||||
std::size_t size)
|
||||
: VideoCommon::BufferBlock{cpu_addr, size} {
|
||||
Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKScheduler& scheduler_,
|
||||
VKStagingBufferPool& staging_pool_, VAddr cpu_addr, std::size_t size)
|
||||
: VideoCommon::BufferBlock{cpu_addr, size}, scheduler{scheduler_}, staging_pool{staging_pool_} {
|
||||
VkBufferCreateInfo ci;
|
||||
ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
ci.pNext = nullptr;
|
||||
@@ -56,40 +56,15 @@ Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VAddr cp
|
||||
|
||||
Buffer::~Buffer() = default;
|
||||
|
||||
VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
|
||||
const VKDevice& device, VKMemoryManager& memory_manager,
|
||||
VKScheduler& scheduler, VKStagingBufferPool& staging_pool)
|
||||
: VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer, system,
|
||||
CreateStreamBuffer(device,
|
||||
scheduler)},
|
||||
device{device}, memory_manager{memory_manager}, scheduler{scheduler}, staging_pool{
|
||||
staging_pool} {}
|
||||
|
||||
VKBufferCache::~VKBufferCache() = default;
|
||||
|
||||
std::shared_ptr<Buffer> VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) {
|
||||
return std::make_shared<Buffer>(device, memory_manager, cpu_addr, size);
|
||||
}
|
||||
|
||||
VkBuffer VKBufferCache::GetEmptyBuffer(std::size_t size) {
|
||||
size = std::max(size, std::size_t(4));
|
||||
const auto& empty = staging_pool.GetUnusedBuffer(size, false);
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([size, buffer = *empty.handle](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.FillBuffer(buffer, 0, size, 0);
|
||||
});
|
||||
return *empty.handle;
|
||||
}
|
||||
|
||||
void VKBufferCache::UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||
const u8* data) {
|
||||
void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) const {
|
||||
const auto& staging = staging_pool.GetUnusedBuffer(size, true);
|
||||
std::memcpy(staging.commit->Map(size), data, size);
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([staging = *staging.handle, buffer = buffer.Handle(), offset,
|
||||
size](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.CopyBuffer(staging, buffer, VkBufferCopy{0, offset, size});
|
||||
|
||||
const VkBuffer handle = Handle();
|
||||
scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, size});
|
||||
|
||||
VkBufferMemoryBarrier barrier;
|
||||
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
|
||||
@@ -98,7 +73,7 @@ void VKBufferCache::UploadBlockData(const Buffer& buffer, std::size_t offset, st
|
||||
barrier.dstAccessMask = UPLOAD_ACCESS_BARRIERS;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.buffer = buffer;
|
||||
barrier.buffer = handle;
|
||||
barrier.offset = offset;
|
||||
barrier.size = size;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {},
|
||||
@@ -106,12 +81,12 @@ void VKBufferCache::UploadBlockData(const Buffer& buffer, std::size_t offset, st
|
||||
});
|
||||
}
|
||||
|
||||
void VKBufferCache::DownloadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||
u8* data) {
|
||||
void Buffer::Download(std::size_t offset, std::size_t size, u8* data) const {
|
||||
const auto& staging = staging_pool.GetUnusedBuffer(size, true);
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([staging = *staging.handle, buffer = buffer.Handle(), offset,
|
||||
size](vk::CommandBuffer cmdbuf) {
|
||||
|
||||
const VkBuffer handle = Handle();
|
||||
scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) {
|
||||
VkBufferMemoryBarrier barrier;
|
||||
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
|
||||
barrier.pNext = nullptr;
|
||||
@@ -119,7 +94,7 @@ void VKBufferCache::DownloadBlockData(const Buffer& buffer, std::size_t offset,
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.buffer = buffer;
|
||||
barrier.buffer = handle;
|
||||
barrier.offset = offset;
|
||||
barrier.size = size;
|
||||
|
||||
@@ -127,17 +102,19 @@ void VKBufferCache::DownloadBlockData(const Buffer& buffer, std::size_t offset,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, barrier, {});
|
||||
cmdbuf.CopyBuffer(buffer, staging, VkBufferCopy{offset, 0, size});
|
||||
cmdbuf.CopyBuffer(handle, staging, VkBufferCopy{offset, 0, size});
|
||||
});
|
||||
scheduler.Finish();
|
||||
|
||||
std::memcpy(data, staging.commit->Map(size), size);
|
||||
}
|
||||
|
||||
void VKBufferCache::CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
|
||||
std::size_t dst_offset, std::size_t size) {
|
||||
void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset,
|
||||
std::size_t size) const {
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([src_buffer = src.Handle(), dst_buffer = dst.Handle(), src_offset, dst_offset,
|
||||
|
||||
const VkBuffer dst_buffer = Handle();
|
||||
scheduler.Record([src_buffer = src.Handle(), dst_buffer, src_offset, dst_offset,
|
||||
size](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.CopyBuffer(src_buffer, dst_buffer, VkBufferCopy{src_offset, dst_offset, size});
|
||||
|
||||
@@ -165,4 +142,30 @@ void VKBufferCache::CopyBlock(const Buffer& src, const Buffer& dst, std::size_t
|
||||
});
|
||||
}
|
||||
|
||||
VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
|
||||
const VKDevice& device, VKMemoryManager& memory_manager,
|
||||
VKScheduler& scheduler, VKStagingBufferPool& staging_pool)
|
||||
: VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer, system,
|
||||
CreateStreamBuffer(device,
|
||||
scheduler)},
|
||||
device{device}, memory_manager{memory_manager}, scheduler{scheduler}, staging_pool{
|
||||
staging_pool} {}
|
||||
|
||||
VKBufferCache::~VKBufferCache() = default;
|
||||
|
||||
std::shared_ptr<Buffer> VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) {
|
||||
return std::make_shared<Buffer>(device, memory_manager, scheduler, staging_pool, cpu_addr,
|
||||
size);
|
||||
}
|
||||
|
||||
VKBufferCache::BufferInfo VKBufferCache::GetEmptyBuffer(std::size_t size) {
|
||||
size = std::max(size, std::size_t(4));
|
||||
const auto& empty = staging_pool.GetUnusedBuffer(size, false);
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([size, buffer = *empty.handle](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.FillBuffer(buffer, 0, size, 0);
|
||||
});
|
||||
return {*empty.handle, 0, 0};
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -25,15 +25,29 @@ class VKScheduler;
|
||||
|
||||
class Buffer final : public VideoCommon::BufferBlock {
|
||||
public:
|
||||
explicit Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VAddr cpu_addr,
|
||||
std::size_t size);
|
||||
explicit Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKScheduler& scheduler,
|
||||
VKStagingBufferPool& staging_pool, VAddr cpu_addr, std::size_t size);
|
||||
~Buffer();
|
||||
|
||||
void Upload(std::size_t offset, std::size_t size, const u8* data) const;
|
||||
|
||||
void Download(std::size_t offset, std::size_t size, u8* data) const;
|
||||
|
||||
void CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset,
|
||||
std::size_t size) const;
|
||||
|
||||
VkBuffer Handle() const {
|
||||
return *buffer.handle;
|
||||
}
|
||||
|
||||
u64 Address() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
VKScheduler& scheduler;
|
||||
VKStagingBufferPool& staging_pool;
|
||||
|
||||
VKBuffer buffer;
|
||||
};
|
||||
|
||||
@@ -44,20 +58,11 @@ public:
|
||||
VKScheduler& scheduler, VKStagingBufferPool& staging_pool);
|
||||
~VKBufferCache();
|
||||
|
||||
VkBuffer GetEmptyBuffer(std::size_t size) override;
|
||||
BufferInfo GetEmptyBuffer(std::size_t size) override;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Buffer> CreateBlock(VAddr cpu_addr, std::size_t size) override;
|
||||
|
||||
void UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||
const u8* data) override;
|
||||
|
||||
void DownloadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||
u8* data) override;
|
||||
|
||||
void CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
|
||||
std::size_t dst_offset, std::size_t size) override;
|
||||
|
||||
private:
|
||||
const VKDevice& device;
|
||||
VKMemoryManager& memory_manager;
|
||||
|
||||
@@ -143,6 +143,49 @@ Tegra::Texture::FullTextureInfo GetTextureInfo(const Engine& engine, const Entry
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Determine if an attachment to be updated has to preserve contents
|
||||
/// @param is_clear True when a clear is being executed
|
||||
/// @param regs 3D registers
|
||||
/// @return True when the contents have to be preserved
|
||||
bool HasToPreserveColorContents(bool is_clear, const Maxwell& regs) {
|
||||
if (!is_clear) {
|
||||
return true;
|
||||
}
|
||||
// First we have to make sure all clear masks are enabled.
|
||||
if (!regs.clear_buffers.R || !regs.clear_buffers.G || !regs.clear_buffers.B ||
|
||||
!regs.clear_buffers.A) {
|
||||
return true;
|
||||
}
|
||||
// If scissors are disabled, the whole screen is cleared
|
||||
if (!regs.clear_flags.scissor) {
|
||||
return false;
|
||||
}
|
||||
// Then we have to confirm scissor testing clears the whole image
|
||||
const std::size_t index = regs.clear_buffers.RT;
|
||||
const auto& scissor = regs.scissor_test[0];
|
||||
return scissor.min_x > 0 || scissor.min_y > 0 || scissor.max_x < regs.rt[index].width ||
|
||||
scissor.max_y < regs.rt[index].height;
|
||||
}
|
||||
|
||||
/// @brief Determine if an attachment to be updated has to preserve contents
|
||||
/// @param is_clear True when a clear is being executed
|
||||
/// @param regs 3D registers
|
||||
/// @return True when the contents have to be preserved
|
||||
bool HasToPreserveDepthContents(bool is_clear, const Maxwell& regs) {
|
||||
// If we are not clearing, the contents have to be preserved
|
||||
if (!is_clear) {
|
||||
return true;
|
||||
}
|
||||
// For depth stencil clears we only have to confirm scissor test covers the whole image
|
||||
if (!regs.clear_flags.scissor) {
|
||||
return false;
|
||||
}
|
||||
// Make sure the clear cover the whole image
|
||||
const auto& scissor = regs.scissor_test[0];
|
||||
return scissor.min_x > 0 || scissor.min_y > 0 || scissor.max_x < regs.zeta_width ||
|
||||
scissor.max_y < regs.zeta_height;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
class BufferBindings final {
|
||||
@@ -344,7 +387,7 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
|
||||
|
||||
buffer_cache.Unmap();
|
||||
|
||||
const Texceptions texceptions = UpdateAttachments();
|
||||
const Texceptions texceptions = UpdateAttachments(false);
|
||||
SetupImageTransitions(texceptions, color_attachments, zeta_attachment);
|
||||
|
||||
key.renderpass_params = GetRenderPassParams(texceptions);
|
||||
@@ -400,7 +443,7 @@ void RasterizerVulkan::Clear() {
|
||||
return;
|
||||
}
|
||||
|
||||
[[maybe_unused]] const auto texceptions = UpdateAttachments();
|
||||
[[maybe_unused]] const auto texceptions = UpdateAttachments(true);
|
||||
DEBUG_ASSERT(texceptions.none());
|
||||
SetupImageTransitions(0, color_attachments, zeta_attachment);
|
||||
|
||||
@@ -677,9 +720,12 @@ void RasterizerVulkan::FlushWork() {
|
||||
draw_counter = 0;
|
||||
}
|
||||
|
||||
RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() {
|
||||
RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments(bool is_clear) {
|
||||
MICROPROFILE_SCOPE(Vulkan_RenderTargets);
|
||||
auto& dirty = system.GPU().Maxwell3D().dirty.flags;
|
||||
auto& maxwell3d = system.GPU().Maxwell3D();
|
||||
auto& dirty = maxwell3d.dirty.flags;
|
||||
auto& regs = maxwell3d.regs;
|
||||
|
||||
const bool update_rendertargets = dirty[VideoCommon::Dirty::RenderTargets];
|
||||
dirty[VideoCommon::Dirty::RenderTargets] = false;
|
||||
|
||||
@@ -688,7 +734,8 @@ RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() {
|
||||
Texceptions texceptions;
|
||||
for (std::size_t rt = 0; rt < Maxwell::NumRenderTargets; ++rt) {
|
||||
if (update_rendertargets) {
|
||||
color_attachments[rt] = texture_cache.GetColorBufferSurface(rt, true);
|
||||
const bool preserve_contents = HasToPreserveColorContents(is_clear, regs);
|
||||
color_attachments[rt] = texture_cache.GetColorBufferSurface(rt, preserve_contents);
|
||||
}
|
||||
if (color_attachments[rt] && WalkAttachmentOverlaps(*color_attachments[rt])) {
|
||||
texceptions[rt] = true;
|
||||
@@ -696,7 +743,8 @@ RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() {
|
||||
}
|
||||
|
||||
if (update_rendertargets) {
|
||||
zeta_attachment = texture_cache.GetDepthBufferSurface(true);
|
||||
const bool preserve_contents = HasToPreserveDepthContents(is_clear, regs);
|
||||
zeta_attachment = texture_cache.GetDepthBufferSurface(preserve_contents);
|
||||
}
|
||||
if (zeta_attachment && WalkAttachmentOverlaps(*zeta_attachment)) {
|
||||
texceptions[ZETA_TEXCEPTION_INDEX] = true;
|
||||
@@ -870,10 +918,10 @@ void RasterizerVulkan::BeginTransformFeedback() {
|
||||
UNIMPLEMENTED_IF(binding.buffer_offset != 0);
|
||||
|
||||
const GPUVAddr gpu_addr = binding.Address();
|
||||
const std::size_t size = binding.buffer_size;
|
||||
const auto [buffer, offset] = buffer_cache.UploadMemory(gpu_addr, size, 4, true);
|
||||
const VkDeviceSize size = static_cast<VkDeviceSize>(binding.buffer_size);
|
||||
const auto info = buffer_cache.UploadMemory(gpu_addr, size, 4, true);
|
||||
|
||||
scheduler.Record([buffer = buffer, offset = offset, size](vk::CommandBuffer cmdbuf) {
|
||||
scheduler.Record([buffer = info.handle, offset = info.offset, size](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.BindTransformFeedbackBuffersEXT(0, 1, &buffer, &offset, &size);
|
||||
cmdbuf.BeginTransformFeedbackEXT(0, 0, nullptr, nullptr);
|
||||
});
|
||||
@@ -925,8 +973,8 @@ void RasterizerVulkan::SetupVertexArrays(FixedPipelineState::VertexInput& vertex
|
||||
buffer_bindings.AddVertexBinding(DefaultBuffer(), 0);
|
||||
continue;
|
||||
}
|
||||
const auto [buffer, offset] = buffer_cache.UploadMemory(start, size);
|
||||
buffer_bindings.AddVertexBinding(buffer, offset);
|
||||
const auto info = buffer_cache.UploadMemory(start, size);
|
||||
buffer_bindings.AddVertexBinding(info.handle, info.offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -948,7 +996,9 @@ void RasterizerVulkan::SetupIndexBuffer(BufferBindings& buffer_bindings, DrawPar
|
||||
break;
|
||||
}
|
||||
const GPUVAddr gpu_addr = regs.index_array.IndexStart();
|
||||
auto [buffer, offset] = buffer_cache.UploadMemory(gpu_addr, CalculateIndexBufferSize());
|
||||
const auto info = buffer_cache.UploadMemory(gpu_addr, CalculateIndexBufferSize());
|
||||
VkBuffer buffer = info.handle;
|
||||
u64 offset = info.offset;
|
||||
std::tie(buffer, offset) = quad_indexed_pass.Assemble(
|
||||
regs.index_array.format, params.num_vertices, params.base_vertex, buffer, offset);
|
||||
|
||||
@@ -962,7 +1012,9 @@ void RasterizerVulkan::SetupIndexBuffer(BufferBindings& buffer_bindings, DrawPar
|
||||
break;
|
||||
}
|
||||
const GPUVAddr gpu_addr = regs.index_array.IndexStart();
|
||||
auto [buffer, offset] = buffer_cache.UploadMemory(gpu_addr, CalculateIndexBufferSize());
|
||||
const auto info = buffer_cache.UploadMemory(gpu_addr, CalculateIndexBufferSize());
|
||||
VkBuffer buffer = info.handle;
|
||||
u64 offset = info.offset;
|
||||
|
||||
auto format = regs.index_array.format;
|
||||
const bool is_uint8 = format == Maxwell::IndexFormat::UnsignedByte;
|
||||
@@ -1109,10 +1161,9 @@ void RasterizerVulkan::SetupConstBuffer(const ConstBufferEntry& entry,
|
||||
Common::AlignUp(CalculateConstBufferSize(entry, buffer), 4 * sizeof(float));
|
||||
ASSERT(size <= MaxConstbufferSize);
|
||||
|
||||
const auto [buffer_handle, offset] =
|
||||
const auto info =
|
||||
buffer_cache.UploadMemory(buffer.address, size, device.GetUniformBufferAlignment());
|
||||
|
||||
update_descriptor_queue.AddBuffer(buffer_handle, offset, size);
|
||||
update_descriptor_queue.AddBuffer(info.handle, info.offset, size);
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address) {
|
||||
@@ -1126,14 +1177,14 @@ void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAdd
|
||||
// Note: Do *not* use DefaultBuffer() here, storage buffers can be written breaking the
|
||||
// default buffer.
|
||||
static constexpr std::size_t dummy_size = 4;
|
||||
const auto buffer = buffer_cache.GetEmptyBuffer(dummy_size);
|
||||
update_descriptor_queue.AddBuffer(buffer, 0, dummy_size);
|
||||
const auto info = buffer_cache.GetEmptyBuffer(dummy_size);
|
||||
update_descriptor_queue.AddBuffer(info.handle, info.offset, dummy_size);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto [buffer, offset] = buffer_cache.UploadMemory(
|
||||
const auto info = buffer_cache.UploadMemory(
|
||||
actual_addr, size, device.GetStorageBufferAlignment(), entry.IsWritten());
|
||||
update_descriptor_queue.AddBuffer(buffer, offset, size);
|
||||
update_descriptor_queue.AddBuffer(info.handle, info.offset, size);
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SetupUniformTexels(const Tegra::Texture::TICEntry& tic,
|
||||
@@ -1154,7 +1205,7 @@ void RasterizerVulkan::SetupTexture(const Tegra::Texture::FullTextureInfo& textu
|
||||
const auto sampler = sampler_cache.GetSampler(texture.tsc);
|
||||
update_descriptor_queue.AddSampledImage(sampler, image_view);
|
||||
|
||||
const auto image_layout = update_descriptor_queue.GetLastImageLayout();
|
||||
VkImageLayout* const image_layout = update_descriptor_queue.LastImageLayout();
|
||||
*image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
sampled_views.push_back(ImageView{std::move(view), image_layout});
|
||||
}
|
||||
@@ -1180,7 +1231,7 @@ void RasterizerVulkan::SetupImage(const Tegra::Texture::TICEntry& tic, const Ima
|
||||
view->GetImageView(tic.x_source, tic.y_source, tic.z_source, tic.w_source);
|
||||
update_descriptor_queue.AddImage(image_view);
|
||||
|
||||
const auto image_layout = update_descriptor_queue.GetLastImageLayout();
|
||||
VkImageLayout* const image_layout = update_descriptor_queue.LastImageLayout();
|
||||
*image_layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
image_views.push_back(ImageView{std::move(view), image_layout});
|
||||
}
|
||||
|
||||
@@ -159,7 +159,10 @@ private:
|
||||
|
||||
void FlushWork();
|
||||
|
||||
Texceptions UpdateAttachments();
|
||||
/// @brief Updates the currently bound attachments
|
||||
/// @param is_clear True when the framebuffer is updated as a clear
|
||||
/// @return Bitfield of attachments being used as sampled textures
|
||||
Texceptions UpdateAttachments(bool is_clear);
|
||||
|
||||
std::tuple<VkFramebuffer, VkExtent2D> ConfigureFramebuffers(VkRenderPass renderpass);
|
||||
|
||||
|
||||
@@ -35,10 +35,14 @@ public:
|
||||
/// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy.
|
||||
void Unmap(u64 size);
|
||||
|
||||
VkBuffer Handle() const {
|
||||
VkBuffer Handle() const noexcept {
|
||||
return *buffer;
|
||||
}
|
||||
|
||||
u64 Address() const noexcept {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Watch final {
|
||||
VKFenceWatch fence;
|
||||
|
||||
@@ -24,35 +24,25 @@ void VKUpdateDescriptorQueue::TickFrame() {
|
||||
}
|
||||
|
||||
void VKUpdateDescriptorQueue::Acquire() {
|
||||
entries.clear();
|
||||
}
|
||||
// Minimum number of entries required.
|
||||
// This is the maximum number of entries a single draw call migth use.
|
||||
static constexpr std::size_t MIN_ENTRIES = 0x400;
|
||||
|
||||
void VKUpdateDescriptorQueue::Send(VkDescriptorUpdateTemplateKHR update_template,
|
||||
VkDescriptorSet set) {
|
||||
if (payload.size() + entries.size() >= payload.max_size()) {
|
||||
if (payload.size() + MIN_ENTRIES >= payload.max_size()) {
|
||||
LOG_WARNING(Render_Vulkan, "Payload overflow, waiting for worker thread");
|
||||
scheduler.WaitWorker();
|
||||
payload.clear();
|
||||
}
|
||||
upload_start = &*payload.end();
|
||||
}
|
||||
|
||||
// TODO(Rodrigo): Rework to write the payload directly
|
||||
const auto payload_start = payload.data() + payload.size();
|
||||
for (const auto& entry : entries) {
|
||||
if (const auto image = std::get_if<VkDescriptorImageInfo>(&entry)) {
|
||||
payload.push_back(*image);
|
||||
} else if (const auto buffer = std::get_if<VkDescriptorBufferInfo>(&entry)) {
|
||||
payload.push_back(*buffer);
|
||||
} else if (const auto texel = std::get_if<VkBufferView>(&entry)) {
|
||||
payload.push_back(*texel);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
scheduler.Record(
|
||||
[payload_start, set, update_template, logical = &device.GetLogical()](vk::CommandBuffer) {
|
||||
logical->UpdateDescriptorSet(set, update_template, payload_start);
|
||||
});
|
||||
void VKUpdateDescriptorQueue::Send(VkDescriptorUpdateTemplateKHR update_template,
|
||||
VkDescriptorSet set) {
|
||||
const void* const data = upload_start;
|
||||
const vk::Device* const logical = &device.GetLogical();
|
||||
scheduler.Record([data, logical, set, update_template](vk::CommandBuffer) {
|
||||
logical->UpdateDescriptorSet(set, update_template, data);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -15,17 +15,13 @@ namespace Vulkan {
|
||||
class VKDevice;
|
||||
class VKScheduler;
|
||||
|
||||
class DescriptorUpdateEntry {
|
||||
public:
|
||||
explicit DescriptorUpdateEntry() {}
|
||||
struct DescriptorUpdateEntry {
|
||||
DescriptorUpdateEntry(VkDescriptorImageInfo image_) : image{image_} {}
|
||||
|
||||
DescriptorUpdateEntry(VkDescriptorImageInfo image) : image{image} {}
|
||||
DescriptorUpdateEntry(VkDescriptorBufferInfo buffer_) : buffer{buffer_} {}
|
||||
|
||||
DescriptorUpdateEntry(VkDescriptorBufferInfo buffer) : buffer{buffer} {}
|
||||
DescriptorUpdateEntry(VkBufferView texel_buffer_) : texel_buffer{texel_buffer_} {}
|
||||
|
||||
DescriptorUpdateEntry(VkBufferView texel_buffer) : texel_buffer{texel_buffer} {}
|
||||
|
||||
private:
|
||||
union {
|
||||
VkDescriptorImageInfo image;
|
||||
VkDescriptorBufferInfo buffer;
|
||||
@@ -45,32 +41,34 @@ public:
|
||||
void Send(VkDescriptorUpdateTemplateKHR update_template, VkDescriptorSet set);
|
||||
|
||||
void AddSampledImage(VkSampler sampler, VkImageView image_view) {
|
||||
entries.emplace_back(VkDescriptorImageInfo{sampler, image_view, {}});
|
||||
payload.emplace_back(VkDescriptorImageInfo{sampler, image_view, {}});
|
||||
}
|
||||
|
||||
void AddImage(VkImageView image_view) {
|
||||
entries.emplace_back(VkDescriptorImageInfo{{}, image_view, {}});
|
||||
payload.emplace_back(VkDescriptorImageInfo{{}, image_view, {}});
|
||||
}
|
||||
|
||||
void AddBuffer(VkBuffer buffer, u64 offset, std::size_t size) {
|
||||
entries.emplace_back(VkDescriptorBufferInfo{buffer, offset, size});
|
||||
payload.emplace_back(VkDescriptorBufferInfo{buffer, offset, size});
|
||||
}
|
||||
|
||||
void AddTexelBuffer(VkBufferView texel_buffer) {
|
||||
entries.emplace_back(texel_buffer);
|
||||
payload.emplace_back(texel_buffer);
|
||||
}
|
||||
|
||||
VkImageLayout* GetLastImageLayout() {
|
||||
return &std::get<VkDescriptorImageInfo>(entries.back()).imageLayout;
|
||||
VkImageLayout* LastImageLayout() {
|
||||
return &payload.back().image.imageLayout;
|
||||
}
|
||||
|
||||
const VkImageLayout* LastImageLayout() const {
|
||||
return &payload.back().image.imageLayout;
|
||||
}
|
||||
|
||||
private:
|
||||
using Variant = std::variant<VkDescriptorImageInfo, VkDescriptorBufferInfo, VkBufferView>;
|
||||
|
||||
const VKDevice& device;
|
||||
VKScheduler& scheduler;
|
||||
|
||||
boost::container::static_vector<Variant, 0x400> entries;
|
||||
const DescriptorUpdateEntry* upload_start = nullptr;
|
||||
boost::container::static_vector<DescriptorUpdateEntry, 0x10000> payload;
|
||||
};
|
||||
|
||||
|
||||
@@ -725,8 +725,7 @@ bool PhysicalDevice::GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR s
|
||||
return supported == VK_TRUE;
|
||||
}
|
||||
|
||||
VkSurfaceCapabilitiesKHR PhysicalDevice::GetSurfaceCapabilitiesKHR(VkSurfaceKHR surface) const
|
||||
noexcept {
|
||||
VkSurfaceCapabilitiesKHR PhysicalDevice::GetSurfaceCapabilitiesKHR(VkSurfaceKHR surface) const {
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
Check(dld->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &capabilities));
|
||||
return capabilities;
|
||||
|
||||
@@ -779,7 +779,7 @@ public:
|
||||
|
||||
bool GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR) const;
|
||||
|
||||
VkSurfaceCapabilitiesKHR GetSurfaceCapabilitiesKHR(VkSurfaceKHR) const noexcept;
|
||||
VkSurfaceCapabilitiesKHR GetSurfaceCapabilitiesKHR(VkSurfaceKHR) const;
|
||||
|
||||
std::vector<VkSurfaceFormatKHR> GetSurfaceFormatsKHR(VkSurfaceKHR) const;
|
||||
|
||||
|
||||
@@ -13,55 +13,101 @@
|
||||
|
||||
namespace VideoCommon::Shader {
|
||||
|
||||
using std::move;
|
||||
using Tegra::Shader::Instruction;
|
||||
using Tegra::Shader::OpCode;
|
||||
using Tegra::Shader::PredCondition;
|
||||
|
||||
u32 ShaderIR::DecodeHalfSet(NodeBlock& bb, u32 pc) {
|
||||
const Instruction instr = {program_code[pc]};
|
||||
const auto opcode = OpCode::Decode(instr);
|
||||
|
||||
if (instr.hset2.ftz == 0) {
|
||||
PredCondition cond;
|
||||
bool bf;
|
||||
bool ftz;
|
||||
bool neg_a;
|
||||
bool abs_a;
|
||||
bool neg_b;
|
||||
bool abs_b;
|
||||
switch (opcode->get().GetId()) {
|
||||
case OpCode::Id::HSET2_C:
|
||||
case OpCode::Id::HSET2_IMM:
|
||||
cond = instr.hsetp2.cbuf_and_imm.cond;
|
||||
bf = instr.Bit(53);
|
||||
ftz = instr.Bit(54);
|
||||
neg_a = instr.Bit(43);
|
||||
abs_a = instr.Bit(44);
|
||||
neg_b = instr.Bit(56);
|
||||
abs_b = instr.Bit(54);
|
||||
break;
|
||||
case OpCode::Id::HSET2_R:
|
||||
cond = instr.hsetp2.reg.cond;
|
||||
bf = instr.Bit(49);
|
||||
ftz = instr.Bit(50);
|
||||
neg_a = instr.Bit(43);
|
||||
abs_a = instr.Bit(44);
|
||||
neg_b = instr.Bit(31);
|
||||
abs_b = instr.Bit(30);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Node op_b = [this, instr, opcode] {
|
||||
switch (opcode->get().GetId()) {
|
||||
case OpCode::Id::HSET2_C:
|
||||
// Inform as unimplemented as this is not tested.
|
||||
UNIMPLEMENTED_MSG("HSET2_C is not implemented");
|
||||
return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset());
|
||||
case OpCode::Id::HSET2_R:
|
||||
return GetRegister(instr.gpr20);
|
||||
case OpCode::Id::HSET2_IMM:
|
||||
return UnpackHalfImmediate(instr, true);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return Node{};
|
||||
}
|
||||
}();
|
||||
|
||||
if (!ftz) {
|
||||
LOG_DEBUG(HW_GPU, "{} without FTZ is not implemented", opcode->get().GetName());
|
||||
}
|
||||
|
||||
Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.hset2.type_a);
|
||||
op_a = GetOperandAbsNegHalf(op_a, instr.hset2.abs_a, instr.hset2.negate_a);
|
||||
op_a = GetOperandAbsNegHalf(op_a, abs_a, neg_a);
|
||||
|
||||
Node op_b = [&]() {
|
||||
switch (opcode->get().GetId()) {
|
||||
case OpCode::Id::HSET2_R:
|
||||
return GetRegister(instr.gpr20);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return Immediate(0);
|
||||
}
|
||||
}();
|
||||
op_b = UnpackHalfFloat(op_b, instr.hset2.type_b);
|
||||
op_b = GetOperandAbsNegHalf(op_b, instr.hset2.abs_b, instr.hset2.negate_b);
|
||||
switch (opcode->get().GetId()) {
|
||||
case OpCode::Id::HSET2_R:
|
||||
op_b = GetOperandAbsNegHalf(move(op_b), abs_b, neg_b);
|
||||
[[fallthrough]];
|
||||
case OpCode::Id::HSET2_C:
|
||||
op_b = UnpackHalfFloat(move(op_b), instr.hset2.type_b);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const Node second_pred = GetPredicate(instr.hset2.pred39, instr.hset2.neg_pred);
|
||||
Node second_pred = GetPredicate(instr.hset2.pred39, instr.hset2.neg_pred);
|
||||
|
||||
const Node comparison_pair = GetPredicateComparisonHalf(instr.hset2.cond, op_a, op_b);
|
||||
Node comparison_pair = GetPredicateComparisonHalf(cond, op_a, op_b);
|
||||
|
||||
const OperationCode combiner = GetPredicateCombiner(instr.hset2.op);
|
||||
|
||||
// HSET2 operates on each half float in the pack.
|
||||
std::array<Node, 2> values;
|
||||
for (u32 i = 0; i < 2; ++i) {
|
||||
const u32 raw_value = instr.hset2.bf ? 0x3c00 : 0xffff;
|
||||
const Node true_value = Immediate(raw_value << (i * 16));
|
||||
const Node false_value = Immediate(0);
|
||||
|
||||
const Node comparison =
|
||||
Operation(OperationCode::LogicalPick2, comparison_pair, Immediate(i));
|
||||
const Node predicate = Operation(combiner, comparison, second_pred);
|
||||
const u32 raw_value = bf ? 0x3c00 : 0xffff;
|
||||
Node true_value = Immediate(raw_value << (i * 16));
|
||||
Node false_value = Immediate(0);
|
||||
|
||||
Node comparison = Operation(OperationCode::LogicalPick2, comparison_pair, Immediate(i));
|
||||
Node predicate = Operation(combiner, comparison, second_pred);
|
||||
values[i] =
|
||||
Operation(OperationCode::Select, NO_PRECISE, predicate, true_value, false_value);
|
||||
Operation(OperationCode::Select, predicate, move(true_value), move(false_value));
|
||||
}
|
||||
|
||||
const Node value = Operation(OperationCode::UBitwiseOr, NO_PRECISE, values[0], values[1]);
|
||||
SetRegister(bb, instr.gpr0, value);
|
||||
Node value = Operation(OperationCode::UBitwiseOr, values[0], values[1]);
|
||||
SetRegister(bb, instr.gpr0, move(value));
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ ComponentType GetComponentType(Tegra::Engines::SamplerDescriptor descriptor,
|
||||
break;
|
||||
case TextureFormat::B5G6R5:
|
||||
case TextureFormat::B6G5R5:
|
||||
case TextureFormat::BF10GF11RF11:
|
||||
if (component == 0) {
|
||||
return descriptor.b_type;
|
||||
}
|
||||
@@ -119,7 +120,7 @@ ComponentType GetComponentType(Tegra::Engines::SamplerDescriptor descriptor,
|
||||
}
|
||||
break;
|
||||
}
|
||||
UNIMPLEMENTED_MSG("texture format not implement={}", format);
|
||||
UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
|
||||
return ComponentType::FLOAT;
|
||||
}
|
||||
|
||||
@@ -191,6 +192,14 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) {
|
||||
return 6;
|
||||
}
|
||||
return 0;
|
||||
case TextureFormat::BF10GF11RF11:
|
||||
if (component == 1 || component == 2) {
|
||||
return 11;
|
||||
}
|
||||
if (component == 0) {
|
||||
return 10;
|
||||
}
|
||||
return 0;
|
||||
case TextureFormat::G8R24:
|
||||
if (component == 0) {
|
||||
return 8;
|
||||
@@ -211,10 +220,9 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) {
|
||||
return (component == 0 || component == 1) ? 8 : 0;
|
||||
case TextureFormat::G4R4:
|
||||
return (component == 0 || component == 1) ? 4 : 0;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("texture format not implement={}", format);
|
||||
return 0;
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t GetImageComponentMask(TextureFormat format) {
|
||||
@@ -235,6 +243,7 @@ std::size_t GetImageComponentMask(TextureFormat format) {
|
||||
case TextureFormat::R32_B24G8:
|
||||
case TextureFormat::B5G6R5:
|
||||
case TextureFormat::B6G5R5:
|
||||
case TextureFormat::BF10GF11RF11:
|
||||
return std::size_t{R | G | B};
|
||||
case TextureFormat::R32_G32:
|
||||
case TextureFormat::R16_G16:
|
||||
@@ -248,10 +257,9 @@ std::size_t GetImageComponentMask(TextureFormat format) {
|
||||
case TextureFormat::R8:
|
||||
case TextureFormat::R1:
|
||||
return std::size_t{R};
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("texture format not implement={}", format);
|
||||
return std::size_t{R | G | B | A};
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
|
||||
return std::size_t{R | G | B | A};
|
||||
}
|
||||
|
||||
std::size_t GetImageTypeNumCoordinates(Tegra::Shader::ImageType image_type) {
|
||||
@@ -299,7 +307,7 @@ std::pair<Node, bool> ShaderIR::GetComponentValue(ComponentType component_type,
|
||||
return {std::move(original_value), true};
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplement component type={}", component_type);
|
||||
UNIMPLEMENTED_MSG("Unimplemented component type={}", component_type);
|
||||
return {std::move(original_value), true};
|
||||
}
|
||||
}
|
||||
@@ -459,7 +467,7 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Unimplemented operation={} type={}",
|
||||
UNIMPLEMENTED_MSG("Unimplemented operation={}, type={}",
|
||||
static_cast<u64>(instr.suatom_d.operation.Value()),
|
||||
static_cast<u64>(instr.suatom_d.operation_type.Value()));
|
||||
return OperationCode::AtomicImageAdd;
|
||||
|
||||
@@ -66,12 +66,12 @@ ProgramCode GetShaderCode(Tegra::MemoryManager& memory_manager, GPUVAddr gpu_add
|
||||
|
||||
u64 GetUniqueIdentifier(Tegra::Engines::ShaderType shader_type, bool is_a, const ProgramCode& code,
|
||||
const ProgramCode& code_b) {
|
||||
u64 unique_identifier = boost::hash_value(code);
|
||||
size_t unique_identifier = boost::hash_value(code);
|
||||
if (is_a) {
|
||||
// VertexA programs include two programs
|
||||
boost::hash_combine(unique_identifier, boost::hash_value(code_b));
|
||||
}
|
||||
return unique_identifier;
|
||||
return static_cast<u64>(unique_identifier);
|
||||
}
|
||||
|
||||
} // namespace VideoCommon::Shader
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace VideoCommon {
|
||||
|
||||
template <class T>
|
||||
class ShaderCache {
|
||||
static constexpr u64 PAGE_SHIFT = 14;
|
||||
static constexpr u64 PAGE_BITS = 14;
|
||||
|
||||
struct Entry {
|
||||
VAddr addr_start;
|
||||
@@ -87,8 +87,8 @@ protected:
|
||||
const VAddr addr_end = addr + size;
|
||||
Entry* const entry = NewEntry(addr, addr_end, data.get());
|
||||
|
||||
const u64 page_end = addr_end >> PAGE_SHIFT;
|
||||
for (u64 page = addr >> PAGE_SHIFT; page <= page_end; ++page) {
|
||||
const u64 page_end = addr_end >> PAGE_BITS;
|
||||
for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
|
||||
invalidation_cache[page].push_back(entry);
|
||||
}
|
||||
|
||||
@@ -108,8 +108,8 @@ private:
|
||||
/// @pre invalidation_mutex is locked
|
||||
void InvalidatePagesInRegion(VAddr addr, std::size_t size) {
|
||||
const VAddr addr_end = addr + size;
|
||||
const u64 page_end = addr_end >> PAGE_SHIFT;
|
||||
for (u64 page = addr >> PAGE_SHIFT; page <= page_end; ++page) {
|
||||
const u64 page_end = addr_end >> PAGE_BITS;
|
||||
for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
|
||||
const auto it = invalidation_cache.find(page);
|
||||
if (it == invalidation_cache.end()) {
|
||||
continue;
|
||||
|
||||
@@ -120,6 +120,9 @@ std::optional<std::pair<u32, u32>> SurfaceBaseImpl::GetLayerMipmap(
|
||||
}
|
||||
const auto relative_address{static_cast<GPUVAddr>(candidate_gpu_addr - gpu_addr)};
|
||||
const auto layer{static_cast<u32>(relative_address / layer_size)};
|
||||
if (layer >= params.depth) {
|
||||
return {};
|
||||
}
|
||||
const GPUVAddr mipmap_address = relative_address - layer_size * layer;
|
||||
const auto mipmap_it =
|
||||
Common::BinaryFind(mipmap_offsets.begin(), mipmap_offsets.end(), mipmap_address);
|
||||
|
||||
@@ -1053,7 +1053,7 @@ private:
|
||||
void DeduceBestBlit(SurfaceParams& src_params, SurfaceParams& dst_params,
|
||||
const GPUVAddr src_gpu_addr, const GPUVAddr dst_gpu_addr) {
|
||||
auto deduced_src = DeduceSurface(src_gpu_addr, src_params);
|
||||
auto deduced_dst = DeduceSurface(src_gpu_addr, src_params);
|
||||
auto deduced_dst = DeduceSurface(dst_gpu_addr, dst_params);
|
||||
if (deduced_src.Failed() || deduced_dst.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -208,6 +208,10 @@ if (MSVC)
|
||||
copy_yuzu_unicorn_deps(yuzu)
|
||||
endif()
|
||||
|
||||
if (NOT APPLE)
|
||||
target_compile_definitions(yuzu PRIVATE HAS_OPENGL)
|
||||
endif()
|
||||
|
||||
if (ENABLE_VULKAN)
|
||||
target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include)
|
||||
target_compile_definitions(yuzu PRIVATE HAS_VULKAN)
|
||||
|
||||
@@ -8,13 +8,16 @@
|
||||
#include <QHBoxLayout>
|
||||
#include <QKeyEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLContext>
|
||||
#include <QPainter>
|
||||
#include <QScreen>
|
||||
#include <QStringList>
|
||||
#include <QWindow>
|
||||
|
||||
#ifdef HAS_OPENGL
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLContext>
|
||||
#endif
|
||||
|
||||
#if !defined(WIN32) && HAS_VULKAN
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
@@ -98,6 +101,7 @@ void EmuThread::run() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAS_OPENGL
|
||||
class OpenGLSharedContext : public Core::Frontend::GraphicsContext {
|
||||
public:
|
||||
/// Create the original context that should be shared from
|
||||
@@ -183,6 +187,7 @@ private:
|
||||
std::unique_ptr<QOffscreenSurface> offscreen_surface{};
|
||||
QSurface* surface;
|
||||
};
|
||||
#endif
|
||||
|
||||
class DummyContext : public Core::Frontend::GraphicsContext {};
|
||||
|
||||
@@ -355,7 +360,7 @@ QByteArray GRenderWindow::saveGeometry() {
|
||||
}
|
||||
|
||||
qreal GRenderWindow::windowPixelRatio() const {
|
||||
return devicePixelRatio();
|
||||
return devicePixelRatioF();
|
||||
}
|
||||
|
||||
std::pair<u32, u32> GRenderWindow::ScaleTouch(const QPointF& pos) const {
|
||||
@@ -473,6 +478,7 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
|
||||
}
|
||||
|
||||
std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
|
||||
#ifdef HAS_OPENGL
|
||||
if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) {
|
||||
auto c = static_cast<OpenGLSharedContext*>(main_context.get());
|
||||
// Bind the shared contexts to the main surface in case the backend wants to take over
|
||||
@@ -480,6 +486,7 @@ std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedCont
|
||||
return std::make_unique<OpenGLSharedContext>(c->GetShareContext(),
|
||||
child_widget->windowHandle());
|
||||
}
|
||||
#endif
|
||||
return std::make_unique<DummyContext>();
|
||||
}
|
||||
|
||||
@@ -560,6 +567,7 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal
|
||||
}
|
||||
|
||||
bool GRenderWindow::InitializeOpenGL() {
|
||||
#ifdef HAS_OPENGL
|
||||
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
|
||||
// WA_DontShowOnScreen, WA_DeleteOnClose
|
||||
auto child = new OpenGLRenderWidget(this);
|
||||
@@ -571,6 +579,11 @@ bool GRenderWindow::InitializeOpenGL() {
|
||||
std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle()));
|
||||
|
||||
return true;
|
||||
#else
|
||||
QMessageBox::warning(this, tr("OpenGL not available!"),
|
||||
tr("yuzu has not been compiled with OpenGL support."));
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GRenderWindow::InitializeVulkan() {
|
||||
|
||||
@@ -211,7 +211,7 @@ const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> Config::default
|
||||
// This must be in alphabetical order according to action name as it must have the same order as
|
||||
// UISetting::values.shortcuts, which is alphabetically ordered.
|
||||
// clang-format off
|
||||
const std::array<UISettings::Shortcut, 15> Config::default_hotkeys{{
|
||||
const std::array<UISettings::Shortcut, 16> Config::default_hotkeys{{
|
||||
{QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Change Docked Mode"), QStringLiteral("Main Window"), {QStringLiteral("F10"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}},
|
||||
@@ -222,6 +222,7 @@ const std::array<UISettings::Shortcut, 15> Config::default_hotkeys{{
|
||||
{QStringLiteral("Increase Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("+"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Load Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Mute Audio"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user