[Piglit] [PATCH 3/4] Add a new comprehensive test for texelFetch().

Kenneth Graunke kenneth at whitecape.org
Tue Dec 6 13:23:57 PST 2011


This exhaustively tests all of GLSL 1.30's texelFetch variants, both in
the vertex and fragment shaders.  It covers:
- Integer and floating point texture formats
- Sampler dimensionality (1D, 2D, 3D, 1DArray, 2DArray)
- Mipmapping
- Non-power-of-two textures

The new "texelFetch" binary takes two arguments: shader stage and
sampler type.  For example:

./bin/texelFetch fs sampler1DArray
./bin/texelFetch usampler3D vs

Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>
---
 tests/all.tests                           |    5 +
 tests/texturing/shaders/CMakeLists.gl.txt |    1 +
 tests/texturing/shaders/texelFetch.c      |  516 +++++++++++++++++++++++++++++
 3 files changed, 522 insertions(+), 0 deletions(-)
 create mode 100644 tests/texturing/shaders/texelFetch.c

diff --git a/tests/all.tests b/tests/all.tests
index d59369a..eb6725b 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -882,10 +882,15 @@ import_glsl_parser_tests(spec['glsl-1.30'],
 			 ['compiler'])
 spec['glsl-1.30']['execution'] = Group()
 spec['glsl-1.30']['execution']['textureSize'] = Group()
+spec['glsl-1.30']['execution']['texelFetch'] = Group()
 for stage in ['vs', 'fs']:
 	# textureSize():
 	for sampler in ['sampler1D', 'sampler2D', 'sampler3D', 'samplerCube', 'sampler1DShadow', 'sampler2DShadow', 'samplerCubeShadow', 'sampler1DArray', 'sampler2DArray', 'sampler1DArrayShadow', 'sampler2DArrayShadow', 'isampler1D', 'isampler2D', 'isampler3D', 'isamplerCube', 'isampler1DArray', 'isampler2DArray', 'usampler1D', 'usampler2D', 'usampler3D', 'usamplerCube', 'usampler1DArray', 'usampler2DArray']:
 		spec['glsl-1.30']['execution']['textureSize'][stage + '-textureSize-' + sampler] = PlainExecTest(['textureSize', stage, sampler, '-auto', '-fbo'])
