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