1 /*
2  * Copyright © 2019 Intel Corporation
3  *
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:
10  *
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.
14  *
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.
22  */
23 /*
24  * \file array-ssbo-auto-binding.c
25  *
26  * This test verifies automatically assigned binding points for ssbo array and ssbo arrays of arrays
27  *
28  * \author Andrii Simiklit <asimiklit.work@gmail.com>
29  */
30 
31 #include "piglit-util-gl.h"
32 
33 PIGLIT_GL_TEST_CONFIG_BEGIN
34 
35    config.supports_gl_compat_version = 32;
36    config.supports_gl_core_version = 32;
37    config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGBA;
38    config.khr_no_error_support = PIGLIT_NO_ERRORS;
39 
40 PIGLIT_GL_TEST_CONFIG_END
41 
42 static GLuint prog;
43 
44 struct test_context
45 {
46    bool packed;
47    int max_fs_blocks;
48 };
49 
50 static void
trace_binding_error(int buffer_binding,int expected_binding,const char * shader)51 trace_binding_error(int buffer_binding, int expected_binding, const char *shader)
52 {
53    fprintf(stderr,
54            "error: binding point is %d but expected %d for shader:\n%s\n",
55            buffer_binding,
56            expected_binding,
57            shader);
58 }
59 
60 static const char*
get_layout(bool packed,int binding)61 get_layout(bool packed, int binding)
62 {
63    static char buffer[256];
64    const char *format = packed ?
65           "layout(packed, binding=%d)" :
66           "layout(binding=%d)";
67 
68    snprintf(buffer, sizeof(buffer), format, binding);
69    return buffer;
70 }
71 
72 
73 static const char*
build_1d_shader(bool packed,int binding,int array_size,int used_element,const char ** block_name)74 build_1d_shader(bool packed, int binding,
75                 int array_size, int used_element,
76                 const char **block_name)
77 {
78    static char name[32];
79    static char buffer[1024];
80    const char *format =
81       "#version 150\n"
82       "#extension GL_ARB_arrays_of_arrays : enable\n"
83       "#extension GL_ARB_shading_language_420pack : enable\n"
84       "#extension GL_ARB_shader_storage_buffer_object : require\n"
85       "\n"
86       "%s buffer SSBO { vec4 a; } ssbo[%d];\n"
87       "out vec4 color;\n"
88       "\n"
89       "void main()\n"
90       "{\n"
91       "   color = ssbo[%d].a;\n"
92       "}\n";
93    snprintf(buffer, sizeof(buffer), format,
94             get_layout(packed, binding), array_size, used_element);
95    snprintf(name, sizeof(name), "SSBO[%d]", used_element);
96    *block_name = name;
97    return buffer;
98 }
99 
100 static const char*
build_2d_shader(bool packed,int binding,int * array_dims,int * used_elements,const char ** block_name)101 build_2d_shader(bool packed, int binding,
102                 int *array_dims, int *used_elements,
103                 const char **block_name)
104 {
105    static char name[32];
106    static char buffer[1024];
107    const char *format =
108       "#version 150\n"
109       "#extension GL_ARB_arrays_of_arrays : enable\n"
110       "#extension GL_ARB_shading_language_420pack : enable\n"
111       "#extension GL_ARB_shader_storage_buffer_object : require\n"
112       "\n"
113       "%s buffer SSBO { vec4 a; } ssbo[%d][%d];\n"
114       "out vec4 color;\n"
115       "\n"
116       "void main()\n"
117       "{\n"
118       "   color = ssbo[%d][%d].a;\n"
119       "}\n";
120    snprintf(buffer, sizeof(buffer), format, get_layout(packed, binding),
121             array_dims[0], array_dims[1],
122             used_elements[0], used_elements[1]);
123    snprintf(name, sizeof(name), "SSBO[%d][%d]",
124             used_elements[0], used_elements[1]);
125    *block_name = name;
126    return buffer;
127 }
128 
129 static const char*
build_3d_shader(bool packed,int binding,int * array_dims,int * used_elements,const char ** block_name)130 build_3d_shader(bool packed, int binding,
131                 int *array_dims, int *used_elements,
132                 const char **block_name)
133 {
134    static char name[32];
135    static char buffer[1024];
136    const char *format =
137       "#version 150\n"
138       "#extension GL_ARB_arrays_of_arrays : enable\n"
139       "#extension GL_ARB_shading_language_420pack : enable\n"
140       "#extension GL_ARB_shader_storage_buffer_object : require\n"
141       "\n"
142       "%s buffer SSBO { vec4 a; } ssbo[%d][%d][%d];\n"
143       "out vec4 color;\n"
144       "\n"
145       "void main()\n"
146       "{\n"
147       "   color = ssbo[%d][%d][%d].a;\n"
148       "}\n";
149    snprintf(buffer, sizeof(buffer), format,
150             get_layout(packed, binding),
151             array_dims[0], array_dims[1],array_dims[2],
152             used_elements[0], used_elements[1], used_elements[2]);
153    snprintf(name, sizeof(name), "SSBO[%d][%d][%d]",
154             used_elements[0], used_elements[1], used_elements[2]);
155    *block_name = name;
156    return buffer;
157 }
158 
159 static bool
ssbo_array1d_test(struct test_context * ctx)160 ssbo_array1d_test(struct test_context *ctx)
161 {
162    bool pass = true;
163    for (int array_size = 2;
164         array_size < ctx->max_fs_blocks; array_size++) {
165       for (int used_element = 0;
166            used_element < array_size; used_element++) {
167          int index;
168          const char *blockname;
169          int buffer_binding = 0;
170          GLenum props = GL_BUFFER_BINDING;
171          int expected_binding = 1 + used_element;
172 
173          const char *fs = build_1d_shader(ctx->packed, 1, array_size,
174                                           used_element, &blockname);
175          prog = piglit_build_simple_program(NULL, fs);
176          index = glGetProgramResourceIndex(prog,
177                  GL_SHADER_STORAGE_BLOCK, blockname);
178          glGetProgramResourceiv(prog, GL_SHADER_STORAGE_BLOCK, index, 1,
179                                 &props, 1, NULL, &buffer_binding);
180          if (expected_binding != buffer_binding) {
181             trace_binding_error(buffer_binding, expected_binding, fs);
182             pass = false;
183          }
184       }
185    }
186    return pass;
187 }
188 
189 static bool
ssbo_array2d_test(struct test_context * ctx)190 ssbo_array2d_test(struct test_context *ctx)
191 {
192    bool pass = true;
193    int array_dims[2];
194 
195    for (array_dims[0] = 2;
196         array_dims[0] < (ctx->max_fs_blocks / 2); array_dims[0]++) {
197 
198       int used_elements[2];
199       array_dims[1] = ctx->max_fs_blocks / array_dims[0];
200 
201       for (used_elements[0] = 0;
202            used_elements[0] < array_dims[0]; used_elements[0]++) {
203          for (used_elements[1] = 0;
204               used_elements[1] < array_dims[1]; used_elements[1]++) {
205             int index;
206             const char *blockname;
207             int buffer_binding = 0;
208             GLenum props = GL_BUFFER_BINDING;
209             int expected_binding = 1 +
210                ((used_elements[0] * array_dims[1]) + used_elements[1]);
211 
212             const char *fs = build_2d_shader(ctx->packed, 1, array_dims,
213                                              used_elements, &blockname);
214             prog = piglit_build_simple_program(NULL, fs);
215             index = glGetProgramResourceIndex(prog,
216                     GL_SHADER_STORAGE_BLOCK, blockname);
217             glGetProgramResourceiv(prog, GL_SHADER_STORAGE_BLOCK, index, 1,
218                                    &props, 1, NULL, &buffer_binding);
219             if (expected_binding != buffer_binding) {
220                trace_binding_error(buffer_binding, expected_binding, fs);
221                pass = false;
222             }
223          }
224       }
225    }
226    return pass;
227 }
228 
229 static bool
ssbo_array3d_test(struct test_context * ctx)230 ssbo_array3d_test(struct test_context *ctx)
231 {
232    bool pass = true;
233    int array_dims[3];
234 
235    for(array_dims[0] = 2;
236        array_dims[0] < (ctx->max_fs_blocks / 2); array_dims[0]++) {
237 
238       int used_elements[3];
239       array_dims[1] = (ctx->max_fs_blocks / array_dims[0]) / 2;
240       array_dims[2] = (ctx->max_fs_blocks / (array_dims[1] * array_dims[0]));
241 
242       for(used_elements[0] = 0;
243           used_elements[0] < array_dims[0]; used_elements[0]++) {
244          for(used_elements[1] = 0;
245              used_elements[1] < array_dims[1]; used_elements[1]++) {
246             for(used_elements[2] = 0;
247                 used_elements[2] < array_dims[2]; used_elements[2]++) {
248                int index;
249                const char *blockname;
250                int buffer_binding = 0;
251                GLenum props = GL_BUFFER_BINDING;
252                int expected_binding = 1 +
253                   (used_elements[0] * array_dims[1] * array_dims[2]) +
254                   (used_elements[1] * array_dims[2]) +
255                   used_elements[2];
256 
257                const char *fs = build_3d_shader(ctx->packed, 1, array_dims,
258                                                 used_elements, &blockname);
259                prog = piglit_build_simple_program(NULL, fs);
260                index = glGetProgramResourceIndex(prog,
261                        GL_SHADER_STORAGE_BLOCK, blockname);
262                glGetProgramResourceiv(prog, GL_SHADER_STORAGE_BLOCK, index, 1,
263                                       &props, 1, NULL, &buffer_binding);
264                if (expected_binding != buffer_binding) {
265                   trace_binding_error(buffer_binding, expected_binding, fs);
266                   pass = false;
267                }
268             }
269          }
270       }
271    }
272    return pass;
273 }
274 
275 
276 void
piglit_init(int argc,char ** argv)277 piglit_init(int argc, char **argv)
278 {
279    bool pass = true;
280    struct test_context ctx = {
281       .packed = true
282    };
283 
284    glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &ctx.max_fs_blocks);
285 
286    pass = ssbo_array1d_test(&ctx) && pass;
287    pass = ssbo_array2d_test(&ctx) && pass;
288    pass = ssbo_array3d_test(&ctx) && pass;
289 
290    ctx.packed = false;
291    pass = ssbo_array1d_test(&ctx) && pass;
292    pass = ssbo_array2d_test(&ctx) && pass;
293    pass = ssbo_array3d_test(&ctx) && pass;
294 
295    piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
296 }
297 
piglit_display(void)298 enum piglit_result piglit_display(void)
299 {
300    /* UNREACHED */
301    return PIGLIT_FAIL;
302 }
303