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