ext_gpu_shader4: add compiler tests for everything
[piglit.git] / tests / spec / ext_framebuffer_multisample / common.cpp
bloba9f332af7ef8b05c7c5e4170122b924d93926f13
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 void
272 Test::init(int num_samples, bool small, bool combine_depth_stencil,
273 int pattern_width, int pattern_height, int supersample_factor,
274 GLenum filter_mode)
276 this->num_samples = num_samples;
277 this->pattern_width = pattern_width;
278 this->pattern_height = pattern_height;
279 this->supersample_factor = supersample_factor;
280 this->filter_mode = filter_mode;
282 FboConfig test_fbo_config(0,
283 small ? 16 : pattern_width,
284 small ? 16 : pattern_height);
285 if (srgb)
286 test_fbo_config.color_internalformat = GL_SRGB8_ALPHA8;
287 test_fbo_config.combine_depth_stencil = combine_depth_stencil;
288 test_fbo.setup(test_fbo_config);
290 FboConfig multisample_fbo_config = test_fbo_config;
291 multisample_fbo_config.num_samples = num_samples;
292 multisample_fbo.setup(multisample_fbo_config);
294 resolve_fbo.setup(test_fbo_config);
296 FboConfig supersample_fbo_config = test_fbo_config;
297 supersample_fbo_config.width = 1024;
298 supersample_fbo_config.height = 1024;
299 supersample_fbo_config.num_tex_attachments = 1;
300 supersample_fbo_config.num_rb_attachments = 0;
301 supersample_fbo.setup(supersample_fbo_config);
303 FboConfig downsample_fbo_config = test_fbo_config;
304 downsample_fbo_config.width = 1024 / supersample_factor;
305 downsample_fbo_config.height = 1024 / supersample_factor;
306 downsample_fbo.setup(downsample_fbo_config);
308 pattern->compile();
309 downsample_prog.compile(supersample_factor);
310 if (manifest_program)
311 manifest_program->compile();
313 /* Only do depth testing in those parts of the test where we
314 * explicitly want it
316 glDisable(GL_DEPTH_TEST);
320 * Blit the data from multisample_fbo to resolve_fbo, forcing the
321 * implementation to do an MSAA resolve.
323 void
324 Test::resolve(Fbo *fbo, GLbitfield which_buffers)
326 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo->handle);
327 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo.handle);
328 resolve_fbo.set_viewport();
330 if (srgb)
331 glEnable(GL_FRAMEBUFFER_SRGB);
332 glBlitFramebuffer(0, 0, fbo->config.width, fbo->config.height,
333 0, 0, resolve_fbo.config.width,
334 resolve_fbo.config.height,
335 which_buffers, filter_mode);
336 glDisable(GL_FRAMEBUFFER_SRGB);
340 * Use downsample_prog to blend 16x16 blocks of samples in
341 * supersample_fbo, to produce a reference image in downsample_fbo.
343 void
344 Test::downsample_color(int downsampled_width, int downsampled_height)
347 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, downsample_fbo.handle);
348 downsample_fbo.set_viewport();
349 downsample_prog.run(&supersample_fbo,
350 downsample_fbo.config.width,
351 downsample_fbo.config.height, srgb);
355 * Blit the color data from src_fbo to the given location in the
356 * windowsystem buffer, so that the user can see it and we can read it
357 * using glReadPixels.
359 void
360 Test::show(Fbo *src_fbo, int x_offset, int y_offset)
362 glBindFramebuffer(GL_READ_FRAMEBUFFER, src_fbo->handle);
363 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, piglit_winsys_fbo);
364 glViewport(0, 0, piglit_width, piglit_height);
365 glBlitFramebuffer(0, 0, src_fbo->config.width, src_fbo->config.height,
366 x_offset, y_offset,
367 x_offset + src_fbo->config.width,
368 y_offset + src_fbo->config.height,
369 GL_COLOR_BUFFER_BIT, GL_NEAREST);
373 * Draw a portion of the test pattern by setting up an appropriate
374 * projection matrix to map that portion of the test pattern to the
375 * full FBO.
377 void
378 Test::draw_pattern(int x_offset, int y_offset, int width, int height)
380 /* Need a projection matrix such that:
381 * xc = ((xe + 1) * pattern_width/2 - x_offset) * 2/width - 1
382 * yc = ((ye + 1) * pattern_height/2 - y_offset) * 2/height - 1
383 * zc = ze
384 * wc = we = 1.0
386 * Therefore
387 * xc = pattern_width / width * xe
388 * + pattern_width / width - x_offset * 2 / width - 1
389 * yc = pattern_height / height * ye
390 * + pattern_height / height - y_offset * 2 / height - 1
391 * zc = ze
392 * wc = we = 1.0
394 float x_scale = float(pattern_width) / width;
395 float x_delta = x_scale - x_offset * 2.0 / width - 1.0;
396 float y_scale = float(pattern_height) / height;
397 float y_delta = y_scale - y_offset * 2.0 / height - 1.0;
398 float proj[4][4] = {
399 { x_scale, 0, 0, x_delta },
400 { 0, y_scale, 0, y_delta },
401 { 0, 0, 1, 0 },
402 { 0, 0, 0, 1 }
405 pattern->draw(proj);
409 * Draw the entire test image, rendering it a piece at a time if
410 * multisample_fbo is very small.
412 void
413 Test::draw_test_image(Fbo *fbo)
415 int num_h_tiles = pattern_width / fbo->config.width;
416 int num_v_tiles = pattern_height / fbo->config.height;
417 for (int h = 0; h < num_h_tiles; ++h) {
418 for (int v = 0; v < num_v_tiles; ++v) {
419 glBindFramebuffer(GL_DRAW_FRAMEBUFFER,
420 fbo->handle);
421 fbo->set_viewport();
422 int x_offset = h * fbo->config.width;
423 int y_offset = v * fbo->config.height;
424 draw_pattern(x_offset, y_offset,
425 fbo->config.width,
426 fbo->config.height);
427 if (test_resolve) {
428 resolve(fbo, blit_type);
429 if (manifest_program)
430 manifest_program->run();
431 } else {
432 if (manifest_program)
433 manifest_program->run();
434 resolve(fbo,
435 GL_COLOR_BUFFER_BIT);
438 show(&resolve_fbo, x_offset, y_offset);
444 * Draw the test image to the default framebuffer
446 void
447 Test::draw_to_default_framebuffer()
449 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, piglit_winsys_fbo);
450 glViewport(0, 0, pattern_width, pattern_height);
451 draw_pattern(0, 0, pattern_width, pattern_height);
455 * Draw the entire test image, rendering it a piece at a time.
457 void
458 Test::draw_reference_image()
460 int downsampled_width =
461 supersample_fbo.config.width / supersample_factor;
462 int downsampled_height =
463 supersample_fbo.config.height / supersample_factor;
464 int num_h_tiles = pattern_width / downsampled_width;
465 int num_v_tiles = pattern_height / downsampled_height;
466 for (int h = 0; h < num_h_tiles; ++h) {
467 for (int v = 0; v < num_v_tiles; ++v) {
468 glBindFramebuffer(GL_DRAW_FRAMEBUFFER,
469 supersample_fbo.handle);
470 supersample_fbo.set_viewport();
471 int x_offset = h * downsampled_width;
472 int y_offset = v * downsampled_height;
473 draw_pattern(x_offset, y_offset,
474 downsampled_width, downsampled_height);
476 if (manifest_program)
477 manifest_program->run();
479 downsample_color(downsampled_width, downsampled_height);
480 show(&downsample_fbo,
481 pattern_width + x_offset, y_offset);
487 * Measure the accuracy of MSAA downsampling. Pixels that are fully
488 * on or off in the reference image are required to be fully on or off
489 * in the test image. Pixels that are not fully on or off in the
490 * reference image may be at any grayscale level; we mesaure the RMS
491 * error between the reference image and the test image.
493 bool
494 Test::measure_accuracy()
496 bool pass = true;
498 glBindFramebuffer(GL_READ_FRAMEBUFFER, piglit_winsys_fbo);
499 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, piglit_winsys_fbo);
500 glViewport(0, 0, piglit_width, piglit_height);
502 float *reference_data = new float[pattern_width * pattern_height * 4];
503 glReadPixels(pattern_width, 0, pattern_width, pattern_height, GL_RGBA,
504 GL_FLOAT, reference_data);
506 float *test_data = new float[pattern_width * pattern_height * 4];
507 glReadPixels(0, 0, pattern_width, pattern_height, GL_RGBA,
508 GL_FLOAT, test_data);
510 Stats unlit_stats;
511 Stats partially_lit_stats;
512 Stats totally_lit_stats;
513 for (int y = 0; y < pattern_height; ++y) {
514 for (int x = 0; x < pattern_width; ++x) {
515 for (int c = 0; c < 4; ++c) {
516 int pixel_pos = 4*(y*pattern_width + x) + c;
517 float ref = reference_data[pixel_pos];
518 float test = test_data[pixel_pos];
519 /* When testing sRGB, compare pixels
520 * linearly so that the measured error
521 * is comparable to the non-sRGB case.
523 if (srgb && c < 3) {
524 ref = piglit_srgb_to_linear(ref);
525 test = piglit_srgb_to_linear(test);
527 if (ref <= 0.0)
528 unlit_stats.record(test - ref);
529 else if (ref >= 1.0)
530 totally_lit_stats.record(test - ref);
531 else
532 partially_lit_stats.record(test - ref);
537 double error_threshold;
538 if (test_resolve) {
539 /* For depth and stencil resolves, the implementation
540 * typically just picks one of the N multisamples, so
541 * we have to allow for a generous amount of error.
543 error_threshold = 0.4;
544 } else {
545 /* Empirically, the RMS error for no oversampling is
546 * about 0.25, and each additional factor of 2
547 * overampling reduces the error by a factor of about
548 * 0.6. Leaving some room for variation, we'll set
549 * the error threshold to 0.333 * 0.62 ^
550 * log2(num_samples).
552 int effective_num_samples = num_samples == 0 ? 1 : num_samples;
553 error_threshold = 0.333 *
554 pow(0.62, ffs(effective_num_samples) - 1);
557 /* The unlit and totally_lit stats are supposed to count the
558 * pixels where either a primitive completely covers the pixel
559 * or no primitive touches it at all. However this is
560 * effectively only determined by checking whether any
561 * primitive has intersected one of the supersample positions
562 * of the reference image. It's completely possible for a
563 * primitive to intersect the pixel boundary but completely
564 * miss any of the supersample positions. The GL
565 * implementation is free to pick whatever multisample
566 * positions it wants within the pixel boundary so it's also
567 * possible for a primitive to intersect a multisample
568 * position but miss all of the supersample positions of the
569 * reference image. To cope with this we allow a small margin
570 * of error for the pixels that are either fully lit or fully
571 * unlit.
573 double full_pixel_threshold = error_threshold * 0.05f;
575 printf("Pixels that should be unlit\n");
576 unlit_stats.summarize();
577 pass = unlit_stats.is_better_than(full_pixel_threshold) && pass;
578 printf("Pixels that should be totally lit\n");
579 totally_lit_stats.summarize();
580 pass = totally_lit_stats.is_better_than(full_pixel_threshold) && pass;
581 printf("The error threshold for unlit and totally lit "
582 "pixels test is %f\n",
583 full_pixel_threshold);
584 printf("Pixels that should be partially lit\n");
585 partially_lit_stats.summarize();
587 printf("The error threshold for partially lit pixels is %f\n",
588 error_threshold);
589 pass = partially_lit_stats.is_better_than(error_threshold) && pass;
590 // TODO: deal with sRGB.
591 return pass;
594 bool
595 Test::run()
597 draw_test_image(&multisample_fbo);
598 draw_reference_image();
599 return measure_accuracy();
603 Test *
604 create_test(test_type_enum test_type, int n_samples, bool small,
605 bool combine_depth_stencil, int pattern_width, int pattern_height,
606 int supersample_factor, GLenum filter_mode)
608 Test *test = NULL;
609 switch (test_type) {
610 case TEST_TYPE_COLOR:
611 test = new Test(new Triangles(), NULL, false, 0, false);
612 break;
613 case TEST_TYPE_SRGB:
614 test = new Test(new Triangles(), NULL, false, 0, true);
615 break;
616 case TEST_TYPE_STENCIL_DRAW:
617 test = new Test(new StencilSunburst(),
618 new ManifestStencil(),
619 false, 0, false);
620 break;
621 case TEST_TYPE_STENCIL_RESOLVE:
622 test = new Test(new StencilSunburst(),
623 new ManifestStencil(),
624 true,
625 GL_STENCIL_BUFFER_BIT, false);
626 break;
627 case TEST_TYPE_DEPTH_DRAW:
628 test = new Test(new DepthSunburst(),
629 new ManifestDepth(),
630 false, 0, false);
631 break;
632 case TEST_TYPE_DEPTH_RESOLVE:
633 test = new Test(new DepthSunburst(),
634 new ManifestDepth(),
635 true,
636 GL_DEPTH_BUFFER_BIT, false);
637 break;
638 default:
639 printf("Unrecognized test type\n");
640 piglit_report_result(PIGLIT_FAIL);
641 break;
644 test->init(n_samples, small, combine_depth_stencil, pattern_width,
645 pattern_height, supersample_factor, filter_mode);
646 return test;