• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Advanced Micro Devices, Inc.
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  * 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:
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 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.
22  *
23  */
24 
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"
30 
31 #include "util/u_box.h"
32 #include "util/u_format.h"
33 #include "util/u_inlines.h"
34 
35 
36 /**
37  * Return an equivalent canonical format without "X" channels.
38  *
39  * Copying between incompatible formats is easier when the format is
40  * canonicalized, meaning that it is in a standard form.
41  *
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.
45  *
46  * If it's not an array format, return a memcpy-equivalent array format.
47  *
48  * The key feature is that swizzled versions of formats of the same
49  * component size always return the same component type.
50  *
51  * X returns A.
52  * Luminance, intensity, alpha, depth, stencil, and 8-bit and 16-bit packed
53  * formats are not supported. (same as ARB_copy_image)
54  */
55 static enum pipe_format
get_canonical_format(enum pipe_format format)56 get_canonical_format(enum pipe_format format)
57 {
58    const struct util_format_description *desc =
59       util_format_description(format);
60 
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);
65 
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);
75 
76       return PIPE_FORMAT_NONE;
77    }
78 
79 #define RETURN_FOR_SWIZZLE1(x, format) \
80    if (desc->swizzle[0] == PIPE_SWIZZLE_##x) \
81       return format
82 
83 #define RETURN_FOR_SWIZZLE2(x, y, format) \
84    if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
85        desc->swizzle[1] == PIPE_SWIZZLE_##y) \
86       return format
87 
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) \
92       return format
93 
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) \
99       return format
100 
101    /* Array formats. */
102    if (desc->is_array) {
103       switch (desc->nr_channels) {
104       case 1:
105          switch (desc->channel[0].size) {
106          case 8:
107             RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R8_UINT);
108             break;
109 
110          case 16:
111             RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R16_UINT);
112             break;
113 
114          case 32:
115             RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R32_UINT);
116             break;
117          }
118          break;
119 
120       case 2:
121          switch (desc->channel[0].size) {
122          case 8:
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.
125              */
126             RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R8G8_UNORM);
127             RETURN_FOR_SWIZZLE2(Y, X, PIPE_FORMAT_G8R8_UNORM);
128             break;
129 
130          case 16:
131             RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R16G16_UNORM);
132             RETURN_FOR_SWIZZLE2(Y, X, PIPE_FORMAT_G16R16_UNORM);
133             break;
134 
135          case 32:
136             RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R32G32_UINT);
137             break;
138          }
139          break;
140 
141       case 3:
142          switch (desc->channel[0].size) {
143          case 8:
144             RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R8G8B8_UINT);
145             break;
146 
147          case 16:
148             RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R16G16B16_UINT);
149             break;
150 
151          case 32:
152             RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R32G32B32_UINT);
153             break;
154          }
155          break;
156 
157       case 4:
158          switch (desc->channel[0].size) {
159          case 8:
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);
168             break;
169 
170          case 16:
171             RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R16G16B16A16_UINT);
172             RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R16G16B16A16_UINT);
173             break;
174 
175          case 32:
176             RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R32G32B32A32_UINT);
177             RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R32G32B32A32_UINT);
178             break;
179          }
180       }
181 
182       assert(!"unknown array format");
183       return PIPE_FORMAT_NONE;
184    }
185 
186    assert(!"unknown packed format");
187    return PIPE_FORMAT_NONE;
188 }
189 
190 /**
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.
193  */
194 static bool
has_identity_swizzle(const struct util_format_description * desc)195 has_identity_swizzle(const struct util_format_description *desc)
196 {
197    int i;
198 
199    for (i = 0; i < desc->nr_channels; i++)
200       if (desc->swizzle[i] != PIPE_SWIZZLE_X + i)
201          return false;
202 
203    return true;
204 }
205 
206 /**
207  * Return a canonical format for the given bits and channel size.
208  */
209 static enum pipe_format
canonical_format_from_bits(unsigned bits,unsigned channel_size)210 canonical_format_from_bits(unsigned bits, unsigned channel_size)
211 {
212    switch (bits) {
213    case 8:
214       if (channel_size == 8)
215          return get_canonical_format(PIPE_FORMAT_R8_UINT);
216       break;
217 
218    case 16:
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);
223       break;
224 
225    case 32:
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);
232       break;
233 
234    case 64:
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);
239       break;
240 
241    case 128:
242       if (channel_size == 32)
243          return get_canonical_format(PIPE_FORMAT_R32G32B32A32_UINT);
244       break;
245    }
246 
247    assert(!"impossible format");
248    return PIPE_FORMAT_NONE;
249 }
250 
251 static void
blit(struct pipe_context * pipe,struct pipe_resource * dst,enum pipe_format dst_format,unsigned dst_level,unsigned dstx,unsigned dsty,unsigned dstz,struct pipe_resource * src,enum pipe_format src_format,unsigned src_level,const struct pipe_box * src_box)252 blit(struct pipe_context *pipe,
253      struct pipe_resource *dst,
254      enum pipe_format dst_format,
255      unsigned dst_level,
256      unsigned dstx, unsigned dsty, unsigned dstz,
257      struct pipe_resource *src,
258      enum pipe_format src_format,
259      unsigned src_level,
260      const struct pipe_box *src_box)
261 {
262    struct pipe_blit_info blit = {{0}};
263 
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;
275 
276    pipe->blit(pipe, &blit);
277 }
278 
279 static void
swizzled_copy(struct pipe_context * pipe,struct pipe_resource * dst,unsigned dst_level,unsigned dstx,unsigned dsty,unsigned dstz,struct pipe_resource * src,unsigned src_level,const struct pipe_box * src_box)280 swizzled_copy(struct pipe_context *pipe,
281               struct pipe_resource *dst,
282               unsigned dst_level,
283               unsigned dstx, unsigned dsty, unsigned dstz,
284               struct pipe_resource *src,
285               unsigned src_level,
286               const struct pipe_box *src_box)
287 {
288    const struct util_format_description *src_desc, *dst_desc;
289    unsigned bits;
290    enum pipe_format blit_src_format, blit_dst_format;
291 
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.
297     */
298    blit_src_format = get_canonical_format(src->format);
299    blit_dst_format = get_canonical_format(dst->format);
300 
301    assert(blit_src_format != PIPE_FORMAT_NONE);
302    assert(blit_dst_format != PIPE_FORMAT_NONE);
303 
304    src_desc = util_format_description(blit_src_format);
305    dst_desc = util_format_description(blit_dst_format);
306 
307    assert(src_desc->block.bits == dst_desc->block.bits);
308    bits = src_desc->block.bits;
309 
310    if (dst_desc->channel[0].size == src_desc->channel[0].size) {
311       /* Only the swizzle is different, which means we can just blit,
312        * e.g. RGBA -> BGRA.
313        */
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
318        */
319       blit_src_format =
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
325        */
326       blit_dst_format =
327          canonical_format_from_bits(bits, src_desc->channel[0].size);
328    } else {
329       assert(!"This should have been handled by handle_complex_copy.");
330       return;
331    }
332 
333    blit(pipe, dst, blit_dst_format, dst_level, dstx, dsty, dstz,
334         src, blit_src_format, src_level, src_box);
335 }
336 
337 static bool
same_size_and_swizzle(const struct util_format_description * d1,const struct util_format_description * d2)338 same_size_and_swizzle(const struct util_format_description *d1,
339                       const struct util_format_description *d2)
340 {
341    int i;
342 
343    if (d1->layout != d2->layout ||
344        d1->nr_channels != d2->nr_channels ||
345        d1->is_array != d2->is_array)
346       return false;
347 
348    for (i = 0; i < d1->nr_channels; i++) {
349       if (d1->channel[i].size != d2->channel[i].size)
350          return false;
351 
352       if (d1->swizzle[i] <= PIPE_SWIZZLE_W &&
353           d2->swizzle[i] <= PIPE_SWIZZLE_W &&
354           d1->swizzle[i] != d2->swizzle[i])
355          return false;
356    }
357 
358    return true;
359 }
360 
361 static struct pipe_resource *
create_texture(struct pipe_screen * screen,enum pipe_format format,unsigned nr_samples,unsigned width,unsigned height,unsigned depth)362 create_texture(struct pipe_screen *screen, enum pipe_format format,
363                unsigned nr_samples,
364                unsigned width, unsigned height, unsigned depth)
365 {
366    struct pipe_resource templ;
367 
368    memset(&templ, 0, sizeof(templ));
369    templ.format = format;
370    templ.width0 = width;
371    templ.height0 = height;
372    templ.depth0 = 1;
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;
377 
378    if (depth > 1)
379       templ.target = PIPE_TEXTURE_2D_ARRAY;
380    else
381       templ.target = PIPE_TEXTURE_2D;
382 
383    return screen->resource_create(screen, &templ);
384 }
385 
386 /**
387  * Handle complex format conversions using 2 blits with a temporary texture
388  * in between, e.g. blitting from B10G10R10A2 to G16R16.
389  *
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.
396  */
397 static bool
handle_complex_copy(struct pipe_context * pipe,struct pipe_resource * dst,unsigned dst_level,unsigned dstx,unsigned dsty,unsigned dstz,struct pipe_resource * src,unsigned src_level,const struct pipe_box * src_box,enum pipe_format noncanon_format,enum pipe_format canon_format)398 handle_complex_copy(struct pipe_context *pipe,
399                     struct pipe_resource *dst,
400                     unsigned dst_level,
401                     unsigned dstx, unsigned dsty, unsigned dstz,
402                     struct pipe_resource *src,
403                     unsigned src_level,
404                     const struct pipe_box *src_box,
405                     enum pipe_format noncanon_format,
406                     enum pipe_format canon_format)
407 {
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;
412    bool src_is_canon;
413    bool src_is_noncanon;
414    bool dst_is_canon;
415    bool dst_is_noncanon;
416 
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);
421 
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);
426 
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);
432          return true;
433       }
434 
435       /* Simple case - only types and swizzles differ. */
436       if (dst_is_canon) {
437          blit(pipe, dst, canon_format, dst_level, dstx, dsty, dstz, src,
438               noncanon_format, src_level, src_box);
439          return true;
440       }
441 
442       /* Use the temporary texture. Src is converted to a canonical format,
443        * then proceed the generic swizzled_copy.
444        */
445       temp = create_texture(pipe->screen, canon_format, src->nr_samples,
446                             src_box->width,
447                             src_box->height, src_box->depth);
448 
449       u_box_3d(0, 0, 0, src_box->width, src_box->height, src_box->depth,
450                &temp_box);
451 
452       blit(pipe, temp, canon_format, 0, 0, 0, 0, src, noncanon_format,
453            src_level, src_box);
454       swizzled_copy(pipe, dst, dst_level, dstx, dsty, dstz, temp, 0,
455                     &temp_box);
456       pipe_resource_reference(&temp, NULL);
457       return true;
458    }
459 
460    if (dst_is_noncanon) {
461       /* Simple case - only types and swizzles differ. */
462       if (src_is_canon) {
463          blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, src,
464               canon_format, src_level, src_box);
465          return true;
466       }
467 
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,
471                             src_box->width,
472                             src_box->height, src_box->depth);
473 
474       u_box_3d(0, 0, 0, src_box->width, src_box->height, src_box->depth,
475                &temp_box);
476 
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);
481       return true;
482    }
483 
484    return false;
485 }
486 
487 static void
copy_image(struct pipe_context * pipe,struct pipe_resource * dst,unsigned dst_level,unsigned dstx,unsigned dsty,unsigned dstz,struct pipe_resource * src,unsigned src_level,const struct pipe_box * src_box)488 copy_image(struct pipe_context *pipe,
489            struct pipe_resource *dst,
490            unsigned dst_level,
491            unsigned dstx, unsigned dsty, unsigned dstz,
492            struct pipe_resource *src,
493            unsigned src_level,
494            const struct pipe_box *src_box)
495 {
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);
501       return;
502    }
503 
504    /* Copying to/from B10G10R10*2 needs 2 blits with R10G10B10A2
505     * as a temporary texture in between.
506     */
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))
510       return;
511 
512    /* Copying to/from G8R8 needs 2 blits with R8G8 as a temporary texture
513     * in between.
514     */
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))
518       return;
519 
520    /* Copying to/from G16R16 needs 2 blits with R16G16 as a temporary texture
521     * in between.
522     */
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))
526       return;
527 
528    /* Only allow non-identity swizzling on RGBA8 formats. */
529 
530    /* Simple copy, memcpy with swizzling, no format conversion. */
531    swizzled_copy(pipe, dst, dst_level, dstx, dsty, dstz, src, src_level,
532                  src_box);
533 }
534 
535 /* Note, the only allowable compressed format for this function is ETC */
536 static void
fallback_copy_image(struct st_context * st,struct gl_texture_image * dst_image,struct pipe_resource * dst_res,int dst_x,int dst_y,int dst_z,struct gl_texture_image * src_image,struct pipe_resource * src_res,int src_x,int src_y,int src_z,int src_w,int src_h)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)
545 {
546    uint8_t *dst, *src;
547    int dst_stride, src_stride;
548    struct pipe_transfer *dst_transfer, *src_transfer;
549    unsigned line_bytes;
550 
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);
553 
554    unsigned dst_w = src_w;
555    unsigned dst_h = src_h;
556    unsigned lines = src_h;
557 
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) {
562       dst_w *= 4;
563       dst_h *= 4;
564    }
565    if (src_is_compressed) {
566       lines = DIV_ROUND_UP(lines, 4);
567    }
568 
569    if (src_image)
570       line_bytes = _mesa_format_row_stride(src_image->TexFormat, src_w);
571    else
572       line_bytes = _mesa_format_row_stride(dst_image->TexFormat, dst_w);
573 
574    if (dst_image) {
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);
579    } else {
580       dst = pipe_transfer_map(st->pipe, dst_res, 0, dst_z,
581                               PIPE_TRANSFER_WRITE,
582                               dst_x, dst_y, dst_w, dst_h,
583                               &dst_transfer);
584       dst_stride = dst_transfer->stride;
585    }
586 
587    if (src_image) {
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);
592    } else {
593       src = pipe_transfer_map(st->pipe, src_res, 0, src_z,
594                               PIPE_TRANSFER_READ,
595                               src_x, src_y, src_w, src_h,
596                               &src_transfer);
597       src_stride = src_transfer->stride;
598    }
599 
600    for (int y = 0; y < lines; y++) {
601       memcpy(dst, src, line_bytes);
602       dst += dst_stride;
603       src += src_stride;
604    }
605 
606    if (dst_image) {
607       st->ctx->Driver.UnmapTextureImage(st->ctx, dst_image, dst_z);
608    } else {
609       pipe_transfer_unmap(st->pipe, dst_transfer);
610    }
611 
612    if (src_image) {
613       st->ctx->Driver.UnmapTextureImage(st->ctx, src_image, src_z);
614    } else {
615       pipe_transfer_unmap(st->pipe, src_transfer);
616    }
617 }
618 
619 static void
st_CopyImageSubData(struct gl_context * ctx,struct gl_texture_image * src_image,struct gl_renderbuffer * src_renderbuffer,int src_x,int src_y,int src_z,struct gl_texture_image * dst_image,struct gl_renderbuffer * dst_renderbuffer,int dst_x,int dst_y,int dst_z,int src_width,int src_height)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)
628 {
629    struct st_context *st = st_context(ctx);
630    struct pipe_context *pipe = st->pipe;
631    struct pipe_resource *src_res, *dst_res;
632    struct pipe_box box;
633    int src_level, dst_level;
634    int orig_src_z = src_z, orig_dst_z = dst_z;
635 
636    st_flush_bitmap_cache(st);
637    st_invalidate_readpix_cache(st);
638 
639    if (src_image) {
640       struct st_texture_image *src = st_texture_image(src_image);
641       src_res = src->pt;
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;
647       }
648    } else {
649       struct st_renderbuffer *src = st_renderbuffer(src_renderbuffer);
650       src_res = src->texture;
651       src_level = 0;
652    }
653 
654    if (dst_image) {
655       struct st_texture_image *dst = st_texture_image(dst_image);
656       dst_res = dst->pt;
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;
662       }
663    } else {
664       struct st_renderbuffer *dst = st_renderbuffer(dst_renderbuffer);
665       dst_res = dst->texture;
666       dst_level = 0;
667    }
668 
669    u_box_2d_zslice(src_x, src_y, src_z, src_width, src_height, &box);
670 
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);
676    } else {
677       copy_image(pipe, dst_res, dst_level, dst_x, dst_y, dst_z,
678                  src_res, src_level, &box);
679    }
680 }
681 
682 void
st_init_copy_image_functions(struct dd_function_table * functions)683 st_init_copy_image_functions(struct dd_function_table *functions)
684 {
685    functions->CopyImageSubData = st_CopyImageSubData;
686 }
687