Files
OpenCL-CTS/test_conformance/gl/helpers.cpp
Sven van Haastregt f46cca0f8f [NFC] clang-format gl (#1612)
Add some clang-format off/on comments to keep kernel code readable.

Signed-off-by: Sven van Haastregt <sven.vanhaastregt@arm.com>
2023-02-06 15:09:04 +00:00

723 lines
26 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"
#if defined(__APPLE__)
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#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;
}