diff options
author | Nicolai Hähnle <nicolai.haehnle@amd.com> | 2016-01-12 16:11:23 -0500 |
---|---|---|
committer | Nicolai Hähnle <nicolai.haehnle@amd.com> | 2016-02-03 15:01:37 +0100 |
commit | eb5532dfaa8b3e3fe73a8bab44784dd5c5007883 (patch) | |
tree | ff060abde3081d532b0f726f0a240abf25fed878 /tests/texturing | |
parent | 47c428754c27bb38dc8fda35c845cbc6283c9601 (diff) |
Add texturing/texsubimage-unpack
This is similar to the texsubimage test, but checks various type and format
conversions as well as a different set of pixel unpack settings.
v2: cleanups and share some code with texsubimage
Diffstat (limited to 'tests/texturing')
-rw-r--r-- | tests/texturing/CMakeLists.gl.txt | 1 | ||||
-rw-r--r-- | tests/texturing/texsubimage-unpack.c | 525 |
2 files changed, 526 insertions, 0 deletions
diff --git a/tests/texturing/CMakeLists.gl.txt b/tests/texturing/CMakeLists.gl.txt index c344cdf60..e41d3c990 100644 --- a/tests/texturing/CMakeLists.gl.txt +++ b/tests/texturing/CMakeLists.gl.txt @@ -91,6 +91,7 @@ IF (UNIX) target_link_libraries (tex-srgb m) ENDIF (UNIX) piglit_add_executable (texsubimage texsubimage.c) +piglit_add_executable (texsubimage-unpack texsubimage-unpack.c) piglit_add_executable (texture-al texture-al.c) piglit_add_executable (texture-rg texture-rg.c) piglit_add_executable (teximage-colors teximage-colors.c) diff --git a/tests/texturing/texsubimage-unpack.c b/tests/texturing/texsubimage-unpack.c new file mode 100644 index 000000000..45dddbb92 --- /dev/null +++ b/tests/texturing/texsubimage-unpack.c @@ -0,0 +1,525 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS 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. + */ + +/* + * Test that glTexSubImage*D works correctly with GL_UNPACK_ALIGNMENT, + * component mapping, and type conversions. + */ + +#include "piglit-util-gl.h" +#include "../fbo/fbo-formats.h" + +PIGLIT_GL_TEST_CONFIG_BEGIN + + config.supports_gl_compat_version = 10; + + config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE; + + config.window_width = 512; + config.window_height = 512; + +PIGLIT_GL_TEST_CONFIG_END + +#define TEX_WIDTH 32 +#define TEX_HEIGHT 16 + +/* If set to true then the texture sub image upload will be read + * from a PBO */ +static bool use_pbo = false; + +static bool have_ARB_texture_rg = false; +static bool have_EXT_bgra = false; +static bool have_EXT_abgr = false; + +struct src_format_desc { + GLenum format; + int8_t data_swizzle[4]; + int8_t tex_swizzle[4]; + bool *enable; +}; + +static const struct src_format_desc test_src_formats[] = { +#define X (-1) +#define Y (-2) + /* This is first because we test it with all types. */ + { GL_RGBA, { 0, 1, 2, 3 }, { 0, 1, 2, 3 } }, + + /* Remainder is in the order of Table 8.8 of the OpenGL 4.5 + * (Compatibility Profile) spec. */ + { GL_RED, { 0, }, { 0, X, X, Y } }, + { GL_GREEN, { 1, }, { X, 1, X, Y } }, + { GL_BLUE, { 2, }, { X, X, 2, Y } }, + { GL_ALPHA, { 3, }, { X, X, X, 3 } }, + { GL_RG, { 0, 1 }, { 0, 1, X, Y }, &have_ARB_texture_rg }, + { GL_RGB, { 0, 1, 2, }, { 0, 1, 2, Y } }, + { GL_BGR, { 2, 1, 0, }, { 0, 1, 2, Y }, &have_EXT_bgra }, + { GL_BGRA, { 2, 1, 0, 3 }, { 0, 1, 2, 3 }, &have_EXT_bgra }, + { GL_LUMINANCE, { 0, }, { 0, 0, 0, Y } }, + { GL_LUMINANCE_ALPHA, { 0, 3, }, { 0, 0, 0, 3 } }, + { GL_ABGR_EXT, { 3, 2, 1, 0 }, { 0, 1, 2, 3 }, &have_EXT_abgr }, +#undef X +#undef Y +}; + +struct base_internal_format_desc { + GLenum format; + int8_t swizzle[4]; +}; + +static const GLenum test_types[] = { + GL_UNSIGNED_BYTE, + GL_BYTE, + GL_UNSIGNED_SHORT, + GL_SHORT, + GL_UNSIGNED_INT, + GL_INT, +}; + +/* Sources of RGBA values read from framebuffer when drawing a texture with the + * fixed function pipeline, depending on the texture base internal format. + */ +static const struct base_internal_format_desc base_internal_formats[] = { +#define X (-1) +#define Y (-2) + { GL_ALPHA, { Y, Y, Y, 3 } }, + { GL_INTENSITY, { 0, 0, 0, 0 } }, + { GL_LUMINANCE, { 0, 0, 0, Y } }, + { GL_LUMINANCE_ALPHA, { 0, 0, 0, 3 } }, + { GL_RED, { 0, X, X, Y } }, + { GL_RG, { 0, 1, X, Y } }, + { GL_RGB, { 0, 1, 2, Y } }, + { GL_RGBA, { 0, 1, 2, 3 } }, +#undef X +#undef Y +}; + +static const struct base_internal_format_desc * +lookup_base_internal_format(GLenum format) +{ + for (unsigned i = 0; i < ARRAY_SIZE(base_internal_formats); ++i) { + const struct base_internal_format_desc *desc = &base_internal_formats[i]; + if (desc->format == format) + return desc; + } + + fprintf(stderr, "bad base internal format\n"); + piglit_report_result(PIGLIT_FAIL); +} + +/** + * Draw each image of the texture to the framebuffer and then save the + * entire thing to a buffer with glReadPixels(). + */ +static void +draw_and_read_texture(GLuint w, GLuint h, GLubyte *ref) +{ + piglit_draw_rect_tex(0, 0, /* x/y */ + w, h, + 0.0, 0.0, /* tx/ty */ + 1.0, 1.0 /* tw/th */); + + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ref); +} + +static GLuint +create_texture(GLenum intFormat, + GLsizei w, GLsizei h, + GLenum srcFormat, + const GLubyte *img) +{ + GLuint tex; + + 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); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, intFormat, w, h, 0, + srcFormat, GL_UNSIGNED_BYTE, img); + + return tex; +} + +/** + * Prepare to upload a region of update_img via glTexSubImage*D(): + * + * - \p update_img is a straight-forward 32-bit RGBA format + * - src_format and type describe the type and format to be used with + * glTexSubImage2D() + * - alignment is the pixel unpack alignment + * + * - the data to be sent to the GL in \p upload will be written to upload + * - the (straight-forward 32-bit RGBA format) \p ref_img image will be + * modified at the relevant pixels + * + * \return the number of bytes written to \p upload + */ +static unsigned +prepare_upload(const GLubyte *update_img, const GLubyte *update_ref, + GLuint w, GLuint h, + const struct base_internal_format_desc *base_format_desc, + const struct src_format_desc *src_format, + GLenum type, + GLint alignment, + GLuint tx, GLuint ty, + GLuint tw, GLuint th, + GLubyte *update_swz_ref, + GLubyte *upload) +{ + unsigned dst = 0; + unsigned components = piglit_num_components(src_format->format); + + for (unsigned y = 0; y < th; ++y) { + unsigned src = 4 * (tx + w * (ty + y)); + const GLubyte *img_tex = update_img + src; + const GLubyte *orig_ref_tex = update_ref + src; + GLubyte *swz_tex = update_swz_ref + src; + for (unsigned x = 0; x < tw; ++x, img_tex += 4, orig_ref_tex += 4, swz_tex += 4) { + for (unsigned i = 0; i < components; ++i) { + GLubyte c = orig_ref_tex[src_format->data_swizzle[i]]; + switch (type) { + case GL_UNSIGNED_BYTE: + upload[dst] = c; + ++dst; + break; + case GL_BYTE: + upload[dst] = c / 2; + ++dst; + break; + case GL_UNSIGNED_SHORT: + *(GLushort *)(upload + dst) = (GLuint)c * 0x0101U; + dst += 2; + break; + case GL_SHORT: + *(GLshort *)(upload + dst) = ((GLuint)c * 0x0101U) / 2; + dst += 2; + break; + case GL_UNSIGNED_INT: + *(GLuint *)(upload + dst) = (GLuint)c * 0x01010101U; + dst += 4; + break; + case GL_INT: + *(GLint *)(upload + dst) = ((GLuint)c * 0x01010101U) / 2; + dst += 4; + break; + default: + assert(!"unsupported type"); + } + } + + for (unsigned i = 0; i < 4; ++i) { + int swz = base_format_desc->swizzle[i]; + if (swz >= 0) + swz = src_format->tex_swizzle[swz]; + if (swz >= 0) + swz_tex[i] = orig_ref_tex[swz]; + else if (swz == -2) + swz_tex[i] = 255; + else if (swz == -1) + swz_tex[i] = 0; + } + } + dst = (dst + alignment - 1) & ~(alignment - 1); + } + + return dst; +} + +static bool +test_formats_type(const struct format_desc *intFormat, + GLuint w, GLuint h, + const struct src_format_desc *srcFormat, GLenum type, + const GLubyte *original_img, const GLubyte *original_ref, + const GLubyte *updated_img, const GLubyte *updated_ref, + GLuint pbo, + GLubyte *updated_swz_ref, GLubyte *upload_data, GLubyte *testImg) +{ + bool pass = true; + const struct base_internal_format_desc *base_format_desc + = lookup_base_internal_format(intFormat->base_internal_format); + unsigned bits = intFormat->min_bits; + + if (!bits || bits > 8) + bits = 8; + if (type == GL_BYTE && bits > 7) + bits = 7; + + for (unsigned t = 0; t < 3 && pass; t++) { + GLuint tex; + unsigned upload_bytes; + + /* Choose random region of texture to update. + * Use sizes and positions that are multiples of + * the compressed block size. + */ + GLint tw = 1 + rand() % w; + GLint th = 1 + rand() % h; + GLint tx = rand() % (w - tw + 1); + GLint ty = rand() % (h - th + 1); + + /* Choose a random alignment. */ + static const GLint alignments[] = { 1, 2, 4, 8 }; + GLint alignment = alignments[rand() % ARRAY_SIZE(alignments)]; + + assert(tx + tw <= w); + assert(ty + th <= h); + + /* Recreate the original texture */ + tex = create_texture(intFormat->internalformat, w, h, + GL_RGBA, original_img); + + upload_bytes = prepare_upload( + updated_img, updated_ref, w, h, + base_format_desc, srcFormat, type, alignment, + tx, ty, tw, th, + updated_swz_ref, upload_data); + + if (use_pbo) { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); + glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, upload_bytes, upload_data); + } + + /* replace texture region with data from updated image */ + glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); + glTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, tw, th, + srcFormat->format, type, + use_pbo ? NULL : upload_data); + + if (use_pbo) + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + /* draw test image */ + glClear(GL_COLOR_BUFFER_BIT); + draw_and_read_texture(w, h, testImg); + + glDeleteTextures(1, &tex); + + piglit_present_results(); + + if (!piglit_equal_images_update_rgba8( + original_ref, updated_swz_ref, testImg, + w, h, 1, tx, ty, 0, tw, th, 1, + bits)) { + printf("texsubimage-unpack failed\n"); + printf(" internal format: %s\n", piglit_get_gl_enum_name(intFormat->internalformat)); + printf(" format: %s\n", piglit_get_gl_enum_name(srcFormat->format)); + printf(" type: %s\n", piglit_get_gl_enum_name(type)); + printf(" alignment: %d\n", alignment); + printf(" region: %d, %d %d x %d\n", tx, ty, tw, th); + pass = false; + } + } + + return pass; +} + +/** + * Create two different images, draw both of them to the framebuffer + * via textures of the given \p intFormat and read them back to obtain the + * reference data. + * + * Then, for various combinations of (source data) formats and types, + * create a texture with the original image plus a random rectangle changed + * to the updated image. Draw that texture, read it back, and compare the + * results to what we expect. + */ +static bool +test_format(const struct format_desc *intFormat) +{ + const GLuint w = TEX_WIDTH; + const GLuint h = TEX_HEIGHT; + GLuint tex, j, k, n; + GLubyte *original_img, *original_ref; + GLubyte *updated_img, *updated_ref; + GLubyte *updated_swz_ref; + GLubyte *upload_data, *testImg; + bool pass = true; + GLuint pbo = 0; + + original_img = (GLubyte *) malloc(w * h * 4); + original_ref = (GLubyte *) malloc(w * h * 4); + updated_img = (GLubyte *) malloc(w * h * 4); + updated_ref = (GLubyte *) malloc(w * h * 4); + updated_swz_ref = (GLubyte *) malloc(w * h * 4); + /* Allow generous extra space for alignment and other data types. */ + upload_data = (GLubyte *) malloc(w * h * 4 * 5); + testImg = (GLubyte *) malloc(w * h * 4); + + /* Fill source tex images. Use only 7 bits of pseudo-randomness per + * component because we test GL_BYTE. */ + n = 0; + for (j = 0; j < h; j++) { + for (k = 0; k < w; k++) { + /* On glibc, RAND_MAX is (1 << 31) - 1, which + * is good enough. */ + int data = rand(); + original_img[n + 0] = ((data >> 0) & 0x7f) * 0x81 >> 6; + original_img[n + 1] = ((data >> 7) & 0x7f) * 0x81 >> 6; + original_img[n + 2] = ((data >> 14) & 0x7f) * 0x81 >> 6; + original_img[n + 3] = ((data >> 21) & 0x7f) * 0x81 >> 6; + + data = rand(); + updated_img[n + 0] = ((data >> 0) & 0x7f) * 0x81 >> 6; + updated_img[n + 1] = ((data >> 7) & 0x7f) * 0x81 >> 6; + updated_img[n + 2] = ((data >> 14) & 0x7f) * 0x81 >> 6; + updated_img[n + 3] = ((data >> 21) & 0x7f) * 0x81 >> 6; + + n += 4; + } + } + + if (use_pbo) { + glGenBuffers(1, &pbo); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); + glBufferData(GL_PIXEL_UNPACK_BUFFER, + w * h * 4 * 5, + NULL, + GL_STREAM_DRAW); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + } + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + + /* draw original reference image */ + tex = create_texture(intFormat->internalformat, w, h, + GL_RGBA, original_img); + glClear(GL_COLOR_BUFFER_BIT); + draw_and_read_texture(w, h, original_ref); + glDeleteTextures(1, &tex); + + /* draw updated reference image */ + tex = create_texture(intFormat->internalformat, w, h, + GL_RGBA, updated_img); + glClear(GL_COLOR_BUFFER_BIT); + draw_and_read_texture(w, h, updated_ref); + glDeleteTextures(1, &tex); + + /* Test all source formats with type GL_UNSIGNED_BYTE. */ + for (n = 0; n < ARRAY_SIZE(test_src_formats); ++n) { + const struct src_format_desc* srcFormat = &test_src_formats[n]; + if (srcFormat->enable && !*srcFormat->enable) + continue; + + pass = test_formats_type( + intFormat, w, h, + srcFormat, GL_UNSIGNED_BYTE, + original_img, original_ref, updated_img, updated_ref, + pbo, updated_swz_ref, upload_data, testImg) && pass; + } + + /* Test the GL_RGBA format with all other types. */ + for (n = 1; n < ARRAY_SIZE(test_types); ++n) { + pass = test_formats_type( + intFormat, w, h, + &test_src_formats[0], test_types[n], + original_img, original_ref, updated_img, updated_ref, + pbo, updated_swz_ref, upload_data, testImg) && pass; + } + + free(original_img); + free(original_ref); + free(updated_img); + free(updated_ref); + free(updated_swz_ref); + free(upload_data); + free(testImg); + + if (use_pbo) + glDeleteBuffers(1, &pbo); + + return pass; +} + + +enum piglit_result +piglit_display(void) +{ + bool pass = true; + int i; + + /* Section 3.8.1 (Texture Image Specification) of the OpenGL 2.1 + * specification says: + * + * "For the purposes of decoding the texture image, TexImage2D is + * equivalent to calling TexImage3D with corresponding arguments + * and depth of 1, except that + * + * ... + * + * * UNPACK_SKIP_IMAGES is ignored." + */ + glPixelStorei(GL_UNPACK_SKIP_IMAGES, 1); + + glEnable(GL_TEXTURE_2D); + + /* loop over the format groups */ + for (i = 0; i < ARRAY_SIZE(core); ++i) + pass = test_format(&core[i]) && pass; + + if (have_ARB_texture_rg) { + for (i = 0; i < ARRAY_SIZE(arb_texture_rg); ++i) + pass = test_format(&arb_texture_rg[i]) && pass; + } + + glDisable(GL_TEXTURE_2D); + + return pass ? PIGLIT_PASS : PIGLIT_FAIL; +} + + +void +piglit_init(int argc, char **argv) +{ + int remaining_argc = 1; + int i; + + srand(0); /* reproducibility of the first error */ + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "pbo")) { + piglit_require_extension("GL_ARB_pixel_buffer_object"); + use_pbo = true; + } else { + argv[remaining_argc++] = argv[i]; + } + } + + fbo_formats_init(remaining_argc, argv, 0); + (void) fbo_formats_display; + + piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE); + +#define CHECK_EXTENSION(name) \ + do { \ + have_ ## name = piglit_is_extension_supported("GL_" #name); \ + printf("GL_" #name " supported = %s\n", \ + have_ ## name ? "yes" : "no"); \ + } while (false) + + CHECK_EXTENSION(ARB_texture_rg); + CHECK_EXTENSION(EXT_bgra); + CHECK_EXTENSION(EXT_abgr); + +#undef CHECK_EXTENSION +} |