[video_core] Skip fragment shaders with known issues on non-NVIDIA drivers (#4503)
Some checks failed
tx-src / sources (push) Has been cancelled
Check Strings / check-strings (push) Has been cancelled

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Skip fragment shaders using a pattern that is not supported by non-NVIDIA drivers.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4503
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
This commit is contained in:
MaranBr 2026-10-08 23:11:34 +02:00 • committed by crueter
parent 3cdd2ce141
commit 67bada77f8
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
7 changed files with 59 additions and 22 deletions

View file

@ -657,9 +657,6 @@ struct Values {
SwitchableSetting<bool> emulate_bgr565{linkage, false, "emulate_bgr565", SwitchableSetting<bool> emulate_bgr565{linkage, false, "emulate_bgr565",
Category::RendererHacks}; Category::RendererHacks};
SwitchableSetting<bool> rescale_hack{linkage, false, "rescale_hack",
Category::RendererHacks};
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders", SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
Category::RendererHacks}; Category::RendererHacks};

View file

@ -279,12 +279,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
"quality and performance consistency in some games.")); "quality and performance consistency in some games."));
INSERT(Settings, fix_bloom_effects, tr("Fix bloom effects"), tr("Removes bloom in Burnout.")); INSERT(Settings, fix_bloom_effects, tr("Fix bloom effects"), tr("Removes bloom in Burnout."));
INSERT(Settings, rescale_hack, tr("Enable Legacy Rescale Pass"),
tr("May fix rescale issues in some games by relying on behavior from the previous "
"implementation.\n"
"Legacy behavior workaround that fixes line artifacts on AMD and Intel GPUs, and "
"grey texture flicker on Nvidia GPUs in Luigis Mansion 3."));
// Renderer (Extensions) // Renderer (Extensions)
INSERT(Settings, dyna_state, tr("Extended Dynamic State"), INSERT(Settings, dyna_state, tr("Extended Dynamic State"),
tr("Controls the number of features that can be used in Extended Dynamic State.\n" tr("Controls the number of features that can be used in Extended Dynamic State.\n"

View file

@ -301,7 +301,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
Optimization::GlobalMemoryToStorageBufferPass(program, normalized_host_info); Optimization::GlobalMemoryToStorageBufferPass(program, normalized_host_info);
Optimization::TexturePass(env, program, normalized_host_info); Optimization::TexturePass(env, program, normalized_host_info);
if (Settings::values.resolution_info.active || Settings::values.rescale_hack.GetValue()) { if (Settings::values.resolution_info.active) {
Optimization::RescalingPass(program); Optimization::RescalingPass(program);
} }
Optimization::DeadCodeEliminationPass(program); Optimization::DeadCodeEliminationPass(program);

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -28,6 +31,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
void LayerPass(IR::Program& program, const HostTranslateInfo& host_info); void LayerPass(IR::Program& program, const HostTranslateInfo& host_info);
void VendorWorkaroundPass(IR::Program& program); void VendorWorkaroundPass(IR::Program& program);
void VerificationPass(const IR::Program& program); void VerificationPass(const IR::Program& program);
bool HasBrokenPattern(const IR::Program& program);
// Dual Vertex // Dual Vertex
void VertexATransformPass(IR::Program& program); void VertexATransformPass(IR::Program& program);

View file

@ -67,18 +67,11 @@ void VisitMark(IR::Block& block, IR::Inst& inst) {
if (must_patch_outside) { if (must_patch_outside) {
const auto it{IR::Block::InstructionList::s_iterator_to(inst)}; const auto it{IR::Block::InstructionList::s_iterator_to(inst)};
IR::IREmitter ir{block, it}; IR::IREmitter ir{block, it};
if (Settings::values.rescale_hack.GetValue()) { IR::Inst* const new_inst{&*block.PrependNewInst(it, inst)};
const IR::F32 new_inst{&*block.PrependNewInst(it, inst)}; const IR::F32 new_bitcast{ir.ConvertUToF(32, 32, IR::Value{new_inst})};
const IR::F32 up_factor{ir.FPRecip(ir.ResolutionDownFactor())}; const IR::F32 up_factor{ir.FPRecip(ir.ResolutionDownFactor())};
const IR::Value converted{ir.FPMul(new_inst, up_factor)}; const IR::Value converted{ir.FPMul(new_bitcast, up_factor)};
inst.ReplaceUsesWith(converted); inst.ReplaceUsesWith(converted);
} else {
IR::Inst* const new_inst{&*block.PrependNewInst(it, inst)};
const IR::F32 new_bitcast{ir.ConvertUToF(32, 32, IR::Value{new_inst})};
const IR::F32 up_factor{ir.FPRecip(ir.ResolutionDownFactor())};
const IR::Value converted{ir.FPMul(new_bitcast, up_factor)};
inst.ReplaceUsesWith(converted);
}
} }
break; break;
} }

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -76,4 +79,44 @@ void VendorWorkaroundPass(IR::Program& program) {
} }
} }
bool HasBrokenPattern(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 } // namespace Shader::Optimization

View file

@ -23,6 +23,7 @@
#include "shader_recompiler/environment.h" #include "shader_recompiler/environment.h"
#include "shader_recompiler/frontend/maxwell/control_flow.h" #include "shader_recompiler/frontend/maxwell/control_flow.h"
#include "shader_recompiler/frontend/maxwell/translate_program.h" #include "shader_recompiler/frontend/maxwell/translate_program.h"
#include "shader_recompiler/ir_opt/passes.h"
#include "shader_recompiler/program_header.h" #include "shader_recompiler/program_header.h"
#include "video_core/engines/kepler_compute.h" #include "video_core/engines/kepler_compute.h"
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
@ -826,6 +827,11 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
programs[index] = MergeDualVertexPrograms(program_va, program_vb, env); programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);
} }
if (device.GetDriverID() != VK_DRIVER_ID_NVIDIA_PROPRIETARY && Shader::Optimization::HasBrokenPattern(programs[index])) {
LOG_WARNING(Render_Vulkan, "0x{:016x}: Skipping shader with known issues", key.unique_hashes[index]);
return nullptr;
}
if (Settings::values.dump_guest_shaders) { if (Settings::values.dump_guest_shaders) {
env.Dump(hash, key.unique_hashes[index]); env.Dump(hash, key.unique_hashes[index]);
} }