glsl-array-bounds: set out-of-bounds array index inside shader
[piglit.git] / tests / shaders / glsl-uniform-interstage-limits.c
blobde57ca5800420f71f874e614fb6769d4d8bef00f
1 /*
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
13 * Software.
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.
24 /** @file glsl-uniform-interstage-limits.c
26 * Tests that arrays of vec4 uniforms are fully correct in both the VS and the
27 * FS.
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
33 * hangs.
36 #include <getopt.h>
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
50 static GLuint prog;
52 static int statechanges;
53 static int subdivide;
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.
62 static void
63 fill_uniform_arrays(int delta, int vs_array_size, int fs_array_size)
65 GLuint unifvs = glGetUniformLocation(prog, "vsu");
66 assert(unifvs != -1);
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");
71 assert(uniffs != -1);
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
79 * its uniforms.
81 static void
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"
89 "void main()\n"
90 "{\n"
91 " result = 0.75;\n"
92 " for (int i = 0; i < vslen; i++) {\n"
93 " if (vsu[i] - delta != vec4(i, i + 1, i + 2, i + 3))\n"
94 " result = 0.25;\n"
95 " }\n"
96 " gl_Position = gl_Vertex;\n"
97 "}\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"
104 "void main()\n"
105 "{\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"
110 " }\n"
111 "}\n";
113 piglit_require_gl_version(20);
115 GLuint vs = piglit_compile_shader_formatted(GL_VERTEX_SHADER, vs_source,
116 vs_array_size);
117 GLuint fs = piglit_compile_shader_formatted(GL_FRAGMENT_SHADER, fs_source,
118 fs_array_size);
119 prog = piglit_link_simple_program(vs, fs);
120 glUseProgram(prog);
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
128 * the results.
130 static bool
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++) {
145 int xi = i % 8;
146 int yi = i / 8;
148 if (statechanges)
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,
153 2.0 / 8,
154 2.0 / 8);
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,
160 expected);
162 glDeleteProgram(prog);
164 return pass;
167 /* Returns an array of array sizes to test in a stage, terminated by a 0. */
168 static int *
169 pick_sizes(int arg, int max)
171 int count = ((!arg && subdivide) ? subdivide : 1) + 1;
173 int *sizes = calloc(count, sizeof(int));
174 if (arg) {
175 sizes[0] = arg;
176 } else if (!subdivide) {
177 sizes[0] = max;
178 } else {
179 sizes[0] = 1;
181 for (int i = 1; i < subdivide; i++) {
182 /* Be careful about overflow if the driver exposes a
183 * large max count.
185 sizes[i] = (uint64_t)i * max / (subdivide - 1);
189 return sizes;
192 /* Iterates over the sizes to test, returns the overall result. */
193 enum piglit_result
194 piglit_display(void)
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);
209 free(vs_sizes);
210 free(fs_sizes);
212 piglit_present_results();
214 return result;
217 void
218 piglit_init(int argc, char **argv)
220 while (1) {
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 },
226 {0, 0, 0, 0 }
229 int c = getopt_long(argc, argv, "v:f:", long_options, NULL);
230 if (c == -1)
231 break;
233 switch (c) {
234 case 0:
235 /* long opt with value */
236 break;
237 case 'v':
238 vs_arg = (int)strtol(optarg, NULL, 10);
239 break;
240 case 'f':
241 fs_arg = (int)strtol(optarg, NULL, 10);
242 break;
243 case 's':
244 subdivide = (int)strtol(optarg, NULL, 10);
245 break;
246 default:
247 fprintf(stderr, "usage: glsl-uniform-count "
248 "[--vs vec4_count] "
249 "[--fs vec4_count] "
250 "[--subdivide divisions] "
251 "[--statechanges]\n");
252 exit(1);
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);