blob: 788ce2344d0dd7f57c6048408e9af7ce9e7b64e9 [file] [log] [blame]
/*
* 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, SecondaryCommandBufferBarrier) {
TEST_DESCRIPTION("Add a pipeline barrier in a secondary command buffer");
ASSERT_NO_FATAL_FAILURE(Init());
m_errorMonitor->ExpectSuccess();
// A renderpass with a single subpass that declared a self-dependency
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 ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
VkSubpassDescription subpasses[] = {
{0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &ref, nullptr, nullptr, 0, nullptr},
};
VkSubpassDependency dep = {0,
0,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_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};
VkRenderPass rp;
VkResult err = vk::CreateRenderPass(m_device->device(), &rpci, nullptr, &rp);
ASSERT_VK_SUCCESS(err);
VkImageObj image(m_device);
image.Init(32, 32, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
VkImageView imageView = image.targetView(VK_FORMAT_R8G8B8A8_UNORM);
VkFramebufferCreateInfo fbci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &imageView, 32, 32, 1};
VkFramebuffer fb;
err = vk::CreateFramebuffer(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,
},
{32, 32}},
0,
nullptr};
vk::CmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
VkCommandPoolObj pool(m_device, m_device->graphics_queue_node_index_, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
VkCommandBufferObj 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.handle(), &cbbi);
VkMemoryBarrier mem_barrier = {};
mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
mem_barrier.pNext = NULL;
mem_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
mem_barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
vk::CmdPipelineBarrier(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);
image.ImageMemoryBarrier(&secondary, VK_IMAGE_ASPECT_COLOR_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
secondary.end();
vk::CmdExecuteCommands(m_commandBuffer->handle(), 1, &secondary.handle());
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);
vk::QueueWaitIdle(m_device->m_queue);
vk::DestroyFramebuffer(m_device->device(), fb, nullptr);
vk::DestroyRenderPass(m_device->device(), rp, nullptr);
m_errorMonitor->VerifyNotFound();
}
TEST_F(VkPositiveLayerTest, ResetQueryPoolFromDifferentCB) {
TEST_DESCRIPTION("Reset a query on one CB and use it in another.");
ASSERT_NO_FATAL_FAILURE(Init());
m_errorMonitor->ExpectSuccess();
VkQueryPool query_pool;
VkQueryPoolCreateInfo query_pool_create_info{};
query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
query_pool_create_info.queryType = VK_QUERY_TYPE_OCCLUSION;
query_pool_create_info.queryCount = 1;
vk::CreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool);
VkCommandBuffer command_buffer[2];
VkCommandBufferAllocateInfo command_buffer_allocate_info{};
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buffer_allocate_info.commandPool = m_commandPool->handle();
command_buffer_allocate_info.commandBufferCount = 2;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
vk::AllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer);
{
VkCommandBufferBeginInfo begin_info{};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vk::BeginCommandBuffer(command_buffer[0], &begin_info);
vk::CmdResetQueryPool(command_buffer[0], query_pool, 0, 1);
vk::EndCommandBuffer(command_buffer[0]);
vk::BeginCommandBuffer(command_buffer[1], &begin_info);
vk::CmdBeginQuery(command_buffer[1], query_pool, 0, 0);
vk::CmdEndQuery(command_buffer[1], query_pool, 0);
vk::EndCommandBuffer(command_buffer[1]);
}
{
VkSubmitInfo submit_info[2]{};
submit_info[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info[0].commandBufferCount = 1;
submit_info[0].pCommandBuffers = &command_buffer[0];
submit_info[0].signalSemaphoreCount = 0;
submit_info[0].pSignalSemaphores = nullptr;
submit_info[1].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info[1].commandBufferCount = 1;
submit_info[1].pCommandBuffers = &command_buffer[1];
submit_info[1].signalSemaphoreCount = 0;
submit_info[1].pSignalSemaphores = nullptr;
vk::QueueSubmit(m_device->m_queue, 2, &submit_info[0], VK_NULL_HANDLE);
}
vk::QueueWaitIdle(m_device->m_queue);
vk::DestroyQueryPool(m_device->device(), query_pool, nullptr);
vk::FreeCommandBuffers(m_device->device(), m_commandPool->handle(), 2, command_buffer);
m_errorMonitor->VerifyNotFound();
}
TEST_F(VkPositiveLayerTest, BasicQuery) {
TEST_DESCRIPTION("Use a couple occlusion queries");
m_errorMonitor->ExpectSuccess();
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
VkCommandPoolCreateFlags pool_flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, pool_flags));
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
uint32_t qfi = 0;
VkBufferCreateInfo bci = {};
bci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
bci.size = 4 * sizeof(uint64_t);
bci.queueFamilyIndexCount = 1;
bci.pQueueFamilyIndices = &qfi;
VkBufferObj buffer;
VkMemoryPropertyFlags mem_props = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
buffer.init(*m_device, bci, mem_props);
VkQueryPool query_pool;
VkQueryPoolCreateInfo query_pool_info;
query_pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
query_pool_info.pNext = NULL;
query_pool_info.queryType = VK_QUERY_TYPE_OCCLUSION;
query_pool_info.flags = 0;
query_pool_info.queryCount = 2;
query_pool_info.pipelineStatistics = 0;
VkResult res = vk::CreateQueryPool(m_device->handle(), &query_pool_info, NULL, &query_pool);
ASSERT_VK_SUCCESS(res);
CreatePipelineHelper pipe(*this);
pipe.InitInfo();
pipe.InitState();
pipe.CreateGraphicsPipeline();
m_commandBuffer->begin();
vk::CmdResetQueryPool(m_commandBuffer->handle(), query_pool, 0, 2);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBeginQuery(m_commandBuffer->handle(), query_pool, 0, 0);
vk::CmdEndQuery(m_commandBuffer->handle(), query_pool, 0);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
vk::CmdBeginQuery(m_commandBuffer->handle(), query_pool, 1, 0);
vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0);
vk::CmdEndRenderPass(m_commandBuffer->handle());
vk::CmdEndQuery(m_commandBuffer->handle(), query_pool, 1);
vk::CmdCopyQueryPoolResults(m_commandBuffer->handle(), query_pool, 0, 2, buffer.handle(), 0, sizeof(uint64_t),
VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
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);
vk::QueueWaitIdle(m_device->m_queue);
uint64_t samples_passed[4];
res = vk::GetQueryPoolResults(m_device->handle(), query_pool, 0, 2, sizeof(samples_passed), samples_passed, sizeof(uint64_t),
VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
ASSERT_VK_SUCCESS(res);
// Now reset query pool in a different command buffer than the BeginQuery
vk::ResetCommandBuffer(m_commandBuffer->handle(), 0);
m_commandBuffer->begin();
vk::CmdResetQueryPool(m_commandBuffer->handle(), query_pool, 0, 1);
m_commandBuffer->end();
m_commandBuffer->QueueCommandBuffer();
vk::QueueWaitIdle(m_device->m_queue);
vk::ResetCommandBuffer(m_commandBuffer->handle(), 0);
m_commandBuffer->begin();
vk::CmdBeginQuery(m_commandBuffer->handle(), query_pool, 0, 0);
vk::CmdEndQuery(m_commandBuffer->handle(), query_pool, 0);
m_commandBuffer->end();
m_commandBuffer->QueueCommandBuffer();
m_errorMonitor->VerifyNotFound();
vk::QueueWaitIdle(m_device->m_queue);
vk::DestroyQueryPool(m_device->handle(), query_pool, NULL);
}
TEST_F(VkPositiveLayerTest, ConfirmNoVLErrorWhenVkCmdClearAttachmentsCalledInSecondaryCB) {
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.");
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
VkCommandBufferObj secondary(m_device, m_commandPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkCommandBufferBeginInfo info = {};
VkCommandBufferInheritanceInfo hinfo = {};
info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.pInheritanceInfo = &hinfo;
hinfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
hinfo.pNext = NULL;
hinfo.renderPass = renderPass();
hinfo.subpass = 0;
hinfo.framebuffer = m_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}, {(uint32_t)m_width, (uint32_t)m_height}}, 0, 1};
vk::CmdClearAttachments(secondary.handle(), 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_commandBuffer->begin();
vk::CmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
vk::CmdExecuteCommands(m_commandBuffer->handle(), 1, &secondary.handle());
vk::CmdEndRenderPass(m_commandBuffer->handle());
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
}
TEST_F(VkPositiveLayerTest, CommandPoolDeleteWithReferences) {
TEST_DESCRIPTION("Ensure the validation layers bookkeeping tracks the implicit command buffer frees.");
ASSERT_NO_FATAL_FAILURE(Init());
VkCommandPoolCreateInfo cmd_pool_info = {};
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmd_pool_info.pNext = NULL;
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->handle(), &cmd_pool_info, NULL, &secondary_cmd_pool);
ASSERT_VK_SUCCESS(res);
VkCommandBufferAllocateInfo cmdalloc = vk_testing::CommandBuffer::create_info(secondary_cmd_pool);
cmdalloc.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
VkCommandBuffer secondary_cmds;
res = vk::AllocateCommandBuffers(m_device->handle(), &cmdalloc, &secondary_cmds);
VkCommandBufferInheritanceInfo cmd_buf_inheritance_info = {};
cmd_buf_inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
cmd_buf_inheritance_info.pNext = NULL;
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 = {};
secondary_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
secondary_begin.pNext = NULL;
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_VK_SUCCESS(res);
vk::EndCommandBuffer(secondary_cmds);
m_commandBuffer->begin();
vk::CmdExecuteCommands(m_commandBuffer->handle(), 1, &secondary_cmds);
m_commandBuffer->end();
// DestroyCommandPool *implicitly* frees the command buffers allocated from it
vk::DestroyCommandPool(m_device->handle(), secondary_cmd_pool, NULL);
// If bookkeeping has been lax, validating the reset will attempt to touch deleted data
res = vk::ResetCommandPool(m_device->handle(), m_commandPool->handle(), 0);
ASSERT_VK_SUCCESS(res);
}
TEST_F(VkPositiveLayerTest, SecondaryCommandBufferClearColorAttachments) {
TEST_DESCRIPTION("Create a secondary command buffer and record a CmdClearAttachments call into it");
m_errorMonitor->ExpectSuccess();
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
VkCommandBufferAllocateInfo command_buffer_allocate_info = {};
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buffer_allocate_info.commandPool = m_commandPool->handle();
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
command_buffer_allocate_info.commandBufferCount = 1;
VkCommandBuffer secondary_command_buffer;
ASSERT_VK_SUCCESS(vk::AllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &secondary_command_buffer));
VkCommandBufferBeginInfo command_buffer_begin_info = {};
VkCommandBufferInheritanceInfo command_buffer_inheritance_info = {};
command_buffer_inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
command_buffer_inheritance_info.renderPass = m_renderPass;
command_buffer_inheritance_info.framebuffer = m_framebuffer;
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
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_commandBuffer->begin();
vk::CmdBeginRenderPass(m_commandBuffer->handle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
vk::CmdExecuteCommands(m_commandBuffer->handle(), 1, &secondary_command_buffer);
vk::CmdEndRenderPass(m_commandBuffer->handle());
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
}
TEST_F(VkPositiveLayerTest, SecondaryCommandBufferImageLayoutTransitions) {
TEST_DESCRIPTION("Perform an image layout transition in a secondary command buffer followed by a transition in the primary.");
VkResult err;
m_errorMonitor->ExpectSuccess();
ASSERT_NO_FATAL_FAILURE(Init());
auto depth_format = FindSupportedDepthStencilFormat(gpu());
if (!depth_format) {
printf("%s Couldn't find depth stencil format.\n", kSkipPrefix);
return;
}
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
// Allocate a secondary and primary cmd buffer
VkCommandBufferAllocateInfo command_buffer_allocate_info = {};
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buffer_allocate_info.commandPool = m_commandPool->handle();
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
command_buffer_allocate_info.commandBufferCount = 1;
VkCommandBuffer secondary_command_buffer;
ASSERT_VK_SUCCESS(vk::AllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &secondary_command_buffer));
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
VkCommandBuffer primary_command_buffer;
ASSERT_VK_SUCCESS(vk::AllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &primary_command_buffer));
VkCommandBufferBeginInfo command_buffer_begin_info = {};
VkCommandBufferInheritanceInfo command_buffer_inheritance_info = {};
command_buffer_inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
command_buffer_begin_info.pInheritanceInfo = &command_buffer_inheritance_info;
err = vk::BeginCommandBuffer(secondary_command_buffer, &command_buffer_begin_info);
ASSERT_VK_SUCCESS(err);
VkImageObj image(m_device);
image.Init(128, 128, 1, depth_format, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
ASSERT_TRUE(image.initialized());
VkImageMemoryBarrier img_barrier = {};
img_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
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.handle();
img_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
img_barrier.subresourceRange.baseArrayLayer = 0;
img_barrier.subresourceRange.baseMipLevel = 0;
img_barrier.subresourceRange.layerCount = 1;
img_barrier.subresourceRange.levelCount = 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);
err = vk::EndCommandBuffer(secondary_command_buffer);
ASSERT_VK_SUCCESS(err);
// Now update primary cmd buffer to execute secondary and transitions image
command_buffer_begin_info.pInheritanceInfo = nullptr;
err = vk::BeginCommandBuffer(primary_command_buffer, &command_buffer_begin_info);
ASSERT_VK_SUCCESS(err);
vk::CmdExecuteCommands(primary_command_buffer, 1, &secondary_command_buffer);
VkImageMemoryBarrier img_barrier2 = {};
img_barrier2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
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.handle();
img_barrier2.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img_barrier2.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img_barrier2.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
img_barrier2.subresourceRange.baseArrayLayer = 0;
img_barrier2.subresourceRange.baseMipLevel = 0;
img_barrier2.subresourceRange.layerCount = 1;
img_barrier2.subresourceRange.levelCount = 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);
err = vk::EndCommandBuffer(primary_command_buffer);
ASSERT_VK_SUCCESS(err);
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &primary_command_buffer;
err = vk::QueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
ASSERT_VK_SUCCESS(err);
m_errorMonitor->VerifyNotFound();
err = vk::DeviceWaitIdle(m_device->device());
ASSERT_VK_SUCCESS(err);
vk::FreeCommandBuffers(m_device->device(), m_commandPool->handle(), 1, &secondary_command_buffer);
vk::FreeCommandBuffers(m_device->device(), m_commandPool->handle(), 1, &primary_command_buffer);
}
TEST_F(VkPositiveLayerTest, DrawIndirectCountWithoutFeature) {
TEST_DESCRIPTION("Use VK_KHR_draw_indirect_count in 1.1 before drawIndirectCount feature was added");
m_errorMonitor->ExpectSuccess();
SetTargetApiVersion(VK_API_VERSION_1_1);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME)) {
m_device_extension_names.push_back(VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME);
} else {
printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME);
return;
}
ASSERT_NO_FATAL_FAILURE(InitState());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
if (DeviceValidationVersion() != VK_API_VERSION_1_1) {
printf("%s Tests requires Vulkan 1.1 exactly, skipping test\n", kSkipPrefix);
return;
}
auto vkCmdDrawIndirectCountKHR =
reinterpret_cast<PFN_vkCmdDrawIndirectCountKHR>(vk::GetDeviceProcAddr(device(), "vkCmdDrawIndirectCountKHR"));
ASSERT_TRUE(vkCmdDrawIndirectCountKHR != nullptr);
auto vkCmdDrawIndexedIndirectCountKHR =
reinterpret_cast<PFN_vkCmdDrawIndexedIndirectCountKHR>(vk::GetDeviceProcAddr(device(), "vkCmdDrawIndexedIndirectCountKHR"));
ASSERT_TRUE(vkCmdDrawIndexedIndirectCountKHR != nullptr);
VkBufferObj indirect_buffer;
indirect_buffer.init(*m_device, sizeof(VkDrawIndirectCommand), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
VkBufferObj indexed_indirect_buffer;
indexed_indirect_buffer.init(*m_device, sizeof(VkDrawIndexedIndirectCommand), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
VkBufferObj count_buffer;
count_buffer.init(*m_device, sizeof(uint32_t), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
VkBufferObj index_buffer;
index_buffer.init(*m_device, sizeof(uint32_t), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
CreatePipelineHelper pipe(*this);
pipe.InitInfo();
pipe.InitState();
pipe.CreateGraphicsPipeline();
// Make calls to valid commands
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
vkCmdDrawIndirectCountKHR(m_commandBuffer->handle(), indirect_buffer.handle(), 0, count_buffer.handle(), 0, 1,
sizeof(VkDrawIndirectCommand));
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), index_buffer.handle(), 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexedIndirectCountKHR(m_commandBuffer->handle(), indexed_indirect_buffer.handle(), 0, count_buffer.handle(), 0, 1,
sizeof(VkDrawIndexedIndirectCommand));
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
}
TEST_F(VkPositiveLayerTest, DrawIndirectCountWithoutFeature12) {
TEST_DESCRIPTION("Use VK_KHR_draw_indirect_count in 1.2 using the extension");
m_errorMonitor->ExpectSuccess();
SetTargetApiVersion(VK_API_VERSION_1_2);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
// Devsim won't read in values like maxDescriptorSetUpdateAfterBindUniformBuffers which cause OneshotTest to fail pipeline
// layout creation if using 1.2 devsim as it enables VK_EXT_descriptor_indexing
if (IsPlatform(kMockICD) || DeviceSimulation()) {
printf("%sNot suppored by MockICD, skipping tests\n", kSkipPrefix);
return;
}
if (DeviceValidationVersion() < VK_API_VERSION_1_2) {
printf("%s Tests requires Vulkan 1.2+, skipping test\n", kSkipPrefix);
return;
}
if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME)) {
m_device_extension_names.push_back(VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME);
} else {
printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME);
return;
}
ASSERT_NO_FATAL_FAILURE(InitState());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
VkBufferObj indirect_buffer;
indirect_buffer.init(*m_device, sizeof(VkDrawIndirectCommand), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
VkBufferObj indexed_indirect_buffer;
indexed_indirect_buffer.init(*m_device, sizeof(VkDrawIndexedIndirectCommand), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
VkBufferObj count_buffer;
count_buffer.init(*m_device, sizeof(uint32_t), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
VkBufferObj index_buffer;
index_buffer.init(*m_device, sizeof(uint32_t), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
CreatePipelineHelper pipe(*this);
pipe.InitInfo();
pipe.InitState();
pipe.CreateGraphicsPipeline();
// Make calls to valid commands
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
vk::CmdDrawIndirectCount(m_commandBuffer->handle(), indirect_buffer.handle(), 0, count_buffer.handle(), 0, 1,
sizeof(VkDrawIndirectCommand));
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), index_buffer.handle(), 0, VK_INDEX_TYPE_UINT32);
vk::CmdDrawIndexedIndirectCount(m_commandBuffer->handle(), indexed_indirect_buffer.handle(), 0, count_buffer.handle(), 0, 1,
sizeof(VkDrawIndexedIndirectCommand));
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
}
TEST_F(VkPositiveLayerTest, DrawIndirectCountWithFeature) {
TEST_DESCRIPTION("Use VK_KHR_draw_indirect_count in 1.2 with feature bit enabled");
m_errorMonitor->ExpectSuccess();
SetTargetApiVersion(VK_API_VERSION_1_2);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
// Devsim won't read in values like maxDescriptorSetUpdateAfterBindUniformBuffers which cause OneshotTest to fail pipeline
// layout creation if using 1.2 devsim as it enables VK_EXT_descriptor_indexing
if (IsPlatform(kMockICD) || DeviceSimulation()) {
printf("%sNot suppored by MockICD, skipping tests\n", kSkipPrefix);
return;
}
if (DeviceValidationVersion() < VK_API_VERSION_1_2) {
printf("%s Tests requires Vulkan 1.2+, skipping test\n", kSkipPrefix);
return;
}
auto features12 = LvlInitStruct<VkPhysicalDeviceVulkan12Features>();
features12.drawIndirectCount = VK_TRUE;
auto features2 = LvlInitStruct<VkPhysicalDeviceFeatures2>(&features12);
vk::GetPhysicalDeviceFeatures2(gpu(), &features2);
if (features12.drawIndirectCount != VK_TRUE) {
printf("drawIndirectCount not supported, skipping test\n");
return;
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
VkBufferObj indirect_buffer;
indirect_buffer.init(*m_device, sizeof(VkDrawIndirectCommand), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
VkBufferObj indexed_indirect_buffer;
indexed_indirect_buffer.init(*m_device, sizeof(VkDrawIndexedIndirectCommand), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
VkBufferObj count_buffer;
count_buffer.init(*m_device, sizeof(uint32_t), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
VkBufferObj index_buffer;
index_buffer.init(*m_device, sizeof(uint32_t), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
CreatePipelineHelper pipe(*this);
pipe.InitInfo();
pipe.InitState();
pipe.CreateGraphicsPipeline();
// Make calls to valid commands
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
vk::CmdDrawIndirectCount(m_commandBuffer->handle(), indirect_buffer.handle(), 0, count_buffer.handle(), 0, 1,
sizeof(VkDrawIndirectCommand));
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), index_buffer.handle(), 0, VK_INDEX_TYPE_UINT32);
vk::CmdDrawIndexedIndirectCount(m_commandBuffer->handle(), indexed_indirect_buffer.handle(), 0, count_buffer.handle(), 0, 1,
sizeof(VkDrawIndexedIndirectCommand));
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
}
TEST_F(VkPositiveLayerTest, CommandBufferSimultaneousUseSync) {
m_errorMonitor->ExpectSuccess();
ASSERT_NO_FATAL_FAILURE(Init());
VkResult err;
// Record (empty!) command buffer that can be submitted multiple times
// simultaneously.
VkCommandBufferBeginInfo cbbi = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr,
VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, nullptr};
m_commandBuffer->begin(&cbbi);
m_commandBuffer->end();
VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0};
VkFence fence;
err = vk::CreateFence(m_device->device(), &fci, nullptr, &fence);
ASSERT_VK_SUCCESS(err);
VkSemaphoreCreateInfo sci = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0};
VkSemaphore s1, s2;
err = vk::CreateSemaphore(m_device->device(), &sci, nullptr, &s1);
ASSERT_VK_SUCCESS(err);
err = vk::CreateSemaphore(m_device->device(), &sci, nullptr, &s2);
ASSERT_VK_SUCCESS(err);
// Submit CB once signaling s1, with fence so we can roll forward to its retirement.
VkSubmitInfo si = {VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 0, nullptr, nullptr, 1, &m_commandBuffer->handle(), 1, &s1};
err = vk::QueueSubmit(m_device->m_queue, 1, &si, fence);
ASSERT_VK_SUCCESS(err);
// Submit CB again, signaling s2.
si.pSignalSemaphores = &s2;
err = vk::QueueSubmit(m_device->m_queue, 1, &si, VK_NULL_HANDLE);
ASSERT_VK_SUCCESS(err);
// Wait for fence.
err = vk::WaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX);
ASSERT_VK_SUCCESS(err);
// CB is still in flight from second submission, but semaphore s1 is no
// longer in flight. delete it.
vk::DestroySemaphore(m_device->device(), s1, nullptr);
m_errorMonitor->VerifyNotFound();
// Force device idle and clean up remaining objects
vk::DeviceWaitIdle(m_device->device());
vk::DestroySemaphore(m_device->device(), s2, nullptr);
vk::DestroyFence(m_device->device(), fence, 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 "
"framebuffer and verify there are no errors.");
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());
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);
// Explicitly create a command buffer to bind the FB to so that we can then
// destroy the command pool in order to implicitly free command buffer
VkCommandPool command_pool;
VkCommandPoolCreateInfo pool_create_info{};
pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_;
pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
vk::CreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool);
VkCommandBuffer command_buffer;
VkCommandBufferAllocateInfo command_buffer_allocate_info{};
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buffer_allocate_info.commandPool = command_pool;
command_buffer_allocate_info.commandBufferCount = 1;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
vk::AllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer);
// Begin our cmd buffer with renderpass using our framebuffer
VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr};
VkCommandBufferBeginInfo begin_info{};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vk::BeginCommandBuffer(command_buffer, &begin_info);
vk::CmdBeginRenderPass(command_buffer, &rpbi, VK_SUBPASS_CONTENTS_INLINE);
vk::CmdEndRenderPass(command_buffer);
vk::EndCommandBuffer(command_buffer);
// Destroy command pool to implicitly free command buffer
vk::DestroyCommandPool(m_device->device(), command_pool, NULL);
vk::DestroyFramebuffer(m_device->device(), fb, nullptr);
vk::DestroyRenderPass(m_device->device(), rp, nullptr);
m_errorMonitor->VerifyNotFound();
}
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.");
ASSERT_NO_FATAL_FAILURE(Init());
VkFormatProperties format_properties;
vk::GetPhysicalDeviceFormatProperties(gpu(), VK_FORMAT_D32_SFLOAT_S8_UINT, &format_properties);
if (!(format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
printf("%s Image format does not support sampling.\n", kSkipPrefix);
return;
}
m_errorMonitor->ExpectSuccess();
VkAttachmentDescription attachment = {0,
VK_FORMAT_D32_SFLOAT_S8_UINT,
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_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
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};
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);
VkImageObj image(m_device);
image.InitNoLayout(32, 32, 1, VK_FORMAT_D32_SFLOAT_S8_UINT,
0x26, // usage
VK_IMAGE_TILING_OPTIMAL, 0);
ASSERT_TRUE(image.initialized());
image.SetLayout(0x6, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
VkImageView view = image.targetView(VK_FORMAT_D32_SFLOAT_S8_UINT, VK_IMAGE_ASPECT_DEPTH_BIT);
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);
m_commandBuffer->begin();
VkImageMemoryBarrier imb = {};
imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imb.pNext = nullptr;
imb.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
imb.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
imb.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
imb.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imb.srcQueueFamilyIndex = 0;
imb.dstQueueFamilyIndex = 0;
imb.image = image.handle();
imb.subresourceRange.aspectMask = 0x6;
imb.subresourceRange.baseMipLevel = 0;
imb.subresourceRange.levelCount = 0x1;
imb.subresourceRange.baseArrayLayer = 0;
imb.subresourceRange.layerCount = 0x1;
vk::CmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, &imb);
m_commandBuffer->end();
m_commandBuffer->QueueCommandBuffer(false);
m_errorMonitor->VerifyNotFound();
vk::DestroyFramebuffer(m_device->device(), fb, nullptr);
vk::DestroyRenderPass(m_device->device(), rp, nullptr);
}
// This is a positive test. No errors should be generated.
TEST_F(VkPositiveLayerTest, QueryAndCopySecondaryCommandBuffers) {
TEST_DESCRIPTION("Issue a query on a secondary command buffer and copy it on a primary.");
ASSERT_NO_FATAL_FAILURE(Init());
if (IsPlatform(kNexusPlayer)) {
printf("%s This test should not run on Nexus Player\n", kSkipPrefix);
return;
}
if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) {
printf("%s Queue family needs to have multiple queues to run this test.\n", kSkipPrefix);
return;
}
uint32_t queue_count;
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_count, NULL);
std::vector<VkQueueFamilyProperties> queue_props(queue_count);
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_count, queue_props.data());
if (queue_props[m_device->graphics_queue_node_index_].timestampValidBits == 0) {
printf("%s Device graphic queue has timestampValidBits of 0, skipping.\n", kSkipPrefix);
return;
}
m_errorMonitor->ExpectSuccess();
VkQueryPool query_pool;
VkQueryPoolCreateInfo query_pool_create_info{};
query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
query_pool_create_info.queryCount = 1;
vk::CreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool);
VkCommandPoolObj command_pool(m_device, m_device->graphics_queue_node_index_, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
VkCommandBufferObj primary_buffer(m_device, &command_pool);
VkCommandBufferObj secondary_buffer(m_device, &command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkQueue queue = VK_NULL_HANDLE;
vk::GetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue);
uint32_t qfi = 0;
VkBufferCreateInfo buff_create_info = {};
buff_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buff_create_info.size = 1024;
buff_create_info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
buff_create_info.queueFamilyIndexCount = 1;
buff_create_info.pQueueFamilyIndices = &qfi;
VkBufferObj buffer;
buffer.init(*m_device, buff_create_info);
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 begin_info{};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.pInheritanceInfo = &hinfo;
secondary_buffer.begin(&begin_info);
vk::CmdResetQueryPool(secondary_buffer.handle(), query_pool, 0, 1);
vk::CmdWriteTimestamp(secondary_buffer.handle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool, 0);
secondary_buffer.end();
primary_buffer.begin();
vk::CmdExecuteCommands(primary_buffer.handle(), 1, &secondary_buffer.handle());
vk::CmdCopyQueryPoolResults(primary_buffer.handle(), query_pool, 0, 1, buffer.handle(), 0, 0, VK_QUERY_RESULT_WAIT_BIT);
primary_buffer.end();
}
primary_buffer.QueueCommandBuffer();
vk::QueueWaitIdle(queue);
vk::DestroyQueryPool(m_device->device(), query_pool, nullptr);
m_errorMonitor->VerifyNotFound();
}
// This is a positive test. No errors should be generated.
TEST_F(VkPositiveLayerTest, QueryAndCopyMultipleCommandBuffers) {
TEST_DESCRIPTION("Issue a query and copy from it on a second command buffer.");
ASSERT_NO_FATAL_FAILURE(Init());
if (IsPlatform(kNexusPlayer)) {
printf("%s This test should not run on Nexus Player\n", kSkipPrefix);
return;
}
if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) {
printf("%s Queue family needs to have multiple queues to run this test.\n", kSkipPrefix);
return;
}
uint32_t queue_count;
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_count, NULL);
std::vector<VkQueueFamilyProperties> queue_props(queue_count);
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_count, queue_props.data());
if (queue_props[m_device->graphics_queue_node_index_].timestampValidBits == 0) {
printf("%s Device graphic queue has timestampValidBits of 0, skipping.\n", kSkipPrefix);
return;
}
m_errorMonitor->ExpectSuccess();
VkQueryPool query_pool;
VkQueryPoolCreateInfo query_pool_create_info{};
query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
query_pool_create_info.queryCount = 1;
vk::CreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool);
VkCommandPool command_pool;
VkCommandPoolCreateInfo pool_create_info{};
pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_;
pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
vk::CreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool);
VkCommandBuffer command_buffer[2];
VkCommandBufferAllocateInfo command_buffer_allocate_info{};
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buffer_allocate_info.commandPool = command_pool;
command_buffer_allocate_info.commandBufferCount = 2;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
vk::AllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer);
VkQueue queue = VK_NULL_HANDLE;
vk::GetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue);
uint32_t qfi = 0;
VkBufferCreateInfo buff_create_info = {};
buff_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buff_create_info.size = 1024;
buff_create_info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
buff_create_info.queueFamilyIndexCount = 1;
buff_create_info.pQueueFamilyIndices = &qfi;
VkBufferObj buffer;
buffer.init(*m_device, buff_create_info);
{
VkCommandBufferBeginInfo begin_info{};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vk::BeginCommandBuffer(command_buffer[0], &begin_info);
vk::CmdResetQueryPool(command_buffer[0], query_pool, 0, 1);
vk::CmdWriteTimestamp(command_buffer[0], VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool, 0);
vk::EndCommandBuffer(command_buffer[0]);
vk::BeginCommandBuffer(command_buffer[1], &begin_info);
vk::CmdCopyQueryPoolResults(command_buffer[1], query_pool, 0, 1, buffer.handle(), 0, 0, VK_QUERY_RESULT_WAIT_BIT);
vk::EndCommandBuffer(command_buffer[1]);
}
{
VkSubmitInfo submit_info{};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 2;
submit_info.pCommandBuffers = command_buffer;
submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = nullptr;
vk::QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
}
vk::QueueWaitIdle(queue);
vk::DestroyQueryPool(m_device->device(), query_pool, nullptr);
vk::FreeCommandBuffers(m_device->device(), command_pool, 2, command_buffer);
vk::DestroyCommandPool(m_device->device(), command_pool, NULL);
m_errorMonitor->VerifyNotFound();
}
TEST_F(VkPositiveLayerTest, DestroyQueryPoolAfterGetQueryPoolResults) {
TEST_DESCRIPTION("Destroy query pool after GetQueryPoolResults() without VK_QUERY_RESULT_PARTIAL_BIT returns VK_SUCCESS");
ASSERT_NO_FATAL_FAILURE(Init());
m_errorMonitor->ExpectSuccess();
uint32_t queue_count;
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_count, NULL);
std::vector<VkQueueFamilyProperties> queue_props(queue_count);
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_count, queue_props.data());
if (queue_props[m_device->graphics_queue_node_index_].timestampValidBits == 0) {
printf("%s Device graphic queue has timestampValidBits of 0, skipping.\n", kSkipPrefix);
return;
}
VkQueryPoolCreateInfo query_pool_create_info = LvlInitStruct<VkQueryPoolCreateInfo>();
query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
query_pool_create_info.queryCount = 1;
VkQueryPool query_pool;
vk::CreateQueryPool(device(), &query_pool_create_info, nullptr, &query_pool);
m_commandBuffer->begin();
vk::CmdResetQueryPool(m_commandBuffer->handle(), query_pool, 0, 1);
vk::CmdWriteTimestamp(m_commandBuffer->handle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool, 0);
m_commandBuffer->end();
VkSubmitInfo submit_info = LvlInitStruct<VkSubmitInfo>();
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &m_commandBuffer->handle();
vk::QueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
const size_t out_data_size = 16;
uint8_t data[out_data_size];
VkResult res;
do {
res = vk::GetQueryPoolResults(m_device->device(), query_pool, 0, 1, out_data_size, &data, 4, 0);
} while (res != VK_SUCCESS);
vk::DestroyQueryPool(m_device->handle(), query_pool, nullptr);
}