layers: Add validation for Image Aspect settings
Image layer gets validation for image aspect settings laid out in the spec.
diff --git a/layers/image.cpp b/layers/image.cpp
index d58f1a7..912c23f 100644
--- a/layers/image.cpp
+++ b/layers/image.cpp
@@ -414,6 +414,12 @@
skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_VIEW_CREATE_ERROR, "IMAGE", ss.str().c_str());
}
}
+
+ // TODO: Image aspect mask must be only VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_DEPTH_BIT or VK_IMAGE_ASPECT_STENCIL_BIT
+ // if the format is a color, depth-only or stencil-only format respectively. If using a depth/stencil format,
+ // aspectMask must include at least one of VK_IMAGE_ASPECT_DEPTH_BIT and VK_IMAGE_ASPECT_STENCIL_BIT, and may include both.
+ // Add after image/buffer state tracking is implemented.
+
if (skipCall)
return VK_ERROR_VALIDATION_FAILED;
@@ -421,6 +427,246 @@
return result;
}
+VK_LAYER_EXPORT void VKAPI vkCmdClearColorImage(
+ VkCmdBuffer cmdBuffer,
+ VkImage image,
+ VkImageLayout imageLayout,
+ const VkClearColorValue *pColor,
+ uint32_t rangeCount,
+ const VkImageSubresourceRange *pRanges)
+{
+ VkBool32 skipCall = VK_FALSE;
+
+ // For each range, image aspect must be color only
+ for (uint32_t i = 0; i < rangeCount; i++) {
+ if (pRanges[i].aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) {
+ layer_data *device_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
+ char const str[] = "vkCmdClearColorImage aspectMasks for all subresource ranges must be set to VK_IMAGE_ASPECT_COLOR_BIT";
+ skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+ (uint64_t)cmdBuffer, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
+ }
+ }
+
+ if (VK_FALSE == skipCall) {
+ get_dispatch_table(image_device_table_map, cmdBuffer)->CmdClearColorImage(cmdBuffer, image, imageLayout,
+ pColor, rangeCount, pRanges);
+ }
+}
+
+VK_LAYER_EXPORT void VKAPI vkCmdClearDepthStencilImage(
+ VkCmdBuffer cmdBuffer,
+ VkImage image,
+ VkImageLayout imageLayout,
+ const VkClearDepthStencilValue *pDepthStencil,
+ uint32_t rangeCount,
+ const VkImageSubresourceRange *pRanges)
+{
+ VkBool32 skipCall = VK_FALSE;
+
+ // For each range, Image aspect must be depth or stencil or both
+ for (uint32_t i = 0; i < rangeCount; i++) {
+ if (((pRanges[i].aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) &&
+ ((pRanges[i].aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT))
+ {
+ layer_data *device_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
+ char const str[] = "vkCmdClearDepthStencilImage aspectMasks for all subresource ranges must be "
+ "set to VK_IMAGE_ASPECT_DEPTH_BIT and/or VK_IMAGE_ASPECT_STENCIL_BIT";
+ skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+ (uint64_t)cmdBuffer, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
+ }
+ }
+
+ if (VK_FALSE == skipCall) {
+ get_dispatch_table(image_device_table_map, cmdBuffer)->CmdClearDepthStencilImage(cmdBuffer,
+ image, imageLayout, pDepthStencil, rangeCount, pRanges);
+ }
+}
+
+VK_LAYER_EXPORT void VKAPI vkCmdClearDepthStencilAttachment(
+ VkCmdBuffer cmdBuffer,
+ VkImageAspectFlags imageAspectMask,
+ VkImageLayout imageLayout,
+ const VkClearDepthStencilValue *pDepthStencil,
+ uint32_t rectCount,
+ const VkRect3D *pRects)
+{
+ VkBool32 skipCall = VK_FALSE;
+
+ // Image aspect must be depth or stencil or both
+ if (((imageAspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) &&
+ ((imageAspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT))
+ {
+ layer_data *device_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
+ char const str[] = "vkCmdClearDepthStencilAttachment aspectMask must be set to VK_IMAGE_ASPECT_DEPTH_BIT and/or VK_IMAGE_ASPECT_STENCIL_BIT";
+ skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+ (uint64_t)cmdBuffer, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
+ }
+
+ if (VK_FALSE == skipCall) {
+ get_dispatch_table(image_device_table_map, cmdBuffer)->CmdClearDepthStencilAttachment(cmdBuffer,
+ imageAspectMask, imageLayout, pDepthStencil, rectCount, pRects);
+ }
+}
+
+VK_LAYER_EXPORT void VKAPI vkCmdCopyImage(
+ VkCmdBuffer cmdBuffer,
+ VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkImage destImage,
+ VkImageLayout destImageLayout,
+ uint32_t regionCount,
+ const VkImageCopy *pRegions)
+{
+ VkBool32 skipCall = VK_FALSE;
+
+ // For each region, src aspect mask must match dest aspect mask
+ // For each region, color aspects cannot be mixed with depth/stencil aspects
+ for (uint32_t i = 0; i < regionCount; i++) {
+ if (pRegions[i].srcSubresource.aspect != pRegions[i].destSubresource.aspect) {
+ layer_data *device_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
+ char const str[] = "vkCmdCopyImage: Src and dest aspectMasks for each region must match";
+ skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+ (uint64_t)cmdBuffer, 0, IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", str);
+ }
+ if ((pRegions[i].srcSubresource.aspect & VK_IMAGE_ASPECT_COLOR) &&
+ (pRegions[i].srcSubresource.aspect & (VK_IMAGE_ASPECT_DEPTH | VK_IMAGE_ASPECT_STENCIL))) {
+ layer_data *device_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
+ char const str[] = "vkCmdCopyImage aspectMask cannot specify both COLOR and DEPTH/STENCIL aspects";
+ skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+ (uint64_t)cmdBuffer, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
+ }
+ }
+
+ if (VK_FALSE == skipCall) {
+ get_dispatch_table(image_device_table_map, cmdBuffer)->CmdCopyImage(cmdBuffer, srcImage,
+ srcImageLayout, destImage, destImageLayout, regionCount, pRegions);
+ }
+}
+
+VK_LAYER_EXPORT void VKAPI vkCmdCopyImageToBuffer(
+ VkCmdBuffer cmdBuffer,
+ VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkBuffer destBuffer,
+ uint32_t regionCount,
+ const VkBufferImageCopy *pRegions)
+{
+ VkBool32 skipCall = VK_FALSE;
+
+ // Image aspect must be ONE OF color, depth, stencil
+ for (uint32_t i = 0; i < regionCount; i++) {
+ VkImageAspect aspect = pRegions[i].imageSubresource.aspect;
+ if ((aspect != VK_IMAGE_ASPECT_COLOR) &&
+ (aspect != VK_IMAGE_ASPECT_DEPTH) &&
+ (aspect != VK_IMAGE_ASPECT_STENCIL)) {
+ layer_data *device_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
+ char const str[] = "vkCmdCopyImageToBuffer: aspectMasks for each region must specify only COLOR or DEPTH or STENCIL";
+ skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+ (uint64_t)cmdBuffer, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
+ }
+ }
+
+ if (VK_FALSE == skipCall) {
+ get_dispatch_table(image_device_table_map, cmdBuffer)->CmdCopyImageToBuffer(cmdBuffer,
+ srcImage, srcImageLayout, destBuffer, regionCount, pRegions);
+ }
+}
+
+
+VK_LAYER_EXPORT void VKAPI vkCmdCopyBufferToImage(
+ VkCmdBuffer cmdBuffer,
+ VkBuffer srcBuffer,
+ VkImage destImage,
+ VkImageLayout destImageLayout,
+ uint32_t regionCount,
+ const VkBufferImageCopy *pRegions)
+{
+ VkBool32 skipCall = VK_FALSE;
+
+ // Image aspect must be ONE OF color, depth, stencil
+ for (uint32_t i = 0; i < regionCount; i++) {
+ VkImageAspect aspect = pRegions[i].imageSubresource.aspect;
+ if ((aspect != VK_IMAGE_ASPECT_COLOR) &&
+ (aspect != VK_IMAGE_ASPECT_DEPTH) &&
+ (aspect != VK_IMAGE_ASPECT_STENCIL)) {
+ layer_data *device_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
+ char const str[] = "vkCmdCopyBufferToImage: aspectMasks for each region must specify only COLOR or DEPTH or STENCIL";
+ skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+ (uint64_t)cmdBuffer, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
+ }
+ }
+
+ if (VK_FALSE == skipCall) {
+ get_dispatch_table(image_device_table_map, cmdBuffer)->CmdCopyBufferToImage(cmdBuffer,
+ srcBuffer, destImage, destImageLayout, regionCount, pRegions);
+ }
+}
+
+VK_LAYER_EXPORT void VKAPI vkCmdBlitImage(
+ VkCmdBuffer cmdBuffer,
+ VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkImage destImage,
+ VkImageLayout destImageLayout,
+ uint32_t regionCount,
+ const VkImageBlit *pRegions,
+ VkTexFilter filter)
+{
+ // TODO: From the spec -- these validation items will require the image layer to maintain image/buffer state.
+ // If one of srcImage and destImage images has signed integer format, the other one must also have be signed integer format.
+ // If one of srcImage and destImage images has unsigned integer format, the other one must also have be an unsigned integer format.
+ // If the format of srcImage is a depth, stencil, depth stencil or integer-based format then filter must be VK_TEX_FILTER_NEAREST.
+ // If one of srcImage and destImage images has a format of depth, stencil or depth stencil, the other one must have exactly the same format.
+ // Additionally the allowed aspect bits in srcSubresource and destSubresource are only VK_IMAGE_ASPECT_DEPTH_BIT and
+ // VK_IMAGE_ASPECT_STENCIL_BIT and the given aspect must exist in the format of both srcImage and destImage images.
+
+ get_dispatch_table(image_device_table_map, cmdBuffer)->CmdBlitImage(cmdBuffer, srcImage,
+ srcImageLayout, destImage, destImageLayout, regionCount, pRegions, filter);
+}
+
+VK_LAYER_EXPORT void VKAPI vkCmdResolveImage(
+ VkCmdBuffer cmdBuffer,
+ VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkImage destImage,
+ VkImageLayout destImageLayout,
+ uint32_t regionCount,
+ const VkImageResolve *pRegions)
+{
+ VkBool32 skipCall = VK_FALSE;
+
+ // For each region, src and dest image aspect must be color only
+ for (uint32_t i = 0; i < regionCount; i++) {
+ if ((pRegions[i].srcSubresource.aspect != VK_IMAGE_ASPECT_COLOR) ||
+ (pRegions[i].destSubresource.aspect != VK_IMAGE_ASPECT_COLOR)) {
+ layer_data *device_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
+ char const str[] = "vkCmdResolveImage: src and dest aspectMasks for each region must specify only VK_IMAGE_ASPECT_COLOR_BIT";
+ skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_COMMAND_BUFFER,
+ (uint64_t)cmdBuffer, 0, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
+ }
+ }
+
+ if (VK_FALSE == skipCall) {
+ get_dispatch_table(image_device_table_map, cmdBuffer)->CmdResolveImage(cmdBuffer, srcImage,
+ srcImageLayout, destImage, destImageLayout, regionCount, pRegions);
+ }
+}
+
+VK_LAYER_EXPORT VkResult VKAPI vkGetImageSubresourceLayout(
+ VkDevice device,
+ VkImage image,
+ const VkImageSubresource *pSubresource,
+ VkSubresourceLayout *pLayout)
+{
+ VkResult result = get_dispatch_table(image_device_table_map, device)->GetImageSubresourceLayout(device,
+ image, pSubresource, pLayout);
+
+ // TODO: After state tracking for images/buffers is implemented, validate that returned aspects match
+ // the created formats -- color for color formats, depth|stencil for ds formats
+
+ return result;
+}
+
VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice device, const char* funcName)
{
if (device == NULL) {
@@ -443,7 +689,24 @@
return (PFN_vkVoidFunction) vkCreateImageView;
if (!strcmp(funcName, "vkCreateRenderPass"))
return (PFN_vkVoidFunction) vkCreateRenderPass;
-
+ if (!strcmp(funcName, "vkCmdClearColorImage"))
+ return (PFN_vkVoidFunction) vkCmdClearColorImage;
+ if (!strcmp(funcName, "vkCmdClearDepthStencilImage"))
+ return (PFN_vkVoidFunction) vkCmdClearDepthStencilImage;
+ if (!strcmp(funcName, "vkCmdClearDepthStencilAttachment"))
+ return (PFN_vkVoidFunction) vkCmdClearDepthStencilAttachment;
+ if (!strcmp(funcName, "vkCmdCopyImage"))
+ return (PFN_vkVoidFunction) vkCmdCopyImage;
+ if (!strcmp(funcName, "vkCmdCopyImageToBuffer"))
+ return (PFN_vkVoidFunction) vkCmdCopyImageToBuffer;
+ if (!strcmp(funcName, "vkCmdCopyBufferToImage"))
+ return (PFN_vkVoidFunction) vkCmdCopyBufferToImage;
+ if (!strcmp(funcName, "vkCmdBlitImage"))
+ return (PFN_vkVoidFunction) vkCmdBlitImage;
+ if (!strcmp(funcName, "vkCmdResolveImage"))
+ return (PFN_vkVoidFunction) vkCmdResolveImage;
+ if (!strcmp(funcName, "vkGetImageSubresourceLayout"))
+ return (PFN_vkVoidFunction) vkGetImageSubresourceLayout;
{
if (get_dispatch_table(image_device_table_map, device)->GetDeviceProcAddr == NULL)
return NULL;