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