1 /*
2 * Copyright (c) 2018 Advanced Micro Devices
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 /**
25 * \file tes-gs-max-output.cpp
26 *
27 * Stress the limits of what tessellation + geometry shaders can output using
28 * generic shaders with points as input and output primitives, allowing
29 * arbitrary:
30 * - number of input instances (instanced draws)
31 * - number of input patches per instance
32 * - (integer) tessellation factors
33 * - number of invocations (GS instances)
34 * - number of output vertices per invocation
35 * - number of output components per vertex
36 *
37 * Verification works by rendering points and writing to an SSBO from the
38 * fragment shader.
39 */
40
41 #include "piglit-util-gl.h"
42
43 #include <algorithm>
44 #include <map>
45 #include <set>
46 #include <vector>
47
48 #define WINDOW_SIZE 256
49
50 PIGLIT_GL_TEST_CONFIG_BEGIN
51
52 config.supports_gl_compat_version = 32;
53 config.supports_gl_core_version = 32;
54 config.window_width = WINDOW_SIZE;
55 config.window_height = WINDOW_SIZE;
56 config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGBA;
57 config.khr_no_error_support = PIGLIT_NO_ERRORS;
58
59 PIGLIT_GL_TEST_CONFIG_END
60
61 #define PASTE(x) #x
62 #define STR(x) PASTE(x)
63
64 struct testcase {
65 unsigned num_instances; /* draw instances */
66 unsigned num_patches; /* draw size / count */
67 unsigned tessfactor_u;
68 unsigned tessfactor_v;
69 unsigned num_invocations; /* GS invocations / instances */
70 unsigned num_outputs; /* # vertex ouput per GS invocation */
71 unsigned num_extra_components; /* # extra components per GS output vertex */
72
operator <testcase73 bool operator<(const testcase &o) const {
74 if (num_instances < o.num_instances)
75 return true;
76 if (num_instances > o.num_instances)
77 return false;
78
79 if (num_patches < o.num_patches)
80 return true;
81 if (num_patches > o.num_patches)
82 return false;
83
84 if (tessfactor_u < o.tessfactor_u)
85 return true;
86 if (tessfactor_u > o.tessfactor_u)
87 return false;
88
89 if (tessfactor_v < o.tessfactor_v)
90 return true;
91 if (tessfactor_v > o.tessfactor_v)
92 return false;
93
94 if (num_invocations < o.num_invocations)
95 return true;
96 if (num_invocations > o.num_invocations)
97 return false;
98
99 if (num_outputs < o.num_outputs)
100 return true;
101 if (num_outputs > o.num_outputs)
102 return false;
103
104 return num_extra_components < o.num_extra_components;
105 }
106 };
107
108 struct fragmentshaderkey {
109 unsigned num_extra_components;
110
operator <fragmentshaderkey111 bool operator<(const fragmentshaderkey &o) const {
112 return num_extra_components < o.num_extra_components;
113 }
114 };
115
116 struct geometryshaderkey {
117 unsigned num_invocations;
118 unsigned num_outputs;
119 unsigned num_extra_components;
120
operator <geometryshaderkey121 bool operator<(const geometryshaderkey &o) const {
122 if (num_invocations < o.num_invocations)
123 return true;
124 if (num_invocations > o.num_invocations)
125 return false;
126 if (num_outputs < o.num_outputs)
127 return true;
128 if (num_outputs > o.num_outputs)
129 return false;
130 return num_extra_components < o.num_extra_components;
131 }
132 };
133
134 static std::map<fragmentshaderkey, GLuint> fragmentshaders;
135 static std::map<geometryshaderkey, GLuint> testprograms;
136
137 static const struct testcase default_testcase = {
138 1, 1, 1, 1, 1, 1, 0,
139 };
140
141 static int32_t *buffer_copy;
142
143 static const unsigned max_final_points = 2 * 1024 * 1024; /* requires 16 MiB buffer */
144 static bool small = false;
145 static GLuint vs_shader;
146 static GLuint tcs_shader;
147 static GLuint tes_shader;
148 static GLuint vao;
149 static GLuint ssbo;
150 static std::vector<testcase> testcases;
151 static std::set<testcase> testcases_set;
152 static GLuint max_tessfactor;
153 static GLuint max_gs_invocations;
154 static GLuint max_gs_out_vertices;
155 static GLuint max_gs_total_out_components;
156 static GLuint max_gs_out_components;
157 static unsigned max_gs_out_vertices_real;
158
159 static const char vs_text[] =
160 "#version 150\n"
161 "\n"
162 "uniform int u_verts_per_instance;\n"
163 "\n"
164 "out int vs_tcs_id;\n"
165 "\n"
166 "void main() {\n"
167 " vs_tcs_id = gl_InstanceID * u_verts_per_instance + gl_VertexID;\n"
168 "}\n";
169
170 static const char tcs_text[] =
171 "#version 150\n"
172 "#extension GL_ARB_tessellation_shader : require\n"
173 "layout(vertices = 1) out;\n"
174 "\n"
175 "in int vs_tcs_id[];\n"
176 "\n"
177 "out int tcs_tes_id[];\n"
178 "\n"
179 "uniform int u_tessfactor_u;\n"
180 "uniform int u_tessfactor_v;\n"
181 "\n"
182 "void main() {\n"
183 " tcs_tes_id[gl_InvocationID] = vs_tcs_id[gl_InvocationID];\n"
184 " gl_TessLevelOuter[0] = u_tessfactor_v;\n"
185 " gl_TessLevelOuter[1] = u_tessfactor_u;\n"
186 "}\n";
187
188 static const char tes_text[] =
189 "#version 150\n"
190 "#extension GL_ARB_tessellation_shader : require\n"
191 "layout(isolines, equal_spacing) in;\n"
192 "\n"
193 "in int tcs_tes_id[];\n"
194 "\n"
195 "out int tes_gs_id;\n"
196 "\n"
197 "void main() {\n"
198 " tes_gs_id = tcs_tes_id[0];\n"
199 " gl_Position.x = gl_TessCoord[0];\n"
200 " gl_Position.y = gl_TessCoord[1];\n"
201 "}\n";
202
203 /* Those numbers really don't matter much for what we're trying to do here. */
204 #define GEN_SEQUENCE \
205 "int seq_next(int x) {\n" \
206 " x = (x + 1) * 709900053;\n" \
207 " x = x ^ (x >> 17);\n" \
208 " return x;\n" \
209 "}\n"
210
211 static const char gs_text[] =
212 "#version 150\n"
213 "#extension GL_ARB_gpu_shader5 : require\n"
214 "\n"
215 "#define NUM_INVOCATIONS %d\n"
216 "#define NUM_OUT_VERTICES %d\n"
217 "#define NUM_EXTRA_COMPONENTS %d\n"
218 "\n"
219 "layout(lines, invocations = NUM_INVOCATIONS) in;\n"
220 "layout(points, max_vertices = NUM_OUT_VERTICES) out;\n"
221 "\n"
222 "uniform int u_tessfactor_u;\n"
223 "uniform int u_tessfactor_v;\n"
224 "\n"
225 "in int tes_gs_id[];\n"
226 "\n"
227 "flat out int gs_ps_data[1 + NUM_EXTRA_COMPONENTS];\n"
228 "\n"
229 GEN_SEQUENCE
230 "\n"
231 "void main() {\n"
232 " int in_id = tes_gs_id[0] * u_tessfactor_u * u_tessfactor_v;\n"
233 " float v = gl_in[0].gl_Position.y;\n"
234 " in_id += u_tessfactor_u * int(v * u_tessfactor_v + 0.5);\n"
235 " float u = min(gl_in[0].gl_Position.x, gl_in[1].gl_Position.x);\n"
236 " in_id += int(u * u_tessfactor_u + 0.5);\n"
237 "\n"
238 " for (int i = 0; i < NUM_OUT_VERTICES; ++i) {\n"
239 " uint id = (in_id * NUM_INVOCATIONS + gl_InvocationID) * NUM_OUT_VERTICES + i;\n"
240 " uint x = id %% " STR(WINDOW_SIZE) "u;\n"
241 " uint y = (id / " STR(WINDOW_SIZE) "u) %% " STR(WINDOW_SIZE) "u;\n"
242 " gl_Position.x = (float(x) + 0.5) / " STR(WINDOW_SIZE) " * 2.0 - 1.0;\n"
243 " gl_Position.y = (float(y) + 0.5) / " STR(WINDOW_SIZE) " * 2.0 - 1.0;\n"
244 " gl_Position.z = 0.0;\n"
245 " gl_Position.w = 1.0;\n"
246 "\n"
247 " int val = int(id);\n"
248 " for (int j = 0; j <= NUM_EXTRA_COMPONENTS; ++j) {\n"
249 " gs_ps_data[j] = val;\n"
250 " val = seq_next(val);\n"
251 " }\n"
252 "\n"
253 " EmitVertex();\n"
254 " }\n"
255 "}\n";
256
257 static const char fs_text[] =
258 "#version 150\n"
259 "#extension GL_ARB_shader_storage_buffer_object : require\n"
260 "\n"
261 "#define NUM_EXTRA_COMPONENTS %d\n"
262 "\n"
263 "flat in int gs_ps_data[1 + NUM_EXTRA_COMPONENTS];\n"
264 "out vec4 out_color;\n"
265 "\n"
266 "layout(std430, binding = 0) buffer SSBO {\n"
267 " ivec2 data[];\n"
268 "} ssbo;\n"
269 "\n"
270 GEN_SEQUENCE
271 "\n"
272 "void main() {\n"
273 " int id = gs_ps_data[0];\n"
274 " int screen_id = int(gl_FragCoord.y) * " STR(WINDOW_SIZE) " + int(gl_FragCoord.x);\n"
275 " if (screen_id != id %% (" STR(WINDOW_SIZE * WINDOW_SIZE) ")) {\n"
276 " ssbo.data[id].x = 1000;\n"
277 " ssbo.data[id].y = screen_id;\n"
278 " out_color = vec4(0.1, 0, 0, 1);\n"
279 " return;\n"
280 " }\n"
281 "\n"
282 " int val = id;\n"
283 " for (int j = 0; j <= NUM_EXTRA_COMPONENTS; ++j) {\n"
284 " if (val != gs_ps_data[j]) {\n"
285 " ssbo.data[id].x = 2000 + j;\n"
286 " ssbo.data[id].y = gs_ps_data[j];\n"
287 " out_color = vec4(0, 0.1, 0, 1);\n"
288 " return;\n"
289 " }\n"
290 " val = seq_next(val);\n"
291 " }\n"
292 "\n"
293 " ssbo.data[id].x = 1;\n"
294 " out_color = vec4(0, 0, 0, 1);\n"
295 "}\n";
296
297 static void
print_testcase(const struct testcase * tc)298 print_testcase(const struct testcase *tc)
299 {
300 printf("Case: instances = %u patches = %u tessfactor = %u,%u invocations = %u "
301 "outputs = %u extra_components = %u\n",
302 tc->num_instances, tc->num_patches, tc->tessfactor_u, tc->tessfactor_v,
303 tc->num_invocations, tc->num_outputs, tc->num_extra_components);
304 }
305
306 static void
add_testcase(const struct testcase * tc)307 add_testcase(const struct testcase *tc)
308 {
309 if (!testcases_set.insert(*tc).second)
310 return;
311
312 if (tc->num_instances > 64 * 1024 ||
313 tc->num_patches > 64 * 1024 ||
314 tc->tessfactor_u > 64 * 1024 ||
315 tc->tessfactor_v > 64 * 1024 ||
316 tc->num_invocations > 64 * 1024 ||
317 tc->num_outputs > 64 * 1024 ||
318 tc->num_extra_components > 64 * 1024) {
319 fprintf(stderr, "Excessive test case size. Are you sure?\n");
320 print_testcase(tc);
321 exit(1);
322 }
323
324 /* Multiple separate multiplies to avoid integer wraparound */
325 if ((uint64_t)tc->num_instances * tc->num_patches * tc->tessfactor_u > max_final_points ||
326 (uint64_t)tc->tessfactor_v * tc->num_invocations * tc->num_outputs > max_final_points ||
327 (uint64_t)tc->num_instances * tc->num_patches * tc->tessfactor_u *
328 tc->tessfactor_v * tc->num_invocations * tc->num_outputs > max_final_points) {
329 fprintf(stderr, "Test case has more than %u final points.\n", max_final_points);
330 print_testcase(tc);
331 exit(1);
332 }
333
334 /* Check against implementation-defined limits. */
335 if (tc->tessfactor_u > max_tessfactor || tc->tessfactor_v > max_tessfactor) {
336 fprintf(stderr, "Tessellation factor too high (max: %u)\n",
337 max_tessfactor);
338 print_testcase(tc);
339 exit(1);
340 }
341 if (tc->num_outputs > max_gs_out_vertices) {
342 fprintf(stderr, "Too many output vertices (max: %d)\n",
343 max_gs_out_vertices);
344 print_testcase(tc);
345 exit(1);
346 }
347 if (tc->num_outputs * (5 + tc->num_extra_components) > max_gs_total_out_components) {
348 fprintf(stderr, "Too many output components (max: %d)\n",
349 max_gs_total_out_components);
350 print_testcase(tc);
351 exit(1);
352 }
353 if (tc->num_invocations > max_gs_invocations) {
354 fprintf(stderr, "Too many GS invocations (max: %d)\n",
355 max_gs_invocations);
356 print_testcase(tc);
357 exit(1);
358 }
359
360 /* Compile GS shader and link program */
361 geometryshaderkey gskey;
362 gskey.num_invocations = tc->num_invocations;
363 gskey.num_outputs = tc->num_outputs;
364 gskey.num_extra_components = tc->num_extra_components;
365 if (testprograms.find(gskey) == testprograms.end()) {
366 char *text;
367
368 fragmentshaderkey fskey;
369 fskey.num_extra_components = tc->num_extra_components;
370 std::map<fragmentshaderkey, GLuint>::const_iterator fsit =
371 fragmentshaders.find(fskey);
372 if (fsit == fragmentshaders.end()) {
373 if (asprintf(&text, fs_text, tc->num_extra_components) < 0)
374 abort();
375 GLuint fs_shader =
376 piglit_compile_shader_text(GL_FRAGMENT_SHADER, text);
377 free(text);
378
379 fsit = fragmentshaders.insert(std::make_pair(fskey, fs_shader)).first;
380 }
381
382 if (asprintf(&text, gs_text, tc->num_invocations, tc->num_outputs,
383 tc->num_extra_components) < 0)
384 abort();
385 GLuint gs_shader =
386 piglit_compile_shader_text(GL_GEOMETRY_SHADER, text);
387 free(text);
388
389 GLuint prog = glCreateProgram();
390 glAttachShader(prog, vs_shader);
391 glAttachShader(prog, tcs_shader);
392 glAttachShader(prog, tes_shader);
393 glAttachShader(prog, gs_shader);
394 glAttachShader(prog, fsit->second);
395 glLinkProgram(prog);
396 if (!piglit_link_check_status(prog))
397 piglit_report_result(PIGLIT_FAIL);
398
399 glDeleteShader(gs_shader);
400
401 testprograms.insert(std::make_pair(gskey, prog));
402 }
403
404 testcases.push_back(*tc);
405 }
406
407 static bool
run_testcase(const struct testcase * tc)408 run_testcase(const struct testcase *tc)
409 {
410 unsigned final_points = tc->num_instances * tc->num_patches * tc->tessfactor_u *
411 tc->tessfactor_v * tc->num_invocations * tc->num_outputs;
412 unsigned bufsize = 2 * sizeof(int32_t) * final_points;
413
414 print_testcase(tc);
415
416 glClearColor(0, 0, 0, 1);
417 glClear(GL_COLOR_BUFFER_BIT);
418
419 geometryshaderkey gskey;
420 gskey.num_invocations = tc->num_invocations;
421 gskey.num_outputs = tc->num_outputs;
422 gskey.num_extra_components = tc->num_extra_components;
423 std::map<geometryshaderkey, GLuint>::const_iterator progit =
424 testprograms.find(gskey);
425 assert(progit != testprograms.end());
426
427 glUseProgram(progit->second);
428 glPatchParameteri(GL_PATCH_VERTICES, 1);
429 glUniform1i(glGetUniformLocation(progit->second, "u_tessfactor_u"),
430 tc->tessfactor_u);
431 glUniform1i(glGetUniformLocation(progit->second, "u_tessfactor_v"),
432 tc->tessfactor_v);
433 glUniform1i(glGetUniformLocation(progit->second, "u_verts_per_instance"),
434 tc->num_patches);
435
436 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
437
438 memset(buffer_copy, 0, bufsize);
439 glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, bufsize, buffer_copy);
440
441 glEnable(GL_BLEND);
442 glBlendFunc(GL_ONE, GL_ONE);
443
444 glDrawArraysInstanced(GL_PATCHES, 0, tc->num_patches, tc->num_instances);
445
446 glDisable(GL_BLEND);
447
448 if (!piglit_check_gl_error(GL_NO_ERROR))
449 return false;
450
451 static const float expected[] = { 0, 0, 0, 1 };
452 bool ok = true;
453
454 if (!piglit_probe_rect_rgba(0, 0, WINDOW_SIZE, WINDOW_SIZE, expected))
455 ok = false;
456
457 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, bufsize, buffer_copy);
458
459 for (unsigned i = 0; i < final_points; ++i) {
460 if (buffer_copy[2 * i] != 1) {
461 printf("Error @ %d: %d %d\n", i,
462 buffer_copy[2 * i], buffer_copy[2 * i + 1]);
463 ok = false;
464 }
465 }
466
467 return ok;
468 }
469
470
471 static void
generate_testcases_max2(const testcase & tc,bool explicit_instances,bool explicit_patches)472 generate_testcases_max2(const testcase &tc, bool explicit_instances, bool explicit_patches)
473 {
474 unsigned amplify = tc.tessfactor_u * tc.tessfactor_v * tc.num_invocations * tc.num_outputs;
475 unsigned target_in = max_final_points / amplify;
476
477 if (small)
478 target_in = MIN2(4, target_in);
479
480 if (!explicit_instances) {
481 testcase tc1 = tc;
482 tc1.num_instances = MAX2(1, target_in / tc1.num_patches);
483 add_testcase(&tc1);
484 }
485
486 if (!explicit_patches) {
487 testcase tc1 = tc;
488 tc1.num_patches = MAX2(1, target_in / tc1.num_instances);
489 add_testcase(&tc1);
490 }
491
492 if (!explicit_instances && !explicit_patches) {
493 testcase tc1 = tc;
494 tc1.num_instances = MAX2(1, (unsigned)sqrt(target_in));
495 tc1.num_patches = MAX2(1, target_in / tc1.num_instances);
496 add_testcase(&tc1);
497 }
498
499 if (explicit_instances && explicit_patches)
500 add_testcase(&tc);
501 }
502
503 static void
generate_testcases_max1(const testcase & tc,bool explicit_instances,bool explicit_patches,bool explicit_tessfactor_u,bool explicit_tessfactor_v,unsigned tess_out_max)504 generate_testcases_max1(const testcase &tc, bool explicit_instances, bool explicit_patches,
505 bool explicit_tessfactor_u, bool explicit_tessfactor_v,
506 unsigned tess_out_max)
507 {
508 if (!explicit_tessfactor_u) {
509 testcase tc1 = tc;
510 tc1.tessfactor_u = MIN2(MAX2(1, tess_out_max / tc1.tessfactor_v),
511 max_tessfactor);
512 generate_testcases_max2(tc1, explicit_instances, explicit_patches);
513 }
514
515 if (!explicit_tessfactor_v) {
516 testcase tc1 = tc;
517 tc1.tessfactor_v = MIN2(MAX2(1, tess_out_max / tc1.tessfactor_u),
518 max_tessfactor);
519 generate_testcases_max2(tc1, explicit_instances, explicit_patches);
520 }
521
522 if (!explicit_tessfactor_u && !explicit_tessfactor_v) {
523 testcase tc1 = tc;
524 tc1.tessfactor_u = MIN2(MAX2(1, (unsigned)sqrt(tess_out_max)),
525 max_tessfactor);
526 tc1.tessfactor_v = MIN2(MAX2(1, tess_out_max / tc1.tessfactor_u),
527 max_tessfactor);
528 generate_testcases_max2(tc1, explicit_instances, explicit_patches);
529 }
530
531 if (explicit_tessfactor_u && explicit_tessfactor_v)
532 generate_testcases_max2(tc, explicit_instances, explicit_patches);
533 }
534
535 static void
generate_testcases_max(const testcase & tc,bool explicit_instances,bool explicit_patches,bool explicit_tessfactor_u,bool explicit_tessfactor_v)536 generate_testcases_max(const testcase &tc, bool explicit_instances, bool explicit_patches,
537 bool explicit_tessfactor_u, bool explicit_tessfactor_v)
538 {
539 unsigned amplify = tc.num_invocations * tc.num_outputs;
540 unsigned tess_out_max = max_final_points / amplify;
541
542 if (small) {
543 generate_testcases_max1(tc, explicit_instances, explicit_patches,
544 explicit_tessfactor_u, explicit_tessfactor_v,
545 MIN2(4, tess_out_max));
546 } else {
547 generate_testcases_max1(tc, explicit_instances, explicit_patches,
548 explicit_tessfactor_u, explicit_tessfactor_v,
549 tess_out_max);
550 while (tess_out_max > 4) {
551 tess_out_max = sqrt(tess_out_max);
552 generate_testcases_max1(tc, explicit_instances, explicit_patches,
553 explicit_tessfactor_u, explicit_tessfactor_v,
554 tess_out_max);
555 }
556 }
557 }
558
559 static float
rand_subdivide(int partitions)560 rand_subdivide(int partitions)
561 {
562 double x = 1.0;
563
564 for (int i = 1; i < partitions; ++i)
565 x = std::min(x, (double)rand() / ((double)RAND_MAX + 1));
566
567 return x;
568 }
569
570 void
piglit_init(int argc,char ** argv)571 piglit_init(int argc, char **argv)
572 {
573 bool explicit_instances = false;
574 bool explicit_patches = false;
575 bool explicit_tessfactor_u = false;
576 bool explicit_tessfactor_v = false;
577 bool explicit_invocations = false;
578 bool explicit_outputs = false;
579 bool explicit_components = false;
580 bool scan_mode = false;
581 unsigned scan_seed = 0;
582 unsigned scan_count = 0;
583 struct testcase explicit_testcase;
584
585 piglit_require_extension("GL_ARB_tessellation_shader");
586 piglit_require_extension("GL_ARB_shader_storage_buffer_object");
587
588 memcpy(&explicit_testcase, &default_testcase, sizeof(explicit_testcase));
589
590 int i;
591 for (i = 1; i < argc; ++i) {
592 if (!strcmp(argv[i], "-small")) {
593 small = true;
594 } else {
595 if (i + 1 >= argc)
596 break;
597
598 if (!strcmp(argv[i], "-instances")) {
599 explicit_testcase.num_instances = atoi(argv[i + 1]);
600 explicit_instances = true;
601 i++;
602 } else if (!strcmp(argv[i], "-patches")) {
603 explicit_testcase.num_patches = atoi(argv[i + 1]);
604 explicit_patches = true;
605 i++;
606 } else if (!strcmp(argv[i], "-tessfactor_u")) {
607 explicit_testcase.tessfactor_u = atoi(argv[i + 1]);
608 explicit_tessfactor_u = true;
609 i++;
610 } else if (!strcmp(argv[i], "-tessfactor_v")) {
611 explicit_testcase.tessfactor_v = atoi(argv[i + 1]);
612 explicit_tessfactor_v = true;
613 i++;
614 } else if (!strcmp(argv[i], "-invocations")) {
615 explicit_testcase.num_invocations = atoi(argv[i + 1]);
616 explicit_invocations = true;
617 i++;
618 } else if (!strcmp(argv[i], "-outputs")) {
619 explicit_testcase.num_outputs = atoi(argv[i + 1]);
620 explicit_outputs = true;
621 i++;
622 } else if (!strcmp(argv[i], "-components")) {
623 explicit_testcase.num_extra_components = atoi(argv[i + 1]);
624 explicit_components = true;
625 i++;
626 } else {
627 if (i + 2 >= argc)
628 break;
629
630 if (!strcmp(argv[i], "-scan")) {
631 scan_seed = atoi(argv[i + 1]);
632 scan_count = atoi(argv[i + 2]);
633 scan_mode = true;
634 i += 2;
635 } else
636 break;
637 }
638 }
639 }
640 if (i < argc) {
641 fprintf(stderr, "Unknown argument or too few params: %s\n", argv[i]);
642 exit(1);
643 }
644
645 /* Various GL objects needed by the test */
646 vs_shader = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_text);
647 if (!piglit_check_gl_error(GL_NO_ERROR))
648 piglit_report_result(PIGLIT_FAIL);
649
650 tcs_shader = piglit_compile_shader_text(GL_TESS_CONTROL_SHADER, tcs_text);
651 if (!piglit_check_gl_error(GL_NO_ERROR))
652 piglit_report_result(PIGLIT_FAIL);
653
654 tes_shader = piglit_compile_shader_text(GL_TESS_EVALUATION_SHADER, tes_text);
655 if (!piglit_check_gl_error(GL_NO_ERROR))
656 piglit_report_result(PIGLIT_FAIL);
657
658 glGenVertexArrays(1, &vao);
659 glBindVertexArray(vao);
660
661 glGenBuffers(1, &ssbo);
662 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
663 glBufferData(GL_SHADER_STORAGE_BUFFER, max_final_points * 8, NULL, GL_DYNAMIC_READ);
664
665 buffer_copy = (int32_t *)calloc(2 * sizeof(int32_t), max_final_points);
666
667 glGetIntegerv(GL_MAX_TESS_GEN_LEVEL, (GLint*)&max_tessfactor);
668 glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, (GLint*)&max_gs_out_vertices);
669 glGetIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS,
670 (GLint*)&max_gs_total_out_components);
671 glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS,
672 (GLint*)&max_gs_out_components);
673 glGetIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS, (GLint*)&max_gs_invocations);
674 if (!piglit_check_gl_error(GL_NO_ERROR))
675 piglit_report_result(PIGLIT_FAIL);
676
677 max_gs_out_vertices_real = MIN2(max_gs_out_vertices,
678 max_gs_total_out_components / 5);
679
680 if (scan_mode) {
681 srand(scan_seed);
682
683 /* First, generate test cases that max out each of the dimensions */
684 testcase tc0 = explicit_testcase;
685 if (!explicit_invocations)
686 tc0.num_invocations = max_gs_invocations;
687
688 if (!explicit_outputs) {
689 testcase tc1 = tc0;
690
691 if (!explicit_components) {
692 tc1.num_outputs = max_gs_out_vertices_real;
693 tc1.num_extra_components =
694 MIN2(max_gs_total_out_components / tc1.num_outputs,
695 max_gs_out_components) - 5;
696 } else {
697 tc1.num_outputs =
698 MIN2(max_gs_total_out_components /
699 (5 + tc1.num_extra_components),
700 max_gs_out_vertices_real);
701 }
702
703 generate_testcases_max(tc1, explicit_instances, explicit_patches,
704 explicit_tessfactor_u, explicit_tessfactor_v);
705 }
706
707 if (!explicit_components) {
708 testcase tc1 = tc0;
709
710 if (!explicit_outputs) {
711 tc1.num_extra_components = max_gs_out_components - 5;
712 tc1.num_outputs =
713 MIN2(max_gs_total_out_components /
714 (5 + tc1.num_extra_components),
715 max_gs_out_vertices_real);
716 } else {
717 tc1.num_extra_components =
718 MIN2(max_gs_total_out_components / tc1.num_outputs,
719 max_gs_out_components) - 4;
720 }
721
722 generate_testcases_max(tc1, explicit_instances, explicit_patches,
723 explicit_tessfactor_u, explicit_tessfactor_v);
724 }
725
726 if (explicit_outputs && explicit_components)
727 generate_testcases_max(tc0, explicit_instances, explicit_patches,
728 explicit_tessfactor_u, explicit_tessfactor_v);
729
730 /* Generate additional tests randomly.
731 *
732 * Attempt to generate a random distribution that isn't too
733 * lop-sided, but admittedly this is all just hand-wavey
734 * heuristics.
735 */
736 while (testcases.size() < scan_count) {
737 testcase tc = explicit_testcase;
738
739 if (!explicit_outputs || !explicit_components) {
740 if (explicit_outputs || rand() & 1) {
741 unsigned max_components =
742 MIN2(max_gs_total_out_components / tc.num_outputs,
743 max_gs_out_components) - 5;
744 tc.num_extra_components = rand() % (max_components + 1);
745
746 if (!explicit_outputs) {
747 unsigned max_outputs =
748 MIN2(max_gs_total_out_components /
749 (5 + tc.num_extra_components),
750 max_gs_out_vertices_real);
751 tc.num_outputs = 1 + rand() % max_outputs;
752 }
753 } else {
754 unsigned max_outputs =
755 MIN2(max_gs_total_out_components /
756 (5 + tc.num_extra_components),
757 max_gs_out_vertices_real);
758 tc.num_outputs = 1 + rand() % max_outputs;
759
760 if (!explicit_components) {
761 unsigned max_components =
762 MIN2(max_gs_total_out_components / tc.num_outputs,
763 max_gs_out_components) - 5;
764 tc.num_extra_components = rand() % (max_components + 1);
765 }
766 }
767 }
768
769 unsigned amplify = tc.num_outputs;
770
771 if (explicit_invocations)
772 amplify *= tc.num_invocations;
773 if (explicit_tessfactor_u)
774 amplify *= tc.tessfactor_u;
775 if (explicit_tessfactor_v)
776 amplify *= tc.tessfactor_v;
777 if (explicit_patches)
778 amplify *= tc.num_patches;
779 if (explicit_instances)
780 amplify *= tc.num_instances;
781
782 unsigned target = max_final_points / amplify;
783
784 if (small)
785 target = MIN2(32, target);
786
787 if (!explicit_tessfactor_u) {
788 float tf_log_weight = logf(target) * rand_subdivide(6);
789 tc.tessfactor_u = MIN2(expf(tf_log_weight), max_tessfactor);
790 target /= tc.tessfactor_u;
791 }
792 if (!explicit_tessfactor_v) {
793 float tf_log_weight = logf(target) * rand_subdivide(6);
794 tc.tessfactor_v = MIN2(expf(tf_log_weight), max_tessfactor);
795 target /= tc.tessfactor_v;
796 }
797 if (!explicit_invocations) {
798 float log_weight = logf(target);
799 if (!explicit_instances || !explicit_patches)
800 log_weight *= rand_subdivide(2);
801 tc.num_invocations = MIN2(expf(log_weight), max_gs_invocations);
802 target /= tc.num_invocations;
803 }
804 if (!explicit_instances) {
805 float log_weight = logf(target);
806 if (!explicit_patches)
807 log_weight *= rand_subdivide(2);
808 tc.num_instances = expf(log_weight);
809 target /= tc.num_instances;
810 }
811 if (!explicit_patches)
812 tc.num_patches = 1 + rand() % target;
813
814 add_testcase(&tc);
815 }
816 } else {
817 add_testcase(&explicit_testcase);
818 }
819 }
820
821 enum piglit_result
piglit_display(void)822 piglit_display(void)
823 {
824 bool pass = true;
825
826 for (unsigned i = 0; i < testcases.size(); ++i) {
827 if (!run_testcase(&testcases[i]))
828 pass = false;
829 }
830
831 if (!piglit_check_gl_error(GL_NO_ERROR))
832 pass = false;
833
834 piglit_present_results();
835
836 return pass ? PIGLIT_PASS : PIGLIT_FAIL;
837 }
838