// // 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" #if defined( __APPLE__ ) #include #else #include #include #endif #if defined (__linux__) GLboolean gluCheckExtension(const GLubyte *extension, const GLubyte *extensions) { const GLubyte *start; GLubyte *where, *terminator; /* Extension names should not have spaces. */ where = (GLubyte *) strchr((const char*)extension, ' '); if (where || *extension == '\0') return 0; /* It takes a bit of care to be fool-proof about parsing the OpenGL extensions string. Don't be fooled by sub-strings, etc. */ start = extensions; for (;;) { where = (GLubyte *) strstr((const char *) start, (const char*) extension); if (!where) break; terminator = where + strlen((const char*) extension); if (where == start || *(where - 1) == ' ') if (*terminator == ' ' || *terminator == '\0') return 1; start = terminator; } return 0; } #endif // This is defined in the write common code: extern 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 ); extern int test_cl_image_read( cl_context context, cl_command_queue queue, GLenum gl_target, cl_mem image, size_t width, size_t height, size_t depth, size_t sampleNum, cl_image_format *outFormat, ExplicitType *outType, void **outResultBuffer ); extern int supportsHalf(cl_context context, bool* supports_half); static int test_attach_renderbuffer_read_image( cl_context context, cl_command_queue queue, GLenum glTarget, GLuint glRenderbuffer, size_t imageWidth, size_t imageHeight, cl_image_format *outFormat, ExplicitType *outType, void **outResultBuffer ) { int error; // Create a CL image from the supplied GL renderbuffer cl_mem image = (*clCreateFromGLRenderbuffer_ptr)( context, CL_MEM_READ_ONLY, glRenderbuffer, &error ); if( error != CL_SUCCESS ) { print_error( error, "Unable to create CL image from GL renderbuffer" ); return error; } return test_cl_image_read( context, queue, glTarget, image, imageWidth, imageHeight, 1, 1, outFormat, outType, outResultBuffer ); } int test_renderbuffer_read_image( cl_context context, cl_command_queue queue, GLsizei width, GLsizei height, GLenum attachment, GLenum format, GLenum internalFormat, GLenum glType, ExplicitType type, MTdata d ) { int error; if( type == kHalf ) if( DetectFloatToHalfRoundingMode(queue) ) return 1; // Create the GL renderbuffer glFramebufferWrapper glFramebuffer; glRenderbufferWrapper glRenderbuffer; void *tmp = CreateGLRenderbuffer( width, height, attachment, format, internalFormat, glType, type, &glFramebuffer, &glRenderbuffer, &error, d, true ); BufferOwningPtr inputBuffer(tmp); 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 actualType; char *outBuffer; error = test_attach_renderbuffer_read_image( context, queue, attachment, glRenderbuffer, width, height, &clFormat, &actualType, (void **)&outBuffer ); if( error != 0 ) return error; BufferOwningPtr actualResults(outBuffer); log_info( "- Read [%4d x %4d] : GL renderbuffer : %s : %s : %s => CL Image : %s : %s \n", width, height, GetGLFormatName( format ), GetGLFormatName( internalFormat ), GetGLTypeName( glType), GetChannelOrderName( clFormat.image_channel_order ), GetChannelTypeName( clFormat.image_channel_data_type )); #ifdef DEBUG log_info("- start read GL data -- \n"); DumpGLBuffer(glType, width, height, actualResults); log_info("- end read GL data -- \n"); #endif // We have to convert our input buffer to the returned type, so we can validate. BufferOwningPtr convertedInput(convert_to_expected( inputBuffer, width * height, type, actualType, get_channel_order_channel_count(clFormat.image_channel_order) )); #ifdef DEBUG log_info("- start input data -- \n"); DumpGLBuffer(GetGLTypeForExplicitType(actualType), width, height, convertedInput); log_info("- end input data -- \n"); #endif #ifdef DEBUG log_info("- start converted data -- \n"); DumpGLBuffer(GetGLTypeForExplicitType(actualType), width, height, actualResults); log_info("- end converted data -- \n"); #endif // Now we validate int valid = 0; if(convertedInput) { if( actualType == kFloat ) valid = validate_float_results( convertedInput, actualResults, width, height, 1, get_channel_order_channel_count(clFormat.image_channel_order) ); else valid = validate_integer_results( convertedInput, actualResults, width, height, 1, get_explicit_type_size( actualType ) ); } return valid; } int test_renderbuffer_read( cl_device_id device, cl_context context, cl_command_queue queue, int numElements ) { GLenum attachments[] = { GL_COLOR_ATTACHMENT0_EXT }; struct { GLenum internal; GLenum format; GLenum datatype; ExplicitType type; } formats[] = { { GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, kUChar }, { GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, kUChar }, { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, kUChar }, { GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, kUShort }, // Renderbuffers with integer formats do not seem to work reliably across // platforms/implementations. Disabling this in version 1.0 of CL conformance tests. #ifdef TEST_INTEGER_FORMATS { GL_RGBA8I_EXT, GL_RGBA_INTEGER_EXT, GL_BYTE, kChar }, { GL_RGBA16I_EXT, GL_RGBA_INTEGER_EXT, GL_SHORT, kShort }, { GL_RGBA32I_EXT, GL_RGBA_INTEGER_EXT, GL_INT, kInt }, { GL_RGBA8UI_EXT, GL_RGBA_INTEGER_EXT, GL_UNSIGNED_BYTE, kUChar }, { GL_RGBA16UI_EXT, GL_RGBA_INTEGER_EXT, GL_UNSIGNED_SHORT, kUShort }, { GL_RGBA32UI_EXT, GL_RGBA_INTEGER_EXT, GL_UNSIGNED_INT, kUInt }, #endif { GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT, kFloat }, { GL_RGBA16F_ARB, GL_RGBA, GL_HALF_FLOAT, kHalf } }; size_t fmtIdx, attIdx; int error = 0; #ifdef DEBUG size_t iter = 1; #else size_t iter = 6; #endif RandomSeed seed( gRandomSeed ); // Check if images are supported if (checkForImageSupport(device)) { log_info("Device does not support images. Skipping test.\n"); return 0; } if( !gluCheckExtension( (const GLubyte *)"GL_EXT_framebuffer_object", glGetString( GL_EXTENSIONS ) ) ) { log_info( "Renderbuffers are not supported by this OpenGL implementation; skipping test\n" ); return 0; } // Loop through a set of GL formats, testing a set of sizes against each one for( fmtIdx = 0; fmtIdx < sizeof( formats ) / sizeof( formats[ 0 ] ); fmtIdx++ ) { for( attIdx = 0; attIdx < sizeof( attachments ) / sizeof( attachments[ 0 ] ); attIdx++ ) { size_t i; log_info( "Testing renderbuffer read for %s : %s : %s : %s\n", GetGLAttachmentName( attachments[ attIdx ] ), GetGLFormatName( formats[ fmtIdx ].internal ), GetGLBaseFormatName( formats[ fmtIdx ].format ), GetGLTypeName( formats[ fmtIdx ].datatype ) ); for( i = 0; i < iter; i++ ) { GLsizei width = random_in_range( 16, 512, seed ); GLsizei height = random_in_range( 16, 512, seed ); #ifdef DEBUG width = height = 4; #endif if( test_renderbuffer_read_image( context, queue, width, height, attachments[ attIdx ], formats[ fmtIdx ].format, formats[ fmtIdx ].internal, formats[ fmtIdx ].datatype, formats[ fmtIdx ].type, seed ) ) { log_error( "ERROR: Renderbuffer read test failed for %s : %s : %s : %s\n\n", GetGLAttachmentName( attachments[ attIdx ] ), GetGLFormatName( formats[ fmtIdx ].internal ), GetGLBaseFormatName( formats[ fmtIdx ].format ), GetGLTypeName( formats[ fmtIdx ].datatype ) ); error++; break; // Skip other sizes for this combination } } if( i == iter ) { log_info( "passed: Renderbuffer read test passed for %s : %s : %s : %s\n\n", GetGLAttachmentName( attachments[ attIdx ] ), GetGLFormatName( formats[ fmtIdx ].internal ), GetGLBaseFormatName( formats[ fmtIdx ].format ), GetGLTypeName( formats[ fmtIdx ].datatype ) ); } } } return error; } #pragma mark -------------------- Write tests ------------------------- int test_attach_renderbuffer_write_to_image( cl_context context, cl_command_queue queue, GLenum glTarget, GLuint glRenderbuffer, size_t imageWidth, size_t imageHeight, cl_image_format *outFormat, ExplicitType *outType, MTdata d, void **outSourceBuffer, bool supports_half ) { int error; // Create a CL image from the supplied GL renderbuffer clMemWrapper image = (*clCreateFromGLRenderbuffer_ptr)( context, CL_MEM_WRITE_ONLY, glRenderbuffer, &error ); if( error != CL_SUCCESS ) { print_error( error, "Unable to create CL image from GL renderbuffer" ); return error; } return test_cl_image_write( context, queue, glTarget, image, imageWidth, imageHeight, 1, outFormat, outType, outSourceBuffer, d, supports_half ); } int test_renderbuffer_image_write( cl_context context, cl_command_queue queue, GLsizei width, GLsizei height, GLenum attachment, GLenum format, GLenum internalFormat, GLenum glType, ExplicitType type, MTdata d ) { int error; if( type == kHalf ) if( DetectFloatToHalfRoundingMode(queue) ) return 1; // Create the GL renderbuffer glFramebufferWrapper glFramebuffer; glRenderbufferWrapper glRenderbuffer; CreateGLRenderbuffer( width, height, attachment, format, internalFormat, glType, type, &glFramebuffer, &glRenderbuffer, &error, d, false ); 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; bool supports_half = false; error = supportsHalf(context, &supports_half); if( error != 0 ) return error; error = test_attach_renderbuffer_write_to_image( context, queue, attachment, glRenderbuffer, width, height, &clFormat, &sourceType, d, (void **)&outSourceBuffer, 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 validationSource( convert_to_expected( outSourceBuffer, width * height, sourceType, validationType, get_channel_order_channel_count(clFormat.image_channel_order) ) ); log_info( "- Write [%4d x %4d] : GL Renderbuffer : %s : %s : %s => CL Image : %s : %s \n", width, height, GetGLFormatName( format ), GetGLFormatName( internalFormat ), GetGLTypeName( glType), GetChannelOrderName( clFormat.image_channel_order ), GetChannelTypeName( clFormat.image_channel_data_type )); // Now read the results from the GL renderbuffer BufferOwningPtr resultData( ReadGLRenderbuffer( glFramebuffer, glRenderbuffer, attachment, format, internalFormat, glType, type, width, height ) ); #ifdef DEBUG log_info("- start result data -- \n"); DumpGLBuffer(glType, width, height, resultData); log_info("- end result data -- \n"); #endif // We have to convert our input buffer to the returned type, so we can validate. BufferOwningPtr convertedData( convert_to_expected( resultData, width * height, type, validationType, get_channel_order_channel_count(clFormat.image_channel_order) ) ); #ifdef DEBUG log_info("- start input data -- \n"); DumpGLBuffer(GetGLTypeForExplicitType(validationType), width, height, validationSource); log_info("- end input data -- \n"); #endif #ifdef DEBUG log_info("- start converted data -- \n"); DumpGLBuffer(GetGLTypeForExplicitType(validationType), width, height, convertedData); log_info("- end converted data -- \n"); #endif // Now we validate int valid = 0; if(convertedData) { if( sourceType == kFloat || sourceType == kHalf ) valid = validate_float_results( validationSource, convertedData, width, height, 1, get_channel_order_channel_count(clFormat.image_channel_order) ); else valid = validate_integer_results( validationSource, convertedData, width, height, 1, get_explicit_type_size( type ) ); } return valid; } int test_renderbuffer_write( cl_device_id device, cl_context context, cl_command_queue queue, int numElements ) { GLenum attachments[] = { GL_COLOR_ATTACHMENT0_EXT }; struct { GLenum internal; GLenum format; GLenum datatype; ExplicitType type; } formats[] = { { GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, kUChar }, { GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, kUChar }, { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, kUChar }, { GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, kUShort }, // Renderbuffers with integer formats do not seem to work reliably across // platforms/implementations. Disabling this in version 1.0 of CL conformance tests. #ifdef TEST_INTEGER_FORMATS { GL_RGBA8I_EXT, GL_RGBA_INTEGER_EXT, GL_BYTE, kChar }, { GL_RGBA16I_EXT, GL_RGBA_INTEGER_EXT, GL_SHORT, kShort }, { GL_RGBA32I_EXT, GL_RGBA_INTEGER_EXT, GL_INT, kInt }, { GL_RGBA8UI_EXT, GL_RGBA_INTEGER_EXT, GL_UNSIGNED_BYTE, kUChar }, { GL_RGBA16UI_EXT, GL_RGBA_INTEGER_EXT, GL_UNSIGNED_SHORT, kUShort }, { GL_RGBA32UI_EXT, GL_RGBA_INTEGER_EXT, GL_UNSIGNED_INT, kUInt }, #endif { GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT, kFloat }, { GL_RGBA16F_ARB, GL_RGBA, GL_HALF_FLOAT, kHalf } }; size_t fmtIdx, attIdx; int error = 0; size_t iter = 6; #ifdef DEBUG iter = 1; #endif RandomSeed seed( gRandomSeed ); // Check if images are supported if (checkForImageSupport(device)) { log_info("Device does not support images. Skipping test.\n"); return 0; } if( !gluCheckExtension( (const GLubyte *)"GL_EXT_framebuffer_object", glGetString( GL_EXTENSIONS ) ) ) { log_info( "Renderbuffers are not supported by this OpenGL implementation; skipping test\n" ); return 0; } // Loop through a set of GL formats, testing a set of sizes against each one for( fmtIdx = 0; fmtIdx < sizeof( formats ) / sizeof( formats[ 0 ] ); fmtIdx++ ) { for( attIdx = 0; attIdx < sizeof( attachments ) / sizeof( attachments[ 0 ] ); attIdx++ ) { log_info( "Testing Renderbuffer write test for %s : %s : %s : %s\n", GetGLAttachmentName( attachments[ attIdx ] ), GetGLFormatName( formats[ fmtIdx ].internal ), GetGLBaseFormatName( formats[ fmtIdx ].format ), GetGLTypeName( formats[ fmtIdx ].datatype ) ); size_t i; for( i = 0; i < iter; i++ ) { GLsizei width = random_in_range( 16, 512, seed ); GLsizei height = random_in_range( 16, 512, seed ); #ifdef DEBUG width = height = 4; #endif if( test_renderbuffer_image_write( context, queue, width, height, attachments[ attIdx ], formats[ fmtIdx ].format, formats[ fmtIdx ].internal, formats[ fmtIdx ].datatype, formats[ fmtIdx ].type, seed ) ) { log_error( "ERROR: Renderbuffer write test failed for %s : %s : %s : %s\n\n", GetGLAttachmentName( attachments[ attIdx ] ), GetGLFormatName( formats[ fmtIdx ].internal ), GetGLBaseFormatName( formats[ fmtIdx ].format ), GetGLTypeName( formats[ fmtIdx ].datatype ) ); error++; break; // Skip other sizes for this combination } } if( i == iter ) { log_info( "passed: Renderbuffer write test passed for %s : %s : %s : %s\n\n", GetGLAttachmentName( attachments[ attIdx ] ), GetGLFormatName( formats[ fmtIdx ].internal ), GetGLBaseFormatName( formats[ fmtIdx ].format ), GetGLTypeName( formats[ fmtIdx ].datatype ) ); } } } return error; }