diff --git a/app/src/main/cpp/skyline/gpu/interconnect/kepler_compute/pipeline_manager.cpp b/app/src/main/cpp/skyline/gpu/interconnect/kepler_compute/pipeline_manager.cpp index b7d9a0d4..5bbcc11b 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/kepler_compute/pipeline_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/interconnect/kepler_compute/pipeline_manager.cpp @@ -25,7 +25,7 @@ namespace skyline::gpu::interconnect::kepler_compute { Shader::Backend::Bindings bindings{}; - return {ctx.gpu.shader->CompileShader({}, program, bindings), program.info}; + return {ctx.gpu.shader->CompileShader({}, program, bindings, packedState.shaderHash), program.info}; } static Pipeline::DescriptorInfo MakePipelineDescriptorInfo(const Pipeline::ShaderStage &stage) { diff --git a/app/src/main/cpp/skyline/gpu/shader_manager.cpp b/app/src/main/cpp/skyline/gpu/shader_manager.cpp index 6acb6117..b0251025 100644 --- a/app/src/main/cpp/skyline/gpu/shader_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/shader_manager.cpp @@ -35,8 +35,10 @@ namespace skyline::gpu { for (const auto &entry : std::filesystem::directory_iterator{replacementDirPath}) { if (entry.is_regular_file()) { // Parse hash from filename - u64 hash{std::stoull(entry.path().filename().string(), nullptr, 16)}; - auto it{shaderReplacements.insert({hash, {}})}; + auto path{entry.path()}; + auto &replacementMap{path.extension().string() == ".spv" ? hostShaderReplacements : guestShaderReplacements}; + u64 hash{std::stoull(path.stem().string(), nullptr, 16)}; + auto it{replacementMap.insert({hash, {}})}; // Read file into map entry std::ifstream file{entry.path(), std::ios::binary | std::ios::ate}; @@ -48,9 +50,10 @@ namespace skyline::gpu { } } - span ShaderManager::ProcessShaderBinary(u64 hash, span binary) { - auto it{shaderReplacements.find(hash)}; - if (it != shaderReplacements.end()) { + span ShaderManager::ProcessShaderBinary(bool spv, u64 hash, span binary) { + auto &replacementMap{spv ? hostShaderReplacements : guestShaderReplacements}; + auto it{replacementMap.find(hash)}; + if (it != replacementMap.end()) { Logger::Info("Replacing shader with hash: 0x{:X}", hash); return it->second; } @@ -58,7 +61,7 @@ namespace skyline::gpu { if (DumpShaders) { std::scoped_lock lock{dumpMutex}; - auto shaderPath{dumpPath / fmt::format("{:016X}", hash)}; + auto shaderPath{dumpPath / fmt::format("{:016X}{}", hash, spv ? ".spv" : "")}; if (!std::filesystem::exists(shaderPath)) { std::ofstream file{shaderPath, std::ios::binary}; file.write(reinterpret_cast(binary.data()), static_cast(binary.size())); @@ -368,7 +371,7 @@ namespace skyline::gpu { u32 textureConstantBufferIndex, bool viewportTransformEnabled, const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) { - binary = ProcessShaderBinary(hash, binary); + binary = ProcessShaderBinary(false, hash, binary); std::scoped_lock lock{poolMutex}; @@ -395,13 +398,13 @@ namespace skyline::gpu { u32 localMemorySize, u32 sharedMemorySize, std::array workgroupDimensions, const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) { - binary = ProcessShaderBinary(hash, binary); + binary = ProcessShaderBinary(false, hash, binary); std::scoped_lock lock{poolMutex}; ComputeEnvironment environment{binary, baseOffset, textureConstantBufferIndex, localMemorySize, sharedMemorySize, workgroupDimensions, constantBufferRead, getTextureType}; Shader::Maxwell::Flow::CFG cfg{environment, flowBlockPool, Shader::Maxwell::Location{static_cast(baseOffset)}}; - return Shader::Maxwell::TranslateProgram(instructionPool, blockPool, environment, cfg, hostTranslateInfo); + return Shader::Maxwell::TranslateProgram(instructionPool, blockPool, environment, cfg, hostTranslateInfo); } vk::ShaderModule ShaderManager::CompileShader(const Shader::RuntimeInfo &runtimeInfo, Shader::IR::Program &program, Shader::Backend::Bindings &bindings, u64 hash) { @@ -410,11 +413,12 @@ namespace skyline::gpu { if (program.info.loads.Legacy() || program.info.stores.Legacy()) Shader::Maxwell::ConvertLegacyToGeneric(program, runtimeInfo); - auto spirv{Shader::Backend::SPIRV::EmitSPIRV(profile, runtimeInfo, program, bindings)}; + auto spirvEmitted{Shader::Backend::SPIRV::EmitSPIRV(profile, runtimeInfo, program, bindings)}; + auto spirv{ProcessShaderBinary(true, hash, span{spirvEmitted}.cast()).cast()}; vk::ShaderModuleCreateInfo createInfo{ .pCode = spirv.data(), - .codeSize = spirv.size() * sizeof(u32), + .codeSize = spirv.size_bytes(), }; return (*gpu.vkDevice).createShaderModule(createInfo, nullptr, *gpu.vkDevice.getDispatcher()); diff --git a/app/src/main/cpp/skyline/gpu/shader_manager.h b/app/src/main/cpp/skyline/gpu/shader_manager.h index aad432a7..9224f5af 100644 --- a/app/src/main/cpp/skyline/gpu/shader_manager.h +++ b/app/src/main/cpp/skyline/gpu/shader_manager.h @@ -28,7 +28,9 @@ namespace skyline::gpu { Shader::ObjectPool flowBlockPool; Shader::ObjectPool instructionPool; Shader::ObjectPool blockPool; - std::unordered_map> shaderReplacements; //!< Map of shader hash -> replacement shader binary, populated at init time and must not be modified after + std::unordered_map> guestShaderReplacements; //!< Map of guest shader hash -> replacement guest shader binary, populated at init time and must not be modified after + std::unordered_map> hostShaderReplacements; //!< ^^ same as above but for host + std::mutex poolMutex; std::filesystem::path dumpPath; std::mutex dumpMutex; @@ -42,7 +44,7 @@ namespace skyline::gpu { * @brief Returns the raw binary of shader replacement for the given hash, if no replacement is found the input binary is returned * @note This will also dump the binary to disk if dumping is enabled */ - span ProcessShaderBinary(u64 hash, span binary); + span ProcessShaderBinary(bool spv, u64 hash, span binary); public: using ConstantBufferRead = std::function; //!< A function which reads a constant buffer at the specified offset and returns the value