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