From 53ee267ba9d38e43e5df56a6d6d1f5fee4fdfad8 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Sat, 3 Feb 2024 03:51:02 +0000 Subject: [PATCH] GPU: Clear fragment enable bit on draw In a few games, depth only draws seem to have random fragment shaders attached to them. In PLA, this isn't too much of an issue as it has rasterize discard enabled, though it still binds resources for an unused fragment stage. However, in Assassin's Creed 2, an alpha testing shader is left bound during the majority of the occlusion culling pass, leading pretty much every fragment to fail and all geometry to be culled out. This PR clears the fragment stage enable bit after each draw, as the commands set by the guest should re-enable it if it's being used. This means that stale fragment shader bindings are removed during depth-only draws, which can avoid incorrect results if the fragment shader could discard. All guest GPU drivers seem to religiously set the enable bit for the fragment shader, other stages are better managed (they never stay accidentally enabled). I traced all the registers AC2 wrote when it did the incorrect draws, and this is the only conclusion I could come to. It's worth testing this in a large number of games. It's entirely possible that this flag is reset in another place, or under specific conditions. OpenGL games are a good one to make sure still work. --- src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index 2b65b45605..7a000f5ddc 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -319,6 +319,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _context.Renderer.Pipeline.BeginTransformFeedback(_drawState.Topology); _prevTfEnable = true; } + + // Unset fragment enable bits for shader, as they need to be reset each draw. + _state.State.ShaderState[(int)ShaderStage.Fragment].Control &= ~(uint)1; } /// @@ -1398,7 +1401,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed for (int index = 0; index < 6; index++) { - var shader = _state.State.ShaderState[index]; + ref var shader = ref _state.State.ShaderState[index]; if (!shader.UnpackEnable() && index != 1) { continue;