radeonsi: don't crash if input_usage_mask is 0 for a VS input
[mesa.git] / src / gallium / drivers / lima / lima_resource.c
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 switch (handle->modifier) {
326 case DRM_FORMAT_MOD_LINEAR:
327 res->tiled = false;
328 break;
329 case DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED:
330 res->tiled = true;
331 break;
332 case DRM_FORMAT_MOD_INVALID:
333 /* Modifier wasn't specified and it's shared buffer. We create these
334 * as linear, so disable tiling.
335 */
336 res->tiled = false;
337 break;
338 default:
339 fprintf(stderr, "Attempted to import unsupported modifier 0x%llx\n",
340 (long long)handle->modifier);
341 goto err_out;
342 }
343
344 /* check alignment for the buffer */
345 if (res->tiled ||
346 (pres->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL))) {
347 unsigned width, height, stride, size;
348
349 width = align(pres->width0, 16);
350 height = align(pres->height0, 16);
351 stride = util_format_get_stride(pres->format, width);
352 size = util_format_get_2d_size(pres->format, stride, height);
353
354 if (res->levels[0].stride != stride || res->bo->size < size) {
355 debug_error("import buffer not properly aligned\n");
356 goto err_out;
357 }
358
359 res->levels[0].width = width;
360 }
361 else
362 res->levels[0].width = pres->width0;
363
364 return pres;
365
366 err_out:
367 lima_resource_destroy(pscreen, pres);
368 return NULL;
369 }
370
371 static bool
372 lima_resource_get_handle(struct pipe_screen *pscreen,
373 struct pipe_context *pctx,
374 struct pipe_resource *pres,
375 struct winsys_handle *handle, unsigned usage)
376 {
377 struct lima_screen *screen = lima_screen(pscreen);
378 struct lima_resource *res = lima_resource(pres);
379
380 if (res->tiled)
381 handle->modifier = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
382 else
383 handle->modifier = DRM_FORMAT_MOD_LINEAR;
384
385 if (handle->type == WINSYS_HANDLE_TYPE_KMS && screen->ro &&
386 renderonly_get_handle(res->scanout, handle))
387 return true;
388
389 if (!lima_bo_export(res->bo, handle))
390 return false;
391
392 handle->offset = res->levels[0].offset;
393 handle->stride = res->levels[0].stride;
394 return true;
395 }
396
397 static void
398 get_scissor_from_box(struct pipe_scissor_state *s,
399 const struct pipe_box *b, int h)
400 {
401 int y = h - (b->y + b->height);
402 /* region in tile unit */
403 s->minx = b->x >> 4;
404 s->miny = y >> 4;
405 s->maxx = (b->x + b->width + 0xf) >> 4;
406 s->maxy = (y + b->height + 0xf) >> 4;
407 }
408
409 static void
410 get_damage_bound_box(struct pipe_resource *pres,
411 const struct pipe_box *rects,
412 unsigned int nrects,
413 struct pipe_scissor_state *bound)
414 {
415 struct pipe_box b = rects[0];
416
417 for (int i = 1; i < nrects; i++)
418 u_box_union_2d(&b, &b, rects + i);
419
420 int ret = u_box_clip_2d(&b, &b, pres->width0, pres->height0);
421 if (ret < 0)
422 memset(bound, 0, sizeof(*bound));
423 else
424 get_scissor_from_box(bound, &b, pres->height0);
425 }
426
427 static void
428 lima_resource_set_damage_region(struct pipe_screen *pscreen,
429 struct pipe_resource *pres,
430 unsigned int nrects,
431 const struct pipe_box *rects)
432 {
433 struct lima_resource *res = lima_resource(pres);
434 struct lima_damage_region *damage = &res->damage;
435 int i;
436
437 if (damage->region) {
438 FREE(damage->region);
439 damage->region = NULL;
440 damage->num_region = 0;
441 }
442
443 if (!nrects)
444 return;
445
446 /* check full damage
447 *
448 * TODO: currently only check if there is any single damage
449 * region that can cover the full render target; there may
450 * be some accurate way, but a single window size damage
451 * region is most of the case from weston
452 */
453 for (i = 0; i < nrects; i++) {
454 if (rects[i].x <= 0 && rects[i].y <= 0 &&
455 rects[i].x + rects[i].width >= pres->width0 &&
456 rects[i].y + rects[i].height >= pres->height0)
457 return;
458 }
459
460 struct pipe_scissor_state *bound = &damage->bound;
461 get_damage_bound_box(pres, rects, nrects, bound);
462
463 damage->region = CALLOC(nrects, sizeof(*damage->region));
464 if (!damage->region)
465 return;
466
467 for (i = 0; i < nrects; i++)
468 get_scissor_from_box(damage->region + i, rects + i,
469 pres->height0);
470
471 /* is region aligned to tiles? */
472 damage->aligned = true;
473 for (i = 0; i < nrects; i++) {
474 if (rects[i].x & 0xf || rects[i].y & 0xf ||
475 rects[i].width & 0xf || rects[i].height & 0xf) {
476 damage->aligned = false;
477 break;
478 }
479 }
480
481 damage->num_region = nrects;
482 }
483
484 void
485 lima_resource_screen_init(struct lima_screen *screen)
486 {
487 screen->base.resource_create = lima_resource_create;
488 screen->base.resource_create_with_modifiers = lima_resource_create_with_modifiers;
489 screen->base.resource_from_handle = lima_resource_from_handle;
490 screen->base.resource_destroy = lima_resource_destroy;
491 screen->base.resource_get_handle = lima_resource_get_handle;
492 screen->base.set_damage_region = lima_resource_set_damage_region;
493 }
494
495 static struct pipe_surface *
496 lima_surface_create(struct pipe_context *pctx,
497 struct pipe_resource *pres,
498 const struct pipe_surface *surf_tmpl)
499 {
500 struct lima_surface *surf = CALLOC_STRUCT(lima_surface);
501
502 if (!surf)
503 return NULL;
504
505 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
506
507 struct pipe_surface *psurf = &surf->base;
508 unsigned level = surf_tmpl->u.tex.level;
509
510 pipe_reference_init(&psurf->reference, 1);
511 pipe_resource_reference(&psurf->texture, pres);
512
513 psurf->context = pctx;
514 psurf->format = surf_tmpl->format;
515 psurf->width = u_minify(pres->width0, level);
516 psurf->height = u_minify(pres->height0, level);
517 psurf->u.tex.level = level;
518 psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
519 psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
520
521 surf->tiled_w = align(psurf->width, 16) >> 4;
522 surf->tiled_h = align(psurf->height, 16) >> 4;
523
524 surf->reload = 0;
525 if (util_format_has_stencil(util_format_description(psurf->format)))
526 surf->reload |= PIPE_CLEAR_STENCIL;
527 if (util_format_has_depth(util_format_description(psurf->format)))
528 surf->reload |= PIPE_CLEAR_DEPTH;
529 if (!util_format_is_depth_or_stencil(psurf->format))
530 surf->reload |= PIPE_CLEAR_COLOR0;
531
532 return &surf->base;
533 }
534
535 static void
536 lima_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
537 {
538 struct lima_surface *surf = lima_surface(psurf);
539
540 pipe_resource_reference(&psurf->texture, NULL);
541 FREE(surf);
542 }
543
544 static void *
545 lima_transfer_map(struct pipe_context *pctx,
546 struct pipe_resource *pres,
547 unsigned level,
548 unsigned usage,
549 const struct pipe_box *box,
550 struct pipe_transfer **pptrans)
551 {
552 struct lima_context *ctx = lima_context(pctx);
553 struct lima_resource *res = lima_resource(pres);
554 struct lima_bo *bo = res->bo;
555 struct lima_transfer *trans;
556 struct pipe_transfer *ptrans;
557
558 /* No direct mappings of tiled, since we need to manually
559 * tile/untile.
560 */
561 if (res->tiled && (usage & PIPE_TRANSFER_MAP_DIRECTLY))
562 return NULL;
563
564 /* use once buffers are made sure to not read/write overlapped
565 * range, so no need to sync */
566 if (pres->usage != PIPE_USAGE_STREAM) {
567 if (usage & PIPE_TRANSFER_READ_WRITE) {
568 lima_flush_job_accessing_bo(ctx, bo, usage & PIPE_TRANSFER_WRITE);
569
570 unsigned op = usage & PIPE_TRANSFER_WRITE ?
571 LIMA_GEM_WAIT_WRITE : LIMA_GEM_WAIT_READ;
572 lima_bo_wait(bo, op, PIPE_TIMEOUT_INFINITE);
573 }
574 }
575
576 if (!lima_bo_map(bo))
577 return NULL;
578
579 trans = slab_alloc(&ctx->transfer_pool);
580 if (!trans)
581 return NULL;
582
583 memset(trans, 0, sizeof(*trans));
584 ptrans = &trans->base;
585
586 pipe_resource_reference(&ptrans->resource, pres);
587 ptrans->level = level;
588 ptrans->usage = usage;
589 ptrans->box = *box;
590
591 *pptrans = ptrans;
592
593 if (res->tiled) {
594 ptrans->stride = util_format_get_stride(pres->format, ptrans->box.width);
595 ptrans->layer_stride = ptrans->stride * ptrans->box.height;
596
597 trans->staging = malloc(ptrans->stride * ptrans->box.height * ptrans->box.depth);
598
599 if (usage & PIPE_TRANSFER_READ) {
600 unsigned i;
601 for (i = 0; i < ptrans->box.depth; i++)
602 panfrost_load_tiled_image(
603 trans->staging + i * ptrans->stride * ptrans->box.height,
604 bo->map + res->levels[level].offset + (i + box->z) * res->levels[level].layer_stride,
605 ptrans->box.x, ptrans->box.y,
606 ptrans->box.width, ptrans->box.height,
607 ptrans->stride,
608 res->levels[level].stride,
609 pres->format);
610 }
611
612 return trans->staging;
613 } else {
614 unsigned dpw = PIPE_TRANSFER_MAP_DIRECTLY | PIPE_TRANSFER_WRITE |
615 PIPE_TRANSFER_PERSISTENT;
616 if ((usage & dpw) == dpw && res->index_cache)
617 return NULL;
618
619 ptrans->stride = res->levels[level].stride;
620 ptrans->layer_stride = res->levels[level].layer_stride;
621
622 if ((usage & PIPE_TRANSFER_WRITE) && (usage & PIPE_TRANSFER_MAP_DIRECTLY))
623 panfrost_minmax_cache_invalidate(res->index_cache, ptrans);
624
625 return bo->map + res->levels[level].offset +
626 box->z * res->levels[level].layer_stride +
627 box->y / util_format_get_blockheight(pres->format) * ptrans->stride +
628 box->x / util_format_get_blockwidth(pres->format) *
629 util_format_get_blocksize(pres->format);
630 }
631 }
632
633 static void
634 lima_transfer_flush_region(struct pipe_context *pctx,
635 struct pipe_transfer *ptrans,
636 const struct pipe_box *box)
637 {
638
639 }
640
641 static void
642 lima_transfer_unmap_inner(struct lima_context *ctx,
643 struct pipe_transfer *ptrans)
644 {
645
646 struct lima_resource *res = lima_resource(ptrans->resource);
647 struct lima_transfer *trans = lima_transfer(ptrans);
648 struct lima_bo *bo = res->bo;
649 struct pipe_resource *pres;
650
651 if (trans->staging) {
652 pres = &res->base;
653 if (trans->base.usage & PIPE_TRANSFER_WRITE) {
654 unsigned i;
655 for (i = 0; i < trans->base.box.depth; i++)
656 panfrost_store_tiled_image(
657 bo->map + res->levels[trans->base.level].offset + (i + trans->base.box.z) * res->levels[trans->base.level].layer_stride,
658 trans->staging + i * ptrans->stride * ptrans->box.height,
659 ptrans->box.x, ptrans->box.y,
660 ptrans->box.width, ptrans->box.height,
661 res->levels[ptrans->level].stride,
662 ptrans->stride,
663 pres->format);
664 }
665 }
666 }
667
668 static void
669 lima_transfer_unmap(struct pipe_context *pctx,
670 struct pipe_transfer *ptrans)
671 {
672 struct lima_context *ctx = lima_context(pctx);
673 struct lima_transfer *trans = lima_transfer(ptrans);
674 struct lima_resource *res = lima_resource(ptrans->resource);
675
676 lima_transfer_unmap_inner(ctx, ptrans);
677 if (trans->staging)
678 free(trans->staging);
679 panfrost_minmax_cache_invalidate(res->index_cache, ptrans);
680
681 pipe_resource_reference(&ptrans->resource, NULL);
682 slab_free(&ctx->transfer_pool, trans);
683 }
684
685 static void
686 lima_util_blitter_save_states(struct lima_context *ctx)
687 {
688 util_blitter_save_blend(ctx->blitter, (void *)ctx->blend);
689 util_blitter_save_depth_stencil_alpha(ctx->blitter, (void *)ctx->zsa);
690 util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
691 util_blitter_save_rasterizer(ctx->blitter, (void *)ctx->rasterizer);
692 util_blitter_save_fragment_shader(ctx->blitter, ctx->fs);
693 util_blitter_save_vertex_shader(ctx->blitter, ctx->vs);
694 util_blitter_save_viewport(ctx->blitter,
695 &ctx->viewport.transform);
696 util_blitter_save_scissor(ctx->blitter, &ctx->scissor);
697 util_blitter_save_vertex_elements(ctx->blitter,
698 ctx->vertex_elements);
699 util_blitter_save_vertex_buffer_slot(ctx->blitter,
700 ctx->vertex_buffers.vb);
701
702 util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer.base);
703
704 util_blitter_save_fragment_sampler_states(ctx->blitter,
705 ctx->tex_stateobj.num_samplers,
706 (void**)ctx->tex_stateobj.samplers);
707 util_blitter_save_fragment_sampler_views(ctx->blitter,
708 ctx->tex_stateobj.num_textures,
709 ctx->tex_stateobj.textures);
710 }
711
712 static void
713 lima_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
714 {
715 struct lima_context *ctx = lima_context(pctx);
716 struct pipe_blit_info info = *blit_info;
717
718 if (util_try_blit_via_copy_region(pctx, &info)) {
719 return; /* done */
720 }
721
722 if (info.mask & PIPE_MASK_S) {
723 debug_printf("lima: cannot blit stencil, skipping\n");
724 info.mask &= ~PIPE_MASK_S;
725 }
726
727 if (!util_blitter_is_blit_supported(ctx->blitter, &info)) {
728 debug_printf("lima: blit unsupported %s -> %s\n",
729 util_format_short_name(info.src.resource->format),
730 util_format_short_name(info.dst.resource->format));
731 return;
732 }
733
734 lima_util_blitter_save_states(ctx);
735
736 util_blitter_blit(ctx->blitter, &info);
737 }
738
739 static void
740 lima_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
741 {
742
743 }
744
745 static void
746 lima_texture_subdata(struct pipe_context *pctx,
747 struct pipe_resource *prsc,
748 unsigned level,
749 unsigned usage,
750 const struct pipe_box *box,
751 const void *data,
752 unsigned stride,
753 unsigned layer_stride)
754 {
755 struct lima_context *ctx = lima_context(pctx);
756 struct lima_resource *res = lima_resource(prsc);
757
758 if (!res->tiled) {
759 u_default_texture_subdata(pctx, prsc, level, usage, box,
760 data, stride, layer_stride);
761 return;
762 }
763
764 assert(!(usage & PIPE_TRANSFER_READ));
765
766 struct lima_transfer t = {
767 .base = {
768 .resource = prsc,
769 .usage = PIPE_TRANSFER_WRITE,
770 .level = level,
771 .box = *box,
772 .stride = stride,
773 .layer_stride = layer_stride,
774 },
775 .staging = (void *)data,
776 };
777
778 lima_flush_job_accessing_bo(ctx, res->bo, true);
779 lima_bo_wait(res->bo, LIMA_GEM_WAIT_WRITE, PIPE_TIMEOUT_INFINITE);
780 if (!lima_bo_map(res->bo))
781 return;
782
783 lima_transfer_unmap_inner(ctx, &t.base);
784 }
785
786 void
787 lima_resource_context_init(struct lima_context *ctx)
788 {
789 ctx->base.create_surface = lima_surface_create;
790 ctx->base.surface_destroy = lima_surface_destroy;
791
792 ctx->base.buffer_subdata = u_default_buffer_subdata;
793 ctx->base.texture_subdata = lima_texture_subdata;
794 /* TODO: optimize resource_copy_region to do copy directly
795 * between 2 tiled or tiled and linear resources instead of
796 * using staging buffer.
797 */
798 ctx->base.resource_copy_region = util_resource_copy_region;
799
800 ctx->base.blit = lima_blit;
801
802 ctx->base.transfer_map = lima_transfer_map;
803 ctx->base.transfer_flush_region = lima_transfer_flush_region;
804 ctx->base.transfer_unmap = lima_transfer_unmap;
805
806 ctx->base.flush_resource = lima_flush_resource;
807 }