[spirv] Support non-constant offsets in .Gather*() methods (#1232)

They are emulated via 4 separate OpImage*Gather instructions.
This commit is contained in:
Lei Zhang 2018-04-16 17:21:02 -04:00 коммит произвёл GitHub
Родитель 4ac938cc5b
Коммит 4491a30fba
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 62 добавлений и 14 удалений

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

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