Skip to content

Commit

Permalink
tests: Add a positive test for host image copy
Browse files Browse the repository at this point in the history
Also share utils between positive and negative tests
  • Loading branch information
TonyBarbour committed Aug 14, 2023
1 parent 919b88a commit 38b78a1
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 18 deletions.
1 change: 1 addition & 0 deletions build-android/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ LOCAL_SRC_FILES += $(SRC_DIR)/tests/framework/layer_validation_tests.cpp \
$(SRC_DIR)/tests/unit/buffer.cpp \
$(SRC_DIR)/tests/unit/external_memory_sync.cpp \
$(SRC_DIR)/tests/unit/host_image_copy.cpp \
$(SRC_DIR)/tests/unit/host_image_copy_positive.cpp \
$(SRC_DIR)/tests/unit/image.cpp \
$(SRC_DIR)/tests/unit/memory.cpp \
$(SRC_DIR)/tests/unit/object_lifetime.cpp \
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions tests/framework/layer_validation_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -415,12 +415,16 @@ class GraphicsLibraryTest : public VkLayerTest {
class NegativeGraphicsLibrary : public GraphicsLibraryTest {};
class PositiveGraphicsLibrary : public GraphicsLibraryTest {};

class NegativeHostImageCopy : public virtual VkLayerTest {
protected:
class HostImageCopyTest : public VkLayerTest {
public:
void InitHostImageCopyTest(const VkImageCreateInfo image_ci, std::vector<VkImageLayout> &copy_src_layouts,
std::vector<VkImageLayout> &copy_dst_layouts, VkFormat &compressed_format,
bool &separate_depth_stencil);
bool CopyLayoutSupported(std::vector<VkImageLayout> &copy_src_layouts, std::vector<VkImageLayout> &copy_dst_layouts,
VkImageLayout layout);
};
class NegativeHostImageCopy : public HostImageCopyTest {};
class PositiveHostImageCopy : public HostImageCopyTest {};

class ImageTest : public VkLayerTest {
public:
Expand Down
31 changes: 15 additions & 16 deletions tests/unit/host_image_copy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,15 @@
#include "utils/vk_layer_utils.h"
#include "generated/enum_flag_bits.h"

bool copy_layout_supported(std::vector<VkImageLayout> &copy_src_layouts, std::vector<VkImageLayout> &copy_dst_layouts,
VkImageLayout layout) {
bool HostImageCopyTest::CopyLayoutSupported(std::vector<VkImageLayout> &copy_src_layouts,
std::vector<VkImageLayout> &copy_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<VkImageLayout> &copy_src_layouts,
std::vector<VkImageLayout> &copy_dst_layouts, VkFormat &compressed_format,
bool &separate_depth_stencil) {
void HostImageCopyTest::InitHostImageCopyTest(const VkImageCreateInfo image_ci, std::vector<VkImageLayout> &copy_src_layouts,
std::vector<VkImageLayout> &copy_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());
Expand Down Expand Up @@ -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";
}
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down
161 changes: 161 additions & 0 deletions tests/unit/host_image_copy_positive.cpp
Original file line number Diff line number Diff line change
@@ -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<VkImageLayout> copy_src_layouts;
std::vector<VkImageLayout> 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<uint8_t> pixels(width * height * 4);
// Fill image with random values
for (auto &channel : pixels) {
const uint32_t r = static_cast<uint32_t>(std::rand());
channel = static_cast<uint8_t>((r & 0xffu) | ((r >> 8) & 0xff) | ((r >> 16) & 0xff) | (r >> 24));
}

auto region_to_image = LvlInitStruct<VkMemoryToImageCopyEXT>();
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<VkCopyMemoryToImageInfoEXT>();
copy_to_image.flags = 0;
copy_to_image.dstImage = image;
copy_to_image.dstImageLayout = layout;
copy_to_image.regionCount = 1;
copy_to_image.pRegions = &region_to_image;

VkResult result = vk::CopyMemoryToImageEXT(*m_device, &copy_to_image);
ASSERT_VK_SUCCESS(result);

// Copy back to host memory
std::vector<uint8_t> welcome_back(width * height * 4);

auto region_from_image = LvlInitStruct<VkImageToMemoryCopyEXT>();
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<VkCopyImageToMemoryInfoEXT>();
copy_from_image.flags = 0;
copy_from_image.srcImage = image;
copy_from_image.srcImageLayout = layout;
copy_from_image.regionCount = 1;
copy_from_image.pRegions = &region_from_image;

result = vk::CopyImageToMemoryEXT(*m_device, &copy_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<VkImageCopy2>();
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<VkCopyImageToImageInfoEXT>();
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, &copy_image_to_image);
ASSERT_VK_SUCCESS(result);

// Copy back from destination image to memory
std::vector<uint8_t> after_image_copy(width * height * 4);

copy_from_image.srcImage = image2;
region_from_image.pHostPointer = after_image_copy.data();
result = vk::CopyImageToMemoryEXT(*m_device, &copy_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<VkHostImageLayoutTransitionInfoEXT>();
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<VkImageSubresource2KHR>();
subresource.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
auto host_copy_size = LvlInitStruct<VkSubresourceHostMemcpySizeEXT>();
auto subresource_layout = LvlInitStruct<VkSubresourceLayout2KHR>(&host_copy_size);
vk::GetImageSubresourceLayout2EXT(*m_device, image, &subresource, &subresource_layout);
ASSERT_NE(host_copy_size.size, 0);

auto perf_data = LvlInitStruct<VkHostImageCopyDevicePerformanceQueryEXT>();
auto image_format_properties = LvlInitStruct<VkImageFormatProperties2>(&perf_data);
auto image_format_info = LvlInitStruct<VkPhysicalDeviceImageFormatInfo2>();
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);
}

0 comments on commit 38b78a1

Please sign in to comment.