+	# texelFetch():
+	for sampler in ['sampler1D', 'sampler2D', 'sampler3D', 'sampler1DArray', 'sampler2DArray', 'isampler1D', 'isampler2D', 'isampler3D', 'isampler1DArray', 'isampler2DArray', 'usampler1D', 'usampler2D', 'usampler3D', 'usampler1DArray', 'usampler2DArray']:
+		spec['glsl-1.30']['execution']['texelFetch'][stage + '-texelFetch-' + sampler] = PlainExecTest(['texelFetch', stage, sampler, '-auto', '-fbo'])
+
 add_plain_test(spec['glsl-1.30']['execution'], 'fs-texelFetch-2D')
 add_plain_test(spec['glsl-1.30']['execution'], 'fs-texelFetchOffset-2D')
 add_shader_test_dir(spec['glsl-1.30']['execution'],
diff --git a/tests/texturing/shaders/CMakeLists.gl.txt b/tests/texturing/shaders/CMakeLists.gl.txt
index e54760f..467ac19 100644
--- a/tests/texturing/shaders/CMakeLists.gl.txt
+++ b/tests/texturing/shaders/CMakeLists.gl.txt
@@ -14,3 +14,4 @@ link_libraries (
 )
 
 add_executable (textureSize textureSize.c common.c)
+add_executable (texelFetch texelFetch.c common.c)
diff --git a/tests/texturing/shaders/texelFetch.c b/tests/texturing/shaders/texelFetch.c
new file mode 100644
index 0000000..34b09da
--- /dev/null
+++ b/tests/texturing/shaders/texelFetch.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright © 2011 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 texelFetch.c
+ *
+ * Tests the GLSL 1.30+ texelFetch() built-in function.
+ *
+ * The "texelFetch" binary takes two arguments: shader stage and sampler type.
+ *
+ * For example:
+ * ./bin/texelFetch fs sampler1DArray
+ * ./bin/texelFetch usampler3D vs
+ *
+ * The test covers:
+ * - All pipeline stages (VS, FS)
+ * - Integer and floating point texture formats
+ * - Sampler dimensionality (1D, 2D, 3D, 1DArray, 2DArray)
+ * - Mipmapping
+ * - Non-power-of-two textures
+ *
+ * Draws a series of "rectangles" which display each miplevel and array slice,
+ * at full size.  They are layed out as follows:
+ *
+ * miplevel 3 +          +          +          +          +
+ *
+ * miplevel 2 +-+        +-+        +-+        +-+        +-+
+ *            +-+        +-+        +-+        +-+        +-+
+ *
+ * miplevel 1 +---+      +---+      +---+      +---+      +---+
+ *            |   |      |   |      |   |      |   |      |   |
+ *            +---+      +---+      +---+      +---+      +---+
+ *
+ *            +------+   +------+   +------+   +------+   +------+
+ * miplevel 0 |      |   |      |   |      |   |      |   |      |
+ *            |      |   |      |   |      |   |      |   |      |
+ *            +------+   +------+   +------+   +------+   +------+
+ *            slice #0   slice #1   slice #2   slice #3   slice #4
+ *
+ * Normally, we could draw each rectangle as a single quad (or two triangles),
+ * interpolate the texture coordinates across the primitive, and let the
+ * fragment shader look up the color values from the texture.
+ *
+ * However, this fails miserably for vertex shader texturing: a quad only has
+ * four vertices, which means we could only fetch/display at most 4 texels.
+ * If we used a simple RGBW checkerboard, as in other Piglit tests, this would
+ * only tell us that we sampled somewhere in the right 1/4 of the texture.
+ *
+ * Instead, we take a clever approach: draw each "rectangle" via a series of
+ * 1-pixel wide GL_POINT primitives.  This gives us one vertex per pixel; by
+ * drawing the texture at full size, each pixel and vertex also correspond to
+ * exactly one texel.  So every texel is sampled and verified for correctness.
+ *
+ * In other words: "One pixel, one texel, one vertex."
+ *
+ * For convenience, we take the same approach for fragment shader testing
+ * as well, since it allows us to reuse the same VBO setup and drawing code.
+ */
+#include "common.h"
+
+int piglit_width = 355, piglit_height = 250;
+int piglit_window_mode = GLUT_RGBA | GLUT_DOUBLE;
+
+/** Vertex shader attribute locations */
+const int pos_loc = 0;
+const int texcoord_loc = 1;
+
+/** Uniform locations */
+int divisor_loc;
+
+/**
+ * Expected color data for each rectangle drawn, indexed by miplevel and slice.
+ * For example, expected_colors[1][3] contains the data for miplevel 1 slice 3.
+ */
+float ***expected_colors;
+
+/**
+ * Return the divisors necessary to scale the unnormalized texture data to
+ * a floating point color value in the range [0, 1].
+ */
+static void
+compute_divisors(int lod, float *divisors)
+{
+	divisors[0] = max2(level_size[lod][0] - 1, 1);
+	divisors[1] = max2(level_size[lod][1] - 1, 1);
+	divisors[2] = max2(level_size[lod][2] - 1, 1);
+	divisors[3] = 1.0;
+
+	if (sampler.data_type != GL_UNSIGNED_INT)
+		divisors[0] = -divisors[0];
+}
+
+enum piglit_result
+piglit_display()
+{
+	int i, l, z;
+	bool pass = true;
+
+	piglit_ortho_projection(piglit_width, piglit_height, false);
+
+	glClearColor(0.1, 0.1, 0.1, 1.0);
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	glPointSize(1.0);
+
+	i = 0;
+	for (l = 0; l < miplevels; ++l) {
+		for (z = 0; z < level_size[l][2]; z++) {
+			/* Draw the "rectangle" for this miplevel/slice. */
+			int points = level_size[l][0] * level_size[l][1];
+			float divisors[4];
+
+			compute_divisors(l, divisors);
+			glUniform4fv(divisor_loc, 1, divisors);
+
+			glDrawArrays(GL_POINTS, i, points);
+
+			i += points;
+
+			/* Compare results against reference image. */
+			pass &= piglit_probe_image_rgba(5+(5+base_size[0]) * z,
+							5+(5+base_size[1]) * l,
+							level_size[l][0],
+							level_size[l][1],
+							expected_colors[l][z]);
+		}
+	}
+
+	piglit_present_results();
+
+	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
+}
+
+/**
+ * Generate two VBOs for our vertex attributes:
+ * 1. Pixel position (in window coordinates).
+ * 2. Texture coordinates.
+ *
+ * The VBOs contain the data for every rectangle being drawn (as opposed to
+ * creating and binding a separate VBO per miplevel/slice.)
+ */
+void
+generate_VBOs()
+{
+	int x, y, z, l;
+	GLuint pos_vbo, tc_vbo;
+	float *pos, *pos_data;
+	int *tc, *tc_data;
+	bool array_1D = sampler.target == GL_TEXTURE_1D_ARRAY;
+	int num_texels = 0;
+
+	/* Calculate the # of texels a.k.a. size of the VBOs */
+	for (l = 0; l < miplevels; l++) {
+		num_texels += level_size[l][0] * level_size[l][1] * level_size[l][2];
+	}
+
+	pos = pos_data = malloc(num_texels * 4 * sizeof(float));
+	tc = tc_data = malloc(num_texels * 4 * sizeof(int));
+
+	for (l = 0; l < miplevels; l++) {
+		for (z = 0; z < level_size[l][2]; z++) {
+			for (y = 0; y < level_size[l][1]; y++) {
+				for (x = 0; x < level_size[l][0]; x++) {
+					/* Assign pixel positions: */
+					pos[0] = 5.5 + (5 + base_size[0])*z + x;
+					pos[1] = 5.5 + (5 + base_size[1])*l + y;
+					pos[2] = 0.0;
+					pos[3] = 1.0;
+					pos += 4;
+
+					/* Assign texture coordinates:
+					 * 1D:      x _ _ l
+					 * 2D:      x y _ l
+					 * 3D:      x y z l
+					 * 1DArray: x z _ l
+					 * 2DArray: x y z l
+					 */
+					tc[0] = x;
+					tc[1] = array_1D ? z : y;
+					tc[2] = z;
+					tc[3] = l;
+					tc += 4;
+				}
+			}
+		}
+	}
+
+	/* Create VBO for pixel positions in screen-space: */
+	glGenBuffers(1, &pos_vbo);
+	glBindBuffer(GL_ARRAY_BUFFER, pos_vbo);
+	glBufferData(GL_ARRAY_BUFFER,
+		     num_texels * 4 * sizeof(float),
+		     pos_data, GL_STATIC_DRAW);
+	glVertexAttribPointer(pos_loc, 4, GL_FLOAT, false, 0, 0);
+	glEnableVertexAttribArray(pos_loc);
+
+	/* Create VBO for texture coordinates: */
+	glGenBuffers(1, &tc_vbo);
+	glBindBuffer(GL_ARRAY_BUFFER, tc_vbo);
+	glBufferData(GL_ARRAY_BUFFER,
+		     num_texels * 4 * sizeof(int),
+		     tc_data, GL_STATIC_DRAW);
+	glVertexAttribIPointer(texcoord_loc, 4, GL_INT, 0, 0);
+	glEnableVertexAttribArray(texcoord_loc);
+}
+
+/**
+ * Create texel data.
+ */
+void
+generate_texture()
+{
+	int l, x, y, z;
+	unsigned *u_level, *u_ptr;
+	int      *i_level, *i_ptr;
+	float    *f_level, *f_ptr;
+	float    *expected_ptr;
+	void *level_image;
+	float divisors[4];
+	GLuint tex;
+	GLenum target = sampler.target;
+
+	glActiveTexture(GL_TEXTURE0);
+
+	glGenTextures(1, &tex);
+	glBindTexture(target, tex);
+	glEnable(target);
+	glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+	glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+	expected_colors = calloc(miplevels, sizeof(float **));
+
+	for (l = 0; l < miplevels; l++) {
+		expected_colors[l] = calloc(level_size[l][2], sizeof(float **));
+
+		i_ptr = i_level =
+			malloc(level_size[l][0] * level_size[l][1] *
+			       level_size[l][2] * 4 * sizeof(int));
+
+		u_ptr = u_level =
+			malloc(level_size[l][0] * level_size[l][1] *
+			       level_size[l][2] * 4 * sizeof(unsigned));
+
+		f_ptr = f_level =
+			malloc(level_size[l][0] * level_size[l][1] *
+			       level_size[l][2] * 4 * sizeof(float));
+
+		for (z = 0; z < level_size[l][2]; z++) {
+			expected_ptr = expected_colors[l][z] =
+				malloc(level_size[l][0] * level_size[l][1] *
+				       level_size[l][2] * 4 * sizeof(float));
+			for (y = 0; y < level_size[l][1]; y++) {
+				for (x = 0; x < level_size[l][0]; x++) {
+					int nx = sampler.data_type == GL_UNSIGNED_INT ?  x : -x;
+					f_ptr[0] = nx;
+					f_ptr[1] = y;
+					f_ptr[2] = z;
+					f_ptr[3] = 1.0;
+
+					i_ptr[0] = nx;
+					i_ptr[1] = y;
+					i_ptr[2] = z;
+					i_ptr[3] = 1;
+
+					u_ptr[0] = nx;
+					u_ptr[1] = y;
+					u_ptr[2] = z;
+					u_ptr[3] = 1;
+
+					compute_divisors(l, divisors);
+
+					expected_ptr[0] = f_ptr[0]/divisors[0];
+					expected_ptr[1] = f_ptr[1]/divisors[1];
+					expected_ptr[2] = f_ptr[2]/divisors[2];
+					expected_ptr[3] = 1.0;
+
+					f_ptr += 4;
+					i_ptr += 4;
+					u_ptr += 4;
+					expected_ptr += 4;
+				}
+			}
+		}
+
+		switch (sampler.data_type) {
+		case GL_FLOAT:
+			level_image = f_level;
+			break;
+		case GL_UNSIGNED_INT:
+			level_image = u_level;
+			break;
+		case GL_INT:
+			level_image = i_level;
+			break;
+		}
+
+		upload_miplevel_data(target, l, level_image);
+	}
+}
+
+/**
+ * How many components are in the coordinate?
+ */
+static int
+coordinate_size()
+{
+	switch (sampler.target) {
+	case GL_TEXTURE_1D:
+		return 1;
+	case GL_TEXTURE_2D:
+	case GL_TEXTURE_1D_ARRAY:
+	case GL_TEXTURE_RECTANGLE:
+		return 2;
+	case GL_TEXTURE_3D:
+	case GL_TEXTURE_2D_ARRAY:
+		return 3;
+	default:
+		assert(!"Should not get here.");
+		return 0;
+	}
+}
+
+/**
+ * Generate, compile, and link the GLSL shaders.
+ */
+int
+generate_GLSL(enum shader_target test_stage)
+{
+	int vs, fs, prog;
+
+	static char *vs_code;
+	static char *fs_code;
+
+	switch (test_stage) {
+	case VS:
+		asprintf(&vs_code,
+			 "#version 130\n"
+			 "#define ivec1 int\n"
+			 "flat out %s color;\n"
+			 "in vec4 pos;\n"
+			 "in ivec4 texcoord;\n"
+			 "uniform %s tex;\n"
+			 "void main()\n"
+			 "{\n"
+			 "    color = texelFetch(tex, ivec%d(texcoord),\n"
+			 "                       texcoord.w);\n"
+			 "    gl_Position = gl_ModelViewProjectionMatrix*pos;\n"
+			 "}\n",
+			 sampler.return_type, sampler.name, coordinate_size());
+		asprintf(&fs_code,
+			 "#version 130\n"
+			 "flat in %s color;\n"
+			 "uniform vec4 divisor;\n"
+			 "void main()\n"
+			 "{\n"
+			 "    gl_FragColor = vec4(color)/divisor;\n"
+			 "}\n",
+			 sampler.return_type);
+		break;
+	case FS:
+		asprintf(&vs_code,
+			 "#version 130\n"
+			 "#define ivec1 int\n"
+			 "in vec4 pos;\n"
+			 "in ivec4 texcoord;\n"
+			 "flat out ivec4 tc;\n"
+			 "void main()\n"
+			 "{\n"
+			 "    tc = texcoord;\n"
+			 "    gl_Position = gl_ModelViewProjectionMatrix*pos;\n"
+			 "}\n");
+		asprintf(&fs_code,
+			 "#version 130\n"
+			 "#define ivec1 int\n"
+			 "flat in ivec4 tc;\n"
+			 "uniform vec4 divisor;\n"
+			 "uniform %s tex;\n"
+			 "void main()\n"
+			 "{\n"
+			 "    vec4 color = texelFetch(tex, ivec%d(tc), tc.w);\n"
+			 "    gl_FragColor = color/divisor;\n"
+			 "}\n",
+			 sampler.name, coordinate_size());
+		break;
+	default:
+		assert(!"Should not get here.");
+		break;
+	}
+
+	vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_code);
+	fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, fs_code);
+	prog = piglit_CreateProgram();
+	piglit_AttachShader(prog, vs);
+	piglit_AttachShader(prog, fs);
+
+	glBindAttribLocation(prog, pos_loc, "pos");
+	glBindAttribLocation(prog, texcoord_loc, "texcoord");
+
+	piglit_LinkProgram(prog);
+	piglit_link_check_status(prog);
+
+	return prog;
+}
+
+/**
+ * Set the size of the texture's base level.
+ */
+void
+set_base_size()
+{
+	base_size[0] = 65;
+	base_size[1] = has_height() ? 32 : 1;
+	base_size[2] = has_slices() ?  5 : 1;
+}
+
+/**
+ * Is this sampler supported by texelFetch?
+ */
+static bool
+supported_sampler()
+{
+	switch (sampler.target) {
+	case GL_TEXTURE_1D:
+	case GL_TEXTURE_2D:
+	case GL_TEXTURE_3D:
+	case GL_TEXTURE_1D_ARRAY:
+	case GL_TEXTURE_2D_ARRAY:
+	/* case GL_TEXTURE_RECTANGLE: not implemented yet */
+		return true;
+	}
+	return false;
+}
+
+void
+fail_and_show_usage()
+{
+	printf("Usage: texelFetch <vs|fs> <sampler type> [piglit args...]\n");
+	piglit_report_result(PIGLIT_FAIL);
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+	int prog;
+	int tex_location;
+	int i;
+	enum shader_target test_stage = UNKNOWN;
+	bool sampler_found = false;
+
+	for (i = 1; i < argc; i++) {
+		if (test_stage == UNKNOWN) {
+			/* Maybe it's the shader stage? */
+			if (strcmp(argv[i], "vs") == 0) {
+				test_stage = VS;
+				continue;
+			} else if (strcmp(argv[i], "fs") == 0) {
+				test_stage = FS;
+				continue;
+			}
+		}
+
+		/* Maybe it's the sampler type? */
+		if (!sampler_found && (sampler_found = select_sampler(argv[i])))
+			continue;
+
+		fail_and_show_usage();
+	}
+
+	if (test_stage == UNKNOWN || !sampler_found)
+		fail_and_show_usage();
+
+	if (!supported_sampler()) {
+		printf("%s unsupported\n", sampler.name);
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	require_GL_features(test_stage);
+
+	prog = generate_GLSL(test_stage);
+
+	tex_location = piglit_GetUniformLocation(prog, "tex");
+	divisor_loc = piglit_GetUniformLocation(prog, "divisor");
+
+	piglit_UseProgram(prog);
+
+	piglit_Uniform1i(tex_location, 0);
+
+	/* Create textures and set miplevel info */
+	set_base_size();
+	compute_miplevel_info();
+	generate_texture();
+
+	generate_VBOs();
+}
-- 
1.7.7.3



More information about the Piglit mailing list