Initial open source release of OpenCL 1.2 CTS.

This commit is contained in:
Kedar Patil
2017-05-16 19:04:36 +05:30
parent 6911ba5116
commit f74871b7a3
563 changed files with 202074 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
if(WIN32)
list(APPEND CLConform_LIBRARIES glut32 opengl32 glu32 )
else(WIN32)
list(APPEND CLConform_LIBRARIES GL glut GLEW GLU)
endif(WIN32)
set (GL_SOURCES
main.cpp
test_buffers.cpp
test_images_2D.cpp
test_images_3D.cpp
test_renderbuffer.cpp
test_images_2D_info.cpp
test_images_3D_info.cpp
test_renderbuffer_info.cpp
test_fence_sync.cpp
helpers.cpp
../../test_common/gl/helpers.cpp
../../test_common/harness/genericThread.cpp
../../test_common/harness/errorHelpers.c
../../test_common/harness/threadTesting.c
../../test_common/harness/testHarness.c
../../test_common/harness/kernelHelpers.c
../../test_common/harness/mt19937.c
../../test_common/harness/conversions.c
../../test_common/harness/msvc9.c
)
if (WIN32)
list (APPEND GL_SOURCES ../../test_common/gl/setup_win32.cpp)
else(WIN32)
list (APPEND GL_SOURCES ../../test_common/gl/setup_x11.cpp)
endif(WIN32)
# Compiling GLEW along with the project if the compiler is MINGW.
# The mingw linker was giving weird errors while linking to glew32.lib generated by
# MSVC.
if(MINGW)
list (APPEND GL_SOURCES GLEW/glew.c)
set_source_files_properties(
${GL_SOURCES}
COMPILE_FLAGS -DGLEW_STATIC)
include_directories("./GLEW/")
endif(MINGW)
if (MSVC)
if(CMAKE_CL_64)
list(APPEND CLConform_LIBRARIES glew64)
else(CMAKE_CL_64)
list(APPEND CLConform_LIBRARIES glew32)
endif(CMAKE_CL_64)
endif(MSVC)
add_executable(conformance_test_gl
${GL_SOURCES} ${GLUT_SOURCES})
set_source_files_properties(
${GL_SOURCES}
PROPERTIES LANGUAGE CXX)
TARGET_LINK_LIBRARIES(conformance_test_gl
${CLConform_LIBRARIES})

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
project
: requirements
# <toolset>gcc:<cflags>-xc++
# <toolset>msvc:<cflags>"/TP"
;
exe test_gl
: helpers.cpp
main.cpp
test_buffers.cpp
test_images_2D.cpp
test_images_2D_info.cpp
test_images_3D.cpp
test_images_3D_info.cpp
test_renderbuffer.cpp
test_renderbuffer_info.cpp
: <target-os>darwin:<source>setup_osx.cpp
<target-os>linux:<source>setup_x11.cpp
<target-os>windows:<source>setup_win32.cpp
<library>../..//glut
<library>../..//glew
;
install dist
: test_gl
: <variant>debug:<location>$(DIST)/debug/tests/test_conformance/gl
<variant>release:<location>$(DIST)/release/tests/test_conformance/gl
;

View File

@@ -0,0 +1,60 @@
ifdef BUILD_WITH_ATF
ATF = -framework ATF
USE_ATF = -DUSE_ATF
endif
SRCS = main.cpp \
helpers.cpp \
test_buffers.cpp \
test_fence_sync.cpp \
test_images_1D.cpp \
test_images_1Darray.cpp \
test_images_2Darray.cpp \
test_images_2D.cpp \
test_images_3D.cpp \
test_images_getinfo_common.cpp \
test_images_read_common.cpp \
test_images_write_common.cpp \
test_renderbuffer.cpp \
test_renderbuffer_info.cpp \
../images/image_helpers.cpp \
../../test_common/gl/helpers.cpp \
../../test_common/gl/setup_osx.cpp \
../../test_common/harness/conversions.c \
../../test_common/harness/errorHelpers.c \
../../test_common/harness/genericThread.cpp \
../../test_common/harness/imageHelpers.c \
../../test_common/harness/kernelHelpers.c \
../../test_common/harness/mt19937.c \
../../test_common/harness/testHarness.c \
../../test_common/harness/threadTesting.c
DEFINES =
SOURCES = $(abspath $(SRCS))
LIBPATH += -L/System/Library/Frameworks/OpenCL.framework/Libraries
LIBPATH += -L.
FRAMEWORK = $(SOURCES)
HEADERS =
TARGET = test_gl
INCLUDE =
COMPILERFLAGS = -c -Wall -g -Wshorten-64-to-32
CC = c++
CFLAGS = $(COMPILERFLAGS) ${RC_CFLAGS} ${USE_ATF} $(DEFINES:%=-D%) $(INCLUDE)
CXXFLAGS = $(COMPILERFLAGS) ${RC_CFLAGS} ${USE_ATF} $(DEFINES:%=-D%) $(INCLUDE)
LIBRARIES = -framework OpenCL -framework OpenGL -framework GLUT -framework AppKit ${ATF}
OBJECTS := ${SOURCES:.c=.o}
OBJECTS := ${OBJECTS:.cpp=.o}
TARGETOBJECT =
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) $(RC_CFLAGS) $(OBJECTS) -o $@ $(LIBPATH) $(LIBRARIES)
clean:
rm -f $(TARGET) $(OBJECTS)
.DEFAULT:
@echo The target \"$@\" does not exist in Makefile.

View File

@@ -0,0 +1,66 @@
//
// 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.
//
#ifndef __COMMON_H__
#define __COMMON_H__
#include "testBase.h"
typedef struct {
size_t width;
size_t height;
size_t depth;
} sizevec_t;
struct format {
GLenum internal;
GLenum formattype;
GLenum datatype;
ExplicitType type;
};
// These are the typically tested formats.
static struct format common_formats[] = {
#ifdef __APPLE__
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, kUChar },
{ 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 },
#endif
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, kUChar },
{ GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, kUShort },
{ 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 },
{ GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT, kFloat },
{ GL_RGBA16F_ARB, GL_RGBA, GL_HALF_FLOAT, kHalf }
};
int test_images_write_common(cl_device_id device, cl_context context,
cl_command_queue queue, struct format* formats, size_t nformats,
GLenum *targets, size_t ntargets, sizevec_t* sizes, size_t nsizes );
int test_images_read_common( cl_device_id device, cl_context context,
cl_command_queue queue, struct format* formats, size_t nformats,
GLenum *targets, size_t ntargets, size_t *sizes, size_t nsizes );
int test_images_get_info_common( cl_device_id device, cl_context context,
cl_command_queue queue, struct format* formats, size_t nformats,
GLenum *targets, size_t ntargets, size_t *sizes, size_t nsizes );
#endif // __COMMON_H__

View File

