1 /*
2  * Copyright 2016 VMware, Inc.
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  * Test rendering of GS adjacency primitives, with:
26  * - First and last provoking vertex
27  * - Front and back-face culling
28  * - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
29  * See code for command line arguments.
30  *
31  * Brian Paul
32  * May 2016
33  */
34 
35 
36 #include "piglit-util-gl.h"
37 #include "piglit-matrix.h"
38 
39 
40 PIGLIT_GL_TEST_CONFIG_BEGIN
41 	config.window_width = 800;
42 	config.window_height = 200;
43 	config.supports_gl_core_version = 32;
44 	config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE;
45 	config.khr_no_error_support = PIGLIT_NO_ERRORS;
46 PIGLIT_GL_TEST_CONFIG_END
47 
48 
49 #define VERTEX_SIZE (2 * sizeof(GLfloat))
50 
51 static const float gray[4] = { 0.5, 0.5, 0.5, 1.0 };
52 static const float black[4] = { 0.0, 0.0, 0.0, 0.0 };
53 
54 static const float colors[18][4] = {
55 	{1.0, 0.2, 0.2, 1.0},
56 	{0.2, 1.0, 0.2, 1.0},
57 	{0.2, 0.2, 1.0, 1.0},
58 	{1.0, 1.0, 1.0, 1.0},
59 	{0.2, 1.0, 1.0, 1.0},
60 	{1.0, 0.2, 1.0, 1.0},
61 	{1.0, 1.0, 0.2, 1.0},
62 	{0.5, 1.0, 1.0, 1.0},
63 	{1.0, 0.5, 1.0, 1.0},
64 	{1.0, 1.0, 0.5, 1.0},
65 	{0.7, 1.0, 1.0, 1.0},
66 	{1.0, 0.7, 1.0, 1.0},
67 	{1.0, 1.0, 0.7, 1.0},
68 	{1.0, 0.2, 0.2, 1.0},
69 	{0.2, 1.0, 0.2, 1.0},
70 	{0.2, 0.2, 1.0, 1.0},
71 	{1.0, 1.0, 1.0, 1.0},
72 	{0.5, 0.5, 0.5, 1.0}
73 };
74 
75 static const float lines_adj_verts[8][2] = {
76 	// first line
77 	{-1, -.75},
78 	{-0.5, -0.25},
79 	{ 0.5, -0.25},
80 	{ 1.0, -.75},
81 	// second line
82 	{-1, 0.0},
83 	{-0.5, 0.5},
84 	{ 0.5, 0.5},
85 	{ 1.0, 0.0}
86 };
87 
88 static const float line_strip_adj_verts[7][2] = {
89 	{-1.5, .3},
90 	{-1, -.3},
91 	{-0.5, .3},
92 	{ 0.0, -.3},
93 	{ 0.5, .3},
94 	{ 1.0, -.3},
95 	{ 1.5, .3},
96 };
97 
98 static const float triangles_adj_verts[6][2] = {
99 	{0, -.5},
100 	{-1.2, 0},
101 	{-.75, 1},
102 	{0, 1.5},
103 	{0.75, 1},
104 	{1.2, 0},
105 };
106 
107 static const float triangle_strip_adj_verts[][2] = {
108 	{-1.5, -0.5},  // 0
109 	{-1.9, 0.0},   // 1
110 	{-1.5, 0.5},   // 2
111 	{-1, -1},      // 3 *
112 	{-1, -.5},     // 4
113 	{-1.5, 1},     // 5 *
114 	{-1, 0.5},     // 6
115 	{-.5, -1},     // 7 *
116 	{-.5, -.5},    // 8
117 	{-1, 1},       // 9 *
118 	{-.5, .5},     // 10
119 	{0, -1},       // 11 *
120 	{0, -.5},      // 12
121 	{-.5, 1},      // 13 *
122 	{0, 0.5},      // 14
123 	{0.5, -1},     // 15 *
124 	{0.5, -.5},    // 16
125 	{1, 0},        // 17
126 };
127 
128 #define NUM_VERTS(ARRAY)  (sizeof(ARRAY) / VERTEX_SIZE)
129 
130 static GLfloat ortho_matrix[16];
131 
132 static GLuint lines_adj_vao;
133 static GLuint line_strip_adj_vao;
134 static GLuint triangles_adj_vao;
135 static GLuint triangle_strip_adj_vao;
136 
137 static GLenum polygon_mode = GL_FILL;
138 static GLenum cull_mode = GL_NONE;
139 static GLenum provoking_vertex = GL_LAST_VERTEX_CONVENTION;
140 
141 static GLuint gs_lines_program;
142 static GLuint gs_line_strip_program;
143 static GLuint gs_triangles_program;
144 static GLuint gs_triangle_strip_program;
145 static GLuint xfb_buf;
146 static GLuint element_buf;
147 static GLuint ref_program;
148 static GLint colorUniform, modelViewProjUniform;
149 
150 // if false, draw without GS, also draw the 'extra' lines/tris.  For debugging.
151 static bool draw_with_gs = true;
152 static bool draw_elements = false;
153 
154 
155 /**
156  * Given a primitive type (adjacency type only), and the first/last provoking
157  * vertex mode, and a primitive (line, triangle) index, return the index of
158  * the vertex which will specify the primitive's flat-shaded color.
159  */
160 static unsigned
provoking_vertex_index(GLenum prim_mode,GLenum pv_mode,unsigned prim_index)161 provoking_vertex_index(GLenum prim_mode, GLenum pv_mode, unsigned prim_index)
162 {
163 	switch (prim_mode) {
164 	case GL_LINES_ADJACENCY:
165 		if (pv_mode == GL_FIRST_VERTEX_CONVENTION)
166 			return prim_index * 4 + 1;
167 		else
168 			return prim_index * 4 + 2;
169 	case GL_LINE_STRIP_ADJACENCY:
170 		if (pv_mode == GL_FIRST_VERTEX_CONVENTION)
171 			return prim_index + 1;
172 		else
173 			return prim_index + 2;
174 	case GL_TRIANGLES_ADJACENCY:
175 		if (pv_mode == GL_FIRST_VERTEX_CONVENTION)
176 			return prim_index * 6 + 0;
177 		else
178 			return prim_index * 6 + 4;
179 	case GL_TRIANGLE_STRIP_ADJACENCY:
180 		if (pv_mode == GL_FIRST_VERTEX_CONVENTION) {
181 			if (prim_index & 1)
182 				return prim_index * 2 + 2;
183 			else
184 				return prim_index * 2;
185 		} else
186 			return prim_index * 2 + 4;
187 	default:
188 		assert(!"Unexpected prim_mode");
189 		return 0;
190 	}
191 }
192 
193 
194 /**
195  * Given a primitive type and a primitive (line/triangle) index, return
196  * the (x,y) screen coordinate for probing.
197  */
198 static void
compute_probe_location(GLenum prim_mode,unsigned prim_index,const float verts[][2],int vp_x,int vp_y,int * x,int * y)199 compute_probe_location(GLenum prim_mode, unsigned prim_index,
200 		       const float verts[][2],
201 		       int vp_x, int vp_y, int *x, int *y)
202 {
203 	int i0, i1, i2 = -1;
204 	float coord[4], ndc[4], win[3];
205 
206 	switch (prim_mode) {
207 	case GL_LINES_ADJACENCY:
208 		i0 = prim_index * 4 + 1;
209 		i1 = prim_index * 4 + 2;
210 		break;
211 	case GL_LINE_STRIP_ADJACENCY:
212 		i0 = prim_index + 1;
213 		i1 = prim_index + 2;
214 		break;
215 	case GL_TRIANGLES_ADJACENCY:
216 		i0 = prim_index * 6 + 0;
217 		i1 = prim_index * 6 + 2;
218 		if (polygon_mode != GL_LINE)
219 			i2 = prim_index * 6 + 4;
220 		break;
221 	case GL_TRIANGLE_STRIP_ADJACENCY:
222 		if (prim_index & 1) {
223 			i0 = prim_index * 2;
224 			i1 = prim_index * 2 + 2;
225 		} else {
226 			i0 = prim_index * 2 + 2;
227 			i1 = prim_index * 2;
228 		}
229 		if (polygon_mode != GL_LINE)
230 			i2 = prim_index * 2 + 4;
231 		break;
232 	default:
233 		assert(!"Unexpected prim_mode");
234 		*x = *y = 0;
235 		return;
236 	}
237 
238 	/* average of 2 or 3 points */
239 	if (i2 == -1) {
240 		coord[0] = (verts[i0][0] + verts[i1][0]) / 2.0;
241 		coord[1] = (verts[i0][1] + verts[i1][1]) / 2.0;
242 	} else {
243 		coord[0] = (verts[i0][0] + verts[i1][0] + verts[i2][0]) / 3.0;
244 		coord[1] = (verts[i0][1] + verts[i1][1] + verts[i2][1]) / 3.0;
245 	}
246 	coord[2] = 0.0;
247 	coord[3] = 1.0;
248 
249 	piglit_matrix_mul_vector(ndc, ortho_matrix, coord);
250 	piglit_ndc_to_window(win, ndc, vp_x, vp_y,
251 			     piglit_width/4, piglit_height);
252 
253 	*x = (int) win[0];
254 	*y = (int) win[1];
255 }
256 
257 
258 /**
259  * Do the colors match, within an epsilon?
260  */
261 static bool
colors_match(const float c1[4],const float c2[4])262 colors_match(const float c1[4], const float c2[4])
263 {
264 	const float epsilon = 1.0 / 256.0;
265 
266 	if (fabs(c1[0] - c2[0]) > epsilon ||
267 	    fabs(c1[1] - c2[1]) > epsilon ||
268 	    fabs(c1[2] - c2[2]) > epsilon ||
269 	    fabs(c1[3] - c2[3]) > epsilon)
270 		return false;
271 	else
272 		return true;
273 }
274 
275 
276 /**
277  * Given a primitive type and a number of vertices, return the number of
278  * primitives (lines/tris) that'll be drawn.
279  */
280 static unsigned
num_gs_prims(GLenum prim_mode,unsigned num_verts)281 num_gs_prims(GLenum prim_mode, unsigned num_verts)
282 {
283 	switch (prim_mode) {
284 	case GL_LINES_ADJACENCY:
285 		assert(num_verts % 4 == 0);
286 		return num_verts / 4;
287 	case GL_LINE_STRIP_ADJACENCY:
288 		assert(num_verts >= 4);
289 		return num_verts - 3;
290 	case GL_TRIANGLES_ADJACENCY:
291 		assert(num_verts % 6 == 0);
292 		return num_verts / 6;
293 	case GL_TRIANGLE_STRIP_ADJACENCY:
294 		assert(num_verts >= 6);
295 		return (num_verts - 4) / 2;
296 	default:
297 		assert(!"Unexpected prim_mode");
298 		return 0;
299 	}
300 }
301 
302 
303 /**
304  * Check if a primitive strip was rendered correctly by doing color probing.
305  * vp_pos is the viewport position (0..3).
306  */
307 static bool
probe_prims(GLenum prim_mode,const float verts[][2],unsigned num_verts,unsigned vp_pos)308 probe_prims(GLenum prim_mode, const float verts[][2], unsigned num_verts,
309 	    unsigned vp_pos)
310 {
311 	const int vp_w = piglit_width / 4;
312 	const unsigned num_prims = num_gs_prims(prim_mode, num_verts);
313 	unsigned prim;
314 
315 	for (prim = 0; prim < num_prims; prim++) {
316 		bool pass = false;
317 		float expected_color[4];
318 		float bad_color[4] = { -1 };
319 		bool bad_color_found = false;
320 		int x, y, i;
321 
322 		compute_probe_location(prim_mode, prim, verts,
323 				       vp_pos * vp_w, 0, &x, &y);
324 
325 		if (cull_mode == GL_FRONT &&
326 		    (prim_mode == GL_TRIANGLES_ADJACENCY ||
327 		     prim_mode == GL_TRIANGLE_STRIP_ADJACENCY)) {
328 			// All triangles should be front facing.
329 			// With front culling, all should be discarded.
330 			// Region should be black.
331 			if (piglit_probe_rect_rgba(x-1, y-1, 3, 3, black)) {
332 				pass = true;
333 			}
334 		} else {
335 			GLfloat buf[9][4];
336 			unsigned pvi = provoking_vertex_index(prim_mode,
337 						     provoking_vertex, prim);
338 			memcpy(&expected_color, colors[pvi], sizeof(expected_color));
339 			if (prim_mode == GL_TRIANGLES_ADJACENCY ||
340 			    prim_mode == GL_TRIANGLE_STRIP_ADJACENCY) {
341 				expected_color[2] = pvi * (1.0 / 255);
342 				expected_color[3] = provoking_vertex == GL_FIRST_VERTEX_CONVENTION ? 0.0 : 1.0;
343 			}
344 
345 			// Read a 3x3 region for line probing
346 			glReadPixels(x-1, y-1, 3, 3, GL_RGBA, GL_FLOAT, buf);
347 
348 			// look for non-black pixel
349 			for (i = 0; i < 9; i++) {
350 				if (buf[i][0] != 0 || buf[i][1] != 0 ||
351 				    buf[i][2] != 0 || buf[i][3] != 0) {
352 					// check for expected color
353 					if (colors_match(expected_color, buf[i]))
354 						pass = true;
355 					else {
356 						bad_color_found = true;
357 						bad_color[0] = buf[i][0];
358 						bad_color[1] = buf[i][1];
359 						bad_color[2] = buf[i][2];
360 						bad_color[3] = buf[i][3];
361 					}
362 				}
363 			}
364 		}
365 
366 		if (!pass) {
367 			printf("Failure for %s, "
368 			       "prim %u wrong color at (%d,%d)\n",
369 			       piglit_get_prim_name(prim_mode), prim, x, y);
370 			if (bad_color_found) {
371 				printf("Expected %g, %g, %g, %g\n",
372 				       expected_color[0],
373 				       expected_color[1],
374 				       expected_color[2],
375 				       expected_color[3]);
376 				printf("Found %g, %g, %g, %g\n",
377 				       bad_color[0],
378 				       bad_color[1],
379 				       bad_color[2],
380 				       bad_color[3]);
381 			}
382 
383 			return false;
384 		}
385 	}
386 
387 	return true;
388 }
389 
390 static bool
probe_xfb(GLenum prim_mode,unsigned num_verts)391 probe_xfb(GLenum prim_mode, unsigned num_verts)
392 {
393 	bool pass = true;
394 	const unsigned num_prims = num_gs_prims(prim_mode, num_verts);
395 	const float *xfb_data = glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
396 
397 	for (unsigned prim = 0; prim < num_prims; prim++) {
398 		const float *found_color;
399 		float expected_color[4];
400 		unsigned pvi = provoking_vertex_index(prim_mode,
401 						provoking_vertex, prim);
402 
403 		memcpy(&expected_color, colors[pvi], sizeof(expected_color));
404 		expected_color[2] = pvi * (1.0 / 255);
405 		expected_color[3] = provoking_vertex == GL_FIRST_VERTEX_CONVENTION ? 0.0 : 1.0;
406 
407 		found_color = xfb_data + 4 * (3 * prim + (provoking_vertex == GL_FIRST_VERTEX_CONVENTION ? 0 : 2));
408 
409 		if (!colors_match(expected_color, found_color)) {
410 			printf("Transform Feedback Failure for %s, prim %u wrong color\n",
411 			       piglit_get_prim_name(prim_mode), prim);
412 			printf("Expected %g, %g, %g, %g\n",
413 			       expected_color[0],
414 			       expected_color[1],
415 			       expected_color[2],
416 			       expected_color[3]);
417 			printf("Found %g, %g, %g, %g\n",
418 			       found_color[0],
419 			       found_color[1],
420 			       found_color[2],
421 			       found_color[3]);
422 
423 			pass = false;
424 		}
425 	}
426 
427 	glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
428 
429 	return pass;
430 }
431 
432 
433 static GLuint
make_gs_program(GLenum input_prim)434 make_gs_program(GLenum input_prim)
435 {
436 	static const char *vs_text =
437 		"#version 150 \n"
438 		"in vec4 vertex; \n"
439 		"in vec4 color; \n"
440 		"uniform mat4 modelViewProj; \n"
441 		"out vec4 pos;\n"
442 		"out vec4 vs_gs_color; \n"
443 		"out int vs_gs_vertex_id; \n"
444 		"void main() \n"
445 		"{ \n"
446 		"   gl_Position = vertex * modelViewProj; \n"
447 		"   pos = vertex * modelViewProj; \n"
448 		"   vs_gs_color = color; \n"
449 		"   vs_gs_vertex_id = gl_VertexID; \n"
450 		"} \n";
451 	static const char *gs_text_lines =
452 		"#version 150 \n"
453 		"layout(lines_adjacency) in;\n"
454 		"layout(line_strip, max_vertices = 2) out;\n"
455 		"in vec4 pos[]; \n"
456 		"in vec4 vs_gs_color[4]; \n"
457 		"flat out vec4 gs_fs_color; \n"
458 		"void main() \n"
459 		"{ \n"
460 		"   gs_fs_color = vs_gs_color[1]; \n"
461 		"   gl_Position = pos[1]; \n"
462 		"   EmitVertex(); \n"
463 		"   gs_fs_color = vs_gs_color[2]; \n"
464 		"   gl_Position = pos[2]; \n"
465 		"   EmitVertex(); \n"
466 		"   EndPrimitive(); \n"
467 		"} \n";
468 	static const char *gs_text_triangles =
469 		"#version 150 \n"
470 		"layout(triangles_adjacency) in;\n"
471 		"layout(triangle_strip, max_vertices = 3) out;\n"
472 		"in vec4 pos[]; \n"
473 		"in vec4 vs_gs_color[6]; \n"
474 		"in int vs_gs_vertex_id[6]; \n"
475 		"flat out vec4 gs_fs_color; \n"
476 		"void main() \n"
477 		"{ \n"
478 		"   gs_fs_color = vs_gs_color[0]; \n"
479 		"   gs_fs_color.b = vs_gs_vertex_id[0] * (1. / 255.); \n"
480 		"   gs_fs_color.a = 0.0; \n"
481 		"   gl_Position = pos[0]; \n"
482 		"   EmitVertex(); \n"
483 		"   gs_fs_color = vs_gs_color[2]; \n"
484 		"   gs_fs_color.b = vs_gs_vertex_id[2] * (1. / 255.); \n"
485 		"   gs_fs_color.a = 0.5; \n"
486 		"   gl_Position = pos[2]; \n"
487 		"   EmitVertex(); \n"
488 		"   gs_fs_color = vs_gs_color[4]; \n"
489 		"   gs_fs_color.b = vs_gs_vertex_id[4] * (1. / 255.); \n"
490 		"   gs_fs_color.a = 1.0; \n"
491 		"   gl_Position = pos[4]; \n"
492 		"   EmitVertex(); \n"
493 		"   //EndPrimitive(); \n"
494 		"} \n";
495 	static const char *fs_text =
496 		"#version 150 \n"
497 		"flat in vec4 gs_fs_color; \n"
498 		"void main() \n"
499 		"{ \n"
500 		"   gl_FragColor = gs_fs_color; \n"
501 		"} \n";
502 	static const char *gs_xfb_varyings[] = { "gs_fs_color" };
503 	const char *gs_text;
504 	GLuint program;
505 
506 	switch (input_prim) {
507 	case GL_LINES_ADJACENCY:
508 	case GL_LINE_STRIP_ADJACENCY:
509 		gs_text = gs_text_lines;
510 		break;
511 	case GL_TRIANGLES_ADJACENCY:
512 	case GL_TRIANGLE_STRIP_ADJACENCY:
513 		gs_text = gs_text_triangles;
514 		break;
515 	default:
516 		assert(!"Unexpected input_prim");
517 		return 0;
518 	}
519 
520 	program = piglit_build_simple_program_unlinked_multiple_shaders(
521 		GL_VERTEX_SHADER, vs_text,
522 		GL_GEOMETRY_SHADER, gs_text,
523 		GL_FRAGMENT_SHADER, fs_text,
524 		0);
525 
526 	assert(program);
527 
528 	glBindAttribLocation(program, 0, "vertex");
529 	glBindAttribLocation(program, 1, "color");
530 
531 	glTransformFeedbackVaryings(program, 1, &gs_xfb_varyings[0],
532 				    GL_INTERLEAVED_ATTRIBS);
533 
534 	glLinkProgram(program);
535 
536 	return program;
537 }
538 
539 
540 static GLuint
make_ref_program(void)541 make_ref_program(void)
542 {
543 	static const char *vs_text =
544 		"#version 150 \n"
545 		"in vec4 vertex; \n"
546 		"uniform vec4 color; \n"
547 		"uniform mat4 modelViewProj; \n"
548 		"out vec4 vs_fs_color; \n"
549 		"void main() \n"
550 		"{ \n"
551 		"   gl_Position = vertex * modelViewProj; \n"
552 		"   vs_fs_color = color; \n"
553 		"} \n";
554 
555 	static const char *fs_text =
556 		"#version 150 \n"
557 		"in vec4 vs_fs_color; \n"
558 		"void main() \n"
559 		"{ \n"
560 		"   gl_FragColor = vs_fs_color; \n"
561 		"} \n";
562 
563 	GLuint program = piglit_build_simple_program_unlinked_multiple_shaders(
564 		GL_VERTEX_SHADER, vs_text,
565 		GL_FRAGMENT_SHADER, fs_text,
566 		0);
567 
568 	glBindAttribLocation(program, 0, "vertex");
569 	glBindAttribLocation(program, 1, "color");
570 
571 	glLinkProgram(program);
572 
573 	return program;
574 }
575 
576 
577 static void
draw_elements3(GLenum mode,unsigned v0,unsigned v1,unsigned v2)578 draw_elements3(GLenum mode, unsigned v0, unsigned v1, unsigned v2)
579 {
580 	GLushort elements[3];
581 	elements[0] = v0;
582 	elements[1] = v1;
583 	elements[2] = v2;
584 	glDrawElements(mode, 3, GL_UNSIGNED_SHORT, elements);
585 }
586 
587 
588 static void
set_color(const GLfloat c[4])589 set_color(const GLfloat c[4])
590 {
591 	glUniform4fv(colorUniform, 1, c);
592 }
593 
594 
595 static void
draw_lines_adj(GLuint vao,unsigned n)596 draw_lines_adj(GLuint vao, unsigned n)
597 {
598 	assert(n % 4 == 0);
599 
600 	glBindVertexArray(vao);
601 	{
602 		unsigned i;
603 		for (i = 0; i < n; i += 4) {
604 			unsigned pvi =
605 				provoking_vertex_index(GL_LINES_ADJACENCY,
606 						       provoking_vertex, i/4);
607 			set_color(gray);
608 
609 			// draw preceeding "wing" line
610 			glDrawArrays(GL_LINES, i, 2);
611 			// draw trailing "wing" line
612 			glDrawArrays(GL_LINES, i+2, 2);
613 
614 			set_color(colors[pvi]);
615 			// draw "real" line
616 			glDrawArrays(GL_LINES, i+1, 2);
617 		}
618 	}
619 }
620 
621 
622 static void
draw_line_strip_adj(GLuint vao,unsigned n)623 draw_line_strip_adj(GLuint vao, unsigned n)
624 {
625 	unsigned i;
626 
627 	assert(n >= 4);
628 
629 	glBindVertexArray(vao);
630 
631 	set_color(gray);
632 	glDrawArrays(GL_LINES, 0, 2);
633 	glDrawArrays(GL_LINES, n-2, 2);
634 
635 	for (i = 1; i < n-2; i++) {
636 		unsigned pvi =
637 			provoking_vertex_index(GL_LINE_STRIP_ADJACENCY,
638 					       provoking_vertex, i-1);
639 		set_color(colors[pvi]);
640 		glDrawArrays(GL_LINES, i, 2);
641 	}
642 }
643 
644 
645 static void
draw_triangles_adj(GLuint vao,unsigned n)646 draw_triangles_adj(GLuint vao, unsigned n)
647 {
648 	unsigned i;
649 
650 	assert(n % 6 == 0);
651 
652 	glBindVertexArray(vao);
653 
654 	for (i = 0; i < n; i += 6) {
655 		unsigned pvi =
656 			provoking_vertex_index(GL_TRIANGLES_ADJACENCY,
657 					       provoking_vertex, i/6);
658 
659 		// draw gray outlines of "wing" triangles
660 		set_color(gray);
661 		draw_elements3(GL_LINE_LOOP, i, i+1, i+2);
662 		draw_elements3(GL_LINE_LOOP, i+2, i+3, i+4);
663 		draw_elements3(GL_LINE_LOOP, i, i+4, i+5);
664 
665 		// draw "real" triangle
666 		set_color(colors[pvi]);
667 		draw_elements3(GL_TRIANGLES, i, i+2, i+4);
668 	}
669 }
670 
671 
672 static void
draw_triangle_strip_adj(GLuint vao,unsigned n)673 draw_triangle_strip_adj(GLuint vao, unsigned n)
674 {
675 	unsigned i;
676 
677 	assert(n >= 6);
678 
679 	glBindVertexArray(vao);
680 
681 	// draw first "wing" triangle
682 	set_color(gray);
683 	glDrawArrays(GL_LINE_LOOP, 0, 3);
684 
685 	for (i = 0; i < n-4; i += 2) {
686 		unsigned pvi =
687 			provoking_vertex_index(GL_TRIANGLE_STRIP_ADJACENCY,
688 					       provoking_vertex, i/2);
689 
690 		if (i % 4 == 2) {
691 			// even tri
692 			set_color(gray);
693 			draw_elements3(GL_LINE_LOOP, i, i+3, i+4);
694 			set_color(colors[pvi]);
695 			draw_elements3(GL_TRIANGLES, i, i+4, i+2);
696 		}
697 		else {
698 			// odd tri
699 			set_color(gray);
700 			draw_elements3(GL_LINE_LOOP, i, i+4, i+3);
701 			set_color(colors[pvi]);
702 			draw_elements3(GL_TRIANGLES, i, i+2, i+4);
703 		}
704 	}
705 
706 	// draw last "wing" triangle
707 	set_color(gray);
708 	draw_elements3(GL_LINE_LOOP, i, i+2, i+3);
709 }
710 
711 
712 static void
use_program(GLuint program)713 use_program(GLuint program)
714 {
715 	glUseProgram(program);
716 	modelViewProjUniform = glGetUniformLocation(program, "modelViewProj");
717 	colorUniform = glGetUniformLocation(program, "color");
718 
719 	piglit_ortho_matrix(ortho_matrix, -2, 2, -2, 2, -1, 1);
720 	glUniformMatrix4fv(modelViewProjUniform, 1, GL_FALSE, ortho_matrix);
721 }
722 
723 
724 static void
set_viewport(unsigned pos)725 set_viewport(unsigned pos)
726 {
727 	int vp_w = piglit_width / 4;
728 	assert(pos < 4);
729 	glViewport(pos * vp_w, 0, vp_w, piglit_height);
730 }
731 
732 
733 static void
draw_gs_triangles(GLenum prim_mode,GLuint vao,unsigned num_verts,unsigned vp_pos)734 draw_gs_triangles(GLenum prim_mode, GLuint vao, unsigned num_verts,
735 		  unsigned vp_pos)
736 {
737 	size_t buffer_size;
738 	void *zeros;
739 
740 	use_program(gs_triangles_program);
741 	set_viewport(vp_pos);
742 	glBindVertexArray(vao);
743 
744 	buffer_size =
745 		12 * sizeof(float) *
746 		num_gs_prims(prim_mode, num_verts);
747 	zeros = calloc(1, buffer_size);
748 
749 	glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buf);
750 	glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, buffer_size,
751 			zeros, GL_STREAM_READ);
752 
753 	free(zeros);
754 
755 	glBeginTransformFeedback(GL_TRIANGLES);
756 
757 	if (draw_elements) {
758 		GLushort* elements;
759 
760 		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buf);
761 		glBufferData(GL_ELEMENT_ARRAY_BUFFER,
762 			sizeof(GLushort) * num_verts, NULL,
763 			GL_STATIC_DRAW);
764 		elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
765 		for (unsigned i = 0; i < num_verts; i++) {
766 			elements[i] = i;
767 		}
768 		glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
769 
770 		glDrawElements(prim_mode, num_verts, GL_UNSIGNED_SHORT, NULL);
771 	} else {
772 		glDrawArrays(prim_mode, 0, num_verts);
773 	}
774 
775 	glEndTransformFeedback();
776 }
777 
778 enum piglit_result
piglit_display(void)779 piglit_display(void)
780 {
781 	bool pass = true;
782 
783 	glClear(GL_COLOR_BUFFER_BIT);
784 
785 	if (draw_with_gs) {
786 		use_program(gs_lines_program);
787 		set_viewport(0);
788 		glBindVertexArray(lines_adj_vao);
789 		glDrawArrays(GL_LINES_ADJACENCY, 0,
790 			     NUM_VERTS(lines_adj_verts));
791 
792 		use_program(gs_line_strip_program);
793 		set_viewport(1);
794 		glBindVertexArray(line_strip_adj_vao);
795 		glDrawArrays(GL_LINE_STRIP_ADJACENCY, 0,
796 			     NUM_VERTS(line_strip_adj_verts));
797 
798 		draw_gs_triangles(GL_TRIANGLES_ADJACENCY, triangles_adj_vao,
799 				  NUM_VERTS(triangles_adj_verts), 2);
800 
801 		pass = probe_xfb(GL_TRIANGLES_ADJACENCY,
802 				 NUM_VERTS(triangles_adj_verts)) && pass;
803 
804 		draw_gs_triangles(GL_TRIANGLE_STRIP_ADJACENCY, triangle_strip_adj_vao,
805 				  NUM_VERTS(triangle_strip_adj_verts), 3);
806 
807 		pass = probe_xfb(GL_TRIANGLE_STRIP_ADJACENCY,
808 				 NUM_VERTS(triangle_strip_adj_verts)) && pass;
809 	}
810 	else {
811 		/* This path is basically for debugging and visualizing the
812 		 * "extra" lines and tris in adjacency primitives.
813 		 */
814 		use_program(ref_program);
815 
816 		set_viewport(0);
817 		draw_lines_adj(lines_adj_vao, 8);
818 
819 		set_viewport(1);
820 		draw_line_strip_adj(line_strip_adj_vao, 7);
821 
822 		set_viewport(2);
823 		draw_triangles_adj(triangles_adj_vao, 6);
824 
825 		set_viewport(3);
826 		draw_triangle_strip_adj(triangle_strip_adj_vao, 17);
827 	}
828 
829 	/* check the rendering */
830 	pass = probe_prims(GL_LINES_ADJACENCY,
831 			   lines_adj_verts,
832 			   NUM_VERTS(lines_adj_verts), 0) && pass;
833 
834 	pass = probe_prims(GL_LINE_STRIP_ADJACENCY,
835 			   line_strip_adj_verts,
836 			   NUM_VERTS(line_strip_adj_verts), 1) && pass;
837 
838 	pass = probe_prims(GL_TRIANGLES_ADJACENCY,
839 			   triangles_adj_verts,
840 			   NUM_VERTS(triangles_adj_verts), 2) && pass;
841 
842 	pass = probe_prims(GL_TRIANGLE_STRIP_ADJACENCY,
843 			   triangle_strip_adj_verts,
844 			   NUM_VERTS(triangle_strip_adj_verts), 3) && pass;
845 
846 	piglit_present_results();
847 
848 	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
849 }
850 
851 
852 static GLuint
create_vao(const GLfloat (* verts)[2],GLuint numVerts)853 create_vao(const GLfloat (*verts)[2], GLuint numVerts)
854 {
855 	GLuint vao, vbo;
856 
857 	glGenVertexArrays(1, &vao);
858 	glBindVertexArray(vao);
859 
860 	// positions
861 	glGenBuffers(1, &vbo);
862 	glBindBuffer(GL_ARRAY_BUFFER, vbo);
863 	glBufferData(GL_ARRAY_BUFFER, numVerts * VERTEX_SIZE,
864 		     verts, GL_STATIC_DRAW);
865 	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, VERTEX_SIZE, NULL);
866 	glEnableVertexAttribArray(0);
867 
868 	// colors
869 	glGenBuffers(1, &vbo);
870 	glBindBuffer(GL_ARRAY_BUFFER, vbo);
871 	glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
872 	glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), NULL);
873 	glEnableVertexAttribArray(1);
874 
875 	return vao;
876 }
877 
878 
879 void
piglit_init(int argc,char ** argv)880 piglit_init(int argc, char **argv)
881 {
882 	int i;
883 
884 	for (i = 1; i < argc; i++) {
885 		if (strcmp(argv[i], "line") == 0)
886 			polygon_mode = GL_LINE;
887 		else if (strcmp(argv[i], "cull-back") == 0)
888 			cull_mode = GL_BACK;
889 		else if (strcmp(argv[i], "cull-front") == 0)
890 			cull_mode = GL_FRONT;
891 		else if (strcmp(argv[i], "ref") == 0)
892 			draw_with_gs = GL_FALSE;
893 		else if (strcmp(argv[i], "pv-last") == 0)
894 			provoking_vertex = GL_LAST_VERTEX_CONVENTION;
895 		else if (strcmp(argv[i], "pv-first") == 0)
896 			provoking_vertex = GL_FIRST_VERTEX_CONVENTION;
897 		else if (strcmp(argv[i], "elements") == 0)
898 			draw_elements = true;
899 		else
900 			printf("Unexpected %s argument\n", argv[i]);
901 	}
902 
903 	glPolygonMode(GL_FRONT_AND_BACK, polygon_mode);
904 	if (cull_mode != GL_NONE) {
905 		glCullFace(cull_mode);
906 		glEnable(GL_CULL_FACE);
907 		glFrontFace(GL_CW);
908 	}
909 	glProvokingVertex(provoking_vertex);
910 
911 	glGenBuffers(1, &xfb_buf);
912 	glGenBuffers(1, &element_buf);
913 
914 	lines_adj_vao = create_vao(lines_adj_verts,
915 				   NUM_VERTS(lines_adj_verts));
916 
917 	line_strip_adj_vao = create_vao(line_strip_adj_verts,
918 					NUM_VERTS(line_strip_adj_verts));
919 
920 	triangles_adj_vao = create_vao(triangles_adj_verts,
921 				       NUM_VERTS(triangles_adj_verts));
922 
923 	triangle_strip_adj_vao = create_vao(triangle_strip_adj_verts,
924 					    NUM_VERTS(triangle_strip_adj_verts));
925 
926 	gs_lines_program = make_gs_program(GL_LINES_ADJACENCY);
927 	gs_line_strip_program = make_gs_program(GL_LINE_STRIP_ADJACENCY);
928 	gs_triangles_program = make_gs_program(GL_TRIANGLES_ADJACENCY);
929 	gs_triangle_strip_program = make_gs_program(GL_TRIANGLE_STRIP_ADJACENCY);
930 	ref_program = make_ref_program();
931 }
932