mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-24 03:41:52 +01:00
Drop the caching aspect of shader manager entirely
Caching here was deemed unnecessary since it will be done implicitly by the pipeline cache and creates issues with the legacy attribute conversion pass. It now purely serves as a frontend for Hades.
This commit is contained in:
parent
e77e4891dc
commit
4dcbf5c3a0
@ -96,7 +96,8 @@ namespace skyline::gpu {
|
|||||||
std::vector<ShaderManager::ConstantBufferWord> constantBufferWords;
|
std::vector<ShaderManager::ConstantBufferWord> constantBufferWords;
|
||||||
std::vector<ShaderManager::CachedTextureType> textureTypes;
|
std::vector<ShaderManager::CachedTextureType> textureTypes;
|
||||||
|
|
||||||
GraphicsEnvironment(Shader::Stage pStage, span<u8> pBinary, u32 baseOffset, u32 textureBufferIndex, ShaderManager::ConstantBufferRead constantBufferRead, ShaderManager::GetTextureType getTextureType) : binary{pBinary}, baseOffset{baseOffset}, textureBufferIndex{textureBufferIndex}, constantBufferRead{std::move(constantBufferRead)}, getTextureType{std::move(getTextureType)} {
|
GraphicsEnvironment(const std::array<u32, 8> &postVtgShaderAttributeSkipMask, Shader::Stage pStage, span<u8> pBinary, u32 baseOffset, u32 textureBufferIndex, ShaderManager::ConstantBufferRead constantBufferRead, ShaderManager::GetTextureType getTextureType) : binary{pBinary}, baseOffset{baseOffset}, textureBufferIndex{textureBufferIndex}, constantBufferRead{std::move(constantBufferRead)}, getTextureType{std::move(getTextureType)} {
|
||||||
|
gp_passthrough_mask = postVtgShaderAttributeSkipMask;
|
||||||
stage = pStage;
|
stage = pStage;
|
||||||
sph = *reinterpret_cast<Shader::ProgramHeader *>(binary.data());
|
sph = *reinterpret_cast<Shader::ProgramHeader *>(binary.data());
|
||||||
start_address = baseOffset;
|
start_address = baseOffset;
|
||||||
@ -185,204 +186,42 @@ namespace skyline::gpu {
|
|||||||
|
|
||||||
constexpr ShaderManager::CachedTextureType::CachedTextureType(u32 handle, Shader::TextureType type) : handle(handle), type(type) {}
|
constexpr ShaderManager::CachedTextureType::CachedTextureType(u32 handle, Shader::TextureType type) : handle(handle), type(type) {}
|
||||||
|
|
||||||
ShaderManager::ShaderProgram::ShaderProgram(Shader::IR::Program &&program) : program{std::move(program)} {}
|
Shader::IR::Program ShaderManager::ParseGraphicsShader(const std::array<u32, 8> &postVtgShaderAttributeSkipMask, Shader::Stage stage, span<u8> binary, u32 baseOffset, u32 textureConstantBufferIndex, const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) {
|
||||||
|
std::scoped_lock lock{poolMutex};
|
||||||
|
|
||||||
bool ShaderManager::SingleShaderProgram::VerifyState(const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) const {
|
GraphicsEnvironment environment{postVtgShaderAttributeSkipMask, stage, binary, baseOffset, textureConstantBufferIndex, constantBufferRead, getTextureType};
|
||||||
return ranges::all_of(constantBufferWords, [&](const ConstantBufferWord &word) {
|
Shader::Maxwell::Flow::CFG cfg{environment, flowBlockPool, Shader::Maxwell::Location{static_cast<u32>(baseOffset + sizeof(Shader::ProgramHeader))}};
|
||||||
return constantBufferRead(word.index, word.offset) == word.value;
|
return Shader::Maxwell::TranslateProgram(instructionPool, blockPool, environment, cfg, hostTranslateInfo);
|
||||||
}) &&
|
|
||||||
ranges::all_of(textureTypes, [&](const CachedTextureType &type) {
|
|
||||||
return getTextureType(type.handle) == type.type;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderManager::GuestShaderKey::GuestShaderKey(Shader::Stage stage, span<u8> bytecode, u32 textureConstantBufferIndex, span<ConstantBufferWord> constantBufferWords, span<CachedTextureType> textureTypes) : stage{stage}, bytecode{bytecode.begin(), bytecode.end()}, textureConstantBufferIndex{textureConstantBufferIndex}, constantBufferWords{constantBufferWords}, textureTypes{textureTypes} {}
|
Shader::IR::Program ShaderManager::CombineVertexShaders(Shader::IR::Program &vertexA, Shader::IR::Program &vertexB, span<u8> vertexBBinary) {
|
||||||
|
std::scoped_lock lock{poolMutex};
|
||||||
|
|
||||||
ShaderManager::GuestShaderLookup::GuestShaderLookup(Shader::Stage stage, span<u8> bytecode, u32 textureConstantBufferIndex, ConstantBufferRead constantBufferRead, GetTextureType getTextureType) : stage(stage), textureConstantBufferIndex(textureConstantBufferIndex), bytecode(bytecode), constantBufferRead(std::move(constantBufferRead)), getTextureType(std::move(getTextureType)) {}
|
VertexBEnvironment env{vertexBBinary};
|
||||||
|
return Shader::Maxwell::MergeDualVertexPrograms(vertexA, vertexB, env);
|
||||||
#define HASH(member) boost::hash_combine(hash, key.member)
|
|
||||||
|
|
||||||
size_t ShaderManager::ShaderProgramHash::operator()(const GuestShaderKey &key) const noexcept {
|
|
||||||
size_t hash{};
|
|
||||||
|
|
||||||
HASH(stage);
|
|
||||||
hash = XXH64(key.bytecode.data(), key.bytecode.size(), hash);
|
|
||||||
HASH(textureConstantBufferIndex);
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ShaderManager::ShaderProgramHash::operator()(const GuestShaderLookup &key) const noexcept {
|
vk::ShaderModule ShaderManager::CompileShader(Shader::RuntimeInfo &runtimeInfo, Shader::IR::Program &program, Shader::Backend::Bindings &bindings) {
|
||||||
size_t hash{};
|
std::scoped_lock lock{poolMutex};
|
||||||
|
|
||||||
HASH(stage);
|
if (program.info.loads.Legacy() || program.info.stores.Legacy())
|
||||||
hash = XXH64(key.bytecode.data(), key.bytecode.size(), hash);
|
Shader::Maxwell::ConvertLegacyToGeneric(program, runtimeInfo);
|
||||||
HASH(textureConstantBufferIndex);
|
|
||||||
|
|
||||||
return hash;
|
auto spirv{Shader::Backend::SPIRV::EmitSPIRV(profile, runtimeInfo, program, bindings)};
|
||||||
}
|
|
||||||
|
|
||||||
#undef HASH
|
|
||||||
|
|
||||||
bool ShaderManager::ShaderProgramEqual::operator()(const GuestShaderKey &lhs, const GuestShaderLookup &rhs) const noexcept {
|
|
||||||
return lhs.stage == rhs.stage &&
|
|
||||||
ranges::equal(lhs.bytecode, rhs.bytecode) &&
|
|
||||||
lhs.textureConstantBufferIndex == rhs.textureConstantBufferIndex &&
|
|
||||||
ranges::all_of(lhs.constantBufferWords, [&constantBufferRead = rhs.constantBufferRead](const ConstantBufferWord &word) {
|
|
||||||
return constantBufferRead(word.index, word.offset) == word.value;
|
|
||||||
}) &&
|
|
||||||
ranges::all_of(lhs.textureTypes, [&getTextureType = rhs.getTextureType](const CachedTextureType &type) {
|
|
||||||
return getTextureType(type.handle) == type.type;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ShaderManager::ShaderProgramEqual::operator()(const GuestShaderKey &lhs, const GuestShaderKey &rhs) const noexcept {
|
|
||||||
return lhs.stage == rhs.stage &&
|
|
||||||
ranges::equal(lhs.bytecode, rhs.bytecode) &&
|
|
||||||
lhs.textureConstantBufferIndex == rhs.textureConstantBufferIndex &&
|
|
||||||
ranges::equal(lhs.constantBufferWords, rhs.constantBufferWords) &&
|
|
||||||
ranges::equal(lhs.textureTypes, rhs.textureTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)} {}
|
|
||||||
|
|
||||||
bool ShaderManager::DualVertexShaderProgram::VerifyState(const ConstantBufferRead &constantBufferRead, const GetTextureType& getTextureType) const {
|
|
||||||
return vertexA->VerifyState(constantBufferRead, getTextureType) && vertexB->VerifyState(constantBufferRead, getTextureType);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<ShaderManager::ShaderProgram> ShaderManager::ParseGraphicsShader(Shader::Stage stage, span<u8> binary, u32 baseOffset, u32 textureConstantBufferIndex, const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) {
|
|
||||||
std::unique_lock lock{programMutex};
|
|
||||||
|
|
||||||
auto it{programCache.find(GuestShaderLookup{stage, binary, textureConstantBufferIndex, constantBufferRead, getTextureType})};
|
|
||||||
if (it != programCache.end())
|
|
||||||
return it->second;
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
auto program{std::make_shared<SingleShaderProgram>()};
|
|
||||||
GraphicsEnvironment environment{stage, binary, baseOffset, textureConstantBufferIndex, constantBufferRead, getTextureType};
|
|
||||||
Shader::Maxwell::Flow::CFG cfg(environment, program->flowBlockPool, Shader::Maxwell::Location{static_cast<u32>(baseOffset + sizeof(Shader::ProgramHeader))});
|
|
||||||
program->program = Shader::Maxwell::TranslateProgram(program->instructionPool, program->blockPool, environment, cfg, hostTranslateInfo);
|
|
||||||
program->constantBufferWords = std::move(environment.constantBufferWords);
|
|
||||||
program->textureTypes = std::move(environment.textureTypes);
|
|
||||||
|
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
auto programIt{programCache.try_emplace(GuestShaderKey{stage, binary, textureConstantBufferIndex, program->constantBufferWords, program->textureTypes}, std::move(program))};
|
|
||||||
return programIt.first->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr size_t ShaderManager::DualVertexProgramsHash::operator()(const std::pair<std::shared_ptr<ShaderProgram>, std::shared_ptr<ShaderProgram>> &p) const {
|
|
||||||
size_t hash{};
|
|
||||||
boost::hash_combine(hash, p.first);
|
|
||||||
boost::hash_combine(hash, p.second);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<ShaderManager::ShaderProgram> ShaderManager::CombineVertexShaders(const std::shared_ptr<ShaderProgram> &vertexA, const std::shared_ptr<ShaderProgram> &vertexB, span<u8> vertexBBinary) {
|
|
||||||
std::unique_lock lock{programMutex};
|
|
||||||
auto &program{dualProgramCache[DualVertexPrograms{vertexA, vertexB}]};
|
|
||||||
if (program)
|
|
||||||
return program;
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
VertexBEnvironment vertexBEnvironment{vertexBBinary};
|
|
||||||
auto mergedProgram{std::make_shared<DualVertexShaderProgram>(Shader::Maxwell::MergeDualVertexPrograms(vertexA->program, vertexB->program, vertexBEnvironment), vertexA, vertexB)};
|
|
||||||
|
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
return program = std::move(mergedProgram);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ShaderManager::ShaderModuleState::operator==(const ShaderModuleState &other) const {
|
|
||||||
if (program != other.program)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (bindings.unified != other.bindings.unified || bindings.uniform_buffer != other.bindings.uniform_buffer || bindings.storage_buffer != other.bindings.storage_buffer || bindings.texture != other.bindings.texture || bindings.image != other.bindings.image || bindings.texture_scaling_index != other.bindings.texture_scaling_index || bindings.image_scaling_index != other.bindings.image_scaling_index)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
static_assert(sizeof(Shader::Backend::Bindings) == 0x1C);
|
|
||||||
|
|
||||||
if (!std::equal(runtimeInfo.generic_input_types.begin(), runtimeInfo.generic_input_types.end(), other.runtimeInfo.generic_input_types.begin()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
#define NEQ(member) runtimeInfo.member != other.runtimeInfo.member
|
|
||||||
|
|
||||||
if (NEQ(previous_stage_stores.mask) || NEQ(convert_depth_mode) || NEQ(force_early_z) || NEQ(tess_primitive) || NEQ(tess_spacing) || NEQ(tess_clockwise) || NEQ(input_topology) || NEQ(fixed_state_point_size) || NEQ(alpha_test_func) || NEQ(alpha_test_reference) || NEQ(y_negate) || NEQ(glasm_use_storage_buffers))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
#undef NEQ
|
|
||||||
|
|
||||||
if (!std::equal(runtimeInfo.xfb_varyings.begin(), runtimeInfo.xfb_varyings.end(), other.runtimeInfo.xfb_varyings.begin(), [](const Shader::TransformFeedbackVarying &a, const Shader::TransformFeedbackVarying &b) {
|
|
||||||
return a.buffer == b.buffer && a.stride == b.stride && a.offset == b.offset && a.components == b.components;
|
|
||||||
}))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
static_assert(sizeof(Shader::RuntimeInfo) == 0x88);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr size_t ShaderManager::ShaderModuleStateHash::operator()(const ShaderModuleState &state) const {
|
|
||||||
size_t hash{};
|
|
||||||
|
|
||||||
boost::hash_combine(hash, state.program);
|
|
||||||
|
|
||||||
hash = XXH64(&state.bindings, sizeof(Shader::Backend::Bindings), hash);
|
|
||||||
|
|
||||||
#define RIH(member) boost::hash_combine(hash, state.runtimeInfo.member)
|
|
||||||
|
|
||||||
hash = XXH64(state.runtimeInfo.generic_input_types.data(), state.runtimeInfo.generic_input_types.size() * sizeof(Shader::AttributeType), hash);
|
|
||||||
hash = XXH64(&state.runtimeInfo.previous_stage_stores.mask, sizeof(state.runtimeInfo.previous_stage_stores.mask), hash);
|
|
||||||
RIH(convert_depth_mode);
|
|
||||||
RIH(force_early_z);
|
|
||||||
RIH(tess_primitive);
|
|
||||||
RIH(tess_spacing);
|
|
||||||
RIH(tess_clockwise);
|
|
||||||
RIH(input_topology);
|
|
||||||
RIH(fixed_state_point_size.value_or(NAN));
|
|
||||||
RIH(alpha_test_func.value_or(Shader::CompareFunction::Never));
|
|
||||||
RIH(alpha_test_reference);
|
|
||||||
RIH(glasm_use_storage_buffers);
|
|
||||||
hash = XXH64(state.runtimeInfo.xfb_varyings.data(), state.runtimeInfo.xfb_varyings.size() * sizeof(Shader::TransformFeedbackVarying), hash);
|
|
||||||
|
|
||||||
static_assert(sizeof(Shader::RuntimeInfo) == 0x88);
|
|
||||||
#undef RIH
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderManager::ShaderModule::ShaderModule(const vk::raii::Device &device, const vk::ShaderModuleCreateInfo &createInfo, Shader::Backend::Bindings bindings) : vkModule{device, createInfo}, bindings{bindings} {}
|
|
||||||
|
|
||||||
vk::ShaderModule ShaderManager::CompileShader(Shader::RuntimeInfo &runtimeInfo, const std::shared_ptr<ShaderProgram> &program, Shader::Backend::Bindings &bindings) {
|
|
||||||
std::unique_lock lock{moduleMutex};
|
|
||||||
ShaderModuleState shaderModuleState{program, bindings, runtimeInfo};
|
|
||||||
auto it{shaderModuleCache.find(shaderModuleState)};
|
|
||||||
if (it != shaderModuleCache.end()) {
|
|
||||||
const auto &entry{it->second};
|
|
||||||
bindings = entry.bindings;
|
|
||||||
return *entry.vkModule;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
// Note: EmitSPIRV will change bindings so we explicitly have pre/post emit bindings
|
|
||||||
if (program->program.info.loads.Legacy() || program->program.info.stores.Legacy()) {
|
|
||||||
// The legacy conversion pass modifies the underlying program based on runtime state, so without making a copy of the program there may be issues if runtimeInfo changes
|
|
||||||
Logger::Warn("Shader uses legacy attributes, beware!");
|
|
||||||
Shader::Maxwell::ConvertLegacyToGeneric(program->program, runtimeInfo);
|
|
||||||
}
|
|
||||||
auto spirv{Shader::Backend::SPIRV::EmitSPIRV(profile, runtimeInfo, program->program, bindings)};
|
|
||||||
|
|
||||||
vk::ShaderModuleCreateInfo createInfo{
|
vk::ShaderModuleCreateInfo createInfo{
|
||||||
.pCode = spirv.data(),
|
.pCode = spirv.data(),
|
||||||
.codeSize = spirv.size() * sizeof(u32),
|
.codeSize = spirv.size() * sizeof(u32),
|
||||||
};
|
};
|
||||||
|
|
||||||
lock.lock();
|
return (*gpu.vkDevice).createShaderModule(createInfo);
|
||||||
|
}
|
||||||
|
|
||||||
auto shaderModule{shaderModuleCache.try_emplace(shaderModuleState, gpu.vkDevice, createInfo, bindings)};
|
void ShaderManager::ResetPools() {
|
||||||
return *(shaderModule.first->second.vkModule);
|
std::scoped_lock lock{poolMutex};
|
||||||
|
|
||||||
|
instructionPool.ReleaseContents();
|
||||||
|
blockPool.ReleaseContents();
|
||||||
|
flowBlockPool.ReleaseContents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,10 @@ namespace skyline::gpu {
|
|||||||
GPU &gpu;
|
GPU &gpu;
|
||||||
Shader::HostTranslateInfo hostTranslateInfo;
|
Shader::HostTranslateInfo hostTranslateInfo;
|
||||||
Shader::Profile profile;
|
Shader::Profile profile;
|
||||||
std::mutex programMutex; //!< Synchronizes accesses to the program caches
|
Shader::ObjectPool<Shader::Maxwell::Flow::Block> flowBlockPool;
|
||||||
std::mutex moduleMutex; //!< Synchronizes accesses to the module cache
|
Shader::ObjectPool<Shader::IR::Inst> instructionPool;
|
||||||
|
Shader::ObjectPool<Shader::IR::Block> blockPool;
|
||||||
|
std::mutex poolMutex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using ConstantBufferRead = std::function<u32(u32 index, u32 offset)>; //!< A function which reads a constant buffer at the specified offset and returns the value
|
using ConstantBufferRead = std::function<u32(u32 index, u32 offset)>; //!< A function which reads a constant buffer at the specified offset and returns the value
|
||||||
@ -54,134 +56,21 @@ namespace skyline::gpu {
|
|||||||
constexpr bool operator==(const CachedTextureType &other) const = default;
|
constexpr bool operator==(const CachedTextureType &other) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ShaderProgram {
|
|
||||||
Shader::IR::Program program;
|
|
||||||
|
|
||||||
ShaderProgram() = default;
|
|
||||||
|
|
||||||
ShaderProgram(Shader::IR::Program &&program);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return If the current state match the expected values, if they don't match then the shader program might be inaccurate for the current behavior
|
|
||||||
*/
|
|
||||||
virtual bool VerifyState(const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct SingleShaderProgram final : ShaderProgram {
|
|
||||||
Shader::ObjectPool<Shader::Maxwell::Flow::Block> flowBlockPool;
|
|
||||||
Shader::ObjectPool<Shader::IR::Inst> instructionPool;
|
|
||||||
Shader::ObjectPool<Shader::IR::Block> blockPool;
|
|
||||||
|
|
||||||
std::vector<ConstantBufferWord> constantBufferWords;
|
|
||||||
std::vector<CachedTextureType> textureTypes;
|
|
||||||
|
|
||||||
SingleShaderProgram() = default;
|
|
||||||
|
|
||||||
SingleShaderProgram(const SingleShaderProgram &) = delete;
|
|
||||||
|
|
||||||
SingleShaderProgram &operator=(const SingleShaderProgram &) = delete;
|
|
||||||
|
|
||||||
bool VerifyState(const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) const final;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GuestShaderKey {
|
|
||||||
Shader::Stage stage;
|
|
||||||
std::vector<u8> bytecode;
|
|
||||||
u32 textureConstantBufferIndex;
|
|
||||||
span<ConstantBufferWord> constantBufferWords;
|
|
||||||
span<CachedTextureType> textureTypes;
|
|
||||||
|
|
||||||
GuestShaderKey(Shader::Stage stage, span<u8> bytecode, u32 textureConstantBufferIndex, span<ConstantBufferWord> constantBufferWords, span<CachedTextureType> textureTypes);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GuestShaderLookup {
|
|
||||||
Shader::Stage stage;
|
|
||||||
span<u8> bytecode;
|
|
||||||
u32 textureConstantBufferIndex;
|
|
||||||
ConstantBufferRead constantBufferRead;
|
|
||||||
GetTextureType getTextureType;
|
|
||||||
|
|
||||||
GuestShaderLookup(Shader::Stage stage, span<u8> bytecode, u32 textureConstantBufferIndex, ConstantBufferRead constantBufferRead, GetTextureType getTextureType);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ShaderProgramHash {
|
|
||||||
using is_transparent = std::true_type;
|
|
||||||
|
|
||||||
size_t operator()(const GuestShaderKey &key) const noexcept;
|
|
||||||
|
|
||||||
size_t operator()(const GuestShaderLookup &key) const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ShaderProgramEqual {
|
|
||||||
using is_transparent = std::true_type;
|
|
||||||
|
|
||||||
bool operator()(const GuestShaderKey &lhs, const GuestShaderLookup &rhs) const noexcept;
|
|
||||||
|
|
||||||
bool operator()(const GuestShaderKey &lhs, const GuestShaderKey &rhs) const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_map<GuestShaderKey, std::shared_ptr<SingleShaderProgram>, ShaderProgramHash, ShaderProgramEqual> programCache; //!< A map from Maxwell bytecode to the corresponding shader program
|
|
||||||
|
|
||||||
struct DualVertexShaderProgram final : 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;
|
|
||||||
|
|
||||||
bool VerifyState(const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) const final;
|
|
||||||
};
|
|
||||||
|
|
||||||
using DualVertexPrograms = std::pair<std::shared_ptr<ShaderProgram>, std::shared_ptr<ShaderProgram>>;
|
|
||||||
|
|
||||||
struct DualVertexProgramsHash {
|
|
||||||
constexpr size_t operator()(const std::pair<std::shared_ptr<ShaderProgram>, std::shared_ptr<ShaderProgram>> &p) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_map<DualVertexPrograms, std::shared_ptr<DualVertexShaderProgram>, DualVertexProgramsHash> dualProgramCache; //!< A map from Vertex A and Vertex B shader programs to the corresponding dual vertex shader program
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief All unique state that is required to compile a shader program, this is used as the key for the associative compiled shader program cache
|
|
||||||
*/
|
|
||||||
struct ShaderModuleState {
|
|
||||||
std::shared_ptr<ShaderProgram> program;
|
|
||||||
Shader::Backend::Bindings bindings; //!< The bindings prior to the shader being compiled
|
|
||||||
Shader::RuntimeInfo runtimeInfo;
|
|
||||||
|
|
||||||
bool operator==(const ShaderModuleState &) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ShaderModuleStateHash {
|
|
||||||
constexpr size_t operator()(const ShaderModuleState &state) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ShaderModule {
|
|
||||||
vk::raii::ShaderModule vkModule;
|
|
||||||
Shader::Backend::Bindings bindings; //!< The bindings after the shader has been compiled
|
|
||||||
|
|
||||||
ShaderModule(const vk::raii::Device &device, const vk::ShaderModuleCreateInfo &createInfo, Shader::Backend::Bindings bindings);
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_map<ShaderModuleState, ShaderModule, ShaderModuleStateHash> shaderModuleCache; //!< A map from shader module state to the corresponding Vulkan shader module
|
|
||||||
|
|
||||||
public:
|
|
||||||
ShaderManager(const DeviceState &state, GPU &gpu);
|
ShaderManager(const DeviceState &state, GPU &gpu);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A shader program that corresponds to all the supplied state including the current state of the constant buffers
|
* @return A shader program that corresponds to all the supplied state including the current state of the constant buffers
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<ShaderManager::ShaderProgram> ParseGraphicsShader(Shader::Stage stage, span<u8> binary, u32 baseOffset, u32 textureConstantBufferIndex, const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType);
|
Shader::IR::Program ParseGraphicsShader(const std::array<u32, 8> &postVtgShaderAttributeSkipMask, Shader::Stage stage, span<u8> binary, u32 baseOffset, u32 textureConstantBufferIndex, const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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
|
* @note VertexA/VertexB shader programs must be SingleShaderProgram and not DualVertexShaderProgram
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<ShaderManager::ShaderProgram> CombineVertexShaders(const std::shared_ptr<ShaderProgram> &vertexA, const std::shared_ptr<ShaderProgram> &vertexB, span<u8> vertexBBinary);
|
Shader::IR::Program CombineVertexShaders(Shader::IR::Program &vertexA, Shader::IR::Program &vertexB, span<u8> vertexBBinary);
|
||||||
|
|
||||||
vk::ShaderModule CompileShader(Shader::RuntimeInfo &runtimeInfo, const std::shared_ptr<ShaderProgram> &program, Shader::Backend::Bindings &bindings);
|
vk::ShaderModule CompileShader(Shader::RuntimeInfo &runtimeInfo, Shader::IR::Program &program, Shader::Backend::Bindings &bindings);
|
||||||
|
|
||||||
|
void ResetPools();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user