Allow treating a 3D image as a layered 2D image When an image is created as a 3D image, but contains the VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT flag, it becomes equivalent to a 2D array with "depth" layers and should be treated as such when accessing a single slice of a 3D image. Bug b/119620767 Change-Id: Ibdc6985acdf5e5f30efcb7bf5adc2563bf64c4f7 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29189 Tested-by: Alexis Hétu <sugoi@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Device/Blitter.cpp b/src/Device/Blitter.cpp index ea0bc96..1b49c92 100644 --- a/src/Device/Blitter.cpp +++ b/src/Device/Blitter.cpp
@@ -192,6 +192,10 @@ area.extent.width = extent.width; area.extent.height = extent.height; } + if(dest->is3DSlice()) + { + extent.depth = 1; // The 3D image is instead interpreted as a 2D image with layers + } for(subresLayers.baseArrayLayer = subresourceRange.baseArrayLayer; subresLayers.baseArrayLayer <= lastLayer; subresLayers.baseArrayLayer++) { @@ -209,6 +213,7 @@ case 2: for(uint32_t i = 0; i < area.extent.height; i++) { + ASSERT(d < dest->end()); sw::clear((uint16_t*)d, packed, area.extent.width); d += rowPitchBytes; } @@ -216,6 +221,7 @@ case 4: for(uint32_t i = 0; i < area.extent.height; i++) { + ASSERT(d < dest->end()); sw::clear((uint32_t*)d, packed, area.extent.width); d += rowPitchBytes; }
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp index 5498bb7..a2784e6 100644 --- a/src/Vulkan/VkImage.cpp +++ b/src/Vulkan/VkImage.cpp
@@ -580,7 +580,7 @@ VkDeviceSize Image::getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const { - return layer * getLayerSize(aspect) + getMemoryOffset(aspect, mipLevel); + return layer * getLayerOffset(aspect, mipLevel) + getMemoryOffset(aspect, mipLevel); } VkDeviceSize Image::getMipLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const @@ -593,6 +593,28 @@ return getMipLevelSize(aspect, mipLevel) * samples; } +bool Image::is3DSlice() const +{ + return ((imageType == VK_IMAGE_TYPE_3D) && (flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT)); +} + +VkDeviceSize Image::getLayerOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel) const +{ + if(is3DSlice()) + { + // When the VkImageSubresourceRange structure is used to select a subset of the slices of a 3D + // images mip level in order to create a 2D or 2D array image view of a 3D image created with + // VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, baseArrayLayer and layerCount specify the first + // slice index and the number of slices to include in the created image view. + ASSERT(samples == VK_SAMPLE_COUNT_1_BIT); + + // Offset to the proper slice of the 3D image's mip level + return slicePitchBytes(aspect, mipLevel); + } + + return getLayerSize(aspect); +} + VkDeviceSize Image::getLayerSize(VkImageAspectFlagBits aspect) const { VkDeviceSize layerSize = 0;
diff --git a/src/Vulkan/VkImage.hpp b/src/Vulkan/VkImage.hpp index 0ac2c9a..eff44b0 100644 --- a/src/Vulkan/VkImage.hpp +++ b/src/Vulkan/VkImage.hpp
@@ -66,6 +66,7 @@ int slicePitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const; void* getTexelPointer(const VkOffset3D& offset, const VkImageSubresourceLayers& subresource) const; bool isCube() const; + bool is3DSlice() const; uint8_t* end() const; VkDeviceSize getLayerSize(VkImageAspectFlagBits aspect) const; @@ -76,6 +77,7 @@ VkDeviceSize getStorageSize(VkImageAspectFlags flags) const; VkDeviceSize getMipLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const; VkDeviceSize getMultiSampledLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const; + VkDeviceSize getLayerOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel) const; VkDeviceSize getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel) const; VkDeviceSize getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const; VkDeviceSize texelOffsetBytesInStorage(const VkOffset3D& offset, const VkImageSubresourceLayers& subresource) const;