[SPIRV-V] Implement Shader Model 6.8 Expanded Comparison Sampling (#6854)

Compile `SampleCmpBias` using `OpImage*SampleDrefImplicitLod` and
`SampleCmpGrad` using `OpImage*SampleDrefExplicitLod`.

The existing handlers for `CalculateLevelOfDetail` and
`CalculateLevelOfDetailUnclamped` work for the
`SamplerComparisonSampler` overload, so no new code is needed other than
tests.
This commit is contained in:
Cassandra Beckley 2024-09-09 11:42:24 -07:00 коммит произвёл GitHub
Родитель 937c8c8811
Коммит ca2e67d29e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
7 изменённых файлов: 347 добавлений и 4 удалений

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

@ -2890,6 +2890,30 @@ If an output unsigned integer ``status`` argument is present,
``OpImageSparseSampleDrefExplicitLod`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``.SampleCmpBias(sampler, location, bias, comparator[, offset][, clamp][, Status])``
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``.
The translation is similar to ``.SampleBias()``, but the
``OpImageSampleDrefImplicitLod`` instruction is used.
If an output unsigned integer ``status`` argument is present,
``OpImageSparseSampleDrefImplicitLod`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``.SampleCmpGrad(sampler, location, ddx, ddy, comparator[, offset][, clamp][, Status])``
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``.
The translation is similar to ``.SampleGrad()``, but the
``OpImageSampleDrefExplicitLod`` instruction are used.
If an output unsigned integer ``status`` argument is present,
``OpImageSparseSampleDrefExplicitLod`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``.Gather()``
+++++++++++++
@ -2983,10 +3007,11 @@ Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
Since texture types are represented as ``OpTypeImage``, the ``OpImageQueryLod``
instruction is used for translation. An ``OpSampledImage`` is created based on
the ``SamplerState`` passed to the function. The resulting sampled image and
the coordinate passed to the function are used to invoke ``OpImageQueryLod``.
The result of ``OpImageQueryLod`` is a ``float2``. The first element contains
the mipmap array layer. The second element contains the unclamped level of detail.
the ``SamplerState`` or ``SamplerComparisonState`` passed to the function. The
resulting sampled image and the coordinate passed to the function are used to
invoke ``OpImageQueryLod``. The result of ``OpImageQueryLod`` is a ``float2``.
The first element contains the mipmap array layer. The second element contains
the unclamped level of detail.
``Texture1D``
~~~~~~~~~~~~~

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

@ -5259,6 +5259,12 @@ SpirvEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
case IntrinsicOp::MOP_SampleCmp:
retVal = processTextureSampleCmp(expr);
break;
case IntrinsicOp::MOP_SampleCmpBias:
retVal = processTextureSampleCmpBias(expr);
break;
case IntrinsicOp::MOP_SampleCmpGrad:
retVal = processTextureSampleCmpGrad(expr);
break;
case IntrinsicOp::MOP_SampleCmpLevelZero:
retVal = processTextureSampleCmpLevelZero(expr);
break;
@ -5468,6 +5474,32 @@ SpirvInstruction *SpirvEmitter::createImageSample(
return retVal;
}
void SpirvEmitter::handleOptionalTextureSampleArgs(
const CXXMemberCallExpr *expr, uint32_t index,
SpirvInstruction **constOffset, SpirvInstruction **varOffset,
SpirvInstruction **clamp, SpirvInstruction **status) {
uint32_t numArgs = expr->getNumArgs();
bool hasOffsetArg = index < numArgs &&
(expr->getArg(index)->getType()->isSignedIntegerType() ||
hlsl::IsHLSLVecType(expr->getArg(index)->getType()));
if (hasOffsetArg) {
handleOffsetInMethodCall(expr, index, constOffset, varOffset);
index++;
}
if (index >= numArgs)
return;
*clamp = doExpr(expr->getArg(index));
index++;
if (index >= numArgs)
return;
*status = doExpr(expr->getArg(index));
}
SpirvInstruction *
SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr,
const bool isSample) {
@ -5753,6 +5785,108 @@ SpirvEmitter::processTextureSampleCmp(const CXXMemberCallExpr *expr) {
expr->getCallee()->getLocStart(), expr->getSourceRange());
}
SpirvInstruction *
SpirvEmitter::processTextureSampleCmpBias(const CXXMemberCallExpr *expr) {
// .SampleCmpBias() Signature:
//
// For Texture1D, Texture1DArray, Texture2D, Texture2DArray:
// float Object.SampleCmpBias(
// SamplerComparisonState S,
// float Location,
// float CompareValue,
// float Bias
// [, int Offset]
// [, float Clamp]
// [, out uint Status]
// );
//
// For TextureCube and TextureCubeArray:
// float Object.SampleCmpBias(
// SamplerComparisonState S,
// float Location,
// float CompareValue,
// float Bias
// [, float Clamp]
// [, out uint Status]
// );
const auto *imageExpr = expr->getImplicitObjectArgument();
auto *image = loadIfGLValue(imageExpr);
auto *sampler = doExpr(expr->getArg(0));
auto *coordinate = doExpr(expr->getArg(1));
auto *compareVal = doExpr(expr->getArg(2));
auto *bias = doExpr(expr->getArg(3));
SpirvInstruction *constOffset = nullptr, *varOffset = nullptr;
SpirvInstruction *clamp = nullptr;
SpirvInstruction *status = nullptr;
handleOptionalTextureSampleArgs(expr, 4, &constOffset, &varOffset, &clamp,
&status);
const auto retType = expr->getDirectCallee()->getReturnType();
const auto imageType = imageExpr->getType();
if (spvContext.isCS()) {
addDerivativeGroupExecutionMode();
}
return createImageSample(
retType, imageType, image, sampler, coordinate, compareVal, bias,
/*lod*/ nullptr, std::make_pair(nullptr, nullptr), constOffset, varOffset,
/*constOffsets*/ nullptr, /*sampleNumber*/ nullptr, /*minLod*/ clamp,
status, expr->getCallee()->getLocStart(), expr->getSourceRange());
}
SpirvInstruction *
SpirvEmitter::processTextureSampleCmpGrad(const CXXMemberCallExpr *expr) {
// Signature:
// For Texture1D, Texture1DArray, Texture2D, Texture2DArray, and Texture3D:
// DXGI_FORMAT Object.SampleGrad(sampler_state S,
// float Location,
// float CompareValue,
// float DDX,
// float DDY
// [, int Offset]
// [, float Clamp]
// [, out uint Status]);
//
// For TextureCube and TextureCubeArray:
// DXGI_FORMAT Object.SampleGrad(sampler_state S,
// float Location,
// float CompareValue,
// float DDX,
// float DDY
// [, float Clamp]
// [, out uint Status]);
const auto *imageExpr = expr->getImplicitObjectArgument();
const QualType imageType = imageExpr->getType();
auto *image = loadIfGLValue(imageExpr);
auto *sampler = doExpr(expr->getArg(0));
auto *coordinate = doExpr(expr->getArg(1));
auto *compareVal = doExpr(expr->getArg(2));
auto *ddx = doExpr(expr->getArg(3));
auto *ddy = doExpr(expr->getArg(4));
SpirvInstruction *constOffset = nullptr, *varOffset = nullptr;
SpirvInstruction *clamp = nullptr;
SpirvInstruction *status = nullptr;
handleOptionalTextureSampleArgs(expr, 5, &constOffset, &varOffset, &clamp,
&status);
const auto retType = expr->getDirectCallee()->getReturnType();
return createImageSample(
retType, imageType, image, sampler, coordinate, compareVal,
/*bias*/ nullptr, /*lod*/ nullptr, std::make_pair(ddx, ddy), constOffset,
varOffset, /*constOffsets*/ nullptr, /*sampleNumber*/ nullptr,
/*minLod*/ clamp, status, expr->getCallee()->getLocStart(),
expr->getSourceRange());
}
SpirvInstruction *
SpirvEmitter::processTextureSampleCmpLevelZero(const CXXMemberCallExpr *expr) {
// .SampleCmpLevelZero() is identical to .SampleCmp() on mipmap level 0 only.

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

@ -979,6 +979,13 @@ private:
SpirvInstruction **constOffset,
SpirvInstruction **varOffset);
void handleOptionalTextureSampleArgs(const CXXMemberCallExpr *expr,
uint32_t index,
SpirvInstruction **constOffset,
SpirvInstruction **varOffset,
SpirvInstruction **clamp,
SpirvInstruction **status);
/// \brief Processes .Load() method call for Buffer/RWBuffer and texture
/// objects.
SpirvInstruction *processBufferTextureLoad(const CXXMemberCallExpr *);
@ -1009,6 +1016,12 @@ private:
/// \brief Processes .SampleCmp() method call for texture objects.
SpirvInstruction *processTextureSampleCmp(const CXXMemberCallExpr *expr);
/// \brief Processes .SampleCmpBias() method call for texture objects.
SpirvInstruction *processTextureSampleCmpBias(const CXXMemberCallExpr *expr);
/// \brief Processes .SampleCmpGrad() method call for texture objects.
SpirvInstruction *processTextureSampleCmpGrad(const CXXMemberCallExpr *expr);
/// \brief Processes .SampleCmpLevelZero() method call for texture objects.
SpirvInstruction *
processTextureSampleCmpLevelZero(const CXXMemberCallExpr *expr);

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

@ -0,0 +1,21 @@
// RUN: %dxc -T ps_6_8 -E main -fcgl %s -spirv | FileCheck %s
// CHECK: OpCapability ImageQuery
SamplerComparisonState scs : register(s2);
Texture1D <float> t1;
// CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image
void main() {
float x = 0.5;
//CHECK: [[t1:%[0-9]+]] = OpLoad %type_1d_image %t1
//CHECK-NEXT: [[ss1:%[0-9]+]] = OpLoad %type_sampler %scs
//CHECK-NEXT: [[x1:%[0-9]+]] = OpLoad %float %x
//CHECK-NEXT: [[si1:%[0-9]+]] = OpSampledImage %type_sampled_image [[t1]] [[ss1]]
//CHECK-NEXT: [[query1:%[0-9]+]] = OpImageQueryLod %v2float [[si1]] [[x1]]
//CHECK-NEXT: {{%[0-9]+}} = OpCompositeExtract %float [[query1]] 1
float lod1 = t1.CalculateLevelOfDetailUnclamped(scs, x);
}

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

@ -0,0 +1,21 @@
// RUN: %dxc -T ps_6_8 -E main -fcgl %s -spirv | FileCheck %s
// CHECK: OpCapability ImageQuery
SamplerComparisonState scs : register(s2);
Texture1D <float> t1;
// CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image
void main() {
float x = 0.5;
//CHECK: [[t1:%[0-9]+]] = OpLoad %type_1d_image %t1
//CHECK-NEXT: [[ss1:%[0-9]+]] = OpLoad %type_sampler %scs
//CHECK-NEXT: [[x1:%[0-9]+]] = OpLoad %float %x
//CHECK-NEXT: [[si1:%[0-9]+]] = OpSampledImage %type_sampled_image [[t1]] [[ss1]]
//CHECK-NEXT: [[query1:%[0-9]+]] = OpImageQueryLod %v2float [[si1]] [[x1]]
//CHECK-NEXT: {{%[0-9]+}} = OpCompositeExtract %float [[query1]] 0
float lod1 = t1.CalculateLevelOfDetail(scs, x);
}

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

@ -0,0 +1,64 @@
// RUN: %dxc -T ps_6_8 -E main -fcgl %s -spirv | FileCheck %s
SamplerComparisonState s;
Texture1D<float4> t1;
Texture1DArray<float4> t1_array;
Texture2D<float4> t2;
TextureCube<float4> tcube;
// CHECK: OpCapability MinLod
// CHECK: OpCapability SparseResidency
// CHECK: [[v2fc:%[0-9]+]] = OpConstantComposite %v2float %float_1 %float_2
// CHECK: [[v2ic:%[0-9]+]] = OpConstantComposite %v2int %int_n5 %int_7
// CHECK: [[v3fc:%[0-9]+]] = OpConstantComposite %v3float %float_1 %float_2 %float_3
// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %float
void main() {
float cmpVal;
float bias;
float clamp;
// CHECK: [[t1:%[0-9]+]] = OpLoad %type_1d_image %t1
// CHECK-NEXT: [[sampler:%[0-9]+]] = OpLoad %type_sampler %s
// CHECK-NEXT: [[cmpVal:%[0-9]+]] = OpLoad %float %cmpVal
// CHECK-NEXT: [[bias:%[0-9]+]] = OpLoad %float %bias
// CHECK-NEXT: [[sampledImg:%[0-9]+]] = OpSampledImage %type_sampled_image [[t1]] [[sampler]]
// CHECK-NEXT: {{%[0-9]+}} = OpImageSampleDrefImplicitLod %float [[sampledImg]] %float_1 [[cmpVal]] Bias [[bias]]
float val1 = t1.SampleCmpBias(s, 1, cmpVal, bias);
// CHECK: [[t1Array:%[0-9]+]] = OpLoad %type_1d_image_array %t1_array
// CHECK-NEXT: [[sampler:%[0-9]+]] = OpLoad %type_sampler %s
// CHECK-NEXT: [[cmpVal:%[0-9]+]] = OpLoad %float %cmpVal
// CHECK-NEXT: [[bias:%[0-9]+]] = OpLoad %float %bias
// CHECK-NEXT: [[sampledImg:%[0-9]+]] = OpSampledImage %type_sampled_image_0 [[t1Array]] [[sampler]]
// CHECK-NEXT: {{%[0-9]+}} = OpImageSampleDrefImplicitLod %float [[sampledImg]] [[v2fc]] [[cmpVal]] Bias|ConstOffset [[bias]] %int_n5
float val2 = t1_array.SampleCmpBias(s, float2(1, 2), cmpVal, bias, -5);
// CHECK: [[t2:%[0-9]+]] = OpLoad %type_2d_image %t2
// CHECK-NEXT: [[sampler:%[0-9]+]] = OpLoad %type_sampler %s
// CHECK-NEXT: [[cmpVal:%[0-9]+]] = OpLoad %float %cmpVal
// CHECK-NEXT: [[bias:%[0-9]+]] = OpLoad %float %bias
// CHECK-NEXT: [[clamp:%[0-9]+]] = OpLoad %float %clamp
// CHECK-NEXT: [[sampledImg:%[0-9]+]] = OpSampledImage %type_sampled_image_1 [[t2]] [[sampler]]
// CHECK-NEXT: {{%[0-9]+}} = OpImageSampleDrefImplicitLod %float [[sampledImg]] [[v2fc]] [[cmpVal]] Bias|ConstOffset|MinLod [[bias]] [[v2ic]] [[clamp]]
float val3 = t2.SampleCmpBias(s, float2(1, 2), cmpVal, bias, uint2(-5, 7), clamp);
uint status;
// CHECK: [[tcube:%[0-9]+]] = OpLoad %type_cube_image %tcube
// CHECK-NEXT: [[sampler:%[0-9]+]] = OpLoad %type_sampler %s
// CHECK-NEXT: [[cmpVal:%[0-9]+]] = OpLoad %float %cmpVal
// CHECK-NEXT: [[bias:%[0-9]+]] = OpLoad %float %bias
// CHECK-NEXT: [[clamp:%[0-9]+]] = OpLoad %float %clamp
// CHECK-NEXT: [[sampledImg:%[0-9]+]] = OpSampledImage %type_sampled_image_2 [[tcube]] [[sampler]]
// CHECK-NEXT: [[structResult:%[0-9]+]] = OpImageSparseSampleDrefImplicitLod %SparseResidencyStruct [[sampledImg]] [[v3fc]] [[cmpVal]] Bias|MinLod [[bias]] [[clamp]]
// CHECK-NEXT: [[status:%[0-9]+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[result:%[0-9]+]] = OpCompositeExtract %float [[structResult]] 1
// CHECK-NEXT: OpStore %val4 [[result]]
float val4 = tcube.SampleCmpBias(s, float3(1, 2, 3), cmpVal, bias, clamp, status);
}

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

@ -0,0 +1,65 @@
// RUN: %dxc -T ps_6_8 -E main -fcgl %s -spirv | FileCheck %s
SamplerComparisonState s;
Texture1D<float4> t1;
Texture1DArray<float4> t1_array;
Texture2D<float4> t2;
TextureCube<float4> tcube;
// CHECK: OpCapability MinLod
// CHECK: OpCapability SparseResidency
// CHECK: [[v2fc:%[0-9]+]] = OpConstantComposite %v2float %float_1 %float_2
// CHECK: [[v2f_2:%[0-9]+]] = OpConstantComposite %v2float %float_2 %float_2
// CHECK: [[v2f_3:%[0-9]+]] = OpConstantComposite %v2float %float_3 %float_3
// CHECK: [[v2ic:%[0-9]+]] = OpConstantComposite %v2int %int_n5 %int_7
// CHECK: [[v3fc:%[0-9]+]] = OpConstantComposite %v3float %float_1 %float_2 %float_3
// CHECK: [[v3f_1:%[0-9]+]] = OpConstantComposite %v3float %float_1 %float_1 %float_1
// CHECK: [[v3f_2:%[0-9]+]] = OpConstantComposite %v3float %float_2 %float_2 %float_2
// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %float
void main() {
float cmpVal;
float clamp;
// CHECK: [[t1:%[0-9]+]] = OpLoad %type_1d_image %t1
// CHECK-NEXT: [[sampler:%[0-9]+]] = OpLoad %type_sampler %s
// CHECK-NEXT: [[cmpVal:%[0-9]+]] = OpLoad %float %cmpVal
// CHECK-NEXT: [[sampledImg:%[0-9]+]] = OpSampledImage %type_sampled_image [[t1]] [[sampler]]
// CHECK-NEXT: {{%[0-9]+}} = OpImageSampleDrefExplicitLod %float [[sampledImg]] %float_1 [[cmpVal]] Grad %float_2 %float_3
float val1 = t1.SampleCmpGrad(s, 1, cmpVal, 2, 3);
// CHECK: [[t1Array:%[0-9]+]] = OpLoad %type_1d_image_array %t1_array
// CHECK-NEXT: [[sampler:%[0-9]+]] = OpLoad %type_sampler %s
// CHECK-NEXT: [[cmpVal:%[0-9]+]] = OpLoad %float %cmpVal
// CHECK-NEXT: [[sampledImg:%[0-9]+]] = OpSampledImage %type_sampled_image_0 [[t1Array]] [[sampler]]
// CHECK-NEXT: {{%[0-9]+}} = OpImageSampleDrefExplicitLod %float [[sampledImg]] [[v2fc]] [[cmpVal]] Grad|ConstOffset %float_2 %float_3 %int_n5
float val2 = t1_array.SampleCmpGrad(s, float2(1, 2), cmpVal, 2, 3, -5);
// CHECK: [[t2:%[0-9]+]] = OpLoad %type_2d_image %t2
// CHECK-NEXT: [[sampler:%[0-9]+]] = OpLoad %type_sampler %s
// CHECK-NEXT: [[cmpVal:%[0-9]+]] = OpLoad %float %cmpVal
// CHECK-NEXT: [[clamp:%[0-9]+]] = OpLoad %float %clamp
// CHECK-NEXT: [[sampledImg:%[0-9]+]] = OpSampledImage %type_sampled_image_1 [[t2]] [[sampler]]
// CHECK-NEXT: {{%[0-9]+}} = OpImageSampleDrefExplicitLod %float [[sampledImg]] [[v2fc]] [[cmpVal]] Grad|ConstOffset|MinLod [[v2f_2]] [[v2f_3]] [[v2ic]] [[clamp]]
float val3 = t2.SampleCmpGrad(s, float2(1, 2), cmpVal, float2(2, 2), float2(3, 3), uint2(-5, 7), clamp);
uint status;
// CHECK: [[tcube:%[0-9]+]] = OpLoad %type_cube_image %tcube
// CHECK-NEXT: [[sampler:%[0-9]+]] = OpLoad %type_sampler %s
// CHECK-NEXT: [[cmpVal:%[0-9]+]] = OpLoad %float %cmpVal
// CHECK-NEXT: [[clamp:%[0-9]+]] = OpLoad %float %clamp
// CHECK-NEXT: [[sampledImg:%[0-9]+]] = OpSampledImage %type_sampled_image_2 [[tcube]] [[sampler]]
// CHECK-NEXT: [[structResult:%[0-9]+]] = OpImageSparseSampleDrefExplicitLod %SparseResidencyStruct [[sampledImg]] [[v3fc]] [[cmpVal]] Grad|MinLod [[v3f_1]] [[v3f_2]] [[clamp]]
// CHECK-NEXT: [[status:%[0-9]+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[result:%[0-9]+]] = OpCompositeExtract %float [[structResult]] 1
// CHECK-NEXT: OpStore %val4 [[result]]
float val4 = tcube.SampleCmpGrad(s, float3(1, 2, 3), cmpVal, float3(1, 1, 1), float3(2, 2, 2), clamp, status);
}