1 /*
2  * Copyright © 2013 Gregory Hainaut <gregory.hainaut@gmail.com>
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 DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "piglit-util-gl.h"
25 
26 PIGLIT_GL_TEST_CONFIG_BEGIN
27 
28 	config.supports_gl_compat_version = 21;
29 	config.supports_gl_core_version = 31;
30 
31 PIGLIT_GL_TEST_CONFIG_END
32 
33 static const char vs_source_template[] =
34 	"#version %d\n"
35 	"\n"
36 	"#if __VERSION__ > 140\n"
37 	"out gl_PerVertex {\n"
38 	"    vec4 gl_Position;\n"
39 	"};\n"
40 	"\n"
41 	"in vec4 position;\n"
42 	"#else\n"
43 	"attribute vec4 position;\n"
44 	"#endif\n"
45 	"\n"
46 	"void main()\n"
47 	"{\n"
48 	"    gl_Position = position;\n"
49 	"}\n"
50 	;
51 static const char fs_source_template[] =
52 	"#version %d\n"
53 	"\n"
54 	"#if __VERSION__ > 140\n"
55 	"out vec4 color;\n"
56 	"#else\n"
57 	"#define color gl_FragColor\n"
58 	"#endif\n"
59 	"\n"
60 	"void main()\n"
61 	"{\n"
62 	"    color = vec4(0.0, 1.0, 0.0, 0.0);\n"
63 	"}\n"
64 	;
65 static const char gs_source_template[] =
66 	"#version %d\n"
67 	"\n"
68 	"in gl_PerVertex {\n"
69 	"    vec4 gl_Position;\n"
70 	"} gl_in[];\n"
71 	"\n"
72 	"out gl_PerVertex {\n"
73 	"    vec4 gl_Position;\n"
74 	"};\n"
75 	"\n"
76 	"layout(triangles) in;\n"
77 	"layout(triangle_strip, max_vertices = 3) out;\n"
78 	"void main()\n"
79 	"{\n"
80 	"    for(int i = 0; i < gl_in.length(); i++) {\n"
81 	"        gl_Position = gl_in[i].gl_Position;\n"
82 	"        EmitVertex();\n"
83 	"    }\n"
84 	"    EndPrimitive();\n"
85 	"}\n"
86 	;
87 static const char tc_source_template[] =
88 	"#version %d\n"
89 	"#extension GL_ARB_tessellation_shader: enable\n"
90 	"\n"
91 	"in gl_PerVertex {\n"
92 	"    vec4 gl_Position;\n"
93 	"} gl_in[];\n"
94 	"\n"
95 	"out gl_PerVertex {\n"
96 	"    vec4 gl_Position;\n"
97 	"} gl_out[];\n"
98 	"\n"
99 	"layout(vertices = 3) out;\n"
100 	"void main()\n"
101 	"{\n"
102 	"    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
103 	"    gl_TessLevelOuter[0] = 1.0;\n"
104 	"    gl_TessLevelOuter[1] = 1.0;\n"
105 	"    gl_TessLevelOuter[2] = 1.0;\n"
106 	"    gl_TessLevelInner[0] = 1.0;\n"
107 	"    gl_TessLevelInner[1] = 1.0;\n"
108 	"}\n"
109 	;
110 static const char te_source_template[] =
111 	"#version %d\n"
112 	"#extension GL_ARB_tessellation_shader: enable\n"
113 	"\n"
114 	"in gl_PerVertex {\n"
115 	"    vec4 gl_Position;\n"
116 	"} gl_in[];\n"
117 	"\n"
118 	"out gl_PerVertex {\n"
119 	"    vec4 gl_Position;\n"
120 	"};\n"
121 	"\n"
122 	"layout(triangles, equal_spacing)  in;\n"
123 	"\n"
124 	"void main()\n"
125 	"{\n"
126 	"    vec4 p0 = gl_in[0].gl_Position;\n"
127 	"    vec4 p1 = gl_in[1].gl_Position;\n"
128 	"    vec4 p2 = gl_in[2].gl_Position;\n"
129 	"\n"
130 	"    vec3 p = gl_TessCoord.xyz;\n"
131 	"\n"
132 	"    gl_Position = p0*p.x + p1*p.y + p2*p.z;\n"
133 	"}\n"
134 	;
135 
136 static bool pass;
137 
138 enum piglit_result
piglit_display(void)139 piglit_display(void)
140 {
141 	/* UNREACHED */
142 	return PIGLIT_FAIL;
143 }
144 
145 static void
validate_pipe(GLuint pipe,bool expected,const char * test_name)146 validate_pipe(GLuint pipe, bool expected, const char *test_name)
147 {
148 	GLint status;
149 
150 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
151 
152 	status = piglit_program_pipeline_check_status_quiet(pipe);
153 
154 	if (status != expected) {
155 		fprintf(stderr,
156 			"Wrong pipeline validation status. Got %d, but "
157 			"expected %d\n",
158 			status, expected);
159 		piglit_report_subtest_result(PIGLIT_FAIL, "%s", test_name);
160 		pass = false;
161 	} else {
162 		piglit_report_subtest_result(PIGLIT_PASS, "%s", test_name);
163 	}
164 }
165 
166 static void
build_and_validate_pipe(GLuint pipe,bool expected,const char * test_name,GLbitfield bit_a,GLuint prog_a,GLbitfield bit_b,GLuint prog_b,GLbitfield bit_c,GLuint prog_c,GLbitfield bit_d,GLuint prog_d,GLbitfield bit_e,GLuint prog_e)167 build_and_validate_pipe(GLuint pipe, bool expected, const char *test_name,
168 			GLbitfield bit_a, GLuint prog_a,
169 			GLbitfield bit_b, GLuint prog_b,
170 			GLbitfield bit_c, GLuint prog_c,
171 			GLbitfield bit_d, GLuint prog_d,
172 			GLbitfield bit_e, GLuint prog_e)
173 {
174 	if (!piglit_automatic)
175 		printf("%s\n", test_name);
176 
177 	if (bit_a != GL_ALL_SHADER_BITS)
178 		glUseProgramStages(pipe, GL_ALL_SHADER_BITS, 0);
179 
180 	if (bit_a != 0)
181 		glUseProgramStages(pipe, bit_a, prog_a);
182 
183 	if (bit_b != 0)
184 		glUseProgramStages(pipe, bit_b, prog_b);
185 
186 	if (bit_c != 0)
187 		glUseProgramStages(pipe, bit_c, prog_c);
188 
189 	if (bit_d != 0)
190 		glUseProgramStages(pipe, bit_d, prog_d);
191 
192 	if (bit_e != 0)
193 		glUseProgramStages(pipe, bit_e, prog_e);
194 
195 	validate_pipe(pipe, expected, test_name);
196 
197 	if (!piglit_automatic)
198 		printf("\n");
199 }
200 
201 static GLuint
create_prog(GLint sh1,GLint sh2)202 create_prog(GLint sh1, GLint sh2)
203 {
204 	GLint p = 0;
205 
206 	p = glCreateProgram();
207 	glProgramParameteri(p, GL_PROGRAM_SEPARABLE, GL_TRUE);
208 	if (sh1)
209 		glAttachShader(p, sh1);
210 	if (sh2)
211 		glAttachShader(p, sh2);
212 	glLinkProgram(p);
213 
214 	pass = piglit_link_check_status(p) && pass;
215 
216 	return p;
217 }
218 
219 void
piglit_init(int argc,char ** argv)220 piglit_init(int argc, char **argv)
221 {
222 	GLint vs, fs, gs, tes, tcs;
223 	GLuint pipe;
224 	GLint prog_vs, prog_fs, prog_gs = 0, prog_tcs = 0, prog_tes = 0, prog_tess;
225 	GLint prog_vs_fs, prog_vs_gs = 0;
226 	GLint separable;
227 	int version;
228 
229 	char *vs_source, *fs_source, *gs_source, *te_source, *tc_source;
230 
231 	const bool has_tess = piglit_get_gl_version() >= 40
232 		|| piglit_is_extension_supported("GL_ARB_tessellation_shader");
233 	const bool has_geo =
234 		piglit_get_gl_version() >= 32;
235 
236 	piglit_require_extension("GL_ARB_separate_shader_objects");
237 
238 	if (piglit_get_gl_version() >= 40)
239 		version = 400;
240 	else if (piglit_get_gl_version() >= 32)
241 		version = 150;
242 	else
243 		version = 120;
244 
245 	pass = true;
246 
247 	/* create the shader program */
248 	(void)!asprintf(&vs_source, vs_source_template, version);
249 	(void)!asprintf(&fs_source, fs_source_template, version);
250 	(void)!asprintf(&gs_source, gs_source_template, version);
251 	(void)!asprintf(&te_source, te_source_template, version);
252 	(void)!asprintf(&tc_source, tc_source_template, version);
253 
254 	vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_source);
255 	fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, fs_source);
256 	pass = (fs != 0) && (vs != 0) && pass;
257 	if (has_geo) {
258 		gs = piglit_compile_shader_text(GL_GEOMETRY_SHADER, gs_source);
259 		pass = (gs != 0) && pass;
260 	}
261 	if (has_tess) {
262 		tes = piglit_compile_shader_text(GL_TESS_EVALUATION_SHADER,
263 						 te_source);
264 		tcs = piglit_compile_shader_text(GL_TESS_CONTROL_SHADER,
265 						 tc_source);
266 		pass = (tes != 0) && (tcs != 0) && pass;
267 	}
268 
269 	free(vs_source);
270 	free(fs_source);
271 	free(gs_source);
272 	free(te_source);
273 	free(tc_source);
274 
275 	prog_vs = create_prog(vs, 0);
276 	prog_fs = create_prog(fs, 0);
277 	prog_vs_fs = create_prog(vs, fs);
278 	if (has_geo) {
279 		prog_gs = create_prog(gs, 0);
280 		prog_vs_gs = create_prog(vs, gs);
281 	}
282 	if (has_tess) {
283 		prog_tcs = create_prog(tcs, 0);
284 		prog_tes = create_prog(tes, 0);
285 		prog_tess = create_prog(tcs, tes);
286 	}
287 
288 	/* Setup or compilation failure. Stop here */
289 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
290 	if (!pass) {
291 		piglit_report_result(PIGLIT_FAIL);
292 		return;
293 	}
294 
295 	if (!piglit_automatic) {
296 		if (has_tess && has_geo) {
297 			printf("INFO: ALL stages supported: running all "
298 			       "test\n");
299 		} else {
300 			if (!has_tess)
301 				printf("INFO: GL_ARB_tessellation_shader / "
302 				       "OpenGL 4.0 not supported: tessellation "
303 				       "test disabled\n");
304 			if (!has_geo)
305 				printf("INFO: OpenGL 3.2 not "
306 				       "supported: geometry test disabled\n");
307 		}
308 	}
309 
310 	/* Create the pipeline */
311 	glGenProgramPipelines(1, &pipe);
312 	glBindProgramPipeline(pipe);
313 
314 	build_and_validate_pipe(pipe, true,
315 				"VS/FS program, single glUseProgramStages "
316 				"call",
317 				GL_ALL_SHADER_BITS, prog_vs_fs,
318 				0, 0,
319 				0, 0,
320 				0, 0,
321 				0, 0);
322 
323 	build_and_validate_pipe(pipe, true,
324 				"VS/FS program, multiple glUseProgramStages "
325 				"calls",
326 				GL_FRAGMENT_SHADER_BIT, prog_vs_fs,
327 				GL_VERTEX_SHADER_BIT, prog_vs_fs,
328 				0, 0,
329 				0, 0,
330 				0, 0);
331 
332 	build_and_validate_pipe(pipe, true,
333 				"program per pipeline stage",
334 				GL_VERTEX_SHADER_BIT, prog_vs,
335 				GL_FRAGMENT_SHADER_BIT, prog_fs,
336 				(has_geo) ? GL_GEOMETRY_SHADER_BIT : 0,
337 				prog_gs,
338 				(has_tess) ? GL_TESS_CONTROL_SHADER_BIT : 0,
339 				prog_tcs,
340 				(has_tess) ? GL_TESS_EVALUATION_SHADER_BIT : 0,
341 				prog_tes);
342 
343 	/* Section 2.11.11 (Shader Execution), subpart "Validation" of the
344 	 * OpenGL 4.1 spec says:
345 	 *
346 	 *     "If the current set of active program objects cannot be
347 	 *     executed, no primitives are processed and the error
348 	 *     INVALID_OPERATION will be generated.  This error is generated
349 	 *     by any command that transfers vertices to the GL if:
350 	 *
351 	 *     ...
352 	 *
353 	 *     - One program object is active for at least two shader stages
354 	 *       and a second program is active for a shader stage between two
355 	 *       stages for which the first program was active."
356 	 */
357 	if (has_geo)
358 		build_and_validate_pipe(pipe, false,
359 					"GS splitting a VS/FS pipeline",
360 					GL_ALL_SHADER_BITS, prog_vs_fs,
361 					GL_GEOMETRY_SHADER_BIT, prog_gs,
362 					0, 0,
363 					0, 0,
364 					0, 0);
365 	else
366 		piglit_report_subtest_result(PIGLIT_SKIP,
367 					     "GS splitting a VS/FS pipeline");
368 
369 	if (has_tess)
370 		build_and_validate_pipe(pipe, false,
371 					"TCS splitting a VS/GS pipeline",
372 					GL_ALL_SHADER_BITS, prog_vs_gs,
373 					GL_TESS_CONTROL_SHADER_BIT, prog_tcs,
374 					0, 0,
375 					0, 0,
376 					0, 0);
377 	else
378 		piglit_report_subtest_result(PIGLIT_SKIP,
379 					     "TCS splitting a VS/GS pipeline");
380 
381 	if (has_tess)
382 		build_and_validate_pipe(pipe, false,
383 					"TES splitting a VS/GS program",
384 					GL_ALL_SHADER_BITS, prog_vs_gs,
385 					GL_FRAGMENT_SHADER_BIT, prog_fs,
386 					GL_TESS_EVALUATION_SHADER_BIT, prog_tes,
387 					0, 0,
388 					0, 0);
389 	else
390 		piglit_report_subtest_result(PIGLIT_SKIP,
391 					     "TES splitting a VS/GS program");
392 
393 	/* Section 2.11.11 (Shader Execution), subpart "Validation" of the
394 	 * OpenGL 4.1 spec says:
395 	 *
396 	 *     "If the current set of active program objects cannot be
397 	 *     executed, no primitives are processed and the error
398 	 *     INVALID_OPERATION will be generated.  This error is generated
399 	 *     by any command that transfers vertices to the GL if:
400 	 *
401 	 *     ...
402 	 *
403 	 *     - There is an active program for tessellation control,
404 	 *       tessellation evaluation, or geometry stages with
405 	 *       corresponding executable shader, but there is no active
406 	 *       program with executable vertex shader."
407 	 */
408 	if (has_geo)
409 		build_and_validate_pipe(pipe, false,
410 					"GS without VS",
411 					GL_FRAGMENT_SHADER_BIT, prog_fs,
412 					GL_GEOMETRY_SHADER_BIT, prog_gs,
413 					0, 0,
414 					0, 0,
415 					0, 0);
416 	else
417 		piglit_report_subtest_result(PIGLIT_SKIP, "GS without VS");
418 
419 	if (has_tess)
420 		build_and_validate_pipe(pipe, false,
421 					"TES/TCS without VS",
422 					GL_ALL_SHADER_BITS, prog_tess,
423 					GL_FRAGMENT_SHADER_BIT, prog_fs,
424 					0, 0,
425 					0, 0,
426 					0, 0);
427 	else
428 		piglit_report_subtest_result(PIGLIT_SKIP, "TES/TCS without VS");
429 
430 	/* Section 2.11.11 (Shader Execution), subpart "Validation" of the
431 	 * OpenGL 4.1 spec says:
432 	 *
433 	 *     "If the current set of active program objects cannot be
434 	 *     executed, no primitives are processed and the error
435 	 *     INVALID_OPERATION will be generated.  This error is generated
436 	 *     by any command that transfers vertices to the GL if:
437 	 *
438 	 *     - A program object is active for at least one, but not all of
439 	 *       the shader stages that were present when the program was
440 	 *       linked."
441 	 */
442 	build_and_validate_pipe(pipe, false,
443 				"Only VS from a VS/FS program",
444 				GL_FRAGMENT_SHADER_BIT, prog_fs,
445 				GL_VERTEX_SHADER_BIT, prog_vs_fs,
446 				0, 0,
447 				0, 0,
448 				0, 0);
449 
450 	if (has_geo)
451 		build_and_validate_pipe(pipe, false,
452 					"Only GS from a VS/GS program",
453 					GL_FRAGMENT_SHADER_BIT, prog_fs,
454 					GL_GEOMETRY_SHADER_BIT, prog_vs_gs,
455 					GL_VERTEX_SHADER_BIT, prog_vs,
456 					0, 0,
457 					0, 0);
458 	else
459 		piglit_report_subtest_result(PIGLIT_SKIP,
460 					     "Only GS from a VS/GS program");
461 
462 	if (has_tess)
463 		build_and_validate_pipe(pipe, false,
464 					"Only TES from TES/TCS program",
465 					GL_FRAGMENT_SHADER_BIT, prog_fs,
466 					GL_TESS_EVALUATION_SHADER_BIT, prog_tess,
467 					GL_VERTEX_SHADER_BIT, prog_vs,
468 					0, 0,
469 					0, 0);
470 	else
471 		piglit_report_subtest_result(PIGLIT_SKIP,
472 					     "Only TES from TES/TCS program");
473 
474 	/* Section 2.11.11 (Shader Execution), subpart "Validation" of the
475 	 * OpenGL 4.1 spec says:
476 	 *
477 	 *     "If the current set of active program objects cannot be
478 	 *     executed, no primitives are processed and the error
479 	 *     INVALID_OPERATION will be generated.  This error is generated
480 	 *     by any command that transfers vertices to the GL if:
481 	 *
482 	 *     ...
483 	 *
484 	 *     - There is no current unified program object and the current
485 	 *       program pipeline object includes a program object that was
486 	 *       relinked since being applied to the pipeline object via
487 	 *       UseProgramStages with the PROGRAM_SEPARABLE parameter set to
488 	 *       FALSE."
489 	 */
490 	build_and_validate_pipe(pipe, true,
491 				"Relink attached VS without "
492 				"GL_PROGRAM_SEPARABLE (sanity pre-test)",
493 				GL_FRAGMENT_SHADER_BIT, prog_fs,
494 				GL_VERTEX_SHADER_BIT, prog_vs,
495 				0, 0,
496 				0, 0,
497 				0, 0);
498 
499 	glGetProgramiv(prog_vs, GL_PROGRAM_SEPARABLE, &separable);
500 	if (!separable) {
501 		printf("Error: %d was not a separable program\n", prog_vs);
502 		pass = false;
503 	}
504 
505 	glProgramParameteri(prog_vs, GL_PROGRAM_SEPARABLE, GL_FALSE);
506 
507 	glGetProgramiv(prog_vs, GL_PROGRAM_SEPARABLE, &separable);
508 
509 	/* NOTE: This check /may/ need to be moved after the call to
510 	 * glLinkProgram.  There has been some discussion as to whether this
511 	 * is supposed to be "latched" state.
512 	 */
513 	if (separable) {
514 		printf("Error: fail to remove separable flags of program %d\n",
515 		       prog_vs);
516 		pass = false;
517 	}
518 
519 	glLinkProgram(prog_vs);
520 	pass = piglit_link_check_status(prog_vs) && pass;
521 	validate_pipe(pipe, GL_FALSE,
522 		      "Relink attached VS without GL_PROGRAM_SEPARABLE");
523 
524 	piglit_present_results();
525 
526 	piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
527 }
528