| /* 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/utility/vk_format_utils.h> |
| #include <vulkan/vulkan_core.h> |
| #include "stateless/stateless_validation.h" |
| #include "error_message/error_strings.h" |
| #include "containers/container_utils.h" |
| #include "utils/convert_utils.h" |
| #include "utils/math_utils.h" |
| #include "utils/image_utils.h" |
| #include "utils/sync_utils.h" |
| #include "utils/vk_api_utils.h" |
| |
| namespace stateless { |
| |
| bool Device::ValidateSubpassGraphicsFlags(const VkRenderPassCreateInfo2 &create_info, uint32_t subpass, |
| VkPipelineStageFlags2 stages, const char *vuid, const Location &loc) const { |
| bool skip = false; |
| if (subpass == VK_SUBPASS_EXTERNAL || subpass >= create_info.subpassCount) { |
| return skip; |
| } |
| |
| // make sure we consider all of the expanded and un-expanded graphics bits to be valid |
| const VkPipelineStageFlags2 kExcludeStages = VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT | VK_PIPELINE_STAGE_2_COPY_BIT | |
| VK_PIPELINE_STAGE_2_RESOLVE_BIT | VK_PIPELINE_STAGE_2_BLIT_BIT | |
| VK_PIPELINE_STAGE_2_CLEAR_BIT; |
| const VkPipelineStageFlags2 kMetaGraphicsStages = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT | |
| VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT | |
| // ALL_COMMANDS means only graphics in graphics only context, |
| // TOP_OF_PIPE/BOTTOM_OF_PIPE are also always valid |
| // https://gitlab.khronos.org/vulkan/vulkan/-/issues/4257 |
| VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT | VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT | |
| VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT; |
| const VkPipelineStageFlags2 kGraphicsStages = |
| (sync_utils::ExpandPipelineStages(VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_QUEUE_GRAPHICS_BIT) | kMetaGraphicsStages) & |
| ~kExcludeStages; |
| |
| const bool is_pipeline = create_info.pSubpasses[subpass].pipelineBindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS; |
| const bool is_all_graphics_stages = (stages & ~kGraphicsStages) == 0; |
| if (is_pipeline && !is_all_graphics_stages) { |
| skip |= LogError(vuid, device, loc, |
| "dependency contains a stage mask (%s) that are not part " |
| "of the Graphics pipeline", |
| sync_utils::StringPipelineStageFlags(stages & ~kGraphicsStages).c_str()); |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateCreateRenderPass(const VkRenderPassCreateInfo2 &create_info, const ErrorObject &error_obj) const { |
| bool skip = false; |
| const bool use_rp2 = error_obj.location.function != Func::vkCreateRenderPass; |
| const char *vuid = nullptr; |
| const Location create_info_loc = error_obj.location.dot(Field::pCreateInfo); |
| |
| VkBool32 android_external_format_resolve_feature = false; |
| #if defined(VK_USE_PLATFORM_ANDROID_KHR) |
| android_external_format_resolve_feature = enabled_features.externalFormatResolve; |
| #endif |
| |
| for (uint32_t i = 0; i < create_info.attachmentCount; ++i) { |
| const Location &attachment_loc = create_info_loc.dot(Field::pAttachments, i); |
| |
| // if not null, also confirms rp2 is being used |
| const void *pNext = |
| (use_rp2) ? reinterpret_cast<VkAttachmentDescription2 const *>(&create_info.pAttachments[i])->pNext : nullptr; |
| const auto *attachment_description_stencil_layout = |
| (use_rp2) ? vku::FindStructInPNextChain<VkAttachmentDescriptionStencilLayout>(pNext) : nullptr; |
| |
| const VkAttachmentDescription2 &attachment = create_info.pAttachments[i]; |
| if (attachment.format == VK_FORMAT_UNDEFINED) { |
| if (use_rp2 && android_external_format_resolve_feature) { |
| if (GetExternalFormat(pNext) == 0) { |
| skip |= LogError("VUID-VkAttachmentDescription2-format-09334", device, attachment_loc.dot(Field::format), |
| "is VK_FORMAT_UNDEFINED."); |
| } |
| } else { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-09332" : "VUID-VkAttachmentDescription-format-06698"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::format), "is VK_FORMAT_UNDEFINED."); |
| } |
| } |
| if (IsValueIn(attachment.finalLayout, |
| {VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_ZERO_INITIALIZED_EXT})) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-finalLayout-00843" : "VUID-VkAttachmentDescription-finalLayout-00843"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), "is %s.", |
| string_VkImageLayout(attachment.finalLayout)); |
| } |
| if (!enabled_features.separateDepthStencilLayouts) { |
| if (IsImageLayoutDepthOnly(attachment.initialLayout) || IsImageLayoutStencilOnly(attachment.initialLayout)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-separateDepthStencilLayouts-03284" |
| : "VUID-VkAttachmentDescription-separateDepthStencilLayouts-03284"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::initialLayout), "is %s.", |
| string_VkImageLayout(attachment.initialLayout)); |
| } |
| if (IsImageLayoutDepthOnly(attachment.finalLayout) || IsImageLayoutStencilOnly(attachment.finalLayout)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-separateDepthStencilLayouts-03285" |
| : "VUID-VkAttachmentDescription-separateDepthStencilLayouts-03285"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), "is %s.", |
| string_VkImageLayout(attachment.finalLayout)); |
| } |
| } |
| if (!enabled_features.attachmentFeedbackLoopLayout) { |
| if (attachment.initialLayout == VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-attachmentFeedbackLoopLayout-07309" |
| : "VUID-VkAttachmentDescription-attachmentFeedbackLoopLayout-07309"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::initialLayout), |
| "is VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT but the " |
| "attachmentFeedbackLoopLayout feature is not enabled."); |
| } |
| if (attachment.finalLayout == VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-attachmentFeedbackLoopLayout-07310" |
| : "VUID-VkAttachmentDescription-attachmentFeedbackLoopLayout-07310"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), |
| "is VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT but the " |
| "attachmentFeedbackLoopLayout feature is not enabled."); |
| } |
| } |
| if (!enabled_features.synchronization2) { |
| if (attachment.initialLayout == VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL || |
| attachment.initialLayout == VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-synchronization2-06908" |
| : "VUID-VkAttachmentDescription-synchronization2-06908"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::initialLayout), |
| "is %s but the synchronization2 feature is not enabled.", |
| string_VkImageLayout(attachment.initialLayout)); |
| } |
| if (attachment.finalLayout == VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL || |
| attachment.finalLayout == VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-synchronization2-06909" |
| : "VUID-VkAttachmentDescription-synchronization2-06909"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), |
| "is %s but the synchronization2 feature is not enabled.", |
| string_VkImageLayout(attachment.finalLayout)); |
| } |
| } |
| if (!enabled_features.dynamicRenderingLocalRead) { |
| if (attachment.initialLayout == VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-dynamicRenderingLocalRead-09544" |
| : "VUID-VkAttachmentDescription-dynamicRenderingLocalRead-09544"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::initialLayout), |
| "is VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ but the " |
| "dynamicRenderingLocalRead feature is not enabled."); |
| } |
| if (attachment.finalLayout == VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-dynamicRenderingLocalRead-09545" |
| : "VUID-VkAttachmentDescription-dynamicRenderingLocalRead-09545"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), |
| "is VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ but the " |
| "dynamicRenderingLocalRead feature is not enabled."); |
| } |
| } |
| if (!vkuFormatIsDepthOrStencil(attachment.format)) { // color format |
| if (IsImageLayoutDepthOnly(attachment.initialLayout) || IsImageLayoutStencilOnly(attachment.initialLayout)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-03286" : "VUID-VkAttachmentDescription-format-03286"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::initialLayout), "is %s.", |
| string_VkImageLayout(attachment.initialLayout)); |
| } |
| if (IsImageLayoutDepthOnly(attachment.finalLayout) || IsImageLayoutStencilOnly(attachment.finalLayout)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-03287" : "VUID-VkAttachmentDescription-format-03287"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), "is %s.", |
| string_VkImageLayout(attachment.finalLayout)); |
| } |
| } else if (vkuFormatIsDepthAndStencil(attachment.format)) { |
| if (IsImageLayoutStencilOnly(attachment.initialLayout)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-06906" : "VUID-VkAttachmentDescription-format-06906"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::initialLayout), "is %s.", |
| string_VkImageLayout(attachment.initialLayout)); |
| } |
| if (IsImageLayoutStencilOnly(attachment.finalLayout)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-06907" : "VUID-VkAttachmentDescription-format-06907"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), "is %s.", |
| string_VkImageLayout(attachment.finalLayout)); |
| } |
| |
| if (!attachment_description_stencil_layout) { |
| if (IsImageLayoutDepthOnly(attachment.initialLayout)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-06249" : "VUID-VkAttachmentDescription-format-06242"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::initialLayout), |
| "is %s but no VkAttachmentDescriptionStencilLayout provided.", |
| string_VkImageLayout(attachment.initialLayout)); |
| } |
| if (IsImageLayoutDepthOnly(attachment.finalLayout)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-06250" : "VUID-VkAttachmentDescription-format-06243"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), |
| "is %s but no VkAttachmentDescriptionStencilLayout provided.", |
| string_VkImageLayout(attachment.finalLayout)); |
| } |
| } |
| } else if (vkuFormatIsDepthOnly(attachment.format)) { |
| if (IsImageLayoutStencilOnly(attachment.initialLayout)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-03290" : "VUID-VkAttachmentDescription-format-03290"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::initialLayout), "is %s.", |
| string_VkImageLayout(attachment.initialLayout)); |
| } |
| if (IsImageLayoutStencilOnly(attachment.finalLayout)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-03291" : "VUID-VkAttachmentDescription-format-03291"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), "is %s.", |
| string_VkImageLayout(attachment.finalLayout)); |
| } |
| } else if (vkuFormatIsStencilOnly(attachment.format) && !attachment_description_stencil_layout) { |
| if (IsImageLayoutDepthOnly(attachment.initialLayout)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-06247" : "VUID-VkAttachmentDescription-format-03292"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::initialLayout), "is %s.", |
| string_VkImageLayout(attachment.initialLayout)); |
| } |
| if (IsImageLayoutDepthOnly(attachment.finalLayout)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-06248" : "VUID-VkAttachmentDescription-format-03293"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), "is %s.", |
| string_VkImageLayout(attachment.finalLayout)); |
| } |
| } |
| if (attachment_description_stencil_layout) { |
| const VkImageLayout stencil_initial_layout = attachment_description_stencil_layout->stencilInitialLayout; |
| if (IsValueIn( |
| stencil_initial_layout, |
| {VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, |
| VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, |
| VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, |
| VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL})) { |
| skip |= LogError("VUID-VkAttachmentDescriptionStencilLayout-stencilInitialLayout-03308", device, |
| attachment_loc.pNext(Struct::VkAttachmentDescriptionStencilLayout, Field::stencilInitialLayout), |
| "is %s.", string_VkImageLayout(stencil_initial_layout)); |
| } |
| |
| const VkImageLayout stencil_final_layout = attachment_description_stencil_layout->stencilFinalLayout; |
| if (IsValueIn( |
| stencil_final_layout, |
| {VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, |
| VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, |
| VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, |
| VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL})) { |
| skip |= LogError("VUID-VkAttachmentDescriptionStencilLayout-stencilFinalLayout-03309", device, |
| attachment_loc.pNext(Struct::VkAttachmentDescriptionStencilLayout, Field::stencilFinalLayout), |
| "is %s.", string_VkImageLayout(stencil_final_layout)); |
| } |
| |
| if (IsValueIn(stencil_final_layout, |
| {VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_ZERO_INITIALIZED_EXT})) { |
| skip |= LogError("VUID-VkAttachmentDescriptionStencilLayout-stencilFinalLayout-03310", device, |
| attachment_loc.pNext(Struct::VkAttachmentDescriptionStencilLayout, Field::stencilFinalLayout), |
| "is %s.", string_VkImageLayout(stencil_final_layout)); |
| } |
| } |
| |
| if (vkuFormatIsDepthOrStencil(attachment.format)) { |
| if (attachment.initialLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-03281" : "VUID-VkAttachmentDescription-format-03281"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::initialLayout), |
| "must not be VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL when using a Depth or Stencil format (%s)", |
| string_VkFormat(attachment.format)); |
| } |
| if (attachment.finalLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-03283" : "VUID-VkAttachmentDescription-format-03283"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), |
| "must not be VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL when using a Depth or Stencil format (%s)", |
| string_VkFormat(attachment.format)); |
| } |
| } |
| if (vkuFormatIsColor(attachment.format)) { |
| if (attachment.initialLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || |
| attachment.initialLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-03280" : "VUID-VkAttachmentDescription-format-03280"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::initialLayout), "is %s, but using a Color format (%s)", |
| string_VkImageLayout(attachment.initialLayout), string_VkFormat(attachment.format)); |
| |
| } else if (attachment.initialLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL || |
| attachment.initialLayout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-06487" : "VUID-VkAttachmentDescription-format-06487"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::initialLayout), "is %s, but using a Color format (%s)", |
| string_VkImageLayout(attachment.initialLayout), string_VkFormat(attachment.format)); |
| } |
| if (attachment.finalLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || |
| attachment.finalLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-03282" : "VUID-VkAttachmentDescription-format-03282"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), "is %s, but using a Color format (%s)", |
| string_VkImageLayout(attachment.finalLayout), string_VkFormat(attachment.format)); |
| } else if (attachment.finalLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL || |
| attachment.finalLayout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-06488" : "VUID-VkAttachmentDescription-format-06488"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::finalLayout), "is %s, but using a Color format (%s)", |
| string_VkImageLayout(attachment.finalLayout), string_VkFormat(attachment.format)); |
| } |
| } |
| if (vkuFormatIsColor(attachment.format) || vkuFormatHasDepth(attachment.format)) { |
| if (create_info.pAttachments[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD && |
| attachment.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-format-06699" : "VUID-VkAttachmentDescription-format-06699"; |
| skip |= LogError( |
| vuid, device, attachment_loc, |
| "format is %s and loadOp is VK_ATTACHMENT_LOAD_OP_LOAD, but initialLayout is VK_IMAGE_LAYOUT_UNDEFINED.", |
| string_VkFormat(attachment.format)); |
| } |
| } |
| if (vkuFormatHasStencil(attachment.format) && create_info.pAttachments[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD) { |
| if (attachment.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-pNext-06704" : "VUID-VkAttachmentDescription-format-06700"; |
| skip |= LogError(vuid, device, attachment_loc, |
| "format (%s) includes stencil aspect and stencilLoadOp is VK_ATTACHMENT_LOAD_OP_LOAD, but " |
| "the initialLayout is VK_IMAGE_LAYOUT_UNDEFINED.", |
| string_VkFormat(attachment.format)); |
| } |
| |
| // rp2 can have seperate depth/stencil layout and need to look in pNext |
| if (attachment_description_stencil_layout) { |
| if (attachment_description_stencil_layout->stencilInitialLayout == VK_IMAGE_LAYOUT_UNDEFINED) { |
| skip |= |
| LogError("VUID-VkAttachmentDescription2-pNext-06705", device, attachment_loc, |
| "format includes stencil aspect and stencilLoadOp is VK_ATTACHMENT_LOAD_OP_LOAD, but " |
| "the VkAttachmentDescriptionStencilLayout::stencilInitialLayout is VK_IMAGE_LAYOUT_UNDEFINED."); |
| } |
| } |
| } |
| |
| const VkAttachmentDescriptionFlags both_skip_enable_transfer_flags = |
| VK_ATTACHMENT_DESCRIPTION_RESOLVE_SKIP_TRANSFER_FUNCTION_BIT_KHR | |
| VK_ATTACHMENT_DESCRIPTION_RESOLVE_ENABLE_TRANSFER_FUNCTION_BIT_KHR; |
| if ((attachment.flags & both_skip_enable_transfer_flags) == both_skip_enable_transfer_flags) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-flags-11773" : "VUID-VkAttachmentDescription-flags-11773"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::flags), "is %s.", |
| string_VkAttachmentDescriptionFlags(attachment.flags).c_str()); |
| } |
| |
| if ((attachment.flags & (VK_ATTACHMENT_DESCRIPTION_RESOLVE_SKIP_TRANSFER_FUNCTION_BIT_KHR | |
| VK_ATTACHMENT_DESCRIPTION_RESOLVE_ENABLE_TRANSFER_FUNCTION_BIT_KHR)) != 0) { |
| if (!enabled_features.maintenance10) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-flags-11775" : "VUID-VkAttachmentDescription-flags-11775"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::flags), "is %s but maintenance10 feature is not enabled.", |
| string_VkAttachmentDescriptionFlags(attachment.flags).c_str()); |
| } else if (!phys_dev_ext_props.maintenance10_props.resolveSrgbFormatSupportsTransferFunctionControl) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-flags-11774" : "VUID-VkAttachmentDescription-flags-11774"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::flags), |
| "is %s but resolveSrgbFormatSupportsTransferFunctionControl feature is not supported.", |
| string_VkAttachmentDescriptionFlags(attachment.flags).c_str()); |
| } |
| |
| if (!vkuFormatIsSRGB(attachment.format)) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-flags-11776" : "VUID-VkAttachmentDescription-flags-11776"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::format), "is %s but %s is %s.", |
| string_VkFormat(attachment.format), attachment_loc.dot(Field::flags).Fields().c_str(), |
| string_VkAttachmentDescriptionFlags(attachment.flags).c_str()); |
| } |
| |
| if (attachment.samples != VK_SAMPLE_COUNT_1_BIT) { |
| vuid = use_rp2 ? "VUID-VkAttachmentDescription2-flags-11777" : "VUID-VkAttachmentDescription-flags-11777"; |
| skip |= LogError(vuid, device, attachment_loc.dot(Field::samples), "is %s but %s is %s.", |
| string_VkSampleCountFlags(attachment.samples).c_str(), |
| attachment_loc.dot(Field::flags).Fields().c_str(), |
| string_VkAttachmentDescriptionFlags(attachment.flags).c_str()); |
| } |
| } |
| } |
| |
| for (uint32_t i = 0; i < create_info.subpassCount; ++i) { |
| const VkSubpassDescription2 &subpass_desc = create_info.pSubpasses[i]; |
| if (subpass_desc.colorAttachmentCount > phys_dev_props.limits.maxColorAttachments) { |
| vuid = use_rp2 ? "VUID-VkSubpassDescription2-colorAttachmentCount-00845" |
| : "VUID-VkSubpassDescription-colorAttachmentCount-00845"; |
| skip |= LogError(vuid, device, create_info_loc.dot(Field::pSubpasses, i).dot(Field::colorAttachmentCount), |
| "(%" PRIu32 ") is greater than maxColorAttachments (%" PRIu32 ").", subpass_desc.colorAttachmentCount, |
| phys_dev_props.limits.maxColorAttachments); |
| } |
| |
| if (subpass_desc.inputAttachmentCount > phys_dev_props.limits.maxPerStageDescriptorInputAttachments) { |
| vuid = use_rp2 ? "VUID-VkSubpassDescription2-inputAttachmentCount-12293" |
| : "VUID-VkSubpassDescription-inputAttachmentCount-12293"; |
| skip |= LogError(vuid, device, create_info_loc.dot(Field::pSubpasses, i).dot(Field::inputAttachmentCount), |
| "(%" PRIu32 ") is greater than maxPerStageDescriptorInputAttachments (%" PRIu32 ").", |
| subpass_desc.inputAttachmentCount, phys_dev_props.limits.maxPerStageDescriptorInputAttachments); |
| } |
| } |
| |
| for (uint32_t i = 0; i < create_info.dependencyCount; ++i) { |
| const VkSubpassDependency2 &dependency = create_info.pDependencies[i]; |
| const Location dependency_loc = create_info_loc.dot(Field::pDependencies, i); |
| |
| // Need to check first so layer doesn't segfault from out of bound array access |
| // src subpass bound check |
| if ((dependency.srcSubpass != VK_SUBPASS_EXTERNAL) && (dependency.srcSubpass >= create_info.subpassCount)) { |
| vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2-srcSubpass-02526" : "VUID-VkRenderPassCreateInfo-pDependencies-06866"; |
| skip |= LogError(vuid, device, dependency_loc.dot(Field::srcSubpass), |
| "index (%" PRIu32 ") has to be less than subpassCount (%" PRIu32 ")", dependency.srcSubpass, |
| create_info.subpassCount); |
| } |
| |
| // dst subpass bound check |
| if ((dependency.dstSubpass != VK_SUBPASS_EXTERNAL) && (dependency.dstSubpass >= create_info.subpassCount)) { |
| vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2-dstSubpass-02527" : "VUID-VkRenderPassCreateInfo-pDependencies-06867"; |
| skip |= LogError(vuid, device, dependency_loc.dot(Field::dstSubpass), |
| "index (%" PRIu32 ") has to be less than subpassCount (%" PRIu32 ")", dependency.dstSubpass, |
| create_info.subpassCount); |
| } |
| |
| VkPipelineStageFlags2 effective_src_stage_mask = dependency.srcStageMask; |
| VkPipelineStageFlags2 effective_dst_stage_mask = dependency.dstStageMask; |
| if (const auto barrier = vku::FindStructInPNextChain<VkMemoryBarrier2>(create_info.pDependencies[i].pNext)) { |
| effective_src_stage_mask = barrier->srcStageMask; |
| effective_dst_stage_mask = barrier->dstStageMask; |
| } |
| |
| // Spec currently only supports Graphics pipeline in render pass -- so only that pipeline is currently checked |
| vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2-pDependencies-03054" : "VUID-VkRenderPassCreateInfo-pDependencies-00837"; |
| skip |= ValidateSubpassGraphicsFlags(create_info, dependency.srcSubpass, effective_src_stage_mask, vuid, |
| dependency_loc.dot(Field::srcSubpass)); |
| |
| vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2-pDependencies-03055" : "VUID-VkRenderPassCreateInfo-pDependencies-00838"; |
| skip |= ValidateSubpassGraphicsFlags(create_info, dependency.dstSubpass, effective_dst_stage_mask, vuid, |
| dependency_loc.dot(Field::dstSubpass)); |
| } |
| |
| if ((create_info.flags & VK_RENDER_PASS_CREATE_PER_LAYER_FRAGMENT_DENSITY_BIT_VALVE) != 0 && |
| !enabled_features.fragmentDensityMapLayered) { |
| vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2-fragmentDensityMapLayered-10829" |
| : "VUID-VkRenderPassCreateInfo-fragmentDensityMapLayered-10828"; |
| skip |= LogError(vuid, device, create_info_loc.dot(Field::flags), |
| "contains VK_RENDER_PASS_CREATE_PER_LAYER_FRAGMENT_DENSITY_BIT_VALVE, but fragmentDensityMapLayered " |
| "feature was not enabled."); |
| } |
| |
| if (const auto tile_memory_size = vku::FindStructInPNextChain<VkTileMemorySizeInfoQCOM>(create_info.pNext)) { |
| skip |= ValidateTileMemorySizeInfo(*tile_memory_size, create_info_loc); |
| } |
| |
| return skip; |
| } |
| |
| bool Device::manual_PreCallValidateCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass, |
| const Context &context) const { |
| vku::safe_VkRenderPassCreateInfo2 create_info_2 = ConvertVkRenderPassCreateInfoToV2KHR(*pCreateInfo); |
| return ValidateCreateRenderPass(*create_info_2.ptr(), context.error_obj); |
| } |
| |
| bool Device::manual_PreCallValidateCreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass, |
| const Context &context) const { |
| vku::safe_VkRenderPassCreateInfo2 create_info_2(pCreateInfo); |
| return ValidateCreateRenderPass(*create_info_2.ptr(), context.error_obj); |
| } |
| |
| void Device::RecordRenderPass(VkRenderPass renderPass, const VkRenderPassCreateInfo2 &create_info) { |
| std::unique_lock<std::mutex> lock(renderpass_map_mutex); |
| auto &renderpass_state = renderpasses_states[renderPass]; |
| lock.unlock(); |
| |
| for (uint32_t subpass = 0; subpass < create_info.subpassCount; ++subpass) { |
| const VkSubpassDescription2 &subpass_desc = create_info.pSubpasses[subpass]; |
| |
| for (uint32_t i = 0; i < subpass_desc.colorAttachmentCount; ++i) { |
| if (subpass_desc.pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) { |
| renderpass_state.subpasses_using_color_attachment.insert(subpass); |
| break; |
| } |
| } |
| |
| if (subpass_desc.pDepthStencilAttachment && subpass_desc.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { |
| renderpass_state.subpasses_using_depthstencil_attachment.insert(subpass); |
| } |
| } |
| } |
| void Device::PostCallRecordCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass, |
| const RecordObject &record_obj) { |
| if (record_obj.result != VK_SUCCESS) { |
| return; |
| } |
| vku::safe_VkRenderPassCreateInfo2 create_info_2 = ConvertVkRenderPassCreateInfoToV2KHR(*pCreateInfo); |
| RecordRenderPass(*pRenderPass, *create_info_2.ptr()); |
| } |
| |
| void Device::PostCallRecordCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass, |
| const RecordObject &record_obj) { |
| // Track the state necessary for checking vkCreateGraphicsPipeline (subpass usage of depth and color attachments) |
| if (record_obj.result != VK_SUCCESS) { |
| return; |
| } |
| vku::safe_VkRenderPassCreateInfo2 create_info_2(pCreateInfo); |
| RecordRenderPass(*pRenderPass, *create_info_2.ptr()); |
| } |
| |
| void Device::PostCallRecordDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator, |
| const RecordObject &record_obj) { |
| // Track the state necessary for checking vkCreateGraphicsPipeline (subpass usage of depth and color attachments) |
| std::unique_lock<std::mutex> lock(renderpass_map_mutex); |
| renderpasses_states.erase(renderPass); |
| } |
| |
| bool Device::ValidateRenderPassStripeBeginInfo(VkCommandBuffer commandBuffer, const void *pNext, const VkRect2D render_area, |
| const Location &loc) const { |
| bool skip = false; |
| const auto rp_stripe_begin = vku::FindStructInPNextChain<VkRenderPassStripeBeginInfoARM>(pNext); |
| if (!rp_stripe_begin) { |
| return skip; |
| } |
| |
| if (rp_stripe_begin->stripeInfoCount > phys_dev_ext_props.renderpass_striped_props.maxRenderPassStripes) { |
| skip |= LogError("VUID-VkRenderPassStripeBeginInfoARM-stripeInfoCount-09450", commandBuffer, |
| loc.pNext(Struct::VkRenderPassStripeBeginInfoARM, Field::stripeInfoCount), |
| "(%" PRIu32 ") is greater than maxRenderPassStripes (%" PRIu32 ").", rp_stripe_begin->stripeInfoCount, |
| phys_dev_ext_props.renderpass_striped_props.maxRenderPassStripes); |
| } |
| |
| const uint32_t width_granularity = phys_dev_ext_props.renderpass_striped_props.renderPassStripeGranularity.width; |
| const uint32_t height_granularity = phys_dev_ext_props.renderpass_striped_props.renderPassStripeGranularity.height; |
| const uint32_t last_stripe_index = (rp_stripe_begin->stripeInfoCount - 1); |
| uint32_t total_stripe_area = 0; |
| bool has_overlapping_stripes = false; |
| |
| for (uint32_t i = 0; i < rp_stripe_begin->stripeInfoCount; ++i) { |
| const Location &stripe_info_loc = loc.pNext(Struct::VkRenderPassStripeBeginInfoARM, Field::pStripeInfos, i); |
| const VkRect2D stripe_area = rp_stripe_begin->pStripeInfos[i].stripeArea; |
| total_stripe_area += (stripe_area.extent.width * stripe_area.extent.height); |
| |
| // Check overlapping stripes, report only first overlapping stripe info. |
| for (uint32_t index = i + 1; (!has_overlapping_stripes && i != last_stripe_index && index <= last_stripe_index); ++index) { |
| const auto rect = rp_stripe_begin->pStripeInfos[index].stripeArea; |
| has_overlapping_stripes = |
| RangesIntersect(rect.offset.x, rect.extent.width, stripe_area.offset.x, stripe_area.extent.width); |
| has_overlapping_stripes &= |
| RangesIntersect(rect.offset.y, rect.extent.height, stripe_area.offset.y, stripe_area.extent.height); |
| |
| if (has_overlapping_stripes) { |
| skip |= LogError("VUID-VkRenderPassStripeBeginInfoARM-stripeArea-09451", commandBuffer, stripe_info_loc, |
| "(offset{%s} extent{%s}) is overlapping with pStripeInfos[%" PRIu32 "] (offset{%s} extent {%s}).", |
| string_VkOffset2D(stripe_area.offset).c_str(), string_VkExtent2D(stripe_area.extent).c_str(), |
| index, string_VkOffset2D(rect.offset).c_str(), string_VkExtent2D(rect.extent).c_str()); |
| break; |
| } |
| } |
| |
| if (width_granularity > 0 && !IsIntegerMultipleOf(stripe_area.offset.x, width_granularity)) { |
| skip |= LogError("VUID-VkRenderPassStripeInfoARM-stripeArea-09452", commandBuffer, |
| stripe_info_loc.dot(Field::stripeArea).dot(Field::offset).dot(Field::x), |
| "(%" PRIu32 ") is not a multiple of %" PRIu32 ".", stripe_area.offset.x, width_granularity); |
| } |
| |
| if (width_granularity > 0 && !IsIntegerMultipleOf(stripe_area.extent.width, width_granularity) && |
| ((stripe_area.extent.width + stripe_area.offset.x) != render_area.extent.width)) { |
| skip |= LogError("VUID-VkRenderPassStripeInfoARM-stripeArea-09453", commandBuffer, |
| stripe_info_loc.dot(Field::stripeArea).dot(Field::extent).dot(Field::width), |
| "(%" PRIu32 ") is not a multiple of %" PRIu32 |
| ", or when added to the stripeArea.offset.x is not equal render area width (%" PRIu32 ")", |
| stripe_area.extent.width, width_granularity, render_area.extent.width); |
| } |
| |
| if (height_granularity > 0 && !IsIntegerMultipleOf(stripe_area.offset.y, height_granularity)) { |
| skip |= LogError("VUID-VkRenderPassStripeInfoARM-stripeArea-09454", commandBuffer, |
| stripe_info_loc.dot(Field::stripeArea).dot(Field::offset).dot(Field::y), |
| "(%" PRIu32 ") is not a multiple of %" PRIu32 ".", stripe_area.offset.y, height_granularity); |
| } |
| |
| if (height_granularity > 0 && !IsIntegerMultipleOf(stripe_area.extent.height, height_granularity) && |
| (stripe_area.extent.height + stripe_area.offset.y) != render_area.extent.height) { |
| skip |= LogError("VUID-VkRenderPassStripeInfoARM-stripeArea-09455", commandBuffer, |
| stripe_info_loc.dot(Field::stripeArea).dot(Field::extent).dot(Field::height), |
| "(%" PRIu32 ") is not a multiple of %" PRIu32 |
| ", or when added to the stripeArea.offset.y is not equal to render area height (%" PRIu32 ")", |
| stripe_area.extent.height, height_granularity, render_area.extent.height); |
| } |
| } |
| |
| // Check render area coverage if there is no overlapping stripe. |
| const uint32_t total_render_area = render_area.extent.width * render_area.extent.height; |
| if (!has_overlapping_stripes && (total_stripe_area != total_render_area)) { |
| const std::string vuid = (loc.function == Func::vkCmdBeginRenderPass) ? "VUID-VkRenderPassBeginInfo-pNext-09539" |
| : "VUID-VkRenderingInfo-pNext-09535"; |
| skip |= LogError(vuid.data(), commandBuffer, loc.pNext(Struct::VkRenderPassStripeBeginInfoARM, Field::pStripeInfos), |
| "has total of stripe area of %" PRIu32 " is not covering whole render area of %" PRIu32 " (%s).", |
| total_stripe_area, total_render_area, string_VkExtent2D(render_area.extent).c_str()); |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateMultiviewPerViewRenderAreasRenderPassBeginInfo( |
| VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* rp_begin_info, const VkRenderingInfo* rendering_info, |
| const VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM& multiview_per_view_info, const Location& loc) const { |
| bool skip = false; |
| if (multiview_per_view_info.perViewRenderAreaCount != 0 && !enabled_features.multiviewPerViewRenderAreas) { |
| const char* vuid = rp_begin_info ? "VUID-VkRenderPassBeginInfo-perViewRenderAreaCount-07859" |
| : "VUID-VkRenderingInfo-perViewRenderAreaCount-07857"; |
| skip |= LogError(vuid, commandBuffer, |
| loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM).dot(Field::perViewRenderAreaCount), |
| "is %" PRIu32 " but the multiviewPerViewRenderAreas feature was not enabled.", |
| multiview_per_view_info.perViewRenderAreaCount); |
| } |
| |
| if (rendering_info) { |
| const uint32_t msb = (uint32_t)MostSignificantBit(rendering_info->viewMask); |
| if (multiview_per_view_info.perViewRenderAreaCount != msb + 1) { |
| skip |= LogError( |
| "VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-pNext-07866", commandBuffer, |
| loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM).dot(Field::perViewRenderAreaCount), |
| "(%" PRIu32 ") must be VkRenderingInfo::viewMask (0x%" PRIx32 ") most significant bit index (%" PRIu32 ") + 1", |
| multiview_per_view_info.perViewRenderAreaCount, rendering_info->viewMask, msb); |
| } |
| } |
| |
| const VkRect2D full_render_area = rendering_info ? rendering_info->renderArea : rp_begin_info->renderArea; |
| |
| for (uint32_t i = 0; i < multiview_per_view_info.perViewRenderAreaCount; i++) { |
| const VkRect2D view_rect = multiview_per_view_info.pPerViewRenderAreas[i]; |
| if (view_rect.offset.x < 0) { |
| skip |= LogError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-offset-07861", commandBuffer, |
| loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM) |
| .dot(Field::pPerViewRenderAreas, i) |
| .dot(Field::offset) |
| .dot(Field::x), |
| "(%" PRId32 ") is less than zero.", view_rect.offset.x); |
| } |
| if (view_rect.offset.y < 0) { |
| skip |= LogError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-offset-07862", commandBuffer, |
| loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM) |
| .dot(Field::pPerViewRenderAreas, i) |
| .dot(Field::offset) |
| .dot(Field::y), |
| "(%" PRId32 ") is less than zero.", view_rect.offset.y); |
| } |
| if ((view_rect.offset.x + view_rect.extent.width) > phys_dev_props.limits.maxFramebufferWidth) { |
| skip |= LogError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-offset-07863", commandBuffer, |
| loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM) |
| .dot(Field::pPerViewRenderAreas, i) |
| .dot(Field::offset) |
| .dot(Field::x), |
| "%" PRId32 " + extent.width (%" PRIu32 ") greater than maxFramebufferWidth (%" PRIu32 ").", |
| view_rect.offset.x, view_rect.extent.width, phys_dev_props.limits.maxFramebufferWidth); |
| } |
| if ((view_rect.offset.y + view_rect.extent.height) > phys_dev_props.limits.maxFramebufferHeight) { |
| skip |= LogError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-offset-07864", commandBuffer, |
| loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM) |
| .dot(Field::pPerViewRenderAreas, i) |
| .dot(Field::offset) |
| .dot(Field::y), |
| "%" PRId32 " + extent.height (%" PRIu32 ") greater than maxFramebufferHeight (%" PRIu32 ").", |
| view_rect.offset.y, view_rect.extent.height, phys_dev_props.limits.maxFramebufferHeight); |
| } |
| |
| if (!ContainsRect(full_render_area, view_rect)) { |
| const char* vuid = rp_begin_info ? "VUID-VkRenderPassBeginInfo-perViewRenderAreaCount-07860" |
| : "VUID-VkRenderingInfo-perViewRenderAreaCount-07858"; |
| skip |= |
| LogError(vuid, commandBuffer, |
| loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM).dot(Field::pPerViewRenderAreas, i), |
| "(%s) is not contained in %s::renderArea (%s)", string_VkRect2D(view_rect).c_str(), |
| rendering_info ? "VkRenderingInfo" : "VkRenderPassBeginInfo", string_VkRect2D(full_render_area).c_str()); |
| } |
| } |
| return skip; |
| } |
| |
| bool Device::ValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *const rp_begin, |
| const ErrorObject &error_obj) const { |
| bool skip = false; |
| if ((rp_begin->clearValueCount != 0) && !rp_begin->pClearValues) { |
| const LogObjectList objlist(commandBuffer, rp_begin->renderPass); |
| skip |= LogError("VUID-VkRenderPassBeginInfo-clearValueCount-04962", objlist, |
| error_obj.location.dot(Field::pRenderPassBegin).dot(Field::clearValueCount), |
| "(%" PRIu32 ") is not zero, but pRenderPassBegin->pClearValues is NULL.", rp_begin->clearValueCount); |
| } |
| |
| const Location loc = error_obj.location.dot(Field::pRenderPassBegin); |
| skip |= ValidateRenderPassStripeBeginInfo(commandBuffer, rp_begin->pNext, rp_begin->renderArea, loc); |
| |
| if (const auto multiview_per_view_info = |
| vku::FindStructInPNextChain<VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM>(rp_begin->pNext)) { |
| skip |= |
| ValidateMultiviewPerViewRenderAreasRenderPassBeginInfo(commandBuffer, rp_begin, nullptr, *multiview_per_view_info, loc); |
| } |
| |
| return skip; |
| } |
| |
| bool Device::manual_PreCallValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, |
| VkSubpassContents, const Context &context) const { |
| return ValidateCmdBeginRenderPass(commandBuffer, pRenderPassBegin, context.error_obj); |
| } |
| |
| bool Device::manual_PreCallValidateCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, |
| const VkSubpassBeginInfo *, const Context &context) const { |
| return ValidateCmdBeginRenderPass(commandBuffer, pRenderPassBegin, context.error_obj); |
| } |
| |
| static bool UniqueRenderingInfoImageViews(const VkRenderingInfo &rendering_info, VkImageView image_view) { |
| bool unique_views = true; |
| for (uint32_t i = 0; i < rendering_info.colorAttachmentCount; ++i) { |
| if (rendering_info.pColorAttachments[i].imageView == image_view) { |
| unique_views = false; |
| } |
| |
| if (rendering_info.pColorAttachments[i].resolveImageView == image_view) { |
| unique_views = false; |
| } |
| } |
| |
| if (rendering_info.pDepthAttachment) { |
| if (rendering_info.pDepthAttachment->imageView == image_view) { |
| unique_views = false; |
| } |
| |
| if (rendering_info.pDepthAttachment->resolveImageView == image_view) { |
| unique_views = false; |
| } |
| } |
| |
| if (rendering_info.pStencilAttachment) { |
| if (rendering_info.pStencilAttachment->imageView == image_view) { |
| unique_views = false; |
| } |
| |
| if (rendering_info.pStencilAttachment->resolveImageView == image_view) { |
| unique_views = false; |
| } |
| } |
| return unique_views; |
| } |
| |
| bool Device::manual_PreCallValidateCmdBeginRendering(VkCommandBuffer commandBuffer, const VkRenderingInfo *pRenderingInfo, |
| const Context &context) const { |
| bool skip = false; |
| const auto &error_obj = context.error_obj; |
| const Location rendering_info_loc = error_obj.location.dot(Field::pRenderingInfo); |
| |
| if (!enabled_features.dynamicRendering) { |
| skip |= LogError("VUID-vkCmdBeginRendering-dynamicRendering-06446", commandBuffer, error_obj.location, |
| "dynamicRendering is not enabled."); |
| } |
| |
| if (pRenderingInfo->viewMask == 0 && pRenderingInfo->layerCount == 0) { |
| skip |= LogError("VUID-VkRenderingInfo-viewMask-06069", commandBuffer, rendering_info_loc, |
| "viewMask and layerCount are both zero"); |
| } |
| |
| if (pRenderingInfo->colorAttachmentCount > phys_dev_props.limits.maxColorAttachments) { |
| skip |= LogError("VUID-VkRenderingInfo-colorAttachmentCount-06106", commandBuffer, |
| rendering_info_loc.dot(Field::colorAttachmentCount), |
| "(%" PRIu32 |
| ") must be less than or equal to " |
| "maxColorAttachments (%" PRIu32 ").", |
| pRenderingInfo->colorAttachmentCount, phys_dev_props.limits.maxColorAttachments); |
| } |
| |
| if ((pRenderingInfo->flags & VK_RENDERING_CONTENTS_INLINE_BIT_KHR) != 0 && !enabled_features.nestedCommandBuffer && |
| !enabled_features.maintenance7) { |
| skip |= LogError("VUID-VkRenderingInfo-flags-10012", commandBuffer, rendering_info_loc.dot(Field::flags), |
| "is %s, but nestedCommandBuffer and maintenance7 feature were not enabled.", |
| string_VkRenderingFlags(pRenderingInfo->flags).c_str()); |
| } |
| if ((pRenderingInfo->flags & (VK_RENDERING_CUSTOM_RESOLVE_BIT_EXT | VK_RENDERING_FRAGMENT_REGION_BIT_EXT)) != 0 && |
| !enabled_features.customResolve) { |
| skip |= |
| LogError("VUID-VkRenderingInfo-flags-11514", commandBuffer, rendering_info_loc.dot(Field::flags), |
| "is %s, but customResolve feature were not enabled.", string_VkRenderingFlags(pRenderingInfo->flags).c_str()); |
| } |
| if (pRenderingInfo->layerCount > phys_dev_props.limits.maxFramebufferLayers) { |
| skip |= LogError("VUID-VkRenderingInfo-layerCount-07817", commandBuffer, rendering_info_loc.dot(Field::layerCount), |
| "(%" PRIu32 ") is greater than maxFramebufferLayers (%" PRIu32 ").", pRenderingInfo->layerCount, |
| phys_dev_props.limits.maxFramebufferLayers); |
| } |
| |
| if (!enabled_features.multiview && (pRenderingInfo->viewMask != 0)) { |
| skip |= LogError("VUID-VkRenderingInfo-multiview-06127", commandBuffer, rendering_info_loc.dot(Field::viewMask), |
| "is 0x%" PRIx32 " (non-zero) but the multiview feature is not enabled.", pRenderingInfo->viewMask); |
| } |
| |
| if (pRenderingInfo->flags & VK_RENDERING_PER_LAYER_FRAGMENT_DENSITY_BIT_VALVE) { |
| if (!enabled_features.fragmentDensityMapLayered) { |
| skip |= LogError("VUID-VkRenderingInfo-fragmentDensityMapLayered-10827", commandBuffer, |
| rendering_info_loc.dot(Field::flags), |
| "contains VK_RENDERING_PER_LAYER_FRAGMENT_DENSITY_BIT_VALVE, but fragmentDensityMapLayered feature " |
| "was not enabled."); |
| } else if (pRenderingInfo->layerCount > phys_dev_ext_props.fragment_density_map_layered_props.maxFragmentDensityMapLayers) { |
| skip |= LogError("VUID-VkRenderingInfo-flags-10826", commandBuffer, rendering_info_loc.dot(Field::layerCount), |
| "is %" PRIu32 " but the maxFragmentDensityMapLayers is %" PRIu32 ".", pRenderingInfo->layerCount, |
| phys_dev_ext_props.fragment_density_map_layered_props.maxFragmentDensityMapLayers); |
| } |
| } |
| |
| const auto rendering_fsr_attachment_info = |
| vku::FindStructInPNextChain<VkRenderingFragmentShadingRateAttachmentInfoKHR>(pRenderingInfo->pNext); |
| if (rendering_fsr_attachment_info) { |
| skip |= ValidateBeginRenderingFragmentShadingRateAttachment(commandBuffer, *pRenderingInfo, *rendering_fsr_attachment_info, |
| rendering_info_loc); |
| } |
| |
| const auto fragment_density_map_attachment_info = |
| vku::FindStructInPNextChain<VkRenderingFragmentDensityMapAttachmentInfoEXT>(pRenderingInfo->pNext); |
| if (fragment_density_map_attachment_info && (fragment_density_map_attachment_info->imageView != VK_NULL_HANDLE)) { |
| if (UniqueRenderingInfoImageViews(*pRenderingInfo, fragment_density_map_attachment_info->imageView) == false) { |
| skip |= LogError("VUID-VkRenderingInfo-imageView-06116", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentDensityMapAttachmentInfoEXT, Field::imageView), |
| "is %s.", FormatHandle(fragment_density_map_attachment_info->imageView).c_str()); |
| } |
| |
| if (fragment_density_map_attachment_info->imageLayout != VK_IMAGE_LAYOUT_GENERAL && |
| fragment_density_map_attachment_info->imageLayout != VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT) { |
| skip |= LogError("VUID-VkRenderingFragmentDensityMapAttachmentInfoEXT-imageView-06157", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentDensityMapAttachmentInfoEXT, Field::imageView), |
| "is %s, but " |
| "VkRenderingFragmentDensityMapAttachmentInfoEXT::imageLayout is %s.", |
| FormatHandle(fragment_density_map_attachment_info->imageView).c_str(), |
| string_VkImageLayout(fragment_density_map_attachment_info->imageLayout)); |
| } |
| |
| if (rendering_fsr_attachment_info && |
| (rendering_fsr_attachment_info->imageView == fragment_density_map_attachment_info->imageView)) { |
| skip |= LogError("VUID-VkRenderingInfo-imageView-06126", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentDensityMapAttachmentInfoEXT, Field::imageView), |
| "and VkRenderingFragmentShadingRateAttachmentInfoKHR::imageView are the same (%s).", |
| FormatHandle(fragment_density_map_attachment_info->imageView).c_str()); |
| } |
| } |
| |
| if (const auto multiview_per_view_info = |
| vku::FindStructInPNextChain<VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM>(pRenderingInfo->pNext)) { |
| skip |= ValidateMultiviewPerViewRenderAreasRenderPassBeginInfo(commandBuffer, nullptr, pRenderingInfo, |
| *multiview_per_view_info, rendering_info_loc); |
| } |
| |
| skip |= ValidateRenderPassStripeBeginInfo(commandBuffer, pRenderingInfo->pNext, pRenderingInfo->renderArea, rendering_info_loc); |
| skip |= ValidateBeginRenderingColorAttachment(commandBuffer, *pRenderingInfo, rendering_info_loc); |
| skip |= ValidateBeginRenderingDepthAttachment(commandBuffer, *pRenderingInfo, rendering_info_loc); |
| skip |= ValidateBeginRenderingStencilAttachment(commandBuffer, *pRenderingInfo, rendering_info_loc); |
| skip |= ValidateBeginRenderingAttachmentFlagsInfo(commandBuffer, *pRenderingInfo, rendering_info_loc); |
| return skip; |
| } |
| |
| bool Device::ValidateRenderingAttachmentLayout(VkCommandBuffer commandBuffer, const VkRenderingAttachmentInfo &attachment_info, |
| const Location &attachment_loc) const { |
| bool skip = false; |
| |
| if (attachment_info.imageLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { |
| const LogObjectList objlist(commandBuffer, attachment_info.imageView); |
| skip |= LogError("VUID-VkRenderingAttachmentInfo-imageView-06145", objlist, attachment_loc.dot(Field::imageLayout), |
| "must not be VK_IMAGE_LAYOUT_PRESENT_SRC_KHR"); |
| } else if (IsValueIn(attachment_info.imageLayout, {VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
| VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_ZERO_INITIALIZED_EXT})) { |
| const LogObjectList objlist(commandBuffer, attachment_info.imageView); |
| skip |= LogError("VUID-VkRenderingAttachmentInfo-imageView-06135", objlist, attachment_loc.dot(Field::imageLayout), |
| "is %s.", string_VkImageLayout(attachment_info.imageLayout)); |
| } |
| |
| if (attachment_info.imageLayout == VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR) { |
| const LogObjectList objlist(commandBuffer, attachment_info.imageView); |
| const char *vuid = IsExtEnabled(extensions.vk_khr_fragment_shading_rate) ? "VUID-VkRenderingAttachmentInfo-imageView-06143" |
| : "VUID-VkRenderingAttachmentInfo-imageView-06138"; |
| skip |= LogError(vuid, objlist, attachment_loc.dot(Field::imageLayout), |
| "must not be VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR (or the alias " |
| "VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV)"); |
| } |
| |
| if (attachment_info.imageLayout == VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT) { |
| const LogObjectList objlist(commandBuffer, attachment_info.imageView); |
| skip |= LogError("VUID-VkRenderingAttachmentInfo-imageView-06140", objlist, attachment_loc.dot(Field::imageLayout), |
| "must not be VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT"); |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateRenderingAttachmentFeedbackLoopInfo(VkCommandBuffer commandBuffer, |
| const VkRenderingAttachmentInfo &attachment_info, |
| const Location &attachment_loc) const { |
| bool skip = false; |
| |
| const auto attachment_feedback_loop_info = vku::FindStructInPNextChain<VkAttachmentFeedbackLoopInfoEXT>(attachment_info.pNext); |
| if (attachment_feedback_loop_info) { |
| if (attachment_feedback_loop_info->feedbackLoopEnable && !enabled_features.unifiedImageLayouts) { |
| skip |= LogError("VUID-VkAttachmentFeedbackLoopInfoEXT-unifiedImageLayouts-10782", commandBuffer, |
| attachment_loc.pNext(Struct::VkAttachmentFeedbackLoopInfoEXT, Field::feedbackLoopEnable), |
| "is VK_TRUE, but VkPhysicalDeviceUnifiedImageLayoutsFeaturesKHR::unifiedImageLayouts is not enabled."); |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateRenderingCustomResolve(VkCommandBuffer commandBuffer, VkRenderingFlags rendering_flags, |
| VkResolveModeFlagBits resolve_mode, const Location &attachment_loc) const { |
| bool skip = false; |
| |
| if (rendering_flags & VK_RENDERING_CUSTOM_RESOLVE_BIT_EXT) { |
| if (!IsValueIn(resolve_mode, {VK_RESOLVE_MODE_CUSTOM_BIT_EXT, VK_RESOLVE_MODE_NONE})) { |
| skip |= |
| LogError("VUID-VkRenderingInfo-flags-11516", commandBuffer, attachment_loc.dot(Field::resolveMode), |
| "is %s but VK_RENDERING_CUSTOM_RESOLVE_BIT_EXT flag is set.", string_VkResolveModeFlagBits(resolve_mode)); |
| } |
| } else if (resolve_mode == VK_RESOLVE_MODE_CUSTOM_BIT_EXT) { |
| skip |= |
| LogError("VUID-VkRenderingInfo-pColorAttachments-11515", commandBuffer, attachment_loc.dot(Field::resolveMode), |
| "is VK_RESOLVE_MODE_CUSTOM_BIT_EXT but VK_RENDERING_CUSTOM_RESOLVE_BIT_EXT flag is missing (flags set %s).", |
| string_VkRenderingFlags(rendering_flags).c_str()); |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateBeginRenderingColorAttachment(VkCommandBuffer commandBuffer, const VkRenderingInfo &rendering_info, |
| const Location &rendering_info_loc) const { |
| bool skip = false; |
| for (uint32_t i = 0; i < rendering_info.colorAttachmentCount; ++i) { |
| const VkRenderingAttachmentInfo &color_attachment = rendering_info.pColorAttachments[i]; |
| if (color_attachment.imageView == VK_NULL_HANDLE) continue; |
| const Location color_attachment_loc = rendering_info_loc.dot(Field::pColorAttachments, i); |
| |
| const VkResolveModeFlagBits resolve_mode = color_attachment.resolveMode; |
| skip |= ValidateRenderingAttachmentFeedbackLoopInfo(commandBuffer, color_attachment, color_attachment_loc); |
| skip |= ValidateRenderingAttachmentLayout(commandBuffer, color_attachment, color_attachment_loc); |
| skip |= ValidateRenderingCustomResolve(commandBuffer, rendering_info.flags, resolve_mode, color_attachment_loc); |
| |
| const VkImageLayout image_layout = color_attachment.imageLayout; |
| if (image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || |
| image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) { |
| skip |= LogError("VUID-VkRenderingInfo-colorAttachmentCount-06090", commandBuffer, |
| color_attachment_loc.dot(Field::imageLayout), "is %s.", string_VkImageLayout(image_layout)); |
| } |
| |
| const VkImageLayout resolve_image_layout = color_attachment.resolveImageLayout; |
| if (resolve_mode != VK_RESOLVE_MODE_NONE) { |
| if (resolve_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || |
| resolve_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) { |
| skip |= LogError("VUID-VkRenderingInfo-colorAttachmentCount-06091", commandBuffer, |
| color_attachment_loc.dot(Field::resolveImageLayout), "is %s and resolveMode is %s.", |
| string_VkImageLayout(resolve_image_layout), string_VkResolveModeFlagBits(resolve_mode)); |
| } |
| } |
| |
| if (IsExtEnabled(extensions.vk_khr_maintenance2)) { |
| if (image_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL || |
| image_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) { |
| skip |= LogError("VUID-VkRenderingInfo-colorAttachmentCount-06096", commandBuffer, |
| color_attachment_loc.dot(Field::imageLayout), "is %s.", string_VkImageLayout(image_layout)); |
| } |
| |
| if (resolve_mode != VK_RESOLVE_MODE_NONE) { |
| if (resolve_image_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL || |
| resolve_image_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) { |
| skip |= LogError("VUID-VkRenderingInfo-colorAttachmentCount-06097", commandBuffer, |
| color_attachment_loc.dot(Field::resolveImageLayout), "is %s and resolveMode is %s.", |
| string_VkImageLayout(resolve_image_layout), string_VkResolveModeFlagBits(resolve_mode)); |
| } |
| } |
| } |
| |
| if (IsImageLayoutDepthOnly(image_layout) || IsImageLayoutStencilOnly(image_layout)) { |
| skip |= LogError("VUID-VkRenderingInfo-colorAttachmentCount-06100", commandBuffer, |
| color_attachment_loc.dot(Field::imageLayout), "is %s.", string_VkImageLayout(image_layout)); |
| } |
| |
| if (resolve_mode != VK_RESOLVE_MODE_NONE) { |
| if (resolve_image_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL || |
| resolve_image_layout == VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL) { |
| skip |= LogError("VUID-VkRenderingInfo-colorAttachmentCount-06101", commandBuffer, |
| color_attachment_loc.dot(Field::resolveImageLayout), "is %s and resolveMode is %s.", |
| string_VkImageLayout(resolve_image_layout), string_VkResolveModeFlagBits(resolve_mode)); |
| } |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateBeginRenderingDepthAttachment(VkCommandBuffer commandBuffer, const VkRenderingInfo &rendering_info, |
| const Location &rendering_info_loc) const { |
| bool skip = false; |
| if (!rendering_info.pDepthAttachment || rendering_info.pDepthAttachment->imageView == VK_NULL_HANDLE) return skip; |
| |
| const VkRenderingAttachmentInfo &depth_attachment = *rendering_info.pDepthAttachment; |
| const Location attachment_loc = rendering_info_loc.dot(Field::pDepthAttachment); |
| |
| skip |= ValidateRenderingAttachmentFeedbackLoopInfo(commandBuffer, depth_attachment, attachment_loc); |
| skip |= ValidateRenderingAttachmentLayout(commandBuffer, depth_attachment, attachment_loc); |
| skip |= ValidateRenderingCustomResolve(commandBuffer, rendering_info.flags, depth_attachment.resolveMode, attachment_loc); |
| |
| if (depth_attachment.imageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { |
| skip |= LogError("VUID-VkRenderingInfo-pDepthAttachment-06092", commandBuffer, attachment_loc.dot(Field::imageLayout), |
| "is VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL."); |
| } else if (IsImageLayoutStencilOnly(depth_attachment.imageLayout)) { |
| skip |= LogError("VUID-VkRenderingInfo-pDepthAttachment-07732", commandBuffer, attachment_loc.dot(Field::imageLayout), |
| "is %s.", string_VkImageLayout(depth_attachment.imageLayout)); |
| } |
| |
| if (depth_attachment.resolveMode != VK_RESOLVE_MODE_NONE) { |
| const VkImageLayout resolve_layout = depth_attachment.resolveImageLayout; |
| if (resolve_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { |
| skip |= LogError("VUID-VkRenderingInfo-pDepthAttachment-06093", commandBuffer, |
| attachment_loc.dot(Field::resolveImageLayout), |
| "is VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL and resolveMode is %s.", |
| string_VkResolveModeFlagBits(depth_attachment.resolveMode)); |
| } else if (IsImageLayoutStencilOnly(resolve_layout)) { |
| skip |= LogError("VUID-VkRenderingInfo-pDepthAttachment-07733", commandBuffer, |
| attachment_loc.dot(Field::resolveImageLayout), "is %s and resolveMode is %s.", |
| string_VkImageLayout(resolve_layout), string_VkResolveModeFlagBits(depth_attachment.resolveMode)); |
| } |
| |
| if (IsExtEnabled(extensions.vk_khr_maintenance2) && |
| resolve_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) { |
| skip |= LogError("VUID-VkRenderingInfo-pDepthAttachment-06098", commandBuffer, |
| attachment_loc.dot(Field::resolveImageLayout), |
| "is VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL."); |
| } |
| |
| if (!(depth_attachment.resolveMode & phys_dev_props_core12.supportedDepthResolveModes)) { |
| skip |= |
| LogError("VUID-VkRenderingInfo-pDepthAttachment-06102", commandBuffer, attachment_loc.dot(Field::resolveMode), |
| "is %s, but supportedDepthResolveModes is %s.", string_VkResolveModeFlagBits(depth_attachment.resolveMode), |
| string_VkResolveModeFlags(phys_dev_props_core12.supportedDepthResolveModes).c_str()); |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateBeginRenderingStencilAttachment(VkCommandBuffer commandBuffer, const VkRenderingInfo &rendering_info, |
| const Location &rendering_info_loc) const { |
| bool skip = false; |
| if (!rendering_info.pStencilAttachment || rendering_info.pStencilAttachment->imageView == VK_NULL_HANDLE) return skip; |
| |
| const VkRenderingAttachmentInfo &stencil_attachment = *rendering_info.pStencilAttachment; |
| const Location attachment_loc = rendering_info_loc.dot(Field::pStencilAttachment); |
| |
| skip |= ValidateRenderingAttachmentFeedbackLoopInfo(commandBuffer, stencil_attachment, attachment_loc); |
| skip |= ValidateRenderingAttachmentLayout(commandBuffer, stencil_attachment, attachment_loc); |
| skip |= ValidateRenderingCustomResolve(commandBuffer, rendering_info.flags, stencil_attachment.resolveMode, attachment_loc); |
| |
| if (stencil_attachment.imageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { |
| skip |= LogError("VUID-VkRenderingInfo-pStencilAttachment-06094", commandBuffer, attachment_loc.dot(Field::imageLayout), |
| "is VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL."); |
| } else if (IsImageLayoutDepthOnly(stencil_attachment.imageLayout)) { |
| skip |= LogError("VUID-VkRenderingInfo-pStencilAttachment-07734", commandBuffer, attachment_loc.dot(Field::imageLayout), |
| "is %s.", string_VkImageLayout(stencil_attachment.imageLayout)); |
| } |
| |
| if (stencil_attachment.resolveMode != VK_RESOLVE_MODE_NONE) { |
| const VkImageLayout resolve_layout = stencil_attachment.resolveImageLayout; |
| if (resolve_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { |
| skip |= LogError("VUID-VkRenderingInfo-pStencilAttachment-06095", commandBuffer, |
| attachment_loc.dot(Field::resolveImageLayout), |
| "is VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL and resolveMode is %s.", |
| string_VkResolveModeFlagBits(stencil_attachment.resolveMode)); |
| } else if (IsImageLayoutDepthOnly(resolve_layout)) { |
| skip |= LogError("VUID-VkRenderingInfo-pStencilAttachment-07735", commandBuffer, |
| attachment_loc.dot(Field::resolveImageLayout), "is %s and resolveMode is %s.", |
| string_VkImageLayout(resolve_layout), string_VkResolveModeFlagBits(stencil_attachment.resolveMode)); |
| } |
| |
| if (IsExtEnabled(extensions.vk_khr_maintenance2) && |
| resolve_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) { |
| skip |= LogError("VUID-VkRenderingInfo-pStencilAttachment-06099", commandBuffer, |
| attachment_loc.dot(Field::resolveImageLayout), |
| "is VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL."); |
| } |
| |
| if (!(stencil_attachment.resolveMode & phys_dev_props_core12.supportedStencilResolveModes)) { |
| skip |= LogError("VUID-VkRenderingInfo-pStencilAttachment-06103", commandBuffer, attachment_loc.dot(Field::resolveMode), |
| "is %s, but supportedStencilResolveModes is %s.", |
| string_VkResolveModeFlagBits(stencil_attachment.resolveMode), |
| string_VkResolveModeFlags(phys_dev_props_core12.supportedStencilResolveModes).c_str()); |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateBeginRenderingAttachmentFlagsInfo(VkCommandBuffer commandBuffer, const VkRenderingInfo &rendering_info, |
| const Location &rendering_info_loc) const { |
| bool skip = false; |
| if (rendering_info.flags & VK_RENDERING_LOCAL_READ_CONCURRENT_ACCESS_CONTROL_BIT_KHR) { |
| if (!enabled_features.maintenance10) { |
| skip |= LogError("VUID-vkCmdBeginRendering-pRenderingInfo-11750", commandBuffer, rendering_info_loc.dot(Field::flags), |
| "contains VK_RENDERING_LOCAL_READ_CONCURRENT_ACCESS_CONTROL_BIT_KHR, but maintenance10 feature " |
| "was not enabled."); |
| } |
| } else { |
| for (uint32_t i = 0; i < rendering_info.colorAttachmentCount; ++i) { |
| const VkRenderingAttachmentInfo &attachment_info = rendering_info.pColorAttachments[i]; |
| if (const auto flags_info = vku::FindStructInPNextChain<VkRenderingAttachmentFlagsInfoKHR>(attachment_info.pNext)) { |
| if (flags_info->flags & VK_RENDERING_ATTACHMENT_INPUT_ATTACHMENT_FEEDBACK_BIT_KHR) { |
| skip |= LogError("VUID-vkCmdBeginRendering-pRenderingInfo-11751", commandBuffer, |
| rendering_info_loc.dot(Field::pColorAttachments, i) |
| .pNext(Struct::VkRenderingAttachmentFlagsInfoKHR, Field::flags), |
| "is %s.", string_VkRenderingAttachmentFlagsKHR(flags_info->flags).c_str()); |
| } |
| } |
| } |
| if (rendering_info.pDepthAttachment) { |
| if (const auto flags_info = |
| vku::FindStructInPNextChain<VkRenderingAttachmentFlagsInfoKHR>(rendering_info.pDepthAttachment->pNext)) { |
| if (flags_info->flags & VK_RENDERING_ATTACHMENT_INPUT_ATTACHMENT_FEEDBACK_BIT_KHR) { |
| skip |= LogError("VUID-vkCmdBeginRendering-pRenderingInfo-11751", commandBuffer, |
| rendering_info_loc.dot(Field::pDepthAttachment) |
| .pNext(Struct::VkRenderingAttachmentFlagsInfoKHR, Field::flags), |
| "is %s.", string_VkRenderingAttachmentFlagsKHR(flags_info->flags).c_str()); |
| } |
| } |
| } |
| if (rendering_info.pStencilAttachment) { |
| if (const auto flags_info = |
| vku::FindStructInPNextChain<VkRenderingAttachmentFlagsInfoKHR>(rendering_info.pStencilAttachment->pNext)) { |
| if (flags_info->flags & VK_RENDERING_ATTACHMENT_INPUT_ATTACHMENT_FEEDBACK_BIT_KHR) { |
| skip |= LogError("VUID-vkCmdBeginRendering-pRenderingInfo-11751", commandBuffer, |
| rendering_info_loc.dot(Field::pStencilAttachment) |
| .pNext(Struct::VkRenderingAttachmentFlagsInfoKHR, Field::flags), |
| "is %s.", string_VkRenderingAttachmentFlagsKHR(flags_info->flags).c_str()); |
| } |
| } |
| } |
| } |
| |
| return skip; |
| } |
| |
| bool Device::ValidateBeginRenderingFragmentShadingRateAttachment( |
| VkCommandBuffer commandBuffer, const VkRenderingInfo &rendering_info, |
| const VkRenderingFragmentShadingRateAttachmentInfoKHR &rendering_fsr_attachment_info, |
| const Location &rendering_info_loc) const { |
| bool skip = false; |
| if (rendering_fsr_attachment_info.imageView == VK_NULL_HANDLE) return skip; |
| |
| if (UniqueRenderingInfoImageViews(rendering_info, rendering_fsr_attachment_info.imageView) == false) { |
| skip |= LogError("VUID-VkRenderingInfo-imageView-06125", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentShadingRateAttachmentInfoKHR, Field::imageView), |
| "is %s.", FormatHandle(rendering_fsr_attachment_info.imageView).c_str()); |
| } |
| |
| const VkImageLayout image_layout = rendering_fsr_attachment_info.imageLayout; |
| if (image_layout != VK_IMAGE_LAYOUT_GENERAL && image_layout != VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR) { |
| skip |= LogError("VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06147", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentShadingRateAttachmentInfoKHR, Field::layout), |
| "is (%s).", string_VkImageLayout(image_layout)); |
| } |
| |
| if (!IsPowerOfTwo(rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.width)) { |
| skip |= LogError( |
| "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06149", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentShadingRateAttachmentInfoKHR, Field::shadingRateAttachmentTexelSize) |
| .dot(Field::width), |
| "(%" PRIu32 ") must be a power of two.", rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.width); |
| } |
| |
| const uint32_t max_frs_attach_texel_width = |
| phys_dev_ext_props.fragment_shading_rate_props.maxFragmentShadingRateAttachmentTexelSize.width; |
| if (rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.width > max_frs_attach_texel_width) { |
| skip |= LogError( |
| "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06150", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentShadingRateAttachmentInfoKHR, Field::shadingRateAttachmentTexelSize) |
| .dot(Field::width), |
| "(%" PRIu32 |
| ") must be less than or equal to " |
| "maxFragmentShadingRateAttachmentTexelSize.width (%" PRIu32 ").", |
| rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.width, max_frs_attach_texel_width); |
| } |
| |
| const uint32_t min_frs_attach_texel_width = |
| phys_dev_ext_props.fragment_shading_rate_props.minFragmentShadingRateAttachmentTexelSize.width; |
| if (rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.width < min_frs_attach_texel_width) { |
| skip |= LogError( |
| "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06151", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentShadingRateAttachmentInfoKHR, Field::shadingRateAttachmentTexelSize) |
| .dot(Field::width), |
| "(%" PRIu32 |
| ") must be greater than or equal to " |
| "minFragmentShadingRateAttachmentTexelSize.width (%" PRIu32 ").", |
| rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.width, min_frs_attach_texel_width); |
| } |
| |
| if (!IsPowerOfTwo(rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.height)) { |
| skip |= LogError( |
| "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06152", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentShadingRateAttachmentInfoKHR, Field::shadingRateAttachmentTexelSize) |
| .dot(Field::height), |
| "(%" PRIu32 ") must be a power of two.", rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.height); |
| } |
| |
| const uint32_t max_frs_attach_texel_height = |
| phys_dev_ext_props.fragment_shading_rate_props.maxFragmentShadingRateAttachmentTexelSize.height; |
| if (rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.height > max_frs_attach_texel_height) { |
| skip |= LogError( |
| "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06153", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentShadingRateAttachmentInfoKHR, Field::shadingRateAttachmentTexelSize) |
| .dot(Field::height), |
| "(%" PRIu32 |
| ") must be less than or equal to " |
| "maxFragmentShadingRateAttachmentTexelSize.height (%" PRIu32 ").", |
| rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.height, max_frs_attach_texel_height); |
| } |
| |
| const uint32_t min_frs_attach_texel_height = |
| phys_dev_ext_props.fragment_shading_rate_props.minFragmentShadingRateAttachmentTexelSize.height; |
| if (rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.height < min_frs_attach_texel_height) { |
| skip |= LogError( |
| "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06154", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentShadingRateAttachmentInfoKHR, Field::shadingRateAttachmentTexelSize) |
| .dot(Field::height), |
| "(%" PRIu32 |
| ") must be greater than or equal to " |
| "minFragmentShadingRateAttachmentTexelSize.height (%" PRIu32 ").", |
| rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.height, min_frs_attach_texel_height); |
| } |
| |
| const uint32_t max_frs_attach_texel_aspect_ratio = |
| phys_dev_ext_props.fragment_shading_rate_props.maxFragmentShadingRateAttachmentTexelSizeAspectRatio; |
| if ((rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.width / |
| rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.height) > max_frs_attach_texel_aspect_ratio) { |
| skip |= LogError("VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06155", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentShadingRateAttachmentInfoKHR, |
| Field::shadingRateAttachmentTexelSize), |
| "the quotient of width (%" PRIu32 ") and height (%" PRIu32 |
| ") " |
| "must be less than or equal to maxFragmentShadingRateAttachmentTexelSizeAspectRatio (%" PRIu32 ").", |
| rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.width, |
| rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.height, max_frs_attach_texel_aspect_ratio); |
| } |
| |
| if ((rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.height / |
| rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.width) > max_frs_attach_texel_aspect_ratio) { |
| skip |= LogError("VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06156", commandBuffer, |
| rendering_info_loc.pNext(Struct::VkRenderingFragmentShadingRateAttachmentInfoKHR, |
| Field::shadingRateAttachmentTexelSize), |
| "the quotient of height (%" PRIu32 ") and width (%" PRIu32 |
| ") " |
| "must be less than or equal to maxFragmentShadingRateAttachmentTexelSizeAspectRatio (%" PRIu32 ").", |
| rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.height, |
| rendering_fsr_attachment_info.shadingRateAttachmentTexelSize.width, max_frs_attach_texel_aspect_ratio); |
| } |
| |
| return skip; |
| } |
| } // namespace stateless |