2 * Copyright (C) 2012 VMware, Inc.
3 * Copyright (C) 2010 Intel Corporation
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
26 * Eric Anholt <eric@anholt.net>
30 /** @file fbo-blit-stretch.c
32 * Tests EXT_framebuffer_blit with various combinations of window system and
33 * FBO objects. Because FBOs are generally stored inverted relative to
34 * window system frambuffers, this could catch flipping failures in blit paths.
41 #include "piglit-util-gl.h"
47 PIGLIT_GL_TEST_CONFIG_BEGIN
49 config
.supports_gl_compat_version
= 10;
51 config
.window_width
= DSTW
;
52 config
.window_height
= DSTH
;
53 config
.window_visual
= PIGLIT_GL_VISUAL_RGB
| PIGLIT_GL_VISUAL_DOUBLE
;
54 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
56 PIGLIT_GL_TEST_CONFIG_END
61 GLint srcX0
; GLint srcY0
; GLint srcX1
; GLint srcY1
;
62 GLint dstX0
; GLint dstY0
; GLint dstX1
; GLint dstY1
;
67 describe(const TestCase
&test
)
69 GLint dstW
= piglit_width
;
70 GLint dstH
= piglit_height
;
72 printf("%ix%i (%i, %i)-(%i, %i) => %ix%i (%i, %i)-(%i, %i)",
74 test
.srcX0
, test
.srcY0
, test
.srcX1
, test
.srcY1
,
76 test
.dstX0
, test
.dstY0
, test
.dstX1
, test
.dstY1
);
78 GLint srcDX
= test
.srcX1
- test
.srcX0
;
79 GLint srcDY
= test
.srcY1
- test
.srcY0
;
80 GLint dstDX
= test
.dstX1
- test
.dstX0
;
81 GLint dstDY
= test
.dstY1
- test
.dstY0
;
84 printf(" flip_src_x");
88 printf(" flip_src_y");
92 printf(" flip_dst_x");
96 printf(" flip_dst_y");
101 printf(" stretch_x");
106 printf(" stretch_y");
110 if (test
.srcX0
< 0 || test
.srcX0
> test
.srcW
||
111 test
.srcX1
< 0 || test
.srcX1
> test
.srcW
)
112 printf(" clamp_src_x");
113 if (test
.srcY0
< 0 || test
.srcY0
> test
.srcH
||
114 test
.srcY1
< 0 || test
.srcY1
> test
.srcH
)
115 printf(" clamp_src_y");
117 if (test
.dstX0
< 0 || test
.dstX0
> dstW
||
118 test
.dstX1
< 0 || test
.dstX1
> dstW
)
119 printf(" clamp_dst_x");
120 if (test
.dstY0
< 0 || test
.dstY0
> dstH
||
121 test
.dstY1
< 0 || test
.dstY1
> dstH
)
122 printf(" clamp_dst_y");
124 switch (test
.filter
) {
139 filter(const TestCase
&test
, float coord
, GLint
&coord0
, GLint
&coord1
, float &weight
)
141 switch (test
.filter
) {
143 coord0
= roundf(coord
);
145 assert(fabsf(coord0
- coord
) != 0.5f
);
149 coord0
= floorf(coord
);
150 weight
= coord
- (float)coord0
;
158 assert(weight
>= 0.0f
);
159 assert(weight
< 1.0f
);
165 clamp(GLint
&x
, GLint xmin
, GLint xmax
)
176 lerp(float x0
, float x1
, float w
)
178 return x0
+ (x1
- x0
) * w
;
182 lerp2d(float xy00
, float xy01
, float xy10
, float xy11
, float wx
, float wy
)
184 float y0
= lerp(xy00
, xy01
, wx
);
185 float y1
= lerp(xy10
, xy11
, wx
);
186 return lerp(y0
, y1
, wy
);
189 static float clearColor
[4] = {
194 verify(const TestCase
&test
, GLuint srcFBO
, GLuint dstFBO
, GLuint numChannels
)
196 GLint srcX0
= test
.srcX0
;
197 GLint srcY0
= test
.srcY0
;
198 GLint srcX1
= test
.srcX1
;
199 GLint srcY1
= test
.srcY1
;
200 GLint dstX0
= test
.dstX0
;
201 GLint dstY0
= test
.dstY0
;
202 GLint dstX1
= test
.dstX1
;
203 GLint dstY1
= test
.dstY1
;
206 std::swap(srcX0
, srcX1
);
207 std::swap(dstX0
, dstX1
);
210 std::swap(srcY0
, srcY1
);
211 std::swap(dstY0
, dstY1
);
214 GLint srcDX
= srcX1
- srcX0
;
215 GLint srcDY
= srcY1
- srcY0
;
216 GLint dstDX
= dstX1
- dstX0
;
217 GLint dstDY
= dstY1
- dstY0
;
219 GLint dstW
= piglit_width
;
220 GLint dstH
= piglit_height
;
222 float *srcPixels
= new float[test
.srcH
* test
.srcW
* numChannels
];
224 glBindFramebuffer(GL_READ_FRAMEBUFFER
, srcFBO
);
225 glReadPixels(0, 0, test
.srcW
, test
.srcH
, GL_RGB
, GL_FLOAT
, srcPixels
);
227 float *expectedDstPixels
= new float[dstH
* dstW
* numChannels
];
229 for (GLint dstY
= 0; dstY
< dstH
; ++dstY
) {
230 for (GLint dstX
= 0; dstX
< dstW
; ++dstX
) {
231 float *dstPixel
= expectedDstPixels
+ (dstY
* dstW
+ dstX
) * numChannels
;
232 for (GLuint c
= 0; c
< numChannels
; ++c
) {
233 dstPixel
[c
] = clearColor
[c
];
238 GLint dstX0clamped
= std::max(dstX0
, 0);
239 GLint dstY0clamped
= std::max(dstY0
, 0);
240 GLint dstX1clamped
= std::min(dstX1
, dstW
);
241 GLint dstY1clamped
= std::min(dstY1
, dstH
);
243 for (GLint dstY
= dstY0clamped
; dstY
< dstY1clamped
; ++dstY
) {
244 float srcY
= srcY0
+ (dstY
- dstY0
+ 0.5) * srcDY
/ dstDY
;
245 if (srcY
< 0 || srcY
>= test
.srcH
) {
251 GLint srcPixelY0
, srcPixelY1
;
253 filter(test
, srcY
, srcPixelY0
, srcPixelY1
, weightY
);
254 clamp(srcPixelY0
, 0, test
.srcH
- 1);
255 clamp(srcPixelY1
, 0, test
.srcH
- 1);
257 for (GLint dstX
= dstX0clamped
; dstX
< dstX1clamped
; ++dstX
) {
258 float srcX
= srcX0
+ (dstX
- dstX0
+ 0.5) * srcDX
/ dstDX
;
259 if (srcX
< 0 || srcX
>= test
.srcW
) {
265 GLint srcPixelX0
, srcPixelX1
;
267 filter(test
, srcX
, srcPixelX0
, srcPixelX1
, weightX
);
268 clamp(srcPixelX0
, 0, test
.srcW
- 1);
269 clamp(srcPixelX1
, 0, test
.srcW
- 1);
271 float *srcPixel00
= srcPixels
+ (srcPixelY0
* test
.srcW
+ srcPixelX0
) * numChannels
;
272 float *srcPixel01
= srcPixels
+ (srcPixelY0
* test
.srcW
+ srcPixelX1
) * numChannels
;
273 float *srcPixel10
= srcPixels
+ (srcPixelY1
* test
.srcW
+ srcPixelX0
) * numChannels
;
274 float *srcPixel11
= srcPixels
+ (srcPixelY1
* test
.srcW
+ srcPixelX1
) * numChannels
;
276 float *dstPixel
= expectedDstPixels
277 + (dstY
* dstW
+ dstX
) * numChannels
;
279 for (GLuint c
= 0; c
< numChannels
; ++c
) {
280 dstPixel
[c
] = lerp2d(srcPixel00
[c
],
291 float *observedDstPixels
= new float[dstH
* dstW
* numChannels
];
292 glBindFramebuffer(GL_READ_FRAMEBUFFER
, dstFBO
);
293 glReadPixels(0, 0, dstW
, dstH
, GL_RGB
, GL_FLOAT
, observedDstPixels
);
296 pass
= piglit_compare_images_color(0, 0, dstW
, dstH
, numChannels
,
301 delete [] observedDstPixels
;
302 delete [] expectedDstPixels
;
308 blit(const TestCase
&test
)
310 glClearColor(clearColor
[0], clearColor
[1], clearColor
[2], clearColor
[3]);
311 glClear(GL_COLOR_BUFFER_BIT
);
312 glBlitFramebuffer(test
.srcX0
, test
.srcY0
, test
.srcX1
, test
.srcY1
,
313 test
.dstX0
, test
.dstY0
, test
.dstX1
, test
.dstY1
,
314 GL_COLOR_BUFFER_BIT
, test
.filter
);
319 run_test(const TestCase
&test
)
329 glGenFramebuffers(1, &fbo
);
330 glBindFramebuffer(GL_FRAMEBUFFER
, fbo
);
332 glGenRenderbuffers(1, &rbo
);
333 glBindRenderbuffer(GL_RENDERBUFFER
, rbo
);
334 glRenderbufferStorage(GL_RENDERBUFFER
, GL_RGBA
, test
.srcW
, test
.srcH
);
335 glBindRenderbuffer(GL_RENDERBUFFER
, 0);
337 glFramebufferRenderbuffer(GL_FRAMEBUFFER
,
338 GL_COLOR_ATTACHMENT0
,
341 if (!piglit_check_gl_error(GL_NO_ERROR
))
342 piglit_report_result(PIGLIT_FAIL
);
344 status
= glCheckFramebufferStatus(GL_FRAMEBUFFER
);
345 if (status
!= GL_FRAMEBUFFER_COMPLETE
) {
348 GLubyte
*image
= piglit_rgbw_image_ubyte(test
.srcW
, test
.srcH
,
350 glDrawPixels(test
.srcW
, test
.srcH
, GL_RGBA
, GL_UNSIGNED_BYTE
,
354 glViewport(0, 0, piglit_width
, piglit_height
);
355 piglit_ortho_projection(piglit_width
, piglit_height
, GL_FALSE
);
357 glBindFramebuffer(GL_READ_FRAMEBUFFER
, fbo
);
358 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, piglit_winsys_fbo
);
362 pass
= verify(test
, fbo
, 0, 3);
364 if (!piglit_automatic
) {
365 piglit_present_results();
372 glBindFramebuffer(GL_FRAMEBUFFER
, piglit_winsys_fbo
);
373 glDeleteFramebuffers(1, &fbo
);
374 glDeleteRenderbuffers(1, &rbo
);
380 * Constants to help define several test cases.
389 #define SRCXMAX (SRCXMIN + DX)
390 #define SRCYMAX (SRCYMIN + DY)
394 #define DSTXMAX (DSTXMIN + DX)
395 #define DSTYMAX (DSTYMIN + DY)
405 SRCXMIN
, SRCYMIN
, SRCXMAX
, SRCYMAX
,
406 DSTXMIN
, DSTYMIN
, DSTXMAX
, DSTYMAX
,
416 SRCXMAX
, SRCYMAX
, SRCXMIN
, SRCYMIN
, // flip xy
417 DSTXMAX
, DSTYMAX
, DSTXMIN
, DSTYMIN
, // flip xy
422 SRCXMAX
, SRCYMIN
, SRCXMIN
, SRCYMAX
, // fliped x
423 DSTXMIN
, DSTYMAX
, DSTXMAX
, DSTYMIN
, // fliped y
428 SRCXMIN
, SRCYMAX
, SRCXMAX
, SRCYMIN
, // fliped y
429 DSTXMAX
, DSTYMIN
, DSTXMIN
, DSTYMAX
, // fliped x
439 SRCXMIN
, SRCYMIN
, SRCXMAX
, SRCYMAX
,
440 DSTXMIN
, DSTYMIN
, DSTXMAX
+ 3*DX
, DSTYMAX
+ 3*DY
, // stretch x y
445 SRCXMIN
, SRCYMIN
, SRCXMAX
, SRCYMAX
,
446 DSTXMIN
, DSTYMIN
, DSTXMAX
+ 3*DX
, DSTYMAX
+ 3*DY
, // stretch x y
451 * Stretch of a single pixel.
456 SRCXMIN
, SRCYMIN
, SRCXMIN
+ 1, SRCYMIN
+ 1,
457 DSTXMIN
, DSTYMIN
, DSTXMIN
+ 7, DSTYMIN
+ 7, // stretch x y
468 SRCXMIN
, SRCYMIN
, SRCXMAX
, SRCYMAX
,
469 -DX
/2, -DY
/2, -DX
/2 + DX
, -DY
/2 + DY
, // clip dst left bottom
474 SRCXMIN
, SRCYMIN
, SRCXMAX
, SRCYMAX
,
475 DSTW
- DX
/2, DSTH
- DY
/2, DSTW
- DX
/2 + DX
, DSTH
- DY
/2 + DY
, // clip dst top right
480 -DX
/2, -DY
/2, -DX
/2 + DX
, -DY
/2 + DY
, // clip src left bottom
481 DSTXMIN
, DSTYMIN
, DSTXMAX
, DSTYMAX
,
486 SRCW
- DX
/2, SRCH
- DY
/2, SRCW
- DX
/2 + DX
, SRCH
- DY
/2 + DY
, // clip src top right
487 DSTXMIN
, DSTYMIN
, DSTXMAX
, DSTYMAX
,
494 * XXX: These tests are disabled for now, because Mesa clips in integer
495 * coordinates, instead of floats, which ends up affecting how the
496 * whole surface is interpolated, which goes against the spec.
501 SRCXMIN
, SRCYMIN
, SRCXMAX
, SRCYMAX
,
502 -DSTXMIN
, -DSTYMIN
, DSTXMAX
, DSTYMAX
, // clip dst left bottom
507 SRCXMIN
, SRCYMIN
, SRCXMAX
, SRCYMAX
,
508 DSTXMIN
, DSTYMIN
, DSTW
+ DSTXMIN
, DSTH
+ DSTYMIN
, // clip dst top right
513 -SRCXMIN
, -SRCYMIN
, SRCXMAX
, SRCYMAX
, // clip src left bottom
514 DSTXMIN
, DSTYMIN
, DSTXMAX
, DSTYMAX
,
519 SRCXMIN
, SRCYMIN
, SRCW
+ SRCXMIN
, SRCH
+ SRCYMIN
, // clip src top right
520 DSTXMIN
, DSTYMIN
, DSTXMAX
, DSTYMAX
,
525 SRCXMAX
, SRCYMIN
, SRCXMIN
, SRCYMAX
, // fliped x
526 -DSTXMIN
, DSTH
+ DSTYMIN
, DSTW
+ DSTXMIN
, -DSTYMIN
, // fliped y, cliped x y
543 static int test_index
= -1;
548 GLboolean pass
= GL_TRUE
;
549 for (unsigned i
= 0; i
< ARRAY_SIZE(tests
); i
++) {
550 if (test_index
!= -1 &&
551 test_index
!= (int) i
)
554 TestCase test
= tests
[i
];
556 test
.filter
= GL_NEAREST
;
557 pass
= run_test(test
) && pass
;
559 test
.filter
= GL_LINEAR
;
560 pass
= run_test(test
) && pass
;
562 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
567 piglit_init(int argc
, char **argv
)
569 piglit_ortho_projection(piglit_width
, piglit_height
, GL_FALSE
);
571 piglit_require_extension("GL_ARB_framebuffer_object");
574 sscanf(argv
[1], "%d", &test_index
);