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 | |
Mark Lobodzinski | 688ed32 | 2017-01-27 11:13:21 -0700 | [diff] [blame] | 118 | if ((pCreateInfo->extent.width <= 0) || (pCreateInfo->extent.height <= 0) || (pCreateInfo->extent.depth <= 0)) { |
| 119 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, |
| 120 | VALIDATION_ERROR_00716, "Image", |
| 121 | "CreateImage extent is 0 for at least one required dimension for image: " |
| 122 | "Width = %d Height = %d Depth = %d. %s", |
| 123 | pCreateInfo->extent.width, pCreateInfo->extent.height, pCreateInfo->extent.depth, |
| 124 | validation_error_map[VALIDATION_ERROR_00716]); |
Mark Lobodzinski | 90224de | 2017-01-26 15:23:11 -0700 | [diff] [blame] | 125 | } |
| 126 | |
| 127 | // TODO: VALIDATION_ERROR_02125 VALIDATION_ERROR_02126 VALIDATION_ERROR_02128 VALIDATION_ERROR_00720 |
| 128 | // All these extent-related VUs should be checked here |
| 129 | if ((pCreateInfo->extent.depth > ImageFormatProperties.maxExtent.depth) || |
| 130 | (pCreateInfo->extent.width > ImageFormatProperties.maxExtent.width) || |
| 131 | (pCreateInfo->extent.height > ImageFormatProperties.maxExtent.height)) { |
| 132 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, |
| 133 | IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image", |
| 134 | "CreateImage extents exceed allowable limits for format: " |
| 135 | "Width = %d Height = %d Depth = %d: Limits for Width = %d Height = %d Depth = %d for format %s.", |
| 136 | pCreateInfo->extent.width, pCreateInfo->extent.height, pCreateInfo->extent.depth, |
| 137 | ImageFormatProperties.maxExtent.width, ImageFormatProperties.maxExtent.height, |
| 138 | ImageFormatProperties.maxExtent.depth, string_VkFormat(pCreateInfo->format)); |
| 139 | } |
| 140 | |
| 141 | uint64_t totalSize = ((uint64_t)pCreateInfo->extent.width * (uint64_t)pCreateInfo->extent.height * |
| 142 | (uint64_t)pCreateInfo->extent.depth * (uint64_t)pCreateInfo->arrayLayers * |
| 143 | (uint64_t)pCreateInfo->samples * (uint64_t)vk_format_get_size(pCreateInfo->format) + |
| 144 | (uint64_t)imageGranularity) & |
| 145 | ~(uint64_t)imageGranularity; |
| 146 | |
| 147 | if (totalSize > ImageFormatProperties.maxResourceSize) { |
| 148 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, |
| 149 | IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image", |
| 150 | "CreateImage resource size exceeds allowable maximum " |
| 151 | "Image resource size = 0x%" PRIxLEAST64 ", maximum resource size = 0x%" PRIxLEAST64 " ", |
| 152 | totalSize, ImageFormatProperties.maxResourceSize); |
| 153 | } |
| 154 | |
| 155 | // TODO: VALIDATION_ERROR_02132 |
| 156 | if (pCreateInfo->mipLevels > ImageFormatProperties.maxMipLevels) { |
| 157 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, |
| 158 | IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image", |
| 159 | "CreateImage mipLevels=%d exceeds allowable maximum supported by format of %d", pCreateInfo->mipLevels, |
| 160 | ImageFormatProperties.maxMipLevels); |
| 161 | } |
| 162 | |
| 163 | if (pCreateInfo->arrayLayers > ImageFormatProperties.maxArrayLayers) { |
| 164 | skip_call |= log_msg( |
| 165 | report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, VALIDATION_ERROR_02133, |
| 166 | "Image", "CreateImage arrayLayers=%d exceeds allowable maximum supported by format of %d. %s", pCreateInfo->arrayLayers, |
| 167 | ImageFormatProperties.maxArrayLayers, validation_error_map[VALIDATION_ERROR_02133]); |
| 168 | } |
| 169 | |
| 170 | if ((pCreateInfo->samples & ImageFormatProperties.sampleCounts) == 0) { |
| 171 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, |
| 172 | VALIDATION_ERROR_02138, "Image", "CreateImage samples %s is not supported by format 0x%.8X. %s", |
| 173 | string_VkSampleCountFlagBits(pCreateInfo->samples), ImageFormatProperties.sampleCounts, |
| 174 | validation_error_map[VALIDATION_ERROR_02138]); |
| 175 | } |
| 176 | |
| 177 | if (pCreateInfo->initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && pCreateInfo->initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) { |
| 178 | skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0, __LINE__, |
| 179 | VALIDATION_ERROR_00731, "Image", |
| 180 | "vkCreateImage parameter, pCreateInfo->initialLayout, must be VK_IMAGE_LAYOUT_UNDEFINED or " |
| 181 | "VK_IMAGE_LAYOUT_PREINITIALIZED. %s", |
| 182 | validation_error_map[VALIDATION_ERROR_00731]); |
| 183 | } |
| 184 | |
| 185 | return skip_call; |
| 186 | } |
| 187 | |
Mark Lobodzinski | 214144a | 2017-01-27 14:25:32 -0700 | [diff] [blame] | 188 | void PostCallRecordCreateImage(core_validation::layer_data *device_data, const VkImageCreateInfo *pCreateInfo, VkImage *pImage) { |
Mark Lobodzinski | 42fe5f7 | 2017-01-11 11:36:16 -0700 | [diff] [blame] | 189 | IMAGE_LAYOUT_NODE image_state; |
| 190 | image_state.layout = pCreateInfo->initialLayout; |
| 191 | image_state.format = pCreateInfo->format; |
Mark Lobodzinski | 214144a | 2017-01-27 14:25:32 -0700 | [diff] [blame] | 192 | GetImageMap(device_data)->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] | 193 | ImageSubresourcePair subpair{*pImage, false, VkImageSubresource()}; |
Mark Lobodzinski | 214144a | 2017-01-27 14:25:32 -0700 | [diff] [blame] | 194 | (*core_validation::GetImageSubresourceMap(device_data))[*pImage].push_back(subpair); |
| 195 | (*core_validation::GetImageLayoutMap(device_data))[subpair] = image_state; |
Mark Lobodzinski | 42fe5f7 | 2017-01-11 11:36:16 -0700 | [diff] [blame] | 196 | } |
Mark Lobodzinski | 9ef5d56 | 2017-01-27 12:28:30 -0700 | [diff] [blame] | 197 | |
| 198 | bool PreCallValidateDestroyImage(core_validation::layer_data *device_data, VkImage image, IMAGE_STATE **image_state, |
| 199 | VK_OBJECT *obj_struct) { |
| 200 | const CHECK_DISABLED *disabled = core_validation::GetDisables(device_data); |
| 201 | *image_state = core_validation::getImageState(device_data, image); |
| 202 | *obj_struct = {reinterpret_cast<uint64_t &>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT}; |
| 203 | if (disabled->destroy_image) return false; |
| 204 | bool skip = false; |
| 205 | if (*image_state) { |
| 206 | skip |= core_validation::ValidateObjectNotInUse(device_data, *image_state, *obj_struct, VALIDATION_ERROR_00743); |
| 207 | } |
| 208 | return skip; |
| 209 | } |
| 210 | |
| 211 | void PostCallRecordDestroyImage(core_validation::layer_data *device_data, VkImage image, IMAGE_STATE *image_state, |
| 212 | VK_OBJECT obj_struct) { |
| 213 | core_validation::invalidateCommandBuffers(device_data, image_state->cb_bindings, obj_struct); |
| 214 | // Clean up memory mapping, bindings and range references for image |
| 215 | for (auto mem_binding : image_state->GetBoundMemory()) { |
| 216 | auto mem_info = core_validation::getMemObjInfo(device_data, mem_binding); |
| 217 | if (mem_info) { |
| 218 | core_validation::RemoveImageMemoryRange(obj_struct.handle, mem_info); |
| 219 | } |
| 220 | } |
| 221 | core_validation::ClearMemoryObjectBindings(device_data, obj_struct.handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT); |
| 222 | // Remove image from imageMap |
| 223 | core_validation::GetImageMap(device_data)->erase(image); |
| 224 | std::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *imageSubresourceMap = |
| 225 | core_validation::GetImageSubresourceMap(device_data); |
| 226 | |
| 227 | const auto &sub_entry = imageSubresourceMap->find(image); |
| 228 | if (sub_entry != imageSubresourceMap->end()) { |
| 229 | for (const auto &pair : sub_entry->second) { |
| 230 | core_validation::GetImageLayoutMap(device_data)->erase(pair); |
| 231 | } |
| 232 | imageSubresourceMap->erase(sub_entry); |
| 233 | } |
| 234 | } |
Mark Lobodzinski | c409a58 | 2017-01-27 15:16:01 -0700 | [diff] [blame] | 235 | |
| 236 | bool ValidateImageAttributes(core_validation::layer_data *device_data, IMAGE_STATE *image_state, VkImageSubresourceRange range) { |
| 237 | bool skip = false; |
| 238 | const debug_report_data *report_data = core_validation::GetReportData(device_data); |
| 239 | |
| 240 | if (range.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) { |
| 241 | char const str[] = "vkCmdClearColorImage aspectMasks for all subresource ranges must be set to VK_IMAGE_ASPECT_COLOR_BIT"; |
| 242 | skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, |
| 243 | reinterpret_cast<uint64_t &>(image_state->image), __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "IMAGE", str); |
| 244 | } |
| 245 | |
| 246 | if (vk_format_is_depth_or_stencil(image_state->createInfo.format)) { |
| 247 | char const str[] = "vkCmdClearColorImage called with depth/stencil image."; |
| 248 | skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, |
| 249 | reinterpret_cast<uint64_t &>(image_state->image), __LINE__, VALIDATION_ERROR_01088, "IMAGE", "%s. %s", str, |
| 250 | validation_error_map[VALIDATION_ERROR_01088]); |
| 251 | } else if (vk_format_is_compressed(image_state->createInfo.format)) { |
| 252 | char const str[] = "vkCmdClearColorImage called with compressed image."; |
| 253 | skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, |
| 254 | reinterpret_cast<uint64_t &>(image_state->image), __LINE__, VALIDATION_ERROR_01088, "IMAGE", "%s. %s", str, |
| 255 | validation_error_map[VALIDATION_ERROR_01088]); |
| 256 | } |
| 257 | |
| 258 | if (!(image_state->createInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) { |
| 259 | char const str[] = "vkCmdClearColorImage called with image created without VK_IMAGE_USAGE_TRANSFER_DST_BIT."; |
| 260 | skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, |
| 261 | reinterpret_cast<uint64_t &>(image_state->image), __LINE__, VALIDATION_ERROR_01084, "IMAGE", "%s. %s", str, |
| 262 | validation_error_map[VALIDATION_ERROR_01084]); |
| 263 | } |
| 264 | return skip; |
| 265 | } |
Mark Lobodzinski | d81d101 | 2017-02-01 09:03:06 -0700 | [diff] [blame] | 266 | |
| 267 | void ResolveRemainingLevelsLayers(core_validation::layer_data *dev_data, VkImageSubresourceRange *range, VkImage image) { |
| 268 | // Expects global_lock to be held by caller |
| 269 | |
| 270 | auto image_state = getImageState(dev_data, image); |
| 271 | if (image_state) { |
| 272 | // If the caller used the special values VK_REMAINING_MIP_LEVELS and VK_REMAINING_ARRAY_LAYERS, resolve them now in our |
| 273 | // internal state to the actual values. |
| 274 | if (range->levelCount == VK_REMAINING_MIP_LEVELS) { |
| 275 | range->levelCount = image_state->createInfo.mipLevels - range->baseMipLevel; |
| 276 | } |
| 277 | |
| 278 | if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) { |
| 279 | range->layerCount = image_state->createInfo.arrayLayers - range->baseArrayLayer; |
| 280 | } |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | // Return the correct layer/level counts if the caller used the special values VK_REMAINING_MIP_LEVELS or VK_REMAINING_ARRAY_LAYERS. |
| 285 | void ResolveRemainingLevelsLayers(core_validation::layer_data *dev_data, uint32_t *levels, uint32_t *layers, |
| 286 | VkImageSubresourceRange range, VkImage image) { |
| 287 | // Expects global_lock to be held by caller |
| 288 | |
| 289 | *levels = range.levelCount; |
| 290 | *layers = range.layerCount; |
| 291 | auto image_state = getImageState(dev_data, image); |
| 292 | if (image_state) { |
| 293 | if (range.levelCount == VK_REMAINING_MIP_LEVELS) { |
| 294 | *levels = image_state->createInfo.mipLevels - range.baseMipLevel; |
| 295 | } |
| 296 | if (range.layerCount == VK_REMAINING_ARRAY_LAYERS) { |
| 297 | *layers = image_state->createInfo.arrayLayers - range.baseArrayLayer; |
| 298 | } |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | bool VerifyClearImageLayout(core_validation::layer_data *device_data, GLOBAL_CB_NODE *cb_node, VkImage image, |
| 303 | VkImageSubresourceRange range, VkImageLayout dest_image_layout, const char *func_name) { |
| 304 | bool skip = false; |
| 305 | const debug_report_data *report_data = core_validation::GetReportData(device_data); |
| 306 | |
| 307 | VkImageSubresourceRange resolved_range = range; |
| 308 | ResolveRemainingLevelsLayers(device_data, &resolved_range, image); |
| 309 | |
| 310 | if (dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { |
| 311 | if (dest_image_layout == VK_IMAGE_LAYOUT_GENERAL) { |
| 312 | auto image_state = getImageState(device_data, image); |
| 313 | if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) { |
| 314 | // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning. |
| 315 | skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, |
| 316 | __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", |
| 317 | "%s: Layout for cleared image should be TRANSFER_DST_OPTIMAL instead of GENERAL.", func_name); |
| 318 | } |
| 319 | } else { |
| 320 | UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_01086; |
| 321 | if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) { |
| 322 | error_code = VALIDATION_ERROR_01101; |
| 323 | } else { |
| 324 | assert(strcmp(func_name, "vkCmdClearColorImage()") == 0); |
| 325 | } |
| 326 | skip |= |
| 327 | log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, error_code, "DS", |
| 328 | "%s: Layout for cleared image is %s but can only be " |
| 329 | "TRANSFER_DST_OPTIMAL or GENERAL. %s", |
| 330 | func_name, string_VkImageLayout(dest_image_layout), validation_error_map[error_code]); |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | for (uint32_t level_index = 0; level_index < resolved_range.levelCount; ++level_index) { |
| 335 | uint32_t level = level_index + resolved_range.baseMipLevel; |
| 336 | for (uint32_t layer_index = 0; layer_index < resolved_range.layerCount; ++layer_index) { |
| 337 | uint32_t layer = layer_index + resolved_range.baseArrayLayer; |
| 338 | VkImageSubresource sub = {resolved_range.aspectMask, level, layer}; |
| 339 | IMAGE_CMD_BUF_LAYOUT_NODE node; |
| 340 | if (core_validation::FindLayout(cb_node, image, sub, node)) { |
| 341 | if (node.layout != dest_image_layout) { |
| 342 | UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_01085; |
| 343 | if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) { |
| 344 | error_code = VALIDATION_ERROR_01100; |
| 345 | } else { |
| 346 | assert(strcmp(func_name, "vkCmdClearColorImage()") == 0); |
| 347 | } |
| 348 | skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, |
| 349 | __LINE__, error_code, "DS", |
| 350 | "%s: Cannot clear an image whose layout is %s and " |
| 351 | "doesn't match the current layout %s. %s", |
| 352 | func_name, string_VkImageLayout(dest_image_layout), string_VkImageLayout(node.layout), |
| 353 | validation_error_map[error_code]); |
| 354 | } |
| 355 | } |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | return skip; |
| 360 | } |
| 361 | |
| 362 | void RecordClearImageLayout(core_validation::layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkImage image, |
| 363 | VkImageSubresourceRange range, VkImageLayout dest_image_layout) { |
| 364 | VkImageSubresourceRange resolved_range = range; |
| 365 | ResolveRemainingLevelsLayers(dev_data, &resolved_range, image); |
| 366 | |
| 367 | for (uint32_t level_index = 0; level_index < resolved_range.levelCount; ++level_index) { |
| 368 | uint32_t level = level_index + resolved_range.baseMipLevel; |
| 369 | for (uint32_t layer_index = 0; layer_index < resolved_range.layerCount; ++layer_index) { |
| 370 | uint32_t layer = layer_index + resolved_range.baseArrayLayer; |
| 371 | VkImageSubresource sub = {resolved_range.aspectMask, level, layer}; |
| 372 | IMAGE_CMD_BUF_LAYOUT_NODE node; |
| 373 | if (!core_validation::FindLayout(cb_node, image, sub, node)) { |
| 374 | SetLayout(cb_node, image, sub, IMAGE_CMD_BUF_LAYOUT_NODE(dest_image_layout, dest_image_layout)); |
| 375 | } |
| 376 | } |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | bool PreCallValidateCmdClearColorImage(core_validation::layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image, |
| 381 | VkImageLayout imageLayout, uint32_t rangeCount, const VkImageSubresourceRange *pRanges) { |
| 382 | bool skip = false; |
| 383 | // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state |
| 384 | auto cb_node = core_validation::getCBNode(dev_data, commandBuffer); |
| 385 | auto image_state = getImageState(dev_data, image); |
| 386 | if (cb_node && image_state) { |
| 387 | skip |= ValidateMemoryIsBoundToImage(dev_data, image_state, "vkCmdClearColorImage()", VALIDATION_ERROR_02527); |
| 388 | skip |= ValidateCmd(dev_data, cb_node, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()"); |
| 389 | skip |= insideRenderPass(dev_data, cb_node, "vkCmdClearColorImage()", VALIDATION_ERROR_01096); |
| 390 | for (uint32_t i = 0; i < rangeCount; ++i) { |
| 391 | skip |= ValidateImageAttributes(dev_data, image_state, pRanges[i]); |
| 392 | skip |= VerifyClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout, "vkCmdClearColorImage()"); |
| 393 | } |
| 394 | } |
| 395 | return skip; |
| 396 | } |
| 397 | |
| 398 | // This state recording routine is shared between ClearColorImage and ClearDepthStencilImage |
| 399 | void PreCallRecordCmdClearImage(core_validation::layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image, |
| 400 | VkImageLayout imageLayout, uint32_t rangeCount, const VkImageSubresourceRange *pRanges, |
| 401 | CMD_TYPE cmd_type) { |
| 402 | auto cb_node = getCBNode(dev_data, commandBuffer); |
| 403 | auto image_state = getImageState(dev_data, image); |
| 404 | if (cb_node && image_state) { |
| 405 | AddCommandBufferBindingImage(dev_data, cb_node, image_state); |
| 406 | std::function<bool()> function = [=]() { |
| 407 | SetImageMemoryValid(dev_data, image_state, true); |
| 408 | return false; |
| 409 | }; |
| 410 | cb_node->validate_functions.push_back(function); |
| 411 | UpdateCmdBufferLastCmd(dev_data, cb_node, cmd_type); |
| 412 | for (uint32_t i = 0; i < rangeCount; ++i) { |
| 413 | RecordClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout); |
| 414 | } |
| 415 | } |
| 416 | } |
| 417 | |
Mark Lobodzinski | 1241a31 | 2017-02-01 10:57:21 -0700 | [diff] [blame^] | 418 | bool PreCallValidateCmdClearDepthStencilImage(core_validation::layer_data *device_data, VkCommandBuffer commandBuffer, |
| 419 | VkImage image, VkImageLayout imageLayout, uint32_t rangeCount, |
Mark Lobodzinski | d81d101 | 2017-02-01 09:03:06 -0700 | [diff] [blame] | 420 | const VkImageSubresourceRange *pRanges) { |
| 421 | bool skip = false; |
Mark Lobodzinski | 1241a31 | 2017-02-01 10:57:21 -0700 | [diff] [blame^] | 422 | const debug_report_data *report_data = core_validation::GetReportData(device_data); |
| 423 | |
Mark Lobodzinski | d81d101 | 2017-02-01 09:03:06 -0700 | [diff] [blame] | 424 | // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state |
Mark Lobodzinski | 1241a31 | 2017-02-01 10:57:21 -0700 | [diff] [blame^] | 425 | auto cb_node = getCBNode(device_data, commandBuffer); |
| 426 | auto image_state = getImageState(device_data, image); |
Mark Lobodzinski | d81d101 | 2017-02-01 09:03:06 -0700 | [diff] [blame] | 427 | if (cb_node && image_state) { |
Mark Lobodzinski | 1241a31 | 2017-02-01 10:57:21 -0700 | [diff] [blame^] | 428 | skip |= ValidateMemoryIsBoundToImage(device_data, image_state, "vkCmdClearDepthStencilImage()", VALIDATION_ERROR_02528); |
| 429 | skip |= ValidateCmd(device_data, cb_node, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()"); |
| 430 | skip |= insideRenderPass(device_data, cb_node, "vkCmdClearDepthStencilImage()", VALIDATION_ERROR_01111); |
Mark Lobodzinski | d81d101 | 2017-02-01 09:03:06 -0700 | [diff] [blame] | 431 | for (uint32_t i = 0; i < rangeCount; ++i) { |
Mark Lobodzinski | 1241a31 | 2017-02-01 10:57:21 -0700 | [diff] [blame^] | 432 | skip |= VerifyClearImageLayout(device_data, cb_node, image, pRanges[i], imageLayout, "vkCmdClearDepthStencilImage()"); |
| 433 | // Image aspect must be depth or stencil or both |
| 434 | if (((pRanges[i].aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) && |
| 435 | ((pRanges[i].aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT)) { |
| 436 | char const str[] = |
| 437 | "vkCmdClearDepthStencilImage aspectMasks for all subresource ranges must be " |
| 438 | "set to VK_IMAGE_ASPECT_DEPTH_BIT and/or VK_IMAGE_ASPECT_STENCIL_BIT"; |
| 439 | skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, |
| 440 | (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "IMAGE", str); |
| 441 | } |
| 442 | } |
| 443 | if (image_state && !vk_format_is_depth_or_stencil(image_state->createInfo.format)) { |
| 444 | char const str[] = "vkCmdClearDepthStencilImage called without a depth/stencil image."; |
| 445 | skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, |
| 446 | reinterpret_cast<uint64_t &>(image), __LINE__, VALIDATION_ERROR_01103, "IMAGE", "%s. %s", str, |
| 447 | validation_error_map[VALIDATION_ERROR_01103]); |
Mark Lobodzinski | d81d101 | 2017-02-01 09:03:06 -0700 | [diff] [blame] | 448 | } |
| 449 | } |
| 450 | return skip; |
| 451 | } |