Compare commits

...

76 Commits

Author SHA1 Message Date
Kewlan
323eb86c9f Fix issues caused when changing the fullscreen hotkey 2020-06-27 11:30:32 +02:00
David
d11baf8bf8 Merge pull request #4141 from Morph1984/SevenSixAxisSensor
hid: Stub a series of "SevenSixAxisSensor" service commands
2020-06-25 19:37:39 +10:00
Morph
2c9308954c hid: Stub a series of "SevenSixAxisSensor" service commands
- Used by Captain Toad: Treasure Tracker Update 1.3.0

While we're at it, fix the input parameters for SetIsPalmaAllConnectable and SetPalmaBoostMode
2020-06-24 11:57:39 -04:00
bunnei
0e1268e507 Merge pull request #4105 from ReinUsesLisp/resident-buffers
gl_rasterizer: Use NV_vertex_buffer_unified_memory for vertex buffer robustness
2020-06-24 11:40:30 -04:00
bunnei
2f2df9a4a7 Merge pull request #4083 from Morph1984/B10G11R11F
decode/image: Implement B10G11R11F
2020-06-24 11:02:38 -04:00
Fernando Sahmkow
32343d820d Merge pull request #4046 from ogniK5377/macro-hle-prod
Add support for HLEing Macros
2020-06-24 09:01:00 -04:00
ReinUsesLisp
32a2dcd415 buffer_cache: Use buffer methods instead of cache virtual methods 2020-06-24 02:36:14 -03:00
ReinUsesLisp
39c97f1b65 gl_stream_buffer: Use InvalidateBufferData instead unmap and map
Making the stream buffer resident increases GPU usage significantly on
some games. This seems to be addressed invalidating the stream buffer
with InvalidateBufferData instead of using a Unmap + Map (with
invalidation flags).
2020-06-24 02:36:14 -03:00
ReinUsesLisp
41a4090320 gl_rasterizer: Use NV_vertex_buffer_unified_memory for vertex buffer robustness
Switch games are allowed to bind less data than what they use in a
vertex buffer, the expected behavior here is that these values are read
as zero. At the moment of writing this only D3D12, OpenGL and NVN through
NV_vertex_buffer_unified_memory support vertex buffer with a size limit.

In theory this could be emulated on Vulkan creating a new VkBuffer for
each (handle, offset, length) tuple and binding the expected data to it.
This is likely going to be slow and memory expensive when used on the
vertex buffer and we have to do it on all draws because we can't know
without analyzing indices when a game is going to read vertex data out
of bounds.

This is not a problem on OpenGL's BufferAddressRangeNV because it takes
a length parameter, unlike Vulkan's CmdBindVertexBuffers that only takes
buffers and offsets (the length is implicit in VkBuffer). It isn't a
problem on D3D12 either, because D3D12_VERTEX_BUFFER_VIEW on
IASetVertexBuffers takes SizeInBytes as a parameter (although I am not
familiar with robustness on D3D12).

Currently this only implements buffer ranges for vertex buffers,
although indices can also be affected. A KHR_robustness profile is not
created, but Nvidia's driver reads out of bound vertex data as zero
anyway, this might have to be changed in the future.

- Fixes SMO random triangles when capturing an enemy, getting hit, or
looking at the environment on certain maps.
2020-06-24 02:36:14 -03:00
ReinUsesLisp
32485917ba gl_buffer_cache: Mark buffers as resident
Make stream buffer and cached buffers as resident and query their
address. This allows us to use GPU addresses for several proprietary
Nvidia extensions.
2020-06-24 02:36:14 -03:00
ReinUsesLisp
73fb3a304b gl_device: Expose NV_vertex_buffer_unified_memory except on Turing
Expose NV_vertex_buffer_unified_memory when the driver supports it.

