Merge pull request #206 from cheezwiz7899/diskshadercachefix3

This commit is contained in:
cheezwiz7899
2026-05-09 15:35:03 +10:00
committed by GitHub
@@ -11,9 +11,9 @@
#include "common/bit_cast.h"
#include "common/cityhash.h"
#include "common/settings.h"
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/settings.h"
#include "common/thread_worker.h"
#include "core/core.h"
#include "shader_recompiler/backend/spirv/emit_spirv.h"
@@ -62,7 +62,8 @@ auto MakeSpan(Container& container) {
return std::span(container.data(), container.size());
}
Shader::OutputTopology MaxwellToOutputTopology(Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology topology) {
Shader::OutputTopology MaxwellToOutputTopology(
Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology topology) {
switch (topology) {
case Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology::Points:
return Shader::OutputTopology::PointList;
@@ -73,7 +74,8 @@ Shader::OutputTopology MaxwellToOutputTopology(Tegra::Engines::Maxwell3D::Regs::
}
}
Shader::CompareFunction MaxwellToCompareFunction(Tegra::Engines::Maxwell3D::Regs::ComparisonOp comparison) {
Shader::CompareFunction MaxwellToCompareFunction(
Tegra::Engines::Maxwell3D::Regs::ComparisonOp comparison) {
switch (comparison) {
case Tegra::Engines::Maxwell3D::Regs::ComparisonOp::Never_D3D:
case Tegra::Engines::Maxwell3D::Regs::ComparisonOp::Never_GL:
@@ -109,7 +111,8 @@ Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribut
return Shader::AttributeType::Disabled;
}
switch (attr.Type()) {
case Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::UnusedEnumDoNotUseBecauseItWillGoAway:
case Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::
UnusedEnumDoNotUseBecauseItWillGoAway:
ASSERT_MSG(false, "Invalid vertex attribute type!");
return Shader::AttributeType::Disabled;
case Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::SNorm:
@@ -189,7 +192,8 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program
info.convert_depth_mode = gl_ndc;
}
if (key.state.dynamic_vertex_input) {
for (size_t index = 0; index < Tegra::Engines::Maxwell3D::Regs::NumVertexAttributes; ++index) {
for (size_t index = 0; index < Tegra::Engines::Maxwell3D::Regs::NumVertexAttributes;
++index) {
info.generic_input_types[index] = AttributeType(key.state, index);
}
} else {
@@ -419,13 +423,16 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
.support_conditional_barrier = device.SupportsConditionalBarriers(),
};
if (device.GetMaxVertexInputAttributes() < Tegra::Engines::Maxwell3D::Regs::NumVertexAttributes) {
if (device.GetMaxVertexInputAttributes() <
Tegra::Engines::Maxwell3D::Regs::NumVertexAttributes) {
LOG_WARNING(Render_Vulkan, "maxVertexInputAttributes is too low: {} < {}",
device.GetMaxVertexInputAttributes(), Tegra::Engines::Maxwell3D::Regs::NumVertexAttributes);
device.GetMaxVertexInputAttributes(),
Tegra::Engines::Maxwell3D::Regs::NumVertexAttributes);
}
if (device.GetMaxVertexInputBindings() < Tegra::Engines::Maxwell3D::Regs::NumVertexArrays) {
LOG_WARNING(Render_Vulkan, "maxVertexInputBindings is too low: {} < {}",
device.GetMaxVertexInputBindings(), Tegra::Engines::Maxwell3D::Regs::NumVertexArrays);
device.GetMaxVertexInputBindings(),
Tegra::Engines::Maxwell3D::Regs::NumVertexArrays);
}
// Apply user's Extended Dynamic State setting
@@ -449,6 +456,10 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
}
PipelineCache::~PipelineCache() {
// Drain all pending SerializePipeline tasks before the serialization_thread
// member is destroyed.
serialization_thread.WaitForRequests();
if (use_vulkan_pipeline_cache && !vulkan_pipeline_cache_filename.empty()) {
SerializeVulkanPipelineCache(vulkan_pipeline_cache_filename, vulkan_pipeline_cache,
CACHE_VERSION);
@@ -597,6 +608,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
auto pipeline{CreateComputePipeline(pools, key, env_, state.statistics.get(), false)};
std::scoped_lock lock{state.mutex};
if (pipeline) {
compute_pipeline_last_use[pipeline.get()] = scheduler.CurrentTick();
compute_cache.emplace(key, std::move(pipeline));
}
++state.built;
@@ -622,7 +634,12 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
(key.state.extended_dynamic_state_3_enables != 0) !=
dynamic_features.has_extended_dynamic_state_3_enables ||
(key.state.dynamic_vertex_input != 0) != dynamic_features.has_dynamic_vertex_input ||
(key.state.xfb_enabled != 0) != dynamic_features.has_transform_feedback) {
(key.state.xfb_enabled != 0 && !dynamic_features.has_transform_feedback)) {
// NOTE: xfb_enabled uses a unidirectional check. It encodes both a
// device capability AND per-pipeline runtime state. We only reject
// the pipeline if it actively requires XFB but the host device
// does not support it
LOG_WARNING(Render_Vulkan, "Skipping cached graphics pipeline: EDS feature mismatch");
return;
}
workers.QueueWork([this, key, envs_ = std::move(envs), &state, &callback]() mutable {
@@ -636,6 +653,12 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
std::scoped_lock lock{state.mutex};
if (pipeline) {
// Initialize last-use frame for disk-loaded pipelines so they
// survive EvictOldPipelines() calls before their first use.
// Without this, pipelines loaded from disk have no entry in
// graphics_pipeline_last_use and are immediately evicted on
// any memory pressure event.
graphics_pipeline_last_use[pipeline.get()] = scheduler.CurrentTick();
graphics_cache.emplace(key, std::move(pipeline));
}
++state.built;
@@ -723,8 +746,9 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
Shader::IR::Program* layer_source_program{};
for (size_t index = 0; index < Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram; ++index) {
const bool is_emulated_stage = layer_source_program != nullptr &&
index == static_cast<u32>(Tegra::Engines::Maxwell3D::Regs::ShaderType::Geometry);
const bool is_emulated_stage =
layer_source_program != nullptr &&
index == static_cast<u32>(Tegra::Engines::Maxwell3D::Regs::ShaderType::Geometry);
if (key.unique_hashes[index] == 0 && is_emulated_stage) {
auto topology = MaxwellToOutputTopology(key.state.topology);
programs[index] = GenerateGeometryPassthrough(pools.inst, pools.block, host_info,
@@ -762,10 +786,11 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
const Shader::IR::Program* previous_stage{};
Shader::Backend::Bindings binding;
for (size_t index = uses_vertex_a && uses_vertex_b ? 1 : 0; index < Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram;
++index) {
const bool is_emulated_stage = layer_source_program != nullptr &&
index == static_cast<u32>(Tegra::Engines::Maxwell3D::Regs::ShaderType::Geometry);
for (size_t index = uses_vertex_a && uses_vertex_b ? 1 : 0;
index < Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram; ++index) {
const bool is_emulated_stage =
layer_source_program != nullptr &&
index == static_cast<u32>(Tegra::Engines::Maxwell3D::Regs::ShaderType::Geometry);
if (key.unique_hashes[index] == 0 && !is_emulated_stage) {
continue;
}
@@ -831,7 +856,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline() {
return pipeline;
}
serialization_thread.QueueWork([this, key = graphics_key, envs = std::move(environments.envs)] {
boost::container::static_vector<const GenericEnvironment*, Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram>
boost::container::static_vector<const GenericEnvironment*,
Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram>
env_ptrs;
for (size_t index = 0; index < Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram; ++index) {
if (key.unique_hashes[index] != 0) {