Mark Lobodzinski | d42e4d2 | 2017-01-17 14:14:22 -0700 | [diff] [blame] | 1 | /* Copyright (c) 2015-2017 The Khronos Group Inc. |
| 2 | * Copyright (c) 2015-2017 Valve Corporation |
| 3 | * Copyright (c) 2015-2017 LunarG, Inc. |
| 4 | * Copyright (C) 2015-2017 Google Inc. |
| 5 | * |
| 6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | * you may not use this file except in compliance with the License. |
| 8 | * You may obtain a copy of the License at |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, software |
| 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | * See the License for the specific language governing permissions and |
| 16 | * limitations under the License. |
| 17 | * |
| 18 | * Author: Mark Lobodzinski <mark@lunarg.com> |
| 19 | */ |
| 20 | |
| 21 | // Allow use of STL min and max functions in Windows |
| 22 | #define NOMINMAX |
| 23 | |
Mark Lobodzinski | 90224de | 2017-01-26 15:23:11 -0700 | [diff] [blame^] | 24 | #include <sstream> |
| 25 | |
| 26 | #include "vk_enum_string_helper.h" |
| 27 | #include "vk_layer_data.h" |
| 28 | #include "vk_layer_utils.h" |
| 29 | #include "vk_layer_logging.h" |
| 30 | |
| 31 | |
Mark Lobodzinski | d42e4d2 | 2017-01-17 14:14:22 -0700 | [diff] [blame] | 32 | #include "buffer_validation.h" |
Mark Lobodzinski | 42fe5f7 | 2017-01-11 11:36:16 -0700 | [diff] [blame] | 33 | |
Mark Lobodzinski | 90224de | 2017-01-26 15:23:11 -0700 | [diff] [blame^] | 34 | bool PreCallValidateCreateImage(core_validation::layer_data *device_data, const VkImageCreateInfo *pCreateInfo, |
| 35 | const VkAllocationCallbacks *pAllocator, VkImage *pImage) { |
| 36 | bool skip_call = false; |
| 37 | VkImageFormatProperties ImageFormatProperties; |
| 38 | const VkPhysicalDevice physical_device = core_validation::GetPhysicalDevice(device_data); |
| 39 | const debug_report_data *report_data = core_validation::GetReportData(device_data); |
| 40 | |
| 41 | if (pCreateInfo->format != VK_FORMAT_UNDEFINED) { |
| 42 | VkFormatProperties properties; |
| 43 | core_validation::GetFormatPropertiesPointer(device_data)(physical_device, pCreateInfo->format, &properties); |
| 44 | |
| 45 | if ((pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR) && (properties.linearTilingFeatures == 0)) { |
| 46 | std::stringstream ss; |
| 47 | ss << "vkCreateImage format parameter (" << string_VkFormat(pCreateInfo->format) << ") is an unsupported format"; |
| 48 | skip_call |= |
| 49 | log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, |
| 50 | VALIDATION_ERROR_02150, "IMAGE", "%s. %s", ss.str().c_str(), validation_error_map[VALIDATION_ERROR_02150]); |
| 51 | } |
| 52 | |
| 53 | if ((pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL) && (properties.optimalTilingFeatures == 0)) { |
| 54 | std::stringstream ss; |
| 55 | ss << "vkCreateImage format parameter (" << string_VkFormat(pCreateInfo->format) << ") is an unsupported format"; |
| 56 | skip_call |= |
| 57 | log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, |
| 58 | VALIDATION_ERROR_02155, "IMAGE", "%s. %s", ss.str().c_str(), validation_error_map[VALIDATION_ERROR_02155]); |
| 59 | } |
| 60 | |
| 61 | // Validate that format supports usage as color attachment |
| 62 | if (pCreateInfo->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { |
| 63 | if ((pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL) && |
| 64 | ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0)) { |
| 65 | std::stringstream ss; |
| 66 | ss << "vkCreateImage: VkFormat for TILING_OPTIMAL image (" << string_VkFormat(pCreateInfo->format) |
| 67 | << ") does not support requested Image usage type VK_IMAGE_USAGE_COLOR_ATTACHMENT"; |
| 68 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, |
| 69 | __LINE__, VALIDATION_ERROR_02158, "IMAGE", "%s. %s", ss.str().c_str(), |
| 70 | validation_error_map[VALIDATION_ERROR_02158]); |
| 71 | } |
| 72 | if ((pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR) && |
| 73 | ((properties.linearTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0)) { |
| 74 | std::stringstream ss; |
| 75 | ss << "vkCreateImage: VkFormat for TILING_LINEAR image (" << string_VkFormat(pCreateInfo->format) |
| 76 | << ") does not support requested Image usage type VK_IMAGE_USAGE_COLOR_ATTACHMENT"; |
| 77 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, |
| 78 | __LINE__, VALIDATION_ERROR_02153, "IMAGE", "%s. %s", ss.str().c_str(), |
| 79 | validation_error_map[VALIDATION_ERROR_02153]); |
| 80 | } |
| 81 | } |
| 82 | // Validate that format supports usage as depth/stencil attachment |
| 83 | if (pCreateInfo->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
| 84 | if ((pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL) && |
| 85 | ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0)) { |
| 86 | std::stringstream ss; |
| 87 | ss << "vkCreateImage: VkFormat for TILING_OPTIMAL image (" << string_VkFormat(pCreateInfo->format) |
| 88 | << ") does not support requested Image usage type VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT"; |
| 89 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, |
| 90 | __LINE__, VALIDATION_ERROR_02159, "IMAGE", "%s. %s", ss.str().c_str(), |
| 91 | validation_error_map[VALIDATION_ERROR_02159]); |
| 92 | } |
| 93 | if ((pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR) && |
| 94 | ((properties.linearTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0)) { |
| 95 | std::stringstream ss; |
| 96 | ss << "vkCreateImage: VkFormat for TILING_LINEAR image (" << string_VkFormat(pCreateInfo->format) |
| 97 | << ") does not support requested Image usage type VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT"; |
| 98 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, |
| 99 | __LINE__, VALIDATION_ERROR_02154, "IMAGE", "%s. %s", ss.str().c_str(), |
| 100 | validation_error_map[VALIDATION_ERROR_02154]); |
| 101 | } |
| 102 | } |
| 103 | } else { |
| 104 | skip_call |= |
| 105 | log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, |
| 106 | VALIDATION_ERROR_00715, "IMAGE", "vkCreateImage: VkFormat for image must not be VK_FORMAT_UNDEFINED. %s", |
| 107 | validation_error_map[VALIDATION_ERROR_00715]); |
| 108 | } |
| 109 | |
| 110 | // Internal call to get format info. Still goes through layers, could potentially go directly to ICD. |
| 111 | core_validation::GetImageFormatPropertiesPointer(device_data)(physical_device, pCreateInfo->format, pCreateInfo->imageType, |
| 112 | pCreateInfo->tiling, pCreateInfo->usage, pCreateInfo->flags, |
| 113 | &ImageFormatProperties); |
| 114 | |
| 115 | VkDeviceSize imageGranularity = core_validation::GetPhysicalDeviceProperties(device_data)->limits.bufferImageGranularity; |
| 116 | imageGranularity = imageGranularity == 1 ? 0 : imageGranularity; |
| 117 | |
| 118 | // Make sure all required dimension are non-zero at least. |
| 119 | bool failedMinSize = false; |
| 120 | switch (pCreateInfo->imageType) { |
| 121 | case VK_IMAGE_TYPE_3D: |
| 122 | if (pCreateInfo->extent.depth == 0) { |
| 123 | failedMinSize = true; |
| 124 | } |
| 125 | // Intentional fall-through |
| 126 | case VK_IMAGE_TYPE_2D: |
| 127 | if (pCreateInfo->extent.height == 0) { |
| 128 | failedMinSize = true; |
| 129 | } |
| 130 | // Intentional fall-through |
| 131 | case VK_IMAGE_TYPE_1D: |
| 132 | if (pCreateInfo->extent.width == 0) { |
| 133 | failedMinSize = true; |
| 134 | } |
| 135 | break; |
| 136 | default: |
| 137 | break; |
| 138 | } |
| 139 | // TODO: VALIDATION_ERROR_00716 |
| 140 | // this is *almost* VU 00716, except should not be condidtional on image type - all extents must be non-zero for all types |
| 141 | if (failedMinSize) { |
| 142 | skip_call |= |
| 143 | log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, |
| 144 | IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image", |
| 145 | "CreateImage extents is 0 for at least one required dimension for image of type %d: " |
| 146 | "Width = %d Height = %d Depth = %d.", |
| 147 | pCreateInfo->imageType, pCreateInfo->extent.width, pCreateInfo->extent.height, pCreateInfo->extent.depth); |
| 148 | } |
| 149 | |
| 150 | // TODO: VALIDATION_ERROR_02125 VALIDATION_ERROR_02126 VALIDATION_ERROR_02128 VALIDATION_ERROR_00720 |
| 151 | // All these extent-related VUs should be checked here |
| 152 | if ((pCreateInfo->extent.depth > ImageFormatProperties.maxExtent.depth) || |
| 153 | (pCreateInfo->extent.width > ImageFormatProperties.maxExtent.width) || |
| 154 | (pCreateInfo->extent.height > ImageFormatProperties.maxExtent.height)) { |
| 155 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, |
| 156 | IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image", |
| 157 | "CreateImage extents exceed allowable limits for format: " |
| 158 | "Width = %d Height = %d Depth = %d: Limits for Width = %d Height = %d Depth = %d for format %s.", |
| 159 | pCreateInfo->extent.width, pCreateInfo->extent.height, pCreateInfo->extent.depth, |
| 160 | ImageFormatProperties.maxExtent.width, ImageFormatProperties.maxExtent.height, |
| 161 | ImageFormatProperties.maxExtent.depth, string_VkFormat(pCreateInfo->format)); |
| 162 | } |
| 163 | |
| 164 | uint64_t totalSize = ((uint64_t)pCreateInfo->extent.width * (uint64_t)pCreateInfo->extent.height * |
| 165 | (uint64_t)pCreateInfo->extent.depth * (uint64_t)pCreateInfo->arrayLayers * |
| 166 | (uint64_t)pCreateInfo->samples * (uint64_t)vk_format_get_size(pCreateInfo->format) + |
| 167 | (uint64_t)imageGranularity) & |
| 168 | ~(uint64_t)imageGranularity; |
| 169 | |
| 170 | if (totalSize > ImageFormatProperties.maxResourceSize) { |
| 171 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, |
| 172 | IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image", |
| 173 | "CreateImage resource size exceeds allowable maximum " |
| 174 | "Image resource size = 0x%" PRIxLEAST64 ", maximum resource size = 0x%" PRIxLEAST64 " ", |
| 175 | totalSize, ImageFormatProperties.maxResourceSize); |
| 176 | } |
| 177 | |
| 178 | // TODO: VALIDATION_ERROR_02132 |
| 179 | if (pCreateInfo->mipLevels > ImageFormatProperties.maxMipLevels) { |
| 180 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, |
| 181 | IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image", |
| 182 | "CreateImage mipLevels=%d exceeds allowable maximum supported by format of %d", pCreateInfo->mipLevels, |
| 183 | ImageFormatProperties.maxMipLevels); |
| 184 | } |
| 185 | |
| 186 | if (pCreateInfo->arrayLayers > ImageFormatProperties.maxArrayLayers) { |
| 187 | skip_call |= log_msg( |
| 188 | report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, VALIDATION_ERROR_02133, |
| 189 | "Image", "CreateImage arrayLayers=%d exceeds allowable maximum supported by format of %d. %s", pCreateInfo->arrayLayers, |
| 190 | ImageFormatProperties.maxArrayLayers, validation_error_map[VALIDATION_ERROR_02133]); |
| 191 | } |
| 192 | |
| 193 | if ((pCreateInfo->samples & ImageFormatProperties.sampleCounts) == 0) { |
| 194 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, |
| 195 | VALIDATION_ERROR_02138, "Image", "CreateImage samples %s is not supported by format 0x%.8X. %s", |
| 196 | string_VkSampleCountFlagBits(pCreateInfo->samples), ImageFormatProperties.sampleCounts, |
| 197 | validation_error_map[VALIDATION_ERROR_02138]); |
| 198 | } |
| 199 | |
| 200 | if (pCreateInfo->initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && pCreateInfo->initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) { |
| 201 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, |
| 202 | VALIDATION_ERROR_00731, "Image", |
| 203 | "vkCreateImage parameter, pCreateInfo->initialLayout, must be VK_IMAGE_LAYOUT_UNDEFINED or " |
| 204 | "VK_IMAGE_LAYOUT_PREINITIALIZED. %s", |
| 205 | validation_error_map[VALIDATION_ERROR_00731]); |
| 206 | } |
| 207 | |
| 208 | return skip_call; |
| 209 | } |
| 210 | |
Mark Lobodzinski | bf93db7 | 2017-01-17 16:24:29 -0700 | [diff] [blame] | 211 | void PostCallRecordCreateImage(std::unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>> *imageMap, |
| 212 | std::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *imageSubresourceMap, |
| 213 | std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> *imageLayoutMap, |
| 214 | const VkImageCreateInfo *pCreateInfo, VkImage *pImage) { |
Mark Lobodzinski | 42fe5f7 | 2017-01-11 11:36:16 -0700 | [diff] [blame] | 215 | IMAGE_LAYOUT_NODE image_state; |
| 216 | image_state.layout = pCreateInfo->initialLayout; |
| 217 | image_state.format = pCreateInfo->format; |
Mark Lobodzinski | bf93db7 | 2017-01-17 16:24:29 -0700 | [diff] [blame] | 218 | (*imageMap).insert(std::make_pair(*pImage, std::unique_ptr<IMAGE_STATE>(new IMAGE_STATE(*pImage, pCreateInfo)))); |
Mark Lobodzinski | 42fe5f7 | 2017-01-11 11:36:16 -0700 | [diff] [blame] | 219 | ImageSubresourcePair subpair{*pImage, false, VkImageSubresource()}; |
Mark Lobodzinski | bf93db7 | 2017-01-17 16:24:29 -0700 | [diff] [blame] | 220 | (*imageSubresourceMap)[*pImage].push_back(subpair); |
| 221 | (*imageLayoutMap)[subpair] = image_state; |
Mark Lobodzinski | 42fe5f7 | 2017-01-11 11:36:16 -0700 | [diff] [blame] | 222 | } |