mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-29 17:25:28 +03:00
Tie Shader ObjectPool
Lifetime to Shader Program
Shader programs allocate instructions and blocks within an `ObjectPool`, there was a global pool prior that was never reaped aside from on destruction. This led to a leak where the pool would contain resources from shader programs that had been deleted, to avert this the pools are now tied to shader programs.
This commit is contained in:
parent
e747de37cf
commit
41aad83c33
@ -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
|
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
|
u32 offset{}; //!< Offset of the shader from the base IOVA
|
||||||
boost::container::static_vector<u8, MaxShaderBytecodeSize> data; //!< The shader bytecode in a statically allocated vector
|
boost::container::static_vector<u8, MaxShaderBytecodeSize> data; //!< The shader bytecode in a statically allocated vector
|
||||||
std::optional<ShaderCompiler::IR::Program> program;
|
std::shared_ptr<ShaderManager::ShaderProgram> program{};
|
||||||
|
|
||||||
Shader(ShaderCompiler::Stage stage) : stage(stage) {}
|
Shader(ShaderCompiler::Stage stage) : stage(stage) {}
|
||||||
|
|
||||||
@ -689,7 +689,7 @@ namespace skyline::gpu::interconnect {
|
|||||||
bool enabled{false};
|
bool enabled{false};
|
||||||
vk::ShaderStageFlagBits vkStage;
|
vk::ShaderStageFlagBits vkStage;
|
||||||
|
|
||||||
std::variant<ShaderCompiler::IR::Program, std::reference_wrapper<ShaderCompiler::IR::Program>> 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<ShaderManager::ShaderProgram> 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
|
bool needsRecompile{}; //!< If the shader needs to be recompiled as runtime information has changed
|
||||||
ShaderCompiler::VaryingState previousStageStores{};
|
ShaderCompiler::VaryingState previousStageStores{};
|
||||||
@ -817,7 +817,7 @@ namespace skyline::gpu::interconnect {
|
|||||||
shader.program = gpu.shader.ParseGraphicsShader(shader.stage, shader.data, shader.offset, bindlessTextureConstantBufferIndex);
|
shader.program = gpu.shader.ParseGraphicsShader(shader.stage, shader.data, shader.offset, bindlessTextureConstantBufferIndex);
|
||||||
|
|
||||||
if (shader.stage != ShaderCompiler::Stage::VertexA && shader.stage != ShaderCompiler::Stage::VertexB) {
|
if (shader.stage != ShaderCompiler::Stage::VertexA && shader.stage != ShaderCompiler::Stage::VertexB) {
|
||||||
pipelineStage.program.emplace<std::reference_wrapper<ShaderCompiler::IR::Program>>(*shader.program);
|
pipelineStage.program = shader.program;
|
||||||
} else if (shader.stage == ShaderCompiler::Stage::VertexA) {
|
} else if (shader.stage == ShaderCompiler::Stage::VertexA) {
|
||||||
auto &vertexB{shaders[maxwell3d::ShaderStage::VertexB]};
|
auto &vertexB{shaders[maxwell3d::ShaderStage::VertexB]};
|
||||||
|
|
||||||
@ -825,15 +825,15 @@ namespace skyline::gpu::interconnect {
|
|||||||
throw exception("Enabling VertexA without VertexB is not supported");
|
throw exception("Enabling VertexA without VertexB is not supported");
|
||||||
else if (!vertexB.invalidated)
|
else if (!vertexB.invalidated)
|
||||||
// If only VertexA is invalidated, we need to recombine here but we can defer it otherwise
|
// 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) {
|
} else if (shader.stage == ShaderCompiler::Stage::VertexB) {
|
||||||
auto &vertexA{shaders[maxwell3d::ShaderStage::VertexA]};
|
auto &vertexA{shaders[maxwell3d::ShaderStage::VertexA]};
|
||||||
|
|
||||||
if (vertexA.enabled)
|
if (vertexA.enabled)
|
||||||
// We need to combine the vertex shader stages if VertexA is 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
|
else
|
||||||
pipelineStage.program.emplace<std::reference_wrapper<ShaderCompiler::IR::Program>>(*shader.program);
|
pipelineStage.program = shader.program;
|
||||||
}
|
}
|
||||||
|
|
||||||
pipelineStage.enabled = true;
|
pipelineStage.enabled = true;
|
||||||
@ -861,18 +861,14 @@ namespace skyline::gpu::interconnect {
|
|||||||
if (!pipelineStage.enabled)
|
if (!pipelineStage.enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto &program{std::visit(VariantVisitor{
|
|
||||||
[](ShaderCompiler::IR::Program &program) -> ShaderCompiler::IR::Program & { return program; },
|
|
||||||
[](std::reference_wrapper<ShaderCompiler::IR::Program> program) -> ShaderCompiler::IR::Program & { return program.get(); },
|
|
||||||
}, pipelineStage.program)};
|
|
||||||
|
|
||||||
if (pipelineStage.needsRecompile || bindings.unified != pipelineStage.bindingBase || pipelineStage.previousStageStores.mask != runtimeInfo.previous_stage_stores.mask) {
|
if (pipelineStage.needsRecompile || bindings.unified != pipelineStage.bindingBase || pipelineStage.previousStageStores.mask != runtimeInfo.previous_stage_stores.mask) {
|
||||||
pipelineStage.previousStageStores = runtimeInfo.previous_stage_stores;
|
pipelineStage.previousStageStores = runtimeInfo.previous_stage_stores;
|
||||||
pipelineStage.bindingBase = bindings.unified;
|
pipelineStage.bindingBase = bindings.unified;
|
||||||
pipelineStage.vkModule = std::make_shared<vk::raii::ShaderModule>(gpu.shader.CompileShader(runtimeInfo, program, bindings));
|
pipelineStage.vkModule = std::make_shared<vk::raii::ShaderModule>(gpu.shader.CompileShader(runtimeInfo, pipelineStage.program, bindings));
|
||||||
pipelineStage.bindingLast = bindings.unified;
|
pipelineStage.bindingLast = bindings.unified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &program{pipelineStage.program->program};
|
||||||
runtimeInfo.previous_stage_stores = program.info.stores;
|
runtimeInfo.previous_stage_stores = program.info.stores;
|
||||||
if (program.is_geometry_passthrough)
|
if (program.is_geometry_passthrough)
|
||||||
runtimeInfo.previous_stage_stores.mask |= program.info.passthrough.mask;
|
runtimeInfo.previous_stage_stores.mask |= program.info.passthrough.mask;
|
||||||
|
@ -165,20 +165,24 @@ namespace skyline::gpu {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Shader::IR::Program ShaderManager::ParseGraphicsShader(Shader::Stage stage, span<u8> binary, u32 baseOffset, u32 bindlessTextureConstantBufferIndex) {
|
ShaderManager::DualVertexShaderProgram::DualVertexShaderProgram(Shader::IR::Program ir, std::shared_ptr<ShaderProgram> vertexA, std::shared_ptr<ShaderProgram> vertexB) : ShaderProgram{std::move(ir)}, vertexA(std::move(vertexA)), vertexB(std::move(vertexB)) {}
|
||||||
|
|
||||||
|
std::shared_ptr<ShaderManager::ShaderProgram> ShaderManager::ParseGraphicsShader(Shader::Stage stage, span<u8> binary, u32 baseOffset, u32 bindlessTextureConstantBufferIndex) {
|
||||||
|
auto program{std::make_shared<SingleShaderProgram>()};
|
||||||
GraphicsEnvironment environment{stage, binary, baseOffset, bindlessTextureConstantBufferIndex};
|
GraphicsEnvironment environment{stage, binary, baseOffset, bindlessTextureConstantBufferIndex};
|
||||||
Shader::Maxwell::Flow::CFG cfg(environment, flowBlockPool, Shader::Maxwell::Location{static_cast<u32>(baseOffset + sizeof(Shader::ProgramHeader))});
|
Shader::Maxwell::Flow::CFG cfg(environment, program->flowBlockPool, Shader::Maxwell::Location{static_cast<u32>(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<u8> vertexBBinary) {
|
std::shared_ptr<ShaderManager::ShaderProgram> ShaderManager::CombineVertexShaders(const std::shared_ptr<ShaderManager::ShaderProgram> &vertexA, const std::shared_ptr<ShaderManager::ShaderProgram> &vertexB, span<u8> vertexBBinary) {
|
||||||
VertexBEnvironment vertexBEnvironment{vertexBBinary};
|
VertexBEnvironment vertexBEnvironment{vertexBBinary};
|
||||||
return Shader::Maxwell::MergeDualVertexPrograms(vertexA, vertexB, vertexBEnvironment);
|
return std::make_shared<DualVertexShaderProgram>(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) {
|
vk::raii::ShaderModule ShaderManager::CompileShader(Shader::RuntimeInfo &runtimeInfo, const std::shared_ptr<ShaderProgram> &program, Shader::Backend::Bindings &bindings) {
|
||||||
auto spirv{Shader::Backend::SPIRV::EmitSPIRV(profile, runtimeInfo, program, bindings)};
|
auto spirv{Shader::Backend::SPIRV::EmitSPIRV(profile, runtimeInfo, program->program, bindings)};
|
||||||
|
|
||||||
vk::ShaderModuleCreateInfo createInfo{
|
vk::ShaderModuleCreateInfo createInfo{
|
||||||
.pCode = spirv.data(),
|
.pCode = spirv.data(),
|
||||||
|
@ -22,22 +22,49 @@ namespace skyline::gpu {
|
|||||||
class ShaderManager {
|
class ShaderManager {
|
||||||
private:
|
private:
|
||||||
GPU &gpu;
|
GPU &gpu;
|
||||||
Shader::ObjectPool<Shader::Maxwell::Flow::Block> flowBlockPool;
|
|
||||||
Shader::ObjectPool<Shader::IR::Inst> instPool;
|
|
||||||
Shader::ObjectPool<Shader::IR::Block> blockPool;
|
|
||||||
Shader::HostTranslateInfo hostTranslateInfo;
|
Shader::HostTranslateInfo hostTranslateInfo;
|
||||||
Shader::Profile profile;
|
Shader::Profile profile;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct ShaderProgram {
|
||||||
|
Shader::IR::Program program;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct SingleShaderProgram : ShaderProgram {
|
||||||
|
Shader::ObjectPool<Shader::Maxwell::Flow::Block> flowBlockPool;
|
||||||
|
Shader::ObjectPool<Shader::IR::Inst> instructionPool;
|
||||||
|
Shader::ObjectPool<Shader::IR::Block> blockPool;
|
||||||
|
|
||||||
|
SingleShaderProgram() = default;
|
||||||
|
|
||||||
|
SingleShaderProgram(const SingleShaderProgram &) = delete;
|
||||||
|
|
||||||
|
SingleShaderProgram &operator=(const SingleShaderProgram &) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DualVertexShaderProgram : ShaderProgram {
|
||||||
|
std::shared_ptr<ShaderProgram> vertexA;
|
||||||
|
std::shared_ptr<ShaderProgram> vertexB;
|
||||||
|
|
||||||
|
DualVertexShaderProgram(Shader::IR::Program program, std::shared_ptr<ShaderProgram> vertexA, std::shared_ptr<ShaderProgram> vertexB);
|
||||||
|
|
||||||
|
DualVertexShaderProgram(const DualVertexShaderProgram &) = delete;
|
||||||
|
|
||||||
|
DualVertexShaderProgram &operator=(const DualVertexShaderProgram &) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ShaderManager(const DeviceState &state, GPU &gpu);
|
ShaderManager(const DeviceState &state, GPU &gpu);
|
||||||
|
|
||||||
Shader::IR::Program ParseGraphicsShader(Shader::Stage stage, span<u8> binary, u32 baseOffset, u32 bindlessTextureConstantBufferIndex);
|
std::shared_ptr<ShaderManager::ShaderProgram> ParseGraphicsShader(Shader::Stage stage, span <u8> binary, u32 baseOffset, u32 bindlessTextureConstantBufferIndex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Combines the VertexA and VertexB shader programs into a single program
|
* @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<u8> vertexBBinary);
|
static std::shared_ptr<ShaderManager::ShaderProgram> CombineVertexShaders(const std::shared_ptr<ShaderProgram> &vertexA, const std::shared_ptr<ShaderProgram> &vertexB, span <u8> 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<ShaderProgram> &program, Shader::Backend::Bindings &bindings);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user