glsl: test loop unroll with uint overflow
[piglit.git] / tests / spec / arb_compute_shader / cs-ids-common.c
blobc07705b8a221ce63ef56c8723d49b46445fb216f
1 /*
2 * Copyright (c) 2014 - 2015 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
21 * DEALINGS IN THE SOFTWARE.
24 #include "piglit-util-gl.h"
25 #include "piglit-shader.h"
26 #include "common.h"
28 #define NUM_ATOMIC_COUNTERS 8
30 static GLuint atomics_bo = 0;
31 static GLuint indirect_bo = 0;
32 static bool verbose = false;
33 static bool indirect_dispatch = false;
34 static bool global_id = false;
35 static GLint prog = 0;
37 static uint32_t global_x = 0, global_y = 0, global_z = 0;
38 static uint32_t local_x = 0, local_y = 0, local_z = 0;
40 static uint32_t sizes[] = {
41 1, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65,
42 127, 128, 129, 255, 256, 257, 511, 512, 513, 1023, 1024
45 static const char *extensions =
46 "#extension GL_ARB_shader_atomic_counters: require\n";
48 static const char *compute_shader_source =
49 "layout(binding = 0) uniform atomic_uint a0;\n"
50 "layout(binding = 0) uniform atomic_uint a1;\n"
51 "layout(binding = 0) uniform atomic_uint a2;\n"
52 "layout(binding = 0) uniform atomic_uint a3;\n"
53 "layout(binding = 0) uniform atomic_uint a4;\n"
54 "layout(binding = 0) uniform atomic_uint a5;\n"
55 "layout(binding = 0) uniform atomic_uint a6;\n"
56 "layout(binding = 0) uniform atomic_uint a7;\n"
57 "\n"
58 "#ifdef GLOBAL_ID_TEST\n"
59 "#define ID_VAR gl_GlobalInvocationID\n"
60 "#define ID_DIM(a) (gl_NumWorkGroups.a * gl_WorkGroupSize.a)\n"
61 "#else\n"
62 "#define ID_VAR gl_LocalInvocationID\n"
63 "#define ID_DIM(a) (gl_WorkGroupSize.a)\n"
64 "#endif\n"
65 "\n"
66 "void main()\n"
67 "{\n"
68 " uint x = ID_VAR.x;\n"
69 " uint y = ID_VAR.y;\n"
70 " uint z = ID_VAR.z;\n"
71 " uint hx = ID_DIM(x) / 2u;\n"
72 " uint hy = ID_DIM(y) / 2u;\n"
73 " uint hz = ID_DIM(z) / 2u;\n"
74 "\n"
75 " if (((x & y) & z) == 0u)\n"
76 " atomicCounterIncrement(a0);\n"
77 " if (((x | y) | z) == 7u)\n"
78 " atomicCounterIncrement(a1);\n"
79 " if (x == y && y == z)\n"
80 " atomicCounterIncrement(a2);\n"
81 " if (x != y && y != z && x != z)\n"
82 " atomicCounterIncrement(a3);\n"
83 " if (((x & y) & z) == 2u)\n"
84 " atomicCounterIncrement(a4);\n"
85 " if (((x | y) | z) == 5u)\n"
86 " atomicCounterIncrement(a5);\n"
87 " if (x < hx && y < hy && z < hz)\n"
88 " atomicCounterIncrement(a6);\n"
89 " if (x >= hx || y >= hy || z >= hz)\n"
90 " atomicCounterIncrement(a7);\n"
91 "}\n";
94 static void
95 clear_program()
97 if (prog != 0) {
98 local_x = 0;
99 local_y = 0;
100 local_z = 0;
101 glDeleteProgram(prog);
102 prog = 0;
106 static enum piglit_result
107 compare_atomic_counters(uint32_t *values, uint32_t xs, uint32_t ys,
108 uint32_t zs)
110 bool pass = true;
111 uint32_t *p;
113 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomics_bo);
114 p = glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER,
116 NUM_ATOMIC_COUNTERS * sizeof(uint32_t),
117 GL_MAP_READ_BIT);
119 if (!p) {
120 printf("Couldn't map atomic counter to verify expected value.\n");
121 return PIGLIT_FAIL;
124 for (unsigned i = 0; i < NUM_ATOMIC_COUNTERS; i++) {
125 uint32_t found = p[i];
126 if (verbose)
127 printf("Atomic counter %d\n"
128 " Reference: %u\n"
129 " Observed: %u\n"
130 " Result: %s\n",
131 i, values[i], found,
132 values[i] == found ? "pass" : "fail");
133 if (values[i] != found) {
134 printf("Atomic counter test %d failed for (%d, %d, %d)\n",
135 i, xs, ys, zs);
136 printf(" Reference: %u\n", values[i]);
137 printf(" Observed: %u\n", found);
138 pass = false;
139 break;
143 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
145 return pass ? PIGLIT_PASS : PIGLIT_FAIL;
148 enum piglit_result
149 cs_ids_confirm_initial_atomic_counters()
151 uint32_t atomics_init[NUM_ATOMIC_COUNTERS] = { 0 };
152 return compare_atomic_counters(atomics_init, 0, 0, 0);
155 enum piglit_result
156 cs_ids_confirm_size()
158 uint32_t values[NUM_ATOMIC_COUNTERS];
159 uint32_t i, x, y, z;
160 uint32_t xs, ys, zs;
161 uint32_t hx, hy, hz;
163 xs = local_x;
164 ys = local_y;
165 zs = local_z;
167 if (global_id) {
168 xs *= global_x;
169 ys *= global_y;
170 zs *= global_z;
173 hx = xs / 2u;
174 hy = ys / 2u;
175 hz = zs / 2u;
177 memset(&values, 0, sizeof values);
179 const bool no_work = global_x == 0 || global_y == 0 || global_z == 0;
180 for (z = 0; z < zs && !no_work; z++) {
181 for (y = 0; y < ys; y++) {
182 for (x = 0; x < xs; x++) {
183 if (((x & y) & z) == 0u)
184 values[0]++;
185 if (((x | y) | z) == 7u)
186 values[1]++;
187 if (x == y && y == z)
188 values[2]++;
189 if (x != y && y != z && x != z)
190 values[3]++;
191 if (((x & y) & z) == 2u)
192 values[4]++;
193 if (((x | y) | z) == 5u)
194 values[5]++;
195 if (x < hx && y < hy && z < hz)
196 values[6]++;
197 if (x >= hx || y >= hy || z >= hz)
198 values[7]++;
203 if (!global_id) {
204 for (i = 0; i < NUM_ATOMIC_COUNTERS; i++)
205 values[i] *= global_x * global_y * global_z;
208 return compare_atomic_counters(values, xs, ys, zs);
212 static enum piglit_result
213 build_program_for_size(uint32_t x, uint32_t y, uint32_t z)
215 char *src;
217 if (local_x == x && local_y == y &&
218 local_z == z && prog != 0) {
219 return PIGLIT_PASS;
222 clear_program();
224 if (global_id) {
225 src = concat(hunk("#define GLOBAL_ID_TEST\n"),
226 hunk(compute_shader_source),
227 NULL);
228 } else {
229 src = hunk(compute_shader_source);
232 prog = generate_cs_prog(x, y, z, hunk(extensions), src);
234 if (!prog)
235 return PIGLIT_FAIL;
237 local_x = x;
238 local_y = y;
239 local_z = z;
241 return PIGLIT_PASS;
245 enum piglit_result
246 cs_ids_set_local_size(uint32_t x, uint32_t y, uint32_t z)
248 enum piglit_result result = PIGLIT_PASS;
250 if (x == 0 || y == 0 || z == 0) {
251 clear_program();
252 return PIGLIT_FAIL;
255 result = build_program_for_size(x, y, z);
256 if (result != PIGLIT_PASS)
257 piglit_report_result(result);
259 return result;
263 enum piglit_result
264 cs_ids_set_global_size(uint32_t x, uint32_t y, uint32_t z)
266 GLuint indirect_buf[3] = { x, y, z };
268 global_x = x;
269 global_y = y;
270 global_z = z;
272 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, indirect_bo);
273 glBufferData(GL_DISPATCH_INDIRECT_BUFFER,
274 sizeof(indirect_buf),
275 indirect_buf, GL_STREAM_READ);
277 return PIGLIT_PASS;
281 void
282 cs_ids_setup_atomics_for_test()
284 uint32_t atomics_init[NUM_ATOMIC_COUNTERS] = { 0 };
286 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomics_bo);
287 glBufferData(GL_ATOMIC_COUNTER_BUFFER,
288 sizeof(atomics_init),
289 atomics_init, GL_STATIC_DRAW);
293 /* Running the test without checking the result is useful for creating display
294 * list tests.
296 void
297 cs_ids_run_test_without_check()
299 if (verbose)
300 printf("Testing local dim = %dx%dx%d; "
301 "global dim = %dx%dx%d\n",
302 local_x, local_y, local_z,
303 global_x, global_y, global_z);
305 if (local_x == 0 || local_y == 0 || local_z == 0) {
306 fprintf(stderr, "Internal error: local size not set\n");
307 return;
310 glUseProgram(prog);
312 glMemoryBarrier(GL_ALL_BARRIER_BITS);
313 if (indirect_dispatch) {
314 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, indirect_bo);
315 glDispatchComputeIndirect(0);
316 } else {
317 glDispatchCompute(global_x, global_y, global_z);
319 glMemoryBarrier(GL_ALL_BARRIER_BITS);
323 enum piglit_result
324 cs_ids_run_test()
326 enum piglit_result result;
328 cs_ids_setup_atomics_for_test();
329 cs_ids_run_test_without_check();
331 result = cs_ids_confirm_size();
332 if (result != PIGLIT_PASS)
333 piglit_report_result(result);
335 return result;
339 static enum piglit_result
340 test_size(uint32_t x, uint32_t y, uint32_t z)
342 enum piglit_result result;
344 result = cs_ids_set_local_size(x, y, z);
345 if (result != PIGLIT_PASS)
346 piglit_report_result(result);
348 result = cs_ids_run_test();
349 if (result != PIGLIT_PASS)
350 piglit_report_result(result);
352 return result;
356 enum piglit_result
357 cs_ids_test_all_sizes()
359 enum piglit_result result = PIGLIT_PASS;
360 uint32_t xi, yi, zi;
361 uint32_t x, y, z;
364 for (zi = 0; zi < ARRAY_SIZE(sizes); zi++) {
365 z = sizes[zi];
366 if (z > 64)
367 break;
368 for (yi = 0; yi < ARRAY_SIZE(sizes); yi++) {
369 y = sizes[yi];
370 if ((y * z) > 1024)
371 break;
372 for (xi = 0; xi < ARRAY_SIZE(sizes); xi++) {
373 x = sizes[xi];
374 if ((x * y * z) > 1024)
375 break;
376 result = test_size(x, y, z);
377 if (result != PIGLIT_PASS)
378 return result;
383 return result;
386 void
387 cs_ids_common_init(void)
389 piglit_require_extension("GL_ARB_compute_shader");
390 piglit_require_extension("GL_ARB_shader_atomic_counters");
392 glGenBuffers(1, &atomics_bo);
393 if (!piglit_check_gl_error(GL_NO_ERROR))
394 piglit_report_result(PIGLIT_FAIL);
396 glGenBuffers(1, &indirect_bo);
397 if (!piglit_check_gl_error(GL_NO_ERROR))
398 piglit_report_result(PIGLIT_FAIL);
399 cs_ids_set_global_size(1, 1, 1);
404 void
405 cs_ids_common_destroy(void)
407 if (atomics_bo != 0)
408 glDeleteBuffers(1, &atomics_bo);
409 if (indirect_bo != 0)
410 glDeleteBuffers(1, &indirect_bo);
414 void
415 cs_ids_set_local_id_test(void)
417 if (global_id) {
418 uint32_t x = local_x, y = local_y, z = local_z;
419 clear_program();
420 global_id = false;
421 cs_ids_set_local_size(x, y, z);
426 void
427 cs_ids_set_global_id_test(void)
429 if (!global_id) {
430 uint32_t x = local_x, y = local_y, z = local_z;
431 clear_program();
432 global_id = true;
433 cs_ids_set_local_size(x, y, z);
438 void
439 cs_ids_use_indirect_dispatch(void)
441 indirect_dispatch = true;
445 void
446 cs_ids_use_direct_dispatch(void)
448 indirect_dispatch = false;
451 void
452 cs_ids_verbose(void)
454 verbose = true;