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 * Common utility functions for the ARB_shader_image_load_store tests.
32 set_uniform_int(GLuint prog
, const char *name
, int value
)
36 loc
= glGetUniformLocation(prog
, name
);
40 glGetIntegerv(GL_CURRENT_PROGRAM
, &last_prog
);
41 if (prog
!= last_prog
)
44 glUniform1i(loc
, value
);
46 return piglit_check_gl_error(GL_NO_ERROR
);
49 static GLuint
*textures
, *buffers
;
50 static unsigned num_textures
, num_buffers
;
53 get_texture(unsigned unit
)
55 if (unit
>= num_textures
) {
56 const unsigned n
= unit
+ 1;
58 textures
= realloc(textures
, sizeof(GLuint
) * n
);
59 memset(&textures
[num_textures
], 0,
60 sizeof(GLuint
) * (n
- num_textures
));
64 return textures
[unit
];
68 get_buffer(unsigned unit
)
70 if (unit
>= num_buffers
) {
71 const unsigned n
= unit
+ 1;
73 buffers
= realloc(buffers
, sizeof(GLuint
) * n
);
74 memset(&buffers
[num_buffers
], 0,
75 sizeof(GLuint
) * (n
- num_buffers
));
82 static GLuint fb
[2], cb
[2], zb
[2];
83 static GLsizei vp
[2][4];
86 generate_fb(const struct grid_info grid
, unsigned idx
)
89 glGenFramebuffers(1, &fb
[idx
]);
90 glGenRenderbuffers(1, &cb
[idx
]);
91 glGenRenderbuffers(1, &zb
[idx
]);
94 glBindFramebuffer(GL_FRAMEBUFFER
, fb
[idx
]);
96 glBindRenderbuffer(GL_RENDERBUFFER
, cb
[idx
]);
97 glRenderbufferStorage(GL_RENDERBUFFER
, grid
.format
->format
,
98 grid
.size
.x
, grid
.size
.y
);
99 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
100 GL_RENDERBUFFER
, cb
[idx
]);
102 glBindRenderbuffer(GL_RENDERBUFFER
, zb
[idx
]);
103 glRenderbufferStorage(GL_RENDERBUFFER
, GL_DEPTH_COMPONENT32F
,
104 grid
.size
.x
, grid
.size
.y
);
105 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER
, GL_DEPTH_ATTACHMENT
,
106 GL_RENDERBUFFER
, zb
[idx
]);
110 vp
[idx
][2] = grid
.size
.x
;
111 vp
[idx
][3] = grid
.size
.y
;
112 glViewport(0, 0, grid
.size
.x
, grid
.size
.y
);
114 return piglit_check_gl_error(GL_NO_ERROR
);
118 upload_image(const struct image_info img
, unsigned unit
,
119 const uint32_t *pixels
)
121 return upload_image_levels(img
, 1, 0, unit
, pixels
);
125 upload_image_levels(const struct image_info img
, unsigned num_levels
,
126 unsigned level
, unsigned unit
, const uint32_t *pixels
)
128 const unsigned m
= image_num_components(img
.format
);
131 if (get_texture(unit
)) {
132 glDeleteTextures(1, &textures
[unit
]);
136 if (get_buffer(unit
)) {
137 glDeleteBuffers(1, &buffers
[unit
]);
141 glGenTextures(1, &textures
[unit
]);
142 glBindTexture(img
.target
->target
, textures
[unit
]);
144 switch (img
.target
->target
) {
146 for (l
= 0; l
< num_levels
; ++l
) {
147 const struct image_extent size
= image_level_size(img
, l
);
149 glTexImage1D(GL_TEXTURE_1D
, l
, img
.format
->format
,
150 size
.x
, 0, img
.format
->pixel_format
,
151 image_base_type(img
.format
),
152 &pixels
[m
* image_level_offset(img
, l
)]);
157 for (l
= 0; l
< num_levels
; ++l
) {
158 const struct image_extent size
= image_level_size(img
, l
);
160 glTexImage2D(GL_TEXTURE_2D
, l
, img
.format
->format
,
162 img
.format
->pixel_format
,
163 image_base_type(img
.format
),
164 &pixels
[m
* image_level_offset(img
, l
)]);
169 for (l
= 0; l
< num_levels
; ++l
) {
170 const struct image_extent size
= image_level_size(img
, l
);
172 glTexImage3D(GL_TEXTURE_3D
, l
, img
.format
->format
,
173 size
.x
, size
.y
, size
.z
, 0,
174 img
.format
->pixel_format
,
175 image_base_type(img
.format
),
176 &pixels
[m
* image_level_offset(img
, l
)]);
180 case GL_TEXTURE_RECTANGLE
:
181 assert(num_levels
== 1);
183 glTexImage2D(GL_TEXTURE_RECTANGLE
, 0, img
.format
->format
,
184 img
.size
.x
, img
.size
.y
, 0, img
.format
->pixel_format
,
185 image_base_type(img
.format
), pixels
);
188 case GL_TEXTURE_CUBE_MAP
:
189 for (l
= 0; l
< num_levels
; ++l
) {
190 const unsigned offset
= m
* image_level_offset(img
, l
);
191 const struct image_extent size
= image_level_size(img
, l
);
192 const unsigned face_sz
= m
* product(size
) / 6;
194 for (i
= 0; i
< 6; ++i
)
195 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ i
, l
,
196 img
.format
->format
, size
.x
, size
.y
, 0,
197 img
.format
->pixel_format
,
198 image_base_type(img
.format
),
199 &pixels
[offset
+ face_sz
* i
]);
203 case GL_TEXTURE_BUFFER
: {
205 * glTexImage*() isn't supposed to work with buffer
206 * textures. We copy the unpacked pixels to a texture
207 * with the desired internal format to let the GL pack
210 const struct image_extent grid
= image_optimal_extent(img
.size
);
213 assert(num_levels
== 1);
215 glGenBuffers(1, &buffers
[unit
]);
216 glBindBuffer(GL_PIXEL_PACK_BUFFER
, buffers
[unit
]);
217 glBufferData(GL_PIXEL_PACK_BUFFER
,
218 img
.size
.x
* image_pixel_size(img
.format
) / 8,
219 NULL
, GL_STATIC_DRAW
);
221 glGenTextures(1, &packed_tex
);
222 glBindTexture(GL_TEXTURE_2D
, packed_tex
);
224 glTexImage2D(GL_TEXTURE_2D
, 0, img
.format
->format
,
225 grid
.x
, grid
.y
, 0, img
.format
->pixel_format
,
226 image_base_type(img
.format
), pixels
);
227 glGetTexImage(GL_TEXTURE_2D
, 0, img
.format
->pixel_format
,
228 img
.format
->pixel_type
, NULL
);
229 glDeleteTextures(1, &packed_tex
);
230 glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0);
232 glTexBuffer(GL_TEXTURE_BUFFER
, image_compat_format(img
.format
),
236 case GL_TEXTURE_1D_ARRAY
:
237 for (l
= 0; l
< num_levels
; ++l
) {
238 const struct image_extent size
= image_level_size(img
, l
);
240 glTexImage2D(GL_TEXTURE_1D_ARRAY
, l
, img
.format
->format
,
241 size
.x
, size
.y
, 0, img
.format
->pixel_format
,
242 image_base_type(img
.format
),
243 &pixels
[m
* image_level_offset(img
, l
)]);
247 case GL_TEXTURE_2D_ARRAY
:
248 for (l
= 0; l
< num_levels
; ++l
) {
249 const struct image_extent size
= image_level_size(img
, l
);
251 glTexImage3D(GL_TEXTURE_2D_ARRAY
, l
, img
.format
->format
,
252 size
.x
, size
.y
, size
.z
, 0,
253 img
.format
->pixel_format
,
254 image_base_type(img
.format
),
255 &pixels
[m
* image_level_offset(img
, l
)]);
259 case GL_TEXTURE_CUBE_MAP_ARRAY
:
260 for (l
= 0; l
< num_levels
; ++l
) {
261 const struct image_extent size
= image_level_size(img
, l
);
263 glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY
, l
, img
.format
->format
,
264 size
.x
, size
.y
, size
.z
, 0,
265 img
.format
->pixel_format
,
266 image_base_type(img
.format
),
267 &pixels
[m
* image_level_offset(img
, l
)]);
271 case GL_TEXTURE_2D_MULTISAMPLE
:
272 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY
: {
274 * GL doesn't seem to provide any direct way to
275 * initialize a multisample texture, so we use
276 * imageStore() to render to it from the fragment
277 * shader copying the contents of a larger
278 * single-sample 2D texture.
280 const struct grid_info grid
= {
281 get_image_stage(GL_FRAGMENT_SHADER
)->bit
,
283 image_optimal_extent(img
.size
)
285 GLuint prog
= generate_program(
286 grid
, GL_FRAGMENT_SHADER
,
287 concat(image_hunk(image_info_for_grid(grid
), "SRC_"),
288 image_hunk(img
, "DST_"),
289 hunk("readonly SRC_IMAGE_UNIFORM_T src_img;\n"
290 "writeonly DST_IMAGE_UNIFORM_T dst_img;\n"
292 "GRID_T op(ivec2 idx, GRID_T x) {\n"
293 " imageStore(dst_img, DST_IMAGE_ADDR(idx),\n"
294 " imageLoad(src_img, SRC_IMAGE_ADDR(idx)));\n"
297 bool ret
= prog
&& generate_fb(grid
, 1);
300 assert(num_levels
== 1);
302 glGenTextures(1, &tmp_tex
);
303 glBindTexture(GL_TEXTURE_2D
, tmp_tex
);
305 if (img
.target
->target
== GL_TEXTURE_2D_MULTISAMPLE_ARRAY
) {
306 glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY
,
307 img
.size
.x
, img
.format
->format
,
308 img
.size
.y
, img
.size
.z
, img
.size
.w
,
311 glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE
,
312 img
.size
.x
, img
.format
->format
,
313 img
.size
.y
, img
.size
.z
,
317 glTexImage2D(GL_TEXTURE_2D
, 0, img
.format
->format
,
318 grid
.size
.x
, grid
.size
.y
, 0,
319 img
.format
->pixel_format
, image_base_type(img
.format
),
322 glBindImageTexture(unit
, textures
[unit
], 0, GL_TRUE
, 0,
323 GL_WRITE_ONLY
, img
.format
->format
);
324 glBindImageTexture(6, tmp_tex
, 0, GL_TRUE
, 0,
325 GL_READ_ONLY
, img
.format
->format
);
327 ret
&= set_uniform_int(prog
, "src_img", 6) &&
328 set_uniform_int(prog
, "dst_img", unit
) &&
329 draw_grid(grid
, prog
);
331 glDeleteProgram(prog
);
332 glDeleteTextures(1, &tmp_tex
);
334 glBindFramebuffer(GL_FRAMEBUFFER
, fb
[0]);
335 glViewport(vp
[0][0], vp
[0][1], vp
[0][2], vp
[0][3]);
337 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
);
347 glBindImageTexture(unit
, textures
[unit
], level
, GL_TRUE
, 0,
348 GL_READ_WRITE
, img
.format
->format
);
350 return piglit_check_gl_error(GL_NO_ERROR
);
354 download_image(const struct image_info img
, unsigned unit
,
357 return download_image_levels(img
, 1, unit
, r_pixels
);
361 download_image_levels(const struct image_info img
, unsigned num_levels
,
362 unsigned unit
, uint32_t *r_pixels
)
364 const unsigned m
= image_num_components(img
.format
);
367 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT
|
368 GL_BUFFER_UPDATE_BARRIER_BIT
|
369 GL_PIXEL_BUFFER_BARRIER_BIT
|
370 GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
);
372 glBindTexture(img
.target
->target
, textures
[unit
]);
374 switch (img
.target
->target
) {
378 case GL_TEXTURE_RECTANGLE
:
379 case GL_TEXTURE_1D_ARRAY
:
380 case GL_TEXTURE_2D_ARRAY
:
381 case GL_TEXTURE_CUBE_MAP_ARRAY
:
382 assert(img
.target
->target
!= GL_TEXTURE_RECTANGLE
||
385 for (l
= 0; l
< num_levels
; ++l
)
386 glGetTexImage(img
.target
->target
, l
,
387 img
.format
->pixel_format
,
388 image_base_type(img
.format
),
389 &r_pixels
[m
* image_level_offset(img
, l
)]);
392 case GL_TEXTURE_CUBE_MAP
:
393 for (l
= 0; l
< num_levels
; ++l
) {
394 const unsigned offset
= m
* image_level_offset(img
, l
);
395 const unsigned face_sz
=
396 m
* product(image_level_size(img
, l
)) / 6;
398 for (i
= 0; i
< 6; ++i
)
399 glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ i
,
400 l
, img
.format
->pixel_format
,
401 image_base_type(img
.format
),
402 &r_pixels
[offset
+ face_sz
* i
]);
407 case GL_TEXTURE_BUFFER
: {
409 * glGetTexImage() isn't supposed to work with buffer
410 * textures. We copy the packed pixels to a texture
411 * with the same internal format as the image to let
412 * the GL unpack it for us.
414 const struct image_extent grid
= image_optimal_extent(img
.size
);
417 assert(num_levels
== 1);
419 glGenTextures(1, &packed_tex
);
420 glBindTexture(GL_TEXTURE_2D
, packed_tex
);
421 glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, buffers
[unit
]);
423 glTexImage2D(GL_TEXTURE_2D
, 0, img
.format
->format
,
424 grid
.x
, grid
.y
, 0, img
.format
->pixel_format
,
425 img
.format
->pixel_type
, NULL
);
426 glGetTexImage(GL_TEXTURE_2D
, 0, img
.format
->pixel_format
,
427 image_base_type(img
.format
), r_pixels
);
429 glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
430 glDeleteTextures(1, &packed_tex
);
433 case GL_TEXTURE_2D_MULTISAMPLE
:
434 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY
: {
436 * GL doesn't seem to provide any direct way to read
437 * back a multisample texture, so we use imageLoad()
438 * to copy its contents to a larger single-sample 2D
439 * texture from the fragment shader.
441 const struct grid_info grid
= {
442 get_image_stage(GL_FRAGMENT_SHADER
)->bit
,
444 image_optimal_extent(img
.size
)
446 GLuint prog
= generate_program(
447 grid
, GL_FRAGMENT_SHADER
,
448 concat(image_hunk(img
, "SRC_"),
449 image_hunk(image_info_for_grid(grid
), "DST_"),
450 hunk("readonly SRC_IMAGE_UNIFORM_T src_img;\n"
451 "writeonly DST_IMAGE_UNIFORM_T dst_img;\n"
453 "GRID_T op(ivec2 idx, GRID_T x) {\n"
454 " imageStore(dst_img, DST_IMAGE_ADDR(idx),\n"
455 " imageLoad(src_img, SRC_IMAGE_ADDR(idx)));\n"
458 bool ret
= prog
&& generate_fb(grid
, 1);
461 assert(num_levels
== 1);
463 glGenTextures(1, &tmp_tex
);
464 glBindTexture(GL_TEXTURE_2D
, tmp_tex
);
466 glTexImage2D(GL_TEXTURE_2D
, 0, img
.format
->format
,
467 grid
.size
.x
, grid
.size
.y
, 0,
468 img
.format
->pixel_format
, image_base_type(img
.format
),
471 glBindImageTexture(unit
, textures
[unit
], 0, GL_TRUE
, 0,
472 GL_READ_ONLY
, img
.format
->format
);
473 glBindImageTexture(6, tmp_tex
, 0, GL_TRUE
, 0,
474 GL_WRITE_ONLY
, img
.format
->format
);
476 ret
&= set_uniform_int(prog
, "src_img", unit
) &&
477 set_uniform_int(prog
, "dst_img", 6) &&
478 draw_grid(grid
, prog
);
480 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT
);
482 glGetTexImage(GL_TEXTURE_2D
, 0, img
.format
->pixel_format
,
483 image_base_type(img
.format
), r_pixels
);
485 glDeleteProgram(prog
);
486 glDeleteTextures(1, &tmp_tex
);
488 glBindFramebuffer(GL_FRAMEBUFFER
, fb
[0]);
489 glViewport(vp
[0][0], vp
[0][1], vp
[0][2], vp
[0][3]);
499 return piglit_check_gl_error(GL_NO_ERROR
);
503 init_pixels(const struct image_info img
, uint32_t *r_pixels
,
504 double r
, double g
, double b
, double a
)
506 const double init
[4] = { r
, g
, b
, a
};
507 const unsigned m
= image_num_components(img
.format
);
510 for (i
= 0; i
< product(img
.size
); ++i
) {
511 for (j
= 0; j
< m
; ++j
) {
512 r_pixels
[i
* m
+ j
] = encode(img
.format
, init
[j
]);
520 check_pixels_vs(const struct image_info img
, unsigned stride
,
521 const uint32_t *pixels
, const uint32_t *expect
)
523 const unsigned m
= image_num_components(img
.format
);
526 for (i
= 0; i
< product(img
.size
); ++i
) {
527 const uint32_t *v
= &pixels
[m
* i
];
528 const uint32_t *u
= &expect
[stride
* m
* i
];
530 for (j
= 0; j
< m
; ++j
) {
531 if ((fabs(decode(img
.format
, v
[j
]) - decode(img
.format
, u
[j
])) >
532 get_idx(img
.epsilon
, j
)) &&
533 isfinite(decode(img
.format
, u
[j
]))) {
534 printf("Probe value at (%u, %u, %u, %u)\n",
536 i
/ img
.size
.x
% img
.size
.y
,
537 i
/ img
.size
.x
/ img
.size
.y
% img
.size
.z
,
538 i
/ img
.size
.x
/ img
.size
.y
/ img
.size
.z
);
540 printf(" Expected:");
542 for (j
= 0; j
< m
; ++j
)
543 printf(" %f", decode(img
.format
, u
[j
]));
545 printf("\n Observed:");
547 for (j
= 0; j
< m
; ++j
)
548 printf(" %f", decode(img
.format
, v
[j
]));
560 check_pixels(const struct image_info img
, const uint32_t *pixels
,
561 double r
, double g
, double b
, double a
)
563 const uint32_t expect
[4] = {
564 encode(img
.format
, r
), encode(img
.format
, g
),
565 encode(img
.format
, b
), encode(img
.format
, a
)
568 return check_pixels_vs(img
, 0, pixels
, expect
);
572 check_pixels_v(const struct image_info img
, const uint32_t *pixels
,
573 const uint32_t *expect
)
575 return check_pixels_vs(img
, 1, pixels
, expect
);
579 init_fb(const struct grid_info grid
)
583 if (grid
.stages
& GL_COMPUTE_SHADER_BIT
) {
584 const struct image_info img
= image_info_for_grid(grid
);
585 const unsigned n
= product(grid
.size
) *
586 image_num_components(grid
.format
);
587 uint32_t *pixels
= malloc(n
* sizeof(*pixels
));
589 ret
= init_pixels(img
, pixels
, 0.5, 0.5, 0.5, 0.5) &&
590 upload_image(img
, max_image_units(), pixels
);
594 ret
= generate_fb(grid
, 0);
596 glClearColor(0.5, 0.5, 0.5, 0.5);
597 glClear(GL_COLOR_BUFFER_BIT
);
600 glClear(GL_DEPTH_BUFFER_BIT
);
607 download_result(const struct grid_info grid
, uint32_t *r_pixels
)
609 if (grid
.stages
& GL_COMPUTE_SHADER_BIT
) {
610 /* No actual framebuffer. Results are returned into
612 return download_image(image_info_for_grid(grid
),
613 max_image_units(), r_pixels
);
616 glReadPixels(0, 0, grid
.size
.x
, grid
.size
.y
,
617 grid
.format
->pixel_format
,
618 image_base_type(grid
.format
),
620 return piglit_check_gl_error(GL_NO_ERROR
);