video_core: Fix transferability issue in vulkan shader disk cache (#1770)

This commit is contained in:
PabloMK7 2026-02-22 22:41:24 +01:00 committed by GitHub
parent 43cecd1692
commit 4c054ff2e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 26 additions and 47 deletions

View File

@ -713,7 +713,10 @@ bool ShaderDiskCache::InitVSCache(const std::atomic_bool& stop_loading,
// New config entry, usually always taken unless there is duplicate entries on the cache
// for some reason.
auto shader_it = programmable_vertex_cache.find(entry->spirv_entry_id);
// We cannot trust the SPIRV entry ID anymore if we are regenerating.
auto shader_it = regenerate_file
? programmable_vertex_cache.end()
: programmable_vertex_cache.find(entry->spirv_entry_id);
if (shader_it != programmable_vertex_cache.end()) {
// The config entry uses a SPIRV entry that was already compiled (this is the usual
// path when the cache doesn't need to be re-generated).
@ -722,40 +725,7 @@ bool ShaderDiskCache::InitVSCache(const std::atomic_bool& stop_loading,
entry->spirv_entry_id);
iter_config->second = &shader_it->second;
if (regenerate_file) {
// In case we are re-generating the cache, we could only have gotten here if the
// SPIRV was already compiled and cached, so only cache the config.
AppendVSConfig(*regenerate_file, *entry, curr.Id());
}
bool new_program = known_vertex_programs.emplace(entry->program_entry_id).second;
if (new_program && regenerate_file) {
// If the vertex program is not known at this point we need to save it as well.
// This can happen to config entries that compile to the same SPIRV but use
// different program code (maybe because garbage data was in the program
// buffer).
auto program_it = pending_programs.find(entry->program_entry_id);
if (program_it == pending_programs.end()) {
// Program code not in disk cache, should never happen.
LOG_ERROR(Render_Vulkan, "Missing program code for config entry");
programmable_vertex_map.erase(iter_config);
continue;
}
// This is very rare so no need to use the LRU.
auto program_cache_entry = vs_cache.ReadAt(program_it->second);
const VSProgramEntry* program_entry;
if (!program_cache_entry.Valid() ||
program_cache_entry.Type() != CacheEntryType::VS_PROGRAM ||
!(program_entry = program_cache_entry.Payload<VSProgramEntry>()) ||
program_entry->version != VSProgramEntry::EXPECTED_VERSION) {
MALFORMED_DISK_CACHE;
}
AppendVSProgram(*regenerate_file, *program_entry, entry->program_entry_id);
}
known_vertex_programs.emplace(entry->program_entry_id).second;
} else {
// Cached SPIRV not found, need to recompile.
@ -859,8 +829,7 @@ bool ShaderDiskCache::InitVSCache(const std::atomic_bool& stop_loading,
// Asign the SPIRV shader to the config
iter_config->second = &iter_prog->second;
LOG_DEBUG(Render_Vulkan, " linked with new SPIRV {:016X}.",
entry->spirv_entry_id);
LOG_DEBUG(Render_Vulkan, " linked with SPIRV {:016X}.", entry->spirv_entry_id);
}
}
}
@ -1017,7 +986,7 @@ bool ShaderDiskCache::InitFSCache(const std::atomic_bool& stop_loading,
tot_callback_index, "Fragment Shader");
}
LOG_DEBUG(Render_Vulkan, "Linking {:016X}.", curr.Id());
LOG_DEBUG(Render_Vulkan, "Linking {:016X}.", offset.first);
if (fragment_shaders.find(offset.first) != fragment_shaders.end()) {
// SPIRV of config was already compiled, no need to regenerate
@ -1250,7 +1219,7 @@ bool ShaderDiskCache::InitGSCache(const std::atomic_bool& stop_loading,
tot_callback_index, "Geometry Shader");
}
LOG_DEBUG(Render_Vulkan, "Linking {:016X}.", curr.Id());
LOG_DEBUG(Render_Vulkan, "Linking {:016X}.", offset.first);
if (fixed_geometry_shaders.find(offset.first) != fixed_geometry_shaders.end()) {
// SPIRV of config was already compiled, no need to regenerate
@ -1400,6 +1369,11 @@ bool ShaderDiskCache::InitPLCache(const std::atomic_bool& stop_loading,
// if any is missing we cannot build it.
std::array<Shader*, MAX_SHADER_STAGES> shaders;
LOG_DEBUG(Render_Vulkan, " uses VS: {:016X}, FS: {:016X}, GS: {:016X}",
entry->pl_info.shader_ids[ProgramType::VS],
entry->pl_info.shader_ids[ProgramType::FS],
entry->pl_info.shader_ids[ProgramType::GS]);
if (entry->pl_info.shader_ids[ProgramType::VS]) {
auto it_vs =
programmable_vertex_map.find(entry->pl_info.shader_ids[ProgramType::VS]);

View File

@ -103,7 +103,8 @@ private:
struct VSConfigEntry {
static constexpr u8 EXPECTED_VERSION = 0;
u8 version; // Surprise tool that can help us later
u64 version; // Surprise tool that can help us later
u64 program_entry_id;
u64 spirv_entry_id;
Pica::Shader::Generator::PicaVSConfig vs_config;
@ -113,34 +114,38 @@ private:
struct VSProgramEntry {
static constexpr u8 EXPECTED_VERSION = 0;
u8 version; // Surprise tool that can help us later
u64 version; // Surprise tool that can help us later
u32 program_len;
u32 swizzle_len;
Pica::ProgramCode program_code;
Pica::SwizzleData swizzle_code;
};
static_assert(sizeof(VSProgramEntry) == 32780);
static_assert(sizeof(VSProgramEntry) == 32784);
struct FSConfigEntry {
static constexpr u8 EXPECTED_VERSION = 0;
u8 version; // Surprise tool that can help us later
u64 version; // Surprise tool that can help us later
Pica::Shader::FSConfig fs_config;
};
static_assert(sizeof(FSConfigEntry) == 276);
static_assert(sizeof(FSConfigEntry) == 280);
struct GSConfigEntry {
static constexpr u8 EXPECTED_VERSION = 0;
u8 version; // Surprise tool that can help us later
u64 version; // Surprise tool that can help us later
Pica::Shader::Generator::PicaFixedGSConfig gs_config;
};
static_assert(sizeof(GSConfigEntry) == 44);
static_assert(sizeof(GSConfigEntry) == 48);
struct PLConfigEntry {
static constexpr u8 EXPECTED_VERSION = 0;
u8 version; // Surprise tool that can help us later
u64 version; // Surprise tool that can help us later
StaticPipelineInfo pl_info;
};
static_assert(sizeof(PLConfigEntry) == 152);