v3d: remove redefine of VG(x)
[mesa.git] / src / gallium / drivers / v3d / v3d_resource.c
1 /*
2 * Copyright © 2014-2017 Broadcom
3 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
4 *
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:
11 *
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
14 * Software.
15 *
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
22 * IN THE SOFTWARE.
23 */
24
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"
35
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"
42
43 static void
44 v3d_debug_resource_layout(struct v3d_resource *rsc, const char *caller)
45 {
46 if (!(V3D_DEBUG & V3D_DEBUG_SURFACE))
47 return;
48
49 struct pipe_resource *prsc = &rsc->base;
50
51 if (prsc->target == PIPE_BUFFER) {
52 fprintf(stderr,
53 "rsc %s %p (format %s), %dx%d buffer @0x%08x-0x%08x\n",
54 caller, rsc,
55 util_format_short_name(prsc->format),
56 prsc->width0, prsc->height0,
57 rsc->bo->offset,
58 rsc->bo->offset + rsc->bo->size - 1);
59 return;
60 }
61
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^",
69 };
70
71 for (int i = 0; i <= prsc->last_level; i++) {
72 struct v3d_resource_slice *slice = &rsc->slices[i];
73
74 int level_width = slice->stride / rsc->cpp;
75 int level_height = slice->padded_height;
76 int level_depth =
77 u_minify(util_next_power_of_two(prsc->depth0), i);
78
79 fprintf(stderr,
80 "rsc %s %p (format %s), %dx%d: "
81 "level %d (%s) %dx%dx%d -> %dx%dx%d, stride %d@0x%08x\n",
82 caller, rsc,
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),
89 level_width,
90 level_height,
91 level_depth,
92 slice->stride,
93 rsc->bo->offset + slice->offset);
94 }
95 }
96
97 static bool
98 v3d_resource_bo_alloc(struct v3d_resource *rsc)
99 {
100 struct pipe_resource *prsc = &rsc->base;
101 struct pipe_screen *pscreen = prsc->screen;
102 struct v3d_bo *bo;
103
104 bo = v3d_bo_alloc(v3d_screen(pscreen), rsc->size, "resource");
105 if (bo) {
106 v3d_bo_unreference(&rsc->bo);
107 rsc->bo = bo;
108 v3d_debug_resource_layout(rsc, "alloc");
109 return true;
110 } else {
111 return false;
112 }
113 }
114
115 static void
116 v3d_resource_transfer_unmap(struct pipe_context *pctx,
117 struct pipe_transfer *ptrans)
118 {
119 struct v3d_context *v3d = v3d_context(pctx);
120 struct v3d_transfer *trans = v3d_transfer(ptrans);
121
122 if (trans->map) {
123 struct v3d_resource *rsc = v3d_resource(ptrans->resource);
124 struct v3d_resource_slice *slice = &rsc->slices[ptrans->level];
125
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,
130 ptrans->level,
131 ptrans->box.z + z);
132 v3d_store_tiled_image(dst,
133 slice->stride,
134 (trans->map +
135 ptrans->stride *
136 ptrans->box.height * z),
137 ptrans->stride,
138 slice->tiling, rsc->cpp,
139 slice->padded_height,
140 &ptrans->box);
141 }
142 }
143 free(trans->map);
144 }
145
146 pipe_resource_reference(&ptrans->resource, NULL);
147 slab_free(&v3d->transfer_pool, ptrans);
148 }
149
150 static void
151 v3d_map_usage_prep(struct pipe_context *pctx,
152 struct pipe_resource *prsc,
153 unsigned usage)
154 {
155 struct v3d_context *v3d = v3d_context(pctx);
156 struct v3d_resource *rsc = v3d_resource(prsc);
157
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
162 * or uniforms.
163 */
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;
168 } else {
169 /* If we failed to reallocate, flush users so that we
170 * don't violate any syncing requirements.
171 */
172 v3d_flush_jobs_reading_resource(v3d, prsc,
173 V3D_FLUSH_DEFAULT,
174 false);
175 }
176 } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
177 /* If we're writing and the buffer is being used by the CL, we
178 * have to flush the CL first. If we're only reading, we need
179 * to flush if the CL has written our buffer.
180 */
181 if (usage & PIPE_TRANSFER_WRITE) {
182 v3d_flush_jobs_reading_resource(v3d, prsc,
183 V3D_FLUSH_ALWAYS,
184 false);
185 } else {
186 v3d_flush_jobs_writing_resource(v3d, prsc,
187 V3D_FLUSH_ALWAYS,
188 false);
189 }
190 }
191
192 if (usage & PIPE_TRANSFER_WRITE) {
193 rsc->writes++;
194 rsc->initialized_buffers = ~0;
195 }
196 }
197
198 static void *
199 v3d_resource_transfer_map(struct pipe_context *pctx,
200 struct pipe_resource *prsc,
201 unsigned level, unsigned usage,
202 const struct pipe_box *box,
203 struct pipe_transfer **pptrans)
204 {
205 struct v3d_context *v3d = v3d_context(pctx);
206 struct v3d_resource *rsc = v3d_resource(prsc);
207 struct v3d_transfer *trans;
208 struct pipe_transfer *ptrans;
209 enum pipe_format format = prsc->format;
210 char *buf;
211
212 /* MSAA maps should have been handled by u_transfer_helper. */
213 assert(prsc->nr_samples <= 1);
214
215 /* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is
216 * being mapped.
217 */
218 if ((usage & PIPE_TRANSFER_DISCARD_RANGE) &&
219 !(usage & PIPE_TRANSFER_UNSYNCHRONIZED) &&
220 !(prsc->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) &&
221 prsc->last_level == 0 &&
222 prsc->width0 == box->width &&
223 prsc->height0 == box->height &&
224 prsc->depth0 == box->depth &&
225 prsc->array_size == 1 &&
226 rsc->bo->private) {
227 usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
228 }
229
230 v3d_map_usage_prep(pctx, prsc, usage);
231
232 trans = slab_alloc(&v3d->transfer_pool);
233 if (!trans)
234 return NULL;
235
236 /* XXX: Handle DONTBLOCK, DISCARD_RANGE, PERSISTENT, COHERENT. */
237
238 /* slab_alloc_st() doesn't zero: */
239 memset(trans, 0, sizeof(*trans));
240 ptrans = &trans->base;
241
242 pipe_resource_reference(&ptrans->resource, prsc);
243 ptrans->level = level;
244 ptrans->usage = usage;
245 ptrans->box = *box;
246
247 /* Note that the current kernel implementation is synchronous, so no
248 * need to do syncing stuff here yet.
249 */
250
251 if (usage & PIPE_TRANSFER_UNSYNCHRONIZED)
252 buf = v3d_bo_map_unsynchronized(rsc->bo);
253 else
254 buf = v3d_bo_map(rsc->bo);
255 if (!buf) {
256 fprintf(stderr, "Failed to map bo\n");
257 goto fail;
258 }
259
260 *pptrans = ptrans;
261
262 /* Our load/store routines work on entire compressed blocks. */
263 ptrans->box.x /= util_format_get_blockwidth(format);
264 ptrans->box.y /= util_format_get_blockheight(format);
265 ptrans->box.width = DIV_ROUND_UP(ptrans->box.width,
266 util_format_get_blockwidth(format));
267 ptrans->box.height = DIV_ROUND_UP(ptrans->box.height,
268 util_format_get_blockheight(format));
269
270 struct v3d_resource_slice *slice = &rsc->slices[level];
271 if (rsc->tiled) {
272 /* No direct mappings of tiled, since we need to manually
273 * tile/untile.
274 */
275 if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
276 return NULL;
277
278 ptrans->stride = ptrans->box.width * rsc->cpp;
279 ptrans->layer_stride = ptrans->stride * ptrans->box.height;
280
281 trans->map = malloc(ptrans->layer_stride * ptrans->box.depth);
282
283 if (usage & PIPE_TRANSFER_READ) {
284 for (int z = 0; z < ptrans->box.depth; z++) {
285 void *src = rsc->bo->map +
286 v3d_layer_offset(&rsc->base,
287 ptrans->level,
288 ptrans->box.z + z);
289 v3d_load_tiled_image((trans->map +
290 ptrans->stride *
291 ptrans->box.height * z),
292 ptrans->stride,
293 src,
294 slice->stride,
295 slice->tiling, rsc->cpp,
296 slice->padded_height,
297 &ptrans->box);
298 }
299 }
300 return trans->map;
301 } else {
302 ptrans->stride = slice->stride;
303 ptrans->layer_stride = rsc->cube_map_stride;
304
305 return buf + slice->offset +
306 ptrans->box.y * ptrans->stride +
307 ptrans->box.x * rsc->cpp +
308 ptrans->box.z * rsc->cube_map_stride;
309 }
310
311
312 fail:
313 v3d_resource_transfer_unmap(pctx, ptrans);
314 return NULL;
315 }
316
317 static void
318 v3d_texture_subdata(struct pipe_context *pctx,
319 struct pipe_resource *prsc,
320 unsigned level,
321 unsigned usage,
322 const struct pipe_box *box,
323 const void *data,
324 unsigned stride,
325 unsigned layer_stride)
326 {
327 struct v3d_resource *rsc = v3d_resource(prsc);
328 struct v3d_resource_slice *slice = &rsc->slices[level];
329
330 /* For a direct mapping, we can just take the u_transfer path. */
331 if (!rsc->tiled) {
332 return u_default_texture_subdata(pctx, prsc, level, usage, box,
333 data, stride, layer_stride);
334 }
335
336 /* Otherwise, map and store the texture data directly into the tiled
337 * texture. Note that gallium's texture_subdata may be called with
338 * obvious usage flags missing!
339 */
340 v3d_map_usage_prep(pctx, prsc, usage | (PIPE_TRANSFER_WRITE |
341 PIPE_TRANSFER_DISCARD_RANGE));
342
343 void *buf;
344 if (usage & PIPE_TRANSFER_UNSYNCHRONIZED)
345 buf = v3d_bo_map_unsynchronized(rsc->bo);
346 else
347 buf = v3d_bo_map(rsc->bo);
348
349 for (int i = 0; i < box->depth; i++) {
350 v3d_store_tiled_image(buf +
351 v3d_layer_offset(&rsc->base,
352 level,
353 box->z + i),
354 slice->stride,
355 (void *)data + layer_stride * i,
356 stride,
357 slice->tiling, rsc->cpp, slice->padded_height,
358 box);
359 }
360 }
361
362 static void
363 v3d_resource_destroy(struct pipe_screen *pscreen,
364 struct pipe_resource *prsc)
365 {
366 struct v3d_screen *screen = v3d_screen(pscreen);
367 struct v3d_resource *rsc = v3d_resource(prsc);
368
369 if (rsc->scanout)
370 renderonly_scanout_destroy(rsc->scanout, screen->ro);
371
372 v3d_bo_unreference(&rsc->bo);
373 free(rsc);
374 }
375
376 static bool
377 v3d_resource_get_handle(struct pipe_screen *pscreen,
378 struct pipe_context *pctx,
379 struct pipe_resource *prsc,
380 struct winsys_handle *whandle,
381 unsigned usage)
382 {
383 struct v3d_screen *screen = v3d_screen(pscreen);
384 struct v3d_resource *rsc = v3d_resource(prsc);
385 struct v3d_bo *bo = rsc->bo;
386
387 whandle->stride = rsc->slices[0].stride;
388 whandle->offset = 0;
389
390 /* If we're passing some reference to our BO out to some other part of
391 * the system, then we can't do any optimizations about only us being
392 * the ones seeing it (like BO caching).
393 */
394 bo->private = false;
395
396 if (rsc->tiled) {
397 /* A shared tiled buffer should always be allocated as UIF,
398 * not UBLINEAR or LT.
399 */
400 assert(rsc->slices[0].tiling == VC5_TILING_UIF_XOR ||
401 rsc->slices[0].tiling == VC5_TILING_UIF_NO_XOR);
402 whandle->modifier = DRM_FORMAT_MOD_BROADCOM_UIF;
403 } else {
404 whandle->modifier = DRM_FORMAT_MOD_LINEAR;
405 }
406
407 switch (whandle->type) {
408 case WINSYS_HANDLE_TYPE_SHARED:
409 return v3d_bo_flink(bo, &whandle->handle);
410 case WINSYS_HANDLE_TYPE_KMS:
411 if (screen->ro) {
412 assert(rsc->scanout);
413 bool ok = renderonly_get_handle(rsc->scanout, whandle);
414 whandle->stride = rsc->slices[0].stride;
415 return ok;
416 }
417 whandle->handle = bo->handle;
418 return true;
419 case WINSYS_HANDLE_TYPE_FD:
420 whandle->handle = v3d_bo_get_dmabuf(bo);
421 return whandle->handle != -1;
422 }
423
424 return false;
425 }
426
427 #define PAGE_UB_ROWS (VC5_UIFCFG_PAGE_SIZE / VC5_UIFBLOCK_ROW_SIZE)
428 #define PAGE_UB_ROWS_TIMES_1_5 ((PAGE_UB_ROWS * 3) >> 1)
429 #define PAGE_CACHE_UB_ROWS (VC5_PAGE_CACHE_SIZE / VC5_UIFBLOCK_ROW_SIZE)
430 #define PAGE_CACHE_MINUS_1_5_UB_ROWS (PAGE_CACHE_UB_ROWS - PAGE_UB_ROWS_TIMES_1_5)
431
432 /**
433 * Computes the HW's UIFblock padding for a given height/cpp.
434 *
435 * The goal of the padding is to keep pages of the same color (bank number) at
436 * least half a page away from each other vertically when crossing between
437 * between columns of UIF blocks.
438 */
439 static uint32_t
440 v3d_get_ub_pad(struct v3d_resource *rsc, uint32_t height)
441 {
442 uint32_t utile_h = v3d_utile_height(rsc->cpp);
443 uint32_t uif_block_h = utile_h * 2;
444 uint32_t height_ub = height / uif_block_h;
445
446 uint32_t height_offset_in_pc = height_ub % PAGE_CACHE_UB_ROWS;
447
448 /* For the perfectly-aligned-for-UIF-XOR case, don't add any pad. */
449 if (height_offset_in_pc == 0)
450 return 0;
451
452 /* Try padding up to where we're offset by at least half a page. */
453 if (height_offset_in_pc < PAGE_UB_ROWS_TIMES_1_5) {
454 /* If we fit entirely in the page cache, don't pad. */
455 if (height_ub < PAGE_CACHE_UB_ROWS)
456 return 0;
457 else
458 return PAGE_UB_ROWS_TIMES_1_5 - height_offset_in_pc;
459 }
460
461 /* If we're close to being aligned to page cache size, then round up
462 * and rely on XOR.
463 */
464 if (height_offset_in_pc > PAGE_CACHE_MINUS_1_5_UB_ROWS)
465 return PAGE_CACHE_UB_ROWS - height_offset_in_pc;
466
467 /* Otherwise, we're far enough away (top and bottom) to not need any
468 * padding.
469 */
470 return 0;
471 }
472
473 static void
474 v3d_setup_slices(struct v3d_resource *rsc, uint32_t winsys_stride,
475 bool uif_top)
476 {
477 struct pipe_resource *prsc = &rsc->base;
478 uint32_t width = prsc->width0;
479 uint32_t height = prsc->height0;
480 uint32_t depth = prsc->depth0;
481 /* Note that power-of-two padding is based on level 1. These are not
482 * equivalent to just util_next_power_of_two(dimension), because at a
483 * level 0 dimension of 9, the level 1 power-of-two padded value is 4,
484 * not 8.
485 */
486 uint32_t pot_width = 2 * util_next_power_of_two(u_minify(width, 1));
487 uint32_t pot_height = 2 * util_next_power_of_two(u_minify(height, 1));
488 uint32_t pot_depth = 2 * util_next_power_of_two(u_minify(depth, 1));
489 uint32_t offset = 0;
490 uint32_t utile_w = v3d_utile_width(rsc->cpp);
491 uint32_t utile_h = v3d_utile_height(rsc->cpp);
492 uint32_t uif_block_w = utile_w * 2;
493 uint32_t uif_block_h = utile_h * 2;
494 uint32_t block_width = util_format_get_blockwidth(prsc->format);
495 uint32_t block_height = util_format_get_blockheight(prsc->format);
496 bool msaa = prsc->nr_samples > 1;
497
498 /* MSAA textures/renderbuffers are always laid out as single-level
499 * UIF.
500 */
501 uif_top |= msaa;
502
503 /* Check some easy mistakes to make in a resource_create() call that
504 * will break our setup.
505 */
506 assert(prsc->array_size != 0);
507 assert(prsc->depth0 != 0);
508
509 for (int i = prsc->last_level; i >= 0; i--) {
510 struct v3d_resource_slice *slice = &rsc->slices[i];
511
512 uint32_t level_width, level_height, level_depth;
513 if (i < 2) {
514 level_width = u_minify(width, i);
515 level_height = u_minify(height, i);
516 } else {
517 level_width = u_minify(pot_width, i);
518 level_height = u_minify(pot_height, i);
519 }
520 if (i < 1)
521 level_depth = u_minify(depth, i);
522 else
523 level_depth = u_minify(pot_depth, i);
524
525 if (msaa) {
526 level_width *= 2;
527 level_height *= 2;
528 }
529
530 level_width = DIV_ROUND_UP(level_width, block_width);
531 level_height = DIV_ROUND_UP(level_height, block_height);
532
533 if (!rsc->tiled) {
534 slice->tiling = VC5_TILING_RASTER;
535 if (prsc->target == PIPE_TEXTURE_1D)
536 level_width = align(level_width, 64 / rsc->cpp);
537 } else {
538 if ((i != 0 || !uif_top) &&
539 (level_width <= utile_w ||
540 level_height <= utile_h)) {
541 slice->tiling = VC5_TILING_LINEARTILE;
542 level_width = align(level_width, utile_w);
543 level_height = align(level_height, utile_h);
544 } else if ((i != 0 || !uif_top) &&
545 level_width <= uif_block_w) {
546 slice->tiling = VC5_TILING_UBLINEAR_1_COLUMN;
547 level_width = align(level_width, uif_block_w);
548 level_height = align(level_height, uif_block_h);
549 } else if ((i != 0 || !uif_top) &&
550 level_width <= 2 * uif_block_w) {
551 slice->tiling = VC5_TILING_UBLINEAR_2_COLUMN;
552 level_width = align(level_width, 2 * uif_block_w);
553 level_height = align(level_height, uif_block_h);
554 } else {
555 /* We align the width to a 4-block column of
556 * UIF blocks, but we only align height to UIF
557 * blocks.
558 */
559 level_width = align(level_width,
560 4 * uif_block_w);
561 level_height = align(level_height,
562 uif_block_h);
563
564 slice->ub_pad = v3d_get_ub_pad(rsc,
565 level_height);
566 level_height += slice->ub_pad * uif_block_h;
567
568 /* If the padding set us to to be aligned to
569 * the page cache size, then the HW will use
570 * the XOR bit on odd columns to get us
571 * perfectly misaligned
572 */
573 if ((level_height / uif_block_h) %
574 (VC5_PAGE_CACHE_SIZE /
575 VC5_UIFBLOCK_ROW_SIZE) == 0) {
576 slice->tiling = VC5_TILING_UIF_XOR;
577 } else {
578 slice->tiling = VC5_TILING_UIF_NO_XOR;
579 }
580 }
581 }
582
583 slice->offset = offset;
584 if (winsys_stride)
585 slice->stride = winsys_stride;
586 else
587 slice->stride = level_width * rsc->cpp;
588 slice->padded_height = level_height;
589 slice->size = level_height * slice->stride;
590
591 uint32_t slice_total_size = slice->size * level_depth;
592
593 /* The HW aligns level 1's base to a page if any of level 1 or
594 * below could be UIF XOR. The lower levels then inherit the
595 * alignment for as long as necesary, thanks to being power of
596 * two aligned.
597 */
598 if (i == 1 &&
599 level_width > 4 * uif_block_w &&
600 level_height > PAGE_CACHE_MINUS_1_5_UB_ROWS * uif_block_h) {
601 slice_total_size = align(slice_total_size,
602 VC5_UIFCFG_PAGE_SIZE);
603 }
604
605 offset += slice_total_size;
606
607 }
608 rsc->size = offset;
609
610 /* UIF/UBLINEAR levels need to be aligned to UIF-blocks, and LT only
611 * needs to be aligned to utile boundaries. Since tiles are laid out
612 * from small to big in memory, we need to align the later UIF slices
613 * to UIF blocks, if they were preceded by non-UIF-block-aligned LT
614 * slices.
615 *
616 * We additionally align to 4k, which improves UIF XOR performance.
617 */
618 uint32_t page_align_offset = (align(rsc->slices[0].offset, 4096) -
619 rsc->slices[0].offset);
620 if (page_align_offset) {
621 rsc->size += page_align_offset;
622 for (int i = 0; i <= prsc->last_level; i++)
623 rsc->slices[i].offset += page_align_offset;
624 }
625
626 /* Arrays and cube textures have a stride which is the distance from
627 * one full mipmap tree to the next (64b aligned). For 3D textures,
628 * we need to program the stride between slices of miplevel 0.
629 */
630 if (prsc->target != PIPE_TEXTURE_3D) {
631 rsc->cube_map_stride = align(rsc->slices[0].offset +
632 rsc->slices[0].size, 64);
633 rsc->size += rsc->cube_map_stride * (prsc->array_size - 1);
634 } else {
635 rsc->cube_map_stride = rsc->slices[0].size;
636 }
637 }
638
639 uint32_t
640 v3d_layer_offset(struct pipe_resource *prsc, uint32_t level, uint32_t layer)
641 {
642 struct v3d_resource *rsc = v3d_resource(prsc);
643 struct v3d_resource_slice *slice = &rsc->slices[level];
644
645 if (prsc->target == PIPE_TEXTURE_3D)
646 return slice->offset + layer * slice->size;
647 else
648 return slice->offset + layer * rsc->cube_map_stride;
649 }
650
651 static struct v3d_resource *
652 v3d_resource_setup(struct pipe_screen *pscreen,
653 const struct pipe_resource *tmpl)
654 {
655 struct v3d_screen *screen = v3d_screen(pscreen);
656 struct v3d_resource *rsc = CALLOC_STRUCT(v3d_resource);
657 if (!rsc)
658 return NULL;
659 struct pipe_resource *prsc = &rsc->base;
660
661 *prsc = *tmpl;
662
663 pipe_reference_init(&prsc->reference, 1);
664 prsc->screen = pscreen;
665
666 if (prsc->nr_samples <= 1 ||
667 screen->devinfo.ver >= 40 ||
668 util_format_is_depth_or_stencil(prsc->format)) {
669 rsc->cpp = util_format_get_blocksize(prsc->format);
670 if (screen->devinfo.ver < 40 && prsc->nr_samples > 1)
671 rsc->cpp *= prsc->nr_samples;
672 } else {
673 assert(v3d_rt_format_supported(&screen->devinfo, prsc->format));
674 uint32_t output_image_format =
675 v3d_get_rt_format(&screen->devinfo, prsc->format);
676 uint32_t internal_type;
677 uint32_t internal_bpp;
678 v3d_get_internal_type_bpp_for_output_format(&screen->devinfo,
679 output_image_format,
680 &internal_type,
681 &internal_bpp);
682 switch (internal_bpp) {
683 case V3D_INTERNAL_BPP_32:
684 rsc->cpp = 4;
685 break;
686 case V3D_INTERNAL_BPP_64:
687 rsc->cpp = 8;
688 break;
689 case V3D_INTERNAL_BPP_128:
690 rsc->cpp = 16;
691 break;
692 }
693 }
694
695 assert(rsc->cpp);
696
697 return rsc;
698 }
699
700 static struct pipe_resource *
701 v3d_resource_create_with_modifiers(struct pipe_screen *pscreen,
702 const struct pipe_resource *tmpl,
703 const uint64_t *modifiers,
704 int count)
705 {
706 struct v3d_screen *screen = v3d_screen(pscreen);
707
708 bool linear_ok = drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count);
709 struct v3d_resource *rsc = v3d_resource_setup(pscreen, tmpl);
710 struct pipe_resource *prsc = &rsc->base;
711 /* Use a tiled layout if we can, for better 3D performance. */
712 bool should_tile = true;
713
714 /* VBOs/PBOs are untiled (and 1 height). */
715 if (tmpl->target == PIPE_BUFFER)
716 should_tile = false;
717
718 /* Cursors are always linear, and the user can request linear as well.
719 */
720 if (tmpl->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR))
721 should_tile = false;
722
723 /* 1D and 1D_ARRAY textures are always raster-order. */
724 if (tmpl->target == PIPE_TEXTURE_1D ||
725 tmpl->target == PIPE_TEXTURE_1D_ARRAY)
726 should_tile = false;
727
728 /* Scanout BOs for simulator need to be linear for interaction with
729 * i965.
730 */
731 if (using_v3d_simulator &&
732 tmpl->bind & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT))
733 should_tile = false;
734
735 /* If using the old-school SCANOUT flag, we don't know what the screen
736 * might support other than linear. Just force linear.
737 */
738 if (tmpl->bind & PIPE_BIND_SCANOUT)
739 should_tile = false;
740
741 /* No user-specified modifier; determine our own. */
742 if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
743 linear_ok = true;
744 rsc->tiled = should_tile;
745 } else if (should_tile &&
746 drm_find_modifier(DRM_FORMAT_MOD_BROADCOM_UIF,
747 modifiers, count)) {
748 rsc->tiled = true;
749 } else if (linear_ok) {
750 rsc->tiled = false;
751 } else {
752 fprintf(stderr, "Unsupported modifier requested\n");
753 goto fail;
754 }
755
756 rsc->internal_format = prsc->format;
757
758 v3d_setup_slices(rsc, 0, tmpl->bind & PIPE_BIND_SHARED);
759
760 /* If we're in a renderonly setup, use the other device to perform our
761 * allocation and just import it to v3d. The other device may be
762 * using CMA, and V3D can import from CMA but doesn't do CMA
763 * allocations on its own.
764 *
765 * We always allocate this way for SHARED, because get_handle will
766 * need a resource on the display fd.
767 */
768 if (screen->ro && (tmpl->bind & (PIPE_BIND_SCANOUT |
769 PIPE_BIND_SHARED))) {
770 struct winsys_handle handle;
771 struct pipe_resource scanout_tmpl = {
772 .target = prsc->target,
773 .format = PIPE_FORMAT_RGBA8888_UNORM,
774 .width0 = 1024, /* one page */
775 .height0 = align(rsc->size, 4096) / 4096,
776 .depth0 = 1,
777 .array_size = 1,
778 };
779
780 rsc->scanout =
781 renderonly_scanout_for_resource(&scanout_tmpl,
782 screen->ro,
783 &handle);
784
785 if (!rsc->scanout) {
786 fprintf(stderr, "Failed to create scanout resource\n");
787 return NULL;
788 }
789 assert(handle.type == WINSYS_HANDLE_TYPE_FD);
790 rsc->bo = v3d_bo_open_dmabuf(screen, handle.handle);
791 close(handle.handle);
792
793 if (!rsc->bo)
794 goto fail;
795
796 v3d_debug_resource_layout(rsc, "renderonly");
797
798 return prsc;
799 } else {
800 if (!v3d_resource_bo_alloc(rsc))
801 goto fail;
802 }
803
804 return prsc;
805 fail:
806 v3d_resource_destroy(pscreen, prsc);
807 return NULL;
808 }
809
810 struct pipe_resource *
811 v3d_resource_create(struct pipe_screen *pscreen,
812 const struct pipe_resource *tmpl)
813 {
814 const uint64_t mod = DRM_FORMAT_MOD_INVALID;
815 return v3d_resource_create_with_modifiers(pscreen, tmpl, &mod, 1);
816 }
817
818 static struct pipe_resource *
819 v3d_resource_from_handle(struct pipe_screen *pscreen,
820 const struct pipe_resource *tmpl,
821 struct winsys_handle *whandle,
822 unsigned usage)
823 {
824 struct v3d_screen *screen = v3d_screen(pscreen);
825 struct v3d_resource *rsc = v3d_resource_setup(pscreen, tmpl);
826 struct pipe_resource *prsc = &rsc->base;
827 struct v3d_resource_slice *slice = &rsc->slices[0];
828
829 if (!rsc)
830 return NULL;
831
832 switch (whandle->modifier) {
833 case DRM_FORMAT_MOD_LINEAR:
834 rsc->tiled = false;
835 break;
836 case DRM_FORMAT_MOD_BROADCOM_UIF:
837 rsc->tiled = true;
838 break;
839 case DRM_FORMAT_MOD_INVALID:
840 rsc->tiled = screen->ro == NULL;
841 break;
842 default:
843 fprintf(stderr,
844 "Attempt to import unsupported modifier 0x%llx\n",
845 (long long)whandle->modifier);
846 goto fail;
847 }
848
849 switch (whandle->type) {
850 case WINSYS_HANDLE_TYPE_SHARED:
851 rsc->bo = v3d_bo_open_name(screen, whandle->handle);
852 break;
853 case WINSYS_HANDLE_TYPE_FD:
854 rsc->bo = v3d_bo_open_dmabuf(screen, whandle->handle);
855 break;
856 default:
857 fprintf(stderr,
858 "Attempt to import unsupported handle type %d\n",
859 whandle->type);
860 goto fail;
861 }
862
863 if (!rsc->bo)
864 goto fail;
865
866 rsc->internal_format = prsc->format;
867
868 v3d_setup_slices(rsc, whandle->stride, true);
869 v3d_debug_resource_layout(rsc, "import");
870
871 if (whandle->offset != 0) {
872 if (rsc->tiled) {
873 fprintf(stderr,
874 "Attempt to import unsupported winsys offset %u\n",
875 whandle->offset);
876 goto fail;
877 }
878 rsc->slices[0].offset += whandle->offset;
879
880 if (rsc->slices[0].offset + rsc->slices[0].size >
881 rsc->bo->size) {
882 fprintf(stderr, "Attempt to import "
883 "with overflowing offset (%d + %d > %d)\n",
884 whandle->offset,
885 rsc->slices[0].size,
886 rsc->bo->size);
887 goto fail;
888 }
889 }
890
891 if (screen->ro) {
892 /* Make sure that renderonly has a handle to our buffer in the
893 * display's fd, so that a later renderonly_get_handle()
894 * returns correct handles or GEM names.
895 */
896 rsc->scanout =
897 renderonly_create_gpu_import_for_resource(prsc,
898 screen->ro,
899 NULL);
900 if (!rsc->scanout) {
901 fprintf(stderr, "Failed to create scanout resource.\n");
902 goto fail;
903 }
904 }
905
906 if (rsc->tiled && whandle->stride != slice->stride) {
907 static bool warned = false;
908 if (!warned) {
909 warned = true;
910 fprintf(stderr,
911 "Attempting to import %dx%d %s with "
912 "unsupported stride %d instead of %d\n",
913 prsc->width0, prsc->height0,
914 util_format_short_name(prsc->format),
915 whandle->stride,
916 slice->stride);
917 }
918 goto fail;
919 } else if (!rsc->tiled) {
920 slice->stride = whandle->stride;
921 }
922
923 return prsc;
924
925 fail:
926 v3d_resource_destroy(pscreen, prsc);
927 return NULL;
928 }
929
930 void
931 v3d_update_shadow_texture(struct pipe_context *pctx,
932 struct pipe_sampler_view *pview)
933 {
934 struct v3d_context *v3d = v3d_context(pctx);
935 struct v3d_sampler_view *view = v3d_sampler_view(pview);
936 struct v3d_resource *shadow = v3d_resource(view->texture);
937 struct v3d_resource *orig = v3d_resource(pview->texture);
938
939 assert(view->texture != pview->texture);
940
941 if (shadow->writes == orig->writes && orig->bo->private)
942 return;
943
944 perf_debug("Updating %dx%d@%d shadow for linear texture\n",
945 orig->base.width0, orig->base.height0,
946 pview->u.tex.first_level);
947
948 for (int i = 0; i <= shadow->base.last_level; i++) {
949 unsigned width = u_minify(shadow->base.width0, i);
950 unsigned height = u_minify(shadow->base.height0, i);
951 struct pipe_blit_info info = {
952 .dst = {
953 .resource = &shadow->base,
954 .level = i,
955 .box = {
956 .x = 0,
957 .y = 0,
958 .z = 0,
959 .width = width,
960 .height = height,
961 .depth = 1,
962 },
963 .format = shadow->base.format,
964 },
965 .src = {
966 .resource = &orig->base,
967 .level = pview->u.tex.first_level + i,
968 .box = {
969 .x = 0,
970 .y = 0,
971 .z = 0,
972 .width = width,
973 .height = height,
974 .depth = 1,
975 },
976 .format = orig->base.format,
977 },
978 .mask = util_format_get_mask(orig->base.format),
979 };
980 pctx->blit(pctx, &info);
981 }
982
983 shadow->writes = orig->writes;
984 }
985
986 static struct pipe_surface *
987 v3d_create_surface(struct pipe_context *pctx,
988 struct pipe_resource *ptex,
989 const struct pipe_surface *surf_tmpl)
990 {
991 struct v3d_context *v3d = v3d_context(pctx);
992 struct v3d_screen *screen = v3d->screen;
993 struct v3d_surface *surface = CALLOC_STRUCT(v3d_surface);
994 struct v3d_resource *rsc = v3d_resource(ptex);
995
996 if (!surface)
997 return NULL;
998
999 struct pipe_surface *psurf = &surface->base;
1000 unsigned level = surf_tmpl->u.tex.level;
1001 struct v3d_resource_slice *slice = &rsc->slices[level];
1002
1003 pipe_reference_init(&psurf->reference, 1);
1004 pipe_resource_reference(&psurf->texture, ptex);
1005
1006 psurf->context = pctx;
1007 psurf->format = surf_tmpl->format;
1008 psurf->width = u_minify(ptex->width0, level);
1009 psurf->height = u_minify(ptex->height0, level);
1010 psurf->u.tex.level = level;
1011 psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
1012 psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
1013
1014 surface->offset = v3d_layer_offset(ptex, level,
1015 psurf->u.tex.first_layer);
1016 surface->tiling = slice->tiling;
1017
1018 surface->format = v3d_get_rt_format(&screen->devinfo, psurf->format);
1019
1020 const struct util_format_description *desc =
1021 util_format_description(psurf->format);
1022
1023 surface->swap_rb = (desc->swizzle[0] == PIPE_SWIZZLE_Z &&
1024 psurf->format != PIPE_FORMAT_B5G6R5_UNORM);
1025
1026 if (util_format_is_depth_or_stencil(psurf->format)) {
1027 switch (psurf->format) {
1028 case PIPE_FORMAT_Z16_UNORM:
1029 surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_16;
1030 break;
1031 case PIPE_FORMAT_Z32_FLOAT:
1032 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
1033 surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_32F;
1034 break;
1035 default:
1036 surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_24;
1037 }
1038 } else {
1039 uint32_t bpp, type;
1040 v3d_get_internal_type_bpp_for_output_format(&screen->devinfo,
1041 surface->format,
1042 &type, &bpp);
1043 surface->internal_type = type;
1044 surface->internal_bpp = bpp;
1045 }
1046
1047 if (surface->tiling == VC5_TILING_UIF_NO_XOR ||
1048 surface->tiling == VC5_TILING_UIF_XOR) {
1049 surface->padded_height_of_output_image_in_uif_blocks =
1050 (slice->padded_height /
1051 (2 * v3d_utile_height(rsc->cpp)));
1052 }
1053
1054 if (rsc->separate_stencil) {
1055 surface->separate_stencil =
1056 v3d_create_surface(pctx, &rsc->separate_stencil->base,
1057 surf_tmpl);
1058 }
1059
1060 return &surface->base;
1061 }
1062
1063 static void
1064 v3d_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
1065 {
1066 struct v3d_surface *surf = v3d_surface(psurf);
1067
1068 if (surf->separate_stencil)
1069 pipe_surface_reference(&surf->separate_stencil, NULL);
1070
1071 pipe_resource_reference(&psurf->texture, NULL);
1072 FREE(psurf);
1073 }
1074
1075 static void
1076 v3d_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
1077 {
1078 /* All calls to flush_resource are followed by a flush of the context,
1079 * so there's nothing to do.
1080 */
1081 }
1082
1083 static enum pipe_format
1084 v3d_resource_get_internal_format(struct pipe_resource *prsc)
1085 {
1086 return v3d_resource(prsc)->internal_format;
1087 }
1088
1089 static void
1090 v3d_resource_set_stencil(struct pipe_resource *prsc,
1091 struct pipe_resource *stencil)
1092 {
1093 v3d_resource(prsc)->separate_stencil = v3d_resource(stencil);
1094 }
1095
1096 static struct pipe_resource *
1097 v3d_resource_get_stencil(struct pipe_resource *prsc)
1098 {
1099 struct v3d_resource *rsc = v3d_resource(prsc);
1100
1101 return &rsc->separate_stencil->base;
1102 }
1103
1104 static const struct u_transfer_vtbl transfer_vtbl = {
1105 .resource_create = v3d_resource_create,
1106 .resource_destroy = v3d_resource_destroy,
1107 .transfer_map = v3d_resource_transfer_map,
1108 .transfer_unmap = v3d_resource_transfer_unmap,
1109 .transfer_flush_region = u_default_transfer_flush_region,
1110 .get_internal_format = v3d_resource_get_internal_format,
1111 .set_stencil = v3d_resource_set_stencil,
1112 .get_stencil = v3d_resource_get_stencil,
1113 };
1114
1115 void
1116 v3d_resource_screen_init(struct pipe_screen *pscreen)
1117 {
1118 pscreen->resource_create_with_modifiers =
1119 v3d_resource_create_with_modifiers;
1120 pscreen->resource_create = u_transfer_helper_resource_create;
1121 pscreen->resource_from_handle = v3d_resource_from_handle;
1122 pscreen->resource_get_handle = v3d_resource_get_handle;
1123 pscreen->resource_destroy = u_transfer_helper_resource_destroy;
1124 pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl,
1125 true, false,
1126 true, true);
1127 }
1128
1129 void
1130 v3d_resource_context_init(struct pipe_context *pctx)
1131 {
1132 pctx->transfer_map = u_transfer_helper_transfer_map;
1133 pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;
1134 pctx->transfer_unmap = u_transfer_helper_transfer_unmap;
1135 pctx->buffer_subdata = u_default_buffer_subdata;
1136 pctx->texture_subdata = v3d_texture_subdata;
1137 pctx->create_surface = v3d_create_surface;
1138 pctx->surface_destroy = v3d_surface_destroy;
1139 pctx->resource_copy_region = util_resource_copy_region;
1140 pctx->blit = v3d_blit;
1141 pctx->generate_mipmap = v3d_generate_mipmap;
1142 pctx->flush_resource = v3d_flush_resource;
1143 }