2 * Copyright © 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
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.
26 * From the GL_ARB_shader_storage_buffer_object spec:
28 * "If the number of active shader storage blocks referenced by the shaders in
29 * a program exceeds implementation-dependent limits, the program will fail
30 * to link. The limits for vertex, tessellation control, tessellation
31 * evaluation, geometry, fragment, and compute shaders can be obtained by
32 * calling GetIntegerv with pname values of MAX_VERTEX_SHADER_STORAGE_BLOCKS,
33 * MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,
34 * MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,
35 * MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, MAX_FRAGMENT_SHADER_STORAGE_BLOCKS,
36 * and MAX_COMPUTE_SHADER_STORAGE_BLOCKS, respectively. Additionally, a
37 * program will fail to link if the sum of the number of active shader
38 * storage blocks referenced by each shader stage in a program exceeds the
39 * value of the implementation-dependent limit
40 * MAX_COMBINED_SHADER_STORAGE_BLOCKS. If a shader storage block in a
41 * program is referenced by multiple shaders, each such reference counts
42 * separately against this combined limit.
45 #include "piglit-util-gl.h"
47 PIGLIT_GL_TEST_CONFIG_BEGIN
49 config
.window_width
= 800;
50 config
.window_height
= 200;
51 config
.supports_gl_compat_version
= 32;
52 config
.supports_gl_core_version
= 32;
53 config
.window_visual
= PIGLIT_GL_VISUAL_RGBA
| PIGLIT_GL_VISUAL_DOUBLE
;
54 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
56 PIGLIT_GL_TEST_CONFIG_END
59 get_shader(GLenum target
, const char *block_prefix
, int blocks
)
62 const char *vs_source
=
64 "#extension GL_ARB_shader_storage_buffer_object : enable\n"
65 "#extension GL_ARB_uniform_buffer_object : enable\n"
68 "in vec4 piglit_vertex;\n"
73 " gl_Position = piglit_vertex;\n"
76 const char *fs_source
=
78 "#extension GL_ARB_shader_storage_buffer_object : enable\n"
79 "#extension GL_ARB_uniform_buffer_object : enable\n"
86 " gl_FragColor = v%s;\n"
88 const char *prefix_template
=
89 "layout(std140) buffer %s_block%d {\n"
92 const char *body_template
=
94 char *prefix
, *prefix_tail
, *body
, *body_tail
;
97 prefix
= calloc(1, (strlen(block_prefix
) * 2 + strlen(prefix_template
) +
99 body
= calloc(1, (strlen(block_prefix
) + strlen(body_template
) +
101 prefix_tail
= prefix
;
106 for (i
= 0; i
< blocks
; i
++) {
107 prefix_tail
+= sprintf(prefix_tail
, prefix_template
,
110 body_tail
+= sprintf(body_tail
, body_template
,
115 case GL_VERTEX_SHADER
:
116 (void)!asprintf(&shader
, vs_source
, prefix
, body
);
118 case GL_FRAGMENT_SHADER
:
119 (void)!asprintf(&shader
, fs_source
, prefix
, body
);
122 piglit_report_result(PIGLIT_FAIL
);
132 build_shaders(const char *vs_prefix
, int vs_blocks
,
133 const char *fs_prefix
, int fs_blocks
)
135 char *vs_source
, *fs_source
;
138 vs_source
= get_shader(GL_VERTEX_SHADER
, vs_prefix
, vs_blocks
);
139 fs_source
= get_shader(GL_FRAGMENT_SHADER
, fs_prefix
, fs_blocks
);
141 vs
= piglit_compile_shader_text(GL_VERTEX_SHADER
, vs_source
);
142 fs
= piglit_compile_shader_text(GL_FRAGMENT_SHADER
, fs_source
);
144 prog
= glCreateProgram();
145 glAttachShader(prog
, vs
);
146 glAttachShader(prog
, fs
);
149 if (!piglit_link_check_status_quiet(prog
)) {
150 glDeleteProgram(prog
);
161 fail_link_test(const char *vs_prefix
, int vs_blocks
,
162 const char *fs_prefix
, int fs_blocks
)
166 prog
= build_shaders(vs_prefix
, vs_blocks
,
167 fs_prefix
, fs_blocks
);
170 printf("linked with (%d, %d) blocks, should have failed\n",
171 vs_blocks
, fs_blocks
);
175 glDeleteProgram(prog
);
180 test_draw(int y_index
, GLuint prog
,
181 GLuint
*bos
, int test_block
, int active_blocks
)
183 float black
[4] = {0, 0, 0, 0};
184 /* Color values have to be 0 or 1, since in the case of a
185 * shared block between VS and FS, they'll be added twice.
187 float other_colors
[][4] = {
196 int screen_x
= screen_w
* (1 + 2 * test_block
);
197 int screen_y
= screen_h
* (1 + 2 * y_index
);
198 float x
= -1.0 + 2.0 * screen_x
/ piglit_width
;
199 float y
= -1.0 + 2.0 * screen_y
/ piglit_height
;
200 float w
= 2.0 * screen_w
/ piglit_width
;
201 float h
= 2.0 * screen_h
/ piglit_height
;
203 float *expected_color
;
205 assert(test_block
< active_blocks
);
207 glViewport(0, 0, piglit_width
, piglit_height
);
209 expected_color
= other_colors
[test_block
% ARRAY_SIZE(other_colors
)];
211 for (i
= 0; i
< active_blocks
; i
++) {
213 color
= expected_color
;
217 glBindBuffer(GL_SHADER_STORAGE_BUFFER
, bos
[i
]);
218 glBufferData(GL_SHADER_STORAGE_BUFFER
,
219 4 * sizeof(float), color
, GL_DYNAMIC_DRAW
);
222 piglit_draw_rect(x
, y
, w
, h
);
224 if (screen_x
+ screen_w
>= piglit_width
||
225 screen_y
+ screen_h
>= piglit_height
) {
226 printf("warning: window too small to display test rect.\n");
230 return piglit_probe_rect_rgba(screen_x
, screen_y
,
231 screen_w
, screen_h
, expected_color
);
235 pass_link_test(int y_index
,
236 const char *vs_prefix
, int vs_blocks
,
237 const char *fs_prefix
, int fs_blocks
)
241 GLuint
*bos
= (GLuint
*) calloc(vs_blocks
+ fs_blocks
, sizeof(GLuint
));
245 prog
= build_shaders(vs_prefix
, vs_blocks
,
246 fs_prefix
, fs_blocks
);
249 printf("shader with (%d, %d) blocks failed to link\n",
250 vs_blocks
, fs_blocks
);
256 glGetProgramInterfaceiv(prog
, GL_SHADER_STORAGE_BLOCK
,
257 GL_ACTIVE_RESOURCES
, &active_blocks
);
258 glGenBuffers(active_blocks
, bos
);
259 for (i
= 0; i
< active_blocks
; i
++) {
260 glShaderStorageBlockBinding(prog
, i
, i
);
261 glBindBufferBase(GL_SHADER_STORAGE_BUFFER
, i
, bos
[i
]);
264 for (i
= 0; i
< active_blocks
; i
++) {
265 if (!test_draw(y_index
, prog
, bos
, i
, active_blocks
)) {
270 glDeleteBuffers(active_blocks
, bos
);
271 glDeleteProgram(prog
);
282 GLint max_vs
, max_fs
, max_combined
, max_combined_out
;
284 piglit_require_extension("GL_ARB_shader_storage_buffer_object");
285 piglit_require_extension("GL_ARB_program_interface_query");
287 glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS
, &max_vs
);
288 glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS
, &max_fs
);
289 glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS
, &max_combined
);
290 glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES
, &max_combined_out
);
292 if (!piglit_check_gl_error(GL_NO_ERROR
))
295 printf("Max VS shader storage blocks: %d\n", max_vs
);
296 printf("Max FS shader storage blocks: %d\n", max_fs
);
297 printf("Max combined shader storage blocks: %d\n", max_combined
);
298 printf("Max combined shader output resources: %d\n", max_combined_out
);
301 glClearColor(0.5, 0.5, 0.5, 0.5);
302 glClear(GL_COLOR_BUFFER_BIT
);
304 pass
= fail_link_test("vs", max_vs
+ 1,
306 pass
= fail_link_test("fs", 0,
307 "fs", max_fs
+ 1) && pass
;
308 if (max_vs
+ max_fs
> max_combined
) {
309 pass
= fail_link_test("vs",
312 max_combined
+ 1 - max_vs
) && pass
;
314 pass
= fail_link_test("shared",
317 max_combined
+ 1 - max_vs
) && pass
;
320 if (max_combined_out
) {
321 pass
= fail_link_test("vs",
324 max_combined_out
+ 1 - max_vs
) && pass
;
326 pass
= fail_link_test("shared",
329 max_combined_out
+ 1 - max_vs
) && pass
;
332 pass
= pass_link_test(0,
336 pass
= pass_link_test(1,
338 "fs", max_fs
) && pass
;
340 pass
= pass_link_test(2,
343 max_combined
- max_vs
)) && pass
;
345 pass
= pass_link_test(3,
347 "shared", MIN2(max_fs
,
348 max_combined
- max_vs
)) && pass
;
350 if (max_combined_out
) {
351 pass
= pass_link_test(4,
354 MIN2(max_fs
, max_combined
- max_vs
)) && pass
;
357 piglit_present_results();
359 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
364 piglit_init(int argc
, char **argv
)