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.
This commit is contained in:
Billy Laws 2023-01-08 19:22:45 +00:00
parent 704660bbeb
commit f1aed86177
2 changed files with 18 additions and 2 deletions

View File

@ -73,6 +73,7 @@ namespace skyline::gpu::interconnect {
span<u8> 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<u8> 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<u8>();
}
return mapping;
}(blockMappingMirror.subspan(blockOffset));
return span<u8>{};
}(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;

View File

@ -35,6 +35,7 @@ namespace skyline::gpu::interconnect {
span<u8> mirrorBlock{}; //!< Guest mapped memory block corresponding to `entry`
u64 lastProgramBase{};
u32 lastProgramOffset{};
std::vector<u8> splitBinaryStorage;
public:
/**