@@ -0,0 +1,508 @@
//
// 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_SNORM_INT8:
case CL_SNORM_INT16:
case CL_HALF_FLOAT:
case CL_FLOAT:
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:
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_HALF_FLOAT:
case CL_FLOAT:
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:
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_HALF_FLOAT:
case CL_FLOAT:
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 )
{
#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 * 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 if( inType == kHalf )
{
cl_half *src = (cl_half *)inputBuffer;
switch( outType )
{
case kFloat:
{
cl_float *outData = new cl_float[ numPixels * 4 ];
for( size_t i = 0; i < numPixels * 4; i++ )
{
outData[ i ] = convert_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 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 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")));
}

View File

@@ -0,0 +1,386 @@
//
// 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 <stdio.h>
#include <stdlib.h>
#if !defined(_WIN32)
#include <stdbool.h>
#endif
#include <math.h>
#include <string.h>
#if !defined (__APPLE__)
#include <CL/cl.h>
#endif
#include "procs.h"
#include "../../test_common/gl/setup.h"
#include "../../test_common/harness/testHarness.h"
#if !defined(_WIN32)
#include <unistd.h>
#endif
static cl_context sCurrentContext = NULL;
#define TEST_FN_REDIRECT( fn ) redirect_##fn
#define TEST_FN_REDIRECTOR( fn ) \
int redirect_##fn(cl_device_id device, cl_context context, cl_command_queue queue, int numElements ) \
{ \
int error; \
clCommandQueueWrapper realQueue = clCreateCommandQueue( sCurrentContext, device, 0, &error ); \
test_error( error, "Unable to create command queue" ); \
return fn( device, sCurrentContext, realQueue, numElements ); \
}
// buffers:
TEST_FN_REDIRECTOR( test_buffers )
TEST_FN_REDIRECTOR( test_buffers_getinfo )
// 1D images:
TEST_FN_REDIRECTOR( test_images_read_1D )
TEST_FN_REDIRECTOR( test_images_write_1D )
TEST_FN_REDIRECTOR( test_images_1D_getinfo )
// 1D image arrays:
TEST_FN_REDIRECTOR( test_images_read_1Darray )
TEST_FN_REDIRECTOR( test_images_write_1Darray )
TEST_FN_REDIRECTOR( test_images_1Darray_getinfo )
// 2D images:
TEST_FN_REDIRECTOR( test_images_read_2D )
TEST_FN_REDIRECTOR( test_images_read_cube )
TEST_FN_REDIRECTOR( test_images_write )
TEST_FN_REDIRECTOR( test_images_write_cube )
TEST_FN_REDIRECTOR( test_images_2D_getinfo )
TEST_FN_REDIRECTOR( test_images_cube_getinfo )
// 2D image arrays:
TEST_FN_REDIRECTOR( test_images_read_2Darray )
TEST_FN_REDIRECTOR( test_images_write_2Darray )
TEST_FN_REDIRECTOR( test_images_2Darray_getinfo )
// 3D images:
TEST_FN_REDIRECTOR( test_images_read_3D )
TEST_FN_REDIRECTOR( test_images_write_3D )
TEST_FN_REDIRECTOR( test_images_3D_getinfo )
// Renderbuffer-backed images:
TEST_FN_REDIRECTOR( test_renderbuffer_read )
TEST_FN_REDIRECTOR( test_renderbuffer_write )
TEST_FN_REDIRECTOR( test_renderbuffer_getinfo )
TEST_FN_REDIRECTOR( test_fence_sync )
basefn basefn_list[] = {
TEST_FN_REDIRECT( test_buffers ),
TEST_FN_REDIRECT( test_buffers_getinfo ),
TEST_FN_REDIRECT( test_images_read_1D ),
TEST_FN_REDIRECT( test_images_write_1D ),
TEST_FN_REDIRECT( test_images_1D_getinfo ),
TEST_FN_REDIRECT( test_images_read_1Darray ),
TEST_FN_REDIRECT( test_images_write_1Darray ),
TEST_FN_REDIRECT( test_images_1Darray_getinfo ),
TEST_FN_REDIRECT( test_images_read_2D ),
TEST_FN_REDIRECT( test_images_write ),
TEST_FN_REDIRECT( test_images_2D_getinfo ),
TEST_FN_REDIRECT( test_images_read_cube ),
TEST_FN_REDIRECT( test_images_write_cube ),
TEST_FN_REDIRECT( test_images_cube_getinfo ),
TEST_FN_REDIRECT( test_images_read_2Darray ),
TEST_FN_REDIRECT( test_images_write_2Darray),
TEST_FN_REDIRECT( test_images_2Darray_getinfo ),
TEST_FN_REDIRECT( test_images_read_3D ),
TEST_FN_REDIRECT( test_images_write_3D ),
TEST_FN_REDIRECT( test_images_3D_getinfo ),
TEST_FN_REDIRECT( test_renderbuffer_read ),
TEST_FN_REDIRECT( test_renderbuffer_write ),
TEST_FN_REDIRECT( test_renderbuffer_getinfo )
};
basefn basefn_list32[] = {
TEST_FN_REDIRECT( test_fence_sync )
};
const char *basefn_names[] = {
"buffers",
"buffers_getinfo",
"images_read_1D",
"images_write_1D",
"images_1D_getinfo",
"images_read_1Darray",
"images_write_1Darray",
"images_1Darray_getinfo",
"images_read", /* 2D */
"images_write",
"images_2D_getinfo",
"images_read_cube",
"images_write_cube",
"images_cube_getinfo",
"images_read_2Darray",
"images_write_2Darray",
"images_2Darray_getinfo",
"images_read_3D",
"images_write_3D",
"images_3D_getinfo",
"renderbuffer_read",
"renderbuffer_write",
"renderbuffer_getinfo",
"all"
};
const char *basefn_names32[] = {
"fence_sync",
"all"
};
ct_assert((sizeof(basefn_names) / sizeof(basefn_names[0]) - 1) == (sizeof(basefn_list) / sizeof(basefn_list[0])));
int num_fns = sizeof(basefn_names) / sizeof(char *);
int num_fns32 = sizeof(basefn_names32) / sizeof(char *);
cl_device_type gDeviceType = CL_DEVICE_TYPE_DEFAULT;
bool gTestRounding = true;
int main(int argc, const char *argv[])
{
int error = 0;
test_start();
cl_device_type requestedDeviceType = CL_DEVICE_TYPE_GPU;
checkDeviceTypeOverride(&requestedDeviceType);
if (requestedDeviceType != CL_DEVICE_TYPE_GPU) {
log_info("GL tests can only run on a GPU device.\n");
test_finish();
return 0;
}
gDeviceType = CL_DEVICE_TYPE_GPU;
if( argc > 1 && strcmp( argv[ 1 ], "-list" ) == 0 )
{
log_info( "Available 2.x tests:\n" );
for( int i = 0; i < num_fns - 1; i++ )
log_info( "\t%s\n", basefn_names[ i ] );
log_info( "Available 3.2 tests:\n" );
for( int i = 0; i < num_fns32 - 1; i++ )
log_info( "\t%s\n", basefn_names32[ i ] );
log_info( "Note: Any 3.2 test names must follow 2.1 test names on the command line.\n" );
log_info( "Use environment variables to specify desired device.\n" );
test_finish();
return 0;
}
// Check to see if any 2.x or 3.2 test names were specified on the command line.
unsigned first_32_testname = 0;
for (int j=1; (j<argc) && (!first_32_testname); ++j)
for (int i=0;i<num_fns32-1;++i)
if (strcmp(basefn_names32[i],argv[j])==0) {
first_32_testname = j;
break;
}
// Create the environment for the test.
GLEnvironment *glEnv = GLEnvironment::Instance();
// Check if any devices of the requested type support CL/GL interop.
int supported = glEnv->SupportsCLGLInterop( requestedDeviceType );
if( supported == 0 ) {
log_info("Test not run because GL-CL interop is not supported for any devices of the requested type.\n");
test_finish();
return 0;
} else if ( supported == -1 ) {
log_error("Unable to setup the test or failed to determine if CL-GL interop is supported.\n");
test_finish();
return -1;
}
// Initialize function pointers.
error = init_clgl_ext();
if (error < 0) {
return error;
}
// OpenGL tests for non-3.2 ////////////////////////////////////////////////////////
if ((argc == 1) || (first_32_testname != 1)) {
// At least one device supports CL-GL interop, so init the test.
if( glEnv->Init( &argc, (char **)argv, CL_FALSE ) ) {
log_error("Failed to initialize the GL environment for this test.\n");
test_finish();
return -1;
}
// Create a context to use and then grab a device (or devices) from it
sCurrentContext = glEnv->CreateCLContext();
if( sCurrentContext == NULL )
{
log_error( "ERROR: Unable to obtain CL context from GL\n" );
test_finish();
return -1;
}
size_t numDevices = 0;
cl_device_id *deviceIDs;
error = clGetContextInfo( sCurrentContext, CL_CONTEXT_DEVICES, 0, NULL, &numDevices);
if( error != CL_SUCCESS )
{
print_error( error, "Unable to get device count from context" );
test_finish();
return -1;
}
deviceIDs = (cl_device_id *)malloc(numDevices);
if (deviceIDs == NULL) {
print_error( error, "malloc failed" );
test_finish();
return -1;
}
error = clGetContextInfo( sCurrentContext, CL_CONTEXT_DEVICES, numDevices, deviceIDs, NULL);
if( error != CL_SUCCESS ) {
print_error( error, "Unable to get device list from context" );
test_finish();
return -1;
}
numDevices /= sizeof(cl_device_id);
if (numDevices < 1) {
log_error("No devices found.\n");
test_finish();
return -1;
}
// Execute tests.
int argc_ = (first_32_testname) ? first_32_testname : argc;
for( size_t i = 0; i < numDevices; i++ ) {
log_info( "\nTesting OpenGL 2.x\n" );
if( printDeviceHeader( deviceIDs[ i ] ) != CL_SUCCESS ) {
test_finish();
return -1;
}
// Note: don't use the entire harness, because we have a different way of obtaining the device (via the context)
error = parseAndCallCommandLineTests( argc_, argv, deviceIDs[ i ], num_fns, basefn_list, basefn_names, true, 0, 1024 );
if( error != 0 )
break;
}
// Clean-up.
free(deviceIDs);
clReleaseContext( sCurrentContext );
//delete glEnv;
}
// OpenGL 3.2 tests. ////////////////////////////////////////////////////////
if ((argc==1) || first_32_testname) {
// At least one device supports CL-GL interop, so init the test.
if( glEnv->Init( &argc, (char **)argv, CL_TRUE ) ) {
log_error("Failed to initialize the GL environment for this test.\n");
test_finish();
return -1;
}
// Create a context to use and then grab a device (or devices) from it
sCurrentContext = glEnv->CreateCLContext();
if( sCurrentContext == NULL ) {
log_error( "ERROR: Unable to obtain CL context from GL\n" );
test_finish();
return -1;
}
size_t numDevices = 0;
cl_device_id *deviceIDs;
error = clGetContextInfo( sCurrentContext, CL_CONTEXT_DEVICES, 0, NULL, &numDevices);
if( error != CL_SUCCESS ) {
print_error( error, "Unable to get device count from context" );
test_finish();
return -1;
}
deviceIDs = (cl_device_id *)malloc(numDevices);
if (deviceIDs == NULL) {
print_error( error, "malloc failed" );
test_finish();
return -1;
}
error = clGetContextInfo( sCurrentContext, CL_CONTEXT_DEVICES, numDevices, deviceIDs, NULL);
if( error != CL_SUCCESS ) {
print_error( error, "Unable to get device list from context" );
test_finish();
return -1;
}
numDevices /= sizeof(cl_device_id);
if (numDevices < 1) {
log_error("No devices found.\n");
test_finish();
return -1;
}
int argc_ = (first_32_testname) ? 1 + (argc - first_32_testname) : argc;
const char** argv_ = (first_32_testname) ? &argv[first_32_testname-1] : argv;
// Execute the tests.
for( size_t i = 0; i < numDevices; i++ ) {
log_info( "\nTesting OpenGL 3.2\n" );
if( printDeviceHeader( deviceIDs[ i ] ) != CL_SUCCESS ) {
test_finish();
return -1;
}
// Note: don't use the entire harness, because we have a different way of obtaining the device (via the context)
error = parseAndCallCommandLineTests( argc_, argv_, deviceIDs[ i ], num_fns32, basefn_list32, basefn_names32, true, 0, 1024 );
if( error != 0 )
break;
}
// Clean-up.
free(deviceIDs);
clReleaseContext( sCurrentContext );
delete glEnv;
}
//All done.
return error;
}

107
test_conformance/gl/procs.h Normal file
View File

@@ -0,0 +1,107 @@
//
// 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 "../../test_common/harness/mt19937.h"
#pragma mark -
#pragma Misc tests
extern int test_buffers( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
extern int test_fence_sync( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements );
#pragma mark -
#pragma mark Tead tests
extern int test_images_read_2D( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
extern int test_images_read_1D( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
extern int test_images_read_1Darray( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
extern int test_images_read_2Darray( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
extern int test_images_read_cube( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
extern int test_images_read_3D( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
extern int test_renderbuffer_read( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
#pragma mark -
#pragma mark Write tests
// 2D tests are the ones with no suffix:
extern int test_images_write( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
extern int test_images_write_cube( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
extern int test_renderbuffer_write( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
// Here are the rest:
extern int test_images_write_1D( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
extern int test_images_write_1Darray( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
extern int test_images_write_2Darray( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
extern int test_images_write_3D( cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements );
#pragma mark -
#pragma mark Get info test entry points
extern int test_buffers_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements );
extern int test_images_1D_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements );
extern int test_images_1Darray_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements );
extern int test_images_2D_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements );
extern int test_images_2Darray_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements );
extern int test_images_cube_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements );
extern int test_images_3D_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements );
extern int test_renderbuffer_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements );

View File

@@ -0,0 +1,68 @@
//
// 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.
//
#ifndef _testBase_h
#define _testBase_h
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#if !defined(_WIN32)
#include <stdbool.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#if !defined (__APPLE__)
#include <CL/cl.h>
#include "../../test_common/gl/gl_headers.h"
#include <CL/cl_gl.h>
#else
#include "../../test_common/gl/gl_headers.h"
#endif
#include "../../test_common/harness/errorHelpers.h"
#include "../../test_common/harness/kernelHelpers.h"
#include "../../test_common/harness/threadTesting.h"
#include "../../test_common/harness/typeWrappers.h"
#include "../../test_common/harness/conversions.h"
#include "../../test_common/harness/mt19937.h"
#include "../../test_common/gl/helpers.h"
#include "../images/image_helpers.h"
extern const char *get_kernel_suffix( cl_image_format *format );
extern const char *get_write_conversion( cl_image_format *format, ExplicitType type);
extern ExplicitType get_read_kernel_type( cl_image_format *format );
extern ExplicitType get_write_kernel_type( cl_image_format *format );
extern char * convert_to_expected( void * inputBuffer, size_t numPixels, ExplicitType inType, ExplicitType outType );
extern int validate_integer_results( void *expectedResults, void *actualResults, size_t width, size_t height, size_t typeSize );
extern int validate_integer_results( void *expectedResults, void *actualResults, size_t width, size_t height, size_t depth, size_t typeSize );
extern int validate_float_results( void *expectedResults, void *actualResults, size_t width, size_t height );
extern int validate_float_results( void *expectedResults, void *actualResults, size_t width, size_t height, size_t depth );
extern 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);
extern bool CheckGLIntegerExtensionSupport();
#endif // _testBase_h

View File

@@ -0,0 +1,359 @@
//
// 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 "../../test_common/harness/conversions.h"
#include "../../test_common/harness/typeWrappers.h"
#include <math.h>
#include <float.h>
#if !defined (__APPLE__)
#include <CL/cl_gl.h>
#endif
extern "C" { extern cl_uint gRandomSeed; };
static const char *bufferKernelPattern =
"__kernel void sample_test( __global %s%s *source, __global %s%s *clDest, __global %s%s *glDest )\n"
"{\n"
" int tid = get_global_id(0);\n"
" clDest[ tid ] = source[ tid ] + (%s%s)(1);\n"
" glDest[ tid ] = source[ tid ] + (%s%s)(2);\n"
"}\n";
#define TYPE_CASE( enum, type, range, offset ) \
case enum: \
{ \
cl_##type *ptr = (cl_##type *)outData; \
for( i = 0; i < count; i++ ) \
ptr[ i ] = (cl_##type)( ( genrand_int32(d) & range ) - offset ); \
break; \
}
void gen_input_data( ExplicitType type, size_t count, MTdata d, void *outData )
{
size_t i;
switch( type )
{
case kBool:
{
bool *boolPtr = (bool *)outData;
for( i = 0; i < count; i++ )
{
boolPtr[i] = ( genrand_int32(d) & 1 ) ? true : false;
}
break;
}
TYPE_CASE( kChar, char, 250, 127 )
TYPE_CASE( kUChar, uchar, 250, 0 )
TYPE_CASE( kShort, short, 65530, 32767 )
TYPE_CASE( kUShort, ushort, 65530, 0 )
TYPE_CASE( kInt, int, 0x0fffffff, 0x70000000 )
TYPE_CASE( kUInt, uint, 0x0fffffff, 0 )
case kLong:
{
cl_long *longPtr = (cl_long *)outData;
for( i = 0; i < count; i++ )
{
longPtr[i] = (cl_long)genrand_int32(d) | ( (cl_ulong)genrand_int32(d) << 32 );
}
break;
}
case kULong:
{
cl_ulong *ulongPtr = (cl_ulong *)outData;
for( i = 0; i < count; i++ )
{
ulongPtr[i] = (cl_ulong)genrand_int32(d) | ( (cl_ulong)genrand_int32(d) << 32 );
}
break;
}
case kFloat:
{
cl_float *floatPtr = (float *)outData;
for( i = 0; i < count; i++ )
floatPtr[i] = get_random_float( -100000.f, 100000.f, d );
break;
}
default:
log_error( "ERROR: Invalid type passed in to generate_random_data!\n" );
break;
}
}
#define INC_CASE( enum, type ) \
case enum: \
{ \
cl_##type *src = (cl_##type *)inData; \
cl_##type *dst = (cl_##type *)outData; \
*dst = *src + 1; \
break; \
}
void get_incremented_value( void *inData, void *outData, ExplicitType type )
{
switch( type )
{
INC_CASE( kChar, char )
INC_CASE( kUChar, uchar )
INC_CASE( kShort, short )
INC_CASE( kUShort, ushort )
INC_CASE( kInt, int )
INC_CASE( kUInt, uint )
INC_CASE( kLong, long )
INC_CASE( kULong, ulong )
INC_CASE( kFloat, float )
default:
break;
}
}
int test_buffer_kernel(cl_context context, cl_command_queue queue, ExplicitType vecType, size_t vecSize, int numElements, int validate_only, MTdata d)
{
clProgramWrapper program;
clKernelWrapper kernel;
clMemWrapper streams[ 3 ];
size_t dataSize = numElements * 16 * sizeof(cl_long);
#if !(defined(_WIN32) && defined(_MSC_VER))
cl_long inData[numElements * 16], outDataCL[numElements * 16], outDataGL[ numElements * 16 ];
#else
cl_long* inData = (cl_long*)_malloca(dataSize);
cl_long* outDataCL = (cl_long*)_malloca(dataSize);
cl_long* outDataGL = (cl_long*)_malloca(dataSize);
#endif
glBufferWrapper inGLBuffer, outGLBuffer;
int i;
size_t bufferSize;
int error;
size_t threads[1], localThreads[1];
char kernelSource[10240];
char *programPtr;
char sizeName[4];
/* Create the source */
if( vecSize == 1 )
sizeName[ 0 ] = 0;
else
sprintf( sizeName, "%d", (int)vecSize );
sprintf( kernelSource, bufferKernelPattern, get_explicit_type_name( vecType ), sizeName,
get_explicit_type_name( vecType ), sizeName,
get_explicit_type_name( vecType ), sizeName,
get_explicit_type_name( vecType ), sizeName,
get_explicit_type_name( vecType ), sizeName );
/* Create kernels */
programPtr = kernelSource;
if( create_single_kernel_helper( context, &program, &kernel, 1, (const char **)&programPtr, "sample_test" ) )
{
return -1;
}
bufferSize = numElements * vecSize * get_explicit_type_size( vecType );
/* Generate some almost-random input data */
gen_input_data( vecType, vecSize * numElements, d, inData );
memset( outDataCL, 0, dataSize );
memset( outDataGL, 0, dataSize );
/* Generate some GL buffers to go against */
glGenBuffers( 1, &inGLBuffer );
glGenBuffers( 1, &outGLBuffer );
glBindBuffer( GL_ARRAY_BUFFER, inGLBuffer );
glBufferData( GL_ARRAY_BUFFER, bufferSize, inData, GL_STATIC_DRAW );
// Note: we need to bind the output buffer, even though we don't care about its values yet,
// because CL needs it to get the buffer size
glBindBuffer( GL_ARRAY_BUFFER, outGLBuffer );
glBufferData( GL_ARRAY_BUFFER, bufferSize, outDataGL, GL_STATIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glFlush();
/* Generate some streams. The first and last ones are GL, middle one just vanilla CL */
streams[ 0 ] = (*clCreateFromGLBuffer_ptr)( context, CL_MEM_READ_ONLY, inGLBuffer, &error );
test_error( error, "Unable to create input GL buffer" );
streams[ 1 ] = clCreateBuffer( context, CL_MEM_READ_WRITE, bufferSize, NULL, &error );
test_error( error, "Unable to create output CL buffer" );
streams[ 2 ] = (*clCreateFromGLBuffer_ptr)( context, CL_MEM_WRITE_ONLY, outGLBuffer, &error );
test_error( error, "Unable to create output GL buffer" );
/* Validate the info */
if (validate_only) {
int result = (CheckGLObjectInfo(streams[0], CL_GL_OBJECT_BUFFER, (GLuint)inGLBuffer, (GLenum)0, 0) |
CheckGLObjectInfo(streams[2], CL_GL_OBJECT_BUFFER, (GLuint)outGLBuffer, (GLenum)0, 0) );
for(i=0;i<3;i++)
{
clReleaseMemObject(streams[i]);
streams[i] = NULL;
}
glDeleteBuffers(1, &inGLBuffer); inGLBuffer = 0;
glDeleteBuffers(1, &outGLBuffer); outGLBuffer = 0;
return result;
}
/* Assign streams and execute */
for( int i = 0; i < 3; i++ )
{
error = clSetKernelArg( kernel, i, sizeof( streams[ i ] ), &streams[ i ] );
test_error( error, "Unable to set kernel arguments" );
}
error = (*clEnqueueAcquireGLObjects_ptr)( queue, 1, &streams[ 0 ], 0, NULL, NULL);
test_error( error, "Unable to acquire GL obejcts");
error = (*clEnqueueAcquireGLObjects_ptr)( queue, 1, &streams[ 2 ], 0, NULL, NULL);
test_error( error, "Unable to acquire GL obejcts");
/* Run the kernel */
threads[0] = numElements;
error = get_max_common_work_group_size( context, kernel, threads[0], &localThreads[0] );
test_error( error, "Unable to get work group size to use" );
error = clEnqueueNDRangeKernel( queue, kernel, 1, NULL, threads, localThreads, 0, NULL, NULL );
test_error( error, "Unable to execute test kernel" );
error = (*clEnqueueReleaseGLObjects_ptr)( queue, 1, &streams[ 0 ], 0, NULL, NULL );
test_error(error, "clEnqueueReleaseGLObjects failed");
error = (*clEnqueueReleaseGLObjects_ptr)( queue, 1, &streams[ 2 ], 0, NULL, NULL );
test_error(error, "clEnqueueReleaseGLObjects failed");
// Get the results from both CL and GL and make sure everything looks correct
error = clEnqueueReadBuffer( queue, streams[ 1 ], CL_TRUE, 0, bufferSize, outDataCL, 0, NULL, NULL );
test_error( error, "Unable to read output CL array!" );
glBindBuffer( GL_ARRAY_BUFFER, outGLBuffer );
void *glMem = glMapBuffer( GL_ARRAY_BUFFER, GL_READ_ONLY );
memcpy( outDataGL, glMem, bufferSize );
glUnmapBuffer( GL_ARRAY_BUFFER );
char *inP = (char *)inData, *glP = (char *)outDataGL, *clP = (char *)outDataCL;
error = 0;
for( size_t i = 0; i < numElements * vecSize; i++ )
{
cl_long expectedCLValue, expectedGLValue;
get_incremented_value( inP, &expectedCLValue, vecType );
get_incremented_value( &expectedCLValue, &expectedGLValue, vecType );
if( memcmp( clP, &expectedCLValue, get_explicit_type_size( vecType ) ) != 0 )
{
char scratch[ 64 ];
log_error( "ERROR: Data sample %d from the CL output did not validate!\n", (int)i );
log_error( "\t Input: %s\n", GetDataVectorString( inP, get_explicit_type_size( vecType ), 1, scratch ) );
log_error( "\tExpected: %s\n", GetDataVectorString( &expectedCLValue, get_explicit_type_size( vecType ), 1, scratch ) );
log_error( "\t Actual: %s\n", GetDataVectorString( clP, get_explicit_type_size( vecType ), 1, scratch ) );
error = -1;
}
if( memcmp( glP, &expectedGLValue, get_explicit_type_size( vecType ) ) != 0 )
{
char scratch[ 64 ];
log_error( "ERROR: Data sample %d from the GL output did not validate!\n", (int)i );
log_error( "\t Input: %s\n", GetDataVectorString( inP, get_explicit_type_size( vecType ), 1, scratch ) );
log_error( "\tExpected: %s\n", GetDataVectorString( &expectedGLValue, get_explicit_type_size( vecType ), 1, scratch ) );
log_error( "\t Actual: %s\n", GetDataVectorString( glP, get_explicit_type_size( vecType ), 1, scratch ) );
error = -1;
}
if( error )
return error;
inP += get_explicit_type_size( vecType );
glP += get_explicit_type_size( vecType );
clP += get_explicit_type_size( vecType );
}
for(i=0;i<3;i++)
{
clReleaseMemObject(streams[i]);
streams[i] = NULL;
}
glDeleteBuffers(1, &inGLBuffer); inGLBuffer = 0;
glDeleteBuffers(1, &outGLBuffer); outGLBuffer = 0;
return 0;
}
int test_buffers( cl_device_id device, cl_context context, cl_command_queue queue, int numElements )
{
ExplicitType vecType[] = { kChar, kUChar, kShort, kUShort, kInt, kUInt, kLong, kULong, kFloat, kNumExplicitTypes };
unsigned int vecSizes[] = { 1, 2, 4, 8, 16, 0 };
unsigned int index, typeIndex;
int retVal = 0;
RandomSeed seed(gRandomSeed);
for( typeIndex = 0; vecType[ typeIndex ] != kNumExplicitTypes; typeIndex++ )
{
for( index = 0; vecSizes[ index ] != 0; index++ )
{
// Test!
if( test_buffer_kernel( context, queue, vecType[ typeIndex ], vecSizes[ index ], numElements, 0, seed) != 0 )
{
char sizeNames[][ 4 ] = { "", "", "2", "", "4", "", "", "", "8", "", "", "", "", "", "", "", "16" };
log_error( " Buffer test %s%s FAILED\n", get_explicit_type_name( vecType[ typeIndex ] ), sizeNames[ vecSizes[ index ] ] );
retVal++;
}
}
}
return retVal;
}
int test_buffers_getinfo( cl_device_id device, cl_context context, cl_command_queue queue, int numElements )
{
ExplicitType vecType[] = { kChar, kUChar, kShort, kUShort, kInt, kUInt, kLong, kULong, kFloat, kNumExplicitTypes };
unsigned int vecSizes[] = { 1, 2, 4, 8, 16, 0 };
unsigned int index, typeIndex;
int retVal = 0;
RandomSeed seed( gRandomSeed );
for( typeIndex = 0; vecType[ typeIndex ] != kNumExplicitTypes; typeIndex++ )
{
for( index = 0; vecSizes[ index ] != 0; index++ )
{
// Test!
if( test_buffer_kernel( context, queue, vecType[ typeIndex ], vecSizes[ index ], numElements, 1, seed ) != 0 )
{
char sizeNames[][ 4 ] = { "", "", "2", "", "4", "", "", "", "8", "", "", "", "", "", "", "", "16" };
log_error( " Buffer test %s%s FAILED\n", get_explicit_type_name( vecType[ typeIndex ] ), sizeNames[ vecSizes[ index ] ] );
retVal++;
}
}
}
return retVal;
}

View File

@@ -0,0 +1,678 @@
//
// 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 "../../test_common/gl/setup.h"
#include "../../test_common/harness/genericThread.h"
#if defined( __APPLE__ )
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#include <CL/cl_gl.h>
#endif
#ifndef GLsync
// For OpenGL before 3.2, we look for the ARB_sync extension and try to use that
#if !defined(_WIN32)
#include <inttypes.h>
#endif // !_WIN32
typedef int64_t GLint64;
typedef uint64_t GLuint64;
typedef struct __GLsync *GLsync;
typedef GLsync (*glFenceSyncPtr)(GLenum condition,GLbitfield flags);
glFenceSyncPtr glFenceSyncFunc;
typedef bool (*glIsSyncPtr)(GLsync sync);
glIsSyncPtr glIsSyncFunc;
typedef void (*glDeleteSyncPtr)(GLsync sync);
glDeleteSyncPtr glDeleteSyncFunc;
typedef GLenum (*glClientWaitSyncPtr)(GLsync sync,GLbitfield flags,GLuint64 timeout);
glClientWaitSyncPtr glClientWaitSyncFunc;
typedef void (*glWaitSyncPtr)(GLsync sync,GLbitfield flags,GLuint64 timeout);
glWaitSyncPtr glWaitSyncFunc;
typedef void (*glGetInteger64vPtr)(GLenum pname, GLint64 *params);
glGetInteger64vPtr glGetInteger64vFunc;
typedef void (*glGetSyncivPtr)(GLsync sync,GLenum pname,GLsizei bufSize,GLsizei *length,
GLint *values);
glGetSyncivPtr glGetSyncivFunc;
#define CHK_GL_ERR() printf("%s\n", gluErrorString(glGetError()))
static void InitSyncFns( void )
{
glFenceSyncFunc = (glFenceSyncPtr)glutGetProcAddress( "glFenceSync" );
glIsSyncFunc = (glIsSyncPtr)glutGetProcAddress( "glIsSync" );
glDeleteSyncFunc = (glDeleteSyncPtr)glutGetProcAddress( "glDeleteSync" );
glClientWaitSyncFunc = (glClientWaitSyncPtr)glutGetProcAddress( "glClientWaitSync" );
glWaitSyncFunc = (glWaitSyncPtr)glutGetProcAddress( "glWaitSync" );
glGetInteger64vFunc = (glGetInteger64vPtr)glutGetProcAddress( "glGetInteger64v" );
glGetSyncivFunc = (glGetSyncivPtr)glutGetProcAddress( "glGetSynciv" );
}
#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
#define GL_OBJECT_TYPE 0x9112
#define GL_SYNC_CONDITION 0x9113
#define GL_SYNC_STATUS 0x9114
#define GL_SYNC_FLAGS 0x9115
#define GL_SYNC_FENCE 0x9116
#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
#define GL_UNSIGNALED 0x9118
#define GL_SIGNALED 0x9119
#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull
#define GL_ALREADY_SIGNALED 0x911A
#define GL_TIMEOUT_EXPIRED 0x911B
#define GL_CONDITION_SATISFIED 0x911C
#define GL_WAIT_FAILED 0x911D
#define USING_ARB_sync 1
#endif
typedef cl_event (CL_API_CALL *clCreateEventFromGLsyncKHR_fn)( cl_context context, GLsync sync, cl_int *errCode_ret) ;
clCreateEventFromGLsyncKHR_fn clCreateEventFromGLsyncKHR_ptr;
static const char *updateBuffersKernel[] = {
"__kernel void update( __global float4 * vertices, __global float4 *colors, int horizWrap, int rowIdx )\n"
"{\n"
" size_t tid = get_global_id(0);\n"
"\n"
" size_t xVal = ( tid & ( horizWrap - 1 ) );\n"
" vertices[ tid * 2 + 0 ] = (float4)( xVal, rowIdx*16.f, 0.0f, 1.f );\n"
" vertices[ tid * 2 + 1 ] = (float4)( xVal, rowIdx*16.f + 4.0f, 0.0f, 1.f );\n"
"\n"
" int rowV = rowIdx + 1;\n"
" colors[ tid * 2 + 0 ] = (float4)( ( rowV & 1 ) / 255.f, ( ( rowV & 2 ) >> 1 ) / 255.f, ( ( rowV & 4 ) >> 2 ) / 255.f, 1.f );\n"
" //colors[ tid * 2 + 0 ] = (float4)( (float)xVal/(float)horizWrap, 1.0f, 1.0f, 1.0f );\n"
" colors[ tid * 2 + 1 ] = colors[ tid * 2 + 0 ];\n"
"}\n" };
//Passthrough VertexShader
static const char *vertexshader =
"#version 150\n"
"uniform mat4 projMatrix;\n"
"in vec4 inPosition;\n"
"in vec4 inColor;\n"
"out vec4 vertColor;\n"
"void main (void) {\n"
" gl_Position = projMatrix*inPosition;\n"
" vertColor = inColor;\n"
"}\n";
//Passthrough FragmentShader
static const char *fragmentshader =
"#version 150\n"
"in vec4 vertColor;\n"
"out vec4 outColor;\n"
"void main (void) {\n"
" outColor = vertColor;\n"
"}\n";
GLuint createShaderProgram(GLint *posLoc, GLint *colLoc)
{
GLint logLength, status;
GLuint program = glCreateProgram();
GLuint vpShader;
vpShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vpShader, 1, (const GLchar **)&vertexshader, NULL);
glCompileShader(vpShader);
glGetShaderiv(vpShader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar*) malloc(logLength);
glGetShaderInfoLog(vpShader, logLength, &logLength, log);
log_info("Vtx Shader compile log:\n%s", log);
free(log);
}
glGetShaderiv(vpShader, GL_COMPILE_STATUS, &status);
if (status == 0)
{
log_error("Failed to compile vtx shader:\n");
return 0;
}
glAttachShader(program, vpShader);
GLuint fpShader;
fpShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fpShader, 1, (const GLchar **)&fragmentshader, NULL);
glCompileShader(fpShader);
glGetShaderiv(fpShader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar*)malloc(logLength);
glGetShaderInfoLog(fpShader, logLength, &logLength, log);
log_info("Frag Shader compile log:\n%s", log);
free(log);
}
glAttachShader(program, fpShader);
glGetShaderiv(fpShader, GL_COMPILE_STATUS, &status);
if (status == 0)
{
log_error("Failed to compile frag shader:\n\n");
return 0;
}
glLinkProgram(program);
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar*)malloc(logLength);
glGetProgramInfoLog(program, logLength, &logLength, log);
log_info("Program link log:\n%s", log);
free(log);
}
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status == 0)
{
log_error("Failed to link program\n");
return 0;
}
*posLoc = glGetAttribLocation(program, "inPosition");
*colLoc = glGetAttribLocation(program, "inColor");
return program;
}
void destroyShaderProgram(GLuint program)
{
GLuint shaders[2];
GLsizei count;
glUseProgram(0);
glGetAttachedShaders(program, 2, &count, shaders);
int i;
for(i = 0; i < count; i++)
{
glDetachShader(program, shaders[i]);
glDeleteShader(shaders[i]);
}
glDeleteProgram(program);
}
// This function queues up and runs the above CL kernel that writes the vertex data
cl_int run_cl_kernel( cl_kernel kernel, cl_command_queue queue, cl_mem stream0, cl_mem stream1,
cl_int rowIdx, cl_event fenceEvent, size_t numThreads )
{
cl_int error = clSetKernelArg( kernel, 3, sizeof( rowIdx ), &rowIdx );
test_error( error, "Unable to set kernel arguments" );
clEventWrapper acqEvent1, acqEvent2, kernEvent, relEvent1, relEvent2;
int numEvents = ( fenceEvent != NULL ) ? 1 : 0;
cl_event *fence_evt = ( fenceEvent != NULL ) ? &fenceEvent : NULL;
error = (*clEnqueueAcquireGLObjects_ptr)( queue, 1, &stream0, numEvents, fence_evt, &acqEvent1 );
test_error( error, "Unable to acquire GL obejcts");
error = (*clEnqueueAcquireGLObjects_ptr)( queue, 1, &stream1, numEvents, fence_evt, &acqEvent2 );
test_error( error, "Unable to acquire GL obejcts");
cl_event evts[ 2 ] = { acqEvent1, acqEvent2 };
error = clEnqueueNDRangeKernel( queue, kernel, 1, NULL, &numThreads, NULL, 2, evts, &kernEvent );
test_error( error, "Unable to execute test kernel" );
error = (*clEnqueueReleaseGLObjects_ptr)( queue, 1, &stream0, 1, &kernEvent, &relEvent1 );
test_error(error, "clEnqueueReleaseGLObjects failed");
error = (*clEnqueueReleaseGLObjects_ptr)( queue, 1, &stream1, 1, &kernEvent, &relEvent2 );
test_error(error, "clEnqueueReleaseGLObjects failed");
evts[ 0 ] = relEvent1;
evts[ 1 ] = relEvent2;
error = clWaitForEvents( 2, evts );
test_error( error, "Unable to wait for release events" );
return 0;
}
class RunThread : public genericThread
{
public:
cl_kernel mKernel;
cl_command_queue mQueue;
cl_mem mStream0, mStream1;
cl_int mRowIdx;
cl_event mFenceEvent;
size_t mNumThreads;
RunThread( cl_kernel kernel, cl_command_queue queue, cl_mem stream0, cl_mem stream1, size_t numThreads )
: mKernel( kernel ), mQueue( queue ), mStream0( stream0 ), mStream1( stream1 ), mNumThreads( numThreads )
{
}
void SetRunData( cl_int rowIdx, cl_event fenceEvent )
{
mRowIdx = rowIdx;
mFenceEvent = fenceEvent;
}
virtual void * IRun( void )
{
cl_int error = run_cl_kernel( mKernel, mQueue, mStream0, mStream1, mRowIdx, mFenceEvent, mNumThreads );
return (void *)error;
}
};
int test_fence_sync_single( cl_device_id device, cl_context context, cl_command_queue queue, bool separateThreads, GLint rend_vs, GLint read_vs, cl_device_id rend_device )
{
int error;
const int framebufferSize = 512;
if( !is_extension_available( device, "cl_khr_gl_event" ) )
{
log_info( "NOTE: cl_khr_gl_event extension not present on this device; skipping fence sync test\n" );
return 0;
}
// Ask OpenCL for the platforms. Warn if more than one platform found,
// since this might not be the platform we want. By default, we simply
// use the first returned platform.
cl_uint nplatforms;
cl_platform_id platform;
clGetPlatformIDs(0, NULL, &nplatforms);
clGetPlatformIDs(1, &platform, NULL);
if (nplatforms > 1) {
log_info("clGetPlatformIDs returned multiple values. This is not "
"an error, but might result in obtaining incorrect function "
"pointers if you do not want the first returned platform.\n");
// Show them the platform name, in case it is a problem.
size_t size;
char *name;
clGetPlatformInfo(platform, CL_PLATFORM_NAME, 0, NULL, &size);
name = (char*)malloc(size);
clGetPlatformInfo(platform, CL_PLATFORM_NAME, size, name, NULL);
log_info("Using platform with name: %s \n", name);
free(name);
}
clCreateEventFromGLsyncKHR_ptr = (clCreateEventFromGLsyncKHR_fn)clGetExtensionFunctionAddressForPlatform(platform, "clCreateEventFromGLsyncKHR");
if( clCreateEventFromGLsyncKHR_ptr == NULL )
{
log_error( "ERROR: Unable to run fence_sync test (clCreateEventFromGLsyncKHR function not discovered!)\n" );
clCreateEventFromGLsyncKHR_ptr = (clCreateEventFromGLsyncKHR_fn)clGetExtensionFunctionAddressForPlatform(platform, "clCreateEventFromGLsyncAPPLE");
return -1;
}
#ifdef USING_ARB_sync
char *gl_version_str = (char*)glGetString( GL_VERSION );
float glCoreVersion;
sscanf(gl_version_str, "%f", &glCoreVersion);
if( glCoreVersion < 3.0f )
{
log_info( "OpenGL version %f does not support fence/sync! Skipping test.\n", glCoreVersion );
return 0;
}
#ifdef __APPLE__
CGLContextObj currCtx = CGLGetCurrentContext();
CGLPixelFormatObj pixFmt = CGLGetPixelFormat(currCtx);
GLint val, screen;
CGLGetVirtualScreen(currCtx, &screen);
CGLDescribePixelFormat(pixFmt, screen, kCGLPFAOpenGLProfile, &val);
if(val != kCGLOGLPVersion_3_2_Core)
{
log_error( "OpenGL context was not created with OpenGL version >= 3.0 profile even though platform supports it"
"OpenGL profile %f does not support fence/sync! Skipping test.\n", glCoreVersion );
return -1;
}
#else
// Need platform specific way to query if current GL context was created with 3.x profile
log_error( "ERROR: not implemented\n\n" );
return -1;
#endif
InitSyncFns();
#endif
#ifdef __APPLE__
CGLSetVirtualScreen(CGLGetCurrentContext(), rend_vs);
#else
// Need platform specific way to set device with id rend_vs the current
// rendering target
log_error( "ERROR: not implemented\n\n" );
return -1;
#endif
GLint posLoc, colLoc;
GLuint shaderprogram = createShaderProgram(&posLoc, &colLoc);
if(!shaderprogram)
{
log_error("Failed to create shader program\n");
return -1;
}
float l = 0.0f; float r = framebufferSize;
float b = 0.0f; float t = framebufferSize;
float projMatrix[16] = { 2.0f/(r-l), 0.0f, 0.0f, 0.0f,
0.0f, 2.0f/(t-b), 0.0f, 0.0f,
0.0f, 0.0f, -1.0f, 0.0f,
-(r+l)/(r-l), -(t+b)/(t-b), 0.0f, 1.0f
};
glUseProgram(shaderprogram);
GLuint projMatLoc = glGetUniformLocation(shaderprogram, "projMatrix");
glUniformMatrix4fv(projMatLoc, 1, 0, projMatrix);
glUseProgram(0);
// Note: the framebuffer is just the target to verify our results against, so we don't
// really care to go through all the possible formats in this case
glFramebufferWrapper glFramebuffer;
glRenderbufferWrapper glRenderbuffer;
error = CreateGLRenderbufferRaw( framebufferSize, 128, GL_COLOR_ATTACHMENT0_EXT,
GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
&glFramebuffer, &glRenderbuffer );
if( error != 0 )
return error;
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBufferWrapper vtxBuffer, colorBuffer;
glGenBuffers( 1, &vtxBuffer );
glGenBuffers( 1, &colorBuffer );
const int numHorizVertices = ( framebufferSize * 64 ) + 1;
glBindBuffer( GL_ARRAY_BUFFER, vtxBuffer );
glBufferData( GL_ARRAY_BUFFER, sizeof( GLfloat ) * numHorizVertices * 2 * 4, NULL, GL_STATIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, colorBuffer );
glBufferData( GL_ARRAY_BUFFER, sizeof( GLfloat ) * numHorizVertices * 2 * 4, NULL, GL_STATIC_DRAW );
// Now that the requisite objects are bound, we can attempt program
// validation:
glValidateProgram(shaderprogram);
GLint logLength, status;
glGetProgramiv(shaderprogram, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar*)malloc(logLength);
glGetProgramInfoLog(shaderprogram, logLength, &logLength, log);
log_info("Program validate log:\n%s", log);
free(log);
}
glGetProgramiv(shaderprogram, GL_VALIDATE_STATUS, &status);
if (status == 0)
{
log_error("Failed to validate program\n");
return 0;
}
clProgramWrapper program;
clKernelWrapper kernel;
clMemWrapper streams[ 2 ];
if( create_single_kernel_helper( context, &program, &kernel, 1, updateBuffersKernel, "update" ) )
return -1;
streams[ 0 ] = (*clCreateFromGLBuffer_ptr)( context, CL_MEM_READ_WRITE, vtxBuffer, &error );
test_error( error, "Unable to create CL buffer from GL vertex buffer" );
streams[ 1 ] = (*clCreateFromGLBuffer_ptr)( context, CL_MEM_READ_WRITE, colorBuffer, &error );
test_error( error, "Unable to create CL buffer from GL color buffer" );
error = clSetKernelArg( kernel, 0, sizeof( streams[ 0 ] ), &streams[ 0 ] );
test_error( error, "Unable to set kernel arguments" );
error = clSetKernelArg( kernel, 1, sizeof( streams[ 1 ] ), &streams[ 1 ] );
test_error( error, "Unable to set kernel arguments" );
cl_int horizWrap = (cl_int)framebufferSize;
error = clSetKernelArg( kernel, 2, sizeof( horizWrap ), &horizWrap );
test_error( error, "Unable to set kernel arguments" );
glViewport( 0, 0, framebufferSize, framebufferSize );
glClearColor( 0, 0, 0, 0 );
glClear( GL_COLOR_BUFFER_BIT );
glClear( GL_DEPTH_BUFFER_BIT );
glDisable( GL_DEPTH_TEST );
glEnable( GL_BLEND );
glBlendFunc( GL_ONE, GL_ONE );
clEventWrapper fenceEvent;
GLsync glFence = 0;
// Do a loop through 8 different horizontal stripes against the framebuffer
RunThread thread( kernel, queue, streams[ 0 ], streams[ 1 ], (size_t)numHorizVertices );
for( int i = 0; i < 8; i++ )
{
// if current rendering device is not the compute device and
// separateThreads == false which means compute is going on same
// thread and we are using implicit synchronization (no GLSync obj used)
// then glFlush by clEnqueueAcquireGLObject is not sufficient ... we need
// to wait for rendering to finish on other device before CL can start
// writing to CL/GL shared mem objects. When separateThreads is true i.e.
// we are using GLSync obj to synchronize then we dont need to call glFinish
// here since CL should wait for rendering on other device before this
// GLSync object to finish before it starts writing to shared mem object.
// Also rend_device == compute_device no need to call glFinish
if(rend_device != device && !separateThreads)
glFinish();
if( separateThreads )
{
thread.SetRunData( (cl_int)i, fenceEvent );
thread.Start();
error = (cl_int)(size_t)thread.Join();
}
else
{
error = run_cl_kernel( kernel, queue, streams[ 0 ], streams[ 1 ], (cl_int)i, fenceEvent, (size_t)numHorizVertices );
}
test_error( error, "Unable to run CL kernel" );
glUseProgram(shaderprogram);
glEnableVertexAttribArray(posLoc);
glEnableVertexAttribArray(colLoc);
glBindBuffer( GL_ARRAY_BUFFER, vtxBuffer );
glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), 0);
glBindBuffer( GL_ARRAY_BUFFER, colorBuffer );
glVertexAttribPointer(colLoc, 4, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), 0);
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glDrawArrays( GL_TRIANGLE_STRIP, 0, numHorizVertices * 2 );
glDisableVertexAttribArray(posLoc);
glDisableVertexAttribArray(colLoc);
glUseProgram(0);
if( separateThreads )
{
// If we're on the same thread, then we're testing implicit syncing, so we
// don't need the actual fence code
if( fenceEvent != NULL )
{
clReleaseEvent( fenceEvent );
glDeleteSyncFunc( glFence );
}
glFence = glFenceSyncFunc( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 );
fenceEvent = clCreateEventFromGLsyncKHR_ptr( context, glFence, &error );
test_error( error, "Unable to create CL event from GL fence" );
// in case of explicit synchronization, we just wait for the sync object to complete
// in clEnqueueAcquireGLObject but we dont flush. Its application's responsibility
// to flush on the context on which glSync is created
glFlush();
}
}
if( glFence != 0 )
// Don't need the final release for fenceEvent, because the wrapper will take care of that
glDeleteSyncFunc( glFence );
#ifdef __APPLE__
CGLSetVirtualScreen(CGLGetCurrentContext(), read_vs);
#else
// Need platform specific code to set the current rendering device (OpenGL target)
// to device with id read_vs so that next glReadPixels get submitted to that device
log_error( "ERROR: not implemented\n\n" );
return -1;
#endif
// Grab the contents of the final framebuffer
BufferOwningPtr<char> resultData( ReadGLRenderbuffer( glFramebuffer, glRenderbuffer,
GL_COLOR_ATTACHMENT0_EXT,
GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, kUChar,
framebufferSize, 128 ) );
// Check the contents now. We should end up with solid color bands 32 pixels high and the
// full width of the framebuffer, at values (128,128,128) due to the additive blending
for( int i = 0; i < 8; i++ )
{
for( int y = 0; y < 4; y++ )
{
// Note: coverage will be double because the 63-0 triangle overwrites again at the end of the pass
cl_uchar valA = ( ( ( i + 1 ) & 1 ) ) * numHorizVertices * 2 / framebufferSize;
cl_uchar valB = ( ( ( i + 1 ) & 2 ) >> 1 ) * numHorizVertices * 2 / framebufferSize;
cl_uchar valC = ( ( ( i + 1 ) & 4 ) >> 2 ) * numHorizVertices * 2 / framebufferSize;
cl_uchar *row = (cl_uchar *)&resultData[ ( i * 16 + y ) * framebufferSize * 4 ];
for( int x = 0; x < ( framebufferSize - 1 ) - 1; x++ )
{
if( ( row[ x * 4 ] != valA ) || ( row[ x * 4 + 1 ] != valB ) ||
( row[ x * 4 + 2 ] != valC ) )
{
log_error( "ERROR: Output framebuffer did not validate!\n" );
DumpGLBuffer( GL_UNSIGNED_BYTE, framebufferSize, 128, resultData );
log_error( "RUNS:\n" );
uint32_t *p = (uint32_t *)(char *)resultData;
size_t a = 0;
for( size_t t = 1; t < framebufferSize * framebufferSize; t++ )
{
if( p[ a ] != 0 )
{
if( p[ t ] == 0 )
{
log_error( "RUN: %ld to %ld (%d,%d to %d,%d) 0x%08x\n", a, t - 1,
(int)( a % framebufferSize ), (int)( a / framebufferSize ),
(int)( ( t - 1 ) % framebufferSize ), (int)( ( t - 1 ) / framebufferSize ),
p[ a ] );
a = t;
}
}
else
{
if( p[ t ] != 0 )
{
a = t;
}
}
}
return -1;
}
}
}
}
destroyShaderProgram(shaderprogram);
glDeleteVertexArrays(1, &vao);
return 0;
}
int test_fence_sync( cl_device_id device, cl_context context, cl_command_queue queue, int numElements )
{
GLint vs_count = 0;
cl_device_id *device_list = NULL;
if( !is_extension_available( device, "cl_khr_gl_event" ) )
{
log_info( "NOTE: cl_khr_gl_event extension not present on this device; skipping fence sync test\n" );
return 0;
}
#ifdef __APPLE__
CGLContextObj ctx = CGLGetCurrentContext();
CGLPixelFormatObj pix = CGLGetPixelFormat(ctx);
CGLError err = CGLDescribePixelFormat(pix, 0, kCGLPFAVirtualScreenCount, &vs_count);
device_list = (cl_device_id *) malloc(sizeof(cl_device_id)*vs_count);
clGetGLContextInfoAPPLE(context, ctx, CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE, sizeof(cl_device_id)*vs_count, device_list, NULL);
#else
// Need platform specific way of getting devices from CL context to which OpenGL can render
// If not available it can be replaced with clGetContextInfo with CL_CONTEXT_DEVICES
log_error( "ERROR: not implemented\n\n" );
return -1;
#endif
GLint rend_vs, read_vs;
int error = 0;
int any_failed = 0;
// Loop through all the devices capable to OpenGL rendering
// and set them as current rendering target
for(rend_vs = 0; rend_vs < vs_count; rend_vs++)
{
// Loop through all the devices and set them as current
// compute target
for(read_vs = 0; read_vs < vs_count; read_vs++)
{
cl_device_id rend_device = device_list[rend_vs], read_device = device_list[read_vs];
char rend_name[200], read_name[200];
clGetDeviceInfo(rend_device, CL_DEVICE_NAME, sizeof(rend_name), rend_name, NULL);
clGetDeviceInfo(read_device, CL_DEVICE_NAME, sizeof(read_name), read_name, NULL);
log_info("Rendering on: %s, read back on: %s\n", rend_name, read_name);
error = test_fence_sync_single( device, context, queue, false, rend_vs, read_vs, rend_device );
any_failed |= error;
if( error != 0 )
log_error( "ERROR: Implicit syncing with GL sync events failed!\n\n" );
else
log_info("Implicit syncing Passed\n");
error = test_fence_sync_single( device, context, queue, true, rend_vs, read_vs, rend_device );
any_failed |= error;
if( error != 0 )
log_error( "ERROR: Explicit syncing with GL sync events failed!\n\n" );
else
log_info("Explicit syncing Passed\n");
}
}
free(device_list);
return any_failed;
}

