| /* Copyright (c) 2015-2026 The Khronos Group Inc. |
| * Copyright (c) 2015-2026 Valve Corporation |
| * Copyright (c) 2015-2026 LunarG, Inc. |
| * Copyright (C) 2015-2026 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <vulkan/vk_enum_string_helper.h> |
| #include <vulkan/utility/vk_format_utils.h> |
| #include <vulkan/vulkan_core.h> |
| #include "error_message/error_strings.h" |
| #include "stateless/stateless_validation.h" |
| #include "generated/enum_flag_bits.h" |
| #include "containers/container_utils.h" |
| #include "utils/math_utils.h" |
| #include "utils/image_utils.h" |
| #include <cmath> |
| |
| namespace stateless { |
| |
| bool Device::manual_PreCallValidateCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, VkImage *pImage, |
| const Context &context) const { |
| bool skip = false; |
| const auto &error_obj = context.error_obj; |
| |
| if (pCreateInfo == nullptr) { |
| return skip; |
| } |
| const Location create_info_loc = error_obj.location.dot(Field::pCreateInfo); |
| if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) { |
| auto const queue_family_index_count = pCreateInfo->queueFamilyIndexCount; |
| if (queue_family_index_count <= 1) { |
| skip |= LogError("VUID-VkImageCreateInfo-sharingMode-00942", device, create_info_loc.dot(Field::queueFamilyIndexCount), |
| "is %" PRIu32 ".", queue_family_index_count); |
| } |
| |
| if (pCreateInfo->pQueueFamilyIndices == nullptr) { |
| skip |= LogError("VUID-VkImageCreateInfo-sharingMode-00941", device, create_info_loc.dot(Field::pQueueFamilyIndices), |
| "is NULL."); |
| } |
| } |
| |
| skip |= context.ValidateNotZero(pCreateInfo->extent.width == 0, "VUID-VkImageCreateInfo-extent-00944", |
| create_info_loc.dot(Field::extent).dot(Field::width)); |
| skip |= context.ValidateNotZero(pCreateInfo->extent.height == 0, "VUID-VkImageCreateInfo-extent-00945", |
| create_info_loc.dot(Field::extent).dot(Field::height)); |
| skip |= context.ValidateNotZero(pCreateInfo->extent.depth == 0, "VUID-VkImageCreateInfo-extent-00946", |
| create_info_loc.dot(Field::extent).dot(Field::depth)); |
| |
| skip |= context.ValidateNotZero(pCreateInfo->mipLevels == 0, "VUID-VkImageCreateInfo-mipLevels-00947", |
| create_info_loc.dot(Field::mipLevels)); |
| skip |= context.ValidateNotZero(pCreateInfo->arrayLayers == 0, "VUID-VkImageCreateInfo-arrayLayers-00948", |
| create_info_loc.dot(Field::arrayLayers)); |
| |
| if (!IsValueIn(pCreateInfo->initialLayout, |
| {VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_ZERO_INITIALIZED_EXT})) { |
| skip |= LogError("VUID-VkImageCreateInfo-initialLayout-00993", device, create_info_loc.dot(Field::initialLayout), |
| "is %s, but must be UNDEFINED or PREINITIALIZED or ZERO_INITIALIZED.", |
| string_VkImageLayout(pCreateInfo->initialLayout)); |
| } else if (pCreateInfo->initialLayout == VK_IMAGE_LAYOUT_ZERO_INITIALIZED_EXT) { |
| if (!enabled_features.zeroInitializeDeviceMemory) { |
| skip |= LogError("VUID-VkImageCreateInfo-initialLayout-10765", device, create_info_loc.dot(Field::initialLayout), |
| "is VK_IMAGE_LAYOUT_ZERO_INITIALIZED_EXT but the zeroInitializeDeviceMemory feature was not enabled."); |
| } |
| } |
| |
| if ((pCreateInfo->imageType == VK_IMAGE_TYPE_1D) && ((pCreateInfo->extent.height != 1) || (pCreateInfo->extent.depth != 1))) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageType-00956", device, create_info_loc.dot(Field::imageType), |
| "is VK_IMAGE_TYPE_1D but extent.height (%" PRIu32 ") and extent.depth (%" PRIu32 ") must both be 1.", |
| pCreateInfo->extent.height, pCreateInfo->extent.depth); |
| } |
| |
| if (pCreateInfo->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) { |
| if (pCreateInfo->imageType != VK_IMAGE_TYPE_2D) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-00949", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT but imageType (%s) is not VK_IMAGE_TYPE_2D.", |
| string_VkImageType(pCreateInfo->imageType)); |
| } |
| |
| if (pCreateInfo->extent.width != pCreateInfo->extent.height) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-08865", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT but extent.width (%" PRIu32 |
| ") is not equal to extent.height (%" PRIu32 ").", |
| pCreateInfo->extent.width, pCreateInfo->extent.height); |
| } |
| |
| if (pCreateInfo->arrayLayers < 6) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-08866", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT but arrayLayers (%" PRIu32 ") is less than 6.", |
| pCreateInfo->arrayLayers); |
| } |
| } |
| |
| if (pCreateInfo->imageType == VK_IMAGE_TYPE_2D) { |
| if (pCreateInfo->extent.depth != 1) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageType-00957", device, create_info_loc.dot(Field::imageType), |
| "is VK_IMAGE_TYPE_2D but extent.depth (%" PRIu32 ") must be 1.", pCreateInfo->extent.depth); |
| } |
| } |
| |
| if ((pCreateInfo->imageType == VK_IMAGE_TYPE_3D) && (pCreateInfo->arrayLayers != 1)) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageType-00961", device, create_info_loc.dot(Field::imageType), |
| "is VK_IMAGE_TYPE_3D but arrayLayers (%" PRIu32 ") must be 1.", pCreateInfo->arrayLayers); |
| } |
| |
| if (0 != (pCreateInfo->usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT)) { |
| VkImageUsageFlags legal_flags = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | |
| VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT); |
| if (0 == (pCreateInfo->usage & legal_flags)) { |
| skip |= LogError("VUID-VkImageCreateInfo-usage-00966", device, create_info_loc.dot(Field::usage), |
| "(%s) includes VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT but is missing one of %s.", |
| string_VkImageUsageFlags(pCreateInfo->usage).c_str(), string_VkImageUsageFlags(legal_flags).c_str()); |
| } |
| legal_flags |= VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT; |
| if (0 != (pCreateInfo->usage & ~legal_flags)) { |
| skip |= LogError("VUID-VkImageCreateInfo-usage-00963", device, create_info_loc, |
| "(%s) includes VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT so it can't include %s.", |
| string_VkImageUsageFlags(pCreateInfo->usage).c_str(), |
| string_VkImageUsageFlags(pCreateInfo->usage & ~legal_flags).c_str()); |
| } |
| } |
| |
| const VkImageCreateFlags image_flags = pCreateInfo->flags; |
| // mipLevels must be less than or equal to the number of levels in the complete mipmap chain |
| uint32_t max_dim = std::max(std::max(pCreateInfo->extent.width, pCreateInfo->extent.height), pCreateInfo->extent.depth); |
| // Max mip levels is different for corner-sampled images vs normal images. |
| uint32_t max_mip_levels = (image_flags & VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV) |
| ? static_cast<uint32_t>(ceil(log2(max_dim))) |
| : static_cast<uint32_t>(floor(log2(max_dim)) + 1); |
| if (max_dim > 0 && pCreateInfo->mipLevels > max_mip_levels) { |
| skip |= LogError("VUID-VkImageCreateInfo-mipLevels-00958", device, create_info_loc.dot(Field::mipLevels), |
| "(%" PRIu32 ") must be less than or equal to %" PRIu32 " (based on extent of %s)", pCreateInfo->mipLevels, |
| max_mip_levels, string_VkExtent3D(pCreateInfo->extent).c_str()); |
| } |
| |
| if ((image_flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT) && (pCreateInfo->imageType != VK_IMAGE_TYPE_3D)) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-00950", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT but " |
| "imageType is %s.", |
| string_VkImageType(pCreateInfo->imageType)); |
| } |
| |
| if ((image_flags & VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT) && (pCreateInfo->imageType != VK_IMAGE_TYPE_3D)) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-07755", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT but " |
| "imageType is %s.", |
| string_VkImageType(pCreateInfo->imageType)); |
| } |
| |
| skip |= ValidateCreateImageSparse(*pCreateInfo, create_info_loc); |
| skip |= ValidateCreateImageFragmentShadingRate(*pCreateInfo, create_info_loc); |
| skip |= ValidateCreateImageCornerSampled(*pCreateInfo, create_info_loc); |
| skip |= ValidateCreateImageStencilUsage(*pCreateInfo, create_info_loc); |
| skip |= ValidateCreateImageCompressionControl(context, *pCreateInfo, create_info_loc); |
| skip |= ValidateCreateImageSwapchain(*pCreateInfo, create_info_loc); |
| skip |= ValidateCreateImageFormatList(*pCreateInfo, create_info_loc); |
| skip |= ValidateCreateImageMetalObject(*pCreateInfo, create_info_loc); |
| |
| std::vector<uint64_t> image_create_drm_format_modifiers; |
| skip |= ValidateCreateImageDrmFormatModifiers(*pCreateInfo, create_info_loc, image_create_drm_format_modifiers); |
| |
| const VkFormat image_format = pCreateInfo->format; |
| if (((image_flags & VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT) != 0) && |
| (vkuFormatHasDepth(image_format) == false)) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-01533", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT but the " |
| "format (%s) must be a depth or depth/stencil format.", |
| string_VkFormat(image_format)); |
| } |
| |
| if ((!enabled_features.shaderStorageImageMultisample) && ((pCreateInfo->usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0) && |
| (pCreateInfo->samples != VK_SAMPLE_COUNT_1_BIT)) { |
| skip |= LogError("VUID-VkImageCreateInfo-usage-00968", device, create_info_loc.dot(Field::usage), |
| "includes VK_IMAGE_USAGE_STORAGE_BIT and imageType is %s, but shaderStorageImageMultisample feature " |
| "was not enabled.", |
| string_VkSampleCountFlagBits(pCreateInfo->samples)); |
| } |
| |
| if (!enabled_features.hostImageCopy && (pCreateInfo->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT) != 0) { |
| skip |= LogError("VUID-VkImageCreateInfo-usage-10245", device, create_info_loc.dot(Field::usage), |
| "includes VK_IMAGE_USAGE_HOST_TRANSFER_BIT, but hostImageCopy feature was not enabled."); |
| } |
| |
| if (!enabled_features.tileMemoryHeap && (pCreateInfo->usage & VK_IMAGE_USAGE_TILE_MEMORY_BIT_QCOM) != 0) { |
| skip |= LogError("VUID-VkImageCreateInfo-tileMemoryHeap-10766", device, create_info_loc.dot(Field::usage), |
| "includes VK_IMAGE_USAGE_TILE_MEMORY_BIT_QCOM, but tileMemoryHeap feature was not enabled."); |
| } |
| |
| static const uint64_t drm_format_mod_linear = 0; |
| bool image_create_maybe_linear = false; |
| if (pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR) { |
| image_create_maybe_linear = true; |
| } else if (pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL) { |
| image_create_maybe_linear = false; |
| } else if (pCreateInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) { |
| image_create_maybe_linear = (std::find(image_create_drm_format_modifiers.begin(), image_create_drm_format_modifiers.end(), |
| drm_format_mod_linear) != image_create_drm_format_modifiers.end()); |
| } |
| |
| // If multi-sample, validate type, usage, tiling and mip levels. |
| if (pCreateInfo->samples != VK_SAMPLE_COUNT_1_BIT) { |
| if (pCreateInfo->imageType != VK_IMAGE_TYPE_2D) { |
| skip |= LogError("VUID-VkImageCreateInfo-samples-02257", device, create_info_loc.dot(Field::samples), |
| "is %s and imageType is %s, but when not VK_SAMPLE_COUNT_1_BIT the imageType must be VK_IMAGE_TYPE_2D", |
| string_VkSampleCountFlagBits(pCreateInfo->samples), string_VkImageType(pCreateInfo->imageType)); |
| } else if (image_flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) { |
| skip |= |
| LogError("VUID-VkImageCreateInfo-samples-02257", device, create_info_loc.dot(Field::samples), |
| "is %s, but when not VK_SAMPLE_COUNT_1_BIT the flags must not contain VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT", |
| string_VkSampleCountFlagBits(pCreateInfo->samples)); |
| } else if (pCreateInfo->mipLevels != 1) { |
| skip |= LogError("VUID-VkImageCreateInfo-samples-02257", device, create_info_loc.dot(Field::samples), |
| "is %s and mipLevels is %" PRIu32 ", but when not VK_SAMPLE_COUNT_1_BIT the mipLevels must be 1", |
| string_VkSampleCountFlagBits(pCreateInfo->samples), pCreateInfo->mipLevels); |
| } else if (image_create_maybe_linear) { |
| skip |= |
| LogError("VUID-VkImageCreateInfo-samples-02257", device, create_info_loc.dot(Field::samples), |
| "is %s, but when not VK_SAMPLE_COUNT_1_BIT the tiling must not be %s", |
| string_VkSampleCountFlagBits(pCreateInfo->samples), |
| (pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR) ? "VK_IMAGE_TILING_LINEAR" |
| : "linear from VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT"); |
| } |
| } |
| |
| if (image_flags & VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT) { |
| if (pCreateInfo->mipLevels != 1) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-02259", device, create_info_loc.dot(Field::flags), |
| "contains VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT but mipLevels (%" PRIu32 ") is not 1", |
| pCreateInfo->mipLevels); |
| } else if (pCreateInfo->arrayLayers != 1) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-02259", device, create_info_loc.dot(Field::flags), |
| "contains VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT but arrayLayers (%" PRIu32 ") is not 1", |
| pCreateInfo->arrayLayers); |
| } else if (pCreateInfo->imageType != VK_IMAGE_TYPE_2D) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-02259", device, create_info_loc.dot(Field::flags), |
| "contains VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT but imageType (%s) is not VK_IMAGE_TYPE_2D", |
| string_VkImageType(pCreateInfo->imageType)); |
| } else if (image_create_maybe_linear) { |
| skip |= |
| LogError("VUID-VkImageCreateInfo-flags-02259", device, create_info_loc.dot(Field::flags), |
| "contains VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT but tiling must not be %s", |
| (pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR) ? "VK_IMAGE_TILING_LINEAR" |
| : "linear from VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT"); |
| } |
| } |
| |
| if (pCreateInfo->usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) { |
| if (pCreateInfo->imageType != VK_IMAGE_TYPE_2D) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-02557", device, create_info_loc.dot(Field::usage), |
| "includes VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT, but imageType is %s.", |
| string_VkImageType(pCreateInfo->imageType)); |
| } |
| if (pCreateInfo->samples != VK_SAMPLE_COUNT_1_BIT) { |
| skip |= LogError("VUID-VkImageCreateInfo-samples-02558", device, create_info_loc.dot(Field::usage), |
| "includes VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT, but samples is %s.", |
| string_VkSampleCountFlagBits(pCreateInfo->samples)); |
| } |
| } |
| if (image_flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) { |
| if (pCreateInfo->tiling != VK_IMAGE_TILING_OPTIMAL) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-02565", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT, but tiling is %s.", |
| string_VkImageTiling(pCreateInfo->tiling)); |
| } |
| if (pCreateInfo->imageType != VK_IMAGE_TYPE_2D) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-02566", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT, but imageType is %s.", |
| string_VkImageType(pCreateInfo->imageType)); |
| } |
| if (image_flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-02567", device, create_info_loc.dot(Field::flags), |
| "(%s) contains both VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT and VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT.", |
| string_VkImageCreateFlags(image_flags).c_str()); |
| } |
| if (pCreateInfo->mipLevels != 1) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-02568", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT, but mipLevels is %" PRIu32 ".", pCreateInfo->mipLevels); |
| } |
| } |
| |
| if (image_flags & VK_IMAGE_CREATE_PROTECTED_BIT) { |
| if (enabled_features.protectedMemory == VK_FALSE) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-01890", device, create_info_loc.dot(Field::flags), |
| "has VK_IMAGE_CREATE_PROTECTED_BIT set, but the protectedMemory device feature is not enabled."); |
| } |
| const VkImageCreateFlags invalid_flags = |
| VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT; |
| if ((pCreateInfo->flags & invalid_flags) != 0) { |
| skip |= LogError("VUID-VkImageCreateInfo-None-01891", device, create_info_loc.dot(Field::flags), |
| "can't have both protected and sparse flags set."); |
| } |
| } |
| |
| if (image_flags & VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT) { |
| if (!(enabled_features.multisampledRenderToSingleSampled)) { |
| skip |= LogError("VUID-VkImageCreateInfo-multisampledRenderToSingleSampled-06882", device, |
| create_info_loc.dot(Field::flags), |
| "contains VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT but the " |
| "multisampledRenderToSingleSampled feature is not enabled."); |
| } |
| if (pCreateInfo->samples != VK_SAMPLE_COUNT_1_BIT) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-06883", device, create_info_loc.dot(Field::flags), |
| "contains VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT but samples (%s) is not equal " |
| "to VK_SAMPLE_COUNT_1_BIT.", |
| string_VkSampleCountFlagBits(pCreateInfo->samples)); |
| } |
| } |
| |
| if ((image_flags & VK_IMAGE_CREATE_DESCRIPTOR_HEAP_CAPTURE_REPLAY_BIT_EXT) && !enabled_features.descriptorHeapCaptureReplay && |
| !enabled_features.descriptorBufferCaptureReplay) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-08104", device, create_info_loc.dot(Field::flags), |
| "contains VK_IMAGE_CREATE_DESCRIPTOR_HEAP_CAPTURE_REPLAY_BIT_EXT but neither descriptorHeapCaptureReplay " |
| "nor descriptorBufferCaptureReplay " |
| "feature is not enabled."); |
| } |
| |
| auto opaque_capture_descriptor_buffer = |
| vku::FindStructInPNextChain<VkOpaqueCaptureDescriptorDataCreateInfoEXT>(pCreateInfo->pNext); |
| if (opaque_capture_descriptor_buffer && !(image_flags & VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT)) { |
| skip |= LogError("VUID-VkImageCreateInfo-pNext-08105", device, create_info_loc.dot(Field::flags), |
| "(%s) does not have VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT, but " |
| "VkOpaqueCaptureDescriptorDataCreateInfoEXT is in pNext chain.\n%s", |
| string_VkImageCreateFlags(image_flags).c_str(), |
| PrintPNextChain(Struct::VkImageCreateInfo, pCreateInfo->pNext).c_str()); |
| } |
| |
| // Check compatibility with VK_KHR_portability_subset |
| if (IsExtEnabled(extensions.vk_khr_portability_subset)) { |
| if (VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT & image_flags && VK_FALSE == enabled_features.imageView2DOn3DImage) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageView2DOn3DImage-04459", device, create_info_loc, |
| "(portability error) VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT is not supported."); |
| } |
| if ((VK_SAMPLE_COUNT_1_BIT != pCreateInfo->samples) && (1 != pCreateInfo->arrayLayers) && |
| (VK_FALSE == enabled_features.multisampleArrayImage)) { |
| skip |= LogError("VUID-VkImageCreateInfo-multisampleArrayImage-04460", device, create_info_loc, |
| "(portability error) Cannot create an image with samples/texel > 1 && arrayLayers != 1"); |
| } |
| } |
| |
| // If Chroma subsampled format ( _420_ or _422_ ) |
| if (vkuFormatIsXChromaSubsampled(image_format) && !IsIntegerMultipleOf(pCreateInfo->extent.width, 2)) { |
| skip |= |
| LogError("VUID-VkImageCreateInfo-format-04712", device, create_info_loc.dot(Field::format), |
| "(%s) is X Chroma Subsampled (has _422 or _420 suffix) so the width (%" PRIu32 ") must be a multiple of 2.", |
| string_VkFormat(image_format), pCreateInfo->extent.width); |
| } |
| if (vkuFormatIsYChromaSubsampled(image_format) && !IsIntegerMultipleOf(pCreateInfo->extent.height, 2)) { |
| skip |= LogError("VUID-VkImageCreateInfo-format-04713", device, create_info_loc.dot(Field::format), |
| "(%s) is Y Chroma Subsampled (has _420 suffix) so the height (%" PRIu32 ") must be a multiple of 2.", |
| string_VkFormat(image_format), pCreateInfo->extent.height); |
| } |
| if (api_version < VK_API_VERSION_1_3 && !enabled_features.ycbcr2plane444Formats) { |
| if (IsValueIn(image_format, {VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, |
| VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, VK_FORMAT_G16_B16R16_2PLANE_444_UNORM})) { |
| skip |= LogError("VUID-VkImageCreateInfo-None-12279", device, create_info_loc.dot(Field::format), "is %s.", |
| string_VkFormat(image_format)); |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateCreateImageSparse(const VkImageCreateInfo &create_info, const Location &create_info_loc) const { |
| bool skip = false; |
| const VkImageCreateFlags image_flags = create_info.flags; |
| const VkImageCreateFlags sparse_flags = |
| VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT; |
| const bool has_sparse_flags = (image_flags & sparse_flags) != 0; |
| |
| if (has_sparse_flags) { |
| if (create_info.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) { |
| skip |= LogError("VUID-VkImageCreateInfo-None-01925", device, create_info_loc, |
| "images using sparse memory cannot have VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT set. (image flags %s)", |
| string_VkImageCreateFlags(image_flags).c_str()); |
| } |
| if ((!enabled_features.maintenance9 || !phys_dev_ext_props.maintenance9_props.image2DViewOf3DSparse) && |
| image_flags & VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageType-10197", device, create_info_loc.dot(Field::flags), "is %s.", |
| string_VkImageCreateFlags(image_flags).c_str()); |
| } |
| if (image_flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-09403", device, create_info_loc.dot(Field::flags), "is %s.", |
| string_VkImageCreateFlags(image_flags).c_str()); |
| } |
| } |
| |
| if ((image_flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) && (!enabled_features.sparseBinding)) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-00969", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SPARSE_BINDING_BIT, but the " |
| "sparseBinding feature was not enabled."); |
| } |
| |
| if ((image_flags & VK_IMAGE_CREATE_SPARSE_ALIASED_BIT) && (!enabled_features.sparseResidencyAliased)) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-01924", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SPARSE_ALIASED_BIT but the sparseResidencyAliased feature was not enabled."); |
| } |
| |
| if (((image_flags & (VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT)) != 0) && |
| ((image_flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) != VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-00987", device, create_info_loc.dot(Field::flags), "is %s.", |
| string_VkImageCreateFlags(image_flags).c_str()); |
| } |
| |
| // Check for combinations of attributes that are incompatible with having VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT set |
| if ((image_flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) != 0) { |
| if (VK_IMAGE_TILING_LINEAR == create_info.tiling) { |
| skip |= LogError("VUID-VkImageCreateInfo-tiling-04121", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT but tiling is VK_IMAGE_TILING_LINEAR."); |
| } |
| |
| if (VK_IMAGE_TYPE_1D == create_info.imageType) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageType-00970", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SPARSE_BINDING_BIT but imageType is VK_IMAGE_TYPE_1D."); |
| } |
| |
| if ((!enabled_features.sparseResidencyImage2D) && (VK_IMAGE_TYPE_2D == create_info.imageType)) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageType-00971", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SPARSE_BINDING_BIT and imageType is VK_IMAGE_TYPE_2D, but " |
| "sparseResidencyImage2D feature was not enabled."); |
| } |
| |
| if ((!enabled_features.sparseResidencyImage3D) && (VK_IMAGE_TYPE_3D == create_info.imageType)) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageType-00972", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SPARSE_BINDING_BIT and imageType is VK_IMAGE_TYPE_3D, but " |
| "sparseResidencyImage3D feature was not enabled."); |
| } |
| |
| if (VK_IMAGE_TYPE_2D == create_info.imageType) { |
| if ((!enabled_features.sparseResidency2Samples) && (VK_SAMPLE_COUNT_2_BIT == create_info.samples)) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageType-00973", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SPARSE_BINDING_BIT and imageType is VK_IMAGE_TYPE_2D and samples is " |
| "VK_SAMPLE_COUNT_2_BIT, but sparseResidency2Samples feature was not enabled."); |
| } else if ((!enabled_features.sparseResidency4Samples) && (VK_SAMPLE_COUNT_4_BIT == create_info.samples)) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageType-00974", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SPARSE_BINDING_BIT and imageType is VK_IMAGE_TYPE_2D and samples is " |
| "VK_SAMPLE_COUNT_4_BIT, but sparseResidency4Samples feature was not enabled."); |
| } else if ((!enabled_features.sparseResidency8Samples) && (VK_SAMPLE_COUNT_8_BIT == create_info.samples)) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageType-00975", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SPARSE_BINDING_BIT and imageType is VK_IMAGE_TYPE_2D and samples is " |
| "VK_SAMPLE_COUNT_8_BIT, but sparseResidency8Samples feature was not enabled."); |
| } else if ((!enabled_features.sparseResidency16Samples) && (VK_SAMPLE_COUNT_16_BIT == create_info.samples)) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageType-00976", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_SPARSE_BINDING_BIT and imageType is VK_IMAGE_TYPE_2D and samples is " |
| "VK_SAMPLE_COUNT_16_BIT, but sparseResidency16Samples feature was not enabled."); |
| } |
| } |
| } |
| return skip; |
| } |
| |
| bool Device::ValidateCreateImageFragmentShadingRate(const VkImageCreateInfo &create_info, const Location &create_info_loc) const { |
| bool skip = false; |
| // alias VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV |
| if ((create_info.usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR) == 0) return skip; |
| |
| if (create_info.imageType != VK_IMAGE_TYPE_2D) { |
| skip |= LogError("VUID-VkImageCreateInfo-imageType-02082", device, create_info_loc.dot(Field::usage), |
| "includes VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR (or the " |
| "alias VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV), but imageType is %s.", |
| string_VkImageType(create_info.imageType)); |
| } |
| if (create_info.samples != VK_SAMPLE_COUNT_1_BIT) { |
| skip |= LogError("VUID-VkImageCreateInfo-samples-02083", device, create_info_loc.dot(Field::usage), |
| "includes VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR (or the " |
| "alias VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV), but samples is %s.", |
| string_VkSampleCountFlagBits(create_info.samples)); |
| } |
| if (enabled_features.shadingRateImage && create_info.tiling != VK_IMAGE_TILING_OPTIMAL) { |
| // KHR flag can be non-optimal |
| skip |= LogError("VUID-VkImageCreateInfo-shadingRateImage-07727", device, create_info_loc.dot(Field::usage), |
| "includes VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, tiling must be " |
| "VK_IMAGE_TILING_OPTIMAL."); |
| } |
| return skip; |
| } |
| |
| bool Device::ValidateCreateImageCornerSampled(const VkImageCreateInfo &create_info, const Location &create_info_loc) const { |
| bool skip = false; |
| if ((create_info.flags & VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV) == 0) return skip; |
| |
| if (create_info.imageType != VK_IMAGE_TYPE_2D && create_info.imageType != VK_IMAGE_TYPE_3D) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-02050", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV, " |
| "but imageType is %s.", |
| string_VkImageType(create_info.imageType)); |
| } |
| |
| if ((create_info.flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) || vkuFormatIsDepthOrStencil(create_info.format)) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-02051", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV, " |
| "it must not also contain VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT and format (%s) must not be a " |
| "depth/stencil format.", |
| string_VkFormat(create_info.format)); |
| } |
| |
| if (create_info.imageType == VK_IMAGE_TYPE_2D && (create_info.extent.width == 1 || create_info.extent.height == 1)) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-02052", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV and " |
| "imageType is VK_IMAGE_TYPE_2D, extent.width and extent.height must be " |
| "greater than 1."); |
| } else if (create_info.imageType == VK_IMAGE_TYPE_3D && |
| (create_info.extent.width == 1 || create_info.extent.height == 1 || create_info.extent.depth == 1)) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-02053", device, create_info_loc.dot(Field::flags), |
| "includes VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV and " |
| "imageType is VK_IMAGE_TYPE_3D, extent.width, extent.height, and extent.depth " |
| "must be greater than 1."); |
| } |
| return skip; |
| } |
| |
| bool Device::ValidateCreateImageStencilUsage(const VkImageCreateInfo &create_info, const Location &create_info_loc) const { |
| bool skip = false; |
| const auto image_stencil_struct = vku::FindStructInPNextChain<VkImageStencilUsageCreateInfo>(create_info.pNext); |
| if (!image_stencil_struct) return skip; |
| |
| if ((image_stencil_struct->stencilUsage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0) { |
| VkImageUsageFlags legal_flags = (VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT); |
| legal_flags |= VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT; |
| if ((image_stencil_struct->stencilUsage & ~legal_flags) != 0) { |
| skip |= LogError("VUID-VkImageStencilUsageCreateInfo-stencilUsage-02539", device, |
| create_info_loc.pNext(Struct::VkImageStencilUsageCreateInfo, Field::stencilUsage), "is %s.", |
| string_VkImageUsageFlags(image_stencil_struct->stencilUsage).c_str()); |
| } |
| } |
| |
| if (vkuFormatIsDepthOrStencil(create_info.format)) { |
| if ((image_stencil_struct->stencilUsage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) != 0) { |
| if (create_info.extent.width > phys_dev_props.limits.maxFramebufferWidth) { |
| skip |= LogError("VUID-VkImageCreateInfo-Format-02536", device, |
| create_info_loc.pNext(Struct::VkImageStencilUsageCreateInfo, Field::stencilUsage), |
| "includes VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT and image width (%" PRIu32 |
| ") exceeds device " |
| "maxFramebufferWidth (%" PRIu32 ")", |
| create_info.extent.width, phys_dev_props.limits.maxFramebufferWidth); |
| } |
| |
| if (create_info.extent.height > phys_dev_props.limits.maxFramebufferHeight) { |
| skip |= LogError("VUID-VkImageCreateInfo-format-02537", device, |
| create_info_loc.pNext(Struct::VkImageStencilUsageCreateInfo, Field::stencilUsage), |
| "includes VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT and image height (%" PRIu32 |
| ") exceeds device " |
| "maxFramebufferHeight (%" PRIu32 ")", |
| create_info.extent.height, phys_dev_props.limits.maxFramebufferHeight); |
| } |
| } |
| |
| if (!enabled_features.shaderStorageImageMultisample && |
| ((image_stencil_struct->stencilUsage & VK_IMAGE_USAGE_STORAGE_BIT) != 0) && |
| (create_info.samples != VK_SAMPLE_COUNT_1_BIT)) { |
| skip |= LogError("VUID-VkImageCreateInfo-format-02538", device, |
| create_info_loc.pNext(Struct::VkImageStencilUsageCreateInfo, Field::stencilUsage), |
| "includes VK_IMAGE_USAGE_STORAGE_BIT and format is %s and samples is %s, but " |
| "shaderStorageImageMultisample feature was not enabled.", |
| string_VkFormat(create_info.format), string_VkSampleCountFlagBits(create_info.samples)); |
| } |
| |
| if (((create_info.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) && |
| ((image_stencil_struct->stencilUsage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0)) { |
| skip |= LogError("VUID-VkImageCreateInfo-format-02795", device, create_info_loc.dot(Field::usage), |
| "is (%s), format is %s, and %s is %s", string_VkImageUsageFlags(create_info.usage).c_str(), |
| string_VkFormat(create_info.format), |
| create_info_loc.pNext(Struct::VkImageStencilUsageCreateInfo, Field::stencilUsage).Fields().c_str(), |
| string_VkImageUsageFlags(image_stencil_struct->stencilUsage).c_str()); |
| } else if (((create_info.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) && |
| ((image_stencil_struct->stencilUsage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0)) { |
| skip |= LogError("VUID-VkImageCreateInfo-format-02796", device, create_info_loc.dot(Field::usage), |
| "is (%s), format is %s, and %s is %s", string_VkImageUsageFlags(create_info.usage).c_str(), |
| string_VkFormat(create_info.format), |
| create_info_loc.pNext(Struct::VkImageStencilUsageCreateInfo, Field::stencilUsage).Fields().c_str(), |
| string_VkImageUsageFlags(image_stencil_struct->stencilUsage).c_str()); |
| } |
| |
| if (((create_info.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0) && |
| ((image_stencil_struct->stencilUsage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) == 0)) { |
| skip |= LogError("VUID-VkImageCreateInfo-format-02797", device, create_info_loc.dot(Field::usage), |
| "is (%s), format is %s, and %s is %s", string_VkImageUsageFlags(create_info.usage).c_str(), |
| string_VkFormat(create_info.format), |
| create_info_loc.pNext(Struct::VkImageStencilUsageCreateInfo, Field::stencilUsage).Fields().c_str(), |
| string_VkImageUsageFlags(image_stencil_struct->stencilUsage).c_str()); |
| } else if (((create_info.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) == 0) && |
| ((image_stencil_struct->stencilUsage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0)) { |
| skip |= LogError("VUID-VkImageCreateInfo-format-02798", device, create_info_loc.dot(Field::usage), |
| "is (%s), format is %s, and %s is %s", string_VkImageUsageFlags(create_info.usage).c_str(), |
| string_VkFormat(create_info.format), |
| create_info_loc.pNext(Struct::VkImageStencilUsageCreateInfo, Field::stencilUsage).Fields().c_str(), |
| string_VkImageUsageFlags(image_stencil_struct->stencilUsage).c_str()); |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateCreateImageCompressionControl(const Context &context, const VkImageCreateInfo &create_info, |
| const Location &create_info_loc) const { |
| bool skip = false; |
| const auto image_compression_control = vku::FindStructInPNextChain<VkImageCompressionControlEXT>(create_info.pNext); |
| if (!image_compression_control) return skip; |
| |
| skip |= context.ValidateFlags(create_info_loc.pNext(Struct::VkImageCompressionControlEXT, Field::flags), |
| vvl::FlagBitmask::VkImageCompressionFlagBitsEXT, AllVkImageCompressionFlagBitsEXT, |
| image_compression_control->flags, kOptionalSingleBit, |
| "VUID-VkImageCompressionControlEXT-flags-06747"); |
| |
| if ((image_compression_control->flags & VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT) != 0) { |
| if (!image_compression_control->pFixedRateFlags) { |
| skip |= LogError("VUID-VkImageCompressionControlEXT-flags-06748", device, |
| create_info_loc.pNext(Struct::VkImageCompressionControlEXT, Field::flags), |
| "is %s, but pFixedRateFlags is NULL.", |
| string_VkImageCompressionFlagsEXT(image_compression_control->flags).c_str()); |
| } |
| |
| if (vkuFormatIsMultiplane(create_info.format)) { |
| if (image_compression_control->compressionControlPlaneCount != vkuFormatPlaneCount(create_info.format)) { |
| skip |= LogError("VUID-VkImageCreateInfo-pNext-06743", device, create_info_loc, |
| "VkImageCompressionControlEXT::flags contain VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT, but " |
| "VkImageCompressionControlEXT::compressionControlPlaneCount (%" PRIu32 |
| ") is not equal to the number of planes in the multi-planar format %s (%" PRIu32 ")", |
| image_compression_control->compressionControlPlaneCount, string_VkFormat(create_info.format), |
| vkuFormatPlaneCount(create_info.format)); |
| } |
| } else { |
| if (image_compression_control->compressionControlPlaneCount != 1) { |
| skip |= LogError("VUID-VkImageCreateInfo-pNext-06744", device, create_info_loc, |
| "VkImageCompressionControlEXT::flags contain VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT and " |
| "VkImageCreateInfo::format is a not a multi-planar format (%s), but " |
| "VkImageCompressionControlEXT::compressionControlPlaneCount is %" PRIu32, |
| string_VkFormat(create_info.format), image_compression_control->compressionControlPlaneCount); |
| } |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateCreateImageSwapchain(const VkImageCreateInfo &create_info, const Location &create_info_loc) const { |
| bool skip = false; |
| const auto swapchain_create_info = vku::FindStructInPNextChain<VkImageSwapchainCreateInfoKHR>(create_info.pNext); |
| if (!swapchain_create_info || swapchain_create_info->swapchain == VK_NULL_HANDLE) return skip; |
| |
| // All the following fall under the same VU that checks that the swapchain image uses parameters listed in the |
| // #swapchain-wsi-image-create-info table. Breaking up into multiple checks allows for more useful information |
| // to be returned when this error occurs. Check for matching Swapchain flags is done later in state tracking validation |
| const char *vuid = "VUID-VkImageSwapchainCreateInfoKHR-swapchain-00995"; |
| const Location swapchain_loc = create_info_loc.pNext(Struct::VkImageSwapchainCreateInfoKHR, Field::swapchain); |
| |
| if (create_info.imageType != VK_IMAGE_TYPE_2D) { |
| // also implicitly forces the check above that extent.depth is 1 |
| skip |= LogError(vuid, swapchain_create_info->swapchain, swapchain_loc, |
| "is not NULL, but imageType (%s) is not VK_IMAGE_TYPE_2D.", string_VkImageType(create_info.imageType)); |
| } |
| if (create_info.mipLevels != 1) { |
| skip |= LogError(vuid, swapchain_create_info->swapchain, swapchain_loc, |
| "is not NULL, but mipLevels (%" PRIu32 ") is not 1.", create_info.mipLevels); |
| } |
| if (create_info.samples != VK_SAMPLE_COUNT_1_BIT) { |
| skip |= LogError(vuid, swapchain_create_info->swapchain, swapchain_loc, |
| "is not NULL, but samples (%s) is not VK_SAMPLE_COUNT_1_BIT.", |
| string_VkSampleCountFlagBits(create_info.samples)); |
| } |
| if (create_info.tiling != VK_IMAGE_TILING_OPTIMAL) { |
| skip |= LogError(vuid, swapchain_create_info->swapchain, swapchain_loc, |
| "is not NULL, but tiling (%s) is not VK_IMAGE_TILING_OPTIMAL.", string_VkImageTiling(create_info.tiling)); |
| } |
| if (create_info.initialLayout != VK_IMAGE_LAYOUT_UNDEFINED) { |
| skip |= LogError(vuid, swapchain_create_info->swapchain, swapchain_loc, |
| "is not NULL, but initialLayout (%s) is not VK_IMAGE_LAYOUT_UNDEFINED.", |
| string_VkImageLayout(create_info.initialLayout)); |
| } |
| const VkImageCreateFlags valid_flags = (VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT | VK_IMAGE_CREATE_PROTECTED_BIT | |
| VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT); |
| if ((create_info.flags & ~valid_flags) != 0) { |
| skip |= LogError(vuid, swapchain_create_info->swapchain, swapchain_loc, |
| "is not NULL, but flags %s must only have valid flags (%s).", |
| string_VkImageCreateFlags(create_info.flags).c_str(), string_VkImageCreateFlags(valid_flags).c_str()); |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateCreateImageFormatList(const VkImageCreateInfo &create_info, const Location &create_info_loc) const { |
| bool skip = false; |
| const auto format_list_info = vku::FindStructInPNextChain<VkImageFormatListCreateInfo>(create_info.pNext); |
| if (!format_list_info) return skip; |
| |
| const VkImageCreateFlags image_flags = create_info.flags; |
| const uint32_t view_format_count = format_list_info->viewFormatCount; |
| const bool mutable_image = (image_flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) != 0; |
| if (!mutable_image && view_format_count > 1) { |
| skip |= LogError("VUID-VkImageCreateInfo-flags-04738", device, |
| create_info_loc.pNext(Struct::VkImageFormatListCreateInfo, Field::viewFormatCount), |
| "is %" PRIu32 " but flag (%s) does not include VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT.", view_format_count, |
| string_VkImageCreateFlags(image_flags).c_str()); |
| } |
| |
| // Check if viewFormatCount is not zero that it is all compatible |
| const VkFormat image_format = create_info.format; |
| const auto image_format_class = vkuFormatCompatibilityClass(image_format); |
| for (uint32_t i = 0; i < view_format_count; i++) { |
| const VkFormat view_format = format_list_info->pViewFormats[i]; |
| const Location format_loc = create_info_loc.pNext(Struct::VkImageFormatListCreateInfo, Field::pViewFormats, i); |
| const auto view_format_class = vkuFormatCompatibilityClass(view_format); |
| |
| if (view_format == VK_FORMAT_UNDEFINED) { |
| skip |= |
| LogError("VUID-VkImageFormatListCreateInfo-viewFormatCount-09540", device, format_loc, "is VK_FORMAT_UNDEFINED."); |
| } else if (vkuFormatIsMultiplane(image_format)) { |
| if (vkuFormatIsMultiplane(view_format)) { |
| // TODO - need VU to say these need to be the same |
| // https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/6967 |
| } else if (mutable_image) { |
| // Need to make sure it is compatible with any possible planes because we don't know the apsectMask yet |
| const VkFormat plane_0_format = vkuFindMultiplaneCompatibleFormat(image_format, VK_IMAGE_ASPECT_PLANE_0_BIT); |
| const VkFormat plane_1_format = vkuFindMultiplaneCompatibleFormat(image_format, VK_IMAGE_ASPECT_PLANE_1_BIT); |
| const VkFormat plane_2_format = vkuFindMultiplaneCompatibleFormat(image_format, VK_IMAGE_ASPECT_PLANE_2_BIT); |
| const uint32_t plane_count = vkuFormatPlaneCount(image_format); |
| bool found_compatible = false; |
| if (view_format_class == vkuFormatCompatibilityClass(plane_0_format)) { |
| found_compatible = true; |
| } else if ((plane_count > 1) && view_format_class == vkuFormatCompatibilityClass(plane_1_format)) { |
| found_compatible = true; |
| } else if ((plane_count > 2) && view_format_class == vkuFormatCompatibilityClass(plane_2_format)) { |
| found_compatible = true; |
| } |
| if (!found_compatible) { |
| std::ostringstream ss; |
| ss << "Plane 0 " << string_VkFormat(plane_0_format); |
| if (plane_count > 1) { |
| ss << "\nPlane 1 " << string_VkFormat(plane_1_format); |
| } |
| if (plane_count > 2) { |
| ss << "\nPlane 2 " << string_VkFormat(plane_2_format); |
| } |
| skip |= LogError("VUID-VkImageCreateInfo-pNext-10062", device, format_loc, |
| "(%s) is not compatible with any plane of VkImageCreateInfo::format (%s)\n%s.", |
| string_VkFormat(view_format), string_VkFormat(image_format), ss.str().c_str()); |
| } |
| } |
| } else if (view_format_class != image_format_class) { |
| if (image_flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT) { |
| if (!AreFormatsSizeCompatible(view_format, image_format)) { |
| skip |= LogError("VUID-VkImageCreateInfo-pNext-06722", device, format_loc, |
| "(%s) and VkImageCreateInfo::format (%s) are not class compatible or size-compatible. %s", |
| string_VkFormat(view_format), string_VkFormat(image_format), |
| DescribeFormatsSizeCompatible(view_format, image_format).c_str()); |
| } |
| } else { |
| skip |= LogError("VUID-VkImageCreateInfo-pNext-06722", device, format_loc, |
| "(%s) and VkImageCreateInfo::format (%s) are not class compatible.", string_VkFormat(view_format), |
| string_VkFormat(image_format)); |
| } |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateCreateImageMetalObject(const VkImageCreateInfo &create_info, const Location &create_info_loc) const { |
| bool skip = false; |
| #ifdef VK_USE_PLATFORM_METAL_EXT |
| auto export_metal_object_info = vku::FindStructInPNextChain<VkExportMetalObjectCreateInfoEXT>(create_info.pNext); |
| while (export_metal_object_info) { |
| if ((export_metal_object_info->exportObjectType != VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT) && |
| (export_metal_object_info->exportObjectType != VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT)) { |
| skip |= LogError("VUID-VkImageCreateInfo-pNext-06783", device, |
| create_info_loc.pNext(Struct::VkExportMetalObjectCreateInfoEXT, Field::exportObjectType), |
| "is %s, but only VkExportMetalObjectCreateInfoEXT structs with exportObjectType of " |
| "VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT or " |
| "VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT are allowed", |
| string_VkExportMetalObjectTypeFlagBitsEXT(export_metal_object_info->exportObjectType)); |
| } |
| export_metal_object_info = vku::FindStructInPNextChain<VkExportMetalObjectCreateInfoEXT>(export_metal_object_info->pNext); |
| } |
| auto import_metal_texture_info = vku::FindStructInPNextChain<VkImportMetalTextureInfoEXT>(create_info.pNext); |
| while (import_metal_texture_info) { |
| const Location texture_info_loc = create_info_loc.pNext(Struct::VkImportMetalTextureInfoEXT, Field::plane); |
| if ((import_metal_texture_info->plane != VK_IMAGE_ASPECT_PLANE_0_BIT) && |
| (import_metal_texture_info->plane != VK_IMAGE_ASPECT_PLANE_1_BIT) && |
| (import_metal_texture_info->plane != VK_IMAGE_ASPECT_PLANE_2_BIT)) { |
| skip |= LogError("VUID-VkImageCreateInfo-pNext-06784", device, texture_info_loc, |
| "is %s, but only VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, or " |
| "VK_IMAGE_ASPECT_PLANE_2_BIT are allowed", |
| string_VkImageAspectFlags(import_metal_texture_info->plane).c_str()); |
| } |
| auto format_plane_count = vkuFormatPlaneCount(create_info.format); |
| if ((format_plane_count <= 1) && (import_metal_texture_info->plane != VK_IMAGE_ASPECT_PLANE_0_BIT)) { |
| skip |= |
| LogError("VUID-VkImageCreateInfo-pNext-06785", device, texture_info_loc, |
| "is %s, but only VK_IMAGE_ASPECT_PLANE_0_BIT is allowed for an image created with format %s, " |
| "which is not multiplanar", |
| string_VkImageAspectFlags(import_metal_texture_info->plane).c_str(), string_VkFormat(create_info.format)); |
| } |
| if ((format_plane_count == 2) && (import_metal_texture_info->plane == VK_IMAGE_ASPECT_PLANE_2_BIT)) { |
| skip |= LogError("VUID-VkImageCreateInfo-pNext-06786", device, texture_info_loc, |
| "is VK_IMAGE_ASPECT_PLANE_2_BIT, which is not allowed for an image created with format %s, " |
| "which has only 2 planes", |
| string_VkFormat(create_info.format)); |
| } |
| import_metal_texture_info = vku::FindStructInPNextChain<VkImportMetalTextureInfoEXT>(import_metal_texture_info->pNext); |
| } |
| #endif // VK_USE_PLATFORM_METAL_EXT |
| return skip; |
| } |
| |
| bool Device::ValidateCreateImageDrmFormatModifiers(const VkImageCreateInfo &create_info, const Location &create_info_loc, |
| std::vector<uint64_t> &image_create_drm_format_modifiers) const { |
| bool skip = false; |
| if (!IsExtEnabled(extensions.vk_ext_image_drm_format_modifier)) return skip; |
| |
| const auto drm_format_mod_list = vku::FindStructInPNextChain<VkImageDrmFormatModifierListCreateInfoEXT>(create_info.pNext); |
| const auto drm_format_mod_explicit = |
| vku::FindStructInPNextChain<VkImageDrmFormatModifierExplicitCreateInfoEXT>(create_info.pNext); |
| if (create_info.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) { |
| if ((!drm_format_mod_list) && (!drm_format_mod_explicit)) { |
| skip |= LogError("VUID-VkImageCreateInfo-tiling-02261", device, create_info_loc.dot(Field::tiling), |
| "is VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT but pNext is missing " |
| "VkImageDrmFormatModifierListCreateInfoEXT or " |
| "VkImageDrmFormatModifierExplicitCreateInfoEXT."); |
| } else if ((drm_format_mod_list) && (drm_format_mod_explicit)) { |
| skip |= LogError("VUID-VkImageCreateInfo-tiling-02261", device, create_info_loc.dot(Field::tiling), |
| "is VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT but pNext has both " |
| "VkImageDrmFormatModifierListCreateInfoEXT and " |
| "VkImageDrmFormatModifierExplicitCreateInfoEXT."); |
| } else if (drm_format_mod_explicit) { |
| image_create_drm_format_modifiers.push_back(drm_format_mod_explicit->drmFormatModifier); |
| } else if (drm_format_mod_list) { |
| for (uint32_t i = 0; i < drm_format_mod_list->drmFormatModifierCount; i++) { |
| image_create_drm_format_modifiers.push_back(*drm_format_mod_list->pDrmFormatModifiers); |
| } |
| } |
| |
| if (create_info.flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) { |
| const auto format_list_info = vku::FindStructInPNextChain<VkImageFormatListCreateInfo>(create_info.pNext); |
| if (!format_list_info) { |
| skip |= LogError("VUID-VkImageCreateInfo-tiling-02353", device, create_info_loc.dot(Field::tiling), |
| "is VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, flags includes " |
| "VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, but pNext is missing VkImageFormatListCreateInfo."); |
| } else if (format_list_info->viewFormatCount == 0) { |
| skip |= LogError("VUID-VkImageCreateInfo-tiling-02353", device, create_info_loc.dot(Field::tiling), |
| "is VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, flags includes VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, " |
| "but pNext<VkImageFormatListCreateInfo>.viewFormatCount is zero."); |
| } |
| } |
| } else if (drm_format_mod_list) { |
| skip |= LogError("VUID-VkImageCreateInfo-pNext-02262", device, create_info_loc.dot(Field::tiling), |
| "is %s, but there is a " |
| "VkImageDrmFormatModifierListCreateInfoEXT in the pNext chain", |
| string_VkImageTiling(create_info.tiling)); |
| } else if (drm_format_mod_explicit) { |
| skip |= LogError("VUID-VkImageCreateInfo-pNext-02262", device, create_info_loc.dot(Field::tiling), |
| "is %s, but there is a VkImageDrmFormatModifierExplicitCreateInfoEXT " |
| "in the pNext chain", |
| string_VkImageTiling(create_info.tiling)); |
| } |
| |
| if (drm_format_mod_explicit && drm_format_mod_explicit->pPlaneLayouts) { |
| for (uint32_t i = 0; i < drm_format_mod_explicit->drmFormatModifierPlaneCount; ++i) { |
| const Location drm_loc = |
| create_info_loc.pNext(Struct::VkImageDrmFormatModifierExplicitCreateInfoEXT, Field::pPlaneLayouts, i); |
| if (drm_format_mod_explicit->pPlaneLayouts[i].size != 0) { |
| skip |= LogError("VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-size-02267", device, drm_loc.dot(Field::size), |
| "is not zero (%" PRIu64 ").", drm_format_mod_explicit->pPlaneLayouts[i].size); |
| } |
| if (create_info.arrayLayers == 1 && drm_format_mod_explicit->pPlaneLayouts[i].arrayPitch != 0) { |
| skip |= LogError("VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-arrayPitch-02268", device, |
| drm_loc.dot(Field::arrayPitch), "is %" PRIu64 " and arrayLayers is 1.", |
| drm_format_mod_explicit->pPlaneLayouts[i].arrayPitch); |
| } |
| if (create_info.extent.depth == 1 && drm_format_mod_explicit->pPlaneLayouts[i].depthPitch != 0) { |
| skip |= LogError("VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-depthPitch-02269", device, |
| drm_loc.dot(Field::depthPitch), "is %" PRIu64 " and extext.depth is 1.", |
| drm_format_mod_explicit->pPlaneLayouts[i].depthPitch); |
| } |
| } |
| } |
| |
| const auto compression_control = vku::FindStructInPNextChain<VkImageCompressionControlEXT>(create_info.pNext); |
| if (drm_format_mod_explicit && compression_control) { |
| skip |= LogError("VUID-VkImageCreateInfo-pNext-06746", device, create_info_loc.dot(Field::pNext), |
| "has both VkImageCompressionControlEXT and VkImageDrmFormatModifierExplicitCreateInfoEXT.\n%s", |
| PrintPNextChain(Struct::VkImageCreateInfo, create_info.pNext).c_str()); |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateImageViewCreateInfo(const VkImageViewCreateInfo &create_info, const Location &create_info_loc) const { |
| bool skip = false; |
| |
| if ((create_info.viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) && (!enabled_features.imageCubeArray)) { |
| skip |= LogError("VUID-VkImageViewCreateInfo-viewType-01004", create_info.image, create_info_loc.dot(Field::viewType), |
| "is VK_IMAGE_VIEW_TYPE_CUBE_ARRAY but the imageCubeArray feature is not enabled."); |
| } |
| |
| if (create_info.subresourceRange.layerCount != VK_REMAINING_ARRAY_LAYERS) { |
| if (create_info.viewType == VK_IMAGE_VIEW_TYPE_CUBE && create_info.subresourceRange.layerCount != 6) { |
| skip |= LogError("VUID-VkImageViewCreateInfo-viewType-02960", create_info.image, |
| create_info_loc.dot(Field::subresourceRange).dot(Field::layerCount), |
| "(%" PRIu32 ") must be 6 or VK_REMAINING_ARRAY_LAYERS.", create_info.subresourceRange.layerCount); |
| } |
| if (create_info.viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY && |
| !IsIntegerMultipleOf(create_info.subresourceRange.layerCount, 6)) { |
| skip |= LogError("VUID-VkImageViewCreateInfo-viewType-02961", create_info.image, |
| create_info_loc.dot(Field::subresourceRange).dot(Field::layerCount), |
| "(%" PRIu32 ") must be a multiple of 6 or VK_REMAINING_ARRAY_LAYERS.", |
| create_info.subresourceRange.layerCount); |
| } |
| } |
| |
| auto astc_decode_mode = vku::FindStructInPNextChain<VkImageViewASTCDecodeModeEXT>(create_info.pNext); |
| if (astc_decode_mode != nullptr) { |
| if ((astc_decode_mode->decodeMode != VK_FORMAT_R16G16B16A16_SFLOAT) && |
| (astc_decode_mode->decodeMode != VK_FORMAT_R8G8B8A8_UNORM) && |
| (astc_decode_mode->decodeMode != VK_FORMAT_E5B9G9R9_UFLOAT_PACK32)) { |
| skip |= LogError("VUID-VkImageViewASTCDecodeModeEXT-decodeMode-02230", create_info.image, |
| create_info_loc.pNext(Struct::VkImageViewASTCDecodeModeEXT, Field::decodeMode), "is %s.", |
| string_VkFormat(astc_decode_mode->decodeMode)); |
| } |
| if ((vkuFormatIsCompressed_ASTC_LDR(create_info.format) == false) && |
| (vkuFormatIsCompressed_ASTC_HDR(create_info.format) == false)) { |
| skip |= |
| LogError("VUID-VkImageViewASTCDecodeModeEXT-format-04084", create_info.image, create_info_loc.dot(Field::format), |
| "%s is not an ASTC format (because VkImageViewASTCDecodeModeEXT was passed in the pNext chain).", |
| string_VkFormat(create_info.format)); |
| } |
| } |
| |
| auto ycbcr_conversion = vku::FindStructInPNextChain<VkSamplerYcbcrConversionInfo>(create_info.pNext); |
| if (ycbcr_conversion != nullptr) { |
| if (ycbcr_conversion->conversion != VK_NULL_HANDLE) { |
| if (IsIdentitySwizzle(create_info.components) == false) { |
| skip |= LogError("VUID-VkImageViewCreateInfo-pNext-01970", create_info.image, create_info_loc, |
| "If there is a VkSamplerYcbcrConversion, the imageView must " |
| "be created with the identity swizzle. Here are the actual swizzle values:\n%s", |
| string_VkComponentMapping(create_info.components).c_str()); |
| } |
| } |
| } |
| #ifdef VK_USE_PLATFORM_METAL_EXT |
| skip |= ExportMetalObjectsPNextUtil(VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT, "VUID-VkImageViewCreateInfo-pNext-06787", |
| create_info_loc, "VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT", create_info.pNext); |
| #endif // VK_USE_PLATFORM_METAL_EXT |
| |
| if (api_version < VK_API_VERSION_1_3 && !enabled_features.ycbcr2plane444Formats) { |
| if (IsValueIn(create_info.format, |
| {VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, |
| VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, VK_FORMAT_G16_B16R16_2PLANE_444_UNORM})) { |
| skip |= LogError("VUID-VkImageViewCreateInfo-None-12280", device, create_info_loc.dot(Field::format), "is %s.", |
| string_VkFormat(create_info.format)); |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool Device::manual_PreCallValidateCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, VkImageView *pView, |
| const Context &context) const { |
| bool skip = false; |
| const auto &error_obj = context.error_obj; |
| |
| if (pCreateInfo == nullptr) { |
| return skip; |
| } |
| const Location create_info_loc = error_obj.location.dot(Field::pCreateInfo); |
| skip = ValidateImageViewCreateInfo(*pCreateInfo, create_info_loc); |
| return skip; |
| } |
| |
| bool Device::manual_PreCallValidateGetDeviceImageSubresourceLayout(VkDevice device, const VkDeviceImageSubresourceInfo *pInfo, |
| VkSubresourceLayout2 *pLayout, const Context &context) const { |
| bool skip = false; |
| const auto &error_obj = context.error_obj; |
| const Location info_loc = error_obj.location.dot(Field::pInfo); |
| const Location create_info_loc = info_loc.dot(Field::pCreateInfo); |
| const Location subresource_loc = info_loc.dot(Field::pSubresource); |
| |
| const VkImageCreateInfo &create_info = *pInfo->pCreateInfo; |
| const VkImageSubresource &subresource = pInfo->pSubresource->imageSubresource; |
| const VkImageAspectFlags aspect_mask = subresource.aspectMask; |
| |
| if (GetBitSetCount(aspect_mask) != 1) { |
| skip |= LogError("VUID-VkDeviceImageSubresourceInfo-aspectMask-00997", device, subresource_loc.dot(Field::aspectMask), |
| "(%s) must have exactly 1 bit set.", string_VkImageAspectFlags(aspect_mask).c_str()); |
| } |
| |
| if (subresource.mipLevel >= create_info.mipLevels) { |
| skip |= LogError("VUID-VkDeviceImageSubresourceInfo-mipLevel-01716", device, subresource_loc.dot(Field::mipLevel), |
| "(%" PRIu32 ") must be less than %s (%" PRIu32 ").", subresource.mipLevel, |
| create_info_loc.dot(Field::mipLevel).Fields().c_str(), create_info.mipLevels); |
| } |
| |
| if (subresource.arrayLayer >= create_info.arrayLayers) { |
| skip |= LogError("VUID-VkDeviceImageSubresourceInfo-arrayLayer-01717", device, subresource_loc.dot(Field::arrayLayer), |
| "(%" PRIu32 ") must be less than %s (%" PRIu32 ").", subresource.arrayLayer, |
| create_info_loc.dot(Field::arrayLayers).Fields().c_str(), create_info.arrayLayers); |
| } |
| |
| const VkFormat image_format = create_info.format; |
| const bool tiling_linear_optimal = |
| create_info.tiling == VK_IMAGE_TILING_LINEAR || create_info.tiling == VK_IMAGE_TILING_OPTIMAL; |
| if (vkuFormatIsColor(image_format) && !vkuFormatIsMultiplane(image_format) && (aspect_mask != VK_IMAGE_ASPECT_COLOR_BIT) && |
| tiling_linear_optimal) { |
| skip |= LogError("VUID-VkDeviceImageSubresourceInfo-format-08886", device, subresource_loc.dot(Field::aspectMask), |
| "(%s) is invalid with %s (%s).", string_VkImageAspectFlags(aspect_mask).c_str(), |
| create_info_loc.dot(Field::format).Fields().c_str(), string_VkFormat(image_format)); |
| } |
| |
| if (vkuFormatHasDepth(image_format) && ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) == 0)) { |
| skip |= LogError("VUID-VkDeviceImageSubresourceInfo-format-04462", device, subresource_loc.dot(Field::aspectMask), |
| "(%s) is invalid with %s (%s).", string_VkImageAspectFlags(aspect_mask).c_str(), |
| create_info_loc.dot(Field::format).Fields().c_str(), string_VkFormat(image_format)); |
| } |
| |
| if (vkuFormatHasStencil(image_format) && ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) == 0)) { |
| skip |= LogError("VUID-VkDeviceImageSubresourceInfo-format-04463", device, subresource_loc.dot(Field::aspectMask), |
| "(%s) is invalid with %s (%s).", string_VkImageAspectFlags(aspect_mask).c_str(), |
| create_info_loc.dot(Field::format).Fields().c_str(), string_VkFormat(image_format)); |
| } |
| |
| if (!vkuFormatHasDepth(image_format) && !vkuFormatHasStencil(image_format)) { |
| if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) { |
| skip |= LogError("VUID-VkDeviceImageSubresourceInfo-format-04464", device, subresource_loc.dot(Field::aspectMask), |
| "(%s) is invalid with %s (%s).", string_VkImageAspectFlags(aspect_mask).c_str(), |
| create_info_loc.dot(Field::format).Fields().c_str(), string_VkFormat(image_format)); |
| } |
| } |
| |
| // subresource's aspect must be compatible with image's format. |
| if (create_info.tiling == VK_IMAGE_TILING_LINEAR) { |
| if (vkuFormatIsMultiplane(image_format) && !IsOnlyOneValidPlaneAspect(image_format, aspect_mask)) { |
| skip |= LogError("VUID-VkDeviceImageSubresourceInfo-tiling-08717", device, subresource_loc.dot(Field::aspectMask), |
| "(%s) is invalid for %s (%s).", string_VkImageAspectFlags(aspect_mask).c_str(), |
| create_info_loc.dot(Field::format).Fields().c_str(), string_VkFormat(image_format)); |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool Device::manual_PreCallValidateCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, |
| VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, |
| const VkImageResolve *pRegions, const Context &context) const { |
| bool skip = false; |
| |
| for (uint32_t i = 0; i < regionCount; i++) { |
| const Location region_loc = context.error_obj.location.dot(Field::pRegions, i); |
| const Location src_subresource_loc = region_loc.dot(Field::srcSubresource); |
| const Location dst_subresource_loc = region_loc.dot(Field::dstSubresource); |
| |
| if (pRegions[i].srcSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) { |
| skip |= LogError("VUID-VkImageResolve-aspectMask-10981", commandBuffer, src_subresource_loc, "is %s.", |
| string_VkImageAspectFlags(pRegions[i].srcSubresource.aspectMask).c_str()); |
| } |
| if (pRegions[i].dstSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) { |
| skip |= LogError("VUID-VkImageResolve-aspectMask-10981", commandBuffer, dst_subresource_loc, "is %s.", |
| string_VkImageAspectFlags(pRegions[i].dstSubresource.aspectMask).c_str()); |
| } |
| |
| if (pRegions[i].srcSubresource.aspectMask != pRegions[i].dstSubresource.aspectMask) { |
| skip |= |
| LogError("VUID-vkCmdResolveImage-srcSubresource-11802", commandBuffer, src_subresource_loc.dot(Field::aspectMask), |
| "(%s) is not equal to %s (%s)", string_VkImageAspectFlags(pRegions[i].srcSubresource.aspectMask).c_str(), |
| dst_subresource_loc.dot(Field::aspectMask).Fields().c_str(), |
| string_VkImageAspectFlags(pRegions[i].dstSubresource.aspectMask).c_str()); |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool Device::manual_PreCallValidateCmdResolveImage2(VkCommandBuffer commandBuffer, const VkResolveImageInfo2 *pResolveImageInfo, |
| const Context &context) const { |
| bool skip = false; |
| const Location resolve_info_loc = context.error_obj.location.dot(Field::pResolveImageInfo); |
| for (uint32_t i = 0; i < pResolveImageInfo->regionCount; i++) { |
| const Location region_loc = resolve_info_loc.dot(Field::pRegions, i); |
| const Location src_subresource_loc = region_loc.dot(Field::srcSubresource); |
| const Location dst_subresource_loc = region_loc.dot(Field::dstSubresource); |
| const VkImageResolve2 ®ion = pResolveImageInfo->pRegions[i]; |
| |
| if (enabled_features.maintenance10) { |
| if (region.srcSubresource.aspectMask & |
| ~(VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { |
| skip |= LogError("VUID-VkImageResolve2-aspectMask-10993", commandBuffer, src_subresource_loc, "is %s.", |
| string_VkImageAspectFlags(region.srcSubresource.aspectMask).c_str()); |
| } |
| if (region.dstSubresource.aspectMask & |
| ~(VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { |
| skip |= LogError("VUID-VkImageResolve2-aspectMask-10993", commandBuffer, dst_subresource_loc, "is %s.", |
| string_VkImageAspectFlags(region.dstSubresource.aspectMask).c_str()); |
| } |
| } else { |
| if (region.srcSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) { |
| skip |= LogError("VUID-VkImageResolve2-maintenance10-10994", commandBuffer, src_subresource_loc, |
| "is %s. (Having maintenance 10 feature enable would allow VK_IMAGE_ASPECT_DEPTH_BIT and " |
| "VK_IMAGE_ASPECT_STENCIL_BIT).", |
| string_VkImageAspectFlags(region.srcSubresource.aspectMask).c_str()); |
| } |
| if (region.dstSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) { |
| skip |= LogError("VUID-VkImageResolve2-maintenance10-10994", commandBuffer, dst_subresource_loc, |
| "is %s. (Having maintenance 10 feature enable would allow VK_IMAGE_ASPECT_DEPTH_BIT and " |
| "VK_IMAGE_ASPECT_STENCIL_BIT).", |
| string_VkImageAspectFlags(region.dstSubresource.aspectMask).c_str()); |
| } |
| } |
| if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) { |
| skip |= |
| LogError("VUID-VkResolveImageInfo2-srcSubresource-11802", commandBuffer, src_subresource_loc.dot(Field::aspectMask), |
| "(%s) is not equal to %s (%s)", string_VkImageAspectFlags(region.srcSubresource.aspectMask).c_str(), |
| dst_subresource_loc.dot(Field::aspectMask).Fields().c_str(), |
| string_VkImageAspectFlags(region.dstSubresource.aspectMask).c_str()); |
| } |
| } |
| |
| if (const auto *resolve_mode_info = vku::FindStructInPNextChain<VkResolveImageModeInfoKHR>(pResolveImageInfo->pNext)) { |
| const auto both_skip_and_enable_transfer_flags = |
| VK_RESOLVE_IMAGE_SKIP_TRANSFER_FUNCTION_BIT_KHR | VK_RESOLVE_IMAGE_ENABLE_TRANSFER_FUNCTION_BIT_KHR; |
| if ((resolve_mode_info->flags & both_skip_and_enable_transfer_flags) == both_skip_and_enable_transfer_flags) { |
| skip |= LogError("VUID-VkResolveImageModeInfoKHR-flags-10995", commandBuffer, |
| resolve_info_loc.pNext(Struct::VkResolveImageModeInfoKHR, Field::flags), "is %s.", |
| string_VkResolveImageFlagsKHR(resolve_mode_info->flags).c_str()); |
| } |
| |
| if ((resolve_mode_info->flags & both_skip_and_enable_transfer_flags)) { |
| if (!phys_dev_ext_props.maintenance10_props.resolveSrgbFormatSupportsTransferFunctionControl) { |
| skip |= LogError("VUID-VkResolveImageModeInfoKHR-flags-10996", commandBuffer, |
| resolve_info_loc.pNext(Struct::VkResolveImageModeInfoKHR, Field::flags), |
| "is %s but resolveSrgbFormatSupportsTransferFunctionControl is not supported on this device.", |
| string_VkResolveImageFlagsKHR(resolve_mode_info->flags).c_str()); |
| } |
| if (resolve_mode_info->resolveMode != VK_RESOLVE_MODE_AVERAGE_BIT) { |
| skip |= LogError("VUID-VkResolveImageModeInfoKHR-flags-10997", commandBuffer, |
| resolve_info_loc.pNext(Struct::VkResolveImageModeInfoKHR, Field::resolveMode), "is %s.", |
| string_VkResolveModeFlagBits(resolve_mode_info->resolveMode)); |
| } |
| } |
| } |
| |
| return skip; |
| } |
| } // namespace stateless |