From 5980734456cf85a0f5e4123791161a2d888c87ba Mon Sep 17 00:00:00 2001 From: Tobias Hector Date: Mon, 22 Oct 2018 15:17:59 +0100 Subject: [PATCH 1/3] layers: Audited renderpass validation, added CRP2 To properly validate VK_KHR_create_renderpass2 (CRP2), the first step was to ensure all the validation for the v1 versions of each new function was up to scratch, as rather than effectively duplicating all the validation those calls have already, it made much more sense to add a switch and reuse the existing code where reasonable. --- build-android/cmake/layerlib/CMakeLists.txt | 1 + build-android/jni/Android.mk | 1 + layers/CMakeLists.txt | 2 +- layers/buffer_validation.cpp | 300 ++++++- layers/buffer_validation.h | 17 +- layers/convert_to_renderpass2.cpp | 202 +++++ layers/convert_to_renderpass2.h | 24 + layers/core_validation.cpp | 906 ++++++++++++++++---- layers/core_validation_types.h | 11 +- tests/layer_validation_tests.cpp | 32 +- 10 files changed, 1251 insertions(+), 245 deletions(-) create mode 100644 layers/convert_to_renderpass2.cpp create mode 100644 layers/convert_to_renderpass2.h diff --git a/build-android/cmake/layerlib/CMakeLists.txt b/build-android/cmake/layerlib/CMakeLists.txt index e9abd5c8aa1..69754b8ed41 100644 --- a/build-android/cmake/layerlib/CMakeLists.txt +++ b/build-android/cmake/layerlib/CMakeLists.txt @@ -62,6 +62,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_ANDROID_KHR \ -fvisibility=hidden") add_library(VkLayer_core_validation SHARED ${SRC_DIR}/layers/core_validation.cpp + ${SRC_DIR}/layers/convert_to_renderpass2.cpp ${SRC_DIR}/layers/descriptor_sets.cpp ${SRC_DIR}/layers/buffer_validation.cpp ${SRC_DIR}/layers/shader_validation.cpp diff --git a/build-android/jni/Android.mk b/build-android/jni/Android.mk index ebec08bd44a..39f04642a1e 100644 --- a/build-android/jni/Android.mk +++ b/build-android/jni/Android.mk @@ -39,6 +39,7 @@ LOCAL_SRC_FILES += $(SRC_DIR)/layers/core_validation.cpp LOCAL_SRC_FILES += $(SRC_DIR)/layers/descriptor_sets.cpp LOCAL_SRC_FILES += $(SRC_DIR)/layers/buffer_validation.cpp LOCAL_SRC_FILES += $(SRC_DIR)/layers/shader_validation.cpp +LOCAL_SRC_FILES += $(SRC_DIR)/layers/convert_to_renderpass2.cpp LOCAL_SRC_FILES += $(SRC_DIR)/layers/xxhash.c LOCAL_C_INCLUDES += $(VULKAN_INCLUDE) \ $(LOCAL_PATH)/$(SRC_DIR)/layers \ diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt index ebba94f443f..5fd5b44bdaf 100644 --- a/layers/CMakeLists.txt +++ b/layers/CMakeLists.txt @@ -178,7 +178,7 @@ GenerateFromVkXml(dispatch_table_helper_generator.py vk_dispatch_table_helper.h) GenerateFromVkXml(object_tracker_generator.py object_tracker.cpp) if(BUILD_LAYERS) - AddVkLayer(core_validation core_validation.cpp descriptor_sets.cpp buffer_validation.cpp shader_validation.cpp xxhash.c) + AddVkLayer(core_validation core_validation.cpp convert_to_renderpass2.cpp descriptor_sets.cpp buffer_validation.cpp shader_validation.cpp xxhash.c) AddVkLayer(object_tracker object_tracker.cpp object_tracker_utils.cpp) AddVkLayer(threading threading.cpp thread_check.h) AddVkLayer(unique_objects unique_objects.cpp unique_objects_wrappers.h) diff --git a/layers/buffer_validation.cpp b/layers/buffer_validation.cpp index d48a0db632e..bb7edf796e5 100644 --- a/layers/buffer_validation.cpp +++ b/layers/buffer_validation.cpp @@ -319,13 +319,116 @@ void SetImageViewLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, VkImag SetImageViewLayout(device_data, cb_node, view_state, layout); } -bool VerifyFramebufferAndRenderPassLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB, +bool ValidateRenderPassLayoutAgainstFramebufferImageUsage(layer_data *device_data, RenderPassCreateVersion rp_version, + VkImageLayout layout, VkImage image, VkImageView image_view, + VkFramebuffer framebuffer, VkRenderPass renderpass, + uint32_t attachment_index, const char *variable_name) { + bool skip = false; + const auto report_data = core_validation::GetReportData(device_data); + auto image_state = GetImageState(device_data, image); + const char *vuid; + const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); + + if (!image_state) { + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), + "VUID-VkRenderPassBeginInfo-framebuffer-parameter", + "Render Pass begin with renderpass 0x%" PRIx64 " uses framebuffer 0x%" PRIx64 " where pAttachments[%" PRIu32 + "] = image view 0x%" PRIx64 ", which refers to an invalid image", + HandleToUint64(renderpass), HandleToUint64(framebuffer), attachment_index, HandleToUint64(image_view)); + return skip; + } + + auto image_usage = image_state->createInfo.usage; + + // Check for layouts that mismatch image usages in the framebuffer + if (layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) { + vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03094" : "VUID-vkCmdBeginRenderPass-initialLayout-00895"; + skip |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid, + "Layout/usage mismatch for attachment %u in render pass 0x%" PRIx64 + " - the %s is %s but the image attached to framebuffer 0x%" PRIx64 " via image view 0x%" PRIx64 + " was not created with VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT", + attachment_index, HandleToUint64(framebuffer), variable_name, string_VkImageLayout(layout), + HandleToUint64(renderpass), HandleToUint64(image_view)); + } + + if (layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && + !(image_usage & (VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) { + vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03097" : "VUID-vkCmdBeginRenderPass-initialLayout-00897"; + skip |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid, + "Layout/usage mismatch for attachment %u in render pass 0x%" PRIx64 + " - the %s is %s but the image attached to framebuffer 0x%" PRIx64 " via image view 0x%" PRIx64 + " was not created with VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT or VK_IMAGE_USAGE_SAMPLED_BIT", + attachment_index, HandleToUint64(framebuffer), variable_name, string_VkImageLayout(layout), + HandleToUint64(renderpass), HandleToUint64(image_view)); + } + + if (layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) { + vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03098" : "VUID-vkCmdBeginRenderPass-initialLayout-00898"; + skip |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid, + "Layout/usage mismatch for attachment %u in render pass 0x%" PRIx64 + " - the %s is %s but the image attached to framebuffer 0x%" PRIx64 " via image view 0x%" PRIx64 + " was not created with VK_IMAGE_USAGE_TRANSFER_SRC_BIT", + attachment_index, HandleToUint64(framebuffer), variable_name, string_VkImageLayout(layout), + HandleToUint64(renderpass), HandleToUint64(image_view)); + } + + if (layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) { + vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03099" : "VUID-vkCmdBeginRenderPass-initialLayout-00899"; + skip |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid, + "Layout/usage mismatch for attachment %u in render pass 0x%" PRIx64 + " - the %s is %s but the image attached to framebuffer 0x%" PRIx64 " via image view 0x%" PRIx64 + " was not created with VK_IMAGE_USAGE_TRANSFER_DST_BIT", + attachment_index, HandleToUint64(framebuffer), variable_name, string_VkImageLayout(layout), + HandleToUint64(renderpass), HandleToUint64(image_view)); + } + + if (GetDeviceExtensions(device_data)->vk_khr_maintenance2) { + if ((layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL || + layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL || + layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || + layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) && + !(image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096" : "VUID-vkCmdBeginRenderPass-initialLayout-01758"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, + HandleToUint64(image), vuid, + "Layout/usage mismatch for attachment %u in render pass 0x%" PRIx64 + " - the %s is %s but the image attached to framebuffer 0x%" PRIx64 " via image view 0x%" PRIx64 + " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT", + attachment_index, HandleToUint64(framebuffer), variable_name, string_VkImageLayout(layout), + HandleToUint64(renderpass), HandleToUint64(image_view)); + } + } else { + // The create render pass 2 extension requires maintenance 2 (the previous branch), so no vuid switch needed here. + if ((layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || + layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) && + !(image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, + HandleToUint64(image), "VUID-vkCmdBeginRenderPass-initialLayout-00896", + "Layout/usage mismatch for attachment %u in render pass 0x%" PRIx64 + " - the %s is %s but the image attached to framebuffer 0x%" PRIx64 " via image view 0x%" PRIx64 + " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT", + attachment_index, HandleToUint64(framebuffer), variable_name, string_VkImageLayout(layout), + HandleToUint64(renderpass), HandleToUint64(image_view)); + } + } + return skip; +} + +bool VerifyFramebufferAndRenderPassLayouts(layer_data *device_data, RenderPassCreateVersion rp_version, GLOBAL_CB_NODE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin, const FRAMEBUFFER_STATE *framebuffer_state) { bool skip = false; auto const pRenderPassInfo = GetRenderPassState(device_data, pRenderPassBegin->renderPass)->createInfo.ptr(); auto const &framebufferInfo = framebuffer_state->createInfo; const auto report_data = core_validation::GetReportData(device_data); + + auto render_pass = GetRenderPassState(device_data, pRenderPassBegin->renderPass)->renderPass; + auto framebuffer = framebuffer_state->framebuffer; + if (pRenderPassInfo->attachmentCount != framebufferInfo.attachmentCount) { skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidRenderpass, @@ -347,6 +450,8 @@ bool VerifyFramebufferAndRenderPassLayouts(layer_data *device_data, GLOBAL_CB_NO const VkImage &image = view_state->create_info.image; const VkImageSubresourceRange &subRange = view_state->create_info.subresourceRange; auto initial_layout = pRenderPassInfo->pAttachments[i].initialLayout; + auto final_layout = pRenderPassInfo->pAttachments[i].finalLayout; + // TODO: Do not iterate over every possibility - consolidate where possible for (uint32_t j = 0; j < subRange.levelCount; j++) { uint32_t level = subRange.baseMipLevel + j; @@ -368,12 +473,71 @@ bool VerifyFramebufferAndRenderPassLayouts(layer_data *device_data, GLOBAL_CB_NO } } } + + ValidateRenderPassLayoutAgainstFramebufferImageUsage(device_data, rp_version, initial_layout, image, image_view, + framebuffer, render_pass, i, "initial layout"); + + ValidateRenderPassLayoutAgainstFramebufferImageUsage(device_data, rp_version, final_layout, image, image_view, framebuffer, + render_pass, i, "final layout"); + } + + for (uint32_t j = 0; j < pRenderPassInfo->subpassCount; ++j) { + auto &subpass = pRenderPassInfo->pSubpasses[j]; + for (uint32_t k = 0; k < pRenderPassInfo->pSubpasses[j].inputAttachmentCount; ++k) { + auto &attachment_ref = subpass.pInputAttachments[k]; + if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { + auto image_view = framebufferInfo.pAttachments[attachment_ref.attachment]; + auto view_state = GetImageViewState(device_data, image_view); + + if (view_state) { + auto image = view_state->create_info.image; + ValidateRenderPassLayoutAgainstFramebufferImageUsage(device_data, rp_version, attachment_ref.layout, image, + image_view, framebuffer, render_pass, + attachment_ref.attachment, "input attachment layout"); + } + } + } + + for (uint32_t k = 0; k < pRenderPassInfo->pSubpasses[j].colorAttachmentCount; ++k) { + auto &attachment_ref = subpass.pColorAttachments[k]; + if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { + auto image_view = framebufferInfo.pAttachments[attachment_ref.attachment]; + auto view_state = GetImageViewState(device_data, image_view); + + if (view_state) { + auto image = view_state->create_info.image; + ValidateRenderPassLayoutAgainstFramebufferImageUsage(device_data, rp_version, attachment_ref.layout, image, + image_view, framebuffer, render_pass, + attachment_ref.attachment, "color attachment layout"); + if (subpass.pResolveAttachments) { + ValidateRenderPassLayoutAgainstFramebufferImageUsage( + device_data, rp_version, attachment_ref.layout, image, image_view, framebuffer, render_pass, + attachment_ref.attachment, "resolve attachment layout"); + } + } + } + } + + if (pRenderPassInfo->pSubpasses[j].pDepthStencilAttachment) { + auto &attachment_ref = *subpass.pDepthStencilAttachment; + if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { + auto image_view = framebufferInfo.pAttachments[attachment_ref.attachment]; + auto view_state = GetImageViewState(device_data, image_view); + + if (view_state) { + auto image = view_state->create_info.image; + ValidateRenderPassLayoutAgainstFramebufferImageUsage(device_data, rp_version, attachment_ref.layout, image, + image_view, framebuffer, render_pass, + attachment_ref.attachment, "input attachment layout"); + } + } + } } return skip; } void TransitionAttachmentRefLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, FRAMEBUFFER_STATE *pFramebuffer, - VkAttachmentReference ref) { + const safe_VkAttachmentReference2KHR &ref) { if (ref.attachment != VK_ATTACHMENT_UNUSED) { auto image_view = GetAttachmentImageViewState(device_data, pFramebuffer, ref.attachment); if (image_view) { @@ -991,7 +1155,7 @@ void TransitionFinalSubpassLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB, auto renderPass = GetRenderPassState(device_data, pRenderPassBegin->renderPass); if (!renderPass) return; - const VkRenderPassCreateInfo *pRenderPassInfo = renderPass->createInfo.ptr(); + const VkRenderPassCreateInfo2KHR *pRenderPassInfo = renderPass->createInfo.ptr(); if (framebuffer_state) { for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) { auto view_state = GetAttachmentImageViewState(device_data, framebuffer_state, i); @@ -2361,8 +2525,8 @@ bool PreCallValidateCmdClearAttachments(layer_data *device_data, VkCommandBuffer // Validate that attachment is in reference list of active subpass if (cb_node->activeRenderPass) { - const VkRenderPassCreateInfo *renderpass_create_info = cb_node->activeRenderPass->createInfo.ptr(); - const VkSubpassDescription *subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass]; + const VkRenderPassCreateInfo2KHR *renderpass_create_info = cb_node->activeRenderPass->createInfo.ptr(); + const VkSubpassDescription2KHR *subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass]; auto framebuffer = GetFramebufferState(device_data, cb_node->activeFramebuffer); for (uint32_t i = 0; i < attachmentCount; i++) { @@ -3012,42 +3176,51 @@ static bool ValidateMaskBits(core_validation::layer_data *device_data, VkCommand // ValidateLayoutVsAttachmentDescription is a general function where we can validate various state associated with the // VkAttachmentDescription structs that are used by the sub-passes of a renderpass. Initial check is to make sure that READ_ONLY // layout attachments don't have CLEAR as their loadOp. -bool ValidateLayoutVsAttachmentDescription(const debug_report_data *report_data, const VkImageLayout first_layout, - const uint32_t attachment, const VkAttachmentDescription &attachment_description) { +bool ValidateLayoutVsAttachmentDescription(const debug_report_data *report_data, RenderPassCreateVersion rp_version, + const VkImageLayout first_layout, const uint32_t attachment, + const VkAttachmentDescription2KHR &attachment_description) { bool skip = false; + const char *vuid; + const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); + // Verify that initial loadOp on READ_ONLY attachments is not CLEAR if (attachment_description.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) { if ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) || (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)) { + vuid = + use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-pAttachments-03053" : "VUID-VkRenderPassCreateInfo-pAttachments-00836"; skip |= - log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkRenderPassCreateInfo-pAttachments-00836", + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout)); } } if (attachment_description.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) { if (first_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) { + vuid = use_rp2 ? kVUID_Core_DrawState_InvalidRenderpass : "VUID-VkRenderPassCreateInfo-pAttachments-01566"; skip |= - log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkRenderPassCreateInfo-pAttachments-01566", + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout)); } } if (attachment_description.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) { if (first_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) { + vuid = use_rp2 ? kVUID_Core_DrawState_InvalidRenderpass : "VUID-VkRenderPassCreateInfo-pAttachments-01567"; skip |= - log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkRenderPassCreateInfo-pAttachments-01567", + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout)); } } return skip; } -bool ValidateLayouts(const core_validation::layer_data *device_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo) { +bool ValidateLayouts(const core_validation::layer_data *device_data, RenderPassCreateVersion rp_version, VkDevice device, + const VkRenderPassCreateInfo2KHR *pCreateInfo) { const debug_report_data *report_data = core_validation::GetReportData(device_data); bool skip = false; + const char *vuid; + const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); + const char *const function_name = use_rp2 ? "vkCreateRenderPass2KHR()" : "vkCreateRenderPass()"; for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) { VkFormat format = pCreateInfo->pAttachments[i].format; @@ -3075,13 +3248,12 @@ bool ValidateLayouts(const core_validation::layer_data *device_data, VkDevice de // Track when we're observing the first use of an attachment std::vector attach_first_use(pCreateInfo->attachmentCount, true); for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; + const VkSubpassDescription2KHR &subpass = pCreateInfo->pSubpasses[i]; // Check input attachments first, so we can detect first-use-as-input for VU #00349 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { auto attach_index = subpass.pInputAttachments[j].attachment; if (attach_index == VK_ATTACHMENT_UNUSED) continue; - switch (subpass.pInputAttachments[j].layout) { case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: @@ -3095,6 +3267,15 @@ bool ValidateLayouts(const core_validation::layer_data *device_data, VkDevice de "Layout for input attachment is GENERAL but should be READ_ONLY_OPTIMAL."); break; + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_PREINITIALIZED: + vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Layout for input attachment reference %u in subpass %u is %s but must be " + "DEPTH_STENCIL_READ_ONLY, SHADER_READ_ONLY_OPTIMAL, or GENERAL.", + j, i, string_VkImageLayout(subpass.pDepthStencilAttachment->layout)); + break; + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR: case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR: if (GetDeviceExtensions(device_data)->vk_khr_maintenance2) { @@ -3103,6 +3284,7 @@ bool ValidateLayouts(const core_validation::layer_data *device_data, VkDevice de // Intentionally fall through to generic error message } // fall through + default: // No other layouts are acceptable skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, @@ -3112,8 +3294,8 @@ bool ValidateLayouts(const core_validation::layer_data *device_data, VkDevice de } if (attach_first_use[attach_index]) { - skip |= ValidateLayoutVsAttachmentDescription(report_data, subpass.pInputAttachments[j].layout, attach_index, - pCreateInfo->pAttachments[attach_index]); + skip |= ValidateLayoutVsAttachmentDescription(report_data, rp_version, subpass.pInputAttachments[j].layout, + attach_index, pCreateInfo->pAttachments[attach_index]); bool used_as_depth = (subpass.pDepthStencilAttachment != NULL && subpass.pDepthStencilAttachment->attachment == attach_index); @@ -3123,15 +3305,15 @@ bool ValidateLayouts(const core_validation::layer_data *device_data, VkDevice de } if (!used_as_depth && !used_as_color && pCreateInfo->pAttachments[attach_index].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) { - skip |= log_msg( - report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkSubpassDescription-loadOp-00846", - "CreateRenderPass: attachment %u is first used as an input attachment in subpass %u with loadOp=CLEAR.", - attach_index, attach_index); + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-loadOp-03064" : "VUID-VkSubpassDescription-loadOp-00846"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: attachment %u is first used as an input attachment in subpass %u with loadOp=CLEAR.", + function_name, attach_index, attach_index); } } attach_first_use[attach_index] = false; } + for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { auto attach_index = subpass.pColorAttachments[j].attachment; if (attach_index == VK_ATTACHMENT_UNUSED) continue; @@ -3153,6 +3335,15 @@ bool ValidateLayouts(const core_validation::layer_data *device_data, VkDevice de "Layout for color attachment is GENERAL but should be COLOR_ATTACHMENT_OPTIMAL."); break; + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_PREINITIALIZED: + vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Layout for color attachment reference %u in subpass %u is %s but should be " + "COLOR_ATTACHMENT_OPTIMAL or GENERAL.", + j, i, string_VkImageLayout(subpass.pColorAttachments[j].layout)); + break; + default: skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_DrawState_InvalidImageLayout, @@ -3160,9 +3351,18 @@ bool ValidateLayouts(const core_validation::layer_data *device_data, VkDevice de string_VkImageLayout(subpass.pColorAttachments[j].layout)); } + if (subpass.pResolveAttachments && (subpass.pResolveAttachments[j].layout == VK_IMAGE_LAYOUT_UNDEFINED || + subpass.pResolveAttachments[j].layout == VK_IMAGE_LAYOUT_PREINITIALIZED)) { + vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Layout for color attachment reference %u in subpass %u is %s but should be " + "COLOR_ATTACHMENT_OPTIMAL or GENERAL.", + j, i, string_VkImageLayout(subpass.pColorAttachments[j].layout)); + } + if (attach_first_use[attach_index]) { - skip |= ValidateLayoutVsAttachmentDescription(report_data, subpass.pColorAttachments[j].layout, attach_index, - pCreateInfo->pAttachments[attach_index]); + skip |= ValidateLayoutVsAttachmentDescription(report_data, rp_version, subpass.pColorAttachments[j].layout, + attach_index, pCreateInfo->pAttachments[attach_index]); } attach_first_use[attach_index] = false; } @@ -3182,6 +3382,15 @@ bool ValidateLayouts(const core_validation::layer_data *device_data, VkDevice de "GENERAL layout for depth attachment may not give optimal performance."); break; + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_PREINITIALIZED: + vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857"; + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Layout for depth attachment reference in subpass %u is %s but must be a valid depth/stencil " + "layout or GENERAL.", + i, string_VkImageLayout(subpass.pDepthStencilAttachment->layout)); + break; + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR: case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR: if (GetDeviceExtensions(device_data)->vk_khr_maintenance2) { @@ -3190,6 +3399,7 @@ bool ValidateLayouts(const core_validation::layer_data *device_data, VkDevice de // Intentionally fall through to generic error message } // fall through + default: // No other layouts are acceptable skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, @@ -3201,8 +3411,8 @@ bool ValidateLayouts(const core_validation::layer_data *device_data, VkDevice de auto attach_index = subpass.pDepthStencilAttachment->attachment; if (attach_first_use[attach_index]) { - skip |= ValidateLayoutVsAttachmentDescription(report_data, subpass.pDepthStencilAttachment->layout, attach_index, - pCreateInfo->pAttachments[attach_index]); + skip |= ValidateLayoutVsAttachmentDescription(report_data, rp_version, subpass.pDepthStencilAttachment->layout, + attach_index, pCreateInfo->pAttachments[attach_index]); } attach_first_use[attach_index] = false; } @@ -3496,52 +3706,49 @@ void PostCallRecordCreateBufferView(layer_data *device_data, const VkBufferViewC } // For the given format verify that the aspect masks make sense -bool ValidateImageAspectMask(layer_data *device_data, VkImage image, VkFormat format, VkImageAspectFlags aspect_mask, - const char *func_name) { +bool ValidateImageAspectMask(const layer_data *device_data, VkImage image, VkFormat format, VkImageAspectFlags aspect_mask, + const char *func_name, const char *vuid) { const debug_report_data *report_data = core_validation::GetReportData(device_data); bool skip = false; + VkDebugReportObjectTypeEXT objectType = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT; + if (image != VK_NULL_HANDLE) { + objectType = VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT; + } + if (FormatIsColor(format)) { if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) { - skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(image), "VUID-VkImageSubresource-aspectMask-parameter", + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid, "%s: Color image formats must have the VK_IMAGE_ASPECT_COLOR_BIT set.", func_name); } else if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != aspect_mask) { - skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(image), "VUID-VkImageSubresource-aspectMask-parameter", + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid, "%s: Color image formats must have ONLY the VK_IMAGE_ASPECT_COLOR_BIT set.", func_name); } } else if (FormatIsDepthAndStencil(format)) { if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) == 0) { - skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(image), "VUID-VkImageSubresource-aspectMask-parameter", + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid, "%s: Depth/stencil image formats must have at least one of VK_IMAGE_ASPECT_DEPTH_BIT and " "VK_IMAGE_ASPECT_STENCIL_BIT set.", func_name); } else if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != aspect_mask) { - skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(image), "VUID-VkImageSubresource-aspectMask-parameter", + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid, "%s: Combination depth/stencil image formats can have only the VK_IMAGE_ASPECT_DEPTH_BIT and " "VK_IMAGE_ASPECT_STENCIL_BIT set.", func_name); } } else if (FormatIsDepthOnly(format)) { if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) { - skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(image), "VUID-VkImageSubresource-aspectMask-parameter", + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid, "%s: Depth-only image formats must have the VK_IMAGE_ASPECT_DEPTH_BIT set.", func_name); } else if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != aspect_mask) { - skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(image), "VUID-VkImageSubresource-aspectMask-parameter", + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid, "%s: Depth-only image formats can have only the VK_IMAGE_ASPECT_DEPTH_BIT set.", func_name); } } else if (FormatIsStencilOnly(format)) { if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT) { - skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(image), "VUID-VkImageSubresource-aspectMask-parameter", + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid, "%s: Stencil-only image formats must have the VK_IMAGE_ASPECT_STENCIL_BIT set.", func_name); } else if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != aspect_mask) { - skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(image), "VUID-VkImageSubresource-aspectMask-parameter", + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid, "%s: Stencil-only image formats can have only the VK_IMAGE_ASPECT_STENCIL_BIT set.", func_name); } } else if (FormatIsMultiplane(format)) { @@ -3550,8 +3757,7 @@ bool ValidateImageAspectMask(layer_data *device_data, VkImage image, VkFormat fo valid_flags = valid_flags | VK_IMAGE_ASPECT_PLANE_2_BIT; } if ((aspect_mask & valid_flags) != aspect_mask) { - skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - HandleToUint64(image), "VUID-VkImageSubresource-aspectMask-parameter", + skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid, "%s: Multi-plane image formats may have only VK_IMAGE_ASPECT_COLOR_BIT or VK_IMAGE_ASPECT_PLANE_n_BITs " "set, where n = [0, 1, 2].", func_name); diff --git a/layers/buffer_validation.h b/layers/buffer_validation.h index 7c46f78a7d9..98789789de2 100644 --- a/layers/buffer_validation.h +++ b/layers/buffer_validation.h @@ -102,11 +102,12 @@ void SetImageViewLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, VkImageVie void SetImageViewLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state, const VkImageLayout &layout); -bool VerifyFramebufferAndRenderPassLayouts(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin, +bool VerifyFramebufferAndRenderPassLayouts(layer_data *dev_data, RenderPassCreateVersion rp_version, GLOBAL_CB_NODE *pCB, + const VkRenderPassBeginInfo *pRenderPassBegin, const FRAMEBUFFER_STATE *framebuffer_state); void TransitionAttachmentRefLayout(layer_data *dev_data, GLOBAL_CB_NODE *pCB, FRAMEBUFFER_STATE *pFramebuffer, - VkAttachmentReference ref); + const safe_VkAttachmentReference2KHR &ref); void TransitionSubpassLayouts(layer_data *, GLOBAL_CB_NODE *, const RENDER_PASS_STATE *, const int, FRAMEBUFFER_STATE *); @@ -182,10 +183,12 @@ void UpdateCmdBufImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB); bool ValidateMaskBitsFromLayouts(core_validation::layer_data *device_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask, const VkImageLayout &layout, const char *type); -bool ValidateLayoutVsAttachmentDescription(const debug_report_data *report_data, const VkImageLayout first_layout, - const uint32_t attachment, const VkAttachmentDescription &attachment_description); +bool ValidateLayoutVsAttachmentDescription(const debug_report_data *report_data, RenderPassCreateVersion rp_version, + const VkImageLayout first_layout, const uint32_t attachment, + const VkAttachmentDescription2KHR &attachment_description); -bool ValidateLayouts(const core_validation::layer_data *dev_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo); +bool ValidateLayouts(const core_validation::layer_data *dev_data, RenderPassCreateVersion rp_version, VkDevice device, + const VkRenderPassCreateInfo2KHR *pCreateInfo); bool ValidateMapImageLayouts(core_validation::layer_data *dev_data, VkDevice device, DEVICE_MEM_INFO const *mem_info, VkDeviceSize offset, VkDeviceSize end_offset); @@ -211,8 +214,8 @@ bool PreCallValidateCreateBufferView(const layer_data *dev_data, const VkBufferV void PostCallRecordCreateBufferView(layer_data *device_data, const VkBufferViewCreateInfo *pCreateInfo, VkBufferView *pView); -bool ValidateImageAspectMask(layer_data *device_data, VkImage image, VkFormat format, VkImageAspectFlags aspect_mask, - const char *func_name); +bool ValidateImageAspectMask(const layer_data *device_data, VkImage image, VkFormat format, VkImageAspectFlags aspect_mask, + const char *func_name, const char *vuid = "VUID-VkImageSubresource-aspectMask-parameter"); bool ValidateCreateImageViewSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state, bool is_imageview_2d_type, const VkImageSubresourceRange &subresourceRange); diff --git a/layers/convert_to_renderpass2.cpp b/layers/convert_to_renderpass2.cpp new file mode 100644 index 00000000000..ca3bbcde84a --- /dev/null +++ b/layers/convert_to_renderpass2.cpp @@ -0,0 +1,202 @@ +/* Copyright (c) 2015-2018 The Khronos Group Inc. + * Copyright (c) 2015-2018 Valve Corporation + * Copyright (c) 2015-2018 LunarG, Inc. + * Copyright (C) 2015-2018 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. + * + * Author: Tobias Hector <@tobski> + */ + +#include + +#include "convert_to_renderpass2.h" +#include "vk_typemap_helper.h" +#include "vk_format_utils.h" + +static void ConvertVkAttachmentReferenceToV2KHR(const VkAttachmentReference* in_struct, + safe_VkAttachmentReference2KHR* out_struct) { + out_struct->sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; + out_struct->pNext = nullptr; + out_struct->attachment = in_struct->attachment; + out_struct->layout = in_struct->layout; + out_struct->aspectMask = + VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM; // Uninitialized - must be filled in by top level struct for input attachments +} + +static void ConvertVkSubpassDependencyToV2KHR(const VkSubpassDependency* in_struct, safe_VkSubpassDependency2KHR* out_struct) { + out_struct->sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR; + out_struct->pNext = nullptr; + out_struct->srcSubpass = in_struct->srcSubpass; + out_struct->dstSubpass = in_struct->dstSubpass; + out_struct->srcStageMask = in_struct->srcStageMask; + out_struct->dstStageMask = in_struct->dstStageMask; + out_struct->srcAccessMask = in_struct->srcAccessMask; + out_struct->dstAccessMask = in_struct->dstAccessMask; + out_struct->dependencyFlags = in_struct->dependencyFlags; + out_struct->viewOffset = 0; +} + +static void ConvertVkSubpassDescriptionToV2KHR(const VkSubpassDescription* in_struct, safe_VkSubpassDescription2KHR* out_struct) { + out_struct->sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR; + out_struct->pNext = nullptr; + out_struct->flags = in_struct->flags; + out_struct->pipelineBindPoint = in_struct->pipelineBindPoint; + out_struct->viewMask = 0; + out_struct->inputAttachmentCount = in_struct->inputAttachmentCount; + out_struct->pInputAttachments = nullptr; + out_struct->colorAttachmentCount = in_struct->colorAttachmentCount; + out_struct->pColorAttachments = nullptr; + out_struct->pResolveAttachments = nullptr; + out_struct->preserveAttachmentCount = in_struct->preserveAttachmentCount; + out_struct->pPreserveAttachments = nullptr; + + if (out_struct->inputAttachmentCount && in_struct->pInputAttachments) { + out_struct->pInputAttachments = new safe_VkAttachmentReference2KHR[out_struct->inputAttachmentCount]; + for (uint32_t i = 0; i < out_struct->inputAttachmentCount; ++i) { + ConvertVkAttachmentReferenceToV2KHR(&in_struct->pInputAttachments[i], &out_struct->pInputAttachments[i]); + } + } + if (out_struct->colorAttachmentCount && in_struct->pColorAttachments) { + out_struct->pColorAttachments = new safe_VkAttachmentReference2KHR[out_struct->colorAttachmentCount]; + for (uint32_t i = 0; i < out_struct->colorAttachmentCount; ++i) { + ConvertVkAttachmentReferenceToV2KHR(&in_struct->pColorAttachments[i], &out_struct->pColorAttachments[i]); + } + } + if (out_struct->colorAttachmentCount && in_struct->pResolveAttachments) { + out_struct->pResolveAttachments = new safe_VkAttachmentReference2KHR[out_struct->colorAttachmentCount]; + for (uint32_t i = 0; i < out_struct->colorAttachmentCount; ++i) { + ConvertVkAttachmentReferenceToV2KHR(&in_struct->pResolveAttachments[i], &out_struct->pResolveAttachments[i]); + } + } + if (in_struct->pDepthStencilAttachment) { + out_struct->pDepthStencilAttachment = new safe_VkAttachmentReference2KHR(); + ConvertVkAttachmentReferenceToV2KHR(in_struct->pDepthStencilAttachment, out_struct->pDepthStencilAttachment); + } else { + out_struct->pDepthStencilAttachment = NULL; + } + if (in_struct->pPreserveAttachments) { + out_struct->pPreserveAttachments = new uint32_t[in_struct->preserveAttachmentCount]; + memcpy((void*)out_struct->pPreserveAttachments, (void*)in_struct->pPreserveAttachments, + sizeof(uint32_t) * in_struct->preserveAttachmentCount); + } +} + +static void ConvertVkAttachmentDescriptionToV2KHR(const VkAttachmentDescription* in_struct, + safe_VkAttachmentDescription2KHR* out_struct) { + out_struct->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR; + out_struct->pNext = nullptr; + out_struct->flags = in_struct->flags; + out_struct->format = in_struct->format; + out_struct->samples = in_struct->samples; + out_struct->loadOp = in_struct->loadOp; + out_struct->storeOp = in_struct->storeOp; + out_struct->stencilLoadOp = in_struct->stencilLoadOp; + out_struct->stencilStoreOp = in_struct->stencilStoreOp; + out_struct->initialLayout = in_struct->initialLayout; + out_struct->finalLayout = in_struct->finalLayout; +} + +void ConvertVkRenderPassCreateInfoToV2KHR(const VkRenderPassCreateInfo* in_struct, safe_VkRenderPassCreateInfo2KHR* out_struct) { + out_struct->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR; + out_struct->pNext = nullptr; + out_struct->flags = in_struct->flags; + out_struct->attachmentCount = in_struct->attachmentCount; + out_struct->pAttachments = nullptr; + out_struct->subpassCount = in_struct->subpassCount; + out_struct->pSubpasses = nullptr; + out_struct->dependencyCount = in_struct->dependencyCount; + out_struct->pDependencies = nullptr; + out_struct->correlatedViewMaskCount = 0; + out_struct->pCorrelatedViewMasks = nullptr; + if (out_struct->attachmentCount && in_struct->pAttachments) { + out_struct->pAttachments = new safe_VkAttachmentDescription2KHR[out_struct->attachmentCount]; + for (uint32_t i = 0; i < out_struct->attachmentCount; ++i) { + ConvertVkAttachmentDescriptionToV2KHR(&in_struct->pAttachments[i], &out_struct->pAttachments[i]); + } + } + if (out_struct->subpassCount && in_struct->pSubpasses) { + out_struct->pSubpasses = new safe_VkSubpassDescription2KHR[out_struct->subpassCount]; + for (uint32_t i = 0; i < out_struct->subpassCount; ++i) { + ConvertVkSubpassDescriptionToV2KHR(&in_struct->pSubpasses[i], &out_struct->pSubpasses[i]); + } + } + if (out_struct->dependencyCount && in_struct->pDependencies) { + out_struct->pDependencies = new safe_VkSubpassDependency2KHR[out_struct->dependencyCount]; + for (uint32_t i = 0; i < out_struct->dependencyCount; ++i) { + ConvertVkSubpassDependencyToV2KHR(&in_struct->pDependencies[i], &out_struct->pDependencies[i]); + } + } + + // Handle extension structs from KHR_multiview and KHR_maintenance2 to fill out the "filled in" bits. + if (in_struct->pNext) { + const VkRenderPassMultiviewCreateInfo* pMultiviewInfo = + lvl_find_in_chain(in_struct->pNext); + if (pMultiviewInfo) { + for (uint32_t subpass = 0; subpass < pMultiviewInfo->subpassCount; ++subpass) { + if (subpass < in_struct->subpassCount) { + out_struct->pSubpasses[subpass].viewMask = pMultiviewInfo->pViewMasks[subpass]; + } + } + for (uint32_t dependency = 0; dependency < pMultiviewInfo->dependencyCount; ++dependency) { + if (dependency < in_struct->dependencyCount) { + out_struct->pDependencies[dependency].viewOffset = pMultiviewInfo->pViewOffsets[dependency]; + } + } + if (pMultiviewInfo->correlationMaskCount) { + out_struct->correlatedViewMaskCount = pMultiviewInfo->correlationMaskCount; + uint32_t* pCorrelatedViewMasks = new uint32_t[out_struct->correlatedViewMaskCount]; + for (uint32_t correlationMask = 0; correlationMask < pMultiviewInfo->correlationMaskCount; ++correlationMask) { + pCorrelatedViewMasks[correlationMask] = pMultiviewInfo->pCorrelationMasks[correlationMask]; + } + out_struct->pCorrelatedViewMasks = pCorrelatedViewMasks; + } + } + const VkRenderPassInputAttachmentAspectCreateInfo* pInputAttachmentAspectInfo = + lvl_find_in_chain(in_struct->pNext); + if (pInputAttachmentAspectInfo) { + for (uint32_t i = 0; i < pInputAttachmentAspectInfo->aspectReferenceCount; ++i) { + uint32_t subpass = pInputAttachmentAspectInfo->pAspectReferences[i].subpass; + uint32_t attachment = pInputAttachmentAspectInfo->pAspectReferences[i].inputAttachmentIndex; + VkImageAspectFlags aspectMask = pInputAttachmentAspectInfo->pAspectReferences[i].aspectMask; + if (subpass < in_struct->subpassCount && attachment < in_struct->pSubpasses[subpass].inputAttachmentCount) { + out_struct->pSubpasses[subpass].pInputAttachments[attachment].aspectMask = aspectMask; + } + } + } + } + + if (out_struct->subpassCount && out_struct->pSubpasses) { + for (uint32_t i = 0; i < out_struct->subpassCount; ++i) { + if (out_struct->pSubpasses[i].inputAttachmentCount && out_struct->pSubpasses[i].pInputAttachments) { + for (uint32_t j = 0; j < out_struct->pSubpasses[i].inputAttachmentCount; ++j) { + safe_VkAttachmentReference2KHR& attachment_ref = out_struct->pSubpasses[i].pInputAttachments[j]; + if (attachment_ref.aspectMask == VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM && + attachment_ref.attachment < out_struct->attachmentCount && out_struct->pAttachments) { + attachment_ref.aspectMask = 0; + VkFormat attachmentFormat = out_struct->pAttachments[attachment_ref.attachment].format; + if (FormatIsColor(attachmentFormat)) { + attachment_ref.aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT; + } + if (FormatHasDepth(attachmentFormat)) { + attachment_ref.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + } + if (FormatHasStencil(attachmentFormat)) { + attachment_ref.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } + } + } + } + } +} diff --git a/layers/convert_to_renderpass2.h b/layers/convert_to_renderpass2.h new file mode 100644 index 00000000000..8e7f0f95a91 --- /dev/null +++ b/layers/convert_to_renderpass2.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2015-2018 The Khronos Group Inc. + * Copyright (c) 2015-2018 Valve Corporation + * Copyright (c) 2015-2018 LunarG, Inc. + * Copyright (C) 2015-2018 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. + * + * Author: Tobias Hector <@tobski> + */ + +#pragma once +#include "vk_safe_struct.h" + +void ConvertVkRenderPassCreateInfoToV2KHR(const VkRenderPassCreateInfo* in_struct, safe_VkRenderPassCreateInfo2KHR* out_struct); diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp index 983e2961d09..ab0e7f0f8a4 100644 --- a/layers/core_validation.cpp +++ b/layers/core_validation.cpp @@ -62,6 +62,7 @@ #if defined(__GNUC__) #pragma GCC diagnostic warning "-Wwrite-strings" #endif +#include "convert_to_renderpass2.h" #include "core_validation.h" #include "buffer_validation.h" #include "shader_validation.h" @@ -1071,7 +1072,7 @@ static bool ValidatePipelineDrawtimeState(layer_data const *dev_data, LAST_BOUND VkSampleCountFlagBits pso_num_samples = GetNumSamples(pPipeline); if (pCB->activeRenderPass) { const auto render_pass_info = pCB->activeRenderPass->createInfo.ptr(); - const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pCB->activeSubpass]; + const VkSubpassDescription2KHR *subpass_desc = &render_pass_info->pSubpasses[pCB->activeSubpass]; uint32_t i; unsigned subpass_num_samples = 0; @@ -1736,7 +1737,8 @@ bool ValidateCmdSubpassState(const layer_data *dev_data, const GLOBAL_CB_NODE *p if (!pCB->activeRenderPass) return false; bool skip = false; if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS && - (cmd_type != CMD_EXECUTECOMMANDS && cmd_type != CMD_NEXTSUBPASS && cmd_type != CMD_ENDRENDERPASS)) { + (cmd_type != CMD_EXECUTECOMMANDS && cmd_type != CMD_NEXTSUBPASS && cmd_type != CMD_ENDRENDERPASS && + cmd_type != CMD_NEXTSUBPASS2KHR && cmd_type != CMD_ENDRENDERPASS2KHR)) { skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidCommandBuffer, "Commands cannot be called in a subpass using secondary command buffers."); @@ -1799,6 +1801,7 @@ static const std::unordered_map must_be_recording_ {CMD_NONE, kVUIDUndefined}, // UNMATCHED {CMD_BEGINQUERY, "VUID-vkCmdBeginQuery-commandBuffer-recording"}, {CMD_BEGINRENDERPASS, "VUID-vkCmdBeginRenderPass-commandBuffer-recording"}, + {CMD_BEGINRENDERPASS2KHR, "VUID-vkCmdBeginRenderPass2KHR-commandBuffer-recording"}, {CMD_BINDDESCRIPTORSETS, "VUID-vkCmdBindDescriptorSets-commandBuffer-recording"}, {CMD_BINDINDEXBUFFER, "VUID-vkCmdBindIndexBuffer-commandBuffer-recording"}, {CMD_BINDPIPELINE, "VUID-vkCmdBindPipeline-commandBuffer-recording"}, @@ -1835,9 +1838,11 @@ static const std::unordered_map must_be_recording_ {CMD_ENDCOMMANDBUFFER, "VUID-vkEndCommandBuffer-commandBuffer-00059"}, {CMD_ENDQUERY, "VUID-vkCmdEndQuery-commandBuffer-recording"}, {CMD_ENDRENDERPASS, "VUID-vkCmdEndRenderPass-commandBuffer-recording"}, + {CMD_ENDRENDERPASS2KHR, "VUID-vkCmdEndRenderPass2KHR-commandBuffer-recording"}, {CMD_EXECUTECOMMANDS, "VUID-vkCmdExecuteCommands-commandBuffer-recording"}, {CMD_FILLBUFFER, "VUID-vkCmdFillBuffer-commandBuffer-recording"}, {CMD_NEXTSUBPASS, "VUID-vkCmdNextSubpass-commandBuffer-recording"}, + {CMD_NEXTSUBPASS2KHR, "VUID-vkCmdNextSubpass2KHR-commandBuffer-recording"}, {CMD_PIPELINEBARRIER, "VUID-vkCmdPipelineBarrier-commandBuffer-recording"}, // Exclude vendor ext (if not already present) { CMD_PROCESSCOMMANDSNVX, "VUID-vkCmdProcessCommandsNVX-commandBuffer-recording" // }, @@ -8097,10 +8102,80 @@ static VkPipelineStageFlags ExpandPipelineStageFlags(VkPipelineStageFlags inflag VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV | VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV); } +static bool HasNonFramebufferStagePipelineStageFlags(VkPipelineStageFlags inflags) { + return (inflags & ~(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)) != 0; +} + +static int GetGraphicsPipelineStageLogicalOrdinal(VkPipelineStageFlagBits flag) { + const VkPipelineStageFlagBits ordered_array[] = { + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, + VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, + // Including the task/mesh shaders here is not technically correct, as they are in a + // separate logical pipeline - but it works for the case this is currently used, and + // fixing it would require significant rework and end up with the code being far more + // verbose for no practical gain. + // However, worth paying attention to this if using this function in a new way. + VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT}; + + const int ordered_array_length = sizeof(ordered_array) / sizeof(VkPipelineStageFlagBits); + + for (int i = 0; i < ordered_array_length; ++i) { + if (ordered_array[i] == flag) { + return i; + } + } + + return -1; +} + +// The following two functions technically have O(N^2) complexity, but it's for a value of O that's largely +// stable and also rather tiny - this could definitely be rejigged to work more efficiently, but the impact +// on runtime is currently negligible, so it wouldn't gain very much. +// If we add a lot more graphics pipeline stages, this set of functions should be rewritten to accomodate. +static VkPipelineStageFlagBits GetLogicallyEarliestGraphicsPipelineStage(VkPipelineStageFlags inflags) { + VkPipelineStageFlagBits earliest_bit = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + int earliest_bit_order = GetGraphicsPipelineStageLogicalOrdinal(earliest_bit); + + for (int i = 0; i < sizeof(VkPipelineStageFlagBits); ++i) { + VkPipelineStageFlagBits current_flag = (VkPipelineStageFlagBits)((inflags & 0x1u) << i); + if (current_flag) { + int new_order = GetGraphicsPipelineStageLogicalOrdinal(current_flag); + if (new_order != -1 && new_order < earliest_bit_order) { + earliest_bit_order = new_order; + earliest_bit = current_flag; + } + } + inflags = inflags >> 1; + } + return earliest_bit; +} + +static VkPipelineStageFlagBits GetLogicallyLatestGraphicsPipelineStage(VkPipelineStageFlags inflags) { + VkPipelineStageFlagBits latest_bit = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + int latest_bit_order = GetGraphicsPipelineStageLogicalOrdinal(latest_bit); + + for (int i = 0; i < sizeof(VkPipelineStageFlagBits); ++i) { + if (inflags & 0x1u) { + int new_order = GetGraphicsPipelineStageLogicalOrdinal((VkPipelineStageFlagBits)((inflags & 0x1u) << i)); + if (new_order != -1 && new_order > latest_bit_order) { + latest_bit_order = new_order; + latest_bit = (VkPipelineStageFlagBits)((inflags & 0x1u) << i); + } + } + inflags = inflags >> 1; + } + return latest_bit; +} + // Verify image barrier image state and that the image is consistent with FB image static bool ValidateImageBarrierImage(layer_data *device_data, const char *funcName, GLOBAL_CB_NODE const *cb_state, - VkFramebuffer framebuffer, uint32_t active_subpass, const safe_VkSubpassDescription &sub_desc, - uint64_t rp_handle, uint32_t img_index, const VkImageMemoryBarrier &img_barrier) { + VkFramebuffer framebuffer, uint32_t active_subpass, + const safe_VkSubpassDescription2KHR &sub_desc, uint64_t rp_handle, uint32_t img_index, + const VkImageMemoryBarrier &img_barrier) { bool skip = false; const auto &fb_state = GetFramebufferState(device_data, framebuffer); assert(fb_state); @@ -8175,9 +8250,10 @@ static bool ValidateImageBarrierImage(layer_data *device_data, const char *funcN // Validate image barriers within a renderPass static bool ValidateRenderPassImageBarriers(layer_data *device_data, const char *funcName, GLOBAL_CB_NODE *cb_state, - uint32_t active_subpass, const safe_VkSubpassDescription &sub_desc, uint64_t rp_handle, - const VkSubpassDependency *dependencies, const std::vector &self_dependencies, - uint32_t image_mem_barrier_count, const VkImageMemoryBarrier *image_barriers) { + uint32_t active_subpass, const safe_VkSubpassDescription2KHR &sub_desc, + uint64_t rp_handle, const safe_VkSubpassDependency2KHR *dependencies, + const std::vector &self_dependencies, uint32_t image_mem_barrier_count, + const VkImageMemoryBarrier *image_barriers) { bool skip = false; for (uint32_t i = 0; i < image_mem_barrier_count; ++i) { const auto &img_barrier = image_barriers[i]; @@ -9393,7 +9469,7 @@ VKAPI_ATTR void VKAPI_CALL CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPi if (cb_state) PostCallRecordCmdWriteTimestamp(cb_state, commandBuffer, queryPool, slot); } -static bool MatchUsage(layer_data *dev_data, uint32_t count, const VkAttachmentReference *attachments, +static bool MatchUsage(layer_data *dev_data, uint32_t count, const VkAttachmentReference2KHR *attachments, const VkFramebufferCreateInfo *fbci, VkImageUsageFlagBits usage_flag, std::string error_code) { bool skip = false; @@ -9435,7 +9511,7 @@ static bool ValidateFramebufferCreateInfo(layer_data *dev_data, const VkFramebuf auto rp_state = GetRenderPassState(dev_data, pCreateInfo->renderPass); if (rp_state) { - const VkRenderPassCreateInfo *rpci = rp_state->createInfo.ptr(); + const VkRenderPassCreateInfo2KHR *rpci = rp_state->createInfo.ptr(); if (rpci->attachmentCount != pCreateInfo->attachmentCount) { skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, HandleToUint64(pCreateInfo->renderPass), "VUID-VkFramebufferCreateInfo-attachmentCount-00876", @@ -9662,11 +9738,11 @@ static bool CheckDependencyExists(const layer_data *dev_data, const uint32_t sub return result; } -static bool CheckPreserved(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, const int index, +static bool CheckPreserved(const layer_data *dev_data, const VkRenderPassCreateInfo2KHR *pCreateInfo, const int index, const uint32_t attachment, const std::vector &subpass_to_node, int depth, bool &skip) { const DAGNode &node = subpass_to_node[index]; // If this node writes to the attachment return true as next nodes need to preserve the attachment. - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index]; + const VkSubpassDescription2KHR &subpass = pCreateInfo->pSubpasses[index]; for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { if (attachment == subpass.pColorAttachments[j].attachment) return true; } @@ -9774,7 +9850,7 @@ static bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE c // Find for each attachment the subpasses that use them. unordered_set attachmentIndices; for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; + const VkSubpassDescription2KHR &subpass = pCreateInfo->pSubpasses[i]; attachmentIndices.clear(); for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { uint32_t attachment = subpass.pInputAttachments[j].attachment; @@ -9810,7 +9886,7 @@ static bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE c } // If there is a dependency needed make sure one exists for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; + const VkSubpassDescription2KHR &subpass = pCreateInfo->pSubpasses[i]; // If the attachment is an input then all subpasses that output must have a dependency relationship for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { uint32_t attachment = subpass.pInputAttachments[j].attachment; @@ -9833,7 +9909,7 @@ static bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE c // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was // written. for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; + const VkSubpassDescription2KHR &subpass = pCreateInfo->pSubpasses[i]; for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { CheckPreserved(dev_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip); } @@ -9841,7 +9917,8 @@ static bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE c return skip; } -static bool CreatePassDAG(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, RENDER_PASS_STATE *render_pass) { +static bool CreatePassDAG(const layer_data *dev_data, RenderPassCreateVersion rp_version, + const VkRenderPassCreateInfo2KHR *pCreateInfo, RENDER_PASS_STATE *render_pass) { // Shorthand... auto &subpass_to_node = render_pass->subpassToNode; subpass_to_node.resize(pCreateInfo->subpassCount); @@ -9849,23 +9926,128 @@ static bool CreatePassDAG(const layer_data *dev_data, const VkRenderPassCreateIn self_dependencies.resize(pCreateInfo->subpassCount); bool skip = false; + const char *vuid; + const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); + for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { subpass_to_node[i].pass = i; self_dependencies[i].clear(); } for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) { - const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i]; - if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL || dependency.dstSubpass == VK_SUBPASS_EXTERNAL) { + const VkSubpassDependency2KHR &dependency = pCreateInfo->pDependencies[i]; + VkPipelineStageFlags exclude_graphics_pipeline_stages = + ~(VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | ExpandPipelineStageFlags(VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT)); + VkPipelineStageFlagBits latest_src_stage = GetLogicallyLatestGraphicsPipelineStage(dependency.srcStageMask); + VkPipelineStageFlagBits earliest_dst_stage = GetLogicallyEarliestGraphicsPipelineStage(dependency.dstStageMask); + + // This VU is actually generalised to *any* pipeline - not just graphics - but only graphics render passes are + // currently supported by the spec - so only that pipeline is checked here. + // If that is ever relaxed, this check should be extended to cover those pipelines. + if (dependency.srcSubpass == dependency.dstSubpass && (dependency.srcStageMask & exclude_graphics_pipeline_stages) != 0u && + (dependency.dstStageMask & exclude_graphics_pipeline_stages) != 0u) { + vuid = use_rp2 ? "VUID-VkSubpassDependency2KHR-srcSubpass-02244" : "VUID-VkSubpassDependency-srcSubpass-01989"; + skip |= log_msg( + dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Dependency %u is a self-dependency, but specifies stage masks that contain stages not in the GRAPHICS pipeline.", + i); + } else if (dependency.srcSubpass != VK_SUBPASS_EXTERNAL && (dependency.srcStageMask & VK_PIPELINE_STAGE_HOST_BIT)) { + vuid = use_rp2 ? "VUID-VkSubpassDependency2KHR-srcSubpass-03078" : "VUID-VkSubpassDependency-srcSubpass-00858"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Dependency %u specifies a dependency from subpass %u, but includes HOST_BIT in the source stage mask.", + i, dependency.srcSubpass); + } else if (dependency.dstSubpass != VK_SUBPASS_EXTERNAL && (dependency.dstStageMask & VK_PIPELINE_STAGE_HOST_BIT)) { + vuid = use_rp2 ? "VUID-VkSubpassDependency2KHR-dstSubpass-03079" : "VUID-VkSubpassDependency-dstSubpass-00859"; + skip |= + log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Dependency %u specifies a dependency to subpass %u, but includes HOST_BIT in the destination stage mask.", + i, dependency.dstSubpass); + } + // These next two VUs are actually generalised to *any* pipeline - not just graphics - but only graphics render passes are + // currently supported by the spec - so only that pipeline is checked here. + // If that is ever relaxed, these next two checks should be extended to cover those pipelines. + else if (dependency.srcSubpass != VK_SUBPASS_EXTERNAL && + pCreateInfo->pSubpasses[dependency.srcSubpass].pipelineBindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS && + (dependency.srcStageMask & exclude_graphics_pipeline_stages) != 0u) { + vuid = + use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03054" : "VUID-VkRenderPassCreateInfo-pDependencies-00837"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Dependency %u specifies a source stage mask that contains stages not in the GRAPHICS pipeline as used " + "by the source subpass %u.", + i, dependency.srcSubpass); + } else if (dependency.dstSubpass != VK_SUBPASS_EXTERNAL && + pCreateInfo->pSubpasses[dependency.dstSubpass].pipelineBindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS && + (dependency.dstStageMask & exclude_graphics_pipeline_stages) != 0u) { + vuid = + use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03055" : "VUID-VkRenderPassCreateInfo-pDependencies-00838"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Dependency %u specifies a destination stage mask that contains stages not in the GRAPHICS pipeline as " + "used by the destination subpass %u.", + i, dependency.dstSubpass); + } + // The first subpass here serves as a good proxy for "is multiview enabled" - since all view masks need to be non-zero if + // any are, which enables multiview. + else if (dependency.dependencyFlags & VK_DEPENDENCY_VIEW_LOCAL_BIT && pCreateInfo->pSubpasses[0].viewMask == 0) { + vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-viewMask-03059" : "VUID-VkSubpassDependency-dependencyFlags-00871"; + skip |= log_msg( + dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Dependency %u specifies the VK_DEPENDENCY_VIEW_LOCAL_BIT, but multiview is not enabled for this render pass.", i); + } else if (use_rp2 && !(dependency.dependencyFlags & VK_DEPENDENCY_VIEW_LOCAL_BIT) && dependency.viewOffset != 0) { + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + "VUID-VkSubpassDependency2KHR-dependencyFlags-03092", + "Dependency %u specifies the VK_DEPENDENCY_VIEW_LOCAL_BIT, but also specifies a view offset of %u.", i, + dependency.viewOffset); + } else if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL || dependency.dstSubpass == VK_SUBPASS_EXTERNAL) { if (dependency.srcSubpass == dependency.dstSubpass) { + vuid = use_rp2 ? "VUID-VkSubpassDependency2KHR-srcSubpass-03085" : "VUID-VkSubpassDependency-srcSubpass-00865"; skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - kVUID_Core_DrawState_InvalidRenderpass, "The src and dest subpasses cannot both be external."); + vuid, "The src and dst subpasses in dependency %u are both external.", i); + } else if (dependency.dependencyFlags & VK_DEPENDENCY_VIEW_LOCAL_BIT) { + vuid = "VUID-VkSubpassDependency-dependencyFlags-00870"; + if (use_rp2) { + // Create render pass 2 distinguishes between source and destination external dependencies. + if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL) { + vuid = "VUID-VkSubpassDependency2KHR-dependencyFlags-03090"; + } else { + vuid = "VUID-VkSubpassDependency2KHR-dependencyFlags-03091"; + } + } + skip |= + log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Dependency %u specifies an external dependency but also specifies VK_DEPENDENCY_VIEW_LOCAL_BIT.", i); } } else if (dependency.srcSubpass > dependency.dstSubpass) { - skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - kVUID_Core_DrawState_InvalidRenderpass, - "Dependency graph must be specified such that an earlier pass cannot depend on a later pass."); + vuid = use_rp2 ? "VUID-VkSubpassDependency2KHR-srcSubpass-03084" : "VUID-VkSubpassDependency-srcSubpass-00864"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Dependency %u specifies a dependency from a later subpass (%u) to an earlier subpass (%u), which is " + "disallowed to prevent cyclic dependencies.", + i, dependency.srcSubpass, dependency.dstSubpass); } else if (dependency.srcSubpass == dependency.dstSubpass) { - self_dependencies[dependency.srcSubpass].push_back(i); + if (dependency.viewOffset != 0) { + vuid = use_rp2 ? kVUID_Core_DrawState_InvalidRenderpass : "VUID-VkRenderPassCreateInfo-pNext-01930"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + vuid, "Dependency %u specifies a self-dependency but has a non-zero view offset of %u", i, + dependency.viewOffset); + } else if ((dependency.dependencyFlags | VK_DEPENDENCY_VIEW_LOCAL_BIT) != dependency.dependencyFlags && + pCreateInfo->pSubpasses[dependency.srcSubpass].viewMask > 1) { + vuid = + use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03060" : "VUID-VkSubpassDependency-srcSubpass-00872"; + skip |= + log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Dependency %u specifies a self-dependency for subpass %u with a non-zero view mask, but does not " + "specify VK_DEPENDENCY_VIEW_LOCAL_BIT.", + i, dependency.srcSubpass); + } else if ((HasNonFramebufferStagePipelineStageFlags(dependency.srcStageMask) || + HasNonFramebufferStagePipelineStageFlags(dependency.dstStageMask)) && + (GetGraphicsPipelineStageLogicalOrdinal(latest_src_stage) > + GetGraphicsPipelineStageLogicalOrdinal(earliest_dst_stage))) { + vuid = use_rp2 ? "VUID-VkSubpassDependency2KHR-srcSubpass-03087" : "VUID-VkSubpassDependency-srcSubpass-00867"; + skip |= log_msg( + dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "Dependency %u specifies a self-dependency from logically-later stage (%s) to a logically-earlier stage (%s).", + i, string_VkPipelineStageFlagBits(latest_src_stage), string_VkPipelineStageFlagBits(earliest_dst_stage)); + } else { + self_dependencies[dependency.srcSubpass].push_back(i); + } } else { subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass); subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass); @@ -9896,12 +10078,17 @@ VKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(VkDevice device, const VkShade return res; } -static bool ValidateAttachmentIndex(const layer_data *dev_data, uint32_t attachment, uint32_t attachment_count, const char *type) { +static bool ValidateAttachmentIndex(const layer_data *dev_data, RenderPassCreateVersion rp_version, uint32_t attachment, + uint32_t attachment_count, const char *type) { bool skip = false; + const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); + const char *const function_name = use_rp2 ? "vkCreateRenderPass2KHR()" : "vkCreateRenderPass()"; + if (attachment >= attachment_count && attachment != VK_ATTACHMENT_UNUSED) { - skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkRenderPassCreateInfo-attachment-00834", - "CreateRenderPass: %s attachment %d must be less than the total number of attachments %d.", type, + const char *vuid = + use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-attachment-03051" : "VUID-VkRenderPassCreateInfo-attachment-00834"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: %s attachment %d must be less than the total number of attachments %d.", type, function_name, attachment, attachment_count); } return skip; @@ -9934,31 +10121,35 @@ char const *StringAttachmentType(uint8_t type) { } } -static bool AddAttachmentUse(const layer_data *dev_data, uint32_t subpass, std::vector &attachment_uses, - std::vector &attachment_layouts, uint32_t attachment, uint8_t new_use, - VkImageLayout new_layout) { +static bool AddAttachmentUse(const layer_data *dev_data, RenderPassCreateVersion rp_version, uint32_t subpass, + std::vector &attachment_uses, std::vector &attachment_layouts, + uint32_t attachment, uint8_t new_use, VkImageLayout new_layout) { if (attachment >= attachment_uses.size()) return false; /* out of range, but already reported */ bool skip = false; auto &uses = attachment_uses[attachment]; + const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); + const char *vuid; + const char *const function_name = use_rp2 ? "vkCreateRenderPass2KHR()" : "vkCreateRenderPass()"; + if (uses & new_use) { - skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - kVUID_Core_DrawState_InvalidRenderpass, - "vkCreateRenderPass(): subpass %u already uses attachment %u as a %s attachment.", subpass, attachment, - StringAttachmentType(new_use)); + log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + kVUID_Core_DrawState_InvalidRenderpass, "%s: subpass %u already uses attachment %u as a %s attachment.", + function_name, subpass, attachment, StringAttachmentType(new_use)); } else if (uses & ~ATTACHMENT_INPUT || (uses && (new_use == ATTACHMENT_RESOLVE || new_use == ATTACHMENT_PRESERVE))) { /* Note: input attachments are assumed to be done first. */ - skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkSubpassDescription-pPreserveAttachments-00854", - "vkCreateRenderPass(): subpass %u uses attachment %u as both %s and %s attachment.", subpass, attachment, + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-pPreserveAttachments-03074" + : "VUID-VkSubpassDescription-pPreserveAttachments-00854"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: subpass %u uses attachment %u as both %s and %s attachment.", function_name, subpass, attachment, StringAttachmentType(uses), StringAttachmentType(new_use)); } else if (uses && attachment_layouts[attachment] != new_layout) { - skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkSubpassDescription-layout-00855", - "vkCreateRenderPass(): subpass %u uses attachment %u with conflicting layouts: input uses %s, but %s " + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-layout-03075" : "VUID-VkSubpassDescription-layout-00855"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: subpass %u uses attachment %u with conflicting layouts: input uses %s, but %s " "attachment uses %s.", - subpass, attachment, string_VkImageLayout(attachment_layouts[attachment]), StringAttachmentType(new_use), - string_VkImageLayout(new_layout)); + function_name, subpass, attachment, string_VkImageLayout(attachment_layouts[attachment]), + StringAttachmentType(new_use), string_VkImageLayout(new_layout)); } else { attachment_layouts[attachment] = new_layout; uses |= new_use; @@ -9967,139 +10158,235 @@ static bool AddAttachmentUse(const layer_data *dev_data, uint32_t subpass, std:: return skip; } -static bool ValidateRenderpassAttachmentUsage(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo) { +static bool ValidateRenderpassAttachmentUsage(const layer_data *dev_data, RenderPassCreateVersion rp_version, + const VkRenderPassCreateInfo2KHR *pCreateInfo) { bool skip = false; + const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); + const char *vuid; + const char *const function_name = use_rp2 ? "vkCreateRenderPass2KHR()" : "vkCreateRenderPass()"; + for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; + const VkSubpassDescription2KHR &subpass = pCreateInfo->pSubpasses[i]; std::vector attachment_uses(pCreateInfo->attachmentCount); std::vector attachment_layouts(pCreateInfo->attachmentCount); if (subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS) { - skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkSubpassDescription-pipelineBindPoint-00844", - "vkCreateRenderPass(): Pipeline bind point for subpass %d must be VK_PIPELINE_BIND_POINT_GRAPHICS.", i); + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-pipelineBindPoint-03062" + : "VUID-VkSubpassDescription-pipelineBindPoint-00844"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: Pipeline bind point for subpass %d must be VK_PIPELINE_BIND_POINT_GRAPHICS.", function_name, i); } for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) { auto const &attachment_ref = subpass.pInputAttachments[j]; if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { - skip |= ValidateAttachmentIndex(dev_data, attachment_ref.attachment, pCreateInfo->attachmentCount, "Input"); - skip |= AddAttachmentUse(dev_data, i, attachment_uses, attachment_layouts, attachment_ref.attachment, - ATTACHMENT_INPUT, attachment_ref.layout); + skip |= + ValidateAttachmentIndex(dev_data, rp_version, attachment_ref.attachment, pCreateInfo->attachmentCount, "Input"); + + if (attachment_ref.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT) { + vuid = + use_rp2 ? kVUID_Core_DrawState_InvalidRenderpass : "VUID-VkInputAttachmentAspectReference-aspectMask-01964"; + skip |= log_msg( + dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: Aspect mask for input attachment reference %d in subpass %d includes VK_IMAGE_ASPECT_METADATA_BIT.", + function_name, i, j); + } + + if (attachment_ref.attachment < pCreateInfo->attachmentCount) { + skip |= AddAttachmentUse(dev_data, rp_version, i, attachment_uses, attachment_layouts, + attachment_ref.attachment, ATTACHMENT_INPUT, attachment_ref.layout); + + vuid = use_rp2 ? kVUID_Core_DrawState_InvalidRenderpass : "VUID-VkRenderPassCreateInfo-pNext-01963"; + skip |= ValidateImageAspectMask(dev_data, VK_NULL_HANDLE, + pCreateInfo->pAttachments[attachment_ref.attachment].format, + attachment_ref.aspectMask, function_name, vuid); + } + } + + if (rp_version == RENDER_PASS_VERSION_2) { + // These are validated automatically as part of parameter validation for create renderpass 1 + // as they are in a struct that only applies to input attachments - not so for v2. + + // Check for 0 + if (attachment_ref.aspectMask == 0) { + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, + 0, "VUID-VkSubpassDescription2KHR-aspectMask-03176", + "%s: Input attachment (%d) aspect mask must not be 0.", function_name, j); + } else { + const VkImageAspectFlags valid_bits = + (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT | + VK_IMAGE_ASPECT_METADATA_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | + VK_IMAGE_ASPECT_PLANE_2_BIT); + + // Check for valid aspect mask bits + if (attachment_ref.aspectMask & ~valid_bits) { + skip |= + log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, + 0, "VUID-VkSubpassDescription2KHR-aspectMask-03175", + "%s: Input attachment (%d) aspect mask (0x%" PRIx32 ")is invalid.", function_name, j, + attachment_ref.aspectMask); + } + } } } for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) { uint32_t attachment = subpass.pPreserveAttachments[j]; if (attachment == VK_ATTACHMENT_UNUSED) { + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-attachment-03073" : "VUID-VkSubpassDescription-attachment-00853"; skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkSubpassDescription-attachment-00853", - "vkCreateRenderPass(): Preserve attachment (%d) must not be VK_ATTACHMENT_UNUSED.", j); + vuid, "%s: Preserve attachment (%d) must not be VK_ATTACHMENT_UNUSED.", function_name, j); } else { - skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Preserve"); - skip |= AddAttachmentUse(dev_data, i, attachment_uses, attachment_layouts, attachment, ATTACHMENT_PRESERVE, - VkImageLayout(0) /* preserve doesn't have any layout */); + skip |= ValidateAttachmentIndex(dev_data, rp_version, attachment, pCreateInfo->attachmentCount, "Preserve"); + if (attachment < pCreateInfo->attachmentCount) { + skip |= AddAttachmentUse(dev_data, rp_version, i, attachment_uses, attachment_layouts, attachment, + ATTACHMENT_PRESERVE, VkImageLayout(0) /* preserve doesn't have any layout */); + } } } - unsigned sample_count = 0; bool subpass_performs_resolve = false; for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { if (subpass.pResolveAttachments) { auto const &attachment_ref = subpass.pResolveAttachments[j]; if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { - skip |= ValidateAttachmentIndex(dev_data, attachment_ref.attachment, pCreateInfo->attachmentCount, "Resolve"); - skip |= AddAttachmentUse(dev_data, i, attachment_uses, attachment_layouts, attachment_ref.attachment, - ATTACHMENT_RESOLVE, attachment_ref.layout); + skip |= ValidateAttachmentIndex(dev_data, rp_version, attachment_ref.attachment, pCreateInfo->attachmentCount, + "Resolve"); - subpass_performs_resolve = true; + if (attachment_ref.attachment < pCreateInfo->attachmentCount) { + skip |= AddAttachmentUse(dev_data, rp_version, i, attachment_uses, attachment_layouts, + attachment_ref.attachment, ATTACHMENT_RESOLVE, attachment_ref.layout); - if (!skip && pCreateInfo->pAttachments[attachment_ref.attachment].samples != VK_SAMPLE_COUNT_1_BIT) { - skip |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, - 0, "VUID-VkSubpassDescription-pResolveAttachments-00849", - "vkCreateRenderPass(): Subpass %u requests multisample resolve into attachment %u, which must " - "have VK_SAMPLE_COUNT_1_BIT but has %s.", - i, attachment_ref.attachment, - string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment_ref.attachment].samples)); + subpass_performs_resolve = true; + + if (pCreateInfo->pAttachments[attachment_ref.attachment].samples != VK_SAMPLE_COUNT_1_BIT) { + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-pResolveAttachments-03067" + : "VUID-VkSubpassDescription-pResolveAttachments-00849"; + skip |= + log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: Subpass %u requests multisample resolve into attachment %u, which must " + "have VK_SAMPLE_COUNT_1_BIT but has %s.", + function_name, i, attachment_ref.attachment, + string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment_ref.attachment].samples)); + } } } } } + if (subpass.pDepthStencilAttachment) { + if (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { + skip |= ValidateAttachmentIndex(dev_data, rp_version, subpass.pDepthStencilAttachment->attachment, + pCreateInfo->attachmentCount, "Depth"); + if (subpass.pDepthStencilAttachment->attachment < pCreateInfo->attachmentCount) { + skip |= AddAttachmentUse(dev_data, rp_version, i, attachment_uses, attachment_layouts, + subpass.pDepthStencilAttachment->attachment, ATTACHMENT_DEPTH, + subpass.pDepthStencilAttachment->layout); + } + } + } + + uint32_t last_sample_count_attachment = VK_ATTACHMENT_UNUSED; for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { auto const &attachment_ref = subpass.pColorAttachments[j]; - skip |= ValidateAttachmentIndex(dev_data, attachment_ref.attachment, pCreateInfo->attachmentCount, "Color"); - if (!skip && attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { - skip |= AddAttachmentUse(dev_data, i, attachment_uses, attachment_layouts, attachment_ref.attachment, + skip |= ValidateAttachmentIndex(dev_data, rp_version, attachment_ref.attachment, pCreateInfo->attachmentCount, "Color"); + if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED && attachment_ref.attachment < pCreateInfo->attachmentCount) { + skip |= AddAttachmentUse(dev_data, rp_version, i, attachment_uses, attachment_layouts, attachment_ref.attachment, ATTACHMENT_COLOR, attachment_ref.layout); - sample_count |= (unsigned)pCreateInfo->pAttachments[attachment_ref.attachment].samples; - if (subpass_performs_resolve && - pCreateInfo->pAttachments[attachment_ref.attachment].samples == VK_SAMPLE_COUNT_1_BIT) { + VkSampleCountFlagBits current_sample_count = pCreateInfo->pAttachments[attachment_ref.attachment].samples; + if (last_sample_count_attachment != VK_ATTACHMENT_UNUSED) { + VkSampleCountFlagBits last_sample_count = + pCreateInfo->pAttachments[subpass.pColorAttachments[last_sample_count_attachment].attachment].samples; + if (current_sample_count != last_sample_count) { + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-pColorAttachments-03069" + : "VUID-VkSubpassDescription-pColorAttachments-01417"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: Subpass %u attempts to render to color attachments with inconsistent sample counts." + "Color attachment ref %u has sample count %s, whereas previous color attachment ref %u has " + "sample count %s.", + function_name, i, j, string_VkSampleCountFlagBits(current_sample_count), + last_sample_count_attachment, string_VkSampleCountFlagBits(last_sample_count)); + } + } + last_sample_count_attachment = j; + + if (subpass_performs_resolve && current_sample_count == VK_SAMPLE_COUNT_1_BIT) { + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-pResolveAttachments-03066" + : "VUID-VkSubpassDescription-pResolveAttachments-00848"; skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, - 0, "VUID-VkSubpassDescription-pResolveAttachments-00848", - "vkCreateRenderPass(): Subpass %u requests multisample resolve from attachment %u which has " + 0, vuid, + "%s: Subpass %u requests multisample resolve from attachment %u which has " "VK_SAMPLE_COUNT_1_BIT.", - i, attachment_ref.attachment); + function_name, i, attachment_ref.attachment); } - if (dev_data->extensions.vk_amd_mixed_attachment_samples && subpass.pDepthStencilAttachment && - subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { + if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED && + subpass.pDepthStencilAttachment->attachment < pCreateInfo->attachmentCount) { const auto depth_stencil_sample_count = pCreateInfo->pAttachments[subpass.pDepthStencilAttachment->attachment].samples; - if (pCreateInfo->pAttachments[attachment_ref.attachment].samples > depth_stencil_sample_count) { + + if (dev_data->extensions.vk_amd_mixed_attachment_samples) { + if (pCreateInfo->pAttachments[attachment_ref.attachment].samples > depth_stencil_sample_count) { + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-pColorAttachments-03070" + : "VUID-VkSubpassDescription-pColorAttachments-01506"; + skip |= + log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: Subpass %u pColorAttachments[%u] has %s which is larger than " + "depth/stencil attachment %s.", + function_name, i, j, + string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment_ref.attachment].samples), + string_VkSampleCountFlagBits(depth_stencil_sample_count)); + break; + } + } + + if (!dev_data->extensions.vk_amd_mixed_attachment_samples && + !dev_data->extensions.vk_nv_framebuffer_mixed_samples && + current_sample_count != depth_stencil_sample_count) { + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-pDepthStencilAttachment-03071" + : "VUID-VkSubpassDescription-pDepthStencilAttachment-01418"; skip |= log_msg( - dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkSubpassDescription-pColorAttachments-01506", - "vkCreateRenderPass(): Subpass %u pColorAttachments[%u] has %s which is larger than " - "depth/stencil attachment %s.", - i, j, string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment_ref.attachment].samples), - string_VkSampleCountFlagBits(depth_stencil_sample_count)); + dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: Subpass %u attempts to render to use a depth/stencil attachment with sample count that differs " + "from color attachment %u." + "The depth attachment ref has sample count %s, whereas color attachment ref %u has sample count %s.", + function_name, i, j, string_VkSampleCountFlagBits(depth_stencil_sample_count), j, + string_VkSampleCountFlagBits(current_sample_count)); + break; } } } - if (!skip && subpass_performs_resolve && subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED) { + if (subpass_performs_resolve && subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED && + subpass.pResolveAttachments[j].attachment < pCreateInfo->attachmentCount) { if (attachment_ref.attachment == VK_ATTACHMENT_UNUSED) { + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-pResolveAttachments-03065" + : "VUID-VkSubpassDescription-pResolveAttachments-00847"; skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, - 0, "VUID-VkSubpassDescription-pResolveAttachments-00847", - "vkCreateRenderPass(): Subpass %u requests multisample resolve from attachment %u which has " + 0, vuid, + "%s: Subpass %u requests multisample resolve from attachment %u which has " "attachment=VK_ATTACHMENT_UNUSED.", - i, attachment_ref.attachment); + function_name, i, attachment_ref.attachment); } else { const auto &color_desc = pCreateInfo->pAttachments[attachment_ref.attachment]; const auto &resolve_desc = pCreateInfo->pAttachments[subpass.pResolveAttachments[j].attachment]; if (color_desc.format != resolve_desc.format) { - skip |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, - 0, "VUID-VkSubpassDescription-pResolveAttachments-00850", - "vkCreateRenderPass(): Subpass %u pColorAttachments[%u] resolves to an attachment with a " - "different format. color format: %u, resolve format: %u.", - i, j, color_desc.format, resolve_desc.format); + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-pResolveAttachments-03068" + : "VUID-VkSubpassDescription-pResolveAttachments-00850"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: Subpass %u pColorAttachments[%u] resolves to an attachment with a " + "different format. color format: %u, resolve format: %u.", + function_name, i, j, color_desc.format, resolve_desc.format); } } } } - - if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) { - auto const &attachment_ref = *subpass.pDepthStencilAttachment; - skip |= ValidateAttachmentIndex(dev_data, attachment_ref.attachment, pCreateInfo->attachmentCount, "Depth stencil"); - - if (!skip && attachment_ref.attachment != VK_ATTACHMENT_UNUSED) { - skip |= AddAttachmentUse(dev_data, i, attachment_uses, attachment_layouts, attachment_ref.attachment, - ATTACHMENT_DEPTH, attachment_ref.layout); - sample_count |= (unsigned)pCreateInfo->pAttachments[attachment_ref.attachment].samples; - } - } - - if (!dev_data->extensions.vk_amd_mixed_attachment_samples && sample_count && !IsPowerOfTwo(sample_count)) { - skip |= - log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkAttachmentDescription-samples-parameter", - "vkCreateRenderPass(): Subpass %u attempts to render to attachments with inconsistent sample counts.", i); - } } return skip; } @@ -10110,44 +10397,151 @@ static void MarkAttachmentFirstUse(RENDER_PASS_STATE *render_pass, uint32_t inde if (!render_pass->attachment_first_read.count(index)) render_pass->attachment_first_read[index] = is_read; } -static bool PreCallValidateCreateRenderPass(const layer_data *dev_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, - RENDER_PASS_STATE *render_pass) { +static bool ValidateCreateRenderPass(const layer_data *dev_data, VkDevice device, RenderPassCreateVersion rp_version, + const VkRenderPassCreateInfo2KHR *pCreateInfo, RENDER_PASS_STATE *render_pass) { bool skip = false; + const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); + const char *vuid; + const char *const function_name = use_rp2 ? "vkCreateRenderPass2KHR()" : "vkCreateRenderPass()"; // TODO: As part of wrapping up the mem_tracker/core_validation merge the following routine should be consolidated with // ValidateLayouts. - skip |= ValidateRenderpassAttachmentUsage(dev_data, pCreateInfo); + skip |= ValidateRenderpassAttachmentUsage(dev_data, rp_version, pCreateInfo); render_pass->renderPass = VK_NULL_HANDLE; - skip |= CreatePassDAG(dev_data, pCreateInfo, render_pass); + skip |= CreatePassDAG(dev_data, rp_version, pCreateInfo, render_pass); + + // Validate multiview correlation and view masks + bool viewMaskZero = false; + bool viewMaskNonZero = false; + + for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { + const VkSubpassDescription2KHR &subpass = pCreateInfo->pSubpasses[i]; + if (subpass.viewMask != 0) { + viewMaskNonZero = true; + } else { + viewMaskZero = true; + } + + if ((subpass.flags & VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX) != 0 && + (subpass.flags & VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX) == 0) { + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-flags-03076" : "VUID-VkSubpassDescription-flags-00856"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: The flags parameter of subpass description %u includes " + "VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX but does not also include " + "VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX.", + function_name, i); + } + } + + if (rp_version == RENDER_PASS_VERSION_2) { + if (viewMaskNonZero && viewMaskZero) { + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + "VUID-VkRenderPassCreateInfo2KHR-viewMask-03058", + "%s: Some view masks are non-zero whilst others are zero.", function_name); + } + + if (viewMaskZero && pCreateInfo->correlatedViewMaskCount != 0) { + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + "VUID-VkRenderPassCreateInfo2KHR-viewMask-03057", + "%s: Multiview is not enabled but correlation masks are still provided", function_name); + } + } + uint32_t aggregated_cvms = 0; + for (uint32_t i = 0; i < pCreateInfo->correlatedViewMaskCount; ++i) { + if (aggregated_cvms & pCreateInfo->pCorrelatedViewMasks[i]) { + vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-pCorrelatedViewMasks-03056" + : "VUID-VkRenderPassMultiviewCreateInfo-pCorrelationMasks-00841"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: pCorrelatedViewMasks[%u] contains a previously appearing view bit.", function_name, i); + } + aggregated_cvms |= pCreateInfo->pCorrelatedViewMasks[i]; + } for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) { auto const &dependency = pCreateInfo->pDependencies[i]; - skip |= ValidateStageMaskGsTsEnables( - dev_data, dependency.srcStageMask, "vkCreateRenderPass()", "VUID-VkSubpassDependency-srcStageMask-00860", - "VUID-VkSubpassDependency-srcStageMask-00862", "VUID-VkSubpassDependency-srcStageMask-02099", - "VUID-VkSubpassDependency-srcStageMask-02100"); - skip |= ValidateStageMaskGsTsEnables( - dev_data, dependency.dstStageMask, "vkCreateRenderPass()", "VUID-VkSubpassDependency-dstStageMask-00861", - "VUID-VkSubpassDependency-dstStageMask-00863", "VUID-VkSubpassDependency-dstStageMask-02101", - "VUID-VkSubpassDependency-dstStageMask-02102"); + if (rp_version == RENDER_PASS_VERSION_2) { + skip |= ValidateStageMaskGsTsEnables( + dev_data, dependency.srcStageMask, function_name, "VUID-VkSubpassDependency2KHR-srcStageMask-03080", + "VUID-VkSubpassDependency2KHR-srcStageMask-03082", "VUID-VkSubpassDependency-srcStageMask-02103", + "VUID-VkSubpassDependency-srcStageMask-02104"); + skip |= ValidateStageMaskGsTsEnables( + dev_data, dependency.dstStageMask, function_name, "VUID-VkSubpassDependency2KHR-dstStageMask-03081", + "VUID-VkSubpassDependency2KHR-dstStageMask-03083", "VUID-VkSubpassDependency-srcStageMask-02105", + "VUID-VkSubpassDependency-srcStageMask-02106"); + } else { + skip |= ValidateStageMaskGsTsEnables( + dev_data, dependency.srcStageMask, function_name, "VUID-VkSubpassDependency-srcStageMask-00860", + "VUID-VkSubpassDependency-srcStageMask-00862", "VUID-VkSubpassDependency-srcStageMask-02099", + "VUID-VkSubpassDependency-srcStageMask-02100"); + skip |= ValidateStageMaskGsTsEnables( + dev_data, dependency.dstStageMask, function_name, "VUID-VkSubpassDependency-dstStageMask-00861", + "VUID-VkSubpassDependency-dstStageMask-00863", "VUID-VkSubpassDependency-dstStageMask-02101", + "VUID-VkSubpassDependency-dstStageMask-02102"); + } if (!ValidateAccessMaskPipelineStage(dependency.srcAccessMask, dependency.srcStageMask)) { - skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkSubpassDependency-srcAccessMask-00868", - "CreateRenderPass: pDependencies[%u].srcAccessMask (0x%X) is not supported by srcStageMask (0x%X).", i, - dependency.srcAccessMask, dependency.srcStageMask); + vuid = use_rp2 ? "VUID-VkSubpassDependency2KHR-srcAccessMask-03088" : "VUID-VkSubpassDependency-srcAccessMask-00868"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: pDependencies[%u].srcAccessMask (0x%" PRIx32 ") is not supported by srcStageMask (0x%" PRIx32 ").", + function_name, i, dependency.srcAccessMask, dependency.srcStageMask); } if (!ValidateAccessMaskPipelineStage(dependency.dstAccessMask, dependency.dstStageMask)) { + vuid = use_rp2 ? "VUID-VkSubpassDependency2KHR-dstAccessMask-03089" : "VUID-VkSubpassDependency-dstAccessMask-00869"; + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "%s: pDependencies[%u].dstAccessMask (0x%" PRIx32 ") is not supported by dstStageMask (0x%" PRIx32 ").", + function_name, i, dependency.dstAccessMask, dependency.dstStageMask); + } + } + if (!skip) { + skip |= ValidateLayouts(dev_data, rp_version, device, pCreateInfo); + } + return skip; +} + +static bool PreCallValidateCreateRenderPass(const layer_data *dev_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, + RENDER_PASS_STATE *render_pass) { + bool skip = false; + // Handle extension structs from KHR_multiview and KHR_maintenance2 that can only be validated for RP1 (indices out of bounds) + const VkRenderPassMultiviewCreateInfo *pMultiviewInfo = lvl_find_in_chain(pCreateInfo->pNext); + if (pMultiviewInfo) { + if (pMultiviewInfo->subpassCount && pMultiviewInfo->subpassCount != pCreateInfo->subpassCount) { skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkSubpassDependency-dstAccessMask-00869", - "CreateRenderPass: pDependencies[%u].dstAccessMask (0x%X) is not supported by dstStageMask (0x%X).", i, - dependency.dstAccessMask, dependency.dstStageMask); + "VUID-VkRenderPassCreateInfo-pNext-01928", + "Subpass count is %u but multiview info has a subpass count of %u.", pCreateInfo->subpassCount, + pMultiviewInfo->subpassCount); + } else if (pMultiviewInfo->dependencyCount && pMultiviewInfo->dependencyCount != pCreateInfo->dependencyCount) { + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + "VUID-VkRenderPassCreateInfo-pNext-01929", + "Dependency count is %u but multiview info has a dependency count of %u.", pCreateInfo->dependencyCount, + pMultiviewInfo->dependencyCount); + } + } + const VkRenderPassInputAttachmentAspectCreateInfo *pInputAttachmentAspectInfo = + lvl_find_in_chain(pCreateInfo->pNext); + if (pInputAttachmentAspectInfo) { + for (uint32_t i = 0; i < pInputAttachmentAspectInfo->aspectReferenceCount; ++i) { + uint32_t subpass = pInputAttachmentAspectInfo->pAspectReferences[i].subpass; + uint32_t attachment = pInputAttachmentAspectInfo->pAspectReferences[i].inputAttachmentIndex; + if (subpass >= pCreateInfo->subpassCount) { + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + "VUID-VkRenderPassCreateInfo-pNext-01926", + "Subpass index %u specified by input attachment aspect info %u is greater than the subpass " + "count of %u for this render pass.", + subpass, i, pCreateInfo->subpassCount); + } else if (pCreateInfo->pSubpasses && attachment >= pCreateInfo->pSubpasses[subpass].inputAttachmentCount) { + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, + "VUID-VkRenderPassCreateInfo-pNext-01927", + "Input attachment index %u specified by input attachment aspect info %u is greater than the " + "input attachment count of %u for this subpass.", + attachment, i, pCreateInfo->pSubpasses[subpass].inputAttachmentCount); + } } } + if (!skip) { - skip |= ValidateLayouts(dev_data, device, pCreateInfo); + skip |= ValidateCreateRenderPass(dev_data, device, RENDER_PASS_VERSION_1, render_pass->createInfo.ptr(), render_pass); } return skip; } @@ -10156,12 +10550,12 @@ static bool PreCallValidateCreateRenderPass(const layer_data *dev_data, VkDevice // Use of rvalue reference exceeds reccommended usage of rvalue refs in google style guide, but intentionally forces caller to move // or copy. This is clearer than passing a pointer to shared_ptr and avoids the atomic increment/decrement of shared_ptr copy // construction or assignment. -static void PostCallRecordCreateRenderPass(layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, - const VkRenderPass render_pass_handle, +static void PostCallRecordCreateRenderPass(layer_data *dev_data, const VkRenderPass render_pass_handle, std::shared_ptr &&render_pass) { render_pass->renderPass = render_pass_handle; + auto pCreateInfo = render_pass->createInfo.ptr(); for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { - const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i]; + const VkSubpassDescription2KHR &subpass = pCreateInfo->pSubpasses[i]; for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) { MarkAttachmentFirstUse(render_pass.get(), subpass.pColorAttachments[j].attachment, false); @@ -10185,11 +10579,13 @@ static void PostCallRecordCreateRenderPass(layer_data *dev_data, const VkRenderP VKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) { bool skip = false; + layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); // If we fail, this will act like a unique_ptr and auto-cleanup, as we aren't saving it anywhere auto render_pass = std::make_shared(pCreateInfo); unique_lock_t lock(global_lock); + skip = PreCallValidateCreateRenderPass(dev_data, device, pCreateInfo, render_pass.get()); lock.unlock(); @@ -10201,7 +10597,38 @@ VKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderP if (VK_SUCCESS == result) { lock.lock(); - PostCallRecordCreateRenderPass(dev_data, pCreateInfo, *pRenderPass, std::move(render_pass)); + PostCallRecordCreateRenderPass(dev_data, *pRenderPass, std::move(render_pass)); + } + return result; +} + +static bool PreCallValidateCreateRenderPass2KHR(const layer_data *dev_data, VkDevice device, + const VkRenderPassCreateInfo2KHR *pCreateInfo, RENDER_PASS_STATE *render_pass) { + return ValidateCreateRenderPass(dev_data, device, RENDER_PASS_VERSION_2, pCreateInfo, render_pass); +} + +VKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) { + bool skip = false; + + layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); + // If we fail, this will act like a unique_ptr and auto-cleanup, as we aren't saving it anywhere + auto render_pass = std::make_shared(pCreateInfo); + + unique_lock_t lock(global_lock); + + skip = PreCallValidateCreateRenderPass2KHR(dev_data, device, pCreateInfo, render_pass.get()); + lock.unlock(); + + if (skip) { + return VK_ERROR_VALIDATION_FAILED_EXT; + } + + VkResult result = dev_data->dispatch_table.CreateRenderPass2KHR(device, pCreateInfo, pAllocator, pRenderPass); + + if (VK_SUCCESS == result) { + lock.lock(); + PostCallRecordCreateRenderPass(dev_data, *pRenderPass, std::move(render_pass)); } return result; } @@ -10250,14 +10677,49 @@ static bool FormatSpecificLoadAndStoreOpSettings(VkFormat format, T color_depth_ return ((check_color_depth_load_op && (color_depth_op == op)) || (check_stencil_load_op && (stencil_op == op))); } -static bool PreCallValidateCmdBeginRenderPass(layer_data *dev_data, const RENDER_PASS_STATE *render_pass_state, - GLOBAL_CB_NODE *cb_state, const FRAMEBUFFER_STATE *framebuffer, +static bool PreCallValidateCmdBeginRenderPass(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, RenderPassCreateVersion rp_version, const VkRenderPassBeginInfo *pRenderPassBegin) { + auto render_pass_state = pRenderPassBegin ? GetRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr; + auto framebuffer = pRenderPassBegin ? GetFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr; + assert(cb_state); bool skip = false; + const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); + const char *vuid; + const char *const function_name = use_rp2 ? "vkCmdBeginRenderPass2KHR()" : "vkCmdBeginRenderPass()"; + if (render_pass_state) { uint32_t clear_op_size = 0; // Make sure pClearValues is at least as large as last LOAD_OP_CLEAR + // Handle extension struct from EXT_sample_locations + const VkRenderPassSampleLocationsBeginInfoEXT *pSampleLocationsBeginInfo = + lvl_find_in_chain(pRenderPassBegin->pNext); + if (pSampleLocationsBeginInfo) { + for (uint32_t i = 0; i < pSampleLocationsBeginInfo->attachmentInitialSampleLocationsCount; ++i) { + if (pSampleLocationsBeginInfo->pAttachmentInitialSampleLocations[i].attachmentIndex >= + render_pass_state->createInfo.attachmentCount) { + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, + 0, "VUID-VkAttachmentSampleLocationsEXT-attachmentIndex-01531", + "Attachment index %u specified by attachment sample locations %u is greater than the " + "attachment count of %u for the render pass being begun.", + pSampleLocationsBeginInfo->pAttachmentInitialSampleLocations[i].attachmentIndex, i, + render_pass_state->createInfo.attachmentCount); + } + } + + for (uint32_t i = 0; i < pSampleLocationsBeginInfo->postSubpassSampleLocationsCount; ++i) { + if (pSampleLocationsBeginInfo->pPostSubpassSampleLocations[i].subpassIndex >= + render_pass_state->createInfo.subpassCount) { + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, + 0, "VUID-VkSubpassSampleLocationsEXT-subpassIndex-01532", + "Subpass index %u specified by subpass sample locations %u is greater than the subpass count " + "of %u for the render pass being begun.", + pSampleLocationsBeginInfo->pPostSubpassSampleLocations[i].subpassIndex, i, + render_pass_state->createInfo.subpassCount); + } + } + } + for (uint32_t i = 0; i < render_pass_state->createInfo.attachmentCount; ++i) { auto pAttachment = &render_pass_state->createInfo.pAttachments[i]; if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp, pAttachment->stencilLoadOp, @@ -10269,36 +10731,45 @@ static bool PreCallValidateCmdBeginRenderPass(layer_data *dev_data, const RENDER if (clear_op_size > pRenderPassBegin->clearValueCount) { skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, HandleToUint64(render_pass_state->renderPass), "VUID-VkRenderPassBeginInfo-clearValueCount-00902", - "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but there " + "In %s the VkRenderPassBeginInfo struct has a clearValueCount of %u but there " "must be at least %u entries in pClearValues array to account for the highest index attachment in " "renderPass 0x%" PRIx64 " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u. Note that the pClearValues array is indexed by " "attachment number so even if some pClearValues entries between 0 and %u correspond to attachments " "that aren't cleared they will be ignored.", - pRenderPassBegin->clearValueCount, clear_op_size, HandleToUint64(render_pass_state->renderPass), - clear_op_size, clear_op_size - 1); + function_name, pRenderPassBegin->clearValueCount, clear_op_size, + HandleToUint64(render_pass_state->renderPass), clear_op_size, clear_op_size - 1); } skip |= VerifyRenderAreaBounds(dev_data, pRenderPassBegin); - skip |= VerifyFramebufferAndRenderPassLayouts(dev_data, cb_state, pRenderPassBegin, + skip |= VerifyFramebufferAndRenderPassLayouts(dev_data, rp_version, cb_state, pRenderPassBegin, GetFramebufferState(dev_data, pRenderPassBegin->framebuffer)); if (framebuffer->rp_state->renderPass != render_pass_state->renderPass) { skip |= ValidateRenderPassCompatibility(dev_data, "render pass", render_pass_state, "framebuffer", - framebuffer->rp_state.get(), "vkCmdBeginRenderPass()", + framebuffer->rp_state.get(), function_name, "VUID-VkRenderPassBeginInfo-renderPass-00904"); } - skip |= InsideRenderPass(dev_data, cb_state, "vkCmdBeginRenderPass()", "VUID-vkCmdBeginRenderPass-renderpass"); + + vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-renderpass" : "VUID-vkCmdBeginRenderPass-renderpass"; + skip |= InsideRenderPass(dev_data, cb_state, function_name, vuid); skip |= ValidateDependencies(dev_data, framebuffer, render_pass_state); - skip |= ValidatePrimaryCommandBuffer(dev_data, cb_state, "vkCmdBeginRenderPass()", "VUID-vkCmdBeginRenderPass-bufferlevel"); - skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBeginRenderPass()", VK_QUEUE_GRAPHICS_BIT, - "VUID-vkCmdBeginRenderPass-commandBuffer-cmdpool"); - skip |= ValidateCmd(dev_data, cb_state, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()"); + + vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-bufferlevel" : "VUID-vkCmdBeginRenderPass-bufferlevel"; + skip |= ValidatePrimaryCommandBuffer(dev_data, cb_state, function_name, vuid); + + vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-commandBuffer-cmdpool" : "VUID-vkCmdBeginRenderPass-commandBuffer-cmdpool"; + skip |= ValidateCmdQueueFlags(dev_data, cb_state, function_name, VK_QUEUE_GRAPHICS_BIT, vuid); + + const CMD_TYPE cmd_type = use_rp2 ? CMD_BEGINRENDERPASS2KHR : CMD_BEGINRENDERPASS; + skip |= ValidateCmd(dev_data, cb_state, cmd_type, function_name); } return skip; } -static void PreCallRecordCmdBeginRenderPass(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, FRAMEBUFFER_STATE *framebuffer, - RENDER_PASS_STATE *render_pass_state, const VkRenderPassBeginInfo *pRenderPassBegin, - const VkSubpassContents contents) { +static void PreCallRecordCmdBeginRenderPass(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, + const VkRenderPassBeginInfo *pRenderPassBegin, const VkSubpassContents contents) { + auto render_pass_state = pRenderPassBegin ? GetRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr; + auto framebuffer = pRenderPassBegin ? GetFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr; + assert(cb_state); if (render_pass_state) { cb_state->activeFramebuffer = pRenderPassBegin->framebuffer; @@ -10324,33 +10795,63 @@ VKAPI_ATTR void VKAPI_CALL CmdBeginRenderPass(VkCommandBuffer commandBuffer, con layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map); unique_lock_t lock(global_lock); GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer); - auto render_pass_state = pRenderPassBegin ? GetRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr; - auto framebuffer = pRenderPassBegin ? GetFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr; if (cb_state) { - skip |= PreCallValidateCmdBeginRenderPass(dev_data, render_pass_state, cb_state, framebuffer, pRenderPassBegin); + skip |= PreCallValidateCmdBeginRenderPass(dev_data, cb_state, RENDER_PASS_VERSION_1, pRenderPassBegin); if (!skip) { - PreCallRecordCmdBeginRenderPass(dev_data, cb_state, framebuffer, render_pass_state, pRenderPassBegin, contents); + PreCallRecordCmdBeginRenderPass(dev_data, cb_state, pRenderPassBegin, contents); } } + lock.unlock(); if (!skip) { dev_data->dispatch_table.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents); } } -static bool PreCallValidateCmdNextSubpass(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) { - bool skip = ValidatePrimaryCommandBuffer(dev_data, cb_state, "vkCmdNextSubpass()", "VUID-vkCmdNextSubpass-bufferlevel"); - skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdNextSubpass()", VK_QUEUE_GRAPHICS_BIT, - "VUID-vkCmdNextSubpass-commandBuffer-cmdpool"); - skip |= ValidateCmd(dev_data, cb_state, CMD_NEXTSUBPASS, "vkCmdNextSubpass()"); - skip |= OutsideRenderPass(dev_data, cb_state, "vkCmdNextSubpass()", "VUID-vkCmdNextSubpass-renderpass"); +VKAPI_ATTR void VKAPI_CALL CmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, + const VkSubpassBeginInfoKHR *pSubpassBeginInfo) { + bool skip = false; + layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map); + unique_lock_t lock(global_lock); + GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer); + if (cb_state) { + skip |= PreCallValidateCmdBeginRenderPass(dev_data, cb_state, RENDER_PASS_VERSION_2, pRenderPassBegin); + if (!skip) { + PreCallRecordCmdBeginRenderPass(dev_data, cb_state, pRenderPassBegin, pSubpassBeginInfo->contents); + } + } + + lock.unlock(); + if (!skip) { + dev_data->dispatch_table.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, pSubpassBeginInfo->contents); + } +} + +static bool PreCallValidateCmdNextSubpass(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, RenderPassCreateVersion rp_version, + VkCommandBuffer commandBuffer) { + bool skip = false; + const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); + const char *vuid; + const char *const function_name = use_rp2 ? "vkCmdNextSubpass2KHR()" : "vkCmdNextSubpass()"; + + vuid = use_rp2 ? "VUID-vkCmdNextSubpass2KHR-bufferlevel" : "VUID-vkCmdNextSubpass-bufferlevel"; + skip |= ValidatePrimaryCommandBuffer(dev_data, cb_state, function_name, vuid); + + vuid = use_rp2 ? "VUID-vkCmdNextSubpass2KHR-commandBuffer-cmdpool" : "VUID-vkCmdNextSubpass-commandBuffer-cmdpool"; + skip |= ValidateCmdQueueFlags(dev_data, cb_state, function_name, VK_QUEUE_GRAPHICS_BIT, vuid); + const CMD_TYPE cmd_type = use_rp2 ? CMD_NEXTSUBPASS2KHR : CMD_NEXTSUBPASS; + skip |= ValidateCmd(dev_data, cb_state, cmd_type, function_name); + + vuid = use_rp2 ? "VUID-vkCmdNextSubpass2KHR-renderpass" : "VUID-vkCmdNextSubpass-renderpass"; + skip |= OutsideRenderPass(dev_data, cb_state, function_name, vuid); auto subpassCount = cb_state->activeRenderPass->createInfo.subpassCount; if (cb_state->activeSubpass == subpassCount - 1) { + vuid = use_rp2 ? "VUID-vkCmdNextSubpass2KHR-None-03102" : "VUID-vkCmdNextSubpass-None-00909"; skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - HandleToUint64(commandBuffer), "VUID-vkCmdNextSubpass-None-00909", - "vkCmdNextSubpass(): Attempted to advance beyond final subpass."); + HandleToUint64(commandBuffer), vuid, "%s: Attempted to advance beyond final subpass.", function_name); } + return skip; } @@ -10367,7 +10868,7 @@ VKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpa unique_lock_t lock(global_lock); GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer); if (pCB) { - skip |= PreCallValidateCmdNextSubpass(dev_data, pCB, commandBuffer); + skip |= PreCallValidateCmdNextSubpass(dev_data, pCB, RENDER_PASS_VERSION_1, commandBuffer); } lock.unlock(); @@ -10381,21 +10882,54 @@ VKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpa } } -static bool PreCallValidateCmdEndRenderPass(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) { +VKAPI_ATTR void VKAPI_CALL CmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR *pSubpassBeginInfo, + const VkSubpassEndInfoKHR *pSubpassEndInfo) { + bool skip = false; + layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map); + unique_lock_t lock(global_lock); + GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer); + if (pCB) { + skip |= PreCallValidateCmdNextSubpass(dev_data, pCB, RENDER_PASS_VERSION_2, commandBuffer); + } + lock.unlock(); + + if (skip) return; + + dev_data->dispatch_table.CmdNextSubpass(commandBuffer, pSubpassBeginInfo->contents); + + if (pCB) { + lock.lock(); + PostCallRecordCmdNextSubpass(dev_data, pCB, pSubpassBeginInfo->contents); + } +} +static bool PreCallValidateCmdEndRenderPass(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, RenderPassCreateVersion rp_version, + VkCommandBuffer commandBuffer) { bool skip = false; + + const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); + const char *vuid; + const char *const function_name = use_rp2 ? "vkCmdEndRenderPass2KHR()" : "vkCmdEndRenderPass()"; + RENDER_PASS_STATE *rp_state = cb_state->activeRenderPass; if (rp_state) { if (cb_state->activeSubpass != rp_state->createInfo.subpassCount - 1) { + vuid = use_rp2 ? "VUID-vkCmdEndRenderPass2KHR-None-03103" : "VUID-vkCmdEndRenderPass-None-00910"; skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, - HandleToUint64(commandBuffer), "VUID-vkCmdEndRenderPass-None-00910", - "vkCmdEndRenderPass(): Called before reaching final subpass."); + HandleToUint64(commandBuffer), vuid, "%s: Called before reaching final subpass.", function_name); } } - skip |= OutsideRenderPass(dev_data, cb_state, "vkCmdEndRenderpass()", "VUID-vkCmdEndRenderPass-renderpass"); - skip |= ValidatePrimaryCommandBuffer(dev_data, cb_state, "vkCmdEndRenderPass()", "VUID-vkCmdEndRenderPass-bufferlevel"); - skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdEndRenderPass()", VK_QUEUE_GRAPHICS_BIT, - "VUID-vkCmdEndRenderPass-commandBuffer-cmdpool"); - skip |= ValidateCmd(dev_data, cb_state, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()"); + + vuid = use_rp2 ? "VUID-vkCmdEndRenderPass2KHR-renderpass" : "VUID-vkCmdEndRenderPass-renderpass"; + skip |= OutsideRenderPass(dev_data, cb_state, function_name, vuid); + + vuid = use_rp2 ? "VUID-vkCmdEndRenderPass2KHR-bufferlevel" : "VUID-vkCmdEndRenderPass-bufferlevel"; + skip |= ValidatePrimaryCommandBuffer(dev_data, cb_state, function_name, vuid); + + vuid = use_rp2 ? "VUID-vkCmdEndRenderPass2KHR-commandBuffer-cmdpool" : "VUID-vkCmdEndRenderPass-commandBuffer-cmdpool"; + skip |= ValidateCmdQueueFlags(dev_data, cb_state, function_name, VK_QUEUE_GRAPHICS_BIT, vuid); + + const CMD_TYPE cmd_type = use_rp2 ? CMD_ENDRENDERPASS2KHR : CMD_ENDRENDERPASS; + skip |= ValidateCmd(dev_data, cb_state, cmd_type, function_name); return skip; } @@ -10413,7 +10947,27 @@ VKAPI_ATTR void VKAPI_CALL CmdEndRenderPass(VkCommandBuffer commandBuffer) { unique_lock_t lock(global_lock); auto pCB = GetCBNode(dev_data, commandBuffer); if (pCB) { - skip |= PreCallValidateCmdEndRenderPass(dev_data, pCB, commandBuffer); + skip |= PreCallValidateCmdEndRenderPass(dev_data, pCB, RENDER_PASS_VERSION_1, commandBuffer); + } + lock.unlock(); + + if (skip) return; + + dev_data->dispatch_table.CmdEndRenderPass(commandBuffer); + + if (pCB) { + lock.lock(); + PostCallRecordCmdEndRenderPass(dev_data, pCB); + } +} + +VKAPI_ATTR void VKAPI_CALL CmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR *pSubpassEndInfo) { + bool skip = false; + layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map); + unique_lock_t lock(global_lock); + auto pCB = GetCBNode(dev_data, commandBuffer); + if (pCB) { + skip |= PreCallValidateCmdEndRenderPass(dev_data, pCB, RENDER_PASS_VERSION_2, commandBuffer); } lock.unlock(); @@ -14367,6 +14921,10 @@ static const std::unordered_map name_to_funcptr_map = { {"vkCmdDrawMeshTasksIndirectNV", (void *)CmdDrawMeshTasksIndirectNV}, {"vkCmdDrawMeshTasksIndirectCountNV", (void *)CmdDrawMeshTasksIndirectCountNV}, {"vkCreateRaytracingPipelinesNVX", (void *)CreateRaytracingPipelinesNVX}, + {"vkCreateRenderPass2KHR", (void *)CreateRenderPass2KHR}, + {"vkCmdBeginRenderPass2KHR", (void *)CmdBeginRenderPass2KHR}, + {"vkCmdNextSubpass2KHR", (void *)CmdNextSubpass2KHR}, + {"vkCmdEndRenderPass2KHR", (void *)CmdEndRenderPass2KHR}, }; VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) { diff --git a/layers/core_validation_types.h b/layers/core_validation_types.h index 0de7dd3f37b..827e3f99860 100644 --- a/layers/core_validation_types.h +++ b/layers/core_validation_types.h @@ -30,6 +30,7 @@ #include "vk_layer_logging.h" #include "vk_object_types.h" #include "vk_extension_helper.h" +#include "convert_to_renderpass2.h" #include #include #include @@ -414,12 +415,13 @@ struct DAGNode { struct RENDER_PASS_STATE : public BASE_NODE { VkRenderPass renderPass; - safe_VkRenderPassCreateInfo createInfo; + safe_VkRenderPassCreateInfo2KHR createInfo; std::vector> self_dependencies; std::vector subpassToNode; std::unordered_map attachment_first_read; - RENDER_PASS_STATE(VkRenderPassCreateInfo const *pCreateInfo) : createInfo(pCreateInfo) {} + RENDER_PASS_STATE(VkRenderPassCreateInfo2KHR const *pCreateInfo) : createInfo(pCreateInfo) {} + RENDER_PASS_STATE(VkRenderPassCreateInfo const *pCreateInfo) { ConvertVkRenderPassCreateInfoToV2KHR(pCreateInfo, &createInfo); } }; // vkCmd tracking -- complete as of header 1.0.68 @@ -430,6 +432,7 @@ enum CMD_TYPE { CMD_NONE, CMD_BEGINQUERY, CMD_BEGINRENDERPASS, + CMD_BEGINRENDERPASS2KHR, CMD_BINDDESCRIPTORSETS, CMD_BINDINDEXBUFFER, CMD_BINDPIPELINE, @@ -464,9 +467,11 @@ enum CMD_TYPE { CMD_ENDCOMMANDBUFFER, // Should be the last command in any RECORDED cmd buffer CMD_ENDQUERY, CMD_ENDRENDERPASS, + CMD_ENDRENDERPASS2KHR, CMD_EXECUTECOMMANDS, CMD_FILLBUFFER, CMD_NEXTSUBPASS, + CMD_NEXTSUBPASS2KHR, CMD_PIPELINEBARRIER, CMD_PROCESSCOMMANDSNVX, CMD_PUSHCONSTANTS, @@ -1102,6 +1107,8 @@ struct DeviceFeatures { VkPhysicalDeviceInlineUniformBlockFeaturesEXT inline_uniform_block; }; +enum RenderPassCreateVersion { RENDER_PASS_VERSION_1 = 0, RENDER_PASS_VERSION_2 = 1 }; + // Fwd declarations of layer_data and helpers to look-up/validate state from layer_data maps namespace core_validation { struct layer_data; diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp index 36f42572329..76d45584d55 100644 --- a/tests/layer_validation_tests.cpp +++ b/tests/layer_validation_tests.cpp @@ -4875,9 +4875,9 @@ TEST_F(VkLayerTest, InvalidSecondaryCommandBufferBarrier) { }; VkSubpassDependency dep = {0, 0, - VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_HOST_WRITE_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_DEPENDENCY_BY_REGION_BIT}; VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attach, 1, subpasses, 1, &dep}; @@ -4931,7 +4931,7 @@ TEST_F(VkLayerTest, InvalidSecondaryCommandBufferBarrier) { vkBeginCommandBuffer(secondary.handle(), &cbbi); VkImageMemoryBarrier img_barrier = {}; img_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - img_barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + img_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; img_barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; img_barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; img_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; @@ -4943,7 +4943,7 @@ TEST_F(VkLayerTest, InvalidSecondaryCommandBufferBarrier) { img_barrier.subresourceRange.baseMipLevel = 0; img_barrier.subresourceRange.layerCount = 1; img_barrier.subresourceRange.levelCount = 1; - vkCmdPipelineBarrier(secondary.handle(), VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + vkCmdPipelineBarrier(secondary.handle(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, &img_barrier); secondary.end(); @@ -5303,9 +5303,9 @@ TEST_F(VkPositiveLayerTest, SecondaryCommandBufferBarrier) { }; VkSubpassDependency dep = {0, 0, - VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_HOST_WRITE_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_DEPENDENCY_BY_REGION_BIT}; VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attach, 1, subpasses, 1, &dep}; @@ -5357,13 +5357,13 @@ TEST_F(VkPositiveLayerTest, SecondaryCommandBufferBarrier) { VkMemoryBarrier mem_barrier = {}; mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; mem_barrier.pNext = NULL; - mem_barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + mem_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; mem_barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - vkCmdPipelineBarrier(secondary.handle(), VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + vkCmdPipelineBarrier(secondary.handle(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 1, &mem_barrier, 0, nullptr, 0, nullptr); VkImageMemoryBarrier img_barrier = {}; img_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - img_barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + img_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; img_barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; img_barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; img_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; @@ -5375,7 +5375,7 @@ TEST_F(VkPositiveLayerTest, SecondaryCommandBufferBarrier) { img_barrier.subresourceRange.baseMipLevel = 0; img_barrier.subresourceRange.layerCount = 1; img_barrier.subresourceRange.levelCount = 1; - vkCmdPipelineBarrier(secondary.handle(), VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + vkCmdPipelineBarrier(secondary.handle(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, &img_barrier); secondary.end(); @@ -5591,18 +5591,20 @@ TEST_F(VkLayerTest, CreateRenderPassAttachments) { } // Test sample count mismatch between color buffers attachments[subpass.pColorAttachments[1].attachment].samples = VK_SAMPLE_COUNT_8_BIT; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAttachmentDescription-samples-parameter"); + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pColorAttachments-01417"); err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); m_errorMonitor->VerifyFound(); if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); attachments[subpass.pColorAttachments[1].attachment].samples = attachments[subpass.pColorAttachments[0].attachment].samples; // Test sample count mismatch between color buffers and depth buffer attachments[subpass.pDepthStencilAttachment->attachment].samples = VK_SAMPLE_COUNT_8_BIT; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAttachmentDescription-samples-parameter"); + subpass.colorAttachmentCount = 1; + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pDepthStencilAttachment-01418"); err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); m_errorMonitor->VerifyFound(); if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); attachments[subpass.pDepthStencilAttachment->attachment].samples = attachments[subpass.pColorAttachments[0].attachment].samples; + subpass.colorAttachmentCount = (uint32_t)color.size(); // Test resolve attachment with UNUSED color attachment color[0].attachment = VK_ATTACHMENT_UNUSED; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pResolveAttachments-00847"); @@ -5612,13 +5614,15 @@ TEST_F(VkLayerTest, CreateRenderPassAttachments) { color[0].attachment = 1; // Test resolve from a single-sampled color attachment attachments[subpass.pColorAttachments[0].attachment].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[subpass.pColorAttachments[1].attachment].samples = VK_SAMPLE_COUNT_1_BIT; // avoid mismatch (00337) + subpass.colorAttachmentCount = 1; // avoid mismatch (00337), and avoid double report + subpass.pDepthStencilAttachment = nullptr; // avoid mismatch (01418) m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pResolveAttachments-00848"); err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); m_errorMonitor->VerifyFound(); if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); attachments[subpass.pColorAttachments[0].attachment].samples = VK_SAMPLE_COUNT_4_BIT; - attachments[subpass.pColorAttachments[1].attachment].samples = VK_SAMPLE_COUNT_4_BIT; + subpass.colorAttachmentCount = (uint32_t)color.size(); // avoid mismatch (00337), and avoid double report + subpass.pDepthStencilAttachment = &depth; // Test resolve to a multi-sampled resolve attachment attachments[subpass.pResolveAttachments[0].attachment].samples = VK_SAMPLE_COUNT_4_BIT; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pResolveAttachments-00849"); From 3511658dc9d41a8afa2d6d6515f3f3b2f9af630c Mon Sep 17 00:00:00 2001 From: Tobias Hector Date: Mon, 22 Oct 2018 15:18:56 +0100 Subject: [PATCH 2/3] layers: Added parameter validation for CRP2 Factored out some of the vkCreateRenderPass into a common function, and added vkCreateRenderPass2KHR using that same code. --- layers/parameter_validation_utils.cpp | 107 +++++++++++++++++----- scripts/parameter_validation_generator.py | 1 + 2 files changed, 84 insertions(+), 24 deletions(-) diff --git a/layers/parameter_validation_utils.cpp b/layers/parameter_validation_utils.cpp index f538153bf86..b379d65f7f8 100644 --- a/layers/parameter_validation_utils.cpp +++ b/layers/parameter_validation_utils.cpp @@ -89,6 +89,8 @@ extern bool parameter_validation_vkCreateCommandPool(VkDevice device, const VkCo const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool); extern bool parameter_validation_vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); +extern bool parameter_validation_vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); extern bool parameter_validation_vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator); @@ -118,6 +120,8 @@ static const VkLayerProperties global_layer = { "LunarG Validation Layer", }; +enum RenderPassCreateVersion { RENDER_PASS_VERSION_1 = 0, RENDER_PASS_VERSION_2 = 1 }; + static const int MaxParamCheckerStringLength = 256; template @@ -758,6 +762,25 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool(VkDevice device, const VkQueryP return result; } +template +static void RecordRenderPass(layer_data *device_data, VkRenderPass renderPass, const T *pCreateInfo) { + auto &renderpass_state = device_data->renderpasses_states[renderPass]; + + for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) { + bool uses_color = false; + for (uint32_t i = 0; i < pCreateInfo->pSubpasses[subpass].colorAttachmentCount && !uses_color; ++i) + if (pCreateInfo->pSubpasses[subpass].pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) uses_color = true; + + bool uses_depthstencil = false; + if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment) + if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) + uses_depthstencil = true; + + if (uses_color) renderpass_state.subpasses_using_color_attachment.insert(subpass); + if (uses_depthstencil) renderpass_state.subpasses_using_depthstencil_attachment.insert(subpass); + } +} + VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) { layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); @@ -782,22 +805,38 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(VkDevice device, const VkRende // track the state necessary for checking vkCreateGraphicsPipeline (subpass usage of depth and color attachments) if (result == VK_SUCCESS) { std::unique_lock lock(global_lock); - const auto renderPass = *pRenderPass; - auto &renderpass_state = device_data->renderpasses_states[renderPass]; + RecordRenderPass(device_data, *pRenderPass, pCreateInfo); + } + } + return result; +} - for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) { - bool uses_color = false; - for (uint32_t i = 0; i < pCreateInfo->pSubpasses[subpass].colorAttachmentCount && !uses_color; ++i) - if (pCreateInfo->pSubpasses[subpass].pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) uses_color = true; +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) { + layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); + bool skip = false; + VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; - bool uses_depthstencil = false; - if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment) - if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) - uses_depthstencil = true; + { + std::unique_lock lock(global_lock); + skip |= parameter_validation_vkCreateRenderPass2KHR(device, pCreateInfo, pAllocator, pRenderPass); - if (uses_color) renderpass_state.subpasses_using_color_attachment.insert(subpass); - if (uses_depthstencil) renderpass_state.subpasses_using_depthstencil_attachment.insert(subpass); - } + typedef bool (*PFN_manual_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); + PFN_manual_vkCreateRenderPass2KHR custom_func = + (PFN_manual_vkCreateRenderPass2KHR)custom_functions["vkCreateRenderPass2KHR"]; + if (custom_func != nullptr) { + skip |= custom_func(device, pCreateInfo, pAllocator, pRenderPass); + } + } + + if (!skip) { + result = device_data->dispatch_table.CreateRenderPass2KHR(device, pCreateInfo, pAllocator, pRenderPass); + + // track the state necessary for checking vkCreateGraphicsPipeline (subpass usage of depth and color attachments) + if (result == VK_SUCCESS) { + std::unique_lock lock(global_lock); + RecordRenderPass(device_data, *pRenderPass, pCreateInfo); } } return result; @@ -2629,40 +2668,59 @@ bool pv_vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, c return skip; } -bool pv_vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, - VkRenderPass *pRenderPass) { +template +bool pv_CreateRenderPassGeneric(VkDevice device, const RenderPassCreateInfoGeneric *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass, + RenderPassCreateVersion rp_version) { bool skip = false; layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); uint32_t max_color_attachments = device_data->device_limits.maxColorAttachments; + bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2); + const char *vuid; for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) { if (pCreateInfo->pAttachments[i].format == VK_FORMAT_UNDEFINED) { std::stringstream ss; - ss << "vkCreateRenderPass: pCreateInfo->pAttachments[" << i << "].format is VK_FORMAT_UNDEFINED. "; + ss << (use_rp2 ? "vkCreateRenderPass2KHR" : "vkCreateRenderPass") << ": pCreateInfo->pAttachments[" << i + << "].format is VK_FORMAT_UNDEFINED. "; + vuid = use_rp2 ? "VUID-VkAttachmentDescription2KHR-format-parameter" : "VUID-VkAttachmentDescription-format-parameter"; skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkAttachmentDescription-format-parameter", "%s", ss.str().c_str()); + vuid, "%s", ss.str().c_str()); } if (pCreateInfo->pAttachments[i].finalLayout == VK_IMAGE_LAYOUT_UNDEFINED || pCreateInfo->pAttachments[i].finalLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) { - skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkAttachmentDescription-finalLayout-00843", - "pCreateInfo->pAttachments[%d].finalLayout must not be VK_IMAGE_LAYOUT_UNDEFINED or " - "VK_IMAGE_LAYOUT_PREINITIALIZED.", - i); + vuid = + use_rp2 ? "VUID-VkAttachmentDescription2KHR-finalLayout-03061" : "VUID-VkAttachmentDescription-finalLayout-00843"; + skip |= + log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, + "pCreateInfo->pAttachments[%d].finalLayout must not be VK_IMAGE_LAYOUT_UNDEFINED or " + "VK_IMAGE_LAYOUT_PREINITIALIZED.", + i); } } for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { if (pCreateInfo->pSubpasses[i].colorAttachmentCount > max_color_attachments) { + vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-colorAttachmentCount-03063" + : "VUID-VkSubpassDescription-colorAttachmentCount-00845"; skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, - "VUID-VkSubpassDescription-colorAttachmentCount-00845", - "Cannot create a render pass with %d color attachments. Max is %d.", + vuid, "Cannot create a render pass with %d color attachments. Max is %d.", pCreateInfo->pSubpasses[i].colorAttachmentCount, max_color_attachments); } } return skip; } +bool pv_vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, + VkRenderPass *pRenderPass) { + return pv_CreateRenderPassGeneric(device, pCreateInfo, pAllocator, pRenderPass, RENDER_PASS_VERSION_1); +} + +bool pv_vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) { + return pv_CreateRenderPassGeneric(device, pCreateInfo, pAllocator, pRenderPass, RENDER_PASS_VERSION_2); +} + bool pv_vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) { bool skip = false; @@ -3593,6 +3651,7 @@ void InitializeManualParameterValidationFunctionPointers() { custom_functions["vkFreeDescriptorSets"] = (void *)pv_vkFreeDescriptorSets; custom_functions["vkUpdateDescriptorSets"] = (void *)pv_vkUpdateDescriptorSets; custom_functions["vkCreateRenderPass"] = (void *)pv_vkCreateRenderPass; + custom_functions["vkCreateRenderPass2KHR"] = (void *)pv_vkCreateRenderPass2KHR; custom_functions["vkBeginCommandBuffer"] = (void *)pv_vkBeginCommandBuffer; custom_functions["vkCmdSetViewport"] = (void *)pv_vkCmdSetViewport; custom_functions["vkCmdSetScissor"] = (void *)pv_vkCmdSetScissor; diff --git a/scripts/parameter_validation_generator.py b/scripts/parameter_validation_generator.py index 3262050067a..ad3b36fd3ab 100644 --- a/scripts/parameter_validation_generator.py +++ b/scripts/parameter_validation_generator.py @@ -146,6 +146,7 @@ def __init__(self, 'vkDestroyDebugReportCallbackEXT', 'vkCreateCommandPool', 'vkCreateRenderPass', + 'vkCreateRenderPass2KHR', 'vkDestroyRenderPass', 'vkCreateDebugUtilsMessengerEXT', 'vkDestroyDebugUtilsMessengerEXT', From 8e26c7ee168afca90620314f20d825197a934bf5 Mon Sep 17 00:00:00 2001 From: Tobias Hector Date: Fri, 26 Oct 2018 16:43:31 +0100 Subject: [PATCH 3/3] tests: Added tests for all the new VUID checks Relevant tests (anything that tests the covered VUID checks) have also been reorganised so that they could be better audited. All such tests are now renamed to follow the pattern "RenderPass{Create|Begin|Destroy|NextSubpass|End}...", and any tests that previously began with "RenderPass..." have been renamed appropriately. --- build-android/jni/Android.mk | 4 + tests/CMakeLists.txt | 1 + tests/layer_validation_tests.cpp | 3696 ++++++++++++++++++++---------- 3 files changed, 2462 insertions(+), 1239 deletions(-) diff --git a/build-android/jni/Android.mk b/build-android/jni/Android.mk index 39f04642a1e..e0824ae1050 100644 --- a/build-android/jni/Android.mk +++ b/build-android/jni/Android.mk @@ -116,6 +116,8 @@ LOCAL_SRC_FILES += $(SRC_DIR)/tests/layer_validation_tests.cpp \ $(SRC_DIR)/tests/vktestbinding.cpp \ $(SRC_DIR)/tests/vktestframeworkandroid.cpp \ $(SRC_DIR)/tests/vkrenderframework.cpp \ + $(SRC_DIR)/layers/convert_to_renderpass2.cpp \ + $(LAYER_DIR)/include/vk_safe_struct.cpp \ $(THIRD_PARTY)/Vulkan-Tools/common/vulkan_wrapper.cpp LOCAL_C_INCLUDES += $(VULKAN_INCLUDE) \ $(LOCAL_PATH)/$(LAYER_DIR)/include \ @@ -138,6 +140,8 @@ LOCAL_SRC_FILES += $(SRC_DIR)/tests/layer_validation_tests.cpp \ $(SRC_DIR)/tests/vktestbinding.cpp \ $(SRC_DIR)/tests/vktestframeworkandroid.cpp \ $(SRC_DIR)/tests/vkrenderframework.cpp \ + $(SRC_DIR)/layers/convert_to_renderpass2.cpp \ + $(LAYER_DIR)/include/vk_safe_struct.cpp \ $(THIRD_PARTY)/Vulkan-Tools/common/vulkan_wrapper.cpp LOCAL_C_INCLUDES += $(VULKAN_INCLUDE) \ $(LOCAL_PATH)/$(LAYER_DIR)/include \ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 022c85fa2c0..f13d2b5097b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -103,6 +103,7 @@ set_source_files_properties(${PROJECT_BINARY_DIR}/vk_safe_struct.cpp PROPERTIES add_executable(vk_layer_validation_tests layer_validation_tests.cpp ../layers/vk_format_utils.cpp + ../layers/convert_to_renderpass2.cpp ${PROJECT_BINARY_DIR}/vk_safe_struct.cpp ${COMMON_CPP}) set_target_properties(vk_layer_validation_tests PROPERTIES COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp index 76d45584d55..ac409c77165 100644 --- a/tests/layer_validation_tests.cpp +++ b/tests/layer_validation_tests.cpp @@ -44,6 +44,7 @@ #include "vk_validation_error_messages.h" #include "vkrenderframework.h" #include "vk_typemap_helper.h" +#include "convert_to_renderpass2.h" #include #include @@ -4449,121 +4450,9 @@ TEST_F(VkLayerTest, MismatchedQueueFamiliesOnSubmit) { m_errorMonitor->VerifyFound(); } -TEST_F(VkLayerTest, RenderPassAttachmentIndexOutOfRange) { - ASSERT_NO_FATAL_FAILURE(Init()); - - // There are no attachments, but refer to attachment 0. - VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - VkSubpassDescription subpasses[] = { - {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &ref, nullptr, nullptr, 0, nullptr}, - }; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 1, subpasses, 0, nullptr}; - VkRenderPass rp; - - // "... must be less than the total number of attachments ..." - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkRenderPassCreateInfo-attachment-00834"); - vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); -} - -TEST_F(VkLayerTest, RenderPassAttachmentUsedTwiceColor) { - ASSERT_NO_FATAL_FAILURE(Init()); - TEST_DESCRIPTION("Attachment is used simultaneously as two color attachments. This is not acceptable."); - - VkAttachmentDescription attach[] = { - {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, - }; - VkAttachmentReference refs[] = { - {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, - {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, - }; - VkSubpassDescription subpasses[] = { - {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 2, refs, nullptr, nullptr, 0, nullptr}, - }; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attach, 1, subpasses, 0, nullptr}; - VkRenderPass rp; - - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, - "subpass 0 already uses attachment 0 as a color attachment"); - vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); -} - -TEST_F(VkLayerTest, RenderPassAttachmentUsedTwiceMismatchingLayout) { - ASSERT_NO_FATAL_FAILURE(Init()); - - TEST_DESCRIPTION("Attachment is used simultaneously as color and input. The layouts differ, which is not acceptable."); - - VkAttachmentDescription attach[] = { - {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL}, - }; - VkAttachmentReference color_ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - VkAttachmentReference input_ref = {0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; - VkSubpassDescription subpasses[] = { - {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &input_ref, 1, &color_ref, nullptr, nullptr, 0, nullptr}, - }; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attach, 1, subpasses, 0, nullptr}; - VkRenderPass rp; - - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-layout-00855"); - vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); -} - -TEST_F(VkPositiveLayerTest, RenderPassAttachmentUsedTwiceOK) { - ASSERT_NO_FATAL_FAILURE(Init()); - - TEST_DESCRIPTION("Attachment is used simultaneously as color and input, with the same layout. This is OK."); - - VkAttachmentDescription attach[] = { - {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL}, - }; - VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_GENERAL}; - VkSubpassDescription subpasses[] = { - {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &ref, 1, &ref, nullptr, nullptr, 0, nullptr}, - }; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attach, 1, subpasses, 0, nullptr}; - VkRenderPass rp; - - m_errorMonitor->ExpectSuccess(); - vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyNotFound(); - vkDestroyRenderPass(m_device->device(), rp, nullptr); -} - -TEST_F(VkLayerTest, RenderPassAttachmentUsedTwicePreserveAndColor) { - ASSERT_NO_FATAL_FAILURE(Init()); - - TEST_DESCRIPTION("Attachment is used simultaneously as color and preserve. This is not acceptable."); - - VkAttachmentDescription attach[] = { - {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL}, - }; - VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_GENERAL}; - uint32_t preserve_attachment = 0; - VkSubpassDescription subpasses[] = { - {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &ref, nullptr, nullptr, 1, &preserve_attachment}, - }; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attach, 1, subpasses, 0, nullptr}; - VkRenderPass rp; - - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pPreserveAttachments-00854"); - vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); -} - -TEST_F(VkLayerTest, RenderPassPipelineSubpassMismatch) { +TEST_F(VkLayerTest, DrawWithPipelineIncompatibleWithSubpass) { TEST_DESCRIPTION("Use a pipeline for the wrong subpass in a render pass instance"); + ASSERT_NO_FATAL_FAILURE(Init()); // A renderpass with two subpasses, both writing the same attachment. @@ -4662,7 +4551,7 @@ TEST_F(VkLayerTest, RenderPassPipelineSubpassMismatch) { vkDestroyRenderPass(m_device->device(), rp, nullptr); } -TEST_F(VkLayerTest, RenderPassBarrierConflicts) { +TEST_F(VkLayerTest, ImageBarrierSubpassConflicts) { TEST_DESCRIPTION("Add a pipeline barrier within a subpass that has conflicting state"); ASSERT_NO_FATAL_FAILURE(Init()); @@ -5394,152 +5283,289 @@ TEST_F(VkPositiveLayerTest, SecondaryCommandBufferBarrier) { vkDestroyRenderPass(m_device->device(), rp, nullptr); } -TEST_F(VkLayerTest, RenderPassInvalidRenderArea) { - TEST_DESCRIPTION("Generate INVALID_RENDER_AREA error by beginning renderpass with extent outside of framebuffer"); - ASSERT_NO_FATAL_FAILURE(Init()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); +static void TestRenderPassCreate(ErrorMonitor *error_monitor, const VkDevice device, const VkRenderPassCreateInfo *create_info, + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR, const char *rp1_vuid, const char *rp2_vuid) { + // "... must be less than the total number of attachments ..." + VkRenderPass render_pass = VK_NULL_HANDLE; + VkResult err; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, - "Cannot execute a render pass with renderArea not within the bound of the framebuffer."); + if (rp1_vuid) { + error_monitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, rp1_vuid); + err = vkCreateRenderPass(device, create_info, nullptr, &render_pass); + if (err == VK_SUCCESS) vkDestroyRenderPass(device, render_pass, nullptr); + error_monitor->VerifyFound(); + } - // Framebuffer for render target is 256x256, exceed that for INVALID_RENDER_AREA - m_renderPassBeginInfo.renderArea.extent.width = 257; - m_renderPassBeginInfo.renderArea.extent.height = 257; - m_commandBuffer->begin(); - m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); - m_errorMonitor->VerifyFound(); + if (vkCreateRenderPass2KHR && rp2_vuid) { + safe_VkRenderPassCreateInfo2KHR create_info2; + ConvertVkRenderPassCreateInfoToV2KHR(create_info, &create_info2); + + error_monitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, rp2_vuid); + err = vkCreateRenderPass2KHR(device, create_info2.ptr(), nullptr, &render_pass); + if (err == VK_SUCCESS) vkDestroyRenderPass(device, render_pass, nullptr); + error_monitor->VerifyFound(); + } } -TEST_F(VkLayerTest, DisabledIndependentBlend) { - TEST_DESCRIPTION( - "Generate INDEPENDENT_BLEND by disabling independent blend and then specifying different blend states for two " - "attachments"); - VkPhysicalDeviceFeatures features = {}; - features.independentBlend = VK_FALSE; - ASSERT_NO_FATAL_FAILURE(Init(&features)); +TEST_F(VkLayerTest, RenderPassCreateAttachmentIndexOutOfRange) { + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } - m_errorMonitor->SetDesiredFailureMsg( - VK_DEBUG_REPORT_ERROR_BIT_EXT, - "Invalid Pipeline CreateInfo: If independent blend feature not enabled, all elements of pAttachments must be identical"); + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr; + bool rp2Supported = false; - VkDescriptorSetObj descriptorSet(m_device); - descriptorSet.AppendDummy(); - descriptorSet.CreateVKDescriptorSet(m_commandBuffer); + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); - VkPipelineObj pipeline(m_device); - // Create a renderPass with two color attachments - VkAttachmentReference attachments[2] = {}; - attachments[0].layout = VK_IMAGE_LAYOUT_GENERAL; - attachments[1].attachment = 1; - attachments[1].layout = VK_IMAGE_LAYOUT_GENERAL; + if (rp2Supported) { + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + } - VkSubpassDescription subpass = {}; - subpass.pColorAttachments = attachments; - subpass.colorAttachmentCount = 2; + // There are no attachments, but refer to attachment 0. + VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkSubpassDescription subpasses[] = { + {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &ref, nullptr, nullptr, 0, nullptr}, + }; - VkRenderPassCreateInfo rpci = {}; - rpci.subpassCount = 1; - rpci.pSubpasses = &subpass; - rpci.attachmentCount = 2; + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 1, subpasses, 0, nullptr}; - VkAttachmentDescription attach_desc[2] = {}; - attach_desc[0].format = VK_FORMAT_B8G8R8A8_UNORM; - attach_desc[0].samples = VK_SAMPLE_COUNT_1_BIT; - attach_desc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attach_desc[0].finalLayout = VK_IMAGE_LAYOUT_GENERAL; - attach_desc[1].format = VK_FORMAT_B8G8R8A8_UNORM; - attach_desc[1].samples = VK_SAMPLE_COUNT_1_BIT; - attach_desc[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attach_desc[1].finalLayout = VK_IMAGE_LAYOUT_GENERAL; + // "... must be less than the total number of attachments ..." + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkRenderPassCreateInfo-attachment-00834", "VUID-VkRenderPassCreateInfo2KHR-attachment-03051"); +} - rpci.pAttachments = attach_desc; - rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; +TEST_F(VkLayerTest, RenderPassCreateAttachmentReadOnlyButCleared) { + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } - VkRenderPass renderpass; - vkCreateRenderPass(m_device->device(), &rpci, NULL, &renderpass); - VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); - pipeline.AddShader(&vs); + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr; + bool rp2Supported = false; + bool maintenance2Supported = false; - VkPipelineColorBlendAttachmentState att_state1 = {}, att_state2 = {}; - att_state1.dstAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR; - att_state1.blendEnable = VK_TRUE; - att_state2.dstAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR; - att_state2.blendEnable = VK_FALSE; - pipeline.AddColorAttachment(0, att_state1); - pipeline.AddColorAttachment(1, att_state2); - pipeline.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderpass); - m_errorMonitor->VerifyFound(); - vkDestroyRenderPass(m_device->device(), renderpass, NULL); -} + // Check for VK_KHR_maintenance2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + maintenance2Supported = true; + } + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); -// Is the Pipeline compatible with the expectations of the Renderpass/subpasses? -TEST_F(VkLayerTest, PipelineRenderpassCompatibility) { - TEST_DESCRIPTION( - "Create a graphics pipeline that is incompatible with the requirements of its contained Renderpass/subpasses."); - ASSERT_NO_FATAL_FAILURE(Init()); + if (m_device->props.apiVersion < VK_API_VERSION_1_1) { + maintenance2Supported = true; + } - VkDescriptorSetObj ds_obj(m_device); - ds_obj.AppendDummy(); - ds_obj.CreateVKDescriptorSet(m_commandBuffer); + if (rp2Supported) { + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + } - VkShaderObj vs_obj(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); + VkAttachmentDescription description = {0, + VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_CLEAR, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_CLEAR, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_GENERAL}; - VkPipelineColorBlendAttachmentState att_state1 = {}; - att_state1.dstAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR; - att_state1.blendEnable = VK_TRUE; + VkAttachmentReference depth_stencil_ref = {0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL}; - VkRenderpassObj rp_obj(m_device); + VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, &depth_stencil_ref, 0, + nullptr}; - { - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, - "VUID-VkGraphicsPipelineCreateInfo-rasterizerDiscardEnable-00753"); - VkPipelineObj pipeline(m_device); - pipeline.AddShader(&vs_obj); - pipeline.AddColorAttachment(0, att_state1); + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &description, 1, &subpass, 0, nullptr}; - VkGraphicsPipelineCreateInfo info = {}; - pipeline.InitGraphicsPipelineCreateInfo(&info); - info.pColorBlendState = nullptr; + // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL but depth cleared + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkRenderPassCreateInfo-pAttachments-00836", "VUID-VkRenderPassCreateInfo2KHR-pAttachments-03053"); - pipeline.CreateVKPipeline(ds_obj.GetPipelineLayout(), rp_obj.handle(), &info); - m_errorMonitor->VerifyFound(); + if (maintenance2Supported) { + // VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL but depth cleared + depth_stencil_ref.layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkRenderPassCreateInfo-pAttachments-01566", nullptr); + + // VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL but depth cleared + depth_stencil_ref.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkRenderPassCreateInfo-pAttachments-01567", nullptr); } } -TEST_F(VkLayerTest, CreateRenderPassAttachments) { - TEST_DESCRIPTION( - "Ensure that CreateRenderPass produces the expected validation errors when a subpass's attachments violate the valid usage " - "conditions."); +TEST_F(VkLayerTest, RenderPassCreateAttachmentUsedTwiceColor) { + TEST_DESCRIPTION("Attachment is used simultaneously as two color attachments. This is usually unintended."); - ASSERT_NO_FATAL_FAILURE(Init()); + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } - std::vector attachments = { - // input attachments - {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL}, - // color attachments - {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, - {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, - // depth attachment - {0, VK_FORMAT_D24_UNORM_S8_UINT, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}, - // resolve attachment + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr; + bool rp2Supported = false; + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); + + if (rp2Supported) { + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + } + + VkAttachmentDescription attach[] = { {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, - // preserve attachments - {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, }; - - std::vector input = { - {0, VK_IMAGE_LAYOUT_GENERAL}, + VkAttachmentReference refs[] = { + {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, + {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, + }; + VkSubpassDescription subpasses[] = { + {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 2, refs, nullptr, nullptr, 0, nullptr}, + }; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attach, 1, subpasses, 0, nullptr}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "subpass 0 already uses attachment 0 as a color attachment", + "subpass 0 already uses attachment 0 as a color attachment"); +} + +TEST_F(VkLayerTest, RenderPassCreateAttachmentDescriptionInvalidFinalLayout) { + TEST_DESCRIPTION("VkAttachmentDescription's finalLayout must not be UNDEFINED or PREINITIALIZED"); + + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr; + bool rp2Supported = false; + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); + + if (rp2Supported) { + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + } + + VkAttachmentDescription attach_desc = {}; + attach_desc.format = VK_FORMAT_R8G8B8A8_UNORM; + attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; + attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attach_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attach_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attach_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attach_desc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attach_desc.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; + VkAttachmentReference attach_ref = {}; + attach_ref.attachment = 0; + attach_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &attach_ref; + VkRenderPassCreateInfo rpci = {}; + rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + rpci.attachmentCount = 1; + rpci.pAttachments = &attach_desc; + rpci.subpassCount = 1; + rpci.pSubpasses = &subpass; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkAttachmentDescription-finalLayout-00843", "VUID-VkAttachmentDescription2KHR-finalLayout-03061"); + + attach_desc.finalLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkAttachmentDescription-finalLayout-00843", "VUID-VkAttachmentDescription2KHR-finalLayout-03061"); +} + +TEST_F(VkLayerTest, RenderPassCreateAttachmentsMisc) { + TEST_DESCRIPTION( + "Ensure that CreateRenderPass produces the expected validation errors when a subpass's attachments violate the valid usage " + "conditions."); + + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr; + bool rp2Supported = false; + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); + + if (rp2Supported) { + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + } + + std::vector attachments = { + // input attachments + {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL}, + // color attachments + {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, + {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, + // depth attachment + {0, VK_FORMAT_D24_UNORM_S8_UINT, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}, + // resolve attachment + {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, + // preserve attachments + {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, + }; + + std::vector input = { + {0, VK_IMAGE_LAYOUT_GENERAL}, }; std::vector color = { {1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, @@ -5573,102 +5599,120 @@ TEST_F(VkLayerTest, CreateRenderPassAttachments) { 0, nullptr}; - VkRenderPass rp; - VkResult err; // Test too many color attachments { std::vector too_many_colors(m_device->props.limits.maxColorAttachments + 1, color[0]); subpass.colorAttachmentCount = (uint32_t)too_many_colors.size(); subpass.pColorAttachments = too_many_colors.data(); subpass.pResolveAttachments = NULL; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-colorAttachmentCount-00845"); - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-colorAttachmentCount-00845", + "VUID-VkSubpassDescription2KHR-colorAttachmentCount-03063"); + subpass.colorAttachmentCount = (uint32_t)color.size(); subpass.pColorAttachments = color.data(); subpass.pResolveAttachments = resolve.data(); } + // Test sample count mismatch between color buffers attachments[subpass.pColorAttachments[1].attachment].samples = VK_SAMPLE_COUNT_8_BIT; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pColorAttachments-01417"); - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + depth.attachment = VK_ATTACHMENT_UNUSED; // Avoids triggering 01418 + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-pColorAttachments-01417", + "VUID-VkSubpassDescription2KHR-pColorAttachments-03069"); + + depth.attachment = 3; attachments[subpass.pColorAttachments[1].attachment].samples = attachments[subpass.pColorAttachments[0].attachment].samples; + // Test sample count mismatch between color buffers and depth buffer attachments[subpass.pDepthStencilAttachment->attachment].samples = VK_SAMPLE_COUNT_8_BIT; - subpass.colorAttachmentCount = 1; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pDepthStencilAttachment-01418"); - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + subpass.colorAttachmentCount = 1; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-pDepthStencilAttachment-01418", + "VUID-VkSubpassDescription2KHR-pDepthStencilAttachment-03071"); + attachments[subpass.pDepthStencilAttachment->attachment].samples = attachments[subpass.pColorAttachments[0].attachment].samples; - subpass.colorAttachmentCount = (uint32_t)color.size(); + subpass.colorAttachmentCount = (uint32_t)color.size(); + // Test resolve attachment with UNUSED color attachment color[0].attachment = VK_ATTACHMENT_UNUSED; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pResolveAttachments-00847"); - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-pResolveAttachments-00847", + "VUID-VkSubpassDescription2KHR-pResolveAttachments-03065"); + color[0].attachment = 1; + // Test resolve from a single-sampled color attachment attachments[subpass.pColorAttachments[0].attachment].samples = VK_SAMPLE_COUNT_1_BIT; - subpass.colorAttachmentCount = 1; // avoid mismatch (00337), and avoid double report - subpass.pDepthStencilAttachment = nullptr; // avoid mismatch (01418) - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pResolveAttachments-00848"); - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + subpass.colorAttachmentCount = 1; // avoid mismatch (00337), and avoid double report + subpass.pDepthStencilAttachment = nullptr; // avoid mismatch (01418) + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-pResolveAttachments-00848", + "VUID-VkSubpassDescription2KHR-pResolveAttachments-03066"); + attachments[subpass.pColorAttachments[0].attachment].samples = VK_SAMPLE_COUNT_4_BIT; - subpass.colorAttachmentCount = (uint32_t)color.size(); // avoid mismatch (00337), and avoid double report - subpass.pDepthStencilAttachment = &depth; + subpass.colorAttachmentCount = (uint32_t)color.size(); + subpass.pDepthStencilAttachment = &depth; + // Test resolve to a multi-sampled resolve attachment attachments[subpass.pResolveAttachments[0].attachment].samples = VK_SAMPLE_COUNT_4_BIT; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pResolveAttachments-00849"); - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-pResolveAttachments-00849", + "VUID-VkSubpassDescription2KHR-pResolveAttachments-03067"); + attachments[subpass.pResolveAttachments[0].attachment].samples = VK_SAMPLE_COUNT_1_BIT; + // Test with color/resolve format mismatch attachments[subpass.pColorAttachments[0].attachment].format = VK_FORMAT_R8G8B8A8_SRGB; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pResolveAttachments-00850"); - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-pResolveAttachments-00850", + "VUID-VkSubpassDescription2KHR-pResolveAttachments-03068"); + attachments[subpass.pColorAttachments[0].attachment].format = attachments[subpass.pResolveAttachments[0].attachment].format; + // Test for UNUSED preserve attachments preserve[0] = VK_ATTACHMENT_UNUSED; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-attachment-00853"); - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-attachment-00853", "VUID-VkSubpassDescription2KHR-attachment-03073"); + preserve[0] = 5; // Test for preserve attachments used elsewhere in the subpass color[0].attachment = preserve[0]; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pPreserveAttachments-00854"); - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-pPreserveAttachments-00854", + "VUID-VkSubpassDescription2KHR-pPreserveAttachments-03074"); + color[0].attachment = 1; - // test for layout mismatch between input attachment and color attachment + + // Test for layout mismatch between input attachment and color attachment input[0].attachment = color[0].attachment; input[0].layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-layout-00855"); - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-layout-00855", "VUID-VkSubpassDescription2KHR-layout-03075"); + input[0].attachment = 0; input[0].layout = VK_IMAGE_LAYOUT_GENERAL; - // test for layout mismatch between input attachment and depth attachment + + // Test for layout mismatch between input attachment and depth attachment input[0].attachment = depth.attachment; input[0].layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-layout-00855"); - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-layout-00855", "VUID-VkSubpassDescription2KHR-layout-03075"); + input[0].attachment = 0; input[0].layout = VK_IMAGE_LAYOUT_GENERAL; + // Test for attachment used first as input with loadOp=CLEAR { std::vector subpasses = {subpass, subpass, subpass}; @@ -5684,94 +5728,2091 @@ TEST_F(VkLayerTest, CreateRenderPassAttachments) { subpasses.data(), 0, nullptr}; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-loadOp-00846"); - err = vkCreateRenderPass(m_device->device(), &rpci_multipass, nullptr, &rp); - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci_multipass, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-loadOp-00846", "VUID-VkSubpassDescription2KHR-loadOp-03064"); + attachments[input[0].attachment].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; } } -TEST_F(VkLayerTest, FramebufferCreateErrors) { - TEST_DESCRIPTION( - "Hit errors when attempting to create a framebuffer :\n" - " 1. Mismatch between framebuffer & renderPass attachmentCount\n" - " 2. Use a color image as depthStencil attachment\n" - " 3. Mismatch framebuffer & renderPass attachment formats\n" - " 4. Mismatch framebuffer & renderPass attachment #samples\n" - " 5. Framebuffer attachment w/ non-1 mip-levels\n" - " 6. Framebuffer attachment where dimensions don't match\n" - " 7. Framebuffer attachment where dimensions don't match\n" - " 8. Framebuffer attachment w/o identity swizzle\n" - " 9. framebuffer dimensions exceed physical device limits\n"); +TEST_F(VkLayerTest, RenderPassCreateAttachmentReferenceInvalidLayout) { + TEST_DESCRIPTION("Attachment reference uses PREINITIALIZED or UNDEFINED layouts"); - ASSERT_NO_FATAL_FAILURE(Init()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkFramebufferCreateInfo-attachmentCount-00876"); + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr; + bool rp2Supported = false; - // Create a renderPass with a single color attachment - VkAttachmentReference attach = {}; - attach.layout = VK_IMAGE_LAYOUT_GENERAL; - VkSubpassDescription subpass = {}; - subpass.pColorAttachments = &attach; - VkRenderPassCreateInfo rpci = {}; - rpci.subpassCount = 1; - rpci.pSubpasses = &subpass; - rpci.attachmentCount = 1; - VkAttachmentDescription attach_desc = {}; - attach_desc.format = VK_FORMAT_B8G8R8A8_UNORM; - attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; - attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL; - rpci.pAttachments = &attach_desc; - rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - VkRenderPass rp; - VkResult err = vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); - ASSERT_VK_SUCCESS(err); + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); - VkImageView ivs[2]; - ivs[0] = m_renderTargets[0]->targetView(VK_FORMAT_B8G8R8A8_UNORM); - ivs[1] = m_renderTargets[0]->targetView(VK_FORMAT_B8G8R8A8_UNORM); - VkFramebufferCreateInfo fb_info = {}; - fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fb_info.pNext = NULL; - fb_info.renderPass = rp; - // Set mis-matching attachmentCount - fb_info.attachmentCount = 2; - fb_info.pAttachments = ivs; - fb_info.width = 100; - fb_info.height = 100; - fb_info.layers = 1; + if (rp2Supported) { + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + } - VkFramebuffer fb; - err = vkCreateFramebuffer(device(), &fb_info, NULL, &fb); + VkAttachmentDescription attach[] = { + {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, + }; + VkAttachmentReference refs[] = { + {0, VK_IMAGE_LAYOUT_UNDEFINED}, + }; + VkSubpassDescription subpasses[] = { + {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, refs, nullptr, nullptr, 0, nullptr}, + }; - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) { - vkDestroyFramebuffer(m_device->device(), fb, NULL); - } - vkDestroyRenderPass(m_device->device(), rp, NULL); + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attach, 1, subpasses, 0, nullptr}; - // Create a renderPass with a depth-stencil attachment created with - // IMAGE_USAGE_COLOR_ATTACHMENT - // Add our color attachment to pDepthStencilAttachment - subpass.pDepthStencilAttachment = &attach; - subpass.pColorAttachments = NULL; - VkRenderPass rp_ds; - err = vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_ds); - ASSERT_VK_SUCCESS(err); - // Set correct attachment count, but attachment has COLOR usage bit set - fb_info.attachmentCount = 1; - fb_info.renderPass = rp_ds; + // Use UNDEFINED layout + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkAttachmentReference-layout-00857", "VUID-VkAttachmentReference2KHR-layout-03077"); - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkFramebufferCreateInfo-pAttachments-00878"); - err = vkCreateFramebuffer(device(), &fb_info, NULL, &fb); + // Use PREINITIALIZED layout + refs[0].layout = VK_IMAGE_LAYOUT_PREINITIALIZED; + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkAttachmentReference-layout-00857", "VUID-VkAttachmentReference2KHR-layout-03077"); +} - m_errorMonitor->VerifyFound(); - if (err == VK_SUCCESS) { - vkDestroyFramebuffer(m_device->device(), fb, NULL); +TEST_F(VkLayerTest, RenderPassCreateOverlappingCorrelationMasks) { + TEST_DESCRIPTION("Create a subpass with overlapping correlation masks"); + + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); } - vkDestroyRenderPass(m_device->device(), rp_ds, NULL); + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr; + bool rp2Supported = false; + + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MULTIVIEW_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + } else { + printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_KHR_MULTIVIEW_EXTENSION_NAME); + return; + } + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); + + if (rp2Supported) { + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + } + + VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr}; + uint32_t viewMasks[] = {0x3u}; + uint32_t correlationMasks[] = {0x1u, 0x3u}; + VkRenderPassMultiviewCreateInfo rpmvci = { + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, nullptr, 1, viewMasks, 0, nullptr, 2, correlationMasks}; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, &rpmvci, 0, 0, nullptr, 1, &subpass, 0, nullptr}; + + // Correlation masks must not overlap + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkRenderPassMultiviewCreateInfo-pCorrelationMasks-00841", + "VUID-VkRenderPassCreateInfo2KHR-pCorrelatedViewMasks-03056"); + + // Check for more specific "don't set any correlation masks when multiview is not enabled" + if (rp2Supported) { + viewMasks[0] = 0; + correlationMasks[0] = 0; + correlationMasks[1] = 0; + safe_VkRenderPassCreateInfo2KHR safe_rpci2; + ConvertVkRenderPassCreateInfoToV2KHR(&rpci, &safe_rpci2); + + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkRenderPassCreateInfo2KHR-viewMask-03057"); + VkRenderPass rp; + VkResult err = vkCreateRenderPass2KHR(m_device->device(), safe_rpci2.ptr(), nullptr, &rp); + if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + m_errorMonitor->VerifyFound(); + } +} + +TEST_F(VkLayerTest, RenderPassCreateInvalidViewMasks) { + TEST_DESCRIPTION("Create a subpass with the wrong number of view masks, or inconsistent setting of view masks"); + + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr; + bool rp2Supported = false; + + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MULTIVIEW_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + } else { + printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_KHR_MULTIVIEW_EXTENSION_NAME); + return; + } + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); + + if (rp2Supported) { + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + } + + VkSubpassDescription subpasses[] = { + {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr}, + {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr}, + }; + uint32_t viewMasks[] = {0x3u, 0u}; + VkRenderPassMultiviewCreateInfo rpmvci = { + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, nullptr, 1, viewMasks, 0, nullptr, 0, nullptr}; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, &rpmvci, 0, 0, nullptr, 2, subpasses, 0, nullptr}; + + // Not enough view masks + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkRenderPassCreateInfo-pNext-01928", "VUID-VkRenderPassCreateInfo2KHR-viewMask-03058"); +} + +TEST_F(VkLayerTest, RenderPassCreateInvalidInputAttachmentReferences) { + TEST_DESCRIPTION("Create a subpass with the meta data aspect mask set for an input attachment"); + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + } else { + printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_KHR_MAINTENANCE2_EXTENSION_NAME); + return; + } + + ASSERT_NO_FATAL_FAILURE(InitState()); + + VkAttachmentDescription attach = {0, + VK_FORMAT_R8G8B8A8_UNORM, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + + VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &ref, 0, nullptr, nullptr, nullptr, 0, nullptr}; + VkInputAttachmentAspectReference iaar = {0, 0, VK_IMAGE_ASPECT_METADATA_BIT}; + VkRenderPassInputAttachmentAspectCreateInfo rpiaaci = {VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, + nullptr, 1, &iaar}; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, &rpiaaci, 0, 1, &attach, 1, &subpass, 0, nullptr}; + + // Invalid meta data aspect + m_errorMonitor->SetDesiredFailureMsg( + VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkRenderPassCreateInfo-pNext-01963"); // Cannot/should not avoid getting this one too + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, nullptr, + "VUID-VkInputAttachmentAspectReference-aspectMask-01964", nullptr); + + // Aspect not present + iaar.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, nullptr, "VUID-VkRenderPassCreateInfo-pNext-01963", nullptr); + + // Invalid subpass index + iaar.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + iaar.subpass = 1; + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, nullptr, "VUID-VkRenderPassCreateInfo-pNext-01926", nullptr); + iaar.subpass = 0; + + // Invalid input attachment index + iaar.inputAttachmentIndex = 1; + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, nullptr, "VUID-VkRenderPassCreateInfo-pNext-01927", nullptr); +} + +TEST_F(VkLayerTest, RenderPassCreateSubpassNonGraphicsPipeline) { + TEST_DESCRIPTION("Create a subpass with the compute pipeline bind point"); + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr; + bool rp2Supported = false; + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); + + if (rp2Supported) { + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + } + + VkSubpassDescription subpasses[] = { + {0, VK_PIPELINE_BIND_POINT_COMPUTE, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr}, + }; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 1, subpasses, 0, nullptr}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-pipelineBindPoint-00844", + "VUID-VkSubpassDescription2KHR-pipelineBindPoint-03062"); +} + +TEST_F(VkLayerTest, RenderPassCreateSubpassMissingAttributesBitMultiviewNVX) { + TEST_DESCRIPTION("Create a subpass with the VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX flag missing"); + + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } else { + printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME); + return; + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr; + bool rp2Supported = false; + + if (DeviceExtensionSupported(gpu(), nullptr, VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + } else { + printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME); + return; + } + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); + + if (rp2Supported) { + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + } + + VkSubpassDescription subpasses[] = { + {VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, + nullptr, 0, nullptr}, + }; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 1, subpasses, 0, nullptr}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, "VUID-VkSubpassDescription-flags-00856", + "VUID-VkSubpassDescription2KHR-flags-03076"); +} + +TEST_F(VkLayerTest, RenderPassCreate2SubpassInvalidInputAttachmentParameters) { + TEST_DESCRIPTION("Create a subpass with parameters in the input attachment ref which are invalid"); + + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } else { + printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + return; + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + } else { + printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + return; + } + + ASSERT_NO_FATAL_FAILURE(InitState()); + + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = + (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + + VkResult err; + + VkAttachmentReference2KHR reference = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR, nullptr, VK_ATTACHMENT_UNUSED, + VK_IMAGE_LAYOUT_UNDEFINED, 0}; + VkSubpassDescription2KHR subpass = {VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, + nullptr, + 0, + VK_PIPELINE_BIND_POINT_GRAPHICS, + 0, + 1, + &reference, + 0, + nullptr, + nullptr, + nullptr, + 0, + nullptr}; + + VkRenderPassCreateInfo2KHR rpci2 = { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR, nullptr, 0, 0, nullptr, 1, &subpass, 0, nullptr, 0, nullptr}; + VkRenderPass rp; + + // Test for aspect mask of 0 + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription2KHR-aspectMask-03176"); + err = vkCreateRenderPass2KHR(m_device->device(), &rpci2, nullptr, &rp); + if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + m_errorMonitor->VerifyFound(); + + // Test for invalid aspect mask bits + reference.aspectMask |= VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM; + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription2KHR-aspectMask-03175"); + err = vkCreateRenderPass2KHR(m_device->device(), &rpci2, nullptr, &rp); + if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + m_errorMonitor->VerifyFound(); +} + +TEST_F(VkLayerTest, RenderPassCreateInvalidSubpassDependencies) { + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr; + bool rp2Supported = false; + bool multiviewSupported = false; + + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MULTIVIEW_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + multiviewSupported = true; + } + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + rp2Supported = true; + } + + // Add a device features struct enabling NO features + VkPhysicalDeviceFeatures features = {0}; + ASSERT_NO_FATAL_FAILURE(InitState(&features)); + + if (m_device->props.apiVersion >= VK_API_VERSION_1_1) { + multiviewSupported = true; + } + + if (rp2Supported) { + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + } + + // Create two dummy subpasses + VkSubpassDescription subpasses[] = { + {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr}, + {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr}, + }; + + VkSubpassDependency dependency; + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 2, subpasses, 1, &dependency}; + // dependency = { 0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0 }; + + // Source subpass is not EXTERNAL, so source stage mask must not include HOST + dependency = {0, 1, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-srcSubpass-00858", "VUID-VkSubpassDependency2KHR-srcSubpass-03078"); + + // Destination subpass is not EXTERNAL, so destination stage mask must not include HOST + dependency = {0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-dstSubpass-00859", "VUID-VkSubpassDependency2KHR-dstSubpass-03079"); + + // Geometry shaders not enabled source + dependency = {0, 1, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-srcStageMask-00860", "VUID-VkSubpassDependency2KHR-srcStageMask-03080"); + + // Geometry shaders not enabled destination + dependency = {0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-dstStageMask-00861", "VUID-VkSubpassDependency2KHR-dstStageMask-03081"); + + // Tessellation not enabled source + dependency = {0, 1, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-srcStageMask-00862", "VUID-VkSubpassDependency2KHR-srcStageMask-03082"); + + // Tessellation not enabled destination + dependency = {0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-dstStageMask-00863", "VUID-VkSubpassDependency2KHR-dstStageMask-03083"); + + // Potential cyclical dependency + dependency = {1, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-srcSubpass-00864", "VUID-VkSubpassDependency2KHR-srcSubpass-03084"); + + // EXTERNAL to EXTERNAL dependency + dependency = { + VK_SUBPASS_EXTERNAL, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-srcSubpass-00865", "VUID-VkSubpassDependency2KHR-srcSubpass-03085"); + + // Source compute stage not part of subpass 0's GRAPHICS pipeline + dependency = {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkRenderPassCreateInfo-pDependencies-00837", "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03054"); + + // Destination compute stage not part of subpass 0's GRAPHICS pipeline + dependency = {VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkRenderPassCreateInfo-pDependencies-00838", "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03055"); + + // Non graphics stage in self dependency + dependency = {0, 0, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-srcSubpass-01989", "VUID-VkSubpassDependency2KHR-srcSubpass-02244"); + + // Logically later source stages in self dependency + dependency = {0, 0, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-srcSubpass-00867", "VUID-VkSubpassDependency2KHR-srcSubpass-03087"); + + // Source access mask mismatch with source stage mask + dependency = {0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_ACCESS_UNIFORM_READ_BIT, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-srcAccessMask-00868", "VUID-VkSubpassDependency2KHR-srcAccessMask-03088"); + + // Destination access mask mismatch with destination stage mask + dependency = { + 0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-dstAccessMask-00869", "VUID-VkSubpassDependency2KHR-dstAccessMask-03089"); + + if (multiviewSupported) { + // VIEW_LOCAL_BIT but multiview is not enabled + dependency = {0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, 0, VK_DEPENDENCY_VIEW_LOCAL_BIT}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-dependencyFlags-00871", "VUID-VkRenderPassCreateInfo2KHR-viewMask-03059"); + + // Enable multiview + uint32_t pViewMasks[2] = {0x3u, 0x3u}; + int32_t pViewOffsets[2] = {0, 0}; + VkRenderPassMultiviewCreateInfo rpmvci = { + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, nullptr, 2, pViewMasks, 0, nullptr, 0, nullptr}; + rpci.pNext = &rpmvci; + + // Excessive view offsets + dependency = {0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, 0, VK_DEPENDENCY_VIEW_LOCAL_BIT}; + rpmvci.pViewOffsets = pViewOffsets; + rpmvci.dependencyCount = 2; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, nullptr, "VUID-VkRenderPassCreateInfo-pNext-01929", + nullptr); + + rpmvci.dependencyCount = 0; + + // View offset with subpass self dependency + dependency = {0, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, 0, VK_DEPENDENCY_VIEW_LOCAL_BIT}; + rpmvci.pViewOffsets = pViewOffsets; + pViewOffsets[0] = 1; + rpmvci.dependencyCount = 1; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, nullptr, "VUID-VkRenderPassCreateInfo-pNext-01930", + nullptr); + + rpmvci.dependencyCount = 0; + + // View offset with no view local bit + if (rp2Supported) { + dependency = {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0}; + rpmvci.pViewOffsets = pViewOffsets; + pViewOffsets[0] = 1; + rpmvci.dependencyCount = 1; + + safe_VkRenderPassCreateInfo2KHR safe_rpci2; + ConvertVkRenderPassCreateInfoToV2KHR(&rpci, &safe_rpci2); + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, nullptr, + "VUID-VkSubpassDependency2KHR-dependencyFlags-03092"); + + rpmvci.dependencyCount = 0; + } + + // EXTERNAL subpass with VIEW_LOCAL_BIT - source subpass + dependency = {VK_SUBPASS_EXTERNAL, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, + VK_DEPENDENCY_VIEW_LOCAL_BIT}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-dependencyFlags-00870", + "VUID-VkSubpassDependency2KHR-dependencyFlags-03090"); + + // EXTERNAL subpass with VIEW_LOCAL_BIT - destination subpass + dependency = {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, + 0, VK_DEPENDENCY_VIEW_LOCAL_BIT}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-dependencyFlags-00870", + "VUID-VkSubpassDependency2KHR-dependencyFlags-03091"); + + // Multiple views but no view local bit in self-dependency + dependency = {0, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0}; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDependency-srcSubpass-00872", "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03060"); + } +} + +TEST_F(VkLayerTest, RenderPassCreateInvalidMixedAttachmentSamplesAMD) { + TEST_DESCRIPTION("Verify error messages for supported and unsupported sample counts in render pass attachments."); + + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr; + bool rp2Supported = false; + + if (DeviceExtensionSupported(gpu(), nullptr, VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME); + } else { + printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME); + return; + } + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); + + if (rp2Supported) { + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR"); + } + + std::vector attachments; + + { + VkAttachmentDescription att = {}; + att.format = VK_FORMAT_R8G8B8A8_UNORM; + att.samples = VK_SAMPLE_COUNT_1_BIT; + att.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + att.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + att.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + att.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + att.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + att.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + attachments.push_back(att); + + att.format = VK_FORMAT_D16_UNORM; + att.samples = VK_SAMPLE_COUNT_4_BIT; + att.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + att.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + att.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + att.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + att.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + att.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + attachments.push_back(att); + } + + VkAttachmentReference color_ref = {}; + color_ref.attachment = 0; + color_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference depth_ref = {}; + depth_ref.attachment = 1; + depth_ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_ref; + subpass.pDepthStencilAttachment = &depth_ref; + + VkRenderPassCreateInfo rpci = {}; + rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + rpci.attachmentCount = attachments.size(); + rpci.pAttachments = attachments.data(); + rpci.subpassCount = 1; + rpci.pSubpasses = &subpass; + + m_errorMonitor->ExpectSuccess(); + + VkRenderPass rp; + VkResult err; + + err = vkCreateRenderPass(device(), &rpci, NULL, &rp); + m_errorMonitor->VerifyNotFound(); + if (err == VK_SUCCESS) vkDestroyRenderPass(m_device->device(), rp, nullptr); + + // Expect an error message for invalid sample counts + attachments[0].samples = VK_SAMPLE_COUNT_4_BIT; + attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; + + TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, + "VUID-VkSubpassDescription-pColorAttachments-01506", + "VUID-VkSubpassDescription2KHR-pColorAttachments-03070"); +} + +static void TestRenderPassBegin(ErrorMonitor *error_monitor, const VkCommandBuffer command_buffer, + const VkRenderPassBeginInfo *begin_info, PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR, + const char *rp1_vuid, const char *rp2_vuid) { + // "... must be less than the total number of attachments ..." + + VkCommandBufferBeginInfo cmd_begin_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, nullptr}; + + if (rp1_vuid) { + vkBeginCommandBuffer(command_buffer, &cmd_begin_info); + error_monitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, rp1_vuid); + vkCmdBeginRenderPass(command_buffer, begin_info, VK_SUBPASS_CONTENTS_INLINE); + error_monitor->VerifyFound(); + vkResetCommandBuffer(command_buffer, 0); + } + if (vkCmdBeginRenderPass2KHR && rp2_vuid) { + VkSubpassBeginInfoKHR subpass_begin_info = {VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR, nullptr, VK_SUBPASS_CONTENTS_INLINE}; + vkBeginCommandBuffer(command_buffer, &cmd_begin_info); + error_monitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, rp2_vuid); + vkCmdBeginRenderPass2KHR(command_buffer, begin_info, &subpass_begin_info); + error_monitor->VerifyFound(); + vkResetCommandBuffer(command_buffer, 0); + } +} + +TEST_F(VkLayerTest, RenderPassBeginInvalidRenderArea) { + TEST_DESCRIPTION("Generate INVALID_RENDER_AREA error by beginning renderpass with extent outside of framebuffer"); + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR = nullptr; + bool rp2Supported = false; + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)); + + if (rp2Supported) { + vkCmdBeginRenderPass2KHR = + (PFN_vkCmdBeginRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCmdBeginRenderPass2KHR"); + } + + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + // Framebuffer for render target is 256x256, exceed that for INVALID_RENDER_AREA + m_renderPassBeginInfo.renderArea.extent.width = 257; + m_renderPassBeginInfo.renderArea.extent.height = 257; + + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &m_renderPassBeginInfo, vkCmdBeginRenderPass2KHR, + "Cannot execute a render pass with renderArea not within the bound of the framebuffer.", + "Cannot execute a render pass with renderArea not within the bound of the framebuffer."); +} + +TEST_F(VkLayerTest, RenderPassBeginWithinRenderPass) { + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR = nullptr; + bool rp2Supported = false; + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); + + if (rp2Supported) { + vkCmdBeginRenderPass2KHR = + (PFN_vkCmdBeginRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCmdBeginRenderPass2KHR"); + } + + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + // Bind a BeginRenderPass within an active RenderPass + m_commandBuffer->begin(); + m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); + + // Just use a dummy Renderpass + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBeginRenderPass-renderpass"); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + m_errorMonitor->VerifyFound(); + + if (rp2Supported) { + VkSubpassBeginInfoKHR subpassBeginInfo = {VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR, nullptr, VK_SUBPASS_CONTENTS_INLINE}; + + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBeginRenderPass2KHR-renderpass"); + vkCmdBeginRenderPass2KHR(m_commandBuffer->handle(), &m_renderPassBeginInfo, &subpassBeginInfo); + m_errorMonitor->VerifyFound(); + } +} + +TEST_F(VkLayerTest, RenderPassBeginIncompatibleFramebufferRenderPass) { + TEST_DESCRIPTION("Test that renderpass begin is compatible with the framebuffer renderpass "); + + ASSERT_NO_FATAL_FAILURE(Init(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)); + + // Create a depth stencil image view + VkImageObj image(m_device); + + image.Init(128, 128, 1, VK_FORMAT_D16_UNORM, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL); + ASSERT_TRUE(image.initialized()); + + VkImageView dsv; + VkImageViewCreateInfo dsvci = {}; + dsvci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + dsvci.pNext = nullptr; + dsvci.image = image.handle(); + dsvci.viewType = VK_IMAGE_VIEW_TYPE_2D; + dsvci.format = VK_FORMAT_D16_UNORM; + dsvci.subresourceRange.layerCount = 1; + dsvci.subresourceRange.baseMipLevel = 0; + dsvci.subresourceRange.levelCount = 1; + dsvci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + vkCreateImageView(m_device->device(), &dsvci, NULL, &dsv); + + // Create a renderPass with a single attachment that uses loadOp CLEAR + VkAttachmentDescription description = {0, + VK_FORMAT_D16_UNORM, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_CLEAR, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_GENERAL}; + + VkAttachmentReference depth_stencil_ref = {0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, &depth_stencil_ref, 0, + nullptr}; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &description, 1, &subpass, 0, nullptr}; + VkRenderPass rp1, rp2; + + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp1); + subpass.pDepthStencilAttachment = nullptr; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp2); + + // Create a framebuffer + + VkFramebufferCreateInfo fbci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp1, 1, &dsv, 128, 128, 1}; + VkFramebuffer fb; + + vkCreateFramebuffer(m_device->handle(), &fbci, nullptr, &fb); + + VkRenderPassBeginInfo rp_begin = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp2, fb, {{0, 0}, {128, 128}}, 0, nullptr}; + + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, nullptr, + "VUID-VkRenderPassBeginInfo-renderPass-00904", nullptr); + + vkDestroyRenderPass(m_device->device(), rp1, nullptr); + vkDestroyRenderPass(m_device->device(), rp2, nullptr); + vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyImageView(m_device->device(), dsv, nullptr); +} + +TEST_F(VkLayerTest, RenderPassBeginLayoutsFramebufferImageUsageMismatches) { + TEST_DESCRIPTION( + "Test that renderpass initial/final layouts match up with the usage bits set for each attachment of the framebuffer"); + + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR = nullptr; + bool rp2Supported = false; + bool maintenance2Supported = false; + + // Check for VK_KHR_maintenance2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + maintenance2Supported = true; + } + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)); + + if (m_device->props.apiVersion >= VK_API_VERSION_1_1) { + maintenance2Supported = true; + } + + if (rp2Supported) { + vkCmdBeginRenderPass2KHR = + (PFN_vkCmdBeginRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCmdBeginRenderPass2KHR"); + } + + // Create an input attachment view + VkImageObj iai(m_device); + + iai.InitNoLayout(128, 128, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL); + ASSERT_TRUE(iai.initialized()); + + VkImageView iav; + VkImageViewCreateInfo iavci = {}; + iavci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + iavci.pNext = nullptr; + iavci.image = iai.handle(); + iavci.viewType = VK_IMAGE_VIEW_TYPE_2D; + iavci.format = VK_FORMAT_R8G8B8A8_UNORM; + iavci.subresourceRange.layerCount = 1; + iavci.subresourceRange.baseMipLevel = 0; + iavci.subresourceRange.levelCount = 1; + iavci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + vkCreateImageView(m_device->device(), &iavci, NULL, &iav); + + // Create a color attachment view + VkImageObj cai(m_device); + + cai.InitNoLayout(128, 128, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL); + ASSERT_TRUE(cai.initialized()); + + VkImageView cav; + VkImageViewCreateInfo cavci = {}; + cavci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + cavci.pNext = nullptr; + cavci.image = cai.handle(); + cavci.viewType = VK_IMAGE_VIEW_TYPE_2D; + cavci.format = VK_FORMAT_R8G8B8A8_UNORM; + cavci.subresourceRange.layerCount = 1; + cavci.subresourceRange.baseMipLevel = 0; + cavci.subresourceRange.levelCount = 1; + cavci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + vkCreateImageView(m_device->device(), &cavci, NULL, &cav); + + // Create a renderPass with those attachments + VkAttachmentDescription descriptions[] = { + {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL}, + {1, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL}}; + + VkAttachmentReference input_ref = {0, VK_IMAGE_LAYOUT_GENERAL}; + VkAttachmentReference color_ref = {1, VK_IMAGE_LAYOUT_GENERAL}; + + VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &input_ref, 1, &color_ref, nullptr, nullptr, 0, nullptr}; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 2, descriptions, 1, &subpass, 0, nullptr}; + + VkRenderPass rp; + + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); + + // Create a framebuffer + + VkImageView views[] = {iav, cav}; + + VkFramebufferCreateInfo fbci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 2, views, 128, 128, 1}; + VkFramebuffer fb; + + vkCreateFramebuffer(m_device->handle(), &fbci, nullptr, &fb); + + VkRenderPassBeginInfo rp_begin = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {128, 128}}, 0, nullptr}; + + VkRenderPass rp_invalid; + + // Initial layout is VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL but attachment doesn't support IMAGE_USAGE_COLOR_ATTACHMENT_BIT + descriptions[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid); + rp_begin.renderPass = rp_invalid; + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR, + "VUID-vkCmdBeginRenderPass-initialLayout-00895", "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03094"); + + vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr); + + // Initial layout is VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL but attachment doesn't support VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT + // / VK_IMAGE_USAGE_SAMPLED_BIT + descriptions[0].initialLayout = VK_IMAGE_LAYOUT_GENERAL; + descriptions[1].initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid); + rp_begin.renderPass = rp_invalid; + + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR, + "VUID-vkCmdBeginRenderPass-initialLayout-00897", "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03097"); + + vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr); + descriptions[1].initialLayout = VK_IMAGE_LAYOUT_GENERAL; + + // Initial layout is VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL but attachment doesn't support VK_IMAGE_USAGE_TRANSFER_SRC_BIT + descriptions[0].initialLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid); + rp_begin.renderPass = rp_invalid; + + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR, + "VUID-vkCmdBeginRenderPass-initialLayout-00898", "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03098"); + + vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr); + + // Initial layout is VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL but attachment doesn't support VK_IMAGE_USAGE_TRANSFER_DST_BIT + descriptions[0].initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid); + rp_begin.renderPass = rp_invalid; + + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR, + "VUID-vkCmdBeginRenderPass-initialLayout-00899", "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03099"); + + vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr); + + // Initial layout is VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL but attachment doesn't support + // VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + descriptions[0].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid); + rp_begin.renderPass = rp_invalid; + const char *initial_layout_vuid_rp1 = + maintenance2Supported ? "VUID-vkCmdBeginRenderPass-initialLayout-01758" : "VUID-vkCmdBeginRenderPass-initialLayout-00896"; + + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR, initial_layout_vuid_rp1, + "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096"); + + vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr); + + // Initial layout is VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL but attachment doesn't support + // VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + descriptions[0].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid); + rp_begin.renderPass = rp_invalid; + + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR, initial_layout_vuid_rp1, + "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096"); + + vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr); + + if (maintenance2Supported || rp2Supported) { + // Initial layout is VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL but attachment doesn't support + // VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + descriptions[0].initialLayout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid); + rp_begin.renderPass = rp_invalid; + + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR, + "VUID-vkCmdBeginRenderPass-initialLayout-01758", "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096"); + + vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr); + + // Initial layout is VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL but attachment doesn't support + // VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + descriptions[0].initialLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid); + rp_begin.renderPass = rp_invalid; + + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR, + "VUID-vkCmdBeginRenderPass-initialLayout-01758", "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096"); + + vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr); + } + + vkDestroyRenderPass(m_device->device(), rp, nullptr); + vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyImageView(m_device->device(), iav, nullptr); + vkDestroyImageView(m_device->device(), cav, nullptr); +} + +TEST_F(VkLayerTest, RenderPassBeginClearOpMismatch) { + TEST_DESCRIPTION( + "Begin a renderPass where clearValueCount is less than the number of renderPass attachments that use " + "loadOp VK_ATTACHMENT_LOAD_OP_CLEAR."); + + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR = nullptr; + bool rp2Supported = false; + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)); + + if (rp2Supported) { + vkCmdBeginRenderPass2KHR = + (PFN_vkCmdBeginRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCmdBeginRenderPass2KHR"); + } + + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + // Create a renderPass with a single attachment that uses loadOp CLEAR + VkAttachmentReference attach = {}; + attach.layout = VK_IMAGE_LAYOUT_GENERAL; + VkSubpassDescription subpass = {}; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &attach; + VkRenderPassCreateInfo rpci = {}; + rpci.subpassCount = 1; + rpci.pSubpasses = &subpass; + rpci.attachmentCount = 1; + VkAttachmentDescription attach_desc = {}; + attach_desc.format = VK_FORMAT_B8G8R8A8_UNORM; + // Set loadOp to CLEAR + attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; + attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL; + rpci.pAttachments = &attach_desc; + rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + VkRenderPass rp; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); + + VkCommandBufferInheritanceInfo hinfo = {}; + hinfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + hinfo.renderPass = VK_NULL_HANDLE; + hinfo.subpass = 0; + hinfo.framebuffer = VK_NULL_HANDLE; + hinfo.occlusionQueryEnable = VK_FALSE; + hinfo.queryFlags = 0; + hinfo.pipelineStatistics = 0; + VkCommandBufferBeginInfo info = {}; + info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + info.pInheritanceInfo = &hinfo; + + VkRenderPassBeginInfo rp_begin = {}; + rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rp_begin.pNext = NULL; + rp_begin.renderPass = renderPass(); + rp_begin.framebuffer = framebuffer(); + rp_begin.clearValueCount = 0; // Should be 1 + + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR, + "VUID-VkRenderPassBeginInfo-clearValueCount-00902", "VUID-VkRenderPassBeginInfo-clearValueCount-00902"); + + vkDestroyRenderPass(m_device->device(), rp, NULL); +} + +TEST_F(VkLayerTest, RenderPassBeginSampleLocationsInvalidIndicesEXT) { + TEST_DESCRIPTION("Test that attachment indices and subpass indices specifed by sample locations structures are valid"); + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + if (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME); + } else { + printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME); + return; + } + + ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)); + + // Create a depth stencil image view + VkImageObj image(m_device); + + image.Init(128, 128, 1, VK_FORMAT_D16_UNORM, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL); + ASSERT_TRUE(image.initialized()); + + VkImageView dsv; + VkImageViewCreateInfo dsvci = {}; + dsvci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + dsvci.pNext = nullptr; + dsvci.image = image.handle(); + dsvci.viewType = VK_IMAGE_VIEW_TYPE_2D; + dsvci.format = VK_FORMAT_D16_UNORM; + dsvci.subresourceRange.layerCount = 1; + dsvci.subresourceRange.baseMipLevel = 0; + dsvci.subresourceRange.levelCount = 1; + dsvci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + vkCreateImageView(m_device->device(), &dsvci, NULL, &dsv); + + // Create a renderPass with a single attachment that uses loadOp CLEAR + VkAttachmentDescription description = {0, + VK_FORMAT_D16_UNORM, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_CLEAR, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_GENERAL}; + + VkAttachmentReference depth_stencil_ref = {0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, &depth_stencil_ref, 0, + nullptr}; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &description, 1, &subpass, 0, nullptr}; + VkRenderPass rp; + + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); + + // Create a framebuffer + + VkFramebufferCreateInfo fbci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &dsv, 128, 128, 1}; + VkFramebuffer fb; + + vkCreateFramebuffer(m_device->handle(), &fbci, nullptr, &fb); + + VkSampleLocationEXT sample_location = {0.5, 0.5}; + + VkSampleLocationsInfoEXT sample_locations_info = { + VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT, nullptr, VK_SAMPLE_COUNT_1_BIT, {1, 1}, 1, &sample_location}; + + VkAttachmentSampleLocationsEXT attachment_sample_locations = {0, sample_locations_info}; + VkSubpassSampleLocationsEXT subpass_sample_locations = {0, sample_locations_info}; + + VkRenderPassSampleLocationsBeginInfoEXT rp_sl_begin = {VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT, + nullptr, + 1, + &attachment_sample_locations, + 1, + &subpass_sample_locations}; + + VkRenderPassBeginInfo rp_begin = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, &rp_sl_begin, rp, fb, {{0, 0}, {128, 128}}, 0, nullptr}; + + attachment_sample_locations.attachmentIndex = 1; + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, nullptr, + "VUID-VkAttachmentSampleLocationsEXT-attachmentIndex-01531", nullptr); + attachment_sample_locations.attachmentIndex = 0; + + subpass_sample_locations.subpassIndex = 1; + TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, nullptr, + "VUID-VkSubpassSampleLocationsEXT-subpassIndex-01532", nullptr); + subpass_sample_locations.subpassIndex = 0; + + vkDestroyRenderPass(m_device->device(), rp, nullptr); + vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyImageView(m_device->device(), dsv, nullptr); +} + +TEST_F(VkLayerTest, RenderPassNextSubpassExcessive) { + TEST_DESCRIPTION("Test that an error is produced when CmdNextSubpass is called too many times in a renderpass instance"); + + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR = nullptr; + bool rp2Supported = false; + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState()); + + if (rp2Supported) { + vkCmdNextSubpass2KHR = (PFN_vkCmdNextSubpass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCmdNextSubpass2KHR"); + } + + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + m_commandBuffer->begin(); + m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); + + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdNextSubpass-None-00909"); + vkCmdNextSubpass(m_commandBuffer->handle(), VK_SUBPASS_CONTENTS_INLINE); + m_errorMonitor->VerifyFound(); + + if (rp2Supported) { + VkSubpassBeginInfoKHR subpassBeginInfo = {VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR, nullptr, VK_SUBPASS_CONTENTS_INLINE}; + VkSubpassEndInfoKHR subpassEndInfo = {VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR, nullptr}; + + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdNextSubpass2KHR-None-03102"); + + vkCmdNextSubpass2KHR(m_commandBuffer->handle(), &subpassBeginInfo, &subpassEndInfo); + m_errorMonitor->VerifyFound(); + } + + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); +} + +TEST_F(VkLayerTest, RenderPassEndBeforeFinalSubpass) { + TEST_DESCRIPTION("Test that an error is produced when CmdEndRenderPass is called before the final subpass has been reached"); + + // Check for VK_KHR_get_physical_device_properties2 + if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } + + ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR = nullptr; + bool rp2Supported = false; + + // Check for VK_KHR_create_renderpass2 + if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { + m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + rp2Supported = true; + } + ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)); + + if (rp2Supported) { + vkCmdEndRenderPass2KHR = (PFN_vkCmdEndRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCmdEndRenderPass2KHR"); + } + + VkSubpassDescription sd[2] = {{0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr}, + {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr}}; + + VkRenderPassCreateInfo rcpi = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 2, sd, 0, nullptr}; + + VkRenderPass rp; + VkResult err = vkCreateRenderPass(m_device->device(), &rcpi, nullptr, &rp); + ASSERT_VK_SUCCESS(err); + + VkFramebufferCreateInfo fbci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 0, nullptr, 16, 16, 1}; + + VkFramebuffer fb; + err = vkCreateFramebuffer(m_device->device(), &fbci, nullptr, &fb); + ASSERT_VK_SUCCESS(err); + + m_commandBuffer->begin(); + + VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {16, 16}}, 0, nullptr}; + + vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); + + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdEndRenderPass-None-00910"); + vkCmdEndRenderPass(m_commandBuffer->handle()); + m_errorMonitor->VerifyFound(); + + if (rp2Supported) { + VkSubpassEndInfoKHR subpassEndInfo = {VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR, nullptr}; + + m_commandBuffer->reset(); + m_commandBuffer->begin(); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); + + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdEndRenderPass2KHR-None-03103"); + vkCmdEndRenderPass2KHR(m_commandBuffer->handle(), &subpassEndInfo); + m_errorMonitor->VerifyFound(); + } + + // Clean up. + vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyRenderPass(m_device->device(), rp, nullptr); +} + +TEST_F(VkLayerTest, RenderPassDestroyWhileInUse) { + TEST_DESCRIPTION("Delete in-use renderPass."); + + ASSERT_NO_FATAL_FAILURE(Init()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + // Create simple renderpass + VkAttachmentReference attach = {}; + attach.layout = VK_IMAGE_LAYOUT_GENERAL; + VkSubpassDescription subpass = {}; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &attach; + VkRenderPassCreateInfo rpci = {}; + rpci.subpassCount = 1; + rpci.pSubpasses = &subpass; + rpci.attachmentCount = 1; + VkAttachmentDescription attach_desc = {}; + attach_desc.format = VK_FORMAT_B8G8R8A8_UNORM; + attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; + attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL; + rpci.pAttachments = &attach_desc; + rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + VkRenderPass rp; + VkResult err = vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); + ASSERT_VK_SUCCESS(err); + + m_errorMonitor->ExpectSuccess(); + + m_commandBuffer->begin(); + VkRenderPassBeginInfo rpbi = {}; + rpbi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rpbi.framebuffer = m_framebuffer; + rpbi.renderPass = rp; + m_commandBuffer->BeginRenderPass(rpbi); + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); + + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &m_commandBuffer->handle(); + vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); + m_errorMonitor->VerifyNotFound(); + + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyRenderPass-renderPass-00873"); + vkDestroyRenderPass(m_device->device(), rp, nullptr); + m_errorMonitor->VerifyFound(); + + // Wait for queue to complete so we can safely destroy rp + vkQueueWaitIdle(m_device->m_queue); + m_errorMonitor->SetUnexpectedError("If renderPass is not VK_NULL_HANDLE, renderPass must be a valid VkRenderPass handle"); + m_errorMonitor->SetUnexpectedError("Was it created? Has it already been destroyed?"); + vkDestroyRenderPass(m_device->device(), rp, nullptr); +} + +TEST_F(VkPositiveLayerTest, RenderPassCreateAttachmentUsedTwiceOK) { + TEST_DESCRIPTION("Attachment is used simultaneously as color and input, with the same layout. This is OK."); + + ASSERT_NO_FATAL_FAILURE(Init()); + + VkAttachmentDescription attach[] = { + {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL}, + }; + VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_GENERAL}; + VkSubpassDescription subpasses[] = { + {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &ref, 1, &ref, nullptr, nullptr, 0, nullptr}, + }; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attach, 1, subpasses, 0, nullptr}; + VkRenderPass rp; + + m_errorMonitor->ExpectSuccess(); + vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); + m_errorMonitor->VerifyNotFound(); + vkDestroyRenderPass(m_device->device(), rp, nullptr); +} + +TEST_F(VkPositiveLayerTest, RenderPassCreateInitialLayoutUndefined) { + TEST_DESCRIPTION( + "Ensure that CmdBeginRenderPass with an attachment's initialLayout of VK_IMAGE_LAYOUT_UNDEFINED works when the command " + "buffer has prior knowledge of that attachment's layout."); + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(Init()); + + // A renderpass with one color attachment. + VkAttachmentDescription attachment = {0, + VK_FORMAT_R8G8B8A8_UNORM, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + + VkAttachmentReference att_ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr}; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 0, nullptr}; + + VkRenderPass rp; + VkResult err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); + ASSERT_VK_SUCCESS(err); + + // A compatible framebuffer. + VkImageObj image(m_device); + image.Init(32, 32, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); + ASSERT_TRUE(image.initialized()); + + VkImageViewCreateInfo ivci = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + nullptr, + 0, + image.handle(), + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, + {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY}, + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}, + }; + VkImageView view; + err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); + ASSERT_VK_SUCCESS(err); + + VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1}; + VkFramebuffer fb; + err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); + ASSERT_VK_SUCCESS(err); + + // Record a single command buffer which uses this renderpass twice. The + // bug is triggered at the beginning of the second renderpass, when the + // command buffer already has a layout recorded for the attachment. + VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; + m_commandBuffer->begin(); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); + vkCmdEndRenderPass(m_commandBuffer->handle()); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); + + m_errorMonitor->VerifyNotFound(); + + vkCmdEndRenderPass(m_commandBuffer->handle()); + m_commandBuffer->end(); + + vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyRenderPass(m_device->device(), rp, nullptr); + vkDestroyImageView(m_device->device(), view, nullptr); +} + +TEST_F(VkPositiveLayerTest, RenderPassCreateAttachmentLayoutWithLoadOpThenReadOnly) { + TEST_DESCRIPTION( + "Positive test where we create a renderpass with an attachment that uses LOAD_OP_CLEAR, the first subpass has a valid " + "layout, and a second subpass then uses a valid *READ_ONLY* layout."); + m_errorMonitor->ExpectSuccess(); + ASSERT_NO_FATAL_FAILURE(Init()); + auto depth_format = FindSupportedDepthStencilFormat(gpu()); + if (!depth_format) { + printf("%s No Depth + Stencil format found. Skipped.\n", kSkipPrefix); + return; + } + + VkAttachmentReference attach[2] = {}; + attach[0].attachment = 0; + attach[0].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attach[1].attachment = 0; + attach[1].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + VkSubpassDescription subpasses[2] = {}; + // First subpass clears DS attach on load + subpasses[0].pDepthStencilAttachment = &attach[0]; + // 2nd subpass reads in DS as input attachment + subpasses[1].inputAttachmentCount = 1; + subpasses[1].pInputAttachments = &attach[1]; + VkAttachmentDescription attach_desc = {}; + attach_desc.format = depth_format; + attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; + attach_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attach_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attach_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attach_desc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attach_desc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + VkRenderPassCreateInfo rpci = {}; + rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + rpci.attachmentCount = 1; + rpci.pAttachments = &attach_desc; + rpci.subpassCount = 2; + rpci.pSubpasses = subpasses; + + // Now create RenderPass and verify no errors + VkRenderPass rp; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); + m_errorMonitor->VerifyNotFound(); + + vkDestroyRenderPass(m_device->device(), rp, NULL); +} + +TEST_F(VkPositiveLayerTest, RenderPassBeginSubpassZeroTransitionsApplied) { + TEST_DESCRIPTION("Ensure that CmdBeginRenderPass applies the layout transitions for the first subpass"); + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(Init()); + + // A renderpass with one color attachment. + VkAttachmentDescription attachment = {0, + VK_FORMAT_R8G8B8A8_UNORM, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + + VkAttachmentReference att_ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr}; + + VkSubpassDependency dep = {0, + 0, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_DEPENDENCY_BY_REGION_BIT}; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 1, &dep}; + + VkResult err; + VkRenderPass rp; + err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); + ASSERT_VK_SUCCESS(err); + + // A compatible framebuffer. + VkImageObj image(m_device); + image.Init(32, 32, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); + ASSERT_TRUE(image.initialized()); + + VkImageView view = image.targetView(VK_FORMAT_R8G8B8A8_UNORM); + + VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1}; + VkFramebuffer fb; + err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); + ASSERT_VK_SUCCESS(err); + + // Record a single command buffer which issues a pipeline barrier w/ + // image memory barrier for the attachment. This detects the previously + // missing tracking of the subpass layout by throwing a validation error + // if it doesn't occur. + VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; + m_commandBuffer->begin(); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); + + VkImageMemoryBarrier imb = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + nullptr, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + image.handle(), + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; + vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, + &imb); + + vkCmdEndRenderPass(m_commandBuffer->handle()); + m_errorMonitor->VerifyNotFound(); + m_commandBuffer->end(); + + vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyRenderPass(m_device->device(), rp, nullptr); +} + +TEST_F(VkPositiveLayerTest, RenderPassBeginTransitionsAttachmentUnused) { + TEST_DESCRIPTION( + "Ensure that layout transitions work correctly without errors, when an attachment reference is VK_ATTACHMENT_UNUSED"); + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(Init()); + + // A renderpass with no attachments + VkAttachmentReference att_ref = {VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr}; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 1, &subpass, 0, nullptr}; + + VkRenderPass rp; + VkResult err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); + ASSERT_VK_SUCCESS(err); + + // A compatible framebuffer. + VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 0, nullptr, 32, 32, 1}; + VkFramebuffer fb; + err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); + ASSERT_VK_SUCCESS(err); + + // Record a command buffer which just begins and ends the renderpass. The + // bug manifests in BeginRenderPass. + VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; + m_commandBuffer->begin(); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); + vkCmdEndRenderPass(m_commandBuffer->handle()); + m_errorMonitor->VerifyNotFound(); + m_commandBuffer->end(); + + vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyRenderPass(m_device->device(), rp, nullptr); +} + +TEST_F(VkPositiveLayerTest, RenderPassBeginStencilLoadOp) { + TEST_DESCRIPTION("Create a stencil-only attachment with a LOAD_OP set to CLEAR. stencil[Load|Store]Op used to be ignored."); + VkResult result = VK_SUCCESS; + ASSERT_NO_FATAL_FAILURE(Init()); + auto depth_format = FindSupportedDepthStencilFormat(gpu()); + if (!depth_format) { + printf("%s No Depth + Stencil format found. Skipped.\n", kSkipPrefix); + return; + } + VkImageFormatProperties formatProps; + vkGetPhysicalDeviceImageFormatProperties(gpu(), depth_format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0, + &formatProps); + if (formatProps.maxExtent.width < 100 || formatProps.maxExtent.height < 100) { + printf("%s Image format max extent is too small.\n", kSkipPrefix); + return; + } + + VkFormat depth_stencil_fmt = depth_format; + m_depthStencil->Init(m_device, 100, 100, depth_stencil_fmt, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + VkAttachmentDescription att = {}; + VkAttachmentReference ref = {}; + att.format = depth_stencil_fmt; + att.samples = VK_SAMPLE_COUNT_1_BIT; + att.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + att.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + att.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + att.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + att.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + att.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkClearValue clear; + clear.depthStencil.depth = 1.0; + clear.depthStencil.stencil = 0; + ref.attachment = 0; + ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.flags = 0; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = NULL; + subpass.colorAttachmentCount = 0; + subpass.pColorAttachments = NULL; + subpass.pResolveAttachments = NULL; + subpass.pDepthStencilAttachment = &ref; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = NULL; + + VkRenderPass rp; + VkRenderPassCreateInfo rp_info = {}; + rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + rp_info.attachmentCount = 1; + rp_info.pAttachments = &att; + rp_info.subpassCount = 1; + rp_info.pSubpasses = &subpass; + result = vkCreateRenderPass(device(), &rp_info, NULL, &rp); + ASSERT_VK_SUCCESS(result); + + VkImageView *depthView = m_depthStencil->BindInfo(); + VkFramebufferCreateInfo fb_info = {}; + fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fb_info.pNext = NULL; + fb_info.renderPass = rp; + fb_info.attachmentCount = 1; + fb_info.pAttachments = depthView; + fb_info.width = 100; + fb_info.height = 100; + fb_info.layers = 1; + VkFramebuffer fb; + result = vkCreateFramebuffer(device(), &fb_info, NULL, &fb); + ASSERT_VK_SUCCESS(result); + + VkRenderPassBeginInfo rpbinfo = {}; + rpbinfo.clearValueCount = 1; + rpbinfo.pClearValues = &clear; + rpbinfo.pNext = NULL; + rpbinfo.renderPass = rp; + rpbinfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rpbinfo.renderArea.extent.width = 100; + rpbinfo.renderArea.extent.height = 100; + rpbinfo.renderArea.offset.x = 0; + rpbinfo.renderArea.offset.y = 0; + rpbinfo.framebuffer = fb; + + VkFenceObj fence; + fence.init(*m_device, VkFenceObj::create_info()); + ASSERT_TRUE(fence.initialized()); + + m_commandBuffer->begin(); + m_commandBuffer->BeginRenderPass(rpbinfo); + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); + m_commandBuffer->QueueCommandBuffer(fence); + + VkImageObj destImage(m_device); + destImage.Init(100, 100, 1, depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + VK_IMAGE_TILING_OPTIMAL, 0); + VkImageMemoryBarrier barrier = {}; + VkImageSubresourceRange range; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + barrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.image = m_depthStencil->handle(); + range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + range.baseMipLevel = 0; + range.levelCount = 1; + range.baseArrayLayer = 0; + range.layerCount = 1; + barrier.subresourceRange = range; + fence.wait(VK_TRUE, UINT64_MAX); + VkCommandBufferObj cmdbuf(m_device, m_commandPool); + cmdbuf.begin(); + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, + &barrier); + barrier.srcAccessMask = 0; + barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.image = destImage.handle(); + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, + &barrier); + VkImageCopy cregion; + cregion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + cregion.srcSubresource.mipLevel = 0; + cregion.srcSubresource.baseArrayLayer = 0; + cregion.srcSubresource.layerCount = 1; + cregion.srcOffset.x = 0; + cregion.srcOffset.y = 0; + cregion.srcOffset.z = 0; + cregion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + cregion.dstSubresource.mipLevel = 0; + cregion.dstSubresource.baseArrayLayer = 0; + cregion.dstSubresource.layerCount = 1; + cregion.dstOffset.x = 0; + cregion.dstOffset.y = 0; + cregion.dstOffset.z = 0; + cregion.extent.width = 100; + cregion.extent.height = 100; + cregion.extent.depth = 1; + cmdbuf.CopyImage(m_depthStencil->handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, destImage.handle(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); + cmdbuf.end(); + + VkSubmitInfo submit_info; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.pNext = NULL; + submit_info.waitSemaphoreCount = 0; + submit_info.pWaitSemaphores = NULL; + submit_info.pWaitDstStageMask = NULL; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &cmdbuf.handle(); + submit_info.signalSemaphoreCount = 0; + submit_info.pSignalSemaphores = NULL; + + m_errorMonitor->ExpectSuccess(); + vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); + m_errorMonitor->VerifyNotFound(); + + vkQueueWaitIdle(m_device->m_queue); + vkDestroyRenderPass(m_device->device(), rp, nullptr); + vkDestroyFramebuffer(m_device->device(), fb, nullptr); +} + +TEST_F(VkPositiveLayerTest, RenderPassBeginInlineAndSecondaryCommandBuffers) { + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(Init()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + m_commandBuffer->begin(); + + vkCmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + vkCmdEndRenderPass(m_commandBuffer->handle()); + m_errorMonitor->VerifyNotFound(); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + m_errorMonitor->VerifyNotFound(); + vkCmdEndRenderPass(m_commandBuffer->handle()); + m_errorMonitor->VerifyNotFound(); + + m_commandBuffer->end(); + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, RenderPassBeginDepthStencilLayoutTransitionFromUndefined) { + TEST_DESCRIPTION( + "Create a render pass with depth-stencil attachment where layout transition from UNDEFINED TO DS_READ_ONLY_OPTIMAL is set " + "by render pass and verify that transition has correctly occurred at queue submit time with no validation errors."); + + ASSERT_NO_FATAL_FAILURE(Init()); + auto depth_format = FindSupportedDepthStencilFormat(gpu()); + if (!depth_format) { + printf("%s No Depth + Stencil format found. Skipped.\n", kSkipPrefix); + return; + } + VkImageFormatProperties format_props; + vkGetPhysicalDeviceImageFormatProperties(gpu(), depth_format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0, &format_props); + if (format_props.maxExtent.width < 32 || format_props.maxExtent.height < 32) { + printf("%s Depth extent too small, RenderPassDepthStencilLayoutTransition skipped.\n", kSkipPrefix); + return; + } + + m_errorMonitor->ExpectSuccess(); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + // A renderpass with one depth/stencil attachment. + VkAttachmentDescription attachment = {0, + depth_format, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + VkAttachmentReference att_ref = {0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, &att_ref, 0, nullptr}; + + VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 0, nullptr}; + + VkRenderPass rp; + VkResult err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); + ASSERT_VK_SUCCESS(err); + // A compatible ds image. + VkImageObj image(m_device); + image.Init(32, 32, 1, depth_format, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); + ASSERT_TRUE(image.initialized()); + + VkImageViewCreateInfo ivci = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + nullptr, + 0, + image.handle(), + VK_IMAGE_VIEW_TYPE_2D, + depth_format, + {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY}, + {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}, + }; + VkImageView view; + err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); + ASSERT_VK_SUCCESS(err); + + VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1}; + VkFramebuffer fb; + err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); + ASSERT_VK_SUCCESS(err); + + VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; + m_commandBuffer->begin(); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); + vkCmdEndRenderPass(m_commandBuffer->handle()); + m_commandBuffer->end(); + m_commandBuffer->QueueCommandBuffer(false); + m_errorMonitor->VerifyNotFound(); + + // Cleanup + vkDestroyImageView(m_device->device(), view, NULL); + vkDestroyRenderPass(m_device->device(), rp, NULL); + vkDestroyFramebuffer(m_device->device(), fb, NULL); +} + +TEST_F(VkLayerTest, DisabledIndependentBlend) { + TEST_DESCRIPTION( + "Generate INDEPENDENT_BLEND by disabling independent blend and then specifying different blend states for two " + "attachments"); + VkPhysicalDeviceFeatures features = {}; + features.independentBlend = VK_FALSE; + ASSERT_NO_FATAL_FAILURE(Init(&features)); + + m_errorMonitor->SetDesiredFailureMsg( + VK_DEBUG_REPORT_ERROR_BIT_EXT, + "Invalid Pipeline CreateInfo: If independent blend feature not enabled, all elements of pAttachments must be identical"); + + VkDescriptorSetObj descriptorSet(m_device); + descriptorSet.AppendDummy(); + descriptorSet.CreateVKDescriptorSet(m_commandBuffer); + + VkPipelineObj pipeline(m_device); + // Create a renderPass with two color attachments + VkAttachmentReference attachments[2] = {}; + attachments[0].layout = VK_IMAGE_LAYOUT_GENERAL; + attachments[1].attachment = 1; + attachments[1].layout = VK_IMAGE_LAYOUT_GENERAL; + + VkSubpassDescription subpass = {}; + subpass.pColorAttachments = attachments; + subpass.colorAttachmentCount = 2; + + VkRenderPassCreateInfo rpci = {}; + rpci.subpassCount = 1; + rpci.pSubpasses = &subpass; + rpci.attachmentCount = 2; + + VkAttachmentDescription attach_desc[2] = {}; + attach_desc[0].format = VK_FORMAT_B8G8R8A8_UNORM; + attach_desc[0].samples = VK_SAMPLE_COUNT_1_BIT; + attach_desc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attach_desc[0].finalLayout = VK_IMAGE_LAYOUT_GENERAL; + attach_desc[1].format = VK_FORMAT_B8G8R8A8_UNORM; + attach_desc[1].samples = VK_SAMPLE_COUNT_1_BIT; + attach_desc[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attach_desc[1].finalLayout = VK_IMAGE_LAYOUT_GENERAL; + + rpci.pAttachments = attach_desc; + rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + + VkRenderPass renderpass; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &renderpass); + VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); + pipeline.AddShader(&vs); + + VkPipelineColorBlendAttachmentState att_state1 = {}, att_state2 = {}; + att_state1.dstAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR; + att_state1.blendEnable = VK_TRUE; + att_state2.dstAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR; + att_state2.blendEnable = VK_FALSE; + pipeline.AddColorAttachment(0, att_state1); + pipeline.AddColorAttachment(1, att_state2); + pipeline.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderpass); + m_errorMonitor->VerifyFound(); + vkDestroyRenderPass(m_device->device(), renderpass, NULL); +} + +// Is the Pipeline compatible with the expectations of the Renderpass/subpasses? +TEST_F(VkLayerTest, PipelineRenderpassCompatibility) { + TEST_DESCRIPTION( + "Create a graphics pipeline that is incompatible with the requirements of its contained Renderpass/subpasses."); + ASSERT_NO_FATAL_FAILURE(Init()); + + VkDescriptorSetObj ds_obj(m_device); + ds_obj.AppendDummy(); + ds_obj.CreateVKDescriptorSet(m_commandBuffer); + + VkShaderObj vs_obj(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); + + VkPipelineColorBlendAttachmentState att_state1 = {}; + att_state1.dstAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR; + att_state1.blendEnable = VK_TRUE; + + VkRenderpassObj rp_obj(m_device); + + { + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, + "VUID-VkGraphicsPipelineCreateInfo-rasterizerDiscardEnable-00753"); + VkPipelineObj pipeline(m_device); + pipeline.AddShader(&vs_obj); + pipeline.AddColorAttachment(0, att_state1); + + VkGraphicsPipelineCreateInfo info = {}; + pipeline.InitGraphicsPipelineCreateInfo(&info); + info.pColorBlendState = nullptr; + + pipeline.CreateVKPipeline(ds_obj.GetPipelineLayout(), rp_obj.handle(), &info); + m_errorMonitor->VerifyFound(); + } +} + +TEST_F(VkLayerTest, FramebufferCreateErrors) { + TEST_DESCRIPTION( + "Hit errors when attempting to create a framebuffer :\n" + " 1. Mismatch between framebuffer & renderPass attachmentCount\n" + " 2. Use a color image as depthStencil attachment\n" + " 3. Mismatch framebuffer & renderPass attachment formats\n" + " 4. Mismatch framebuffer & renderPass attachment #samples\n" + " 5. Framebuffer attachment w/ non-1 mip-levels\n" + " 6. Framebuffer attachment where dimensions don't match\n" + " 7. Framebuffer attachment where dimensions don't match\n" + " 8. Framebuffer attachment w/o identity swizzle\n" + " 9. framebuffer dimensions exceed physical device limits\n"); + + ASSERT_NO_FATAL_FAILURE(Init()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkFramebufferCreateInfo-attachmentCount-00876"); + + // Create a renderPass with a single color attachment + VkAttachmentReference attach = {}; + attach.layout = VK_IMAGE_LAYOUT_GENERAL; + VkSubpassDescription subpass = {}; + subpass.pColorAttachments = &attach; + VkRenderPassCreateInfo rpci = {}; + rpci.subpassCount = 1; + rpci.pSubpasses = &subpass; + rpci.attachmentCount = 1; + VkAttachmentDescription attach_desc = {}; + attach_desc.format = VK_FORMAT_B8G8R8A8_UNORM; + attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; + attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL; + rpci.pAttachments = &attach_desc; + rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + VkRenderPass rp; + VkResult err = vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); + ASSERT_VK_SUCCESS(err); + + VkImageView ivs[2]; + ivs[0] = m_renderTargets[0]->targetView(VK_FORMAT_B8G8R8A8_UNORM); + ivs[1] = m_renderTargets[0]->targetView(VK_FORMAT_B8G8R8A8_UNORM); + VkFramebufferCreateInfo fb_info = {}; + fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fb_info.pNext = NULL; + fb_info.renderPass = rp; + // Set mis-matching attachmentCount + fb_info.attachmentCount = 2; + fb_info.pAttachments = ivs; + fb_info.width = 100; + fb_info.height = 100; + fb_info.layers = 1; + + VkFramebuffer fb; + err = vkCreateFramebuffer(device(), &fb_info, NULL, &fb); + + m_errorMonitor->VerifyFound(); + if (err == VK_SUCCESS) { + vkDestroyFramebuffer(m_device->device(), fb, NULL); + } + vkDestroyRenderPass(m_device->device(), rp, NULL); + + // Create a renderPass with a depth-stencil attachment created with + // IMAGE_USAGE_COLOR_ATTACHMENT + // Add our color attachment to pDepthStencilAttachment + subpass.pDepthStencilAttachment = &attach; + subpass.pColorAttachments = NULL; + VkRenderPass rp_ds; + err = vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_ds); + ASSERT_VK_SUCCESS(err); + // Set correct attachment count, but attachment has COLOR usage bit set + fb_info.attachmentCount = 1; + fb_info.renderPass = rp_ds; + + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkFramebufferCreateInfo-pAttachments-00878"); + err = vkCreateFramebuffer(device(), &fb_info, NULL, &fb); + + m_errorMonitor->VerifyFound(); + if (err == VK_SUCCESS) { + vkDestroyFramebuffer(m_device->device(), fb, NULL); + } + vkDestroyRenderPass(m_device->device(), rp_ds, NULL); // Create new renderpass with alternate attachment format from fb attach_desc.format = VK_FORMAT_R8G8B8A8_UNORM; @@ -7742,61 +9783,6 @@ TEST_F(VkLayerTest, FramebufferImageInUseDestroyedSignaled) { vkFreeMemory(m_device->device(), image_memory, nullptr); } -TEST_F(VkLayerTest, RenderPassInUseDestroyedSignaled) { - TEST_DESCRIPTION("Delete in-use renderPass."); - - ASSERT_NO_FATAL_FAILURE(Init()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - // Create simple renderpass - VkAttachmentReference attach = {}; - attach.layout = VK_IMAGE_LAYOUT_GENERAL; - VkSubpassDescription subpass = {}; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &attach; - VkRenderPassCreateInfo rpci = {}; - rpci.subpassCount = 1; - rpci.pSubpasses = &subpass; - rpci.attachmentCount = 1; - VkAttachmentDescription attach_desc = {}; - attach_desc.format = VK_FORMAT_B8G8R8A8_UNORM; - attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; - attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL; - rpci.pAttachments = &attach_desc; - rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - VkRenderPass rp; - VkResult err = vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); - ASSERT_VK_SUCCESS(err); - - m_errorMonitor->ExpectSuccess(); - - m_commandBuffer->begin(); - VkRenderPassBeginInfo rpbi = {}; - rpbi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - rpbi.framebuffer = m_framebuffer; - rpbi.renderPass = rp; - m_commandBuffer->BeginRenderPass(rpbi); - m_commandBuffer->EndRenderPass(); - m_commandBuffer->end(); - - VkSubmitInfo submit_info = {}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &m_commandBuffer->handle(); - vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); - m_errorMonitor->VerifyNotFound(); - - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkDestroyRenderPass-renderPass-00873"); - vkDestroyRenderPass(m_device->device(), rp, nullptr); - m_errorMonitor->VerifyFound(); - - // Wait for queue to complete so we can safely destroy rp - vkQueueWaitIdle(m_device->m_queue); - m_errorMonitor->SetUnexpectedError("If renderPass is not VK_NULL_HANDLE, renderPass must be a valid VkRenderPass handle"); - m_errorMonitor->SetUnexpectedError("Was it created? Has it already been destroyed?"); - vkDestroyRenderPass(m_device->device(), rp, nullptr); -} - TEST_F(VkLayerTest, ImageMemoryNotBound) { TEST_DESCRIPTION("Attempt to draw with an image which has not had memory bound to it."); ASSERT_NO_FATAL_FAILURE(Init()); @@ -12035,91 +14021,12 @@ TEST_F(VkLayerTest, NullRenderPass) { m_commandBuffer->begin(); // Don't care about RenderPass handle b/c error should be flagged before - // that - vkCmdBeginRenderPass(m_commandBuffer->handle(), NULL, VK_SUBPASS_CONTENTS_INLINE); - - m_errorMonitor->VerifyFound(); - - m_commandBuffer->end(); -} - -TEST_F(VkLayerTest, RenderPassWithinRenderPass) { - // Bind a BeginRenderPass within an active RenderPass - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, - "It is invalid to issue this call inside an active render pass"); - - ASSERT_NO_FATAL_FAILURE(Init()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - m_commandBuffer->begin(); - m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); - // Just create a dummy Renderpass that's non-NULL so we can get to the - // proper error - vkCmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - - m_errorMonitor->VerifyFound(); - - m_commandBuffer->EndRenderPass(); - m_commandBuffer->end(); -} - -TEST_F(VkLayerTest, RenderPassClearOpMismatch) { - TEST_DESCRIPTION( - "Begin a renderPass where clearValueCount is less than the number of renderPass attachments that use " - "loadOpVK_ATTACHMENT_LOAD_OP_CLEAR."); - - ASSERT_NO_FATAL_FAILURE(Init()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - // Create a renderPass with a single attachment that uses loadOp CLEAR - VkAttachmentReference attach = {}; - attach.layout = VK_IMAGE_LAYOUT_GENERAL; - VkSubpassDescription subpass = {}; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &attach; - VkRenderPassCreateInfo rpci = {}; - rpci.subpassCount = 1; - rpci.pSubpasses = &subpass; - rpci.attachmentCount = 1; - VkAttachmentDescription attach_desc = {}; - attach_desc.format = VK_FORMAT_B8G8R8A8_UNORM; - // Set loadOp to CLEAR - attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; - attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL; - rpci.pAttachments = &attach_desc; - rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - VkRenderPass rp; - vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); - - VkCommandBufferInheritanceInfo hinfo = {}; - hinfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; - hinfo.renderPass = VK_NULL_HANDLE; - hinfo.subpass = 0; - hinfo.framebuffer = VK_NULL_HANDLE; - hinfo.occlusionQueryEnable = VK_FALSE; - hinfo.queryFlags = 0; - hinfo.pipelineStatistics = 0; - VkCommandBufferBeginInfo info = {}; - info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - info.pInheritanceInfo = &hinfo; - - vkBeginCommandBuffer(m_commandBuffer->handle(), &info); - VkRenderPassBeginInfo rp_begin = {}; - rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - rp_begin.pNext = NULL; - rp_begin.renderPass = renderPass(); - rp_begin.framebuffer = framebuffer(); - rp_begin.clearValueCount = 0; // Should be 1 - - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkRenderPassBeginInfo-clearValueCount-00902"); - - vkCmdBeginRenderPass(m_commandBuffer->handle(), &rp_begin, VK_SUBPASS_CONTENTS_INLINE); + // that + vkCmdBeginRenderPass(m_commandBuffer->handle(), NULL, VK_SUBPASS_CONTENTS_INLINE); m_errorMonitor->VerifyFound(); - vkDestroyRenderPass(m_device->device(), rp, NULL); + m_commandBuffer->end(); } TEST_F(VkLayerTest, EndCommandBufferWithinRenderPass) { @@ -12491,63 +14398,6 @@ TEST_F(VkLayerTest, ClearColorAttachmentsOutsideRenderPass) { m_errorMonitor->VerifyFound(); } -TEST_F(VkLayerTest, RenderPassExcessiveNextSubpass) { - TEST_DESCRIPTION("Test that an error is produced when CmdNextSubpass is called too many times in a renderpass instance"); - - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, - "vkCmdNextSubpass(): Attempted to advance beyond final subpass"); - - ASSERT_NO_FATAL_FAILURE(Init()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - m_commandBuffer->begin(); - m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); - - // error here. - vkCmdNextSubpass(m_commandBuffer->handle(), VK_SUBPASS_CONTENTS_INLINE); - m_errorMonitor->VerifyFound(); - - m_commandBuffer->EndRenderPass(); - m_commandBuffer->end(); -} - -TEST_F(VkLayerTest, RenderPassEndedBeforeFinalSubpass) { - TEST_DESCRIPTION("Test that an error is produced when CmdEndRenderPass is called before the final subpass has been reached"); - - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, - "vkCmdEndRenderPass(): Called before reaching final subpass"); - - ASSERT_NO_FATAL_FAILURE(Init()); - VkSubpassDescription sd[2] = {{0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr}, - {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr}}; - - VkRenderPassCreateInfo rcpi = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 2, sd, 0, nullptr}; - - VkRenderPass rp; - VkResult err = vkCreateRenderPass(m_device->device(), &rcpi, nullptr, &rp); - ASSERT_VK_SUCCESS(err); - - VkFramebufferCreateInfo fbci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 0, nullptr, 16, 16, 1}; - - VkFramebuffer fb; - err = vkCreateFramebuffer(m_device->device(), &fbci, nullptr, &fb); - ASSERT_VK_SUCCESS(err); - - m_commandBuffer->begin(); // no implicit RP begin - - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {16, 16}}, 0, nullptr}; - - vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); - - // Error here. - vkCmdEndRenderPass(m_commandBuffer->handle()); - m_errorMonitor->VerifyFound(); - - // Clean up. - vkDestroyFramebuffer(m_device->device(), fb, nullptr); - vkDestroyRenderPass(m_device->device(), rp, nullptr); -} - TEST_F(VkLayerTest, BufferMemoryBarrierNoBuffer) { // Try to add a buffer memory barrier with no buffer. m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, @@ -14614,7 +16464,7 @@ TEST_F(VkLayerTest, NumSamplesMismatch) { m_errorMonitor->VerifyFound(); } -TEST_F(VkLayerTest, RenderPassIncompatible) { +TEST_F(VkLayerTest, DrawWithPipelineIncompatibleWithRenderPass) { TEST_DESCRIPTION( "Hit RenderPass incompatible cases. Initial case is drawing with an active renderpass that's not compatible with the bound " "pipeline state object's creation renderpass"); @@ -19758,51 +21608,6 @@ TEST_F(VkLayerTest, AttachmentDescriptionUndefinedFormat) { } } -TEST_F(VkLayerTest, AttachmentDescriptionInvalidFinalLayout) { - TEST_DESCRIPTION("VkAttachmentDescription's finalLayout must not be UNDEFINED or PREINITIALIZED"); - - ASSERT_NO_FATAL_FAILURE(Init()); - - VkAttachmentDescription attach_desc = {}; - attach_desc.format = VK_FORMAT_R8G8B8A8_UNORM; - attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; - attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attach_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attach_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attach_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attach_desc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attach_desc.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; - VkAttachmentReference attach_ref = {}; - attach_ref.attachment = 0; - attach_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &attach_ref; - VkRenderPassCreateInfo rpci = {}; - rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rpci.attachmentCount = 1; - rpci.pAttachments = &attach_desc; - rpci.subpassCount = 1; - rpci.pSubpasses = &subpass; - VkRenderPass rp = VK_NULL_HANDLE; - - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAttachmentDescription-finalLayout-00843"); - vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); - m_errorMonitor->VerifyFound(); - if (rp != VK_NULL_HANDLE) { - vkDestroyRenderPass(m_device->device(), rp, NULL); - } - - attach_desc.finalLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAttachmentDescription-finalLayout-00843"); - vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); - m_errorMonitor->VerifyFound(); - if (rp != VK_NULL_HANDLE) { - vkDestroyRenderPass(m_device->device(), rp, NULL); - } -} - TEST_F(VkLayerTest, CreateImageViewNoMemoryBoundToImage) { VkResult err; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, @@ -26902,80 +28707,6 @@ TEST_F(VkPositiveLayerTest, BindSparse) { m_errorMonitor->VerifyNotFound(); } -TEST_F(VkPositiveLayerTest, RenderPassInitialLayoutUndefined) { - TEST_DESCRIPTION( - "Ensure that CmdBeginRenderPass with an attachment's initialLayout of VK_IMAGE_LAYOUT_UNDEFINED works when the command " - "buffer has prior knowledge of that attachment's layout."); - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(Init()); - - // A renderpass with one color attachment. - VkAttachmentDescription attachment = {0, - VK_FORMAT_R8G8B8A8_UNORM, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkAttachmentReference att_ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr}; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 0, nullptr}; - - VkRenderPass rp; - VkResult err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - ASSERT_VK_SUCCESS(err); - - // A compatible framebuffer. - VkImageObj image(m_device); - image.Init(32, 32, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); - ASSERT_TRUE(image.initialized()); - - VkImageViewCreateInfo ivci = { - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - nullptr, - 0, - image.handle(), - VK_IMAGE_VIEW_TYPE_2D, - VK_FORMAT_R8G8B8A8_UNORM, - {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY}, - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}, - }; - VkImageView view; - err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); - ASSERT_VK_SUCCESS(err); - - VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1}; - VkFramebuffer fb; - err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); - ASSERT_VK_SUCCESS(err); - - // Record a single command buffer which uses this renderpass twice. The - // bug is triggered at the beginning of the second renderpass, when the - // command buffer already has a layout recorded for the attachment. - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; - m_commandBuffer->begin(); - vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); - vkCmdEndRenderPass(m_commandBuffer->handle()); - vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); - - m_errorMonitor->VerifyNotFound(); - - vkCmdEndRenderPass(m_commandBuffer->handle()); - m_commandBuffer->end(); - - vkDestroyFramebuffer(m_device->device(), fb, nullptr); - vkDestroyRenderPass(m_device->device(), rp, nullptr); - vkDestroyImageView(m_device->device(), view, nullptr); -} - TEST_F(VkPositiveLayerTest, FramebufferBindingDestroyCommandPool) { TEST_DESCRIPTION( "This test should pass. Create a Framebuffer and command buffer, bind them together, then destroy command pool and " @@ -27018,119 +28749,40 @@ TEST_F(VkPositiveLayerTest, FramebufferBindingDestroyCommandPool) { err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); ASSERT_VK_SUCCESS(err); - // Explicitly create a command buffer to bind the FB to so that we can then - // destroy the command pool in order to implicitly free command buffer - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 1; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer); - - // Begin our cmd buffer with renderpass using our framebuffer - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer, &begin_info); - - vkCmdBeginRenderPass(command_buffer, &rpbi, VK_SUBPASS_CONTENTS_INLINE); - vkCmdEndRenderPass(command_buffer); - vkEndCommandBuffer(command_buffer); - // Destroy command pool to implicitly free command buffer - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - vkDestroyFramebuffer(m_device->device(), fb, nullptr); - vkDestroyRenderPass(m_device->device(), rp, nullptr); - m_errorMonitor->VerifyNotFound(); -} - -TEST_F(VkPositiveLayerTest, RenderPassSubpassZeroTransitionsApplied) { - TEST_DESCRIPTION("Ensure that CmdBeginRenderPass applies the layout transitions for the first subpass"); - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(Init()); - - // A renderpass with one color attachment. - VkAttachmentDescription attachment = {0, - VK_FORMAT_R8G8B8A8_UNORM, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkAttachmentReference att_ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr}; - - VkSubpassDependency dep = {0, - 0, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_DEPENDENCY_BY_REGION_BIT}; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 1, &dep}; - - VkResult err; - VkRenderPass rp; - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - ASSERT_VK_SUCCESS(err); - - // A compatible framebuffer. - VkImageObj image(m_device); - image.Init(32, 32, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); - ASSERT_TRUE(image.initialized()); - - VkImageView view = image.targetView(VK_FORMAT_R8G8B8A8_UNORM); - - VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1}; - VkFramebuffer fb; - err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); - ASSERT_VK_SUCCESS(err); - - // Record a single command buffer which issues a pipeline barrier w/ - // image memory barrier for the attachment. This detects the previously - // missing tracking of the subpass layout by throwing a validation error - // if it doesn't occur. - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; - m_commandBuffer->begin(); - vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); - - VkImageMemoryBarrier imb = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - nullptr, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - image.handle(), - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; - vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, - &imb); + // Explicitly create a command buffer to bind the FB to so that we can then + // destroy the command pool in order to implicitly free command buffer + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - vkCmdEndRenderPass(m_commandBuffer->handle()); - m_errorMonitor->VerifyNotFound(); - m_commandBuffer->end(); + VkCommandBuffer command_buffer; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 1; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer); + + // Begin our cmd buffer with renderpass using our framebuffer + VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer, &begin_info); + vkCmdBeginRenderPass(command_buffer, &rpbi, VK_SUBPASS_CONTENTS_INLINE); + vkCmdEndRenderPass(command_buffer); + vkEndCommandBuffer(command_buffer); + // Destroy command pool to implicitly free command buffer + vkDestroyCommandPool(m_device->device(), command_pool, NULL); vkDestroyFramebuffer(m_device->device(), fb, nullptr); vkDestroyRenderPass(m_device->device(), rp, nullptr); + m_errorMonitor->VerifyNotFound(); } -TEST_F(VkPositiveLayerTest, DepthStencilLayoutTransitionForDepthOnlyImageview) { +TEST_F(VkPositiveLayerTest, FramebufferCreateDepthStencilLayoutTransitionForDepthOnlyImageView) { TEST_DESCRIPTION( "Validate that when an imageView of a depth/stencil image is used as a depth/stencil framebuffer attachment, the " "aspectMask is ignored and both depth and stencil image subresources are used."); @@ -27200,240 +28852,34 @@ TEST_F(VkPositiveLayerTest, DepthStencilLayoutTransitionForDepthOnlyImageview) { err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); ASSERT_VK_SUCCESS(err); - m_commandBuffer->begin(); - - VkImageMemoryBarrier imb = {}; - imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imb.pNext = nullptr; - imb.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - imb.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - imb.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - imb.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imb.srcQueueFamilyIndex = 0; - imb.dstQueueFamilyIndex = 0; - imb.image = image.handle(); - imb.subresourceRange.aspectMask = 0x6; - imb.subresourceRange.baseMipLevel = 0; - imb.subresourceRange.levelCount = 0x1; - imb.subresourceRange.baseArrayLayer = 0; - imb.subresourceRange.layerCount = 0x1; - - vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, &imb); - - m_commandBuffer->end(); - m_commandBuffer->QueueCommandBuffer(false); - m_errorMonitor->VerifyNotFound(); - - vkDestroyFramebuffer(m_device->device(), fb, nullptr); - vkDestroyRenderPass(m_device->device(), rp, nullptr); - vkDestroyImageView(m_device->device(), view, nullptr); -} - -TEST_F(VkPositiveLayerTest, RenderPassTransitionsAttachmentUnused) { - TEST_DESCRIPTION( - "Ensure that layout transitions work correctly without errors, when an attachment reference is VK_ATTACHMENT_UNUSED"); - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(Init()); - - // A renderpass with no attachments - VkAttachmentReference att_ref = {VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr}; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 1, &subpass, 0, nullptr}; - - VkRenderPass rp; - VkResult err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - ASSERT_VK_SUCCESS(err); - - // A compatible framebuffer. - VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 0, nullptr, 32, 32, 1}; - VkFramebuffer fb; - err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); - ASSERT_VK_SUCCESS(err); - - // Record a command buffer which just begins and ends the renderpass. The - // bug manifests in BeginRenderPass. - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; - m_commandBuffer->begin(); - vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); - vkCmdEndRenderPass(m_commandBuffer->handle()); - m_errorMonitor->VerifyNotFound(); - m_commandBuffer->end(); - - vkDestroyFramebuffer(m_device->device(), fb, nullptr); - vkDestroyRenderPass(m_device->device(), rp, nullptr); -} - -// This is a positive test. No errors are expected. -TEST_F(VkPositiveLayerTest, StencilLoadOp) { - TEST_DESCRIPTION("Create a stencil-only attachment with a LOAD_OP set to CLEAR. stencil[Load|Store]Op used to be ignored."); - VkResult result = VK_SUCCESS; - ASSERT_NO_FATAL_FAILURE(Init()); - auto depth_format = FindSupportedDepthStencilFormat(gpu()); - if (!depth_format) { - printf("%s No Depth + Stencil format found. Skipped.\n", kSkipPrefix); - return; - } - VkImageFormatProperties formatProps; - vkGetPhysicalDeviceImageFormatProperties(gpu(), depth_format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0, - &formatProps); - if (formatProps.maxExtent.width < 100 || formatProps.maxExtent.height < 100) { - printf("%s Image format max extent is too small.\n", kSkipPrefix); - return; - } - - VkFormat depth_stencil_fmt = depth_format; - m_depthStencil->Init(m_device, 100, 100, depth_stencil_fmt, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - VkAttachmentDescription att = {}; - VkAttachmentReference ref = {}; - att.format = depth_stencil_fmt; - att.samples = VK_SAMPLE_COUNT_1_BIT; - att.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - att.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - att.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - att.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - att.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - att.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkClearValue clear; - clear.depthStencil.depth = 1.0; - clear.depthStencil.stencil = 0; - ref.attachment = 0; - ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.flags = 0; - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = NULL; - subpass.colorAttachmentCount = 0; - subpass.pColorAttachments = NULL; - subpass.pResolveAttachments = NULL; - subpass.pDepthStencilAttachment = &ref; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = NULL; - - VkRenderPass rp; - VkRenderPassCreateInfo rp_info = {}; - rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rp_info.attachmentCount = 1; - rp_info.pAttachments = &att; - rp_info.subpassCount = 1; - rp_info.pSubpasses = &subpass; - result = vkCreateRenderPass(device(), &rp_info, NULL, &rp); - ASSERT_VK_SUCCESS(result); - - VkImageView *depthView = m_depthStencil->BindInfo(); - VkFramebufferCreateInfo fb_info = {}; - fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fb_info.pNext = NULL; - fb_info.renderPass = rp; - fb_info.attachmentCount = 1; - fb_info.pAttachments = depthView; - fb_info.width = 100; - fb_info.height = 100; - fb_info.layers = 1; - VkFramebuffer fb; - result = vkCreateFramebuffer(device(), &fb_info, NULL, &fb); - ASSERT_VK_SUCCESS(result); - - VkRenderPassBeginInfo rpbinfo = {}; - rpbinfo.clearValueCount = 1; - rpbinfo.pClearValues = &clear; - rpbinfo.pNext = NULL; - rpbinfo.renderPass = rp; - rpbinfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - rpbinfo.renderArea.extent.width = 100; - rpbinfo.renderArea.extent.height = 100; - rpbinfo.renderArea.offset.x = 0; - rpbinfo.renderArea.offset.y = 0; - rpbinfo.framebuffer = fb; - - VkFenceObj fence; - fence.init(*m_device, VkFenceObj::create_info()); - ASSERT_TRUE(fence.initialized()); - - m_commandBuffer->begin(); - m_commandBuffer->BeginRenderPass(rpbinfo); - m_commandBuffer->EndRenderPass(); - m_commandBuffer->end(); - m_commandBuffer->QueueCommandBuffer(fence); - - VkImageObj destImage(m_device); - destImage.Init(100, 100, 1, depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - VK_IMAGE_TILING_OPTIMAL, 0); - VkImageMemoryBarrier barrier = {}; - VkImageSubresourceRange range; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; - barrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier.image = m_depthStencil->handle(); - range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - range.baseMipLevel = 0; - range.levelCount = 1; - range.baseArrayLayer = 0; - range.layerCount = 1; - barrier.subresourceRange = range; - fence.wait(VK_TRUE, UINT64_MAX); - VkCommandBufferObj cmdbuf(m_device, m_commandPool); - cmdbuf.begin(); - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, - &barrier); - barrier.srcAccessMask = 0; - barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier.image = destImage.handle(); - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, - &barrier); - VkImageCopy cregion; - cregion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - cregion.srcSubresource.mipLevel = 0; - cregion.srcSubresource.baseArrayLayer = 0; - cregion.srcSubresource.layerCount = 1; - cregion.srcOffset.x = 0; - cregion.srcOffset.y = 0; - cregion.srcOffset.z = 0; - cregion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - cregion.dstSubresource.mipLevel = 0; - cregion.dstSubresource.baseArrayLayer = 0; - cregion.dstSubresource.layerCount = 1; - cregion.dstOffset.x = 0; - cregion.dstOffset.y = 0; - cregion.dstOffset.z = 0; - cregion.extent.width = 100; - cregion.extent.height = 100; - cregion.extent.depth = 1; - cmdbuf.CopyImage(m_depthStencil->handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, destImage.handle(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); - cmdbuf.end(); - - VkSubmitInfo submit_info; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.pNext = NULL; - submit_info.waitSemaphoreCount = 0; - submit_info.pWaitSemaphores = NULL; - submit_info.pWaitDstStageMask = NULL; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &cmdbuf.handle(); - submit_info.signalSemaphoreCount = 0; - submit_info.pSignalSemaphores = NULL; + m_commandBuffer->begin(); - m_errorMonitor->ExpectSuccess(); - vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); + VkImageMemoryBarrier imb = {}; + imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imb.pNext = nullptr; + imb.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + imb.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + imb.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + imb.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imb.srcQueueFamilyIndex = 0; + imb.dstQueueFamilyIndex = 0; + imb.image = image.handle(); + imb.subresourceRange.aspectMask = 0x6; + imb.subresourceRange.baseMipLevel = 0; + imb.subresourceRange.levelCount = 0x1; + imb.subresourceRange.baseArrayLayer = 0; + imb.subresourceRange.layerCount = 0x1; + + vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, &imb); + + m_commandBuffer->end(); + m_commandBuffer->QueueCommandBuffer(false); m_errorMonitor->VerifyNotFound(); - vkQueueWaitIdle(m_device->m_queue); - vkDestroyRenderPass(m_device->device(), rp, nullptr); vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyRenderPass(m_device->device(), rp, nullptr); + vkDestroyImageView(m_device->device(), view, nullptr); } // This is a positive test. No errors should be generated. @@ -28796,154 +30242,6 @@ TEST_F(VkPositiveLayerTest, TwoSubmitInfosWithSemaphoreOneQueueSubmitsOneFence) m_errorMonitor->VerifyNotFound(); } -TEST_F(VkPositiveLayerTest, RenderPassSecondaryCommandBuffersMultipleTimes) { - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(Init()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - m_commandBuffer->begin(); - - vkCmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); - vkCmdEndRenderPass(m_commandBuffer->handle()); - m_errorMonitor->VerifyNotFound(); - vkCmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - m_errorMonitor->VerifyNotFound(); - vkCmdEndRenderPass(m_commandBuffer->handle()); - m_errorMonitor->VerifyNotFound(); - - m_commandBuffer->end(); - m_errorMonitor->VerifyNotFound(); -} - -TEST_F(VkPositiveLayerTest, ValidRenderPassAttachmentLayoutWithLoadOp) { - TEST_DESCRIPTION( - "Positive test where we create a renderpass with an attachment that uses LOAD_OP_CLEAR, the first subpass has a valid " - "layout, and a second subpass then uses a valid *READ_ONLY* layout."); - m_errorMonitor->ExpectSuccess(); - ASSERT_NO_FATAL_FAILURE(Init()); - auto depth_format = FindSupportedDepthStencilFormat(gpu()); - if (!depth_format) { - printf("%s No Depth + Stencil format found. Skipped.\n", kSkipPrefix); - return; - } - - VkAttachmentReference attach[2] = {}; - attach[0].attachment = 0; - attach[0].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attach[1].attachment = 0; - attach[1].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; - VkSubpassDescription subpasses[2] = {}; - // First subpass clears DS attach on load - subpasses[0].pDepthStencilAttachment = &attach[0]; - // 2nd subpass reads in DS as input attachment - subpasses[1].inputAttachmentCount = 1; - subpasses[1].pInputAttachments = &attach[1]; - VkAttachmentDescription attach_desc = {}; - attach_desc.format = depth_format; - attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; - attach_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attach_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attach_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attach_desc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attach_desc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; - VkRenderPassCreateInfo rpci = {}; - rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rpci.attachmentCount = 1; - rpci.pAttachments = &attach_desc; - rpci.subpassCount = 2; - rpci.pSubpasses = subpasses; - - // Now create RenderPass and verify no errors - VkRenderPass rp; - vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); - m_errorMonitor->VerifyNotFound(); - - vkDestroyRenderPass(m_device->device(), rp, NULL); -} - -TEST_F(VkPositiveLayerTest, RenderPassDepthStencilLayoutTransition) { - TEST_DESCRIPTION( - "Create a render pass with depth-stencil attachment where layout transition from UNDEFINED TO DS_READ_ONLY_OPTIMAL is set " - "by render pass and verify that transition has correctly occurred at queue submit time with no validation errors."); - - ASSERT_NO_FATAL_FAILURE(Init()); - auto depth_format = FindSupportedDepthStencilFormat(gpu()); - if (!depth_format) { - printf("%s No Depth + Stencil format found. Skipped.\n", kSkipPrefix); - return; - } - VkImageFormatProperties format_props; - vkGetPhysicalDeviceImageFormatProperties(gpu(), depth_format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0, &format_props); - if (format_props.maxExtent.width < 32 || format_props.maxExtent.height < 32) { - printf("%s Depth extent too small, RenderPassDepthStencilLayoutTransition skipped.\n", kSkipPrefix); - return; - } - - m_errorMonitor->ExpectSuccess(); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - // A renderpass with one depth/stencil attachment. - VkAttachmentDescription attachment = {0, - depth_format, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - - VkAttachmentReference att_ref = {0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, &att_ref, 0, nullptr}; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 0, nullptr}; - - VkRenderPass rp; - VkResult err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - ASSERT_VK_SUCCESS(err); - // A compatible ds image. - VkImageObj image(m_device); - image.Init(32, 32, 1, depth_format, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); - ASSERT_TRUE(image.initialized()); - - VkImageViewCreateInfo ivci = { - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - nullptr, - 0, - image.handle(), - VK_IMAGE_VIEW_TYPE_2D, - depth_format, - {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY}, - {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}, - }; - VkImageView view; - err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); - ASSERT_VK_SUCCESS(err); - - VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1}; - VkFramebuffer fb; - err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); - ASSERT_VK_SUCCESS(err); - - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; - m_commandBuffer->begin(); - vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); - vkCmdEndRenderPass(m_commandBuffer->handle()); - m_commandBuffer->end(); - m_commandBuffer->QueueCommandBuffer(false); - m_errorMonitor->VerifyNotFound(); - - // Cleanup - vkDestroyImageView(m_device->device(), view, NULL); - vkDestroyRenderPass(m_device->device(), rp, NULL); - vkDestroyFramebuffer(m_device->device(), fb, NULL); -} - TEST_F(VkPositiveLayerTest, CreatePipelineAttribMatrixType) { TEST_DESCRIPTION("Test that pipeline validation accepts matrices passed as vertex attributes"); m_errorMonitor->ExpectSuccess(); @@ -30852,86 +32150,6 @@ TEST_F(VkPositiveLayerTest, ExternalMemory) { m_errorMonitor->VerifyNotFound(); } -TEST_F(VkLayerTest, AMDMixedAttachmentSamplesValidateRenderPass) { - TEST_DESCRIPTION("Verify error messages for supported and unsupported sample counts in render pass attachments."); - - ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor)); - if (DeviceExtensionSupported(gpu(), nullptr, VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME)) { - m_device_extension_names.push_back(VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME); - } else { - printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME); - return; - } - ASSERT_NO_FATAL_FAILURE(InitState()); - - m_errorMonitor->ExpectSuccess(); - - std::vector attachments; - - { - VkAttachmentDescription att = {}; - att.format = VK_FORMAT_R8G8B8A8_UNORM; - att.samples = VK_SAMPLE_COUNT_1_BIT; - att.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - att.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - att.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - att.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - att.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - att.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - attachments.push_back(att); - - att.format = VK_FORMAT_D16_UNORM; - att.samples = VK_SAMPLE_COUNT_4_BIT; - att.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - att.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - att.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - att.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - att.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - att.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - attachments.push_back(att); - } - - VkAttachmentReference color_ref = {}; - color_ref.attachment = 0; - color_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkAttachmentReference depth_ref = {}; - depth_ref.attachment = 1; - depth_ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_ref; - subpass.pDepthStencilAttachment = &depth_ref; - - VkRenderPassCreateInfo rp_info = {}; - rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rp_info.attachmentCount = attachments.size(); - rp_info.pAttachments = attachments.data(); - rp_info.subpassCount = 1; - rp_info.pSubpasses = &subpass; - - vkCreateRenderPass(device(), &rp_info, NULL, &m_renderPass); - m_errorMonitor->VerifyNotFound(); - - // Expect an error message for invalid sample counts - - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubpassDescription-pColorAttachments-01506"); - - attachments[0].samples = VK_SAMPLE_COUNT_4_BIT; - attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; - - { - VkRenderPass render_pass; - VkResult err = vkCreateRenderPass(device(), &rp_info, NULL, &render_pass); - m_errorMonitor->VerifyFound(); - ASSERT_NE(err, VK_SUCCESS); - } -} - TEST_F(VkLayerTest, AMDMixedAttachmentSamplesValidateGraphicsPipeline) { TEST_DESCRIPTION("Verify an error message for an incorrect graphics pipeline rasterization sample count.");