Parse the OpTypeImage information into ImageInstructionSignature
This will provide everything we need to make GetTexelAddress() no longer
have to parse SPIR-V, which in turn will allow using it in a trampolined
sampling routine to support storageImageWriteWithoutFormat.
Bug: b/203730083
Change-Id: I374850f4d2137375a48f62b19f774c028c2c6229
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/59508
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 60750be..8bd25af 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -514,7 +514,6 @@
struct ImageInstructionSignature
{
ImageInstructionSignature(Variant variant, SamplerMethod samplerMethod)
- : signature(0)
{
this->variant = variant;
this->samplerMethod = samplerMethod;
@@ -557,6 +556,9 @@
Variant variant : BITS(VARIANT_LAST);
SamplerMethod samplerMethod : BITS(SAMPLER_METHOD_LAST);
uint32_t gatherComponent : 2;
+ uint32_t dim : BITS(spv::DimSubpassData); // spv::Dim
+ uint32_t arrayed : 1;
+ uint32_t imageFormat : BITS(spv::ImageFormatR64i); // spv::ImageFormat
// Parameters are passed to the sampling routine in this order:
uint32_t coordinates : 3; // 1-4 (does not contain projection component)
@@ -567,7 +569,7 @@
uint32_t sample : 1; // 0-1 scalar integer
};
- uint32_t signature;
+ uint32_t signature = 0;
};
};
@@ -805,7 +807,7 @@
};
std::unordered_map<Object::ID, DescriptorDecorations> descriptorDecorations;
- std::vector<VkFormat> inputAttachmentFormats;
+ std::vector<vk::Format> inputAttachmentFormats;
struct InterfaceComponent
{
diff --git a/src/Pipeline/SpirvShaderImage.cpp b/src/Pipeline/SpirvShaderImage.cpp
index edb8737..44e9ab2 100644
--- a/src/Pipeline/SpirvShaderImage.cpp
+++ b/src/Pipeline/SpirvShaderImage.cpp
@@ -23,7 +23,7 @@
namespace {
-VkFormat SpirvFormatToVulkanFormat(spv::ImageFormat format)
+vk::Format SpirvFormatToVulkanFormat(spv::ImageFormat format)
{
switch(format)
{
@@ -126,6 +126,21 @@
coordinateId = insn.word(4);
}
+ // `imageId` can represent either a Sampled Image, a samplerless Image, or a pointer to an Image.
+ // To get to the OpTypeImage operands, traverse the OpTypeSampledImage or OpTypePointer.
+ const Type &imageObjectType = spirv.getObjectType(imageId);
+ const Type &imageReferenceType = (imageObjectType.opcode() == spv::OpTypeSampledImage)
+ ? spirv.getType(imageObjectType.definition.word(2))
+ : imageObjectType;
+ const Type &imageType = ((imageReferenceType.opcode() == spv::OpTypePointer)
+ ? spirv.getType(imageReferenceType.element)
+ : imageReferenceType);
+
+ ASSERT(imageType.opcode() == spv::OpTypeImage);
+ dim = imageType.definition.word(3);
+ arrayed = imageType.definition.word(5);
+ imageFormat = imageType.definition.word(8);
+
const Object &coordinateObject = spirv.getObject(coordinateId);
const Type &coordinateType = spirv.getType(coordinateObject);
coordinates = coordinateType.componentCount - (isProj() ? 1 : 0);
@@ -703,25 +718,25 @@
auto &imageType = getType(image);
ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
- auto dim = static_cast<spv::Dim>(imageType.definition.word(3));
+ auto dim = static_cast<spv::Dim>(instruction.dim);
auto coordinate = Operand(this, state, instruction.coordinateId);
const DescriptorDecorations &d = descriptorDecorations.at(instruction.imageId);
// For subpass data, format in the instruction is spv::ImageFormatUnknown. Get it from
// the renderpass data instead. In all other cases, we can use the format in the instruction.
- auto vkFormat = (dim == spv::DimSubpassData)
- ? inputAttachmentFormats[d.InputAttachmentIndex]
- : SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(imageType.definition.word(8)));
+ auto imageFormat = (dim == spv::DimSubpassData)
+ ? inputAttachmentFormats[d.InputAttachmentIndex]
+ : SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(instruction.imageFormat));
// Depth+Stencil image attachments select aspect based on the Sampled Type of the
// OpTypeImage. If float, then we want the depth aspect. If int, we want the stencil aspect.
- auto useStencilAspect = (vkFormat == VK_FORMAT_D32_SFLOAT_S8_UINT &&
+ auto useStencilAspect = (imageFormat == VK_FORMAT_D32_SFLOAT_S8_UINT &&
getType(imageType.definition.word(2)).opcode() == spv::OpTypeInt);
if(useStencilAspect)
{
- vkFormat = VK_FORMAT_S8_UINT;
+ imageFormat = VK_FORMAT_S8_UINT;
}
Pointer<Byte> descriptor = state->getPointer(instruction.imageId).base; // vk::StorageImageDescriptor*
@@ -736,8 +751,8 @@
// VK_EXT_image_robustness requires replacing out-of-bounds access with zero.
// TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
auto robustness = OutOfBoundsBehavior::Nullify;
+ const int texelSize = imageFormat.bytes();
- auto texelSize = vk::Format(vkFormat).bytes();
auto texelPtr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, descriptor, texelSize, instruction.sampleId, useStencilAspect, robustness);
// Gather packed texel data. Texels larger than 4 bytes occupy multiple SIMD::Int elements.
@@ -783,7 +798,7 @@
// Format support requirements here come from two sources:
// - Minimum required set of formats for loads from storage images
// - Any format supported as a color or depth/stencil attachment, for input attachments
- switch(vkFormat)
+ switch(imageFormat)
{
case VK_FORMAT_R32G32B32A32_SFLOAT:
case VK_FORMAT_R32G32B32A32_SINT:
@@ -1100,7 +1115,7 @@
dst.move(3, SIMD::Float(1.0f));
break;
default:
- UNSUPPORTED("VkFormat %d", int(vkFormat));
+ UNSUPPORTED("VkFormat %d", int(imageFormat));
break;
}
@@ -1124,14 +1139,12 @@
Int imageSizeInBytes = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
SIMD::Int packed[4];
- int texelSize = 0;
- vk::Format format = SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(imageType.definition.word(8)));
- switch(format)
+ vk::Format imageFormat = SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(instruction.imageFormat));
+ switch(imageFormat)
{
case VK_FORMAT_R32G32B32A32_SFLOAT:
case VK_FORMAT_R32G32B32A32_SINT:
case VK_FORMAT_R32G32B32A32_UINT:
- texelSize = 16;
packed[0] = texel.Int(0);
packed[1] = texel.Int(1);
packed[2] = texel.Int(2);
@@ -1140,18 +1153,15 @@
case VK_FORMAT_R32_SFLOAT:
case VK_FORMAT_R32_SINT:
case VK_FORMAT_R32_UINT:
- texelSize = 4;
packed[0] = texel.Int(0);
break;
case VK_FORMAT_R8G8B8A8_UNORM:
- texelSize = 4;
packed[0] = (SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) |
((SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 8) |
((SIMD::UInt(Round(Min(Max(texel.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 16) |
((SIMD::UInt(Round(Min(Max(texel.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 24);
break;
case VK_FORMAT_R8G8B8A8_SNORM:
- texelSize = 4;
packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
SIMD::Int(0xFF)) |
((SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
@@ -1166,131 +1176,108 @@
break;
case VK_FORMAT_R8G8B8A8_SINT:
case VK_FORMAT_R8G8B8A8_UINT:
- texelSize = 4;
packed[0] = (SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xff))) |
(SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xff)) << 8) |
(SIMD::UInt(texel.UInt(2) & SIMD::UInt(0xff)) << 16) |
(SIMD::UInt(texel.UInt(3) & SIMD::UInt(0xff)) << 24);
break;
case VK_FORMAT_R16G16B16A16_SFLOAT:
- texelSize = 8;
packed[0] = floatToHalfBits(texel.UInt(0), false) | floatToHalfBits(texel.UInt(1), true);
packed[1] = floatToHalfBits(texel.UInt(2), false) | floatToHalfBits(texel.UInt(3), true);
break;
case VK_FORMAT_R16G16B16A16_SINT:
case VK_FORMAT_R16G16B16A16_UINT:
- texelSize = 8;
packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFFFF)) << 16);
packed[1] = SIMD::UInt(texel.UInt(2) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(3) & SIMD::UInt(0xFFFF)) << 16);
break;
case VK_FORMAT_R32G32_SFLOAT:
case VK_FORMAT_R32G32_SINT:
case VK_FORMAT_R32G32_UINT:
- texelSize = 8;
packed[0] = texel.Int(0);
packed[1] = texel.Int(1);
break;
case VK_FORMAT_R16G16_SFLOAT:
- texelSize = 4;
packed[0] = floatToHalfBits(texel.UInt(0), false) | floatToHalfBits(texel.UInt(1), true);
break;
case VK_FORMAT_R16G16_SINT:
case VK_FORMAT_R16G16_UINT:
- texelSize = 4;
packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFFFF)) << 16);
break;
case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
- texelSize = 4;
// Truncates instead of rounding. See b/147900455
packed[0] = ((floatToHalfBits(As<SIMD::UInt>(Max(texel.Float(0), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FF0)) >> 4) |
((floatToHalfBits(As<SIMD::UInt>(Max(texel.Float(1), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FF0)) << 7) |
((floatToHalfBits(As<SIMD::UInt>(Max(texel.Float(2), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FE0)) << 17);
break;
case VK_FORMAT_R16_SFLOAT:
- texelSize = 2;
packed[0] = floatToHalfBits(texel.UInt(0), false);
break;
case VK_FORMAT_R16G16B16A16_UNORM:
- texelSize = 8;
packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
(SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
packed[1] = SIMD::UInt(Round(Min(Max(texel.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
(SIMD::UInt(Round(Min(Max(texel.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
break;
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
- texelSize = 4;
packed[0] = (SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) |
((SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) << 10) |
((SIMD::UInt(Round(Min(Max(texel.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) << 20) |
((SIMD::UInt(Round(Min(Max(texel.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3)))) << 30);
break;
case VK_FORMAT_R16G16_UNORM:
- texelSize = 4;
packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
(SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
break;
case VK_FORMAT_R8G8_UNORM:
- texelSize = 2;
packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF))) |
(SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF))) << 8);
break;
case VK_FORMAT_R16_UNORM:
- texelSize = 2;
packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF)));
break;
case VK_FORMAT_R8_UNORM:
- texelSize = 1;
packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF)));
break;
case VK_FORMAT_R16G16B16A16_SNORM:
- texelSize = 8;
packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
(SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
packed[1] = (SIMD::Int(Round(Min(Max(texel.Float(2), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
(SIMD::Int(Round(Min(Max(texel.Float(3), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
break;
case VK_FORMAT_R16G16_SNORM:
- texelSize = 4;
packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
(SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
break;
case VK_FORMAT_R8G8_SNORM:
- texelSize = 2;
packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F))) & SIMD::Int(0xFF)) |
(SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F))) << 8);
break;
case VK_FORMAT_R16_SNORM:
- texelSize = 2;
packed[0] = SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF)));
break;
case VK_FORMAT_R8_SNORM:
- texelSize = 1;
packed[0] = SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F)));
break;
case VK_FORMAT_R8G8_SINT:
case VK_FORMAT_R8G8_UINT:
- texelSize = 2;
packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFF)) << 8);
break;
case VK_FORMAT_R16_SINT:
case VK_FORMAT_R16_UINT:
- texelSize = 2;
packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF));
break;
case VK_FORMAT_R8_SINT:
case VK_FORMAT_R8_UINT:
- texelSize = 1;
packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFF));
break;
case VK_FORMAT_A2B10G10R10_UINT_PACK32:
- texelSize = 4;
packed[0] = (SIMD::UInt(texel.UInt(0) & SIMD::UInt(0x3FF))) |
(SIMD::UInt(texel.UInt(1) & SIMD::UInt(0x3FF)) << 10) |
(SIMD::UInt(texel.UInt(2) & SIMD::UInt(0x3FF)) << 20) |
(SIMD::UInt(texel.UInt(3) & SIMD::UInt(0x3)) << 30);
break;
default:
- UNSUPPORTED("VkFormat %d", int(format));
+ UNSUPPORTED("VkFormat %d", int(imageFormat));
break;
}
@@ -1298,6 +1285,7 @@
// validation. If the texel fails integer texel coordinate validation, then the write has no effect."
// - https://www.khronos.org/registry/vulkan/specs/1.2/html/chap16.html#textures-output-coordinate-validation
auto robustness = OutOfBoundsBehavior::Nullify;
+ const int texelSize = imageFormat.bytes();
auto texelPtr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, descriptor, texelSize, instruction.sampleId, false, robustness);
@@ -1354,9 +1342,6 @@
ASSERT(imageType.opcode() == spv::OpTypeImage);
ASSERT(resultType.storageClass == spv::StorageClassImage);
- ASSERT(getType(resultType.element).opcode() == spv::OpTypeInt);
- const int texelSize = sizeof(uint32_t);
-
auto coordinate = Operand(this, state, instruction.coordinateId);
Pointer<Byte> descriptor = state->getPointer(instruction.imageId).base; // vk::StorageImageDescriptor*
@@ -1366,6 +1351,7 @@
// VK_EXT_image_robustness requires checking for out-of-bounds accesses.
// TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
auto robustness = OutOfBoundsBehavior::Nullify;
+ const int texelSize = SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(instruction.imageFormat)).bytes();
auto ptr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, descriptor, texelSize, instruction.sampleId, false, robustness);