Files
OpenCL-CTS/test_conformance/gl/test_images_write_common.cpp
Kevin Petit d8733efc0f Synchronise with Khronos-private Gitlab branch
The maintenance of the conformance tests is moving to Github.

This commit contains all the changes that have been done in
Gitlab since the first public release of the conformance tests.

Signed-off-by: Kevin Petit <kevin.petit@arm.com>
2019-03-05 16:23:49 +00:00

601 lines
20 KiB
C++

//
// Copyright (c) 2017 The Khronos Group 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "testBase.h"
#include "common.h"
#include <limits.h>
#if defined( __APPLE__ )
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#include <CL/cl_gl.h>
#endif
extern "C" { extern cl_uint gRandomSeed; };
#pragma mark -
#pragma mark Write test kernels
static const char *kernelpattern_image_write_1D =
"__kernel void sample_test( __global %s4 *source, write_only image1d_t dest )\n"
"{\n"
" uint index = get_global_id(0);\n"
" %s4 value = source[index];\n"
" write_image%s( dest, index, %s(value));\n"
"}\n";
static const char *kernelpattern_image_write_1D_half =
"__kernel void sample_test( __global half4 *source, write_only image1d_t dest )\n"
"{\n"
" uint index = get_global_id(0);\n"
" write_imagef( dest, index, vload_half4(index, (half *)source));\n"
"}\n";
static const char *kernelpattern_image_write_2D =
"__kernel void sample_test( __global %s4 *source, write_only image2d_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" uint index = tidY * get_image_width( dest ) + tidX;\n"
" %s4 value = source[index];\n"
" write_image%s( dest, (int2)( tidX, tidY ), %s(value));\n"
"}\n";
static const char *kernelpattern_image_write_2D_half =
"__kernel void sample_test( __global half4 *source, write_only image2d_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" uint index = tidY * get_image_width( dest ) + tidX;\n"
" write_imagef( dest, (int2)( tidX, tidY ), vload_half4(index, (half *)source));\n"
"}\n";
static const char *kernelpattern_image_write_1Darray =
"__kernel void sample_test( __global %s4 *source, write_only image1d_array_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" uint index = tidY * get_image_width( dest ) + tidX;\n"
" %s4 value = source[index];\n"
" write_image%s( dest, (int2)( tidX, tidY ), %s(value));\n"
"}\n";
static const char *kernelpattern_image_write_1Darray_half =
"__kernel void sample_test( __global half4 *source, write_only image1d_array_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" uint index = tidY * get_image_width( dest ) + tidX;\n"
" write_imagef( dest, (int2)( tidX, tidY ), vload_half4(index, (half *)source));\n"
"}\n";
static const char *kernelpattern_image_write_3D =
"#pragma OPENCL EXTENSION cl_khr_3d_image_writes: enable \n"
"__kernel void sample_test( __global %s4 *source, write_only image3d_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" int tidZ = get_global_id(2);\n"
" int width = get_image_width( dest );\n"
" int height = get_image_height( dest );\n"
" int index = tidZ * width * height + tidY * width + tidX;\n"
" %s4 value = source[index];\n"
" write_image%s( dest, (int4)( tidX, tidY, tidZ, 0 ), %s(value));\n"
"}\n";
static const char *kernelpattern_image_write_3D_half =
"#pragma OPENCL EXTENSION cl_khr_3d_image_writes: enable \n"
"__kernel void sample_test( __global half4 *source, write_only image3d_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" int tidZ = get_global_id(2);\n"
" int width = get_image_width( dest );\n"
" int height = get_image_height( dest );\n"
" int index = tidZ * width * height + tidY * width + tidX;\n"
" write_imagef( dest, (int4)( tidX, tidY, tidZ, 0 ), vload_half4(index, (half *)source));\n"
"}\n";
static const char *kernelpattern_image_write_2Darray =
"__kernel void sample_test( __global %s4 *source, write_only image2d_array_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" int tidZ = get_global_id(2);\n"
" int width = get_image_width( dest );\n"
" int height = get_image_height( dest );\n"
" int index = tidZ * width * height + tidY * width + tidX;\n"
" %s4 value = source[index];\n"
" write_image%s( dest, (int4)( tidX, tidY, tidZ, 0 ), %s(value));\n"
"}\n";
static const char *kernelpattern_image_write_2Darray_half =
"__kernel void sample_test( __global half4 *source, write_only image2d_array_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" int tidZ = get_global_id(2);\n"
" int width = get_image_width( dest );\n"
" int height = get_image_height( dest );\n"
" int index = tidZ * width * height + tidY * width + tidX;\n"
" write_imagef( dest, (int4)( tidX, tidY, tidZ, 0 ), vload_half4(index, (half *)source));\n"
"}\n";
#pragma mark -
#pragma mark Utility functions
static const char* get_appropriate_write_kernel(GLenum target,
ExplicitType type)
{
switch (get_base_gl_target(target)) {
case GL_TEXTURE_1D:
case GL_TEXTURE_BUFFER:
if (type == kHalf)
return kernelpattern_image_write_1D_half;
else
return kernelpattern_image_write_1D;
break;
case GL_TEXTURE_1D_ARRAY:
if (type == kHalf)
return kernelpattern_image_write_1Darray_half;
else
return kernelpattern_image_write_1Darray;
break;
case GL_COLOR_ATTACHMENT0:
case GL_RENDERBUFFER:
case GL_TEXTURE_RECTANGLE_EXT:
case GL_TEXTURE_2D:
if (type == kHalf)
return kernelpattern_image_write_2D_half;
else
return kernelpattern_image_write_2D;
break;
case GL_TEXTURE_2D_ARRAY:
if (type == kHalf)
return kernelpattern_image_write_2Darray_half;
else
return kernelpattern_image_write_2Darray;
break;
case GL_TEXTURE_3D:
if (type == kHalf)
return kernelpattern_image_write_3D_half;
else
return kernelpattern_image_write_3D;
break;
default:
log_error("Unsupported GL tex target (%s) passed to write test: "
"%s (%s):%d", GetGLTargetName(target), __FUNCTION__,
__FILE__, __LINE__);
return NULL;
}
}
void set_dimensions_by_target(GLenum target, size_t *dims, size_t sizes[3],
size_t width, size_t height, size_t depth)
{
switch (get_base_gl_target(target)) {
case GL_TEXTURE_1D:
sizes[0] = width;
*dims = 1;
break;
case GL_TEXTURE_BUFFER:
sizes[0] = width;
*dims = 1;
break;
case GL_TEXTURE_1D_ARRAY:
sizes[0] = width;
sizes[1] = height;
*dims = 2;
break;
case GL_COLOR_ATTACHMENT0:
case GL_RENDERBUFFER:
case GL_TEXTURE_RECTANGLE_EXT:
case GL_TEXTURE_2D:
sizes[0] = width;
sizes[1] = height;
*dims = 2;
break;
case GL_TEXTURE_2D_ARRAY:
sizes[0] = width;
sizes[1] = height;
sizes[2] = depth;
*dims = 3;
break;
case GL_TEXTURE_3D:
sizes[0] = width;
sizes[1] = height;
sizes[2] = depth;
*dims = 3;
break;
default:
log_error("Unsupported GL tex target (%s) passed to write test: "
"%s (%s):%d", GetGLTargetName(target), __FUNCTION__,
__FILE__, __LINE__);
}
}
int test_cl_image_write( cl_context context, cl_command_queue queue,
GLenum target, cl_mem clImage, size_t width, size_t height, size_t depth,
cl_image_format *outFormat, ExplicitType *outType, void **outSourceBuffer,
MTdata d, bool supports_half )
{
size_t global_dims, global_sizes[3];
clProgramWrapper program;
clKernelWrapper kernel;
clMemWrapper inStream;
char* programPtr;
int error;
char kernelSource[2048];
// What CL format did we get from the texture?
error = clGetImageInfo(clImage, CL_IMAGE_FORMAT, sizeof(cl_image_format),
outFormat, NULL);
test_error(error, "Unable to get the CL image format");
// Create the kernel source. The target and the data type will influence
// which particular kernel we choose.
*outType = get_write_kernel_type( outFormat );
size_t channelSize = get_explicit_type_size(*outType);
const char* appropriateKernel = get_appropriate_write_kernel(target,
*outType);
if (*outType == kHalf && !supports_half) {
log_info("cl_khr_fp16 isn't supported. Skip this test.\n");
return 0;
}
const char* suffix = get_kernel_suffix( outFormat );
const char* convert = get_write_conversion( outFormat, *outType );
sprintf(kernelSource, appropriateKernel, get_explicit_type_name( *outType ),
get_explicit_type_name( *outType ), suffix, convert);
programPtr = kernelSource;
if( create_single_kernel_helper( context, &program, &kernel, 1,
(const char **)&programPtr, "sample_test" ) )
{
return -1;
}
// Create an appropriately-sized output buffer.
*outSourceBuffer = CreateRandomData(*outType, width*height*depth*4, d);
inStream = clCreateBuffer( context, CL_MEM_COPY_HOST_PTR,
channelSize * 4 * width * height * depth, *outSourceBuffer, &error );
test_error( error, "Unable to create output buffer" );
clSamplerWrapper sampler = clCreateSampler( context, CL_FALSE,
CL_ADDRESS_NONE, CL_FILTER_NEAREST, &error );
test_error( error, "Unable to create sampler" );
error = clSetKernelArg( kernel, 0, sizeof( inStream ), &inStream );
test_error( error, "Unable to set kernel arguments" );
error = clSetKernelArg( kernel, 1, sizeof( clImage ), &clImage );
test_error( error, "Unable to set kernel arguments" );
// Flush and Acquire.
glFlush();
error = (*clEnqueueAcquireGLObjects_ptr)( queue, 1, &clImage, 0, NULL, NULL);
test_error( error, "Unable to acquire GL obejcts");
// Execute ( letting OpenCL choose the local size )
// Setup the global dimensions and sizes based on the target type.
set_dimensions_by_target(target, &global_dims, global_sizes,
width, height, depth);
error = clEnqueueNDRangeKernel( queue, kernel, global_dims, NULL,
global_sizes, NULL, 0, NULL, NULL );
test_error( error, "Unable to execute test kernel" );
clEventWrapper event;
error = (*clEnqueueReleaseGLObjects_ptr)( queue, 1, &clImage, 0, NULL, &event );
test_error(error, "clEnqueueReleaseGLObjects failed");
error = clWaitForEvents( 1, &event );
test_error(error, "clWaitForEvents failed");
return 0;
}
static int test_image_write( cl_context context, cl_command_queue queue,
GLenum glTarget, GLuint glTexture, size_t width, size_t height, size_t depth,
cl_image_format *outFormat, ExplicitType *outType, void **outSourceBuffer,
MTdata d, bool supports_half )
{
int error;
// Create a CL image from the supplied GL texture
clMemWrapper image = (*clCreateFromGLTexture_ptr)( context, CL_MEM_WRITE_ONLY,
glTarget, 0, glTexture, &error );
if ( error != CL_SUCCESS ) {
print_error( error, "Unable to create CL image from GL texture" );
GLint fmt;
glGetTexLevelParameteriv( glTarget, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt );
log_error( " Supplied GL texture was base format %s and internal "
"format %s\n", GetGLBaseFormatName( fmt ), GetGLFormatName( fmt ) );
return error;
}
return test_cl_image_write( context, queue, glTarget, image,
width, height, depth, outFormat, outType, outSourceBuffer, d, supports_half );
}
int supportsHalf(cl_context context, bool* supports_half)
{
int error;
size_t size;
cl_uint numDev;
error = clGetContextInfo(context, CL_CONTEXT_NUM_DEVICES, sizeof(cl_uint), &numDev, NULL);
test_error(error, "clGetContextInfo for CL_CONTEXT_NUM_DEVICES failed");
cl_device_id* devices = new cl_device_id[numDev];
error = clGetContextInfo(context, CL_CONTEXT_DEVICES, numDev * sizeof(cl_device_id), devices, NULL);
test_error(error, "clGetContextInfo for CL_CONTEXT_DEVICES failed");
// Get the extensions string for the device
error = clGetDeviceInfo(devices[0], CL_DEVICE_EXTENSIONS, 0, NULL, &size);
test_error(error, "clGetDeviceInfo for CL_DEVICE_EXTENSIONS size failed");
char *extensions = new char[size+1];
if (extensions == 0) {
log_error("Failed to allocate memory for extensions string.\n");
return -1;
}
memset( extensions, CHAR_MIN, sizeof(char)*(size+1) );
error = clGetDeviceInfo(devices[0], CL_DEVICE_EXTENSIONS, sizeof(char)*size, extensions, NULL);
test_error(error, "clGetDeviceInfo for CL_DEVICE_EXTENSIONS failed");
*supports_half = strstr(extensions, "cl_khr_fp16");
delete [] extensions;
delete [] devices;
return error;
}
static int test_image_format_write( cl_context context, cl_command_queue queue,
size_t width, size_t height, size_t depth, GLenum target, GLenum format,
GLenum internalFormat, GLenum glType, ExplicitType type, MTdata d )
{
int error;
// If we're testing a half float format, then we need to determine the
// rounding mode of this machine. Punt if we fail to do so.
if( type == kHalf )
if( DetectFloatToHalfRoundingMode(queue) )
return 1;
// Create an appropriate GL texture or renderbuffer, given the target.
glTextureWrapper glTexture;
glBufferWrapper glBuf;
glFramebufferWrapper glFramebuffer;
glRenderbufferWrapper glRenderbuffer;
switch (get_base_gl_target(target)) {
case GL_TEXTURE_1D:
CreateGLTexture1D( width, target, format, internalFormat, glType,
type, &glTexture, &error, false, d );
break;
case GL_TEXTURE_BUFFER:
CreateGLTextureBuffer( width, target, format, internalFormat, glType,
type, &glTexture, &glBuf, &error, false, d );
break;
case GL_TEXTURE_1D_ARRAY:
CreateGLTexture1DArray( width, height, target, format, internalFormat,
glType, type, &glTexture, &error, false, d );
break;
case GL_TEXTURE_RECTANGLE_EXT:
case GL_TEXTURE_2D:
CreateGLTexture2D( width, height, target, format, internalFormat, glType,
type, &glTexture, &error, false, d );
break;
case GL_COLOR_ATTACHMENT0:
case GL_RENDERBUFFER:
CreateGLRenderbuffer(width, height, target, format, internalFormat,
glType, type, &glFramebuffer, &glRenderbuffer, &error, d, false);
case GL_TEXTURE_2D_ARRAY:
CreateGLTexture2DArray( width, height, depth, target, format,
internalFormat, glType, type, &glTexture, &error, false, d );
break;
case GL_TEXTURE_3D:
CreateGLTexture3D( width, height, depth, target, format,
internalFormat, glType, type, &glTexture, &error, d, false );
break;
default:
log_error("Unsupported GL tex target (%s) passed to write test: "
"%s (%s):%d", GetGLTargetName(target), __FUNCTION__,
__FILE__, __LINE__);
}
// If there was a problem during creation, make sure it isn't a known
// cause, and then complain.
if ( error != 0 ) {
if ((format == GL_RGBA_INTEGER_EXT) && (!CheckGLIntegerExtensionSupport())){
log_info("OpenGL version does not support GL_RGBA_INTEGER_EXT. "
"Skipping test.\n");
return 0;
} else {
return error;
}
}
// Run and get the results
cl_image_format clFormat;
ExplicitType sourceType;
ExplicitType validationType;
void *outSourceBuffer;
GLenum globj = glTexture;
if (target == GL_RENDERBUFFER || target == GL_COLOR_ATTACHMENT0) {
globj = glRenderbuffer;
}
bool supports_half = false;
error = supportsHalf(context, &supports_half);
if( error != 0 )
return error;
error = test_image_write( context, queue, target, globj, width, height,
depth, &clFormat, &sourceType, (void **)&outSourceBuffer, d, supports_half );
if( error != 0 || ((sourceType == kHalf ) && !supports_half))
return error;
// If actual source type was half, convert to float for validation.
if ( sourceType == kHalf )
validationType = kFloat;
else
validationType = sourceType;
BufferOwningPtr<char> validationSource( convert_to_expected( outSourceBuffer,
width * height * depth, sourceType, validationType ) );
log_info( "- Write for %s [%4ld x %4ld x %4ld] : GL Texture : %s : %s : %s =>"
" CL Image : %s : %s \n",
GetGLTargetName(target),
width, height, depth,
GetGLFormatName( format ),
GetGLFormatName( internalFormat ),
GetGLTypeName( glType),
GetChannelOrderName( clFormat.image_channel_order ),
GetChannelTypeName( clFormat.image_channel_data_type ));
// Read the results from the GL texture.
ExplicitType readType = type;
BufferOwningPtr<char> glResults( ReadGLTexture(
target, glTexture, glBuf, width, format,
internalFormat, glType, readType, /* unused */ 1, 1 ) );
// We have to convert our input buffer to the returned type, so we can validate.
BufferOwningPtr<char> convertedGLResults( convert_to_expected(
glResults, width * height * depth, readType, validationType ) );
// Validate.
int valid = 0;
if (convertedGLResults) {
if( sourceType == kFloat || sourceType == kHalf )
valid = validate_float_results( validationSource, convertedGLResults,
width, height, depth );
else
valid = validate_integer_results( validationSource, convertedGLResults,
width, height, depth, get_explicit_type_size( readType ) );
}
return valid;
}
#pragma mark -
#pragma mark Write test common entry point
// This is the main loop for all of the write tests. It iterates over the
// given formats & targets, testing a variety of sizes against each
// combination.
int test_images_write_common(cl_device_id device, cl_context context,
cl_command_queue queue, struct format* formats, size_t nformats,
GLenum *targets, size_t ntargets, sizevec_t* sizes, size_t nsizes )
{
int error = 0;
RandomSeed seed(gRandomSeed);
// First, ensure this device supports images.
if (checkForImageSupport(device)) {
log_info("Device does not support images. Skipping test.\n");
return 0;
}
size_t fidx, tidx, sidx;
for ( fidx = 0; fidx < nformats; fidx++ ) {
for ( tidx = 0; tidx < ntargets; tidx++ ) {
log_info( "Testing image write test for %s : %s : %s : %s\n",
GetGLTargetName( targets[ tidx ] ),
GetGLFormatName( formats[ fidx ].internal ),
GetGLBaseFormatName( formats[ fidx ].formattype ),
GetGLTypeName( formats[ fidx ].datatype ) );
for (sidx = 0; sidx < nsizes; sidx++) {
if( test_image_format_write( context, queue,
sizes[sidx].width,
sizes[sidx].height,
sizes[sidx].depth,
targets[ tidx ],
formats[ fidx ].formattype,
formats[ fidx ].internal,
formats[ fidx ].datatype,
formats[ fidx ].type, seed ) )
{
log_error( "ERROR: Image write test failed for %s : %s : %s : %s "
" and size (%ld,%ld,%ld)\n\n",
GetGLTargetName( targets[ tidx ] ),
GetGLFormatName( formats[ fidx ].internal ),
GetGLBaseFormatName( formats[ fidx ].formattype ),
GetGLTypeName( formats[ fidx ].datatype ),
sizes[sidx].width,
sizes[sidx].height,
sizes[sidx].depth);
error++;
break; // Skip other sizes for this combination
}
}
// If we passed all sizes (check versus size loop count):
if (sidx == nsizes) {
log_info( "passed: Image write for GL format %s : %s : %s : %s\n\n",
GetGLTargetName( targets[ tidx ] ),
GetGLFormatName( formats[ fidx ].internal ),
GetGLBaseFormatName( formats[ fidx ].formattype ),
GetGLTypeName( formats[ fidx ].datatype ) );
}
}
}
return error;
}