glsl: test loop unroll with uint overflow
[piglit.git] / tests / spec / arb_shader_image_load_store / grid.c
blob9e7e2c17f2b8adc08f7477bf2da471e9384a03ed
1 /*
2 * Copyright (C) 2014 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
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 grid.c
26 * Utility code for running a grid of shader invocations abstracting
27 * out the details of the specific shader stage it's run on.
30 #include "common.h"
32 char *
33 concat(char *hunk0, ...)
35 char *s = hunk0;
36 char *hunk;
37 va_list ap;
39 va_start(ap, hunk0);
41 while ((hunk = va_arg(ap, char *))) {
42 char *t = s;
43 (void)!asprintf(&s, "%s\n%s", t, hunk);
44 free(t);
45 free(hunk);
48 va_end(ap);
49 return s;
52 char *
53 image_hunk(const struct image_info img, const char *prefix)
55 char *s = NULL;
57 (void)!asprintf(&s,
58 "#define %sBASE_T %s\n"
59 "#define %sDATA_T %s\n"
60 "#define %sSCALE vec4(%.8e, %.8e, %.8e, %.8e)\n"
61 "#define %sIMAGE_ADDR_(addr_t, ext, i) %s\n"
62 "#define %sIMAGE_ADDR(idx)"
63 " %sIMAGE_ADDR_(%s, ivec4(%d, %d, %d, %d),"
64 " ((idx).x + W * (idx).y))\n"
65 "#define %sIMAGE_LAYOUT_Q layout(%s)\n"
66 "#define %sIMAGE_BARE_T %s%s\n"
67 "#define %sIMAGE_UNIFORM_T %sIMAGE_LAYOUT_Q uniform %sIMAGE_BARE_T\n",
68 prefix, image_scalar_type_name(img.format),
69 prefix, image_vector_type_name(img.format),
70 prefix, image_format_scale(img.format).x,
71 image_format_scale(img.format).y,
72 image_format_scale(img.format).z,
73 image_format_scale(img.format).w,
74 prefix, (image_target_samples(img.target) > 1 ?
75 "addr_t(ivec3(i / ext.x % ext.y,"
76 " i / ext.x / ext.y % ext.z,"
77 " i / ext.x / ext.y / ext.z)),"
78 "(i % ext.x)" :
79 "addr_t(ivec3(i % ext.x,"
80 " i / ext.x % ext.y,"
81 " i / ext.x / ext.y))"),
82 prefix, prefix, img.target->addr_type_name,
83 img.size.x, img.size.y, img.size.z, img.size.w,
84 prefix, img.format->name,
85 prefix, image_type_name(img.format), img.target->name,
86 prefix, prefix, prefix);
87 return s;
90 static char *
91 header_hunk(const struct grid_info grid)
93 char *s = NULL;
95 (void)!asprintf(&s, "#version 150\n"
96 "#extension GL_ARB_shader_image_load_store : enable\n"
97 "#define W %d\n"
98 "#define H %d\n"
99 "#define N %d\n"
100 "#define GRID_T %s\n"
101 "#define RET_IMAGE_UNIFORM_T layout(%s) uniform %s2D\n",
102 grid.size.x, grid.size.y, product(grid.size),
103 image_vector_type_name(grid.format),
104 grid.format->name, image_type_name(grid.format));
105 return s;
108 static char *
109 generate_stage_source(const struct grid_info grid,
110 unsigned stage, const char *_body)
112 char *header = header_hunk(grid);
113 char *body = hunk(_body ? _body :
114 "GRID_T op(ivec2 idx, GRID_T x) {\n"
115 " return x;\n"
116 "}\n");
118 switch (stage) {
119 case GL_VERTEX_SHADER:
120 return concat(
121 header, body,
122 hunk("in vec4 piglit_vertex;\n"
123 "out ivec2 vidx;\n"
124 "flat out GRID_T vcolor;\n"
125 "\n"
126 "void main() {\n"
127 " ivec2 idx = ivec2((piglit_vertex + 1.0).xy *"
128 " vec2(W, H) / 2);\n"
129 "\n"
130 " vcolor = op(idx, GRID_T(0));\n"
131 " vidx = idx;\n"
132 " gl_Position = piglit_vertex;\n"
133 "}\n"), NULL);
135 case GL_TESS_CONTROL_SHADER:
136 return concat(
137 header,
138 hunk("#extension GL_ARB_tessellation_shader : enable\n"),
139 body,
140 hunk("layout(vertices=4) out;\n"
141 "\n"
142 "in ivec2 vidx[];\n"
143 "flat in GRID_T vcolor[];\n"
144 "out ivec2 tcidx[];\n"
145 "out GRID_T tccolor[];\n"
146 "\n"
147 "void main() {\n"
148 " if (gl_InvocationID == 0) {\n"
149 " /* No subdivisions, thanks. */\n"
150 " gl_TessLevelInner[0] = 1;\n"
151 " gl_TessLevelInner[1] = 1;\n"
152 " gl_TessLevelOuter[0] = 1;\n"
153 " gl_TessLevelOuter[1] = 1;\n"
154 " gl_TessLevelOuter[2] = 1;\n"
155 " gl_TessLevelOuter[3] = 1;\n"
156 " }\n"
157 " tccolor[gl_InvocationID] ="
158 " op(vidx[gl_InvocationID],"
159 " vcolor[gl_InvocationID]);\n"
160 " tcidx[gl_InvocationID] = vidx[gl_InvocationID];\n"
161 " gl_out[gl_InvocationID].gl_Position ="
162 " gl_in[gl_InvocationID].gl_Position;\n"
163 "}\n"), NULL);
165 case GL_TESS_EVALUATION_SHADER:
166 return concat(
167 header,
168 hunk("#extension GL_ARB_tessellation_shader : enable\n"),
169 body,
170 hunk("layout(quads, point_mode) in;\n"
171 "\n"
172 "in ivec2 tcidx[];\n"
173 "in GRID_T tccolor[];\n"
174 "out ivec2 teidx;\n"
175 "flat out GRID_T tecolor;\n"
176 "\n"
177 "void main() {\n"
178 " int idx = ((gl_TessCoord.x > 0.5 ? 1 : 0) +"
179 " (gl_TessCoord.y > 0.5 ? 2 : 0));\n"
180 "\n"
181 " tecolor = op(tcidx[idx], tccolor[idx]);\n"
182 " teidx = tcidx[idx];\n"
183 " gl_Position = gl_in[idx].gl_Position;\n"
184 "}\n"), NULL);
186 case GL_GEOMETRY_SHADER:
187 return concat(
188 header,
189 hunk(grid.stages & (GL_TESS_CONTROL_SHADER_BIT |
190 GL_TESS_EVALUATION_SHADER_BIT) ?
191 "#define IN(name) te##name\n" :
192 "#define IN(name) v##name\n"),
193 body,
194 hunk("layout(points) in;\n"
195 "layout(points, max_vertices=1) out;\n"
196 "\n"
197 "in ivec2 IN(idx)[];\n"
198 "flat in GRID_T IN(color)[];\n"
199 "flat out GRID_T gcolor;\n"
200 "\n"
201 "void main() {\n"
202 " gcolor = op(IN(idx)[0], IN(color)[0]);\n"
203 " gl_Position = gl_in[0].gl_Position;\n"
204 " EmitVertex();\n"
205 "}\n"), NULL);
207 case GL_FRAGMENT_SHADER:
208 return concat(
209 header,
210 hunk(grid.stages & (GL_TESS_CONTROL_SHADER_BIT |
211 GL_TESS_EVALUATION_SHADER_BIT |
212 GL_GEOMETRY_SHADER_BIT) ?
213 "#define IN(name) g##name\n" :
214 "#define IN(name) v##name\n"),
215 body,
216 hunk("flat in GRID_T IN(color);\n"
217 "out GRID_T fcolor;\n"
218 "\n"
219 "void main() {\n"
220 " fcolor = op(ivec2(gl_FragCoord), IN(color));\n"
221 "}\n"), NULL);
223 case GL_COMPUTE_SHADER:
224 return concat(
225 header,
226 hunk("#extension GL_ARB_compute_shader : enable\n"),
227 body,
228 hunk("layout (local_size_x = W) in;\n"
229 "\n"
230 "RET_IMAGE_UNIFORM_T ret_img;\n"
231 "\n"
232 "void main() {\n"
233 " ivec2 idx = ivec2(gl_GlobalInvocationID);\n"
234 " GRID_T x = op(idx, GRID_T(0));\n"
235 " imageStore(ret_img, idx, x);\n"
236 "}\n"), NULL);
238 default:
239 abort();
243 static inline unsigned
244 get_stage_idx(const struct image_stage_info *stage)
246 return ffs(stage->bit) - 1;
250 * Generate a full program pipeline using the shader code provided in
251 * the \a sources array.
253 static GLuint
254 generate_program_v(const struct grid_info grid, const char **sources)
256 const unsigned basic_stages = (GL_FRAGMENT_SHADER_BIT |
257 GL_VERTEX_SHADER_BIT);
258 const unsigned tess_stages = (GL_TESS_CONTROL_SHADER_BIT |
259 GL_TESS_EVALUATION_SHADER_BIT);
260 const unsigned graphic_stages = (basic_stages | tess_stages |
261 GL_GEOMETRY_SHADER_BIT);
262 const unsigned stages =
263 (grid.stages |
264 /* Make a full pipeline if a tessellation shader was
265 * requested. */
266 (grid.stages & tess_stages ? graphic_stages : 0) |
267 /* Make sure there is always a vertex and fragment
268 * shader if we're doing graphics. */
269 (grid.stages & graphic_stages ? basic_stages : 0));
270 GLuint prog = glCreateProgram();
271 const struct image_stage_info *stage;
273 for (stage = known_image_stages(); stage->stage; ++stage) {
274 if (stages & stage->bit) {
275 char *source = generate_stage_source(
276 grid, stage->stage,
277 sources[get_stage_idx(stage)]);
278 GLuint shader = piglit_compile_shader_text_nothrow(
279 stage->stage, source, true);
281 free(source);
283 if (!shader) {
284 glDeleteProgram(prog);
285 return 0;
288 glAttachShader(prog, shader);
289 glDeleteShader(shader);
293 glBindAttribLocation(prog, PIGLIT_ATTRIB_POS, "piglit_vertex");
294 glBindAttribLocation(prog, PIGLIT_ATTRIB_TEX, "piglit_texcoord");
295 glLinkProgram(prog);
297 if (!piglit_link_check_status(prog)) {
298 glDeleteProgram(prog);
299 return 0;
302 return prog;
305 GLuint
306 generate_program(const struct grid_info grid, ...)
308 char *sources[6] = { NULL };
309 va_list ap;
310 unsigned stages, i;
311 GLuint prog;
313 va_start(ap, grid);
315 for (stages = grid.stages; stages;) {
316 const struct image_stage_info *stage =
317 get_image_stage(va_arg(ap, GLenum));
318 char *source = va_arg(ap, char *);
320 if (stage) {
321 assert(get_stage_idx(stage) < ARRAY_SIZE(sources));
322 sources[get_stage_idx(stage)] = source;
323 stages &= ~stage->bit;
327 va_end(ap);
329 prog = generate_program_v(grid, (const char **)sources);
331 for (i = 0; i < ARRAY_SIZE(sources); ++i)
332 free(sources[i]);
334 return prog;
337 bool
338 draw_grid(const struct grid_info grid, GLuint prog)
340 static GLuint lprog;
342 if (lprog != prog) {
343 glUseProgram(prog);
344 lprog = prog;
347 if (grid.stages & GL_COMPUTE_SHADER_BIT) {
348 set_uniform_int(prog, "ret_img", max_image_units());
349 glDispatchCompute(1, grid.size.y, 1);
351 } else if (grid.stages & (GL_TESS_CONTROL_SHADER_BIT |
352 GL_TESS_EVALUATION_SHADER_BIT)) {
353 static struct image_extent size;
354 static GLuint vao, vbo;
356 if (size.x != grid.size.x || size.y != grid.size.y) {
357 size = grid.size;
359 if (!generate_grid_arrays(
360 &vao, &vbo,
361 1.0 / size.x - 1.0, 1.0 / size.y - 1.0,
362 2.0 / size.x, 2.0 / size.y,
363 size.x, size.y))
364 return false;
367 glBindVertexArray(vao);
368 glPatchParameteri(GL_PATCH_VERTICES, 4);
369 glDrawArrays(GL_PATCHES, 0, product(size));
371 } else if (grid.stages & (GL_VERTEX_SHADER_BIT |
372 GL_GEOMETRY_SHADER_BIT)) {
373 static struct image_extent size;
374 static GLuint vao, vbo;
376 if (size.x != grid.size.x || size.y != grid.size.y) {
377 size = grid.size;
379 if (!generate_grid_arrays(
380 &vao, &vbo,
381 1.0 / size.x - 1.0, 1.0 / size.y - 1.0,
382 2.0 / size.x, 2.0 / size.y,
383 size.x, size.y))
384 return false;
387 glBindVertexArray(vao);
388 glDrawArrays(GL_POINTS, 0, product(size));
390 } else {
391 static struct image_extent size;
392 static GLuint vao, vbo;
394 if (size.x != grid.size.x || size.y != grid.size.y) {
395 int vp[4];
397 glGetIntegerv(GL_VIEWPORT, vp);
398 size = grid.size;
400 if (!generate_grid_arrays(
401 &vao, &vbo, -1.0, -1.0,
402 2.0 * size.x / vp[2], 2.0 * size.y / vp[3],
403 2, 2))
404 return false;
408 glBindVertexArray(vao);
409 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
412 return piglit_check_gl_error(GL_NO_ERROR);
415 bool
416 generate_grid_arrays(GLuint *vao, GLuint *vbo,
417 float x, float y, float dx, float dy,
418 unsigned nx, unsigned ny)
420 float (*verts)[4] = malloc(sizeof(*verts) * nx * ny);
421 int i, j;
423 for (i = 0; i < nx; ++i) {
424 for (j = 0; j < ny; ++j) {
425 const unsigned k = (nx * (j & ~1) + 2 * (i & ~1) +
426 (i & 1) + 2 * (j & 1));
427 verts[k][0] = x + i * dx;
428 verts[k][1] = y + j * dy;
429 verts[k][2] = 0.0;
430 verts[k][3] = 1.0;
434 if (!*vao) {
435 glGenVertexArrays(1, vao);
436 glGenBuffers(1, vbo);
439 glBindVertexArray(*vao);
440 glBindBuffer(GL_ARRAY_BUFFER, *vbo);
441 glBufferData(GL_ARRAY_BUFFER, sizeof(*verts) * nx * ny,
442 verts, GL_STATIC_DRAW);
444 glVertexAttribPointer(PIGLIT_ATTRIB_POS, 4, GL_FLOAT,
445 GL_FALSE, 0, 0);
446 glEnableVertexAttribArray(PIGLIT_ATTRIB_POS);
448 free(verts);
449 return piglit_check_gl_error(GL_NO_ERROR);