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

Brian Paul brianp at vmware.com
Fri Oct 12 07:25:53 PDT 2012


On 10/11/2012 09:13 PM, Chad Versace wrote:
> 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).

This is good, but I think another common scenario would be using 
glTexSubImage2D() with non-default pixel unpacking state to update a 
subregion of a texture image from a subregion of a source image.


> + *
> + * 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;

Could you put a final cast to int in there?  Otherwise MSVC will 
complain about an implicit double->int conversion.


> +}
> +
> +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;
> +}

Looks good.  The comments are very helpful.

Reviewed-by: Brian Paul <brianp at vmware.com>


More information about the Piglit mailing list