From f1aed86177591ef2ad8520b61fde9cc3d7c5fb2f Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sun, 8 Jan 2023 19:22:45 +0000 Subject: [PATCH] Add a workaround for split-mapping shaders Some games split shaders across multiple mappings and *also* miss the end header, so read a suitably large amount and hope that's enough for now. --- .../gpu/interconnect/common/shader_cache.cpp | 19 +++++++++++++++++-- .../gpu/interconnect/common/shader_cache.h | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/interconnect/common/shader_cache.cpp b/app/src/main/cpp/skyline/gpu/interconnect/common/shader_cache.cpp index 743caaf6..55bb336d 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/common/shader_cache.cpp +++ b/app/src/main/cpp/skyline/gpu/interconnect/common/shader_cache.cpp @@ -73,6 +73,7 @@ namespace skyline::gpu::interconnect { span blockMappingMirror{blockMapping.data() - mirrorBlock.data() + entry->mirror.data(), blockMapping.size()}; ShaderBinary binary{}; + auto shaderSubmapping{blockMappingMirror.subspan(blockOffset)}; // If nothing was in the cache then do a full shader parse binary.binary = [](span mapping) { // We attempt to find the shader size by looking for "BRA $" (Infinite Loop) which is used as padding at the end of the shader @@ -87,8 +88,22 @@ namespace skyline::gpu::interconnect { return span{shaderInstructions.begin(), it}.cast(); } - return mapping; - }(blockMappingMirror.subspan(blockOffset)); + return span{}; + }(shaderSubmapping); + + if (!binary.binary.valid()) { + static constexpr size_t FallbackSize{0x10000}; //!< Fallback shader size for when we can't detect it with the BRA $ pattern + if (shaderSubmapping.size() > FallbackSize) { + binary.binary = shaderSubmapping; + } else { + // If the shader is split across multiple mappings then read into an internal vector to store the binary + size_t storageOffset{splitBinaryStorage.size()}; + splitBinaryStorage.resize(storageOffset + FallbackSize); + auto shaderStorage{span{splitBinaryStorage}.subspan(storageOffset, FallbackSize)}; + ctx.channelCtx.asCtx->gmmu.Read(shaderStorage, programBase + programOffset); + binary.binary = shaderStorage; + } + } binary.baseOffset = programOffset; diff --git a/app/src/main/cpp/skyline/gpu/interconnect/common/shader_cache.h b/app/src/main/cpp/skyline/gpu/interconnect/common/shader_cache.h index 9c9fa77c..a832af16 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/common/shader_cache.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/common/shader_cache.h @@ -35,6 +35,7 @@ namespace skyline::gpu::interconnect { span mirrorBlock{}; //!< Guest mapped memory block corresponding to `entry` u64 lastProgramBase{}; u32 lastProgramOffset{}; + std::vector splitBinaryStorage; public: /**