Implement VK_EXT_host_image_copy
Tests: *
Bug: angleproject:8341
Change-Id: I201ace1d3d6016beba53199acf0814920d347193
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/72408
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@google.com>
Tested-by: Shahbaz Youssefi <syoussefi@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Vulkan/VkGetProcAddress.cpp b/src/Vulkan/VkGetProcAddress.cpp
index 6f6f276..d61f600 100644
--- a/src/Vulkan/VkGetProcAddress.cpp
+++ b/src/Vulkan/VkGetProcAddress.cpp
@@ -606,6 +606,16 @@
MAKE_VULKAN_DEVICE_ENTRY(vkGetPrivateDataEXT),
MAKE_VULKAN_DEVICE_ENTRY(vkSetPrivateDataEXT),
} },
+ // VK_EXT_host_image_copy
+ {
+ VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME,
+ {
+ MAKE_VULKAN_DEVICE_ENTRY(vkCopyImageToImageEXT),
+ MAKE_VULKAN_DEVICE_ENTRY(vkCopyImageToMemoryEXT),
+ MAKE_VULKAN_DEVICE_ENTRY(vkCopyMemoryToImageEXT),
+ MAKE_VULKAN_DEVICE_ENTRY(vkGetImageSubresourceLayout2EXT),
+ MAKE_VULKAN_DEVICE_ENTRY(vkTransitionImageLayoutEXT),
+ } },
#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
// VK_ANDROID_external_memory_android_hardware_buffer
{
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index b4422fc..cc17cf7 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -162,6 +162,11 @@
case VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO:
case VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO:
break;
+ case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT:
+ {
+ // Explicitly ignored, since VK_EXT_image_drm_format_modifier is not supported
+ }
+ break;
case VK_STRUCTURE_TYPE_MAX_ENUM:
// dEQP tests that this value is ignored.
break;
@@ -581,9 +586,19 @@
dstImage->contentsChanged(ImageSubresourceRange(region.dstSubresource));
}
-void Image::copy(Buffer *buffer, const VkBufferImageCopy2KHR ®ion, bool bufferIsSource)
+void Image::copy(const void *srcCopyMemory,
+ void *dstCopyMemory,
+ uint32_t rowLength,
+ uint32_t imageHeight,
+ const VkImageSubresourceLayers &imageSubresource,
+ const VkOffset3D &imageCopyOffset,
+ const VkExtent3D &imageCopyExtent)
{
- switch(region.imageSubresource.aspectMask)
+ // Decide on whether copying from buffer/memory or to buffer/memory
+ ASSERT((srcCopyMemory == nullptr) != (dstCopyMemory == nullptr));
+ const bool memoryIsSource = srcCopyMemory != nullptr;
+
+ switch(imageSubresource.aspectMask)
{
case VK_IMAGE_ASPECT_COLOR_BIT:
case VK_IMAGE_ASPECT_DEPTH_BIT:
@@ -593,56 +608,54 @@
case VK_IMAGE_ASPECT_PLANE_2_BIT:
break;
default:
- UNSUPPORTED("aspectMask %x", int(region.imageSubresource.aspectMask));
+ UNSUPPORTED("aspectMask %x", int(imageSubresource.aspectMask));
break;
}
- auto aspect = static_cast<VkImageAspectFlagBits>(region.imageSubresource.aspectMask);
+ auto aspect = static_cast<VkImageAspectFlagBits>(imageSubresource.aspectMask);
Format copyFormat = getFormat(aspect);
- VkExtent3D imageExtent = imageExtentInBlocks(region.imageExtent, aspect);
+ VkExtent3D imageExtent = imageExtentInBlocks(imageCopyExtent, aspect);
if(imageExtent.width == 0 || imageExtent.height == 0 || imageExtent.depth == 0)
{
return;
}
- VkExtent2D bufferExtent = bufferExtentInBlocks(Extent2D(imageExtent), region);
+ VkExtent2D extent = bufferExtentInBlocks(Extent2D(imageExtent), rowLength, imageHeight, imageSubresource, imageCopyOffset);
int bytesPerBlock = copyFormat.bytesPerBlock();
- int bufferRowPitchBytes = bufferExtent.width * bytesPerBlock;
- int bufferSlicePitchBytes = bufferExtent.height * bufferRowPitchBytes;
+ int memoryRowPitchBytes = extent.width * bytesPerBlock;
+ int memorySlicePitchBytes = extent.height * memoryRowPitchBytes;
ASSERT(samples == 1);
- uint8_t *bufferMemory = static_cast<uint8_t *>(buffer->getOffsetPointer(region.bufferOffset));
- uint8_t *imageMemory = static_cast<uint8_t *>(getTexelPointer(region.imageOffset, ImageSubresource(region.imageSubresource)));
- uint8_t *srcMemory = bufferIsSource ? bufferMemory : imageMemory;
- uint8_t *dstMemory = bufferIsSource ? imageMemory : bufferMemory;
- int imageRowPitchBytes = rowPitchBytes(aspect, region.imageSubresource.mipLevel);
- int imageSlicePitchBytes = slicePitchBytes(aspect, region.imageSubresource.mipLevel);
+ uint8_t *imageMemory = static_cast<uint8_t *>(getTexelPointer(imageCopyOffset, ImageSubresource(imageSubresource)));
+ const uint8_t *srcMemory = memoryIsSource ? static_cast<const uint8_t *>(srcCopyMemory) : imageMemory;
+ uint8_t *dstMemory = memoryIsSource ? imageMemory : static_cast<uint8_t *>(dstCopyMemory);
+ int imageRowPitchBytes = rowPitchBytes(aspect, imageSubresource.mipLevel);
+ int imageSlicePitchBytes = slicePitchBytes(aspect, imageSubresource.mipLevel);
- int srcSlicePitchBytes = bufferIsSource ? bufferSlicePitchBytes : imageSlicePitchBytes;
- int dstSlicePitchBytes = bufferIsSource ? imageSlicePitchBytes : bufferSlicePitchBytes;
- int srcRowPitchBytes = bufferIsSource ? bufferRowPitchBytes : imageRowPitchBytes;
- int dstRowPitchBytes = bufferIsSource ? imageRowPitchBytes : bufferRowPitchBytes;
+ int srcSlicePitchBytes = memoryIsSource ? memorySlicePitchBytes : imageSlicePitchBytes;
+ int dstSlicePitchBytes = memoryIsSource ? imageSlicePitchBytes : memorySlicePitchBytes;
+ int srcRowPitchBytes = memoryIsSource ? memoryRowPitchBytes : imageRowPitchBytes;
+ int dstRowPitchBytes = memoryIsSource ? imageRowPitchBytes : memoryRowPitchBytes;
VkDeviceSize copySize = imageExtent.width * bytesPerBlock;
VkDeviceSize imageLayerSize = getLayerSize(aspect);
- VkDeviceSize srcLayerSize = bufferIsSource ? bufferSlicePitchBytes : imageLayerSize;
- VkDeviceSize dstLayerSize = bufferIsSource ? imageLayerSize : bufferSlicePitchBytes;
+ VkDeviceSize srcLayerSize = memoryIsSource ? memorySlicePitchBytes : imageLayerSize;
+ VkDeviceSize dstLayerSize = memoryIsSource ? imageLayerSize : memorySlicePitchBytes;
- for(uint32_t i = 0; i < region.imageSubresource.layerCount; i++)
+ for(uint32_t i = 0; i < imageSubresource.layerCount; i++)
{
- uint8_t *srcLayerMemory = srcMemory;
+ const uint8_t *srcLayerMemory = srcMemory;
uint8_t *dstLayerMemory = dstMemory;
for(uint32_t z = 0; z < imageExtent.depth; z++)
{
- uint8_t *srcSliceMemory = srcLayerMemory;
+ const uint8_t *srcSliceMemory = srcLayerMemory;
uint8_t *dstSliceMemory = dstLayerMemory;
for(uint32_t y = 0; y < imageExtent.height; y++)
{
- ASSERT(((bufferIsSource ? dstSliceMemory : srcSliceMemory) + copySize) < end());
- ASSERT(((bufferIsSource ? srcSliceMemory : dstSliceMemory) + copySize) < buffer->end());
+ ASSERT(((memoryIsSource ? dstSliceMemory : srcSliceMemory) + copySize) < end());
memcpy(dstSliceMemory, srcSliceMemory, copySize);
srcSliceMemory += srcRowPitchBytes;
dstSliceMemory += dstRowPitchBytes;
@@ -655,20 +668,30 @@
dstMemory += dstLayerSize;
}
- if(bufferIsSource)
+ if(memoryIsSource)
{
- contentsChanged(ImageSubresourceRange(region.imageSubresource));
+ contentsChanged(ImageSubresourceRange(imageSubresource));
}
}
void Image::copyTo(Buffer *dstBuffer, const VkBufferImageCopy2KHR ®ion)
{
- copy(dstBuffer, region, false);
+ copy(nullptr, dstBuffer->getOffsetPointer(region.bufferOffset), region.bufferRowLength, region.bufferImageHeight, region.imageSubresource, region.imageOffset, region.imageExtent);
}
void Image::copyFrom(Buffer *srcBuffer, const VkBufferImageCopy2KHR ®ion)
{
- copy(srcBuffer, region, true);
+ copy(srcBuffer->getOffsetPointer(region.bufferOffset), nullptr, region.bufferRowLength, region.bufferImageHeight, region.imageSubresource, region.imageOffset, region.imageExtent);
+}
+
+void Image::copyToMemory(const VkImageToMemoryCopyEXT ®ion)
+{
+ copy(nullptr, region.pHostPointer, region.memoryRowLength, region.memoryImageHeight, region.imageSubresource, region.imageOffset, region.imageExtent);
+}
+
+void Image::copyFromMemory(const VkMemoryToImageCopyEXT ®ion)
+{
+ copy(region.pHostPointer, nullptr, region.memoryRowLength, region.memoryImageHeight, region.imageSubresource, region.imageOffset, region.imageExtent);
}
void *Image::getTexelPointer(const VkOffset3D &offset, const VkImageSubresource &subresource) const
@@ -714,33 +737,33 @@
return adjustedOffset;
}
-VkExtent2D Image::bufferExtentInBlocks(const VkExtent2D &extent, const VkBufferImageCopy2KHR ®ion) const
+VkExtent2D Image::bufferExtentInBlocks(const VkExtent2D &extent, uint32_t rowLength, uint32_t imageHeight, const VkImageSubresourceLayers &imageSubresource, const VkOffset3D &imageOffset) const
{
VkExtent2D adjustedExtent = extent;
- VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(region.imageSubresource.aspectMask);
+ VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(imageSubresource.aspectMask);
Format usedFormat = getFormat(aspect);
- if(region.bufferRowLength != 0)
+ if(rowLength != 0)
{
- adjustedExtent.width = region.bufferRowLength;
+ adjustedExtent.width = rowLength;
if(usedFormat.isCompressed())
{
int blockWidth = usedFormat.blockWidth();
- ASSERT((adjustedExtent.width % blockWidth == 0) || (adjustedExtent.width + region.imageOffset.x == extent.width));
- adjustedExtent.width = (region.bufferRowLength + blockWidth - 1) / blockWidth;
+ ASSERT((adjustedExtent.width % blockWidth == 0) || (adjustedExtent.width + imageOffset.x == extent.width));
+ adjustedExtent.width = (rowLength + blockWidth - 1) / blockWidth;
}
}
- if(region.bufferImageHeight != 0)
+ if(imageHeight != 0)
{
- adjustedExtent.height = region.bufferImageHeight;
+ adjustedExtent.height = imageHeight;
if(usedFormat.isCompressed())
{
int blockHeight = usedFormat.blockHeight();
- ASSERT((adjustedExtent.height % blockHeight == 0) || (adjustedExtent.height + region.imageOffset.y == extent.height));
- adjustedExtent.height = (region.bufferImageHeight + blockHeight - 1) / blockHeight;
+ ASSERT((adjustedExtent.height % blockHeight == 0) || (adjustedExtent.height + imageOffset.y == extent.height));
+ adjustedExtent.height = (imageHeight + blockHeight - 1) / blockHeight;
}
}
diff --git a/src/Vulkan/VkImage.hpp b/src/Vulkan/VkImage.hpp
index 839c1c4..d8a247e 100644
--- a/src/Vulkan/VkImage.hpp
+++ b/src/Vulkan/VkImage.hpp
@@ -63,6 +63,10 @@
void copyTo(Buffer *dstBuffer, const VkBufferImageCopy2KHR ®ion);
void copyFrom(Buffer *srcBuffer, const VkBufferImageCopy2KHR ®ion);
+ // VK_EXT_host_image_copy variants of copy
+ void copyToMemory(const VkImageToMemoryCopyEXT ®ion);
+ void copyFromMemory(const VkMemoryToImageCopyEXT ®ion);
+
void blitTo(Image *dstImage, const VkImageBlit2KHR ®ion, VkFilter filter) const;
void copyTo(uint8_t *dst, unsigned int dstPitch) const;
void resolveTo(Image *dstImage, const VkImageResolve2KHR ®ion) const;
@@ -119,7 +123,13 @@
DeviceMemory *deviceMemory = nullptr;
private:
- void copy(Buffer *buffer, const VkBufferImageCopy2KHR ®ion, bool bufferIsSource);
+ void copy(const void *srcCopyMemory,
+ void *dstCopyMemory,
+ uint32_t rowLength,
+ uint32_t imageHeight,
+ const VkImageSubresourceLayers &imageSubresource,
+ const VkOffset3D &imageCopyOffset,
+ const VkExtent3D &imageCopyExtent);
void copySingleAspectTo(Image *dstImage, const VkImageCopy2KHR ®ion) const;
VkDeviceSize getStorageSize(VkImageAspectFlags flags) const;
VkDeviceSize getMultiSampledLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const;
@@ -130,7 +140,7 @@
VkDeviceSize texelOffsetBytesInStorage(const VkOffset3D &offset, const VkImageSubresource &subresource) const;
VkExtent3D imageExtentInBlocks(const VkExtent3D &extent, VkImageAspectFlagBits aspect) const;
VkOffset3D imageOffsetInBlocks(const VkOffset3D &offset, VkImageAspectFlagBits aspect) const;
- VkExtent2D bufferExtentInBlocks(const VkExtent2D &extent, const VkBufferImageCopy2KHR ®ion) const;
+ VkExtent2D bufferExtentInBlocks(const VkExtent2D &extent, uint32_t rowLength, uint32_t imageHeight, const VkImageSubresourceLayers &imageSubresource, const VkOffset3D &imageOffset) const;
void clear(const void *pixelData, VkFormat pixelFormat, const vk::Format &viewFormat, const VkImageSubresourceRange &subresourceRange, const VkRect2D *renderArea);
int borderSize() const;
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 049ec97..3866d91 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -401,6 +401,12 @@
}
template<typename T>
+static void getPhysicalDeviceHostImageCopyFeatures(T *features)
+{
+ features->hostImageCopy = VK_TRUE;
+}
+
+template<typename T>
static void getPhysicalDeviceVulkan12Features(T *features)
{
features->samplerMirrorClampToEdge = VK_TRUE;
@@ -643,6 +649,9 @@
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT:
getPhysicalDeviceSwapchainMaintenance1FeaturesKHR(reinterpret_cast<struct VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT *>(curExtension));
break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT:
+ getPhysicalDeviceHostImageCopyFeatures(reinterpret_cast<struct VkPhysicalDeviceHostImageCopyFeaturesEXT *>(curExtension));
+ break;
case VK_STRUCTURE_TYPE_MAX_ENUM: // TODO(b/176893525): This may not be legal. dEQP tests that this value is ignored.
break;
default:
@@ -1403,6 +1412,60 @@
getPipelineRobustnessProperties(properties);
}
+template<typename T>
+static void getHostImageCopyProperties(T *properties)
+{
+ // There are no image layouts in SwiftShader, so support all layouts for host image copy
+ constexpr VkImageLayout kAllLayouts[] = {
+ VK_IMAGE_LAYOUT_GENERAL,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
+ VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL,
+ VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL,
+ VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL,
+ VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+ VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
+ };
+ constexpr uint32_t kAllLayoutsCount = std::size(kAllLayouts);
+
+ if(properties->pCopySrcLayouts == nullptr)
+ {
+ properties->copySrcLayoutCount = kAllLayoutsCount;
+ }
+ else
+ {
+ properties->copySrcLayoutCount = std::min(properties->copySrcLayoutCount, kAllLayoutsCount);
+ memcpy(properties->pCopySrcLayouts, kAllLayouts, properties->copySrcLayoutCount * sizeof(*properties->pCopySrcLayouts));
+ }
+
+ if(properties->pCopyDstLayouts == nullptr)
+ {
+ properties->copyDstLayoutCount = kAllLayoutsCount;
+ }
+ else
+ {
+ properties->copyDstLayoutCount = std::min(properties->copyDstLayoutCount, kAllLayoutsCount);
+ memcpy(properties->pCopyDstLayouts, kAllLayouts, properties->copyDstLayoutCount * sizeof(*properties->pCopyDstLayouts));
+ }
+
+ memcpy(properties->optimalTilingLayoutUUID, SWIFTSHADER_UUID, VK_UUID_SIZE);
+ properties->identicalMemoryTypeRequirements = VK_TRUE;
+}
+
+void PhysicalDevice::getProperties(VkPhysicalDeviceHostImageCopyPropertiesEXT *properties) const
+{
+ getHostImageCopyProperties(properties);
+}
+
void PhysicalDevice::getProperties(VkPhysicalDeviceVulkan12Properties *properties) const
{
getDriverProperties(properties);
@@ -1672,6 +1735,13 @@
return CheckFeature(requested, supported, swapchainMaintenance1);
}
+bool PhysicalDevice::hasExtendedFeatures(const VkPhysicalDeviceHostImageCopyFeaturesEXT *requested) const
+{
+ auto supported = getSupportedFeatures(requested);
+
+ return CheckFeature(requested, supported, hostImageCopy);
+}
+
bool PhysicalDevice::hasExtendedFeatures(const VkPhysicalDeviceDescriptorIndexingFeatures *requested) const
{
auto supported = getSupportedFeatures(requested);
@@ -1729,7 +1799,7 @@
}
#undef CheckFeature
-static bool checkFormatUsage(VkImageUsageFlags usage, VkFormatFeatureFlags features)
+static bool checkFormatUsage(VkImageUsageFlags usage, VkFormatFeatureFlags2KHR features)
{
// Check for usage conflict with features
if((usage & VK_IMAGE_USAGE_SAMPLED_BIT) && !(features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
@@ -1767,13 +1837,18 @@
return false;
}
+ if((usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT) && !(features & VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT))
+ {
+ return false;
+ }
+
return true;
}
bool vk::PhysicalDevice::isFormatSupported(vk::Format format, VkImageType type, VkImageTiling tiling,
VkImageUsageFlags usage, VkImageUsageFlags stencilUsage, VkImageCreateFlags flags)
{
- VkFormatProperties properties = {};
+ VkFormatProperties3 properties = {};
vk::PhysicalDevice::GetFormatProperties(format, &properties);
if(flags & VK_IMAGE_CREATE_EXTENDED_USAGE_BIT)
@@ -1788,7 +1863,7 @@
}
}
- VkFormatFeatureFlags features;
+ VkFormatFeatureFlags2KHR features;
switch(tiling)
{
case VK_IMAGE_TILING_LINEAR:
@@ -1828,7 +1903,8 @@
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
- VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
+ VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT;
ASSERT(!(usage & ~(allRecognizedUsageBits)));
if(usage & VK_IMAGE_USAGE_SAMPLED_BIT)
@@ -2029,7 +2105,8 @@
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
VK_FORMAT_FEATURE_BLIT_SRC_BIT |
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
- VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
+ VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
+ VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT;
break;
// YCbCr formats:
@@ -2041,7 +2118,8 @@
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
- VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT;
+ VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
+ VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT;
break;
default:
break;
@@ -2329,9 +2407,16 @@
{
// "Formats that are required to support VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT must also support
// VK_FORMAT_FEATURE_TRANSFER_SRC_BIT and VK_FORMAT_FEATURE_TRANSFER_DST_BIT."
+ //
+ // Additionally:
+ // "If VK_EXT_host_image_copy is supported and VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT is supported
+ // in optimalTilingFeatures or linearTilingFeatures for a color format,
+ // VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT must also be supported in optimalTilingFeatures
+ // or linearTilingFeatures respectively."
pFormatProperties->linearTilingFeatures |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
- VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
+ VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
+ VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT;
if(!format.isCompressed())
{
diff --git a/src/Vulkan/VkPhysicalDevice.hpp b/src/Vulkan/VkPhysicalDevice.hpp
index 11e3d47..60454e3 100644
--- a/src/Vulkan/VkPhysicalDevice.hpp
+++ b/src/Vulkan/VkPhysicalDevice.hpp
@@ -62,6 +62,7 @@
bool hasExtendedFeatures(const VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT *requested) const;
bool hasExtendedFeatures(const VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR *requested) const;
bool hasExtendedFeatures(const VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT *requested) const;
+ bool hasExtendedFeatures(const VkPhysicalDeviceHostImageCopyFeaturesEXT *requested) const;
const VkPhysicalDeviceProperties &getProperties() const;
void getProperties(VkPhysicalDeviceIDProperties *properties) const;
@@ -98,6 +99,7 @@
void getProperties(VkPhysicalDeviceShaderIntegerDotProductProperties *properties) const;
void getProperties(VkPhysicalDevicePipelineRobustnessPropertiesEXT *properties) const;
void getProperties(VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT *properties) const;
+ void getProperties(VkPhysicalDeviceHostImageCopyPropertiesEXT *properties) const;
void getProperties(VkPhysicalDeviceVulkan11Properties *properties) const;
void getProperties(VkPhysicalDeviceVulkan12Properties *properties) const;
void getProperties(VkPhysicalDeviceVulkan13Properties *properties) const;
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index d27b46b..5360f95 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -436,7 +436,8 @@
// Used by ANGLE to implement triangle/etc list restarts as possible in OpenGL
{ { VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME, VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_SPEC_VERSION } },
{ { VK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME, VK_EXT_PIPELINE_ROBUSTNESS_SPEC_VERSION } },
- { { VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION } }
+ { { VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION } },
+ { { VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME, VK_EXT_HOST_IMAGE_COPY_SPEC_VERSION } },
};
static uint32_t numSupportedExtensions(const ExtensionProperties *extensionProperties, uint32_t extensionPropertiesCount)
@@ -1125,6 +1126,7 @@
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT:
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT:
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT:
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT:
break;
default:
// "the [driver] must skip over, without processing (other than reading the sType and pNext members) any structures in the chain with sType values not defined by [supported extenions]"
@@ -2001,6 +2003,12 @@
(void)stencilUsageInfo->stencilUsage;
}
break;
+ case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT:
+ {
+ // Explicitly ignored, since VK_EXT_image_drm_format_modifier is not supported
+ ASSERT(!hasDeviceExtension(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME));
+ }
+ break;
case VK_STRUCTURE_TYPE_MAX_ENUM:
// dEQP tests that this value is ignored.
break;
@@ -2072,6 +2080,37 @@
vk::Cast(image)->getSubresourceLayout(pSubresource, pLayout);
}
+VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout2EXT(VkDevice device, VkImage image, const VkImageSubresource2KHR *pSubresource, VkSubresourceLayout2KHR *pLayout)
+{
+ TRACE("(VkDevice device = %p, VkImage image = %p, const VkImageSubresource2KHR* pSubresource = %p, VkSubresourceLayout2KHR* pLayout = %p)",
+ device, static_cast<void *>(image), pSubresource, pLayout);
+
+ // If tiling is OPTIMAL, this doesn't need to be done, but it's harmless especially since
+ // LINEAR and OPTIMAL are the same.
+ vk::Cast(image)->getSubresourceLayout(&pSubresource->imageSubresource, &pLayout->subresourceLayout);
+
+ VkBaseOutStructure *extInfo = reinterpret_cast<VkBaseOutStructure *>(pLayout->pNext);
+ while(extInfo)
+ {
+ switch(extInfo->sType)
+ {
+ case VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE_EXT:
+ {
+ // Since the subresource layout is filled above already, get the size out of
+ // that.
+ VkSubresourceHostMemcpySizeEXT *hostMemcpySize = reinterpret_cast<VkSubresourceHostMemcpySizeEXT *>(extInfo);
+ hostMemcpySize->size = pLayout->subresourceLayout.size;
+ break;
+ }
+ default:
+ UNSUPPORTED("pLayout->pNext sType = %s", vk::Stringify(extInfo->sType).c_str());
+ break;
+ }
+
+ extInfo = extInfo->pNext;
+ }
+}
+
VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImageView *pView)
{
TRACE("(VkDevice device = %p, const VkImageViewCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkImageView* pView = %p)",
@@ -3760,6 +3799,12 @@
vk::Cast(physicalDevice)->getProperties(properties);
}
break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES_EXT:
+ {
+ auto *properties = reinterpret_cast<VkPhysicalDeviceHostImageCopyPropertiesEXT *>(extensionProperties);
+ vk::Cast(physicalDevice)->getProperties(properties);
+ }
+ break;
default:
// "the [driver] must skip over, without processing (other than reading the sType and pNext members) any structures in the chain with sType values not defined by [supported extenions]"
UNSUPPORTED("pProperties->pNext sType = %s", vk::Stringify(extensionProperties->sType).c_str());
@@ -3883,6 +3928,14 @@
ASSERT(!hasDeviceExtension(VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME));
}
break;
+ case VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY_EXT:
+ {
+ auto *properties = reinterpret_cast<VkHostImageCopyDevicePerformanceQueryEXT *>(extensionProperties);
+ // Host image copy is equally performant on the host with SwiftShader; it's the same code running on the main thread.
+ properties->optimalDeviceAccess = VK_TRUE;
+ properties->identicalMemoryLayout = VK_TRUE;
+ }
+ break;
#ifdef __ANDROID__
case VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID:
{
@@ -4329,6 +4382,67 @@
vk::Cast(instance)->submitDebugUtilsMessage(messageSeverity, messageTypes, pCallbackData);
}
+VKAPI_ATTR VkResult VKAPI_CALL vkCopyMemoryToImageEXT(VkDevice device, const VkCopyMemoryToImageInfoEXT *pCopyMemoryToImageInfo)
+{
+ TRACE("(VkDevice device = %p, const VkCopyMemoryToImageInfoEXT* pCopyMemoryToImageInfo = %p)",
+ device, pCopyMemoryToImageInfo);
+
+ constexpr auto allRecognizedFlagBits = VK_HOST_IMAGE_COPY_MEMCPY_EXT;
+ ASSERT(!(pCopyMemoryToImageInfo->flags & ~allRecognizedFlagBits));
+
+ vk::Image *dstImage = vk::Cast(pCopyMemoryToImageInfo->dstImage);
+ for(uint32_t i = 0; i < pCopyMemoryToImageInfo->regionCount; i++)
+ {
+ dstImage->copyFromMemory(pCopyMemoryToImageInfo->pRegions[i]);
+ }
+
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCopyImageToMemoryEXT(VkDevice device, const VkCopyImageToMemoryInfoEXT *pCopyImageToMemoryInfo)
+{
+ TRACE("(VkDevice device = %p, const VkCopyImageToMemoryInfoEXT* pCopyImageToMemoryInfo = %p)",
+ device, pCopyImageToMemoryInfo);
+
+ constexpr auto allRecognizedFlagBits = VK_HOST_IMAGE_COPY_MEMCPY_EXT;
+ ASSERT(!(pCopyImageToMemoryInfo->flags & ~allRecognizedFlagBits));
+
+ vk::Image *srcImage = vk::Cast(pCopyImageToMemoryInfo->srcImage);
+ for(uint32_t i = 0; i < pCopyImageToMemoryInfo->regionCount; i++)
+ {
+ srcImage->copyToMemory(pCopyImageToMemoryInfo->pRegions[i]);
+ }
+
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCopyImageToImageEXT(VkDevice device, const VkCopyImageToImageInfoEXT *pCopyImageToImageInfo)
+{
+ TRACE("(VkDevice device = %p, const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo = %p)",
+ device, pCopyImageToImageInfo);
+
+ constexpr auto allRecognizedFlagBits = VK_HOST_IMAGE_COPY_MEMCPY_EXT;
+ ASSERT(!(pCopyImageToImageInfo->flags & ~allRecognizedFlagBits));
+
+ vk::Image *srcImage = vk::Cast(pCopyImageToImageInfo->srcImage);
+ vk::Image *dstImage = vk::Cast(pCopyImageToImageInfo->dstImage);
+ for(uint32_t i = 0; i < pCopyImageToImageInfo->regionCount; i++)
+ {
+ srcImage->copyTo(dstImage, pCopyImageToImageInfo->pRegions[i]);
+ }
+
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL vkTransitionImageLayoutEXT(VkDevice device, uint32_t transitionCount, const VkHostImageLayoutTransitionInfoEXT *pTransitions)
+{
+ TRACE("(VkDevice device = %p, uint32_t transitionCount = %u, const VkHostImageLayoutTransitionInfoEXT* pTransitions = %p)",
+ device, transitionCount, pTransitions);
+
+ // This function is a no-op; there are no image layouts in SwiftShader.
+ return VK_SUCCESS;
+}
+
#ifdef VK_USE_PLATFORM_XCB_KHR
VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface)
{