1 /*
2  * Copyright © 2017 Red Hat
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  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include "pipe/p_screen.h"
25 
26 #include "util/u_box.h"
27 #include "util/format/u_format.h"
28 #include "util/format/u_format_rgtc.h"
29 #include "util/format/u_format_zs.h"
30 #include "util/u_inlines.h"
31 #include "util/u_transfer_helper.h"
32 
33 
34 struct u_transfer_helper {
35    const struct u_transfer_vtbl *vtbl;
36    bool separate_z32s8; /**< separate z32 and s8 */
37    bool separate_stencil; /**< separate stencil for all formats */
38    bool fake_rgtc;
39    bool msaa_map;
40 };
41 
handle_transfer(struct pipe_resource * prsc)42 static inline bool handle_transfer(struct pipe_resource *prsc)
43 {
44    struct u_transfer_helper *helper = prsc->screen->transfer_helper;
45 
46    if (helper->vtbl->get_internal_format) {
47       enum pipe_format internal_format =
48             helper->vtbl->get_internal_format(prsc);
49       if (internal_format != prsc->format)
50          return true;
51    }
52 
53    if (helper->msaa_map && (prsc->nr_samples > 1))
54       return true;
55 
56    return false;
57 }
58 
59 /* The pipe_transfer ptr could either be the driver's, or u_transfer,
60  * depending on whether we are intervening or not.  Check handle_transfer()
61  * before dereferencing.
62  */
63 struct u_transfer {
64    struct pipe_transfer base;
65    /* Note that in case of MSAA resolve for transfer plus z32s8 or fake rgtc
66     * we end up with stacked u_transfer's.  The MSAA resolve case doesn't call
67     * helper->vtbl fxns directly, but calls back to pctx->transfer_map()/etc
68     * so the format related handling can work in conjunction with MSAA resolve.
69     */
70    struct pipe_transfer *trans;   /* driver's transfer */
71    struct pipe_transfer *trans2;  /* 2nd transfer for s8 stencil buffer in z32s8 */
72    void *ptr, *ptr2;              /* ptr to trans, and trans2 */
73    void *staging;                 /* staging buffer */
74    struct pipe_resource *ss;      /* staging resource for MSAA resolves */
75 };
76 
77 static inline struct u_transfer *
u_transfer(struct pipe_transfer * ptrans)78 u_transfer(struct pipe_transfer *ptrans)
79 {
80    debug_assert(handle_transfer(ptrans->resource));
81    return (struct u_transfer *)ptrans;
82 }
83 
84 struct pipe_resource *
u_transfer_helper_resource_create(struct pipe_screen * pscreen,const struct pipe_resource * templ)85 u_transfer_helper_resource_create(struct pipe_screen *pscreen,
86                                   const struct pipe_resource *templ)
87 {
88    struct u_transfer_helper *helper = pscreen->transfer_helper;
89    enum pipe_format format = templ->format;
90    struct pipe_resource *prsc;
91 
92    if ((helper->separate_stencil && util_format_is_depth_and_stencil(format)) ||
93        (format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT && helper->separate_z32s8)) {
94       struct pipe_resource t = *templ;
95       struct pipe_resource *stencil;
96 
97       t.format = util_format_get_depth_only(format);
98 
99       prsc = helper->vtbl->resource_create(pscreen, &t);
100       if (!prsc)
101          return NULL;
102 
103       prsc->format = format;  /* frob the format back to the "external" format */
104 
105       t.format = PIPE_FORMAT_S8_UINT;
106       stencil = helper->vtbl->resource_create(pscreen, &t);
107 
108       if (!stencil) {
109          helper->vtbl->resource_destroy(pscreen, prsc);
110          return NULL;
111       }
112 
113       helper->vtbl->set_stencil(prsc, stencil);
114    } else if ((util_format_description(format)->layout == UTIL_FORMAT_LAYOUT_RGTC) &&
115          helper->fake_rgtc) {
116       struct pipe_resource t = *templ;
117       t.format = PIPE_FORMAT_R8G8B8A8_UNORM;
118 
119       prsc = helper->vtbl->resource_create(pscreen, &t);
120       if (!prsc)
121          return NULL;
122 
123       prsc->format = format;  /* frob the format back to the "external" format */
124    } else {
125       /* normal case, no special handling: */
126       prsc = helper->vtbl->resource_create(pscreen, templ);
127       if (!prsc)
128          return NULL;
129    }
130 
131    return prsc;
132 }
133 
134 void
u_transfer_helper_resource_destroy(struct pipe_screen * pscreen,struct pipe_resource * prsc)135 u_transfer_helper_resource_destroy(struct pipe_screen *pscreen,
136                                    struct pipe_resource *prsc)
137 {
138    struct u_transfer_helper *helper = pscreen->transfer_helper;
139 
140    if (helper->vtbl->get_stencil) {
141       struct pipe_resource *stencil = helper->vtbl->get_stencil(prsc);
142 
143       pipe_resource_reference(&stencil, NULL);
144    }
145 
146    helper->vtbl->resource_destroy(pscreen, prsc);
147 }
148 
needs_pack(unsigned usage)149 static bool needs_pack(unsigned usage)
150 {
151    return (usage & PIPE_MAP_READ) &&
152       !(usage & (PIPE_MAP_DISCARD_WHOLE_RESOURCE | PIPE_MAP_DISCARD_RANGE));
153 }
154 
155 /* In the case of transfer_map of a multi-sample resource, call back into
156  * pctx->transfer_map() to map the staging resource, to handle cases of
157  * MSAA + separate_z32s8 or fake_rgtc
158  */
159 static void *
transfer_map_msaa(struct pipe_context * pctx,struct pipe_resource * prsc,unsigned level,unsigned usage,const struct pipe_box * box,struct pipe_transfer ** pptrans)160 transfer_map_msaa(struct pipe_context *pctx,
161                   struct pipe_resource *prsc,
162                   unsigned level, unsigned usage,
163                   const struct pipe_box *box,
164                   struct pipe_transfer **pptrans)
165 {
166    struct pipe_screen *pscreen = pctx->screen;
167    struct u_transfer *trans = calloc(1, sizeof(*trans));
168    if (!trans)
169       return NULL;
170    struct pipe_transfer *ptrans = &trans->base;
171 
172    pipe_resource_reference(&ptrans->resource, prsc);
173    ptrans->level = level;
174    ptrans->usage = usage;
175    ptrans->box = *box;
176 
177    struct pipe_resource tmpl = {
178          .target = prsc->target,
179          .format = prsc->format,
180          .width0 = box->width,
181          .height0 = box->height,
182          .depth0 = 1,
183          .array_size = 1,
184    };
185    trans->ss = pscreen->resource_create(pscreen, &tmpl);
186    if (!trans->ss) {
187       free(trans);
188       return NULL;
189    }
190 
191    if (needs_pack(usage)) {
192       struct pipe_blit_info blit;
193       memset(&blit, 0, sizeof(blit));
194 
195       blit.src.resource = ptrans->resource;
196       blit.src.format = ptrans->resource->format;
197       blit.src.level = ptrans->level;
198       blit.src.box = *box;
199 
200       blit.dst.resource = trans->ss;
201       blit.dst.format = trans->ss->format;
202       blit.dst.box.width = box->width;
203       blit.dst.box.height = box->height;
204       blit.dst.box.depth = 1;
205 
206       blit.mask = util_format_get_mask(prsc->format);
207       blit.filter = PIPE_TEX_FILTER_NEAREST;
208 
209       pctx->blit(pctx, &blit);
210    }
211 
212    struct pipe_box map_box = *box;
213    map_box.x = 0;
214    map_box.y = 0;
215 
216    void *ss_map = pctx->texture_map(pctx, trans->ss, 0, usage, &map_box,
217          &trans->trans);
218    if (!ss_map) {
219       free(trans);
220       return NULL;
221    }
222 
223    ptrans->stride = trans->trans->stride;
224    *pptrans = ptrans;
225    return ss_map;
226 }
227 
228 void *
u_transfer_helper_transfer_map(struct pipe_context * pctx,struct pipe_resource * prsc,unsigned level,unsigned usage,const struct pipe_box * box,struct pipe_transfer ** pptrans)229 u_transfer_helper_transfer_map(struct pipe_context *pctx,
230                                struct pipe_resource *prsc,
231                                unsigned level, unsigned usage,
232                                const struct pipe_box *box,
233                                struct pipe_transfer **pptrans)
234 {
235    struct u_transfer_helper *helper = pctx->screen->transfer_helper;
236    struct u_transfer *trans;
237    struct pipe_transfer *ptrans;
238    enum pipe_format format = prsc->format;
239    unsigned width = box->width;
240    unsigned height = box->height;
241 
242    if (!handle_transfer(prsc))
243       return helper->vtbl->transfer_map(pctx, prsc, level, usage, box, pptrans);
244 
245    if (helper->msaa_map && (prsc->nr_samples > 1))
246       return transfer_map_msaa(pctx, prsc, level, usage, box, pptrans);
247 
248    debug_assert(box->depth == 1);
249 
250    trans = calloc(1, sizeof(*trans));
251    if (!trans)
252       return NULL;
253 
254    ptrans = &trans->base;
255    pipe_resource_reference(&ptrans->resource, prsc);
256    ptrans->level = level;
257    ptrans->usage = usage;
258    ptrans->box   = *box;
259    ptrans->stride = util_format_get_stride(format, box->width);
260    ptrans->layer_stride = ptrans->stride * box->height;
261 
262    trans->staging = malloc(ptrans->layer_stride);
263    if (!trans->staging)
264       goto fail;
265 
266    trans->ptr = helper->vtbl->transfer_map(pctx, prsc, level, usage, box,
267                                            &trans->trans);
268    if (!trans->ptr)
269       goto fail;
270 
271    if (util_format_is_depth_and_stencil(prsc->format)) {
272       struct pipe_resource *stencil = helper->vtbl->get_stencil(prsc);
273       trans->ptr2 = helper->vtbl->transfer_map(pctx, stencil, level,
274                                                usage, box, &trans->trans2);
275 
276       if (needs_pack(usage)) {
277          switch (prsc->format) {
278          case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
279             util_format_z32_float_s8x24_uint_pack_z_float(trans->staging,
280                                                           ptrans->stride,
281                                                           trans->ptr,
282                                                           trans->trans->stride,
283                                                           width, height);
284             util_format_z32_float_s8x24_uint_pack_s_8uint(trans->staging,
285                                                           ptrans->stride,
286                                                           trans->ptr2,
287                                                           trans->trans2->stride,
288                                                           width, height);
289             break;
290          case PIPE_FORMAT_Z24_UNORM_S8_UINT:
291             util_format_z24_unorm_s8_uint_pack_separate(trans->staging,
292                                                         ptrans->stride,
293                                                         trans->ptr,
294                                                         trans->trans->stride,
295                                                         trans->ptr2,
296                                                         trans->trans2->stride,
297                                                         width, height);
298             break;
299          default:
300             unreachable("Unexpected format");
301          }
302       }
303    } else if (util_format_description(prsc->format)->layout == UTIL_FORMAT_LAYOUT_RGTC) {
304       if (needs_pack(usage)) {
305          switch (prsc->format) {
306          case PIPE_FORMAT_RGTC1_UNORM:
307          case PIPE_FORMAT_RGTC1_SNORM:
308          case PIPE_FORMAT_LATC1_UNORM:
309          case PIPE_FORMAT_LATC1_SNORM:
310             util_format_rgtc1_unorm_pack_rgba_8unorm(trans->staging,
311                                                      ptrans->stride,
312                                                      trans->ptr,
313                                                      trans->trans->stride,
314                                                      width, height);
315             break;
316          case PIPE_FORMAT_RGTC2_UNORM:
317          case PIPE_FORMAT_RGTC2_SNORM:
318          case PIPE_FORMAT_LATC2_UNORM:
319          case PIPE_FORMAT_LATC2_SNORM:
320             util_format_rgtc2_unorm_pack_rgba_8unorm(trans->staging,
321                                                      ptrans->stride,
322                                                      trans->ptr,
323                                                      trans->trans->stride,
324                                                      width, height);
325             break;
326          default:
327             assert(!"Unexpected format");
328             break;
329          }
330       }
331    } else {
332       unreachable("bleh");
333    }
334 
335    *pptrans = ptrans;
336    return trans->staging;
337 
338 fail:
339    if (trans->trans)
340       helper->vtbl->transfer_unmap(pctx, trans->trans);
341    if (trans->trans2)
342       helper->vtbl->transfer_unmap(pctx, trans->trans2);
343    pipe_resource_reference(&ptrans->resource, NULL);
344    free(trans->staging);
345    free(trans);
346    return NULL;
347 }
348 
349 static void
flush_region(struct pipe_context * pctx,struct pipe_transfer * ptrans,const struct pipe_box * box)350 flush_region(struct pipe_context *pctx, struct pipe_transfer *ptrans,
351              const struct pipe_box *box)
352 {
353    struct u_transfer_helper *helper = pctx->screen->transfer_helper;
354    /* using the function here hits an assert for the deinterleave cases */
355    struct u_transfer *trans = (struct u_transfer *)ptrans;
356    enum pipe_format iformat, format = ptrans->resource->format;
357    unsigned width = box->width;
358    unsigned height = box->height;
359    void *src, *dst;
360 
361    if (!(ptrans->usage & PIPE_MAP_WRITE))
362       return;
363 
364    if (trans->ss) {
365       struct pipe_blit_info blit;
366       memset(&blit, 0, sizeof(blit));
367 
368       blit.src.resource = trans->ss;
369       blit.src.format = trans->ss->format;
370       blit.src.box = *box;
371 
372       blit.dst.resource = ptrans->resource;
373       blit.dst.format = ptrans->resource->format;
374       blit.dst.level = ptrans->level;
375 
376       u_box_2d(ptrans->box.x + box->x,
377                ptrans->box.y + box->y,
378                box->width, box->height,
379                &blit.dst.box);
380 
381       blit.mask = util_format_get_mask(ptrans->resource->format);
382       blit.filter = PIPE_TEX_FILTER_NEAREST;
383 
384       pctx->blit(pctx, &blit);
385 
386       return;
387    }
388 
389    iformat = helper->vtbl->get_internal_format(ptrans->resource);
390 
391    src = (uint8_t *)trans->staging +
392          (box->y * ptrans->stride) +
393          (box->x * util_format_get_blocksize(format));
394    dst = (uint8_t *)trans->ptr +
395          (box->y * trans->trans->stride) +
396          (box->x * util_format_get_blocksize(iformat));
397 
398    switch (format) {
399    case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
400       util_format_z32_float_s8x24_uint_unpack_z_float(dst,
401                                                       trans->trans->stride,
402                                                       src,
403                                                       ptrans->stride,
404                                                       width, height);
405       FALLTHROUGH;
406    case PIPE_FORMAT_X32_S8X24_UINT:
407       dst = (uint8_t *)trans->ptr2 +
408             (box->y * trans->trans2->stride) +
409             (box->x * util_format_get_blocksize(PIPE_FORMAT_S8_UINT));
410 
411       util_format_z32_float_s8x24_uint_unpack_s_8uint(dst,
412                                                       trans->trans2->stride,
413                                                       src,
414                                                       ptrans->stride,
415                                                       width, height);
416       break;
417    case PIPE_FORMAT_Z24_UNORM_S8_UINT:
418       /* just do a strided 32-bit copy for depth; s8 can become garbage x8 */
419       util_format_z32_unorm_unpack_z_32unorm(dst, trans->trans->stride,
420                                              src, ptrans->stride,
421                                              width, height);
422       FALLTHROUGH;
423    case PIPE_FORMAT_X24S8_UINT:
424       dst = (uint8_t *)trans->ptr2 +
425             (box->y * trans->trans2->stride) +
426             (box->x * util_format_get_blocksize(PIPE_FORMAT_S8_UINT));
427 
428       util_format_z24_unorm_s8_uint_unpack_s_8uint(dst, trans->trans2->stride,
429                                                    src, ptrans->stride,
430                                                    width, height);
431       break;
432 
433    case PIPE_FORMAT_RGTC1_UNORM:
434    case PIPE_FORMAT_RGTC1_SNORM:
435    case PIPE_FORMAT_LATC1_UNORM:
436    case PIPE_FORMAT_LATC1_SNORM:
437       util_format_rgtc1_unorm_unpack_rgba_8unorm(dst,
438                                                  trans->trans->stride,
439                                                  src,
440                                                  ptrans->stride,
441                                                  width, height);
442       break;
443    case PIPE_FORMAT_RGTC2_UNORM:
444    case PIPE_FORMAT_RGTC2_SNORM:
445    case PIPE_FORMAT_LATC2_UNORM:
446    case PIPE_FORMAT_LATC2_SNORM:
447       util_format_rgtc2_unorm_unpack_rgba_8unorm(dst,
448                                                  trans->trans->stride,
449                                                  src,
450                                                  ptrans->stride,
451                                                  width, height);
452       break;
453    default:
454       assert(!"Unexpected staging transfer type");
455       break;
456    }
457 }
458 
459 void
u_transfer_helper_transfer_flush_region(struct pipe_context * pctx,struct pipe_transfer * ptrans,const struct pipe_box * box)460 u_transfer_helper_transfer_flush_region(struct pipe_context *pctx,
461                                         struct pipe_transfer *ptrans,
462                                         const struct pipe_box *box)
463 {
464    struct u_transfer_helper *helper = pctx->screen->transfer_helper;
465 
466    if (handle_transfer(ptrans->resource)) {
467       struct u_transfer *trans = u_transfer(ptrans);
468 
469       flush_region(pctx, ptrans, box);
470 
471       /* handle MSAA case, since there could be multiple levels of
472        * wrapped transfer, call pctx->transfer_flush_region()
473        * instead of helper->vtbl->transfer_flush_region()
474        */
475       if (trans->ss) {
476          pctx->transfer_flush_region(pctx, trans->trans, box);
477          return;
478       }
479 
480       helper->vtbl->transfer_flush_region(pctx, trans->trans, box);
481       if (trans->trans2)
482          helper->vtbl->transfer_flush_region(pctx, trans->trans2, box);
483 
484    } else {
485       helper->vtbl->transfer_flush_region(pctx, ptrans, box);
486    }
487 }
488 
489 void
u_transfer_helper_transfer_unmap(struct pipe_context * pctx,struct pipe_transfer * ptrans)490 u_transfer_helper_transfer_unmap(struct pipe_context *pctx,
491                                  struct pipe_transfer *ptrans)
492 {
493    struct u_transfer_helper *helper = pctx->screen->transfer_helper;
494 
495    if (handle_transfer(ptrans->resource)) {
496       struct u_transfer *trans = u_transfer(ptrans);
497 
498       if (!(ptrans->usage & PIPE_MAP_FLUSH_EXPLICIT)) {
499          struct pipe_box box;
500          u_box_2d(0, 0, ptrans->box.width, ptrans->box.height, &box);
501          flush_region(pctx, ptrans, &box);
502       }
503 
504       /* in MSAA case, there could be multiple levels of wrapping
505        * so don't call helper->vtbl->transfer_unmap() directly
506        */
507       if (trans->ss) {
508          pctx->texture_unmap(pctx, trans->trans);
509          pipe_resource_reference(&trans->ss, NULL);
510       } else {
511          helper->vtbl->transfer_unmap(pctx, trans->trans);
512          if (trans->trans2)
513             helper->vtbl->transfer_unmap(pctx, trans->trans2);
514       }
515 
516       pipe_resource_reference(&ptrans->resource, NULL);
517 
518       free(trans->staging);
519       free(trans);
520    } else {
521       helper->vtbl->transfer_unmap(pctx, ptrans);
522    }
523 }
524 
525 struct u_transfer_helper *
u_transfer_helper_create(const struct u_transfer_vtbl * vtbl,bool separate_z32s8,bool separate_stencil,bool fake_rgtc,bool msaa_map)526 u_transfer_helper_create(const struct u_transfer_vtbl *vtbl,
527                          bool separate_z32s8,
528                          bool separate_stencil,
529                          bool fake_rgtc,
530                          bool msaa_map)
531 {
532    struct u_transfer_helper *helper = calloc(1, sizeof(*helper));
533 
534    helper->vtbl = vtbl;
535    helper->separate_z32s8 = separate_z32s8;
536    helper->separate_stencil = separate_stencil;
537    helper->fake_rgtc = fake_rgtc;
538    helper->msaa_map = msaa_map;
539 
540    return helper;
541 }
542 
543 void
u_transfer_helper_destroy(struct u_transfer_helper * helper)544 u_transfer_helper_destroy(struct u_transfer_helper *helper)
545 {
546    free(helper);
547 }
548 
549 
550 /* these two functions 'deinterleave' are meant to be used without the corresponding
551  * resource_create/destroy hooks, as they perform the interleaving on-the-fly
552  *
553  * drivers should expect to be passed the same buffer repeatedly with the format changed
554  * to indicate which component is being mapped
555  */
556 void *
u_transfer_helper_deinterleave_transfer_map(struct pipe_context * pctx,struct pipe_resource * prsc,unsigned level,unsigned usage,const struct pipe_box * box,struct pipe_transfer ** pptrans)557 u_transfer_helper_deinterleave_transfer_map(struct pipe_context *pctx,
558                                             struct pipe_resource *prsc,
559                                             unsigned level, unsigned usage,
560                                             const struct pipe_box *box,
561                                             struct pipe_transfer **pptrans)
562 {
563    struct u_transfer_helper *helper = pctx->screen->transfer_helper;
564    struct u_transfer *trans;
565    struct pipe_transfer *ptrans;
566    enum pipe_format format = prsc->format;
567    unsigned width = box->width;
568    unsigned height = box->height;
569 
570    if (!((helper->separate_stencil && util_format_is_depth_and_stencil(format)) ||
571        (format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT && helper->separate_z32s8)))
572       return helper->vtbl->transfer_map(pctx, prsc, level, usage, box, pptrans);
573 
574    debug_assert(box->depth == 1);
575 
576    trans = calloc(1, sizeof(*trans));
577    if (!trans)
578       return NULL;
579 
580    ptrans = &trans->base;
581    pipe_resource_reference(&ptrans->resource, prsc);
582    ptrans->level = level;
583    ptrans->usage = usage;
584    ptrans->box   = *box;
585    ptrans->stride = util_format_get_stride(format, box->width);
586    ptrans->layer_stride = ptrans->stride * box->height;
587 
588    trans->staging = malloc(ptrans->layer_stride);
589    if (!trans->staging)
590       goto fail;
591 
592    trans->ptr = helper->vtbl->transfer_map(pctx, prsc, level, usage | PIPE_MAP_DEPTH_ONLY, box,
593                                            &trans->trans);
594    if (!trans->ptr)
595       goto fail;
596 
597    trans->ptr2 = helper->vtbl->transfer_map(pctx, prsc, level,
598                                             usage | PIPE_MAP_STENCIL_ONLY, box, &trans->trans2);
599    if (needs_pack(usage)) {
600       switch (prsc->format) {
601       case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
602          util_format_z32_float_s8x24_uint_pack_z_float(trans->staging,
603                                                        ptrans->stride,
604                                                        trans->ptr,
605                                                        trans->trans->stride,
606                                                        width, height);
607          util_format_z32_float_s8x24_uint_pack_s_8uint(trans->staging,
608                                                        ptrans->stride,
609                                                        trans->ptr2,
610                                                        trans->trans2->stride,
611                                                        width, height);
612          break;
613       case PIPE_FORMAT_Z24_UNORM_S8_UINT:
614          util_format_z24_unorm_s8_uint_pack_separate(trans->staging,
615                                                      ptrans->stride,
616                                                      trans->ptr,
617                                                      trans->trans->stride,
618                                                      trans->ptr2,
619                                                      trans->trans2->stride,
620                                                      width, height);
621          break;
622       default:
623          unreachable("Unexpected format");
624       }
625    }
626 
627    *pptrans = ptrans;
628    return trans->staging;
629 
630 fail:
631    if (trans->trans)
632       helper->vtbl->transfer_unmap(pctx, trans->trans);
633    if (trans->trans2)
634       helper->vtbl->transfer_unmap(pctx, trans->trans2);
635    pipe_resource_reference(&ptrans->resource, NULL);
636    free(trans->staging);
637    free(trans);
638    return NULL;
639 }
640 
641 void
u_transfer_helper_deinterleave_transfer_unmap(struct pipe_context * pctx,struct pipe_transfer * ptrans)642 u_transfer_helper_deinterleave_transfer_unmap(struct pipe_context *pctx,
643                                               struct pipe_transfer *ptrans)
644 {
645    struct u_transfer_helper *helper = pctx->screen->transfer_helper;
646    enum pipe_format format = ptrans->resource->format;
647 
648    if ((helper->separate_stencil && util_format_is_depth_and_stencil(format)) ||
649        (format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT && helper->separate_z32s8)) {
650       struct u_transfer *trans = (struct u_transfer *)ptrans;
651 
652       if (!(ptrans->usage & PIPE_MAP_FLUSH_EXPLICIT)) {
653          struct pipe_box box;
654          u_box_2d(0, 0, ptrans->box.width, ptrans->box.height, &box);
655          flush_region(pctx, ptrans, &box);
656       }
657 
658       helper->vtbl->transfer_unmap(pctx, trans->trans);
659       if (trans->trans2)
660          helper->vtbl->transfer_unmap(pctx, trans->trans2);
661 
662       pipe_resource_reference(&ptrans->resource, NULL);
663 
664       free(trans->staging);
665       free(trans);
666    } else {
667       helper->vtbl->transfer_unmap(pctx, ptrans);
668    }
669 }
670