summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2008-02-21 13:52:09 -0800
committerEric Anholt <eric@anholt.net>2008-02-21 15:13:13 -0800
commit1a63befcc01d19ff203ff3fd434037ba618bed83 (patch)
tree5dc104260c3415d14a9d5fecade8e5055c4820ef
parent22fbbb5e8679ddf91532cb10eaa31be533383b48 (diff)
Update glean tests to CVS HEAD from 2008-02-21.
-rw-r--r--tests/all.tests5
-rw-r--r--tests/glean/CMakeLists.txt5
-rw-r--r--tests/glean/environ.cpp16
-rw-r--r--tests/glean/glutils.cpp10
-rw-r--r--tests/glean/glutils.h3
-rw-r--r--tests/glean/main.cpp24
-rw-r--r--tests/glean/options.cpp11
-rw-r--r--tests/glean/options.h15
-rw-r--r--tests/glean/tapi2.cpp1019
-rw-r--r--tests/glean/tapi2.h87
-rw-r--r--tests/glean/tbase.h46
-rw-r--r--tests/glean/tblend.cpp813
-rw-r--r--tests/glean/tblend.h51
-rw-r--r--tests/glean/tdepthstencil.cpp9
-rw-r--r--tests/glean/tdepthstencil.h2
-rw-r--r--tests/glean/test.h16
-rw-r--r--tests/glean/tfragprog1.cpp214
-rw-r--r--tests/glean/tfragprog1.h27
-rw-r--r--tests/glean/tglsl1.cpp3396
-rw-r--r--tests/glean/tglsl1.h90
-rw-r--r--tests/glean/tmultitest.cpp18
-rw-r--r--tests/glean/toccluqry.cpp675
-rw-r--r--tests/glean/toccluqry.h72
-rw-r--r--tests/glean/tpbo.cpp1240
-rw-r--r--tests/glean/tpbo.h86
-rw-r--r--tests/glean/tpointatten.cpp38
-rw-r--r--tests/glean/tpointatten.h6
-rw-r--r--tests/glean/tpointsprite.cpp428
-rw-r--r--tests/glean/tpointsprite.h70
-rw-r--r--tests/glean/treadpix.cpp120
-rw-r--r--tests/glean/treadpix.h48
-rw-r--r--tests/glean/treadpixperf.cpp4
-rw-r--r--tests/glean/ttexrect.cpp6
-rw-r--r--tests/glean/tvertprog1.h4
34 files changed, 8097 insertions, 577 deletions
diff --git a/tests/all.tests b/tests/all.tests
index 931ec3665..917631b6f 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -34,14 +34,17 @@ for line in out.split('\n'):
# Collecting all tests
glean = Group()
glean['basic'] = GleanTest('basic')
+glean['api2'] = GleanTest('api2')
glean['makeCurrent'] = GleanTest('makeCurrent')
glean['blendFunc'] = GleanTest('blendFunc')
glean['depthStencil'] = GleanTest('depthStencil')
glean['fpexceptions'] = GleanTest('fpexceptions')
glean['fragProg1'] = GleanTest('fragProg1') # also add entire tests, because of interdependency bugs that only occur when several different FPs are used
glean['getString'] = GleanTest('getString')
+glean['glsl1'] = GleanTest('glsl1')
glean['logicOp'] = GleanTest('logicOp')
glean['maskedClear'] = GleanTest('maskedClear')
+glean['occluquery'] = GleanTest('occluquery')
glean['orthoPosRandTris'] = GleanTest('orthoPosRandTris')
glean['orthoPosRandRects'] = GleanTest('orthoPosRandRects')
glean['orthoPosTinyQuads'] = GleanTest('orthoPosTinyQuads')
@@ -49,9 +52,11 @@ glean['orthoPosHLines'] = GleanTest('orthoPosHLines')
glean['orthoPosVLines'] = GleanTest('orthoPosVLines')
glean['orthoPosPoints'] = GleanTest('orthoPosPoints')
glean['paths'] = GleanTest('paths')
+glean['pbo'] = GleanTest('pbo')
glean['polygonOffset'] = GleanTest('polygonOffset')
glean['pixelFormats'] = GleanTest('pixelFormats')
glean['pointAtten'] = GleanTest('pointAtten')
+glean['pointSprite'] = GleanTest('pointSprite')
glean['exactRGBA'] = GleanTest('exactRGBA')
glean['readPixSanity'] = GleanTest('readPixSanity')
glean['rgbTriStrip'] = GleanTest('rgbTriStrip')
diff --git a/tests/glean/CMakeLists.txt b/tests/glean/CMakeLists.txt
index 9156f1a8d..6bf3f671c 100644
--- a/tests/glean/CMakeLists.txt
+++ b/tests/glean/CMakeLists.txt
@@ -16,6 +16,7 @@ add_executable (glean
misc.cpp
options.cpp
rc.cpp
+ tapi2.cpp
tbasic.cpp
tbasicperf.cpp
tbinding.cpp
@@ -26,14 +27,18 @@ add_executable (glean
tfpexceptions.cpp
tfragprog1.cpp
tgetstr.cpp
+ tglsl1.cpp
tlogicop.cpp
tmaskedclear.cpp
tmultitest.cpp
+ toccluqry.cpp
torthpos.cpp
tpaths.cpp
+ tpbo.cpp
tpgos.cpp
tpixelformats.cpp
tpointatten.cpp
+ tpointsprite.cpp
treadpix.cpp
treadpixperf.cpp
trgbtris.cpp
diff --git a/tests/glean/environ.cpp b/tests/glean/environ.cpp
index d1447cd0a..39d8815c6 100644
--- a/tests/glean/environ.cpp
+++ b/tests/glean/environ.cpp
@@ -1,7 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
-//
+//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -10,11 +10,11 @@
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the
// Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
@@ -23,7 +23,7 @@
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-//
+//
// END_COPYRIGHT
@@ -75,7 +75,7 @@ Environment::Environment(Options& opt):
}
// If comparing previous runs, make a token attempt to verify
// that the two databases exist.
- } else if (opt.mode == Options::compare) {
+ } else {
struct stat s;
if (stat(opt.db1Name.c_str(), &s) || !S_ISDIR(s.st_mode))
throw DBCantOpen(opt.db1Name);
@@ -99,8 +99,8 @@ Environment::Environment(Options& opt):
}
// If comparing previous runs, make a token attempt to verify
// that the two databases exist.
- } else if (opt.mode == Options::compare) {
- struct _stat s;
+ } else {
+ struct _stat s;
if (_stat(opt.db1Name.c_str(), &s) || !(s.st_mode & _S_IFDIR))
throw DBCantOpen(opt.db1Name);
diff --git a/tests/glean/glutils.cpp b/tests/glean/glutils.cpp
index 342bd4768..4b38d6203 100644
--- a/tests/glean/glutils.cpp
+++ b/tests/glean/glutils.cpp
@@ -99,6 +99,16 @@ haveExtensions(const char* required) {
return haveAll;
} // haveExtensions
+
+float
+getVersion()
+{
+ const GLubyte *version = glGetString(GL_VERSION);
+ // we rely on atof() stopping parsing at whitespace
+ return atof((const char *) version);
+}
+
+
///////////////////////////////////////////////////////////////////////////////
// getProcAddress: Get address of an OpenGL or window-system-binding function.
// This belongs here, rather than as a member of RenderingContext, because
diff --git a/tests/glean/glutils.h b/tests/glean/glutils.h
index 94db42c5f..bc96b59aa 100644
--- a/tests/glean/glutils.h
+++ b/tests/glean/glutils.h
@@ -59,6 +59,9 @@ inline bool haveExtension(const char* name) {
// RenderingContext.
void (*getProcAddress(const char* name))();
+// Return GL renderer version as a float (1.1, 2.0, etc)
+float getVersion();
+
// Check for OpenGL errors and log any that have occurred:
void logGLErrors(Environment& env);
diff --git a/tests/glean/main.cpp b/tests/glean/main.cpp
index c40b5db5b..b7a1d2d53 100644
--- a/tests/glean/main.cpp
+++ b/tests/glean/main.cpp
@@ -1,7 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
-//
+//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -10,11 +10,11 @@
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the
// Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
@@ -23,7 +23,7 @@
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-//
+//
// END_COPYRIGHT
@@ -80,8 +80,6 @@ main(int argc, char* argv[]) {
} else if (!strcmp(argv[i], "-o")
|| !strcmp(argv[i], "--overwrite")) {
o.overwrite = true;
- } else if (!strcmp(argv[i], "--ignore-prereqs")) {
- o.ignorePrereqs = true;
} else if (!strcmp(argv[i], "-c")
|| !strcmp(argv[i], "--compare")) {
o.mode = Options::compare;
@@ -98,8 +96,6 @@ main(int argc, char* argv[]) {
selectTests(o, allTestNames, argc, argv, i);
} else if (!strcmp(argv[i], "--listtests")) {
o.mode = Options::listtests;
- } else if (!strcmp(argv[i], "--listdetails")) {
- o.mode = Options::listdetails;
# if defined(__X11__)
} else if (!strcmp(argv[i], "-display")
|| !strcmp(argv[i], "--display")) {
@@ -156,14 +152,6 @@ main(int argc, char* argv[]) {
}
break;
}
- case Options::listdetails:
- {
- for (Test* t = Test::testList; t; t = t->nextTest)
- if (binary_search(o.selectedTests.begin(),
- o.selectedTests.end(), t->name))
- t->details(e);
- break;
- }
default:
cerr << "Bad run mode in main()\n";
break;
@@ -332,10 +320,8 @@ usage(char* command) {
" (-o|--overwrite) # overwrite existing results database\n"
" --visuals 'filter-string' # select subset of visuals (FBConfigs,\n"
" # pixel formats) to test\n"
-" --ignore-prereqs # do not force prerequisite tests\n"
" (-t|--tests) {(+|-)test} # choose tests to include (+) or exclude (-)\n"
" --listtests # list test names and exit\n"
-" --listdetails # list details of the selected tests and exit\n"
" --help # display usage information\n"
#if defined(__X11__)
" -display X11-display-name # select X11 display to use\n"
diff --git a/tests/glean/options.cpp b/tests/glean/options.cpp
index 9bda4e484..7e97e5fa7 100644
--- a/tests/glean/options.cpp
+++ b/tests/glean/options.cpp
@@ -1,7 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
-//
+//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -10,11 +10,11 @@
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the
// Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
@@ -23,7 +23,7 @@
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-//
+//
// END_COPYRIGHT
@@ -48,7 +48,6 @@ Options::Options() {
visFilter = "1";
selectedTests.resize(0);
overwrite = false;
- ignorePrereqs = false;
# if defined(__X11__)
{
char* display = getenv("DISPLAY");
diff --git a/tests/glean/options.h b/tests/glean/options.h
index ad476d37c..8027069c8 100644
--- a/tests/glean/options.h
+++ b/tests/glean/options.h
@@ -1,7 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
-//
+//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -10,11 +10,11 @@
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the
// Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
@@ -23,7 +23,7 @@
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-//
+//
// END_COPYRIGHT
@@ -38,7 +38,7 @@
// We collect this information for two reasons. First, it allows the
// (relatively) large number of parameters needed for creating an
-// Environment to be passed cleanly to Environment's constructor.
+// Environment to be passed cleanly to Environment's constructor.
// Second, it allows the process of gathering parameters (by parsing a
// command line, running a set of GUI dialogs, etc.) to be separated
// from the creation of the Environment.
@@ -57,7 +57,7 @@ namespace GLEAN {
class Options {
public:
- typedef enum {notSet, run, compare, listtests, listdetails} RunMode;
+ typedef enum {notSet, run, compare, listtests} RunMode;
RunMode mode; // Indicates whether we're generating
// results, or comparing two previous runs.
@@ -82,7 +82,6 @@ class Options {
// Sorted list of tests to be executed.
bool overwrite; // overwrite old results database if exists
- bool ignorePrereqs; // ignore prerequisite tests
#if defined(__X11__)
string dpyName; // Name of the X11 display providing the
// OpenGL implementation to be tested.
diff --git a/tests/glean/tapi2.cpp b/tests/glean/tapi2.cpp
new file mode 100644
index 000000000..d6860e2db
--- /dev/null
+++ b/tests/glean/tapi2.cpp
@@ -0,0 +1,1019 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tapi2.h: Test OpenGL 2.x API functions/features
+// Brian Paul 9 March 2007
+
+#define GL_GLEXT_PROTOTYPES
+
+#include "tapi2.h"
+#include <cassert>
+#include <math.h>
+
+
+namespace GLEAN {
+
+
+static PFNGLATTACHSHADERPROC glAttachShader_func = NULL;
+static PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation_func = NULL;
+static PFNGLCOMPILESHADERPROC glCompileShader_func = NULL;
+static PFNGLCREATEPROGRAMPROC glCreateProgram_func = NULL;
+static PFNGLCREATESHADERPROC glCreateShader_func = NULL;
+static PFNGLDELETEPROGRAMPROC glDeleteProgram_func = NULL;
+static PFNGLDELETESHADERPROC glDeleteShader_func = NULL;
+static PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray_func = NULL;
+static PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray_func = NULL;
+static PFNGLGETATTACHEDSHADERSPROC glGetAttachedShaders_func = NULL;
+static PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation_func = NULL;
+static PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog_func = NULL;
+static PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog_func = NULL;
+static PFNGLGETSHADERIVPROC glGetShaderiv_func = NULL;
+static PFNGLGETPROGRAMIVPROC glGetProgramiv_func = NULL;
+static PFNGLGETSHADERSOURCEPROC glGetShaderSource_func = NULL;
+static PFNGLGETUNIFORMFVPROC glGetUniformfv_func = NULL;
+static PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation_func = NULL;
+static PFNGLISPROGRAMPROC glIsProgram_func = NULL;
+static PFNGLISSHADERPROC glIsShader_func = NULL;
+static PFNGLLINKPROGRAMPROC glLinkProgram_func = NULL;
+static PFNGLSHADERSOURCEPROC glShaderSource_func = NULL;
+static PFNGLUNIFORM1FVPROC glUniform1fv_func = NULL;
+static PFNGLUNIFORM2FVPROC glUniform2fv_func = NULL;
+static PFNGLUNIFORM3FVPROC glUniform3fv_func = NULL;
+static PFNGLUNIFORM4FVPROC glUniform4fv_func = NULL;
+static PFNGLUNIFORM1FPROC glUniform1f_func = NULL;
+static PFNGLUNIFORM2FPROC glUniform2f_func = NULL;
+static PFNGLUNIFORM3FPROC glUniform3f_func = NULL;
+static PFNGLUNIFORM4FPROC glUniform4f_func = NULL;
+static PFNGLUNIFORM1IPROC glUniform1i_func = NULL;
+static PFNGLUNIFORM2IPROC glUniform2i_func = NULL;
+static PFNGLUNIFORM3IPROC glUniform3i_func = NULL;
+static PFNGLUNIFORM4IPROC glUniform4i_func = NULL;
+static PFNGLUNIFORM1IVPROC glUniform1iv_func = NULL;
+static PFNGLUNIFORM2IVPROC glUniform2iv_func = NULL;
+static PFNGLUNIFORM3IVPROC glUniform3iv_func = NULL;
+static PFNGLUNIFORM4IVPROC glUniform4iv_func = NULL;
+static PFNGLUNIFORMMATRIX2FVPROC glUniformMatrix2fv_func = NULL;
+static PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv_func = NULL;
+static PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv_func = NULL;
+static PFNGLUSEPROGRAMPROC glUseProgram_func = NULL;
+static PFNGLVALIDATEPROGRAMPROC glValidateProgram_func = NULL;
+
+static PFNGLVERTEXATTRIB1FPROC glVertexAttrib1f_func = NULL;
+static PFNGLVERTEXATTRIB2FPROC glVertexAttrib2f_func = NULL;
+static PFNGLVERTEXATTRIB3FPROC glVertexAttrib3f_func = NULL;
+static PFNGLVERTEXATTRIB4FPROC glVertexAttrib4f_func = NULL;
+static PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer_func = NULL;
+
+static PFNGLSTENCILOPSEPARATEPROC glStencilOpSeparate_func = NULL;
+static PFNGLSTENCILFUNCSEPARATEPROC glStencilFuncSeparate_func = NULL;
+static PFNGLSTENCILMASKSEPARATEPROC glStencilMaskSeparate_func = NULL;
+
+static PFNGLBLENDEQUATIONSEPARATEPROC glBlendEquationSeparate_func = NULL;
+static PFNGLDRAWBUFFERSPROC glDrawBuffers_func = NULL;
+
+
+
+// Get ptrs to 2.0 API functions.
+// \param errorFunc returns name of API function in case of error
+// \return true for success, false for error
+bool
+API2Test::getFunctions_2_0(char **errorFunc)
+{
+#define GET(PTR, TYPE, STR) \
+ PTR = (TYPE) GLUtils::getProcAddress(STR); \
+ if (!PTR) { \
+ *errorFunc = STR; \
+ return false; \
+ }
+
+ // shading language
+ GET(glAttachShader_func, PFNGLATTACHSHADERPROC, "glAttachShader");
+ GET(glBindAttribLocation_func, PFNGLBINDATTRIBLOCATIONPROC, "glBindAttribLocation");
+ GET(glCompileShader_func, PFNGLCOMPILESHADERPROC, "glCompileShader");
+ GET(glCreateProgram_func, PFNGLCREATEPROGRAMPROC, "glCreateProgram");
+ GET(glCreateShader_func, PFNGLCREATESHADERPROC, "glCreateShader");
+ GET(glDeleteProgram_func, PFNGLDELETEPROGRAMPROC, "glDeleteProgram");
+ GET(glDeleteShader_func, PFNGLDELETESHADERPROC, "glDeleteShader");
+ GET(glDisableVertexAttribArray_func, PFNGLDISABLEVERTEXATTRIBARRAYPROC, "glDisableVertexAttribArray");
+ GET(glEnableVertexAttribArray_func, PFNGLENABLEVERTEXATTRIBARRAYPROC, "glEnableVertexAttribArray");
+ GET(glGetAttachedShaders_func, PFNGLGETATTACHEDSHADERSPROC, "glGetAttachedShaders");
+ GET(glGetAttribLocation_func, PFNGLGETATTRIBLOCATIONPROC, "glGetAttribLocation");
+ GET(glGetProgramInfoLog_func, PFNGLGETPROGRAMINFOLOGPROC, "glGetProgramInfoLog");
+ GET(glGetShaderInfoLog_func, PFNGLGETSHADERINFOLOGPROC, "glGetShaderInfoLog");
+ GET(glGetProgramiv_func, PFNGLGETPROGRAMIVPROC, "glGetProgramiv");
+ GET(glGetShaderiv_func, PFNGLGETSHADERIVPROC, "glGetShaderiv");
+ GET(glGetShaderSource_func, PFNGLGETSHADERSOURCEPROC, "glGetShaderSource");
+ GET(glGetUniformLocation_func, PFNGLGETUNIFORMLOCATIONPROC, "glGetUniformLocation");
+ GET(glGetUniformfv_func, PFNGLGETUNIFORMFVPROC, "glGetUniformfv");
+ GET(glIsProgram_func, PFNGLISPROGRAMPROC, "glIsProgram");
+ GET(glIsShader_func, PFNGLISSHADERPROC, "glIsShader");
+ GET(glLinkProgram_func, PFNGLLINKPROGRAMPROC, "glLinkProgram");
+ GET(glShaderSource_func, PFNGLSHADERSOURCEPROC, "glShaderSource");
+ GET(glUniform1f_func, PFNGLUNIFORM1FPROC, "glUniform1f");
+ GET(glUniform2f_func, PFNGLUNIFORM2FPROC, "glUniform2f");
+ GET(glUniform3f_func, PFNGLUNIFORM3FPROC, "glUniform3f");
+ GET(glUniform4f_func, PFNGLUNIFORM4FPROC, "glUniform4f");
+ GET(glUniform1fv_func, PFNGLUNIFORM1FVPROC, "glUniform1fv");
+ GET(glUniform2fv_func, PFNGLUNIFORM2FVPROC, "glUniform2fv");
+ GET(glUniform3fv_func, PFNGLUNIFORM3FVPROC, "glUniform3fv");
+ GET(glUniform4fv_func, PFNGLUNIFORM3FVPROC, "glUniform4fv");
+ GET(glUniform1i_func, PFNGLUNIFORM1IPROC, "glUniform1i");
+ GET(glUniform2i_func, PFNGLUNIFORM2IPROC, "glUniform2i");
+ GET(glUniform3i_func, PFNGLUNIFORM3IPROC, "glUniform3i");
+ GET(glUniform4i_func, PFNGLUNIFORM4IPROC, "glUniform4i");
+ GET(glUniform1iv_func, PFNGLUNIFORM1IVPROC, "glUniform1iv");
+ GET(glUniform2iv_func, PFNGLUNIFORM2IVPROC, "glUniform2iv");
+ GET(glUniform3iv_func, PFNGLUNIFORM3IVPROC, "glUniform3iv");
+ GET(glUniform4iv_func, PFNGLUNIFORM4IVPROC, "glUniform4iv");
+ GET(glUniformMatrix2fv_func, PFNGLUNIFORMMATRIX2FVPROC, "glUniformMatrix2fv");
+ GET(glUniformMatrix3fv_func, PFNGLUNIFORMMATRIX3FVPROC, "glUniformMatrix3fv");
+ GET(glUniformMatrix4fv_func, PFNGLUNIFORMMATRIX4FVPROC, "glUniformMatrix4fv");
+ GET(glUseProgram_func, PFNGLUSEPROGRAMPROC, "glUseProgram");
+ GET(glValidateProgram_func, PFNGLVALIDATEPROGRAMPROC, "glValidateProgram");
+ GET(glVertexAttrib1f_func, PFNGLVERTEXATTRIB1FPROC, "glVertexAttrib1f");
+ GET(glVertexAttrib2f_func, PFNGLVERTEXATTRIB2FPROC, "glVertexAttrib2f");
+ GET(glVertexAttrib3f_func, PFNGLVERTEXATTRIB3FPROC, "glVertexAttrib3f");
+ GET(glVertexAttrib4f_func, PFNGLVERTEXATTRIB4FPROC, "glVertexAttrib4f");
+ GET(glVertexAttribPointer_func, PFNGLVERTEXATTRIBPOINTERPROC, "glVertexAttribPointer");
+
+ // stencil
+ GET(glStencilOpSeparate_func, PFNGLSTENCILOPSEPARATEPROC, "glStencilOpSeparate");
+ GET(glStencilFuncSeparate_func, PFNGLSTENCILFUNCSEPARATEPROC, "glStencilFuncSeparate");
+ GET(glStencilMaskSeparate_func, PFNGLSTENCILMASKSEPARATEPROC, "glStencilMaskSeparate");
+
+ // misc
+ GET(glBlendEquationSeparate_func, PFNGLBLENDEQUATIONSEPARATEPROC, "glBlendEquationSeparate");
+ GET(glDrawBuffers_func, PFNGLDRAWBUFFERSPROC, "glDrawBuffers");
+
+ return true;
+#undef GET
+}
+
+
+bool
+API2Test::setup(void)
+{
+ // check that we have OpenGL 2.0
+ const char *version = (const char *) glGetString(GL_VERSION);
+ if (version[0] != '2' || version[1] != '.') {
+ //env->log << "OpenGL 2.0 not supported\n";
+ return false;
+ }
+
+ char *errorFunc;
+ if (!getFunctions_2_0(&errorFunc)) {
+ env->log << "Unable to get pointer to OpenGL 2.0 function '"
+ << errorFunc
+ << "'\n";
+ return false;
+ }
+
+ GLenum err = glGetError();
+ assert(!err); // should be OK
+
+ // setup vertex transform (we'll draw a quad in middle of window)
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-4.0, 4.0, -4.0, 4.0, 0.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glDrawBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
+
+ // compute error tolerances (may need fine-tuning)
+ int bufferBits[5];
+ glGetIntegerv(GL_RED_BITS, &bufferBits[0]);
+ glGetIntegerv(GL_GREEN_BITS, &bufferBits[1]);
+ glGetIntegerv(GL_BLUE_BITS, &bufferBits[2]);
+ glGetIntegerv(GL_ALPHA_BITS, &bufferBits[3]);
+ glGetIntegerv(GL_DEPTH_BITS, &bufferBits[4]);
+
+ tolerance[0] = 2.0 / (1 << bufferBits[0]);
+ tolerance[1] = 2.0 / (1 << bufferBits[1]);
+ tolerance[2] = 2.0 / (1 << bufferBits[2]);
+ if (bufferBits[3])
+ tolerance[3] = 2.0 / (1 << bufferBits[3]);
+ else
+ tolerance[3] = 1.0;
+ if (bufferBits[4])
+ tolerance[4] = 16.0 / (1 << bufferBits[4]);
+ else
+ tolerance[4] = 1.0;
+
+ return true;
+}
+
+
+void
+API2Test::reportFailure(const char *msg, int line) const
+{
+ env->log << "FAILURE: " << msg << " (at tapi2.cpp:" << line << ")\n";
+}
+
+
+void
+API2Test::reportFailure(const char *msg, GLenum target, int line) const
+{
+ env->log << "FAILURE: " << msg;
+ if (target == GL_FRAGMENT_SHADER)
+ env->log << " (fragment)";
+ else
+ env->log << " (vertex)";
+ env->log << " (at tapi2.cpp:" << line << ")\n";
+}
+
+
+
+#define REPORT_FAILURE(MSG) reportFailure(MSG, __LINE__)
+#define REPORT_FAILURE_T(MSG, TARGET) reportFailure(MSG, TARGET, __LINE__)
+
+
+// Compare actual and expected colors
+bool
+API2Test::equalColors(const GLfloat act[4], const GLfloat exp[4]) const
+{
+ if ((fabsf(act[0] - exp[0]) > tolerance[0]) ||
+ (fabsf(act[1] - exp[1]) > tolerance[1]) ||
+ (fabsf(act[2] - exp[2]) > tolerance[2]) ||
+ (fabsf(act[3] - exp[3]) > tolerance[3]))
+ return false;
+ else
+ return true;
+}
+
+
+// Render test quad w/ current shader program, return RGBA color of quad
+void
+API2Test::renderQuad(GLfloat *pixel) const
+{
+ const GLfloat r = 0.62; // XXX draw 16x16 pixel quad
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex2f(-r, -r);
+ glTexCoord2f(1, 0); glVertex2f( r, -r);
+ glTexCoord2f(1, 1); glVertex2f( r, r);
+ glTexCoord2f(0, 1); glVertex2f(-r, r);
+ glEnd();
+
+ // read a pixel from lower-left corder of rendered quad
+ glReadPixels(windowSize / 2 - 2, windowSize / 2 - 2, 1, 1,
+ GL_RGBA, GL_FLOAT, pixel);
+}
+
+
+// As above, but use vertex arrays
+// \param attr which vertex attribute array to put colors into
+// \param value 4-component valut to put into the attribute array
+// \param pixel returns the rendered color obtained with glReadPixels
+void
+API2Test::renderQuadWithArrays(GLint attr, const GLfloat value[4],
+ GLfloat *pixel) const
+{
+ const GLfloat r = 0.62; // XXX draw 16x16 pixel quad
+ static const GLfloat vertcoords[4][3] = {
+ { -r, -r, 0 }, { r, -r, 0 }, { r, r, 0 }, { -r, r, 0 }
+ };
+ GLfloat values[4][4];
+ GLint i;
+ for (i = 0; i < 4; i++) {
+ values[i][0] = value[0];
+ values[i][1] = value[1];
+ values[i][2] = value[2];
+ values[i][3] = value[3];
+ };
+
+ glVertexPointer(3, GL_FLOAT, 0, vertcoords);
+ glEnable(GL_VERTEX_ARRAY);
+ glVertexAttribPointer_func(attr, 4, GL_FLOAT, GL_FALSE, 0, values);
+ glEnableVertexAttribArray_func(attr);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glDrawArrays(GL_POLYGON, 0, 4);
+
+ glDisable(GL_VERTEX_ARRAY);
+ glDisableVertexAttribArray_func(attr);
+
+ // read a pixel from lower-left corder of rendered quad
+ glReadPixels(windowSize / 2 - 2, windowSize / 2 - 2, 1, 1,
+ GL_RGBA, GL_FLOAT, pixel);
+}
+
+
+GLuint
+API2Test::loadAndCompileShader(GLenum target, const char *text)
+{
+ GLint stat, val;
+ GLuint shader = glCreateShader_func(target);
+ if (!shader) {
+ REPORT_FAILURE("glCreateShader failed (fragment)");
+ return 0;
+ }
+ glShaderSource_func(shader, 1,
+ (const GLchar **) &text, NULL);
+ glCompileShader_func(shader);
+ glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
+ if (!stat) {
+ REPORT_FAILURE_T("glShaderSource or glCompileShader failed", target);
+ return 0;
+ }
+ if (!glIsShader_func(shader)) {
+ REPORT_FAILURE("glIsShader failed (fragment)");
+ return false;
+ }
+ glGetShaderiv_func(shader, GL_SHADER_TYPE, &val);
+ if (val != (GLint) target) {
+ REPORT_FAILURE_T("glGetShaderiv(GL_SHADER_TYPE) failed", target);
+ return 0;
+ }
+ glGetShaderiv_func(shader, GL_COMPILE_STATUS, &val);
+ if (val != GL_TRUE) {
+ REPORT_FAILURE_T("glGetShaderiv(GL_COMPILE_STATUS) failed", target);
+ return 0;
+ }
+ glGetShaderiv_func(shader, GL_SHADER_SOURCE_LENGTH, &val);
+ // Note: some OpenGLs return a 1-char shorter length than strlen(text)
+ if (abs(val - (int) strlen(text)) > 1) {
+ REPORT_FAILURE_T("glGetShaderiv(GL_SHADER_SOURCE_LENGTH) failed", target);
+ return 0;
+ }
+ return shader;
+}
+
+
+GLuint
+API2Test::createProgram(GLuint vertShader, GLuint fragShader)
+{
+ GLuint program = glCreateProgram_func();
+ if (vertShader)
+ glAttachShader_func(program, vertShader);
+ if (fragShader)
+ glAttachShader_func(program, fragShader);
+ glLinkProgram_func(program);
+ return program;
+}
+
+
+bool
+API2Test::testShaderObjectFuncs(void)
+{
+ static const char *vertShaderText =
+ "void main() { \n"
+ " gl_Position = ftransform(); \n"
+ "} \n";
+ static const char *fragShaderText =
+ "void main() { \n"
+ " gl_FragColor = vec4(1.0, 0.5, 0.25, 0.0); \n"
+ "} \n";
+ GLuint vertShader, fragShader, program;
+ GLint stat, val, err;
+
+ vertShader = loadAndCompileShader(GL_VERTEX_SHADER, vertShaderText);
+ if (!vertShader)
+ return false;
+ fragShader = loadAndCompileShader(GL_FRAGMENT_SHADER, fragShaderText);
+ if (!fragShader)
+ return false;
+
+
+ program = createProgram(vertShader, fragShader);
+ if (!program) {
+ REPORT_FAILURE("glCreateProgram failed");
+ return false;
+ }
+ glGetProgramiv_func(program, GL_LINK_STATUS, &stat);
+ if (!stat) {
+ REPORT_FAILURE("glLinkProgram failed");
+ return false;
+ }
+ glUseProgram_func(program);
+
+ glGetIntegerv(GL_CURRENT_PROGRAM, &val);
+ if (val != (GLint) program) {
+ REPORT_FAILURE("glGetInteger(GL_CURRENT_PROGRAM) failed");
+ return false;
+ }
+
+ err = glGetError();
+ if (err) {
+ REPORT_FAILURE("OpenGL error detected in testShaderFuncs");
+ return false;
+ }
+
+ if (!glIsProgram_func(program)) {
+ REPORT_FAILURE("glIsProgram failed");
+ return false;
+ }
+
+ GLuint objects[2];
+ GLsizei count;
+ glGetProgramiv_func(program, GL_ATTACHED_SHADERS, &val);
+ if (val != 2) {
+ REPORT_FAILURE("glGetProgramiv(GL_ATTACHED_SHADERS) failed");
+ return false;
+ }
+ glGetAttachedShaders_func(program, 2, &count, objects);
+ if (count != 2) {
+ REPORT_FAILURE("glGetAttachedShaders failed (wrong count)");
+ return false;
+ }
+ if (objects[0] != vertShader && objects[1] != vertShader) {
+ REPORT_FAILURE("glGetAttachedShaders failed (vertex shader missing)");
+ return false;
+ }
+ if (objects[0] != fragShader && objects[1] != fragShader) {
+ REPORT_FAILURE("glGetAttachedShaders failed (fragment shader missing)");
+ return false;
+ }
+
+ glValidateProgram_func(program);
+ glGetProgramiv_func(program, GL_VALIDATE_STATUS, &stat);
+ if (!stat) {
+ REPORT_FAILURE("glValidateProgram failed");
+ return false;
+ }
+
+ // Delete vertex shader
+ glDeleteShader_func(vertShader);
+ if (!glIsShader_func(vertShader)) {
+ // the shader is still attached so the handle should be valid
+ REPORT_FAILURE("glIsShader(deleted shader) failed");
+ return false;
+ }
+ glGetShaderiv_func(vertShader, GL_DELETE_STATUS, &stat);
+ if (stat != GL_TRUE) {
+ REPORT_FAILURE("Incorrect shader delete status");
+ return false;
+ }
+
+ // Delete fragment shader
+ glDeleteShader_func(fragShader);
+
+ // Delete program object
+ glDeleteProgram_func(program);
+ if (!glIsProgram_func(program)) {
+ // the program is still in use so the handle should be valid
+ REPORT_FAILURE("glIsProgram(deleted program) failed");
+ return false;
+ }
+ glGetProgramiv_func(program, GL_DELETE_STATUS, &stat);
+ if (stat != GL_TRUE) {
+ REPORT_FAILURE("Incorrect program delete status");
+ return false;
+ }
+
+ // now unbind the program
+ glUseProgram_func(0);
+ stat = glIsProgram_func(program);
+ if (stat) {
+ // the program and handle should have really been deleted now
+ REPORT_FAILURE("glIsProgram(deleted program) failed");
+ return false;
+ }
+
+ glGetProgramiv_func(program, GL_DELETE_STATUS, &stat);
+ err = glGetError();
+ if (!err) {
+ // the program and handle should have been deleted now
+ // so glGetProgramiv() should have generated an error
+ REPORT_FAILURE("glGetProgramiv(deleted program) failed");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
+API2Test::testUniformfFuncs(void)
+{
+ static const char *fragShaderText =
+ "uniform float uf1; \n"
+ "uniform vec2 uf2; \n"
+ "uniform vec3 uf3; \n"
+ "uniform vec4 uf4; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(uf1, uf2.y, uf3.z, uf4.w); \n"
+ "} \n";
+ GLuint fragShader, program;
+ GLint uf1, uf2, uf3, uf4;
+ GLfloat value[4];
+
+ fragShader = loadAndCompileShader(GL_FRAGMENT_SHADER, fragShaderText);
+ if (!fragShader) {
+ return false;
+ }
+ program = createProgram(0, fragShader);
+ if (!program) {
+ REPORT_FAILURE("glCreateProgram (uniform test) failed");
+ return false;
+ }
+ glUseProgram_func(program);
+
+ uf1 = glGetUniformLocation_func(program, "uf1");
+ if (uf1 < 0) {
+ REPORT_FAILURE("glGetUniform \"uf1\" failed");
+ return false;
+ }
+ uf2 = glGetUniformLocation_func(program, "uf2");
+ if (uf2 < 0) {
+ REPORT_FAILURE("glGetUniform \"uf2\" failed");
+ return false;
+ }
+ uf3 = glGetUniformLocation_func(program, "uf3");
+ if (uf3 < 0) {
+ REPORT_FAILURE("glGetUniform \"uf3\" failed");
+ return false;
+ }
+ uf4 = glGetUniformLocation_func(program, "uf4");
+ if (uf4 < 0) {
+ REPORT_FAILURE("glGetUniform \"uf4\" failed");
+ return false;
+ }
+
+
+ GLfloat pixel[4], expected[4];
+
+ // Test glUniform[1234]f()
+ expected[0] = 0.1;
+ expected[1] = 0.2;
+ expected[2] = 0.3;
+ expected[3] = 0.4;
+ glUniform1f_func(uf1, expected[0]);
+ glUniform2f_func(uf2, 0.0, expected[1]);
+ glUniform3f_func(uf3, 0.0, 0.0, expected[2]);
+ glUniform4f_func(uf4, 0.0, 0.0, 0.0, expected[3]);
+ renderQuad(pixel);
+ if (!equalColors(pixel, expected)) {
+ REPORT_FAILURE("glUniform[1234]f failed");
+ printf("%f %f %f %f\n", pixel[0], pixel[1], pixel[2], pixel[3]);
+ return false;
+ }
+
+ // Test glUniform[1234]fv()
+ GLfloat u[4];
+ expected[0] = 0.9;
+ expected[1] = 0.8;
+ expected[2] = 0.7;
+ expected[3] = 0.6;
+ u[0] = expected[0];
+ glUniform1fv_func(uf1, 1, u);
+ u[0] = 0.0; u[1] = expected[1];
+ glUniform2fv_func(uf2, 1, u);
+ u[0] = 0.0; u[1] = 0.0; u[2] = expected[2];
+ glUniform3fv_func(uf3, 1, u);
+ u[0] = 0.0; u[1] = 0.0; u[2] = 0.0; u[3] = expected[3];
+ glUniform4fv_func(uf4, 1, u);
+ renderQuad(pixel);
+ if (!equalColors(pixel, expected)) {
+ REPORT_FAILURE("glUniform[1234]f failed");
+ return false;
+ }
+
+ // Test glGetUniformfv
+ glUniform4fv_func(uf4, 1, expected);
+ glGetUniformfv_func(program, uf4, value);
+ if (value[0] != expected[0] ||
+ value[1] != expected[1] ||
+ value[2] != expected[2] ||
+ value[3] != expected[3]) {
+ REPORT_FAILURE("glGetUniformfv failed");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
+API2Test::testUniformiFuncs(void)
+{
+ static const char *fragShaderText =
+ "uniform int ui1; \n"
+ "uniform ivec2 ui2; \n"
+ "uniform ivec3 ui3; \n"
+ "uniform ivec4 ui4; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(ui1, ui2.y, ui3.z, ui4.w) * 0.1; \n"
+ "} \n";
+ GLuint fragShader, program;
+ GLint ui1, ui2, ui3, ui4;
+
+ fragShader = loadAndCompileShader(GL_FRAGMENT_SHADER, fragShaderText);
+ if (!fragShader) {
+ return false;
+ }
+ program = createProgram(0, fragShader);
+ if (!program) {
+ REPORT_FAILURE("glCreateProgram (uniform test) failed");
+ return false;
+ }
+ glUseProgram_func(program);
+
+ ui1 = glGetUniformLocation_func(program, "ui1");
+ if (ui1 < 0) {
+ REPORT_FAILURE("glGetUniform \"ui1\" failed");
+ return false;
+ }
+ ui2 = glGetUniformLocation_func(program, "ui2");
+ if (ui2 < 0) {
+ REPORT_FAILURE("glGetUniform \"ui2\" failed");
+ return false;
+ }
+ ui3 = glGetUniformLocation_func(program, "ui3");
+ if (ui3 < 0) {
+ REPORT_FAILURE("glGetUniform \"ui3\" failed");
+ return false;
+ }
+ ui4 = glGetUniformLocation_func(program, "ui4");
+ if (ui4 < 0) {
+ REPORT_FAILURE("glGetUniform \"ui4\" failed");
+ return false;
+ }
+
+ GLfloat pixel[4], expected[4];
+ GLint expectedInt[4];
+
+ // Test glUniform[1234]f()
+ expectedInt[0] = 1;
+ expectedInt[1] = 2;
+ expectedInt[2] = 3;
+ expectedInt[3] = 4;
+ expected[0] = 0.1;
+ expected[1] = 0.2;
+ expected[2] = 0.3;
+ expected[3] = 0.4;
+ glUniform1i_func(ui1, expectedInt[0]);
+ glUniform2i_func(ui2, 0, expectedInt[1]);
+ glUniform3i_func(ui3, 0, 0, expectedInt[2]);
+ glUniform4i_func(ui4, 0, 0, 0, expectedInt[3]);
+ renderQuad(pixel);
+ if (!equalColors(pixel, expected)) {
+ REPORT_FAILURE("glUniform[1234]i failed");
+ printf("%f %f %f %f\n", pixel[0], pixel[1], pixel[2], pixel[3]);
+ return false;
+ }
+
+ // Test glUniform[1234]fv()
+ GLint u[4];
+ expectedInt[0] = 9;
+ expectedInt[1] = 8;
+ expectedInt[2] = 7;
+ expectedInt[3] = 6;
+ expected[0] = 0.9;
+ expected[1] = 0.8;
+ expected[2] = 0.7;
+ expected[3] = 0.6;
+ u[0] = expectedInt[0];
+ glUniform1iv_func(ui1, 1, u);
+ u[0] = 0; u[1] = expectedInt[1];
+ glUniform2iv_func(ui2, 1, u);
+ u[0] = 0; u[1] = 0; u[2] = expectedInt[2];
+ glUniform3iv_func(ui3, 1, u);
+ u[0] = 0; u[1] = 0; u[2] = 0; u[3] = expectedInt[3];
+ glUniform4iv_func(ui4, 1, u);
+ renderQuad(pixel);
+ if (!equalColors(pixel, expected)) {
+ REPORT_FAILURE("glUniform[1234]i failed");
+ printf("%f %f %f %f\n", pixel[0], pixel[1], pixel[2], pixel[3]);
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
+API2Test::testShaderAttribs(void)
+{
+ static const char *vertShaderText =
+ "attribute vec4 generic; \n"
+ "void main() { \n"
+ " gl_Position = ftransform(); \n"
+ " gl_FrontColor = generic; \n"
+ "} \n";
+ GLuint vertShader, program;
+
+ vertShader = loadAndCompileShader(GL_VERTEX_SHADER, vertShaderText);
+ if (!vertShader) {
+ return false;
+ }
+ program = createProgram(vertShader, 0);
+ if (!program) {
+ REPORT_FAILURE("glCreateProgram (uniform test) failed");
+ return false;
+ }
+ glUseProgram_func(program);
+
+ static const GLfloat testColors[3][4] = {
+ { 1.0, 0.5, 0.25, 0.0 },
+ { 0.0, 0.1, 0.2, 0.3 },
+ { 0.5, 0.6, 0.7, 0.8 },
+ };
+
+ // let compiler allocate the attribute location
+ const GLint attr = glGetAttribLocation_func(program, "generic");
+ if (attr < 0) {
+ REPORT_FAILURE("glGetAttribLocation failed");
+ return false;
+ }
+ for (int i = 0; i < 3; i++) {
+ GLfloat pixel[4];
+ renderQuadWithArrays(attr, testColors[i], pixel);
+ if (!equalColors(pixel, testColors[i])) {
+ REPORT_FAILURE("Vertex array test failed");
+ return false;
+ }
+ }
+
+ // Test explicit attribute binding.
+ const GLint bindAttr = 6; // XXX a non-colliding alias
+ glBindAttribLocation_func(program, bindAttr, "generic");
+ glLinkProgram_func(program);
+ GLint loc = glGetAttribLocation_func(program, "generic");
+ if (loc != bindAttr) {
+ REPORT_FAILURE("glBindAttribLocation failed");
+ return false;
+ }
+ for (int i = 0; i < 3; i++) {
+ GLfloat pixel[4];
+ renderQuadWithArrays(bindAttr, testColors[i], pixel);
+ if (!equalColors(pixel, testColors[i])) {
+ REPORT_FAILURE("Vertex array test failed (2)");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) )
+
+bool
+API2Test::testStencilFuncSeparate(void)
+{
+ GLint val;
+ GLint stencilBits, stencilMax;
+
+ glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
+ stencilMax = (1 << stencilBits) - 1;
+
+ glStencilFuncSeparate_func(GL_FRONT, GL_LEQUAL, 12, 0xf);
+ glStencilFuncSeparate_func(GL_BACK, GL_GEQUAL, 13, 0xe);
+
+ glGetIntegerv(GL_STENCIL_BACK_FUNC, &val);
+ if (val != GL_GEQUAL) {
+ REPORT_FAILURE("GL_STENCIL_BACK_FUNC query returned wrong value");
+ return false;
+ }
+
+ glGetIntegerv(GL_STENCIL_FUNC, &val);
+ if (val != GL_LEQUAL) {
+ REPORT_FAILURE("GL_STENCIL_FUNC (front) query returned wrong value");
+ return false;
+ }
+
+ glGetIntegerv(GL_STENCIL_BACK_REF, &val);
+ if (val != CLAMP(13, 0, stencilMax)) {
+ REPORT_FAILURE("GL_STENCIL_BACK_REF query returned wrong value");
+ return false;
+ }
+
+ glGetIntegerv(GL_STENCIL_REF, &val);
+ if (val != CLAMP(12, 0, stencilMax)) {
+ REPORT_FAILURE("GL_STENCIL_REF (front) query returned wrong value");
+ return false;
+ }
+
+ glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &val);
+ if (val != 0xe) {
+ REPORT_FAILURE("GL_STENCIL_BACK_VALUE_MASK query returned wrong value");
+ return false;
+ }
+
+ glGetIntegerv(GL_STENCIL_VALUE_MASK, &val);
+ if (val != 0xf) {
+ REPORT_FAILURE("GL_STENCIL_VALUE_MASK (front) query returned wrong value");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
+API2Test::testStencilOpSeparate(void)
+{
+ GLint val;
+
+ // face, fail, zfail, zpass
+ glStencilOpSeparate_func(GL_FRONT, GL_INVERT, GL_ZERO, GL_INCR);
+ glStencilOpSeparate_func(GL_BACK, GL_INCR, GL_KEEP, GL_REPLACE);
+
+ glGetIntegerv(GL_STENCIL_BACK_FAIL, &val);
+ if (val != GL_INCR) {
+ REPORT_FAILURE("GL_STENCIL_BACK_FAIL query returned wrong value");
+ return false;
+ }
+
+ glGetIntegerv(GL_STENCIL_FAIL, &val);
+ if (val != GL_INVERT) {
+ REPORT_FAILURE("GL_STENCIL_FAIL (front) query returned wrong value");
+ return false;
+ }
+
+ glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL, &val);
+ if (val != GL_KEEP) {
+ REPORT_FAILURE("GL_STENCIL_BACK_PASS_DEPTH_FAIL query returned wrong value");
+ return false;
+ }
+
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &val);
+ if (val != GL_ZERO) {
+ REPORT_FAILURE("GL_STENCIL_PASS_DEPTH_FAIL (front) query returned wrong value");
+ return false;
+ }
+
+ glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &val);
+ if (val != GL_REPLACE) {
+ REPORT_FAILURE("GL_STENCIL_BACK_PASS_DEPTH_PASS query returned wrong value");
+ return false;
+ }
+
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &val);
+ if (val != GL_INCR) {
+ REPORT_FAILURE("GL_STENCIL_PASS_DEPTH_PASS (front) query returned wrong value");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
+API2Test::testStencilMaskSeparate(void)
+{
+ GLint val;
+
+ // face, fail, zfail, zpass
+ glStencilMaskSeparate_func(GL_BACK, 0xa);
+ glStencilMaskSeparate_func(GL_FRONT, 0xb);
+
+ glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &val);
+ if (val != 0xa) {
+ REPORT_FAILURE("GL_STENCIL_BACK_WRITEMASK query returned wrong value");
+ return false;
+ }
+
+ glGetIntegerv(GL_STENCIL_WRITEMASK, &val);
+ if (val != 0xb) {
+ REPORT_FAILURE("GL_STENCIL_WRITEMASK (front) query returned wrong value");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
+API2Test::testBlendEquationSeparate(void)
+{
+ GLint val;
+
+ glBlendEquationSeparate_func(GL_MAX, GL_FUNC_SUBTRACT);
+
+ glGetIntegerv(GL_BLEND_EQUATION, &val);
+ if (val != GL_MAX) {
+ REPORT_FAILURE("GL_BLEND_EQUATION (rgb) query returned wrong value");
+ return false;
+ }
+
+ glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &val);
+ if (val != GL_FUNC_SUBTRACT) {
+ REPORT_FAILURE("GL_BLEND_EQUATION (rgb) query returned wrong value");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
+API2Test::testDrawBuffers(void)
+{
+ const int MAX = 2;
+ GLint maxBuf = -1, i, n, val;
+ GLenum buffers[MAX], err;
+ GLint initDrawBuffer;
+
+ glGetIntegerv(GL_DRAW_BUFFER, &initDrawBuffer);
+
+ glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxBuf);
+ if (maxBuf < 1) {
+ REPORT_FAILURE("GL_MAX_DRAW_BUFFERS query failed");
+ return false;
+ }
+
+ n = maxBuf < MAX ? maxBuf : MAX;
+ assert(n > 0);
+ for (i = 0; i < n; i++) {
+ buffers[i] = (i & 1) ? GL_FRONT_LEFT : GL_BACK_LEFT;
+ }
+ glDrawBuffers_func(n, buffers);
+
+ for (i = 0; i < n; i++) {
+ glGetIntegerv(GL_DRAW_BUFFER0 + i, &val);
+ if (val != (GLint) buffers[i]) {
+ REPORT_FAILURE("glDrawBuffers failed");
+ return false;
+ }
+ }
+
+ // restore
+ glDrawBuffer(initDrawBuffer);
+
+ err = glGetError();
+ if (err) {
+ REPORT_FAILURE("glDrawBuffers generrated an OpenGL error");
+ return false;
+ }
+
+ return true;
+}
+
+
+// Run all the subtests, incrementing numPassed, numFailed
+void
+API2Test::runSubTests(MultiTestResult &r)
+{
+ static TestFunc funcs[] = {
+ &GLEAN::API2Test::testStencilFuncSeparate,
+ &GLEAN::API2Test::testStencilOpSeparate,
+ &GLEAN::API2Test::testStencilMaskSeparate,
+ &GLEAN::API2Test::testBlendEquationSeparate,
+ &GLEAN::API2Test::testDrawBuffers,
+ &GLEAN::API2Test::testShaderObjectFuncs,
+ &GLEAN::API2Test::testUniformfFuncs,
+ &GLEAN::API2Test::testUniformiFuncs,
+ &GLEAN::API2Test::testShaderAttribs,
+ NULL
+ };
+
+ for (int i = 0; funcs[i]; i++)
+ if ((this->*funcs[i])())
+ r.numPassed++;
+ else
+ r.numFailed++;
+}
+
+
+void
+API2Test::runOne(MultiTestResult &r, Window &w)
+{
+ (void) w;
+
+ if (!setup()) {
+ r.pass = false;
+ return;
+ }
+
+ runSubTests(r);
+
+ r.pass = (r.numFailed == 0);
+}
+
+
+// The test object itself:
+API2Test api2Test("api2", "window, rgb, z, db",
+ "", // no extension filter (we'll test for version 2.x during setup)
+ "API2 test: check that OpenGL 2.x API functions work.\n"
+ );
+
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tapi2.h b/tests/glean/tapi2.h
new file mode 100644
index 000000000..c4df77193
--- /dev/null
+++ b/tests/glean/tapi2.h
@@ -0,0 +1,87 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tapi2.h: Test OpenGL 2.x API functions/features
+// Brian Paul 9 March 2007
+
+#ifndef __tapi2_h__
+#define __tapi2_h__
+
+#include "tmultitest.h"
+
+namespace GLEAN {
+
+#define windowSize 100
+
+
+class API2Test: public MultiTest
+{
+public:
+ API2Test(const char* testName, const char* filter,
+ const char *extensions, const char* description):
+ MultiTest(testName, filter, extensions, description)
+ {
+ }
+
+ virtual void runOne(MultiTestResult &r, Window &w);
+
+private:
+ typedef bool (API2Test::*TestFunc)(void);
+
+ GLfloat tolerance[5];
+ bool getFunctions_2_0(char **errorFunc);
+
+ GLuint loadAndCompileShader(GLenum target, const char *str);
+ GLuint createProgram(GLuint vertShader, GLuint fragShader);
+
+ void renderQuad(GLfloat *pixel) const;
+ void renderQuadWithArrays(GLint attr, const GLfloat value[4],
+ GLfloat *pixel) const;
+
+ bool testStencilFuncSeparate(void);
+ bool testStencilOpSeparate(void);
+ bool testStencilMaskSeparate(void);
+ bool testBlendEquationSeparate(void);
+ bool testDrawBuffers(void);
+ bool testShaderObjectFuncs(void);
+ bool testUniformfFuncs(void);
+ bool testUniformiFuncs(void);
+ bool testShaderAttribs(void);
+
+ void runSubTests(MultiTestResult &r);
+
+ bool setup(void);
+ bool equalColors(const GLfloat a[4], const GLfloat b[4]) const;
+
+ void reportFailure(const char *msg, int line) const;
+ void reportFailure(const char *msg, GLenum target, int line) const;
+};
+
+} // namespace GLEAN
+
+#endif // __tglsl1_h__
diff --git a/tests/glean/tbase.h b/tests/glean/tbase.h
index 476754278..afe539437 100644
--- a/tests/glean/tbase.h
+++ b/tests/glean/tbase.h
@@ -1,7 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
-//
+//
// Copyright (C) 1999-2000 Allen Akin All Rights Reserved.
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -10,11 +10,11 @@
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the
// Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
@@ -23,7 +23,7 @@
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-//
+//
// END_COPYRIGHT
/*
@@ -67,7 +67,7 @@ constructing a test:
contexts that support all the listed extensions. Extension
names in the string may be separated with non alphanumerics;
whitespace and commas are used by convention.
-
+
A description string. This will be printed in the test log to
describe the test.
@@ -89,7 +89,7 @@ Your new test will need a few common declarations (such as
constructors). To simplify writing them, this file provides a few
helper macros. GLEAN_CLASS(TEST,RESULT) handles the declarations for
a test class named TEST and a result class named RESULT, using the
-default values for window width and height and the run-once flag.
+default values for window width and height and the run-once flag.
GLEAN_CLASS_WH() and GLEAN_CLASS_WHO() allow you to specify the width,
height, and run-once flag if you choose.
@@ -170,12 +170,12 @@ public:
virtual void putresults(ostream& s) const = 0;
virtual bool getresults(istream& s) = 0;
-
+
virtual void put(ostream& s) const {
s << config->canonicalDescription() << '\n';
putresults(s);
}
-
+
virtual bool get(istream& s) {
SkipWhitespace(s);
string configDesc;
@@ -194,7 +194,7 @@ public:
description = aDescription;
fWidth = 258;
fHeight = 258;
- testOne = false;
+ testOne = false;
}
BaseTest(const char* aName, const char* aFilter, Test** thePrereqs,
const char* aDescription):
@@ -204,7 +204,7 @@ public:
description = aDescription;
fWidth = 258;
fHeight = 258;
- testOne = false;
+ testOne = false;
}
BaseTest(const char* aName, const char* aFilter,
const char* anExtensionList,
@@ -243,7 +243,7 @@ public:
}
return v;
}
-
+
virtual void logDescription() {
if (env->options.verbosity)
env->log <<
@@ -255,10 +255,8 @@ public:
virtual void run(Environment& environment) {
if (hasRun) return; // no multiple invocations
// Invoke the prerequisite tests, if any:
- if (!environment.options.ignorePrereqs) {
- for (Test** t = prereqs; t != 0 && *t != 0; ++t)
- (*t)->run(environment);
- }
+ for (Test** t = prereqs; t != 0 && *t != 0; ++t)
+ (*t)->run(environment);
env = &environment; // make environment available
logDescription(); // log invocation
WindowSystem& ws = env->winSys;
@@ -291,7 +289,7 @@ public:
r->config = *p;
runOne(*r, w);
logOne(*r);
-
+
// Save the result
results.push_back(r);
r->put(os);
@@ -311,10 +309,10 @@ public:
env->log << "Could not create a rendering context\n";
}
env->log << '\n';
-
+
hasRun = true; // Note that we've completed the run
}
-
+
virtual void compare(Environment& environment) {
env = &environment; // Save the environment
logDescription();
@@ -397,16 +395,6 @@ public:
virtual void logConcise(ResultType& r) {
env->log << r.config->conciseDescription() << '\n';
}
-
- virtual void printDetails() {
- }
-
- virtual void details(Environment& environment) {
- env = &environment;
- env->log << "DETAILS for " << name << '\n';
- printDetails();
- env->log << "END DETAILS\n";
- }
}; // class BaseTest
} // namespace GLEAN
diff --git a/tests/glean/tblend.cpp b/tests/glean/tblend.cpp
index 87d0934d7..3fb8d6116 100644
--- a/tests/glean/tblend.cpp
+++ b/tests/glean/tblend.cpp
@@ -1,7 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
-//
+//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -10,11 +10,11 @@
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the
// Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
@@ -23,20 +23,32 @@
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-//
+//
// END_COPYRIGHT
// tblend.cpp: Test blending functions.
+#include <assert.h>
#include "tblend.h"
#include "rand.h"
#include "image.h"
#include <cmath>
-namespace {
+#define ELEMENTS(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0]))
-struct factorNameMapping {GLenum factor; char* name;};
-factorNameMapping factorNames[] = {
+static PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate_func = NULL;
+static PFNGLBLENDCOLORPROC glBlendColor_func = NULL;
+static PFNGLBLENDEQUATIONPROC glBlendEquation_func = NULL;
+static PFNGLBLENDEQUATIONSEPARATEPROC glBlendEquationSeparate_func = NULL;
+
+//namespace {
+
+struct enumNameMapping {
+ GLenum token;
+ char* name;
+};
+
+enumNameMapping factorNames[] = {
{GL_DST_ALPHA, "GL_DST_ALPHA"},
{GL_DST_COLOR, "GL_DST_COLOR"},
{GL_ONE, "GL_ONE"},
@@ -47,35 +59,75 @@ factorNameMapping factorNames[] = {
{GL_SRC_ALPHA, "GL_SRC_ALPHA"},
{GL_SRC_ALPHA_SATURATE, "GL_SRC_ALPHA_SATURATE"},
{GL_SRC_COLOR, "GL_SRC_COLOR"},
- {GL_ZERO, "GL_ZERO"}
+ {GL_ZERO, "GL_ZERO"},
+ {GL_CONSTANT_COLOR, "GL_CONSTANT_COLOR"},
+ {GL_ONE_MINUS_CONSTANT_COLOR, "GL_ONE_MINUS_CONSTANT_COLOR"},
+ {GL_CONSTANT_ALPHA, "GL_CONSTANT_ALPHA"},
+ {GL_ONE_MINUS_CONSTANT_ALPHA, "GL_ONE_MINUS_CONSTANT_ALPHA"}
};
+// aka blend "equation"
+enumNameMapping blendopNames[] = {
+ {GL_FUNC_ADD, "GL_FUNC_ADD"},
+ {GL_FUNC_SUBTRACT, "GL_FUNC_SUBTRACT"},
+ {GL_FUNC_REVERSE_SUBTRACT, "GL_FUNC_REVERSE_SUBTRACT"},
+ {GL_MIN, "GL_MIN"},
+ {GL_MAX, "GL_MAX"}
+};
+
+
char*
factorToName(GLenum factor) {
- for (unsigned int i = 0;
- i < sizeof(factorNames) / sizeof(factorNames[0]);
- ++i)
- if (factorNames[i].factor == factor)
+ for (unsigned int i = 0; i < ELEMENTS(factorNames); ++i)
+ if (factorNames[i].token == factor)
return factorNames[i].name;
return 0;
} // factorToName
GLenum
nameToFactor(string& name) {
- for (unsigned int i = 0;
- i < sizeof(factorNames) / sizeof(factorNames[0]);
- ++i)
+ for (unsigned int i = 0; i < ELEMENTS(factorNames); ++i)
if (factorNames[i].name == name)
- return factorNames[i].factor;
+ return factorNames[i].token;
return GL_ZERO;
} // nameToFactor
+char *
+opToName(GLenum op) {
+ for (unsigned int i = 0; i < ELEMENTS(blendopNames); ++i)
+ if (blendopNames[i].token == op)
+ return blendopNames[i].name;
+ return 0;
+} // opToName
+
+GLenum
+nameToOp(string& name) {
+ for (unsigned int i = 0; i < ELEMENTS(blendopNames); ++i)
+ if (blendopNames[i].name == name)
+ return blendopNames[i].token;
+ return GL_ZERO;
+} // nameToOp
+
+
bool
needsDstAlpha(const GLenum func) {
return func == GL_DST_ALPHA || func == GL_ONE_MINUS_DST_ALPHA
|| func == GL_SRC_ALPHA_SATURATE;
}
+bool
+needsBlendColor(const GLenum func) {
+ switch (func) {
+ case GL_CONSTANT_COLOR:
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ case GL_CONSTANT_ALPHA:
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ return true;
+ default:
+ return false;
+ }
+}
+
void
makeRGBA(GLEAN::RandomBitsDouble& rRand,
GLEAN::RandomBitsDouble& gRand,
@@ -88,7 +140,7 @@ makeRGBA(GLEAN::RandomBitsDouble& rRand,
rgba[3] = aRand.next();
} // makeRGBA
-void
+void
drawQuad(const int x, const int y, const float* color) {
glColor4fv(color);
glBegin(GL_QUADS);
@@ -109,101 +161,295 @@ clamp(float f) {
return f;
} // clamp
-void
-applyBlend(GLenum srcFactor, GLenum dstFactor, float* dst, float* src) {
- // XXX Currently we don't test any of the const-color blend factors.
- // It would be a good idea to do so as soon as we have access to an
- // implementation that supports the OpenGL 1.2 imaging extensions.
-
- float sf[4];
- switch (srcFactor) {
- case GL_ZERO:
- sf[0] = sf[1] = sf[2] = sf[3] = 0.0;
- break;
- case GL_ONE:
- sf[0] = sf[1] = sf[2] = sf[3] = 1.0;
- break;
- case GL_DST_COLOR:
- sf[0] = dst[0]; sf[1] = dst[1]; sf[2] = dst[2]; sf[3] = dst[3];
- break;
- case GL_ONE_MINUS_DST_COLOR:
- sf[0] = 1.0 - dst[0]; sf[1] = 1.0 - dst[1];
- sf[2] = 1.0 - dst[2]; sf[3] = 1.0 - dst[3];
- break;
- case GL_SRC_ALPHA:
- sf[0] = sf[1] = sf[2] = sf[3] = src[3];
- break;
- case GL_ONE_MINUS_SRC_ALPHA:
- sf[0] = sf[1] = sf[2] = sf[3] = 1.0 - src[3];
- break;
- case GL_DST_ALPHA:
- sf[0] = sf[1] = sf[2] = sf[3] = dst[3];
- break;
- case GL_ONE_MINUS_DST_ALPHA:
- sf[0] = sf[1] = sf[2] = sf[3] = 1.0 - dst[3];
- break;
- case GL_SRC_ALPHA_SATURATE: {
- float f = 1.0 - dst[3];
- if (src[3] < f)
- f = src[3];
- sf[0] = sf[1] = sf[2] = f; sf[3] = 1.0;
+static void
+applyBlend(GLenum srcFactorRGB, GLenum srcFactorA,
+ GLenum dstFactorRGB, GLenum dstFactorA,
+ GLenum opRGB, GLenum opA,
+ float* dst, const float* src,
+ const GLfloat constantColor[4])
+{
+ float sf[4], df[4];
+
+ if (opRGB != GL_MIN && opRGB != GL_MAX) {
+ // Src RGB term
+ switch (srcFactorRGB) {
+ case GL_ZERO:
+ sf[0] = sf[1] = sf[2] = 0.0;
+ break;
+ case GL_ONE:
+ sf[0] = sf[1] = sf[2] = 1.0;
+ break;
+ case GL_DST_COLOR:
+ sf[0] = dst[0];
+ sf[1] = dst[1];
+ sf[2] = dst[2];
+ break;
+ case GL_ONE_MINUS_DST_COLOR:
+ sf[0] = 1.0 - dst[0];
+ sf[1] = 1.0 - dst[1];
+ sf[2] = 1.0 - dst[2];
+ break;
+ case GL_SRC_ALPHA:
+ sf[0] = sf[1] = sf[2] = src[3];
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ sf[0] = sf[1] = sf[2] = 1.0 - src[3];
+ break;
+ case GL_DST_ALPHA:
+ sf[0] = sf[1] = sf[2] = dst[3];
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ sf[0] = sf[1] = sf[2] = 1.0 - dst[3];
+ break;
+ case GL_SRC_ALPHA_SATURATE: {
+ float f = 1.0 - dst[3];
+ if (src[3] < f)
+ f = src[3];
+ sf[0] = sf[1] = sf[2] = f;
+ }
+ break;
+ case GL_CONSTANT_COLOR:
+ sf[0] = constantColor[0];
+ sf[1] = constantColor[1];
+ sf[2] = constantColor[2];
+ break;
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ sf[0] = 1.0 - constantColor[0];
+ sf[1] = 1.0 - constantColor[1];
+ sf[2] = 1.0 - constantColor[2];
+ break;
+ case GL_CONSTANT_ALPHA:
+ sf[0] =
+ sf[1] =
+ sf[2] = constantColor[3];
+ break;
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ sf[0] =
+ sf[1] =
+ sf[2] = 1.0 - constantColor[3];
+ break;
+ default:
+ sf[0] = sf[1] = sf[2] = 0.0;
+ abort();
+ break;
+ }
+
+ // Dest RGB term
+ switch (dstFactorRGB) {
+ case GL_ZERO:
+ df[0] = df[1] = df[2] = 0.0;
+ break;
+ case GL_ONE:
+ df[0] = df[1] = df[2] = 1.0;
+ break;
+ case GL_SRC_COLOR:
+ df[0] = src[0];
+ df[1] = src[1];
+ df[2] = src[2];
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ df[0] = 1.0 - src[0];
+ df[1] = 1.0 - src[1];
+ df[2] = 1.0 - src[2];
+ break;
+ case GL_SRC_ALPHA:
+ df[0] = df[1] = df[2] = src[3];
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ df[0] = df[1] = df[2] = 1.0 - src[3];
+ break;
+ case GL_DST_ALPHA:
+ df[0] = df[1] = df[2] = dst[3];
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ df[0] = df[1] = df[2] = 1.0 - dst[3];
+ break;
+ case GL_CONSTANT_COLOR:
+ df[0] = constantColor[0];
+ df[1] = constantColor[1];
+ df[2] = constantColor[2];
+ break;
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ df[0] = 1.0 - constantColor[0];
+ df[1] = 1.0 - constantColor[1];
+ df[2] = 1.0 - constantColor[2];
+ break;
+ case GL_CONSTANT_ALPHA:
+ df[0] =
+ df[1] =
+ df[2] = constantColor[3];
+ break;
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ df[0] =
+ df[1] =
+ df[2] = 1.0 - constantColor[3];
+ break;
+ default:
+ df[0] = df[1] = df[2] = 0.0;
+ abort();
+ break;
}
- break;
- default:
- sf[0] = sf[1] = sf[2] = sf[3] = 0.0;
- break;
}
- float df[4];
- switch (dstFactor) {
- case GL_ZERO:
- df[0] = df[1] = df[2] = df[3] = 0.0;
+ if (opA != GL_MIN && opA != GL_MAX) {
+ // Src Alpha term
+ switch (srcFactorA) {
+ case GL_ZERO:
+ sf[3] = 0.0;
+ break;
+ case GL_ONE:
+ sf[3] = 1.0;
+ break;
+ case GL_DST_COLOR:
+ sf[3] = dst[3];
+ break;
+ case GL_ONE_MINUS_DST_COLOR:
+ sf[3] = 1.0 - dst[3];
+ break;
+ case GL_SRC_ALPHA:
+ sf[3] = src[3];
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ sf[3] = 1.0 - src[3];
+ break;
+ case GL_DST_ALPHA:
+ sf[3] = dst[3];
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ sf[3] = 1.0 - dst[3];
+ break;
+ case GL_SRC_ALPHA_SATURATE:
+ sf[3] = 1.0;
+ break;
+ case GL_CONSTANT_COLOR:
+ sf[3] = constantColor[3];
+ break;
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ sf[3] = 1.0 - constantColor[3];
+ break;
+ case GL_CONSTANT_ALPHA:
+ sf[3] = constantColor[3];
+ break;
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ sf[3] = 1.0 - constantColor[3];
+ break;
+ default:
+ sf[3] = 0.0;
+ abort();
+ break;
+ }
+
+ // Dst Alpha term
+ switch (dstFactorA) {
+ case GL_ZERO:
+ df[3] = 0.0;
+ break;
+ case GL_ONE:
+ df[3] = 1.0;
+ break;
+ case GL_SRC_COLOR:
+ df[3] = src[3];
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ df[3] = 1.0 - src[3];
+ break;
+ case GL_SRC_ALPHA:
+ df[3] = src[3];
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ df[3] = 1.0 - src[3];
+ break;
+ case GL_DST_ALPHA:
+ df[3] = dst[3];
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ df[3] = 1.0 - dst[3];
+ break;
+ case GL_CONSTANT_COLOR:
+ df[3] = constantColor[3];
+ break;
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ df[3] = 1.0 - constantColor[3];
+ break;
+ case GL_CONSTANT_ALPHA:
+ df[3] = constantColor[3];
+ break;
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ df[3] = 1.0 - constantColor[3];
+ break;
+ default:
+ df[3] = 0.0;
+ abort();
+ break;
+ }
+ }
+
+ switch (opRGB) {
+ case GL_FUNC_ADD:
+ dst[0] = clamp(src[0] * sf[0] + dst[0] * df[0]);
+ dst[1] = clamp(src[1] * sf[1] + dst[1] * df[1]);
+ dst[2] = clamp(src[2] * sf[2] + dst[2] * df[2]);
+ break;
+ case GL_FUNC_SUBTRACT:
+ dst[0] = clamp(src[0] * sf[0] - dst[0] * df[0]);
+ dst[1] = clamp(src[1] * sf[1] - dst[1] * df[1]);
+ dst[2] = clamp(src[2] * sf[2] - dst[2] * df[2]);
break;
- case GL_ONE:
- df[0] = df[1] = df[2] = df[3] = 1.0;
+ case GL_FUNC_REVERSE_SUBTRACT:
+ dst[0] = clamp(dst[0] * df[0] - src[0] * sf[0]);
+ dst[1] = clamp(dst[1] * df[1] - src[1] * sf[1]);
+ dst[2] = clamp(dst[2] * df[2] - src[2] * sf[2]);
break;
- case GL_SRC_COLOR:
- df[0] = src[0]; df[1] = src[1]; df[2] = src[2]; df[3] = src[3];
+ case GL_MIN:
+ dst[0] = min(src[0], dst[0]);
+ dst[1] = min(src[1], dst[1]);
+ dst[2] = min(src[2], dst[2]);
break;
- case GL_ONE_MINUS_SRC_COLOR:
- df[0] = 1.0 - src[0]; df[1] = 1.0 - src[1];
- df[2] = 1.0 - src[2]; df[3] = 1.0 - src[3];
+ case GL_MAX:
+ dst[0] = max(src[0], dst[0]);
+ dst[1] = max(src[1], dst[1]);
+ dst[2] = max(src[2], dst[2]);
break;
- case GL_SRC_ALPHA:
- df[0] = df[1] = df[2] = df[3] = src[3];
+ default:
+ abort();
+ }
+
+ switch (opA) {
+ case GL_FUNC_ADD:
+ dst[3] = clamp(src[3] * sf[3] + dst[3] * df[3]);
break;
- case GL_ONE_MINUS_SRC_ALPHA:
- df[0] = df[1] = df[2] = df[3] = 1.0 - src[3];
+ case GL_FUNC_SUBTRACT:
+ dst[3] = clamp(src[3] * sf[3] - dst[3] * df[3]);
break;
- case GL_DST_ALPHA:
- df[0] = df[1] = df[2] = df[3] = dst[3];
+ case GL_FUNC_REVERSE_SUBTRACT:
+ dst[3] = clamp(dst[3] * df[3] - src[3] * sf[3]);
break;
- case GL_ONE_MINUS_DST_ALPHA:
- df[0] = df[1] = df[2] = df[3] = 1.0 - dst[3];
+ case GL_MIN:
+ dst[3] = min(src[3], dst[3]);
break;
- default:
- df[0] = df[1] = df[2] = df[3] = 0.0;
+ case GL_MAX:
+ dst[3] = max(src[3], dst[3]);
break;
- }
+ default:
+ abort();
+ }
- dst[0] = clamp(src[0] * sf[0] + dst[0] * df[0]);
- dst[1] = clamp(src[1] * sf[1] + dst[1] * df[1]);
- dst[2] = clamp(src[2] * sf[2] + dst[2] * df[2]);
- dst[3] = clamp(src[3] * sf[3] + dst[3] * df[3]);
} // applyBlend
-struct runFactorsResult {
- float readbackErrorBits;
- float blendRGBErrorBits;
- float blendAlphaErrorBits;
-};
-runFactorsResult
-runFactors(GLenum srcFactor, GLenum dstFactor,
- GLEAN::DrawingSurfaceConfig& config, GLEAN::Environment& env,
- float rgbTolerance, float alphaTolerance) {
- using namespace GLEAN;
+namespace GLEAN {
+
+BlendFuncTest::runFactorsResult
+BlendFuncTest::runFactors(GLenum srcFactorRGB, GLenum srcFactorA,
+ GLenum dstFactorRGB, GLenum dstFactorA,
+ GLenum opRGB, GLenum opA,
+ const GLfloat constantColor[4],
+ GLEAN::DrawingSurfaceConfig& config,
+ GLEAN::Environment& env)
+{
+ using namespace GLEAN;
+
runFactorsResult result;
int y;
@@ -262,7 +508,17 @@ runFactors(GLenum srcFactor, GLenum dstFactor,
Image src(drawingSize, drawingSize, GL_RGBA, GL_FLOAT);
RandomBitsDouble srcARand(16, 42);
- glBlendFunc(srcFactor, dstFactor);
+ if (haveSepFunc)
+ glBlendFuncSeparate_func(srcFactorRGB, dstFactorRGB,
+ srcFactorA, dstFactorA);
+ else
+ glBlendFunc(srcFactorRGB, dstFactorRGB);
+
+ if (haveBlendEquationSep)
+ glBlendEquationSeparate_func(opRGB, opA);
+ else if (haveBlendEquation)
+ glBlendEquation_func(opRGB);
+
glEnable(GL_BLEND);
dRow = expected.pixels();
@@ -278,7 +534,10 @@ runFactors(GLenum srcFactor, GLenum dstFactor,
sPix[2] = rgba[2];
sPix[3] = rgba[3];
drawQuad(x + 1, y + 1, rgba);
- applyBlend(srcFactor, dstFactor, pix, rgba);
+ applyBlend(srcFactorRGB, srcFactorA,
+ dstFactorRGB, dstFactorA,
+ opRGB, opA,
+ pix, rgba, constantColor);
pix += 4;
sPix += 4;
}
@@ -294,8 +553,7 @@ runFactors(GLenum srcFactor, GLenum dstFactor,
// maximum error encountered.
Image actual(drawingSize, drawingSize, GL_RGBA, GL_FLOAT);
actual.read(1, 1);
- result.blendRGBErrorBits = 0.0;
- result.blendAlphaErrorBits = 0.0;
+ result.blendErrorBits = 0.0;
sRow = actual.pixels();
dRow = expected.pixels();
for (/*int */y = 0; y < drawingSize; ++y) {
@@ -306,15 +564,13 @@ runFactors(GLenum srcFactor, GLenum dstFactor,
float gError = fabs(aPix[1] - ePix[1]);
float bError = fabs(aPix[2] - ePix[2]);
float aError = fabs(aPix[3] - ePix[3]);
- result.blendRGBErrorBits =
- max(static_cast<double>(result.blendRGBErrorBits),
+ result.blendErrorBits =
+ max(static_cast<double>(result.blendErrorBits),
max(ErrorBits(rError, config.r),
max(ErrorBits(gError, config.g),
- ErrorBits(bError, config.b))));
- result.blendAlphaErrorBits =
- max(static_cast<double>(result.blendAlphaErrorBits),
- ErrorBits(aError, config.a));
- if (result.blendRGBErrorBits > rgbTolerance || result.blendAlphaErrorBits > alphaTolerance) {
+ max(ErrorBits(bError, config.b),
+ ErrorBits(aError, config.a)))));
+ if (result.blendErrorBits > 1.0) {
if (env.options.verbosity) {
float* sPix = reinterpret_cast<float*>(src.pixels()
+ y * src.rowSizeInBytes() + x * 4 * sizeof(float));
@@ -345,9 +601,44 @@ env.log << '\n'
return result;
} // runOneSet
-} // anonymous namespace
-namespace GLEAN {
+bool
+BlendFuncTest::runCombo(BlendFuncResult& r, Window& w,
+ BlendFuncResult::PartialResult p,
+ GLEAN::Environment& env)
+{
+ runFactorsResult res(runFactors(p.srcRGB, p.srcA, p.dstRGB, p.dstA,
+ p.opRGB, p.opA, p.constColor,
+ *(r.config), env));
+ w.swap();
+
+ p.rbErr = res.readbackErrorBits;
+ p.blErr = res.blendErrorBits;
+ r.results.push_back(p);
+
+ if (p.rbErr > 1.0 || p.blErr > 1.0) {
+ env.log << name << ": FAIL "
+ << r.config->conciseDescription() << '\n'
+ << "\tsource factor RGB = " << factorToName(p.srcRGB)
+ << ", source factor A = " << factorToName(p.srcA)
+ << "\n\tdest factor RGB = " << factorToName(p.dstRGB)
+ << ", dest factor A = " << factorToName(p.dstA)
+ << "\n\tequation RGB = " << opToName(p.opRGB)
+ << ", equation A = " << opToName(p.opA)
+ << "\n\tconst color = { "
+ << p.constColor[0] << ", "
+ << p.constColor[1] << ", "
+ << p.constColor[2] << ", "
+ << p.constColor[3] << " }"
+ << "\n\tReadback had " << p.rbErr
+ << " bits in error; blending had "
+ << p.blErr << " bits in error.\n";
+ return false;
+ }
+ return true;
+}
+
+
///////////////////////////////////////////////////////////////////////////////
// runOne: Run a single test case
@@ -365,7 +656,11 @@ BlendFuncTest::runOne(BlendFuncResult& r, Window& w) {
GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA,
- GL_SRC_ALPHA_SATURATE
+ GL_SRC_ALPHA_SATURATE,
+ GL_CONSTANT_COLOR,
+ GL_ONE_MINUS_CONSTANT_COLOR,
+ GL_CONSTANT_ALPHA,
+ GL_ONE_MINUS_CONSTANT_ALPHA
};
static GLenum dstFactors[] = {
GL_ZERO,
@@ -375,64 +670,170 @@ BlendFuncTest::runOne(BlendFuncResult& r, Window& w) {
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
- GL_ONE_MINUS_DST_ALPHA
+ GL_ONE_MINUS_DST_ALPHA,
+ GL_CONSTANT_COLOR,
+ GL_ONE_MINUS_CONSTANT_COLOR,
+ GL_CONSTANT_ALPHA,
+ GL_ONE_MINUS_CONSTANT_ALPHA
+ };
+ static GLenum operators[] = {
+ GL_FUNC_ADD,
+ GL_FUNC_SUBTRACT,
+ GL_FUNC_REVERSE_SUBTRACT,
+ GL_MIN,
+ GL_MAX
};
- // Hack: Make driver tests on incorrect hardware feasible
- // by adjusting the error tolerance to whatever the hardware can do
- float rgbTolerance = 1.0;
- float alphaTolerance = 1.0;
- const char* s;
+ unsigned numSrcFactorsSep, numDstFactorsSep;
+ unsigned numOperatorsRGB, numOperatorsA;
+ BlendFuncResult::PartialResult p;
+ bool allPassed = true;
- s = getenv("GLEAN_BLEND_RGB_TOLERANCE");
- if (s) {
- rgbTolerance = atof(s);
- env->log << "Note: RGB tolerance adjusted to " << rgbTolerance << "\n";
+ // test for features, get function pointers
+ if (GLUtils::getVersion() >= 1.4) {
+ haveSepFunc = true;
+ glBlendFuncSeparate_func = (PFNGLBLENDFUNCSEPARATEPROC)
+ GLUtils::getProcAddress("glBlendFuncSeparate");
}
- s = getenv("GLEAN_BLEND_ALPHA_TOLERANCE");
- if (s) {
- alphaTolerance = atof(s);
- env->log << "Note: Alpha tolerance adjusted to " << alphaTolerance << "\n";
+ else if (GLUtils::haveExtension("GL_EXT_blend_func_separate")) {
+ haveSepFunc = true;
+ glBlendFuncSeparate_func = (PFNGLBLENDFUNCSEPARATEPROC)
+ GLUtils::getProcAddress("glBlendFuncSeparateEXT");
}
- bool allPassed = true;
- for (unsigned int sf = 0; sf < sizeof(srcFactors)/sizeof(srcFactors[0]);
- ++sf)
-
- for (unsigned int df = 0;
- df < sizeof(dstFactors)/sizeof(dstFactors[0]); ++df) {
-
- BlendFuncResult::PartialResult p;
- p.src = srcFactors[sf];
- p.dst = dstFactors[df];
-
- if ((needsDstAlpha(p.src) || needsDstAlpha(p.dst))
- && (r.config->a == 0))
- continue;
-
- runFactorsResult res(runFactors(p.src, p.dst,
- *(r.config), *env, rgbTolerance, alphaTolerance));
- w.swap();
-
- p.rbErr = res.readbackErrorBits;
- p.blRGBErr = res.blendRGBErrorBits;
- p.blAErr = res.blendAlphaErrorBits;
- r.results.push_back(p);
-
- if (p.rbErr > 1.0 || p.blRGBErr > rgbTolerance || p.blAErr > alphaTolerance) {
- env->log << name << ": FAIL "
- << r.config->conciseDescription()<< '\n'
- << "\tsource factor = "
- << factorToName(p.src)
- << ", dest factor = "
- << factorToName(p.dst)
- << "\n\tReadback had " << p.rbErr
- << " bits in error; RGB blending had "
- << p.blRGBErr << " bits in error, Alpha blending had "
- << p.blAErr << " bits in error.\n";
- allPassed = false;
+ if (GLUtils::getVersion() >= 1.4) {
+ haveBlendColor = true;
+ glBlendColor_func = (PFNGLBLENDCOLORPROC)
+ GLUtils::getProcAddress("glBlendColor");
+ }
+ else if (GLUtils::haveExtension("GL_EXT_blend_color")) {
+ haveBlendColor = true;
+ glBlendColor_func = (PFNGLBLENDCOLORPROC)
+ GLUtils::getProcAddress("glBlendColorEXT");
+ }
+
+ if (GLUtils::getVersion() >= 1.4) {
+ haveBlendEquation = true;
+ glBlendEquation_func = (PFNGLBLENDEQUATIONPROC)
+ GLUtils::getProcAddress("glBlendEquation");
+ }
+ else if (GLUtils::haveExtension("GL_EXT_blend_subtract") &&
+ GLUtils::haveExtension("GL_EXT_blend_min_max")) {
+ haveBlendEquation = true;
+ glBlendEquation_func = (PFNGLBLENDEQUATIONPROC)
+ GLUtils::getProcAddress("glBlendEquationEXT");
+ }
+
+ if (GLUtils::getVersion() >= 2.0) {
+ haveBlendEquationSep = true;
+ glBlendEquationSeparate_func = (PFNGLBLENDEQUATIONSEPARATEPROC)
+ GLUtils::getProcAddress("glBlendEquationSeparate");
+ }
+ else if (GLUtils::haveExtension("GL_EXT_blend_equation_separate")) {
+ haveBlendEquationSep = true;
+ glBlendEquationSeparate_func = (PFNGLBLENDEQUATIONSEPARATEPROC)
+ GLUtils::getProcAddress("glBlendEquationSeparateEXT");
+ }
+
+ if (haveBlendColor) {
+ // Just one blend color setting for all tests
+ p.constColor[0] = 0.25;
+ p.constColor[1] = 0.0;
+ p.constColor[2] = 1.0;
+ p.constColor[3] = 0.75;
+ glBlendColor_func(p.constColor[0], p.constColor[1],
+ p.constColor[2], p.constColor[3]);
+ }
+
+ if (haveSepFunc) {
+ numSrcFactorsSep = ELEMENTS(srcFactors);
+ numDstFactorsSep = ELEMENTS(dstFactors);
+ }
+ else {
+ numSrcFactorsSep = 1;
+ numDstFactorsSep = 1;
+ }
+
+ if (haveBlendEquation) {
+ numOperatorsRGB = ELEMENTS(operators);
+ numOperatorsA = ELEMENTS(operators);
+ }
+ else {
+ numOperatorsRGB = 1; // just ADD
+ numOperatorsA = 1; // just ADD
+ }
+
+#if 0
+ // use this to test a single combination:
+ p.srcRGB = p.srcA = GL_SRC_ALPHA;
+ p.dstRGB = p.dstA = GL_ONE_MINUS_SRC_ALPHA;
+ p.opRGB = GL_FUNC_ADD;
+ p.opA = GL_FUNC_ADD;
+ allPassed = runCombo(r, w, p, *env);
+#else
+ for (unsigned int op = 0; op < numOperatorsRGB; ++op) {
+ p.opRGB = operators[op];
+
+ for (unsigned int opa = 0; opa < numOperatorsA; ++opa) {
+ p.opA = operators[opa];
+
+ unsigned int step;
+ if (p.opRGB == GL_FUNC_ADD && p.opA == GL_FUNC_ADD) {
+ // test _all_ blend term combinations
+ step = 1;
+ }
+ else if (p.opRGB == GL_MIN || p.opRGB == GL_MAX ||
+ p.opA == GL_MIN || p.opA == GL_MAX) {
+ // blend terms are N/A so only do one iteration of loops
+ step = 1000;
+ }
+ else {
+ // subtract modes: do every 3rd blend term for speed
+ step = 3;
+ }
+
+ for (unsigned int sf = 0; sf < ELEMENTS(srcFactors); sf += step) {
+ for (unsigned int sfa = 0; sfa < numSrcFactorsSep; sfa += step) {
+ for (unsigned int df = 0; df < ELEMENTS(dstFactors); df += step) {
+ for (unsigned int dfa = 0; dfa < numDstFactorsSep; dfa += step) {
+
+ if (haveSepFunc) {
+ p.srcRGB = srcFactors[sf];
+ p.srcA = srcFactors[sfa];
+ p.dstRGB = dstFactors[df];
+ p.dstA = dstFactors[dfa];
+ }
+ else {
+ p.srcRGB = p.srcA = srcFactors[sf];
+ p.dstRGB = p.dstA = dstFactors[df];
+ }
+
+ // skip test if it depends on non-existant alpha channel
+ if ((r.config->a == 0)
+ && (needsDstAlpha(p.srcRGB) ||
+ needsDstAlpha(p.srcA) ||
+ needsDstAlpha(p.dstRGB) ||
+ needsDstAlpha(p.dstA)))
+ continue;
+
+ // skip test if blend color used, but not supported.
+ if (!haveBlendColor
+ && (needsBlendColor(p.srcRGB) ||
+ needsBlendColor(p.srcA) ||
+ needsBlendColor(p.dstRGB) ||
+ needsBlendColor(p.dstA)))
+ continue;
+
+ if (!runCombo(r, w, p, *env)) {
+ allPassed = false;
+ }
+ }
+ }
+ }
}
}
+ }
+#endif
r.pass = allPassed;
} // BlendFuncTest::runOne
@@ -449,6 +850,37 @@ BlendFuncTest::logOne(BlendFuncResult& r) {
}
+bool
+BlendFuncTest::equalMode(const BlendFuncResult::PartialResult &r1,
+ const BlendFuncResult::PartialResult &r2) const
+{
+ return (r1.srcRGB == r2.srcRGB &&
+ r1.srcA == r2.srcA &&
+ r1.dstRGB == r2.dstRGB &&
+ r1.dstA == r2.dstA &&
+ r1.opRGB == r2.opRGB &&
+ r1.opA == r2.opA);
+}
+
+
+void
+BlendFuncTest::printMode(const BlendFuncResult::PartialResult &r) const
+{
+ env->log << "\t\t"
+ << factorToName(r.srcRGB)
+ << ' '
+ << factorToName(r.srcA)
+ << ' '
+ << factorToName(r.dstRGB)
+ << ' '
+ << factorToName(r.dstA)
+ << ' '
+ << opToName(r.opRGB)
+ << ' '
+ << opToName(r.opA)
+ << '\n';
+}
+
///////////////////////////////////////////////////////////////////////////////
// compareOne: Compare results for a single test case
///////////////////////////////////////////////////////////////////////////////
@@ -463,15 +895,14 @@ BlendFuncTest::compareOne(BlendFuncResult& oldR, BlendFuncResult& newR) {
for (np = newR.results.begin(); np != newR.results.end(); ++np)
// Find the matching case, if any, in the old results:
for (op = oldR.results.begin(); op != oldR.results.end(); ++op)
- if (np->src == op->src && np->dst == op->dst) {
+ if (equalMode(*np, *op)) {
readbackStats.sample(np->rbErr - op->rbErr);
- blendStats.sample(np->blRGBErr - op->blRGBErr);
- blendStats.sample(np->blAErr - op->blAErr);
+ blendStats.sample(np->blErr - op->blErr);
}
if (readbackStats.n() == static_cast<int>(newR.results.size())
- && newR.results.size() == oldR.results.size()
- && readbackStats.mean() == 0.0 && blendStats.mean() == 0.0) {
+ && newR.results.size() == oldR.results.size()
+ && readbackStats.mean() == 0.0 && blendStats.mean() == 0.0) {
if (env->options.verbosity)
env->log << name << ": SAME "
<< newR.config->conciseDescription() << '\n';
@@ -501,15 +932,10 @@ BlendFuncTest::compareOne(BlendFuncResult& oldR, BlendFuncResult& newR) {
np != newR.results.end(); ++np) {
for (op = oldR.results.begin();
op != oldR.results.end(); ++op)
- if (np->src == op->src
- && np->dst == op->dst)
+ if (equalMode(*np, *op))
break;
if (op == oldR.results.end())
- env->log << "\t\t"
- << factorToName(np->src)
- << ' '
- << factorToName(np->dst)
- << '\n';
+ printMode(*np);
}
}
if (readbackStats.n() != static_cast<int>(oldR.results.size())){
@@ -522,15 +948,10 @@ BlendFuncTest::compareOne(BlendFuncResult& oldR, BlendFuncResult& newR) {
op != oldR.results.end(); ++op) {
for (np = newR.results.begin();
np != newR.results.end(); ++np)
- if (op->src == np->src
- && op->dst == np->dst)
+ if (equalMode(*op, *np))
break;
if (np == newR.results.end())
- env->log << "\t\t"
- << factorToName(op->src)
- << ' '
- << factorToName(op->dst)
- << '\n';
+ printMode(*op);
}
}
if (env->options.verbosity) {
@@ -543,15 +964,10 @@ BlendFuncTest::compareOne(BlendFuncResult& oldR, BlendFuncResult& newR) {
np != newR.results.end(); ++np){
for (op = oldR.results.begin();
op != oldR.results.end(); ++op)
- if (np->src == op->src
- && np->dst == op->dst)
+ if (equalMode(*op, *np))
break;
if (op != oldR.results.end())
- env->log << "\t\t"
- << factorToName(np->src)
- << ' '
- << factorToName(np->dst)
- << '\n';
+ printMode(*op);
}
}
}
@@ -565,9 +981,13 @@ BlendFuncResult::putresults(ostream& s) const {
s << results.size() << '\n';
for (vector<PartialResult>::const_iterator p = results.begin();
p != results.end(); ++p)
- s << factorToName(p->src) << ' '
- << factorToName(p->dst) << ' '
- << p->rbErr << ' ' << p->blRGBErr << ' ' << p->blAErr << '\n';
+ s << factorToName(p->srcRGB) << ' '
+ << factorToName(p->srcA) << ' '
+ << factorToName(p->dstRGB) << ' '
+ << factorToName(p->dstA) << ' '
+ << opToName(p->opRGB) << ' '
+ << opToName(p->opA) << ' '
+ << p->rbErr << ' ' << p->blErr << '\n';
} // BlendFuncResult::put
bool
@@ -576,11 +996,16 @@ BlendFuncResult::getresults(istream& s) {
s >> n;
for (int i = 0; i < n; ++i) {
PartialResult p;
- string src;
- string dst;
- s >> src >> dst >> p.rbErr >> p.blRGBErr >> p.blAErr;
- p.src = nameToFactor(src);
- p.dst = nameToFactor(dst);
+ string srcRGB, srcA;
+ string dstRGB, dstA;
+ string opRGB, opA;
+ s >> srcRGB >> srcA >> dstRGB >> dstA >> opRGB >> opA >> p.rbErr >> p.blErr;
+ p.srcRGB = nameToFactor(srcRGB);
+ p.srcA = nameToFactor(srcA);
+ p.srcRGB = nameToFactor(srcRGB);
+ p.dstA = nameToFactor(dstA);
+ p.opRGB = nameToFactor(opRGB);
+ p.opA = nameToFactor(opA);
results.push_back(p);
}
diff --git a/tests/glean/tblend.h b/tests/glean/tblend.h
index 5a83902c3..abf3c80a8 100644
--- a/tests/glean/tblend.h
+++ b/tests/glean/tblend.h
@@ -1,7 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
-//
+//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -10,11 +10,11 @@
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the
// Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
@@ -23,7 +23,7 @@
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-//
+//
// END_COPYRIGHT
// tblend.h: Test blending functions.
@@ -35,7 +35,7 @@
namespace GLEAN {
-#define drawingSize 64 // We will check each pair of blend factors
+#define drawingSize 32 // We will check each pair of blend factors
// for each pixel in a square image of this
// dimension, so if you make it too large,
// the tests may take quite a while to run.
@@ -46,14 +46,15 @@ public:
bool pass; // not written to log file
struct PartialResult {
- GLenum src; // Source blend factor.
- GLenum dst; // Destination blend factor.
+ GLenum srcRGB, srcA; // Source blend factor.
+ GLenum dstRGB, dstA; // Destination blend factor.
+ GLenum opRGB, opA; // Operator (add, sub, min, max)
+ GLfloat constColor[4];
float rbErr; // Max readback error, in bits.
- float blRGBErr; // Max RGB blend error, in bits.
- float blAErr; // Max Alpha blend error, in bits.
+ float blErr; // Max blend error, in bits.
};
vector<PartialResult> results;
-
+
virtual void putresults(ostream& s) const;
virtual bool getresults(istream& s);
};
@@ -62,6 +63,34 @@ class BlendFuncTest: public BaseTest<BlendFuncResult> {
public:
GLEAN_CLASS_WH(BlendFuncTest, BlendFuncResult,
windowSize, windowSize);
+
+private:
+ struct runFactorsResult {
+ float readbackErrorBits;
+ float blendErrorBits;
+ };
+
+ runFactorsResult runFactors(GLenum srcFactorRGB, GLenum srcFactorA,
+ GLenum dstFactorRGB, GLenum dstFactorA,
+ GLenum opRGB, GLenum opA,
+ const GLfloat constantColor[4],
+ GLEAN::DrawingSurfaceConfig& config,
+ GLEAN::Environment& env);
+
+ bool runCombo(BlendFuncResult& r, Window& w,
+ BlendFuncResult::PartialResult p,
+ GLEAN::Environment& env);
+
+ bool equalMode(const BlendFuncResult::PartialResult &r1,
+ const BlendFuncResult::PartialResult &r2) const;
+
+ void printMode(const BlendFuncResult::PartialResult &r) const;
+
+ bool haveSepFunc;
+ bool haveBlendEquation;
+ bool haveBlendEquationSep;
+ bool haveBlendColor;
+
}; // class BlendFuncTest
} // namespace GLEAN
diff --git a/tests/glean/tdepthstencil.cpp b/tests/glean/tdepthstencil.cpp
index f691d2cf8..945d8bd1c 100644
--- a/tests/glean/tdepthstencil.cpp
+++ b/tests/glean/tdepthstencil.cpp
@@ -44,6 +44,15 @@ namespace GLEAN {
static PFNGLWINDOWPOS2IARBPROC WindowPos2i = NULL;
+DepthStencilResult::DepthStencilResult()
+{
+ pass = false;
+ readDepthStencilRate = 0;
+ readDepthUintRate = 0;
+ readDepthUshortRate = 0;
+}
+
+
bool
DepthStencilTest::checkError(const char *where)
{
diff --git a/tests/glean/tdepthstencil.h b/tests/glean/tdepthstencil.h
index 9c915ecc0..0709f733c 100644
--- a/tests/glean/tdepthstencil.h
+++ b/tests/glean/tdepthstencil.h
@@ -47,6 +47,8 @@ public:
double readDepthUintRate; // pixels/second
double readDepthUshortRate; // pixels/second
+ DepthStencilResult();
+
virtual void putresults(ostream& s) const;
virtual bool getresults(istream& s);
};
diff --git a/tests/glean/test.h b/tests/glean/test.h
index 1d6e78c47..55da31769 100644
--- a/tests/glean/test.h
+++ b/tests/glean/test.h
@@ -1,7 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
-//
+//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -10,11 +10,11 @@
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the
// Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
@@ -23,7 +23,7 @@
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-//
+//
// END_COPYRIGHT
@@ -43,7 +43,7 @@
// vary depending on the drawing surface configuration or the
// particular type of drawing surface used).
-// It is possible to derive test classes directly from this class.
+// It is possible to derive test classes directly from this class.
// Most people will find it more convenient to use the BaseTest
// template class. See tbase.h for more information.
@@ -90,7 +90,7 @@ class Test {
Test** prereqs; // Pointer to array of prerequisite tests.
// These will always be run before the
// current test.
-
+
bool hasRun; // True if test has been run.
Environment* env; // Environment in which runs or comparisons
@@ -99,8 +99,6 @@ class Test {
virtual void run(Environment& env) = 0; // Run test, save results.
virtual void compare(Environment& env) = 0;
-
- virtual void details(Environment& env) = 0;
// Compare two previous runs.
// Exceptions:
diff --git a/tests/glean/tfragprog1.cpp b/tests/glean/tfragprog1.cpp
index 632a5af29..b1a59bd93 100644
--- a/tests/glean/tfragprog1.cpp
+++ b/tests/glean/tfragprog1.cpp
@@ -1,7 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
-//
+//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -10,11 +10,11 @@
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the
// Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
@@ -23,7 +23,7 @@
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-//
+//
// END_COPYRIGHT
// tfragprog.cpp: Test GL_ARB_fragment_program extension.
@@ -103,7 +103,6 @@ static const FragmentProgram Programs[] = {
ABS(Param2[3])
},
DONT_CARE_Z,
- false,
},
{
"ADD test",
@@ -116,8 +115,7 @@ static const FragmentProgram Programs[] = {
CLAMP01(FragColor[2] + Param1[2]),
CLAMP01(FragColor[3] + Param1[3])
},
- DONT_CARE_Z,
- false,
+ DONT_CARE_Z
},
{
"CMP test",
@@ -128,8 +126,7 @@ static const FragmentProgram Programs[] = {
"CMP result.color, p2, zero, p1; \n"
"END \n",
{ Param0[0], Param1[1], Param1[2], Param0[3] },
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"COS test",
@@ -145,8 +142,23 @@ static const FragmentProgram Programs[] = {
CLAMP01(0.8775),
CLAMP01(0.5403)
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
+ },
+ {
+ "COS test 2",
+ "!!ARBfp1.0\n"
+ "PARAM values = { 6.78318, 7.28318, 6.28318, -5.78318 }; \n"
+ "COS result.color.x, values.x; \n"
+ "COS result.color.y, values.y; \n"
+ "COS result.color.z, values.z; \n"
+ "COS result.color.w, values.w; \n"
+ "END \n",
+ { CLAMP01(0.8775),
+ CLAMP01(0.5403),
+ CLAMP01(1.0),
+ CLAMP01(0.8775)
+ },
+ DONT_CARE_Z
},
{
"DP3 test",
@@ -158,8 +170,7 @@ static const FragmentProgram Programs[] = {
Param1[1] * FragColor[1] +
Param1[2] * FragColor[2]))
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"DP4 test",
@@ -172,8 +183,7 @@ static const FragmentProgram Programs[] = {
Param1[2] * FragColor[2] +
Param1[3] * FragColor[3]))
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"DPH test",
@@ -189,8 +199,7 @@ static const FragmentProgram Programs[] = {
Param1[2] * FragColor[2] +
FragColor[3]) * 0.1))
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"DST test",
@@ -205,8 +214,7 @@ static const FragmentProgram Programs[] = {
0.16, // v1.z
CLAMP01(2.5) // v2.w
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"EX2 test",
@@ -224,8 +232,7 @@ static const FragmentProgram Programs[] = {
2.0 * 0.01,
16.0 * 0.01,
0.25 * 0.01 },
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"FLR test",
@@ -241,8 +248,7 @@ static const FragmentProgram Programs[] = {
CLAMP01(-0.1),
0.1
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"FRC test",
@@ -251,8 +257,7 @@ static const FragmentProgram Programs[] = {
"FRC result.color, values; \n"
"END \n",
{ 0.9, 0.1, 0.8, 0.4 },
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"LG2 test",
@@ -271,8 +276,7 @@ static const FragmentProgram Programs[] = {
0.49,
0.2
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"LIT test 1",
@@ -285,8 +289,7 @@ static const FragmentProgram Programs[] = {
0.433, // roughly Pow(values.y, values.w)
1.0
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"LIT test 2 (degenerate case: 0 ^ 0 -> 1)",
@@ -299,8 +302,7 @@ static const FragmentProgram Programs[] = {
1.0, // 0^0
1.0
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"LIT test 3 (case x < 0)",
@@ -313,8 +315,7 @@ static const FragmentProgram Programs[] = {
0.0,
1.0
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"LRP test",
@@ -328,8 +329,7 @@ static const FragmentProgram Programs[] = {
1.0 * FragColor[2] + (1.0 - 1.0) * Param1[2],
0.0 * FragColor[3] + (1.0 - 0.0) * Param1[3]
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"MAD test",
@@ -343,8 +343,7 @@ static const FragmentProgram Programs[] = {
CLAMP01(FragColor[2] * Param1[2] + Param2[2]),
CLAMP01(FragColor[3] * Param1[3] + Param2[3])
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"MAX test",
@@ -358,8 +357,7 @@ static const FragmentProgram Programs[] = {
MAX(Param1[2], Param2[2]),
MAX(Param1[3], Param2[3]),
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"MIN test",
@@ -372,8 +370,7 @@ static const FragmentProgram Programs[] = {
MIN(Param1[2], FragColor[2]),
MIN(Param1[3], FragColor[3]),
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"MOV test",
@@ -382,7 +379,6 @@ static const FragmentProgram Programs[] = {
"END \n",
FRAGCOLOR,
DONT_CARE_Z,
- false
},
{
"MUL test",
@@ -395,8 +391,7 @@ static const FragmentProgram Programs[] = {
CLAMP01(FragColor[2] * Param1[2]),
CLAMP01(FragColor[3] * Param1[3])
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"masked MUL test",
@@ -411,8 +406,7 @@ static const FragmentProgram Programs[] = {
0.0,
0.0
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"POW test (exponentiation)",
@@ -427,8 +421,7 @@ static const FragmentProgram Programs[] = {
0.5 * 0.5 * 0.5,
0.5 * 0.5 * 0.5 * 0.5,
CLAMP01(2.0) },
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"RCP test (reciprocal)",
@@ -440,8 +433,7 @@ static const FragmentProgram Programs[] = {
"RCP result.color.w, values.w; \n"
"END \n",
{ 1.0 / 8.0, CLAMP01(1.0 / -10.0), 1, 1.0 / 12.0 },
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"RSQ test 1 (reciprocal square root)",
@@ -453,8 +445,7 @@ static const FragmentProgram Programs[] = {
"RSQ result.color.w, values.w; \n"
"END \n",
{ 1.0, 0.5, 0.3333, 0.1 },
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"RSQ test 2 (reciprocal square root of negative value)",
@@ -470,8 +461,7 @@ static const FragmentProgram Programs[] = {
0.447,
1.0,
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"SCS test",
@@ -485,8 +475,7 @@ static const FragmentProgram Programs[] = {
DONT_CARE_COLOR,
DONT_CARE_COLOR,
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"SGE test",
@@ -500,8 +489,7 @@ static const FragmentProgram Programs[] = {
Param2[2] >= Param0[2] ? 1.0 : 0.0,
Param2[3] >= Param0[3] ? 1.0 : 0.0,
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"SIN test",
@@ -517,8 +505,23 @@ static const FragmentProgram Programs[] = {
CLAMP01(0.4794),
CLAMP01(0.8414)
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
+ },
+ {
+ "SIN test 2",
+ "!!ARBfp1.0\n"
+ "PARAM values = { 3.14159, -3.14159, 6.78319, -5.78319 }; \n"
+ "SIN result.color.x, values.x; \n"
+ "SIN result.color.y, values.y; \n"
+ "SIN result.color.z, values.z; \n"
+ "SIN result.color.w, values.w; \n"
+ "END \n",
+ { CLAMP01(0.0),
+ CLAMP01(0.0),
+ CLAMP01(0.4794),
+ CLAMP01(0.4794)
+ },
+ DONT_CARE_Z
},
{
"SLT test",
@@ -531,8 +534,7 @@ static const FragmentProgram Programs[] = {
FragColor[2] < Param1[2] ? 1.0 : 0.0,
FragColor[3] < Param1[3] ? 1.0 : 0.0,
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"SUB test (with swizzle)",
@@ -545,8 +547,7 @@ static const FragmentProgram Programs[] = {
CLAMP01(Param1[3] - FragColor[3]),
CLAMP01(Param1[2] - FragColor[2])
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"SWZ test",
@@ -559,8 +560,7 @@ static const FragmentProgram Programs[] = {
CLAMP01(Param1[2]),
CLAMP01(0.0)
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"XPD test 1",
@@ -574,8 +574,7 @@ static const FragmentProgram Programs[] = {
CLAMP01(Param1[0] * Param2[1] - Param1[1] * Param2[0]),
DONT_CARE_COLOR
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"Z-write test",
@@ -589,8 +588,7 @@ static const FragmentProgram Programs[] = {
Param1[2],
Param1[3]
},
- Param1[1],
- false
+ Param1[1]
},
// ============= Numeric stress tests =================================
@@ -610,8 +608,7 @@ static const FragmentProgram Programs[] = {
DONT_CARE_COLOR,
DONT_CARE_COLOR
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
{
"Infinity / nan test",
@@ -625,8 +622,7 @@ static const FragmentProgram Programs[] = {
DONT_CARE_COLOR,
DONT_CARE_COLOR
},
- DONT_CARE_Z,
- false
+ DONT_CARE_Z
},
// ============= Fog tests ============================================
@@ -643,8 +639,7 @@ static const FragmentProgram Programs[] = {
FragColor[2] * FOG_FACT + FogColor[2] * (1.0 - FOG_FACT),
FragColor[3]
},
- DONT_CARE_Z,
- true
+ DONT_CARE_Z
},
{
"Computed fog linear test",
@@ -668,8 +663,7 @@ static const FragmentProgram Programs[] = {
FragColor[2] * FOG_FACT + FogColor[2] * (1.0 - FOG_FACT),
FragColor[3]
},
- DONT_CARE_Z,
- true
+ DONT_CARE_Z
},
#undef FOG_FACT
@@ -686,8 +680,7 @@ static const FragmentProgram Programs[] = {
FragColor[2] * FOG_FACT + FogColor[2] * (1.0 - FOG_FACT),
FragColor[3]
},
- DONT_CARE_Z,
- true
+ DONT_CARE_Z
},
#undef FOG_FACT
#define FOG_FACT 0.3535 // = ex2(-Density * Coord)
@@ -714,8 +707,7 @@ static const FragmentProgram Programs[] = {
FragColor[2] * FOG_FACT + FogColor[2] * (1.0 - FOG_FACT),
FragColor[3]
},
- DONT_CARE_Z,
- true
+ DONT_CARE_Z
},
#undef FOG_FACT
@@ -732,8 +724,7 @@ static const FragmentProgram Programs[] = {
FragColor[2] * FOG_FACT + FogColor[2] * (1.0 - FOG_FACT),
FragColor[3]
},
- DONT_CARE_Z,
- true
+ DONT_CARE_Z
},
#undef FOG_FACT
#define FOG_FACT 0.2102 // = ex2(-(Density * Coord)^2)
@@ -761,13 +752,12 @@ static const FragmentProgram Programs[] = {
FragColor[2] * FOG_FACT + FogColor[2] * (1.0 - FOG_FACT),
FragColor[3]
},
- DONT_CARE_Z,
- true
+ DONT_CARE_Z
},
#undef FOG_FACT
// XXX add lots more tests here!
- { NULL, NULL, {0,0,0,0}, 0, false } // end of list sentinal
+ { NULL, NULL, {0,0,0,0}, 0 } // end of list sentinal
};
@@ -775,11 +765,6 @@ static const FragmentProgram Programs[] = {
void
FragmentProgramTest::setup(void)
{
- haveFogCoord = false;
-
- if (GLUtils::haveExtensions("EXT_fog_coord"))
- haveFogCoord = true;
-
// setup Infinity, Nan values
int nan;
float *nanPtr;
@@ -813,10 +798,8 @@ FragmentProgramTest::setup(void)
glGetProgramivARB_func = (PFNGLGETPROGRAMIVARBPROC) GLUtils::getProcAddress("glGetProgramivARB");
assert(glGetProgramivARB_func);
- if (haveFogCoord) {
- glFogCoordf_func = (PFNGLFOGCOORDFPROC) GLUtils::getProcAddress("glFogCoordf");
- assert(glFogCoordf_func);
- }
+ glFogCoordf_func = (PFNGLFOGCOORDFPROC) GLUtils::getProcAddress("glFogCoordf");
+ assert(glFogCoordf_func);
GLuint progID;
glGenProgramsARB_func(1, &progID);
@@ -844,17 +827,15 @@ FragmentProgramTest::setup(void)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDrawBuffer(GL_FRONT);
- glReadBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
// other GL state
- if (haveFogCoord) {
- glFogf(GL_FOG_START, FogStart);
- glFogf(GL_FOG_END, FogEnd);
- glFogf(GL_FOG_DENSITY, FogDensity);
- glFogfv(GL_FOG_COLOR, FogColor);
- glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
- glFogCoordf_func(FogCoord);
- }
+ glFogf(GL_FOG_START, FogStart);
+ glFogf(GL_FOG_END, FogEnd);
+ glFogf(GL_FOG_DENSITY, FogDensity);
+ glFogfv(GL_FOG_COLOR, FogColor);
+ glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
+ glFogCoordf_func(FogCoord);
// compute error tolerances (may need fine-tuning)
int bufferBits[5];
@@ -977,7 +958,7 @@ FragmentProgramTest::testProgram(const FragmentProgram &p)
printf("%s: Expect: %.3f %.3f %.3f %.3f found: %.3f %.3f %.3f %.3f\n",
p.name,
p.expectedColor[0], p.expectedColor[1],
- p.expectedColor[2], p.expectedColor[3],
+ p.expectedColor[2], p.expectedColor[3],
pixel[0], pixel[1], pixel[2], pixel[3]);
if (!equalColors(pixel, p.expectedColor)) {
@@ -1004,22 +985,10 @@ FragmentProgramTest::runOne(MultiTestResult &r, Window &w)
(void) w;
setup();
- const char* filter;
-
- filter = getenv("GLEAN_FRAGPROG");
- if (filter && !strlen(filter))
- filter = 0;
-
#if DEVEL_MODE
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
#endif
for (int i = 0; Programs[i].name; i++) {
- if (filter && strcmp(filter, Programs[i].name))
- continue;
-
- if (Programs[i].needFogCoord && !haveFogCoord)
- continue;
-
#if DEVEL_MODE
glViewport(0, i * 20, windowWidth, 20);
#endif
@@ -1038,13 +1007,6 @@ FragmentProgramTest::runOne(MultiTestResult &r, Window &w)
r.pass = (r.numFailed == 0);
}
-void
-FragmentProgramTest::printDetails()
-{
- for (int i = 0; Programs[i].name; i++)
- env->log << Programs[i].name << '\n';
-}
-
// The test object itself:
FragmentProgramTest fragmentProgramTest("fragProg1", "window, rgb, z",
diff --git a/tests/glean/tfragprog1.h b/tests/glean/tfragprog1.h
index b36e7a6f9..37656eb0b 100644
--- a/tests/glean/tfragprog1.h
+++ b/tests/glean/tfragprog1.h
@@ -1,7 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
-//
+//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -10,11 +10,11 @@
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the
// Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
@@ -23,7 +23,7 @@
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-//
+//
// END_COPYRIGHT
// tfragprog.h: Test GL_ARB_fragment_program extension.
@@ -32,10 +32,6 @@
#ifndef __tfragprog_h__
#define __tfragprog_h__
-#include "tmultitest.h"
-
-namespace GLEAN {
-
// If DEVEL_MODE==1 we generate a tall window of color swatches, one per
// fragment program, which can be eyeballed against a reference image.
// Use this if glReadPixels functionality is not working yet.
@@ -51,14 +47,18 @@ namespace GLEAN {
#endif
+#include "tmultitest.h"
+
+namespace GLEAN {
+
+
class FragmentProgram
{
public:
const char *name;
const char *progString;
- const GLfloat expectedColor[4];
- const GLfloat expectedZ;
- const bool needFogCoord;
+ GLfloat expectedColor[4];
+ GLfloat expectedZ;
};
@@ -75,8 +75,6 @@ public:
private:
GLfloat tolerance[5];
- bool haveFogCoord;
-
void setup(void);
bool equalColors(const GLfloat a[4], const GLfloat b[4]) const;
bool equalDepth(GLfloat z0, GLfloat z1) const;
@@ -86,7 +84,6 @@ private:
const GLfloat actualColor[4] ) const;
void reportZFailure(const char *programName,
GLfloat expectedZ, GLfloat actualZ) const;
- void printDetails();
};
} // namespace GLEAN
diff --git a/tests/glean/tglsl1.cpp b/tests/glean/tglsl1.cpp
new file mode 100644
index 000000000..397b3dc32
--- /dev/null
+++ b/tests/glean/tglsl1.cpp
@@ -0,0 +1,3396 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tglsl1.h: Test OpenGL shading language
+// Brian Paul 6 March 2007
+
+#define GL_GLEXT_PROTOTYPES
+
+#include "tglsl1.h"
+#include <cassert>
+#include <math.h>
+
+
+namespace GLEAN {
+
+
+static PFNGLATTACHSHADERPROC glAttachShader_func = NULL;
+static PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation_func = NULL;
+static PFNGLCOMPILESHADERPROC glCompileShader_func = NULL;
+static PFNGLCREATEPROGRAMPROC glCreateProgram_func = NULL;
+static PFNGLCREATESHADERPROC glCreateShader_func = NULL;
+static PFNGLDELETEPROGRAMPROC glDeleteProgram_func = NULL;
+static PFNGLDELETESHADERPROC glDeleteShader_func = NULL;
+static PFNGLGETATTACHEDSHADERSPROC glGetAttachedShaders_func = NULL;
+static PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation_func = NULL;
+static PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog_func = NULL;
+static PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog_func = NULL;
+static PFNGLGETSHADERIVPROC glGetShaderiv_func = NULL;
+static PFNGLGETPROGRAMIVPROC glGetProgramiv_func = NULL;
+static PFNGLGETSHADERSOURCEPROC glGetShaderSource_func = NULL;
+static PFNGLGETUNIFORMFVPROC glGetUniformfv_func = NULL;
+static PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation_func = NULL;
+static PFNGLISPROGRAMPROC glIsProgram_func = NULL;
+static PFNGLISSHADERPROC glIsShader_func = NULL;
+static PFNGLLINKPROGRAMPROC glLinkProgram_func = NULL;
+static PFNGLSHADERSOURCEPROC glShaderSource_func = NULL;
+static PFNGLUNIFORM1IPROC glUniform1i_func = NULL;
+static PFNGLUNIFORM1FVPROC glUniform1fv_func = NULL;
+static PFNGLUNIFORM2FVPROC glUniform2fv_func = NULL;
+static PFNGLUNIFORM3FVPROC glUniform3fv_func = NULL;
+static PFNGLUNIFORM4FVPROC glUniform4fv_func = NULL;
+static PFNGLUNIFORMMATRIX2FVPROC glUniformMatrix2fv_func = NULL;
+static PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv_func = NULL;
+static PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv_func = NULL;
+static PFNGLUSEPROGRAMPROC glUseProgram_func = NULL;
+static PFNGLVERTEXATTRIB1FPROC glVertexAttrib1f_func = NULL;
+static PFNGLVERTEXATTRIB2FPROC glVertexAttrib2f_func = NULL;
+static PFNGLVERTEXATTRIB3FPROC glVertexAttrib3f_func = NULL;
+static PFNGLVERTEXATTRIB4FPROC glVertexAttrib4f_func = NULL;
+
+static PFNGLUNIFORMMATRIX2X4FVPROC glUniformMatrix2x4fv_func = NULL;
+static PFNGLUNIFORMMATRIX4X3FVPROC glUniformMatrix4x3fv_func = NULL;
+
+
+#define FLAG_NONE 0x0
+#define FLAG_LOOSE 0x1 // to indicate a looser tolerance test is needed
+#define FLAG_ILLEGAL_SHADER 0x2 // the shader test should not compile
+#define FLAG_ILLEGAL_LINK 0x4 // the shaders should not link
+#define FLAG_VERSION_2_1 0x8 // OpenGL 2.1 test (or GLSL 1.20)
+#define FLAG_WINDING_CW 0x10 // clockwise-winding polygon
+
+#define DONT_CARE_Z -1.0
+
+#define NO_VERTEX_SHADER NULL
+#define NO_FRAGMENT_SHADER NULL
+
+#define PRIMARY_R 0.25
+#define PRIMARY_G 0.75
+#define PRIMARY_B 0.5
+#define PRIMARY_A 0.25
+#define SECONDARY_R 0.0
+#define SECONDARY_G 0.25
+#define SECONDARY_B 0.25
+#define SECONDARY_A 1.0
+
+#define AMBIENT { 0.2, 0.4, 0.6, 0.8 }
+#define LIGHT_DIFFUSE { 0.1, 0.3, 0.5, 0.7 }
+#define MAT_DIFFUSE { 0.1, 0.3, 0.5, 0.7 }
+#define DIFFUSE_PRODUCT { 0.01, 0.09, 0.25, 0.7 } // note alpha!
+
+#define UNIFORM1 {1.0, 0.25, 0.75, 0.0 } // don't change!
+
+#define PSIZE 3.0
+#define PSIZE_MIN 2.0
+#define PSIZE_MAX 8.0
+#define PSIZE_THRESH 1.5
+#define PSIZE_ATTEN0 4.0
+#define PSIZE_ATTEN1 5.0
+#define PSIZE_ATTEN2 6.0
+
+#define FOG_START 100.0
+#define FOG_END 200.0
+#define FOG_R 1.0
+#define FOG_G 0.5
+#define FOG_B 1.0
+#define FOG_A 0.0
+
+static const GLfloat PrimaryColor[4] = { PRIMARY_R, PRIMARY_G,
+ PRIMARY_B, PRIMARY_A };
+static const GLfloat SecondaryColor[4] = { SECONDARY_R, SECONDARY_G,
+ SECONDARY_B, SECONDARY_A };
+
+static const GLfloat Ambient[4] = AMBIENT;
+static const GLfloat MatDiffuse[4] = MAT_DIFFUSE;
+static const GLfloat LightDiffuse[4] = LIGHT_DIFFUSE;
+
+static const GLfloat Uniform1[4] = UNIFORM1;
+
+static const GLfloat PointAtten[3] = { PSIZE_ATTEN0, PSIZE_ATTEN1, PSIZE_ATTEN2 };
+static const GLfloat FogColor[4] = { FOG_R, FOG_G, FOG_B, FOG_A };
+
+// Shader program test cases
+static const ShaderProgram Programs[] = {
+ // Simple tests =======================================================
+ {
+ "Directly set fragment color", // name
+ NO_VERTEX_SHADER, // vertex shader
+ // fragment shader:
+ "void main() { \n"
+ " gl_FragColor = vec4(1.0, 0.5, 0.25, 0.0); \n"
+ "} \n",
+ { 1.0, 0.5, 0.25, 0.0 }, // expectedColor
+ DONT_CARE_Z, // expectedZ
+ FLAG_NONE // flags
+ },
+
+ {
+ "Directly set vertex color",
+ "void main() { \n"
+ " gl_Position = ftransform(); \n"
+ " gl_FrontColor = vec4(0.5, 1.0, 0.25, 0.0); \n"
+ "} \n",
+ NO_FRAGMENT_SHADER,
+ { 0.5, 1.0, 0.25, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Pass-through vertex color",
+ // vert shader:
+ "void main() { \n"
+ " gl_Position = ftransform(); \n"
+ " gl_FrontColor = vec4(0.25, 1.0, 0.75, 0.0); \n"
+ "} \n",
+ // frag shader:
+ "void main() { \n"
+ " gl_FragColor = gl_Color; \n"
+ "} \n",
+ { 0.25, 1.0, 0.75, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Primary plus secondary color",
+ // vert shader:
+ "void main() { \n"
+ " gl_Position = ftransform(); \n"
+ " gl_FrontColor = gl_Color + gl_SecondaryColor; \n"
+ "} \n",
+ // frag shader:
+ "void main() { \n"
+ " gl_FragColor = gl_Color; \n"
+ "} \n",
+ { PRIMARY_R + SECONDARY_R,
+ PRIMARY_G + SECONDARY_G,
+ PRIMARY_B + SECONDARY_B,
+ 1.0 /*PRIMARY_A + SECONDARY_A*/ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Empty blocks ({}), nil (;) statements",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " {} \n" // empty block
+ " ; \n" // nil statement
+ " gl_FragColor = vec4(1.0, 0.5, 0.25, 0.0); \n"
+ "} \n",
+ { 1.0, 0.5, 0.25, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Global vars and initializers",
+ NO_VERTEX_SHADER,
+ "vec4 c = vec4(1.0, 0.5, 0.25, 0.0); \n"
+ "void main() { \n"
+ " gl_FragColor = c; \n"
+ "} \n",
+ { 1.0, 0.5, 0.25, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Global vars and initializers (2)",
+ NO_VERTEX_SHADER,
+ "vec4 c1 = vec4(0.4, 0.5, 0.25, 0.0); \n"
+ "vec4 c2 = vec4(0.3, 0.5, 0.5, 0.4); \n"
+ "vec4 c3 = c1 + c2; \n"
+ "void main() { \n"
+ " gl_FragColor = c3; \n"
+ "} \n",
+ { 0.7, 1.0, 0.75, 0.4 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // Swizzle, writemask =================================================
+ {
+ "Swizzle",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4(0.5, 0.25, 0.0, 1.0); \n"
+ " gl_FragColor = a.yxxz; \n"
+ "} \n",
+ { 0.25, 0.5, 0.5, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Swizzle (rgba)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4(0.5, 0.25, 0.0, 1.0); \n"
+ " gl_FragColor = a.grrb; \n"
+ "} \n",
+ { 0.25, 0.5, 0.5, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Swizzle (stpq)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4(0.5, 0.25, 0.0, 1.0); \n"
+ " gl_FragColor = a.tssp; \n"
+ "} \n",
+ { 0.25, 0.5, 0.5, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Writemask",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(1.0); \n"
+ " gl_FragColor.x = 0.5; \n"
+ " gl_FragColor.z = 0.25; \n"
+ "} \n",
+ { 0.5, 1.0, 0.25, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Swizzled writemask",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor.zwxy = vec4(1.0, 0.5, 0.25, 0.75); \n"
+ "} \n",
+ { 0.25, 0.75, 1.0, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Swizzled writemask (2)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor.zy = vec2(1.0, 0.5); \n"
+ " gl_FragColor.wx = vec2(0.25, 0.75); \n"
+ "} \n",
+ { 0.75, 0.5, 1.0, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Swizzled writemask (rgba)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor.bg = vec2(1.0, 0.5); \n"
+ " gl_FragColor.ar = vec2(0.25, 0.75); \n"
+ "} \n",
+ { 0.75, 0.5, 1.0, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Swizzled writemask (stpq)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor.pt = vec2(1.0, 0.5); \n"
+ " gl_FragColor.qs = vec2(0.25, 0.75); \n"
+ "} \n",
+ { 0.75, 0.5, 1.0, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // Z-write ============================================================
+ {
+ "gl_FragDepth writing",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.5); \n"
+ " gl_FragDepth = 0.25; \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ 0.25, // Z value
+ FLAG_NONE
+ },
+
+ // Basic arithmetic ===================================================
+ {
+ "Addition",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4(0.5, 0.25, 0.0, 0.0); \n"
+ " vec4 b = vec4(0.25, 0.0, 0.2, 0.0); \n"
+ " gl_FragColor = a + b; \n"
+ "} \n",
+ { 0.75, 0.25, 0.2, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "vec4, scalar arithmetic",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4(0.5, 0.25, 0.2, 0.0); \n"
+ " vec4 b = vec4(0.25, 0.0, 0.0, 0.0); \n"
+ " gl_FragColor = a * 2.0 - b; \n"
+ "} \n",
+ { 0.75, 0.50, 0.4, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "chained assignment",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float x, y, z; \n"
+ " x = y = z = 0.25; \n"
+ " gl_FragColor = vec4(x + y + z); \n"
+ "} \n",
+ { 0.75, 0.75, 0.75, 0.75 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "integer, float arithmetic",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " int k = 100; \n"
+ " gl_FragColor.x = k * 0.01; \n"
+ " gl_FragColor.y = k * 0.005; \n"
+ " gl_FragColor.z = k * 0.0025; \n"
+ " gl_FragColor.w = k * 0.0; \n"
+ "} \n",
+ { 1.0, 0.5, 0.25, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "unary negation",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 v = vec4(-1.0, -0.5, 0.5, -0.25); \n"
+ " gl_FragColor = -v; \n"
+ "} \n",
+ { 1.0, 0.5, 0.0, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "integer division",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " int i = 15, j = 6; \n"
+ " int k = i / j; \n"
+ " gl_FragColor = vec4(k * 0.1); \n"
+ "} \n",
+ { 0.2, 0.2, 0.2, 0.2 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "integer division with uniform var",
+ NO_VERTEX_SHADER,
+ "// as above, but prevent compile-time evaluation \n"
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " int i = int(15 * uniform1.x); \n"
+ " int j = 6; \n"
+ " int k = i / j; \n"
+ " gl_FragColor = vec4(k * 0.1); \n"
+ "} \n",
+ { 0.2, 0.2, 0.2, 0.2 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "assignment operators",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 v = vec4(0.0, 0.25, 0.5, 0.75); \n"
+ " v *= 2.0; \n"
+ " v -= vec4(-0.5, 0.0, 0.25, 1.0); \n"
+ " gl_FragColor = v; \n"
+ "} \n",
+ { 0.5, 0.5, 0.75, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "post increment (x++)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " float x = uniform1.y; // should be 0.25 \n"
+ " float y = x++; // y should be 0.25 \n"
+ " gl_FragColor = vec4(y); \n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "pre increment (++x)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " float x = uniform1.y; // should be 0.25 \n"
+ " float y = ++x; // y should be 1.25 \n"
+ " gl_FragColor = vec4(y); \n"
+ "} \n",
+ { 1.0, 1.0, 1.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "post decrement (x--)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " float x = uniform1.y; // should be 0.25 \n"
+ " float y = x--; // y should be 0.25 \n"
+ " gl_FragColor = vec4(y); \n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "pre decrement (--x)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " float x = uniform1.y; // should be 0.25 \n"
+ " float y = --x; // y should be -0.75 \n"
+ " gl_FragColor = vec4(-y); // negate \n"
+ "} \n",
+ { 0.75, 0.75, 0.75, 0.75 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // built-in functions ================================================
+ {
+ "dot product",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 u = vec4(-1.0, 0.5, 0.5, -0.25); \n"
+ " vec4 v = vec4(0.5, 1.0, 0.5, 0.0); \n"
+ " gl_FragColor = vec4(dot(u, v)); \n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "length() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec3 u = vec3(0.25, 0.1, 0.2); \n"
+ " gl_FragColor = vec4(length(u)); \n"
+ "} \n",
+ { 0.335, 0.335, 0.335, 0.335 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "clamp() function",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " vec4 u = uniform1 * vec4(3.0); \n"
+ " gl_FragColor = clamp(u, 0.0, 1.0); \n"
+ "} \n",
+ { 1.0, 0.75, 1.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "clamp() function, vec4",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " vec4 u = uniform1; \n"
+ " gl_FragColor = clamp(u, vec4(0.2), vec4(0.8)); \n"
+ "} \n",
+ { 0.8, 0.25, 0.75, 0.2 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "sin(vec4) function",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " vec4 u = vec4(0.0, 3.1415/2.0, 3.1415, -3.1415/2.0); \n"
+ " u = u * uniform1.x; // mul by one \n"
+ " u = sin(u); \n"
+ " gl_FragColor = u * 0.5 + 0.5; // scale to [0,1] range \n"
+ "} \n",
+ { 0.5, 1.0, 0.5, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "cos(vec4) function",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " vec4 u = vec4(0.0, 3.1415/2.0, 3.1415, -3.1415/2.0); \n"
+ " u = u * uniform1.x; // mul by one \n"
+ " u = cos(u); \n"
+ " gl_FragColor = u * 0.5 + 0.5; // scale to [0,1] range \n"
+ "} \n",
+ { 1.0, 0.5, 0.0, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "asin(vec4) function",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " vec4 u = vec4(0.0, 1.0, -1.0, 0.0); \n"
+ " u = u * uniform1.x; // mul by one \n"
+ " u = asin(u); \n"
+ " gl_FragColor = u * 0.1 + 0.5; \n"
+ "} \n",
+ { 0.5, 0.5 + 0.157, 0.5 - 0.157, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "acos(vec4) function",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " vec4 u = vec4(0.0, 0.8, -0.8, 1.0); \n"
+ " u = u * uniform1.x; // mul by one \n"
+ " u = acos(u); \n"
+ " gl_FragColor = u * 0.1; \n"
+ "} \n",
+ { 0.157, 0.064, 0.249, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "atan(vec4) function",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " vec4 u = vec4(0.0, 0.8, -0.6, 0.5); \n"
+ " u = u * uniform1.x; // mul by one \n"
+ " u = atan(u); \n"
+ " gl_FragColor = u; \n"
+ " gl_FragColor.z = -u.z; \n"
+ "} \n",
+ { 0.0, 0.675, 0.540, 0.464 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "pow(vec4) function",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " vec4 u = vec4(0.5, 2.0, 0.3, 2.0); \n"
+ " u = u * uniform1.x; // mul by one \n"
+ " vec4 v = vec4(2.0, 0.5, 1.0, 0.0); \n"
+ " gl_FragColor = pow(u, v) * 0.5; \n"
+ "} \n",
+ { 0.25 * 0.5, 1.4142 * 0.5, 0.3 * 0.5, 1.0 * 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "exp(vec4) function",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " vec4 u = vec4(1.0, 0.5, -0.5, 2.0); \n"
+ " gl_FragColor = exp(u) * 0.1; \n"
+ "} \n",
+ { 0.2718, 0.1649, 0.0606, 0.7389 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "length() functions",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec2 v2 = vec2(1.0, 3.0); \n"
+ " vec3 v3 = vec3(0.5, -1.0, 2.0); \n"
+ " vec4 v4 = vec4(0.5, -1.0, 2.0, 1.0); \n"
+ " gl_FragColor.x = length(v2) * 0.1; \n"
+ " gl_FragColor.y = length(v3) * 0.1; \n"
+ " gl_FragColor.z = length(v4) * 0.1; \n"
+ " gl_FragColor.w = 1.0; \n"
+ "} \n",
+ { 0.3162, 0.2291, 0.25, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "normalize(vec3) function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec3 v3 = vec3(0.5, -1.0, 2.0); \n"
+ " v3 = normalize(v3); \n"
+ " gl_FragColor.x = v3.x; \n"
+ " gl_FragColor.y = v3.y; \n"
+ " gl_FragColor.z = v3.z; \n"
+ " gl_FragColor.w = 1.0; \n"
+ "} \n",
+ { 0.2182, /*-0.4364*/0.0, 0.8729, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "cross() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec3 u = vec3(0.5, 0.0, 0.0); \n"
+ " vec3 v = vec3(0.0, 0.5, 0.0); \n"
+ " vec3 w = cross(u, v); \n"
+ " gl_FragColor.xyz = w; \n"
+ " gl_FragColor.w = 1.0; \n"
+ "} \n",
+ { 0.0, 0.0, 0.25, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "abs() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 v = vec4(-0.3, -0.7, 0.2, 0.0); \n"
+ " gl_FragColor = abs(v); \n"
+ "} \n",
+ { 0.3, 0.7, 0.2, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "sign() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 v = vec4(-0.3, 0.0, 0.2, 0.0); \n"
+ " v = sign(v); \n"
+ " gl_FragColor.x = v.x + 1.5; \n"
+ " gl_FragColor.y = v.y + 0.5; \n"
+ " gl_FragColor.z = v.z - 0.5; \n"
+ " gl_FragColor.w = v.w + 0.5; \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "floor() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 v = vec4(1.3, -1.7, -0.2, 0.0); \n"
+ " v = floor(v); \n"
+ " gl_FragColor.x = v.x * 0.5; \n"
+ " gl_FragColor.y = v.y + 2.5; \n"
+ " gl_FragColor.z = v.z + 1.5; \n"
+ " gl_FragColor.w = v.w + 0.5; \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "ceil() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 v = vec4(1.3, -1.7, -0.2, 0.0); \n"
+ " v = ceil(v); \n"
+ " gl_FragColor.x = v.x - 1.5; \n"
+ " gl_FragColor.y = v.y + 1.5; \n"
+ " gl_FragColor.z = v.z + 0.5; \n"
+ " gl_FragColor.w = v.w + 0.5; \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "fract() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 v = vec4(1.3, -1.7, -0.2, 1.0); \n"
+ " gl_FragColor = fract(v); \n"
+ "} \n",
+ { 0.3, 0.3, 0.8, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "mod() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 u = vec4(7.0, 5.2, 5.3, 0.5); \n"
+ " vec4 v = vec4(4.0, 5.0, -5.0, 1.0); \n"
+ " vec4 w = mod(u, v); \n"
+ " gl_FragColor.x = w.x * 0.1; \n"
+ " gl_FragColor.y = w.y; \n"
+ " gl_FragColor.z = w.z * -0.1; \n"
+ " gl_FragColor.w = w.w; \n"
+ "} \n",
+ { 0.3, 0.2, 0.47, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "min() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 u = vec4(-1.0, 0.5, 0.5, -0.25); \n"
+ " vec4 v = vec4(0.5, 1.0, 0.5, 0.0); \n"
+ " gl_FragColor = min(u, v); \n"
+ "} \n",
+ { 0.0, 0.5, 0.5, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "max() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 u = vec4(-1.0, 0.5, 0.5, -0.25); \n"
+ " vec4 v = vec4(0.5, 1.0, 0.5, 0.0); \n"
+ " gl_FragColor = max(u, v); \n"
+ "} \n",
+ { 0.5, 1.0, 0.5, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "step() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 edge = vec4(1.0, -2.0, 0.5, -1.0); \n"
+ " vec4 v = vec4(0.5, -1.0, 0.0, 0.0); \n"
+ " gl_FragColor = step(edge, v); \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "smoothstep() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 edge0 = vec4(2.0); \n"
+ " vec4 edge1 = vec4(4.0); \n"
+ " vec4 v = vec4(1.0, 3.0, 4.0, 5.0); \n"
+ " gl_FragColor = smoothstep(edge0, edge1, v); \n"
+ "} \n",
+ { 0.0, 0.5, 1.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "mix(vec4) function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 v0 = vec4(0.0, 1.0, -4.8, 0.0); \n"
+ " vec4 v1 = vec4(1.0, 0.0, 15.2, 0.0); \n"
+ " gl_FragColor = mix(v0, v1, 0.25); \n"
+ "} \n",
+ { 0.25, 0.75, 0.2, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "mix(float) function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float v0 = 0.0; \n"
+ " float v1 = 1.0; \n"
+ " gl_FragColor.x = mix(v0, v1, 0.25); \n"
+ " v0 = 1.0; \n"
+ " v1 = 0.0; \n"
+ " gl_FragColor.y = mix(v0, v1, 0.25); \n"
+ " v0 = -4.8; \n"
+ " v1 = 15.2; \n"
+ " gl_FragColor.z = mix(v0, v1, 0.25); \n"
+ " v0 = 0.0; \n"
+ " v1 = 0.0; \n"
+ " gl_FragColor.w = mix(v0, v1, 0.25); \n"
+ "} \n",
+ { 0.25, 0.75, 0.2, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // Flow Control ======================================================
+ {
+ "simple if statement",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " // this should always be true \n"
+ " if (gl_FragCoord.x >= 0.0) { \n"
+ " gl_FragColor = vec4(0.5, 0.0, 0.5, 0.0); \n"
+ " } \n"
+ "} \n",
+ { 0.5, 0.0, 0.5, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "simple if statement (scalar test)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float x = 1.0; \n"
+ " if (x) { \n"
+ " gl_FragColor = vec4(0.5, 0.0, 0.5, 0.0); \n"
+ " } \n"
+ "} \n",
+ { 0.5, 0.0, 0.5, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "simple if/else statement",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " // this should always be false \n"
+ " if (gl_FragCoord.x < 0.0) { \n"
+ " gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); \n"
+ " } else { \n"
+ " gl_FragColor = vec4(0.5, 0.25, 0.5, 0.0); \n"
+ " } \n"
+ "} \n",
+ { 0.5, 0.25, 0.5, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "while-loop",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float sum = 0.0; \n"
+ " while (sum < 0.499999) { \n"
+ " sum += 0.1; \n"
+ " } \n"
+ " gl_FragColor = vec4(sum); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "do-loop",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float sum = 0.0; \n"
+ " do { \n"
+ " sum += 0.1; \n"
+ " } while (sum < 0.499999); \n"
+ " gl_FragColor = vec4(sum); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "for-loop",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 sum = vec4(0.0); \n"
+ " int i; \n"
+ " for (i = 0; i < 5; ++i) { \n"
+ " sum += vec4(0.1); \n"
+ " } \n"
+ " gl_FragColor = sum; \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "do-loop with break",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float sum = 0.0; \n"
+ " do { \n"
+ " sum += 0.1; \n"
+ " if (sum >= 0.499999) \n"
+ " break; \n"
+ " } while (1); \n"
+ " gl_FragColor = vec4(sum); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "do-loop with continue and break",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float sum = 0.0; \n"
+ " do { \n"
+ " sum += 0.1; \n"
+ " if (sum < 0.499999) \n"
+ " continue; \n"
+ " break; \n"
+ " } while (1); \n"
+ " gl_FragColor = vec4(sum); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "discard statement (1)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(1.0); \n"
+ " if (gl_TexCoord[0].x < 0.5) \n"
+ " discard; \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 }, // glClear color
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "discard statement (2)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(1.0); \n"
+ " if (gl_TexCoord[0].x > 0.5) \n"
+ " discard; \n"
+ "} \n",
+ { 1.0, 1.0, 1.0, 1.0 }, // fragment color
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "conditional expression",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = gl_FragCoord.x < 0.0 ? vec4(0.0) : vec4(0.5); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "sequence (comma) operator",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float x, y, z; \n"
+ " x = 1.0, y = 0.5, z = x * y; \n"
+ " gl_FragColor = vec4(z); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "array with constant indexing",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float ar[4]; \n"
+ " ar[0] = 0.5; \n"
+ " ar[1] = 1.0; \n"
+ " ar[2] = 0.25; \n"
+ " ar[3] = 0.2; \n"
+ " gl_FragColor.x = ar[0]; \n"
+ " gl_FragColor.y = ar[1]; \n"
+ " gl_FragColor.z = ar[2]; \n"
+ " gl_FragColor.w = ar[3]; \n"
+ "} \n",
+ { 0.5, 1.0, 0.25, 0.2 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // Equality/inequality tests==========================================
+ {
+ "equality (float, pass)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " float v = uniform1.x; \n"
+ " if (uniform1.x == v) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "equality (float, fail)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " if (uniform1.x == 99.0) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "inequality (float, pass)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " float v = uniform1.x; \n"
+ " if (uniform1.y != v) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "inequality (float, fail)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " float v = uniform1.x; \n"
+ " if (uniform1.x != v) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "equality (vec2, pass)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " vec2 v = uniform1.xy; \n"
+ " if (uniform1.xy == v) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "equality (vec2, fail)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " vec2 v = uniform1.xy; \n"
+ " if (v == vec2(99.0)) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "inequality (vec2, pass)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " vec2 v = uniform1.yx; \n"
+ " if (uniform1.xy != v) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "inequality (vec2, fail)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " vec2 v = uniform1.xy; \n"
+ " if (uniform1.xy != v) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "equality (vec3, pass)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " vec3 v = uniform1.xyz; \n"
+ " if (uniform1.xyz == v) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "equality (vec3, fail)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " if (uniform1.xyz == vec3(99.0)) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "inequality (vec3, pass)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " vec3 v = uniform1.zyx; \n"
+ " if (uniform1.xyz != v) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "inequality (vec3, fail)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " vec3 v = uniform1.xyz; \n"
+ " if (uniform1.xyz != v) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "equality (vec4, pass)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " vec4 v = uniform1; \n"
+ " if (uniform1 == v) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "equality (vec4, fail)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " if (uniform1 == vec4(99.0)) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "inequality (vec4, pass)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " vec4 v = uniform1.zyxw; \n"
+ " if (uniform1 != v) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "inequality (vec4, fail)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " vec4 v = uniform1.xyzw; \n"
+ " if (uniform1 != v) \n"
+ " gl_FragColor = vec4(0, 1, 0, 0); // green \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // Logical operators =================================================
+ {
+ "&& operator (1)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.25); \n"
+ " // this should always be true \n"
+ " if (gl_FragCoord.x >= 0.0 && gl_FragCoord.y >= 0.0) { \n"
+ " gl_FragColor = vec4(0.5, 0.0, 0.5, 0.0); \n"
+ " } \n"
+ "} \n",
+ { 0.5, 0.0, 0.5, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "&& operator (2)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.25); \n"
+ " // this should always be false \n"
+ " if (gl_FragCoord.x >= 0.0 && gl_FragCoord.y < 0.0) { \n"
+ " gl_FragColor = vec4(0.5, 0.0, 0.5, 0.0); \n"
+ " } \n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "&& operator, short-circuit",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float x = 0.75; \n"
+ " // this should always be false \n"
+ " if (x <= 0.5 && ++x) { \n"
+ " x += 0.1; \n"
+ " } \n"
+ " gl_FragColor = vec4(x); \n"
+ "} \n",
+ { 0.75, 0.75, 0.75, 0.75 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "|| operator (1)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.25); \n"
+ " // this should always be true \n"
+ " if (gl_FragCoord.x < 0.0 || gl_FragCoord.y >= 0.0) { \n"
+ " gl_FragColor = vec4(0.5, 0.0, 0.5, 0.0); \n"
+ " } \n"
+ "} \n",
+ { 0.5, 0.0, 0.5, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "|| operator (2)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.25); \n"
+ " // this should always be false \n"
+ " if (gl_FragCoord.x < 0.0 || gl_FragCoord.y < 0.0) { \n"
+ " gl_FragColor = vec4(0.5, 0.0, 0.5, 0.0); \n"
+ " } \n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "|| operator, short-circuit",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float x = 0.75; \n"
+ " // this should always be true \n"
+ " if (x >= 0.5 || ++x) { \n"
+ " x += 0.1; \n"
+ " } \n"
+ " gl_FragColor = vec4(x); \n"
+ "} \n",
+ { 0.85, 0.85, 0.85, 0.85 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "^^ operator (1)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.25); \n"
+ " // this should always be true \n"
+ " if (gl_FragCoord.x < 0.0 ^^ gl_FragCoord.y >= 0.0) { \n"
+ " gl_FragColor = vec4(0.5); \n"
+ " } \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "^^ operator (2)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.25); \n"
+ " // this should always be false \n"
+ " if (gl_FragCoord.x >= 0.0 ^^ gl_FragCoord.y >= 0.0) { \n"
+ " gl_FragColor = vec4(0.5); \n"
+ " } \n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "! (not) operator (1, pass)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " bool b = gl_FragCoord.x < 0.0; \n"
+ " if (!b) { \n"
+ " gl_FragColor = vec4(0.5); \n"
+ " } \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "! (not) operator (1, fail)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " bool b = gl_FragCoord.x > 0.0; \n"
+ " if (!b) { \n"
+ " gl_FragColor = vec4(0.5); \n"
+ " } \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "! (not) operator (2, pass)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " if (!(gl_FragCoord.x < 0.0)) { \n"
+ " gl_FragColor = vec4(0.5); \n"
+ " } \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "! (not) operator (2, fail)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0); \n"
+ " if (!(gl_FragCoord.x > 0.0)) { \n"
+ " gl_FragColor = vec4(0.5); \n"
+ " } \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // Uniform & Varying vars ============================================
+ {
+ "uniform variable (fragment shader)",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FragColor = uniform1; \n"
+ "} \n",
+ UNIFORM1,
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "uniform variable (vertex shader)",
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " gl_FrontColor = uniform1; \n"
+ " gl_Position = ftransform(); \n"
+ "} \n",
+ NO_FRAGMENT_SHADER,
+ UNIFORM1,
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "varying variable",
+ // vertex program:
+ "varying vec4 var1; \n"
+ "void main() { \n"
+ " var1 = vec4(1.0, 0.5, 0.25, 0.0); \n"
+ " gl_Position = ftransform(); \n"
+ "} \n",
+ // fragment program:
+ "varying vec4 var1; \n"
+ "void main() { \n"
+ " gl_FragColor = var1; \n"
+ "} \n",
+ { 1.0, 0.5, 0.25, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // GL state refs =====================================================
+ {
+ "GL state variable reference (gl_FrontMaterial.ambient)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = gl_FrontMaterial.ambient; \n"
+ "} \n",
+ AMBIENT,
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "GL state variable reference (gl_LightSource[0].diffuse)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = gl_LightSource[0].diffuse; \n"
+ "} \n",
+ LIGHT_DIFFUSE,
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "GL state variable reference (diffuse product)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = gl_FrontLightProduct[0].diffuse; \n"
+ "} \n",
+ DIFFUSE_PRODUCT,
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "GL state variable reference (point size)",
+ "void main() { \n"
+ " gl_Position = ftransform(); \n"
+ " gl_FrontColor.x = gl_Point.size * 0.1; \n"
+ " gl_FrontColor.y = gl_Point.sizeMin * 0.1; \n"
+ " gl_FrontColor.z = gl_Point.sizeMax * 0.1; \n"
+ " gl_FrontColor.w = 0.0; \n"
+ "} \n",
+ NO_FRAGMENT_SHADER,
+ { PSIZE * 0.1, PSIZE_MIN * 0.1, PSIZE_MAX * 0.1, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "GL state variable reference (point attenuation)",
+ "void main() { \n"
+ " gl_Position = ftransform(); \n"
+ " gl_FrontColor.x = gl_Point.distanceConstantAttenuation * 0.1; \n"
+ " gl_FrontColor.y = gl_Point.distanceLinearAttenuation * 0.1; \n"
+ " gl_FrontColor.z = gl_Point.distanceQuadraticAttenuation * 0.1; \n"
+ " gl_FrontColor.w = 0.0; \n"
+ "} \n",
+ NO_FRAGMENT_SHADER,
+ { PSIZE_ATTEN0 * 0.1, PSIZE_ATTEN1 * 0.1,
+ PSIZE_ATTEN2 * 0.1, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "linear fog",
+ // vertex prog:
+ "void main() { \n"
+ " gl_Position = ftransform(); \n"
+ " gl_FogFragCoord = 125.0; \n"
+ " gl_FrontColor = gl_Color; \n"
+ "} \n",
+ // fragment prog:
+ "void main() { \n"
+ " float bf = (gl_FogFragCoord - gl_Fog.start) * gl_Fog.scale; \n"
+ " gl_FragColor = mix(gl_Color, gl_Fog.color, bf); \n"
+ "} \n",
+#define BF (125.0 - FOG_START) / (FOG_END - FOG_START) // Blend Factor
+ { PRIMARY_R + BF * (FOG_R - PRIMARY_R),
+ PRIMARY_G + BF * (FOG_G - PRIMARY_G),
+ PRIMARY_B + BF * (FOG_B - PRIMARY_B),
+ PRIMARY_A + BF * (FOG_A - PRIMARY_A) },
+#undef BF
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "built-in constants",
+ // vertex shader:
+ "void main() { \n"
+ " gl_Position = ftransform(); \n"
+ " // front color values should all be >= 1.0 \n"
+ " gl_FrontColor = vec4(gl_MaxLights, gl_MaxClipPlanes,\n"
+ " gl_MaxTextureUnits, \n"
+ " gl_MaxTextureCoords); \n"
+ "} \n",
+ NO_FRAGMENT_SHADER,
+ { 1.0, 1.0, 1.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "gl_FrontFacing var (1)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.5 * float(gl_FrontFacing)); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "gl_FrontFacing var (2)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.25 + float(gl_FrontFacing)); \n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 0.25 },
+ DONT_CARE_Z,
+ FLAG_WINDING_CW
+ },
+
+ // Texture functions ==================================================
+ {
+ "texture2D()",
+ NO_VERTEX_SHADER,
+ "uniform sampler2D tex2d; \n"
+ "void main() { \n"
+ " gl_FragColor = texture2D(tex2d, gl_TexCoord[0].xy);\n"
+ "} \n",
+ { 1.0, 0.0, 0.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "texture2D(), computed coordinate",
+ NO_VERTEX_SHADER,
+ "uniform sampler2D tex2d; \n"
+ "void main() { \n"
+ " vec2 coord = gl_TexCoord[0].xy + vec2(0.5); \n"
+ " gl_FragColor = texture2D(tex2d, coord, 0.0); \n"
+ "} \n",
+ { 1.0, 1.0, 1.0, 1.0 }, // upper-right tex color
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "texture2D(), with bias",
+ NO_VERTEX_SHADER,
+ "uniform sampler2D tex2d; \n"
+ "void main() { \n"
+ " gl_FragColor = texture2D(tex2d, gl_TexCoord[0].xy, 1.0);\n"
+ "} \n",
+ { 0.5, 0.0, 0.0, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "2D Texture lookup with explicit lod (Vertex shader)",
+ "uniform sampler2D tex2d; \n"
+ "void main() { \n"
+ " gl_FrontColor = texture2DLod(tex2d, gl_MultiTexCoord0.xy, 2.0);\n"
+ " gl_Position = ftransform(); \n"
+ "} \n",
+ NO_FRAGMENT_SHADER,
+ { 0.25, 0.0, 0.0, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "texture2DProj()",
+ NO_VERTEX_SHADER,
+ "uniform sampler2D tex2d; \n"
+ "void main() { \n"
+ " vec4 coord = gl_TexCoord[0] * vec4(2.25); \n"
+ " // 'proj' will divide components by w (=2.25) \n"
+ " gl_FragColor = texture2DProj(tex2d, coord);\n"
+ "} \n",
+ { 1.0, 0.0, 0.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "texture1D()",
+ NO_VERTEX_SHADER,
+ "uniform sampler1D tex1d; \n"
+ "void main() { \n"
+ " gl_FragColor = texture1D(tex1d, gl_TexCoord[0].x);\n"
+ "} \n",
+ { 1.0, 0.0, 0.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "texture3D()",
+ NO_VERTEX_SHADER,
+ "uniform sampler3D tex3d; \n"
+ "void main() { \n"
+ " gl_FragColor = texture3D(tex3d, gl_TexCoord[0].xyz);\n"
+ "} \n",
+ { 1.0, 0.0, 0.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "texture3D(), computed coord",
+ NO_VERTEX_SHADER,
+ "uniform sampler3D tex3d; \n"
+ "void main() { \n"
+ " vec3 coord = gl_TexCoord[0].xyz; \n"
+ " coord.y = 0.75; \n"
+ " coord.z = 0.75; \n"
+ " gl_FragColor = texture3D(tex3d, coord); \n"
+ "} \n",
+ { 0.0, 0.0, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "shadow2D(): 1",
+ NO_VERTEX_SHADER,
+ "uniform sampler2DShadow texZ; \n"
+ "void main() { \n"
+ " vec3 coord = vec3(0.1, 0.1, 0.5); \n"
+ " // shadow map value should be 0.25 \n"
+ " gl_FragColor = shadow2D(texZ, coord) + vec4(0.25); \n"
+ " // 0.5 <= 0.25 ? color = 1 : 0\n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "shadow2D(): 2",
+ NO_VERTEX_SHADER,
+ "uniform sampler2DShadow texZ; \n"
+ "void main() { \n"
+ " vec3 coord = vec3(0.1, 0.1, 0.2); \n"
+ " // shadow map value should be 0.25 \n"
+ " gl_FragColor = shadow2D(texZ, coord); \n"
+ " // 0.2 <= 0.25 ? color = 1 : 0\n"
+ "} \n",
+ { 1.0, 1.0, 1.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "shadow2D(): 3",
+ NO_VERTEX_SHADER,
+ "uniform sampler2DShadow texZ; \n"
+ "void main() { \n"
+ " vec3 coord = vec3(0.9, 0.9, 0.95); \n"
+ " // shadow map value should be 0.75 \n"
+ " gl_FragColor = shadow2D(texZ, coord) + vec4(0.25); \n"
+ " // 0.95 <= 0.75 ? color = 1 : 0\n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "shadow2D(): 4",
+ NO_VERTEX_SHADER,
+ "uniform sampler2DShadow texZ; \n"
+ "void main() { \n"
+ " vec3 coord = vec3(0.9, 0.9, 0.65); \n"
+ " // shadow map value should be 0.75 \n"
+ " gl_FragColor = shadow2D(texZ, coord); \n"
+ " // 0.65 <= 0.75 ? color = 1 : 0\n"
+ "} \n",
+ { 1.0, 1.0, 1.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // Function calls ====================================================
+ {
+ "simple function call",
+ NO_VERTEX_SHADER,
+ "vec4 avg(const in vec4 a, const in vec4 b) { \n"
+ " return (a + b) * 0.5; \n"
+ "} \n"
+ "\n"
+ "void main() { \n"
+ " vec4 a = vec4(1.0, 0.0, 0.5, 0.0); \n"
+ " vec4 b = vec4(0.0, 0.8, 0.5, 0.0); \n"
+ " gl_FragColor = avg(a, b); \n"
+ "} \n",
+ { 0.5, 0.4, 0.5, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "function call with inout params",
+ NO_VERTEX_SHADER,
+ "void swap(inout float x, inout float y) { \n"
+ " float t = x; \n"
+ " x = y; \n"
+ " y = t; \n"
+ "} \n"
+ "\n"
+ "void main() { \n"
+ " float a = 0.5, b = 0.25; \n"
+ " swap(a, b); \n"
+ " gl_FragColor.x = a; \n"
+ " gl_FragColor.y = b; \n"
+ " gl_FragColor.z = 0.0; \n"
+ " gl_FragColor.w = 0.0; \n"
+ "} \n",
+ { 0.25, 0.5, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "function call with in, out params",
+ NO_VERTEX_SHADER,
+ "void half(in float x, out float y) { \n"
+ " y = 0.5 * x; \n"
+ "} \n"
+ "\n"
+ "void main() { \n"
+ " float a = 0.5, b = 0.1; \n"
+ " half(a, b); \n"
+ " gl_FragColor = vec4(b); \n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "function with early return",
+ NO_VERTEX_SHADER,
+ "float minimum(in float x, in float y) { \n"
+ " if (x < y) \n"
+ " return x; \n"
+ " return y; \n"
+ "} \n"
+ "\n"
+ "void main() { \n"
+ " float a = 0.5; \n"
+ " float z = minimum(a, 0.25); \n"
+ " gl_FragColor = vec4(z); \n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "nested function calls (1)",
+ NO_VERTEX_SHADER,
+ "float half(const in float x) { \n"
+ " return 0.5 * x; \n"
+ "} \n"
+ "\n"
+ "float square(const in float x) { \n"
+ " return x * x; \n"
+ "} \n"
+ "\n"
+ "void main() { \n"
+ " float a = 0.5; \n"
+ " float b = square(half(1.0)); \n"
+ " gl_FragColor = vec4(b); \n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "nested function calls (2)",
+ NO_VERTEX_SHADER,
+ "float half(const in float x) { \n"
+ " return 0.5 * x; \n"
+ "} \n"
+ "\n"
+ "float square_half(const in float x) { \n"
+ " float y = half(x); \n"
+ " return y * y; \n"
+ "} \n"
+ "\n"
+ "void main() { \n"
+ " float a = 1.0; \n"
+ " float b = square_half(a); \n"
+ " gl_FragColor = vec4(b); \n"
+ "} \n",
+ { 0.25, 0.25, 0.25, 0.25 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "nested function calls (3)",
+ NO_VERTEX_SHADER,
+ "float half(const in float x) { \n"
+ " return 0.5 * x; \n"
+ "} \n"
+ "\n"
+ "void main() { \n"
+ " float a = 0.5; \n"
+ " float b = half(half(a)); \n"
+ " gl_FragColor = vec4(b); \n"
+ "} \n",
+ { 0.125, 0.125, 0.125, 0.125 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // Matrix tests ======================================================
+ {
+ "matrix column check (1)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " mat4 m = gl_TextureMatrix[1]; \n"
+ " gl_FragColor = m[0]; \n"
+ "} \n",
+ { 1.0, 0.5, 0.6, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "matrix column check (2)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " mat4 m = gl_TextureMatrix[1]; \n"
+ " gl_FragColor = m[3]; \n"
+ "} \n",
+ { 0.1, 0.2, 0.3, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "matrix, vector multiply (1)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " mat4 m = mat4(0.5); // scale by 0.5 \n"
+ " vec4 color = gl_Color * m; \n"
+ " gl_FragColor = color; \n"
+ "} \n",
+ { 0.5 * PRIMARY_R, 0.5 * PRIMARY_G,
+ 0.5 * PRIMARY_B, 0.5 * PRIMARY_A },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "matrix, vector multiply (2)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 color = gl_TextureMatrix[1] * gl_Color; \n"
+ " gl_FragColor = color; \n"
+ "} \n",
+ { 0.2745, 0.9255, 0.7294, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "matrix, vector multiply (3)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 color = gl_Color * gl_TextureMatrix[1]; \n"
+ " gl_FragColor = color; \n"
+ "} \n",
+ { 0.925, 0.925, 0.6999, .5750 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "uniform matrix",
+ NO_VERTEX_SHADER,
+ "uniform mat4 uniformMat4; \n"
+ "void main() { \n"
+ " gl_FragColor = uniformMat4[3]; \n"
+ "} \n",
+ { 0.6, 0.7, 0.8, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "uniform matrix, transposed",
+ NO_VERTEX_SHADER,
+ "uniform mat4 uniformMat4t; \n"
+ "void main() { \n"
+ " gl_FragColor = uniformMat4t[2]; \n"
+ "} \n",
+ { 0.2, 0.0, 1.0, 0.8 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // Vectors, booleans =================================================
+ {
+ "vector relational (vec4 ==)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4( 1.0, 0.0, 0.2, 0.5); \n"
+ " vec4 b = vec4( 1.0, 3.0, 0.0, 0.5); \n"
+ " gl_FragColor = equal(a, b); \n"
+ "} \n",
+ { 1.0, 0.0, 0.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "vector relational (vec4 !=)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4( 1.0, 0.0, 0.2, 0.5); \n"
+ " vec4 b = vec4( 1.0, 3.0, 0.0, 0.5); \n"
+ " gl_FragColor = notEqual(a, b); \n"
+ "} \n",
+ { 0.0, 1.0, 1.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "vector relational (vec4 <=)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4( 0.5, 1.0, 0.4, 0.0); \n"
+ " vec4 b = vec4( 1.0, 0.2, 0.4, 0.0); \n"
+ " gl_FragColor = lessThanEqual(a, b); \n"
+ "} \n",
+ { 1.0, 0.0, 1.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "vector relational (vec4 >=)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4( 0.5, 1.0, 0.4, 0.0); \n"
+ " vec4 b = vec4( 1.0, 0.2, 0.4, 0.0); \n"
+ " gl_FragColor = greaterThanEqual(a, b); \n"
+ "} \n",
+ { 0.0, 1.0, 1.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "vector relational (vec4 <)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4( 0.5, 1.0, 0.4, 0.0); \n"
+ " vec4 b = vec4( 1.0, 0.2, 0.4, 0.0); \n"
+ " gl_FragColor = lessThan(a, b); \n"
+ "} \n",
+ { 1.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "vector relational (vec4 >)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4( 0.5, 1.0, 0.4, 0.0); \n"
+ " vec4 b = vec4( 1.0, 0.2, 0.4, 0.0); \n"
+ " gl_FragColor = greaterThan(a, b); \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "vector relational (bvec2 <,<=)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec2 a = vec2(-1.0, 2.0); \n"
+ " vec2 b = vec2( 1.0, 2.0); \n"
+ " vec2 c = vec2( 3.0, 2.0); \n"
+ " bvec2 b1 = lessThan(a, b); \n"
+ " bvec2 b2 = lessThanEqual(b, c); \n"
+ " gl_FragColor.x = float(b1.x); \n"
+ " gl_FragColor.y = float(b1.y); \n"
+ " gl_FragColor.z = float(b2.x); \n"
+ " gl_FragColor.w = float(b2.y); \n"
+ "} \n",
+ { 1.0, 0.0, 1.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "vector relational (bvec2 >,>=)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec2 a = vec2(-1.0, 3.0); \n"
+ " vec2 b = vec2( 1.0, 2.0); \n"
+ " vec2 c = vec2( 3.0, 2.0); \n"
+ " bvec2 b1 = greaterThan(a, b); \n"
+ " bvec2 b2 = greaterThanEqual(b, c); \n"
+ " gl_FragColor.x = float(b1.x); \n"
+ " gl_FragColor.y = float(b1.y); \n"
+ " gl_FragColor.z = float(b2.x); \n"
+ " gl_FragColor.w = float(b2.y); \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "vector relational (bvec2 ==,!=)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec2 a = vec2(-1.0, 3.0); \n"
+ " vec2 b = vec2(-1.0, 2.0); \n"
+ " vec2 c = vec2( 3.0, 2.0); \n"
+ " bvec2 b1 = equal(a, b); \n"
+ " bvec2 b2 = notEqual(b, c); \n"
+ " gl_FragColor.x = b1.x; \n"
+ " gl_FragColor.y = b1.y; \n"
+ " gl_FragColor.z = b2.x; \n"
+ " gl_FragColor.w = b2.y; \n"
+ "} \n",
+ { 1.0, 0.0, 1.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "any() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " bvec4 b1 = bvec4(false, false, true, false); \n"
+ " bvec4 b2 = bvec4(false, false, false, false); \n"
+ " bool a1 = any(b1); \n"
+ " bool a2 = any(b2); \n"
+ " gl_FragColor.x = float(a1); \n"
+ " gl_FragColor.y = float(a2); \n"
+ " gl_FragColor.z = 0.0; \n"
+ " gl_FragColor.w = 0.0; \n"
+ "} \n",
+ { 1.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "all() function",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " bvec4 b1 = bvec4(false, true, true, false); \n"
+ " bvec4 b2 = bvec4(true, true, true, true ); \n"
+ " bool a1 = all(b1); \n"
+ " bool a2 = all(b2); \n"
+ " gl_FragColor.x = float(a1); \n"
+ " gl_FragColor.y = float(a2); \n"
+ " gl_FragColor.z = 0.0; \n"
+ " gl_FragColor.w = 0.0; \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // Preprocessor tests ================================================
+ {
+ "Preprocessor test (1)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ "#if 0 \n"
+ " gl_FragColor = vec4(0.5); \n"
+ "#else \n"
+ " gl_FragColor = vec4(0.3); \n"
+ "#endif \n"
+ "} \n",
+ { 0.3, 0.3, 0.3, 0.3 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Preprocessor test (2)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ "#if 1 \n"
+ " gl_FragColor = vec4(0.5); \n"
+ "#else \n"
+ " gl_FragColor = vec4(0.3); \n"
+ "#endif \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Preprocessor test (3)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ "#define SYMBOL 3 \n"
+ "#if SYMBOL == 3 \n"
+ " gl_FragColor = vec4(0.5); \n"
+ "#else \n"
+ " gl_FragColor = vec4(0.3); \n"
+ "#endif \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // Illegal shaders ==================================================
+ {
+ "undefined variable",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec3 v = u; \n"
+ " gl_FragColor = vec4(0.5); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_ILLEGAL_SHADER
+ },
+
+ {
+ "if (boolean/scalar) check",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec3 v; \n"
+ " if (v) { \n"
+ " } \n"
+ " gl_FragColor = vec4(0.5); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_ILLEGAL_SHADER
+ },
+
+ {
+ "break with no loop",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " break; \n"
+ " gl_FragColor = vec4(0.5); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_ILLEGAL_SHADER
+ },
+
+ {
+ "continue with no loop",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " continue; \n"
+ " gl_FragColor = vec4(0.5); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_ILLEGAL_SHADER
+ },
+
+ {
+ "illegal assignment",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float x = main; \n"
+ " gl_FragColor = vec4(0.5); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_ILLEGAL_SHADER
+ },
+
+ {
+ "syntax error check (1)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " float x = ; \n"
+ " gl_FragColor = vec4(0.5); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_ILLEGAL_SHADER
+ },
+
+ {
+ "syntax error check (2)",
+ NO_VERTEX_SHADER,
+ "main() { \n"
+ " gl_FragColor = vec4(0.5); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_ILLEGAL_SHADER
+ },
+
+ {
+ "syntax error check (3)",
+ NO_VERTEX_SHADER,
+ "main() { \n"
+ " float x = 1.0 2.0; \n"
+ " gl_FragColor = vec4(0.5); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_ILLEGAL_SHADER
+ },
+
+ // GLSL 1.20 tests ======================================================
+ {
+ "mat2x4 construct",
+ NO_VERTEX_SHADER,
+ "#version 120\n"
+ "void main() { \n"
+ " mat2x4 m = mat2x4(0.1, 0.2, 0.3, 0.4, \n"
+ " 0.5, 0.6, 0.7, 0.8); \n"
+ " gl_FragColor = m[1]; \n"
+ "} \n",
+ { 0.5, 0.6, 0.7, 0.8 },
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+ {
+ "mat4x2 construct",
+ NO_VERTEX_SHADER,
+ "#version 120\n"
+ "void main() { \n"
+ " mat4x2 m = mat4x2(0.1, 0.2, \n"
+ " 0.3, 0.4, \n"
+ " 0.5, 0.6, \n"
+ " 0.7, 0.8); \n"
+ " gl_FragColor.xy = m[1]; \n"
+ " gl_FragColor.zw = m[2]; \n"
+ "} \n",
+ { 0.3, 0.4, 0.5, 0.6 },
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+ {
+ "mat2x3 construct",
+ NO_VERTEX_SHADER,
+ "#version 120\n"
+ "void main() { \n"
+ " mat2x3 m = mat2x3(0.1, 0.2, 0.3, \n"
+ " 0.4, 0.5, 0.6); \n"
+ " gl_FragColor.xyz = m[1]; \n"
+ " gl_FragColor.w = 1.0; \n"
+ "} \n",
+ { 0.4, 0.5, 0.6, 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+ {
+ "mat3x2 construct",
+ NO_VERTEX_SHADER,
+ "#version 120\n"
+ "void main() { \n"
+ " mat3x2 m = mat3x2(0.1, 0.2, \n"
+ " 0.3, 0.4, \n"
+ " 0.5, 0.6); \n"
+ " gl_FragColor.xy = m[1]; \n"
+ " gl_FragColor.zw = m[2]; \n"
+ "} \n",
+ { 0.3, 0.4, 0.5, 0.6 },
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+ {
+ "mat4x3 construct",
+ NO_VERTEX_SHADER,
+ "#version 120\n"
+ "void main() { \n"
+ " mat4x3 m = mat4x3(0.1, 0.2, 0.3, \n"
+ " 0.4, 0.5, 0.6, \n"
+ " 0.7, 0.8, 0.9, \n"
+ " 1.0, 0.0, 1.0); \n"
+ " gl_FragColor.xyz = m[1]; \n"
+ " gl_FragColor.w = 1.0; \n"
+ "} \n",
+ { 0.4, 0.5, 0.6, 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+ {
+ "mat3x4 construct",
+ NO_VERTEX_SHADER,
+ "#version 120\n"
+ "void main() { \n"
+ " mat3x4 m = mat3x4(0.1, 0.2, 0.3, 0.4, \n"
+ " 0.5, 0.6, 0.7, 0.8, \n"
+ " 0.9, 1.0, 0.0, 1.0);\n"
+ " gl_FragColor = m[1]; \n"
+ "} \n",
+ { 0.5, 0.6, 0.7, 0.8 },
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+
+ {
+ "vec4 * mat3x4 multiply",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "void main() { \n"
+ " vec4 v = vec4(0.2, -0.2, 0.4, 0.1); \n"
+ " mat3x4 m = mat3x4(0.1, 0.2, 0.3, 0.4, \n"
+ " 0.5, 0.6, 0.7, 0.8, \n"
+ " 0.9, 1.0, 0.0, 1.0);\n"
+ " gl_FragColor.xyz = v * m; \n"
+ " gl_FragColor.w = 1.0; \n"
+ "} \n",
+ { 0.2 * 0.1 + -0.2 * 0.2 + 0.4 * 0.3 + 0.1 * 0.4,
+ 0.2 * 0.5 + -0.2 * 0.6 + 0.4 * 0.7 + 0.1 * 0.8,
+ 0.2 * 0.9 + -0.2 * 1.0 + 0.4 * 0.0 + 0.1 * 1.0,
+ 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+
+ {
+ "mat4x2 * vec4",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "void main() { \n"
+ " mat4x2 m = mat4x2(0.1, 0.2, \n"
+ " 0.3, 0.4, \n"
+ " 0.5, 0.6, \n"
+ " 0.7, 0.8); \n"
+ " vec4 v = vec4(0.9, 0.8, 0.7, 0.6); \n"
+ " gl_FragColor.xy = (m * v) * 0.5; \n"
+ " gl_FragColor.zw = vec2(0.0); \n"
+ "} \n",
+ { (0.1 * 0.9 + 0.3 * 0.8 + 0.5 * 0.7 + 0.7 * 0.6) * 0.5,
+ (0.2 * 0.9 + 0.4 * 0.8 + 0.6 * 0.7 + 0.8 * 0.6) * 0.5,
+ 0.0,
+ 0.0
+ },
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+
+ {
+ "mat4x2 * mat2x4",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "void main() { \n"
+ " mat4x2 m1 = mat4x2(0.1, 0.2, \n"
+ " 0.3, 0.4, \n"
+ " 0.5, 0.6, \n"
+ " 0.7, 0.8); \n"
+ " mat2x4 m2 = mat2x4(0.9, 0.8, 0.7, 0.6, \n"
+ " 0.5, 0.4, 0.3, 0.2); \n"
+ " mat2 m3 = m1 * m2; \n"
+ " vec4 v4; \n"
+ " v4.xy = m3[0]; \n"
+ " v4.zw = m3[1]; \n"
+ " gl_FragColor = v4 * 0.5; \n"
+ "} \n",
+ { (0.1 * 0.9 + 0.3 * 0.8 + 0.5 * 0.7 + 0.7 * 0.6) * 0.5,
+ (0.2 * 0.9 + 0.4 * 0.8 + 0.6 * 0.7 + 0.8 * 0.6) * 0.5,
+ (0.1 * 0.5 + 0.3 * 0.4 + 0.5 * 0.3 + 0.7 * 0.2) * 0.5,
+ (0.2 * 0.5 + 0.4 * 0.4 + 0.6 * 0.3 + 0.8 * 0.2) * 0.5
+ },
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+
+ {
+ "vec2 * mat4x2 multiply",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "void main() { \n"
+ " vec2 v = vec2(0.2, 0.5); \n"
+ " mat4x2 m = mat4x2(0.1, 0.2, \n"
+ " 0.3, 0.4, \n"
+ " 0.5, 0.6, \n"
+ " 0.7, 0.8); \n"
+ " gl_FragColor = v * m; \n"
+ "} \n",
+ { 0.2 * 0.1 + 0.5 * 0.2,
+ 0.2 * 0.3 + 0.5 * 0.4,
+ 0.2 * 0.5 + 0.5 * 0.6,
+ 0.2 * 0.7 + 0.5 * 0.8 },
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+ {
+ "vec3 * mat4x3 multiply",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "void main() { \n"
+ " vec3 v = vec3(0.2, 0.5, 0.1); \n"
+ " mat4x3 m = mat4x3(0.1, 0.2, 0.3, \n"
+ " 0.4, 0.5, 0.6, \n"
+ " 0.7, 0.8, 0.9, \n"
+ " 1.0, 0.1, 0.2); \n"
+ " gl_FragColor = v * m; \n"
+ "} \n",
+ { 0.2 * 0.1 + 0.5 * 0.2 + 0.1 * 0.3,
+ 0.2 * 0.4 + 0.5 * 0.5 + 0.1 * 0.6,
+ 0.2 * 0.7 + 0.5 * 0.8 + 0.1 * 0.9,
+ 0.2 * 1.0 + 0.5 * 0.1 + 0.1 * 0.2 },
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+
+ {
+ "uniform matrix 2x4",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "uniform mat2x4 uniformMat2x4; \n"
+ "void main() { \n"
+ " gl_FragColor = uniformMat2x4[0]; \n"
+ "} \n",
+ { 0.0, 0.1, 0.2, 0.3 }, // first column of 2x4 matrix
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+ {
+ "uniform matrix 2x4, transposed",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "uniform mat2x4 uniformMat2x4t; \n"
+ "void main() { \n"
+ " gl_FragColor = uniformMat2x4t[0]; \n"
+ "} \n",
+ { 0.0, 0.2, 0.4, 0.6 }, // first row of 4x2 matrix
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+ {
+ "uniform matrix 4x3",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "uniform mat4x3 uniformMat4x3; \n"
+ "void main() { \n"
+ " gl_FragColor.xyz = uniformMat4x3[1]; \n"
+ " gl_FragColor.w = 1.0; \n"
+ "} \n",
+ { 0.3, 0.4, 0.5, 1.0 }, // second column of 4x3 matrix
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+ {
+ "uniform matrix 4x3, transposed",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "uniform mat4x3 uniformMat4x3t; \n"
+ "void main() { \n"
+ " gl_FragColor.xyz = uniformMat4x3t[1]; \n"
+ " gl_FragColor.w = 1.0; \n"
+ "} \n",
+ { 0.1, 0.5, 0.9, 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_2_1
+ },
+
+ // Illegal link test ===================================================
+ {
+ "gl_Position not written check",
+ "void main() { \n"
+ " gl_FrontColor = vec4(0.3); \n"
+ "} \n",
+ NO_FRAGMENT_SHADER,
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_ILLEGAL_LINK
+ },
+
+ {
+ "varying var mismatch",
+ // vert shader:
+ "varying vec4 foo; \n"
+ "void main() { \n"
+ " foo = gl_Color; \n"
+ " gl_Position = ftransform(); \n"
+ "} \n",
+ // frag shader:
+ "varying vec4 bar; \n"
+ "void main() { \n"
+ " gl_FragColor = bar; \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_ILLEGAL_LINK
+ },
+
+ { NULL, NULL, NULL, {0,0,0,0}, 0, FLAG_NONE } // end of list sentinal
+};
+
+
+
+// Get ptrs to 2.0 API functions.
+bool
+GLSLTest::getFunctions(void)
+{
+ glAttachShader_func = (PFNGLATTACHSHADERPROC) GLUtils::getProcAddress("glAttachShader");
+ if (!glAttachShader_func)
+ return false;
+ glBindAttribLocation_func = (PFNGLBINDATTRIBLOCATIONPROC) GLUtils::getProcAddress("glBindAttribLocation");
+ if (!glBindAttribLocation_func)
+ return false;
+ glCompileShader_func = (PFNGLCOMPILESHADERPROC) GLUtils::getProcAddress("glCompileShader");
+ if (!glCompileShader_func)
+ return false;
+ glCreateProgram_func = (PFNGLCREATEPROGRAMPROC) GLUtils::getProcAddress("glCreateProgram");
+ if (!glCreateProgram_func)
+ return false;
+ glCreateShader_func = (PFNGLCREATESHADERPROC) GLUtils::getProcAddress("glCreateShader");
+ if (!glCreateShader_func)
+ return false;
+ glDeleteProgram_func = (PFNGLDELETEPROGRAMPROC) GLUtils::getProcAddress("glDeleteProgram");
+ if (!glDeleteProgram_func)
+ return false;
+ glDeleteShader_func = (PFNGLDELETESHADERPROC) GLUtils::getProcAddress("glDeleteShader");
+ if (!glDeleteShader_func)
+ return false;
+ glGetAttachedShaders_func = (PFNGLGETATTACHEDSHADERSPROC) GLUtils::getProcAddress("glGetAttachedShaders");
+ if (!glGetAttachedShaders_func)
+ return false;
+ glGetAttribLocation_func = (PFNGLGETATTRIBLOCATIONPROC) GLUtils::getProcAddress("glGetAttribLocation");
+ if (!glGetAttribLocation_func)
+ return false;
+ glGetProgramInfoLog_func = (PFNGLGETPROGRAMINFOLOGPROC) GLUtils::getProcAddress("glGetProgramInfoLog");
+ if (!glGetProgramInfoLog_func)
+ return false;
+ glGetShaderInfoLog_func = (PFNGLGETSHADERINFOLOGPROC) GLUtils::getProcAddress("glGetShaderInfoLog");
+ if (!glGetShaderInfoLog_func)
+ return false;
+ glGetProgramiv_func = (PFNGLGETPROGRAMIVPROC) GLUtils::getProcAddress("glGetProgramiv");
+ if (!glGetProgramiv_func)
+ return false;
+ glGetShaderiv_func = (PFNGLGETSHADERIVPROC) GLUtils::getProcAddress("glGetShaderiv");
+ if (!glGetShaderiv_func)
+ return false;
+ glGetShaderSource_func = (PFNGLGETSHADERSOURCEPROC) GLUtils::getProcAddress("glGetShaderSource");
+ if (!glGetShaderSource_func)
+ return false;
+ glGetUniformLocation_func = (PFNGLGETUNIFORMLOCATIONPROC) GLUtils::getProcAddress("glGetUniformLocation");
+ if (!glGetUniformLocation_func)
+ return false;
+ glGetUniformfv_func = (PFNGLGETUNIFORMFVPROC) GLUtils::getProcAddress("glGetUniformfv");
+ if (!glGetUniformfv_func)
+ return false;
+ glIsProgram_func = (PFNGLISPROGRAMPROC) GLUtils::getProcAddress("glIsProgram");
+ if (!glIsProgram_func)
+ return false;
+ glIsShader_func = (PFNGLISSHADERPROC) GLUtils::getProcAddress("glIsShader");
+ if (!glIsShader_func)
+ return false;
+ glLinkProgram_func = (PFNGLLINKPROGRAMPROC) GLUtils::getProcAddress("glLinkProgram");
+ if (!glLinkProgram_func)
+ return false;
+ glShaderSource_func = (PFNGLSHADERSOURCEPROC) GLUtils::getProcAddress("glShaderSource");
+ if (!glShaderSource_func)
+ return false;
+ glUniform1i_func = (PFNGLUNIFORM1IPROC) GLUtils::getProcAddress("glUniform1i");
+ if (!glUniform1i_func)
+ return false;
+ glUniform1fv_func = (PFNGLUNIFORM1FVPROC) GLUtils::getProcAddress("glUniform1fv");
+ if (!glUniform1fv_func)
+ return false;
+ glUniform2fv_func = (PFNGLUNIFORM2FVPROC) GLUtils::getProcAddress("glUniform2fv");
+ if (!glUniform2fv_func)
+ return false;
+ glUniform3fv_func = (PFNGLUNIFORM3FVPROC) GLUtils::getProcAddress("glUniform3fv");
+ if (!glUniform3fv_func)
+ return false;
+ glUniform4fv_func = (PFNGLUNIFORM3FVPROC) GLUtils::getProcAddress("glUniform4fv");
+ if (!glUniform4fv_func)
+ return false;
+ glUniformMatrix2fv_func = (PFNGLUNIFORMMATRIX2FVPROC) GLUtils::getProcAddress("glUniformMatrix2fv");
+ if (!glUniformMatrix2fv_func)
+ return false;
+ glUniformMatrix3fv_func = (PFNGLUNIFORMMATRIX3FVPROC) GLUtils::getProcAddress("glUniformMatrix3fv");
+ if (!glUniformMatrix3fv_func)
+ return false;
+ glUniformMatrix4fv_func = (PFNGLUNIFORMMATRIX4FVPROC) GLUtils::getProcAddress("glUniformMatrix4fv");
+ if (!glUniformMatrix4fv_func)
+ return false;
+ glUseProgram_func = (PFNGLUSEPROGRAMPROC) GLUtils::getProcAddress("glUseProgram");
+ if (!glUseProgram_func)
+ return false;
+ glVertexAttrib1f_func = (PFNGLVERTEXATTRIB1FPROC) GLUtils::getProcAddress("glVertexAttrib1f");
+ if (!glVertexAttrib1f_func)
+ return false;
+ glVertexAttrib2f_func = (PFNGLVERTEXATTRIB2FPROC) GLUtils::getProcAddress("glVertexAttrib2f");
+ if (!glVertexAttrib2f_func)
+ return false;
+ glVertexAttrib3f_func = (PFNGLVERTEXATTRIB3FPROC) GLUtils::getProcAddress("glVertexAttrib3f");
+ if (!glVertexAttrib3f_func)
+ return false;
+ glVertexAttrib4f_func = (PFNGLVERTEXATTRIB4FPROC) GLUtils::getProcAddress("glVertexAttrib4f");
+ if (!glVertexAttrib4f_func)
+ return false;
+
+ /* 2.1 */
+ glUniformMatrix2x4fv_func = (PFNGLUNIFORMMATRIX2X4FVPROC) GLUtils::getProcAddress("glUniformMatrix2x4fv");
+ if (!glUniformMatrix2x4fv_func)
+ return false;
+ glUniformMatrix4x3fv_func = (PFNGLUNIFORMMATRIX4X3FVPROC) GLUtils::getProcAddress("glUniformMatrix4x3fv");
+ if (!glUniformMatrix4x3fv_func)
+ return false;
+
+ return true;
+}
+
+
+void
+GLSLTest::setupTextures(void)
+{
+ GLubyte teximage0[16][16][4];
+ GLubyte teximage1[8][8][4];
+ GLubyte teximage2[4][4][4];
+ GLubyte teximage3D[16][16][16][4];
+ GLfloat teximageZ[16][16];
+ GLint i, j, k;
+ GLuint obj1D, obj2D, obj3D, objZ;
+
+ glGenTextures(1, &obj1D);
+ glGenTextures(1, &obj2D);
+ glGenTextures(1, &obj3D);
+ glGenTextures(1, &objZ);
+
+ glActiveTexture(GL_TEXTURE0);
+
+ //
+ // 2D texture, w/ mipmap
+ //
+ glBindTexture(GL_TEXTURE_2D, obj2D);
+ // +-------+-------+
+ // | blue | white |
+ // +-------+-------+
+ // | red | green |
+ // +-------+-------+
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 16; j++) {
+ if (i < 8) {
+ // bottom half
+ if (j < 8) {
+ // red
+ teximage0[i][j][0] = 255;
+ teximage0[i][j][1] = 0;
+ teximage0[i][j][2] = 0;
+ teximage0[i][j][3] = 255;
+ }
+ else {
+ // green
+ teximage0[i][j][0] = 0;
+ teximage0[i][j][1] = 255;
+ teximage0[i][j][2] = 0;
+ teximage0[i][j][3] = 255;
+ }
+ }
+ else {
+ // top half
+ if (j < 8) {
+ // blue
+ teximage0[i][j][0] = 0;
+ teximage0[i][j][1] = 0;
+ teximage0[i][j][2] = 255;
+ teximage0[i][j][3] = 255;
+ }
+ else {
+ // white
+ teximage0[i][j][0] = 255;
+ teximage0[i][j][1] = 255;
+ teximage0[i][j][2] = 255;
+ teximage0[i][j][3] = 255;
+ }
+ }
+ }
+ }
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, teximage0);
+
+ // level 1: same colors, half intensity
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++) {
+ teximage1[i][j][0] = teximage0[i*2][j*2][0] / 2;
+ teximage1[i][j][1] = teximage0[i*2][j*2][1] / 2;
+ teximage1[i][j][2] = teximage0[i*2][j*2][2] / 2;
+ teximage1[i][j][3] = teximage0[i*2][j*2][3] / 2;
+ }
+ }
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, teximage1);
+
+ // level 2: 1/4 intensity
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ teximage2[i][j][0] = teximage0[i*4][j*4][0] / 4;
+ teximage2[i][j][1] = teximage0[i*4][j*4][1] / 4;
+ teximage2[i][j][2] = teximage0[i*4][j*4][2] / 4;
+ teximage2[i][j][3] = teximage0[i*4][j*4][3] / 4;
+ }
+ }
+ glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 4, 4, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, teximage2);
+
+ // level 3, 4: don't care
+ glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA, 2, 2, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, teximage0);
+ glTexImage2D(GL_TEXTURE_2D, 4, GL_RGBA, 1, 1, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, teximage0);
+
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ //
+ // 1D texture: just bottom row of the 2D texture
+ //
+ glBindTexture(GL_TEXTURE_1D, obj1D);
+ glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 16, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, teximage0);
+
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ //
+ // 3D texture: 2D texture, depth = 1
+ //
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 16; j++) {
+ for (k = 0; k < 16; k++) {
+ if (i < 8) {
+ teximage3D[i][j][k][0] = teximage0[j][k][0];
+ teximage3D[i][j][k][1] = teximage0[j][k][1];
+ teximage3D[i][j][k][2] = teximage0[j][k][2];
+ teximage3D[i][j][k][3] = teximage0[j][k][3];
+ }
+ else {
+ // back half: half intensity
+ teximage3D[i][j][k][0] = teximage0[j][k][0] / 2;
+ teximage3D[i][j][k][1] = teximage0[j][k][1] / 2;
+ teximage3D[i][j][k][2] = teximage0[j][k][2] / 2;
+ teximage3D[i][j][k][3] = teximage0[j][k][3] / 2;
+ }
+ }
+ }
+ }
+ glBindTexture(GL_TEXTURE_3D, obj3D);
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 16, 16, 16, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, teximage3D);
+
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ //
+ // 2D GL_DEPTH_COMPONENT texture (for shadow sampler tests)
+ //
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 16; j++) {
+ if (j < 8)
+ teximageZ[i][j] = 0.25;
+ else
+ teximageZ[i][j] = 0.75;
+ }
+ }
+ glActiveTexture(GL_TEXTURE1); // NOTE: Unit 1
+ glBindTexture(GL_TEXTURE_2D, objZ);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 16, 16, 0,
+ GL_DEPTH_COMPONENT, GL_FLOAT, teximageZ);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
+ GL_COMPARE_R_TO_TEXTURE_ARB);
+
+ glActiveTexture(GL_TEXTURE0);
+}
+
+
+void
+GLSLTest::setupTextureMatrix1(void)
+{
+ // This matrix is used by some of the general matrix tests
+ static const GLfloat m[16] = {
+ 1.0, 0.5, 0.6, 0.0, // col 0
+ 0.0, 1.0, 0.0, 0.7, // col 1
+ 0.0, 0.0, 1.0, 0.8, // col 2
+ 0.1, 0.2, 0.3, 1.0 // col 3
+ };
+ glMatrixMode(GL_TEXTURE);
+ glActiveTexture(GL_TEXTURE1);
+ glLoadMatrixf(m);
+ glActiveTexture(GL_TEXTURE0);
+ glMatrixMode(GL_MODELVIEW);
+}
+
+
+bool
+GLSLTest::setup(void)
+{
+ // check that we have OpenGL 2.0
+ const char *verString = (const char *) glGetString(GL_VERSION);
+ if (verString[0] != '2' || verString[1] != '.') {
+ //env->log << "OpenGL 2.x not supported\n";
+ return false;
+ }
+ if (verString[2] >= '1')
+ version21 = GL_TRUE; // update when needed
+ else
+ version21 = GL_FALSE; // play it safe
+
+ if (!getFunctions()) {
+ env->log << "Unable to get pointer to an OpenGL 2.0 API function\n";
+ return false;
+ }
+
+ setupTextures();
+ setupTextureMatrix1();
+
+ // load program inputs
+ glColor4fv(PrimaryColor);
+ glSecondaryColor3fv(SecondaryColor);
+
+ // other GL state
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, Ambient);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MatDiffuse);
+ glPointSize(PSIZE);
+ glPointParameterf(GL_POINT_SIZE_MIN, PSIZE_MIN);
+ glPointParameterf(GL_POINT_SIZE_MAX, PSIZE_MAX);
+ glPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE, PSIZE_THRESH);
+ glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, PointAtten);
+ glFogf(GL_FOG_START, FOG_START);
+ glFogf(GL_FOG_END, FOG_END);
+ glFogfv(GL_FOG_COLOR, FogColor);
+
+ GLenum err = glGetError();
+ assert(!err); // should be OK
+
+ // setup vertex transform (we'll draw a quad in middle of window)
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-4.0, 4.0, -4.0, 4.0, 0.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glDrawBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
+
+ // compute error tolerances (may need fine-tuning)
+ int bufferBits[5];
+ glGetIntegerv(GL_RED_BITS, &bufferBits[0]);
+ glGetIntegerv(GL_GREEN_BITS, &bufferBits[1]);
+ glGetIntegerv(GL_BLUE_BITS, &bufferBits[2]);
+ glGetIntegerv(GL_ALPHA_BITS, &bufferBits[3]);
+ glGetIntegerv(GL_DEPTH_BITS, &bufferBits[4]);
+
+ tolerance[0] = 2.0 / (1 << bufferBits[0]);
+ tolerance[1] = 2.0 / (1 << bufferBits[1]);
+ tolerance[2] = 2.0 / (1 << bufferBits[2]);
+ if (bufferBits[3])
+ tolerance[3] = 2.0 / (1 << bufferBits[3]);
+ else
+ tolerance[3] = 1.0;
+ if (bufferBits[4])
+ tolerance[4] = 16.0 / (1 << bufferBits[4]);
+ else
+ tolerance[4] = 1.0;
+
+ // Some tests request a looser tolerance:
+ // XXX a factor of 4 may be too much...
+ for (int i = 0; i < 5; i++)
+ looseTolerance[i] = 4.0 * tolerance[i];
+
+ return true;
+}
+
+
+void
+GLSLTest::reportFailure(const char *programName,
+ const GLfloat expectedColor[4],
+ const GLfloat actualColor[4] ) const
+{
+ env->log << "FAILURE:\n";
+ env->log << " Shader test: " << programName << "\n";
+ env->log << " Expected color: ";
+ env->log << expectedColor[0] << ", ";
+ env->log << expectedColor[1] << ", ";
+ env->log << expectedColor[2] << ", ";
+ env->log << expectedColor[3] << "\n";
+ env->log << " Observed color: ";
+ env->log << actualColor[0] << ", ";
+ env->log << actualColor[1] << ", ";
+ env->log << actualColor[2] << ", ";
+ env->log << actualColor[3] << "\n";
+}
+
+void
+GLSLTest::reportZFailure(const char *programName,
+ GLfloat expectedZ, GLfloat actualZ) const
+{
+ env->log << "FAILURE:\n";
+ env->log << " Shader test: " << programName << "\n";
+ env->log << " Expected Z: " << expectedZ << "\n";
+ env->log << " Observed Z: " << actualZ << "\n";
+}
+
+
+// Compare actual and expected colors
+bool
+GLSLTest::equalColors(const GLfloat act[4], const GLfloat exp[4], int flags) const
+{
+ const GLfloat *tol;
+ if (flags & FLAG_LOOSE)
+ tol = looseTolerance;
+ else
+ tol = tolerance;
+ if ((fabsf(act[0] - exp[0]) > tol[0]) ||
+ (fabsf(act[1] - exp[1]) > tol[1]) ||
+ (fabsf(act[2] - exp[2]) > tol[2]) ||
+ (fabsf(act[3] - exp[3]) > tol[3]))
+ return false;
+ else
+ return true;
+}
+
+
+bool
+GLSLTest::equalDepth(GLfloat z0, GLfloat z1) const
+{
+ if (fabsf(z0 - z1) > tolerance[4])
+ return false;
+ else
+ return true;
+}
+
+
+GLuint
+GLSLTest::loadAndCompileShader(GLenum target, const char *str)
+{
+ GLuint shader;
+ shader = glCreateShader_func(target);
+ glShaderSource_func(shader, 1,
+ (const GLchar **) &str, NULL);
+ glCompileShader_func(shader);
+ return shader;
+}
+
+
+// Check the compile status of the just compiled shader.
+// If the outcome is unexpected, report an error.
+bool
+GLSLTest::checkCompileStatus(GLenum target, GLuint shader,
+ const ShaderProgram &p)
+{
+ GLint stat;
+ GLchar infoLog[1000];
+ GLsizei len;
+
+ glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
+ if (!stat) {
+ glGetShaderInfoLog_func(shader, 1000, &len, infoLog);
+ // env->log << infoLog << "\n";
+ }
+
+ if (!stat && (p.flags & FLAG_ILLEGAL_SHADER) == 0) {
+ // this _should_ have compiled
+ env->log << "FAILURE:\n";
+ env->log << " Shader test: " << p.name << "\n";
+ if (target == GL_FRAGMENT_SHADER)
+ env->log << "Fragment shader did not compile:\n";
+ else
+ env->log << "Vertex shader did not compile:\n";
+ env->log << infoLog;
+ return false;
+ }
+ else if (stat && (p.flags & FLAG_ILLEGAL_SHADER)) {
+ // this should _not_ have compiled!
+ env->log << "FAILURE:\n";
+ env->log << " Shader test: " << p.name << "\n";
+ env->log << " Shader should not have compiled, but it did.\n";
+ return false;
+ }
+ return true;
+}
+
+
+bool
+GLSLTest::testProgram(const ShaderProgram &p)
+{
+ static const GLfloat uniformMatrix[16] = {
+ 1.0, 0.1, 0.2, 0.3, // col 0
+ 0.0, 1.0, 0.0, 0.4, // col 1
+ 0.0, 1.0, 1.0, 0.5, // col 2
+ 0.6, 0.7, 0.8, 1.0 // col 3
+ };
+ static const GLfloat uniformMatrix2x4[8] = {
+ 0.0, 0.1, 0.2, 0.3, // col 0
+ 0.4, 0.5, 0.6, 0.7 // col 1
+ };
+ static const GLfloat uniformMatrix4x3[12] = {
+ 0.0, 0.1, 0.2, // col 0
+ 0.3, 0.4, 0.5, // col 1
+ 0.6, 0.7, 0.8, // col 2
+ 0.9, 1.0, 0.0 // col 3
+ };
+ const GLfloat r = 0.62; // XXX draw 16x16 pixel quad
+ GLuint fragShader = 0, vertShader = 0, program = 0;
+ GLint u1, utex1d, utex2d, utex3d, utexZ, umat4, umat4t;
+ GLint umat2x4, umat2x4t, umat4x3, umat4x3t;
+ bool retVal = false;
+
+ if (p.fragShaderString) {
+ fragShader = loadAndCompileShader(GL_FRAGMENT_SHADER,
+ p.fragShaderString);
+ if (!checkCompileStatus(GL_FRAGMENT_SHADER, fragShader, p)) {
+ retVal = false;
+ goto cleanup;
+ }
+ }
+ if (p.vertShaderString) {
+ vertShader = loadAndCompileShader(GL_VERTEX_SHADER,
+ p.vertShaderString);
+ if (!checkCompileStatus(GL_VERTEX_SHADER, vertShader, p)) {
+ retVal = false;
+ goto cleanup;
+ }
+ }
+ if (!fragShader && !vertShader) {
+ // must have had a compilation errror
+ retVal = false;
+ goto cleanup;
+ }
+
+ if (p.flags & FLAG_ILLEGAL_SHADER) {
+ // don't render/test
+ retVal = true;
+ goto cleanup;
+ }
+
+ program = glCreateProgram_func();
+ if (fragShader)
+ glAttachShader_func(program, fragShader);
+ if (vertShader)
+ glAttachShader_func(program, vertShader);
+ glLinkProgram_func(program);
+
+ // check link
+ {
+ GLint stat;
+ glGetProgramiv_func(program, GL_LINK_STATUS, &stat);
+ if (!stat) {
+ if (p.flags & FLAG_ILLEGAL_LINK) {
+ // this is the expected outcome
+ retVal = true;
+ goto cleanup;
+ }
+ else {
+ GLchar log[1000];
+ GLsizei len;
+ glGetProgramInfoLog_func(program, 1000, &len, log);
+ env->log << "FAILURE:\n";
+ env->log << " Shader test: " << p.name << "\n";
+ env->log << " Link error: ";
+ env->log << log;
+ retVal = false;
+ goto cleanup;
+ }
+ }
+ else {
+ // link successful
+ if (p.flags & FLAG_ILLEGAL_LINK) {
+ // the shaders should _not_ have linked
+ env->log << "FAILURE:\n";
+ env->log << " Shader test: " << p.name << "\n";
+ env->log << " Program linked, but shouldn't have.\n";
+ retVal = false;
+ goto cleanup;
+ }
+ }
+ }
+
+ glUseProgram_func(program);
+
+ // load uniform vars
+ u1 = glGetUniformLocation_func(program, "uniform1");
+ if (u1 >= 0)
+ glUniform4fv_func(u1, 1, Uniform1);
+
+ utex1d = glGetUniformLocation_func(program, "tex1d");
+ if (utex1d >= 0)
+ glUniform1i_func(utex1d, 0); // bind to tex unit 0
+
+ utex2d = glGetUniformLocation_func(program, "tex2d");
+ if (utex2d >= 0)
+ glUniform1i_func(utex2d, 0); // bind to tex unit 0
+
+ utex3d = glGetUniformLocation_func(program, "tex3d");
+ if (utex3d >= 0)
+ glUniform1i_func(utex3d, 0); // bind to tex unit 0
+
+ utexZ = glGetUniformLocation_func(program, "texZ");
+ if (utexZ >= 0)
+ glUniform1i_func(utexZ, 1); // bind to tex unit 1
+
+ umat4 = glGetUniformLocation_func(program, "uniformMat4");
+ if (umat4 >= 0)
+ glUniformMatrix4fv_func(umat4, 1, GL_FALSE, uniformMatrix);
+
+ umat4t = glGetUniformLocation_func(program, "uniformMat4t");
+ if (umat4t >= 0)
+ glUniformMatrix4fv_func(umat4t, 1, GL_TRUE, uniformMatrix);
+
+ umat2x4 = glGetUniformLocation_func(program, "uniformMat2x4");
+ if (umat2x4 >= 0)
+ glUniformMatrix2x4fv_func(umat2x4, 1, GL_FALSE, uniformMatrix2x4);
+
+ umat2x4t = glGetUniformLocation_func(program, "uniformMat2x4t");
+ if (umat2x4t >= 0)
+ glUniformMatrix2x4fv_func(umat2x4t, 1, GL_TRUE, uniformMatrix2x4);
+
+ umat4x3 = glGetUniformLocation_func(program, "uniformMat4x3");
+ if (umat4x3 >= 0)
+ glUniformMatrix4x3fv_func(umat4x3, 1, GL_FALSE, uniformMatrix4x3);
+
+ umat4x3t = glGetUniformLocation_func(program, "uniformMat4x3t");
+ if (umat4x3t >= 0)
+ glUniformMatrix4x3fv_func(umat4x3t, 1, GL_TRUE, uniformMatrix4x3);
+
+
+ // to avoid potential issue with undefined result.depth.z
+ if (p.expectedZ == DONT_CARE_Z)
+ glDisable(GL_DEPTH_TEST);
+ else
+ glEnable(GL_DEPTH_TEST);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ if (p.flags & FLAG_WINDING_CW) {
+ /* Clockwise */
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex2f(-r, -r);
+ glTexCoord2f(0, 1); glVertex2f(-r, r);
+ glTexCoord2f(1, 1); glVertex2f( r, r);
+ glTexCoord2f(1, 0); glVertex2f( r, -r);
+ glEnd();
+ }
+ else {
+ /* Counter Clockwise */
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex2f(-r, -r);
+ glTexCoord2f(1, 0); glVertex2f( r, -r);
+ glTexCoord2f(1, 1); glVertex2f( r, r);
+ glTexCoord2f(0, 1); glVertex2f(-r, r);
+ glEnd();
+ }
+
+ // read a pixel from lower-left corder of rendered quad
+ GLfloat pixel[4];
+ glReadPixels(windowSize / 2 - 2, windowSize / 2 - 2, 1, 1,
+ GL_RGBA, GL_FLOAT, pixel);
+ if (0) // debug
+ printf("%s: Expect: %.3f %.3f %.3f %.3f found: %.3f %.3f %.3f %.3f\n",
+ p.name,
+ p.expectedColor[0], p.expectedColor[1],
+ p.expectedColor[2], p.expectedColor[3],
+ pixel[0], pixel[1], pixel[2], pixel[3]);
+
+ if (!equalColors(pixel, p.expectedColor, p.flags)) {
+ reportFailure(p.name, p.expectedColor, pixel);
+ retVal = false;
+ goto cleanup;
+ }
+
+ if (p.expectedZ != DONT_CARE_Z) {
+ GLfloat z;
+ // read z at center of quad
+ glReadPixels(windowSize / 2, windowSize / 2, 1, 1,
+ GL_DEPTH_COMPONENT, GL_FLOAT, &z);
+ if (!equalDepth(z, p.expectedZ)) {
+ reportZFailure(p.name, p.expectedZ, z);
+ retVal = false;
+ goto cleanup;
+ }
+ }
+
+ // passed!
+ retVal = true;
+
+ if (0) // debug
+ printf("%s passed\n", p.name);
+
+ cleanup:
+ if (fragShader)
+ glDeleteShader_func(fragShader);
+ if (vertShader)
+ glDeleteShader_func(vertShader);
+ glDeleteProgram_func(program);
+
+ return retVal;
+}
+
+
+void
+GLSLTest::runOne(MultiTestResult &r, Window &w)
+{
+ (void) w;
+ if (!setup()) {
+ r.pass = false;
+ return;
+ }
+
+ // If you just want to run a single sub-test, assign the name to singleTest.
+ const char *singleTest = NULL;
+ if (singleTest) {
+ for (int i = 0; Programs[i].name; i++) {
+ if (strcmp(Programs[i].name, singleTest) == 0) {
+ r.numPassed = testProgram(Programs[i]);
+ r.numFailed = 1 - r.numPassed;
+ break;
+ }
+ }
+ }
+ else {
+ // loop over all tests
+ for (int i = 0; Programs[i].name; i++) {
+ if ((Programs[i].flags & FLAG_VERSION_2_1) && !version21)
+ continue; // skip non-applicable tests
+ if (testProgram(Programs[i])) {
+ r.numPassed++;
+ }
+ else {
+ r.numFailed++;
+ }
+ }
+ }
+ r.pass = (r.numFailed == 0);
+}
+
+
+// The test object itself:
+GLSLTest glslTest("glsl1", "window, rgb, z",
+ "", // no extension filter (we'll test for version 2.x during setup)
+ "GLSL test 1: test basic Shading Language functionality.\n"
+ );
+
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tglsl1.h b/tests/glean/tglsl1.h
new file mode 100644
index 000000000..84a3d723f
--- /dev/null
+++ b/tests/glean/tglsl1.h
@@ -0,0 +1,90 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tglsl1.h: Test OpenGL shading language
+// Brian Paul 6 March 2007
+
+#ifndef __tglsl1_h__
+#define __tglsl1_h__
+
+#include "tmultitest.h"
+
+namespace GLEAN {
+
+#define windowSize 100
+
+
+class ShaderProgram
+{
+public:
+ const char *name;
+ const char *vertShaderString;
+ const char *fragShaderString;
+ GLfloat expectedColor[4];
+ GLfloat expectedZ;
+ int flags;
+};
+
+
+
+class GLSLTest: public MultiTest
+{
+public:
+ GLSLTest(const char* testName, const char* filter,
+ const char *extensions, const char* description):
+ MultiTest(testName, filter, extensions, description)
+ {
+ }
+
+ virtual void runOne(MultiTestResult &r, Window &w);
+
+private:
+ GLfloat tolerance[5];
+ GLfloat looseTolerance[5];
+ GLfloat version21; // OpenGL 2.1 or higher supported?
+ bool getFunctions(void);
+ void setupTextures(void);
+ void setupTextureMatrix1(void);
+ bool setup(void);
+ bool equalColors(const GLfloat a[4], const GLfloat b[4], int flags) const;
+ bool equalDepth(GLfloat z0, GLfloat z1) const;
+ GLuint loadAndCompileShader(GLenum target, const char *str);
+ bool checkCompileStatus(GLenum target, GLuint shader,
+ const ShaderProgram &p);
+ bool testProgram(const ShaderProgram &p);
+ void reportFailure(const char *programName,
+ const GLfloat expectedColor[4],
+ const GLfloat actualColor[4] ) const;
+ void reportZFailure(const char *programName,
+ GLfloat expectedZ, GLfloat actualZ) const;
+
+};
+
+} // namespace GLEAN
+
+#endif // __tglsl1_h__
diff --git a/tests/glean/tmultitest.cpp b/tests/glean/tmultitest.cpp
index 42cac0389..c98d7ec31 100644
--- a/tests/glean/tmultitest.cpp
+++ b/tests/glean/tmultitest.cpp
@@ -71,11 +71,19 @@ MultiTest::runOne(MultiTestResult &r, Window &)
void
MultiTest::logOne(MultiTestResult &r)
{
- logPassFail(r);
- logConcise(r);
- env->log << "\t"
- << r.numPassed << " tests passed, "
- << r.numFailed << " tests failed.\n";
+ if (r.numPassed == 0 && r.numFailed == 0) {
+ // non-applicable test
+ env->log << name << ": NOTE ";
+ logConcise(r);
+ env->log << "\tTest skipped/non-applicable\n";
+ }
+ else {
+ logPassFail(r);
+ logConcise(r);
+ env->log << "\t"
+ << r.numPassed << " tests passed, "
+ << r.numFailed << " tests failed.\n";
+ }
}
diff --git a/tests/glean/toccluqry.cpp b/tests/glean/toccluqry.cpp
new file mode 100644
index 000000000..7cc49b445
--- /dev/null
+++ b/tests/glean/toccluqry.cpp
@@ -0,0 +1,675 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+
+/*
+ * Copyright © 2006 Intel Corporation
+ * Copyright © 1999 Allen Akin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Wei Wang <wei.z.wang@intel.com>
+ *
+ */
+
+/*
+ * toccluqry.cpp: Conformance test on ARB_occlusion_query extension
+ */
+
+#define GL_GLEXT_PROTOTYPES
+#include "toccluqry.h"
+#include <cassert>
+#include <stdio.h>
+#include <cmath>
+
+
+#define START_QUERY(id)\
+ glBeginQueryARB(GL_SAMPLES_PASSED_ARB, id);
+
+
+#define TERM_QUERY()\
+ glEndQueryARB(GL_SAMPLES_PASSED_ARB);\
+
+
+namespace GLEAN {
+
+/* Generate a box which will be occluded by the occluder */
+void OccluQryTest::gen_box(GLfloat left, GLfloat right,
+ GLfloat top, GLfloat btm)
+{
+ glBegin(GL_POLYGON);
+ glVertex3f(left, top, 0);
+ glVertex3f(right, top, 0);
+ glVertex3f(right, btm, 0);
+ glVertex3f(left, btm, 0);
+ glEnd();
+}
+
+
+bool OccluQryTest::chk_ext()
+{
+ const char *ext = (const char *) glGetString(GL_EXTENSIONS);
+
+ if (!strstr(ext, "GL_ARB_occlusion_query")) {
+ fprintf(stdout, "W: Extension GL_ARB_occlusion_query is missing.\n");
+ return false;
+ }
+
+ return true;
+}
+
+
+GLuint OccluQryTest::find_unused_id()
+{
+ unsigned int id;
+ int counter = 0;
+
+#define MAX_FIND_ID_ROUND 256
+
+ while (1) {
+ /* assuming that at least 2^32-1 <id> can be generated */
+ id = random() % ((unsigned long)1 << 32 - 1);
+ if (id != 0 && glIsQueryARB(id) == GL_FALSE)
+ return id;
+ if (++ counter >= MAX_FIND_ID_ROUND) {
+ fprintf(stderr,
+ "W: Cannot find the unused id after [%d] tries.\n",
+ MAX_FIND_ID_ROUND);
+ return 0;
+ }
+ }
+}
+
+
+/* If multiple queries are issued on the same target and id prior to calling
+ * GetQueryObject[u]iVARB, the result returned will always be from the last
+ * query issued. The results from any queries before the last one will be lost
+ * if the results are not retrieved before starting a new query on the same
+ * target and id.
+ */
+bool OccluQryTest::conformOQ_GetObjivAval_multi1(GLuint id)
+{
+ GLint ready;
+ GLuint passed = 0;
+
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glMatrixMode( GL_PROJECTION );
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho( -1.0, 1.0, -1.0, 1.0, 0.0, 25.0 );
+
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -10.0);
+
+ /* draw the occluder (red) */
+ glColorMask(1, 1, 1, 1);
+ glDepthMask(GL_TRUE);
+ glColor3f(1, 0, 0);
+ gen_box(-0.5, 0.5, 0.5, -0.5);
+
+ glPushMatrix();
+ glTranslatef( 0.0, 0.0, -5.0);
+ glColorMask(0, 0, 0, 0);
+ glDepthMask(GL_FALSE);
+
+ /* draw the 1st box (gren) which is occluded by the occluder partly */
+ START_QUERY(id);
+ glColor3f(0, 1, 0);
+ gen_box(-0.51, 0.51, 0.51, -0.51);
+ TERM_QUERY();
+
+ /* draw the 2nd box (blue) which is occluded by the occluder throughly */
+ START_QUERY(id);
+ glColor3f(0, 0, 1);
+ gen_box(-0.4, 0.4, 0.4, -0.4);
+ TERM_QUERY();
+
+ glPopMatrix();
+
+ glPopMatrix();
+ glMatrixMode( GL_PROJECTION );
+ glPopMatrix();
+
+ do {
+ glGetQueryObjectivARB(id, GL_QUERY_RESULT_AVAILABLE_ARB, &ready);
+ } while (!ready);
+ glGetQueryObjectuivARB(id, GL_QUERY_RESULT_ARB, &passed);
+
+ // 'passed' should be zero
+ return passed > 0 ? false : true;
+}
+
+
+/* If mutiple queries are issued on the same target and diff ids prior
+ * to calling GetQueryObject[u]iVARB, the results should be
+ * corresponding to those queries (ids) respectively.
+ */
+bool OccluQryTest::conformOQ_GetObjivAval_multi2()
+{
+ GLuint passed1 = 0, passed2 = 0, passed3 = 0;
+ GLuint id1, id2, id3;
+
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glMatrixMode( GL_PROJECTION );
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho( -1.0, 1.0, -1.0, 1.0, 0.0, 25.0 );
+
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -10.0);
+
+
+ /* draw the occluder (red) */
+ glColorMask(1, 1, 1, 1);
+ glDepthMask(GL_TRUE);
+ glColor3f(1, 0, 0);
+ gen_box(-0.5, 0.5, 0.5, -0.5);
+
+ glPushMatrix();
+ glTranslatef( 0.0, 0.0, -5.0);
+ glColorMask(0, 0, 0, 0);
+ glDepthMask(GL_FALSE);
+
+ id1 = find_unused_id();
+ START_QUERY(id1);
+ /* draw green quad, much larger than occluder */
+ glColor3f(0, 1, 0);
+ gen_box(-0.7, 0.7, 0.7, -0.7);
+ TERM_QUERY();
+
+ id2 = find_unused_id();
+ START_QUERY(id2);
+ /* draw blue quad, slightly larger than occluder */
+ glColor3f(0, 0, 1);
+ gen_box(-0.53, 0.53, 0.53, -0.53);
+ TERM_QUERY();
+
+ id3 = find_unused_id();
+ START_QUERY(id3);
+ /* draw white quad, smaller than occluder (should not be visible) */
+ glColor3f(1, 1, 1);
+ gen_box(-0.4, 0.4, 0.4, -0.4);
+ TERM_QUERY();
+
+ glPopMatrix();
+
+ glGetQueryObjectuivARB(id1, GL_QUERY_RESULT_ARB, &passed1);
+ glGetQueryObjectuivARB(id2, GL_QUERY_RESULT_ARB, &passed2);
+ glGetQueryObjectuivARB(id3, GL_QUERY_RESULT_ARB, &passed3);
+
+ glDepthMask(GL_TRUE);
+
+
+ glDeleteQueriesARB(1, &id1);
+ glDeleteQueriesARB(1, &id2);
+ glDeleteQueriesARB(1, &id3);
+
+ glPopMatrix();
+ glMatrixMode( GL_PROJECTION );
+ glPopMatrix();
+
+ if ( passed1 > passed2 && passed2 > passed3 && passed3 == 0)
+ return true;
+ else
+ return false;
+}
+
+
+/*
+ * void GetQueryivARB(enum target, enum pname, int *params);
+ *
+ * If <pname> is QUERY_COUNTER_BITS_ARB, the number of bits in the counter
+ * for <target> will be placed in <params>. The minimum number of query
+ * counter bits allowed is a function of the implementation's maximum
+ * viewport dimensions (MAX_VIEWPORT_DIMS). If the counter is non-zero,
+ * then the counter must be able to represent at least two overdraws for
+ * every pixel in the viewport using only one sample buffer. The formula to
+ * compute the allowable minimum value is below (where n is the minimum
+ * number of bits):
+ * n = (min (32, ceil (log2 (maxViewportWidth x maxViewportHeight x 2) ) ) ) or 0
+ */
+bool OccluQryTest::conformOQ_GetQry_CnterBit()
+{
+ int bit_num, dims[2];
+ GLenum err;
+ float min_impl, min_bit_num;
+
+ /* get the minimum bit number supported by the implementation,
+ * and check the legality of result of GL_QUERY_COUNTER_BITS_ARB */
+ glGetQueryivARB(GL_SAMPLES_PASSED_ARB, GL_QUERY_COUNTER_BITS_ARB, &bit_num);
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims);
+ err = glGetError();
+ if (err == GL_INVALID_OPERATION || err == GL_INVALID_ENUM)
+ return false;
+
+ min_impl = ceil(logf((float)dims[0]*(float)dims[1]*1.0*2.0) / logf(2.0));
+ min_bit_num = 32.0 > min_impl ? min_impl : 32.0;
+
+ if ((float)bit_num < min_bit_num)
+ return false;
+
+ return true;
+}
+
+
+/* If BeginQueryARB is called with an unused <id>, that name is marked as used
+ * and associated with a new query object. */
+bool OccluQryTest::conformOQ_Begin_unused_id()
+{
+ unsigned int id;
+ bool pass = true;
+
+ id = find_unused_id();
+
+ if (id == 0)
+ return false;
+
+ glBeginQuery(GL_SAMPLES_PASSED_ARB, id);
+
+ if (glIsQueryARB(id) == GL_FALSE) {
+ fprintf(stderr, "F: Begin with a unused id failed.\n");
+ pass = false;
+ }
+
+ glEndQuery(GL_SAMPLES_PASSED_ARB);
+
+ return pass;
+}
+
+/* if EndQueryARB is called while no query with the same target is in progress,
+ * an INVALID_OPERATION error is generated. */
+bool OccluQryTest::conformOQ_EndAfter(GLuint id)
+{
+ START_QUERY(id);
+ TERM_QUERY();
+
+ glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+
+ if (glGetError() != GL_INVALID_OPERATION) {
+ fprintf(stderr, "F: No GL_INVALID_OPERATION generated if "
+ "EndQuery when there is no queries.\n");
+ return false;
+ }
+
+ return true;
+}
+
+
+/* Calling either GenQueriesARB while any query of any target is active causes
+ * an INVALID_OPERATION error to be generated. */
+bool OccluQryTest::conformOQ_GenIn(GLuint id)
+{
+ int pass = true;
+
+ START_QUERY(id);
+
+ glGenQueriesARB(1, &id);
+ if (glGetError() != GL_INVALID_OPERATION) {
+ fprintf(stderr, "F: No GL_INVALID_OPERATION generated if "
+ "GenQueries in the progress of another.\n");
+ pass = false;
+ }
+
+ TERM_QUERY();
+
+ return pass;
+}
+
+
+/* Calling either DeleteQueriesARB while any query of any target is active causes
+ * an INVALID_OPERATION error to be generated. */
+bool OccluQryTest::conformOQ_DeleteIn(GLuint id)
+{
+ int pass = true;
+
+ START_QUERY(id);
+
+ if (id > 0) {
+ glDeleteQueriesARB(1, &id);
+
+ if (glGetError() != GL_INVALID_OPERATION) {
+ fprintf(stderr, "F: No GL_INVALID_OPERATION generated if "
+ "DeleteQueries in the progress of another.\n");
+ pass = false;
+ }
+ }
+
+ TERM_QUERY();
+
+ return pass;
+}
+
+
+/* If BeginQueryARB is called while another query is already in progress with
+ * the same target, an INVALID_OPERATION error should be generated. */
+bool OccluQryTest::conformOQ_BeginIn(GLuint id)
+{
+ int pass = true;
+
+ START_QUERY(id);
+
+ /* Issue another BeginQueryARB while another query is already in
+ progress */
+ glBeginQueryARB(GL_SAMPLES_PASSED_ARB, id);
+
+ if (glGetError() != GL_INVALID_OPERATION) {
+ fprintf(stderr, "F: No GL_INVALID_OPERATION generated if "
+ "BeginQuery in the progress of another.\n");
+ pass = false;
+ }
+
+ TERM_QUERY();
+ return pass;
+}
+
+
+/* if the query object named by <id> is currently active, then an
+ * INVALID_OPERATION error is generated. */
+bool OccluQryTest::conformOQ_GetObjAvalIn(GLuint id)
+{
+ int pass = true;
+ GLint param;
+
+ START_QUERY(id);
+
+ glGetQueryObjectivARB(id, GL_QUERY_RESULT_AVAILABLE_ARB, &param);
+ if (glGetError() != GL_INVALID_OPERATION)
+ pass = false;
+
+ glGetQueryObjectuivARB(id, GL_QUERY_RESULT_AVAILABLE_ARB, (GLuint *)&param);
+ if (glGetError() != GL_INVALID_OPERATION)
+ pass = false;
+
+ if (pass == false) {
+ fprintf(stderr, "F: No GL_INVALID_OPERATION generated if "
+ "GetQueryObjectuiv with GL_QUERY_RESULT_AVAILABLE_ARB "
+ "in the active progress.\n");
+ }
+ TERM_QUERY();
+
+ return pass;
+}
+
+
+/* if the query object named by <id> is currently active, then an
+ * INVALID_OPERATION error is generated. */
+bool OccluQryTest::conformOQ_GetObjResultIn(GLuint id)
+{
+ int pass = true;
+ GLint param;
+
+ START_QUERY(id);
+
+ glGetQueryObjectivARB(id, GL_QUERY_RESULT_ARB, &param);
+ if (glGetError() != GL_INVALID_OPERATION)
+ pass = false;
+
+ glGetQueryObjectuivARB(id, GL_QUERY_RESULT_ARB, (GLuint *)&param);
+ if (glGetError() != GL_INVALID_OPERATION)
+ pass = false;
+
+ if (pass == false) {
+ fprintf(stderr, "F: No GL_INVALID_OPERATION generated if "
+ "GetQueryObject[u]iv with GL_QUERY_RESULT_ARB "
+ "in the active progress.\n");
+ }
+ TERM_QUERY();
+
+ return pass;
+}
+
+
+/* If <id> is not the name of a query object, then an INVALID_OPERATION error
+ * is generated. */
+bool OccluQryTest::conformOQ_GetObjivAval(GLuint id)
+{
+ GLuint id_tmp;
+ GLint param;
+
+ START_QUERY(id);
+ TERM_QUERY();
+
+ id_tmp = find_unused_id();
+
+ if (id_tmp == 0)
+ return false;
+
+ glGetQueryObjectivARB(id_tmp, GL_QUERY_RESULT_AVAILABLE_ARB, &param);
+
+ if (glGetError() != GL_INVALID_OPERATION) {
+ fprintf(stderr, "F: No GL_INVALID_OPERATION generated if "
+ "GetQueryObjectuiv can still query the result"
+ "by an unused query id\n.");
+ return false;
+ }
+
+ return true;
+}
+
+
+/* Basic tests on query id generation and deletion */
+bool OccluQryTest::conformOQ_Gen_Delete(unsigned int id_n)
+{
+ GLuint *ids1 = NULL, *ids2 = NULL;
+ unsigned int i, j;
+ bool pass = true;
+
+ ids1 = (GLuint *)malloc(id_n * sizeof(GLuint));
+ ids2 = (GLuint *)malloc(id_n * sizeof(GLuint));
+
+ if (!ids1 || !ids2) {
+ fprintf(stderr, "F: Cannot alloc memory to pointer ids[12].\n");
+ return false;
+ }
+
+ glGenQueriesARB(id_n, ids1);
+ glGenQueriesARB(id_n, ids2);
+
+ /* compare whether <id> generated during the previous 2 rounds are
+ * duplicated */
+ for (i = 0; i < id_n; i ++) {
+ for (j = 0; j < id_n; j ++) {
+ if (ids1[i] == ids2[j]) {
+ fprintf(stderr, "F: ids1[%d] == ids2[%d] == %u.\n",
+ i, j, ids1[i]);
+ pass = false;
+ }
+ }
+ }
+
+ /* Note: the spec seems to indicate that glGenQueries reserves query
+ * IDs but doesn't create query objects for those IDs. A query object
+ * isn't created until they are used by glBeginQuery. So this part
+ * of the test is invalid.
+ */
+#if 0
+ /* Checkout whether the Query ID just generated is valid */
+ for (i = 0; i < id_n; i ++) {
+ if (glIsQueryARB(ids1[i]) == GL_FALSE) {
+ fprintf(stderr, "F: id [%d] just generated is not valid.\n",
+ ids1[i]);
+ pass = false;
+ }
+ }
+#endif
+
+ /* if <id> is a non-zero value that is not the name of a query object,
+ * IsQueryARB returns FALSE. */
+ glDeleteQueriesARB(id_n, ids1);
+ for (i = 0; i < id_n; i ++) {
+ if (glIsQueryARB(ids1[i]) == GL_TRUE) {
+ fprintf(stderr, "F: id [%d] just deleted is still valid.\n",
+ ids1[i]);
+ pass = false;
+ }
+ }
+
+ /* Delete only for sanity purpose */
+ glDeleteQueriesARB(id_n, ids2);
+
+ if (ids1)
+ free(ids1);
+ if (ids2)
+ free(ids2);
+
+
+ ids1 = (GLuint *)malloc(id_n * sizeof(GLuint));
+ if (ids1 == NULL)
+ return false;
+
+ for (i = 0; i < id_n; i ++) {
+ glGenQueriesARB(1, ids1 + i);
+ for (j = 0; j < i; j ++) {
+ if (ids1[i] == ids1[j]) {
+ fprintf(stderr, "E: duplicated id generated [ %u ]",
+ ids1[i]);
+ pass = false;
+ }
+ }
+ }
+
+ glDeleteQueriesARB(id_n, ids1);
+ if (ids1)
+ free(ids1);
+
+ return pass;
+}
+
+
+/* If <id> is zero, IsQueryARB should return FALSE.*/
+bool OccluQryTest::conformOQ_IsIdZero(void)
+{
+ if (glIsQueryARB(0) == GL_TRUE) {
+ fprintf(stderr, "F: zero is treated as a valid id by"
+ "IsQueryARB().\n");
+ return false;
+ }
+
+ return true;
+}
+
+
+/* If BeginQueryARB is called with an <id> of zero, an INVALID_OPERATION error
+ * should be generated. */
+bool OccluQryTest::conformOQ_BeginIdZero(void)
+{
+ glBeginQueryARB(GL_SAMPLES_PASSED_ARB, 0);
+ if (glGetError() != GL_INVALID_OPERATION) {
+ fprintf(stderr, "F: No GL_INVALID_OPERATION generated if "
+ "BeginQuery with zero ID.\n");
+ return false;
+ }
+
+ return true;
+}
+
+
+void OccluQryTest::runOne(MultiTestResult &r, Window &w)
+{
+ bool result;
+ (void) w;
+ GLuint queryId;
+
+ if (!chk_ext())
+ return;
+ glEnable(GL_DEPTH_TEST);
+ glGenQueriesARB(1, &queryId);
+
+ if (queryId == 0)
+ return;
+
+#if defined(GL_ARB_occlusion_query)
+ result = conformOQ_GetQry_CnterBit();
+ reportPassFail(r, result, "conformOQ_GetQry_CnterBit");
+
+ result = conformOQ_GetObjivAval_multi1(queryId);
+ reportPassFail(r, result, "conformOQ_GetObjivAval_multi1");
+
+ result = conformOQ_GetObjivAval_multi2();
+ reportPassFail(r, result, "conformOQ_GetObjivAval_multi2");
+
+ result = conformOQ_Begin_unused_id();
+ reportPassFail(r, result, "conformOQ_Begin_unused_id");
+
+ result = conformOQ_EndAfter(queryId);
+ reportPassFail(r, result, "conformOQ_EndAfter");
+
+ result = conformOQ_GenIn(queryId);
+ reportPassFail(r, result, "conformOQ_GenIn");
+
+ result = conformOQ_BeginIn(queryId);
+ reportPassFail(r, result, "conformOQ_BeginIn");
+
+ result = conformOQ_DeleteIn(queryId);
+ reportPassFail(r, result, "conformOQ_DeleteIn");
+
+ result = conformOQ_GetObjAvalIn(queryId);
+ reportPassFail(r, result, "conformOQ_GetObjAvalIn");
+
+ result = conformOQ_GetObjResultIn(queryId);
+ reportPassFail(r, result, "conformOQ_GetObjResultIn");
+
+ result = conformOQ_GetObjivAval(queryId);
+ reportPassFail(r, result, "conformOQ_GetObjivAval");
+
+ result = conformOQ_Gen_Delete(64);
+ reportPassFail(r, result, "conformOQ_Gen_Delete");
+
+ result = conformOQ_IsIdZero();
+ reportPassFail(r, result, "conformOQ_IsIdZero");
+
+ result = conformOQ_BeginIdZero();
+ reportPassFail(r, result, "conformOQ_BeginIdZero");
+
+ glDeleteQueriesARB(1, &queryId);
+
+ r.pass = (r.numFailed == 0);
+#endif
+}
+
+
+void OccluQryTest::reportPassFail(MultiTestResult &r,
+ bool pass, const char *msg) const
+{
+ if (pass) {
+ if (env->options.verbosity)
+ env->log << name << " subcase PASS: "
+ << msg << " test\n";
+ r.numPassed++;
+ } else {
+ if (env->options.verbosity)
+ env->log << name << " subcase FAIL: "
+ << msg << " test\n";
+ r.numFailed++;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+OccluQryTest occluQryTest("occluQry", "window, rgb, z",
+ "GL_ARB_occlusion_query",
+ "Test occlusion query comformance.\n");
+} // namespace GLEAN
diff --git a/tests/glean/toccluqry.h b/tests/glean/toccluqry.h
new file mode 100644
index 000000000..c4f74e3f4
--- /dev/null
+++ b/tests/glean/toccluqry.h
@@ -0,0 +1,72 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Wei Wang <wei.z.wang@intel.com>
+ *
+ */
+
+
+// toccluqry.h: Test basic ARB_occlusion_query support.
+
+#ifndef __toccluqry_h__
+#define __toccluqry_h__
+
+#include "tmultitest.h"
+
+namespace GLEAN {
+
+class OccluQryTest: public MultiTest {
+ public:
+ OccluQryTest(const char* testName, const char* filter,
+ const char *prereqs, const char* description):
+ MultiTest(testName, filter, prereqs, description) {
+ }
+
+ virtual void runOne(MultiTestResult& r, Window& w);
+ protected:
+ bool conformOQ_GetObjivAval_multi1(GLuint id);
+ bool conformOQ_GetObjivAval_multi2();
+ bool conformOQ_GetQry_CnterBit();
+ bool conformOQ_Begin_unused_id();
+ bool conformOQ_EndAfter(GLuint id);
+ bool conformOQ_GenIn(GLuint id);
+ bool conformOQ_BeginIn(GLuint id);
+ bool conformOQ_DeleteIn(GLuint id);
+ bool conformOQ_GetObjAvalIn(GLuint id);
+ bool conformOQ_GetObjResultIn(GLuint id);
+ bool conformOQ_GetObjivAval(GLuint id);
+ bool conformOQ_Gen_Delete(unsigned int id_n);
+ bool conformOQ_IsIdZero(void);
+ bool conformOQ_BeginIdZero(void);
+ private:
+ void gen_box(GLfloat left, GLfloat right, GLfloat top, GLfloat btm);
+ GLuint find_unused_id();
+ bool chk_ext();
+ void reportPassFail(MultiTestResult &r, bool pass, const char *msg) const;
+};
+
+} // namespace GLEAN
+
+#endif
diff --git a/tests/glean/tpbo.cpp b/tests/glean/tpbo.cpp
new file mode 100644
index 000000000..ba24bde17
--- /dev/null
+++ b/tests/glean/tpbo.cpp
@@ -0,0 +1,1240 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyrigth (C) 2007 Intel Corporation
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+//
+// Authors:
+// Shuang He <shuang.he@intel.com>
+//
+// tpbo.cpp: Test OpenGL Extension GL_ARB_pixel_buffer_object
+
+
+#define GL_GLEXT_PROTOTYPES
+#include "tpbo.h"
+#include <cassert>
+#include <math.h>
+#include "timer.h"
+namespace GLEAN
+{
+
+static int usePBO;
+#define BUFFER_OFFSET(i) ((char *)NULL + (i))
+
+bool PBOTest::setup(void)
+{
+ glMatrixMode(GL_PROJECTION);
+
+ glLoadIdentity();
+ gluOrtho2D(0, 100, 0, 100);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glDrawBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
+
+ // compute error tolerances (may need fine-tuning)
+ int
+ bufferBits[5];
+
+ glGetIntegerv(GL_RED_BITS, &bufferBits[0]);
+ glGetIntegerv(GL_GREEN_BITS, &bufferBits[1]);
+ glGetIntegerv(GL_BLUE_BITS, &bufferBits[2]);
+ glGetIntegerv(GL_ALPHA_BITS, &bufferBits[3]);
+ glGetIntegerv(GL_DEPTH_BITS, &bufferBits[4]);
+
+ tolerance[0] = 2.0 / (1 << bufferBits[0]);
+ tolerance[1] = 2.0 / (1 << bufferBits[1]);
+ tolerance[2] = 2.0 / (1 << bufferBits[2]);
+ if (bufferBits[3])
+ tolerance[3] = 2.0 / (1 << bufferBits[3]);
+ else
+ tolerance[3] = 1.0;
+ if (bufferBits[4])
+ tolerance[4] = 16.0 / (1 << bufferBits[4]);
+ else
+ tolerance[4] = 1.0;
+
+ // Check if GL_ARB_pixel_buffer_object is supported
+ if (!strstr((char *) glGetString(GL_EXTENSIONS), "GL_ARB_pixel_buffer_object")) {
+ printf("GL_ARB_pixel_buffer_object is not supported\n");
+ usePBO = 0;
+ return false;
+ }
+ else {
+ printf("GL_ARB_pixel_buffer_object is supported\n");
+ usePBO = 1;
+ }
+
+ return true;
+}
+
+
+void
+PBOTest::reportFailure(const char *msg, const int line) const
+{
+ env->log << "FAILURE: " << msg << " (at tpbo.cpp:" << line << ")\n";
+}
+
+void
+PBOTest::reportFailure(const char *msg, const GLenum target, const int line) const
+{
+ env->log << "FAILURE: " << msg;
+ if (target == GL_FRAGMENT_SHADER)
+ env->log << " (fragment)";
+ else
+ env->log << " (vertex)";
+ env->log << " (at tpbo.cpp:" << line << ")\n";
+}
+
+#define REPORT_FAILURE(MSG) reportFailure(MSG, __LINE__)
+#define REPORT_FAILURE_T(MSG, TARGET) reportFailure(MSG, TARGET, __LINE__)
+// Compare actual and expected colors
+bool PBOTest::equalColors(const GLfloat act[3], const GLfloat exp[3]) const
+{
+ if ((fabsf(act[0] - exp[0]) > tolerance[0])
+ || (fabsf(act[1] - exp[1]) > tolerance[1])
+ || (fabsf(act[2] - exp[2]) > tolerance[2])) {
+ return false;
+ }
+ else
+ return true;
+}
+
+bool PBOTest::equalColors1(const GLubyte act[3], const GLubyte exp[3]) const
+{
+ if ((act[0] != exp[0])
+ || (act[1] != exp[1])
+ || (act[2] != exp[2])) {
+ return false;
+ }
+ else
+ return true;
+}
+
+
+
+#define TEXSIZE 64
+
+bool PBOTest::testSanity(void)
+{
+ GLuint pbs[1];
+ GLuint pb_binding;
+
+ if (!usePBO)
+ return true;
+
+ // Check default binding
+ glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING_ARB, (GLint *) & pb_binding);
+ if (pb_binding != 0) {
+ REPORT_FAILURE("Failed to bind unpack pixel buffer object");
+ return false;
+ }
+
+ glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING_ARB, (GLint *) & pb_binding);
+ if (pb_binding != 0) {
+ REPORT_FAILURE("Failed to bind pack pixel buffer object");
+ return false;
+ }
+
+ glGenBuffersARB(1, pbs);
+
+ if (glIsBufferARB(pbs[0]) != GL_TRUE) {
+ REPORT_FAILURE("Failed to call glIsBuffersARB");
+ return false;
+ }
+
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbs[0]);
+ glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING_ARB, (GLint *) & pb_binding);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+ if (pb_binding != pbs[0]) {
+ REPORT_FAILURE("Failed to bind unpack pixel buffer object");
+ return false;
+ }
+
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbs[0]);
+ glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING_ARB, (GLint *) & pb_binding);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
+ if (pb_binding != pbs[0]) {
+ REPORT_FAILURE("Failed to bind unpack pixel buffer object");
+ return false;
+ }
+
+ glDeleteBuffersARB(1, pbs);
+
+ if (glIsBufferARB(pbs[0]) == GL_TRUE) {
+ REPORT_FAILURE("Failed to call glIsBuffersARB");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool PBOTest::testDrawPixels(void)
+{
+ int useUnpackBuffer;
+ int usePackBuffer;
+ GLuint pb_pack[1];
+ GLuint pb_unpack[1];
+ GLubyte buf[windowSize * windowSize * 4];
+ GLubyte t[TEXSIZE * TEXSIZE * 4];
+ int i, j;
+ GLubyte * pboPackMem = NULL;
+ GLubyte black[3] = { 0, 0, 0 };
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ glBindBuffer(GL_PIXEL_PACK_BUFFER_EXT, 0);
+
+ for (useUnpackBuffer = 0; useUnpackBuffer < usePBO + 1; useUnpackBuffer++) {
+ for (usePackBuffer = 0; usePackBuffer < usePBO + 1; usePackBuffer++) {
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ if (useUnpackBuffer) {
+ glGenBuffersARB(1, pb_unpack);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb_unpack[0]);
+ glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT,
+ TEXSIZE * TEXSIZE * 4 * sizeof(GLubyte), NULL,
+ GL_STREAM_DRAW);
+ }
+ GLubyte *pboMem = NULL;
+ if (useUnpackBuffer) {
+ pboMem = (GLubyte *) glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT,
+ GL_WRITE_ONLY);
+ }
+ else {
+ pboMem = t;
+ }
+
+ for (i = 0; i < TEXSIZE; i++)
+ for (j = 0; j < TEXSIZE; j++) {
+ pboMem[4 * (i * TEXSIZE + j)] = i % 256;
+ pboMem[4 * (i * TEXSIZE + j) + 1] = i % 256;
+ pboMem[4 * (i * TEXSIZE + j) + 2] = i % 256;
+ pboMem[4 * (i * TEXSIZE + j) + 3] = 0;
+ }
+
+ if (useUnpackBuffer) {
+ glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ }
+
+ if (useUnpackBuffer) {
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb_unpack[0]);
+ glDrawPixels(TEXSIZE, TEXSIZE, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ }
+ else
+ glDrawPixels(TEXSIZE, TEXSIZE, GL_BGRA, GL_UNSIGNED_BYTE, pboMem);
+
+ // Check the result
+ if (usePackBuffer) {
+ glGenBuffersARB(1, pb_pack);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, pb_pack[0]);
+ glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT,
+ windowSize * windowSize * 4 *
+ sizeof(GL_UNSIGNED_BYTE), NULL, GL_STREAM_DRAW);
+ glReadPixels(0, 0, windowSize, windowSize, GL_BGRA,
+ GL_UNSIGNED_BYTE, NULL);
+ pboPackMem = (GLubyte *) glMapBufferARB(GL_PIXEL_PACK_BUFFER_EXT,
+ GL_READ_ONLY);
+ }
+ else {
+ pboPackMem = buf;
+ glReadPixels(0, 0, windowSize, windowSize, GL_BGRA,
+ GL_UNSIGNED_BYTE, pboPackMem);
+ }
+
+ for (j = 0; j < windowSize; j++) {
+ for (i = 0; i < windowSize; i++) {
+ GLubyte exp[3];
+ exp[0] = j % 256;
+ exp[1] = j % 256;
+ exp[2] = j % 256;
+
+ if (i < TEXSIZE && j < TEXSIZE) {
+ if (equalColors1(&pboPackMem[(j * windowSize + i) * 4], exp)
+ != true) {
+ REPORT_FAILURE("glDrawPixels failed");
+ printf(" got (%d, %d) = [%d, %d, %d], ", i, j,
+ pboPackMem[(j * windowSize + i) * 4],
+ pboPackMem[(j * windowSize + i) * 4 + 1],
+ pboPackMem[(j * windowSize + i) * 4 + 2]);
+ printf("should be [%d, %d, %d]\n",
+ exp[0], exp[1], exp[2]);
+
+ return false;
+ }
+ }
+ else {
+ if (equalColors1(&pboPackMem[(j * windowSize + i) * 4],
+ black) != true) {
+ REPORT_FAILURE("glDrawPixels failed");
+ printf("(%d, %d) = [%d, %d, %d], ", i, j,
+ pboPackMem[(j * windowSize + i) * 4],
+ pboPackMem[(j * windowSize + i) * 4 + 1],
+ pboPackMem[(j * windowSize + i) * 4 + 2]);
+ printf("should be [0.0, 0.0, 0.0]\n");
+ return false;
+ }
+
+ }
+ }
+ }
+
+
+ if (usePackBuffer) {
+ glBindBuffer(GL_PIXEL_PACK_BUFFER_EXT, 0);
+ glDeleteBuffersARB(1, pb_pack);
+ }
+
+ if (useUnpackBuffer) {
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ glDeleteBuffersARB(1, pb_unpack);
+ }
+
+ }
+ }
+
+ return true;
+}
+
+
+bool PBOTest::testPixelMap(void)
+{
+ int useUnpackBuffer;
+ int usePackBuffer;
+ GLuint pb_pack[1];
+ GLuint pb_unpack[1];
+ int i;
+ int size;
+ int max;
+
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);
+
+ glGetIntegerv(GL_MAX_PIXEL_MAP_TABLE, &max);
+
+ for (usePackBuffer = 0; usePackBuffer < usePBO + 1; usePackBuffer++) {
+ for (useUnpackBuffer = 0; useUnpackBuffer < usePBO + 1;
+ useUnpackBuffer++) {
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ if (useUnpackBuffer) {
+ glGenBuffersARB(1, pb_unpack);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb_unpack[0]);
+ glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, max * sizeof(GLushort),
+ NULL, GL_STREAM_DRAW);
+ }
+ GLushort *pboMem = NULL;
+ if (useUnpackBuffer) {
+ pboMem = (GLushort *) glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT,
+ GL_WRITE_ONLY);
+ }
+ else {
+ pboMem = (GLushort *) malloc(sizeof(GLushort) * max);
+ }
+ for (i = 0; i < max; i++)
+ pboMem[i] = max - i - 1;
+
+ if (useUnpackBuffer) {
+ glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
+ glPixelMapusv(GL_PIXEL_MAP_R_TO_R, max, NULL);
+ glPixelMapusv(GL_PIXEL_MAP_G_TO_G, max, NULL);
+ glPixelMapusv(GL_PIXEL_MAP_B_TO_B, max, NULL);
+ glPixelMapusv(GL_PIXEL_MAP_A_TO_A, max, NULL);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ }
+ else {
+ glPixelMapusv(GL_PIXEL_MAP_R_TO_R, max, pboMem);
+ glPixelMapusv(GL_PIXEL_MAP_G_TO_G, max, pboMem);
+ glPixelMapusv(GL_PIXEL_MAP_B_TO_B, max, pboMem);
+ glPixelMapusv(GL_PIXEL_MAP_A_TO_A, max, pboMem);
+ free(pboMem);
+ }
+
+
+ glGetIntegerv(GL_PIXEL_MAP_R_TO_R_SIZE, &size);
+ if (size != max) {
+ REPORT_FAILURE("glPixelMap failed");
+ return false;
+ }
+ glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
+
+ // Read back pixel map
+ if (usePackBuffer) {
+ glGenBuffersARB(1, pb_pack);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, pb_pack[0]);
+ glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT, max * sizeof(GLushort),
+ NULL, GL_STREAM_DRAW);
+ glGetPixelMapusv(GL_PIXEL_MAP_R_TO_R, NULL);
+ pboMem = (GLushort *) glMapBufferARB(GL_PIXEL_PACK_BUFFER_EXT,
+ GL_READ_ONLY);
+ }
+ else {
+ pboMem = (GLushort *) malloc(sizeof(GLushort) * max);
+ glGetPixelMapusv(GL_PIXEL_MAP_R_TO_R, pboMem);
+ }
+
+ for (i = 0; i < max; i++) {
+ if (pboMem[i] != (255 - i)) {
+ REPORT_FAILURE("get PixelMap failed");
+ return false;
+ }
+ }
+
+
+ if (usePackBuffer) {
+ glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_EXT);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);
+ glDeleteBuffersARB(1, pb_pack);
+ }
+ else {
+ free(pboMem);
+ }
+
+ if (useUnpackBuffer) {
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ glDeleteBuffersARB(1, pb_unpack);
+ }
+
+ }
+ }
+
+ return true;
+}
+
+bool PBOTest::testBitmap(void)
+{
+ GLuint pb_unpack[1];
+ GLuint pb_pack[1];
+ int useUnpackBuffer = usePBO;
+ int usePackBuffer = 0;
+ GLubyte bitmap[TEXSIZE * TEXSIZE / 8];
+ GLfloat buf[windowSize * windowSize * 3];
+ GLfloat white[3] = { 1.0, 1.0, 1.0 };
+ GLfloat black[3] = { 0.0, 0.0, 0.0 };
+ int i, j;
+ GLubyte *pboUnpackMem = NULL;
+ GLfloat *pboPackMem = NULL;
+
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);
+
+ for (usePackBuffer = 0; usePackBuffer < usePBO + 1; usePackBuffer++) {
+ for (useUnpackBuffer = 0; useUnpackBuffer < usePBO + 1;
+ useUnpackBuffer++) {
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if (useUnpackBuffer) {
+ glGenBuffersARB(1, pb_unpack);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb_unpack[0]);
+ glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, TEXSIZE * TEXSIZE, NULL,
+ GL_STREAM_DRAW);
+ pboUnpackMem = (GLubyte *) glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT,
+ GL_WRITE_ONLY);
+ }
+ else {
+ pboUnpackMem = bitmap;
+ }
+
+ for (i = 0; i < TEXSIZE * TEXSIZE / 8; i++) {
+ pboUnpackMem[i] = 0xAA;
+ }
+
+
+ glColor4f(1.0, 1.0, 1.0, 0.0);
+ glRasterPos2f(0.0, 0.0);
+ if (useUnpackBuffer) {
+ glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
+ glBitmap(TEXSIZE, TEXSIZE, 0, 0, 0, 0, NULL);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ }
+ else
+ glBitmap(TEXSIZE, TEXSIZE, 0, 0, 0, 0, pboUnpackMem);
+
+ // Check the result
+ if (usePackBuffer) {
+ glGenBuffersARB(1, pb_pack);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, pb_pack[0]);
+ glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT, TEXSIZE * TEXSIZE, NULL,
+ GL_STREAM_DRAW);
+ glReadPixels(0, 0, windowSize, windowSize, GL_RGB, GL_FLOAT,
+ NULL);
+ pboPackMem =
+ (GLfloat *) glMapBufferARB(GL_PIXEL_PACK_BUFFER_EXT,
+ GL_READ_ONLY);
+ }
+ else {
+ pboPackMem = buf;
+ glReadPixels(0, 0, windowSize, windowSize, GL_RGB, GL_FLOAT,
+ pboPackMem);
+ }
+
+ for (j = 0; j < windowSize; j++) {
+ for (i = 0; i < windowSize; i++) {
+ const GLfloat *exp;
+ if ((i & 1))
+ exp = black;
+ else
+ exp = white;
+ if (i < TEXSIZE && j < TEXSIZE) {
+ if (equalColors(&pboPackMem[(j * windowSize + i) * 3], exp)
+ != true) {
+ REPORT_FAILURE("glBitmap failed");
+ printf(" got (%d, %d) = [%f, %f, %f], ", i, j,
+ pboPackMem[(j * windowSize + i) * 3],
+ pboPackMem[(j * windowSize + i) * 3 + 1],
+ pboPackMem[(j * windowSize + i) * 3 + 2]);
+ printf("should be [%f, %f, %f]\n",
+ exp[0], exp[1], exp[2]);
+
+ return false;
+ }
+ }
+ else {
+ if (equalColors
+ (&pboPackMem[(j * windowSize + i) * 3],
+ black) != true) {
+ REPORT_FAILURE("glBitmap failed");
+ printf("(%d, %d) = [%f, %f, %f], ", i, j,
+ pboPackMem[(j * windowSize + i) * 3],
+ pboPackMem[(j * windowSize + i) * 3 + 1],
+ pboPackMem[(j * windowSize + i) * 3 + 2]);
+ printf("should be [0.0, 0.0, 0.0]\n");
+ return false;
+ }
+
+ }
+ }
+ }
+ if (usePackBuffer) {
+ glUnmapBuffer(GL_PIXEL_PACK_BUFFER_EXT);
+ glBindBuffer(GL_PIXEL_PACK_BUFFER_EXT, 0);
+ glDeleteBuffersARB(1, pb_pack);
+ }
+
+ if (useUnpackBuffer) {
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ glDeleteBuffersARB(1, pb_unpack);
+ }
+ }
+ }
+ return true;
+}
+
+
+bool PBOTest::testTexImage(void)
+{
+ int breakCOWPBO, breakCOWTexture;
+ int useTexUnpackBuffer, useTexPackBuffer;
+ GLuint unpack_pb[1];
+ GLuint pack_pb[1];
+ GLfloat t1[TEXSIZE * TEXSIZE * 3];
+ GLfloat t2[TEXSIZE * TEXSIZE * 3];
+ GLfloat *pboMem = NULL;
+ int i, j;
+ GLfloat green[3] = { 1.0, 1.0, 0.0 };
+ GLfloat black[3] = { 0.0, 0.0, 0.0 };
+ GLfloat buf[windowSize * windowSize * 3];
+
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);
+
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ for (useTexPackBuffer = 0; useTexPackBuffer < usePBO + 1;
+ useTexPackBuffer++) {
+ for (useTexUnpackBuffer = 0; useTexUnpackBuffer < usePBO + 1;
+ useTexUnpackBuffer++) {
+ for (breakCOWPBO = 0; breakCOWPBO < useTexUnpackBuffer + 1;
+ breakCOWPBO++) {
+ for (breakCOWTexture = 0;
+ breakCOWTexture < useTexUnpackBuffer + 1;
+ breakCOWTexture++) {
+ if (useTexUnpackBuffer) {
+ glGenBuffersARB(1, unpack_pb);
+ if (glIsBufferARB(unpack_pb[0]) == false)
+ return false;
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, unpack_pb[0]);
+ glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT,
+ TEXSIZE * TEXSIZE * 3 * sizeof(GLfloat), NULL,
+ GL_STREAM_DRAW);
+ }
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+
+ if (useTexUnpackBuffer) {
+ pboMem =
+ (GLfloat *) glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT,
+ GL_WRITE_ONLY);
+ }
+ else {
+ pboMem = t1;
+ }
+
+ for (i = 0; i < TEXSIZE * TEXSIZE; i++) {
+ pboMem[3 * i] = 1.0;
+ pboMem[3 * i + 1] = 1.0;
+ pboMem[3 * i + 2] = 0.0;
+ }
+
+ if (useTexUnpackBuffer) {
+ glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXSIZE, TEXSIZE, 0,
+ GL_RGB, GL_FLOAT, NULL);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ }
+ else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXSIZE, TEXSIZE, 0,
+ GL_RGB, GL_FLOAT, pboMem);
+
+ if (useTexUnpackBuffer) {
+ if (breakCOWPBO) {
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, unpack_pb[0]);
+ pboMem =
+ (GLfloat *) glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT,
+ GL_WRITE_ONLY);
+ for (i = 0; i < TEXSIZE * TEXSIZE * 3; i++)
+ pboMem[i] = 0.2;
+ glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ }
+ }
+
+ if (useTexUnpackBuffer) {
+ if (breakCOWTexture) {
+ GLfloat temp[1 * 1 * 3];
+ for (i = 0; i < 1 * 1 * 3; i++)
+ temp[i] = 0.8;
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGB,
+ GL_FLOAT, temp);
+ }
+ }
+
+ // Check PBO's content
+ if (useTexUnpackBuffer) {
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, unpack_pb[0]);
+ pboMem = (GLfloat *) glMapBuffer(GL_PIXEL_UNPACK_BUFFER_EXT,
+ GL_READ_ONLY);
+ if (breakCOWPBO) {
+ for (i = 0; i < TEXSIZE * TEXSIZE * 3; i++)
+ if (fabsf(pboMem[i] - 0.2) > tolerance[0]) {
+ REPORT_FAILURE
+ ("PBO modified by someone else, there must be something wrong");
+ return false;
+ }
+ }
+ glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ }
+
+
+ // Read texture back
+ if (useTexPackBuffer) {
+ glGenBuffersARB(1, pack_pb);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, pack_pb[0]);
+ glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT,
+ TEXSIZE * TEXSIZE * 3 * sizeof(GLfloat), NULL,
+ GL_STREAM_DRAW);
+ glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_FLOAT, NULL);
+ pboMem = (GLfloat *) glMapBufferARB(GL_PIXEL_PACK_BUFFER_EXT,
+ GL_READ_ONLY);
+ }
+ else {
+ glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_FLOAT, t2);
+ pboMem = t2;
+ }
+
+ // Check texture image
+ for (i = 0; i < TEXSIZE * TEXSIZE; i++) {
+ if (i == 0 && breakCOWTexture && useTexUnpackBuffer) {
+ GLfloat exp[3] = { 0.8, 0.8, 0.8 };
+ if (equalColors(&pboMem[i * 3], exp) != true) {
+ REPORT_FAILURE("glGetTexImage failed");
+ printf(" got (%d) = [%f, %f, %f], ", i,
+ pboMem[i * 3],
+ pboMem[i * 3 + 1], pboMem[i * 3 + 2]);
+ printf("should be [%f, %f, %f]\n",
+ exp[0], exp[1], exp[2]);
+
+ return false;
+ }
+ }
+ else {
+ GLfloat exp[3] = { 1.0, 1.0, 0.0 };
+ if (equalColors(&pboMem[i * 3], exp) != true) {
+ REPORT_FAILURE("glGetTexImage failed");
+ printf(" got (%d) = [%f, %f, %f], ", i,
+ pboMem[i * 3],
+ pboMem[i * 3 + 1], pboMem[i * 3 + 2]);
+ printf("should be [%f, %f, %f]\n",
+ exp[0], exp[1], exp[2]);
+
+ return false;
+ }
+ }
+ }
+
+ if (useTexPackBuffer) {
+ glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_EXT);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);
+ glDeleteBuffersARB(1, pack_pb);
+ }
+ if (useTexUnpackBuffer) {
+ glDeleteBuffersARB(1, unpack_pb);
+ }
+
+ glEnable(GL_TEXTURE_2D);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0);
+ glVertex2f(0, 0);
+ glTexCoord2f(1, 0);
+ glVertex2f(TEXSIZE, 0);
+ glTexCoord2f(1, 1);
+ glVertex2f(TEXSIZE, TEXSIZE);
+ glTexCoord2f(0, 1);
+ glVertex2f(0, TEXSIZE);
+ glEnd();
+
+ glReadPixels(0, 0, windowSize, windowSize, GL_RGB, GL_FLOAT,
+ buf);
+ for (j = 0; j < windowSize; j++) {
+ for (i = 0; i < windowSize; i++) {
+ if (i == 0 && j == 0 && breakCOWTexture
+ && useTexUnpackBuffer) {
+ GLfloat exp[3] = { 0.8, 0.8, 0.8 };
+ if (equalColors(&buf[(j * windowSize + i) * 3], exp)
+ != true) {
+ REPORT_FAILURE("glTexImage failed");
+ printf(" got (%d, %d) = [%f, %f, %f], ", i, j,
+ buf[(j * windowSize + i) * 3],
+ buf[(j * windowSize + i) * 3 + 1],
+ buf[(j * windowSize + i) * 3 + 2]);
+ printf("should be [%f, %f, %f]\n",
+ exp[0], exp[1], exp[2]);
+
+ return false;
+ }
+ }
+ else if (i < TEXSIZE && j < TEXSIZE) {
+ if (equalColors(&buf[(j * windowSize + i) * 3], green)
+ != true) {
+ REPORT_FAILURE("glTexImage failed");
+ printf(" got (%d, %d) = [%f, %f, %f], ", i, j,
+ buf[(j * windowSize + i) * 3],
+ buf[(j * windowSize + i) * 3 + 1],
+ buf[(j * windowSize + i) * 3 + 2]);
+ printf("should be [%f, %f, %f]\n",
+ green[0], green[1], green[2]);
+
+ return false;
+ }
+ }
+ else {
+ if (equalColors(&buf[(j * windowSize + i) * 3], black)
+ != true) {
+ REPORT_FAILURE("glTexImage failed");
+ printf("(%d, %d) = [%f, %f, %f], ", i, j,
+ buf[(j * windowSize + i) * 3],
+ buf[(j * windowSize + i) * 3 + 1],
+ buf[(j * windowSize + i) * 3 + 2]);
+ printf("should be [0.0, 0.0, 0.0]\n");
+
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool PBOTest::testTexSubImage(void)
+{
+ GLuint pbs[1];
+ GLfloat t[TEXSIZE * TEXSIZE * 3];
+ int i, j;
+ int useUnpackBuffer = 0;
+ GLfloat green[3] = { 0.0, 1.0, 0.0 };
+ GLfloat black[3] = { 0.0, 0.0, 0.0 };
+
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);
+
+ for (useUnpackBuffer = 0; useUnpackBuffer < usePBO + 1; useUnpackBuffer++) {
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if (useUnpackBuffer) {
+ glGenBuffersARB(1, pbs);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pbs[0]);
+ glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, TEXSIZE * TEXSIZE * 3 * sizeof(GLfloat),
+ NULL, GL_STREAM_DRAW);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ }
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXSIZE, TEXSIZE, 0, GL_RGB,
+ GL_FLOAT, NULL);
+
+ GLfloat *pboMem = NULL;
+ if (useUnpackBuffer) {
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pbs[0]);
+ pboMem = (GLfloat *) glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT,
+ GL_WRITE_ONLY);
+ }
+ else {
+ pboMem = t;
+ }
+
+ for (i = 0; i < TEXSIZE * TEXSIZE; i++) {
+ pboMem[3 * i] = 0.0;
+ pboMem[3 * i + 1] = 1.0;
+ pboMem[3 * i + 2] = 0.0;
+ }
+
+ if (useUnpackBuffer) {
+ glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEXSIZE, TEXSIZE, GL_RGB,
+ GL_FLOAT, NULL);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ }
+ else
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEXSIZE, TEXSIZE, GL_RGB,
+ GL_FLOAT, pboMem);
+
+ glEnable(GL_TEXTURE_2D);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0);
+ glVertex2f(0, 0);
+ glTexCoord2f(1, 0);
+ glVertex2f(10, 0);
+ glTexCoord2f(1, 1);
+ glVertex2f(10, 10);
+ glTexCoord2f(0, 1);
+ glVertex2f(0, 10);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+
+ GLfloat buf[windowSize * windowSize * 3];
+
+ glReadPixels(0, 0, windowSize, windowSize, GL_RGB, GL_FLOAT, buf);
+ for (j = 0; j < windowSize; j++) {
+ for (i = 0; i < windowSize; i++) {
+ if (i < 10 && j < 10) {
+ if (equalColors(&buf[(j * windowSize + i) * 3], green) != true) {
+ REPORT_FAILURE("glTexSubImage failed");
+ printf(" got (%d, %d) = [%f, %f, %f], ", i, j,
+ buf[(j * windowSize + i) * 3],
+ buf[(j * windowSize + i) * 3 + 1],
+ buf[(j * windowSize + i) * 3 + 2]);
+ printf("should be [%f, %f, %f]\n",
+ green[0], green[1], green[2]);
+
+ return false;
+ }
+ }
+ else {
+ if (equalColors(&buf[(j * windowSize + i) * 3], black) != true) {
+ REPORT_FAILURE("glTexSubImage failed");
+ printf("(%d, %d) = [%f, %f, %f], ", i, j,
+ buf[(j * windowSize + i) * 3],
+ buf[(j * windowSize + i) * 3 + 1],
+ buf[(j * windowSize + i) * 3 + 2]);
+ printf("should be [0.0, 0.0, 0.0]\n");
+
+ return false;
+ }
+
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool PBOTest::testPolygonStip(void)
+{
+ int useUnpackBuffer = 0;
+ int usePackBuffer = 0;
+ GLuint unpack_pb[1];
+ GLuint pack_pb[1];
+ GLubyte t1[32 * 32 / 8];
+ GLubyte t2[32 * 32 / 8];
+ GLubyte *pboMem = NULL;
+ int i, j;
+ GLfloat white[3] = { 1.0, 1.0, 1.0 };
+ GLfloat black[3] = { 0.0, 0.0, 0.0 };
+
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);
+
+ for (useUnpackBuffer = 0; useUnpackBuffer < usePBO + 1; useUnpackBuffer++) {
+ for (usePackBuffer = 0; usePackBuffer < usePBO + 1; usePackBuffer++) {
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if (useUnpackBuffer) {
+ glGenBuffersARB(1, unpack_pb);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, unpack_pb[0]);
+ glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, 32 * 32 / 8, NULL,
+ GL_STREAM_DRAW);
+ pboMem = (GLubyte *) glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT,
+ GL_WRITE_ONLY);
+ }
+ else {
+ pboMem = t1;
+ }
+
+
+ // Fill in the stipple pattern
+ for (i = 0; i < 32 * 32 / 8; i++) {
+ pboMem[i] = 0xAA;
+ }
+
+ if (useUnpackBuffer) {
+ glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
+ glPolygonStipple(NULL);
+ }
+ else {
+ glPolygonStipple(pboMem);
+ }
+
+ // Read back the stipple pattern
+ if (usePackBuffer) {
+ glGenBuffersARB(1, pack_pb);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, pack_pb[0]);
+ glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT, 32 * 32 / 8, NULL,
+ GL_STREAM_DRAW);
+ glGetPolygonStipple(NULL);
+ pboMem = (GLubyte *) glMapBufferARB(GL_PIXEL_PACK_BUFFER_EXT,
+ GL_READ_ONLY);
+ }
+ else {
+ glGetPolygonStipple(t2);
+ pboMem = t2;
+ }
+
+ for (i = 0; i < 32 * 32 / 8; i++) {
+ if (pboMem[i] != 0xAA) {
+ REPORT_FAILURE("glGetPolygonStipple failed");
+ return false;
+ }
+ }
+
+
+ if (useUnpackBuffer) {
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ glDeleteBuffersARB(1, unpack_pb);
+ }
+ if (usePackBuffer) {
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);
+ glDeleteBuffersARB(1, pack_pb);
+ }
+
+ glEnable(GL_POLYGON_STIPPLE);
+ glBegin(GL_POLYGON);
+ glVertex2f(0, 0);
+ glVertex2f(10, 0);
+ glVertex2f(10, 10);
+ glVertex2f(0, 10);
+ glEnd();
+
+ glDisable(GL_POLYGON_STIPPLE);
+
+ // Check the result
+ GLfloat buf[windowSize * windowSize * 3];
+
+ glReadPixels(0, 0, windowSize, windowSize, GL_RGB, GL_FLOAT, buf);
+
+ for (j = 0; j < windowSize; j++) {
+ for (i = 0; i < windowSize; i++) {
+ const GLfloat *exp;
+ if (i & 1)
+ exp = black;
+ else
+ exp = white;
+ if (i < 10 && j < 10) {
+ if (equalColors(&buf[(j * windowSize + i) * 3], exp) !=
+ true) {
+ REPORT_FAILURE("glGetPolygonStipple failed");
+ printf("(%d, %d) = [%f, %f, %f], ", i, j,
+ buf[(j * windowSize + i) * 3],
+ buf[(j * windowSize + i) * 3 + 1],
+ buf[(j * windowSize + i) * 3 + 2]);
+ printf("should be [1.0, 1.0, 1.0]\n");
+ return false;
+ }
+ }
+ else {
+ if (equalColors(&buf[(j * windowSize + i) * 3], black) !=
+ true) {
+ REPORT_FAILURE("glGetPolygonStipple failed");
+ printf("(%d, %d) = [%f, %f, %f], ", i, j,
+ buf[(j * windowSize + i) * 3],
+ buf[(j * windowSize + i) * 3 + 1],
+ buf[(j * windowSize + i) * 3 + 2]);
+ printf("should be [0.0, 0.0, 0.0]\n");
+ return false;
+ }
+
+ }
+ }
+ }
+
+ }
+ }
+
+ return true;
+}
+
+
+bool PBOTest::testErrorHandling(void)
+{
+ GLuint fbs[1];
+
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);
+
+ if (usePBO) {
+ //handle exceed memory size
+ glGenBuffersARB(1, fbs);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, fbs[0]);
+ glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, 32 * 32 * 4, NULL,
+ GL_STREAM_DRAW);
+ glDrawPixels(32, 32 + 1, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ if (glGetError() != GL_INVALID_OPERATION)
+ return false;
+
+ glDeleteBuffersARB(1, fbs);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ glGenBuffersARB(1, fbs);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER, fbs[0]);
+ glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT, 32 * 32 * 4, NULL,
+ GL_STREAM_DRAW);
+ glReadPixels(0, 0, 32, 32 + 1, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ if (glGetError() != GL_INVALID_OPERATION)
+ return false;
+
+ glDeleteBuffersARB(1, fbs);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER, 0);
+ }
+ return true;
+}
+
+bool PBOTest::testFunctionality(MultiTestResult & r)
+{
+ static SubTestFunc
+ funcs[] = {
+ &GLEAN::PBOTest::testSanity,
+ &GLEAN::PBOTest::testBitmap,
+ &GLEAN::PBOTest::testDrawPixels,
+ &GLEAN::PBOTest::testPixelMap,
+ &GLEAN::PBOTest::testTexImage,
+ &GLEAN::PBOTest::testTexSubImage,
+ &GLEAN::PBOTest::testPolygonStip,
+ &GLEAN::PBOTest::testErrorHandling,
+ NULL
+ };
+
+ for (int i = 0; funcs[i]; i++)
+ if ((this->*funcs[i]) ())
+ r.numPassed++;
+ else
+ r.numFailed++;
+ return true;
+}
+
+enum {
+ BLACK,
+ RED,
+ GREEN,
+ BLUE,
+WHITE };
+
+GLfloat colors1[][4] = {
+ {0.0, 0.0, 0.0, 0.0},
+ {1.0, 0.0, 0.0, 1.0},
+ {0.0, 1.0, 0.0, 1.0},
+ {0.0, 0.0, 1.0, 1.0},
+ {1.0, 1.0, 1.0, 1.0}
+};
+
+#define TEXSIZE1 64
+bool PBOTest::testPerformance(MultiTestResult & r)
+{
+ GLuint pbs[1];
+ GLuint textures[1];
+ GLubyte data[TEXSIZE1 * TEXSIZE1 * 4];
+ int mode;
+ int i, j;
+ Timer t;
+ double t0, t1, perf[2];
+ GLubyte *pboMem = NULL;
+
+ (void) r;
+
+ for (mode = 0; mode < usePBO + 1; mode++) {
+ t0 = t.getClock();
+
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ if (mode) {
+ glGenBuffersARB(1, pbs);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, pbs[0]);
+ glBufferDataARB(GL_PIXEL_UNPACK_BUFFER,
+ TEXSIZE1 * TEXSIZE1 * 4 * sizeof(GLubyte), NULL,
+ GL_STREAM_DRAW);
+ }
+ glGenTextures(1, textures);
+ glBindTexture(GL_TEXTURE_2D, textures[0]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA, TEXSIZE1,
+ TEXSIZE1, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ for (i = 0; i < 1024; i++) {
+ if (mode) {
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, pbs[0]);
+ pboMem =
+ (GLubyte *) glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT,
+ GL_WRITE_ONLY);
+ }
+ else {
+ pboMem = data;
+ }
+
+ for (j = 0; j < TEXSIZE1 * TEXSIZE1; j++) {
+ pboMem[4 * j] = 255;
+ pboMem[4 * j + 1] = 255;
+ pboMem[4 * j + 2] = 0;
+ pboMem[4 * j + 3] = 0;
+ }
+
+ if (mode) {
+ glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEXSIZE1,
+ TEXSIZE1, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, 0);
+ }
+ else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEXSIZE1,
+ TEXSIZE1, GL_BGRA, GL_UNSIGNED_BYTE, data);
+ }
+
+
+ // Actually apply the texture
+ glEnable(GL_TEXTURE_2D);
+ glColor4fv(colors1[WHITE]);
+
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0.0, 0.0);
+ glVertex2f(0, 0);
+ glTexCoord2f(1.0, 0.0);
+ glVertex2f(1, 0);
+ glTexCoord2f(1.0, 1.0);
+ glVertex2f(1, 1);
+ glTexCoord2f(0.0, 1.0);
+ glVertex2f(0, 1);
+ glEnd();
+ glFlush();
+ glDisable(GL_TEXTURE_2D);
+ }
+ t1 = t.getClock();
+ glDeleteTextures(1, textures);
+ if (mode)
+ glDeleteBuffersARB(1, pbs);
+
+ perf[mode] = (double) TEXSIZE1 * TEXSIZE1 * 3 * sizeof(GLfloat) / 1024 / (t1 - t0);
+
+ }
+
+ if (perf[1] < perf[0] && usePBO) {
+ env->log << name << ": NOTE "
+ << "perf[0] = " << perf[0] <<
+ " MB/s, which is in normal mode" << endl;
+ env->log << name << ": NOTE " << "perf[1] = " <<
+ perf[1] << " MB/s, which is using PBO" << endl;
+ }
+
+ return true;
+}
+
+
+
+// Run all the subtests, incrementing numPassed, numFailed
+void
+PBOTest::runSubTests(MultiTestResult & r)
+{
+ static TestFunc funcs[] = {
+ &GLEAN::PBOTest::testFunctionality,
+ &GLEAN::PBOTest::testPerformance,
+ NULL
+ };
+
+ for (int i = 0; funcs[i]; i++)
+ if ((this->*funcs[i]) (r))
+ r.numPassed++;
+ else
+ r.numFailed++;
+}
+
+
+void
+PBOTest::runOne(MultiTestResult & r, Window & w)
+{
+ (void) w;
+
+ if (!setup()) {
+ r.pass = false;
+ return;
+ }
+
+ runSubTests(r);
+
+ r.pass = (r.numFailed == 0);
+}
+
+
+// The test object itself:
+PBOTest pboTest("pbo", "window, rgb, z", "", // no extension filter
+ "pbo test: Test OpenGL Extension GL_ARB_pixel_buffer_object\n");
+
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tpbo.h b/tests/glean/tpbo.h
new file mode 100644
index 000000000..46321bf6a
--- /dev/null
+++ b/tests/glean/tpbo.h
@@ -0,0 +1,86 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyrigth (C) 2007 Intel Corporation
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+//
+// Authors:
+// Shuang He <shuang.he@intel.com>
+//
+// tfbo.h: Test OpenGL Extension GL_ARB_pixel_buffer_objec
+
+#ifndef __pfbo_h__
+#define __pfbo_h__
+
+#include "tmultitest.h"
+
+namespace GLEAN {
+
+#define windowSize 100
+
+
+class PBOTest: public MultiTest
+{
+public:
+ PBOTest(const char* testName, const char* filter,
+ const char *extensions, const char* description):
+ MultiTest(testName, filter, extensions, description)
+ {
+ }
+
+ virtual void runOne(MultiTestResult &r, Window &w);
+
+private:
+ typedef bool (PBOTest::*TestFunc)(MultiTestResult &r);
+ typedef bool (PBOTest::*SubTestFunc)(void);
+
+ GLfloat tolerance[5];
+
+ bool testFunctionality(MultiTestResult &r);
+ bool testPerformance(MultiTestResult &r);
+ bool testSanity(void);
+ bool testErrorHandling(void);
+ bool testDrawPixels(void);
+ bool testPixelMap(void);
+ bool testBitmap(void);
+ bool testTexImage(void);
+ bool testTexSubImage(void);
+ bool testPolygonStip(void);
+
+ void runSubTests(MultiTestResult &r);
+
+ bool setup(void);
+ bool checkResult(const GLfloat exp[4], const int depth, const int stencil) const;
+ bool equalColors(const GLfloat a[4], const GLfloat b[4]) const;
+ bool equalColors1(const GLubyte a[4], const GLubyte b[4]) const;
+
+ void reportFailure(const char *msg, int line) const;
+ void reportFailure(const char *msg, GLenum target, int line) const;
+};
+
+} // namespace GLEAN
+
+#endif // __tpbo_h__
diff --git a/tests/glean/tpointatten.cpp b/tests/glean/tpointatten.cpp
index 879197806..086f8974f 100644
--- a/tests/glean/tpointatten.cpp
+++ b/tests/glean/tpointatten.cpp
@@ -63,7 +63,7 @@ PointAttenuationTest::setup(void)
glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, smoothLimits);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
- glOrtho(-1.0, 1.0, -1.0, 1.0, -10.0, 10.0);
+ glOrtho(-10.0, 10.0, -10.0, 10.0, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
@@ -120,20 +120,22 @@ PointAttenuationTest::expectedSize(GLfloat initSize,
size = CLAMP(size, smoothLimits[0], smoothLimits[1]);
else
size = CLAMP(size, aliasedLimits[0], aliasedLimits[1]);
-
return size;
}
-// measure size of rendered point
+// measure size of rendered point at yPos (in model coords)
GLfloat
-PointAttenuationTest::measureSize() const
+PointAttenuationTest::measureSize(GLfloat yPos) const
{
+ assert(yPos >= -10.0);
+ assert(yPos <= 10.0);
+ float yNdc = (yPos + 10.0) / 20.0; // See glOrtho above
int x = 0;
- int y = windowSize / 2;
- int w = windowSize;
+ int y = (int) (yNdc * windowHeight);
+ int w = windowWidth;
int h = 1;
- GLfloat image[windowSize * 3];
+ GLfloat image[windowWidth * 3];
// Read row of pixels and add up colors, which should be white
// or shades of gray if smoothing is enabled.
glReadPixels(x, y, w, h, GL_RGB, GL_FLOAT, image);
@@ -182,16 +184,22 @@ PointAttenuationTest::testPointRendering(GLboolean smooth)
PointParameterfARB(GL_POINT_SIZE_MAX_ARB, max);
for (float size = 1.0; size < MAX_SIZE; size += 4) {
glPointSize(size);
- for (float z = -8.0; z <= 8.0; z += 1.0) {
- glClear(GL_COLOR_BUFFER_BIT);
- glBegin(GL_POINTS);
- glVertex3f(0, 0, z);
- glEnd();
+
+ // draw column of points
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBegin(GL_POINTS);
+ for (float z = -6.0; z <= 6.0; z += 1.0) {
+ glVertex3f(0, z, z);
+ }
+ glEnd();
+
+ // test the column of points
+ for (float z = -6.0; z <= 6.0; z += 1.0) {
count++;
float expected
= expectedSize(size, atten, min, max,
z, smooth);
- float actual = measureSize();
+ float actual = measureSize(z);
if (fabs(expected - actual) > epsilon) {
reportFailure(size, atten, min, max,
z, smooth,
@@ -243,8 +251,8 @@ PointAttenuationTest::PointAttenuationTest(const char *testName,
const char *description)
: BasicTest(testName, filter, extensions, description)
{
- fWidth = windowSize;
- fHeight = windowSize;
+ fWidth = windowWidth;
+ fHeight = windowHeight;
}
diff --git a/tests/glean/tpointatten.h b/tests/glean/tpointatten.h
index 4ee032d53..459220261 100644
--- a/tests/glean/tpointatten.h
+++ b/tests/glean/tpointatten.h
@@ -36,8 +36,8 @@
namespace GLEAN {
-#define drawingSize 101 // yes, odd
-#define windowSize (drawingSize + 2)
+#define windowWidth 100
+#define windowHeight 503 // yes, odd
class PointAttenuationTest: public BasicTest
@@ -69,7 +69,7 @@ private:
const GLfloat attenuation[3],
GLfloat min, GLfloat max,
GLfloat eyeZ, GLboolean smooth) const;
- GLfloat measureSize() const;
+ GLfloat measureSize(GLfloat yPos) const;
};
} // namespace GLEAN
diff --git a/tests/glean/tpointsprite.cpp b/tests/glean/tpointsprite.cpp
new file mode 100644
index 000000000..47cff89ae
--- /dev/null
+++ b/tests/glean/tpointsprite.cpp
@@ -0,0 +1,428 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+
+/*
+ * Copyright (C) 2007 Intel Corporation
+ * Copyright (C) 1999 Allen Akin All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* tpointsprite.cpp: Test the ARB_point_sprite extension
+ * Author: Nian Wu <nian.wu@intel.com>
+ *
+ * Test procedure:
+ * Create mipmap textures which size varies from 32x32 to 1x1, every texture
+ * has different two colors: the upper half is one color and the lower half
+ * is another color.
+ * Draw point and polygon which mode is GL_POINT, and check that the point
+ * is rendered correctly.
+ */
+
+#define GL_GLEXT_PROTOTYPES
+#include "tpointsprite.h"
+#include <cassert>
+#include <cmath>
+#include <stdio.h>
+
+namespace GLEAN {
+
+//background color
+static GLfloat bgColor[4] = {0.0, 0.0, 0.0, 0.0};
+
+//mipmap texture's color, every texture partite to upper and lower part that
+//has different colors
+//for 1x1 texture, only lower part is used
+static GLfloat texColor[6][2][4] = {
+ {{1.0, 0.0, 0.0, 1.0}, {0.0, 1.0, 0.0, 1.0}}, // 32x32
+ {{0.0, 0.0, 1.0, 1.0}, {1.0, 1.0, 0.0, 1.0}}, // 16x16
+ {{1.0, 0.0, 1.0, 1.0}, {0.0, 1.0, 1.0, 1.0}}, // 8x8
+ {{1.0, 1.0, 1.0, 1.0}, {1.0, 0.0, 0.0, 1.0}}, // 4x4
+ {{0.0, 1.0, 0.0, 1.0}, {0.0, 0.0, 1.0, 1.0}}, // 2x2
+ {{1.0, 1.0, 0.0, 1.0}, {1.0, 1.0, 1.0, 1.0}}, // 1x1
+};
+
+//generate mipmap
+void
+PointSpriteTest::GenMipmap()
+{
+ int level, i, j;
+ GLint texWidth;
+ GLfloat *texPtr;
+ GLfloat *upperColor, *lowColor;
+
+ for (level = 0; level < 6; level++)
+ {
+ texWidth = 1 << (6 - level - 1);
+ texImages[level] = (GLfloat *)malloc(texWidth * texWidth * 4 * sizeof(GLfloat));
+ texPtr = texImages[level];
+ upperColor = texColor[level][0];
+ lowColor = texColor[level][1];
+
+ for (i = 0; i < texWidth; i++)
+ {
+ for (j = 0; j < texWidth; j++)
+ {
+ if (i < texWidth / 2) //lower part
+ {
+ *texPtr++ = lowColor[0];
+ *texPtr++ = lowColor[1];
+ *texPtr++ = lowColor[2];
+ *texPtr++ = lowColor[3];
+ } else { //upper part
+ *texPtr++ = upperColor[0];
+ *texPtr++ = upperColor[1];
+ *texPtr++ = upperColor[2];
+ *texPtr++ = upperColor[3];
+ }
+ }
+ }
+ }
+}
+
+//enable texture and setup mipmap
+void
+PointSpriteTest::SetupMipmap(GLuint *texID)
+{
+ glEnable(GL_TEXTURE_2D);
+
+ glGenTextures(1, texID);
+ glBindTexture(GL_TEXTURE_2D, *texID);
+
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0,
+ GL_RGBA, GL_FLOAT, texImages[0]);
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 16, 16, 0,
+ GL_RGBA, GL_FLOAT, texImages[1]);
+ glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 8, 8, 0,
+ GL_RGBA, GL_FLOAT, texImages[2]);
+ glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA, 4, 4, 0,
+ GL_RGBA, GL_FLOAT, texImages[3]);
+ glTexImage2D(GL_TEXTURE_2D, 4, GL_RGBA, 2, 2, 0,
+ GL_RGBA, GL_FLOAT, texImages[4]);
+ glTexImage2D(GL_TEXTURE_2D, 5, GL_RGBA, 1, 1, 0,
+ GL_RGBA, GL_FLOAT, texImages[5]);
+
+ glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
+}
+
+void
+PointSpriteTest::CheckDefaultState(MultiTestResult &r)
+{
+ GLboolean enable;
+ GLint coordReplace;
+ GLint coordOrigin;
+
+ // check point sprite status, default is GL_FALSE
+ enable = glIsEnabled(GL_POINT_SPRITE_ARB);
+ if (enable != GL_FALSE)
+ {
+ env->log << name << "subcase FAIL: "
+ << "PointSprite should be disabled defaultlly\n";
+ r.numFailed++;
+ } else {
+ r.numPassed++;
+ }
+
+ // check coordinate replacement, default is GL_FALSE
+ glGetTexEnviv(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, &coordReplace);
+
+ if (coordReplace != GL_FALSE)
+ {
+ env->log << name << "subcase FAIL: "
+ << "default value of COORD_REPLACE should be GL_FALSE\n";
+ r.numFailed++;
+ } else {
+ r.numPassed++;
+ }
+
+ // check coordinate origin, default is UPPER_LEFT
+ glEnable(GL_POINT_SPRITE);
+ glGetIntegerv(GL_POINT_SPRITE_COORD_ORIGIN, &coordOrigin);
+ if (coordOrigin != GL_UPPER_LEFT)
+ {
+ env->log << name << "subcase FAIL: "
+ << "defult value of COORD_ORIGIN should be GL_UPPER_LEFT\n";
+ r.numFailed++;
+ } else {
+ r.numPassed++;
+ }
+
+ glDisable(GL_POINT_SPRITE);
+}
+
+GLboolean
+PointSpriteTest::OutOfPoint(int x, int y, int pSize, int x0, int y0)
+{
+ if ((x < x0) ||
+ (y < y0) ||
+ (x >= x0 + pSize) ||
+ (y >= y0 + pSize))
+ return GL_TRUE;
+ else
+ return GL_FALSE;
+}
+
+GLfloat *
+PointSpriteTest::GetTexColor(int pSize, int dir)
+{
+ int level;
+
+ // Note: we use GL_NEAREST_MIPMAP_NEAREST for GL_TEXTURE_MIN_FILTER
+ if (pSize <= 1) level = 5;
+ else if (pSize < 3) level = 4;
+ else if (pSize < 6) level = 3;
+ else if (pSize < 12) level = 2;
+ else if (pSize < 24) level = 1;
+ else level = 0;
+
+ return texColor[level][dir];
+}
+
+void
+PointSpriteTest::CalculateTolerance()
+{
+ GLint rBits, gBits, bBits;
+ GLint rTexBits, gTexBits, bTexBits;
+
+ // Get fb resolution
+ glGetIntegerv(GL_RED_BITS, &rBits);
+ glGetIntegerv(GL_GREEN_BITS, &gBits);
+ glGetIntegerv(GL_BLUE_BITS, &bBits);
+
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
+ GL_TEXTURE_RED_SIZE, &rTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
+ GL_TEXTURE_GREEN_SIZE, &gTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
+ GL_TEXTURE_BLUE_SIZE, &bTexBits);
+
+ // Find smaller of frame buffer and texture bits
+ rBits = (rBits < rTexBits) ? rBits : rTexBits;
+ gBits = (gBits < gTexBits) ? gBits : gTexBits;
+ bBits = (bBits < bTexBits) ? bBits : bTexBits;
+
+ mTolerance[0] = 3.0 / (1 << rBits);
+ mTolerance[1] = 3.0 / (1 << gBits);
+ mTolerance[2] = 3.0 / (1 << bBits);
+}
+
+//Test if two colors are colse enough to be considered the same.
+GLboolean
+PointSpriteTest::CompareColor(GLfloat *actual, GLfloat *expected)
+{
+ return (fabs(actual[0] - expected[0]) <= mTolerance[0] &&
+ fabs(actual[1] - expected[1]) <= mTolerance[1] &&
+ fabs(actual[2] - expected[2]) <= mTolerance[2] );
+}
+
+
+static void
+FindNonBlack(const GLfloat *buf, GLint w, GLint h, GLint *x0, GLint *y0)
+{
+ GLint i, j;
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++) {
+ int k = (i * w + j) * 3;
+ if (buf[k+0] != bgColor[0] ||
+ buf[k+1] != bgColor[1] ||
+ buf[k+2] != bgColor[2]) {
+ *x0 = j;
+ *y0 = i;
+ return;
+ }
+ }
+ }
+ abort();
+}
+
+
+/**
+ * compare pixels located at (0,0) to (WINSIZE/2, WINSIZE/2).
+ * @param buf: pixels' RGB value
+ * @param pSize: point size
+ * @param coordOrigin: coordinate origin--UPPER_LEFT or LOWER_LEFT
+ */
+GLboolean
+PointSpriteTest::ComparePixels(GLfloat *buf, int pSize, int coordOrigin)
+{
+ GLfloat *lowerColor, *upperColor, *expectedColor;
+ GLint i, j;
+ GLint x0, y0;
+
+ lowerColor = GetTexColor(pSize, coordOrigin ? 0 : 1);
+ upperColor = GetTexColor(pSize, coordOrigin ? 1 : 0);
+
+ // Find first (lower-left) pixel that's not black.
+ // The pixels hit by sprite rasterization may vary from one GL to
+ // another so try to compensate for that.
+ FindNonBlack(buf, WINSIZE/2, WINSIZE/2, &x0, &y0);
+
+ for (i = 0; i < WINSIZE / 2; i++)
+ {
+ for (j = 0; j < WINSIZE / 2; j++)
+ {
+ if (OutOfPoint(i, j, pSize, x0, y0))
+ { //pixel (i, j) is out of point
+ //its color should bebackground
+ if (!CompareColor(buf, bgColor))
+ {
+ env->log << "Incorrect pixel at (" << i << ", " << j << "):\n"
+ <<"\tit should be backgound color: ("
+ << bgColor[0] << ", " << bgColor[1] << ", " << bgColor[2]
+ << "), actual read: (" << buf[0] << ", " << buf[1] << ", " << buf[2] << ")\n" ;
+ return GL_FALSE;
+ }
+ } else { //inside point
+ if (i - x0 < pSize/2)
+ expectedColor = lowerColor;
+ else
+ expectedColor = upperColor;
+
+ if (!CompareColor(buf, expectedColor))
+ {
+ env->log << "Incorrect pixel at (" << i << ", " << j << "):\n"
+ <<"\tit should be rendered with color: ("
+ << expectedColor[0] << ", " << expectedColor[1] << ", " << expectedColor[2]
+ << "), actual read: (" << buf[0] << ", " << buf[1] << ", " << buf[2] << ")\n" ;
+ return GL_FALSE;
+ }
+ }
+ buf += 3;
+ }
+ }
+
+ return GL_TRUE;
+}
+
+// Test default state.
+// Test point and polygon which mode is GL_POINT, and texture's coordinate
+// origin is UPPER_LEFT or LOWER_LEFT.
+// Result will indicate number of passes and failures.
+void
+PointSpriteTest::runOne(MultiTestResult &r, Window &w)
+{
+ GLfloat maxPointSize, pointSize;
+ GLint expectedSize;
+ GLint primType, coordOrigin;
+ GLfloat *buf;
+ GLuint texID;
+ int i;
+
+ (void) w;
+
+ CheckDefaultState(r);
+
+ glDrawBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
+
+ glClearColor(bgColor[0], bgColor[1], bgColor[2], bgColor[3]);
+
+ glViewport(0, 0, WINSIZE, WINSIZE);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, WINSIZE, 0, WINSIZE, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ GenMipmap();
+ SetupMipmap(&texID);
+ CalculateTolerance();
+
+ buf = (GLfloat *)malloc(3 * WINSIZE * WINSIZE / 4 * sizeof(GLfloat));
+
+ // enable point_sprite_ARB
+ glEnable(GL_POINT_SPRITE_ARB);
+
+ glGetFloatv(GL_POINT_SIZE_MAX_ARB, &maxPointSize);
+ if (maxPointSize > WINSIZE / 2)
+ maxPointSize = WINSIZE / 2;
+
+ //primitive may be point or polygon which mode is GL_POINT
+ for (primType = 0; primType < 2; primType ++)
+ {
+ for (coordOrigin = 0; coordOrigin < 2; coordOrigin++)
+ {
+
+ if (coordOrigin)
+ glPointParameterf(GL_POINT_SPRITE_COORD_ORIGIN, GL_UPPER_LEFT);
+ else
+ glPointParameterf(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
+
+ pointSize = 1.85;
+ for (; pointSize <= maxPointSize; pointSize += 2.0)
+ {
+ expectedSize = (int)(pointSize + 0.2);
+
+ glPointSize(pointSize);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if (primType == 0)
+ {
+ glBegin(GL_POINTS);
+ glVertex2i(WINSIZE/4, WINSIZE/4);
+ glEnd();
+ } else {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
+ glBegin(GL_POLYGON);
+ glVertex2i(WINSIZE/4, WINSIZE/4);
+ glVertex2i(WINSIZE, WINSIZE / 4);
+ glVertex2i(WINSIZE, WINSIZE);
+ glVertex2i(WINSIZE / 4, WINSIZE);
+ glEnd();
+ }
+
+ glReadPixels(0, 0, WINSIZE/2, WINSIZE/2, GL_RGB, GL_FLOAT, buf);
+
+ if (!ComparePixels(buf, expectedSize, coordOrigin))
+ {
+ env->log << "\tPrimitive type: " << (primType ? "GL_POLYGON" : "GL_POINTS") << "\n";
+ env->log << "\tCoord Origin at: " << (coordOrigin ? "GL_LOWER_LEFT" : "GL_UPPER_LEFT") << "\n";
+ env->log << "\tPointSize: " << pointSize << "\n";
+ r.numFailed++;
+ r.numPassed--;
+ break;
+ }
+ }
+ r.numPassed++;
+ }
+ }
+
+ glDeleteTextures(1, &texID);
+ glDisable(GL_POINT_SPRITE_ARB);
+ free(buf);
+ for (i = 0; i < 6; i++)
+ free(texImages[i]);
+
+ r.pass = (r.numFailed == 0);
+}
+
+// The test object itself:
+PointSpriteTest pointSpriteTest("pointSprite", "window, rgb",
+ "GL_ARB_point_sprite",
+ "Test basic point sprite functionality.\n");
+
+} // namespace GLEAN
diff --git a/tests/glean/tpointsprite.h b/tests/glean/tpointsprite.h
new file mode 100644
index 000000000..ed04c8f56
--- /dev/null
+++ b/tests/glean/tpointsprite.h
@@ -0,0 +1,70 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+
+/*
+ * Copyright (C) 2007 Intel Coporation All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+// tpointsprite.h: Test basic ARB_point_sprite support.
+// Author: Nian Wu <nian.wu@intel.com>
+
+
+#ifndef __tpointsprite_h__
+#define __tpointsprite_h__
+
+#include "tmultitest.h"
+
+namespace GLEAN {
+
+#define WINSIZE 80
+
+class PointSpriteTest: public MultiTest
+{
+ public:
+ PointSpriteTest(const char* testName, const char* filter,
+ const char *extensions, const char* description):
+ MultiTest(testName, filter, extensions, description){
+ }
+
+ virtual void runOne(MultiTestResult &r, Window &w);
+
+private:
+ GLfloat *texImages[6];
+ GLfloat mTolerance[3];
+
+ void GenMipmap();
+ void SetupMipmap(GLuint *texID);
+ void CheckDefaultState(MultiTestResult &r);
+ void CalculateTolerance();
+ GLboolean OutOfPoint(int x, int y, int pSize, int x0, int y0);
+ GLfloat *GetTexColor(int pSize, int dir);
+ GLboolean CompareColor(GLfloat *actual, GLfloat *expected);
+ GLboolean ComparePixels(GLfloat *buf, int pSize, int coordOrigin);
+}; // class PointSpriteTest
+
+} // namespace GLEAN
+
+#endif // __tpointsprite_h__
+
diff --git a/tests/glean/treadpix.cpp b/tests/glean/treadpix.cpp
index bc1b3d078..3c146d425 100644
--- a/tests/glean/treadpix.cpp
+++ b/tests/glean/treadpix.cpp
@@ -1,7 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
-//
+//
// Copyright (C) 2001 Allen Akin All Rights Reserved.
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -10,11 +10,11 @@
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the
// Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
@@ -23,7 +23,7 @@
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-//
+//
// END_COPYRIGHT
// treadpix.cpp: implementation of ReadPixels tests
@@ -269,7 +269,7 @@ ReadPixSanityTest::runOne(ReadPixSanityResult& r, GLEAN::Window& w) {
checkDepth(r, w);
if (r.config->s)
checkStencil(r, w);
-
+
r.pass = r.passRGBA & r.passDepth & r.passStencil & r.passIndex;
} // ReadPixSanityTest::runOne
@@ -500,7 +500,7 @@ namespace {
template<class T>
void
check(GLEAN::ExactRGBAResult::Flavor& r, GLEAN::DrawingSurfaceConfig& config,
- GLenum type, int roundingMode) {
+ GLenum type) {
unsigned size = EXACT_RGBA_WIN_SIZE - 2;
unsigned nPixels = size * size;
unsigned nComponents = 4 * nPixels;
@@ -563,18 +563,15 @@ check(GLEAN::ExactRGBAResult::Flavor& r, GLEAN::DrawingSurfaceConfig& config,
hostBits = 32;
break;
}
- T Mask[4];
-
- Mask[0] = static_cast<T>(-1) << (hostBits - min(hostBits, config.r));
- Mask[1] = static_cast<T>(-1) << (hostBits - min(hostBits, config.g));
- Mask[2] = static_cast<T>(-1) << (hostBits - min(hostBits, config.b));
- Mask[3] = static_cast<T>(-1) << (hostBits - min(hostBits, config.a));
-
+ T rMask = static_cast<T>(-1) << (hostBits - min(hostBits, config.r));
+ T gMask = static_cast<T>(-1) << (hostBits - min(hostBits, config.g));
+ T bMask = static_cast<T>(-1) << (hostBits - min(hostBits, config.b));
+ T aMask = static_cast<T>(-1) << (hostBits - min(hostBits, config.a));
// Patch up arithmetic for RGB drawing surfaces. All other nasty cases
// are eliminated by the drawing surface filter, which requires
// nonzero R, G, and B.
- if (config.a == 0)
- Mask[3] = 0;
+ if (aMask == static_cast<T>(-1))
+ aMask = 0;
// Compare masked actual and expected values, and record the
// worst-case error location and magnitude.
@@ -584,35 +581,18 @@ check(GLEAN::ExactRGBAResult::Flavor& r, GLEAN::DrawingSurfaceConfig& config,
for (y = 0; y < size; ++y)
for (x = 0; x < size; ++x) {
T e[4];
+ e[0] = p[0] & rMask;
+ e[1] = p[1] & gMask;
+ e[2] = p[2] & bMask;
+ e[3] = p[3] & aMask;
T a[4];
- if (roundingMode == 1) {
- e[0] = p[0];
- e[1] = p[1];
- e[2] = p[2];
- e[3] = p[3];
- a[0] = q[0];
- a[1] = q[1];
- a[2] = q[2];
- a[3] = q[3];
- if (config.a == 0) {
- e[3] = a[3] = 0;
- }
- } else {
- e[0] = p[0] & Mask[0];
- e[1] = p[1] & Mask[1];
- e[2] = p[2] & Mask[2];
- e[3] = p[3] & Mask[3];
- a[0] = q[0] & Mask[0];
- a[1] = q[1] & Mask[1];
- a[2] = q[2] & Mask[2];
- a[3] = q[3] & Mask[3];
- }
+ a[0] = q[0] & rMask;
+ a[1] = q[1] & gMask;
+ a[2] = q[2] & bMask;
+ a[3] = q[3] & aMask;
for (unsigned i = 0; i < 4; ++i) {
- GLuint err = max(e[i], a[i]) - min(e[i], a[i]);
- if (roundingMode == 1) {
- if (err < ~Mask[i] / 2)
- err = 0;
- }
+ GLuint err =
+ max(e[i], a[i]) - min(e[i], a[i]);
if (err > r.err) {
r.x = x;
r.y = y;
@@ -620,8 +600,6 @@ check(GLEAN::ExactRGBAResult::Flavor& r, GLEAN::DrawingSurfaceConfig& config,
for (unsigned j = 0; j < 4; ++j) {
r.expected[j] = e[j];
r.actual[j] = a[j];
- r.written[j] = p[j];
- r.read[j] = q[j];
}
}
}
@@ -673,18 +651,16 @@ ExactRGBATest::runOne(ExactRGBAResult& r, GLEAN::Window& w) {
// Don't bother running if the ReadPixels sanity test for this
// display surface configuration failed:
- if (!env->options.ignorePrereqs) {
- vector<ReadPixSanityResult*>::const_iterator rpsRes;
- for (rpsRes = readPixSanityTest.results.begin();
- rpsRes != readPixSanityTest.results.end();
- ++rpsRes)
- if ((*rpsRes)->config == r.config)
- break;
- if (rpsRes == readPixSanityTest.results.end() || !(*rpsRes)->pass) {
- r.skipped = true;
- r.pass = false;
- return;
- }
+ vector<ReadPixSanityResult*>::const_iterator rpsRes;
+ for (rpsRes = readPixSanityTest.results.begin();
+ rpsRes != readPixSanityTest.results.end();
+ ++rpsRes)
+ if ((*rpsRes)->config == r.config)
+ break;
+ if (rpsRes == readPixSanityTest.results.end() || !(*rpsRes)->pass) {
+ r.skipped = true;
+ r.pass = false;
+ return;
}
// Much of this state should already be set, if the defaults are
@@ -751,25 +727,11 @@ ExactRGBATest::runOne(ExactRGBAResult& r, GLEAN::Window& w) {
glPixelTransferf(GL_ALPHA_BIAS, 0.0);
glPixelTransferf(GL_DEPTH_BIAS, 0.0);
- // Hack: Make hardware driver tests feasible
- // The OpenGL spec apparently requires insane behaviour on the part
- // of the implementation: On the one hand, implementations should round
- // color values to the nearest representable color value, while on the
- // other hand it has to truncate. Silly...
- int roundingMode = 0;
- const char* s;
-
- s = getenv("GLEAN_EXACTRGBA_ROUNDING");
- if (s) {
- roundingMode = atoi(s);
- env->log << "Note: Rounding mode changed to " << roundingMode << "\n";
- }
-
- check<GLubyte>(r.ub, *(r.config), GL_UNSIGNED_BYTE, roundingMode);
+ check<GLubyte>(r.ub, *(r.config), GL_UNSIGNED_BYTE);
w.swap();
- check<GLushort>(r.us, *(r.config), GL_UNSIGNED_SHORT, roundingMode);
+ check<GLushort>(r.us, *(r.config), GL_UNSIGNED_SHORT);
w.swap();
- check<GLuint>(r.ui, *(r.config), GL_UNSIGNED_INT, roundingMode);
+ check<GLuint>(r.ui, *(r.config), GL_UNSIGNED_INT);
w.swap();
r.pass = r.ub.pass && r.us.pass && r.ui.pass;
r.skipped = false;
@@ -908,15 +870,7 @@ ExactRGBATest::logFlavor(const char* label, const ExactRGBAResult::Flavor& r) {
<< r.actual[0] << ", 0x"
<< r.actual[1] << ", 0x"
<< r.actual[2] << ", 0x"
- << r.actual[3] << ")\n\t\twrote (0x"
- << r.written[0] << ", 0x"
- << r.written[1] << ", 0x"
- << r.written[2] << ", 0x"
- << r.written[3] << ")\n\t\tread (0x"
- << r.read[0] << ", 0x"
- << r.read[1] << ", 0x"
- << r.read[2] << ", 0x"
- << r.read[3] << ")\n"
+ << r.actual[3] << ")\n"
<< dec
;
}
diff --git a/tests/glean/treadpix.h b/tests/glean/treadpix.h
index 07106883f..8dc8d9e01 100644
--- a/tests/glean/treadpix.h
+++ b/tests/glean/treadpix.h
@@ -1,7 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
-//
+//
// Copyright (C) 2001 Allen Akin All Rights Reserved.
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -10,11 +10,11 @@
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the
// Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
@@ -23,7 +23,7 @@
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-//
+//
// END_COPYRIGHT
@@ -77,7 +77,7 @@ public:
= expectedRGBA[3] = 0.0;
actualRGBA[0] = actualRGBA[1] = actualRGBA[2]
= actualRGBA[3] = 0.0;
-
+
passDepth = true;
xDepth = yDepth = 0;
errDepth = 0.0;
@@ -94,7 +94,7 @@ public:
expectedIndex = 0;
actualIndex = 0;
}
-
+
void putresults(ostream& s) const {
s
<< pass << '\n'
@@ -125,7 +125,7 @@ public:
<< actualIndex << '\n'
;
}
-
+
bool getresults(istream& s) {
s >> pass
@@ -184,8 +184,6 @@ public:
GLuint err;
GLuint expected[4];
GLuint actual[4];
- GLuint written[4];
- GLuint read[4];
bool operator== (const Flavor& f) const {
return pass == f.pass
@@ -200,14 +198,6 @@ public:
&& actual[1] == f.actual[1]
&& actual[2] == f.actual[2]
&& actual[3] == f.actual[3]
- && written[0] == f.written[0]
- && written[1] == f.written[1]
- && written[2] == f.written[2]
- && written[3] == f.written[3]
- && read[0] == f.read[0]
- && read[1] == f.read[1]
- && read[2] == f.read[2]
- && read[3] == f.read[3]
;
}
@@ -218,8 +208,6 @@ public:
expected[0] = expected[1] = expected[2]
= expected[3] = 0;
actual[0] = actual[1] = actual[2] = actual[3] = 0;
- written[0] = written[1] = written[2] = written[3] = 0;
- read[0] = read[1] = read[2] = read[3] = 0;
}
void put(ostream& s) const {
@@ -235,14 +223,6 @@ public:
<< actual[1] << ' '
<< actual[2] << ' '
<< actual[3] << '\n'
- << written[0] << ' '
- << written[1] << ' '
- << written[2] << ' '
- << written[3] << '\n'
- << read[0] << ' '
- << read[1] << ' '
- << read[2] << ' '
- << read[3] << '\n'
;
}
void get(istream& s) {
@@ -258,14 +238,6 @@ public:
>> actual[1]
>> actual[2]
>> actual[3]
- >> written[0]
- >> written[1]
- >> written[2]
- >> written[3]
- >> read[0]
- >> read[1]
- >> read[2]
- >> read[3]
;
}
};
@@ -281,7 +253,7 @@ public:
skipped = false;
pass = true;
}
-
+
void putresults(ostream& s) const {
s
<< skipped << '\n'
@@ -291,7 +263,7 @@ public:
us.put(s);
ui.put(s);
}
-
+
bool getresults(istream& s) {
s
>> skipped
diff --git a/tests/glean/treadpixperf.cpp b/tests/glean/treadpixperf.cpp
index 058e67a09..0cde676d3 100644
--- a/tests/glean/treadpixperf.cpp
+++ b/tests/glean/treadpixperf.cpp
@@ -467,9 +467,9 @@ ReadpixPerfTest::compareOne(ReadpixPerfResult &oldR,
<< descrip
<< "' changed by "
<< diff
- << " percent (old: "
+ << " percent (new: "
<< newres.rate
- << " new: "
+ << " old: "
<< oldres.rate
<< " MPixels/sec)\n";
}
diff --git a/tests/glean/ttexrect.cpp b/tests/glean/ttexrect.cpp
index 7adcb3a0c..ccc5ba3dc 100644
--- a/tests/glean/ttexrect.cpp
+++ b/tests/glean/ttexrect.cpp
@@ -142,10 +142,8 @@ TexRectTest::runOne(BasicResult& r, Window& w)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
- if (w.config->db) {
- glDrawBuffer(GL_BACK);
- glReadBuffer(GL_BACK);
- }
+ glDrawBuffer(GL_BACK);
+ glReadBuffer(GL_BACK);
r.pass = true;
diff --git a/tests/glean/tvertprog1.h b/tests/glean/tvertprog1.h
index df42073cc..b40f59f78 100644
--- a/tests/glean/tvertprog1.h
+++ b/tests/glean/tvertprog1.h
@@ -47,8 +47,8 @@ class VertexProgram
public:
const char *name;
const char *progString;
- const GLfloat expectedColor[4];
- const GLfloat expectedZ;
+ GLfloat expectedColor[4];
+ GLfloat expectedZ;
int flags;
};