perf(shader): cache pixel export masks (#288)

This commit is contained in:
999sian
2026-07-17 02:17:39 +01:00
committed by GitHub
parent 7494792249
commit 6b1abc1a38
3 changed files with 74 additions and 25 deletions
+11 -25
View File
@@ -5937,13 +5937,14 @@ public static partial class AgcExports
// Every bound color target the shader exports to. Deferred renderers
// draw a multi-render-target G-buffer (up to eight slots) in one pass.
// Fall back to slot 0 if we cannot match any export to a bound target.
var pixelColorExportMasks = pixelState.Program.PixelColorExportMasks;
var allBoundTargets = GetRenderTargets(state.CxRegisters);
// At most 8 slots; a manual filter avoids the per-draw LINQ iterator/
// closure allocations. Slots are distinct, so sorting by slot is stable.
var selectedTargets = new List<RenderTargetDescriptor>(allBoundTargets.Count);
foreach (var target in allBoundTargets)
{
if (HasPixelColorExport(pixelState, target.Slot))
if (GetPixelColorExportMask(pixelColorExportMasks, target.Slot) != 0)
{
selectedTargets.Add(target);
}
@@ -5966,7 +5967,7 @@ public static partial class AgcExports
{
TraceAgcShader(
$"agc.mrt_filter ps=0x{pixelShaderAddress:X16} " +
$"bound=[{string.Join(",", allBoundTargets.Select(t => $"s{t.Slot}:0x{t.Address:X}:exp{(HasPixelColorExport(pixelState, t.Slot) ? 1 : 0)}"))}] " +
$"bound=[{string.Join(",", allBoundTargets.Select(t => $"s{t.Slot}:0x{t.Address:X}:exp{(GetPixelColorExportMask(pixelColorExportMasks, t.Slot) != 0 ? 1 : 0)}"))}] " +
$"kept={renderTargets.Length}");
}
@@ -6166,7 +6167,7 @@ public static partial class AgcExports
DecodeDepthTarget(state.CxRegisters),
guestTargets,
ApplyTransparentPremultipliedFillClear(
CreateRenderState(state.CxRegisters, renderTargets, pixelState),
CreateRenderState(state.CxRegisters, renderTargets, pixelColorExportMasks),
textures,
vertexInputs,
pixelEvaluation.InitialScalarRegisters),
@@ -6410,26 +6411,10 @@ public static partial class AgcExports
return true;
}
private static bool HasPixelColorExport(Gen5ShaderState state, uint target) =>
GetPixelColorExportMask(state, target) != 0;
private static uint GetPixelColorExportMask(Gen5ShaderState state, uint target)
{
// Called per render target (twice per draw via CreateRenderState +
// HasPixelColorExport); a manual scan avoids the per-call LINQ iterator
// and closure allocations. Same result as the previous
// Select/OfType/Where/Aggregate chain.
var mask = 0u;
foreach (var instruction in state.Program.Instructions)
{
if (instruction.Control is Gen5ExportControl export && export.Target == target)
{
mask |= export.EnableMask & 0xFu;
}
}
return mask;
}
private static uint GetPixelColorExportMask(uint packedMasks, uint target) =>
target < ColorTargetCount
? (packedMasks >> (int)(target * 4)) & 0xFu
: 0;
private static uint GetInterpolatedAttributeCount(Gen5ShaderState state)
{
@@ -6627,7 +6612,7 @@ public static partial class AgcExports
private static GuestRenderState CreateRenderState(
IReadOnlyDictionary<uint, uint> registers,
IReadOnlyList<RenderTargetDescriptor> targets,
Gen5ShaderState pixelState)
uint pixelColorExportMasks)
{
if (targets.Count == 0)
{
@@ -6642,7 +6627,8 @@ public static partial class AgcExports
var blend = DecodeBlendState(registers, target.Slot);
return blend with
{
WriteMask = blend.WriteMask & GetPixelColorExportMask(pixelState, target.Slot),
WriteMask = blend.WriteMask &
GetPixelColorExportMask(pixelColorExportMasks, target.Slot),
};
}).ToArray(),
scissor,