From fd5bbe87891f319890afa0296218d3bbbad34b88 Mon Sep 17 00:00:00 2001 From: Mark Lobodzinski Date: Thu, 2 Feb 2017 14:38:47 -0700 Subject: [PATCH] layers: Move CmdCopyImage validation into CV Moved from image layer into buffer module. Change-Id: If4a826cd8ce311a30d2ce15a820459dbe4b96743 --- layers/buffer_validation.cpp | 243 +++++++++++++++++++++++++++++++++ layers/buffer_validation.h | 3 + layers/core_validation.cpp | 3 + layers/core_validation_error_enums.h | 1 + layers/image.cpp | 255 ----------------------------------- 5 files changed, 250 insertions(+), 255 deletions(-) diff --git a/layers/buffer_validation.cpp b/layers/buffer_validation.cpp index e788e88..5feb7ad 100644 --- a/layers/buffer_validation.cpp +++ b/layers/buffer_validation.cpp @@ -855,3 +855,246 @@ bool PreCallValidateCmdClearDepthStencilImage(core_validation::layer_data *devic } return skip; } + +// Returns true if [x, xoffset] and [y, yoffset] overlap +static bool RangesIntersect(int32_t start, uint32_t start_offset, int32_t end, uint32_t end_offset) { + bool result = false; + uint32_t intersection_min = std::max(static_cast(start), static_cast(end)); + uint32_t intersection_max = std::min(static_cast(start) + start_offset, static_cast(end) + end_offset); + + if (intersection_max > intersection_min) { + result = true; + } + return result; +} + +// Returns true if two VkImageCopy structures overlap +static bool RegionIntersects(const VkImageCopy *src, const VkImageCopy *dst, VkImageType type) { + bool result = false; + if ((src->srcSubresource.mipLevel == dst->dstSubresource.mipLevel) && + (RangesIntersect(src->srcSubresource.baseArrayLayer, src->srcSubresource.layerCount, dst->dstSubresource.baseArrayLayer, + dst->dstSubresource.layerCount))) { + result = true; + switch (type) { + case VK_IMAGE_TYPE_3D: + result &= RangesIntersect(src->srcOffset.z, src->extent.depth, dst->dstOffset.z, dst->extent.depth); + // Intentionally fall through to 2D case + case VK_IMAGE_TYPE_2D: + result &= RangesIntersect(src->srcOffset.y, src->extent.height, dst->dstOffset.y, dst->extent.height); + // Intentionally fall through to 1D case + case VK_IMAGE_TYPE_1D: + result &= RangesIntersect(src->srcOffset.x, src->extent.width, dst->dstOffset.x, dst->extent.width); + break; + default: + // Unrecognized or new IMAGE_TYPE enums will be caught in parameter_validation + assert(false); + } + } + return result; +} + +// Returns true if offset and extent exceed image extents +static bool ExceedsBounds(const VkOffset3D *offset, const VkExtent3D *extent, const IMAGE_STATE *image_state) { + bool result = false; + // Extents/depths cannot be negative but checks left in for clarity + switch (image_state->createInfo.imageType) { + case VK_IMAGE_TYPE_3D: // Validate z and depth + if ((offset->z + extent->depth > image_state->createInfo.extent.depth) || (offset->z < 0) || + ((offset->z + static_cast(extent->depth)) < 0)) { + result = true; + } + // Intentionally fall through to 2D case to check height + case VK_IMAGE_TYPE_2D: // Validate y and height + if ((offset->y + extent->height > image_state->createInfo.extent.height) || (offset->y < 0) || + ((offset->y + static_cast(extent->height)) < 0)) { + result = true; + } + // Intentionally fall through to 1D case to check width + case VK_IMAGE_TYPE_1D: // Validate x and width + if ((offset->x + extent->width > image_state->createInfo.extent.width) || (offset->x < 0) || + ((offset->x + static_cast(extent->width)) < 0)) { + result = true; + } + break; + default: + assert(false); + } + return result; +} + +bool PreCallValidateCmdCopyImage(core_validation::layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state, + IMAGE_STATE *dst_image_state, uint32_t region_count, const VkImageCopy *regions) { + bool skip = false; + const debug_report_data *report_data = core_validation::GetReportData(device_data); + VkCommandBuffer command_buffer = cb_node->commandBuffer; + + // TODO: This does not cover swapchain-created images. This should fall out when this layer is moved into the core_validation + // layer + if (src_image_state && dst_image_state) { + for (uint32_t i = 0; i < region_count; i++) { + if (regions[i].srcSubresource.layerCount == 0) { + std::stringstream ss; + ss << "vkCmdCopyImage: number of layers in pRegions[" << i << "] srcSubresource is zero"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "IMAGE", + "%s", ss.str().c_str()); + } + + if (regions[i].dstSubresource.layerCount == 0) { + std::stringstream ss; + ss << "vkCmdCopyImage: number of layers in pRegions[" << i << "] dstSubresource is zero"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "IMAGE", + "%s", ss.str().c_str()); + } + + // For each region the layerCount member of srcSubresource and dstSubresource must match + if (regions[i].srcSubresource.layerCount != regions[i].dstSubresource.layerCount) { + std::stringstream ss; + ss << "vkCmdCopyImage: number of layers in source and destination subresources for pRegions[" << i + << "] do not match"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01198, "IMAGE", "%s. %s", + ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01198]); + } + + // For each region, the aspectMask member of srcSubresource and dstSubresource must match + if (regions[i].srcSubresource.aspectMask != regions[i].dstSubresource.aspectMask) { + char const str[] = "vkCmdCopyImage: Src and dest aspectMasks for each region must match"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01197, "IMAGE", "%s. %s", + str, validation_error_map[VALIDATION_ERROR_01197]); + } + + // AspectMask must not contain VK_IMAGE_ASPECT_METADATA_BIT + if ((regions[i].srcSubresource.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT) || + (regions[i].dstSubresource.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT)) { + std::stringstream ss; + ss << "vkCmdCopyImage: pRegions[" << i << "] may not specify aspectMask containing VK_IMAGE_ASPECT_METADATA_BIT"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01222, "IMAGE", "%s. %s", + ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01222]); + } + + // For each region, if aspectMask contains VK_IMAGE_ASPECT_COLOR_BIT, it must not contain either of + // VK_IMAGE_ASPECT_DEPTH_BIT or VK_IMAGE_ASPECT_STENCIL_BIT + if ((regions[i].srcSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) && + (regions[i].srcSubresource.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) { + char const str[] = "vkCmdCopyImage aspectMask cannot specify both COLOR and DEPTH/STENCIL aspects"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01221, "IMAGE", "%s. %s", + str, validation_error_map[VALIDATION_ERROR_01221]); + } + + // If either of the calling command's src_image or dst_image parameters are of VkImageType VK_IMAGE_TYPE_3D, + // the baseArrayLayer and layerCount members of both srcSubresource and dstSubresource must be 0 and 1, respectively + if (((src_image_state->createInfo.imageType == VK_IMAGE_TYPE_3D) || + (dst_image_state->createInfo.imageType == VK_IMAGE_TYPE_3D)) && + ((regions[i].srcSubresource.baseArrayLayer != 0) || (regions[i].srcSubresource.layerCount != 1) || + (regions[i].dstSubresource.baseArrayLayer != 0) || (regions[i].dstSubresource.layerCount != 1))) { + std::stringstream ss; + ss << "vkCmdCopyImage: src or dstImage type was IMAGE_TYPE_3D, but in subRegion[" << i + << "] baseArrayLayer was not zero or layerCount was not 1."; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01199, "IMAGE", "%s. %s", + ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01199]); + } + + // MipLevel must be less than the mipLevels specified in VkImageCreateInfo when the image was created + if (regions[i].srcSubresource.mipLevel >= src_image_state->createInfo.mipLevels) { + std::stringstream ss; + ss << "vkCmdCopyImage: pRegions[" << i + << "] specifies a src mipLevel greater than the number specified when the srcImage was created."; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01223, "IMAGE", "%s. %s", + ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01223]); + } + if (regions[i].dstSubresource.mipLevel >= dst_image_state->createInfo.mipLevels) { + std::stringstream ss; + ss << "vkCmdCopyImage: pRegions[" << i + << "] specifies a dst mipLevel greater than the number specified when the dstImage was created."; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01223, "IMAGE", "%s. %s", + ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01223]); + } + + // (baseArrayLayer + layerCount) must be less than or equal to the arrayLayers specified in VkImageCreateInfo when the + // image was created + if ((regions[i].srcSubresource.baseArrayLayer + regions[i].srcSubresource.layerCount) > + src_image_state->createInfo.arrayLayers) { + std::stringstream ss; + ss << "vkCmdCopyImage: srcImage arrayLayers was " << src_image_state->createInfo.arrayLayers << " but subRegion[" + << i << "] baseArrayLayer + layerCount is " + << (regions[i].srcSubresource.baseArrayLayer + regions[i].srcSubresource.layerCount); + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01224, "IMAGE", "%s. %s", + ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01224]); + } + if ((regions[i].dstSubresource.baseArrayLayer + regions[i].dstSubresource.layerCount) > + dst_image_state->createInfo.arrayLayers) { + std::stringstream ss; + ss << "vkCmdCopyImage: dstImage arrayLayers was " << dst_image_state->createInfo.arrayLayers << " but subRegion[" + << i << "] baseArrayLayer + layerCount is " + << (regions[i].dstSubresource.baseArrayLayer + regions[i].dstSubresource.layerCount); + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01224, "IMAGE", "%s. %s", + ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01224]); + } + + // The source region specified by a given element of regions must be a region that is contained within srcImage + if (ExceedsBounds(®ions[i].srcOffset, ®ions[i].extent, src_image_state)) { + std::stringstream ss; + ss << "vkCmdCopyImage: srcSubResource in pRegions[" << i << "] exceeds extents srcImage was created with"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01175, "IMAGE", "%s. %s", + ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01175]); + } + + // The destination region specified by a given element of regions must be a region that is contained within dst_image + if (ExceedsBounds(®ions[i].dstOffset, ®ions[i].extent, dst_image_state)) { + std::stringstream ss; + ss << "vkCmdCopyImage: dstSubResource in pRegions[" << i << "] exceeds extents dstImage was created with"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01176, "IMAGE", "%s. %s", + ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01176]); + } + + // The union of all source regions, and the union of all destination regions, specified by the elements of regions, + // must not overlap in memory + if (src_image_state->image == dst_image_state->image) { + for (uint32_t j = 0; j < region_count; j++) { + if (RegionIntersects(®ions[i], ®ions[j], src_image_state->createInfo.imageType)) { + std::stringstream ss; + ss << "vkCmdCopyImage: pRegions[" << i << "] src overlaps with pRegions[" << j << "]."; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01177, "IMAGE", + "%s. %s", ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01177]); + } + } + } + } + + // The formats of src_image and dst_image must be compatible. Formats are considered compatible if their texel size in bytes + // is the same between both formats. For example, VK_FORMAT_R8G8B8A8_UNORM is compatible with VK_FORMAT_R32_UINT because + // because both texels are 4 bytes in size. Depth/stencil formats must match exactly. + if (vk_format_is_depth_or_stencil(src_image_state->createInfo.format) || + vk_format_is_depth_or_stencil(dst_image_state->createInfo.format)) { + if (src_image_state->createInfo.format != dst_image_state->createInfo.format) { + char const str[] = "vkCmdCopyImage called with unmatched source and dest image depth/stencil formats."; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, DRAWSTATE_MISMATCHED_IMAGE_FORMAT, "IMAGE", + str); + } + } else { + size_t srcSize = vk_format_get_size(src_image_state->createInfo.format); + size_t destSize = vk_format_get_size(dst_image_state->createInfo.format); + if (srcSize != destSize) { + char const str[] = "vkCmdCopyImage called with unmatched source and dest image format sizes."; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01184, "IMAGE", "%s. %s", + str, validation_error_map[VALIDATION_ERROR_01184]); + } + } + } + return skip; +} diff --git a/layers/buffer_validation.h b/layers/buffer_validation.h index 25865e6..849ee49 100644 --- a/layers/buffer_validation.h +++ b/layers/buffer_validation.h @@ -121,4 +121,7 @@ bool VerifyDestImageLayout(core_validation::layer_data *dev_data, GLOBAL_CB_NODE void TransitionFinalSubpassLayouts(core_validation::layer_data *dev_data, GLOBAL_CB_NODE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin, FRAMEBUFFER_STATE *framebuffer_state); +bool PreCallValidateCmdCopyImage(core_validation::layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state, + IMAGE_STATE *dst_image_state, uint32_t region_count, const VkImageCopy *regions); + #endif // CORE_VALIDATION_BUFFER_VALIDATION_H_ diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp index 3df40a8..eb414bf 100644 --- a/layers/core_validation.cpp +++ b/layers/core_validation.cpp @@ -8127,6 +8127,9 @@ VKAPI_ATTR void VKAPI_CALL CmdCopyImage(VkCommandBuffer commandBuffer, VkImage s auto src_image_state = getImageState(dev_data, srcImage); auto dst_image_state = getImageState(dev_data, dstImage); if (cb_node && src_image_state && dst_image_state) { + + skip_call = PreCallValidateCmdCopyImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions); + skip_call |= ValidateMemoryIsBoundToImage(dev_data, src_image_state, "vkCmdCopyImage()", VALIDATION_ERROR_02533); skip_call |= ValidateMemoryIsBoundToImage(dev_data, dst_image_state, "vkCmdCopyImage()", VALIDATION_ERROR_02534); // Update bindings between images and cmd buffer diff --git a/layers/core_validation_error_enums.h b/layers/core_validation_error_enums.h index 4efd778..1de410d 100644 --- a/layers/core_validation_error_enums.h +++ b/layers/core_validation_error_enums.h @@ -135,6 +135,7 @@ enum DRAW_STATE_ERROR { DRAWSTATE_IMAGE_TRANSFER_GRANULARITY, DRAWSTATE_PUSH_CONSTANTS_ERROR, DRAWSTATE_INVALID_SUBPASS_INDEX, + DRAWSTATE_MISMATCHED_IMAGE_FORMAT, DRAWSTATE_SWAPCHAIN_NO_SYNC_FOR_ACQUIRE, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, DRAWSTATE_SWAPCHAIN_IMAGE_NOT_ACQUIRED, diff --git a/layers/image.cpp b/layers/image.cpp index 9153b83..fad72d7 100644 --- a/layers/image.cpp +++ b/layers/image.cpp @@ -241,267 +241,12 @@ VKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const Vk device_data->device_dispatch_table->DestroyImage(device, image, pAllocator); } -// Returns true if [x, xoffset] and [y, yoffset] overlap -static bool RangesIntersect(int32_t start, uint32_t start_offset, int32_t end, uint32_t end_offset) { - bool result = false; - uint32_t intersection_min = std::max(static_cast(start), static_cast(end)); - uint32_t intersection_max = std::min(static_cast(start) + start_offset, static_cast(end) + end_offset); - - if (intersection_max > intersection_min) { - result = true; - } - return result; -} - -// Returns true if two VkImageCopy structures overlap -static bool RegionIntersects(const VkImageCopy *src, const VkImageCopy *dst, VkImageType type) { - bool result = false; - if ((src->srcSubresource.mipLevel == dst->dstSubresource.mipLevel) && - (RangesIntersect(src->srcSubresource.baseArrayLayer, src->srcSubresource.layerCount, dst->dstSubresource.baseArrayLayer, - dst->dstSubresource.layerCount))) { - result = true; - switch (type) { - case VK_IMAGE_TYPE_3D: - result &= RangesIntersect(src->srcOffset.z, src->extent.depth, dst->dstOffset.z, dst->extent.depth); - // Intentionally fall through to 2D case - case VK_IMAGE_TYPE_2D: - result &= RangesIntersect(src->srcOffset.y, src->extent.height, dst->dstOffset.y, dst->extent.height); - // Intentionally fall through to 1D case - case VK_IMAGE_TYPE_1D: - result &= RangesIntersect(src->srcOffset.x, src->extent.width, dst->dstOffset.x, dst->extent.width); - break; - default: - // Unrecognized or new IMAGE_TYPE enums will be caught in parameter_validation - assert(false); - } - } - return result; -} - -// Returns true if offset and extent exceed image extents -static bool ExceedsBounds(const VkOffset3D *offset, const VkExtent3D *extent, const IMAGE_STATE *image) { - bool result = false; - // Extents/depths cannot be negative but checks left in for clarity - switch (image->imageType) { - case VK_IMAGE_TYPE_3D: // Validate z and depth - if ((offset->z + extent->depth > image->extent.depth) || (offset->z < 0) || - ((offset->z + static_cast(extent->depth)) < 0)) { - result = true; - } - // Intentionally fall through to 2D case to check height - case VK_IMAGE_TYPE_2D: // Validate y and height - if ((offset->y + extent->height > image->extent.height) || (offset->y < 0) || - ((offset->y + static_cast(extent->height)) < 0)) { - result = true; - } - // Intentionally fall through to 1D case to check width - case VK_IMAGE_TYPE_1D: // Validate x and width - if ((offset->x + extent->width > image->extent.width) || (offset->x < 0) || - ((offset->x + static_cast(extent->width)) < 0)) { - result = true; - } - break; - default: - assert(false); - } - return result; -} - -bool PreCallValidateCmdCopyImage(VkCommandBuffer command_buffer, VkImage src_image, VkImage dst_image, uint32_t region_count, - const VkImageCopy *regions) { - bool skip = false; - layer_data *device_data = get_my_data_ptr(get_dispatch_key(command_buffer), layer_data_map); - auto src_image_entry = getImageState(device_data, src_image); - auto dst_image_entry = getImageState(device_data, dst_image); - - // TODO: This does not cover swapchain-created images. This should fall out when this layer is moved - // into the core_validation layer - if (src_image_entry && dst_image_entry) { - for (uint32_t i = 0; i < region_count; i++) { - if (regions[i].srcSubresource.layerCount == 0) { - std::stringstream ss; - ss << "vkCmdCopyImage: number of layers in pRegions[" << i << "] srcSubresource is zero"; - skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast(command_buffer), - __LINE__, IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str()); - } - - if (regions[i].dstSubresource.layerCount == 0) { - std::stringstream ss; - ss << "vkCmdCopyImage: number of layers in pRegions[" << i << "] dstSubresource is zero"; - skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast(command_buffer), - __LINE__, IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str()); - } - - // For each region the layerCount member of srcSubresource and dstSubresource must match - if (regions[i].srcSubresource.layerCount != regions[i].dstSubresource.layerCount) { - std::stringstream ss; - ss << "vkCmdCopyImage: number of layers in source and destination subresources for pRegions[" << i - << "] do not match"; - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01198, "IMAGE", "%s. %s", - ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01198]); - } - - // For each region, the aspectMask member of srcSubresource and dstSubresource must match - if (regions[i].srcSubresource.aspectMask != regions[i].dstSubresource.aspectMask) { - char const str[] = "vkCmdCopyImage: Src and dest aspectMasks for each region must match"; - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01197, "IMAGE", "%s. %s", str, - validation_error_map[VALIDATION_ERROR_01197]); - } - - // AspectMask must not contain VK_IMAGE_ASPECT_METADATA_BIT - if ((regions[i].srcSubresource.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT) || - (regions[i].dstSubresource.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT)) { - std::stringstream ss; - ss << "vkCmdCopyImage: pRegions[" << i << "] may not specify aspectMask containing VK_IMAGE_ASPECT_METADATA_BIT"; - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01222, "IMAGE", "%s. %s", - ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01222]); - } - - // For each region, if aspectMask contains VK_IMAGE_ASPECT_COLOR_BIT, it must not contain either of - // VK_IMAGE_ASPECT_DEPTH_BIT or VK_IMAGE_ASPECT_STENCIL_BIT - if ((regions[i].srcSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) && - (regions[i].srcSubresource.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) { - char const str[] = "vkCmdCopyImage aspectMask cannot specify both COLOR and DEPTH/STENCIL aspects"; - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01221, "IMAGE", "%s. %s", str, - validation_error_map[VALIDATION_ERROR_01221]); - } - - // If either of the calling command's src_image or dst_image parameters are of VkImageType VK_IMAGE_TYPE_3D, - // the baseArrayLayer and layerCount members of both srcSubresource and dstSubresource must be 0 and 1, respectively - if (((src_image_entry->imageType == VK_IMAGE_TYPE_3D) || (dst_image_entry->imageType == VK_IMAGE_TYPE_3D)) && - ((regions[i].srcSubresource.baseArrayLayer != 0) || (regions[i].srcSubresource.layerCount != 1) || - (regions[i].dstSubresource.baseArrayLayer != 0) || (regions[i].dstSubresource.layerCount != 1))) { - std::stringstream ss; - ss << "vkCmdCopyImage: src or dstImage type was IMAGE_TYPE_3D, but in subRegion[" << i - << "] baseArrayLayer was not zero or layerCount was not 1."; - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01199, "IMAGE", "%s. %s", - ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01199]); - } - - // MipLevel must be less than the mipLevels specified in VkImageCreateInfo when the image was created - if (regions[i].srcSubresource.mipLevel >= src_image_entry->mipLevels) { - std::stringstream ss; - ss << "vkCmdCopyImage: pRegions[" << i - << "] specifies a src mipLevel greater than the number specified when the srcImage was created."; - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01223, "IMAGE", "%s. %s", - ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01223]); - } - if (regions[i].dstSubresource.mipLevel >= dst_image_entry->mipLevels) { - std::stringstream ss; - ss << "vkCmdCopyImage: pRegions[" << i - << "] specifies a dst mipLevel greater than the number specified when the dstImage was created."; - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01223, "IMAGE", "%s. %s", - ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01223]); - } - - // (baseArrayLayer + layerCount) must be less than or equal to the arrayLayers specified in VkImageCreateInfo when the - // image was created - if ((regions[i].srcSubresource.baseArrayLayer + regions[i].srcSubresource.layerCount) > src_image_entry->arraySize) { - std::stringstream ss; - ss << "vkCmdCopyImage: srcImage arrayLayers was " << src_image_entry->arraySize << " but subRegion[" << i - << "] baseArrayLayer + layerCount is " - << (regions[i].srcSubresource.baseArrayLayer + regions[i].srcSubresource.layerCount); - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01224, "IMAGE", "%s. %s", - ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01224]); - } - if ((regions[i].dstSubresource.baseArrayLayer + regions[i].dstSubresource.layerCount) > dst_image_entry->arraySize) { - std::stringstream ss; - ss << "vkCmdCopyImage: dstImage arrayLayers was " << dst_image_entry->arraySize << " but subRegion[" << i - << "] baseArrayLayer + layerCount is " - << (regions[i].dstSubresource.baseArrayLayer + regions[i].dstSubresource.layerCount); - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01224, "IMAGE", "%s. %s", - ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01224]); - } - - // The source region specified by a given element of regions must be a region that is contained within srcImage - if (ExceedsBounds(®ions[i].srcOffset, ®ions[i].extent, src_image_entry)) { - std::stringstream ss; - ss << "vkCmdCopyImage: srcSubResource in pRegions[" << i << "] exceeds extents srcImage was created with"; - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01175, "IMAGE", "%s. %s", - ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01175]); - } - - // The destination region specified by a given element of regions must be a region that is contained within dst_image - if (ExceedsBounds(®ions[i].dstOffset, ®ions[i].extent, dst_image_entry)) { - std::stringstream ss; - ss << "vkCmdCopyImage: dstSubResource in pRegions[" << i << "] exceeds extents dstImage was created with"; - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01176, "IMAGE", "%s. %s", - ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01176]); - } - - // The union of all source regions, and the union of all destination regions, specified by the elements of regions, - // must not overlap in memory - if (src_image == dst_image) { - for (uint32_t j = 0; j < region_count; j++) { - if (RegionIntersects(®ions[i], ®ions[j], src_image_entry->imageType)) { - std::stringstream ss; - ss << "vkCmdCopyImage: pRegions[" << i << "] src overlaps with pRegions[" << j << "]."; - skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01177, "IMAGE", - "%s. %s", ss.str().c_str(), validation_error_map[VALIDATION_ERROR_01177]); - } - } - } - } - - // The formats of src_image and dst_image must be compatible. Formats are considered compatible if their texel size in bytes - // is the same between both formats. For example, VK_FORMAT_R8G8B8A8_UNORM is compatible with VK_FORMAT_R32_UINT because - // because both texels are 4 bytes in size. Depth/stencil formats must match exactly. - if (vk_format_is_depth_or_stencil(src_image_entry->format) || vk_format_is_depth_or_stencil(dst_image_entry->format)) { - if (src_image_entry->format != dst_image_entry->format) { - char const str[] = "vkCmdCopyImage called with unmatched source and dest image depth/stencil formats."; - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, IMAGE_MISMATCHED_IMAGE_FORMAT, "IMAGE", str); - } - } else { - size_t srcSize = vk_format_get_size(src_image_entry->format); - size_t destSize = vk_format_get_size(dst_image_entry->format); - if (srcSize != destSize) { - char const str[] = "vkCmdCopyImage called with unmatched source and dest image format sizes."; - skip |= - log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - reinterpret_cast(command_buffer), __LINE__, VALIDATION_ERROR_01184, "IMAGE", "%s. %s", str, - validation_error_map[VALIDATION_ERROR_01184]); - } - } - } - return skip; -} - VKAPI_ATTR void VKAPI_CALL CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) { bool skip = false; layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); - skip = PreCallValidateCmdCopyImage(commandBuffer, srcImage, dstImage, regionCount, pRegions); - if (!skip) { device_data->device_dispatch_table->CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); -- 2.7.4