This commit adds a function the determine if a GL_RENDERER is a Turing
GPU. This is required because on Turing GPUs Nvidia's driver crashes
when the buffer is marked as resident or on DeleteBuffers. Without a
synchronous debug output (single threaded driver), it's likely that
the driver will crash in the first blocking call.
2020-06-24 02:36:14 -03:00
ReinUsesLisp
00c66a7289 gl_stream_buffer: Always use a non-coherent buffer 2020-06-24 02:35:33 -03:00
ReinUsesLisp
da79ec9565 gl_stream_buffer: Always use persistent memory maps
yuzu no longer supports platforms without persistent maps.
2020-06-24 02:35:33 -03:00
Rodrigo Locatti
b66ccaa376 Merge pull request #4129 from Morph1984/texture-shadow-lod-workaround
gl_shader_decompiler: Workaround textureLod when GL_EXT_texture_shadow_lod is not available
2020-06-24 01:51:15 -03:00
David Marcec
f5e2aec422 addressed issues 2020-06-24 12:18:33 +10:00
David Marcec
52340e94ac clear mme draw mode
We already draw, so we can clear it
2020-06-24 12:09:04 +10:00
David Marcec
fabdf5d385 Addressed issues 2020-06-24 12:09:03 +10:00
David Marcec
74b4334d51 Fix constbuffer for 0217920100488FF7 2020-06-24 12:09:02 +10:00
David Marcec
6ce5f3120b Macro HLE support 2020-06-24 12:09:01 +10:00
bunnei
3bab5a5e4a Merge pull request #4138 from Morph1984/GyroscopeZeroDriftMode
hid: Implement Get/ResetGyroscopeZeroDriftMode
2020-06-23 21:56:16 -04:00
bunnei
1d1489da80 Merge pull request #4128 from lioncash/move2
software_keyboard: Eliminate trivial redundant copies
2020-06-23 18:24:15 -04:00
bunnei
bfe2e40882 Merge pull request #4135 from FearlessTobi/port-5324
Port citra-emu/citra#5324: "Update manifest file to include new elements that are introduced with Windows 10 later versions"
2020-06-23 16:03:35 -04:00
bunnei
15aeae3dd3 Merge pull request #4127 from lioncash/dst-typo
texture_cache: Fix incorrect address used in a DeduceSurface() call
2020-06-23 15:59:37 -04:00
bunnei
60da57b518 Merge pull request #3948 from Morph1984/log-cpu-instructions
main/common: Log/append AVX/FMA to the Host CPU string if available and add AVX512 detection
2020-06-23 15:19:47 -04:00
Rodrigo Locatti
2ce3aedda8 Merge pull request #4148 from Morph1984/silence-warnings
Silence miscellaneous warnings
2020-06-23 00:39:04 -03:00
Morph
b8798a995b yuzu_tester: Silence type conversion warning 2020-06-22 22:56:15 -04:00
Morph
45dac6bc5c lm: Silence no return value warning 2020-06-22 22:55:32 -04:00
VolcaEM
e193aa3f53 account: Update function tables and add missing classes (#4145)
* account: Update function tables and add missing classes

* clang-format

* Add missing "public"

* Add missing public again

* Add missing final
2020-06-22 16:03:26 -04:00
LC
25174afa79 Merge pull request #4142 from Morph1984/core-arm-logging
arm_dynarmic: Minor logging changes
2020-06-22 14:21:53 -04:00
Morph
f2df941e8d arm_dynarmic_64: Log the instruction when an exception is raised 2020-06-22 07:00:24 -04:00
Morph
e0af4cdf98 arm_dynarmic_32: Log under Core_ARM instead of HW_GPU 2020-06-22 06:59:41 -04:00
Rodrigo Locatti
406d298457 Merge pull request #4110 from ReinUsesLisp/direct-upload-sets
vk_update_descriptor: Upload descriptor sets data directly
2020-06-22 05:02:13 -03:00
bunnei
14a1181a97 Merge pull request #4122 from lioncash/hide
video_core: Eliminate some variable shadowing
2020-06-21 22:38:04 -04:00
bunnei
c27c76ed43 Merge pull request #4126 from lioncash/noexcept
vulkan/wrapper: Remove noexcept from GetSurfaceCapabilitiesKHR()
2020-06-21 22:36:14 -04:00
bunnei
e8855ed0fc Merge pull request #4134 from FearlessTobi/port-5322
Port citra-emu/citra#5322: "Fix: fatal error CVT1100 when compiling manifest file"
2020-06-21 22:35:17 -04:00
Morph
0235915baa hid: Implement Get/ResetGyroscopeZeroDriftMode
- Used by Captain Toad Treasure Tracker
2020-06-21 16:25:41 -04:00
Morph
f77c897b8d gl_shader_decompiler: Enable GL_EXT_texture_shadow_lod if available
Enable GL_EXT_texture_shadow_lod if available. If this extension is not available, such as on Intel/AMD proprietary drivers, use textureGrad as a workaround.
2020-06-20 23:02:29 -04:00
Morph
1e65da971b gl_device: Check for GL_EXT_texture_shadow_lod 2020-06-20 22:14:32 -04:00
bunnei
f98bf1025f Merge pull request #4120 from lioncash/arb
gl_arb_decompiler: Avoid several string copies
2020-06-20 22:11:49 -04:00
FearlessTobi
20ed33b53b Update manifest file to include new elements that are introduced with Windows 10 later versions
Co-Authored-By: dragios <dragios@users.noreply.github.com>
2020-06-21 03:17:55 +02:00
FearlessTobi
a8674a7b86 Fix: fatal error CVT1100 when compiling manifest file
Occurs when doing a local compile in MSVC build. The compiler I'm using is as below:
Microsoft Visual Studio Community 2019 Preview
Version 16.6.0 Preview 5.0

Fixes this error:
CVTRES : fatal error CVT1100: duplicate resource. type:MANIFEST, name:1, language:0x0409
LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt

I have put 0 since previous name was 1. If have other names in mind, please let me know.

Co-Authored-By: dragios <dragios@users.noreply.github.com>
2020-06-21 03:11:23 +02:00
LC
c6ba7a228d Merge pull request #4133 from MerryMage/macrojit-shifts
macro_jit_x64: Use ecx for shift register
2020-06-20 19:58:51 -04:00
MerryMage
c12eb814b4 macro_jit_x64: Use ecx for shift register
shl/shr only accept cl as their second argument
2020-06-20 22:24:05 +01:00
Lioncash
ef53b2fd08 texture_cache: Fix incorrect address used in a DeduceSurface() call
Previously the source was being deduced twice in a row.
2020-06-20 14:11:28 -04:00
merry
928e9c09aa Merge pull request #4125 from lioncash/macro-shift
macro_jit_x64: Amend readability of Compile_ExtractShiftLeftRegister()
2020-06-20 16:08:23 +01:00
merry
2bd903e021 Merge pull request #4123 from lioncash/unused-var
macro_jit_x64: Remove unused variable
2020-06-20 16:07:58 +01:00
Lioncash
a5ed0c3df7 software_keyboard: Eliminate trivial redundant copies
We can just make use of moves here to get rid of two redundant copies
2020-06-20 01:06:10 -04:00
Morph
9bb5bf0b2b main: Append AVX and FMA instructions to cpu string
Append AVX and FMA instructions to cpu string if the host cpu supports them
2020-06-20 00:31:37 -04:00
Morph
97ba520434 common/telemetry: Add AVX512 to telemetry 2020-06-20 00:31:37 -04:00
Morph
d6474b4aca common/cpu_detect: Add AVX512 detection 2020-06-20 00:31:37 -04:00
Morph
480e1fa987 decode/image: Implement B10G11R11F
- Used by Kirby Star Allies
2020-06-20 00:28:30 -04:00
bunnei
7d1dca4c98 Merge pull request #4099 from MerryMage/macOS-build
Fix compilation on macOS
2020-06-19 23:31:04 -04:00
Lioncash
5865a10885 gl_arb_decompiler: Avoid several string copies
Variables that are marked as const cannot have the move constructor
invoked when returning from a function (the move constructor requires a
non-const variable so it can "steal" the resources from it.
2020-06-19 23:09:16 -04:00
Lioncash
a6e5b84d1f vulkan/wrapper: Remove noexcept from GetSurfaceCapabilitiesKHR()
Check() can throw an exception if the Vulkan result isn't successful.

We remove the check so that std::terminate isn't outright called and
allows for better debugging (should it ever actually fail).
2020-06-19 23:01:59 -04:00
Lioncash
5a4e89b901 macro_jit_x64: Correct readability of Compile_ExtractShiftLeftImmediate()
Previously dst wasn't being used.
2020-06-19 22:57:23 -04:00
Lioncash
140f953b6a macro_jit_x64: Correct readability of Compile_ExtractShiftLeftRegister()
Previously dst wasn't being used.
2020-06-19 22:56:55 -04:00
Lioncash
8ea749c1ca macro_jit_x64: Remove unused variable
Removes a completely unused label and marks another variable as unused,
given it seems like it has potential uses in the future.
2020-06-19 22:10:45 -04:00
Lioncash
479605b3e5 memory_manager: Eliminate variable shadowing
Renames some variables to prevent ones in inner scopes from shadowing
outer-scoped variables.

The Copy* functions have no shadowing, but we rename them anyways to
remain consistent with the other functions.
2020-06-19 22:02:58 -04:00
bunnei
9c5ed4408d Merge pull request #4113 from ogniK5377/boxcat-disable
Fix compilation when not building with boxcat
2020-06-19 21:59:59 -04:00
Lioncash
811bff009e macro_jit_x64: Eliminate variable shadowing in Compile_ProcessResult()
We can reduce the capture scope so that it's not possible for both "reg"
variables to clash with one another.

While we're at it, we can prevent unnecessary copies while we're at it.
2020-06-19 21:57:44 -04:00
Lioncash
4514b80b3e buffer_cache: Eliminate local variable shadowing
We can just make use of the instance in the scope above this one.
2020-06-19 21:55:02 -04:00
bunnei
7daea551c0 Merge pull request #4087 from MerryMage/macrojit-inline-Read
macro_jit_x64: Inline Engines::Maxwell3D::GetRegisterValue
2020-06-19 21:32:07 -04:00
LC
8434630dcc Merge pull request #4114 from MerryMage/nrvo
Remove redundant moves
2020-06-19 15:17:04 -04:00
MerryMage
c6a963c48e input_common/motion_emu: Remove redundant move
Named return value optimization automatically applies here.
2020-06-19 14:29:59 +01:00
MerryMage
8272f53cf9 input_common/keyboard: Remove redundant move
Named return value optimization automatically applies here.
2020-06-19 14:29:36 +01:00
MerryMage
7236393114 mii_model: Remove redundant std::move
Named return value optimization automatically applies here.
2020-06-19 14:29:09 +01:00
MerryMage
977ceb4056 macro_jit_x64: Remove unused function Read 2020-06-19 11:39:41 +01:00
ReinUsesLisp
7d763f060e vk_update_descriptor: Upload descriptor sets data directly
Instead of copying to a temporary payload before sending the update task
to the worker thread, insert elements to the payload directly.
2020-06-18 17:47:19 -03:00
MerryMage
778f86989a bootmanager: Remove references to OpenGL for macOS
OpenGL macOS headers definitions clash heavily with each other
2020-06-18 15:47:44 +01:00
MerryMage
b19fe55f84 memory_manager: Explicitly specifcy std::min<size_t> 2020-06-18 15:47:44 +01:00
MerryMage
4f09f0aea4 shared_font: Service::NS::EncryptSharedFont takes a size_t& 2020-06-18 15:47:44 +01:00
MerryMage
69f38355ed vk_rasterizer: BindTransformFeedbackBuffersEXT accepts a size of type VkDeviceSize 2020-06-18 15:47:44 +01:00
MerryMage
b1eada6079 renderer_vulkan: Fix macOS GetBundleDirectory reference 2020-06-18 15:47:44 +01:00
MerryMage
442e48ef4c memory_util: boost hashes are size_t
* boost::hash_value returns a size_t
* boost::hash_combine takes a size_t& argument
2020-06-18 15:47:43 +01:00
MerryMage
8ae7154541 Rename PAGE_SHIFT to PAGE_BITS
macOS header files #define PAGE_SHIFT
2020-06-18 15:47:43 +01:00
MerryMage
44f10d9b9f macro_jit_x64: Inline Engines::Maxwell3D::GetRegisterValue 2020-06-17 17:17:08 +01:00
67 changed files with 1347 additions and 495 deletions

80
dist/yuzu.manifest vendored
View File

@@ -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>

View File

@@ -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);

View File

@@ -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;
}
}
}

