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