Commit 2a25ed8a by Nicolas Capens Committed by Nicolas Capens

Parse 'Sample' image instruction operand

OpImageFetch/Read/Write can have an optional 'Sample' operand which indicates the sample index to operate on. It is orthogonal to other operands so it is indicated by a new Boolean field in sw::SamplerFunction and SpirvShader::ImageInstruction. The offset operand was also turned into a Boolean field / component count. The sample index is not wired up to be taken into account by the Fetch sampling routine yet. OpImageRead already had support for the Sample operand, but OpImageWrite does not. Bug: b/135265531 Tests: dEQP-VK.pipeline.multisample.sampled_image.* Change-Id: I20f50a888436775b996221e8283a4c4ab7f28e17 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/32908Tested-by: 's avatarNicolas Capens <nicolascapens@google.com> Presubmit-Ready: Nicolas Capens <nicolascapens@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarChris Forbes <chrisforbes@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
parent 8fd5330f
...@@ -1231,7 +1231,7 @@ namespace sw ...@@ -1231,7 +1231,7 @@ namespace sw
void SamplerCore::computeIndices(UInt index[4], Short4 uuuu, Short4 vvvv, Short4 wwww, Vector4f &offset, const Pointer<Byte> &mipmap, SamplerFunction function) void SamplerCore::computeIndices(UInt index[4], Short4 uuuu, Short4 vvvv, Short4 wwww, Vector4f &offset, const Pointer<Byte> &mipmap, SamplerFunction function)
{ {
bool texelFetch = (function == Fetch); bool texelFetch = (function == Fetch);
bool hasOffset = (function.option == Offset); bool hasOffset = (function.offset != 0);
if(!texelFetch) if(!texelFetch)
{ {
...@@ -2088,7 +2088,7 @@ namespace sw ...@@ -2088,7 +2088,7 @@ namespace sw
if(function == Fetch) if(function == Fetch)
{ {
xyz0 = Min(Max(((function.option == Offset) && (addressingMode != ADDRESSING_LAYER)) ? As<Int4>(uvw) + As<Int4>(texOffset) : As<Int4>(uvw), Int4(0)), maxXYZ); xyz0 = Min(Max(((function.offset != 0) && (addressingMode != ADDRESSING_LAYER)) ? As<Int4>(uvw) + As<Int4>(texOffset) : As<Int4>(uvw), Int4(0)), maxXYZ);
} }
else if(addressingMode == ADDRESSING_LAYER) // Note: Offset does not apply to array layers else if(addressingMode == ADDRESSING_LAYER) // Note: Offset does not apply to array layers
{ {
...@@ -2139,7 +2139,7 @@ namespace sw ...@@ -2139,7 +2139,7 @@ namespace sw
Float4 floor = Floor(coord); Float4 floor = Floor(coord);
xyz0 = Int4(floor); xyz0 = Int4(floor);
if(function.option == Offset) if(function.offset != 0)
{ {
xyz0 += As<Int4>(texOffset); xyz0 += As<Int4>(texOffset);
} }
...@@ -2153,7 +2153,7 @@ namespace sw ...@@ -2153,7 +2153,7 @@ namespace sw
} }
else else
{ {
if(function.option != Offset) if(function.offset == 0)
{ {
switch(addressingMode) switch(addressingMode)
{ {
...@@ -2197,7 +2197,7 @@ namespace sw ...@@ -2197,7 +2197,7 @@ namespace sw
if(state.textureFilter == FILTER_POINT) if(state.textureFilter == FILTER_POINT)
{ {
if(addressingMode == ADDRESSING_BORDER || function.option == Offset) if(addressingMode == ADDRESSING_BORDER || function.offset != 0)
{ {
xyz0 = Int4(Floor(coord)); xyz0 = Int4(Floor(coord));
} }
...@@ -2223,7 +2223,7 @@ namespace sw ...@@ -2223,7 +2223,7 @@ namespace sw
f = coord - floor; f = coord - floor;
} }
if(function.option == Offset) if(function.offset != 0)
{ {
xyz0 += As<Int4>(texOffset); xyz0 += As<Int4>(texOffset);
} }
...@@ -2243,7 +2243,7 @@ namespace sw ...@@ -2243,7 +2243,7 @@ namespace sw
xyz0 |= border0; xyz0 |= border0;
xyz1 |= border1; xyz1 |= border1;
} }
else if(function.option == Offset) else if(function.offset != 0)
{ {
switch(addressingMode) switch(addressingMode)
{ {
......
...@@ -40,21 +40,18 @@ namespace sw ...@@ -40,21 +40,18 @@ namespace sw
SAMPLER_METHOD_LAST = Gather, SAMPLER_METHOD_LAST = Gather,
}; };
enum SamplerOption
{
None,
Offset, // Offset sample location by provided integer coordinates.
SAMPLER_OPTION_LAST = Offset,
};
// TODO(b/129523279): Eliminate and use SpirvShader::ImageInstruction instead. // TODO(b/129523279): Eliminate and use SpirvShader::ImageInstruction instead.
struct SamplerFunction struct SamplerFunction
{ {
SamplerFunction(SamplerMethod method, SamplerOption option = None) : method(method), option(option) {} SamplerFunction(SamplerMethod method, bool offset = false, bool sample = false)
: method(method), offset(offset), sample(sample)
{}
operator SamplerMethod() { return method; } operator SamplerMethod() { return method; }
const SamplerMethod method; const SamplerMethod method;
const SamplerOption option; const bool offset;
const bool sample;
}; };
class SamplerCore class SamplerCore
......
...@@ -4783,6 +4783,7 @@ namespace sw ...@@ -4783,6 +4783,7 @@ namespace sw
bool constOffset = false; bool constOffset = false;
Object::ID offsetId = 0; Object::ID offsetId = 0;
bool sample = false; bool sample = false;
Object::ID sampleId = 0;
uint32_t operand = (instruction.isDref() || instruction.samplerMethod == Gather) ? 6 : 5; uint32_t operand = (instruction.isDref() || instruction.samplerMethod == Gather) ? 6 : 5;
...@@ -4829,14 +4830,17 @@ namespace sw ...@@ -4829,14 +4830,17 @@ namespace sw
if(imageOperands & spv::ImageOperandsSampleMask) if(imageOperands & spv::ImageOperandsSampleMask)
{ {
UNIMPLEMENTED("Image operand %x", spv::ImageOperandsSampleMask); (void)sample;
sample = true; sample = true;
sampleId = insn.word(operand);
imageOperands &= ~spv::ImageOperandsSampleMask; imageOperands &= ~spv::ImageOperandsSampleMask;
ASSERT(instruction.samplerMethod == Fetch);
instruction.sample = true;
} }
if(imageOperands != 0) if(imageOperands != 0)
{ {
UNIMPLEMENTED("Image operand %x", imageOperands); UNSUPPORTED("Image operand %x", imageOperands);
} }
} }
...@@ -4887,7 +4891,7 @@ namespace sw ...@@ -4887,7 +4891,7 @@ namespace sw
auto &dxyType = getType(dxValue.type); auto &dxyType = getType(dxValue.type);
ASSERT(dxyType.sizeInComponents == getType(dyValue.type).sizeInComponents); ASSERT(dxyType.sizeInComponents == getType(dyValue.type).sizeInComponents);
instruction.gradComponents = dxyType.sizeInComponents; instruction.grad = dxyType.sizeInComponents;
for(uint32_t j = 0; j < dxyType.sizeInComponents; j++, i++) for(uint32_t j = 0; j < dxyType.sizeInComponents; j++, i++)
{ {
...@@ -4913,8 +4917,7 @@ namespace sw ...@@ -4913,8 +4917,7 @@ namespace sw
auto offsetValue = GenericValue(this, state->routine, offsetId); auto offsetValue = GenericValue(this, state->routine, offsetId);
auto &offsetType = getType(offsetValue.type); auto &offsetType = getType(offsetValue.type);
instruction.samplerOption = Offset; instruction.offset = offsetType.sizeInComponents;
instruction.offsetComponents = offsetType.sizeInComponents;
for(uint32_t j = 0; j < offsetType.sizeInComponents; j++, i++) for(uint32_t j = 0; j < offsetType.sizeInComponents; j++, i++)
{ {
...@@ -4922,6 +4925,12 @@ namespace sw ...@@ -4922,6 +4925,12 @@ namespace sw
} }
} }
if(sample)
{
auto sampleValue = GenericValue(this, state->routine, sampleId);
in[i] = sampleValue.Float(0);
}
auto samplerFunc = Call(getImageSampler, instruction.parameters, imageDescriptor, sampler); auto samplerFunc = Call(getImageSampler, instruction.parameters, imageDescriptor, sampler);
Array<SIMD::Float> out(4); Array<SIMD::Float> out(4);
...@@ -5455,7 +5464,7 @@ namespace sw ...@@ -5455,7 +5464,7 @@ namespace sw
ASSERT(imageType.definition.opcode() == spv::OpTypeImage); ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
// Not handling any image operands yet. // TODO(b/131171141): Not handling any image operands yet.
ASSERT(insn.wordCount() == 4); ASSERT(insn.wordCount() == 4);
auto coordinate = GenericValue(this, state->routine, insn.word(2)); auto coordinate = GenericValue(this, state->routine, insn.word(2));
......
...@@ -504,7 +504,7 @@ namespace sw ...@@ -504,7 +504,7 @@ namespace sw
SamplerFunction getSamplerFunction() const SamplerFunction getSamplerFunction() const
{ {
return { static_cast<SamplerMethod>(samplerMethod), static_cast<SamplerOption>(samplerOption) }; return { static_cast<SamplerMethod>(samplerMethod), offset != 0, sample != 0 };
} }
bool isDref() const bool isDref() const
...@@ -523,22 +523,22 @@ namespace sw ...@@ -523,22 +523,22 @@ namespace sw
{ {
uint32_t variant : BITS(VARIANT_LAST); uint32_t variant : BITS(VARIANT_LAST);
uint32_t samplerMethod : BITS(SAMPLER_METHOD_LAST); uint32_t samplerMethod : BITS(SAMPLER_METHOD_LAST);
uint32_t samplerOption : BITS(SAMPLER_OPTION_LAST);
uint32_t gatherComponent : 2; uint32_t gatherComponent : 2;
// Parameters are passed to the sampling routine in this order: // Parameters are passed to the sampling routine in this order:
uint32_t coordinates : 3; // 1-4 (does not contain projection component) uint32_t coordinates : 3; // 1-4 (does not contain projection component)
// uint32_t dref : 1; // Indicated by Variant::ProjDref|Dref // uint32_t dref : 1; // Indicated by Variant::ProjDref|Dref
// uint32_t lodOrBias : 1; // Indicated by SamplerMethod::Lod|Bias|Fetch // uint32_t lodOrBias : 1; // Indicated by SamplerMethod::Lod|Bias|Fetch
uint32_t gradComponents : 2; // 0-3 (for each of dx / dy) uint32_t grad : 2; // 0-3 components (for each of dx / dy)
uint32_t offsetComponents : 2; // 0-3 uint32_t offset : 2; // 0-3 components
uint32_t sample : 1; // 0-1 scalar integer
}; };
uint32_t parameters; uint32_t parameters;
}; };
}; };
static_assert(sizeof(ImageInstruction) == 4, "ImageInstruction must be 32-bit"); static_assert(sizeof(ImageInstruction) == sizeof(uint32_t), "ImageInstruction must be 32-bit");
int getSerialID() const int getSerialID() const
{ {
......
...@@ -164,24 +164,23 @@ SpirvShader::ImageSampler *SpirvShader::emitSamplerFunction(ImageInstruction ins ...@@ -164,24 +164,23 @@ SpirvShader::ImageSampler *SpirvShader::emitSamplerFunction(ImageInstruction ins
} }
else if(instruction.samplerMethod == Grad) else if(instruction.samplerMethod == Grad)
{ {
for(uint32_t j = 0; j < instruction.gradComponents; j++, i++) for(uint32_t j = 0; j < instruction.grad; j++, i++)
{ {
dsx[j] = in[i]; dsx[j] = in[i];
} }
for(uint32_t j = 0; j < instruction.gradComponents; j++, i++) for(uint32_t j = 0; j < instruction.grad; j++, i++)
{ {
dsy[j] = in[i]; dsy[j] = in[i];
} }
} }
if(instruction.samplerOption == Offset) for(uint32_t j = 0; j < instruction.offset; j++, i++)
{
for(uint32_t j = 0; j < instruction.offsetComponents; j++, i++)
{ {
offset[j] = in[i]; offset[j] = in[i];
} }
}
// TODO(b/133868964): Handle 'Sample' operand.
SamplerCore s(constants, samplerState); SamplerCore s(constants, samplerState);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment