blob: 4a5e7ebf0a36df8552050a0d23e49eeec5b46ee1 [file] [log] [blame]
/*
* Copyright (c) 2015-2025 The Khronos Group Inc.
* Copyright (c) 2015-2025 Valve Corporation
* Copyright (c) 2015-2025 LunarG, Inc.
* Copyright (c) 2015-2025 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
*/
#include "../framework/layer_validation_tests.h"
#include "../framework/descriptor_helper.h"
#include "../framework/pipeline_helper.h"
#include "../framework/render_pass_helper.h"
class PositiveSecondaryCommandBuffer : public VkLayerTest {};
TEST_F(PositiveSecondaryCommandBuffer, Barrier) {
TEST_DESCRIPTION("Add a pipeline barrier in a secondary command buffer");
RETURN_IF_SKIP(Init());
// A renderpass with a single subpass that declared a self-dependency
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddColorAttachment(0);
rp.AddSubpassDependency(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT);
rp.CreateRenderPass();
vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
image.SetLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
vkt::ImageView imageView = image.CreateView();
vkt::Framebuffer fb(*m_device, rp, 1, &imageView.handle());
m_command_buffer.Begin();
VkRenderPassBeginInfo rpbi =
vku::InitStruct<VkRenderPassBeginInfo>(nullptr, rp.Handle(), fb.handle(), VkRect2D{{0, 0}, {32u, 32u}}, 0u, nullptr);
vk::CmdBeginRenderPass(m_command_buffer, &rpbi, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
vkt::CommandPool pool(*m_device, m_device->graphics_queue_node_index_, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
vkt::CommandBuffer secondary(*m_device, pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkCommandBufferInheritanceInfo cbii = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
nullptr,
rp,
0,
VK_NULL_HANDLE, // Set to NULL FB handle intentionally to flesh out any errors
VK_FALSE,
0,
0};
VkCommandBufferBeginInfo cbbi = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr,
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT,
&cbii};
vk::BeginCommandBuffer(secondary, &cbbi);
VkMemoryBarrier mem_barrier = vku::InitStructHelper();
mem_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
mem_barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
vk::CmdPipelineBarrier(secondary, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_DEPENDENCY_BY_REGION_BIT, 1, &mem_barrier, 0, nullptr, 0, nullptr);
image.ImageMemoryBarrier(secondary, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
secondary.End();
vk::CmdExecuteCommands(m_command_buffer, 1, &secondary.handle());
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
}
TEST_F(PositiveSecondaryCommandBuffer, ClearAttachmentsCalled) {
TEST_DESCRIPTION(
"This test is to verify that when vkCmdClearAttachments is called by a secondary commandbuffer, the validation layers do "
"not throw an error if the primary commandbuffer begins a renderpass before executing the secondary commandbuffer.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
vkt::CommandBuffer secondary(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkCommandBufferBeginInfo info = vku::InitStructHelper();
VkCommandBufferInheritanceInfo hinfo = vku::InitStructHelper();
info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
info.pInheritanceInfo = &hinfo;
hinfo.renderPass = RenderPass();
hinfo.subpass = 0;
hinfo.framebuffer = Framebuffer();
hinfo.occlusionQueryEnable = VK_FALSE;
hinfo.queryFlags = 0;
hinfo.pipelineStatistics = 0;
secondary.Begin(&info);
VkClearAttachment color_attachment;
color_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
color_attachment.clearValue.color.float32[0] = 0.0;
color_attachment.clearValue.color.float32[1] = 0.0;
color_attachment.clearValue.color.float32[2] = 0.0;
color_attachment.clearValue.color.float32[3] = 0.0;
color_attachment.colorAttachment = 0;
VkClearRect clear_rect = {{{0, 0}, {m_width, m_height}}, 0, 1};
vk::CmdClearAttachments(secondary, 1, &color_attachment, 1, &clear_rect);
secondary.End();
// Modify clear rect here to verify that it doesn't cause validation error
clear_rect = {{{0, 0}, {99999999, 99999999}}, 0, 0};
m_command_buffer.Begin();
vk::CmdBeginRenderPass(m_command_buffer, &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
vk::CmdExecuteCommands(m_command_buffer, 1, &secondary.handle());
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveSecondaryCommandBuffer, ClearAttachmentsCalledWithoutFb) {
TEST_DESCRIPTION(
"Verify calling vkCmdClearAttachments inside secondary commandbuffer without linking framebuffer pointer to"
"inheritance struct");
RETURN_IF_SKIP(Init());
m_depth_stencil_fmt = FindSupportedDepthStencilFormat(Gpu());
m_depthStencil->Init(*m_device, m_width, m_height, 1, m_depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
vkt::ImageView depth_image_view = m_depthStencil->CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
InitRenderTarget(&depth_image_view.handle());
vkt::CommandBuffer secondary(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkCommandBufferInheritanceInfo hinfo = vku::InitStructHelper();
hinfo.renderPass = RenderPass();
VkCommandBufferBeginInfo info = vku::InitStructHelper();
info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
info.pInheritanceInfo = &hinfo;
secondary.Begin(&info);
VkClearAttachment color_attachment = {VK_IMAGE_ASPECT_COLOR_BIT, 0, VkClearValue{}};
VkClearAttachment ds_attachment = {};
ds_attachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
ds_attachment.clearValue.depthStencil.depth = 0.2f;
ds_attachment.clearValue.depthStencil.stencil = 1;
const std::array clear_attachments = {color_attachment, ds_attachment};
VkClearRect clear_rect = {{{0, 0}, {m_width, m_height}}, 0, 1};
vk::CmdClearAttachments(secondary, size32(clear_attachments), clear_attachments.data(), 1, &clear_rect);
secondary.End();
m_command_buffer.Begin();
vk::CmdBeginRenderPass(m_command_buffer, &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
vk::CmdExecuteCommands(m_command_buffer, 1, &secondary.handle());
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveSecondaryCommandBuffer, CommandPoolDeleteWithReferences) {
TEST_DESCRIPTION("Ensure the validation layers bookkeeping tracks the implicit command buffer frees.");
RETURN_IF_SKIP(Init());
VkCommandPoolCreateInfo cmd_pool_info = vku::InitStructHelper();
cmd_pool_info.queueFamilyIndex = m_device->graphics_queue_node_index_;
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
cmd_pool_info.flags = 0;
VkCommandPool secondary_cmd_pool;
VkResult res = vk::CreateCommandPool(*m_device, &cmd_pool_info, NULL, &secondary_cmd_pool);
ASSERT_EQ(VK_SUCCESS, res);
VkCommandBufferAllocateInfo cmdalloc = vkt::CommandBuffer::CreateInfo(secondary_cmd_pool);
cmdalloc.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
VkCommandBuffer secondary_cmds;
res = vk::AllocateCommandBuffers(*m_device, &cmdalloc, &secondary_cmds);
VkCommandBufferInheritanceInfo cmd_buf_inheritance_info = vku::InitStructHelper();
cmd_buf_inheritance_info.renderPass = VK_NULL_HANDLE;
cmd_buf_inheritance_info.subpass = 0;
cmd_buf_inheritance_info.framebuffer = VK_NULL_HANDLE;
cmd_buf_inheritance_info.occlusionQueryEnable = VK_FALSE;
cmd_buf_inheritance_info.queryFlags = 0;
cmd_buf_inheritance_info.pipelineStatistics = 0;
VkCommandBufferBeginInfo secondary_begin = vku::InitStructHelper();
secondary_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
secondary_begin.pInheritanceInfo = &cmd_buf_inheritance_info;
res = vk::BeginCommandBuffer(secondary_cmds, &secondary_begin);
ASSERT_EQ(VK_SUCCESS, res);
vk::EndCommandBuffer(secondary_cmds);
m_command_buffer.Begin();
vk::CmdExecuteCommands(m_command_buffer, 1, &secondary_cmds);
m_command_buffer.End();
// DestroyCommandPool *implicitly* frees the command buffers allocated from it
vk::DestroyCommandPool(*m_device, secondary_cmd_pool, NULL);
// If bookkeeping has been lax, validating the reset will attempt to touch deleted data
res = vk::ResetCommandPool(*m_device, m_command_pool, 0);
ASSERT_EQ(VK_SUCCESS, res);
}
TEST_F(PositiveSecondaryCommandBuffer, ClearColorAttachments) {
TEST_DESCRIPTION("Create a secondary command buffer and record a CmdClearAttachments call into it");
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkCommandBufferAllocateInfo command_buffer_allocate_info = vku::InitStructHelper();
command_buffer_allocate_info.commandPool = m_command_pool;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
command_buffer_allocate_info.commandBufferCount = 1;
VkCommandBuffer secondary_command_buffer;
ASSERT_EQ(VK_SUCCESS, vk::AllocateCommandBuffers(device(), &command_buffer_allocate_info, &secondary_command_buffer));
VkCommandBufferBeginInfo command_buffer_begin_info = vku::InitStructHelper();
VkCommandBufferInheritanceInfo command_buffer_inheritance_info = vku::InitStructHelper();
command_buffer_inheritance_info.renderPass = m_renderPass;
command_buffer_inheritance_info.framebuffer = Framebuffer();
command_buffer_begin_info.flags =
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
command_buffer_begin_info.pInheritanceInfo = &command_buffer_inheritance_info;
vk::BeginCommandBuffer(secondary_command_buffer, &command_buffer_begin_info);
VkClearAttachment color_attachment;
color_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
color_attachment.clearValue.color.float32[0] = 0;
color_attachment.clearValue.color.float32[1] = 0;
color_attachment.clearValue.color.float32[2] = 0;
color_attachment.clearValue.color.float32[3] = 0;
color_attachment.colorAttachment = 0;
VkClearRect clear_rect = {{{0, 0}, {32, 32}}, 0, 1};
vk::CmdClearAttachments(secondary_command_buffer, 1, &color_attachment, 1, &clear_rect);
vk::EndCommandBuffer(secondary_command_buffer);
m_command_buffer.Begin();
vk::CmdBeginRenderPass(m_command_buffer, &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
vk::CmdExecuteCommands(m_command_buffer, 1, &secondary_command_buffer);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveSecondaryCommandBuffer, ImageLayoutTransitions) {
TEST_DESCRIPTION("Perform an image layout transition in a secondary command buffer followed by a transition in the primary.");
RETURN_IF_SKIP(Init());
auto depth_format = FindSupportedDepthStencilFormat(Gpu());
InitRenderTarget();
// Allocate a secondary and primary cmd buffer
VkCommandBufferAllocateInfo command_buffer_allocate_info = vku::InitStructHelper();
command_buffer_allocate_info.commandPool = m_command_pool;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
command_buffer_allocate_info.commandBufferCount = 1;
VkCommandBuffer secondary_command_buffer;
vk::AllocateCommandBuffers(device(), &command_buffer_allocate_info, &secondary_command_buffer);
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
VkCommandBuffer primary_command_buffer;
vk::AllocateCommandBuffers(device(), &command_buffer_allocate_info, &primary_command_buffer);
VkCommandBufferBeginInfo command_buffer_begin_info = vku::InitStructHelper();
VkCommandBufferInheritanceInfo command_buffer_inheritance_info = vku::InitStructHelper();
command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
command_buffer_begin_info.pInheritanceInfo = &command_buffer_inheritance_info;
vk::BeginCommandBuffer(secondary_command_buffer, &command_buffer_begin_info);
vkt::Image image(*m_device, 128, 128, depth_format, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
VkImageMemoryBarrier img_barrier = vku::InitStructHelper();
img_barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
img_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
img_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
img_barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
img_barrier.image = image;
img_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img_barrier.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1};
vk::CmdPipelineBarrier(secondary_command_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0, 0, nullptr,
0, nullptr, 1, &img_barrier);
vk::EndCommandBuffer(secondary_command_buffer);
// Now update primary cmd buffer to execute secondary and transitions image
command_buffer_begin_info.pInheritanceInfo = nullptr;
vk::BeginCommandBuffer(primary_command_buffer, &command_buffer_begin_info);
vk::CmdExecuteCommands(primary_command_buffer, 1, &secondary_command_buffer);
VkImageMemoryBarrier img_barrier2 = vku::InitStructHelper();
img_barrier2.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
img_barrier2.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
img_barrier2.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
img_barrier2.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
img_barrier2.image = image;
img_barrier2.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img_barrier2.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img_barrier2.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1};
vk::CmdPipelineBarrier(primary_command_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0, 0, nullptr,
0, nullptr, 1, &img_barrier2);
vk::EndCommandBuffer(primary_command_buffer);
VkSubmitInfo submit_info = vku::InitStructHelper();
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &primary_command_buffer;
vk::QueueSubmit(m_default_queue->handle(), 1, &submit_info, VK_NULL_HANDLE);
m_device->Wait();
vk::FreeCommandBuffers(device(), m_command_pool, 1, &secondary_command_buffer);
vk::FreeCommandBuffers(device(), m_command_pool, 1, &primary_command_buffer);
}
TEST_F(PositiveSecondaryCommandBuffer, Sync2ImageLayouts) {
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7896
TEST_DESCRIPTION("Test comparison of expected and current layout on the boundary of secondary command buffer");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
vkt::Image image(*m_device, 32, 32, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::ImageView image_view = image.CreateView();
// Main command buffer transitions to READ_ONLY_OPTIMAL
VkImageMemoryBarrier2 layout_transition = vku::InitStructHelper();
layout_transition.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
layout_transition.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
layout_transition.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
layout_transition.newLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL;
layout_transition.image = image;
layout_transition.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
// Secondary command buffer expects sampled image to be in READ_ONLY_OPTIMAL
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT}});
descriptor_set.WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL);
descriptor_set.UpdateDescriptorSets();
const char *cs_source = R"glsl(
#version 450
layout(set=0, binding=0) uniform sampler2D color_image;
void main() {
vec4 data = texture(color_image, vec2(0));
}
)glsl";
CreateComputePipelineHelper cs_pipe(*this);
cs_pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT);
cs_pipe.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&descriptor_set.layout_});
cs_pipe.CreateComputePipeline();
vkt::CommandBuffer secondary(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
secondary.Begin();
vk::CmdBindPipeline(secondary, VK_PIPELINE_BIND_POINT_COMPUTE, cs_pipe);
vk::CmdBindDescriptorSets(secondary, VK_PIPELINE_BIND_POINT_COMPUTE, cs_pipe.pipeline_layout_, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDispatch(secondary, 1, 1, 1);
secondary.End();
m_command_buffer.Begin();
m_command_buffer.Barrier(layout_transition);
vk::CmdExecuteCommands(m_command_buffer, 1, &secondary.handle());
m_command_buffer.End();
}
TEST_F(PositiveSecondaryCommandBuffer, EventStageMask) {
TEST_DESCRIPTION("Check secondary command buffers transfer event data when executed by primary ones");
RETURN_IF_SKIP(Init());
vkt::CommandBuffer commandBuffer(*m_device, m_command_pool);
vkt::CommandBuffer secondary(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
vkt::Event event(*m_device);
secondary.Begin();
vk::CmdSetEvent(secondary, event, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
secondary.End();
commandBuffer.Begin();
vk::CmdExecuteCommands(commandBuffer, 1, &secondary.handle());
vk::CmdWaitEvents(commandBuffer, 1, &event.handle(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0, nullptr, 0, nullptr, 0, nullptr);
commandBuffer.End();
m_default_queue->Submit(commandBuffer);
m_default_queue->Wait();
}
TEST_F(PositiveSecondaryCommandBuffer, EventsIn) {
TEST_DESCRIPTION("Test setting and waiting for an event in a secondary command buffer");
RETURN_IF_SKIP(Init());
vkt::Event event(*m_device);
vkt::CommandBuffer secondary_cb(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
secondary_cb.Begin();
vk::CmdSetEvent(secondary_cb, event, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT);
vk::CmdWaitEvents(secondary_cb, 1, &event.handle(), VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0, nullptr, 0, nullptr, 0, nullptr);
secondary_cb.End();
m_command_buffer.Begin();
vk::CmdExecuteCommands(m_command_buffer, 1, &secondary_cb.handle());
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
}
TEST_F(PositiveSecondaryCommandBuffer, Nested) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_NESTED_COMMAND_BUFFER_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::nestedCommandBuffer);
AddRequiredFeature(vkt::Feature::nestedCommandBufferRendering);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::inheritedQueries);
RETURN_IF_SKIP(Init());
InitRenderTarget();
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_OCCLUSION, 1);
vkt::CommandBuffer secondary1(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
vkt::CommandBuffer secondary2(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkCommandBufferInheritanceRenderingInfo cbiri = vku::InitStructHelper();
cbiri.colorAttachmentCount = 1;
cbiri.pColorAttachmentFormats = &m_render_target_fmt;
cbiri.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkCommandBufferInheritanceInfo cbii = vku::InitStructHelper(&cbiri);
cbii.occlusionQueryEnable = VK_TRUE;
cbii.queryFlags = 0;
VkCommandBufferBeginInfo cbbi = vku::InitStructHelper();
cbbi.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
cbbi.pInheritanceInfo = &cbii;
secondary1.Begin(&cbbi);
secondary1.End();
secondary2.Begin(&cbbi);
vk::CmdBeginQuery(secondary2, query_pool, 0, 0);
vk::CmdExecuteCommands(secondary2, 1u, &secondary1.handle());
vk::CmdEndQuery(secondary2, query_pool, 0);
secondary2.End();
}
TEST_F(PositiveSecondaryCommandBuffer, NestedPrimary) {
TEST_DESCRIPTION("https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/7090");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_NESTED_COMMAND_BUFFER_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::nestedCommandBuffer);
AddRequiredFeature(vkt::Feature::nestedCommandBufferRendering);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::inheritedQueries);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkPhysicalDeviceNestedCommandBufferPropertiesEXT nested_cb_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(nested_cb_props);
if (nested_cb_props.maxCommandBufferNestingLevel != 1) {
GTEST_SKIP() << "needs maxCommandBufferNestingLevel to be 1";
}
vkt::CommandBuffer secondary1(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
vkt::CommandBuffer secondary2(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkCommandBufferInheritanceRenderingInfo cbiri = vku::InitStructHelper();
cbiri.colorAttachmentCount = 1;
cbiri.pColorAttachmentFormats = &m_render_target_fmt;
cbiri.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkCommandBufferInheritanceInfo cbii = vku::InitStructHelper(&cbiri);
cbii.occlusionQueryEnable = VK_TRUE;
cbii.queryFlags = 0;
VkCommandBufferBeginInfo cbbi = vku::InitStructHelper();
cbbi.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
cbbi.pInheritanceInfo = &cbii;
secondary1.Begin(&cbbi);
secondary1.End();
secondary2.Begin(&cbbi);
vk::CmdExecuteCommands(secondary2, 1u, &secondary1.handle());
secondary2.End();
// The primary command buffer doesn't count toward nesting
m_command_buffer.Begin(&cbbi);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
vk::CmdExecuteCommands(m_command_buffer, 1u, &secondary2.handle());
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveSecondaryCommandBuffer, NonNestedWithRenderPassContinue) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9541");
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkCommandBufferInheritanceInfo cbii = vku::InitStructHelper();
cbii.renderPass = RenderPass();
cbii.framebuffer = Framebuffer();
VkCommandBufferBeginInfo cbbi = vku::InitStructHelper();
cbbi.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
cbbi.pInheritanceInfo = &cbii;
vkt::CommandBuffer secondary(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
secondary.Begin(&cbbi);
secondary.End();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
vk::CmdExecuteCommands(m_command_buffer, 1u, &secondary.handle());
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
}
TEST_F(PositiveSecondaryCommandBuffer, NestedDrawWithoutInline) {
TEST_DESCRIPTION("http://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10761");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_NESTED_COMMAND_BUFFER_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::nestedCommandBuffer);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
VkFormat color_format = VK_FORMAT_R8G8B8A8_UNORM;
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &color_format;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.CreateGraphicsPipeline();
VkCommandBufferInheritanceRenderingInfo inheritance_rendering_info = vku::InitStructHelper();
inheritance_rendering_info.flags = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT;
inheritance_rendering_info.colorAttachmentCount = 1;
inheritance_rendering_info.pColorAttachmentFormats = &color_format;
inheritance_rendering_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
const VkCommandBufferInheritanceInfo cmdbuff_ii = vku::InitStructHelper(&inheritance_rendering_info);
VkCommandBufferBeginInfo cmdbuff_bi = vku::InitStructHelper();
cmdbuff_bi.pInheritanceInfo = &cmdbuff_ii;
cmdbuff_bi.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
vkt::CommandBuffer secondary(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
secondary.Begin(&cmdbuff_bi);
vk::CmdBindPipeline(secondary, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDraw(secondary, 3, 1, 0, 0);
secondary.End();
}
TEST_F(PositiveSecondaryCommandBuffer, CustomResolveDynamicRendering) {
TEST_DESCRIPTION("Call vkCmdBeginCustomResolveEXT in the secondary");
AddRequiredExtensions(VK_EXT_CUSTOM_RESOLVE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::customResolve);
RETURN_IF_SKIP(Init());
VkFormat color_format = VK_FORMAT_R8G8B8A8_UNORM;
VkCustomResolveCreateInfoEXT custom_resolve_info = vku::InitStructHelper();
custom_resolve_info.customResolve = VK_FALSE;
custom_resolve_info.colorAttachmentCount = 1;
custom_resolve_info.pColorAttachmentFormats = &color_format;
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(&custom_resolve_info);
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &color_format;
CreatePipelineHelper pipe_1(*this, &pipeline_rendering_info);
pipe_1.CreateGraphicsPipeline();
custom_resolve_info.customResolve = VK_TRUE;
CreatePipelineHelper pipe_2(*this, &pipeline_rendering_info);
pipe_2.CreateGraphicsPipeline();
VkCommandBufferInheritanceRenderingInfo inheritance_rendering_info = vku::InitStructHelper(&custom_resolve_info);
inheritance_rendering_info.flags = VK_RENDERING_CUSTOM_RESOLVE_BIT_EXT;
inheritance_rendering_info.colorAttachmentCount = 1;
inheritance_rendering_info.pColorAttachmentFormats = &color_format;
inheritance_rendering_info.rasterizationSamples = VK_SAMPLE_COUNT_4_BIT;
const VkCommandBufferInheritanceInfo cmdbuff_ii = vku::InitStructHelper(&inheritance_rendering_info);
VkCommandBufferBeginInfo cmdbuff_bi = vku::InitStructHelper();
cmdbuff_bi.flags = 0;
cmdbuff_bi.pInheritanceInfo = &cmdbuff_ii;
VkImageCreateInfo image_ci = vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, color_format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
image_ci.samples = VK_SAMPLE_COUNT_4_BIT;
vkt::Image color_image(*m_device, image_ci);
vkt::ImageView color_image_view = color_image.CreateView();
image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
vkt::Image resolve_image(*m_device, image_ci);
vkt::ImageView resolve_image_view = resolve_image.CreateView();
VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper();
color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_attachment.imageView = color_image_view;
color_attachment.resolveMode = VK_RESOLVE_MODE_CUSTOM_BIT_EXT;
color_attachment.resolveImageView = resolve_image_view;
color_attachment.resolveImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkRenderingInfo begin_rendering_info = vku::InitStructHelper();
begin_rendering_info.flags = VK_RENDERING_CUSTOM_RESOLVE_BIT_EXT;
begin_rendering_info.colorAttachmentCount = 1;
begin_rendering_info.pColorAttachments = &color_attachment;
begin_rendering_info.layerCount = 1;
begin_rendering_info.renderArea = {{0, 0}, {1, 1}};
vkt::CommandBuffer secondary(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
secondary.Begin(&cmdbuff_bi);
secondary.BeginRendering(begin_rendering_info);
VkBeginCustomResolveInfoEXT begin_resolve_info = vku::InitStructHelper();
vk::CmdBeginCustomResolveEXT(secondary, &begin_resolve_info);
vk::CmdBindPipeline(secondary, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_2);
vk::CmdDraw(secondary, 3, 1, 0, 0);
secondary.EndRendering();
secondary.End();
m_command_buffer.Begin();
vk::CmdExecuteCommands(m_command_buffer, 1, &secondary.handle());
m_command_buffer.End();
}
TEST_F(PositiveSecondaryCommandBuffer, CustomResolveDynamicRenderingInputAttachmentIndex) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/11099");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_CUSTOM_RESOLVE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::customResolve);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::dynamicRenderingLocalRead);
RETURN_IF_SKIP(Init());
const VkFormat depth_format = FindSupportedDepthOnlyFormat(Gpu());
VkCustomResolveCreateInfoEXT custom_resolve_info = vku::InitStructHelper();
custom_resolve_info.customResolve = VK_TRUE;
custom_resolve_info.colorAttachmentCount = 0;
custom_resolve_info.pColorAttachmentFormats = nullptr;
custom_resolve_info.depthAttachmentFormat = depth_format;
custom_resolve_info.stencilAttachmentFormat = VK_FORMAT_UNDEFINED;
uint32_t zero = 0;
VkRenderingInputAttachmentIndexInfo input_info = vku::InitStructHelper(&custom_resolve_info);
input_info.colorAttachmentCount = 0;
input_info.pColorAttachmentInputIndices = nullptr;
input_info.pDepthInputAttachmentIndex = &zero;
input_info.pStencilInputAttachmentIndex = nullptr;
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(&input_info);
pipeline_rendering_info.colorAttachmentCount = 0;
pipeline_rendering_info.pColorAttachmentFormats = nullptr;
pipeline_rendering_info.depthAttachmentFormat = depth_format;
pipeline_rendering_info.stencilAttachmentFormat = VK_FORMAT_UNDEFINED;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.ds_ci_ = vku::InitStructHelper();
pipe.CreateGraphicsPipeline();
VkCommandBufferInheritanceRenderingInfo inheritance_rendering_info = vku::InitStructHelper(&input_info);
inheritance_rendering_info.flags = VK_RENDERING_CUSTOM_RESOLVE_BIT_EXT;
inheritance_rendering_info.colorAttachmentCount = 0;
inheritance_rendering_info.pColorAttachmentFormats = nullptr;
inheritance_rendering_info.depthAttachmentFormat = depth_format;
inheritance_rendering_info.stencilAttachmentFormat = VK_FORMAT_UNDEFINED;
inheritance_rendering_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
const VkCommandBufferInheritanceInfo cmdbuff_ii = vku::InitStructHelper(&inheritance_rendering_info);
VkCommandBufferBeginInfo cmdbuff_bi = vku::InitStructHelper();
cmdbuff_bi.pInheritanceInfo = &cmdbuff_ii;
cmdbuff_bi.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
vkt::CommandBuffer secondary(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
secondary.Begin(&cmdbuff_bi);
vk::CmdBindPipeline(secondary, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDraw(secondary, 3, 1, 0, 0);
secondary.End();
}