[Piglit] [PATCH] msaa: Test that the "centroid" interpolation qualifier works correctly.

Paul Berry stereotype441 at gmail.com
Thu Jun 21 10:18:08 PDT 2012


This patch adds tests to verify that:

- When GL_MULTISAMPLE is disabled, the "centroid" keyword is ignored,
  and interpolation is performed at pixel centers (consistent with the
  GL rules for non-antialiased rendering).

- When GL_MULTISAMPLE is enabled and the "centroid" keyword is used,
  interpolation is performed at a location within the boundary of the
  triangle.  The test also verifies that errors introduced into
  derivatives are kept within reasonable bounds.

- When GL_MULTISAMPLE is enabled and the "centroid" keyword is absent,
  derivatives are accurate.

Verified using nVidia's proprietary binary driver for Linux.
---

Note: this patch depends on some other piglit patches that are still
out for review.  You can see the patch in its proper context by
checking out branch "centroid" from
git://github.com/stereotype441/piglit.git.


 tests/all.tests                                    |   15 +
 .../ext_framebuffer_multisample/CMakeLists.gl.txt  |    1 +
 tests/spec/ext_framebuffer_multisample/common.cpp  |  132 ++++++
 tests/spec/ext_framebuffer_multisample/common.h    |   38 ++-
 .../ext_framebuffer_multisample/interpolation.cpp  |  453 ++++++++++++++++++++
 5 files changed, 638 insertions(+), 1 deletions(-)
 create mode 100644 tests/spec/ext_framebuffer_multisample/interpolation.cpp

diff --git a/tests/all.tests b/tests/all.tests
index 1990d40..bf081d9 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -1407,6 +1407,21 @@ for num_samples in MSAA_SAMPLE_COUNTS:
                 ext_framebuffer_multisample[test_name] = PlainExecTest(
                         executable)
 
+# Note: the interpolation tests also check for sensible behaviour with
+# non-multisampled framebuffers, so go ahead and test them with
+# num_samples==0 as well.
+for num_samples in (0,) + MSAA_SAMPLE_COUNTS:
+        for test_type in ('non-centroid-disabled', 'centroid-disabled',
+                          'centroid-edges', 'non-centroid-deriv',
+                          'non-centroid-deriv-disabled', 'centroid-deriv',
+                          'centroid-deriv-disabled'):
+                test_name = ' '.join(['interpolation', str(num_samples),
+                                      test_type])
+                executable = 'ext_framebuffer_multisample-{0} -auto'.format(
+                        test_name)
+                ext_framebuffer_multisample[test_name] = PlainExecTest(
+                        executable)
+
 ext_framebuffer_object = Group()
 spec['EXT_framebuffer_object'] = ext_framebuffer_object
 add_fbo_stencil_tests(ext_framebuffer_object, 'GL_STENCIL_INDEX1')
diff --git a/tests/spec/ext_framebuffer_multisample/CMakeLists.gl.txt b/tests/spec/ext_framebuffer_multisample/CMakeLists.gl.txt
index b9deef0..7a73e95 100644
--- a/tests/spec/ext_framebuffer_multisample/CMakeLists.gl.txt
+++ b/tests/spec/ext_framebuffer_multisample/CMakeLists.gl.txt
@@ -17,6 +17,7 @@ piglit_add_executable (ext_framebuffer_multisample-clip-and-scissor-blit common.
 piglit_add_executable (ext_framebuffer_multisample-dlist dlist.c)
 piglit_add_executable (ext_framebuffer_multisample-enable-flag enable-flag.cpp common.cpp)
 piglit_add_executable (ext_framebuffer_multisample-formats common.cpp formats.cpp)
+piglit_add_executable (ext_framebuffer_multisample-interpolation common.cpp interpolation.cpp)
 piglit_add_executable (ext_framebuffer_multisample-line-smooth common.cpp line-smooth.cpp)
 piglit_add_executable (ext_framebuffer_multisample-minmax minmax.c)
 piglit_add_executable (ext_framebuffer_multisample-multisample-blit common.cpp multisample-blit.cpp)
diff --git a/tests/spec/ext_framebuffer_multisample/common.cpp b/tests/spec/ext_framebuffer_multisample/common.cpp
index c211363..897f901 100644
--- a/tests/spec/ext_framebuffer_multisample/common.cpp
+++ b/tests/spec/ext_framebuffer_multisample/common.cpp
@@ -691,6 +691,138 @@ void Triangles::draw(const float (*proj)[4])
 	}
 }
 
