2 * Copyright © 2020 Google LLC
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-uniform-interstage-limits.c
26 * Tests that arrays of vec4 uniforms are fully correct in both the VS and the
29 * On adreno HW, the const file (which we move uniforms to if we can) is
30 * shared between the stages, and you need to allocate between them. Failure
31 * to limit your stages by just a little bit seems to lead to corruption as
32 * one shader writes over another's memory, while larger failure leads to GPU
37 #include "piglit-util-gl.h"
39 PIGLIT_GL_TEST_CONFIG_BEGIN
41 config
.supports_gl_compat_version
= 10;
43 config
.window_visual
= PIGLIT_GL_VISUAL_RGBA
| PIGLIT_GL_VISUAL_DOUBLE
;
44 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
45 config
.window_width
= 64;
46 config
.window_height
= 64;
48 PIGLIT_GL_TEST_CONFIG_END
52 static int statechanges
;
54 static int vs_arg
, fs_arg
;
55 static int max_vs_vec4
, max_fs_vec4
;
57 /* Sets up the uniform arrays in the program for the given array sizes. The
58 * contents vary slightly between the stages to make sure you don't mix those
59 * up, and the "delta" argument is used in the statechanges case to make sure
60 * you don't use a stale uniform buffer's contents.
63 fill_uniform_arrays(int delta
, int vs_array_size
, int fs_array_size
)
65 GLuint unifvs
= glGetUniformLocation(prog
, "vsu");
67 for (int i
= delta
; i
< delta
+ vs_array_size
; i
++)
68 glUniform4f(unifvs
+ i
- delta
, i
, i
+ 1, i
+ 2, i
+ 3);
70 GLuint uniffs
= glGetUniformLocation(prog
, "fsu");
72 for (int i
= delta
; i
< delta
+ fs_array_size
; i
++)
73 glUniform4f(uniffs
+ i
- delta
, i
, i
+ 1, i
+ 2, i
+ 4);
75 glUniform1f(glGetUniformLocation(prog
, "delta"), delta
);
78 /* Creates the shader program for the given array sizes and initially fills
82 setup_program(int vs_array_size
, int fs_array_size
)
84 const char *vs_source
=
85 "uniform vec4 vsu[%d];\n"
86 "uniform int vslen;\n"
87 "uniform float delta;\n"
88 "varying float result;\n"
92 " for (int i = 0; i < vslen; i++) {\n"
93 " if (vsu[i] - delta != vec4(i, i + 1, i + 2, i + 3))\n"
96 " gl_Position = gl_Vertex;\n"
99 const char *fs_source
=
100 "uniform vec4 fsu[%d];\n"
101 "uniform int fslen;\n"
102 "uniform float delta;\n"
103 "varying float result;\n"
106 " gl_FragColor = vec4(0.0, result, 0.75, 0.0);\n"
107 " for (int i = 0; i < fslen; i++) {\n"
108 " if (fsu[i] - delta != vec4(i, i + 1, i + 2, i + 4))\n"
109 " gl_FragColor.z = 0.25;\n"
113 piglit_require_gl_version(20);
115 GLuint vs
= piglit_compile_shader_formatted(GL_VERTEX_SHADER
, vs_source
,
117 GLuint fs
= piglit_compile_shader_formatted(GL_FRAGMENT_SHADER
, fs_source
,
119 prog
= piglit_link_simple_program(vs
, fs
);
122 glUniform1i(glGetUniformLocation(prog
, "vslen"), vs_array_size
);
123 glUniform1i(glGetUniformLocation(prog
, "fslen"), fs_array_size
);
124 fill_uniform_arrays(0, vs_array_size
, fs_array_size
);
127 /* Generates a program for the given uniform array sizes, draws, and checks
131 test(int vs_array_size
, int fs_array_size
)
133 printf("Testing %d VS vec4, %d fs vec4\n",
134 vs_array_size
, fs_array_size
);
136 setup_program(vs_array_size
, fs_array_size
);
138 glClearColor(0.0, 1.0, 0.0, 0.0);
139 glClear(GL_COLOR_BUFFER_BIT
);
141 /* Emit several draws, so if the FS state overwrites the VS, we
142 * hopefully catch it on the next draw.
144 for (int i
= 0; i
< 256; i
++) {
149 fill_uniform_arrays(i
, vs_array_size
, fs_array_size
);
151 piglit_draw_rect(-1.0 + 2.0 * xi
/ 8.0,
152 -1.0 + 2.0 * yi
/ 8.0,
158 float expected
[4] = {0.0, 0.75, 0.75, 0.0};
159 bool pass
= piglit_probe_rect_rgba(0, 0, piglit_width
, piglit_height
,
162 glDeleteProgram(prog
);
167 /* Returns an array of array sizes to test in a stage, terminated by a 0. */
169 pick_sizes(int arg
, int max
)
171 int count
= ((!arg
&& subdivide
) ? subdivide
: 1) + 1;
173 int *sizes
= calloc(count
, sizeof(int));
176 } else if (!subdivide
) {
181 for (int i
= 1; i
< subdivide
; i
++) {
182 /* Be careful about overflow if the driver exposes a
185 sizes
[i
] = (uint64_t)i
* max
/ (subdivide
- 1);
192 /* Iterates over the sizes to test, returns the overall result. */
196 enum piglit_result result
= PIGLIT_PASS
;
198 int *vs_sizes
= pick_sizes(vs_arg
, max_vs_vec4
);
199 int *fs_sizes
= pick_sizes(fs_arg
, max_fs_vec4
);
201 for (int v
= 0; vs_sizes
[v
] != 0; v
++) {
202 for (int f
= 0; fs_sizes
[f
] != 0; f
++) {
203 piglit_merge_result(&result
,
204 test(vs_sizes
[v
], fs_sizes
[f
]) ?
205 PIGLIT_PASS
: PIGLIT_FAIL
);
212 piglit_present_results();
218 piglit_init(int argc
, char **argv
)
221 static struct option long_options
[] = {
222 {"vs", required_argument
, 0, 'v' },
223 {"fs", required_argument
, 0, 'f' },
224 {"subdivide", required_argument
, 0, 's' },
225 {"statechanges", no_argument
, &statechanges
, 1 },
229 int c
= getopt_long(argc
, argv
, "v:f:", long_options
, NULL
);
235 /* long opt with value */
238 vs_arg
= (int)strtol(optarg
, NULL
, 10);
241 fs_arg
= (int)strtol(optarg
, NULL
, 10);
244 subdivide
= (int)strtol(optarg
, NULL
, 10);
247 fprintf(stderr
, "usage: glsl-uniform-count "
250 "[--subdivide divisions] "
251 "[--statechanges]\n");
256 /* Check against HW limits.
258 GLint max_vs
, max_fs
;
259 glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS
, &max_vs
);
260 glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS
, &max_fs
);
261 /* Note: less than a vec4 worth of other uniforms in each of our
262 * shaders besides the array.
264 max_vs_vec4
= max_vs
/ 4 - 1;
265 max_fs_vec4
= max_fs
/ 4 - 1;
267 if (vs_arg
> max_vs_vec4
) {
268 fprintf(stderr
, "VS vec4 count too large for HW limits "
269 "(%d dwords)\n", max_vs
);
270 piglit_report_result(PIGLIT_SKIP
);
273 if (fs_arg
> max_fs_vec4
) {
274 fprintf(stderr
, "FS vec4 count too large for HW limits "
275 "(%d dwords)\n", max_fs
);
276 piglit_report_result(PIGLIT_SKIP
);