Support images with linear tiling for transfers
The Vulkan 1.1 spec on vkCreateImage states that "Creation of images
with tiling VK_IMAGE_TILING_LINEAR may not be supported unless other
parameters meet all of the constraints:
* imageType is VK_IMAGE_TYPE_2D
* format is not a depth/stencil format
* mipLevels is 1
* arrayLayers is 1
* samples is VK_SAMPLE_COUNT_1_BIT
* usage only includes VK_IMAGE_USAGE_TRANSFER_SRC_BIT and/or
VK_IMAGE_USAGE_TRANSFER_DST_BIT"
Also restrict YCbCr image creation in accordance with:
"Creation of images with a format requiring Y’CBCR conversion may not be
supported unless other parameters meet all of the constraints:
* imageType is VK_IMAGE_TYPE_2D
* mipLevels is 1
* arrayLayers is 1
* samples is VK_SAMPLE_COUNT_1_BIT"
Bug: b/119620767
Bug: b/132437008
Tests: dEQP-VK.*ycbcr*
Change-Id: I909fda2a154e69fbd4afb862cf4cc14c244005bf
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31788
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index fb9c43c..91043c9 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -111,11 +111,15 @@
{
// By spec, aspectMask has a single bit set.
if (!((pSubresource->aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
- (pSubresource->aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) ||
- (pSubresource->aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT)))
+ (pSubresource->aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) ||
+ (pSubresource->aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) ||
+ (pSubresource->aspectMask == VK_IMAGE_ASPECT_PLANE_0_BIT) ||
+ (pSubresource->aspectMask == VK_IMAGE_ASPECT_PLANE_1_BIT) ||
+ (pSubresource->aspectMask == VK_IMAGE_ASPECT_PLANE_2_BIT)))
{
- UNIMPLEMENTED("aspectMask");
+ UNSUPPORTED("aspectMask %X", pSubresource->aspectMask);
}
+
auto aspect = static_cast<VkImageAspectFlagBits>(pSubresource->aspectMask);
pLayout->offset = getMemoryOffset(aspect, pSubresource->mipLevel, pSubresource->arrayLayer);
pLayout->size = getMultiSampledLevelSize(aspect, pSubresource->mipLevel);
@@ -130,18 +134,24 @@
// an image to another image that has the same number of bytes per pixel.
Image* dst = Cast(dstImage);
- if(!((pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
- (pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) ||
- (pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT)))
+ if (!((pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
+ (pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) ||
+ (pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) ||
+ (pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_PLANE_0_BIT) ||
+ (pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_PLANE_1_BIT) ||
+ (pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_PLANE_2_BIT)))
{
- UNIMPLEMENTED("srcSubresource");
+ UNSUPPORTED("srcSubresource.aspectMask %X", pRegion.srcSubresource.aspectMask);
}
- if(!((pRegion.dstSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
- (pRegion.dstSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) ||
- (pRegion.dstSubresource.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT)))
+ if (!((pRegion.dstSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
+ (pRegion.dstSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) ||
+ (pRegion.dstSubresource.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) ||
+ (pRegion.dstSubresource.aspectMask == VK_IMAGE_ASPECT_PLANE_0_BIT) ||
+ (pRegion.dstSubresource.aspectMask == VK_IMAGE_ASPECT_PLANE_1_BIT) ||
+ (pRegion.dstSubresource.aspectMask == VK_IMAGE_ASPECT_PLANE_2_BIT)))
{
- UNIMPLEMENTED("dstSubresource");
+ UNSUPPORTED("dstSubresource.aspectMask %X", pRegion.dstSubresource.aspectMask);
}
VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(pRegion.srcSubresource.aspectMask);
@@ -510,9 +520,9 @@
mipLevelExtent.height = extent.height >> mipLevel;
mipLevelExtent.depth = extent.depth >> mipLevel;
- if(mipLevelExtent.width == 0) mipLevelExtent.width = 1;
- if(mipLevelExtent.height == 0) mipLevelExtent.height = 1;
- if(mipLevelExtent.depth == 0) mipLevelExtent.depth = 1;
+ if(mipLevelExtent.width == 0) { mipLevelExtent.width = 1; }
+ if(mipLevelExtent.height == 0) { mipLevelExtent.height = 1; }
+ if(mipLevelExtent.depth == 0) { mipLevelExtent.depth = 1; }
switch(aspect)
{
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index dda45f3..8a3b59a 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -375,7 +375,7 @@
return true;
}
-void PhysicalDevice::getFormatProperties(VkFormat format, VkFormatProperties* pFormatProperties) const
+void PhysicalDevice::getFormatProperties(Format format, VkFormatProperties* pFormatProperties) const
{
pFormatProperties->linearTilingFeatures = 0; // Unsupported format
pFormatProperties->optimalTilingFeatures = 0; // Unsupported format
@@ -660,11 +660,17 @@
default:
break;
}
+
+ if(pFormatProperties->optimalTilingFeatures)
+ {
+ pFormatProperties->linearTilingFeatures = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
+ VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
+ }
}
-void PhysicalDevice::getImageFormatProperties(VkFormat format, VkImageType type, VkImageTiling tiling,
+void PhysicalDevice::getImageFormatProperties(Format format, VkImageType type, VkImageTiling tiling,
VkImageUsageFlags usage, VkImageCreateFlags flags,
- VkImageFormatProperties* pImageFormatProperties) const
+ VkImageFormatProperties* pImageFormatProperties) const
{
pImageFormatProperties->sampleCounts = VK_SAMPLE_COUNT_1_BIT;
pImageFormatProperties->maxArrayLayers = vk::MAX_IMAGE_ARRAY_LAYERS;
@@ -713,6 +719,24 @@
}
pImageFormatProperties->maxResourceSize = 1 << 31; // Minimum value for maxResourceSize
+
+ // "Images created with tiling equal to VK_IMAGE_TILING_LINEAR have further restrictions on their limits and capabilities
+ // compared to images created with tiling equal to VK_IMAGE_TILING_OPTIMAL."
+ if(tiling == VK_IMAGE_TILING_LINEAR)
+ {
+ pImageFormatProperties->maxMipLevels = 1;
+ pImageFormatProperties->maxArrayLayers = 1;
+ pImageFormatProperties->sampleCounts = VK_SAMPLE_COUNT_1_BIT;
+ }
+
+ // "Images created with a format from one of those listed in Formats requiring sampler YCBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views
+ // have further restrictions on their limits and capabilities compared to images created with other formats."
+ if(format.isYcbcrFormat())
+ {
+ pImageFormatProperties->maxMipLevels = 1;
+ pImageFormatProperties->maxArrayLayers = 1;
+ pImageFormatProperties->sampleCounts = VK_SAMPLE_COUNT_1_BIT;
+ }
}
uint32_t PhysicalDevice::getQueueFamilyPropertyCount() const
diff --git a/src/Vulkan/VkPhysicalDevice.hpp b/src/Vulkan/VkPhysicalDevice.hpp
index 216b22a..c126675 100644
--- a/src/Vulkan/VkPhysicalDevice.hpp
+++ b/src/Vulkan/VkPhysicalDevice.hpp
@@ -16,6 +16,7 @@
#define VK_PHYSICAL_DEVICE_HPP_
#include "VkObject.hpp"
+#include "VkFormat.h"
#ifdef VK_USE_PLATFORM_ANDROID_KHR
#include <vulkan/vk_android_native_buffer.h>
@@ -60,8 +61,8 @@
void getProperties(const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) const;
void getProperties(const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) const;
- void getFormatProperties(VkFormat format, VkFormatProperties* pFormatProperties) const;
- void getImageFormatProperties(VkFormat format, VkImageType type, VkImageTiling tiling,
+ void getFormatProperties(Format format, VkFormatProperties* pFormatProperties) const;
+ void getImageFormatProperties(Format format, VkImageType type, VkImageTiling tiling,
VkImageUsageFlags usage, VkImageCreateFlags flags,
VkImageFormatProperties* pImageFormatProperties) const;
uint32_t getQueueFamilyPropertyCount() const;
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 081414e..891ba3c 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -232,6 +232,10 @@
TRACE("(VkPhysicalDevice physicalDevice = %p, VkFormat format = %d, VkImageType type = %d, VkImageTiling tiling = %d, VkImageUsageFlags usage = %d, VkImageCreateFlags flags = %d, VkImageFormatProperties* pImageFormatProperties = %p)",
physicalDevice, (int)format, (int)type, (int)tiling, usage, flags, pImageFormatProperties);
+ // "If the combination of parameters to vkGetPhysicalDeviceImageFormatProperties is not supported by the implementation
+ // for use in vkCreateImage, then all members of VkImageFormatProperties will be filled with zero."
+ memset(pImageFormatProperties, 0, sizeof(VkImageFormatProperties));
+
VkFormatProperties properties;
vk::Cast(physicalDevice)->getFormatProperties(format, &properties);
@@ -302,6 +306,31 @@
VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
ASSERT(!(usage & ~(allRecognizedUsageBits)));
+ // "Images created with tiling equal to VK_IMAGE_TILING_LINEAR have further restrictions on their limits and capabilities
+ // compared to images created with tiling equal to VK_IMAGE_TILING_OPTIMAL."
+ if(tiling == VK_IMAGE_TILING_LINEAR)
+ {
+ if(type != VK_IMAGE_TYPE_2D)
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ if(vk::Format(format).isDepth() || vk::Format(format).isStencil())
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+ }
+
+ // "Images created with a format from one of those listed in Formats requiring sampler YCBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views
+ // have further restrictions on their limits and capabilities compared to images created with other formats."
+ if(vk::Format(format).isYcbcrFormat())
+ {
+ if(type != VK_IMAGE_TYPE_2D)
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+ }
+
vk::Cast(physicalDevice)->getImageFormatProperties(format, type, tiling, usage, flags, pImageFormatProperties);
return VK_SUCCESS;