aboutsummaryrefslogtreecommitdiff
path: root/layers/buffer_validation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layers/buffer_validation.cpp')
-rw-r--r--layers/buffer_validation.cpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/layers/buffer_validation.cpp b/layers/buffer_validation.cpp
index 5de8be0f..f4b62bd9 100644
--- a/layers/buffer_validation.cpp
+++ b/layers/buffer_validation.cpp
@@ -2454,3 +2454,175 @@ void PreCallRecordCmdFillBuffer(layer_data *device_data, GLOBAL_CB_NODE *cb_node
AddCommandBufferBindingBuffer(device_data, cb_node, buffer_state);
core_validation::UpdateCmdBufferLastCmd(cb_node, CMD_FILLBUFFER);
}
+
+bool ValidateBufferImageCopyData(layer_data *device_data, uint32_t regionCount, const VkBufferImageCopy *pRegions,
+ VkImage image, const char *function) {
+ const debug_report_data *report_data = core_validation::GetReportData(device_data);
+ bool skip = false;
+
+ for (uint32_t i = 0; i < regionCount; i++) {
+ auto image_info = GetImageState(device_data, image);
+ if (image_info) {
+ if (image_info->createInfo.imageType == VK_IMAGE_TYPE_1D) {
+ if ((pRegions[i].imageOffset.y != 0) || (pRegions[i].imageExtent.height != 1)) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01746, "IMAGE",
+ "%s(): pRegion[%d] imageOffset.y is %d and imageExtent.height is %d. For 1D images these "
+ "must be 0 and 1, respectively. %s",
+ function, i, pRegions[i].imageOffset.y, pRegions[i].imageExtent.height,
+ validation_error_map[VALIDATION_ERROR_01746]);
+ }
+ }
+
+ if ((image_info->createInfo.imageType == VK_IMAGE_TYPE_1D) || (image_info->createInfo.imageType == VK_IMAGE_TYPE_2D)) {
+ if ((pRegions[i].imageOffset.z != 0) || (pRegions[i].imageExtent.depth != 1)) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01747, "IMAGE",
+ "%s(): pRegion[%d] imageOffset.z is %d and imageExtent.depth is %d. For 1D and 2D images these "
+ "must be 0 and 1, respectively. %s",
+ function, i, pRegions[i].imageOffset.z, pRegions[i].imageExtent.depth,
+ validation_error_map[VALIDATION_ERROR_01747]);
+ }
+ }
+
+ if (image_info->createInfo.imageType == VK_IMAGE_TYPE_3D) {
+ if ((0 != pRegions[i].imageSubresource.baseArrayLayer) || (1 != pRegions[i].imageSubresource.layerCount)) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01281, "IMAGE",
+ "%s(): pRegion[%d] imageSubresource.baseArrayLayer is %d and imageSubresource.layerCount is "
+ "%d. For 3D images these must be 0 and 1, respectively. %s",
+ function, i, pRegions[i].imageSubresource.baseArrayLayer,
+ pRegions[i].imageSubresource.layerCount, validation_error_map[VALIDATION_ERROR_01281]);
+ }
+ }
+
+ // If the the calling command's VkImage parameter's format is not a depth/stencil format,
+ // then bufferOffset must be a multiple of the calling command's VkImage parameter's texel size
+ auto texel_size = vk_format_get_size(image_info->createInfo.format);
+ if (!vk_format_is_depth_and_stencil(image_info->createInfo.format) &&
+ vk_safe_modulo(pRegions[i].bufferOffset, texel_size) != 0) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01263, "IMAGE",
+ "%s(): pRegion[%d] bufferOffset 0x%" PRIxLEAST64
+ " must be a multiple of this format's texel size (" PRINTF_SIZE_T_SPECIFIER "). %s",
+ function, i, pRegions[i].bufferOffset, texel_size, validation_error_map[VALIDATION_ERROR_01263]);
+ }
+
+ // BufferOffset must be a multiple of 4
+ if (vk_safe_modulo(pRegions[i].bufferOffset, 4) != 0) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01264, "IMAGE",
+ "%s(): pRegion[%d] bufferOffset 0x%" PRIxLEAST64 " must be a multiple of 4. %s", function, i,
+ pRegions[i].bufferOffset, validation_error_map[VALIDATION_ERROR_01264]);
+ }
+
+ // BufferRowLength must be 0, or greater than or equal to the width member of imageExtent
+ if ((pRegions[i].bufferRowLength != 0) && (pRegions[i].bufferRowLength < pRegions[i].imageExtent.width)) {
+ skip |= log_msg(
+ report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01265, "IMAGE",
+ "%s(): pRegion[%d] bufferRowLength (%d) must be zero or greater-than-or-equal-to imageExtent.width (%d). %s",
+ function, i, pRegions[i].bufferRowLength, pRegions[i].imageExtent.width,
+ validation_error_map[VALIDATION_ERROR_01265]);
+ }
+
+ // BufferImageHeight must be 0, or greater than or equal to the height member of imageExtent
+ if ((pRegions[i].bufferImageHeight != 0) && (pRegions[i].bufferImageHeight < pRegions[i].imageExtent.height)) {
+ skip |= log_msg(
+ report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01266, "IMAGE",
+ "%s(): pRegion[%d] bufferImageHeight (%d) must be zero or greater-than-or-equal-to imageExtent.height (%d). %s",
+ function, i, pRegions[i].bufferImageHeight, pRegions[i].imageExtent.height,
+ validation_error_map[VALIDATION_ERROR_01266]);
+ }
+
+ // subresource aspectMask must have exactly 1 bit set
+ const int num_bits = sizeof(VkFlags) * CHAR_BIT;
+ std::bitset<num_bits> aspect_mask_bits(pRegions[i].imageSubresource.aspectMask);
+ if (aspect_mask_bits.count() != 1) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01280, "IMAGE",
+ "%s: aspectMasks for imageSubresource in each region must have only a single bit set. %s", function,
+ validation_error_map[VALIDATION_ERROR_01280]);
+ }
+
+ // image subresource aspect bit must match format
+ if (((0 != (pRegions[i].imageSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT)) &&
+ (!vk_format_is_color(image_info->createInfo.format))) ||
+ ((0 != (pRegions[i].imageSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)) &&
+ (!vk_format_has_depth(image_info->createInfo.format))) ||
+ ((0 != (pRegions[i].imageSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) &&
+ (!vk_format_has_stencil(image_info->createInfo.format)))) {
+ skip |= log_msg(
+ report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01279, "IMAGE",
+ "%s(): pRegion[%d] subresource aspectMask 0x%x specifies aspects that are not present in image format 0x%x. %s",
+ function, i, pRegions[i].imageSubresource.aspectMask, image_info->createInfo.format,
+ validation_error_map[VALIDATION_ERROR_01279]);
+ }
+
+ // Checks that apply only to compressed images
+ // TODO: there is a comment in ValidateCopyBufferImageTransferGranularityRequirements() in core_validation.cpp that
+ // reserves a place for these compressed image checks. This block of code could move there once the image
+ // stuff is moved into core validation.
+ if (vk_format_is_compressed(image_info->createInfo.format)) {
+ VkExtent2D block_size = vk_format_compressed_block_size(image_info->createInfo.format);
+
+ // BufferRowLength must be a multiple of block width
+ if (vk_safe_modulo(pRegions[i].bufferRowLength, block_size.width) != 0) {
+ skip |= log_msg(
+ report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01271, "IMAGE",
+ "%s(): pRegion[%d] bufferRowLength (%d) must be a multiple of the compressed image's texel width (%d). %s.",
+ function, i, pRegions[i].bufferRowLength, block_size.width, validation_error_map[VALIDATION_ERROR_01271]);
+ }
+
+ // BufferRowHeight must be a multiple of block height
+ if (vk_safe_modulo(pRegions[i].bufferImageHeight, block_size.height) != 0) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01272, "IMAGE",
+ "%s(): pRegion[%d] bufferImageHeight (%d) must be a multiple of the compressed image's texel "
+ "height (%d). %s.",
+ function, i, pRegions[i].bufferImageHeight, block_size.height,
+ validation_error_map[VALIDATION_ERROR_01272]);
+ }
+
+ // image offsets must be multiples of block dimensions
+ if ((vk_safe_modulo(pRegions[i].imageOffset.x, block_size.width) != 0) ||
+ (vk_safe_modulo(pRegions[i].imageOffset.y, block_size.height) != 0)) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01273, "IMAGE",
+ "%s(): pRegion[%d] imageOffset(x,y) (%d, %d) must be multiples of the compressed image's texel "
+ "width & height (%d, %d). %s.",
+ function, i, pRegions[i].imageOffset.x, pRegions[i].imageOffset.y, block_size.width,
+ block_size.height, validation_error_map[VALIDATION_ERROR_01273]);
+ }
+
+ // bufferOffset must be a multiple of block size (linear bytes)
+ int block_size_in_bytes = block_size.width * block_size.height;
+ if (vk_safe_modulo(pRegions[i].bufferOffset, block_size_in_bytes) != 0) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+ reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01274, "IMAGE",
+ "%s(): pRegion[%d] bufferOffset (0x%" PRIxLEAST64 ") must be a multiple of the compressed image's texel block "
+ "size (0x%x). %s.",
+ function, i, pRegions[i].bufferOffset, block_size_in_bytes,
+ validation_error_map[VALIDATION_ERROR_01274]);
+ }
+ }
+ }
+ }
+
+ return skip;
+}
+
+bool PreCallValidateCmdCopyImageToBuffer(layer_data *dev_data, VkImage srcImage, uint32_t regionCount,
+ const VkBufferImageCopy *pRegions, const char *func_name) {
+ bool skip = ValidateBufferImageCopyData(dev_data, regionCount, pRegions, srcImage, "vkCmdCopyImageToBuffer");
+ return skip;
+}
+
+bool PreCallValidateCmdCopyBufferToImage(layer_data *dev_data, VkImage dstImage, uint32_t regionCount,
+ const VkBufferImageCopy *pRegions, const char *func_name) {
+ bool skip = ValidateBufferImageCopyData(dev_data, regionCount, pRegions, dstImage, "vkCmdCopyBufferToImage");
+ return skip;
+}