+
+InterpolationTestPattern::InterpolationTestPattern(const char *frag)
+	: frag(frag)
+{
+}
+
+
+void
+InterpolationTestPattern::compile()
+{
+	static struct vertex_attributes {
+		float pos_within_tri[2];
+		float barycentric_coords[3];
+	} vertex_data[] = {
+		{ { -0.5, -1.0 }, { 1, 0, 0 } },
+		{ {  0.0,  1.0 }, { 0, 1, 0 } },
+		{ {  0.5, -1.0 }, { 0, 0, 1 } }
+	};
+
+	/* Number of triangle instances across (and down) */
+	int tris_across = 8;
+
+	/* Total number of triangles drawn */
+	num_tris = tris_across * tris_across;
+
+	/* Scaling factor uniformly applied to triangle coords */
+	float tri_scale = 0.8 / tris_across;
+
+	/* Amount each triangle should be rotated compared to prev */
+	float rotation_delta = M_PI * 2.0 / num_tris;
+
+	/* Final scaling factor */
+	float final_scale = 0.95;
+
+	static const char *vert =
+		"#version 130\n"
+		"in vec2 pos_within_tri;\n"
+		"in vec3 in_barycentric_coords;\n"
+		"out vec3 barycentric_coords;\n"
+		"centroid out vec3 barycentric_coords_centroid;\n"
+		"out vec2 pixel_pos;\n"
+		"centroid out vec2 pixel_pos_centroid;\n"
+		"uniform float tri_scale;\n"
+		"uniform float rotation_delta;\n"
+		"uniform int tris_across;\n"
+		"uniform float final_scale;\n"
+		"uniform mat4 proj;\n"
+		"uniform int tri_num;\n"
+		"uniform ivec2 viewport_size;\n"
+		"\n"
+		"void main()\n"
+		"{\n"
+		"  vec2 pos = tri_scale * pos_within_tri;\n"
+		"  float rotation = rotation_delta * tri_num;\n"
+		"  pos = mat2(cos(rotation), sin(rotation),\n"
+		"             -sin(rotation), cos(rotation)) * pos;\n"
+		"  int i = tri_num % tris_across;\n"
+		"  int j = tris_across - 1 - tri_num / tris_across;\n"
+		"  pos += (vec2(i, j) * 2.0 + 1.0) / tris_across - 1.0;\n"
+		"  pos *= final_scale;\n"
+		"  gl_Position = proj * vec4(pos, 0.0, 1.0);\n"
+		"  barycentric_coords = barycentric_coords_centroid =\n"
+		"    in_barycentric_coords;\n"
+		"  pixel_pos = pixel_pos_centroid =\n"
+		"    vec2(viewport_size) * (pos + 1.0) / 2.0;\n"
+		"}\n";
+
+	/* Compile program */
+	prog = glCreateProgram();
+	GLint vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vert);
+	glAttachShader(prog, vs);
+	GLint fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, frag);
+	glAttachShader(prog, fs);
+	glBindAttribLocation(prog, 0, "pos_within_tri");
+	glBindAttribLocation(prog, 1, "in_barycentric_coords");
+	glLinkProgram(prog);
+	if (!piglit_link_check_status(prog)) {
+		piglit_report_result(PIGLIT_FAIL);
+	}
+
+	/* Set up uniforms */
+	glUseProgram(prog);
+	glUniform1f(glGetUniformLocation(prog, "tri_scale"), tri_scale);
+	glUniform1f(glGetUniformLocation(prog, "rotation_delta"),
+		    rotation_delta);
+	glUniform1i(glGetUniformLocation(prog, "tris_across"), tris_across);
+	glUniform1f(glGetUniformLocation(prog, "final_scale"), final_scale);
+	proj_loc = glGetUniformLocation(prog, "proj");
+	tri_num_loc = glGetUniformLocation(prog, "tri_num");
+	viewport_size_loc = glGetUniformLocation(prog, "viewport_size");
+
+	/* Set up vertex array object */
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+
+	/* Set up vertex input buffer */
+	glGenBuffers(1, &vertex_buf);
+	glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
+		     GL_STATIC_DRAW);
+	glEnableVertexAttribArray(0);
+	glVertexAttribPointer(0, ARRAY_SIZE(vertex_data[0].pos_within_tri),
+			      GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
+			      (void *) offsetof(vertex_attributes,
+						pos_within_tri));
+	glEnableVertexAttribArray(1);
+	glVertexAttribPointer(1, ARRAY_SIZE(vertex_data[0].barycentric_coords),
+			      GL_FLOAT, GL_FALSE, sizeof(vertex_data[0]),
+			      (void *) offsetof(vertex_attributes,
+						barycentric_coords));
+}
+
+
+void
+InterpolationTestPattern::draw(const float (*proj)[4])
+{
+	glUseProgram(prog);
+
+	/* Depending what the fragment shader does, it's possible that
+	 * viewport_size might get optimized away.  Only set it if it
+	 * didn't.
+	 */
+	if (viewport_size_loc != -1) {
+		GLint viewport_dims[4];
+		glGetIntegerv(GL_VIEWPORT, viewport_dims);
+		glUniform2i(viewport_size_loc, viewport_dims[2], viewport_dims[3]);
+	}
+
+	Triangles::draw(proj);
+}
+
+
 void Lines::compile()
 {
 	/* Line coords within (-1,-1) to (1,1) rect */
diff --git a/tests/spec/ext_framebuffer_multisample/common.h b/tests/spec/ext_framebuffer_multisample/common.h
index a248dbc..4eb1ee7 100644
--- a/tests/spec/ext_framebuffer_multisample/common.h
+++ b/tests/spec/ext_framebuffer_multisample/common.h
@@ -245,7 +245,7 @@ public:
 	virtual void compile();
 	virtual void draw(const float (*proj)[4]);
 
-private:
+protected:
 	GLint prog;
 	GLuint vertex_buf;
 	GLuint vao;
@@ -254,6 +254,42 @@ private:
 	int num_tris;
 };
 
