ext_gpu_shader4: add compiler tests for everything
[piglit.git] / tests / spec / arb_tessellation_shader / tes-gs-max-output.cpp
blob3f31cfe5d9c6ed4ed32ab92bdd2e84d7a2d1fc2b
1 /*
2 * Copyright (c) 2018 Advanced Micro Devices
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:
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.
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.
24 /**
25 * \file tes-gs-max-output.cpp
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
37 * Verification works by rendering points and writing to an SSBO from the
38 * fragment shader.
41 #include "piglit-util-gl.h"
43 #include <algorithm>
44 #include <map>
45 #include <set>
46 #include <vector>
48 #define WINDOW_SIZE 256
50 PIGLIT_GL_TEST_CONFIG_BEGIN
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;
59 PIGLIT_GL_TEST_CONFIG_END
61 #define PASTE(x) #x
62 #define STR(x) PASTE(x)
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 */
73 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;
79 if (num_patches < o.num_patches)
80 return true;
81 if (num_patches > o.num_patches)
82 return false;
84 if (tessfactor_u < o.tessfactor_u)
85 return true;
86 if (tessfactor_u > o.tessfactor_u)
87 return false;
89 if (tessfactor_v < o.tessfactor_v)
90 return true;
91 if (tessfactor_v > o.tessfactor_v)
92 return false;
94 if (num_invocations < o.num_invocations)
95 return true;
96 if (num_invocations > o.num_invocations)
97 return false;
99 if (num_outputs < o.num_outputs)
100 return true;
101 if (num_outputs > o.num_outputs)
102 return false;
104 return num_extra_components < o.num_extra_components;
108 struct fragmentshaderkey {
109 unsigned num_extra_components;
111 bool operator<(const fragmentshaderkey &o) const {
112 return num_extra_components < o.num_extra_components;
116 struct geometryshaderkey {
117 unsigned num_invocations;
118 unsigned num_outputs;
119 unsigned num_extra_components;
121 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;
134 static std::map<fragmentshaderkey, GLuint> fragmentshaders;
135 static std::map<geometryshaderkey, GLuint> testprograms;
137 static const struct testcase default_testcase = {
138 .num_instances = 1,
139 .num_patches = 1,
140 .tessfactor_u = 1,
141 .tessfactor_v = 1,
142 .num_invocations = 1,
143 .num_outputs = 1,
144 .num_extra_components = 0,
147 static int32_t *buffer_copy;
149 static const unsigned max_final_points = 2 * 1024 * 1024; /* requires 16 MiB buffer */
150 static bool small = false;
151 static GLuint vs_shader;
152 static GLuint tcs_shader;
153 static GLuint tes_shader;
154 static GLuint vao;
155 static GLuint ssbo;
156 static std::vector<testcase> testcases;
157 static std::set<testcase> testcases_set;
158 static GLuint max_tessfactor;
159 static GLuint max_gs_invocations;
160 static GLuint max_gs_out_vertices;
161 static GLuint max_gs_total_out_components;
162 static GLuint max_gs_out_components;
163 static unsigned max_gs_out_vertices_real;
165 static const char vs_text[] =
166 "#version 150\n"
167 "\n"
168 "uniform int u_verts_per_instance;\n"
169 "\n"
170 "out int vs_tcs_id;\n"
171 "\n"
172 "void main() {\n"
173 " vs_tcs_id = gl_InstanceID * u_verts_per_instance + gl_VertexID;\n"
174 "}\n";
176 static const char tcs_text[] =
177 "#version 150\n"
178 "#extension GL_ARB_tessellation_shader : require\n"
179 "layout(vertices = 1) out;\n"
180 "\n"
181 "in int vs_tcs_id[];\n"
182 "\n"
183 "out int tcs_tes_id[];\n"
184 "\n"
185 "uniform int u_tessfactor_u;\n"
186 "uniform int u_tessfactor_v;\n"
187 "\n"
188 "void main() {\n"
189 " tcs_tes_id[gl_InvocationID] = vs_tcs_id[gl_InvocationID];\n"
190 " gl_TessLevelOuter[0] = u_tessfactor_v;\n"
191 " gl_TessLevelOuter[1] = u_tessfactor_u;\n"
192 "}\n";
194 static const char tes_text[] =
195 "#version 150\n"
196 "#extension GL_ARB_tessellation_shader : require\n"
197 "layout(isolines, equal_spacing) in;\n"
198 "\n"
199 "in int tcs_tes_id[];\n"
200 "\n"
201 "out int tes_gs_id;\n"
202 "\n"
203 "void main() {\n"
204 " tes_gs_id = tcs_tes_id[0];\n"
205 " gl_Position.x = gl_TessCoord[0];\n"
206 " gl_Position.y = gl_TessCoord[1];\n"
207 "}\n";
209 /* Those numbers really don't matter much for what we're trying to do here. */
210 #define GEN_SEQUENCE \
211 "int seq_next(int x) {\n" \
212 " x = (x + 1) * 709900053;\n" \
213 " x = x ^ (x >> 17);\n" \
214 " return x;\n" \
215 "}\n"
217 static const char gs_text[] =
218 "#version 150\n"
219 "#extension GL_ARB_gpu_shader5 : require\n"
220 "\n"
221 "#define NUM_INVOCATIONS %d\n"
222 "#define NUM_OUT_VERTICES %d\n"
223 "#define NUM_EXTRA_COMPONENTS %d\n"
224 "\n"
225 "layout(lines, invocations = NUM_INVOCATIONS) in;\n"
226 "layout(points, max_vertices = NUM_OUT_VERTICES) out;\n"
227 "\n"
228 "uniform int u_tessfactor_u;\n"
229 "uniform int u_tessfactor_v;\n"
230 "\n"
231 "in int tes_gs_id[];\n"
232 "\n"
233 "flat out int gs_ps_data[1 + NUM_EXTRA_COMPONENTS];\n"
234 "\n"
235 GEN_SEQUENCE
236 "\n"
237 "void main() {\n"
238 " int in_id = tes_gs_id[0] * u_tessfactor_u * u_tessfactor_v;\n"
239 " float v = gl_in[0].gl_Position.y;\n"
240 " in_id += u_tessfactor_u * int(v * u_tessfactor_v + 0.5);\n"
241 " float u = min(gl_in[0].gl_Position.x, gl_in[1].gl_Position.x);\n"
242 " in_id += int(u * u_tessfactor_u + 0.5);\n"
243 "\n"
244 " for (int i = 0; i < NUM_OUT_VERTICES; ++i) {\n"
245 " uint id = (in_id * NUM_INVOCATIONS + gl_InvocationID) * NUM_OUT_VERTICES + i;\n"
246 " uint x = id %% " STR(WINDOW_SIZE) "u;\n"
247 " uint y = (id / " STR(WINDOW_SIZE) "u) %% " STR(WINDOW_SIZE) "u;\n"
248 " gl_Position.x = (float(x) + 0.5) / " STR(WINDOW_SIZE) " * 2.0 - 1.0;\n"
249 " gl_Position.y = (float(y) + 0.5) / " STR(WINDOW_SIZE) " * 2.0 - 1.0;\n"
250 " gl_Position.z = 0.0;\n"
251 " gl_Position.w = 1.0;\n"
252 "\n"
253 " int val = int(id);\n"
254 " for (int j = 0; j <= NUM_EXTRA_COMPONENTS; ++j) {\n"
255 " gs_ps_data[j] = val;\n"
256 " val = seq_next(val);\n"
257 " }\n"
258 "\n"
259 " EmitVertex();\n"
260 " }\n"
261 "}\n";
263 static const char fs_text[] =
264 "#version 150\n"
265 "#extension GL_ARB_shader_storage_buffer_object : require\n"
266 "\n"
267 "#define NUM_EXTRA_COMPONENTS %d\n"
268 "\n"
269 "flat in int gs_ps_data[1 + NUM_EXTRA_COMPONENTS];\n"
270 "out vec4 out_color;\n"
271 "\n"
272 "layout(std430, binding = 0) buffer SSBO {\n"
273 " ivec2 data[];\n"
274 "} ssbo;\n"
275 "\n"
276 GEN_SEQUENCE
277 "\n"
278 "void main() {\n"
279 " int id = gs_ps_data[0];\n"
280 " int screen_id = int(gl_FragCoord.y) * " STR(WINDOW_SIZE) " + int(gl_FragCoord.x);\n"
281 " if (screen_id != id %% (" STR(WINDOW_SIZE * WINDOW_SIZE) ")) {\n"
282 " ssbo.data[id].x = 1000;\n"
283 " ssbo.data[id].y = screen_id;\n"
284 " out_color = vec4(0.1, 0, 0, 1);\n"
285 " return;\n"
286 " }\n"
287 "\n"
288 " int val = id;\n"
289 " for (int j = 0; j <= NUM_EXTRA_COMPONENTS; ++j) {\n"
290 " if (val != gs_ps_data[j]) {\n"
291 " ssbo.data[id].x = 2000 + j;\n"
292 " ssbo.data[id].y = gs_ps_data[j];\n"
293 " out_color = vec4(0, 0.1, 0, 1);\n"
294 " return;\n"
295 " }\n"
296 " val = seq_next(val);\n"
297 " }\n"
298 "\n"
299 " ssbo.data[id].x = 1;\n"
300 " out_color = vec4(0, 0, 0, 1);\n"
301 "}\n";
303 static void
304 print_testcase(const struct testcase *tc)
306 printf("Case: instances = %u patches = %u tessfactor = %u,%u invocations = %u "
307 "outputs = %u extra_components = %u\n",
308 tc->num_instances, tc->num_patches, tc->tessfactor_u, tc->tessfactor_v,
309 tc->num_invocations, tc->num_outputs, tc->num_extra_components);
312 static void
313 add_testcase(const struct testcase *tc)
315 if (!testcases_set.insert(*tc).second)
316 return;
318 if (tc->num_instances > 64 * 1024 ||
319 tc->num_patches > 64 * 1024 ||
320 tc->tessfactor_u > 64 * 1024 ||
321 tc->tessfactor_v > 64 * 1024 ||
322 tc->num_invocations > 64 * 1024 ||
323 tc->num_outputs > 64 * 1024 ||
324 tc->num_extra_components > 64 * 1024) {
325 fprintf(stderr, "Excessive test case size. Are you sure?\n");
326 print_testcase(tc);
327 exit(1);
330 /* Multiple separate multiplies to avoid integer wraparound */
331 if ((uint64_t)tc->num_instances * tc->num_patches * tc->tessfactor_u > max_final_points ||
332 (uint64_t)tc->tessfactor_v * tc->num_invocations * tc->num_outputs > max_final_points ||
333 (uint64_t)tc->num_instances * tc->num_patches * tc->tessfactor_u *
334 tc->tessfactor_v * tc->num_invocations * tc->num_outputs > max_final_points) {
335 fprintf(stderr, "Test case has more than %u final points.\n", max_final_points);
336 print_testcase(tc);
337 exit(1);
340 /* Check against implementation-defined limits. */
341 if (tc->tessfactor_u > max_tessfactor || tc->tessfactor_v > max_tessfactor) {
342 fprintf(stderr, "Tessellation factor too high (max: %u)\n",
343 max_tessfactor);
344 print_testcase(tc);
345 exit(1);
347 if (tc->num_outputs > max_gs_out_vertices) {
348 fprintf(stderr, "Too many output vertices (max: %d)\n",
349 max_gs_out_vertices);
350 print_testcase(tc);
351 exit(1);
353 if (tc->num_outputs * (5 + tc->num_extra_components) > max_gs_total_out_components) {
354 fprintf(stderr, "Too many output components (max: %d)\n",
355 max_gs_total_out_components);
356 print_testcase(tc);
357 exit(1);
359 if (tc->num_invocations > max_gs_invocations) {
360 fprintf(stderr, "Too many GS invocations (max: %d)\n",
361 max_gs_invocations);
362 print_testcase(tc);
363 exit(1);
366 /* Compile GS shader and link program */
367 geometryshaderkey gskey;
368 gskey.num_invocations = tc->num_invocations;
369 gskey.num_outputs = tc->num_outputs;
370 gskey.num_extra_components = tc->num_extra_components;
371 if (testprograms.find(gskey) == testprograms.end()) {
372 char *text;
374 fragmentshaderkey fskey;
375 fskey.num_extra_components = tc->num_extra_components;
376 std::map<fragmentshaderkey, GLuint>::const_iterator fsit =
377 fragmentshaders.find(fskey);
378 if (fsit == fragmentshaders.end()) {
379 if (asprintf(&text, fs_text, tc->num_extra_components) < 0)
380 abort();
381 GLuint fs_shader =
382 piglit_compile_shader_text(GL_FRAGMENT_SHADER, text);
383 free(text);
385 fsit = fragmentshaders.insert(std::make_pair(fskey, fs_shader)).first;
388 if (asprintf(&text, gs_text, tc->num_invocations, tc->num_outputs,
389 tc->num_extra_components) < 0)
390 abort();
391 GLuint gs_shader =
392 piglit_compile_shader_text(GL_GEOMETRY_SHADER, text);
393 free(text);
395 GLuint prog = glCreateProgram();
396 glAttachShader(prog, vs_shader);
397 glAttachShader(prog, tcs_shader);
398 glAttachShader(prog, tes_shader);
399 glAttachShader(prog, gs_shader);
400 glAttachShader(prog, fsit->second);
401 glLinkProgram(prog);
402 if (!piglit_link_check_status(prog))
403 piglit_report_result(PIGLIT_FAIL);
405 glDeleteShader(gs_shader);
407 testprograms.insert(std::make_pair(gskey, prog));
410 testcases.push_back(*tc);
413 static bool
414 run_testcase(const struct testcase *tc)
416 unsigned final_points = tc->num_instances * tc->num_patches * tc->tessfactor_u *
417 tc->tessfactor_v * tc->num_invocations * tc->num_outputs;
418 unsigned bufsize = 2 * sizeof(int32_t) * final_points;
420 print_testcase(tc);
422 glClearColor(0, 0, 0, 1);
423 glClear(GL_COLOR_BUFFER_BIT);
425 geometryshaderkey gskey;
426 gskey.num_invocations = tc->num_invocations;
427 gskey.num_outputs = tc->num_outputs;
428 gskey.num_extra_components = tc->num_extra_components;
429 std::map<geometryshaderkey, GLuint>::const_iterator progit =
430 testprograms.find(gskey);
431 assert(progit != testprograms.end());
433 glUseProgram(progit->second);
434 glPatchParameteri(GL_PATCH_VERTICES, 1);
435 glUniform1i(glGetUniformLocation(progit->second, "u_tessfactor_u"),
436 tc->tessfactor_u);
437 glUniform1i(glGetUniformLocation(progit->second, "u_tessfactor_v"),
438 tc->tessfactor_v);
439 glUniform1i(glGetUniformLocation(progit->second, "u_verts_per_instance"),
440 tc->num_patches);
442 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
444 memset(buffer_copy, 0, bufsize);
445 glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, bufsize, buffer_copy);
447 glEnable(GL_BLEND);
448 glBlendFunc(GL_ONE, GL_ONE);
450 glDrawArraysInstanced(GL_PATCHES, 0, tc->num_patches, tc->num_instances);
452 glDisable(GL_BLEND);
454 if (!piglit_check_gl_error(GL_NO_ERROR))
455 return false;
457 static const float expected[] = { 0, 0, 0, 1 };
458 bool ok = true;
460 if (!piglit_probe_rect_rgba(0, 0, WINDOW_SIZE, WINDOW_SIZE, expected))
461 ok = false;
463 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, bufsize, buffer_copy);
465 for (unsigned i = 0; i < final_points; ++i) {
466 if (buffer_copy[2 * i] != 1) {
467 printf("Error @ %d: %d %d\n", i,
468 buffer_copy[2 * i], buffer_copy[2 * i + 1]);
469 ok = false;
473 return ok;
477 static void
478 generate_testcases_max2(const testcase &tc, bool explicit_instances, bool explicit_patches)
480 unsigned amplify = tc.tessfactor_u * tc.tessfactor_v * tc.num_invocations * tc.num_outputs;
481 unsigned target_in = max_final_points / amplify;
483 if (small)
484 target_in = MIN2(4, target_in);
486 if (!explicit_instances) {
487 testcase tc1 = tc;
488 tc1.num_instances = MAX2(1, target_in / tc1.num_patches);
489 add_testcase(&tc1);
492 if (!explicit_patches) {
493 testcase tc1 = tc;
494 tc1.num_patches = MAX2(1, target_in / tc1.num_instances);
495 add_testcase(&tc1);
498 if (!explicit_instances && !explicit_patches) {
499 testcase tc1 = tc;
500 tc1.num_instances = MAX2(1, (unsigned)sqrt(target_in));
501 tc1.num_patches = MAX2(1, target_in / tc1.num_instances);
502 add_testcase(&tc1);
505 if (explicit_instances && explicit_patches)
506 add_testcase(&tc);
509 static void
510 generate_testcases_max1(const testcase &tc, bool explicit_instances, bool explicit_patches,
511 bool explicit_tessfactor_u, bool explicit_tessfactor_v,
512 unsigned tess_out_max)
514 if (!explicit_tessfactor_u) {
515 testcase tc1 = tc;
516 tc1.tessfactor_u = MIN2(MAX2(1, tess_out_max / tc1.tessfactor_v),
517 max_tessfactor);
518 generate_testcases_max2(tc1, explicit_instances, explicit_patches);
521 if (!explicit_tessfactor_v) {
522 testcase tc1 = tc;
523 tc1.tessfactor_v = MIN2(MAX2(1, tess_out_max / tc1.tessfactor_u),
524 max_tessfactor);
525 generate_testcases_max2(tc1, explicit_instances, explicit_patches);
528 if (!explicit_tessfactor_u && !explicit_tessfactor_v) {
529 testcase tc1 = tc;
530 tc1.tessfactor_u = MIN2(MAX2(1, (unsigned)sqrt(tess_out_max)),
531 max_tessfactor);
532 tc1.tessfactor_v = MIN2(MAX2(1, tess_out_max / tc1.tessfactor_u),
533 max_tessfactor);
534 generate_testcases_max2(tc1, explicit_instances, explicit_patches);
537 if (explicit_tessfactor_u && explicit_tessfactor_v)
538 generate_testcases_max2(tc, explicit_instances, explicit_patches);
541 static void
542 generate_testcases_max(const testcase &tc, bool explicit_instances, bool explicit_patches,
543 bool explicit_tessfactor_u, bool explicit_tessfactor_v)
545 unsigned amplify = tc.num_invocations * tc.num_outputs;
546 unsigned tess_out_max = max_final_points / amplify;
548 if (small) {
549 generate_testcases_max1(tc, explicit_instances, explicit_patches,
550 explicit_tessfactor_u, explicit_tessfactor_v,
551 MIN2(4, tess_out_max));
552 } else {
553 generate_testcases_max1(tc, explicit_instances, explicit_patches,
554 explicit_tessfactor_u, explicit_tessfactor_v,
555 tess_out_max);
556 while (tess_out_max > 4) {
557 tess_out_max = sqrt(tess_out_max);
558 generate_testcases_max1(tc, explicit_instances, explicit_patches,
559 explicit_tessfactor_u, explicit_tessfactor_v,
560 tess_out_max);
565 static float
566 rand_subdivide(int partitions)
568 double x = 1.0;
570 for (int i = 1; i < partitions; ++i)
571 x = std::min(x, (double)rand() / ((double)RAND_MAX + 1));
573 return x;
576 void
577 piglit_init(int argc, char **argv)
579 bool explicit_instances = false;
580 bool explicit_patches = false;
581 bool explicit_tessfactor_u = false;
582 bool explicit_tessfactor_v = false;
583 bool explicit_invocations = false;
584 bool explicit_outputs = false;
585 bool explicit_components = false;
586 bool scan_mode = false;
587 unsigned scan_seed = 0;
588 unsigned scan_count = 0;
589 struct testcase explicit_testcase;
591 piglit_require_extension("GL_ARB_tessellation_shader");
592 piglit_require_extension("GL_ARB_shader_storage_buffer_object");
594 memcpy(&explicit_testcase, &default_testcase, sizeof(explicit_testcase));
596 int i;
597 for (i = 1; i < argc; ++i) {
598 if (!strcmp(argv[i], "-small")) {
599 small = true;
600 } else {
601 if (i + 1 >= argc)
602 break;
604 if (!strcmp(argv[i], "-instances")) {
605 explicit_testcase.num_instances = atoi(argv[i + 1]);
606 explicit_instances = true;
607 i++;
608 } else if (!strcmp(argv[i], "-patches")) {
609 explicit_testcase.num_patches = atoi(argv[i + 1]);
610 explicit_patches = true;
611 i++;
612 } else if (!strcmp(argv[i], "-tessfactor_u")) {
613 explicit_testcase.tessfactor_u = atoi(argv[i + 1]);
614 explicit_tessfactor_u = true;
615 i++;
616 } else if (!strcmp(argv[i], "-tessfactor_v")) {
617 explicit_testcase.tessfactor_v = atoi(argv[i + 1]);
618 explicit_tessfactor_v = true;
619 i++;
620 } else if (!strcmp(argv[i], "-invocations")) {
621 explicit_testcase.num_invocations = atoi(argv[i + 1]);
622 explicit_invocations = true;
623 i++;
624 } else if (!strcmp(argv[i], "-outputs")) {
625 explicit_testcase.num_outputs = atoi(argv[i + 1]);
626 explicit_outputs = true;
627 i++;
628 } else if (!strcmp(argv[i], "-components")) {
629 explicit_testcase.num_extra_components = atoi(argv[i + 1]);
630 explicit_components = true;
631 i++;
632 } else {
633 if (i + 2 >= argc)
634 break;
636 if (!strcmp(argv[i], "-scan")) {
637 scan_seed = atoi(argv[i + 1]);
638 scan_count = atoi(argv[i + 2]);
639 scan_mode = true;
640 i += 2;
641 } else
642 break;
646 if (i < argc) {
647 fprintf(stderr, "Unknown argument or too few params: %s\n", argv[i]);
648 exit(1);
651 /* Various GL objects needed by the test */
652 vs_shader = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_text);
653 if (!piglit_check_gl_error(GL_NO_ERROR))
654 piglit_report_result(PIGLIT_FAIL);
656 tcs_shader = piglit_compile_shader_text(GL_TESS_CONTROL_SHADER, tcs_text);
657 if (!piglit_check_gl_error(GL_NO_ERROR))
658 piglit_report_result(PIGLIT_FAIL);
660 tes_shader = piglit_compile_shader_text(GL_TESS_EVALUATION_SHADER, tes_text);
661 if (!piglit_check_gl_error(GL_NO_ERROR))
662 piglit_report_result(PIGLIT_FAIL);
664 glGenVertexArrays(1, &vao);
665 glBindVertexArray(vao);
667 glGenBuffers(1, &ssbo);
668 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
669 glBufferData(GL_SHADER_STORAGE_BUFFER, max_final_points * 8, NULL, GL_DYNAMIC_READ);
671 buffer_copy = (int32_t *)calloc(2 * sizeof(int32_t), max_final_points);
673 glGetIntegerv(GL_MAX_TESS_GEN_LEVEL, (GLint*)&max_tessfactor);
674 glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, (GLint*)&max_gs_out_vertices);
675 glGetIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS,
676 (GLint*)&max_gs_total_out_components);
677 glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS,
678 (GLint*)&max_gs_out_components);
679 glGetIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS, (GLint*)&max_gs_invocations);
680 if (!piglit_check_gl_error(GL_NO_ERROR))
681 piglit_report_result(PIGLIT_FAIL);
683 max_gs_out_vertices_real = MIN2(max_gs_out_vertices,
684 max_gs_total_out_components / 5);
686 if (scan_mode) {
687 srand(scan_seed);
689 /* First, generate test cases that max out each of the dimensions */
690 testcase tc0 = explicit_testcase;
691 if (!explicit_invocations)
692 tc0.num_invocations = max_gs_invocations;
694 if (!explicit_outputs) {
695 testcase tc1 = tc0;
697 if (!explicit_components) {
698 tc1.num_outputs = max_gs_out_vertices_real;
699 tc1.num_extra_components =
700 MIN2(max_gs_total_out_components / tc1.num_outputs,
701 max_gs_out_components) - 5;
702 } else {
703 tc1.num_outputs =
704 MIN2(max_gs_total_out_components /
705 (5 + tc1.num_extra_components),
706 max_gs_out_vertices_real);
709 generate_testcases_max(tc1, explicit_instances, explicit_patches,
710 explicit_tessfactor_u, explicit_tessfactor_v);
713 if (!explicit_components) {
714 testcase tc1 = tc0;
716 if (!explicit_outputs) {
717 tc1.num_extra_components = max_gs_out_components - 5;
718 tc1.num_outputs =
719 MIN2(max_gs_total_out_components /
720 (5 + tc1.num_extra_components),
721 max_gs_out_vertices_real);
722 } else {
723 tc1.num_extra_components =
724 MIN2(max_gs_total_out_components / tc1.num_outputs,
725 max_gs_out_components) - 4;
728 generate_testcases_max(tc1, explicit_instances, explicit_patches,
729 explicit_tessfactor_u, explicit_tessfactor_v);
732 if (explicit_outputs && explicit_components)
733 generate_testcases_max(tc0, explicit_instances, explicit_patches,
734 explicit_tessfactor_u, explicit_tessfactor_v);
736 /* Generate additional tests randomly.
738 * Attempt to generate a random distribution that isn't too
739 * lop-sided, but admittedly this is all just hand-wavey
740 * heuristics.
742 while (testcases.size() < scan_count) {
743 testcase tc = explicit_testcase;
745 if (!explicit_outputs || !explicit_components) {
746 if (explicit_outputs || rand() & 1) {
747 unsigned max_components =
748 MIN2(max_gs_total_out_components / tc.num_outputs,
749 max_gs_out_components) - 5;
750 tc.num_extra_components = rand() % (max_components + 1);
752 if (!explicit_outputs) {
753 unsigned max_outputs =
754 MIN2(max_gs_total_out_components /
755 (5 + tc.num_extra_components),
756 max_gs_out_vertices_real);
757 tc.num_outputs = 1 + rand() % max_outputs;
759 } else {
760 unsigned max_outputs =
761 MIN2(max_gs_total_out_components /
762 (5 + tc.num_extra_components),
763 max_gs_out_vertices_real);
764 tc.num_outputs = 1 + rand() % max_outputs;
766 if (!explicit_components) {
767 unsigned max_components =
768 MIN2(max_gs_total_out_components / tc.num_outputs,
769 max_gs_out_components) - 5;
770 tc.num_extra_components = rand() % (max_components + 1);
775 unsigned amplify = tc.num_outputs;
777 if (explicit_invocations)
778 amplify *= tc.num_invocations;
779 if (explicit_tessfactor_u)
780 amplify *= tc.tessfactor_u;
781 if (explicit_tessfactor_v)
782 amplify *= tc.tessfactor_v;
783 if (explicit_patches)
784 amplify *= tc.num_patches;
785 if (explicit_instances)
786 amplify *= tc.num_instances;
788 unsigned target = max_final_points / amplify;
790 if (small)
791 target = MIN2(32, target);
793 if (!explicit_tessfactor_u) {
794 float tf_log_weight = logf(target) * rand_subdivide(6);
795 tc.tessfactor_u = MIN2(expf(tf_log_weight), max_tessfactor);
796 target /= tc.tessfactor_u;
798 if (!explicit_tessfactor_v) {
799 float tf_log_weight = logf(target) * rand_subdivide(6);
800 tc.tessfactor_v = MIN2(expf(tf_log_weight), max_tessfactor);
801 target /= tc.tessfactor_v;
803 if (!explicit_invocations) {
804 float log_weight = logf(target);
805 if (!explicit_instances || !explicit_patches)
806 log_weight *= rand_subdivide(2);
807 tc.num_invocations = MIN2(expf(log_weight), max_gs_invocations);
808 target /= tc.num_invocations;
810 if (!explicit_instances) {
811 float log_weight = logf(target);
812 if (!explicit_patches)
813 log_weight *= rand_subdivide(2);
814 tc.num_instances = expf(log_weight);
815 target /= tc.num_instances;
817 if (!explicit_patches)
818 tc.num_patches = 1 + rand() % target;
820 add_testcase(&tc);
822 } else {
823 add_testcase(&explicit_testcase);
827 enum piglit_result
828 piglit_display(void)
830 bool pass = true;
832 for (unsigned i = 0; i < testcases.size(); ++i) {
833 if (!run_testcase(&testcases[i]))
834 pass = false;
837 if (!piglit_check_gl_error(GL_NO_ERROR))
838 pass = false;
840 piglit_present_results();
842 return pass ? PIGLIT_PASS : PIGLIT_FAIL;