[Piglit] [PATCH] texturing: Add test unpack-teximage2d

Chad Versace chad.versace at linux.intel.com
Thu Oct 11 20:13:13 PDT 2012


Add four tests for testing the unpacking state with glTexImage2D.
    unpack-teximage2d pbo=0 format=GL_RGBA
    unpack-teximage2d pbo=1 format=GL_RGBA
    unpack-teximage2d pbo=0 format=GL_BGRA
    unpack-teximage2d pbo=1 format=GL_BGRA

The tests randomly explore, with a fixed seed, the correctness of
glTexImage2D over the combinatorial space of pixel unpacking state.

On Intel gen6 with mesa-34c58ac, the RGBA tests pass and the BGRA tests
fail.

CC: Rob Bradford <rob at linux.intel.com>
CC: Neil Roberts <neil at linux.intel.com>
Signed-off-by: Chad Versace <chad.versace at linux.intel.com>
---
 tests/all.tests                     |   5 +
 tests/texturing/CMakeLists.gl.txt   |   1 +
 tests/texturing/unpack-teximage2d.c | 477 ++++++++++++++++++++++++++++++++++++
 3 files changed, 483 insertions(+)
 create mode 100644 tests/texturing/unpack-teximage2d.c

diff --git a/tests/all.tests b/tests/all.tests
index 964c84c..01b2c5f 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -765,6 +765,11 @@ add_plain_test(texturing, 'texture-al')
 add_plain_test(texturing, 'texture-packed-formats')
 add_plain_test(texturing, 'texture-rg')
 add_plain_test(texturing, 'tex-srgb')
+texturing['unpack-teximage2d pbo=0 format=GL_RGBA'] = concurrent_test(texturing, 'unpack-teximage2d --pbo=0 --format=GL_RGBA')
+texturing['unpack-teximage2d pbo=1 format=GL_RGBA'] = concurrent_test(texturing, 'unpack-teximage2d --pbo=1 --format=GL_RGBA')
+texturing['unpack-teximage2d pbo=0 format=GL_BGRA'] = concurrent_test(texturing, 'unpack-teximage2d --pbo=0 --format=GL_BGRA')
+texturing['unpack-teximage2d pbo=1 format=GL_BGRA'] = concurrent_test(texturing, 'unpack-teximage2d --pbo=1 --format=GL_BGRA')
+add_concurrent_test(texturing, 'unpack-2d --pbo=0 --format=GL_RGBA')
 
 # Note: the buffer sizes of 146, 292, 585, and 1024 hav been chosen to
 # exercise all possible combinations of buffer alignments on i965.
diff --git a/tests/texturing/CMakeLists.gl.txt b/tests/texturing/CMakeLists.gl.txt
index 8567fa8..1cbd7b8 100644
--- a/tests/texturing/CMakeLists.gl.txt
+++ b/tests/texturing/CMakeLists.gl.txt
@@ -70,6 +70,7 @@ piglit_add_executable (texrect-many texrect-many.c)
 piglit_add_executable (texredefine texredefine.c)
 piglit_add_executable (texture-packed-formats texture-packed-formats.c)
 piglit_add_executable (texwrap texwrap.c)
+piglit_add_executable (unpack-teximage2d unpack-teximage2d.c)
 piglit_add_executable (depth-tex-modes      depth-tex-modes.c depth-tex-modes-common.c)
 piglit_add_executable (depth-tex-modes-rg   depth-tex-modes-rg.c depth-tex-modes-common.c)
 piglit_add_executable (depth-tex-modes-glsl depth-tex-modes-glsl.c)
