1 /*
2 * Copyright (c) 2011 VMware, Inc.
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the 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,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NON-INFRINGEMENT. IN NO EVENT SHALL VMWARE AND/OR THEIR SUPPLIERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25
26 /**
27 * @file getteximage-formats.c
28 *
29 * Test glGetTexImage with a variety of formats.
30 * Brian Paul
31 * Sep 2011
32 */
33
34
35 #include "piglit-util-gl.h"
36 #include "../fbo/fbo-formats.h"
37
38 PIGLIT_GL_TEST_CONFIG_BEGIN
39
40 config.supports_gl_compat_version = 10;
41
42 config.window_width = 600;
43 config.window_height = 200;
44 config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE;
45 config.khr_no_error_support = PIGLIT_NO_ERRORS;
46
47 PIGLIT_GL_TEST_CONFIG_END
48
49 static const char *TestName = "getteximage-formats";
50
51 static const GLfloat clearColor[4] = { 0.4, 0.4, 0.4, 0.0 };
52 static GLuint texture_id;
53 static GLboolean init_by_rendering;
54 static GLboolean init_by_clearing_first;
55
56 #define TEX_SIZE 128
57
58 #define DO_BLEND 1
59
60
61 /**
62 * Make a simple texture image where red increases from left to right,
63 * green increases from bottom to top, blue stays constant (50%) and
64 * the alpha channel is a checkerboard pattern.
65 * \return GL_TRUE for success, GL_FALSE if unsupported format
66 */
67 static GLboolean
make_texture_image(GLenum intFormat,GLubyte upperRightTexel[4])68 make_texture_image(GLenum intFormat, GLubyte upperRightTexel[4])
69 {
70 GLubyte tex[TEX_SIZE][TEX_SIZE][4];
71 int i, j;
72 GLuint fb, status;
73
74 for (i = 0; i < TEX_SIZE; i++) {
75 for (j = 0; j < TEX_SIZE; j++) {
76 tex[i][j][0] = j * 255 / TEX_SIZE;
77 tex[i][j][1] = i * 255 / TEX_SIZE;
78 tex[i][j][2] = 128;
79 if (((i >> 4) ^ (j >> 4)) & 1)
80 tex[i][j][3] = 255; /* opaque */
81 else
82 tex[i][j][3] = 125; /* transparent */
83 }
84 }
85
86 memcpy(upperRightTexel, tex[TEX_SIZE-1][TEX_SIZE-1], 4);
87
88 if (init_by_rendering || init_by_clearing_first) {
89 /* Initialize the mipmap levels. */
90 for (i = TEX_SIZE, j = 0; i; i >>= 1, j++) {
91 glTexImage2D(GL_TEXTURE_2D, j, intFormat, i, i, 0,
92 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
93 }
94
95 /* Initialize the texture with glDrawPixels. */
96 glGenFramebuffers(1, &fb);
97 glBindFramebuffer(GL_FRAMEBUFFER, fb);
98 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
99 GL_TEXTURE_2D, texture_id, 0);
100 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
101 if (status != GL_FRAMEBUFFER_COMPLETE) {
102 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
103 glDeleteFramebuffers(1, &fb);
104 return GL_FALSE;
105 }
106
107 if (init_by_clearing_first) {
108 glClearColor(1, 0, 0, 1);
109 glClear(GL_COLOR_BUFFER_BIT);
110 }
111
112 glViewport(0, 0, TEX_SIZE, TEX_SIZE);
113
114 /* Disable dithering during glDrawPixels to prevent
115 * disagreement with glGenerateMipmap. The spec requires
116 * glDrawPixels to respect the dither state, but the spec
117 * strongly implies that glGenerateMipmap should not dither.
118 *
119 * On dithering and glDrawPixels, see the OpenGL 4.5
120 * Compatibility Specification, Section 18.1 Drawing Pixels,
121 * p620:
122 *
123 * Once pixels are transferred, DrawPixels performs final
124 * conversion on pixel values [...] which are processed in
125 * the same fashion as fragments generated by rasterization
126 * (see chapters 15 and 16).
127 *
128 * On dithering and glGenerateMipmap, see the Mesa commit
129 * message in:
130 *
131 * commit c4b87f129eb036c9615df3adcc1cebd9df10fc84
132 * Author: Chad Versace <chadversary@chromium.org>
133 * Date: Thu Dec 29 13:05:27 2016 -0800
134 * Subject: meta: Disable dithering during glGenerateMipmap
135 */
136 glDisable(GL_DITHER);
137 glWindowPos2iARB(0, 0);
138 glDrawPixels(TEX_SIZE, TEX_SIZE, GL_RGBA, GL_UNSIGNED_BYTE, tex);
139 glEnable(GL_DITHER);
140
141 glGenerateMipmap(GL_TEXTURE_2D);
142
143 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, piglit_winsys_fbo);
144 glDeleteFramebuffers(1, &fb);
145 glViewport(0, 0, piglit_width, piglit_height);
146 }
147 else {
148 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
149 glTexImage2D(GL_TEXTURE_2D, 0, intFormat, TEX_SIZE, TEX_SIZE, 0,
150 GL_RGBA, GL_UNSIGNED_BYTE, tex);
151 }
152
153 return glGetError() == GL_NO_ERROR;
154 }
155
156 static GLfloat
ubyte_to_float(GLubyte b,GLint bits)157 ubyte_to_float(GLubyte b, GLint bits)
158 {
159 if (bits <= 8) {
160 GLint b2 = b >> (8 - bits);
161 GLint max = 255 >> (8 - bits);
162 return b2 / (float) max;
163 }
164 else {
165 return b / 255.0;
166 }
167 }
168
169
170
171 static GLfloat
bits_to_tolerance(GLint bits,GLboolean compressed)172 bits_to_tolerance(GLint bits, GLboolean compressed)
173 {
174 GLfloat t;
175
176 if (bits == 0) {
177 return 0.25;
178 }
179 else if (bits == 1) {
180 return 0.5;
181 }
182 else if (bits > 8) {
183 /* The original texture was specified as GLubyte and we
184 * assume that the window/surface is 8-bits/channel.
185 */
186 t = 4.0 / 255;
187 }
188 else {
189 t = 4.0 / (1 << (bits - 1));
190 }
191
192 if (compressed) {
193 /* Use a fudge factor. The queries for GL_TEXTURE_RED/
194 * GREEN/BLUE/ALPHA_SIZE don't return well-defined values for
195 * compressed formats so using them is unreliable. This is
196 * pretty loose, but good enough to catch some Mesa bugs during
197 * development.
198 */
199 t = 0.3;
200 }
201 return t;
202 }
203
204
205 static void
compute_expected_color(const struct format_desc * fmt,const GLubyte upperRightTexel[4],GLfloat expected[4],GLfloat tolerance[4])206 compute_expected_color(const struct format_desc *fmt,
207 const GLubyte upperRightTexel[4],
208 GLfloat expected[4], GLfloat tolerance[4])
209 {
210 GLfloat texel[4];
211 GLint compressed;
212 int bits[4];
213
214 bits[0] = bits[1] = bits[2] = bits[3] = 0;
215
216 /* Handle special cases first */
217 if (fmt->internalformat == GL_R11F_G11F_B10F_EXT) {
218 bits[0] = bits[1] = bits[2] = 8;
219 bits[3] = 0;
220 texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
221 texel[1] = ubyte_to_float(upperRightTexel[1], bits[1]);
222 texel[2] = ubyte_to_float(upperRightTexel[2], bits[2]);
223 texel[3] = 1.0;
224 compressed = GL_FALSE;
225 }
226 else {
227 GLint r, g, b, a, l, i;
228 GLenum baseFormat = 0;
229
230 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_RED_SIZE, &r);
231 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_GREEN_SIZE, &g);
232 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BLUE_SIZE, &b);
233 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_ALPHA_SIZE, &a);
234 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_LUMINANCE_SIZE, &l);
235 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTENSITY_SIZE, &i);
236 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &compressed);
237
238 if (0)
239 printf("r=%d g=%d b=%d a=%d l=%d i=%d\n", r, g, b, a, l, i);
240
241 if (i > 0) {
242 baseFormat = GL_INTENSITY;
243 bits[0] = i;
244 bits[1] = 0;
245 bits[2] = 0;
246 bits[3] = i;
247 texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
248 texel[1] = 0.0;
249 texel[2] = 0.0;
250 texel[3] = ubyte_to_float(upperRightTexel[0], bits[3]);
251 }
252 else if (a > 0) {
253 if (l > 0) {
254 baseFormat = GL_LUMINANCE_ALPHA;
255 bits[0] = l;
256 bits[1] = 0;
257 bits[2] = 0;
258 bits[3] = a;
259 texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
260 texel[1] = 0.0;
261 texel[2] = 0.0;
262 texel[3] = ubyte_to_float(upperRightTexel[3], bits[3]);
263 }
264 else if (r > 0 && g > 0 && b > 0) {
265 baseFormat = GL_RGBA;
266 bits[0] = r;
267 bits[1] = g;
268 bits[2] = b;
269 bits[3] = a;
270 texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
271 texel[1] = ubyte_to_float(upperRightTexel[1], bits[1]);
272 texel[2] = ubyte_to_float(upperRightTexel[2], bits[2]);
273 texel[3] = ubyte_to_float(upperRightTexel[3], bits[3]);
274 }
275 else if (r == 0 && g == 0 && b == 0) {
276 baseFormat = GL_ALPHA;
277 bits[0] = 0;
278 bits[1] = 0;
279 bits[2] = 0;
280 bits[3] = a;
281 texel[0] = 0.0;
282 texel[1] = 0.0;
283 texel[2] = 0.0;
284 texel[3] = ubyte_to_float(upperRightTexel[3], bits[3]);
285 }
286 else {
287 baseFormat = 0; /* ??? */
288 texel[0] = 0.0;
289 texel[1] = 0.0;
290 texel[2] = 0.0;
291 texel[3] = 0.0;
292 }
293 }
294 else if (l > 0) {
295 baseFormat = GL_LUMINANCE;
296 bits[0] = l;
297 bits[1] = 0;
298 bits[2] = 0;
299 bits[3] = 0;
300 texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
301 texel[1] = 0.0;
302 texel[2] = 0.0;
303 texel[3] = 1.0;
304 }
305 else if (r > 0) {
306 if (g > 0) {
307 if (b > 0) {
308 baseFormat = GL_RGB;
309 bits[0] = r;
310 bits[1] = g;
311 bits[2] = b;
312 bits[3] = 0;
313 texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
314 texel[1] = ubyte_to_float(upperRightTexel[1], bits[1]);
315 texel[2] = ubyte_to_float(upperRightTexel[2], bits[2]);
316 texel[3] = 1.0;
317 }
318 else {
319 baseFormat = GL_RG;
320 bits[0] = r;
321 bits[1] = g;
322 bits[2] = 0;
323 bits[3] = 0;
324 texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
325 texel[1] = ubyte_to_float(upperRightTexel[1], bits[1]);
326 texel[2] = 0.0;
327 texel[3] = 1.0;
328 }
329 }
330 else {
331 baseFormat = GL_RED;
332 bits[0] = r;
333 bits[1] = 0;
334 bits[2] = 0;
335 bits[3] = 0;
336 texel[0] = ubyte_to_float(upperRightTexel[0], bits[0]);
337 texel[1] = 0.0;
338 texel[2] = 0.0;
339 texel[3] = 1.0;
340 }
341 } else {
342 assert(!"Unexpected texture component sizes");
343 texel[0] = 0.0;
344 texel[1] = 0.0;
345 texel[2] = 0.0;
346 texel[3] = 0.0;
347 }
348
349 (void) baseFormat; /* not used, at this time */
350 }
351
352 /* compute texel color blended with background color */
353 #if DO_BLEND
354 expected[0] = texel[0] * texel[3] + clearColor[0] * (1.0 - texel[3]);
355 expected[1] = texel[1] * texel[3] + clearColor[1] * (1.0 - texel[3]);
356 expected[2] = texel[2] * texel[3] + clearColor[2] * (1.0 - texel[3]);
357 expected[3] = texel[3] * texel[3] + clearColor[3] * (1.0 - texel[3]);
358 #else
359 expected[0] = texel[0];
360 expected[1] = texel[1];
361 expected[2] = texel[2];
362 expected[3] = texel[3];
363 #endif
364
365 assert(expected[0] == expected[0]);
366
367 tolerance[0] = bits_to_tolerance(bits[0], compressed);
368 tolerance[1] = bits_to_tolerance(bits[1], compressed);
369 tolerance[2] = bits_to_tolerance(bits[2], compressed);
370 tolerance[3] = bits_to_tolerance(bits[3], compressed);
371 }
372
373
374 static GLboolean
colors_equal(const GLfloat expected[4],const GLfloat pix[4],GLfloat tolerance[4])375 colors_equal(const GLfloat expected[4], const GLfloat pix[4],
376 GLfloat tolerance[4])
377 {
378 if (fabsf(expected[0] - pix[0]) > tolerance[0] ||
379 fabsf(expected[1] - pix[1]) > tolerance[1] ||
380 fabsf(expected[2] - pix[2]) > tolerance[2] ||
381 fabsf(expected[3] - pix[3]) > tolerance[3]) {
382 return GL_FALSE;
383 }
384 return GL_TRUE;
385 }
386
387
388 static GLboolean
test_format(const struct test_desc * test,const struct format_desc * fmt)389 test_format(const struct test_desc *test,
390 const struct format_desc *fmt)
391 {
392 int x, y;
393 int w = TEX_SIZE, h = TEX_SIZE;
394 GLfloat readback[TEX_SIZE][TEX_SIZE][4];
395 GLubyte upperRightTexel[4];
396 int level;
397 GLfloat expected[4], pix[4], tolerance[4];
398 GLboolean pass = GL_TRUE;
399
400 glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
401 glClear(GL_COLOR_BUFFER_BIT);
402
403 /* The RGBA_DXT1 formats seem to expose a Mesa/libtxc_dxtn bug.
404 * Just skip them for now. Testing the other compressed formats
405 * is good enough.
406 */
407 if (fmt->internalformat != GL_COMPRESSED_RGBA_S3TC_DXT1_EXT &&
408 fmt->internalformat != GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) {
409 /* init texture image */
410 if (!make_texture_image(fmt->internalformat, upperRightTexel))
411 return GL_TRUE; /* unsupported = OK */
412
413 x = 10;
414 y = 40;
415
416 compute_expected_color(fmt, upperRightTexel, expected, tolerance);
417
418 /* Draw with the texture */
419 glEnable(GL_TEXTURE_2D);
420 #if DO_BLEND
421 glEnable(GL_BLEND);
422 #endif
423 piglit_draw_rect_tex(x, y, w, h, 0.0, 0.0, 1.0, 1.0);
424 glDisable(GL_TEXTURE_2D);
425 glDisable(GL_BLEND);
426
427 x += TEX_SIZE + 20;
428
429 level = 0;
430 while (w > 0) {
431 /* Get the texture image */
432 assert(!glIsEnabled(GL_TEXTURE_2D));
433 glGetTexImage(GL_TEXTURE_2D, level, GL_RGBA, GL_FLOAT, readback);
434
435 assert(!glIsEnabled(GL_TEXTURE_2D));
436 /* Draw the texture image */
437 glWindowPos2iARB(x, y);
438 #if DO_BLEND
439 glEnable(GL_BLEND);
440 #endif
441 assert(!glIsEnabled(GL_TEXTURE_2D));
442 glDrawPixels(w, h, GL_RGBA, GL_FLOAT, readback);
443 glDisable(GL_BLEND);
444
445 assert(!glIsEnabled(GL_TEXTURE_2D));
446
447 if (level <= 2) {
448 GLint rx = x + w-1;
449 GLint ry = y + h-1;
450 glReadPixels(rx, ry, 1, 1, GL_RGBA, GL_FLOAT, pix);
451 if (!colors_equal(expected, pix, tolerance)) {
452 printf("%s failure: format: %s, level %d at pixel(%d, %d)\n",
453 TestName,
454 get_format_name(
455 fmt->internalformat),
456 level, rx, ry);
457 printf(" Expected (%f, %f, %f, %f)\n",
458 expected[0], expected[1], expected[2], expected[3]);
459 printf(" Found (%f, %f, %f, %f)\n",
460 pix[0], pix[1], pix[2], pix[3]);
461 printf("Tolerance (%f, %f, %f, %f)\n",
462 tolerance[0], tolerance[1], tolerance[2], tolerance[3]);
463 pass = GL_FALSE;
464 }
465 }
466
467 x += w + 20;
468 w /= 2;
469 h /= 2;
470 level++;
471 }
472
473 }
474
475 piglit_present_results();
476
477 return pass;
478 }
479
480
481 /**
482 * Is the given set of formats supported?
483 * This checks if required extensions are present and if this piglit test
484 * can actually grok the formats.
485 */
486 static GLboolean
supported_format_set(const struct test_desc * set)487 supported_format_set(const struct test_desc *set)
488 {
489 if (!supported(set))
490 return GL_FALSE;
491
492 if (set->format == ext_texture_integer ||
493 set->format == ext_packed_depth_stencil ||
494 set->format == arb_texture_stencil8 ||
495 set->format == arb_texture_rg_int ||
496 set->format == arb_depth_texture ||
497 set->format == arb_depth_buffer_float) {
498 /*
499 * texture_integer requires a fragment shader, different
500 * glTexImage calls. Depth/stencil formats not implemented.
501 */
502 return GL_FALSE;
503 }
504
505 return GL_TRUE;
506 }
507
508
509 static GLboolean
test_all_formats(void)510 test_all_formats(void)
511 {
512 GLboolean pass = GL_TRUE;
513 int i, j;
514
515 for (i = 0; i < ARRAY_SIZE(test_sets); i++) {
516 const struct test_desc *set = &test_sets[i];
517 if (supported_format_set(set)) {
518 for (j = 0; j < set->num_formats; j++) {
519 if (!test_format(set, &set->format[j])) {
520 pass = GL_FALSE;
521 }
522 }
523 }
524 }
525
526 return pass;
527 }
528
529
530 enum piglit_result
piglit_display(void)531 piglit_display(void)
532 {
533 GLboolean pass;
534
535 piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
536
537 if (piglit_automatic) {
538 pass = test_all_formats();
539 }
540 else {
541 const struct test_desc *set = &test_sets[test_index];
542 if (supported_format_set(set)) {
543 pass = test_format(set, &set->format[format_index]);
544 }
545 else {
546 /* unsupported format - not a failure */
547 pass = GL_TRUE;
548 glClear(GL_COLOR_BUFFER_BIT);
549 piglit_present_results();
550 }
551 }
552
553 return pass ? PIGLIT_PASS : PIGLIT_FAIL;
554 }
555
556 void
piglit_init(int argc,char ** argv)557 piglit_init(int argc, char **argv)
558 {
559 bool found_test_set = false;
560 int i;
561
562 if ((piglit_get_gl_version() < 14) && !piglit_is_extension_supported("GL_ARB_window_pos")) {
563 printf("Requires GL 1.4 or GL_ARB_window_pos");
564 piglit_report_result(PIGLIT_SKIP);
565 }
566
567 (void) fbo_formats_display;
568
569 for (i = 1; i < argc; i++) {
570 if (strcmp(argv[i], "init-by-rendering") == 0) {
571 init_by_rendering = GL_TRUE;
572 puts("The textures will be initialized by rendering "
573 "to them using glDrawPixels.");
574 break;
575 } else if (strcmp(argv[i], "init-by-clear-and-render") == 0) {
576 init_by_clearing_first = GL_TRUE;
577 puts("The textures will be initialized by rendering "
578 "to them using glClear and glDrawPixels.");
579 break;
580 } else if (!found_test_set) {
581 found_test_set = fbo_use_test_set(argv[i], true);
582 if (!found_test_set) {
583 printf("Bad test set name: %s\n", argv[i]);
584 }
585 }
586 }
587
588 glGenTextures(1, &texture_id);
589 glBindTexture(GL_TEXTURE_2D, texture_id);
590 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
591 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
592
593 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
594
595 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
596 }
597