vk_shader_cache: Small cleanup

This commit is contained in:
IndecisiveTurtle 2024-08-29 19:20:53 +03:00
parent 93db0625f6
commit dbb9e457ea
3 changed files with 69 additions and 56 deletions

View File

@ -161,16 +161,17 @@ void PipelineCache::RefreshGraphicsKey() {
continue; continue;
} }
const auto stage = Shader::Stage{i}; const auto stage = Shader::Stage{i};
const GuestProgram guest_pgm{pgm, stage};
std::tie(infos[i], modules[i], key.stage_hashes[i]) = std::tie(infos[i], modules[i], key.stage_hashes[i]) =
shader_cache->GetProgram(pgm, stage, binding); shader_cache->GetProgram(guest_pgm, binding);
} }
} }
void PipelineCache::RefreshComputeKey() { void PipelineCache::RefreshComputeKey() {
u32 binding{}; u32 binding{};
const auto* cs_pgm = &liverpool->regs.cs_program; const auto* cs_pgm = &liverpool->regs.cs_program;
std::tie(infos[0], modules[0], compute_key) = const GuestProgram guest_pgm{cs_pgm, Shader::Stage::Compute};
shader_cache->GetProgram(cs_pgm, Shader::Stage::Compute, binding); std::tie(infos[0], modules[0], compute_key) = shader_cache->GetProgram(guest_pgm, binding);
} }
} // namespace Vulkan } // namespace Vulkan

View File