+
+/**
+ * Program we use to test that interpolation works properly.
+ *
+ * This program draws the same sequence of small triangles as the
+ * Triangles program, but it's capable of coloring the triangles in
+ * various ways based on the fragment program provided to the
+ * constructor.
+ *
+ * The fragment program has access to the following variables:
+ *
+ * - in vec3 barycentric_coords: barycentric coordinates of the
+ *   triangle being drawn, normally interpolated.
+ *
+ * - centroid in vec3 barycentric_coords_centroid: same as
+ *   barycentric_coords, but centroid interpolated.
+ *
+ * - in vec2 pixel_pos: pixel coordinate ((0,0) to (viewport_width,
+ *   viewport_height)), normally interpolated.
+ *
+ * - centroid in vec2 pixel_pos_centroid: same as pixel_pos, but
+ *   centroid interpolated.
+ */
+class InterpolationTestPattern : public Triangles
+{
+public:
+	explicit InterpolationTestPattern(const char *frag);
+	virtual void compile();
+	virtual void draw(const float (*proj)[4]);
+
+private:
+	const char *frag;
+	GLint viewport_size_loc;
+};
+
+
 /**
  * Program we use to draw a test pattern into the color buffer.
  *
diff --git a/tests/spec/ext_framebuffer_multisample/interpolation.cpp b/tests/spec/ext_framebuffer_multisample/interpolation.cpp
new file mode 100644
index 0000000..45db66f
--- /dev/null
+++ b/tests/spec/ext_framebuffer_multisample/interpolation.cpp
@@ -0,0 +1,453 @@
+/*
+ * Copyright © 2012 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 interpolation.cpp
+ *
+ * Verify that the implementation interpolates varyings correctly when
+ * multisampling is in use, particularly that it properly implements
+ * the "centroid" keyword.
+ *
+ * From the GLSL 1.30 spec, section 4.3.7 (Interpolation):
+ *
+ *     "This paragraph only applies if interpolation is being done: If
+ *     single-sampling, the value is interpolated to the pixel's
+ *     center, and the centroid qualifier, if present, is ignored. If
+ *     multi-sampling and the variable is not qualified with centroid,
+ *     then the value must be interpolated to the pixel's center, or
+ *     anywhere within the pixel, or to one of the pixel's samples. If
+ *     multi-sampling and the variable is qualified with centroid,
+ *     then the value must be interpolated to a point that lies in
+ *     both the pixel and in the primitive being rendered, or to one
+ *     of the pixel's samples that falls within the primitive. Due to
+ *     the less regular location of centroids, their derivatives may
+ *     be less accurate than non-centroid interpolated variables."
+ *
+ *
+ * This test accepts two command-line parameters, a value for
+ * num_samples, and a test type.  The test types are as follows:
+ *
+ * - non-centroid-disabled: verify that non-centroid interpolation
+ *   produces the same results when applied to a non-multisampled
+ *   buffer and a multisampled buffer with GL_MULTISAMPLE disabled.
+ *   This effectively verifies that non-centroid varyings are
+ *   interpolated at the pixel center when single-sampling.  The test
+ *   uses a fragment shader that sets the red, green, and blue
+ *   channels to the barycentric coordinates within each triangle.
+ *
+ * - centroid-disabled: verify that centroid interpolation produces
+ *   the same results as non-centroid interpolation when applied to a
+ *   multisampled buffer with GL_MULTISAMPLE disabled.  This
+ *   effectively verifies that centroid varyings are interpolated at
+ *   the pixel center when single-sampling.  This test may also be run
+ *   with num_samples=0 to verify that centroid varyings work properly
+ *   in non-multisampled buffers.  The test uses a fragment shader
+ *   that sets the red, green, and blue channels to the barycentric
+ *   coordinates within each triangle.
+ *
+ * - centroid-edges: verify that centroid interpolation occurs at
+ *   points that lie within the extents of the triangle, even for
+ *   pixels on triangle edges, where the center of the pixel might lie
+ *   outside the extents of the triangle.  The test uses a fragment
+ *   shader that sets the blue channel to 1.0 (so that the triangles
+ *   can be seen) and the red and green channels to 1.0 if any of the
+ *   centroid-interpolated barycentric coordinates is outside the
+ *   range [0, 1].
+ *
+ * - non-centroid-deriv: verify that the numeric derivative of a
+ *   varying using non-centroid interpolation is correct, even at
+ *   triangle edges.  This ensures that the implementation properly
+ *   handles a subtle corner case: since numeric derivatives are
+ *   usually computed using finite differences between adjacent
+ *   pixels, it's possible that the value of a varying at a completely
+ *   uncovered pixel might be used.  In effect, this tests that the
+ *   values of varyings are correct on completely uncovered pixels, if
+ *   those values are needed for derivatives.  This test may also be
+ *   run with num_samples=0 to verify that non-centroid varyings
+ *   exhibit proper derivative behaviour in non-multisampled buffers.
+ *   The test uses a fragment shader that sets red=dFdx(interpolated x
+ *   coordinate), green=dFdy(interpolated y coordinate), and blue=1.0,
+ *   with appropriate scaling applied to the red and green outputs so
+ *   that the expected output is red=0.5 and green=0.5.
+ *
+ * - non-centroid-deriv-disabled: Like non-centroid-deriv, but the
+ *   test is done with GL_MULTISAMPLE disabled.
+ *
+ * - centroid-deriv: verify that the numeric derivative of a vaying
+ *   using centroid interpolation is within reasonable bounds.  Any
+ *   derivative value between 0 and twice the expected derivative is
+ *   considered passing, since this is the expected error bound for a
+ *   typical implementation (where derivative is computed via a finite
+ *   difference of adjacent pixels, and sample points are within the
+ *   pixel boundary). As with non-centroid-deriv, this test may also
+ *   be run with num_samples=0 to verify that centroid varyings
+ *   exhibit proper derivative behaviour in non-multisampled buffers;
+ *   in this case, the error bounds are as in non-centroid-deriv,
+ *   since centroid-related derivative errors are not expected.  When
+ *   num_samples=0, the fragment shader generates outputs as in
+ *   non-centroid-deriv.  Otherwise it sets the blue channel to 1.0
+ *   (so that the triangles can be seen) and the red nd green channels
+ *   to 1.0 if either derivative is out of tolerance.
+ *
+ * - centroid-deriv-disabled: like centroid-deriv, but the test is
+ *   done with GL_MULTISAMPLE disabled, and the error bounds are as in
+ *   non-centroid-deriv.  The fragment shader generates outputs as in
+ *   non-centroid-deriv.
+ *
+ * All test types draw an array of small triangles at various
+ * rotations, so that pixels are covered in a wide variety of
+ * patterns.  In each case the rendered result is displayed on the
+ * left, and the expected result is displayed on the right for
+ * comparison.
+ */
+
+#include "common.h"
+
+PIGLIT_GL_TEST_MAIN(
+    512 /*window_width*/,
+    256 /*window_height*/,
+    GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA)
+
+namespace {
+
+const int pattern_width = 256; const int pattern_height = 256;
+
+Fbo singlesampled_fbo;
+Fbo multisampled_fbo;
+
+
+/**
+ * Test pattern that we'll use to draw the test image.
+ */
+TestPattern *test_pattern;
+
+
+/**
+ * Test pattern that we'll use to draw the reference image.
+ */
+TestPattern *ref_pattern;
+
+
+/**
+ * If true, we will disable GL_MULTISAMPLE while drawing the test
+ * image, and we will draw the reference image into a single-sample
+ * buffer.
+ */
+bool disable_msaa_during_test_image = false;
+
+
+/**
+ * Fragment shader source that sets the red, green, and blue channels
+ * to the non-centroid-interpolated barycentric coordinates within
+ * each triangle.
+ */
+const char *frag_non_centroid_barycentric =
+	"#version 130\n"
+	"in vec3 barycentric_coords;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"  gl_FragColor = vec4(barycentric_coords, 1.0);\n"
+	"}\n";
+
+
+/**
+ * Fragment shader source that sets the red, green, and blue channels
+ * to the centroid-interpolated barycentric coordinates within each
+ * triangle.
+ */
+const char *frag_centroid_barycentric =
+	"#version 130\n"
+	"centroid in vec3 barycentric_coords_centroid;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"  gl_FragColor = vec4(barycentric_coords_centroid, 1.0);\n"
+	"}\n";
+
+
+/**
+ * Fragment shader source that sets the blue channel to 1.0, and the
+ * red and green channels to 1.0 if any of the centroid-interpolated
+ * barycentric coordinates is outside the range [0, 1].
+ */
+const char *frag_centroid_range_check =
+	"#version 130\n"
+	"centroid in vec3 barycentric_coords_centroid;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"  if (any(greaterThan(barycentric_coords_centroid, vec3(1.0))) ||\n"
+	"      any(lessThan(barycentric_coords_centroid, vec3(0.0))))\n"
+	"    gl_FragColor = vec4(1.0);\n"
+	"  else\n"
+	"    gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
+	"}\n";
+
+
+/**
+ * Fragment shader source that sets red=dFdx(interpolated x
+ * coordinate), green=dFdy(interpolated y coordinate), and blue=1.0,
+ * with appropriate scaling applied to the red and green outputs so
+ * that the expected output is red=0.5 and green=0.5.  The coordinates
+ * are non-centroid interpolated.
+ */
+const char *frag_non_centroid_deriv =
+	"#version 130\n"
+	"in vec2 pixel_pos;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"  gl_FragColor = vec4(0.5*dFdx(pixel_pos.x),\n"
+	"                      0.5*dFdy(pixel_pos.y),\n"
+	"                      1.0, 1.0);\n"
+	"}\n";
+
+
+/**
+ * Fragment shader source that sets red=dFdx(interpolated x
+ * coordinate), green=dFdy(interpolated y coordinate), and blue=1.0,
+ * with appropriate scaling applied to the red and green outputs so
+ * that the expected output is red=0.5 and green=0.5.  The coordinates
+ * are non-centroid interpolated.
+ */
+const char *frag_centroid_deriv =
+	"#version 130\n"
+	"centroid in vec2 pixel_pos_centroid;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"  gl_FragColor = vec4(0.5*dFdx(pixel_pos_centroid.x),\n"
+        "                      0.5*dFdy(pixel_pos_centroid.y),\n"
+	"                      1.0, 1.0);\n"
+	"}\n";
+
+
+/**
+ * Fragment shader source that sets the blue channel to 1.0, and the
+ * red and green channels to 1.0 if either derivative is out of
+ * tolerance.
+ */
+const char *frag_centroid_deriv_range_check =
+	"#version 130\n"
+	"centroid in vec2 pixel_pos_centroid;\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"  if (distance(1.0, dFdx(pixel_pos_centroid.x)) > 1.0 ||\n"
+	"      distance(1.0, dFdy(pixel_pos_centroid.y)) > 1.0)\n"
+	"    gl_FragColor = vec4(1.0);\n"
+	"  else\n"
+	"    gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
+	"}\n";
+
+
+/**
+ * Fragment shader source that outputs blue (the expected output of
+ * frag_centroid_range_check and frag_centroid_deriv_range_check).
+ */
+const char *frag_blue =
+	"#version 130\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"  gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
+	"}\n";
+
+
+/**
+ * Fragment shader source that sets red=0.5, green=0.5, and blue=1.0
+ * (the expected output of frag_non_centroid_deriv and
+ * frag_centroid_deriv).
+ */
+const char *frag_rg_0_5 =
+	"#version 130\n"
+	"\n"
+	"void main()\n"
+	"{\n"
+	"  gl_FragColor = vec4(0.5, 0.5, 1.0, 1.0);\n"
+	"}\n";
+
+
+void
+print_usage_and_exit(char *prog_name)
+{
+	printf("Usage: %s <num_samples> <test_type>\n"
+	       "  where <test_type> is one of:\n"
+	       "    non-centroid-disabled: non-centroid varying, MSAA off\n"
+	       "    centroid-disabled: centroid varying, MSAA off\n"
+	       "    centroid-edges: centroid behaviour at trinagle edges\n"
+	       "    non-centroid-deriv: dFdx/dFdy on non-centroid varying\n"
+	       "    non-centroid-deriv-disabled: As above, with MSAA off\n"
+	       "    centroid-deriv: dFdx/dFdy on centroid varying\n"
+	       "    centroid-deriv-disabled: As above, with MSAA off\n",
+	       prog_name);
+	piglit_report_result(PIGLIT_FAIL);
+}
+
+extern "C" void
+piglit_init(int argc, char **argv)
+{
+	if (argc != 3)
+		print_usage_and_exit(argv[0]);
+
+	/* 1st arg: num_samples */
+	char *endptr = NULL;
+	int num_samples = strtol(argv[1], &endptr, 0);
+	if (endptr != argv[1] + strlen(argv[1]))
+		print_usage_and_exit(argv[0]);
+
+	/* 2nd arg: test_type */
+	const char *frag; /* Fragment shader for the test image */
+	const char *ref_frag; /* Fragment shader for the reference image */
+	if (strcmp(argv[2], "non-centroid-disabled") == 0) {
+		frag = frag_non_centroid_barycentric;
+		ref_frag = frag_non_centroid_barycentric;
+		disable_msaa_during_test_image = true;
+	} else if (strcmp(argv[2], "centroid-disabled") == 0) {
+		frag = frag_centroid_barycentric;
+		ref_frag = frag_non_centroid_barycentric;
+		disable_msaa_during_test_image = true;
+	} else if (strcmp(argv[2], "centroid-edges") == 0) {
+		frag = frag_centroid_range_check;
+		ref_frag = frag_blue;
+	} else if (strcmp(argv[2], "non-centroid-deriv") == 0) {
+		frag = frag_non_centroid_deriv;
+	        ref_frag = frag_rg_0_5;
+	} else if (strcmp(argv[2], "non-centroid-deriv-disabled") == 0) {
+		frag = frag_non_centroid_deriv;
+	        ref_frag = frag_rg_0_5;
+		disable_msaa_during_test_image = true;
+	} else if (strcmp(argv[2], "centroid-deriv") == 0) {
+		if (num_samples == 0) {
+			frag = frag_centroid_deriv;
+			ref_frag = frag_rg_0_5;
+		} else {
+			frag = frag_centroid_deriv_range_check;
+			ref_frag = frag_blue;
+		}
+	} else if (strcmp(argv[2], "centroid-deriv-disabled") == 0) {
+		frag = frag_centroid_deriv;
+		ref_frag = frag_rg_0_5;
+		disable_msaa_during_test_image = true;
+	} else {
+		print_usage_and_exit(argv[0]);
+	}
+
+	piglit_require_gl_version(30);
+
+	/* Skip the test if num_samples > GL_MAX_SAMPLES */
+	GLint max_samples;
+	glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
+	if (num_samples > max_samples)
+		piglit_report_result(PIGLIT_SKIP);
+
+	singlesampled_fbo.setup(FboConfig(0, pattern_width,
+					  pattern_height));
+	multisampled_fbo.setup(FboConfig(num_samples, pattern_width,
+					 pattern_height));
+	test_pattern = new InterpolationTestPattern(frag);
+	test_pattern->compile();
+	ref_pattern = new InterpolationTestPattern(ref_frag);
+	ref_pattern->compile();
+
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		piglit_report_result(PIGLIT_FAIL);
+}
+
+extern "C" enum piglit_result
+piglit_display()
+{
+	bool pass = true;
+
+	/* Draw the test pattern into the multisampled buffer,
+	 * disabling MSAA if appropriate.
+	 */
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, multisampled_fbo.handle);
+	multisampled_fbo.set_viewport();
+	if (disable_msaa_during_test_image)
+		glDisable(GL_MULTISAMPLE);
+	test_pattern->draw(TestPattern::no_projection);
+	if (disable_msaa_during_test_image)
+		glEnable(GL_MULTISAMPLE);
+
+	/* Blit the test pattern to the single-sampled buffer to force
+	 * a resolve.
+	 */
+	glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampled_fbo.handle);
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, singlesampled_fbo.handle);
+	glBlitFramebuffer(0, 0, pattern_width, pattern_height,
+			  0, 0, pattern_width, pattern_height,
+			  GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+	/* Blit the test pattern to the left half of the piglit window. */
+	glBindFramebuffer(GL_READ_FRAMEBUFFER, singlesampled_fbo.handle);
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+	glBlitFramebuffer(0, 0, pattern_width, pattern_height,
+			  0, 0, pattern_width, pattern_height,
+			  GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+	/* Draw the reference pattern.  If we disabled GL_MULTISAMPLE
+	 * while drawing the test pattern, then draw the reference
+	 * pattern into a single-sampled buffer so that multisampling
+	 * won't take place; otherwise draw the reference pattern into
+	 * the multisampled buffer.
+	 */
+	Fbo *draw_fbo = disable_msaa_during_test_image ?
+		&singlesampled_fbo : &multisampled_fbo;
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_fbo->handle);
+	draw_fbo->set_viewport();
+	ref_pattern->draw(TestPattern::no_projection);
+
+	/* If we drew the reference pattern into the multisampled
+	 * buffer, blit to the single-sampled buffer to force a
+	 * resolve.
+	 */
+	if (!disable_msaa_during_test_image) {
+		glBindFramebuffer(GL_READ_FRAMEBUFFER,
+				  multisampled_fbo.handle);
+		glBindFramebuffer(GL_DRAW_FRAMEBUFFER,
+				  singlesampled_fbo.handle);
+		glBlitFramebuffer(0, 0, pattern_width, pattern_height,
+				  0, 0, pattern_width, pattern_height,
+				  GL_COLOR_BUFFER_BIT, GL_NEAREST);
+	}
+
+	/* Blit the reference image to the right half of the piglit window. */
+	glBindFramebuffer(GL_READ_FRAMEBUFFER, singlesampled_fbo.handle);
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+	glBlitFramebuffer(0, 0, pattern_width, pattern_height,
+			  pattern_width, 0, 2*pattern_width, pattern_height,
+			  GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+	/* Compare the test pattern to the reference image. */
+	glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+	pass = piglit_probe_rect_halves_equal_rgba(0, 0, 2*pattern_width,
+						   pattern_height) && pass;
+
+	piglit_present_results();
+
+	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
+}
+
+} /* Anonymous namespace */
-- 
1.7.7.6



More information about the Piglit mailing list