From a9a34aa70ececc2f38b4cfe0f0434b3563af67eb Mon Sep 17 00:00:00 2001 From: Mark Lobodzinski Date: Thu, 12 Nov 2015 15:14:35 -0700 Subject: layers: LX196, validate createImage paramters against format limits Relocated some validation from DeviceLimits layer to Image layer, added additional per-format limit validation for CreateImage parameters. --- layers/device_limits.cpp | 57 ------------------ layers/image.cpp | 106 +++++++++++++++++++++++++++++----- layers/image.h | 1 + layers/vk_validation_layer_details.md | 1 + 4 files changed, 93 insertions(+), 72 deletions(-) diff --git a/layers/device_limits.cpp b/layers/device_limits.cpp index a08fb26a..7dbca10f 100644 --- a/layers/device_limits.cpp +++ b/layers/device_limits.cpp @@ -490,61 +490,6 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue(VkDevice device, uin dev_data->device_dispatch_table->GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue); } -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage( - VkDevice device, - const VkImageCreateInfo *pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkImage *pImage) -{ - VkBool32 skipCall = VK_FALSE; - VkResult result = VK_ERROR_VALIDATION_FAILED; - VkImageFormatProperties ImageFormatProperties = {0}; - - layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - VkPhysicalDevice physicalDevice = dev_data->physicalDevice; - layer_data *phy_dev_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map); - // Internal call to get format info. Still goes through layers, could potentially go directly to ICD. - phy_dev_data->instance_dispatch_table->GetPhysicalDeviceImageFormatProperties( - physicalDevice, pCreateInfo->format, pCreateInfo->imageType, pCreateInfo->tiling, - pCreateInfo->usage, pCreateInfo->flags, &ImageFormatProperties); - - VkDeviceSize imageGranularity = phy_dev_data->physicalDeviceProperties.limits.bufferImageGranularity; - imageGranularity = imageGranularity == 1 ? 0 : imageGranularity; - - if ((pCreateInfo->extent.depth > ImageFormatProperties.maxExtent.depth) || - (pCreateInfo->extent.width > ImageFormatProperties.maxExtent.width) || - (pCreateInfo->extent.height > ImageFormatProperties.maxExtent.height)) { - skipCall |= log_msg(phy_dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE, (uint64_t)pImage, 0, - DEVLIMITS_LIMITS_VIOLATION, "DL", - "CreateImage extents exceed allowable limits for format: " - "Width = %d Height = %d Depth = %d: Limits for Width = %d Height = %d Depth = %d for format %s.", - pCreateInfo->extent.width, pCreateInfo->extent.height, pCreateInfo->extent.depth, - ImageFormatProperties.maxExtent.width, ImageFormatProperties.maxExtent.height, ImageFormatProperties.maxExtent.depth, - string_VkFormat(pCreateInfo->format)); - - } - - uint64_t totalSize = ((uint64_t)pCreateInfo->extent.width * - (uint64_t)pCreateInfo->extent.height * - (uint64_t)pCreateInfo->extent.depth * - (uint64_t)pCreateInfo->arrayLayers * - (uint64_t)pCreateInfo->samples * - (uint64_t)vk_format_get_size(pCreateInfo->format) + - (uint64_t)imageGranularity ) & ~(uint64_t)imageGranularity; - - if (totalSize > ImageFormatProperties.maxResourceSize) { - skipCall |= log_msg(phy_dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE, (uint64_t)pImage, 0, - DEVLIMITS_LIMITS_VIOLATION, "DL", - "CreateImage resource size exceeds allowable maximum " - "Image resource size = %#" PRIxLEAST64 ", maximum resource size = %#" PRIxLEAST64 " ", - totalSize, ImageFormatProperties.maxResourceSize); - } - if (VK_FALSE == skipCall) { - result = dev_data->device_dispatch_table->CreateImage(device, pCreateInfo, pAllocator, pImage); - } - return result; -} - VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer( VkCommandBuffer commandBuffer, VkBuffer dstBuffer, @@ -651,8 +596,6 @@ VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkD return (PFN_vkVoidFunction) vkDestroyDevice; if (!strcmp(funcName, "vkGetDeviceQueue")) return (PFN_vkVoidFunction) vkGetDeviceQueue; - if (!strcmp(funcName, "vkCreateImage")) - return (PFN_vkVoidFunction) vkCreateImage; if (!strcmp(funcName, "CreateCommandPool")) return (PFN_vkVoidFunction) vkCreateCommandPool; if (!strcmp(funcName, "DestroyCommandPool")) diff --git a/layers/image.cpp b/layers/image.cpp index 59bd108e..3a37530e 100644 --- a/layers/image.cpp +++ b/layers/image.cpp @@ -52,18 +52,21 @@ using namespace std; using namespace std; struct layer_data { - debug_report_data *report_data; - std::vector logging_callback; - VkLayerDispatchTable* device_dispatch_table; - VkLayerInstanceDispatchTable* instance_dispatch_table; - VkPhysicalDevice physicalDevice; + debug_report_data *report_data; + vector logging_callback; + VkLayerDispatchTable* device_dispatch_table; + VkLayerInstanceDispatchTable *instance_dispatch_table; + VkPhysicalDevice physicalDevice; + VkPhysicalDeviceProperties physicalDeviceProperties; + unordered_map imageMap; layer_data() : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr), - physicalDevice(0) + physicalDevice(0), + physicalDeviceProperties() {}; }; @@ -163,6 +166,8 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice p device_data->physicalDevice = physicalDevice; } + instance_data->instance_dispatch_table->GetPhysicalDeviceProperties(physicalDevice, &(device_data->physicalDeviceProperties)); + return result; } @@ -263,26 +268,89 @@ static inline uint32_t validate_VkImageLayoutKHR(VkImageLayout input_value) VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage) { - VkBool32 skipCall = VK_FALSE; - layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); - if(pCreateInfo->format != VK_FORMAT_UNDEFINED) + VkBool32 skipCall = VK_FALSE; + VkResult result = VK_ERROR_VALIDATION_FAILED; + VkImageFormatProperties ImageFormatProperties = {0}; + + layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); + VkPhysicalDevice physicalDevice = device_data->physicalDevice; + layer_data *phy_dev_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map); + + if (pCreateInfo->format != VK_FORMAT_UNDEFINED) { VkFormatProperties properties; - get_my_data_ptr(get_dispatch_key(device_data->physicalDevice), layer_data_map)->instance_dispatch_table->GetPhysicalDeviceFormatProperties( + phy_dev_data->instance_dispatch_table->GetPhysicalDeviceFormatProperties( device_data->physicalDevice, pCreateInfo->format, &properties); - if((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0)) + if ((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0)) { char const str[] = "vkCreateImage parameter, VkFormat pCreateInfo->format, contains unsupported format"; skipCall |= log_msg(device_data->report_data, VK_DBG_REPORT_WARN_BIT, (VkDbgObjectType)0, 0, 0, IMAGE_FORMAT_UNSUPPORTED, "IMAGE", str); } } - if (skipCall) - return VK_ERROR_VALIDATION_FAILED; - VkResult result = device_data->device_dispatch_table->CreateImage(device, pCreateInfo, pAllocator, pImage); + // Internal call to get format info. Still goes through layers, could potentially go directly to ICD. + phy_dev_data->instance_dispatch_table->GetPhysicalDeviceImageFormatProperties( + physicalDevice, pCreateInfo->format, pCreateInfo->imageType, pCreateInfo->tiling, + pCreateInfo->usage, pCreateInfo->flags, &ImageFormatProperties); + + VkDeviceSize imageGranularity = device_data->physicalDeviceProperties.limits.bufferImageGranularity; + imageGranularity = imageGranularity == 1 ? 0 : imageGranularity; + + if ((pCreateInfo->extent.depth > ImageFormatProperties.maxExtent.depth) || + (pCreateInfo->extent.width > ImageFormatProperties.maxExtent.width) || + (pCreateInfo->extent.height > ImageFormatProperties.maxExtent.height)) { + skipCall |= log_msg(phy_dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE, (uint64_t)pImage, 0, + IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image", + "CreateImage extents exceed allowable limits for format: " + "Width = %d Height = %d Depth = %d: Limits for Width = %d Height = %d Depth = %d for format %s.", + pCreateInfo->extent.width, pCreateInfo->extent.height, pCreateInfo->extent.depth, + ImageFormatProperties.maxExtent.width, ImageFormatProperties.maxExtent.height, ImageFormatProperties.maxExtent.depth, + string_VkFormat(pCreateInfo->format)); + + } + + uint64_t totalSize = ((uint64_t)pCreateInfo->extent.width * + (uint64_t)pCreateInfo->extent.height * + (uint64_t)pCreateInfo->extent.depth * + (uint64_t)pCreateInfo->arrayLayers * + (uint64_t)pCreateInfo->samples * + (uint64_t)vk_format_get_size(pCreateInfo->format) + + (uint64_t)imageGranularity ) & ~(uint64_t)imageGranularity; + + if (totalSize > ImageFormatProperties.maxResourceSize) { + skipCall |= log_msg(phy_dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE, (uint64_t)pImage, 0, + IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image", + "CreateImage resource size exceeds allowable maximum " + "Image resource size = %#" PRIxLEAST64 ", maximum resource size = %#" PRIxLEAST64 " ", + totalSize, ImageFormatProperties.maxResourceSize); + } + + if (pCreateInfo->mipLevels > ImageFormatProperties.maxMipLevels) { + skipCall |= log_msg(phy_dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE, (uint64_t)pImage, 0, + IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image", + "CreateImage mipLevels=%d exceeds allowable maximum supported by format of %d", + pCreateInfo->mipLevels, ImageFormatProperties.maxMipLevels); + } + + if (pCreateInfo->arrayLayers > ImageFormatProperties.maxArrayLayers) { + skipCall |= log_msg(phy_dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE, (uint64_t)pImage, 0, + IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image", + "CreateImage arrayLayers=%d exceeds allowable maximum supported by format of %d", + pCreateInfo->arrayLayers, ImageFormatProperties.maxArrayLayers); + } + + if ((pCreateInfo->samples & ImageFormatProperties.sampleCounts) == 0) { + skipCall |= log_msg(phy_dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_IMAGE, (uint64_t)pImage, 0, + IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image", + "CreateImage samples %s is not supported by format 0x%.8X", + string_VkSampleCountFlagBits(pCreateInfo->samples), ImageFormatProperties.sampleCounts); + } - if(result == VK_SUCCESS) { + if (VK_FALSE == skipCall) { + result = device_data->device_dispatch_table->CreateImage(device, pCreateInfo, pAllocator, pImage); + } + if (result == VK_SUCCESS) { device_data->imageMap[*pImage] = IMAGE_STATE(pCreateInfo); } return result; @@ -988,6 +1056,12 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout( } } +VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties) +{ + layer_data *phy_dev_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map); + phy_dev_data->instance_dispatch_table->GetPhysicalDeviceProperties(physicalDevice, pProperties); +} + VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char* funcName) { if (device == NULL) { @@ -1075,6 +1149,8 @@ VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(V return (PFN_vkVoidFunction) vkEnumerateDeviceLayerProperties; if (!strcmp(funcName, "vkEnumerateDeviceExtensionProperties")) return (PFN_vkVoidFunction) vkEnumerateDeviceExtensionProperties; + if (!strcmp(funcName, "vkGetPhysicalDeviceProperties")) + return (PFN_vkVoidFunction) vkGetPhysicalDeviceProperties; PFN_vkVoidFunction fptr = debug_report_get_instance_proc_addr(my_data->report_data, funcName); if(fptr) diff --git a/layers/image.h b/layers/image.h index 2ddd4eba..cbe61f81 100644 --- a/layers/image.h +++ b/layers/image.h @@ -45,6 +45,7 @@ typedef enum _IMAGE_ERROR IMAGE_INVALID_RESOLVE_SAMPLES, // Image resolve source samples less than two or dest samples greater than one IMAGE_INVALID_FORMAT, // Operation specifies an invalid format, or there is a format mismatch IMAGE_INVALID_FILTER, // Operation specifies an invalid filter setting + IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, // Device limits for this format have been exceeded } IMAGE_ERROR; typedef struct _IMAGE_STATE diff --git a/layers/vk_validation_layer_details.md b/layers/vk_validation_layer_details.md index 4e06cb20..e6588d4a 100644 --- a/layers/vk_validation_layer_details.md +++ b/layers/vk_validation_layer_details.md @@ -141,6 +141,7 @@ DETAILS TABLE PENDING | Resolve Sample Count | Verifies that source and dest images sample counts are valid | INVALID_RESOLVE_SAMPLES | vkCmdResolveImage | ResolveImageHighSampleCount ResolveImageLowSampleCount | NA | | Verify Format | Verifies the formats are valid for this image operation | INVALID_FORMAT | vkCreateImageView vkCmdBlitImage | TBD | NA | | Verify Correct Image Filter| Verifies that specified filter is valid | INVALID_FILTER | vkCmdBlitImage | TBD | NA | +| Verify Image Format Limits | Verifies that image creation parameters are with the device format limits | INVALID_FORMAT_LIMITS_VIOLATION | vkCreateImage | TBD | NA | | NA | Enum used for informational messages | NONE | | NA | None | ### Image Pending Work -- cgit v1.2.3