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
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
26 * Test image unit binding by creating a number of textures and
27 * binding them as images with different parameters (including
28 * incorrect arguments that are supposed to generate GL errors),
29 * delete and unbind a few images and check using the state query API
30 * that the implementation is keeping track of the image unit state
33 * A second test checks that glUniform*() work as specified when used
34 * to assign image units to shader image uniforms.
39 PIGLIT_GL_TEST_CONFIG_BEGIN
47 /** Total number of pixels in the image. */
50 /** Maximum number of mipmap levels. */
53 config
.supports_gl_core_version
= 32;
55 config
.window_width
= 1;
56 config
.window_height
= 1;
57 config
.window_visual
= PIGLIT_GL_VISUAL_DOUBLE
| PIGLIT_GL_VISUAL_RGBA
;
58 config
.khr_no_error_support
= PIGLIT_HAS_ERRORS
;
60 PIGLIT_GL_TEST_CONFIG_END
62 struct image_unit_action
{
64 /** End of action list. */
67 /** Create a new texture object of type \a obj and
68 * bind it to the specified image unit. */
71 /** Bind the same texture object that was previously
72 * bound to image unit \a obj to the specified image
76 /** Bind texture object \a obj to the specified image
80 /** Delete the texture object that was previously
81 * bound to image unit \a obj. */
85 /** Image unit this action has an effect on. */
88 /** Object of this action. */
91 /** Texture mipmap level that should be bound. */
94 /** If true the whole texture level is bound rather than a
98 /** If \a layered is false, the index of the individual layer
102 /** GL_READ_ONLY, GL_WRITE_ONLY or GL_READ_WRITE. */
105 /** Image format used to interpret the texture data. */
108 /** GL error code that should be expected after the completion
110 GLenum expect_status
;
113 static const struct image_unit_action actions
[] = {
114 { BIND_NEW
, 0, GL_TEXTURE_2D
,
115 2, GL_FALSE
, 0, GL_READ_WRITE
, GL_RGBA16UI
,
117 { BIND_NEW
, 1, GL_TEXTURE_2D
,
118 1, GL_FALSE
, 0, GL_READ_WRITE
, GL_RGBA16F
,
120 { BIND_NEW
, 2, GL_TEXTURE_BUFFER
,
121 0, GL_FALSE
, 0, GL_WRITE_ONLY
, GL_RGBA16F
,
123 { BIND_NEW
, 3, GL_TEXTURE_2D
,
124 -1, GL_FALSE
, 0, GL_WRITE_ONLY
, GL_RGBA16_SNORM
,
126 { BIND_NEW
, 3, GL_TEXTURE_2D
,
127 0, GL_FALSE
, 0, GL_WRITE_ONLY
, GL_RGB565
,
129 { BIND_NEW
, 3, GL_TEXTURE_2D_ARRAY
,
130 0, GL_FALSE
, -1, GL_WRITE_ONLY
, GL_RGBA16_SNORM
,
132 { BIND_OBJ
, 3, 0xdeadcafe,
133 0, GL_FALSE
, 0, GL_WRITE_ONLY
, GL_RGBA8
,
135 { BIND_NEW
, 3, GL_TEXTURE_2D_ARRAY
,
136 0, GL_FALSE
, 2, GL_WRITE_ONLY
, GL_RGBA16
,
138 { BIND_NEW
, 4, GL_TEXTURE_2D_ARRAY
,
139 0, GL_TRUE
, 0, GL_READ_ONLY
, GL_RGBA16
,
142 0, GL_FALSE
, 0, GL_READ_ONLY
, GL_R8
,
145 0, GL_FALSE
, 0, GL_WRITE_ONLY
, GL_RGBA16_SNORM
,
147 { BIND_NEW
, 5, GL_TEXTURE_2D
,
148 0, GL_FALSE
, 0, GL_READ_ONLY
, GL_RGBA16F
,
150 { BIND_NEW
, 6, GL_TEXTURE_3D
,
151 0, GL_FALSE
, 3, GL_WRITE_ONLY
, GL_RGBA16F
,
154 0, GL_FALSE
, 0, GL_READ_ONLY
, GL_R8
,
160 * Get the maximum number of image units supported by the
164 first_invalid_image_unit(void)
167 glGetIntegerv(GL_MAX_IMAGE_UNITS
, &n
);
172 * Get the last action that modified the state of image unit \a idx.
174 static struct image_unit_action
175 get_last_unit_action(unsigned idx
)
177 /* The initial image unit state is equivalent to this
179 const struct image_unit_action def_action
= {
180 BIND_OBJ
, idx
, 0, 0, GL_FALSE
, 0,
181 GL_READ_ONLY
, GL_R8
, GL_NO_ERROR
183 const struct image_unit_action
*a
, *la
= &def_action
;
185 for (a
= actions
; a
->action
; ++a
) {
194 * Execute the given action.
197 exec_action(const struct image_unit_action a
)
199 if (a
.action
== BIND_NEW
) {
200 const GLenum format
= (get_image_format(a
.format
) ?
201 a
.format
: GL_RGBA32F
);
202 const struct image_info img
= image_info(a
.obj
, format
, W
, H
);
203 const unsigned num_levels
= image_num_levels(img
);
204 uint32_t pixels
[4 * N
* M
] = { 0 };
206 if (!upload_image_levels(img
, num_levels
, 0, a
.idx
, pixels
))
209 glBindImageTexture(a
.idx
, get_texture(a
.idx
),
210 a
.level
, a
.layered
, a
.layer
,
213 } else if (a
.action
== BIND_IDX
) {
214 const unsigned idx
= MIN2(a
.idx
, first_invalid_image_unit());
216 glBindImageTexture(idx
, get_texture(a
.obj
),
217 a
.level
, a
.layered
, a
.layer
,
220 } else if (a
.action
== BIND_OBJ
) {
221 glBindImageTexture(a
.idx
, a
.obj
,
222 a
.level
, a
.layered
, a
.layer
,
225 } else if (a
.action
== DELETE_IDX
) {
226 GLuint tex
= get_texture(a
.idx
);
228 glDeleteTextures(1, &tex
);
234 return piglit_check_gl_error(a
.expect_status
);
238 check_integer(GLenum name
, unsigned idx
, int expect
)
242 glGetIntegeri_v(name
, idx
, &v
);
244 fprintf(stderr
, "Invalid value for integer %s index %d\n"
247 piglit_get_gl_enum_name(name
), idx
, expect
, v
);
255 check_tex_parameter(GLenum target
, GLuint obj
, GLenum name
, int expect
)
259 glBindTexture(target
, obj
);
260 glGetTexParameteriv(target
, name
, &v
);
262 fprintf(stderr
, "Invalid value for tex parameter %s\n"
265 piglit_get_gl_enum_name(name
), expect
, v
);
273 * Check that the image unit state matches the result of the specified
277 check_action(const struct image_unit_action a
)
279 if ((a
.action
== BIND_NEW
||
280 a
.action
== BIND_OBJ
||
281 a
.action
== BIND_IDX
) &&
282 a
.expect_status
== GL_NO_ERROR
) {
283 const GLuint obj
= (a
.action
== BIND_NEW
? get_texture(a
.idx
) :
284 a
.action
== BIND_IDX
? get_texture(a
.obj
) :
287 if (a
.action
== BIND_NEW
&&
288 !check_tex_parameter(a
.obj
, obj
,
289 GL_IMAGE_FORMAT_COMPATIBILITY_TYPE
,
290 GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE
))
293 return check_integer(GL_IMAGE_BINDING_NAME
, a
.idx
,
295 check_integer(GL_IMAGE_BINDING_LEVEL
, a
.idx
,
297 check_integer(GL_IMAGE_BINDING_LAYERED
, a
.idx
,
299 check_integer(GL_IMAGE_BINDING_LAYER
, a
.idx
,
301 check_integer(GL_IMAGE_BINDING_ACCESS
, a
.idx
,
303 check_integer(GL_IMAGE_BINDING_FORMAT
, a
.idx
,
307 return check_integer(GL_IMAGE_BINDING_NAME
, a
.idx
, 0);
312 * Bind a number of texture objects to different image units and check
313 * that the image unit state was updated correctly.
316 run_test_binding(void)
318 const struct image_unit_action
*action
;
322 for (action
= actions
; action
->action
; ++action
)
323 ret
&= exec_action(*action
);
325 for (i
= 0; i
< max_image_units(); ++i
)
326 ret
&= check_action(get_last_unit_action(i
));
332 check_uniform_int(GLuint prog
, int loc
, int expect
)
336 glGetUniformiv(prog
, loc
, &v
);
338 fprintf(stderr
, "Invalid value for uniform %d\n"
345 return piglit_check_gl_error(GL_NO_ERROR
);
348 #define CHECK_INVAL_1(prefix, suffix, args, ret) do { \
349 prefix##suffix args; \
350 ret &= piglit_check_gl_error(GL_INVALID_OPERATION); \
353 #define CHECK_INVAL_2(prefix, suffix0, suffix1, args, ret) do { \
354 CHECK_INVAL_1(prefix, suffix0, args, ret); \
355 CHECK_INVAL_1(prefix, suffix1, args, ret); \
358 #define CHECK_INVAL_3(prefix, suffix0, suffix1, suffix2, args, ret) do { \
359 CHECK_INVAL_2(prefix, suffix0, suffix1, args, ret); \
360 CHECK_INVAL_1(prefix, suffix2, args, ret); \
364 * Test binding image uniforms to image units for a simple shader
368 run_test_uniform(void)
370 const struct grid_info grid
=
371 grid_info(GL_FRAGMENT_SHADER
, GL_RGBA32F
, W
, H
);
372 GLuint prog
= generate_program(
373 grid
, GL_FRAGMENT_SHADER
,
374 concat(image_hunk(image_info_for_grid(grid
), ""),
375 hunk("IMAGE_UNIFORM_T imgs[2];\n"
377 "GRID_T op(ivec2 idx, GRID_T x) {\n"
378 " imageStore(imgs[0], IMAGE_ADDR(idx), x);\n"
379 " imageStore(imgs[1], IMAGE_ADDR(idx), x);\n"
382 const int loc
= glGetUniformLocation(prog
, "imgs");
383 bool ret
= prog
&& check_uniform_int(prog
, loc
, 0) &&
384 check_uniform_int(prog
, loc
+ 1, 0);
390 * Image uniforms are bound to image units using
394 ret
&= check_uniform_int(prog
, loc
, 3) &&
395 check_uniform_int(prog
, loc
+ 1, 0);
397 glUniform1i(loc
+ 1, 3);
398 ret
&= check_uniform_int(prog
, loc
, 3) &&
399 check_uniform_int(prog
, loc
+ 1, 3);
403 glUniform1iv(loc
, 2, v
);
404 ret
&= check_uniform_int(prog
, loc
, 4) &&
405 check_uniform_int(prog
, loc
+ 1, 5);
408 * GL_INVALID_VALUE is generated if the value specified is
409 * greater than or equal to the value of GL_MAX_IMAGE_UNITS.
411 glUniform1i(loc
, first_invalid_image_unit());
412 ret
&= piglit_check_gl_error(GL_INVALID_VALUE
);
415 v
[1] = first_invalid_image_unit() + 1;
416 glUniform1iv(loc
, 2, v
);
417 ret
&= piglit_check_gl_error(GL_INVALID_VALUE
);
420 * GL_INVALID_VALUE is generated if the value specified is
423 glUniform1i(loc
, -1);
424 ret
&= piglit_check_gl_error(GL_INVALID_VALUE
);
428 glUniform1iv(loc
, 2, v
);
429 ret
&= piglit_check_gl_error(GL_INVALID_VALUE
);
432 * GL_INVALID_OPERATION is generated by Uniform* functions
433 * other than Uniform1i{v}.
435 CHECK_INVAL_2(glUniform
, 1f
, 1ui
, (loc
, 0), ret
);
436 CHECK_INVAL_3(glUniform
, 2i
, 2f
, 2ui
, (loc
, 0, 0), ret
);
437 CHECK_INVAL_3(glUniform
, 3i
, 3f
, 3ui
, (loc
, 0, 0, 0), ret
);
438 CHECK_INVAL_3(glUniform
, 4i
, 4f
, 4ui
, (loc
, 0, 0, 0, 0), ret
);
440 CHECK_INVAL_2(glUniform
, 1fv
, 1uiv
, (loc
, 1, (void *)v
), ret
);
441 CHECK_INVAL_3(glUniform
, 2iv
, 2fv
, 2uiv
, (loc
, 1, (void *)v
), ret
);
442 CHECK_INVAL_3(glUniform
, 3iv
, 3fv
, 3uiv
, (loc
, 1, (void *)v
), ret
);
443 CHECK_INVAL_3(glUniform
, 4iv
, 4fv
, 4uiv
, (loc
, 1, (void *)v
), ret
);
445 CHECK_INVAL_3(glUniformMatrix
, 2fv
, 3fv
, 4fv
,
446 (loc
, 1, GL_FALSE
, (float *)v
), ret
);
447 CHECK_INVAL_3(glUniformMatrix
, 2x3fv
, 3x2fv
, 2x4fv
,
448 (loc
, 1, GL_FALSE
, (float *)v
), ret
);
449 CHECK_INVAL_3(glUniformMatrix
, 4x2fv
, 3x4fv
, 4x3fv
,
450 (loc
, 1, GL_FALSE
, (float *)v
), ret
);
452 if (piglit_is_extension_supported("GL_ARB_gpu_shader_fp64")) {
453 CHECK_INVAL_1(glUniform
, 1d
, (loc
, 0), ret
);
454 CHECK_INVAL_1(glUniform
, 2d
, (loc
, 0, 0), ret
);
455 CHECK_INVAL_1(glUniform
, 3d
, (loc
, 0, 0, 0), ret
);
456 CHECK_INVAL_1(glUniform
, 4d
, (loc
, 0, 0, 0, 0), ret
);
458 CHECK_INVAL_2(glUniform
, 1dv
, 2dv
, (loc
, 1, (double *)v
), ret
);
459 CHECK_INVAL_2(glUniform
, 3dv
, 4dv
, (loc
, 1, (double *)v
), ret
);
461 CHECK_INVAL_3(glUniformMatrix
, 2dv
, 3dv
, 4dv
,
462 (loc
, 1, GL_FALSE
, (double *)v
), ret
);
463 CHECK_INVAL_3(glUniformMatrix
, 2x3dv
, 3x2dv
, 2x4dv
,
464 (loc
, 1, GL_FALSE
, (double *)v
), ret
);
465 CHECK_INVAL_3(glUniformMatrix
, 4x2dv
, 3x4dv
, 4x3dv
,
466 (loc
, 1, GL_FALSE
, (double *)v
), ret
);
469 glDeleteProgram(prog
);
474 piglit_init(int argc
, char **argv
)
476 enum piglit_result status
= PIGLIT_PASS
;
478 piglit_require_extension("GL_ARB_shader_image_load_store");
480 subtest(&status
, true, run_test_binding(),
481 "binding state test");
483 subtest(&status
, true, run_test_uniform(),
484 "uniform state test");
486 piglit_report_result(status
);