1 /*
2  * Copyright © 2012 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 DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 /**
25  * \file simple.c
26  *
27  * This file checks that simple cases of varying packing work
28  * correctly.  Specifically, it tests that for each basic type allowed
29  * in varyings, it is possible to create a shader with the maximum
30  * possible number of that type of varying (determined by the
31  * implementation's reported value of GL_MAX_VARYING_FLOATS).  If the
32  * size of the basic type being tested does not evenly divide
33  * GL_MAX_VARYING_FLOATS, the remaining varyings are taken up by
34  * individual floats.
35  *
36  * The test may be run in two modes: "array" mode, in which the test
37  * uses a single varying whose type is an array (e.g. mat3[7]), and
38  * "separate" mode, in which the test uses separate individual
39  * varyings of the given type.
40  *
41  * The test operates by first querying the implementation's value of
42  * GL_MAX_VARYING_FLOATS, then creating a vertex and fragment shader
43  * that use up all possible varying components.  The vertex shader
44  * fills the varying components with consecutive integer values (where
45  * the starting value is determined by a uniform), and the fragment
46  * shader checks that all of the varying components were received
47  * correctly.  The shaders are compiled and run, to ensure that the
48  * implementation not only claims to be able to pack the varyings, but
49  * actually packs them correctly too.
50  *
51  * For example, on an implementation where GL_MAX_VARYING_FLOATS is
52  * 64, when testing the mat3 type in "array" mode, the vertex shader
53  * looks like this:
54  *
55  *   #version 110
56  *   uniform int i;
57  *   varying mat3 var0[7];
58  *   varying float var1;
59  *
60  *   void main()
61  *   {
62  *     gl_Position = gl_Vertex;
63  *     var0[0][0][0] = float(i + 0);
64  *     var0[0][0][1] = float(i + 1);
65  *     var0[0][0][2] = float(i + 2);
66  *     var0[0][1][0] = float(i + 3);
67  *     ...
68  *     var0[6][2][1] = float(i + 61);
69  *     var0[6][2][2] = float(i + 62);
70  *     var1 = float(i + 63);
71  *   }
72  *
73  * And the fragment shader looks like this:
74  *
75  *   #version 110
76  *   uniform int i;
77  *   varying mat3 var0[7];
78  *   varying float var1;
79  *
80  *   void main()
81  *   {
82  *     bool failed = false;
83  *     if (var0[0][0][0] != float(i + 0))
84  *       failed = true;
85  *     if (var0[0][0][1] != float(i + 1))
86  *       failed = true;
87  *     ...
88  *     if (var0[6][2][2] != float(i + 62))
89  *       failed = true;
90  *     if (var1 != float(i + 63))
91  *       failed = true;
92  *     if (failed)
93  *       gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
94  *     else
95  *       gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
96  *   }
97  */
98 #include "piglit-util-gl.h"
99 
100 static void
101 parse_args(int argc, char *argv[], struct piglit_gl_test_config *config);
102 
103 static const int outer_dim_size = 2;
104 
105 PIGLIT_GL_TEST_CONFIG_BEGIN
106 
107 	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
108 	config.khr_no_error_support = PIGLIT_NO_ERRORS;
109 	parse_args(argc, argv, &config);
110 
111 PIGLIT_GL_TEST_CONFIG_END
112 
113 static GLuint prog;
114 static GLint i_location;
115 
116 enum base_type
117 {
118 	BASE_TYPE_FLOAT,
119 	BASE_TYPE_UINT,
120 	BASE_TYPE_INT,
121 	BASE_TYPE_DOUBLE,
122 };
123 
124 enum test_array_type
125 {
126 	SEPARATE,
127 	ARRAY,
128 	ARRAYS_OF_ARRAYS,
129 };
130 
131 static const char *
get_base_type_name(enum base_type t)132 get_base_type_name(enum base_type t)
133 {
134 	switch (t) {
135 	case BASE_TYPE_FLOAT: return "float";
136 	case BASE_TYPE_UINT:  return "uint";
137 	case BASE_TYPE_INT:   return "int";
138 	case BASE_TYPE_DOUBLE:return "double";
139 	default:              return "???";
140 	}
141 }
142 
143 struct type_desc
144 {
145 	const char *name;
146 	enum base_type base;
147 	unsigned num_cols;
148 	unsigned num_rows;
149 	unsigned glsl_version_required;
150 };
151 
152 struct type_desc int_type     = { "int",     BASE_TYPE_INT,    1, 1, 130 };
153 struct type_desc uint_type    = { "uint",    BASE_TYPE_UINT,   1, 1, 130 };
154 struct type_desc float_type   = { "float",   BASE_TYPE_FLOAT,  1, 1, 110 };
155 struct type_desc double_type  = { "double",  BASE_TYPE_DOUBLE, 1, 1, 150 };
156 struct type_desc vec2_type    = { "vec2",    BASE_TYPE_FLOAT,  1, 2, 110 };
157 struct type_desc vec3_type    = { "vec3",    BASE_TYPE_FLOAT,  1, 3, 110 };
158 struct type_desc vec4_type    = { "vec4",    BASE_TYPE_FLOAT,  1, 4, 110 };
159 struct type_desc ivec2_type   = { "ivec2",   BASE_TYPE_INT,    1, 2, 130 };
160 struct type_desc ivec3_type   = { "ivec3",   BASE_TYPE_INT,    1, 3, 130 };
161 struct type_desc ivec4_type   = { "ivec4",   BASE_TYPE_INT,    1, 4, 130 };
162 struct type_desc uvec2_type   = { "uvec2",   BASE_TYPE_UINT,   1, 2, 130 };
163 struct type_desc uvec3_type   = { "uvec3",   BASE_TYPE_UINT,   1, 3, 130 };
164 struct type_desc uvec4_type   = { "uvec4",   BASE_TYPE_UINT,   1, 4, 130 };
165 struct type_desc dvec2_type   = { "dvec2",   BASE_TYPE_DOUBLE, 1, 2, 150 };
166 struct type_desc dvec3_type   = { "dvec3",   BASE_TYPE_DOUBLE, 1, 3, 150 };
167 struct type_desc dvec4_type   = { "dvec4",   BASE_TYPE_DOUBLE, 1, 4, 150 };
168 struct type_desc mat2_type    = { "mat2",    BASE_TYPE_FLOAT,  2, 2, 110 };
169 struct type_desc mat3_type    = { "mat3",    BASE_TYPE_FLOAT,  3, 3, 110 };
170 struct type_desc mat4_type    = { "mat4",    BASE_TYPE_FLOAT,  4, 4, 110 };
171 struct type_desc mat2x3_type  = { "mat2x3",  BASE_TYPE_FLOAT,  2, 3, 120 };
172 struct type_desc mat2x4_type  = { "mat2x4",  BASE_TYPE_FLOAT,  2, 4, 120 };
173 struct type_desc mat3x2_type  = { "mat3x2",  BASE_TYPE_FLOAT,  3, 2, 120 };
174 struct type_desc mat3x4_type  = { "mat3x4",  BASE_TYPE_FLOAT,  3, 4, 120 };
175 struct type_desc mat4x2_type  = { "mat4x2",  BASE_TYPE_FLOAT,  4, 2, 120 };
176 struct type_desc mat4x3_type  = { "mat4x3",  BASE_TYPE_FLOAT,  4, 3, 120 };
177 struct type_desc dmat2_type   = { "dmat2",   BASE_TYPE_DOUBLE, 2, 2, 150 };
178 struct type_desc dmat3_type   = { "dmat3",   BASE_TYPE_DOUBLE, 3, 3, 150 };
179 struct type_desc dmat4_type   = { "dmat4",   BASE_TYPE_DOUBLE, 4, 4, 150 };
180 struct type_desc dmat2x3_type = { "dmat2x3", BASE_TYPE_DOUBLE, 2, 3, 150 };
181 struct type_desc dmat2x4_type = { "dmat2x4", BASE_TYPE_DOUBLE, 2, 4, 150 };
182 struct type_desc dmat3x2_type = { "dmat3x2", BASE_TYPE_DOUBLE, 3, 2, 150 };
183 struct type_desc dmat3x4_type = { "dmat3x4", BASE_TYPE_DOUBLE, 3, 4, 150 };
184 struct type_desc dmat4x2_type = { "dmat4x2", BASE_TYPE_DOUBLE, 4, 2, 150 };
185 struct type_desc dmat4x3_type = { "dmat4x3", BASE_TYPE_DOUBLE, 4, 3, 150 };
186 
187 const struct type_desc *all_types[] = {
188 	&int_type,
189 	&uint_type,
190 	&float_type,
191 	&double_type,
192 	&vec2_type,
193 	&vec3_type,
194 	&vec4_type,
195 	&ivec2_type,
196 	&ivec3_type,
197 	&ivec4_type,
198 	&uvec2_type,
199 	&uvec3_type,
200 	&uvec4_type,
201 	&dvec2_type,
202 	&dvec3_type,
203 	&dvec4_type,
204 	&mat2_type,
205 	&mat3_type,
206 	&mat4_type,
207 	&mat2x3_type,
208 	&mat2x4_type,
209 	&mat3x2_type,
210 	&mat3x4_type,
211 	&mat4x2_type,
212 	&mat4x3_type,
213 	&dmat2_type,
214 	&dmat3_type,
215 	&dmat4_type,
216 	&dmat2x3_type,
217 	&dmat2x4_type,
218 	&dmat3x2_type,
219 	&dmat3x4_type,
220 	&dmat4x2_type,
221 	&dmat4x3_type,
222 	NULL,
223 };
224 
225 /**
226  * Type used to communicate to get_shader() the set of varyings to
227  * test.
228  */
229 struct varying_desc
230 {
231 	const struct type_desc *type;
232 	unsigned one_dim_array_elems;
233 	unsigned two_dim_array_elems;
234 };
235 
236 /**
237  * Generate a vertex or fragment shader to test the given set of
238  * varyings.
239  */
240 static GLint
get_shader(bool is_vs,unsigned glsl_version,int num_varyings,struct varying_desc * varyings,enum test_array_type array_type)241 get_shader(bool is_vs, unsigned glsl_version, int num_varyings,
242 	   struct varying_desc *varyings, enum test_array_type array_type)
243 {
244 	GLuint shader;
245 	char *full_text = malloc(1000 * 100 + num_varyings);
246 	char *text = full_text;
247 	unsigned i, j, k, l, m;
248 	const char *varying_keyword;
249 	unsigned offset = 0;
250 	GLenum shader_type = is_vs ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER;
251 	bool fp64 = false;
252 
253 	if (glsl_version >= 130) {
254 		if (is_vs)
255 			varying_keyword = "out";
256 		else
257 			varying_keyword = "in";
258 	} else {
259 		varying_keyword = "varying";
260 	}
261 
262 	text += sprintf(text, "#version %u\n", glsl_version);
263 	if (array_type == ARRAYS_OF_ARRAYS)
264 		text += sprintf(text, "#extension GL_ARB_arrays_of_arrays: enable\n");
265 	for (i = 0; i < num_varyings; ++i) {
266 		const char *opt_flat_keyword = "";
267 		if (!fp64 && varyings[i].type->base == BASE_TYPE_DOUBLE) {
268 			text += sprintf(text, "#extension GL_ARB_gpu_shader_fp64: enable\n");
269 			fp64 = true;
270 		}
271 		if (varyings[i].type->base != BASE_TYPE_FLOAT)
272 			opt_flat_keyword = "flat ";
273 		if (varyings[i].two_dim_array_elems != 0) {
274 			text += sprintf(text, "%s%s %s var%03u[%u][%u];\n",
275 					opt_flat_keyword, varying_keyword,
276 					varyings[i].type->name, i,
277 					outer_dim_size,
278 					varyings[i].two_dim_array_elems);
279 		} else if (varyings[i].one_dim_array_elems != 0) {
280 			text += sprintf(text, "%s%s %s var%03u[%u];\n",
281 					opt_flat_keyword, varying_keyword,
282 					varyings[i].type->name, i,
283 					varyings[i].one_dim_array_elems);
284 		} else {
285 			text += sprintf(text, "%s%s %s var%03u;\n",
286 					opt_flat_keyword, varying_keyword,
287 					varyings[i].type->name, i);
288 		}
289 	}
290 	if (glsl_version >= 150 && is_vs) {
291 		text += sprintf(text, "in vec4 piglit_vertex;\n");
292 		text += sprintf(text, "#define gl_Vertex piglit_vertex\n");
293 	}
294 	text += sprintf(text, "uniform int i;\n");
295 	text += sprintf(text,
296 			"\n"
297 			"void main()\n"
298 			"{\n");
299 	if (is_vs)
300 		text += sprintf(text, "  gl_Position = gl_Vertex;\n");
301 	else
302 		text += sprintf(text, "  bool failed = false;\n");
303 	for (i = 0; i < num_varyings; ++i) {
304 		unsigned array_loop_bound;
305 		unsigned outer_array_loop_bound = 1;
306 		const char *base_type_name
307 			= get_base_type_name(varyings[i].type->base);
308 		if (varyings[i].two_dim_array_elems != 0) {
309 			outer_array_loop_bound = outer_dim_size;
310 			array_loop_bound = varyings[i].two_dim_array_elems;
311 		} else {
312 			array_loop_bound = varyings[i].one_dim_array_elems;
313 		}
314 		if (array_loop_bound == 0)
315 			array_loop_bound = 1;
316 		for (j = 0; j < outer_array_loop_bound; ++j) {
317 			for (k = 0; k < array_loop_bound; ++k) {
318 				for (l = 0; l < varyings[i].type->num_cols; ++l) {
319 					for (m = 0; m < varyings[i].type->num_rows; ++m) {
320 						text += sprintf(text, "  ");
321 						if (!is_vs)
322 							text += sprintf(text, "failed = failed || ");
323 						text += sprintf(text, "var%03u", i);
324 						if (varyings[i].two_dim_array_elems)
325 							text += sprintf(text, "[%u]", j);
326 						if (varyings[i].one_dim_array_elems || varyings[i].two_dim_array_elems)
327 							text += sprintf(text, "[%u]", k);
328 						if (varyings[i].type->num_cols > 1)
329 							text += sprintf(text, "[%u]", l);
330 						if (varyings[i].type->num_rows > 1)
331 							text += sprintf(text, "[%u]", m);
332 						if (is_vs)
333 							text += sprintf(text, " = ");
334 						else
335 							text += sprintf(text, " != ");
336 						text += sprintf(text, "%s(i + %u);\n",
337 								base_type_name,
338 								offset++);
339 					}
340 				}
341 			}
342 		}
343 	}
344 	if (!is_vs) {
345 		text += sprintf(text,
346 				"  if (failed)\n"
347 				"    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
348 				"  else\n"
349 				"    gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n");
350 	}
351 	text += sprintf(text, "}\n");
352 
353 	shader = piglit_compile_shader_text(shader_type, full_text);
354 
355 	free(full_text);
356 
357 	return shader;
358 }
359 
360 /**
361  * Choose the set of varyings necessary to properly run the given test
362  * configuration, given the implementation's reported value of
363  * max_varying_floats.
364  */
365 static unsigned
choose_varyings(struct varying_desc * varyings,const struct type_desc * test_type,enum test_array_type array_type,unsigned max_varying_floats)366 choose_varyings(struct varying_desc *varyings,
367 		const struct type_desc *test_type,
368 		enum test_array_type array_type,
369 		unsigned max_varying_floats)
370 {
371 	unsigned num_varyings = 0;
372 	unsigned element_size = test_type->base == BASE_TYPE_DOUBLE ? 2 : 1;
373 	unsigned components_in_test_type
374 		= test_type->num_cols * test_type->num_rows * element_size;
375 	unsigned num_test_varyings
376 		= max_varying_floats / components_in_test_type;
377 	unsigned num_two_dim_test_varyings
378 		 = num_test_varyings / outer_dim_size;
379 	unsigned num_extra_arrays = 0;
380 	unsigned num_extra_varyings
381 		= (max_varying_floats -
382 		   num_test_varyings * components_in_test_type) / element_size;
383 	unsigned i;
384 	if (array_type == ARRAYS_OF_ARRAYS) {
385 		varyings[num_varyings].type = test_type;
386 		varyings[num_varyings].two_dim_array_elems = num_two_dim_test_varyings;
387 		varyings[num_varyings].one_dim_array_elems = 0;
388 		num_extra_arrays
389 			= num_test_varyings - (num_two_dim_test_varyings * outer_dim_size);
390 		++num_varyings;
391 		if (num_extra_arrays > 0) {
392 			varyings[num_varyings].type = test_type;
393 			varyings[num_varyings].two_dim_array_elems = 0;
394 			varyings[num_varyings].one_dim_array_elems = num_extra_arrays;
395 			++num_varyings;
396 		}
397 	} else if (array_type == ARRAY) {
398 		varyings[num_varyings].type = test_type;
399 		varyings[num_varyings].two_dim_array_elems = 0;
400 		varyings[num_varyings].one_dim_array_elems = num_test_varyings;
401 		++num_varyings;
402 	} else {
403 		for (i = 0; i < num_test_varyings; ++i) {
404 			varyings[num_varyings].type = test_type;
405 			varyings[num_varyings].two_dim_array_elems = 0;
406 			varyings[num_varyings].one_dim_array_elems = 0;
407 			++num_varyings;
408 		}
409 	}
410 	for (i = 0; i < num_extra_varyings; ++i) {
411 		switch(test_type->base) {
412 		case BASE_TYPE_UINT:
413 			varyings[num_varyings].type = &uint_type;
414 			break;
415 		case BASE_TYPE_INT:
416 			varyings[num_varyings].type = &int_type;
417 			break;
418 		case BASE_TYPE_FLOAT:
419 			varyings[num_varyings].type = &float_type;
420 			break;
421 		case BASE_TYPE_DOUBLE:
422 			varyings[num_varyings].type = &double_type;
423 			break;
424 		}
425 		varyings[num_varyings].two_dim_array_elems = 0;
426 		varyings[num_varyings].one_dim_array_elems = 0;
427 		++num_varyings;
428 	}
429 
430 	return num_varyings;
431 }
432 
433 void
print_usage_and_exit(const char * prog_name)434 NORETURN print_usage_and_exit(const char *prog_name)
435 {
436 	unsigned i;
437 	printf("Usage: %s <type> <arrayspec>\n"
438 	       "  where <type> is one of:\n", prog_name);
439 	for (i = 0; all_types[i]; ++i)
440 		printf("    %s\n", all_types[i]->name);
441 	printf("  and <arrayspec> is one of:\n"
442 	       "    array: test using an array of the above type\n"
443 	       "    arrays_of_arrays: test using a multidimensional array"
444 	       " of the above type\n"
445 	       "    separate: test using separately declared varyings\n");
446 	piglit_report_result(PIGLIT_FAIL);
447 }
448 
449 static const struct type_desc *test_type;
450 
451 static void
parse_args(int argc,char * argv[],struct piglit_gl_test_config * config)452 parse_args(int argc, char *argv[], struct piglit_gl_test_config *config)
453 {
454 	unsigned i;
455 
456 	if (argc < 3)
457 		print_usage_and_exit(argv[0]);
458 	for (i = 0; all_types[i]; ++i) {
459 		if (strcmp(argv[1], all_types[i]->name) == 0)
460 			break;
461 	}
462 	if (all_types[i])
463 		test_type = all_types[i];
464 	else
465 		print_usage_and_exit(argv[0]);
466 
467 	if (test_type->glsl_version_required <= 110)
468 		config->supports_gl_compat_version = 20;
469 	else if (test_type->glsl_version_required <= 120)
470 		config->supports_gl_compat_version = 21;
471 	else if (test_type->glsl_version_required <= 130)
472 		config->supports_gl_compat_version = 30;
473 	else if (test_type->glsl_version_required <= 150)
474 		config->supports_gl_core_version = 32;
475 	else
476 		piglit_report_result(PIGLIT_FAIL);
477 }
478 
479 void
piglit_init(int argc,char ** argv)480 piglit_init(int argc, char **argv)
481 {
482 	enum test_array_type array_type;
483 	GLint max_varying_floats;
484 	struct varying_desc *varyings;
485 	unsigned num_varyings;
486 	unsigned glsl_version;
487 	GLuint vs, fs;
488 
489 	if (argc != 3)
490 		print_usage_and_exit(argv[0]);
491 
492 	glsl_version = test_type->glsl_version_required;
493 
494 	if (strcmp(argv[2], "array") == 0)
495 		array_type = ARRAY;
496 	else if (strcmp(argv[2], "separate") == 0)
497 		array_type = SEPARATE;
498 	else if (strcmp(argv[2], "arrays_of_arrays") == 0) {
499 		array_type = ARRAYS_OF_ARRAYS;
500 		piglit_require_extension("GL_ARB_arrays_of_arrays");
501 		if (glsl_version < 120)
502 			glsl_version = 120;
503 	} else
504 		print_usage_and_exit(argv[0]);
505 
506 	piglit_require_gl_version(20);
507 	piglit_require_GLSL_version(glsl_version);
508 	if (test_type->base == BASE_TYPE_DOUBLE)
509 		piglit_require_extension("GL_ARB_gpu_shader_fp64");
510 	glGetIntegerv(GL_MAX_VARYING_FLOATS, &max_varying_floats);
511 
512 	varyings = malloc(sizeof(*varyings) * max_varying_floats);
513 	num_varyings = choose_varyings(varyings, test_type,
514 				       array_type, max_varying_floats);
515 
516 	vs = get_shader(true, test_type->glsl_version_required,
517 			num_varyings, varyings, array_type);
518 	fs = get_shader(false, test_type->glsl_version_required,
519 			num_varyings, varyings, array_type);
520 	prog = piglit_link_simple_program(vs, fs);
521 	i_location = glGetUniformLocation(prog, "i");
522 	free(varyings);
523 }
524 
525 enum piglit_result
piglit_display(void)526 piglit_display(void)
527 {
528 	GLboolean pass = GL_TRUE;
529 	GLuint vao;
530 	float green[] = { 0.0, 1.0, 0.0, 1.0 };
531 
532 	glClear(GL_COLOR_BUFFER_BIT);
533 	glUseProgram(prog);
534 	glUniform1i(i_location, 0);
535 	if (piglit_is_core_profile) {
536 		glGenVertexArrays(1, &vao);
537 		glBindVertexArray(vao);
538 	}
539 	piglit_draw_rect(-1, -1, 2, 2);
540 	pass = piglit_probe_rect_rgba(0, 0, piglit_width, piglit_height, green)
541 		&& pass;
542 
543 	piglit_present_results();
544 
545 	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
546 }
547