nv50/ir: when merging immediates/consts, load directly
[mesa.git] / src / gallium / drivers / vc5 / vc5_resource.c
1 /*
2 * Copyright © 2014-2017 Broadcom
3 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include "util/u_blit.h"
26 #include "util/u_memory.h"
27 #include "util/u_format.h"
28 #include "util/u_inlines.h"
29 #include "util/u_surface.h"
30 #include "util/u_upload_mgr.h"
31
32 #include "drm_fourcc.h"
33 #include "vc5_screen.h"
34 #include "vc5_context.h"
35 #include "vc5_resource.h"
36 #include "vc5_tiling.h"
37 #include "broadcom/cle/v3d_packet_v33_pack.h"
38
39 #ifndef DRM_FORMAT_MOD_INVALID
40 #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
41 #endif
42
43 static void
44 vc5_debug_resource_layout(struct vc5_resource *rsc, const char *caller)
45 {
46 if (!(V3D_DEBUG & V3D_DEBUG_SURFACE))
47 return;
48
49 struct pipe_resource *prsc = &rsc->base;
50
51 if (prsc->target == PIPE_BUFFER) {
52 fprintf(stderr,
53 "rsc %s %p (format %s), %dx%d buffer @0x%08x-0x%08x\n",
54 caller, rsc,
55 util_format_short_name(prsc->format),
56 prsc->width0, prsc->height0,
57 rsc->bo->offset,
58 rsc->bo->offset + rsc->bo->size - 1);
59 return;
60 }
61
62 static const char *const tiling_descriptions[] = {
63 [VC5_TILING_RASTER] = "R",
64 [VC5_TILING_LINEARTILE] = "LT",
65 [VC5_TILING_UBLINEAR_1_COLUMN] = "UB1",
66 [VC5_TILING_UBLINEAR_2_COLUMN] = "UB2",
67 [VC5_TILING_UIF_NO_XOR] = "UIF",
68 [VC5_TILING_UIF_XOR] = "UIF^",
69 };
70
71 for (int i = 0; i <= prsc->last_level; i++) {
72 struct vc5_resource_slice *slice = &rsc->slices[i];
73
74 int level_width = slice->stride / rsc->cpp;
75 int level_height = slice->size / slice->stride;
76
77 fprintf(stderr,
78 "rsc %s %p (format %s), %dx%d: "
79 "level %d (%s) %dx%d -> %dx%d, stride %d@0x%08x\n",
80 caller, rsc,
81 util_format_short_name(prsc->format),
82 prsc->width0, prsc->height0,
83 i, tiling_descriptions[slice->tiling],
84 u_minify(prsc->width0, i),
85 u_minify(prsc->height0, i),
86 level_width,
87 level_height,
88 slice->stride,
89 rsc->bo->offset + slice->offset);
90 }
91 }
92
93 static bool
94 vc5_resource_bo_alloc(struct vc5_resource *rsc)
95 {
96 struct pipe_resource *prsc = &rsc->base;
97 struct pipe_screen *pscreen = prsc->screen;
98 struct vc5_bo *bo;
99 int layers = (prsc->target == PIPE_TEXTURE_3D ?
100 prsc->depth0 : prsc->array_size);
101
102 bo = vc5_bo_alloc(vc5_screen(pscreen),
103 rsc->slices[0].offset +
104 rsc->slices[0].size +
105 rsc->cube_map_stride * layers - 1,
106 "resource");
107 if (bo) {
108 vc5_bo_unreference(&rsc->bo);
109 rsc->bo = bo;
110 vc5_debug_resource_layout(rsc, "alloc");
111 return true;
112 } else {
113 return false;
114 }
115 }
116
117 static void
118 vc5_resource_transfer_unmap(struct pipe_context *pctx,
119 struct pipe_transfer *ptrans)
120 {
121 struct vc5_context *vc5 = vc5_context(pctx);
122 struct vc5_transfer *trans = vc5_transfer(ptrans);
123
124 if (trans->map) {
125 struct vc5_resource *rsc;
126 struct vc5_resource_slice *slice;
127 if (trans->ss_resource) {
128 rsc = vc5_resource(trans->ss_resource);
129 slice = &rsc->slices[0];
130 } else {
131 rsc = vc5_resource(ptrans->resource);
132 slice = &rsc->slices[ptrans->level];
133 }
134
135 if (ptrans->usage & PIPE_TRANSFER_WRITE) {
136 vc5_store_tiled_image(rsc->bo->map + slice->offset +
137 ptrans->box.z * rsc->cube_map_stride,
138 slice->stride,
139 trans->map, ptrans->stride,
140 slice->tiling, rsc->cpp,
141 rsc->base.height0,
142 &ptrans->box);
143 }
144 free(trans->map);
145 }
146
147 if (trans->ss_resource && (ptrans->usage & PIPE_TRANSFER_WRITE)) {
148 struct pipe_blit_info blit;
149 memset(&blit, 0, sizeof(blit));
150
151 blit.src.resource = trans->ss_resource;
152 blit.src.format = trans->ss_resource->format;
153 blit.src.box.width = trans->ss_box.width;
154 blit.src.box.height = trans->ss_box.height;
155 blit.src.box.depth = 1;
156
157 blit.dst.resource = ptrans->resource;
158 blit.dst.format = ptrans->resource->format;
159 blit.dst.level = ptrans->level;
160 blit.dst.box = trans->ss_box;
161
162 blit.mask = util_format_get_mask(ptrans->resource->format);
163 blit.filter = PIPE_TEX_FILTER_NEAREST;
164
165 pctx->blit(pctx, &blit);
166
167 pipe_resource_reference(&trans->ss_resource, NULL);
168 }
169
170 pipe_resource_reference(&ptrans->resource, NULL);
171 slab_free(&vc5->transfer_pool, ptrans);
172 }
173
174 static struct pipe_resource *
175 vc5_get_temp_resource(struct pipe_context *pctx,
176 struct pipe_resource *prsc,
177 const struct pipe_box *box)
178 {
179 struct pipe_resource temp_setup;
180
181 memset(&temp_setup, 0, sizeof(temp_setup));
182 temp_setup.target = prsc->target;
183 temp_setup.format = prsc->format;
184 temp_setup.width0 = box->width;
185 temp_setup.height0 = box->height;
186 temp_setup.depth0 = 1;
187 temp_setup.array_size = 1;
188
189 return pctx->screen->resource_create(pctx->screen, &temp_setup);
190 }
191
192 static void *
193 vc5_resource_transfer_map(struct pipe_context *pctx,
194 struct pipe_resource *prsc,
195 unsigned level, unsigned usage,
196 const struct pipe_box *box,
197 struct pipe_transfer **pptrans)
198 {
199 struct vc5_context *vc5 = vc5_context(pctx);
200 struct vc5_resource *rsc = vc5_resource(prsc);
201 struct vc5_transfer *trans;
202 struct pipe_transfer *ptrans;
203 enum pipe_format format = prsc->format;
204 char *buf;
205
206 /* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is
207 * being mapped.
208 */
209 if ((usage & PIPE_TRANSFER_DISCARD_RANGE) &&
210 !(usage & PIPE_TRANSFER_UNSYNCHRONIZED) &&
211 !(prsc->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT) &&
212 prsc->last_level == 0 &&
213 prsc->width0 == box->width &&
214 prsc->height0 == box->height &&
215 prsc->depth0 == box->depth &&
216 prsc->array_size == 1 &&
217 rsc->bo->private) {
218 usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
219 }
220
221 if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
222 if (vc5_resource_bo_alloc(rsc)) {
223 /* If it might be bound as one of our vertex buffers
224 * or UBOs, make sure we re-emit vertex buffer state
225 * or uniforms.
226 */
227 if (prsc->bind & PIPE_BIND_VERTEX_BUFFER)
228 vc5->dirty |= VC5_DIRTY_VTXBUF;
229 if (prsc->bind & PIPE_BIND_CONSTANT_BUFFER)
230 vc5->dirty |= VC5_DIRTY_CONSTBUF;
231 } else {
232 /* If we failed to reallocate, flush users so that we
233 * don't violate any syncing requirements.
234 */
235 vc5_flush_jobs_reading_resource(vc5, prsc);
236 }
237 } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
238 /* If we're writing and the buffer is being used by the CL, we
239 * have to flush the CL first. If we're only reading, we need
240 * to flush if the CL has written our buffer.
241 */
242 if (usage & PIPE_TRANSFER_WRITE)
243 vc5_flush_jobs_reading_resource(vc5, prsc);
244 else
245 vc5_flush_jobs_writing_resource(vc5, prsc);
246 }
247
248 if (usage & PIPE_TRANSFER_WRITE) {
249 rsc->writes++;
250 rsc->initialized_buffers = ~0;
251 }
252
253 trans = slab_alloc(&vc5->transfer_pool);
254 if (!trans)
255 return NULL;
256
257 /* XXX: Handle DONTBLOCK, DISCARD_RANGE, PERSISTENT, COHERENT. */
258
259 /* slab_alloc_st() doesn't zero: */
260 memset(trans, 0, sizeof(*trans));
261 ptrans = &trans->base;
262
263 pipe_resource_reference(&ptrans->resource, prsc);
264 ptrans->level = level;
265 ptrans->usage = usage;
266 ptrans->box = *box;
267
268 /* If the resource is multisampled, we need to resolve to single
269 * sample. This seems like it should be handled at a higher layer.
270 */
271 if (prsc->nr_samples > 1) {
272 trans->ss_resource = vc5_get_temp_resource(pctx, prsc, box);
273 if (!trans->ss_resource)
274 goto fail;
275 assert(!trans->ss_resource->nr_samples);
276
277 /* The ptrans->box gets modified for tile alignment, so save
278 * the original box for unmap time.
279 */
280 trans->ss_box = *box;
281
282 if (usage & PIPE_TRANSFER_READ) {
283 struct pipe_blit_info blit;
284 memset(&blit, 0, sizeof(blit));
285
286 blit.src.resource = ptrans->resource;
287 blit.src.format = ptrans->resource->format;
288 blit.src.level = ptrans->level;
289 blit.src.box = trans->ss_box;
290
291 blit.dst.resource = trans->ss_resource;
292 blit.dst.format = trans->ss_resource->format;
293 blit.dst.box.width = trans->ss_box.width;
294 blit.dst.box.height = trans->ss_box.height;
295 blit.dst.box.depth = 1;
296
297 blit.mask = util_format_get_mask(prsc->format);
298 blit.filter = PIPE_TEX_FILTER_NEAREST;
299
300 pctx->blit(pctx, &blit);
301 vc5_flush_jobs_writing_resource(vc5, blit.dst.resource);
302 }
303
304 /* The rest of the mapping process should use our temporary. */
305 prsc = trans->ss_resource;
306 rsc = vc5_resource(prsc);
307 ptrans->box.x = 0;
308 ptrans->box.y = 0;
309 ptrans->box.z = 0;
310 }
311
312 /* Note that the current kernel implementation is synchronous, so no
313 * need to do syncing stuff here yet.
314 */
315
316 if (usage & PIPE_TRANSFER_UNSYNCHRONIZED)
317 buf = vc5_bo_map_unsynchronized(rsc->bo);
318 else
319 buf = vc5_bo_map(rsc->bo);
320 if (!buf) {
321 fprintf(stderr, "Failed to map bo\n");
322 goto fail;
323 }
324
325 *pptrans = ptrans;
326
327 struct vc5_resource_slice *slice = &rsc->slices[level];
328 if (rsc->tiled) {
329 /* No direct mappings of tiled, since we need to manually
330 * tile/untile.
331 */
332 if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
333 return NULL;
334
335 ptrans->stride = ptrans->box.width * rsc->cpp;
336 ptrans->layer_stride = ptrans->stride * ptrans->box.height;
337
338 trans->map = malloc(ptrans->layer_stride * ptrans->box.depth);
339
340 if (usage & PIPE_TRANSFER_READ) {
341 vc5_load_tiled_image(trans->map, ptrans->stride,
342 buf + slice->offset +
343 ptrans->box.z * rsc->cube_map_stride,
344 slice->stride,
345 slice->tiling, rsc->cpp,
346 rsc->base.height0,
347 &ptrans->box);
348 }
349 return trans->map;
350 } else {
351 ptrans->stride = slice->stride;
352 ptrans->layer_stride = ptrans->stride;
353
354 return buf + slice->offset +
355 ptrans->box.y / util_format_get_blockheight(format) * ptrans->stride +
356 ptrans->box.x / util_format_get_blockwidth(format) * rsc->cpp +
357 ptrans->box.z * rsc->cube_map_stride;
358 }
359
360
361 fail:
362 vc5_resource_transfer_unmap(pctx, ptrans);
363 return NULL;
364 }
365
366 static void
367 vc5_resource_destroy(struct pipe_screen *pscreen,
368 struct pipe_resource *prsc)
369 {
370 struct vc5_resource *rsc = vc5_resource(prsc);
371 vc5_bo_unreference(&rsc->bo);
372 free(rsc);
373 }
374
375 static boolean
376 vc5_resource_get_handle(struct pipe_screen *pscreen,
377 struct pipe_context *pctx,
378 struct pipe_resource *prsc,
379 struct winsys_handle *whandle,
380 unsigned usage)
381 {
382 struct vc5_resource *rsc = vc5_resource(prsc);
383 struct vc5_bo *bo = rsc->bo;
384
385 whandle->stride = rsc->slices[0].stride;
386
387 /* If we're passing some reference to our BO out to some other part of
388 * the system, then we can't do any optimizations about only us being
389 * the ones seeing it (like BO caching).
390 */
391 bo->private = false;
392
393 switch (whandle->type) {
394 case DRM_API_HANDLE_TYPE_SHARED:
395 return vc5_bo_flink(bo, &whandle->handle);
396 case DRM_API_HANDLE_TYPE_KMS:
397 whandle->handle = bo->handle;
398 return TRUE;
399 case DRM_API_HANDLE_TYPE_FD:
400 whandle->handle = vc5_bo_get_dmabuf(bo);
401 return whandle->handle != -1;
402 }
403
404 return FALSE;
405 }
406
407 static void
408 vc5_setup_slices(struct vc5_resource *rsc)
409 {
410 struct pipe_resource *prsc = &rsc->base;
411 uint32_t width = prsc->width0;
412 uint32_t height = prsc->height0;
413 uint32_t pot_width = util_next_power_of_two(width);
414 uint32_t pot_height = util_next_power_of_two(height);
415 uint32_t offset = 0;
416 uint32_t utile_w = vc5_utile_width(rsc->cpp);
417 uint32_t utile_h = vc5_utile_height(rsc->cpp);
418 uint32_t uif_block_w = utile_w * 2;
419 uint32_t uif_block_h = utile_h * 2;
420 bool msaa = prsc->nr_samples > 1;
421 /* MSAA textures/renderbuffers are always laid out as single-level
422 * UIF.
423 */
424 bool uif_top = msaa;
425
426 for (int i = prsc->last_level; i >= 0; i--) {
427 struct vc5_resource_slice *slice = &rsc->slices[i];
428
429 uint32_t level_width, level_height;
430 if (i < 2) {
431 level_width = u_minify(width, i);
432 level_height = u_minify(height, i);
433 } else {
434 level_width = u_minify(pot_width, i);
435 level_height = u_minify(pot_height, i);
436 }
437
438 if (msaa) {
439 level_width *= 2;
440 level_height *= 2;
441 }
442
443 if (!rsc->tiled) {
444 slice->tiling = VC5_TILING_RASTER;
445 if (prsc->target == PIPE_TEXTURE_1D)
446 level_width = align(level_width, 64 / rsc->cpp);
447 } else {
448 if ((i != 0 || !uif_top) &&
449 (level_width <= utile_w ||
450 level_height <= utile_h)) {
451 slice->tiling = VC5_TILING_LINEARTILE;
452 level_width = align(level_width, utile_w);
453 level_height = align(level_height, utile_h);
454 } else if ((i != 0 || !uif_top) &&
455 level_width <= uif_block_w) {
456 slice->tiling = VC5_TILING_UBLINEAR_1_COLUMN;
457 level_width = align(level_width, uif_block_w);
458 level_height = align(level_height, uif_block_h);
459 } else if ((i != 0 || !uif_top) &&
460 level_width <= 2 * uif_block_w) {
461 slice->tiling = VC5_TILING_UBLINEAR_2_COLUMN;
462 level_width = align(level_width, 2 * uif_block_w);
463 level_height = align(level_height, uif_block_h);
464 } else {
465 slice->tiling = VC5_TILING_UIF_NO_XOR;
466
467 /* We align the width to a 4-block column of
468 * UIF blocks, but we only align height to UIF
469 * blocks.
470 */
471 level_width = align(level_width,
472 4 * uif_block_w);
473 level_height = align(level_height,
474 uif_block_h);
475 }
476 }
477
478 slice->offset = offset;
479 slice->stride = level_width * rsc->cpp;
480 slice->size = level_height * slice->stride;
481
482 offset += slice->size;
483 }
484
485 /* UIF/UBLINEAR levels need to be aligned to UIF-blocks, and LT only
486 * needs to be aligned to utile boundaries. Since tiles are laid out
487 * from small to big in memory, we need to align the later UIF slices
488 * to UIF blocks, if they were preceded by non-UIF-block-aligned LT
489 * slices.
490 *
491 * We additionally align to 4k, which improves UIF XOR performance.
492 */
493 uint32_t page_align_offset = (align(rsc->slices[0].offset, 4096) -
494 rsc->slices[0].offset);
495 if (page_align_offset) {
496 for (int i = 0; i <= prsc->last_level; i++)
497 rsc->slices[i].offset += page_align_offset;
498 }
499
500 /* Arrays, cubes, and 3D textures have a stride which is the distance
501 * from one full mipmap tree to the next (64b aligned).
502 */
503 rsc->cube_map_stride = align(rsc->slices[0].offset +
504 rsc->slices[0].size, 64);
505 }
506
507 static struct vc5_resource *
508 vc5_resource_setup(struct pipe_screen *pscreen,
509 const struct pipe_resource *tmpl)
510 {
511 struct vc5_resource *rsc = CALLOC_STRUCT(vc5_resource);
512 if (!rsc)
513 return NULL;
514 struct pipe_resource *prsc = &rsc->base;
515
516 *prsc = *tmpl;
517
518 pipe_reference_init(&prsc->reference, 1);
519 prsc->screen = pscreen;
520
521 if (prsc->nr_samples <= 1) {
522 rsc->cpp = util_format_get_blocksize(prsc->format);
523 } else {
524 assert(vc5_rt_format_supported(prsc->format));
525 uint32_t output_image_format = vc5_get_rt_format(prsc->format);
526 uint32_t internal_type;
527 uint32_t internal_bpp;
528 vc5_get_internal_type_bpp_for_output_format(output_image_format,
529 &internal_type,
530 &internal_bpp);
531 switch (internal_bpp) {
532 case INTERNAL_BPP_32:
533 rsc->cpp = 4;
534 break;
535 case INTERNAL_BPP_64:
536 rsc->cpp = 8;
537 break;
538 case INTERNAL_BPP_128:
539 rsc->cpp = 16;
540 break;
541 }
542 }
543
544 assert(rsc->cpp);
545
546 return rsc;
547 }
548
549 static bool
550 find_modifier(uint64_t needle, const uint64_t *haystack, int count)
551 {
552 int i;
553
554 for (i = 0; i < count; i++) {
555 if (haystack[i] == needle)
556 return true;
557 }
558
559 return false;
560 }
561
562 static struct pipe_resource *
563 vc5_resource_create_with_modifiers(struct pipe_screen *pscreen,
564 const struct pipe_resource *tmpl,
565 const uint64_t *modifiers,
566 int count)
567 {
568 bool linear_ok = find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count);
569 struct vc5_resource *rsc = vc5_resource_setup(pscreen, tmpl);
570 struct pipe_resource *prsc = &rsc->base;
571 /* Use a tiled layout if we can, for better 3D performance. */
572 bool should_tile = true;
573
574 /* VBOs/PBOs are untiled (and 1 height). */
575 if (tmpl->target == PIPE_BUFFER)
576 should_tile = false;
577
578 /* Cursors are always linear, and the user can request linear as well.
579 */
580 if (tmpl->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR))
581 should_tile = false;
582
583 /* 1D and 1D_ARRAY textures are always raster-order. */
584 if (tmpl->target == PIPE_TEXTURE_1D ||
585 tmpl->target == PIPE_TEXTURE_1D_ARRAY)
586 should_tile = false;
587
588 /* Scanout BOs for simulator need to be linear for interaction with
589 * i965.
590 */
591 if (using_vc5_simulator &&
592 tmpl->bind & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT))
593 should_tile = false;
594
595 /* No user-specified modifier; determine our own. */
596 if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
597 linear_ok = true;
598 rsc->tiled = should_tile;
599 } else if (should_tile &&
600 find_modifier(DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
601 modifiers, count)) {
602 rsc->tiled = true;
603 } else if (linear_ok) {
604 rsc->tiled = false;
605 } else {
606 fprintf(stderr, "Unsupported modifier requested\n");
607 return NULL;
608 }
609
610 vc5_setup_slices(rsc);
611 if (!vc5_resource_bo_alloc(rsc))
612 goto fail;
613
614 return prsc;
615 fail:
616 vc5_resource_destroy(pscreen, prsc);
617 return NULL;
618 }
619
620 struct pipe_resource *
621 vc5_resource_create(struct pipe_screen *pscreen,
622 const struct pipe_resource *tmpl)
623 {
624 const uint64_t mod = DRM_FORMAT_MOD_INVALID;
625 return vc5_resource_create_with_modifiers(pscreen, tmpl, &mod, 1);
626 }
627
628 static struct pipe_resource *
629 vc5_resource_from_handle(struct pipe_screen *pscreen,
630 const struct pipe_resource *tmpl,
631 struct winsys_handle *whandle,
632 unsigned usage)
633 {
634 struct vc5_screen *screen = vc5_screen(pscreen);
635 struct vc5_resource *rsc = vc5_resource_setup(pscreen, tmpl);
636 struct pipe_resource *prsc = &rsc->base;
637 struct vc5_resource_slice *slice = &rsc->slices[0];
638
639 if (!rsc)
640 return NULL;
641
642 switch (whandle->modifier) {
643 case DRM_FORMAT_MOD_LINEAR:
644 rsc->tiled = false;
645 break;
646 /* XXX: UIF */
647 default:
648 fprintf(stderr,
649 "Attempt to import unsupported modifier 0x%llx\n",
650 (long long)whandle->modifier);
651 goto fail;
652 }
653
654 if (whandle->offset != 0) {
655 fprintf(stderr,
656 "Attempt to import unsupported winsys offset %u\n",
657 whandle->offset);
658 goto fail;
659 }
660
661 switch (whandle->type) {
662 case DRM_API_HANDLE_TYPE_SHARED:
663 rsc->bo = vc5_bo_open_name(screen,
664 whandle->handle, whandle->stride);
665 break;
666 case DRM_API_HANDLE_TYPE_FD:
667 rsc->bo = vc5_bo_open_dmabuf(screen,
668 whandle->handle, whandle->stride);
669 break;
670 default:
671 fprintf(stderr,
672 "Attempt to import unsupported handle type %d\n",
673 whandle->type);
674 goto fail;
675 }
676
677 if (!rsc->bo)
678 goto fail;
679
680 vc5_setup_slices(rsc);
681 vc5_debug_resource_layout(rsc, "import");
682
683 if (whandle->stride != slice->stride) {
684 static bool warned = false;
685 if (!warned) {
686 warned = true;
687 fprintf(stderr,
688 "Attempting to import %dx%d %s with "
689 "unsupported stride %d instead of %d\n",
690 prsc->width0, prsc->height0,
691 util_format_short_name(prsc->format),
692 whandle->stride,
693 slice->stride);
694 }
695 goto fail;
696 }
697
698 return prsc;
699
700 fail:
701 vc5_resource_destroy(pscreen, prsc);
702 return NULL;
703 }
704
705 static struct pipe_surface *
706 vc5_create_surface(struct pipe_context *pctx,
707 struct pipe_resource *ptex,
708 const struct pipe_surface *surf_tmpl)
709 {
710 struct vc5_surface *surface = CALLOC_STRUCT(vc5_surface);
711 struct vc5_resource *rsc = vc5_resource(ptex);
712
713 if (!surface)
714 return NULL;
715
716 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
717
718 struct pipe_surface *psurf = &surface->base;
719 unsigned level = surf_tmpl->u.tex.level;
720 struct vc5_resource_slice *slice = &rsc->slices[level];
721
722 pipe_reference_init(&psurf->reference, 1);
723 pipe_resource_reference(&psurf->texture, ptex);
724
725 psurf->context = pctx;
726 psurf->format = surf_tmpl->format;
727 psurf->width = u_minify(ptex->width0, level);
728 psurf->height = u_minify(ptex->height0, level);
729 psurf->u.tex.level = level;
730 psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
731 psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
732
733 surface->offset = (slice->offset +
734 psurf->u.tex.first_layer * rsc->cube_map_stride);
735 surface->tiling = slice->tiling;
736 surface->format = vc5_get_rt_format(psurf->format);
737
738 if (util_format_is_depth_or_stencil(psurf->format)) {
739 switch (psurf->format) {
740 case PIPE_FORMAT_Z16_UNORM:
741 surface->internal_type = INTERNAL_TYPE_DEPTH_16;
742 break;
743 case PIPE_FORMAT_Z32_FLOAT:
744 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
745 surface->internal_type = INTERNAL_TYPE_DEPTH_32F;
746 break;
747 default:
748 surface->internal_type = INTERNAL_TYPE_DEPTH_24;
749 }
750 } else {
751 uint32_t bpp, type;
752 vc5_get_internal_type_bpp_for_output_format(surface->format,
753 &type, &bpp);
754 surface->internal_type = type;
755 surface->internal_bpp = bpp;
756 }
757
758 if (surface->tiling == VC5_TILING_UIF_NO_XOR ||
759 surface->tiling == VC5_TILING_UIF_XOR) {
760 surface->padded_height_of_output_image_in_uif_blocks =
761 ((slice->size / slice->stride) /
762 (2 * vc5_utile_height(rsc->cpp)));
763 }
764
765 return &surface->base;
766 }
767
768 static void
769 vc5_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
770 {
771 pipe_resource_reference(&psurf->texture, NULL);
772 FREE(psurf);
773 }
774
775 static void
776 vc5_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
777 {
778 /* All calls to flush_resource are followed by a flush of the context,
779 * so there's nothing to do.
780 */
781 }
782
783 void
784 vc5_resource_screen_init(struct pipe_screen *pscreen)
785 {
786 pscreen->resource_create_with_modifiers =
787 vc5_resource_create_with_modifiers;
788 pscreen->resource_create = vc5_resource_create;
789 pscreen->resource_from_handle = vc5_resource_from_handle;
790 pscreen->resource_get_handle = vc5_resource_get_handle;
791 pscreen->resource_destroy = vc5_resource_destroy;
792 }
793
794 void
795 vc5_resource_context_init(struct pipe_context *pctx)
796 {
797 pctx->transfer_map = vc5_resource_transfer_map;
798 pctx->transfer_flush_region = u_default_transfer_flush_region;
799 pctx->transfer_unmap = vc5_resource_transfer_unmap;
800 pctx->buffer_subdata = u_default_buffer_subdata;
801 pctx->texture_subdata = u_default_texture_subdata;
802 pctx->create_surface = vc5_create_surface;
803 pctx->surface_destroy = vc5_surface_destroy;
804 pctx->resource_copy_region = util_resource_copy_region;
805 pctx->blit = vc5_blit;
806 pctx->flush_resource = vc5_flush_resource;
807 }