1 /*
2  * Copyright (C) 2014 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 DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 /** @file state.c
25  *
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
31  * correctly.
32  *
33  * A second test checks that glUniform*() work as specified when used
34  * to assign image units to shader image uniforms.
35  */
36 
37 #include "common.h"
38 
39 PIGLIT_GL_TEST_CONFIG_BEGIN
40 
41 /** Image width. */
42 #define W 16
43 
44 /** Image height. */
45 #define H 96
46 
47 /** Total number of pixels in the image. */
48 #define N (W * H)
49 
50 /** Maximum number of mipmap levels. */
51 #define M 11
52 
53 config.supports_gl_core_version = 32;
54 
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;
59 
60 PIGLIT_GL_TEST_CONFIG_END
61 
62 struct image_unit_action {
63         enum {
64                 /** End of action list. */
65                 END = 0,
66 
67                 /** Create a new texture object of type \a obj and
68                  * bind it to the specified image unit. */
69                 BIND_NEW,
70 
71                 /** Bind the same texture object that was previously
72                  * bound to image unit \a obj to the specified image
73                  * unit. */
74                 BIND_IDX,
75 
76                 /** Bind texture object \a obj to the specified image
77                  * unit. */
78                 BIND_OBJ,
79 
80                 /** Delete the texture object that was previously
81                  * bound to image unit \a obj. */
82                 DELETE_IDX
83         } action;
84 
85         /** Image unit this action has an effect on. */
86         unsigned idx;
87 
88         /** Object of this action. */
89         unsigned obj;
90 
91         /** Texture mipmap level that should be bound. */
92         int level;
93 
94         /** If true the whole texture level is bound rather than a
95          * single layer. */
96         bool layered;
97 
98         /** If \a layered is false, the index of the individual layer
99          * to bind. */
100         int layer;
101 
102         /** GL_READ_ONLY, GL_WRITE_ONLY or GL_READ_WRITE. */
103         GLenum access;
104 
105         /** Image format used to interpret the texture data. */
106         GLenum format;
107 
108         /** GL error code that should be expected after the completion
109          * of this action. */
110         GLenum expect_status;
111 };
112 
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,
116           GL_NO_ERROR },
117         { BIND_NEW, 1, GL_TEXTURE_2D,
118           1, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16F,
119           GL_NO_ERROR },
120         { BIND_NEW, 2, GL_TEXTURE_BUFFER,
121           0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA16F,
122           GL_NO_ERROR },
123         { BIND_NEW, 3, GL_TEXTURE_2D,
124           -1, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA16_SNORM,
125           GL_INVALID_VALUE },
126         { BIND_NEW, 3, GL_TEXTURE_2D,
127           0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGB565,
128           GL_INVALID_VALUE },
129         { BIND_NEW, 3, GL_TEXTURE_2D_ARRAY,
130           0, GL_FALSE, -1, GL_WRITE_ONLY, GL_RGBA16_SNORM,
131           GL_INVALID_VALUE },
132         { BIND_OBJ, 3, 0xdeadcafe,
133           0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8,
134           GL_INVALID_VALUE },
135         { BIND_NEW, 3, GL_TEXTURE_2D_ARRAY,
136           0, GL_FALSE, 2, GL_WRITE_ONLY, GL_RGBA16,
137           GL_NO_ERROR },
138         { BIND_NEW, 4, GL_TEXTURE_2D_ARRAY,
139           0, GL_TRUE, 0, GL_READ_ONLY, GL_RGBA16,
140           GL_NO_ERROR },
141         { BIND_OBJ, 2, 0,
142           0, GL_FALSE, 0, GL_READ_ONLY, GL_R8,
143           GL_NO_ERROR },
144         { BIND_IDX, ~0, 1,
145           0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA16_SNORM,
146           GL_INVALID_VALUE },
147         { BIND_NEW, 5, GL_TEXTURE_2D,
148           0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA16F,
149           GL_NO_ERROR },
150         { BIND_NEW, 6, GL_TEXTURE_3D,
151           0, GL_FALSE, 3, GL_WRITE_ONLY, GL_RGBA16F,
152           GL_NO_ERROR },
153         { DELETE_IDX, 5, 5,
154           0, GL_FALSE, 0, GL_READ_ONLY, GL_R8,
155           GL_NO_ERROR },
156         { END }
157 };
158 
159 /**
160  * Get the maximum number of image units supported by the
161  * implementation.
162  */
163 static unsigned
first_invalid_image_unit(void)164 first_invalid_image_unit(void)
165 {
166         int n;
167         glGetIntegerv(GL_MAX_IMAGE_UNITS, &n);
168         return n;
169 }
170 
171 /**
172  * Get the last action that modified the state of image unit \a idx.
173  */
174 static struct image_unit_action
get_last_unit_action(unsigned idx)175 get_last_unit_action(unsigned idx)
176 {
177         /* The initial image unit state is equivalent to this
178          * action. */
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
182         };
183         const struct image_unit_action *a, *la = &def_action;
184 
185         for (a = actions; a->action; ++a) {
186                 if (a->idx == idx)
187                         la = a;
188         }
189 
190         return *la;
191 }
192 
193 /**
194  * Execute the given action.
195  */
196 static bool
exec_action(const struct image_unit_action a)197 exec_action(const struct image_unit_action a)
198 {
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 };
205 
206                 if (!upload_image_levels(img, num_levels, 0, a.idx, pixels))
207                         return false;
208 
209                 glBindImageTexture(a.idx, get_texture(a.idx),
210                                    a.level, a.layered, a.layer,
211                                    a.access, a.format);
212 
213         } else if (a.action == BIND_IDX) {
214                 const unsigned idx = MIN2(a.idx, first_invalid_image_unit());
215 
216                 glBindImageTexture(idx, get_texture(a.obj),
217                                    a.level, a.layered, a.layer,
218                                    a.access, a.format);
219 
220         } else if (a.action == BIND_OBJ) {
221                 glBindImageTexture(a.idx, a.obj,
222                                    a.level, a.layered, a.layer,
223                                    a.access, a.format);
224 
225         } else if (a.action == DELETE_IDX) {
226                 GLuint tex = get_texture(a.idx);
227 
228                 glDeleteTextures(1, &tex);
229 
230         } else {
231                 abort();
232         }
233 
234         return piglit_check_gl_error(a.expect_status);
235 }
236 
237 static bool
check_integer(GLenum name,unsigned idx,int expect)238 check_integer(GLenum name, unsigned idx, int expect)
239 {
240         int v = 0xdeadcafe;
241 
242         glGetIntegeri_v(name, idx, &v);
243         if (v != expect) {
244                 fprintf(stderr, "Invalid value for integer %s index %d\n"
245                         "   Expected: %d\n"
246                         "   Observed: %d\n",
247                         piglit_get_gl_enum_name(name), idx, expect, v);
248                 return false;
249         }
250 
251         return true;
252 }
253 
254 static bool
check_tex_parameter(GLenum target,GLuint obj,GLenum name,int expect)255 check_tex_parameter(GLenum target, GLuint obj, GLenum name, int expect)
256 {
257         int v = 0xdeadcafe;
258 
259         glBindTexture(target, obj);
260         glGetTexParameteriv(target, name, &v);
261         if (v != expect) {
262                 fprintf(stderr, "Invalid value for tex parameter %s\n"
263                         "   Expected: %d\n"
264                         "   Observed: %d\n",
265                         piglit_get_gl_enum_name(name), expect, v);
266                 return false;
267         }
268 
269         return true;
270 }
271 
272 /**
273  * Check that the image unit state matches the result of the specified
274  * action.
275  */
276 static bool
check_action(const struct image_unit_action a)277 check_action(const struct image_unit_action a)
278 {
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) :
285                                     a.obj);
286 
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))
291                         return false;
292 
293                 return check_integer(GL_IMAGE_BINDING_NAME, a.idx,
294                                      obj) &&
295                         check_integer(GL_IMAGE_BINDING_LEVEL, a.idx,
296                                       a.level) &&
297                         check_integer(GL_IMAGE_BINDING_LAYERED, a.idx,
298                                       a.layered) &&
299                         check_integer(GL_IMAGE_BINDING_LAYER, a.idx,
300                                       a.layer) &&
301                         check_integer(GL_IMAGE_BINDING_ACCESS, a.idx,
302                                       a.access) &&
303                         check_integer(GL_IMAGE_BINDING_FORMAT, a.idx,
304                                       a.format);
305 
306         } else {
307                 return check_integer(GL_IMAGE_BINDING_NAME, a.idx, 0);
308         }
309 }
310 
311 /**
312  * Bind a number of texture objects to different image units and check
313  * that the image unit state was updated correctly.
314  */
315 static bool
run_test_binding(void)316 run_test_binding(void)
317 {
318         const struct image_unit_action *action;
319         bool ret = true;
320         int i;
321 
322         for (action = actions; action->action; ++action)
323                 ret &= exec_action(*action);
324 
325         for (i = 0; i < max_image_units(); ++i)
326                 ret &= check_action(get_last_unit_action(i));
327 
328         return ret;
329 }
330 
331 static bool
check_uniform_int(GLuint prog,int loc,int expect)332 check_uniform_int(GLuint prog, int loc, int expect)
333 {
334         int v = 0xdeadcafe;
335 
336         glGetUniformiv(prog, loc, &v);
337         if (v != expect) {
338                 fprintf(stderr, "Invalid value for uniform %d\n"
339                         "   Expected: %d\n"
340                         "   Observed: %d\n",
341                         loc, expect, v);
342                 return false;
343         }
344 
345         return piglit_check_gl_error(GL_NO_ERROR);
346 }
347 
348 #define CHECK_INVAL_1(prefix, suffix, args, ret) do {                      \
349                 prefix##suffix args;                                       \
350                 ret &= piglit_check_gl_error(GL_INVALID_OPERATION);        \
351         } while (0)
352 
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);                 \
356         } while (0)
357 
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);                 \
361         } while (0)
362 
363 /**
364  * Test binding image uniforms to image units for a simple shader
365  * program.
366  */
367 static bool
run_test_uniform(void)368 run_test_uniform(void)
369 {
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"
376                             "\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"
380                             "        return x;\n"
381                             "}\n"), NULL));
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);
385         int v[2];
386 
387         glUseProgram(prog);
388 
389         /*
390          * Image uniforms are bound to image units using
391          * glUniform1i{v}.
392          */
393         glUniform1i(loc, 3);
394         ret &= check_uniform_int(prog, loc, 3) &&
395                 check_uniform_int(prog, loc + 1, 0);
396 
397         glUniform1i(loc + 1, 3);
398         ret &= check_uniform_int(prog, loc, 3) &&
399                 check_uniform_int(prog, loc + 1, 3);
400 
401         v[0] = 4;
402         v[1] = 5;
403         glUniform1iv(loc, 2, v);
404         ret &= check_uniform_int(prog, loc, 4) &&
405                 check_uniform_int(prog, loc + 1, 5);
406 
407         /*
408          * GL_INVALID_VALUE is generated if the value specified is
409          * greater than or equal to the value of GL_MAX_IMAGE_UNITS.
410          */
411         glUniform1i(loc, first_invalid_image_unit());
412         ret &= piglit_check_gl_error(GL_INVALID_VALUE);
413 
414         v[0] = 3;
415         v[1] = first_invalid_image_unit() + 1;
416         glUniform1iv(loc, 2, v);
417         ret &= piglit_check_gl_error(GL_INVALID_VALUE);
418 
419         /*
420          * GL_INVALID_VALUE is generated if the value specified is
421          * less than zero.
422          */
423         glUniform1i(loc, -1);
424         ret &= piglit_check_gl_error(GL_INVALID_VALUE);
425 
426         v[0] = 3;
427         v[1] = -4;
428         glUniform1iv(loc, 2, v);
429         ret &= piglit_check_gl_error(GL_INVALID_VALUE);
430 
431         /*
432          * GL_INVALID_OPERATION is generated by Uniform* functions
433          * other than Uniform1i{v}.
434          */
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);
439 
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);
444 
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);
451 
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);
457 
458                 CHECK_INVAL_2(glUniform, 1dv, 2dv, (loc, 1, (double *)v), ret);
459                 CHECK_INVAL_2(glUniform, 3dv, 4dv, (loc, 1, (double *)v), ret);
460 
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);
467         }
468 
469         glDeleteProgram(prog);
470         return ret;
471 }
472 
473 void
piglit_init(int argc,char ** argv)474 piglit_init(int argc, char **argv)
475 {
476         enum piglit_result status = PIGLIT_PASS;
477 
478         piglit_require_extension("GL_ARB_shader_image_load_store");
479 
480         subtest(&status, true, run_test_binding(),
481                 "binding state test");
482 
483         subtest(&status, true, run_test_uniform(),
484                 "uniform state test");
485 
486         piglit_report_result(status);
487 }
488 
489 enum piglit_result
piglit_display(void)490 piglit_display(void)
491 {
492         return PIGLIT_FAIL;
493 }
494