| // |
| // 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 <OpenGL/glu.h> |
| #else |
| #include <GL/glu.h> |
| #include <CL/cl_gl.h> |
| #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); |
| |
| 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); |
| |
| |
| 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<char> 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<char> 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<char> 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) |
| { |
| 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); |
| } |
| |
| 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; |
| |
| error = test_attach_renderbuffer_write_to_image( |
| context, queue, attachment, glRenderbuffer, width, height, &clFormat, |
| &sourceType, d, (void **)&outSourceBuffer); |
| if (error != 0) 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, 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<char> 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<char> 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; |
| } |