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