mirror of
https://github.com/KhronosGroup/OpenCL-CTS.git
synced 2026-03-19 06:09:01 +00:00
Add AHB lifetime test (#2569)
Add lifetime test for AHardwareBuffer in which for both CL Buffers and CL Images the following steps are taken - Create AHB - Create mem object from the AHB - Release the AHB - Read and write from and to the mem object - Verify the reads and write have happened sucessfully The CL implementation should maintain a reference count to the AHB since the AHB must not be deallocated for the test to pass. Signed-off-by: Alex Davicenko <alex.davicenko@arm.com> Signed-off-by: Ahmed Hesham <ahmed.hesham@arm.com> Co-authored-by: Alex Davicenko <alex.davicenko@arm.com>
This commit is contained in:
@@ -96,6 +96,23 @@ static const char *diff_images_kernel_source = {
|
|||||||
})"
|
})"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *lifetime_kernel_source = {
|
||||||
|
R"(
|
||||||
|
__kernel void increment_buffer(global uchar* buffer)
|
||||||
|
{
|
||||||
|
int tid = get_global_id(0);
|
||||||
|
buffer[tid] ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
__kernel void set_image_color(write_only image2d_t ahb_image, float4 set_color)
|
||||||
|
{
|
||||||
|
int tidX = get_global_id(0);
|
||||||
|
int tidY = get_global_id(1);
|
||||||
|
|
||||||
|
write_imagef(ahb_image, (int2)( tidX, tidY ), set_color);
|
||||||
|
})"
|
||||||
|
};
|
||||||
|
|
||||||
// Checks that the inferred image format is correct
|
// Checks that the inferred image format is correct
|
||||||
REGISTER_TEST(images)
|
REGISTER_TEST(images)
|
||||||
{
|
{
|
||||||
@@ -1857,3 +1874,289 @@ REGISTER_TEST(blob)
|
|||||||
|
|
||||||
return TEST_PASS;
|
return TEST_PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For cl buffer and cl image
|
||||||
|
* Create a AHB
|
||||||
|
* Create a mem object from the AHB
|
||||||
|
* Release the AHB
|
||||||
|
* Read and write using the mem object
|
||||||
|
* Verify reads and writes
|
||||||
|
*/
|
||||||
|
REGISTER_TEST(lifetime_buffer)
|
||||||
|
{
|
||||||
|
REQUIRE_EXTENSION("cl_khr_external_memory_android_hardware_buffer");
|
||||||
|
|
||||||
|
cl_int err;
|
||||||
|
constexpr cl_uint buffer_size = 4096;
|
||||||
|
std::vector<uint8_t> host_buffer(buffer_size, 1);
|
||||||
|
clMemWrapper imported_buffer;
|
||||||
|
|
||||||
|
{
|
||||||
|
// Check if AHB descriptors for buffers and images are supported
|
||||||
|
AHardwareBuffer_Desc aHardwareBufferDesc = { 0 };
|
||||||
|
aHardwareBufferDesc.width = buffer_size;
|
||||||
|
aHardwareBufferDesc.height = 1;
|
||||||
|
aHardwareBufferDesc.layers = 1;
|
||||||
|
aHardwareBufferDesc.format = AHARDWAREBUFFER_FORMAT_BLOB;
|
||||||
|
aHardwareBufferDesc.usage = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN
|
||||||
|
| AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
|
||||||
|
|
||||||
|
if (!AHardwareBuffer_isSupported(&aHardwareBufferDesc))
|
||||||
|
{
|
||||||
|
log_unsupported_ahb_format(aHardwareBufferDesc);
|
||||||
|
return TEST_SKIPPED_ITSELF;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("Testing buffer lifetime\n");
|
||||||
|
|
||||||
|
AHardwareBufferWrapper aHardwareBuffer(&aHardwareBufferDesc);
|
||||||
|
|
||||||
|
const cl_mem_properties props[] = {
|
||||||
|
CL_EXTERNAL_MEMORY_HANDLE_ANDROID_HARDWARE_BUFFER_KHR,
|
||||||
|
aHardwareBuffer.get_props(),
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
imported_buffer = clCreateBufferWithProperties(
|
||||||
|
context, props, CL_MEM_READ_WRITE, 0, nullptr, &err);
|
||||||
|
test_error(err, "Failed to create CL buffer from AHardwareBuffer");
|
||||||
|
|
||||||
|
// Fill AHB buffer
|
||||||
|
void *data_ptr = nullptr;
|
||||||
|
int ahb_result = AHardwareBuffer_lock(
|
||||||
|
aHardwareBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1, nullptr,
|
||||||
|
&data_ptr);
|
||||||
|
if (ahb_result != 0)
|
||||||
|
{
|
||||||
|
log_error("AHardwareBuffer_lock failed with code %d\n", ahb_result);
|
||||||
|
return TEST_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data_ptr, host_buffer.data(), buffer_size);
|
||||||
|
|
||||||
|
ahb_result = AHardwareBuffer_unlock(aHardwareBuffer, nullptr);
|
||||||
|
if (ahb_result != 0)
|
||||||
|
{
|
||||||
|
log_error("AHardwareBuffer_unlock failed with code %d\n",
|
||||||
|
ahb_result);
|
||||||
|
return TEST_FAIL;
|
||||||
|
}
|
||||||
|
} // Release test scope reference to AHB
|
||||||
|
|
||||||
|
|
||||||
|
// Verify buffer read by comparing to host buffer
|
||||||
|
std::vector<uint8_t> read_buffer(buffer_size);
|
||||||
|
err = clEnqueueReadBuffer(queue, imported_buffer, true, 0, buffer_size,
|
||||||
|
read_buffer.data(), 0, nullptr, nullptr);
|
||||||
|
test_error(err, "failed clEnqueueReadBuffer");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < buffer_size; i++)
|
||||||
|
{
|
||||||
|
if (read_buffer[i] != host_buffer[i])
|
||||||
|
{
|
||||||
|
log_error("At position %zu expected value: %u but got value: %u\n",
|
||||||
|
i, host_buffer[i], read_buffer[i]);
|
||||||
|
return TEST_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt buffer write
|
||||||
|
clProgramWrapper program;
|
||||||
|
clKernelWrapper kernel;
|
||||||
|
|
||||||
|
err = create_single_kernel_helper(context, &program, &kernel, 1,
|
||||||
|
&lifetime_kernel_source,
|
||||||
|
"increment_buffer");
|
||||||
|
test_error(err, "kernel creation failed");
|
||||||
|
|
||||||
|
err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &imported_buffer);
|
||||||
|
test_error(err, "clSetKernelArg failed");
|
||||||
|
|
||||||
|
size_t gws[1] = { buffer_size };
|
||||||
|
err = clEnqueueNDRangeKernel(queue, kernel, 1, nullptr, gws, nullptr, 0,
|
||||||
|
nullptr, nullptr);
|
||||||
|
test_error(err, "Failed clEnqueueNDRangeKernel");
|
||||||
|
|
||||||
|
// Verify write
|
||||||
|
err = clEnqueueReadBuffer(queue, imported_buffer, true, 0, buffer_size,
|
||||||
|
read_buffer.data(), 0, nullptr, nullptr);
|
||||||
|
test_error(err, "failed clEnqueueReadBuffer");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < buffer_size; i++)
|
||||||
|
{
|
||||||
|
if (read_buffer[i]
|
||||||
|
!= host_buffer[i] + 1) // Kernel incremented each index by 1
|
||||||
|
{
|
||||||
|
log_error("At position %zu expected value: %u but got value: %u\n",
|
||||||
|
i, host_buffer[i], read_buffer[i]);
|
||||||
|
return TEST_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TEST_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
REGISTER_TEST(lifetime_image)
|
||||||
|
{
|
||||||
|
REQUIRE_EXTENSION("cl_khr_external_memory_android_hardware_buffer");
|
||||||
|
|
||||||
|
int err;
|
||||||
|
const AHardwareBuffer_Format aHardwareBufferFormat =
|
||||||
|
AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
const cl_image_format clImageFormat = { CL_RGBA, CL_UNORM_INT8 };
|
||||||
|
const size_t pixel_size = get_pixel_size(&clImageFormat);
|
||||||
|
|
||||||
|
for (auto resolution : test_sizes)
|
||||||
|
{
|
||||||
|
const size_t image_size =
|
||||||
|
resolution.width * resolution.height * pixel_size;
|
||||||
|
|
||||||
|
std::vector<uint8_t> host_image_data(image_size, 1);
|
||||||
|
clMemWrapper imported_image;
|
||||||
|
{
|
||||||
|
// Check if AHB descriptors for buffers and images are supported
|
||||||
|
AHardwareBuffer_Desc aHardwareBufferDesc = { 0 };
|
||||||
|
aHardwareBufferDesc.width = resolution.width;
|
||||||
|
aHardwareBufferDesc.height = resolution.height;
|
||||||
|
aHardwareBufferDesc.layers = 1;
|
||||||
|
aHardwareBufferDesc.format = aHardwareBufferFormat;
|
||||||
|
aHardwareBufferDesc.usage = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN
|
||||||
|
| AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
|
||||||
|
|
||||||
|
if (!AHardwareBuffer_isSupported(&aHardwareBufferDesc))
|
||||||
|
{
|
||||||
|
log_unsupported_ahb_format(aHardwareBufferDesc);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("Testing image lifetime\n");
|
||||||
|
|
||||||
|
AHardwareBufferWrapper aHardwareBuffer(&aHardwareBufferDesc);
|
||||||
|
|
||||||
|
const cl_mem_properties props_image[] = {
|
||||||
|
CL_EXTERNAL_MEMORY_HANDLE_ANDROID_HARDWARE_BUFFER_KHR,
|
||||||
|
aHardwareBuffer.get_props(),
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
imported_image = clCreateImageWithProperties(
|
||||||
|
context, props_image, CL_MEM_READ_WRITE, nullptr, nullptr,
|
||||||
|
nullptr, &err);
|
||||||
|
test_error(err, "Failed to create CL image from AHardwareBuffer");
|
||||||
|
|
||||||
|
void *data_ptr = nullptr;
|
||||||
|
int ahb_result = AHardwareBuffer_lock(
|
||||||
|
aHardwareBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1,
|
||||||
|
nullptr, &data_ptr);
|
||||||
|
if (ahb_result != 0)
|
||||||
|
{
|
||||||
|
log_error("AHardwareBuffer_lock failed with code %d\n",
|
||||||
|
ahb_result);
|
||||||
|
return TEST_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data_ptr, host_image_data.data(), image_size);
|
||||||
|
|
||||||
|
ahb_result = AHardwareBuffer_unlock(aHardwareBuffer, nullptr);
|
||||||
|
if (ahb_result != 0)
|
||||||
|
{
|
||||||
|
log_error("AHardwareBuffer_unlock failed with code %d\n",
|
||||||
|
ahb_result);
|
||||||
|
return TEST_FAIL;
|
||||||
|
}
|
||||||
|
} // Release test scope reference to AHB
|
||||||
|
|
||||||
|
|
||||||
|
// Verify image read using host data
|
||||||
|
size_t origin[3] = { 0, 0, 0 };
|
||||||
|
size_t region[3] = { resolution.width, resolution.height, 1 };
|
||||||
|
size_t row_pitch;
|
||||||
|
uint8_t *mapped_image_ptr = static_cast<uint8_t *>(clEnqueueMapImage(
|
||||||
|
queue, imported_image, true, CL_MAP_READ, origin, region,
|
||||||
|
&row_pitch, nullptr, 0, nullptr, nullptr, &err));
|
||||||
|
test_error(err, "clEnqueueMapImage failed");
|
||||||
|
|
||||||
|
for (size_t row = 0; row < resolution.height; ++row)
|
||||||
|
{
|
||||||
|
for (size_t col = 0; col < resolution.width; ++col)
|
||||||
|
{
|
||||||
|
size_t mapped_image_idx = row * row_pitch + col;
|
||||||
|
size_t host_image_idx = row * resolution.width + col;
|
||||||
|
if (mapped_image_ptr[mapped_image_idx]
|
||||||
|
!= host_image_data[host_image_idx])
|
||||||
|
{
|
||||||
|
log_error(
|
||||||
|
"At position (%zu, %zu) expected value: %u but got "
|
||||||
|
"value: %u\n",
|
||||||
|
row, col, host_image_data[host_image_idx],
|
||||||
|
mapped_image_ptr[mapped_image_idx]);
|
||||||
|
return TEST_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = clEnqueueUnmapMemObject(queue, imported_image, mapped_image_ptr,
|
||||||
|
0, nullptr, nullptr);
|
||||||
|
test_error(err, "clEnqueueUnmapMemObject failed");
|
||||||
|
|
||||||
|
err = clFinish(queue);
|
||||||
|
test_error(err, "clFinish failed");
|
||||||
|
|
||||||
|
|
||||||
|
// Attempt image write
|
||||||
|
clProgramWrapper program;
|
||||||
|
clKernelWrapper kernel;
|
||||||
|
err = create_single_kernel_helper(context, &program, &kernel, 1,
|
||||||
|
&lifetime_kernel_source,
|
||||||
|
"set_image_color");
|
||||||
|
test_error(err, "kernel creation failed");
|
||||||
|
|
||||||
|
err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &imported_image);
|
||||||
|
test_error(err, "clSetKernelArg failed");
|
||||||
|
|
||||||
|
cl_float4 color = { { 0.5f, 0.5f, 0.5f, 0.5f } };
|
||||||
|
err = clSetKernelArg(kernel, 1, sizeof(cl_float4), &color);
|
||||||
|
test_error(err, "clSetKernelArg failed");
|
||||||
|
|
||||||
|
std::vector<size_t> gws = { resolution.width, resolution.height };
|
||||||
|
err = clEnqueueNDRangeKernel(queue, kernel, 2, nullptr, gws.data(),
|
||||||
|
nullptr, 0, nullptr, nullptr);
|
||||||
|
test_error(err, "Failed clEnqueueNDRangeKernel");
|
||||||
|
|
||||||
|
err = clFinish(queue);
|
||||||
|
test_error(err, "clFinish failed");
|
||||||
|
|
||||||
|
|
||||||
|
// Verify image write
|
||||||
|
mapped_image_ptr = static_cast<uint8_t *>(clEnqueueMapImage(
|
||||||
|
queue, imported_image, true, CL_MAP_READ, origin, region,
|
||||||
|
&row_pitch, nullptr, 0, nullptr, nullptr, &err));
|
||||||
|
test_error(err, "clEnqueueMapImage failed");
|
||||||
|
|
||||||
|
for (size_t row = 0; row < resolution.height; ++row)
|
||||||
|
{
|
||||||
|
for (size_t col = 0; col < resolution.width; ++col)
|
||||||
|
{
|
||||||
|
size_t mapped_image_idx = row * row_pitch + col;
|
||||||
|
if (128 != mapped_image_ptr[mapped_image_idx])
|
||||||
|
{
|
||||||
|
log_error(
|
||||||
|
"At position (%zu, %zu) expected value: %u but got "
|
||||||
|
"value: %u\n",
|
||||||
|
row, col, 128, mapped_image_ptr[mapped_image_idx]);
|
||||||
|
return TEST_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = clEnqueueUnmapMemObject(queue, imported_image, mapped_image_ptr,
|
||||||
|
0, nullptr, nullptr);
|
||||||
|
test_error(err, "clEnqueueUnmapMemObject failed");
|
||||||
|
|
||||||
|
err = clFinish(queue);
|
||||||
|
test_error(err, "clFinish failed");
|
||||||
|
}
|
||||||
|
return TEST_PASS;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user