Skip to content

Commit

Permalink
[SPIR-V] Implement EvaluateAttribute* functions (#6945)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
cassiebeckley authored Oct 8, 2024
1 parent b48341e commit b26fd80
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 1 deletion.
2 changes: 2 additions & 0 deletions tools/clang/lib/SPIRV/CapabilityVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
44 changes: 44 additions & 0 deletions tools/clang/lib/SPIRV/SpirvEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions tools/clang/lib/SPIRV/SpirvEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,12 @@ class SpirvEmitter : public ASTConsumer {
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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv -Vd | FileCheck %s

RWStructuredBuffer<float4> 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);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv -Vd | FileCheck %s

RWStructuredBuffer<float4> 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);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv -Vd | FileCheck %s

RWStructuredBuffer<float4> 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));
}

0 comments on commit b26fd80

Please sign in to comment.