From 16e981c82c95819c721da6aef6a9a75a523fd813 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Tue, 25 Feb 2025 20:38:01 +0100 Subject: [PATCH 01/41] first spirv cache implementation --- src/emulator.cpp | 5 ++++ .../renderer_vulkan/vk_pipeline_cache.cpp | 29 +++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/emulator.cpp b/src/emulator.cpp index 68c1e332c..0e282b89f 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -248,6 +248,11 @@ void Emulator::Run(const std::filesystem::path& file, const std::vectorGetHLESymbols()); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 4823b8ffe..97bfc4702 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -17,6 +17,7 @@ #include "video_core/renderer_vulkan/vk_presenter.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_shader_util.h" +#include extern std::unique_ptr presenter; @@ -504,8 +505,31 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim DumpShader(code, info.pgm_hash, info.stage, perm_idx, "bin"); const auto ir_program = Shader::TranslateProgram(code, pools, info, runtime_info, profile); - auto spv = Shader::Backend::SPIRV::EmitSPIRV(profile, runtime_info, ir_program, binding); - DumpShader(spv, info.pgm_hash, info.stage, perm_idx, "spv"); + + std::string shader_name = GetShaderName(info.stage, info.pgm_hash, perm_idx); + std::string cacheFilename = + shader_name + "_" + Common::g_scm_rev + ".spv "; + + const auto shader_cache_dir = + Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache"; + std::filesystem::path shader_cache_file_path = shader_cache_dir / cacheFilename; + + std::vector spv; + + if (std::filesystem::exists(shader_cache_file_path)) { + Common::FS::IOFile shader_cache_file(shader_cache_file_path, Common::FS::FileAccessMode::Read); + spv.resize(shader_cache_file.GetSize() / sizeof(u32)); + shader_cache_file.Read(spv); + LOG_INFO(Render_Vulkan, "Loaded SPIR-V from cache: {}", shader_cache_file_path.string()); + } else { + spv = Shader::Backend::SPIRV::EmitSPIRV(profile, runtime_info, ir_program, binding); + + DumpShader(spv, info.pgm_hash, info.stage, perm_idx, "spv"); + + Common::FS::IOFile shader_cache_file(shader_cache_file_path, Common::FS::FileAccessMode::Write); + shader_cache_file.WriteSpan(std::span(spv)); + LOG_INFO(Render_Vulkan, "Compiled SPIR-V and stored in cache: {}", shader_cache_file_path.string()); + } vk::ShaderModule module; @@ -520,6 +544,7 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim const auto name = GetShaderName(info.stage, info.pgm_hash, perm_idx); Vulkan::SetObjectName(instance.GetDevice(), module, name); + if (Config::collectShadersForDebug()) { DebugState.CollectShader(name, info.l_stage, module, spv, code, patch ? *patch : std::span{}, is_patched); From c188b7c60d35549b94294169538e6b8b5c46c98c Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Tue, 25 Feb 2025 21:07:24 +0100 Subject: [PATCH 02/41] better naming --- .../renderer_vulkan/vk_pipeline_cache.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 97bfc4702..bb46c8375 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -507,28 +507,28 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim const auto ir_program = Shader::TranslateProgram(code, pools, info, runtime_info, profile); std::string shader_name = GetShaderName(info.stage, info.pgm_hash, perm_idx); - std::string cacheFilename = + std::string spirv_cache_filename = shader_name + "_" + Common::g_scm_rev + ".spv "; const auto shader_cache_dir = Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache"; - std::filesystem::path shader_cache_file_path = shader_cache_dir / cacheFilename; + std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; std::vector spv; - if (std::filesystem::exists(shader_cache_file_path)) { - Common::FS::IOFile shader_cache_file(shader_cache_file_path, Common::FS::FileAccessMode::Read); - spv.resize(shader_cache_file.GetSize() / sizeof(u32)); - shader_cache_file.Read(spv); - LOG_INFO(Render_Vulkan, "Loaded SPIR-V from cache: {}", shader_cache_file_path.string()); + if (std::filesystem::exists(spirv_cache_file_path)) { + Common::FS::IOFile spirv_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Read); + spv.resize(spirv_cache_file.GetSize() / sizeof(u32)); + spirv_cache_file.Read(spv); + LOG_INFO(Render_Vulkan, "Loaded SPIR-V from cache: {}", spirv_cache_file_path.string()); } else { spv = Shader::Backend::SPIRV::EmitSPIRV(profile, runtime_info, ir_program, binding); DumpShader(spv, info.pgm_hash, info.stage, perm_idx, "spv"); - Common::FS::IOFile shader_cache_file(shader_cache_file_path, Common::FS::FileAccessMode::Write); + Common::FS::IOFile shader_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Write); shader_cache_file.WriteSpan(std::span(spv)); - LOG_INFO(Render_Vulkan, "Compiled SPIR-V and stored in cache: {}", shader_cache_file_path.string()); + LOG_INFO(Render_Vulkan, "Compiled SPIR-V and stored in cache: {}", spirv_cache_file_path.string()); } vk::ShaderModule module; From 2aee03218c93ce74ca4937dbc192bbd9aaa7eebb Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Wed, 30 Apr 2025 19:56:38 +0200 Subject: [PATCH 03/41] temp push --- CMakeLists.txt | 1 + src/common/binary_helper.h | 43 +++++++++++++++++++ .../renderer_vulkan/shader_cache.cpp | 28 ++++++++++++ src/video_core/renderer_vulkan/shader_cache.h | 0 .../renderer_vulkan/vk_pipeline_cache.cpp | 5 +-- 5 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 src/common/binary_helper.h create mode 100644 src/video_core/renderer_vulkan/shader_cache.cpp create mode 100644 src/video_core/renderer_vulkan/shader_cache.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e36c1f280..2014dd1aa 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -633,6 +633,7 @@ set(COMMON src/common/logging/backend.cpp src/common/arch.h src/common/assert.cpp src/common/assert.h + src/common/binary_helper.h src/common/bit_field.h src/common/bounded_threadsafe_queue.h src/common/concepts.h diff --git a/src/common/binary_helper.h b/src/common/binary_helper.h new file mode 100644 index 000000000..b6883cf61 --- /dev/null +++ b/src/common/binary_helper.h @@ -0,0 +1,43 @@ +#include +#include + +using u32 = uint32_t; + +template +void writeBin(std::ostream& os, const T& v) { + os.write(reinterpret_cast(&v), sizeof(T)); +} + +template +void readBin(std::istream& is, T& v) { + is.read(reinterpret_cast(&v), sizeof(T)); +} + +// Spezialfall für Arrays/Blöcke +template +void writeBlock(std::ostream& os, const T* data, size_t count) { + os.write(reinterpret_cast(data), sizeof(T) * count); +} + +template +void readBlock(std::istream& is, T* data, size_t count) { + is.read(reinterpret_cast(data), sizeof(T) * count); +} + +// Spezialfall für Container +template +void writeContainer(std::ostream& os, const std::vector& v) { + u32 n = static_cast(v.size()); + writeBin(os, n); + if (n) + writeBlock(os, v.data(), n); +} + +template +void readContainer(std::istream& is, std::vector& v) { + u32 n; + readBin(is, n); + v.resize(n); + if (n) + readBlock(is, v.data(), n); +} \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp new file mode 100644 index 000000000..17860b4dc --- /dev/null +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +namespace ShaderCache { + +const auto shader_cache_dir = Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache"; +std::string CreateShaderID(std::ostream& info_dump, std::ostream& profile_dump) { + std::ostringstream info_stream, profile_stream; + info_stream << info_dump.rdbuf(); + profile_stream << profile_dump.rdbuf(); + + std::string combined_data = info_stream.str() + profile_stream.str(); + + std::hash hasher; + size_t shader_id = hasher(combined_data); + return std::to_string(shader_id); +} + +void GetShader{ + +} +void AddShader(std::vector spv, std::ostream& info_dump, std::ostream& profile_dump) { + + std::string spirv_cache_filename = shader_name + ".spv "; +} + +} \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache.h b/src/video_core/renderer_vulkan/shader_cache.h new file mode 100644 index 000000000..e69de29bb diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 49f3ba706..0d5fe8a69 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -493,13 +493,12 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim DumpShader(code, info.pgm_hash, info.stage, perm_idx, "bin"); const auto ir_program = Shader::TranslateProgram(code, pools, info, runtime_info, profile); - + std::string shader_name = GetShaderName(info.stage, info.pgm_hash, perm_idx); std::string spirv_cache_filename = shader_name + "_" + Common::g_scm_rev + ".spv "; - const auto shader_cache_dir = - Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache"; + std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; std::vector spv; From 09f844add1699f6861e5a80c093c06d224a5cff2 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Wed, 30 Apr 2025 22:01:22 +0200 Subject: [PATCH 04/41] initial codebase --- CMakeLists.txt | 2 + src/common/binary_helper.h | 4 +- .../renderer_vulkan/shader_cache.cpp | 64 ++++++++++++++++--- src/video_core/renderer_vulkan/shader_cache.h | 20 ++++++ .../renderer_vulkan/vk_pipeline_cache.cpp | 23 +++---- 5 files changed, 93 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2014dd1aa..931783df1 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -893,6 +893,8 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp src/video_core/buffer_cache/word_manager.h src/video_core/renderer_vulkan/liverpool_to_vk.cpp src/video_core/renderer_vulkan/liverpool_to_vk.h + src/video_core/renderer_vulkan/shader_cache.cpp + src/video_core/renderer_vulkan/shader_cache.h src/video_core/renderer_vulkan/vk_common.cpp src/video_core/renderer_vulkan/vk_common.h src/video_core/renderer_vulkan/vk_compute_pipeline.cpp diff --git a/src/common/binary_helper.h b/src/common/binary_helper.h index b6883cf61..cfcc213ae 100644 --- a/src/common/binary_helper.h +++ b/src/common/binary_helper.h @@ -1,4 +1,6 @@ -#include +#pragma once + +#include #include using u32 = uint32_t; diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 17860b4dc..63db08b03 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -1,12 +1,21 @@ #include #include #include +#include +#include "common/path_util.h" +#include "common/io_file.h" +#include "common/binary_helper.h" +#include "shader_recompiler/info.h" + +using u64 = uint64_t; namespace ShaderCache { const auto shader_cache_dir = Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache"; -std::string CreateShaderID(std::ostream& info_dump, std::ostream& profile_dump) { + +std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_dump, std::ostream& profile_dump) { std::ostringstream info_stream, profile_stream; + info_stream << pgm_hash << perm_idx; info_stream << info_dump.rdbuf(); profile_stream << profile_dump.rdbuf(); @@ -17,12 +26,51 @@ std::string CreateShaderID(std::ostream& info_dump, std::ostream& profile_dump) return std::to_string(shader_id); } -void GetShader{ - -} -void AddShader(std::vector spv, std::ostream& info_dump, std::ostream& profile_dump) { - - std::string spirv_cache_filename = shader_name + ".spv "; +void DumpInfo(std::ostream& info_dump, Shader::Info info) { + writeBin(info_dump, info.mrt_mask); } -} \ No newline at end of file +void DumpProfile(std::ostream& profile_dump, Shader::Profile profile) { + writeBin(profile_dump, profile.has_broken_spirv_clamp); +} + +bool CheckShaderCache(std::string shader_id) { + return 0; +} + +bool GetShader(std::string shader_id) { + std::string spirv_cache_filename = shader_id + ".spv "; + std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; + Common::FS::IOFile spirv_cache_file(spirv_cache_file_path, + Common::FS::FileAccessMode::Read); + std::vector spv; + spv.resize(spirv_cache_file.GetSize() / sizeof(u32)); + spirv_cache_file.Read(spv); +} + +void AddShader(std::string shader_id, std::vector spv, std::ostream& info_dump, std::ostream& profile_dump) { + std::string spirv_cache_filename = shader_id + ".spv "; + std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; + Common::FS::IOFile shader_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Write); + shader_cache_file.WriteSpan(std::span(spv)); + + std::filesystem::path resources_dump_file_path = shader_cache_dir / (shader_id + ".resources"); + Common::FS::IOFile resources_dump_file(resources_dump_file_path, Common::FS::FileAccessMode::Write); + // Schreibe beide Streams nacheinander in die Ressourcen-Datei + std::ostringstream info_stream, profile_stream; + info_stream << info_dump.rdbuf(); + profile_stream << profile_dump.rdbuf(); + + // Schreibe zuerst die Größe des info-Dumps, dann die Daten + u32 info_size = static_cast(info_stream.str().size()); + resources_dump_file.WriteString(std::span(info_stream.str().data(), info_size)); + + // Schreibe danach die Größe des profile-Dumps, dann die Daten + u32 profile_size = static_cast(profile_stream.str().size()); + resources_dump_file.WriteString( + std::span(profile_stream.str().data(), profile_size)); + + +} + +} // namespace ShaderCache \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache.h b/src/video_core/renderer_vulkan/shader_cache.h index e69de29bb..0ae35ed2c 100644 --- a/src/video_core/renderer_vulkan/shader_cache.h +++ b/src/video_core/renderer_vulkan/shader_cache.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include +#include +#include +#include "shader_recompiler/info.h" + +namespace ShaderCache { + +std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_dump, + std::ostream& profile_dump); +void DumpInfo(std::ostream& info_dump, Shader::Info info); +void DumpProfile(std::ostream& profile_dump, Shader::Profile profile); +bool CheckShaderCache(std::string shader_id); +bool GetShader(std::string shader_id); +void AddShader(std::string shader_id, std::vector spv, std::ostream& info_dump, + std::ostream& profile_dump); + +} // namespace ShaderCache diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 0d5fe8a69..ab0f9f3f8 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -12,6 +12,7 @@ #include "shader_recompiler/info.h" #include "shader_recompiler/recompiler.h" #include "shader_recompiler/runtime_info.h" +#include "video_core/renderer_vulkan/shader_cache.h" #include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_pipeline_cache.h" #include "video_core/renderer_vulkan/vk_presenter.h" @@ -492,30 +493,30 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim perm_idx != 0 ? "(permutation)" : ""); DumpShader(code, info.pgm_hash, info.stage, perm_idx, "bin"); + std::ostringstream info_dump, profile_dump; + ::ShaderCache::DumpInfo(info_dump, info); + ::ShaderCache::DumpProfile(profile_dump, profile); + std::string shader_id = ::ShaderCache::CreateShaderID(info.pgm_hash, perm_idx, info_dump, profile_dump); + ::ShaderCache::AddShader(shader_id, std::vector{}, info_dump, profile_dump); + LOG_INFO(Render_Vulkan, "Shader ID: {}", shader_id); + const auto ir_program = Shader::TranslateProgram(code, pools, info, runtime_info, profile); std::string shader_name = GetShaderName(info.stage, info.pgm_hash, perm_idx); - std::string spirv_cache_filename = - shader_name + "_" + Common::g_scm_rev + ".spv "; - std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; std::vector spv; - if (std::filesystem::exists(spirv_cache_file_path)) { - Common::FS::IOFile spirv_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Read); - spv.resize(spirv_cache_file.GetSize() / sizeof(u32)); - spirv_cache_file.Read(spv); - LOG_INFO(Render_Vulkan, "Loaded SPIR-V from cache: {}", spirv_cache_file_path.string()); + if (::ShaderCache::CheckShaderCache(shader_id)) { + LOG_INFO(Render_Vulkan, "Loaded SPIR-V from cache"); } else { spv = Shader::Backend::SPIRV::EmitSPIRV(profile, runtime_info, ir_program, binding); DumpShader(spv, info.pgm_hash, info.stage, perm_idx, "spv"); - Common::FS::IOFile shader_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Write); - shader_cache_file.WriteSpan(std::span(spv)); - LOG_INFO(Render_Vulkan, "Compiled SPIR-V and stored in cache: {}", spirv_cache_file_path.string()); + + LOG_INFO(Render_Vulkan, "Compiled SPIR-V and stored in cache"); } vk::ShaderModule module; From bde3873781c79e37377243d7e57daf625a5defbc Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Wed, 30 Apr 2025 23:02:05 +0200 Subject: [PATCH 05/41] more --- .../renderer_vulkan/shader_cache.cpp | 30 +++++++++++-------- src/video_core/renderer_vulkan/shader_cache.h | 4 +-- .../renderer_vulkan/vk_pipeline_cache.cpp | 10 +++---- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 63db08b03..cce789b45 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -13,11 +13,11 @@ namespace ShaderCache { const auto shader_cache_dir = Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache"; -std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_dump, std::ostream& profile_dump) { +std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_serialized, std::ostream& profile_serialized) { std::ostringstream info_stream, profile_stream; info_stream << pgm_hash << perm_idx; - info_stream << info_dump.rdbuf(); - profile_stream << profile_dump.rdbuf(); + info_stream << info_serialized.rdbuf(); + profile_stream << profile_serialized.rdbuf(); std::string combined_data = info_stream.str() + profile_stream.str(); @@ -26,12 +26,20 @@ std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_dum return std::to_string(shader_id); } -void DumpInfo(std::ostream& info_dump, Shader::Info info) { - writeBin(info_dump, info.mrt_mask); +void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { + writeBin(info_serialized, info.mrt_mask); } -void DumpProfile(std::ostream& profile_dump, Shader::Profile profile) { - writeBin(profile_dump, profile.has_broken_spirv_clamp); +void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { + readBin(info_serialized, info.mrt_mask); +} + +void SerializeProfile(std::ostream& profile_serialized, Shader::Profile profile) { + writeBin(profile_serialized, profile.has_broken_spirv_clamp); +} + +void DeserializeProfile(std::istream& profile_serialized, Shader::Profile& profile) { + readBin(profile_serialized, profile.has_broken_spirv_clamp); } bool CheckShaderCache(std::string shader_id) { @@ -48,7 +56,7 @@ bool GetShader(std::string shader_id) { spirv_cache_file.Read(spv); } -void AddShader(std::string shader_id, std::vector spv, std::ostream& info_dump, std::ostream& profile_dump) { +void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized, std::ostream& profile_serialized) { std::string spirv_cache_filename = shader_id + ".spv "; std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; Common::FS::IOFile shader_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Write); @@ -58,8 +66,8 @@ void AddShader(std::string shader_id, std::vector spv, std::ostream& info_d Common::FS::IOFile resources_dump_file(resources_dump_file_path, Common::FS::FileAccessMode::Write); // Schreibe beide Streams nacheinander in die Ressourcen-Datei std::ostringstream info_stream, profile_stream; - info_stream << info_dump.rdbuf(); - profile_stream << profile_dump.rdbuf(); + info_stream << info_serialized.rdbuf(); + profile_stream << profile_serialized.rdbuf(); // Schreibe zuerst die Größe des info-Dumps, dann die Daten u32 info_size = static_cast(info_stream.str().size()); @@ -69,8 +77,6 @@ void AddShader(std::string shader_id, std::vector spv, std::ostream& info_d u32 profile_size = static_cast(profile_stream.str().size()); resources_dump_file.WriteString( std::span(profile_stream.str().data(), profile_size)); - - } } // namespace ShaderCache \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache.h b/src/video_core/renderer_vulkan/shader_cache.h index 0ae35ed2c..c789eb855 100644 --- a/src/video_core/renderer_vulkan/shader_cache.h +++ b/src/video_core/renderer_vulkan/shader_cache.h @@ -10,8 +10,8 @@ namespace ShaderCache { std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_dump, std::ostream& profile_dump); -void DumpInfo(std::ostream& info_dump, Shader::Info info); -void DumpProfile(std::ostream& profile_dump, Shader::Profile profile); +void SerializeInfo(std::ostream& info_dump, Shader::Info info); +void SerializeProfile(std::ostream& profile_dump, Shader::Profile profile); bool CheckShaderCache(std::string shader_id); bool GetShader(std::string shader_id); void AddShader(std::string shader_id, std::vector spv, std::ostream& info_dump, diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index ab0f9f3f8..ca6b19c91 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -493,11 +493,11 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim perm_idx != 0 ? "(permutation)" : ""); DumpShader(code, info.pgm_hash, info.stage, perm_idx, "bin"); - std::ostringstream info_dump, profile_dump; - ::ShaderCache::DumpInfo(info_dump, info); - ::ShaderCache::DumpProfile(profile_dump, profile); - std::string shader_id = ::ShaderCache::CreateShaderID(info.pgm_hash, perm_idx, info_dump, profile_dump); - ::ShaderCache::AddShader(shader_id, std::vector{}, info_dump, profile_dump); + std::ostringstream info_serialized, profile_serialized; + ::ShaderCache::SerializeInfo(info_serialized, info); + ::ShaderCache::SerializeProfile(profile_serialized, profile); + std::string shader_id = ::ShaderCache::CreateShaderID(info.pgm_hash, perm_idx, info_serialized, profile_serialized); + ::ShaderCache::AddShader(shader_id, std::vector{}, info_serialized, profile_serialized); LOG_INFO(Render_Vulkan, "Shader ID: {}", shader_id); const auto ir_program = Shader::TranslateProgram(code, pools, info, runtime_info, profile); From 24f17f59f249dd146148ba0c41765c91eb815e27 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Thu, 1 May 2025 07:11:21 +0200 Subject: [PATCH 06/41] more --- .../renderer_vulkan/shader_cache.cpp | 28 ++++++++++++++++++- src/video_core/renderer_vulkan/shader_cache.h | 13 +++++---- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index cce789b45..8eaa72ad1 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -46,7 +46,7 @@ bool CheckShaderCache(std::string shader_id) { return 0; } -bool GetShader(std::string shader_id) { +void GetShader(std::string shader_id, Shader::Info& info, Shader::Profile& profile) { std::string spirv_cache_filename = shader_id + ".spv "; std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; Common::FS::IOFile spirv_cache_file(spirv_cache_file_path, @@ -54,6 +54,30 @@ bool GetShader(std::string shader_id) { std::vector spv; spv.resize(spirv_cache_file.GetSize() / sizeof(u32)); spirv_cache_file.Read(spv); + spirv_cache_file.Close(); + + std::filesystem::path resources_dump_file_path = shader_cache_dir / (shader_id + ".resources"); + Common::FS::IOFile resources_dump_file(resources_dump_file_path, + Common::FS::FileAccessMode::Read); + + // Lese die Ressourcendaten + std::vector resources_data; + resources_data.resize(resources_dump_file.GetSize()); + resources_dump_file.Read(resources_data); + resources_dump_file.Close(); + + // Verarbeite die gespeicherten Daten + std::istringstream combined_stream(std::string(resources_data.begin(), resources_data.end())); + + // Deserialisiere info und profile + std::istringstream info_stream; + info_stream.str(std::string(resources_data.begin(), resources_data.end())); + DeserializeInfo(info_stream, info); + + std::istringstream profile_stream; + profile_stream.str( + std::string(resources_data.begin() + info_stream.tellg(), resources_data.end())); + DeserializeProfile(profile_stream, profile); } void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized, std::ostream& profile_serialized) { @@ -77,6 +101,8 @@ void AddShader(std::string shader_id, std::vector spv, std::ostream& info_s u32 profile_size = static_cast(profile_stream.str().size()); resources_dump_file.WriteString( std::span(profile_stream.str().data(), profile_size)); + + resources_dump_file.Close(); } } // namespace ShaderCache \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache.h b/src/video_core/renderer_vulkan/shader_cache.h index c789eb855..4f885a99d 100644 --- a/src/video_core/renderer_vulkan/shader_cache.h +++ b/src/video_core/renderer_vulkan/shader_cache.h @@ -10,11 +10,14 @@ namespace ShaderCache { std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_dump, std::ostream& profile_dump); -void SerializeInfo(std::ostream& info_dump, Shader::Info info); -void SerializeProfile(std::ostream& profile_dump, Shader::Profile profile); +void SerializeInfo(std::ostream& info_serialized, Shader::Info info); +void SerializeProfile(std::ostream& profile_serialized, Shader::Profile profile); +void DeserializeInfo(std::istream& info_serialized, Shader::Info& info); +void DeserializeProfile(std::istream& profile_serialized, Shader::Profile& profile); + bool CheckShaderCache(std::string shader_id); -bool GetShader(std::string shader_id); -void AddShader(std::string shader_id, std::vector spv, std::ostream& info_dump, - std::ostream& profile_dump); +void GetShader(std::string shader_id, Shader::Info& info, Shader::Profile& profile); +void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized, + std::ostream& profile_serialized); } // namespace ShaderCache From b32ba2918b2b82a0628a2d0a8e289a805c85b900 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Thu, 1 May 2025 18:50:20 +0200 Subject: [PATCH 07/41] fix filewriting --- .../renderer_vulkan/shader_cache.cpp | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 8eaa72ad1..65df6e295 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -81,26 +81,29 @@ void GetShader(std::string shader_id, Shader::Info& info, Shader::Profile& profi } void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized, std::ostream& profile_serialized) { - std::string spirv_cache_filename = shader_id + ".spv "; + // SPIR-V-Datei speichern + std::string spirv_cache_filename = shader_id + ".spv"; std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; Common::FS::IOFile shader_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Write); shader_cache_file.WriteSpan(std::span(spv)); + shader_cache_file.Close(); + // Resources-Datei vorbereiten std::filesystem::path resources_dump_file_path = shader_cache_dir / (shader_id + ".resources"); - Common::FS::IOFile resources_dump_file(resources_dump_file_path, Common::FS::FileAccessMode::Write); - // Schreibe beide Streams nacheinander in die Ressourcen-Datei - std::ostringstream info_stream, profile_stream; - info_stream << info_serialized.rdbuf(); - profile_stream << profile_serialized.rdbuf(); + Common::FS::IOFile resources_dump_file(resources_dump_file_path, + Common::FS::FileAccessMode::Write); - // Schreibe zuerst die Größe des info-Dumps, dann die Daten - u32 info_size = static_cast(info_stream.str().size()); - resources_dump_file.WriteString(std::span(info_stream.str().data(), info_size)); + // Die Streams müssen zurückgesetzt werden, bevor wir sie lesen können + if (std::ostringstream* info_oss = dynamic_cast(&info_serialized)) { + std::string info_data = info_oss->str(); + resources_dump_file.WriteSpan(std::span(info_data.data(), info_data.size())); + } - // Schreibe danach die Größe des profile-Dumps, dann die Daten - u32 profile_size = static_cast(profile_stream.str().size()); - resources_dump_file.WriteString( - std::span(profile_stream.str().data(), profile_size)); + if (std::ostringstream* profile_oss = dynamic_cast(&profile_serialized)) { + std::string profile_data = profile_oss->str(); + resources_dump_file.WriteSpan( + std::span(profile_data.data(), profile_data.size())); + } resources_dump_file.Close(); } From 3eb8000b75789ef7fadabf348369decab3d2a4b3 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Thu, 1 May 2025 20:58:38 +0200 Subject: [PATCH 08/41] some progress --- src/common/binary_helper.h | 30 ++--- .../renderer_vulkan/shader_cache.cpp | 105 +++++++++++++----- src/video_core/renderer_vulkan/shader_cache.h | 10 +- .../renderer_vulkan/vk_pipeline_cache.cpp | 15 ++- 4 files changed, 102 insertions(+), 58 deletions(-) diff --git a/src/common/binary_helper.h b/src/common/binary_helper.h index cfcc213ae..564896f11 100644 --- a/src/common/binary_helper.h +++ b/src/common/binary_helper.h @@ -2,44 +2,46 @@ #include #include +#include "common/logging/log.h" using u32 = uint32_t; template -void writeBin(std::ostream& os, const T& v) { - os.write(reinterpret_cast(&v), sizeof(T)); +void writeBin(std::ostream& os, const T& v) { + LOG_INFO(Render_Recompiler, "BinaryHelper: Pos: {}", static_cast(os.tellp())); + os.write(reinterpret_cast(&v), sizeof(T)); } template void readBin(std::istream& is, T& v) { - is.read(reinterpret_cast(&v), sizeof(T)); + is.read(reinterpret_cast(&v), sizeof(T)); } // Spezialfall für Arrays/Blöcke template void writeBlock(std::ostream& os, const T* data, size_t count) { - os.write(reinterpret_cast(data), sizeof(T) * count); + os.write(reinterpret_cast(data), sizeof(T) * count); } template void readBlock(std::istream& is, T* data, size_t count) { - is.read(reinterpret_cast(data), sizeof(T) * count); + is.read(reinterpret_cast(data), sizeof(T) * count); } // Spezialfall für Container template void writeContainer(std::ostream& os, const std::vector& v) { - u32 n = static_cast(v.size()); - writeBin(os, n); - if (n) - writeBlock(os, v.data(), n); + u32 n = static_cast(v.size()); + writeBin(os, n); + if (n) + writeBlock(os, v.data(), n); } template void readContainer(std::istream& is, std::vector& v) { - u32 n; - readBin(is, n); - v.resize(n); - if (n) - readBlock(is, v.data(), n); + u32 n; + readBin(is, n); + v.resize(n); + if (n) + readBlock(is, v.data(), n); } \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 65df6e295..4097b140a 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -5,28 +5,93 @@ #include "common/path_util.h" #include "common/io_file.h" #include "common/binary_helper.h" +#include "common/logging/log.h" #include "shader_recompiler/info.h" using u64 = uint64_t; +using u32 = uint32_t; namespace ShaderCache { const auto shader_cache_dir = Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache"; -std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_serialized, std::ostream& profile_serialized) { - std::ostringstream info_stream, profile_stream; - info_stream << pgm_hash << perm_idx; - info_stream << info_serialized.rdbuf(); - profile_stream << profile_serialized.rdbuf(); - - std::string combined_data = info_stream.str() + profile_stream.str(); - +std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_serialized) { + std::ostringstream data_stream; + data_stream << pgm_hash << perm_idx; + data_stream << info_serialized.rdbuf(); std::hash hasher; - size_t shader_id = hasher(combined_data); + size_t shader_id = hasher(data_stream.str()); return std::to_string(shader_id); } void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { + // UD Mask + writeBin(info_serialized, info.ud_mask.mask); + + // Buffer-Resources + u32 count = static_cast(info.buffers.size()); + writeBin(info_serialized, count); // Buffer Amount + LOG_INFO(Render_Recompiler, "ShaderCache: Buffer count: {}", info.buffers.size()); + + for (const auto& buffer : info.buffers) { + writeBin(info_serialized, buffer.sharp_idx); + writeBin(info_serialized, static_cast(buffer.used_types)); + writeBin(info_serialized, static_cast(buffer.buffer_type)); + writeBin(info_serialized, buffer.instance_attrib); + writeBin(info_serialized, static_cast(buffer.is_written ? 1 : 0)); + writeBin(info_serialized, static_cast(buffer.is_formatted ? 1 : 0)); + } + + // Image-Resources + count = static_cast(info.images.size()); + writeBin(info_serialized, count); // Image Amount + LOG_INFO(Render_Recompiler, "ShaderCache: Image count: {}", info.images.size()); + for (const auto& image : info.images) { + writeBin(info_serialized, image.sharp_idx); + writeBin(info_serialized, static_cast(image.is_depth ? 1 : 0)); + writeBin(info_serialized, static_cast(image.is_atomic ? 1 : 0)); + writeBin(info_serialized, static_cast(image.is_array ? 1 : 0)); + writeBin(info_serialized, static_cast(image.is_written ? 1 : 0)); + } + + // Sampler-Resources + count = static_cast(info.samplers.size()); + writeBin(info_serialized, count); // Sampler Amount + LOG_INFO(Render_Recompiler, "ShaderCache: Sampler count: {}", info.samplers.size()); + for (const auto& sampler : info.samplers) { + writeBin(info_serialized, sampler.sharp_idx); + } + + // FMask-Resources + count = static_cast(info.fmasks.size()); + writeBin(info_serialized, count); // FMask Amount + LOG_INFO(Render_Recompiler, "ShaderCache: FMask count: {}", info.fmasks.size()); + for (const auto& fmask : info.fmasks) { + writeBin(info_serialized, fmask.sharp_idx); + } + + // GS Copy Data + writeBin(info_serialized, info.gs_copy_data.num_attrs); + + u32 mapCount = static_cast(info.gs_copy_data.attr_map.size()); + writeBin(info_serialized, mapCount); + + for (auto const& [loc, idx] : info.gs_copy_data.attr_map) { + writeBin(info_serialized, loc); + writeBin(info_serialized, idx); + } + + // SRT Info + u32 srtCount = static_cast(info.srt_info.srt_reservations.size()); + writeBin(info_serialized, count); + + for (const auto& res : info.srt_info.srt_reservations) { + writeBin(info_serialized, res.sgpr_base); + writeBin(info_serialized, res.dword_offset); + writeBin(info_serialized, res.num_dwords); + } + + // MRT Mask writeBin(info_serialized, info.mrt_mask); } @@ -34,19 +99,11 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { readBin(info_serialized, info.mrt_mask); } -void SerializeProfile(std::ostream& profile_serialized, Shader::Profile profile) { - writeBin(profile_serialized, profile.has_broken_spirv_clamp); -} - -void DeserializeProfile(std::istream& profile_serialized, Shader::Profile& profile) { - readBin(profile_serialized, profile.has_broken_spirv_clamp); -} - bool CheckShaderCache(std::string shader_id) { return 0; } -void GetShader(std::string shader_id, Shader::Info& info, Shader::Profile& profile) { +void GetShader(std::string shader_id, Shader::Info& info) { std::string spirv_cache_filename = shader_id + ".spv "; std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; Common::FS::IOFile spirv_cache_file(spirv_cache_file_path, @@ -74,13 +131,9 @@ void GetShader(std::string shader_id, Shader::Info& info, Shader::Profile& profi info_stream.str(std::string(resources_data.begin(), resources_data.end())); DeserializeInfo(info_stream, info); - std::istringstream profile_stream; - profile_stream.str( - std::string(resources_data.begin() + info_stream.tellg(), resources_data.end())); - DeserializeProfile(profile_stream, profile); } -void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized, std::ostream& profile_serialized) { +void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized) { // SPIR-V-Datei speichern std::string spirv_cache_filename = shader_id + ".spv"; std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; @@ -99,12 +152,6 @@ void AddShader(std::string shader_id, std::vector spv, std::ostream& info_s resources_dump_file.WriteSpan(std::span(info_data.data(), info_data.size())); } - if (std::ostringstream* profile_oss = dynamic_cast(&profile_serialized)) { - std::string profile_data = profile_oss->str(); - resources_dump_file.WriteSpan( - std::span(profile_data.data(), profile_data.size())); - } - resources_dump_file.Close(); } diff --git a/src/video_core/renderer_vulkan/shader_cache.h b/src/video_core/renderer_vulkan/shader_cache.h index 4f885a99d..2b5c1ae75 100644 --- a/src/video_core/renderer_vulkan/shader_cache.h +++ b/src/video_core/renderer_vulkan/shader_cache.h @@ -8,16 +8,12 @@ namespace ShaderCache { -std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_dump, - std::ostream& profile_dump); +std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_dump); void SerializeInfo(std::ostream& info_serialized, Shader::Info info); -void SerializeProfile(std::ostream& profile_serialized, Shader::Profile profile); void DeserializeInfo(std::istream& info_serialized, Shader::Info& info); -void DeserializeProfile(std::istream& profile_serialized, Shader::Profile& profile); bool CheckShaderCache(std::string shader_id); -void GetShader(std::string shader_id, Shader::Info& info, Shader::Profile& profile); -void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized, - std::ostream& profile_serialized); +void GetShader(std::string shader_id, Shader::Info& info); +void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized); } // namespace ShaderCache diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index ca6b19c91..cb4a6c0ce 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -493,12 +493,6 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim perm_idx != 0 ? "(permutation)" : ""); DumpShader(code, info.pgm_hash, info.stage, perm_idx, "bin"); - std::ostringstream info_serialized, profile_serialized; - ::ShaderCache::SerializeInfo(info_serialized, info); - ::ShaderCache::SerializeProfile(profile_serialized, profile); - std::string shader_id = ::ShaderCache::CreateShaderID(info.pgm_hash, perm_idx, info_serialized, profile_serialized); - ::ShaderCache::AddShader(shader_id, std::vector{}, info_serialized, profile_serialized); - LOG_INFO(Render_Vulkan, "Shader ID: {}", shader_id); const auto ir_program = Shader::TranslateProgram(code, pools, info, runtime_info, profile); @@ -508,11 +502,16 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim std::vector spv; - if (::ShaderCache::CheckShaderCache(shader_id)) { + if (false){ //(::ShaderCache::CheckShaderCache(shader_id)) { LOG_INFO(Render_Vulkan, "Loaded SPIR-V from cache"); } else { spv = Shader::Backend::SPIRV::EmitSPIRV(profile, runtime_info, ir_program, binding); - + std::ostringstream info_serialized; + ::ShaderCache::SerializeInfo(info_serialized, info); + std::string shader_id = + ::ShaderCache::CreateShaderID(info.pgm_hash, perm_idx, info_serialized); + ::ShaderCache::AddShader(shader_id, spv, info_serialized); + LOG_INFO(Render_Vulkan, "Shader ID: {}", shader_id); DumpShader(spv, info.pgm_hash, info.stage, perm_idx, "spv"); From a500b98e9bcc2a392acfd2370c31f50387834127 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 3 May 2025 15:29:57 +0200 Subject: [PATCH 09/41] more --- src/common/binary_helper.h | 31 +- src/common/hash.h | 9 +- .../renderer_vulkan/shader_cache.cpp | 587 +++++++++++++++++- src/video_core/renderer_vulkan/shader_cache.h | 8 +- .../renderer_vulkan/vk_pipeline_cache.cpp | 35 +- .../renderer_vulkan/vk_pipeline_cache.h | 2 +- 6 files changed, 582 insertions(+), 90 deletions(-) diff --git a/src/common/binary_helper.h b/src/common/binary_helper.h index 564896f11..de1bb9b78 100644 --- a/src/common/binary_helper.h +++ b/src/common/binary_helper.h @@ -15,33 +15,4 @@ void writeBin(std::ostream& os, const T& v) { template void readBin(std::istream& is, T& v) { is.read(reinterpret_cast(&v), sizeof(T)); -} - -// Spezialfall für Arrays/Blöcke -template -void writeBlock(std::ostream& os, const T* data, size_t count) { - os.write(reinterpret_cast(data), sizeof(T) * count); -} - -template -void readBlock(std::istream& is, T* data, size_t count) { - is.read(reinterpret_cast(data), sizeof(T) * count); -} - -// Spezialfall für Container -template -void writeContainer(std::ostream& os, const std::vector& v) { - u32 n = static_cast(v.size()); - writeBin(os, n); - if (n) - writeBlock(os, v.data(), n); -} - -template -void readContainer(std::istream& is, std::vector& v) { - u32 n; - readBin(is, n); - v.resize(n); - if (n) - readBlock(is, v.data(), n); -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/common/hash.h b/src/common/hash.h index d5cacedd7..b29cfb90f 100644 --- a/src/common/hash.h +++ b/src/common/hash.h @@ -5,10 +5,7 @@ #include "common/types.h" -[[nodiscard]] inline u64 HashCombine(const u64 seed, const u64 hash) { - return seed ^ (hash + 0x9e3779b9 + (seed << 12) + (seed >> 4)); -} - -[[nodiscard]] inline u32 HashCombine(const u32 seed, const u32 hash) { - return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2)); +template +T HashCombine(const T& seed, const U& value) { + return seed ^ (static_cast(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); } \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 4097b140a..b256d2cda 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -1,12 +1,14 @@ #include #include -#include #include +#include "common/hash.h" #include "common/path_util.h" #include "common/io_file.h" #include "common/binary_helper.h" #include "common/logging/log.h" +#include "shader_recompiler/ir/type.h" #include "shader_recompiler/info.h" +#include "shader_recompiler/specialization.h" using u64 = uint64_t; using u32 = uint32_t; @@ -15,13 +17,242 @@ namespace ShaderCache { const auto shader_cache_dir = Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache"; -std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_serialized) { - std::ostringstream data_stream; - data_stream << pgm_hash << perm_idx; - data_stream << info_serialized.rdbuf(); - std::hash hasher; - size_t shader_id = hasher(data_stream.str()); - return std::to_string(shader_id); +u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { + u64 hash = 0; + + // Start mit dem Hash der RuntimeInfo + // Die RuntimeInfo enthält verschiedene Unions, daher müssen wir basierend auf dem Stage-Typ + // hashen + const auto& runtime_info = spec.runtime_info; + hash = HashCombine(hash, static_cast(runtime_info.stage)); + hash = HashCombine(hash, runtime_info.num_user_data); + hash = HashCombine(hash, runtime_info.num_input_vgprs); + hash = HashCombine(hash, runtime_info.num_allocated_vgprs); + hash = HashCombine(hash, static_cast(runtime_info.fp_denorm_mode32)); + hash = HashCombine(hash, static_cast(runtime_info.fp_round_mode32)); + + // Abhängig vom Stage-Typ die spezifischen RuntimeInfo-Felder hashen + switch (runtime_info.stage) { + case Shader::Stage::Local: + hash = HashCombine(hash, runtime_info.ls_info.ls_stride); + hash = HashCombine(hash, runtime_info.ls_info.links_with_tcs); + break; + case Shader::Stage::Export: + hash = HashCombine(hash, runtime_info.es_info.vertex_data_size); + break; + case Shader::Stage::Vertex: + hash = HashCombine(hash, runtime_info.vs_info.num_outputs); + // Hash der Output-Maps + for (size_t i = 0; + i < runtime_info.vs_info.num_outputs && i < runtime_info.vs_info.outputs.size(); ++i) { + const auto& output_map = runtime_info.vs_info.outputs[i]; + for (const auto& output : output_map) { + hash = HashCombine(hash, static_cast(output)); + } + } + hash = HashCombine(hash, runtime_info.vs_info.emulate_depth_negative_one_to_one); + hash = HashCombine(hash, runtime_info.vs_info.clip_disable); + hash = HashCombine(hash, static_cast(runtime_info.vs_info.tess_type)); + hash = HashCombine(hash, static_cast(runtime_info.vs_info.tess_topology)); + hash = HashCombine(hash, static_cast(runtime_info.vs_info.tess_partitioning)); + hash = HashCombine(hash, runtime_info.vs_info.hs_output_cp_stride); + break; + case Shader::Stage::Hull: + hash = HashCombine(hash, runtime_info.hs_info.num_input_control_points); + hash = HashCombine(hash, runtime_info.hs_info.num_threads); + hash = HashCombine(hash, static_cast(runtime_info.hs_info.tess_type)); + hash = HashCombine(hash, runtime_info.hs_info.ls_stride); + hash = HashCombine(hash, runtime_info.hs_info.hs_output_cp_stride); + hash = HashCombine(hash, runtime_info.hs_info.hs_output_base); + break; + case Shader::Stage::Geometry: + hash = HashCombine(hash, runtime_info.gs_info.num_invocations); + hash = HashCombine(hash, runtime_info.gs_info.output_vertices); + hash = HashCombine(hash, runtime_info.gs_info.in_vertex_data_size); + hash = HashCombine(hash, runtime_info.gs_info.out_vertex_data_size); + hash = HashCombine(hash, static_cast(runtime_info.gs_info.in_primitive)); + // Hash der Output-Primitive-Types für alle Streams + for (const auto& out_prim : runtime_info.gs_info.out_primitive) { + hash = HashCombine(hash, static_cast(out_prim)); + } + hash = HashCombine(hash, runtime_info.gs_info.vs_copy_hash); + break; + case Shader::Stage::Fragment: + hash = HashCombine(hash, runtime_info.fs_info.en_flags.raw); + hash = HashCombine(hash, runtime_info.fs_info.addr_flags.raw); + hash = HashCombine(hash, runtime_info.fs_info.num_inputs); + + // Hash der PS-Inputs + for (u32 i = 0; + i < runtime_info.fs_info.num_inputs && i < runtime_info.fs_info.inputs.size(); ++i) { + const auto& input = runtime_info.fs_info.inputs[i]; + hash = HashCombine(hash, input.param_index); + hash = HashCombine(hash, input.is_default); + hash = HashCombine(hash, input.is_flat); + hash = HashCombine(hash, input.default_value); + } + + // Hash der ColorBuffers + for (const auto& color_buffer : runtime_info.fs_info.color_buffers) { + hash = HashCombine(hash, static_cast(color_buffer.num_format)); + hash = HashCombine(hash, static_cast(color_buffer.num_conversion)); + hash = HashCombine(hash, static_cast(color_buffer.export_format)); + hash = HashCombine(hash, color_buffer.needs_unorm_fixup); + hash = HashCombine(hash, color_buffer.swizzle.r); + hash = HashCombine(hash, color_buffer.swizzle.g); + hash = HashCombine(hash, color_buffer.swizzle.b); + hash = HashCombine(hash, color_buffer.swizzle.a); + } + break; + case Shader::Stage::Compute: + hash = HashCombine(hash, runtime_info.cs_info.shared_memory_size); + for (u32 i = 0; i < 3; ++i) { + hash = HashCombine(hash, runtime_info.cs_info.workgroup_size[i]); + hash = HashCombine(hash, runtime_info.cs_info.tgid_enable[i]); + } + break; + } + + // Hash des FetchShader-Daten + if (spec.fetch_shader_data) { + const auto& fetch_shader = *spec.fetch_shader_data; + hash = HashCombine(hash, fetch_shader.size); + hash = HashCombine(hash, static_cast(fetch_shader.vertex_offset_sgpr)); + hash = HashCombine(hash, static_cast(fetch_shader.instance_offset_sgpr)); + + // Hash der Attribute + for (const auto& attr : fetch_shader.attributes) { + hash = HashCombine(hash, static_cast(attr.semantic)); + hash = HashCombine(hash, static_cast(attr.dest_vgpr)); + hash = HashCombine(hash, static_cast(attr.num_elements)); + hash = HashCombine(hash, static_cast(attr.sgpr_base)); + hash = HashCombine(hash, static_cast(attr.dword_offset)); + hash = HashCombine(hash, static_cast(attr.instance_data)); + } + } + + // Hash der VS-Attribut-Spezialisierungen + for (const auto& vs_attrib : spec.vs_attribs) { + hash = HashCombine(hash, vs_attrib.num_components); + hash = HashCombine(hash, static_cast(vs_attrib.num_class)); + hash = HashCombine(hash, vs_attrib.dst_select.r); + hash = HashCombine(hash, vs_attrib.dst_select.g); + hash = HashCombine(hash, vs_attrib.dst_select.b); + hash = HashCombine(hash, vs_attrib.dst_select.a); + } + + // Hash des Bitsets + const std::string bitset_str = spec.bitset.to_string(); + for (size_t i = 0; i < bitset_str.size(); i += 8) { + size_t end = std::min(i + 8, bitset_str.size()); + std::string chunk = bitset_str.substr(i, end - i); + u8 value = 0; + for (size_t j = 0; j < chunk.size(); ++j) { + if (chunk[j] == '1') { + value |= (1 << j); + } + } + hash = HashCombine(hash, value); + } + + // Hash der Buffer-Spezialisierungen + for (const auto& buffer : spec.buffers) { + hash = HashCombine(hash, buffer.stride); + hash = HashCombine(hash, buffer.is_storage); + hash = HashCombine(hash, buffer.is_formatted); + hash = HashCombine(hash, buffer.swizzle_enable); + + if (buffer.is_formatted) { + hash = HashCombine(hash, buffer.data_format); + hash = HashCombine(hash, buffer.num_format); + hash = HashCombine(hash, buffer.dst_select.r); + hash = HashCombine(hash, buffer.dst_select.g); + hash = HashCombine(hash, buffer.dst_select.b); + hash = HashCombine(hash, buffer.dst_select.a); + hash = HashCombine(hash, static_cast(buffer.num_conversion)); + } + + if (buffer.swizzle_enable) { + hash = HashCombine(hash, buffer.index_stride); + hash = HashCombine(hash, buffer.element_size); + } + } + + // Hash der Bild-Spezialisierungen + for (const auto& image : spec.images) { + hash = HashCombine(hash, static_cast(image.type)); + hash = HashCombine(hash, image.is_integer); + hash = HashCombine(hash, image.is_storage); + hash = HashCombine(hash, image.is_cube); + + if (image.is_storage) { + hash = HashCombine(hash, image.dst_select.r); + hash = HashCombine(hash, image.dst_select.g); + hash = HashCombine(hash, image.dst_select.b); + hash = HashCombine(hash, image.dst_select.a); + } + + hash = HashCombine(hash, static_cast(image.num_conversion)); + } + + // Hash der FMask-Spezialisierungen + for (const auto& fmask : spec.fmasks) { + hash = HashCombine(hash, fmask.width); + hash = HashCombine(hash, fmask.height); + } + + // Hash der Sampler-Spezialisierungen + for (const auto& sampler : spec.samplers) { + hash = HashCombine(hash, sampler.force_unnormalized); + } + + // Hash der Start-Bindings + hash = HashCombine(hash, spec.start.buffer); + hash = HashCombine(hash, spec.start.unified); + hash = HashCombine(hash, spec.start.user_data); + + // Hash vom info pointer + if (spec.info) { + hash = HashCombine(hash, spec.info->pgm_hash); + hash = HashCombine(hash, static_cast(spec.info->stage)); + hash = HashCombine(hash, static_cast(spec.info->l_stage)); + hash = HashCombine(hash, spec.info->has_storage_images); + hash = HashCombine(hash, spec.info->has_discard); + hash = HashCombine(hash, spec.info->has_image_gather); + hash = HashCombine(hash, spec.info->has_image_query); + hash = HashCombine(hash, spec.info->uses_lane_id); + hash = HashCombine(hash, spec.info->uses_group_quad); + hash = HashCombine(hash, spec.info->uses_group_ballot); + hash = HashCombine(hash, spec.info->uses_shared); + hash = HashCombine(hash, spec.info->uses_fp16); + hash = HashCombine(hash, spec.info->uses_fp64); + hash = HashCombine(hash, spec.info->uses_pack_10_11_11); + hash = HashCombine(hash, spec.info->uses_unpack_10_11_11); + hash = HashCombine(hash, spec.info->stores_tess_level_outer); + hash = HashCombine(hash, spec.info->stores_tess_level_inner); + hash = HashCombine(hash, spec.info->translation_failed); + hash = HashCombine(hash, spec.info->has_readconst); + hash = HashCombine(hash, spec.info->mrt_mask); + hash = HashCombine(hash, spec.info->has_fetch_shader); + hash = HashCombine(hash, spec.info->fetch_shader_sgpr_base); + + // Hash der Flags für loads und stores + for (size_t i = 0; i < spec.info->loads.flags.size(); ++i) { + hash = HashCombine(hash, spec.info->loads.flags[i]); + } + + for (size_t i = 0; i < spec.info->stores.flags.size(); ++i) { + hash = HashCombine(hash, spec.info->stores.flags[i]); + } + + // Hash der UserDataMask + hash = HashCombine(hash, spec.info->ud_mask.mask); + + // Hash der uses_patches + hash = HashCombine(hash, spec.info->uses_patches); + } + + return hash; } void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { @@ -29,9 +260,8 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { writeBin(info_serialized, info.ud_mask.mask); // Buffer-Resources - u32 count = static_cast(info.buffers.size()); - writeBin(info_serialized, count); // Buffer Amount - LOG_INFO(Render_Recompiler, "ShaderCache: Buffer count: {}", info.buffers.size()); + u32 bufferCount = static_cast(info.buffers.size()); + writeBin(info_serialized, bufferCount); // Buffer Amount for (const auto& buffer : info.buffers) { writeBin(info_serialized, buffer.sharp_idx); @@ -43,9 +273,9 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { } // Image-Resources - count = static_cast(info.images.size()); - writeBin(info_serialized, count); // Image Amount - LOG_INFO(Render_Recompiler, "ShaderCache: Image count: {}", info.images.size()); + u32 imageCount = static_cast(info.images.size()); + writeBin(info_serialized, imageCount); // Image Amount + for (const auto& image : info.images) { writeBin(info_serialized, image.sharp_idx); writeBin(info_serialized, static_cast(image.is_depth ? 1 : 0)); @@ -55,35 +285,36 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { } // Sampler-Resources - count = static_cast(info.samplers.size()); - writeBin(info_serialized, count); // Sampler Amount - LOG_INFO(Render_Recompiler, "ShaderCache: Sampler count: {}", info.samplers.size()); + u32 samplerCount = static_cast(info.samplers.size()); + writeBin(info_serialized, samplerCount); // Sampler Amount + for (const auto& sampler : info.samplers) { writeBin(info_serialized, sampler.sharp_idx); } // FMask-Resources - count = static_cast(info.fmasks.size()); - writeBin(info_serialized, count); // FMask Amount - LOG_INFO(Render_Recompiler, "ShaderCache: FMask count: {}", info.fmasks.size()); + u32 fmaskCount = static_cast(info.fmasks.size()); + writeBin(info_serialized, fmaskCount); // FMask Amount + for (const auto& fmask : info.fmasks) { writeBin(info_serialized, fmask.sharp_idx); } // GS Copy Data - writeBin(info_serialized, info.gs_copy_data.num_attrs); - u32 mapCount = static_cast(info.gs_copy_data.attr_map.size()); writeBin(info_serialized, mapCount); - for (auto const& [loc, idx] : info.gs_copy_data.attr_map) { + for (auto const& [loc, attr_pair] : info.gs_copy_data.attr_map) { writeBin(info_serialized, loc); - writeBin(info_serialized, idx); + // Das erste Element des Paars ist ein Shader::IR::Attribute, ein Enum + writeBin(info_serialized, static_cast(attr_pair.first)); + // Das zweite Element ist ein u32 + writeBin(info_serialized, attr_pair.second); } // SRT Info u32 srtCount = static_cast(info.srt_info.srt_reservations.size()); - writeBin(info_serialized, count); + writeBin(info_serialized, srtCount); for (const auto& res : info.srt_info.srt_reservations) { writeBin(info_serialized, res.sgpr_base); @@ -91,24 +322,313 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { writeBin(info_serialized, res.num_dwords); } + // Flat UD + + u32 flatCount = static_cast(info.flattened_ud_buf.size()); + writeBin(info_serialized, flatCount); + + for (const auto& flat : info.flattened_ud_buf) { + writeBin(info_serialized, flat); + } + + // Tessellation Data + writeBin(info_serialized, info.tess_consts_ptr_base); + writeBin(info_serialized, info.tess_consts_dword_offset); + + // Flags + writeBin(info_serialized, static_cast(info.has_storage_images ? 1 : 0)); + writeBin(info_serialized, static_cast(info.has_discard ? 1 : 0)); + writeBin(info_serialized, static_cast(info.has_image_gather ? 1 : 0)); + writeBin(info_serialized, static_cast(info.has_image_query ? 1 : 0)); + writeBin(info_serialized, static_cast(info.uses_lane_id ? 1 : 0)); + writeBin(info_serialized, static_cast(info.uses_group_quad ? 1 : 0)); + writeBin(info_serialized, static_cast(info.uses_group_ballot ? 1 : 0)); + writeBin(info_serialized, static_cast(info.uses_shared ? 1 : 0)); + writeBin(info_serialized, static_cast(info.uses_fp16 ? 1 : 0)); + writeBin(info_serialized, static_cast(info.uses_fp64 ? 1 : 0)); + writeBin(info_serialized, static_cast(info.uses_pack_10_11_11 ? 1 : 0)); + writeBin(info_serialized, static_cast(info.uses_unpack_10_11_11 ? 1 : 0)); + writeBin(info_serialized, static_cast(info.stores_tess_level_outer ? 1 : 0)); + writeBin(info_serialized, static_cast(info.stores_tess_level_inner ? 1 : 0)); + writeBin(info_serialized, static_cast(info.translation_failed ? 1 : 0)); + writeBin(info_serialized, static_cast(info.has_readconst ? 1 : 0)); + // MRT Mask writeBin(info_serialized, info.mrt_mask); -} -void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { - readBin(info_serialized, info.mrt_mask); + // Fetch + + writeBin(info_serialized, static_cast(info.has_fetch_shader ? 1 : 0)); + writeBin(info_serialized, info.fetch_shader_sgpr_base); + + // Stage + writeBin(info_serialized, info.stage); + writeBin(info_serialized, info.l_stage); + writeBin(info_serialized, info.pgm_hash); + + // AttributeFlags für loads + u32 loads_size = static_cast(info.loads.flags.size()); + writeBin(info_serialized, loads_size); + for (size_t i = 0; i < info.loads.flags.size(); ++i) { + writeBin(info_serialized, info.loads.flags[i]); + } + + // AttributeFlags für stores + u32 stores_size = static_cast(info.stores.flags.size()); + writeBin(info_serialized, stores_size); + for (size_t i = 0; i < info.stores.flags.size(); ++i) { + writeBin(info_serialized, info.stores.flags[i]); + } } bool CheckShaderCache(std::string shader_id) { - return 0; + // Überprüfen, ob das Verzeichnis existiert + if (!std::filesystem::exists(shader_cache_dir)) { + LOG_INFO(Render_Vulkan, "Shader-Cache-Verzeichnis existiert nicht"); + return false; + } + + // Überprüfen, ob sowohl die SPIR-V-Datei als auch die Ressourcendatei existieren + std::filesystem::path spirv_cache_file_path = shader_cache_dir / (shader_id + ".spv"); + std::filesystem::path resources_file_path = shader_cache_dir / (shader_id + ".resources"); + + if (!std::filesystem::exists(spirv_cache_file_path)) { + LOG_DEBUG(Render_Vulkan, "SPIR-V-Datei nicht gefunden: {}", spirv_cache_file_path.string()); + return false; + } + + if (!std::filesystem::exists(resources_file_path)) { + LOG_DEBUG(Render_Vulkan, "Ressourcendatei nicht gefunden: {}", + resources_file_path.string()); + return false; + } + + // Überprüfen, ob die Dateien lesbar und nicht leer sind + Common::FS::IOFile spirv_file(spirv_cache_file_path, Common::FS::FileAccessMode::Read); + Common::FS::IOFile resources_file(resources_file_path, Common::FS::FileAccessMode::Read); + + const bool spirv_valid = spirv_file.IsOpen() && spirv_file.GetSize() > 0; + const bool resources_valid = resources_file.IsOpen() && resources_file.GetSize() > 0; + + spirv_file.Close(); + resources_file.Close(); + + if (!spirv_valid || !resources_valid) { + LOG_WARNING(Render_Vulkan, "Ungueltige Dateien im Shader-Cache für ID: {}", shader_id); + // Fehlerhafte Dateien entfernen, um zukünftige Probleme zu vermeiden + if (std::filesystem::exists(spirv_cache_file_path)) { + std::filesystem::remove(spirv_cache_file_path); + } + if (std::filesystem::exists(resources_file_path)) { + std::filesystem::remove(resources_file_path); + } + return false; + } + + LOG_INFO(Render_Vulkan, "Shader mit ID {} im Cache gefunden", shader_id); + return true; } -void GetShader(std::string shader_id, Shader::Info& info) { - std::string spirv_cache_filename = shader_id + ".spv "; +void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { + // UD Mask + readBin(info_serialized, info.ud_mask.mask); + + // Buffer-Resources + u32 bufferCount; + readBin(info_serialized, bufferCount); + + info.buffers.clear(); + info.buffers.reserve(bufferCount); + for (u32 i = 0; i < bufferCount; ++i) { + Shader::BufferResource buffer; + readBin(info_serialized, buffer.sharp_idx); + u32 used_types; + readBin(info_serialized, used_types); + buffer.used_types = static_cast(used_types); + u32 buffer_type; + readBin(info_serialized, buffer_type); + buffer.buffer_type = static_cast(buffer_type); + readBin(info_serialized, buffer.instance_attrib); + u8 is_written; + readBin(info_serialized, is_written); + buffer.is_written = (is_written == 1); + u8 is_formatted; + readBin(info_serialized, is_formatted); + buffer.is_formatted = (is_formatted == 1); + info.buffers.push_back(std::move(buffer)); + } + + // Image-Resources + u32 imageCount; + readBin(info_serialized, imageCount); + + info.images.clear(); + info.images.reserve(imageCount); + for (u32 i = 0; i < imageCount; ++i) { + Shader::ImageResource image; + readBin(info_serialized, image.sharp_idx); + u8 is_depth; + readBin(info_serialized, is_depth); + image.is_depth = (is_depth == 1); + u8 is_atomic; + readBin(info_serialized, is_atomic); + image.is_atomic = (is_atomic == 1); + u8 is_array; + readBin(info_serialized, is_array); + image.is_array = (is_array == 1); + u8 is_written; + readBin(info_serialized, is_written); + image.is_written = (is_written == 1); + info.images.push_back(std::move(image)); + } + + // Sampler-Resources + u32 samplerCount; + readBin(info_serialized, samplerCount); + + info.samplers.clear(); + info.samplers.reserve(samplerCount); + for (u32 i = 0; i < samplerCount; ++i) { + Shader::SamplerResource sampler; + readBin(info_serialized, sampler.sharp_idx); + info.samplers.push_back(std::move(sampler)); + } + + // FMask-Resources + u32 fmaskCount; + readBin(info_serialized, fmaskCount); + + info.fmasks.clear(); + info.fmasks.reserve(fmaskCount); + for (u32 i = 0; i < fmaskCount; ++i) { + Shader::FMaskResource fmask; + readBin(info_serialized, fmask.sharp_idx); + info.fmasks.push_back(std::move(fmask)); + } + + // GS Copy Data + u32 mapCount; + readBin(info_serialized, mapCount); + + info.gs_copy_data.attr_map.clear(); + for (u32 i = 0; i < mapCount; ++i) { + u32 loc; + u32 attribute_value; + u32 idx; + readBin(info_serialized, loc); + readBin(info_serialized, attribute_value); + readBin(info_serialized, idx); + + // Umwandeln des numerischen Werts zurück in das Shader::IR::Attribute-Enum + Shader::IR::Attribute attribute = static_cast(attribute_value); + + // Einfügen in die Map mit dem richtigen Paar-Typ + info.gs_copy_data.attr_map.emplace(loc, std::make_pair(attribute, idx)); + } + + // SRT Info + u32 srtCount; + readBin(info_serialized, srtCount); + + info.srt_info.srt_reservations.clear(); + info.srt_info.srt_reservations.resize(srtCount); + for (u32 i = 0; i < srtCount; ++i) { + auto& res = info.srt_info.srt_reservations[i]; + readBin(info_serialized, res.sgpr_base); + readBin(info_serialized, res.dword_offset); + readBin(info_serialized, res.num_dwords); + } + + // Flat UD + u32 flatCount; + readBin(info_serialized, flatCount); + + info.flattened_ud_buf.clear(); + info.flattened_ud_buf.resize(flatCount); + for (u32 i = 0; i < flatCount; ++i) { + readBin(info_serialized, info.flattened_ud_buf[i]); + } + + // Tessellation Data + readBin(info_serialized, info.tess_consts_ptr_base); + readBin(info_serialized, info.tess_consts_dword_offset); + + // Flags + u8 flag_value; + readBin(info_serialized, flag_value); + info.has_storage_images = (flag_value == 1); + readBin(info_serialized, flag_value); + info.has_discard = (flag_value == 1); + readBin(info_serialized, flag_value); + info.has_image_gather = (flag_value == 1); + readBin(info_serialized, flag_value); + info.has_image_query = (flag_value == 1); + readBin(info_serialized, flag_value); + info.uses_lane_id = (flag_value == 1); + readBin(info_serialized, flag_value); + info.uses_group_quad = (flag_value == 1); + readBin(info_serialized, flag_value); + info.uses_group_ballot = (flag_value == 1); + readBin(info_serialized, flag_value); + info.uses_shared = (flag_value == 1); + readBin(info_serialized, flag_value); + info.uses_fp16 = (flag_value == 1); + readBin(info_serialized, flag_value); + info.uses_fp64 = (flag_value == 1); + readBin(info_serialized, flag_value); + info.uses_pack_10_11_11 = (flag_value == 1); + readBin(info_serialized, flag_value); + info.uses_unpack_10_11_11 = (flag_value == 1); + readBin(info_serialized, flag_value); + info.stores_tess_level_outer = (flag_value == 1); + readBin(info_serialized, flag_value); + info.stores_tess_level_inner = (flag_value == 1); + readBin(info_serialized, flag_value); + info.translation_failed = (flag_value == 1); + readBin(info_serialized, flag_value); + info.has_readconst = (flag_value == 1); + + // MRT Mask + readBin(info_serialized, info.mrt_mask); + + // Fetch Shader + u8 has_fetch_shader; + readBin(info_serialized, has_fetch_shader); + info.has_fetch_shader = (has_fetch_shader == 1); + readBin(info_serialized, info.fetch_shader_sgpr_base); + + // Stage + readBin(info_serialized, info.stage); + readBin(info_serialized, info.l_stage); + readBin(info_serialized, info.pgm_hash); + + // AttributeFlags für loads + u32 loads_size; + readBin(info_serialized, loads_size); + for (size_t i = 0; i < loads_size && i < info.loads.flags.size(); ++i) { + readBin(info_serialized, info.loads.flags[i]); + } + + // AttributeFlags für stores + u32 stores_size; + readBin(info_serialized, stores_size); + for (size_t i = 0; i < stores_size && i < info.stores.flags.size(); ++i) { + readBin(info_serialized, info.stores.flags[i]); + } + + // Check if there are any remaining bytes in the stream + if (info_serialized.peek() != EOF) { + LOG_WARNING(Render_Vulkan, "Es sind noch {} Bytes im Stream übrig", + info_serialized.gcount()); + } +} + + +void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) { + std::string spirv_cache_filename = shader_id + ".spv"; std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; Common::FS::IOFile spirv_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Read); - std::vector spv; spv.resize(spirv_cache_file.GetSize() / sizeof(u32)); spirv_cache_file.Read(spv); spirv_cache_file.Close(); @@ -126,7 +646,6 @@ void GetShader(std::string shader_id, Shader::Info& info) { // Verarbeite die gespeicherten Daten std::istringstream combined_stream(std::string(resources_data.begin(), resources_data.end())); - // Deserialisiere info und profile std::istringstream info_stream; info_stream.str(std::string(resources_data.begin(), resources_data.end())); DeserializeInfo(info_stream, info); @@ -146,7 +665,7 @@ void AddShader(std::string shader_id, std::vector spv, std::ostream& info_s Common::FS::IOFile resources_dump_file(resources_dump_file_path, Common::FS::FileAccessMode::Write); - // Die Streams müssen zurückgesetzt werden, bevor wir sie lesen können + // Die Streams müssen zurückgesetzt werden, bevor wir sie lesen können if (std::ostringstream* info_oss = dynamic_cast(&info_serialized)) { std::string info_data = info_oss->str(); resources_dump_file.WriteSpan(std::span(info_data.data(), info_data.size())); diff --git a/src/video_core/renderer_vulkan/shader_cache.h b/src/video_core/renderer_vulkan/shader_cache.h index 2b5c1ae75..d2320e455 100644 --- a/src/video_core/renderer_vulkan/shader_cache.h +++ b/src/video_core/renderer_vulkan/shader_cache.h @@ -5,15 +5,17 @@ #include #include #include "shader_recompiler/info.h" +#include namespace ShaderCache { -std::string CreateShaderID(u64 pgm_hash, size_t perm_idx, std::ostream& info_dump); -void SerializeInfo(std::ostream& info_serialized, Shader::Info info); +u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec); +void SerializeInfo( + std::ostream& info_serialized, Shader::Info info); void DeserializeInfo(std::istream& info_serialized, Shader::Info& info); bool CheckShaderCache(std::string shader_id); -void GetShader(std::string shader_id, Shader::Info& info); +void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv); void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized); } // namespace ShaderCache diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index cb4a6c0ce..4036d3379 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -488,34 +488,36 @@ bool PipelineCache::RefreshComputeKey() { vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::RuntimeInfo& runtime_info, std::span code, size_t perm_idx, - Shader::Backend::Bindings& binding) { + Shader::Backend::Bindings& binding, Shader::StageSpecialization spec) { LOG_INFO(Render_Vulkan, "Compiling {} shader {:#x} {}", info.stage, info.pgm_hash, perm_idx != 0 ? "(permutation)" : ""); + DumpShader(code, info.pgm_hash, info.stage, perm_idx, "bin"); - - - const auto ir_program = Shader::TranslateProgram(code, pools, info, runtime_info, profile); std::string shader_name = GetShaderName(info.stage, info.pgm_hash, perm_idx); - - std::vector spv; - - if (false){ //(::ShaderCache::CheckShaderCache(shader_id)) { - LOG_INFO(Render_Vulkan, "Loaded SPIR-V from cache"); + std::string shader_id = std::to_string(::ShaderCache::CalculateSpecializationHash(spec)); + if (::ShaderCache::CheckShaderCache(shader_id)) { + LOG_INFO(Render_Vulkan, "Loaded shader {} {:#x} {} from cache", info.stage, info.pgm_hash, + perm_idx != 0 ? "(permutation)" : ""); + ::ShaderCache::GetShader(shader_id, info, spv); + info.RefreshFlatBuf(); } else { + LOG_INFO(Render_Vulkan, "Shader {} {:#x} {} not in cache", info.stage, + info.pgm_hash, perm_idx != 0 ? "(permutation)" : ""); + const auto ir_program = Shader::TranslateProgram(code, pools, info, runtime_info, profile); spv = Shader::Backend::SPIRV::EmitSPIRV(profile, runtime_info, ir_program, binding); std::ostringstream info_serialized; ::ShaderCache::SerializeInfo(info_serialized, info); - std::string shader_id = - ::ShaderCache::CreateShaderID(info.pgm_hash, perm_idx, info_serialized); + ::ShaderCache::AddShader(shader_id, spv, info_serialized); LOG_INFO(Render_Vulkan, "Shader ID: {}", shader_id); DumpShader(spv, info.pgm_hash, info.stage, perm_idx, "spv"); - LOG_INFO(Render_Vulkan, "Compiled SPIR-V and stored in cache"); + LOG_INFO(Render_Vulkan, "Compiled shader {} {:#x} {} and saved it to cache", info.stage, info.pgm_hash, + perm_idx != 0 ? "(permutation)" : ""); } vk::ShaderModule module; @@ -543,13 +545,14 @@ PipelineCache::Result PipelineCache::GetProgram(Stage stage, LogicalStage l_stag Shader::ShaderParams params, Shader::Backend::Bindings& binding) { auto runtime_info = BuildRuntimeInfo(stage, l_stage); - auto [it_pgm, new_program] = program_cache.try_emplace(params.hash); + auto [it_pgm, new_program] = program_cache.try_emplace(params.hash); // code in vs if (new_program) { it_pgm.value() = std::make_unique(stage, l_stage, params); auto& program = it_pgm.value(); auto start = binding; - const auto module = CompileModule(program->info, runtime_info, params.code, 0, binding); - const auto spec = Shader::StageSpecialization(program->info, runtime_info, profile, start); + Shader::StageSpecialization spec = + Shader::StageSpecialization(program->info, runtime_info, profile, start); + const auto module = CompileModule(program->info, runtime_info, params.code, 0, binding, spec); program->AddPermut(module, std::move(spec)); return std::make_tuple(&program->info, module, spec.fetch_shader_data, HashCombine(params.hash, 0)); @@ -566,7 +569,7 @@ PipelineCache::Result PipelineCache::GetProgram(Stage stage, LogicalStage l_stag const auto it = std::ranges::find(program->modules, spec, &Program::Module::spec); if (it == program->modules.end()) { auto new_info = Shader::Info(stage, l_stage, params); - module = CompileModule(new_info, runtime_info, params.code, perm_idx, binding); + module = CompileModule(new_info, runtime_info, params.code, perm_idx, binding, spec); program->AddPermut(module, std::move(spec)); } else { info.AddBindings(binding); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index ba3407b48..c20d06a7b 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -82,7 +82,7 @@ private: std::string_view ext); vk::ShaderModule CompileModule(Shader::Info& info, Shader::RuntimeInfo& runtime_info, std::span code, size_t perm_idx, - Shader::Backend::Bindings& binding); + Shader::Backend::Bindings& binding, Shader::StageSpecialization spec); const Shader::RuntimeInfo& BuildRuntimeInfo(Shader::Stage stage, Shader::LogicalStage l_stage); private: From 3e56133cda50cf062203cea15ab69e3df5e940de Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 3 May 2025 16:36:39 +0200 Subject: [PATCH 10/41] now heroes give at least a bit of image --- .../renderer_vulkan/shader_cache.cpp | 110 +++++++++++++++++- 1 file changed, 108 insertions(+), 2 deletions(-) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index b256d2cda..f07c41aa7 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -270,6 +270,25 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { writeBin(info_serialized, buffer.instance_attrib); writeBin(info_serialized, static_cast(buffer.is_written ? 1 : 0)); writeBin(info_serialized, static_cast(buffer.is_formatted ? 1 : 0)); + + writeBin(info_serialized, buffer.inline_cbuf.base_address); + writeBin(info_serialized, buffer.inline_cbuf._padding0); + writeBin(info_serialized, buffer.inline_cbuf.stride); + writeBin(info_serialized, buffer.inline_cbuf.cache_swizzle); + writeBin(info_serialized, buffer.inline_cbuf.swizzle_enable); + writeBin(info_serialized, buffer.inline_cbuf.num_records); + writeBin(info_serialized, buffer.inline_cbuf.dst_sel_x); + writeBin(info_serialized, buffer.inline_cbuf.dst_sel_y); + writeBin(info_serialized, buffer.inline_cbuf.dst_sel_z); + writeBin(info_serialized, buffer.inline_cbuf.dst_sel_w); + writeBin(info_serialized, buffer.inline_cbuf.num_format); + writeBin(info_serialized, buffer.inline_cbuf.data_format); + writeBin(info_serialized, buffer.inline_cbuf.element_size); + writeBin(info_serialized, buffer.inline_cbuf.index_stride); + writeBin(info_serialized, buffer.inline_cbuf.add_tid_enable); + writeBin(info_serialized, buffer.inline_cbuf._padding1); + writeBin(info_serialized, buffer.inline_cbuf.type); + } // Image-Resources @@ -290,6 +309,13 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { for (const auto& sampler : info.samplers) { writeBin(info_serialized, sampler.sharp_idx); + writeBin(info_serialized, sampler.associated_image); + writeBin(info_serialized, sampler.disable_aniso); + + writeBin(info_serialized, sampler.inline_sampler.raw0); + writeBin(info_serialized, sampler.inline_sampler.raw1); + + } // FMask-Resources @@ -455,6 +481,73 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { u8 is_formatted; readBin(info_serialized, is_formatted); buffer.is_formatted = (is_formatted == 1); + + u64 base_address; + readBin(info_serialized, base_address); + buffer.inline_cbuf.base_address = base_address; + + u64 padding0; + readBin(info_serialized, padding0); + buffer.inline_cbuf._padding0 = padding0; + + u64 stride; + readBin(info_serialized, stride); + buffer.inline_cbuf.stride = stride; + + u64 cache_swizzle; + readBin(info_serialized, cache_swizzle); + buffer.inline_cbuf.cache_swizzle = cache_swizzle; + + u64 swizzle_enable; + readBin(info_serialized, swizzle_enable); + buffer.inline_cbuf.swizzle_enable = swizzle_enable; + + readBin(info_serialized, buffer.inline_cbuf.num_records); + + u32 dst_sel_x; + readBin(info_serialized, dst_sel_x); + buffer.inline_cbuf.dst_sel_x = dst_sel_x; + + u32 dst_sel_y; + readBin(info_serialized, dst_sel_y); + buffer.inline_cbuf.dst_sel_y = dst_sel_y; + + u32 dst_sel_z; + readBin(info_serialized, dst_sel_z); + buffer.inline_cbuf.dst_sel_z = dst_sel_z; + + u32 dst_sel_w; + readBin(info_serialized, dst_sel_w); + buffer.inline_cbuf.dst_sel_w = dst_sel_w; + + u32 num_format; + readBin(info_serialized, num_format); + buffer.inline_cbuf.num_format = num_format; + + u32 data_format; + readBin(info_serialized, data_format); + buffer.inline_cbuf.data_format = data_format; + + u32 element_size; + readBin(info_serialized, element_size); + buffer.inline_cbuf.element_size = element_size; + + u32 index_stride; + readBin(info_serialized, index_stride); + buffer.inline_cbuf.index_stride = index_stride; + + u32 add_tid_enable; + readBin(info_serialized, add_tid_enable); + buffer.inline_cbuf.add_tid_enable = add_tid_enable; + + u32 padding1; + readBin(info_serialized, padding1); + buffer.inline_cbuf._padding1 = padding1; + + u32 type; + readBin(info_serialized, type); + buffer.inline_cbuf.type = type; + info.buffers.push_back(std::move(buffer)); } @@ -491,6 +584,19 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { for (u32 i = 0; i < samplerCount; ++i) { Shader::SamplerResource sampler; readBin(info_serialized, sampler.sharp_idx); + + u32 associated_image; + readBin(info_serialized, associated_image); + sampler.associated_image = associated_image; + + u32 disable_aniso; + readBin(info_serialized, disable_aniso); + sampler.disable_aniso = disable_aniso; + + // Inline-Sampler deserialisieren + readBin(info_serialized, sampler.inline_sampler.raw0); + readBin(info_serialized, sampler.inline_sampler.raw1); + info.samplers.push_back(std::move(sampler)); } @@ -605,14 +711,14 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { // AttributeFlags für loads u32 loads_size; readBin(info_serialized, loads_size); - for (size_t i = 0; i < loads_size && i < info.loads.flags.size(); ++i) { + for (size_t i = 0; i < loads_size; ++i) { readBin(info_serialized, info.loads.flags[i]); } // AttributeFlags für stores u32 stores_size; readBin(info_serialized, stores_size); - for (size_t i = 0; i < stores_size && i < info.stores.flags.size(); ++i) { + for (size_t i = 0; i < stores_size; ++i) { readBin(info_serialized, info.stores.flags[i]); } From b9b75cf2c8f017c7d5932c42b1bfb81c4c446ffa Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 3 May 2025 19:45:05 +0200 Subject: [PATCH 11/41] crashes fixed --- src/video_core/renderer_vulkan/shader_cache.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index f07c41aa7..8b12e5209 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -348,6 +348,8 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { writeBin(info_serialized, res.num_dwords); } + writeBin(info_serialized, info.srt_info.flattened_bufsize_dw); + // Flat UD u32 flatCount = static_cast(info.flattened_ud_buf.size()); @@ -645,12 +647,17 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { readBin(info_serialized, res.num_dwords); } + readBin(info_serialized, info.srt_info.flattened_bufsize_dw); + // Flat UD + u32 flatCount; readBin(info_serialized, flatCount); info.flattened_ud_buf.clear(); - info.flattened_ud_buf.resize(flatCount); + u32 required_size = std::max(flatCount, info.srt_info.flattened_bufsize_dw); + info.flattened_ud_buf.resize(required_size); + for (u32 i = 0; i < flatCount; ++i) { readBin(info_serialized, info.flattened_ud_buf[i]); } From bcc65e7dd9b4d43e32e8f8e621724813c832e668 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 3 May 2025 21:49:09 +0200 Subject: [PATCH 12/41] remove include --- src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 4036d3379..7aacc9b9c 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -18,7 +18,6 @@ #include "video_core/renderer_vulkan/vk_presenter.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_shader_util.h" -#include extern std::unique_ptr presenter; From 6c8a792176c951f2685dc5d8fa7600750cd65acf Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 3 May 2025 21:50:44 +0200 Subject: [PATCH 13/41] handle file eof when readBin --- src/common/binary_helper.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/common/binary_helper.h b/src/common/binary_helper.h index de1bb9b78..366b1a13d 100644 --- a/src/common/binary_helper.h +++ b/src/common/binary_helper.h @@ -13,6 +13,10 @@ void writeBin(std::ostream& os, const T& v) { } template -void readBin(std::istream& is, T& v) { +void readBin(std::istream& is, T& v) { + if (is.eof()) { + LOG_WARNING(Render_Recompiler, "BinaryHelper: EOF"); + } + LOG_WARNING is.read(reinterpret_cast(&v), sizeof(T)); } \ No newline at end of file From 019172f740856f0b43c3f8c3684c4505ebeb5d4a Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 3 May 2025 21:52:04 +0200 Subject: [PATCH 14/41] im dumb --- src/common/binary_helper.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/binary_helper.h b/src/common/binary_helper.h index 366b1a13d..dcf5c2dc4 100644 --- a/src/common/binary_helper.h +++ b/src/common/binary_helper.h @@ -17,6 +17,5 @@ void readBin(std::istream& is, T& v) { if (is.eof()) { LOG_WARNING(Render_Recompiler, "BinaryHelper: EOF"); } - LOG_WARNING is.read(reinterpret_cast(&v), sizeof(T)); } \ No newline at end of file From 2a3470804752dd54f4ed18f9a2f277b978e0a51c Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 3 May 2025 22:14:07 +0200 Subject: [PATCH 15/41] more --- .../renderer_vulkan/shader_cache.cpp | 121 +++++++++++------- 1 file changed, 74 insertions(+), 47 deletions(-) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 8b12e5209..ffa8bb476 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -16,6 +16,7 @@ using u32 = uint32_t; namespace ShaderCache { const auto shader_cache_dir = Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache"; +std::unordered_map> g_ud_storage; u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { u64 hash = 0; @@ -407,54 +408,16 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { for (size_t i = 0; i < info.stores.flags.size(); ++i) { writeBin(info_serialized, info.stores.flags[i]); } -} -bool CheckShaderCache(std::string shader_id) { - // Überprüfen, ob das Verzeichnis existiert - if (!std::filesystem::exists(shader_cache_dir)) { - LOG_INFO(Render_Vulkan, "Shader-Cache-Verzeichnis existiert nicht"); - return false; + // UserData + u32 userDataSize = static_cast(info.user_data.size()); + writeBin(info_serialized, userDataSize); + for (size_t i = 0; i < info.user_data.size(); ++i) { + writeBin(info_serialized, info.user_data[i]); } - // Überprüfen, ob sowohl die SPIR-V-Datei als auch die Ressourcendatei existieren - std::filesystem::path spirv_cache_file_path = shader_cache_dir / (shader_id + ".spv"); - std::filesystem::path resources_file_path = shader_cache_dir / (shader_id + ".resources"); - - if (!std::filesystem::exists(spirv_cache_file_path)) { - LOG_DEBUG(Render_Vulkan, "SPIR-V-Datei nicht gefunden: {}", spirv_cache_file_path.string()); - return false; - } - - if (!std::filesystem::exists(resources_file_path)) { - LOG_DEBUG(Render_Vulkan, "Ressourcendatei nicht gefunden: {}", - resources_file_path.string()); - return false; - } - - // Überprüfen, ob die Dateien lesbar und nicht leer sind - Common::FS::IOFile spirv_file(spirv_cache_file_path, Common::FS::FileAccessMode::Read); - Common::FS::IOFile resources_file(resources_file_path, Common::FS::FileAccessMode::Read); - - const bool spirv_valid = spirv_file.IsOpen() && spirv_file.GetSize() > 0; - const bool resources_valid = resources_file.IsOpen() && resources_file.GetSize() > 0; - - spirv_file.Close(); - resources_file.Close(); - - if (!spirv_valid || !resources_valid) { - LOG_WARNING(Render_Vulkan, "Ungueltige Dateien im Shader-Cache für ID: {}", shader_id); - // Fehlerhafte Dateien entfernen, um zukünftige Probleme zu vermeiden - if (std::filesystem::exists(spirv_cache_file_path)) { - std::filesystem::remove(spirv_cache_file_path); - } - if (std::filesystem::exists(resources_file_path)) { - std::filesystem::remove(resources_file_path); - } - return false; - } - - LOG_INFO(Render_Vulkan, "Shader mit ID {} im Cache gefunden", shader_id); - return true; + // Pgm Base + writeBin(info_serialized, info.pgm_base); } void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { @@ -729,13 +692,77 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { readBin(info_serialized, info.stores.flags[i]); } + // UserData + u32 userDataSize; + readBin(info_serialized, userDataSize); + + static std::vector temp_user_data_storage; + temp_user_data_storage.clear(); + temp_user_data_storage.resize(userDataSize); + + for (u32 i = 0; i < userDataSize; ++i) { + readBin(info_serialized, temp_user_data_storage[i]); + } + + info.user_data = std::span(temp_user_data_storage); + + // Pgm Base + readBin(info_serialized, info.pgm_base); + + // Check if there are any remaining bytes in the stream if (info_serialized.peek() != EOF) { - LOG_WARNING(Render_Vulkan, "Es sind noch {} Bytes im Stream übrig", - info_serialized.gcount()); + LOG_WARNING(Render_Vulkan, "Es sind noch Bytes im Stream übrig"); } } +bool CheckShaderCache(std::string shader_id) { + // Überprüfen, ob das Verzeichnis existiert + if (!std::filesystem::exists(shader_cache_dir)) { + LOG_INFO(Render_Vulkan, "Shader-Cache-Verzeichnis existiert nicht"); + return false; + } + + // Überprüfen, ob sowohl die SPIR-V-Datei als auch die Ressourcendatei existieren + std::filesystem::path spirv_cache_file_path = shader_cache_dir / (shader_id + ".spv"); + std::filesystem::path resources_file_path = shader_cache_dir / (shader_id + ".resources"); + + if (!std::filesystem::exists(spirv_cache_file_path)) { + LOG_DEBUG(Render_Vulkan, "SPIR-V-Datei nicht gefunden: {}", spirv_cache_file_path.string()); + return false; + } + + if (!std::filesystem::exists(resources_file_path)) { + LOG_DEBUG(Render_Vulkan, "Ressourcendatei nicht gefunden: {}", + resources_file_path.string()); + return false; + } + + // Überprüfen, ob die Dateien lesbar und nicht leer sind + Common::FS::IOFile spirv_file(spirv_cache_file_path, Common::FS::FileAccessMode::Read); + Common::FS::IOFile resources_file(resources_file_path, Common::FS::FileAccessMode::Read); + + const bool spirv_valid = spirv_file.IsOpen() && spirv_file.GetSize() > 0; + const bool resources_valid = resources_file.IsOpen() && resources_file.GetSize() > 0; + + spirv_file.Close(); + resources_file.Close(); + + if (!spirv_valid || !resources_valid) { + LOG_WARNING(Render_Vulkan, "Ungueltige Dateien im Shader-Cache für ID: {}", shader_id); + // Fehlerhafte Dateien entfernen, um zukünftige Probleme zu vermeiden + if (std::filesystem::exists(spirv_cache_file_path)) { + std::filesystem::remove(spirv_cache_file_path); + } + if (std::filesystem::exists(resources_file_path)) { + std::filesystem::remove(resources_file_path); + } + return false; + } + + LOG_INFO(Render_Vulkan, "Shader mit ID {} im Cache gefunden", shader_id); + return true; +} void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) { std::string spirv_cache_filename = shader_id + ".spv"; From 84ee3f9425c946d8bf380c354814808800d88276 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 10 May 2025 22:05:01 +0200 Subject: [PATCH 16/41] more --- .../renderer_vulkan/shader_cache.cpp | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index ffa8bb476..28df9d209 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -1,6 +1,12 @@ #include #include #include +#ifdef _WIN32 +#include +#else +#include +#include +#endif #include "common/hash.h" #include "common/path_util.h" #include "common/io_file.h" @@ -350,7 +356,33 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { } writeBin(info_serialized, info.srt_info.flattened_bufsize_dw); + bool has_walker_func = (info.srt_info.walker_func != nullptr); + writeBin(info_serialized, static_cast(has_walker_func ? 1 : 0)); + if (has_walker_func) { + // Größe des JIT-Codes ermitteln + const u8* walker_start = reinterpret_cast(info.srt_info.walker_func); + + // Wir müssen die Größe des generierten Codes bestimmen + // Dies kann aus der Xbyak::CodeGenerator Instanz extrahiert werden + // Alternativ können wir die Distanz zum nächsten Ret-Befehl berechnen + size_t walker_size = 0; + const u8* ptr = walker_start; + const u32 MAX_CODE_SIZE = 4096; // Sicherheitsbegrenzung + + // Suche nach Ret-Befehl (C3 in x86/x64) + for (walker_size = 0; walker_size < MAX_CODE_SIZE; walker_size++) { + // Einfacher Ret-Befehl (C3) + if (ptr[walker_size] == 0xC3) { + walker_size++; // Ret einschließen + break; + } + } + + // Speichere Größe und JIT-Code + writeBin(info_serialized, static_cast(walker_size)); + info_serialized.write(reinterpret_cast(walker_start), walker_size); + } // Flat UD u32 flatCount = static_cast(info.flattened_ud_buf.size()); @@ -611,7 +643,36 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { } readBin(info_serialized, info.srt_info.flattened_bufsize_dw); + // Laden des walker_func JIT-Codes + u8 has_walker_func; + readBin(info_serialized, has_walker_func); + if (has_walker_func == 1) { + // Größe des JIT-Codes lesen + u32 walker_size; + readBin(info_serialized, walker_size); + + // Speicher für ausführbaren Code allokieren + void* code_memory = nullptr; +#ifdef _WIN32 + code_memory = + VirtualAlloc(nullptr, walker_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); +#else + code_memory = mmap(nullptr, walker_size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#endif + + if (!code_memory) { + LOG_ERROR(Render_Vulkan, "Konnte keinen ausführbaren Speicher für JIT-Code allokieren"); + return; + } + + // JIT-Code laden + info_serialized.read(reinterpret_cast(code_memory), walker_size); + + // JIT-Funktion zuweisen + info.srt_info.walker_func = reinterpret_cast(code_memory); + } // Flat UD u32 flatCount; From 742b3ced660a34ce3206284224dc2cd220a1b8fe Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Wed, 18 Jun 2025 12:39:50 +0200 Subject: [PATCH 17/41] add CMakePresets.json --- CMakePresets.json | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 CMakePresets.json diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 000000000..6a446b46d --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,47 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 24, + "patch": 0 + }, + "configurePresets": [ + { + "name": "x64-Clang-Debug", + "displayName": "Clang x64 Debug", + "generator": "Ninja", + "binaryDir": "${sourceDir}/Build/x64-Clang-Debug", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl", + "CMAKE_CXX_COMPILER": "clang-cl", + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-Debug" + + } + }, + { + "name": "x64-Clang-Release", + "displayName": "Clang x64 Release", + "generator": "Ninja", + "binaryDir": "${sourceDir}/Build/x64-Clang-Release", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl", + "CMAKE_CXX_COMPILER": "clang-cl", + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-Release" + } + }, + { + "name": "x64-Clang-RelWithDebInfo", + "displayName": "Clang x64 RelWithDebInfo", + "generator": "Ninja", + "binaryDir": "${sourceDir}/Build/x64-Clang-RelWithDebInfo", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl", + "CMAKE_CXX_COMPILER": "clang-cl", + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-RelWithDebInfo" + } + } + ] +} From dd0365ffc75aa39cacda485ec580f8b70846e733 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Wed, 18 Jun 2025 13:41:26 +0200 Subject: [PATCH 18/41] Update REUSE.toml --- REUSE.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/REUSE.toml b/REUSE.toml index 662987611..5f5229e4b 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -5,6 +5,7 @@ path = [ "REUSE.toml", "crowdin.yml", "CMakeSettings.json", + "CMakePresets.json", ".github/FUNDING.yml", ".github/shadps4.png", ".github/workflows/scripts/update_translation.sh", From ddb11feeb7cefb392b18acd12b3f319146fea9da Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Thu, 19 Jun 2025 20:51:34 +0200 Subject: [PATCH 19/41] fix vs --- CMakePresets.json | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 6a446b46d..c4d60b04e 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,5 +1,5 @@ { - "version": 3, + "version": 5, "cmakeMinimumRequired": { "major": 3, "minor": 24, @@ -16,7 +16,11 @@ "CMAKE_CXX_COMPILER": "clang-cl", "CMAKE_BUILD_TYPE": "Debug", "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-Debug" - + }, + "vendor": { + "microsoft.com/VisualStudioSettings/CMake/1.0": { + "intelliSenseMode": "windows-clang-x64" + } } }, { @@ -29,6 +33,11 @@ "CMAKE_CXX_COMPILER": "clang-cl", "CMAKE_BUILD_TYPE": "Release", "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-Release" + }, + "vendor": { + "microsoft.com/VisualStudioSettings/CMake/1.0": { + "intelliSenseMode": "windows-clang-x64" + } } }, { @@ -41,6 +50,11 @@ "CMAKE_CXX_COMPILER": "clang-cl", "CMAKE_BUILD_TYPE": "RelWithDebInfo", "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-RelWithDebInfo" + }, + "vendor": { + "microsoft.com/VisualStudioSettings/CMake/1.0": { + "intelliSenseMode": "windows-clang-x64" + } } } ] From 8a35cc992016b54be2b806d361ecc5cd87d19b33 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 21 Jun 2025 21:00:21 +0200 Subject: [PATCH 20/41] impl --- CMakeLists.txt | 2 ++ CMakePresets.json | 54 ++++++++++++++++++++++++++++++++++++++++++++++ cmake/FindQt.cmake | 12 +++++++++++ 3 files changed, 68 insertions(+) create mode 100644 cmake/FindQt.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d8fe5f68b..80f326432 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -214,6 +214,8 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_ message("end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}") +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/findQt.cmake") + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") find_package(Boost 1.84.0 CONFIG) find_package(FFmpeg 5.1.2 MODULE) diff --git a/CMakePresets.json b/CMakePresets.json index c4d60b04e..454b4e767 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -23,6 +23,24 @@ } } }, + { + "name": "x64-Clang-Debug-Qt", + "displayName": "Clang x64 Debug with Qt", + "generator": "Ninja", + "binaryDir": "${sourceDir}/Build/x64-Clang-Debug-Qt", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl", + "CMAKE_CXX_COMPILER": "clang-cl", + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-Debug-Qt", + "ENABLE_QT_GUI": "ON" + }, + "vendor": { + "microsoft.com/VisualStudioSettings/CMake/1.0": { + "intelliSenseMode": "windows-clang-x64" + } + } + }, { "name": "x64-Clang-Release", "displayName": "Clang x64 Release", @@ -40,6 +58,24 @@ } } }, + { + "name": "x64-Clang-Release-Qt", + "displayName": "Clang x64 Release with Qt", + "generator": "Ninja", + "binaryDir": "${sourceDir}/Build/x64-Clang-Release-Qt", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl", + "CMAKE_CXX_COMPILER": "clang-cl", + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-Release-Qt", + "ENABLE_QT_GUI": "ON" + }, + "vendor": { + "microsoft.com/VisualStudioSettings/CMake/1.0": { + "intelliSenseMode": "windows-clang-x64" + } + } + }, { "name": "x64-Clang-RelWithDebInfo", "displayName": "Clang x64 RelWithDebInfo", @@ -56,6 +92,24 @@ "intelliSenseMode": "windows-clang-x64" } } + }, + { + "name": "x64-Clang-RelWithDebInfo-Qt", + "displayName": "Clang x64 RelWithDebInfo with Qt", + "generator": "Ninja", + "binaryDir": "${sourceDir}/Build/x64-Clang-RelWithDebInfo-Qt", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl", + "CMAKE_CXX_COMPILER": "clang-cl", + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-RelWithDebInfo-Qt", + "ENABLE_QT_GUI": "ON" + }, + "vendor": { + "microsoft.com/VisualStudioSettings/CMake/1.0": { + "intelliSenseMode": "windows-clang-x64" + } + } } ] } diff --git a/cmake/FindQt.cmake b/cmake/FindQt.cmake new file mode 100644 index 000000000..bff3b6a51 --- /dev/null +++ b/cmake/FindQt.cmake @@ -0,0 +1,12 @@ +if(WIN32 AND NOT CMAKE_PREFIX_PATH) + file(GLOB QT_KITS LIST_DIRECTORIES true "C:/Qt/*/msvc*") + list(SORT QT_KITS COMPARE NATURAL) + list(REVERSE QT_KITS) + list(GET QT_KITS 0 QT_PREFIX) + if(QT_PREFIX) + set(CMAKE_PREFIX_PATH "${QT_PREFIX}" CACHE PATH "Qt prefix auto‑detected" FORCE) + message(STATUS "Auto-detected Qt prefix: ${QT_PREFIX}") + else() + message(WARNING "findQt.cmake: no Qt‑Directory found in C:/Qt – please set CMAKE_PREFIX_PATH manually") + endif() +endif() From e4f19145d6ff111f48a26b42fa973bc6472bae83 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 21 Jun 2025 21:33:56 +0200 Subject: [PATCH 21/41] adjust CMakeSettings.json --- CMakeSettings.json | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CMakeSettings.json b/CMakeSettings.json index bb522fcfc..e1ed36887 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -12,6 +12,18 @@ "inheritEnvironments": [ "clang_cl_x64_x64" ], "intelliSenseMode": "windows-clang-x64" }, + { + "name": "x64-Clang-Release-Qt", + "generator": "Ninja", + "configurationType": "Release", + "buildRoot": "${projectDir}\\Build\\${name}", + "installRoot": "${projectDir}\\Install\\${name}", + "cmakeCommandArgs": "-DENABLE_QT_GUI=ON", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "clang_cl_x64_x64" ], + "intelliSenseMode": "windows-clang-x64" + }, { "name": "x64-Clang-Debug", "generator": "Ninja", @@ -24,6 +36,18 @@ "inheritEnvironments": [ "clang_cl_x64_x64" ], "intelliSenseMode": "windows-clang-x64" }, + { + "name": "x64-Clang-Debug-Qt", + "generator": "Ninja", + "configurationType": "Debug", + "buildRoot": "${projectDir}\\Build\\${name}", + "installRoot": "${projectDir}\\Install\\${name}", + "cmakeCommandArgs": "-DENABLE_QT_GUI=ON", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "clang_cl_x64_x64" ], + "intelliSenseMode": "windows-clang-x64" + }, { "name": "x64-Clang-RelWithDebInfo", "generator": "Ninja", @@ -35,6 +59,18 @@ "ctestCommandArgs": "", "inheritEnvironments": [ "clang_cl_x64_x64" ], "intelliSenseMode": "windows-clang-x64" + }, + { + "name": "x64-Clang-RelWithDebInfo-Qt", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "buildRoot": "${projectDir}\\Build\\${name}", + "installRoot": "${projectDir}\\Install\\${name}", + "cmakeCommandArgs": "-DENABLE_QT_GUI=ON", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "clang_cl_x64_x64" ], + "intelliSenseMode": "windows-clang-x64" } ] } \ No newline at end of file From bee3f1075d20071d5a36a3ce64894d560f44b8bf Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 21 Jun 2025 21:36:12 +0200 Subject: [PATCH 22/41] add FindQt.cmake to reuse --- cmake/FindQt.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/FindQt.cmake b/cmake/FindQt.cmake index bff3b6a51..d568c55ad 100644 --- a/cmake/FindQt.cmake +++ b/cmake/FindQt.cmake @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + if(WIN32 AND NOT CMAKE_PREFIX_PATH) file(GLOB QT_KITS LIST_DIRECTORIES true "C:/Qt/*/msvc*") list(SORT QT_KITS COMPARE NATURAL) From 321ed8b26768721c148264fc9f7beae3a775c69c Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sun, 22 Jun 2025 19:23:54 +0200 Subject: [PATCH 23/41] rename cmake file, add check before running cmake and add inheritation to presets --- CMakeLists.txt | 4 +- CMakePresets.json | 75 ++++++++++---------------------- cmake/DetectQtInstallation.cmake | 14 ++++++ cmake/FindQt.cmake | 15 ------- 4 files changed, 40 insertions(+), 68 deletions(-) create mode 100644 cmake/DetectQtInstallation.cmake delete mode 100644 cmake/FindQt.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 80f326432..8d50e3bf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -214,7 +214,9 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_ message("end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}") -include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/findQt.cmake") +if(WIN32 AND ENABLE_QT_GUI AND NOT CMAKE_PREFIX_PATH) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/DetectQtInstallation.cmake") +endif () list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") find_package(Boost 1.84.0 CONFIG) diff --git a/CMakePresets.json b/CMakePresets.json index 454b4e767..2aeb0f064 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -6,6 +6,22 @@ "patch": 0 }, "configurePresets": [ + { + "name": "x64-Clang-Base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/Build/${presetName}", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl", + "CMAKE_CXX_COMPILER": "clang-cl", + "CMAKE_INSTALL_PREFIX": "${sourceDir}/Build/${presetName}" + }, + "vendor": { + "microsoft.com/VisualStudioSettings/CMake/1.0": { + "intelliSenseMode": "windows-clang-x64" + } + } + }, { "name": "x64-Clang-Debug", "displayName": "Clang x64 Debug", @@ -26,89 +42,44 @@ { "name": "x64-Clang-Debug-Qt", "displayName": "Clang x64 Debug with Qt", - "generator": "Ninja", - "binaryDir": "${sourceDir}/Build/x64-Clang-Debug-Qt", + "inherits": ["x64-Clang-Base"], "cacheVariables": { - "CMAKE_C_COMPILER": "clang-cl", - "CMAKE_CXX_COMPILER": "clang-cl", "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-Debug-Qt", "ENABLE_QT_GUI": "ON" - }, - "vendor": { - "microsoft.com/VisualStudioSettings/CMake/1.0": { - "intelliSenseMode": "windows-clang-x64" - } } }, { "name": "x64-Clang-Release", "displayName": "Clang x64 Release", - "generator": "Ninja", - "binaryDir": "${sourceDir}/Build/x64-Clang-Release", + "inherits": ["x64-Clang-Base"], "cacheVariables": { - "CMAKE_C_COMPILER": "clang-cl", - "CMAKE_CXX_COMPILER": "clang-cl", - "CMAKE_BUILD_TYPE": "Release", - "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-Release" - }, - "vendor": { - "microsoft.com/VisualStudioSettings/CMake/1.0": { - "intelliSenseMode": "windows-clang-x64" - } + "CMAKE_BUILD_TYPE": "Release" } }, { "name": "x64-Clang-Release-Qt", "displayName": "Clang x64 Release with Qt", - "generator": "Ninja", - "binaryDir": "${sourceDir}/Build/x64-Clang-Release-Qt", + "inherits": ["x64-Clang-Base"], "cacheVariables": { - "CMAKE_C_COMPILER": "clang-cl", - "CMAKE_CXX_COMPILER": "clang-cl", "CMAKE_BUILD_TYPE": "Release", - "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-Release-Qt", "ENABLE_QT_GUI": "ON" - }, - "vendor": { - "microsoft.com/VisualStudioSettings/CMake/1.0": { - "intelliSenseMode": "windows-clang-x64" - } } }, { "name": "x64-Clang-RelWithDebInfo", "displayName": "Clang x64 RelWithDebInfo", - "generator": "Ninja", - "binaryDir": "${sourceDir}/Build/x64-Clang-RelWithDebInfo", + "inherits": ["x64-Clang-Base"], "cacheVariables": { - "CMAKE_C_COMPILER": "clang-cl", - "CMAKE_CXX_COMPILER": "clang-cl", - "CMAKE_BUILD_TYPE": "RelWithDebInfo", - "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-RelWithDebInfo" - }, - "vendor": { - "microsoft.com/VisualStudioSettings/CMake/1.0": { - "intelliSenseMode": "windows-clang-x64" - } + "CMAKE_BUILD_TYPE": "RelWithDebInfo" } }, { "name": "x64-Clang-RelWithDebInfo-Qt", "displayName": "Clang x64 RelWithDebInfo with Qt", - "generator": "Ninja", - "binaryDir": "${sourceDir}/Build/x64-Clang-RelWithDebInfo-Qt", + "inherits": ["x64-Clang-Base"], "cacheVariables": { - "CMAKE_C_COMPILER": "clang-cl", - "CMAKE_CXX_COMPILER": "clang-cl", "CMAKE_BUILD_TYPE": "RelWithDebInfo", - "CMAKE_INSTALL_PREFIX": "${sourceDir}/Install/x64-Clang-RelWithDebInfo-Qt", "ENABLE_QT_GUI": "ON" - }, - "vendor": { - "microsoft.com/VisualStudioSettings/CMake/1.0": { - "intelliSenseMode": "windows-clang-x64" - } } } ] diff --git a/cmake/DetectQtInstallation.cmake b/cmake/DetectQtInstallation.cmake new file mode 100644 index 000000000..0f1dd6a8b --- /dev/null +++ b/cmake/DetectQtInstallation.cmake @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +file(GLOB QT_KITS LIST_DIRECTORIES true "C:/Qt/*/msvc*") +list(SORT QT_KITS COMPARE NATURAL) +list(REVERSE QT_KITS) +list(GET QT_KITS 0 QT_PREFIX) +if(QT_PREFIX) + set(CMAKE_PREFIX_PATH "${QT_PREFIX}" CACHE PATH "Qt prefix auto‑detected" FORCE) + message(STATUS "Auto-detected Qt prefix: ${QT_PREFIX}") +else() + message(WARNING "findQt.cmake: no Qt‑Directory found in C:/Qt – please set CMAKE_PREFIX_PATH manually") +endif() + diff --git a/cmake/FindQt.cmake b/cmake/FindQt.cmake deleted file mode 100644 index d568c55ad..000000000 --- a/cmake/FindQt.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project -# SPDX-License-Identifier: GPL-2.0-or-later - -if(WIN32 AND NOT CMAKE_PREFIX_PATH) - file(GLOB QT_KITS LIST_DIRECTORIES true "C:/Qt/*/msvc*") - list(SORT QT_KITS COMPARE NATURAL) - list(REVERSE QT_KITS) - list(GET QT_KITS 0 QT_PREFIX) - if(QT_PREFIX) - set(CMAKE_PREFIX_PATH "${QT_PREFIX}" CACHE PATH "Qt prefix auto‑detected" FORCE) - message(STATUS "Auto-detected Qt prefix: ${QT_PREFIX}") - else() - message(WARNING "findQt.cmake: no Qt‑Directory found in C:/Qt – please set CMAKE_PREFIX_PATH manually") - endif() -endif() From 06cae185c9a2aae7dd361353583edfe2f16f151f Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sun, 22 Jun 2025 19:36:19 +0200 Subject: [PATCH 24/41] add error check in cmake --- cmake/DetectQtInstallation.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/DetectQtInstallation.cmake b/cmake/DetectQtInstallation.cmake index 0f1dd6a8b..d482ed9c7 100644 --- a/cmake/DetectQtInstallation.cmake +++ b/cmake/DetectQtInstallation.cmake @@ -4,8 +4,8 @@ file(GLOB QT_KITS LIST_DIRECTORIES true "C:/Qt/*/msvc*") list(SORT QT_KITS COMPARE NATURAL) list(REVERSE QT_KITS) -list(GET QT_KITS 0 QT_PREFIX) -if(QT_PREFIX) +if(QT_KITS) + list(GET QT_KITS 0 QT_PREFIX) set(CMAKE_PREFIX_PATH "${QT_PREFIX}" CACHE PATH "Qt prefix auto‑detected" FORCE) message(STATUS "Auto-detected Qt prefix: ${QT_PREFIX}") else() From 85b42b6cf85e132c1fddbf6ab8eaaf8458519ae2 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Tue, 24 Jun 2025 19:03:28 +0200 Subject: [PATCH 25/41] remove german comments --- .../renderer_vulkan/shader_cache.cpp | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 28df9d209..0ae720413 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -27,9 +27,6 @@ std::unordered_map> g_ud_storage; u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { u64 hash = 0; - // Start mit dem Hash der RuntimeInfo - // Die RuntimeInfo enthält verschiedene Unions, daher müssen wir basierend auf dem Stage-Typ - // hashen const auto& runtime_info = spec.runtime_info; hash = HashCombine(hash, static_cast(runtime_info.stage)); hash = HashCombine(hash, runtime_info.num_user_data); @@ -38,7 +35,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { hash = HashCombine(hash, static_cast(runtime_info.fp_denorm_mode32)); hash = HashCombine(hash, static_cast(runtime_info.fp_round_mode32)); - // Abhängig vom Stage-Typ die spezifischen RuntimeInfo-Felder hashen switch (runtime_info.stage) { case Shader::Stage::Local: hash = HashCombine(hash, runtime_info.ls_info.ls_stride); @@ -49,7 +45,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { break; case Shader::Stage::Vertex: hash = HashCombine(hash, runtime_info.vs_info.num_outputs); - // Hash der Output-Maps for (size_t i = 0; i < runtime_info.vs_info.num_outputs && i < runtime_info.vs_info.outputs.size(); ++i) { const auto& output_map = runtime_info.vs_info.outputs[i]; @@ -78,7 +73,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { hash = HashCombine(hash, runtime_info.gs_info.in_vertex_data_size); hash = HashCombine(hash, runtime_info.gs_info.out_vertex_data_size); hash = HashCombine(hash, static_cast(runtime_info.gs_info.in_primitive)); - // Hash der Output-Primitive-Types für alle Streams for (const auto& out_prim : runtime_info.gs_info.out_primitive) { hash = HashCombine(hash, static_cast(out_prim)); } @@ -89,7 +83,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { hash = HashCombine(hash, runtime_info.fs_info.addr_flags.raw); hash = HashCombine(hash, runtime_info.fs_info.num_inputs); - // Hash der PS-Inputs for (u32 i = 0; i < runtime_info.fs_info.num_inputs && i < runtime_info.fs_info.inputs.size(); ++i) { const auto& input = runtime_info.fs_info.inputs[i]; @@ -99,7 +92,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { hash = HashCombine(hash, input.default_value); } - // Hash der ColorBuffers for (const auto& color_buffer : runtime_info.fs_info.color_buffers) { hash = HashCombine(hash, static_cast(color_buffer.num_format)); hash = HashCombine(hash, static_cast(color_buffer.num_conversion)); @@ -120,14 +112,12 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { break; } - // Hash des FetchShader-Daten if (spec.fetch_shader_data) { const auto& fetch_shader = *spec.fetch_shader_data; hash = HashCombine(hash, fetch_shader.size); hash = HashCombine(hash, static_cast(fetch_shader.vertex_offset_sgpr)); hash = HashCombine(hash, static_cast(fetch_shader.instance_offset_sgpr)); - // Hash der Attribute for (const auto& attr : fetch_shader.attributes) { hash = HashCombine(hash, static_cast(attr.semantic)); hash = HashCombine(hash, static_cast(attr.dest_vgpr)); @@ -138,7 +128,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { } } - // Hash der VS-Attribut-Spezialisierungen for (const auto& vs_attrib : spec.vs_attribs) { hash = HashCombine(hash, vs_attrib.num_components); hash = HashCombine(hash, static_cast(vs_attrib.num_class)); @@ -148,7 +137,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { hash = HashCombine(hash, vs_attrib.dst_select.a); } - // Hash des Bitsets const std::string bitset_str = spec.bitset.to_string(); for (size_t i = 0; i < bitset_str.size(); i += 8) { size_t end = std::min(i + 8, bitset_str.size()); @@ -162,7 +150,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { hash = HashCombine(hash, value); } - // Hash der Buffer-Spezialisierungen for (const auto& buffer : spec.buffers) { hash = HashCombine(hash, buffer.stride); hash = HashCombine(hash, buffer.is_storage); @@ -185,7 +172,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { } } - // Hash der Bild-Spezialisierungen for (const auto& image : spec.images) { hash = HashCombine(hash, static_cast(image.type)); hash = HashCombine(hash, image.is_integer); @@ -202,23 +188,19 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { hash = HashCombine(hash, static_cast(image.num_conversion)); } - // Hash der FMask-Spezialisierungen for (const auto& fmask : spec.fmasks) { hash = HashCombine(hash, fmask.width); hash = HashCombine(hash, fmask.height); } - // Hash der Sampler-Spezialisierungen for (const auto& sampler : spec.samplers) { hash = HashCombine(hash, sampler.force_unnormalized); } - // Hash der Start-Bindings hash = HashCombine(hash, spec.start.buffer); hash = HashCombine(hash, spec.start.unified); hash = HashCombine(hash, spec.start.user_data); - // Hash vom info pointer if (spec.info) { hash = HashCombine(hash, spec.info->pgm_hash); hash = HashCombine(hash, static_cast(spec.info->stage)); @@ -243,7 +225,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { hash = HashCombine(hash, spec.info->has_fetch_shader); hash = HashCombine(hash, spec.info->fetch_shader_sgpr_base); - // Hash der Flags für loads und stores for (size_t i = 0; i < spec.info->loads.flags.size(); ++i) { hash = HashCombine(hash, spec.info->loads.flags[i]); } @@ -252,10 +233,8 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { hash = HashCombine(hash, spec.info->stores.flags[i]); } - // Hash der UserDataMask hash = HashCombine(hash, spec.info->ud_mask.mask); - // Hash der uses_patches hash = HashCombine(hash, spec.info->uses_patches); } @@ -263,10 +242,8 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { } void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { - // UD Mask writeBin(info_serialized, info.ud_mask.mask); - // Buffer-Resources u32 bufferCount = static_cast(info.buffers.size()); writeBin(info_serialized, bufferCount); // Buffer Amount From 469c8fc241f915f3a5d70e8a1d9a4226167cf877 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Tue, 24 Jun 2025 20:09:59 +0200 Subject: [PATCH 26/41] many things --- .../renderer_vulkan/shader_cache.cpp | 158 ++++++------------ 1 file changed, 50 insertions(+), 108 deletions(-) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 0ae720413..542f12433 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -212,7 +212,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { hash = HashCombine(hash, spec.info->uses_lane_id); hash = HashCombine(hash, spec.info->uses_group_quad); hash = HashCombine(hash, spec.info->uses_group_ballot); - hash = HashCombine(hash, spec.info->uses_shared); hash = HashCombine(hash, spec.info->uses_fp16); hash = HashCombine(hash, spec.info->uses_fp64); hash = HashCombine(hash, spec.info->uses_pack_10_11_11); @@ -220,7 +219,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { hash = HashCombine(hash, spec.info->stores_tess_level_outer); hash = HashCombine(hash, spec.info->stores_tess_level_inner); hash = HashCombine(hash, spec.info->translation_failed); - hash = HashCombine(hash, spec.info->has_readconst); hash = HashCombine(hash, spec.info->mrt_mask); hash = HashCombine(hash, spec.info->has_fetch_shader); hash = HashCombine(hash, spec.info->fetch_shader_sgpr_base); @@ -292,14 +290,29 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { writeBin(info_serialized, samplerCount); // Sampler Amount for (const auto& sampler : info.samplers) { - writeBin(info_serialized, sampler.sharp_idx); - writeBin(info_serialized, sampler.associated_image); - writeBin(info_serialized, sampler.disable_aniso); + if (std::holds_alternative(sampler.sampler)) + { + std::uint8_t tag = 0; + writeBin(info_serialized, tag); - writeBin(info_serialized, sampler.inline_sampler.raw0); - writeBin(info_serialized, sampler.inline_sampler.raw1); + u32 sharp_idx = std::get(sampler.sampler); + writeBin(info_serialized, sharp_idx); + } + else + { + std::uint8_t tag = 1; + writeBin(info_serialized, tag); + const AmdGpu::Sampler& hw_sampler = + std::get(sampler.sampler); + writeBin(info_serialized, hw_sampler); + } + std::uint8_t packed = + static_cast((sampler.disable_aniso & 0x1) << 4) | + static_cast(sampler.associated_image & 0xF); + + writeBin(info_serialized, packed); } // FMask-Resources @@ -316,9 +329,7 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { for (auto const& [loc, attr_pair] : info.gs_copy_data.attr_map) { writeBin(info_serialized, loc); - // Das erste Element des Paars ist ein Shader::IR::Attribute, ein Enum writeBin(info_serialized, static_cast(attr_pair.first)); - // Das zweite Element ist ein u32 writeBin(info_serialized, attr_pair.second); } @@ -333,33 +344,7 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { } writeBin(info_serialized, info.srt_info.flattened_bufsize_dw); - bool has_walker_func = (info.srt_info.walker_func != nullptr); - writeBin(info_serialized, static_cast(has_walker_func ? 1 : 0)); - if (has_walker_func) { - // Größe des JIT-Codes ermitteln - const u8* walker_start = reinterpret_cast(info.srt_info.walker_func); - - // Wir müssen die Größe des generierten Codes bestimmen - // Dies kann aus der Xbyak::CodeGenerator Instanz extrahiert werden - // Alternativ können wir die Distanz zum nächsten Ret-Befehl berechnen - size_t walker_size = 0; - const u8* ptr = walker_start; - const u32 MAX_CODE_SIZE = 4096; // Sicherheitsbegrenzung - - // Suche nach Ret-Befehl (C3 in x86/x64) - for (walker_size = 0; walker_size < MAX_CODE_SIZE; walker_size++) { - // Einfacher Ret-Befehl (C3) - if (ptr[walker_size] == 0xC3) { - walker_size++; // Ret einschließen - break; - } - } - - // Speichere Größe und JIT-Code - writeBin(info_serialized, static_cast(walker_size)); - info_serialized.write(reinterpret_cast(walker_start), walker_size); - } // Flat UD u32 flatCount = static_cast(info.flattened_ud_buf.size()); @@ -381,7 +366,6 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { writeBin(info_serialized, static_cast(info.uses_lane_id ? 1 : 0)); writeBin(info_serialized, static_cast(info.uses_group_quad ? 1 : 0)); writeBin(info_serialized, static_cast(info.uses_group_ballot ? 1 : 0)); - writeBin(info_serialized, static_cast(info.uses_shared ? 1 : 0)); writeBin(info_serialized, static_cast(info.uses_fp16 ? 1 : 0)); writeBin(info_serialized, static_cast(info.uses_fp64 ? 1 : 0)); writeBin(info_serialized, static_cast(info.uses_pack_10_11_11 ? 1 : 0)); @@ -389,7 +373,6 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { writeBin(info_serialized, static_cast(info.stores_tess_level_outer ? 1 : 0)); writeBin(info_serialized, static_cast(info.stores_tess_level_inner ? 1 : 0)); writeBin(info_serialized, static_cast(info.translation_failed ? 1 : 0)); - writeBin(info_serialized, static_cast(info.has_readconst ? 1 : 0)); // MRT Mask writeBin(info_serialized, info.mrt_mask); @@ -404,14 +387,14 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { writeBin(info_serialized, info.l_stage); writeBin(info_serialized, info.pgm_hash); - // AttributeFlags für loads + // AttributeFlags for loads u32 loads_size = static_cast(info.loads.flags.size()); writeBin(info_serialized, loads_size); for (size_t i = 0; i < info.loads.flags.size(); ++i) { writeBin(info_serialized, info.loads.flags[i]); } - // AttributeFlags für stores + // AttributeFlags for stores u32 stores_size = static_cast(info.stores.flags.size()); writeBin(info_serialized, stores_size); for (size_t i = 0; i < info.stores.flags.size(); ++i) { @@ -555,22 +538,32 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { info.samplers.clear(); info.samplers.reserve(samplerCount); - for (u32 i = 0; i < samplerCount; ++i) { - Shader::SamplerResource sampler; - readBin(info_serialized, sampler.sharp_idx); + for (u32 i = 0; i < samplerCount; ++i) + { + std::uint8_t tag; + readBin(info_serialized, tag); - u32 associated_image; - readBin(info_serialized, associated_image); - sampler.associated_image = associated_image; + Shader::SamplerResource sampler{0, 0, false}; // Dummy-Init - u32 disable_aniso; - readBin(info_serialized, disable_aniso); - sampler.disable_aniso = disable_aniso; + if (tag == 0) + { + u32 sharp_idx; + readBin(info_serialized, sharp_idx); + sampler.sampler = sharp_idx; + } + else + { + AmdGpu::Sampler hw_sampler; + readBin(info_serialized, hw_sampler); + sampler.sampler = hw_sampler; + } + + std::uint8_t packed; + readBin(info_serialized, packed); + + sampler.associated_image = packed & 0xF; + sampler.disable_aniso = (packed >> 4) & 0x1; - // Inline-Sampler deserialisieren - readBin(info_serialized, sampler.inline_sampler.raw0); - readBin(info_serialized, sampler.inline_sampler.raw1); - info.samplers.push_back(std::move(sampler)); } @@ -598,11 +591,7 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { readBin(info_serialized, loc); readBin(info_serialized, attribute_value); readBin(info_serialized, idx); - - // Umwandeln des numerischen Werts zurück in das Shader::IR::Attribute-Enum Shader::IR::Attribute attribute = static_cast(attribute_value); - - // Einfügen in die Map mit dem richtigen Paar-Typ info.gs_copy_data.attr_map.emplace(loc, std::make_pair(attribute, idx)); } @@ -620,36 +609,7 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { } readBin(info_serialized, info.srt_info.flattened_bufsize_dw); - // Laden des walker_func JIT-Codes - u8 has_walker_func; - readBin(info_serialized, has_walker_func); - if (has_walker_func == 1) { - // Größe des JIT-Codes lesen - u32 walker_size; - readBin(info_serialized, walker_size); - - // Speicher für ausführbaren Code allokieren - void* code_memory = nullptr; -#ifdef _WIN32 - code_memory = - VirtualAlloc(nullptr, walker_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); -#else - code_memory = mmap(nullptr, walker_size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -#endif - - if (!code_memory) { - LOG_ERROR(Render_Vulkan, "Konnte keinen ausführbaren Speicher für JIT-Code allokieren"); - return; - } - - // JIT-Code laden - info_serialized.read(reinterpret_cast(code_memory), walker_size); - - // JIT-Funktion zuweisen - info.srt_info.walker_func = reinterpret_cast(code_memory); - } // Flat UD u32 flatCount; @@ -684,8 +644,6 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { readBin(info_serialized, flag_value); info.uses_group_ballot = (flag_value == 1); readBin(info_serialized, flag_value); - info.uses_shared = (flag_value == 1); - readBin(info_serialized, flag_value); info.uses_fp16 = (flag_value == 1); readBin(info_serialized, flag_value); info.uses_fp64 = (flag_value == 1); @@ -699,8 +657,6 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { info.stores_tess_level_inner = (flag_value == 1); readBin(info_serialized, flag_value); info.translation_failed = (flag_value == 1); - readBin(info_serialized, flag_value); - info.has_readconst = (flag_value == 1); // MRT Mask readBin(info_serialized, info.mrt_mask); @@ -716,14 +672,14 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { readBin(info_serialized, info.l_stage); readBin(info_serialized, info.pgm_hash); - // AttributeFlags für loads + // AttributeFlags for loads u32 loads_size; readBin(info_serialized, loads_size); for (size_t i = 0; i < loads_size; ++i) { readBin(info_serialized, info.loads.flags[i]); } - // AttributeFlags für stores + // AttributeFlags for stores u32 stores_size; readBin(info_serialized, stores_size); for (size_t i = 0; i < stores_size; ++i) { @@ -750,18 +706,11 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { // Check if there are any remaining bytes in the stream if (info_serialized.peek() != EOF) { - LOG_WARNING(Render_Vulkan, "Es sind noch Bytes im Stream übrig"); + LOG_WARNING(Render_Vulkan, "There are remaining bytes in the cache file"); } } bool CheckShaderCache(std::string shader_id) { - // Überprüfen, ob das Verzeichnis existiert - if (!std::filesystem::exists(shader_cache_dir)) { - LOG_INFO(Render_Vulkan, "Shader-Cache-Verzeichnis existiert nicht"); - return false; - } - - // Überprüfen, ob sowohl die SPIR-V-Datei als auch die Ressourcendatei existieren std::filesystem::path spirv_cache_file_path = shader_cache_dir / (shader_id + ".spv"); std::filesystem::path resources_file_path = shader_cache_dir / (shader_id + ".resources"); @@ -776,7 +725,6 @@ bool CheckShaderCache(std::string shader_id) { return false; } - // Überprüfen, ob die Dateien lesbar und nicht leer sind Common::FS::IOFile spirv_file(spirv_cache_file_path, Common::FS::FileAccessMode::Read); Common::FS::IOFile resources_file(resources_file_path, Common::FS::FileAccessMode::Read); @@ -787,8 +735,7 @@ bool CheckShaderCache(std::string shader_id) { resources_file.Close(); if (!spirv_valid || !resources_valid) { - LOG_WARNING(Render_Vulkan, "Ungueltige Dateien im Shader-Cache für ID: {}", shader_id); - // Fehlerhafte Dateien entfernen, um zukünftige Probleme zu vermeiden + LOG_WARNING(Render_Vulkan, "Invalid cache file for shader with ID: {}", shader_id); if (std::filesystem::exists(spirv_cache_file_path)) { std::filesystem::remove(spirv_cache_file_path); } @@ -798,7 +745,7 @@ bool CheckShaderCache(std::string shader_id) { return false; } - LOG_INFO(Render_Vulkan, "Shader mit ID {} im Cache gefunden", shader_id); + LOG_INFO(Render_Vulkan, "Found shader with ID {} in the cache", shader_id); return true; } @@ -815,13 +762,11 @@ void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) Common::FS::IOFile resources_dump_file(resources_dump_file_path, Common::FS::FileAccessMode::Read); - // Lese die Ressourcendaten std::vector resources_data; resources_data.resize(resources_dump_file.GetSize()); resources_dump_file.Read(resources_data); resources_dump_file.Close(); - // Verarbeite die gespeicherten Daten std::istringstream combined_stream(std::string(resources_data.begin(), resources_data.end())); std::istringstream info_stream; @@ -831,19 +776,16 @@ void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) } void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized) { - // SPIR-V-Datei speichern std::string spirv_cache_filename = shader_id + ".spv"; std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; Common::FS::IOFile shader_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Write); shader_cache_file.WriteSpan(std::span(spv)); shader_cache_file.Close(); - // Resources-Datei vorbereiten std::filesystem::path resources_dump_file_path = shader_cache_dir / (shader_id + ".resources"); Common::FS::IOFile resources_dump_file(resources_dump_file_path, Common::FS::FileAccessMode::Write); - // Die Streams müssen zurückgesetzt werden, bevor wir sie lesen können if (std::ostringstream* info_oss = dynamic_cast(&info_serialized)) { std::string info_data = info_oss->str(); resources_dump_file.WriteSpan(std::span(info_data.data(), info_data.size())); From 1e71ac8f997315e800bea844b78f8d837efc0de6 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Tue, 24 Jun 2025 20:16:43 +0200 Subject: [PATCH 27/41] should fix linux build --- src/video_core/renderer_vulkan/shader_cache.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 542f12433..7533674d1 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #ifdef _WIN32 #include #else From 3346c5a39c715040757d445d29053a96f70e25a7 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sun, 13 Jul 2025 16:57:27 +0200 Subject: [PATCH 28/41] begin rewrite --- .gitmodules | 3 + CMakeLists.txt | 8 +- externals/CMakeLists.txt | 9 + externals/cereal | 1 + src/common/binary_helper.h | 21 - .../renderer_vulkan/shader_cache.cpp | 494 +----------------- .../shader_cache_serialization.h | 37 ++ 7 files changed, 72 insertions(+), 501 deletions(-) create mode 160000 externals/cereal delete mode 100644 src/common/binary_helper.h create mode 100644 src/video_core/renderer_vulkan/shader_cache_serialization.h diff --git a/.gitmodules b/.gitmodules index 25b5d307b..b2d65f32d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -106,3 +106,6 @@ [submodule "externals/libusb"] path = externals/libusb url = https://github.com/libusb/libusb-cmake.git +[submodule "externals/cereal"] + path = externals/cereal + url = https://github.com/USCiLab/cereal diff --git a/CMakeLists.txt b/CMakeLists.txt index 08fa59ebd..5ff386d36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,6 +239,8 @@ find_package(ZLIB 1.3 MODULE) find_package(Zydis 5.0.0 CONFIG) find_package(pugixml 1.14 CONFIG) find_package(libusb 1.0.27 MODULE) +find_package(cereal 1.3.2 CONFIG) + if (APPLE) find_package(date 3.0.1 CONFIG) endif() @@ -657,8 +659,7 @@ set(COMMON src/common/logging/backend.cpp src/common/arch.h src/common/assert.cpp src/common/assert.h - src/common/binary_helper.h - src/common/bit_array.h + src/common/bit_array.h src/common/bit_field.h src/common/bounded_threadsafe_queue.h src/common/concepts.h @@ -927,6 +928,7 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp src/video_core/renderer_vulkan/liverpool_to_vk.h src/video_core/renderer_vulkan/shader_cache.cpp src/video_core/renderer_vulkan/shader_cache.h + src/video_core/renderer_vulkan/shader_cache_serialization.h src/video_core/renderer_vulkan/vk_common.cpp src/video_core/renderer_vulkan/vk_common.h src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -1111,7 +1113,7 @@ endif() create_target_directory_groups(shadps4) target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half ZLIB::ZLIB PNG::PNG) -target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers libusb::usb) +target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers libusb::usb cereal::cereal) target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h") target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h") diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 89b0fbfdd..1fd4ffb2b 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -216,6 +216,15 @@ if (NOT TARGET stb::headers) add_library(stb::headers ALIAS stb) endif() +if (NOT TARGET cereal::cereal) + set(SKIP_PERFORMANCE_COMPARISON ON "") + set(BUILD_SANDBOX OFF "") + set(BUILD_TESTS OFF "") + set(BUILD_DOC OFF "") + set(SKIP_PORTABILITY_TEST ON "") + add_subdirectory(cereal) +endif () + # Apple-only dependencies if (APPLE) # date diff --git a/externals/cereal b/externals/cereal new file mode 160000 index 000000000..a56bad8bb --- /dev/null +++ b/externals/cereal @@ -0,0 +1 @@ +Subproject commit a56bad8bbb770ee266e930c95d37fff2a5be7fea diff --git a/src/common/binary_helper.h b/src/common/binary_helper.h deleted file mode 100644 index dcf5c2dc4..000000000 --- a/src/common/binary_helper.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include -#include "common/logging/log.h" - -using u32 = uint32_t; - -template -void writeBin(std::ostream& os, const T& v) { - LOG_INFO(Render_Recompiler, "BinaryHelper: Pos: {}", static_cast(os.tellp())); - os.write(reinterpret_cast(&v), sizeof(T)); -} - -template -void readBin(std::istream& is, T& v) { - if (is.eof()) { - LOG_WARNING(Render_Recompiler, "BinaryHelper: EOF"); - } - is.read(reinterpret_cast(&v), sizeof(T)); -} \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 7533674d1..f65332c9e 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + #include #include #include @@ -11,11 +14,16 @@ #include "common/hash.h" #include "common/path_util.h" #include "common/io_file.h" -#include "common/binary_helper.h" +#include "video_core/renderer_vulkan/shader_cache_serialization.h" +#include #include "common/logging/log.h" #include "shader_recompiler/ir/type.h" #include "shader_recompiler/info.h" #include "shader_recompiler/specialization.h" +#include +#include + +#include "shader_cache.h" using u64 = uint64_t; using u32 = uint32_t; @@ -240,489 +248,15 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { return hash; } -void SerializeInfo(std::ostream& info_serialized, Shader::Info info) { - writeBin(info_serialized, info.ud_mask.mask); - - u32 bufferCount = static_cast(info.buffers.size()); - writeBin(info_serialized, bufferCount); // Buffer Amount - - for (const auto& buffer : info.buffers) { - writeBin(info_serialized, buffer.sharp_idx); - writeBin(info_serialized, static_cast(buffer.used_types)); - writeBin(info_serialized, static_cast(buffer.buffer_type)); - writeBin(info_serialized, buffer.instance_attrib); - writeBin(info_serialized, static_cast(buffer.is_written ? 1 : 0)); - writeBin(info_serialized, static_cast(buffer.is_formatted ? 1 : 0)); - - writeBin(info_serialized, buffer.inline_cbuf.base_address); - writeBin(info_serialized, buffer.inline_cbuf._padding0); - writeBin(info_serialized, buffer.inline_cbuf.stride); - writeBin(info_serialized, buffer.inline_cbuf.cache_swizzle); - writeBin(info_serialized, buffer.inline_cbuf.swizzle_enable); - writeBin(info_serialized, buffer.inline_cbuf.num_records); - writeBin(info_serialized, buffer.inline_cbuf.dst_sel_x); - writeBin(info_serialized, buffer.inline_cbuf.dst_sel_y); - writeBin(info_serialized, buffer.inline_cbuf.dst_sel_z); - writeBin(info_serialized, buffer.inline_cbuf.dst_sel_w); - writeBin(info_serialized, buffer.inline_cbuf.num_format); - writeBin(info_serialized, buffer.inline_cbuf.data_format); - writeBin(info_serialized, buffer.inline_cbuf.element_size); - writeBin(info_serialized, buffer.inline_cbuf.index_stride); - writeBin(info_serialized, buffer.inline_cbuf.add_tid_enable); - writeBin(info_serialized, buffer.inline_cbuf._padding1); - writeBin(info_serialized, buffer.inline_cbuf.type); - - } - - // Image-Resources - u32 imageCount = static_cast(info.images.size()); - writeBin(info_serialized, imageCount); // Image Amount - - for (const auto& image : info.images) { - writeBin(info_serialized, image.sharp_idx); - writeBin(info_serialized, static_cast(image.is_depth ? 1 : 0)); - writeBin(info_serialized, static_cast(image.is_atomic ? 1 : 0)); - writeBin(info_serialized, static_cast(image.is_array ? 1 : 0)); - writeBin(info_serialized, static_cast(image.is_written ? 1 : 0)); - } - - // Sampler-Resources - u32 samplerCount = static_cast(info.samplers.size()); - writeBin(info_serialized, samplerCount); // Sampler Amount - - for (const auto& sampler : info.samplers) { - if (std::holds_alternative(sampler.sampler)) - { - std::uint8_t tag = 0; - writeBin(info_serialized, tag); - - u32 sharp_idx = std::get(sampler.sampler); - writeBin(info_serialized, sharp_idx); - } - else - { - std::uint8_t tag = 1; - writeBin(info_serialized, tag); - - const AmdGpu::Sampler& hw_sampler = - std::get(sampler.sampler); - writeBin(info_serialized, hw_sampler); - } - - std::uint8_t packed = - static_cast((sampler.disable_aniso & 0x1) << 4) | - static_cast(sampler.associated_image & 0xF); - - writeBin(info_serialized, packed); - } - - // FMask-Resources - u32 fmaskCount = static_cast(info.fmasks.size()); - writeBin(info_serialized, fmaskCount); // FMask Amount - - for (const auto& fmask : info.fmasks) { - writeBin(info_serialized, fmask.sharp_idx); - } - - // GS Copy Data - u32 mapCount = static_cast(info.gs_copy_data.attr_map.size()); - writeBin(info_serialized, mapCount); - - for (auto const& [loc, attr_pair] : info.gs_copy_data.attr_map) { - writeBin(info_serialized, loc); - writeBin(info_serialized, static_cast(attr_pair.first)); - writeBin(info_serialized, attr_pair.second); - } - - // SRT Info - u32 srtCount = static_cast(info.srt_info.srt_reservations.size()); - writeBin(info_serialized, srtCount); - - for (const auto& res : info.srt_info.srt_reservations) { - writeBin(info_serialized, res.sgpr_base); - writeBin(info_serialized, res.dword_offset); - writeBin(info_serialized, res.num_dwords); - } - - writeBin(info_serialized, info.srt_info.flattened_bufsize_dw); - - // Flat UD - - u32 flatCount = static_cast(info.flattened_ud_buf.size()); - writeBin(info_serialized, flatCount); - - for (const auto& flat : info.flattened_ud_buf) { - writeBin(info_serialized, flat); - } - - // Tessellation Data - writeBin(info_serialized, info.tess_consts_ptr_base); - writeBin(info_serialized, info.tess_consts_dword_offset); - - // Flags - writeBin(info_serialized, static_cast(info.has_storage_images ? 1 : 0)); - writeBin(info_serialized, static_cast(info.has_discard ? 1 : 0)); - writeBin(info_serialized, static_cast(info.has_image_gather ? 1 : 0)); - writeBin(info_serialized, static_cast(info.has_image_query ? 1 : 0)); - writeBin(info_serialized, static_cast(info.uses_lane_id ? 1 : 0)); - writeBin(info_serialized, static_cast(info.uses_group_quad ? 1 : 0)); - writeBin(info_serialized, static_cast(info.uses_group_ballot ? 1 : 0)); - writeBin(info_serialized, static_cast(info.uses_fp16 ? 1 : 0)); - writeBin(info_serialized, static_cast(info.uses_fp64 ? 1 : 0)); - writeBin(info_serialized, static_cast(info.uses_pack_10_11_11 ? 1 : 0)); - writeBin(info_serialized, static_cast(info.uses_unpack_10_11_11 ? 1 : 0)); - writeBin(info_serialized, static_cast(info.stores_tess_level_outer ? 1 : 0)); - writeBin(info_serialized, static_cast(info.stores_tess_level_inner ? 1 : 0)); - writeBin(info_serialized, static_cast(info.translation_failed ? 1 : 0)); - - // MRT Mask - writeBin(info_serialized, info.mrt_mask); - - // Fetch - - writeBin(info_serialized, static_cast(info.has_fetch_shader ? 1 : 0)); - writeBin(info_serialized, info.fetch_shader_sgpr_base); - - // Stage - writeBin(info_serialized, info.stage); - writeBin(info_serialized, info.l_stage); - writeBin(info_serialized, info.pgm_hash); - - // AttributeFlags for loads - u32 loads_size = static_cast(info.loads.flags.size()); - writeBin(info_serialized, loads_size); - for (size_t i = 0; i < info.loads.flags.size(); ++i) { - writeBin(info_serialized, info.loads.flags[i]); - } - - // AttributeFlags for stores - u32 stores_size = static_cast(info.stores.flags.size()); - writeBin(info_serialized, stores_size); - for (size_t i = 0; i < info.stores.flags.size(); ++i) { - writeBin(info_serialized, info.stores.flags[i]); - } - - // UserData - u32 userDataSize = static_cast(info.user_data.size()); - writeBin(info_serialized, userDataSize); - for (size_t i = 0; i < info.user_data.size(); ++i) { - writeBin(info_serialized, info.user_data[i]); - } - - // Pgm Base - writeBin(info_serialized, info.pgm_base); -} - -void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { - // UD Mask - readBin(info_serialized, info.ud_mask.mask); - - // Buffer-Resources - u32 bufferCount; - readBin(info_serialized, bufferCount); - - info.buffers.clear(); - info.buffers.reserve(bufferCount); - for (u32 i = 0; i < bufferCount; ++i) { - Shader::BufferResource buffer; - readBin(info_serialized, buffer.sharp_idx); - u32 used_types; - readBin(info_serialized, used_types); - buffer.used_types = static_cast(used_types); - u32 buffer_type; - readBin(info_serialized, buffer_type); - buffer.buffer_type = static_cast(buffer_type); - readBin(info_serialized, buffer.instance_attrib); - u8 is_written; - readBin(info_serialized, is_written); - buffer.is_written = (is_written == 1); - u8 is_formatted; - readBin(info_serialized, is_formatted); - buffer.is_formatted = (is_formatted == 1); - - u64 base_address; - readBin(info_serialized, base_address); - buffer.inline_cbuf.base_address = base_address; - - u64 padding0; - readBin(info_serialized, padding0); - buffer.inline_cbuf._padding0 = padding0; - - u64 stride; - readBin(info_serialized, stride); - buffer.inline_cbuf.stride = stride; - - u64 cache_swizzle; - readBin(info_serialized, cache_swizzle); - buffer.inline_cbuf.cache_swizzle = cache_swizzle; - - u64 swizzle_enable; - readBin(info_serialized, swizzle_enable); - buffer.inline_cbuf.swizzle_enable = swizzle_enable; - - readBin(info_serialized, buffer.inline_cbuf.num_records); - - u32 dst_sel_x; - readBin(info_serialized, dst_sel_x); - buffer.inline_cbuf.dst_sel_x = dst_sel_x; - - u32 dst_sel_y; - readBin(info_serialized, dst_sel_y); - buffer.inline_cbuf.dst_sel_y = dst_sel_y; - - u32 dst_sel_z; - readBin(info_serialized, dst_sel_z); - buffer.inline_cbuf.dst_sel_z = dst_sel_z; - - u32 dst_sel_w; - readBin(info_serialized, dst_sel_w); - buffer.inline_cbuf.dst_sel_w = dst_sel_w; - - u32 num_format; - readBin(info_serialized, num_format); - buffer.inline_cbuf.num_format = num_format; - - u32 data_format; - readBin(info_serialized, data_format); - buffer.inline_cbuf.data_format = data_format; - - u32 element_size; - readBin(info_serialized, element_size); - buffer.inline_cbuf.element_size = element_size; - - u32 index_stride; - readBin(info_serialized, index_stride); - buffer.inline_cbuf.index_stride = index_stride; - - u32 add_tid_enable; - readBin(info_serialized, add_tid_enable); - buffer.inline_cbuf.add_tid_enable = add_tid_enable; - - u32 padding1; - readBin(info_serialized, padding1); - buffer.inline_cbuf._padding1 = padding1; - - u32 type; - readBin(info_serialized, type); - buffer.inline_cbuf.type = type; - - info.buffers.push_back(std::move(buffer)); - } - - // Image-Resources - u32 imageCount; - readBin(info_serialized, imageCount); - - info.images.clear(); - info.images.reserve(imageCount); - for (u32 i = 0; i < imageCount; ++i) { - Shader::ImageResource image; - readBin(info_serialized, image.sharp_idx); - u8 is_depth; - readBin(info_serialized, is_depth); - image.is_depth = (is_depth == 1); - u8 is_atomic; - readBin(info_serialized, is_atomic); - image.is_atomic = (is_atomic == 1); - u8 is_array; - readBin(info_serialized, is_array); - image.is_array = (is_array == 1); - u8 is_written; - readBin(info_serialized, is_written); - image.is_written = (is_written == 1); - info.images.push_back(std::move(image)); - } - - // Sampler-Resources - u32 samplerCount; - readBin(info_serialized, samplerCount); - - info.samplers.clear(); - info.samplers.reserve(samplerCount); - for (u32 i = 0; i < samplerCount; ++i) - { - std::uint8_t tag; - readBin(info_serialized, tag); - - Shader::SamplerResource sampler{0, 0, false}; // Dummy-Init - - if (tag == 0) - { - u32 sharp_idx; - readBin(info_serialized, sharp_idx); - sampler.sampler = sharp_idx; - } - else - { - AmdGpu::Sampler hw_sampler; - readBin(info_serialized, hw_sampler); - sampler.sampler = hw_sampler; - } - - std::uint8_t packed; - readBin(info_serialized, packed); - - sampler.associated_image = packed & 0xF; - sampler.disable_aniso = (packed >> 4) & 0x1; - - info.samplers.push_back(std::move(sampler)); - } - - // FMask-Resources - u32 fmaskCount; - readBin(info_serialized, fmaskCount); - - info.fmasks.clear(); - info.fmasks.reserve(fmaskCount); - for (u32 i = 0; i < fmaskCount; ++i) { - Shader::FMaskResource fmask; - readBin(info_serialized, fmask.sharp_idx); - info.fmasks.push_back(std::move(fmask)); - } - - // GS Copy Data - u32 mapCount; - readBin(info_serialized, mapCount); - - info.gs_copy_data.attr_map.clear(); - for (u32 i = 0; i < mapCount; ++i) { - u32 loc; - u32 attribute_value; - u32 idx; - readBin(info_serialized, loc); - readBin(info_serialized, attribute_value); - readBin(info_serialized, idx); - Shader::IR::Attribute attribute = static_cast(attribute_value); - info.gs_copy_data.attr_map.emplace(loc, std::make_pair(attribute, idx)); - } - - // SRT Info - u32 srtCount; - readBin(info_serialized, srtCount); - - info.srt_info.srt_reservations.clear(); - info.srt_info.srt_reservations.resize(srtCount); - for (u32 i = 0; i < srtCount; ++i) { - auto& res = info.srt_info.srt_reservations[i]; - readBin(info_serialized, res.sgpr_base); - readBin(info_serialized, res.dword_offset); - readBin(info_serialized, res.num_dwords); - } - - readBin(info_serialized, info.srt_info.flattened_bufsize_dw); - - // Flat UD - - u32 flatCount; - readBin(info_serialized, flatCount); - - info.flattened_ud_buf.clear(); - u32 required_size = std::max(flatCount, info.srt_info.flattened_bufsize_dw); - info.flattened_ud_buf.resize(required_size); - - for (u32 i = 0; i < flatCount; ++i) { - readBin(info_serialized, info.flattened_ud_buf[i]); - } - - // Tessellation Data - readBin(info_serialized, info.tess_consts_ptr_base); - readBin(info_serialized, info.tess_consts_dword_offset); - - // Flags - u8 flag_value; - readBin(info_serialized, flag_value); - info.has_storage_images = (flag_value == 1); - readBin(info_serialized, flag_value); - info.has_discard = (flag_value == 1); - readBin(info_serialized, flag_value); - info.has_image_gather = (flag_value == 1); - readBin(info_serialized, flag_value); - info.has_image_query = (flag_value == 1); - readBin(info_serialized, flag_value); - info.uses_lane_id = (flag_value == 1); - readBin(info_serialized, flag_value); - info.uses_group_quad = (flag_value == 1); - readBin(info_serialized, flag_value); - info.uses_group_ballot = (flag_value == 1); - readBin(info_serialized, flag_value); - info.uses_fp16 = (flag_value == 1); - readBin(info_serialized, flag_value); - info.uses_fp64 = (flag_value == 1); - readBin(info_serialized, flag_value); - info.uses_pack_10_11_11 = (flag_value == 1); - readBin(info_serialized, flag_value); - info.uses_unpack_10_11_11 = (flag_value == 1); - readBin(info_serialized, flag_value); - info.stores_tess_level_outer = (flag_value == 1); - readBin(info_serialized, flag_value); - info.stores_tess_level_inner = (flag_value == 1); - readBin(info_serialized, flag_value); - info.translation_failed = (flag_value == 1); - - // MRT Mask - readBin(info_serialized, info.mrt_mask); - - // Fetch Shader - u8 has_fetch_shader; - readBin(info_serialized, has_fetch_shader); - info.has_fetch_shader = (has_fetch_shader == 1); - readBin(info_serialized, info.fetch_shader_sgpr_base); - - // Stage - readBin(info_serialized, info.stage); - readBin(info_serialized, info.l_stage); - readBin(info_serialized, info.pgm_hash); - - // AttributeFlags for loads - u32 loads_size; - readBin(info_serialized, loads_size); - for (size_t i = 0; i < loads_size; ++i) { - readBin(info_serialized, info.loads.flags[i]); - } - - // AttributeFlags for stores - u32 stores_size; - readBin(info_serialized, stores_size); - for (size_t i = 0; i < stores_size; ++i) { - readBin(info_serialized, info.stores.flags[i]); - } - - // UserData - u32 userDataSize; - readBin(info_serialized, userDataSize); - - static std::vector temp_user_data_storage; - temp_user_data_storage.clear(); - temp_user_data_storage.resize(userDataSize); - - for (u32 i = 0; i < userDataSize; ++i) { - readBin(info_serialized, temp_user_data_storage[i]); - } - - info.user_data = std::span(temp_user_data_storage); - - // Pgm Base - readBin(info_serialized, info.pgm_base); - - - // Check if there are any remaining bytes in the stream - if (info_serialized.peek() != EOF) { - LOG_WARNING(Render_Vulkan, "There are remaining bytes in the cache file"); - } -} - bool CheckShaderCache(std::string shader_id) { std::filesystem::path spirv_cache_file_path = shader_cache_dir / (shader_id + ".spv"); std::filesystem::path resources_file_path = shader_cache_dir / (shader_id + ".resources"); if (!std::filesystem::exists(spirv_cache_file_path)) { - LOG_DEBUG(Render_Vulkan, "SPIR-V-Datei nicht gefunden: {}", spirv_cache_file_path.string()); return false; } if (!std::filesystem::exists(resources_file_path)) { - LOG_DEBUG(Render_Vulkan, "Ressourcendatei nicht gefunden: {}", - resources_file_path.string()); return false; } @@ -762,7 +296,7 @@ void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) std::filesystem::path resources_dump_file_path = shader_cache_dir / (shader_id + ".resources"); Common::FS::IOFile resources_dump_file(resources_dump_file_path, Common::FS::FileAccessMode::Read); - + std::vector resources_data; resources_data.resize(resources_dump_file.GetSize()); resources_dump_file.Read(resources_data); @@ -772,7 +306,7 @@ void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) std::istringstream info_stream; info_stream.str(std::string(resources_data.begin(), resources_data.end())); - DeserializeInfo(info_stream, info); + } @@ -795,4 +329,10 @@ void AddShader(std::string shader_id, std::vector spv, std::ostream& info_s resources_dump_file.Close(); } +void SerializeInfo( + std::ostream& info_serialized, Shader::Info info) { + cereal::BinaryOutputArchive ar(info_serialized); + ar << info.images; +} + } // namespace ShaderCache \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache_serialization.h b/src/video_core/renderer_vulkan/shader_cache_serialization.h new file mode 100644 index 000000000..98b996066 --- /dev/null +++ b/src/video_core/renderer_vulkan/shader_cache_serialization.h @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include "shader_recompiler/info.h" + +namespace cereal { + +// boost::small_vector +template +void save(Archive& ar, boost::container::small_vector const& v) { + ar(static_cast(v.size())); + for (auto const& e : v) + ar(e); +} + +template +void load(Archive& ar, boost::container::small_vector& v) { + std::uint32_t n; + ar(n); + v.resize(n); + for (auto& e : v) + ar(e); +} + +// Shader::ImageResource +template +void serialize(Archive& ar, Shader::ImageResource& img) +{ + ar(img.sharp_idx, + img.is_depth, + img.is_atomic, + img.is_array, + img.is_written, + img.is_r128); +} +} \ No newline at end of file From 438e1cdac18cb3fb2b927ba858e5cd51ddcf83ef Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sun, 13 Jul 2025 16:59:49 +0200 Subject: [PATCH 29/41] oops --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ff386d36..b0685cffa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -659,7 +659,7 @@ set(COMMON src/common/logging/backend.cpp src/common/arch.h src/common/assert.cpp src/common/assert.h - src/common/bit_array.h + src/common/bit_array.h src/common/bit_field.h src/common/bounded_threadsafe_queue.h src/common/concepts.h From f9e199e1a00fed1d591f59af2ea801976add9c61 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sun, 13 Jul 2025 17:20:20 +0200 Subject: [PATCH 30/41] cleanup --- src/common/hash.h | 9 ++++++--- src/video_core/renderer_vulkan/shader_cache.h | 4 +++- src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/common/hash.h b/src/common/hash.h index b29cfb90f..d5cacedd7 100644 --- a/src/common/hash.h +++ b/src/common/hash.h @@ -5,7 +5,10 @@ #include "common/types.h" -template -T HashCombine(const T& seed, const U& value) { - return seed ^ (static_cast(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); +[[nodiscard]] inline u64 HashCombine(const u64 seed, const u64 hash) { + return seed ^ (hash + 0x9e3779b9 + (seed << 12) + (seed >> 4)); +} + +[[nodiscard]] inline u32 HashCombine(const u32 seed, const u32 hash) { + return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2)); } \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache.h b/src/video_core/renderer_vulkan/shader_cache.h index d2320e455..c9518e918 100644 --- a/src/video_core/renderer_vulkan/shader_cache.h +++ b/src/video_core/renderer_vulkan/shader_cache.h @@ -1,6 +1,8 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + #pragma once -#include #include #include #include diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 0e54c46d0..d15b212d6 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -569,7 +569,7 @@ PipelineCache::Result PipelineCache::GetProgram(Stage stage, LogicalStage l_stag Shader::ShaderParams params, Shader::Backend::Bindings& binding) { auto runtime_info = BuildRuntimeInfo(stage, l_stage); - auto [it_pgm, new_program] = program_cache.try_emplace(params.hash); // code in vs + auto [it_pgm, new_program] = program_cache.try_emplace(params.hash); if (new_program) { it_pgm.value() = std::make_unique(stage, l_stage, params); auto& program = it_pgm.value(); From e418249f756cac56874e921934bcaea9e8eac627 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Mon, 14 Jul 2025 20:44:10 +0200 Subject: [PATCH 31/41] more --- src/common/hash.h | 12 +-- .../renderer_vulkan/shader_cache.cpp | 34 ++++----- src/video_core/renderer_vulkan/shader_cache.h | 2 +- .../shader_cache_serialization.h | 74 ++++++++++++++----- 4 files changed, 81 insertions(+), 41 deletions(-) diff --git a/src/common/hash.h b/src/common/hash.h index d5cacedd7..7f819fd4b 100644 --- a/src/common/hash.h +++ b/src/common/hash.h @@ -5,10 +5,10 @@ #include "common/types.h" -[[nodiscard]] inline u64 HashCombine(const u64 seed, const u64 hash) { - return seed ^ (hash + 0x9e3779b9 + (seed << 12) + (seed >> 4)); -} +template +[[nodiscard]] constexpr u64 HashCombine(T1 seed, T2 hash) noexcept { + u64 s = static_cast(seed); + u64 h = static_cast(hash); -[[nodiscard]] inline u32 HashCombine(const u32 seed, const u32 hash) { - return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2)); -} \ No newline at end of file + return s ^ (h + 0x9e3779b9 + (s << 12) + (s >> 4)); +} diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index f65332c9e..d6643a4df 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -2,26 +2,25 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include -#include #include #include +#include #ifdef _WIN32 #include #else #include #include #endif -#include "common/hash.h" -#include "common/path_util.h" -#include "common/io_file.h" -#include "video_core/renderer_vulkan/shader_cache_serialization.h" -#include -#include "common/logging/log.h" -#include "shader_recompiler/ir/type.h" -#include "shader_recompiler/info.h" -#include "shader_recompiler/specialization.h" #include -#include +#include +#include "common/hash.h" +#include "common/io_file.h" +#include "common/logging/log.h" +#include "common/path_util.h" +#include "shader_recompiler/info.h" +#include "shader_recompiler/ir/type.h" +#include "shader_recompiler/specialization.h" +#include "video_core/renderer_vulkan/shader_cache_serialization.h" #include "shader_cache.h" @@ -287,8 +286,7 @@ bool CheckShaderCache(std::string shader_id) { void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) { std::string spirv_cache_filename = shader_id + ".spv"; std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; - Common::FS::IOFile spirv_cache_file(spirv_cache_file_path, - Common::FS::FileAccessMode::Read); + Common::FS::IOFile spirv_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Read); spv.resize(spirv_cache_file.GetSize() / sizeof(u32)); spirv_cache_file.Read(spv); spirv_cache_file.Close(); @@ -306,8 +304,6 @@ void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) std::istringstream info_stream; info_stream.str(std::string(resources_data.begin(), resources_data.end())); - - } void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized) { @@ -329,10 +325,14 @@ void AddShader(std::string shader_id, std::vector spv, std::ostream& info_s resources_dump_file.Close(); } -void SerializeInfo( - std::ostream& info_serialized, Shader::Info info) { +void SerializeInfo(std::ostream& info_serialized, Shader::Info &info) { cereal::BinaryOutputArchive ar(info_serialized); + ar << info.ud_mask; + ar << info.gs_copy_data; + ar << info.uses_patches; + ar << info.buffers; ar << info.images; + } } // namespace ShaderCache \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache.h b/src/video_core/renderer_vulkan/shader_cache.h index c9518e918..4df74e115 100644 --- a/src/video_core/renderer_vulkan/shader_cache.h +++ b/src/video_core/renderer_vulkan/shader_cache.h @@ -13,7 +13,7 @@ namespace ShaderCache { u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec); void SerializeInfo( - std::ostream& info_serialized, Shader::Info info); + std::ostream& info_serialized, Shader::Info& info); void DeserializeInfo(std::istream& info_serialized, Shader::Info& info); bool CheckShaderCache(std::string shader_id); diff --git a/src/video_core/renderer_vulkan/shader_cache_serialization.h b/src/video_core/renderer_vulkan/shader_cache_serialization.h index 98b996066..ba48ae7be 100644 --- a/src/video_core/renderer_vulkan/shader_cache_serialization.h +++ b/src/video_core/renderer_vulkan/shader_cache_serialization.h @@ -2,36 +2,76 @@ // SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#include +#include #include "shader_recompiler/info.h" namespace cereal { // boost::small_vector template -void save(Archive& ar, boost::container::small_vector const& v) { - ar(static_cast(v.size())); - for (auto const& e : v) - ar(e); +void save(Archive& ar, boost::container::small_vector const& smallVector) { + ar(static_cast(smallVector.size())); + for (auto const& element : smallVector) + ar(element); } template -void load(Archive& ar, boost::container::small_vector& v) { - std::uint32_t n; - ar(n); - v.resize(n); - for (auto& e : v) - ar(e); +void load(Archive& ar, boost::container::small_vector& smallVector) { + std::uint32_t elementCount; + ar(elementCount); + smallVector.resize(elementCount); + for (auto& element : smallVector) + ar(element); +} + +// Shader::Info::UserDataMask +template +void serialize(Archive& ar, Shader::Info::UserDataMask& mask) { + ar(mask.mask); +} + +// Shader::CopyShaderData +template +void serialize(Archive& ar, Shader::CopyShaderData& data) { + ar( + data.attr_map, + data.num_attrs, + data.output_vertices); +} + +// AmdGPU::Buffer +template +void serialize(Archive& ar, AmdGpu::Buffer& buffer) { + ar(cereal::binary_data(reinterpret_cast(&buffer), sizeof(buffer))); + // is base_adress cacheable? +} + +// Shader::BufferResource +template +void serialize(Archive& ar, Shader::BufferResource& buffer) +{ + ar( + buffer.sharp_idx, + buffer.used_types, + buffer.inline_cbuf, + buffer.buffer_type, + buffer.instance_attrib, + buffer.is_written, + buffer.is_formatted); } // Shader::ImageResource template -void serialize(Archive& ar, Shader::ImageResource& img) +void serialize(Archive& ar, Shader::ImageResource& image) { - ar(img.sharp_idx, - img.is_depth, - img.is_atomic, - img.is_array, - img.is_written, - img.is_r128); + ar( + image.sharp_idx, + image.is_depth, + image.is_atomic, + image.is_array, + image.is_written, + image.is_r128); } + } \ No newline at end of file From 292b2878cc60bf3e7214fa3635a47a3e7931e538 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Mon, 14 Jul 2025 21:17:55 +0200 Subject: [PATCH 32/41] samplers --- src/video_core/renderer_vulkan/shader_cache.cpp | 1 + .../renderer_vulkan/shader_cache_serialization.h | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index d6643a4df..cea80eb80 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -332,6 +332,7 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info &info) { ar << info.uses_patches; ar << info.buffers; ar << info.images; + ar << info.samplers; } diff --git a/src/video_core/renderer_vulkan/shader_cache_serialization.h b/src/video_core/renderer_vulkan/shader_cache_serialization.h index ba48ae7be..bbe0bf97c 100644 --- a/src/video_core/renderer_vulkan/shader_cache_serialization.h +++ b/src/video_core/renderer_vulkan/shader_cache_serialization.h @@ -3,6 +3,7 @@ #pragma once #include +#include #include #include "shader_recompiler/info.h" @@ -74,4 +75,18 @@ void serialize(Archive& ar, Shader::ImageResource& image) image.is_r128); } +// AmdGpu::Sampler +template +void serialize(Archive& ar, AmdGpu::Sampler& sampler) { + ar(cereal::binary_data(reinterpret_cast(&sampler), sizeof(sampler))); +} + +// Shader::SamplerResource +template +void serialize(Archive& ar, Shader::SamplerResource& sampler) { + ar(sampler.sampler); + ar(static_cast(sampler.associated_image), + static_cast(sampler.disable_aniso)); +} + } \ No newline at end of file From 56e98b3dc07335749100cb1afd11d8c37f2409df Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Mon, 14 Jul 2025 21:22:47 +0200 Subject: [PATCH 33/41] rebase --- src/video_core/renderer_vulkan/shader_cache.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index cea80eb80..5c17ec480 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -46,7 +46,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { switch (runtime_info.stage) { case Shader::Stage::Local: hash = HashCombine(hash, runtime_info.ls_info.ls_stride); - hash = HashCombine(hash, runtime_info.ls_info.links_with_tcs); break; case Shader::Stage::Export: hash = HashCombine(hash, runtime_info.es_info.vertex_data_size); @@ -137,7 +136,6 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { } for (const auto& vs_attrib : spec.vs_attribs) { - hash = HashCombine(hash, vs_attrib.num_components); hash = HashCombine(hash, static_cast(vs_attrib.num_class)); hash = HashCombine(hash, vs_attrib.dst_select.r); hash = HashCombine(hash, vs_attrib.dst_select.g); From b1db45a64d80604beb16bc8f75c59a5fac6565eb Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Tue, 15 Jul 2025 20:34:03 +0200 Subject: [PATCH 34/41] fmask, refactoring, fixes and mac fix(?) --- CMakeLists.txt | 1 + externals/CMakeLists.txt | 3 ++- src/emulator.cpp | 8 +++--- .../renderer_vulkan/shader_cache.cpp | 24 ++++++++++-------- src/video_core/renderer_vulkan/shader_cache.h | 2 ++ .../shader_cache_serialization.h | 25 ++++++------------- .../renderer_vulkan/vk_pipeline_cache.cpp | 12 ++++----- 7 files changed, 37 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c0e8b0dbf..d74510d36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -690,6 +690,7 @@ set(COMMON src/common/logging/backend.cpp src/common/rdtsc.h src/common/recursive_lock.cpp src/common/recursive_lock.h + src/common/serialization.h src/common/sha1.h src/common/shared_first_mutex.h src/common/signal_context.h diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 1fd4ffb2b..ae52dae9d 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -216,7 +216,8 @@ if (NOT TARGET stb::headers) add_library(stb::headers ALIAS stb) endif() -if (NOT TARGET cereal::cereal) +# cereal +if (NOT TARGET cereal::cereal AND NOT APPLE) set(SKIP_PERFORMANCE_COMPARISON ON "") set(BUILD_SANDBOX OFF "") set(BUILD_TESTS OFF "") diff --git a/src/emulator.cpp b/src/emulator.cpp index e2ee3e103..705060252 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -41,6 +41,7 @@ #include "core/memory.h" #include "emulator.h" #include "video_core/renderdoc.h" +#include "video_core/renderer_vulkan/shader_cache.h" Frontend::WindowSDL* g_window = nullptr; @@ -256,10 +257,9 @@ void Emulator::Run(std::filesystem::path file, const std::vector ar } VideoCore::SetOutputDir(mount_captures_dir, id); - const auto shader_cache_dir = Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache"; - if (!std::filesystem::exists(shader_cache_dir)) { - std::filesystem::create_directories(shader_cache_dir); - LOG_INFO(Loader, "Created shader cache directory: {}", shader_cache_dir.string()); + if (!std::filesystem::exists(SHADER_CACHE_DIR)) { + std::filesystem::create_directories(SHADER_CACHE_DIR); + LOG_INFO(Loader, "Created shader cache directory: {}", SHADER_CACHE_DIR.string()); } // Initialize kernel and library facilities. Libraries::InitHLELibs(&linker->GetHLESymbols()); diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 5c17ec480..607c2de54 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -29,8 +29,6 @@ using u32 = uint32_t; namespace ShaderCache { -const auto shader_cache_dir = Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache"; -std::unordered_map> g_ud_storage; u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { u64 hash = 0; @@ -246,8 +244,9 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { } bool CheckShaderCache(std::string shader_id) { - std::filesystem::path spirv_cache_file_path = shader_cache_dir / (shader_id + ".spv"); - std::filesystem::path resources_file_path = shader_cache_dir / (shader_id + ".resources"); + std::filesystem::path spirv_cache_file_path = SHADER_CACHE_DIR / static_cast(shader_id + ".spv"); + std::filesystem::path resources_file_path = SHADER_CACHE_DIR / static_cast(shader_id + ".resources"); +; if (!std::filesystem::exists(spirv_cache_file_path)) { return false; @@ -282,14 +281,17 @@ bool CheckShaderCache(std::string shader_id) { } void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) { - std::string spirv_cache_filename = shader_id + ".spv"; - std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; + // read spirv + std::filesystem::path spirv_cache_filename = shader_id + ".spv"; + std::filesystem::path spirv_cache_file_path = SHADER_CACHE_DIR / spirv_cache_filename; Common::FS::IOFile spirv_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Read); spv.resize(spirv_cache_file.GetSize() / sizeof(u32)); spirv_cache_file.Read(spv); spirv_cache_file.Close(); - std::filesystem::path resources_dump_file_path = shader_cache_dir / (shader_id + ".resources"); + // read resources + std::filesystem::path resource_dump_filename = shader_id + ".resources"; + std::filesystem::path resources_dump_file_path = SHADER_CACHE_DIR / resource_dump_filename; Common::FS::IOFile resources_dump_file(resources_dump_file_path, Common::FS::FileAccessMode::Read); @@ -305,13 +307,14 @@ void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) } void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized) { - std::string spirv_cache_filename = shader_id + ".spv"; - std::filesystem::path spirv_cache_file_path = shader_cache_dir / spirv_cache_filename; + std::filesystem::path spirv_cache_filename = shader_id + ".spv"; + std::filesystem::path spirv_cache_file_path = SHADER_CACHE_DIR / spirv_cache_filename; Common::FS::IOFile shader_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Write); shader_cache_file.WriteSpan(std::span(spv)); shader_cache_file.Close(); - std::filesystem::path resources_dump_file_path = shader_cache_dir / (shader_id + ".resources"); + std::filesystem::path resource_dump_filename = shader_id + ".resources"; + std::filesystem::path resources_dump_file_path = SHADER_CACHE_DIR / resource_dump_filename; Common::FS::IOFile resources_dump_file(resources_dump_file_path, Common::FS::FileAccessMode::Write); @@ -331,6 +334,7 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info &info) { ar << info.buffers; ar << info.images; ar << info.samplers; + ar << info.fmasks; } diff --git a/src/video_core/renderer_vulkan/shader_cache.h b/src/video_core/renderer_vulkan/shader_cache.h index 4df74e115..51b2b17ed 100644 --- a/src/video_core/renderer_vulkan/shader_cache.h +++ b/src/video_core/renderer_vulkan/shader_cache.h @@ -11,6 +11,8 @@ namespace ShaderCache { +#define SHADER_CACHE_DIR (Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache" / "portable") + u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec); void SerializeInfo( std::ostream& info_serialized, Shader::Info& info); diff --git a/src/video_core/renderer_vulkan/shader_cache_serialization.h b/src/video_core/renderer_vulkan/shader_cache_serialization.h index bbe0bf97c..b4ee48d2f 100644 --- a/src/video_core/renderer_vulkan/shader_cache_serialization.h +++ b/src/video_core/renderer_vulkan/shader_cache_serialization.h @@ -5,27 +5,12 @@ #include #include #include + +#include "common/serialization.h" #include "shader_recompiler/info.h" namespace cereal { -// boost::small_vector -template -void save(Archive& ar, boost::container::small_vector const& smallVector) { - ar(static_cast(smallVector.size())); - for (auto const& element : smallVector) - ar(element); -} - -template -void load(Archive& ar, boost::container::small_vector& smallVector) { - std::uint32_t elementCount; - ar(elementCount); - smallVector.resize(elementCount); - for (auto& element : smallVector) - ar(element); -} - // Shader::Info::UserDataMask template void serialize(Archive& ar, Shader::Info::UserDataMask& mask) { @@ -89,4 +74,10 @@ void serialize(Archive& ar, Shader::SamplerResource& sampler) { static_cast(sampler.disable_aniso)); } +// Shader::FMaskResource +template +void serialize(Archive& ar, Shader::FMaskResource& fmask) { + cereal::binary_data(reinterpret_cast(&fmask), sizeof(fmask)); +} + } \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 42d1d8c75..904ac96f7 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -516,13 +516,13 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim std::vector spv; std::string shader_id = std::to_string(::ShaderCache::CalculateSpecializationHash(spec)); if (::ShaderCache::CheckShaderCache(shader_id)) { - LOG_INFO(Render_Vulkan, "Loaded shader {} {:#x} {} from cache", info.stage, info.pgm_hash, - perm_idx != 0 ? "(permutation)" : ""); + LOG_INFO(Render_Vulkan, "Loaded shader {} {:#x} {}from cache", info.stage, info.pgm_hash, + perm_idx != 0 ? "(permutation) " : ""); ::ShaderCache::GetShader(shader_id, info, spv); info.RefreshFlatBuf(); } else { - LOG_INFO(Render_Vulkan, "Shader {} {:#x} {} not in cache", info.stage, - info.pgm_hash, perm_idx != 0 ? "(permutation)" : ""); + LOG_INFO(Render_Vulkan, "Shader {} {:#x} {}not in cache", info.stage, + info.pgm_hash, perm_idx != 0 ? "(permutation) " : ""); const auto ir_program = Shader::TranslateProgram(code, pools, info, runtime_info, profile); spv = Shader::Backend::SPIRV::EmitSPIRV(profile, runtime_info, ir_program, binding); std::ostringstream info_serialized; @@ -533,8 +533,8 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim DumpShader(spv, info.pgm_hash, info.stage, perm_idx, "spv"); - LOG_INFO(Render_Vulkan, "Compiled shader {} {:#x} {} and saved it to cache", info.stage, info.pgm_hash, - perm_idx != 0 ? "(permutation)" : ""); + LOG_INFO(Render_Vulkan, "Compiled shader {} {:#x} {}and saved it to cache", info.stage, info.pgm_hash, + perm_idx != 0 ? "(permutation) " : ""); } vk::ShaderModule module; From 4a3bbb37475750bb4c7c5a8f1e724638ae8e7694 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Tue, 15 Jul 2025 20:38:56 +0200 Subject: [PATCH 35/41] forgot file --- src/common/serialization.h | 29 +++++++++++++++++++ .../renderer_vulkan/shader_cache.cpp | 2 -- 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 src/common/serialization.h diff --git a/src/common/serialization.h b/src/common/serialization.h new file mode 100644 index 000000000..63c112021 --- /dev/null +++ b/src/common/serialization.h @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include + +namespace cereal { + +// boost::small_vector +template +void save(Archive& ar, boost::container::small_vector const& smallVector) { + ar(make_size_tag(static_cast(smallVector.size()))); + for (auto const& element : smallVector) + ar(element); +} + +template +void load(Archive& ar, boost::container::small_vector& smallVector) { + u32 elementCount; + ar(make_size_tag(elementCount)); + smallVector.resize(elementCount); + for (auto& element : smallVector) + ar(element); +} + +} \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 607c2de54..e4f14d699 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -281,7 +281,6 @@ bool CheckShaderCache(std::string shader_id) { } void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) { - // read spirv std::filesystem::path spirv_cache_filename = shader_id + ".spv"; std::filesystem::path spirv_cache_file_path = SHADER_CACHE_DIR / spirv_cache_filename; Common::FS::IOFile spirv_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Read); @@ -289,7 +288,6 @@ void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) spirv_cache_file.Read(spv); spirv_cache_file.Close(); - // read resources std::filesystem::path resource_dump_filename = shader_id + ".resources"; std::filesystem::path resources_dump_file_path = SHADER_CACHE_DIR / resource_dump_filename; Common::FS::IOFile resources_dump_file(resources_dump_file_path, From 0da10ee0916f6e6ffd352888c6525fe120ee22a5 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Tue, 15 Jul 2025 22:12:43 +0200 Subject: [PATCH 36/41] clang + deserialize + flattened_udbuf + fs_interpolation --- src/common/serialization.h | 8 +-- src/shader_recompiler/info.h | 2 + .../renderer_vulkan/shader_cache.cpp | 27 ++++++-- .../shader_cache_serialization.h | 63 ++++++++----------- 4 files changed, 55 insertions(+), 45 deletions(-) diff --git a/src/common/serialization.h b/src/common/serialization.h index 63c112021..a05a1acab 100644 --- a/src/common/serialization.h +++ b/src/common/serialization.h @@ -3,21 +3,21 @@ #pragma once -#include #include +#include #include namespace cereal { // boost::small_vector -template +template void save(Archive& ar, boost::container::small_vector const& smallVector) { ar(make_size_tag(static_cast(smallVector.size()))); for (auto const& element : smallVector) ar(element); } -template +template void load(Archive& ar, boost::container::small_vector& smallVector) { u32 elementCount; ar(make_size_tag(elementCount)); @@ -26,4 +26,4 @@ void load(Archive& ar, boost::container::small_vector& smallVector) ar(element); } -} \ No newline at end of file +} // namespace cereal \ No newline at end of file diff --git a/src/shader_recompiler/info.h b/src/shader_recompiler/info.h index bb5c88584..6942368e5 100644 --- a/src/shader_recompiler/info.h +++ b/src/shader_recompiler/info.h @@ -93,6 +93,8 @@ struct ImageResource { using ImageResourceList = boost::container::small_vector; struct SamplerResource { + SamplerResource() = default; + std::variant sampler; u32 associated_image : 4; u32 disable_aniso : 1; diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index e4f14d699..903b5dc33 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -29,7 +29,6 @@ using u32 = uint32_t; namespace ShaderCache { - u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { u64 hash = 0; @@ -244,9 +243,11 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { } bool CheckShaderCache(std::string shader_id) { - std::filesystem::path spirv_cache_file_path = SHADER_CACHE_DIR / static_cast(shader_id + ".spv"); - std::filesystem::path resources_file_path = SHADER_CACHE_DIR / static_cast(shader_id + ".resources"); -; + std::filesystem::path spirv_cache_file_path = + SHADER_CACHE_DIR / static_cast(shader_id + ".spv"); + std::filesystem::path resources_file_path = + SHADER_CACHE_DIR / static_cast(shader_id + ".resources"); + ; if (!std::filesystem::exists(spirv_cache_file_path)) { return false; @@ -324,7 +325,7 @@ void AddShader(std::string shader_id, std::vector spv, std::ostream& info_s resources_dump_file.Close(); } -void SerializeInfo(std::ostream& info_serialized, Shader::Info &info) { +void SerializeInfo(std::ostream& info_serialized, Shader::Info& info) { cereal::BinaryOutputArchive ar(info_serialized); ar << info.ud_mask; ar << info.gs_copy_data; @@ -333,7 +334,23 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info &info) { ar << info.images; ar << info.samplers; ar << info.fmasks; + // srt info + ar << info.flattened_ud_buf; + ar << info.fs_interpolation; +} +void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { + cereal::BinaryInputArchive ar(info_serialized); + ar >> info.ud_mask; + ar >> info.gs_copy_data; + ar >> info.uses_patches; + ar >> info.buffers; + ar >> info.images; + ar >> info.samplers; + ar >> info.fmasks; + // srt info + ar >> info.flattened_ud_buf; + ar >> info.fs_interpolation; } } // namespace ShaderCache \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache_serialization.h b/src/video_core/renderer_vulkan/shader_cache_serialization.h index b4ee48d2f..b1a5aaf5c 100644 --- a/src/video_core/renderer_vulkan/shader_cache_serialization.h +++ b/src/video_core/renderer_vulkan/shader_cache_serialization.h @@ -2,82 +2,73 @@ // SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#include #include -#include #include - +#include +#include #include "common/serialization.h" #include "shader_recompiler/info.h" +#include "shader_recompiler/info.h" + namespace cereal { // Shader::Info::UserDataMask -template +template void serialize(Archive& ar, Shader::Info::UserDataMask& mask) { ar(mask.mask); } // Shader::CopyShaderData -template +template void serialize(Archive& ar, Shader::CopyShaderData& data) { - ar( - data.attr_map, - data.num_attrs, - data.output_vertices); + ar(data.attr_map, data.num_attrs, data.output_vertices); } // AmdGPU::Buffer -template +template void serialize(Archive& ar, AmdGpu::Buffer& buffer) { ar(cereal::binary_data(reinterpret_cast(&buffer), sizeof(buffer))); // is base_adress cacheable? } // Shader::BufferResource -template -void serialize(Archive& ar, Shader::BufferResource& buffer) -{ - ar( - buffer.sharp_idx, - buffer.used_types, - buffer.inline_cbuf, - buffer.buffer_type, - buffer.instance_attrib, - buffer.is_written, - buffer.is_formatted); +template +void serialize(Archive& ar, Shader::BufferResource& buffer) { + ar(buffer.sharp_idx, buffer.used_types, buffer.inline_cbuf, buffer.buffer_type, + buffer.instance_attrib, buffer.is_written, buffer.is_formatted); } // Shader::ImageResource -template -void serialize(Archive& ar, Shader::ImageResource& image) -{ - ar( - image.sharp_idx, - image.is_depth, - image.is_atomic, - image.is_array, - image.is_written, - image.is_r128); +template +void serialize(Archive& ar, Shader::ImageResource& image) { + ar(image.sharp_idx, image.is_depth, image.is_atomic, image.is_array, image.is_written, + image.is_r128); } // AmdGpu::Sampler -template +template void serialize(Archive& ar, AmdGpu::Sampler& sampler) { ar(cereal::binary_data(reinterpret_cast(&sampler), sizeof(sampler))); } // Shader::SamplerResource -template +template void serialize(Archive& ar, Shader::SamplerResource& sampler) { ar(sampler.sampler); - ar(static_cast(sampler.associated_image), - static_cast(sampler.disable_aniso)); + ar(static_cast(sampler.associated_image), static_cast(sampler.disable_aniso)); } // Shader::FMaskResource -template +template void serialize(Archive& ar, Shader::FMaskResource& fmask) { cereal::binary_data(reinterpret_cast(&fmask), sizeof(fmask)); } -} \ No newline at end of file +// Shader::Info::Interpolation +template +void serialize(Archive& ar, Shader::Info::Interpolation& interpolation) { + ar(interpolation.primary, interpolation.auxiliary); +} +} // namespace cereal \ No newline at end of file From da818336666f4851b0ac45b3f925e9f534a3c78a Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Fri, 18 Jul 2025 21:20:28 +0200 Subject: [PATCH 37/41] new storage mechanism --- src/common/config.cpp | 14 +- src/common/config.h | 2 + src/emulator.cpp | 4 + .../renderer_vulkan/shader_cache.cpp | 134 ++++++++---------- src/video_core/renderer_vulkan/shader_cache.h | 12 +- .../shader_cache_serialization.h | 1 + 6 files changed, 91 insertions(+), 76 deletions(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index 6f8563377..4f298ba54 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -71,6 +71,7 @@ static bool readbackLinearImagesEnabled = false; static bool directMemoryAccessEnabled = false; static bool shouldDumpShaders = false; static bool shouldPatchShaders = false; +static bool shaderCachePreloadEnabled = false; static u32 vblankDivider = 1; static bool isFullscreen = false; static std::string fullscreenMode = "Windowed"; @@ -106,7 +107,7 @@ u32 m_language = 1; // english static std::string trophyKey = ""; // Expected number of items in the config file -static constexpr u64 total_entries = 54; +static constexpr u64 total_entries = 55; bool allowHDR() { return isHDRAllowed; @@ -289,6 +290,10 @@ bool patchShaders() { return shouldPatchShaders; } +bool getShaderCachePreloadEnabled() { + return shaderCachePreloadEnabled; +} + bool isRdocEnabled() { return rdocEnable; } @@ -405,6 +410,10 @@ void setDumpShaders(bool enable) { shouldDumpShaders = enable; } +void setShaderCachePreloadEnabled(bool enable) { + shaderCachePreloadEnabled = enable; +} + void setVkValidation(bool enable) { vkValidation = enable; } @@ -664,6 +673,7 @@ void load(const std::filesystem::path& path) { toml::find_or(gpu, "directMemoryAccess", directMemoryAccessEnabled); shouldDumpShaders = toml::find_or(gpu, "dumpShaders", shouldDumpShaders); shouldPatchShaders = toml::find_or(gpu, "patchShaders", shouldPatchShaders); + shaderCachePreloadEnabled = toml::find_or(gpu, "shaderCachePreload", shaderCachePreloadEnabled); vblankDivider = toml::find_or(gpu, "vblankDivider", vblankDivider); isFullscreen = toml::find_or(gpu, "Fullscreen", isFullscreen); fullscreenMode = toml::find_or(gpu, "FullscreenMode", fullscreenMode); @@ -837,6 +847,7 @@ void save(const std::filesystem::path& path) { data["GPU"]["directMemoryAccess"] = directMemoryAccessEnabled; data["GPU"]["dumpShaders"] = shouldDumpShaders; data["GPU"]["patchShaders"] = shouldPatchShaders; + data["GPU"]["shaderCachePreload"] = shaderCachePreloadEnabled; data["GPU"]["vblankDivider"] = vblankDivider; data["GPU"]["Fullscreen"] = isFullscreen; data["GPU"]["FullscreenMode"] = fullscreenMode; @@ -940,6 +951,7 @@ void setDefaultValues() { directMemoryAccessEnabled = false; shouldDumpShaders = false; shouldPatchShaders = false; + shaderCachePreloadEnabled = false; vblankDivider = 1; isFullscreen = false; fullscreenMode = "Windowed"; diff --git a/src/common/config.h b/src/common/config.h index e54425676..8cbe1b627 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -56,6 +56,8 @@ bool directMemoryAccess(); void setDirectMemoryAccess(bool enable); bool dumpShaders(); void setDumpShaders(bool enable); +bool getShaderCachePreloadEnabled(); +void setShaderCachePreloadEnabled(); u32 vblankDiv(); void setVblankDiv(u32 value); bool getisTrophyPopupDisabled(); diff --git a/src/emulator.cpp b/src/emulator.cpp index 705060252..8553dba7f 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -257,10 +257,14 @@ void Emulator::Run(std::filesystem::path file, const std::vector ar } VideoCore::SetOutputDir(mount_captures_dir, id); + // Initialize shader cache if (!std::filesystem::exists(SHADER_CACHE_DIR)) { std::filesystem::create_directories(SHADER_CACHE_DIR); LOG_INFO(Loader, "Created shader cache directory: {}", SHADER_CACHE_DIR.string()); } + ShaderCache::InitializeShaderCache(); + LOG_INFO(Loader, "{} shaders in cache {}", ShaderCache::shader_registry.size(), Config::getShaderCachePreloadEnabled() != 0 ? "(preloaded) " : ""); + // Initialize kernel and library facilities. Libraries::InitHLELibs(&linker->GetHLESymbols()); diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 903b5dc33..01edfd9dc 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -17,6 +17,7 @@ #include "common/io_file.h" #include "common/logging/log.h" #include "common/path_util.h" +#include "common/config.h" #include "shader_recompiler/info.h" #include "shader_recompiler/ir/type.h" #include "shader_recompiler/specialization.h" @@ -243,86 +244,77 @@ u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { } bool CheckShaderCache(std::string shader_id) { - std::filesystem::path spirv_cache_file_path = - SHADER_CACHE_DIR / static_cast(shader_id + ".spv"); - std::filesystem::path resources_file_path = - SHADER_CACHE_DIR / static_cast(shader_id + ".resources"); - ; - - if (!std::filesystem::exists(spirv_cache_file_path)) { - return false; + if (Config::getShaderCachePreloadEnabled()) { + return shader_cache.contains(shader_id); } - if (!std::filesystem::exists(resources_file_path)) { - return false; + return shader_registry.contains(shader_id); +} + +void InitializeShaderCache() { + if (!std::filesystem::exists(SHADER_CACHE_REGISTRY_PATH) || std::filesystem::file_size(SHADER_CACHE_REGISTRY_PATH) == 0) { + return; } - - Common::FS::IOFile spirv_file(spirv_cache_file_path, Common::FS::FileAccessMode::Read); - Common::FS::IOFile resources_file(resources_file_path, Common::FS::FileAccessMode::Read); - - const bool spirv_valid = spirv_file.IsOpen() && spirv_file.GetSize() > 0; - const bool resources_valid = resources_file.IsOpen() && resources_file.GetSize() > 0; - - spirv_file.Close(); - resources_file.Close(); - - if (!spirv_valid || !resources_valid) { - LOG_WARNING(Render_Vulkan, "Invalid cache file for shader with ID: {}", shader_id); - if (std::filesystem::exists(spirv_cache_file_path)) { - std::filesystem::remove(spirv_cache_file_path); + std::ifstream registry_file(SHADER_CACHE_REGISTRY_PATH, std::ios::binary); + cereal::BinaryInputArchive registry_ar(registry_file); + while (registry_file.tellg() < std::filesystem::file_size(SHADER_CACHE_REGISTRY_PATH)) { + std::string shader_key; + u64 offset; + registry_ar(shader_key, offset); + shader_registry[shader_key] = offset; + } + if (Config::getShaderCachePreloadEnabled()) { + std::ifstream blob_file(SHADER_CACHE_BLOB_PATH, std::ios::binary); + for (auto const& [shader_key, offset] : shader_registry) { + blob_file.seekg(offset, std::ios::beg); + { + cereal::BinaryInputArchive blob_ar(blob_file); + std::string resources; + std::vector spv; + blob_ar(spv, resources); + shader_cache[shader_key] = std::make_pair(spv, resources); + } } - if (std::filesystem::exists(resources_file_path)) { - std::filesystem::remove(resources_file_path); - } - return false; } - - LOG_INFO(Render_Vulkan, "Found shader with ID {} in the cache", shader_id); - return true; } void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) { - std::filesystem::path spirv_cache_filename = shader_id + ".spv"; - std::filesystem::path spirv_cache_file_path = SHADER_CACHE_DIR / spirv_cache_filename; - Common::FS::IOFile spirv_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Read); - spv.resize(spirv_cache_file.GetSize() / sizeof(u32)); - spirv_cache_file.Read(spv); - spirv_cache_file.Close(); + std::string resources; + if (Config::getShaderCachePreloadEnabled()) { + auto& [spv_cached, resources] = shader_cache[shader_id]; + spv = spv_cached; + } + else { + std::ifstream blob_file(SHADER_CACHE_BLOB_PATH, std::ios::binary); + blob_file.seekg(shader_registry[shader_id], std::ios::beg); + cereal::BinaryInputArchive ar(blob_file); - std::filesystem::path resource_dump_filename = shader_id + ".resources"; - std::filesystem::path resources_dump_file_path = SHADER_CACHE_DIR / resource_dump_filename; - Common::FS::IOFile resources_dump_file(resources_dump_file_path, - Common::FS::FileAccessMode::Read); - - std::vector resources_data; - resources_data.resize(resources_dump_file.GetSize()); - resources_dump_file.Read(resources_data); - resources_dump_file.Close(); - - std::istringstream combined_stream(std::string(resources_data.begin(), resources_data.end())); - - std::istringstream info_stream; - info_stream.str(std::string(resources_data.begin(), resources_data.end())); -} - -void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized) { - std::filesystem::path spirv_cache_filename = shader_id + ".spv"; - std::filesystem::path spirv_cache_file_path = SHADER_CACHE_DIR / spirv_cache_filename; - Common::FS::IOFile shader_cache_file(spirv_cache_file_path, Common::FS::FileAccessMode::Write); - shader_cache_file.WriteSpan(std::span(spv)); - shader_cache_file.Close(); - - std::filesystem::path resource_dump_filename = shader_id + ".resources"; - std::filesystem::path resources_dump_file_path = SHADER_CACHE_DIR / resource_dump_filename; - Common::FS::IOFile resources_dump_file(resources_dump_file_path, - Common::FS::FileAccessMode::Write); - - if (std::ostringstream* info_oss = dynamic_cast(&info_serialized)) { - std::string info_data = info_oss->str(); - resources_dump_file.WriteSpan(std::span(info_data.data(), info_data.size())); + ar(spv, resources); } - resources_dump_file.Close(); + std::istringstream info_serialized(resources); + DeserializeInfo(info_serialized, info); +} + +void AddShader(std::string shader_id, std::vector spv, std::ostringstream& info_serialized) { + std::ofstream registry_file(SHADER_CACHE_REGISTRY_PATH, std::ios::binary | std::ios::app); + registry_file.seekp(0, std::ios::end); + cereal::BinaryOutputArchive reg_ar(registry_file); + + std::ofstream blob_file(SHADER_CACHE_BLOB_PATH, std::ios::binary | std::ios::app); + blob_file.seekp(0, std::ios::end); + cereal::BinaryOutputArchive blob_ar(blob_file); + + u64 offset = static_cast(blob_file.tellp()); + reg_ar(shader_id, offset); + + std::string info_blob = info_serialized.str(); + blob_ar(spv, info_blob); + + shader_registry[shader_id] = offset; + if (Config::getShaderCachePreloadEnabled()) { + shader_cache[shader_id] = std::make_pair(spv, info_blob); + } } void SerializeInfo(std::ostream& info_serialized, Shader::Info& info) { @@ -334,8 +326,6 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info& info) { ar << info.images; ar << info.samplers; ar << info.fmasks; - // srt info - ar << info.flattened_ud_buf; ar << info.fs_interpolation; } @@ -348,8 +338,6 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { ar >> info.images; ar >> info.samplers; ar >> info.fmasks; - // srt info - ar >> info.flattened_ud_buf; ar >> info.fs_interpolation; } diff --git a/src/video_core/renderer_vulkan/shader_cache.h b/src/video_core/renderer_vulkan/shader_cache.h index 51b2b17ed..2d8a3818c 100644 --- a/src/video_core/renderer_vulkan/shader_cache.h +++ b/src/video_core/renderer_vulkan/shader_cache.h @@ -6,20 +6,28 @@ #include #include #include + #include "shader_recompiler/info.h" -#include +#include "shader_recompiler/specialization.h" +#include "common/elf_info.h" namespace ShaderCache { #define SHADER_CACHE_DIR (Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache" / "portable") +#define SHADER_CACHE_BLOB_PATH (SHADER_CACHE_DIR / (std::string{Common::ElfInfo::Instance().GameSerial()} + "_shaders.bin")) +#define SHADER_CACHE_REGISTRY_PATH (SHADER_CACHE_DIR / (std::string{Common::ElfInfo::Instance().GameSerial()} + "_shaders_registry.bin")) + +inline std::map shader_registry; // shader_key:offset +inline std::map, std::string>> shader_cache; // only used when preload active // shader_key:blob u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec); +void InitializeShaderCache(); void SerializeInfo( std::ostream& info_serialized, Shader::Info& info); void DeserializeInfo(std::istream& info_serialized, Shader::Info& info); bool CheckShaderCache(std::string shader_id); void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv); -void AddShader(std::string shader_id, std::vector spv, std::ostream& info_serialized); +void AddShader(std::string shader_id, std::vector spv, std::ostringstream& info_serialized); } // namespace ShaderCache diff --git a/src/video_core/renderer_vulkan/shader_cache_serialization.h b/src/video_core/renderer_vulkan/shader_cache_serialization.h index b1a5aaf5c..d83230efa 100644 --- a/src/video_core/renderer_vulkan/shader_cache_serialization.h +++ b/src/video_core/renderer_vulkan/shader_cache_serialization.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "common/serialization.h" #include "shader_recompiler/info.h" From e522918ee49fde587e9a6a623e2b1874c674ae4a Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 19 Jul 2025 10:56:21 +0200 Subject: [PATCH 38/41] fixed minor bug --- src/video_core/renderer_vulkan/shader_cache.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 01edfd9dc..db318c948 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -281,8 +281,9 @@ void InitializeShaderCache() { void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) { std::string resources; if (Config::getShaderCachePreloadEnabled()) { - auto& [spv_cached, resources] = shader_cache[shader_id]; - spv = spv_cached; + auto& entry = shader_cache[shader_id]; + spv = entry.first; + resources = entry.second; } else { std::ifstream blob_file(SHADER_CACHE_BLOB_PATH, std::ios::binary); From f456df76a9f34b1ed6e6bf2a801de7fb969493a3 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 19 Jul 2025 11:27:46 +0200 Subject: [PATCH 39/41] more cached values --- .../renderer_vulkan/shader_cache.cpp | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index db318c948..13c947b9e 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -328,6 +328,36 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info& info) { ar << info.samplers; ar << info.fmasks; ar << info.fs_interpolation; + ar << info.tess_consts_ptr_base; + ar << info.tess_consts_dword_offset; + ar << info.stage; + ar << info.l_stage; + ar << info.pgm_hash; + ar << info.pgm_base; // ! + ar << info.has_storage_images; + ar << info.has_discard; + ar << info.has_image_gather; + ar << info.has_image_query; + ar << info.uses_buffer_atomic_float_min_max; + ar << info.uses_image_atomic_float_min_max; + ar << info.uses_lane_id; + ar << info.uses_group_quad; + ar << info.uses_group_ballot; + ar << info.shared_types; + ar << info.uses_fp16; + ar << info.uses_fp64; + ar << info.uses_pack_10_11_11; + ar << info.uses_unpack_10_11_11; + ar << info.uses_buffer_int64_atomics; + ar << info.uses_shared_int64_atomics; + ar << info.stores_tess_level_outer; + ar << info.stores_tess_level_inner; + ar << info.translation_failed; + ar << info.mrt_mask; + ar << info.has_fetch_shader; + ar << info.fetch_shader_sgpr_base; // ! + ar << info.readconst_types; + ar << info.uses_dma; } void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { @@ -340,6 +370,36 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { ar >> info.samplers; ar >> info.fmasks; ar >> info.fs_interpolation; + ar >> info.tess_consts_ptr_base; + ar >> info.tess_consts_dword_offset; + ar >> info.stage; + ar >> info.l_stage; + ar >> info.pgm_hash; + ar >> info.pgm_base; // ! + ar >> info.has_storage_images; + ar >> info.has_discard; + ar >> info.has_image_gather; + ar >> info.has_image_query; + ar >> info.uses_buffer_atomic_float_min_max; + ar >> info.uses_image_atomic_float_min_max; + ar >> info.uses_lane_id; + ar >> info.uses_group_quad; + ar >> info.uses_group_ballot; + ar >> info.shared_types; + ar >> info.uses_fp16; + ar >> info.uses_fp64; + ar >> info.uses_pack_10_11_11; + ar >> info.uses_unpack_10_11_11; + ar >> info.uses_buffer_int64_atomics; + ar >> info.uses_shared_int64_atomics; + ar >> info.stores_tess_level_outer; + ar >> info.stores_tess_level_inner; + ar >> info.translation_failed; + ar >> info.mrt_mask; + ar >> info.has_fetch_shader; + ar >> info.fetch_shader_sgpr_base; // ! + ar >> info.readconst_types; + ar >> info.uses_dma; } } // namespace ShaderCache \ No newline at end of file From 95a81a13ed902771040a2022f52dddd2b4700219 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 19 Jul 2025 11:49:59 +0200 Subject: [PATCH 40/41] prevent readudbuf chrash --- src/video_core/renderer_vulkan/shader_cache.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index 13c947b9e..df895e684 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -358,6 +358,7 @@ void SerializeInfo(std::ostream& info_serialized, Shader::Info& info) { ar << info.fetch_shader_sgpr_base; // ! ar << info.readconst_types; ar << info.uses_dma; + ar << info.srt_info.flattened_bufsize_dw; } void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { @@ -400,6 +401,7 @@ void DeserializeInfo(std::istream& info_serialized, Shader::Info& info) { ar >> info.fetch_shader_sgpr_base; // ! ar >> info.readconst_types; ar >> info.uses_dma; + ar >> info.srt_info.flattened_bufsize_dw; } } // namespace ShaderCache \ No newline at end of file From 99cad6efa1770876b11988cf4e1fdcdf067d3756 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Sat, 19 Jul 2025 17:23:16 +0200 Subject: [PATCH 41/41] cleanup --- src/common/config.cpp | 7 ++++-- src/common/config.h | 2 +- src/common/serialization.h | 1 + src/emulator.cpp | 3 ++- .../renderer_vulkan/shader_cache.cpp | 25 ++++++------------- src/video_core/renderer_vulkan/shader_cache.h | 22 ++++++++++------ .../shader_cache_serialization.h | 5 ++-- .../renderer_vulkan/vk_pipeline_cache.cpp | 17 +++++++------ .../renderer_vulkan/vk_pipeline_cache.h | 3 ++- 9 files changed, 44 insertions(+), 41 deletions(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index da028f9b7..72569a99a 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -113,6 +113,7 @@ static constexpr u64 total_entries = 55; int getVolumeSlider() { return volumeSlider; } + bool allowHDR() { return isHDRAllowed; } @@ -682,7 +683,8 @@ void load(const std::filesystem::path& path) { toml::find_or(gpu, "directMemoryAccess", directMemoryAccessEnabled); shouldDumpShaders = toml::find_or(gpu, "dumpShaders", shouldDumpShaders); shouldPatchShaders = toml::find_or(gpu, "patchShaders", shouldPatchShaders); - shaderCachePreloadEnabled = toml::find_or(gpu, "shaderCachePreload", shaderCachePreloadEnabled); + shaderCachePreloadEnabled = + toml::find_or(gpu, "shaderCachePreload", shaderCachePreloadEnabled); vblankDivider = toml::find_or(gpu, "vblankDivider", vblankDivider); isFullscreen = toml::find_or(gpu, "Fullscreen", isFullscreen); fullscreenMode = toml::find_or(gpu, "FullscreenMode", fullscreenMode); @@ -1065,6 +1067,7 @@ analog_deadzone = rightjoystick, 2, 127 override_controller_color = false, 0, 0, 255 )"; } + std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id) { // Read configuration file of the game, and if it doesn't exist, generate it from default // If that doesn't exist either, generate that from getDefaultConfig() and try again @@ -1101,4 +1104,4 @@ std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id) { return config_file; } -} // namespace Config +} // namespace Config \ No newline at end of file diff --git a/src/common/config.h b/src/common/config.h index 1c5401c38..fee2fd3ac 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -143,4 +143,4 @@ void setDefaultValues(); // todo: name and function location pending std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id = ""); -}; // namespace Config +}; // namespace Config \ No newline at end of file diff --git a/src/common/serialization.h b/src/common/serialization.h index a05a1acab..efb50c889 100644 --- a/src/common/serialization.h +++ b/src/common/serialization.h @@ -5,6 +5,7 @@ #include #include + #include namespace cereal { diff --git a/src/emulator.cpp b/src/emulator.cpp index df57b96ca..edadac6fb 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -266,7 +266,8 @@ void Emulator::Run(std::filesystem::path file, const std::vector ar LOG_INFO(Loader, "Created shader cache directory: {}", SHADER_CACHE_DIR.string()); } ShaderCache::InitializeShaderCache(); - LOG_INFO(Loader, "{} shaders in cache {}", ShaderCache::shader_registry.size(), Config::getShaderCachePreloadEnabled() != 0 ? "(preloaded) " : ""); + LOG_INFO(Loader, "{} shaders in cache {}", ShaderCache::shader_registry.size(), + Config::getShaderCachePreloadEnabled() != 0 ? "(preloaded) " : ""); // Initialize kernel and library facilities. Libraries::InitHLELibs(&linker->GetHLESymbols()); diff --git a/src/video_core/renderer_vulkan/shader_cache.cpp b/src/video_core/renderer_vulkan/shader_cache.cpp index df895e684..8ff9a3006 100644 --- a/src/video_core/renderer_vulkan/shader_cache.cpp +++ b/src/video_core/renderer_vulkan/shader_cache.cpp @@ -1,33 +1,24 @@ // SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include +#include #include #include #include -#ifdef _WIN32 -#include -#else -#include -#include -#endif -#include + #include + +#include "common/config.h" #include "common/hash.h" #include "common/io_file.h" #include "common/logging/log.h" #include "common/path_util.h" -#include "common/config.h" +#include "shader_cache.h" #include "shader_recompiler/info.h" #include "shader_recompiler/ir/type.h" #include "shader_recompiler/specialization.h" #include "video_core/renderer_vulkan/shader_cache_serialization.h" -#include "shader_cache.h" - -using u64 = uint64_t; -using u32 = uint32_t; - namespace ShaderCache { u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec) { @@ -252,7 +243,8 @@ bool CheckShaderCache(std::string shader_id) { } void InitializeShaderCache() { - if (!std::filesystem::exists(SHADER_CACHE_REGISTRY_PATH) || std::filesystem::file_size(SHADER_CACHE_REGISTRY_PATH) == 0) { + if (!std::filesystem::exists(SHADER_CACHE_REGISTRY_PATH) || + std::filesystem::file_size(SHADER_CACHE_REGISTRY_PATH) == 0) { return; } std::ifstream registry_file(SHADER_CACHE_REGISTRY_PATH, std::ios::binary); @@ -284,8 +276,7 @@ void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv) auto& entry = shader_cache[shader_id]; spv = entry.first; resources = entry.second; - } - else { + } else { std::ifstream blob_file(SHADER_CACHE_BLOB_PATH, std::ios::binary); blob_file.seekg(shader_registry[shader_id], std::ios::beg); cereal::BinaryInputArchive ar(blob_file); diff --git a/src/video_core/renderer_vulkan/shader_cache.h b/src/video_core/renderer_vulkan/shader_cache.h index 2d8a3818c..975b8290e 100644 --- a/src/video_core/renderer_vulkan/shader_cache.h +++ b/src/video_core/renderer_vulkan/shader_cache.h @@ -7,27 +7,33 @@ #include #include +#include "common/elf_info.h" #include "shader_recompiler/info.h" #include "shader_recompiler/specialization.h" -#include "common/elf_info.h" namespace ShaderCache { -#define SHADER_CACHE_DIR (Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache" / "portable") -#define SHADER_CACHE_BLOB_PATH (SHADER_CACHE_DIR / (std::string{Common::ElfInfo::Instance().GameSerial()} + "_shaders.bin")) -#define SHADER_CACHE_REGISTRY_PATH (SHADER_CACHE_DIR / (std::string{Common::ElfInfo::Instance().GameSerial()} + "_shaders_registry.bin")) +#define SHADER_CACHE_DIR \ + (Common::FS::GetUserPath(Common::FS::PathType::ShaderDir) / "cache" / "portable") + +#define SHADER_CACHE_BLOB_PATH \ + (SHADER_CACHE_DIR / (std::string{Common::ElfInfo::Instance().GameSerial()} + "_shaders.bin")) + +#define SHADER_CACHE_REGISTRY_PATH \ + (SHADER_CACHE_DIR / \ + (std::string{Common::ElfInfo::Instance().GameSerial()} + "_shaders_registry.bin")) inline std::map shader_registry; // shader_key:offset -inline std::map, std::string>> shader_cache; // only used when preload active // shader_key:blob +inline std::map, std::string>> shader_cache; +// only used when preload active // shader_key:blob[spv,info] u64 CalculateSpecializationHash(const Shader::StageSpecialization& spec); void InitializeShaderCache(); -void SerializeInfo( - std::ostream& info_serialized, Shader::Info& info); +void SerializeInfo(std::ostream& info_serialized, Shader::Info& info); void DeserializeInfo(std::istream& info_serialized, Shader::Info& info); bool CheckShaderCache(std::string shader_id); void GetShader(std::string shader_id, Shader::Info& info, std::vector& spv); void AddShader(std::string shader_id, std::vector spv, std::ostringstream& info_serialized); -} // namespace ShaderCache +} // namespace ShaderCache \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/shader_cache_serialization.h b/src/video_core/renderer_vulkan/shader_cache_serialization.h index d83230efa..f3f5f22af 100644 --- a/src/video_core/renderer_vulkan/shader_cache_serialization.h +++ b/src/video_core/renderer_vulkan/shader_cache_serialization.h @@ -4,13 +4,12 @@ #include #include +#include #include #include #include -#include -#include "common/serialization.h" -#include "shader_recompiler/info.h" +#include "common/serialization.h" #include "shader_recompiler/info.h" namespace cereal { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index e0a50b101..3ceb1fc9b 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -497,12 +497,13 @@ bool PipelineCache::RefreshComputeKey() { vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::RuntimeInfo& runtime_info, std::span code, size_t perm_idx, - Shader::Backend::Bindings& binding, Shader::StageSpecialization spec) { + Shader::Backend::Bindings& binding, + Shader::StageSpecialization spec) { LOG_INFO(Render_Vulkan, "Compiling {} shader {:#x} {}", info.stage, info.pgm_hash, perm_idx != 0 ? "(permutation)" : ""); DumpShader(code, info.pgm_hash, info.stage, perm_idx, "bin"); - + std::string shader_name = GetShaderName(info.stage, info.pgm_hash, perm_idx); std::vector spv; @@ -513,8 +514,8 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim ::ShaderCache::GetShader(shader_id, info, spv); info.RefreshFlatBuf(); } else { - LOG_INFO(Render_Vulkan, "Shader {} {:#x} {}not in cache", info.stage, - info.pgm_hash, perm_idx != 0 ? "(permutation) " : ""); + LOG_INFO(Render_Vulkan, "Shader {} {:#x} {}not in cache", info.stage, info.pgm_hash, + perm_idx != 0 ? "(permutation) " : ""); const auto ir_program = Shader::TranslateProgram(code, pools, info, runtime_info, profile); spv = Shader::Backend::SPIRV::EmitSPIRV(profile, runtime_info, ir_program, binding); std::ostringstream info_serialized; @@ -524,9 +525,8 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim LOG_INFO(Render_Vulkan, "Shader ID: {}", shader_id); DumpShader(spv, info.pgm_hash, info.stage, perm_idx, "spv"); - - LOG_INFO(Render_Vulkan, "Compiled shader {} {:#x} {}and saved it to cache", info.stage, info.pgm_hash, - perm_idx != 0 ? "(permutation) " : ""); + LOG_INFO(Render_Vulkan, "Compiled shader {} {:#x} {}and saved it to cache", info.stage, + info.pgm_hash, perm_idx != 0 ? "(permutation) " : ""); } vk::ShaderModule module; @@ -561,7 +561,8 @@ PipelineCache::Result PipelineCache::GetProgram(Stage stage, LogicalStage l_stag auto start = binding; Shader::StageSpecialization spec = Shader::StageSpecialization(program->info, runtime_info, profile, start); - const auto module = CompileModule(program->info, runtime_info, params.code, 0, binding, spec); + const auto module = + CompileModule(program->info, runtime_info, params.code, 0, binding, spec); program->AddPermut(module, std::move(spec)); return std::make_tuple(&program->info, module, spec.fetch_shader_data, HashCombine(params.hash, 0)); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index c20d06a7b..cf78def7a 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -82,7 +82,8 @@ private: std::string_view ext); vk::ShaderModule CompileModule(Shader::Info& info, Shader::RuntimeInfo& runtime_info, std::span code, size_t perm_idx, - Shader::Backend::Bindings& binding, Shader::StageSpecialization spec); + Shader::Backend::Bindings& binding, + Shader::StageSpecialization spec); const Shader::RuntimeInfo& BuildRuntimeInfo(Shader::Stage stage, Shader::LogicalStage l_stage); private: