Add support for Sample image operand in OpImageRead
Enables reading from multisampled input attachments and storage images
Bug: b/131171141
Test: dEQP-VK.renderpass.*.multisample.*
Change-Id: I719d54c31eb12f58ba7fbdd614ecf3073bfc6d40
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/30553
Presubmit-Ready: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 16a4d73..2c912c7 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -4756,7 +4756,7 @@
return EmitResult::Continue;
}
- SIMD::Pointer SpirvShader::GetTexelAddress(SpirvRoutine const *routine, SIMD::Pointer ptr, GenericValue const & coordinate, Type const & imageType, Pointer<Byte> descriptor, int texelSize) const
+ SIMD::Pointer SpirvShader::GetTexelAddress(SpirvRoutine const *routine, SIMD::Pointer ptr, GenericValue const & coordinate, Type const & imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId) const
{
bool isArrayed = imageType.definition.word(5) != 0;
auto dim = static_cast<spv::Dim>(imageType.definition.word(3));
@@ -4787,6 +4787,13 @@
*Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, slicePitchBytes)));
}
+ if (sampleId.value())
+ {
+ GenericValue sample{this, routine, sampleId};
+ ptr += sample.Int(0) * SIMD::Int(
+ *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, samplePitchBytes)));
+ }
+
return ptr;
}
@@ -4798,8 +4805,21 @@
auto &imageType = getType(image.type);
Object::ID resultId = insn.word(2);
- // Not handling any image operands yet.
- ASSERT(insn.wordCount() == 5);
+ Object::ID sampleId = 0;
+
+ if (insn.wordCount() > 5)
+ {
+ int operand = 6;
+ auto imageOperands = insn.word(5);
+ if (imageOperands & spv::ImageOperandsSampleMask)
+ {
+ sampleId = insn.word(operand++);
+ imageOperands &= ~spv::ImageOperandsSampleMask;
+ }
+
+ // Should be no remaining image operands.
+ ASSERT(!imageOperands);
+ }
ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
auto dim = static_cast<spv::Dim>(imageType.definition.word(3));
@@ -4821,7 +4841,7 @@
: SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(imageType.definition.word(8)));
auto texelSize = vk::Format(vkFormat).bytes();
auto basePtr = SIMD::Pointer(imageBase, imageSizeInBytes);
- auto texelPtr = GetTexelAddress(state->routine, basePtr, coordinate, imageType, binding, texelSize);
+ auto texelPtr = GetTexelAddress(state->routine, basePtr, coordinate, imageType, binding, texelSize, sampleId);
SIMD::Int packed[4];
// Round up texel size: for formats smaller than 32 bits per texel, we will emit a bunch
@@ -5156,7 +5176,7 @@
}
auto basePtr = SIMD::Pointer(imageBase, imageSizeInBytes);
- auto texelPtr = GetTexelAddress(state->routine, basePtr, coordinate, imageType, binding, texelSize);
+ auto texelPtr = GetTexelAddress(state->routine, basePtr, coordinate, imageType, binding, texelSize, 0);
for (auto i = 0u; i < numPackedElements; i++)
{
@@ -5188,7 +5208,7 @@
auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
auto basePtr = SIMD::Pointer(imageBase, imageSizeInBytes);
- auto ptr = GetTexelAddress(state->routine, basePtr, coordinate, imageType, binding, sizeof(uint32_t));
+ auto ptr = GetTexelAddress(state->routine, basePtr, coordinate, imageType, binding, sizeof(uint32_t), 0);
state->routine->createPointer(resultId, ptr);
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index a97b376..b893073 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -909,7 +909,7 @@
EmitResult EmitCopyMemory(InsnIterator insn, EmitState *state) const;
EmitResult EmitGroupNonUniform(InsnIterator insn, EmitState *state) const;
- SIMD::Pointer GetTexelAddress(SpirvRoutine const * routine, SIMD::Pointer base, GenericValue const & coordinate, Type const & imageType, Pointer<Byte> descriptor, int texelSize) const;
+ SIMD::Pointer GetTexelAddress(SpirvRoutine const * routine, SIMD::Pointer base, GenericValue const & coordinate, Type const & imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId) const;
spv::Scope GetScope(Object::ID id) const;
// OpcodeName() returns the name of the opcode op.
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp
index e0566a1..d44bbab 100644
--- a/src/Vulkan/VkDescriptorSetLayout.cpp
+++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -490,9 +490,10 @@
descriptor[i].ptr = imageView->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_COLOR_BIT, 0, 0);
descriptor[i].extent = imageView->getMipLevelExtent(0);
descriptor[i].rowPitchBytes = imageView->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
- descriptor[i].slicePitchBytes = imageView->getSubresourceRange().layerCount > 1
- ? imageView->layerPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT)
- : imageView->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
+ descriptor[i].samplePitchBytes = imageView->getSubresourceRange().layerCount > 1
+ ? imageView->layerPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT)
+ : imageView->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
+ descriptor[i].slicePitchBytes = descriptor[i].samplePitchBytes * imageView->getSampleCount();
descriptor[i].arrayLayers = imageView->getSubresourceRange().layerCount;
descriptor[i].sizeInBytes = imageView->getImageSizeInBytes();
}
@@ -508,6 +509,7 @@
descriptor[i].extent = {bufferView->getElementCount(), 1, 1};
descriptor[i].rowPitchBytes = 0;
descriptor[i].slicePitchBytes = 0;
+ descriptor[i].samplePitchBytes = 0;
descriptor[i].arrayLayers = 1;
descriptor[i].sizeInBytes = bufferView->getRangeInBytes();
}
diff --git a/src/Vulkan/VkDescriptorSetLayout.hpp b/src/Vulkan/VkDescriptorSetLayout.hpp
index e63bb4f..38722d5 100644
--- a/src/Vulkan/VkDescriptorSetLayout.hpp
+++ b/src/Vulkan/VkDescriptorSetLayout.hpp
@@ -44,6 +44,7 @@
VkExtent3D extent;
int rowPitchBytes;
int slicePitchBytes;
+ int samplePitchBytes;
int arrayLayers;
int sizeInBytes;
};
diff --git a/src/Vulkan/VkImageView.hpp b/src/Vulkan/VkImageView.hpp
index 27d909c..6daa326 100644
--- a/src/Vulkan/VkImageView.hpp
+++ b/src/Vulkan/VkImageView.hpp
@@ -45,12 +45,23 @@
VkImageViewType getType() const { return viewType; }
Format getFormat(Usage usage = RAW) const;
- int getSampleCount() const { return image->getSampleCountFlagBits(); }
int rowPitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel, Usage usage = RAW) const;
int slicePitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel, Usage usage = RAW) const;
int layerPitchBytes(VkImageAspectFlagBits aspect, Usage usage = RAW) const;
VkExtent3D getMipLevelExtent(uint32_t mipLevel) const;
+ int getSampleCount() const
+ {
+ switch (image->getSampleCountFlagBits())
+ {
+ case VK_SAMPLE_COUNT_1_BIT: return 1;
+ case VK_SAMPLE_COUNT_4_BIT: return 4;
+ default:
+ UNIMPLEMENTED("Sample count flags %d", image->getSampleCountFlagBits());
+ return 1;
+ }
+ }
+
void *getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer, Usage usage = RAW) const;
bool hasDepthAspect() const { return (subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; }
bool hasStencilAspect() const { return (subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; }