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..e0824ae1050 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 \ @@ -115,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 \ @@ -137,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/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/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', 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 36f42572329..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()); @@ -4875,9 +4764,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 +4820,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 +4832,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 +5192,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 +5246,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 +5264,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(); @@ -5394,143 +5283,280 @@ 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_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}; + + 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, @@ -5573,98 +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-VkAttachmentDescription-samples-parameter"); - 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; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkAttachmentDescription-samples-parameter"); - 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(); + // 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; - attachments[subpass.pColorAttachments[1].attachment].samples = VK_SAMPLE_COUNT_1_BIT; // avoid mismatch (00337) - 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; - attachments[subpass.pColorAttachments[1].attachment].samples = VK_SAMPLE_COUNT_4_BIT; + 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}; @@ -5680,101 +5728,2098 @@ 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); - // Create new renderpass with alternate attachment format from fb - attach_desc.format = VK_FORMAT_R8G8B8A8_UNORM; - subpass.pDepthStencilAttachment = NULL; - subpass.pColorAttachments = &attach; - err = vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); - ASSERT_VK_SUCCESS(err); + 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; + subpass.pDepthStencilAttachment = NULL; + subpass.pColorAttachments = &attach; + err = vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); + ASSERT_VK_SUCCESS(err); // Cause error due to mis-matched formats between rp & fb // rp attachment 0 now has RGBA8 but corresponding fb attach is BGRA8 @@ -7738,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()); @@ -12031,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) { @@ -12487,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, @@ -14610,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"); @@ -19754,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, @@ -26898,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 " @@ -27014,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."); @@ -27196,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. @@ -28792,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(); @@ -30848,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.");