Support Dual Vertex Shader Programs

Add support for parsing and combining `VertexA` and `VertexB` programs into a single vertex pipeline program prior to compilation, atomic reparsing and combining is supported to only reparse the stage that was modified and recombine once at most within a single pipeline compilation.
This commit is contained in:
PixelyIon 2021-12-23 22:21:29 +05:30
parent 974cf03c18
commit e1e14e781f
3 changed files with 66 additions and 1 deletions

View File

@ -743,7 +743,23 @@ namespace skyline::gpu::interconnect {
shader.program = gpu.shader.ParseGraphicsShader(shader.data, shader.stage, shader.offset);
if (shader.stage != ShaderCompiler::Stage::VertexA) {
if (shader.stage != ShaderCompiler::Stage::VertexA && shader.stage != ShaderCompiler::Stage::VertexB) {
pipelineStage.program.emplace<std::reference_wrapper<ShaderCompiler::IR::Program>>(*shader.program);
} else if (shader.stage == ShaderCompiler::Stage::VertexA) {
auto &vertexB{shaders[maxwell3d::ShaderStage::VertexB]};
if (!vertexB.enabled)
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);
} 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);
else
pipelineStage.program.emplace<std::reference_wrapper<ShaderCompiler::IR::Program>>(*shader.program);
}

View File

@ -125,6 +125,45 @@ namespace skyline::gpu {
}
};
/**
* @brief A shader environment for VertexB during combination as it only requires the shader header and no higher level context
*/
class VertexBEnvironment : public Shader::Environment {
public:
explicit VertexBEnvironment(span<u8> binary) {
sph = *reinterpret_cast<Shader::ProgramHeader *>(binary.data());
stage = Shader::Stage::VertexB;
}
[[nodiscard]] u64 ReadInstruction(u32 address) final {
throw exception("Not implemented");
}
[[nodiscard]] u32 ReadCbufValue(u32 cbuf_index, u32 cbuf_offset) final {
throw exception("Not implemented");
}
[[nodiscard]] Shader::TextureType ReadTextureType(u32 raw_handle) final {
throw exception("Not implemented");
}
[[nodiscard]] u32 TextureBoundBuffer() const final {
throw exception("Not implemented");
}
[[nodiscard]] u32 LocalMemorySize() const final {
return static_cast<u32>(sph.LocalMemorySize()) + sph.common3.shader_local_memory_crs_size;
}
[[nodiscard]] u32 SharedMemorySize() const final {
return 0;
}
[[nodiscard]] std::array<u32, 3> WorkgroupSize() const final {
return {0, 0, 0};
}
};
Shader::IR::Program ShaderManager::ParseGraphicsShader(span<u8> binary, Shader::Stage stage, u32 baseOffset) {
GraphicsEnvironment environment{binary, baseOffset, stage};
Shader::Maxwell::Flow::CFG cfg(environment, flowBlockPool, Shader::Maxwell::Location{static_cast<u32>(baseOffset + sizeof(Shader::ProgramHeader))});
@ -132,6 +171,11 @@ namespace skyline::gpu {
return Shader::Maxwell::TranslateProgram(instPool, blockPool, environment, cfg, hostTranslateInfo);
}
Shader::IR::Program ShaderManager::CombineVertexShaders(Shader::IR::Program &vertexA, Shader::IR::Program &vertexB, span<u8> vertexBBinary) {
VertexBEnvironment vertexBEnvironment{vertexBBinary};
return Shader::Maxwell::MergeDualVertexPrograms(vertexA, vertexB, vertexBEnvironment);
}
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)};

View File

@ -33,6 +33,11 @@ namespace skyline::gpu {
Shader::IR::Program ParseGraphicsShader(span<u8> binary, Shader::Stage stage, u32 baseOffset);
/**
* @brief Combines the VertexA and VertexB shader programs into a single program
*/
static Shader::IR::Program CombineVertexShaders(Shader::IR::Program &vertexA, Shader::IR::Program &vertexB, span<u8> vertexBBinary);
vk::raii::ShaderModule CompileShader(Shader::RuntimeInfo &runtimeInfo, Shader::IR::Program &program, Shader::Backend::Bindings &bindings);
};
}