1b8e80941Smrg/**************************************************************************
2b8e80941Smrg *
3b8e80941Smrg * Copyright 2008 VMware, Inc.
4b8e80941Smrg * Copyright 2014 Broadcom
5b8e80941Smrg * Copyright 2018 Alyssa Rosenzweig
6b8e80941Smrg * All Rights Reserved.
7b8e80941Smrg *
8b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
9b8e80941Smrg * copy of this software and associated documentation files (the
10b8e80941Smrg * "Software"), to deal in the Software without restriction, including
11b8e80941Smrg * without limitation the rights to use, copy, modify, merge, publish,
12b8e80941Smrg * distribute, sub license, and/or sell copies of the Software, and to
13b8e80941Smrg * permit persons to whom the Software is furnished to do so, subject to
14b8e80941Smrg * the following conditions:
15b8e80941Smrg *
16b8e80941Smrg * The above copyright notice and this permission notice (including the
17b8e80941Smrg * next paragraph) shall be included in all copies or substantial portions
18b8e80941Smrg * of the Software.
19b8e80941Smrg *
20b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21b8e80941Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22b8e80941Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
23b8e80941Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
24b8e80941Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25b8e80941Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26b8e80941Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27b8e80941Smrg *
28b8e80941Smrg **************************************************************************/
29b8e80941Smrg
30b8e80941Smrg#include <xf86drm.h>
31b8e80941Smrg#include <fcntl.h>
32b8e80941Smrg#include "drm-uapi/drm_fourcc.h"
33b8e80941Smrg
34b8e80941Smrg#include "state_tracker/winsys_handle.h"
35b8e80941Smrg#include "util/u_format.h"
36b8e80941Smrg#include "util/u_memory.h"
37b8e80941Smrg#include "util/u_surface.h"
38b8e80941Smrg#include "util/u_transfer.h"
39b8e80941Smrg#include "util/u_transfer_helper.h"
40b8e80941Smrg
41b8e80941Smrg#include "pan_context.h"
42b8e80941Smrg#include "pan_screen.h"
43b8e80941Smrg#include "pan_resource.h"
44b8e80941Smrg#include "pan_swizzle.h"
45b8e80941Smrg#include "pan_util.h"
46b8e80941Smrg
47b8e80941Smrgstatic struct pipe_resource *
48b8e80941Smrgpanfrost_resource_from_handle(struct pipe_screen *pscreen,
49b8e80941Smrg                              const struct pipe_resource *templat,
50b8e80941Smrg                              struct winsys_handle *whandle,
51b8e80941Smrg                              unsigned usage)
52b8e80941Smrg{
53b8e80941Smrg        struct panfrost_screen *screen = pan_screen(pscreen);
54b8e80941Smrg        struct panfrost_resource *rsc;
55b8e80941Smrg        struct pipe_resource *prsc;
56b8e80941Smrg
57b8e80941Smrg        assert(whandle->type == WINSYS_HANDLE_TYPE_FD);
58b8e80941Smrg
59b8e80941Smrg        rsc = CALLOC_STRUCT(panfrost_resource);
60b8e80941Smrg        if (!rsc)
61b8e80941Smrg                return NULL;
62b8e80941Smrg
63b8e80941Smrg        prsc = &rsc->base;
64b8e80941Smrg
65b8e80941Smrg        *prsc = *templat;
66b8e80941Smrg
67b8e80941Smrg        pipe_reference_init(&prsc->reference, 1);
68b8e80941Smrg        prsc->screen = pscreen;
69b8e80941Smrg
70b8e80941Smrg	rsc->bo = screen->driver->import_bo(screen, whandle);
71b8e80941Smrg	rsc->bo->slices[0].stride = whandle->stride;
72b8e80941Smrg
73b8e80941Smrg	if (screen->ro) {
74b8e80941Smrg		rsc->scanout =
75b8e80941Smrg			renderonly_create_gpu_import_for_resource(prsc, screen->ro, NULL);
76b8e80941Smrg		/* failure is expected in some cases.. */
77b8e80941Smrg	}
78b8e80941Smrg
79b8e80941Smrg        return prsc;
80b8e80941Smrg}
81b8e80941Smrg
82b8e80941Smrgstatic boolean
83b8e80941Smrgpanfrost_resource_get_handle(struct pipe_screen *pscreen,
84b8e80941Smrg                             struct pipe_context *ctx,
85b8e80941Smrg                             struct pipe_resource *pt,
86b8e80941Smrg                             struct winsys_handle *handle,
87b8e80941Smrg                             unsigned usage)
88b8e80941Smrg{
89b8e80941Smrg        struct panfrost_screen *screen = pan_screen(pscreen);
90b8e80941Smrg        struct panfrost_resource *rsrc = (struct panfrost_resource *) pt;
91b8e80941Smrg        struct renderonly_scanout *scanout = rsrc->scanout;
92b8e80941Smrg
93b8e80941Smrg        handle->modifier = DRM_FORMAT_MOD_INVALID;
94b8e80941Smrg
95b8e80941Smrg	if (handle->type == WINSYS_HANDLE_TYPE_SHARED) {
96b8e80941Smrg		return FALSE;
97b8e80941Smrg	} else if (handle->type == WINSYS_HANDLE_TYPE_KMS) {
98b8e80941Smrg		if (renderonly_get_handle(scanout, handle))
99b8e80941Smrg			return TRUE;
100b8e80941Smrg
101b8e80941Smrg		handle->handle = rsrc->bo->gem_handle;
102b8e80941Smrg		handle->stride = rsrc->bo->slices[0].stride;
103b8e80941Smrg		return TRUE;
104b8e80941Smrg	} else if (handle->type == WINSYS_HANDLE_TYPE_FD) {
105b8e80941Smrg                if (scanout) {
106b8e80941Smrg                        struct drm_prime_handle args = {
107b8e80941Smrg                                .handle = scanout->handle,
108b8e80941Smrg                                .flags = DRM_CLOEXEC,
109b8e80941Smrg                        };
110b8e80941Smrg
111b8e80941Smrg                        int ret = drmIoctl(screen->ro->kms_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
112b8e80941Smrg                        if (ret == -1)
113b8e80941Smrg                                return FALSE;
114b8e80941Smrg
115b8e80941Smrg                        handle->stride = scanout->stride;
116b8e80941Smrg                        handle->handle = args.fd;
117b8e80941Smrg
118b8e80941Smrg                        return TRUE;
119b8e80941Smrg                } else
120b8e80941Smrg			return screen->driver->export_bo(screen, rsrc->bo->gem_handle, rsrc->bo->slices[0].stride, handle);
121b8e80941Smrg	}
122b8e80941Smrg
123b8e80941Smrg	return FALSE;
124b8e80941Smrg}
125b8e80941Smrg
126b8e80941Smrgstatic void
127b8e80941Smrgpanfrost_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
128b8e80941Smrg{
129b8e80941Smrg        //DBG("TODO %s\n", __func__);
130b8e80941Smrg}
131b8e80941Smrg
132b8e80941Smrgstatic void
133b8e80941Smrgpanfrost_blit(struct pipe_context *pipe,
134b8e80941Smrg              const struct pipe_blit_info *info)
135b8e80941Smrg{
136b8e80941Smrg        if (util_try_blit_via_copy_region(pipe, info))
137b8e80941Smrg                return;
138b8e80941Smrg
139b8e80941Smrg        /* TODO */
140b8e80941Smrg        DBG("Unhandled blit.\n");
141b8e80941Smrg
142b8e80941Smrg        return;
143b8e80941Smrg}
144b8e80941Smrg
145b8e80941Smrgstatic struct pipe_surface *
146b8e80941Smrgpanfrost_create_surface(struct pipe_context *pipe,
147b8e80941Smrg                        struct pipe_resource *pt,
148b8e80941Smrg                        const struct pipe_surface *surf_tmpl)
149b8e80941Smrg{
150b8e80941Smrg        struct pipe_surface *ps = NULL;
151b8e80941Smrg
152b8e80941Smrg        ps = CALLOC_STRUCT(pipe_surface);
153b8e80941Smrg
154b8e80941Smrg        if (ps) {
155b8e80941Smrg                pipe_reference_init(&ps->reference, 1);
156b8e80941Smrg                pipe_resource_reference(&ps->texture, pt);
157b8e80941Smrg                ps->context = pipe;
158b8e80941Smrg                ps->format = surf_tmpl->format;
159b8e80941Smrg
160b8e80941Smrg                if (pt->target != PIPE_BUFFER) {
161b8e80941Smrg                        assert(surf_tmpl->u.tex.level <= pt->last_level);
162b8e80941Smrg                        ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level);
163b8e80941Smrg                        ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level);
164b8e80941Smrg                        ps->u.tex.level = surf_tmpl->u.tex.level;
165b8e80941Smrg                        ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
166b8e80941Smrg                        ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
167b8e80941Smrg                } else {
168b8e80941Smrg                        /* setting width as number of elements should get us correct renderbuffer width */
169b8e80941Smrg                        ps->width = surf_tmpl->u.buf.last_element - surf_tmpl->u.buf.first_element + 1;
170b8e80941Smrg                        ps->height = pt->height0;
171b8e80941Smrg                        ps->u.buf.first_element = surf_tmpl->u.buf.first_element;
172b8e80941Smrg                        ps->u.buf.last_element = surf_tmpl->u.buf.last_element;
173b8e80941Smrg                        assert(ps->u.buf.first_element <= ps->u.buf.last_element);
174b8e80941Smrg                        assert(ps->u.buf.last_element < ps->width);
175b8e80941Smrg                }
176b8e80941Smrg        }
177b8e80941Smrg
178b8e80941Smrg        return ps;
179b8e80941Smrg}
180b8e80941Smrg
181b8e80941Smrgstatic void
182b8e80941Smrgpanfrost_surface_destroy(struct pipe_context *pipe,
183b8e80941Smrg                         struct pipe_surface *surf)
184b8e80941Smrg{
185b8e80941Smrg        assert(surf->texture);
186b8e80941Smrg        pipe_resource_reference(&surf->texture, NULL);
187b8e80941Smrg        free(surf);
188b8e80941Smrg}
189b8e80941Smrg
190b8e80941Smrgstatic void
191b8e80941Smrgpanfrost_setup_slices(const struct pipe_resource *tmpl, struct panfrost_bo *bo)
192b8e80941Smrg{
193b8e80941Smrg        unsigned width = tmpl->width0;
194b8e80941Smrg        unsigned height = tmpl->height0;
195b8e80941Smrg        unsigned bytes_per_pixel = util_format_get_blocksize(tmpl->format);
196b8e80941Smrg
197b8e80941Smrg        unsigned offset = 0;
198b8e80941Smrg
199b8e80941Smrg        for (unsigned l = 0; l <= tmpl->last_level; ++l) {
200b8e80941Smrg                struct panfrost_slice *slice = &bo->slices[l];
201b8e80941Smrg
202b8e80941Smrg                unsigned effective_width = width;
203b8e80941Smrg                unsigned effective_height = height;
204b8e80941Smrg
205b8e80941Smrg                /* Tiled operates blockwise; linear is packed */
206b8e80941Smrg
207b8e80941Smrg                if (bo->layout == PAN_TILED) {
208b8e80941Smrg                        effective_width = ALIGN(effective_width, 16);
209b8e80941Smrg                        effective_height = ALIGN(effective_height, 16);
210b8e80941Smrg                }
211b8e80941Smrg
212b8e80941Smrg                slice->offset = offset;
213b8e80941Smrg                slice->stride = bytes_per_pixel * effective_width;
214b8e80941Smrg
215b8e80941Smrg                offset += slice->stride * effective_height;
216b8e80941Smrg
217b8e80941Smrg                width = u_minify(width, 1);
218b8e80941Smrg                height = u_minify(height, 1);
219b8e80941Smrg        }
220b8e80941Smrg
221b8e80941Smrg        assert(tmpl->array_size);
222b8e80941Smrg
223b8e80941Smrg        bo->cubemap_stride = ALIGN(offset, 64);
224b8e80941Smrg        bo->size = ALIGN(bo->cubemap_stride * tmpl->array_size, 4096);
225b8e80941Smrg}
226b8e80941Smrg
227b8e80941Smrgstatic struct panfrost_bo *
228b8e80941Smrgpanfrost_create_bo(struct panfrost_screen *screen, const struct pipe_resource *template)
229b8e80941Smrg{
230b8e80941Smrg	struct panfrost_bo *bo = CALLOC_STRUCT(panfrost_bo);
231b8e80941Smrg        pipe_reference_init(&bo->reference, 1);
232b8e80941Smrg
233b8e80941Smrg        /* Based on the usage, figure out what storing will be used. There are
234b8e80941Smrg         * various tradeoffs:
235b8e80941Smrg         *
236b8e80941Smrg         * Linear: the basic format, bad for memory bandwidth, bad for cache
237b8e80941Smrg         * use. Zero-copy, though. Renderable.
238b8e80941Smrg         *
239b8e80941Smrg         * Tiled: Not compressed, but cache-optimized. Expensive to write into
240b8e80941Smrg         * (due to software tiling), but cheap to sample from. Ideal for most
241b8e80941Smrg         * textures.
242b8e80941Smrg         *
243b8e80941Smrg         * AFBC: Compressed and renderable (so always desirable for non-scanout
244b8e80941Smrg         * rendertargets). Cheap to sample from. The format is black box, so we
245b8e80941Smrg         * can't read/write from software.
246b8e80941Smrg         */
247b8e80941Smrg
248b8e80941Smrg        /* Tiling textures is almost always faster, unless we only use it once */
249b8e80941Smrg        bool should_tile = (template->usage != PIPE_USAGE_STREAM) && (template->bind & PIPE_BIND_SAMPLER_VIEW);
250b8e80941Smrg
251b8e80941Smrg        /* For unclear reasons, depth/stencil is faster linear than AFBC, so
252b8e80941Smrg         * make sure it's linear */
253b8e80941Smrg
254b8e80941Smrg        if (template->bind & PIPE_BIND_DEPTH_STENCIL)
255b8e80941Smrg                should_tile = false;
256b8e80941Smrg
257b8e80941Smrg        /* Set the layout appropriately */
258b8e80941Smrg        bo->layout = should_tile ? PAN_TILED : PAN_LINEAR;
259b8e80941Smrg
260b8e80941Smrg        panfrost_setup_slices(template, bo);
261b8e80941Smrg
262b8e80941Smrg        if (bo->layout == PAN_TILED || bo->layout == PAN_LINEAR) {
263b8e80941Smrg                struct panfrost_memory mem;
264b8e80941Smrg
265b8e80941Smrg                screen->driver->allocate_slab(screen, &mem, bo->size / 4096, true, 0, 0, 0);
266b8e80941Smrg
267b8e80941Smrg                bo->cpu = mem.cpu;
268b8e80941Smrg                bo->gpu = mem.gpu;
269b8e80941Smrg                bo->gem_handle = mem.gem_handle;
270b8e80941Smrg        }
271b8e80941Smrg
272b8e80941Smrg        return bo;
273b8e80941Smrg}
274b8e80941Smrg
275b8e80941Smrgstatic struct pipe_resource *
276b8e80941Smrgpanfrost_resource_create(struct pipe_screen *screen,
277b8e80941Smrg                         const struct pipe_resource *template)
278b8e80941Smrg{
279b8e80941Smrg        struct panfrost_resource *so = CALLOC_STRUCT(panfrost_resource);
280b8e80941Smrg        struct panfrost_screen *pscreen = (struct panfrost_screen *) screen;
281b8e80941Smrg
282b8e80941Smrg        so->base = *template;
283b8e80941Smrg        so->base.screen = screen;
284b8e80941Smrg
285b8e80941Smrg        pipe_reference_init(&so->base.reference, 1);
286b8e80941Smrg
287b8e80941Smrg        /* Make sure we're familiar */
288b8e80941Smrg        switch (template->target) {
289b8e80941Smrg                case PIPE_BUFFER:
290b8e80941Smrg                case PIPE_TEXTURE_1D:
291b8e80941Smrg                case PIPE_TEXTURE_2D:
292b8e80941Smrg                case PIPE_TEXTURE_3D:
293b8e80941Smrg                case PIPE_TEXTURE_CUBE:
294b8e80941Smrg                case PIPE_TEXTURE_RECT:
295b8e80941Smrg                        break;
296b8e80941Smrg                default:
297b8e80941Smrg                        DBG("Unknown texture target %d\n", template->target);
298b8e80941Smrg                        assert(0);
299b8e80941Smrg        }
300b8e80941Smrg
301b8e80941Smrg        util_range_init(&so->valid_buffer_range);
302b8e80941Smrg
303b8e80941Smrg        if (template->bind & PIPE_BIND_DISPLAY_TARGET ||
304b8e80941Smrg            template->bind & PIPE_BIND_SCANOUT ||
305b8e80941Smrg            template->bind & PIPE_BIND_SHARED) {
306b8e80941Smrg                struct pipe_resource scanout_templat = *template;
307b8e80941Smrg                struct renderonly_scanout *scanout;
308b8e80941Smrg                struct winsys_handle handle;
309b8e80941Smrg
310b8e80941Smrg                scanout = renderonly_scanout_for_resource(&scanout_templat,
311b8e80941Smrg                                                          pscreen->ro, &handle);
312b8e80941Smrg                if (!scanout)
313b8e80941Smrg                        return NULL;
314b8e80941Smrg
315b8e80941Smrg                assert(handle.type == WINSYS_HANDLE_TYPE_FD);
316b8e80941Smrg                /* TODO: handle modifiers? */
317b8e80941Smrg                so = pan_resource(screen->resource_from_handle(screen, template,
318b8e80941Smrg                                                                 &handle,
319b8e80941Smrg                                                                 PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE));
320b8e80941Smrg                close(handle.handle);
321b8e80941Smrg                if (!so)
322b8e80941Smrg                        return NULL;
323b8e80941Smrg
324b8e80941Smrg                so->scanout = scanout;
325b8e80941Smrg                pscreen->display_target = so;
326b8e80941Smrg        } else {
327b8e80941Smrg                so->bo = panfrost_create_bo(pscreen, template);
328b8e80941Smrg        }
329b8e80941Smrg
330b8e80941Smrg        return (struct pipe_resource *)so;
331b8e80941Smrg}
332b8e80941Smrg
333b8e80941Smrgstatic void
334b8e80941Smrgpanfrost_destroy_bo(struct panfrost_screen *screen, struct panfrost_bo *pbo)
335b8e80941Smrg{
336b8e80941Smrg	struct panfrost_bo *bo = (struct panfrost_bo *)pbo;
337b8e80941Smrg
338b8e80941Smrg        if ((bo->layout == PAN_LINEAR || bo->layout == PAN_TILED) &&
339b8e80941Smrg                        !bo->imported) {
340b8e80941Smrg                struct panfrost_memory mem = {
341b8e80941Smrg                        .cpu = bo->cpu,
342b8e80941Smrg                        .gpu = bo->gpu,
343b8e80941Smrg                        .size = bo->size,
344b8e80941Smrg                        .gem_handle = bo->gem_handle,
345b8e80941Smrg                };
346b8e80941Smrg
347b8e80941Smrg                screen->driver->free_slab(screen, &mem);
348b8e80941Smrg        }
349b8e80941Smrg
350b8e80941Smrg        if (bo->layout == PAN_AFBC) {
351b8e80941Smrg                /* TODO */
352b8e80941Smrg                DBG("--leaking afbc (%d bytes)--\n", bo->afbc_metadata_size);
353b8e80941Smrg        }
354b8e80941Smrg
355b8e80941Smrg        if (bo->has_checksum) {
356b8e80941Smrg                /* TODO */
357b8e80941Smrg                DBG("--leaking checksum (%zd bytes)--\n", bo->checksum_slab.size);
358b8e80941Smrg        }
359b8e80941Smrg
360b8e80941Smrg        if (bo->imported) {
361b8e80941Smrg                screen->driver->free_imported_bo(screen, bo);
362b8e80941Smrg        }
363b8e80941Smrg}
364b8e80941Smrg
365b8e80941Smrgvoid
366b8e80941Smrgpanfrost_bo_reference(struct panfrost_bo *bo)
367b8e80941Smrg{
368b8e80941Smrg        pipe_reference(NULL, &bo->reference);
369b8e80941Smrg}
370b8e80941Smrg
371b8e80941Smrgvoid
372b8e80941Smrgpanfrost_bo_unreference(struct pipe_screen *screen, struct panfrost_bo *bo)
373b8e80941Smrg{
374b8e80941Smrg        /* When the reference count goes to zero, we need to cleanup */
375b8e80941Smrg
376b8e80941Smrg        if (pipe_reference(&bo->reference, NULL)) {
377b8e80941Smrg                panfrost_destroy_bo(pan_screen(screen), bo);
378b8e80941Smrg        }
379b8e80941Smrg}
380b8e80941Smrg
381b8e80941Smrgstatic void
382b8e80941Smrgpanfrost_resource_destroy(struct pipe_screen *screen,
383b8e80941Smrg                          struct pipe_resource *pt)
384b8e80941Smrg{
385b8e80941Smrg        struct panfrost_screen *pscreen = pan_screen(screen);
386b8e80941Smrg        struct panfrost_resource *rsrc = (struct panfrost_resource *) pt;
387b8e80941Smrg
388b8e80941Smrg	if (rsrc->scanout)
389b8e80941Smrg		renderonly_scanout_destroy(rsrc->scanout, pscreen->ro);
390b8e80941Smrg
391b8e80941Smrg	if (rsrc->bo)
392b8e80941Smrg                panfrost_bo_unreference(screen, rsrc->bo);
393b8e80941Smrg
394b8e80941Smrg        util_range_destroy(&rsrc->valid_buffer_range);
395b8e80941Smrg	FREE(rsrc);
396b8e80941Smrg}
397b8e80941Smrg
398b8e80941Smrgstatic void *
399b8e80941Smrgpanfrost_transfer_map(struct pipe_context *pctx,
400b8e80941Smrg                      struct pipe_resource *resource,
401b8e80941Smrg                      unsigned level,
402b8e80941Smrg                      unsigned usage,  /* a combination of PIPE_TRANSFER_x */
403b8e80941Smrg                      const struct pipe_box *box,
404b8e80941Smrg                      struct pipe_transfer **out_transfer)
405b8e80941Smrg{
406b8e80941Smrg        int bytes_per_pixel = util_format_get_blocksize(resource->format);
407b8e80941Smrg        struct panfrost_resource *rsrc = pan_resource(resource);
408b8e80941Smrg        struct panfrost_bo *bo = rsrc->bo;
409b8e80941Smrg
410b8e80941Smrg        struct panfrost_gtransfer *transfer = CALLOC_STRUCT(panfrost_gtransfer);
411b8e80941Smrg        transfer->base.level = level;
412b8e80941Smrg        transfer->base.usage = usage;
413b8e80941Smrg        transfer->base.box = *box;
414b8e80941Smrg
415b8e80941Smrg        pipe_resource_reference(&transfer->base.resource, resource);
416b8e80941Smrg
417b8e80941Smrg        *out_transfer = &transfer->base;
418b8e80941Smrg
419b8e80941Smrg        /* Check if we're bound for rendering and this is a read pixels. If so,
420b8e80941Smrg         * we need to flush */
421b8e80941Smrg
422b8e80941Smrg        struct panfrost_context *ctx = pan_context(pctx);
423b8e80941Smrg        struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer;
424b8e80941Smrg
425b8e80941Smrg        bool is_bound = false;
426b8e80941Smrg
427b8e80941Smrg        for (unsigned c = 0; c < fb->nr_cbufs; ++c) {
428b8e80941Smrg                is_bound |= fb->cbufs[c]->texture == resource;
429b8e80941Smrg        }
430b8e80941Smrg
431b8e80941Smrg        if (is_bound && (usage & PIPE_TRANSFER_READ)) {
432b8e80941Smrg                assert(level == 0);
433b8e80941Smrg                panfrost_flush(pctx, NULL, PIPE_FLUSH_END_OF_FRAME);
434b8e80941Smrg        }
435b8e80941Smrg
436b8e80941Smrg        /* TODO: Respect usage flags */
437b8e80941Smrg
438b8e80941Smrg        if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
439b8e80941Smrg                /* TODO: reallocate */
440b8e80941Smrg                //printf("debug: Missed reallocate\n");
441b8e80941Smrg        } else if ((usage & PIPE_TRANSFER_WRITE)
442b8e80941Smrg                        && resource->target == PIPE_BUFFER
443b8e80941Smrg                        && !util_ranges_intersect(&rsrc->valid_buffer_range, box->x, box->x + box->width)) {
444b8e80941Smrg                /* No flush for writes to uninitialized */
445b8e80941Smrg        } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
446b8e80941Smrg                if (usage & PIPE_TRANSFER_WRITE) {
447b8e80941Smrg                        /* STUB: flush reading */
448b8e80941Smrg                        //printf("debug: missed reading flush %d\n", resource->target);
449b8e80941Smrg                } else if (usage & PIPE_TRANSFER_READ) {
450b8e80941Smrg                        /* STUB: flush writing */
451b8e80941Smrg                        //printf("debug: missed writing flush %d (%d-%d)\n", resource->target, box->x, box->x + box->width);
452b8e80941Smrg                } else {
453b8e80941Smrg                        /* Why are you even mapping?! */
454b8e80941Smrg                }
455b8e80941Smrg        }
456b8e80941Smrg
457b8e80941Smrg        if (bo->layout != PAN_LINEAR) {
458b8e80941Smrg                /* Non-linear resources need to be indirectly mapped */
459b8e80941Smrg
460b8e80941Smrg                if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
461b8e80941Smrg                        return NULL;
462b8e80941Smrg
463b8e80941Smrg                transfer->base.stride = box->width * bytes_per_pixel;
464b8e80941Smrg                transfer->base.layer_stride = transfer->base.stride * box->height;
465b8e80941Smrg
466b8e80941Smrg                /* TODO: Reads */
467b8e80941Smrg                transfer->map = malloc(transfer->base.layer_stride * box->depth);
468b8e80941Smrg
469b8e80941Smrg                return transfer->map;
470b8e80941Smrg        } else {
471b8e80941Smrg                transfer->base.stride = bo->slices[level].stride;
472b8e80941Smrg                transfer->base.layer_stride = bo->cubemap_stride;
473b8e80941Smrg
474b8e80941Smrg                return bo->cpu
475b8e80941Smrg                        + bo->slices[level].offset
476b8e80941Smrg                        + transfer->base.box.z * bo->cubemap_stride
477b8e80941Smrg                        + transfer->base.box.y * bo->slices[level].stride
478b8e80941Smrg                        + transfer->base.box.x * bytes_per_pixel;
479b8e80941Smrg        }
480b8e80941Smrg}
481b8e80941Smrg
482b8e80941Smrgstatic void
483b8e80941Smrgpanfrost_tile_texture(struct panfrost_screen *screen, struct panfrost_resource *rsrc, struct panfrost_gtransfer *trans)
484b8e80941Smrg{
485b8e80941Smrg	struct panfrost_bo *bo = (struct panfrost_bo *)rsrc->bo;
486b8e80941Smrg
487b8e80941Smrg        unsigned level = trans->base.level;
488b8e80941Smrg
489b8e80941Smrg        panfrost_texture_swizzle(
490b8e80941Smrg                        trans->base.box.x,
491b8e80941Smrg                        trans->base.box.y,
492b8e80941Smrg                        trans->base.box.width,
493b8e80941Smrg                        trans->base.box.height,
494b8e80941Smrg                        util_format_get_blocksize(rsrc->base.format),
495b8e80941Smrg                        u_minify(rsrc->base.width0, level),
496b8e80941Smrg                        trans->map,
497b8e80941Smrg                        bo->cpu
498b8e80941Smrg                                + bo->slices[level].offset
499b8e80941Smrg                                + bo->cubemap_stride * trans->base.box.z
500b8e80941Smrg                        );
501b8e80941Smrg}
502b8e80941Smrg
503b8e80941Smrgstatic void
504b8e80941Smrgpanfrost_transfer_unmap(struct pipe_context *pctx,
505b8e80941Smrg                        struct pipe_transfer *transfer)
506b8e80941Smrg{
507b8e80941Smrg        struct panfrost_context *ctx = pan_context(pctx);
508b8e80941Smrg
509b8e80941Smrg        /* Gallium expects writeback here, so we tile */
510b8e80941Smrg
511b8e80941Smrg        struct panfrost_gtransfer *trans = pan_transfer(transfer);
512b8e80941Smrg        struct panfrost_resource *prsrc = (struct panfrost_resource *) transfer->resource;
513b8e80941Smrg
514b8e80941Smrg        if (trans->map) {
515b8e80941Smrg                struct panfrost_bo *bo = prsrc->bo;
516b8e80941Smrg
517b8e80941Smrg                if (transfer->usage & PIPE_TRANSFER_WRITE) {
518b8e80941Smrg
519b8e80941Smrg                        if (bo->layout == PAN_AFBC) {
520b8e80941Smrg                                DBG("Unimplemented: writes to AFBC\n");
521b8e80941Smrg                        } else if (bo->layout == PAN_TILED) {
522b8e80941Smrg                                struct pipe_context *gallium = (struct pipe_context *) ctx;
523b8e80941Smrg                                struct panfrost_screen *screen = pan_screen(gallium->screen);
524b8e80941Smrg                                assert(transfer->box.depth == 1);
525b8e80941Smrg                                panfrost_tile_texture(screen, prsrc, trans);
526b8e80941Smrg                        }
527b8e80941Smrg                }
528b8e80941Smrg
529b8e80941Smrg                free(trans->map);
530b8e80941Smrg        }
531b8e80941Smrg
532b8e80941Smrg
533b8e80941Smrg	util_range_add(&prsrc->valid_buffer_range,
534b8e80941Smrg                        transfer->box.x,
535b8e80941Smrg                        transfer->box.x + transfer->box.width);
536b8e80941Smrg
537b8e80941Smrg        /* Derefence the resource */
538b8e80941Smrg        pipe_resource_reference(&transfer->resource, NULL);
539b8e80941Smrg
540b8e80941Smrg        /* Transfer itself is CALLOCed at the moment */
541b8e80941Smrg        free(transfer);
542b8e80941Smrg}
543b8e80941Smrg
544b8e80941Smrgstatic void
545b8e80941Smrgpanfrost_transfer_flush_region(struct pipe_context *pctx,
546b8e80941Smrg		struct pipe_transfer *transfer,
547b8e80941Smrg		const struct pipe_box *box)
548b8e80941Smrg{
549b8e80941Smrg	struct panfrost_resource *rsc = pan_resource(transfer->resource);
550b8e80941Smrg
551b8e80941Smrg	if (transfer->resource->target == PIPE_BUFFER) {
552b8e80941Smrg		util_range_add(&rsc->valid_buffer_range,
553b8e80941Smrg					   transfer->box.x + box->x,
554b8e80941Smrg					   transfer->box.x + box->x + box->width);
555b8e80941Smrg        }
556b8e80941Smrg}
557b8e80941Smrg
558b8e80941Smrgstatic struct pb_slab *
559b8e80941Smrgpanfrost_slab_alloc(void *priv, unsigned heap, unsigned entry_size, unsigned group_index)
560b8e80941Smrg{
561b8e80941Smrg        struct panfrost_screen *screen = (struct panfrost_screen *) priv;
562b8e80941Smrg        struct panfrost_memory *mem = CALLOC_STRUCT(panfrost_memory);
563b8e80941Smrg
564b8e80941Smrg        size_t slab_size = (1 << (MAX_SLAB_ENTRY_SIZE + 1));
565b8e80941Smrg
566b8e80941Smrg        mem->slab.num_entries = slab_size / entry_size;
567b8e80941Smrg        mem->slab.num_free = mem->slab.num_entries;
568b8e80941Smrg
569b8e80941Smrg        LIST_INITHEAD(&mem->slab.free);
570b8e80941Smrg        for (unsigned i = 0; i < mem->slab.num_entries; ++i) {
571b8e80941Smrg                /* Create a slab entry */
572b8e80941Smrg                struct panfrost_memory_entry *entry = CALLOC_STRUCT(panfrost_memory_entry);
573b8e80941Smrg                entry->offset = entry_size * i;
574b8e80941Smrg
575b8e80941Smrg                entry->base.slab = &mem->slab;
576b8e80941Smrg                entry->base.group_index = group_index;
577b8e80941Smrg
578b8e80941Smrg                LIST_ADDTAIL(&entry->base.head, &mem->slab.free);
579b8e80941Smrg        }
580b8e80941Smrg
581b8e80941Smrg        /* Actually allocate the memory from kernel-space. Mapped, same_va, no
582b8e80941Smrg         * special flags */
583b8e80941Smrg
584b8e80941Smrg        screen->driver->allocate_slab(screen, mem, slab_size / 4096, true, 0, 0, 0);
585b8e80941Smrg
586b8e80941Smrg        return &mem->slab;
587b8e80941Smrg}
588b8e80941Smrg
589b8e80941Smrgstatic bool
590b8e80941Smrgpanfrost_slab_can_reclaim(void *priv, struct pb_slab_entry *entry)
591b8e80941Smrg{
592b8e80941Smrg        struct panfrost_memory_entry *p_entry = (struct panfrost_memory_entry *) entry;
593b8e80941Smrg        return p_entry->freed;
594b8e80941Smrg}
595b8e80941Smrg
596b8e80941Smrgstatic void
597b8e80941Smrgpanfrost_slab_free(void *priv, struct pb_slab *slab)
598b8e80941Smrg{
599b8e80941Smrg        struct panfrost_memory *mem = (struct panfrost_memory *) slab;
600b8e80941Smrg        struct panfrost_screen *screen = (struct panfrost_screen *) priv;
601b8e80941Smrg
602b8e80941Smrg        screen->driver->free_slab(screen, mem);
603b8e80941Smrg}
604b8e80941Smrg
605b8e80941Smrgstatic void
606b8e80941Smrgpanfrost_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
607b8e80941Smrg{
608b8e80941Smrg        //DBG("TODO %s\n", __func__);
609b8e80941Smrg}
610b8e80941Smrg
611b8e80941Smrgstatic enum pipe_format
612b8e80941Smrgpanfrost_resource_get_internal_format(struct pipe_resource *prsrc)
613b8e80941Smrg{
614b8e80941Smrg        return prsrc->format;
615b8e80941Smrg}
616b8e80941Smrg
617b8e80941Smrgstatic void
618b8e80941Smrgpanfrost_resource_set_stencil(struct pipe_resource *prsrc,
619b8e80941Smrg                              struct pipe_resource *stencil)
620b8e80941Smrg{
621b8e80941Smrg        pan_resource(prsrc)->separate_stencil = pan_resource(stencil);
622b8e80941Smrg}
623b8e80941Smrg
624b8e80941Smrgstatic struct pipe_resource *
625b8e80941Smrgpanfrost_resource_get_stencil(struct pipe_resource *prsrc)
626b8e80941Smrg{
627b8e80941Smrg        return &pan_resource(prsrc)->separate_stencil->base;
628b8e80941Smrg}
629b8e80941Smrg
630b8e80941Smrgstatic const struct u_transfer_vtbl transfer_vtbl = {
631b8e80941Smrg        .resource_create          = panfrost_resource_create,
632b8e80941Smrg        .resource_destroy         = panfrost_resource_destroy,
633b8e80941Smrg        .transfer_map             = panfrost_transfer_map,
634b8e80941Smrg        .transfer_unmap           = panfrost_transfer_unmap,
635b8e80941Smrg        .transfer_flush_region    = panfrost_transfer_flush_region,
636b8e80941Smrg        .get_internal_format      = panfrost_resource_get_internal_format,
637b8e80941Smrg        .set_stencil              = panfrost_resource_set_stencil,
638b8e80941Smrg        .get_stencil              = panfrost_resource_get_stencil,
639b8e80941Smrg};
640b8e80941Smrg
641b8e80941Smrgvoid
642b8e80941Smrgpanfrost_resource_screen_init(struct panfrost_screen *pscreen)
643b8e80941Smrg{
644b8e80941Smrg        //pscreen->base.resource_create_with_modifiers =
645b8e80941Smrg        //        panfrost_resource_create_with_modifiers;
646b8e80941Smrg        pscreen->base.resource_create = u_transfer_helper_resource_create;
647b8e80941Smrg        pscreen->base.resource_destroy = u_transfer_helper_resource_destroy;
648b8e80941Smrg        pscreen->base.resource_from_handle = panfrost_resource_from_handle;
649b8e80941Smrg        pscreen->base.resource_get_handle = panfrost_resource_get_handle;
650b8e80941Smrg        pscreen->base.transfer_helper = u_transfer_helper_create(&transfer_vtbl,
651b8e80941Smrg                                                            true, false,
652b8e80941Smrg                                                            true, true);
653b8e80941Smrg
654b8e80941Smrg        pb_slabs_init(&pscreen->slabs,
655b8e80941Smrg                        MIN_SLAB_ENTRY_SIZE,
656b8e80941Smrg                        MAX_SLAB_ENTRY_SIZE,
657b8e80941Smrg
658b8e80941Smrg                        3, /* Number of heaps */
659b8e80941Smrg
660b8e80941Smrg                        pscreen,
661b8e80941Smrg
662b8e80941Smrg                        panfrost_slab_can_reclaim,
663b8e80941Smrg                        panfrost_slab_alloc,
664b8e80941Smrg                        panfrost_slab_free);
665b8e80941Smrg}
666b8e80941Smrg
667b8e80941Smrgvoid
668b8e80941Smrgpanfrost_resource_context_init(struct pipe_context *pctx)
669b8e80941Smrg{
670b8e80941Smrg        pctx->transfer_map = u_transfer_helper_transfer_map;
671b8e80941Smrg        pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;
672b8e80941Smrg        pctx->transfer_unmap = u_transfer_helper_transfer_unmap;
673b8e80941Smrg        pctx->buffer_subdata = u_default_buffer_subdata;
674b8e80941Smrg        pctx->create_surface = panfrost_create_surface;
675b8e80941Smrg        pctx->surface_destroy = panfrost_surface_destroy;
676b8e80941Smrg        pctx->resource_copy_region = util_resource_copy_region;
677b8e80941Smrg        pctx->blit = panfrost_blit;
678b8e80941Smrg        pctx->flush_resource = panfrost_flush_resource;
679b8e80941Smrg        pctx->invalidate_resource = panfrost_invalidate_resource;
680b8e80941Smrg        pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;
681b8e80941Smrg        pctx->buffer_subdata = u_default_buffer_subdata;
682b8e80941Smrg        pctx->texture_subdata = u_default_texture_subdata;
683b8e80941Smrg}
684