Add support for OpImageRead
Bug: b/130768731
Test: dEQP-VK.image.*
Change-Id: Ib3e9b5cd4b28f9ed3020dcd4e724cf961c3ddac3
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29410
Tested-by: Chris Forbes <chrisforbes@google.com>
Presubmit-Ready: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 682c7d6..301c0d6 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -681,6 +681,7 @@
case spv::OpPhi:
case spv::OpImageSampleImplicitLod:
case spv::OpImageQuerySize:
+ case spv::OpImageRead:
// Instructions that yield an intermediate value or divergent pointer
DefineResult(insn);
break;
@@ -2140,6 +2141,9 @@
case spv::OpImageQuerySize:
return EmitImageQuerySize(insn, state);
+ case spv::OpImageRead:
+ return EmitImageRead(insn, state);
+
case spv::OpImageWrite:
return EmitImageWrite(insn, state);
@@ -4408,6 +4412,176 @@
return EmitResult::Continue;
}
+ SpirvShader::EmitResult SpirvShader::EmitImageRead(InsnIterator insn, EmitState *state) const
+ {
+ auto &resultType = getType(Type::ID(insn.word(1)));
+ auto imageId = Object::ID(insn.word(3));
+ auto &image = getObject(imageId);
+ auto &imageType = getType(image.type);
+ Object::ID resultId = insn.word(2);
+
+ // Not handling any image operands yet.
+ ASSERT(insn.wordCount() == 5);
+
+ ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
+
+ const DescriptorDecorations &d = descriptorDecorations.at(imageId);
+ uint32_t arrayIndex = 0; // TODO(b/129523279)
+ auto setLayout = state->routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet);
+ size_t bindingOffset = setLayout->getBindingOffset(d.Binding, arrayIndex);
+
+ auto coordinate = GenericValue(this, state->routine, insn.word(4));
+
+ Pointer<Byte> set = state->routine->descriptorSets[d.DescriptorSet]; // DescriptorSet*
+ Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset);
+ Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr));
+
+ auto &dst = state->routine->createIntermediate(resultId, resultType.sizeInComponents);
+
+
+ SIMD::Int packed[4];
+ auto numPackedElements = 0u;
+ int texelSize = 0;
+ auto format = static_cast<spv::ImageFormat>(imageType.definition.word(8));
+ switch (format)
+ {
+ case spv::ImageFormatRgba32f:
+ case spv::ImageFormatRgba32i:
+ case spv::ImageFormatRgba32ui:
+ texelSize = 16;
+ numPackedElements = 4;
+ break;
+ case spv::ImageFormatR32f:
+ case spv::ImageFormatR32i:
+ case spv::ImageFormatR32ui:
+ texelSize = 4;
+ numPackedElements = 1;
+ break;
+ case spv::ImageFormatRgba8:
+ texelSize = 4;
+ numPackedElements = 1;
+ break;
+ case spv::ImageFormatRgba8Snorm:
+ texelSize = 4;
+ numPackedElements = 1;
+ break;
+ case spv::ImageFormatRgba8i:
+ case spv::ImageFormatRgba8ui:
+ texelSize = 4;
+ numPackedElements = 1;
+ break;
+ case spv::ImageFormatRgba16f:
+ texelSize = 8;
+ numPackedElements = 2;
+ break;
+ case spv::ImageFormatRgba16i:
+ case spv::ImageFormatRgba16ui:
+ texelSize = 8;
+ numPackedElements = 2;
+ break;
+ default:
+ UNIMPLEMENTED("spv::ImageFormat %u", format);
+ }
+
+ SIMD::Int texelOffset = coordinate.Int(0) * SIMD::Int(texelSize);
+ if (getType(coordinate.type).sizeInComponents > 1)
+ {
+ texelOffset += coordinate.Int(1) * SIMD::Int(
+ *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, rowPitchBytes)));
+ }
+ if (getType(coordinate.type).sizeInComponents > 2)
+ {
+ texelOffset += coordinate.Int(2) * SIMD::Int(
+ *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, slicePitchBytes)));
+ }
+
+ for (auto i = 0u; i < numPackedElements; i++)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ If(Extract(state->activeLaneMask(), j) != 0)
+ {
+ Int offset = Int(sizeof(float) * i) + Extract(texelOffset, j);
+ packed[i] = Insert(packed[i], Load(RValue<Pointer<Int>>(&imageBase[offset]), sizeof(uint32_t), false,
+ std::memory_order_relaxed), j);
+ }
+ }
+ }
+
+ switch(format)
+ {
+ case spv::ImageFormatRgba32f:
+ case spv::ImageFormatRgba32i:
+ case spv::ImageFormatRgba32ui:
+ dst.move(0, packed[0]);
+ dst.move(1, packed[1]);
+ dst.move(2, packed[2]);
+ dst.move(3, packed[3]);
+ break;
+ case spv::ImageFormatR32i:
+ case spv::ImageFormatR32ui:
+ dst.move(0, packed[0]);
+ // Fill remaining channels with 0,0,1 (of the correct type)
+ dst.move(1, SIMD::Int(0));
+ dst.move(2, SIMD::Int(0));
+ dst.move(3, SIMD::Int(1));
+ break;
+ case spv::ImageFormatR32f:
+ dst.move(0, packed[0]);
+ // Fill remaining channels with 0,0,1 (of the correct type)
+ dst.move(1, SIMD::Float(0));
+ dst.move(2, SIMD::Float(0));
+ dst.move(3, SIMD::Float(1));
+ break;
+ case spv::ImageFormatRgba16i:
+ dst.move(0, (packed[0] << 16) >> 16);
+ dst.move(1, (packed[0]) >> 16);
+ dst.move(2, (packed[1] << 16) >> 16);
+ dst.move(3, (packed[1]) >> 16);
+ break;
+ case spv::ImageFormatRgba16ui:
+ dst.move(0, packed[0] & SIMD::Int(0xffff));
+ dst.move(1, (packed[0] >> 16) & SIMD::Int(0xffff));
+ dst.move(2, packed[1] & SIMD::Int(0xffff));
+ dst.move(3, (packed[1] >> 16) & SIMD::Int(0xffff));
+ break;
+ case spv::ImageFormatRgba16f:
+ dst.move(0, HalfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
+ dst.move(1, HalfToFloatBits((As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFFFF0000)) >> 16));
+ dst.move(2, HalfToFloatBits(As<SIMD::UInt>(packed[1]) & SIMD::UInt(0x0000FFFF)));
+ dst.move(3, HalfToFloatBits((As<SIMD::UInt>(packed[1]) & SIMD::UInt(0xFFFF0000)) >> 16));
+ break;
+ case spv::ImageFormatRgba8Snorm:
+ dst.move(0, Min(Max(SIMD::Float(((packed[0]<<24) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f)));
+ dst.move(1, Min(Max(SIMD::Float(((packed[0]<<16) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f)));
+ dst.move(2, Min(Max(SIMD::Float(((packed[0]<<8) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f)));
+ dst.move(3, Min(Max(SIMD::Float(((packed[0]) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f)));
+ break;
+ case spv::ImageFormatRgba8:
+ dst.move(0, SIMD::Float((packed[0] & SIMD::Int(0xFF))) * SIMD::Float(1.0f / 255.f));
+ dst.move(1, SIMD::Float(((packed[0]>>8) & SIMD::Int(0xFF))) * SIMD::Float(1.0f / 255.f));
+ dst.move(2, SIMD::Float(((packed[0]>>16) & SIMD::Int(0xFF))) * SIMD::Float(1.0f / 255.f));
+ dst.move(3, SIMD::Float(((packed[0]>>24) & SIMD::Int(0xFF))) * SIMD::Float(1.0f / 255.f));
+ break;
+ case spv::ImageFormatRgba8ui:
+ dst.move(0, (As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF)));
+ dst.move(1, ((As<SIMD::UInt>(packed[0])>>8) & SIMD::UInt(0xFF)));
+ dst.move(2, ((As<SIMD::UInt>(packed[0])>>16) & SIMD::UInt(0xFF)));
+ dst.move(3, ((As<SIMD::UInt>(packed[0])>>24) & SIMD::UInt(0xFF)));
+ break;
+ case spv::ImageFormatRgba8i:
+ dst.move(0, (packed[0] << 24) >> 24);
+ dst.move(1, (packed[0] << 16) >> 24);
+ dst.move(2, (packed[0] << 8) >> 24);
+ dst.move(3, (packed[0]) >> 24);
+ break;
+ default:
+ UNIMPLEMENTED("");
+ }
+
+ return EmitResult::Continue;
+ }
+
SpirvShader::EmitResult SpirvShader::EmitImageWrite(InsnIterator insn, EmitState *state) const
{
auto imageId = Object::ID(insn.word(1));
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index e70571f..e394db1 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -724,6 +724,7 @@
EmitResult EmitPhi(InsnIterator insn, EmitState *state) const;
EmitResult EmitImageSampleImplicitLod(InsnIterator insn, EmitState *state) const;
EmitResult EmitImageQuerySize(InsnIterator insn, EmitState *state) const;
+ EmitResult EmitImageRead(InsnIterator insn, EmitState *state) const;
EmitResult EmitImageWrite(InsnIterator insn, EmitState *state) const;
// OpcodeName() returns the name of the opcode op.