1 /*
2  * Copyright © 2010 Intel Corporation
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  * Authors:
24  *    Eric Anholt <eric@anholt.net>
25  *
26  */
27 
28 /** @file glsl-max-varyings.c
29  *
30  * Tests whether each varying can be used at all numbers of varyings up to
31  * GL_MAX_VARYING_FLOATS / 4.
32  */
33 
34 #include "piglit-util-gl.h"
35 
36 #define MAX_VARYING 256
37 
38 /* 2x2 rectangles with 2 pixels of pad.  Deal with up to 256 varyings. */
39 
40 PIGLIT_GL_TEST_CONFIG_BEGIN
41 
42 	config.supports_gl_compat_version = 10;
43 
44 	config.window_width = (2+MAX_VARYING*4);
45 	config.window_height = (2+MAX_VARYING*4);
46 	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
47 
48 PIGLIT_GL_TEST_CONFIG_END
49 
50 static bool exceed_limits = false;
51 static int max_varyings;
52 
53 /* Generate a VS that writes to num_varyings vec4s, and put
54  * interesting data in data_varying with 0.0 everywhere else.
55  */
get_vs(int num_varyings,int data_varying)56 static GLint get_vs(int num_varyings, int data_varying)
57 {
58 	GLuint shader;
59 	unsigned i;
60 	char *code = malloc(4096);
61 	char temp[2048];
62 
63 	code[0] = 0;
64 	for (i = 0; i < num_varyings; i++) {
65 		sprintf(temp, "varying vec4 v%d;\n", i);
66 		strcat(code, temp);
67 	}
68 
69 	sprintf(temp,
70 		"attribute vec4 vertex;\n"
71 		"attribute vec4 green;\n"
72 		"attribute vec4 red;\n"
73 		"void main()\n"
74 		"{\n"
75 		"	gl_Position = (gl_ModelViewProjectionMatrix * \n"
76 		"			vertex);\n"
77 		);
78 	strcat(code, temp);
79 
80 	for (i = 0; i < num_varyings; i++) {
81 		if (i == data_varying)
82 			sprintf(temp, "	v%d = green;\n", i);
83 		else
84 			sprintf(temp, "	v%d = red;\n", i);
85 		strcat(code, temp);
86 	}
87 
88 	sprintf(temp,
89 		"}\n"
90 		);
91 	strcat(code, temp);
92 
93 	shader = piglit_compile_shader_text(GL_VERTEX_SHADER, code);
94 	/* printf("%s\n", code); */
95 
96 	free(code);
97 	return shader;
98 }
99 
100 /* Generate a FS that does operations on num_varyings, yet makes only
101  * data_varying contribute to the output.
102  *
103  * We could make a single FS per num_varyings that did this by using a
104  * uniform for data_varying and some multiplication by comparisons
105  * (see glsl-routing for an example), but since we're linking a new
106  * shader each time anyway, this produces a simpler FS to read and
107  * verify.
108  */
get_fs(int num_varyings,int data_varying)109 static GLint get_fs(int num_varyings, int data_varying)
110 {
111 	GLuint shader;
112 	unsigned i;
113 	char *code = malloc(8192);
114 	char temp[2048];
115 
116 	code[0] = 0;
117 	for (i = 0; i < num_varyings; i++) {
118 		sprintf(temp, "varying vec4 v%d;\n", i);
119 		strcat(code, temp);
120 	}
121 
122 	sprintf(temp,
123 		"uniform float zero;\n"
124 		"uniform float one;\n"
125 		"void main()\n"
126 		"{\n"
127 		"	vec4 val = vec4(0.0);\n"
128 		);
129 	strcat(code, temp);
130 
131 	for (i = 0; i < num_varyings; i++) {
132 		if (i == data_varying)
133 			sprintf(temp, "	val += one * v%d;\n", i);
134 		else
135 			sprintf(temp, "	val += zero * v%d;\n", i);
136 		strcat(code, temp);
137 	}
138 
139 	sprintf(temp,
140 		"	gl_FragColor = val;\n"
141 		"}\n"
142 		);
143 	strcat(code, temp);
144 
145 	/* printf("%s\n", code); */
146 	shader = piglit_compile_shader_text(GL_FRAGMENT_SHADER, code);
147 
148 	free(code);
149 	return shader;
150 }
151 
152 static int
coord_from_index(int index)153 coord_from_index(int index)
154 {
155 	return 2 + 4 * index;
156 }
157 
158 static bool
draw(int num_varyings)159 draw(int num_varyings)
160 {
161 	int data_varying;
162 	float vertex[4][4] = { {0.0, 0.0, 0.0, 1.0},
163 			       {0.0, 0.0, 0.0, 1.0},
164 			       {0.0, 0.0, 0.0, 1.0},
165 			       {0.0, 0.0, 0.0, 1.0} };
166 	float green[4][4] = { {0.0, 1.0, 0.0, 0.0},
167 			      {0.0, 1.0, 0.0, 0.0},
168 			      {0.0, 1.0, 0.0, 0.0},
169 			      {0.0, 1.0, 0.0, 0.0} };
170 	float red[4][4] = { {1.0, 0.0, 0.0, 0.0},
171 			    {1.0, 0.0, 0.0, 0.0},
172 			    {1.0, 0.0, 0.0, 0.0},
173 			    {1.0, 0.0, 0.0, 0.0} };
174 
175 	glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float),
176 			      vertex);
177 	glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float),
178 			      green);
179 	glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float),
180 			      red);
181 	glEnableVertexAttribArray(0);
182 	glEnableVertexAttribArray(1);
183 	glEnableVertexAttribArray(2);
184 
185 	for (data_varying = 0; data_varying < num_varyings; data_varying++) {
186 		GLuint prog, vs, fs;
187 		GLint loc;
188 		float x, y;
189 
190 		vs = get_vs(num_varyings, data_varying);
191 		fs = get_fs(num_varyings, data_varying);
192 
193 		prog = glCreateProgram();
194 		glAttachShader(prog, vs);
195 		glAttachShader(prog, fs);
196 
197 		glBindAttribLocation(prog, 0, "vertex");
198 		glBindAttribLocation(prog, 1, "green");
199 		glBindAttribLocation(prog, 2, "red");
200 
201 		glLinkProgram(prog);
202 		if (!piglit_link_check_status_quiet(prog)) {
203 			if (num_varyings > max_varyings) {
204 				printf("Failed to link with %d out of %d "
205 				       "varyings used\n",
206 				       num_varyings, max_varyings);
207 				return false;
208 			} else {
209 				piglit_report_result(PIGLIT_FAIL);
210 			}
211 		}
212 
213 		glUseProgram(prog);
214 
215 		loc = glGetUniformLocation(prog, "zero");
216 		if (loc != -1) /* not used for num_varyings == 1 */
217 			glUniform1f(loc, 0.0);
218 
219 		loc = glGetUniformLocation(prog, "one");
220 		assert(loc != -1); /* should always be used */
221 		glUniform1f(loc, 1.0);
222 
223 		x = coord_from_index(data_varying);
224 		y = coord_from_index(num_varyings - 1);
225 		vertex[0][0] = x;
226 		vertex[0][1] = y;
227 		vertex[1][0] = x + 2;
228 		vertex[1][1] = y;
229 		vertex[2][0] = x;
230 		vertex[2][1] = y + 2;
231 		vertex[3][0] = x + 2;
232 		vertex[3][1] = y + 2;
233 		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
234 
235 		glDeleteShader(vs);
236 		glDeleteShader(fs);
237 		glDeleteProgram(prog);
238 	}
239 
240 	return true;
241 }
242 
243 enum piglit_result
piglit_display(void)244 piglit_display(void)
245 {
246 	GLint max_components;
247 	int test_varyings, row, col;
248 	GLboolean pass = GL_TRUE, warned = GL_FALSE;
249 	bool drew[MAX_VARYING];
250 
251 	piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
252 
253 	glGetIntegerv(GL_MAX_VARYING_FLOATS, &max_components);
254 	max_varyings = max_components / 4;
255 
256 	printf("GL_MAX_VARYING_FLOATS = %i\n", max_components);
257 
258 	test_varyings = max_varyings;
259 	if (exceed_limits)
260 		test_varyings++;
261 	if (test_varyings > MAX_VARYING) {
262 		printf("test not designed to handle >%d varying vec4s.\n"
263 		       "(implementation reports %d components)\n",
264 		       MAX_VARYING, max_varyings);
265 		test_varyings = MAX_VARYING;
266 		warned = GL_TRUE;
267 	}
268 
269 	glClearColor(0.5, 0.5, 0.5, 0.5);
270 	glClear(GL_COLOR_BUFFER_BIT);
271 
272 	for (row = 0; row < test_varyings; row++) {
273 		drew[row] = draw(row + 1);
274 	}
275 
276 	for (row = 0; row < test_varyings; row++) {
277 		if (!drew[row])
278 			continue;
279 
280 		for (col = 0; col <= row; col++) {
281 			GLboolean ok;
282 			float green[3] = {0.0, 1.0, 0.0};
283 
284 			ok = piglit_probe_rect_rgb(coord_from_index(col),
285 						   coord_from_index(row),
286 						   2, 2,
287 						   green);
288 			if (!ok) {
289 				printf("  Failure with %d vec4 varyings used "
290 				       "in varying index %d\n",
291 				       row + 1, col);
292 				pass = GL_FALSE;
293 				break;
294 			}
295 		}
296 	}
297 
298 	piglit_present_results();
299 
300 	if (!pass)
301 		return PIGLIT_FAIL;
302 	if (warned)
303 		return PIGLIT_WARN;
304 	else
305 		return PIGLIT_PASS;
306 }
307 
piglit_init(int argc,char ** argv)308 void piglit_init(int argc, char **argv)
309 {
310 	int i;
311 
312 	piglit_require_gl_version(20);
313 
314 	for (i = 0; i < argc; i++) {
315 		if (strcmp(argv[i], "--exceed-limits") == 0)
316 			exceed_limits = true;
317 	}
318 
319 	printf("Vertical axis: Increasing numbers of varyings.\n");
320 	printf("Horizontal axis: Which of the varyings contains the color.\n");
321 }
322 
323