xref: /aosp_15_r20/external/mesa3d/src/mesa/state_tracker/st_cb_copyimage.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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_texture.h"
29 #include "state_tracker/st_texture.h"
30 #include "state_tracker/st_util.h"
31 
32 #include "util/box.h"
33 #include "util/format/u_format.h"
34 #include "util/u_inlines.h"
35 
36 
37 /**
38  * Return an equivalent canonical format without "X" channels.
39  *
40  * Copying between incompatible formats is easier when the format is
41  * canonicalized, meaning that it is in a standard form.
42  *
43  * The returned format has the same component sizes and swizzles as
44  * the source format, the type is changed to UINT or UNORM, depending on
45  * which one has the most swizzle combinations in their group.
46  *
47  * If it's not an array format, return a memcpy-equivalent array format.
48  *
49  * The key feature is that swizzled versions of formats of the same
50  * component size always return the same component type.
51  *
52  * X returns A.
53  * Luminance, intensity, alpha, depth, stencil, and 8-bit and 16-bit packed
54  * formats are not supported. (same as ARB_copy_image)
55  */
56 static enum pipe_format
get_canonical_format(struct pipe_screen * screen,enum pipe_format format)57 get_canonical_format(struct pipe_screen *screen,
58                      enum pipe_format format)
59 {
60    const struct util_format_description *desc =
61       util_format_description(format);
62 
63    /* Packed formats. Return the equivalent array format. */
64    if (format == PIPE_FORMAT_R11G11B10_FLOAT ||
65        format == PIPE_FORMAT_R9G9B9E5_FLOAT)
66       return get_canonical_format(screen, PIPE_FORMAT_R8G8B8A8_UINT);
67 
68    if (desc->nr_channels == 4 &&
69        desc->channel[0].size == 10 &&
70        desc->channel[1].size == 10 &&
71        desc->channel[2].size == 10 &&
72        desc->channel[3].size == 2) {
73       if (desc->swizzle[0] == PIPE_SWIZZLE_X &&
74           desc->swizzle[1] == PIPE_SWIZZLE_Y &&
75           desc->swizzle[2] == PIPE_SWIZZLE_Z)
76          return get_canonical_format(screen, PIPE_FORMAT_R8G8B8A8_UINT);
77 
78       return PIPE_FORMAT_NONE;
79    }
80 
81 #define RETURN_FOR_SWIZZLE1(x, format) \
82    if (desc->swizzle[0] == PIPE_SWIZZLE_##x) \
83       return (screen->get_canonical_format ? \
84               screen->get_canonical_format(screen, format) : \
85               format)
86 
87 #define RETURN_FOR_SWIZZLE2(x, y, format) \
88    if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
89        desc->swizzle[1] == PIPE_SWIZZLE_##y) \
90       return (screen->get_canonical_format ? \
91               screen->get_canonical_format(screen, format) : \
92               format)
93 
94 #define RETURN_FOR_SWIZZLE3(x, y, z, format) \
95    if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
96        desc->swizzle[1] == PIPE_SWIZZLE_##y && \
97        desc->swizzle[2] == PIPE_SWIZZLE_##z) \
98       return (screen->get_canonical_format ? \
99               screen->get_canonical_format(screen, format) : \
100               format)
101 
102 #define RETURN_FOR_SWIZZLE4(x, y, z, w, format) \
103    if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
104        desc->swizzle[1] == PIPE_SWIZZLE_##y && \
105        desc->swizzle[2] == PIPE_SWIZZLE_##z && \
106        desc->swizzle[3] == PIPE_SWIZZLE_##w) \
107       return (screen->get_canonical_format ? \
108               screen->get_canonical_format(screen, format) : \
109               format)
110 
111    /* Array formats. */
112    if (desc->is_array) {
113       switch (desc->nr_channels) {
114       case 1:
115          switch (desc->channel[0].size) {
116          case 8:
117             RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R8_UINT);
118             break;
119 
120          case 16:
121             RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R16_UINT);
122             break;
123 
124          case 32:
125             RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R32_UINT);
126             break;
127          }
128          break;
129 
130       case 2:
131          switch (desc->channel[0].size) {
132          case 8:
133             /* All formats in each group must be of the same type.
134              * We can't use UINT for R8G8 while using UNORM for G8R8.
135              */
136             RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R8G8_UNORM);
137             RETURN_FOR_SWIZZLE2(Y, X, PIPE_FORMAT_G8R8_UNORM);
138             break;
139 
140          case 16:
141             RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R16G16_UNORM);
142             RETURN_FOR_SWIZZLE2(Y, X, PIPE_FORMAT_G16R16_UNORM);
143             break;
144 
145          case 32:
146             RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R32G32_UINT);
147             break;
148          }
149          break;
150 
151       case 3:
152          switch (desc->channel[0].size) {
153          case 8:
154             RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R8G8B8_UINT);
155             break;
156 
157          case 16:
158             RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R16G16B16_UINT);
159             break;
160 
161          case 32:
162             RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R32G32B32_UINT);
163             break;
164          }
165          break;
166 
167       case 4:
168          switch (desc->channel[0].size) {
169          case 8:
170             RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R8G8B8A8_UNORM);
171             RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R8G8B8A8_UNORM);
172             RETURN_FOR_SWIZZLE4(Z, Y, X, W, PIPE_FORMAT_B8G8R8A8_UNORM);
173             RETURN_FOR_SWIZZLE4(Z, Y, X, 1, PIPE_FORMAT_B8G8R8A8_UNORM);
174             RETURN_FOR_SWIZZLE4(W, Z, Y, X, PIPE_FORMAT_A8B8G8R8_UNORM);
175             RETURN_FOR_SWIZZLE4(W, Z, Y, 1, PIPE_FORMAT_A8B8G8R8_UNORM);
176             RETURN_FOR_SWIZZLE4(Y, Z, W, X, PIPE_FORMAT_A8R8G8B8_UNORM);
177             RETURN_FOR_SWIZZLE4(Y, Z, W, 1, PIPE_FORMAT_A8R8G8B8_UNORM);
178             break;
179 
180          case 16:
181             RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R16G16B16A16_UINT);
182             RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R16G16B16A16_UINT);
183             break;
184 
185          case 32:
186             RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R32G32B32A32_UINT);
187             RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R32G32B32A32_UINT);
188             break;
189          }
190       }
191 
192       assert(!"unknown array format");
193       return PIPE_FORMAT_NONE;
194    }
195 
196    assert(!"unknown packed format");
197    return PIPE_FORMAT_NONE;
198 }
199 
200 /**
201  * Return true if the swizzle is XYZW in case of a 4-channel format,
202  * XY in case of a 2-channel format, or X in case of a 1-channel format.
203  */
204 static bool
has_identity_swizzle(const struct util_format_description * desc)205 has_identity_swizzle(const struct util_format_description *desc)
206 {
207    int i;
208 
209    for (i = 0; i < desc->nr_channels; i++)
210       if (desc->swizzle[i] != PIPE_SWIZZLE_X + i)
211          return false;
212 
213    return true;
214 }
215 
216 /**
217  * Return a canonical format for the given bits and channel size.
218  */
219 static enum pipe_format
canonical_format_from_bits(struct pipe_screen * screen,unsigned bits,unsigned channel_size)220 canonical_format_from_bits(struct pipe_screen *screen,
221                            unsigned bits,
222                            unsigned channel_size)
223 {
224    switch (bits) {
225    case 8:
226       if (channel_size == 8)
227          return get_canonical_format(screen, PIPE_FORMAT_R8_UINT);
228       break;
229 
230    case 16:
231       if (channel_size == 8)
232          return get_canonical_format(screen, PIPE_FORMAT_R8G8_UINT);
233       if (channel_size == 16)
234          return get_canonical_format(screen, PIPE_FORMAT_R16_UINT);
235       break;
236 
237    case 32:
238       if (channel_size == 8)
239          return get_canonical_format(screen, PIPE_FORMAT_R8G8B8A8_UINT);
240       if (channel_size == 16)
241          return get_canonical_format(screen, PIPE_FORMAT_R16G16_UINT);
242       if (channel_size == 32)
243          return get_canonical_format(screen, PIPE_FORMAT_R32_UINT);
244       break;
245 
246    case 64:
247       if (channel_size == 16)
248          return get_canonical_format(screen, PIPE_FORMAT_R16G16B16A16_UINT);
249       if (channel_size == 32)
250          return get_canonical_format(screen, PIPE_FORMAT_R32G32_UINT);
251       break;
252 
253    case 128:
254       if (channel_size == 32)
255          return get_canonical_format(screen, PIPE_FORMAT_R32G32B32A32_UINT);
256       break;
257    }
258 
259    assert(!"impossible format");
260    return PIPE_FORMAT_NONE;
261 }
262 
263 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)264 blit(struct pipe_context *pipe,
265      struct pipe_resource *dst,
266      enum pipe_format dst_format,
267      unsigned dst_level,
268      unsigned dstx, unsigned dsty, unsigned dstz,
269      struct pipe_resource *src,
270      enum pipe_format src_format,
271      unsigned src_level,
272      const struct pipe_box *src_box)
273 {
274    struct pipe_blit_info blit = {{0}};
275 
276    blit.src.resource = src;
277    blit.dst.resource = dst;
278    blit.src.format = src_format;
279    blit.dst.format = dst_format;
280    blit.src.level = src_level;
281    blit.dst.level = dst_level;
282    blit.src.box = *src_box;
283    u_box_3d(dstx, dsty, dstz, src_box->width, src_box->height,
284             src_box->depth, &blit.dst.box);
285    if (util_format_is_depth_or_stencil(dst_format))
286       blit.mask = PIPE_MASK_ZS;
287    else
288       blit.mask = PIPE_MASK_RGBA;
289    blit.filter = PIPE_TEX_FILTER_NEAREST;
290 
291    pipe->blit(pipe, &blit);
292 }
293 
294 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)295 swizzled_copy(struct pipe_context *pipe,
296               struct pipe_resource *dst,
297               unsigned dst_level,
298               unsigned dstx, unsigned dsty, unsigned dstz,
299               struct pipe_resource *src,
300               unsigned src_level,
301               const struct pipe_box *src_box)
302 {
303    const struct util_format_description *src_desc, *dst_desc;
304    unsigned bits;
305    enum pipe_format blit_src_format, blit_dst_format;
306 
307    /* Get equivalent canonical formats. Those are always array formats and
308     * copying between compatible canonical formats behaves either like
309     * memcpy or like swizzled memcpy. The idea is that we won't have to care
310     * about the channel type from this point on.
311     * Only the swizzle and channel size.
312     */
313    blit_src_format = get_canonical_format(pipe->screen, src->format);
314    blit_dst_format = get_canonical_format(pipe->screen, dst->format);
315 
316    assert(blit_src_format != PIPE_FORMAT_NONE);
317    assert(blit_dst_format != PIPE_FORMAT_NONE);
318 
319    src_desc = util_format_description(blit_src_format);
320    dst_desc = util_format_description(blit_dst_format);
321 
322    assert(src_desc->block.bits == dst_desc->block.bits);
323    bits = src_desc->block.bits;
324 
325    if (dst_desc->channel[0].size == src_desc->channel[0].size) {
326       /* Only the swizzle is different, which means we can just blit,
327        * e.g. RGBA -> BGRA.
328        */
329    } else if (has_identity_swizzle(src_desc)) {
330       /* Src is unswizzled and dst can be swizzled, so src is typecast
331        * to an equivalent dst-compatible format.
332        * e.g. R32 -> BGRA8 is realized as RGBA8 -> BGRA8
333        */
334       blit_src_format =
335          canonical_format_from_bits(pipe->screen, bits, dst_desc->channel[0].size);
336    } else if (has_identity_swizzle(dst_desc)) {
337       /* Dst is unswizzled and src can be swizzled, so dst is typecast
338        * to an equivalent src-compatible format.
339        * e.g. BGRA8 -> R32 is realized as BGRA8 -> RGBA8
340        */
341       blit_dst_format =
342          canonical_format_from_bits(pipe->screen, bits, src_desc->channel[0].size);
343    } else {
344       assert(!"This should have been handled by handle_complex_copy.");
345       return;
346    }
347 
348    blit(pipe, dst, blit_dst_format, dst_level, dstx, dsty, dstz,
349         src, blit_src_format, src_level, src_box);
350 }
351 
352 static bool
same_size_and_swizzle(const struct util_format_description * d1,const struct util_format_description * d2)353 same_size_and_swizzle(const struct util_format_description *d1,
354                       const struct util_format_description *d2)
355 {
356    int i;
357 
358    if (d1->layout != d2->layout ||
359        d1->nr_channels != d2->nr_channels ||
360        d1->is_array != d2->is_array)
361       return false;
362 
363    for (i = 0; i < d1->nr_channels; i++) {
364       if (d1->channel[i].size != d2->channel[i].size)
365          return false;
366 
367       if (d1->swizzle[i] <= PIPE_SWIZZLE_W &&
368           d2->swizzle[i] <= PIPE_SWIZZLE_W &&
369           d1->swizzle[i] != d2->swizzle[i])
370          return false;
371    }
372 
373    return true;
374 }
375 
376 static struct pipe_resource *
create_texture(struct pipe_screen * screen,enum pipe_format format,unsigned nr_samples,unsigned nr_storage_samples,unsigned width,unsigned height,unsigned depth)377 create_texture(struct pipe_screen *screen, enum pipe_format format,
378                unsigned nr_samples, unsigned nr_storage_samples,
379                unsigned width, unsigned height, unsigned depth)
380 {
381    struct pipe_resource templ;
382 
383    memset(&templ, 0, sizeof(templ));
384    templ.format = format;
385    templ.width0 = width;
386    templ.height0 = height;
387    templ.depth0 = 1;
388    templ.array_size = depth;
389    templ.nr_samples = nr_samples;
390    templ.nr_storage_samples = nr_storage_samples;
391    templ.usage = PIPE_USAGE_DEFAULT;
392    templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
393 
394    if (depth > 1)
395       templ.target = PIPE_TEXTURE_2D_ARRAY;
396    else
397       templ.target = PIPE_TEXTURE_2D;
398 
399    return screen->resource_create(screen, &templ);
400 }
401 
402 /**
403  * Handle complex format conversions using 2 blits with a temporary texture
404  * in between, e.g. blitting from B10G10R10A2 to G16R16.
405  *
406  * This example is implemented this way:
407  * 1) First, blit from B10G10R10A2 to R10G10B10A2, which is canonical, so it
408  *    can be reinterpreted as a different canonical format of the same bpp,
409  *    such as R16G16. This blit only swaps R and B 10-bit components.
410  * 2) Finally, blit the result, which is R10G10B10A2, as R16G16 to G16R16.
411  *    This blit only swaps R and G 16-bit components.
412  */
413 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)414 handle_complex_copy(struct pipe_context *pipe,
415                     struct pipe_resource *dst,
416                     unsigned dst_level,
417                     unsigned dstx, unsigned dsty, unsigned dstz,
418                     struct pipe_resource *src,
419                     unsigned src_level,
420                     const struct pipe_box *src_box,
421                     enum pipe_format noncanon_format,
422                     enum pipe_format canon_format)
423 {
424    struct pipe_box temp_box;
425    struct pipe_resource *temp = NULL;
426    const struct util_format_description *src_desc, *dst_desc;
427    const struct util_format_description *canon_desc, *noncanon_desc;
428    bool src_is_canon;
429    bool src_is_noncanon;
430    bool dst_is_canon;
431    bool dst_is_noncanon;
432 
433    src_desc = util_format_description(src->format);
434    dst_desc = util_format_description(dst->format);
435    canon_desc = util_format_description(canon_format);
436    noncanon_desc = util_format_description(noncanon_format);
437 
438    src_is_canon = same_size_and_swizzle(src_desc, canon_desc);
439    dst_is_canon = same_size_and_swizzle(dst_desc, canon_desc);
440    src_is_noncanon = same_size_and_swizzle(src_desc, noncanon_desc);
441    dst_is_noncanon = same_size_and_swizzle(dst_desc, noncanon_desc);
442 
443    if (src_is_noncanon) {
444       /* Simple case - only types differ (e.g. UNORM and UINT). */
445       if (dst_is_noncanon) {
446          blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, src,
447               noncanon_format, src_level, src_box);
448          return true;
449       }
450 
451       /* Simple case - only types and swizzles differ. */
452       if (dst_is_canon) {
453          blit(pipe, dst, canon_format, dst_level, dstx, dsty, dstz, src,
454               noncanon_format, src_level, src_box);
455          return true;
456       }
457 
458       /* Use the temporary texture. Src is converted to a canonical format,
459        * then proceed the generic swizzled_copy.
460        */
461       temp = create_texture(pipe->screen, canon_format, src->nr_samples,
462                             src->nr_storage_samples, src_box->width,
463                             src_box->height, src_box->depth);
464 
465       u_box_3d(0, 0, 0, src_box->width, src_box->height, src_box->depth,
466                &temp_box);
467 
468       blit(pipe, temp, canon_format, 0, 0, 0, 0, src, noncanon_format,
469            src_level, src_box);
470       swizzled_copy(pipe, dst, dst_level, dstx, dsty, dstz, temp, 0,
471                     &temp_box);
472       pipe_resource_reference(&temp, NULL);
473       return true;
474    }
475 
476    if (dst_is_noncanon) {
477       /* Simple case - only types and swizzles differ. */
478       if (src_is_canon) {
479          blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, src,
480               canon_format, src_level, src_box);
481          return true;
482       }
483 
484       /* Use the temporary texture. First, use the generic copy, but use
485        * a canonical format in the destination. Then convert */
486       temp = create_texture(pipe->screen, canon_format, dst->nr_samples,
487                             dst->nr_storage_samples, src_box->width,
488                             src_box->height, src_box->depth);
489 
490       u_box_3d(0, 0, 0, src_box->width, src_box->height, src_box->depth,
491                &temp_box);
492 
493       swizzled_copy(pipe, temp, 0, 0, 0, 0, src, src_level, src_box);
494       blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, temp,
495            canon_format, 0, &temp_box);
496       pipe_resource_reference(&temp, NULL);
497       return true;
498    }
499 
500    return false;
501 }
502 
503 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)504 copy_image(struct pipe_context *pipe,
505            struct pipe_resource *dst,
506            unsigned dst_level,
507            unsigned dstx, unsigned dsty, unsigned dstz,
508            struct pipe_resource *src,
509            unsigned src_level,
510            const struct pipe_box *src_box)
511 {
512    if (src->format == dst->format ||
513        util_format_is_compressed(src->format) ||
514        util_format_is_compressed(dst->format)) {
515 
516       if (src->nr_samples <= 1 && dst->nr_samples <= 1) {
517          pipe->resource_copy_region(pipe, dst, dst_level, dstx, dsty, dstz,
518                                     src, src_level, src_box);
519       } else {
520          blit(pipe, dst, dst->format, dst_level, dstx, dsty, dstz,
521               src, src->format, src_level, src_box);
522       }
523       return;
524    }
525 
526    /* Copying to/from B10G10R10*2 needs 2 blits with R10G10B10A2
527     * as a temporary texture in between.
528     */
529    if (handle_complex_copy(pipe, dst, dst_level, dstx, dsty, dstz, src,
530                            src_level, src_box, PIPE_FORMAT_B10G10R10A2_UINT,
531                            PIPE_FORMAT_R10G10B10A2_UINT))
532       return;
533 
534    /* Copying to/from G8R8 needs 2 blits with R8G8 as a temporary texture
535     * in between.
536     */
537    if (handle_complex_copy(pipe, dst, dst_level, dstx, dsty, dstz, src,
538                            src_level, src_box, PIPE_FORMAT_G8R8_UNORM,
539                            PIPE_FORMAT_R8G8_UNORM))
540       return;
541 
542    /* Copying to/from G16R16 needs 2 blits with R16G16 as a temporary texture
543     * in between.
544     */
545    if (handle_complex_copy(pipe, dst, dst_level, dstx, dsty, dstz, src,
546                            src_level, src_box, PIPE_FORMAT_G16R16_UNORM,
547                            PIPE_FORMAT_R16G16_UNORM))
548       return;
549 
550    /* Only allow non-identity swizzling on RGBA8 formats. */
551 
552    /* Simple copy, memcpy with swizzling, no format conversion. */
553    swizzled_copy(pipe, dst, dst_level, dstx, dsty, dstz, src, src_level,
554                  src_box);
555 }
556 
557 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)558 fallback_copy_image(struct st_context *st,
559                     struct gl_texture_image *dst_image,
560                     struct pipe_resource *dst_res,
561                     int dst_x, int dst_y, int dst_z,
562                     struct gl_texture_image *src_image,
563                     struct pipe_resource *src_res,
564                     int src_x, int src_y, int src_z,
565                     int src_w, int src_h)
566 {
567    uint8_t *dst, *src;
568    int dst_stride, src_stride;
569    struct pipe_transfer *dst_transfer, *src_transfer;
570    unsigned line_bytes;
571 
572    bool dst_is_compressed = dst_image && _mesa_is_format_compressed(dst_image->TexFormat);
573    bool src_is_compressed = src_image && _mesa_is_format_compressed(src_image->TexFormat);
574 
575    unsigned dst_blk_w = 1, dst_blk_h = 1, src_blk_w = 1, src_blk_h = 1;
576    if (dst_image)
577       _mesa_get_format_block_size(dst_image->TexFormat, &dst_blk_w, &dst_blk_h);
578    if (src_image)
579       _mesa_get_format_block_size(src_image->TexFormat, &src_blk_w, &src_blk_h);
580 
581    unsigned dst_w = src_w;
582    unsigned dst_h = src_h;
583    unsigned lines = src_h;
584 
585    if (src_is_compressed && !dst_is_compressed) {
586       dst_w = DIV_ROUND_UP(dst_w, src_blk_w);
587       dst_h = DIV_ROUND_UP(dst_h, src_blk_h);
588    } else if (!src_is_compressed && dst_is_compressed) {
589       dst_w *= dst_blk_w;
590       dst_h *= dst_blk_h;
591    }
592    if (src_is_compressed) {
593       lines = DIV_ROUND_UP(lines, src_blk_h);
594    }
595 
596    if (src_image)
597       line_bytes = _mesa_format_row_stride(src_image->TexFormat, src_w);
598    else
599       line_bytes = _mesa_format_row_stride(dst_image->TexFormat, dst_w);
600 
601    if (src_image == dst_image && src_z == dst_z) {
602       assert(dst_image != NULL);
603 
604       /* calculate bounding-box of the two rectangles */
605       int min_x = MIN2(src_x, dst_x);
606       int min_y = MIN2(src_y, dst_y);
607       int max_x = MAX2(src_x + src_w, dst_x + dst_w);
608       int max_y = MAX2(src_y + src_h, dst_y + dst_h);
609       st_MapTextureImage(
610             st->ctx, dst_image, dst_z,
611             min_x, min_y, max_x - min_x, max_y - min_y,
612             GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, &dst, &dst_stride);
613       src = dst;
614       src_stride = dst_stride;
615 
616       /* adjust pointers */
617       int format_bytes = _mesa_get_format_bytes(dst_image->TexFormat);
618       src += ((src_y - min_y) / src_blk_h) * src_stride;
619       src += ((src_x - min_x) / src_blk_w) * format_bytes;
620       dst += ((dst_y - min_y) / src_blk_h) * dst_stride;
621       dst += ((dst_x - min_x) / dst_blk_w) * format_bytes;
622    } else {
623       if (dst_image) {
624          st_MapTextureImage(
625                st->ctx, dst_image, dst_z,
626                dst_x, dst_y, dst_w, dst_h,
627                GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT,
628                &dst, &dst_stride);
629       } else {
630          dst = pipe_texture_map(st->pipe, dst_res, 0, dst_z,
631                                  PIPE_MAP_WRITE | PIPE_MAP_DISCARD_RANGE,
632                                  dst_x, dst_y, dst_w, dst_h,
633                                  &dst_transfer);
634          dst_stride = dst_transfer->stride;
635       }
636 
637       if (src_image) {
638          st_MapTextureImage(
639                st->ctx, src_image, src_z,
640                src_x, src_y, src_w, src_h,
641                GL_MAP_READ_BIT, &src, &src_stride);
642       } else {
643          src = pipe_texture_map(st->pipe, src_res, 0, src_z,
644                                  PIPE_MAP_READ,
645                                  src_x, src_y, src_w, src_h,
646                                  &src_transfer);
647          src_stride = src_transfer->stride;
648       }
649    }
650 
651    for (int y = 0; y < lines; y++) {
652       memcpy(dst, src, line_bytes);
653       dst += dst_stride;
654       src += src_stride;
655    }
656 
657    if (dst_image) {
658       st_UnmapTextureImage(st->ctx, dst_image, dst_z);
659    } else {
660       pipe_texture_unmap(st->pipe, dst_transfer);
661    }
662 
663    if (src_image) {
664       if (src_image != dst_image || src_z != dst_z)
665          st_UnmapTextureImage(st->ctx, src_image, src_z);
666    } else {
667       pipe_texture_unmap(st->pipe, src_transfer);
668    }
669 }
670 
671 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)672 st_CopyImageSubData(struct gl_context *ctx,
673                     struct gl_texture_image *src_image,
674                     struct gl_renderbuffer *src_renderbuffer,
675                     int src_x, int src_y, int src_z,
676                     struct gl_texture_image *dst_image,
677                     struct gl_renderbuffer *dst_renderbuffer,
678                     int dst_x, int dst_y, int dst_z,
679                     int src_width, int src_height)
680 {
681    struct st_context *st = st_context(ctx);
682    struct pipe_context *pipe = st->pipe;
683    struct pipe_resource *src_res, *dst_res;
684    struct pipe_box box;
685    int src_level, dst_level;
686    int orig_src_z = src_z, orig_dst_z = dst_z;
687 
688    st_flush_bitmap_cache(st);
689    st_invalidate_readpix_cache(st);
690 
691    if (src_image) {
692       struct gl_texture_image *src = src_image;
693       struct gl_texture_object *stObj = src_image->TexObject;
694       src_res = src->pt;
695       src_level = stObj->pt != src_res ? 0 : src_image->Level;
696       src_z += src_image->Face;
697       if (src_image->TexObject->Immutable) {
698          src_level += src_image->TexObject->Attrib.MinLevel;
699          src_z += src_image->TexObject->Attrib.MinLayer;
700       }
701    } else {
702       src_res = src_renderbuffer->texture;
703       src_level = 0;
704    }
705 
706    if (dst_image) {
707       struct gl_texture_image *dst = dst_image;
708       struct gl_texture_object *stObj = dst_image->TexObject;
709       dst_res = dst->pt;
710       dst_level = stObj->pt != dst_res ? 0 : dst_image->Level;
711       dst_z += dst_image->Face;
712       if (dst_image->TexObject->Immutable) {
713          dst_level += dst_image->TexObject->Attrib.MinLevel;
714          dst_z += dst_image->TexObject->Attrib.MinLayer;
715       }
716    } else {
717       dst_res = dst_renderbuffer->texture;
718       dst_level = 0;
719    }
720 
721    u_box_2d_zslice(src_x, src_y, src_z, src_width, src_height, &box);
722 
723    if ((src_image && st_compressed_format_fallback(st, src_image->TexFormat)) ||
724        (dst_image && st_compressed_format_fallback(st, dst_image->TexFormat))) {
725       fallback_copy_image(st, dst_image, dst_res, dst_x, dst_y, orig_dst_z,
726                           src_image, src_res, src_x, src_y, orig_src_z,
727                           src_width, src_height);
728    } else {
729       copy_image(pipe, dst_res, dst_level, dst_x, dst_y, dst_z,
730                  src_res, src_level, &box);
731    }
732 }
733