Skip to content

Commit 9ad095d

Browse files
authored
[SPIR-V] Add support for SampleCmpLevel (microsoft#6618)
SampleCmpLevel is similar to SampleCmpLevel0, except the LOD level can be specified using either a const-offset, or a variable. This should be available starting SM6.7 Fixes microsoft#6613 --------- Signed-off-by: Nathan Gauër <[email protected]>
1 parent 9ee3f23 commit 9ad095d

File tree

3 files changed

+209
-33
lines changed

3 files changed

+209
-33
lines changed

tools/clang/lib/SPIRV/SpirvEmitter.cpp

Lines changed: 112 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5143,10 +5143,13 @@ SpirvEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
51435143
retVal = processTextureSampleGrad(expr);
51445144
break;
51455145
case IntrinsicOp::MOP_SampleCmp:
5146-
retVal = processTextureSampleCmpCmpLevelZero(expr, /*isCmp=*/true);
5146+
retVal = processTextureSampleCmp(expr);
51475147
break;
51485148
case IntrinsicOp::MOP_SampleCmpLevelZero:
5149-
retVal = processTextureSampleCmpCmpLevelZero(expr, /*isCmp=*/false);
5149+
retVal = processTextureSampleCmpLevelZero(expr);
5150+
break;
5151+
case IntrinsicOp::MOP_SampleCmpLevel:
5152+
retVal = processTextureSampleCmpLevel(expr);
51505153
break;
51515154
case IntrinsicOp::MOP_GatherRed:
51525155
retVal = processTextureGatherRGBACmpRGBA(expr, /*isCmp=*/false, 0);
@@ -5573,8 +5576,7 @@ SpirvEmitter::processTextureSampleGrad(const CXXMemberCallExpr *expr) {
55735576
}
55745577

55755578
SpirvInstruction *
5576-
SpirvEmitter::processTextureSampleCmpCmpLevelZero(const CXXMemberCallExpr *expr,
5577-
const bool isCmp) {
5579+
SpirvEmitter::processTextureSampleCmp(const CXXMemberCallExpr *expr) {
55785580
// .SampleCmp() Signature:
55795581
//
55805582
// For Texture1D, Texture1DArray, Texture2D, Texture2DArray:
@@ -5595,10 +5597,55 @@ SpirvEmitter::processTextureSampleCmpCmpLevelZero(const CXXMemberCallExpr *expr,
55955597
// [, float Clamp]
55965598
// [, out uint Status]
55975599
// );
5598-
//
5600+
5601+
const auto numArgs = expr->getNumArgs();
5602+
const bool hasStatusArg =
5603+
expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType();
5604+
auto *status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : nullptr;
5605+
5606+
SpirvInstruction *clamp = nullptr;
5607+
if (numArgs > 3 && expr->getArg(3)->getType()->isFloatingType())
5608+
clamp = doExpr(expr->getArg(3));
5609+
else if (numArgs > 4 && expr->getArg(4)->getType()->isFloatingType())
5610+
clamp = doExpr(expr->getArg(4));
5611+
const bool hasClampArg = clamp != nullptr;
5612+
5613+
const auto *imageExpr = expr->getImplicitObjectArgument();
5614+
auto *image = loadIfGLValue(imageExpr);
5615+
auto *sampler = doExpr(expr->getArg(0));
5616+
auto *coordinate = doExpr(expr->getArg(1));
5617+
auto *compareVal = doExpr(expr->getArg(2));
5618+
// If offset is present in .SampleCmp(), it will be the fourth argument.
5619+
SpirvInstruction *constOffset = nullptr, *varOffset = nullptr;
5620+
5621+
// Subtract 1 for clamp (if it exists), 1 for status (if it exists),
5622+
// and 3 for sampler_state, location, and compare_value.
5623+
const bool hasOffsetArg = numArgs - hasStatusArg - hasClampArg - 3 > 0;
5624+
if (hasOffsetArg)
5625+
handleOffsetInMethodCall(expr, 3, &constOffset, &varOffset);
5626+
5627+
const auto retType = expr->getDirectCallee()->getReturnType();
5628+
const auto imageType = imageExpr->getType();
5629+
5630+
if (spvContext.isCS()) {
5631+
addDerivativeGroupExecutionMode();
5632+
}
5633+
5634+
return createImageSample(
5635+
retType, imageType, image, sampler, coordinate, compareVal,
5636+
/*bias*/ nullptr, /*lod*/ nullptr, std::make_pair(nullptr, nullptr),
5637+
constOffset, varOffset, /*constOffsets*/ nullptr,
5638+
/*sampleNumber*/ nullptr, /*minLod*/ clamp, status,
5639+
expr->getCallee()->getLocStart(), expr->getSourceRange());
5640+
}
5641+
5642+
SpirvInstruction *
5643+
SpirvEmitter::processTextureSampleCmpLevelZero(const CXXMemberCallExpr *expr) {
55995644
// .SampleCmpLevelZero() is identical to .SampleCmp() on mipmap level 0 only.
56005645
// It never takes a clamp argument, which is good because lod and clamp may
56015646
// not be used together.
5647+
// .SampleCmpLevel() is identical to .SampleCmpLevel, except the LOD level
5648+
// is taken as a float argument.
56025649
//
56035650
// .SampleCmpLevelZero() Signature:
56045651
//
@@ -5624,46 +5671,82 @@ SpirvEmitter::processTextureSampleCmpCmpLevelZero(const CXXMemberCallExpr *expr,
56245671
expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType();
56255672
auto *status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : nullptr;
56265673

5627-
SpirvInstruction *clamp = nullptr;
5628-
// The .SampleCmpLevelZero() methods do not take the clamp argument.
5629-
if (isCmp) {
5630-
if (numArgs > 3 && expr->getArg(3)->getType()->isFloatingType())
5631-
clamp = doExpr(expr->getArg(3));
5632-
else if (numArgs > 4 && expr->getArg(4)->getType()->isFloatingType())
5633-
clamp = doExpr(expr->getArg(4));
5634-
}
5635-
const bool hasClampArg = clamp != nullptr;
5636-
5637-
// Subtract 1 for clamp (if it exists), 1 for status (if it exists),
5638-
// and 3 for sampler_state, location, and compare_value.
5639-
const bool hasOffsetArg = numArgs - hasClampArg - hasStatusArg - 3 > 0;
5640-
56415674
const auto *imageExpr = expr->getImplicitObjectArgument();
56425675
auto *image = loadIfGLValue(imageExpr);
56435676
auto *sampler = doExpr(expr->getArg(0));
56445677
auto *coordinate = doExpr(expr->getArg(1));
56455678
auto *compareVal = doExpr(expr->getArg(2));
5679+
auto *lod =
5680+
spvBuilder.getConstantFloat(astContext.FloatTy, llvm::APFloat(0.0f));
5681+
56465682
// If offset is present in .SampleCmp(), it will be the fourth argument.
56475683
SpirvInstruction *constOffset = nullptr, *varOffset = nullptr;
5684+
const bool hasOffsetArg = numArgs - hasStatusArg - 3 > 0;
56485685
if (hasOffsetArg)
56495686
handleOffsetInMethodCall(expr, 3, &constOffset, &varOffset);
5650-
auto *lod = isCmp ? nullptr
5651-
: spvBuilder.getConstantFloat(astContext.FloatTy,
5652-
llvm::APFloat(0.0f));
56535687

56545688
const auto retType = expr->getDirectCallee()->getReturnType();
56555689
const auto imageType = imageExpr->getType();
56565690

5657-
if (!lod && spvContext.isCS()) {
5658-
addDerivativeGroupExecutionMode();
5659-
}
5691+
return createImageSample(
5692+
retType, imageType, image, sampler, coordinate, compareVal,
5693+
/*bias*/ nullptr, /*lod*/ lod, std::make_pair(nullptr, nullptr),
5694+
constOffset, varOffset, /*constOffsets*/ nullptr,
5695+
/*sampleNumber*/ nullptr, /*clamp*/ nullptr, status,
5696+
expr->getCallee()->getLocStart(), expr->getSourceRange());
5697+
}
5698+
5699+
SpirvInstruction *
5700+
SpirvEmitter::processTextureSampleCmpLevel(const CXXMemberCallExpr *expr) {
5701+
// .SampleCmpLevel() is identical to .SampleCmpLevel, except the LOD level
5702+
// is taken as a float argument.
5703+
//
5704+
// For Texture1D, Texture1DArray, Texture2D, Texture2DArray:
5705+
// float Object.SampleCmpLevel(
5706+
// SamplerComparisonState S,
5707+
// float Location,
5708+
// float CompareValue,
5709+
// float LOD,
5710+
// [, int Offset]
5711+
// [, out uint Status]
5712+
// );
5713+
//
5714+
// For TextureCube and TextureCubeArray:
5715+
// float Object.SampleCmpLevel(
5716+
// SamplerComparisonState S,
5717+
// float Location,
5718+
// float CompareValue
5719+
// float LOD,
5720+
// [, out uint Status]
5721+
// );
5722+
5723+
const auto numArgs = expr->getNumArgs();
5724+
const bool hasStatusArg =
5725+
expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType();
5726+
auto *status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : nullptr;
5727+
5728+
const auto *imageExpr = expr->getImplicitObjectArgument();
5729+
auto *image = loadIfGLValue(imageExpr);
5730+
auto *sampler = doExpr(expr->getArg(0));
5731+
auto *coordinate = doExpr(expr->getArg(1));
5732+
auto *compareVal = doExpr(expr->getArg(2));
5733+
auto *lod = doExpr(expr->getArg(3));
5734+
5735+
// If offset is present in .SampleCmp(), it will be the fourth argument.
5736+
SpirvInstruction *constOffset = nullptr, *varOffset = nullptr;
5737+
const bool hasOffsetArg = numArgs - hasStatusArg - 4 > 0;
5738+
if (hasOffsetArg)
5739+
handleOffsetInMethodCall(expr, 4, &constOffset, &varOffset);
5740+
5741+
const auto retType = expr->getDirectCallee()->getReturnType();
5742+
const auto imageType = imageExpr->getType();
56605743

56615744
return createImageSample(
56625745
retType, imageType, image, sampler, coordinate, compareVal,
5663-
/*bias*/ nullptr, lod, std::make_pair(nullptr, nullptr), constOffset,
5664-
varOffset,
5665-
/*constOffsets*/ nullptr, /*sampleNumber*/ nullptr, /*minLod*/ clamp,
5666-
status, expr->getCallee()->getLocStart(), expr->getSourceRange());
5746+
/*bias*/ nullptr, /*lod*/ lod, std::make_pair(nullptr, nullptr),
5747+
constOffset, varOffset, /*constOffsets*/ nullptr,
5748+
/*sampleNumber*/ nullptr, /*clamp*/ nullptr, status,
5749+
expr->getCallee()->getLocStart(), expr->getSourceRange());
56675750
}
56685751

56695752
SpirvInstruction *

tools/clang/lib/SPIRV/SpirvEmitter.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -985,11 +985,15 @@ class SpirvEmitter : public ASTConsumer {
985985
/// \brief Processes .SampleGrad() method call for texture objects.
986986
SpirvInstruction *processTextureSampleGrad(const CXXMemberCallExpr *expr);
987987

988-
/// \brief Processes .SampleCmp() or .SampleCmpLevelZero() method call for
989-
/// texture objects.
988+
/// \brief Processes .SampleCmp() method call for texture objects.
989+
SpirvInstruction *processTextureSampleCmp(const CXXMemberCallExpr *expr);
990+
991+
/// \brief Processes .SampleCmpLevelZero() method call for texture objects.
990992
SpirvInstruction *
991-
processTextureSampleCmpCmpLevelZero(const CXXMemberCallExpr *expr,
992-
bool isCmp);
993+
processTextureSampleCmpLevelZero(const CXXMemberCallExpr *expr);
994+
995+
/// \brief Processes .SampleCmpLevel() method call for texture objects.
996+
SpirvInstruction *processTextureSampleCmpLevel(const CXXMemberCallExpr *expr);
993997

994998
/// \brief Handles .Gather{|Cmp}{Red|Green|Blue|Alpha}() calls on texture
995999
/// types.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// RUN: %dxc -T ps_6_7 -spirv -fcgl %s | FileCheck %s
2+
3+
Texture1D<float4> tex1d;
4+
Texture2D<float4> tex2d;
5+
TextureCube<float4> texCube;
6+
TextureCubeArray<float4> texCubeArray;
7+
SamplerComparisonState samplerComparisonState;
8+
RWStructuredBuffer<uint> data;
9+
10+
// CHECK-DAG: [[v2f_0_0:%[0-9]+]] = OpConstantComposite %v2float %float_0 %float_0
11+
// CHECK-DAG: [[v3f_0_0_0:%[0-9]+]] = OpConstantComposite %v3float %float_0 %float_0 %float_0
12+
// CHECK-DAG: [[v4f_0_0_0_0:%[0-9]+]] = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
13+
// CHECK-DAG: [[t_1d_sampled_image:%[^ ]+]] = OpTypeSampledImage %type_1d_image
14+
// CHECK-DAG: [[t_2d_sampled_image:%[^ ]+]] = OpTypeSampledImage %type_2d_image
15+
// CHECK-DAG: [[t_cube_sampled_image:%[^ ]+]] = OpTypeSampledImage %type_cube_image
16+
// CHECK-DAG: [[t_cube_array_sampled_image:%[^ ]+]] = OpTypeSampledImage %type_cube_image_array
17+
18+
float4 main() : SV_Target {
19+
// CHECK: [[texture:%[0-9]+]] = OpLoad %type_1d_image %tex1d
20+
// CHECK-DAG: [[sampler:%[0-9]+]] = OpLoad %type_sampler %samplerComparisonState
21+
// CHECK-DAG: [[sampledImage:%[0-9]+]] = OpSampledImage [[t_1d_sampled_image]] [[texture]] [[sampler]]
22+
// CHECK-NEXT: OpImageSampleDrefExplicitLod %float [[sampledImage]] %float_1 %float_2 Lod %float_0
23+
float4 a = tex1d.SampleCmpLevelZero(samplerComparisonState, 1, 2);
24+
25+
// CHECK: [[texture:%[0-9]+]] = OpLoad %type_1d_image %tex1d
26+
// CHECK-DAG: [[sampler:%[0-9]+]] = OpLoad %type_sampler %samplerComparisonState
27+
// CHECK-DAG: [[sampledImage:%[0-9]+]] = OpSampledImage [[t_1d_sampled_image]] [[texture]] [[sampler]]
28+
// CHECK-NEXT: OpImageSampleDrefExplicitLod %float [[sampledImage]] %float_1 %float_2 Lod|ConstOffset %float_0 %int_3
29+
float4 b = tex1d.SampleCmpLevelZero(samplerComparisonState, 1, 2, 3);
30+
31+
// CHECK: [[texture:%[0-9]+]] = OpLoad %type_1d_image %tex1d
32+
// CHECK-DAG: [[sampler:%[0-9]+]] = OpLoad %type_sampler %samplerComparisonState
33+
// CHECK-DAG: [[sampledImage:%[0-9]+]] = OpSampledImage [[t_1d_sampled_image]] [[texture]] [[sampler]]
34+
// CHECK-DAG: [[ptr:%[0-9]+]] = OpAccessChain %_ptr_Uniform_uint %data %int_0 %uint_0
35+
// CHECK-DAG: [[tmp:%[0-9]+]] = OpLoad %uint [[ptr]]
36+
// CHECK-DAG: [[offset:%[0-9]+]] = OpBitcast %int [[tmp]]
37+
// CHECK-NEXT: OpImageSampleDrefExplicitLod %float [[sampledImage]] %float_1 %float_2 Lod|Offset %float_0 [[offset]]
38+
float4 c = tex1d.SampleCmpLevelZero(samplerComparisonState, 1, 2, data[0]);
39+
40+
// CHECK: [[texture:%[0-9]+]] = OpLoad %type_1d_image %tex1d
41+
// CHECK-DAG: [[sampler:%[0-9]+]] = OpLoad %type_sampler %samplerComparisonState
42+
// CHECK-DAG: [[sampledImage:%[0-9]+]] = OpSampledImage [[t_1d_sampled_image]] [[texture]] [[sampler]]
43+
// CHECK-DAG: [[ptr:%[0-9]+]] = OpAccessChain %_ptr_Uniform_uint %data %int_0 %uint_0
44+
// CHECK-DAG: [[tmp:%[0-9]+]] = OpLoad %uint [[ptr]]
45+
// CHECK-DAG: [[offset:%[0-9]+]] = OpBitcast %int [[tmp]]
46+
// CHECK-NEXT: [[tmp:%[0-9]+]] = OpImageSparseSampleDrefExplicitLod %SparseResidencyStruct [[sampledImage]] %float_1 %float_2 Lod|Offset %float_0 [[offset]]
47+
// CHECK-NEXT: [[res:%[0-9]+]] = OpCompositeExtract %uint [[tmp]] 0
48+
// CHECK-NEXT: OpStore %status_0 [[res]]
49+
uint status_0;
50+
float4 d = tex1d.SampleCmpLevelZero(samplerComparisonState, 1, 2, data[0], status_0);
51+
52+
// CHECK: [[texture:%[0-9]+]] = OpLoad %type_2d_image %tex2d
53+
// CHECK-DAG: [[sampler:%[0-9]+]] = OpLoad %type_sampler %samplerComparisonState
54+
// CHECK-DAG: [[sampledImage:%[0-9]+]] = OpSampledImage [[t_2d_sampled_image]] [[texture]] [[sampler]]
55+
// CHECK-NEXT: OpImageSampleDrefExplicitLod %float [[sampledImage]] [[v2f_0_0]] %float_2 Lod %float_3
56+
float4 e = tex2d.SampleCmpLevel(samplerComparisonState, float2(0, 0), 2, 3);
57+
58+
// CHECK: [[texture:%[0-9]+]] = OpLoad %type_cube_image %texCube
59+
// CHECK-DAG: [[sampler:%[0-9]+]] = OpLoad %type_sampler %samplerComparisonState
60+
// CHECK-DAG: [[sampledImage:%[0-9]+]] = OpSampledImage [[t_cube_sampled_image]] [[texture]] [[sampler]]
61+
// CHECK-NEXT: OpImageSampleDrefExplicitLod %float [[sampledImage]] [[v3f_0_0_0]] %float_1 Lod %float_2
62+
float4 f = texCube.SampleCmpLevel(samplerComparisonState, float3(0, 0, 0), 1, 2);
63+
64+
// CHECK: [[texture:%[0-9]+]] = OpLoad %type_cube_image %texCube
65+
// CHECK-DAG: [[sampler:%[0-9]+]] = OpLoad %type_sampler %samplerComparisonState
66+
// CHECK-DAG: [[sampledImage:%[0-9]+]] = OpSampledImage [[t_cube_sampled_image]] [[texture]] [[sampler]]
67+
// CHECK-NEXT: [[tmp:%[0-9]+]] = OpImageSparseSampleDrefExplicitLod %SparseResidencyStruct [[sampledImage]] [[v3f_0_0_0]] %float_1 Lod %float_2
68+
// CHECK-NEXT: [[res:%[0-9]+]] = OpCompositeExtract %uint [[tmp]] 0
69+
// CHECK-NEXT: OpStore %status_1 [[res]]
70+
uint status_1;
71+
float4 g = texCube.SampleCmpLevel(samplerComparisonState, float3(0, 0, 0), 1, 2, status_1);
72+
73+
// CHECK: [[texture:%[0-9]+]] = OpLoad %type_cube_image_array %texCubeArray
74+
// CHECK-DAG: [[sampler:%[0-9]+]] = OpLoad %type_sampler %samplerComparisonState
75+
// CHECK-DAG: [[sampledImage:%[0-9]+]] = OpSampledImage [[t_cube_array_sampled_image]] [[texture]] [[sampler]]
76+
// CHECK-NEXT: OpImageSampleDrefExplicitLod %float [[sampledImage]] [[v4f_0_0_0_0]] %float_1 Lod %float_2
77+
float4 h = texCubeArray.SampleCmpLevel(samplerComparisonState, float4(0, 0, 0, 0), 1, 2);
78+
79+
// CHECK: [[texture:%[0-9]+]] = OpLoad %type_cube_image_array %texCubeArray
80+
// CHECK-DAG: [[sampler:%[0-9]+]] = OpLoad %type_sampler %samplerComparisonState
81+
// CHECK-DAG: [[sampledImage:%[0-9]+]] = OpSampledImage [[t_cube_array_sampled_image]] [[texture]] [[sampler]]
82+
// CHECK-NEXT: [[tmp:%[0-9]+]] = OpImageSparseSampleDrefExplicitLod %SparseResidencyStruct [[sampledImage]] [[v4f_0_0_0_0]] %float_1 Lod %float_2
83+
// CHECK-NEXT: [[res:%[0-9]+]] = OpCompositeExtract %uint [[tmp]] 0
84+
// CHECK-NEXT: OpStore %status_2 [[res]]
85+
uint status_2;
86+
float4 i = texCubeArray.SampleCmpLevel(samplerComparisonState, float4(0, 0, 0, 0), 1, 2, status_2);
87+
88+
return float4(0, 0, 0, 0);
89+
}

0 commit comments

Comments
 (0)