482 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			482 lines
		
	
	
		
			17 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 "gl_headers.h"
 | |
| 
 | |
| const char *get_kernel_suffix( cl_image_format *format )
 | |
| {
 | |
|     switch( format->image_channel_data_type )
 | |
|     {
 | |
|         case CL_UNORM_INT8:
 | |
|         case CL_UNORM_INT16:
 | |
|         case CL_SNORM_INT8:
 | |
|         case CL_SNORM_INT16:
 | |
|         case CL_FLOAT:
 | |
|             return "f";
 | |
|         case CL_HALF_FLOAT:
 | |
|             return "h";
 | |
|         case CL_SIGNED_INT8:
 | |
|         case CL_SIGNED_INT16:
 | |
|         case CL_SIGNED_INT32:
 | |
|             return "i";
 | |
|         case CL_UNSIGNED_INT8:
 | |
|         case CL_UNSIGNED_INT16:
 | |
|         case CL_UNSIGNED_INT32:
 | |
|             return "ui";
 | |
|         default:
 | |
|             return "";
 | |
|     }
 | |
| }
 | |
| 
 | |
| ExplicitType get_read_kernel_type( cl_image_format *format )
 | |
| {
 | |
|     switch( format->image_channel_data_type )
 | |
|     {
 | |
|         case CL_UNORM_INT8:
 | |
|         case CL_UNORM_INT16:
 | |
|         case CL_SNORM_INT8:
 | |
|         case CL_SNORM_INT16:
 | |
|         case CL_FLOAT:
 | |
|             return kFloat;
 | |
|         case CL_HALF_FLOAT:
 | |
|             return kHalf;
 | |
|         case CL_SIGNED_INT8:
 | |
|         case CL_SIGNED_INT16:
 | |
|         case CL_SIGNED_INT32:
 | |
|             return kInt;
 | |
|         case CL_UNSIGNED_INT8:
 | |
|         case CL_UNSIGNED_INT16:
 | |
|         case CL_UNSIGNED_INT32:
 | |
|             return kUInt;
 | |
|         default:
 | |
|             return kInt;
 | |
|     }
 | |
| }
 | |
| 
 | |
| ExplicitType get_write_kernel_type( cl_image_format *format )
 | |
| {
 | |
|     switch( format->image_channel_data_type )
 | |
|     {
 | |
|         case CL_UNORM_INT8:
 | |
|             return kFloat;
 | |
|         case CL_UNORM_INT16:
 | |
|             return kFloat;
 | |
|         case CL_SNORM_INT8:
 | |
|             return kFloat;
 | |
|         case CL_SNORM_INT16:
 | |
|             return kFloat;
 | |
|         case CL_HALF_FLOAT:
 | |
|             return kHalf;
 | |
|         case CL_FLOAT:
 | |
|             return kFloat;
 | |
|         case CL_SIGNED_INT8:
 | |
|             return kChar;
 | |
|         case CL_SIGNED_INT16:
 | |
|             return kShort;
 | |
|         case CL_SIGNED_INT32:
 | |
|             return kInt;
 | |
|         case CL_UNSIGNED_INT8:
 | |
|             return kUChar;
 | |
|         case CL_UNSIGNED_INT16:
 | |
|             return kUShort;
 | |
|         case CL_UNSIGNED_INT32:
 | |
|             return kUInt;
 | |
|         default:
 | |
|             return kInt;
 | |
|     }
 | |
| }
 | |
| 
 | |
| const char* get_write_conversion( cl_image_format *format, ExplicitType type )
 | |
| {
 | |
|     switch( format->image_channel_data_type )
 | |
|     {
 | |
|         case CL_UNORM_INT8:
 | |
|         case CL_UNORM_INT16:
 | |
|         case CL_SNORM_INT8:
 | |
|         case CL_SNORM_INT16:
 | |
|         case CL_FLOAT:
 | |
|             if(type != kFloat) return "convert_float4";
 | |
|             break;
 | |
|         case CL_HALF_FLOAT:
 | |
|             break;
 | |
|         case CL_SIGNED_INT8:
 | |
|         case CL_SIGNED_INT16:
 | |
|         case CL_SIGNED_INT32:
 | |
|             if(type != kInt) return "convert_int4";
 | |
|             break;
 | |
|         case CL_UNSIGNED_INT8:
 | |
|         case CL_UNSIGNED_INT16:
 | |
|         case CL_UNSIGNED_INT32:
 | |
|             if(type != kUInt) return "convert_uint4";
 | |
|             break;
 | |
|         default:
 | |
|             return "";
 | |
|     }
 | |
|     return "";
 | |
| }
 | |
