2 * Copyright 2012 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 * 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:
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, 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
25 * Verify error checking for compressed texture functions, using s3tc as
26 * the specific compression formats.
27 * Some rendering is also tested, but it's not the focus here.
28 * Other compressed formats could be added as well (the test should probably
29 * be renamed at that point.)
35 #include "piglit-util-gl.h"
37 PIGLIT_GL_TEST_CONFIG_BEGIN
39 #ifdef PIGLIT_USE_OPENGL
40 config
.supports_gl_compat_version
= 11;
41 #else // PIGLIT_USE_OPENGL_ES2
42 config
.supports_gl_es_version
= 20;
45 config
.window_width
= 200;
46 config
.window_height
= 200;
47 config
.window_visual
= PIGLIT_GL_VISUAL_RGB
| PIGLIT_GL_VISUAL_DOUBLE
;
48 config
.khr_no_error_support
= PIGLIT_HAS_ERRORS
;
50 PIGLIT_GL_TEST_CONFIG_END
52 static const float red
[4] = {1.0, 0.0, 0.0, 1.0};
53 static const float green
[4] = {0.0, 1.0, 0.0, 1.0};
54 static const float blue
[4] = {0.0, 0.0, 1.0, 1.0};
55 static const float white
[4] = {1.0, 1.0, 1.0, 1.0};
57 #ifdef PIGLIT_USE_OPENGL_ES2
59 const char *vs_source
=
61 "attribute vec4 piglit_vertex;\n"
62 "attribute vec2 piglit_texcoord;\n"
63 "varying mediump vec2 tex_coord;\n"
64 "uniform mat4 proj;\n"
68 " gl_Position = proj * piglit_vertex;\n"
69 " tex_coord = piglit_texcoord;\n"
72 const char *fs_source
=
74 "varying mediump vec2 tex_coord;\n"
75 "uniform sampler2D tex;\n"
79 " gl_FragColor = texture2D(tex, tex_coord);\n"
82 #include "piglit-matrix.h"
84 GLint tex_program
, proj_loc
;
88 static const GLenum s3tc_formats
[] = {
89 GL_COMPRESSED_RGB_S3TC_DXT1_EXT
,
90 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
,
91 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
,
92 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
97 check_rendering_(int width
, int height
, int line
)
99 const int w
= width
/ 2 - 2;
100 const int h
= height
/ 2 - 2;
103 #ifdef PIGLIT_USE_OPENGL
104 piglit_ortho_projection(piglit_width
, piglit_height
, GL_FALSE
);
106 glUseProgram(tex_program
);
107 piglit_ortho_uniform(proj_loc
, piglit_width
, piglit_height
);
110 glClear(GL_COLOR_BUFFER_BIT
);
112 #ifdef PIGLIT_USE_OPENGL
113 glEnable(GL_TEXTURE_2D
);
117 /* draw the texture */
118 piglit_draw_rect_tex(0, 0, width
, height
, 0, 0, 1, 1);
120 /* NOTE: don't probe the border pixels of the quadrants just to
121 * avoid potential off-by one errors.
125 pass
= piglit_probe_rect_rgb(1, 1, w
, h
, red
) && pass
;
127 /* lower-right green */
128 pass
= piglit_probe_rect_rgb(width
/2 + 1, 1, w
, h
, green
) && pass
;
130 /* upper-left blue */
131 pass
= piglit_probe_rect_rgb(1, height
/2 + 1, w
, h
, blue
) && pass
;
133 /* upper-right white */
134 pass
= piglit_probe_rect_rgb(width
/2 + 1, height
/2 + 1,
135 w
, h
, white
) && pass
;
137 piglit_present_results();
140 printf("s3tc-errors failure at line %d\n", line
);
147 #define check_rendering(w, h) check_rendering_(w, h, __LINE__)
150 #ifdef PIGLIT_USE_OPENGL
152 * Check for either of two expected GL errors.
153 * XXX this could be a piglit util function
156 check_gl_error2_(GLenum err1
, GLenum err2
, int line
)
158 GLenum err
= glGetError();
159 if (err
!= err1
&& err
!= err2
) {
160 printf("Unexpected error %s at %s:%d\n",
161 piglit_get_gl_error_name(err
), __FILE__
, line
);
167 #define check_gl_error2(err1, err2) check_gl_error2_(err1, err2, __LINE__)
172 test_format(int width
, int height
, GLfloat
*image
, GLenum requested_format
)
174 #ifdef PIGLIT_USE_OPENGL
175 GLubyte
*compressed_image
;
181 GLuint expected_size
;
183 GLint compressed_size
;
186 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, 0);
187 glPixelStorei(GL_UNPACK_SKIP_ROWS
, 0);
188 glPixelStorei(GL_UNPACK_ROW_LENGTH
, width
);
190 /* Setup initial texture */
191 glGenTextures(1, &tex
);
192 glBindTexture(GL_TEXTURE_2D
, tex
);
193 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
194 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
195 glTexImage2D(GL_TEXTURE_2D
, 0, requested_format
, width
, height
, 0,
196 GL_RGBA
, GL_FLOAT
, image
);
198 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
199 pass
= check_rendering(width
, height
) && pass
;
201 if (!piglit_is_gles() || piglit_get_gl_version() >= 31) {
203 glGetTexLevelParameteriv(GL_TEXTURE_2D
, 0, GL_TEXTURE_COMPRESSED
,
205 glGetTexLevelParameteriv(GL_TEXTURE_2D
, 0,
206 GL_TEXTURE_INTERNAL_FORMAT
, &format
);
207 glGetTexLevelParameteriv(GL_TEXTURE_2D
, 0,
208 GL_TEXTURE_COMPRESSED_IMAGE_SIZE
,
211 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
213 if (!is_compressed
) {
214 printf("Image was not compressed\n");
218 if (format
!= requested_format
) {
219 printf("Internal Format mismatch. Found: 0x%04x Expected: 0x%04x\n",
220 format
, requested_format
);
224 expected_size
= piglit_compressed_image_size(requested_format
,
227 if (compressed_size
!= expected_size
) {
228 printf("Compressed image size mismatch. Found: %u Expected: %u\n",
229 compressed_size
, expected_size
);
234 #ifdef PIGLIT_USE_OPENGL
235 /* Use GL_TEXTURE_COMPRESSED_IMAGE_SIZE even if it wasn't what we
236 * expected to avoid corruption due to under-allocated buffer.
238 compressed_image
= malloc(compressed_size
);
240 /* Read back the compressed image data */
241 glGetCompressedTexImage(GL_TEXTURE_2D
, 0, compressed_image
);
244 /* Try texsubimage on 4-texel boundary - should work */
249 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, x
);
250 glPixelStorei(GL_UNPACK_SKIP_ROWS
, y
);
251 glTexSubImage2D(GL_TEXTURE_2D
, 0,
253 GL_RGBA
, GL_FLOAT
, image
);
255 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
256 pass
= check_rendering(width
, height
) && pass
;
258 /* Try texsubimage on non 4-texel boundary - should not work */
261 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, x
);
262 glPixelStorei(GL_UNPACK_SKIP_ROWS
, y
);
263 glTexSubImage2D(GL_TEXTURE_2D
, 0,
265 GL_RGBA
, GL_FLOAT
, image
);
267 pass
= piglit_check_gl_error(GL_INVALID_OPERATION
) && pass
;
269 #ifdef PIGLIT_USE_OPENGL
270 /* Try compressed subimage on 4-texel boundary - should work */
273 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, x
);
274 glPixelStorei(GL_UNPACK_SKIP_ROWS
, y
);
275 glCompressedTexSubImage2D(GL_TEXTURE_2D
, 0,
278 piglit_compressed_image_size(format
, w
, h
),
280 piglit_compressed_pixel_offset(format
, width
, x
, y
));
282 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
283 pass
= check_rendering(width
, height
) && pass
;
285 /* Try compressed subimage on non 4-texel boundary - should not work */
288 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, x
);
289 glPixelStorei(GL_UNPACK_SKIP_ROWS
, y
);
290 glCompressedTexSubImage2D(GL_TEXTURE_2D
, 0,
293 piglit_compressed_image_size(format
, w
, h
),
295 piglit_compressed_pixel_offset(format
, width
, 0, 0));
297 pass
= piglit_check_gl_error(GL_INVALID_OPERATION
) && pass
;
299 /* Try compressed subimage with size not a multiple of 4 -
306 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, x
);
307 glPixelStorei(GL_UNPACK_SKIP_ROWS
, y
);
308 glCompressedTexSubImage2D(GL_TEXTURE_2D
, 0,
311 piglit_compressed_image_size(format
, 4, 4),
313 piglit_compressed_pixel_offset(format
, width
, x
, y
));
315 /* Note, we can get either of these errors depending on the order
316 * in which glCompressedTexSubImage parameters are checked.
317 * INVALID_OPERATION for the bad size or INVALID_VALUE for the
318 * wrong compressed image size.
320 pass
= check_gl_error2(GL_INVALID_OPERATION
, GL_INVALID_VALUE
) && pass
;
322 /* Try compressed subimage with invalid offset - should not work */
327 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, 0);
328 glPixelStorei(GL_UNPACK_SKIP_ROWS
, 0);
329 glCompressedTexSubImage2D(GL_TEXTURE_2D
, 0,
332 piglit_compressed_image_size(format
, w
, h
),
334 piglit_compressed_pixel_offset(format
, width
, 0, 0));
336 pass
= piglit_check_gl_error(GL_INVALID_VALUE
) && pass
;
338 /* Try compressed subimage with too large of image - should not work */
343 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, x
);
344 glPixelStorei(GL_UNPACK_SKIP_ROWS
, y
);
345 glCompressedTexSubImage2D(GL_TEXTURE_2D
, 0,
348 piglit_compressed_image_size(format
, w
, h
),
350 piglit_compressed_pixel_offset(format
, width
, x
, y
));
352 pass
= piglit_check_gl_error(GL_INVALID_VALUE
) && pass
;
354 /* Try compressed subimage with different format - should not work */
355 if (format
== GL_COMPRESSED_RGB_S3TC_DXT1_EXT
)
356 format2
= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
;
358 format2
= GL_COMPRESSED_RGB_S3TC_DXT1_EXT
;
363 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, x
);
364 glPixelStorei(GL_UNPACK_SKIP_ROWS
, y
);
365 glCompressedTexSubImage2D(GL_TEXTURE_2D
, 0,
368 piglit_compressed_image_size(format2
, w
, h
),
370 piglit_compressed_pixel_offset(format2
, width
, x
, y
));
372 pass
= piglit_check_gl_error(GL_INVALID_OPERATION
) && pass
;
374 /* Try zero-sized subimage - should not be an error */
379 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, x
);
380 glPixelStorei(GL_UNPACK_SKIP_ROWS
, y
);
381 glCompressedTexSubImage2D(GL_TEXTURE_2D
, 0,
384 piglit_compressed_image_size(format
, w
, h
),
386 piglit_compressed_pixel_offset(format
, width
, x
, y
));
388 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
391 /* Try CompressedTexSubImage into level 1 (which is missing) */
396 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, x
);
397 glPixelStorei(GL_UNPACK_SKIP_ROWS
, y
);
398 glCompressedTexSubImage2D(GL_TEXTURE_2D
, 1,
401 piglit_compressed_image_size(format
, w
, h
),
403 piglit_compressed_pixel_offset(format
, width
, x
, y
));
405 pass
= piglit_check_gl_error(GL_INVALID_OPERATION
) && pass
;
407 /* Try CompressedTexImage of size zero - should not be an erorr */
410 glCompressedTexImage2D(GL_TEXTURE_2D
, 0, format
, w
, h
, 0,
411 piglit_compressed_image_size(format
, w
, h
),
414 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
416 /* Try CompressedTexImage with size which is a not a multiple of the
417 * block size - should not be an error
421 glCompressedTexImage2D(GL_TEXTURE_2D
, 0, format
, w
, h
, 0,
422 piglit_compressed_image_size(format
, w
, h
),
425 if (piglit_get_gl_version() < 20 &&
426 !piglit_is_extension_supported("GL_ARB_texture_non_power_of_two")) {
427 pass
= piglit_check_gl_error(GL_INVALID_VALUE
) && pass
;
429 /* Reload the original into the texture. */
432 glCompressedTexImage2D(GL_TEXTURE_2D
, 0, format
, w
, h
, 0,
433 piglit_compressed_image_size(format
, w
, h
),
437 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
438 pass
= check_rendering(width
, height
) && pass
;
440 free(compressed_image
);
444 glDeleteTextures(1, &tex
);
450 test_small_mipmap_level(void)
456 int format
= GL_COMPRESSED_RGB_S3TC_DXT1_EXT
;
458 memset(buf
, 0, sizeof(buf
));
460 glGenTextures(1, &tex
);
461 glBindTexture(GL_TEXTURE_2D
, tex
);
463 /* test sizes 1x1, 1x2, 2x1, .. 2x4, 4x4 */
464 for (width
= 1; width
<= 4; width
*= 2) {
465 for (height
= 1; height
<= 4; height
*= 2) {
467 glTexImage2D(GL_TEXTURE_2D
, 0, format
, width
, height
,
468 0, GL_RGBA
, GL_UNSIGNED_BYTE
, buf
);
470 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
472 /* Try TexSubImage of whole texture */
473 glTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, width
, height
,
474 GL_RGBA
, GL_UNSIGNED_BYTE
, buf
);
476 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
480 glDeleteTextures(1, &tex
);
487 test_non_power_of_two(void)
491 if (piglit_is_extension_supported("GL_ARB_texture_non_power_of_two")) {
494 int width
= 11, height
= 14;
495 int format
= GL_COMPRESSED_RGB_S3TC_DXT1_EXT
;
497 memset(buf
, 0, sizeof(buf
));
499 /* Setup initial texture */
500 glGenTextures(1, &tex
);
501 glBindTexture(GL_TEXTURE_2D
, tex
);
502 glTexImage2D(GL_TEXTURE_2D
, 0, format
, width
, height
, 0,
503 GL_RGBA
, GL_UNSIGNED_BYTE
, buf
);
505 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
507 /* Try TexSubImage of partial block on right edge */
508 glTexSubImage2D(GL_TEXTURE_2D
, 0,
509 width
-3, 0, /* position */
511 GL_RGBA
, GL_UNSIGNED_BYTE
, buf
);
513 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
515 /* Try TexSubImage of partial block on top edge */
516 glTexSubImage2D(GL_TEXTURE_2D
, 0,
517 0, height
-2, /* position */
519 GL_RGBA
, GL_UNSIGNED_BYTE
, buf
);
521 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
523 /* Try TexSubImage of larger partial block on right edge */
524 glTexSubImage2D(GL_TEXTURE_2D
, 0,
525 width
-3-4, 0, /* position */
527 GL_RGBA
, GL_UNSIGNED_BYTE
, buf
);
529 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
531 /* Try TexSubImage of larger partial block on top edge */
532 glTexSubImage2D(GL_TEXTURE_2D
, 0,
533 0, height
-2-4, /* position */
535 GL_RGBA
, GL_UNSIGNED_BYTE
, buf
);
537 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
539 glDeleteTextures(1, &tex
);
550 const int num_formats
= ARRAY_SIZE(s3tc_formats
);
551 const int width
= 128, height
= 64;
552 GLfloat
*image
= piglit_rgbw_image(GL_RGBA
, width
, height
,
553 GL_FALSE
, /* alpha */
554 GL_UNSIGNED_NORMALIZED
);
558 for (i
= 0; i
< num_formats
; i
++) {
559 const GLenum format
= s3tc_formats
[i
];
560 pass
= test_format(width
, height
, image
, format
) && pass
;
563 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
564 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, 0);
565 glPixelStorei(GL_UNPACK_SKIP_ROWS
, 0);
576 bool pass
= test_formats();
577 pass
= test_small_mipmap_level() && pass
;
578 pass
= test_non_power_of_two() && pass
;
580 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
585 piglit_init(int argc
, char **argv
)
587 piglit_require_extension("GL_EXT_texture_compression_s3tc");
589 #ifdef PIGLIT_USE_OPENGL_ES2
590 tex_program
= piglit_build_simple_program(vs_source
, fs_source
);
591 proj_loc
= glGetUniformLocation(tex_program
, "proj");