diff options
author | Eric Anholt <eric@anholt.net> | 2009-03-07 03:36:21 -0800 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2009-03-07 03:40:55 -0800 |
commit | e5fc8a140e66de7144cba57ab4737532573a5b3d (patch) | |
tree | 39a22b8af3d397a8e3a59482ac29712d237b7185 | |
parent | b74fa0389df84a1aa4d4495fc79bbd63fbd69bc5 (diff) | |
parent | aa7c71facfe968af8f82c5a07b02cad039a3134e (diff) |
Merge branch 'glean-master'
Conflicts:
tests/glean/dsconfig.cpp
tests/glean/dsfilt.cpp
tests/glean/tapi2.cpp
tests/glean/tdepthstencil.cpp
tests/glean/tglsl1.cpp
tests/glean/tlogicop.cpp
tests/glean/toccluqry.cpp
tests/glean/tpbo.cpp
tests/glean/tpixelformats.cpp
tests/glean/tpointsprite.cpp
tests/glean/ttexture_srgb.cpp
tests/glean/tvertattrib.cpp
I decided to just take stock glean code where conflicts occurred. I kept
delaying due to resolving the conflicts, and the only conflicts of value
should be warning-related. Those should really be resolved upstream, instead.
41 files changed, 3791 insertions, 133 deletions
diff --git a/tests/all.tests b/tests/all.tests index 26591a2d..e4a6c159 100644 --- a/tests/all.tests +++ b/tests/all.tests @@ -48,7 +48,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 aa59e56c..4090d975 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 16440b44..861c0c83 100644 --- a/tests/glean/dsconfig.cpp +++ b/tests/glean/dsconfig.cpp @@ -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 @@ -10,11 +12,11 @@ // sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: -// +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the // Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR @@ -23,17 +25,17 @@ // 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 // dsconfig.cpp: Implementation of drawing surface configuration utilities #include "dsconfig.h" #include <iostream> -#include <sstream> -#include <cstring> +#include <strstream> +#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, @@ -118,8 +121,7 @@ typedef enum { // These variable tags are used as array indices, V_LAST } CanonVar; -struct CanonVarMapping {CanonVar var; const char* name;}; -CanonVarMapping varNames[] = { +struct {CanonVar var; char* name;} varNames[] = { {VID, "id"}, {VFBCID, "fbcID"}, {VCANRGBA, "canRGBA"}, @@ -139,6 +141,7 @@ CanonVarMapping varNames[] = { {VACCUMG, "accumG"}, {VACCUMB, "accumB"}, {VACCUMA, "accumA"}, + {VSAMPLES, "multisample"}, {VCANWINDOW, "window"}, {VCANPIXMAP, "pixmap"}, {VCANPBUFFER, "pBuffer"}, @@ -156,7 +159,7 @@ CanonVarMapping varNames[] = { {VTRANSI, "transI"} }; -const char* mapVarToName[V_LAST]; +char* mapVarToName[V_LAST]; map<string, CanonVar> mapNameToVar; bool mapsInitialized = false; @@ -229,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. @@ -299,9 +314,9 @@ DrawingSurfaceConfig::DrawingSurfaceConfig(int id, ::PIXELFORMATDESCRIPTOR *ppfd pfd = ppfd; pfdID = id; - - canRGBA = pfd->iPixelType == PFD_TYPE_RGBA; - canCI = pfd->iPixelType == PFD_TYPE_COLORINDEX; + + canRGBA = pfd->iPixelType == PFD_TYPE_RGBA; + canCI = pfd->iPixelType == PFD_TYPE_COLORINDEX; bufSize = pfd->cColorBits + pfd->cAlphaBits; @@ -330,9 +345,11 @@ DrawingSurfaceConfig::DrawingSurfaceConfig(int id, ::PIXELFORMATDESCRIPTOR *ppfd accB = pfd->cAccumBlueBits; accA = pfd->cAccumAlphaBits; - canWindow = pfd->dwFlags & PFD_DRAW_TO_WINDOW; + samples = 0; // XXX implement properly for Windows! - canWinSysRender = pfd->dwFlags & PFD_SUPPORT_GDI; + canWindow = pfd->dwFlags & PFD_DRAW_TO_WINDOW; + + canWinSysRender = pfd->dwFlags & PFD_SUPPORT_GDI; if (pfd->dwFlags & PFD_GENERIC_FORMAT) { @@ -341,20 +358,20 @@ DrawingSurfaceConfig::DrawingSurfaceConfig(int id, ::PIXELFORMATDESCRIPTOR *ppfd // it's an MCD - at least it has some acceleration fast = true; } - else + else { - // it's software + // it's software fast = false; } } - else + else { - // it's an ICD + // it's an ICD fast = true; } // we'll assume that the OpenGL implementation thinks it is conformant - conformant = true; + conformant = true; // chromakeying isn't supported transparent = false; @@ -379,15 +396,16 @@ DrawingSurfaceConfig::DrawingSurfaceConfig() { accB = 32; accA = 32; + samples = 0; - canWindow = 1; - canWinSysRender = 1; + canWindow = 1; + canWinSysRender = 1; // This is a software-mode assumption fast = false; // we'll assume that the OpenGL implementation thinks it is conformant - conformant = true; + conformant = true; // chromakeying isn't supported transparent = false; @@ -399,18 +417,18 @@ DrawingSurfaceConfig::DrawingSurfaceConfig() { DrawingSurfaceConfig::DrawingSurfaceConfig(int id, ::AGLPixelFormat pfd) { long i; - + if (!mapsInitialized) initializeMaps(); pf = pfd; - + if (aglDescribePixelFormat( pf, AGL_RGBA, &i)) canRGBA = (i == GL_TRUE); - canCI = (i == GL_FALSE); + canCI = (i == GL_FALSE); if (aglDescribePixelFormat( pf, AGL_BUFFER_SIZE, &i)) - bufSize = i; + bufSize = i; level = 0; @@ -437,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); @@ -453,7 +473,7 @@ DrawingSurfaceConfig::DrawingSurfaceConfig(int id, ::AGLPixelFormat pfd) fast = i; // we'll assume that the OpenGL implementation thinks it is conformant - conformant = true; + conformant = true; // chromakeying isn't supported transparent = false; @@ -545,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; @@ -628,7 +651,10 @@ DrawingSurfaceConfig::DrawingSurfaceConfig(string& str) { string DrawingSurfaceConfig::canonicalDescription() { - ostringstream s; + // Would rather use ostringstream, but it's not available in + // egcs 1.1.2. + char buf[1024]; + ostrstream s(buf, sizeof(buf)); # if defined(__X11__) s << mapVarToName[VID] << ' ' << visID; @@ -636,7 +662,7 @@ DrawingSurfaceConfig::canonicalDescription() { s << ' ' << mapVarToName[VFBCID] << ' ' << fbcID; # endif # elif defined(__WIN__) - s << mapVarToName[VID] << ' ' << pfdID; + s << mapVarToName[VID] << ' ' << pfdID; # endif s << ' ' << mapVarToName[VCANRGBA] << ' ' << canRGBA; @@ -666,6 +692,8 @@ DrawingSurfaceConfig::canonicalDescription() { << ' ' << mapVarToName[VACCUMB] << ' ' << accB << ' ' << mapVarToName[VACCUMA] << ' ' << accA; + s << ' ' << mapVarToName[VSAMPLES] << ' ' << samples; + s << ' ' << mapVarToName[VCANWINDOW] << ' ' << canWindow; # if defined(__X11__) @@ -703,7 +731,8 @@ DrawingSurfaceConfig::canonicalDescription() { /////////////////////////////////////////////////////////////////////////////// string DrawingSurfaceConfig::conciseDescription() { - ostringstream s; + char buf[1024]; + ostrstream s(buf, sizeof(buf)); if (canRGBA && canCI) s << "dual "; @@ -765,6 +794,10 @@ DrawingSurfaceConfig::conciseDescription() { } } + if (samples) { + s << ", samples" << samples; + } + { s << ", "; bool sep = false; @@ -865,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 a5f24f92..ea7ffd7c 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 e5cf32fa..6b1795b4 100644 --- a/tests/glean/dsfilt.cpp +++ b/tests/glean/dsfilt.cpp @@ -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 @@ -10,11 +12,11 @@ // sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: -// +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the // Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR @@ -23,7 +25,7 @@ // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -// +// // END_COPYRIGHT @@ -32,6 +34,7 @@ // dsfilt.cpp: Implementation of drawing surface configuration filtering #include <iostream> +#include <strstream> #include <ctype.h> #include <stdlib.h> #include <algorithm> @@ -213,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; @@ -282,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; @@ -302,7 +309,7 @@ DrawingSurfaceFilter::FetchVariable(const DrawingSurfaceConfig& c, Token v) { # else return 0; # endif - + case VAR_LEVEL: return c.level; case VAR_MAIN: diff --git a/tests/glean/dsfilt.h b/tests/glean/dsfilt.h index 89c6d583..ec715759 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/glutils.cpp b/tests/glean/glutils.cpp index df19c8ca..ff3b0707 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 83942f4f..fd28f49c 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 adfdc224..17626701 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 492226a4..ec0ac47a 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 32eddd27..15fe59d4 100644 --- a/tests/glean/tapi2.cpp +++ b/tests/glean/tapi2.cpp @@ -1,7 +1,7 @@ // BEGIN_COPYRIGHT -*- glean -*- -// +// // Copyright (C) 1999 Allen Akin All Rights Reserved. -// +// // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -10,11 +10,11 @@ // sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: -// +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the // Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR @@ -23,7 +23,7 @@ // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -// +// // END_COPYRIGHT // tapi2.h: Test OpenGL 2.x API functions/features @@ -31,11 +31,11 @@ #define GL_GLEXT_PROTOTYPES -#include "tapi2.h" -#include <cassert> +#include <stdlib.h> #include <cstring> -#include <cstdlib> -#include <cmath> +#include <cassert> +#include <math.h> +#include "tapi2.h" namespace GLEAN { @@ -205,7 +205,7 @@ API2Test::setup(void) glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDrawBuffer(GL_FRONT); - glReadBuffer(GL_FRONT); + glReadBuffer(GL_FRONT); // compute error tolerances (may need fine-tuning) int bufferBits[5]; @@ -283,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); } @@ -321,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); } @@ -704,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; } @@ -750,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 f5950fb8..cd01fc94 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, @@ -257,14 +266,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 @@ -280,8 +298,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 @@ -298,7 +321,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 3d87d6c0..be346578 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 110eb565..54e97df0 100644 --- a/tests/glean/tdepthstencil.cpp +++ b/tests/glean/tdepthstencil.cpp @@ -30,14 +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> -#include <cstdlib> -#include <cstring> #ifdef GL_EXT_packed_depth_stencil diff --git a/tests/glean/tfbo.cpp b/tests/glean/tfbo.cpp index e269fead..325b523d 100644 --- a/tests/glean/tfbo.cpp +++ b/tests/glean/tfbo.cpp @@ -82,15 +82,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; } @@ -1218,7 +1224,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); @@ -1239,15 +1246,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); @@ -1268,15 +1276,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 + @@ -1286,13 +1296,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); @@ -1303,7 +1313,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 4a35c602..01d0d271 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 7a93eda1..2038007a 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 216dc506..9abe354c 100644 --- a/tests/glean/tfragprog1.cpp +++ b/tests/glean/tfragprog1.cpp @@ -437,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" @@ -564,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 a98694ac..42bc9c4e 100644 --- a/tests/glean/tglsl1.cpp +++ b/tests/glean/tglsl1.cpp @@ -336,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", @@ -1060,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" @@ -1091,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 *=", @@ -2898,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 }; @@ -3205,13 +3334,6 @@ 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"; - return false; - } - // check GLSL version #ifdef GL_SHADING_LANGUAGE_VERSION const char *glslVersion = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION); @@ -3222,7 +3344,7 @@ GLSLTest::setup(void) env->log << "GLSL 1.x not supported\n"; return false; } - glsl_120 = (verString[2] >= '2'); + glsl_120 = (glslVersion[2] >= '2'); if (!getFunctions()) { env->log << "Unable to get pointer to an OpenGL 2.0 API function\n"; @@ -3662,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 cf1ed924..73972b0e 100644 --- a/tests/glean/tglsl1.h +++ b/tests/glean/tglsl1.h @@ -59,8 +59,11 @@ 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: diff --git a/tests/glean/tlogicop.cpp b/tests/glean/tlogicop.cpp index 5aee3520..470654a7 100644 --- a/tests/glean/tlogicop.cpp +++ b/tests/glean/tlogicop.cpp @@ -1,7 +1,7 @@ // BEGIN_COPYRIGHT -*- glean -*- -// +// // Copyright (C) 1999 Allen Akin All Rights Reserved. -// +// // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -10,11 +10,11 @@ // sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: -// +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the // Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR @@ -23,22 +23,22 @@ // 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 // tlogicop.cpp: Test RGBA logic op functions. // 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> -#include <cstdlib> namespace { -struct logicopNameMapping {GLenum op; const char* name;}; +struct logicopNameMapping {GLenum op; char* name;}; logicopNameMapping logicopNames[] = { {GL_CLEAR, "GL_CLEAR"}, {GL_SET, "GL_SET"}, @@ -58,7 +58,7 @@ logicopNameMapping logicopNames[] = { {GL_OR_INVERTED, "GL_OR_INVERTED"} }; -const char* +char* logicopToName(GLenum op) { for (unsigned int i = 0; i < sizeof(logicopNames) / sizeof(logicopNames[0]); ++i) { @@ -90,7 +90,7 @@ makeRGBA(GLEAN::RandomBits& rRand, rgba[3] = aRand.next() & 0xff; } // makeRGBA -void +void drawQuad(const int x, const int y, const GLubyte* color) { glColor4ubv(color); glBegin(GL_QUADS); @@ -233,7 +233,7 @@ static runResult runTest(GLenum logicop, GLEAN::DrawingSurfaceConfig& config, GLEAN::Environment& env) { using namespace GLEAN; - + runResult result; int y; diff --git a/tests/glean/toccluqry.cpp b/tests/glean/toccluqry.cpp index 2359bb6b..a362fc13 100644 --- a/tests/glean/toccluqry.cpp +++ b/tests/glean/toccluqry.cpp @@ -33,12 +33,12 @@ */ #define GL_GLEXT_PROTOTYPES -#include "toccluqry.h" +#include <stdlib.h> #include <cassert> -#include <cstdlib> -#include <cstdio> #include <cstring> +#include <stdio.h> #include <cmath> +#include "toccluqry.h" #define START_QUERY(id)\ @@ -86,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 1683b4e7..7807a089 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" #include <cstdlib> diff --git a/tests/glean/tpbo.cpp b/tests/glean/tpbo.cpp index 0b5e7c2e..5ae7a574 100644 --- a/tests/glean/tpbo.cpp +++ b/tests/glean/tpbo.cpp @@ -34,12 +34,15 @@ #define GL_GLEXT_PROTOTYPES
-#include "tpbo.h"
-#include <cassert>
-#include <cmath>
-#include <cstdlib>
+
+#include <stdlib.h>
#include <cstring>
+#include <cassert>
+#include <math.h>
+#include "tpbo.h"
#include "timer.h"
+
+
namespace GLEAN
{
@@ -81,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 1d367faf..3603bf57 100644 --- a/tests/glean/tpixelformats.cpp +++ b/tests/glean/tpixelformats.cpp @@ -1,7 +1,7 @@ // BEGIN_COPYRIGHT -*- glean -*- -// +// // Copyright (C) 1999 Allen Akin All Rights Reserved. -// +// // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -10,11 +10,11 @@ // sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: -// +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the // Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR @@ -23,14 +23,14 @@ // 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 -#include "tpixelformats.h" +#include <stdlib.h> #include <cassert> #include <cmath> -#include <cstdlib> +#include "tpixelformats.h" // Set to 1 to help debug test failures: @@ -1119,8 +1119,8 @@ PixelFormatsTest::ComputeExpected(GLenum srcFormat, int testChan, exp[3] = testChan == 1 ? 255 : 0; break; case GL_RGB: - exp[0] = - exp[1] = + exp[0] = + exp[1] = exp[2] = testChan == 0 ? 255 : 0; exp[3] = defaultAlpha; // fragment alpha or texture alpha break; @@ -1131,8 +1131,8 @@ PixelFormatsTest::ComputeExpected(GLenum srcFormat, int testChan, exp[3] = testChan == 1 ? 255 : 0; break; case GL_LUMINANCE: - exp[0] = - exp[1] = + exp[0] = + exp[1] = exp[2] = testChan == 0 ? 255 : 0; exp[3] = defaultAlpha; // fragment alpha or texture alpha break; @@ -1202,7 +1202,7 @@ PixelFormatsTest::CheckRendering(int width, int height, int comp, sprintf(msg, " Expected: 0x%02x 0x%02x 0x%02x 0x%02x\n", expected[0], expected[1], expected[2], expected[3]); env->log << msg; - sprintf(msg, " Found: 0x%02x 0x%02x 0x%02x 0x%02x\n", + sprintf(msg, " Found: 0x%02x 0x%02x 0x%02x 0x%02x\n", image[i + 0], image[i + 1], image[i + 2], image[i + 3]); env->log << msg; ok = false; diff --git a/tests/glean/tpointsprite.cpp b/tests/glean/tpointsprite.cpp index c098d915..280984c2 100644 --- a/tests/glean/tpointsprite.cpp +++ b/tests/glean/tpointsprite.cpp @@ -40,12 +40,13 @@ */ #define GL_GLEXT_PROTOTYPES -#include "tpointsprite.h" + +#include <stdlib.h> #include <cassert> #include <cmath> -#include <cstring> -#include <cstdio> -#include <cstdlib> +#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 00000000..643bb621 --- /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 00000000..e1fc9c1d --- /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 00000000..d0c783a8 --- /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 00000000..8c332cda --- /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 00000000..1173d523 --- /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 00000000..f6d323ee --- /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 9f593c49..930d6b73 100644 --- a/tests/glean/ttexenv.cpp +++ b/tests/glean/ttexenv.cpp @@ -40,11 +40,13 @@ // post-texture alpha value is correct. // -#include "ttexenv.h" +#include <stdlib.h> #include <cassert> #include <cstdio> #include <cstdlib> #include <cmath> +#include "ttexenv.h" + namespace GLEAN { diff --git a/tests/glean/ttexswizzle.cpp b/tests/glean/ttexswizzle.cpp new file mode 100644 index 00000000..6bd1304a --- /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 00000000..efe39414 --- /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 b125976e..4fa5b9d1 100644 --- a/tests/glean/ttexture_srgb.cpp +++ b/tests/glean/ttexture_srgb.cpp @@ -30,11 +30,12 @@ // Brian Paul August 2006 -#include "ttexture_srgb.h" -#include "rand.h" #include <cassert> -#include <cmath> #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 00000000..e84c94e1 --- /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 00000000..803c515b --- /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 00000000..737af0c4 --- /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 00000000..2b3a1184 --- /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 7338b8f2..6dadf904 100644 --- a/tests/glean/tvertattrib.cpp +++ b/tests/glean/tvertattrib.cpp @@ -45,14 +45,11 @@ // Author: Brian Paul (brian.paul a t tungstengraphics.com) October 2004 -#include <cmath> -#ifdef __CYGWIN__ -#undef log2 -#endif -#include <cstdlib> +#include <stdlib.h> +#include <cassert> +#include <math.h> #include "tvertattrib.h" #include "glutils.h" -#include <cassert> namespace GLEAN { |