2 * Copyright © 2012 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_uniform_buffer_object spec:
28 * "There is a set of implementation-dependent maximums for the
29 * number of active uniform blocks used by each shader (vertex,
30 * fragment, geometry). If the number of uniform blocks used by
31 * any shader in the program exceeds its corresponding limit, the
32 * program will fail to link. The limits for vertex, fragment,
33 * and geometry shaders can be obtained by calling GetIntegerv
34 * with <pname> values of MAX_VERTEX_UNIFORM_BLOCKS,
35 * MAX_FRAGMENT_UNIFORM_BLOCKS, and MAX_GEOMETRY_UNIFORM_BLOCKS,
38 * Additionally, there is an implementation-dependent limit on
39 * the sum of the number of active uniform blocks used by each
40 * shader of a program. If a uniform block is used by multiple
41 * shaders, each such use counts separately against this combined
42 * limit. The combined uniform block use limit can be obtained
43 * by calling GetIntegerv with a <pname> of
44 * MAX_COMBINED_UNIFORM_BLOCKS."
47 #include "piglit-util-gl.h"
49 PIGLIT_GL_TEST_CONFIG_BEGIN
51 config
.window_width
= 800;
52 config
.window_height
= 100;
53 config
.supports_gl_compat_version
= 10;
54 config
.window_visual
= PIGLIT_GL_VISUAL_RGBA
| PIGLIT_GL_VISUAL_DOUBLE
;
55 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
57 PIGLIT_GL_TEST_CONFIG_END
60 get_shader(GLenum target
, const char *block_prefix
, int blocks
)
63 const char *vs_source
=
64 "#extension GL_ARB_uniform_buffer_object : enable\n"
71 " gl_Position = gl_Vertex;\n"
74 const char *fs_source
=
75 "#extension GL_ARB_uniform_buffer_object : enable\n"
82 " gl_FragColor = v%s;\n"
84 const char *prefix_template
=
85 "layout(std140) uniform %s_block%d {\n"
88 const char *body_template
=
90 char *prefix
, *prefix_tail
, *body
, *body_tail
;
93 prefix
= calloc(1, (strlen(block_prefix
) * 2 + strlen(prefix_template
) +
95 body
= calloc(1, (strlen(block_prefix
) + strlen(body_template
) +
102 for (i
= 0; i
< blocks
; i
++) {
103 prefix_tail
+= sprintf(prefix_tail
, prefix_template
,
106 body_tail
+= sprintf(body_tail
, body_template
,
111 case GL_VERTEX_SHADER
:
112 (void)!asprintf(&shader
, vs_source
, prefix
, body
);
114 case GL_FRAGMENT_SHADER
:
115 (void)!asprintf(&shader
, fs_source
, prefix
, body
);
118 piglit_report_result(PIGLIT_FAIL
);
128 build_shaders(const char *vs_prefix
, int vs_blocks
,
129 const char *fs_prefix
, int fs_blocks
)
131 char *vs_source
, *fs_source
;
134 vs_source
= get_shader(GL_VERTEX_SHADER
, vs_prefix
, vs_blocks
);
135 fs_source
= get_shader(GL_FRAGMENT_SHADER
, fs_prefix
, fs_blocks
);
137 vs
= piglit_compile_shader_text(GL_VERTEX_SHADER
, vs_source
);
138 fs
= piglit_compile_shader_text(GL_FRAGMENT_SHADER
, fs_source
);
140 prog
= glCreateProgram();
141 glAttachShader(prog
, vs
);
142 glAttachShader(prog
, fs
);
145 if (!piglit_link_check_status_quiet(prog
)) {
146 glDeleteProgram(prog
);
157 fail_link_test(const char *vs_prefix
, int vs_blocks
,
158 const char *fs_prefix
, int fs_blocks
)
162 prog
= build_shaders(vs_prefix
, vs_blocks
,
163 fs_prefix
, fs_blocks
);
166 printf("linked with (%d, %d) blocks, should have failed\n",
167 vs_blocks
, fs_blocks
);
171 glDeleteProgram(prog
);
176 test_draw(int y_index
, GLuint prog
,
177 GLuint
*bos
, int test_block
, int active_blocks
)
179 float black
[4] = {0, 0, 0, 0};
180 /* Color values have to be 0 or 1, since in the case of a
181 * shared block between VS and FS, they'll be added twice.
183 float other_colors
[][4] = {
192 int screen_x
= screen_w
* (1 + 2 * test_block
);
193 int screen_y
= screen_h
* (1 + 2 * y_index
);
194 float x
= -1.0 + 2.0 * screen_x
/ piglit_width
;
195 float y
= -1.0 + 2.0 * screen_y
/ piglit_height
;
196 float w
= 2.0 * screen_w
/ piglit_width
;
197 float h
= 2.0 * screen_h
/ piglit_height
;
199 float *expected_color
;
201 assert(test_block
< active_blocks
);
203 glViewport(0, 0, piglit_width
, piglit_height
);
205 expected_color
= other_colors
[test_block
% ARRAY_SIZE(other_colors
)];
207 for (i
= 0; i
< active_blocks
; i
++) {
209 color
= expected_color
;
213 glBindBuffer(GL_UNIFORM_BUFFER
, bos
[i
]);
214 glBufferData(GL_UNIFORM_BUFFER
,
215 4 * sizeof(float), color
, GL_DYNAMIC_DRAW
);
218 piglit_draw_rect(x
, y
, w
, h
);
220 if (screen_x
+ screen_w
>= piglit_width
||
221 screen_y
+ screen_h
>= piglit_height
) {
222 printf("warning: window too small to display test rect.\n");
226 return piglit_probe_rect_rgba(screen_x
, screen_y
,
227 screen_w
, screen_h
, expected_color
);
231 pass_link_test(int y_index
,
232 const char *vs_prefix
, int vs_blocks
,
233 const char *fs_prefix
, int fs_blocks
)
237 GLuint
*bos
= (GLuint
*) calloc(vs_blocks
+ fs_blocks
, sizeof(GLuint
));
241 prog
= build_shaders(vs_prefix
, vs_blocks
,
242 fs_prefix
, fs_blocks
);
245 printf("shader with (%d, %d) blocks failed to link\n",
246 vs_blocks
, fs_blocks
);
252 glGetProgramiv(prog
, GL_ACTIVE_UNIFORM_BLOCKS
, &active_blocks
);
253 glGenBuffers(active_blocks
, bos
);
254 for (i
= 0; i
< active_blocks
; i
++) {
255 glUniformBlockBinding(prog
, i
, i
);
256 glBindBufferBase(GL_UNIFORM_BUFFER
, i
, bos
[i
]);
259 for (i
= 0; i
< active_blocks
; i
++) {
260 if (!test_draw(y_index
, prog
, bos
, i
, active_blocks
)) {
265 glDeleteBuffers(active_blocks
, bos
);
266 glDeleteProgram(prog
);
277 GLint max_vs
, max_fs
, max_combined
;
279 piglit_require_extension("GL_ARB_uniform_buffer_object");
281 glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS
, &max_vs
);
282 glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS
, &max_fs
);
283 glGetIntegerv(GL_MAX_COMBINED_UNIFORM_BLOCKS
, &max_combined
);
284 printf("Max VS uniform blocks: %d\n", max_vs
);
285 printf("Max FS uniform blocks: %d\n", max_fs
);
286 printf("Max combined uniform blocks: %d\n", max_combined
);
288 glClearColor(0.5, 0.5, 0.5, 0.5);
289 glClear(GL_COLOR_BUFFER_BIT
);
291 pass
= fail_link_test("vs", max_vs
+ 1,
293 pass
= fail_link_test("fs", 0,
294 "fs", max_fs
+ 1) && pass
;
295 if (max_vs
+ max_fs
> max_combined
) {
296 pass
= fail_link_test("vs",
299 max_combined
+ 1 - max_vs
) && pass
;
301 pass
= fail_link_test("shared",
304 max_combined
+ 1 - max_vs
) && pass
;
307 pass
= pass_link_test(0,
311 pass
= pass_link_test(1,
313 "fs", max_fs
) && pass
;
315 pass
= pass_link_test(2,
318 max_combined
- max_vs
)) && pass
;
320 pass
= pass_link_test(3,
322 "shared", MIN2(max_fs
,
323 max_combined
- max_vs
)) && pass
;
325 piglit_present_results();
327 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
332 piglit_init(int argc
, char **argv
)