1 /*
2  * Copyright (C) 2008 VMware, Inc.
3  * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
4  * Copyright (C) 2014-2017 Broadcom
5  * Copyright (C) 2018-2019 Alyssa Rosenzweig
6  * Copyright (C) 2019 Collabora, Ltd.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the next
16  * paragraph) shall be included in all copies or substantial portions of the
17  * Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  *
27  * Authors (Collabora):
28  *   Tomeu Vizoso <tomeu.vizoso@collabora.com>
29  *   Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
30  *
31  */
32 
33 #include <xf86drm.h>
34 #include <fcntl.h>
35 #include "drm-uapi/drm_fourcc.h"
36 
37 #include "frontend/winsys_handle.h"
38 #include "util/format/u_format.h"
39 #include "util/u_memory.h"
40 #include "util/u_surface.h"
41 #include "util/u_transfer.h"
42 #include "util/u_transfer_helper.h"
43 #include "util/u_gen_mipmap.h"
44 #include "util/u_drm.h"
45 
46 #include "pan_bo.h"
47 #include "pan_context.h"
48 #include "pan_screen.h"
49 #include "pan_resource.h"
50 #include "pan_util.h"
51 #include "pan_tiling.h"
52 #include "decode.h"
53 #include "panfrost-quirks.h"
54 
55 static struct pipe_resource *
panfrost_resource_from_handle(struct pipe_screen * pscreen,const struct pipe_resource * templat,struct winsys_handle * whandle,unsigned usage)56 panfrost_resource_from_handle(struct pipe_screen *pscreen,
57                               const struct pipe_resource *templat,
58                               struct winsys_handle *whandle,
59                               unsigned usage)
60 {
61         struct panfrost_device *dev = pan_device(pscreen);
62         struct panfrost_resource *rsc;
63         struct pipe_resource *prsc;
64 
65         assert(whandle->type == WINSYS_HANDLE_TYPE_FD);
66 
67         rsc = rzalloc(pscreen, struct panfrost_resource);
68         if (!rsc)
69                 return NULL;
70 
71         prsc = &rsc->base;
72 
73         *prsc = *templat;
74 
75         pipe_reference_init(&prsc->reference, 1);
76         prsc->screen = pscreen;
77 
78         rsc->bo = panfrost_bo_import(dev, whandle->handle);
79         rsc->internal_format = templat->format;
80         rsc->modifier = (whandle->modifier == DRM_FORMAT_MOD_INVALID) ?
81                 DRM_FORMAT_MOD_LINEAR : whandle->modifier;
82         rsc->modifier_constant = true;
83         rsc->slices[0].stride = whandle->stride;
84         rsc->slices[0].offset = whandle->offset;
85         rsc->slices[0].initialized = true;
86         panfrost_resource_set_damage_region(NULL, &rsc->base, 0, NULL);
87 
88         if (dev->quirks & IS_BIFROST &&
89             templat->bind & PIPE_BIND_RENDER_TARGET) {
90                 unsigned size = panfrost_compute_checksum_size(
91                                         &rsc->slices[0], templat->width0, templat->height0);
92                 rsc->slices[0].checksum_bo = panfrost_bo_create(dev, size, 0);
93                 rsc->checksummed = true;
94         }
95 
96         if (drm_is_afbc(whandle->modifier)) {
97                 rsc->slices[0].header_size =
98                         panfrost_afbc_header_size(templat->width0, templat->height0);
99         }
100 
101         if (dev->ro) {
102                 rsc->scanout =
103                         renderonly_create_gpu_import_for_resource(prsc, dev->ro, NULL);
104                 /* failure is expected in some cases.. */
105         }
106 
107         return prsc;
108 }
109 
110 static bool
panfrost_resource_get_handle(struct pipe_screen * pscreen,struct pipe_context * ctx,struct pipe_resource * pt,struct winsys_handle * handle,unsigned usage)111 panfrost_resource_get_handle(struct pipe_screen *pscreen,
112                              struct pipe_context *ctx,
113                              struct pipe_resource *pt,
114                              struct winsys_handle *handle,
115                              unsigned usage)
116 {
117         struct panfrost_device *dev = pan_device(pscreen);
118         struct panfrost_resource *rsrc = (struct panfrost_resource *) pt;
119         struct renderonly_scanout *scanout = rsrc->scanout;
120 
121         handle->modifier = rsrc->modifier;
122         rsrc->modifier_constant = true;
123 
124         if (handle->type == WINSYS_HANDLE_TYPE_SHARED) {
125                 return false;
126         } else if (handle->type == WINSYS_HANDLE_TYPE_KMS) {
127                 if (renderonly_get_handle(scanout, handle))
128                         return true;
129 
130                 handle->handle = rsrc->bo->gem_handle;
131                 handle->stride = rsrc->slices[0].stride;
132                 handle->offset = rsrc->slices[0].offset;
133                 return TRUE;
134         } else if (handle->type == WINSYS_HANDLE_TYPE_FD) {
135                 if (scanout) {
136                         struct drm_prime_handle args = {
137                                 .handle = scanout->handle,
138                                 .flags = DRM_CLOEXEC,
139                         };
140 
141                         int ret = drmIoctl(dev->ro->kms_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
142                         if (ret == -1)
143                                 return false;
144 
145                         handle->stride = scanout->stride;
146                         handle->handle = args.fd;
147 
148                         return true;
149                 } else {
150                         int fd = panfrost_bo_export(rsrc->bo);
151 
152                         if (fd < 0)
153                                 return false;
154 
155                         handle->handle = fd;
156                         handle->stride = rsrc->slices[0].stride;
157                         handle->offset = rsrc->slices[0].offset;
158                         return true;
159                 }
160         }
161 
162         return false;
163 }
164 
165 static void
panfrost_flush_resource(struct pipe_context * pctx,struct pipe_resource * prsc)166 panfrost_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
167 {
168         /* TODO */
169 }
170 
171 static struct pipe_surface *
panfrost_create_surface(struct pipe_context * pipe,struct pipe_resource * pt,const struct pipe_surface * surf_tmpl)172 panfrost_create_surface(struct pipe_context *pipe,
173                         struct pipe_resource *pt,
174                         const struct pipe_surface *surf_tmpl)
175 {
176         struct pipe_surface *ps = NULL;
177 
178         ps = CALLOC_STRUCT(pipe_surface);
179 
180         if (ps) {
181                 pipe_reference_init(&ps->reference, 1);
182                 pipe_resource_reference(&ps->texture, pt);
183                 ps->context = pipe;
184                 ps->format = surf_tmpl->format;
185 
186                 if (pt->target != PIPE_BUFFER) {
187                         assert(surf_tmpl->u.tex.level <= pt->last_level);
188                         ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level);
189                         ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level);
190                         ps->nr_samples = surf_tmpl->nr_samples;
191                         ps->u.tex.level = surf_tmpl->u.tex.level;
192                         ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
193                         ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
194                 } else {
195                         /* setting width as number of elements should get us correct renderbuffer width */
196                         ps->width = surf_tmpl->u.buf.last_element - surf_tmpl->u.buf.first_element + 1;
197                         ps->height = pt->height0;
198                         ps->u.buf.first_element = surf_tmpl->u.buf.first_element;
199                         ps->u.buf.last_element = surf_tmpl->u.buf.last_element;
200                         assert(ps->u.buf.first_element <= ps->u.buf.last_element);
201                         assert(ps->u.buf.last_element < ps->width);
202                 }
203         }
204 
205         return ps;
206 }
207 
208 static void
panfrost_surface_destroy(struct pipe_context * pipe,struct pipe_surface * surf)209 panfrost_surface_destroy(struct pipe_context *pipe,
210                          struct pipe_surface *surf)
211 {
212         assert(surf->texture);
213         pipe_resource_reference(&surf->texture, NULL);
214         free(surf);
215 }
216 
217 static struct pipe_resource *
panfrost_create_scanout_res(struct pipe_screen * screen,const struct pipe_resource * template,uint64_t modifier)218 panfrost_create_scanout_res(struct pipe_screen *screen,
219                             const struct pipe_resource *template,
220                             uint64_t modifier)
221 {
222         struct panfrost_device *dev = pan_device(screen);
223         struct renderonly_scanout *scanout;
224         struct winsys_handle handle;
225         struct pipe_resource *res;
226         struct pipe_resource scanout_templat = *template;
227 
228         /* Tiled formats need to be tile aligned */
229         if (modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
230                 scanout_templat.width0 = ALIGN_POT(template->width0, 16);
231                 scanout_templat.height0 = ALIGN_POT(template->height0, 16);
232         }
233 
234         /* AFBC formats need a header. Thankfully we don't care about the
235          * stride so we can just use wonky dimensions as long as the right
236          * number of bytes are allocated at the end of the day... this implies
237          * that stride/pitch is invalid for AFBC buffers */
238 
239         if (drm_is_afbc(modifier)) {
240                 /* Space for the header. We need to keep vaguely similar
241                  * dimensions because... reasons... to allocate with renderonly
242                  * as a dumb buffer. To do so, after the usual 16x16 alignment,
243                  * we add on extra rows for the header. The order of operations
244                  * matters here, the extra rows of padding can in fact be
245                  * needed and missing them can lead to faults. */
246 
247                 unsigned header_size = panfrost_afbc_header_size(
248                                 template->width0, template->height0);
249 
250                 unsigned pitch = ALIGN_POT(template->width0, 16) *
251                         util_format_get_blocksize(template->format);
252 
253                 unsigned header_rows =
254                         DIV_ROUND_UP(header_size, pitch);
255 
256                 scanout_templat.width0 = ALIGN_POT(template->width0, 16);
257                 scanout_templat.height0 = ALIGN_POT(template->height0, 16) + header_rows;
258         }
259 
260         scanout = renderonly_scanout_for_resource(&scanout_templat,
261                         dev->ro, &handle);
262         if (!scanout)
263                 return NULL;
264 
265         assert(handle.type == WINSYS_HANDLE_TYPE_FD);
266         handle.modifier = modifier;
267         res = screen->resource_from_handle(screen, template, &handle,
268                                            PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
269         close(handle.handle);
270         if (!res)
271                 return NULL;
272 
273         struct panfrost_resource *pres = pan_resource(res);
274 
275         pres->scanout = scanout;
276 
277         return res;
278 }
279 
280 /* Setup the mip tree given a particular modifier, possibly with checksumming */
281 
282 static void
panfrost_setup_slices(struct panfrost_resource * pres,size_t * bo_size)283 panfrost_setup_slices(struct panfrost_resource *pres, size_t *bo_size)
284 {
285         struct pipe_resource *res = &pres->base;
286         unsigned width = res->width0;
287         unsigned height = res->height0;
288         unsigned depth = res->depth0;
289         unsigned bytes_per_pixel = util_format_get_blocksize(pres->internal_format);
290 
291         /* MSAA is implemented as a 3D texture with z corresponding to the
292          * sample #, horrifyingly enough */
293 
294         bool msaa = res->nr_samples > 1;
295 
296         if (msaa) {
297                 assert(depth == 1);
298                 depth = res->nr_samples;
299         }
300 
301         assert(depth > 0);
302 
303         /* Tiled operates blockwise; linear is packed. Also, anything
304          * we render to has to be tile-aligned. Maybe not strictly
305          * necessary, but we're not *that* pressed for memory and it
306          * makes code a lot simpler */
307 
308         bool renderable = res->bind &
309                           (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL) &&
310                           res->target != PIPE_BUFFER;
311         bool afbc = drm_is_afbc(pres->modifier);
312         bool tiled = pres->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
313         bool linear = pres->modifier == DRM_FORMAT_MOD_LINEAR;
314         bool should_align = renderable || tiled || afbc;
315 
316         /* We don't know how to specify a 2D stride for 3D textures */
317 
318         bool can_align_stride =
319                 res->target != PIPE_TEXTURE_3D;
320 
321         should_align &= can_align_stride;
322 
323         unsigned offset = 0;
324         unsigned size_2d = 0;
325 
326         for (unsigned l = 0; l <= res->last_level; ++l) {
327                 struct panfrost_slice *slice = &pres->slices[l];
328 
329                 unsigned effective_width = width;
330                 unsigned effective_height = height;
331                 unsigned effective_depth = depth;
332 
333                 if (should_align) {
334                         effective_width = ALIGN_POT(effective_width, 16);
335                         effective_height = ALIGN_POT(effective_height, 16);
336 
337                         /* We don't need to align depth */
338                 }
339 
340                 /* Align levels to cache-line as a performance improvement for
341                  * linear/tiled and as a requirement for AFBC */
342 
343                 offset = ALIGN_POT(offset, 64);
344 
345                 slice->offset = offset;
346 
347                 /* Compute the would-be stride */
348                 unsigned stride = bytes_per_pixel * effective_width;
349 
350                 if (util_format_is_compressed(pres->internal_format))
351                         stride /= 4;
352 
353                 /* ..but cache-line align it for performance */
354                 if (can_align_stride && linear)
355                         stride = ALIGN_POT(stride, 64);
356 
357                 slice->stride = stride;
358 
359                 unsigned slice_one_size = slice->stride * effective_height;
360                 unsigned slice_full_size = slice_one_size * effective_depth;
361 
362                 slice->size0 = slice_one_size;
363 
364                 /* Report 2D size for 3D texturing */
365 
366                 if (l == 0)
367                         size_2d = slice_one_size;
368 
369                 /* Compute AFBC sizes if necessary */
370                 if (afbc) {
371                         slice->header_size =
372                                 panfrost_afbc_header_size(width, height);
373 
374                         offset += slice->header_size;
375                 }
376 
377                 offset += slice_full_size;
378 
379                 /* Add a checksum region if necessary */
380                 if (pres->checksummed) {
381                         slice->checksum_offset = offset;
382 
383                         unsigned size = panfrost_compute_checksum_size(
384                                                 slice, width, height);
385 
386                         offset += size;
387                 }
388 
389                 width = u_minify(width, 1);
390                 height = u_minify(height, 1);
391 
392                 /* Don't mipmap the sample count */
393                 if (!msaa)
394                         depth = u_minify(depth, 1);
395         }
396 
397         assert(res->array_size);
398 
399         if (res->target != PIPE_TEXTURE_3D) {
400                 /* Arrays and cubemaps have the entire miptree duplicated */
401 
402                 pres->cubemap_stride = ALIGN_POT(offset, 64);
403                 if (bo_size)
404                         *bo_size = ALIGN_POT(pres->cubemap_stride * res->array_size, 4096);
405         } else {
406                 /* 3D strides across the 2D layers */
407                 assert(res->array_size == 1);
408 
409                 pres->cubemap_stride = size_2d;
410                 if (bo_size)
411                         *bo_size = ALIGN_POT(offset, 4096);
412         }
413 }
414 
415 /* Based on the usage, determine if it makes sense to use u-inteleaved tiling.
416  * We only have routines to tile 2D textures of sane bpps. On the hardware
417  * level, not all usages are valid for tiling. Finally, if the app is hinting
418  * that the contents frequently change, tiling will be a loss.
419  *
420  * Due to incomplete information on some platforms, we may need to force tiling
421  * in some cases.
422  *
423  * On platforms where it is supported, AFBC is even better. */
424 
425 static bool
panfrost_can_linear(struct panfrost_device * dev,const struct panfrost_resource * pres)426 panfrost_can_linear(struct panfrost_device *dev, const struct panfrost_resource *pres)
427 {
428         /* XXX: We should be able to do linear Z/S with the right bits.. */
429         return !((pres->base.bind & PIPE_BIND_DEPTH_STENCIL) &&
430                 (dev->quirks & MIDGARD_SFBD));
431 }
432 
433 static bool
panfrost_should_afbc(struct panfrost_device * dev,const struct panfrost_resource * pres)434 panfrost_should_afbc(struct panfrost_device *dev, const struct panfrost_resource *pres)
435 {
436         /* AFBC resources may be rendered to, textured from, or shared across
437          * processes, but may not be used as e.g buffers */
438         const unsigned valid_binding =
439                 PIPE_BIND_DEPTH_STENCIL |
440                 PIPE_BIND_RENDER_TARGET |
441                 PIPE_BIND_BLENDABLE |
442                 PIPE_BIND_SAMPLER_VIEW |
443                 PIPE_BIND_DISPLAY_TARGET |
444                 PIPE_BIND_SCANOUT |
445                 PIPE_BIND_SHARED;
446 
447         if (pres->base.bind & ~valid_binding)
448                 return false;
449 
450         /* AFBC introduced with Mali T760 */
451         if (dev->quirks & MIDGARD_NO_AFBC)
452                 return false;
453 
454         /* AFBC<-->staging is expensive */
455         if (pres->base.usage == PIPE_USAGE_STREAM)
456                 return false;
457 
458         /* Only a small selection of formats are AFBC'able */
459         if (!panfrost_format_supports_afbc(pres->internal_format))
460                 return false;
461 
462         /* AFBC does not support layered (GLES3 style) multisampling. Use
463          * EXT_multisampled_render_to_texture instead */
464         if (pres->base.nr_samples > 1)
465                 return false;
466 
467         /* TODO: Is AFBC of 3D textures possible? */
468         if ((pres->base.target != PIPE_TEXTURE_2D) && (pres->base.target != PIPE_TEXTURE_RECT))
469                 return false;
470 
471         /* For one tile, AFBC is a loss compared to u-interleaved */
472         if (pres->base.width0 <= 16 && pres->base.height0 <= 16)
473                 return false;
474 
475         /* Otherwise, we'd prefer AFBC as it is dramatically more efficient
476          * than linear or usually even u-interleaved */
477         return true;
478 }
479 
480 static bool
panfrost_should_tile(struct panfrost_device * dev,const struct panfrost_resource * pres)481 panfrost_should_tile(struct panfrost_device *dev, const struct panfrost_resource *pres)
482 {
483         const unsigned valid_binding =
484                 PIPE_BIND_DEPTH_STENCIL |
485                 PIPE_BIND_RENDER_TARGET |
486                 PIPE_BIND_BLENDABLE |
487                 PIPE_BIND_SAMPLER_VIEW |
488                 PIPE_BIND_DISPLAY_TARGET |
489                 PIPE_BIND_SCANOUT |
490                 PIPE_BIND_SHARED;
491 
492         unsigned bpp = util_format_get_blocksizebits(pres->internal_format);
493 
494         bool is_sane_bpp =
495                 bpp == 8 || bpp == 16 || bpp == 24 || bpp == 32 ||
496                 bpp == 64 || bpp == 128;
497 
498         bool is_2d = (pres->base.target == PIPE_TEXTURE_2D)
499                 || (pres->base.target == PIPE_TEXTURE_RECT);
500 
501         bool can_tile = is_2d && is_sane_bpp && ((pres->base.bind & ~valid_binding) == 0);
502 
503         if (!panfrost_can_linear(dev, pres)) {
504                 assert(can_tile);
505                 return true;
506         }
507 
508         return can_tile && (pres->base.usage != PIPE_USAGE_STREAM);
509 }
510 
511 static uint64_t
panfrost_best_modifier(struct panfrost_device * dev,const struct panfrost_resource * pres)512 panfrost_best_modifier(struct panfrost_device *dev,
513                 const struct panfrost_resource *pres)
514 {
515         if (panfrost_should_afbc(dev, pres)) {
516                 uint64_t afbc =
517                         AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
518                         AFBC_FORMAT_MOD_SPARSE;
519 
520                 if (panfrost_afbc_can_ytr(pres->base.format))
521                         afbc |= AFBC_FORMAT_MOD_YTR;
522 
523                 return DRM_FORMAT_MOD_ARM_AFBC(afbc);
524         } else if (panfrost_should_tile(dev, pres))
525                 return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
526         else
527                 return DRM_FORMAT_MOD_LINEAR;
528 }
529 
530 static void
panfrost_resource_setup(struct panfrost_device * dev,struct panfrost_resource * pres,size_t * bo_size,uint64_t modifier)531 panfrost_resource_setup(struct panfrost_device *dev, struct panfrost_resource *pres,
532                         size_t *bo_size, uint64_t modifier)
533 {
534         pres->modifier = (modifier != DRM_FORMAT_MOD_INVALID) ? modifier :
535                 panfrost_best_modifier(dev, pres);
536         pres->checksummed = (pres->base.bind & PIPE_BIND_RENDER_TARGET);
537 
538         /* We can only switch tiled->linear if the resource isn't already
539          * linear, and if we control the modifier, and if the resource can be
540          * linear. */
541         pres->modifier_constant = !((pres->modifier != DRM_FORMAT_MOD_LINEAR)
542                         && (modifier == DRM_FORMAT_MOD_INVALID)
543                         && panfrost_can_linear(dev, pres));
544 
545         panfrost_setup_slices(pres, bo_size);
546 }
547 
548 void
panfrost_resource_set_damage_region(struct pipe_screen * screen,struct pipe_resource * res,unsigned int nrects,const struct pipe_box * rects)549 panfrost_resource_set_damage_region(struct pipe_screen *screen,
550                                     struct pipe_resource *res,
551                                     unsigned int nrects,
552                                     const struct pipe_box *rects)
553 {
554         struct panfrost_resource *pres = pan_resource(res);
555         struct pipe_scissor_state *damage_extent = &pres->damage.extent;
556         unsigned int i;
557 
558         if (pres->damage.inverted_rects)
559                 ralloc_free(pres->damage.inverted_rects);
560 
561         memset(&pres->damage, 0, sizeof(pres->damage));
562 
563         pres->damage.inverted_rects =
564                 pan_subtract_damage(pres,
565                         res->width0, res->height0,
566                         nrects, rects, &pres->damage.inverted_len);
567 
568         /* Track the damage extent: the quad including all damage regions. Will
569          * be used restrict the rendering area */
570 
571         damage_extent->minx = 0xffff;
572         damage_extent->miny = 0xffff;
573 
574         for (i = 0; i < nrects; i++) {
575                 int x = rects[i].x, w = rects[i].width, h = rects[i].height;
576                 int y = res->height0 - (rects[i].y + h);
577 
578                 damage_extent->minx = MIN2(damage_extent->minx, x);
579                 damage_extent->miny = MIN2(damage_extent->miny, y);
580                 damage_extent->maxx = MAX2(damage_extent->maxx,
581                                            MIN2(x + w, res->width0));
582                 damage_extent->maxy = MAX2(damage_extent->maxy,
583                                            MIN2(y + h, res->height0));
584         }
585 
586         if (nrects == 0) {
587                 damage_extent->minx = 0;
588                 damage_extent->miny = 0;
589                 damage_extent->maxx = res->width0;
590                 damage_extent->maxy = res->height0;
591         }
592 
593 }
594 
595 static struct pipe_resource *
panfrost_resource_create_with_modifier(struct pipe_screen * screen,const struct pipe_resource * template,uint64_t modifier)596 panfrost_resource_create_with_modifier(struct pipe_screen *screen,
597                          const struct pipe_resource *template,
598                          uint64_t modifier)
599 {
600         struct panfrost_device *dev = pan_device(screen);
601 
602         /* Make sure we're familiar */
603         switch (template->target) {
604         case PIPE_BUFFER:
605         case PIPE_TEXTURE_1D:
606         case PIPE_TEXTURE_2D:
607         case PIPE_TEXTURE_3D:
608         case PIPE_TEXTURE_CUBE:
609         case PIPE_TEXTURE_RECT:
610         case PIPE_TEXTURE_1D_ARRAY:
611         case PIPE_TEXTURE_2D_ARRAY:
612                 break;
613         default:
614                 unreachable("Unknown texture target\n");
615         }
616 
617         if (dev->ro && (template->bind &
618             (PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT | PIPE_BIND_SHARED)))
619                 return panfrost_create_scanout_res(screen, template, modifier);
620 
621         struct panfrost_resource *so = rzalloc(screen, struct panfrost_resource);
622         so->base = *template;
623         so->base.screen = screen;
624         so->internal_format = template->format;
625 
626         pipe_reference_init(&so->base.reference, 1);
627 
628         util_range_init(&so->valid_buffer_range);
629 
630         size_t bo_size;
631         panfrost_resource_setup(dev, so, &bo_size, modifier);
632 
633         /* We create a BO immediately but don't bother mapping, since we don't
634          * care to map e.g. FBOs which the CPU probably won't touch */
635         so->bo = panfrost_bo_create(dev, bo_size, PAN_BO_DELAY_MMAP);
636 
637         panfrost_resource_set_damage_region(NULL, &so->base, 0, NULL);
638 
639         if (template->bind & PIPE_BIND_INDEX_BUFFER)
640                 so->index_cache = rzalloc(so, struct panfrost_minmax_cache);
641 
642         return (struct pipe_resource *)so;
643 }
644 
645 /* Default is to create a resource as don't care */
646 
647 static struct pipe_resource *
panfrost_resource_create(struct pipe_screen * screen,const struct pipe_resource * template)648 panfrost_resource_create(struct pipe_screen *screen,
649                          const struct pipe_resource *template)
650 {
651         return panfrost_resource_create_with_modifier(screen, template,
652                         DRM_FORMAT_MOD_INVALID);
653 }
654 
655 /* If no modifier is specified, we'll choose. Otherwise, the order of
656  * preference is compressed, tiled, linear. */
657 
658 static struct pipe_resource *
panfrost_resource_create_with_modifiers(struct pipe_screen * screen,const struct pipe_resource * template,const uint64_t * modifiers,int count)659 panfrost_resource_create_with_modifiers(struct pipe_screen *screen,
660                          const struct pipe_resource *template,
661                          const uint64_t *modifiers, int count)
662 {
663         for (unsigned i = 0; i < PAN_MODIFIER_COUNT; ++i) {
664                 if (drm_find_modifier(pan_best_modifiers[i], modifiers, count)) {
665                         return panfrost_resource_create_with_modifier(screen, template,
666                                         pan_best_modifiers[i]);
667                 }
668         }
669 
670         /* If we didn't find one, app specified invalid */
671         assert(count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID);
672         return panfrost_resource_create(screen, template);
673 }
674 
675 static void
panfrost_resource_destroy(struct pipe_screen * screen,struct pipe_resource * pt)676 panfrost_resource_destroy(struct pipe_screen *screen,
677                           struct pipe_resource *pt)
678 {
679         struct panfrost_device *dev = pan_device(screen);
680         struct panfrost_resource *rsrc = (struct panfrost_resource *) pt;
681 
682         if (rsrc->scanout)
683                 renderonly_scanout_destroy(rsrc->scanout, dev->ro);
684 
685         if (rsrc->bo)
686                 panfrost_bo_unreference(rsrc->bo);
687 
688         if (rsrc->slices[0].checksum_bo)
689                 panfrost_bo_unreference(rsrc->slices[0].checksum_bo);
690 
691         util_range_destroy(&rsrc->valid_buffer_range);
692         ralloc_free(rsrc);
693 }
694 
695 /* Most of the time we can do CPU-side transfers, but sometimes we need to use
696  * the 3D pipe for this. Let's wrap u_blitter to blit to/from staging textures.
697  * Code adapted from freedreno */
698 
699 static struct panfrost_resource *
pan_alloc_staging(struct panfrost_context * ctx,struct panfrost_resource * rsc,unsigned level,const struct pipe_box * box)700 pan_alloc_staging(struct panfrost_context *ctx, struct panfrost_resource *rsc,
701 		unsigned level, const struct pipe_box *box)
702 {
703         struct pipe_context *pctx = &ctx->base;
704         struct pipe_resource tmpl = rsc->base;
705 
706         tmpl.width0  = box->width;
707         tmpl.height0 = box->height;
708         /* for array textures, box->depth is the array_size, otherwise
709          * for 3d textures, it is the depth:
710          */
711         if (tmpl.array_size > 1) {
712                 if (tmpl.target == PIPE_TEXTURE_CUBE)
713                         tmpl.target = PIPE_TEXTURE_2D_ARRAY;
714                 tmpl.array_size = box->depth;
715                 tmpl.depth0 = 1;
716         } else {
717                 tmpl.array_size = 1;
718                 tmpl.depth0 = box->depth;
719         }
720         tmpl.last_level = 0;
721         tmpl.bind |= PIPE_BIND_LINEAR;
722 
723         struct pipe_resource *pstaging =
724                 pctx->screen->resource_create(pctx->screen, &tmpl);
725         if (!pstaging)
726                 return NULL;
727 
728         return pan_resource(pstaging);
729 }
730 
731 static enum pipe_format
pan_blit_format(enum pipe_format fmt)732 pan_blit_format(enum pipe_format fmt)
733 {
734         const struct util_format_description *desc;
735         desc = util_format_description(fmt);
736 
737         /* This must be an emulated format (using u_transfer_helper) as if it
738          * was real RGTC we wouldn't have used AFBC and needed a blit. */
739         if (desc->layout == UTIL_FORMAT_LAYOUT_RGTC)
740                 fmt = PIPE_FORMAT_R8G8B8A8_UNORM;
741 
742         return fmt;
743 }
744 
745 static void
pan_blit_from_staging(struct pipe_context * pctx,struct panfrost_transfer * trans)746 pan_blit_from_staging(struct pipe_context *pctx, struct panfrost_transfer *trans)
747 {
748         struct pipe_resource *dst = trans->base.resource;
749         struct pipe_blit_info blit = {0};
750 
751         blit.dst.resource = dst;
752         blit.dst.format   = pan_blit_format(dst->format);
753         blit.dst.level    = trans->base.level;
754         blit.dst.box      = trans->base.box;
755         blit.src.resource = trans->staging.rsrc;
756         blit.src.format   = pan_blit_format(trans->staging.rsrc->format);
757         blit.src.level    = 0;
758         blit.src.box      = trans->staging.box;
759         blit.mask = util_format_get_mask(blit.src.format);
760         blit.filter = PIPE_TEX_FILTER_NEAREST;
761 
762         panfrost_blit(pctx, &blit);
763 }
764 
765 static void
pan_blit_to_staging(struct pipe_context * pctx,struct panfrost_transfer * trans)766 pan_blit_to_staging(struct pipe_context *pctx, struct panfrost_transfer *trans)
767 {
768         struct pipe_resource *src = trans->base.resource;
769         struct pipe_blit_info blit = {0};
770 
771         blit.src.resource = src;
772         blit.src.format   = pan_blit_format(src->format);
773         blit.src.level    = trans->base.level;
774         blit.src.box      = trans->base.box;
775         blit.dst.resource = trans->staging.rsrc;
776         blit.dst.format   = pan_blit_format(trans->staging.rsrc->format);
777         blit.dst.level    = 0;
778         blit.dst.box      = trans->staging.box;
779         blit.mask = util_format_get_mask(blit.dst.format);
780         blit.filter = PIPE_TEX_FILTER_NEAREST;
781 
782         panfrost_blit(pctx, &blit);
783 }
784 
785 static void *
panfrost_ptr_map(struct pipe_context * pctx,struct pipe_resource * resource,unsigned level,unsigned usage,const struct pipe_box * box,struct pipe_transfer ** out_transfer)786 panfrost_ptr_map(struct pipe_context *pctx,
787                       struct pipe_resource *resource,
788                       unsigned level,
789                       unsigned usage,  /* a combination of PIPE_MAP_x */
790                       const struct pipe_box *box,
791                       struct pipe_transfer **out_transfer)
792 {
793         struct panfrost_context *ctx = pan_context(pctx);
794         struct panfrost_device *dev = pan_device(pctx->screen);
795         struct panfrost_resource *rsrc = pan_resource(resource);
796         int bytes_per_pixel = util_format_get_blocksize(rsrc->internal_format);
797         struct panfrost_bo *bo = rsrc->bo;
798 
799         /* Can't map tiled/compressed directly */
800         if ((usage & PIPE_MAP_DIRECTLY) && rsrc->modifier != DRM_FORMAT_MOD_LINEAR)
801                 return NULL;
802 
803         struct panfrost_transfer *transfer = rzalloc(pctx, struct panfrost_transfer);
804         transfer->base.level = level;
805         transfer->base.usage = usage;
806         transfer->base.box = *box;
807 
808         pipe_resource_reference(&transfer->base.resource, resource);
809         *out_transfer = &transfer->base;
810 
811         /* We don't have s/w routines for AFBC, so use a staging texture */
812         if (drm_is_afbc(rsrc->modifier)) {
813                 struct panfrost_resource *staging = pan_alloc_staging(ctx, rsrc, level, box);
814                 transfer->base.stride = staging->slices[0].stride;
815                 transfer->base.layer_stride = transfer->base.stride * box->height;
816 
817                 transfer->staging.rsrc = &staging->base;
818 
819                 transfer->staging.box = *box;
820                 transfer->staging.box.x = 0;
821                 transfer->staging.box.y = 0;
822                 transfer->staging.box.z = 0;
823 
824                 assert(transfer->staging.rsrc != NULL);
825 
826                 /* TODO: Eliminate this flush. It's only there to determine if
827                  * we're initialized or not, when the initialization could come
828                  * from a pending batch XXX */
829                 panfrost_flush_batches_accessing_bo(ctx, rsrc->bo, true);
830 
831                 if ((usage & PIPE_MAP_READ) && rsrc->slices[level].initialized) {
832                         pan_blit_to_staging(pctx, transfer);
833                         panfrost_flush_batches_accessing_bo(ctx, staging->bo, true);
834                         panfrost_bo_wait(staging->bo, INT64_MAX, false);
835                 }
836 
837                 panfrost_bo_mmap(staging->bo);
838                 return staging->bo->ptr.cpu;
839         }
840 
841         /* If we haven't already mmaped, now's the time */
842         panfrost_bo_mmap(bo);
843 
844         if (dev->debug & (PAN_DBG_TRACE | PAN_DBG_SYNC))
845                 pandecode_inject_mmap(bo->ptr.gpu, bo->ptr.cpu, bo->size, NULL);
846 
847         bool create_new_bo = usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE;
848         bool copy_resource = false;
849 
850         if (!create_new_bo &&
851             !(usage & PIPE_MAP_UNSYNCHRONIZED) &&
852             (usage & PIPE_MAP_WRITE) &&
853             !(resource->target == PIPE_BUFFER
854               && !util_ranges_intersect(&rsrc->valid_buffer_range, box->x, box->x + box->width)) &&
855             panfrost_pending_batches_access_bo(ctx, bo)) {
856 
857                 /* When a resource to be modified is already being used by a
858                  * pending batch, it is often faster to copy the whole BO than
859                  * to flush and split the frame in two.
860                  */
861 
862                 panfrost_flush_batches_accessing_bo(ctx, bo, false);
863                 panfrost_bo_wait(bo, INT64_MAX, false);
864 
865                 create_new_bo = true;
866                 copy_resource = true;
867         }
868 
869         if (create_new_bo) {
870                 /* If the BO is used by one of the pending batches or if it's
871                  * not ready yet (still accessed by one of the already flushed
872                  * batches), we try to allocate a new one to avoid waiting.
873                  */
874                 if (panfrost_pending_batches_access_bo(ctx, bo) ||
875                     !panfrost_bo_wait(bo, 0, true)) {
876                         /* We want the BO to be MMAPed. */
877                         uint32_t flags = bo->flags & ~PAN_BO_DELAY_MMAP;
878                         struct panfrost_bo *newbo = NULL;
879 
880                         /* When the BO has been imported/exported, we can't
881                          * replace it by another one, otherwise the
882                          * importer/exporter wouldn't see the change we're
883                          * doing to it.
884                          */
885                         if (!(bo->flags & PAN_BO_SHARED))
886                                 newbo = panfrost_bo_create(dev, bo->size,
887                                                            flags);
888 
889                         if (newbo) {
890                                 if (copy_resource)
891                                         memcpy(newbo->ptr.cpu, rsrc->bo->ptr.cpu, bo->size);
892 
893                                 panfrost_bo_unreference(bo);
894                                 rsrc->bo = newbo;
895                                 bo = newbo;
896                         } else {
897                                 /* Allocation failed or was impossible, let's
898                                  * fall back on a flush+wait.
899                                  */
900                                 panfrost_flush_batches_accessing_bo(ctx, bo, true);
901                                 panfrost_bo_wait(bo, INT64_MAX, true);
902                         }
903                 }
904         } else if ((usage & PIPE_MAP_WRITE)
905                    && resource->target == PIPE_BUFFER
906                    && !util_ranges_intersect(&rsrc->valid_buffer_range, box->x, box->x + box->width)) {
907                 /* No flush for writes to uninitialized */
908         } else if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) {
909                 if (usage & PIPE_MAP_WRITE) {
910                         panfrost_flush_batches_accessing_bo(ctx, bo, true);
911                         panfrost_bo_wait(bo, INT64_MAX, true);
912                 } else if (usage & PIPE_MAP_READ) {
913                         panfrost_flush_batches_accessing_bo(ctx, bo, false);
914                         panfrost_bo_wait(bo, INT64_MAX, false);
915                 }
916         }
917 
918         if (rsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
919                 transfer->base.stride = box->width * bytes_per_pixel;
920                 transfer->base.layer_stride = transfer->base.stride * box->height;
921                 transfer->map = ralloc_size(transfer, transfer->base.layer_stride * box->depth);
922                 assert(box->depth == 1);
923 
924                 if ((usage & PIPE_MAP_READ) && rsrc->slices[level].initialized) {
925                         panfrost_load_tiled_image(
926                                         transfer->map,
927                                         bo->ptr.cpu + rsrc->slices[level].offset,
928                                         box->x, box->y, box->width, box->height,
929                                         transfer->base.stride,
930                                         rsrc->slices[level].stride,
931                                         rsrc->internal_format);
932                 }
933 
934                 return transfer->map;
935         } else {
936                 assert (rsrc->modifier == DRM_FORMAT_MOD_LINEAR);
937 
938                 /* Direct, persistent writes create holes in time for
939                  * caching... I don't know if this is actually possible but we
940                  * should still get it right */
941 
942                 unsigned dpw = PIPE_MAP_DIRECTLY | PIPE_MAP_WRITE | PIPE_MAP_PERSISTENT;
943 
944                 if ((usage & dpw) == dpw && rsrc->index_cache)
945                         return NULL;
946 
947                 transfer->base.stride = rsrc->slices[level].stride;
948                 transfer->base.layer_stride = panfrost_get_layer_stride(
949                                 rsrc->slices, rsrc->base.target == PIPE_TEXTURE_3D,
950                                 rsrc->cubemap_stride, level);
951 
952                 /* By mapping direct-write, we're implicitly already
953                  * initialized (maybe), so be conservative */
954 
955                 if (usage & PIPE_MAP_WRITE) {
956                         rsrc->slices[level].initialized = true;
957                         panfrost_minmax_cache_invalidate(rsrc->index_cache, &transfer->base);
958                 }
959 
960                 return bo->ptr.cpu
961                        + rsrc->slices[level].offset
962                        + transfer->base.box.z * transfer->base.layer_stride
963                        + transfer->base.box.y * rsrc->slices[level].stride
964                        + transfer->base.box.x * bytes_per_pixel;
965         }
966 }
967 
968 static bool
panfrost_should_linear_convert(struct panfrost_resource * prsrc,struct pipe_transfer * transfer)969 panfrost_should_linear_convert(struct panfrost_resource *prsrc,
970                                struct pipe_transfer *transfer)
971 {
972         if (prsrc->modifier_constant)
973                 return false;
974 
975         /* Overwriting the entire resource indicates streaming, for which
976          * linear layout is most efficient due to the lack of expensive
977          * conversion.
978          *
979          * For now we just switch to linear after a number of complete
980          * overwrites to keep things simple, but we could do better.
981          */
982 
983         bool entire_overwrite = prsrc->base.last_level == 0
984                 && transfer->box.width == prsrc->base.width0
985                 && transfer->box.height == prsrc->base.height0
986                 && transfer->box.x == 0
987                 && transfer->box.y == 0;
988 
989         if (entire_overwrite)
990                 ++prsrc->modifier_updates;
991 
992         return prsrc->modifier_updates >= LAYOUT_CONVERT_THRESHOLD;
993 }
994 
995 static void
panfrost_ptr_unmap(struct pipe_context * pctx,struct pipe_transfer * transfer)996 panfrost_ptr_unmap(struct pipe_context *pctx,
997                         struct pipe_transfer *transfer)
998 {
999         /* Gallium expects writeback here, so we tile */
1000 
1001         struct panfrost_transfer *trans = pan_transfer(transfer);
1002         struct panfrost_resource *prsrc = (struct panfrost_resource *) transfer->resource;
1003         struct panfrost_device *dev = pan_device(pctx->screen);
1004 
1005         /* AFBC will use a staging resource. `initialized` will be set when the
1006          * fragment job is created; this is deferred to prevent useless surface
1007          * reloads that can cascade into DATA_INVALID_FAULTs due to reading
1008          * malformed AFBC data if uninitialized */
1009 
1010         if (trans->staging.rsrc) {
1011                 if (transfer->usage & PIPE_MAP_WRITE) {
1012                         if (panfrost_should_linear_convert(prsrc, transfer)) {
1013 
1014                                 panfrost_bo_unreference(prsrc->bo);
1015                                 if (prsrc->slices[0].checksum_bo)
1016                                         panfrost_bo_unreference(prsrc->slices[0].checksum_bo);
1017 
1018                                 panfrost_resource_setup(dev, prsrc, NULL, DRM_FORMAT_MOD_LINEAR);
1019 
1020                                 prsrc->bo = pan_resource(trans->staging.rsrc)->bo;
1021                                 panfrost_bo_reference(prsrc->bo);
1022                         } else {
1023                                 pan_blit_from_staging(pctx, trans);
1024                                 panfrost_flush_batches_accessing_bo(pan_context(pctx), pan_resource(trans->staging.rsrc)->bo, true);
1025                         }
1026                 }
1027 
1028                 pipe_resource_reference(&trans->staging.rsrc, NULL);
1029         }
1030 
1031         /* Tiling will occur in software from a staging cpu buffer */
1032         if (trans->map) {
1033                 struct panfrost_bo *bo = prsrc->bo;
1034 
1035                 if (transfer->usage & PIPE_MAP_WRITE) {
1036                         prsrc->slices[transfer->level].initialized = true;
1037 
1038                         if (prsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
1039                                 assert(transfer->box.depth == 1);
1040 
1041                                 if (panfrost_should_linear_convert(prsrc, transfer)) {
1042                                         prsrc->modifier = DRM_FORMAT_MOD_LINEAR;
1043 
1044                                         util_copy_rect(
1045                                                 bo->ptr.cpu + prsrc->slices[0].offset,
1046                                                 prsrc->base.format,
1047                                                 prsrc->slices[0].stride,
1048                                                 0, 0,
1049                                                 transfer->box.width,
1050                                                 transfer->box.height,
1051                                                 trans->map,
1052                                                 transfer->stride,
1053                                                 0, 0);
1054                                 } else {
1055                                         panfrost_store_tiled_image(
1056                                                 bo->ptr.cpu + prsrc->slices[transfer->level].offset,
1057                                                 trans->map,
1058                                                 transfer->box.x, transfer->box.y,
1059                                                 transfer->box.width, transfer->box.height,
1060                                                 prsrc->slices[transfer->level].stride,
1061                                                 transfer->stride,
1062                                                 prsrc->internal_format);
1063                                 }
1064                         }
1065                 }
1066         }
1067 
1068 
1069         util_range_add(&prsrc->base, &prsrc->valid_buffer_range,
1070                        transfer->box.x,
1071                        transfer->box.x + transfer->box.width);
1072 
1073         panfrost_minmax_cache_invalidate(prsrc->index_cache, transfer);
1074 
1075         /* Derefence the resource */
1076         pipe_resource_reference(&transfer->resource, NULL);
1077 
1078         /* Transfer itself is RALLOCed at the moment */
1079         ralloc_free(transfer);
1080 }
1081 
1082 static void
panfrost_ptr_flush_region(struct pipe_context * pctx,struct pipe_transfer * transfer,const struct pipe_box * box)1083 panfrost_ptr_flush_region(struct pipe_context *pctx,
1084                                struct pipe_transfer *transfer,
1085                                const struct pipe_box *box)
1086 {
1087         struct panfrost_resource *rsc = pan_resource(transfer->resource);
1088 
1089         if (transfer->resource->target == PIPE_BUFFER) {
1090                 util_range_add(&rsc->base, &rsc->valid_buffer_range,
1091                                transfer->box.x + box->x,
1092                                transfer->box.x + box->x + box->width);
1093         } else {
1094                 unsigned level = transfer->level;
1095                 rsc->slices[level].initialized = true;
1096         }
1097 }
1098 
1099 static void
panfrost_invalidate_resource(struct pipe_context * pctx,struct pipe_resource * prsc)1100 panfrost_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
1101 {
1102         /* TODO */
1103 }
1104 
1105 static enum pipe_format
panfrost_resource_get_internal_format(struct pipe_resource * rsrc)1106 panfrost_resource_get_internal_format(struct pipe_resource *rsrc)
1107 {
1108         struct panfrost_resource *prsrc = (struct panfrost_resource *) rsrc;
1109         return prsrc->internal_format;
1110 }
1111 
1112 static bool
panfrost_generate_mipmap(struct pipe_context * pctx,struct pipe_resource * prsrc,enum pipe_format format,unsigned base_level,unsigned last_level,unsigned first_layer,unsigned last_layer)1113 panfrost_generate_mipmap(
1114         struct pipe_context *pctx,
1115         struct pipe_resource *prsrc,
1116         enum pipe_format format,
1117         unsigned base_level,
1118         unsigned last_level,
1119         unsigned first_layer,
1120         unsigned last_layer)
1121 {
1122         struct panfrost_resource *rsrc = pan_resource(prsrc);
1123 
1124         /* Generating a mipmap invalidates the written levels, so make that
1125          * explicit so we don't try to wallpaper them back and end up with
1126          * u_blitter recursion */
1127 
1128         assert(rsrc->bo);
1129         for (unsigned l = base_level + 1; l <= last_level; ++l)
1130                 rsrc->slices[l].initialized = false;
1131 
1132         /* Beyond that, we just delegate the hard stuff. */
1133 
1134         bool blit_res = util_gen_mipmap(
1135                                 pctx, prsrc, format,
1136                                 base_level, last_level,
1137                                 first_layer, last_layer,
1138                                 PIPE_TEX_FILTER_LINEAR);
1139 
1140         return blit_res;
1141 }
1142 
1143 /* Computes the address to a texture at a particular slice */
1144 
1145 mali_ptr
panfrost_get_texture_address(struct panfrost_resource * rsrc,unsigned level,unsigned face,unsigned sample)1146 panfrost_get_texture_address(
1147         struct panfrost_resource *rsrc,
1148         unsigned level, unsigned face, unsigned sample)
1149 {
1150         bool is_3d = rsrc->base.target == PIPE_TEXTURE_3D;
1151         return rsrc->bo->ptr.gpu +
1152                panfrost_texture_offset(rsrc->slices, is_3d,
1153                                        rsrc->cubemap_stride,
1154                                        level, face, sample);
1155 }
1156 
1157 static void
panfrost_resource_set_stencil(struct pipe_resource * prsrc,struct pipe_resource * stencil)1158 panfrost_resource_set_stencil(struct pipe_resource *prsrc,
1159                               struct pipe_resource *stencil)
1160 {
1161         pan_resource(prsrc)->separate_stencil = pan_resource(stencil);
1162 }
1163 
1164 static struct pipe_resource *
panfrost_resource_get_stencil(struct pipe_resource * prsrc)1165 panfrost_resource_get_stencil(struct pipe_resource *prsrc)
1166 {
1167         return &pan_resource(prsrc)->separate_stencil->base;
1168 }
1169 
1170 static const struct u_transfer_vtbl transfer_vtbl = {
1171         .resource_create          = panfrost_resource_create,
1172         .resource_destroy         = panfrost_resource_destroy,
1173         .transfer_map             = panfrost_ptr_map,
1174         .transfer_unmap           = panfrost_ptr_unmap,
1175         .transfer_flush_region    = panfrost_ptr_flush_region,
1176         .get_internal_format      = panfrost_resource_get_internal_format,
1177         .set_stencil              = panfrost_resource_set_stencil,
1178         .get_stencil              = panfrost_resource_get_stencil,
1179 };
1180 
1181 void
panfrost_resource_screen_init(struct pipe_screen * pscreen)1182 panfrost_resource_screen_init(struct pipe_screen *pscreen)
1183 {
1184         struct panfrost_device *dev = pan_device(pscreen);
1185 
1186         bool fake_rgtc = !panfrost_supports_compressed_format(dev, MALI_BC4_UNORM);
1187 
1188         pscreen->resource_create_with_modifiers =
1189                 panfrost_resource_create_with_modifiers;
1190         pscreen->resource_create = u_transfer_helper_resource_create;
1191         pscreen->resource_destroy = u_transfer_helper_resource_destroy;
1192         pscreen->resource_from_handle = panfrost_resource_from_handle;
1193         pscreen->resource_get_handle = panfrost_resource_get_handle;
1194         pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl,
1195                                         true, false,
1196                                         fake_rgtc, true);
1197 }
1198 
1199 void
panfrost_resource_context_init(struct pipe_context * pctx)1200 panfrost_resource_context_init(struct pipe_context *pctx)
1201 {
1202         pctx->transfer_map = u_transfer_helper_transfer_map;
1203         pctx->transfer_unmap = u_transfer_helper_transfer_unmap;
1204         pctx->create_surface = panfrost_create_surface;
1205         pctx->surface_destroy = panfrost_surface_destroy;
1206         pctx->resource_copy_region = util_resource_copy_region;
1207         pctx->blit = panfrost_blit;
1208         pctx->generate_mipmap = panfrost_generate_mipmap;
1209         pctx->flush_resource = panfrost_flush_resource;
1210         pctx->invalidate_resource = panfrost_invalidate_resource;
1211         pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;
1212         pctx->buffer_subdata = u_default_buffer_subdata;
1213         pctx->texture_subdata = u_default_texture_subdata;
1214 }
1215