From bf3b6886a0f80402a3208cb1f348cf8b5ac66555 Mon Sep 17 00:00:00 2001 From: MaranBr Date: Thu, 1 Oct 2026 09:04:40 -0400 Subject: [PATCH] Skip unsupported fragment shader pattern on non-NVIDIA drivers --- src/shader_recompiler/ir_opt/passes.h | 1 + .../ir_opt/vendor_workaround_pass.cpp | 40 +++++++++++++++++++ .../renderer_vulkan/vk_pipeline_cache.cpp | 6 +++ 3 files changed, 47 insertions(+) diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h index 1e637cb23c..2efdc67b4e 100644 --- a/src/shader_recompiler/ir_opt/passes.h +++ b/src/shader_recompiler/ir_opt/passes.h @@ -27,6 +27,7 @@ void PositionPass(Environment& env, IR::Program& program); void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info); void LayerPass(IR::Program& program, const HostTranslateInfo& host_info); void VendorWorkaroundPass(IR::Program& program); +bool HasProblematicFragmentShaderPattern(const IR::Program& program); void VerificationPass(const IR::Program& program); // Dual Vertex diff --git a/src/shader_recompiler/ir_opt/vendor_workaround_pass.cpp b/src/shader_recompiler/ir_opt/vendor_workaround_pass.cpp index 08c658cb81..47adfdd86d 100644 --- a/src/shader_recompiler/ir_opt/vendor_workaround_pass.cpp +++ b/src/shader_recompiler/ir_opt/vendor_workaround_pass.cpp @@ -76,4 +76,44 @@ void VendorWorkaroundPass(IR::Program& program) { } } +bool HasProblematicFragmentShaderPattern(const IR::Program& program) { + if (program.stage != Stage::Fragment) { + return false; + } + for (const IR::Block* block : program.post_order_blocks) { + for (const IR::Inst& inst : block->Instructions()) { + switch (inst.GetOpcode()) { + case IR::Opcode::ShuffleIndex: + case IR::Opcode::ShuffleUp: + case IR::Opcode::ShuffleDown: + case IR::Opcode::ShuffleButterfly: + break; + default: + continue; + } + const IR::Value shuffle_arg{inst.Arg(0)}; + if (shuffle_arg.IsImmediate()) { + continue; + } + const IR::Inst* bitcast{shuffle_arg.InstRecursive()}; + if (!bitcast || bitcast->GetOpcode() != IR::Opcode::BitCastU32F32) { + continue; + } + const IR::Value bitcast_arg{bitcast->Arg(0)}; + if (bitcast_arg.IsImmediate()) { + continue; + } + const IR::Inst* attribute{bitcast_arg.InstRecursive()}; + if (!attribute || attribute->GetOpcode() != IR::Opcode::GetAttribute) { + continue; + } + const IR::Attribute attr{attribute->Arg(0).Attribute()}; + if (attr == IR::Attribute::PositionX || attr == IR::Attribute::PositionY) { + return true; + } + } + } + return false; +} + } // namespace Shader::Optimization diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 642b9fa223..53b87ca289 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -23,6 +23,7 @@ #include "shader_recompiler/environment.h" #include "shader_recompiler/frontend/maxwell/control_flow.h" #include "shader_recompiler/frontend/maxwell/translate_program.h" +#include "shader_recompiler/ir_opt/passes.h" #include "shader_recompiler/program_header.h" #include "video_core/engines/kepler_compute.h" #include "video_core/engines/maxwell_3d.h" @@ -826,6 +827,11 @@ std::unique_ptr PipelineCache::CreateGraphicsPipeline( programs[index] = MergeDualVertexPrograms(program_va, program_vb, env); } + if (device.GetDriverID() != VK_DRIVER_ID_NVIDIA_PROPRIETARY && Shader::Optimization::HasProblematicFragmentShaderPattern(programs[index])) { + LOG_WARNING(Render_Vulkan, "0x{:016x}: Skipping incompatible fragment shader.", key.unique_hashes[index]); + return nullptr; + } + if (Settings::values.dump_guest_shaders) { env.Dump(hash, key.unique_hashes[index]); }