Merge #935 (pr/pixel-system-inputs)
This commit is contained in:
commit
2f3ee0935c
|
|
@ -13,6 +13,9 @@ public static partial class Gen5SpirvTranslator
|
|||
private readonly HashSet<uint> _flatParameterAttributes = [];
|
||||
private readonly Dictionary<int, uint> _barycentricInputs = [];
|
||||
private uint _interpolationSampleId;
|
||||
private uint _frontFacingInput;
|
||||
private uint _ancillaryLayerInput;
|
||||
private uint _sampleMaskInput;
|
||||
private const uint InterpolateAtCentroid = 76;
|
||||
private const uint InterpolateAtSample = 77;
|
||||
private const uint InterpolateAtOffset = 78;
|
||||
|
|
@ -90,6 +93,86 @@ public static partial class Gen5SpirvTranslator
|
|||
}
|
||||
}
|
||||
|
||||
// FRONT_FACE and ANCILLARY are VGPRs the hardware fills for pixel shaders that enable them.
|
||||
// UE writes volume textures one slice per instance and has the pixel shader read the slice
|
||||
// back out of ANCILLARY[28:16] (the render target array index); leaving that register zero
|
||||
// bakes every slice of a color grading LUT from the blue=0 slice.
|
||||
private void DeclarePixelSystemInputs()
|
||||
{
|
||||
var enabledInputs = _pixelInputAddress & _pixelInputEnable;
|
||||
if ((enabledInputs & (1u << 12)) != 0)
|
||||
{
|
||||
_frontFacingInput = _module.AddGlobalVariable(
|
||||
_module.TypePointer(SpirvStorageClass.Input, _boolType), SpirvStorageClass.Input);
|
||||
_module.AddDecoration(_frontFacingInput, SpirvDecoration.BuiltIn, (uint)SpirvBuiltIn.FrontFacing);
|
||||
_interfaces.Add(_frontFacingInput);
|
||||
}
|
||||
|
||||
if ((enabledInputs & (1u << 13)) != 0)
|
||||
{
|
||||
_module.AddExtension("SPV_EXT_shader_viewport_index_layer");
|
||||
_module.AddCapability(SpirvCapability.ShaderViewportIndexLayerExt);
|
||||
_ancillaryLayerInput = _module.AddGlobalVariable(
|
||||
_module.TypePointer(SpirvStorageClass.Input, _uintType), SpirvStorageClass.Input);
|
||||
_module.AddDecoration(_ancillaryLayerInput, SpirvDecoration.BuiltIn, (uint)SpirvBuiltIn.Layer);
|
||||
_module.AddDecoration(_ancillaryLayerInput, SpirvDecoration.Flat);
|
||||
_interfaces.Add(_ancillaryLayerInput);
|
||||
}
|
||||
|
||||
if ((enabledInputs & (1u << 14)) != 0)
|
||||
{
|
||||
var maskArray = _module.TypeArray(_intType, 1);
|
||||
_sampleMaskInput = _module.AddGlobalVariable(
|
||||
_module.TypePointer(SpirvStorageClass.Input, maskArray), SpirvStorageClass.Input);
|
||||
_module.AddDecoration(_sampleMaskInput, SpirvDecoration.BuiltIn, (uint)SpirvBuiltIn.SampleMask);
|
||||
_module.AddDecoration(_sampleMaskInput, SpirvDecoration.Flat);
|
||||
_interfaces.Add(_sampleMaskInput);
|
||||
}
|
||||
}
|
||||
|
||||
// Front facing reads as 1.0f and back facing as 0, which satisfies both the float greater-than
|
||||
// and the integer not-equal tests compilers emit for it.
|
||||
private uint LoadFrontFaceInput() => _module.AddInstruction(
|
||||
SpirvOp.Select, _uintType, Load(_boolType, _frontFacingInput), UInt(0x3F800000u), UInt(0));
|
||||
|
||||
private uint LoadAncillaryInput() =>
|
||||
ShiftLeftLogical(Load(_uintType, _ancillaryLayerInput), UInt(16));
|
||||
|
||||
private uint LoadSampleCoverageInput()
|
||||
{
|
||||
var element = _module.AddInstruction(SpirvOp.AccessChain,
|
||||
_module.TypePointer(SpirvStorageClass.Input, _intType), _sampleMaskInput, UInt(0));
|
||||
return Bitcast(_uintType, Load(_intType, element));
|
||||
}
|
||||
|
||||
// POS_FIXED_PT holds the integer pixel position: x in bits [15:0] and y in bits [31:16].
|
||||
private uint LoadFixedPointPositionInput(uint fragCoord)
|
||||
{
|
||||
var x = _module.AddInstruction(SpirvOp.ConvertFToU, _uintType,
|
||||
_module.AddInstruction(SpirvOp.CompositeExtract, _floatType, fragCoord, 0));
|
||||
var y = _module.AddInstruction(SpirvOp.ConvertFToU, _uintType,
|
||||
_module.AddInstruction(SpirvOp.CompositeExtract, _floatType, fragCoord, 1));
|
||||
return _module.AddInstruction(SpirvOp.BitwiseOr, _uintType,
|
||||
_module.AddInstruction(SpirvOp.BitwiseAnd, _uintType, x, UInt(0xFFFF)),
|
||||
ShiftLeftLogical(y, UInt(16)));
|
||||
}
|
||||
|
||||
private void EmitPixelSystemInput(int bit, uint value, ref uint vgpr)
|
||||
{
|
||||
var mask = 1u << bit;
|
||||
if ((_pixelInputAddress & mask) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((_pixelInputEnable & mask) != 0 && value != 0)
|
||||
{
|
||||
StoreV(vgpr, value, guardWithExec: false);
|
||||
}
|
||||
|
||||
vgpr++;
|
||||
}
|
||||
|
||||
private uint LoadBarycentricCoordinates(int bit, uint variable) => bit switch
|
||||
{
|
||||
0 or 4 => _module.AddInstruction(SpirvOp.ExtInst, _vec3Type, _glsl, InterpolateAtSample,
|
||||
|
|
|
|||
|
|
@ -962,6 +962,7 @@ public static partial class Gen5SpirvTranslator
|
|||
SpirvDecoration.BuiltIn,
|
||||
(uint)SpirvBuiltIn.FragCoord);
|
||||
_interfaces.Add(_fragCoordInput);
|
||||
DeclarePixelSystemInputs();
|
||||
|
||||
var declaredPixelOutputs =
|
||||
Environment.GetEnvironmentVariable(
|
||||
|
|
@ -1237,12 +1238,11 @@ public static partial class Gen5SpirvTranslator
|
|||
EmitPixelPositionInput(11, 3, fragCoord, ref vgpr); // POS_W_FLOAT
|
||||
|
||||
// FRONT_FACE, ANCILLARY, SAMPLE_COVERAGE and POS_FIXED_PT follow
|
||||
// position inputs. Reserve their compact slots until their SPIR-V
|
||||
// builtins are needed by a guest shader.
|
||||
AdvancePixelInput(12, 1, ref vgpr);
|
||||
AdvancePixelInput(13, 1, ref vgpr);
|
||||
AdvancePixelInput(14, 1, ref vgpr);
|
||||
AdvancePixelInput(15, 1, ref vgpr);
|
||||
// position inputs.
|
||||
EmitPixelSystemInput(12, _frontFacingInput == 0 ? 0 : LoadFrontFaceInput(), ref vgpr);
|
||||
EmitPixelSystemInput(13, _ancillaryLayerInput == 0 ? 0 : LoadAncillaryInput(), ref vgpr);
|
||||
EmitPixelSystemInput(14, _sampleMaskInput == 0 ? 0 : LoadSampleCoverageInput(), ref vgpr);
|
||||
EmitPixelSystemInput(15, (_pixelInputAddress & _pixelInputEnable & 0x8000u) == 0 ? 0 : LoadFixedPointPositionInput(fragCoord), ref vgpr);
|
||||
}
|
||||
|
||||
private void AdvancePixelInput(int bit, uint dwordCount, ref uint vgpr)
|
||||
|
|
|
|||
|
|
@ -281,6 +281,7 @@ public enum SpirvBuiltIn : uint
|
|||
SubgroupSize = 36,
|
||||
SubgroupLocalInvocationId = 41,
|
||||
SampleId = 18,
|
||||
SampleMask = 20,
|
||||
FragDepth = 22,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,23 @@ public sealed class Gen5InterpolationParameterTests
|
|||
instruction.Operands[1] == (uint)SpirvDecoration.PerVertexKhr);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PixelSystemInputs_ReadTheirBuiltIns()
|
||||
{
|
||||
Assert.True(Gen5SpirvTranslator.TryCompileProgram(
|
||||
Request(0, false, inputs: 0xF002, opcode: "VInterpP2F32"), out var shader, out var error), error);
|
||||
var instructions = Instructions(shader.Spirv);
|
||||
var builtIns = instructions
|
||||
.Where(instruction => instruction.Opcode == SpirvOp.Decorate &&
|
||||
instruction.Operands[1] == (uint)SpirvDecoration.BuiltIn)
|
||||
.Select(instruction => instruction.Operands[2]).ToArray();
|
||||
Assert.Contains((uint)SpirvBuiltIn.FrontFacing, builtIns);
|
||||
Assert.Contains((uint)SpirvBuiltIn.Layer, builtIns);
|
||||
Assert.Contains((uint)SpirvBuiltIn.SampleMask, builtIns);
|
||||
Assert.Contains(instructions, instruction => instruction.Opcode == SpirvOp.ShiftLeftLogical);
|
||||
ValidateWhenAvailable(shader.Spirv);
|
||||
}
|
||||
|
||||
private static ShaderCompileRequest Request(
|
||||
uint selector, bool custom, uint inputs = 2, string opcode = "VInterpMovF32",
|
||||
uint inputCntl = 0x401, bool supportsPerVertex = true)
|
||||
|
|
|
|||
Loading…
Reference in New Issue