2 * Copyright © 2012 Intel Corporation
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:
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
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
24 /** @file glsl-max-varyings.c
26 * Test that all varyings can be captured using transform feedback, up
27 * to the maximum allowed by
28 * GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS. Also verify that
29 * the varyings are passed correctly to the fragment shader. This
30 * test uses vec4 varyings, so it does not rely on the implementation
31 * packing varyings correctly.
33 * The test uses a vertex shader that generates an array of
34 * (GL_MAX_VARYING_FLOATS / 4) vec4's, and a fragment shader that
35 * checks the values of all of those vec4's. It uses transform
36 * feedback to capture contiguous subsets of that array, with all
37 * possible lengths and offsets.
40 #include "piglit-util-gl.h"
42 #define MAX_VARYING 32
43 #define AOA_OUTER_DIM 2
45 static const struct piglit_gl_test_config
* piglit_config
;
46 static const char *xfb_varying_array
[MAX_VARYING
];
47 static const char *xfb_varying_aoa
[MAX_VARYING
];
48 static GLuint xfb_buf
;
50 /* Generate a VS that writes to a varying vec4[num_varyings] called
51 * "v". The values written are v[0] = (0.0, 1.0, 2.0, 3.0), v[1] =
52 * (4.0, 5.0, 6.0, 7.0), and so on.
55 get_vs(int num_varyings
)
62 "varying vec4[%d] v;\n"
67 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
68 " for (i = 0; i < v.length(); ++i) {\n"
69 " v[i] = 4.0*i + vec4(0.0, 1.0, 2.0, 3.0);\n"
73 shader
= piglit_compile_shader_text(GL_VERTEX_SHADER
, vstext
);
79 get_vs_aoa(int num_varyings
)
83 int inner_dim
= num_varyings
/ AOA_OUTER_DIM
;
85 /* If there is an odd number of varyings add one more */
87 char *extra_statement
;
88 if (num_varyings
% 2 != 0) {
89 extra_varying
= "varying vec4 y;";
90 extra_statement
= "y = 4.0*(offset+j) + vec4(0.0, 1.0, 2.0, 3.0);";
98 "#extension GL_ARB_arrays_of_arrays : enable\n"
99 "varying vec4[%d][%d] v;\n"
106 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
107 " for (int i = 0; i < v.length(); ++i) {\n"
108 " offset = i * v[i].length();\n"
109 " for (j = 0; j < v[i].length(); ++j) {\n"
110 " v[i][j] = 4.0*(offset+j) + vec4(0.0, 1.0, 2.0, 3.0);\n"
114 "}\n", AOA_OUTER_DIM
, inner_dim
, extra_varying
, extra_statement
);
116 shader
= piglit_compile_shader_text(GL_VERTEX_SHADER
, vstext
);
121 /* Generate a FS that checks all the varyings written by the VS, and
122 * outputs green if they are all correct.
125 get_fs(int num_varyings
)
132 "varying vec4[%d] v;\n"
136 " bool failed = false;\n"
137 " for(int i = 0; i < v.length(); ++i) {\n"
138 " failed = failed || (v[i] != 4.0*i + vec4(0.0, 1.0, 2.0, 3.0));\n"
140 " gl_FragColor = vec4(float(failed), 1.0 - float(failed), 0.0, 1.0);\n"
141 "}\n", num_varyings
);
143 shader
= piglit_compile_shader_text(GL_FRAGMENT_SHADER
, fstext
);
149 get_fs_aoa(int num_varyings
)
153 int inner_dim
= num_varyings
/ AOA_OUTER_DIM
;
155 /* If there is an odd number of varyings add one more */
157 char *extra_statement
;
158 if (num_varyings
% 2 != 0) {
159 extra_varying
= "varying vec4 y;";
160 extra_statement
= "failed = failed || (y != 4.0*(offset+j) + vec4(0.0, 1.0, 2.0, 3.0));";
164 extra_statement
= "";
169 "#extension GL_ARB_arrays_of_arrays : enable\n"
170 "varying vec4[%d][%d] v;\n"
175 " bool failed = false;\n"
178 " for(int i = 0; i < v.length(); ++i) {\n"
179 " offset = i * v[i].length();\n"
180 " for (j = 0; j < v[i].length(); ++j) {\n"
181 " failed = failed || (v[i][j] != 4.0*(offset+j) + vec4(0.0, 1.0, 2.0, 3.0));\n"
185 " gl_FragColor = vec4(float(failed), 1.0 - float(failed), 0.0, 1.0);\n"
186 "}\n", AOA_OUTER_DIM
, inner_dim
, extra_varying
, extra_statement
);
188 shader
= piglit_compile_shader_text(GL_FRAGMENT_SHADER
, fstext
);
194 * Initialize xfb_varying_array to contain the names of the varyings
195 * used by get_vs and get_fs.
198 init_xfb_varyings(int max_varyings
)
201 int inner_dim
= max_varyings
/ AOA_OUTER_DIM
;
204 /* Initialise arrays of arrays */
205 for (i
= 0; i
< AOA_OUTER_DIM
; ++i
) {
206 for (j
= 0; j
< inner_dim
; ++j
) {
207 char *buf
= malloc(16);
208 sprintf(buf
, "v[%d][%d]", i
, j
);
209 xfb_varying_aoa
[count
++] = buf
;
212 if (max_varyings
% 2 != 0) {
213 char *buf
= malloc(8);
215 xfb_varying_aoa
[count
++] = buf
;
218 /* Initialise singlie dimension array */
219 for (i
= 0; i
< MAX_VARYING
; ++i
) {
220 char *buf
= malloc(6);
221 sprintf(buf
, "v[%d]", i
);
222 xfb_varying_array
[i
] = buf
;
227 coord_from_index(int index
)
229 return 2 + 12 * index
;
233 check_xfb_output(int max_varyings
, int num_xfb_varyings
,
234 int offset
, const char **xfb_varyings
)
236 GLboolean pass
= GL_TRUE
;
237 int vertex
, varying
, i
;
238 float (*buffer
)[4] = glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER
,
242 for (vertex
= 0; vertex
< 6; ++vertex
) {
243 for (varying
= 0; varying
< num_xfb_varyings
; ++varying
) {
246 for (i
= 0; i
< 4; ++i
) {
247 expected
[i
] = (varying
+ offset
) * 4.0 + i
;
249 actual
= buffer
[vertex
* num_xfb_varyings
+ varying
];
250 if (memcmp(expected
, actual
, 4 * sizeof(float)) != 0) {
251 printf("When recording %i varyings\n",
253 printf("Out of a total of %i\n", max_varyings
);
254 printf("With an offset of %i\n", offset
);
255 printf("Got incorrect transform feedback data "
256 "for vertex %i, varying %s\n",
257 vertex
, *(xfb_varyings
+ offset
));
258 printf("Expected (%f, %f, %f, %f)\n",
259 expected
[0], expected
[1], expected
[2],
261 printf("Actual (%f, %f, %f, %f)\n",
262 actual
[0], actual
[1], actual
[2],
265 if (++numFail
>= 10) {
273 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER
);
279 draw(GLuint vs
, GLuint fs
, int num_xfb_varyings
,
280 int max_varyings
, const char **xfb_varyings
)
282 GLboolean pass
= GL_TRUE
;
285 for (offset
= 0; offset
+ num_xfb_varyings
<= max_varyings
; ++offset
) {
287 float initial_buffer
[MAX_VARYING
* 6][4];
289 prog
= glCreateProgram();
290 glAttachShader(prog
, vs
);
291 glAttachShader(prog
, fs
);
293 glTransformFeedbackVaryings(prog
, num_xfb_varyings
,
294 xfb_varyings
+ offset
,
295 GL_INTERLEAVED_ATTRIBS
);
298 if (!piglit_link_check_status(prog
))
299 piglit_report_result(PIGLIT_FAIL
);
303 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER
, xfb_buf
);
304 memset(initial_buffer
, 0, sizeof(initial_buffer
));
305 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER
,
306 sizeof(initial_buffer
), initial_buffer
,
308 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER
, 0, xfb_buf
);
309 glBeginTransformFeedback(GL_TRIANGLES
);
311 piglit_draw_rect(coord_from_index(offset
),
312 coord_from_index(num_xfb_varyings
- 1),
316 glEndTransformFeedback();
317 pass
= check_xfb_output(max_varyings
, num_xfb_varyings
,
318 offset
, xfb_varyings
);
320 glDeleteProgram(prog
);
330 run_subtest(GLuint vs
, GLuint fs
, int max_xfb_varyings
,
331 int max_varyings
, const char **xfb_varyings
)
333 GLboolean pass
= GL_TRUE
;
336 glClearColor(0.5, 0.5, 0.5, 0.5);
337 glClear(GL_COLOR_BUFFER_BIT
);
339 for (row
= 0; row
< max_xfb_varyings
; row
++) {
340 pass
= draw(vs
, fs
, row
+ 1, max_varyings
, xfb_varyings
);
346 for (row
= 0; row
< max_xfb_varyings
; row
++) {
347 for (col
= 0; col
< max_varyings
- row
; col
++) {
349 float green
[3] = {0.0, 1.0, 0.0};
351 ok
= piglit_probe_rect_rgb(coord_from_index(col
),
352 coord_from_index(row
),
356 printf(" Failure with %d vec4 varyings"
357 " captured and offset %d\n",
370 GLint max_components
;
371 int max_xfb_varyings
;
372 GLint max_xfb_components
;
375 static enum piglit_result
376 test_1d_array(void * data
) {
377 struct common_data
* test_data
= (struct common_data
*)data
;
379 GLuint vs
= get_vs(test_data
->max_varyings
);
380 GLuint fs
= get_fs(test_data
->max_varyings
);
381 bool pass
= run_subtest(
383 test_data
->max_xfb_varyings
,
384 test_data
->max_varyings
,
387 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
390 static enum piglit_result
391 test_aoa(void * data
) {
392 if (!piglit_is_extension_supported("GL_ARB_arrays_of_arrays")) {
396 struct common_data
* test_data
= (struct common_data
*)data
;
398 GLuint vs
= get_vs_aoa(test_data
->max_varyings
);
399 GLuint fs
= get_fs_aoa(test_data
->max_varyings
);
400 bool pass
= run_subtest(
403 test_data
->max_xfb_varyings
,
404 test_data
->max_varyings
, xfb_varying_aoa
);
406 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
409 static struct piglit_subtest tests
[] = {
411 "max-varying-single-dimension-array",
417 "max-varying-arrays-of-arrays",
425 /* 10x10 rectangles with 2 pixels of pad. Deal with up to 32 varyings. */
427 PIGLIT_GL_TEST_CONFIG_BEGIN
429 piglit_config
= &config
;
430 config
.subtests
= tests
;
431 config
.supports_gl_compat_version
= 20;
433 config
.window_width
= (2+MAX_VARYING
*12);
434 config
.window_height
= (2+MAX_VARYING
*12);
435 config
.window_visual
= PIGLIT_GL_VISUAL_RGB
| PIGLIT_GL_VISUAL_DOUBLE
;
436 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
438 PIGLIT_GL_TEST_CONFIG_END
443 struct common_data data
= { 0, 0, 0, 0 };
444 enum piglit_result status
= PIGLIT_PASS
;
446 piglit_ortho_projection(piglit_width
, piglit_height
, GL_FALSE
);
448 glGetIntegerv(GL_MAX_VARYING_FLOATS
, &data
.max_components
);
449 data
.max_varyings
= data
.max_components
/ 4;
450 init_xfb_varyings(data
.max_varyings
);
452 printf("GL_MAX_VARYING_FLOATS = %i\n", data
.max_components
);
454 if (data
.max_varyings
> MAX_VARYING
) {
455 printf("test not designed to handle >%d varying vec4s.\n"
456 "(implementation reports %d components)\n",
457 data
.max_components
, MAX_VARYING
);
458 data
.max_varyings
= MAX_VARYING
;
459 status
= PIGLIT_WARN
;
462 glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS
,
463 &data
.max_xfb_components
);
464 data
.max_xfb_varyings
= MIN2(data
.max_xfb_components
/ 4, data
.max_varyings
);
466 printf("GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = %i\n",
467 data
.max_xfb_components
);
469 for (unsigned i
= 0; i
< ARRAY_SIZE(tests
); ++i
) {
470 tests
[i
].data
= (void *)&data
;
473 status
= piglit_run_selected_subtests(
475 piglit_config
->selected_subtests
,
476 piglit_config
->num_selected_subtests
,
482 void piglit_init(int argc
, char **argv
)
484 piglit_require_GLSL_version(120);
485 piglit_require_transform_feedback();
486 glGenBuffers(1, &xfb_buf
);
488 printf("Vertical axis: Increasing numbers of varyings captured by "
489 "transform feedback.\n");
490 printf("Horizontal axis: Offset of first varying captured.\n");