2 * Copyright 2015 Advanced Micro Devices, Inc.
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 #include "state_tracker/st_context.h"
26 #include "state_tracker/st_cb_copyimage.h"
27 #include "state_tracker/st_cb_fbo.h"
28 #include "state_tracker/st_texture.h"
30 #include "util/u_box.h"
31 #include "util/u_format.h"
32 #include "util/u_inlines.h"
36 * Return an equivalent canonical format without "X" channels.
38 * Copying between incompatible formats is easier when the format is
39 * canonicalized, meaning that it is in a standard form.
41 * The returned format has the same component sizes and swizzles as
42 * the source format, the type is changed to UINT or UNORM, depending on
43 * which one has the most swizzle combinations in their group.
45 * If it's not an array format, return a memcpy-equivalent array format.
47 * The key feature is that swizzled versions of formats of the same
48 * component size always return the same component type.
51 * Luminance, intensity, alpha, depth, stencil, and 8-bit and 16-bit packed
52 * formats are not supported. (same as ARB_copy_image)
54 static enum pipe_format
55 get_canonical_format(enum pipe_format format
)
57 const struct util_format_description
*desc
=
58 util_format_description(format
);
60 /* Packed formats. Return the equivalent array format. */
61 if (format
== PIPE_FORMAT_R11G11B10_FLOAT
||
62 format
== PIPE_FORMAT_R9G9B9E5_FLOAT
)
63 return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT
);
65 if (desc
->nr_channels
== 4 &&
66 desc
->channel
[0].size
== 10 &&
67 desc
->channel
[1].size
== 10 &&
68 desc
->channel
[2].size
== 10 &&
69 desc
->channel
[3].size
== 2) {
70 if (desc
->swizzle
[0] == PIPE_SWIZZLE_X
&&
71 desc
->swizzle
[1] == PIPE_SWIZZLE_Y
&&
72 desc
->swizzle
[2] == PIPE_SWIZZLE_Z
)
73 return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT
);
75 return PIPE_FORMAT_NONE
;
78 #define RETURN_FOR_SWIZZLE1(x, format) \
79 if (desc->swizzle[0] == PIPE_SWIZZLE_##x) \
82 #define RETURN_FOR_SWIZZLE2(x, y, format) \
83 if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
84 desc->swizzle[1] == PIPE_SWIZZLE_##y) \
87 #define RETURN_FOR_SWIZZLE3(x, y, z, format) \
88 if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
89 desc->swizzle[1] == PIPE_SWIZZLE_##y && \
90 desc->swizzle[2] == PIPE_SWIZZLE_##z) \
93 #define RETURN_FOR_SWIZZLE4(x, y, z, w, format) \
94 if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
95 desc->swizzle[1] == PIPE_SWIZZLE_##y && \
96 desc->swizzle[2] == PIPE_SWIZZLE_##z && \
97 desc->swizzle[3] == PIPE_SWIZZLE_##w) \
101 if (desc
->is_array
) {
102 switch (desc
->nr_channels
) {
104 switch (desc
->channel
[0].size
) {
106 RETURN_FOR_SWIZZLE1(X
, PIPE_FORMAT_R8_UINT
);
110 RETURN_FOR_SWIZZLE1(X
, PIPE_FORMAT_R16_UINT
);
114 RETURN_FOR_SWIZZLE1(X
, PIPE_FORMAT_R32_UINT
);
120 switch (desc
->channel
[0].size
) {
122 /* All formats in each group must be of the same type.
123 * We can't use UINT for R8G8 while using UNORM for G8R8.
125 RETURN_FOR_SWIZZLE2(X
, Y
, PIPE_FORMAT_R8G8_UNORM
);
126 RETURN_FOR_SWIZZLE2(Y
, X
, PIPE_FORMAT_G8R8_UNORM
);
130 RETURN_FOR_SWIZZLE2(X
, Y
, PIPE_FORMAT_R16G16_UNORM
);
131 RETURN_FOR_SWIZZLE2(Y
, X
, PIPE_FORMAT_G16R16_UNORM
);
135 RETURN_FOR_SWIZZLE2(X
, Y
, PIPE_FORMAT_R32G32_UINT
);
141 switch (desc
->channel
[0].size
) {
143 RETURN_FOR_SWIZZLE3(X
, Y
, Z
, PIPE_FORMAT_R8G8B8_UINT
);
147 RETURN_FOR_SWIZZLE3(X
, Y
, Z
, PIPE_FORMAT_R16G16B16_UINT
);
151 RETURN_FOR_SWIZZLE3(X
, Y
, Z
, PIPE_FORMAT_R32G32B32_UINT
);
157 switch (desc
->channel
[0].size
) {
159 RETURN_FOR_SWIZZLE4(X
, Y
, Z
, W
, PIPE_FORMAT_R8G8B8A8_UNORM
);
160 RETURN_FOR_SWIZZLE4(X
, Y
, Z
, 1, PIPE_FORMAT_R8G8B8A8_UNORM
);
161 RETURN_FOR_SWIZZLE4(Z
, Y
, X
, W
, PIPE_FORMAT_B8G8R8A8_UNORM
);
162 RETURN_FOR_SWIZZLE4(Z
, Y
, X
, 1, PIPE_FORMAT_B8G8R8A8_UNORM
);
163 RETURN_FOR_SWIZZLE4(W
, Z
, Y
, X
, PIPE_FORMAT_A8B8G8R8_UNORM
);
164 RETURN_FOR_SWIZZLE4(W
, Z
, Y
, 1, PIPE_FORMAT_A8B8G8R8_UNORM
);
165 RETURN_FOR_SWIZZLE4(Y
, Z
, W
, X
, PIPE_FORMAT_A8R8G8B8_UNORM
);
166 RETURN_FOR_SWIZZLE4(Y
, Z
, W
, 1, PIPE_FORMAT_A8R8G8B8_UNORM
);
170 RETURN_FOR_SWIZZLE4(X
, Y
, Z
, W
, PIPE_FORMAT_R16G16B16A16_UINT
);
171 RETURN_FOR_SWIZZLE4(X
, Y
, Z
, 1, PIPE_FORMAT_R16G16B16A16_UINT
);
175 RETURN_FOR_SWIZZLE4(X
, Y
, Z
, W
, PIPE_FORMAT_R32G32B32A32_UINT
);
176 RETURN_FOR_SWIZZLE4(X
, Y
, Z
, 1, PIPE_FORMAT_R32G32B32A32_UINT
);
181 assert(!"unknown array format");
182 return PIPE_FORMAT_NONE
;
185 assert(!"unknown packed format");
186 return PIPE_FORMAT_NONE
;
190 * Return true if the swizzle is XYZW in case of a 4-channel format,
191 * XY in case of a 2-channel format, or X in case of a 1-channel format.
194 has_identity_swizzle(const struct util_format_description
*desc
)
198 for (i
= 0; i
< desc
->nr_channels
; i
++)
199 if (desc
->swizzle
[i
] != PIPE_SWIZZLE_X
+ i
)
206 * Return a canonical format for the given bits and channel size.
208 static enum pipe_format
209 canonical_format_from_bits(unsigned bits
, unsigned channel_size
)
213 if (channel_size
== 8)
214 return get_canonical_format(PIPE_FORMAT_R8_UINT
);
218 if (channel_size
== 8)
219 return get_canonical_format(PIPE_FORMAT_R8G8_UINT
);
220 if (channel_size
== 16)
221 return get_canonical_format(PIPE_FORMAT_R16_UINT
);
225 if (channel_size
== 8)
226 return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT
);
227 if (channel_size
== 16)
228 return get_canonical_format(PIPE_FORMAT_R16G16_UINT
);
229 if (channel_size
== 32)
230 return get_canonical_format(PIPE_FORMAT_R32_UINT
);
234 if (channel_size
== 16)
235 return get_canonical_format(PIPE_FORMAT_R16G16B16A16_UINT
);
236 if (channel_size
== 32)
237 return get_canonical_format(PIPE_FORMAT_R32G32_UINT
);
241 if (channel_size
== 32)
242 return get_canonical_format(PIPE_FORMAT_R32G32B32A32_UINT
);
246 assert(!"impossible format");
247 return PIPE_FORMAT_NONE
;
251 blit(struct pipe_context
*pipe
,
252 struct pipe_resource
*dst
,
253 enum pipe_format dst_format
,
255 unsigned dstx
, unsigned dsty
, unsigned dstz
,
256 struct pipe_resource
*src
,
257 enum pipe_format src_format
,
259 const struct pipe_box
*src_box
)
261 struct pipe_blit_info blit
= {{0}};
263 blit
.src
.resource
= src
;
264 blit
.dst
.resource
= dst
;
265 blit
.src
.format
= src_format
;
266 blit
.dst
.format
= dst_format
;
267 blit
.src
.level
= src_level
;
268 blit
.dst
.level
= dst_level
;
269 blit
.src
.box
= *src_box
;
270 u_box_3d(dstx
, dsty
, dstz
, src_box
->width
, src_box
->height
,
271 src_box
->depth
, &blit
.dst
.box
);
272 blit
.mask
= PIPE_MASK_RGBA
;
273 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
275 pipe
->blit(pipe
, &blit
);
279 swizzled_copy(struct pipe_context
*pipe
,
280 struct pipe_resource
*dst
,
282 unsigned dstx
, unsigned dsty
, unsigned dstz
,
283 struct pipe_resource
*src
,
285 const struct pipe_box
*src_box
)
287 const struct util_format_description
*src_desc
, *dst_desc
;
289 enum pipe_format blit_src_format
, blit_dst_format
;
291 /* Get equivalent canonical formats. Those are always array formats and
292 * copying between compatible canonical formats behaves either like
293 * memcpy or like swizzled memcpy. The idea is that we won't have to care
294 * about the channel type from this point on.
295 * Only the swizzle and channel size.
297 blit_src_format
= get_canonical_format(src
->format
);
298 blit_dst_format
= get_canonical_format(dst
->format
);
300 assert(blit_src_format
!= PIPE_FORMAT_NONE
);
301 assert(blit_dst_format
!= PIPE_FORMAT_NONE
);
303 src_desc
= util_format_description(blit_src_format
);
304 dst_desc
= util_format_description(blit_dst_format
);
306 assert(src_desc
->block
.bits
== dst_desc
->block
.bits
);
307 bits
= src_desc
->block
.bits
;
309 if (dst_desc
->channel
[0].size
== src_desc
->channel
[0].size
) {
310 /* Only the swizzle is different, which means we can just blit,
313 } else if (has_identity_swizzle(src_desc
)) {
314 /* Src is unswizzled and dst can be swizzled, so src is typecast
315 * to an equivalent dst-compatible format.
316 * e.g. R32 -> BGRA8 is realized as RGBA8 -> BGRA8
319 canonical_format_from_bits(bits
, dst_desc
->channel
[0].size
);
320 } else if (has_identity_swizzle(dst_desc
)) {
321 /* Dst is unswizzled and src can be swizzled, so dst is typecast
322 * to an equivalent src-compatible format.
323 * e.g. BGRA8 -> R32 is realized as BGRA8 -> RGBA8
326 canonical_format_from_bits(bits
, src_desc
->channel
[0].size
);
328 assert(!"This should have been handled by handle_complex_copy.");
332 blit(pipe
, dst
, blit_dst_format
, dst_level
, dstx
, dsty
, dstz
,
333 src
, blit_src_format
, src_level
, src_box
);
337 same_size_and_swizzle(const struct util_format_description
*d1
,
338 const struct util_format_description
*d2
)
342 if (d1
->layout
!= d2
->layout
||
343 d1
->nr_channels
!= d2
->nr_channels
||
344 d1
->is_array
!= d2
->is_array
)
347 for (i
= 0; i
< d1
->nr_channels
; i
++) {
348 if (d1
->channel
[i
].size
!= d2
->channel
[i
].size
)
351 if (d1
->swizzle
[i
] <= PIPE_SWIZZLE_W
&&
352 d2
->swizzle
[i
] <= PIPE_SWIZZLE_W
&&
353 d1
->swizzle
[i
] != d2
->swizzle
[i
])
360 static struct pipe_resource
*
361 create_texture(struct pipe_screen
*screen
, enum pipe_format format
,
363 unsigned width
, unsigned height
, unsigned depth
)
365 struct pipe_resource templ
;
367 memset(&templ
, 0, sizeof(templ
));
368 templ
.format
= format
;
369 templ
.width0
= width
;
370 templ
.height0
= height
;
372 templ
.array_size
= depth
;
373 templ
.nr_samples
= nr_samples
;
374 templ
.usage
= PIPE_USAGE_DEFAULT
;
375 templ
.bind
= PIPE_BIND_SAMPLER_VIEW
| PIPE_BIND_RENDER_TARGET
;
378 templ
.target
= PIPE_TEXTURE_2D_ARRAY
;
380 templ
.target
= PIPE_TEXTURE_2D
;
382 return screen
->resource_create(screen
, &templ
);
386 * Handle complex format conversions using 2 blits with a temporary texture
387 * in between, e.g. blitting from B10G10R10A2 to G16R16.
389 * This example is implemented this way:
390 * 1) First, blit from B10G10R10A2 to R10G10B10A2, which is canonical, so it
391 * can be reinterpreted as a different canonical format of the same bpp,
392 * such as R16G16. This blit only swaps R and B 10-bit components.
393 * 2) Finally, blit the result, which is R10G10B10A2, as R16G16 to G16R16.
394 * This blit only swaps R and G 16-bit components.
397 handle_complex_copy(struct pipe_context
*pipe
,
398 struct pipe_resource
*dst
,
400 unsigned dstx
, unsigned dsty
, unsigned dstz
,
401 struct pipe_resource
*src
,
403 const struct pipe_box
*src_box
,
404 enum pipe_format noncanon_format
,
405 enum pipe_format canon_format
)
407 struct pipe_box temp_box
;
408 struct pipe_resource
*temp
= NULL
;
409 const struct util_format_description
*src_desc
, *dst_desc
;
410 const struct util_format_description
*canon_desc
, *noncanon_desc
;
412 bool src_is_noncanon
;
414 bool dst_is_noncanon
;
416 src_desc
= util_format_description(src
->format
);
417 dst_desc
= util_format_description(dst
->format
);
418 canon_desc
= util_format_description(canon_format
);
419 noncanon_desc
= util_format_description(noncanon_format
);
421 src_is_canon
= same_size_and_swizzle(src_desc
, canon_desc
);
422 dst_is_canon
= same_size_and_swizzle(dst_desc
, canon_desc
);
423 src_is_noncanon
= same_size_and_swizzle(src_desc
, noncanon_desc
);
424 dst_is_noncanon
= same_size_and_swizzle(dst_desc
, noncanon_desc
);
426 if (src_is_noncanon
) {
427 /* Simple case - only types differ (e.g. UNORM and UINT). */
428 if (dst_is_noncanon
) {
429 blit(pipe
, dst
, noncanon_format
, dst_level
, dstx
, dsty
, dstz
, src
,
430 noncanon_format
, src_level
, src_box
);
434 /* Simple case - only types and swizzles differ. */
436 blit(pipe
, dst
, canon_format
, dst_level
, dstx
, dsty
, dstz
, src
,
437 noncanon_format
, src_level
, src_box
);
441 /* Use the temporary texture. Src is converted to a canonical format,
442 * then proceed the generic swizzled_copy.
444 temp
= create_texture(pipe
->screen
, canon_format
, src
->nr_samples
,
446 src_box
->height
, src_box
->depth
);
448 u_box_3d(0, 0, 0, src_box
->width
, src_box
->height
, src_box
->depth
,
451 blit(pipe
, temp
, canon_format
, 0, 0, 0, 0, src
, noncanon_format
,
453 swizzled_copy(pipe
, dst
, dst_level
, dstx
, dsty
, dstz
, temp
, 0,
455 pipe_resource_reference(&temp
, NULL
);
459 if (dst_is_noncanon
) {
460 /* Simple case - only types and swizzles differ. */
462 blit(pipe
, dst
, noncanon_format
, dst_level
, dstx
, dsty
, dstz
, src
,
463 canon_format
, src_level
, src_box
);
467 /* Use the temporary texture. First, use the generic copy, but use
468 * a canonical format in the destination. Then convert */
469 temp
= create_texture(pipe
->screen
, canon_format
, dst
->nr_samples
,
471 src_box
->height
, src_box
->depth
);
473 u_box_3d(0, 0, 0, src_box
->width
, src_box
->height
, src_box
->depth
,
476 swizzled_copy(pipe
, temp
, 0, 0, 0, 0, src
, src_level
, src_box
);
477 blit(pipe
, dst
, noncanon_format
, dst_level
, dstx
, dsty
, dstz
, temp
,
478 canon_format
, 0, &temp_box
);
479 pipe_resource_reference(&temp
, NULL
);
487 copy_image(struct pipe_context
*pipe
,
488 struct pipe_resource
*dst
,
490 unsigned dstx
, unsigned dsty
, unsigned dstz
,
491 struct pipe_resource
*src
,
493 const struct pipe_box
*src_box
)
495 if (src
->format
== dst
->format
||
496 util_format_is_compressed(src
->format
) ||
497 util_format_is_compressed(dst
->format
)) {
498 pipe
->resource_copy_region(pipe
, dst
, dst_level
, dstx
, dsty
, dstz
,
499 src
, src_level
, src_box
);
503 /* Copying to/from B10G10R10*2 needs 2 blits with R10G10B10A2
504 * as a temporary texture in between.
506 if (handle_complex_copy(pipe
, dst
, dst_level
, dstx
, dsty
, dstz
, src
,
507 src_level
, src_box
, PIPE_FORMAT_B10G10R10A2_UINT
,
508 PIPE_FORMAT_R10G10B10A2_UINT
))
511 /* Copying to/from G8R8 needs 2 blits with R8G8 as a temporary texture
514 if (handle_complex_copy(pipe
, dst
, dst_level
, dstx
, dsty
, dstz
, src
,
515 src_level
, src_box
, PIPE_FORMAT_G8R8_UNORM
,
516 PIPE_FORMAT_R8G8_UNORM
))
519 /* Copying to/from G16R16 needs 2 blits with R16G16 as a temporary texture
522 if (handle_complex_copy(pipe
, dst
, dst_level
, dstx
, dsty
, dstz
, src
,
523 src_level
, src_box
, PIPE_FORMAT_G16R16_UNORM
,
524 PIPE_FORMAT_R16G16_UNORM
))
527 /* Only allow non-identity swizzling on RGBA8 formats. */
529 /* Simple copy, memcpy with swizzling, no format conversion. */
530 swizzled_copy(pipe
, dst
, dst_level
, dstx
, dsty
, dstz
, src
, src_level
,
535 st_CopyImageSubData(struct gl_context
*ctx
,
536 struct gl_texture_image
*src_image
,
537 struct gl_renderbuffer
*src_renderbuffer
,
538 int src_x
, int src_y
, int src_z
,
539 struct gl_texture_image
*dst_image
,
540 struct gl_renderbuffer
*dst_renderbuffer
,
541 int dst_x
, int dst_y
, int dst_z
,
542 int src_width
, int src_height
)
544 struct st_context
*st
= st_context(ctx
);
545 struct pipe_context
*pipe
= st
->pipe
;
546 struct pipe_resource
*src_res
, *dst_res
;
548 int src_level
, dst_level
;
551 struct st_texture_image
*src
= st_texture_image(src_image
);
553 src_level
= src_image
->Level
;
554 src_z
+= src_image
->Face
;
555 if (src_image
->TexObject
->Immutable
) {
556 src_level
+= src_image
->TexObject
->MinLevel
;
557 src_z
+= src_image
->TexObject
->MinLayer
;
560 struct st_renderbuffer
*src
= st_renderbuffer(src_renderbuffer
);
561 src_res
= src
->texture
;
566 struct st_texture_image
*dst
= st_texture_image(dst_image
);
568 dst_level
= dst_image
->Level
;
569 dst_z
+= dst_image
->Face
;
570 if (dst_image
->TexObject
->Immutable
) {
571 dst_level
+= dst_image
->TexObject
->MinLevel
;
572 dst_z
+= dst_image
->TexObject
->MinLayer
;
575 struct st_renderbuffer
*dst
= st_renderbuffer(dst_renderbuffer
);
576 dst_res
= dst
->texture
;
580 u_box_2d_zslice(src_x
, src_y
, src_z
, src_width
, src_height
, &box
);
582 copy_image(pipe
, dst_res
, dst_level
, dst_x
, dst_y
, dst_z
,
583 src_res
, src_level
, &box
);
587 st_init_copy_image_functions(struct dd_function_table
*functions
)
589 functions
->CopyImageSubData
= st_CopyImageSubData
;