lima: fix tile buffer reloading
[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/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 "lima_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
120 /* The start address of each level <= 10 must be 64-aligned
121 * in order to be able to pass the addresses
122 * to the hardware.
123 * The start addresses of level 11 and level 12 are passed
124 * implicitely: they start at an offset of respectively
125 * 0x0400 and 0x0800 from the start address of level 10 */
126 if (level < 10)
127 size += align(actual_level_size, 64);
128 else if (level != pres->last_level)
129 size += 0x0400;
130 else
131 size += actual_level_size; /* Save some memory */
132
133 width = u_minify(width, 1);
134 height = u_minify(height, 1);
135 depth = u_minify(depth, 1);
136 }
137
138 return size;
139 }
140
141 static struct pipe_resource *
142 lima_resource_create_bo(struct pipe_screen *pscreen,
143 const struct pipe_resource *templat,
144 unsigned width, unsigned height,
145 bool should_align_dimensions)
146 {
147 struct lima_screen *screen = lima_screen(pscreen);
148 struct lima_resource *res;
149 struct pipe_resource *pres;
150
151 res = CALLOC_STRUCT(lima_resource);
152 if (!res)
153 return NULL;
154
155 res->base = *templat;
156 res->base.screen = pscreen;
157 pipe_reference_init(&res->base.reference, 1);
158
159 pres = &res->base;
160
161 uint32_t size = setup_miptree(res, width, height, should_align_dimensions);
162 size = align(size, LIMA_PAGE_SIZE);
163
164 res->bo = lima_bo_create(screen, size, 0);
165 if (!res->bo) {
166 FREE(res);
167 return NULL;
168 }
169
170 return pres;
171 }
172
173 static struct pipe_resource *
174 _lima_resource_create_with_modifiers(struct pipe_screen *pscreen,
175 const struct pipe_resource *templat,
176 const uint64_t *modifiers,
177 int count)
178 {
179 struct lima_screen *screen = lima_screen(pscreen);
180 bool should_tile = false;
181 unsigned width, height;
182 bool should_align_dimensions;
183
184 /* VBOs/PBOs are untiled (and 1 height). */
185 if (templat->target == PIPE_BUFFER)
186 should_tile = false;
187
188 if (templat->bind & (PIPE_BIND_LINEAR | PIPE_BIND_SCANOUT))
189 should_tile = false;
190
191 /* if linear buffer is not allowed, alloc fail */
192 if (!should_tile && !drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count))
193 return NULL;
194
195 if (should_tile || (templat->bind & PIPE_BIND_RENDER_TARGET) ||
196 (templat->bind & PIPE_BIND_DEPTH_STENCIL)) {
197 should_align_dimensions = true;
198 width = align(templat->width0, 16);
199 height = align(templat->height0, 16);
200 }
201 else {
202 should_align_dimensions = false;
203 width = templat->width0;
204 height = templat->height0;
205 }
206
207 struct pipe_resource *pres;
208 if (screen->ro && (templat->bind & PIPE_BIND_SCANOUT))
209 pres = lima_resource_create_scanout(pscreen, templat, width, height);
210 else
211 pres = lima_resource_create_bo(pscreen, templat, width, height,
212 should_align_dimensions);
213
214 if (pres) {
215 struct lima_resource *res = lima_resource(pres);
216 res->tiled = should_tile;
217
218 debug_printf("%s: pres=%p width=%u height=%u depth=%u target=%d "
219 "bind=%x usage=%d tile=%d last_level=%d\n", __func__,
220 pres, pres->width0, pres->height0, pres->depth0,
221 pres->target, pres->bind, pres->usage, should_tile, templat->last_level);
222 }
223 return pres;
224 }
225
226 static struct pipe_resource *
227 lima_resource_create(struct pipe_screen *pscreen,
228 const struct pipe_resource *templat)
229 {
230 static const uint64_t modifiers[] = {
231 DRM_FORMAT_MOD_LINEAR,
232 };
233 return _lima_resource_create_with_modifiers(pscreen, templat, modifiers, ARRAY_SIZE(modifiers));
234 }
235
236 static struct pipe_resource *
237 lima_resource_create_with_modifiers(struct pipe_screen *pscreen,
238 const struct pipe_resource *templat,
239 const uint64_t *modifiers,
240 int count)
241 {
242 struct pipe_resource tmpl = *templat;
243
244 /* gbm_bo_create_with_modifiers & gbm_surface_create_with_modifiers
245 * don't have usage parameter, but buffer created by these functions
246 * may be used for scanout. So we assume buffer created by this
247 * function always enable scanout if linear modifier is permitted.
248 */
249 if (drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count))
250 tmpl.bind |= PIPE_BIND_SCANOUT;
251
252 return _lima_resource_create_with_modifiers(pscreen, &tmpl, modifiers, count);
253 }
254
255 static void
256 lima_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *pres)
257 {
258 struct lima_screen *screen = lima_screen(pscreen);
259 struct lima_resource *res = lima_resource(pres);
260
261 if (res->bo)
262 lima_bo_free(res->bo);
263
264 if (res->scanout)
265 renderonly_scanout_destroy(res->scanout, screen->ro);
266
267 FREE(res);
268 }
269
270 static struct pipe_resource *
271 lima_resource_from_handle(struct pipe_screen *pscreen,
272 const struct pipe_resource *templat,
273 struct winsys_handle *handle, unsigned usage)
274 {
275 struct lima_resource *res;
276 struct lima_screen *screen = lima_screen(pscreen);
277
278 res = CALLOC_STRUCT(lima_resource);
279 if (!res)
280 return NULL;
281
282 struct pipe_resource *pres = &res->base;
283 *pres = *templat;
284 pres->screen = pscreen;
285 pipe_reference_init(&pres->reference, 1);
286 res->levels[0].offset = 0;
287 res->levels[0].stride = handle->stride;
288
289 res->bo = lima_bo_import(screen, handle);
290 if (!res->bo) {
291 FREE(res);
292 return NULL;
293 }
294
295 /* check alignment for the buffer */
296 if (pres->bind & PIPE_BIND_RENDER_TARGET) {
297 unsigned width, height, stride, size;
298
299 width = align(pres->width0, 16);
300 height = align(pres->height0, 16);
301 stride = util_format_get_stride(pres->format, width);
302 size = util_format_get_2d_size(pres->format, stride, height);
303
304 if (res->levels[0].stride != stride || res->bo->size < size) {
305 debug_error("import buffer not properly aligned\n");
306 goto err_out;
307 }
308
309 res->levels[0].width = width;
310 }
311 else
312 res->levels[0].width = pres->width0;
313
314 handle->modifier = DRM_FORMAT_MOD_LINEAR;
315 res->tiled = false;
316
317 return pres;
318
319 err_out:
320 lima_resource_destroy(pscreen, pres);
321 return NULL;
322 }
323
324 static boolean
325 lima_resource_get_handle(struct pipe_screen *pscreen,
326 struct pipe_context *pctx,
327 struct pipe_resource *pres,
328 struct winsys_handle *handle, unsigned usage)
329 {
330 struct lima_screen *screen = lima_screen(pscreen);
331 struct lima_resource *res = lima_resource(pres);
332
333 handle->modifier = DRM_FORMAT_MOD_LINEAR;
334
335 if (handle->type == WINSYS_HANDLE_TYPE_KMS && screen->ro &&
336 renderonly_get_handle(res->scanout, handle))
337 return TRUE;
338
339 if (!lima_bo_export(res->bo, handle))
340 return FALSE;
341
342 handle->stride = res->levels[0].stride;
343 return TRUE;
344 }
345
346 void
347 lima_resource_screen_init(struct lima_screen *screen)
348 {
349 screen->base.resource_create = lima_resource_create;
350 screen->base.resource_create_with_modifiers = lima_resource_create_with_modifiers;
351 screen->base.resource_from_handle = lima_resource_from_handle;
352 screen->base.resource_destroy = lima_resource_destroy;
353 screen->base.resource_get_handle = lima_resource_get_handle;
354 }
355
356 static struct pipe_surface *
357 lima_surface_create(struct pipe_context *pctx,
358 struct pipe_resource *pres,
359 const struct pipe_surface *surf_tmpl)
360 {
361 struct lima_surface *surf = CALLOC_STRUCT(lima_surface);
362
363 if (!surf)
364 return NULL;
365
366 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
367
368 struct pipe_surface *psurf = &surf->base;
369 unsigned level = surf_tmpl->u.tex.level;
370
371 pipe_reference_init(&psurf->reference, 1);
372 pipe_resource_reference(&psurf->texture, pres);
373
374 psurf->context = pctx;
375 psurf->format = surf_tmpl->format;
376 psurf->width = u_minify(pres->width0, level);
377 psurf->height = u_minify(pres->height0, level);
378 psurf->u.tex.level = level;
379 psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
380 psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
381
382 surf->tiled_w = align(psurf->width, 16) >> 4;
383 surf->tiled_h = align(psurf->height, 16) >> 4;
384
385 surf->reload = true;
386
387 struct lima_context *ctx = lima_context(pctx);
388 if (ctx->plb_pp_stream) {
389 struct lima_ctx_plb_pp_stream_key key = {
390 .tiled_w = surf->tiled_w,
391 .tiled_h = surf->tiled_h,
392 };
393
394 for (int i = 0; i < lima_ctx_num_plb; i++) {
395 key.plb_index = i;
396
397 struct hash_entry *entry =
398 _mesa_hash_table_search(ctx->plb_pp_stream, &key);
399 if (entry) {
400 struct lima_ctx_plb_pp_stream *s = entry->data;
401 s->refcnt++;
402 }
403 else {
404 struct lima_ctx_plb_pp_stream *s =
405 ralloc(ctx->plb_pp_stream, struct lima_ctx_plb_pp_stream);
406 s->key.plb_index = i;
407 s->key.tiled_w = surf->tiled_w;
408 s->key.tiled_h = surf->tiled_h;
409 s->refcnt = 1;
410 s->bo = NULL;
411 _mesa_hash_table_insert(ctx->plb_pp_stream, &s->key, s);
412 }
413 }
414 }
415
416 return &surf->base;
417 }
418
419 static void
420 lima_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
421 {
422 struct lima_surface *surf = lima_surface(psurf);
423 /* psurf->context may be not equal with pctx (i.e. glxinfo) */
424 struct lima_context *ctx = lima_context(psurf->context);
425
426 if (ctx->plb_pp_stream) {
427 struct lima_ctx_plb_pp_stream_key key = {
428 .tiled_w = surf->tiled_w,
429 .tiled_h = surf->tiled_h,
430 };
431
432 for (int i = 0; i < lima_ctx_num_plb; i++) {
433 key.plb_index = i;
434
435 struct hash_entry *entry =
436 _mesa_hash_table_search(ctx->plb_pp_stream, &key);
437 struct lima_ctx_plb_pp_stream *s = entry->data;
438 if (--s->refcnt == 0) {
439 if (s->bo)
440 lima_bo_free(s->bo);
441 _mesa_hash_table_remove(ctx->plb_pp_stream, entry);
442 ralloc_free(s);
443 }
444 }
445 }
446
447 pipe_resource_reference(&psurf->texture, NULL);
448 FREE(surf);
449 }
450
451 static void *
452 lima_transfer_map(struct pipe_context *pctx,
453 struct pipe_resource *pres,
454 unsigned level,
455 unsigned usage,
456 const struct pipe_box *box,
457 struct pipe_transfer **pptrans)
458 {
459 struct lima_context *ctx = lima_context(pctx);
460 struct lima_resource *res = lima_resource(pres);
461 struct lima_bo *bo = res->bo;
462 struct lima_transfer *trans;
463 struct pipe_transfer *ptrans;
464
465 /* No direct mappings of tiled, since we need to manually
466 * tile/untile.
467 */
468 if (res->tiled && (usage & PIPE_TRANSFER_MAP_DIRECTLY))
469 return NULL;
470
471 /* use once buffers are made sure to not read/write overlapped
472 * range, so no need to sync */
473 if (pres->usage != PIPE_USAGE_STREAM) {
474 if (usage & PIPE_TRANSFER_READ_WRITE) {
475 if (lima_need_flush(ctx, bo, usage & PIPE_TRANSFER_WRITE))
476 lima_flush(ctx);
477
478 unsigned op = usage & PIPE_TRANSFER_WRITE ?
479 LIMA_GEM_WAIT_WRITE : LIMA_GEM_WAIT_READ;
480 lima_bo_wait(bo, op, PIPE_TIMEOUT_INFINITE);
481 }
482 }
483
484 if (!lima_bo_map(bo))
485 return NULL;
486
487 trans = slab_alloc(&ctx->transfer_pool);
488 if (!trans)
489 return NULL;
490
491 memset(trans, 0, sizeof(*trans));
492 ptrans = &trans->base;
493
494 pipe_resource_reference(&ptrans->resource, pres);
495 ptrans->level = level;
496 ptrans->usage = usage;
497 ptrans->box = *box;
498
499 *pptrans = ptrans;
500
501 if (res->tiled) {
502 ptrans->stride = util_format_get_stride(pres->format, ptrans->box.width);
503 ptrans->layer_stride = ptrans->stride * ptrans->box.height;
504
505 trans->staging = malloc(ptrans->stride * ptrans->box.height * ptrans->box.depth);
506
507 if (usage & PIPE_TRANSFER_READ)
508 lima_load_tiled_image(trans->staging, bo->map + res->levels[level].offset,
509 &ptrans->box,
510 ptrans->stride,
511 res->levels[level].stride,
512 util_format_get_blocksize(pres->format));
513
514 return trans->staging;
515 } else {
516 ptrans->stride = res->levels[level].stride;
517 ptrans->layer_stride = ptrans->stride * box->height;
518
519 return bo->map + res->levels[level].offset +
520 box->z * ptrans->layer_stride +
521 box->y / util_format_get_blockheight(pres->format) * ptrans->stride +
522 box->x / util_format_get_blockwidth(pres->format) *
523 util_format_get_blocksize(pres->format);
524 }
525 }
526
527 static void
528 lima_transfer_flush_region(struct pipe_context *pctx,
529 struct pipe_transfer *ptrans,
530 const struct pipe_box *box)
531 {
532
533 }
534
535 static void
536 lima_transfer_unmap(struct pipe_context *pctx,
537 struct pipe_transfer *ptrans)
538 {
539 struct lima_context *ctx = lima_context(pctx);
540 struct lima_transfer *trans = lima_transfer(ptrans);
541 struct lima_resource *res = lima_resource(ptrans->resource);
542 struct lima_bo *bo = res->bo;
543 struct pipe_resource *pres;
544
545 if (trans->staging) {
546 pres = &res->base;
547 if (ptrans->usage & PIPE_TRANSFER_WRITE)
548 lima_store_tiled_image(bo->map + res->levels[ptrans->level].offset, trans->staging,
549 &ptrans->box,
550 res->levels[ptrans->level].stride,
551 ptrans->stride,
552 util_format_get_blocksize(pres->format));
553 free(trans->staging);
554 }
555
556 pipe_resource_reference(&ptrans->resource, NULL);
557 slab_free(&ctx->transfer_pool, trans);
558 }
559
560 static void
561 lima_util_blitter_save_states(struct lima_context *ctx)
562 {
563 util_blitter_save_blend(ctx->blitter, (void *)ctx->blend);
564 util_blitter_save_depth_stencil_alpha(ctx->blitter, (void *)ctx->zsa);
565 util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
566 util_blitter_save_rasterizer(ctx->blitter, (void *)ctx->rasterizer);
567 util_blitter_save_fragment_shader(ctx->blitter, ctx->fs);
568 util_blitter_save_vertex_shader(ctx->blitter, ctx->vs);
569 util_blitter_save_viewport(ctx->blitter,
570 &ctx->viewport.transform);
571 util_blitter_save_scissor(ctx->blitter, &ctx->scissor);
572 util_blitter_save_vertex_elements(ctx->blitter,
573 ctx->vertex_elements);
574 util_blitter_save_vertex_buffer_slot(ctx->blitter,
575 ctx->vertex_buffers.vb);
576
577 util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer.base);
578
579 util_blitter_save_fragment_sampler_states(ctx->blitter,
580 ctx->tex_stateobj.num_samplers,
581 (void**)ctx->tex_stateobj.samplers);
582 util_blitter_save_fragment_sampler_views(ctx->blitter,
583 ctx->tex_stateobj.num_textures,
584 ctx->tex_stateobj.textures);
585 }
586
587 static void
588 lima_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
589 {
590 struct lima_context *ctx = lima_context(pctx);
591 struct pipe_blit_info info = *blit_info;
592
593 if (util_try_blit_via_copy_region(pctx, &info)) {
594 return; /* done */
595 }
596
597 if (info.mask & PIPE_MASK_S) {
598 debug_printf("lima: cannot blit stencil, skipping\n");
599 info.mask &= ~PIPE_MASK_S;
600 }
601
602 if (!util_blitter_is_blit_supported(ctx->blitter, &info)) {
603 debug_printf("lima: blit unsupported %s -> %s\n",
604 util_format_short_name(info.src.resource->format),
605 util_format_short_name(info.dst.resource->format));
606 return;
607 }
608
609 lima_util_blitter_save_states(ctx);
610
611 util_blitter_blit(ctx->blitter, &info);
612 }
613
614 static void
615 lima_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
616 {
617
618 }
619
620 void
621 lima_resource_context_init(struct lima_context *ctx)
622 {
623 ctx->base.create_surface = lima_surface_create;
624 ctx->base.surface_destroy = lima_surface_destroy;
625
626 /* TODO: optimize these functions to read/write data directly
627 * from/to target instead of creating a staging memory for tiled
628 * buffer indirectly
629 */
630 ctx->base.buffer_subdata = u_default_buffer_subdata;
631 ctx->base.texture_subdata = u_default_texture_subdata;
632 ctx->base.resource_copy_region = util_resource_copy_region;
633
634 ctx->base.blit = lima_blit;
635
636 ctx->base.transfer_map = lima_transfer_map;
637 ctx->base.transfer_flush_region = lima_transfer_flush_region;
638 ctx->base.transfer_unmap = lima_transfer_unmap;
639
640 ctx->base.flush_resource = lima_flush_resource;
641 }