Add more structure constructor tests.
[piglit/hramrach.git] / tests / shaders / shader_runner.c
blobbb96379473e3104373193fd15499277675e11a8a
1 /*
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
13 * Software.
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.
24 #define _GNU_SOURCE
25 #if defined(_MSC_VER)
26 #define bool BOOL
27 #define true 1
28 #define false 0
29 #else
30 #include <stdbool.h>
31 #endif
32 #include <string.h>
33 #include <ctype.h>
34 #include "piglit-util.h"
36 #ifndef GL_GEOMETRY_SHADER_ARB
37 #define GL_GEOMETRY_SHADER_ARB 0x8DD9
38 #endif
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;
56 /**
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;
65 GLuint prog;
67 enum states {
68 none = 0,
69 requirements,
70 vertex_shader,
71 vertex_shader_file,
72 vertex_program,
73 geometry_shader,
74 geometry_shader_file,
75 geometry_program,
76 fragment_shader,
77 fragment_shader_file,
78 fragment_program,
79 test,
83 enum comparison {
84 equal = 0,
85 not_equal,
86 less,
87 greater_equal,
88 greater,
89 less_equal
93 void
94 compile_glsl(GLenum target, bool release_text)
96 GLuint shader = glCreateShader(target);
97 GLint ok;
98 unsigned i;
100 glShaderSource(shader, num_shader_strings,
101 (const GLchar **) shader_strings, shader_string_sizes);
103 glCompileShader(shader);
105 glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
107 if (!ok) {
108 GLchar *info;
109 GLint size;
111 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
112 info = malloc(size);
114 glGetShaderInfoLog(shader, size, NULL, info);
116 fprintf(stderr, "Failed to compile %s: %s\n",
117 target == GL_FRAGMENT_SHADER ? "FS" : "VS",
118 info);
120 free(info);
121 piglit_report_result(PIGLIT_FAILURE);
124 if (release_text) {
125 for (i = 0; i < num_shader_strings; i++)
126 free(shader_strings[i]);
129 switch (target) {
130 case GL_VERTEX_SHADER:
131 vertex_shaders[num_vertex_shaders] = shader;
132 num_vertex_shaders++;
133 break;
134 case GL_GEOMETRY_SHADER_ARB:
135 geometry_shaders[num_geometry_shaders] = shader;
136 num_geometry_shaders++;
137 break;
138 case GL_FRAGMENT_SHADER:
139 fragment_shaders[num_fragment_shaders] = shader;
140 num_fragment_shaders++;
141 break;
147 * Copy a string until either whitespace or the end of the string
149 const char *
150 strcpy_to_space(char *dst, const char *src)
152 while (!isspace(*src) && (*src != '\0'))
153 *(dst++) = *(src++);
155 *dst = '\0';
156 return src;
161 * Skip over whitespace upto the end of line
163 const char *
164 eat_whitespace(const char *src)
166 while (isspace(*src) && (*src != '\n'))
167 src++;
169 return src;
174 * Skip over non-whitespace upto the end of line
176 const char *
177 eat_text(const char *src)
179 while (!isspace(*src) && (*src != '\0'))
180 src++;
182 return src;
187 * Compare two values given a specified comparison operator
189 bool
190 compare(float ref, float value, enum comparison cmp)
192 switch (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
208 const char *
209 comparison_string(enum comparison cmp)
211 switch (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.");
224 void
225 load_shader_file(const char *line)
227 GLsizei *const size = &shader_string_sizes[num_shader_strings];
228 char buf[256];
229 char *text;
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);
238 buf[len] = '/';
239 strcpy_to_space(&buf[len + 1], line);
241 text = piglit_load_text_file(buf, (unsigned *) size);
244 if (text == NULL) {
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
259 const char *
260 process_comparison(const char *src, enum comparison *cmp)
262 char buf[32];
264 switch (src[0]) {
265 case '=':
266 if (src[1] == '=') {
267 *cmp = equal;
268 return src + 2;
270 break;
271 case '<':
272 if (src[1] == '=') {
273 *cmp = less_equal;
274 return src + 2;
275 } else {
276 *cmp = less;
277 return src + 1;
279 case '>':
280 if (src[1] == '=') {
281 *cmp = greater_equal;
282 return src + 2;
283 } else {
284 *cmp = greater;
285 return src + 1;
287 case '!':
288 if (src[1] == '=') {
289 *cmp = not_equal;
290 return src + 2;
292 break;
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. */
301 return NULL;
306 * Parse and check a line from the requirement section of the test
308 void
309 process_requirement(const char *line)
311 char buffer[4096];
313 /* There are three types of requirements that a test can currently
314 * have:
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) {
332 enum comparison cmp;
333 float version;
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),
344 version,
345 glsl_version);
346 piglit_report_result(PIGLIT_SKIP);
348 } else if (strncmp("GL", line, 2) == 0) {
349 enum comparison cmp;
350 float version;
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),
361 version,
362 gl_version);
363 piglit_report_result(PIGLIT_SKIP);
369 void
370 leave_state(enum states state, const char *line)
372 switch (state) {
373 case none:
374 break;
376 case requirements:
377 break;
379 case vertex_shader:
380 shader_string_sizes[0] = line - shader_strings[0];
381 num_shader_strings = 1;
382 compile_glsl(GL_VERTEX_SHADER, false);
383 break;
385 case vertex_shader_file:
386 compile_glsl(GL_VERTEX_SHADER, true);
387 break;
389 case vertex_program:
390 break;
392 case geometry_shader:
393 break;
395 case geometry_program:
396 break;
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);
402 break;
404 case fragment_shader_file:
405 compile_glsl(GL_FRAGMENT_SHADER, true);
406 break;
408 case fragment_program:
409 break;
411 case test:
412 break;
414 default:
415 assert(!"Not yet supported.");
420 void
421 link_and_use_shaders(void)
423 unsigned i;
424 GLenum err;
425 GLint ok;
427 if ((num_vertex_shaders == 0)
428 && (num_fragment_shaders == 0)
429 && (num_geometry_shaders == 0))
430 return;
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]);
446 glLinkProgram(prog);
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);
461 if (!ok) {
462 GLchar *info;
463 GLint size;
465 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
466 info = malloc(size);
468 glGetProgramInfoLog(prog, size, NULL, info);
470 fprintf(stderr, "Failed to link:\n%s\n",
471 info);
473 free(info);
474 piglit_report_result(PIGLIT_FAILURE);
477 glUseProgram(prog);
479 err = glGetError();
480 if (err) {
481 GLchar *info;
482 GLint size;
484 printf("GL error after linking program: 0x%04x\n", err);
486 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
487 info = malloc(size);
489 glGetProgramInfoLog(prog, size, NULL, info);
490 fprintf(stderr, "Info log: %s\n", info);
492 piglit_report_result(PIGLIT_FAILURE);
497 void
498 process_test_script(const char *script_name)
500 unsigned text_size;
501 char *text = piglit_load_text_file(script_name, &text_size);
502 enum states state = none;
503 const char *line = text;
505 if (line == NULL) {
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')
533 test_start++;
534 return;
536 } else {
537 switch (state) {
538 case none:
539 break;
541 case requirements:
542 process_requirement(line);
543 break;
545 case vertex_shader:
546 case vertex_program:
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;
553 break;
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);
561 break;
563 case test:
564 break;
568 line = strchrnul(line, '\n');
569 if (line[0] != '\0')
570 line++;
573 leave_state(state, line);
577 void
578 get_floats(const char *line, float *f, unsigned count)
580 unsigned i;
582 for (i = 0; i < count; i++)
583 f[i] = strtod(line, (char **) &line);
587 void
588 set_uniform(const char *line)
590 char name[512];
591 float f[16];
592 GLuint prog;
593 GLint loc;
594 const char *type;
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);
603 if (loc < 0) {
604 printf("cannot get location of uniform \"%s\"\n",
605 name);
606 piglit_report_result(PIGLIT_FAILURE);
609 if (strncmp("float", type, 5) == 0) {
610 get_floats(line, f, 1);
611 glUniform1fv(loc, 1, f);
612 return;
613 } else if (strncmp("int", type, 3) == 0) {
614 int val = atoi(line);
615 glUniform1i(loc, val);
616 return;
617 } else if (strncmp("vec", type, 3) == 0) {
618 switch (type[3]) {
619 case '2':
620 get_floats(line, f, 2);
621 glUniform2fv(loc, 1, f);
622 return;
623 case '3':
624 get_floats(line, f, 3);
625 glUniform3fv(loc, 1, f);
626 return;
627 case '4':
628 get_floats(line, f, 4);
629 glUniform4fv(loc, 1, f);
630 return;
634 strcpy_to_space(name, type);
635 printf("unknown uniform type \"%s\"", name);
636 piglit_report_result(PIGLIT_FAILURE);
638 return;
641 static GLboolean
642 string_match(const char *string, const char *line)
644 return (strncmp(string, line, strlen(string)) == 0);
647 enum piglit_result
648 piglit_display(void)
650 const char *line;
651 bool pass = true;
652 GLbitfield clear_bits = 0;
654 if (test_start == NULL)
655 return PIGLIT_SUCCESS;
658 line = test_start;
659 while (line[0] != '\0') {
660 float c[32];
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)) {
670 glClear(clear_bits);
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,
676 GL_FALSE);
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],
680 & c[2])) {
681 pass = false;
683 } else if (sscanf(line,
684 "relative probe rgba ( %f , %f ) "
685 "( %f , %f , %f , %f )",
686 c + 0, c + 1,
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])) {
696 pass = false;
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],
701 & c[2])) {
702 pass = false;
704 } else if (sscanf(line,
705 "relative probe rgb ( %f , %f ) "
706 "( %f , %f , %f )",
707 c + 0, c + 1,
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])) {
717 pass = false;
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++) {
723 pass = pass &&
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++) {
732 pass = pass &&
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,
752 w, h,
753 w / 2, h / 2,
754 c + 0, c + 4);
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');
765 if (line[0] != '\0')
766 line++;
769 glutSwapBuffers();
771 if (piglit_automatic) {
772 /* Free our resources, useful for valgrinding. */
773 glDeleteProgram(prog);
774 glUseProgram(0);
777 return pass ? PIGLIT_SUCCESS : PIGLIT_FAILURE;
781 void
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);
793 if (argc > 2)
794 path = argv[2];
796 process_test_script(argv[1]);
797 link_and_use_shaders();