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