2 * Copyright © 2009 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 DEALINGS
24 * Eric Anholt <eric@anholt.net>
28 /** @file glslparsertest.c
30 * Tests that compiling (but not linking or drawing with) a given
31 * shader either succeeds or fails as expected.
36 #include "piglit-util-gl.h"
38 #define COMPAT_FLAG (1u << 31)
40 static unsigned parse_glsl_version_number(const char *str
);
41 static int process_options(int argc
, char **argv
);
43 PIGLIT_GL_TEST_CONFIG_BEGIN
45 argc
= process_options(argc
, argv
);
47 const unsigned int version
48 = parse_glsl_version_number(argv
[3]);
49 const bool compat
= !!(version
& COMPAT_FLAG
);
50 const unsigned int int_version
= version
& ~COMPAT_FLAG
;
51 switch (int_version
) {
52 /* This is a hack to support es
54 * This works because version 1.00, 3.00, 3.10, 3.20 (even
55 * though 3.x should include "es") are unique to GLES, there is
56 * no desktop OpenGL shader language 1.00, 3.00, 3.10, or 3.20
59 config
.supports_gl_compat_version
= 10;
60 config
.supports_gl_es_version
= 20;
63 config
.supports_gl_compat_version
= 10;
64 config
.supports_gl_es_version
= 30;
67 config
.supports_gl_compat_version
= 10;
68 config
.supports_gl_es_version
= 31;
71 config
.supports_gl_compat_version
= 10;
72 config
.supports_gl_es_version
= 32;
75 const unsigned int gl_version
76 = required_gl_version_from_glsl_version(int_version
);
77 config
.supports_gl_compat_version
= gl_version
;
78 if (gl_version
< 31 || compat
)
79 config
.supports_gl_core_version
= 0;
81 config
.supports_gl_core_version
= gl_version
;
86 config
.supports_gl_compat_version
= 10;
87 config
.supports_gl_es_version
= 20;
90 config
.window_width
= 200;
91 config
.window_height
= 100;
92 config
.window_visual
= PIGLIT_GL_VISUAL_DOUBLE
| PIGLIT_GL_VISUAL_RGB
;
94 PIGLIT_GL_TEST_CONFIG_END
96 static char *filename
;
97 static int expected_pass
;
98 static int gl_version_times_10
= 0;
99 static int check_link
= 0;
100 static unsigned requested_version
= 110;
101 static bool test_requires_geometry_shader4
= false;
102 static bool dummy_shader_include
= false;
103 static char *shader_include_path
= NULL
;
106 get_shader_compile_status(GLuint shader
)
110 #if defined PIGLIT_USE_OPENGL
111 if (gl_version_times_10
>= 20) {
112 glGetShaderiv(shader
, GL_COMPILE_STATUS
, &status
);
114 glGetObjectParameterivARB(shader
, GL_OBJECT_COMPILE_STATUS_ARB
, &status
);
116 #elif defined PIGLIT_USE_OPENGL_ES2
117 glGetShaderiv(shader
, GL_COMPILE_STATUS
, &status
);
126 get_shader_info_log_length(GLuint shader
)
130 #if defined PIGLIT_USE_OPENGL
131 if (gl_version_times_10
>= 20) {
132 glGetShaderiv(shader
, GL_INFO_LOG_LENGTH
, &length
);
134 glGetObjectParameterivARB(shader
, GL_OBJECT_INFO_LOG_LENGTH_ARB
, &length
);
136 #elif defined PIGLIT_USE_OPENGL_ES2
137 glGetShaderiv(shader
, GL_INFO_LOG_LENGTH
, &length
);
146 get_shader_name(GLenum type
)
149 case GL_VERTEX_SHADER
:
151 case GL_TESS_CONTROL_SHADER
:
152 return "tessellation control";
153 case GL_TESS_EVALUATION_SHADER
:
154 return "tessellation evaluation";
155 case GL_GEOMETRY_SHADER
:
157 case GL_FRAGMENT_SHADER
:
159 case GL_COMPUTE_SHADER
:
162 fprintf(stderr
, "Unexpected type in get_shader_name()\n");
163 piglit_report_result(PIGLIT_FAIL
);
169 glsl_is_es(int version
)
171 if (version
== 100 || version
== 300 || version
== 310 || version
== 320) {
178 * Attach a dumy shader of the given type.
181 attach_dummy_shader(GLuint shader_prog
, GLenum type
)
183 const char *shader_template
;
184 char shader_text
[4096];
186 /* this sets the 'es' string at the end of the version, 1.00 doesn't have that */
187 bool es_flag
= (glsl_is_es(requested_version
) && requested_version
!= 100);
190 case GL_VERTEX_SHADER
:
193 "void main() { gl_Position = vec4(0.0); }";
195 case GL_TESS_EVALUATION_SHADER
:
198 "#extension GL_ARB_tessellation_shader : require\n"
199 "layout(quads, equal_spacing) in;\n"
200 "void main() { gl_Position = vec4(0.0); }";
202 case GL_FRAGMENT_SHADER
:
208 shader_template
= NULL
;
209 printf("No dummy shader available for this shader type\n");
210 piglit_report_result(PIGLIT_FAIL
);
214 snprintf(shader_text
, sizeof(shader_text
),
217 es_flag
? "es" : "");
218 shader
= piglit_compile_shader_text(type
, shader_text
);
219 glAttachShader(shader_prog
, shader
);
224 * GLES requires both vertex and fragment shaders to be present in
225 * order to link. From section 2.10.3 (Program Objects) of the GLES 2.0 spec:
227 * "Linking will also fail ... if program does not contain both a
228 * vertex shader and a fragment shader ..."
230 * So compile a dummy shader of type complementary to "type" and
231 * attach it to shader_prog.
234 attach_complementary_shader(GLuint shader_prog
, GLenum type
)
236 if (type
== GL_FRAGMENT_SHADER
)
237 attach_dummy_shader(shader_prog
, GL_VERTEX_SHADER
);
238 else if (type
== GL_VERTEX_SHADER
)
239 attach_dummy_shader(shader_prog
, GL_FRAGMENT_SHADER
);
243 require_feature(int gl_ver
, const char *gl_ext
, int es_ver
, const char *es_ext
)
245 const int required_ver
= piglit_is_gles() ? es_ver
: gl_ver
;
246 const char *required_ext
= piglit_is_gles() ? es_ext
: gl_ext
;
248 if (piglit_get_gl_version() < required_ver
&&
249 !piglit_is_extension_supported(required_ext
)) {
250 printf("Test requires version %g or %s\n",
251 required_ver
/ 10.0, required_ext
);
252 piglit_report_result(PIGLIT_SKIP
);
267 char *failing_stage
= NULL
;
269 if (strcmp(filename
+ strlen(filename
) - 4, "frag") == 0)
270 type
= GL_FRAGMENT_SHADER
;
271 else if (strcmp(filename
+ strlen(filename
) - 4, "vert") == 0)
272 type
= GL_VERTEX_SHADER
;
273 else if (strcmp(filename
+ strlen(filename
) - 4, "tesc") == 0)
274 type
= GL_TESS_CONTROL_SHADER
;
275 else if (strcmp(filename
+ strlen(filename
) - 4, "tese") == 0)
276 type
= GL_TESS_EVALUATION_SHADER
;
277 else if (strcmp(filename
+ strlen(filename
) - 4, "geom") == 0)
278 type
= GL_GEOMETRY_SHADER
;
279 else if (strcmp(filename
+ strlen(filename
) - 4, "comp") == 0)
280 type
= GL_COMPUTE_SHADER
;
283 fprintf(stderr
, "Couldn't determine type of program %s\n",
285 piglit_report_result(PIGLIT_FAIL
);
288 piglit_require_vertex_shader();
289 piglit_require_fragment_shader();
291 if (type
== GL_TESS_CONTROL_SHADER
|| type
== GL_TESS_EVALUATION_SHADER
) {
292 require_feature(40, "GL_ARB_tessellation_shader",
293 32, "GL_OES_tessellation_shader");
296 if (type
== GL_COMPUTE_SHADER
) {
297 require_feature(43, "GL_ARB_compute_shader", 31, NULL
);
300 prog_string
= piglit_load_text_file(filename
, NULL
);
301 if (prog_string
== NULL
) {
302 fprintf(stderr
, "Couldn't open program %s: %s\n",
303 filename
, strerror(errno
));
307 if (dummy_shader_include
) {
308 glNamedStringARB(GL_SHADER_INCLUDE_ARB
, -1, "/dummy/path_to/shader_include",
312 prog
= glCreateShader(type
);
313 glShaderSource(prog
, 1, (const GLchar
**)&prog_string
, NULL
);
315 if (shader_include_path
)
316 glCompileShaderIncludeARB(prog
, 1, (const char * const *) &shader_include_path
, NULL
);
318 glCompileShader(prog
);
320 ok
= get_shader_compile_status(prog
);
322 size
= get_shader_info_log_length(prog
);
325 glGetShaderInfoLog(prog
, size
, NULL
, info
);
327 info
= "(no compiler output)";
331 failing_stage
= "compile";
333 /* Try linking the shader if it compiled. We do this
334 * even if --check-link wasn't specified, to increase
335 * coverage of linker code.
339 shader_prog
= glCreateProgram();
340 glAttachShader(shader_prog
, prog
);
341 if (glsl_is_es(requested_version
)) {
342 attach_complementary_shader(shader_prog
, type
);
344 #if PIGLIT_USE_OPENGL
345 if (type
== GL_GEOMETRY_SHADER
||
346 type
== GL_TESS_CONTROL_SHADER
||
347 type
== GL_TESS_EVALUATION_SHADER
)
348 attach_dummy_shader(shader_prog
, GL_VERTEX_SHADER
);
349 if (type
== GL_TESS_CONTROL_SHADER
)
350 attach_dummy_shader(shader_prog
, GL_TESS_EVALUATION_SHADER
);
351 if (test_requires_geometry_shader4
) {
352 /* The default value of
353 * GL_GEOMETRY_VERTICES_OUT_ARB is zero, which
354 * is useless for testing. Use a value of 3.
356 glProgramParameteriARB(shader_prog
,
357 GL_GEOMETRY_VERTICES_OUT_ARB
,
361 glLinkProgram(shader_prog
);
363 ok
= piglit_link_check_status_quiet(shader_prog
);
365 failing_stage
= "link";
368 glDeleteProgram(shader_prog
);
371 pass
= (expected_pass
== ok
);
379 fprintf(out
, "Failed to %s %s shader %s: %s\n",
381 get_shader_name(type
),
384 printf("Shader source:\n");
385 printf("%s\n", prog_string
);
388 fprintf(out
, "Successfully %s %s shader %s: %s\n",
389 check_link
? "compiled and linked" : "compiled",
390 get_shader_name(type
),
392 if (!expected_pass
) {
393 printf("Shader source:\n");
394 printf("%s\n", prog_string
);
401 glDeleteShader(prog
);
402 piglit_report_result (pass
? PIGLIT_PASS
: PIGLIT_FAIL
);
405 static void usage(char *name
)
407 printf("%s {options} <filename.frag|filename.vert> <pass|fail> "
408 "{requested GLSL version} {list of required GL extensions}\n", name
);
409 printf("\nSupported options:\n");
410 printf(" --check-link: also detect link failures\n");
415 * Process any options and remove them from the argv array. Return
419 process_options(int argc
, char **argv
)
424 if (argv
[i
][0] == '-' && strcmp(argv
[i
], "-compat") != 0) {
425 if (strcmp(argv
[i
], "--check-link") == 0)
427 else if (strcmp(argv
[i
], "--dummy-shader-include") == 0)
428 dummy_shader_include
= true;
429 else if (strncmp(argv
[i
], "--shader-include-path=", 22) == 0)
430 shader_include_path
= argv
[i
] + 22;
433 /* do not retain the option; we've processed it */
436 /* retain the option in the argv array */
437 argv
[new_argc
++] = argv
[i
++];
444 parse_glsl_version_number(const char *str
)
450 /* Accept a return value of either 1 or 2 from sscanf(), so
451 * that the version number may be supplied as either "<int>"
454 if (sscanf(str
, "%u.%u", &major
, &minor
) == 0) {
455 printf("Ill-formed GLSL version number: %s\n", str
);
456 piglit_report_result(PIGLIT_FAIL
);
459 if (strstr(str
, "compatibility"))
460 flags
|= COMPAT_FLAG
;
462 return ((major
* 100) + minor
) | flags
;
467 parse_glsl_version_string(const char *str
)
469 if (piglit_is_gles()) {
470 /* In GLSL ES, the string returned by
471 * glGetString(GL_SHADING_LANGUAGE_VERSION) is
472 * prefixed by some text. Verify that the expected
473 * text is there and skip it before calling
474 * parse_glsl_version_number().
476 const char *expected_prefix
= "OpenGL ES GLSL ES ";
477 if (strncmp(str
, expected_prefix
,
478 strlen(expected_prefix
)) != 0) {
479 printf("Ill-formed GLSL version string: %s\n", str
);
480 piglit_report_result(PIGLIT_FAIL
);
482 str
+= strlen(expected_prefix
);
484 return parse_glsl_version_number(str
);
489 check_version(unsigned glsl_version
)
491 if (!piglit_is_gles()) {
492 if (requested_version
== 100) {
493 piglit_require_extension("GL_ARB_ES2_compatibility");
495 } else if (requested_version
== 300) {
496 piglit_require_extension("GL_ARB_ES3_compatibility");
498 } else if (requested_version
== 310) {
499 piglit_require_extension("GL_ARB_ES3_1_compatibility");
501 } else if (requested_version
== 320) {
502 piglit_require_extension("GL_ARB_ES3_2_compatibility");
507 if (glsl_version
< requested_version
) {
509 "GLSL version is %u.%u, but requested version %u.%u is required\n",
510 glsl_version
/ 100, glsl_version
% 100,
511 requested_version
/ 100, requested_version
% 100);
512 piglit_report_result(PIGLIT_SKIP
);
518 piglit_init(int argc
, char**argv
)
520 const char *glsl_version_string
;
521 unsigned glsl_version
= 0;
527 if (strlen(argv
[1]) < 5)
531 if (strcmp(argv
[2], "pass") == 0)
533 else if (strcmp(argv
[2], "fail") == 0)
539 requested_version
= parse_glsl_version_number(argv
[3]) & ~COMPAT_FLAG
;
541 gl_version_times_10
= piglit_get_gl_version();
543 if (gl_version_times_10
< 20
544 && !piglit_is_extension_supported("GL_ARB_shader_objects")) {
545 printf("Requires OpenGL 2.0\n");
546 piglit_report_result(PIGLIT_SKIP
);
549 glsl_version_string
= (char *)
550 glGetString(GL_SHADING_LANGUAGE_VERSION
);
552 if (glsl_version_string
!= NULL
)
553 glsl_version
= parse_glsl_version_string(glsl_version_string
);
555 check_version(glsl_version
);
557 for (i
= 4; i
< argc
; i
++) {
558 if (argv
[i
][0] == '!') {
559 piglit_require_not_extension(argv
[i
] + 1);
561 piglit_require_extension(argv
[i
]);
562 if (strstr(argv
[i
], "geometry_shader4") != NULL
)
563 test_requires_geometry_shader4
= true;
573 /* Should never be reached */