@ -59,14 +59,13 @@ void BuildVsOutputs(Shader::Info& info, const AmdGpu::Liverpool::VsOutputControl
: (ctl.IsCullDistEnabled(7) ? VsOutput::CullDist7 : VsOutput::None)); : (ctl.IsCullDistEnabled(7) ? VsOutput::CullDist7 : VsOutput::None));
} }
Shader::Info MakeShaderInfo(Shader::Stage stage, std::span<const u32, 16> user_data, u64 pgm_base, Shader::Info MakeShaderInfo(const GuestProgram& pgm, const AmdGpu::Liverpool::Regs& regs) {
u64 hash, const AmdGpu::Liverpool::Regs& regs) {
Shader::Info info{}; Shader::Info info{};
info.user_data = user_data; info.user_data = pgm.user_data;
info.pgm_base = pgm_base; info.pgm_base = VAddr(pgm.code.data());
info.pgm_hash = hash; info.pgm_hash = pgm.hash;
info.stage = stage; info.stage = pgm.stage;
switch (stage) { switch (pgm.stage) {
case Shader::Stage::Vertex: { case Shader::Stage::Vertex: {
info.num_user_data = regs.vs_program.settings.num_user_regs; info.num_user_data = regs.vs_program.settings.num_user_regs;
info.num_input_vgprs = regs.vs_program.settings.vgpr_comp_cnt; info.num_input_vgprs = regs.vs_program.settings.vgpr_comp_cnt;
@ -101,6 +100,10 @@ Shader::Info MakeShaderInfo(Shader::Stage stage, std::span<const u32, 16> user_d
return info; return info;
} }
[[nodiscard]] inline u64 HashCombine(const u64 seed, const u64 hash) {
return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}
ShaderCache::ShaderCache(const Instance& instance_, AmdGpu::Liverpool* liverpool_) ShaderCache::ShaderCache(const Instance& instance_, AmdGpu::Liverpool* liverpool_)
: instance{instance_}, liverpool{liverpool_}, inst_pool{8192}, block_pool{512} { : instance{instance_}, liverpool{liverpool_}, inst_pool{8192}, block_pool{512} {
profile = Shader::Profile{ profile = Shader::Profile{
@ -137,6 +140,43 @@ vk::ShaderModule ShaderCache::CompileModule(Shader::Info& info, std::span<const
return module; return module;
} }
Program* ShaderCache::CreateProgram(const GuestProgram& pgm, u32& binding) {
Program* program = program_pool.Create(MakeShaderInfo(pgm, liverpool->regs));
u32 start_binding = binding;
const auto module = CompileModule(program->info, pgm.code, 0, binding);
program->modules.emplace_back(module, StageSpecialization{program->info, start_binding});
return program;
}
std::tuple<const Shader::Info*, vk::ShaderModule, u64> ShaderCache::GetProgram(
const GuestProgram& pgm, u32& binding) {
auto [it_pgm, new_program] = program_cache.try_emplace(pgm.hash);
if (new_program) {
auto program = CreateProgram(pgm, binding);
const auto module = program->modules.back().module;
it_pgm.value() = program;
return std::make_tuple(&program->info, module, HashCombine(pgm.hash, 0));
}
Program* program = it_pgm->second;
const auto& info = program->info;
size_t perm_idx = program->modules.size();
StageSpecialization spec{info, binding};
vk::ShaderModule module{};
const auto it = std::ranges::find(program->modules, spec, &Program::Module::spec);
if (it == program->modules.end()) {
auto new_info = MakeShaderInfo(pgm, liverpool->regs);
module = CompileModule(new_info, pgm.code, perm_idx, binding);
program->modules.emplace_back(module, std::move(spec));
} else {
binding += info.NumBindings();
module = it->module;
perm_idx = std::distance(program->modules.begin(), it);
}
return std::make_tuple(&info, module, HashCombine(pgm.hash, perm_idx));
}
void ShaderCache::DumpShader(std::span<const u32> code, u64 hash, Shader::Stage stage, void ShaderCache::DumpShader(std::span<const u32> code, u64 hash, Shader::Stage stage,
size_t perm_idx, std::string_view ext) { size_t perm_idx, std::string_view ext) {
using namespace Common::FS; using namespace Common::FS;

View File

@ -111,65 +111,37 @@ struct Program {
Shader::Info info; Shader::Info info;
boost::container::small_vector<Module, 8> modules; boost::container::small_vector<Module, 8> modules;
explicit Program(const Shader::Info& info_) : info{info_} {}
}; };
Shader::Info MakeShaderInfo(Shader::Stage stage, std::span<const u32, 16> user_data, u64 pgm_base, struct GuestProgram {
u64 hash, const AmdGpu::Liverpool::Regs& regs); Shader::Stage stage;
std::span<const u32, AmdGpu::Liverpool::NumShaderUserData> user_data;
std::span<const u32> code;
u64 hash;
[[nodiscard]] inline u64 HashCombine(const u64 seed, const u64 hash) { explicit GuestProgram(const auto* pgm, Shader::Stage stage_)
return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2)); : stage{stage_}, user_data{pgm->user_data}, code{pgm->Code()} {
const auto* bininfo = AmdGpu::Liverpool::GetBinaryInfo(*pgm);
hash = bininfo->shader_hash;
} }
};
class ShaderCache { class ShaderCache {
public: public:
explicit ShaderCache(const Instance& instance, AmdGpu::Liverpool* liverpool); explicit ShaderCache(const Instance& instance, AmdGpu::Liverpool* liverpool);
~ShaderCache() = default; ~ShaderCache() = default;
void DumpShader(std::span<const u32> code, u64 hash, Shader::Stage stage, size_t perm_idx, std::tuple<const Shader::Info*, vk::ShaderModule, u64> GetProgram(const GuestProgram& pgm,
std::string_view ext);
vk::ShaderModule CompileModule(Shader::Info& info, std::span<const u32> code, size_t perm_idx,
u32& binding); u32& binding);
std::tuple<const Shader::Info*, vk::ShaderModule, u64> GetProgram(const auto* pgm, private:
Shader::Stage stage, void DumpShader(std::span<const u32> code, u64 hash, Shader::Stage stage, size_t perm_idx,
u32& binding) { std::string_view ext);
// Fetch program for binaryinfo hash. vk::ShaderModule CompileModule(Shader::Info& info, std::span<const u32> code, size_t perm_idx,
const auto* bininfo = AmdGpu::Liverpool::GetBinaryInfo(*pgm); u32& binding);
const u64 hash = bininfo->shader_hash; Program* CreateProgram(const GuestProgram& pgm, u32& binding);
auto [it_pgm, new_program] = program_cache.try_emplace(hash);
u64 stage_key{};
if (new_program) {
const VAddr pgm_base = pgm->template Address<VAddr>();
auto program = program_pool.Create();
program->info = MakeShaderInfo(stage, pgm->user_data, pgm_base, hash, liverpool->regs);
u32 start_binding = binding;
const auto module = CompileModule(program->info, pgm->Code(), 0, binding);
program->modules.emplace_back(module,
StageSpecialization{program->info, start_binding});
it_pgm.value() = program;
return std::make_tuple(&program->info, module, HashCombine(hash, 0));
}
Program* program = it_pgm->second;
const auto& info = program->info;
size_t perm_idx = program->modules.size();
StageSpecialization spec{info, binding};
vk::ShaderModule module{};
const auto it = std::ranges::find(program->modules, spec, &Program::Module::spec);
if (it == program->modules.end()) {
auto new_info = MakeShaderInfo(stage, pgm->user_data, info.pgm_base, info.pgm_hash,
liverpool->regs);
module = CompileModule(new_info, pgm->Code(), perm_idx, binding);
program->modules.emplace_back(module, std::move(spec));
} else {
binding += info.NumBindings();
module = it->module;
perm_idx = std::distance(program->modules.begin(), it);
}
return std::make_tuple(&info, module, HashCombine(hash, perm_idx));
}
private: private:
const Instance& instance; const Instance& instance;