1 /*
2  * Copyright © 2017 Fabian Bieler
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  * @file long-line-loop.c
26  * Draw cricles with line loops and a line strips blended on top of each
27  * other and check that the renderings match.
28  */
29 
30 #include "piglit-util-gl.h"
31 
32 PIGLIT_GL_TEST_CONFIG_BEGIN
33 
34 	config.supports_gl_compat_version = 10;
35 	config.window_width = 1024;
36 	config.window_height = 1024;
37 	config.window_visual = PIGLIT_GL_VISUAL_RGB;
38 	config.khr_no_error_support = PIGLIT_NO_ERRORS;
39 
40 PIGLIT_GL_TEST_CONFIG_END
41 
42 static int max_vertices;
43 static int num_vertices;
44 static int probe_location[2];
45 static const float radius = 0.9;
46 
47 static void
print_usage_and_exit(const char * prog_name)48 print_usage_and_exit(const char *prog_name)
49 {
50 	printf("Usage: %s [<vertex_count>]\n"
51 	       "  where <vertex_count> is the number of vertices to test.\n"
52 	       "\n"
53 	       "  If omitted, sequentially test from 16 to max_vertices by "
54 	       "quadrupling,\n"
55 	       "  where max_vertices is GL_MAX_ELEMENTS_VERTICES clamped to "
56 	       "[0x10000, 0x40000].\n",
57 	       prog_name);
58 	piglit_report_result(PIGLIT_FAIL);
59 }
60 
61 void
piglit_init(int argc,char ** argv)62 piglit_init(int argc, char **argv)
63 {
64 	glBlendFunc(GL_ONE, GL_ONE);
65 
66 	piglit_ortho_projection(piglit_width, piglit_height, false);
67 
68 	if (argc == 1) {
69 		/* This isn't a hard limit, but staying below should help
70 		 * performance.
71 		 *
72 		 * XXX: It could be interesting to go beyond this limit to
73 		 * test a different code path in the GL implementation.
74 		 */
75 		glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &max_vertices);
76 		max_vertices = CLAMP(max_vertices, 0x10000, 0x40000);
77 	} else if (argc == 2) {
78 		char *endptr;
79 		num_vertices = strtol(argv[1], &endptr, 0);
80 		if (endptr != argv[1] + strlen(argv[1]))
81 			print_usage_and_exit(argv[0]);
82 		if (num_vertices < 6)
83 			print_usage_and_exit(argv[0]);
84 	} else {
85 		print_usage_and_exit(argv[0]);
86 	}
87 }
88 
89 static void
draw_circle(int segments)90 draw_circle(int segments)
91 {
92 	/* The first (segments - 1) vertices describe the arc of a circle
93 	 * slice with central angle (360° - alpha).
94 	 * The last vertex is identical to the first vertex.
95 	 * alpha is chosen so that the last line segment covers two pixels.
96 	 */
97 	const float alpha = asinf(2.0 / (piglit_width / 2 * radius));
98 	struct {
99 		float pos[4];
100 		float green[4];
101 		float blue[4];
102 	} *vertex = malloc(sizeof(vertex[0]) * segments);
103 
104 	for (int i = 0; i < segments - 1; ++i) {
105 		const float phi = alpha -
106 				  (2 * M_PI - alpha) /
107 				  (float)(segments - 2) *
108 				  (float)i;
109 
110 		vertex[i].pos[0] = round(piglit_width / 2 *
111 					  (1 + radius * cosf(phi))) + 0.5;
112 		vertex[i].pos[1] = round(piglit_height / 2 *
113 					  (1 + radius * sinf(phi))) + 0.5;
114 		vertex[i].pos[2] = 0;
115 		vertex[i].pos[3] = 1;
116 		vertex[i].green[0] = 0;
117 		vertex[i].green[1] = 1;
118 		vertex[i].green[2] = 0;
119 		vertex[i].green[3] = 1;
120 		vertex[i].blue[0] = 0;
121 		vertex[i].blue[1] = 0;
122 		vertex[i].blue[2] = 1;
123 		vertex[i].blue[3] = 1;
124 	}
125 	memcpy(&vertex[segments - 1], &vertex[0], sizeof(vertex[0]));
126 
127 	/* Find a pixel in the last line segment: */
128 	for (int i = 0; i < 2; ++i)
129 		probe_location[i] = round((vertex[segments - 2].pos[i] +
130 					   vertex[segments - 1].pos[i] -
131 					   1.0) / 2.0);
132 
133 	/* Render twice: */
134 	glClear(GL_COLOR_BUFFER_BIT);
135 
136 	glVertexPointer(4, GL_FLOAT, sizeof(vertex[0]), vertex[0].pos);
137 	glColorPointer(4, GL_FLOAT, sizeof(vertex[0]), vertex[0].green);
138 
139 	glEnableClientState(GL_VERTEX_ARRAY);
140 	glEnableClientState(GL_COLOR_ARRAY);
141 
142 	glDrawArrays(GL_LINE_LOOP, 0, segments - 1);
143 
144 	glEnable(GL_BLEND);
145 	glColorPointer(4, GL_FLOAT, sizeof(vertex[0]), vertex[0].blue);
146 	glDrawArrays(GL_LINE_STRIP, 0, segments);
147 	glDisable(GL_BLEND);
148 
149 	free(vertex);
150 
151 	piglit_present_results();
152 }
153 
154 static bool
check_circle(void)155 check_circle(void)
156 {
157 	bool pass = true;
158 	const float teal[] = {0, 1, 1};
159 	const float black[] = {0, 0, 0};
160 
161 	/* check that the two renderings are identical */
162 	pass = piglit_probe_rect_two_rgb(0, 0, piglit_width, piglit_height,
163 					 black, teal) && pass;
164 
165 	/* belt + suspenders: Additionally check that the last line segment
166 	 * was drawn...
167 	 */
168 	pass = piglit_probe_pixel_rgb(probe_location[0], probe_location[1],
169 				      teal) && pass;
170 
171 	/* ...and that the center of the circle is black */
172 	const int x = ceil(piglit_width / 2 * radius / M_SQRT2) + 1;
173 	const int y = ceil(piglit_height / 2 * radius / M_SQRT2) + 1;
174 	pass = piglit_probe_rect_rgb(x, y, piglit_width - 2 * x,
175 				     piglit_height - 2 * y, black) && pass;
176 
177 	return pass;
178 }
179 
180 enum piglit_result
piglit_display(void)181 piglit_display(void)
182 {
183 	bool pass = true;
184 
185 	if (max_vertices) {
186 		for (int vertices = 16;
187 		     vertices <= max_vertices;
188 		     vertices <<= 2) {
189 			draw_circle(vertices);
190 			pass = check_circle() && pass;
191 		}
192 	} else {
193 		draw_circle(num_vertices);
194 		pass = check_circle() && pass;
195 	}
196 
197 	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
198 }
199 
200