| /* |
| * Copyright (c) 2015-2021 The Khronos Group Inc. |
| * Copyright (c) 2015-2021 Valve Corporation |
| * Copyright (c) 2015-2021 LunarG, Inc. |
| * Copyright (c) 2015-2021 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 |
| * |
| * Author: Chia-I Wu <olvaffe@gmail.com> |
| * Author: Chris Forbes <chrisf@ijw.co.nz> |
| * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> |
| * Author: Mark Lobodzinski <mark@lunarg.com> |
| * Author: Mike Stroyan <mike@LunarG.com> |
| * Author: Tobin Ehlis <tobine@google.com> |
| * Author: Tony Barbour <tony@LunarG.com> |
| * Author: Cody Northrop <cnorthrop@google.com> |
| * Author: Dave Houlton <daveh@lunarg.com> |
| * Author: Jeremy Kniager <jeremyk@lunarg.com> |
| * Author: Shannon McPherson <shannon@lunarg.com> |
| * Author: John Zulauf <jzulauf@lunarg.com> |
| */ |
| |
| #include "../layer_validation_tests.h" |
| #include "vk_extension_helper.h" |
| |
| #include <algorithm> |
| #include <array> |
| #include <chrono> |
| #include <memory> |
| #include <mutex> |
| #include <thread> |
| |
| #include "cast_utils.h" |
| |
| // |
| // POSITIVE VALIDATION TESTS |
| // |
| // These tests do not expect to encounter ANY validation errors pass only if this is true |
| |
| 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(); |
| vk::CreateRenderPass(m_device->device(), &rpci, nullptr, &rp); |
| m_errorMonitor->VerifyNotFound(); |
| vk::DestroyRenderPass(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 = vk::CreateRenderPass(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 = vk::CreateImageView(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 = vk::CreateFramebuffer(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(); |
| vk::CmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); |
| vk::CmdEndRenderPass(m_commandBuffer->handle()); |
| vk::CmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); |
| |
| m_errorMonitor->VerifyNotFound(); |
| |
| vk::CmdEndRenderPass(m_commandBuffer->handle()); |
| m_commandBuffer->end(); |
| |
| vk::DestroyFramebuffer(m_device->device(), fb, nullptr); |
| vk::DestroyRenderPass(m_device->device(), rp, nullptr); |
| vk::DestroyImageView(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; |
| vk::CreateRenderPass(m_device->device(), &rpci, NULL, &rp); |
| m_errorMonitor->VerifyNotFound(); |
| |
| vk::DestroyRenderPass(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 = vk::CreateRenderPass(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 = vk::CreateFramebuffer(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(); |
| vk::CmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); |
| |
| image.ImageMemoryBarrier(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); |
| |
| vk::CmdEndRenderPass(m_commandBuffer->handle()); |
| m_errorMonitor->VerifyNotFound(); |
| m_commandBuffer->end(); |
| |
| vk::DestroyFramebuffer(m_device->device(), fb, nullptr); |
| vk::DestroyRenderPass(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"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| if (IsPlatform(kNexusPlayer)) { |
| printf("%s This test should not run on Nexus Player\n", kSkipPrefix); |
| return; |
| } |
| m_errorMonitor->ExpectSuccess(); |
| |
| // 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 = vk::CreateRenderPass(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 = vk::CreateFramebuffer(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(); |
| vk::CmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); |
| vk::CmdEndRenderPass(m_commandBuffer->handle()); |
| m_errorMonitor->VerifyNotFound(); |
| m_commandBuffer->end(); |
| |
| vk::DestroyFramebuffer(m_device->device(), fb, nullptr); |
| vk::DestroyRenderPass(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; |
| vk::GetPhysicalDeviceImageFormatProperties(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 = vk::CreateRenderPass(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 = vk::CreateFramebuffer(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); |
| fence.wait(UINT64_MAX); |
| VkCommandBufferObj cmdbuf(m_device, m_commandPool); |
| cmdbuf.begin(); |
| |
| m_depthStencil->ImageMemoryBarrier(&cmdbuf, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, |
| VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, |
| VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); |
| |
| destImage.ImageMemoryBarrier(&cmdbuf, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, |
| VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, 0, |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); |
| 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(); |
| vk::QueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyNotFound(); |
| |
| vk::QueueWaitIdle(m_device->m_queue); |
| vk::DestroyRenderPass(m_device->device(), rp, nullptr); |
| vk::DestroyFramebuffer(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(); |
| |
| vk::CmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); |
| vk::CmdEndRenderPass(m_commandBuffer->handle()); |
| m_errorMonitor->VerifyNotFound(); |
| vk::CmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); |
| m_errorMonitor->VerifyNotFound(); |
| vk::CmdEndRenderPass(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; |
| vk::GetPhysicalDeviceImageFormatProperties(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 = vk::CreateRenderPass(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 = vk::CreateImageView(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 = vk::CreateFramebuffer(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(); |
| vk::CmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); |
| vk::CmdEndRenderPass(m_commandBuffer->handle()); |
| m_commandBuffer->end(); |
| m_commandBuffer->QueueCommandBuffer(false); |
| m_errorMonitor->VerifyNotFound(); |
| |
| // Cleanup |
| vk::DestroyImageView(m_device->device(), view, NULL); |
| vk::DestroyRenderPass(m_device->device(), rp, NULL); |
| vk::DestroyFramebuffer(m_device->device(), fb, NULL); |
| } |
| |
| TEST_F(VkPositiveLayerTest, DestroyPipelineRenderPass) { |
| TEST_DESCRIPTION("Draw using a pipeline whose create renderPass has been destroyed."); |
| m_errorMonitor->ExpectSuccess(); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| if (IsPlatform(kNexusPlayer)) { |
| printf("%s This test should not run on Nexus Player\n", kSkipPrefix); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| VkResult err; |
| |
| // Create a renderPass that's compatible with Draw-time renderPass |
| VkAttachmentDescription att = {}; |
| att.format = m_render_target_fmt; |
| 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; |
| |
| VkAttachmentReference ref = {}; |
| ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| ref.attachment = 0; |
| |
| m_renderPassClearValues.clear(); |
| VkClearValue clear = {}; |
| clear.color = m_clear_color; |
| |
| VkSubpassDescription subpass = {}; |
| subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; |
| subpass.flags = 0; |
| subpass.inputAttachmentCount = 0; |
| subpass.pInputAttachments = NULL; |
| subpass.colorAttachmentCount = 1; |
| subpass.pColorAttachments = &ref; |
| subpass.pResolveAttachments = NULL; |
| |
| subpass.pDepthStencilAttachment = NULL; |
| subpass.preserveAttachmentCount = 0; |
| subpass.pPreserveAttachments = NULL; |
| |
| 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; |
| |
| VkRenderPass rp; |
| err = vk::CreateRenderPass(device(), &rp_info, NULL, &rp); |
| ASSERT_VK_SUCCESS(err); |
| |
| VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); |
| VkShaderObj fs(m_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); |
| |
| VkPipelineObj pipe(m_device); |
| pipe.AddDefaultColorAttachment(); |
| pipe.AddShader(&vs); |
| pipe.AddShader(&fs); |
| VkViewport viewport = {0.0f, 0.0f, 64.0f, 64.0f, 0.0f, 1.0f}; |
| m_viewports.push_back(viewport); |
| pipe.SetViewport(m_viewports); |
| VkRect2D rect = {{0, 0}, {64, 64}}; |
| m_scissors.push_back(rect); |
| pipe.SetScissor(m_scissors); |
| |
| const VkPipelineLayoutObj pl(m_device); |
| pipe.CreateVKPipeline(pl.handle(), rp); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle()); |
| // Destroy renderPass before pipeline is used in Draw |
| // We delay until after CmdBindPipeline to verify that invalid binding isn't |
| // created between CB & renderPass, which we used to do. |
| vk::DestroyRenderPass(m_device->device(), rp, nullptr); |
| vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); |
| vk::CmdEndRenderPass(m_commandBuffer->handle()); |
| m_commandBuffer->end(); |
| |
| VkSubmitInfo submit_info = {}; |
| submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
| submit_info.commandBufferCount = 1; |
| submit_info.pCommandBuffers = &m_commandBuffer->handle(); |
| vk::QueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyNotFound(); |
| vk::QueueWaitIdle(m_device->m_queue); |
| } |
| |
| TEST_F(VkPositiveLayerTest, ImagelessFramebufferNonZeroBaseMip) { |
| TEST_DESCRIPTION("Use a 1D image view for an imageless framebuffer with base mip level > 0."); |
| m_errorMonitor->ExpectSuccess(); |
| |
| if (!AddRequiredExtensions(VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME)) { |
| printf("%s Instance extensions for %s not supported\n", kSkipPrefix, VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME); |
| return; |
| } |
| |
| auto pd_imageless_fb_features = LvlInitStruct<VkPhysicalDeviceImagelessFramebufferFeaturesKHR>(); |
| pd_imageless_fb_features.imagelessFramebuffer = VK_TRUE; |
| auto pd_features2 = LvlInitStruct<VkPhysicalDeviceFeatures2>(&pd_imageless_fb_features); |
| if (!InitFrameworkAndRetrieveFeatures(pd_features2)) { |
| printf("%s Failed to initialize physical device and query features\n", kSkipPrefix); |
| return; |
| } |
| |
| if (!AreRequestedExtensionsEnabled()) { |
| printf("%s Device extensions for %s not supported\n", kSkipPrefix, VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME); |
| return; |
| } |
| |
| if (pd_imageless_fb_features.imagelessFramebuffer != VK_TRUE) { |
| printf("%s VkPhysicalDeviceImagelessFramebufferFeaturesKHR::imagelessFramebuffer feature not supported\n", kSkipPrefix); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &pd_features2, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)); |
| |
| constexpr uint32_t width = 512; |
| constexpr uint32_t height = 1; |
| VkFormat formats[2] = {VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM}; |
| VkFormat fb_attachments[2] = {VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM}; |
| constexpr uint32_t base_mip = 1; |
| |
| // Create a renderPass with a single attachment |
| VkAttachmentDescription attachment_desc = {}; |
| attachment_desc.format = formats[0]; |
| attachment_desc.samples = VK_SAMPLE_COUNT_1_BIT; |
| attachment_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL; |
| VkAttachmentReference attachment_ref = {}; |
| attachment_ref.layout = VK_IMAGE_LAYOUT_GENERAL; |
| |
| VkSubpassDescription subpass_desc = {}; |
| subpass_desc.colorAttachmentCount = 1; |
| subpass_desc.pColorAttachments = &attachment_ref; |
| |
| VkRenderPassCreateInfo rp_ci = {}; |
| rp_ci.subpassCount = 1; |
| rp_ci.pSubpasses = &subpass_desc; |
| rp_ci.attachmentCount = 1; |
| rp_ci.pAttachments = &attachment_desc; |
| rp_ci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; |
| vk_testing::RenderPass rp(*m_device, rp_ci); |
| |
| auto fb_attachment_image_info = LvlInitStruct<VkFramebufferAttachmentImageInfoKHR>(); |
| fb_attachment_image_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| fb_attachment_image_info.width = width; |
| fb_attachment_image_info.height = height; |
| fb_attachment_image_info.layerCount = 1; |
| fb_attachment_image_info.viewFormatCount = 2; |
| fb_attachment_image_info.pViewFormats = fb_attachments; |
| fb_attachment_image_info.height = 1; |
| fb_attachment_image_info.width = width >> base_mip; |
| |
| auto fb_attachments_ci = LvlInitStruct<VkFramebufferAttachmentsCreateInfoKHR>(); |
| fb_attachments_ci.attachmentImageInfoCount = 1; |
| fb_attachments_ci.pAttachmentImageInfos = &fb_attachment_image_info; |
| |
| auto fb_ci = LvlInitStruct<VkFramebufferCreateInfo>(&fb_attachments_ci); |
| fb_ci.flags = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR; |
| fb_ci.width = width >> base_mip; |
| fb_ci.height = height; |
| fb_ci.layers = 1; |
| fb_ci.attachmentCount = 1; |
| fb_ci.pAttachments = nullptr; |
| fb_ci.renderPass = rp.handle(); |
| vk_testing::Framebuffer fb(*m_device, fb_ci); |
| |
| auto image_ci = LvlInitStruct<VkImageCreateInfo>(); |
| image_ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| image_ci.extent.width = width; |
| image_ci.extent.height = 1; |
| image_ci.extent.depth = 1; |
| image_ci.arrayLayers = 1; |
| image_ci.mipLevels = 2; |
| image_ci.imageType = VK_IMAGE_TYPE_1D; |
| image_ci.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_ci.format = formats[0]; |
| |
| VkImageObj image_object(m_device); |
| image_object.init(&image_ci); |
| VkImage image = image_object.image(); |
| |
| auto image_view_ci = LvlInitStruct<VkImageViewCreateInfo>(); |
| image_view_ci.image = image; |
| image_view_ci.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY; |
| image_view_ci.format = formats[0]; |
| image_view_ci.subresourceRange.layerCount = 1; |
| image_view_ci.subresourceRange.levelCount = 1; |
| image_view_ci.subresourceRange.baseMipLevel = base_mip; |
| image_view_ci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| vk_testing::ImageView image_view_obj(*m_device, image_view_ci); |
| VkImageView image_view = image_view_obj.handle(); |
| |
| auto rp_attachment_begin_info = LvlInitStruct<VkRenderPassAttachmentBeginInfoKHR>(); |
| rp_attachment_begin_info.attachmentCount = 1; |
| rp_attachment_begin_info.pAttachments = &image_view; |
| auto rp_begin_info = LvlInitStruct<VkRenderPassBeginInfo>(&rp_attachment_begin_info); |
| rp_begin_info.renderPass = rp.handle(); |
| rp_begin_info.renderArea.extent.width = width >> base_mip; |
| rp_begin_info.renderArea.extent.height = height; |
| rp_begin_info.framebuffer = fb.handle(); |
| |
| VkCommandBufferBeginInfo cmd_begin_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, |
| VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, nullptr}; |
| |
| m_commandBuffer->begin(&cmd_begin_info); |
| vk::CmdBeginRenderPass(m_commandBuffer->handle(), &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE); |
| } |
| |
| TEST_F(VkPositiveLayerTest, RenderPassValidStages) { |
| TEST_DESCRIPTION("Create render pass with valid stages"); |
| |
| bool rp2_supported = InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| if (rp2_supported) m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| if (rp2_supported) rp2_supported = CheckCreateRenderPass2Support(this, m_device_extension_names); |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| VkSubpassDescription sci[2] = {}; |
| sci[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; |
| sci[1].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; |
| |
| VkSubpassDependency dependency = {}; |
| // to be filled later by tests |
| |
| VkRenderPassCreateInfo rpci = {}; |
| rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; |
| rpci.subpassCount = 2; |
| rpci.pSubpasses = sci; |
| rpci.dependencyCount = 1; |
| rpci.pDependencies = &dependency; |
| |
| const VkPipelineStageFlags kGraphicsStages = |
| VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | 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_FRAGMENT_SHADER_BIT | |
| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; |
| |
| dependency.srcSubpass = 0; |
| dependency.dstSubpass = 1; |
| dependency.srcStageMask = kGraphicsStages; |
| dependency.dstStageMask = kGraphicsStages; |
| PositiveTestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2_supported); |
| |
| dependency.srcSubpass = VK_SUBPASS_EXTERNAL; |
| dependency.dstSubpass = 0; |
| dependency.srcStageMask = kGraphicsStages | VK_PIPELINE_STAGE_HOST_BIT; |
| dependency.dstStageMask = kGraphicsStages; |
| PositiveTestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2_supported); |
| |
| dependency.srcSubpass = 0; |
| dependency.dstSubpass = VK_SUBPASS_EXTERNAL; |
| dependency.srcStageMask = kGraphicsStages; |
| dependency.dstStageMask = VK_PIPELINE_STAGE_HOST_BIT; |
| PositiveTestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2_supported); |
| } |