[Piglit] [PATCH 1/2] Ported the read pixels sanity test from Glean to Piglit.

Laura Ekstrand laura at jlekstrand.net
Fri Oct 17 14:24:54 PDT 2014


---
 tests/all.py                        |   1 +
 tests/spec/gl-1.0/CMakeLists.gl.txt |   1 +
 tests/spec/gl-1.0/readpix.c         | 381 ++++++++++++++++++++++++++++++++++++
 3 files changed, 383 insertions(+)
 create mode 100644 tests/spec/gl-1.0/readpix.c

diff --git a/tests/all.py b/tests/all.py
index 8bfc84e..6c5588a 100644
--- a/tests/all.py
+++ b/tests/all.py
@@ -793,6 +793,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/spec/gl-1.0/CMakeLists.gl.txt b/tests/spec/gl-1.0/CMakeLists.gl.txt
index 1ed735d..11bd581 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 0000000..dca4bb1
--- /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>
+
+#define window_size 32
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 13;
+
+	config.window_width = window_size;
+	config.window_height = window_size;
+
+	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[window_size][window_size][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 use it to 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, window_size,
+			window_size, GL_RGBA, GL_FLOAT, buf);
+
+		/*
+		 * Now compute the error for each pixel, and record the
+		 * worst one we find:
+		 */
+		for (y = 0; y < window_size; ++y) {
+			for (x = 0; x < window_size; ++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[window_size][window_size];
+	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 use it to 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, window_size,
+			window_size, 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 < window_size; ++y) {
+			for (x = 0; x < window_size; ++x) {
+				dd = abs(buf[y][x]/4294967295.0 /* Why the big number? */
+					- 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[window_size][window_size];
+	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, window_size,
+			window_size, GL_STENCIL_INDEX,
+			GL_UNSIGNED_INT, buf);
+		pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+		for (y = 0; y < window_size && pass; ++y) {
+			for (x = 0; x < window_size; ++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 */
-- 
2.1.0



More information about the Piglit mailing list