Merge remote-tracking branch 'aosp/Vulkan-ValidationLayers-upstream-master' into 20181031-merge-vulkan_update
Change-Id: Ib0b60317d7438a2fb6408162098bc839656d2f54
diff --git a/build-android/cmake/layerlib/CMakeLists.txt b/build-android/cmake/layerlib/CMakeLists.txt
index e9abd5c..69754b8 100644
--- a/build-android/cmake/layerlib/CMakeLists.txt
+++ b/build-android/cmake/layerlib/CMakeLists.txt
@@ -62,6 +62,7 @@
-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 7dd51bc..26b237b 100644
--- a/build-android/jni/Android.mk
+++ b/build-android/jni/Android.mk
@@ -39,6 +39,7 @@
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 @@
$(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 @@
$(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 ebba94f..5fd5b44 100644
--- a/layers/CMakeLists.txt
+++ b/layers/CMakeLists.txt
@@ -178,7 +178,7 @@
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 d48a0db..bb7edf7 100644
--- a/layers/buffer_validation.cpp
+++ b/layers/buffer_validation.cpp
@@ -319,13 +319,116 @@
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 @@
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 @@
}
}
}
+
+ 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 @@
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 @@
// 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 @@
// 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 @@
// Track when we're observing the first use of an attachment
std::vector<bool> 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 @@
"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 @@
// 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 @@
}
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 @@
}
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 @@
"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 @@
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 @@
"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 @@
// 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 @@
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 @@
}
// 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 @@
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 7c46f78..9878978 100644
--- a/layers/buffer_validation.h
+++ b/layers/buffer_validation.h
@@ -102,11 +102,12 @@
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 @@
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 @@
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 0000000..ca3bbcd
--- /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 <string.h>
+
+#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<VkRenderPassMultiviewCreateInfo>(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<VkRenderPassInputAttachmentAspectCreateInfo>(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 0000000..8e7f0f9
--- /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 b98c66e..1af98db 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -61,6 +61,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"
@@ -1070,7 +1071,7 @@
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;
@@ -1275,7 +1276,7 @@
const auto &binding_req_map = reduced_map.Map();
// Bind this set and its active descriptor resources to the command buffer
- descriptor_set->BindCommandBuffer(cb_state, binding_req_map);
+ descriptor_set->UpdateDrawState(cb_state, binding_req_map);
// For given active slots record updated images & buffers
descriptor_set->GetStorageUpdates(binding_req_map, &cb_state->updateBuffers, &cb_state->updateImages);
}
@@ -1735,7 +1736,8 @@
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.");
@@ -1798,6 +1800,7 @@
{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"},
@@ -1834,9 +1837,11 @@
{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"
// },
@@ -7503,14 +7508,6 @@
UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point);
UpdateResourceTrackingOnDraw(cb_state);
cb_state->hasDrawCmd = true;
-
- // Add descriptor image/CIS layouts to CB layout map
- auto &desc_sets = cb_state->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].boundDescriptorSets;
- for (auto &desc : desc_sets) {
- if (desc) {
- desc->UpdateDSImageLayoutState(cb_state);
- }
- }
}
static bool PreCallValidateCmdDraw(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
@@ -8096,10 +8093,80 @@
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);
@@ -8174,9 +8241,10 @@
// 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<uint32_t> &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<uint32_t> &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];
@@ -9392,7 +9460,7 @@
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;
@@ -9434,7 +9502,7 @@
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",
@@ -9661,11 +9729,11 @@
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<DAGNode> &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;
}
@@ -9773,7 +9841,7 @@
// Find for each attachment the subpasses that use them.
unordered_set<uint32_t> 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;
@@ -9809,7 +9877,7 @@
}
// 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;
@@ -9832,7 +9900,7 @@
// 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);
}
@@ -9840,7 +9908,8 @@
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);
@@ -9848,23 +9917,128 @@
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);
@@ -9895,12 +10069,17 @@
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;
@@ -9933,31 +10112,35 @@
}
}
-static bool AddAttachmentUse(const layer_data *dev_data, uint32_t subpass, std::vector<uint8_t> &attachment_uses,
- std::vector<VkImageLayout> &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<uint8_t> &attachment_uses, std::vector<VkImageLayout> &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;
@@ -9966,139 +10149,235 @@
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<uint8_t> attachment_uses(pCreateInfo->attachmentCount);
std::vector<VkImageLayout> 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;
}
@@ -10109,44 +10388,151 @@
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)) {
- 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 = 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, device, pCreateInfo);
+ 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<VkRenderPassMultiviewCreateInfo>(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-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<VkRenderPassInputAttachmentAspectCreateInfo>(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 |= ValidateCreateRenderPass(dev_data, device, RENDER_PASS_VERSION_1, render_pass->createInfo.ptr(), render_pass);
}
return skip;
}
@@ -10155,12 +10541,12 @@
// 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_STATE> &&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);
@@ -10184,11 +10570,13 @@
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<RENDER_PASS_STATE>(pCreateInfo);
unique_lock_t lock(global_lock);
+
skip = PreCallValidateCreateRenderPass(dev_data, device, pCreateInfo, render_pass.get());
lock.unlock();
@@ -10200,7 +10588,38 @@
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<RENDER_PASS_STATE>(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;
}
@@ -10249,14 +10668,49 @@
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<VkRenderPassSampleLocationsBeginInfoEXT>(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,
@@ -10268,36 +10722,45 @@
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;
@@ -10323,33 +10786,63 @@
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;
}
@@ -10366,7 +10859,7 @@
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();
@@ -10380,21 +10873,54 @@
}
}
-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;
}
@@ -10412,7 +10938,27 @@
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();
@@ -14366,6 +14912,10 @@
{"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 f471d24..d90f503 100644
--- a/layers/core_validation_types.h
+++ b/layers/core_validation_types.h
@@ -29,6 +29,7 @@
#include "vk_layer_logging.h"
#include "vk_object_types.h"
#include "vk_extension_helper.h"
+#include "convert_to_renderpass2.h"
#include <atomic>
#include <functional>
#include <map>
@@ -413,12 +414,13 @@
struct RENDER_PASS_STATE : public BASE_NODE {
VkRenderPass renderPass;
- safe_VkRenderPassCreateInfo createInfo;
+ safe_VkRenderPassCreateInfo2KHR createInfo;
std::vector<std::vector<uint32_t>> self_dependencies;
std::vector<DAGNode> subpassToNode;
std::unordered_map<uint32_t, bool> 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
@@ -429,6 +431,7 @@
CMD_NONE,
CMD_BEGINQUERY,
CMD_BEGINRENDERPASS,
+ CMD_BEGINRENDERPASS2KHR,
CMD_BINDDESCRIPTORSETS,
CMD_BINDINDEXBUFFER,
CMD_BINDPIPELINE,
@@ -463,9 +466,11 @@
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,
@@ -1101,6 +1106,8 @@
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/descriptor_sets.cpp b/layers/descriptor_sets.cpp
index a3b7030..7d8b2d8 100644
--- a/layers/descriptor_sets.cpp
+++ b/layers/descriptor_sets.cpp
@@ -1168,11 +1168,15 @@
}
}
-// Bind cb_node to this set and this set to cb_node.
+// Update the drawing state for the affected descriptors.
+// Set cb_node to this set and this set to cb_node.
+// Add the bindings of the descriptor
+// Set the layout based on the current descriptor layout (will mask subsequent layer mismatch errors)
+// TODO: Modify the UpdateDrawState virtural functions to *only* set initial layout and not change layouts
// Prereq: This should be called for a set that has been confirmed to be active for the given cb_node, meaning it's going
// to be used in a draw by the given cb_node
-void cvdescriptorset::DescriptorSet::BindCommandBuffer(GLOBAL_CB_NODE *cb_node,
- const std::map<uint32_t, descriptor_req> &binding_req_map) {
+void cvdescriptorset::DescriptorSet::UpdateDrawState(GLOBAL_CB_NODE *cb_node,
+ const std::map<uint32_t, descriptor_req> &binding_req_map) {
// bind cb to this descriptor set
cb_bindings.insert(cb_node);
// Add bindings for descriptor set, the set's pool, and individual objects in the set
@@ -1185,25 +1189,7 @@
auto binding = binding_req_pair.first;
auto range = p_layout_->GetGlobalIndexRangeFromBinding(binding);
for (uint32_t i = range.start; i < range.end; ++i) {
- descriptors_[i]->BindCommandBuffer(device_data_, cb_node);
- }
- }
-}
-
-// Update CB layout map with any image/imagesampler descriptor image layouts
-void cvdescriptorset::DescriptorSet::UpdateDSImageLayoutState(GLOBAL_CB_NODE *cb_state) {
- for (auto const &desc : descriptors_) {
- if (desc->updated && (desc->descriptor_class == ImageSampler || desc->descriptor_class == Image)) {
- VkImageView image_view;
- VkImageLayout image_layout;
- if (desc->descriptor_class == ImageSampler) {
- image_view = static_cast<ImageSamplerDescriptor *>(desc.get())->GetImageView();
- image_layout = static_cast<ImageSamplerDescriptor *>(desc.get())->GetImageLayout();
- } else {
- image_view = static_cast<ImageDescriptor *>(desc.get())->GetImageView();
- image_layout = static_cast<ImageDescriptor *>(desc.get())->GetImageLayout();
- }
- SetImageViewLayout(device_data_, cb_state, image_view, image_layout);
+ descriptors_[i]->UpdateDrawState(device_data_, cb_node);
}
}
}
@@ -1491,7 +1477,7 @@
updated = true;
}
-void cvdescriptorset::SamplerDescriptor::BindCommandBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
+void cvdescriptorset::SamplerDescriptor::UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
if (!immutable_) {
auto sampler_state = GetSamplerState(dev_data, sampler_);
if (sampler_state) core_validation::AddCommandBufferBindingSampler(cb_node, sampler_state);
@@ -1530,7 +1516,7 @@
image_layout_ = image_layout;
}
-void cvdescriptorset::ImageSamplerDescriptor::BindCommandBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
+void cvdescriptorset::ImageSamplerDescriptor::UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
// First add binding for any non-immutable sampler
if (!immutable_) {
auto sampler_state = GetSamplerState(dev_data, sampler_);
@@ -1541,6 +1527,7 @@
if (iv_state) {
core_validation::AddCommandBufferBindingImageView(dev_data, cb_node, iv_state);
}
+ SetImageViewLayout(dev_data, cb_node, image_view_, image_layout_);
}
cvdescriptorset::ImageDescriptor::ImageDescriptor(const VkDescriptorType type)
@@ -1565,12 +1552,13 @@
image_layout_ = image_layout;
}
-void cvdescriptorset::ImageDescriptor::BindCommandBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
+void cvdescriptorset::ImageDescriptor::UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
// Add binding for image
auto iv_state = GetImageViewState(dev_data, image_view_);
if (iv_state) {
core_validation::AddCommandBufferBindingImageView(dev_data, cb_node, iv_state);
}
+ SetImageViewLayout(dev_data, cb_node, image_view_, image_layout_);
}
cvdescriptorset::BufferDescriptor::BufferDescriptor(const VkDescriptorType type)
@@ -1602,7 +1590,7 @@
range_ = buff_desc->range_;
}
-void cvdescriptorset::BufferDescriptor::BindCommandBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
+void cvdescriptorset::BufferDescriptor::UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
auto buffer_node = GetBufferState(dev_data, buffer_);
if (buffer_node) core_validation::AddCommandBufferBindingBuffer(dev_data, cb_node, buffer_node);
}
@@ -1623,7 +1611,7 @@
buffer_view_ = static_cast<const TexelDescriptor *>(src)->buffer_view_;
}
-void cvdescriptorset::TexelDescriptor::BindCommandBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
+void cvdescriptorset::TexelDescriptor::UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
auto bv_state = GetBufferViewState(dev_data, buffer_view_);
if (bv_state) {
core_validation::AddCommandBufferBindingBufferView(dev_data, cb_node, bv_state);
diff --git a/layers/descriptor_sets.h b/layers/descriptor_sets.h
index a542ef2..74a3bde 100644
--- a/layers/descriptor_sets.h
+++ b/layers/descriptor_sets.h
@@ -300,7 +300,7 @@
virtual void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) = 0;
virtual void CopyUpdate(const Descriptor *) = 0;
// Create binding between resources of this descriptor and given cb_node
- virtual void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) = 0;
+ virtual void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) = 0;
virtual DescriptorClass GetClass() const { return descriptor_class; };
// Special fast-path check for SamplerDescriptors that are immutable
virtual bool IsImmutableSampler() const { return false; };
@@ -322,7 +322,7 @@
SamplerDescriptor(const VkSampler *);
void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
void CopyUpdate(const Descriptor *) override;
- void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) override;
+ void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override;
virtual bool IsImmutableSampler() const override { return immutable_; };
VkSampler GetSampler() const { return sampler_; }
@@ -337,7 +337,7 @@
ImageSamplerDescriptor(const VkSampler *);
void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
void CopyUpdate(const Descriptor *) override;
- void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) override;
+ void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override;
virtual bool IsImmutableSampler() const override { return immutable_; };
VkSampler GetSampler() const { return sampler_; }
VkImageView GetImageView() const { return image_view_; }
@@ -355,7 +355,7 @@
ImageDescriptor(const VkDescriptorType);
void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
void CopyUpdate(const Descriptor *) override;
- void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) override;
+ void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override;
virtual bool IsStorage() const override { return storage_; }
VkImageView GetImageView() const { return image_view_; }
VkImageLayout GetImageLayout() const { return image_layout_; }
@@ -371,7 +371,7 @@
TexelDescriptor(const VkDescriptorType);
void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
void CopyUpdate(const Descriptor *) override;
- void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) override;
+ void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override;
virtual bool IsStorage() const override { return storage_; }
VkBufferView GetBufferView() const { return buffer_view_; }
@@ -385,7 +385,7 @@
BufferDescriptor(const VkDescriptorType);
void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
void CopyUpdate(const Descriptor *) override;
- void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) override;
+ void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override;
virtual bool IsDynamic() const override { return dynamic_; }
virtual bool IsStorage() const override { return storage_; }
VkBuffer GetBuffer() const { return buffer_; }
@@ -408,7 +408,7 @@
}
void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override { updated = true; }
void CopyUpdate(const Descriptor *) override { updated = true; }
- void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) override {}
+ void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override {}
};
class AccelerationStructureDescriptor : public Descriptor {
@@ -419,7 +419,7 @@
}
void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override { updated = true; }
void CopyUpdate(const Descriptor *) override { updated = true; }
- void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) override {}
+ void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override {}
};
// Structs to contain common elements that need to be shared between Validate* and Perform* calls below
@@ -515,10 +515,9 @@
VkDescriptorSet GetSet() const { return set_; };
// Return unordered_set of all command buffers that this set is bound to
std::unordered_set<GLOBAL_CB_NODE *> GetBoundCmdBuffers() const { return cb_bindings; }
- // Bind given cmd_buffer to this descriptor set
- void BindCommandBuffer(GLOBAL_CB_NODE *, const std::map<uint32_t, descriptor_req> &);
- // Update CB image layout map with image/imagesampler descriptor image layouts
- void UpdateDSImageLayoutState(GLOBAL_CB_NODE *);
+ // Bind given cmd_buffer to this descriptor set and
+ // update CB image layout map with image/imagesampler descriptor image layouts
+ void UpdateDrawState(GLOBAL_CB_NODE *, const std::map<uint32_t, descriptor_req> &);
// Track work that has been bound or validated to avoid duplicate work, important when large descriptor arrays
// are present
diff --git a/layers/object_tracker_utils.cpp b/layers/object_tracker_utils.cpp
index 9a71619..e3ac38a 100644
--- a/layers/object_tracker_utils.cpp
+++ b/layers/object_tracker_utils.cpp
@@ -1323,11 +1323,9 @@
instance_data->instance_dispatch_table.GetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, pPropertyCount, pProperties);
lock.lock();
- if (result == VK_SUCCESS) {
- if (pProperties) {
- for (uint32_t i = 0; i < *pPropertyCount; ++i) {
- CreateObject(physicalDevice, pProperties[i].display, kVulkanObjectTypeDisplayKHR, nullptr);
- }
+ if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
+ for (uint32_t i = 0; i < *pPropertyCount; ++i) {
+ CreateObject(physicalDevice, pProperties[i].display, kVulkanObjectTypeDisplayKHR, nullptr);
}
}
lock.unlock();
@@ -1353,13 +1351,12 @@
instance_data->instance_dispatch_table.GetDisplayModePropertiesKHR(physicalDevice, display, pPropertyCount, pProperties);
lock.lock();
- if (result == VK_SUCCESS) {
- if (pProperties) {
- for (uint32_t i = 0; i < *pPropertyCount; ++i) {
- CreateObject(physicalDevice, pProperties[i].displayMode, kVulkanObjectTypeDisplayModeKHR, nullptr);
- }
+ if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
+ for (uint32_t i = 0; i < *pPropertyCount; ++i) {
+ CreateObject(physicalDevice, pProperties[i].displayMode, kVulkanObjectTypeDisplayModeKHR, nullptr);
}
}
+
lock.unlock();
return result;
diff --git a/layers/parameter_validation_utils.cpp b/layers/parameter_validation_utils.cpp
index 29cc315..2bb5400 100644
--- a/layers/parameter_validation_utils.cpp
+++ b/layers/parameter_validation_utils.cpp
@@ -88,6 +88,8 @@
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);
@@ -117,6 +119,8 @@
"LunarG Validation Layer",
};
+enum RenderPassCreateVersion { RENDER_PASS_VERSION_1 = 0, RENDER_PASS_VERSION_2 = 1 };
+
static const int MaxParamCheckerStringLength = 256;
template <typename T>
@@ -757,6 +761,25 @@
return result;
}
+template <typename T>
+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);
@@ -781,22 +804,38 @@
// track the state necessary for checking vkCreateGraphicsPipeline (subpass usage of depth and color attachments)
if (result == VK_SUCCESS) {
std::unique_lock<std::mutex> 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<std::mutex> 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<std::mutex> lock(global_lock);
+ RecordRenderPass(device_data, *pRenderPass, pCreateInfo);
}
}
return result;
@@ -2633,40 +2672,59 @@
return skip;
}
-bool pv_vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
- VkRenderPass *pRenderPass) {
+template <typename RenderPassCreateInfoGeneric>
+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;
@@ -3597,6 +3655,7 @@
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/layers/unique_objects.cpp b/layers/unique_objects.cpp
index 2625a90..0cf31fc 100644
--- a/layers/unique_objects.cpp
+++ b/layers/unique_objects.cpp
@@ -852,7 +852,7 @@
if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
std::lock_guard<std::mutex> lock(global_lock);
for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
- pProperties[idx0].display = WrapNew(pProperties[idx0].display);
+ pProperties[idx0].display = MaybeWrapDisplay(pProperties[idx0].display, my_map_data);
}
}
return result;
@@ -867,7 +867,8 @@
if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
std::lock_guard<std::mutex> lock(global_lock);
for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
- pProperties[idx0].displayProperties.display = WrapNew(pProperties[idx0].displayProperties.display);
+ pProperties[idx0].displayProperties.display =
+ MaybeWrapDisplay(pProperties[idx0].displayProperties.display, my_map_data);
}
}
return result;
@@ -883,7 +884,7 @@
std::lock_guard<std::mutex> lock(global_lock);
for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
VkDisplayKHR &opt_display = pProperties[idx0].currentDisplay;
- if (opt_display) opt_display = WrapNew(opt_display);
+ if (opt_display) opt_display = MaybeWrapDisplay(opt_display, my_map_data);
}
}
return result;
@@ -900,7 +901,7 @@
std::lock_guard<std::mutex> lock(global_lock);
for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
VkDisplayKHR &opt_display = pProperties[idx0].displayPlaneProperties.currentDisplay;
- if (opt_display) opt_display = WrapNew(opt_display);
+ if (opt_display) opt_display = MaybeWrapDisplay(opt_display, my_map_data);
}
}
return result;
@@ -914,10 +915,7 @@
if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pDisplays) {
std::lock_guard<std::mutex> lock(global_lock);
for (uint32_t i = 0; i < *pDisplayCount; ++i) {
- // TODO: this looks like it really wants a /reverse/ mapping. What's going on here?
- auto it = unique_id_mapping.find(reinterpret_cast<const uint64_t &>(pDisplays[i]));
- assert(it != unique_id_mapping.end());
- pDisplays[i] = reinterpret_cast<VkDisplayKHR &>(it->second);
+ if (pDisplays[i]) pDisplays[i] = MaybeWrapDisplay(pDisplays[i], my_map_data);
}
}
return result;
diff --git a/layers/unique_objects.h b/layers/unique_objects.h
index 2fbf68e..753c5b2 100644
--- a/layers/unique_objects.h
+++ b/layers/unique_objects.h
@@ -53,6 +53,7 @@
std::vector<VkDebugReportCallbackEXT> logging_callback;
std::vector<VkDebugUtilsMessengerEXT> logging_messenger;
VkLayerInstanceDispatchTable dispatch_table = {};
+ std::unordered_map<VkDisplayKHR, uint64_t> display_id_reverse_mapping; // Reverse map display handles
// The following are for keeping track of the temporary callbacks that can
// be used in vkCreateInstance and vkDestroyInstance:
@@ -133,4 +134,24 @@
return (HandleType)unique_id;
}
+// Specialized handling for VkDisplayKHR. Adds an entry to enable reverse-lookup.
+// must hold lock!
+VkDisplayKHR WrapDisplay(VkDisplayKHR newlyCreatedHandle, instance_layer_data *map_data) {
+ auto unique_id = global_unique_id++;
+ unique_id_mapping[unique_id] = reinterpret_cast<uint64_t const &>(newlyCreatedHandle);
+ map_data->display_id_reverse_mapping[newlyCreatedHandle] = unique_id;
+ return (VkDisplayKHR)unique_id;
+}
+
+// VkDisplayKHR objects don't have a single point of creation, so we need to see
+// if one already exists in the map before creating another.
+// must hold lock!
+VkDisplayKHR MaybeWrapDisplay(VkDisplayKHR handle, instance_layer_data *map_data) {
+ // See if this display is already known
+ auto it = map_data->display_id_reverse_mapping.find(handle);
+ if (it != map_data->display_id_reverse_mapping.end()) return (VkDisplayKHR)it->second;
+ // Unknown, so wrap
+ return WrapDisplay(handle, map_data);
+}
+
} // namespace unique_objects
diff --git a/scripts/helper_file_generator.py b/scripts/helper_file_generator.py
index 0df8dab..9e095fb 100644
--- a/scripts/helper_file_generator.py
+++ b/scripts/helper_file_generator.py
@@ -272,9 +272,9 @@
decoratedName = '{}/{}'.format(*match.group(2, 3))
else:
# Matches expressions similar to 'latexmath : [dataSize \over 4]'
- match = re.match(r'latexmath\s*\:\s*\[\s*(\w+)\s*\\over\s*(\d+)\s*\]', source)
- name = match.group(1)
- decoratedName = '{}/{}'.format(*match.group(1, 2))
+ match = re.match(r'latexmath\s*\:\s*\[\s*(\\textrm\{)?(\w+)\}?\s*\\over\s*(\d+)\s*\]', source)
+ name = match.group(2)
+ decoratedName = '{}/{}'.format(*match.group(2, 3))
return name, decoratedName
#
# Retrieve the value of the len tag
@@ -296,7 +296,7 @@
result = str(result).replace('::', '->')
return result
#
- # Check if a structure is or contains a dispatchable (dispatchable = True) or
+ # Check if a structure is or contains a dispatchable (dispatchable = True) or
# non-dispatchable (dispatchable = False) handle
def TypeContainsObjectHandle(self, handle_type, dispatchable):
if dispatchable:
@@ -1245,4 +1245,3 @@
return self.GenerateTypeMapHelperHeader()
else:
return 'Bad Helper File Generator Option %s' % self.helper_file_type
-
diff --git a/scripts/parameter_validation_generator.py b/scripts/parameter_validation_generator.py
index 3262050..214695c 100644
--- a/scripts/parameter_validation_generator.py
+++ b/scripts/parameter_validation_generator.py
@@ -146,6 +146,7 @@
'vkDestroyDebugReportCallbackEXT',
'vkCreateCommandPool',
'vkCreateRenderPass',
+ 'vkCreateRenderPass2KHR',
'vkDestroyRenderPass',
'vkCreateDebugUtilsMessengerEXT',
'vkDestroyDebugUtilsMessengerEXT',
@@ -782,9 +783,9 @@
decoratedName = '{}({}/{})'.format(*match.group(1, 2, 3))
else:
# Matches expressions similar to 'latexmath : [dataSize \over 4]'
- match = re.match(r'latexmath\s*\:\s*\[\s*(\w+)\s*\\over\s*(\d+)\s*\]', source)
- name = match.group(1)
- decoratedName = '{}/{}'.format(*match.group(1, 2))
+ match = re.match(r'latexmath\s*\:\s*\[\s*(\\textrm\{)?(\w+)\}?\s*\\over\s*(\d+)\s*\]', source)
+ name = match.group(2)
+ decoratedName = '{}/{}'.format(*match.group(2, 3))
return name, decoratedName
#
# Get the length paramater record for the specified parameter name
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 022c85f..f13d2b5 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -103,6 +103,7 @@
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 511a950..b150118 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -43,6 +43,7 @@
#include "vk_format_utils.h"
#include "vkrenderframework.h"
#include "vk_typemap_helper.h"
+#include "convert_to_renderpass2.h"
#include <algorithm>
#include <cmath>
@@ -4448,121 +4449,9 @@
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.
@@ -4661,7 +4550,7 @@
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());
@@ -4874,9 +4763,9 @@
};
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};
@@ -4930,7 +4819,7 @@
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;
@@ -4942,7 +4831,7 @@
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();
@@ -5302,9 +5191,9 @@
};
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};
@@ -5356,13 +5245,13 @@
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;
@@ -5374,7 +5263,7 @@
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();
@@ -5393,20 +5282,2345 @@
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();
+ }
+
+ 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, 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);
+ }
+
+ 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");
+ }
+
+ // 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};
+
+ // "... 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");
+}
+
+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);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+ PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = 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());
+
+ if (m_device->props.apiVersion < VK_API_VERSION_1_1) {
+ maintenance2Supported = true;
+ }
+
+ if (rp2Supported) {
+ vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
+ }
+
+ 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};
+
+ VkAttachmentReference depth_stencil_ref = {0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_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};
+
+ // 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");
+
+ 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, RenderPassCreateAttachmentUsedTwiceColor) {
+ TEST_DESCRIPTION("Attachment is used simultaneously as two color attachments. This is usually unintended.");
+
+ // 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[] = {
+ {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};
+
+ 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<VkAttachmentDescription> attachments = {
+ // input attachments
+ {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL},
+ // color attachments
+ {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
+ {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
+ // depth attachment
+ {0, VK_FORMAT_D24_UNORM_S8_UINT, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL},
+ // resolve attachment
+ {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
+ // preserve attachments
+ {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
+ };
+
+ std::vector<VkAttachmentReference> input = {
+ {0, VK_IMAGE_LAYOUT_GENERAL},
+ };
+ std::vector<VkAttachmentReference> color = {
+ {1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
+ {2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
+ };
+ VkAttachmentReference depth = {3, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
+ std::vector<VkAttachmentReference> resolve = {
+ {4, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
+ {VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
+ };
+ std::vector<uint32_t> preserve = {5};
+
+ VkSubpassDescription subpass = {0,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ (uint32_t)input.size(),
+ input.data(),
+ (uint32_t)color.size(),
+ color.data(),
+ resolve.data(),
+ &depth,
+ (uint32_t)preserve.size(),
+ preserve.data()};
+
+ VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+ nullptr,
+ 0,
+ (uint32_t)attachments.size(),
+ attachments.data(),
+ 1,
+ &subpass,
+ 0,
+ nullptr};
+
+ // Test too many color attachments
+ {
+ std::vector<VkAttachmentReference> 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;
+
+ 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;
+ depth.attachment = VK_ATTACHMENT_UNUSED; // Avoids triggering 01418
+
+ TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+ "VUID-VkSubpassDescription-pColorAttachments-01417",
+ "VUID-VkSubpassDescription2KHR-pColorAttachments-03069");
+
+ depth.attachment = 3;
+ attachments[subpass.pColorAttachments[1].attachment].samples = attachments[subpass.pColorAttachments[0].attachment].samples;
+
+ // Test sample count mismatch between color buffers and depth buffer
+ attachments[subpass.pDepthStencilAttachment->attachment].samples = VK_SAMPLE_COUNT_8_BIT;
+ subpass.colorAttachmentCount = 1;
+
+ 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;
+
+ TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+ "VUID-VkSubpassDescription-pResolveAttachments-00847",
+ "VUID-VkSubpassDescription2KHR-pResolveAttachments-03065");
+
+ color[0].attachment = 1;
+
+ // Test resolve from a single-sampled color attachment
+ attachments[subpass.pColorAttachments[0].attachment].samples = VK_SAMPLE_COUNT_1_BIT;
+ subpass.colorAttachmentCount = 1; // avoid mismatch (00337), and avoid double report
+ subpass.pDepthStencilAttachment = nullptr; // avoid mismatch (01418)
+
+ TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+ "VUID-VkSubpassDescription-pResolveAttachments-00848",
+ "VUID-VkSubpassDescription2KHR-pResolveAttachments-03066");
+
+ attachments[subpass.pColorAttachments[0].attachment].samples = VK_SAMPLE_COUNT_4_BIT;
+ subpass.colorAttachmentCount = (uint32_t)color.size();
+ subpass.pDepthStencilAttachment = &depth;
+
+ // Test resolve to a multi-sampled resolve attachment
+ attachments[subpass.pResolveAttachments[0].attachment].samples = VK_SAMPLE_COUNT_4_BIT;
+
+ 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;
+
+ 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;
+
+ 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];
+
+ 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
+ input[0].attachment = color[0].attachment;
+ input[0].layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ 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
+ input[0].attachment = depth.attachment;
+ input[0].layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ 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<VkSubpassDescription> subpasses = {subpass, subpass, subpass};
+ subpasses[0].inputAttachmentCount = 0;
+ subpasses[1].inputAttachmentCount = 0;
+ attachments[input[0].attachment].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ VkRenderPassCreateInfo rpci_multipass = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+ nullptr,
+ 0,
+ (uint32_t)attachments.size(),
+ attachments.data(),
+ (uint32_t)subpasses.size(),
+ subpasses.data(),
+ 0,
+ 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, RenderPassCreateAttachmentReferenceInvalidLayout) {
+ TEST_DESCRIPTION("Attachment reference uses PREINITIALIZED or UNDEFINED layouts");
+
+ // 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[] = {
+ {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},
+ };
+
+ VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attach, 1, subpasses, 0, nullptr};
+
+ // Use UNDEFINED layout
+ TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+ "VUID-VkAttachmentReference-layout-00857", "VUID-VkAttachmentReference2KHR-layout-03077");
+
+ // 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");
+}
+
+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);
+ }
+
+ 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<VkAttachmentDescription> 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);
+
+ 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) {
@@ -5505,188 +7719,6 @@
}
}
-TEST_F(VkLayerTest, CreateRenderPassAttachments) {
- TEST_DESCRIPTION(
- "Ensure that CreateRenderPass produces the expected validation errors when a subpass's attachments violate the valid usage "
- "conditions.");
-
- ASSERT_NO_FATAL_FAILURE(Init());
-
- std::vector<VkAttachmentDescription> attachments = {
- // input attachments
- {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
- VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL},
- // color attachments
- {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
- VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
- {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
- VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
- // depth attachment
- {0, VK_FORMAT_D24_UNORM_S8_UINT, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
- VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
- VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL},
- // resolve attachment
- {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
- VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
- // preserve attachments
- {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
- VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
- };
-
- std::vector<VkAttachmentReference> input = {
- {0, VK_IMAGE_LAYOUT_GENERAL},
- };
- std::vector<VkAttachmentReference> color = {
- {1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
- {2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
- };
- VkAttachmentReference depth = {3, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
- std::vector<VkAttachmentReference> resolve = {
- {4, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
- {VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
- };
- std::vector<uint32_t> preserve = {5};
-
- VkSubpassDescription subpass = {0,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- (uint32_t)input.size(),
- input.data(),
- (uint32_t)color.size(),
- color.data(),
- resolve.data(),
- &depth,
- (uint32_t)preserve.size(),
- preserve.data()};
-
- VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
- nullptr,
- 0,
- (uint32_t)attachments.size(),
- attachments.data(),
- 1,
- &subpass,
- 0,
- nullptr};
-
- VkRenderPass rp;
- VkResult err;
- // Test too many color attachments
- {
- std::vector<VkAttachmentReference> 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);
- 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);
- 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);
- attachments[subpass.pDepthStencilAttachment->attachment].samples = attachments[subpass.pColorAttachments[0].attachment].samples;
- // 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);
- 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);
- attachments[subpass.pColorAttachments[0].attachment].samples = VK_SAMPLE_COUNT_4_BIT;
- attachments[subpass.pColorAttachments[1].attachment].samples = VK_SAMPLE_COUNT_4_BIT;
- // 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);
- 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);
- 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);
- 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);
- color[0].attachment = 1;
- // 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);
- input[0].attachment = 0;
- input[0].layout = VK_IMAGE_LAYOUT_GENERAL;
- // 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);
- input[0].attachment = 0;
- input[0].layout = VK_IMAGE_LAYOUT_GENERAL;
- // Test for attachment used first as input with loadOp=CLEAR
- {
- std::vector<VkSubpassDescription> subpasses = {subpass, subpass, subpass};
- subpasses[0].inputAttachmentCount = 0;
- subpasses[1].inputAttachmentCount = 0;
- attachments[input[0].attachment].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- VkRenderPassCreateInfo rpci_multipass = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
- nullptr,
- 0,
- (uint32_t)attachments.size(),
- attachments.data(),
- (uint32_t)subpasses.size(),
- 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);
- 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"
@@ -7737,61 +9769,6 @@
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());
@@ -12038,85 +14015,6 @@
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);
-
- m_errorMonitor->VerifyFound();
-
- vkDestroyRenderPass(m_device->device(), rp, NULL);
-}
-
TEST_F(VkLayerTest, EndCommandBufferWithinRenderPass) {
TEST_DESCRIPTION("End a command buffer with an active render pass");
@@ -12486,63 +14384,6 @@
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,
@@ -14609,7 +16450,7 @@
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");
@@ -19753,51 +21594,6 @@
}
}
-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,
@@ -26897,80 +28693,6 @@
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 "
@@ -27046,86 +28768,7 @@
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);
-
- 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, 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.");
@@ -27225,212 +28868,6 @@
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_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);
-}
-
// This is a positive test. No errors should be generated.
TEST_F(VkPositiveLayerTest, BarrierLayoutToImageUsage) {
TEST_DESCRIPTION("Ensure barriers' new and old VkImageLayout are compatible with their images' VkImageUsageFlags");
@@ -28791,154 +30228,6 @@
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();
@@ -30847,86 +32136,6 @@
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<VkAttachmentDescription> 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.");