diff --git a/test/conformance/enqueue/CMakeLists.txt b/test/conformance/enqueue/CMakeLists.txt index 48ee69d8f2..2e364b5bdb 100644 --- a/test/conformance/enqueue/CMakeLists.txt +++ b/test/conformance/enqueue/CMakeLists.txt @@ -16,8 +16,6 @@ add_conformance_test_with_kernels_environment(enqueue urEnqueueMemBufferWrite.cpp urEnqueueMemBufferWriteRect.cpp urEnqueueMemImageCopy.cpp - urEnqueueMemImageFill.cpp - urEnqueueMemImageMap.cpp urEnqueueMemImageRead.cpp urEnqueueMemImageWrite.cpp urEnqueueMemUnmap.cpp diff --git a/test/conformance/enqueue/urEnqueueMemImageCopy.cpp b/test/conformance/enqueue/urEnqueueMemImageCopy.cpp index 281aa8badb..d3cb5b566e 100644 --- a/test/conformance/enqueue/urEnqueueMemImageCopy.cpp +++ b/test/conformance/enqueue/urEnqueueMemImageCopy.cpp @@ -2,3 +2,246 @@ // Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions. // See LICENSE.TXT // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include + +struct urEnqueueMemImageCopyTest + : public uur::urQueueTestWithParam { + // Helper type so element offset calculations work the same as pixel offsets + struct rgba_pixel { + uint32_t data[4]; + }; + void SetUp() override { + UUR_RETURN_ON_FATAL_FAILURE(urQueueTestWithParam::SetUp()); + type = getParam(); + size = (type == UR_MEM_TYPE_IMAGE1D) ? ur_rect_region_t{width, 1, 1} + : (type == UR_MEM_TYPE_IMAGE2D) + ? ur_rect_region_t{width, height, 1} + : ur_rect_region_t{width, height, depth}; + buffSize = size.width * size.height * size.depth; + // Create a region that is half the size on each dimension so we can + // test partial copies of images + partialRegion = { + size.width / 2, + size.height > 1 ? size.height / 2 : 1, + size.depth > 1 ? size.depth / 2 : 1, + }; + // Create an offset that is the centre of the image on each dimension. + // Used with the above region to test partial copies to non-zero offsets + partialRegionOffset = { + size.width / 2, + size.height > 1 ? size.height / 2 : 0, + size.depth > 1 ? size.depth / 2 : 0, + }; + + ur_image_desc_t desc = {UR_STRUCTURE_TYPE_IMAGE_DESC, // stype + nullptr, // pNext + type, // mem object type + size.width, // image width + size.height, // image height + size.depth, // image depth + 1, // array size + 0, // row pitch + 0, // slice pitch + 0, // mip levels + 0}; // num samples + ASSERT_SUCCESS(urMemImageCreate(this->context, UR_MEM_FLAG_READ_WRITE, + &format, &desc, nullptr, &srcImage)); + ASSERT_SUCCESS(urMemImageCreate(this->context, UR_MEM_FLAG_READ_WRITE, + &format, &desc, nullptr, &dstImage)); + input.assign(buffSize, inputFill); + ASSERT_SUCCESS(urEnqueueMemImageWrite(queue, srcImage, true, origin, + size, 0, 0, input.data(), 0, + nullptr, nullptr)); + // Fill the dst image with arbitrary data that is different to the + // input image so we can test partial copies + std::vector dstData(buffSize, outputFill); + ASSERT_SUCCESS(urEnqueueMemImageWrite(queue, dstImage, true, origin, + size, 0, 0, dstData.data(), 0, + nullptr, nullptr)); + } + + void TearDown() override { + if (srcImage) { + EXPECT_SUCCESS(urMemRelease(dstImage)); + } + if (dstImage) { + EXPECT_SUCCESS(urMemRelease(dstImage)); + } + UUR_RETURN_ON_FATAL_FAILURE(urQueueTestWithParam::TearDown()); + } + + const size_t width = 32; + const size_t height = 8; + const size_t depth = 4; + const ur_rect_offset_t origin{0, 0, 0}; + const ur_image_format_t format = {UR_IMAGE_CHANNEL_ORDER_RGBA, + UR_IMAGE_CHANNEL_TYPE_FLOAT}; + const rgba_pixel inputFill = {42, 42, 42, 42}; + const rgba_pixel outputFill = {21, 21, 21, 21}; + + ur_mem_type_t type; + ur_rect_region_t size; + ur_rect_region_t partialRegion; + ur_rect_offset_t partialRegionOffset; + size_t buffSize; + ur_mem_handle_t srcImage = nullptr; + ur_mem_handle_t dstImage = nullptr; + std::vector input; +}; + +bool operator==(urEnqueueMemImageCopyTest::rgba_pixel lhs, + urEnqueueMemImageCopyTest::rgba_pixel rhs) { + return lhs.data[0] == rhs.data[0] && lhs.data[1] == rhs.data[1] && + lhs.data[2] == rhs.data[2] && lhs.data[3] == rhs.data[3]; +} + +template +inline std::string printImageCopyTestString( + const testing::TestParamInfo &info) { + // ParamType will be std::tuple + const auto device_handle = std::get<0>(info.param); + const auto platform_device_name = + uur::GetPlatformAndDeviceName(device_handle); + const auto image_type = std::get<1>(info.param); + auto test_name = (image_type == UR_MEM_TYPE_IMAGE1D) ? "1D" + : (image_type == UR_MEM_TYPE_IMAGE2D) ? "2D" + : "3D"; + return platform_device_name + "__" + test_name; +} + +UUR_TEST_SUITE_P(urEnqueueMemImageCopyTest, + testing::ValuesIn({UR_MEM_TYPE_IMAGE1D, UR_MEM_TYPE_IMAGE2D, + UR_MEM_TYPE_IMAGE3D}), + printImageCopyTestString); + +TEST_P(urEnqueueMemImageCopyTest, Success) { + ASSERT_SUCCESS(urEnqueueMemImageCopy(queue, srcImage, dstImage, {0, 0, 0}, + {0, 0, 0}, size, 0, nullptr, nullptr)); + std::vector output(buffSize, {1, 1, 1, 1}); + ASSERT_SUCCESS(urEnqueueMemImageRead(queue, dstImage, true, origin, size, 0, + 0, output.data(), 0, nullptr, + nullptr)); + ASSERT_EQ(input, output); +} + +TEST_P(urEnqueueMemImageCopyTest, SuccessPartialCopy) { + ASSERT_SUCCESS(urEnqueueMemImageCopy(queue, srcImage, dstImage, {0, 0, 0}, + {0, 0, 0}, partialRegion, 0, nullptr, + nullptr)); + std::vector output(buffSize, {0, 0, 0, 0}); + ASSERT_SUCCESS(urEnqueueMemImageRead(queue, dstImage, true, origin, size, 0, + 0, output.data(), 0, nullptr, + nullptr)); + + // Perform equivalent copy of the region on the host + std::vector expectedOutput(buffSize, outputFill); + for (size_t z = 0; z < partialRegion.depth; z++) { + for (size_t y = 0; y < partialRegion.height; y++) { + for (size_t x = 0; x < partialRegion.width; x++) { + size_t index = + (z * (size.width * size.height)) + (y * size.width) + x; + expectedOutput.data()[index] = input.data()[index]; + } + } + } + + ASSERT_EQ(expectedOutput, output); +} + +TEST_P(urEnqueueMemImageCopyTest, SuccessPartialCopyWithSrcOffset) { + ASSERT_SUCCESS(urEnqueueMemImageCopy(queue, srcImage, dstImage, + partialRegionOffset, {0, 0, 0}, + partialRegion, 0, nullptr, nullptr)); + std::vector output(buffSize, {0, 0, 0, 0}); + ASSERT_SUCCESS(urEnqueueMemImageRead(queue, dstImage, true, origin, size, 0, + 0, output.data(), 0, nullptr, + nullptr)); + + // Perform equivalent copy of the region on the host + std::vector expectedOutput(buffSize, outputFill); + for (size_t z = 0; z < partialRegion.depth; z++) { + for (size_t y = 0; y < partialRegion.height; y++) { + for (size_t x = 0; x < partialRegion.width; x++) { + size_t index = + (z * (size.width * size.height)) + (y * size.width) + x; + expectedOutput.data()[index] = input.data()[index]; + } + } + } + + ASSERT_EQ(expectedOutput, output); +} + +TEST_P(urEnqueueMemImageCopyTest, SuccessPartialCopyWithDstOffset) { + ASSERT_SUCCESS(urEnqueueMemImageCopy(queue, srcImage, dstImage, {0, 0, 0}, + partialRegionOffset, partialRegion, 0, + nullptr, nullptr)); + std::vector output(buffSize, {0, 0, 0, 0}); + ASSERT_SUCCESS(urEnqueueMemImageRead(queue, dstImage, true, origin, size, 0, + 0, output.data(), 0, nullptr, + nullptr)); + + // Perform equivalent copy of the region on the host + std::vector expectedOutput(buffSize, outputFill); + for (size_t z = partialRegionOffset.z; + z < partialRegionOffset.z + partialRegion.depth; z++) { + for (size_t y = partialRegionOffset.y; + y < partialRegionOffset.y + partialRegion.height; y++) { + for (size_t x = partialRegionOffset.x; + x < partialRegionOffset.x + partialRegion.width; x++) { + size_t index = + (z * (size.width * size.height)) + (y * size.width) + x; + expectedOutput.data()[index] = input.data()[index]; + } + } + } + + ASSERT_EQ(expectedOutput, output); +} + +TEST_P(urEnqueueMemImageCopyTest, InvalidNullHandleQueue) { + ASSERT_EQ_RESULT(UR_RESULT_ERROR_INVALID_NULL_HANDLE, + urEnqueueMemImageCopy(nullptr, srcImage, dstImage, + {0, 0, 0}, {0, 0, 0}, size, 0, + nullptr, nullptr)); +} + +TEST_P(urEnqueueMemImageCopyTest, InvalidNullHandleImageSrc) { + ASSERT_EQ_RESULT(UR_RESULT_ERROR_INVALID_NULL_HANDLE, + urEnqueueMemImageCopy(queue, nullptr, dstImage, {0, 0, 0}, + {0, 0, 0}, size, 0, nullptr, + nullptr)); +} + +TEST_P(urEnqueueMemImageCopyTest, InvalidNullHandleImageDst) { + ASSERT_EQ_RESULT(UR_RESULT_ERROR_INVALID_NULL_HANDLE, + urEnqueueMemImageCopy(queue, srcImage, nullptr, {0, 0, 0}, + {0, 0, 0}, size, 0, nullptr, + nullptr)); +} + +TEST_P(urEnqueueMemImageCopyTest, InvalidNullPtrEventWaitList) { + ASSERT_EQ_RESULT(urEnqueueMemImageCopy(queue, srcImage, dstImage, {0, 0, 0}, + {0, 0, 0}, size, 1, nullptr, + nullptr), + UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST); + + ur_event_handle_t validEvent; + ASSERT_SUCCESS(urEnqueueEventsWait(queue, 0, nullptr, &validEvent)); + + ASSERT_EQ_RESULT(urEnqueueMemImageCopy(queue, srcImage, dstImage, {0, 0, 0}, + {0, 0, 0}, size, 0, &validEvent, + nullptr), + UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST); +} + +TEST_P(urEnqueueMemImageCopyTest, InvalidSize) { + ASSERT_EQ_RESULT(UR_RESULT_ERROR_INVALID_SIZE, + urEnqueueMemImageCopy(queue, srcImage, dstImage, {1, 0, 0}, + {0, 0, 0}, size, 0, nullptr, + nullptr)); + ASSERT_EQ_RESULT(UR_RESULT_ERROR_INVALID_SIZE, + urEnqueueMemImageCopy(queue, srcImage, dstImage, {0, 0, 0}, + {1, 0, 0}, size, 0, nullptr, + nullptr)); +} diff --git a/test/conformance/enqueue/urEnqueueMemImageFill.cpp b/test/conformance/enqueue/urEnqueueMemImageFill.cpp deleted file mode 100644 index 281aa8badb..0000000000 --- a/test/conformance/enqueue/urEnqueueMemImageFill.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (C) 2023 Intel Corporation -// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See LICENSE.TXT -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception diff --git a/test/conformance/enqueue/urEnqueueMemImageMap.cpp b/test/conformance/enqueue/urEnqueueMemImageMap.cpp deleted file mode 100644 index 281aa8badb..0000000000 --- a/test/conformance/enqueue/urEnqueueMemImageMap.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (C) 2023 Intel Corporation -// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See LICENSE.TXT -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception