[Piglit] [PATCH] s3tc-errors: test GL error checking with s3tc textures

Brian Paul brian.e.paul at gmail.com
Sat Sep 22 08:30:10 PDT 2012


From: Brian Paul <brianp at vmware.com>

Check for expected OpenGL errors related to texture compression.  For
example, glCompresedTexSubImage2D() offset/size values must be multiples
of four.

This test could be expanded to cover other compression formats in the future.

Also, this test contains some texture compression helper functions that could
be made into piglit utility functions.

Verified with NVIDIA's driver.  One error found in Mesa, to be fixed soon.
---
 tests/all.tests                   |    1 +
 tests/texturing/CMakeLists.gl.txt |    1 +
 tests/texturing/s3tc-errors.c     |  381 +++++++++++++++++++++++++++++++++++++
 3 files changed, 383 insertions(+), 0 deletions(-)
 create mode 100644 tests/texturing/s3tc-errors.c

diff --git a/tests/all.tests b/tests/all.tests
index 381c38f..dcead58 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -740,6 +740,7 @@ add_plain_test(texturing, 'rg-teximage-01')
 add_plain_test(texturing, 'rg-teximage-02')
 add_plain_test(texturing, 'rgtc-teximage-01')
 add_plain_test(texturing, 'rgtc-teximage-02')
+add_concurrent_test(texturing, 's3tc-errors')
 add_plain_test(texturing, 's3tc-teximage')
 add_plain_test(texturing, 's3tc-texsubimage')
 add_plain_test(texturing, 'sampler-cube-shadow')
diff --git a/tests/texturing/CMakeLists.gl.txt b/tests/texturing/CMakeLists.gl.txt
index c439273..cc0623c 100644
--- a/tests/texturing/CMakeLists.gl.txt
+++ b/tests/texturing/CMakeLists.gl.txt
@@ -62,6 +62,7 @@ ENDIF (UNIX)
 piglit_add_executable (s3tc-teximage s3tc-teximage.c)
 piglit_add_executable (fxt1-teximage fxt1-teximage.c)
 piglit_add_executable (s3tc-texsubimage s3tc-texsubimage.c)
+piglit_add_executable (s3tc-errors s3tc-errors.c)
 piglit_add_executable (sampler-cube-shadow sampler-cube-shadow.c)
 piglit_add_executable (streaming-texture-leak streaming-texture-leak.c)
 piglit_add_executable (tex-miplevel-selection tex-miplevel-selection.c)
diff --git a/tests/texturing/s3tc-errors.c b/tests/texturing/s3tc-errors.c
new file mode 100644
index 0000000..955d22f
--- /dev/null
+++ b/tests/texturing/s3tc-errors.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2012 VMware, 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
+ * 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.
+ */
+
+/**
+ * Verify error checking for compressed texture functions, using s3tc as
+ * the specific compression formats.
+ * Some rendering is also tested, but it's not the focus here.
+ * Other compressed formats could be added as well (the test should probably
+ * be renamed at that point.)
+ *
+ * Brian Paul
+ * Sep 20, 2012
+ */
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_MAIN(200, 200, GLUT_RGB | GLUT_DOUBLE)
+
+
+static const float red[4] =   {1.0, 0.0, 0.0, 1.0};
+static const float green[4] = {0.0, 1.0, 0.0, 1.0};
+static const float blue[4] =  {0.0, 0.0, 1.0, 1.0};
+static const float white[4] = {1.0, 1.0, 1.0, 1.0};
+
+
+static const GLenum s3tc_formats[] = {
+	GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
+	GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
+	GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
+	GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
+};
+
+
+static bool
+check_rendering_(int width, int height, int line)
+{
+	const int w = width / 2 - 2;
+	const int h = height / 2 - 2;
+	bool pass = true;
+
+	piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
+
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	glEnable(GL_TEXTURE_2D);
+	glColor3f(1, 1, 1);
+
+	/* draw the texture */
+	piglit_draw_rect_tex(0, 0, width, height, 0, 0, 1, 1);
+
+	/* NOTE: don't probe the border pixels of the quadrants just to
+	 * avoid potential off-by one errors.
+	 */
+
+	/* lower-left red */
+	pass = piglit_probe_rect_rgb(1, 1, w, h, red) && pass;
+
+	/* lower-right green */
+	pass = piglit_probe_rect_rgb(width/2 + 1, 1, w, h, green) && pass;
+
+	/* upper-left blue */
+	pass = piglit_probe_rect_rgb(1, height/2 + 1, w, h, blue) && pass;
+
+	/* upper-right white */
+	pass = piglit_probe_rect_rgb(width/2 + 1, height/2 + 1,
+				     w, h, white) && pass;
+
+	piglit_present_results();
+
+	if (!pass) {
+		printf("s3tc-errors failure at line %d\n", line);
+	}
+
+	return pass;
+}
+
+
+#define check_rendering(w, h) check_rendering_(w, h, __LINE__)
+
+
+/**
+ * Return block size info for a compressed format.
+ * XXX this could be a piglit utility function someday
+ */
+static void
+get_compressed_block_size(GLenum format, int *bw, int *bh, int *bytes)
+{
+	switch (format) {
+	case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+	case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+		*bytes = 8;
+		break;
+	case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+	case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+		*bytes = 16;
+		break;
+	default:
+		assert(!"Unexpected format in get_compressed_block_size()");
+	}
+	/* XXX all formats use 4x4 blocks at this time */
+	*bw = *bh = 4;
+}
+
+
+/**
+ * Compute size (in bytes) neede to store an image in the given compressed
+ * format.
+ * XXX this could be a piglit utility function someday
+ */
+static int
+compressed_image_size(GLenum format, int width, int height)
+{
+	int bw, bh, bytes;
+	get_compressed_block_size(format, &bw, &bh, &bytes);
+	return width / bw * height / bh * bytes;
+}
+
+
+/**
+ * Return offset (in bytes) to the given texel in a compressed image.
+ * Note the x and y must be multiples of the compressed block size.
+ * XXX this could be a piglit utility function someday
+ */
+static int
+compressed_offset(GLenum format, int x, int y, int width)
+{
+	int bw, bh, bytes, offset;
+
+	get_compressed_block_size(format, &bw, &bh, &bytes);
+
+	assert(x % bw == 0);
+	assert(y % bh == 0);
+	assert(width % bw == 0);
+
+	offset = (width / bw * bytes * y / bh) + (x / bw * bytes);
+
+	return offset;
+}
+
+
+/**
+ * Check for either of two expected GL errors.
+ * XXX this could be a piglit util function
+ */
+static bool
+check_gl_error2_(GLenum err1, GLenum err2, int line)
+{
+	GLenum err = glGetError();
+	if (err != err1 && err != err2) {
+		printf("Unexpected error %s at %s:%d\n",
+		       piglit_get_gl_error_name(err), __FILE__, line);
+		return false;
+	}
+	return true;
+}
+
+#define check_gl_error2(err1, err2)  check_gl_error2_(err1, err2, __LINE__)
+
+
+static bool
+test_format(int width, int height, GLfloat *image, GLenum format)
+{
+	GLubyte *compressed_image =
+		malloc(compressed_image_size(format, width, height));
+	GLenum format2;
+	int x, y, w, h;
+	GLuint tex;
+	bool pass = true;
+
+	glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+	glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+	glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
+
+	/* Setup initial texture */
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_2D, tex);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
+		     GL_RGBA, GL_FLOAT, image);
+
+	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
+	pass = check_rendering(width, height) && pass;
+
+	/* Read back the compressed image data */
+	glGetCompressedTexImage(GL_TEXTURE_2D, 0, compressed_image);
+
+	/* Try texsubimage on 4-texel boundary - should work */
+	x = 20;
+	y = 12;
+	w = 16;
+	h = 8;
+	glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
+	glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
+	glTexSubImage2D(GL_TEXTURE_2D, 0,
+			x, y, w, h,
+			GL_RGBA, GL_FLOAT, image);
+
+	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
+	pass = check_rendering(width, height) && pass;
+
+	/* Try texsubimage on non 4-texel boundary - should not work */
+	x = 10;
+	y = 11;
+	glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
+	glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
+	glTexSubImage2D(GL_TEXTURE_2D, 0,
+			x, y, w, h,
+			GL_RGBA, GL_FLOAT, image);
+
+	pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
+
+	/* Try compressed subimage on 4-texel boundary - should work */
+	x = 12;
+	y = 8;
+	glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
+	glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
+	glCompressedTexSubImage2D(GL_TEXTURE_2D, 0,
+				  x, y, w, h,
+				  format,
+				  compressed_image_size(format, w, h),
+				  compressed_image +
+				  compressed_offset(format, x, y, width));
+
+	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
+	pass = check_rendering(width, height) && pass;
+
+	/* Try compressed subimage on non 4-texel boundary - should not work */
+	x = 14;
+	y = 9;
+	glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
+	glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
+	glCompressedTexSubImage2D(GL_TEXTURE_2D, 0,
+				  x, y, w, h,
+				  format,
+				  compressed_image_size(format, w, h),
+				  compressed_image +
+				  compressed_offset(format, 0, 0, width));
+
+	pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
+
+	/* Try compressed subimage with size not a multiple of 4 -
+	 * should not work
+	 */
+	x = 8;
+	y = 8;
+	w = 14;
+	h = 10;
+	glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
+	glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
+	glCompressedTexSubImage2D(GL_TEXTURE_2D, 0,
+				  x, y, w, h,
+				  format,
+				  compressed_image_size(format, 4, 4),
+				  compressed_image +
+				  compressed_offset(format, x, y, width));
+	/* Note, we can get either of these errors depending on the order
+	 * in which glCompressedTexSubImage parameters are checked.
+	 * INVALID_OPERATION for the bad size or INVALID_VALUE for the
+	 * wrong compressed image size.
+	 */
+	pass = check_gl_error2(GL_INVALID_OPERATION, GL_INVALID_VALUE) && pass;
+
+	/* Try compressed subimage with invalid offset - should not work */
+	x = -3;
+	y = 8;
+	w = 4;
+	h = 4;
+	glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
+	glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
+	glCompressedTexSubImage2D(GL_TEXTURE_2D, 0,
+				  x, y, w, h,
+				  format,
+				  compressed_image_size(format, w, h),
+				  compressed_image +
+				  compressed_offset(format, 0, 0, width));
+
+	pass = piglit_check_gl_error(GL_INVALID_VALUE) && pass;
+
+	/* Try compressed subimage with too large of image - should not work */
+	x = 16;
+	y = 8;
+	w = width * 2;
+	h = height * 2;
+	glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
+	glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
+	glCompressedTexSubImage2D(GL_TEXTURE_2D, 0,
+				  x, y, w, h,
+				  format,
+				  compressed_image_size(format, w, h),
+				  compressed_image +
+				  compressed_offset(format, x, y, width));
+
+	pass = piglit_check_gl_error(GL_INVALID_VALUE) && pass;
+
+	/* Try compressed subimage with different format - should not work */
+	if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
+		format2 = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+	else
+		format2 = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+	x = 4;
+	y = 4;
+	w = 4;
+	h = 4;
+	glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
+	glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
+	glCompressedTexSubImage2D(GL_TEXTURE_2D, 0,
+				  x, y, w, h,
+				  format2,
+				  compressed_image_size(format2, w, h),
+				  compressed_image +
+				  compressed_offset(format2, x, y, width));
+
+	pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
+
+	glDeleteTextures(1, &tex);
+
+	free(compressed_image);
+
+	return pass;
+}
+
+
+static bool
+test_formats(void)
+{
+	const int num_formats = ARRAY_SIZE(s3tc_formats);
+	const int width = 128, height = 64;
+	GLfloat *image = piglit_rgbw_image(GL_RGBA, width, height,
+					   GL_FALSE, /* alpha */
+					   GL_UNSIGNED_NORMALIZED);
+	int i;
+	bool pass = true;
+
+	for (i = 0; i < num_formats; i++) {
+		const GLenum format = s3tc_formats[i];
+		pass = test_format(width, height, image, format) && pass;
+	}
+
+	glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+	glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+	glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+
+	free(image);
+
+	return pass;
+}
+
+
+enum piglit_result
+piglit_display(void)
+{
+	return test_formats() ? PIGLIT_PASS : PIGLIT_FAIL;
+}
+
+
+void
+piglit_init(int argc, char **argv)
+{
+	piglit_require_extension("GL_EXT_texture_compression_s3tc");
+}
-- 
1.7.4.1



More information about the Piglit mailing list