From 6d3d199b4261d7679cb2004aa649095a2f987b3e Mon Sep 17 00:00:00 2001 From: Michael Rizkalla Date: Wed, 19 Feb 2025 04:50:43 +0000 Subject: [PATCH] Deduplicate create_image from Copy/Fill image tests (#2262) 1. Remove duplicate `create_image` code that is in both clFillImage and clCopyImage test directories. 2. Unify how pitch buffer's memory is deallocated; The buffer can be allocated with either `malloc` or `align_malloc` and the free function is pre-set in `pitch_buffe_data`'s member variable `free_fn` and used when the buffer is deallocated. With this, the change removes `is_aligned` conditional variable that was used to select the appropriate free function. Signed-off-by: Michael Rizkalla --- .../images/clCopyImage/test_copy_generic.cpp | 407 +--------------- .../images/clFillImage/test_fill_generic.cpp | 337 +------------ test_conformance/images/common.cpp | 443 ++++++++++++++++++ test_conformance/images/common.h | 5 + 4 files changed, 458 insertions(+), 734 deletions(-) diff --git a/test_conformance/images/clCopyImage/test_copy_generic.cpp b/test_conformance/images/clCopyImage/test_copy_generic.cpp index 37fc8e30..761eec6b 100644 --- a/test_conformance/images/clCopyImage/test_copy_generic.cpp +++ b/test_conformance/images/clCopyImage/test_copy_generic.cpp @@ -15,406 +15,7 @@ // #include "../testBase.h" #include - -struct pitch_buffer_data -{ - void *buf; - bool is_aligned; -}; - -static void CL_CALLBACK free_pitch_buffer(cl_mem image, void *data) -{ - pitch_buffer_data *d = static_cast(data); - if (d->is_aligned) - { - align_free(d->buf); - } - else - { - free(d->buf); - } - free(d); -} - -static void CL_CALLBACK release_cl_buffer(cl_mem image, void *buf) -{ - clReleaseMemObject((cl_mem)buf); -} - -cl_mem create_image( cl_context context, cl_command_queue queue, BufferOwningPtr& data, image_descriptor *imageInfo, int *error ) -{ - cl_mem img; - cl_image_desc imageDesc; - cl_mem_flags mem_flags = CL_MEM_READ_ONLY; - void *host_ptr = NULL; - bool is_host_ptr_aligned = false; - - memset(&imageDesc, 0x0, sizeof(cl_image_desc)); - imageDesc.image_type = imageInfo->type; - imageDesc.image_width = imageInfo->width; - imageDesc.image_height = imageInfo->height; - imageDesc.image_depth = imageInfo->depth; - imageDesc.image_array_size = imageInfo->arraySize; - imageDesc.image_row_pitch = gEnablePitch ? imageInfo->rowPitch : 0; - imageDesc.image_slice_pitch = gEnablePitch ? imageInfo->slicePitch : 0; - imageDesc.num_mip_levels = gTestMipmaps ? imageInfo->num_mip_levels : 0; - - Version version; - cl_device_id device; - { - cl_int err = clGetCommandQueueInfo(queue, CL_QUEUE_DEVICE, - sizeof(device), &device, nullptr); - if (err != CL_SUCCESS) - { - log_error("Error: Could not get CL_QUEUE_DEVICE from queue"); - return nullptr; - } - version = get_device_cl_version(device); - } - - switch (imageInfo->type) - { - case CL_MEM_OBJECT_IMAGE1D: - if ( gDebugTrace ) - log_info( " - Creating 1D image %d ...\n", (int)imageInfo->width ); - if ( gEnablePitch ) - host_ptr = malloc( imageInfo->rowPitch ); - break; - case CL_MEM_OBJECT_IMAGE2D: - if ( gDebugTrace ) - log_info( " - Creating 2D image %d by %d ...\n", (int)imageInfo->width, (int)imageInfo->height ); - if ( gEnablePitch ) - host_ptr = malloc( imageInfo->height * imageInfo->rowPitch ); - break; - case CL_MEM_OBJECT_IMAGE3D: - if ( gDebugTrace ) - log_info( " - Creating 3D image %d by %d by %d...\n", (int)imageInfo->width, (int)imageInfo->height, (int)imageInfo->depth ); - if ( gEnablePitch ) - host_ptr = malloc( imageInfo->depth * imageInfo->slicePitch ); - break; - case CL_MEM_OBJECT_IMAGE1D_ARRAY: - if ( gDebugTrace ) - log_info( " - Creating 1D image array %d by %d...\n", (int)imageInfo->width, (int)imageInfo->arraySize ); - if ( gEnablePitch ) - host_ptr = malloc( imageInfo->arraySize * imageInfo->slicePitch ); - break; - case CL_MEM_OBJECT_IMAGE2D_ARRAY: - if ( gDebugTrace ) - log_info( " - Creating 2D image array %d by %d by %d...\n", (int)imageInfo->width, (int)imageInfo->height, (int)imageInfo->arraySize ); - if ( gEnablePitch ) - host_ptr = malloc( imageInfo->arraySize * imageInfo->slicePitch ); - break; - case CL_MEM_OBJECT_IMAGE1D_BUFFER: - if (gDebugTrace) - log_info(" - Creating 1D buffer image %d ...\n", - (int)imageInfo->width); - { - cl_int err; - cl_mem_flags buffer_flags = CL_MEM_READ_WRITE; - if (gEnablePitch) - { - if (version.major() == 1) - { - host_ptr = malloc(imageInfo->rowPitch); - } - else - { - cl_uint base_address_alignment = 0; - err = clGetDeviceInfo( - device, CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT, - sizeof(base_address_alignment), - &base_address_alignment, nullptr); - if (err != CL_SUCCESS) - { - log_error("ERROR: Could not get " - "CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT " - "from device"); - return NULL; - } - host_ptr = align_malloc(imageInfo->rowPitch, - base_address_alignment); - is_host_ptr_aligned = true; - } - buffer_flags |= CL_MEM_USE_HOST_PTR; - } - - cl_mem buffer = clCreateBuffer( - context, buffer_flags, imageInfo->rowPitch, host_ptr, &err); - if (err != CL_SUCCESS) - { - log_error("ERROR: Could not create buffer for 1D buffer " - "image. %zu bytes\n", - imageInfo->width); - return NULL; - } - imageDesc.buffer = buffer; - } - break; - } - - if ( gDebugTrace && gTestMipmaps ) - log_info(" - with %llu mip levels\n", (unsigned long long) imageInfo->num_mip_levels); - - if (gEnablePitch) - { - if ( NULL == host_ptr ) - { - log_error("ERROR: Unable to create backing store for pitched 3D " - "image. %zu bytes\n", - imageInfo->depth * imageInfo->slicePitch); - return NULL; - } - if (imageInfo->type != CL_MEM_OBJECT_IMAGE1D_BUFFER) - { - mem_flags = CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR; - } - } - - if (imageInfo->type != CL_MEM_OBJECT_IMAGE1D_BUFFER) - { - img = clCreateImage(context, mem_flags, imageInfo->format, &imageDesc, - host_ptr, error); - } - else - { - img = clCreateImage(context, mem_flags, imageInfo->format, &imageDesc, - nullptr, error); - } - - if (gEnablePitch) - { - pitch_buffer_data *data = - static_cast(malloc(sizeof(pitch_buffer_data))); - data->buf = host_ptr; - data->is_aligned = is_host_ptr_aligned; - if ( *error == CL_SUCCESS ) - { - int callbackError = - clSetMemObjectDestructorCallback(img, free_pitch_buffer, data); - if ( CL_SUCCESS != callbackError ) - { - free_pitch_buffer(img, data); - log_error( "ERROR: Unable to attach destructor callback to pitched 3D image. Err: %d\n", callbackError ); - clReleaseMemObject( img ); - return NULL; - } - } - else - { - free_pitch_buffer(img, data); - } - } - - if (imageDesc.buffer != NULL) - { - int callbackError = clSetMemObjectDestructorCallback( - img, release_cl_buffer, imageDesc.buffer); - if (callbackError != CL_SUCCESS) - { - log_error("Error: Unable to attach destructor callback to 1d " - "buffer image. Err: %d\n", - callbackError); - clReleaseMemObject(imageDesc.buffer); - clReleaseMemObject(img); - return NULL; - } - } - - if ( *error != CL_SUCCESS ) - { - long long unsigned imageSize = get_image_size_mb(imageInfo); - switch (imageInfo->type) - { - case CL_MEM_OBJECT_IMAGE1D: - log_error("ERROR: Unable to create 1D image of size %d (%llu " - "MB):(%s)", - (int)imageInfo->width, imageSize, - IGetErrorString(*error)); - break; - case CL_MEM_OBJECT_IMAGE2D: - log_error("ERROR: Unable to create 2D image of size %d x %d " - "(%llu MB):(%s)", - (int)imageInfo->width, (int)imageInfo->height, - imageSize, IGetErrorString(*error)); - break; - case CL_MEM_OBJECT_IMAGE3D: - log_error("ERROR: Unable to create 3D image of size %d x %d x " - "%d (%llu MB):(%s)", - (int)imageInfo->width, (int)imageInfo->height, - (int)imageInfo->depth, imageSize, - IGetErrorString(*error)); - break; - case CL_MEM_OBJECT_IMAGE1D_ARRAY: - log_error("ERROR: Unable to create 1D image array of size %d x " - "%d (%llu MB):(%s)", - (int)imageInfo->width, (int)imageInfo->arraySize, - imageSize, IGetErrorString(*error)); - break; - break; - case CL_MEM_OBJECT_IMAGE2D_ARRAY: - log_error("ERROR: Unable to create 2D image array of size %d x " - "%d x %d (%llu MB):(%s)", - (int)imageInfo->width, (int)imageInfo->height, - (int)imageInfo->arraySize, imageSize, - IGetErrorString(*error)); - break; - case CL_MEM_OBJECT_IMAGE1D_BUFFER: - log_error( - "ERROR: Unable to create 1D buffer image of size %d (%llu " - "MB):(%s)", - (int)imageInfo->width, imageSize, IGetErrorString(*error)); - break; - } - log_error("ERROR: and %llu mip levels\n", (unsigned long long) imageInfo->num_mip_levels); - return NULL; - } - - // Copy the specified data to the image via a Map operation. - size_t mappedRow, mappedSlice; - size_t width = imageInfo->width; - size_t height = 1; - size_t depth = 1; - size_t row_pitch_lod, slice_pitch_lod; - row_pitch_lod = imageInfo->rowPitch; - slice_pitch_lod = imageInfo->slicePitch; - - switch (imageInfo->type) - { - case CL_MEM_OBJECT_IMAGE1D_ARRAY: - height = imageInfo->arraySize; - depth = 1; - break; - case CL_MEM_OBJECT_IMAGE1D_BUFFER: - case CL_MEM_OBJECT_IMAGE1D: - height = depth = 1; - break; - case CL_MEM_OBJECT_IMAGE2D: - height = imageInfo->height; - depth = 1; - break; - case CL_MEM_OBJECT_IMAGE2D_ARRAY: - height = imageInfo->height; - depth = imageInfo->arraySize; - break; - case CL_MEM_OBJECT_IMAGE3D: - height = imageInfo->height; - depth = imageInfo->depth; - break; - } - - size_t origin[ 4 ] = { 0, 0, 0, 0 }; - size_t region[ 3 ] = { imageInfo->width, height, depth }; - - for ( size_t lod = 0; (gTestMipmaps && (lod < imageInfo->num_mip_levels)) || (!gTestMipmaps && (lod < 1)); lod++) - { - // Map the appropriate miplevel to copy the specified data. - if(gTestMipmaps) - { - switch (imageInfo->type) - { - case CL_MEM_OBJECT_IMAGE3D: - case CL_MEM_OBJECT_IMAGE2D_ARRAY: - origin[ 3 ] = lod; - break; - case CL_MEM_OBJECT_IMAGE2D: - case CL_MEM_OBJECT_IMAGE1D_ARRAY: - origin[ 2 ] = lod; - break; - case CL_MEM_OBJECT_IMAGE1D_BUFFER: - case CL_MEM_OBJECT_IMAGE1D: - origin[ 1 ] = lod; - break; - } - - //Adjust image dimensions as per miplevel - switch (imageInfo->type) - { - case CL_MEM_OBJECT_IMAGE3D: - depth = ( imageInfo->depth >> lod ) ? (imageInfo->depth >> lod) : 1; - case CL_MEM_OBJECT_IMAGE2D_ARRAY: - case CL_MEM_OBJECT_IMAGE2D: - height = ( imageInfo->height >> lod ) ? (imageInfo->height >> lod) : 1; - case CL_MEM_OBJECT_IMAGE1D_ARRAY: - case CL_MEM_OBJECT_IMAGE1D_BUFFER: - case CL_MEM_OBJECT_IMAGE1D: - width = ( imageInfo->width >> lod ) ? (imageInfo->width >> lod) : 1; - } - row_pitch_lod = width * get_pixel_size(imageInfo->format); - slice_pitch_lod = row_pitch_lod * height; - region[0] = width; - region[1] = height; - region[2] = depth; - } - - void* mapped = (char*)clEnqueueMapImage(queue, img, CL_TRUE, CL_MAP_WRITE, origin, region, &mappedRow, &mappedSlice, 0, NULL, NULL, error); - if (*error != CL_SUCCESS) - { - log_error( "ERROR: Unable to map image for writing: %s\n", IGetErrorString( *error ) ); - return NULL; - } - size_t mappedSlicePad = mappedSlice - (mappedRow * height); - - // For 1Darray, the height variable actually contains the arraysize, - // so it can't be used for calculating the slice padding. - if (imageInfo->type == CL_MEM_OBJECT_IMAGE1D_ARRAY) - mappedSlicePad = mappedSlice - (mappedRow * 1); - - // Copy the image. - size_t scanlineSize = row_pitch_lod; - size_t sliceSize = slice_pitch_lod - scanlineSize * height; - size_t imageSize = scanlineSize * height * depth; - size_t data_lod_offset = 0; - if( gTestMipmaps ) - data_lod_offset = compute_mip_level_offset(imageInfo, lod); - - char* src = (char*)data + data_lod_offset; - char* dst = (char*)mapped; - - if ((mappedRow == scanlineSize) && (mappedSlicePad==0 || (imageInfo->depth==0 && imageInfo->arraySize==0))) { - // Copy the whole image. - memcpy( dst, src, imageSize ); - } - else { - // Else copy one scan line at a time. - size_t dstPitch2D = 0; - switch (imageInfo->type) - { - case CL_MEM_OBJECT_IMAGE3D: - case CL_MEM_OBJECT_IMAGE2D_ARRAY: - case CL_MEM_OBJECT_IMAGE2D: - dstPitch2D = mappedRow; - break; - case CL_MEM_OBJECT_IMAGE1D_ARRAY: - case CL_MEM_OBJECT_IMAGE1D: - case CL_MEM_OBJECT_IMAGE1D_BUFFER: - dstPitch2D = mappedSlice; - break; - } - for ( size_t z = 0; z < depth; z++ ) - { - for ( size_t y = 0; y < height; y++ ) - { - memcpy( dst, src, scanlineSize ); - dst += dstPitch2D; - src += scanlineSize; - } - - // mappedSlicePad is incorrect for 2D images here, but we will exit the z loop before this is a problem. - dst += mappedSlicePad; - src += sliceSize; - } - } - - // Unmap the image. - *error = clEnqueueUnmapMemObject(queue, img, mapped, 0, NULL, NULL); - if (*error != CL_SUCCESS) - { - log_error( "ERROR: Unable to unmap image after writing: %s\n", IGetErrorString( *error ) ); - return NULL; - } - } - return img; -} +#include "../common.h" int test_copy_image_generic( cl_context context, cl_command_queue queue, image_descriptor *srcImageInfo, image_descriptor *dstImageInfo, const size_t sourcePos[], const size_t destPos[], const size_t regionSize[], MTdata d ) @@ -463,7 +64,8 @@ int test_copy_image_generic( cl_context context, cl_command_queue queue, image_d if( gDebugTrace ) log_info( " - Writing source image...\n" ); - srcImage = create_image( context, queue, srcData, srcImageInfo, &error ); + srcImage = create_image(context, queue, srcData, srcImageInfo, gEnablePitch, + gTestMipmaps, &error); if( srcImage == NULL ) return error; @@ -508,7 +110,8 @@ int test_copy_image_generic( cl_context context, cl_command_queue queue, image_d if( gDebugTrace ) log_info( " - Writing destination image...\n" ); - dstImage = create_image( context, queue, dstData, dstImageInfo, &error ); + dstImage = create_image(context, queue, dstData, dstImageInfo, gEnablePitch, + gTestMipmaps, &error); if( dstImage == NULL ) return error; diff --git a/test_conformance/images/clFillImage/test_fill_generic.cpp b/test_conformance/images/clFillImage/test_fill_generic.cpp index 24c91813..f9b9096c 100644 --- a/test_conformance/images/clFillImage/test_fill_generic.cpp +++ b/test_conformance/images/clFillImage/test_fill_generic.cpp @@ -14,338 +14,10 @@ // limitations under the License. // #include "../testBase.h" -extern void read_image_pixel_float( void *imageData, image_descriptor *imageInfo, int x, int y, int z, float *outData ); +#include "../common.h" -struct pitch_buffer_data -{ - void *buf; - bool is_aligned; -}; -static void CL_CALLBACK free_pitch_buffer(cl_mem image, void *data) -{ - struct pitch_buffer_data *d = (struct pitch_buffer_data *)data; - if (d->is_aligned) - { - align_free(d->buf); - } - else - { - free(d->buf); - } - free(d); -} -static void CL_CALLBACK release_cl_buffer(cl_mem image, void *buf) -{ - clReleaseMemObject((cl_mem)buf); -} - -cl_mem create_image( cl_context context, cl_command_queue queue, BufferOwningPtr& data, image_descriptor *imageInfo, int *error ) -{ - cl_mem img; - cl_image_desc imageDesc; - cl_mem_flags mem_flags = CL_MEM_READ_ONLY; - void *host_ptr = NULL; - - memset(&imageDesc, 0x0, sizeof(cl_image_desc)); - imageDesc.image_type = imageInfo->type; - imageDesc.image_width = imageInfo->width; - imageDesc.image_height = imageInfo->height; - imageDesc.image_depth = imageInfo->depth; - imageDesc.image_array_size = imageInfo->arraySize; - imageDesc.image_row_pitch = gEnablePitch ? imageInfo->rowPitch : 0; - imageDesc.image_slice_pitch = gEnablePitch ? imageInfo->slicePitch : 0; - cl_device_id device; - Version version; - { - cl_int err = clGetCommandQueueInfo(queue, CL_QUEUE_DEVICE, - sizeof(device), &device, nullptr); - if (err != CL_SUCCESS) - { - log_error("Error: Could not get CL_QUEUE_DEVICE from queue"); - return NULL; - } - version = get_device_cl_version(device); - } - - switch (imageInfo->type) - { - case CL_MEM_OBJECT_IMAGE1D: - if ( gDebugTrace ) - log_info( " - Creating 1D image %d ...\n", (int)imageInfo->width ); - if ( gEnablePitch ) - host_ptr = malloc( imageInfo->rowPitch ); - break; - case CL_MEM_OBJECT_IMAGE2D: - if ( gDebugTrace ) - log_info( " - Creating 2D image %d by %d ...\n", (int)imageInfo->width, (int)imageInfo->height ); - if ( gEnablePitch ) - host_ptr = malloc( imageInfo->height * imageInfo->rowPitch ); - break; - case CL_MEM_OBJECT_IMAGE3D: - if ( gDebugTrace ) - log_info( " - Creating 3D image %d by %d by %d...\n", (int)imageInfo->width, (int)imageInfo->height, (int)imageInfo->depth ); - if ( gEnablePitch ) - host_ptr = malloc( imageInfo->depth * imageInfo->slicePitch ); - break; - case CL_MEM_OBJECT_IMAGE1D_ARRAY: - if ( gDebugTrace ) - log_info( " - Creating 1D image array %d by %d...\n", (int)imageInfo->width, (int)imageInfo->arraySize ); - if ( gEnablePitch ) - host_ptr = malloc( imageInfo->arraySize * imageInfo->slicePitch ); - break; - case CL_MEM_OBJECT_IMAGE2D_ARRAY: - if ( gDebugTrace ) - log_info( " - Creating 2D image array %d by %d by %d...\n", (int)imageInfo->width, (int)imageInfo->height, (int)imageInfo->arraySize ); - if ( gEnablePitch ) - host_ptr = malloc( imageInfo->arraySize * imageInfo->slicePitch ); - break; - case CL_MEM_OBJECT_IMAGE1D_BUFFER: - if (gDebugTrace) - log_info(" - Creating 1D buffer image %d ...\n", - (int)imageInfo->width); - { - cl_int err; - cl_mem_flags buffer_flags = CL_MEM_READ_WRITE; - if (gEnablePitch) - { - if (version.major() == 1) - { - host_ptr = malloc(imageInfo->rowPitch); - } - else - { - cl_uint base_address_alignment = 0; - err = clGetDeviceInfo( - device, CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT, - sizeof(base_address_alignment), - &base_address_alignment, nullptr); - if (err != CL_SUCCESS) - { - log_error("ERROR: Could not get " - "CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT " - "from device"); - return NULL; - } - host_ptr = align_malloc(imageInfo->rowPitch, - base_address_alignment); - } - buffer_flags |= CL_MEM_USE_HOST_PTR; - } - cl_mem buffer = clCreateBuffer( - context, buffer_flags, imageInfo->rowPitch, host_ptr, &err); - if (err != CL_SUCCESS) - { - log_error("ERROR: Could not create buffer for 1D buffer " - "image. %zu bytes\n", - imageInfo->rowPitch); - return NULL; - } - imageDesc.buffer = buffer; - } - break; - } - - if (gEnablePitch) - { - if ( NULL == host_ptr ) - { - log_error("ERROR: Unable to create backing store for pitched 3D " - "image. %zu bytes\n", - imageInfo->depth * imageInfo->slicePitch); - return NULL; - } - if (imageInfo->type != CL_MEM_OBJECT_IMAGE1D_BUFFER) - { - mem_flags = CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR; - } - } - - if (imageInfo->type != CL_MEM_OBJECT_IMAGE1D_BUFFER) - { - img = clCreateImage(context, mem_flags, imageInfo->format, &imageDesc, - host_ptr, error); - } - else - { - img = clCreateImage(context, mem_flags, imageInfo->format, &imageDesc, - nullptr, error); - } - - if (gEnablePitch) - { - struct pitch_buffer_data *data = (struct pitch_buffer_data *)malloc( - sizeof(struct pitch_buffer_data)); - data->buf = host_ptr; - data->is_aligned = (version.major() != 1) - && (imageInfo->type == CL_MEM_OBJECT_IMAGE1D_BUFFER); - if (*error == CL_SUCCESS) - { - int callbackError = - clSetMemObjectDestructorCallback(img, free_pitch_buffer, data); - if (CL_SUCCESS != callbackError) - { - free_pitch_buffer(img, data); - log_error("ERROR: Unable to attach destructor callback to " - "pitched 3D image. Err: %d\n", - callbackError); - clReleaseMemObject(img); - return NULL; - } - } - else - { - free_pitch_buffer(img, data); - } - } - - if (imageDesc.buffer != NULL) - { - int callbackError = clSetMemObjectDestructorCallback( - img, release_cl_buffer, imageDesc.buffer); - if (callbackError != CL_SUCCESS) - { - log_error("Error: Unable to attach destructor callback to 1d " - "buffer image. Err: %d\n", - callbackError); - clReleaseMemObject(imageDesc.buffer); - clReleaseMemObject(img); - return NULL; - } - } - - if ( *error != CL_SUCCESS ) - { - long long unsigned imageSize = get_image_size_mb( imageInfo ); - switch (imageInfo->type) - { - case CL_MEM_OBJECT_IMAGE1D: - log_error( "ERROR: Unable to create 1D image of size %d (%llu MB): %s\n", (int)imageInfo->width, imageSize, IGetErrorString( *error ) ); - break; - case CL_MEM_OBJECT_IMAGE2D: - log_error( "ERROR: Unable to create 2D image of size %d x %d (%llu MB): %s\n", (int)imageInfo->width, (int)imageInfo->height, imageSize, IGetErrorString( *error ) ); - break; - case CL_MEM_OBJECT_IMAGE3D: - log_error( "ERROR: Unable to create 3D image of size %d x %d x %d (%llu MB): %s\n", (int)imageInfo->width, (int)imageInfo->height, (int)imageInfo->depth, imageSize, IGetErrorString( *error ) ); - break; - case CL_MEM_OBJECT_IMAGE1D_ARRAY: - log_error( "ERROR: Unable to create 1D image array of size %d x %d (%llu MB): %s\n", (int)imageInfo->width, (int)imageInfo->arraySize, imageSize, IGetErrorString( *error ) ); - break; - break; - case CL_MEM_OBJECT_IMAGE2D_ARRAY: - log_error( "ERROR: Unable to create 2D image array of size %d x %d x %d (%llu MB): %s\n", (int)imageInfo->width, (int)imageInfo->height, (int)imageInfo->arraySize, imageSize, IGetErrorString( *error ) ); - break; - case CL_MEM_OBJECT_IMAGE1D_BUFFER: - log_error( - "ERROR: Unable to create 1D buffer image of size %d (%llu " - "MB):(%s)", - (int)imageInfo->width, imageSize, IGetErrorString(*error)); - break; - } - return NULL; - } - - // Copy the specified data to the image via a Map operation. - size_t mappedRow, mappedSlice; - size_t height; - size_t depth; - size_t imageSize = 0; - - switch (imageInfo->type) - { - case CL_MEM_OBJECT_IMAGE1D_ARRAY: - height = imageInfo->arraySize; - depth = 1; - imageSize = imageInfo->rowPitch * imageInfo->arraySize; - break; - case CL_MEM_OBJECT_IMAGE1D_BUFFER: - case CL_MEM_OBJECT_IMAGE1D: - height = depth = 1; - imageSize = imageInfo->rowPitch; - break; - case CL_MEM_OBJECT_IMAGE2D: - height = imageInfo->height; - depth = 1; - imageSize = imageInfo->rowPitch * imageInfo->height; - break; - case CL_MEM_OBJECT_IMAGE2D_ARRAY: - height = imageInfo->height; - depth = imageInfo->arraySize; - imageSize = imageInfo->slicePitch * imageInfo->arraySize; - break; - case CL_MEM_OBJECT_IMAGE3D: - height = imageInfo->height; - depth = imageInfo->depth; - imageSize = imageInfo->slicePitch * imageInfo->depth; - break; - default: - log_error("ERROR Invalid imageInfo->type = %d\n", imageInfo->type); - height = 0; - depth = 0; - break; - } - - size_t origin[ 3 ] = { 0, 0, 0 }; - size_t region[ 3 ] = { imageInfo->width, height, depth }; - - void* mapped = (char*)clEnqueueMapImage(queue, img, CL_TRUE, CL_MAP_WRITE, origin, region, &mappedRow, &mappedSlice, 0, NULL, NULL, error); - if (*error != CL_SUCCESS || !mapped) - { - log_error( "ERROR: Unable to map image for writing: %s\n", IGetErrorString( *error ) ); - return NULL; - } - size_t mappedSlicePad = mappedSlice - (mappedRow * height); - - // Copy the image. - size_t scanlineSize = imageInfo->rowPitch; - size_t sliceSize = imageInfo->slicePitch - scanlineSize * height; - - char* src = (char*)data; - char* dst = (char*)mapped; - - if ((mappedRow == scanlineSize) && ((mappedSlice == imageInfo->slicePitch) || (imageInfo->depth==0 && imageInfo->arraySize==0))) { - // Copy the whole image. - memcpy( dst, src, imageSize ); - } - else { - // Else copy one scan line at a time. - size_t dstPitch2D = 0; - switch (imageInfo->type) - { - case CL_MEM_OBJECT_IMAGE3D: - case CL_MEM_OBJECT_IMAGE2D_ARRAY: - case CL_MEM_OBJECT_IMAGE2D: - dstPitch2D = mappedRow; - break; - case CL_MEM_OBJECT_IMAGE1D_ARRAY: - case CL_MEM_OBJECT_IMAGE1D: - case CL_MEM_OBJECT_IMAGE1D_BUFFER: dstPitch2D = mappedSlice; break; - } - - for ( size_t z = 0; z < depth; z++ ) - { - for ( size_t y = 0; y < height; y++ ) - { - memcpy( dst, src, imageInfo->width * get_pixel_size(imageInfo->format) ); - dst += dstPitch2D; - src += scanlineSize; - } - - // mappedSlicePad is incorrect for 2D images here, but we will exit the z loop before this is a problem. - dst += mappedSlicePad; - src += sliceSize; - } - } - - // Unmap the image. - *error = clEnqueueUnmapMemObject(queue, img, mapped, 0, NULL, NULL); - if (*error != CL_SUCCESS) - { - log_error( "ERROR: Unable to unmap image after writing: %s\n", IGetErrorString( *error ) ); - return NULL; - } - - return img; -} +extern void read_image_pixel_float(void *imageData, image_descriptor *imageInfo, + int x, int y, int z, float *outData); static void fill_region_with_value( image_descriptor *imageInfo, void *imageValues, void *value, const size_t origin[], const size_t region[] ) @@ -438,7 +110,8 @@ int test_fill_image_generic( cl_context context, cl_command_queue queue, image_d if ( gDebugTrace ) log_info( " - Creating image...\n" ); - image = create_image( context, queue, imgData, imageInfo, &error ); + image = create_image(context, queue, imgData, imageInfo, gEnablePitch, + false, &error); if ( image == NULL ) return error; diff --git a/test_conformance/images/common.cpp b/test_conformance/images/common.cpp index 178f962f..f11a0215 100644 --- a/test_conformance/images/common.cpp +++ b/test_conformance/images/common.cpp @@ -146,3 +146,446 @@ size_t random_in_ranges(size_t minimum, size_t rangeA, size_t rangeB, MTdata d) if (rangeA < minimum) return rangeA; return (size_t)random_in_range((int)minimum, (int)rangeA - 1, d); } + +using free_function_t = void (*)(void *); +struct pitch_buffer_data +{ + void *buf; + free_function_t free_fn; + + static void CL_CALLBACK free_buffer(cl_mem, void *data) + { + pitch_buffer_data *d = static_cast(data); + d->free_fn(d->buf); + delete d; + } +}; + +static void CL_CALLBACK release_cl_buffer(cl_mem image, void *buf) +{ + clReleaseMemObject((cl_mem)buf); +} + +clMemWrapper create_image(cl_context context, cl_command_queue queue, + BufferOwningPtr &data, + image_descriptor *imageInfo, bool enable_pitch, + bool create_mipmaps, int *error) +{ + cl_mem img; + cl_image_desc imageDesc; + cl_mem_flags mem_flags = CL_MEM_READ_ONLY; + void *host_ptr = nullptr; + bool is_host_ptr_aligned = false; + + memset(&imageDesc, 0x0, sizeof(cl_image_desc)); + imageDesc.image_type = imageInfo->type; + imageDesc.image_width = imageInfo->width; + imageDesc.image_height = imageInfo->height; + imageDesc.image_depth = imageInfo->depth; + imageDesc.image_array_size = imageInfo->arraySize; + imageDesc.image_row_pitch = enable_pitch ? imageInfo->rowPitch : 0; + imageDesc.image_slice_pitch = enable_pitch ? imageInfo->slicePitch : 0; + imageDesc.num_mip_levels = create_mipmaps ? imageInfo->num_mip_levels : 0; + + Version version; + cl_device_id device; + { + cl_int err = clGetCommandQueueInfo(queue, CL_QUEUE_DEVICE, + sizeof(device), &device, nullptr); + if (err != CL_SUCCESS) + { + log_error("Error: Could not get CL_QUEUE_DEVICE from queue"); + return nullptr; + } + version = get_device_cl_version(device); + } + + switch (imageInfo->type) + { + case CL_MEM_OBJECT_IMAGE1D: + if (gDebugTrace) + log_info(" - Creating 1D image %d ...\n", + (int)imageInfo->width); + if (enable_pitch) host_ptr = malloc(imageInfo->rowPitch); + break; + case CL_MEM_OBJECT_IMAGE2D: + if (gDebugTrace) + log_info(" - Creating 2D image %d by %d ...\n", + (int)imageInfo->width, (int)imageInfo->height); + if (enable_pitch) + host_ptr = malloc(imageInfo->height * imageInfo->rowPitch); + break; + case CL_MEM_OBJECT_IMAGE3D: + if (gDebugTrace) + log_info(" - Creating 3D image %d by %d by %d...\n", + (int)imageInfo->width, (int)imageInfo->height, + (int)imageInfo->depth); + if (enable_pitch) + host_ptr = malloc(imageInfo->depth * imageInfo->slicePitch); + break; + case CL_MEM_OBJECT_IMAGE1D_ARRAY: + if (gDebugTrace) + log_info(" - Creating 1D image array %d by %d...\n", + (int)imageInfo->width, (int)imageInfo->arraySize); + if (enable_pitch) + host_ptr = malloc(imageInfo->arraySize * imageInfo->slicePitch); + break; + case CL_MEM_OBJECT_IMAGE2D_ARRAY: + if (gDebugTrace) + log_info(" - Creating 2D image array %d by %d by %d...\n", + (int)imageInfo->width, (int)imageInfo->height, + (int)imageInfo->arraySize); + if (enable_pitch) + host_ptr = malloc(imageInfo->arraySize * imageInfo->slicePitch); + break; + case CL_MEM_OBJECT_IMAGE1D_BUFFER: + if (gDebugTrace) + log_info(" - Creating 1D buffer image %d ...\n", + (int)imageInfo->width); + { + cl_int err; + cl_mem_flags buffer_flags = CL_MEM_READ_WRITE; + if (enable_pitch) + { + if (version.major() == 1) + { + host_ptr = malloc(imageInfo->rowPitch); + } + else + { + cl_uint base_address_alignment = 0; + err = clGetDeviceInfo( + device, CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT, + sizeof(base_address_alignment), + &base_address_alignment, nullptr); + if (err != CL_SUCCESS) + { + log_error("ERROR: Could not get " + "CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT " + "from device"); + return nullptr; + } + host_ptr = align_malloc(imageInfo->rowPitch, + base_address_alignment); + is_host_ptr_aligned = true; + } + buffer_flags |= CL_MEM_USE_HOST_PTR; + } + + cl_mem buffer = clCreateBuffer( + context, buffer_flags, imageInfo->rowPitch, host_ptr, &err); + if (err != CL_SUCCESS) + { + log_error("ERROR: Could not create buffer for 1D buffer " + "image. %zu bytes\n", + imageInfo->width); + if (host_ptr) + { + if (is_host_ptr_aligned) + { + align_free(host_ptr); + } + else + { + free(host_ptr); + } + } + return nullptr; + } + imageDesc.buffer = buffer; + } + break; + } + + if (gDebugTrace && create_mipmaps) + log_info(" - with %llu mip levels\n", + (unsigned long long)imageInfo->num_mip_levels); + + if (enable_pitch) + { + if (nullptr == host_ptr) + { + log_error("ERROR: Unable to create backing store for pitched 3D " + "image. %zu bytes\n", + imageInfo->depth * imageInfo->slicePitch); + return nullptr; + } + if (imageInfo->type != CL_MEM_OBJECT_IMAGE1D_BUFFER) + { + mem_flags = CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR; + } + } + + if (imageInfo->type != CL_MEM_OBJECT_IMAGE1D_BUFFER) + { + img = clCreateImage(context, mem_flags, imageInfo->format, &imageDesc, + host_ptr, error); + } + else + { + img = clCreateImage(context, mem_flags, imageInfo->format, &imageDesc, + nullptr, error); + } + + if (enable_pitch) + { + free_function_t free_fn = is_host_ptr_aligned ? align_free : free; + if (*error == CL_SUCCESS) + { + pitch_buffer_data *buf_data = new pitch_buffer_data; + buf_data->buf = host_ptr; + buf_data->free_fn = free_fn; + + int callbackError = clSetMemObjectDestructorCallback( + img, pitch_buffer_data::free_buffer, buf_data); + if (CL_SUCCESS != callbackError) + { + pitch_buffer_data::free_buffer(img, buf_data); + log_error("ERROR: Unable to attach destructor callback to " + "pitched 3D image. Err: %d\n", + callbackError); + clReleaseMemObject(img); + return nullptr; + } + } + else + { + free_fn(host_ptr); + } + } + + if (imageDesc.buffer != nullptr) + { + int callbackError = clSetMemObjectDestructorCallback( + img, release_cl_buffer, imageDesc.buffer); + if (callbackError != CL_SUCCESS) + { + log_error("Error: Unable to attach destructor callback to 1d " + "buffer image. Err: %d\n", + callbackError); + clReleaseMemObject(imageDesc.buffer); + clReleaseMemObject(img); + return nullptr; + } + } + + if (*error != CL_SUCCESS) + { + long long unsigned imageSize = get_image_size_mb(imageInfo); + switch (imageInfo->type) + { + case CL_MEM_OBJECT_IMAGE1D: + log_error("ERROR: Unable to create 1D image of size %d (%llu " + "MB):(%s)", + (int)imageInfo->width, imageSize, + IGetErrorString(*error)); + break; + case CL_MEM_OBJECT_IMAGE2D: + log_error("ERROR: Unable to create 2D image of size %d x %d " + "(%llu MB):(%s)", + (int)imageInfo->width, (int)imageInfo->height, + imageSize, IGetErrorString(*error)); + break; + case CL_MEM_OBJECT_IMAGE3D: + log_error("ERROR: Unable to create 3D image of size %d x %d x " + "%d (%llu MB):(%s)", + (int)imageInfo->width, (int)imageInfo->height, + (int)imageInfo->depth, imageSize, + IGetErrorString(*error)); + break; + case CL_MEM_OBJECT_IMAGE1D_ARRAY: + log_error("ERROR: Unable to create 1D image array of size %d x " + "%d (%llu MB):(%s)", + (int)imageInfo->width, (int)imageInfo->arraySize, + imageSize, IGetErrorString(*error)); + break; + case CL_MEM_OBJECT_IMAGE2D_ARRAY: + log_error("ERROR: Unable to create 2D image array of size %d x " + "%d x %d (%llu MB):(%s)", + (int)imageInfo->width, (int)imageInfo->height, + (int)imageInfo->arraySize, imageSize, + IGetErrorString(*error)); + break; + case CL_MEM_OBJECT_IMAGE1D_BUFFER: + log_error( + "ERROR: Unable to create 1D buffer image of size %d (%llu " + "MB):(%s)", + (int)imageInfo->width, imageSize, IGetErrorString(*error)); + break; + } + log_error("ERROR: and %llu mip levels\n", + (unsigned long long)imageInfo->num_mip_levels); + return nullptr; + } + + // Copy the specified data to the image via a Map operation. + size_t mappedRow, mappedSlice; + size_t width = imageInfo->width; + size_t height = 1; + size_t depth = 1; + size_t row_pitch_lod, slice_pitch_lod; + row_pitch_lod = imageInfo->rowPitch; + slice_pitch_lod = imageInfo->slicePitch; + + switch (imageInfo->type) + { + case CL_MEM_OBJECT_IMAGE1D_ARRAY: + height = imageInfo->arraySize; + depth = 1; + break; + case CL_MEM_OBJECT_IMAGE1D_BUFFER: + case CL_MEM_OBJECT_IMAGE1D: height = depth = 1; break; + case CL_MEM_OBJECT_IMAGE2D: + height = imageInfo->height; + depth = 1; + break; + case CL_MEM_OBJECT_IMAGE2D_ARRAY: + height = imageInfo->height; + depth = imageInfo->arraySize; + break; + case CL_MEM_OBJECT_IMAGE3D: + height = imageInfo->height; + depth = imageInfo->depth; + break; + default: + log_error("ERROR Invalid imageInfo->type = %d\n", imageInfo->type); + height = 0; + depth = 0; + return nullptr; + break; + } + + size_t origin[4] = { 0, 0, 0, 0 }; + size_t region[3] = { imageInfo->width, height, depth }; + + for (size_t lod = 0; (create_mipmaps && (lod < imageInfo->num_mip_levels)) + || (!create_mipmaps && (lod < 1)); + lod++) + { + // Map the appropriate miplevel to copy the specified data. + if (create_mipmaps) + { + switch (imageInfo->type) + { + case CL_MEM_OBJECT_IMAGE3D: + case CL_MEM_OBJECT_IMAGE2D_ARRAY: + origin[0] = origin[1] = origin[2] = 0; + origin[3] = lod; + break; + case CL_MEM_OBJECT_IMAGE2D: + case CL_MEM_OBJECT_IMAGE1D_ARRAY: + origin[0] = origin[1] = origin[3] = 0; + origin[2] = lod; + break; + case CL_MEM_OBJECT_IMAGE1D_BUFFER: + case CL_MEM_OBJECT_IMAGE1D: + origin[0] = origin[2] = origin[3] = 0; + origin[1] = lod; + break; + } + + // Adjust image dimensions as per miplevel + switch (imageInfo->type) + { + case CL_MEM_OBJECT_IMAGE3D: + depth = (imageInfo->depth >> lod) + ? (imageInfo->depth >> lod) + : 1; + case CL_MEM_OBJECT_IMAGE2D_ARRAY: + case CL_MEM_OBJECT_IMAGE2D: + height = (imageInfo->height >> lod) + ? (imageInfo->height >> lod) + : 1; + case CL_MEM_OBJECT_IMAGE1D_ARRAY: + case CL_MEM_OBJECT_IMAGE1D_BUFFER: + case CL_MEM_OBJECT_IMAGE1D: + width = (imageInfo->width >> lod) + ? (imageInfo->width >> lod) + : 1; + } + row_pitch_lod = width * get_pixel_size(imageInfo->format); + slice_pitch_lod = row_pitch_lod * height; + region[0] = width; + region[1] = height; + region[2] = depth; + } + + char *mapped = static_cast(clEnqueueMapImage( + queue, img, CL_TRUE, CL_MAP_WRITE, origin, region, &mappedRow, + &mappedSlice, 0, nullptr, nullptr, error)); + if (*error != CL_SUCCESS || !mapped) + { + log_error("ERROR: Unable to map image for writing: %s\n", + IGetErrorString(*error)); + return nullptr; + } + size_t mappedSlicePad = mappedSlice - (mappedRow * height); + + // For 1Darray, the height variable actually contains the arraysize, + // so it can't be used for calculating the slice padding. + if (imageInfo->type == CL_MEM_OBJECT_IMAGE1D_ARRAY) + mappedSlicePad = mappedSlice - (mappedRow * 1); + + // Copy the image. + size_t scanlineSize = row_pitch_lod; + size_t sliceSize = slice_pitch_lod - scanlineSize * height; + size_t imageSize = scanlineSize * height * depth; + size_t data_lod_offset = 0; + if (create_mipmaps) + { + data_lod_offset = compute_mip_level_offset(imageInfo, lod); + } + + char *src = static_cast(data) + data_lod_offset; + char *dst = mapped; + + if ((mappedRow == scanlineSize) + && (mappedSlicePad == 0 + || (imageInfo->depth == 0 && imageInfo->arraySize == 0))) + { + // Copy the whole image. + memcpy(dst, src, imageSize); + } + else + { + // Else copy one scan line at a time. + size_t dstPitch2D = 0; + switch (imageInfo->type) + { + case CL_MEM_OBJECT_IMAGE3D: + case CL_MEM_OBJECT_IMAGE2D_ARRAY: + case CL_MEM_OBJECT_IMAGE2D: dstPitch2D = mappedRow; break; + case CL_MEM_OBJECT_IMAGE1D_ARRAY: + case CL_MEM_OBJECT_IMAGE1D: + case CL_MEM_OBJECT_IMAGE1D_BUFFER: + dstPitch2D = mappedSlice; + break; + } + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + memcpy(dst, src, scanlineSize); + dst += dstPitch2D; + src += scanlineSize; + } + + // mappedSlicePad is incorrect for 2D images here, but we will + // exit the z loop before this is a problem. + dst += mappedSlicePad; + src += sliceSize; + } + } + + // Unmap the image. + *error = + clEnqueueUnmapMemObject(queue, img, mapped, 0, nullptr, nullptr); + if (*error != CL_SUCCESS) + { + log_error("ERROR: Unable to unmap image after writing: %s\n", + IGetErrorString(*error)); + return nullptr; + } + } + return img; +} diff --git a/test_conformance/images/common.h b/test_conformance/images/common.h index 27e8679b..f7aa1495 100644 --- a/test_conformance/images/common.h +++ b/test_conformance/images/common.h @@ -50,4 +50,9 @@ int get_format_list(cl_context context, cl_mem_object_type imageType, cl_mem_flags flags); size_t random_in_ranges(size_t minimum, size_t rangeA, size_t rangeB, MTdata d); +clMemWrapper create_image(cl_context context, cl_command_queue queue, + BufferOwningPtr &data, + image_descriptor *imageInfo, bool enable_pitch, + bool create_mipmaps, int *error); + #endif // IMAGES_COMMON_H