From 76d8172a354dda48fb0bbfe9052721550864eb22 Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Sat, 16 Apr 2022 04:20:38 +0530 Subject: [PATCH] Implement Shader IR Cache This implements the first step of a full shader cache with caching any IR by treating the shared pointer as a handle and key for an associative map alongside hashing the Maxwell shader bytecode, it supports both single shader program and dual vertex program caching. --- .../main/cpp/skyline/gpu/shader_manager.cpp | 22 ++++++++++++++++--- app/src/main/cpp/skyline/gpu/shader_manager.h | 14 ++++++++++-- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/shader_manager.cpp b/app/src/main/cpp/skyline/gpu/shader_manager.cpp index 3b09969e..9762b85d 100644 --- a/app/src/main/cpp/skyline/gpu/shader_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/shader_manager.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) +#include #include #include #include @@ -168,17 +169,32 @@ namespace skyline::gpu { ShaderManager::DualVertexShaderProgram::DualVertexShaderProgram(Shader::IR::Program ir, std::shared_ptr vertexA, std::shared_ptr vertexB) : ShaderProgram{std::move(ir)}, vertexA(std::move(vertexA)), vertexB(std::move(vertexB)) {} std::shared_ptr ShaderManager::ParseGraphicsShader(Shader::Stage stage, span binary, u32 baseOffset, u32 bindlessTextureConstantBufferIndex) { - auto program{std::make_shared()}; + auto &program{programCache[binary]}; + if (program) + return program; + + program = std::make_shared(); GraphicsEnvironment environment{stage, binary, baseOffset, bindlessTextureConstantBufferIndex}; Shader::Maxwell::Flow::CFG cfg(environment, program->flowBlockPool, Shader::Maxwell::Location{static_cast(baseOffset + sizeof(Shader::ProgramHeader))}); - program->program = Shader::Maxwell::TranslateProgram(program->instructionPool, program->blockPool, environment, cfg, hostTranslateInfo); return program; } + constexpr size_t ShaderManager::DualVertexProgramsHash::operator()(const std::pair, std::shared_ptr> &p) const { + size_t hash{}; + boost::hash_combine(hash, p.first); + boost::hash_combine(hash, p.second); + return hash; + } + std::shared_ptr ShaderManager::CombineVertexShaders(const std::shared_ptr &vertexA, const std::shared_ptr &vertexB, span vertexBBinary) { + auto &program{dualProgramCache[DualVertexPrograms{vertexA, vertexB}]}; + if (program) + return program; + VertexBEnvironment vertexBEnvironment{vertexBBinary}; - return std::make_shared(Shader::Maxwell::MergeDualVertexPrograms(vertexA->program, vertexB->program, vertexBEnvironment), vertexA, vertexB); + program = std::make_shared(Shader::Maxwell::MergeDualVertexPrograms(vertexA->program, vertexB->program, vertexBEnvironment), vertexA, vertexB); + return program; } vk::raii::ShaderModule ShaderManager::CompileShader(Shader::RuntimeInfo &runtimeInfo, const std::shared_ptr &program, Shader::Backend::Bindings &bindings) { diff --git a/app/src/main/cpp/skyline/gpu/shader_manager.h b/app/src/main/cpp/skyline/gpu/shader_manager.h index ff967995..abf3de5a 100644 --- a/app/src/main/cpp/skyline/gpu/shader_manager.h +++ b/app/src/main/cpp/skyline/gpu/shader_manager.h @@ -43,6 +43,8 @@ namespace skyline::gpu { SingleShaderProgram &operator=(const SingleShaderProgram &) = delete; }; + std::unordered_map, std::shared_ptr, SpanHash, SpanEqual> programCache; //!< A map from Maxwell bytecode to the corresponding shader program + struct DualVertexShaderProgram : ShaderProgram { std::shared_ptr vertexA; std::shared_ptr vertexB; @@ -54,16 +56,24 @@ namespace skyline::gpu { DualVertexShaderProgram &operator=(const DualVertexShaderProgram &) = delete; }; + using DualVertexPrograms = std::pair, std::shared_ptr>; + + struct DualVertexProgramsHash { + constexpr size_t operator()(const std::pair, std::shared_ptr> &p) const; + }; + + std::unordered_map, DualVertexProgramsHash> dualProgramCache; //!< A map from Vertex A and Vertex B shader programs to the corresponding dual vertex shader program + public: ShaderManager(const DeviceState &state, GPU &gpu); - std::shared_ptr ParseGraphicsShader(Shader::Stage stage, span binary, u32 baseOffset, u32 bindlessTextureConstantBufferIndex); + std::shared_ptr ParseGraphicsShader(Shader::Stage stage, span binary, u32 baseOffset, u32 bindlessTextureConstantBufferIndex); /** * @brief Combines the VertexA and VertexB shader programs into a single program * @note VertexA/VertexB shader programs must be SingleShaderProgram and not DualVertexShaderProgram */ - static std::shared_ptr CombineVertexShaders(const std::shared_ptr &vertexA, const std::shared_ptr &vertexB, span vertexBBinary); + std::shared_ptr CombineVertexShaders(const std::shared_ptr &vertexA, const std::shared_ptr &vertexB, span vertexBBinary); vk::raii::ShaderModule CompileShader(Shader::RuntimeInfo &runtimeInfo, const std::shared_ptr &program, Shader::Backend::Bindings &bindings); };