2 * Copyright © 2014-2017 Broadcom
3 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 #include "pipe/p_defines.h"
26 #include "util/u_blit.h"
27 #include "util/u_memory.h"
28 #include "util/format/u_format.h"
29 #include "util/u_inlines.h"
30 #include "util/u_surface.h"
31 #include "util/u_transfer_helper.h"
32 #include "util/u_upload_mgr.h"
33 #include "util/format/u_format_zs.h"
34 #include "util/u_drm.h"
36 #include "drm-uapi/drm_fourcc.h"
37 #include "v3d_screen.h"
38 #include "v3d_context.h"
39 #include "v3d_resource.h"
40 #include "v3d_tiling.h"
41 #include "broadcom/cle/v3d_packet_v33_pack.h"
44 v3d_debug_resource_layout(struct v3d_resource
*rsc
, const char *caller
)
46 if (!(V3D_DEBUG
& V3D_DEBUG_SURFACE
))
49 struct pipe_resource
*prsc
= &rsc
->base
;
51 if (prsc
->target
== PIPE_BUFFER
) {
53 "rsc %s %p (format %s), %dx%d buffer @0x%08x-0x%08x\n",
55 util_format_short_name(prsc
->format
),
56 prsc
->width0
, prsc
->height0
,
58 rsc
->bo
->offset
+ rsc
->bo
->size
- 1);
62 static const char *const tiling_descriptions
[] = {
63 [VC5_TILING_RASTER
] = "R",
64 [VC5_TILING_LINEARTILE
] = "LT",
65 [VC5_TILING_UBLINEAR_1_COLUMN
] = "UB1",
66 [VC5_TILING_UBLINEAR_2_COLUMN
] = "UB2",
67 [VC5_TILING_UIF_NO_XOR
] = "UIF",
68 [VC5_TILING_UIF_XOR
] = "UIF^",
71 for (int i
= 0; i
<= prsc
->last_level
; i
++) {
72 struct v3d_resource_slice
*slice
= &rsc
->slices
[i
];
74 int level_width
= slice
->stride
/ rsc
->cpp
;
75 int level_height
= slice
->padded_height
;
77 u_minify(util_next_power_of_two(prsc
->depth0
), i
);
80 "rsc %s %p (format %s), %dx%d: "
81 "level %d (%s) %dx%dx%d -> %dx%dx%d, stride %d@0x%08x\n",
83 util_format_short_name(prsc
->format
),
84 prsc
->width0
, prsc
->height0
,
85 i
, tiling_descriptions
[slice
->tiling
],
86 u_minify(prsc
->width0
, i
),
87 u_minify(prsc
->height0
, i
),
88 u_minify(prsc
->depth0
, i
),
93 rsc
->bo
->offset
+ slice
->offset
);
98 v3d_resource_bo_alloc(struct v3d_resource
*rsc
)
100 struct pipe_resource
*prsc
= &rsc
->base
;
101 struct pipe_screen
*pscreen
= prsc
->screen
;
104 bo
= v3d_bo_alloc(v3d_screen(pscreen
), rsc
->size
, "resource");
106 v3d_bo_unreference(&rsc
->bo
);
108 v3d_debug_resource_layout(rsc
, "alloc");
116 v3d_resource_transfer_unmap(struct pipe_context
*pctx
,
117 struct pipe_transfer
*ptrans
)
119 struct v3d_context
*v3d
= v3d_context(pctx
);
120 struct v3d_transfer
*trans
= v3d_transfer(ptrans
);
123 struct v3d_resource
*rsc
= v3d_resource(ptrans
->resource
);
124 struct v3d_resource_slice
*slice
= &rsc
->slices
[ptrans
->level
];
126 if (ptrans
->usage
& PIPE_TRANSFER_WRITE
) {
127 for (int z
= 0; z
< ptrans
->box
.depth
; z
++) {
128 void *dst
= rsc
->bo
->map
+
129 v3d_layer_offset(&rsc
->base
,
132 v3d_store_tiled_image(dst
,
136 ptrans
->box
.height
* z
),
138 slice
->tiling
, rsc
->cpp
,
139 slice
->padded_height
,
146 pipe_resource_reference(&ptrans
->resource
, NULL
);
147 slab_free(&v3d
->transfer_pool
, ptrans
);
151 v3d_map_usage_prep(struct pipe_context
*pctx
,
152 struct pipe_resource
*prsc
,
155 struct v3d_context
*v3d
= v3d_context(pctx
);
156 struct v3d_resource
*rsc
= v3d_resource(prsc
);
158 if (usage
& PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE
) {
159 if (v3d_resource_bo_alloc(rsc
)) {
160 /* If it might be bound as one of our vertex buffers
161 * or UBOs, make sure we re-emit vertex buffer state
164 if (prsc
->bind
& PIPE_BIND_VERTEX_BUFFER
)
165 v3d
->dirty
|= VC5_DIRTY_VTXBUF
;
166 if (prsc
->bind
& PIPE_BIND_CONSTANT_BUFFER
)
167 v3d
->dirty
|= VC5_DIRTY_CONSTBUF
;
169 /* If we failed to reallocate, flush users so that we
170 * don't violate any syncing requirements.
172 v3d_flush_jobs_reading_resource(v3d
, prsc
,
175 } else if (!(usage
& PIPE_TRANSFER_UNSYNCHRONIZED
)) {
176 /* If we're writing and the buffer is being used by the CL, we
177 * have to flush the CL first. If we're only reading, we need
178 * to flush if the CL has written our buffer.
180 if (usage
& PIPE_TRANSFER_WRITE
)
181 v3d_flush_jobs_reading_resource(v3d
, prsc
,
184 v3d_flush_jobs_writing_resource(v3d
, prsc
,
188 if (usage
& PIPE_TRANSFER_WRITE
) {
190 rsc
->initialized_buffers
= ~0;
195 v3d_resource_transfer_map(struct pipe_context
*pctx
,
196 struct pipe_resource
*prsc
,
197 unsigned level
, unsigned usage
,
198 const struct pipe_box
*box
,
199 struct pipe_transfer
**pptrans
)
201 struct v3d_context
*v3d
= v3d_context(pctx
);
202 struct v3d_resource
*rsc
= v3d_resource(prsc
);
203 struct v3d_transfer
*trans
;
204 struct pipe_transfer
*ptrans
;
205 enum pipe_format format
= prsc
->format
;
208 /* MSAA maps should have been handled by u_transfer_helper. */
209 assert(prsc
->nr_samples
<= 1);
211 /* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is
214 if ((usage
& PIPE_TRANSFER_DISCARD_RANGE
) &&
215 !(usage
& PIPE_TRANSFER_UNSYNCHRONIZED
) &&
216 !(prsc
->flags
& PIPE_RESOURCE_FLAG_MAP_PERSISTENT
) &&
217 prsc
->last_level
== 0 &&
218 prsc
->width0
== box
->width
&&
219 prsc
->height0
== box
->height
&&
220 prsc
->depth0
== box
->depth
&&
221 prsc
->array_size
== 1 &&
223 usage
|= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE
;
226 v3d_map_usage_prep(pctx
, prsc
, usage
);
228 trans
= slab_alloc(&v3d
->transfer_pool
);
232 /* XXX: Handle DONTBLOCK, DISCARD_RANGE, PERSISTENT, COHERENT. */
234 /* slab_alloc_st() doesn't zero: */
235 memset(trans
, 0, sizeof(*trans
));
236 ptrans
= &trans
->base
;
238 pipe_resource_reference(&ptrans
->resource
, prsc
);
239 ptrans
->level
= level
;
240 ptrans
->usage
= usage
;
243 /* Note that the current kernel implementation is synchronous, so no
244 * need to do syncing stuff here yet.
247 if (usage
& PIPE_TRANSFER_UNSYNCHRONIZED
)
248 buf
= v3d_bo_map_unsynchronized(rsc
->bo
);
250 buf
= v3d_bo_map(rsc
->bo
);
252 fprintf(stderr
, "Failed to map bo\n");
258 /* Our load/store routines work on entire compressed blocks. */
259 ptrans
->box
.x
/= util_format_get_blockwidth(format
);
260 ptrans
->box
.y
/= util_format_get_blockheight(format
);
261 ptrans
->box
.width
= DIV_ROUND_UP(ptrans
->box
.width
,
262 util_format_get_blockwidth(format
));
263 ptrans
->box
.height
= DIV_ROUND_UP(ptrans
->box
.height
,
264 util_format_get_blockheight(format
));
266 struct v3d_resource_slice
*slice
= &rsc
->slices
[level
];
268 /* No direct mappings of tiled, since we need to manually
271 if (usage
& PIPE_TRANSFER_MAP_DIRECTLY
)
274 ptrans
->stride
= ptrans
->box
.width
* rsc
->cpp
;
275 ptrans
->layer_stride
= ptrans
->stride
* ptrans
->box
.height
;
277 trans
->map
= malloc(ptrans
->layer_stride
* ptrans
->box
.depth
);
279 if (usage
& PIPE_TRANSFER_READ
) {
280 for (int z
= 0; z
< ptrans
->box
.depth
; z
++) {
281 void *src
= rsc
->bo
->map
+
282 v3d_layer_offset(&rsc
->base
,
285 v3d_load_tiled_image((trans
->map
+
287 ptrans
->box
.height
* z
),
291 slice
->tiling
, rsc
->cpp
,
292 slice
->padded_height
,
298 ptrans
->stride
= slice
->stride
;
299 ptrans
->layer_stride
= rsc
->cube_map_stride
;
301 return buf
+ slice
->offset
+
302 ptrans
->box
.y
* ptrans
->stride
+
303 ptrans
->box
.x
* rsc
->cpp
+
304 ptrans
->box
.z
* rsc
->cube_map_stride
;
309 v3d_resource_transfer_unmap(pctx
, ptrans
);
314 v3d_texture_subdata(struct pipe_context
*pctx
,
315 struct pipe_resource
*prsc
,
318 const struct pipe_box
*box
,
321 unsigned layer_stride
)
323 struct v3d_resource
*rsc
= v3d_resource(prsc
);
324 struct v3d_resource_slice
*slice
= &rsc
->slices
[level
];
326 /* For a direct mapping, we can just take the u_transfer path. */
328 return u_default_texture_subdata(pctx
, prsc
, level
, usage
, box
,
329 data
, stride
, layer_stride
);
332 /* Otherwise, map and store the texture data directly into the tiled
333 * texture. Note that gallium's texture_subdata may be called with
334 * obvious usage flags missing!
336 v3d_map_usage_prep(pctx
, prsc
, usage
| (PIPE_TRANSFER_WRITE
|
337 PIPE_TRANSFER_DISCARD_RANGE
));
340 if (usage
& PIPE_TRANSFER_UNSYNCHRONIZED
)
341 buf
= v3d_bo_map_unsynchronized(rsc
->bo
);
343 buf
= v3d_bo_map(rsc
->bo
);
345 for (int i
= 0; i
< box
->depth
; i
++) {
346 v3d_store_tiled_image(buf
+
347 v3d_layer_offset(&rsc
->base
,
351 (void *)data
+ layer_stride
* i
,
353 slice
->tiling
, rsc
->cpp
, slice
->padded_height
,
359 v3d_resource_destroy(struct pipe_screen
*pscreen
,
360 struct pipe_resource
*prsc
)
362 struct v3d_screen
*screen
= v3d_screen(pscreen
);
363 struct v3d_resource
*rsc
= v3d_resource(prsc
);
366 renderonly_scanout_destroy(rsc
->scanout
, screen
->ro
);
368 v3d_bo_unreference(&rsc
->bo
);
373 v3d_resource_get_handle(struct pipe_screen
*pscreen
,
374 struct pipe_context
*pctx
,
375 struct pipe_resource
*prsc
,
376 struct winsys_handle
*whandle
,
379 struct v3d_screen
*screen
= v3d_screen(pscreen
);
380 struct v3d_resource
*rsc
= v3d_resource(prsc
);
381 struct v3d_bo
*bo
= rsc
->bo
;
383 whandle
->stride
= rsc
->slices
[0].stride
;
386 /* If we're passing some reference to our BO out to some other part of
387 * the system, then we can't do any optimizations about only us being
388 * the ones seeing it (like BO caching).
393 /* A shared tiled buffer should always be allocated as UIF,
394 * not UBLINEAR or LT.
396 assert(rsc
->slices
[0].tiling
== VC5_TILING_UIF_XOR
||
397 rsc
->slices
[0].tiling
== VC5_TILING_UIF_NO_XOR
);
398 whandle
->modifier
= DRM_FORMAT_MOD_BROADCOM_UIF
;
400 whandle
->modifier
= DRM_FORMAT_MOD_LINEAR
;
403 switch (whandle
->type
) {
404 case WINSYS_HANDLE_TYPE_SHARED
:
405 return v3d_bo_flink(bo
, &whandle
->handle
);
406 case WINSYS_HANDLE_TYPE_KMS
:
408 assert(rsc
->scanout
);
409 bool ok
= renderonly_get_handle(rsc
->scanout
, whandle
);
410 whandle
->stride
= rsc
->slices
[0].stride
;
413 whandle
->handle
= bo
->handle
;
415 case WINSYS_HANDLE_TYPE_FD
:
416 whandle
->handle
= v3d_bo_get_dmabuf(bo
);
417 return whandle
->handle
!= -1;
423 #define PAGE_UB_ROWS (VC5_UIFCFG_PAGE_SIZE / VC5_UIFBLOCK_ROW_SIZE)
424 #define PAGE_UB_ROWS_TIMES_1_5 ((PAGE_UB_ROWS * 3) >> 1)
425 #define PAGE_CACHE_UB_ROWS (VC5_PAGE_CACHE_SIZE / VC5_UIFBLOCK_ROW_SIZE)
426 #define PAGE_CACHE_MINUS_1_5_UB_ROWS (PAGE_CACHE_UB_ROWS - PAGE_UB_ROWS_TIMES_1_5)
429 * Computes the HW's UIFblock padding for a given height/cpp.
431 * The goal of the padding is to keep pages of the same color (bank number) at
432 * least half a page away from each other vertically when crossing between
433 * between columns of UIF blocks.
436 v3d_get_ub_pad(struct v3d_resource
*rsc
, uint32_t height
)
438 uint32_t utile_h
= v3d_utile_height(rsc
->cpp
);
439 uint32_t uif_block_h
= utile_h
* 2;
440 uint32_t height_ub
= height
/ uif_block_h
;
442 uint32_t height_offset_in_pc
= height_ub
% PAGE_CACHE_UB_ROWS
;
444 /* For the perfectly-aligned-for-UIF-XOR case, don't add any pad. */
445 if (height_offset_in_pc
== 0)
448 /* Try padding up to where we're offset by at least half a page. */
449 if (height_offset_in_pc
< PAGE_UB_ROWS_TIMES_1_5
) {
450 /* If we fit entirely in the page cache, don't pad. */
451 if (height_ub
< PAGE_CACHE_UB_ROWS
)
454 return PAGE_UB_ROWS_TIMES_1_5
- height_offset_in_pc
;
457 /* If we're close to being aligned to page cache size, then round up
460 if (height_offset_in_pc
> PAGE_CACHE_MINUS_1_5_UB_ROWS
)
461 return PAGE_CACHE_UB_ROWS
- height_offset_in_pc
;
463 /* Otherwise, we're far enough away (top and bottom) to not need any
470 v3d_setup_slices(struct v3d_resource
*rsc
, uint32_t winsys_stride
,
473 struct pipe_resource
*prsc
= &rsc
->base
;
474 uint32_t width
= prsc
->width0
;
475 uint32_t height
= prsc
->height0
;
476 uint32_t depth
= prsc
->depth0
;
477 /* Note that power-of-two padding is based on level 1. These are not
478 * equivalent to just util_next_power_of_two(dimension), because at a
479 * level 0 dimension of 9, the level 1 power-of-two padded value is 4,
482 uint32_t pot_width
= 2 * util_next_power_of_two(u_minify(width
, 1));
483 uint32_t pot_height
= 2 * util_next_power_of_two(u_minify(height
, 1));
484 uint32_t pot_depth
= 2 * util_next_power_of_two(u_minify(depth
, 1));
486 uint32_t utile_w
= v3d_utile_width(rsc
->cpp
);
487 uint32_t utile_h
= v3d_utile_height(rsc
->cpp
);
488 uint32_t uif_block_w
= utile_w
* 2;
489 uint32_t uif_block_h
= utile_h
* 2;
490 uint32_t block_width
= util_format_get_blockwidth(prsc
->format
);
491 uint32_t block_height
= util_format_get_blockheight(prsc
->format
);
492 bool msaa
= prsc
->nr_samples
> 1;
494 /* MSAA textures/renderbuffers are always laid out as single-level
499 /* Check some easy mistakes to make in a resource_create() call that
500 * will break our setup.
502 assert(prsc
->array_size
!= 0);
503 assert(prsc
->depth0
!= 0);
505 for (int i
= prsc
->last_level
; i
>= 0; i
--) {
506 struct v3d_resource_slice
*slice
= &rsc
->slices
[i
];
508 uint32_t level_width
, level_height
, level_depth
;
510 level_width
= u_minify(width
, i
);
511 level_height
= u_minify(height
, i
);
513 level_width
= u_minify(pot_width
, i
);
514 level_height
= u_minify(pot_height
, i
);
517 level_depth
= u_minify(depth
, i
);
519 level_depth
= u_minify(pot_depth
, i
);
526 level_width
= DIV_ROUND_UP(level_width
, block_width
);
527 level_height
= DIV_ROUND_UP(level_height
, block_height
);
530 slice
->tiling
= VC5_TILING_RASTER
;
531 if (prsc
->target
== PIPE_TEXTURE_1D
)
532 level_width
= align(level_width
, 64 / rsc
->cpp
);
534 if ((i
!= 0 || !uif_top
) &&
535 (level_width
<= utile_w
||
536 level_height
<= utile_h
)) {
537 slice
->tiling
= VC5_TILING_LINEARTILE
;
538 level_width
= align(level_width
, utile_w
);
539 level_height
= align(level_height
, utile_h
);
540 } else if ((i
!= 0 || !uif_top
) &&
541 level_width
<= uif_block_w
) {
542 slice
->tiling
= VC5_TILING_UBLINEAR_1_COLUMN
;
543 level_width
= align(level_width
, uif_block_w
);
544 level_height
= align(level_height
, uif_block_h
);
545 } else if ((i
!= 0 || !uif_top
) &&
546 level_width
<= 2 * uif_block_w
) {
547 slice
->tiling
= VC5_TILING_UBLINEAR_2_COLUMN
;
548 level_width
= align(level_width
, 2 * uif_block_w
);
549 level_height
= align(level_height
, uif_block_h
);
551 /* We align the width to a 4-block column of
552 * UIF blocks, but we only align height to UIF
555 level_width
= align(level_width
,
557 level_height
= align(level_height
,
560 slice
->ub_pad
= v3d_get_ub_pad(rsc
,
562 level_height
+= slice
->ub_pad
* uif_block_h
;
564 /* If the padding set us to to be aligned to
565 * the page cache size, then the HW will use
566 * the XOR bit on odd columns to get us
567 * perfectly misaligned
569 if ((level_height
/ uif_block_h
) %
570 (VC5_PAGE_CACHE_SIZE
/
571 VC5_UIFBLOCK_ROW_SIZE
) == 0) {
572 slice
->tiling
= VC5_TILING_UIF_XOR
;
574 slice
->tiling
= VC5_TILING_UIF_NO_XOR
;
579 slice
->offset
= offset
;
581 slice
->stride
= winsys_stride
;
583 slice
->stride
= level_width
* rsc
->cpp
;
584 slice
->padded_height
= level_height
;
585 slice
->size
= level_height
* slice
->stride
;
587 uint32_t slice_total_size
= slice
->size
* level_depth
;
589 /* The HW aligns level 1's base to a page if any of level 1 or
590 * below could be UIF XOR. The lower levels then inherit the
591 * alignment for as long as necesary, thanks to being power of
595 level_width
> 4 * uif_block_w
&&
596 level_height
> PAGE_CACHE_MINUS_1_5_UB_ROWS
* uif_block_h
) {
597 slice_total_size
= align(slice_total_size
,
598 VC5_UIFCFG_PAGE_SIZE
);
601 offset
+= slice_total_size
;
606 /* UIF/UBLINEAR levels need to be aligned to UIF-blocks, and LT only
607 * needs to be aligned to utile boundaries. Since tiles are laid out
608 * from small to big in memory, we need to align the later UIF slices
609 * to UIF blocks, if they were preceded by non-UIF-block-aligned LT
612 * We additionally align to 4k, which improves UIF XOR performance.
614 uint32_t page_align_offset
= (align(rsc
->slices
[0].offset
, 4096) -
615 rsc
->slices
[0].offset
);
616 if (page_align_offset
) {
617 rsc
->size
+= page_align_offset
;
618 for (int i
= 0; i
<= prsc
->last_level
; i
++)
619 rsc
->slices
[i
].offset
+= page_align_offset
;
622 /* Arrays and cube textures have a stride which is the distance from
623 * one full mipmap tree to the next (64b aligned). For 3D textures,
624 * we need to program the stride between slices of miplevel 0.
626 if (prsc
->target
!= PIPE_TEXTURE_3D
) {
627 rsc
->cube_map_stride
= align(rsc
->slices
[0].offset
+
628 rsc
->slices
[0].size
, 64);
629 rsc
->size
+= rsc
->cube_map_stride
* (prsc
->array_size
- 1);
631 rsc
->cube_map_stride
= rsc
->slices
[0].size
;
636 v3d_layer_offset(struct pipe_resource
*prsc
, uint32_t level
, uint32_t layer
)
638 struct v3d_resource
*rsc
= v3d_resource(prsc
);
639 struct v3d_resource_slice
*slice
= &rsc
->slices
[level
];
641 if (prsc
->target
== PIPE_TEXTURE_3D
)
642 return slice
->offset
+ layer
* slice
->size
;
644 return slice
->offset
+ layer
* rsc
->cube_map_stride
;
647 static struct v3d_resource
*
648 v3d_resource_setup(struct pipe_screen
*pscreen
,
649 const struct pipe_resource
*tmpl
)
651 struct v3d_screen
*screen
= v3d_screen(pscreen
);
652 struct v3d_resource
*rsc
= CALLOC_STRUCT(v3d_resource
);
655 struct pipe_resource
*prsc
= &rsc
->base
;
659 pipe_reference_init(&prsc
->reference
, 1);
660 prsc
->screen
= pscreen
;
662 if (prsc
->nr_samples
<= 1 ||
663 screen
->devinfo
.ver
>= 40 ||
664 util_format_is_depth_or_stencil(prsc
->format
)) {
665 rsc
->cpp
= util_format_get_blocksize(prsc
->format
);
666 if (screen
->devinfo
.ver
< 40 && prsc
->nr_samples
> 1)
667 rsc
->cpp
*= prsc
->nr_samples
;
669 assert(v3d_rt_format_supported(&screen
->devinfo
, prsc
->format
));
670 uint32_t output_image_format
=
671 v3d_get_rt_format(&screen
->devinfo
, prsc
->format
);
672 uint32_t internal_type
;
673 uint32_t internal_bpp
;
674 v3d_get_internal_type_bpp_for_output_format(&screen
->devinfo
,
678 switch (internal_bpp
) {
679 case V3D_INTERNAL_BPP_32
:
682 case V3D_INTERNAL_BPP_64
:
685 case V3D_INTERNAL_BPP_128
:
696 static struct pipe_resource
*
697 v3d_resource_create_with_modifiers(struct pipe_screen
*pscreen
,
698 const struct pipe_resource
*tmpl
,
699 const uint64_t *modifiers
,
702 struct v3d_screen
*screen
= v3d_screen(pscreen
);
704 bool linear_ok
= drm_find_modifier(DRM_FORMAT_MOD_LINEAR
, modifiers
, count
);
705 struct v3d_resource
*rsc
= v3d_resource_setup(pscreen
, tmpl
);
706 struct pipe_resource
*prsc
= &rsc
->base
;
707 /* Use a tiled layout if we can, for better 3D performance. */
708 bool should_tile
= true;
710 /* VBOs/PBOs are untiled (and 1 height). */
711 if (tmpl
->target
== PIPE_BUFFER
)
714 /* Cursors are always linear, and the user can request linear as well.
716 if (tmpl
->bind
& (PIPE_BIND_LINEAR
| PIPE_BIND_CURSOR
))
719 /* 1D and 1D_ARRAY textures are always raster-order. */
720 if (tmpl
->target
== PIPE_TEXTURE_1D
||
721 tmpl
->target
== PIPE_TEXTURE_1D_ARRAY
)
724 /* Scanout BOs for simulator need to be linear for interaction with
727 if (using_v3d_simulator
&&
728 tmpl
->bind
& (PIPE_BIND_SHARED
| PIPE_BIND_SCANOUT
))
731 /* If using the old-school SCANOUT flag, we don't know what the screen
732 * might support other than linear. Just force linear.
734 if (tmpl
->bind
& PIPE_BIND_SCANOUT
)
737 /* No user-specified modifier; determine our own. */
738 if (count
== 1 && modifiers
[0] == DRM_FORMAT_MOD_INVALID
) {
740 rsc
->tiled
= should_tile
;
741 } else if (should_tile
&&
742 drm_find_modifier(DRM_FORMAT_MOD_BROADCOM_UIF
,
745 } else if (linear_ok
) {
748 fprintf(stderr
, "Unsupported modifier requested\n");
752 rsc
->internal_format
= prsc
->format
;
754 v3d_setup_slices(rsc
, 0, tmpl
->bind
& PIPE_BIND_SHARED
);
756 /* If we're in a renderonly setup, use the other device to perform our
757 * allocation and just import it to v3d. The other device may be
758 * using CMA, and V3D can import from CMA but doesn't do CMA
759 * allocations on its own.
761 * We always allocate this way for SHARED, because get_handle will
762 * need a resource on the display fd.
764 if (screen
->ro
&& (tmpl
->bind
& (PIPE_BIND_SCANOUT
|
765 PIPE_BIND_SHARED
))) {
766 struct winsys_handle handle
;
767 struct pipe_resource scanout_tmpl
= {
768 .target
= prsc
->target
,
769 .format
= PIPE_FORMAT_RGBA8888_UNORM
,
770 .width0
= 1024, /* one page */
771 .height0
= align(rsc
->size
, 4096) / 4096,
777 renderonly_scanout_for_resource(&scanout_tmpl
,
782 fprintf(stderr
, "Failed to create scanout resource\n");
785 assert(handle
.type
== WINSYS_HANDLE_TYPE_FD
);
786 rsc
->bo
= v3d_bo_open_dmabuf(screen
, handle
.handle
);
787 close(handle
.handle
);
792 v3d_debug_resource_layout(rsc
, "renderonly");
796 if (!v3d_resource_bo_alloc(rsc
))
802 v3d_resource_destroy(pscreen
, prsc
);
806 struct pipe_resource
*
807 v3d_resource_create(struct pipe_screen
*pscreen
,
808 const struct pipe_resource
*tmpl
)
810 const uint64_t mod
= DRM_FORMAT_MOD_INVALID
;
811 return v3d_resource_create_with_modifiers(pscreen
, tmpl
, &mod
, 1);
814 static struct pipe_resource
*
815 v3d_resource_from_handle(struct pipe_screen
*pscreen
,
816 const struct pipe_resource
*tmpl
,
817 struct winsys_handle
*whandle
,
820 struct v3d_screen
*screen
= v3d_screen(pscreen
);
821 struct v3d_resource
*rsc
= v3d_resource_setup(pscreen
, tmpl
);
822 struct pipe_resource
*prsc
= &rsc
->base
;
823 struct v3d_resource_slice
*slice
= &rsc
->slices
[0];
828 switch (whandle
->modifier
) {
829 case DRM_FORMAT_MOD_LINEAR
:
832 case DRM_FORMAT_MOD_BROADCOM_UIF
:
835 case DRM_FORMAT_MOD_INVALID
:
836 rsc
->tiled
= screen
->ro
== NULL
;
840 "Attempt to import unsupported modifier 0x%llx\n",
841 (long long)whandle
->modifier
);
845 switch (whandle
->type
) {
846 case WINSYS_HANDLE_TYPE_SHARED
:
847 rsc
->bo
= v3d_bo_open_name(screen
, whandle
->handle
);
849 case WINSYS_HANDLE_TYPE_FD
:
850 rsc
->bo
= v3d_bo_open_dmabuf(screen
, whandle
->handle
);
854 "Attempt to import unsupported handle type %d\n",
862 rsc
->internal_format
= prsc
->format
;
864 v3d_setup_slices(rsc
, whandle
->stride
, true);
865 v3d_debug_resource_layout(rsc
, "import");
867 if (whandle
->offset
!= 0) {
870 "Attempt to import unsupported winsys offset %u\n",
874 rsc
->slices
[0].offset
+= whandle
->offset
;
876 if (rsc
->slices
[0].offset
+ rsc
->slices
[0].size
>
878 fprintf(stderr
, "Attempt to import "
879 "with overflowing offset (%d + %d > %d)\n",
888 /* Make sure that renderonly has a handle to our buffer in the
889 * display's fd, so that a later renderonly_get_handle()
890 * returns correct handles or GEM names.
893 renderonly_create_gpu_import_for_resource(prsc
,
897 fprintf(stderr
, "Failed to create scanout resource.\n");
902 if (rsc
->tiled
&& whandle
->stride
!= slice
->stride
) {
903 static bool warned
= false;
907 "Attempting to import %dx%d %s with "
908 "unsupported stride %d instead of %d\n",
909 prsc
->width0
, prsc
->height0
,
910 util_format_short_name(prsc
->format
),
915 } else if (!rsc
->tiled
) {
916 slice
->stride
= whandle
->stride
;
922 v3d_resource_destroy(pscreen
, prsc
);
927 v3d_update_shadow_texture(struct pipe_context
*pctx
,
928 struct pipe_sampler_view
*pview
)
930 struct v3d_context
*v3d
= v3d_context(pctx
);
931 struct v3d_sampler_view
*view
= v3d_sampler_view(pview
);
932 struct v3d_resource
*shadow
= v3d_resource(view
->texture
);
933 struct v3d_resource
*orig
= v3d_resource(pview
->texture
);
935 assert(view
->texture
!= pview
->texture
);
937 if (shadow
->writes
== orig
->writes
&& orig
->bo
->private)
940 perf_debug("Updating %dx%d@%d shadow for linear texture\n",
941 orig
->base
.width0
, orig
->base
.height0
,
942 pview
->u
.tex
.first_level
);
944 for (int i
= 0; i
<= shadow
->base
.last_level
; i
++) {
945 unsigned width
= u_minify(shadow
->base
.width0
, i
);
946 unsigned height
= u_minify(shadow
->base
.height0
, i
);
947 struct pipe_blit_info info
= {
949 .resource
= &shadow
->base
,
959 .format
= shadow
->base
.format
,
962 .resource
= &orig
->base
,
963 .level
= pview
->u
.tex
.first_level
+ i
,
972 .format
= orig
->base
.format
,
974 .mask
= util_format_get_mask(orig
->base
.format
),
976 pctx
->blit(pctx
, &info
);
979 shadow
->writes
= orig
->writes
;
982 static struct pipe_surface
*
983 v3d_create_surface(struct pipe_context
*pctx
,
984 struct pipe_resource
*ptex
,
985 const struct pipe_surface
*surf_tmpl
)
987 struct v3d_context
*v3d
= v3d_context(pctx
);
988 struct v3d_screen
*screen
= v3d
->screen
;
989 struct v3d_surface
*surface
= CALLOC_STRUCT(v3d_surface
);
990 struct v3d_resource
*rsc
= v3d_resource(ptex
);
995 assert(surf_tmpl
->u
.tex
.first_layer
== surf_tmpl
->u
.tex
.last_layer
);
997 struct pipe_surface
*psurf
= &surface
->base
;
998 unsigned level
= surf_tmpl
->u
.tex
.level
;
999 struct v3d_resource_slice
*slice
= &rsc
->slices
[level
];
1001 pipe_reference_init(&psurf
->reference
, 1);
1002 pipe_resource_reference(&psurf
->texture
, ptex
);
1004 psurf
->context
= pctx
;
1005 psurf
->format
= surf_tmpl
->format
;
1006 psurf
->width
= u_minify(ptex
->width0
, level
);
1007 psurf
->height
= u_minify(ptex
->height0
, level
);
1008 psurf
->u
.tex
.level
= level
;
1009 psurf
->u
.tex
.first_layer
= surf_tmpl
->u
.tex
.first_layer
;
1010 psurf
->u
.tex
.last_layer
= surf_tmpl
->u
.tex
.last_layer
;
1012 surface
->offset
= v3d_layer_offset(ptex
, level
,
1013 psurf
->u
.tex
.first_layer
);
1014 surface
->tiling
= slice
->tiling
;
1016 surface
->format
= v3d_get_rt_format(&screen
->devinfo
, psurf
->format
);
1018 const struct util_format_description
*desc
=
1019 util_format_description(psurf
->format
);
1021 surface
->swap_rb
= (desc
->swizzle
[0] == PIPE_SWIZZLE_Z
&&
1022 psurf
->format
!= PIPE_FORMAT_B5G6R5_UNORM
);
1024 if (util_format_is_depth_or_stencil(psurf
->format
)) {
1025 switch (psurf
->format
) {
1026 case PIPE_FORMAT_Z16_UNORM
:
1027 surface
->internal_type
= V3D_INTERNAL_TYPE_DEPTH_16
;
1029 case PIPE_FORMAT_Z32_FLOAT
:
1030 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT
:
1031 surface
->internal_type
= V3D_INTERNAL_TYPE_DEPTH_32F
;
1034 surface
->internal_type
= V3D_INTERNAL_TYPE_DEPTH_24
;
1038 v3d_get_internal_type_bpp_for_output_format(&screen
->devinfo
,
1041 surface
->internal_type
= type
;
1042 surface
->internal_bpp
= bpp
;
1045 if (surface
->tiling
== VC5_TILING_UIF_NO_XOR
||
1046 surface
->tiling
== VC5_TILING_UIF_XOR
) {
1047 surface
->padded_height_of_output_image_in_uif_blocks
=
1048 (slice
->padded_height
/
1049 (2 * v3d_utile_height(rsc
->cpp
)));
1052 if (rsc
->separate_stencil
) {
1053 surface
->separate_stencil
=
1054 v3d_create_surface(pctx
, &rsc
->separate_stencil
->base
,
1058 return &surface
->base
;
1062 v3d_surface_destroy(struct pipe_context
*pctx
, struct pipe_surface
*psurf
)
1064 struct v3d_surface
*surf
= v3d_surface(psurf
);
1066 if (surf
->separate_stencil
)
1067 pipe_surface_reference(&surf
->separate_stencil
, NULL
);
1069 pipe_resource_reference(&psurf
->texture
, NULL
);
1074 v3d_flush_resource(struct pipe_context
*pctx
, struct pipe_resource
*resource
)
1076 /* All calls to flush_resource are followed by a flush of the context,
1077 * so there's nothing to do.
1081 static enum pipe_format
1082 v3d_resource_get_internal_format(struct pipe_resource
*prsc
)
1084 return v3d_resource(prsc
)->internal_format
;
1088 v3d_resource_set_stencil(struct pipe_resource
*prsc
,
1089 struct pipe_resource
*stencil
)
1091 v3d_resource(prsc
)->separate_stencil
= v3d_resource(stencil
);
1094 static struct pipe_resource
*
1095 v3d_resource_get_stencil(struct pipe_resource
*prsc
)
1097 struct v3d_resource
*rsc
= v3d_resource(prsc
);
1099 return &rsc
->separate_stencil
->base
;
1102 static const struct u_transfer_vtbl transfer_vtbl
= {
1103 .resource_create
= v3d_resource_create
,
1104 .resource_destroy
= v3d_resource_destroy
,
1105 .transfer_map
= v3d_resource_transfer_map
,
1106 .transfer_unmap
= v3d_resource_transfer_unmap
,
1107 .transfer_flush_region
= u_default_transfer_flush_region
,
1108 .get_internal_format
= v3d_resource_get_internal_format
,
1109 .set_stencil
= v3d_resource_set_stencil
,
1110 .get_stencil
= v3d_resource_get_stencil
,
1114 v3d_resource_screen_init(struct pipe_screen
*pscreen
)
1116 pscreen
->resource_create_with_modifiers
=
1117 v3d_resource_create_with_modifiers
;
1118 pscreen
->resource_create
= u_transfer_helper_resource_create
;
1119 pscreen
->resource_from_handle
= v3d_resource_from_handle
;
1120 pscreen
->resource_get_handle
= v3d_resource_get_handle
;
1121 pscreen
->resource_destroy
= u_transfer_helper_resource_destroy
;
1122 pscreen
->transfer_helper
= u_transfer_helper_create(&transfer_vtbl
,
1128 v3d_resource_context_init(struct pipe_context
*pctx
)
1130 pctx
->transfer_map
= u_transfer_helper_transfer_map
;
1131 pctx
->transfer_flush_region
= u_transfer_helper_transfer_flush_region
;
1132 pctx
->transfer_unmap
= u_transfer_helper_transfer_unmap
;
1133 pctx
->buffer_subdata
= u_default_buffer_subdata
;
1134 pctx
->texture_subdata
= v3d_texture_subdata
;
1135 pctx
->create_surface
= v3d_create_surface
;
1136 pctx
->surface_destroy
= v3d_surface_destroy
;
1137 pctx
->resource_copy_region
= util_resource_copy_region
;
1138 pctx
->blit
= v3d_blit
;
1139 pctx
->generate_mipmap
= v3d_generate_mipmap
;
1140 pctx
->flush_resource
= v3d_flush_resource
;