2 * Copyright © 2010 Intel Corporation
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
21 * DEALINGS IN THE SOFTWARE.
34 #include "piglit-util.h"
36 #ifndef GL_GEOMETRY_SHADER_ARB
37 #define GL_GEOMETRY_SHADER_ARB 0x8DD9
40 int piglit_width
= 250, piglit_height
= 250;
41 int piglit_window_mode
= GLUT_RGB
| GLUT_ALPHA
| GLUT_DOUBLE
;
43 static float gl_version
= 0.0;
44 static float glsl_version
= 0.0;
46 const char *path
= NULL
;
47 const char *test_start
= NULL
;
49 GLuint vertex_shaders
[256];
50 unsigned num_vertex_shaders
= 0;
51 GLuint geometry_shaders
[256];
52 unsigned num_geometry_shaders
= 0;
53 GLuint fragment_shaders
[256];
54 unsigned num_fragment_shaders
= 0;
57 * List of strings loaded from files
59 * Some test script sections, such as "[vertex shader file]", can supply shader
60 * source code from multiple disk files. This array stores those strings.
62 char *shader_strings
[256];
63 GLsizei shader_string_sizes
[256];
64 unsigned num_shader_strings
= 0;
94 compile_glsl(GLenum target
, bool release_text
)
96 GLuint shader
= glCreateShader(target
);
100 glShaderSource(shader
, num_shader_strings
,
101 (const GLchar
**) shader_strings
, shader_string_sizes
);
103 glCompileShader(shader
);
105 glGetShaderiv(shader
, GL_COMPILE_STATUS
, &ok
);
111 glGetShaderiv(shader
, GL_INFO_LOG_LENGTH
, &size
);
114 glGetShaderInfoLog(shader
, size
, NULL
, info
);
116 fprintf(stderr
, "Failed to compile %s: %s\n",
117 target
== GL_FRAGMENT_SHADER
? "FS" : "VS",
121 piglit_report_result(PIGLIT_FAILURE
);
125 for (i
= 0; i
< num_shader_strings
; i
++)
126 free(shader_strings
[i
]);
130 case GL_VERTEX_SHADER
:
131 vertex_shaders
[num_vertex_shaders
] = shader
;
132 num_vertex_shaders
++;
134 case GL_GEOMETRY_SHADER_ARB
:
135 geometry_shaders
[num_geometry_shaders
] = shader
;
136 num_geometry_shaders
++;
138 case GL_FRAGMENT_SHADER
:
139 fragment_shaders
[num_fragment_shaders
] = shader
;
140 num_fragment_shaders
++;
147 * Copy a string until either whitespace or the end of the string
150 strcpy_to_space(char *dst
, const char *src
)
152 while (!isspace(*src
) && (*src
!= '\0'))
161 * Skip over whitespace upto the end of line
164 eat_whitespace(const char *src
)
166 while (isspace(*src
) && (*src
!= '\n'))
174 * Skip over non-whitespace upto the end of line
177 eat_text(const char *src
)
179 while (!isspace(*src
) && (*src
!= '\0'))
187 * Compare two values given a specified comparison operator
190 compare(float ref
, float value
, enum comparison cmp
)
193 case equal
: return value
== ref
;
194 case not_equal
: return value
!= ref
;
195 case less
: return value
< ref
;
196 case greater_equal
: return value
>= ref
;
197 case greater
: return value
> ref
;
198 case less_equal
: return value
<= ref
;
201 assert(!"Should not get here.");
206 * Get the string representation of a comparison operator
209 comparison_string(enum comparison cmp
)
212 case equal
: return "==";
213 case not_equal
: return "!=";
214 case less
: return "<";
215 case greater_equal
: return ">=";
216 case greater
: return ">";
217 case less_equal
: return "<=";
220 assert(!"Should not get here.");
225 load_shader_file(const char *line
)
227 GLsizei
*const size
= &shader_string_sizes
[num_shader_strings
];
231 strcpy_to_space(buf
, line
);
233 text
= piglit_load_text_file(buf
, (unsigned *) size
);
234 if ((text
== NULL
) && (path
!= NULL
)) {
235 const size_t len
= strlen(path
);
237 memcpy(buf
, path
, len
);
239 strcpy_to_space(&buf
[len
+ 1], line
);
241 text
= piglit_load_text_file(buf
, (unsigned *) size
);
245 strcpy_to_space(buf
, line
);
247 printf("could not load file \"%s\"\n", buf
);
248 piglit_report_result(PIGLIT_FAILURE
);
251 shader_strings
[num_shader_strings
] = text
;
252 num_shader_strings
++;
257 * Parse a binary comparison operator and return the matching token
260 process_comparison(const char *src
, enum comparison
*cmp
)
281 *cmp
= greater_equal
;
295 strncpy(buf
, src
, sizeof(buf
));
296 buf
[sizeof(buf
) - 1] = '\0';
297 printf("invalid comparison in test script:\n%s\n", buf
);
298 piglit_report_result(PIGLIT_FAILURE
);
300 /* Won't get here. */
306 * Parse and check a line from the requirement section of the test
309 process_requirement(const char *line
)
313 /* There are three types of requirements that a test can currently
316 * * Require that some GL extension be supported
317 * * Require some particular versions of GL
318 * * Require some particular versions of GLSL
320 * The tests for GL and GLSL versions can be equal, not equal,
321 * less, less-or-equal, greater, or greater-or-equal. Extension tests
322 * can also require that a particular extension not be supported by
323 * prepending ! to the extension name.
325 if (strncmp("GL_", line
, 3) == 0) {
326 strcpy_to_space(buffer
, line
);
327 piglit_require_extension(buffer
);
328 } else if (strncmp("!GL_", line
, 4) == 0) {
329 strcpy_to_space(buffer
, line
+ 1);
330 piglit_require_not_extension(buffer
);
331 } else if (strncmp("GLSL", line
, 4) == 0) {
335 line
= eat_whitespace(line
+ 4);
337 line
= process_comparison(line
, &cmp
);
339 version
= strtod(line
, NULL
);
340 if (!compare(version
, glsl_version
, cmp
)) {
341 printf("Test requires GLSL version %s %.1f. "
342 "Actual version is %.1f.\n",
343 comparison_string(cmp
),
346 piglit_report_result(PIGLIT_SKIP
);
348 } else if (strncmp("GL", line
, 2) == 0) {
352 line
= eat_whitespace(line
+ 2);
354 line
= process_comparison(line
, &cmp
);
356 version
= strtod(line
, NULL
);
357 if (!compare(version
, gl_version
, cmp
)) {
358 printf("Test requires GL version %s %.1f. "
359 "Actual version is %.1f.\n",
360 comparison_string(cmp
),
363 piglit_report_result(PIGLIT_SKIP
);
370 leave_state(enum states state
, const char *line
)
380 shader_string_sizes
[0] = line
- shader_strings
[0];
381 num_shader_strings
= 1;
382 compile_glsl(GL_VERTEX_SHADER
, false);
385 case vertex_shader_file
:
386 compile_glsl(GL_VERTEX_SHADER
, true);
392 case geometry_shader
:
395 case geometry_program
:
398 case fragment_shader
:
399 shader_string_sizes
[0] = line
- shader_strings
[0];
400 num_shader_strings
= 1;
401 compile_glsl(GL_FRAGMENT_SHADER
, false);
404 case fragment_shader_file
:
405 compile_glsl(GL_FRAGMENT_SHADER
, true);
408 case fragment_program
:
415 assert(!"Not yet supported.");
421 link_and_use_shaders(void)
427 if ((num_vertex_shaders
== 0)
428 && (num_fragment_shaders
== 0)
429 && (num_geometry_shaders
== 0))
432 prog
= glCreateProgram();
434 for (i
= 0; i
< num_vertex_shaders
; i
++) {
435 glAttachShader(prog
, vertex_shaders
[i
]);
438 for (i
= 0; i
< num_geometry_shaders
; i
++) {
439 glAttachShader(prog
, geometry_shaders
[i
]);
442 for (i
= 0; i
< num_fragment_shaders
; i
++) {
443 glAttachShader(prog
, fragment_shaders
[i
]);
448 for (i
= 0; i
< num_vertex_shaders
; i
++) {
449 glDeleteShader(vertex_shaders
[i
]);
452 for (i
= 0; i
< num_geometry_shaders
; i
++) {
453 glDeleteShader(geometry_shaders
[i
]);
456 for (i
= 0; i
< num_fragment_shaders
; i
++) {
457 glDeleteShader(fragment_shaders
[i
]);
460 glGetProgramiv(prog
, GL_LINK_STATUS
, &ok
);
465 glGetProgramiv(prog
, GL_INFO_LOG_LENGTH
, &size
);
468 glGetProgramInfoLog(prog
, size
, NULL
, info
);
470 fprintf(stderr
, "Failed to link:\n%s\n",
474 piglit_report_result(PIGLIT_FAILURE
);
484 printf("GL error after linking program: 0x%04x\n", err
);
486 glGetProgramiv(prog
, GL_INFO_LOG_LENGTH
, &size
);
489 glGetProgramInfoLog(prog
, size
, NULL
, info
);
490 fprintf(stderr
, "Info log: %s\n", info
);
492 piglit_report_result(PIGLIT_FAILURE
);
498 process_test_script(const char *script_name
)
501 char *text
= piglit_load_text_file(script_name
, &text_size
);
502 enum states state
= none
;
503 const char *line
= text
;
506 printf("could not read file \"%s\"\n", script_name
);
507 piglit_report_result(PIGLIT_FAILURE
);
510 while (line
[0] != '\0') {
511 if (line
[0] == '[') {
512 leave_state(state
, line
);
514 if (strncmp(line
, "[require]", 9) == 0) {
515 state
= requirements
;
516 } else if (strncmp(line
, "[vertex shader]", 15) == 0) {
517 state
= vertex_shader
;
518 shader_strings
[0] = NULL
;
519 } else if (strncmp(line
, "[vertex shader file]", 20) == 0) {
520 state
= vertex_shader_file
;
521 shader_strings
[0] = NULL
;
522 num_shader_strings
= 0;
523 } else if (strncmp(line
, "[fragment shader]", 17) == 0) {
524 state
= fragment_shader
;
525 shader_strings
[0] = NULL
;
526 } else if (strncmp(line
, "[fragment shader file]", 22) == 0) {
527 state
= fragment_shader_file
;
528 shader_strings
[0] = NULL
;
529 num_shader_strings
= 0;
530 } else if (strncmp(line
, "[test]", 6) == 0) {
531 test_start
= strchrnul(line
, '\n');
532 if (test_start
[0] != '\0')
542 process_requirement(line
);
547 case geometry_shader
:
548 case geometry_program
:
549 case fragment_shader
:
550 case fragment_program
:
551 if (shader_strings
[0] == NULL
)
552 shader_strings
[0] = (char *) line
;
555 case vertex_shader_file
:
556 case geometry_shader_file
:
557 case fragment_shader_file
:
558 line
= eat_whitespace(line
);
559 if ((line
[0] != '\n') && (line
[0] != '#'))
560 load_shader_file(line
);
568 line
= strchrnul(line
, '\n');
573 leave_state(state
, line
);
578 get_floats(const char *line
, float *f
, unsigned count
)
582 for (i
= 0; i
< count
; i
++)
583 f
[i
] = strtod(line
, (char **) &line
);
588 set_uniform(const char *line
)
596 glGetIntegerv(GL_CURRENT_PROGRAM
, (GLint
*) &prog
);
598 type
= eat_whitespace(line
);
599 line
= eat_text(type
);
601 line
= strcpy_to_space(name
, eat_whitespace(line
));
602 loc
= glGetUniformLocation(prog
, name
);
604 printf("cannot get location of uniform \"%s\"\n",
606 piglit_report_result(PIGLIT_FAILURE
);
609 if (strncmp("float", type
, 5) == 0) {
610 get_floats(line
, f
, 1);
611 glUniform1fv(loc
, 1, f
);
613 } else if (strncmp("int", type
, 3) == 0) {
614 int val
= atoi(line
);
615 glUniform1i(loc
, val
);
617 } else if (strncmp("vec", type
, 3) == 0) {
620 get_floats(line
, f
, 2);
621 glUniform2fv(loc
, 1, f
);
624 get_floats(line
, f
, 3);
625 glUniform3fv(loc
, 1, f
);
628 get_floats(line
, f
, 4);
629 glUniform4fv(loc
, 1, f
);
634 strcpy_to_space(name
, type
);
635 printf("unknown uniform type \"%s\"", name
);
636 piglit_report_result(PIGLIT_FAILURE
);
642 string_match(const char *string
, const char *line
)
644 return (strncmp(string
, line
, strlen(string
)) == 0);
652 GLbitfield clear_bits
= 0;
654 if (test_start
== NULL
)
655 return PIGLIT_SUCCESS
;
659 while (line
[0] != '\0') {
661 int x
, y
, w
, h
, tex
, level
;
663 line
= eat_whitespace(line
);
665 if (string_match("clear color", line
)) {
666 get_floats(line
+ 11, c
, 4);
667 glClearColor(c
[0], c
[1], c
[2], c
[3]);
668 clear_bits
|= GL_COLOR_BUFFER_BIT
;
669 } else if (string_match("clear", line
)) {
671 } else if (string_match("draw rect", line
)) {
672 get_floats(line
+ 9, c
, 4);
673 piglit_draw_rect(c
[0], c
[1], c
[2], c
[3]);
674 } else if (string_match("ortho", line
)) {
675 piglit_ortho_projection(piglit_width
, piglit_height
,
677 } else if (string_match("probe rgba", line
)) {
678 get_floats(line
+ 10, c
, 6);
679 if (!piglit_probe_pixel_rgba((int) c
[0], (int) c
[1],
683 } else if (sscanf(line
,
684 "relative probe rgba ( %f , %f ) "
685 "( %f , %f , %f , %f )",
687 c
+ 2, c
+ 3, c
+ 4, c
+ 5) == 6) {
688 x
= c
[0] * piglit_width
;
689 y
= c
[1] * piglit_width
;
690 if (x
>= piglit_width
)
691 x
= piglit_width
- 1;
692 if (y
>= piglit_height
)
693 y
= piglit_height
- 1;
695 if (!piglit_probe_pixel_rgba(x
, y
, &c
[2])) {
698 } else if (string_match("probe rgb", line
)) {
699 get_floats(line
+ 9, c
, 5);
700 if (!piglit_probe_pixel_rgb((int) c
[0], (int) c
[1],
704 } else if (sscanf(line
,
705 "relative probe rgb ( %f , %f ) "
708 c
+ 2, c
+ 3, c
+ 4) == 5) {
709 x
= c
[0] * piglit_width
;
710 y
= c
[1] * piglit_width
;
711 if (x
>= piglit_width
)
712 x
= piglit_width
- 1;
713 if (y
>= piglit_height
)
714 y
= piglit_height
- 1;
716 if (!piglit_probe_pixel_rgb(x
, y
, &c
[2])) {
719 } else if (string_match("probe all rgba", line
)) {
720 get_floats(line
+ 14, c
, 4);
721 for (y
= 0; y
< piglit_height
; y
++ ) {
722 for (x
= 0; x
< piglit_width
; x
++) {
724 piglit_probe_pixel_rgba(x
, y
,
728 } else if (string_match("probe all rgb", line
)) {
729 get_floats(line
+ 13, c
, 3);
730 for (y
= 0; y
< piglit_height
; y
++ ) {
731 for (x
= 0; x
< piglit_width
; x
++) {
733 piglit_probe_pixel_rgb(x
, y
,
737 } else if (sscanf(line
,
738 "texture rgbw %d ( %d , %d )",
739 &tex
, &w
, &h
) == 3) {
740 glActiveTexture(GL_TEXTURE0
+ tex
);
741 piglit_rgbw_texture(GL_RGBA
, w
, h
, GL_FALSE
);
742 glEnable(GL_TEXTURE_2D
);
743 } else if (sscanf(line
,
744 "texture checkerboard %d %d ( %d , %d ) "
745 "( %f , %f , %f , %f ) "
746 "( %f , %f , %f , %f )",
747 &tex
, &level
, &w
, &h
,
748 c
+ 0, c
+ 1, c
+ 2, c
+ 3,
749 c
+ 4, c
+ 5, c
+ 6, c
+ 7) == 12) {
750 glActiveTexture(GL_TEXTURE0
+ tex
);
751 piglit_checkerboard_texture(0, level
,
755 glEnable(GL_TEXTURE_2D
);
756 } else if (string_match("uniform", line
)) {
757 set_uniform(line
+ 7);
758 } else if ((line
[0] != '\n') && (line
[0] != '\0')
759 && (line
[0] != '#')) {
760 printf("unknown command \"%s\"", line
);
761 piglit_report_result(PIGLIT_FAILURE
);
764 line
= strchrnul(line
, '\n');
771 if (piglit_automatic
) {
772 /* Free our resources, useful for valgrinding. */
773 glDeleteProgram(prog
);
777 return pass
? PIGLIT_SUCCESS
: PIGLIT_FAILURE
;
782 piglit_init(int argc
, char **argv
)
784 const char *glsl_version_string
;
786 gl_version
= strtod((char *) glGetString(GL_VERSION
), NULL
);
788 glsl_version_string
= (char *)
789 glGetString(GL_SHADING_LANGUAGE_VERSION
);
790 glsl_version
= (glsl_version_string
== NULL
)
791 ? 0.0 : strtod(glsl_version_string
, NULL
);
796 process_test_script(argv
[1]);
797 link_and_use_shaders();