panfrost: Rework linear<--->tiled conversions
[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/u_drm.h"
35 #include "renderonly/renderonly.h"
36
37 #include "state_tracker/drm_driver.h"
38
39 #include "drm-uapi/drm_fourcc.h"
40 #include "drm-uapi/lima_drm.h"
41
42 #include "lima_screen.h"
43 #include "lima_context.h"
44 #include "lima_resource.h"
45 #include "lima_bo.h"
46 #include "lima_util.h"
47 #include "pan_tiling.h"
48
49 static struct pipe_resource *
50 lima_resource_create_scanout(struct pipe_screen *pscreen,
51 const struct pipe_resource *templat,
52 unsigned width, unsigned height)
53 {
54 struct lima_screen *screen = lima_screen(pscreen);
55 struct renderonly_scanout *scanout;
56 struct winsys_handle handle;
57 struct pipe_resource *pres;
58
59 struct pipe_resource scanout_templat = *templat;
60 scanout_templat.width0 = width;
61 scanout_templat.height0 = height;
62 scanout_templat.screen = pscreen;
63
64 scanout = renderonly_scanout_for_resource(&scanout_templat,
65 screen->ro, &handle);
66 if (!scanout)
67 return NULL;
68
69 assert(handle.type == WINSYS_HANDLE_TYPE_FD);
70 pres = pscreen->resource_from_handle(pscreen, templat, &handle,
71 PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
72
73 close(handle.handle);
74 if (!pres) {
75 renderonly_scanout_destroy(scanout, screen->ro);
76 return NULL;
77 }
78
79 struct lima_resource *res = lima_resource(pres);
80 res->scanout = scanout;
81
82 return pres;
83 }
84
85 static uint32_t
86 setup_miptree(struct lima_resource *res,
87 unsigned width0, unsigned height0,
88 bool should_align_dimensions)
89 {
90 struct pipe_resource *pres = &res->base;
91 unsigned level;
92 unsigned width = width0;
93 unsigned height = height0;
94 unsigned depth = pres->depth0;
95 uint32_t size = 0;
96
97 for (level = 0; level <= pres->last_level; level++) {
98 uint32_t actual_level_size;
99 uint32_t stride;
100 unsigned aligned_width;
101 unsigned aligned_height;
102
103 if (should_align_dimensions) {
104 aligned_width = align(width, 16);
105 aligned_height = align(height, 16);
106 } else {
107 aligned_width = width;
108 aligned_height = height;
109 }
110
111 stride = util_format_get_stride(pres->format, aligned_width);
112 actual_level_size = stride *
113 util_format_get_nblocksy(pres->format, aligned_height) *
114 pres->array_size * depth;
115
116 res->levels[level].width = aligned_width;
117 res->levels[level].stride = stride;
118 res->levels[level].offset = size;
119 res->levels[level].layer_stride = util_format_get_stride(pres->format, align(width, 16)) * align(height, 16);
120
121 /* The start address of each level <= 10 must be 64-aligned
122 * in order to be able to pass the addresses
123 * to the hardware.
124 * The start addresses of level 11 and level 12 are passed
125 * implicitely: they start at an offset of respectively
126 * 0x0400 and 0x0800 from the start address of level 10 */
127 if (level < 10)
128 size += align(actual_level_size, 64);
129 else if (level != pres->last_level)
130 size += 0x0400;
131 else
132 size += actual_level_size; /* Save some memory */
133
134 width = u_minify(width, 1);
135 height = u_minify(height, 1);
136 depth = u_minify(depth, 1);
137 }
138
139 return size;
140 }
141
142 static struct pipe_resource *
143 lima_resource_create_bo(struct pipe_screen *pscreen,
144 const struct pipe_resource *templat,
145 unsigned width, unsigned height,
146 bool should_align_dimensions)
147 {
148 struct lima_screen *screen = lima_screen(pscreen);
149 struct lima_resource *res;
150 struct pipe_resource *pres;
151
152 res = CALLOC_STRUCT(lima_resource);
153 if (!res)
154 return NULL;
155
156 res->base = *templat;
157 res->base.screen = pscreen;
158 pipe_reference_init(&res->base.reference, 1);
159
160 pres = &res->base;
161
162 uint32_t size = setup_miptree(res, width, height, should_align_dimensions);
163 size = align(size, LIMA_PAGE_SIZE);
164
165 res->bo = lima_bo_create(screen, size, 0);
166 if (!res->bo) {
167 FREE(res);
168 return NULL;
169 }
170
171 return pres;
172 }
173
174 static struct pipe_resource *
175 _lima_resource_create_with_modifiers(struct pipe_screen *pscreen,
176 const struct pipe_resource *templat,
177 const uint64_t *modifiers,
178 int count)
179 {
180 struct lima_screen *screen = lima_screen(pscreen);
181 bool should_tile = lima_debug & LIMA_DEBUG_NO_TILING ? false : true;
182 unsigned width, height;
183 bool should_align_dimensions;
184 bool has_user_modifiers = true;
185
186 if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)
187 has_user_modifiers = false;
188
189 /* VBOs/PBOs are untiled (and 1 height). */
190 if (templat->target == PIPE_BUFFER)
191 should_tile = false;
192
193 if (templat->bind & (PIPE_BIND_LINEAR | PIPE_BIND_SCANOUT))
194 should_tile = false;
195
196 /* If there's no user modifiers and buffer is shared we use linear */
197 if (!has_user_modifiers && (templat->bind & PIPE_BIND_SHARED))
198 should_tile = false;
199
200 if (drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count))
201 should_tile = false;
202
203 if (has_user_modifiers &&
204 !drm_find_modifier(DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED,
205 modifiers, count))
206 should_tile = false;
207
208 if (should_tile || (templat->bind & PIPE_BIND_RENDER_TARGET) ||
209 (templat->bind & PIPE_BIND_DEPTH_STENCIL)) {
210 should_align_dimensions = true;
211 width = align(templat->width0, 16);
212 height = align(templat->height0, 16);
213 }
214 else {
215 should_align_dimensions = false;
216 width = templat->width0;
217 height = templat->height0;
218 }
219
220 struct pipe_resource *pres;
221 if (screen->ro && (templat->bind & PIPE_BIND_SCANOUT))
222 pres = lima_resource_create_scanout(pscreen, templat, width, height);
223 else
224 pres = lima_resource_create_bo(pscreen, templat, width, height,
225 should_align_dimensions);
226
227 if (pres) {
228 struct lima_resource *res = lima_resource(pres);
229 res->tiled = should_tile;
230
231 debug_printf("%s: pres=%p width=%u height=%u depth=%u target=%d "
232 "bind=%x usage=%d tile=%d last_level=%d\n", __func__,
233 pres, pres->width0, pres->height0, pres->depth0,
234 pres->target, pres->bind, pres->usage, should_tile, templat->last_level);
235 }
236 return pres;
237 }
238
239 static struct pipe_resource *
240 lima_resource_create(struct pipe_screen *pscreen,
241 const struct pipe_resource *templat)
242 {
243 const uint64_t mod = DRM_FORMAT_MOD_INVALID;
244
245 return _lima_resource_create_with_modifiers(pscreen, templat, &mod, 1);
246 }
247
248 static struct pipe_resource *
249 lima_resource_create_with_modifiers(struct pipe_screen *pscreen,
250 const struct pipe_resource *templat,
251 const uint64_t *modifiers,
252 int count)
253 {
254 struct pipe_resource tmpl = *templat;
255
256 /* gbm_bo_create_with_modifiers & gbm_surface_create_with_modifiers
257 * don't have usage parameter, but buffer created by these functions
258 * may be used for scanout. So we assume buffer created by this
259 * function always enable scanout if linear modifier is permitted.
260 */
261 if (drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count))
262 tmpl.bind |= PIPE_BIND_SCANOUT;
263
264 return _lima_resource_create_with_modifiers(pscreen, &tmpl, modifiers, count);
265 }
266
267 static void
268 lima_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *pres)
269 {
270 struct lima_screen *screen = lima_screen(pscreen);
271 struct lima_resource *res = lima_resource(pres);
272
273 if (res->bo)
274 lima_bo_unreference(res->bo);
275
276 if (res->scanout)
277 renderonly_scanout_destroy(res->scanout, screen->ro);
278
279 if (res->damage.region)
280 FREE(res->damage.region);
281
282 FREE(res);
283 }
284
285 static struct pipe_resource *
286 lima_resource_from_handle(struct pipe_screen *pscreen,
287 const struct pipe_resource *templat,
288 struct winsys_handle *handle, unsigned usage)
289 {
290 struct lima_resource *res;
291 struct lima_screen *screen = lima_screen(pscreen);
292
293 res = CALLOC_STRUCT(lima_resource);
294 if (!res)
295 return NULL;
296
297 struct pipe_resource *pres = &res->base;
298 *pres = *templat;
299 pres->screen = pscreen;
300 pipe_reference_init(&pres->reference, 1);
301 res->levels[0].offset = 0;
302 res->levels[0].stride = handle->stride;
303
304 res->bo = lima_bo_import(screen, handle);
305 if (!res->bo) {
306 FREE(res);
307 return NULL;
308 }
309
310 /* check alignment for the buffer */
311 if (pres->bind & PIPE_BIND_RENDER_TARGET) {
312 unsigned width, height, stride, size;
313
314 width = align(pres->width0, 16);
315 height = align(pres->height0, 16);
316 stride = util_format_get_stride(pres->format, width);
317 size = util_format_get_2d_size(pres->format, stride, height);
318
319 if (res->levels[0].stride != stride || res->bo->size < size) {
320 debug_error("import buffer not properly aligned\n");
321 goto err_out;
322 }
323
324 res->levels[0].width = width;
325 }
326 else
327 res->levels[0].width = pres->width0;
328
329 switch (handle->modifier) {
330 case DRM_FORMAT_MOD_LINEAR:
331 res->tiled = false;
332 break;
333 case DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED:
334 res->tiled = true;
335 break;
336 case DRM_FORMAT_MOD_INVALID:
337 /* Modifier wasn't specified and it's shared buffer. We create these
338 * as linear, so disable tiling.
339 */
340 res->tiled = false;
341 break;
342 default:
343 fprintf(stderr, "Attempted to import unsupported modifier 0x%llx\n",
344 (long long)handle->modifier);
345 goto err_out;
346 }
347
348 return pres;
349
350 err_out:
351 lima_resource_destroy(pscreen, pres);
352 return NULL;
353 }
354
355 static bool
356 lima_resource_get_handle(struct pipe_screen *pscreen,
357 struct pipe_context *pctx,
358 struct pipe_resource *pres,
359 struct winsys_handle *handle, unsigned usage)
360 {
361 struct lima_screen *screen = lima_screen(pscreen);
362 struct lima_resource *res = lima_resource(pres);
363
364 if (res->tiled)
365 handle->modifier = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
366 else
367 handle->modifier = DRM_FORMAT_MOD_LINEAR;
368
369 if (handle->type == WINSYS_HANDLE_TYPE_KMS && screen->ro &&
370 renderonly_get_handle(res->scanout, handle))
371 return true;
372
373 if (!lima_bo_export(res->bo, handle))
374 return false;
375
376 handle->stride = res->levels[0].stride;
377 return true;
378 }
379
380 static void
381 get_scissor_from_box(struct pipe_scissor_state *s,
382 const struct pipe_box *b, int h)
383 {
384 int y = h - (b->y + b->height);
385 /* region in tile unit */
386 s->minx = b->x >> 4;
387 s->miny = y >> 4;
388 s->maxx = (b->x + b->width + 0xf) >> 4;
389 s->maxy = (y + b->height + 0xf) >> 4;
390 }
391
392 static void
393 get_damage_bound_box(struct pipe_resource *pres,
394 const struct pipe_box *rects,
395 unsigned int nrects,
396 struct pipe_scissor_state *bound)
397 {
398 struct pipe_box b = rects[0];
399
400 for (int i = 1; i < nrects; i++)
401 u_box_union_2d(&b, &b, rects + i);
402
403 int ret = u_box_clip_2d(&b, &b, pres->width0, pres->height0);
404 if (ret < 0)
405 memset(bound, 0, sizeof(*bound));
406 else
407 get_scissor_from_box(bound, &b, pres->height0);
408 }
409
410 static void
411 lima_resource_set_damage_region(struct pipe_screen *pscreen,
412 struct pipe_resource *pres,
413 unsigned int nrects,
414 const struct pipe_box *rects)
415 {
416 struct lima_resource *res = lima_resource(pres);
417 struct lima_damage_region *damage = &res->damage;
418 int i;
419
420 if (damage->region) {
421 FREE(damage->region);
422 damage->region = NULL;
423 damage->num_region = 0;
424 }
425
426 if (!nrects)
427 return;
428
429 /* check full damage
430 *
431 * TODO: currently only check if there is any single damage
432 * region that can cover the full render target; there may
433 * be some accurate way, but a single window size damage
434 * region is most of the case from weston
435 */
436 for (i = 0; i < nrects; i++) {
437 if (rects[i].x <= 0 && rects[i].y <= 0 &&
438 rects[i].x + rects[i].width >= pres->width0 &&
439 rects[i].y + rects[i].height >= pres->height0)
440 return;
441 }
442
443 struct pipe_scissor_state *bound = &damage->bound;
444 get_damage_bound_box(pres, rects, nrects, bound);
445
446 damage->region = CALLOC(nrects, sizeof(*damage->region));
447 if (!damage->region)
448 return;
449
450 for (i = 0; i < nrects; i++)
451 get_scissor_from_box(damage->region + i, rects + i,
452 pres->height0);
453
454 /* is region aligned to tiles? */
455 damage->aligned = true;
456 for (i = 0; i < nrects; i++) {
457 if (rects[i].x & 0xf || rects[i].y & 0xf ||
458 rects[i].width & 0xf || rects[i].height & 0xf) {
459 damage->aligned = false;
460 break;
461 }
462 }
463
464 damage->num_region = nrects;
465 }
466
467 void
468 lima_resource_screen_init(struct lima_screen *screen)
469 {
470 screen->base.resource_create = lima_resource_create;
471 screen->base.resource_create_with_modifiers = lima_resource_create_with_modifiers;
472 screen->base.resource_from_handle = lima_resource_from_handle;
473 screen->base.resource_destroy = lima_resource_destroy;
474 screen->base.resource_get_handle = lima_resource_get_handle;
475 screen->base.set_damage_region = lima_resource_set_damage_region;
476 }
477
478 static struct pipe_surface *
479 lima_surface_create(struct pipe_context *pctx,
480 struct pipe_resource *pres,
481 const struct pipe_surface *surf_tmpl)
482 {
483 struct lima_surface *surf = CALLOC_STRUCT(lima_surface);
484
485 if (!surf)
486 return NULL;
487
488 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
489
490 struct pipe_surface *psurf = &surf->base;
491 unsigned level = surf_tmpl->u.tex.level;
492
493 pipe_reference_init(&psurf->reference, 1);
494 pipe_resource_reference(&psurf->texture, pres);
495
496 psurf->context = pctx;
497 psurf->format = surf_tmpl->format;
498 psurf->width = u_minify(pres->width0, level);
499 psurf->height = u_minify(pres->height0, level);
500 psurf->u.tex.level = level;
501 psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
502 psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
503
504 surf->tiled_w = align(psurf->width, 16) >> 4;
505 surf->tiled_h = align(psurf->height, 16) >> 4;
506
507 surf->reload = true;
508
509 struct lima_context *ctx = lima_context(pctx);
510 if (ctx->plb_pp_stream) {
511 struct lima_ctx_plb_pp_stream_key key = {
512 .tiled_w = surf->tiled_w,
513 .tiled_h = surf->tiled_h,
514 };
515
516 for (int i = 0; i < lima_ctx_num_plb; i++) {
517 key.plb_index = i;
518
519 struct hash_entry *entry =
520 _mesa_hash_table_search(ctx->plb_pp_stream, &key);
521 if (entry) {
522 struct lima_ctx_plb_pp_stream *s = entry->data;
523 s->refcnt++;
524 }
525 else {
526 struct lima_ctx_plb_pp_stream *s =
527 ralloc(ctx->plb_pp_stream, struct lima_ctx_plb_pp_stream);
528 s->key.plb_index = i;
529 s->key.tiled_w = surf->tiled_w;
530 s->key.tiled_h = surf->tiled_h;
531 s->refcnt = 1;
532 s->bo = NULL;
533 _mesa_hash_table_insert(ctx->plb_pp_stream, &s->key, s);
534 }
535 }
536 }
537
538 return &surf->base;
539 }
540
541 static void
542 lima_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
543 {
544 struct lima_surface *surf = lima_surface(psurf);
545 /* psurf->context may be not equal with pctx (i.e. glxinfo) */
546 struct lima_context *ctx = lima_context(psurf->context);
547
548 if (ctx->plb_pp_stream) {
549 struct lima_ctx_plb_pp_stream_key key = {
550 .tiled_w = surf->tiled_w,
551 .tiled_h = surf->tiled_h,
552 };
553
554 for (int i = 0; i < lima_ctx_num_plb; i++) {
555 key.plb_index = i;
556
557 struct hash_entry *entry =
558 _mesa_hash_table_search(ctx->plb_pp_stream, &key);
559 struct lima_ctx_plb_pp_stream *s = entry->data;
560 if (--s->refcnt == 0) {
561 if (s->bo)
562 lima_bo_unreference(s->bo);
563 _mesa_hash_table_remove(ctx->plb_pp_stream, entry);
564 ralloc_free(s);
565 }
566 }
567 }
568
569 pipe_resource_reference(&psurf->texture, NULL);
570 FREE(surf);
571 }
572
573 static void *
574 lima_transfer_map(struct pipe_context *pctx,
575 struct pipe_resource *pres,
576 unsigned level,
577 unsigned usage,
578 const struct pipe_box *box,
579 struct pipe_transfer **pptrans)
580 {
581 struct lima_context *ctx = lima_context(pctx);
582 struct lima_resource *res = lima_resource(pres);
583 struct lima_bo *bo = res->bo;
584 struct lima_transfer *trans;
585 struct pipe_transfer *ptrans;
586
587 /* No direct mappings of tiled, since we need to manually
588 * tile/untile.
589 */
590 if (res->tiled && (usage & PIPE_TRANSFER_MAP_DIRECTLY))
591 return NULL;
592
593 /* use once buffers are made sure to not read/write overlapped
594 * range, so no need to sync */
595 if (pres->usage != PIPE_USAGE_STREAM) {
596 if (usage & PIPE_TRANSFER_READ_WRITE) {
597 if (lima_need_flush(ctx, bo, usage & PIPE_TRANSFER_WRITE))
598 lima_flush(ctx);
599
600 unsigned op = usage & PIPE_TRANSFER_WRITE ?
601 LIMA_GEM_WAIT_WRITE : LIMA_GEM_WAIT_READ;
602 lima_bo_wait(bo, op, PIPE_TIMEOUT_INFINITE);
603 }
604 }
605
606 if (!lima_bo_map(bo))
607 return NULL;
608
609 trans = slab_alloc(&ctx->transfer_pool);
610 if (!trans)
611 return NULL;
612
613 memset(trans, 0, sizeof(*trans));
614 ptrans = &trans->base;
615
616 pipe_resource_reference(&ptrans->resource, pres);
617 ptrans->level = level;
618 ptrans->usage = usage;
619 ptrans->box = *box;
620
621 *pptrans = ptrans;
622
623 if (res->tiled) {
624 ptrans->stride = util_format_get_stride(pres->format, ptrans->box.width);
625 ptrans->layer_stride = ptrans->stride * ptrans->box.height;
626
627 trans->staging = malloc(ptrans->stride * ptrans->box.height * ptrans->box.depth);
628
629 if (usage & PIPE_TRANSFER_READ) {
630 unsigned i;
631 for (i = 0; i < ptrans->box.depth; i++)
632 panfrost_load_tiled_image(
633 trans->staging + i * ptrans->stride * ptrans->box.height,
634 bo->map + res->levels[level].offset + (i + box->z) * res->levels[level].layer_stride,
635 ptrans->box.x, ptrans->box.y,
636 ptrans->box.width, ptrans->box.height,
637 ptrans->stride,
638 res->levels[level].stride,
639 pres->format);
640 }
641
642 return trans->staging;
643 } else {
644 ptrans->stride = res->levels[level].stride;
645 ptrans->layer_stride = res->levels[level].layer_stride;
646
647 return bo->map + res->levels[level].offset +
648 box->z * res->levels[level].layer_stride +
649 box->y / util_format_get_blockheight(pres->format) * ptrans->stride +
650 box->x / util_format_get_blockwidth(pres->format) *
651 util_format_get_blocksize(pres->format);
652 }
653 }
654
655 static void
656 lima_transfer_flush_region(struct pipe_context *pctx,
657 struct pipe_transfer *ptrans,
658 const struct pipe_box *box)
659 {
660
661 }
662
663 static void
664 lima_transfer_unmap(struct pipe_context *pctx,
665 struct pipe_transfer *ptrans)
666 {
667 struct lima_context *ctx = lima_context(pctx);
668 struct lima_transfer *trans = lima_transfer(ptrans);
669 struct lima_resource *res = lima_resource(ptrans->resource);
670 struct lima_bo *bo = res->bo;
671 struct pipe_resource *pres;
672
673 if (trans->staging) {
674 pres = &res->base;
675 if (ptrans->usage & PIPE_TRANSFER_WRITE) {
676 unsigned i;
677 for (i = 0; i < ptrans->box.depth; i++)
678 panfrost_store_tiled_image(
679 bo->map + res->levels[ptrans->level].offset + (i + ptrans->box.z) * res->levels[ptrans->level].layer_stride,
680 trans->staging + i * ptrans->stride * ptrans->box.height,
681 ptrans->box.x, ptrans->box.y,
682 ptrans->box.width, ptrans->box.height,
683 res->levels[ptrans->level].stride,
684 ptrans->stride,
685 pres->format);
686 }
687 free(trans->staging);
688 }
689
690 pipe_resource_reference(&ptrans->resource, NULL);
691 slab_free(&ctx->transfer_pool, trans);
692 }
693
694 static void
695 lima_util_blitter_save_states(struct lima_context *ctx)
696 {
697 util_blitter_save_blend(ctx->blitter, (void *)ctx->blend);
698 util_blitter_save_depth_stencil_alpha(ctx->blitter, (void *)ctx->zsa);
699 util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
700 util_blitter_save_rasterizer(ctx->blitter, (void *)ctx->rasterizer);
701 util_blitter_save_fragment_shader(ctx->blitter, ctx->fs);
702 util_blitter_save_vertex_shader(ctx->blitter, ctx->vs);
703 util_blitter_save_viewport(ctx->blitter,
704 &ctx->viewport.transform);
705 util_blitter_save_scissor(ctx->blitter, &ctx->scissor);
706 util_blitter_save_vertex_elements(ctx->blitter,
707 ctx->vertex_elements);
708 util_blitter_save_vertex_buffer_slot(ctx->blitter,
709 ctx->vertex_buffers.vb);
710
711 util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer.base);
712
713 util_blitter_save_fragment_sampler_states(ctx->blitter,
714 ctx->tex_stateobj.num_samplers,
715 (void**)ctx->tex_stateobj.samplers);
716 util_blitter_save_fragment_sampler_views(ctx->blitter,
717 ctx->tex_stateobj.num_textures,
718 ctx->tex_stateobj.textures);
719 }
720
721 static void
722 lima_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
723 {
724 struct lima_context *ctx = lima_context(pctx);
725 struct pipe_blit_info info = *blit_info;
726
727 if (util_try_blit_via_copy_region(pctx, &info)) {
728 return; /* done */
729 }
730
731 if (info.mask & PIPE_MASK_S) {
732 debug_printf("lima: cannot blit stencil, skipping\n");
733 info.mask &= ~PIPE_MASK_S;
734 }
735
736 if (!util_blitter_is_blit_supported(ctx->blitter, &info)) {
737 debug_printf("lima: blit unsupported %s -> %s\n",
738 util_format_short_name(info.src.resource->format),
739 util_format_short_name(info.dst.resource->format));
740 return;
741 }
742
743 lima_util_blitter_save_states(ctx);
744
745 util_blitter_blit(ctx->blitter, &info);
746 }
747
748 static void
749 lima_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
750 {
751
752 }
753
754 void
755 lima_resource_context_init(struct lima_context *ctx)
756 {
757 ctx->base.create_surface = lima_surface_create;
758 ctx->base.surface_destroy = lima_surface_destroy;
759
760 /* TODO: optimize these functions to read/write data directly
761 * from/to target instead of creating a staging memory for tiled
762 * buffer indirectly
763 */
764 ctx->base.buffer_subdata = u_default_buffer_subdata;
765 ctx->base.texture_subdata = u_default_texture_subdata;
766 ctx->base.resource_copy_region = util_resource_copy_region;
767
768 ctx->base.blit = lima_blit;
769
770 ctx->base.transfer_map = lima_transfer_map;
771 ctx->base.transfer_flush_region = lima_transfer_flush_region;
772 ctx->base.transfer_unmap = lima_transfer_unmap;
773
774 ctx->base.flush_resource = lima_flush_resource;
775 }