// // 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 #endif 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_UNORM_INT24: case CL_SNORM_INT8: case CL_SNORM_INT16: case CL_HALF_FLOAT: case CL_FLOAT: case CL_UNORM_INT_101010: return "f"; 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: log_error("Test error: unsupported kernel suffix for " "image_channel_data_type 0x%X\n", format->image_channel_data_type); 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_UNORM_INT24: case CL_SNORM_INT8: case CL_SNORM_INT16: case CL_HALF_FLOAT: case CL_FLOAT: case CL_UNORM_INT_101010: #ifdef GL_VERSION_3_2 case CL_DEPTH: #endif return kFloat; 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: log_error("Test error: unsupported kernel suffix for " "image_channel_data_type 0x%X\n", format->image_channel_data_type); return kNumExplicitTypes; } } 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_UNORM_INT24: 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; case CL_UNORM_INT_101010: return kFloat; #ifdef GL_VERSION_3_2 case CL_DEPTH: return kFloat; #endif 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_HALF_FLOAT: case CL_FLOAT: case CL_UNORM_INT_101010: case CL_UNORM_INT24: if (type != kFloat) return "convert_float4"; 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, size_t channelNum, GLenum glDataType) { #ifdef 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 * channelNum * get_explicit_type_size(outType)]; // sizeof( cl_int ) ]; if (glDataType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV) { for (size_t i = 0; i < numPixels; ++i) { ((cl_float *)outData)[i] = ((cl_float *)inputBuffer)[2 * i]; } } else { memcpy(outData, inputBuffer, numPixels * channelNum * 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 * channelNum]; for (size_t i = 0; i < numPixels * channelNum; 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 * channelNum]; for (size_t i = 0; i < numPixels * channelNum; 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 * channelNum]; for (size_t i = 0; i < numPixels * channelNum; 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 * channelNum]; for (size_t i = 0; i < numPixels * channelNum; 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 * channelNum]; for (size_t i = 0; i < numPixels * channelNum; 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 * channelNum]; for (size_t i = 0; i < numPixels * channelNum; 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 * channelNum]; for (size_t i = 0; i < numPixels * channelNum; 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 * channelNum]; for (size_t i = 0; i < numPixels * channelNum; 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 * channelNum]; for (size_t i = 0; i < numPixels * channelNum; 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 * channelNum]; const cl_float MaxValue = (glDataType == GL_UNSIGNED_INT_24_8) ? 16777215.f : 4294967295.f; const cl_uint ShiftBits = (glDataType == GL_UNSIGNED_INT_24_8) ? 8 : 0; for (size_t i = 0; i < numPixels * channelNum; i++) { outData[i] = (cl_float)(src[i] >> ShiftBits) / MaxValue; } 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 == kHalf) { cl_half *src = (cl_half *)inputBuffer; switch (outType) { case kFloat: { cl_float *outData = new cl_float[numPixels * channelNum]; for (size_t i = 0; i < numPixels * channelNum; i++) { outData[i] = cl_half_to_float(src[i]); } 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 sampleNum, size_t typeSize) { return validate_integer_results(expectedResults, actualResults, width, height, sampleNum, 0, typeSize); } int validate_integer_results(void *expectedResults, void *actualResults, size_t width, size_t height, size_t depth, size_t sampleNum, size_t typeSize) { char *expected = (char *)expectedResults; char *actual = (char *)actualResults; for (size_t s = 0; s < sampleNum; s++) { 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,%d did not " "validate!\n", (int)x, (int)y, (int)s); else log_error("ERROR: Data sample %d,%d,%d,%d did not " "validate!\n", (int)x, (int)y, (int)z, (int)s); 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, size_t sampleNum, size_t channelNum) { return validate_float_results(expectedResults, actualResults, width, height, sampleNum, 0, channelNum); } int validate_float_results(void *expectedResults, void *actualResults, size_t width, size_t height, size_t depth, size_t sampleNum, size_t channelNum) { cl_float *expected = (cl_float *)expectedResults; cl_float *actual = (cl_float *)actualResults; for (size_t s = 0; s < sampleNum; s++) { 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 < channelNum; 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,%d did not " "validate!\n", (int)x, (int)y, (int)s); else log_error("ERROR: Data sample %d,%d,%d,%d did not " "validate!\n", (int)x, (int)y, (int)z, (int)s); if (channelNum == 4) { 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]); } else if (channelNum == 1) { log_error("\tExpected: %f\n", expected[0]); log_error("\t : %a\n", expected[0]); log_error("\t Actual: %f\n", actual[0]); log_error("\t : %a\n", actual[0]); } return -1; } expected += channelNum; actual += channelNum; } } } } return 0; } int validate_float_results_rgb_101010(void *expectedResults, void *actualResults, size_t width, size_t height, size_t sampleNum) { return validate_float_results_rgb_101010(expectedResults, actualResults, width, height, sampleNum, 0); } int validate_float_results_rgb_101010(void *expectedResults, void *actualResults, size_t width, size_t height, size_t depth, size_t sampleNum) { cl_float *expected = (cl_float *)expectedResults; cl_float *actual = (cl_float *)actualResults; for (size_t s = 0; s < sampleNum; s++) { 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 < 3; i++) // skip the fourth channel { 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,%d did not " "validate!\n", (int)x, (int)y, (int)s); else log_error("ERROR: Data sample %d,%d,%d,%d did not " "validate!\n", (int)x, (int)y, (int)z, (int)s); log_error("\tExpected: %f %f %f\n", expected[0], expected[1], expected[2]); log_error("\t : %a %a %a\n", expected[0], expected[1], expected[2]); log_error("\t Actual: %f %f %f\n", actual[0], actual[1], actual[2]); log_error("\t : %a %a %a\n", actual[0], actual[1], actual[2]); 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 we're dealing with a buffer or render buffer, we are done. if (object_type == CL_GL_OBJECT_BUFFER || object_type == CL_GL_OBJECT_RENDERBUFFER) { return 0; } // Otherwise, it's a texture-based object and requires a bit more checking. 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"))); } int is_rgb_101010_supported(cl_context context, GLenum gl_target) { cl_image_format formatList[128]; cl_uint formatCount = 0; unsigned int i; int error; cl_mem_object_type image_type; switch (get_base_gl_target(gl_target)) { case GL_TEXTURE_1D: image_type = CL_MEM_OBJECT_IMAGE1D; case GL_TEXTURE_BUFFER: image_type = CL_MEM_OBJECT_IMAGE1D_BUFFER; break; case GL_TEXTURE_RECTANGLE_EXT: case GL_TEXTURE_2D: case GL_COLOR_ATTACHMENT0: case GL_RENDERBUFFER: case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_CUBE_MAP_POSITIVE_X: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: image_type = CL_MEM_OBJECT_IMAGE2D; break; case GL_TEXTURE_3D: image_type = CL_MEM_OBJECT_IMAGE3D; case GL_TEXTURE_1D_ARRAY: image_type = CL_MEM_OBJECT_IMAGE1D_ARRAY; case GL_TEXTURE_2D_ARRAY: image_type = CL_MEM_OBJECT_IMAGE2D_ARRAY; break; default: image_type = CL_MEM_OBJECT_IMAGE2D; } if ((error = clGetSupportedImageFormats(context, CL_MEM_READ_WRITE, image_type, 128, formatList, &formatCount))) { return error; } // Check if the RGB 101010 format is supported for (i = 0; i < formatCount; i++) { if (formatList[i].image_channel_data_type == CL_UNORM_INT_101010) { return 1; } } return 0; }