ARB_ubo/referenced-by-shader: pass if shader compiler moves UBOs between shaders
[piglit.git] / tests / spec / ext_framebuffer_multisample / common.cpp
blobed8e1dc019d6d9aa6405854a7395a2bc689d4367
1 /*
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
13 * Software.
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
21 * IN THE SOFTWARE.
24 /**
25 * \file common.cpp
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
79 * mode.
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
102 * case on i965).
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.
111 #include "common.h"
112 using namespace piglit_util_fbo;
113 using namespace piglit_util_test_pattern;
115 void
116 DownsampleProg::compile(int supersample_factor)
118 static const char *vert =
119 "#version 120\n"
120 "attribute vec2 pos;\n"
121 "attribute vec2 texCoord;\n"
122 "varying vec2 texCoordVarying;\n"
123 "void main()\n"
124 "{\n"
125 " gl_Position = vec4(pos, 0.0, 1.0);\n"
126 " texCoordVarying = texCoord;\n"
127 "}\n";
129 static const char *frag_template =
130 "#version 120\n"
131 "uniform sampler2DRect samp;\n"
132 "varying vec2 texCoordVarying;\n"
133 "void main()\n"
134 "{\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"
142 " }\n"
143 " }\n"
144 " gl_FragColor = sum / (supersample_factor * supersample_factor);\n"
145 "}\n";
146 char *frag;
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);
153 free(frag);
154 glBindAttribLocation(prog, 0, "pos");
155 glBindAttribLocation(prog, 1, "texCoord");
156 glLinkProgram(prog);
157 if (!piglit_link_check_status(prog)) {
158 piglit_report_result(PIGLIT_FAIL);
161 /* Set up uniforms */
162 glUseProgram(prog);
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),
174 (void *) 0);
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
180 * triangles
182 unsigned int indices[6] = { 0, 1, 2, 0, 2, 3 };
183 GLuint element_buf;
184 glGenBuffers(1, &element_buf);
185 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buf);
186 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
187 GL_STATIC_DRAW);
190 void
191 DownsampleProg::run(const Fbo *src_fbo, int dest_width, int dest_height,
192 bool srgb)
194 float w = dest_width;
195 float h = dest_height;
197 glActiveTexture(GL_TEXTURE0);
198 glBindTexture(GL_TEXTURE_RECTANGLE, src_fbo->color_tex[0]);
200 glUseProgram(prog);
201 glBindVertexArray(vao);
203 float vertex_data[4][4] = {
204 { -1, -1, 0, 0 },
205 { -1, 1, 0, h },
206 { 1, 1, w, h },
207 { 1, -1, w, 0 }
209 glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
210 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
211 GL_STREAM_DRAW);
213 if (srgb) {
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);
224 Stats::Stats()
225 : count(0), sum_squared_error(0.0)
229 void
230 Stats::summarize()
232 printf(" count = %d\n", count);
233 if (count != 0) {
234 if (sum_squared_error != 0.0) {
235 printf(" RMS error = %f\n",
236 sqrt(sum_squared_error / count));
237 } else {
238 printf(" Perfect output\n");
243 bool
244 Stats::is_perfect()
246 return sum_squared_error == 0.0;
249 bool
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)
257 : pattern(pattern),
258 manifest_program(manifest_program),
259 test_resolve(test_resolve),
260 blit_type(blit_type),
261 num_samples(0),
262 pattern_width(0),
263 pattern_height(0),
264 supersample_factor(0),
265 srgb(srgb),
266 downsample_prog(),
267 filter_mode(GL_NONE)
271 Test::~Test() {
272 delete pattern;
273 delete manifest_program;
276 void
277 Test::init(int num_samples, bool small, bool combine_depth_stencil,
278 int pattern_width, int pattern_height, int supersample_factor,
279 GLenum filter_mode)
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);
290 if (srgb)
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);
313 pattern->compile();
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
319 * explicitly want it
321 glDisable(GL_DEPTH_TEST);
325 * Blit the data from multisample_fbo to resolve_fbo, forcing the
326 * implementation to do an MSAA resolve.
328 void
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();
335 if (srgb)
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.
348 void
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.
364 void
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,
371 x_offset, y_offset,
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
380 * full FBO.
382 void
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
388 * zc = ze
389 * wc = we = 1.0
391 * Therefore
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
396 * zc = ze
397 * wc = we = 1.0
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;
403 float proj[4][4] = {
404 { x_scale, 0, 0, x_delta },
405 { 0, y_scale, 0, y_delta },
406 { 0, 0, 1, 0 },
407 { 0, 0, 0, 1 }
410 pattern->draw(proj);
414 * Draw the entire test image, rendering it a piece at a time if
415 * multisample_fbo is very small.
417 void
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,
425 fbo->handle);
426 fbo->set_viewport();
427 int x_offset = h * fbo->config.width;
428 int y_offset = v * fbo->config.height;
429 draw_pattern(x_offset, y_offset,
430 fbo->config.width,
431 fbo->config.height);
432 if (test_resolve) {
433 resolve(fbo, blit_type);
434 if (manifest_program)
435 manifest_program->run();
436 } else {
437 if (manifest_program)
438 manifest_program->run();
439 resolve(fbo,
440 GL_COLOR_BUFFER_BIT);
443 show(&resolve_fbo, x_offset, y_offset);
449 * Draw the test image to the default framebuffer
451 void
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.
462 void
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.
498 bool
499 Test::measure_accuracy()
501 bool pass = true;
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);
515 Stats unlit_stats;
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.
528 if (srgb && c < 3) {
529 ref = piglit_srgb_to_linear(ref);
530 test = piglit_srgb_to_linear(test);
532 if (ref <= 0.0)
533 unlit_stats.record(test - ref);
534 else if (ref >= 1.0)
535 totally_lit_stats.record(test - ref);
536 else
537 partially_lit_stats.record(test - ref);
542 double error_threshold;
543 if (test_resolve) {
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;
549 } else {
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 ^
555 * log2(num_samples).
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
576 * unlit.
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",
593 error_threshold);
594 pass = partially_lit_stats.is_better_than(error_threshold) && pass;
595 // TODO: deal with sRGB.
596 return pass;
599 bool
600 Test::run()
602 draw_test_image(&multisample_fbo);
603 draw_reference_image();
604 return measure_accuracy();
608 Test *
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)
613 Test *test = NULL;
614 switch (test_type) {
615 case TEST_TYPE_COLOR:
616 test = new Test(new Triangles(), NULL, false, 0, false);
617 break;
618 case TEST_TYPE_SRGB:
619 test = new Test(new Triangles(), NULL, false, 0, true);
620 break;
621 case TEST_TYPE_STENCIL_DRAW:
622 test = new Test(new StencilSunburst(),
623 new ManifestStencil(),
624 false, 0, false);
625 break;
626 case TEST_TYPE_STENCIL_RESOLVE:
627 test = new Test(new StencilSunburst(),
628 new ManifestStencil(),
629 true,
630 GL_STENCIL_BUFFER_BIT, false);
631 break;
632 case TEST_TYPE_DEPTH_DRAW:
633 test = new Test(new DepthSunburst(),
634 new ManifestDepth(),
635 false, 0, false);
636 break;
637 case TEST_TYPE_DEPTH_RESOLVE:
638 test = new Test(new DepthSunburst(),
639 new ManifestDepth(),
640 true,
641 GL_DEPTH_BUFFER_BIT, false);
642 break;
643 default:
644 printf("Unrecognized test type\n");
645 piglit_report_result(PIGLIT_FAIL);
646 break;
649 test->init(n_samples, small, combine_depth_stencil, pattern_width,
650 pattern_height, supersample_factor, filter_mode);
651 return test;