[spirv] Support non-constant offsets in .Gather*() methods (#1232)
They are emulated via 4 separate OpImage*Gather instructions.
This commit is contained in:
Родитель
4ac938cc5b
Коммит
4491a30fba
|
@ -2199,7 +2199,9 @@ There are a few overloads for these functions:
|
|||
|
||||
- For those overloads taking 4 offset parameters, those offset parameters will
|
||||
be conveyed as an additional ``ConstOffsets`` image operands to the
|
||||
instruction. So those offset parameters must all be constant values.
|
||||
instruction if those offset parameters are all constants. Otherwise,
|
||||
4 separate ``OpImageGather`` instructions will be emitted to get each texel
|
||||
from each offset, using the ``Offset`` image operands.
|
||||
- For those overloads with the ``status`` parameter, ``OpImageSparseGather``
|
||||
is used instead, and the resulting SPIR-V ``Residency Code`` will be
|
||||
written to ``status``.
|
||||
|
|
|
@ -2939,6 +2939,7 @@ uint32_t SPIRVEmitter::processTextureGatherRGBACmpRGBA(
|
|||
const uint32_t compareVal = isCmp ? doExpr(expr->getArg(2)) : 0;
|
||||
|
||||
// Handle offsets (if any).
|
||||
bool needsEmulation = false;
|
||||
uint32_t constOffset = 0, varOffset = 0, constOffsets = 0;
|
||||
if (numOffsetArgs == 1) {
|
||||
// The offset arg is not optional.
|
||||
|
@ -2949,21 +2950,40 @@ uint32_t SPIRVEmitter::processTextureGatherRGBACmpRGBA(
|
|||
const auto offset2 = tryToEvaluateAsConst(expr->getArg(4 + isCmp));
|
||||
const auto offset3 = tryToEvaluateAsConst(expr->getArg(5 + isCmp));
|
||||
|
||||
// Make sure we can generate the ConstOffsets image operands in SPIR-V.
|
||||
if (!offset0 || !offset1 || !offset2 || !offset3) {
|
||||
emitError("all offset parameters to '%0' method call must be constants",
|
||||
expr->getExprLoc())
|
||||
<< callee->getName() << expr->getSourceRange();
|
||||
return 0;
|
||||
// If any of the offsets is not constant, we then need to emulate the call
|
||||
// using 4 OpImageGather instructions. Otherwise, we can leverage the
|
||||
// ConstOffsets image operand.
|
||||
if (offset0 && offset1 && offset2 && offset3) {
|
||||
const uint32_t v2i32 =
|
||||
theBuilder.getVecType(theBuilder.getInt32Type(), 2);
|
||||
const uint32_t offsetType =
|
||||
theBuilder.getArrayType(v2i32, theBuilder.getConstantUint32(4));
|
||||
constOffsets = theBuilder.getConstantComposite(
|
||||
offsetType, {offset0, offset1, offset2, offset3});
|
||||
} else {
|
||||
needsEmulation = true;
|
||||
}
|
||||
const uint32_t v2i32 = theBuilder.getVecType(theBuilder.getInt32Type(), 2);
|
||||
const uint32_t offsetType =
|
||||
theBuilder.getArrayType(v2i32, theBuilder.getConstantUint32(4));
|
||||
constOffsets = theBuilder.getConstantComposite(
|
||||
offsetType, {offset0, offset1, offset2, offset3});
|
||||
}
|
||||
|
||||
const auto status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : 0;
|
||||
|
||||
if (needsEmulation) {
|
||||
const auto elemType = typeTranslator.translateType(
|
||||
hlsl::GetHLSLVecElementType(callee->getReturnType()));
|
||||
|
||||
uint32_t texels[4];
|
||||
for (uint32_t i = 0; i < 4; ++i) {
|
||||
varOffset = doExpr(expr->getArg(2 + isCmp + i));
|
||||
const uint32_t gatherRet = theBuilder.createImageGather(
|
||||
retTypeId, imageTypeId, image, sampler, coordinate,
|
||||
theBuilder.getConstantInt32(component), compareVal, /*constOffset*/ 0,
|
||||
varOffset, /*constOffsets*/ 0, /*sampleNumber*/ 0, status);
|
||||
texels[i] = theBuilder.createCompositeExtract(elemType, gatherRet, {i});
|
||||
}
|
||||
return theBuilder.createCompositeConstruct(
|
||||
retTypeId, {texels[0], texels[1], texels[2], texels[3]});
|
||||
}
|
||||
|
||||
return theBuilder.createImageGather(
|
||||
retTypeId, imageTypeId, image, sampler, coordinate,
|
||||
theBuilder.getConstantInt32(component), compareVal, constOffset,
|
||||
|
|
|
@ -21,7 +21,7 @@ TextureCubeArray<int4> tCubeArray : register(t3);
|
|||
|
||||
// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
|
||||
|
||||
float4 main(float3 location: A) : SV_Target {
|
||||
float4 main(float3 location: A, int2 offset : B) : SV_Target {
|
||||
// CHECK: [[t2f4:%\d+]] = OpLoad %type_2d_image_array %t2f4
|
||||
// CHECK-NEXT: [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
|
||||
// CHECK-NEXT: [[loc:%\d+]] = OpLoad %v3float %location
|
||||
|
@ -85,5 +85,18 @@ float4 main(float3 location: A) : SV_Target {
|
|||
// CHECK-NEXT: OpStore %g [[result]]
|
||||
int4 g = tCubeArray.GatherRed(gSampler, /*location*/ float4(1.5, 1.5, 1.5, 1.5), status);
|
||||
|
||||
// CHECK: [[offset:%\d+]] = OpLoad %v2int %offset
|
||||
// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[offset]]
|
||||
// CHECK: [[texel0:%\d+]] = OpCompositeExtract %float [[gather]] 0
|
||||
// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[c34]]
|
||||
// CHECK: [[texel1:%\d+]] = OpCompositeExtract %float [[gather]] 1
|
||||
// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[c56]]
|
||||
// CHECK: [[texel2:%\d+]] = OpCompositeExtract %float [[gather]] 2
|
||||
// CHECK: [[offset:%\d+]] = OpLoad %v2int %offset
|
||||
// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[offset]]
|
||||
// CHECK: [[texel3:%\d+]] = OpCompositeExtract %float [[gather]] 3
|
||||
// CHECK: OpCompositeConstruct %v4float [[texel0]] [[texel1]] [[texel2]] [[texel3]]
|
||||
float4 h = t2f4.GatherRed(gSampler, location, offset, int2(3, 4), int2(5, 6), offset);
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ TextureCube<int4> tCube : register(t3);
|
|||
|
||||
// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
|
||||
|
||||
float4 main(float2 location: A) : SV_Target {
|
||||
float4 main(float2 location: A, int2 offset : B) : SV_Target {
|
||||
// CHECK: [[t2f4:%\d+]] = OpLoad %type_2d_image %t2f4
|
||||
// CHECK-NEXT: [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
|
||||
// CHECK-NEXT: [[loc:%\d+]] = OpLoad %v2float %location
|
||||
|
@ -86,5 +86,18 @@ float4 main(float2 location: A) : SV_Target {
|
|||
// CHECK-NEXT: OpStore %g [[result]]
|
||||
int4 g = tCube.GatherRed(gSampler, /*location*/ float3(1.5, 1.5, 1.5), status);
|
||||
|
||||
// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[c12]]
|
||||
// CHECK: [[texel0:%\d+]] = OpCompositeExtract %float [[gather]] 0
|
||||
// CHECK: [[offset:%\d+]] = OpLoad %v2int %offset
|
||||
// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[offset]]
|
||||
// CHECK: [[texel1:%\d+]] = OpCompositeExtract %float [[gather]] 1
|
||||
// CHECK: [[offset:%\d+]] = OpLoad %v2int %offset
|
||||
// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[offset]]
|
||||
// CHECK: [[texel2:%\d+]] = OpCompositeExtract %float [[gather]] 2
|
||||
// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[c78]]
|
||||
// CHECK: [[texel3:%\d+]] = OpCompositeExtract %float [[gather]] 3
|
||||
// CHECK: OpCompositeConstruct %v4float [[texel0]] [[texel1]] [[texel2]] [[texel3]]
|
||||
float4 h = t2f4.GatherRed(gSampler, location, int2(1, 2), offset, offset, int2(7, 8));
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче