[Piglit] [PATCH] tex3d-maxsize: rewrite to be more robust and do more testing

Brian Paul brianp at vmware.com
Wed Jul 13 21:47:53 UTC 2016


1. It seems with NVIDIA's driver that using a proxy texture isn't a
sure fire way to know that a given texture format/size can actually be
created.  Update the find_max_tex3d_size() function to actually try
creating a texture with glTexImage3D/glTexStorage3D and see if it
works.

2. Improve the speed of texture initialization by copying the first
3D slice to the other slices with glCopyImageSubData().

3. Use glTexStorage3D when GL_ARB_texture_storage is supported.

4. In addition to GL_RGBA8, test GL_INTENSITY8 and GL_RGBA32F formats.

5. Before testing the largest possible texture, try a couple smaller
sizes as a sanity check.

6. Loosen the piglit probe tolerance by one bit to account for inaccuracy
caused by GL_NEAREST filtering.

Tested with NVIDIA driver, VMware driver and llvmpipe.
---
 tests/texturing/tex3d-maxsize.c | 285 +++++++++++++++++++++++++++++-----------
 1 file changed, 211 insertions(+), 74 deletions(-)

diff --git a/tests/texturing/tex3d-maxsize.c b/tests/texturing/tex3d-maxsize.c
index e168d14..60c9c63 100644
--- a/tests/texturing/tex3d-maxsize.c
+++ b/tests/texturing/tex3d-maxsize.c
@@ -30,31 +30,88 @@
 
 PIGLIT_GL_TEST_CONFIG_BEGIN
 
-	config.supports_gl_compat_version = 10;
+	config.supports_gl_compat_version = 12;
 
 	config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE;
 
 PIGLIT_GL_TEST_CONFIG_END
 
-static const char *TestName = "tex3d-maxsize";
+
+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(GLint initSize, GLint *width, GLint *height, GLint *depth)
+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;
 
-		glTexImage3D(GL_PROXY_TEXTURE_3D, level, GL_RGBA8,
-			     w, h, d, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+		alloc_tex3d(GL_PROXY_TEXTURE_3D, internalFormat, w, h, d);
 
 		glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, level,
 					 GL_TEXTURE_WIDTH, &pw);
@@ -63,12 +120,40 @@ find_max_tex3d_size(GLint initSize, GLint *width, GLint *height, GLint *depth)
 		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) {
-			/* success! */
-			*width = w;
-			*height = h;
-			*depth = d;
-			return;
+			/* 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 */
@@ -84,70 +169,39 @@ find_max_tex3d_size(GLint initSize, GLint *width, GLint *height, GLint *depth)
 }
 
 
-enum piglit_result
-piglit_display(void)
+/**
+ * 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)
 {
-	GLuint tex;
-	GLint maxsize, width, height, depth;
-	GLenum err;
+	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;
-	GLboolean pass = GL_TRUE;
-	float c1[4] = {0.25, 0.25, 0.25, 1.0};
-	float c2[4] = {0.75, 0.75, 0.75, 1.0};
-
-	piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
+	GLuint tex;
+	unsigned mbytes = tex_size(internalFormat, width, height, depth);
 
-	glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &maxsize);
+	printf("Testing %d x %d x %d %s (%u MB) texture\n",
+	       width, height, depth,
+	       piglit_get_gl_enum_name(internalFormat), mbytes);
+	fflush(stdout);
 
-	/* Create the texture. */
 	glGenTextures(1, &tex);
 	glBindTexture(GL_TEXTURE_3D, tex);
-	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-	if (glGetError())
-		return PIGLIT_FAIL;
-
-	glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, maxsize, maxsize, maxsize, 0,
-		     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-
-	err = glGetError();
-
-	if (err == GL_OUT_OF_MEMORY) {
+	alloc_tex3d(GL_TEXTURE_3D, internalFormat, width, height, depth);
 
-		/* use proxy texture to find working max texture size */
-		width = height = depth = 0;
-		find_max_tex3d_size(maxsize, &width, &height, &depth);
-
-		printf("Max 3D texture size: %d x %d x %d\n",
-		       width, height, depth);
-		fflush(stdout);
-
-		glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, width, height, depth, 0,
-			     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-		err = glGetError();
-
-		if (err == GL_OUT_OF_MEMORY)
-			return PIGLIT_PASS;
-	}
-	else {
-		/* the max 3D texture size actually worked */
-		width = height = depth = maxsize;
-	}
-
-	if (err != GL_NO_ERROR) {
-		printf("%s: unexpected glTexImage3D error: 0x%x\n",
-		       TestName, err);
-		return PIGLIT_FAIL;
+	if (!piglit_check_gl_error(GL_NO_ERROR)) {
+		printf("Creating texture failed in test_render().\n");
+		pass = false;
+		goto end;
 	}
 
-	if (0)
-		printf("max 3D texture size = %d x %d x %d\n",
-		       width, height, depth);
-
 	/* Set its pixels, slice by slice. */
 	data = malloc(width * height * 4);
-	for (j = 0; j < height; j++)
+	for (j = 0; j < height; j++) {
 		for (i = 0; i < width; i++) {
 			int a = (j * width + i) * 4;
 			data[a+0] =
@@ -155,26 +209,45 @@ piglit_display(void)
 			data[a+2] =
 			data[a+3] = (i * 255) / (width - 1);
 		}
+	}
 
-	for (i = 0; i < depth; i++) {
-		glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, i, width, height, 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, 1);
+	glTexCoord3f(0, 0, 0.5);
 	glVertex2f(0, 0);
-	glTexCoord3f(0, 1, 1);
+	glTexCoord3f(0, 1, 0.5);
 	glVertex2f(0, piglit_height);
-	glTexCoord3f(1, 1, 1);
+	glTexCoord3f(1, 1, 0.5);
 	glVertex2f(piglit_width, piglit_height);
-	glTexCoord3f(1, 0, 1);
+	glTexCoord3f(1, 0, 0.5);
 	glVertex2f(piglit_width, 0);
 	glEnd();
-	glDeleteTextures(1, &tex);
 
 	pass = piglit_probe_pixel_rgb(piglit_width * 1 / 4,
 				      piglit_height * 1 / 4, c1) && pass;
@@ -187,17 +260,81 @@ piglit_display(void)
 	piglit_present_results();
 
 	if (!pass) {
-		printf("%s: failed at size %d x %d x %d\n", TestName,
-		       width, height, depth);
+		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)
 {
-	piglit_require_gl_version(12);
-
 	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]);
+}
-- 
1.9.1



More information about the Piglit mailing list