View File

@@ -19,6 +19,7 @@ struct CPUCaps {
bool lzcnt;
bool avx;
bool avx2;
bool avx512;
bool bmi1;
bool bmi2;
bool fma;

View File

@@ -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();
}

View File

@@ -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));
}
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}
@@ -165,7 +165,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);
}

View File

@@ -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};

View File

@@ -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);
}

View File

@@ -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"},
};

View File

@@ -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

View File

@@ -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"},
};

View File

@@ -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);
@@ -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);
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 "";
}
}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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

View File

@@ -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));

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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,10 +240,10 @@ void MacroJITx64Impl::Compile_ExtractInsert(Macro::Opcode opcode) {
}
void MacroJITx64Impl::Compile_ExtractShiftLeftImmediate(Macro::Opcode opcode) {
auto dst = Compile_GetRegister(opcode.src_a, eax);
auto src = Compile_GetRegister(opcode.src_b, RESULT);
const auto dst = Compile_GetRegister(opcode.src_a, ecx);
const auto src = Compile_GetRegister(opcode.src_b, RESULT);
shr(src, al);
shr(src, dst.cvt8());
if (opcode.bf_size != 0 && opcode.bf_size != 31) {
and_(src, opcode.GetBitfieldMask());
} else if (opcode.bf_size == 0) {
@@ -259,8 +259,8 @@ void MacroJITx64Impl::Compile_ExtractShiftLeftImmediate(Macro::Opcode opcode) {
}
void MacroJITx64Impl::Compile_ExtractShiftLeftRegister(Macro::Opcode opcode) {
auto dst = Compile_GetRegister(opcode.src_a, eax);
auto src = Compile_GetRegister(opcode.src_b, RESULT);
const auto dst = Compile_GetRegister(opcode.src_a, ecx);
const auto src = Compile_GetRegister(opcode.src_b, RESULT);
if (opcode.bf_src_bit != 0) {
shr(src, opcode.bf_src_bit);
@@ -269,18 +269,11 @@ void MacroJITx64Impl::Compile_ExtractShiftLeftRegister(Macro::Opcode opcode) {
if (opcode.bf_size != 31) {
and_(src, opcode.GetBitfieldMask());
}
shl(src, al);
shl(src, dst.cvt8());
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) {
@@ -298,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]);
@@ -438,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();
@@ -546,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) {
@@ -554,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:

View File

@@ -76,6 +76,7 @@ private:
bool zero_reg_skip{};
bool skip_dummy_addimmediate{};
bool optimize_for_method_move{};
bool enable_asserts{};
};
OptimizerState optimizer{};

View File

@@ -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) {

View File

@@ -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

View File

@@ -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;

View File

@@ -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;");

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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{};

View File

@@ -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));
}
}

