diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 1a90a584..7e880657 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -161,16 +161,17 @@ void PipelineCache::RefreshGraphicsKey() { continue; } const auto stage = Shader::Stage{i}; + const GuestProgram guest_pgm{pgm, stage}; 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() { u32 binding{}; const auto* cs_pgm = &liverpool->regs.cs_program; - std::tie(infos[0], modules[0], compute_key) = - shader_cache->GetProgram(cs_pgm, Shader::Stage::Compute, binding); + const GuestProgram guest_pgm{cs_pgm, Shader::Stage::Compute}; + std::tie(infos[0], modules[0], compute_key) = shader_cache->GetProgram(guest_pgm, binding); } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_shader_cache.cpp b/src/video_core/renderer_vulkan/vk_shader_cache.cpp index 3bf599a7..76255712 100644 --- a/src/video_core/renderer_vulkan/vk_shader_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_cache.cpp @@ -59,14 +59,13 @@ void BuildVsOutputs(Shader::Info& info, const AmdGpu::Liverpool::VsOutputControl : (ctl.IsCullDistEnabled(7) ? VsOutput::CullDist7 : VsOutput::None)); } -Shader::Info MakeShaderInfo(Shader::Stage stage, std::span user_data, u64 pgm_base, - u64 hash, const AmdGpu::Liverpool::Regs& regs) { +Shader::Info MakeShaderInfo(const GuestProgram& pgm, const AmdGpu::Liverpool::Regs& regs) { Shader::Info info{}; - info.user_data = user_data; - info.pgm_base = pgm_base; - info.pgm_hash = hash; - info.stage = stage; - switch (stage) { + info.user_data = pgm.user_data; + info.pgm_base = VAddr(pgm.code.data()); + info.pgm_hash = pgm.hash; + info.stage = pgm.stage; + switch (pgm.stage) { case Shader::Stage::Vertex: { info.num_user_data = regs.vs_program.settings.num_user_regs; info.num_input_vgprs = regs.vs_program.settings.vgpr_comp_cnt; @@ -101,6 +100,10 @@ Shader::Info MakeShaderInfo(Shader::Stage stage, std::span user_d 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_) : instance{instance_}, liverpool{liverpool_}, inst_pool{8192}, block_pool{512} { profile = Shader::Profile{ @@ -137,6 +140,43 @@ vk::ShaderModule ShaderCache::CompileModule(Shader::Info& info, std::spanregs)); + 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 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 code, u64 hash, Shader::Stage stage, size_t perm_idx, std::string_view ext) { using namespace Common::FS; diff --git a/src/video_core/renderer_vulkan/vk_shader_cache.h b/src/video_core/renderer_vulkan/vk_shader_cache.h index 387bd45c..191e1b08 100644 --- a/src/video_core/renderer_vulkan/vk_shader_cache.h +++ b/src/video_core/renderer_vulkan/vk_shader_cache.h @@ -111,65 +111,37 @@ struct Program { Shader::Info info; boost::container::small_vector modules; + + explicit Program(const Shader::Info& info_) : info{info_} {} }; -Shader::Info MakeShaderInfo(Shader::Stage stage, std::span user_data, u64 pgm_base, - u64 hash, const AmdGpu::Liverpool::Regs& regs); +struct GuestProgram { + Shader::Stage stage; + std::span user_data; + std::span code; + u64 hash; -[[nodiscard]] inline u64 HashCombine(const u64 seed, const u64 hash) { - return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2)); -} + explicit GuestProgram(const auto* pgm, Shader::Stage stage_) + : stage{stage_}, user_data{pgm->user_data}, code{pgm->Code()} { + const auto* bininfo = AmdGpu::Liverpool::GetBinaryInfo(*pgm); + hash = bininfo->shader_hash; + } +}; class ShaderCache { public: explicit ShaderCache(const Instance& instance, AmdGpu::Liverpool* liverpool); ~ShaderCache() = default; + std::tuple GetProgram(const GuestProgram& pgm, + u32& binding); + +private: void DumpShader(std::span code, u64 hash, Shader::Stage stage, size_t perm_idx, std::string_view ext); - vk::ShaderModule CompileModule(Shader::Info& info, std::span code, size_t perm_idx, u32& binding); - - std::tuple GetProgram(const auto* pgm, - Shader::Stage stage, - u32& binding) { - // Fetch program for binaryinfo hash. - const auto* bininfo = AmdGpu::Liverpool::GetBinaryInfo(*pgm); - const u64 hash = bininfo->shader_hash; - auto [it_pgm, new_program] = program_cache.try_emplace(hash); - u64 stage_key{}; - if (new_program) { - const VAddr pgm_base = pgm->template Address(); - 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)); - } + Program* CreateProgram(const GuestProgram& pgm, u32& binding); private: const Instance& instance;