blob: e35466d0923fe36057c123498a61b9e1faa320c7 [file]
/*
* Copyright (c) 2023-2026 Valve Corporation
* Copyright (c) 2023-2026 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
#include "../framework/render_pass_helper.h"
#include "utils/convert_utils.h"
class PositiveSubpass : public VkLayerTest {};
TEST_F(PositiveSubpass, SubpassImageBarrier) {
TEST_DESCRIPTION("Subpass with image barrier (self-dependency)");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
const VkAttachmentDescription 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_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL};
const VkSubpassDependency dependency = {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};
const VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_GENERAL};
const VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &ref, 1, &ref, nullptr, nullptr, 0, nullptr};
VkRenderPassCreateInfo rpci = vku::InitStructHelper();
rpci.attachmentCount = 1;
rpci.pAttachments = &attachment;
rpci.subpassCount = 1;
rpci.pSubpasses = &subpass;
rpci.dependencyCount = 1;
rpci.pDependencies = &dependency;
vkt::RenderPass render_pass(*m_device, rpci);
vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView image_view = image.CreateView();
vkt::Framebuffer framebuffer(*m_device, render_pass, 1, &image_view.handle());
// VkImageMemoryBarrier
VkImageMemoryBarrier barrier = vku::InitStructHelper();
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.image = image;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
// VkDependencyInfo with VkImageMemoryBarrier2
const auto safe_barrier2 = ConvertVkImageMemoryBarrierToV2(barrier, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
// Test vkCmdPipelineBarrier subpass barrier
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(render_pass, framebuffer, 32, 32);
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1,
&barrier);
vk::CmdEndRenderPass(m_command_buffer);
m_command_buffer.End();
// Test vkCmdPipelineBarrier2 subpass barrier
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(render_pass, framebuffer, 32, 32);
m_command_buffer.Barrier(*safe_barrier2.ptr(), VK_DEPENDENCY_BY_REGION_BIT);
vk::CmdEndRenderPass(m_command_buffer);
m_command_buffer.End();
}
TEST_F(PositiveSubpass, SubpassWithEventWait) {
TEST_DESCRIPTION("Subpass waits for the event set outside of this subpass");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
const VkAttachmentDescription 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_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL};
const VkSubpassDependency dependency = {VK_SUBPASS_EXTERNAL,
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,
0};
const VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_GENERAL};
const VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &ref, 1, &ref, nullptr, nullptr, 0, nullptr};
VkRenderPassCreateInfo rpci = vku::InitStructHelper();
rpci.attachmentCount = 1;
rpci.pAttachments = &attachment;
rpci.subpassCount = 1;
rpci.pSubpasses = &subpass;
rpci.dependencyCount = 1;
rpci.pDependencies = &dependency;
vkt::RenderPass render_pass(*m_device, rpci);
vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView image_view = image.CreateView();
vkt::Framebuffer framebuffer(*m_device, render_pass, 1, &image_view.handle());
// VkImageMemoryBarrier
VkImageMemoryBarrier barrier = vku::InitStructHelper();
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.image = image;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
// VkDependencyInfo with VkImageMemoryBarrier2
const auto safe_barrier2 = ConvertVkImageMemoryBarrierToV2(barrier, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
VkDependencyInfo dependency_info = vku::InitStructHelper();
dependency_info.dependencyFlags = 0;
dependency_info.imageMemoryBarrierCount = 1;
dependency_info.pImageMemoryBarriers = safe_barrier2.ptr();
// vkCmdWaitEvents inside render pass
{
vkt::Event event(*m_device);
m_command_buffer.Begin();
vk::CmdSetEvent(m_command_buffer, event, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
m_command_buffer.BeginRenderPass(render_pass, framebuffer, 32, 32);
vk::CmdWaitEvents(m_command_buffer, 1, &event.handle(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, nullptr, 0, nullptr, 1, &barrier);
vk::CmdEndRenderPass(m_command_buffer);
m_command_buffer.End();
}
// vkCmdWaitEvents2 inside render pass.
// It's also a regression test for https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/4258
{
vkt::Event event2(*m_device);
m_command_buffer.Begin();
vk::CmdSetEvent2(m_command_buffer, event2, &dependency_info);
m_command_buffer.BeginRenderPass(render_pass, framebuffer, 32, 32);
vk::CmdWaitEvents2(m_command_buffer, 1, &event2.handle(), &dependency_info);
vk::CmdEndRenderPass(m_command_buffer);
m_command_buffer.End();
}
}
TEST_F(PositiveSubpass, InputAttachmentMissingSpecConstant) {
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::shaderInputAttachmentArrayDynamicIndexing);
RETURN_IF_SKIP(Init());
InitRenderTarget();
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM);
rp.AddColorAttachment(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddInputAttachment(1, VK_IMAGE_LAYOUT_GENERAL);
rp.CreateRenderPass();
const char* fsSource = R"glsl(
#version 450
layout (constant_id = 0) const int index = 3; // invalid if left as 3
layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput xs[4];
layout(location=0) out vec4 color;
void main() {
color = subpassLoad(xs[index]);
}
)glsl";
uint32_t data = 0;
VkSpecializationMapEntry entry = {0, 0, sizeof(uint32_t)};
VkSpecializationInfo specialization_info = {1, &entry, sizeof(uint32_t), &data};
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, &specialization_info);
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.renderPass = rp;
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 4, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
pipe.CreateGraphicsPipeline();
}
TEST_F(PositiveSubpass, InputAttachmentMissingSpecConstant2) {
RETURN_IF_SKIP(Init());
InitRenderTarget();
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM);
rp.AddColorAttachment(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddInputAttachment(1, VK_IMAGE_LAYOUT_GENERAL);
rp.CreateRenderPass();
const char* fsSource = R"glsl(
#version 450
layout (constant_id = 0) const int index = 4; // over VkDescriptorSetLayoutBinding::descriptorCount
layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput xs[index];
layout(location=0) out vec4 color;
void main() {
color = subpassLoad(xs[0]);
}
)glsl";
uint32_t data = 2;
VkSpecializationMapEntry entry = {0, 0, sizeof(uint32_t)};
VkSpecializationInfo specialization_info = {1, &entry, sizeof(uint32_t), &data};
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, &specialization_info);
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.renderPass = rp;
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 2, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
pipe.CreateGraphicsPipeline();
}
TEST_F(PositiveSubpass, AccessFlags3) {
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_MAINTENANCE_8_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance8);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkMemoryBarrierAccessFlags3KHR memory_barrier_access_flags = vku::InitStructHelper();
memory_barrier_access_flags.srcAccessMask3 = VK_ACCESS_3_NONE_KHR;
memory_barrier_access_flags.dstAccessMask3 = VK_ACCESS_3_NONE_KHR;
VkMemoryBarrier2 memory_barrier = vku::InitStructHelper(&memory_barrier_access_flags);
VkSubpassDependency2 subpass_dependency = vku::InitStructHelper(&memory_barrier);
subpass_dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkAttachmentDescription2 attach_desc = vku::InitStructHelper();
attach_desc.format = VK_FORMAT_R32_UINT;
attach_desc.samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkAttachmentReference2 reference = vku::InitStructHelper();
reference.attachment = 0;
reference.layout = VK_IMAGE_LAYOUT_GENERAL;
reference.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
VkSubpassDescription2 subpass = vku::InitStructHelper();
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.viewMask = 0;
subpass.inputAttachmentCount = 1;
subpass.pInputAttachments = &reference;
auto rpci2 =
vku::InitStruct<VkRenderPassCreateInfo2>(nullptr, 0u, 1u, &attach_desc, 1u, &subpass, 1u, &subpass_dependency, 0u, nullptr);
vkt::RenderPass rp(*m_device, rpci2);
}
TEST_F(PositiveSubpass, AllCommandsInSubpassDependency) {
TEST_DESCRIPTION("Test ALL_COMMANDS_BIT is allowed in subpass dependency");
RETURN_IF_SKIP(Init());
VkSubpassDependency subpass_dep{};
subpass_dep.srcSubpass = 0;
subpass_dep.dstSubpass = VK_SUBPASS_EXTERNAL;
subpass_dep.srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; // Here!
subpass_dep.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
subpass_dep.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
subpass_dep.dstAccessMask = VK_ACCESS_NONE;
RenderPassSingleSubpass rp(*this);
rp.AddSubpassDependency(subpass_dep);
rp.CreateRenderPass();
}
TEST_F(PositiveSubpass, TopOfPipeInSubpassDependency) {
TEST_DESCRIPTION("Test TOP_OF_PIPE is allowed in subpass dependency");
RETURN_IF_SKIP(Init());
VkSubpassDependency subpass_dep{};
subpass_dep.srcSubpass = VK_SUBPASS_EXTERNAL;
subpass_dep.dstSubpass = 0;
subpass_dep.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
subpass_dep.dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; // Here!
subpass_dep.srcAccessMask = VK_ACCESS_NONE;
subpass_dep.dstAccessMask = VK_ACCESS_NONE;
RenderPassSingleSubpass rp(*this);
rp.AddSubpassDependency(subpass_dep);
rp.CreateRenderPass();
}
TEST_F(PositiveSubpass, BottomOfPipeInSubpassDependency) {
TEST_DESCRIPTION("Test BOTTOM_OF_PIPE is allowed in subpass dependency");
RETURN_IF_SKIP(Init());
VkSubpassDependency subpass_dep{};
subpass_dep.srcSubpass = 0;
subpass_dep.dstSubpass = VK_SUBPASS_EXTERNAL;
subpass_dep.srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; // Here!
subpass_dep.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
subpass_dep.srcAccessMask = VK_ACCESS_NONE;
subpass_dep.dstAccessMask = VK_ACCESS_NONE;
RenderPassSingleSubpass rp(*this);
rp.AddSubpassDependency(subpass_dep);
rp.CreateRenderPass();
}
TEST_F(PositiveSubpass, ColorBlendEnable) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10535");
RETURN_IF_SKIP(Init());
const VkFormat depth_format = FindSupportedDepthStencilFormat(Gpu());
VkAttachmentDescription attach_desc[3];
attach_desc[0].flags = 0;
attach_desc[0].format = VK_FORMAT_R8G8B8A8_UNORM;
attach_desc[0].samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attach_desc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attach_desc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attach_desc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attach_desc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attach_desc[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attach_desc[1] = attach_desc[0];
attach_desc[1].format = depth_format;
attach_desc[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
attach_desc[2] = attach_desc[0];
attach_desc[2].format = VK_FORMAT_R32G32B32A32_UINT;
attach_desc[2].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference color_reference[2] = {};
color_reference[0].attachment = 0;
color_reference[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_reference[1].attachment = 2;
color_reference[1].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference ds_reference = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
VkSubpassDescription subpasses[2] = {};
subpasses[0].colorAttachmentCount = 2;
subpasses[0].pColorAttachments = color_reference;
subpasses[0].pDepthStencilAttachment = &ds_reference;
subpasses[1].colorAttachmentCount = 1;
subpasses[1].pColorAttachments = &color_reference[0];
subpasses[1].pDepthStencilAttachment = &ds_reference;
VkSubpassDependency dependencies[2] = {
{VK_SUBPASS_EXTERNAL, 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},
{0, 1, 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 = vku::InitStructHelper();
rpci.attachmentCount = 3;
rpci.pAttachments = attach_desc;
rpci.subpassCount = 2;
rpci.pSubpasses = subpasses;
rpci.dependencyCount = 2;
rpci.pDependencies = dependencies;
vkt::RenderPass rp(*m_device, rpci);
vkt::Image image_0(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView image_view_0 = image_0.CreateView();
vkt::Image image_1(*m_device, 32, 32, depth_format, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
vkt::ImageView image_view_1 = image_1.CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
vkt::Image image_2(*m_device, 32, 32, VK_FORMAT_R32G32B32A32_UINT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView image_view_2 = image_2.CreateView();
VkImageView fb_attachments[3] = {image_view_0, image_view_1, image_view_2};
vkt::Framebuffer fb(*m_device, rp, 3, fb_attachments);
VkPipelineDepthStencilStateCreateInfo ds_state_ci = vku::InitStructHelper();
ds_state_ci.depthTestEnable = VK_FALSE;
ds_state_ci.stencilTestEnable = VK_FALSE;
VkPipelineColorBlendAttachmentState color_state[2];
color_state[0] = DefaultColorBlendAttachmentState();
color_state[0].blendEnable = VK_FALSE;
color_state[1] = DefaultColorBlendAttachmentState();
color_state[1].blendEnable = VK_FALSE;
CreatePipelineHelper pipe0(*this);
pipe0.gp_ci_.renderPass = rp;
pipe0.gp_ci_.pDepthStencilState = &ds_state_ci;
pipe0.cb_ci_.attachmentCount = 2;
pipe0.cb_ci_.pAttachments = color_state;
pipe0.CreateGraphicsPipeline();
CreatePipelineHelper pipe1(*this);
pipe1.gp_ci_.renderPass = rp;
pipe1.gp_ci_.pDepthStencilState = &ds_state_ci;
pipe1.cb_ci_.attachmentCount = 1;
pipe1.cb_ci_.pAttachments = color_state;
pipe1.gp_ci_.subpass = 1;
pipe1.CreateGraphicsPipeline();
VkClearValue clear_values[3];
memset(clear_values, 0, sizeof(clear_values));
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(rp, fb, 32, 32, 3, clear_values);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe0);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.NextSubpass();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe1);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveSubpass, InputAttachmentLayout) {
TEST_DESCRIPTION("Create renderpass where an input attachment is also uses as another type");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddOptionalExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
const bool rp2_supported = IsExtensionsEnabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
const VkAttachmentDescription attach0 = {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};
const VkAttachmentDescription attach1 = {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};
const VkAttachmentReference ref0 = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
const VkAttachmentReference ref1 = {1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
const VkAttachmentReference inRef0 = {0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
const VkAttachmentReference inRef1 = {1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
// First subpass draws to attachment 0
const VkSubpassDescription subpass0 = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &ref0, nullptr, nullptr, 0, nullptr};
// Second subpass reads attachment 0 as input-attachment, writes to attachment 1
const VkSubpassDescription subpass1 = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &inRef0, 1, &ref1, nullptr, nullptr, 0, nullptr};
// Seconnd subpass reads attachment 1 as input-attachment, writes to attachment 0
const VkSubpassDescription subpass2 = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &inRef1, 1, &ref0, nullptr, nullptr, 0, nullptr};
// Subpass 0 writes attachment 0 as output, subpass 1 reads as input (RAW)
VkSubpassDependency dep0 = {0,
1,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
VK_DEPENDENCY_BY_REGION_BIT};
// Subpass 1 writes attachment 1 as output, subpass 2 reads as input while (RAW)
VkSubpassDependency dep1 = {1,
2,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
VK_DEPENDENCY_BY_REGION_BIT};
// Subpass 1 reads attachment 0 as input, subpass 2 writes output (WAR)
VkSubpassDependency dep2 = {1,
2,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_DEPENDENCY_BY_REGION_BIT};
std::vector<VkAttachmentDescription> attachs = {attach0, attach1};
std::vector<VkSubpassDescription> subpasses = {subpass0, subpass1, subpass2};
std::vector<VkSubpassDependency> deps = {dep0, dep1, dep2};
auto rpci = vku::InitStruct<VkRenderPassCreateInfo>(nullptr, 0u, size32(attachs), attachs.data(), size32(subpasses),
subpasses.data(), size32(deps), deps.data());
// Current setup should be OK -- no attachment is both input and output in same subpass
vkt::RenderPass render_pass(*m_device, rpci);
if (rp2_supported) {
vkt::RenderPass rp2(*m_device, *ConvertVkRenderPassCreateInfoToV2KHR(rpci).ptr());
}
}