arb_copy_image: test copying of different mipmap levels of a texture
[piglit.git] / tests / fbo / fbo-blit-stretch.cpp
bloba83288c0fafb72e5f0fd07105ca9b5744b0a1aa4
1 /*
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
14 * Software.
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
22 * IN THE SOFTWARE.
24 * Authors:
25 * Jose Fonseca
26 * Eric Anholt <eric@anholt.net>
27 * Brian Paul
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.
36 * See also fbo-blit.c
39 #include <algorithm>
41 #include "piglit-util-gl.h"
44 #define DSTW 200
45 #define DSTH 150
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
58 struct TestCase
60 GLint srcW, srcH;
61 GLint srcX0; GLint srcY0; GLint srcX1; GLint srcY1;
62 GLint dstX0; GLint dstY0; GLint dstX1; GLint dstY1;
63 GLenum filter;
66 static void
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)",
73 test.srcW, test.srcH,
74 test.srcX0, test.srcY0, test.srcX1, test.srcY1,
75 dstW, dstH,
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;
83 if (srcDX < 0) {
84 printf(" flip_src_x");
85 srcDX = -srcDX;
87 if (srcDY < 0) {
88 printf(" flip_src_y");
89 srcDY = -srcDY;
91 if (dstDX < 0) {
92 printf(" flip_dst_x");
93 dstDX = -dstDX;
95 if (dstDY < 0) {
96 printf(" flip_dst_y");
97 dstDY = -dstDY;
100 if (dstDX > srcDX)
101 printf(" stretch_x");
102 if (dstDX < srcDX)
103 printf(" shrink_x");
105 if (dstDY > srcDY)
106 printf(" stretch_y");
107 if (dstDY < srcDY)
108 printf(" shrink_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) {
125 case GL_NEAREST:
126 printf(" nearest");
127 break;
128 case GL_LINEAR:
129 printf(" linear");
130 break;
131 default:
132 assert(0);
135 printf("\n");
138 static void
139 filter(const TestCase &test, float coord, GLint &coord0, GLint &coord1, float &weight)
141 switch (test.filter) {
142 case GL_NEAREST:
143 coord0 = roundf(coord);
144 // ambiguous
145 assert(fabsf(coord0 - coord) != 0.5f);
146 weight = 0.0f;
147 break;
148 case GL_LINEAR:
149 coord0 = floorf(coord);
150 weight = coord - (float)coord0;
151 break;
152 default:
153 assert(0);
154 coord0 = 0;
155 weight = 0.0f;
158 assert(weight >= 0.0f);
159 assert(weight < 1.0f);
161 coord1 = coord0 + 1;
164 static void
165 clamp(GLint &x, GLint xmin, GLint xmax)
167 if (x < xmin) {
168 x = xmin;
170 if (x > xmax) {
171 x = xmax;
175 static float
176 lerp(float x0, float x1, float w)
178 return x0 + (x1 - x0) * w;
181 static float
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] = {
190 0.5, 0.5, 0.5, 0.5
193 static GLboolean
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;
205 if (dstX1 < dstX0) {
206 std::swap(srcX0, srcX1);
207 std::swap(dstX0, dstX1);
209 if (dstY1 < dstY0) {
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) {
246 continue;
249 srcY -= 0.5f;
251 GLint srcPixelY0, srcPixelY1;
252 float weightY;
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) {
260 continue;
263 srcX -= 0.5f;
265 GLint srcPixelX0, srcPixelX1;
266 float weightX;
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],
281 srcPixel01[c],
282 srcPixel10[c],
283 srcPixel11[c],
284 weightX, weightY);
289 delete [] srcPixels;
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);
295 GLboolean pass;
296 pass = piglit_compare_images_color(0, 0, dstW, dstH, numChannels,
297 piglit_tolerance,
298 expectedDstPixels,
299 observedDstPixels);
301 delete [] observedDstPixels;
302 delete [] expectedDstPixels;
304 return pass;
307 static void
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);
318 static GLboolean
319 run_test(const TestCase &test)
321 describe(test);
323 GLboolean pass;
325 GLuint rbo;
326 GLuint fbo;
327 GLenum status;
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,
339 GL_RENDERBUFFER,
340 rbo);
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) {
346 pass = GL_TRUE;
347 } else {
348 GLubyte *image = piglit_rgbw_image_ubyte(test.srcW, test.srcH,
349 GL_TRUE);
350 glDrawPixels(test.srcW, test.srcH, GL_RGBA, GL_UNSIGNED_BYTE,
351 image);
352 free(image);
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);
360 blit(test);
362 pass = verify(test, fbo, 0, 3);
364 if (!piglit_automatic) {
365 piglit_present_results();
366 if (!pass) {
367 //getchar();
372 glBindFramebuffer(GL_FRAMEBUFFER, piglit_winsys_fbo);
373 glDeleteFramebuffers(1, &fbo);
374 glDeleteRenderbuffers(1, &rbo);
376 return pass;
380 * Constants to help define several test cases.
383 #define SRCW 45
384 #define SRCH 79
385 #define DX 17
386 #define DY 11
387 #define SRCXMIN 13
388 #define SRCYMIN 33
389 #define SRCXMAX (SRCXMIN + DX)
390 #define SRCYMAX (SRCYMIN + DY)
392 #define DSTXMIN 19
393 #define DSTYMIN 23
394 #define DSTXMAX (DSTXMIN + DX)
395 #define DSTYMAX (DSTYMIN + DY)
397 const TestCase
398 tests[] = {
400 * Basic 1:1 copy
404 SRCW, SRCH,
405 SRCXMIN, SRCYMIN, SRCXMAX, SRCYMAX,
406 DSTXMIN, DSTYMIN, DSTXMAX, DSTYMAX,
407 GL_NEAREST,
411 * Flip tests
415 SRCW, SRCH,
416 SRCXMAX, SRCYMAX, SRCXMIN, SRCYMIN, // flip xy
417 DSTXMAX, DSTYMAX, DSTXMIN, DSTYMIN, // flip xy
418 GL_NEAREST,
421 SRCW, SRCH,
422 SRCXMAX, SRCYMIN, SRCXMIN, SRCYMAX, // fliped x
423 DSTXMIN, DSTYMAX, DSTXMAX, DSTYMIN, // fliped y
424 GL_NEAREST,
427 SRCW, SRCH,
428 SRCXMIN, SRCYMAX, SRCXMAX, SRCYMIN, // fliped y
429 DSTXMAX, DSTYMIN, DSTXMIN, DSTYMAX, // fliped x
430 GL_NEAREST,
434 * Stretch.
438 SRCW, SRCH,
439 SRCXMIN, SRCYMIN, SRCXMAX, SRCYMAX,
440 DSTXMIN, DSTYMIN, DSTXMAX + 3*DX, DSTYMAX + 3*DY, // stretch x y
441 GL_NEAREST,
444 SRCW, SRCH,
445 SRCXMIN, SRCYMIN, SRCXMAX, SRCYMAX,
446 DSTXMIN, DSTYMIN, DSTXMAX + 3*DX, DSTYMAX + 3*DY, // stretch x y
447 GL_NEAREST,
451 * Stretch of a single pixel.
455 SRCW, SRCH,
456 SRCXMIN, SRCYMIN, SRCXMIN + 1, SRCYMIN + 1,
457 DSTXMIN, DSTYMIN, DSTXMIN + 7, DSTYMIN + 7, // stretch x y
458 GL_NEAREST,
463 * Clip
467 SRCW, SRCH,
468 SRCXMIN, SRCYMIN, SRCXMAX, SRCYMAX,
469 -DX/2, -DY/2, -DX/2 + DX, -DY/2 + DY, // clip dst left bottom
470 GL_NEAREST,
473 SRCW, SRCH,
474 SRCXMIN, SRCYMIN, SRCXMAX, SRCYMAX,
475 DSTW - DX/2, DSTH - DY/2, DSTW - DX/2 + DX, DSTH - DY/2 + DY, // clip dst top right
476 GL_NEAREST,
479 SRCW, SRCH,
480 -DX/2, -DY/2, -DX/2 + DX, -DY/2 + DY, // clip src left bottom
481 DSTXMIN, DSTYMIN, DSTXMAX, DSTYMAX,
482 GL_NEAREST,
485 SRCW, SRCH,
486 SRCW - DX/2, SRCH - DY/2, SRCW - DX/2 + DX, SRCH - DY/2 + DY, // clip src top right
487 DSTXMIN, DSTYMIN, DSTXMAX, DSTYMAX,
488 GL_NEAREST,
492 * Clip & stretch.
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.
498 #if 0
500 SRCW, SRCH,
501 SRCXMIN, SRCYMIN, SRCXMAX, SRCYMAX,
502 -DSTXMIN, -DSTYMIN, DSTXMAX, DSTYMAX, // clip dst left bottom
503 GL_NEAREST,
506 SRCW, SRCH,
507 SRCXMIN, SRCYMIN, SRCXMAX, SRCYMAX,
508 DSTXMIN, DSTYMIN, DSTW + DSTXMIN, DSTH + DSTYMIN, // clip dst top right
509 GL_NEAREST,
512 SRCW, SRCH,
513 -SRCXMIN, -SRCYMIN, SRCXMAX, SRCYMAX, // clip src left bottom
514 DSTXMIN, DSTYMIN, DSTXMAX, DSTYMAX,
515 GL_NEAREST,
518 SRCW, SRCH,
519 SRCXMIN, SRCYMIN, SRCW + SRCXMIN, SRCH + SRCYMIN, // clip src top right
520 DSTXMIN, DSTYMIN, DSTXMAX, DSTYMAX,
521 GL_NEAREST,
524 SRCW, SRCH,
525 SRCXMAX, SRCYMIN, SRCXMIN, SRCYMAX, // fliped x
526 -DSTXMIN, DSTH + DSTYMIN, DSTW + DSTXMIN, -DSTYMIN, // fliped y, cliped x y
527 GL_NEAREST,
529 #endif
532 * Full stretch
536 SRCW, SRCH,
537 0, 0, SRCW, SRCH,
538 0, 0, DSTW, DSTH,
539 GL_NEAREST,
543 static int test_index = -1;
545 enum piglit_result
546 piglit_display(void)
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)
552 continue;
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;
566 void
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");
573 if (argc == 2)
574 sscanf(argv[1], "%d", &test_index);