1 /*
2  * Copyright © 2009, 2013 VMware, Inc.
3  * Copyright © 2015 Intel Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 /*
26  * Test that the correct provoking vertex is used when a tri/quad/polygon
27  * is clipped for glShadeModel(GL_FLAT).
28  *
29  * This is based on the glean clipFlat test.
30  *
31  * Test with glDrawArrays and glBegin/End.  Test GL_CCW and GL_CW winding.
32  * Back-face polygon culling is enabled so if the winding order of any
33  * primitive is incorrect, nothing may be drawn.
34  *
35  * XXX We should also test with two-sided lighting.
36  *
37  * If GL_ARB/EXT_provoking_vertex is supported, that feature is tested as well.
38  *
39  * Author: Brian Paul
40  */
41 
42 
43 #include "piglit-util-gl.h"
44 
45 PIGLIT_GL_TEST_CONFIG_BEGIN
46 	config.supports_gl_compat_version = 10;
47 	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
48 	config.khr_no_error_support = PIGLIT_NO_ERRORS;
49 PIGLIT_GL_TEST_CONFIG_END
50 
51 
52 /* Note: all correctly rendered tris/quad/polygons will be green.
53  * Any other color indicates that the wrong vertex color was used.
54  */
55 
56 // GL_TRIANGLES: provoking vertex = last of tri
57 static const GLfloat TriVerts[6][5] =
58 	{
59 		// R  G  B     X   Y
60 		{ 1, 0, 0,   -1, -1 },
61 		{ 0, 0, 1,    1, -1 },
62 		{ 0, 1, 0,    1,  1 }, // PV
63 
64 		{ 0, 0, 1,    1,  1 },
65 		{ 1, 0, 0,   -1,  1 },
66 		{ 0, 1, 0,   -1, -1 } // PV
67 	};
68 
69 // GL_TRIANGLES: first provoking vertex
70 static const GLfloat TriVertsFirstPV[6][5] =
71 	{
72 		{ 0, 1, 0,    1,  1 }, // PV
73 		{ 1, 0, 0,   -1, -1 },
74 		{ 0, 0, 1,    1, -1 },
75 
76 		{ 0, 1, 0,   -1, -1 }, // PV
77 		{ 0, 0, 1,    1,  1 },
78 		{ 1, 0, 0,   -1,  1 }
79 	};
80 
81 
82 // GL_TRIANGLE_STRIP: provoking vertex = last of tri
83 static const GLfloat TriStripVerts[6][5] =
84 	{
85 		{ 1, 0, 0,   -1, -1 },
86 		{ 0, 0, 1,    1, -1 },
87 		{ 0, 1, 0,   -1,  0 }, // PV
88 		{ 0, 1, 0,    1,  0 }, // PV
89 		{ 0, 1, 0,   -1,  1 }, // PV
90 		{ 0, 1, 0,    1,  1 }  // PV
91 	};
92 
93 // GL_TRIANGLE_STRIP: first provoking vertex
94 static const GLfloat TriStripVertsFirstPV[6][5] =
95 	{
96 		{ 0, 1, 0,   -1, -1 }, // PV
97 		{ 0, 1, 0,    1, -1 }, // PV
98 		{ 0, 1, 0,   -1,  0 }, // PV
99 		{ 0, 1, 0,    1,  0 }, // PV
100 		{ 1, 0, 0,   -1,  1 },
101 		{ 0, 0, 1,    1,  1 }
102 	};
103 
104 
105 // GL_TRIANGLE_FAN: provoking vertex = last of tri
106 static const GLfloat TriFanVerts[4][5] =
107 	{
108 		{ 1, 0, 0,   -1, -1 },
109 		{ 0, 0, 1,    1, -1 },
110 		{ 0, 1, 0,    1,  1 }, // PV
111 		{ 0, 1, 0,   -1,  1 }  // PV
112 	};
113 
114 // GL_TRIANGLE_FAN: first provoking vertex
115 static const GLfloat TriFanVertsFirstPV[4][5] =
116 	{
117 		{ 0, 0, 1,    1, -1 },
118 		{ 0, 1, 0,    1,  1 }, // PV
119 		{ 0, 1, 0,   -1,  1 }, // PV
120 		{ 1, 0, 0,   -1, -1 }
121 	};
122 
123 
124 // GL_QUADS: provoking vertex = last of quad
125 static const GLfloat QuadVerts[4][5] =
126 	{
127 		{ 1, 0, 0,   -1, -1 },
128 		{ 0, 0, 1,    1, -1 },
129 		{ 1, 1, 0,    1,  1 },
130 		{ 0, 1, 0,   -1,  1 }  // PV
131 	};
132 
133 // GL_QUADS: first provoking vertex
134 static const GLfloat QuadVertsFirstPV[4][5] =
135 	{
136 		{ 0, 1, 0,   -1,  1 }, // PV
137 		{ 1, 0, 0,   -1, -1 },
138 		{ 0, 0, 1,    1, -1 },
139 		{ 1, 1, 0,    1,  1 }
140 	};
141 
142 
143 // GL_QUAD_STRIP: provoking vertex = last of quad
144 static const GLfloat QuadStripVerts[6][5] =
145 	{
146 		{ 1, 0, 0,   -1, -1 },
147 		{ 0, 0, 1,    1, -1 },
148 		{ 1, 1, 0,   -1,  0 },
149 		{ 0, 1, 0,    1,  0 }, // PV
150 		{ 1, 1, 0,   -1,  1 },
151 		{ 0, 1, 0,    1,  1 }  // PV
152 	};
153 
154 // GL_QUAD_STRIP: first provoking vertex
155 static const GLfloat QuadStripVertsFirstPV[6][5] =
156 	{
157 		{ 0, 1, 0,   -1, -1 }, // PV
158 		{ 1, 1, 0,    1, -1 },
159 		{ 0, 1, 0,   -1,  0 }, // PV
160 		{ 1, 0, 0,    1,  0 },
161 		{ 0, 0, 1,   -1,  1 },
162 		{ 1, 0, 0,    1,  1 }
163 	};
164 
165 
166 // GL_POLYGON: provoking vertex = first vertex
167 static const GLfloat PolygonVerts[4][5] =
168 	{
169 		{ 0, 1, 0,   -1, -1 }, // PV
170 		{ 1, 0, 0,    1, -1 },
171 		{ 0, 0, 1,    1,  1 },
172 		{ 1, 1, 0,   -1,  1 }
173 	};
174 
175 
176 enum draw_mode {
177 	BEGIN_END,
178 	DRAW_ARRAYS,
179 	DRAW_ELEMENTS,
180 	NUM_DRAW_MODES
181 };
182 
183 
184 static bool provoking_vertex_first;
185 static bool quads_follows_pv_convention;
186 static bool testing_first_pv;
187 
188 
189 void
piglit_init(int argc,char ** argv)190 piglit_init(int argc, char **argv)
191 {
192 	glMatrixMode(GL_PROJECTION);
193 	glLoadIdentity();
194 	glOrtho(-1.25, 1.25, -1.25, 1.25, -1, 1);
195 	glMatrixMode(GL_MODELVIEW);
196 	glLoadIdentity();
197 
198 	glShadeModel(GL_FLAT);
199 	glPixelStorei(GL_PACK_ALIGNMENT, 1);
200 
201 	glFrontFace(GL_CW);
202 	glCullFace(GL_FRONT);
203 	glEnable(GL_CULL_FACE);
204 
205 	if (piglit_is_extension_supported("GL_ARB_provoking_vertex")) {
206 		provoking_vertex_first = true;
207 	}
208 	else if (piglit_is_extension_supported("GL_EXT_provoking_vertex")) {
209 		provoking_vertex_first = true;
210 	}
211 
212 	printf("Have GL_ARB/EXT_provoking_vertex: %s\n",
213 	       provoking_vertex_first ? "yes" : "no");
214 
215 	if (provoking_vertex_first) {
216 		GLboolean k;
217 		glGetBooleanv(GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT, &k);
218 		quads_follows_pv_convention = k;
219 
220 		printf("Quads follow provoking vertex convention: %s\n",
221 		       k ? "yes" : "no");
222 	}
223 }
224 
225 
226 // Draw with glDrawArrays()
227 static void
drawArrays(GLenum mode,const GLfloat * verts,GLuint count)228 drawArrays(GLenum mode, const GLfloat *verts, GLuint count)
229 {
230 	glColorPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), verts + 0);
231 	glVertexPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), verts + 3);
232 	glEnableClientState(GL_COLOR_ARRAY);
233 	glEnableClientState(GL_VERTEX_ARRAY);
234 
235 	glDrawArrays(mode, 0, count);
236 
237 	glDisableClientState(GL_COLOR_ARRAY);
238 	glDisableClientState(GL_VERTEX_ARRAY);
239 }
240 
241 
242 // Draw with glDrawElements()
243 static void
drawElements(GLenum mode,const GLfloat * verts,GLuint count)244 drawElements(GLenum mode, const GLfloat *verts, GLuint count)
245 {
246 	static const GLuint elements[6] = { 0, 1, 2, 3, 4, 5 };
247 	glColorPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), verts + 0);
248 	glVertexPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), verts + 3);
249 	glEnableClientState(GL_COLOR_ARRAY);
250 	glEnableClientState(GL_VERTEX_ARRAY);
251 
252 	assert(count <= ARRAY_SIZE(elements));
253 
254 	glDrawElements(mode, count, GL_UNSIGNED_INT, elements);
255 
256 	glDisableClientState(GL_COLOR_ARRAY);
257 	glDisableClientState(GL_VERTEX_ARRAY);
258 }
259 
260 
261 // Draw with glBegin/End()
262 static void
drawBeginEnd(GLenum mode,const GLfloat * verts,GLuint count)263 drawBeginEnd(GLenum mode, const GLfloat *verts, GLuint count)
264 {
265 	GLuint i;
266 
267 	glBegin(mode);
268 	for (i = 0; i < count; i++) {
269 		glColor3fv(verts + i * 5);
270 		glVertex2fv(verts + i * 5 + 3);
271 	}
272 	glEnd();
273 }
274 
275 
276 // Read pixels and check pixels.  All pixels should be green or black.
277 // Any other color indicates a failure.
278 static bool
checkResult(GLfloat badColor[3])279 checkResult(GLfloat badColor[3])
280 {
281 	GLubyte *image;
282 	GLuint i, j;
283 	bool anyGreen = false;
284 
285 	image = malloc(piglit_width * piglit_height * 3);
286 
287 	badColor[0] = badColor[1] = badColor[2] = 0.0f;
288 
289 	glReadPixels(0, 0, piglit_width, piglit_height,
290 		     GL_RGB, GL_UNSIGNED_BYTE, image);
291 
292 	if (!piglit_automatic)
293 		piglit_present_results();
294 
295 	for (i = 0; i < piglit_height; i++) {
296 		for (j = 0; j < piglit_width; j++) {
297 			GLuint k = (i * piglit_width + j) * 3;
298 
299 			if (image[k + 0] == 0 &&
300 			    image[k + 1] == 0 &&
301 			    image[k + 2] == 0) {
302 				// black - OK
303 			}
304 			else if (image[k + 0] == 0 &&
305 				 image[k + 1] >= 254 &&
306 				 image[k + 2] == 0) {
307 				// green - OK
308 				anyGreen = true;
309 			}
310 			else {
311 				// any other color = failure
312 				badColor[0] = image[k + 0] / 255.0;
313 				badColor[1] = image[k + 1] / 255.0;
314 				badColor[2] = image[k + 2] / 255.0;
315 				free(image);
316 				return false;
317 			}
318 		}
319 	}
320 
321 	free(image);
322 
323 	return anyGreen;
324 }
325 
326 
327 char *
calcQuadrant(GLfloat x,GLfloat y)328 calcQuadrant(GLfloat x, GLfloat y)
329 {
330 	const char *strx, *stry;
331 	char *ret;
332 	int _x, _y;
333 	_x = (int) x;
334 	_y = (int) y;
335 
336 	switch (_x) {
337 	case -1:
338 		strx = "left";
339 		break;
340 	case 0:
341 		strx = "center";
342 		break;
343 	case 1:
344 		strx = "right";
345 		break;
346 	default:
347 		assert(0);
348 	}
349 
350 	switch (_y) {
351 	case 1:
352 		stry = "top";
353 		break;
354 	case 0:
355 		stry = "middle";
356 		break;
357 	case -1:
358 		stry = "bottom";
359 		break;
360 	default:
361 		assert(0);
362 	}
363 
364 	(void)!asprintf(&ret, "%s %s", strx, stry);
365 	return ret;
366 }
367 
368 
369 static void
reportSubtest(GLenum mode,int drawMode,const GLenum order,const GLenum poly_mode,const GLfloat badColor[3],GLfloat x,GLfloat y,bool pass)370 reportSubtest(GLenum mode, int drawMode,
371               const GLenum order, const GLenum poly_mode,
372               const GLfloat badColor[3], GLfloat x, GLfloat y,
373               bool pass)
374 {
375 	const char *m, *d, *f, *p;
376 	char *q;
377 
378 	m = piglit_get_prim_name(mode);
379 
380 	switch (drawMode) {
381 	case BEGIN_END:
382 		d = "glBegin/End";
383 		break;
384 	case DRAW_ARRAYS:
385 		d = "glDrawArrays";
386 		break;
387 	case DRAW_ELEMENTS:
388 		d = "glDrawElements";
389 		break;
390 	default:
391 		assert(0);
392 		d = "???";
393 	}
394 
395 	f = piglit_get_gl_enum_name(order);
396 
397 	p = piglit_get_gl_enum_name(poly_mode);
398 
399 	q = calcQuadrant(x, y);
400 
401 	if (!pass) {
402 		printf("clipflat: Failure for %s(%s), glFrontFace(%s), "
403 		       "glPolygonMode(%s), quadrant: %s\n",
404 		       d, m, f, p, q);
405 
406 		if (testing_first_pv) {
407 			printf("\tGL_EXT_provoking_vertex test: "
408 			       "GL_FIRST_VERTEX_CONVENTION_EXT mode\n");
409 		}
410 
411 		printf("Expected color (0, 1, 0) but found (%g, %g, %g)\n",
412 		       badColor[0], badColor[1], badColor[2]);
413 		printf("\n");
414 	}
415 
416 	piglit_report_subtest_result(pass ? PIGLIT_PASS : PIGLIT_FAIL,
417 				     "%s(%s), glFrontFace(%s), glPolygonMode(%s), "
418 				     "quadrant: %s",
419 				     d, m, f, p, q);
420 
421 	free(q);
422 }
423 
424 
425 // Test a particular primitive mode for one drawing mode, filled/unfilled
426 // state and CW/CCW winding.
427 static bool
testPrimCombo(GLenum mode,const GLfloat * verts,GLuint count,bool fill,enum draw_mode drawMode,GLuint facing)428 testPrimCombo(GLenum mode, const GLfloat *verts, GLuint count,
429 			  bool fill, enum draw_mode drawMode, GLuint facing)
430 {
431 	GLfloat x, y;
432 	bool pass = true;
433 	const GLenum poly_mode = fill ? GL_LINE : GL_FILL;
434 	const GLenum order = facing ? GL_CW : GL_CCW;
435 	const GLenum cull_face = facing ? GL_FRONT : GL_BACK;
436 
437 	glPolygonMode(GL_FRONT_AND_BACK, poly_mode);
438 
439 	glFrontFace(order);
440 	glCullFace(cull_face);
441 
442 	// Position the geometry at 9 different locations to test
443 	// clipping against the left, right, bottom and top edges of
444 	// the window.
445 	// Only the center location will be unclipped.
446 	for (y = -1.0; y <= 1.0; y += 1.0) {
447 		for (x = -1.0; x <= 1.0; x += 1.0) {
448 			bool quad_pass;
449 			GLfloat badColor[3];
450 
451 			glPushMatrix();
452 			glTranslatef(x, y, 0.0);
453 
454 			glClear(GL_COLOR_BUFFER_BIT);
455 
456 			switch (drawMode) {
457 			case BEGIN_END:
458 				drawBeginEnd(mode, verts, count);
459 				break;
460 			case DRAW_ARRAYS:
461 				drawArrays(mode, verts, count);
462 				break;
463 			case DRAW_ELEMENTS:
464 				drawElements(mode, verts, count);
465 				break;
466 			default:
467 				assert(0);
468 			}
469 
470 			glPopMatrix();
471 
472 			quad_pass = checkResult(badColor);
473 			pass = pass && quad_pass;
474 			reportSubtest(mode, drawMode, order, poly_mode,
475 						  badColor, x, y, quad_pass);
476 		}
477 	}
478 
479 	return pass;
480 }
481 
482 
483 // Test a particular primitive mode for all drawing modes, filled/unfilled
484 // and CW/CCW winding.
485 static bool
testPrim(GLenum mode,const GLfloat * verts,GLuint count)486 testPrim(GLenum mode, const GLfloat *verts, GLuint count)
487 {
488 	GLuint facing, fill;
489 	int drawMode;
490 	bool pass = true;
491 
492 	// Loop over polygon mode: filled vs. outline
493 	for (fill = 0; fill < 2; fill++) {
494 
495 		// Loop over drawing mode: glBegin/End vs glDrawArrays vs glDrawElements
496 		for (drawMode = 0; drawMode < NUM_DRAW_MODES; drawMode++) {
497 
498 			// Loop over CW vs. CCW winding (should make no difference)
499 			for (facing = 0; facing < 2; facing++) {
500 				pass = testPrimCombo(mode, verts, count,
501 									 fill, drawMode, facing) && pass;
502 			}
503 		}
504 	}
505 	return pass;
506 }
507 
508 
509 enum piglit_result
piglit_display(void)510 piglit_display(void)
511 {
512 	bool pass = true;
513 
514 	testing_first_pv = false;
515 
516 	pass = testPrim(GL_TRIANGLES,
517 			(GLfloat *) TriVerts,
518 			ARRAY_SIZE(TriVerts)) && pass;
519 
520 	pass = testPrim(GL_TRIANGLE_STRIP,
521 			(GLfloat *) TriStripVerts,
522 			ARRAY_SIZE(TriStripVerts)) && pass;
523 
524 	pass = testPrim(GL_TRIANGLE_FAN,
525 			(GLfloat *) TriFanVerts,
526 			ARRAY_SIZE(TriFanVerts)) && pass;
527 
528 	pass = testPrim(GL_QUADS,
529 			(GLfloat *) QuadVerts,
530 			ARRAY_SIZE(QuadVerts)) && pass;
531 
532 	pass = testPrim(GL_QUAD_STRIP,
533 			(GLfloat *) QuadStripVerts,
534 			ARRAY_SIZE(QuadStripVerts)) && pass;
535 
536 	pass = testPrim(GL_POLYGON,
537 			(GLfloat *) PolygonVerts,
538 			ARRAY_SIZE(PolygonVerts)) && pass;
539 
540 	if (provoking_vertex_first) {
541 		glProvokingVertex(GL_FIRST_VERTEX_CONVENTION_EXT);
542 		testing_first_pv = true;
543 
544 		pass = testPrim(GL_TRIANGLES,
545 				(GLfloat *) TriVertsFirstPV,
546 				ARRAY_SIZE(TriVertsFirstPV)) && pass;
547 
548 		pass = testPrim(GL_TRIANGLE_STRIP,
549 				(GLfloat *) TriStripVertsFirstPV,
550 				ARRAY_SIZE(TriStripVertsFirstPV)) && pass;
551 
552 		pass = testPrim(GL_TRIANGLE_FAN,
553 				(GLfloat *) TriFanVertsFirstPV,
554 				ARRAY_SIZE(TriFanVertsFirstPV)) && pass;
555 
556 		if (quads_follows_pv_convention)
557 			pass = testPrim(GL_QUADS,
558 					(GLfloat *) QuadVertsFirstPV,
559 					ARRAY_SIZE(QuadVertsFirstPV)) && pass;
560 		else
561 			pass = testPrim(GL_QUADS,
562 					(GLfloat *) QuadVerts,
563 					ARRAY_SIZE(QuadVerts)) && pass;
564 
565 		if (quads_follows_pv_convention)
566 			pass = testPrim(GL_QUAD_STRIP,
567 					(GLfloat *) QuadStripVertsFirstPV,
568 					ARRAY_SIZE(QuadStripVertsFirstPV)) && pass;
569 		else
570 			pass = testPrim(GL_QUAD_STRIP,
571 					(GLfloat *) QuadStripVerts,
572 					ARRAY_SIZE(QuadStripVerts)) && pass;
573 
574 		pass  = testPrim(GL_POLYGON,
575 				 (GLfloat *) PolygonVerts,
576 				 ARRAY_SIZE(PolygonVerts)) && pass;
577 	}
578 
579 	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
580 }
581