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