Implement shaderStorageImageExtendedFormats support
Bug: b/146579770
Tests: dEQP-VK.*
Change-Id: Ibd383e01c9fce41faf3c26deb4aefa6bc056cfdb
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/46068
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/Device/Blitter.cpp b/src/Device/Blitter.cpp
index 7ad251a..fd8e26f 100644
--- a/src/Device/Blitter.cpp
+++ b/src/Device/Blitter.cpp
@@ -370,6 +370,7 @@
c = Float4(*Pointer<Byte4>(element));
break;
case VK_FORMAT_R16G16B16A16_SINT:
+ case VK_FORMAT_R16G16B16A16_SNORM:
c = Float4(*Pointer<Short4>(element));
break;
case VK_FORMAT_R16G16B16A16_UNORM:
diff --git a/src/Pipeline/SpirvShaderImage.cpp b/src/Pipeline/SpirvShaderImage.cpp
index c26790a..f86a296 100644
--- a/src/Pipeline/SpirvShaderImage.cpp
+++ b/src/Pipeline/SpirvShaderImage.cpp
@@ -28,24 +28,44 @@
switch(format)
{
case spv::ImageFormatRgba32f: return VK_FORMAT_R32G32B32A32_SFLOAT;
- case spv::ImageFormatRgba32i: return VK_FORMAT_R32G32B32A32_SINT;
- case spv::ImageFormatRgba32ui: return VK_FORMAT_R32G32B32A32_UINT;
+ case spv::ImageFormatRgba16f: return VK_FORMAT_R16G16B16A16_SFLOAT;
case spv::ImageFormatR32f: return VK_FORMAT_R32_SFLOAT;
- case spv::ImageFormatR32i: return VK_FORMAT_R32_SINT;
- case spv::ImageFormatR32ui: return VK_FORMAT_R32_UINT;
case spv::ImageFormatRgba8: return VK_FORMAT_R8G8B8A8_UNORM;
case spv::ImageFormatRgba8Snorm: return VK_FORMAT_R8G8B8A8_SNORM;
- case spv::ImageFormatRgba8i: return VK_FORMAT_R8G8B8A8_SINT;
- case spv::ImageFormatRgba8ui: return VK_FORMAT_R8G8B8A8_UINT;
- case spv::ImageFormatRgba16f: return VK_FORMAT_R16G16B16A16_SFLOAT;
- case spv::ImageFormatRgba16i: return VK_FORMAT_R16G16B16A16_SINT;
- case spv::ImageFormatRgba16ui: return VK_FORMAT_R16G16B16A16_UINT;
case spv::ImageFormatRg32f: return VK_FORMAT_R32G32_SFLOAT;
- case spv::ImageFormatRg32i: return VK_FORMAT_R32G32_SINT;
- case spv::ImageFormatRg32ui: return VK_FORMAT_R32G32_UINT;
case spv::ImageFormatRg16f: return VK_FORMAT_R16G16_SFLOAT;
+ case spv::ImageFormatR11fG11fB10f: return VK_FORMAT_B10G11R11_UFLOAT_PACK32;
+ case spv::ImageFormatR16f: return VK_FORMAT_R16_SFLOAT;
+ case spv::ImageFormatRgba16: return VK_FORMAT_R16G16B16A16_UNORM;
+ case spv::ImageFormatRgb10A2: return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
+ case spv::ImageFormatRg16: return VK_FORMAT_R16G16_UNORM;
+ case spv::ImageFormatRg8: return VK_FORMAT_R8G8_UNORM;
+ case spv::ImageFormatR16: return VK_FORMAT_R16_UNORM;
+ case spv::ImageFormatR8: return VK_FORMAT_R8_UNORM;
+ case spv::ImageFormatRgba16Snorm: return VK_FORMAT_R16G16B16A16_SNORM;
+ case spv::ImageFormatRg16Snorm: return VK_FORMAT_R16G16_SNORM;
+ case spv::ImageFormatRg8Snorm: return VK_FORMAT_R8G8_SNORM;
+ case spv::ImageFormatR16Snorm: return VK_FORMAT_R16_SNORM;
+ case spv::ImageFormatR8Snorm: return VK_FORMAT_R8_SNORM;
+ case spv::ImageFormatRgba32i: return VK_FORMAT_R32G32B32A32_SINT;
+ case spv::ImageFormatRgba16i: return VK_FORMAT_R16G16B16A16_SINT;
+ case spv::ImageFormatRgba8i: return VK_FORMAT_R8G8B8A8_SINT;
+ case spv::ImageFormatR32i: return VK_FORMAT_R32_SINT;
+ case spv::ImageFormatRg32i: return VK_FORMAT_R32G32_SINT;
case spv::ImageFormatRg16i: return VK_FORMAT_R16G16_SINT;
+ case spv::ImageFormatRg8i: return VK_FORMAT_R8G8_SINT;
+ case spv::ImageFormatR16i: return VK_FORMAT_R16_SINT;
+ case spv::ImageFormatR8i: return VK_FORMAT_R8_SINT;
+ case spv::ImageFormatRgba32ui: return VK_FORMAT_R32G32B32A32_UINT;
+ case spv::ImageFormatRgba16ui: return VK_FORMAT_R16G16B16A16_UINT;
+ case spv::ImageFormatRgba8ui: return VK_FORMAT_R8G8B8A8_UINT;
+ case spv::ImageFormatR32ui: return VK_FORMAT_R32_UINT;
+ case spv::ImageFormatRgb10a2ui: return VK_FORMAT_A2B10G10R10_UINT_PACK32;
+ case spv::ImageFormatRg32ui: return VK_FORMAT_R32G32_UINT;
case spv::ImageFormatRg16ui: return VK_FORMAT_R16G16_UINT;
+ case spv::ImageFormatRg8ui: return VK_FORMAT_R8G8_UINT;
+ case spv::ImageFormatR16ui: return VK_FORMAT_R16_UINT;
+ case spv::ImageFormatR8ui: return VK_FORMAT_R8_UINT;
default:
UNSUPPORTED("SPIR-V ImageFormat %u", format);
@@ -635,6 +655,7 @@
// While we could be using OutOfBoundsBehavior::RobustBufferAccess for read operations from buffer resources,
// emulating the glsl function loadImage() requires that this function returns 0 when used with out of bounds
// coordinates, so we have to use OutOfBoundsBehavior::Nullify in that case.
+ // TODO(b/159329067): Claim VK_EXT_image_robustness
auto robustness = OutOfBoundsBehavior::Nullify;
auto texelSize = vk::Format(vkFormat).bytes();
@@ -716,6 +737,18 @@
dst.move(2, SIMD::Float(0.0f));
dst.move(3, SIMD::Float(1.0f));
break;
+ case VK_FORMAT_R16G16B16A16_UNORM:
+ dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
+ dst.move(1, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
+ dst.move(2, SIMD::Float(packed[1] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
+ dst.move(3, SIMD::Float((packed[1] >> 16) & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
+ break;
+ case VK_FORMAT_R16G16B16A16_SNORM:
+ dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
+ dst.move(1, Max(SIMD::Float(packed[0] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
+ dst.move(2, Max(SIMD::Float((packed[1] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
+ dst.move(3, Max(SIMD::Float(packed[1] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
+ break;
case VK_FORMAT_R16G16B16A16_SINT:
dst.move(0, (packed[0] << 16) >> 16);
dst.move(1, packed[0] >> 16);
@@ -836,6 +869,18 @@
dst.move(2, SIMD::Float(0.0f));
dst.move(3, SIMD::Float(1.0f));
break;
+ case VK_FORMAT_R16_UNORM:
+ dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
+ dst.move(1, SIMD::Float(0.0f));
+ dst.move(2, SIMD::Float(0.0f));
+ dst.move(3, SIMD::Float(1.0f));
+ break;
+ case VK_FORMAT_R16_SNORM:
+ dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
+ dst.move(1, SIMD::Float(0.0f));
+ dst.move(2, SIMD::Float(0.0f));
+ dst.move(3, SIMD::Float(1.0f));
+ break;
case VK_FORMAT_R16_UINT:
dst.move(0, packed[0] & SIMD::Int(0xFFFF));
dst.move(1, SIMD::UInt(0));
@@ -854,6 +899,18 @@
dst.move(2, SIMD::Float(0.0f));
dst.move(3, SIMD::Float(1.0f));
break;
+ case VK_FORMAT_R16G16_UNORM:
+ dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
+ dst.move(1, SIMD::Float(As<SIMD::UInt>(packed[0]) >> 16) * SIMD::Float(1.0f / 0xFFFF));
+ dst.move(2, SIMD::Float(0.0f));
+ dst.move(3, SIMD::Float(1.0f));
+ break;
+ case VK_FORMAT_R16G16_SNORM:
+ dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
+ dst.move(1, Max(SIMD::Float(packed[0] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
+ dst.move(2, SIMD::Float(0.0f));
+ dst.move(3, SIMD::Float(1.0f));
+ break;
case VK_FORMAT_R16G16_UINT:
dst.move(0, packed[0] & SIMD::Int(0xFFFF));
dst.move(1, (packed[0] >> 16) & SIMD::Int(0xFFFF));
@@ -1023,32 +1080,98 @@
texelSize = 4;
packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFFFF)) << 16);
break;
-
case spv::ImageFormatR11fG11fB10f:
- case spv::ImageFormatR16f:
- case spv::ImageFormatRgba16:
- case spv::ImageFormatRgb10A2:
- case spv::ImageFormatRg16:
- case spv::ImageFormatRg8:
- case spv::ImageFormatR16:
- case spv::ImageFormatR8:
- case spv::ImageFormatRgba16Snorm:
- case spv::ImageFormatRg16Snorm:
- case spv::ImageFormatRg8Snorm:
- case spv::ImageFormatR16Snorm:
- case spv::ImageFormatR8Snorm:
- case spv::ImageFormatRg8i:
- case spv::ImageFormatR16i:
- case spv::ImageFormatR8i:
- case spv::ImageFormatRgb10a2ui:
- case spv::ImageFormatRg8ui:
- case spv::ImageFormatR16ui:
- case spv::ImageFormatR8ui:
- UNSUPPORTED("spv::ImageFormat %d", int(format));
+ 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 spv::ImageFormatR16f:
+ texelSize = 2;
+ packed[0] = floatToHalfBits(texel.UInt(0), false);
+ break;
+ case spv::ImageFormatRgba16:
+ 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 spv::ImageFormatRgb10A2:
+ 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 spv::ImageFormatRg16:
+ 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 spv::ImageFormatRg8:
+ 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 spv::ImageFormatR16:
+ 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 spv::ImageFormatR8:
+ 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 spv::ImageFormatRgba16Snorm:
+ 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 spv::ImageFormatRg16Snorm:
+ 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 spv::ImageFormatRg8Snorm:
+ 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 spv::ImageFormatR16Snorm:
+ 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 spv::ImageFormatR8Snorm:
+ 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 spv::ImageFormatRg8i:
+ case spv::ImageFormatRg8ui:
+ texelSize = 2;
+ packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFF)) << 8);
+ break;
+ case spv::ImageFormatR16i:
+ case spv::ImageFormatR16ui:
+ texelSize = 2;
+ packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF));
+ break;
+ case spv::ImageFormatR8i:
+ case spv::ImageFormatR8ui:
+ texelSize = 1;
+ packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFF));
+ break;
+ case spv::ImageFormatRgb10a2ui:
+ 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:
- UNREACHABLE("spv::ImageFormat %d", int(format));
+ UNSUPPORTED("spv::ImageFormat %d", int(format));
break;
}
@@ -1056,6 +1179,7 @@
// Emulating the glsl function imageStore() requires that this function is noop when used with out of bounds
// coordinates, so we have to use OutOfBoundsBehavior::Nullify in that case.
+ // TODO(b/159329067): Claim VK_EXT_image_robustness
auto robustness = OutOfBoundsBehavior::Nullify;
auto texelPtr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, texelSize, 0, false, robustness);
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 0a806ce..77168b1 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -97,7 +97,7 @@
VK_TRUE, // fragmentStoresAndAtomics
VK_FALSE, // shaderTessellationAndGeometryPointSize
VK_FALSE, // shaderImageGatherExtended
- VK_FALSE, // shaderStorageImageExtendedFormats
+ VK_TRUE, // shaderStorageImageExtendedFormats
VK_FALSE, // shaderStorageImageMultisample
VK_FALSE, // shaderStorageImageReadWithoutFormat
VK_FALSE, // shaderStorageImageWriteWithoutFormat
@@ -647,9 +647,30 @@
case VK_FORMAT_R32G32B32A32_UINT:
case VK_FORMAT_R32G32B32A32_SINT:
case VK_FORMAT_R32G32B32A32_SFLOAT:
- case VK_FORMAT_R16G16_UINT:
- case VK_FORMAT_R16G16_SINT:
+ // shaderStorageImageExtendedFormats
case VK_FORMAT_R16G16_SFLOAT:
+ case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
+ case VK_FORMAT_R16_SFLOAT:
+ case VK_FORMAT_R16G16B16A16_UNORM:
+ case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+ case VK_FORMAT_R16G16_UNORM:
+ case VK_FORMAT_R8G8_UNORM:
+ case VK_FORMAT_R16_UNORM:
+ case VK_FORMAT_R8_UNORM:
+ case VK_FORMAT_R16G16B16A16_SNORM:
+ case VK_FORMAT_R16G16_SNORM:
+ case VK_FORMAT_R8G8_SNORM:
+ case VK_FORMAT_R16_SNORM:
+ case VK_FORMAT_R8_SNORM:
+ case VK_FORMAT_R16G16_SINT:
+ case VK_FORMAT_R8G8_SINT:
+ case VK_FORMAT_R16_SINT:
+ case VK_FORMAT_R8_SINT:
+ case VK_FORMAT_A2B10G10R10_UINT_PACK32:
+ case VK_FORMAT_R16G16_UINT:
+ case VK_FORMAT_R8G8_UINT:
+ case VK_FORMAT_R16_UINT:
+ case VK_FORMAT_R8_UINT:
pFormatProperties->optimalTilingFeatures |=
VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
// [[fallthrough]]