View File

@@ -0,0 +1,79 @@
//
// 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 "common.h"
#include "testBase.h"
#if defined( __APPLE__ )
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#include <CL/cl_gl.h>
#endif
int test_images_read_1D( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
size_t sizes[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
size_t nsizes = sizeof(sizes) / sizeof(sizes[0]);
GLenum targets[] = { GL_TEXTURE_1D, GL_TEXTURE_BUFFER };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
return test_images_read_common(device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes);
}
int test_images_write_1D( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
int error = 0;
size_t i;
const size_t nsizes = 6;
sizevec_t sizes[nsizes];
GLenum targets[] = { GL_TEXTURE_1D, GL_TEXTURE_BUFFER };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
RandomSeed seed( gRandomSeed );
// Generate some random sizes (within reasonable ranges)
for (i = 0; i < nsizes; i++) {
sizes[i].width = random_in_range( 10, 4000, seed );
sizes[i].height = 1;
sizes[i].depth = 1;
}
return test_images_write_common( device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes );
}
int test_images_1D_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
size_t sizes[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
size_t nsizes = sizeof(sizes) / sizeof(sizes[0]);
GLenum targets[] = { GL_TEXTURE_1D /*, GL_TEXTURE_BUFFER */ };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
return test_images_get_info_common( device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes);
}

View File

@@ -0,0 +1,79 @@
//
// 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 "common.h"
#include "testBase.h"
#if defined( __APPLE__ )
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#include <CL/cl_gl.h>
#endif
int test_images_read_1Darray( cl_device_id device, cl_context context,
cl_command_queue queue, int )
{
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
size_t sizes[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
size_t nsizes = sizeof(sizes) / sizeof(sizes[0]);
GLenum targets[] = { GL_TEXTURE_1D_ARRAY };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
return test_images_read_common(device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes);
}
int test_images_write_1Darray( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
int error = 0;
size_t i;
const size_t nsizes = 6;
sizevec_t sizes[nsizes];
GLenum targets[] = { GL_TEXTURE_1D_ARRAY };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
RandomSeed seed( gRandomSeed );
// Generate some random sizes (within reasonable ranges)
for (i = 0; i < nsizes; i++) {
sizes[i].width = random_in_range( 10, 4000, seed );
sizes[i].height = random_in_range( 16, 512, seed );
sizes[i].depth = 1;
}
return test_images_write_common( device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes );
}
int test_images_1Darray_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int )
{
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
size_t sizes[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
size_t nsizes = sizeof(sizes) / sizeof(sizes[0]);
GLenum targets[] = { GL_TEXTURE_1D_ARRAY };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
return test_images_get_info_common(device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes);
}

View File

@@ -0,0 +1,172 @@
//
// 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 "common.h"
#if defined( __APPLE__ )
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#include <CL/cl_gl.h>
#endif
extern "C" { extern cl_uint gRandomSeed; }
#pragma mark -
#pragma mark _2D read tests
int test_images_read_2D( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
RandomSeed seed( gRandomSeed );
GLenum targets[] = { GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_EXT };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
const size_t nsizes = 6;
size_t sizes[nsizes];
for (int i = 0; i < nsizes; i++) {
sizes[i] = random_in_range(16, 512, seed);
}
return test_images_read_common(device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes);
}
int test_images_read_cube( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
GLenum targets[] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
size_t sizes[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
size_t nsizes = sizeof(sizes) / sizeof(sizes[0]);
return test_images_read_common(device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes);
}
#pragma mark -
#pragma mark _2D write tests
#include "common.h"
int test_images_write( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
int error = 0;
size_t i;
const size_t nsizes = 6;
sizevec_t sizes[nsizes];
GLenum targets[] = { GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_EXT };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
RandomSeed seed( gRandomSeed );
// Generate some random sizes (within reasonable ranges)
for (i = 0; i < nsizes; i++) {
sizes[i].width = random_in_range( 16, 512, seed );
sizes[i].height = random_in_range( 16, 512, seed );
sizes[i].depth = 1;
}
return test_images_write_common( device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes );
}
int test_images_write_cube( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
size_t i;
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
GLenum targets[] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
const size_t nsizes = 9;
size_t base_size = 16;
sizevec_t sizes[nsizes];
// Generate power-of-two 2D sizes, 16-4096:
for (i = 0; i < nsizes; i++) {
sizes[i].width = sizes[i].height = base_size;
sizes[i].depth = 1;
base_size *= 2;
}
return test_images_write_common( device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes );
}
#pragma mark -
#pragma mark _2D get info tests
int test_images_2D_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
GLenum targets[] = { GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_EXT };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
size_t sizes[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
size_t nsizes = sizeof(sizes) / sizeof(sizes[0]);
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
return test_images_get_info_common(device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes);
}
int test_images_cube_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
GLenum targets[] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
size_t sizes[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
size_t nsizes = sizeof(sizes) / sizeof(sizes[0]);
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
return test_images_get_info_common(device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes);
}

View File

@@ -0,0 +1,81 @@
//
// 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 "common.h"
#include "testBase.h"
#if defined( __APPLE__ )
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#include <CL/cl_gl.h>
#endif
int test_images_read_2Darray( cl_device_id device, cl_context context,
cl_command_queue queue, int )
{
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
size_t sizes[] = { 2, 4, 8, 16, 32, 64, 128 };
size_t nsizes = sizeof(sizes) / sizeof(sizes[0]);
GLenum targets[] = { GL_TEXTURE_2D_ARRAY };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
return test_images_read_common(device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes);
}
int test_images_write_2Darray( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
int error = 0;
size_t i;
const size_t nsizes = 6;
sizevec_t sizes[nsizes];
// FIXME: Query for 2D image array write support.
GLenum targets[] = { GL_TEXTURE_2D_ARRAY };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
RandomSeed seed( gRandomSeed );
// Generate some random sizes (within reasonable ranges)
for (i = 0; i < nsizes; i++) {
sizes[i].width = random_in_range( 16, 512, seed );
sizes[i].height = random_in_range( 16, 512, seed );
sizes[i].depth = random_in_range( 4, 24, seed );
}
return test_images_write_common( device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes );
}
int test_images_2Darray_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int )
{
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
size_t sizes[] = { 2, 4, 8, 16, 32, 64, 128 };
size_t nsizes = sizeof(sizes) / sizeof(sizes[0]);
GLenum targets[] = { GL_TEXTURE_2D_ARRAY };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
return test_images_get_info_common(device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes);
}

View File

@@ -0,0 +1,97 @@
//
// 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 "common.h"
#if defined( __APPLE__ )
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#include <CL/cl_gl.h>
#endif
extern "C" { extern cl_uint gRandomSeed; };
#pragma mark -
#pragma mark _3D read test
int test_images_read_3D( cl_device_id device, cl_context context, cl_command_queue queue, int numElements )
{
GLenum targets[] = { GL_TEXTURE_3D };
size_t ntargets = 1;
size_t sizes[] = { 2, 4, 8, 16, 32, 64, 128 };
size_t nsizes = sizeof(sizes) / sizeof(sizes[0]);
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
return test_images_read_common(device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes);
}
#pragma mark -
#pragma marm _3D write test
int test_images_write_3D( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
int error = 0;
size_t i;
const size_t nsizes = 6;
sizevec_t sizes[nsizes];
// TODO: Perhaps the expected behavior is to FAIL if 3D images are
// unsupported?
if (!is_extension_available(device, "cl_khr_3d_image_writes")) {
log_info("This device does not support 3D image writes. Skipping test.\n");
return 0;
}
GLenum targets[] = { GL_TEXTURE_3D };
size_t ntargets = sizeof(targets) / sizeof(targets[0]);
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
RandomSeed seed( gRandomSeed );
// Generate some random sizes (within reasonable ranges)
for (i = 0; i < nsizes; i++) {
sizes[i].width = random_in_range( 16, 512, seed );
sizes[i].height = random_in_range( 16, 512, seed );
sizes[i].depth = random_in_range( 4, 24, seed );
}
return test_images_write_common( device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes );
}
#pragma mark -
#pragma mark _3D get info test
int test_images_3D_getinfo( cl_device_id device, cl_context context,
cl_command_queue queue, int numElements )
{
GLenum targets[] = { GL_TEXTURE_3D };
size_t ntargets = 1;
size_t sizes[] = { 2, 4, 8, 16, 32, 64, 128 };
size_t nsizes = sizeof(sizes) / sizeof(sizes[0]);
size_t nformats = sizeof(common_formats) / sizeof(common_formats[0]);
return test_images_get_info_common(device, context, queue, common_formats,
nformats, targets, ntargets, sizes, nsizes);
}

View File

@@ -0,0 +1,215 @@
//
// 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 "common.h"
#if defined( __APPLE__ )
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#include <CL/cl_gl.h>
#endif
extern "C" { extern cl_uint gRandomSeed; };
static int test_image_info( cl_context context, cl_command_queue queue,
GLenum glTarget, GLuint glTexture, size_t imageWidth, size_t imageHeight,
size_t imageDepth, cl_image_format *outFormat, ExplicitType *outType,
void **outResultBuffer )
{
clMemWrapper streams[ 2 ];
int error;
// Create a CL image from the supplied GL texture
streams[ 0 ] = (*clCreateFromGLTexture_ptr)( context, CL_MEM_READ_ONLY,
glTarget, 0, glTexture, &error );
if( error != CL_SUCCESS )
{
print_error( error, "Unable to create CL image from GL texture" );
GLint fmt;
glGetTexLevelParameteriv( glTarget, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt );
log_error( " Supplied GL texture was format %s\n", GetGLFormatName( fmt ) );
return error;
}
// Determine data type and format that CL came up with
error = clGetImageInfo( streams[ 0 ], CL_IMAGE_FORMAT,
sizeof( cl_image_format ), outFormat, NULL );
test_error( error, "Unable to get CL image format" );
cl_gl_object_type object_type;
switch (glTarget) {
case GL_TEXTURE_1D:
object_type = CL_GL_OBJECT_TEXTURE1D;
break;
case GL_TEXTURE_BUFFER:
object_type = CL_GL_OBJECT_TEXTURE_BUFFER;
break;
case GL_TEXTURE_1D_ARRAY:
object_type = CL_GL_OBJECT_TEXTURE1D_ARRAY;
break;
case GL_TEXTURE_2D:
case GL_TEXTURE_RECTANGLE_EXT:
object_type = CL_GL_OBJECT_TEXTURE2D;
break;
case GL_TEXTURE_2D_ARRAY:
object_type = CL_GL_OBJECT_TEXTURE2D_ARRAY;
break;
case GL_TEXTURE_3D:
object_type = CL_GL_OBJECT_TEXTURE3D;
break;
default:
log_error("Unsupported texture target.");
return 1;
}
return CheckGLObjectInfo(streams[0], object_type, glTexture, glTarget, 0);
}
static int test_image_format_get_info(
cl_context context, cl_command_queue queue,
size_t width, size_t height, size_t depth,
GLenum target, struct format* fmt, MTdata data)
{
int error = 0;
size_t w = width, h = height, d = depth;
// Unpack the format and use it, along with the target, to create an
// appropriate GL texture.
GLenum gl_fmt = fmt->formattype;
GLenum gl_internal_fmt = fmt->internal;
GLenum gl_type = fmt->datatype;
ExplicitType type = fmt->type;
glTextureWrapper texture;
glBufferWrapper glbuf;
// Use the correct texture creation function depending on the target, and
// adjust width, height, depth as appropriate so subsequent size calculations
// succeed.
switch (target) {
case GL_TEXTURE_1D:
h = 1; d = 1;
CreateGLTexture1D( width, target, gl_fmt,
gl_internal_fmt, gl_type, type, &texture, &error, false, data );
break;
case GL_TEXTURE_BUFFER:
h = 1; d = 1;
CreateGLTextureBuffer( width, target, gl_fmt,
gl_internal_fmt, gl_type, type, &texture, &glbuf, &error, false, data );
break;
case GL_TEXTURE_1D_ARRAY:
d = 1;
CreateGLTexture1DArray( width, height, target, gl_fmt,
gl_internal_fmt, gl_type, type, &texture, &error, false, data );
break;
case GL_TEXTURE_RECTANGLE_EXT:
case GL_TEXTURE_2D:
d = 1;
CreateGLTexture2D( width, height, target, gl_fmt,
gl_internal_fmt, gl_type, type, &texture, &error, false, data );
break;
case GL_TEXTURE_2D_ARRAY:
CreateGLTexture2DArray( width, height, depth, target, gl_fmt,
gl_internal_fmt, gl_type, type, &texture, &error, false, data );
break;
case GL_TEXTURE_3D:
d = 1;
CreateGLTexture3D( width, height, depth, target, gl_fmt,
gl_internal_fmt, gl_type, type, &texture, &error, data, false );
break;
default:
log_error("Unsupported texture target.\n");
return 1;
}
if ( error != 0 ) {
if ((gl_fmt == GL_RGBA_INTEGER_EXT) && (!CheckGLIntegerExtensionSupport())) {
log_info("OpenGL version does not support GL_RGBA_INTEGER_EXT. "
"Skipping test.\n");
return 0;
} else {
return error;
}
}
cl_image_format clFormat;
ExplicitType actualType;
char *outBuffer;
// Perform the info check:
return test_image_info( context, queue, target, texture, w, h, d, &clFormat,
&actualType, (void **)&outBuffer );
}
int test_images_get_info_common( cl_device_id device, cl_context context,
cl_command_queue queue, struct format* formats, size_t nformats,
GLenum *targets, size_t ntargets, size_t *sizes, size_t nsizes )
{
int error = 0;
RandomSeed seed(gRandomSeed);
// First, ensure this device supports images.
if (checkForImageSupport(device)) {
log_info("Device does not support images. Skipping test.\n");
return 0;
}
size_t fidx, tidx, sidx;
// Test each format on every target, every size.
for ( fidx = 0; fidx < nformats; fidx++ ) {
for ( tidx = 0; tidx < ntargets; tidx++ ) {
log_info( "Testing image info for GL format %s : %s : %s : %s\n",
GetGLTargetName( targets[ tidx ] ),
GetGLFormatName( formats[ fidx ].internal ),
GetGLBaseFormatName( formats[ fidx ].formattype ),
GetGLTypeName( formats[ fidx ].datatype ) );
for ( sidx = 0; sidx < nsizes; sidx++ ) {
// Test this format + size:
if ( test_image_format_get_info(context, queue,
sizes[sidx], sizes[sidx], sizes[sidx],
targets[tidx], &formats[fidx], seed) )
{
// We land here in the event of test failure.
log_error( "ERROR: Image info test failed for %s : %s : %s : %s\n\n",
GetGLTargetName( targets[ tidx ] ),
GetGLFormatName( formats[ fidx ].internal ),
GetGLBaseFormatName( formats[ fidx ].formattype ),
GetGLTypeName( formats[ fidx ].datatype ) );
error++;
// Skip the other sizes for this format.
break;
}
}
}
}
return error;
}

View File

@@ -0,0 +1,452 @@
//
// 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 "common.h"
#include "testBase.h"
#if defined( __APPLE__ )
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#include <CL/cl_gl.h>
#endif
extern "C" { extern cl_uint gRandomSeed; };
static const char *kernelpattern_image_read_1d =
"__kernel void sample_test( read_only image1d_t source, sampler_t sampler, __global %s4 *results )\n"
"{\n"
" int offset = get_global_id(0);\n"
" results[ offset ] = read_image%s( source, sampler, offset );\n"
"}\n";
static const char *kernelpattern_image_read_1darray =
"__kernel void sample_test( read_only image1d_array_t source, sampler_t sampler, __global %s4 *results )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" results[ tidY * get_image_width( source ) + tidX ] = read_image%s( source, sampler, (int2)( tidX, tidY ) );\n"
"}\n";
static const char *kernelpattern_image_read_2d =
"__kernel void sample_test( read_only image2d_t source, sampler_t sampler, __global %s4 *results )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" results[ tidY * get_image_width( source ) + tidX ] = read_image%s( source, sampler, (int2)( tidX, tidY ) );\n"
"}\n";
static const char *kernelpattern_image_read_2darray =
"__kernel void sample_test( read_only image2d_array_t source, sampler_t sampler, __global %s4 *results )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" int tidZ = get_global_id(2);\n"
" int width = get_image_width( source );\n"
" int height = get_image_height( source );\n"
" int offset = tidZ * width * height + tidY * width + tidX;\n"
"\n"
" results[ offset ] = read_image%s( source, sampler, (int4)( tidX, tidY, tidZ, 0 ) );\n"
"}\n";
static const char *kernelpattern_image_read_3d =
"__kernel void sample_test( read_only image3d_t source, sampler_t sampler, __global %s4 *results )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" int tidZ = get_global_id(2);\n"
" int width = get_image_width( source );\n"
" int height = get_image_height( source );\n"
" int offset = tidZ * width * height + tidY * width + tidX;\n"
"\n"
" results[ offset ] = read_image%s( source, sampler, (int4)( tidX, tidY, tidZ, 0 ) );\n"
"}\n";
static const char* get_appropriate_kernel_for_target(GLenum target) {
switch (get_base_gl_target(target)) {
case GL_TEXTURE_1D:
case GL_TEXTURE_BUFFER:
return kernelpattern_image_read_1d;
case GL_TEXTURE_1D_ARRAY:
return kernelpattern_image_read_1darray;
case GL_TEXTURE_RECTANGLE_EXT:
case GL_TEXTURE_2D:
case GL_COLOR_ATTACHMENT0:
case GL_RENDERBUFFER:
return kernelpattern_image_read_2d;
case GL_TEXTURE_2D_ARRAY:
return kernelpattern_image_read_2darray;
case GL_TEXTURE_3D:
return kernelpattern_image_read_3d;
default:
log_error("Unsupported texture target (%s); cannot determine "
"appropriate kernel.", GetGLTargetName(target));
return NULL;
}
}
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,
cl_image_format *outFormat, ExplicitType *outType, void **outResultBuffer )
{
clProgramWrapper program;
clKernelWrapper kernel;
clMemWrapper streams[ 2 ];
int error;
char kernelSource[1024];
char *programPtr;
// Use the image created from the GL texture.
streams[ 0 ] = image;
// Determine data type and format that CL came up with
error = clGetImageInfo( streams[ 0 ], CL_IMAGE_FORMAT, sizeof( cl_image_format ), outFormat, NULL );
test_error( error, "Unable to get CL image format" );
// Create the source
*outType = get_read_kernel_type( outFormat );
size_t channelSize = get_explicit_type_size( *outType );
const char* source = get_appropriate_kernel_for_target(gl_target);
sprintf( kernelSource, source, get_explicit_type_name( *outType ),
get_kernel_suffix( outFormat ) );
programPtr = kernelSource;
if( create_single_kernel_helper( context, &program, &kernel, 1,
(const char **)&programPtr, "sample_test" ) )
{
return -1;
}
// Create a vanilla output buffer
streams[ 1 ] = clCreateBuffer( context, CL_MEM_READ_WRITE,
channelSize * 4 * width * height * depth, NULL, &error );
test_error( error, "Unable to create output buffer" );
/* Assign streams and execute */
clSamplerWrapper sampler = clCreateSampler( context, CL_FALSE, CL_ADDRESS_NONE, CL_FILTER_NEAREST, &error );
test_error( error, "Unable to create sampler" );
error = clSetKernelArg( kernel, 0, sizeof( streams[ 0 ] ), &streams[ 0 ] );
test_error( error, "Unable to set kernel arguments" );
error = clSetKernelArg( kernel, 1, sizeof( sampler ), &sampler );
test_error( error, "Unable to set kernel arguments" );
error = clSetKernelArg( kernel, 2, sizeof( streams[ 1 ] ), &streams[ 1 ] );
test_error( error, "Unable to set kernel arguments" );
glFlush();
error = (*clEnqueueAcquireGLObjects_ptr)( queue, 1, &streams[ 0 ], 0, NULL, NULL);
test_error( error, "Unable to acquire GL obejcts");
// The ND range we use is a function of the dimensionality of the image.
size_t global_range[3] = { width, height, depth };
size_t *local_range = NULL;
int ndim = 1;
switch (get_base_gl_target(gl_target)) {
case GL_TEXTURE_1D:
case GL_TEXTURE_BUFFER:
ndim = 1;
break;
case GL_TEXTURE_RECTANGLE_EXT:
case GL_TEXTURE_2D:
case GL_TEXTURE_1D_ARRAY:
case GL_COLOR_ATTACHMENT0:
case GL_RENDERBUFFER:
ndim = 2;
break;
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
ndim = 3;
break;
default:
log_error("Unsupported texture target.");
return 1;
}
// 2D and 3D images have a special way to set the local size (legacy).
// Otherwise, we let CL select by leaving local_range as NULL.
if (gl_target == GL_TEXTURE_2D) {
local_range = (size_t*)malloc(sizeof(size_t) * ndim);
get_max_common_2D_work_group_size( context, kernel, global_range, local_range );
} else if (gl_target == GL_TEXTURE_3D) {
local_range = (size_t*)malloc(sizeof(size_t) * ndim);
get_max_common_3D_work_group_size( context, kernel, global_range, local_range );
}
error = clEnqueueNDRangeKernel( queue, kernel, ndim, NULL, global_range,
local_range, 0, NULL, NULL );
test_error( error, "Unable to execute test kernel" );
error = (*clEnqueueReleaseGLObjects_ptr)( queue, 1, &streams[ 0 ],
0, NULL, NULL );
test_error(error, "clEnqueueReleaseGLObjects failed");
// Read results from the CL buffer
*outResultBuffer = (void *)( new char[ channelSize * 4 * width * height * depth ] );
error = clEnqueueReadBuffer( queue, streams[ 1 ], CL_TRUE, 0,
channelSize * 4 * width * height * depth, *outResultBuffer, 0, NULL, NULL );
test_error( error, "Unable to read output CL buffer!" );
// free the ranges
if (local_range) free(local_range);
return 0;
}
static int test_image_read( cl_context context, cl_command_queue queue,
GLenum target, GLuint globj, size_t width, size_t height, size_t depth,
cl_image_format *outFormat, ExplicitType *outType, void **outResultBuffer )
{
int error;
// Create a CL image from the supplied GL texture or renderbuffer.
cl_mem image;
if (target == GL_RENDERBUFFER || target == GL_COLOR_ATTACHMENT0) {
image = (*clCreateFromGLRenderbuffer_ptr)( context, CL_MEM_READ_ONLY, globj, &error );
} else {
image = (*clCreateFromGLTexture_ptr)( context, CL_MEM_READ_ONLY,
target, 0, globj, &error );
}
if( error != CL_SUCCESS ) {
if (target == GL_RENDERBUFFER || target == GL_COLOR_ATTACHMENT0) {
print_error( error, "Unable to create CL image from GL renderbuffer" );
} else {
print_error( error, "Unable to create CL image from GL texture" );
GLint fmt;
glGetTexLevelParameteriv( target, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt );
log_error( " Supplied GL texture was base format %s and internal "
"format %s\n", GetGLBaseFormatName( fmt ), GetGLFormatName( fmt ) );
}
return error;
}
return test_cl_image_read( context, queue, target, image,
width, height, depth, outFormat, outType, outResultBuffer );
}
static int test_image_format_read(
cl_context context, cl_command_queue queue,
size_t width, size_t height, size_t depth,
GLenum target, struct format* fmt, MTdata data)
{
int error = 0;
// If we're testing a half float format, then we need to determine the
// rounding mode of this machine. Punt if we fail to do so.
if( fmt->type == kHalf )
if( DetectFloatToHalfRoundingMode(queue) )
return 1;
size_t w = width, h = height, d = depth;
// Unpack the format and use it, along with the target, to create an
// appropriate GL texture.
GLenum gl_fmt = fmt->formattype;
GLenum gl_internal_fmt = fmt->internal;
GLenum gl_type = fmt->datatype;
ExplicitType type = fmt->type;
// Required for most of the texture-backed cases:
glTextureWrapper texture;
// Required for the special case of TextureBuffer textures:
glBufferWrapper glbuf;
// And these are required for the case of Renderbuffer images:
glFramebufferWrapper glFramebuffer;
glRenderbufferWrapper glRenderbuffer;
void* buffer = NULL;
// Use the correct texture creation function depending on the target, and
// adjust width, height, depth as appropriate so subsequent size calculations
// succeed.
switch (get_base_gl_target(target)) {
case GL_TEXTURE_1D:
h = 1; d = 1;
buffer = CreateGLTexture1D( width, target, gl_fmt,
gl_internal_fmt, gl_type, type, &texture, &error, true, data );
break;
case GL_TEXTURE_BUFFER:
h = 1; d = 1;
buffer = CreateGLTextureBuffer(width, target, gl_fmt, gl_internal_fmt,
gl_type, type, &texture, &glbuf, &error, true, data);
break;
case GL_RENDERBUFFER:
case GL_COLOR_ATTACHMENT0:
buffer = CreateGLRenderbuffer(width, height, target, gl_fmt,
gl_internal_fmt, gl_type, type, &glFramebuffer, &glRenderbuffer, &error,
data, true);
break;
case GL_TEXTURE_2D:
case GL_TEXTURE_RECTANGLE_EXT:
d = 1;
buffer = CreateGLTexture2D(width, height, target, gl_fmt, gl_internal_fmt,
gl_type, type, &texture, &error, true, data);
break;
case GL_TEXTURE_1D_ARRAY:
d = 1;
buffer = CreateGLTexture1DArray( width, height, target, gl_fmt,
gl_internal_fmt, gl_type, type, &texture, &error, true, data );
break;
case GL_TEXTURE_2D_ARRAY:
buffer = CreateGLTexture2DArray( width, height, depth, target, gl_fmt,
gl_internal_fmt, gl_type, type, &texture, &error, true, data );
break;
case GL_TEXTURE_3D:
buffer = CreateGLTexture3D( width, height, depth, target, gl_fmt,
gl_internal_fmt, gl_type, type, &texture, &error, data, true );
break;
default:
log_error("Unsupported texture target.");
return 1;
}
if ( error != 0 ) {
if ((gl_fmt == GL_RGBA_INTEGER_EXT) && (!CheckGLIntegerExtensionSupport())){
log_info("OpenGL version does not support GL_RGBA_INTEGER_EXT. "
"Skipping test.\n");
return 0;
} else {
return error;
}
}
BufferOwningPtr<char> inputBuffer(buffer);
cl_image_format clFormat;
ExplicitType actualType;
char *outBuffer;
// Perform the read:
GLuint globj = texture;
if (target == GL_RENDERBUFFER || target == GL_COLOR_ATTACHMENT0) {
globj = glRenderbuffer;
}
error = test_image_read( context, queue, target, globj, w, h, d, &clFormat,
&actualType, (void **)&outBuffer );
if( error != 0 )
return error;
BufferOwningPtr<char> actualResults(outBuffer);
log_info( "- Read [%4d x %4d x %4d] : GL Texture : %s : %s : %s => CL Image : %s : %s \n",
(int)w, (int)h, (int)d, GetGLFormatName( gl_fmt ), GetGLFormatName( gl_internal_fmt ),
GetGLTypeName( gl_type ), GetChannelOrderName( clFormat.image_channel_order ),
GetChannelTypeName( clFormat.image_channel_data_type ));
// We have to convert our input buffer to the returned type, so we can validate.
// This is necessary because OpenCL might not actually pick an internal format
// that actually matches our input format (for example, if it picks a normalized
// format, the results will come out as floats instead of going in as ints).
BufferOwningPtr<char> convertedInputs(convert_to_expected( inputBuffer,
w * h * d, type, actualType ));
if( convertedInputs == NULL )
return -1;
// Now we validate
if( actualType == kFloat ) {
return validate_float_results( convertedInputs, actualResults, w, h, d );
} else {
return validate_integer_results( convertedInputs, actualResults, w, h, d,
get_explicit_type_size( actualType ) );
}
}
int test_images_read_common( cl_device_id device, cl_context context,
cl_command_queue queue, struct format* formats, size_t nformats,
GLenum *targets, size_t ntargets, size_t *sizes, size_t nsizes )
{
int error = 0;
RandomSeed seed(gRandomSeed);
// First, ensure this device supports images.
if (checkForImageSupport(device)) {
log_info("Device does not support images. Skipping test.\n");
return 0;
}
size_t fidx, tidx, sidx;
// Test each format on every target, every size.
for ( fidx = 0; fidx < nformats; fidx++ ) {
for ( tidx = 0; tidx < ntargets; tidx++ ) {
log_info( "Testing image read for GL format %s : %s : %s : %s\n",
GetGLTargetName( targets[ tidx ] ),
GetGLFormatName( formats[ fidx ].internal ),
GetGLBaseFormatName( formats[ fidx ].formattype ),
GetGLTypeName( formats[ fidx ].datatype ) );
for ( sidx = 0; sidx < nsizes; sidx++ ) {
// Test this format + size:
if ( test_image_format_read(context, queue,
sizes[sidx], sizes[sidx], sizes[sidx],
targets[tidx], &formats[fidx], seed) )
{
// We land here in the event of test failure.
log_error( "ERROR: Image read test failed for %s : %s : %s : %s\n\n",
GetGLTargetName( targets[ tidx ] ),
GetGLFormatName( formats[ fidx ].internal ),
GetGLBaseFormatName( formats[ fidx ].formattype ),
GetGLTypeName( formats[ fidx ].datatype ) );
error++;
// Skip the other sizes for this format.
break;
}
}
// Note a successful format test, if we passed every size.
if( sidx == sizeof (sizes) / sizeof( sizes[0] ) ) {
log_info( "passed: Image read test for GL format %s : %s : %s : %s\n\n",
GetGLTargetName( targets[ tidx ] ),
GetGLFormatName( formats[ fidx ].internal ),
GetGLBaseFormatName( formats[ fidx ].formattype ),
GetGLTypeName( formats[ fidx ].datatype ) );
}
}
}
return error;
}

View File

@@ -0,0 +1,598 @@
//
// 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 "common.h"
#include <limits.h>
#if defined( __APPLE__ )
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#include <CL/cl_gl.h>
#endif
extern "C" { extern cl_uint gRandomSeed; };
#pragma mark -
#pragma mark Write test kernels
static const char *kernelpattern_image_write_1D =
"__kernel void sample_test( __global %s4 *source, write_only image1d_t dest )\n"
"{\n"
" uint index = get_global_id(0);\n"
" %s4 value = source[index];\n"
" write_image%s( dest, index, %s(value));\n"
"}\n";
static const char *kernelpattern_image_write_1D_half =
"__kernel void sample_test( __global half4 *source, write_only image1d_t dest )\n"
"{\n"
" uint index = get_global_id(0);\n"
" write_imagef( dest, index, vload_half4(index, (half *)source));\n"
"}\n";
static const char *kernelpattern_image_write_2D =
"__kernel void sample_test( __global %s4 *source, write_only image2d_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" uint index = tidY * get_image_width( dest ) + tidX;\n"
" %s4 value = source[index];\n"
" write_image%s( dest, (int2)( tidX, tidY ), %s(value));\n"
"}\n";
static const char *kernelpattern_image_write_2D_half =
"__kernel void sample_test( __global half4 *source, write_only image2d_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" uint index = tidY * get_image_width( dest ) + tidX;\n"
" write_imagef( dest, (int2)( tidX, tidY ), vload_half4(index, (half *)source));\n"
"}\n";
static const char *kernelpattern_image_write_1Darray =
"__kernel void sample_test( __global %s4 *source, write_only image1d_array_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" uint index = tidY * get_image_width( dest ) + tidX;\n"
" %s4 value = source[index];\n"
" write_image%s( dest, (int2)( tidX, tidY ), %s(value));\n"
"}\n";
static const char *kernelpattern_image_write_1Darray_half =
"__kernel void sample_test( __global half4 *source, write_only image1d_array_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" uint index = tidY * get_image_width( dest ) + tidX;\n"
" write_imagef( dest, (int2)( tidX, tidY ), vload_half4(index, (half *)source));\n"
"}\n";
static const char *kernelpattern_image_write_3D =
"__kernel void sample_test( __global %s4 *source, write_only image3d_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" int tidZ = get_global_id(2);\n"
" int width = get_image_width( dest );\n"
" int height = get_image_height( dest );\n"
" int index = tidZ * width * height + tidY * width + tidX;\n"
" %s4 value = source[index];\n"
" write_image%s( dest, (int4)( tidX, tidY, tidZ, 0 ), %s(value));\n"
"}\n";
static const char *kernelpattern_image_write_3D_half =
"__kernel void sample_test( __global half4 *source, write_only image3d_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" int tidZ = get_global_id(2);\n"
" int width = get_image_width( dest );\n"
" int height = get_image_height( dest );\n"
" int index = tidZ * width * height + tidY * width + tidX;\n"
" write_imagef( dest, (int4)( tidX, tidY, tidZ, 0 ), vload_half4(index, (half *)source));\n"
"}\n";
static const char *kernelpattern_image_write_2Darray =
"__kernel void sample_test( __global %s4 *source, write_only image2d_array_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" int tidZ = get_global_id(2);\n"
" int width = get_image_width( dest );\n"
" int height = get_image_height( dest );\n"
" int index = tidZ * width * height + tidY * width + tidX;\n"
" %s4 value = source[index];\n"
" write_image%s( dest, (int4)( tidX, tidY, tidZ, 0 ), %s(value));\n"
"}\n";
static const char *kernelpattern_image_write_2Darray_half =
"__kernel void sample_test( __global half4 *source, write_only image2d_array_t dest )\n"
"{\n"
" int tidX = get_global_id(0);\n"
" int tidY = get_global_id(1);\n"
" int tidZ = get_global_id(2);\n"
" int width = get_image_width( dest );\n"
" int height = get_image_height( dest );\n"
" int index = tidZ * width * height + tidY * width + tidX;\n"
" write_imagef( dest, (int4)( tidX, tidY, tidZ, 0 ), vload_half4(index, (half *)source));\n"
"}\n";
#pragma mark -
#pragma mark Utility functions
static const char* get_appropriate_write_kernel(GLenum target,
ExplicitType type)
{
switch (get_base_gl_target(target)) {
case GL_TEXTURE_1D:
case GL_TEXTURE_BUFFER:
if (type == kHalf)
return kernelpattern_image_write_1D_half;
else
return kernelpattern_image_write_1D;
break;
case GL_TEXTURE_1D_ARRAY:
if (type == kHalf)
return kernelpattern_image_write_1Darray_half;
else
return kernelpattern_image_write_1Darray;
break;
case GL_COLOR_ATTACHMENT0:
case GL_RENDERBUFFER:
case GL_TEXTURE_RECTANGLE_EXT:
case GL_TEXTURE_2D:
if (type == kHalf)
return kernelpattern_image_write_2D_half;
else
return kernelpattern_image_write_2D;
break;
case GL_TEXTURE_2D_ARRAY:
if (type == kHalf)
return kernelpattern_image_write_2Darray_half;
else
return kernelpattern_image_write_2Darray;
break;
case GL_TEXTURE_3D:
if (type == kHalf)
return kernelpattern_image_write_3D_half;
else
return kernelpattern_image_write_3D;
break;
default:
log_error("Unsupported GL tex target (%s) passed to write test: "
"%s (%s):%d", GetGLTargetName(target), __FUNCTION__,
__FILE__, __LINE__);
return NULL;
}
}
void set_dimensions_by_target(GLenum target, size_t *dims, size_t sizes[3],
size_t width, size_t height, size_t depth)
{
switch (get_base_gl_target(target)) {
case GL_TEXTURE_1D:
sizes[0] = width;
*dims = 1;
break;
case GL_TEXTURE_BUFFER:
sizes[0] = width;
*dims = 1;
break;
case GL_TEXTURE_1D_ARRAY:
sizes[0] = width;
sizes[1] = height;
*dims = 2;
break;
case GL_COLOR_ATTACHMENT0:
case GL_RENDERBUFFER:
case GL_TEXTURE_RECTANGLE_EXT:
case GL_TEXTURE_2D:
sizes[0] = width;
sizes[1] = height;
*dims = 2;
break;
case GL_TEXTURE_2D_ARRAY:
sizes[0] = width;
sizes[1] = height;
sizes[2] = depth;
*dims = 3;
break;
case GL_TEXTURE_3D:
sizes[0] = width;
sizes[1] = height;
sizes[2] = depth;
*dims = 3;
break;
default:
log_error("Unsupported GL tex target (%s) passed to write test: "
"%s (%s):%d", GetGLTargetName(target), __FUNCTION__,
__FILE__, __LINE__);
}
}
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 )
{
size_t global_dims, global_sizes[3];
clProgramWrapper program;
clKernelWrapper kernel;
clMemWrapper inStream;
char* programPtr;
int error;
char kernelSource[2048];
// What CL format did we get from the texture?
error = clGetImageInfo(clImage, CL_IMAGE_FORMAT, sizeof(cl_image_format),
outFormat, NULL);
test_error(error, "Unable to get the CL image format");
// Create the kernel source. The target and the data type will influence
// which particular kernel we choose.
*outType = get_write_kernel_type( outFormat );
size_t channelSize = get_explicit_type_size(*outType);
const char* appropriateKernel = get_appropriate_write_kernel(target,
*outType);
if (*outType == kHalf && !supports_half) {
log_info("cl_khr_fp16 isn't supported. Skip this test.\n");
return 0;
}
const char* suffix = get_kernel_suffix( outFormat );
const char* convert = get_write_conversion( outFormat, *outType );
sprintf(kernelSource, appropriateKernel, get_explicit_type_name( *outType ),
get_explicit_type_name( *outType ), suffix, convert);
programPtr = kernelSource;
if( create_single_kernel_helper( context, &program, &kernel, 1,
(const char **)&programPtr, "sample_test" ) )
{
return -1;
}
// Create an appropriately-sized output buffer.
*outSourceBuffer = CreateRandomData(*outType, width*height*depth*4, d);
inStream = clCreateBuffer( context, CL_MEM_COPY_HOST_PTR,
channelSize * 4 * width * height * depth, *outSourceBuffer, &error );
test_error( error, "Unable to create output buffer" );
clSamplerWrapper sampler = clCreateSampler( context, CL_FALSE,
CL_ADDRESS_NONE, CL_FILTER_NEAREST, &error );
test_error( error, "Unable to create sampler" );
error = clSetKernelArg( kernel, 0, sizeof( inStream ), &inStream );
test_error( error, "Unable to set kernel arguments" );
error = clSetKernelArg( kernel, 1, sizeof( clImage ), &clImage );
test_error( error, "Unable to set kernel arguments" );
// Flush and Acquire.
glFlush();
error = (*clEnqueueAcquireGLObjects_ptr)( queue, 1, &clImage, 0, NULL, NULL);
test_error( error, "Unable to acquire GL obejcts");
// Execute ( letting OpenCL choose the local size )
// Setup the global dimensions and sizes based on the target type.
set_dimensions_by_target(target, &global_dims, global_sizes,
width, height, depth);
error = clEnqueueNDRangeKernel( queue, kernel, global_dims, NULL,
global_sizes, NULL, 0, NULL, NULL );
test_error( error, "Unable to execute test kernel" );
clEventWrapper event;
error = (*clEnqueueReleaseGLObjects_ptr)( queue, 1, &clImage, 0, NULL, &event );
test_error(error, "clEnqueueReleaseGLObjects failed");
error = clWaitForEvents( 1, &event );
test_error(error, "clWaitForEvents failed");
return 0;
}
static int test_image_write( cl_context context, cl_command_queue queue,
GLenum glTarget, GLuint glTexture, size_t width, size_t height, size_t depth,
cl_image_format *outFormat, ExplicitType *outType, void **outSourceBuffer,
MTdata d, bool supports_half )
{
int error;
// Create a CL image from the supplied GL texture
clMemWrapper image = (*clCreateFromGLTexture_ptr)( context, CL_MEM_WRITE_ONLY,
glTarget, 0, glTexture, &error );
if ( error != CL_SUCCESS ) {
print_error( error, "Unable to create CL image from GL texture" );
GLint fmt;
glGetTexLevelParameteriv( glTarget, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt );
log_error( " Supplied GL texture was base format %s and internal "
"format %s\n", GetGLBaseFormatName( fmt ), GetGLFormatName( fmt ) );
return error;
}
return test_cl_image_write( context, queue, glTarget, image,
width, height, depth, outFormat, outType, outSourceBuffer, d, supports_half );
}
int supportsHalf(cl_context context, bool* supports_half)
{
int error;
size_t size;
cl_uint numDev;
error = clGetContextInfo(context, CL_CONTEXT_NUM_DEVICES, sizeof(cl_uint), &numDev, NULL);
test_error(error, "clGetContextInfo for CL_CONTEXT_NUM_DEVICES failed");
cl_device_id* devices = new cl_device_id[numDev];
error = clGetContextInfo(context, CL_CONTEXT_DEVICES, numDev * sizeof(cl_device_id), devices, NULL);
test_error(error, "clGetContextInfo for CL_CONTEXT_DEVICES failed");
// Get the extensions string for the device
error = clGetDeviceInfo(devices[0], CL_DEVICE_EXTENSIONS, 0, NULL, &size);
test_error(error, "clGetDeviceInfo for CL_DEVICE_EXTENSIONS size failed");
char *extensions = new char[size+1];
if (extensions == 0) {
log_error("Failed to allocate memory for extensions string.\n");
return -1;
}
memset( extensions, CHAR_MIN, sizeof(char)*(size+1) );
error = clGetDeviceInfo(devices[0], CL_DEVICE_EXTENSIONS, sizeof(char)*size, extensions, NULL);
test_error(error, "clGetDeviceInfo for CL_DEVICE_EXTENSIONS failed");
*supports_half = strstr(extensions, "cl_khr_fp16");
delete [] extensions;
delete [] devices;
return error;
}
static int test_image_format_write( cl_context context, cl_command_queue queue,
size_t width, size_t height, size_t depth, GLenum target, GLenum format,
GLenum internalFormat, GLenum glType, ExplicitType type, MTdata d )
{
int error;
// If we're testing a half float format, then we need to determine the
// rounding mode of this machine. Punt if we fail to do so.
if( type == kHalf )
if( DetectFloatToHalfRoundingMode(queue) )
return 1;
// Create an appropriate GL texture or renderbuffer, given the target.
glTextureWrapper glTexture;
glBufferWrapper glBuf;
glFramebufferWrapper glFramebuffer;
glRenderbufferWrapper glRenderbuffer;
switch (get_base_gl_target(target)) {
case GL_TEXTURE_1D:
CreateGLTexture1D( width, target, format, internalFormat, glType,
type, &glTexture, &error, false, d );
break;
case GL_TEXTURE_BUFFER:
CreateGLTextureBuffer( width, target, format, internalFormat, glType,
type, &glTexture, &glBuf, &error, false, d );
break;
case GL_TEXTURE_1D_ARRAY:
CreateGLTexture1DArray( width, height, target, format, internalFormat,
glType, type, &glTexture, &error, false, d );
break;
case GL_TEXTURE_RECTANGLE_EXT:
case GL_TEXTURE_2D:
CreateGLTexture2D( width, height, target, format, internalFormat, glType,
type, &glTexture, &error, false, d );
break;
case GL_COLOR_ATTACHMENT0:
case GL_RENDERBUFFER:
CreateGLRenderbuffer(width, height, target, format, internalFormat,
glType, type, &glFramebuffer, &glRenderbuffer, &error, d, false);
case GL_TEXTURE_2D_ARRAY:
CreateGLTexture2DArray( width, height, depth, target, format,
internalFormat, glType, type, &glTexture, &error, false, d );
break;
case GL_TEXTURE_3D:
CreateGLTexture3D( width, height, depth, target, format,
internalFormat, glType, type, &glTexture, &error, d, false );
break;
default:
log_error("Unsupported GL tex target (%s) passed to write test: "
"%s (%s):%d", GetGLTargetName(target), __FUNCTION__,
__FILE__, __LINE__);
}
// If there was a problem during creation, make sure it isn't a known
// cause, and then complain.
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;
GLenum globj = glTexture;
if (target == GL_RENDERBUFFER || target == GL_COLOR_ATTACHMENT0) {
globj = glRenderbuffer;
}
bool supports_half = false;
error = supportsHalf(context, &supports_half);
if( error != 0 )
return error;
error = test_image_write( context, queue, target, globj, width, height,
depth, &clFormat, &sourceType, (void **)&outSourceBuffer, d, 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<char> validationSource( convert_to_expected( outSourceBuffer,
width * height * depth, sourceType, validationType ) );
log_info( "- Write for %s [%4ld x %4ld x %4ld] : GL Texture : %s : %s : %s =>"
" CL Image : %s : %s \n",
GetGLTargetName(target),
width, height, depth,
GetGLFormatName( format ),
GetGLFormatName( internalFormat ),
GetGLTypeName( glType),
GetChannelOrderName( clFormat.image_channel_order ),
GetChannelTypeName( clFormat.image_channel_data_type ));
// Read the results from the GL texture.
ExplicitType readType = type;
BufferOwningPtr<char> glResults( ReadGLTexture(
target, glTexture, glBuf, width, format,
internalFormat, glType, readType, /* unused */ 1, 1 ) );
// We have to convert our input buffer to the returned type, so we can validate.
BufferOwningPtr<char> convertedGLResults( convert_to_expected(
glResults, width * height * depth, readType, validationType ) );
// Validate.
int valid = 0;
if (convertedGLResults) {
if( sourceType == kFloat || sourceType == kHalf )
valid = validate_float_results( validationSource, convertedGLResults,
width, height, depth );
else
valid = validate_integer_results( validationSource, convertedGLResults,
width, height, depth, get_explicit_type_size( readType ) );
}
return valid;
}
#pragma mark -
#pragma mark Write test common entry point
// This is the main loop for all of the write tests. It iterates over the
// given formats & targets, testing a variety of sizes against each
// combination.
int test_images_write_common(cl_device_id device, cl_context context,
cl_command_queue queue, struct format* formats, size_t nformats,
GLenum *targets, size_t ntargets, sizevec_t* sizes, size_t nsizes )
{
int error = 0;
RandomSeed seed(gRandomSeed);
// First, ensure this device supports images.
if (checkForImageSupport(device)) {
log_info("Device does not support images. Skipping test.\n");
return 0;
}
size_t fidx, tidx, sidx;
for ( fidx = 0; fidx < nformats; fidx++ ) {
for ( tidx = 0; tidx < ntargets; tidx++ ) {
log_info( "Testing image write test for %s : %s : %s : %s\n",
GetGLTargetName( targets[ tidx ] ),
GetGLFormatName( formats[ fidx ].internal ),
GetGLBaseFormatName( formats[ fidx ].formattype ),
GetGLTypeName( formats[ fidx ].datatype ) );
for (sidx = 0; sidx < nsizes; sidx++) {
if( test_image_format_write( context, queue,
sizes[sidx].width,
sizes[sidx].height,
sizes[sidx].depth,
targets[ tidx ],
formats[ fidx ].formattype,
formats[ fidx ].internal,
formats[ fidx ].datatype,
formats[ fidx ].type, seed ) )
{
log_error( "ERROR: Image write test failed for %s : %s : %s : %s "
" and size (%ld,%ld,%ld)\n\n",
GetGLTargetName( targets[ tidx ] ),
GetGLFormatName( formats[ fidx ].internal ),
GetGLBaseFormatName( formats[ fidx ].formattype ),
GetGLTypeName( formats[ fidx ].datatype ),
sizes[sidx].width,
sizes[sidx].height,
sizes[sidx].depth);
error++;
break; // Skip other sizes for this combination
}
}
// If we passed all sizes (check versus size loop count):
if (sidx == nsizes) {
log_info( "passed: Image write for GL format %s : %s : %s : %s\n\n",
GetGLTargetName( targets[ tidx ] ),
GetGLFormatName( formats[ fidx ].internal ),
GetGLBaseFormatName( formats[ fidx ].formattype ),
GetGLTypeName( formats[ fidx ].datatype ) );
}
}
}
return error;
}

View File

@@ -0,0 +1,479 @@
//
// 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
extern "C" { extern cl_uint gRandomSeed; };
// 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 imageWidth, size_t imageHeight,
size_t imageDepth, 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,
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, 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 ));
#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 );
else
valid = validate_integer_results( convertedInput, actualResults, width, height, 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<char> validationSource( convert_to_expected( outSourceBuffer, width * height, sourceType, validationType ) );
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 ) );
#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 );
else
valid = validate_integer_results( validationSource, convertedData, width, height, 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;
}

