• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    bool z24_in_z32f; /* the z24 values are stored in a z32 - translate them. */
41 };
42 
need_interleave_path(struct u_transfer_helper * helper,enum pipe_format format)43 static 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 
handle_transfer(struct pipe_resource * prsc)56 static 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  */
77 struct 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 
91 static inline struct u_transfer *
u_transfer(struct pipe_transfer * ptrans)92 u_transfer(struct pipe_transfer *ptrans)
93 {
94    assert(handle_transfer(ptrans->resource));
95    return (struct u_transfer *)ptrans;
96 }
97 
98 struct pipe_resource *
u_transfer_helper_resource_create(struct pipe_screen * pscreen,const struct pipe_resource * templ)99 u_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 
148 void
u_transfer_helper_resource_destroy(struct pipe_screen * pscreen,struct pipe_resource * prsc)149 u_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 
needs_pack(unsigned usage)163 static 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  */
173 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)174 transfer_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 
242 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)243 u_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 
353 fail:
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 
364 static void
flush_region(struct pipe_context * pctx,struct pipe_transfer * ptrans,const struct pipe_box * box)365 flush_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 
485 void
u_transfer_helper_transfer_flush_region(struct pipe_context * pctx,struct pipe_transfer * ptrans,const struct pipe_box * box)486 u_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 
516 void
u_transfer_helper_transfer_unmap(struct pipe_context * pctx,struct pipe_transfer * ptrans)517 u_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 
554 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,bool z24_in_z32f)555 u_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 
574 void
u_transfer_helper_destroy(struct u_transfer_helper * helper)575 u_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  */
587 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)588 u_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 
680 fail:
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 
691 void
u_transfer_helper_deinterleave_transfer_unmap(struct pipe_context * pctx,struct pipe_transfer * ptrans)692 u_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