2 * Copyright (c) 2011 VMware, Inc.
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:
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,
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
27 * @file getteximage-formats.c
29 * Test glGetTexImage with a variety of formats.
35 #include "piglit-util-gl.h"
36 #include "../fbo/fbo-formats.h"
38 PIGLIT_GL_TEST_CONFIG_BEGIN
40 config
.supports_gl_compat_version
= 10;
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
;
47 PIGLIT_GL_TEST_CONFIG_END
49 static const char *TestName
= "getteximage-formats";
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
;
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
68 make_texture_image(GLenum intFormat
, GLubyte upperRightTexel
[4])
70 GLubyte tex
[TEX_SIZE
][TEX_SIZE
][4];
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
;
79 if (((i
>> 4) ^ (j
>> 4)) & 1)
80 tex
[i
][j
][3] = 255; /* opaque */
82 tex
[i
][j
][3] = 125; /* transparent */
86 memcpy(upperRightTexel
, tex
[TEX_SIZE
-1][TEX_SIZE
-1], 4);
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
);
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
);
107 if (init_by_clearing_first
) {
108 glClearColor(1, 0, 0, 1);
109 glClear(GL_COLOR_BUFFER_BIT
);
112 glViewport(0, 0, TEX_SIZE
, TEX_SIZE
);
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.
119 * On dithering and glDrawPixels, see the OpenGL 4.5
120 * Compatibility Specification, Section 18.1 Drawing Pixels,
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).
128 * On dithering and glGenerateMipmap, see the Mesa commit
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
136 glDisable(GL_DITHER
);
137 glWindowPos2iARB(0, 0);
138 glDrawPixels(TEX_SIZE
, TEX_SIZE
, GL_RGBA
, GL_UNSIGNED_BYTE
, tex
);
141 glGenerateMipmap(GL_TEXTURE_2D
);
143 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, piglit_winsys_fbo
);
144 glDeleteFramebuffers(1, &fb
);
145 glViewport(0, 0, piglit_width
, piglit_height
);
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
);
153 return glGetError() == GL_NO_ERROR
;
157 ubyte_to_float(GLubyte b
, GLint bits
)
160 GLint b2
= b
>> (8 - bits
);
161 GLint max
= 255 >> (8 - bits
);
162 return b2
/ (float) max
;
172 bits_to_tolerance(GLint bits
, GLboolean compressed
)
179 else if (bits
== 1) {
183 /* The original texture was specified as GLubyte and we
184 * assume that the window/surface is 8-bits/channel.
189 t
= 4.0 / (1 << (bits
- 1));
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
206 compute_expected_color(const struct format_desc
*fmt
,
207 const GLubyte upperRightTexel
[4],
208 GLfloat expected
[4], GLfloat tolerance
[4])
214 bits
[0] = bits
[1] = bits
[2] = bits
[3] = 0;
216 /* Handle special cases first */
217 if (fmt
->internalformat
== GL_R11F_G11F_B10F_EXT
) {
218 bits
[0] = bits
[1] = bits
[2] = 8;
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]);
224 compressed
= GL_FALSE
;
227 GLint r
, g
, b
, a
, l
, i
;
228 GLenum baseFormat
= 0;
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
);
239 printf("r=%d g=%d b=%d a=%d l=%d i=%d\n", r
, g
, b
, a
, l
, i
);
242 baseFormat
= GL_INTENSITY
;
247 texel
[0] = ubyte_to_float(upperRightTexel
[0], bits
[0]);
250 texel
[3] = ubyte_to_float(upperRightTexel
[0], bits
[3]);
254 baseFormat
= GL_LUMINANCE_ALPHA
;
259 texel
[0] = ubyte_to_float(upperRightTexel
[0], bits
[0]);
262 texel
[3] = ubyte_to_float(upperRightTexel
[3], bits
[3]);
264 else if (r
> 0 && g
> 0 && b
> 0) {
265 baseFormat
= GL_RGBA
;
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]);
275 else if (r
== 0 && g
== 0 && b
== 0) {
276 baseFormat
= GL_ALPHA
;
284 texel
[3] = ubyte_to_float(upperRightTexel
[3], bits
[3]);
287 baseFormat
= 0; /* ??? */
295 baseFormat
= GL_LUMINANCE
;
300 texel
[0] = ubyte_to_float(upperRightTexel
[0], bits
[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]);
324 texel
[0] = ubyte_to_float(upperRightTexel
[0], bits
[0]);
325 texel
[1] = ubyte_to_float(upperRightTexel
[1], bits
[1]);
336 texel
[0] = ubyte_to_float(upperRightTexel
[0], bits
[0]);
342 assert(!"Unexpected texture component sizes");
349 (void) baseFormat
; /* not used, at this time */
352 /* compute texel color blended with background color */
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]);
359 expected
[0] = texel
[0];
360 expected
[1] = texel
[1];
361 expected
[2] = texel
[2];
362 expected
[3] = texel
[3];
365 assert(expected
[0] == expected
[0]);
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
);
375 colors_equal(const GLfloat expected
[4], const GLfloat pix
[4],
376 GLfloat tolerance
[4])
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]) {
389 test_format(const struct test_desc
*test
,
390 const struct format_desc
*fmt
)
393 int w
= TEX_SIZE
, h
= TEX_SIZE
;
394 GLfloat readback
[TEX_SIZE
][TEX_SIZE
][4];
395 GLubyte upperRightTexel
[4];
397 GLfloat expected
[4], pix
[4], tolerance
[4];
398 GLboolean pass
= GL_TRUE
;
400 glClearColor(clearColor
[0], clearColor
[1], clearColor
[2], clearColor
[3]);
401 glClear(GL_COLOR_BUFFER_BIT
);
403 /* The RGBA_DXT1 formats seem to expose a Mesa/libtxc_dxtn bug.
404 * Just skip them for now. Testing the other compressed formats
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 */
416 compute_expected_color(fmt
, upperRightTexel
, expected
, tolerance
);
418 /* Draw with the texture */
419 glEnable(GL_TEXTURE_2D
);
423 piglit_draw_rect_tex(x
, y
, w
, h
, 0.0, 0.0, 1.0, 1.0);
424 glDisable(GL_TEXTURE_2D
);
431 /* Get the texture image */
432 assert(!glIsEnabled(GL_TEXTURE_2D
));
433 glGetTexImage(GL_TEXTURE_2D
, level
, GL_RGBA
, GL_FLOAT
, readback
);
435 assert(!glIsEnabled(GL_TEXTURE_2D
));
436 /* Draw the texture image */
437 glWindowPos2iARB(x
, y
);
441 assert(!glIsEnabled(GL_TEXTURE_2D
));
442 glDrawPixels(w
, h
, GL_RGBA
, GL_FLOAT
, readback
);
445 assert(!glIsEnabled(GL_TEXTURE_2D
));
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",
455 fmt
->internalformat
),
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]);
475 piglit_present_results();
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.
487 supported_format_set(const struct test_desc
*set
)
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
) {
499 * texture_integer requires a fragment shader, different
500 * glTexImage calls. Depth/stencil formats not implemented.
510 test_all_formats(void)
512 GLboolean pass
= GL_TRUE
;
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
])) {
535 piglit_ortho_projection(piglit_width
, piglit_height
, GL_FALSE
);
537 if (piglit_automatic
) {
538 pass
= test_all_formats();
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
]);
546 /* unsupported format - not a failure */
548 glClear(GL_COLOR_BUFFER_BIT
);
549 piglit_present_results();
553 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
557 piglit_init(int argc
, char **argv
)
559 bool found_test_set
= false;
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
);
567 (void) fbo_formats_display
;
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.");
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.");
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
]);
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
);
593 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
595 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);