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 <r...@linux.intel.com> CC: Neil Roberts <n...@linux.intel.com> Signed-off-by: Chad Versace <chad.vers...@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 _______________________________________________ Piglit mailing list Piglit@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/piglit