View File

@@ -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 + ')';
}

View File

@@ -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;

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -870,10 +870,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 +925,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 +948,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 +964,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 +1113,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 +1129,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 +1157,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 +1183,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});
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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 {};
@@ -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() {

View File

@@ -217,7 +217,20 @@ GMainWindow::GMainWindow()
LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", yuzu_build_version, Common::g_scm_branch,
Common::g_scm_desc);
#ifdef ARCHITECTURE_x86_64
LOG_INFO(Frontend, "Host CPU: {}", Common::GetCPUCaps().cpu_string);
const auto& caps = Common::GetCPUCaps();
std::string cpu_string = caps.cpu_string;
if (caps.avx || caps.avx2 || caps.avx512) {
cpu_string += " | AVX";
if (caps.avx512) {
cpu_string += "512";
} else if (caps.avx2) {
cpu_string += '2';
}
if (caps.fma || caps.fma4) {
cpu_string += " | FMA";
}
}
LOG_INFO(Frontend, "Host CPU: {}", cpu_string);
#endif
LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString());
LOG_INFO(Frontend, "Host RAM: {:.2f} GB",
@@ -653,6 +666,11 @@ void GMainWindow::InitializeHotkeys() {
ui.action_Capture_Screenshot->setShortcutContext(
hotkey_registry.GetShortcutContext(main_window, capture_screenshot));
ui.action_Fullscreen->setShortcut(
hotkey_registry.GetHotkey(main_window, fullscreen, this)->key());
ui.action_Fullscreen->setShortcutContext(
hotkey_registry.GetShortcutContext(main_window, fullscreen));
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this),
&QShortcut::activated, this, &GMainWindow::OnMenuLoadFile);
connect(
@@ -836,10 +854,6 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui.action_Reset_Window_Size, &QAction::triggered, this, &GMainWindow::ResetWindowSize);
// Fullscreen
ui.action_Fullscreen->setShortcut(
hotkey_registry
.GetHotkey(QStringLiteral("Main Window"), QStringLiteral("Fullscreen"), this)
->key());
connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
// Movie

View File

@@ -16,4 +16,4 @@ IDI_ICON1 ICON "../../dist/yuzu.ico"
// RT_MANIFEST
//
1 RT_MANIFEST "../../dist/yuzu.manifest"
0 RT_MANIFEST "../../dist/yuzu.manifest"

View File

@@ -14,4 +14,4 @@ YUZU_ICON ICON "../../dist/yuzu.ico"
// RT_MANIFEST
//
1 RT_MANIFEST "../../dist/yuzu.manifest"
0 RT_MANIFEST "../../dist/yuzu.manifest"

View File

@@ -53,7 +53,7 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(write_size);
rb.Push<u32>(static_cast<u32>(write_size));
}
void StartIndividual(Kernel::HLERequestContext& ctx) {

View File

@@ -14,4 +14,4 @@ YUZU_ICON ICON "../../dist/yuzu.ico"
// RT_MANIFEST
//
1 RT_MANIFEST "../../dist/yuzu.manifest"
0 RT_MANIFEST "../../dist/yuzu.manifest"