1 /*
2 * Copyright © 2009-2011 Intel Corporation
3 *
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:
10 *
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.
14 *
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.
22 *
23 * Authors:
24 * Eric Anholt <eric@anholt.net>
25 *
26 */
27
28 /** @file fbo-clear-formats.c
29 *
30 * Tests that glClear works correctly on all levels of 2D
31 * texture-based FBOs of various internalformats.
32 */
33
34 #include "piglit-util-gl.h"
35 #include "fbo-formats.h"
36
37 #define TEX_WIDTH 256
38 #define TEX_HEIGHT 256
39
40 PIGLIT_GL_TEST_CONFIG_BEGIN
41
42 config.supports_gl_compat_version = 10;
43
44 config.window_width = 700;
45 config.window_height = 300;
46 config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_STENCIL |
47 PIGLIT_GL_VISUAL_RGBA;
48 config.khr_no_error_support = PIGLIT_NO_ERRORS;
49
50 PIGLIT_GL_TEST_CONFIG_END
51
52 static bool clear_stencil = false;
53
54 /* Do piglit_rgbw_texture() image but using glClear */
55 static bool
do_rgba_clear(GLenum format,GLuint tex,int level,int size)56 do_rgba_clear(GLenum format, GLuint tex, int level, int size)
57 {
58 float red[4] = {1.0, 0.0, 0.0, 0.0};
59 float green[4] = {0.0, 1.0, 0.0, 0.25};
60 float blue[4] = {0.0, 0.0, 1.0, 0.5};
61 float white[4] = {1.0, 1.0, 1.0, 1.0};
62 float black[4] = {0.0, 0.0, 0.0, 0.0};
63 float *color;
64 GLuint fb;
65 GLenum status;
66
67 glGenFramebuffersEXT(1, &fb);
68 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
69
70 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
71 GL_COLOR_ATTACHMENT0_EXT,
72 GL_TEXTURE_2D,
73 tex,
74 level);
75
76 status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
77 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
78 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
79 glDeleteFramebuffersEXT(1, &fb);
80 return false;
81 }
82
83 /* Handle the small sizes of compressed mipmap blocks */
84 switch (format) {
85 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
86 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
87 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
88 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
89 case GL_COMPRESSED_RGB_FXT1_3DFX:
90 case GL_COMPRESSED_RGBA_FXT1_3DFX:
91 if (size == 4)
92 color = red;
93 else if (size == 2)
94 color = green;
95 else if (size == 1)
96 color = blue;
97 else {
98 assert(0);
99 color = black;
100 }
101 glClearColor(color[0], color[1], color[2], color[3]);
102 glClear(GL_COLOR_BUFFER_BIT);
103 return true;
104 }
105
106 /* Do the first clear unscissored, to give a bit of exposure
107 * to hardware fast-clearing paths on tiled renderers that
108 * require unscissored clears.
109 */
110 glClearColor(red[0], red[1], red[2], red[3]);
111 glClear(GL_COLOR_BUFFER_BIT);
112
113 glEnable(GL_SCISSOR_TEST);
114 glScissor(size / 2, 0, size / 2, size / 2);
115 glClearColor(green[0], green[1], green[2], green[3]);
116 glClear(GL_COLOR_BUFFER_BIT);
117
118 glScissor(0, size / 2, size / 2, size / 2);
119 glClearColor(blue[0], blue[1], blue[2], blue[3]);
120 glClear(GL_COLOR_BUFFER_BIT);
121
122 glScissor(size / 2, size / 2, size / 2, size / 2);
123 glClearColor(white[0], white[1], white[2], white[3]);
124 glClear(GL_COLOR_BUFFER_BIT);
125
126 glDisable(GL_SCISSOR_TEST);
127
128 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
129 glDeleteFramebuffersEXT(1, &fb);
130
131 return true;
132 }
133
134 static bool
do_depth_clear(GLenum format,GLuint tex,int level,int size)135 do_depth_clear(GLenum format, GLuint tex, int level, int size)
136 {
137 GLuint fb;
138 GLenum status;
139 GLint draw_buffer, read_buffer;
140 int x;
141
142 glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
143 glGetIntegerv(GL_READ_BUFFER, &read_buffer);
144
145 glGenFramebuffersEXT(1, &fb);
146 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
147
148 glDrawBuffer(GL_NONE);
149 glReadBuffer(GL_NONE);
150
151 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
152 GL_DEPTH_ATTACHMENT_EXT,
153 GL_TEXTURE_2D,
154 tex,
155 level);
156
157 status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
158 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
159 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
160 glDeleteFramebuffersEXT(1, &fb);
161 return false;
162 }
163
164 glEnable(GL_SCISSOR_TEST);
165
166 for (x = 0; x < size; x++) {
167 float val = (x + 0.5) / (size);
168 glScissor(x, 0, 1, size);
169 glClearDepth(val);
170 glClear(GL_DEPTH_BUFFER_BIT);
171 }
172
173 glDisable(GL_SCISSOR_TEST);
174
175 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
176 glDeleteFramebuffersEXT(1, &fb);
177
178 glDrawBuffer(draw_buffer);
179 glReadBuffer(read_buffer);
180
181 return true;
182 }
183
184 static bool
do_stencil_clear(GLenum format,GLuint tex,int level,int size)185 do_stencil_clear(GLenum format, GLuint tex, int level, int size)
186 {
187 GLuint fb;
188 GLenum status;
189 GLint draw_buffer, read_buffer;
190 int x;
191
192 glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
193 glGetIntegerv(GL_READ_BUFFER, &read_buffer);
194
195 glGenFramebuffersEXT(1, &fb);
196 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
197
198 glDrawBuffer(GL_NONE);
199 glReadBuffer(GL_NONE);
200
201 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
202 GL_DEPTH_STENCIL_ATTACHMENT,
203 GL_TEXTURE_2D,
204 tex,
205 level);
206
207 status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
208 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
209 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
210 glDeleteFramebuffersEXT(1, &fb);
211 return false;
212 }
213
214 glEnable(GL_SCISSOR_TEST);
215
216 for (x = 0; x < size; x++) {
217 unsigned val = ((x + 0.5) / (size)) * 0xff;
218 glScissor(x, 0, 1, size);
219 glClearStencil(val);
220 glClear(GL_STENCIL_BUFFER_BIT);
221 }
222
223 glDisable(GL_SCISSOR_TEST);
224
225 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
226 glDeleteFramebuffersEXT(1, &fb);
227
228 glDrawBuffer(draw_buffer);
229 glReadBuffer(read_buffer);
230
231 if (!piglit_check_gl_error(GL_NO_ERROR)) {
232 /* Should be no error at this point. If there is, report failure */
233 piglit_report_result(PIGLIT_FAIL);
234 }
235
236 return true;
237 }
238
239 static GLuint
create_tex(GLenum internalformat,GLenum baseformat)240 create_tex(GLenum internalformat, GLenum baseformat)
241 {
242 GLuint tex;
243 int level, dim;
244 GLenum type, format;
245
246 glGenTextures(1, &tex);
247 glBindTexture(GL_TEXTURE_2D, tex);
248
249 if (internalformat == GL_DEPTH32F_STENCIL8) {
250 format = GL_DEPTH_STENCIL;
251 type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
252 } else if (baseformat == GL_DEPTH_COMPONENT) {
253 format = GL_DEPTH_COMPONENT;
254 type = GL_FLOAT;
255 } else if (baseformat == GL_DEPTH_STENCIL) {
256 format = GL_DEPTH_STENCIL_EXT;
257 type = GL_UNSIGNED_INT_24_8_EXT;
258 } else {
259 format = GL_RGBA;
260 type = GL_FLOAT;
261 }
262
263 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
264 GL_LINEAR);
265 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
266 GL_LINEAR_MIPMAP_NEAREST);
267
268 for (level = 0, dim = TEX_WIDTH; dim > 0; level++, dim /= 2) {
269 glTexImage2D(GL_TEXTURE_2D, level, internalformat,
270 dim, dim,
271 0,
272 format, type, NULL);
273 }
274
275 for (level = 0, dim = TEX_WIDTH; dim > 0; level++, dim /= 2) {
276 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level);
277 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, level);
278
279 if (clear_stencil || baseformat == GL_STENCIL_INDEX) {
280 if (!do_stencil_clear(format, tex, level, dim)) {
281 glDeleteTextures(1, &tex);
282 return 0;
283 }
284 } else if (baseformat == GL_DEPTH_COMPONENT ||
285 baseformat == GL_DEPTH_STENCIL) {
286 if (!do_depth_clear(format, tex, level, dim)) {
287 glDeleteTextures(1, &tex);
288 return 0;
289 }
290 } else {
291 if (!do_rgba_clear(format, tex, level, dim)) {
292 glDeleteTextures(1, &tex);
293 return 0;
294 }
295 }
296 }
297
298 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1);
299 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
300
301 if (!piglit_check_gl_error(GL_NO_ERROR)) {
302 /* Should be no error at this point. If there is, report failure */
303 piglit_report_result(PIGLIT_FAIL);
304 }
305
306 return tex;
307 }
308
309 static void
draw_mipmap(int x,int y,int dim)310 draw_mipmap(int x, int y, int dim)
311 {
312 glEnable(GL_TEXTURE_2D);
313 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
314 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
316
317 piglit_draw_rect_tex(x, y, dim, dim,
318 0, 0, 1, 1);
319
320 glDisable(GL_TEXTURE_2D);
321 }
322
323 static void
draw_stencil_mipmap(int x,int y,int dim,GLuint tex,GLuint level)324 draw_stencil_mipmap(int x, int y, int dim, GLuint tex, GLuint level)
325 {
326 GLuint fbo;
327 GLint draw_buffer, read_buffer;
328
329 glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
330 glGetIntegerv(GL_READ_BUFFER, &read_buffer);
331
332 glGenFramebuffers(1, &fbo);
333 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
334
335 glDrawBuffer(GL_NONE);
336 glReadBuffer(GL_NONE);
337
338 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
339 GL_TEXTURE_2D, tex, level);
340 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, piglit_winsys_fbo);
341 glWindowPos2i(x, y);
342 glCopyPixels(0, 0, dim, dim, GL_STENCIL);
343 if (!piglit_check_gl_error(GL_NO_ERROR)) {
344 /* The blit shouldn't generate an error. If it does, report failure */
345 piglit_report_result(PIGLIT_FAIL);
346 }
347
348 glBindFramebuffer(GL_FRAMEBUFFER, piglit_winsys_fbo);
349 glDeleteFramebuffers(1, &fbo);
350
351 glDrawBuffer(draw_buffer);
352 glReadBuffer(read_buffer);
353 }
354
355 static void
visualize_stencil()356 visualize_stencil()
357 {
358 unsigned i;
359
360 glEnable(GL_STENCIL_TEST);
361 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
362 for (i = 0; i <= 0xff; i++) {
363 glStencilFunc(GL_EQUAL, i, ~0);
364 glColor4ub(i, i, i, 255);
365 piglit_draw_rect(0, 0, piglit_width, piglit_height);
366 }
367 glDisable(GL_STENCIL_TEST);
368 glColor4ub(255, 255, 255, 255);
369 }
370
371 static GLboolean
test_mipmap_drawing(int x,int y,int dim,int level,GLuint internalformat)372 test_mipmap_drawing(int x, int y, int dim, int level, GLuint internalformat)
373 {
374 GLboolean pass = GL_TRUE;
375 int half = dim / 2;
376 int x1 = x, y1 = y, x2 = x + half, y2 = y + half;
377 float r[] = {1, 0, 0, 0};
378 float g[] = {0, 1, 0, 0.25};
379 float b[] = {0, 0, 1, 0.5};
380 float w[] = {1, 1, 1, 1};
381 GLint r_size, g_size, b_size, l_size, a_size, d_size, i_size;
382 GLint compressed;
383
384 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
385 GL_TEXTURE_COMPRESSED, &compressed);
386 if (compressed && dim < 8)
387 return GL_TRUE;
388
389 if (piglit_is_extension_supported("GL_ARB_depth_texture")) {
390 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
391 GL_TEXTURE_DEPTH_SIZE, &d_size);
392 } else {
393 d_size = 0;
394 }
395 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
396 GL_TEXTURE_LUMINANCE_SIZE, &l_size);
397 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
398 GL_TEXTURE_ALPHA_SIZE, &a_size);
399 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
400 GL_TEXTURE_INTENSITY_SIZE, &i_size);
401 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
402 GL_TEXTURE_RED_SIZE, &r_size);
403 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
404 GL_TEXTURE_GREEN_SIZE, &g_size);
405 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
406 GL_TEXTURE_BLUE_SIZE, &b_size);
407
408 if (d_size) {
409 for (x1 = x; x1 < x + dim; x1++) {
410 float val = (x1 - x + 0.5) / (dim);
411 float color[3] = {val, val, val};
412 pass = pass && piglit_probe_rect_rgb(x1, y, 1, dim,
413 color);
414 }
415 return pass;
416 }
417
418 if (i_size || l_size) {
419 r[0] = 1.0;
420 r[1] = 1.0;
421 r[2] = 1.0;
422
423 g[0] = 0.0;
424 g[1] = 0.0;
425 g[2] = 0.0;
426
427 b[0] = 0.0;
428 b[1] = 0.0;
429 b[2] = 0.0;
430
431 if (i_size) {
432 r[3] = 1.0;
433 g[3] = 0.0;
434 b[3] = 0.0;
435 } else if (l_size && !a_size) {
436 r[3] = 1.0;
437 g[3] = 1.0;
438 b[3] = 1.0;
439 w[3] = 1.0;
440 }
441 } else if (a_size && !r_size && !l_size) {
442 r[0] = 1.0;
443 r[1] = 1.0;
444 r[2] = 1.0;
445 g[0] = 1.0;
446 g[1] = 1.0;
447 g[2] = 1.0;
448 b[0] = 1.0;
449 b[1] = 1.0;
450 b[2] = 1.0;
451 } else {
452 if (!r_size) {
453 r[0] = 0.0;
454 w[0] = 0.0;
455 }
456
457 if (!g_size) {
458 g[1] = 0.0;
459 w[1] = 0.0;
460 }
461
462 if (!b_size) {
463 b[2] = 0.0;
464 w[2] = 0.0;
465 }
466 if (!a_size) {
467 r[3] = 1.0;
468 g[3] = 1.0;
469 b[3] = 1.0;
470 w[3] = 1.0;
471 }
472 }
473
474 /* Clamp the bits for the framebuffer, except we aren't checking
475 * the actual framebuffer bits.
476 */
477 if (l_size > 8)
478 l_size = 8;
479 if (i_size > 8)
480 i_size = 8;
481 if (r_size > 8)
482 r_size = 8;
483 if (g_size > 8)
484 g_size = 8;
485 if (b_size > 8)
486 b_size = 8;
487 if (a_size > 8)
488 a_size = 8;
489
490 if (d_size) {
491 piglit_set_tolerance_for_bits(8, 8, 8, 8);
492 } else if (i_size) {
493 piglit_set_tolerance_for_bits(i_size, i_size, i_size, i_size);
494 } else if (l_size) {
495 piglit_set_tolerance_for_bits(l_size, l_size, l_size, a_size);
496 } else {
497 piglit_set_tolerance_for_bits(r_size, g_size, b_size, a_size);
498 }
499
500 if (internalformat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
501 internalformat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) {
502 /* If alpha in DXT1 is < 0.5, the whole pixel should be black. */
503 r[0] = r[1] = r[2] = r[3] = 0;
504 g[0] = g[1] = g[2] = g[3] = 0;
505 /* If alpha in DXT1 is >= 0.5, it should be white. */
506 b[3] = 1;
507 }
508
509 pass = pass && piglit_probe_rect_rgba(x1, y1, half, half, r);
510 pass = pass && piglit_probe_rect_rgba(x2, y1, half, half, g);
511 pass = pass && piglit_probe_rect_rgba(x1, y2, half, half, b);
512 pass = pass && piglit_probe_rect_rgba(x2, y2, half, half, w);
513
514 return pass;
515 }
516
517 static enum piglit_result
test_format(const struct format_desc * format)518 test_format(const struct format_desc *format)
519 {
520 int dim;
521 GLuint tex;
522 int x;
523 int level;
524 GLboolean pass = GL_TRUE;
525 const char *name = get_format_name(format->internalformat);
526
527 printf("Testing %s", name);
528
529 if (format->base_internal_format == GL_STENCIL_INDEX)
530 clear_stencil = true;
531
532 if (clear_stencil && format->base_internal_format != GL_DEPTH_STENCIL &&
533 format->base_internal_format != GL_STENCIL_INDEX) {
534 printf(" - no stencil.\n");
535 return PIGLIT_SKIP;
536 }
537
538 tex = create_tex(format->internalformat, format->base_internal_format);
539 if (tex == 0) {
540 printf(" - FBO incomplete\n");
541 piglit_report_subtest_result(PIGLIT_SKIP,
542 "%s (fbo incomplete)",
543 name);
544 return PIGLIT_SKIP;
545 }
546 printf("\n");
547
548 if (clear_stencil) {
549 glClearStencil(0x0);
550 glClear(GL_STENCIL_BUFFER_BIT);
551 }
552
553 glViewport(0, 0, piglit_width, piglit_height);
554 piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
555
556 x = 1;
557 level = 0;
558 for (dim = TEX_WIDTH; dim > 1; dim /= 2) {
559 if (clear_stencil)
560 draw_stencil_mipmap(x, 1, dim, tex, level);
561 else
562 draw_mipmap(x, 1, dim);
563 x += dim + 1;
564 level++;
565 }
566
567 if (clear_stencil)
568 visualize_stencil();
569
570 x = 1;
571 level = 0;
572 for (dim = TEX_WIDTH; dim > 1; dim /= 2) {
573 pass = pass && test_mipmap_drawing(x, 1, dim, level,
574 format->internalformat);
575 x += dim + 1;
576 level++;
577 }
578
579 glDeleteTextures(1, &tex);
580
581 piglit_report_subtest_result(pass ? PIGLIT_PASS : PIGLIT_FAIL,
582 "%s", name);
583 return pass ? PIGLIT_PASS : PIGLIT_FAIL;
584 }
585
piglit_display(void)586 enum piglit_result piglit_display(void)
587 {
588 return fbo_formats_display(test_format);
589 }
590
piglit_init(int argc,char ** argv)591 void piglit_init(int argc, char **argv)
592 {
593 if (argc == 3 && strcmp(argv[2], "stencil") == 0)
594 clear_stencil = true;
595
596 if (clear_stencil)
597 piglit_require_extension("GL_ARB_framebuffer_object");
598
599 fbo_formats_init(clear_stencil ? 2 : argc, argv, GL_TRUE);
600 }
601