From b26fd8099aa435c6a46b10b179549280ba3930b0 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Tue, 8 Oct 2024 11:53:49 -0700 Subject: [PATCH] [SPIR-V] Implement EvaluateAttribute* functions (#6945) Emits SPIR-V InterpolateAt* instructions from the GLSL.std.450 extended instruction set for EvaluateAttribute*. Relies on the optimizer's copy propagate passes to ensure that these instructions are passed valid pointers in the Input storage class after legalization. Fixes #3649 --- external/SPIRV-Tools | 2 +- tools/clang/lib/SPIRV/CapabilityVisitor.cpp | 2 + tools/clang/lib/SPIRV/SpirvEmitter.cpp | 44 +++++++++++++++ tools/clang/lib/SPIRV/SpirvEmitter.h | 6 ++ ...trinsics.evaluate-attribute-at-sample.hlsl | 44 +++++++++++++++ ...ntrinsics.evaluate-attribute-centroid.hlsl | 45 +++++++++++++++ ...intrinsics.evaluate-attribute-snapped.hlsl | 55 +++++++++++++++++++ 7 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 tools/clang/test/CodeGenSPIRV/intrinsics.evaluate-attribute-at-sample.hlsl create mode 100644 tools/clang/test/CodeGenSPIRV/intrinsics.evaluate-attribute-centroid.hlsl create mode 100644 tools/clang/test/CodeGenSPIRV/intrinsics.evaluate-attribute-snapped.hlsl diff --git a/external/SPIRV-Tools b/external/SPIRV-Tools index c173df736..522dfead3 160000 --- a/external/SPIRV-Tools +++ b/external/SPIRV-Tools @@ -1 +1 @@ -Subproject commit c173df736cb89ba4daba0beec039317292f22e0d +Subproject commit 522dfead39eb232b3873f0e7cfe57cde6b9e69c1 diff --git a/tools/clang/lib/SPIRV/CapabilityVisitor.cpp b/tools/clang/lib/SPIRV/CapabilityVisitor.cpp index f2d295854..a2f53757c 100644 --- a/tools/clang/lib/SPIRV/CapabilityVisitor.cpp +++ b/tools/clang/lib/SPIRV/CapabilityVisitor.cpp @@ -895,6 +895,8 @@ bool CapabilityVisitor::visit(SpirvModule *, Visitor::Phase phase) { Extension::NV_shader_subgroup_partitioned, {spv::Capability::GroupNonUniformPartitionedNV}); + addCapability(spv::Capability::InterpolationFunction); + return true; } diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index 466a59c9b..ac455c547 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -9366,6 +9366,12 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) { case hlsl::IntrinsicOp::IOP_isfinite: retVal = processIntrinsicIsFinite(callExpr); break; + case hlsl::IntrinsicOp::IOP_EvaluateAttributeCentroid: + case hlsl::IntrinsicOp::IOP_EvaluateAttributeAtSample: + case hlsl::IntrinsicOp::IOP_EvaluateAttributeSnapped: { + retVal = processEvaluateAttributeAt(callExpr, hlslOpcode, srcLoc, srcRange); + break; + } INTRINSIC_SPIRV_OP_CASE(ddx, DPdx, true); INTRINSIC_SPIRV_OP_CASE(ddx_coarse, DPdxCoarse, false); INTRINSIC_SPIRV_OP_CASE(ddx_fine, DPdxFine, false); @@ -11939,6 +11945,44 @@ SpirvInstruction *SpirvEmitter::processIntrinsicUsingGLSLInst( return nullptr; } +SpirvInstruction *SpirvEmitter::processEvaluateAttributeAt( + const CallExpr *callExpr, hlsl::IntrinsicOp opcode, SourceLocation loc, + SourceRange range) { + QualType returnType = callExpr->getType(); + SpirvInstruction *arg0Instr = doExpr(callExpr->getArg(0)); + SpirvInstruction *interpolant = + turnIntoLValue(callExpr->getType(), arg0Instr, callExpr->getExprLoc()); + + switch (opcode) { + case hlsl::IntrinsicOp::IOP_EvaluateAttributeCentroid: + return spvBuilder.createGLSLExtInst( + returnType, GLSLstd450InterpolateAtCentroid, {interpolant}, loc, range); + case hlsl::IntrinsicOp::IOP_EvaluateAttributeAtSample: { + SpirvInstruction *sample = doExpr(callExpr->getArg(1)); + return spvBuilder.createGLSLExtInst(returnType, + GLSLstd450InterpolateAtSample, + {interpolant, sample}, loc, range); + } + case hlsl::IntrinsicOp::IOP_EvaluateAttributeSnapped: { + const Expr *arg1 = callExpr->getArg(1); + SpirvInstruction *arg1Inst = doExpr(arg1); + + QualType float2Type = astContext.getExtVectorType(astContext.FloatTy, 2); + SpirvInstruction *offset = + castToFloat(arg1Inst, arg1->getType(), float2Type, arg1->getLocStart(), + arg1->getSourceRange()); + + return spvBuilder.createGLSLExtInst(returnType, + GLSLstd450InterpolateAtOffset, + {interpolant, offset}, loc, range); + } + default: + assert(false && "processEvaluateAttributeAt must be called with an " + "EvaluateAttribute* opcode"); + return nullptr; + } +} + SpirvInstruction * SpirvEmitter::processIntrinsicLog10(const CallExpr *callExpr) { // Since there is no log10 instruction in SPIR-V, we can use: diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.h b/tools/clang/lib/SPIRV/SpirvEmitter.h index 242550c29..6589e642c 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.h +++ b/tools/clang/lib/SPIRV/SpirvEmitter.h @@ -622,6 +622,12 @@ private: SpirvInstruction *processIntrinsicMemberCall(const CXXMemberCallExpr *expr, hlsl::IntrinsicOp opcode); + /// Processes EvaluateAttributeAt* intrinsic calls. + SpirvInstruction *processEvaluateAttributeAt(const CallExpr *expr, + hlsl::IntrinsicOp opcode, + SourceLocation loc, + SourceRange range); + /// Processes Interlocked* intrinsic functions. SpirvInstruction *processIntrinsicInterlockedMethod(const CallExpr *, hlsl::IntrinsicOp); diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.evaluate-attribute-at-sample.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.evaluate-attribute-at-sample.hlsl new file mode 100644 index 000000000..45f880d0d --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/intrinsics.evaluate-attribute-at-sample.hlsl @@ -0,0 +1,44 @@ +// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv -Vd | FileCheck %s + +RWStructuredBuffer a; + +[[vk::ext_builtin_input(/* PointCoord */ 16)]] +static const float2 gl_PointCoord; + +// CHECK: [[instSet:%[0-9]+]] = OpExtInstImport "GLSL.std.450" + +void setValue(float4 input); + +// CHECK: %src_main = OpFunction +void main(float4 color : COLOR, float instance : SV_InstanceID) { +// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %color +// CHECK: OpStore %temp_var_v4float [[val]] +// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtSample %temp_var_v4float %uint_0 + a[0] = EvaluateAttributeAtSample(color, 0); + + setValue(color); + +// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %c2 +// CHECK: OpStore %temp_var_v4float_0 [[val]] +// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtSample %temp_var_v4float_0 %uint_2 + float4 c2 = color; + a[2] = EvaluateAttributeAtSample(c2, 2); + +// CHECK: [[val:%[0-9]+]] = OpLoad %float %instance +// CHECK: OpStore %temp_var_float [[val]] +// CHECK: OpExtInst %float [[instSet]] InterpolateAtSample %temp_var_float %uint_3 + a[3] = EvaluateAttributeAtSample(instance, 3); + +// CHECK: [[val:%[0-9]+]] = OpLoad %v2float %gl_PointCoord +// CHECK: OpStore %temp_var_v2float [[val]] +// CHECK: OpExtInst %v2float [[instSet]] InterpolateAtSample %temp_var_v2float %uint_4 + a[4] = float4(EvaluateAttributeAtSample(gl_PointCoord, 4), 0, 0); +} + +// CHECK: %setValue = OpFunction +void setValue(float4 input) { +// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %input +// CHECK: OpStore %temp_var_v4float_1 [[val]] +// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtSample %temp_var_v4float_1 %uint_1 + a[1] = EvaluateAttributeAtSample(input, 1); +} diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.evaluate-attribute-centroid.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.evaluate-attribute-centroid.hlsl new file mode 100644 index 000000000..9324c42ea --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/intrinsics.evaluate-attribute-centroid.hlsl @@ -0,0 +1,45 @@ +// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv -Vd | FileCheck %s + +RWStructuredBuffer a; + +[[vk::ext_builtin_input(/* PointCoord */ 16)]] +static const float2 gl_PointCoord; + +// CHECK: [[instSet:%[0-9]+]] = OpExtInstImport "GLSL.std.450" + +void setValue(float4 input); + +// CHECK: %src_main = OpFunction +void main(float4 color : COLOR, float instance : SV_InstanceID) { +// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %color +// CHECK: OpStore %temp_var_v4float [[val]] +// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtCentroid %temp_var_v4float + a[0] = EvaluateAttributeCentroid(color); + + setValue(color); + +// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %c2 +// CHECK: OpStore %temp_var_v4float_0 [[val]] +// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtCentroid %temp_var_v4float_0 + float4 c2 = color; + a[2] = EvaluateAttributeCentroid(c2); + +// CHECK: [[val:%[0-9]+]] = OpLoad %float %instance +// CHECK: OpStore %temp_var_float [[val]] +// CHECK: OpExtInst %float [[instSet]] InterpolateAtCentroid %temp_var_float + a[3] = EvaluateAttributeCentroid(instance); + +// CHECK: [[val:%[0-9]+]] = OpLoad %v2float %gl_PointCoord +// CHECK: OpStore %temp_var_v2float [[val]] +// CHECK: OpExtInst %v2float [[instSet]] InterpolateAtCentroid %temp_var_v2float + a[4] = float4(EvaluateAttributeCentroid(gl_PointCoord), 0, 0); +} + + +// CHECK: %setValue = OpFunction +void setValue(float4 input) { +// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %input +// CHECK: OpStore %temp_var_v4float_1 [[val]] +// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtCentroid %temp_var_v4float_1 + a[1] = EvaluateAttributeCentroid(input); +} diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.evaluate-attribute-snapped.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.evaluate-attribute-snapped.hlsl new file mode 100644 index 000000000..bf4084e6c --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/intrinsics.evaluate-attribute-snapped.hlsl @@ -0,0 +1,55 @@ +// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv -Vd | FileCheck %s + +RWStructuredBuffer a; + +[[vk::ext_builtin_input(/* PointCoord */ 16)]] +static const float2 gl_PointCoord; + +// CHECK: [[instSet:%[0-9]+]] = OpExtInstImport "GLSL.std.450" + +// CHECK: [[v2int_0_0:%[0-9]+]] = OpConstantComposite %v2int %int_0 %int_0 +// CHECK: [[v2int_2_2:%[0-9]+]] = OpConstantComposite %v2int %int_2 %int_2 +// CHECK: [[v2int_3_3:%[0-9]+]] = OpConstantComposite %v2int %int_3 %int_3 +// CHECK: [[v2int_4_4:%[0-9]+]] = OpConstantComposite %v2int %int_4 %int_4 +// CHECK: [[v2int_1_1:%[0-9]+]] = OpConstantComposite %v2int %int_1 %int_1 + +void setValue(float4 input); + +// CHECK: %src_main = OpFunction +void main(float4 color : COLOR, float instance : SV_InstanceID) { +// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %color +// CHECK: OpStore %temp_var_v4float [[val]] +// CHECK: [[offset:%[0-9]+]] = OpConvertSToF %v2float [[v2int_0_0]] +// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtOffset %temp_var_v4float [[offset]] + a[0] = EvaluateAttributeSnapped(color, int2(0,0)); + + setValue(color); + +// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %c2 +// CHECK: OpStore %temp_var_v4float_0 [[val]] +// CHECK: [[offset:%[0-9]+]] = OpConvertSToF %v2float [[v2int_2_2]] +// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtOffset %temp_var_v4float_0 [[offset]] + float4 c2 = color; + a[2] = EvaluateAttributeSnapped(c2, int2(2,2)); + +// CHECK: [[val:%[0-9]+]] = OpLoad %float %instance +// CHECK: OpStore %temp_var_float [[val]] +// CHECK: [[offset:%[0-9]+]] = OpConvertSToF %v2float [[v2int_3_3]] +// CHECK: OpExtInst %float [[instSet]] InterpolateAtOffset %temp_var_float [[offset]] + a[3] = EvaluateAttributeSnapped(instance, int2(3,3)); + +// CHECK: [[val:%[0-9]+]] = OpLoad %v2float %gl_PointCoord +// CHECK: OpStore %temp_var_v2float [[val]] +// CHECK: [[offset:%[0-9]+]] = OpConvertSToF %v2float [[v2int_4_4]] +// CHECK: OpExtInst %v2float [[instSet]] InterpolateAtOffset %temp_var_v2float [[offset]] + a[4] = float4(EvaluateAttributeSnapped(gl_PointCoord, int2(4, 4)), 0, 0); +} + +// CHECK: %setValue = OpFunction +void setValue(float4 input) { +// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %input +// CHECK: OpStore %temp_var_v4float_1 [[val]] +// CHECK: [[offset:%[0-9]+]] = OpConvertSToF %v2float [[v2int_1_1]] +// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtOffset %temp_var_v4float_1 [[offset]] + a[1] = EvaluateAttributeSnapped(input, int2(1,1)); +}