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