blob: 23b816d56c3fd0aea6b35449c86d2dc1c810e6af [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 <type_traits>
#include "cast_utils.h"
#include "layer_validation_tests.h"
TEST_F(VkSyncValTest, SyncBufferCopyHazards) {
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
if (DeviceExtensionSupported(gpu(), nullptr, VK_AMD_BUFFER_MARKER_EXTENSION_NAME)) {
m_device_extension_names.push_back(VK_AMD_BUFFER_MARKER_EXTENSION_NAME);
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
bool has_amd_buffer_maker = DeviceExtensionEnabled(VK_AMD_BUFFER_MARKER_EXTENSION_NAME);
VkBufferObj buffer_a;
VkBufferObj buffer_b;
VkBufferObj buffer_c;
VkMemoryPropertyFlags mem_prop = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
buffer_a.init_as_src_and_dst(*m_device, 256, mem_prop);
buffer_b.init_as_src_and_dst(*m_device, 256, mem_prop);
buffer_c.init_as_src_and_dst(*m_device, 256, mem_prop);
VkBufferCopy region = {0, 0, 256};
VkBufferCopy front2front = {0, 0, 128};
VkBufferCopy front2back = {0, 128, 128};
VkBufferCopy back2back = {128, 128, 128};
auto cb = m_commandBuffer->handle();
m_commandBuffer->begin();
vk::CmdCopyBuffer(cb, buffer_a.handle(), buffer_b.handle(), 1, &region);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyBuffer(cb, buffer_c.handle(), buffer_a.handle(), 1, &region);
m_errorMonitor->VerifyFound();
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
auto buffer_barrier = LvlInitStruct<VkBufferMemoryBarrier>();
buffer_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
buffer_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
buffer_barrier.buffer = buffer_a.handle();
buffer_barrier.offset = 0;
buffer_barrier.size = 256;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1, &buffer_barrier, 0,
nullptr);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyBuffer(cb, buffer_c.handle(), buffer_a.handle(), 1, &front2front);
vk::CmdCopyBuffer(cb, buffer_c.handle(), buffer_a.handle(), 1, &back2back);
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyBuffer(cb, buffer_c.handle(), buffer_a.handle(), 1, &front2back);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyBuffer(cb, buffer_c.handle(), buffer_b.handle(), 1, &region);
m_errorMonitor->VerifyFound();
// NOTE: Since the previous command skips in validation, the state update is never done, and the validation layer thus doesn't
// record the write operation to b. So we'll need to repeat it successfully to set up for the *next* test.
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
auto mem_barrier = LvlInitStruct<VkMemoryBarrier>();
mem_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
mem_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &mem_barrier, 0, nullptr, 0,
nullptr);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_c.handle(), buffer_b.handle(), 1, &region);
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
mem_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; // Protect C but not B
mem_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &mem_barrier, 0, nullptr, 0,
nullptr);
vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_b.handle(), buffer_c.handle(), 1, &region);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
// CmdFillBuffer
m_errorMonitor->ExpectSuccess();
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdFillBuffer(m_commandBuffer->handle(), buffer_a.handle(), 0, 256, 1);
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdCopyBuffer(cb, buffer_b.handle(), buffer_a.handle(), 1, &region);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdFillBuffer(m_commandBuffer->handle(), buffer_a.handle(), 0, 256, 1);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
// CmdUpdateBuffer
int i = 10;
m_errorMonitor->ExpectSuccess();
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdUpdateBuffer(m_commandBuffer->handle(), buffer_a.handle(), 0, sizeof(i), &i);
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdCopyBuffer(cb, buffer_b.handle(), buffer_a.handle(), 1, &region);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdUpdateBuffer(m_commandBuffer->handle(), buffer_a.handle(), 0, sizeof(i), &i);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
// Create secondary buffers to use
m_errorMonitor->ExpectSuccess();
VkCommandBufferObj secondary_cb1(m_device, m_commandPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkCommandBuffer scb1 = secondary_cb1.handle();
secondary_cb1.begin();
vk::CmdCopyBuffer(scb1, buffer_c.handle(), buffer_a.handle(), 1, &front2front);
secondary_cb1.end();
m_errorMonitor->VerifyNotFound();
m_errorMonitor->ExpectSuccess();
VkCommandBufferObj secondary_cb2(m_device, m_commandPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkCommandBuffer scb2 = secondary_cb2.handle();
secondary_cb2.begin();
vk::CmdCopyBuffer(scb2, buffer_a.handle(), buffer_c.handle(), 1, &front2front);
secondary_cb2.end();
m_errorMonitor->VerifyNotFound();
m_errorMonitor->ExpectSuccess();
VkCommandBufferObj secondary_cb3(m_device, m_commandPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkCommandBuffer scb3 = secondary_cb3.handle();
secondary_cb3.begin();
secondary_cb3.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 0,
nullptr);
secondary_cb3.end();
m_errorMonitor->VerifyNotFound();
m_errorMonitor->ExpectSuccess();
VkCommandBufferObj secondary_cb4(m_device, m_commandPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkCommandBuffer scb4 = secondary_cb4.handle();
secondary_cb4.begin();
vk::CmdCopyBuffer(scb4, buffer_b.handle(), buffer_c.handle(), 1, &front2front);
secondary_cb4.end();
m_errorMonitor->VerifyNotFound();
// One secondary CB hazard with active command buffer
m_errorMonitor->ExpectSuccess();
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdCopyBuffer(cb, buffer_c.handle(), buffer_a.handle(), 1, &front2front);
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdExecuteCommands(cb, 1, &scb1);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
// Two secondary CB hazard with each other
m_commandBuffer->reset();
m_commandBuffer->begin();
m_errorMonitor->VerifyNotFound();
// This is also a "SYNC-HAZARD-WRITE_AFTER_WRITE" present, but only the first hazard is reported.
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
{
VkCommandBuffer two_cbs[2] = {scb1, scb2};
vk::CmdExecuteCommands(cb, 2, two_cbs);
}
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
// Two secondary CB hazard with each other
m_commandBuffer->reset();
m_commandBuffer->begin();
m_errorMonitor->VerifyNotFound();
{
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
VkCommandBuffer two_cbs[2] = {scb1, scb4};
vk::CmdExecuteCommands(cb, 2, two_cbs);
m_errorMonitor->VerifyFound();
}
m_commandBuffer->end();
// Add a secondary CB with a barrier
m_commandBuffer->reset();
m_commandBuffer->begin();
{
m_errorMonitor->ExpectSuccess();
VkCommandBuffer three_cbs[3] = {scb1, scb3, scb4};
vk::CmdExecuteCommands(cb, 3, three_cbs);
m_errorMonitor->VerifyNotFound();
}
m_commandBuffer->end();
m_commandBuffer->reset();
// CmdWriteBufferMarkerAMD
if (has_amd_buffer_maker) {
auto fpCmdWriteBufferMarkerAMD =
(PFN_vkCmdWriteBufferMarkerAMD)vk::GetDeviceProcAddr(m_device->device(), "vkCmdWriteBufferMarkerAMD");
if (!fpCmdWriteBufferMarkerAMD) {
printf("%s Test requires unsupported vkCmdWriteBufferMarkerAMD feature. Skipped.\n", kSkipPrefix);
} else {
m_errorMonitor->ExpectSuccess();
m_commandBuffer->reset();
m_commandBuffer->begin();
fpCmdWriteBufferMarkerAMD(m_commandBuffer->handle(), VK_PIPELINE_STAGE_TRANSFER_BIT, buffer_a.handle(), 0, 1);
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdCopyBuffer(cb, buffer_b.handle(), buffer_a.handle(), 1, &region);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
fpCmdWriteBufferMarkerAMD(m_commandBuffer->handle(), VK_PIPELINE_STAGE_TRANSFER_BIT, buffer_a.handle(), 0, 1);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
} else {
printf("%s Test requires unsupported vkCmdWriteBufferMarkerAMD feature. Skipped.\n", kSkipPrefix);
}
}
TEST_F(VkSyncValTest, Sync2BufferCopyHazards) {
SetTargetApiVersion(VK_API_VERSION_1_2);
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME)) {
m_device_extension_names.push_back(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
} else {
printf("%s Synchronization2 not supported, skipping test\n", kSkipPrefix);
return;
}
if (!CheckSynchronization2SupportAndInitState(this)) {
printf("%s Synchronization2 not supported, skipping test\n", kSkipPrefix);
return;
}
auto fpCmdPipelineBarrier2KHR = (PFN_vkCmdPipelineBarrier2KHR)vk::GetDeviceProcAddr(m_device->device(), "vkCmdPipelineBarrier2KHR");
VkBufferObj buffer_a;
VkBufferObj buffer_b;
VkBufferObj buffer_c;
VkMemoryPropertyFlags mem_prop = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
buffer_a.init_as_src_and_dst(*m_device, 256, mem_prop);
buffer_b.init_as_src_and_dst(*m_device, 256, mem_prop);
buffer_c.init_as_src_and_dst(*m_device, 256, mem_prop);
VkBufferCopy region = {0, 0, 256};
VkBufferCopy front2front = {0, 0, 128};
VkBufferCopy front2back = {0, 128, 128};
VkBufferCopy back2back = {128, 128, 128};
auto cb = m_commandBuffer->handle();
m_commandBuffer->begin();
vk::CmdCopyBuffer(cb, buffer_a.handle(), buffer_b.handle(), 1, &region);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyBuffer(cb, buffer_c.handle(), buffer_a.handle(), 1, &region);
m_errorMonitor->VerifyFound();
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
{
auto buffer_barrier = lvl_init_struct<VkBufferMemoryBarrier2KHR>();
buffer_barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR;
buffer_barrier.dstStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR;
buffer_barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT_KHR;
buffer_barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR;
buffer_barrier.buffer = buffer_a.handle();
buffer_barrier.offset = 0;
buffer_barrier.size = 256;
auto dep_info = lvl_init_struct<VkDependencyInfoKHR>();
dep_info.bufferMemoryBarrierCount = 1;
dep_info.pBufferMemoryBarriers = &buffer_barrier;
fpCmdPipelineBarrier2KHR(cb, &dep_info);
}
m_errorMonitor->ExpectSuccess();
vk::CmdCopyBuffer(cb, buffer_c.handle(), buffer_a.handle(), 1, &front2front);
vk::CmdCopyBuffer(cb, buffer_c.handle(), buffer_a.handle(), 1, &back2back);
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyBuffer(cb, buffer_c.handle(), buffer_a.handle(), 1, &front2back);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyBuffer(cb, buffer_c.handle(), buffer_b.handle(), 1, &region);
m_errorMonitor->VerifyFound();
// NOTE: Since the previous command skips in validation, the state update is never done, and the validation layer thus doesn't
// record the write operation to b. So we'll need to repeat it successfully to set up for the *next* test.
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
{
auto mem_barrier = lvl_init_struct<VkMemoryBarrier2KHR>();
mem_barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR;
mem_barrier.dstStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR;
mem_barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR;
mem_barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR;
auto dep_info = lvl_init_struct<VkDependencyInfoKHR>();
dep_info.memoryBarrierCount = 1;
dep_info.pMemoryBarriers = &mem_barrier;
fpCmdPipelineBarrier2KHR(cb, &dep_info);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_c.handle(), buffer_b.handle(), 1, &region);
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
mem_barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT_KHR; // Protect C but not B
mem_barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR;
fpCmdPipelineBarrier2KHR(cb, &dep_info);
vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_b.handle(), buffer_c.handle(), 1, &region);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
}
TEST_F(VkSyncValTest, SyncCopyOptimalImageHazards) {
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageObj image_a(m_device);
auto image_ci = VkImageObj::ImageCreateInfo2D(128, 128, 1, 2, format, usage, VK_IMAGE_TILING_OPTIMAL);
image_a.Init(image_ci);
ASSERT_TRUE(image_a.initialized());
VkImageObj image_b(m_device);
image_b.Init(image_ci);
ASSERT_TRUE(image_b.initialized());
VkImageObj image_c(m_device);
image_c.Init(image_ci);
ASSERT_TRUE(image_c.initialized());
VkImageSubresourceLayers layers_all{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 2};
VkImageSubresourceLayers layers_0{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
VkImageSubresourceLayers layers_1{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 1};
VkImageSubresourceRange full_subresource_range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 2};
VkOffset3D zero_offset{0, 0, 0};
VkOffset3D half_offset{64, 64, 0};
VkExtent3D full_extent{128, 128, 1}; // <-- image type is 2D
VkExtent3D half_extent{64, 64, 1}; // <-- image type is 2D
VkImageCopy full_region = {layers_all, zero_offset, layers_all, zero_offset, full_extent};
VkImageCopy region_0_to_0 = {layers_0, zero_offset, layers_0, zero_offset, full_extent};
VkImageCopy region_0_to_1 = {layers_0, zero_offset, layers_1, zero_offset, full_extent};
VkImageCopy region_1_to_1 = {layers_1, zero_offset, layers_1, zero_offset, full_extent};
VkImageCopy region_0_front = {layers_0, zero_offset, layers_0, zero_offset, half_extent};
VkImageCopy region_0_back = {layers_0, half_offset, layers_0, half_offset, half_extent};
m_commandBuffer->begin();
image_c.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_b.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_a.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
auto cb = m_commandBuffer->handle();
vk::CmdCopyImage(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->VerifyFound();
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
auto image_barrier = LvlInitStruct<VkImageMemoryBarrier>();
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
image_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_barrier.image = image_a.handle();
image_barrier.subresourceRange = full_subresource_range;
image_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
&image_barrier);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_0_to_0);
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_1_to_1);
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_0_to_1);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->VerifyFound();
// NOTE: Since the previous command skips in validation, the state update is never done, and the validation layer thus doesn't
// record the write operation to b. So we'll need to repeat it successfully to set up for the *next* test.
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
auto mem_barrier = LvlInitStruct<VkMemoryBarrier>();
mem_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
mem_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &mem_barrier, 0, nullptr, 0,
nullptr);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->VerifyNotFound();
// Use barrier to protect last reader, but not last writer...
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
mem_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; // Protects C but not B
mem_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &mem_barrier, 0, nullptr, 0,
nullptr);
vk::CmdCopyImage(cb, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->VerifyFound();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_0_front);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_0_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_0_back);
m_errorMonitor->VerifyNotFound();
m_commandBuffer->end();
// Test secondary command buffers
// Create secondary buffers to use
m_errorMonitor->ExpectSuccess();
VkCommandBufferObj secondary_cb1(m_device, m_commandPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
VkCommandBuffer scb1 = secondary_cb1.handle();
secondary_cb1.begin();
vk::CmdCopyImage(scb1, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
secondary_cb1.end();
m_errorMonitor->VerifyNotFound();
auto record_primary = [&]() {
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdCopyImage(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
vk::CmdExecuteCommands(cb, 1, &scb1);
m_commandBuffer->end();
};
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
record_primary();
m_errorMonitor->VerifyFound();
m_errorMonitor->ExpectSuccess();
// With a barrier...
secondary_cb1.reset();
secondary_cb1.begin();
vk::CmdPipelineBarrier(scb1, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &mem_barrier, 0, nullptr, 0,
nullptr);
vk::CmdCopyImage(scb1, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
secondary_cb1.end();
record_primary();
m_errorMonitor->VerifyNotFound();
auto image_transition_barrier = image_barrier;
image_transition_barrier.image = image_a.handle();
image_transition_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
image_transition_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
m_errorMonitor->ExpectSuccess();
secondary_cb1.reset();
secondary_cb1.begin();
// Use the wrong stage, get an error
vk::CmdPipelineBarrier(scb1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1,
&image_transition_barrier);
secondary_cb1.end();
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
record_primary();
m_errorMonitor->VerifyFound();
// CmdResolveImage hazard testing
VkImageFormatProperties formProps = {{0, 0, 0}, 0, 0, 0, 0};
vk::GetPhysicalDeviceImageFormatProperties(m_device->phy().handle(), VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TYPE_2D,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0, &formProps);
if (!(formProps.sampleCounts & VK_SAMPLE_COUNT_2_BIT)) {
printf("%s CmdResolveImage Test requires unsupported VK_SAMPLE_COUNT_2_BIT feature. Skipped.\n", kSkipPrefix);
} else {
m_errorMonitor->ExpectSuccess();
VkImageObj image_s2_a(m_device), image_s2_b(m_device);
image_ci.samples = VK_SAMPLE_COUNT_2_BIT;
image_s2_a.Init(image_ci);
ASSERT_TRUE(image_s2_a.initialized());
image_s2_b.Init(image_ci);
ASSERT_TRUE(image_s2_b.initialized());
VkImageResolve r_full_region = {layers_all, zero_offset, layers_all, zero_offset, full_extent};
m_commandBuffer->reset();
m_commandBuffer->begin();
image_s2_a.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_s2_b.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
vk::CmdResolveImage(cb, image_s2_a.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&r_full_region);
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdCopyImage(cb, image_s2_b.handle(), VK_IMAGE_LAYOUT_GENERAL, image_s2_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&full_region);
vk::CmdCopyImage(cb, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdResolveImage(cb, image_s2_a.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&r_full_region);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdResolveImage(cb, image_s2_b.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&r_full_region);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
}
TEST_F(VkSyncValTest, Sync2CopyOptimalImageHazards) {
SetTargetApiVersion(VK_API_VERSION_1_2);
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME)) {
m_device_extension_names.push_back(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
} else {
printf("%s Synchronization2 not supported, skipping test\n", kSkipPrefix);
return;
}
if (!CheckSynchronization2SupportAndInitState(this)) {
printf("%s Synchronization2 not supported, skipping test\n", kSkipPrefix);
return;
}
auto fpCmdPipelineBarrier2KHR = (PFN_vkCmdPipelineBarrier2KHR)vk::GetDeviceProcAddr(m_device->device(), "vkCmdPipelineBarrier2KHR");
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageObj image_a(m_device);
auto image_ci = VkImageObj::ImageCreateInfo2D(128, 128, 1, 2, format, usage, VK_IMAGE_TILING_OPTIMAL);
image_a.Init(image_ci);
ASSERT_TRUE(image_a.initialized());
VkImageObj image_b(m_device);
image_b.Init(image_ci);
ASSERT_TRUE(image_b.initialized());
VkImageObj image_c(m_device);
image_c.Init(image_ci);
ASSERT_TRUE(image_c.initialized());
VkImageSubresourceLayers layers_all{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 2};
VkImageSubresourceLayers layers_0{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
VkImageSubresourceLayers layers_1{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 1};
VkImageSubresourceRange full_subresource_range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 2};
VkOffset3D zero_offset{0, 0, 0};
VkOffset3D half_offset{64, 64, 0};
VkExtent3D full_extent{128, 128, 1}; // <-- image type is 2D
VkExtent3D half_extent{64, 64, 1}; // <-- image type is 2D
VkImageCopy full_region = {layers_all, zero_offset, layers_all, zero_offset, full_extent};
VkImageCopy region_0_to_0 = {layers_0, zero_offset, layers_0, zero_offset, full_extent};
VkImageCopy region_0_to_1 = {layers_0, zero_offset, layers_1, zero_offset, full_extent};
VkImageCopy region_1_to_1 = {layers_1, zero_offset, layers_1, zero_offset, full_extent};
VkImageCopy region_0_front = {layers_0, zero_offset, layers_0, zero_offset, half_extent};
VkImageCopy region_0_back = {layers_0, half_offset, layers_0, half_offset, half_extent};
m_commandBuffer->begin();
image_c.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_b.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_a.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
auto cb = m_commandBuffer->handle();
vk::CmdCopyImage(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->VerifyFound();
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
{
auto image_barrier = lvl_init_struct<VkImageMemoryBarrier2KHR>();
image_barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR;
image_barrier.dstStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR;
image_barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT_KHR;
image_barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR;
image_barrier.image = image_a.handle();
image_barrier.subresourceRange = full_subresource_range;
image_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
auto dep_info = lvl_init_struct<VkDependencyInfoKHR>();
dep_info.imageMemoryBarrierCount = 1;
dep_info.pImageMemoryBarriers = &image_barrier;
fpCmdPipelineBarrier2KHR(cb, &dep_info);
}
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_0_to_0);
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_1_to_1);
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_0_to_1);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->VerifyFound();
// NOTE: Since the previous command skips in validation, the state update is never done, and the validation layer thus doesn't
// record the write operation to b. So we'll need to repeat it successfully to set up for the *next* test.
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
{
auto mem_barrier = lvl_init_struct<VkMemoryBarrier2KHR>();
mem_barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR;
mem_barrier.dstStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR;
mem_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
mem_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
auto dep_info = lvl_init_struct<VkDependencyInfoKHR>();
dep_info.memoryBarrierCount = 1;
dep_info.pMemoryBarriers = &mem_barrier;
fpCmdPipelineBarrier2KHR(cb, &dep_info);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->VerifyNotFound();
// Use barrier to protect last reader, but not last writer...
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
mem_barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT_KHR; // Protects C but not B
mem_barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR;
fpCmdPipelineBarrier2KHR(cb, &dep_info);
vk::CmdCopyImage(cb, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->VerifyFound();
}
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_0_front);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_0_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_0_back);
m_errorMonitor->VerifyNotFound();
m_commandBuffer->end();
}
TEST_F(VkSyncValTest, SyncCopyOptimalMultiPlanarHazards) {
// TODO: Add code to enable sync validation
// Enable KHR multiplane req'd extensions
bool mp_extensions = InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION);
if (mp_extensions) {
m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
}
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE_1_EXTENSION_NAME);
mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
if (mp_extensions) {
m_device_extension_names.push_back(VK_KHR_MAINTENANCE_1_EXTENSION_NAME);
m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
} else {
printf("%s test requires KHR multiplane extensions, not available. Skipping.\n", kSkipPrefix);
return;
}
ASSERT_NO_FATAL_FAILURE(InitState());
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkFormat format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
VkImageObj image_a(m_device);
const auto image_ci = VkImageObj::ImageCreateInfo2D(128, 128, 1, 2, format, usage, VK_IMAGE_TILING_OPTIMAL);
// Verify format
bool supported = ImageFormatAndFeaturesSupported(instance(), gpu(), image_ci,
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
if (!supported) {
printf("%s Multiplane image format not supported. Skipping test.\n", kSkipPrefix);
return; // Assume there's low ROI on searching for different mp formats
}
image_a.Init(image_ci);
VkImageObj image_b(m_device);
image_b.Init(image_ci);
VkImageObj image_c(m_device);
image_c.Init(image_ci);
VkImageSubresourceLayers layer_all_plane0{VK_IMAGE_ASPECT_PLANE_0_BIT_KHR, 0, 0, 2};
VkImageSubresourceLayers layer0_plane0{VK_IMAGE_ASPECT_PLANE_0_BIT_KHR, 0, 0, 1};
VkImageSubresourceLayers layer0_plane1{VK_IMAGE_ASPECT_PLANE_1_BIT_KHR, 0, 0, 1};
VkImageSubresourceLayers layer1_plane1{VK_IMAGE_ASPECT_PLANE_1_BIT_KHR, 0, 1, 1};
VkImageSubresourceRange full_subresource_range{
VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR | VK_IMAGE_ASPECT_PLANE_2_BIT_KHR, 0, 1, 0, 2};
VkOffset3D zero_offset{0, 0, 0};
VkOffset3D one_four_offset{32, 32, 0};
VkExtent3D full_extent{128, 128, 1}; // <-- image type is 2D
VkExtent3D half_extent{64, 64, 1}; // <-- image type is 2D
VkExtent3D one_four_extent{32, 32, 1}; // <-- image type is 2D
VkImageCopy region_all_plane0_to_all_plane0 = {layer_all_plane0, zero_offset, layer_all_plane0, zero_offset, full_extent};
VkImageCopy region_layer0_plane0_to_layer0_plane0 = {layer0_plane0, zero_offset, layer0_plane0, zero_offset, full_extent};
VkImageCopy region_layer0_plane0_to_layer0_plane1 = {layer0_plane0, zero_offset, layer0_plane1, zero_offset, half_extent};
VkImageCopy region_layer1_plane1_to_layer1_plane1_front = {layer1_plane1, zero_offset, layer1_plane1, zero_offset,
one_four_extent};
VkImageCopy region_layer1_plane1_to_layer1_plane1_back = {layer1_plane1, one_four_offset, layer1_plane1, one_four_offset,
one_four_extent};
m_commandBuffer->begin();
image_c.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_b.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_a.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
auto cb = m_commandBuffer->handle();
vk::CmdCopyImage(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_all_plane0_to_all_plane0);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_all_plane0_to_all_plane0);
m_errorMonitor->VerifyFound();
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
auto image_barrier = LvlInitStruct<VkImageMemoryBarrier>();
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
image_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_barrier.image = image_a.handle();
image_barrier.subresourceRange = full_subresource_range;
image_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
&image_barrier);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_layer0_plane0_to_layer0_plane0);
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_layer0_plane0_to_layer0_plane1);
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_layer0_plane0_to_layer0_plane1);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_all_plane0_to_all_plane0);
m_errorMonitor->VerifyFound();
// NOTE: Since the previous command skips in validation, the state update is never done, and the validation layer thus doesn't
// record the write operation to b. So we'll need to repeat it successfully to set up for the *next* test.
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
auto mem_barrier = LvlInitStruct<VkMemoryBarrier>();
mem_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
mem_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &mem_barrier, 0, nullptr, 0,
nullptr);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_all_plane0_to_all_plane0);
m_errorMonitor->VerifyNotFound();
// Use barrier to protect last reader, but not last writer...
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
mem_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; // Protects C but not B
mem_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &mem_barrier, 0, nullptr, 0,
nullptr);
vk::CmdCopyImage(cb, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_all_plane0_to_all_plane0);
m_errorMonitor->VerifyFound();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_layer1_plane1_to_layer1_plane1_front);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_layer1_plane1_to_layer1_plane1_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_layer1_plane1_to_layer1_plane1_back);
m_errorMonitor->VerifyNotFound();
m_commandBuffer->end();
}
TEST_F(VkSyncValTest, SyncCopyLinearImageHazards) {
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
ASSERT_NO_FATAL_FAILURE(InitState());
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageObj image_a(m_device);
const auto image_ci = VkImageObj::ImageCreateInfo2D(128, 128, 1, 1, format, usage, VK_IMAGE_TILING_LINEAR);
image_a.Init(image_ci);
VkImageObj image_b(m_device);
image_b.Init(image_ci);
VkImageObj image_c(m_device);
image_c.Init(image_ci);
VkImageSubresourceLayers layers_all{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
VkImageSubresourceRange full_subresource_range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
VkOffset3D zero_offset{0, 0, 0};
VkOffset3D half_offset{64, 64, 0};
VkExtent3D full_extent{128, 128, 1}; // <-- image type is 2D
VkExtent3D half_extent{64, 64, 1}; // <-- image type is 2D
VkImageCopy full_region = {layers_all, zero_offset, layers_all, zero_offset, full_extent};
VkImageCopy region_front = {layers_all, zero_offset, layers_all, zero_offset, half_extent};
VkImageCopy region_back = {layers_all, half_offset, layers_all, half_offset, half_extent};
m_commandBuffer->begin();
image_c.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_b.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_a.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
auto cb = m_commandBuffer->handle();
vk::CmdCopyImage(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->VerifyFound();
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
auto image_barrier = LvlInitStruct<VkImageMemoryBarrier>();
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_barrier.image = image_b.handle();
image_barrier.subresourceRange = full_subresource_range;
image_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
&image_barrier);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->VerifyNotFound();
// Use barrier to protect last reader, but not last writer...
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; // Protects C but not B
image_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
&image_barrier);
vk::CmdCopyImage(cb, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->VerifyFound();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_front);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_back);
m_errorMonitor->VerifyNotFound();
}
TEST_F(VkSyncValTest, SyncCopyLinearMultiPlanarHazards) {
// TODO: Add code to enable sync validation
// Enable KHR multiplane req'd extensions
bool mp_extensions = InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION);
if (mp_extensions) {
m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
}
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE_1_EXTENSION_NAME);
mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
if (mp_extensions) {
m_device_extension_names.push_back(VK_KHR_MAINTENANCE_1_EXTENSION_NAME);
m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
} else {
printf("%s test requires KHR multiplane extensions, not available. Skipping.\n", kSkipPrefix);
return;
}
ASSERT_NO_FATAL_FAILURE(InitState());
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkFormat format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
VkImageObj image_a(m_device);
const auto image_ci = VkImageObj::ImageCreateInfo2D(128, 128, 1, 1, format, usage, VK_IMAGE_TILING_LINEAR);
// Verify format
bool supported = ImageFormatAndFeaturesSupported(instance(), gpu(), image_ci,
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
if (!supported) {
printf("%s Multiplane image format not supported. Skipping test.\n", kSkipPrefix);
return; // Assume there's low ROI on searching for different mp formats
}
image_a.Init(image_ci);
VkImageObj image_b(m_device);
image_b.Init(image_ci);
VkImageObj image_c(m_device);
image_c.Init(image_ci);
VkImageSubresourceLayers layer_all_plane0{VK_IMAGE_ASPECT_PLANE_0_BIT_KHR, 0, 0, 1};
VkImageSubresourceLayers layer_all_plane1{VK_IMAGE_ASPECT_PLANE_1_BIT_KHR, 0, 0, 1};
VkImageSubresourceRange full_subresource_range{
VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR | VK_IMAGE_ASPECT_PLANE_2_BIT_KHR, 0, 1, 0, 1};
VkOffset3D zero_offset{0, 0, 0};
VkOffset3D one_four_offset{32, 32, 0};
VkExtent3D full_extent{128, 128, 1}; // <-- image type is 2D
VkExtent3D half_extent{64, 64, 1}; // <-- image type is 2D
VkExtent3D one_four_extent{32, 32, 1}; // <-- image type is 2D
VkImageCopy region_plane0_to_plane0 = {layer_all_plane0, zero_offset, layer_all_plane0, zero_offset, full_extent};
VkImageCopy region_plane0_to_plane1 = {layer_all_plane0, zero_offset, layer_all_plane1, zero_offset, half_extent};
VkImageCopy region_plane1_to_plane1_front = {layer_all_plane1, zero_offset, layer_all_plane1, zero_offset, one_four_extent};
VkImageCopy region_plane1_to_plane1_back = {layer_all_plane1, one_four_offset, layer_all_plane1, one_four_offset,
one_four_extent};
m_commandBuffer->begin();
image_c.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_b.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_a.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
auto cb = m_commandBuffer->handle();
vk::CmdCopyImage(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_plane0_to_plane0);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_plane0_to_plane0);
m_errorMonitor->VerifyFound();
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
auto image_barrier = LvlInitStruct<VkImageMemoryBarrier>();
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
image_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_barrier.image = image_a.handle();
image_barrier.subresourceRange = full_subresource_range;
image_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
&image_barrier);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_plane0_to_plane0);
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_plane0_to_plane1);
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_plane0_to_plane1);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_plane0_to_plane0);
m_errorMonitor->VerifyFound();
// NOTE: Since the previous command skips in validation, the state update is never done, and the validation layer thus doesn't
// record the write operation to b. So we'll need to repeat it successfully to set up for the *next* test.
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
auto mem_barrier = LvlInitStruct<VkMemoryBarrier>();
mem_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
mem_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &mem_barrier, 0, nullptr, 0,
nullptr);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_plane0_to_plane0);
m_errorMonitor->VerifyNotFound();
// Use barrier to protect last reader, but not last writer...
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
mem_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; // Protects C but not B
mem_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &mem_barrier, 0, nullptr, 0,
nullptr);
vk::CmdCopyImage(cb, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_plane0_to_plane0);
m_errorMonitor->VerifyFound();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_plane1_to_plane1_front);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_plane1_to_plane1_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImage(cb, image_c.handle(), VK_IMAGE_LAYOUT_GENERAL, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_plane1_to_plane1_back);
m_errorMonitor->VerifyNotFound();
m_commandBuffer->end();
}
TEST_F(VkSyncValTest, SyncCopyBufferImageHazards) {
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
ASSERT_NO_FATAL_FAILURE(InitState());
VkBufferObj buffer_a, buffer_b;
VkMemoryPropertyFlags mem_prop = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
buffer_a.init_as_src_and_dst(*m_device, 2048, mem_prop);
buffer_b.init_as_src_and_dst(*m_device, 2048, mem_prop);
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageObj image_a(m_device), image_b(m_device);
const auto image_ci = VkImageObj::ImageCreateInfo2D(32, 32, 1, 2, format, usage, VK_IMAGE_TILING_OPTIMAL);
image_a.Init(image_ci);
image_b.Init(image_ci);
VkImageSubresourceLayers layers_0{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
VkImageSubresourceLayers layers_1{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 1};
VkOffset3D zero_offset{0, 0, 0};
VkOffset3D half_offset{16, 16, 0};
VkExtent3D half_extent{16, 16, 1}; // <-- image type is 2D
VkBufferImageCopy region_buffer_front_image_0_front = {0, 16, 16, layers_0, zero_offset, half_extent};
VkBufferImageCopy region_buffer_front_image_1_front = {0, 16, 16, layers_1, zero_offset, half_extent};
VkBufferImageCopy region_buffer_front_image_1_back = {0, 16, 16, layers_1, half_offset, half_extent};
VkBufferImageCopy region_buffer_back_image_0_front = {1024, 16, 16, layers_0, zero_offset, half_extent};
VkBufferImageCopy region_buffer_back_image_0_back = {1024, 16, 16, layers_0, half_offset, half_extent};
VkBufferImageCopy region_buffer_back_image_1_front = {1024, 16, 16, layers_1, zero_offset, half_extent};
VkBufferImageCopy region_buffer_back_image_1_back = {1024, 16, 16, layers_1, half_offset, half_extent};
m_commandBuffer->begin();
image_b.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_a.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
auto cb = m_commandBuffer->handle();
vk::CmdCopyBufferToImage(cb, buffer_a.handle(), image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_buffer_front_image_0_front);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyBufferToImage(cb, buffer_a.handle(), image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_buffer_front_image_0_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
vk::CmdCopyImageToBuffer(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, buffer_a.handle(), 1,
&region_buffer_front_image_0_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
vk::CmdCopyImageToBuffer(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, buffer_a.handle(), 1,
&region_buffer_back_image_0_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyImageToBuffer(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, buffer_a.handle(), 1,
&region_buffer_front_image_1_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyImageToBuffer(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, buffer_a.handle(), 1,
&region_buffer_front_image_1_back);
m_errorMonitor->VerifyFound();
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImageToBuffer(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, buffer_a.handle(), 1, &region_buffer_back_image_0_back);
m_errorMonitor->VerifyNotFound();
auto buffer_barrier = LvlInitStruct<VkBufferMemoryBarrier>();
buffer_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
buffer_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
buffer_barrier.buffer = buffer_a.handle();
buffer_barrier.offset = 1024;
buffer_barrier.size = 2048;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1, &buffer_barrier, 0,
nullptr);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImageToBuffer(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, buffer_a.handle(), 1,
&region_buffer_back_image_1_front);
m_errorMonitor->VerifyNotFound();
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1, &buffer_barrier, 0,
nullptr);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyImageToBuffer(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, buffer_a.handle(), 1, &region_buffer_back_image_1_back);
m_errorMonitor->VerifyNotFound();
vk::CmdCopyImageToBuffer(cb, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, buffer_b.handle(), 1,
&region_buffer_front_image_0_front);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyImageToBuffer(cb, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, buffer_b.handle(), 1,
&region_buffer_front_image_0_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
vk::CmdCopyBufferToImage(cb, buffer_b.handle(), image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_buffer_front_image_0_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyBufferToImage(cb, buffer_b.handle(), image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_buffer_back_image_0_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
vk::CmdCopyBufferToImage(cb, buffer_b.handle(), image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_buffer_front_image_1_front);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
vk::CmdCopyBufferToImage(cb, buffer_b.handle(), image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_buffer_front_image_1_back);
m_errorMonitor->VerifyFound();
m_errorMonitor->ExpectSuccess();
vk::CmdCopyBufferToImage(cb, buffer_b.handle(), image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_buffer_back_image_0_back);
m_errorMonitor->VerifyNotFound();
buffer_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
buffer_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
buffer_barrier.buffer = buffer_b.handle();
buffer_barrier.offset = 1024;
buffer_barrier.size = 2048;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1, &buffer_barrier, 0,
nullptr);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyBufferToImage(cb, buffer_b.handle(), image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_buffer_back_image_1_front);
m_errorMonitor->VerifyNotFound();
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1, &buffer_barrier, 0,
nullptr);
m_errorMonitor->ExpectSuccess();
vk::CmdCopyBufferToImage(cb, buffer_b.handle(), image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_buffer_back_image_1_back);
m_errorMonitor->VerifyNotFound();
m_commandBuffer->end();
}
TEST_F(VkSyncValTest, SyncBlitImageHazards) {
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
ASSERT_NO_FATAL_FAILURE(InitState());
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageObj image_a(m_device), image_b(m_device);
const auto image_ci = VkImageObj::ImageCreateInfo2D(32, 32, 1, 2, format, usage, VK_IMAGE_TILING_OPTIMAL);
image_a.Init(image_ci);
image_b.Init(image_ci);
VkImageSubresourceLayers layers_0{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
VkImageSubresourceLayers layers_1{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 1};
VkOffset3D zero_offset{0, 0, 0};
VkOffset3D half_0_offset{16, 16, 0};
VkOffset3D half_1_offset{16, 16, 1};
VkOffset3D full_offset{32, 32, 1};
VkImageBlit region_0_front_1_front = {layers_0, {zero_offset, half_1_offset}, layers_1, {zero_offset, half_1_offset}};
VkImageBlit region_1_front_0_front = {layers_1, {zero_offset, half_1_offset}, layers_0, {zero_offset, half_1_offset}};
VkImageBlit region_1_back_0_back = {layers_1, {half_0_offset, full_offset}, layers_0, {half_0_offset, full_offset}};
m_commandBuffer->begin();
image_b.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_a.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
auto cb = m_commandBuffer->handle();
vk::CmdBlitImage(cb, image_a.image(), VK_IMAGE_LAYOUT_GENERAL, image_b.image(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_0_front_1_front, VK_FILTER_NEAREST);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdBlitImage(cb, image_a.image(), VK_IMAGE_LAYOUT_GENERAL, image_b.image(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_0_front_1_front, VK_FILTER_NEAREST);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdBlitImage(cb, image_b.image(), VK_IMAGE_LAYOUT_GENERAL, image_a.image(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_1_front_0_front, VK_FILTER_NEAREST);
m_errorMonitor->VerifyFound();
m_errorMonitor->ExpectSuccess();
vk::CmdBlitImage(cb, image_b.image(), VK_IMAGE_LAYOUT_GENERAL, image_a.image(), VK_IMAGE_LAYOUT_GENERAL, 1,
&region_1_back_0_back, VK_FILTER_NEAREST);
m_errorMonitor->VerifyNotFound();
m_commandBuffer->end();
}
TEST_F(VkSyncValTest, SyncRenderPassBeginTransitionHazard) {
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
ASSERT_NO_FATAL_FAILURE(InitState());
const VkSubpassDependency external_subpass_dependency = {VK_SUBPASS_EXTERNAL,
0,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_DEPENDENCY_BY_REGION_BIT};
m_additionalSubpassDependencies.push_back(external_subpass_dependency);
ASSERT_NO_FATAL_FAILURE(InitRenderTarget(2));
// Render Target Information
auto width = static_cast<uint32_t>(m_width);
auto height = static_cast<uint32_t>(m_height);
auto *rt_0 = m_renderTargets[0].get();
auto *rt_1 = m_renderTargets[1].get();
// Other buffers with which to interact
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageObj image_a(m_device), image_b(m_device);
const auto image_ci = VkImageObj::ImageCreateInfo2D(width, height, 1, 1, format, usage, VK_IMAGE_TILING_OPTIMAL);
image_a.Init(image_ci);
image_b.Init(image_ci);
VkOffset3D zero_offset{0, 0, 0};
VkExtent3D full_extent{width, height, 1}; // <-- image type is 2D
VkImageSubresourceLayers layer_color{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
VkImageCopy region_to_copy = {layer_color, zero_offset, layer_color, zero_offset, full_extent};
auto cb = m_commandBuffer->handle();
m_errorMonitor->ExpectSuccess();
m_commandBuffer->begin();
image_b.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_a.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
rt_0->SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
rt_1->SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
rt_0->SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
vk::CmdCopyImage(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, rt_0->handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_to_copy);
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); // This fails so the driver call is skip and no end is valid
m_errorMonitor->VerifyFound();
m_errorMonitor->ExpectSuccess();
// Use the barrier to clean up the WAW, and try again. (and show that validation is accounting for the barrier effect too.)
VkImageSubresourceRange rt_full_subresource_range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
auto image_barrier = LvlInitStruct<VkImageMemoryBarrier>();
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
image_barrier.image = rt_0->handle();
image_barrier.subresourceRange = rt_full_subresource_range;
image_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0,
nullptr, 1, &image_barrier);
vk::CmdCopyImage(cb, rt_1->handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &region_to_copy);
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); // This fails so the driver call is skip and no end is valid
m_errorMonitor->VerifyFound();
m_errorMonitor->ExpectSuccess();
// A global execution barrier that the implict external dependency can chain with should work...
vk::CmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 0,
nullptr);
// With the barrier above, the layout transition has a chained execution sync operation, and the default
// implict VkSubpassDependency safes the load op clear vs. the layout transition...
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
m_commandBuffer->EndRenderPass();
m_errorMonitor->VerifyNotFound();
}
TEST_F(VkSyncValTest, SyncCmdDispatchDrawHazards) {
// TODO: Add code to enable sync validation
SetTargetApiVersion(VK_API_VERSION_1_2);
// Enable VK_KHR_draw_indirect_count for KHR variants
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
VkPhysicalDeviceVulkan12Features features12 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, nullptr};
if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME)) {
m_device_extension_names.push_back(VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME);
if (DeviceValidationVersion() >= VK_API_VERSION_1_2) {
features12.drawIndirectCount = VK_TRUE;
}
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features12, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
bool has_khr_indirect = DeviceExtensionEnabled(VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
VkImageUsageFlags image_usage_combine = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageObj image_c_a(m_device), image_c_b(m_device);
const auto image_c_ci = VkImageObj::ImageCreateInfo2D(16, 16, 1, 1, format, image_usage_combine, VK_IMAGE_TILING_OPTIMAL);
image_c_a.Init(image_c_ci);
image_c_b.Init(image_c_ci);
VkImageView imageview_c = image_c_a.targetView(format);
VkImageUsageFlags image_usage_storage =
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkImageObj image_s_a(m_device), image_s_b(m_device);
const auto image_s_ci = VkImageObj::ImageCreateInfo2D(16, 16, 1, 1, format, image_usage_storage, VK_IMAGE_TILING_OPTIMAL);
image_s_a.Init(image_s_ci);
image_s_b.Init(image_s_ci);
image_s_a.SetLayout(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_s_b.SetLayout(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
VkImageView imageview_s = image_s_a.targetView(format);
vk_testing::Sampler sampler_s, sampler_c;
VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo();
sampler_s.init(*m_device, sampler_ci);
sampler_c.init(*m_device, sampler_ci);
VkBufferObj buffer_a, buffer_b;
VkMemoryPropertyFlags mem_prop = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
VkBufferUsageFlags buffer_usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
buffer_a.init(*m_device, buffer_a.create_info(2048, buffer_usage, nullptr), mem_prop);
buffer_b.init(*m_device, buffer_b.create_info(2048, buffer_usage, nullptr), mem_prop);
vk_testing::BufferView bufferview;
auto bvci = LvlInitStruct<VkBufferViewCreateInfo>();
bvci.buffer = buffer_a.handle();
bvci.format = VK_FORMAT_R32_SFLOAT;
bvci.offset = 0;
bvci.range = VK_WHOLE_SIZE;
bufferview.init(*m_device, bvci);
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
{2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr},
{3, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
descriptor_set.WriteDescriptorBufferInfo(0, buffer_a.handle(), 0, 2048);
descriptor_set.WriteDescriptorImageInfo(1, imageview_c, sampler_c.handle(), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_IMAGE_LAYOUT_GENERAL);
descriptor_set.WriteDescriptorImageInfo(2, imageview_s, sampler_s.handle(), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_LAYOUT_GENERAL);
descriptor_set.WriteDescriptorBufferView(3, bufferview.handle());
descriptor_set.UpdateDescriptorSets();
// Dispatch
std::string csSource = R"glsl(
#version 450
layout(set=0, binding=0) uniform foo { float x; } ub0;
layout(set=0, binding=1) uniform sampler2D cis1;
layout(set=0, binding=2, rgba8) uniform readonly image2D si2;
layout(set=0, binding=3, r32f) uniform readonly imageBuffer stb3;
void main(){
vec4 vColor4;
vColor4.x = ub0.x;
vColor4 = texture(cis1, vec2(0));
vColor4 = imageLoad(si2, ivec2(0));
vColor4 = imageLoad(stb3, 0);
}
)glsl";
VkEventObj event;
event.init(*m_device, VkEventObj::create_info(0));
VkEvent event_handle = event.handle();
CreateComputePipelineHelper pipe(*this);
pipe.InitInfo();
pipe.cs_.reset(new VkShaderObj(m_device, csSource.c_str(), VK_SHADER_STAGE_COMPUTE_BIT, this));
pipe.InitState();
pipe.pipeline_layout_ = VkPipelineLayoutObj(m_device, {&descriptor_set.layout_});
pipe.CreateComputePipeline();
m_commandBuffer->begin();
VkBufferCopy buffer_region = {0, 0, 2048};
vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_b.handle(), buffer_a.handle(), 1, &buffer_region);
VkImageSubresourceLayers layer{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
VkOffset3D zero_offset{0, 0, 0};
VkExtent3D full_extent{16, 16, 1};
VkImageCopy image_region = {layer, zero_offset, layer, zero_offset, full_extent};
vk::CmdCopyImage(m_commandBuffer->handle(), image_c_b.handle(), VK_IMAGE_LAYOUT_GENERAL, image_c_a.handle(),
VK_IMAGE_LAYOUT_GENERAL, 1, &image_region);
vk::CmdCopyImage(m_commandBuffer->handle(), image_s_b.handle(), VK_IMAGE_LAYOUT_GENERAL, image_s_a.handle(),
VK_IMAGE_LAYOUT_GENERAL, 1, &image_region);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
vk::CmdDispatch(m_commandBuffer->handle(), 1, 1, 1);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
vk::CmdDispatch(m_commandBuffer->handle(), 1, 1, 1);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_b.handle(), buffer_a.handle(), 1, &buffer_region);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyImage(m_commandBuffer->handle(), image_c_b.handle(), VK_IMAGE_LAYOUT_GENERAL, image_c_a.handle(),
VK_IMAGE_LAYOUT_GENERAL, 1, &image_region);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
m_commandBuffer->reset();
// DispatchIndirect
m_errorMonitor->ExpectSuccess();
VkBufferObj buffer_dispatchIndirect, buffer_dispatchIndirect2;
buffer_usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
buffer_dispatchIndirect.init(
*m_device, buffer_dispatchIndirect.create_info(sizeof(VkDispatchIndirectCommand), buffer_usage, nullptr), mem_prop);
buffer_dispatchIndirect2.init(
*m_device, buffer_dispatchIndirect2.create_info(sizeof(VkDispatchIndirectCommand), buffer_usage, nullptr), mem_prop);
m_commandBuffer->begin();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
vk::CmdDispatchIndirect(m_commandBuffer->handle(), buffer_dispatchIndirect.handle(), 0);
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
buffer_region = {0, 0, sizeof(VkDispatchIndirectCommand)};
vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_dispatchIndirect2.handle(), buffer_dispatchIndirect.handle(), 1,
&buffer_region);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
vk::CmdDispatchIndirect(m_commandBuffer->handle(), buffer_dispatchIndirect.handle(), 0);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
// Draw
m_errorMonitor->ExpectSuccess();
const float vbo_data[3] = {1.f, 0.f, 1.f};
VkVertexInputAttributeDescription VertexInputAttributeDescription = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, sizeof(vbo_data)};
VkVertexInputBindingDescription VertexInputBindingDescription = {0, sizeof(vbo_data), VK_VERTEX_INPUT_RATE_VERTEX};
VkBufferObj vbo, vbo2;
buffer_usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
vbo.init(*m_device, vbo.create_info(sizeof(vbo_data), buffer_usage, nullptr), mem_prop);
vbo2.init(*m_device, vbo2.create_info(sizeof(vbo_data), buffer_usage, nullptr), mem_prop);
VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this);
VkShaderObj fs(m_device, csSource.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT, this);
CreatePipelineHelper g_pipe(*this);
g_pipe.InitInfo();
g_pipe.InitState();
g_pipe.vi_ci_.pVertexBindingDescriptions = &VertexInputBindingDescription;
g_pipe.vi_ci_.vertexBindingDescriptionCount = 1;
g_pipe.vi_ci_.pVertexAttributeDescriptions = &VertexInputAttributeDescription;
g_pipe.vi_ci_.vertexAttributeDescriptionCount = 1;
g_pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
g_pipe.pipeline_layout_ = VkPipelineLayoutObj(m_device, {&descriptor_set.layout_});
ASSERT_VK_SUCCESS(g_pipe.CreateGraphicsPipeline());
m_commandBuffer->reset();
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
VkDeviceSize offset = 0;
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
VkViewport viewport = {0, 0, 16, 16, 0, 1};
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
VkRect2D scissor = {{0, 0}, {16, 16}};
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
buffer_region = {0, 0, sizeof(vbo_data)};
vk::CmdCopyBuffer(m_commandBuffer->handle(), vbo2.handle(), vbo.handle(), 1, &buffer_region);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
// Repeat the draw test with a WaitEvent to protect it.
m_errorMonitor->ExpectSuccess();
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdCopyBuffer(m_commandBuffer->handle(), vbo2.handle(), vbo.handle(), 1, &buffer_region);
auto vbo_barrier = LvlInitStruct<VkBufferMemoryBarrier>();
vbo_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vbo_barrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
vbo_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vbo_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vbo_barrier.buffer = vbo.handle();
vbo_barrier.offset = buffer_region.dstOffset;
vbo_barrier.size = buffer_region.size;
m_commandBuffer->SetEvent(event, VK_PIPELINE_STAGE_TRANSFER_BIT);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
m_commandBuffer->WaitEvents(1, &event_handle, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, nullptr, 1,
&vbo_barrier, 0, nullptr);
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
// DrawIndexed
m_errorMonitor->ExpectSuccess();
const float ibo_data[3] = {0.f, 0.f, 0.f};
VkBufferObj ibo, ibo2;
buffer_usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
ibo.init(*m_device, ibo.create_info(sizeof(ibo_data), buffer_usage, nullptr), mem_prop);
ibo2.init(*m_device, ibo2.create_info(sizeof(ibo_data), buffer_usage, nullptr), mem_prop);
m_commandBuffer->reset();
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), ibo.handle(), 0, VK_INDEX_TYPE_UINT16);
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
m_commandBuffer->DrawIndexed(3, 1, 0, 0, 0);
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
buffer_region = {0, 0, sizeof(ibo_data)};
vk::CmdCopyBuffer(m_commandBuffer->handle(), ibo2.handle(), ibo.handle(), 1, &buffer_region);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), ibo.handle(), 0, VK_INDEX_TYPE_UINT16);
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
m_commandBuffer->DrawIndexed(3, 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
// DrawIndirect
m_errorMonitor->ExpectSuccess();
VkBufferObj buffer_drawIndirect, buffer_drawIndirect2;
buffer_usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
buffer_drawIndirect.init(*m_device, buffer_drawIndirect.create_info(sizeof(VkDrawIndirectCommand), buffer_usage, nullptr),
mem_prop);
buffer_drawIndirect2.init(*m_device, buffer_drawIndirect2.create_info(sizeof(VkDrawIndirectCommand), buffer_usage, nullptr),
mem_prop);
m_commandBuffer->reset();
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
vk::CmdDrawIndirect(m_commandBuffer->handle(), buffer_drawIndirect.handle(), 0, 1, sizeof(VkDrawIndirectCommand));
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
buffer_region = {0, 0, sizeof(VkDrawIndirectCommand)};
vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_drawIndirect2.handle(), buffer_drawIndirect.handle(), 1, &buffer_region);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
vk::CmdDrawIndirect(m_commandBuffer->handle(), buffer_drawIndirect.handle(), 0, 1, sizeof(VkDrawIndirectCommand));
m_errorMonitor->VerifyFound();
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
// DrawIndexedIndirect
m_errorMonitor->ExpectSuccess();
VkBufferObj buffer_drawIndexedIndirect, buffer_drawIndexedIndirect2;
buffer_usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
buffer_drawIndexedIndirect.init(
*m_device, buffer_drawIndexedIndirect.create_info(sizeof(VkDrawIndexedIndirectCommand), buffer_usage, nullptr), mem_prop);
buffer_drawIndexedIndirect2.init(
*m_device, buffer_drawIndexedIndirect2.create_info(sizeof(VkDrawIndexedIndirectCommand), buffer_usage, nullptr), mem_prop);
m_commandBuffer->reset();
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), ibo.handle(), 0, VK_INDEX_TYPE_UINT16);
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), buffer_drawIndirect.handle(), 0, 1, sizeof(VkDrawIndexedIndirectCommand));
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
buffer_region = {0, 0, sizeof(VkDrawIndexedIndirectCommand)};
vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_drawIndexedIndirect2.handle(), buffer_drawIndexedIndirect.handle(), 1,
&buffer_region);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), ibo.handle(), 0, VK_INDEX_TYPE_UINT16);
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), buffer_drawIndexedIndirect.handle(), 0, 1,
sizeof(VkDrawIndexedIndirectCommand));
m_errorMonitor->VerifyFound();
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
if (has_khr_indirect) {
// DrawIndirectCount
auto fpCmdDrawIndirectCountKHR =
(PFN_vkCmdDrawIndirectCount)vk::GetDeviceProcAddr(m_device->device(), "vkCmdDrawIndirectCountKHR");
if (!fpCmdDrawIndirectCountKHR) {
printf("%s Test requires unsupported vkCmdDrawIndirectCountKHR feature. Skipped.\n", kSkipPrefix);
} else {
m_errorMonitor->ExpectSuccess();
VkBufferObj buffer_count, buffer_count2;
buffer_usage =
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
buffer_count.init(*m_device, buffer_count.create_info(sizeof(uint32_t), buffer_usage, nullptr), mem_prop);
buffer_count2.init(*m_device, buffer_count2.create_info(sizeof(uint32_t), buffer_usage, nullptr), mem_prop);
m_commandBuffer->reset();
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(),
0, 1, &descriptor_set.set_, 0, nullptr);
fpCmdDrawIndirectCountKHR(m_commandBuffer->handle(), buffer_drawIndirect.handle(), 0, buffer_count.handle(), 0, 1,
sizeof(VkDrawIndirectCommand));
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
buffer_region = {0, 0, sizeof(uint32_t)};
vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_count2.handle(), buffer_count.handle(), 1, &buffer_region);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(),
0, 1, &descriptor_set.set_, 0, nullptr);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
fpCmdDrawIndirectCountKHR(m_commandBuffer->handle(), buffer_drawIndirect.handle(), 0, buffer_count.handle(), 0, 1,
sizeof(VkDrawIndirectCommand));
m_errorMonitor->VerifyFound();
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
// DrawIndexedIndirectCount
auto fpCmdDrawIndexIndirectCountKHR =
(PFN_vkCmdDrawIndirectCount)vk::GetDeviceProcAddr(m_device->device(), "vkCmdDrawIndexedIndirectCountKHR");
if (!fpCmdDrawIndexIndirectCountKHR) {
printf("%s Test requires unsupported vkCmdDrawIndexedIndirectCountKHR feature. Skipped.\n", kSkipPrefix);
} else {
m_errorMonitor->ExpectSuccess();
VkBufferObj buffer_count, buffer_count2;
buffer_usage =
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
buffer_count.init(*m_device, buffer_count.create_info(sizeof(uint32_t), buffer_usage, nullptr), mem_prop);
buffer_count2.init(*m_device, buffer_count2.create_info(sizeof(uint32_t), buffer_usage, nullptr), mem_prop);
m_commandBuffer->reset();
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), ibo.handle(), 0, VK_INDEX_TYPE_UINT16);
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(),
0, 1, &descriptor_set.set_, 0, nullptr);
fpCmdDrawIndexIndirectCountKHR(m_commandBuffer->handle(), buffer_drawIndexedIndirect.handle(), 0, buffer_count.handle(),
0, 1, sizeof(VkDrawIndexedIndirectCommand));
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
buffer_region = {0, 0, sizeof(uint32_t)};
vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_count2.handle(), buffer_count.handle(), 1, &buffer_region);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), ibo.handle(), 0, VK_INDEX_TYPE_UINT16);
vk::CmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
vk::CmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(),
0, 1, &descriptor_set.set_, 0, nullptr);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-READ_AFTER_WRITE");
fpCmdDrawIndexIndirectCountKHR(m_commandBuffer->handle(), buffer_drawIndexedIndirect.handle(), 0, buffer_count.handle(),
0, 1, sizeof(VkDrawIndexedIndirectCommand));
m_errorMonitor->VerifyFound();
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
} else {
printf("%s Test requires unsupported vkCmdDrawIndirectCountKHR & vkDrawIndexedIndirectCountKHR feature. Skipped.\n",
kSkipPrefix);
}
}
TEST_F(VkSyncValTest, SyncCmdClear) {
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
// CmdClearColorImage
m_errorMonitor->ExpectSuccess();
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageObj image_a(m_device), image_b(m_device);
auto image_ci = VkImageObj::ImageCreateInfo2D(128, 128, 1, 1, format, usage, VK_IMAGE_TILING_OPTIMAL);
image_a.Init(image_ci);
image_b.Init(image_ci);
VkImageSubresourceLayers layers_all{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
VkOffset3D zero_offset{0, 0, 0};
VkExtent3D full_extent{128, 128, 1}; // <-- image type is 2D
VkImageSubresourceRange full_subresource_range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
VkImageCopy full_region = {layers_all, zero_offset, layers_all, zero_offset, full_extent};
m_commandBuffer->begin();
image_b.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
image_a.SetLayout(m_commandBuffer, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
auto cb = m_commandBuffer->handle();
VkClearColorValue ccv = {};
vk::CmdClearColorImage(m_commandBuffer->handle(), image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, &ccv, 1, &full_subresource_range);
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdCopyImage(cb, image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, &full_region);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdClearColorImage(m_commandBuffer->handle(), image_a.handle(), VK_IMAGE_LAYOUT_GENERAL, &ccv, 1, &full_subresource_range);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdClearColorImage(m_commandBuffer->handle(), image_b.handle(), VK_IMAGE_LAYOUT_GENERAL, &ccv, 1, &full_subresource_range);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
// CmdClearDepthStencilImage
format = FindSupportedDepthStencilFormat(gpu());
if (!format) {
printf("%s No Depth + Stencil format found. Skipped.\n", kSkipPrefix);
return;
}
m_errorMonitor->ExpectSuccess();
VkImageObj image_ds_a(m_device), image_ds_b(m_device);
image_ci = VkImageObj::ImageCreateInfo2D(128, 128, 1, 1, format, usage, VK_IMAGE_TILING_OPTIMAL);
image_ds_a.Init(image_ci);
image_ds_b.Init(image_ci);
const VkImageAspectFlags ds_aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
image_ds_a.SetLayout(ds_aspect, VK_IMAGE_LAYOUT_GENERAL);
image_ds_b.SetLayout(ds_aspect, VK_IMAGE_LAYOUT_GENERAL);
m_commandBuffer->begin();
const VkClearDepthStencilValue clear_value = {};
VkImageSubresourceRange ds_range = {ds_aspect, 0, 1, 0, 1};
vk::CmdClearDepthStencilImage(cb, image_ds_a.handle(), VK_IMAGE_LAYOUT_GENERAL, &clear_value, 1, &ds_range);
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
VkImageSubresourceLayers ds_layers_all{ds_aspect, 0, 0, 1};
VkImageCopy ds_full_region = {ds_layers_all, zero_offset, ds_layers_all, zero_offset, full_extent};
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdCopyImage(cb, image_ds_a.handle(), VK_IMAGE_LAYOUT_GENERAL, image_ds_b.handle(), VK_IMAGE_LAYOUT_GENERAL, 1,
&ds_full_region);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdClearDepthStencilImage(m_commandBuffer->handle(), image_ds_a.handle(), VK_IMAGE_LAYOUT_GENERAL, &clear_value, 1,
&ds_range);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdClearDepthStencilImage(m_commandBuffer->handle(), image_ds_b.handle(), VK_IMAGE_LAYOUT_GENERAL, &clear_value, 1,
&ds_range);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(VkSyncValTest, SyncCmdQuery) {
// CmdCopyQueryPoolResults
m_errorMonitor->ExpectSuccess();
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
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;
}
vk_testing::QueryPool 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;
query_pool.init(*m_device, query_pool_create_info);
VkBufferObj buffer_a, buffer_b;
VkMemoryPropertyFlags mem_prop = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
buffer_a.init_as_src_and_dst(*m_device, 256, mem_prop);
buffer_b.init_as_src_and_dst(*m_device, 256, mem_prop);
VkBufferCopy region = {0, 0, 256};
auto cb = m_commandBuffer->handle();
m_commandBuffer->begin();
vk::CmdResetQueryPool(cb, query_pool.handle(), 0, 1);
vk::CmdWriteTimestamp(cb, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool.handle(), 0);
vk::CmdCopyQueryPoolResults(cb, query_pool.handle(), 0, 1, buffer_a.handle(), 0, 0, VK_QUERY_RESULT_WAIT_BIT);
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
vk::CmdCopyBuffer(cb, buffer_a.handle(), buffer_b.handle(), 1, &region);
vk::CmdResetQueryPool(cb, query_pool.handle(), 0, 1);
vk::CmdWriteTimestamp(cb, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool.handle(), 0);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
vk::CmdCopyQueryPoolResults(cb, query_pool.handle(), 0, 1, buffer_a.handle(), 0, 256, VK_QUERY_RESULT_WAIT_BIT);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
vk::CmdCopyQueryPoolResults(cb, query_pool.handle(), 0, 1, buffer_b.handle(), 0, 256, VK_QUERY_RESULT_WAIT_BIT);
m_commandBuffer->end();
m_errorMonitor->VerifyFound();
// TODO:Track VkQueryPool
// TODO:CmdWriteTimestamp
}
TEST_F(VkSyncValTest, SyncCmdDrawDepthStencil) {
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
m_errorMonitor->ExpectSuccess();
const auto format_ds = FindSupportedDepthStencilFormat(gpu());
if (!format_ds) {
printf("%s No Depth + Stencil format found. Skipped.\n", kSkipPrefix);
return;
}
const auto format_dp = FindSupportedDepthOnlyFormat(gpu());
if (!format_dp) {
printf("%s No only Depth format found. Skipped.\n", kSkipPrefix);
return;
}
const auto format_st = FindSupportedStencilOnlyFormat(gpu());
if (!format_st) {
printf("%s No only Stencil format found. Skipped.\n", kSkipPrefix);
return;
}
VkDepthStencilObj image_ds(m_device), image_dp(m_device), image_st(m_device);
image_ds.Init(m_device, 16, 16, format_ds);
image_dp.Init(m_device, 16, 16, format_dp);
image_st.Init(m_device, 16, 16, format_st);
VkRenderpassObj rp_ds(m_device, format_ds, true), rp_dp(m_device, format_dp, true), rp_st(m_device, format_st, true);
vk_testing::Framebuffer fb_ds, fb_dp, fb_st;
VkFramebufferCreateInfo fbci = {
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp_ds.handle(), 1, image_ds.BindInfo(), 16, 16, 1};
fb_ds.init(*m_device, fbci);
fbci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp_dp.handle(), 1, image_dp.BindInfo(), 16, 16, 1};
fb_dp.init(*m_device, fbci);
fbci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp_st.handle(), 1, image_st.BindInfo(), 16, 16, 1};
fb_st.init(*m_device, fbci);
VkStencilOpState stencil = {};
stencil.failOp = VK_STENCIL_OP_KEEP;
stencil.passOp = VK_STENCIL_OP_KEEP;
stencil.depthFailOp = VK_STENCIL_OP_KEEP;
stencil.compareOp = VK_COMPARE_OP_NEVER;
auto ds_ci = LvlInitStruct<VkPipelineDepthStencilStateCreateInfo>();
ds_ci.depthTestEnable = VK_TRUE;
ds_ci.depthWriteEnable = VK_TRUE;
ds_ci.depthCompareOp = VK_COMPARE_OP_NEVER;
ds_ci.stencilTestEnable = VK_TRUE;
ds_ci.front = stencil;
ds_ci.back = stencil;
CreatePipelineHelper g_pipe_ds(*this), g_pipe_dp(*this), g_pipe_st(*this);
g_pipe_ds.InitInfo();
g_pipe_ds.gp_ci_.renderPass = rp_ds.handle();
g_pipe_ds.gp_ci_.pDepthStencilState = &ds_ci;
g_pipe_ds.InitState();
ASSERT_VK_SUCCESS(g_pipe_ds.CreateGraphicsPipeline());
g_pipe_dp.InitInfo();
g_pipe_dp.gp_ci_.renderPass = rp_dp.handle();
ds_ci.stencilTestEnable = VK_FALSE;
g_pipe_dp.gp_ci_.pDepthStencilState = &ds_ci;
g_pipe_dp.InitState();
ASSERT_VK_SUCCESS(g_pipe_dp.CreateGraphicsPipeline());
g_pipe_st.InitInfo();
g_pipe_st.gp_ci_.renderPass = rp_st.handle();
ds_ci.depthTestEnable = VK_FALSE;
ds_ci.stencilTestEnable = VK_TRUE;
g_pipe_st.gp_ci_.pDepthStencilState = &ds_ci;
g_pipe_st.InitState();
ASSERT_VK_SUCCESS(g_pipe_st.CreateGraphicsPipeline());
m_commandBuffer->begin();
m_renderPassBeginInfo.renderArea = {{0, 0}, {16, 16}};
m_renderPassBeginInfo.pClearValues = nullptr;
m_renderPassBeginInfo.clearValueCount = 0;
m_renderPassBeginInfo.renderPass = rp_ds.handle();
m_renderPassBeginInfo.framebuffer = fb_ds.handle();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe_ds.pipeline_);
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_commandBuffer->EndRenderPass();
m_renderPassBeginInfo.renderPass = rp_dp.handle();
m_renderPassBeginInfo.framebuffer = fb_dp.handle();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe_dp.pipeline_);
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_commandBuffer->EndRenderPass();
m_renderPassBeginInfo.renderPass = rp_st.handle();
m_renderPassBeginInfo.framebuffer = fb_st.handle();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe_st.pipeline_);
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
m_errorMonitor->VerifyNotFound();
m_commandBuffer->reset();
m_commandBuffer->begin();
VkImageCopy copyRegion;
copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
copyRegion.srcSubresource.mipLevel = 0;
copyRegion.srcSubresource.baseArrayLayer = 0;
copyRegion.srcSubresource.layerCount = 1;
copyRegion.srcOffset = {0, 0, 0};
copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
copyRegion.dstSubresource.mipLevel = 0;
copyRegion.dstSubresource.baseArrayLayer = 0;
copyRegion.dstSubresource.layerCount = 1;
copyRegion.dstOffset = {0, 0, 0};
copyRegion.extent = {16, 16, 1};
m_commandBuffer->CopyImage(image_ds.handle(), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, image_dp.handle(),
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1, &copyRegion);
copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
m_commandBuffer->CopyImage(image_ds.handle(), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, image_st.handle(),
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1, &copyRegion);
m_renderPassBeginInfo.renderPass = rp_ds.handle();
m_renderPassBeginInfo.framebuffer = fb_ds.handle();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_READ");
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
m_errorMonitor->VerifyFound();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe_ds.pipeline_);
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_commandBuffer->EndRenderPass();
m_renderPassBeginInfo.renderPass = rp_dp.handle();
m_renderPassBeginInfo.framebuffer = fb_dp.handle();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
m_errorMonitor->VerifyFound();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe_dp.pipeline_);
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_commandBuffer->EndRenderPass();
m_renderPassBeginInfo.renderPass = rp_st.handle();
m_renderPassBeginInfo.framebuffer = fb_st.handle();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "SYNC-HAZARD-WRITE_AFTER_WRITE");
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
m_errorMonitor->VerifyFound();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe_st.pipeline_);
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
TEST_F(VkSyncValTest, RenderPassLoadHazardVsInitialLayout) {
ASSERT_NO_FATAL_FAILURE(InitSyncValFramework());
bool do_none_load_op_test = false;
if (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME)) {
m_device_extension_names.push_back(VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME);
do_none_load_op_test = true;
}
ASSERT_NO_FATAL_FAILURE(InitState());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
VkImageUsageFlags usage_color = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
VkImageUsageFlags usage_input = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageObj image_color(m_device), image_input(m_device);
auto image_ci = VkImageObj::ImageCreateInfo2D(32, 32, 1, 1, format, usage_color, VK_IMAGE_TILING_OPTIMAL);
image_color.Init(image_ci);
image_ci.usage = usage_input;
image_input.Init(image_ci);
VkImageView attachments[] = {image_color.targetView(format), image_input.targetView(format)};
VkAttachmentDescription attachmentDescriptions[] = {
// Result attachment
{(VkAttachmentDescriptionFlags)0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR,
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_UNDEFINED, // Here causes DesiredError that SYNC-HAZARD-NONE in BeginRenderPass.
// It should be VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
// Input attachment
{(VkAttachmentDescriptionFlags)0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}};
const VkAttachmentReference resultAttachmentRef = {0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
const VkAttachmentReference inputAttachmentRef = {1u, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
const VkSubpassDescription subpassDescription = {(VkSubpassDescriptionFlags)0,
VK_PIPELINE_BIND_POINT_GRAPHICS,
1u,
&inputAttachmentRef,
1u,
&resultAttachmentRef,
0,
0,
0u,
0};
const VkSubpassDependency subpassDependency = {VK_SUBPASS_EXTERNAL,
0,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT,
VK_DEPENDENCY_BY_REGION_BIT};
const VkRenderPassCreateInfo renderPassInfo = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
0,
(VkRenderPassCreateFlags)0,
2u,