[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
This commit is contained in:
Cassandra Beckley 2024-10-08 11:53:49 -07:00 коммит произвёл GitHub
Родитель b48341e403
Коммит b26fd8099a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
7 изменённых файлов: 197 добавлений и 1 удалений

2
external/SPIRV-Tools поставляемый

@ -1 +1 @@
Subproject commit c173df736cb89ba4daba0beec039317292f22e0d Subproject commit 522dfead39eb232b3873f0e7cfe57cde6b9e69c1

Просмотреть файл

@ -895,6 +895,8 @@ bool CapabilityVisitor::visit(SpirvModule *, Visitor::Phase phase) {
Extension::NV_shader_subgroup_partitioned, Extension::NV_shader_subgroup_partitioned,
{spv::Capability::GroupNonUniformPartitionedNV}); {spv::Capability::GroupNonUniformPartitionedNV});
addCapability(spv::Capability::InterpolationFunction);
return true; return true;
} }

Просмотреть файл

@ -9366,6 +9366,12 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
case hlsl::IntrinsicOp::IOP_isfinite: case hlsl::IntrinsicOp::IOP_isfinite:
retVal = processIntrinsicIsFinite(callExpr); retVal = processIntrinsicIsFinite(callExpr);
break; 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, DPdx, true);
INTRINSIC_SPIRV_OP_CASE(ddx_coarse, DPdxCoarse, false); INTRINSIC_SPIRV_OP_CASE(ddx_coarse, DPdxCoarse, false);
INTRINSIC_SPIRV_OP_CASE(ddx_fine, DPdxFine, false); INTRINSIC_SPIRV_OP_CASE(ddx_fine, DPdxFine, false);
@ -11939,6 +11945,44 @@ SpirvInstruction *SpirvEmitter::processIntrinsicUsingGLSLInst(
return nullptr; 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 * SpirvInstruction *
SpirvEmitter::processIntrinsicLog10(const CallExpr *callExpr) { SpirvEmitter::processIntrinsicLog10(const CallExpr *callExpr) {
// Since there is no log10 instruction in SPIR-V, we can use: // Since there is no log10 instruction in SPIR-V, we can use:

Просмотреть файл

@ -622,6 +622,12 @@ private:
SpirvInstruction *processIntrinsicMemberCall(const CXXMemberCallExpr *expr, SpirvInstruction *processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
hlsl::IntrinsicOp opcode); hlsl::IntrinsicOp opcode);
/// Processes EvaluateAttributeAt* intrinsic calls.
SpirvInstruction *processEvaluateAttributeAt(const CallExpr *expr,
hlsl::IntrinsicOp opcode,
SourceLocation loc,
SourceRange range);
/// Processes Interlocked* intrinsic functions. /// Processes Interlocked* intrinsic functions.
SpirvInstruction *processIntrinsicInterlockedMethod(const CallExpr *, SpirvInstruction *processIntrinsicInterlockedMethod(const CallExpr *,
hlsl::IntrinsicOp); hlsl::IntrinsicOp);

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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));
}