| /* |
| * 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); |
| } |