From e5ba6e5bd2c8dd93d6d977a620ae9b1a4675d1ba Mon Sep 17 00:00:00 2001 From: Tony Barbour Date: Mon, 14 Aug 2023 12:05:54 -0600 Subject: [PATCH] tests: Add a positive test for host image copy Also share utils between positive and negative tests --- tests/CMakeLists.txt | 1 + tests/framework/layer_validation_tests.h | 10 +- tests/unit/host_image_copy.cpp | 31 +++-- tests/unit/host_image_copy_positive.cpp | 161 +++++++++++++++++++++++ 4 files changed, 184 insertions(+), 19 deletions(-) create mode 100644 tests/unit/host_image_copy_positive.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8f2315ad15a..c48016cd221 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -72,6 +72,7 @@ target_sources(vk_layer_validation_tests PRIVATE unit/graphics_library.cpp unit/graphics_library_positive.cpp unit/host_image_copy.cpp + unit/host_image_copy_positive.cpp unit/image.cpp unit/image_positive.cpp unit/imageless_framebuffer.cpp diff --git a/tests/framework/layer_validation_tests.h b/tests/framework/layer_validation_tests.h index ad8bd77fe73..2ada28d72cc 100644 --- a/tests/framework/layer_validation_tests.h +++ b/tests/framework/layer_validation_tests.h @@ -415,12 +415,16 @@ class GraphicsLibraryTest : public VkLayerTest { class NegativeGraphicsLibrary : public GraphicsLibraryTest {}; class PositiveGraphicsLibrary : public GraphicsLibraryTest {}; -class NegativeHostImageCopy : public virtual VkLayerTest { - protected: - void InitHostImageCopyTest(const VkImageCreateInfo image_ci, std::vector ©_src_layouts, +class HostImageCopyTest : public VkLayerTest { + public: + void InitHostImageCopyTest(const VkImageCreateInfo &image_ci, std::vector ©_src_layouts, std::vector ©_dst_layouts, VkFormat &compressed_format, bool &separate_depth_stencil); + bool CopyLayoutSupported(const std::vector ©_src_layouts, const std::vector ©_dst_layouts, + VkImageLayout layout); }; +class NegativeHostImageCopy : public HostImageCopyTest {}; +class PositiveHostImageCopy : public HostImageCopyTest {}; class ImageTest : public VkLayerTest { public: diff --git a/tests/unit/host_image_copy.cpp b/tests/unit/host_image_copy.cpp index 093d26d641b..2dd6dd1a057 100644 --- a/tests/unit/host_image_copy.cpp +++ b/tests/unit/host_image_copy.cpp @@ -15,16 +15,15 @@ #include "utils/vk_layer_utils.h" #include "generated/enum_flag_bits.h" -bool copy_layout_supported(std::vector ©_src_layouts, std::vector ©_dst_layouts, - VkImageLayout layout) { +bool HostImageCopyTest::CopyLayoutSupported(const std::vector ©_src_layouts, + const std::vector ©_dst_layouts, VkImageLayout layout) { return ((std::find(copy_src_layouts.begin(), copy_src_layouts.end(), layout) != copy_src_layouts.end()) && (std::find(copy_dst_layouts.begin(), copy_dst_layouts.end(), layout) != copy_dst_layouts.end())); } -void NegativeHostImageCopy::InitHostImageCopyTest(const VkImageCreateInfo image_ci, - std::vector ©_src_layouts, - std::vector ©_dst_layouts, VkFormat &compressed_format, - bool &separate_depth_stencil) { +void HostImageCopyTest::InitHostImageCopyTest(const VkImageCreateInfo &image_ci, std::vector ©_src_layouts, + std::vector ©_dst_layouts, VkFormat &compressed_format, + bool &separate_depth_stencil) { SetTargetApiVersion(VK_API_VERSION_1_2); AddRequiredExtensions(VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME); ASSERT_NO_FATAL_FAILURE(InitFramework()); @@ -68,8 +67,8 @@ void NegativeHostImageCopy::InitHostImageCopyTest(const VkImageCreateInfo image_ host_image_copy_props.pCopySrcLayouts = copy_src_layouts.data(); host_image_copy_props.pCopyDstLayouts = copy_dst_layouts.data(); GetPhysicalDeviceProperties2(host_image_copy_props); - if (!copy_layout_supported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) || - !copy_layout_supported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_GENERAL)) { + if (!CopyLayoutSupported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) || + !CopyLayoutSupported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_GENERAL)) { GTEST_SKIP() << "Required formats/features not supported"; } } @@ -529,7 +528,7 @@ TEST_F(NegativeHostImageCopy, HostCopyImageToFromMemory) { region_to_image.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region_from_image.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - if (copy_layout_supported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)) { + if (CopyLayoutSupported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)) { auto stencil_format = FindSupportedDepthStencilFormat(gpu()); VkImageObj image_stencil(m_device); image_ci.format = stencil_format; @@ -659,7 +658,7 @@ TEST_F(NegativeHostImageCopy, HostCopyImageToFromMemory) { copy_from_image.srcImage = image; } - if (!copy_layout_supported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)) { + if (!CopyLayoutSupported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)) { // layout must be one of the image layouts returned in VkPhysicalDeviceHostImageCopyPropertiesEXT::pCopySrcLayouts image.SetLayout(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); copy_to_image.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; @@ -788,7 +787,7 @@ TEST_F(NegativeHostImageCopy, HostCopyImageToImage) { // Note that because the images need to be identical to avoid 09069, we'll go ahead and test for src and dst errors in one call - if (copy_layout_supported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)) { + if (CopyLayoutSupported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)) { auto stencil_format = FindSupportedDepthStencilFormat(gpu()); VkImageObj image_stencil1(m_device); VkImageObj image_stencil2(m_device); @@ -1200,7 +1199,7 @@ TEST_F(NegativeHostImageCopy, HostCopyImageToImage) { copy_image_to_image.srcImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; copy_image_to_image.dstImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - if (!copy_layout_supported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)) { + if (!CopyLayoutSupported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)) { // layout must be one of the image layouts returned in VkPhysicalDeviceHostImageCopyPropertiesEXT::pCopySrcLayouts image1.SetLayout(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); image2.SetLayout(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); @@ -1403,9 +1402,9 @@ TEST_F(NegativeHostImageCopy, HostTransitionImageLayout) { transition_info.image = image; } - if (copy_layout_supported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) && - copy_layout_supported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL) && - copy_layout_supported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL)) { + if (CopyLayoutSupported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) && + CopyLayoutSupported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL) && + CopyLayoutSupported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL)) { auto stencil_format = FindSupportedDepthStencilFormat(gpu()); if (VK_SUCCESS == vk::GetPhysicalDeviceImageFormatProperties( m_device->phy().handle(), stencil_format, image_ci.imageType, image_ci.tiling, @@ -1462,7 +1461,7 @@ TEST_F(NegativeHostImageCopy, HostTransitionImageLayout) { } } - if (!copy_layout_supported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)) { + if (!CopyLayoutSupported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)) { // layout must be one of the image layouts returned in VkPhysicalDeviceHostImageCopyPropertiesEXT::pCopySrcLayouts image.SetLayout(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); transition_info.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; diff --git a/tests/unit/host_image_copy_positive.cpp b/tests/unit/host_image_copy_positive.cpp new file mode 100644 index 00000000000..66c590fb9a5 --- /dev/null +++ b/tests/unit/host_image_copy_positive.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2023 The Khronos Group Inc. + * Copyright (c) 2023 Valve Corporation + * Copyright (c) 2023 LunarG, Inc. + * Copyright (c) 2023 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include "../framework/layer_validation_tests.h" +#include "utils/vk_layer_utils.h" + +TEST_F(PositiveHostImageCopy, BasicUsage) { + TEST_DESCRIPTION("Use VK_EXT_host_image_copy to copy to and from host memory"); + + VkFormat compressed_format = VK_FORMAT_UNDEFINED; + bool separate_depth_stencil = false; + std::vector copy_src_layouts; + std::vector copy_dst_layouts; + uint32_t width = 32; + uint32_t height = 32; + VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; + auto image_ci = VkImageObj::ImageCreateInfo2D( + width, height, 1, 1, format, + VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + VK_IMAGE_TILING_OPTIMAL); + InitHostImageCopyTest(image_ci, copy_src_layouts, copy_dst_layouts, compressed_format, + separate_depth_stencil); + if (::testing::Test::IsSkipped()) return; + + if (IsPlatform(kMockICD)) { + GTEST_SKIP() << "Positive host image copy test requires a driver that can copy."; + } + if (!CopyLayoutSupported(copy_src_layouts, copy_dst_layouts, VK_IMAGE_LAYOUT_GENERAL)) { + GTEST_SKIP() << "Required formats/features not supported"; + } + + VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL; + VkImageObj image(m_device); + image.Init(image_ci); + image.SetLayout(VK_IMAGE_ASPECT_COLOR_BIT, layout); + + std::vector pixels(width * height * 4); + // Fill image with random values + for (auto &channel : pixels) { + const uint32_t r = static_cast(std::rand()); + channel = static_cast((r & 0xffu) | ((r >> 8) & 0xff) | ((r >> 16) & 0xff) | (r >> 24)); + } + + auto region_to_image = LvlInitStruct(); + region_to_image.pHostPointer = pixels.data(); + region_to_image.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region_to_image.imageSubresource.layerCount = 1; + region_to_image.imageExtent.width = width; + region_to_image.imageExtent.height = height; + region_to_image.imageExtent.depth = 1; + + auto copy_to_image = LvlInitStruct(); + copy_to_image.flags = 0; + copy_to_image.dstImage = image; + copy_to_image.dstImageLayout = layout; + copy_to_image.regionCount = 1; + copy_to_image.pRegions = ®ion_to_image; + + VkResult result = vk::CopyMemoryToImageEXT(*m_device, ©_to_image); + ASSERT_VK_SUCCESS(result); + + // Copy back to host memory + std::vector welcome_back(width * height * 4); + + auto region_from_image = LvlInitStruct(); + region_from_image.pHostPointer = welcome_back.data(); + region_from_image.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region_from_image.imageSubresource.layerCount = 1; + region_from_image.imageExtent.width = width; + region_from_image.imageExtent.height = height; + region_from_image.imageExtent.depth = 1; + + auto copy_from_image = LvlInitStruct(); + copy_from_image.flags = 0; + copy_from_image.srcImage = image; + copy_from_image.srcImageLayout = layout; + copy_from_image.regionCount = 1; + copy_from_image.pRegions = ®ion_from_image; + + result = vk::CopyImageToMemoryEXT(*m_device, ©_from_image); + ASSERT_VK_SUCCESS(result); + ASSERT_EQ(pixels, welcome_back); + + // Copy from one image to another + VkImageObj image2(m_device); + image2.Init(image_ci); + image2.SetLayout(VK_IMAGE_ASPECT_COLOR_BIT, layout); + + auto image_copy_2 = LvlInitStruct(); + image_copy_2.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + image_copy_2.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + image_copy_2.extent = {width, height, 1}; + auto copy_image_to_image = LvlInitStruct(); + copy_image_to_image.regionCount = 1; + copy_image_to_image.pRegions = &image_copy_2; + copy_image_to_image.srcImageLayout = layout; + copy_image_to_image.dstImageLayout = layout; + copy_image_to_image.srcImage = image; + copy_image_to_image.dstImage = image2; + + result = vk::CopyImageToImageEXT(*m_device, ©_image_to_image); + ASSERT_VK_SUCCESS(result); + + // Copy back from destination image to memory + std::vector after_image_copy(width * height * 4); + + copy_from_image.srcImage = image2; + region_from_image.pHostPointer = after_image_copy.data(); + result = vk::CopyImageToMemoryEXT(*m_device, ©_from_image); + ASSERT_VK_SUCCESS(result); + ASSERT_EQ(pixels, after_image_copy); + + // Do a layout transition, then use the image in new layout + auto transition_info = LvlInitStruct(); + transition_info.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + transition_info.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + transition_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + transition_info.image = image2; + result = vk::TransitionImageLayoutEXT(*m_device, 1, &transition_info); + ASSERT_VK_SUCCESS(result); + VkImageSubresource image_sub = VkImageObj::subresource(VK_IMAGE_ASPECT_COLOR_BIT, 0, 0); + VkImageSubresourceRange image_sub_range = VkImageObj::subresource_range(image_sub); + VkImageMemoryBarrier image_barrier = + image2.image_memory_barrier(0, 0, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, image_sub_range); + + image_barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + m_commandBuffer->begin(); + vk::CmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, + nullptr, 0, nullptr, 1, &image_barrier); + m_commandBuffer->end(); + m_commandBuffer->QueueCommandBuffer(true); + + // Get memory size of tiled image + auto subresource = LvlInitStruct(); + subresource.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + auto host_copy_size = LvlInitStruct(); + auto subresource_layout = LvlInitStruct(&host_copy_size); + vk::GetImageSubresourceLayout2EXT(*m_device, image, &subresource, &subresource_layout); + ASSERT_NE(host_copy_size.size, 0); + + auto perf_data = LvlInitStruct(); + auto image_format_properties = LvlInitStruct(&perf_data); + auto image_format_info = LvlInitStruct(); + image_format_info.format = VK_FORMAT_R8G8B8A8_UNORM; + image_format_info.type = VK_IMAGE_TYPE_2D; + image_format_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_format_info.usage = VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT; + image_format_info.flags = 0; + vk::GetPhysicalDeviceImageFormatProperties2KHR(gpu(), &image_format_info, &image_format_properties); +}