View File

@@ -0,0 +1,133 @@
//
// 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
extern "C" {extern cl_uint gRandomSeed;};
static int test_renderbuffer_object_info( 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 render buffer
glFramebufferWrapper glFramebuffer;
glRenderbufferWrapper glRenderbuffer;
BufferOwningPtr<char> inputBuffer(CreateGLRenderbuffer( width, height, attachment, format, internalFormat, glType, type, &glFramebuffer, &glRenderbuffer, &error, d, true ));
if( error != 0 )
return error;
clMemWrapper image = (*clCreateFromGLRenderbuffer_ptr)(context, CL_MEM_READ_ONLY, glRenderbuffer, &error);
test_error(error, "clCreateFromGLRenderbuffer failed");
log_info( "- Given a GL format of %s, input type was %s, size was %d x %d\n",
GetGLFormatName( internalFormat ),
get_explicit_type_name( type ), (int)width, (int)height );
// Verify the expected information here.
return CheckGLObjectInfo(image, CL_GL_OBJECT_RENDERBUFFER, (GLuint)glRenderbuffer, internalFormat, 0);
}
int test_renderbuffer_getinfo( 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_RGBA, GL_UNSIGNED_BYTE, kUChar },
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, kUChar },
{ GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, kUShort },
{ GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT, kFloat },
{ GL_RGBA16F_ARB, GL_RGBA, GL_HALF_FLOAT, kHalf }
};
size_t fmtIdx, tgtIdx;
int error = 0;
size_t iter = 6;
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( tgtIdx = 0; tgtIdx < sizeof( attachments ) / sizeof( attachments[ 0 ] ); tgtIdx++ )
{
log_info( "Testing Renderbuffer object info for %s : %s : %s\n",
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 );
if( test_renderbuffer_object_info( context, queue, (int)width, (int)height,
attachments[ tgtIdx ],
formats[ fmtIdx ].format,
formats[ fmtIdx ].internal,
formats[ fmtIdx ].datatype,
formats[ fmtIdx ].type, seed ) )
{
log_error( "ERROR: Renderbuffer write test failed for GL format %s : %s\n\n",
GetGLFormatName( formats[ fmtIdx ].internal ),
GetGLTypeName( formats[ fmtIdx ].datatype ) );
error++;
break; // Skip other sizes for this combination
}
}
if( i == iter )
{
log_info( "passed: Renderbuffer write test passed for GL format %s : %s\n\n",
GetGLFormatName( formats[ fmtIdx ].internal ),
GetGLTypeName( formats[ fmtIdx ].datatype ) );
}
}
}
return error;
}