diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 40e7f83583..ce4b67fc19 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp @@ -391,6 +391,52 @@ IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b return result; } +void PrunePassthroughStores(IR::Program& program, const VaryingState& previous_stage_stores) { + if (program.stage != Stage::Geometry || program.is_geometry_passthrough) { + return; + } + VaryingState pruned; + for (size_t index = 0; index < program.info.passthrough.mask.size(); ++index) { + if (!program.info.passthrough.mask[index] || previous_stage_stores.mask[index]) { + continue; + } + const IR::Attribute attr{static_cast(index)}; + if (attr >= IR::Attribute::PositionX && attr <= IR::Attribute::PositionW) { + continue; + } + pruned.mask[index] = true; + } + if (pruned.mask.none()) { + return; + } + const auto erase_matching{[&pruned](IR::Block* block, IR::Opcode opcode, bool skip_used) { + auto it{block->begin()}; + while (it != block->end()) { + IR::Inst& inst{*it}; + if (inst.GetOpcode() != opcode || + !pruned.mask[static_cast(inst.Arg(0).Attribute())]) { + ++it; + continue; + } + if (skip_used && inst.HasUses()) { + ++it; + continue; + } + inst.Invalidate(); + it = block->Instructions().erase(it); + } + }}; + for (IR::Block* const block : program.post_order_blocks) { + erase_matching(block, IR::Opcode::SetAttribute, false); + } + for (IR::Block* const block : program.post_order_blocks) { + erase_matching(block, IR::Opcode::GetAttribute, true); + } + program.info.stores.mask &= ~pruned.mask; + program.info.loads.mask &= ~pruned.mask; + program.info.passthrough.mask &= ~pruned.mask; +} + void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& runtime_info) { auto& stores = program.info.stores; if (stores.Legacy()) { diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.h b/src/shader_recompiler/frontend/maxwell/translate_program.h index 23c7ba1bbf..d44814ecce 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.h +++ b/src/shader_recompiler/frontend/maxwell/translate_program.h @@ -29,6 +29,8 @@ namespace Shader::Maxwell { void ConvertLegacyToGeneric(IR::Program& program, const RuntimeInfo& runtime_info); +void PrunePassthroughStores(IR::Program& program, const VaryingState& previous_stage_stores); + // Maxwell v1 and older Nvidia cards don't support setting gl_Layer from non-geometry stages. // This creates a workaround by setting the layer as a generic output and creating a // passthrough geometry shader that reads the generic and sets the layer. diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index c07d6fbde2..68431c67e3 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -45,6 +45,7 @@ using Shader::Backend::SPIRV::EmitSPIRV; using Shader::Maxwell::ConvertLegacyToGeneric; using Shader::Maxwell::GenerateGeometryPassthrough; using Shader::Maxwell::MergeDualVertexPrograms; +using Shader::Maxwell::PrunePassthroughStores; using Shader::Maxwell::TranslateProgram; using VideoCommon::ComputeEnvironment; using VideoCommon::FileEnvironment; @@ -54,7 +55,7 @@ using VideoCommon::LoadPipelines; using VideoCommon::SerializePipeline; using Context = ShaderContext::Context; -constexpr u32 CACHE_VERSION = 17; +constexpr u32 CACHE_VERSION = 18; template auto MakeSpan(Container& container) { @@ -537,6 +538,9 @@ std::unique_ptr ShaderCache::CreateGraphicsPipeline( const size_t stage_index{index - 1}; infos[stage_index] = &program.info; + if (previous_program) { + PrunePassthroughStores(program, previous_program->info.stores); + } const auto runtime_info = MakeRuntimeInfo(key, program, previous_program, glasm_use_storage_buffers, use_glasm); switch (::Settings::values.renderer_backend.GetValue()) { case Settings::RendererBackend::OpenGL_GLSL: diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 854bef3192..606396529b 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -56,13 +56,14 @@ using Shader::Backend::SPIRV::EmitSPIRV; using Shader::Maxwell::ConvertLegacyToGeneric; using Shader::Maxwell::GenerateGeometryPassthrough; using Shader::Maxwell::MergeDualVertexPrograms; +using Shader::Maxwell::PrunePassthroughStores; using Shader::Maxwell::TranslateProgram; using VideoCommon::ComputeEnvironment; using VideoCommon::FileEnvironment; using VideoCommon::GenericEnvironment; using VideoCommon::GraphicsEnvironment; -constexpr u32 CACHE_VERSION = 20; +constexpr u32 CACHE_VERSION = 21; constexpr size_t VULKAN_CACHE_FLUSH_PIPELINES = 128; constexpr size_t VULKAN_CACHE_FLUSH_MIN_SECONDS = 30; constexpr std::array VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'}; @@ -838,6 +839,9 @@ std::unique_ptr PipelineCache::CreateGraphicsPipeline( const size_t stage_index{index - 1}; infos[stage_index] = &program.info; + if (previous_stage) { + PrunePassthroughStores(program, previous_stage->info.stores); + } const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage, device)}; ConvertLegacyToGeneric(program, runtime_info); const std::vector code{EmitSPIRV(profile, runtime_info, program, binding)};