summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2009-02-16 15:23:39 -0800
committerEric Anholt <eric@anholt.net>2009-03-07 03:30:55 -0800
commitaa7c71facfe968af8f82c5a07b02cad039a3134e (patch)
tree9d6b0f210d05ec689520e7db6f1634845f3d91c1 /tests
parenta2c35c6fe4b81bd9516ece02ca209dc0bbb2a9f0 (diff)
Update glean tests to CVS HEAD from 2009-03-07.
Diffstat (limited to 'tests')
-rw-r--r--tests/all.tests4
-rw-r--r--tests/glean/CMakeLists.txt4
-rw-r--r--tests/glean/dsconfig.cpp38
-rw-r--r--tests/glean/dsconfig.h5
-rw-r--r--tests/glean/dsfilt.cpp6
-rw-r--r--tests/glean/dsfilt.h4
-rw-r--r--tests/glean/environ.cpp1
-rw-r--r--tests/glean/glutils.cpp1
-rw-r--r--tests/glean/image.h5
-rw-r--r--tests/glean/image_misc.cpp26
-rw-r--r--tests/glean/main.cpp1
-rw-r--r--tests/glean/tapi2.cpp23
-rw-r--r--tests/glean/tbase.h34
-rw-r--r--tests/glean/tblend.cpp1
-rw-r--r--tests/glean/tdepthstencil.cpp5
-rw-r--r--tests/glean/tfbo.cpp46
-rw-r--r--tests/glean/tfbo.h1
-rw-r--r--tests/glean/tfpexceptions.cpp2
-rw-r--r--tests/glean/tfragprog1.cpp26
-rw-r--r--tests/glean/tglsl1.cpp457
-rw-r--r--tests/glean/tglsl1.h5
-rw-r--r--tests/glean/tlogicop.cpp3
-rw-r--r--tests/glean/toccluqry.cpp6
-rw-r--r--tests/glean/tpaths.cpp1
-rw-r--r--tests/glean/tpbo.cpp11
-rw-r--r--tests/glean/tpixelformats.cpp3
-rw-r--r--tests/glean/tpointsprite.cpp5
-rw-r--r--tests/glean/tshaderapi.cpp600
-rw-r--r--tests/glean/tshaderapi.h94
-rw-r--r--tests/glean/tstencil2.cpp785
-rw-r--r--tests/glean/tstencil2.h95
-rw-r--r--tests/glean/ttexcombine4.cpp424
-rw-r--r--tests/glean/ttexcombine4.h88
-rw-r--r--tests/glean/ttexenv.cpp4
-rw-r--r--tests/glean/ttexswizzle.cpp456
-rw-r--r--tests/glean/ttexswizzle.h88
-rw-r--r--tests/glean/ttexture_srgb.cpp6
-rw-r--r--tests/glean/ttexunits.cpp323
-rw-r--r--tests/glean/ttexunits.h70
-rw-r--r--tests/glean/tvertarraybgra.cpp248
-rw-r--r--tests/glean/tvertarraybgra.h74
-rw-r--r--tests/glean/tvertattrib.cpp3
-rw-r--r--tests/glean/tvertprog1.cpp3
43 files changed, 4004 insertions, 81 deletions
diff --git a/tests/all.tests b/tests/all.tests
index 8184e9c18..a83b4b51e 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -68,7 +68,11 @@ glean['texCube'] = GleanTest('texCube')
glean['texEnv'] = GleanTest('texEnv')
glean['texgen'] = GleanTest('texgen')
glean['texRect'] = GleanTest('texRect')
+glean['texcombine4'] = GleanTest('texcombine4')
+glean['texswizzle'] = GleanTest('texswizzle')
glean['texture_srgb'] = GleanTest('texture_srgb')
+glean['texunits'] = GleanTest('texunits')
+glean['vertarraybgra'] = GleanTest('vertarraybgra')
glean['vertattrib'] = GleanTest('vertattrib')
glean['vertProg1'] = GleanTest('vertProg1')
diff --git a/tests/glean/CMakeLists.txt b/tests/glean/CMakeLists.txt
index 67a1696b1..dd5650ead 100644
--- a/tests/glean/CMakeLists.txt
+++ b/tests/glean/CMakeLists.txt
@@ -46,11 +46,15 @@ add_executable (glean
tscissor.cpp
tteapot.cpp
ttexcombine.cpp
+ ttexcombine4.cpp
ttexcube.cpp
ttexenv.cpp
ttexgen.cpp
ttexrect.cpp
+ ttexswizzle.cpp
ttexture_srgb.cpp
+ ttexunits.cpp
+ tvertarraybgra.cpp
tvertattrib.cpp
tvertprog1.cpp
tvtxperf.cpp
diff --git a/tests/glean/dsconfig.cpp b/tests/glean/dsconfig.cpp
index 88f9a81b1..861c0c831 100644
--- a/tests/glean/dsconfig.cpp
+++ b/tests/glean/dsconfig.cpp
@@ -2,6 +2,8 @@
//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
//
+// multisample changes: Copyright (c) 2008 VMware, Inc. 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
@@ -31,9 +33,9 @@
#include "dsconfig.h"
#include <iostream>
#include <strstream>
-#include <cstring>
+#include <string.h>
#include <map>
-#include <climits>
+#include <limits.h>
#ifdef __WIN__
// disable the annoying warning : "forcing value to bool 'true' or 'false' (performance warning)"
@@ -100,6 +102,7 @@ typedef enum { // These variable tags are used as array indices,
VACCUMG,
VACCUMB,
VACCUMA,
+ VSAMPLES,
VCANWINDOW,
VCANPIXMAP,
VCANPBUFFER,
@@ -138,6 +141,7 @@ struct {CanonVar var; char* name;} varNames[] = {
{VACCUMG, "accumG"},
{VACCUMB, "accumB"},
{VACCUMA, "accumA"},
+ {VSAMPLES, "multisample"},
{VCANWINDOW, "window"},
{VCANPIXMAP, "pixmap"},
{VCANPBUFFER, "pBuffer"},
@@ -228,6 +232,18 @@ DrawingSurfaceConfig::DrawingSurfaceConfig(::Display* dpy, ::XVisualInfo* pvi) {
} else
accR = accG = accB = accA = 0;
+ // Note that samples=0 means no multisampling!
+ // One might think that one sample per pixel means non-multisampling
+ // but that's not the convention used here.
+ samples = 0;
+ if (canRGBA) {
+ int sampBuf = 0;
+ glXGetConfig(dpy, vi, GLX_SAMPLE_BUFFERS, &sampBuf);
+ if (sampBuf) {
+ glXGetConfig(dpy, vi, GLX_SAMPLES, &samples);
+ }
+ }
+
canWindow = canPixmap = true;
// Only guaranteed in early versions of GLX.
@@ -329,6 +345,8 @@ DrawingSurfaceConfig::DrawingSurfaceConfig(int id, ::PIXELFORMATDESCRIPTOR *ppfd
accB = pfd->cAccumBlueBits;
accA = pfd->cAccumAlphaBits;
+ samples = 0; // XXX implement properly for Windows!
+
canWindow = pfd->dwFlags & PFD_DRAW_TO_WINDOW;
canWinSysRender = pfd->dwFlags & PFD_SUPPORT_GDI;
@@ -378,6 +396,7 @@ DrawingSurfaceConfig::DrawingSurfaceConfig() {
accB = 32;
accA = 32;
+ samples = 0;
canWindow = 1;
canWinSysRender = 1;
@@ -436,6 +455,8 @@ DrawingSurfaceConfig::DrawingSurfaceConfig(int id, ::AGLPixelFormat pfd)
else
r = g = b = a = 0;
+ samples = 0; // XXX implement properly for AGL
+
aglDescribePixelFormat( pf, AGL_DEPTH_SIZE, (long *)& z);
aglDescribePixelFormat( pf, AGL_STENCIL_SIZE, (long *)& s);
@@ -544,6 +565,9 @@ DrawingSurfaceConfig::DrawingSurfaceConfig(string& str) {
case VACCUMA:
accA = lex.iValue;
break;
+ case VSAMPLES:
+ samples = lex.iValue;
+ break;
case VCANWINDOW:
canWindow = lex.iValue;
break;
@@ -668,6 +692,8 @@ DrawingSurfaceConfig::canonicalDescription() {
<< ' ' << mapVarToName[VACCUMB] << ' ' << accB
<< ' ' << mapVarToName[VACCUMA] << ' ' << accA;
+ s << ' ' << mapVarToName[VSAMPLES] << ' ' << samples;
+
s << ' ' << mapVarToName[VCANWINDOW] << ' ' << canWindow;
# if defined(__X11__)
@@ -768,6 +794,10 @@ DrawingSurfaceConfig::conciseDescription() {
}
}
+ if (samples) {
+ s << ", samples" << samples;
+ }
+
{
s << ", ";
bool sep = false;
@@ -868,6 +898,10 @@ DrawingSurfaceConfig::match(vector<DrawingSurfaceConfig*>& choices) {
error += abs(accB - c.accB);
if (accA && c.accA)
error += abs(accA - c.accA);
+ // Use a huge error value for multisample mismatch.
+ // Not sure this is the best solution.
+ if (samples != c.samples)
+ error += 1000;
if (error < bestError) {
bestError = error;
diff --git a/tests/glean/dsconfig.h b/tests/glean/dsconfig.h
index a5f24f925..ea7ffd7cf 100644
--- a/tests/glean/dsconfig.h
+++ b/tests/glean/dsconfig.h
@@ -1,6 +1,8 @@
// BEGIN_COPYRIGHT
//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// multisample changes: Copyright (c) 2008 VMware, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@@ -135,6 +137,9 @@ class DrawingSurfaceConfig {
int accA; // Depth of accum buf alpha channel.
+ int samples; // Number of samples per pixel.
+ // Zero indicates a non-ms config.
+
bool canWindow; // True if can be used for windows.
# if defined(__X11__)
diff --git a/tests/glean/dsfilt.cpp b/tests/glean/dsfilt.cpp
index 9227bc6fe..6b1795b42 100644
--- a/tests/glean/dsfilt.cpp
+++ b/tests/glean/dsfilt.cpp
@@ -2,6 +2,8 @@
//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
//
+// multisample changes: Copyright (c) 2008 VMware, Inc. 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
@@ -214,6 +216,7 @@ DrawingSurfaceFilter::InitVarTable() {
varTable["accuma"] = VAR_ACCUM_A;
varTable["accumrgb"] = VAR_ACCUM_RGB;
varTable["accumrgba"] = VAR_ACCUM_RGBA;
+ varTable["samples"] = VAR_SAMPLES;
varTable["aux"] = VAR_AUX;
varTable["db"] = VAR_DB;
varTable["sb"] = VAR_SB;
@@ -283,6 +286,9 @@ DrawingSurfaceFilter::FetchVariable(const DrawingSurfaceConfig& c, Token v) {
case VAR_ACCUM_RGBA:
return min(c.accR, min(c.accG, min(c.accB, c.accA)));
+ case VAR_SAMPLES:
+ return c.samples;
+
case VAR_AUX:
return c.aux;
diff --git a/tests/glean/dsfilt.h b/tests/glean/dsfilt.h
index 89c6d5833..ec715759f 100644
--- a/tests/glean/dsfilt.h
+++ b/tests/glean/dsfilt.h
@@ -2,6 +2,8 @@
//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
//
+// multisample changes: Copyright (c) 2008 VMware, Inc. 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
@@ -175,6 +177,8 @@ class DrawingSurfaceFilter {
VAR_ACCUM_RGB, // min(accum r, accum g, accum b)
VAR_ACCUM_RGBA, // min(accum r, accum g, accum b, accum a)
+ VAR_SAMPLES, // number of samples per pixel
+
VAR_AUX, // number of aux color buffers
VAR_DB, // nonzero if double buffered
diff --git a/tests/glean/environ.cpp b/tests/glean/environ.cpp
index 39d8815c6..fac0f6690 100644
--- a/tests/glean/environ.cpp
+++ b/tests/glean/environ.cpp
@@ -39,6 +39,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
+#include <stdlib.h>
#elif defined(__MS__)
#include <sys/stat.h>
diff --git a/tests/glean/glutils.cpp b/tests/glean/glutils.cpp
index 4b38d6203..26d348831 100644
--- a/tests/glean/glutils.cpp
+++ b/tests/glean/glutils.cpp
@@ -32,6 +32,7 @@
// glutils.cpp: frequently-used OpenGL operations
#define GLX_GLXEXT_PROTOTYPES
+#include <stdlib.h>
#include "glwrap.h"
#include "environ.h"
#include "lex.h"
diff --git a/tests/glean/image.h b/tests/glean/image.h
index 83942f4f7..fd28f49cb 100644
--- a/tests/glean/image.h
+++ b/tests/glean/image.h
@@ -223,7 +223,10 @@ class Image {
BasicStats stats[4]; // stats for absolute error in
// R, G, B, and A
};
- Registration reg(Image& ref);
+ Registration reg(Image& img);
+
+ // test if images are identical
+ bool operator==(const Image &ref) const;
// Image arithmetic
// XXX type and format conversions, with appropriate scaling.
diff --git a/tests/glean/image_misc.cpp b/tests/glean/image_misc.cpp
index adfdc2247..176267011 100644
--- a/tests/glean/image_misc.cpp
+++ b/tests/glean/image_misc.cpp
@@ -131,6 +131,32 @@ Image::~Image() {
delete[] _pixels;
}
+
+// Test if two images are identical
+bool Image::operator==(const Image &img) const
+{
+ // cast away const because of rowSizeInBytes()
+ Image &img1 = const_cast<Image&>(*this);
+ Image &img2 = const_cast<Image&>(img);
+
+ if (img1.width() != img2.width() ||
+ img1.height() != img2.height() ||
+ img1.format() != img2.format() ||
+ img1.type() != img2.type() ||
+ img1.alignment() != img2.alignment() ||
+ img1.rowSizeInBytes() != img2.rowSizeInBytes())
+ return false;
+
+ const char *p1 = img1.pixels();
+ const char *p2 = img2.pixels();
+ const int n = img1.rowSizeInBytes() * img1.height();
+ if (memcmp(p1, p2, n) != 0)
+ return false;
+
+ return true;
+}
+
+
///////////////////////////////////////////////////////////////////////////////
// pixels - set pointer to pixel array
///////////////////////////////////////////////////////////////////////////////
diff --git a/tests/glean/main.cpp b/tests/glean/main.cpp
index b7a1d2d53..77fae4ff8 100644
--- a/tests/glean/main.cpp
+++ b/tests/glean/main.cpp
@@ -34,6 +34,7 @@
using namespace std;
#include <cassert>
+#include <cstring>
#include <iostream>
#include <string>
#include <vector>
diff --git a/tests/glean/tapi2.cpp b/tests/glean/tapi2.cpp
index 795b4516b..8367d74d1 100644
--- a/tests/glean/tapi2.cpp
+++ b/tests/glean/tapi2.cpp
@@ -31,9 +31,11 @@
#define GL_GLEXT_PROTOTYPES
-#include "tapi2.h"
+#include <stdlib.h>
+#include <cstring>
#include <cassert>
#include <math.h>
+#include "tapi2.h"
namespace GLEAN {
@@ -281,7 +283,7 @@ API2Test::renderQuad(GLfloat *pixel) const
glTexCoord2f(0, 1); glVertex2f(-r, r);
glEnd();
- // read a pixel from lower-left corder of rendered quad
+ // read a pixel from lower-left corner of rendered quad
glReadPixels(windowSize / 2 - 2, windowSize / 2 - 2, 1, 1,
GL_RGBA, GL_FLOAT, pixel);
}
@@ -319,7 +321,7 @@ API2Test::renderQuadWithArrays(GLint attr, const GLfloat value[4],
glDisable(GL_VERTEX_ARRAY);
glDisableVertexAttribArray_func(attr);
- // read a pixel from lower-left corder of rendered quad
+ // read a pixel from lower-left corner of rendered quad
glReadPixels(windowSize / 2 - 2, windowSize / 2 - 2, 1, 1,
GL_RGBA, GL_FLOAT, pixel);
}
@@ -702,7 +704,12 @@ API2Test::testUniformiFuncs(void)
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]);
+#if 0
+ printf("Expected color %f %f %f %f\n",
+ expected[0], expected[1], expected[2], expected[3]);
+ printf("Found color %f %f %f %f\n",
+ pixel[0], pixel[1], pixel[2], pixel[3]);
+#endif
return false;
}
@@ -748,6 +755,14 @@ API2Test::testShaderAttribs(void)
GLfloat pixel[4];
renderQuadWithArrays(attr, testColors[i], pixel);
if (!equalColors(pixel, testColors[i])) {
+#if 0
+ printf("Expected color %f %f %f\n",
+ testColors[i][0],
+ testColors[i][1],
+ testColors[i][2]);
+ printf("Found color %f %f %f\n",
+ pixel[0], pixel[1], pixel[2]);
+#endif
REPORT_FAILURE("Vertex array test failed");
return false;
}
diff --git a/tests/glean/tbase.h b/tests/glean/tbase.h
index afe539437..2cf72dd1e 100644
--- a/tests/glean/tbase.h
+++ b/tests/glean/tbase.h
@@ -125,6 +125,8 @@ and tbasic.cpp.
class GLEAN::DrawingSurfaceConfig; // Forward reference.
+
+// Macro for constructor for Glean test taking width, height and one config flag
#define GLEAN_CLASS_WHO(TEST, RESULT, WIDTH, HEIGHT, ONE) \
TEST(const char* aName, const char* aFilter, \
const char* aDescription): \
@@ -146,6 +148,7 @@ class GLEAN::DrawingSurfaceConfig; // Forward reference.
BaseTest<RESULT>(aName, aFilter, anExtensionList, aDescription) { \
fWidth = WIDTH; \
fHeight = HEIGHT; \
+ testOne = ONE; \
} \
virtual ~TEST() {} \
\
@@ -153,12 +156,16 @@ class GLEAN::DrawingSurfaceConfig; // Forward reference.
virtual void compareOne(RESULT& oldR, RESULT& newR); \
virtual void logOne(RESULT& r)
+// Macro for constructor for Glean test taking width, height
#define GLEAN_CLASS_WH(TEST, RESULT, WIDTH, HEIGHT) \
GLEAN_CLASS_WHO(TEST, RESULT, WIDTH, HEIGHT, false)
+// Macro for constructor for Glean test taking only test class and result class
#define GLEAN_CLASS(TEST, RESULT) \
GLEAN_CLASS_WHO(TEST, RESULT, 258, 258, false)
+
+
namespace GLEAN {
class BaseResult : public Result {
@@ -185,6 +192,8 @@ public:
}
};
+
+// The BaseTest class is a templatized class taking a ResultType as a parameter
template <class ResultType> class BaseTest: public Test {
public:
BaseTest(const char* aName, const char* aFilter,
@@ -252,14 +261,23 @@ public:
<< '\n';
}
+ // This method allows a test to indicate that it's not applicable.
+ // For example, the GL version is too low.
+ virtual bool isApplicable() const {
+ return true;
+ }
+
virtual void run(Environment& environment) {
- if (hasRun) return; // no multiple invocations
+ if (hasRun)
+ return; // no multiple invocations
+
// Invoke the prerequisite tests, if any:
for (Test** t = prereqs; t != 0 && *t != 0; ++t)
(*t)->run(environment);
env = &environment; // make environment available
logDescription(); // log invocation
WindowSystem& ws = env->winSys;
+
try {
OutputStream os(*this); // open results file
@@ -275,8 +293,13 @@ public:
++p) {
Window w(ws, **p, fWidth, fHeight);
RenderingContext rc(ws, **p);
- if (!ws.makeCurrent(rc, w))
- ; // XXX need to throw exception here
+ if (!ws.makeCurrent(rc, w)) {
+ // XXX need to throw exception here
+ }
+
+ // Check if test is applicable to this context
+ if (!isApplicable())
+ continue;
// Check for all prerequisite extensions. Note
// that this must be done after the rendering
@@ -293,7 +316,10 @@ public:
// Save the result
results.push_back(r);
r->put(os);
- if (testOne) break;
+
+ // if testOne, skip remaining surface configs
+ if (testOne)
+ break;
}
}
catch (DrawingSurfaceFilter::Syntax e) {
diff --git a/tests/glean/tblend.cpp b/tests/glean/tblend.cpp
index 3fb8d6116..b94c82f48 100644
--- a/tests/glean/tblend.cpp
+++ b/tests/glean/tblend.cpp
@@ -29,6 +29,7 @@
// tblend.cpp: Test blending functions.
#include <assert.h>
+#include <stdlib.h>
#include "tblend.h"
#include "rand.h"
#include "image.h"
diff --git a/tests/glean/tdepthstencil.cpp b/tests/glean/tdepthstencil.cpp
index 945d8bd1c..54e97df0f 100644
--- a/tests/glean/tdepthstencil.cpp
+++ b/tests/glean/tdepthstencil.cpp
@@ -30,12 +30,13 @@
// Brian Paul 1 October 2005
+#include <cassert>
+#include <cmath>
+#include <cstring>
#include "tdepthstencil.h"
#include "rand.h"
#include "timer.h"
#include "image.h"
-#include <cassert>
-#include <cmath>
#ifdef GL_EXT_packed_depth_stencil
diff --git a/tests/glean/tfbo.cpp b/tests/glean/tfbo.cpp
index 24b03f5c1..ddfea1ccc 100644
--- a/tests/glean/tfbo.cpp
+++ b/tests/glean/tfbo.cpp
@@ -81,15 +81,21 @@ FBOTest::setup(void)
tolerance[4] = 1.0;
// Check if GL_EXT_framebuffer_object is supported
- if (!strstr((char *) glGetString(GL_EXTENSIONS), "GL_EXT_framebuffer_object")) {
+ if (GLUtils::haveExtension("GL_EXT_framebuffer_object")) {
+ printf("GL_EXT_framebuffer_object is supported\n");
+ useFramebuffer = 1;
+ }
+ else {
printf("GL_EXT_framebuffer_object is not supported\n");
useFramebuffer = 0;
return false;
}
- else {
- printf("GL_EXT_framebuffer_object is supported\n");
- useFramebuffer = 1;
- }
+
+ haveARBfbo = GLUtils::haveExtension("GL_ARB_framebuffer_object");
+ if (haveARBfbo)
+ printf("GL_ARB_framebuffer_object is supported\n");
+ else
+ printf("GL_ARB_framebuffer_object is not supported\n");
return true;
}
@@ -1217,7 +1223,8 @@ FBOTest::testErrorHandling(void)
return false;
}
- // All attached images have the same width and height
+ // All attached images have the same width and height,
+ // unless GL_ARB_framebuffer object is supported.
glGenFramebuffersEXT(1, fbs);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbs[0]);
glGenTextures(2, textures);
@@ -1238,15 +1245,16 @@ FBOTest::testErrorHandling(void)
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT(1, fbs);
glDeleteTextures(2, textures);
- if (status != GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT) {
+ if (!haveARBfbo &&
+ status != GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT) {
REPORT_FAILURE
- ("If no image is attached to framebuffer, status should be GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT");
+ ("If renderbuffer sizes don't all match, status should be GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT");
return false;
}
// All images attached to the attachment points
- // COLOR_ATTACHMENT0_EXT through COLOR_ATTACHMENTn_EXT must have
- // the same internal format.
+ // COLOR_ATTACHMENT0_EXT through COLOR_ATTACHMENTn_EXT must
+ // have the same internal format, unless ARB_fbo is supported.
glGenFramebuffersEXT(1, fbs);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbs[0]);
glGenTextures(2, textures);
@@ -1267,15 +1275,17 @@ FBOTest::testErrorHandling(void)
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT(1, fbs);
glDeleteTextures(2, textures);
- if (status != GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT) {
+ if (!haveARBfbo &&
+ status != GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT) {
REPORT_FAILURE
- ("If no image is attached to framebuffer, status should be GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT");
+ ("All color renderbuffers must be of same format, status should be GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT");
return false;
}
- // The value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT must not be
- // NONE for any color attachment point(s) named by DRAW_BUFFERi
+ // The value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT must not
+ // be NONE for any color attachment point(s) named by
+ // DRAW_BUFFERi.
glGenFramebuffersEXT(1, fbs);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbs[0]);
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT +
@@ -1285,13 +1295,13 @@ FBOTest::testErrorHandling(void)
glDeleteFramebuffersEXT(1, fbs);
if (status != GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT) {
REPORT_FAILURE
- ("If no image is attached to framebuffer, status should be GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT");
+ ("All any buffer named by glDrawBuffers is missing, status should be GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT");
return false;
}
// If READ_BUFFER is not NONE, then the value of
- // FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT must not be NONE for the
- // color attachment point named by READ_BUFFER.
+ // FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT must not be NONE for
+ // the color attachment point named by READ_BUFFER.
glGenFramebuffersEXT(1, fbs);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbs[0]);
glDrawBuffer(GL_NONE);
@@ -1302,7 +1312,7 @@ FBOTest::testErrorHandling(void)
glDeleteFramebuffersEXT(1, fbs);
if (status != GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT) {
REPORT_FAILURE
- ("If no image is attached to framebuffer, status should be GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT");
+ ("If buffer named by glReadBuffers is missing, status should be GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT");
return false;
}
}
diff --git a/tests/glean/tfbo.h b/tests/glean/tfbo.h
index 4a35c6024..01d0d271c 100644
--- a/tests/glean/tfbo.h
+++ b/tests/glean/tfbo.h
@@ -57,6 +57,7 @@ private:
typedef bool (FBOTest::*TestFunc)(MultiTestResult &r);
typedef bool (FBOTest::*SubTestFunc)(void);
+ GLboolean haveARBfbo; // GL_ARB_framebuffer_object supported?
GLfloat tolerance[5];
void reset(void);
bool testFunctionality(MultiTestResult &r);
diff --git a/tests/glean/tfpexceptions.cpp b/tests/glean/tfpexceptions.cpp
index 7a93eda1e..2038007a7 100644
--- a/tests/glean/tfpexceptions.cpp
+++ b/tests/glean/tfpexceptions.cpp
@@ -480,7 +480,7 @@ FPExceptionsTest::testOverflow(void)
GLdouble mat[16];
for (int i = 0; i < 15; i++)
mat[i] = 0.0;
- mat[0] = mat[5] = mat[10] = mat[15] = 1.0e500;
+ mat[0] = mat[5] = mat[10] = mat[15] = 1.0e100;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
diff --git a/tests/glean/tfragprog1.cpp b/tests/glean/tfragprog1.cpp
index 99e051a81..9abe354c8 100644
--- a/tests/glean/tfragprog1.cpp
+++ b/tests/glean/tfragprog1.cpp
@@ -39,10 +39,11 @@
// unique programs work correctly.
-#include "tfragprog1.h"
+#include <cstring>
#include <cassert>
#include <cmath>
#include <math.h>
+#include "tfragprog1.h"
namespace GLEAN {
@@ -436,6 +437,17 @@ static const FragmentProgram Programs[] = {
DONT_CARE_Z
},
{
+ /* check that RCP result is replicated across XYZW */
+ "RCP test 2 (reciprocal)",
+ "!!ARBfp1.0\n"
+ "PARAM values = {8, -10, 1, 12 }; \n"
+ "MOV result.color, values; \n"
+ "RCP result.color, values.x; \n"
+ "END \n",
+ { 1.0 / 8.0, 1.0 / 8.0, 1.0 / 8.0, 1.0 / 8.0 },
+ DONT_CARE_Z
+ },
+ {
"RSQ test 1 (reciprocal square root)",
"!!ARBfp1.0\n"
"PARAM values = {1, 4, 9, 100 }; \n"
@@ -563,6 +575,18 @@ static const FragmentProgram Programs[] = {
DONT_CARE_Z
},
{
+ "swizzled move test",
+ "!!ARBfp1.0\n"
+ "TEMP t; \n"
+ "PARAM p = program.local[1]; \n"
+ "MOV t, p; \n"
+ "MOV t, t.yxwz; \n" // "in-place" swizzle
+ "MOV result.color, t; \n"
+ "END \n",
+ { Param1[1], Param1[0], Param1[3], Param1[2] },
+ DONT_CARE_Z
+ },
+ {
"XPD test 1",
"!!ARBfp1.0\n"
"PARAM p1 = program.local[1]; \n"
diff --git a/tests/glean/tglsl1.cpp b/tests/glean/tglsl1.cpp
index 469485f94..42bc9c4ed 100644
--- a/tests/glean/tglsl1.cpp
+++ b/tests/glean/tglsl1.cpp
@@ -1,6 +1,7 @@
// BEGIN_COPYRIGHT -*- glean -*-
//
// Copyright (C) 1999 Allen Akin All Rights Reserved.
+// Copyright (C) 2008 VMWare, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@@ -31,9 +32,11 @@
#define GL_GLEXT_PROTOTYPES
-#include "tglsl1.h"
+#include <stdlib.h>
#include <cassert>
+#include <cstring>
#include <math.h>
+#include "tglsl1.h"
namespace GLEAN {
@@ -81,7 +84,7 @@ static PFNGLUNIFORMMATRIX4X3FVPROC glUniformMatrix4x3fv_func = NULL;
#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_VERSION_1_20 0x8 // GLSL 1.20 test
#define FLAG_WINDING_CW 0x10 // clockwise-winding polygon
#define FLAG_VERTEX_TEXTURE 0x20
@@ -333,6 +336,47 @@ static const ShaderProgram Programs[] = {
FLAG_NONE
},
+ {
+ "Swizzled expression",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4(1, 1, 1, 1); \n"
+ " vec4 b = vec4(0.5, 0.2, 0.1, 0.8); \n"
+ " vec4 c = (a * b).wzyx; \n"
+ " gl_FragColor = c; \n"
+ "} \n",
+ { 0.8, 0.1, 0.2, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Swizzled swizzle",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4(0.1, 0.2, 0.3, 0.4); \n"
+ " vec4 b = a.wzyx.yxwz; \n"
+ " gl_FragColor = b; \n"
+ "} \n",
+ { 0.3, 0.4, 0.1, 0.2 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "Swizzled swizzled swizzle",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " vec4 a = vec4(0.1, 0.2, 0.3, 0.4); \n"
+ " vec4 b = a.wzyx.yxwz.xxyz; \n"
+ " gl_FragColor = b; \n"
+ "} \n",
+ { 0.3, 0.3, 0.4, 0.1 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+
// Z-write ============================================================
{
"gl_FragDepth writing",
@@ -1057,6 +1101,19 @@ static const ShaderProgram Programs[] = {
},
{
+ "conditional expression (2)",
+ NO_VERTEX_SHADER,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.0); \n"
+ " bool b = true; \n"
+ " gl_FragColor.y = b ? 1.0 : 0.5; \n"
+ "} \n",
+ { 0.0, 1.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
"sequence (comma) operator",
NO_VERTEX_SHADER,
"void main() { \n"
@@ -1088,6 +1145,45 @@ static const ShaderProgram Programs[] = {
FLAG_NONE
},
+ {
+ "array with variable indexing",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " float ar[4]; \n"
+ " ar[0] = 0.0; \n"
+ " ar[1] = 0.1; \n"
+ " ar[2] = 0.5; \n"
+ " ar[3] = 0.7; \n"
+ " int indx = int(uniform1.y * 8.0); // should be 2 \n"
+ " gl_FragColor = vec4(ar[indx]); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "array with swizzled variable indexing",
+ NO_VERTEX_SHADER,
+ "uniform vec4 uniform1; \n"
+ "void main() { \n"
+ " float ar[4]; \n"
+ " ar[0] = 0.0; \n"
+ " ar[1] = 0.8; \n"
+ " ar[2] = 0.5; \n"
+ " ar[3] = 0.7; \n"
+ " ivec2 indx; \n"
+ " indx.x = 1; \n"
+ " indx.y = int(uniform1.y * 8.0); // should be 2 \n"
+ " float p = ar[indx.x] * ar[indx.y]; \n"
+ " gl_FragColor = vec4(p); \n"
+ "} \n",
+ { 0.4, 0.4, 0.4, 0.4 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
#if 0 // XXX enable someday
{
"vector subscript *=",
@@ -2069,7 +2165,7 @@ static const ShaderProgram Programs[] = {
"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"
+ " gl_FragColor = vec4(equal(a, b)); \n"
"} \n",
{ 1.0, 0.0, 0.0, 1.0 },
DONT_CARE_Z,
@@ -2082,7 +2178,7 @@ static const ShaderProgram Programs[] = {
"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"
+ " gl_FragColor = vec4(notEqual(a, b)); \n"
"} \n",
{ 0.0, 1.0, 1.0, 0.0 },
DONT_CARE_Z,
@@ -2095,7 +2191,7 @@ static const ShaderProgram Programs[] = {
"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"
+ " gl_FragColor = vec4(lessThanEqual(a, b)); \n"
"} \n",
{ 1.0, 0.0, 1.0, 1.0 },
DONT_CARE_Z,
@@ -2108,7 +2204,7 @@ static const ShaderProgram Programs[] = {
"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"
+ " gl_FragColor = vec4(greaterThanEqual(a, b)); \n"
"} \n",
{ 0.0, 1.0, 1.0, 1.0 },
DONT_CARE_Z,
@@ -2121,7 +2217,7 @@ static const ShaderProgram Programs[] = {
"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"
+ " gl_FragColor = vec4(lessThan(a, b)); \n"
"} \n",
{ 1.0, 0.0, 0.0, 0.0 },
DONT_CARE_Z,
@@ -2134,7 +2230,7 @@ static const ShaderProgram Programs[] = {
"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"
+ " gl_FragColor = vec4(greaterThan(a, b)); \n"
"} \n",
{ 0.0, 1.0, 0.0, 0.0 },
DONT_CARE_Z,
@@ -2234,6 +2330,93 @@ static const ShaderProgram Programs[] = {
FLAG_NONE
},
+ {
+ "struct (1)",
+ NO_VERTEX_SHADER,
+ "struct s1 { \n"
+ " float f1; \n"
+ " vec4 v4; \n"
+ "}; \n"
+ "\n"
+ "void main() { \n"
+ " s1 a, b; \n"
+ " a.v4 = vec4(0.25, 0.5, 0.75, 1.0); \n"
+ " a.f1 = 0.0; \n"
+ " b = a; \n"
+ " gl_FragColor = b.v4; \n"
+ "} \n",
+ { 0.25, 0.5, 0.75, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "struct (2)",
+ NO_VERTEX_SHADER,
+ "struct s1 { \n"
+ " float f1; \n"
+ " vec4 v4; \n"
+ "}; \n"
+ "\n"
+ "void main() { \n"
+ " s1 a[2]; \n"
+ " a[0].v4 = vec4(0.25, 0.5, 0.75, 1.0); \n"
+ " a[0].f1 = 0.0; \n"
+ " a[1] = a[0]; \n"
+ " gl_FragColor = a[1].v4; \n"
+ "} \n",
+ { 0.25, 0.5, 0.75, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "struct (3)",
+ NO_VERTEX_SHADER,
+ "struct s1 { \n"
+ " float f1; \n"
+ " vec4 v4; \n"
+ "}; \n"
+ "\n"
+ "void main() { \n"
+ " vec4 scale = vec4(0.5); \n"
+ " vec4 bias = vec4(0.1); \n"
+ " s1 a; \n"
+ " a.v4 = vec4(0.25, 0.5, 0.75, 1.0); \n"
+ " a.f1 = 0.0; \n"
+ " gl_FragColor = a.v4 * scale + bias; \n"
+ "} \n",
+ { 0.225, 0.35, 0.475, 0.6 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ {
+ "struct (4)",
+ NO_VERTEX_SHADER,
+ "struct s1 { \n"
+ " float foo; \n"
+ " vec4 v4; \n"
+ "}; \n"
+ "struct s2 { \n"
+ " float bar; \n"
+ " s1 s; \n"
+ " float baz; \n"
+ "}; \n"
+ "\n"
+ "void main() { \n"
+ " s2 a; \n"
+ " a.s.v4 = vec4(0.25, 0.5, 0.75, 1.0); \n"
+ " a.bar = 0.0; \n"
+ " a.baz = 0.0; \n"
+ " a.s.foo = 0.0; \n"
+ " gl_FragColor = a.s.v4; \n"
+ "} \n",
+ { 0.25, 0.5, 0.75, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
// Preprocessor tests ================================================
{
"Preprocessor test (1)",
@@ -2391,7 +2574,7 @@ static const ShaderProgram Programs[] = {
"} \n",
{ 0.5, 0.6, 0.7, 0.8 },
DONT_CARE_Z,
- FLAG_VERSION_2_1
+ FLAG_VERSION_1_20
},
{
"mat4x2 construct",
@@ -2407,7 +2590,7 @@ static const ShaderProgram Programs[] = {
"} \n",
{ 0.3, 0.4, 0.5, 0.6 },
DONT_CARE_Z,
- FLAG_VERSION_2_1
+ FLAG_VERSION_1_20
},
{
"mat2x3 construct",
@@ -2421,7 +2604,7 @@ static const ShaderProgram Programs[] = {
"} \n",
{ 0.4, 0.5, 0.6, 1.0 },
DONT_CARE_Z,
- FLAG_VERSION_2_1
+ FLAG_VERSION_1_20
},
{
"mat3x2 construct",
@@ -2436,7 +2619,7 @@ static const ShaderProgram Programs[] = {
"} \n",
{ 0.3, 0.4, 0.5, 0.6 },
DONT_CARE_Z,
- FLAG_VERSION_2_1
+ FLAG_VERSION_1_20
},
{
"mat4x3 construct",
@@ -2452,7 +2635,7 @@ static const ShaderProgram Programs[] = {
"} \n",
{ 0.4, 0.5, 0.6, 1.0 },
DONT_CARE_Z,
- FLAG_VERSION_2_1
+ FLAG_VERSION_1_20
},
{
"mat3x4 construct",
@@ -2466,7 +2649,7 @@ static const ShaderProgram Programs[] = {
"} \n",
{ 0.5, 0.6, 0.7, 0.8 },
DONT_CARE_Z,
- FLAG_VERSION_2_1
+ FLAG_VERSION_1_20
},
{
@@ -2486,7 +2669,7 @@ static const ShaderProgram Programs[] = {
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
+ FLAG_VERSION_1_20
},
{
@@ -2508,7 +2691,7 @@ static const ShaderProgram Programs[] = {
0.0
},
DONT_CARE_Z,
- FLAG_VERSION_2_1
+ FLAG_VERSION_1_20
},
{
@@ -2534,7 +2717,7 @@ static const ShaderProgram Programs[] = {
(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
+ FLAG_VERSION_1_20
},
{
@@ -2554,7 +2737,7 @@ static const ShaderProgram Programs[] = {
0.2 * 0.5 + 0.5 * 0.6,
0.2 * 0.7 + 0.5 * 0.8 },
DONT_CARE_Z,
- FLAG_VERSION_2_1
+ FLAG_VERSION_1_20
},
{
"vec3 * mat4x3 multiply",
@@ -2573,7 +2756,7 @@ static const ShaderProgram Programs[] = {
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
+ FLAG_VERSION_1_20
},
{
@@ -2586,7 +2769,7 @@ static const ShaderProgram Programs[] = {
"} \n",
{ 0.0, 0.1, 0.2, 0.3 }, // first column of 2x4 matrix
DONT_CARE_Z,
- FLAG_VERSION_2_1
+ FLAG_VERSION_1_20
},
{
"uniform matrix 2x4, transposed",
@@ -2598,7 +2781,7 @@ static const ShaderProgram Programs[] = {
"} \n",
{ 0.0, 0.2, 0.4, 0.6 }, // first row of 4x2 matrix
DONT_CARE_Z,
- FLAG_VERSION_2_1
+ FLAG_VERSION_1_20
},
{
"uniform matrix 4x3",
@@ -2611,7 +2794,7 @@ static const ShaderProgram Programs[] = {
"} \n",
{ 0.3, 0.4, 0.5, 1.0 }, // second column of 4x3 matrix
DONT_CARE_Z,
- FLAG_VERSION_2_1
+ FLAG_VERSION_1_20
},
{
"uniform matrix 4x3, transposed",
@@ -2624,10 +2807,161 @@ static const ShaderProgram Programs[] = {
"} \n",
{ 0.1, 0.5, 0.9, 1.0 },
DONT_CARE_Z,
- FLAG_VERSION_2_1
+ FLAG_VERSION_1_20
},
- // Illegal link test ===================================================
+ // Tests for GLSL 1.20 new array features
+ {
+ "GLSL 1.20 arrays",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "float [2] x; \n"
+ "void main() { \n"
+ " x[0] = 1.0; \n"
+ " x[1] = 2.0; \n"
+ " gl_FragColor.x = x[0]; \n"
+ " gl_FragColor.y = 0.25 * x[1]; \n"
+ " gl_FragColor.z = 0.1 * (x[0] + x[1]); \n"
+ " gl_FragColor.w = 1.0; \n"
+ "} \n",
+ { 1.0, 0.5, 0.3, 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_1_20
+ },
+ {
+ "GLSL 1.20 array constructor 1",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "float [2] x = float[2](1.0, 2.0); \n"
+ "void main() { \n"
+ " gl_FragColor.x = x[0]; \n"
+ " gl_FragColor.y = 0.25 * x[1]; \n"
+ " gl_FragColor.z = 0.1 * (x[0] + x[1]); \n"
+ " gl_FragColor.w = 1.0; \n"
+ "} \n",
+ { 1.0, 0.5, 0.3, 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_1_20
+ },
+ {
+ "GLSL 1.20 array constructor 2",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "vec4 [2] colors = vec4[2](vec4(0.5, 0.4, 0.3, 0.2), \n"
+ " vec4(0.7, 0.8, 0.9, 1.0)); \n"
+ "void main() { \n"
+ " gl_FragColor = colors[1]; \n"
+ "} \n",
+ { 0.7, 0.8, 0.9, 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_1_20
+ },
+ {
+ "GLSL 1.20 const array constructor 1",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "const float [2] x = float[2](1.0, 2.0); \n"
+ "void main() { \n"
+ " gl_FragColor.x = x[0]; \n"
+ " gl_FragColor.y = 0.25 * x[1]; \n"
+ " gl_FragColor.z = 0.1 * (x[0] + x[1]); \n"
+ " gl_FragColor.w = 1.0; \n"
+ "} \n",
+ { 1.0, 0.5, 0.3, 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_1_20
+ },
+ {
+ "GLSL 1.20 const array constructor 2",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "const vec4 [2] colors = vec4[2](vec4(0.5, 0.4, 0.3, 0.2), \n"
+ " vec4(0.7, 0.8, 0.9, 1.0)); \n"
+ "void main() { \n"
+ " gl_FragColor = colors[1]; \n"
+ "} \n",
+ { 0.7, 0.8, 0.9, 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_1_20
+ },
+ {
+ "GLSL 1.20 uniform array constructor",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "uniform float [2] x = float[2](1.0, 2.0); \n"
+ "void main() { \n"
+ " gl_FragColor.x = x[0]; \n"
+ " gl_FragColor.y = 0.25 * x[1]; \n"
+ " gl_FragColor.z = 0.1 * (x[0] + x[1]); \n"
+ " gl_FragColor.w = 1.0; \n"
+ "} \n",
+ { 1.0, 0.5, 0.3, 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_1_20
+ },
+ {
+ "GLSL 1.20 array.length()",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "const float [2] x = float[2](1.0, 2.0); \n"
+ "void main() { \n"
+ " int l = x.length(); \n"
+ " gl_FragColor = vec4(l * 0.25); \n"
+ "} \n",
+ { 0.5, 0.5, 0.5, 0.5 },
+ DONT_CARE_Z,
+ FLAG_VERSION_1_20
+ },
+ {
+ "GLSL 1.20 array error check",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "// Note array size disagreement here: \n"
+ "const float [2] x = float[3](1.0, 2.0); \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(1); \n"
+ "} \n",
+ { 1.0, 1.0, 1.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_1_20 | FLAG_ILLEGAL_SHADER
+ },
+
+ // Other new GLSL 1.20 features (just parse/compile tests)
+ {
+ "GLSL 1.20 precision qualifiers",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "highp float f1; \n"
+ "mediump float f2; \n"
+ "lowp float f3; \n"
+ "precision mediump float; \n"
+ "precision lowp int; \n"
+ "precision highp float; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(1); \n"
+ "} \n",
+ { 1.0, 1.0, 1.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_1_20
+ },
+ {
+ "GLSL 1.20 invariant, centroid qualifiers",
+ NO_VERTEX_SHADER,
+ "#version 120 \n"
+ "invariant varying vec4 v1; \n"
+ "centroid varying vec4 v2; \n"
+ "invariant centroid varying vec4 v3; \n"
+ "varying vec4 v4; \n"
+ "invariant v4; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(1); \n"
+ "} \n",
+ { 1.0, 1.0, 1.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_VERSION_1_20
+ },
+
+ // Illegal link test ==================================================
{
"gl_Position not written check",
"void main() { \n"
@@ -2657,6 +2991,42 @@ static const ShaderProgram Programs[] = {
FLAG_ILLEGAL_LINK
},
+ {
+ "varying read but not written",
+ // vert shader:
+ "varying vec4 foo; \n"
+ "void main() { \n"
+ " gl_Position = ftransform(); \n"
+ "} \n",
+ // frag shader:
+ "varying vec4 foo; \n"
+ "void main() { \n"
+ " gl_FragColor = foo; \n"
+ "} \n",
+ { 0.0, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_ILLEGAL_LINK
+ },
+
+ {
+ "texcoord varying",
+ // Does the linker correctly recognize that texcoord[1] is
+ // written by the vertex shader and read by the fragment shader?
+ // vert shader:
+ "void main() { \n"
+ " int i = 1; \n"
+ " gl_TexCoord[i] = vec4(0.5, 0, 0, 0); \n"
+ " gl_Position = ftransform(); \n"
+ "} \n",
+ // frag shader:
+ "void main() { \n"
+ " gl_FragColor = gl_TexCoord[1]; \n"
+ "} \n",
+ { 0.5, 0.0, 0.0, 0.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
{ NULL, NULL, NULL, {0,0,0,0}, 0, FLAG_NONE } // end of list sentinal
};
@@ -2964,16 +3334,17 @@ GLSLTest::setupTextureMatrix1(void)
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";
+ // check GLSL version
+#ifdef GL_SHADING_LANGUAGE_VERSION
+ const char *glslVersion = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
+#else
+ const char *glslVersion = NULL;
+#endif
+ if (!glslVersion || glslVersion[0] != '1') {
+ env->log << "GLSL 1.x not supported\n";
return false;
}
- if (verString[2] >= '1')
- version21 = GL_TRUE; // update when needed
- else
- version21 = GL_FALSE; // play it safe
+ glsl_120 = (glslVersion[2] >= '2');
if (!getFunctions()) {
env->log << "Unable to get pointer to an OpenGL 2.0 API function\n";
@@ -3399,7 +3770,7 @@ GLSLTest::runOne(MultiTestResult &r, Window &w)
else {
// loop over all tests
for (int i = 0; Programs[i].name; i++) {
- if ((Programs[i].flags & FLAG_VERSION_2_1) && !version21)
+ if ((Programs[i].flags & FLAG_VERSION_1_20) && !glsl_120)
continue; // skip non-applicable tests
if (testProgram(Programs[i])) {
r.numPassed++;
@@ -3413,9 +3784,27 @@ GLSLTest::runOne(MultiTestResult &r, Window &w)
}
+// We need OpenGL 2.0, 2.1 or 3.0
+bool
+GLSLTest::isApplicable() const
+{
+ const char *version = (const char *) glGetString(GL_VERSION);
+ if (strncmp(version, "2.0", 3) == 0 ||
+ strncmp(version, "2.1", 3) == 0 ||
+ strncmp(version, "3.0", 3) == 0) {
+ return true;
+ }
+ else {
+ env->log << name
+ << ": skipped. Requires GL 2.0, 2.1 or 3.0.\n";
+ return false;
+ }
+}
+
+
// The test object itself:
GLSLTest glslTest("glsl1", "window, rgb, z",
- "", // no extension filter (we'll test for version 2.x during setup)
+ "", // no extension filter but see isApplicable()
"GLSL test 1: test basic Shading Language functionality.\n"
);
diff --git a/tests/glean/tglsl1.h b/tests/glean/tglsl1.h
index 84a3d723f..73972b0e9 100644
--- a/tests/glean/tglsl1.h
+++ b/tests/glean/tglsl1.h
@@ -59,14 +59,17 @@ public:
const char *extensions, const char* description):
MultiTest(testName, filter, extensions, description)
{
+ testOne = true; // test with just one surface config
}
+ bool isApplicable() const;
+
virtual void runOne(MultiTestResult &r, Window &w);
private:
GLfloat tolerance[5];
GLfloat looseTolerance[5];
- GLfloat version21; // OpenGL 2.1 or higher supported?
+ GLfloat glsl_120; // GLSL 1.20 or higher supported?
bool getFunctions(void);
void setupTextures(void);
void setupTextureMatrix1(void);
diff --git a/tests/glean/tlogicop.cpp b/tests/glean/tlogicop.cpp
index 06a80cfce..470654a7a 100644
--- a/tests/glean/tlogicop.cpp
+++ b/tests/glean/tlogicop.cpp
@@ -30,10 +30,11 @@
// Based on Allen's blendFunc test.
// Brian Paul 10 May 2001
+#include <stdlib.h>
+#include <cmath>
#include "tlogicop.h"
#include "rand.h"
#include "image.h"
-#include <cmath>
namespace {
diff --git a/tests/glean/toccluqry.cpp b/tests/glean/toccluqry.cpp
index 7cc49b445..a362fc130 100644
--- a/tests/glean/toccluqry.cpp
+++ b/tests/glean/toccluqry.cpp
@@ -33,10 +33,12 @@
*/
#define GL_GLEXT_PROTOTYPES
-#include "toccluqry.h"
+#include <stdlib.h>
#include <cassert>
+#include <cstring>
#include <stdio.h>
#include <cmath>
+#include "toccluqry.h"
#define START_QUERY(id)\
@@ -84,7 +86,7 @@ GLuint OccluQryTest::find_unused_id()
while (1) {
/* assuming that at least 2^32-1 <id> can be generated */
- id = random() % ((unsigned long)1 << 32 - 1);
+ id = random() % (((unsigned long) 1 << 32) - 1);
if (id != 0 && glIsQueryARB(id) == GL_FALSE)
return id;
if (++ counter >= MAX_FIND_ID_ROUND) {
diff --git a/tests/glean/tpaths.cpp b/tests/glean/tpaths.cpp
index 00926ea11..eed2194e6 100644
--- a/tests/glean/tpaths.cpp
+++ b/tests/glean/tpaths.cpp
@@ -41,6 +41,7 @@
//
// Author: Brian Paul (brianp@valinux.com) November 2000
+#include <stdlib.h>
#include "tpaths.h"
namespace GLEAN {
diff --git a/tests/glean/tpbo.cpp b/tests/glean/tpbo.cpp
index 4642690df..5ae7a5745 100644
--- a/tests/glean/tpbo.cpp
+++ b/tests/glean/tpbo.cpp
@@ -34,10 +34,15 @@
#define GL_GLEXT_PROTOTYPES
-#include "tpbo.h"
+
+#include <stdlib.h>
+#include <cstring>
#include <cassert>
#include <math.h>
+#include "tpbo.h"
#include "timer.h"
+
+
namespace GLEAN
{
@@ -79,12 +84,12 @@ bool PBOTest::setup(void)
// 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");
+ //printf("GL_ARB_pixel_buffer_object is not supported\n");
usePBO = 0;
return false;
}
else {
- printf("GL_ARB_pixel_buffer_object is supported\n");
+ //printf("GL_ARB_pixel_buffer_object is supported\n");
usePBO = 1;
}
diff --git a/tests/glean/tpixelformats.cpp b/tests/glean/tpixelformats.cpp
index 867ba08fa..3603bf571 100644
--- a/tests/glean/tpixelformats.cpp
+++ b/tests/glean/tpixelformats.cpp
@@ -27,9 +27,10 @@
// END_COPYRIGHT
-#include "tpixelformats.h"
+#include <stdlib.h>
#include <cassert>
#include <cmath>
+#include "tpixelformats.h"
// Set to 1 to help debug test failures:
diff --git a/tests/glean/tpointsprite.cpp b/tests/glean/tpointsprite.cpp
index 47cff89ae..280984c29 100644
--- a/tests/glean/tpointsprite.cpp
+++ b/tests/glean/tpointsprite.cpp
@@ -40,10 +40,13 @@
*/
#define GL_GLEXT_PROTOTYPES
-#include "tpointsprite.h"
+
+#include <stdlib.h>
#include <cassert>
#include <cmath>
#include <stdio.h>
+#include "tpointsprite.h"
+
namespace GLEAN {
diff --git a/tests/glean/tshaderapi.cpp b/tests/glean/tshaderapi.cpp
new file mode 100644
index 000000000..643bb6214
--- /dev/null
+++ b/tests/glean/tshaderapi.cpp
@@ -0,0 +1,600 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2009 VMware, Inc. 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 VMWARE 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
+
+
+// Test GLSL-related API functions for correct behaviour
+// Based on the "shader_api.c" test from Mesa, written by Bruce Merry.
+
+
+#include <cstring>
+#include "tshaderapi.h"
+#include "rand.h"
+#include "timer.h"
+#include "image.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 PFNGLDETACHSHADERPROC glDetachShader_func = NULL;
+static PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray_func = NULL;
+static PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray_func = NULL;
+static PFNGLGETACTIVEATTRIBPROC glGetActiveAttrib_func = NULL;
+static PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform_func = NULL;
+static PFNGLGETATTACHEDSHADERSPROC glGetAttachedShaders_func = NULL;
+static PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation_func = NULL;
+static PFNGLGETPROGRAMIVPROC glGetProgramiv_func = NULL;
+static PFNGLGETPROGRAMINFOLOGPROC glGetPrograminfolog_func = NULL;
+static PFNGLGETSHADERIVPROC glGetShaderiv_func = NULL;
+static PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog_func = NULL;
+static PFNGLGETSHADERSOURCEPROC glGetShaderSource_func = NULL;
+static PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation_func = NULL;
+static PFNGLGETUNIFORMFVPROC glGetUniformfv_func = NULL;
+static PFNGLGETUNIFORMIVPROC glGetUniformiv_func = NULL;
+static PFNGLLINKPROGRAMPROC glLinkProgram_func = NULL;
+static PFNGLSHADERSOURCEPROC glShaderSource_func = NULL;
+static PFNGLUSEPROGRAMPROC glUseProgram_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 PFNGLUNIFORM1FVPROC glUniform1fv_func = NULL;
+static PFNGLUNIFORM2FVPROC glUniform2fv_func = NULL;
+static PFNGLUNIFORM3FVPROC glUniform3fv_func = NULL;
+static PFNGLUNIFORM4FVPROC glUniform4fv_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 PFNGLVALIDATEPROGRAMPROC glValidateProgram_func = NULL;
+
+
+ShaderAPIResult::ShaderAPIResult()
+{
+ pass = false;
+}
+
+
+void
+ShaderAPITest::get_ext_procs(void)
+{
+ glAttachShader_func = (PFNGLATTACHSHADERPROC) GLUtils::getProcAddress("glAttachShader");
+ glBindAttribLocation_func = (PFNGLBINDATTRIBLOCATIONPROC) GLUtils::getProcAddress("glBindAttribLocation");
+ glCompileShader_func = (PFNGLCOMPILESHADERPROC) GLUtils::getProcAddress("glCompileShader");
+ glCreateProgram_func = (PFNGLCREATEPROGRAMPROC) GLUtils::getProcAddress("glCreateProgram");
+ glCreateShader_func = (PFNGLCREATESHADERPROC) GLUtils::getProcAddress("glCreateShader");
+ glDeleteProgram_func = (PFNGLDELETEPROGRAMPROC) GLUtils::getProcAddress("glDeleteProgram");
+ glDeleteShader_func = (PFNGLDELETESHADERPROC) GLUtils::getProcAddress("glDeleteShader");
+ glDetachShader_func = (PFNGLDETACHSHADERPROC) GLUtils::getProcAddress("glDetachShader");
+ glDisableVertexAttribArray_func = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) GLUtils::getProcAddress("glDisableVertexAttribArray");
+ glEnableVertexAttribArray_func = (PFNGLENABLEVERTEXATTRIBARRAYPROC) GLUtils::getProcAddress("glEnableVertexAttribArray");
+ glGetActiveAttrib_func = (PFNGLGETACTIVEATTRIBPROC) GLUtils::getProcAddress("glGetActiveAttrib");
+ glGetActiveUniform_func = (PFNGLGETACTIVEUNIFORMPROC) GLUtils::getProcAddress("glGetActiveUniform");
+ glGetAttachedShaders_func = (PFNGLGETATTACHEDSHADERSPROC) GLUtils::getProcAddress("glGetAttachedShaders");
+ glGetAttribLocation_func = (PFNGLGETATTRIBLOCATIONPROC) GLUtils::getProcAddress("glGetAttribLocation");
+ glGetProgramiv_func = (PFNGLGETPROGRAMIVPROC) GLUtils::getProcAddress("glGetProgramiv");
+ glGetPrograminfolog_func = (PFNGLGETPROGRAMINFOLOGPROC) GLUtils::getProcAddress("glGetPrograminfolog");
+ glGetShaderiv_func = (PFNGLGETSHADERIVPROC) GLUtils::getProcAddress("glGetShaderiv");
+ glGetShaderInfoLog_func = (PFNGLGETSHADERINFOLOGPROC) GLUtils::getProcAddress("glGetShaderInfoLog");
+ glGetShaderSource_func = (PFNGLGETSHADERSOURCEPROC) GLUtils::getProcAddress("glGetShaderSource");
+ glGetUniformLocation_func = (PFNGLGETUNIFORMLOCATIONPROC) GLUtils::getProcAddress("glGetUniformLocation");
+ glGetUniformfv_func = (PFNGLGETUNIFORMFVPROC) GLUtils::getProcAddress("glGetUniformfv");
+ glGetUniformiv_func = (PFNGLGETUNIFORMIVPROC) GLUtils::getProcAddress("glGetUniformiv");
+ glLinkProgram_func = (PFNGLLINKPROGRAMPROC) GLUtils::getProcAddress("glLinkProgram");
+ glShaderSource_func = (PFNGLSHADERSOURCEPROC) GLUtils::getProcAddress("glShaderSource");
+ glUseProgram_func = (PFNGLUSEPROGRAMPROC) GLUtils::getProcAddress("glUseProgram");
+ glUniform1f_func = (PFNGLUNIFORM1FPROC) GLUtils::getProcAddress("glUniform1f");
+ glUniform2f_func = (PFNGLUNIFORM2FPROC) GLUtils::getProcAddress("glUniform2f");
+ glUniform3f_func = (PFNGLUNIFORM3FPROC) GLUtils::getProcAddress("glUniform3f");
+ glUniform4f_func = (PFNGLUNIFORM4FPROC) GLUtils::getProcAddress("glUniform4f");
+ glUniform1i_func = (PFNGLUNIFORM1IPROC) GLUtils::getProcAddress("glUniform1i");
+ glUniform2i_func = (PFNGLUNIFORM2IPROC) GLUtils::getProcAddress("glUniform2i");
+ glUniform3i_func = (PFNGLUNIFORM3IPROC) GLUtils::getProcAddress("glUniform3i");
+ glUniform4i_func = (PFNGLUNIFORM4IPROC) GLUtils::getProcAddress("glUniform4i");
+ glUniform1fv_func = (PFNGLUNIFORM1FVPROC) GLUtils::getProcAddress("glUniform1fv");
+ glUniform2fv_func = (PFNGLUNIFORM2FVPROC) GLUtils::getProcAddress("glUniform2fv");
+ glUniform3fv_func = (PFNGLUNIFORM3FVPROC) GLUtils::getProcAddress("glUniform3fv");
+ glUniform4fv_func = (PFNGLUNIFORM4FVPROC) GLUtils::getProcAddress("glUniform4fv");
+ glUniform1iv_func = (PFNGLUNIFORM1IVPROC) GLUtils::getProcAddress("glUniform1iv");
+ glUniform2iv_func = (PFNGLUNIFORM2IVPROC) GLUtils::getProcAddress("glUniform2iv");
+ glUniform3iv_func = (PFNGLUNIFORM3IVPROC) GLUtils::getProcAddress("glUniform3iv");
+ glUniform4iv_func = (PFNGLUNIFORM4IVPROC) GLUtils::getProcAddress("glUniform4iv");
+ glUniformMatrix2fv_func = (PFNGLUNIFORMMATRIX2FVPROC) GLUtils::getProcAddress("glUniformMatrix2fv");
+ glUniformMatrix3fv_func = (PFNGLUNIFORMMATRIX3FVPROC) GLUtils::getProcAddress("glUniformMatrix3fv");
+ glUniformMatrix4fv_func = (PFNGLUNIFORMMATRIX4FVPROC) GLUtils::getProcAddress("glUniformMatrix4fv");
+ glValidateProgram_func = (PFNGLVALIDATEPROGRAMPROC) GLUtils::getProcAddress("glValidateProgram");
+}
+
+
+void
+ShaderAPITest::assert_test(const char *file, int line, int cond, const char *msg)
+{
+ if (!cond) {
+ error = true;
+ fprintf(stderr, "%s:%d assertion \"%s\" failed\n", file, line, msg);
+ }
+}
+
+#undef assert
+#define assert(x) assert_test(__FILE__, __LINE__, (x), #x)
+
+
+void
+ShaderAPITest::assert_no_error_test(const char *file, int line)
+{
+ GLenum err;
+
+ err = glGetError();
+ if (err != GL_NO_ERROR) {
+ error = true;
+ fprintf(stderr, "%s:%d received error %s\n",
+ file, line, gluErrorString(err));
+ }
+}
+
+#define assert_no_error() assert_no_error_test(__FILE__, __LINE__)
+
+
+void
+ShaderAPITest::assert_error_test(const char *file, int line, GLenum expect)
+{
+ GLenum err;
+
+ err = glGetError();
+ if (err != expect) {
+ fprintf(stderr, "%s:%d expected %s but received %s\n",
+ file, line, gluErrorString(expect), gluErrorString(err));
+ error = true;
+ }
+
+ while (glGetError())
+ ; /* consume any following errors */
+}
+
+#define assert_error(err) assert_error_test(__FILE__, __LINE__, (err))
+
+
+void
+ShaderAPITest::check_status(GLuint id, GLenum pname, void (*query)(GLuint, GLenum, GLint *))
+{
+ GLint status;
+
+ query(id, pname, &status);
+ if (!status) {
+ char info[65536];
+
+ fprintf(stderr, "Compilation/link failure:\n");
+ glGetShaderInfoLog_func(id, sizeof(info), NULL, info);
+ fprintf(stderr, "%s\n", info);
+
+ error = true;
+ }
+}
+
+
+void
+ShaderAPITest::check_compile_status(GLuint id)
+{
+ check_status(id, GL_COMPILE_STATUS, glGetShaderiv_func);
+}
+
+
+void
+ShaderAPITest::check_link_status(GLuint id)
+{
+ check_status(id, GL_LINK_STATUS, glGetProgramiv_func);
+}
+
+
+GLuint
+ShaderAPITest::make_shader(GLenum type, const char *src)
+{
+ GLuint id;
+
+ assert_no_error();
+ id = glCreateShader_func(type);
+ glShaderSource_func(id, 1, &src, NULL);
+ glCompileShader_func(id);
+ check_compile_status(id);
+ assert_no_error();
+ return id;
+}
+
+
+GLuint
+ShaderAPITest::make_program(const char *vs_src, const char *fs_src)
+{
+ GLuint id, vs, fs;
+
+ assert_no_error();
+ id = glCreateProgram_func();
+ if (vs_src) {
+ vs = make_shader(GL_VERTEX_SHADER, vs_src);
+ glAttachShader_func(id, vs);
+ glDeleteShader_func(vs);
+ }
+ if (fs_src) {
+ fs = make_shader(GL_FRAGMENT_SHADER, fs_src);
+ glAttachShader_func(id, fs);
+ glDeleteShader_func(fs);
+ }
+ glLinkProgram_func(id);
+ check_link_status(id);
+ glUseProgram_func(id);
+ glDeleteProgram_func(id);
+ assert_no_error();
+ return id;
+}
+
+
+void
+ShaderAPITest::test_uniform_size_type1(const char *glslType, GLenum glType, const char *el)
+{
+ char buffer[1024];
+ GLuint program;
+ GLint active, i;
+ GLenum type;
+ GLint size;
+
+ //printf(" Running subtest %s\n", glslType);
+ //fflush(stdout);
+ sprintf(buffer, "#version 120\nuniform %s m[60];\nvoid main() { gl_Position[0] = m[59]%s; }\n",
+ glslType, el);
+
+ program = make_program(buffer, NULL);
+ glGetProgramiv_func(program, GL_ACTIVE_UNIFORMS, &active);
+ assert_no_error();
+ for (i = 0; i < active; i++) {
+ size = -1;
+ type = 0;
+ glGetActiveUniform_func(program, i, sizeof(buffer), NULL,
+ &size, &type, buffer);
+ assert_no_error();
+ if (strncmp(buffer, "m", 1) == 0)
+ break;
+ }
+ assert(i < active); /* Otherwise the compiler optimised it out */
+ assert(type == glType);
+ assert(size == 60);
+}
+
+
+void
+ShaderAPITest::test_uniform_size_type(void)
+{
+ test_uniform_size_type1("float", GL_FLOAT, "");
+ test_uniform_size_type1("vec2", GL_FLOAT_VEC2, "[0]");
+ test_uniform_size_type1("vec3", GL_FLOAT_VEC3, "[0]");
+ test_uniform_size_type1("vec4", GL_FLOAT_VEC4, "[0]");
+
+ test_uniform_size_type1("bool", GL_BOOL, " ? 1.0 : 0.0");
+ test_uniform_size_type1("bvec2", GL_BOOL_VEC2, "[0] ? 1.0 : 0.0");
+ test_uniform_size_type1("bvec3", GL_BOOL_VEC3, "[0] ? 1.0 : 0.0");
+ test_uniform_size_type1("bvec4", GL_BOOL_VEC4, "[0] ? 1.0 : 0.0");
+
+ test_uniform_size_type1("int", GL_INT, "");
+ test_uniform_size_type1("ivec2", GL_INT_VEC2, "[0]");
+ test_uniform_size_type1("ivec3", GL_INT_VEC3, "[0]");
+ test_uniform_size_type1("ivec4", GL_INT_VEC4, "[0]");
+
+ test_uniform_size_type1("mat2", GL_FLOAT_MAT2, "[0][0]");
+ test_uniform_size_type1("mat3", GL_FLOAT_MAT3, "[0][0]");
+ test_uniform_size_type1("mat4", GL_FLOAT_MAT4, "[0][0]");
+ test_uniform_size_type1("mat2x3", GL_FLOAT_MAT2x3, "[0][0]");
+ test_uniform_size_type1("mat2x4", GL_FLOAT_MAT2x4, "[0][0]");
+ test_uniform_size_type1("mat3x2", GL_FLOAT_MAT3x2, "[0][0]");
+ test_uniform_size_type1("mat3x4", GL_FLOAT_MAT3x4, "[0][0]");
+ test_uniform_size_type1("mat4x2", GL_FLOAT_MAT4x2, "[0][0]");
+ test_uniform_size_type1("mat4x3", GL_FLOAT_MAT4x3, "[0][0]");
+}
+
+
+void
+ShaderAPITest::test_attrib_size_type1(const char *glslType, GLenum glType, const char *el)
+{
+ char buffer[1024];
+ GLuint program;
+ GLint active, i;
+ GLenum type;
+ GLint size;
+
+ //printf(" Running subtest %s\n", glslType);
+ //fflush(stdout);
+ sprintf(buffer, "#version 120\nattribute %s m;\nvoid main() { gl_Position[0] = m%s; }\n",
+ glslType, el);
+
+ program = make_program(buffer, NULL);
+ glGetProgramiv_func(program, GL_ACTIVE_ATTRIBUTES, &active);
+ assert_no_error();
+ for (i = 0; i < active; i++) {
+ size = -1;
+ type = -1;
+ glGetActiveAttrib_func(program, i, sizeof(buffer), NULL,
+ &size, &type, buffer);
+ assert_no_error();
+ if (strncmp(buffer, "m", 1) == 0)
+ break;
+ }
+ assert(i < active); /* Otherwise the compiler optimised it out */
+ assert(type == glType);
+ assert(size == 1);
+}
+
+
+void
+ShaderAPITest::test_attrib_size_type(void)
+{
+ test_attrib_size_type1("float", GL_FLOAT, "");
+ test_attrib_size_type1("vec2", GL_FLOAT_VEC2, "[0]");
+ test_attrib_size_type1("vec3", GL_FLOAT_VEC3, "[0]");
+ test_attrib_size_type1("vec4", GL_FLOAT_VEC4, "[0]");
+ test_attrib_size_type1("mat2", GL_FLOAT_MAT2, "[0][0]");
+ test_attrib_size_type1("mat3", GL_FLOAT_MAT3, "[0][0]");
+ test_attrib_size_type1("mat4", GL_FLOAT_MAT4, "[0][0]");
+ test_attrib_size_type1("mat2x3", GL_FLOAT_MAT2x3, "[0][0]");
+ test_attrib_size_type1("mat2x4", GL_FLOAT_MAT2x4, "[0][0]");
+ test_attrib_size_type1("mat3x2", GL_FLOAT_MAT3x2, "[0][0]");
+ test_attrib_size_type1("mat3x4", GL_FLOAT_MAT3x4, "[0][0]");
+ test_attrib_size_type1("mat4x2", GL_FLOAT_MAT4x2, "[0][0]");
+ test_attrib_size_type1("mat4x3", GL_FLOAT_MAT4x3, "[0][0]");
+}
+
+
+void
+ShaderAPITest::test_uniform_array_overflow(void)
+{
+ GLuint program;
+ GLint location;
+ GLfloat data[128];
+
+ program = make_program("#version 120\nuniform vec2 x[10];\nvoid main() { gl_Position.xy = x[9]; }\n", NULL);
+ location = glGetUniformLocation_func(program, "x");
+ assert_no_error();
+ glUniform2fv_func(location, 64, data);
+ assert_no_error();
+}
+
+
+void
+ShaderAPITest::test_uniform_scalar_count(void)
+{
+ GLuint program;
+ GLint location;
+ GLfloat data[128];
+
+ program = make_program("#version 110\nuniform vec2 x;\nvoid main() { gl_Position.xy = x; }\n", NULL);
+ location = glGetUniformLocation_func(program, "x");
+ assert_no_error();
+ glUniform2fv_func(location, 64, data);
+ assert_error(GL_INVALID_OPERATION);
+}
+
+
+void
+ShaderAPITest::test_uniform_query_matrix(void)
+{
+ GLuint program;
+ GLfloat data[18];
+ GLint i, r, c;
+ GLint location;
+
+ program = make_program("#version 110\nuniform mat3 m[2];\nvoid main() { gl_Position.xyz = m[1][2]; }\n", NULL);
+ location = glGetUniformLocation_func(program, "m");
+ for (i = 0; i < 9; i++)
+ data[i] = i;
+ for (i = 9; i < 18; i++)
+ data[i] = 321.0;
+ glUniformMatrix3fv_func(location, 1, GL_TRUE, data);
+
+ for (i = 0; i < 18; i++)
+ data[i] = 123.0;
+ glGetUniformfv_func(program, location, data);
+ for (c = 0; c < 3; c++)
+ for (r = 0; r < 3; r++)
+ assert(data[c * 3 + r] == r * 3 + c);
+ for (i = 9; i < 18; i++)
+ assert(data[i] == 123.0);
+}
+
+
+void
+ShaderAPITest::test_uniform_neg_location(void)
+{
+ GLuint program;
+ GLfloat data[4];
+
+ program = make_program("#version 110\nvoid main() { gl_Position = vec4(1.0, 1.0, 1.0, 1.0); }\n", NULL);
+ assert_no_error();
+ glUniform1i_func(-1, 1);
+ assert_no_error();
+ glUniform1i_func(-200, 1);
+ assert_error(GL_INVALID_OPERATION);
+ glUniformMatrix2fv_func(-1, 1, GL_FALSE, data);
+ assert_no_error();
+ glUniformMatrix2fv_func(-200, 1, GL_FALSE, data);
+ assert_error(GL_INVALID_OPERATION);
+}
+
+
+void
+ShaderAPITest::test_uniform_bool_conversion(void)
+{
+ GLuint program;
+ GLint location;
+ GLint value[16]; /* in case glGetUniformiv goes nuts on the stack */
+
+ assert_no_error();
+ program = make_program("uniform bool b;\nvoid main() { gl_Position.x = b ? 1.5 : 0.5; }\n", NULL);
+ location = glGetUniformLocation_func(program, "b");
+ assert(location != -1);
+ assert_no_error();
+ glUniform1i_func(location, 5);
+ assert_no_error();
+ glGetUniformiv_func(program, location, &value[0]);
+ assert_no_error();
+ assert(value[0] == 1);
+}
+
+
+void
+ShaderAPITest::test_uniform_multiple_samplers(void)
+{
+ GLuint program;
+ GLint location;
+ GLint values[2] = {0, 1};
+
+ assert_no_error();
+ program = make_program(NULL, "uniform sampler2D s[2];\nvoid main() { gl_FragColor = texture2D(s[1], vec2(0.0, 0.0)); }\n");
+ location = glGetUniformLocation_func(program, "s[0]");
+ assert(location != -1);
+ assert_no_error();
+ glUniform1iv_func(location, 2, values);
+ assert_no_error();
+}
+
+
+void
+ShaderAPITest::run_tests(void)
+{
+ test_uniform_size_type();
+ test_attrib_size_type();
+ test_uniform_array_overflow();
+ test_uniform_scalar_count();
+ test_uniform_query_matrix();
+ test_uniform_neg_location();
+ test_uniform_bool_conversion();
+ test_uniform_multiple_samplers();
+}
+
+
+void
+ShaderAPITest::runOne(ShaderAPIResult &r, Window &w)
+{
+ (void) w; // silence warning
+
+ // error will be set to true if any of the assert functions below fail.
+ error = false;
+
+ get_ext_procs();
+
+ run_tests();
+
+ r.pass = !error;
+}
+
+
+void
+ShaderAPITest::logOne(ShaderAPIResult &r)
+{
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ }
+ else {
+ env->log << name << "FAIL\n";
+ }
+}
+
+
+void
+ShaderAPITest::compareOne(ShaderAPIResult &oldR,
+ ShaderAPIResult &newR)
+{
+ comparePassFail(oldR, newR);
+}
+
+
+void
+ShaderAPIResult::putresults(ostream &s) const
+{
+ if (pass) {
+ s << "PASS\n";
+ }
+ else {
+ s << "FAIL\n";
+ }
+}
+
+
+bool
+ShaderAPIResult::getresults(istream &s)
+{
+ char result[1000];
+ s >> result;
+
+ if (strcmp(result, "FAIL") == 0) {
+ pass = false;
+ }
+ else {
+ pass = true;
+ }
+ return s.good();
+}
+
+
+// We need OpenGL 2.0, 2.1 or 3.0
+bool
+ShaderAPITest::isApplicable() const
+{
+ const char *version = (const char *) glGetString(GL_VERSION);
+ if (strncmp(version, "2.0", 3) == 0 ||
+ strncmp(version, "2.1", 3) == 0 ||
+ strncmp(version, "3.0", 3) == 0) {
+ return true;
+ }
+ else {
+ env->log << name
+ << ": skipped. Requires GL 2.0, 2.1 or 3.0.\n";
+ return false;
+ }
+}
+
+
+// The test object itself:
+ShaderAPITest shaderAPITest("shaderAPI", "window, rgb",
+ "", // no extensions, but see isApplicable()
+ "Test GLSL shader-related API features.\n");
+
+
+
+} // namespace GLEAN
+
+
diff --git a/tests/glean/tshaderapi.h b/tests/glean/tshaderapi.h
new file mode 100644
index 000000000..e1fc9c1db
--- /dev/null
+++ b/tests/glean/tshaderapi.h
@@ -0,0 +1,94 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2009 VMware, Inc. 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 VMWARE 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
+
+
+#ifndef __tshaderapi_h__
+#define __tshaderapi_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+#define windowSize 100
+
+
+class ShaderAPIResult: public BaseResult
+{
+public:
+ bool pass;
+
+ ShaderAPIResult();
+
+ virtual void putresults(ostream& s) const;
+ virtual bool getresults(istream& s);
+};
+
+
+class ShaderAPITest: public BaseTest<ShaderAPIResult>
+{
+public:
+ // "WHO" = width, height and one config flag
+ GLEAN_CLASS_WHO(ShaderAPITest, ShaderAPIResult,
+ windowSize, windowSize, true);
+
+ virtual bool isApplicable() const;
+
+private:
+ bool error;
+
+ void assert_test(const char *file, int line, int cond, const char *msg);
+ void assert_no_error_test(const char *file, int line);
+ void assert_error_test(const char *file, int line, GLenum expect);
+
+ void check_status(GLuint id, GLenum pname, void (*query)(GLuint, GLenum, GLint *));
+ void check_compile_status(GLuint id);
+ void check_link_status(GLuint id);
+
+ GLuint make_shader(GLenum type, const char *src);
+ GLuint make_program(const char *vs_src, const char *fs_src);
+
+ void test_uniform_size_type1(const char *glslType, GLenum glType, const char *el);
+ void test_attrib_size_type1(const char *glslType, GLenum glType, const char *el);
+
+ void test_uniform_size_type(void);
+ void test_attrib_size_type(void);
+ void test_uniform_array_overflow(void);
+ void test_uniform_scalar_count(void);
+ void test_uniform_query_matrix(void);
+ void test_uniform_neg_location(void);
+ void test_uniform_bool_conversion(void);
+ void test_uniform_multiple_samplers(void);
+ void run_tests(void);
+
+ void get_ext_procs(void);
+};
+
+} // namespace GLEAN
+
+#endif // __tshaderapi_h__
+
diff --git a/tests/glean/tstencil2.cpp b/tests/glean/tstencil2.cpp
new file mode 100644
index 000000000..d0c783a8f
--- /dev/null
+++ b/tests/glean/tstencil2.cpp
@@ -0,0 +1,785 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2009 VMware, Inc. 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 VMWARE 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
+
+
+// Test two-sided stencil extensions
+// Brian Paul
+// 19 Feb 2009
+
+
+// This test could be better:
+// 1. Generate random state vectors, render and compare to expected values
+// 2. Exercise separate front/back reference values and masks for the
+// EXT and GL2 variations.
+
+
+
+#include <cassert>
+#include <cstring>
+#include "tstencil2.h"
+
+
+namespace GLEAN {
+
+// ATI
+static PFNGLSTENCILOPSEPARATEATIPROC glStencilOpSeparateATI_func;
+static PFNGLSTENCILFUNCSEPARATEATIPROC glStencilFuncSeparateATI_func;
+
+// EXT
+static PFNGLACTIVESTENCILFACEEXTPROC glActiveStencilFaceEXT_func;
+
+// GL2
+static PFNGLSTENCILOPSEPARATEPROC glStencilOpSeparate_func;
+static PFNGLSTENCILFUNCSEPARATEPROC glStencilFuncSeparate_func;
+static PFNGLSTENCILMASKSEPARATEPROC glStencilMaskSeparate_func;
+
+
+// two-sided methods:
+#define ATI 1
+#define EXT 2
+#define GL2 3
+
+
+Stencil2Result::Stencil2Result()
+{
+ pass = false;
+}
+
+
+void
+Stencil2Test::get_ext_functions(void)
+{
+ // ATI
+ glStencilOpSeparateATI_func = (PFNGLSTENCILOPSEPARATEATIPROC)
+ GLUtils::getProcAddress("glStencilOpSeparateATI");
+ glStencilFuncSeparateATI_func = (PFNGLSTENCILFUNCSEPARATEATIPROC)
+ GLUtils::getProcAddress("glStencilFuncSeparateATI");
+
+ // EXT
+ glActiveStencilFaceEXT_func = (PFNGLACTIVESTENCILFACEEXTPROC)
+ GLUtils::getProcAddress("glActiveStencilFaceEXT");
+
+ // GL2
+ glStencilOpSeparate_func = (PFNGLSTENCILOPSEPARATEPROC)
+ GLUtils::getProcAddress("glStencilOpSeparate");
+
+ glStencilFuncSeparate_func = (PFNGLSTENCILFUNCSEPARATEPROC)
+ GLUtils::getProcAddress("glStencilFuncSeparate");
+
+ glStencilMaskSeparate_func= (PFNGLSTENCILMASKSEPARATEPROC)
+ GLUtils::getProcAddress("glStencilMaskSeparate");
+}
+
+
+bool
+Stencil2Test::have_ATI_separate_stencil(void) const
+{
+ return GLUtils::haveExtension("GL_ATI_separate_stencil");
+}
+
+bool
+Stencil2Test::have_EXT_stencil_two_side(void) const
+{
+ return GLUtils::haveExtension("GL_EXT_stencil_two_side");
+}
+
+bool
+Stencil2Test::have_GL2_stencil_two_side(void) const
+{
+ const char *version = (const char *) glGetString(GL_VERSION);
+ if (strncmp(version, "2.", 2) == 0 ||
+ strncmp(version, "3.0", 3) == 0) {
+ return true;
+ }
+ return false;
+}
+
+bool
+Stencil2Test::have_stencil_wrap(void) const
+{
+ const char *version = (const char *) glGetString(GL_VERSION);
+ if (strncmp(version, "2.", 2) == 0 ||
+ strncmp(version, "3.0", 3) == 0) {
+ return true;
+ }
+ else if (GLUtils::haveExtension("GL_EXT_stencil_wrap")) {
+ return true;
+ }
+ return false;
+}
+
+
+// Draw four quads:
+// Bottom row uses GL_CCW
+// Top row uses GL_CW
+// Left column is front-facing
+// Right column is back-facing
+// Check the values in the stencil buffer to see if they match
+// the expected values.
+bool
+Stencil2Test::render_test(GLuint expectedFront, GLuint expectedBack)
+{
+ GLint x0 = 0;
+ GLint x1 = windowSize / 2;
+ GLint x2 = windowSize;
+ GLint y0 = 0;
+ GLint y1 = windowSize / 2;
+ GLint y2 = windowSize;
+
+ glFrontFace(GL_CCW); // this the GL default
+
+ // lower left quad = front-facing
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(x0, y0);
+ glVertex2f(x1, y0);
+ glVertex2f(x1, y1);
+ glVertex2f(x0, y1);
+ glEnd();
+
+ // lower right quad = back-facing
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(x1, y0);
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y1);
+ glVertex2f(x2, y0);
+ glEnd();
+
+ glFrontFace(GL_CW);
+
+ // upper left quad = front-facing
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(x0, y1);
+ glVertex2f(x0, y2);
+ glVertex2f(x1, y2);
+ glVertex2f(x1, y1);
+ glEnd();
+
+ // upper right quad = back-facing
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y1);
+ glVertex2f(x2, y2);
+ glVertex2f(x1, y2);
+ glEnd();
+
+ GLint midXleft = (x0 + x1) / 2;
+ GLint midXright = (x1 + x2) / 2;
+ GLint midYlower = (y0 + y1) / 2;
+ GLint midYupper = (y1 + y2) / 2;
+ GLuint lowerLeftVal, lowerRightVal;
+ GLuint upperLeftVal, upperRightVal;
+
+ glReadPixels(midXleft, midYlower, 1, 1,
+ GL_STENCIL_INDEX, GL_UNSIGNED_INT, &lowerLeftVal);
+ glReadPixels(midXright, midYlower, 1, 1,
+ GL_STENCIL_INDEX, GL_UNSIGNED_INT, &lowerRightVal);
+
+ glReadPixels(midXleft, midYupper, 1, 1,
+ GL_STENCIL_INDEX, GL_UNSIGNED_INT, &upperLeftVal);
+ glReadPixels(midXright, midYupper, 1, 1,
+ GL_STENCIL_INDEX, GL_UNSIGNED_INT, &upperRightVal);
+
+ if (lowerLeftVal != upperLeftVal) {
+ env->log << "FAIL:\n";
+ env->log << "\tLower-left value (" << lowerLeftVal
+ << ") doesn't match upper-left value ("
+ << upperLeftVal
+ << ").\n";
+ env->log << "\tLooks like a front/back-face orientation bug.\n";
+ return false;
+ }
+
+ if (lowerRightVal != upperRightVal) {
+ env->log << "FAIL:\n";
+ env->log << "\tLower-right value (" << lowerRightVal
+ << ") doesn't match upper-right value ("
+ << upperRightVal
+ << ").\n";
+ env->log << "\tLooks like a front/back-face orientation bug.\n";
+ return false;
+ }
+
+
+ if (lowerLeftVal != expectedFront) {
+ env->log << "FAIL:\n";
+ env->log << "\tExpected front-face stencil value is "
+ << expectedFront
+ << " but found " << lowerLeftVal << "\n";
+ return false;
+ }
+ else if (lowerRightVal != expectedBack) {
+ env->log << "FAIL:\n";
+ env->log << "\tExpected back-face stencil value is " << expectedBack
+ << " but found " << lowerRightVal << "\n";
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+
+bool
+Stencil2Test::compare_state(int method, GLenum found, GLenum expected,
+ const char *msg)
+{
+ if (found != expected) {
+ env->log << "FAIL:\n";
+ env->log << "\tQuery of " << msg << " state failed for ";
+ switch (method) {
+ case ATI:
+ env->log << "GL_ATI_separate_stencil";
+ break;
+ case EXT:
+ env->log << "GL_EXT_stencil_two_side";
+ break;
+ case GL2:
+ env->log << "GL 2.x two-sided stencil";
+ break;
+ default:
+ assert(0);
+ }
+ env->log << "\n";
+ char s[1000];
+ sprintf(s, "\tFound 0x%x, expected 0x%x\n", found, expected);
+ env->log << s;
+ return false;
+ }
+ return true;
+}
+
+
+// Set stencil state, plus read it back and check that it's correct.
+// Note: we only test with one reference value and one mask value
+// even though EXT and GL2 support separate front/back refs/masks
+bool
+Stencil2Test::set_stencil_state(int method,
+ GLenum frontStencilFail,
+ GLenum backStencilFail,
+ GLenum frontZFail,
+ GLenum backZFail,
+ GLenum frontZPass,
+ GLenum backZPass,
+ GLenum frontFunc,
+ GLenum backFunc,
+ GLint ref,
+ GLuint mask)
+{
+ GLint get_frontStencilFail;
+ GLint get_backStencilFail;
+ GLint get_frontZFail;
+ GLint get_backZFail;
+ GLint get_frontZPass;
+ GLint get_backZPass;
+ GLint get_frontFunc;
+ GLint get_backFunc;
+ GLint get_ref;
+ GLint get_mask;
+ GLint twoEnabled;
+
+ switch (method) {
+ case ATI:
+ // set state
+ glStencilOpSeparateATI_func(GL_FRONT,
+ frontStencilFail,
+ frontZFail,
+ frontZPass);
+
+ glStencilOpSeparateATI_func(GL_BACK,
+ backStencilFail,
+ backZFail,
+ backZPass);
+
+ glStencilFuncSeparateATI_func(frontFunc, backFunc, ref, mask);
+
+ // get state
+ glGetIntegerv(GL_STENCIL_FAIL, &get_frontStencilFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &get_frontZFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &get_frontZPass);
+ glGetIntegerv(GL_STENCIL_FUNC, &get_frontFunc);
+ glGetIntegerv(GL_STENCIL_REF, &get_ref);
+ glGetIntegerv(GL_STENCIL_VALUE_MASK, &get_mask);
+
+ glGetIntegerv(GL_STENCIL_BACK_FUNC_ATI, &get_backFunc);
+ glGetIntegerv(GL_STENCIL_BACK_FAIL_ATI, &get_backStencilFail);
+ glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI, &get_backZFail);
+ glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI, &get_backZPass);
+ twoEnabled = GL_TRUE;
+ break;
+
+ case EXT:
+ // set state
+ glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+
+ glActiveStencilFaceEXT_func(GL_FRONT);
+ glStencilOp(frontStencilFail, frontZFail, frontZPass);
+ glStencilFunc(frontFunc, ref, mask);
+
+ glActiveStencilFaceEXT_func(GL_BACK);
+ glStencilOp(backStencilFail, backZFail, backZPass);
+ glStencilFunc(backFunc, ref, mask);
+
+ // get state
+ glActiveStencilFaceEXT_func(GL_FRONT);
+ glGetIntegerv(GL_STENCIL_FAIL, &get_frontStencilFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &get_frontZFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &get_frontZPass);
+ glGetIntegerv(GL_STENCIL_FUNC, &get_frontFunc);
+ glGetIntegerv(GL_STENCIL_REF, &get_ref);
+ glGetIntegerv(GL_STENCIL_VALUE_MASK, &get_mask);
+ glActiveStencilFaceEXT_func(GL_BACK);
+ glGetIntegerv(GL_STENCIL_FAIL, &get_backStencilFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &get_backZFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &get_backZPass);
+ glGetIntegerv(GL_STENCIL_FUNC, &get_backFunc);
+ glGetIntegerv(GL_STENCIL_REF, &get_ref);
+ glGetIntegerv(GL_STENCIL_VALUE_MASK, &get_mask);
+ glGetIntegerv(GL_STENCIL_TEST_TWO_SIDE_EXT, &twoEnabled);
+ break;
+
+ case GL2:
+ // set state
+ glStencilOpSeparate_func(GL_FRONT,
+ frontStencilFail,
+ frontZFail,
+ frontZPass);
+ glStencilOpSeparate_func(GL_BACK,
+ backStencilFail,
+ backZFail,
+ backZPass);
+ glStencilFuncSeparate_func(GL_FRONT, frontFunc, ref, mask);
+ glStencilFuncSeparate_func(GL_BACK, backFunc, ref, mask);
+
+ // get state
+ glGetIntegerv(GL_STENCIL_FAIL, &get_frontStencilFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &get_frontZFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &get_frontZPass);
+ glGetIntegerv(GL_STENCIL_FUNC, &get_frontFunc);
+ glGetIntegerv(GL_STENCIL_REF, &get_ref);
+ glGetIntegerv(GL_STENCIL_VALUE_MASK, &get_mask);
+
+ glGetIntegerv(GL_STENCIL_BACK_FUNC, &get_backFunc);
+ glGetIntegerv(GL_STENCIL_BACK_FAIL, &get_backStencilFail);
+ glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL, &get_backZFail);
+ glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &get_backZPass);
+ twoEnabled = GL_TRUE;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ // mask off bits we don't care about
+ get_mask &= stencilMax;
+ mask &= stencilMax;
+
+ GLenum err = glGetError();
+ if (err != GL_NO_ERROR) {
+ env->log << "FAIL:\n";
+ env->log << "\tGL error " << err << " detected.\n";
+ return false;
+ }
+
+ // see if state-get matches state-set
+
+ if (!compare_state(method, get_frontStencilFail, frontStencilFail,
+ "front stencil fail"))
+ return false;
+
+ if (!compare_state(method, get_backStencilFail, backStencilFail,
+ "back stencil fail"))
+ return false;
+
+ if (!compare_state(method, get_frontZFail, frontZFail,
+ "front Z fail"))
+ return false;
+
+ if (!compare_state(method, get_backZFail, backZFail,
+ "back Z fail"))
+ return false;
+
+ if (!compare_state(method, get_frontZPass, frontZPass,
+ "front Z pass"))
+ return false;
+
+ if (!compare_state(method, get_backZPass, backZPass,
+ "back Z pass"))
+ return false;
+
+ if (!compare_state(method, get_frontFunc, frontFunc,
+ "front stencil func"))
+ return false;
+
+ if (!compare_state(method, get_backFunc, backFunc,
+ "back stencil func"))
+ return false;
+
+ if (!compare_state(method, get_ref, ref, "stencil ref"))
+ return false;
+
+ if (!compare_state(method, get_mask, mask, "stencil mask"))
+ return false;
+
+ if (!compare_state(method, twoEnabled, GL_TRUE, "two-side enable"))
+ return false;
+
+ return true;
+}
+
+
+void
+Stencil2Test::reset_stencil_state(int method)
+{
+ switch (method) {
+ case ATI:
+ break;
+ case EXT:
+ glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+ glActiveStencilFaceEXT_func(GL_FRONT);
+ break;
+ case GL2:
+ break;
+ default:
+ assert(0);
+ }
+}
+
+
+bool
+Stencil2Test::test_stencil(int method)
+{
+ bool pass;
+
+ glEnable(GL_STENCIL_TEST);
+
+ //============================================================
+ // No depth testing
+ glDisable(GL_DEPTH_TEST);
+
+ glClear(GL_COLOR_BUFFER_BIT |
+ GL_STENCIL_BUFFER_BIT |
+ GL_DEPTH_BUFFER_BIT);
+
+
+ // set stencil buffer vals to 5
+ pass = set_stencil_state(method,
+ GL_KEEP, GL_KEEP, // stencil fail
+ GL_KEEP, GL_KEEP, // z fail
+ GL_REPLACE, GL_REPLACE, // z pass
+ GL_ALWAYS, GL_ALWAYS, // stencil func
+ 5, ~0); // ref, mask
+ if (pass)
+ pass = render_test(5, 5);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+ // incr front val to 6, decr back val to 4
+ pass = set_stencil_state(method,
+ GL_KEEP, GL_KEEP, // stencil fail
+ GL_KEEP, GL_KEEP, // z fail
+ GL_INCR, GL_DECR, // z pass
+ GL_ALWAYS, GL_ALWAYS, // stencil func
+ 5, ~0); // ref, mask
+ if (pass)
+ pass = render_test(6, 4);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+ // if front==6, keep
+ // if back<6, replace with zero
+ // final: front=6, back=0
+ pass = set_stencil_state(method,
+ GL_KEEP, GL_ZERO, // stencil fail
+ GL_KEEP, GL_KEEP, // z fail
+ GL_KEEP, GL_KEEP, // z pass
+ GL_EQUAL, GL_LESS, // stencil func
+ 6, ~0); // ref, mask
+ if (pass)
+ pass = render_test(6, 0);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+ // if front!=10, keep, else decr
+ // if back<10, keep, else incr
+ // final: front=6, back=1
+ pass = set_stencil_state(method,
+ GL_DECR, GL_INCR, // stencil fail
+ GL_KEEP, GL_KEEP, // z fail
+ GL_KEEP, GL_KEEP, // z pass
+ GL_NOTEQUAL, GL_LESS, // stencil func
+ 10, ~0); // ref, mask
+ if (pass)
+ pass = render_test(6, 1);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ //============================================================
+ // Now begin tests with depth test
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+
+ glClear(GL_COLOR_BUFFER_BIT |
+ GL_STENCIL_BUFFER_BIT |
+ GL_DEPTH_BUFFER_BIT);
+
+ // set stencil buffer vals to 7, set Z values
+ pass = set_stencil_state(method,
+ GL_KEEP, GL_KEEP, // stencil fail
+ GL_KEEP, GL_KEEP, // z fail
+ GL_REPLACE, GL_REPLACE, // z pass
+ GL_ALWAYS, GL_ALWAYS, // stencil func
+ 7, ~0); // ref, mask
+ if (pass)
+ pass = render_test(7, 7);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ // GL_LESS test should fail everywhere
+ // decr front to 5, incr back to 2
+ pass = set_stencil_state(method,
+ GL_KEEP, GL_KEEP, // stencil fail
+ GL_DECR, GL_INCR, // z fail
+ GL_KEEP, GL_KEEP, // z pass
+ GL_ALWAYS, GL_ALWAYS, // stencil func
+ 99, ~0); // ref, mask
+ if (pass)
+ pass = render_test(6, 8);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ // set depth test = GL_EQUAL
+ // Z test should pass everywhere
+ // set front to 3
+ // decr back to 7
+ glDepthFunc(GL_EQUAL);
+ pass = set_stencil_state(method,
+ GL_KEEP, GL_KEEP, // stencil fail
+ GL_KEEP, GL_KEEP, // z fail
+ GL_REPLACE, GL_DECR, // z pass
+ GL_ALWAYS, GL_ALWAYS, // stencil func
+ 3, ~0); // ref, mask
+ if (pass)
+ pass = render_test(3, 7);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ // incr front to 4 (by z pass), decr back to 6 (by stencil fail)
+ pass = set_stencil_state(method,
+ GL_DECR, GL_INCR, // stencil fail
+ GL_KEEP, GL_KEEP, // z fail
+ GL_INCR, GL_DECR, // z pass
+ GL_EQUAL, GL_NOTEQUAL, // stencil func
+ 3, ~0); // ref, mask
+ if (pass)
+ pass = render_test(4, 6);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ //============================================================
+ // Disable depth test
+ glDisable(GL_DEPTH_TEST);
+
+ // test stencil value mask
+ // only test bit 1 in stencil values
+ // if !(front&0x2 == 15&0x2), decr to 3 (should happen)
+ // if !(back&0x2 == 15&0x2), incr to 7 (should not happen)
+ pass = set_stencil_state(method,
+ GL_DECR, GL_INCR, // stencil fail
+ GL_KEEP, GL_KEEP, // z fail
+ GL_KEEP, GL_KEEP, // z pass
+ GL_EQUAL, GL_EQUAL, // stencil func
+ 15, 0x2); // ref, mask
+ if (pass)
+ pass = render_test(3, 6);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ //============================================================
+ // Test common two-sided stencil modes for shadow volume rendering
+ // Requires stencil +/- wrap feature.
+
+ if (!have_stencil_wrap())
+ return true;
+
+ glClear(GL_COLOR_BUFFER_BIT |
+ GL_STENCIL_BUFFER_BIT |
+ GL_DEPTH_BUFFER_BIT);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+
+ // "traditional / Z-pass" method:
+ // front face: incr on zpass
+ // back face: decr on zpass
+ // both front and back Z-test should pass here
+ pass = set_stencil_state(method,
+ GL_KEEP, GL_KEEP, // stencil fail
+ GL_KEEP, GL_KEEP, // z fail
+ GL_INCR_WRAP_EXT, GL_DECR_WRAP_EXT, // z pass
+ GL_ALWAYS, GL_ALWAYS, // stencil func
+ 0, ~0); // ref, mask
+ if (pass)
+ pass = render_test(1, stencilMax);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ // "Z-fail" method:
+ // front face: decr on zfail
+ // back face: incr on zfail
+ // both front and back Z-test should fail here
+ pass = set_stencil_state(method,
+ GL_KEEP, GL_KEEP, // stencil fail
+ GL_DECR_WRAP_EXT, GL_INCR_WRAP_EXT, // z fail
+ GL_KEEP, GL_KEEP, // z pass
+ GL_ALWAYS, GL_ALWAYS, // stencil func
+ 0, ~0); // ref, mask
+ if (pass)
+ pass = render_test(0, 0);
+ reset_stencil_state(method);
+ if (!pass)
+ return false;
+
+
+ return true;
+}
+
+
+void
+Stencil2Test::runOne(Stencil2Result &r, Window &w)
+{
+ (void) w; // silence warning
+ r.pass = true;
+
+ get_ext_functions();
+
+ // how many stencil bits (we assume at least 8 above)
+ glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
+ stencilMax = (1 << stencilBits) - 1;
+ assert(stencilBits >= 8);
+
+ glViewport(0, 0, windowSize, windowSize);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, windowSize, 0, windowSize, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ if (have_ATI_separate_stencil()) {
+ r.pass &= test_stencil(ATI);
+ }
+
+ if (have_EXT_stencil_two_side()) {
+ r.pass &= test_stencil(EXT);
+ }
+
+ if (have_GL2_stencil_two_side()) {
+ r.pass &= test_stencil(GL2);
+ }
+}
+
+
+void
+Stencil2Test::logOne(Stencil2Result &r)
+{
+ logPassFail(r);
+ logConcise(r);
+}
+
+
+void
+Stencil2Test::compareOne(Stencil2Result &oldR,
+ Stencil2Result &stencil2R)
+{
+ comparePassFail(oldR, stencil2R);
+}
+
+
+void
+Stencil2Result::putresults(ostream &s) const
+{
+ if (pass) {
+ s << "PASS\n";
+ }
+ else {
+ s << "FAIL\n";
+ }
+}
+
+
+bool
+Stencil2Result::getresults(istream &s)
+{
+ char result[1000];
+ s >> result;
+
+ if (strcmp(result, "FAIL") == 0) {
+ pass = false;
+ }
+ else {
+ pass = true;
+ }
+ return s.good();
+}
+
+
+bool
+Stencil2Test::isApplicable() const
+{
+ return (have_ATI_separate_stencil() ||
+ have_EXT_stencil_two_side() ||
+ have_EXT_stencil_two_side());
+}
+
+
+
+// The test object itself:
+Stencil2Test stencil2Test("stencil2",
+ "window, rgb, s, z", // we need stencil and Z
+ "", // no extension filter, but see isApplicable()
+ "Test two-sided stencil features\n");
+
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tstencil2.h b/tests/glean/tstencil2.h
new file mode 100644
index 000000000..8c332cda2
--- /dev/null
+++ b/tests/glean/tstencil2.h
@@ -0,0 +1,95 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2009 VMware, Inc. 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 VMWARE 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
+
+// tstencil2.h: Test two-sided stencil features
+
+#ifndef __tstencil2_h__
+#define __tstencil2_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+#define windowSize 100
+
+class Stencil2Result: public BaseResult
+{
+public:
+ bool pass;
+
+ Stencil2Result();
+
+ virtual void putresults(ostream& s) const;
+ virtual bool getresults(istream& s);
+};
+
+
+class Stencil2Test: public BaseTest<Stencil2Result>
+{
+public:
+ GLEAN_CLASS_WH(Stencil2Test, Stencil2Result,
+ windowSize, windowSize);
+
+ bool isApplicable() const;
+
+private:
+ GLint stencilBits, stencilMax;
+
+ void get_ext_functions();
+
+ bool have_ATI_separate_stencil(void) const;
+ bool have_EXT_stencil_two_side(void) const;
+ bool have_GL2_stencil_two_side(void) const;
+ bool have_stencil_wrap(void) const;
+
+ bool render_test(GLuint expectedFront, GLuint expectedBack);
+
+ bool compare_state(int method, GLenum found, GLenum expected, const char *msg);
+
+ bool set_stencil_state(int method,
+ GLenum frontStencilFail,
+ GLenum backStencilFail,
+ GLenum frontZFail,
+ GLenum backZFail,
+ GLenum frontZPass,
+ GLenum backZPass,
+ GLenum frontFunc,
+ GLenum backFunc,
+ GLint ref,
+ GLuint mask);
+
+ void reset_stencil_state(int method);
+
+ bool test_stencil(GLint method);
+
+};
+
+} // namespace GLEAN
+
+#endif // __tstencil2_h__
+
diff --git a/tests/glean/ttexcombine4.cpp b/tests/glean/ttexcombine4.cpp
new file mode 100644
index 000000000..1173d523c
--- /dev/null
+++ b/tests/glean/ttexcombine4.cpp
@@ -0,0 +1,424 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2009 VMware, Inc. 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 VMWARE 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
+
+
+// Test GL_NV_texture_env_combine4
+// Generate some random combiner state and colors, compute the expected
+// color, then render with the combiner state and compare the results.
+// Only one texture unit is tested and not all possible combiner terms
+// are exercised.
+//
+// Brian Paul
+// 23 Jan 2009
+
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <cassert>
+#include <cmath>
+#include <cstring>
+#include "ttexcombine4.h"
+#include "timer.h"
+
+
+namespace GLEAN {
+
+TexCombine4Result::TexCombine4Result()
+{
+ pass = true;
+}
+
+
+// generate random combiner state
+void
+TexCombine4Test::generate_state(struct combine_state &state)
+{
+ int i;
+
+ if (rand.next() > 0.5f)
+ state.CombineMode = GL_ADD;
+ else
+ state.CombineMode = GL_ADD_SIGNED_EXT;
+
+ for (i = 0; i < 4; i++) {
+ int src = int(rand.next() * 4.0);
+ switch (src) {
+ case 0:
+ state.Source[i] = GL_ZERO;
+ break;
+ case 1:
+ state.Source[i] = GL_TEXTURE;
+ break;
+ case 2:
+ state.Source[i] = GL_CONSTANT_EXT;
+ break;
+ default:
+ state.Source[i] = GL_PRIMARY_COLOR_EXT;
+ break;
+ }
+
+ if (rand.next() > 0.5f) {
+ state.OperandRGB[i] = GL_SRC_COLOR;
+ state.OperandA[i] = GL_SRC_ALPHA;
+ }
+ else {
+ state.OperandRGB[i] = GL_ONE_MINUS_SRC_COLOR;
+ state.OperandA[i] = GL_ONE_MINUS_SRC_ALPHA;
+ }
+ }
+
+ state.PrimaryColor[0] = rand.next();
+ state.PrimaryColor[1] = rand.next();
+ state.PrimaryColor[2] = rand.next();
+ state.PrimaryColor[3] = rand.next();
+
+ state.ConstantColor[0] = rand.next();
+ state.ConstantColor[1] = rand.next();
+ state.ConstantColor[2] = rand.next();
+ state.ConstantColor[3] = rand.next();
+
+ state.TextureColor[0] = rand.next();
+ state.TextureColor[1] = rand.next();
+ state.TextureColor[2] = rand.next();
+ state.TextureColor[3] = rand.next();
+}
+
+
+// compute expected final color
+void
+TexCombine4Test::evaluate_state(const struct combine_state &state,
+ GLfloat result[4])
+{
+ GLfloat arg[4][4];
+ int i;
+
+ // setup terms
+ for (i = 0; i < 4; i++) {
+ switch (state.Source[i]) {
+ case GL_ZERO:
+ arg[i][0] = arg[i][1] = arg[i][2] = arg[i][3] = 0.0f;
+ break;
+ case GL_PRIMARY_COLOR_EXT:
+ arg[i][0] = state.PrimaryColor[0];
+ arg[i][1] = state.PrimaryColor[1];
+ arg[i][2] = state.PrimaryColor[2];
+ arg[i][3] = state.PrimaryColor[3];
+ break;
+ case GL_CONSTANT_EXT:
+ arg[i][0] = state.ConstantColor[0];
+ arg[i][1] = state.ConstantColor[1];
+ arg[i][2] = state.ConstantColor[2];
+ arg[i][3] = state.ConstantColor[3];
+ break;
+ case GL_TEXTURE:
+ arg[i][0] = state.TextureColor[0];
+ arg[i][1] = state.TextureColor[1];
+ arg[i][2] = state.TextureColor[2];
+ arg[i][3] = state.TextureColor[3];
+ break;
+ default:
+ assert(0);
+ }
+
+ switch (state.OperandRGB[i]) {
+ case GL_SRC_COLOR:
+ // nop
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ arg[i][0] = 1.0f - arg[i][0];
+ arg[i][1] = 1.0f - arg[i][1];
+ arg[i][2] = 1.0f - arg[i][2];
+ arg[i][3] = 1.0f - arg[i][3];
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ // combine terms, loop over color channels
+ for (i = 0; i < 4; i++) {
+ result[i] = arg[0][i] * arg[1][i] + arg[2][i] * arg[3][i];
+ if (state.CombineMode == GL_ADD_SIGNED_EXT)
+ result[i] -= 0.5f;
+ if (result[i] < 0.0f)
+ result[i] = 0.0f;
+ else if (result[i] > 1.0f)
+ result[i] = 1.0f;
+ }
+}
+
+
+// render quad with given combiner state and return resulting color
+// return false if GL error is detected, true otherwise.
+bool
+TexCombine4Test::render_state(const struct combine_state &state,
+ GLfloat result[4])
+{
+ if (glGetError()) {
+ reportError("GL error detected before setting combiner state.");
+ return false;
+ }
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, state.CombineMode);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, state.CombineMode);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, state.Source[0]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, state.Source[0]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, state.Source[1]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, state.Source[1]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, state.Source[2]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, state.Source[2]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, state.Source[3]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, state.Source[3]);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, state.OperandRGB[0]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, state.OperandA[0]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, state.OperandRGB[1]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, state.OperandA[1]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, state.OperandRGB[2]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, state.OperandA[2]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, state.OperandRGB[3]);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, state.OperandA[3]);
+
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, state.ConstantColor);
+
+ if (glGetError()) {
+ reportError("GL error generated by combiner state.");
+ return false;
+ }
+
+ glEnable(GL_TEXTURE_2D);
+ 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_RGBA, 1, 1, 0,
+ GL_RGBA, GL_FLOAT, state.TextureColor);
+
+ glColor4fv(state.PrimaryColor);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0.0, 0.0);
+ glVertex2f(-1.0, -1.0);
+ glTexCoord2f(1.0, 0.0);
+ glVertex2f(1.0, -1.0);
+ glTexCoord2f(1.0, 1.0);
+ glVertex2f( 1.0, 1.0);
+ glTexCoord2f(0.0, 1.0);
+ glVertex2f(-1.0, 1.0);
+ glEnd();
+
+ glReadPixels(WINDOW_SIZE / 2, WINDOW_SIZE / 2, 1, 1,
+ GL_RGBA, GL_FLOAT, result);
+
+ return true;
+}
+
+
+void
+TexCombine4Test::report_state(const struct combine_state &state)
+{
+ env->log << "\tCurrent GL state:\n";
+
+ if (state.CombineMode == GL_ADD)
+ env->log << "\t\tCOMBINE = GL_ADD\n";
+ else
+ env->log << "\t\tCOMBINE = GL_ADD_SIGNED_EXT\n";
+
+ for (int i = 0; i < 4; i++) {
+ env->log << "\t\t" << "SOURCE" << i << ": ";
+ switch (state.Source[i]) {
+ case GL_ZERO:
+ env->log << "GL_ZERO\n";
+ break;
+ case GL_TEXTURE:
+ env->log << "GL_TEXTURE\n";
+ break;
+ case GL_CONSTANT_EXT:
+ env->log << "GL_CONSTANT\n";
+ break;
+ case GL_PRIMARY_COLOR_EXT:
+ env->log << "GL_PRIMARY_COLOR\n";
+ break;
+ default:
+ assert(0);
+ }
+
+ env->log << "\t\t" << "OPERAND" << i << "_RGB: ";
+ switch (state.OperandRGB[i]) {
+ case GL_SRC_COLOR:
+ env->log << "GL_SRC_COLOR\n";
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ env->log << "GL_ONE_MINUS_SRC_COLOR\n";
+ break;
+ default:
+ assert(0);
+ }
+
+ env->log << "\t\t" << "OPERAND" << i << "_ALPHA: ";
+ switch (state.OperandRGB[i]) {
+ case GL_SRC_COLOR:
+ env->log << "GL_SRC_ALPHA\n";
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ env->log << "GL_ONE_MINUS_SRC_ALPHA\n";
+ break;
+ default:
+ assert(0);
+ }
+
+ }
+
+ char str[100];
+ sprintf(str, "%.3f, %.3f, %.3f, %.3f",
+ state.PrimaryColor[0], state.PrimaryColor[1],
+ state.PrimaryColor[2], state.PrimaryColor[3]);
+ env->log << "\t\tPrimary Color: " << str << "\n";
+ sprintf(str, "%.3f, %.3f, %.3f, %.3f",
+ state.ConstantColor[0], state.ConstantColor[1],
+ state.ConstantColor[2], state.ConstantColor[3]);
+ env->log << "\t\tConstant Color: " << str << "\n";
+ sprintf(str, "%.3f, %.3f, %.3f, %.3f",
+ state.TextureColor[0], state.TextureColor[1],
+ state.TextureColor[2], state.TextureColor[3]);
+ env->log << "\t\tTexture Color: " << str << "\n";
+}
+
+
+void
+TexCombine4Test::reportError(const char *msg)
+{
+ env->log << name << ": Error: " << msg << "\n";
+}
+
+
+void
+TexCombine4Test::runOne(TexCombine4Result &r, Window &w)
+{
+ (void) w; // silence warning
+
+ rand = RandomDouble(42); // init random number generator
+
+ const float err = 0.05; // xxx compute something better
+
+ for (int i = 0; i < NUM_TESTS; i++) {
+ combine_state state;
+ GLfloat expected[4], actual[4];
+
+ //env->log << "\t iteration " << i << "\n";
+
+ generate_state(state);
+
+ evaluate_state(state, expected);
+
+ if (!render_state(state, actual)) {
+ r.pass = false;
+ return;
+ }
+
+ if (fabs(expected[0] - actual[0]) > err ||
+ fabs(expected[1] - actual[1]) > err ||
+ fabs(expected[2] - actual[2]) > err) {
+ char str[100];
+ env->log << name << ": Error: GL_NV_texure_env_combine4 failed\n";
+ report_state(state);
+ env->log << "\tResults:\n";
+ sprintf(str, "%.3f, %.3f, %.3f, %.3f",
+ expected[0], expected[1],
+ expected[2], expected[3]);
+ env->log << "\t\tExpected color: " << str << "\n";
+ sprintf(str, "%.3f, %.3f, %.3f, %.3f",
+ actual[0], actual[1],
+ actual[2], actual[3]);
+ env->log << "\t\tRendered color: " << str << "\n";
+ r.pass = false;
+ return;
+ }
+ }
+
+ r.pass = true;
+}
+
+
+void
+TexCombine4Test::logOne(TexCombine4Result &r)
+{
+ logPassFail(r);
+ logConcise(r);
+}
+
+
+void
+TexCombine4Test::compareOne(TexCombine4Result &oldR,
+ TexCombine4Result &newR)
+{
+ comparePassFail(oldR, newR);
+}
+
+
+void
+TexCombine4Result::putresults(ostream &s) const
+{
+ if (pass) {
+ s << "PASS\n";
+ }
+ else {
+ s << "FAIL\n";
+ }
+}
+
+
+bool
+TexCombine4Result::getresults(istream &s)
+{
+ char result[1000];
+ s >> result;
+
+ if (strcmp(result, "FAIL") == 0) {
+ pass = false;
+ }
+ else {
+ pass = true;
+ }
+ return s.good();
+}
+
+
+// The test object itself:
+TexCombine4Test texCombine4Test("texCombine4", "window, rgb",
+ "GL_NV_texture_env_combine4, GL_EXT_texture_env_combine",
+ "Test the GL_NV_texture_env_combine4 extension.\n");
+
+
+
+} // namespace GLEAN
+
+
diff --git a/tests/glean/ttexcombine4.h b/tests/glean/ttexcombine4.h
new file mode 100644
index 000000000..f6d323ee6
--- /dev/null
+++ b/tests/glean/ttexcombine4.h
@@ -0,0 +1,88 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2009 VMware, Inc. 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 VMWARE 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
+
+// ttexcombine4.h: Test GL_NV_texture_env_combine4
+
+#ifndef __ttexcombine4_h__
+#define __ttexcombine4_h__
+
+#include "tbase.h"
+#include "rand.h"
+
+
+namespace GLEAN {
+
+#define NUM_POINTS 1000
+#define WINDOW_SIZE 100
+#define NUM_TESTS 200
+
+
+class TexCombine4Result: public BaseResult
+{
+public:
+ TexCombine4Result();
+
+ virtual void putresults(ostream& s) const;
+ virtual bool getresults(istream& s);
+
+ bool pass;
+};
+
+
+class TexCombine4Test: public BaseTest<TexCombine4Result>
+{
+public:
+ GLEAN_CLASS_WH(TexCombine4Test, TexCombine4Result,
+ WINDOW_SIZE, WINDOW_SIZE);
+
+private:
+ struct combine_state
+ {
+ GLenum CombineMode;
+ GLenum Source[4];
+ GLenum OperandRGB[4];
+ GLenum OperandA[4];
+ GLfloat PrimaryColor[4];
+ GLfloat ConstantColor[4];
+ GLfloat TextureColor[4];
+ };
+
+ RandomDouble rand;
+
+ void generate_state(struct combine_state &state);
+ void evaluate_state(const struct combine_state &state, GLfloat result[4]);
+ bool render_state(const struct combine_state &state, GLfloat result[4]);
+ void report_state(const struct combine_state &state);
+
+ void reportError(const char *msg);
+};
+
+} // namespace GLEAN
+
+#endif // __ttexcombine4_h__
+
diff --git a/tests/glean/ttexenv.cpp b/tests/glean/ttexenv.cpp
index 223f53cfb..6a8f8d886 100644
--- a/tests/glean/ttexenv.cpp
+++ b/tests/glean/ttexenv.cpp
@@ -40,10 +40,12 @@
// post-texture alpha value is correct.
//
-#include "ttexenv.h"
+#include <stdlib.h>
#include <cassert>
#include <stdio.h>
#include <cmath>
+#include "ttexenv.h"
+
namespace GLEAN {
diff --git a/tests/glean/ttexswizzle.cpp b/tests/glean/ttexswizzle.cpp
new file mode 100644
index 000000000..6bd1304a9
--- /dev/null
+++ b/tests/glean/ttexswizzle.cpp
@@ -0,0 +1,456 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2009 VMware, Inc. 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 VMWARE 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
+
+
+// Test GL_EXT_texture_swizzle for all possible swizzle combinations
+// both with fixed function and a fragment program.
+// Brian Paul
+// 28 Jan 2009
+
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <cassert>
+#include <cmath>
+#include <cstring>
+#include <stdlib.h>
+#include "ttexswizzle.h"
+#include "rand.h"
+#include "timer.h"
+#include "image.h"
+
+
+// In case glext.h isn't new enough:
+#ifndef GL_EXT_texture_swizzle
+
+#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42
+#define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43
+#define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44
+#define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45
+#define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46
+
+#endif
+
+
+namespace GLEAN {
+
+
+static const int TexSize = 16;
+
+static const GLfloat vertexData[4][4] = {
+ // x, y, s, t
+ { -1.0, -1.0, 0.0, 0.0 },
+ { 1.0, -1.0, 1.0, 0.0 },
+ { 1.0, 1.0, 1.0, 1.0 },
+ { -1.0, 1.0, 0.0, 1.0 }
+};
+
+
+TexSwizzleResult::TexSwizzleResult()
+{
+ pass = false;
+}
+
+
+void
+TexSwizzleTest::RandomColor(GLubyte *color)
+{
+ color[0] = rand.next() & 0xff;
+ color[1] = rand.next() & 0xff;
+ color[2] = rand.next() & 0xff;
+ color[3] = rand.next() & 0xff;
+}
+
+
+void
+TexSwizzleTest::SetTextureColor(const GLubyte *color)
+{
+ GLubyte texImage[TexSize][TexSize][4];
+ int i, j;
+
+ for (i = 0; i < TexSize; i++) {
+ for (j = 0; j < TexSize; j++) {
+ texImage[i][j][0] = color[0];
+ texImage[i][j][1] = color[1];
+ texImage[i][j][2] = color[2];
+ texImage[i][j][3] = color[3];
+ }
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TexSize, TexSize, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, texImage);
+}
+
+
+GLubyte
+TexSwizzleTest::Swizzle(const GLubyte *texColor, GLenum swizzle)
+{
+ switch (swizzle) {
+ case GL_RED:
+ return texColor[0];
+ case GL_GREEN:
+ return texColor[1];
+ case GL_BLUE:
+ return texColor[2];
+ case GL_ALPHA:
+ return texColor[3];
+ case GL_ONE:
+ return 255;
+ case GL_ZERO:
+ return 0;
+ default:
+ assert(0);
+ }
+}
+
+
+void
+TexSwizzleTest::ComputeExpectedColor(const GLubyte *texColor,
+ GLenum swizzleR,
+ GLenum swizzleG,
+ GLenum swizzleB,
+ GLenum swizzleA,
+ GLubyte *expectedColor)
+{
+ expectedColor[0] = Swizzle(texColor, swizzleR);
+ expectedColor[1] = Swizzle(texColor, swizzleG);
+ expectedColor[2] = Swizzle(texColor, swizzleB);
+ expectedColor[3] = Swizzle(texColor, swizzleA);
+}
+
+
+const char *
+TexSwizzleTest::SwizzleString(GLenum swizzle)
+{
+ switch (swizzle) {
+ case GL_RED:
+ return "GL_RED";
+ case GL_GREEN:
+ return "GL_GREEN";
+ case GL_BLUE:
+ return "GL_BLUE";
+ case GL_ALPHA:
+ return "GL_ALPHA";
+ case GL_ZERO:
+ return "GL_ZERO";
+ case GL_ONE:
+ return "GL_ONE";
+ default:
+ assert(0);
+ return "???";
+ }
+}
+
+
+void
+TexSwizzleTest::ReportFailure(GLenum swizzleR, GLenum swizzleG,
+ GLenum swizzleB, GLenum swizzleA,
+ const GLubyte *texColor,
+ const GLubyte *actual,
+ const GLubyte *expected)
+{
+ char str[100];
+
+ env->log << name << ": Error: GL_EXT_texure_swizzle test failed\n";
+ env->log << "\tGL_TEXTURE_SWIZZLE_R_EXT = " << SwizzleString(swizzleR) << "\n";
+ env->log << "\tGL_TEXTURE_SWIZZLE_G_EXT = " << SwizzleString(swizzleG) << "\n";
+ env->log << "\tGL_TEXTURE_SWIZZLE_B_EXT = " << SwizzleString(swizzleB) << "\n";
+ env->log << "\tGL_TEXTURE_SWIZZLE_A_EXT = " << SwizzleString(swizzleA) << "\n";
+ if (glIsEnabled(GL_FRAGMENT_PROGRAM_ARB)) {
+ env->log << "\tGL_FRAGMENT_PROGRAM enabled\n";
+ }
+ sprintf(str, "%d, %d, %d, %d",
+ texColor[0], texColor[1], texColor[2], texColor[3]);
+ env->log << "\tTexture color: " << str << "\n";
+ sprintf(str, "%d, %d, %d, %d",
+ expected[0], expected[1], expected[2], expected[3]);
+ env->log << "\tExpected color: " << str << "\n";
+ sprintf(str, "%d, %d, %d, %d",
+ actual[0], actual[1], actual[2], actual[3]);
+ env->log << "\tRendered color: " << str << "\n";
+}
+
+
+// Test state setting/getting for texture swizzle.
+bool
+TexSwizzleTest::TestAPI(void)
+{
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R_EXT, GL_ONE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G_EXT, GL_ZERO);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B_EXT, GL_RED);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A_EXT, GL_BLUE);
+
+ if (glGetError() != GL_NO_ERROR) {
+ env->log << "\tSetting GL_TEXTURE_SWIZZLE_R/G/B/A generated an error.\n";
+ return false;
+ }
+
+ GLint val;
+ glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R_EXT, &val);
+ if (val != GL_ONE) {
+ env->log << "\tQuery of GL_TEXTURE_SWIZZLE_R_EXT failed.\n";
+ return false;
+ }
+ glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G_EXT, &val);
+ if (val != GL_ZERO) {
+ env->log << "\tQuery of GL_TEXTURE_SWIZZLE_G_EXT failed.\n";
+ return false;
+ }
+ glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B_EXT, &val);
+ if (val != GL_RED) {
+ env->log << "\tQuery of GL_TEXTURE_SWIZZLE_B_EXT failed.\n";
+ return false;
+ }
+ glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A_EXT, &val);
+ if (val != GL_BLUE) {
+ env->log << "\tQuery of GL_TEXTURE_SWIZZLE_A_EXT failed.\n";
+ return false;
+ }
+
+ // set all at once
+ const GLint swz[4] = { GL_BLUE, GL_GREEN, GL_ALPHA, GL_ZERO };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA_EXT, swz);
+ if (glGetError() != GL_NO_ERROR) {
+ env->log << "\tSetting GL_TEXTURE_SWIZZLE_RGBA_EXT generated an error.\n";
+ return false;
+ }
+
+ GLint swzOut[4];
+ glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA_EXT, swzOut);
+ if (swzOut[0] != swz[0] ||
+ swzOut[1] != swz[1] ||
+ swzOut[2] != swz[2] ||
+ swzOut[3] != swz[3]) {
+ env->log << "\tQuerying GL_TEXTURE_SWIZZLE_RGBA_EXT failed.\n";
+ return false;
+ }
+
+ return true;
+}
+
+
+// Loop over all possible combinations of texture swizzles,
+// drawing with a texture and checking if the results are correct.
+// return true/false for pass/fail
+bool
+TexSwizzleTest::TestSwizzles(void)
+{
+ static const GLenum swizzles[6] = {
+ GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_ZERO, GL_ONE
+ };
+ int ir, ig, ib, ia;
+ GLubyte texColor[4];
+ int err = 1; // XXX this should be computed from framebuffer depth
+
+ for (ir = 0; ir < 6; ir++) {
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_SWIZZLE_R_EXT,
+ swizzles[ir]);
+ for (ig = 0; ig < 6; ig++) {
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_SWIZZLE_G_EXT,
+ swizzles[ig]);
+
+ // Setup random texture color here (not in the innermost loop
+ // for _every_ iteration) just to speed things up a bit.
+ RandomColor(texColor);
+ SetTextureColor(texColor);
+
+ for (ib = 0; ib < 6; ib++) {
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_SWIZZLE_B_EXT,
+ swizzles[ib]);
+ for (ia = 0; ia < 6; ia++) {
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_SWIZZLE_A_EXT,
+ swizzles[ia]);
+
+ GLubyte expected[4];
+ ComputeExpectedColor(texColor,
+ swizzles[ir],
+ swizzles[ig],
+ swizzles[ib],
+ swizzles[ia],
+ expected);
+
+ // draw something and read back a pixel
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ GLubyte actual[4];
+ glReadPixels(windowSize / 2, windowSize / 2, 1, 1,
+ GL_RGBA, GL_UNSIGNED_BYTE, actual);
+
+ if (abs((int) actual[0] - (int) expected[0]) > err ||
+ abs((int) actual[1] - (int) expected[1]) > err ||
+ abs((int) actual[2] - (int) expected[2]) > err) {
+
+ ReportFailure(swizzles[ir],
+ swizzles[ig],
+ swizzles[ib],
+ swizzles[ia],
+ texColor, actual, expected);
+
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+
+// Same test as above, but using a fragment program instead of fixed-function.
+bool
+TexSwizzleTest::TestSwizzlesWithProgram(void)
+{
+ const char *text =
+ "!!ARBfp1.0\n"
+ "TEX result.color, fragment.texcoord[0], texture[0], 2D; \n"
+ "END\n";
+ GLuint prog;
+
+ glGenProgramsARB(1, &prog);
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog);
+ glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(text), (const GLubyte *) text);
+
+ assert(glGetError() == GL_NO_ERROR);
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+
+ bool pass = TestSwizzles();
+
+ glDisable(GL_FRAGMENT_PROGRAM_ARB);
+
+ return pass;
+}
+
+
+void
+TexSwizzleTest::Setup(void)
+{
+ // setup transformation
+ glViewport(0, 0, windowSize, windowSize);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ // setup vertex arrays (draw textured quad)
+ glVertexPointer(2, GL_FLOAT, 16, vertexData);
+ glTexCoordPointer(2, GL_FLOAT, 16, &vertexData[0][2]);
+ glEnable(GL_VERTEX_ARRAY);
+ glEnable(GL_TEXTURE_COORD_ARRAY);
+
+ // setup texture
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_2D);
+}
+
+
+void
+TexSwizzleTest::runOne(TexSwizzleResult &r, Window &w)
+{
+ (void) w; // silence warning
+
+ Setup();
+
+ r.pass = TestAPI();
+
+ if (r.pass) {
+ r.pass = TestSwizzles();
+ }
+
+ if (r.pass && GLUtils::haveExtension("GL_ARB_fragment_program")) {
+ r. pass = TestSwizzlesWithProgram();
+ }
+}
+
+
+void
+TexSwizzleTest::logOne(TexSwizzleResult &r)
+{
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ }
+ else {
+ env->log << name << " FAIL\n";
+ }
+}
+
+
+void
+TexSwizzleTest::compareOne(TexSwizzleResult &oldR,
+ TexSwizzleResult &newR)
+{
+ comparePassFail(oldR, newR);
+}
+
+
+void
+TexSwizzleResult::putresults(ostream &s) const
+{
+ if (pass) {
+ s << "PASS\n";
+ }
+ else {
+ s << "FAIL\n";
+ }
+}
+
+
+bool
+TexSwizzleResult::getresults(istream &s)
+{
+ char result[1000];
+ s >> result;
+
+ if (strcmp(result, "FAIL") == 0) {
+ pass = false;
+ }
+ else {
+ pass = true;
+ }
+ return s.good();
+}
+
+
+// The test object itself:
+TexSwizzleTest texSwizzleTest("texSwizzle", "window, rgb",
+ "GL_EXT_texture_swizzle",
+ "Test the GL_EXT_texture_swizzle extension.\n");
+
+
+
+} // namespace GLEAN
+
+
diff --git a/tests/glean/ttexswizzle.h b/tests/glean/ttexswizzle.h
new file mode 100644
index 000000000..efe394143
--- /dev/null
+++ b/tests/glean/ttexswizzle.h
@@ -0,0 +1,88 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2009 VMware, Inc. 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 VMWARE 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
+
+// tTexSwizzle.h: Test GL_EXT_texture_swizzle
+
+#ifndef __ttexswizzle_h__
+#define __ttexswizzle_h__
+
+#include "tbase.h"
+#include "rand.h"
+
+namespace GLEAN {
+
+#define windowSize 50
+
+class TexSwizzleResult: public BaseResult
+{
+public:
+ bool pass;
+
+ TexSwizzleResult();
+
+ virtual void putresults(ostream& s) const;
+ virtual bool getresults(istream& s);
+};
+
+
+class TexSwizzleTest: public BaseTest<TexSwizzleResult>
+{
+public:
+ GLEAN_CLASS_WH(TexSwizzleTest, TexSwizzleResult,
+ windowSize, windowSize);
+
+private:
+ RandomBase rand;
+
+ void RandomColor(GLubyte *color);
+ void SetTextureColor(const GLubyte *color);
+ GLubyte Swizzle(const GLubyte *texColor, GLenum swizzle);
+ void ComputeExpectedColor(const GLubyte *texColor,
+ GLenum swizzleR,
+ GLenum swizzleG,
+ GLenum swizzleB,
+ GLenum swizzleA,
+ GLubyte *expectedColor);
+ const char *SwizzleString(GLenum swizzle);
+ void ReportFailure(GLenum swizzleR,
+ GLenum swizzleG,
+ GLenum swizzleB,
+ GLenum swizzleA,
+ const GLubyte *texColor,
+ const GLubyte *actual,
+ const GLubyte *expected);
+ bool TestAPI(void);
+ bool TestSwizzles(void);
+ bool TestSwizzlesWithProgram(void);
+ void Setup(void);
+};
+
+} // namespace GLEAN
+
+#endif // __ttexswizzle_h__
+
diff --git a/tests/glean/ttexture_srgb.cpp b/tests/glean/ttexture_srgb.cpp
index 809a56a6c..4fa5b9d1a 100644
--- a/tests/glean/ttexture_srgb.cpp
+++ b/tests/glean/ttexture_srgb.cpp
@@ -30,10 +30,12 @@
// Brian Paul August 2006
-#include "ttexture_srgb.h"
-#include "rand.h"
#include <cassert>
+#include <cstring>
#include <cmath>
+#include "ttexture_srgb.h"
+#include "rand.h"
+
#ifdef GL_EXT_texture_sRGB
diff --git a/tests/glean/ttexunits.cpp b/tests/glean/ttexunits.cpp
new file mode 100644
index 000000000..e84c94e1d
--- /dev/null
+++ b/tests/glean/ttexunits.cpp
@@ -0,0 +1,323 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2008 VMWare, Inc. 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
+
+// Test texture unit things
+// We're generally just testing API-related things, not rendering.
+// Brian Paul 31 Dec 2008
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <cstring>
+#include <cassert>
+#include <math.h>
+#include "ttexunits.h"
+
+
+namespace GLEAN {
+
+
+void
+TexUnitsTest::reportFailure(const char *msg) const
+{
+ env->log << "FAILURE:\n";
+ env->log << "\t" << msg << "\n";
+}
+
+
+void
+TexUnitsTest::reportFailure(const char *msg, GLint unit) const
+{
+ char s[100];
+ snprintf(s, sizeof(s), msg, unit);
+ env->log << "FAILURE:\n";
+ env->log << "\t" << s << "\n";
+}
+
+
+bool
+TexUnitsTest::setup(void)
+{
+ // check that we have OpenGL 2.x or 3.x
+ const char *verString = (const char *) glGetString(GL_VERSION);
+
+ if (verString[0] != '2' && verString[0] != '3') {
+ env->log << "OpenGL 2.x or 3.x not supported\n";
+ return false;
+ }
+
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxImageUnits);
+ glGetIntegerv(GL_MAX_TEXTURE_COORDS, &maxCoordUnits);
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxUnits);
+
+ return true;
+}
+
+
+bool
+TexUnitsTest::testLimits(void)
+{
+ if (maxImageUnits < maxUnits) {
+ reportFailure("GL_MAX_TEXTURE_IMAGE_UNITS < GL_MAX_TEXTURE_UNITS");
+ return false;
+ }
+ if (maxCoordUnits < maxUnits) {
+ reportFailure("GL_MAX_TEXTURE_COORD_UNITS < GL_MAX_TEXTURE_UNITS");
+ return false;
+ }
+ return true;
+}
+
+
+bool
+TexUnitsTest::testActiveTexture(void)
+{
+ GLint i;
+ GLint maxUnits;
+
+ if (maxImageUnits > maxCoordUnits)
+ maxUnits = maxImageUnits;
+ else
+ maxUnits = maxCoordUnits;
+
+ // clear any error state
+ while (glGetError())
+ ;
+
+ // test glActiveTexture()
+ for (i = 0; i < maxUnits; i++) {
+ glActiveTexture(GL_TEXTURE0 + i);
+ if (glGetError()) {
+ reportFailure("glActiveTexture(GL_TEXTURE%d) failed", i);
+ return false;
+ }
+
+ GLint unit;
+ glGetIntegerv(GL_ACTIVE_TEXTURE, &unit);
+ if (unit != GL_TEXTURE0 + i || glGetError()) {
+ reportFailure("glGetIntegerv(GL_ACTIVE_TEXTURE) failed");
+ return false;
+ }
+ }
+
+ // this should fail:
+ glActiveTexture(GL_TEXTURE0 + maxUnits);
+ if (glGetError() != GL_INVALID_ENUM) {
+ reportFailure("glActiveTexture(GL_TEXTURE%d) failed to generate an error",
+ maxUnits);
+ return false;
+ }
+
+
+ // test glClientActiveTexture()
+ for (i = 0; i < maxCoordUnits; i++) {
+ glClientActiveTexture(GL_TEXTURE0 + i);
+ if (glGetError()) {
+ reportFailure("glClientActiveTexture(GL_TEXTURE%d) failed", i);
+ return false;
+ }
+
+ GLint unit;
+ glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &unit);
+ if (unit != GL_TEXTURE0 + i || glGetError()) {
+ reportFailure("glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE) failed");
+ return false;
+ }
+ }
+
+ // this should fail:
+ glClientActiveTexture(GL_TEXTURE0 + maxUnits);
+ if (glGetError() != GL_INVALID_ENUM) {
+ reportFailure("glClientActiveTexture(GL_TEXTURE%d) failed to generate an error", maxUnits);
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
+TexUnitsTest::testTextureMatrices(void)
+{
+ GLint i;
+
+ glActiveTexture(GL_TEXTURE0);
+ glMatrixMode(GL_TEXTURE);
+
+ // set texture matrices
+ for (i = 0; i < maxCoordUnits; i++) {
+ glActiveTexture(GL_TEXTURE0 + i);
+
+ // generate matrix
+ GLfloat m[16];
+ for (int j = 0; j < 16; j++) {
+ m[j] = float(i * 100 + j);
+ }
+
+ glLoadMatrixf(m);
+ }
+
+ // query texture matrices
+ for (i = 0; i < maxCoordUnits; i++) {
+ glActiveTexture(GL_TEXTURE0 + i);
+
+ // get matrix and check it
+ GLfloat m[16];
+ memset(m, 0, sizeof(m));
+ glGetFloatv(GL_TEXTURE_MATRIX, m);
+
+ if (glGetError()) {
+ reportFailure("Query of texture matrix %d raised an error", i);
+ return false;
+ }
+
+ for (int j = 0; j < 16; j++) {
+ if (m[j] != float(i * 100 + j)) {
+ reportFailure("Query of texture matrix %d failed", i);
+ return false;
+ }
+ }
+ }
+
+ if (glGetError()) {
+ reportFailure("GL error was generated while testing texture matrices");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
+TexUnitsTest::testTextureCoordGen(void)
+{
+ GLint i;
+
+ glActiveTexture(GL_TEXTURE0);
+ glMatrixMode(GL_TEXTURE);
+
+ // test texgen enable/disable
+ for (i = 0; i < maxUnits; i++) {
+ glActiveTexture(GL_TEXTURE0 + i);
+
+ glEnable(GL_TEXTURE_GEN_S);
+ glEnable(GL_TEXTURE_GEN_T);
+ glEnable(GL_TEXTURE_GEN_R);
+ glEnable(GL_TEXTURE_GEN_Q);
+ if (i < maxCoordUnits) {
+ // should be no error
+ if (glGetError()) {
+ reportFailure("GL error was generated by enabling GL_TEXTURE_GEN_x, unit %d", i);
+ return false;
+ }
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glDisable(GL_TEXTURE_GEN_R);
+ glDisable(GL_TEXTURE_GEN_Q);
+ }
+ else {
+ // should be an error
+ if (glGetError() != GL_INVALID_OPERATION) {
+ reportFailure("GL error not generated by invalid enable of GL_TEXTURE_GEN_x, unit %d", i);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+bool
+TexUnitsTest::testTexcoordArrays(void)
+{
+ GLint i;
+
+ for (i = 0; i < maxCoordUnits; i++) {
+ glClientActiveTexture(GL_TEXTURE0 + i);
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ if (glGetError()) {
+ reportFailure("GL error was generated by glEnableClientState for unit %d", i);
+ return false;
+ }
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ }
+
+ return true;
+}
+
+
+void
+TexUnitsTest::runOne(MultiTestResult &r, Window &w)
+{
+ (void) w;
+
+ if (!setup()) {
+ r.pass = false;
+ return;
+ }
+
+ if (testLimits())
+ r.numPassed++;
+ else
+ r.numFailed++;
+
+ if (testActiveTexture())
+ r.numPassed++;
+ else
+ r.numFailed++;
+
+ if (testTextureMatrices())
+ r.numPassed++;
+ else
+ r.numFailed++;
+
+ if (testTextureCoordGen())
+ r.numPassed++;
+ else
+ r.numFailed++;
+
+ if (testTexcoordArrays())
+ r.numPassed++;
+ else
+ r.numFailed++;
+
+ r.pass = (r.numFailed == 0);
+}
+
+
+// The test object itself:
+TexUnitsTest texUnitTest("texUnits", "window, rgb",
+ "", // no extension filter
+ "texUnits: test texture units.\n"
+ );
+
+
+
+} // namespace GLEAN
diff --git a/tests/glean/ttexunits.h b/tests/glean/ttexunits.h
new file mode 100644
index 000000000..803c515b6
--- /dev/null
+++ b/tests/glean/ttexunits.h
@@ -0,0 +1,70 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2008 VMware, Inc. 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
+
+
+#ifndef __ttexunits_h__
+#define __ttexunits_h__
+
+#include "tmultitest.h"
+
+namespace GLEAN {
+
+#define windowSize 100
+
+
+class TexUnitsTest: public MultiTest
+{
+public:
+ TexUnitsTest(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:
+ GLint maxImageUnits;
+ GLint maxCoordUnits;
+ GLint maxUnits;
+
+ void reportFailure(const char *msg) const;
+ void reportFailure(const char *msg, GLint unit) const;
+
+ bool setup(void);
+ bool testLimits(void);
+ bool testActiveTexture(void);
+ bool testTextureMatrices(void);
+ bool testTextureCoordGen(void);
+ bool testTexcoordArrays(void);
+};
+
+
+} // namespace GLEAN
+
+#endif // __ttexunits_h__
diff --git a/tests/glean/tvertarraybgra.cpp b/tests/glean/tvertarraybgra.cpp
new file mode 100644
index 000000000..737af0c44
--- /dev/null
+++ b/tests/glean/tvertarraybgra.cpp
@@ -0,0 +1,248 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2009 VMware, Inc. 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 VMWARE 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
+
+
+// Render some geometry with random GLubyte/RGBA vertex colors.
+// Then re-render same thing with GLubyte/BGRA vertex colors.
+// Brian Paul
+// 23 Jan 2009
+
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <cassert>
+#include <cmath>
+#include <cstring>
+#include "tvertarraybgra.h"
+#include "rand.h"
+#include "timer.h"
+#include "image.h"
+
+
+namespace GLEAN {
+
+
+VertArrayBGRAResult::VertArrayBGRAResult()
+{
+ pass = true;
+}
+
+
+void
+VertArrayBGRATest::reportError(const char *msg)
+{
+ env->log << name << ": Error: " << msg << "\n";
+}
+
+
+bool
+VertArrayBGRATest::testAPI(void)
+{
+ // Get glVertexAttrib() function
+ PFNGLVERTEXATTRIBPOINTERARBPROC VertexAttribPointer = NULL;
+ const char *version = (const char *) glGetString(GL_VERSION);
+ if (version[0] == '2') {
+ VertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERARBPROC)
+ GLUtils::getProcAddress("glVertexAttribPointer");
+ }
+
+ GLubyte array[4];
+
+ if (glGetError()) {
+ reportError("initial error state is not GL_NO_ERROR.");
+ return false;
+ }
+
+ glColorPointer(GL_BGRA, GL_UNSIGNED_BYTE, 0, array);
+ if (glGetError()) {
+ reportError("glColorPointer(size=GL_BGRA) generated an error.");
+ return false;
+ }
+
+ glSecondaryColorPointer(GL_BGRA, GL_UNSIGNED_BYTE, 0, array);
+ if (glGetError()) {
+ reportError("glSecondaryColorPointer(size=GL_BGRA) generated an error.");
+ return false;
+ }
+
+ if (VertexAttribPointer) {
+ VertexAttribPointer(2, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, 0, array);
+ if (glGetError()) {
+ reportError("glVertexAttribPointer(size=GL_BGRA) generated an error.");
+ return false;
+ }
+ }
+
+ // this _should_ generate an error
+ glColorPointer(GL_BGRA, GL_FLOAT, 0, array);
+ if (glGetError() != GL_INVALID_VALUE) {
+ reportError("glColorPointer(size=GL_BGRA, type=GL_FLOAT) did not generate expected error.");
+ return false;
+ }
+
+ return true;
+}
+
+
+void
+VertArrayBGRATest::setupPoints()
+{
+ RandomDouble r(10);
+ int i;
+ for (i = 0; i < NUM_POINTS; i++) {
+ mPos[i][0] = r.next() * WINDOW_SIZE;
+ mPos[i][1] = r.next() * WINDOW_SIZE;
+ mRGBA[i][0] = int(r.next() * 255);
+ mRGBA[i][1] = int(r.next() * 255);
+ mRGBA[i][2] = int(r.next() * 255);
+ mRGBA[i][3] = int(r.next() * 255);
+ mBGRA[i][0] = mRGBA[i][2]; // blue
+ mBGRA[i][1] = mRGBA[i][1]; // green
+ mBGRA[i][2] = mRGBA[i][0]; // red
+ mBGRA[i][3] = mRGBA[i][3]; // alpha
+ }
+}
+
+
+void
+VertArrayBGRATest::renderPoints(bool useBGRA)
+{
+ glVertexPointer(2, GL_FLOAT, 0, mPos);
+ glEnable(GL_VERTEX_ARRAY);
+
+ if (useBGRA)
+ glColorPointer(GL_BGRA, GL_UNSIGNED_BYTE, 0, mBGRA);
+ else
+ glColorPointer(4, GL_UNSIGNED_BYTE, 0, mRGBA);
+ glEnable(GL_COLOR_ARRAY);
+
+ glDrawArrays(GL_POINTS, 0, NUM_POINTS);
+
+ glDisable(GL_VERTEX_ARRAY);
+ glDisable(GL_COLOR_ARRAY);
+}
+
+
+void
+VertArrayBGRATest::runOne(VertArrayBGRAResult &r, Window &w)
+{
+ (void) w; // silence warning
+ Image rgbaImage(WINDOW_SIZE, WINDOW_SIZE, GL_RGBA, GL_UNSIGNED_BYTE);
+ Image bgraImage(WINDOW_SIZE, WINDOW_SIZE, GL_RGBA, GL_UNSIGNED_BYTE);
+
+ r.pass = testAPI();
+ if (!r.pass)
+ return;
+
+ setupPoints();
+#if 0 // test lighting path too (debug only)
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_COLOR_MATERIAL);
+#endif
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, WINDOW_SIZE, 0, WINDOW_SIZE, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ // render with RGBA colors and save image
+ glClear(GL_COLOR_BUFFER_BIT);
+ renderPoints(false);
+ rgbaImage.read(0, 0); // pos=(0,0)
+ w.swap();
+
+ // render with BGRA colors and save image
+ glClear(GL_COLOR_BUFFER_BIT);
+ renderPoints(true);
+ bgraImage.read(0, 0); // pos=(0,0)
+ w.swap();
+
+ // images should be identical
+ r.pass = (rgbaImage == bgraImage);
+ if (!r.pass) {
+ reportError("BGRA colors did not match RGBA colors.");
+ }
+}
+
+
+void
+VertArrayBGRATest::logOne(VertArrayBGRAResult &r)
+{
+ logPassFail(r);
+ logConcise(r);
+}
+
+
+void
+VertArrayBGRATest::compareOne(VertArrayBGRAResult &oldR,
+ VertArrayBGRAResult &newR)
+{
+ comparePassFail(oldR, newR);
+}
+
+
+void
+VertArrayBGRAResult::putresults(ostream &s) const
+{
+ if (pass) {
+ s << "PASS\n";
+ }
+ else {
+ s << "FAIL\n";
+ }
+}
+
+
+bool
+VertArrayBGRAResult::getresults(istream &s)
+{
+ char result[1000];
+ s >> result;
+
+ if (strcmp(result, "FAIL") == 0) {
+ pass = false;
+ }
+ else {
+ pass = true;
+ }
+ return s.good();
+}
+
+
+// The test object itself:
+VertArrayBGRATest vertArrayBGRATest("vertArrayBGRA", "window, rgb",
+ "GL_EXT_vertex_array_bgra",
+ "Test the GL_EXT_vertex_array_bgra extension.\n");
+
+
+
+} // namespace GLEAN
+
+
diff --git a/tests/glean/tvertarraybgra.h b/tests/glean/tvertarraybgra.h
new file mode 100644
index 000000000..2b3a11845
--- /dev/null
+++ b/tests/glean/tvertarraybgra.h
@@ -0,0 +1,74 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2009 VMware, Inc. 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 VMWARE 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
+
+// tvertarraybgra.h: Test GL_EXT_vertex_array bgra
+
+#ifndef __tvertarraybgra_h__
+#define __tvertarraybgra_h__
+
+#include "tbase.h"
+
+
+namespace GLEAN {
+
+#define NUM_POINTS 1000
+#define WINDOW_SIZE 100
+
+class VertArrayBGRAResult: public BaseResult
+{
+public:
+ VertArrayBGRAResult();
+
+ virtual void putresults(ostream& s) const;
+ virtual bool getresults(istream& s);
+
+ bool pass;
+};
+
+
+class VertArrayBGRATest: public BaseTest<VertArrayBGRAResult>
+{
+public:
+ GLEAN_CLASS_WH(VertArrayBGRATest, VertArrayBGRAResult,
+ WINDOW_SIZE, WINDOW_SIZE);
+
+private:
+ float mPos[NUM_POINTS][2];
+ GLubyte mRGBA[NUM_POINTS][4];
+ GLubyte mBGRA[NUM_POINTS][4];
+
+ void reportError(const char *msg);
+ bool testAPI(void);
+ void setupPoints(void);
+ void renderPoints(bool useBGRA);
+};
+
+} // namespace GLEAN
+
+#endif // __tvertarraybgra_h__
+
diff --git a/tests/glean/tvertattrib.cpp b/tests/glean/tvertattrib.cpp
index fd7e12cbe..6dadf9046 100644
--- a/tests/glean/tvertattrib.cpp
+++ b/tests/glean/tvertattrib.cpp
@@ -45,10 +45,11 @@
// Author: Brian Paul (brian.paul a t tungstengraphics.com) October 2004
+#include <stdlib.h>
+#include <cassert>
#include <math.h>
#include "tvertattrib.h"
#include "glutils.h"
-#include <cassert>
namespace GLEAN {
diff --git a/tests/glean/tvertprog1.cpp b/tests/glean/tvertprog1.cpp
index 9cfd52a4d..32053358d 100644
--- a/tests/glean/tvertprog1.cpp
+++ b/tests/glean/tvertprog1.cpp
@@ -31,10 +31,11 @@
//
// See tfragprog.cpp for comments (this test is very similar).
-#include "tvertprog1.h"
#include <cassert>
#include <cmath>
+#include <cstring>
#include <math.h>
+#include "tvertprog1.h"
namespace GLEAN {