[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