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
27 * This file defines the functions which can be utilized to develop new
28 * multisample test cases. Functions can be utilized to:
30 * - Draw a test image to default framebuffer.
31 * - Initialize test_fbo with specified sample count.
32 * - Draw a test image to test_fbo.
33 * - Draw a reference image.
34 * - Verify the accuracy of multisample antialiasing in FBO.
36 * Accuracy verification is done by rendering a scene consisting of
37 * triangles that aren't perfectly aligned to pixel coordinates. Every
38 * triangle in the scene is rendered using a solid color whose color
39 * components are all 0.0 or 1.0. The scene is renederd in two ways:
41 * - At normal resoluation, using MSAA.
43 * - At very high resolution ("supersampled" by a factor of 16 in both
44 * X and Y dimensions), without MSAA.
46 * Then, the supersampled image is scaled down to match the resolution
47 * of the MSAA image, using a fragment shader to manually blend each
48 * block of 16x16 pixels down to 1 pixel. This produces a reference
49 * image, which is then compared to the MSAA image to measure the
50 * error introduced by MSAA.
52 * (Note: the supersampled image is actually larger than the maximum
53 * texture size that GL 3.0 requires all implementations to support
54 * (1024x1024), so it is actually done in 1024x1024 tiles that are
55 * then stitched together to form the reference image).
57 * In the piglit window, the MSAA image appears on the left; the
58 * reference image is on the right.
60 * For each color component of each pixel, if the reference image has
61 * a value of exactly 0.0 or 1.0, that pixel is presumed to be
62 * completely covered by a triangle, so the test verifies that the
63 * corresponding pixel in the MSAA image is exactly 0.0 or 1.0. Where
64 * the reference image has a value between 0.0 and 1.0, we know there
65 * is a triangle boundary that MSAA should smooth out, so the test
66 * estimates the accuracy of MSAA rendering by computing the RMS error
67 * between the reference image and the MSAA image for these pixels.
69 * In addition to the above test (the "color" test), there are functions
70 * which can also verify the proper behavior of the stencil MSAA buffer.
71 * This can be done in two ways:
73 * - "stencil_draw" test: after drawing the scene, we clear the MSAA
74 * color buffer and run a "manifest" pass which uses stencil
75 * operations to make a visual representation of the contents of the
76 * stencil buffer show up in the color buffer. The rest of the test
77 * operates as usual. This allows us to verify that drawing
78 * operations that use the stencil buffer operate correctly in MSAA
81 * - "stencil_resolve" test: same as above, except that we blit the
82 * MSAA stencil buffer to a single-sampled FBO before running the
83 * "manifest" pass. This allows us to verify that the
84 * implementation properly downsamples the MSAA stencil buffer.
86 * There are similar variants "depth_draw" and "depth_resolve" for
87 * testing the MSAA depth buffer.
89 * Note that when downsampling the MSAA color buffer, implementations
90 * are expected to blend the values of each of the color samples;
91 * but when downsampling the stencil and depth buffers, they are
92 * expected to just choose one representative sample (this is because
93 * an intermediate stencil or depth value would not be meaningful).
94 * Therefore, the pass threshold is relaxed for the "stencil_resolve"
95 * and "depth_resolve" tests.
97 * Functions also accepts the following flags:
99 * - "small": Causes the MSAA image to be rendered in extremely tiny
100 * (16x16) tiles that are then stitched together. This verifies
101 * that MSAA works properly on very small buffers (a critical corner
104 * - "depthstencil": Causes the framebuffers to use a combined
105 * depth/stencil buffer (as opposed to separate depth and stencil
106 * buffers). On some implementations (e.g. the nVidia proprietary
107 * driver for Linux) this is necessary for framebuffer completeness.
108 * On others (e.g. i965), this is an important corner case to test.
112 using namespace piglit_util_fbo
;
113 using namespace piglit_util_test_pattern
;
116 DownsampleProg::compile(int supersample_factor
)
118 static const char *vert
=
120 "attribute vec2 pos;\n"
121 "attribute vec2 texCoord;\n"
122 "varying vec2 texCoordVarying;\n"
125 " gl_Position = vec4(pos, 0.0, 1.0);\n"
126 " texCoordVarying = texCoord;\n"
129 static const char *frag_template
=
131 "uniform sampler2DRect samp;\n"
132 "varying vec2 texCoordVarying;\n"
135 " int supersample_factor = %d;\n"
136 " vec4 sum = vec4(0.0);\n"
137 " vec2 pixel = floor(texCoordVarying);\n"
138 " for (int i = 0; i < supersample_factor; ++i) {\n"
139 " for (int j = 0; j < supersample_factor; ++j) {\n"
140 " sum += texture2DRect(\n"
141 " samp, pixel * float(supersample_factor) + vec2(i, j));\n"
144 " gl_FragColor = sum / (supersample_factor * supersample_factor);\n"
148 if (asprintf(&frag
, frag_template
, supersample_factor
) == -1)
149 piglit_report_result(PIGLIT_FAIL
);
151 /* Compile program */
152 prog
= piglit_build_simple_program_unlinked(vert
, frag
);
154 glBindAttribLocation(prog
, 0, "pos");
155 glBindAttribLocation(prog
, 1, "texCoord");
157 if (!piglit_link_check_status(prog
)) {
158 piglit_report_result(PIGLIT_FAIL
);
161 /* Set up uniforms */
163 glUniform1i(glGetUniformLocation(prog
, "samp"), 0);
165 /* Set up vertex array object */
166 glGenVertexArrays(1, &vao
);
167 glBindVertexArray(vao
);
169 /* Set up vertex input buffer */
170 glGenBuffers(1, &vertex_buf
);
171 glBindBuffer(GL_ARRAY_BUFFER
, vertex_buf
);
172 glEnableVertexAttribArray(0);
173 glVertexAttribPointer(0, 2, GL_FLOAT
, GL_FALSE
, 4*sizeof(float),
175 glEnableVertexAttribArray(1);
176 glVertexAttribPointer(1, 2, GL_FLOAT
, GL_FALSE
, 4*sizeof(float),
177 (void *) (2*sizeof(float)));
179 /* Set up element input buffer to tessellate a quad into
182 unsigned int indices
[6] = { 0, 1, 2, 0, 2, 3 };
184 glGenBuffers(1, &element_buf
);
185 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, element_buf
);
186 glBufferData(GL_ELEMENT_ARRAY_BUFFER
, sizeof(indices
), indices
,
191 DownsampleProg::run(const Fbo
*src_fbo
, int dest_width
, int dest_height
,
194 float w
= dest_width
;
195 float h
= dest_height
;
197 glActiveTexture(GL_TEXTURE0
);
198 glBindTexture(GL_TEXTURE_RECTANGLE
, src_fbo
->color_tex
[0]);
201 glBindVertexArray(vao
);
203 float vertex_data
[4][4] = {
209 glBindBuffer(GL_ARRAY_BUFFER
, vertex_buf
);
210 glBufferData(GL_ARRAY_BUFFER
, sizeof(vertex_data
), vertex_data
,
214 /* If we're testing sRGB color, instruct OpenGL to
215 * convert the output of the fragment shader from
216 * linear color space to sRGB color space.
218 glEnable(GL_FRAMEBUFFER_SRGB
);
220 glDrawElements(GL_TRIANGLES
, 6, GL_UNSIGNED_INT
, (void *) 0);
221 glDisable(GL_FRAMEBUFFER_SRGB
);
225 : count(0), sum_squared_error(0.0)
232 printf(" count = %d\n", count
);
234 if (sum_squared_error
!= 0.0) {
235 printf(" RMS error = %f\n",
236 sqrt(sum_squared_error
/ count
));
238 printf(" Perfect output\n");
246 return sum_squared_error
== 0.0;
250 Stats::is_better_than(double rms_error_threshold
)
252 return sqrt(sum_squared_error
/ count
) < rms_error_threshold
;
255 Test::Test(TestPattern
*pattern
, ManifestProgram
*manifest_program
,
256 bool test_resolve
, GLbitfield blit_type
, bool srgb
)
258 manifest_program(manifest_program
),
259 test_resolve(test_resolve
),
260 blit_type(blit_type
),
264 supersample_factor(0),
273 delete manifest_program
;
277 Test::init(int num_samples
, bool small
, bool combine_depth_stencil
,
278 int pattern_width
, int pattern_height
, int supersample_factor
,
281 this->num_samples
= num_samples
;
282 this->pattern_width
= pattern_width
;
283 this->pattern_height
= pattern_height
;
284 this->supersample_factor
= supersample_factor
;
285 this->filter_mode
= filter_mode
;
287 FboConfig
test_fbo_config(0,
288 small
? 16 : pattern_width
,
289 small
? 16 : pattern_height
);
291 test_fbo_config
.color_internalformat
= GL_SRGB8_ALPHA8
;
292 test_fbo_config
.combine_depth_stencil
= combine_depth_stencil
;
293 test_fbo
.setup(test_fbo_config
);
295 FboConfig multisample_fbo_config
= test_fbo_config
;
296 multisample_fbo_config
.num_samples
= num_samples
;
297 multisample_fbo
.setup(multisample_fbo_config
);
299 resolve_fbo
.setup(test_fbo_config
);
301 FboConfig supersample_fbo_config
= test_fbo_config
;
302 supersample_fbo_config
.width
= 1024;
303 supersample_fbo_config
.height
= 1024;
304 supersample_fbo_config
.num_tex_attachments
= 1;
305 supersample_fbo_config
.num_rb_attachments
= 0;
306 supersample_fbo
.setup(supersample_fbo_config
);
308 FboConfig downsample_fbo_config
= test_fbo_config
;
309 downsample_fbo_config
.width
= 1024 / supersample_factor
;
310 downsample_fbo_config
.height
= 1024 / supersample_factor
;
311 downsample_fbo
.setup(downsample_fbo_config
);
314 downsample_prog
.compile(supersample_factor
);
315 if (manifest_program
)
316 manifest_program
->compile();
318 /* Only do depth testing in those parts of the test where we
321 glDisable(GL_DEPTH_TEST
);
325 * Blit the data from multisample_fbo to resolve_fbo, forcing the
326 * implementation to do an MSAA resolve.
329 Test::resolve(Fbo
*fbo
, GLbitfield which_buffers
)
331 glBindFramebuffer(GL_READ_FRAMEBUFFER
, fbo
->handle
);
332 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, resolve_fbo
.handle
);
333 resolve_fbo
.set_viewport();
336 glEnable(GL_FRAMEBUFFER_SRGB
);
337 glBlitFramebuffer(0, 0, fbo
->config
.width
, fbo
->config
.height
,
338 0, 0, resolve_fbo
.config
.width
,
339 resolve_fbo
.config
.height
,
340 which_buffers
, filter_mode
);
341 glDisable(GL_FRAMEBUFFER_SRGB
);
345 * Use downsample_prog to blend 16x16 blocks of samples in
346 * supersample_fbo, to produce a reference image in downsample_fbo.
349 Test::downsample_color(int downsampled_width
, int downsampled_height
)
352 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, downsample_fbo
.handle
);
353 downsample_fbo
.set_viewport();
354 downsample_prog
.run(&supersample_fbo
,
355 downsample_fbo
.config
.width
,
356 downsample_fbo
.config
.height
, srgb
);
360 * Blit the color data from src_fbo to the given location in the
361 * windowsystem buffer, so that the user can see it and we can read it
362 * using glReadPixels.
365 Test::show(Fbo
*src_fbo
, int x_offset
, int y_offset
)
367 glBindFramebuffer(GL_READ_FRAMEBUFFER
, src_fbo
->handle
);
368 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, piglit_winsys_fbo
);
369 glViewport(0, 0, piglit_width
, piglit_height
);
370 glBlitFramebuffer(0, 0, src_fbo
->config
.width
, src_fbo
->config
.height
,
372 x_offset
+ src_fbo
->config
.width
,
373 y_offset
+ src_fbo
->config
.height
,
374 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
378 * Draw a portion of the test pattern by setting up an appropriate
379 * projection matrix to map that portion of the test pattern to the
383 Test::draw_pattern(int x_offset
, int y_offset
, int width
, int height
)
385 /* Need a projection matrix such that:
386 * xc = ((xe + 1) * pattern_width/2 - x_offset) * 2/width - 1
387 * yc = ((ye + 1) * pattern_height/2 - y_offset) * 2/height - 1
392 * xc = pattern_width / width * xe
393 * + pattern_width / width - x_offset * 2 / width - 1
394 * yc = pattern_height / height * ye
395 * + pattern_height / height - y_offset * 2 / height - 1
399 float x_scale
= float(pattern_width
) / width
;
400 float x_delta
= x_scale
- x_offset
* 2.0 / width
- 1.0;
401 float y_scale
= float(pattern_height
) / height
;
402 float y_delta
= y_scale
- y_offset
* 2.0 / height
- 1.0;
404 { x_scale
, 0, 0, x_delta
},
405 { 0, y_scale
, 0, y_delta
},
414 * Draw the entire test image, rendering it a piece at a time if
415 * multisample_fbo is very small.
418 Test::draw_test_image(Fbo
*fbo
)
420 int num_h_tiles
= pattern_width
/ fbo
->config
.width
;
421 int num_v_tiles
= pattern_height
/ fbo
->config
.height
;
422 for (int h
= 0; h
< num_h_tiles
; ++h
) {
423 for (int v
= 0; v
< num_v_tiles
; ++v
) {
424 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
,
427 int x_offset
= h
* fbo
->config
.width
;
428 int y_offset
= v
* fbo
->config
.height
;
429 draw_pattern(x_offset
, y_offset
,
433 resolve(fbo
, blit_type
);
434 if (manifest_program
)
435 manifest_program
->run();
437 if (manifest_program
)
438 manifest_program
->run();
440 GL_COLOR_BUFFER_BIT
);
443 show(&resolve_fbo
, x_offset
, y_offset
);
449 * Draw the test image to the default framebuffer
452 Test::draw_to_default_framebuffer()
454 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, piglit_winsys_fbo
);
455 glViewport(0, 0, pattern_width
, pattern_height
);
456 draw_pattern(0, 0, pattern_width
, pattern_height
);
460 * Draw the entire test image, rendering it a piece at a time.
463 Test::draw_reference_image()
465 int downsampled_width
=
466 supersample_fbo
.config
.width
/ supersample_factor
;
467 int downsampled_height
=
468 supersample_fbo
.config
.height
/ supersample_factor
;
469 int num_h_tiles
= pattern_width
/ downsampled_width
;
470 int num_v_tiles
= pattern_height
/ downsampled_height
;
471 for (int h
= 0; h
< num_h_tiles
; ++h
) {
472 for (int v
= 0; v
< num_v_tiles
; ++v
) {
473 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
,
474 supersample_fbo
.handle
);
475 supersample_fbo
.set_viewport();
476 int x_offset
= h
* downsampled_width
;
477 int y_offset
= v
* downsampled_height
;
478 draw_pattern(x_offset
, y_offset
,
479 downsampled_width
, downsampled_height
);
481 if (manifest_program
)
482 manifest_program
->run();
484 downsample_color(downsampled_width
, downsampled_height
);
485 show(&downsample_fbo
,
486 pattern_width
+ x_offset
, y_offset
);
492 * Measure the accuracy of MSAA downsampling. Pixels that are fully
493 * on or off in the reference image are required to be fully on or off
494 * in the test image. Pixels that are not fully on or off in the
495 * reference image may be at any grayscale level; we mesaure the RMS
496 * error between the reference image and the test image.
499 Test::measure_accuracy()
503 glBindFramebuffer(GL_READ_FRAMEBUFFER
, piglit_winsys_fbo
);
504 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, piglit_winsys_fbo
);
505 glViewport(0, 0, piglit_width
, piglit_height
);
507 float *reference_data
= new float[pattern_width
* pattern_height
* 4];
508 glReadPixels(pattern_width
, 0, pattern_width
, pattern_height
, GL_RGBA
,
509 GL_FLOAT
, reference_data
);
511 float *test_data
= new float[pattern_width
* pattern_height
* 4];
512 glReadPixels(0, 0, pattern_width
, pattern_height
, GL_RGBA
,
513 GL_FLOAT
, test_data
);
516 Stats partially_lit_stats
;
517 Stats totally_lit_stats
;
518 for (int y
= 0; y
< pattern_height
; ++y
) {
519 for (int x
= 0; x
< pattern_width
; ++x
) {
520 for (int c
= 0; c
< 4; ++c
) {
521 int pixel_pos
= 4*(y
*pattern_width
+ x
) + c
;
522 float ref
= reference_data
[pixel_pos
];
523 float test
= test_data
[pixel_pos
];
524 /* When testing sRGB, compare pixels
525 * linearly so that the measured error
526 * is comparable to the non-sRGB case.
529 ref
= piglit_srgb_to_linear(ref
);
530 test
= piglit_srgb_to_linear(test
);
533 unlit_stats
.record(test
- ref
);
535 totally_lit_stats
.record(test
- ref
);
537 partially_lit_stats
.record(test
- ref
);
542 double error_threshold
;
544 /* For depth and stencil resolves, the implementation
545 * typically just picks one of the N multisamples, so
546 * we have to allow for a generous amount of error.
548 error_threshold
= 0.4;
550 /* Empirically, the RMS error for no oversampling is
551 * about 0.25, and each additional factor of 2
552 * overampling reduces the error by a factor of about
553 * 0.6. Leaving some room for variation, we'll set
554 * the error threshold to 0.333 * 0.62 ^
557 int effective_num_samples
= num_samples
== 0 ? 1 : num_samples
;
558 error_threshold
= 0.333 *
559 pow(0.62, ffs(effective_num_samples
) - 1);
562 /* The unlit and totally_lit stats are supposed to count the
563 * pixels where either a primitive completely covers the pixel
564 * or no primitive touches it at all. However this is
565 * effectively only determined by checking whether any
566 * primitive has intersected one of the supersample positions
567 * of the reference image. It's completely possible for a
568 * primitive to intersect the pixel boundary but completely
569 * miss any of the supersample positions. The GL
570 * implementation is free to pick whatever multisample
571 * positions it wants within the pixel boundary so it's also
572 * possible for a primitive to intersect a multisample
573 * position but miss all of the supersample positions of the
574 * reference image. To cope with this we allow a small margin
575 * of error for the pixels that are either fully lit or fully
578 double full_pixel_threshold
= error_threshold
* 0.05f
;
580 printf("Pixels that should be unlit\n");
581 unlit_stats
.summarize();
582 pass
= unlit_stats
.is_better_than(full_pixel_threshold
) && pass
;
583 printf("Pixels that should be totally lit\n");
584 totally_lit_stats
.summarize();
585 pass
= totally_lit_stats
.is_better_than(full_pixel_threshold
) && pass
;
586 printf("The error threshold for unlit and totally lit "
587 "pixels test is %f\n",
588 full_pixel_threshold
);
589 printf("Pixels that should be partially lit\n");
590 partially_lit_stats
.summarize();
592 printf("The error threshold for partially lit pixels is %f\n",
594 pass
= partially_lit_stats
.is_better_than(error_threshold
) && pass
;
595 // TODO: deal with sRGB.
602 draw_test_image(&multisample_fbo
);
603 draw_reference_image();
604 return measure_accuracy();
609 create_test(test_type_enum test_type
, int n_samples
, bool small
,
610 bool combine_depth_stencil
, int pattern_width
, int pattern_height
,
611 int supersample_factor
, GLenum filter_mode
)
615 case TEST_TYPE_COLOR
:
616 test
= new Test(new Triangles(), NULL
, false, 0, false);
619 test
= new Test(new Triangles(), NULL
, false, 0, true);
621 case TEST_TYPE_STENCIL_DRAW
:
622 test
= new Test(new StencilSunburst(),
623 new ManifestStencil(),
626 case TEST_TYPE_STENCIL_RESOLVE
:
627 test
= new Test(new StencilSunburst(),
628 new ManifestStencil(),
630 GL_STENCIL_BUFFER_BIT
, false);
632 case TEST_TYPE_DEPTH_DRAW
:
633 test
= new Test(new DepthSunburst(),
637 case TEST_TYPE_DEPTH_RESOLVE
:
638 test
= new Test(new DepthSunburst(),
641 GL_DEPTH_BUFFER_BIT
, false);
644 printf("Unrecognized test type\n");
645 piglit_report_result(PIGLIT_FAIL
);
649 test
->init(n_samples
, small
, combine_depth_stencil
, pattern_width
,
650 pattern_height
, supersample_factor
, filter_mode
);