Implement OpImageSampleExplicitLod with Grad operand
OpImageSampleExplicitLod can either have a Lod or Grad operand.
Bug: b/129523279
Test: dEQP-VK.glsl.texture_functions.texturegrad.sampler2d_fixed_fragment
Change-Id: I0c4a885cc6833614572ed7a061b53c9f41838f0b
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/30032
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 57bbd47..4b72909 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -4456,16 +4456,23 @@
SpirvShader::EmitResult SpirvShader::EmitImageSampleImplicitLod(InsnIterator insn, EmitState *state) const
{
- ImageInstruction imageInstruction(Implicit);
-
- return EmitImageSample(imageInstruction, insn, state);
+ return EmitImageSample({Implicit}, insn, state);
}
SpirvShader::EmitResult SpirvShader::EmitImageSampleExplicitLod(InsnIterator insn, EmitState *state) const
{
- ImageInstruction imageInstruction(Lod);
+ uint32_t imageOperands = static_cast<spv::ImageOperandsMask>(insn.word(5));
- return EmitImageSample(imageInstruction, insn, state);
+ if((imageOperands & spv::ImageOperandsLodMask) == imageOperands)
+ {
+ return EmitImageSample({Lod}, insn, state);
+ }
+ else if((imageOperands & spv::ImageOperandsGradMask) == imageOperands)
+ {
+ return EmitImageSample({Grad}, insn, state);
+ }
+ else UNIMPLEMENTED("Image Operands %x", imageOperands);
+ return EmitResult::Continue;
}
SpirvShader::EmitResult SpirvShader::EmitImageSample(ImageInstruction instruction, InsnIterator insn, EmitState *state) const
@@ -4485,14 +4492,13 @@
auto sampler = *Pointer<Pointer<Byte>>(descriptor + OFFSET(vk::SampledImageDescriptor, sampler)); // vk::Sampler*
auto imageView = *Pointer<Pointer<Byte>>(descriptor + OFFSET(vk::SampledImageDescriptor, imageView)); // vk::ImageView*
- instruction.coordinates = coordinateType.sizeInComponents;
- auto samplerFunc = Call(getImageSampler, instruction.parameters, imageView, sampler);
-
uint32_t imageOperands = spv::ImageOperandsMaskNone;
bool bias = false;
bool lod = false;
Object::ID lodId = 0;
bool grad = false;
+ Object::ID gradDxId = 0;
+ Object::ID gradDyId = 0;
bool constOffset = false;
bool sample = false;
@@ -4518,8 +4524,11 @@
if(imageOperands & spv::ImageOperandsGradMask)
{
- UNIMPLEMENTED("Image operand %x", spv::ImageOperandsGradMask); (void)grad;
+ ASSERT(!lod); // SPIR-V 1.3: "It is invalid to set both the Lod and Grad bits."
grad = true;
+ gradDxId = insn.word(operand + 0);
+ gradDyId = insn.word(operand + 1);
+ operand += 2;
imageOperands &= ~spv::ImageOperandsGradMask;
}
@@ -4543,7 +4552,7 @@
}
}
- Array<SIMD::Float> in(coordinateType.sizeInComponents + lod);
+ Array<SIMD::Float> in(16); // Maximum 16 input parameter components.
uint32_t i = 0;
for( ; i < coordinateType.sizeInComponents; i++)
@@ -4557,6 +4566,31 @@
in[i] = lodValue.Float(0);
i++;
}
+ else if(grad)
+ {
+ auto dxValue = GenericValue(this, state->routine, gradDxId);
+ auto dyValue = GenericValue(this, state->routine, gradDyId);
+ auto &dxyType = getType(dxValue.type);
+ ASSERT(dxyType.sizeInComponents == getType(dyValue.type).sizeInComponents);
+
+ instruction.gradComponents = dxyType.sizeInComponents;
+
+ for(uint32_t j = 0; j < dxyType.sizeInComponents; j++)
+ {
+ in[i] = dxValue.Float(j);
+ i++;
+ }
+
+ for(uint32_t j = 0; j < dxyType.sizeInComponents; j++)
+ {
+ in[i] = dyValue.Float(j);
+ i++;
+ }
+ }
+
+ instruction.coordinates = coordinateType.sizeInComponents;
+
+ auto samplerFunc = Call(getImageSampler, instruction.parameters, imageView, sampler);
Array<SIMD::Float> out(4);
Call<ImageSampler>(samplerFunc, sampledImage.base, &in[0], &out[0], state->routine->constants);
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index beb21b9..143b282 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -491,7 +491,8 @@
struct
{
uint32_t samplerMethod : BITS(SAMPLER_METHOD_LAST);
- uint32_t coordinates : 3;
+ uint32_t coordinates : 3; // 1-4
+ uint32_t gradComponents : 2; // 0-3 (for each of dx / dy)
};
uint32_t parameters = 0;
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp
index baf5c32..d28abc4 100644
--- a/src/Pipeline/SpirvShaderSampling.cpp
+++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -119,12 +119,23 @@
uvw[1] = SIMD::Float(0);
}
+ // Lod and Grad are explicit-lod image operands, and always come after the coordinates.
if(instruction.samplerMethod == Lod)
{
- // Lod is the second optional image operand, and is incompatible with the first one (Bias),
- // so it always comes after the coordinates.
bias = in[instruction.coordinates];
}
+ else if(instruction.samplerMethod == Grad)
+ {
+ for(uint32_t i = 0; i < instruction.gradComponents; i++)
+ {
+ dsx[i] = in[instruction.coordinates + i];
+ }
+
+ for(uint32_t i = 0; i < instruction.gradComponents; i++)
+ {
+ dsy[i] = in[instruction.coordinates + instruction.gradComponents + i];
+ }
+ }
Vector4f sample = s.sampleTexture(texture, uvw[0], uvw[1], uvw[2], q, bias, dsx, dsy, offset, samplerFunction);