101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2014-2017 Broadcom
301e04c3fSmrg * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
401e04c3fSmrg *
501e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
601e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
701e04c3fSmrg * to deal in the Software without restriction, including without limitation
801e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
901e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
1001e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1101e04c3fSmrg *
1201e04c3fSmrg * The above copyright notice and this permission notice (including the next
1301e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1401e04c3fSmrg * Software.
1501e04c3fSmrg *
1601e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1701e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1801e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1901e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2001e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2101e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2201e04c3fSmrg * IN THE SOFTWARE.
2301e04c3fSmrg */
2401e04c3fSmrg
2501e04c3fSmrg#include "pipe/p_defines.h"
2601e04c3fSmrg#include "util/u_memory.h"
277ec681f3Smrg#include "util/format/u_format.h"
2801e04c3fSmrg#include "util/u_inlines.h"
2901e04c3fSmrg#include "util/u_surface.h"
3001e04c3fSmrg#include "util/u_transfer_helper.h"
3101e04c3fSmrg#include "util/u_upload_mgr.h"
327ec681f3Smrg#include "util/format/u_format_zs.h"
339f464c52Smaya#include "util/u_drm.h"
3401e04c3fSmrg
359f464c52Smaya#include "drm-uapi/drm_fourcc.h"
3601e04c3fSmrg#include "v3d_screen.h"
3701e04c3fSmrg#include "v3d_context.h"
3801e04c3fSmrg#include "v3d_resource.h"
3901e04c3fSmrg#include "broadcom/cle/v3d_packet_v33_pack.h"
4001e04c3fSmrg
4101e04c3fSmrgstatic void
4201e04c3fSmrgv3d_debug_resource_layout(struct v3d_resource *rsc, const char *caller)
4301e04c3fSmrg{
447ec681f3Smrg        if (!(unlikely(V3D_DEBUG & V3D_DEBUG_SURFACE)))
4501e04c3fSmrg                return;
4601e04c3fSmrg
4701e04c3fSmrg        struct pipe_resource *prsc = &rsc->base;
4801e04c3fSmrg
4901e04c3fSmrg        if (prsc->target == PIPE_BUFFER) {
5001e04c3fSmrg                fprintf(stderr,
5101e04c3fSmrg                        "rsc %s %p (format %s), %dx%d buffer @0x%08x-0x%08x\n",
5201e04c3fSmrg                        caller, rsc,
5301e04c3fSmrg                        util_format_short_name(prsc->format),
5401e04c3fSmrg                        prsc->width0, prsc->height0,
5501e04c3fSmrg                        rsc->bo->offset,
5601e04c3fSmrg                        rsc->bo->offset + rsc->bo->size - 1);
5701e04c3fSmrg                return;
5801e04c3fSmrg        }
5901e04c3fSmrg
6001e04c3fSmrg        static const char *const tiling_descriptions[] = {
617ec681f3Smrg                [V3D_TILING_RASTER] = "R",
627ec681f3Smrg                [V3D_TILING_LINEARTILE] = "LT",
637ec681f3Smrg                [V3D_TILING_UBLINEAR_1_COLUMN] = "UB1",
647ec681f3Smrg                [V3D_TILING_UBLINEAR_2_COLUMN] = "UB2",
657ec681f3Smrg                [V3D_TILING_UIF_NO_XOR] = "UIF",
667ec681f3Smrg                [V3D_TILING_UIF_XOR] = "UIF^",
6701e04c3fSmrg        };
6801e04c3fSmrg
6901e04c3fSmrg        for (int i = 0; i <= prsc->last_level; i++) {
7001e04c3fSmrg                struct v3d_resource_slice *slice = &rsc->slices[i];
7101e04c3fSmrg
7201e04c3fSmrg                int level_width = slice->stride / rsc->cpp;
7301e04c3fSmrg                int level_height = slice->padded_height;
7401e04c3fSmrg                int level_depth =
7501e04c3fSmrg                        u_minify(util_next_power_of_two(prsc->depth0), i);
7601e04c3fSmrg
7701e04c3fSmrg                fprintf(stderr,
7801e04c3fSmrg                        "rsc %s %p (format %s), %dx%d: "
7901e04c3fSmrg                        "level %d (%s) %dx%dx%d -> %dx%dx%d, stride %d@0x%08x\n",
8001e04c3fSmrg                        caller, rsc,
8101e04c3fSmrg                        util_format_short_name(prsc->format),
8201e04c3fSmrg                        prsc->width0, prsc->height0,
8301e04c3fSmrg                        i, tiling_descriptions[slice->tiling],
8401e04c3fSmrg                        u_minify(prsc->width0, i),
8501e04c3fSmrg                        u_minify(prsc->height0, i),
8601e04c3fSmrg                        u_minify(prsc->depth0, i),
8701e04c3fSmrg                        level_width,
8801e04c3fSmrg                        level_height,
8901e04c3fSmrg                        level_depth,
9001e04c3fSmrg                        slice->stride,
9101e04c3fSmrg                        rsc->bo->offset + slice->offset);
9201e04c3fSmrg        }
9301e04c3fSmrg}
9401e04c3fSmrg
9501e04c3fSmrgstatic bool
9601e04c3fSmrgv3d_resource_bo_alloc(struct v3d_resource *rsc)
9701e04c3fSmrg{
9801e04c3fSmrg        struct pipe_resource *prsc = &rsc->base;
9901e04c3fSmrg        struct pipe_screen *pscreen = prsc->screen;
10001e04c3fSmrg        struct v3d_bo *bo;
10101e04c3fSmrg
10201e04c3fSmrg        bo = v3d_bo_alloc(v3d_screen(pscreen), rsc->size, "resource");
10301e04c3fSmrg        if (bo) {
10401e04c3fSmrg                v3d_bo_unreference(&rsc->bo);
10501e04c3fSmrg                rsc->bo = bo;
10601e04c3fSmrg                v3d_debug_resource_layout(rsc, "alloc");
10701e04c3fSmrg                return true;
10801e04c3fSmrg        } else {
10901e04c3fSmrg                return false;
11001e04c3fSmrg        }
11101e04c3fSmrg}
11201e04c3fSmrg
11301e04c3fSmrgstatic void
11401e04c3fSmrgv3d_resource_transfer_unmap(struct pipe_context *pctx,
11501e04c3fSmrg                            struct pipe_transfer *ptrans)
11601e04c3fSmrg{
11701e04c3fSmrg        struct v3d_context *v3d = v3d_context(pctx);
11801e04c3fSmrg        struct v3d_transfer *trans = v3d_transfer(ptrans);
11901e04c3fSmrg
12001e04c3fSmrg        if (trans->map) {
12101e04c3fSmrg                struct v3d_resource *rsc = v3d_resource(ptrans->resource);
12201e04c3fSmrg                struct v3d_resource_slice *slice = &rsc->slices[ptrans->level];
12301e04c3fSmrg
1247ec681f3Smrg                if (ptrans->usage & PIPE_MAP_WRITE) {
12501e04c3fSmrg                        for (int z = 0; z < ptrans->box.depth; z++) {
12601e04c3fSmrg                                void *dst = rsc->bo->map +
12701e04c3fSmrg                                        v3d_layer_offset(&rsc->base,
12801e04c3fSmrg                                                         ptrans->level,
12901e04c3fSmrg                                                         ptrans->box.z + z);
13001e04c3fSmrg                                v3d_store_tiled_image(dst,
13101e04c3fSmrg                                                      slice->stride,
13201e04c3fSmrg                                                      (trans->map +
13301e04c3fSmrg                                                       ptrans->stride *
13401e04c3fSmrg                                                       ptrans->box.height * z),
13501e04c3fSmrg                                                      ptrans->stride,
13601e04c3fSmrg                                                      slice->tiling, rsc->cpp,
13701e04c3fSmrg                                                      slice->padded_height,
13801e04c3fSmrg                                                      &ptrans->box);
13901e04c3fSmrg                        }
14001e04c3fSmrg                }
14101e04c3fSmrg                free(trans->map);
14201e04c3fSmrg        }
14301e04c3fSmrg
14401e04c3fSmrg        pipe_resource_reference(&ptrans->resource, NULL);
14501e04c3fSmrg        slab_free(&v3d->transfer_pool, ptrans);
14601e04c3fSmrg}
14701e04c3fSmrg
1487ec681f3Smrgstatic void
1497ec681f3Smrgrebind_sampler_views(struct v3d_context *v3d,
1507ec681f3Smrg                     struct v3d_resource *rsc)
1517ec681f3Smrg{
1527ec681f3Smrg        for (int st = 0; st < PIPE_SHADER_TYPES; st++) {
1537ec681f3Smrg                struct v3d_texture_stateobj *tex = v3d->tex + st;
1547ec681f3Smrg
1557ec681f3Smrg                for (unsigned i = 0; i < tex->num_textures; i++) {
1567ec681f3Smrg                        struct pipe_sampler_view *psview = tex->textures[i];
1577ec681f3Smrg
1587ec681f3Smrg                        if (psview->texture != &rsc->base)
1597ec681f3Smrg                                continue;
1607ec681f3Smrg
1617ec681f3Smrg                        struct v3d_sampler_view *sview =
1627ec681f3Smrg                                v3d_sampler_view(psview);
1637ec681f3Smrg
1647ec681f3Smrg                        v3d_create_texture_shader_state_bo(v3d, sview);
1657ec681f3Smrg
1667ec681f3Smrg                        v3d_flag_dirty_sampler_state(v3d, st);
1677ec681f3Smrg                }
1687ec681f3Smrg        }
1697ec681f3Smrg}
1707ec681f3Smrg
1719f464c52Smayastatic void
1729f464c52Smayav3d_map_usage_prep(struct pipe_context *pctx,
1739f464c52Smaya                   struct pipe_resource *prsc,
1749f464c52Smaya                   unsigned usage)
17501e04c3fSmrg{
17601e04c3fSmrg        struct v3d_context *v3d = v3d_context(pctx);
17701e04c3fSmrg        struct v3d_resource *rsc = v3d_resource(prsc);
17801e04c3fSmrg
1797ec681f3Smrg        if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) {
18001e04c3fSmrg                if (v3d_resource_bo_alloc(rsc)) {
18101e04c3fSmrg                        /* If it might be bound as one of our vertex buffers
18201e04c3fSmrg                         * or UBOs, make sure we re-emit vertex buffer state
18301e04c3fSmrg                         * or uniforms.
18401e04c3fSmrg                         */
18501e04c3fSmrg                        if (prsc->bind & PIPE_BIND_VERTEX_BUFFER)
1867ec681f3Smrg                                v3d->dirty |= V3D_DIRTY_VTXBUF;
18701e04c3fSmrg                        if (prsc->bind & PIPE_BIND_CONSTANT_BUFFER)
1887ec681f3Smrg                                v3d->dirty |= V3D_DIRTY_CONSTBUF;
1897ec681f3Smrg                        if (prsc->bind & PIPE_BIND_SAMPLER_VIEW)
1907ec681f3Smrg                                rebind_sampler_views(v3d, rsc);
19101e04c3fSmrg                } else {
19201e04c3fSmrg                        /* If we failed to reallocate, flush users so that we
19301e04c3fSmrg                         * don't violate any syncing requirements.
19401e04c3fSmrg                         */
1957ec681f3Smrg                        v3d_flush_jobs_reading_resource(v3d, prsc,
1967ec681f3Smrg                                                        V3D_FLUSH_DEFAULT,
1977ec681f3Smrg                                                        false);
19801e04c3fSmrg                }
1997ec681f3Smrg        } else if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) {
20001e04c3fSmrg                /* If we're writing and the buffer is being used by the CL, we
20101e04c3fSmrg                 * have to flush the CL first.  If we're only reading, we need
20201e04c3fSmrg                 * to flush if the CL has written our buffer.
20301e04c3fSmrg                 */
2047ec681f3Smrg                if (usage & PIPE_MAP_WRITE) {
2057ec681f3Smrg                        v3d_flush_jobs_reading_resource(v3d, prsc,
2067ec681f3Smrg                                                        V3D_FLUSH_ALWAYS,
2077ec681f3Smrg                                                        false);
2087ec681f3Smrg                } else {
2097ec681f3Smrg                        v3d_flush_jobs_writing_resource(v3d, prsc,
2107ec681f3Smrg                                                        V3D_FLUSH_ALWAYS,
2117ec681f3Smrg                                                        false);
2127ec681f3Smrg                }
21301e04c3fSmrg        }
21401e04c3fSmrg
2157ec681f3Smrg        if (usage & PIPE_MAP_WRITE) {
21601e04c3fSmrg                rsc->writes++;
21701e04c3fSmrg                rsc->initialized_buffers = ~0;
21801e04c3fSmrg        }
2199f464c52Smaya}
2209f464c52Smaya
2219f464c52Smayastatic void *
2229f464c52Smayav3d_resource_transfer_map(struct pipe_context *pctx,
2239f464c52Smaya                          struct pipe_resource *prsc,
2249f464c52Smaya                          unsigned level, unsigned usage,
2259f464c52Smaya                          const struct pipe_box *box,
2269f464c52Smaya                          struct pipe_transfer **pptrans)
2279f464c52Smaya{
2289f464c52Smaya        struct v3d_context *v3d = v3d_context(pctx);
2299f464c52Smaya        struct v3d_resource *rsc = v3d_resource(prsc);
2309f464c52Smaya        struct v3d_transfer *trans;
2319f464c52Smaya        struct pipe_transfer *ptrans;
2329f464c52Smaya        enum pipe_format format = prsc->format;
2339f464c52Smaya        char *buf;
2349f464c52Smaya
2359f464c52Smaya        /* MSAA maps should have been handled by u_transfer_helper. */
2369f464c52Smaya        assert(prsc->nr_samples <= 1);
2379f464c52Smaya
2389f464c52Smaya        /* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is
2399f464c52Smaya         * being mapped.
2409f464c52Smaya         */
2417ec681f3Smrg        if ((usage & PIPE_MAP_DISCARD_RANGE) &&
2427ec681f3Smrg            !(usage & PIPE_MAP_UNSYNCHRONIZED) &&
2439f464c52Smaya            !(prsc->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) &&
2449f464c52Smaya            prsc->last_level == 0 &&
2459f464c52Smaya            prsc->width0 == box->width &&
2469f464c52Smaya            prsc->height0 == box->height &&
2479f464c52Smaya            prsc->depth0 == box->depth &&
2489f464c52Smaya            prsc->array_size == 1 &&
2499f464c52Smaya            rsc->bo->private) {
2507ec681f3Smrg                usage |= PIPE_MAP_DISCARD_WHOLE_RESOURCE;
2519f464c52Smaya        }
2529f464c52Smaya
2539f464c52Smaya        v3d_map_usage_prep(pctx, prsc, usage);
25401e04c3fSmrg
25501e04c3fSmrg        trans = slab_alloc(&v3d->transfer_pool);
25601e04c3fSmrg        if (!trans)
25701e04c3fSmrg                return NULL;
25801e04c3fSmrg
25901e04c3fSmrg        /* XXX: Handle DONTBLOCK, DISCARD_RANGE, PERSISTENT, COHERENT. */
26001e04c3fSmrg
26101e04c3fSmrg        /* slab_alloc_st() doesn't zero: */
26201e04c3fSmrg        memset(trans, 0, sizeof(*trans));
26301e04c3fSmrg        ptrans = &trans->base;
26401e04c3fSmrg
26501e04c3fSmrg        pipe_resource_reference(&ptrans->resource, prsc);
26601e04c3fSmrg        ptrans->level = level;
26701e04c3fSmrg        ptrans->usage = usage;
26801e04c3fSmrg        ptrans->box = *box;
26901e04c3fSmrg
27001e04c3fSmrg        /* Note that the current kernel implementation is synchronous, so no
27101e04c3fSmrg         * need to do syncing stuff here yet.
27201e04c3fSmrg         */
27301e04c3fSmrg
2747ec681f3Smrg        if (usage & PIPE_MAP_UNSYNCHRONIZED)
27501e04c3fSmrg                buf = v3d_bo_map_unsynchronized(rsc->bo);
27601e04c3fSmrg        else
27701e04c3fSmrg                buf = v3d_bo_map(rsc->bo);
27801e04c3fSmrg        if (!buf) {
27901e04c3fSmrg                fprintf(stderr, "Failed to map bo\n");
28001e04c3fSmrg                goto fail;
28101e04c3fSmrg        }
28201e04c3fSmrg
28301e04c3fSmrg        *pptrans = ptrans;
28401e04c3fSmrg
28501e04c3fSmrg        /* Our load/store routines work on entire compressed blocks. */
28601e04c3fSmrg        ptrans->box.x /= util_format_get_blockwidth(format);
28701e04c3fSmrg        ptrans->box.y /= util_format_get_blockheight(format);
28801e04c3fSmrg        ptrans->box.width = DIV_ROUND_UP(ptrans->box.width,
28901e04c3fSmrg                                         util_format_get_blockwidth(format));
29001e04c3fSmrg        ptrans->box.height = DIV_ROUND_UP(ptrans->box.height,
29101e04c3fSmrg                                          util_format_get_blockheight(format));
29201e04c3fSmrg
29301e04c3fSmrg        struct v3d_resource_slice *slice = &rsc->slices[level];
29401e04c3fSmrg        if (rsc->tiled) {
29501e04c3fSmrg                /* No direct mappings of tiled, since we need to manually
29601e04c3fSmrg                 * tile/untile.
29701e04c3fSmrg                 */
2987ec681f3Smrg                if (usage & PIPE_MAP_DIRECTLY)
29901e04c3fSmrg                        return NULL;
30001e04c3fSmrg
30101e04c3fSmrg                ptrans->stride = ptrans->box.width * rsc->cpp;
30201e04c3fSmrg                ptrans->layer_stride = ptrans->stride * ptrans->box.height;
30301e04c3fSmrg
30401e04c3fSmrg                trans->map = malloc(ptrans->layer_stride * ptrans->box.depth);
30501e04c3fSmrg
3067ec681f3Smrg                if (usage & PIPE_MAP_READ) {
30701e04c3fSmrg                        for (int z = 0; z < ptrans->box.depth; z++) {
30801e04c3fSmrg                                void *src = rsc->bo->map +
30901e04c3fSmrg                                        v3d_layer_offset(&rsc->base,
31001e04c3fSmrg                                                         ptrans->level,
31101e04c3fSmrg                                                         ptrans->box.z + z);
31201e04c3fSmrg                                v3d_load_tiled_image((trans->map +
31301e04c3fSmrg                                                      ptrans->stride *
31401e04c3fSmrg                                                      ptrans->box.height * z),
31501e04c3fSmrg                                                     ptrans->stride,
31601e04c3fSmrg                                                     src,
31701e04c3fSmrg                                                     slice->stride,
31801e04c3fSmrg                                                     slice->tiling, rsc->cpp,
31901e04c3fSmrg                                                     slice->padded_height,
32001e04c3fSmrg                                             &ptrans->box);
32101e04c3fSmrg                        }
32201e04c3fSmrg                }
32301e04c3fSmrg                return trans->map;
32401e04c3fSmrg        } else {
32501e04c3fSmrg                ptrans->stride = slice->stride;
32601e04c3fSmrg                ptrans->layer_stride = rsc->cube_map_stride;
32701e04c3fSmrg
32801e04c3fSmrg                return buf + slice->offset +
32901e04c3fSmrg                        ptrans->box.y * ptrans->stride +
33001e04c3fSmrg                        ptrans->box.x * rsc->cpp +
33101e04c3fSmrg                        ptrans->box.z * rsc->cube_map_stride;
33201e04c3fSmrg        }
33301e04c3fSmrg
33401e04c3fSmrg
33501e04c3fSmrgfail:
33601e04c3fSmrg        v3d_resource_transfer_unmap(pctx, ptrans);
33701e04c3fSmrg        return NULL;
33801e04c3fSmrg}
33901e04c3fSmrg
3409f464c52Smayastatic void
3419f464c52Smayav3d_texture_subdata(struct pipe_context *pctx,
3429f464c52Smaya                    struct pipe_resource *prsc,
3439f464c52Smaya                    unsigned level,
3449f464c52Smaya                    unsigned usage,
3459f464c52Smaya                    const struct pipe_box *box,
3469f464c52Smaya                    const void *data,
3479f464c52Smaya                    unsigned stride,
3489f464c52Smaya                    unsigned layer_stride)
3499f464c52Smaya{
3509f464c52Smaya        struct v3d_resource *rsc = v3d_resource(prsc);
3519f464c52Smaya        struct v3d_resource_slice *slice = &rsc->slices[level];
3529f464c52Smaya
3539f464c52Smaya        /* For a direct mapping, we can just take the u_transfer path. */
3549f464c52Smaya        if (!rsc->tiled) {
3559f464c52Smaya                return u_default_texture_subdata(pctx, prsc, level, usage, box,
3569f464c52Smaya                                                 data, stride, layer_stride);
3579f464c52Smaya        }
3589f464c52Smaya
3599f464c52Smaya        /* Otherwise, map and store the texture data directly into the tiled
3609f464c52Smaya         * texture.  Note that gallium's texture_subdata may be called with
3619f464c52Smaya         * obvious usage flags missing!
3629f464c52Smaya         */
3637ec681f3Smrg        v3d_map_usage_prep(pctx, prsc, usage | (PIPE_MAP_WRITE |
3647ec681f3Smrg                                                PIPE_MAP_DISCARD_RANGE));
3659f464c52Smaya
3669f464c52Smaya        void *buf;
3677ec681f3Smrg        if (usage & PIPE_MAP_UNSYNCHRONIZED)
3689f464c52Smaya                buf = v3d_bo_map_unsynchronized(rsc->bo);
3699f464c52Smaya        else
3709f464c52Smaya                buf = v3d_bo_map(rsc->bo);
3719f464c52Smaya
3729f464c52Smaya        for (int i = 0; i < box->depth; i++) {
3739f464c52Smaya                v3d_store_tiled_image(buf +
3749f464c52Smaya                                      v3d_layer_offset(&rsc->base,
3759f464c52Smaya                                                       level,
3769f464c52Smaya                                                       box->z + i),
3779f464c52Smaya                                      slice->stride,
3789f464c52Smaya                                      (void *)data + layer_stride * i,
3799f464c52Smaya                                      stride,
3809f464c52Smaya                                      slice->tiling, rsc->cpp, slice->padded_height,
3819f464c52Smaya                                      box);
3829f464c52Smaya        }
3839f464c52Smaya}
3849f464c52Smaya
38501e04c3fSmrgstatic void
38601e04c3fSmrgv3d_resource_destroy(struct pipe_screen *pscreen,
38701e04c3fSmrg                     struct pipe_resource *prsc)
38801e04c3fSmrg{
3899f464c52Smaya        struct v3d_screen *screen = v3d_screen(pscreen);
39001e04c3fSmrg        struct v3d_resource *rsc = v3d_resource(prsc);
39101e04c3fSmrg
3929f464c52Smaya        if (rsc->scanout)
3939f464c52Smaya                renderonly_scanout_destroy(rsc->scanout, screen->ro);
3949f464c52Smaya
39501e04c3fSmrg        v3d_bo_unreference(&rsc->bo);
39601e04c3fSmrg        free(rsc);
39701e04c3fSmrg}
39801e04c3fSmrg
3997ec681f3Smrgstatic uint64_t
4007ec681f3Smrgv3d_resource_modifier(struct v3d_resource *rsc)
4017ec681f3Smrg{
4027ec681f3Smrg        if (rsc->tiled) {
4037ec681f3Smrg                /* A shared tiled buffer should always be allocated as UIF,
4047ec681f3Smrg                 * not UBLINEAR or LT.
4057ec681f3Smrg                 */
4067ec681f3Smrg                assert(rsc->slices[0].tiling == V3D_TILING_UIF_XOR ||
4077ec681f3Smrg                       rsc->slices[0].tiling == V3D_TILING_UIF_NO_XOR);
4087ec681f3Smrg                return DRM_FORMAT_MOD_BROADCOM_UIF;
4097ec681f3Smrg        } else {
4107ec681f3Smrg                return DRM_FORMAT_MOD_LINEAR;
4117ec681f3Smrg        }
4127ec681f3Smrg}
4137ec681f3Smrg
4147ec681f3Smrgstatic bool
41501e04c3fSmrgv3d_resource_get_handle(struct pipe_screen *pscreen,
41601e04c3fSmrg                        struct pipe_context *pctx,
41701e04c3fSmrg                        struct pipe_resource *prsc,
41801e04c3fSmrg                        struct winsys_handle *whandle,
41901e04c3fSmrg                        unsigned usage)
42001e04c3fSmrg{
4219f464c52Smaya        struct v3d_screen *screen = v3d_screen(pscreen);
42201e04c3fSmrg        struct v3d_resource *rsc = v3d_resource(prsc);
42301e04c3fSmrg        struct v3d_bo *bo = rsc->bo;
42401e04c3fSmrg
42501e04c3fSmrg        whandle->stride = rsc->slices[0].stride;
42601e04c3fSmrg        whandle->offset = 0;
4277ec681f3Smrg        whandle->modifier = v3d_resource_modifier(rsc);
42801e04c3fSmrg
42901e04c3fSmrg        /* If we're passing some reference to our BO out to some other part of
43001e04c3fSmrg         * the system, then we can't do any optimizations about only us being
43101e04c3fSmrg         * the ones seeing it (like BO caching).
43201e04c3fSmrg         */
43301e04c3fSmrg        bo->private = false;
43401e04c3fSmrg
43501e04c3fSmrg        switch (whandle->type) {
43601e04c3fSmrg        case WINSYS_HANDLE_TYPE_SHARED:
43701e04c3fSmrg                return v3d_bo_flink(bo, &whandle->handle);
43801e04c3fSmrg        case WINSYS_HANDLE_TYPE_KMS:
4399f464c52Smaya                if (screen->ro) {
4407ec681f3Smrg                        if (renderonly_get_handle(rsc->scanout, whandle)) {
4417ec681f3Smrg                                whandle->stride = rsc->slices[0].stride;
4427ec681f3Smrg                                return true;
4437ec681f3Smrg                        }
4447ec681f3Smrg                        return false;
4459f464c52Smaya                }
44601e04c3fSmrg                whandle->handle = bo->handle;
4477ec681f3Smrg                return true;
44801e04c3fSmrg        case WINSYS_HANDLE_TYPE_FD:
44901e04c3fSmrg                whandle->handle = v3d_bo_get_dmabuf(bo);
45001e04c3fSmrg                return whandle->handle != -1;
45101e04c3fSmrg        }
45201e04c3fSmrg
4537ec681f3Smrg        return false;
45401e04c3fSmrg}
45501e04c3fSmrg
4567ec681f3Smrgstatic bool
4577ec681f3Smrgv3d_resource_get_param(struct pipe_screen *pscreen,
4587ec681f3Smrg                       struct pipe_context *pctx, struct pipe_resource *prsc,
4597ec681f3Smrg                       unsigned plane, unsigned layer, unsigned level,
4607ec681f3Smrg                       enum pipe_resource_param param,
4617ec681f3Smrg                       unsigned usage, uint64_t *value)
4627ec681f3Smrg{
4637ec681f3Smrg        struct v3d_resource *rsc = v3d_resource(prsc);
4647ec681f3Smrg
4657ec681f3Smrg        switch (param) {
4667ec681f3Smrg        case PIPE_RESOURCE_PARAM_STRIDE:
4677ec681f3Smrg                *value = rsc->slices[level].stride;
4687ec681f3Smrg                return true;
4697ec681f3Smrg        case PIPE_RESOURCE_PARAM_OFFSET:
4707ec681f3Smrg                *value = 0;
4717ec681f3Smrg                return true;
4727ec681f3Smrg        case PIPE_RESOURCE_PARAM_MODIFIER:
4737ec681f3Smrg                *value = v3d_resource_modifier(rsc);
4747ec681f3Smrg                return true;
4757ec681f3Smrg        default:
4767ec681f3Smrg                return false;
4777ec681f3Smrg        }
4787ec681f3Smrg}
4797ec681f3Smrg
4807ec681f3Smrg#define PAGE_UB_ROWS (V3D_UIFCFG_PAGE_SIZE / V3D_UIFBLOCK_ROW_SIZE)
48101e04c3fSmrg#define PAGE_UB_ROWS_TIMES_1_5 ((PAGE_UB_ROWS * 3) >> 1)
4827ec681f3Smrg#define PAGE_CACHE_UB_ROWS (V3D_PAGE_CACHE_SIZE / V3D_UIFBLOCK_ROW_SIZE)
48301e04c3fSmrg#define PAGE_CACHE_MINUS_1_5_UB_ROWS (PAGE_CACHE_UB_ROWS - PAGE_UB_ROWS_TIMES_1_5)
48401e04c3fSmrg
48501e04c3fSmrg/**
48601e04c3fSmrg * Computes the HW's UIFblock padding for a given height/cpp.
48701e04c3fSmrg *
48801e04c3fSmrg * The goal of the padding is to keep pages of the same color (bank number) at
48901e04c3fSmrg * least half a page away from each other vertically when crossing between
49001e04c3fSmrg * between columns of UIF blocks.
49101e04c3fSmrg */
49201e04c3fSmrgstatic uint32_t
49301e04c3fSmrgv3d_get_ub_pad(struct v3d_resource *rsc, uint32_t height)
49401e04c3fSmrg{
49501e04c3fSmrg        uint32_t utile_h = v3d_utile_height(rsc->cpp);
49601e04c3fSmrg        uint32_t uif_block_h = utile_h * 2;
49701e04c3fSmrg        uint32_t height_ub = height / uif_block_h;
49801e04c3fSmrg
49901e04c3fSmrg        uint32_t height_offset_in_pc = height_ub % PAGE_CACHE_UB_ROWS;
50001e04c3fSmrg
50101e04c3fSmrg        /* For the perfectly-aligned-for-UIF-XOR case, don't add any pad. */
50201e04c3fSmrg        if (height_offset_in_pc == 0)
50301e04c3fSmrg                return 0;
50401e04c3fSmrg
50501e04c3fSmrg        /* Try padding up to where we're offset by at least half a page. */
50601e04c3fSmrg        if (height_offset_in_pc < PAGE_UB_ROWS_TIMES_1_5) {
50701e04c3fSmrg                /* If we fit entirely in the page cache, don't pad. */
50801e04c3fSmrg                if (height_ub < PAGE_CACHE_UB_ROWS)
50901e04c3fSmrg                        return 0;
51001e04c3fSmrg                else
51101e04c3fSmrg                        return PAGE_UB_ROWS_TIMES_1_5 - height_offset_in_pc;
51201e04c3fSmrg        }
51301e04c3fSmrg
51401e04c3fSmrg        /* If we're close to being aligned to page cache size, then round up
51501e04c3fSmrg         * and rely on XOR.
51601e04c3fSmrg         */
51701e04c3fSmrg        if (height_offset_in_pc > PAGE_CACHE_MINUS_1_5_UB_ROWS)
51801e04c3fSmrg                return PAGE_CACHE_UB_ROWS - height_offset_in_pc;
51901e04c3fSmrg
52001e04c3fSmrg        /* Otherwise, we're far enough away (top and bottom) to not need any
52101e04c3fSmrg         * padding.
52201e04c3fSmrg         */
52301e04c3fSmrg        return 0;
52401e04c3fSmrg}
52501e04c3fSmrg
52601e04c3fSmrgstatic void
5279f464c52Smayav3d_setup_slices(struct v3d_resource *rsc, uint32_t winsys_stride,
5289f464c52Smaya                 bool uif_top)
52901e04c3fSmrg{
53001e04c3fSmrg        struct pipe_resource *prsc = &rsc->base;
53101e04c3fSmrg        uint32_t width = prsc->width0;
53201e04c3fSmrg        uint32_t height = prsc->height0;
53301e04c3fSmrg        uint32_t depth = prsc->depth0;
53401e04c3fSmrg        /* Note that power-of-two padding is based on level 1.  These are not
53501e04c3fSmrg         * equivalent to just util_next_power_of_two(dimension), because at a
53601e04c3fSmrg         * level 0 dimension of 9, the level 1 power-of-two padded value is 4,
53701e04c3fSmrg         * not 8.
53801e04c3fSmrg         */
53901e04c3fSmrg        uint32_t pot_width = 2 * util_next_power_of_two(u_minify(width, 1));
54001e04c3fSmrg        uint32_t pot_height = 2 * util_next_power_of_two(u_minify(height, 1));
54101e04c3fSmrg        uint32_t pot_depth = 2 * util_next_power_of_two(u_minify(depth, 1));
54201e04c3fSmrg        uint32_t offset = 0;
54301e04c3fSmrg        uint32_t utile_w = v3d_utile_width(rsc->cpp);
54401e04c3fSmrg        uint32_t utile_h = v3d_utile_height(rsc->cpp);
54501e04c3fSmrg        uint32_t uif_block_w = utile_w * 2;
54601e04c3fSmrg        uint32_t uif_block_h = utile_h * 2;
54701e04c3fSmrg        uint32_t block_width = util_format_get_blockwidth(prsc->format);
54801e04c3fSmrg        uint32_t block_height = util_format_get_blockheight(prsc->format);
54901e04c3fSmrg        bool msaa = prsc->nr_samples > 1;
5509f464c52Smaya
55101e04c3fSmrg        /* MSAA textures/renderbuffers are always laid out as single-level
55201e04c3fSmrg         * UIF.
55301e04c3fSmrg         */
5549f464c52Smaya        uif_top |= msaa;
5559f464c52Smaya
5569f464c52Smaya        /* Check some easy mistakes to make in a resource_create() call that
5579f464c52Smaya         * will break our setup.
5589f464c52Smaya         */
5599f464c52Smaya        assert(prsc->array_size != 0);
5609f464c52Smaya        assert(prsc->depth0 != 0);
56101e04c3fSmrg
56201e04c3fSmrg        for (int i = prsc->last_level; i >= 0; i--) {
56301e04c3fSmrg                struct v3d_resource_slice *slice = &rsc->slices[i];
56401e04c3fSmrg
56501e04c3fSmrg                uint32_t level_width, level_height, level_depth;
56601e04c3fSmrg                if (i < 2) {
56701e04c3fSmrg                        level_width = u_minify(width, i);
56801e04c3fSmrg                        level_height = u_minify(height, i);
56901e04c3fSmrg                } else {
57001e04c3fSmrg                        level_width = u_minify(pot_width, i);
57101e04c3fSmrg                        level_height = u_minify(pot_height, i);
57201e04c3fSmrg                }
57301e04c3fSmrg                if (i < 1)
57401e04c3fSmrg                        level_depth = u_minify(depth, i);
57501e04c3fSmrg                else
57601e04c3fSmrg                        level_depth = u_minify(pot_depth, i);
57701e04c3fSmrg
57801e04c3fSmrg                if (msaa) {
57901e04c3fSmrg                        level_width *= 2;
58001e04c3fSmrg                        level_height *= 2;
58101e04c3fSmrg                }
58201e04c3fSmrg
58301e04c3fSmrg                level_width = DIV_ROUND_UP(level_width, block_width);
58401e04c3fSmrg                level_height = DIV_ROUND_UP(level_height, block_height);
58501e04c3fSmrg
58601e04c3fSmrg                if (!rsc->tiled) {
5877ec681f3Smrg                        slice->tiling = V3D_TILING_RASTER;
58801e04c3fSmrg                        if (prsc->target == PIPE_TEXTURE_1D)
58901e04c3fSmrg                                level_width = align(level_width, 64 / rsc->cpp);
59001e04c3fSmrg                } else {
59101e04c3fSmrg                        if ((i != 0 || !uif_top) &&
59201e04c3fSmrg                            (level_width <= utile_w ||
59301e04c3fSmrg                             level_height <= utile_h)) {
5947ec681f3Smrg                                slice->tiling = V3D_TILING_LINEARTILE;
59501e04c3fSmrg                                level_width = align(level_width, utile_w);
59601e04c3fSmrg                                level_height = align(level_height, utile_h);
59701e04c3fSmrg                        } else if ((i != 0 || !uif_top) &&
59801e04c3fSmrg                                   level_width <= uif_block_w) {
5997ec681f3Smrg                                slice->tiling = V3D_TILING_UBLINEAR_1_COLUMN;
60001e04c3fSmrg                                level_width = align(level_width, uif_block_w);
60101e04c3fSmrg                                level_height = align(level_height, uif_block_h);
60201e04c3fSmrg                        } else if ((i != 0 || !uif_top) &&
60301e04c3fSmrg                                   level_width <= 2 * uif_block_w) {
6047ec681f3Smrg                                slice->tiling = V3D_TILING_UBLINEAR_2_COLUMN;
60501e04c3fSmrg                                level_width = align(level_width, 2 * uif_block_w);
60601e04c3fSmrg                                level_height = align(level_height, uif_block_h);
60701e04c3fSmrg                        } else {
60801e04c3fSmrg                                /* We align the width to a 4-block column of
60901e04c3fSmrg                                 * UIF blocks, but we only align height to UIF
61001e04c3fSmrg                                 * blocks.
61101e04c3fSmrg                                 */
61201e04c3fSmrg                                level_width = align(level_width,
61301e04c3fSmrg                                                    4 * uif_block_w);
61401e04c3fSmrg                                level_height = align(level_height,
61501e04c3fSmrg                                                     uif_block_h);
61601e04c3fSmrg
61701e04c3fSmrg                                slice->ub_pad = v3d_get_ub_pad(rsc,
61801e04c3fSmrg                                                               level_height);
61901e04c3fSmrg                                level_height += slice->ub_pad * uif_block_h;
62001e04c3fSmrg
62101e04c3fSmrg                                /* If the padding set us to to be aligned to
62201e04c3fSmrg                                 * the page cache size, then the HW will use
62301e04c3fSmrg                                 * the XOR bit on odd columns to get us
62401e04c3fSmrg                                 * perfectly misaligned
62501e04c3fSmrg                                 */
62601e04c3fSmrg                                if ((level_height / uif_block_h) %
6277ec681f3Smrg                                    (V3D_PAGE_CACHE_SIZE /
6287ec681f3Smrg                                     V3D_UIFBLOCK_ROW_SIZE) == 0) {
6297ec681f3Smrg                                        slice->tiling = V3D_TILING_UIF_XOR;
63001e04c3fSmrg                                } else {
6317ec681f3Smrg                                        slice->tiling = V3D_TILING_UIF_NO_XOR;
63201e04c3fSmrg                                }
63301e04c3fSmrg                        }
63401e04c3fSmrg                }
63501e04c3fSmrg
63601e04c3fSmrg                slice->offset = offset;
6379f464c52Smaya                if (winsys_stride)
6389f464c52Smaya                        slice->stride = winsys_stride;
6399f464c52Smaya                else
6409f464c52Smaya                        slice->stride = level_width * rsc->cpp;
64101e04c3fSmrg                slice->padded_height = level_height;
64201e04c3fSmrg                slice->size = level_height * slice->stride;
64301e04c3fSmrg
64401e04c3fSmrg                uint32_t slice_total_size = slice->size * level_depth;
64501e04c3fSmrg
64601e04c3fSmrg                /* The HW aligns level 1's base to a page if any of level 1 or
64701e04c3fSmrg                 * below could be UIF XOR.  The lower levels then inherit the
6487ec681f3Smrg                 * alignment for as long as necessary, thanks to being power of
64901e04c3fSmrg                 * two aligned.
65001e04c3fSmrg                 */
65101e04c3fSmrg                if (i == 1 &&
65201e04c3fSmrg                    level_width > 4 * uif_block_w &&
65301e04c3fSmrg                    level_height > PAGE_CACHE_MINUS_1_5_UB_ROWS * uif_block_h) {
65401e04c3fSmrg                        slice_total_size = align(slice_total_size,
6557ec681f3Smrg                                                 V3D_UIFCFG_PAGE_SIZE);
65601e04c3fSmrg                }
65701e04c3fSmrg
65801e04c3fSmrg                offset += slice_total_size;
65901e04c3fSmrg
66001e04c3fSmrg        }
66101e04c3fSmrg        rsc->size = offset;
66201e04c3fSmrg
66301e04c3fSmrg        /* UIF/UBLINEAR levels need to be aligned to UIF-blocks, and LT only
66401e04c3fSmrg         * needs to be aligned to utile boundaries.  Since tiles are laid out
66501e04c3fSmrg         * from small to big in memory, we need to align the later UIF slices
66601e04c3fSmrg         * to UIF blocks, if they were preceded by non-UIF-block-aligned LT
66701e04c3fSmrg         * slices.
66801e04c3fSmrg         *
66901e04c3fSmrg         * We additionally align to 4k, which improves UIF XOR performance.
67001e04c3fSmrg         */
67101e04c3fSmrg        uint32_t page_align_offset = (align(rsc->slices[0].offset, 4096) -
67201e04c3fSmrg                                      rsc->slices[0].offset);
67301e04c3fSmrg        if (page_align_offset) {
67401e04c3fSmrg                rsc->size += page_align_offset;
67501e04c3fSmrg                for (int i = 0; i <= prsc->last_level; i++)
67601e04c3fSmrg                        rsc->slices[i].offset += page_align_offset;
67701e04c3fSmrg        }
67801e04c3fSmrg
67901e04c3fSmrg        /* Arrays and cube textures have a stride which is the distance from
68001e04c3fSmrg         * one full mipmap tree to the next (64b aligned).  For 3D textures,
68101e04c3fSmrg         * we need to program the stride between slices of miplevel 0.
68201e04c3fSmrg         */
68301e04c3fSmrg        if (prsc->target != PIPE_TEXTURE_3D) {
68401e04c3fSmrg                rsc->cube_map_stride = align(rsc->slices[0].offset +
68501e04c3fSmrg                                             rsc->slices[0].size, 64);
68601e04c3fSmrg                rsc->size += rsc->cube_map_stride * (prsc->array_size - 1);
68701e04c3fSmrg        } else {
68801e04c3fSmrg                rsc->cube_map_stride = rsc->slices[0].size;
68901e04c3fSmrg        }
69001e04c3fSmrg}
69101e04c3fSmrg
69201e04c3fSmrguint32_t
69301e04c3fSmrgv3d_layer_offset(struct pipe_resource *prsc, uint32_t level, uint32_t layer)
69401e04c3fSmrg{
69501e04c3fSmrg        struct v3d_resource *rsc = v3d_resource(prsc);
69601e04c3fSmrg        struct v3d_resource_slice *slice = &rsc->slices[level];
69701e04c3fSmrg
69801e04c3fSmrg        if (prsc->target == PIPE_TEXTURE_3D)
69901e04c3fSmrg                return slice->offset + layer * slice->size;
70001e04c3fSmrg        else
70101e04c3fSmrg                return slice->offset + layer * rsc->cube_map_stride;
70201e04c3fSmrg}
70301e04c3fSmrg
70401e04c3fSmrgstatic struct v3d_resource *
70501e04c3fSmrgv3d_resource_setup(struct pipe_screen *pscreen,
70601e04c3fSmrg                   const struct pipe_resource *tmpl)
70701e04c3fSmrg{
70801e04c3fSmrg        struct v3d_screen *screen = v3d_screen(pscreen);
70901e04c3fSmrg        struct v3d_resource *rsc = CALLOC_STRUCT(v3d_resource);
71001e04c3fSmrg        if (!rsc)
71101e04c3fSmrg                return NULL;
71201e04c3fSmrg        struct pipe_resource *prsc = &rsc->base;
71301e04c3fSmrg
71401e04c3fSmrg        *prsc = *tmpl;
71501e04c3fSmrg
71601e04c3fSmrg        pipe_reference_init(&prsc->reference, 1);
71701e04c3fSmrg        prsc->screen = pscreen;
71801e04c3fSmrg
71901e04c3fSmrg        if (prsc->nr_samples <= 1 ||
72001e04c3fSmrg            screen->devinfo.ver >= 40 ||
72101e04c3fSmrg            util_format_is_depth_or_stencil(prsc->format)) {
72201e04c3fSmrg                rsc->cpp = util_format_get_blocksize(prsc->format);
72301e04c3fSmrg                if (screen->devinfo.ver < 40 && prsc->nr_samples > 1)
72401e04c3fSmrg                        rsc->cpp *= prsc->nr_samples;
72501e04c3fSmrg        } else {
72601e04c3fSmrg                assert(v3d_rt_format_supported(&screen->devinfo, prsc->format));
72701e04c3fSmrg                uint32_t output_image_format =
72801e04c3fSmrg                        v3d_get_rt_format(&screen->devinfo, prsc->format);
72901e04c3fSmrg                uint32_t internal_type;
73001e04c3fSmrg                uint32_t internal_bpp;
73101e04c3fSmrg                v3d_get_internal_type_bpp_for_output_format(&screen->devinfo,
73201e04c3fSmrg                                                            output_image_format,
73301e04c3fSmrg                                                            &internal_type,
73401e04c3fSmrg                                                            &internal_bpp);
73501e04c3fSmrg                switch (internal_bpp) {
73601e04c3fSmrg                case V3D_INTERNAL_BPP_32:
73701e04c3fSmrg                        rsc->cpp = 4;
73801e04c3fSmrg                        break;
73901e04c3fSmrg                case V3D_INTERNAL_BPP_64:
74001e04c3fSmrg                        rsc->cpp = 8;
74101e04c3fSmrg                        break;
74201e04c3fSmrg                case V3D_INTERNAL_BPP_128:
74301e04c3fSmrg                        rsc->cpp = 16;
74401e04c3fSmrg                        break;
74501e04c3fSmrg                }
74601e04c3fSmrg        }
74701e04c3fSmrg
74801e04c3fSmrg        assert(rsc->cpp);
74901e04c3fSmrg
75001e04c3fSmrg        return rsc;
75101e04c3fSmrg}
75201e04c3fSmrg
75301e04c3fSmrgstatic struct pipe_resource *
75401e04c3fSmrgv3d_resource_create_with_modifiers(struct pipe_screen *pscreen,
75501e04c3fSmrg                                   const struct pipe_resource *tmpl,
75601e04c3fSmrg                                   const uint64_t *modifiers,
75701e04c3fSmrg                                   int count)
75801e04c3fSmrg{
7599f464c52Smaya        struct v3d_screen *screen = v3d_screen(pscreen);
7609f464c52Smaya
7619f464c52Smaya        bool linear_ok = drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count);
76201e04c3fSmrg        struct v3d_resource *rsc = v3d_resource_setup(pscreen, tmpl);
76301e04c3fSmrg        struct pipe_resource *prsc = &rsc->base;
76401e04c3fSmrg        /* Use a tiled layout if we can, for better 3D performance. */
76501e04c3fSmrg        bool should_tile = true;
76601e04c3fSmrg
76701e04c3fSmrg        /* VBOs/PBOs are untiled (and 1 height). */
76801e04c3fSmrg        if (tmpl->target == PIPE_BUFFER)
76901e04c3fSmrg                should_tile = false;
77001e04c3fSmrg
77101e04c3fSmrg        /* Cursors are always linear, and the user can request linear as well.
77201e04c3fSmrg         */
77301e04c3fSmrg        if (tmpl->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR))
77401e04c3fSmrg                should_tile = false;
77501e04c3fSmrg
77601e04c3fSmrg        /* 1D and 1D_ARRAY textures are always raster-order. */
77701e04c3fSmrg        if (tmpl->target == PIPE_TEXTURE_1D ||
77801e04c3fSmrg            tmpl->target == PIPE_TEXTURE_1D_ARRAY)
77901e04c3fSmrg                should_tile = false;
78001e04c3fSmrg
78101e04c3fSmrg        /* Scanout BOs for simulator need to be linear for interaction with
78201e04c3fSmrg         * i965.
78301e04c3fSmrg         */
78401e04c3fSmrg        if (using_v3d_simulator &&
78501e04c3fSmrg            tmpl->bind & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT))
78601e04c3fSmrg                should_tile = false;
78701e04c3fSmrg
7889f464c52Smaya        /* If using the old-school SCANOUT flag, we don't know what the screen
7899f464c52Smaya         * might support other than linear. Just force linear.
7909f464c52Smaya         */
7919f464c52Smaya        if (tmpl->bind & PIPE_BIND_SCANOUT)
7929f464c52Smaya                should_tile = false;
7939f464c52Smaya
79401e04c3fSmrg        /* No user-specified modifier; determine our own. */
79501e04c3fSmrg        if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
79601e04c3fSmrg                linear_ok = true;
79701e04c3fSmrg                rsc->tiled = should_tile;
79801e04c3fSmrg        } else if (should_tile &&
7999f464c52Smaya                   drm_find_modifier(DRM_FORMAT_MOD_BROADCOM_UIF,
80001e04c3fSmrg                                 modifiers, count)) {
80101e04c3fSmrg                rsc->tiled = true;
80201e04c3fSmrg        } else if (linear_ok) {
80301e04c3fSmrg                rsc->tiled = false;
80401e04c3fSmrg        } else {
80501e04c3fSmrg                fprintf(stderr, "Unsupported modifier requested\n");
80601e04c3fSmrg                goto fail;
80701e04c3fSmrg        }
80801e04c3fSmrg
80901e04c3fSmrg        rsc->internal_format = prsc->format;
81001e04c3fSmrg
8119f464c52Smaya        v3d_setup_slices(rsc, 0, tmpl->bind & PIPE_BIND_SHARED);
8129f464c52Smaya
8139f464c52Smaya        /* If we're in a renderonly setup, use the other device to perform our
8149f464c52Smaya         * allocation and just import it to v3d.  The other device may be
8159f464c52Smaya         * using CMA, and V3D can import from CMA but doesn't do CMA
8169f464c52Smaya         * allocations on its own.
8179f464c52Smaya         *
8189f464c52Smaya         * We always allocate this way for SHARED, because get_handle will
8199f464c52Smaya         * need a resource on the display fd.
8209f464c52Smaya         */
8219f464c52Smaya        if (screen->ro && (tmpl->bind & (PIPE_BIND_SCANOUT |
8229f464c52Smaya                                         PIPE_BIND_SHARED))) {
8239f464c52Smaya                struct winsys_handle handle;
8249f464c52Smaya                struct pipe_resource scanout_tmpl = {
8259f464c52Smaya                        .target = prsc->target,
8269f464c52Smaya                        .format = PIPE_FORMAT_RGBA8888_UNORM,
8279f464c52Smaya                        .width0 = 1024, /* one page */
8289f464c52Smaya                        .height0 = align(rsc->size, 4096) / 4096,
8299f464c52Smaya                        .depth0 = 1,
8309f464c52Smaya                        .array_size = 1,
8319f464c52Smaya                };
8329f464c52Smaya
8339f464c52Smaya                rsc->scanout =
8349f464c52Smaya                        renderonly_scanout_for_resource(&scanout_tmpl,
8359f464c52Smaya                                                        screen->ro,
8369f464c52Smaya                                                        &handle);
8379f464c52Smaya
8389f464c52Smaya                if (!rsc->scanout) {
8399f464c52Smaya                        fprintf(stderr, "Failed to create scanout resource\n");
8407ec681f3Smrg                        goto fail;
8419f464c52Smaya                }
8429f464c52Smaya                assert(handle.type == WINSYS_HANDLE_TYPE_FD);
8439f464c52Smaya                rsc->bo = v3d_bo_open_dmabuf(screen, handle.handle);
8449f464c52Smaya                close(handle.handle);
8459f464c52Smaya
8469f464c52Smaya                if (!rsc->bo)
8479f464c52Smaya                        goto fail;
8489f464c52Smaya
8499f464c52Smaya                v3d_debug_resource_layout(rsc, "renderonly");
8509f464c52Smaya
8519f464c52Smaya                return prsc;
8529f464c52Smaya        } else {
8539f464c52Smaya                if (!v3d_resource_bo_alloc(rsc))
8549f464c52Smaya                        goto fail;
8559f464c52Smaya        }
85601e04c3fSmrg
85701e04c3fSmrg        return prsc;
85801e04c3fSmrgfail:
85901e04c3fSmrg        v3d_resource_destroy(pscreen, prsc);
86001e04c3fSmrg        return NULL;
86101e04c3fSmrg}
86201e04c3fSmrg
86301e04c3fSmrgstruct pipe_resource *
86401e04c3fSmrgv3d_resource_create(struct pipe_screen *pscreen,
86501e04c3fSmrg                    const struct pipe_resource *tmpl)
86601e04c3fSmrg{
86701e04c3fSmrg        const uint64_t mod = DRM_FORMAT_MOD_INVALID;
86801e04c3fSmrg        return v3d_resource_create_with_modifiers(pscreen, tmpl, &mod, 1);
86901e04c3fSmrg}
87001e04c3fSmrg
87101e04c3fSmrgstatic struct pipe_resource *
87201e04c3fSmrgv3d_resource_from_handle(struct pipe_screen *pscreen,
87301e04c3fSmrg                         const struct pipe_resource *tmpl,
87401e04c3fSmrg                         struct winsys_handle *whandle,
87501e04c3fSmrg                         unsigned usage)
87601e04c3fSmrg{
87701e04c3fSmrg        struct v3d_screen *screen = v3d_screen(pscreen);
87801e04c3fSmrg        struct v3d_resource *rsc = v3d_resource_setup(pscreen, tmpl);
87901e04c3fSmrg        struct pipe_resource *prsc = &rsc->base;
88001e04c3fSmrg        struct v3d_resource_slice *slice = &rsc->slices[0];
88101e04c3fSmrg
88201e04c3fSmrg        if (!rsc)
88301e04c3fSmrg                return NULL;
88401e04c3fSmrg
88501e04c3fSmrg        switch (whandle->modifier) {
88601e04c3fSmrg        case DRM_FORMAT_MOD_LINEAR:
88701e04c3fSmrg                rsc->tiled = false;
88801e04c3fSmrg                break;
88901e04c3fSmrg        case DRM_FORMAT_MOD_BROADCOM_UIF:
89001e04c3fSmrg                rsc->tiled = true;
89101e04c3fSmrg                break;
8929f464c52Smaya        case DRM_FORMAT_MOD_INVALID:
8939f464c52Smaya                rsc->tiled = screen->ro == NULL;
8949f464c52Smaya                break;
89501e04c3fSmrg        default:
8967ec681f3Smrg                switch(fourcc_mod_broadcom_mod(whandle->modifier)) {
8977ec681f3Smrg                case DRM_FORMAT_MOD_BROADCOM_SAND128:
8987ec681f3Smrg                        rsc->tiled = false;
8997ec681f3Smrg                        rsc->sand_col128_stride =
9007ec681f3Smrg                                fourcc_mod_broadcom_param(whandle->modifier);
9017ec681f3Smrg                        break;
9027ec681f3Smrg                default:
9037ec681f3Smrg                        fprintf(stderr,
9047ec681f3Smrg                                "Attempt to import unsupported modifier 0x%llx\n",
9057ec681f3Smrg                                (long long)whandle->modifier);
9067ec681f3Smrg                        goto fail;
9077ec681f3Smrg                }
90801e04c3fSmrg        }
90901e04c3fSmrg
91001e04c3fSmrg        switch (whandle->type) {
91101e04c3fSmrg        case WINSYS_HANDLE_TYPE_SHARED:
9129f464c52Smaya                rsc->bo = v3d_bo_open_name(screen, whandle->handle);
91301e04c3fSmrg                break;
91401e04c3fSmrg        case WINSYS_HANDLE_TYPE_FD:
9159f464c52Smaya                rsc->bo = v3d_bo_open_dmabuf(screen, whandle->handle);
91601e04c3fSmrg                break;
91701e04c3fSmrg        default:
91801e04c3fSmrg                fprintf(stderr,
91901e04c3fSmrg                        "Attempt to import unsupported handle type %d\n",
92001e04c3fSmrg                        whandle->type);
92101e04c3fSmrg                goto fail;
92201e04c3fSmrg        }
92301e04c3fSmrg
92401e04c3fSmrg        if (!rsc->bo)
92501e04c3fSmrg                goto fail;
92601e04c3fSmrg
92701e04c3fSmrg        rsc->internal_format = prsc->format;
92801e04c3fSmrg
9299f464c52Smaya        v3d_setup_slices(rsc, whandle->stride, true);
93001e04c3fSmrg        v3d_debug_resource_layout(rsc, "import");
93101e04c3fSmrg
9327ec681f3Smrg        if (whandle->offset != 0) {
9337ec681f3Smrg                if (rsc->tiled) {
9347ec681f3Smrg                        fprintf(stderr,
9357ec681f3Smrg                                "Attempt to import unsupported winsys offset %u\n",
9367ec681f3Smrg                                whandle->offset);
9377ec681f3Smrg                        goto fail;
9387ec681f3Smrg                }
9397ec681f3Smrg                rsc->slices[0].offset += whandle->offset;
9407ec681f3Smrg
9417ec681f3Smrg                if (rsc->slices[0].offset + rsc->slices[0].size >
9427ec681f3Smrg                    rsc->bo->size) {
9437ec681f3Smrg                        fprintf(stderr, "Attempt to import "
9447ec681f3Smrg                                "with overflowing offset (%d + %d > %d)\n",
9457ec681f3Smrg                                whandle->offset,
9467ec681f3Smrg                                rsc->slices[0].size,
9477ec681f3Smrg                                rsc->bo->size);
9487ec681f3Smrg                         goto fail;
9497ec681f3Smrg                 }
9507ec681f3Smrg        }
9517ec681f3Smrg
9529f464c52Smaya        if (screen->ro) {
9539f464c52Smaya                /* Make sure that renderonly has a handle to our buffer in the
9549f464c52Smaya                 * display's fd, so that a later renderonly_get_handle()
9559f464c52Smaya                 * returns correct handles or GEM names.
9569f464c52Smaya                 */
9579f464c52Smaya                rsc->scanout =
9589f464c52Smaya                        renderonly_create_gpu_import_for_resource(prsc,
9599f464c52Smaya                                                                  screen->ro,
9609f464c52Smaya                                                                  NULL);
9619f464c52Smaya        }
9629f464c52Smaya
9637ec681f3Smrg        if (rsc->tiled && whandle->stride != slice->stride) {
96401e04c3fSmrg                static bool warned = false;
96501e04c3fSmrg                if (!warned) {
96601e04c3fSmrg                        warned = true;
96701e04c3fSmrg                        fprintf(stderr,
96801e04c3fSmrg                                "Attempting to import %dx%d %s with "
96901e04c3fSmrg                                "unsupported stride %d instead of %d\n",
97001e04c3fSmrg                                prsc->width0, prsc->height0,
97101e04c3fSmrg                                util_format_short_name(prsc->format),
97201e04c3fSmrg                                whandle->stride,
97301e04c3fSmrg                                slice->stride);
97401e04c3fSmrg                }
97501e04c3fSmrg                goto fail;
9767ec681f3Smrg        } else if (!rsc->tiled) {
9777ec681f3Smrg                slice->stride = whandle->stride;
97801e04c3fSmrg        }
97901e04c3fSmrg
98001e04c3fSmrg        return prsc;
98101e04c3fSmrg
98201e04c3fSmrgfail:
98301e04c3fSmrg        v3d_resource_destroy(pscreen, prsc);
98401e04c3fSmrg        return NULL;
98501e04c3fSmrg}
98601e04c3fSmrg
9879f464c52Smayavoid
9889f464c52Smayav3d_update_shadow_texture(struct pipe_context *pctx,
9899f464c52Smaya                          struct pipe_sampler_view *pview)
9909f464c52Smaya{
9919f464c52Smaya        struct v3d_context *v3d = v3d_context(pctx);
9929f464c52Smaya        struct v3d_sampler_view *view = v3d_sampler_view(pview);
9939f464c52Smaya        struct v3d_resource *shadow = v3d_resource(view->texture);
9949f464c52Smaya        struct v3d_resource *orig = v3d_resource(pview->texture);
9959f464c52Smaya
9969f464c52Smaya        assert(view->texture != pview->texture);
9979f464c52Smaya
9989f464c52Smaya        if (shadow->writes == orig->writes && orig->bo->private)
9999f464c52Smaya                return;
10009f464c52Smaya
10019f464c52Smaya        perf_debug("Updating %dx%d@%d shadow for linear texture\n",
10029f464c52Smaya                   orig->base.width0, orig->base.height0,
10039f464c52Smaya                   pview->u.tex.first_level);
10049f464c52Smaya
10059f464c52Smaya        for (int i = 0; i <= shadow->base.last_level; i++) {
10069f464c52Smaya                unsigned width = u_minify(shadow->base.width0, i);
10079f464c52Smaya                unsigned height = u_minify(shadow->base.height0, i);
10089f464c52Smaya                struct pipe_blit_info info = {
10099f464c52Smaya                        .dst = {
10109f464c52Smaya                                .resource = &shadow->base,
10119f464c52Smaya                                .level = i,
10129f464c52Smaya                                .box = {
10139f464c52Smaya                                        .x = 0,
10149f464c52Smaya                                        .y = 0,
10159f464c52Smaya                                        .z = 0,
10169f464c52Smaya                                        .width = width,
10179f464c52Smaya                                        .height = height,
10189f464c52Smaya                                        .depth = 1,
10199f464c52Smaya                                },
10209f464c52Smaya                                .format = shadow->base.format,
10219f464c52Smaya                        },
10229f464c52Smaya                        .src = {
10239f464c52Smaya                                .resource = &orig->base,
10249f464c52Smaya                                .level = pview->u.tex.first_level + i,
10259f464c52Smaya                                .box = {
10269f464c52Smaya                                        .x = 0,
10279f464c52Smaya                                        .y = 0,
10289f464c52Smaya                                        .z = 0,
10299f464c52Smaya                                        .width = width,
10309f464c52Smaya                                        .height = height,
10319f464c52Smaya                                        .depth = 1,
10329f464c52Smaya                                },
10339f464c52Smaya                                .format = orig->base.format,
10349f464c52Smaya                        },
10359f464c52Smaya                        .mask = util_format_get_mask(orig->base.format),
10369f464c52Smaya                };
10379f464c52Smaya                pctx->blit(pctx, &info);
10389f464c52Smaya        }
10399f464c52Smaya
10409f464c52Smaya        shadow->writes = orig->writes;
10419f464c52Smaya}
10429f464c52Smaya
104301e04c3fSmrgstatic struct pipe_surface *
104401e04c3fSmrgv3d_create_surface(struct pipe_context *pctx,
104501e04c3fSmrg                   struct pipe_resource *ptex,
104601e04c3fSmrg                   const struct pipe_surface *surf_tmpl)
104701e04c3fSmrg{
104801e04c3fSmrg        struct v3d_context *v3d = v3d_context(pctx);
104901e04c3fSmrg        struct v3d_screen *screen = v3d->screen;
105001e04c3fSmrg        struct v3d_surface *surface = CALLOC_STRUCT(v3d_surface);
105101e04c3fSmrg        struct v3d_resource *rsc = v3d_resource(ptex);
105201e04c3fSmrg
105301e04c3fSmrg        if (!surface)
105401e04c3fSmrg                return NULL;
105501e04c3fSmrg
105601e04c3fSmrg        struct pipe_surface *psurf = &surface->base;
105701e04c3fSmrg        unsigned level = surf_tmpl->u.tex.level;
105801e04c3fSmrg        struct v3d_resource_slice *slice = &rsc->slices[level];
105901e04c3fSmrg
106001e04c3fSmrg        pipe_reference_init(&psurf->reference, 1);
106101e04c3fSmrg        pipe_resource_reference(&psurf->texture, ptex);
106201e04c3fSmrg
106301e04c3fSmrg        psurf->context = pctx;
106401e04c3fSmrg        psurf->format = surf_tmpl->format;
106501e04c3fSmrg        psurf->width = u_minify(ptex->width0, level);
106601e04c3fSmrg        psurf->height = u_minify(ptex->height0, level);
106701e04c3fSmrg        psurf->u.tex.level = level;
106801e04c3fSmrg        psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
106901e04c3fSmrg        psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
107001e04c3fSmrg
107101e04c3fSmrg        surface->offset = v3d_layer_offset(ptex, level,
107201e04c3fSmrg                                           psurf->u.tex.first_layer);
107301e04c3fSmrg        surface->tiling = slice->tiling;
107401e04c3fSmrg
107501e04c3fSmrg        surface->format = v3d_get_rt_format(&screen->devinfo, psurf->format);
107601e04c3fSmrg
10779f464c52Smaya        const struct util_format_description *desc =
10789f464c52Smaya                util_format_description(psurf->format);
10799f464c52Smaya
10809f464c52Smaya        surface->swap_rb = (desc->swizzle[0] == PIPE_SWIZZLE_Z &&
10819f464c52Smaya                            psurf->format != PIPE_FORMAT_B5G6R5_UNORM);
10829f464c52Smaya
108301e04c3fSmrg        if (util_format_is_depth_or_stencil(psurf->format)) {
108401e04c3fSmrg                switch (psurf->format) {
108501e04c3fSmrg                case PIPE_FORMAT_Z16_UNORM:
108601e04c3fSmrg                        surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_16;
108701e04c3fSmrg                        break;
108801e04c3fSmrg                case PIPE_FORMAT_Z32_FLOAT:
108901e04c3fSmrg                case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
109001e04c3fSmrg                        surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_32F;
109101e04c3fSmrg                        break;
109201e04c3fSmrg                default:
109301e04c3fSmrg                        surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_24;
109401e04c3fSmrg                }
109501e04c3fSmrg        } else {
109601e04c3fSmrg                uint32_t bpp, type;
109701e04c3fSmrg                v3d_get_internal_type_bpp_for_output_format(&screen->devinfo,
109801e04c3fSmrg                                                            surface->format,
109901e04c3fSmrg                                                            &type, &bpp);
110001e04c3fSmrg                surface->internal_type = type;
110101e04c3fSmrg                surface->internal_bpp = bpp;
110201e04c3fSmrg        }
110301e04c3fSmrg
11047ec681f3Smrg        if (surface->tiling == V3D_TILING_UIF_NO_XOR ||
11057ec681f3Smrg            surface->tiling == V3D_TILING_UIF_XOR) {
110601e04c3fSmrg                surface->padded_height_of_output_image_in_uif_blocks =
110701e04c3fSmrg                        (slice->padded_height /
110801e04c3fSmrg                         (2 * v3d_utile_height(rsc->cpp)));
110901e04c3fSmrg        }
111001e04c3fSmrg
111101e04c3fSmrg        if (rsc->separate_stencil) {
111201e04c3fSmrg                surface->separate_stencil =
111301e04c3fSmrg                        v3d_create_surface(pctx, &rsc->separate_stencil->base,
111401e04c3fSmrg                                           surf_tmpl);
111501e04c3fSmrg        }
111601e04c3fSmrg
111701e04c3fSmrg        return &surface->base;
111801e04c3fSmrg}
111901e04c3fSmrg
112001e04c3fSmrgstatic void
112101e04c3fSmrgv3d_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
112201e04c3fSmrg{
112301e04c3fSmrg        struct v3d_surface *surf = v3d_surface(psurf);
112401e04c3fSmrg
112501e04c3fSmrg        if (surf->separate_stencil)
112601e04c3fSmrg                pipe_surface_reference(&surf->separate_stencil, NULL);
112701e04c3fSmrg
112801e04c3fSmrg        pipe_resource_reference(&psurf->texture, NULL);
112901e04c3fSmrg        FREE(psurf);
113001e04c3fSmrg}
113101e04c3fSmrg
113201e04c3fSmrgstatic void
113301e04c3fSmrgv3d_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
113401e04c3fSmrg{
113501e04c3fSmrg        /* All calls to flush_resource are followed by a flush of the context,
113601e04c3fSmrg         * so there's nothing to do.
113701e04c3fSmrg         */
113801e04c3fSmrg}
113901e04c3fSmrg
114001e04c3fSmrgstatic enum pipe_format
114101e04c3fSmrgv3d_resource_get_internal_format(struct pipe_resource *prsc)
114201e04c3fSmrg{
114301e04c3fSmrg        return v3d_resource(prsc)->internal_format;
114401e04c3fSmrg}
114501e04c3fSmrg
114601e04c3fSmrgstatic void
114701e04c3fSmrgv3d_resource_set_stencil(struct pipe_resource *prsc,
114801e04c3fSmrg                         struct pipe_resource *stencil)
114901e04c3fSmrg{
115001e04c3fSmrg        v3d_resource(prsc)->separate_stencil = v3d_resource(stencil);
115101e04c3fSmrg}
115201e04c3fSmrg
115301e04c3fSmrgstatic struct pipe_resource *
115401e04c3fSmrgv3d_resource_get_stencil(struct pipe_resource *prsc)
115501e04c3fSmrg{
115601e04c3fSmrg        struct v3d_resource *rsc = v3d_resource(prsc);
115701e04c3fSmrg
115801e04c3fSmrg        return &rsc->separate_stencil->base;
115901e04c3fSmrg}
116001e04c3fSmrg
116101e04c3fSmrgstatic const struct u_transfer_vtbl transfer_vtbl = {
116201e04c3fSmrg        .resource_create          = v3d_resource_create,
116301e04c3fSmrg        .resource_destroy         = v3d_resource_destroy,
116401e04c3fSmrg        .transfer_map             = v3d_resource_transfer_map,
116501e04c3fSmrg        .transfer_unmap           = v3d_resource_transfer_unmap,
116601e04c3fSmrg        .transfer_flush_region    = u_default_transfer_flush_region,
116701e04c3fSmrg        .get_internal_format      = v3d_resource_get_internal_format,
116801e04c3fSmrg        .set_stencil              = v3d_resource_set_stencil,
116901e04c3fSmrg        .get_stencil              = v3d_resource_get_stencil,
117001e04c3fSmrg};
117101e04c3fSmrg
117201e04c3fSmrgvoid
117301e04c3fSmrgv3d_resource_screen_init(struct pipe_screen *pscreen)
117401e04c3fSmrg{
117501e04c3fSmrg        pscreen->resource_create_with_modifiers =
117601e04c3fSmrg                v3d_resource_create_with_modifiers;
117701e04c3fSmrg        pscreen->resource_create = u_transfer_helper_resource_create;
117801e04c3fSmrg        pscreen->resource_from_handle = v3d_resource_from_handle;
117901e04c3fSmrg        pscreen->resource_get_handle = v3d_resource_get_handle;
11807ec681f3Smrg        pscreen->resource_get_param = v3d_resource_get_param;
118101e04c3fSmrg        pscreen->resource_destroy = u_transfer_helper_resource_destroy;
118201e04c3fSmrg        pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl,
118301e04c3fSmrg                                                            true, false,
118401e04c3fSmrg                                                            true, true);
118501e04c3fSmrg}
118601e04c3fSmrg
118701e04c3fSmrgvoid
118801e04c3fSmrgv3d_resource_context_init(struct pipe_context *pctx)
118901e04c3fSmrg{
11907ec681f3Smrg        pctx->buffer_map = u_transfer_helper_transfer_map;
11917ec681f3Smrg        pctx->texture_map = u_transfer_helper_transfer_map;
119201e04c3fSmrg        pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;
11937ec681f3Smrg        pctx->buffer_unmap = u_transfer_helper_transfer_unmap;
11947ec681f3Smrg        pctx->texture_unmap = u_transfer_helper_transfer_unmap;
119501e04c3fSmrg        pctx->buffer_subdata = u_default_buffer_subdata;
11969f464c52Smaya        pctx->texture_subdata = v3d_texture_subdata;
119701e04c3fSmrg        pctx->create_surface = v3d_create_surface;
119801e04c3fSmrg        pctx->surface_destroy = v3d_surface_destroy;
119901e04c3fSmrg        pctx->resource_copy_region = util_resource_copy_region;
120001e04c3fSmrg        pctx->blit = v3d_blit;
12019f464c52Smaya        pctx->generate_mipmap = v3d_generate_mipmap;
120201e04c3fSmrg        pctx->flush_resource = v3d_flush_resource;
120301e04c3fSmrg}
1204