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