diff options
Diffstat (limited to 'layers/buffer_validation.cpp')
| -rw-r--r-- | layers/buffer_validation.cpp | 172 |
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; +} |
