1 /*
2 * Copyright © 2013 Intel Corporation
3 *
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:
10 *
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.
14 *
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.
22 */
23
24 /** \file
25 *
26 * Test that any desktop GLSL version may be linked with any other
27 * desktop GLSL version.
28 *
29 * From the GLSL 4.30 spec, section 3.3 (Preprocessor):
30 *
31 * "Shaders for the core or compatibility profiles that declare
32 * different versions can be linked together."
33 *
34 * This is a deliberate relaxation of the cross-version linking rules
35 * from previous versions of the GLSL spec (which prohibited some
36 * combinations of GLSL versions from being linked together). It was
37 * made because existing implementations didn't follow the old
38 * cross-version linking rules (see Khronos bug 8463). So it seems
39 * reasonable to expect all implementations to follow the new relaxed
40 * rules.
41 *
42 * This test can be run in the following ways:
43 *
44 * - "interstage" checks that a vertex shader of one version can be
45 * linked with a fragment shader of another version.
46 *
47 * - "intrastage" checks that two vertex shaders of different versions
48 * can be linked together.
49 *
50 * - "vs-gs" checks that a vertex shader of one version can be linked
51 * with a geometry shader of another version.
52 */
53
54 #include "piglit-util-gl.h"
55
56 static enum test_type {
57 test_type_interstage,
58 test_type_intrastage,
59 test_type_vs_gs,
60 } test_type;
61
62 static void parse_params();
63
64 PIGLIT_GL_TEST_CONFIG_BEGIN
65
66 piglit_gl_process_args(&argc, argv, &config);
67 parse_params(argc, argv);
68 if (test_type == test_type_vs_gs) {
69 config.supports_gl_compat_version = 32;
70 config.supports_gl_core_version = 32;
71 } else {
72 config.supports_gl_compat_version = 10;
73 config.supports_gl_core_version = 31;
74 }
75
76 PIGLIT_GL_TEST_CONFIG_END
77
78 static const char *interstage_vs =
79 "#version %d\n"
80 "\n"
81 "void main()\n"
82 "{\n"
83 " gl_Position = vec4(0.0);\n"
84 "}\n";
85
86 static const char *interstage_gs =
87 "#version %d\n"
88 "\n"
89 "layout(triangles) in;\n"
90 "layout(triangle_strip, max_vertices = 3) out;\n"
91 "void main()\n"
92 "{\n"
93 " for (int i = 0; i < 3; i++) {\n"
94 " gl_Position = gl_in[i].gl_Position;\n"
95 " EmitVertex();\n"
96 " }\n"
97 "}\n";
98
99 static const char *interstage_fs =
100 "#version %d\n"
101 "\n"
102 "void main()\n"
103 "{\n"
104 " gl_FragColor = vec4(0.0);\n"
105 "}\n";
106
107 /* Section 1.2.1 (Summary of Changes from Version 4.10) of the OpenGL
108 * Shading Language 4.20 spec says:
109 *
110 * Move these previously deprecated features to be only in the
111 * compatibility profile:
112 * ...
113 * * The built-in variables gl_FragColor and gl_FragData.
114 */
115 static const char *interstage_fs_420 =
116 "#version %d\n"
117 "\n"
118 "out vec4 color;\n"
119 "\n"
120 "void main()\n"
121 "{\n"
122 " color = vec4(0.0);\n"
123 "}\n";
124
125 static const char *intrastage_vs1 =
126 "#version %d\n"
127 "\n"
128 "void f();\n"
129 "void main()\n"
130 "{\n"
131 " f();\n"
132 "}\n";
133
134 static const char *intrastage_vs2 =
135 "#version %d\n"
136 "\n"
137 "void f()\n"
138 "{\n"
139 " gl_Position = vec4(0.0);\n"
140 "}\n";
141
142 static int all_glsl_versions[] = {
143 110, 120, 130, 140, 150, 330, 400, 410, 420, 430, 440
144 };
145
146
147 static void
print_usage_and_exit(const char * prog_name)148 print_usage_and_exit(const char *prog_name)
149 {
150 printf("Usage: %s <subtest>\n"
151 " where <subtest> is one of:\n"
152 " interstage: test interstage linking (vs-to-fs)\n"
153 " intrastage: test intrastage linking (vs-to-vs)\n"
154 " vs-gs: test interstage linking (vs-to-gs)\n",
155 prog_name);
156 piglit_report_result(PIGLIT_FAIL);
157 }
158
159
160 static int
get_max_glsl_version()161 get_max_glsl_version()
162 {
163 bool es;
164 int major, minor;
165 piglit_get_glsl_version(&es, &major, &minor);
166 if (es) {
167 printf("This test should only be run on desktop GL.\n");
168 piglit_report_result(PIGLIT_FAIL);
169 }
170 return 100 * major + minor;
171 }
172
173
174 /**
175 * Try compiling a shader of type \c target, whose string is formed by
176 * applying \c version to \c shader_template, and attach it to \c
177 * prog. On success, return true. If there is a problem, print an
178 * error message using \c shader_desc to describe the shader, and
179 * return false.
180 */
181 static bool
try_attach_shader(GLuint prog,const char * shader_desc,GLenum target,const char * shader_template,int version)182 try_attach_shader(GLuint prog, const char *shader_desc, GLenum target,
183 const char *shader_template, int version)
184 {
185 char *shader_text = NULL;
186 GLuint shader = glCreateShader(target);
187 GLint ok;
188
189 (void)!asprintf(&shader_text, shader_template, version);
190 glShaderSource(shader, 1, (const GLchar **) &shader_text, NULL);
191 free(shader_text);
192 glCompileShader(shader);
193 glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
194 if (!ok) {
195 printf("%s failed to compile.\n", shader_desc);
196 glDeleteShader(shader);
197 return false;
198 }
199 glAttachShader(prog, shader);
200 glDeleteShader(shader);
201 return true;
202 }
203
204
205 /**
206 * Test interstage linking between VS and FS, and print a message
207 * describing the result, and return true if compilation and linking
208 * succeeded.
209 */
210 static bool
test_interstage(int version_vs,int version_other,bool use_gs)211 test_interstage(int version_vs, int version_other, bool use_gs)
212 {
213 GLuint prog = glCreateProgram();
214 GLint ok;
215
216 if (!try_attach_shader(prog, "vertex shader", GL_VERTEX_SHADER,
217 interstage_vs, version_vs)) {
218 glDeleteProgram(prog);
219 return false;
220 }
221 if (use_gs) {
222 if (version_other < 150) {
223 printf("Not tested (GS requires GLSL 1.50).\n");
224 glDeleteProgram(prog);
225 return true;
226 }
227 if (!try_attach_shader(prog, "geometry shader",
228 GL_GEOMETRY_SHADER, interstage_gs,
229 version_other)) {
230 glDeleteProgram(prog);
231 return false;
232 }
233 } else {
234 const char *fs = interstage_fs;
235
236 if (version_other >= 420)
237 fs = interstage_fs_420;
238
239 if (!try_attach_shader(prog, "fragment shader",
240 GL_FRAGMENT_SHADER, fs,
241 version_other)) {
242 glDeleteProgram(prog);
243 return false;
244 }
245 }
246 glLinkProgram(prog);
247 glGetProgramiv(prog, GL_LINK_STATUS, &ok);
248 if (ok)
249 printf("Success.\n");
250 else
251 printf("Link failed.\n");
252 return ok;
253 }
254
255
256 /**
257 * Test intrastage linking between two VS shaders, and print a message
258 * describing the result, and return true if compilation and linking
259 * succeeded.
260 */
261 static bool
test_intrastage(int version_vs1,int version_vs2)262 test_intrastage(int version_vs1, int version_vs2)
263 {
264 GLuint prog = glCreateProgram();
265 GLint ok;
266
267 if (!try_attach_shader(prog, "vertex shader 1", GL_VERTEX_SHADER,
268 intrastage_vs1, version_vs1)) {
269 glDeleteProgram(prog);
270 return false;
271 }
272 if (!try_attach_shader(prog, "vertex shader 2", GL_VERTEX_SHADER,
273 intrastage_vs2, version_vs2)) {
274 glDeleteProgram(prog);
275 return false;
276 }
277 glLinkProgram(prog);
278 glGetProgramiv(prog, GL_LINK_STATUS, &ok);
279 if (ok)
280 printf("Success.\n");
281 else
282 printf("Link failed.\n");
283 return ok;
284 }
285
286
287 void
parse_params(int argc,char ** argv)288 parse_params(int argc, char **argv)
289 {
290 if (argc != 2)
291 print_usage_and_exit(argv[0]);
292 if (strcmp(argv[1], "interstage") == 0)
293 test_type = test_type_interstage;
294 else if (strcmp(argv[1], "intrastage") == 0)
295 test_type = test_type_intrastage;
296 else if (strcmp(argv[1], "vs-gs") == 0)
297 test_type = test_type_vs_gs;
298 else
299 print_usage_and_exit(argv[0]);
300 }
301
302
303 void
piglit_init(int argc,char ** argv)304 piglit_init(int argc, char **argv)
305 {
306 int i, j;
307 bool pass = true;
308 int max_glsl_version;
309
310 piglit_require_GLSL();
311 max_glsl_version = get_max_glsl_version();
312
313 for (i = 0; i < ARRAY_SIZE(all_glsl_versions); i++) {
314 if (all_glsl_versions[i] > max_glsl_version)
315 continue;
316 for (j = 0; j < ARRAY_SIZE(all_glsl_versions); j++) {
317 if (all_glsl_versions[j] > max_glsl_version)
318 continue;
319 printf("Testing versions %d and %d: ",
320 all_glsl_versions[i], all_glsl_versions[j]);
321 switch (test_type) {
322 case test_type_interstage:
323 pass = test_interstage(all_glsl_versions[i],
324 all_glsl_versions[j],
325 false /* use_gs */)
326 && pass;
327 break;
328 case test_type_vs_gs:
329 pass = test_interstage(all_glsl_versions[i],
330 all_glsl_versions[j],
331 true /* use_gs */)
332 && pass;
333 break;
334 case test_type_intrastage:
335 pass = test_intrastage(all_glsl_versions[i],
336 all_glsl_versions[j])
337 && pass;
338 break;
339 default:
340 /* Should never occur */
341 piglit_report_result(PIGLIT_FAIL);
342 break;
343 }
344 }
345 }
346
347 piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
348 }
349
350
351 enum piglit_result
piglit_display(void)352 piglit_display(void)
353 {
354 /* Should never be reached */
355 return PIGLIT_FAIL;
356 }
357