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