summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaura Ekstrand <laura@jlekstrand.net>2014-10-16 12:22:40 -0700
committerLaura Ekstrand <laura@jlekstrand.net>2014-10-28 15:12:19 -0700
commit0d0492b7cbbe38b2a9197f26d7a7cf230a144b1a (patch)
treeb61e3fe9eb6f44d5731f8b9c8dbd34a959bec75c
parent5af73e9d451574f110c474363c1d51bb80aae2b1 (diff)
Ported the read pixels sanity test from Glean to Piglit.
-rw-r--r--tests/all.py1
-rw-r--r--tests/sanity.py7
-rw-r--r--tests/spec/gl-1.0/CMakeLists.gl.txt1
-rw-r--r--tests/spec/gl-1.0/readpix.c381
4 files changed, 387 insertions, 3 deletions
diff --git a/tests/all.py b/tests/all.py
index 8ee94f463..4b56e4b03 100644
--- a/tests/all.py
+++ b/tests/all.py
@@ -802,6 +802,7 @@ add_concurrent_test(gl10, 'gl-1.0-polygon-line-aa')
add_concurrent_test(gl10, 'gl-1.0-blend-func')
add_concurrent_test(gl10, 'gl-1.0-fpexceptions')
add_concurrent_test(gl10, 'gl-1.0-ortho-pos')
+add_concurrent_test(gl10, 'gl-1.0-readpixsanity')
gl12 = {}
spec['!OpenGL 1.2'] = gl12
diff --git a/tests/sanity.py b/tests/sanity.py
index db07447b4..eb246e682 100644
--- a/tests/sanity.py
+++ b/tests/sanity.py
@@ -3,10 +3,11 @@
#
from framework.profile import TestProfile
-from framework.test import GleanTest
+from framework.test import PiglitGLTest
__all__ = ['profile']
profile = TestProfile()
-profile.tests['glean/basic'] = GleanTest('basic')
-profile.tests['glean/readPixSanity'] = GleanTest('readPixSanity')
+
+profile.tests['spec/!OpenGL 1.0/gl-1.0-readpixsanity'] = \
+ PiglitGLTest('gl-1.0-readpixsanity', run_concurrent=True)
diff --git a/tests/spec/gl-1.0/CMakeLists.gl.txt b/tests/spec/gl-1.0/CMakeLists.gl.txt
index 1ed735d05..11bd58178 100644
--- a/tests/spec/gl-1.0/CMakeLists.gl.txt
+++ b/tests/spec/gl-1.0/CMakeLists.gl.txt
@@ -23,5 +23,6 @@ piglit_add_executable (gl-1.0-polygon-line-aa polygon-line-aa.c)
piglit_add_executable (gl-1.0-blend-func blend.c)
piglit_add_executable (gl-1.0-ortho-pos orthpos.c)
piglit_add_executable (gl-1.0-fpexceptions fpexceptions.c)
+piglit_add_executable (gl-1.0-readpixsanity readpix.c)
# vim: ft=cmake:
diff --git a/tests/spec/gl-1.0/readpix.c b/tests/spec/gl-1.0/readpix.c
new file mode 100644
index 000000000..ab728068d
--- /dev/null
+++ b/tests/spec/gl-1.0/readpix.c
@@ -0,0 +1,381 @@
+/*
+ * BEGIN_COPYRIGHT -*- glean -*-
+ *
+ * Copyright (C) 2001 Allen Akin All Rights Reserved.
+ * Copyright (C) 2014 Intel Corporation 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 (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * END_COPYRIGHT
+ */
+
+/** @file readpix.c
+ *
+ * Checks to make sure glReadPixels is functioning properly.
+ *
+ * This test performs a sanity check of glReadPixels, using as
+ * few other portions of the GL as possible. If this test fails,
+ * it may be pointless to run other tests, since so many of them
+ * depend on reading the contents of the framebuffer to determine
+ * if they pass.
+ *
+ * The test works by using glClear to fill the framebuffer with a
+ * randomly-chosen value, reading the contents of the
+ * framebuffer, and comparing the actual contents with the
+ * expected contents. RGB, RGBA, color index, stencil, and depth
+ * buffers (whichever are applicable to the current rendering
+ * context) are checked. The test passes if the actual contents
+ * are within 1 LSB of the expected contents.
+ */
+
+#include "piglit-util-gl.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <assert.h>
+
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+ config.supports_gl_compat_version = 13;
+
+ config.window_visual = PIGLIT_GL_VISUAL_RGBA |
+ PIGLIT_GL_VISUAL_DOUBLE |
+ PIGLIT_GL_VISUAL_STENCIL | PIGLIT_GL_VISUAL_DEPTH;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+void
+piglit_init(int argc, char **argv)
+{
+ srand(0);
+} /* piglit_init */
+
+/** Returns a float in the range [0.0, 1.0]. */
+float
+random_float(void)
+{
+ return (float) rand() / RAND_MAX;
+}
+
+/** Computes log base 2 (copied from Glean's misc.cpp) */
+double
+log2(double x)
+{
+ return 1.4426950408889634 * log(x);
+}
+
+/**
+ * (Copied from Glean's misc.cpp.)
+ * Utility routine to compute error, expressed in bits
+ * Typically used to convert a floating-point error (in the range [0,1])
+ * to the number of bits in the representation of a color.
+ */
+double
+error_bits(double abs_error, int rep_bits) {
+ double log2_error;
+ if (abs_error <= 0.0)
+ return 0.0;
+ log2_error = log2(abs_error) + rep_bits;
+ return (log2_error <= 0.0)? 0.0: log2_error;
+} /* error_bits */
+
+bool
+check_rgba(void)
+{
+ int i, x, y, j;
+ int thresh = 1;
+ bool pass = true;
+ double current_error = 0.0;
+ double err;
+ int xerr, yerr;
+ float expected[4], expected_rgba[4], actual_rgba[4];
+ GLfloat buf[piglit_width][piglit_height][4];
+ GLfloat dr, dg, db, da;
+ GLint rbits, gbits, bbits, abits;
+ glGetIntegerv(GL_RED_BITS, &rbits);
+ glGetIntegerv(GL_GREEN_BITS, &gbits);
+ glGetIntegerv(GL_BLUE_BITS, &bbits);
+ glGetIntegerv(GL_ALPHA_BITS, &abits);
+
+ for (i = 0; i < 100 && pass; ++i) {
+ /* Generate a random color and clear the color buffer: */
+ expected[0] = random_float();
+ expected[1] = random_float();
+ expected[2] = random_float();
+ expected[3] = random_float();
+ glClearColor(expected[0], expected[1],
+ expected[2], expected[3]);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* Read the buffer: */
+ glReadPixels(0, 0, piglit_width,
+ piglit_height, GL_RGBA, GL_FLOAT, buf);
+
+ /*
+ * Now compute the error for each pixel, and record the
+ * worst one we find:
+ */
+ for (y = 0; y < piglit_height; ++y) {
+ for (x = 0; x < piglit_width; ++x) {
+ dr = fabs(buf[y][x][0] - expected[0]);
+ dg = fabs(buf[y][x][1] - expected[1]);
+ db = fabs(buf[y][x][2] - expected[2]);
+ da = fabs(buf[y][x][3] - expected[3]);
+ err =
+ fmax(error_bits(dr, rbits),
+ fmax(error_bits(dg, gbits),
+ fmax(error_bits(db, bbits),
+ error_bits(da,
+ abits? abits: thresh+1))));
+ /*
+ * The "thresh+1" fudge above is
+ * needed to force the error to
+ * be greater than the threshold
+ * in the case where there is no
+ * alpha channel. Without it the
+ * error would be just equal to
+ * the threshold, and the test
+ * would spuriously pass.
+ */
+ if (err > current_error) {
+ current_error = err;
+ xerr = x;
+ yerr = y;
+ for (j = 0; j < 4; ++j) {
+ expected_rgba[j] =
+ expected[j];
+ actual_rgba[j] =
+ buf[y][x][j];
+ }
+ }
+ }
+ }
+
+ if (current_error > thresh)
+ pass = false;
+
+ /* Show the image */
+ if (!piglit_automatic) {
+ piglit_present_results();
+ }
+ }
+
+ if (!pass) {
+ printf("\tRGB(A) worst-case error was %f bits at (%i, %i)\n",
+ current_error, xerr, yerr);
+ printf("\t\texpected (%f, %f, %f, %f)\n",
+ expected_rgba[0],
+ expected_rgba[1],
+ expected_rgba[2],
+ expected_rgba[3]);
+ printf("\t\tgot (%f, %f, %f, %f)\n",
+ actual_rgba[0],
+ actual_rgba[1],
+ actual_rgba[2],
+ actual_rgba[3]);
+
+ }
+
+ return pass;
+} /* check_rgba */
+
+bool
+check_depth(void)
+{
+ int i, x, y;
+ int thresh = 1;
+ bool pass = true;
+ GLdouble expected, expected_depth, actual_depth;
+ GLuint buf[piglit_width][piglit_height];
+ double current_error = 0.0;
+ GLfloat dd;
+ double err;
+ int xerr, yerr;
+ GLint dbits;
+ glGetIntegerv(GL_DEPTH_BITS, &dbits);
+
+ for (i = 0; i < 100 && pass; ++i) {
+ /* Generate a random depth and clear the depth buffer */
+ expected = random_float();
+ glClearDepth(expected);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ /*
+ * Because glReadPixels won't return data of type GLdouble,
+ * there's no straightforward portable way to deal with
+ * integer depth buffers that are deeper than 32 bits or
+ * floating-point depth buffers that have higher precision
+ * than a GLfloat. Since this is just a sanity check, we'll
+ * use integer readback and settle for 32 bits at best.
+ */
+ glReadPixels(0, 0, piglit_width,
+ piglit_height, GL_DEPTH_COMPONENT,
+ GL_UNSIGNED_INT, buf);
+
+ /*
+ * Now compute the error for each pixel, and record the
+ * worst one we find:
+ */
+ for (y = 0; y < piglit_height; ++y) {
+ for (x = 0; x < piglit_width; ++x) {
+ dd = abs(buf[y][x]/4294967295.0
+ - expected);
+ err = error_bits(dd, dbits);
+ if (err > current_error) {
+ current_error = err;
+ xerr = x;
+ yerr = y;
+ expected_depth = expected;
+ actual_depth = buf[y][x]/4294967295.0;
+ }
+ }
+ }
+
+ if (current_error > thresh)
+ pass = false;
+
+ /* Show the image */
+ if (!piglit_automatic) {
+ piglit_present_results();
+ }
+ }
+
+ if (!pass) {
+ printf("\tDepth worst-case error was %f bits at (%i, %i)\n",
+ current_error, xerr, yerr);
+ printf("\t\texpected %f; got %f.\n", expected_depth,
+ actual_depth);
+ }
+
+ return pass;
+} /* check_depth */
+
+/** Generate a random number with the number of bits specified */
+unsigned int
+random_bits(unsigned int bits)
+{
+ assert(bits <= 32);
+ assert(bits > 0);
+ if (bits == 32)
+ return rand();
+ else
+ return rand() % (1 << bits);
+}
+
+bool
+check_stencil(void)
+{
+ int i, x, y;
+ bool pass = true;
+ GLuint buf[piglit_width][piglit_height];
+ GLuint expected;
+ GLint sbits;
+ glGetIntegerv(GL_STENCIL_BITS, &sbits);
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+ for (i = 0; i < 100 && pass; ++i) {
+ expected = random_bits(sbits);
+ glClearStencil(expected);
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+ glReadPixels(0, 0, piglit_width,
+ piglit_height, GL_STENCIL_INDEX,
+ GL_UNSIGNED_INT, buf);
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+ for (y = 0; y < piglit_height && pass; ++y) {
+ for (x = 0; x < piglit_width; ++x) {
+ if (buf[y][x] != expected) {
+ pass = false;
+ break;
+ }
+ }
+ }
+
+ /* Show the image */
+ if (!piglit_automatic) {
+ piglit_present_results();
+ }
+ }
+
+ if (!pass) {
+ printf("\tStencil failed at (%i, %i).\n",
+ x, y);
+ printf("\t\tExpected %i; got %i.\n",
+ expected, buf[y][x]);
+ }
+
+ return pass;
+} /* check_stencil */
+
+enum piglit_result
+piglit_display(void)
+{
+ /*
+ * Many (if not most) other tests need to read the contents of
+ * the framebuffer to determine if the correct image has been
+ * drawn. Obviously this is a waste of time if the basic
+ * functionality of glReadPixels isn't working.
+ *
+ * This test does a "sanity" check of glReadPixels. Using as
+ * little of the GL as practicable, it writes a random value
+ * in the framebuffer, reads it, and compares the value read
+ * with the value written.
+ */
+ bool pass = true;
+
+ glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE);
+ glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
+ glPixelTransferi(GL_MAP_STENCIL, GL_FALSE);
+ glPixelTransferi(GL_INDEX_SHIFT, 0);
+ glPixelTransferi(GL_INDEX_OFFSET, 0);
+ glPixelTransferf(GL_RED_SCALE, 1.0);
+ glPixelTransferf(GL_GREEN_SCALE, 1.0);
+ glPixelTransferf(GL_BLUE_SCALE, 1.0);
+ glPixelTransferf(GL_ALPHA_SCALE, 1.0);
+ glPixelTransferf(GL_DEPTH_SCALE, 1.0);
+ glPixelTransferf(GL_RED_BIAS, 0.0);
+ glPixelTransferf(GL_GREEN_BIAS, 0.0);
+ glPixelTransferf(GL_BLUE_BIAS, 0.0);
+ glPixelTransferf(GL_ALPHA_BIAS, 0.0);
+ glPixelTransferf(GL_DEPTH_BIAS, 0.0);
+
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_DITHER);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_TRUE);
+ glStencilMask(~0);
+
+ pass &= check_rgba();
+ pass &= check_depth();
+ pass &= check_stencil();
+
+ return pass ? PIGLIT_PASS : PIGLIT_FAIL;
+} /* piglit_display */