/* * Copyright (c) 2010 Marek Olšák * * 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 * VA LINUX SYSTEM, IBM 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. */ /** * @file * Tests 3D textures. */ #include "piglit-util-gl.h" PIGLIT_GL_TEST_CONFIG_BEGIN config.supports_gl_compat_version = 12; config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE; config.khr_no_error_support = PIGLIT_NO_ERRORS; PIGLIT_GL_TEST_CONFIG_END static GLint MaxSize; /** * Compute size (in megabytes) of a texture of the given dimensions and * internal format. */ static unsigned tex_size(GLenum internalFormat, int width, int height, int depth) { uint64_t sz; sz = (uint64_t) width * (uint64_t) height * (uint64_t) depth; switch (internalFormat) { case GL_INTENSITY8: sz *= 1; break; case GL_RGBA8: sz *= 4; break; case GL_RGBA32F: sz *= 16; break; default: assert(!"Unexpected internalFormat"); } return (unsigned) (sz / (uint64_t) (1024 * 1024)); } /** * Allocate a 1-level 3D texture. */ static void alloc_tex3d(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth) { if (target == GL_TEXTURE_3D) { glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } if (piglit_is_extension_supported("GL_ARB_texture_storage")) { glTexStorage3D(target, 1, internalFormat, width, height, depth); } else { glTexImage3D(target, 0, internalFormat, width, height, depth, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); } } /* * Use proxy texture to find largest possible 3D texture size. */ static void find_max_tex3d_size(GLenum internalFormat, GLint initSize, GLint *width, GLint *height, GLint *depth) { GLint dim = 0, w, h, d, pw, ph, pd; piglit_check_gl_error(GL_NO_ERROR); w = h = d = initSize; while (w >= 1 && h >= 1 && d >= 1) { /* try proxy image */ const int level = 0; alloc_tex3d(GL_PROXY_TEXTURE_3D, internalFormat, w, h, d); glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, level, GL_TEXTURE_WIDTH, &pw); glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, level, GL_TEXTURE_HEIGHT, &ph); glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, level, GL_TEXTURE_DEPTH, &pd); if (!piglit_check_gl_error(GL_NO_ERROR)) { printf("Unexpected error during texture proxy test.\n"); piglit_report_result(PIGLIT_FAIL); } if (pw == w && ph == h && pd == d) { /* this size should be supported, but test it to * be sure. */ GLuint tex; GLenum err; /* Create a texture object for the non-proxy texture below */ glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_3D, tex); alloc_tex3d(GL_TEXTURE_3D, internalFormat, w, h, d); err = glGetError(); glDeleteTextures(1, &tex); if (err == GL_NO_ERROR) { /* success! */ *width = w; *height = h; *depth = d; return; } else { printf("Note: proxy texture of size " "%d x %d x %d worked, but actual " "glTexImage3D call failed!\n", w, h, d); } } /* halve one of the dimensions and try again */ if (dim == 0) w /= 2; else if (dim == 1) h /= 2; else d /= 2; dim = (dim + 1) % 3; } } /** * Create a 3D texture of the given format and size, draw a textured quad * with that texture, and check results. */ static bool test_render(GLenum internalFormat, int width, int height, int depth) { static const float c1[4] = {0.25, 0.25, 0.25, 1.0}; static const float c2[4] = {0.75, 0.75, 0.75, 1.0}; bool pass = true; char *data; int i, j; GLuint tex; unsigned mbytes = tex_size(internalFormat, width, height, depth); printf("Testing %d x %d x %d %s (%u MB) texture\n", width, height, depth, piglit_get_gl_enum_name(internalFormat), mbytes); fflush(stdout); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_3D, tex); alloc_tex3d(GL_TEXTURE_3D, internalFormat, width, height, depth); if (!piglit_check_gl_error(GL_NO_ERROR)) { printf("Creating texture failed in test_render().\n"); pass = false; goto end; } /* Set its pixels, slice by slice. */ data = malloc(width * height * 4); for (j = 0; j < height; j++) { for (i = 0; i < width; i++) { int a = (j * width + i) * 4; data[a+0] = data[a+1] = data[a+2] = data[a+3] = (i * 255) / (width - 1); } } if (piglit_is_extension_supported("GL_ARB_copy_image")) { /* load 0th slice */ glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, data); /* copy 0th slice to other slices (should be faster) */ for (i = 1; i < depth; i++) { glCopyImageSubData(tex, GL_TEXTURE_3D, 0, 0, 0, 0, tex, GL_TEXTURE_3D, 0, 0, 0, i, width, height, 1); } } else { /* load each slice with glTexSubImage3D */ for (i = 0; i < depth; i++) { glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, i, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, data); } } free(data); glClear(GL_COLOR_BUFFER_BIT); /* Now try basic rendering. */ glEnable(GL_TEXTURE_3D); glBegin(GL_QUADS); glTexCoord3f(0, 0, 0.5); glVertex2f(0, 0); glTexCoord3f(0, 1, 0.5); glVertex2f(0, piglit_height); glTexCoord3f(1, 1, 0.5); glVertex2f(piglit_width, piglit_height); glTexCoord3f(1, 0, 0.5); glVertex2f(piglit_width, 0); glEnd(); pass = piglit_probe_pixel_rgb(piglit_width * 1 / 4, piglit_height * 1 / 4, c1) && pass; pass = piglit_probe_pixel_rgb(piglit_width * 3 / 4, piglit_height * 1 / 4, c2) && pass; pass = piglit_probe_pixel_rgb(piglit_width * 1 / 4, piglit_height * 3 / 4, c1) && pass; pass = piglit_probe_pixel_rgb(piglit_width * 3 / 4, piglit_height * 3 / 4, c2) && pass; piglit_present_results(); if (!pass) { printf("rendering failed with %d x %d x %d %s texture\n", width, height, depth, piglit_get_gl_enum_name(internalFormat)); } end: glDeleteTextures(1, &tex); return pass; } static bool test_3d_tex_format(GLenum internalFormat) { GLint width, height, depth; bool pass = true; unsigned mbytes; piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE); /* use proxy texture to find actual max texture size */ width = height = depth = 0; find_max_tex3d_size(internalFormat, MaxSize, &width, &height, &depth); mbytes = tex_size(internalFormat, width, height, depth); printf("Actual max 3D texture size for %s: %d x %d x %d (%u MB)\n", piglit_get_gl_enum_name(internalFormat), width, height, depth, mbytes); /* first, try some smaller res 3D texture rendering */ pass = test_render(internalFormat, width, height, depth/4); pass = test_render(internalFormat, width, height, depth/2) && pass; /* test largest 3D texture size */ pass = test_render(internalFormat, width, height, depth) && pass; return pass; } enum piglit_result piglit_display(void) { bool pass; glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &MaxSize); printf("GL_MAX_3D_TEXTURE_SIZE = %d\n", MaxSize); pass = test_3d_tex_format(GL_INTENSITY8); pass = test_3d_tex_format(GL_RGBA8) && pass; if (piglit_is_extension_supported("GL_ARB_texture_float")) { pass = test_3d_tex_format(GL_RGBA32F) && pass; } return pass ? PIGLIT_PASS : PIGLIT_FAIL; } void piglit_init(int argc, char **argv) { glDisable(GL_DITHER); /* Set the tolerance a little looser since we're using GL_NEAREST * texture sampling. GL_NEAREST is fastest for software rendering. * We probably wouldn't have to loosen the tolerance if we used * GL_LINEAR filtering. */ piglit_set_tolerance_for_bits(7, 7, 7, 7); printf("Probe tolerance: %f, %f, %f, %f\n", piglit_tolerance[0], piglit_tolerance[1], piglit_tolerance[2], piglit_tolerance[3]); }