Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/lima/lima_resource.c
4565 views
1
/*
2
* Copyright (c) 2017-2019 Lima Project
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sub license,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
10
*
11
* The above copyright notice and this permission notice (including the
12
* next paragraph) shall be included in all copies or substantial portions
13
* of the Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
* DEALINGS IN THE SOFTWARE.
22
*
23
*/
24
25
#include "util/u_memory.h"
26
#include "util/u_blitter.h"
27
#include "util/format/u_format.h"
28
#include "util/u_inlines.h"
29
#include "util/u_math.h"
30
#include "util/u_debug.h"
31
#include "util/u_transfer.h"
32
#include "util/u_surface.h"
33
#include "util/hash_table.h"
34
#include "util/ralloc.h"
35
#include "util/u_drm.h"
36
#include "renderonly/renderonly.h"
37
38
#include "frontend/drm_driver.h"
39
40
#include "drm-uapi/drm_fourcc.h"
41
#include "drm-uapi/lima_drm.h"
42
43
#include "lima_screen.h"
44
#include "lima_context.h"
45
#include "lima_resource.h"
46
#include "lima_bo.h"
47
#include "lima_util.h"
48
49
#include "pan_minmax_cache.h"
50
#include "pan_tiling.h"
51
52
static struct pipe_resource *
53
lima_resource_create_scanout(struct pipe_screen *pscreen,
54
const struct pipe_resource *templat,
55
unsigned width, unsigned height)
56
{
57
struct lima_screen *screen = lima_screen(pscreen);
58
struct renderonly_scanout *scanout;
59
struct winsys_handle handle;
60
struct pipe_resource *pres;
61
62
struct pipe_resource scanout_templat = *templat;
63
scanout_templat.width0 = width;
64
scanout_templat.height0 = height;
65
scanout_templat.screen = pscreen;
66
67
scanout = renderonly_scanout_for_resource(&scanout_templat,
68
screen->ro, &handle);
69
if (!scanout)
70
return NULL;
71
72
assert(handle.type == WINSYS_HANDLE_TYPE_FD);
73
pres = pscreen->resource_from_handle(pscreen, templat, &handle,
74
PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
75
76
close(handle.handle);
77
if (!pres) {
78
renderonly_scanout_destroy(scanout, screen->ro);
79
return NULL;
80
}
81
82
struct lima_resource *res = lima_resource(pres);
83
res->scanout = scanout;
84
85
return pres;
86
}
87
88
static uint32_t
89
setup_miptree(struct lima_resource *res,
90
unsigned width0, unsigned height0,
91
bool should_align_dimensions)
92
{
93
struct pipe_resource *pres = &res->base;
94
unsigned level;
95
unsigned width = width0;
96
unsigned height = height0;
97
unsigned depth = pres->depth0;
98
uint32_t size = 0;
99
100
for (level = 0; level <= pres->last_level; level++) {
101
uint32_t actual_level_size;
102
uint32_t stride;
103
unsigned aligned_width;
104
unsigned aligned_height;
105
106
if (should_align_dimensions) {
107
aligned_width = align(width, 16);
108
aligned_height = align(height, 16);
109
} else {
110
aligned_width = width;
111
aligned_height = height;
112
}
113
114
stride = util_format_get_stride(pres->format, aligned_width);
115
actual_level_size = stride *
116
util_format_get_nblocksy(pres->format, aligned_height) *
117
pres->array_size * depth;
118
119
res->levels[level].width = aligned_width;
120
res->levels[level].stride = stride;
121
res->levels[level].offset = size;
122
res->levels[level].layer_stride = util_format_get_stride(pres->format, align(width, 16)) * align(height, 16);
123
124
if (util_format_is_compressed(pres->format))
125
res->levels[level].layer_stride /= 4;
126
127
/* The start address of each level except the last level
128
* must be 64-aligned in order to be able to pass the
129
* addresses to the hardware. */
130
if (level != pres->last_level)
131
size += align(actual_level_size, 64);
132
else
133
size += actual_level_size; /* Save some memory */
134
135
width = u_minify(width, 1);
136
height = u_minify(height, 1);
137
depth = u_minify(depth, 1);
138
}
139
140
return size;
141
}
142
143
static struct pipe_resource *
144
lima_resource_create_bo(struct pipe_screen *pscreen,
145
const struct pipe_resource *templat,
146
unsigned width, unsigned height,
147
bool should_align_dimensions)
148
{
149
struct lima_screen *screen = lima_screen(pscreen);
150
struct lima_resource *res;
151
struct pipe_resource *pres;
152
153
res = CALLOC_STRUCT(lima_resource);
154
if (!res)
155
return NULL;
156
157
res->base = *templat;
158
res->base.screen = pscreen;
159
pipe_reference_init(&res->base.reference, 1);
160
161
pres = &res->base;
162
163
uint32_t size = setup_miptree(res, width, height, should_align_dimensions);
164
size = align(size, LIMA_PAGE_SIZE);
165
166
res->bo = lima_bo_create(screen, size, 0);
167
if (!res->bo) {
168
FREE(res);
169
return NULL;
170
}
171
172
return pres;
173
}
174
175
static struct pipe_resource *
176
_lima_resource_create_with_modifiers(struct pipe_screen *pscreen,
177
const struct pipe_resource *templat,
178
const uint64_t *modifiers,
179
int count)
180
{
181
struct lima_screen *screen = lima_screen(pscreen);
182
bool should_tile = lima_debug & LIMA_DEBUG_NO_TILING ? false : true;
183
unsigned width, height;
184
bool should_align_dimensions;
185
bool has_user_modifiers = true;
186
187
if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)
188
has_user_modifiers = false;
189
190
/* VBOs/PBOs are untiled (and 1 height). */
191
if (templat->target == PIPE_BUFFER)
192
should_tile = false;
193
194
if (templat->bind & (PIPE_BIND_LINEAR | PIPE_BIND_SCANOUT))
195
should_tile = false;
196
197
/* If there's no user modifiers and buffer is shared we use linear */
198
if (!has_user_modifiers && (templat->bind & PIPE_BIND_SHARED))
199
should_tile = false;
200
201
if (has_user_modifiers &&
202
!drm_find_modifier(DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED,
203
modifiers, count))
204
should_tile = false;
205
206
if (should_tile || (templat->bind & PIPE_BIND_RENDER_TARGET) ||
207
(templat->bind & PIPE_BIND_DEPTH_STENCIL)) {
208
should_align_dimensions = true;
209
width = align(templat->width0, 16);
210
height = align(templat->height0, 16);
211
}
212
else {
213
should_align_dimensions = false;
214
width = templat->width0;
215
height = templat->height0;
216
}
217
218
struct pipe_resource *pres;
219
if (screen->ro && (templat->bind & PIPE_BIND_SCANOUT))
220
pres = lima_resource_create_scanout(pscreen, templat, width, height);
221
else
222
pres = lima_resource_create_bo(pscreen, templat, width, height,
223
should_align_dimensions);
224
225
if (pres) {
226
struct lima_resource *res = lima_resource(pres);
227
res->tiled = should_tile;
228
229
if (templat->bind & PIPE_BIND_INDEX_BUFFER)
230
res->index_cache = CALLOC_STRUCT(panfrost_minmax_cache);
231
232
debug_printf("%s: pres=%p width=%u height=%u depth=%u target=%d "
233
"bind=%x usage=%d tile=%d last_level=%d\n", __func__,
234
pres, pres->width0, pres->height0, pres->depth0,
235
pres->target, pres->bind, pres->usage, should_tile, templat->last_level);
236
}
237
return pres;
238
}
239
240
static struct pipe_resource *
241
lima_resource_create(struct pipe_screen *pscreen,
242
const struct pipe_resource *templat)
243
{
244
const uint64_t mod = DRM_FORMAT_MOD_INVALID;
245
246
return _lima_resource_create_with_modifiers(pscreen, templat, &mod, 1);
247
}
248
249
static struct pipe_resource *
250
lima_resource_create_with_modifiers(struct pipe_screen *pscreen,
251
const struct pipe_resource *templat,
252
const uint64_t *modifiers,
253
int count)
254
{
255
struct pipe_resource tmpl = *templat;
256
257
/* gbm_bo_create_with_modifiers & gbm_surface_create_with_modifiers
258
* don't have usage parameter, but buffer created by these functions
259
* may be used for scanout. So we assume buffer created by this
260
* function always enable scanout if linear modifier is permitted.
261
*/
262
if (drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count))
263
tmpl.bind |= PIPE_BIND_SCANOUT;
264
265
return _lima_resource_create_with_modifiers(pscreen, &tmpl, modifiers, count);
266
}
267
268
static void
269
lima_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *pres)
270
{
271
struct lima_screen *screen = lima_screen(pscreen);
272
struct lima_resource *res = lima_resource(pres);
273
274
if (res->bo)
275
lima_bo_unreference(res->bo);
276
277
if (res->scanout)
278
renderonly_scanout_destroy(res->scanout, screen->ro);
279
280
if (res->damage.region)
281
FREE(res->damage.region);
282
283
if (res->index_cache)
284
FREE(res->index_cache);
285
286
FREE(res);
287
}
288
289
static struct pipe_resource *
290
lima_resource_from_handle(struct pipe_screen *pscreen,
291
const struct pipe_resource *templat,
292
struct winsys_handle *handle, unsigned usage)
293
{
294
if (templat->bind & (PIPE_BIND_SAMPLER_VIEW |
295
PIPE_BIND_RENDER_TARGET |
296
PIPE_BIND_DEPTH_STENCIL)) {
297
/* sampler hardware need offset alignment 64, while render hardware
298
* need offset alignment 8, but due to render target may be reloaded
299
* which uses the sampler, set alignment requrement to 64 for all
300
*/
301
if (handle->offset & 0x3f) {
302
debug_error("import buffer offset not properly aligned\n");
303
return NULL;
304
}
305
}
306
307
struct lima_resource *res = CALLOC_STRUCT(lima_resource);
308
if (!res)
309
return NULL;
310
311
struct pipe_resource *pres = &res->base;
312
*pres = *templat;
313
pres->screen = pscreen;
314
pipe_reference_init(&pres->reference, 1);
315
res->levels[0].offset = handle->offset;
316
res->levels[0].stride = handle->stride;
317
318
struct lima_screen *screen = lima_screen(pscreen);
319
res->bo = lima_bo_import(screen, handle);
320
if (!res->bo) {
321
FREE(res);
322
return NULL;
323
}
324
325
res->modifier_constant = true;
326
327
switch (handle->modifier) {
328
case DRM_FORMAT_MOD_LINEAR:
329
res->tiled = false;
330
break;
331
case DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED:
332
res->tiled = true;
333
break;
334
case DRM_FORMAT_MOD_INVALID:
335
/* Modifier wasn't specified and it's shared buffer. We create these
336
* as linear, so disable tiling.
337
*/
338
res->tiled = false;
339
break;
340
default:
341
fprintf(stderr, "Attempted to import unsupported modifier 0x%llx\n",
342
(long long)handle->modifier);
343
goto err_out;
344
}
345
346
/* check alignment for the buffer */
347
if (res->tiled ||
348
(pres->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL))) {
349
unsigned width, height, stride, size;
350
351
width = align(pres->width0, 16);
352
height = align(pres->height0, 16);
353
stride = util_format_get_stride(pres->format, width);
354
size = util_format_get_2d_size(pres->format, stride, height);
355
356
if (res->tiled && res->levels[0].stride != stride) {
357
fprintf(stderr, "tiled imported buffer has mismatching stride: %d (BO) != %d (expected)",
358
res->levels[0].stride, stride);
359
goto err_out;
360
}
361
362
if (!res->tiled && (res->levels[0].stride % 8)) {
363
fprintf(stderr, "linear imported buffer stride is not aligned to 8 bytes: %d\n",
364
res->levels[0].stride);
365
}
366
367
if (!res->tiled && res->levels[0].stride < stride) {
368
fprintf(stderr, "linear imported buffer stride is smaller than minimal: %d (BO) < %d (min)",
369
res->levels[0].stride, stride);
370
goto err_out;
371
}
372
373
if ((res->bo->size - res->levels[0].offset) < size) {
374
fprintf(stderr, "imported bo size is smaller than expected: %d (BO) < %d (expected)\n",
375
(res->bo->size - res->levels[0].offset), size);
376
goto err_out;
377
}
378
379
res->levels[0].width = width;
380
}
381
else
382
res->levels[0].width = pres->width0;
383
384
if (screen->ro) {
385
/* Make sure that renderonly has a handle to our buffer in the
386
* display's fd, so that a later renderonly_get_handle()
387
* returns correct handles or GEM names.
388
*/
389
res->scanout =
390
renderonly_create_gpu_import_for_resource(pres,
391
screen->ro,
392
NULL);
393
/* ignore failiure to allow importing non-displayable buffer */
394
}
395
396
return pres;
397
398
err_out:
399
lima_resource_destroy(pscreen, pres);
400
return NULL;
401
}
402
403
static bool
404
lima_resource_get_handle(struct pipe_screen *pscreen,
405
struct pipe_context *pctx,
406
struct pipe_resource *pres,
407
struct winsys_handle *handle, unsigned usage)
408
{
409
struct lima_screen *screen = lima_screen(pscreen);
410
struct lima_resource *res = lima_resource(pres);
411
412
if (res->tiled)
413
handle->modifier = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
414
else
415
handle->modifier = DRM_FORMAT_MOD_LINEAR;
416
417
res->modifier_constant = true;
418
419
if (handle->type == WINSYS_HANDLE_TYPE_KMS && screen->ro)
420
return renderonly_get_handle(res->scanout, handle);
421
422
if (!lima_bo_export(res->bo, handle))
423
return false;
424
425
handle->offset = res->levels[0].offset;
426
handle->stride = res->levels[0].stride;
427
return true;
428
}
429
430
static bool
431
lima_resource_get_param(struct pipe_screen *pscreen,
432
struct pipe_context *pctx,
433
struct pipe_resource *pres,
434
unsigned plane, unsigned layer, unsigned level,
435
enum pipe_resource_param param,
436
unsigned usage, uint64_t *value)
437
{
438
struct lima_resource *res = lima_resource(pres);
439
440
switch (param) {
441
case PIPE_RESOURCE_PARAM_STRIDE:
442
*value = res->levels[level].stride;
443
return true;
444
case PIPE_RESOURCE_PARAM_OFFSET:
445
*value = res->levels[level].offset;
446
return true;
447
case PIPE_RESOURCE_PARAM_MODIFIER:
448
if (res->tiled)
449
*value = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
450
else
451
*value = DRM_FORMAT_MOD_LINEAR;
452
453
return true;
454
default:
455
return false;
456
}
457
}
458
459
static void
460
get_scissor_from_box(struct pipe_scissor_state *s,
461
const struct pipe_box *b, int h)
462
{
463
int y = h - (b->y + b->height);
464
/* region in tile unit */
465
s->minx = b->x >> 4;
466
s->miny = y >> 4;
467
s->maxx = (b->x + b->width + 0xf) >> 4;
468
s->maxy = (y + b->height + 0xf) >> 4;
469
}
470
471
static void
472
get_damage_bound_box(struct pipe_resource *pres,
473
const struct pipe_box *rects,
474
unsigned int nrects,
475
struct pipe_scissor_state *bound)
476
{
477
struct pipe_box b = rects[0];
478
479
for (int i = 1; i < nrects; i++)
480
u_box_union_2d(&b, &b, rects + i);
481
482
int ret = u_box_clip_2d(&b, &b, pres->width0, pres->height0);
483
if (ret < 0)
484
memset(bound, 0, sizeof(*bound));
485
else
486
get_scissor_from_box(bound, &b, pres->height0);
487
}
488
489
static void
490
lima_resource_set_damage_region(struct pipe_screen *pscreen,
491
struct pipe_resource *pres,
492
unsigned int nrects,
493
const struct pipe_box *rects)
494
{
495
struct lima_resource *res = lima_resource(pres);
496
struct lima_damage_region *damage = &res->damage;
497
int i;
498
499
if (damage->region) {
500
FREE(damage->region);
501
damage->region = NULL;
502
damage->num_region = 0;
503
}
504
505
if (!nrects)
506
return;
507
508
/* check full damage
509
*
510
* TODO: currently only check if there is any single damage
511
* region that can cover the full render target; there may
512
* be some accurate way, but a single window size damage
513
* region is most of the case from weston
514
*/
515
for (i = 0; i < nrects; i++) {
516
if (rects[i].x <= 0 && rects[i].y <= 0 &&
517
rects[i].x + rects[i].width >= pres->width0 &&
518
rects[i].y + rects[i].height >= pres->height0)
519
return;
520
}
521
522
struct pipe_scissor_state *bound = &damage->bound;
523
get_damage_bound_box(pres, rects, nrects, bound);
524
525
damage->region = CALLOC(nrects, sizeof(*damage->region));
526
if (!damage->region)
527
return;
528
529
for (i = 0; i < nrects; i++)
530
get_scissor_from_box(damage->region + i, rects + i,
531
pres->height0);
532
533
/* is region aligned to tiles? */
534
damage->aligned = true;
535
for (i = 0; i < nrects; i++) {
536
if (rects[i].x & 0xf || rects[i].y & 0xf ||
537
rects[i].width & 0xf || rects[i].height & 0xf) {
538
damage->aligned = false;
539
break;
540
}
541
}
542
543
damage->num_region = nrects;
544
}
545
546
void
547
lima_resource_screen_init(struct lima_screen *screen)
548
{
549
screen->base.resource_create = lima_resource_create;
550
screen->base.resource_create_with_modifiers = lima_resource_create_with_modifiers;
551
screen->base.resource_from_handle = lima_resource_from_handle;
552
screen->base.resource_destroy = lima_resource_destroy;
553
screen->base.resource_get_handle = lima_resource_get_handle;
554
screen->base.resource_get_param = lima_resource_get_param;
555
screen->base.set_damage_region = lima_resource_set_damage_region;
556
}
557
558
static struct pipe_surface *
559
lima_surface_create(struct pipe_context *pctx,
560
struct pipe_resource *pres,
561
const struct pipe_surface *surf_tmpl)
562
{
563
struct lima_surface *surf = CALLOC_STRUCT(lima_surface);
564
565
if (!surf)
566
return NULL;
567
568
assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
569
570
struct pipe_surface *psurf = &surf->base;
571
unsigned level = surf_tmpl->u.tex.level;
572
573
pipe_reference_init(&psurf->reference, 1);
574
pipe_resource_reference(&psurf->texture, pres);
575
576
psurf->context = pctx;
577
psurf->format = surf_tmpl->format;
578
psurf->width = u_minify(pres->width0, level);
579
psurf->height = u_minify(pres->height0, level);
580
psurf->u.tex.level = level;
581
psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
582
psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
583
584
surf->tiled_w = align(psurf->width, 16) >> 4;
585
surf->tiled_h = align(psurf->height, 16) >> 4;
586
587
surf->reload = 0;
588
if (util_format_has_stencil(util_format_description(psurf->format)))
589
surf->reload |= PIPE_CLEAR_STENCIL;
590
if (util_format_has_depth(util_format_description(psurf->format)))
591
surf->reload |= PIPE_CLEAR_DEPTH;
592
if (!util_format_is_depth_or_stencil(psurf->format))
593
surf->reload |= PIPE_CLEAR_COLOR0;
594
595
return &surf->base;
596
}
597
598
static void
599
lima_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
600
{
601
struct lima_surface *surf = lima_surface(psurf);
602
603
pipe_resource_reference(&psurf->texture, NULL);
604
FREE(surf);
605
}
606
607
static void *
608
lima_transfer_map(struct pipe_context *pctx,
609
struct pipe_resource *pres,
610
unsigned level,
611
unsigned usage,
612
const struct pipe_box *box,
613
struct pipe_transfer **pptrans)
614
{
615
struct lima_screen *screen = lima_screen(pres->screen);
616
struct lima_context *ctx = lima_context(pctx);
617
struct lima_resource *res = lima_resource(pres);
618
struct lima_bo *bo = res->bo;
619
struct lima_transfer *trans;
620
struct pipe_transfer *ptrans;
621
622
/* No direct mappings of tiled, since we need to manually
623
* tile/untile.
624
*/
625
if (res->tiled && (usage & PIPE_MAP_DIRECTLY))
626
return NULL;
627
628
/* bo might be in use in a previous stream draw. Allocate a new
629
* one for the resource to avoid overwriting data in use. */
630
if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) {
631
struct lima_bo *new_bo;
632
assert(res->bo && res->bo->size);
633
634
new_bo = lima_bo_create(screen, res->bo->size, res->bo->flags);
635
if (!new_bo)
636
return NULL;
637
638
lima_bo_unreference(res->bo);
639
res->bo = new_bo;
640
641
if (pres->bind & PIPE_BIND_VERTEX_BUFFER)
642
ctx->dirty |= LIMA_CONTEXT_DIRTY_VERTEX_BUFF;
643
644
bo = res->bo;
645
}
646
else if (!(usage & PIPE_MAP_UNSYNCHRONIZED) &&
647
(usage & PIPE_MAP_READ_WRITE)) {
648
/* use once buffers are made sure to not read/write overlapped
649
* range, so no need to sync */
650
lima_flush_job_accessing_bo(ctx, bo, usage & PIPE_MAP_WRITE);
651
652
unsigned op = usage & PIPE_MAP_WRITE ?
653
LIMA_GEM_WAIT_WRITE : LIMA_GEM_WAIT_READ;
654
lima_bo_wait(bo, op, PIPE_TIMEOUT_INFINITE);
655
}
656
657
if (!lima_bo_map(bo))
658
return NULL;
659
660
trans = slab_alloc(&ctx->transfer_pool);
661
if (!trans)
662
return NULL;
663
664
memset(trans, 0, sizeof(*trans));
665
ptrans = &trans->base;
666
667
pipe_resource_reference(&ptrans->resource, pres);
668
ptrans->level = level;
669
ptrans->usage = usage;
670
ptrans->box = *box;
671
672
*pptrans = ptrans;
673
674
if (res->tiled) {
675
ptrans->stride = util_format_get_stride(pres->format, ptrans->box.width);
676
ptrans->layer_stride = ptrans->stride * ptrans->box.height;
677
678
trans->staging = malloc(ptrans->stride * ptrans->box.height * ptrans->box.depth);
679
680
if (usage & PIPE_MAP_READ) {
681
unsigned i;
682
for (i = 0; i < ptrans->box.depth; i++)
683
panfrost_load_tiled_image(
684
trans->staging + i * ptrans->stride * ptrans->box.height,
685
bo->map + res->levels[level].offset + (i + box->z) * res->levels[level].layer_stride,
686
ptrans->box.x, ptrans->box.y,
687
ptrans->box.width, ptrans->box.height,
688
ptrans->stride,
689
res->levels[level].stride,
690
pres->format);
691
}
692
693
return trans->staging;
694
} else {
695
unsigned dpw = PIPE_MAP_DIRECTLY | PIPE_MAP_WRITE |
696
PIPE_MAP_PERSISTENT;
697
if ((usage & dpw) == dpw && res->index_cache)
698
return NULL;
699
700
ptrans->stride = res->levels[level].stride;
701
ptrans->layer_stride = res->levels[level].layer_stride;
702
703
if ((usage & PIPE_MAP_WRITE) && (usage & PIPE_MAP_DIRECTLY))
704
panfrost_minmax_cache_invalidate(res->index_cache, ptrans);
705
706
return bo->map + res->levels[level].offset +
707
box->z * res->levels[level].layer_stride +
708
box->y / util_format_get_blockheight(pres->format) * ptrans->stride +
709
box->x / util_format_get_blockwidth(pres->format) *
710
util_format_get_blocksize(pres->format);
711
}
712
}
713
714
static void
715
lima_transfer_flush_region(struct pipe_context *pctx,
716
struct pipe_transfer *ptrans,
717
const struct pipe_box *box)
718
{
719
720
}
721
722
static bool
723
lima_should_convert_linear(struct lima_resource *res,
724
struct pipe_transfer *ptrans)
725
{
726
if (res->modifier_constant)
727
return false;
728
729
/* Overwriting the entire resource indicates streaming, for which
730
* linear layout is most efficient due to the lack of expensive
731
* conversion.
732
*
733
* For now we just switch to linear after a number of complete
734
* overwrites to keep things simple, but we could do better.
735
*/
736
737
unsigned depth = res->base.target == PIPE_TEXTURE_3D ?
738
res->base.depth0 : res->base.array_size;
739
bool entire_overwrite =
740
res->base.last_level == 0 &&
741
ptrans->box.width == res->base.width0 &&
742
ptrans->box.height == res->base.height0 &&
743
ptrans->box.depth == depth &&
744
ptrans->box.x == 0 &&
745
ptrans->box.y == 0 &&
746
ptrans->box.z == 0;
747
748
if (entire_overwrite)
749
++res->full_updates;
750
751
return res->full_updates >= LAYOUT_CONVERT_THRESHOLD;
752
}
753
754
static void
755
lima_transfer_unmap_inner(struct lima_context *ctx,
756
struct pipe_transfer *ptrans)
757
{
758
struct lima_resource *res = lima_resource(ptrans->resource);
759
struct lima_transfer *trans = lima_transfer(ptrans);
760
struct lima_bo *bo = res->bo;
761
struct pipe_resource *pres;
762
763
if (trans->staging) {
764
pres = &res->base;
765
if (trans->base.usage & PIPE_MAP_WRITE) {
766
unsigned i;
767
if (lima_should_convert_linear(res, ptrans)) {
768
/* It's safe to re-use the same BO since tiled BO always has
769
* aligned dimensions */
770
for (i = 0; i < trans->base.box.depth; i++) {
771
util_copy_rect(bo->map + res->levels[0].offset +
772
(i + trans->base.box.z) * res->levels[0].stride,
773
res->base.format,
774
res->levels[0].stride,
775
0, 0,
776
ptrans->box.width,
777
ptrans->box.height,
778
trans->staging + i * ptrans->stride * ptrans->box.height,
779
ptrans->stride,
780
0, 0);
781
}
782
res->tiled = false;
783
res->modifier_constant = true;
784
/* Update texture descriptor */
785
ctx->dirty |= LIMA_CONTEXT_DIRTY_TEXTURES;
786
} else {
787
for (i = 0; i < trans->base.box.depth; i++)
788
panfrost_store_tiled_image(
789
bo->map + res->levels[trans->base.level].offset + (i + trans->base.box.z) * res->levels[trans->base.level].layer_stride,
790
trans->staging + i * ptrans->stride * ptrans->box.height,
791
ptrans->box.x, ptrans->box.y,
792
ptrans->box.width, ptrans->box.height,
793
res->levels[ptrans->level].stride,
794
ptrans->stride,
795
pres->format);
796
}
797
}
798
}
799
}
800
801
static void
802
lima_transfer_unmap(struct pipe_context *pctx,
803
struct pipe_transfer *ptrans)
804
{
805
struct lima_context *ctx = lima_context(pctx);
806
struct lima_transfer *trans = lima_transfer(ptrans);
807
struct lima_resource *res = lima_resource(ptrans->resource);
808
809
lima_transfer_unmap_inner(ctx, ptrans);
810
if (trans->staging)
811
free(trans->staging);
812
panfrost_minmax_cache_invalidate(res->index_cache, ptrans);
813
814
pipe_resource_reference(&ptrans->resource, NULL);
815
slab_free(&ctx->transfer_pool, trans);
816
}
817
818
static void
819
lima_util_blitter_save_states(struct lima_context *ctx)
820
{
821
util_blitter_save_blend(ctx->blitter, (void *)ctx->blend);
822
util_blitter_save_depth_stencil_alpha(ctx->blitter, (void *)ctx->zsa);
823
util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
824
util_blitter_save_rasterizer(ctx->blitter, (void *)ctx->rasterizer);
825
util_blitter_save_fragment_shader(ctx->blitter, ctx->uncomp_fs);
826
util_blitter_save_vertex_shader(ctx->blitter, ctx->uncomp_vs);
827
util_blitter_save_viewport(ctx->blitter,
828
&ctx->viewport.transform);
829
util_blitter_save_scissor(ctx->blitter, &ctx->scissor);
830
util_blitter_save_vertex_elements(ctx->blitter,
831
ctx->vertex_elements);
832
util_blitter_save_vertex_buffer_slot(ctx->blitter,
833
ctx->vertex_buffers.vb);
834
835
util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer.base);
836
837
util_blitter_save_fragment_sampler_states(ctx->blitter,
838
ctx->tex_stateobj.num_samplers,
839
(void**)ctx->tex_stateobj.samplers);
840
util_blitter_save_fragment_sampler_views(ctx->blitter,
841
ctx->tex_stateobj.num_textures,
842
ctx->tex_stateobj.textures);
843
}
844
845
static void
846
lima_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
847
{
848
struct lima_context *ctx = lima_context(pctx);
849
struct pipe_blit_info info = *blit_info;
850
851
if (util_try_blit_via_copy_region(pctx, &info)) {
852
return; /* done */
853
}
854
855
if (info.mask & PIPE_MASK_S) {
856
debug_printf("lima: cannot blit stencil, skipping\n");
857
info.mask &= ~PIPE_MASK_S;
858
}
859
860
if (!util_blitter_is_blit_supported(ctx->blitter, &info)) {
861
debug_printf("lima: blit unsupported %s -> %s\n",
862
util_format_short_name(info.src.resource->format),
863
util_format_short_name(info.dst.resource->format));
864
return;
865
}
866
867
lima_util_blitter_save_states(ctx);
868
869
util_blitter_blit(ctx->blitter, &info);
870
}
871
872
static void
873
lima_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
874
{
875
876
}
877
878
static void
879
lima_texture_subdata(struct pipe_context *pctx,
880
struct pipe_resource *prsc,
881
unsigned level,
882
unsigned usage,
883
const struct pipe_box *box,
884
const void *data,
885
unsigned stride,
886
unsigned layer_stride)
887
{
888
struct lima_context *ctx = lima_context(pctx);
889
struct lima_resource *res = lima_resource(prsc);
890
891
if (!res->tiled) {
892
u_default_texture_subdata(pctx, prsc, level, usage, box,
893
data, stride, layer_stride);
894
return;
895
}
896
897
assert(!(usage & PIPE_MAP_READ));
898
899
struct lima_transfer t = {
900
.base = {
901
.resource = prsc,
902
.usage = PIPE_MAP_WRITE,
903
.level = level,
904
.box = *box,
905
.stride = stride,
906
.layer_stride = layer_stride,
907
},
908
.staging = (void *)data,
909
};
910
911
lima_flush_job_accessing_bo(ctx, res->bo, true);
912
lima_bo_wait(res->bo, LIMA_GEM_WAIT_WRITE, PIPE_TIMEOUT_INFINITE);
913
if (!lima_bo_map(res->bo))
914
return;
915
916
lima_transfer_unmap_inner(ctx, &t.base);
917
}
918
919
void
920
lima_resource_context_init(struct lima_context *ctx)
921
{
922
ctx->base.create_surface = lima_surface_create;
923
ctx->base.surface_destroy = lima_surface_destroy;
924
925
ctx->base.buffer_subdata = u_default_buffer_subdata;
926
ctx->base.texture_subdata = lima_texture_subdata;
927
/* TODO: optimize resource_copy_region to do copy directly
928
* between 2 tiled or tiled and linear resources instead of
929
* using staging buffer.
930
*/
931
ctx->base.resource_copy_region = util_resource_copy_region;
932
933
ctx->base.blit = lima_blit;
934
935
ctx->base.buffer_map = lima_transfer_map;
936
ctx->base.texture_map = lima_transfer_map;
937
ctx->base.transfer_flush_region = lima_transfer_flush_region;
938
ctx->base.buffer_unmap = lima_transfer_unmap;
939
ctx->base.texture_unmap = lima_transfer_unmap;
940
941
ctx->base.flush_resource = lima_flush_resource;
942
}
943
944