diff --git a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index 3526f0da..a2453ac9 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -636,7 +636,7 @@ namespace skyline::gpu::interconnect { bool shouldCheckSame{false}; //!< If we should do a check for the shader being the same as before u32 offset{}; //!< Offset of the shader from the base IOVA boost::container::static_vector data; //!< The shader bytecode in a statically allocated vector - std::optional program; + std::shared_ptr program{}; Shader(ShaderCompiler::Stage stage) : stage(stage) {} @@ -689,7 +689,7 @@ namespace skyline::gpu::interconnect { bool enabled{false}; vk::ShaderStageFlagBits vkStage; - std::variant> program; //!< The shader program by value or by reference (VertexA and VertexB shaders when combined will store by value, otherwise only a reference is stored) + std::shared_ptr program; //!< The shader program by value or by reference (VertexA and VertexB shaders when combined will store by value, otherwise only a reference is stored) bool needsRecompile{}; //!< If the shader needs to be recompiled as runtime information has changed ShaderCompiler::VaryingState previousStageStores{}; @@ -817,7 +817,7 @@ namespace skyline::gpu::interconnect { shader.program = gpu.shader.ParseGraphicsShader(shader.stage, shader.data, shader.offset, bindlessTextureConstantBufferIndex); if (shader.stage != ShaderCompiler::Stage::VertexA && shader.stage != ShaderCompiler::Stage::VertexB) { - pipelineStage.program.emplace>(*shader.program); + pipelineStage.program = shader.program; } else if (shader.stage == ShaderCompiler::Stage::VertexA) { auto &vertexB{shaders[maxwell3d::ShaderStage::VertexB]}; @@ -825,15 +825,15 @@ namespace skyline::gpu::interconnect { throw exception("Enabling VertexA without VertexB is not supported"); else if (!vertexB.invalidated) // If only VertexA is invalidated, we need to recombine here but we can defer it otherwise - pipelineStage.program = gpu.shader.CombineVertexShaders(*shader.program, *vertexB.program, vertexB.data); + pipelineStage.program = gpu.shader.CombineVertexShaders(shader.program, vertexB.program, vertexB.data); } else if (shader.stage == ShaderCompiler::Stage::VertexB) { auto &vertexA{shaders[maxwell3d::ShaderStage::VertexA]}; if (vertexA.enabled) // We need to combine the vertex shader stages if VertexA is enabled - pipelineStage.program = gpu.shader.CombineVertexShaders(*vertexA.program, *shader.program, shader.data); + pipelineStage.program = gpu.shader.CombineVertexShaders(vertexA.program, shader.program, shader.data); else - pipelineStage.program.emplace>(*shader.program); + pipelineStage.program = shader.program; } pipelineStage.enabled = true; @@ -861,18 +861,14 @@ namespace skyline::gpu::interconnect { if (!pipelineStage.enabled) continue; - auto &program{std::visit(VariantVisitor{ - [](ShaderCompiler::IR::Program &program) -> ShaderCompiler::IR::Program & { return program; }, - [](std::reference_wrapper program) -> ShaderCompiler::IR::Program & { return program.get(); }, - }, pipelineStage.program)}; - if (pipelineStage.needsRecompile || bindings.unified != pipelineStage.bindingBase || pipelineStage.previousStageStores.mask != runtimeInfo.previous_stage_stores.mask) { pipelineStage.previousStageStores = runtimeInfo.previous_stage_stores; pipelineStage.bindingBase = bindings.unified; - pipelineStage.vkModule = std::make_shared(gpu.shader.CompileShader(runtimeInfo, program, bindings)); + pipelineStage.vkModule = std::make_shared(gpu.shader.CompileShader(runtimeInfo, pipelineStage.program, bindings)); pipelineStage.bindingLast = bindings.unified; } + auto &program{pipelineStage.program->program}; runtimeInfo.previous_stage_stores = program.info.stores; if (program.is_geometry_passthrough) runtimeInfo.previous_stage_stores.mask |= program.info.passthrough.mask; diff --git a/app/src/main/cpp/skyline/gpu/shader_manager.cpp b/app/src/main/cpp/skyline/gpu/shader_manager.cpp index 90384629..1276a8d7 100644 --- a/app/src/main/cpp/skyline/gpu/shader_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/shader_manager.cpp @@ -165,20 +165,24 @@ namespace skyline::gpu { } }; - Shader::IR::Program ShaderManager::ParseGraphicsShader(Shader::Stage stage, span binary, u32 baseOffset, u32 bindlessTextureConstantBufferIndex) { + 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()}; GraphicsEnvironment environment{stage, binary, baseOffset, bindlessTextureConstantBufferIndex}; - Shader::Maxwell::Flow::CFG cfg(environment, flowBlockPool, Shader::Maxwell::Location{static_cast(baseOffset + sizeof(Shader::ProgramHeader))}); + Shader::Maxwell::Flow::CFG cfg(environment, program->flowBlockPool, Shader::Maxwell::Location{static_cast(baseOffset + sizeof(Shader::ProgramHeader))}); - return Shader::Maxwell::TranslateProgram(instPool, blockPool, environment, cfg, hostTranslateInfo); + program->program = Shader::Maxwell::TranslateProgram(program->instructionPool, program->blockPool, environment, cfg, hostTranslateInfo); + return program; } - Shader::IR::Program ShaderManager::CombineVertexShaders(Shader::IR::Program &vertexA, Shader::IR::Program &vertexB, span vertexBBinary) { + std::shared_ptr ShaderManager::CombineVertexShaders(const std::shared_ptr &vertexA, const std::shared_ptr &vertexB, span vertexBBinary) { VertexBEnvironment vertexBEnvironment{vertexBBinary}; - return Shader::Maxwell::MergeDualVertexPrograms(vertexA, vertexB, vertexBEnvironment); + return std::make_shared(Shader::Maxwell::MergeDualVertexPrograms(vertexA->program, vertexB->program, vertexBEnvironment), vertexA, vertexB); } - vk::raii::ShaderModule ShaderManager::CompileShader(Shader::RuntimeInfo &runtimeInfo, Shader::IR::Program &program, Shader::Backend::Bindings &bindings) { - auto spirv{Shader::Backend::SPIRV::EmitSPIRV(profile, runtimeInfo, program, bindings)}; + vk::raii::ShaderModule ShaderManager::CompileShader(Shader::RuntimeInfo &runtimeInfo, const std::shared_ptr &program, Shader::Backend::Bindings &bindings) { + auto spirv{Shader::Backend::SPIRV::EmitSPIRV(profile, runtimeInfo, program->program, bindings)}; vk::ShaderModuleCreateInfo createInfo{ .pCode = spirv.data(), diff --git a/app/src/main/cpp/skyline/gpu/shader_manager.h b/app/src/main/cpp/skyline/gpu/shader_manager.h index 475083e3..ff967995 100644 --- a/app/src/main/cpp/skyline/gpu/shader_manager.h +++ b/app/src/main/cpp/skyline/gpu/shader_manager.h @@ -22,22 +22,49 @@ namespace skyline::gpu { class ShaderManager { private: GPU &gpu; - Shader::ObjectPool flowBlockPool; - Shader::ObjectPool instPool; - Shader::ObjectPool blockPool; Shader::HostTranslateInfo hostTranslateInfo; Shader::Profile profile; + public: + struct ShaderProgram { + Shader::IR::Program program; + }; + + private: + struct SingleShaderProgram : ShaderProgram { + Shader::ObjectPool flowBlockPool; + Shader::ObjectPool instructionPool; + Shader::ObjectPool blockPool; + + SingleShaderProgram() = default; + + SingleShaderProgram(const SingleShaderProgram &) = delete; + + SingleShaderProgram &operator=(const SingleShaderProgram &) = delete; + }; + + struct DualVertexShaderProgram : ShaderProgram { + std::shared_ptr vertexA; + std::shared_ptr vertexB; + + DualVertexShaderProgram(Shader::IR::Program program, std::shared_ptr vertexA, std::shared_ptr vertexB); + + DualVertexShaderProgram(const DualVertexShaderProgram &) = delete; + + DualVertexShaderProgram &operator=(const DualVertexShaderProgram &) = delete; + }; + public: ShaderManager(const DeviceState &state, GPU &gpu); - Shader::IR::Program 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 Shader::IR::Program CombineVertexShaders(Shader::IR::Program &vertexA, Shader::IR::Program &vertexB, span vertexBBinary); + static std::shared_ptr CombineVertexShaders(const std::shared_ptr &vertexA, const std::shared_ptr &vertexB, span vertexBBinary); - vk::raii::ShaderModule CompileShader(Shader::RuntimeInfo &runtimeInfo, Shader::IR::Program &program, Shader::Backend::Bindings &bindings); + vk::raii::ShaderModule CompileShader(Shader::RuntimeInfo &runtimeInfo, const std::shared_ptr &program, Shader::Backend::Bindings &bindings); }; }