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_bitmap.h"
27 #include "state_tracker/st_cb_copyimage.h"
28 #include "state_tracker/st_cb_fbo.h"
29 #include "state_tracker/st_texture.h"
31 #include "util/u_box.h"
32 #include "util/u_format.h"
33 #include "util/u_inlines.h"
37 * Return an equivalent canonical format without "X" channels.
39 * Copying between incompatible formats is easier when the format is
40 * canonicalized, meaning that it is in a standard form.
42 * The returned format has the same component sizes and swizzles as
43 * the source format, the type is changed to UINT or UNORM, depending on
44 * which one has the most swizzle combinations in their group.
46 * If it's not an array format, return a memcpy-equivalent array format.
48 * The key feature is that swizzled versions of formats of the same
49 * component size always return the same component type.
52 * Luminance, intensity, alpha, depth, stencil, and 8-bit and 16-bit packed
53 * formats are not supported. (same as ARB_copy_image)
55 static enum pipe_format
56 get_canonical_format(enum pipe_format format
)
58 const struct util_format_description
*desc
=
59 util_format_description(format
);
61 /* Packed formats. Return the equivalent array format. */
62 if (format
== PIPE_FORMAT_R11G11B10_FLOAT
||
63 format
== PIPE_FORMAT_R9G9B9E5_FLOAT
)
64 return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT
);
66 if (desc
->nr_channels
== 4 &&
67 desc
->channel
[0].size
== 10 &&
68 desc
->channel
[1].size
== 10 &&
69 desc
->channel
[2].size
== 10 &&
70 desc
->channel
[3].size
== 2) {
71 if (desc
->swizzle
[0] == PIPE_SWIZZLE_X
&&
72 desc
->swizzle
[1] == PIPE_SWIZZLE_Y
&&
73 desc
->swizzle
[2] == PIPE_SWIZZLE_Z
)
74 return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT
);
76 return PIPE_FORMAT_NONE
;
79 #define RETURN_FOR_SWIZZLE1(x, format) \
80 if (desc->swizzle[0] == PIPE_SWIZZLE_##x) \
83 #define RETURN_FOR_SWIZZLE2(x, y, format) \
84 if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
85 desc->swizzle[1] == PIPE_SWIZZLE_##y) \
88 #define RETURN_FOR_SWIZZLE3(x, y, z, format) \
89 if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
90 desc->swizzle[1] == PIPE_SWIZZLE_##y && \
91 desc->swizzle[2] == PIPE_SWIZZLE_##z) \
94 #define RETURN_FOR_SWIZZLE4(x, y, z, w, format) \
95 if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
96 desc->swizzle[1] == PIPE_SWIZZLE_##y && \
97 desc->swizzle[2] == PIPE_SWIZZLE_##z && \
98 desc->swizzle[3] == PIPE_SWIZZLE_##w) \
102 if (desc
->is_array
) {
103 switch (desc
->nr_channels
) {
105 switch (desc
->channel
[0].size
) {
107 RETURN_FOR_SWIZZLE1(X
, PIPE_FORMAT_R8_UINT
);
111 RETURN_FOR_SWIZZLE1(X
, PIPE_FORMAT_R16_UINT
);
115 RETURN_FOR_SWIZZLE1(X
, PIPE_FORMAT_R32_UINT
);
121 switch (desc
->channel
[0].size
) {
123 /* All formats in each group must be of the same type.
124 * We can't use UINT for R8G8 while using UNORM for G8R8.
126 RETURN_FOR_SWIZZLE2(X
, Y
, PIPE_FORMAT_R8G8_UNORM
);
127 RETURN_FOR_SWIZZLE2(Y
, X
, PIPE_FORMAT_G8R8_UNORM
);
131 RETURN_FOR_SWIZZLE2(X
, Y
, PIPE_FORMAT_R16G16_UNORM
);
132 RETURN_FOR_SWIZZLE2(Y
, X
, PIPE_FORMAT_G16R16_UNORM
);
136 RETURN_FOR_SWIZZLE2(X
, Y
, PIPE_FORMAT_R32G32_UINT
);
142 switch (desc
->channel
[0].size
) {
144 RETURN_FOR_SWIZZLE3(X
, Y
, Z
, PIPE_FORMAT_R8G8B8_UINT
);
148 RETURN_FOR_SWIZZLE3(X
, Y
, Z
, PIPE_FORMAT_R16G16B16_UINT
);
152 RETURN_FOR_SWIZZLE3(X
, Y
, Z
, PIPE_FORMAT_R32G32B32_UINT
);
158 switch (desc
->channel
[0].size
) {
160 RETURN_FOR_SWIZZLE4(X
, Y
, Z
, W
, PIPE_FORMAT_R8G8B8A8_UNORM
);
161 RETURN_FOR_SWIZZLE4(X
, Y
, Z
, 1, PIPE_FORMAT_R8G8B8A8_UNORM
);
162 RETURN_FOR_SWIZZLE4(Z
, Y
, X
, W
, PIPE_FORMAT_B8G8R8A8_UNORM
);
163 RETURN_FOR_SWIZZLE4(Z
, Y
, X
, 1, PIPE_FORMAT_B8G8R8A8_UNORM
);
164 RETURN_FOR_SWIZZLE4(W
, Z
, Y
, X
, PIPE_FORMAT_A8B8G8R8_UNORM
);
165 RETURN_FOR_SWIZZLE4(W
, Z
, Y
, 1, PIPE_FORMAT_A8B8G8R8_UNORM
);
166 RETURN_FOR_SWIZZLE4(Y
, Z
, W
, X
, PIPE_FORMAT_A8R8G8B8_UNORM
);
167 RETURN_FOR_SWIZZLE4(Y
, Z
, W
, 1, PIPE_FORMAT_A8R8G8B8_UNORM
);
171 RETURN_FOR_SWIZZLE4(X
, Y
, Z
, W
, PIPE_FORMAT_R16G16B16A16_UINT
);
172 RETURN_FOR_SWIZZLE4(X
, Y
, Z
, 1, PIPE_FORMAT_R16G16B16A16_UINT
);
176 RETURN_FOR_SWIZZLE4(X
, Y
, Z
, W
, PIPE_FORMAT_R32G32B32A32_UINT
);
177 RETURN_FOR_SWIZZLE4(X
, Y
, Z
, 1, PIPE_FORMAT_R32G32B32A32_UINT
);
182 assert(!"unknown array format");
183 return PIPE_FORMAT_NONE
;
186 assert(!"unknown packed format");
187 return PIPE_FORMAT_NONE
;
191 * Return true if the swizzle is XYZW in case of a 4-channel format,
192 * XY in case of a 2-channel format, or X in case of a 1-channel format.
195 has_identity_swizzle(const struct util_format_description
*desc
)
199 for (i
= 0; i
< desc
->nr_channels
; i
++)
200 if (desc
->swizzle
[i
] != PIPE_SWIZZLE_X
+ i
)
207 * Return a canonical format for the given bits and channel size.
209 static enum pipe_format
210 canonical_format_from_bits(unsigned bits
, unsigned channel_size
)
214 if (channel_size
== 8)
215 return get_canonical_format(PIPE_FORMAT_R8_UINT
);
219 if (channel_size
== 8)
220 return get_canonical_format(PIPE_FORMAT_R8G8_UINT
);
221 if (channel_size
== 16)
222 return get_canonical_format(PIPE_FORMAT_R16_UINT
);
226 if (channel_size
== 8)
227 return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT
);
228 if (channel_size
== 16)
229 return get_canonical_format(PIPE_FORMAT_R16G16_UINT
);
230 if (channel_size
== 32)
231 return get_canonical_format(PIPE_FORMAT_R32_UINT
);
235 if (channel_size
== 16)
236 return get_canonical_format(PIPE_FORMAT_R16G16B16A16_UINT
);
237 if (channel_size
== 32)
238 return get_canonical_format(PIPE_FORMAT_R32G32_UINT
);
242 if (channel_size
== 32)
243 return get_canonical_format(PIPE_FORMAT_R32G32B32A32_UINT
);
247 assert(!"impossible format");
248 return PIPE_FORMAT_NONE
;
252 blit(struct pipe_context
*pipe
,
253 struct pipe_resource
*dst
,
254 enum pipe_format dst_format
,
256 unsigned dstx
, unsigned dsty
, unsigned dstz
,
257 struct pipe_resource
*src
,
258 enum pipe_format src_format
,
260 const struct pipe_box
*src_box
)
262 struct pipe_blit_info blit
= {{0}};
264 blit
.src
.resource
= src
;
265 blit
.dst
.resource
= dst
;
266 blit
.src
.format
= src_format
;
267 blit
.dst
.format
= dst_format
;
268 blit
.src
.level
= src_level
;
269 blit
.dst
.level
= dst_level
;
270 blit
.src
.box
= *src_box
;
271 u_box_3d(dstx
, dsty
, dstz
, src_box
->width
, src_box
->height
,
272 src_box
->depth
, &blit
.dst
.box
);
273 blit
.mask
= PIPE_MASK_RGBA
;
274 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
276 pipe
->blit(pipe
, &blit
);
280 swizzled_copy(struct pipe_context
*pipe
,
281 struct pipe_resource
*dst
,
283 unsigned dstx
, unsigned dsty
, unsigned dstz
,
284 struct pipe_resource
*src
,
286 const struct pipe_box
*src_box
)
288 const struct util_format_description
*src_desc
, *dst_desc
;
290 enum pipe_format blit_src_format
, blit_dst_format
;
292 /* Get equivalent canonical formats. Those are always array formats and
293 * copying between compatible canonical formats behaves either like
294 * memcpy or like swizzled memcpy. The idea is that we won't have to care
295 * about the channel type from this point on.
296 * Only the swizzle and channel size.
298 blit_src_format
= get_canonical_format(src
->format
);
299 blit_dst_format
= get_canonical_format(dst
->format
);
301 assert(blit_src_format
!= PIPE_FORMAT_NONE
);
302 assert(blit_dst_format
!= PIPE_FORMAT_NONE
);
304 src_desc
= util_format_description(blit_src_format
);
305 dst_desc
= util_format_description(blit_dst_format
);
307 assert(src_desc
->block
.bits
== dst_desc
->block
.bits
);
308 bits
= src_desc
->block
.bits
;
310 if (dst_desc
->channel
[0].size
== src_desc
->channel
[0].size
) {
311 /* Only the swizzle is different, which means we can just blit,
314 } else if (has_identity_swizzle(src_desc
)) {
315 /* Src is unswizzled and dst can be swizzled, so src is typecast
316 * to an equivalent dst-compatible format.
317 * e.g. R32 -> BGRA8 is realized as RGBA8 -> BGRA8
320 canonical_format_from_bits(bits
, dst_desc
->channel
[0].size
);
321 } else if (has_identity_swizzle(dst_desc
)) {
322 /* Dst is unswizzled and src can be swizzled, so dst is typecast
323 * to an equivalent src-compatible format.
324 * e.g. BGRA8 -> R32 is realized as BGRA8 -> RGBA8
327 canonical_format_from_bits(bits
, src_desc
->channel
[0].size
);
329 assert(!"This should have been handled by handle_complex_copy.");
333 blit(pipe
, dst
, blit_dst_format
, dst_level
, dstx
, dsty
, dstz
,
334 src
, blit_src_format
, src_level
, src_box
);
338 same_size_and_swizzle(const struct util_format_description
*d1
,
339 const struct util_format_description
*d2
)
343 if (d1
->layout
!= d2
->layout
||
344 d1
->nr_channels
!= d2
->nr_channels
||
345 d1
->is_array
!= d2
->is_array
)
348 for (i
= 0; i
< d1
->nr_channels
; i
++) {
349 if (d1
->channel
[i
].size
!= d2
->channel
[i
].size
)
352 if (d1
->swizzle
[i
] <= PIPE_SWIZZLE_W
&&
353 d2
->swizzle
[i
] <= PIPE_SWIZZLE_W
&&
354 d1
->swizzle
[i
] != d2
->swizzle
[i
])
361 static struct pipe_resource
*
362 create_texture(struct pipe_screen
*screen
, enum pipe_format format
,
364 unsigned width
, unsigned height
, unsigned depth
)
366 struct pipe_resource templ
;
368 memset(&templ
, 0, sizeof(templ
));
369 templ
.format
= format
;
370 templ
.width0
= width
;
371 templ
.height0
= height
;
373 templ
.array_size
= depth
;
374 templ
.nr_samples
= nr_samples
;
375 templ
.usage
= PIPE_USAGE_DEFAULT
;
376 templ
.bind
= PIPE_BIND_SAMPLER_VIEW
| PIPE_BIND_RENDER_TARGET
;
379 templ
.target
= PIPE_TEXTURE_2D_ARRAY
;
381 templ
.target
= PIPE_TEXTURE_2D
;
383 return screen
->resource_create(screen
, &templ
);
387 * Handle complex format conversions using 2 blits with a temporary texture
388 * in between, e.g. blitting from B10G10R10A2 to G16R16.
390 * This example is implemented this way:
391 * 1) First, blit from B10G10R10A2 to R10G10B10A2, which is canonical, so it
392 * can be reinterpreted as a different canonical format of the same bpp,
393 * such as R16G16. This blit only swaps R and B 10-bit components.
394 * 2) Finally, blit the result, which is R10G10B10A2, as R16G16 to G16R16.
395 * This blit only swaps R and G 16-bit components.
398 handle_complex_copy(struct pipe_context
*pipe
,
399 struct pipe_resource
*dst
,
401 unsigned dstx
, unsigned dsty
, unsigned dstz
,
402 struct pipe_resource
*src
,
404 const struct pipe_box
*src_box
,
405 enum pipe_format noncanon_format
,
406 enum pipe_format canon_format
)
408 struct pipe_box temp_box
;
409 struct pipe_resource
*temp
= NULL
;
410 const struct util_format_description
*src_desc
, *dst_desc
;
411 const struct util_format_description
*canon_desc
, *noncanon_desc
;
413 bool src_is_noncanon
;
415 bool dst_is_noncanon
;
417 src_desc
= util_format_description(src
->format
);
418 dst_desc
= util_format_description(dst
->format
);
419 canon_desc
= util_format_description(canon_format
);
420 noncanon_desc
= util_format_description(noncanon_format
);
422 src_is_canon
= same_size_and_swizzle(src_desc
, canon_desc
);
423 dst_is_canon
= same_size_and_swizzle(dst_desc
, canon_desc
);
424 src_is_noncanon
= same_size_and_swizzle(src_desc
, noncanon_desc
);
425 dst_is_noncanon
= same_size_and_swizzle(dst_desc
, noncanon_desc
);
427 if (src_is_noncanon
) {
428 /* Simple case - only types differ (e.g. UNORM and UINT). */
429 if (dst_is_noncanon
) {
430 blit(pipe
, dst
, noncanon_format
, dst_level
, dstx
, dsty
, dstz
, src
,
431 noncanon_format
, src_level
, src_box
);
435 /* Simple case - only types and swizzles differ. */
437 blit(pipe
, dst
, canon_format
, dst_level
, dstx
, dsty
, dstz
, src
,
438 noncanon_format
, src_level
, src_box
);
442 /* Use the temporary texture. Src is converted to a canonical format,
443 * then proceed the generic swizzled_copy.
445 temp
= create_texture(pipe
->screen
, canon_format
, src
->nr_samples
,
447 src_box
->height
, src_box
->depth
);
449 u_box_3d(0, 0, 0, src_box
->width
, src_box
->height
, src_box
->depth
,
452 blit(pipe
, temp
, canon_format
, 0, 0, 0, 0, src
, noncanon_format
,
454 swizzled_copy(pipe
, dst
, dst_level
, dstx
, dsty
, dstz
, temp
, 0,
456 pipe_resource_reference(&temp
, NULL
);
460 if (dst_is_noncanon
) {
461 /* Simple case - only types and swizzles differ. */
463 blit(pipe
, dst
, noncanon_format
, dst_level
, dstx
, dsty
, dstz
, src
,
464 canon_format
, src_level
, src_box
);
468 /* Use the temporary texture. First, use the generic copy, but use
469 * a canonical format in the destination. Then convert */
470 temp
= create_texture(pipe
->screen
, canon_format
, dst
->nr_samples
,
472 src_box
->height
, src_box
->depth
);
474 u_box_3d(0, 0, 0, src_box
->width
, src_box
->height
, src_box
->depth
,
477 swizzled_copy(pipe
, temp
, 0, 0, 0, 0, src
, src_level
, src_box
);
478 blit(pipe
, dst
, noncanon_format
, dst_level
, dstx
, dsty
, dstz
, temp
,
479 canon_format
, 0, &temp_box
);
480 pipe_resource_reference(&temp
, NULL
);
488 copy_image(struct pipe_context
*pipe
,
489 struct pipe_resource
*dst
,
491 unsigned dstx
, unsigned dsty
, unsigned dstz
,
492 struct pipe_resource
*src
,
494 const struct pipe_box
*src_box
)
496 if (src
->format
== dst
->format
||
497 util_format_is_compressed(src
->format
) ||
498 util_format_is_compressed(dst
->format
)) {
499 pipe
->resource_copy_region(pipe
, dst
, dst_level
, dstx
, dsty
, dstz
,
500 src
, src_level
, src_box
);
504 /* Copying to/from B10G10R10*2 needs 2 blits with R10G10B10A2
505 * as a temporary texture in between.
507 if (handle_complex_copy(pipe
, dst
, dst_level
, dstx
, dsty
, dstz
, src
,
508 src_level
, src_box
, PIPE_FORMAT_B10G10R10A2_UINT
,
509 PIPE_FORMAT_R10G10B10A2_UINT
))
512 /* Copying to/from G8R8 needs 2 blits with R8G8 as a temporary texture
515 if (handle_complex_copy(pipe
, dst
, dst_level
, dstx
, dsty
, dstz
, src
,
516 src_level
, src_box
, PIPE_FORMAT_G8R8_UNORM
,
517 PIPE_FORMAT_R8G8_UNORM
))
520 /* Copying to/from G16R16 needs 2 blits with R16G16 as a temporary texture
523 if (handle_complex_copy(pipe
, dst
, dst_level
, dstx
, dsty
, dstz
, src
,
524 src_level
, src_box
, PIPE_FORMAT_G16R16_UNORM
,
525 PIPE_FORMAT_R16G16_UNORM
))
528 /* Only allow non-identity swizzling on RGBA8 formats. */
530 /* Simple copy, memcpy with swizzling, no format conversion. */
531 swizzled_copy(pipe
, dst
, dst_level
, dstx
, dsty
, dstz
, src
, src_level
,
535 /* Note, the only allowable compressed format for this function is ETC */
537 fallback_copy_image(struct st_context
*st
,
538 struct gl_texture_image
*dst_image
,
539 struct pipe_resource
*dst_res
,
540 int dst_x
, int dst_y
, int dst_z
,
541 struct gl_texture_image
*src_image
,
542 struct pipe_resource
*src_res
,
543 int src_x
, int src_y
, int src_z
,
544 int src_w
, int src_h
)
547 int dst_stride
, src_stride
;
548 struct pipe_transfer
*dst_transfer
, *src_transfer
;
551 bool dst_is_compressed
= dst_image
&& _mesa_is_format_compressed(dst_image
->TexFormat
);
552 bool src_is_compressed
= src_image
&& _mesa_is_format_compressed(src_image
->TexFormat
);
554 unsigned dst_w
= src_w
;
555 unsigned dst_h
= src_h
;
556 unsigned lines
= src_h
;
558 if (src_is_compressed
&& !dst_is_compressed
) {
559 dst_w
= DIV_ROUND_UP(dst_w
, 4);
560 dst_h
= DIV_ROUND_UP(dst_h
, 4);
561 } else if (!src_is_compressed
&& dst_is_compressed
) {
565 if (src_is_compressed
) {
566 lines
= DIV_ROUND_UP(lines
, 4);
570 line_bytes
= _mesa_format_row_stride(src_image
->TexFormat
, src_w
);
572 line_bytes
= _mesa_format_row_stride(dst_image
->TexFormat
, dst_w
);
575 st
->ctx
->Driver
.MapTextureImage(
576 st
->ctx
, dst_image
, dst_z
,
577 dst_x
, dst_y
, dst_w
, dst_h
,
578 GL_MAP_WRITE_BIT
, &dst
, &dst_stride
);
580 dst
= pipe_transfer_map(st
->pipe
, dst_res
, 0, dst_z
,
582 dst_x
, dst_y
, dst_w
, dst_h
,
584 dst_stride
= dst_transfer
->stride
;
588 st
->ctx
->Driver
.MapTextureImage(
589 st
->ctx
, src_image
, src_z
,
590 src_x
, src_y
, src_w
, src_h
,
591 GL_MAP_READ_BIT
, &src
, &src_stride
);
593 src
= pipe_transfer_map(st
->pipe
, src_res
, 0, src_z
,
595 src_x
, src_y
, src_w
, src_h
,
597 src_stride
= src_transfer
->stride
;
600 for (int y
= 0; y
< lines
; y
++) {
601 memcpy(dst
, src
, line_bytes
);
607 st
->ctx
->Driver
.UnmapTextureImage(st
->ctx
, dst_image
, dst_z
);
609 pipe_transfer_unmap(st
->pipe
, dst_transfer
);
613 st
->ctx
->Driver
.UnmapTextureImage(st
->ctx
, src_image
, src_z
);
615 pipe_transfer_unmap(st
->pipe
, src_transfer
);
620 st_CopyImageSubData(struct gl_context
*ctx
,
621 struct gl_texture_image
*src_image
,
622 struct gl_renderbuffer
*src_renderbuffer
,
623 int src_x
, int src_y
, int src_z
,
624 struct gl_texture_image
*dst_image
,
625 struct gl_renderbuffer
*dst_renderbuffer
,
626 int dst_x
, int dst_y
, int dst_z
,
627 int src_width
, int src_height
)
629 struct st_context
*st
= st_context(ctx
);
630 struct pipe_context
*pipe
= st
->pipe
;
631 struct pipe_resource
*src_res
, *dst_res
;
633 int src_level
, dst_level
;
634 int orig_src_z
= src_z
, orig_dst_z
= dst_z
;
636 st_flush_bitmap_cache(st
);
637 st_invalidate_readpix_cache(st
);
640 struct st_texture_image
*src
= st_texture_image(src_image
);
642 src_level
= src_image
->Level
;
643 src_z
+= src_image
->Face
;
644 if (src_image
->TexObject
->Immutable
) {
645 src_level
+= src_image
->TexObject
->MinLevel
;
646 src_z
+= src_image
->TexObject
->MinLayer
;
649 struct st_renderbuffer
*src
= st_renderbuffer(src_renderbuffer
);
650 src_res
= src
->texture
;
655 struct st_texture_image
*dst
= st_texture_image(dst_image
);
657 dst_level
= dst_image
->Level
;
658 dst_z
+= dst_image
->Face
;
659 if (dst_image
->TexObject
->Immutable
) {
660 dst_level
+= dst_image
->TexObject
->MinLevel
;
661 dst_z
+= dst_image
->TexObject
->MinLayer
;
664 struct st_renderbuffer
*dst
= st_renderbuffer(dst_renderbuffer
);
665 dst_res
= dst
->texture
;
669 u_box_2d_zslice(src_x
, src_y
, src_z
, src_width
, src_height
, &box
);
671 if ((src_image
&& st_etc_fallback(st
, src_image
)) ||
672 (dst_image
&& st_etc_fallback(st
, dst_image
))) {
673 fallback_copy_image(st
, dst_image
, dst_res
, dst_x
, dst_y
, orig_dst_z
,
674 src_image
, src_res
, src_x
, src_y
, orig_src_z
,
675 src_width
, src_height
);
677 copy_image(pipe
, dst_res
, dst_level
, dst_x
, dst_y
, dst_z
,
678 src_res
, src_level
, &box
);
683 st_init_copy_image_functions(struct dd_function_table
*functions
)
685 functions
->CopyImageSubData
= st_CopyImageSubData
;