From 7fa87a1d9e15fc527653ec7abc3365e3badf9e7e Mon Sep 17 00:00:00 2001 From: ParantezTech <12572227+par274@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:52:06 +0300 Subject: [PATCH] [AGC] Share the interpolant mapping computation of both mapping variants --- .../Agc/AgcExports.ShaderState.cs | 128 +++++++++++------- 1 file changed, 77 insertions(+), 51 deletions(-) diff --git a/src/SharpEmu.Libs/Agc/AgcExports.ShaderState.cs b/src/SharpEmu.Libs/Agc/AgcExports.ShaderState.cs index 07dcd96..b3f576d 100644 --- a/src/SharpEmu.Libs/Agc/AgcExports.ShaderState.cs +++ b/src/SharpEmu.Libs/Agc/AgcExports.ShaderState.cs @@ -658,47 +658,7 @@ public static partial class AgcExports { var source = BinaryPrimitives.ReadUInt32LittleEndian(inputWords[(inputIndex * sizeof(uint))..]); var hasMask = TryFindOutputSemantic(outputWords, source, out var mask); - - var mode = (source >> 20) & 0x3u; - uint flags; - if (mode == 0) - { - flags = (((source >> 24) & 0x1u) | (hasMask ? 0u : 1u)) << 5; - flags = ApplyInterpolantTwoBitField(flags, source >> 28, 8); - } - else - { - flags = ((source << 4) & 0x0300_0000u) + 0x0008_0000u; - if (mode == 2) - { - flags &= 0xFFEF_FFDFu; - flags |= hasMask ? ((~(mask & source) >> 16) & 0x20u) : 0x20u; - flags = ApplyInterpolantTwoBitField(flags, source >> 30, 8); - flags = ApplyInterpolantTwoBitField(flags, source >> 30, 21); - } - else - { - if (hasMask) - { - var masked = mask & source; - flags = (flags & 0xFFFF_FFDFu) | ((masked >> 15) & 0x20u); - flags ^= 0x20u; - flags = (flags & 0xFFEF_FFFFu) | ((~masked >> 1) & 0x0010_0000u); - } - else - { - flags |= 0x0010_0020u; - } - - flags = ApplyInterpolantTwoBitField(flags, source >> 28, 8); - flags = ApplyInterpolantTwoBitField(flags, source >> 30, 21); - } - } - - flags = hasMask - ? ApplyInterpolantFinalMask(flags, source, mask) - : flags & 0xFFFF_FBE0u; - SetInterpolantRegister(registers, inputIndex, flags); + SetInterpolantRegister(registers, inputIndex, InterpolantMapping2Value(source, hasMask, mask)); } } finally @@ -778,6 +738,81 @@ public static partial class AgcExports TryWriteUInt32(ctx, destinationAddress + 8, outputPrimitiveOffset) && TryWriteUInt32(ctx, destinationAddress + 12, outputPrimitiveValue); } + private static uint InterpolantMapping2Value(uint source, bool hasMask, uint mask) + { + var mode = (source >> 20) & 0x3u; + uint flags; + if (mode == 0) + { + flags = (((source >> 24) & 0x1u) | (hasMask ? 0u : 1u)) << 5; + flags = ApplyInterpolantTwoBitField(flags, source >> 28, 8); + } + else + { + flags = ((source << 4) & 0x0300_0000u) + 0x0008_0000u; + if (mode == 2) + { + flags &= 0xFFEF_FFDFu; + flags |= hasMask ? ((~(mask & source) >> 16) & 0x20u) : 0x20u; + flags = ApplyInterpolantTwoBitField(flags, source >> 30, 8); + flags = ApplyInterpolantTwoBitField(flags, source >> 30, 21); + } + else + { + if (hasMask) + { + var masked = mask & source; + flags = (flags & 0xFFFF_FFDFu) | ((masked >> 15) & 0x20u); + flags ^= 0x20u; + flags = (flags & 0xFFEF_FFFFu) | ((~masked >> 1) & 0x0010_0000u); + } + else + { + flags |= 0x0010_0020u; + } + + flags = ApplyInterpolantTwoBitField(flags, source >> 28, 8); + flags = ApplyInterpolantTwoBitField(flags, source >> 30, 21); + } + } + + return hasMask + ? ApplyInterpolantFinalMask(flags, source, mask) + : flags & 0xFFFF_FBE0u; + } + + private static uint InterpolantMappingValue(uint psWord, uint? gsWord) + { + var value = (psWord & 0x0030_0000u) != 0 + ? CreateInterpolantF16Value(psWord, gsWord) + : CreateInterpolantNonF16Value(psWord, gsWord.HasValue); + return gsWord is { } matched + ? CreateInterpolantMappingValue(value, psWord, matched) + : CreateInterpolantDefaultParamValue(value, psWord); + } + + internal static uint[] ComputeInterpolantMapping(ReadOnlySpan pixelInputs, ReadOnlySpan vertexOutputs, bool secondVariant) + { + var registers = new uint[InterpolantRegisterCount]; + for (var index = 0; index < registers.Length; index++) + { + registers[index] = (uint)index; + } + + var outputBytes = System.Runtime.InteropServices.MemoryMarshal.AsBytes(vertexOutputs); + var count = Math.Min(pixelInputs.Length, InterpolantRegisterCount); + for (var index = 0; index < count; index++) + { + var input = pixelInputs[index]; + var matched = TryFindOutputSemantic(outputBytes, input, out var output); + registers[index] = secondVariant + ? InterpolantMapping2Value(input, matched, output) + : InterpolantMappingValue(input, matched ? output : null); + } + + return registers; + } + private static uint ApplyInterpolantTwoBitField(uint value, uint field, int shift) { var mask = 0x3u << shift; @@ -880,16 +915,7 @@ public static partial class AgcExports { var psWord = BinaryPrimitives.ReadUInt32LittleEndian(psWords[(psIndex * sizeof(uint))..]); uint? gsWord = TryFindOutputSemantic(gsWords, psWord, out var candidate) ? candidate : null; - - var value = (psWord & 0x0030_0000u) != 0 - ? CreateInterpolantF16Value(psWord, gsWord) - : CreateInterpolantNonF16Value(psWord, gsWord.HasValue); - SetInterpolantRegister( - registers, - psIndex, - gsWord is { } matched - ? CreateInterpolantMappingValue(value, psWord, matched) - : CreateInterpolantDefaultParamValue(value, psWord)); + SetInterpolantRegister(registers, psIndex, InterpolantMappingValue(psWord, gsWord)); } } finally