diff --git a/tests/texturing/unpack-teximage2d.c b/tests/texturing/unpack-teximage2d.c
new file mode 100644
index 0000000..ade9f0f
--- /dev/null
+++ b/tests/texturing/unpack-teximage2d.c
@@ -0,0 +1,477 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file
+ * \brief Tests pixel unpacking state with glTexImage2D.
+ *
+ * This test randomly explores, with a fixed seed, the correctness of
+ * glTexImage2D over the combinatorial space of pixel unpacking state. In
+ * addition to choosing random unpacking state, the test also chooses random
+ * texture dimensions (the former is not very interesting without the latter).
+ *
+ * There are two pieces of state chosen by command line arguments:
+ *      - to upload the texture image from client memory or a pixel buffer
+ *      - which texture format to use
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 10;
+
+	config.window_width = 100;
+	config.window_height = 100;
+	config.window_visual = PIGLIT_GL_VISUAL_RGBA;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+static const char *usage_text =
+	"usage:\n"
+	"    unpack-teximage2d --pbo=<0|1> --format=<GL_RGBA|GL_BGRA>\n"
+	"\n"
+	"If pbo is 0, then glTexImage2D uploads client memory.\n"
+	"If pbo is 1, then glTexImage2D uploads a pixel buffer object.\n"
+	"\n"
+	"Set env var PIGLIT_DEBUG=1 to print debug info.\n"
+	;
+
+static int rand_seed = 1;
+static bool use_pbo;
+static GLenum tex_format;
+
+static GLuint tex;
+static GLuint pbo;
+
+/* Assume GL_RGBA or GL_BGRA with GL_UNSIGNED_BYTE. */
+#define PIXEL_SIZE 4
+
+/* TEX_DATA_SIZE is significantly greater than PIXEL_SIZE*MAX_TEX_WIDTH^2 in order to
+ * allow room for GL_UNPACK_SKIP_* and subtest::tex_offset.
+ */
+#define MAX_TEX_WIDTH (1 << 6)
+#define TEX_DATA_SIZE (PIXEL_SIZE * (1 << 16))
+static uint8_t tex_data[TEX_DATA_SIZE];
+
+struct subtest {
+	int tex_width;
+	int tex_height;
+
+	/**
+	 * Offset into tex_data or into the pbo.
+	 */
+	intptr_t tex_offset;
+
+	/**
+	 * See Table 4.5 of the GL 2.1 spec.
+	 */
+	struct unpack_state {
+		bool swap_bytes;
+		bool lsb_first;
+		int row_length;
+		int skip_rows;
+		int skip_pixels;
+		int alignment;
+	} unpack;
+};
+
+static void
+usage_error(void)
+{
+	printf("%s", usage_text);
+	piglit_report_result(PIGLIT_FAIL);
+}
+
+static int
+randi(int min, int max)
+{
+	return (double) (max - min) * rand() / RAND_MAX + min;
+}
+
+static void
+logd(const char *format, ...)
+{
+	static int debug = -1;
+	va_list va;
+
+	if (debug == -1) {
+		const char *env = getenv("PIGLIT_DEBUG");
+		if (env == NULL) {
+			debug = 0;
+		} else if (strcmp(env, "0") == 0) {
+			debug = 0;
+		} else if (strcmp(env, "1") == 0) {
+			debug = 1;
+		} else {
+			printf("env var PIGLIT_DEBUG has bad value \"%s\"\n", env);
+			piglit_report_result(PIGLIT_FAIL);
+		}
+	}
+
+	if (debug == 0)
+		return;
+
+	va_start(va, format);
+	printf("piglit: debug: ");
+	vprintf(format, va);
+	va_end(va);
+}
+
+static void
+randomize_subtest(struct subtest *subtest)
+{
+	int row_length;
+
+	subtest->tex_width = randi(1, MAX_TEX_WIDTH);
+	subtest->tex_height = randi(1, MAX_TEX_WIDTH);
+
+	/* Assume that tex_format is GL_RGBA or GL_BGRA. Then tex_offset needs
+	 * to be divisible by 4.
+	 *
+	 * From page 127 (141 of pdf) of the GL 2.1 spec:
+	 *     If a pixel unpack buffer object is bound and data is not evenly
+	 *     divisible by the number of basic machine units needed to store
+	 *     in memory the corresponding GL data type from table 3.5 for the
+	 *     type parameter, an INVALID OPERATION error results.
+	 */
+	subtest->tex_offset = 4 * randi(0, MAX_TEX_WIDTH);
+
+	/* From page 131 (145 of pdf) of the GL 2.1 spec:
+	 *    If the value of UNPACK ROW LENGTH is not positive, then the
+	 *    number of groups in a row is width; otherwise the number of
+	 *    groups is UNPACK ROW LENGTH.
+	 */
+	if (rand() % 17 == 0) {
+		subtest->unpack.row_length = 0;
+		row_length = subtest->tex_width;
+	} else {
+		subtest->unpack.row_length = randi(subtest->tex_width,
+						   4 * subtest->tex_width);
+		row_length = subtest->unpack.row_length;
+	}
+
+	subtest->unpack.skip_rows = randi(0, 4 * subtest->tex_height);
+	subtest->unpack.skip_pixels = randi(0, row_length - subtest->tex_width);
+	subtest->unpack.alignment = 1 << randi(0, 3);
+
+	/* This test does not yet support the following unpacking state. */
+	subtest->unpack.lsb_first = false;
+	subtest->unpack.swap_bytes = false;
+
+	/* Indent underneath "subtest %d:\n". */
+	logd("    tex_width:         %d\n", subtest->tex_width);
+	logd("    tex_height:        %d\n", subtest->tex_height);
+	logd("    tex_offset:        %d\n", subtest->tex_offset);
+	logd("    unpack:\n");
+	logd("        row_length:    %d\n", subtest->unpack.row_length);
+	logd("        skip_rows:     %d\n", subtest->unpack.skip_rows);
+	logd("        skip_pixels:   %d\n", subtest->unpack.skip_pixels);
+	logd("        alignment:     %d\n", subtest->unpack.alignment);
+	logd("        lsb_first:     %d\n", subtest->unpack.lsb_first);
+	logd("        swap_bytes:    %d\n", subtest->unpack.swap_bytes);
+}
+
+static void
+set_unpack_state(const struct subtest *subtest)
+{
+	glPixelStorei(GL_UNPACK_SWAP_BYTES,     subtest->unpack.swap_bytes);
+	glPixelStorei(GL_UNPACK_LSB_FIRST,      subtest->unpack.lsb_first);
+	glPixelStorei(GL_UNPACK_ROW_LENGTH,     subtest->unpack.row_length);
+	glPixelStorei(GL_UNPACK_SKIP_ROWS,      subtest->unpack.skip_rows);
+	glPixelStorei(GL_UNPACK_SKIP_PIXELS,    subtest->unpack.skip_pixels);
+	glPixelStorei(GL_UNPACK_ALIGNMENT,      subtest->unpack.alignment);
+
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		piglit_report_result(PIGLIT_FAIL);
+}
+
+static void
+load_tex_data(const struct subtest *subtest)
+{
+	const void *data;
+
+	if (use_pbo)
+		data = NULL;
+	else
+		data = tex_data;
+
+	data += subtest->tex_offset;
+
+	glTexImage2D(GL_TEXTURE_2D,
+		     0 /*level*/,
+		     GL_RGBA,
+		     subtest->tex_width,
+		     subtest->tex_height,
+		     0 /*border*/,
+		     tex_format /*format*/,
+		     GL_UNSIGNED_BYTE,
+		     data);
+
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		piglit_report_result(PIGLIT_FAIL);
+}
+
+static void
+tex_pixel_to_rgba(const GLubyte *tex_pixel, GLfloat rgba_pixel[4])
+{
+    switch (tex_format) {
+	    case GL_RGBA:
+		    rgba_pixel[0] = tex_pixel[0] / 255.0;
+		    rgba_pixel[1] = tex_pixel[1] / 255.0;
+		    rgba_pixel[2] = tex_pixel[2] / 255.0;
+		    rgba_pixel[3] = tex_pixel[3] / 255.0;
+		    break;
+	    case GL_BGRA:
+		    rgba_pixel[0] = tex_pixel[2] / 255.0;
+		    rgba_pixel[1] = tex_pixel[1] / 255.0;
+		    rgba_pixel[2] = tex_pixel[0] / 255.0;
+		    rgba_pixel[3] = tex_pixel[3] / 255.0;
+		    break;
+	    default:
+		    assert(0);
+		    break;
+    }
+}
+
+static bool
+probe_texels(const struct subtest *subtest)
+{
+	/* The base address of the total image in Figure 3.8 of the GL 2.1
+	 * spec.
+	 */
+	const void *tex_base;
+
+	/* The texel currently being probed. */
+	int y;
+	int x;
+
+	/* The single-letter variable names below are those found in equations
+	 * 3.12 and 3.13 on page 131 (145 of pdf) of the GL 2.1 spec.
+	 */
+
+	 /* Size of an element, in GLubytes. That is, the number of bytes in
+	  * one channel of the pixel. Assume that the texture data type is
+	  * GL_UNSIGNED_BYTE.
+	  */
+	const int s = 1;
+
+	 /* Number of elements in a group. That is, the number of channels in
+	  * a pixel. Assume that the texture format is GL_RGBA or GL_BGRA.
+	  */
+	const int n = 4;
+
+	const int a = subtest->unpack.alignment;
+
+	/* Row length, in pixels. */
+	int l;
+
+	/* Stride, defined by equation 3.13. */
+	int k;
+
+	 /* Location of first element in first row. That is, the base
+	  * address of the subimage in Figure 3.8.
+	  */
+	const void *p;
+
+	const int pixel_size = n * s;
+
+	/* The test does not yet support the following unpacking state. */
+	assert(!subtest->unpack.swap_bytes);
+	assert(!subtest->unpack.lsb_first);
+
+	tex_base = (const void*) tex_data + subtest->tex_offset;
+
+	/* From page 131 (145 of pdf) of the GL 2.1 spec:
+	 *    If the value of UNPACK ROW LENGTH is not positive, then the
+	 *    number of groups in a row is width; otherwise the number of
+	 *    groups is UNPACK ROW LENGTH.
+	 */
+	if (subtest->unpack.row_length <= 0)
+		l = subtest->tex_width;
+	else
+		l = subtest->unpack.row_length;
+
+	for (y = 0; y < subtest->tex_height; ++y) {
+		/* Location of first element in the current row. Defined by equation 3.12. */
+		const void *row_base;
+
+		p = tex_base
+		  + pixel_size * l * subtest->unpack.skip_rows
+		  + pixel_size * subtest->unpack.skip_pixels;
+
+		/* Equation 3.13 from the GL 2.1 spec.
+		 *
+		 * This equation does not apply to all texture formats. From
+		 * the same page as the equation:
+		 *     If the number of bits per element is not 1, 2, 4, or
+		 *     8 times the number of bits in a GL ubyte, then k = nl
+		 *     for all values of a.
+		 */
+		if (s >= subtest->unpack.alignment) {
+			k = n * l;
+		} else {
+			k = (a / s) * (int) ceilf((float) s * n * l / a);
+		}
+
+		/* Equation 3.12 from the GL 2.1 spec. */
+		row_base = p + y * k;
+
+		for (x = 0; x < subtest->tex_width; ++x) {
+			const int image_x = (double) piglit_width * (x + 0.5) / subtest->tex_width;
+			const int image_y = (double) piglit_height * (y + 0.5) / subtest->tex_height;
+			const GLubyte *tex_pixel = row_base + pixel_size * x;
+			float rgba_pixel[4];
+
+			tex_pixel_to_rgba(tex_pixel, rgba_pixel);
+
+			if (!piglit_probe_pixel_rgba(image_x, image_y,
+						     rgba_pixel)) {
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
+static bool
+run_subtest(void)
+{
+	bool pass = true;
+	struct subtest subtest;
+
+	randomize_subtest(&subtest);
+	set_unpack_state(&subtest);
+	load_tex_data(&subtest);
+	glClear(GL_COLOR_BUFFER_BIT);
+	piglit_draw_rect_tex(-1, -1, 2, 2,
+			     0, 0, 1, 1);
+	pass = probe_texels(&subtest);
+	piglit_present_results();
+
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		piglit_report_result(PIGLIT_FAIL);
+
+	return pass;
+}
+
+static void
+parse_args(int argc, char *argv[])
+{
+	int i;
+
+	bool found_pbo = false;
+	bool found_format = false;
+
+	for (i = 1; i < argc; ++i) {
+		const char *arg = argv[i];
+
+		if (strcmp(arg, "--pbo=0") == 0) {
+			found_pbo = true;
+			use_pbo = false;
+		} else if (strcmp(arg, "--pbo=1") == 0) {
+			found_pbo = true;
+			use_pbo = true;
+		} else if (strcmp(arg, "--format=GL_RGBA") == 0) {
+			found_format = true;
+			tex_format = GL_RGBA;
+		} else if (strcmp(arg, "--format=GL_BGRA") == 0) {
+			found_format= true;
+			tex_format = GL_BGRA;
+		} else if (strncmp(arg, "--seed=", 7) == 0) {
+			rand_seed = strtod(arg + 7, NULL);
+		} else {
+			printf("unrecognized argument: %s\n", arg);
+			usage_error();
+		}
+	}
+
+	if (!found_pbo || !found_format) {
+		usage_error();
+	}
+}
+
+void
+piglit_init(int argc, char *argv[])
+{
+	int i;
+
+	parse_args(argc, argv);
+
+	srand(rand_seed);
+	piglit_require_gl_version(21);
+	glClearColor(0.5, 0.5, 0.5, 1.0);
+
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_2D, tex);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0);
+	glEnable(GL_TEXTURE_2D);
+
+	/* Fill tex_data with random pixels. */
+	for (i = 0; i < TEX_DATA_SIZE; ++i) {
+		if (i % 4 == 3) {
+			/* alpha channel */
+			tex_data[i] = 0xff;
+		} else {
+			/* rgb channels */
+			tex_data[i] = randi(0, 255);
+		}
+	}
+
+	if (use_pbo) {
+		glGenBuffers(1, &pbo);
+		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
+		glBufferData(GL_PIXEL_UNPACK_BUFFER, TEX_DATA_SIZE, tex_data,
+			     GL_STATIC_DRAW);
+	}
+
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		piglit_report_result(PIGLIT_FAIL);
+}
+
+enum piglit_result
+piglit_display(void)
+{
+	bool pass = true;
+	const int num_subtests = 256;
+	int i;
+
+	/* We reset the random seed for each call to piglit_display() so that
+	 * the testrun is consistent.
+	 */
+	srand(rand_seed);
+
+	for (i = 0; i < num_subtests; ++i) {
+		logd("subtest %d:\n", i);
+		pass &= run_subtest();
+	}
+
+	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
+}
-- 
1.7.11.7



More information about the Piglit mailing list