2 * Copyright (c) The Piglit project 2007
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, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
36 #include "piglit-util.h"
38 /* These texture coordinates should have 1 or -1 in the major axis selecting
39 * the face, and a nearly-1-or-negative-1 value in the other two coordinates
40 * which will be used to produce the s,t values used to sample that face's
43 GLfloat cube_face_texcoords
[6][4][3] = {
44 { /* GL_TEXTURE_CUBE_MAP_POSITIVE_X */
50 { /* GL_TEXTURE_CUBE_MAP_POSITIVE_Y */
56 { /* GL_TEXTURE_CUBE_MAP_POSITIVE_Z */
62 { /* GL_TEXTURE_CUBE_MAP_NEGATIVE_X */
68 { /* GL_TEXTURE_CUBE_MAP_NEGATIVE_Y */
74 { /* GL_TEXTURE_CUBE_MAP_NEGATIVE_Z */
82 const char *cube_face_names
[6] = {
91 const GLenum cube_face_targets
[6] = {
92 GL_TEXTURE_CUBE_MAP_POSITIVE_X
,
93 GL_TEXTURE_CUBE_MAP_POSITIVE_Y
,
94 GL_TEXTURE_CUBE_MAP_POSITIVE_Z
,
95 GL_TEXTURE_CUBE_MAP_NEGATIVE_X
,
96 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
,
97 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
,
100 GLint piglit_ARBfp_pass_through
= 0;
102 /** Returns the line in the program string given the character position. */
103 int FindLine(const char *program
, int position
)
106 for (i
= 0; i
< position
; i
++) {
107 if (program
[i
] == '0')
108 return -1; /* unknown line */
109 if (program
[i
] == '\n')
116 piglit_report_result(enum piglit_result result
)
120 if (result
== PIGLIT_SUCCESS
) {
121 printf("PIGLIT: {'result': 'pass' }\n");
124 } else if (result
== PIGLIT_SKIP
) {
125 printf("PIGLIT: {'result': 'skip' }\n");
128 } else if (result
== PIGLIT_WARN
) {
129 printf("PIGLIT: {'result': 'warn' }\n");
133 printf("PIGLIT: {'result': 'fail' }\n");
139 void piglit_require_extension(const char *name
)
141 if (!glutExtensionSupported(name
)) {
142 piglit_report_result(PIGLIT_SKIP
);
147 void piglit_require_not_extension(const char *name
)
149 if (glutExtensionSupported(name
)) {
150 piglit_report_result(PIGLIT_SKIP
);
156 * Read a pixel from the given location and compare its RGBA value to the
157 * given expected values.
159 * Print a log message if the color value deviates from the expected value.
160 * \return true if the color values match, false otherwise
162 int piglit_probe_pixel_rgba(int x
, int y
, const float* expected
)
169 glReadPixels(x
, y
, 1, 1, GL_RGBA
, GL_FLOAT
, probe
);
172 for(i
= 0; i
< 4; ++i
) {
173 delta
[i
] = probe
[i
] - expected
[i
];
174 if (fabs(delta
[i
]) > deltamax
)
175 deltamax
= fabs(delta
[i
]);
181 printf("Probe at (%i,%i)\n", x
, y
);
182 printf(" Expected: %f %f %f %f\n", expected
[0], expected
[1], expected
[2], expected
[3]);
183 printf(" Observed: %f %f %f %f\n", probe
[0], probe
[1], probe
[2], probe
[3]);
189 piglit_probe_rect_rgba(int x
, int y
, int w
, int h
, const float *expected
)
193 for (i
= 0; i
< w
; i
++) {
194 for (j
= 0; j
< h
; j
++) {
195 if (!piglit_probe_pixel_rgba(i
, j
, expected
))
204 * Read a pixel from the given location and compare its RGB value to the
205 * given expected values.
207 * Print a log message if the color value deviates from the expected value.
208 * \return true if the color values match, false otherwise
210 int piglit_probe_pixel_rgb(int x
, int y
, const float* expected
)
217 glReadPixels(x
, y
, 1, 1, GL_RGB
, GL_FLOAT
, probe
);
220 for(i
= 0; i
< 3; ++i
) {
221 delta
[i
] = probe
[i
] - expected
[i
];
222 if (fabs(delta
[i
]) > deltamax
)
223 deltamax
= fabs(delta
[i
]);
229 printf("Probe at (%i,%i)\n", x
, y
);
230 printf(" Expected: %f %f %f\n", expected
[0], expected
[1], expected
[2]);
231 printf(" Observed: %f %f %f\n", probe
[0], probe
[1], probe
[2]);
237 piglit_probe_rect_rgb(int x
, int y
, int w
, int h
, const float *expected
)
241 for (i
= 0; i
< w
; i
++) {
242 for (j
= 0; j
< h
; j
++) {
243 if (!piglit_probe_pixel_rgb(i
, j
, expected
))
252 * Read a pixel from the given location and compare its depth value to the
253 * given expected value.
255 * Print a log message if the depth value deviates from the expected value.
256 * \return true if the depth value matches, false otherwise
258 int piglit_probe_pixel_depth(int x
, int y
, float expected
)
263 glReadPixels(x
, y
, 1, 1, GL_DEPTH_COMPONENT
, GL_FLOAT
, &probe
);
265 delta
= probe
- expected
;
266 if (fabs(delta
) < 0.01)
269 printf("Probe at (%i,%i)\n", x
, y
);
270 printf(" Expected: %f\n", expected
);
271 printf(" Observed: %f\n", probe
);
277 * Read a texel from the given location and compare its RGBA value to the
278 * given expected values.
280 * Print a log message if the color value deviates from the expected value.
281 * \return true if the color values match, false otherwise
283 int piglit_probe_texel_rgba(int target
, int level
, int x
, int y
,
284 const float* expected
)
294 glGetTexLevelParameteriv(target
, level
, GL_TEXTURE_WIDTH
, &width
);
295 glGetTexLevelParameteriv(target
, level
, GL_TEXTURE_HEIGHT
, &height
);
296 buffer
= malloc(width
* height
* 4 * sizeof(GLfloat
));
298 glGetTexImage(target
, level
, GL_RGBA
, GL_FLOAT
, buffer
);
300 probe
= &buffer
[4 * ((width
* y
) + x
)];
302 for(i
= 0; i
< 4; ++i
) {
303 delta
[i
] = probe
[i
] - expected
[i
];
304 if (fabs(delta
[i
]) > deltamax
)
305 deltamax
= fabs(delta
[i
]);
308 if (deltamax
< 0.01) {
313 printf("Probe at (%i,%i)\n", x
, y
);
314 printf(" Expected: %f %f %f %f\n", expected
[0], expected
[1], expected
[2], expected
[3]);
315 printf(" Observed: %f %f %f %f\n", probe
[0], probe
[1], probe
[2], probe
[3]);
322 * Read a texel from the given location and compare its RGBA value to the
323 * given expected values.
325 * Print a log message if the color value deviates from the expected value.
326 * \return true if the color values match, false otherwise
328 int piglit_probe_texel_rgb(int target
, int level
, int x
, int y
,
329 const float* expected
)
339 glGetTexLevelParameteriv(target
, level
, GL_TEXTURE_WIDTH
, &width
);
340 glGetTexLevelParameteriv(target
, level
, GL_TEXTURE_HEIGHT
, &height
);
341 buffer
= malloc(width
* height
* 3 * sizeof(GLfloat
));
343 glGetTexImage(target
, level
, GL_RGB
, GL_FLOAT
, buffer
);
345 probe
= &buffer
[3 * ((width
* y
) + x
)];
347 for(i
= 0; i
< 3; ++i
) {
348 delta
[i
] = probe
[i
] - expected
[i
];
349 if (fabs(delta
[i
]) > deltamax
)
350 deltamax
= fabs(delta
[i
]);
353 if (deltamax
< 0.01) {
358 printf("Probe at (%i,%i)\n", x
, y
);
359 printf(" Expected: %f %f %f\n", expected
[0], expected
[1], expected
[2]);
360 printf(" Observed: %f %f %f\n", probe
[0], probe
[1], probe
[2]);
366 int piglit_use_fragment_program(void)
368 static const char source
[] =
370 "MOV result.color, fragment.color;\n"
375 if (!GLEW_ARB_fragment_program
)
378 piglit_ARBfp_pass_through
=
379 piglit_compile_program(GL_FRAGMENT_PROGRAM_ARB
, source
);
381 return (piglit_ARBfp_pass_through
!= 0);
384 void piglit_require_fragment_program(void)
386 if (!piglit_use_fragment_program()) {
387 printf("GL_ARB_fragment_program not supported.\n");
388 piglit_report_result(PIGLIT_SKIP
);
393 int piglit_use_vertex_program(void)
396 return GLEW_ARB_vertex_program
;
399 void piglit_require_vertex_program(void)
401 if (!piglit_use_vertex_program()) {
402 printf("GL_ARB_vertex_program not supported.\n");
403 piglit_report_result(PIGLIT_SKIP
);
408 GLuint
piglit_compile_program(GLenum target
, const char* text
)
413 glGenProgramsARB(1, &program
);
414 glBindProgramARB(target
, program
);
417 GL_PROGRAM_FORMAT_ASCII_ARB
,
419 (const GLubyte
*)text
);
420 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB
, &errorPos
);
421 if (glGetError() != GL_NO_ERROR
|| errorPos
!= -1) {
422 int l
= FindLine(text
, errorPos
);
425 fprintf(stderr
, "Compiler Error (pos=%d line=%d): %s\n",
427 (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB
));
429 for (a
=-10; a
<10; a
++)
433 if (errorPos
+a
>= strlen(text
))
435 fprintf(stderr
, "%c", text
[errorPos
+a
]);
437 fprintf(stderr
, "\nin program:\n%s", text
);
438 piglit_report_result(PIGLIT_FAILURE
);
440 if (!glIsProgramARB(program
)) {
441 fprintf(stderr
, "glIsProgramARB failed\n");
442 piglit_report_result(PIGLIT_FAILURE
);
449 * Convenience function to compile a GLSL shader from a file.
452 piglit_compile_shader(GLenum target
, char *filename
)
459 const char *source_dir
;
460 char filename_with_path
[FILENAME_MAX
];
462 source_dir
= getenv("PIGLIT_SOURCE_DIR");
463 if (source_dir
== NULL
) {
464 source_dir
= SOURCE_DIR
;
467 snprintf(filename_with_path
, FILENAME_MAX
- 1,
468 "%s/tests/%s", source_dir
, filename
);
469 filename_with_path
[FILENAME_MAX
- 1] = 0;
471 err
= stat(filename_with_path
, &st
);
473 fprintf(stderr
, "Couldn't stat program %s: %s\n", filename
, strerror(errno
));
474 fprintf(stderr
, "You can override the source dir by setting the PIGLIT_SOURCE_DIR environment variable.\n");
478 prog_string
= malloc(st
.st_size
+ 1);
479 if (prog_string
== NULL
) {
480 fprintf(stderr
, "malloc\n");
484 f
= fopen(filename_with_path
, "r");
486 fprintf(stderr
, "Couldn't open program: %s\n", strerror(errno
));
489 fread(prog_string
, 1, st
.st_size
, f
);
490 prog_string
[st
.st_size
] = '\0';
493 prog
= piglit_compile_shader_text(target
, prog_string
);
501 * Convenience function to compile a GLSL shader.
504 piglit_compile_shader_text(GLenum target
, const char *text
)
509 prog
= glCreateShader(target
);
510 glShaderSource(prog
, 1, (const GLchar
**) &text
, NULL
);
511 glCompileShader(prog
);
513 glGetShaderiv(prog
, GL_COMPILE_STATUS
, &ok
);
519 glGetShaderiv(prog
, GL_INFO_LOG_LENGTH
, &size
);
522 glGetShaderInfoLog(prog
, size
, NULL
, info
);
524 fprintf(stderr
, "Failed to compile %s: %s\n",
525 target
== GL_FRAGMENT_SHADER
? "FS" : "VS",
529 /* Enable this to get extra compilation info.
530 * Even if there's no compilation errors, the info
531 * log may have some remarks.
533 fprintf(stderr
, "Shader compiler warning: %s\n", info
);
542 piglit_link_check_status(GLint prog
)
548 glGetProgramiv(prog
, GL_LINK_STATUS
, &ok
);
550 glGetProgramiv(prog
, GL_INFO_LOG_LENGTH
, &size
);
553 glGetProgramInfoLog(prog
, size
, NULL
, info
);
555 fprintf(stderr
, "Failed to link: %s\n", info
);
558 /* Enable this to get extra linking info.
559 * Even if there's no link errors, the info log may
562 fprintf(stderr
, "Linker warning: %s\n", info
);
570 GLint
piglit_link_simple_program(GLint vs
, GLint fs
)
574 prog
= glCreateProgram();
576 glAttachShader(prog
, fs
);
578 glAttachShader(prog
, vs
);
581 piglit_link_check_status(prog
);
587 piglit_escape_exit_key(unsigned char key
, int x
, int y
)
600 * Convenience function to draw an axis-aligned rectangle.
603 piglit_draw_rect(float x
, float y
, float w
, float h
)
624 glVertexPointer(4, GL_FLOAT
, 0, verts
);
625 glEnableClientState(GL_VERTEX_ARRAY
);
627 glDrawArrays(GL_QUADS
, 0, 4);
629 glDisableClientState(GL_VERTEX_ARRAY
);
633 * Convenience function to draw an axis-aligned rectangle.
636 piglit_draw_rect_z(float z
, float x
, float y
, float w
, float h
)
657 glVertexPointer(4, GL_FLOAT
, 0, verts
);
658 glEnableClientState(GL_VERTEX_ARRAY
);
660 glDrawArrays(GL_QUADS
, 0, 4);
662 glDisableClientState(GL_VERTEX_ARRAY
);
666 * Convenience function to draw an axis-aligned rectangle
667 * with texture coordinates.
670 piglit_draw_rect_tex(float x
, float y
, float w
, float h
,
671 float tx
, float ty
, float tw
, float th
)
701 glVertexPointer(4, GL_FLOAT
, 0, verts
);
702 glTexCoordPointer(2, GL_FLOAT
, 0, tex
);
703 glEnableClientState(GL_VERTEX_ARRAY
);
704 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
706 glDrawArrays(GL_QUADS
, 0, 4);
708 glDisableClientState(GL_VERTEX_ARRAY
);
709 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
714 * Convenience function to configure projection matrix for window coordinates
717 piglit_ortho_projection(int w
, int h
, GLboolean push
)
719 /* Set up projection matrix so we can just draw using window
722 glMatrixMode(GL_PROJECTION
);
726 glOrtho(0, w
, 0, h
, -1, 1);
728 glMatrixMode(GL_MODELVIEW
);
736 * Generate a checkerboard texture
738 * \param tex Name of the texture to be used. If \c tex is
739 * zero, a new texture name will be generated.
740 * \param level Mipmap level the checkerboard should be written to
741 * \param width Width of the texture image
742 * \param height Height of the texture image
743 * \param horiz_square_size Size of each checkerboard tile along the X axis
744 * \param vert_square_size Size of each checkerboard tile along the Y axis
745 * \param black RGBA color to be used for "black" tiles
746 * \param white RGBA color to be used for "white" tiles
748 * A texture with alternating black and white squares in a checkerboard
749 * pattern is generated. The texture data is written to LOD \c level of
750 * the texture \c tex.
752 * If \c tex is zero, a new texture created. This texture will have several
753 * texture parameters set to non-default values:
755 * - S and T wrap modes will be set to \c GL_CLAMP_TO_BORDER.
756 * - Border color will be set to { 1.0, 0.0, 0.0, 1.0 }.
757 * - Min and mag filter will be set to \c GL_NEAREST.
760 * Name of the texture. In addition, this texture will be bound to the
761 * \c GL_TEXTURE_2D target of the currently active texture unit.
764 piglit_checkerboard_texture(GLuint tex
, unsigned level
,
765 unsigned width
, unsigned height
,
766 unsigned horiz_square_size
,
767 unsigned vert_square_size
,
768 const float *black
, const float *white
)
770 static const GLfloat border_color
[4] = { 1.0, 0.0, 0.0, 1.0 };
774 float *const tex_data
= malloc(width
* height
* (4 * sizeof(float)));
775 float *texel
= tex_data
;
777 for (i
= 0; i
< height
; i
++) {
778 const unsigned row
= i
/ vert_square_size
;
780 for (j
= 0; j
< width
; j
++) {
781 const unsigned col
= j
/ horiz_square_size
;
783 if ((row
^ col
) & 1) {
784 memcpy(texel
, white
, 4 * sizeof(float));
786 memcpy(texel
, black
, 4 * sizeof(float));
795 glGenTextures(1, &tex
);
797 glBindTexture(GL_TEXTURE_2D
, tex
);
798 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
800 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
,
802 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
,
804 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
,
806 glTexParameterfv(GL_TEXTURE_2D
, GL_TEXTURE_BORDER_COLOR
,
809 glBindTexture(GL_TEXTURE_2D
, tex
);
812 glTexImage2D(GL_TEXTURE_2D
, level
, GL_RGBA
, width
, height
, 0, GL_RGBA
,
819 * Generates a texture with the given internalFormat, w, h with a
820 * teximage of r, g, b w quadrants.
822 * Note that for compressed teximages, where the blocking would be
823 * problematic, we assign the whole layers at w == 4 to red, w == 2 to
824 * green, and w == 1 to blue.
827 piglit_rgbw_texture(GLenum format
, int w
, int h
, GLboolean mip
)
830 int size
, x
, y
, level
;
832 float red
[4] = {1.0, 0.0, 0.0, 1.0};
833 float green
[4] = {0.0, 1.0, 0.0, 1.0};
834 float blue
[4] = {0.0, 0.0, 1.0, 1.0};
835 float white
[4] = {1.0, 1.0, 1.0, 1.0};
837 glGenTextures(1, &tex
);
838 glBindTexture(GL_TEXTURE_2D
, tex
);
839 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
840 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
842 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
,
844 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
845 GL_LINEAR_MIPMAP_NEAREST
);
847 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
,
849 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
852 data
= malloc(w
* h
* 4 * sizeof(GLfloat
));
854 /* XXX: Do we want non-square textures? Surely some day. */
857 for (level
= 0, size
= w
; size
> 0; level
++, size
>>= 1) {
858 for (y
= 0; y
< size
; y
++) {
859 for (x
= 0; x
< size
; x
++) {
862 if (x
< size
/ 2 && y
< size
/ 2)
864 else if (y
< size
/ 2)
866 else if (x
< size
/ 2)
872 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT
:
873 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
:
874 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
:
875 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
:
876 case GL_COMPRESSED_RGB_FXT1_3DFX
:
877 case GL_COMPRESSED_RGBA_FXT1_3DFX
:
889 memcpy(data
+ (y
* size
+ x
) * 4, color
,
893 glTexImage2D(GL_TEXTURE_2D
, level
,
896 GL_RGBA
, GL_FLOAT
, data
);
905 #ifndef HAVE_STRCHRNUL
906 char *strchrnul(const char *s
, int c
)
908 char *t
= strchr(s
, c
);
910 return (t
== NULL
) ? (s
+ strlen(s
)) : t
;