| 
 | |
| // The only three input types to this function are kInt, kUInt and kFloat, due to the way we set up our tests
 | |
| // The output types, though, are pretty much anything valid for GL to receive
 | |
| 
 | |
| #define DOWNSCALE_INTEGER_CASE( enum, type, bitShift )    \
 | |
|     case enum:    \
 | |
|     {        \
 | |
|         cl_##type *dst = new cl_##type[ numPixels * 4 ]; \
 | |
|         for( size_t i = 0; i < numPixels * 4; i++ ) \
 | |
|             dst[ i ] = src[ i ];    \
 | |
|         return (char *)dst;        \
 | |
|     }
 | |
| 
 | |
| #define UPSCALE_FLOAT_CASE( enum, type, typeMax )    \
 | |
|     case enum:    \
 | |
|     {        \
 | |
|         cl_##type *dst = new cl_##type[ numPixels * 4 ]; \
 | |
|         for( size_t i = 0; i < numPixels * 4; i++ ) \
 | |
|             dst[ i ] = (cl_##type)( src[ i ] * typeMax );    \
 | |
|         return (char *)dst;        \
 | |
|     }
 | |
| 
 | |
| char * convert_to_expected( void * inputBuffer, size_t numPixels, ExplicitType inType, ExplicitType outType )
 | |
| {
 | |
| #ifdef GLES_DEBUG
 | |
|     log_info( "- Converting from input type '%s' to output type '%s'\n",
 | |
|              get_explicit_type_name( inType ), get_explicit_type_name( outType ) );
 | |
| #endif
 | |
| 
 | |
|     if( inType == outType )
 | |
|     {
 | |
|         char *outData = new char[ numPixels * 4 * get_explicit_type_size(outType) ] ; // sizeof( cl_int ) ];
 | |
|         memcpy( outData, inputBuffer, numPixels * 4 * get_explicit_type_size(inType)  );
 | |
|         return outData;
 | |
|     }
 | |
|     else if( inType == kChar )
 | |
|     {
 | |
|         cl_char *src = (cl_char *)inputBuffer;
 | |
| 
 | |
|         switch( outType )
 | |
|         {
 | |
|             case kInt:
 | |
|             {
 | |
|                 cl_int *outData = new cl_int[ numPixels * 4 ];
 | |
|                 for( size_t i = 0; i < numPixels * 4; i++ )
 | |
|                 {
 | |
|                     outData[ i ] = (cl_int)((src[ i ]));
 | |
|                 }
 | |
|                 return (char *)outData;
 | |
|             }
 | |
|             case kFloat:
 | |
|             {
 | |
|                 // If we're converting to float, then CL decided that we should be normalized
 | |
|                 cl_float *outData = new cl_float[ numPixels * 4 ];
 | |
|                 for( size_t i = 0; i < numPixels * 4; i++ )
 | |
|                 {
 | |
|                     outData[ i ] = (cl_float)src[ i ] / 127.0f;
 | |
|                 }
 | |
|                 return (char *)outData;
 | |
|             }
 | |
|             default:
 | |
|                 log_error( "ERROR: Unsupported conversion from %s to %s!\n", get_explicit_type_name( inType ), get_explicit_type_name( outType ) );
 | |
|                 return NULL;
 | |
|         }
 | |
|     }
 | |
|     else if( inType == kUChar )
 | |
|     {
 | |
|         cl_uchar *src = (cl_uchar *)inputBuffer;
 | |
| 
 | |
|         switch( outType )
 | |
|         {
 | |
|             case kUInt:
 | |
|             {
 | |
|                 cl_uint *outData = new cl_uint[ numPixels * 4 ];
 | |
|                 for( size_t i = 0; i < numPixels * 4; i++ )
 | |
|                 {
 | |
|                     outData[ i ] = (cl_uint)((src[ i ]));
 | |
|                 }
 | |
|                 return (char *)outData;
 | |
|             }
 | |
|             case kFloat:
 | |
|             {
 | |
|                 // If we're converting to float, then CL decided that we should be normalized
 | |
|                 cl_float *outData = new cl_float[ numPixels * 4 ];
 | |
|                 for( size_t i = 0; i < numPixels * 4; i++ )
 | |
|                 {
 | |
|                     outData[ i ] = (cl_float)(src[ i ]) / 256.0f;
 | |
|                 }
 | |
|                 return (char *)outData;
 | |
|             }
 | |
|             default:
 | |
|                 log_error( "ERROR: Unsupported conversion from %s to %s!\n", get_explicit_type_name( inType ), get_explicit_type_name( outType ) );
 | |
|                 return NULL;
 | |
|         }
 | |
|     }
 | |
|     else if( inType == kShort )
 | |
|     {
 | |
|         cl_short *src = (cl_short *)inputBuffer;
 | |
| 
 | |
|         switch( outType )
 | |
|         {
 | |
|             case kInt:
 | |
|             {
 | |
|                 cl_int *outData = new cl_int[ numPixels * 4 ];
 | |
|                 for( size_t i = 0; i < numPixels * 4; i++ )
 | |
|                 {
 | |
|                     outData[ i ] = (cl_int)((src[ i ]));
 | |
|                 }
 | |
|                 return (char *)outData;
 | |
|             }
 | |
|             case kFloat:
 | |
|             {
 | |
|                 // If we're converting to float, then CL decided that we should be normalized
 | |
|                 cl_float *outData = new cl_float[ numPixels * 4 ];
 | |
|                 for( size_t i = 0; i < numPixels * 4; i++ )
 | |
|                 {
 | |
|                     outData[ i ] = (cl_float)src[ i ] / 32768.0f;
 | |
|                 }
 | |
|                 return (char *)outData;
 | |
|             }
 | |
|             default:
 | |
|                 log_error( "ERROR: Unsupported conversion from %s to %s!\n", get_explicit_type_name( inType ), get_explicit_type_name( outType ) );
 | |
|                 return NULL;
 | |
|         }
 | |
|     }
 | |
|     else if( inType == kUShort )
 | |
|     {
 | |
|         cl_ushort *src = (cl_ushort *)inputBuffer;
 | |
| 
 | |
|         switch( outType )
 | |
|         {
 | |
|             case kUInt:
 | |
|             {
 | |
|                 cl_uint *outData = new cl_uint[ numPixels * 4 ];
 | |
|                 for( size_t i = 0; i < numPixels * 4; i++ )
 | |
|                 {
 | |
|                     outData[ i ] = (cl_uint)((src[ i ]));
 | |
|                 }
 | |
|                 return (char *)outData;
 | |
|             }
 | |
|             case kFloat:
 | |
|             {
 | |
|                 // If we're converting to float, then CL decided that we should be normalized
 | |
|                 cl_float *outData = new cl_float[ numPixels * 4 ];
 | |
|                 for( size_t i = 0; i < numPixels * 4; i++ )
 | |
|                 {
 | |
|                     outData[ i ] = (cl_float)(src[ i ]) / 65535.0f;
 | |
|                 }
 | |
|                 return (char *)outData;
 | |
|             }
 | |
|             default:
 | |
|                 log_error( "ERROR: Unsupported conversion from %s to %s!\n", get_explicit_type_name( inType ), get_explicit_type_name( outType ) );
 | |
|                 return NULL;
 | |
|         }
 | |
|     }
 | |
|     else if( inType == kInt )
 | |
|     {
 | |
|         cl_int *src = (cl_int *)inputBuffer;
 | |
| 
 | |
|         switch( outType )
 | |
|         {
 | |
|                 DOWNSCALE_INTEGER_CASE( kShort, short, 16 )
 | |
|                 DOWNSCALE_INTEGER_CASE( kChar, char, 24 )
 | |
|             case kFloat:
 | |
|             {
 | |
|                 // If we're converting to float, then CL decided that we should be normalized
 | |
|                 cl_float *outData = new cl_float[ numPixels * 4 ];
 | |
|                 for( size_t i = 0; i < numPixels * 4; i++ )
 | |
|                 {
 | |
|                     outData[ i ] = (cl_float)fmaxf( (float)src[ i ] / 2147483647.f, -1.f );
 | |
|                 }
 | |
|                 return (char *)outData;
 | |
|             }
 | |
|             default:
 | |
|                 log_error( "ERROR: Unsupported conversion from %s to %s!\n", get_explicit_type_name( inType ), get_explicit_type_name( outType ) );
 | |
|                 return NULL;
 | |
|         }
 | |
|     }
 | |
|     else if( inType == kUInt )
 | |
|     {
 | |
|         cl_uint *src = (cl_uint *)inputBuffer;
 | |
| 
 | |
|         switch( outType )
 | |
|         {
 | |
|                 DOWNSCALE_INTEGER_CASE( kUShort, ushort, 16 )
 | |
|                 DOWNSCALE_INTEGER_CASE( kUChar, uchar, 24 )
 | |
|             case kFloat:
 | |
|             {
 | |
|                 // If we're converting to float, then CL decided that we should be normalized
 | |
|                 cl_float *outData = new cl_float[ numPixels * 4 ];
 | |
|                 for( size_t i = 0; i < numPixels * 4; i++ )
 | |
|                 {
 | |
|                     outData[ i ] = (cl_float)src[ i ] / 4294967295.f;
 | |
|                 }
 | |
|                 return (char *)outData;
 | |
|             }
 | |
|             default:
 | |
|                 log_error( "ERROR: Unsupported conversion from %s to %s!\n", get_explicit_type_name( inType ), get_explicit_type_name( outType ) );
 | |
|                 return NULL;
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         cl_float *src = (cl_float *)inputBuffer;
 | |
| 
 | |
|         switch( outType )
 | |
|         {
 | |
|                 UPSCALE_FLOAT_CASE( kChar, char, 127.f )
 | |
|                 UPSCALE_FLOAT_CASE( kUChar, uchar, 255.f )
 | |
|                 UPSCALE_FLOAT_CASE( kShort, short, 32767.f )
 | |
|                 UPSCALE_FLOAT_CASE( kUShort, ushort, 65535.f )
 | |
|                 UPSCALE_FLOAT_CASE( kInt, int, 2147483647.f )
 | |
|                 UPSCALE_FLOAT_CASE( kUInt, uint, 4294967295.f )
 | |
|             default:
 | |
|                 log_error( "ERROR: Unsupported conversion from %s to %s!\n", get_explicit_type_name( inType ), get_explicit_type_name( outType ) );
 | |
|                 return NULL;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| int validate_integer_results( void *expectedResults, void *actualResults, size_t width, size_t height, size_t typeSize )
 | |
| {
 | |
|     return validate_integer_results( expectedResults, actualResults, width, height, 0, typeSize );
 | |
| }
 | |
| 
 | |
| int validate_integer_results( void *expectedResults, void *actualResults, size_t width, size_t height, size_t depth, size_t typeSize )
 | |
| {
 | |
|     char *expected = (char *)expectedResults;
 | |
|     char *actual = (char *)actualResults;
 | |
|     for( size_t z = 0; z < ( ( depth == 0 ) ? 1 : depth ); z++ )
 | |
|     {
 | |
|         for( size_t y = 0; y < height; y++ )
 | |
|         {
 | |
|             for( size_t x = 0; x < width; x++ )
 | |
|             {
 | |
|                 if( memcmp( expected, actual, typeSize * 4 ) != 0 )
 | |
|                 {
 | |
|                     char scratch[ 1024 ];
 | |
| 
 | |
|                     if( depth == 0 )
 | |
|                         log_error( "ERROR: Data sample %d,%d did not validate!\n", (int)x, (int)y );
 | |
|                     else
 | |
|                         log_error( "ERROR: Data sample %d,%d,%d did not validate!\n", (int)x, (int)y, (int)z );
 | |
|                     log_error( "\tExpected: %s\n", GetDataVectorString( expected, typeSize, 4, scratch ) );
 | |
|                     log_error( "\t  Actual: %s\n", GetDataVectorString( actual, typeSize, 4, scratch ) );
 | |
|                     return -1;
 | |
|                 }
 | |
|                 expected += typeSize * 4;
 | |
|                 actual += typeSize * 4;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int validate_float_results( void *expectedResults, void *actualResults, size_t width, size_t height )
 | |
| {
 | |
|     return validate_float_results( expectedResults, actualResults, width, height, 0 );
 | |
| }
 | |
| 
 | |
| int validate_float_results( void *expectedResults, void *actualResults, size_t width, size_t height, size_t depth )
 | |
| {
 | |
|     cl_float *expected = (cl_float *)expectedResults;
 | |
|     cl_float *actual = (cl_float *)actualResults;
 | |
|     for( size_t z = 0; z < ( ( depth == 0 ) ? 1 : depth ); z++ )
 | |
|     {
 | |
|         for( size_t y = 0; y < height; y++ )
 | |
|         {
 | |
|             for( size_t x = 0; x < width; x++ )
 | |
|             {
 | |
|                 float err = 0.f;
 | |
|                 for( size_t i = 0; i < 4; i++ )
 | |
|                 {
 | |
|                     float error = fabsf( expected[ i ] - actual[ i ] );
 | |
|                     if( error > err )
 | |
|                         err = error;
 | |
|                 }
 | |
| 
 | |
|                 if( err > 1.f / 127.f ) // Max expected range of error if we converted from an 8-bit integer to a normalized float
 | |
|                 {
 | |
|                     if( depth == 0 )
 | |
|                         log_error( "ERROR: Data sample %d,%d did not validate!\n", (int)x, (int)y );
 | |
|                     else
 | |
|                         log_error( "ERROR: Data sample %d,%d,%d did not validate!\n", (int)x, (int)y, (int)z );
 | |
|                     log_error( "\tExpected: %f %f %f %f\n", expected[ 0 ], expected[ 1 ], expected[ 2 ], expected[ 3 ] );
 | |
|                     log_error( "\t        : %a %a %a %a\n", expected[ 0 ], expected[ 1 ], expected[ 2 ], expected[ 3 ] );
 | |
|                     log_error( "\t  Actual: %f %f %f %f\n", actual[ 0 ], actual[ 1 ], actual[ 2 ], actual[ 3 ] );
 | |
|                     log_error( "\t        : %a %a %a %a\n", actual[ 0 ], actual[ 1 ], actual[ 2 ], actual[ 3 ] );
 | |
|                     return -1;
 | |
|                 }
 | |
|                 expected += 4;
 | |
|                 actual += 4;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int CheckGLObjectInfo(cl_mem mem, cl_gl_object_type expected_cl_gl_type, GLuint expected_gl_name,
 | |
|                   GLenum expected_cl_gl_texture_target, GLint expected_cl_gl_mipmap_level)
 | |
| {
 | |
|   cl_gl_object_type object_type;
 | |
|   GLuint object_name;
 | |
|   GLenum texture_target;
 | |
|   GLint mipmap_level;
 | |
|     int error;
 | |
| 
 | |
|   error = (*clGetGLObjectInfo_ptr)(mem, &object_type, &object_name);
 | |
|   test_error( error, "clGetGLObjectInfo failed");
 | |
|   if (object_type != expected_cl_gl_type) {
 | |
|     log_error("clGetGLObjectInfo did not return expected object type: expected %d, got %d.\n", expected_cl_gl_type, object_type);
 | |
|     return -1;
 | |
|   }
 | |
|   if (object_name != expected_gl_name) {
 | |
|     log_error("clGetGLObjectInfo did not return expected object name: expected %d, got %d.\n", expected_gl_name, object_name);
 | |
|     return -1;
 | |
|   }
 | |
| 
 | |
|   if (object_type == CL_GL_OBJECT_TEXTURE2D || object_type == CL_GL_OBJECT_TEXTURE3D) {
 | |
|        error = (*clGetGLTextureInfo_ptr)(mem, CL_GL_TEXTURE_TARGET, sizeof(texture_target), &texture_target, NULL);
 | |
|     test_error( error, "clGetGLTextureInfo for CL_GL_TEXTURE_TARGET failed");
 | |
| 
 | |
|     if (texture_target != expected_cl_gl_texture_target) {
 | |
|       log_error("clGetGLTextureInfo did not return expected texture target: expected %d, got %d.\n", expected_cl_gl_texture_target, texture_target);
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|        error = (*clGetGLTextureInfo_ptr)(mem, CL_GL_MIPMAP_LEVEL, sizeof(mipmap_level), &mipmap_level, NULL);
 | |
|     test_error( error, "clGetGLTextureInfo for CL_GL_MIPMAP_LEVEL failed");
 | |
| 
 | |
|     if (mipmap_level != expected_cl_gl_mipmap_level) {
 | |
|       log_error("clGetGLTextureInfo did not return expected mipmap level: expected %d, got %d.\n", expected_cl_gl_mipmap_level, mipmap_level);
 | |
|       return -1;
 | |
|     }
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| bool CheckGLIntegerExtensionSupport()
 | |
| {
 | |
|     // Get the OpenGL version and supported extensions
 | |
|     const GLubyte *glVersion = glGetString(GL_VERSION);
 | |
|     const GLubyte *glExtensionList = glGetString(GL_EXTENSIONS);
 | |
| 
 | |
|     // Check if the OpenGL vrsion is 3.0 or grater or GL_EXT_texture_integer is supported
 | |
|     return (((glVersion[0] - '0') >= 3) || (strstr((const char*)glExtensionList, "GL_EXT_texture_integer")));
 | |
| }
 |