2 * Copyright © 2017 Red Hat
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:
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
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
24 #include "pipe/p_screen.h"
26 #include "util/u_box.h"
27 #include "util/u_format.h"
28 #include "util/u_format_rgtc.h"
29 #include "util/u_format_zs.h"
30 #include "util/u_inlines.h"
31 #include "util/u_transfer_helper.h"
34 struct u_transfer_helper
{
35 const struct u_transfer_vtbl
*vtbl
;
41 static inline bool handle_transfer(struct pipe_resource
*prsc
)
43 struct u_transfer_helper
*helper
= prsc
->screen
->transfer_helper
;
45 if (helper
->vtbl
->get_internal_format
) {
46 enum pipe_format internal_format
=
47 helper
->vtbl
->get_internal_format(prsc
);
48 if (internal_format
!= prsc
->format
)
52 if (helper
->msaa_map
&& (prsc
->nr_samples
> 1))
58 /* The pipe_transfer ptr could either be the driver's, or u_transfer,
59 * depending on whether we are intervening or not. Check handle_transfer()
60 * before dereferencing.
63 struct pipe_transfer base
;
64 /* Note that in case of MSAA resolve for transfer plus z32s8 or fake rgtc
65 * we end up with stacked u_transfer's. The MSAA resolve case doesn't call
66 * helper->vtbl fxns directly, but calls back to pctx->transfer_map()/etc
67 * so the format related handling can work in conjunction with MSAA resolve.
69 struct pipe_transfer
*trans
; /* driver's transfer */
70 struct pipe_transfer
*trans2
; /* 2nd transfer for s8 stencil buffer in z32s8 */
71 void *ptr
, *ptr2
; /* ptr to trans, and trans2 */
72 void *staging
; /* staging buffer */
73 struct pipe_resource
*ss
; /* staging resource for MSAA resolves */
76 static inline struct u_transfer
*
77 u_transfer(struct pipe_transfer
*ptrans
)
79 debug_assert(handle_transfer(ptrans
->resource
));
80 return (struct u_transfer
*)ptrans
;
83 struct pipe_resource
*
84 u_transfer_helper_resource_create(struct pipe_screen
*pscreen
,
85 const struct pipe_resource
*templ
)
87 struct u_transfer_helper
*helper
= pscreen
->transfer_helper
;
88 enum pipe_format format
= templ
->format
;
89 struct pipe_resource
*prsc
;
91 if ((format
== PIPE_FORMAT_Z32_FLOAT_S8X24_UINT
) && helper
->separate_z32s8
) {
92 struct pipe_resource t
= *templ
;
93 struct pipe_resource
*stencil
;
95 t
.format
= PIPE_FORMAT_Z32_FLOAT
;
97 prsc
= helper
->vtbl
->resource_create(pscreen
, &t
);
101 prsc
->format
= format
; /* frob the format back to the "external" format */
103 t
.format
= PIPE_FORMAT_S8_UINT
;
104 stencil
= helper
->vtbl
->resource_create(pscreen
, &t
);
107 helper
->vtbl
->resource_destroy(pscreen
, prsc
);
111 helper
->vtbl
->set_stencil(prsc
, stencil
);
112 } else if ((util_format_description(format
)->layout
== UTIL_FORMAT_LAYOUT_RGTC
) &&
114 struct pipe_resource t
= *templ
;
115 t
.format
= PIPE_FORMAT_R8G8B8A8_UNORM
;
117 prsc
= helper
->vtbl
->resource_create(pscreen
, &t
);
121 prsc
->format
= format
; /* frob the format back to the "external" format */
123 /* normal case, no special handling: */
124 prsc
= helper
->vtbl
->resource_create(pscreen
, templ
);
133 u_transfer_helper_resource_destroy(struct pipe_screen
*pscreen
,
134 struct pipe_resource
*prsc
)
136 struct u_transfer_helper
*helper
= pscreen
->transfer_helper
;
138 if (helper
->vtbl
->get_stencil
) {
139 struct pipe_resource
*stencil
= helper
->vtbl
->get_stencil(prsc
);
141 pipe_resource_reference(&stencil
, NULL
);
144 helper
->vtbl
->resource_destroy(pscreen
, prsc
);
147 static bool needs_pack(unsigned usage
)
149 return (usage
& PIPE_TRANSFER_READ
) &&
150 !(usage
& (PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE
| PIPE_TRANSFER_DISCARD_RANGE
));
153 /* In the case of transfer_map of a multi-sample resource, call back into
154 * pctx->transfer_map() to map the staging resource, to handle cases of
155 * MSAA + separate_z32s8 or fake_rgtc
158 transfer_map_msaa(struct pipe_context
*pctx
,
159 struct pipe_resource
*prsc
,
160 unsigned level
, unsigned usage
,
161 const struct pipe_box
*box
,
162 struct pipe_transfer
**pptrans
)
164 struct pipe_screen
*pscreen
= pctx
->screen
;
165 struct u_transfer
*trans
= calloc(1, sizeof(*trans
));
168 struct pipe_transfer
*ptrans
= &trans
->base
;
170 pipe_resource_reference(&ptrans
->resource
, prsc
);
171 ptrans
->level
= level
;
172 ptrans
->usage
= usage
;
175 struct pipe_resource tmpl
= {
176 .target
= prsc
->target
,
177 .format
= prsc
->format
,
178 .width0
= box
->width
,
179 .height0
= box
->height
,
183 trans
->ss
= pscreen
->resource_create(pscreen
, &tmpl
);
189 if (needs_pack(usage
)) {
190 struct pipe_blit_info blit
;
191 memset(&blit
, 0, sizeof(blit
));
193 blit
.src
.resource
= ptrans
->resource
;
194 blit
.src
.format
= ptrans
->resource
->format
;
195 blit
.src
.level
= ptrans
->level
;
198 blit
.dst
.resource
= trans
->ss
;
199 blit
.dst
.format
= trans
->ss
->format
;
200 blit
.dst
.box
.width
= box
->width
;
201 blit
.dst
.box
.height
= box
->height
;
202 blit
.dst
.box
.depth
= 1;
204 blit
.mask
= util_format_get_mask(prsc
->format
);
205 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
207 pctx
->blit(pctx
, &blit
);
210 struct pipe_box map_box
= *box
;
214 void *ss_map
= pctx
->transfer_map(pctx
, trans
->ss
, 0, usage
, &map_box
,
221 ptrans
->stride
= trans
->trans
->stride
;
227 u_transfer_helper_transfer_map(struct pipe_context
*pctx
,
228 struct pipe_resource
*prsc
,
229 unsigned level
, unsigned usage
,
230 const struct pipe_box
*box
,
231 struct pipe_transfer
**pptrans
)
233 struct u_transfer_helper
*helper
= pctx
->screen
->transfer_helper
;
234 struct u_transfer
*trans
;
235 struct pipe_transfer
*ptrans
;
236 enum pipe_format format
= prsc
->format
;
237 unsigned width
= box
->width
;
238 unsigned height
= box
->height
;
240 if (!handle_transfer(prsc
))
241 return helper
->vtbl
->transfer_map(pctx
, prsc
, level
, usage
, box
, pptrans
);
243 if (helper
->msaa_map
&& (prsc
->nr_samples
> 1))
244 return transfer_map_msaa(pctx
, prsc
, level
, usage
, box
, pptrans
);
246 debug_assert(box
->depth
== 1);
248 trans
= calloc(1, sizeof(*trans
));
252 ptrans
= &trans
->base
;
253 pipe_resource_reference(&ptrans
->resource
, prsc
);
254 ptrans
->level
= level
;
255 ptrans
->usage
= usage
;
257 ptrans
->stride
= util_format_get_stride(format
, box
->width
);
258 ptrans
->layer_stride
= ptrans
->stride
* box
->height
;
260 trans
->staging
= malloc(ptrans
->layer_stride
);
264 trans
->ptr
= helper
->vtbl
->transfer_map(pctx
, prsc
, level
, usage
, box
,
269 if (prsc
->format
== PIPE_FORMAT_Z32_FLOAT_S8X24_UINT
) {
270 struct pipe_resource
*stencil
= helper
->vtbl
->get_stencil(prsc
);
271 trans
->ptr2
= helper
->vtbl
->transfer_map(pctx
, stencil
, level
,
272 usage
, box
, &trans
->trans2
);
274 if (needs_pack(usage
)) {
275 util_format_z32_float_s8x24_uint_pack_z_float(trans
->staging
,
278 trans
->trans
->stride
,
280 util_format_z32_float_s8x24_uint_pack_s_8uint(trans
->staging
,
283 trans
->trans2
->stride
,
286 } else if (needs_pack(usage
) &&
287 util_format_description(prsc
->format
)->layout
== UTIL_FORMAT_LAYOUT_RGTC
) {
288 switch (prsc
->format
) {
289 case PIPE_FORMAT_RGTC1_UNORM
:
290 case PIPE_FORMAT_RGTC1_SNORM
:
291 case PIPE_FORMAT_LATC1_UNORM
:
292 case PIPE_FORMAT_LATC1_SNORM
:
293 util_format_rgtc1_unorm_pack_rgba_8unorm(trans
->staging
,
296 trans
->trans
->stride
,
299 case PIPE_FORMAT_RGTC2_UNORM
:
300 case PIPE_FORMAT_RGTC2_SNORM
:
301 case PIPE_FORMAT_LATC2_UNORM
:
302 case PIPE_FORMAT_LATC2_SNORM
:
303 util_format_rgtc2_unorm_pack_rgba_8unorm(trans
->staging
,
306 trans
->trans
->stride
,
310 assert(!"Unexpected format");
318 return trans
->staging
;
322 helper
->vtbl
->transfer_unmap(pctx
, trans
->trans
);
324 helper
->vtbl
->transfer_unmap(pctx
, trans
->trans2
);
325 pipe_resource_reference(&ptrans
->resource
, NULL
);
326 free(trans
->staging
);
332 flush_region(struct pipe_context
*pctx
, struct pipe_transfer
*ptrans
,
333 const struct pipe_box
*box
)
335 struct u_transfer_helper
*helper
= pctx
->screen
->transfer_helper
;
336 struct u_transfer
*trans
= u_transfer(ptrans
);
337 enum pipe_format iformat
, format
= ptrans
->resource
->format
;
338 unsigned width
= box
->width
;
339 unsigned height
= box
->height
;
342 if (!(ptrans
->usage
& PIPE_TRANSFER_WRITE
))
346 struct pipe_blit_info blit
;
347 memset(&blit
, 0, sizeof(blit
));
349 blit
.src
.resource
= trans
->ss
;
350 blit
.src
.format
= trans
->ss
->format
;
353 blit
.dst
.resource
= ptrans
->resource
;
354 blit
.dst
.format
= ptrans
->resource
->format
;
355 blit
.dst
.level
= ptrans
->level
;
357 u_box_2d(ptrans
->box
.x
+ box
->x
,
358 ptrans
->box
.y
+ box
->y
,
359 box
->width
, box
->height
,
362 blit
.mask
= util_format_get_mask(ptrans
->resource
->format
);
363 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
365 pctx
->blit(pctx
, &blit
);
370 iformat
= helper
->vtbl
->get_internal_format(ptrans
->resource
);
372 src
= (uint8_t *)trans
->staging
+
373 (box
->y
* ptrans
->stride
) +
374 (box
->x
* util_format_get_blocksize(format
));
375 dst
= (uint8_t *)trans
->ptr
+
376 (box
->y
* trans
->trans
->stride
) +
377 (box
->x
* util_format_get_blocksize(iformat
));
380 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT
:
381 util_format_z32_float_s8x24_uint_unpack_z_float(dst
,
382 trans
->trans
->stride
,
387 case PIPE_FORMAT_X32_S8X24_UINT
:
388 dst
= (uint8_t *)trans
->ptr2
+
389 (box
->y
* trans
->trans2
->stride
) +
390 (box
->x
* util_format_get_blocksize(PIPE_FORMAT_S8_UINT
));
392 util_format_z32_float_s8x24_uint_unpack_s_8uint(dst
,
393 trans
->trans2
->stride
,
398 case PIPE_FORMAT_RGTC1_UNORM
:
399 case PIPE_FORMAT_RGTC1_SNORM
:
400 case PIPE_FORMAT_LATC1_UNORM
:
401 case PIPE_FORMAT_LATC1_SNORM
:
402 util_format_rgtc1_unorm_unpack_rgba_8unorm(dst
,
403 trans
->trans
->stride
,
408 case PIPE_FORMAT_RGTC2_UNORM
:
409 case PIPE_FORMAT_RGTC2_SNORM
:
410 case PIPE_FORMAT_LATC2_UNORM
:
411 case PIPE_FORMAT_LATC2_SNORM
:
412 util_format_rgtc2_unorm_unpack_rgba_8unorm(dst
,
413 trans
->trans
->stride
,
419 assert(!"Unexpected staging transfer type");
425 u_transfer_helper_transfer_flush_region(struct pipe_context
*pctx
,
426 struct pipe_transfer
*ptrans
,
427 const struct pipe_box
*box
)
429 struct u_transfer_helper
*helper
= pctx
->screen
->transfer_helper
;
431 if (handle_transfer(ptrans
->resource
)) {
432 struct u_transfer
*trans
= u_transfer(ptrans
);
434 flush_region(pctx
, ptrans
, box
);
436 /* handle MSAA case, since there could be multiple levels of
437 * wrapped transfer, call pctx->transfer_flush_region()
438 * instead of helper->vtbl->transfer_flush_region()
441 pctx
->transfer_flush_region(pctx
, trans
->trans
, box
);
445 helper
->vtbl
->transfer_flush_region(pctx
, trans
->trans
, box
);
447 helper
->vtbl
->transfer_flush_region(pctx
, trans
->trans2
, box
);
450 helper
->vtbl
->transfer_flush_region(pctx
, ptrans
, box
);
455 u_transfer_helper_transfer_unmap(struct pipe_context
*pctx
,
456 struct pipe_transfer
*ptrans
)
458 struct u_transfer_helper
*helper
= pctx
->screen
->transfer_helper
;
460 if (handle_transfer(ptrans
->resource
)) {
461 struct u_transfer
*trans
= u_transfer(ptrans
);
463 if (!(ptrans
->usage
& PIPE_TRANSFER_FLUSH_EXPLICIT
)) {
465 u_box_2d(0, 0, ptrans
->box
.width
, ptrans
->box
.height
, &box
);
466 flush_region(pctx
, ptrans
, &box
);
469 /* in MSAA case, there could be multiple levels of wrapping
470 * so don't call helper->vtbl->transfer_unmap() directly
473 pctx
->transfer_unmap(pctx
, trans
->trans
);
474 pipe_resource_reference(&trans
->ss
, NULL
);
476 helper
->vtbl
->transfer_unmap(pctx
, trans
->trans
);
478 helper
->vtbl
->transfer_unmap(pctx
, trans
->trans2
);
483 helper
->vtbl
->transfer_unmap(pctx
, ptrans
);
487 struct u_transfer_helper
*
488 u_transfer_helper_create(const struct u_transfer_vtbl
*vtbl
,
493 struct u_transfer_helper
*helper
= calloc(1, sizeof(*helper
));
496 helper
->separate_z32s8
= separate_z32s8
;
497 helper
->fake_rgtc
= fake_rgtc
;
498 helper
->msaa_map
= msaa_map
;
504 u_transfer_helper_destroy(struct u_transfer_helper
*helper
)