Compare commits

...

4 commits

Author SHA1 Message Date
riperiperi bec47ca57b
Merge 53ee267ba9 into a23d8cb92f 2024-05-09 09:06:12 +02:00
Marco Carvalho a23d8cb92f
Replace "List.ForEach" for "foreach" (#6783)
* Replace "List.ForEach" for "foreach"

* dotnet format

* Update Ptc.cs

* Update GpuContext.cs
2024-05-08 13:53:25 +02:00
riperiperi 53ee267ba9 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.
2024-02-03 14:01:00 +00:00
Gabriel A 6dcb867816 Limit remote closed session removal to SM service 2024-02-03 01:17:12 -03:00
3 changed files with 20 additions and 5 deletions

View file

@ -857,8 +857,14 @@ namespace ARMeilleure.Translation.PTC
Stopwatch sw = Stopwatch.StartNew();
threads.ForEach((thread) => thread.Start());
threads.ForEach((thread) => thread.Join());
foreach (var thread in threads)
{
thread.Start();
}
foreach (var thread in threads)
{
thread.Join();
}
threads.Clear();

View file

@ -322,6 +322,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;
}
/// <summary>
@ -1420,7 +1423,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;

View file

@ -395,8 +395,14 @@ namespace Ryujinx.Graphics.Gpu
{
Renderer.CreateSync(SyncNumber, strict);
SyncActions.ForEach(action => action.SyncPreAction(syncpoint));
SyncpointActions.ForEach(action => action.SyncPreAction(syncpoint));
foreach (var action in SyncActions)
{
action.SyncPreAction(syncpoint);
}
foreach (var action in SyncpointActions)
{
action.SyncPreAction(syncpoint);
}
SyncNumber++;