Add tests for cl_ext_immutable_memory_objects (#2286)

This change provides partial test coverage for
KhronosGroup/OpenCL-Docs#1280

Adding CTS tests for:
1. clEnqueueMapBuffer, clEnqueueMapImage.
2. Command buffer negative tests.
3. clSetKernelArgs negative tests.

The bulk of the tests is to make sure that the CL driver does not allow
writing to a memory object that is created with `CL_MEM_IMMUTABLE_EXT`
flag when used with the above APIs.

---------

Signed-off-by: Michael Rizkalla <michael.rizkalla@arm.com>
This commit is contained in:
Michael Rizkalla
2025-06-17 18:19:11 +01:00
committed by GitHub
parent e622512301
commit 8701acfa90
7 changed files with 745 additions and 10 deletions

View File

@@ -29,6 +29,9 @@ const cl_mem_flags flag_set[] = {
CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR,
CL_MEM_USE_HOST_PTR,
CL_MEM_COPY_HOST_PTR,
CL_MEM_USE_HOST_PTR | CL_MEM_IMMUTABLE_EXT,
CL_MEM_COPY_HOST_PTR | CL_MEM_IMMUTABLE_EXT,
CL_MEM_COPY_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_IMMUTABLE_EXT,
0
};
@@ -37,6 +40,9 @@ const char *flag_set_names[] = {
"CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR",
"CL_MEM_USE_HOST_PTR",
"CL_MEM_COPY_HOST_PTR",
"CL_MEM_USE_HOST_PTR | CL_MEM_IMMUTABLE_EXT",
"CL_MEM_COPY_HOST_PTR | CL_MEM_IMMUTABLE_EXT",
"CL_MEM_COPY_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_IMMUTABLE_EXT",
"0"
};
// clang-format on
@@ -44,7 +50,7 @@ const char *flag_set_names[] = {
REGISTER_TEST(enqueue_map_buffer)
{
int error;
const size_t bufferSize = 256 * 256;
constexpr size_t bufferSize = 256 * 256;
MTdataHolder d{ gRandomSeed };
BufferOwningPtr<cl_char> hostPtrData{ malloc(bufferSize) };
BufferOwningPtr<cl_char> referenceData{ malloc(bufferSize) };
@@ -57,18 +63,28 @@ REGISTER_TEST(enqueue_map_buffer)
log_info("Testing with cl_mem_flags src: %s\n",
flag_set_names[src_flag_id]);
if ((flag_set[src_flag_id] & CL_MEM_IMMUTABLE_EXT)
&& !is_extension_available(device,
"cl_ext_immutable_memory_objects"))
{
log_info("Device does not support CL_MEM_IMMUTABLE_EXT. "
"Skipping the memory flag.\n");
continue;
}
generate_random_data(kChar, (unsigned int)bufferSize, d, hostPtrData);
memcpy(referenceData, hostPtrData, bufferSize);
void *hostPtr = nullptr;
cl_mem_flags flags = flag_set[src_flag_id];
const bool is_immutable_buffer = flags & CL_MEM_IMMUTABLE_EXT;
bool hasHostPtr =
(flags & CL_MEM_USE_HOST_PTR) || (flags & CL_MEM_COPY_HOST_PTR);
if (hasHostPtr) hostPtr = hostPtrData;
memObject = clCreateBuffer(context, flags, bufferSize, hostPtr, &error);
test_error(error, "Unable to create testing buffer");
if (!hasHostPtr)
if (!hasHostPtr && !is_immutable_buffer)
{
error =
clEnqueueWriteBuffer(queue, memObject, CL_TRUE, 0, bufferSize,
@@ -86,7 +102,18 @@ REGISTER_TEST(enqueue_map_buffer)
cl_char *mappedRegion = (cl_char *)clEnqueueMapBuffer(
queue, memObject, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, offset,
length, 0, NULL, NULL, &error);
if (error != CL_SUCCESS)
// Mapping should fail if the buffer is immutable
if (is_immutable_buffer)
{
test_failure_error_ret(
error, CL_INVALID_OPERATION,
"clEnqueueMapBuffer call was expected to fail "
"with CL_INVALID_OPERATION",
TEST_FAIL);
continue;
}
else if (error != CL_SUCCESS)
{
print_error(error, "clEnqueueMapBuffer call failed");
log_error("\tOffset: %d Length: %d\n", (int)offset,
@@ -122,6 +149,11 @@ REGISTER_TEST(enqueue_map_buffer)
finalData, 0, NULL, NULL);
test_error(error, "Unable to read results");
if (is_immutable_buffer && !hasHostPtr)
{
continue;
}
for (size_t q = 0; q < bufferSize; q++)
{
if (referenceData[q] != finalData[q])
@@ -140,9 +172,10 @@ REGISTER_TEST(enqueue_map_buffer)
REGISTER_TEST(enqueue_map_image)
{
int error;
cl_image_format format = { CL_RGBA, CL_UNSIGNED_INT32 };
const size_t imageSize = 256;
const size_t imageDataSize = imageSize * imageSize * 4 * sizeof(cl_uint);
constexpr cl_image_format format = { CL_RGBA, CL_UNSIGNED_INT32 };
constexpr size_t imageSize = 256;
constexpr size_t imageDataSize =
imageSize * imageSize * 4 * sizeof(cl_uint);
PASSIVE_REQUIRE_IMAGE_SUPPORT(device)
@@ -158,20 +191,30 @@ REGISTER_TEST(enqueue_map_image)
log_info("Testing with cl_mem_flags src: %s\n",
flag_set_names[src_flag_id]);
if ((flag_set[src_flag_id] & CL_MEM_IMMUTABLE_EXT)
&& !is_extension_available(device,
"cl_ext_immutable_memory_objects"))
{
log_info("Device does not support CL_MEM_IMMUTABLE_EXT. "
"Skipping the memory flag.\n");
continue;
}
generate_random_data(kUInt, (unsigned int)(imageSize * imageSize * 4),
d, hostPtrData);
memcpy(referenceData, hostPtrData, imageDataSize);
cl_mem_flags flags = flag_set[src_flag_id];
bool is_immutable_image = flags & CL_MEM_IMMUTABLE_EXT;
bool hasHostPtr =
(flags & CL_MEM_USE_HOST_PTR) || (flags & CL_MEM_COPY_HOST_PTR);
void *hostPtr = nullptr;
if (hasHostPtr) hostPtr = hostPtrData;
memObject = create_image_2d(context, CL_MEM_READ_WRITE | flags, &format,
imageSize, imageSize, 0, hostPtr, &error);
memObject = create_image_2d(context, flags, &format, imageSize,
imageSize, 0, hostPtr, &error);
test_error(error, "Unable to create testing buffer");
if (!hasHostPtr)
if (!hasHostPtr && !is_immutable_image)
{
size_t write_origin[3] = { 0, 0, 0 },
write_region[3] = { imageSize, imageSize, 1 };
@@ -198,7 +241,17 @@ REGISTER_TEST(enqueue_map_image)
cl_uint *mappedRegion = (cl_uint *)clEnqueueMapImage(
queue, memObject, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, offset,
region, &rowPitch, NULL, 0, NULL, NULL, &error);
if (error != CL_SUCCESS)
if (is_immutable_image)
{
test_failure_error_ret(
error, CL_INVALID_OPERATION,
"clEnqueueMapImage call was expected to fail "
"with CL_INVALID_OPERATION",
TEST_FAIL);
continue;
}
else if (error != CL_SUCCESS)
{
print_error(error, "clEnqueueMapImage call failed");
log_error("\tOffset: %d,%d Region: %d,%d\n", (int)offset[0],
@@ -245,6 +298,11 @@ REGISTER_TEST(enqueue_map_image)
finalRegion, 0, 0, finalData, 0, NULL, NULL);
test_error(error, "Unable to read results");
if (is_immutable_image && !hasHostPtr)
{
continue;
}
for (size_t q = 0; q < imageSize * imageSize * 4; q++)
{
if (referenceData[q] != finalData[q])