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 clip-and-scissor-blit.cpp
27 * Verify the accuracy of blits incolving MSAA buffers when the blit
28 * coordinates are clipped to the edges of the source or destination
29 * surface, or scissored.
31 * The test starts by creating a source framebuffer and populating it
32 * with a simple image. It also creates a destination framebuffer.
34 * Then, it executes the following sequence of steps several times in
37 * 1. Clear the destination framebuffer to gray.
39 * 2. Blit from the source framebuffer to the destination framebuffer,
40 * using clipping or scissoring to limit the amount of data that is
43 * 3. Do a simple (unclipped, unscissored) blit from the destination
44 * framebuffer to the screen. This produces a test image.
46 * 4. Clear the destination framebuffer to gray.
48 * 5. Blit from the source framebuffer to the destination framebuffer,
49 * this time adjusting the coordinates to limit the amount of data
52 * 6. Do a simple (unclipped, unscissored) blit from the destination
53 * framebuffer to the screen. This produces a reference image.
55 * 7. Verify that the test and reference images match.
57 #include "piglit-fbo.h"
58 using namespace piglit_util_fbo
;
60 PIGLIT_GL_TEST_CONFIG_BEGIN
62 config
.supports_gl_compat_version
= 10;
64 config
.window_width
= 600;
65 config
.window_height
= 320;
66 config
.window_visual
= PIGLIT_GL_VISUAL_DOUBLE
| PIGLIT_GL_VISUAL_RGBA
;
67 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
69 PIGLIT_GL_TEST_CONFIG_END
73 const int src_size
[2] = { 30, 20 };
74 const int dst_size
[2] = { 50, 40 };
75 const int cut_amount
[2] = { 10, 7 };
89 * From the GL 3.3 spec (section 4.3.2 Copying Pixels):
91 * If SAMPLE_BUFFERS for either the read framebuffer or draw
92 * framebuffer is greater than zero, no copy is performed and an
93 * INVALID_OPERATION error is generated if the dimensions of the
94 * source and destination rectangles provided to BlitFramebuffer are
95 * not identical, if the formats of the read and draw framebuffers are
96 * not identical, or if the values of SAMPLES for the read and draw
97 * buffers are not identical.
99 * It is not 100% clear whether "the dimensions of the source and
100 * destination rectangles" are meant in a signed sense or an unsigned
101 * sense--in other words, if SAMPLE_BUFFERS is greater than zero for
102 * either the read or draw framebuffer, and abs(srcX0 - srcX1) ==
103 * abs(dstX0 - dstX1), but (srcX0 - srcX1) and (dstX0 - dstX1) have
104 * opposite signs (so that the image is being mirrored in the X
105 * direction), should an INVALID_OPERATION error be generated?
107 * Some implementations have interpreted the answer to be yes, so we
108 * only test clipping of mirrored blits when SAMPLE_BUFFERS is 0 for
109 * both the read and draw framebuffers.
111 * This boolean is true if we should test clipping of mirrored blits.
113 bool test_mirrored_blits
= false;
116 draw_simple_src_image()
118 glColor4f(1.0, 0.0, 0.0, 0.0);
119 piglit_draw_rect(-1, -1, 1, 1);
121 glColor4f(0.0, 1.0, 0.0, 0.25);
122 piglit_draw_rect(0, -1, 1, 1);
124 glColor4f(0.0, 0.0, 1.0, 0.5);
125 piglit_draw_rect(-1, 0, 1, 1);
127 glColor4f(1.0, 1.0, 1.0, 1.0);
128 piglit_draw_rect(0, 0, 1, 1);
132 do_test(int coord
, bool clip_low
, test_type_enum test_type
,
133 bool flip_src
, bool flip_dst
)
135 /* If this test flips src but not dst (or vice versa), then it
136 * is unclear from the spec whether it should be allowed for
137 * multisampled blits, so skip it unless test_mirrored_blits
140 if (flip_src
!= flip_dst
&& !test_mirrored_blits
)
143 /* Figure out where to draw the images */
144 int display_x
= (6 * coord
+ 2 * test_type
) * dst_size
[0];
145 int display_y
= ((clip_low
? 4 : 0) + (flip_src
? 2 : 0) +
146 (flip_dst
? 1 : 0)) * dst_size
[1];
148 static const char * const test_type_strings
[] = {
153 printf("Testing %s %s%s%s%s at (%d, %d)\n",
154 test_type_strings
[test_type
],
155 clip_low
? "-" : "+",
157 flip_src
? " (flip src)" : "",
158 flip_dst
? " (flip dst)" : "",
159 display_x
, display_y
);
161 /* Number of pixels we'll try to cut out of the blit by
162 * clipping or scissoring.
164 int cut
= cut_amount
[coord
];
166 /* Amount by which the blits must be offset to produce an
167 * image in the center of the destination fbo.
169 int dx
= (dst_size
[0] - src_size
[0]) / 2;
170 int dy
= (dst_size
[1] - src_size
[1]) / 2;
172 /* Set up blit and scissor parameters for both the test and
175 int test_src
[2][2] = { /* E.g. test_src[1][0] == srcY0 */
176 { 0, src_size
[0] }, { 0, src_size
[1] } };
177 int test_dst
[2][2] = { /* E.g. test_dst[1][0] == dstY0 */
178 { dx
, src_size
[0] + dx
}, { dy
, src_size
[1] + dy
} };
179 int ref_src
[2][2] = { /* E.g. test_src[1][0] == srcY0 */
180 { 0, src_size
[0] }, { 0, src_size
[1] } };
181 int ref_dst
[2][2] = { /* E.g. test_dst[1][0] == dstY0 */
182 { dx
, src_size
[0] + dx
}, { dy
, src_size
[1] + dy
} };
183 int scissor
[2][2] = { /* E.g. scissor[0] = { left, right } */
184 { 0, 0 }, { 0, 0 } };
188 test_src
[coord
][0] += cut
;
189 test_src
[coord
][1] += cut
;
190 ref_src
[coord
][0] += cut
;
191 ref_dst
[coord
][1] -= cut
;
193 test_src
[coord
][0] -= cut
;
194 test_src
[coord
][1] -= cut
;
195 ref_src
[coord
][1] -= cut
;
196 ref_dst
[coord
][0] += cut
;
201 test_dst
[coord
][0] = -cut
;
203 test_dst
[coord
][0] + src_size
[coord
];
204 ref_src
[coord
][0] = cut
;
205 ref_dst
[coord
][0] = 0;
206 ref_dst
[coord
][1] = test_dst
[coord
][1];
208 test_dst
[coord
][1] = dst_size
[coord
] + cut
;
210 test_dst
[coord
][1] - src_size
[coord
];
211 ref_src
[coord
][1] = src_size
[coord
] - cut
;
212 ref_dst
[coord
][0] = test_dst
[coord
][0];
213 ref_dst
[coord
][1] = dst_size
[coord
];
216 case TEST_TYPE_SCISSOR
:
218 scissor
[coord
][0] = test_dst
[coord
][0] + cut
;
219 scissor
[coord
][1] = dst_size
[coord
];
220 ref_src
[coord
][0] += cut
;
221 ref_dst
[coord
][0] += cut
;
223 scissor
[coord
][0] = 0;
224 scissor
[coord
][1] = test_dst
[coord
][1] - cut
;
225 ref_src
[coord
][1] -= cut
;
226 ref_dst
[coord
][1] -= cut
;
228 scissor
[1-coord
][0] = 0;
229 scissor
[1-coord
][1] = dst_size
[1-coord
];
232 printf("Unexpected test type\n");
233 piglit_report_result(PIGLIT_FAIL
);
237 /* Flip coordinates if requested */
239 test_src
[coord
][0] = src_size
[coord
] - test_src
[coord
][0];
240 test_src
[coord
][1] = src_size
[coord
] - test_src
[coord
][1];
241 ref_src
[coord
][0] = src_size
[coord
] - ref_src
[coord
][0];
242 ref_src
[coord
][1] = src_size
[coord
] - ref_src
[coord
][1];
245 test_dst
[coord
][0] = dst_size
[coord
] - test_dst
[coord
][0];
246 test_dst
[coord
][1] = dst_size
[coord
] - test_dst
[coord
][1];
247 ref_dst
[coord
][0] = dst_size
[coord
] - ref_dst
[coord
][0];
248 ref_dst
[coord
][1] = dst_size
[coord
] - ref_dst
[coord
][1];
249 int tmp
= scissor
[coord
][0];
250 scissor
[coord
][0] = dst_size
[coord
] - scissor
[coord
][1];
251 scissor
[coord
][1] = dst_size
[coord
] - tmp
;
254 /* Clear the destination framebuffer to gray */
255 glBindFramebuffer(GL_READ_FRAMEBUFFER
, src_fbo
.handle
);
256 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, dst_fbo
.handle
);
257 glClearColor(0.5, 0.5, 0.5, 0.5);
258 glClear(GL_COLOR_BUFFER_BIT
);
261 glScissor(scissor
[0][0],
263 scissor
[0][1] - scissor
[0][0],
264 scissor
[1][1] - scissor
[1][0]);
265 if (test_type
== TEST_TYPE_SCISSOR
)
266 glEnable(GL_SCISSOR_TEST
);
268 glDisable(GL_SCISSOR_TEST
);
270 /* Do the test blit */
271 glBlitFramebuffer(test_src
[0][0], test_src
[1][0],
272 test_src
[0][1], test_src
[1][1],
273 test_dst
[0][0], test_dst
[1][0],
274 test_dst
[0][1], test_dst
[1][1],
275 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
277 /* Disable scissoring */
278 glDisable(GL_SCISSOR_TEST
);
280 /* Transfer the test image to the screen */
281 glBindFramebuffer(GL_READ_FRAMEBUFFER
, dst_fbo
.handle
);
282 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, piglit_winsys_fbo
);
283 glBlitFramebuffer(0, 0, dst_size
[0], dst_size
[1],
284 display_x
, display_y
,
285 display_x
+ dst_size
[0], display_y
+ dst_size
[1],
286 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
288 /* Clear the destination framebuffer to gray */
289 glBindFramebuffer(GL_READ_FRAMEBUFFER
, src_fbo
.handle
);
290 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, dst_fbo
.handle
);
291 glClearColor(0.5, 0.5, 0.5, 0.5);
292 glClear(GL_COLOR_BUFFER_BIT
);
294 /* Do the reference blit */
295 glBlitFramebuffer(ref_src
[0][0], ref_src
[1][0],
296 ref_src
[0][1], ref_src
[1][1],
297 ref_dst
[0][0], ref_dst
[1][0],
298 ref_dst
[0][1], ref_dst
[1][1],
299 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
301 /* Transfer the reference image to the screen */
302 glBindFramebuffer(GL_READ_FRAMEBUFFER
, dst_fbo
.handle
);
303 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, piglit_winsys_fbo
);
304 glBlitFramebuffer(0, 0, dst_size
[0], dst_size
[1],
305 display_x
+ dst_size
[0], display_y
,
306 display_x
+ 2 * dst_size
[0], display_y
+ dst_size
[1],
307 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
309 /* Compare the test and reference images */
310 glBindFramebuffer(GL_READ_FRAMEBUFFER
, piglit_winsys_fbo
);
311 return piglit_probe_rect_halves_equal_rgba(display_x
, display_y
,
317 print_usage_and_exit(char *prog_name
)
319 printf("Usage: %s <num_samples> <blit_type>\n"
320 " where <blit_type> is one of:\n"
326 piglit_report_result(PIGLIT_FAIL
);
330 piglit_init(int argc
, char **argv
)
332 piglit_require_gl_version(21);
333 piglit_require_extension("GL_ARB_framebuffer_object");
334 piglit_require_extension("GL_ARB_vertex_array_object");
337 print_usage_and_exit(argv
[0]);
342 num_samples
= strtol(argv
[1], &endptr
, 0);
343 if (endptr
!= argv
[1] + strlen(argv
[1]))
344 print_usage_and_exit(argv
[0]);
347 /* Skip the test if num_samples > GL_MAX_SAMPLES */
349 glGetIntegerv(GL_MAX_SAMPLES
, &max_samples
);
350 if (num_samples
> max_samples
)
351 piglit_report_result(PIGLIT_SKIP
);
355 if (strcmp(argv
[2], "msaa") == 0) {
356 src_samples
= dst_samples
= num_samples
;
357 } else if (strcmp(argv
[2], "upsample") == 0) {
359 dst_samples
= num_samples
;
360 } else if (strcmp(argv
[2], "downsample") == 0) {
361 src_samples
= num_samples
;
363 } else if (strcmp(argv
[2], "normal") == 0) {
364 src_samples
= dst_samples
= 0;
365 test_mirrored_blits
= true;
367 print_usage_and_exit(argv
[0]);
370 src_fbo
.setup(FboConfig(src_samples
, src_size
[0], src_size
[1]));
371 dst_fbo
.setup(FboConfig(dst_samples
, dst_size
[0], dst_size
[1]));
374 extern "C" enum piglit_result
377 /* Draw a simple image in the source buffer */
378 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, src_fbo
.handle
);
379 src_fbo
.set_viewport();
380 draw_simple_src_image();
383 for (int coord
= 0; coord
< 2; ++coord
) {
384 for (int clip_low
= 0; clip_low
< 2; ++clip_low
) {
385 for (int test_type
= 0; test_type
< NUM_TEST_TYPES
; ++test_type
) {
386 for (int flip_src
= 0; flip_src
< 2; ++flip_src
) {
387 for (int flip_dst
= 0; flip_dst
< 2; ++flip_dst
) {
388 pass
= do_test(coord
, clip_low
, test_type_enum(test_type
),
389 flip_src
, flip_dst
) && pass
;
396 piglit_present_results();
398 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
401 } /* anonymous namespace */