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