2 * Copyright © 2012 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * \file interpolation.cpp
27 * Verify that the implementation interpolates varyings correctly when
28 * multisampling is in use, particularly that it properly implements
29 * the "centroid" keyword.
31 * From the GLSL 1.30 spec, section 4.3.7 (Interpolation):
33 * "This paragraph only applies if interpolation is being done: If
34 * single-sampling, the value is interpolated to the pixel's
35 * center, and the centroid qualifier, if present, is ignored. If
36 * multi-sampling and the variable is not qualified with centroid,
37 * then the value must be interpolated to the pixel's center, or
38 * anywhere within the pixel, or to one of the pixel's samples. If
39 * multi-sampling and the variable is qualified with centroid,
40 * then the value must be interpolated to a point that lies in
41 * both the pixel and in the primitive being rendered, or to one
42 * of the pixel's samples that falls within the primitive. Due to
43 * the less regular location of centroids, their derivatives may
44 * be less accurate than non-centroid interpolated variables."
47 * This test accepts two command-line parameters, a value for
48 * num_samples, and a test type. The test types are as follows:
50 * - non-centroid-disabled: verify that non-centroid interpolation
51 * produces the same results when applied to a non-multisampled
52 * buffer and a multisampled buffer with GL_MULTISAMPLE disabled.
53 * This effectively verifies that non-centroid varyings are
54 * interpolated at the pixel center when single-sampling. The test
55 * uses a fragment shader that sets the red, green, and blue
56 * channels to the barycentric coordinates within each triangle.
58 * - centroid-disabled: verify that centroid interpolation produces
59 * the same results as non-centroid interpolation when applied to a
60 * multisampled buffer with GL_MULTISAMPLE disabled. This
61 * effectively verifies that centroid varyings are interpolated at
62 * the pixel center when single-sampling. This test may also be run
63 * with num_samples=0 to verify that centroid varyings work properly
64 * in non-multisampled buffers. The test uses a fragment shader
65 * that sets the red, green, and blue channels to the barycentric
66 * coordinates within each triangle.
68 * - centroid-edges: verify that centroid interpolation occurs at
69 * points that lie within the extents of the triangle, even for
70 * pixels on triangle edges, where the center of the pixel might lie
71 * outside the extents of the triangle. The test uses a fragment
72 * shader that sets the blue channel to 1.0 (so that the triangles
73 * can be seen) and the red and green channels to 1.0 if any of the
74 * centroid-interpolated barycentric coordinates is outside the
75 * range [0, 1]; except when num_samples == 0, in which case
76 * it behaves like centroid-disabled.
78 * - non-centroid-deriv: verify that the numeric derivative of a
79 * varying using non-centroid interpolation is correct, even at
80 * triangle edges. This ensures that the implementation properly
81 * handles a subtle corner case: since numeric derivatives are
82 * usually computed using finite differences between adjacent
83 * pixels, it's possible that the value of a varying at a completely
84 * uncovered pixel might be used. In effect, this tests that the
85 * values of varyings are correct on completely uncovered pixels, if
86 * those values are needed for derivatives. This test may also be
87 * run with num_samples=0 to verify that non-centroid varyings
88 * exhibit proper derivative behaviour in non-multisampled buffers.
89 * The test uses a fragment shader that sets red=dFdx(interpolated x
90 * coordinate), green=dFdy(interpolated y coordinate), and blue=1.0,
91 * with appropriate scaling applied to the red and green outputs so
92 * that the expected output is red=0.5 and green=0.5.
94 * - non-centroid-deriv-disabled: Like non-centroid-deriv, but the
95 * test is done with GL_MULTISAMPLE disabled.
97 * - centroid-deriv: verify that the numeric derivative of a vaying
98 * using centroid interpolation is within reasonable bounds. Any
99 * derivative value between 0 and twice the expected derivative is
100 * considered passing, since this is the expected error bound for a
101 * typical implementation (where derivative is computed via a finite
102 * difference of adjacent pixels, and sample points are within the
103 * pixel boundary). As with non-centroid-deriv, this test may also
104 * be run with num_samples=0 to verify that centroid varyings
105 * exhibit proper derivative behaviour in non-multisampled buffers;
106 * in this case, the error bounds are as in non-centroid-deriv,
107 * since centroid-related derivative errors are not expected. When
108 * num_samples=0, the fragment shader generates outputs as in
109 * non-centroid-deriv. Otherwise it sets the blue channel to 1.0
110 * (so that the triangles can be seen) and the red nd green channels
111 * to 1.0 if either derivative is out of tolerance.
113 * - centroid-deriv-disabled: like centroid-deriv, but the test is
114 * done with GL_MULTISAMPLE disabled, and the error bounds are as in
115 * non-centroid-deriv. The fragment shader generates outputs as in
116 * non-centroid-deriv.
118 * All test types draw an array of small triangles at various
119 * rotations, so that pixels are covered in a wide variety of
120 * patterns. In each case the rendered result is displayed on the
121 * left, and the expected result is displayed on the right for
125 #include "piglit-test-pattern.h"
126 #include "piglit-fbo.h"
127 using namespace piglit_util_fbo
;
128 using namespace piglit_util_test_pattern
;
130 PIGLIT_GL_TEST_CONFIG_BEGIN
132 config
.supports_gl_compat_version
= 10;
134 config
.window_width
= 512;
135 config
.window_height
= 256;
136 config
.window_visual
= PIGLIT_GL_VISUAL_DOUBLE
| PIGLIT_GL_VISUAL_RGBA
;
137 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
139 PIGLIT_GL_TEST_CONFIG_END
143 const int pattern_width
= 256; const int pattern_height
= 256;
145 Fbo singlesampled_fbo
;
146 Fbo multisampled_fbo
;
150 * Test pattern that we'll use to draw the test image.
152 TestPattern
*test_pattern
;
156 * Test pattern that we'll use to draw the reference image.
158 TestPattern
*ref_pattern
;
162 * If true, we will disable GL_MULTISAMPLE while drawing the test
163 * image, and we will draw the reference image into a single-sample
166 bool disable_msaa_during_test_image
= false;
170 * Fragment shader source that sets the red, green, and blue channels
171 * to the non-centroid-interpolated barycentric coordinates within
174 const char *frag_non_centroid_barycentric
=
176 "varying vec3 barycentric_coords;\n"
180 " gl_FragColor = vec4(barycentric_coords, 1.0);\n"
185 * Fragment shader source that sets the red, green, and blue channels
186 * to the centroid-interpolated barycentric coordinates within each
189 const char *frag_centroid_barycentric
=
191 "centroid varying vec3 barycentric_coords_centroid;\n"
195 " gl_FragColor = vec4(barycentric_coords_centroid, 1.0);\n"
200 * Fragment shader source that sets the blue channel to 1.0, and the
201 * red and green channels to 1.0 if any of the centroid-interpolated
202 * barycentric coordinates is outside the range [0, 1].
204 const char *frag_centroid_range_check
=
206 "centroid varying vec3 barycentric_coords_centroid;\n"
210 " if (any(greaterThan(barycentric_coords_centroid, vec3(1.0))) ||\n"
211 " any(lessThan(barycentric_coords_centroid, vec3(0.0))))\n"
212 " gl_FragColor = vec4(1.0);\n"
214 " gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
219 * Fragment shader source that sets red=dFdx(interpolated x
220 * coordinate), green=dFdy(interpolated y coordinate), and blue=1.0,
221 * with appropriate scaling applied to the red and green outputs so
222 * that the expected output is red=0.5 and green=0.5. The coordinates
223 * are non-centroid interpolated.
225 const char *frag_non_centroid_deriv
=
227 "varying vec2 pixel_pos;\n"
231 " gl_FragColor = vec4(0.5*dFdx(pixel_pos.x),\n"
232 " 0.5*dFdy(pixel_pos.y),\n"
238 * Fragment shader source that sets red=dFdx(interpolated x
239 * coordinate), green=dFdy(interpolated y coordinate), and blue=1.0,
240 * with appropriate scaling applied to the red and green outputs so
241 * that the expected output is red=0.5 and green=0.5. The coordinates
242 * are non-centroid interpolated.
244 const char *frag_centroid_deriv
=
246 "centroid varying vec2 pixel_pos_centroid;\n"
250 " gl_FragColor = vec4(0.5*dFdx(pixel_pos_centroid.x),\n"
251 " 0.5*dFdy(pixel_pos_centroid.y),\n"
257 * Fragment shader source that sets the blue channel to 1.0, and the
258 * red and green channels to 1.0 if either derivative is out of
261 const char *frag_centroid_deriv_range_check
=
263 "centroid varying vec2 pixel_pos_centroid;\n"
267 " if (distance(1.0, dFdx(pixel_pos_centroid.x)) > 1.0 ||\n"
268 " distance(1.0, dFdy(pixel_pos_centroid.y)) > 1.0)\n"
269 " gl_FragColor = vec4(1.0);\n"
271 " gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
276 * Fragment shader source that outputs blue (the expected output of
277 * frag_centroid_range_check and frag_centroid_deriv_range_check).
279 const char *frag_blue
=
284 " gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
289 * Fragment shader source that sets red=0.5, green=0.5, and blue=1.0
290 * (the expected output of frag_non_centroid_deriv and
291 * frag_centroid_deriv).
293 const char *frag_rg_0_5
=
298 " gl_FragColor = vec4(0.5, 0.5, 1.0, 1.0);\n"
303 print_usage_and_exit(char *prog_name
)
305 printf("Usage: %s <num_samples> <test_type>\n"
306 " where <test_type> is one of:\n"
307 " non-centroid-disabled: non-centroid varying, MSAA off\n"
308 " centroid-disabled: centroid varying, MSAA off\n"
309 " centroid-edges: centroid behaviour at trinagle edges\n"
310 " non-centroid-deriv: dFdx/dFdy on non-centroid varying\n"
311 " non-centroid-deriv-disabled: As above, with MSAA off\n"
312 " centroid-deriv: dFdx/dFdy on centroid varying\n"
313 " centroid-deriv-disabled: As above, with MSAA off\n",
315 piglit_report_result(PIGLIT_FAIL
);
319 piglit_init(int argc
, char **argv
)
322 print_usage_and_exit(argv
[0]);
324 /* 1st arg: num_samples */
326 int num_samples
= strtol(argv
[1], &endptr
, 0);
327 if (endptr
!= argv
[1] + strlen(argv
[1]))
328 print_usage_and_exit(argv
[0]);
330 /* 2nd arg: test_type */
331 const char *frag
; /* Fragment shader for the test image */
332 const char *ref_frag
; /* Fragment shader for the reference image */
333 if (strcmp(argv
[2], "non-centroid-disabled") == 0) {
334 frag
= frag_non_centroid_barycentric
;
335 ref_frag
= frag_non_centroid_barycentric
;
336 disable_msaa_during_test_image
= true;
337 } else if (strcmp(argv
[2], "centroid-disabled") == 0) {
338 frag
= frag_centroid_barycentric
;
339 ref_frag
= frag_non_centroid_barycentric
;
340 disable_msaa_during_test_image
= true;
341 } else if (strcmp(argv
[2], "centroid-edges") == 0) {
342 if (num_samples
== 0) {
343 frag
= frag_centroid_barycentric
;
344 ref_frag
= frag_non_centroid_barycentric
;
346 frag
= frag_centroid_range_check
;
347 ref_frag
= frag_blue
;
349 } else if (strcmp(argv
[2], "non-centroid-deriv") == 0) {
350 frag
= frag_non_centroid_deriv
;
351 ref_frag
= frag_rg_0_5
;
352 } else if (strcmp(argv
[2], "non-centroid-deriv-disabled") == 0) {
353 frag
= frag_non_centroid_deriv
;
354 ref_frag
= frag_rg_0_5
;
355 disable_msaa_during_test_image
= true;
356 } else if (strcmp(argv
[2], "centroid-deriv") == 0) {
357 if (num_samples
== 0) {
358 frag
= frag_centroid_deriv
;
359 ref_frag
= frag_rg_0_5
;
361 frag
= frag_centroid_deriv_range_check
;
362 ref_frag
= frag_blue
;
364 } else if (strcmp(argv
[2], "centroid-deriv-disabled") == 0) {
365 frag
= frag_centroid_deriv
;
366 ref_frag
= frag_rg_0_5
;
367 disable_msaa_during_test_image
= true;
369 print_usage_and_exit(argv
[0]);
372 piglit_require_gl_version(21);
373 piglit_require_extension("GL_ARB_framebuffer_object");
374 piglit_require_extension("GL_ARB_vertex_array_object");
375 piglit_require_extension("GL_EXT_framebuffer_multisample");
377 /* Skip the test if num_samples > GL_MAX_SAMPLES */
379 glGetIntegerv(GL_MAX_SAMPLES
, &max_samples
);
380 if (num_samples
> max_samples
)
381 piglit_report_result(PIGLIT_SKIP
);
383 singlesampled_fbo
.setup(FboConfig(0, pattern_width
,
385 multisampled_fbo
.setup(FboConfig(num_samples
, pattern_width
,
387 test_pattern
= new InterpolationTestPattern(frag
);
388 test_pattern
->compile();
389 ref_pattern
= new InterpolationTestPattern(ref_frag
);
390 ref_pattern
->compile();
392 if (!piglit_check_gl_error(GL_NO_ERROR
))
393 piglit_report_result(PIGLIT_FAIL
);
396 extern "C" enum piglit_result
401 /* Draw the test pattern into the multisampled buffer,
402 * disabling MSAA if appropriate.
404 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, multisampled_fbo
.handle
);
405 multisampled_fbo
.set_viewport();
406 if (disable_msaa_during_test_image
)
407 glDisable(GL_MULTISAMPLE
);
408 test_pattern
->draw(TestPattern::no_projection
);
409 if (disable_msaa_during_test_image
)
410 glEnable(GL_MULTISAMPLE
);
412 /* Blit the test pattern to the single-sampled buffer to force
415 glBindFramebuffer(GL_READ_FRAMEBUFFER
, multisampled_fbo
.handle
);
416 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, singlesampled_fbo
.handle
);
417 glBlitFramebuffer(0, 0, pattern_width
, pattern_height
,
418 0, 0, pattern_width
, pattern_height
,
419 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
421 /* Blit the test pattern to the left half of the piglit window. */
422 glBindFramebuffer(GL_READ_FRAMEBUFFER
, singlesampled_fbo
.handle
);
423 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, piglit_winsys_fbo
);
424 glBlitFramebuffer(0, 0, pattern_width
, pattern_height
,
425 0, 0, pattern_width
, pattern_height
,
426 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
428 /* Draw the reference pattern. If we disabled GL_MULTISAMPLE
429 * while drawing the test pattern, then draw the reference
430 * pattern into a single-sampled buffer so that multisampling
431 * won't take place; otherwise draw the reference pattern into
432 * the multisampled buffer.
434 Fbo
*draw_fbo
= disable_msaa_during_test_image
?
435 &singlesampled_fbo
: &multisampled_fbo
;
436 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, draw_fbo
->handle
);
437 draw_fbo
->set_viewport();
438 ref_pattern
->draw(TestPattern::no_projection
);
440 /* If we drew the reference pattern into the multisampled
441 * buffer, blit to the single-sampled buffer to force a
444 if (!disable_msaa_during_test_image
) {
445 glBindFramebuffer(GL_READ_FRAMEBUFFER
,
446 multisampled_fbo
.handle
);
447 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
,
448 singlesampled_fbo
.handle
);
449 glBlitFramebuffer(0, 0, pattern_width
, pattern_height
,
450 0, 0, pattern_width
, pattern_height
,
451 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
454 /* Blit the reference image to the right half of the piglit window. */
455 glBindFramebuffer(GL_READ_FRAMEBUFFER
, singlesampled_fbo
.handle
);
456 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, piglit_winsys_fbo
);
457 glBlitFramebuffer(0, 0, pattern_width
, pattern_height
,
458 pattern_width
, 0, 2*pattern_width
, pattern_height
,
459 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
461 /* Compare the test pattern to the reference image. */
462 glBindFramebuffer(GL_READ_FRAMEBUFFER
, piglit_winsys_fbo
);
463 pass
= piglit_probe_rect_halves_equal_rgba(0, 0, 2*pattern_width
,
464 pattern_height
) && pass
;
466 piglit_present_results();
468 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
471 } /* Anonymous namespace */