Home | History | Annotate | Download | only in etnaviv
      1 /*
      2  * Copyright (c) 2012-2015 Etnaviv Project
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sub license,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the
     12  * next paragraph) shall be included in all copies or substantial portions
     13  * of the Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21  * DEALINGS IN THE SOFTWARE.
     22  *
     23  * Authors:
     24  *    Wladimir J. van der Laan <laanwj (at) gmail.com>
     25  */
     26 
     27 #include "etnaviv_resource.h"
     28 
     29 #include "hw/common.xml.h"
     30 
     31 #include "etnaviv_context.h"
     32 #include "etnaviv_debug.h"
     33 #include "etnaviv_screen.h"
     34 #include "etnaviv_translate.h"
     35 
     36 #include "util/u_inlines.h"
     37 #include "util/u_memory.h"
     38 
     39 #include <drm_fourcc.h>
     40 
     41 #ifndef DRM_FORMAT_MOD_INVALID
     42 #define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
     43 #endif
     44 
     45 static enum etna_surface_layout modifier_to_layout(uint64_t modifier)
     46 {
     47    switch (modifier) {
     48    case DRM_FORMAT_MOD_VIVANTE_TILED:
     49       return ETNA_LAYOUT_TILED;
     50    case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
     51       return ETNA_LAYOUT_SUPER_TILED;
     52    case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
     53       return ETNA_LAYOUT_MULTI_TILED;
     54    case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
     55       return ETNA_LAYOUT_MULTI_SUPERTILED;
     56    case DRM_FORMAT_MOD_LINEAR:
     57    default:
     58       return ETNA_LAYOUT_LINEAR;
     59    }
     60 }
     61 
     62 static uint64_t layout_to_modifier(enum etna_surface_layout layout)
     63 {
     64    switch (layout) {
     65    case ETNA_LAYOUT_TILED:
     66       return DRM_FORMAT_MOD_VIVANTE_TILED;
     67    case ETNA_LAYOUT_SUPER_TILED:
     68       return DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
     69    case ETNA_LAYOUT_MULTI_TILED:
     70       return DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED;
     71    case ETNA_LAYOUT_MULTI_SUPERTILED:
     72       return DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED;
     73    case ETNA_LAYOUT_LINEAR:
     74       return DRM_FORMAT_MOD_LINEAR;
     75    default:
     76       return DRM_FORMAT_MOD_INVALID;
     77    }
     78 }
     79 
     80 /* A tile is 4x4 pixels, having 'screen->specs.bits_per_tile' of tile status.
     81  * So, in a buffer of N pixels, there are N / (4 * 4) tiles.
     82  * We need N * screen->specs.bits_per_tile / (4 * 4) bits of tile status, or
     83  * N * screen->specs.bits_per_tile / (4 * 4 * 8) bytes.
     84  */
     85 bool
     86 etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
     87                               struct etna_resource *rsc)
     88 {
     89    struct etna_screen *screen = etna_screen(pscreen);
     90    size_t rt_ts_size, ts_layer_stride, pixels;
     91 
     92    assert(!rsc->ts_bo);
     93 
     94    /* TS only for level 0 -- XXX is this formula correct? */
     95    pixels = rsc->levels[0].layer_stride / util_format_get_blocksize(rsc->base.format);
     96    ts_layer_stride = align(pixels * screen->specs.bits_per_tile / 0x80,
     97                            0x100 * screen->specs.pixel_pipes);
     98    rt_ts_size = ts_layer_stride * rsc->base.array_size;
     99    if (rt_ts_size == 0)
    100       return true;
    101 
    102    DBG_F(ETNA_DBG_RESOURCE_MSGS, "%p: Allocating tile status of size %zu",
    103          rsc, rt_ts_size);
    104 
    105    struct etna_bo *rt_ts;
    106    rt_ts = etna_bo_new(screen->dev, rt_ts_size, DRM_ETNA_GEM_CACHE_WC);
    107 
    108    if (unlikely(!rt_ts)) {
    109       BUG("Problem allocating tile status for resource");
    110       return false;
    111    }
    112 
    113    rsc->ts_bo = rt_ts;
    114    rsc->levels[0].ts_offset = 0;
    115    rsc->levels[0].ts_layer_stride = ts_layer_stride;
    116    rsc->levels[0].ts_size = rt_ts_size;
    117 
    118    /* It is important to initialize the TS, as random pattern
    119     * can result in crashes. Do this on the CPU as this only happens once
    120     * per surface anyway and it's a small area, so it may not be worth
    121     * queuing this to the GPU. */
    122    void *ts_map = etna_bo_map(rt_ts);
    123    memset(ts_map, screen->specs.ts_clear_value, rt_ts_size);
    124 
    125    return true;
    126 }
    127 
    128 static boolean
    129 etna_screen_can_create_resource(struct pipe_screen *pscreen,
    130                                 const struct pipe_resource *templat)
    131 {
    132    struct etna_screen *screen = etna_screen(pscreen);
    133    if (!translate_samples_to_xyscale(templat->nr_samples, NULL, NULL, NULL))
    134       return false;
    135 
    136    /* templat->bind is not set here, so we must use the minimum sizes */
    137    uint max_size =
    138       MIN2(screen->specs.max_rendertarget_size, screen->specs.max_texture_size);
    139 
    140    if (templat->width0 > max_size || templat->height0 > max_size)
    141       return false;
    142 
    143    return true;
    144 }
    145 
    146 static unsigned
    147 setup_miptree(struct etna_resource *rsc, unsigned paddingX, unsigned paddingY,
    148               unsigned msaa_xscale, unsigned msaa_yscale)
    149 {
    150    struct pipe_resource *prsc = &rsc->base;
    151    unsigned level, size = 0;
    152    unsigned width = prsc->width0;
    153    unsigned height = prsc->height0;
    154    unsigned depth = prsc->depth0;
    155 
    156    for (level = 0; level <= prsc->last_level; level++) {
    157       struct etna_resource_level *mip = &rsc->levels[level];
    158 
    159       mip->width = width;
    160       mip->height = height;
    161       mip->padded_width = align(width * msaa_xscale, paddingX);
    162       mip->padded_height = align(height * msaa_yscale, paddingY);
    163       mip->stride = util_format_get_stride(prsc->format, mip->padded_width);
    164       mip->offset = size;
    165       mip->layer_stride = mip->stride * util_format_get_nblocksy(prsc->format, mip->padded_height);
    166       mip->size = prsc->array_size * mip->layer_stride;
    167 
    168       /* align levels to 64 bytes to be able to render to them */
    169       size += align(mip->size, ETNA_PE_ALIGNMENT) * depth;
    170 
    171       width = u_minify(width, 1);
    172       height = u_minify(height, 1);
    173       depth = u_minify(depth, 1);
    174    }
    175 
    176    return size;
    177 }
    178 
    179 /* Create a new resource object, using the given template info */
    180 struct pipe_resource *
    181 etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
    182                     uint64_t modifier, const struct pipe_resource *templat)
    183 {
    184    struct etna_screen *screen = etna_screen(pscreen);
    185    struct etna_resource *rsc;
    186    unsigned size;
    187 
    188    DBG_F(ETNA_DBG_RESOURCE_MSGS,
    189          "target=%d, format=%s, %ux%ux%u, array_size=%u, "
    190          "last_level=%u, nr_samples=%u, usage=%u, bind=%x, flags=%x",
    191          templat->target, util_format_name(templat->format), templat->width0,
    192          templat->height0, templat->depth0, templat->array_size,
    193          templat->last_level, templat->nr_samples, templat->usage,
    194          templat->bind, templat->flags);
    195 
    196    /* Determine scaling for antialiasing, allow override using debug flag */
    197    int nr_samples = templat->nr_samples;
    198    if ((templat->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL)) &&
    199        !(templat->bind & PIPE_BIND_SAMPLER_VIEW)) {
    200       if (DBG_ENABLED(ETNA_DBG_MSAA_2X))
    201          nr_samples = 2;
    202       if (DBG_ENABLED(ETNA_DBG_MSAA_4X))
    203          nr_samples = 4;
    204    }
    205 
    206    int msaa_xscale = 1, msaa_yscale = 1;
    207    if (!translate_samples_to_xyscale(nr_samples, &msaa_xscale, &msaa_yscale, NULL)) {
    208       /* Number of samples not supported */
    209       return NULL;
    210    }
    211 
    212    /* Determine needed padding (alignment of height/width) */
    213    unsigned paddingX = 0, paddingY = 0;
    214    unsigned halign = TEXTURE_HALIGN_FOUR;
    215    if (!util_format_is_compressed(templat->format)) {
    216       /* If we have the TEXTURE_HALIGN feature, we can always align to the
    217        * resolve engine's width.  If not, we must not align resources used
    218        * only for textures. If this GPU uses the BLT engine, never do RS align.
    219        */
    220       bool rs_align = screen->specs.use_blt ? false : (
    221                          VIV_FEATURE(screen, chipMinorFeatures1, TEXTURE_HALIGN) ||
    222                          !etna_resource_sampler_only(templat));
    223       etna_layout_multiple(layout, screen->specs.pixel_pipes, rs_align, &paddingX,
    224                            &paddingY, &halign);
    225       assert(paddingX && paddingY);
    226    } else {
    227       /* Compressed textures are padded to their block size, but we don't have
    228        * to do anything special for that. */
    229       paddingX = 1;
    230       paddingY = 1;
    231    }
    232 
    233    if (!screen->specs.use_blt && templat->target != PIPE_BUFFER)
    234       etna_adjust_rs_align(screen->specs.pixel_pipes, NULL, &paddingY);
    235 
    236    if (templat->bind & PIPE_BIND_SCANOUT) {
    237       struct pipe_resource scanout_templat = *templat;
    238       struct renderonly_scanout *scanout;
    239       struct winsys_handle handle;
    240 
    241       /* pad scanout buffer size to be compatible with the RS */
    242       if (!screen->specs.use_blt && modifier == DRM_FORMAT_MOD_LINEAR)
    243          etna_adjust_rs_align(screen->specs.pixel_pipes, &paddingX, &paddingY);
    244 
    245       scanout_templat.width0 = align(scanout_templat.width0, paddingX);
    246       scanout_templat.height0 = align(scanout_templat.height0, paddingY);
    247 
    248       scanout = renderonly_scanout_for_resource(&scanout_templat,
    249                                                 screen->ro, &handle);
    250       if (!scanout)
    251          return NULL;
    252 
    253       assert(handle.type == DRM_API_HANDLE_TYPE_FD);
    254       handle.modifier = modifier;
    255       rsc = etna_resource(pscreen->resource_from_handle(pscreen, templat,
    256                                                         &handle,
    257                                                         PIPE_HANDLE_USAGE_WRITE));
    258       close(handle.handle);
    259       if (!rsc)
    260          return NULL;
    261 
    262       rsc->scanout = scanout;
    263 
    264       return &rsc->base;
    265    }
    266 
    267    rsc = CALLOC_STRUCT(etna_resource);
    268    if (!rsc)
    269       return NULL;
    270 
    271    rsc->base = *templat;
    272    rsc->base.screen = pscreen;
    273    rsc->base.nr_samples = nr_samples;
    274    rsc->layout = layout;
    275    rsc->halign = halign;
    276 
    277    pipe_reference_init(&rsc->base.reference, 1);
    278    list_inithead(&rsc->list);
    279 
    280    size = setup_miptree(rsc, paddingX, paddingY, msaa_xscale, msaa_yscale);
    281 
    282    uint32_t flags = DRM_ETNA_GEM_CACHE_WC;
    283    if (templat->bind & PIPE_BIND_VERTEX_BUFFER)
    284       flags |= DRM_ETNA_GEM_FORCE_MMU;
    285    struct etna_bo *bo = etna_bo_new(screen->dev, size, flags);
    286    if (unlikely(bo == NULL)) {
    287       BUG("Problem allocating video memory for resource");
    288       goto free_rsc;
    289    }
    290 
    291    rsc->bo = bo;
    292    rsc->ts_bo = 0; /* TS is only created when first bound to surface */
    293 
    294    if (DBG_ENABLED(ETNA_DBG_ZERO)) {
    295       void *map = etna_bo_map(bo);
    296       memset(map, 0, size);
    297    }
    298 
    299    return &rsc->base;
    300 
    301 free_rsc:
    302    FREE(rsc);
    303    return NULL;
    304 }
    305 
    306 static struct pipe_resource *
    307 etna_resource_create(struct pipe_screen *pscreen,
    308                      const struct pipe_resource *templat)
    309 {
    310    struct etna_screen *screen = etna_screen(pscreen);
    311 
    312    /* Figure out what tiling to use -- for now, assume that texture cannot be linear.
    313     * there is a capability LINEAR_TEXTURE_SUPPORT (supported on gc880 and
    314     * gc2000 at least), but not sure how it works.
    315     * Buffers always have LINEAR layout.
    316     */
    317    unsigned layout = ETNA_LAYOUT_LINEAR;
    318    if (etna_resource_sampler_only(templat)) {
    319       /* The buffer is only used for texturing, so create something
    320        * directly compatible with the sampler.  Such a buffer can
    321        * never be rendered to. */
    322       layout = ETNA_LAYOUT_TILED;
    323 
    324       if (util_format_is_compressed(templat->format))
    325          layout = ETNA_LAYOUT_LINEAR;
    326    } else if (templat->target != PIPE_BUFFER) {
    327       bool want_multitiled = false;
    328       bool want_supertiled = screen->specs.can_supertile;
    329 
    330       /* When this GPU supports single-buffer rendering, don't ever enable
    331        * multi-tiling. This replicates the blob behavior on GC3000.
    332        */
    333       if (!screen->specs.single_buffer)
    334          want_multitiled = screen->specs.pixel_pipes > 1;
    335 
    336       /* Keep single byte blocksized resources as tiled, since we
    337        * are unable to use the RS blit to de-tile them. However,
    338        * if they're used as a render target or depth/stencil, they
    339        * must be multi-tiled for GPUs with multiple pixel pipes.
    340        * Ignore depth/stencil here, but it is an error for a render
    341        * target.
    342        */
    343       if (util_format_get_blocksize(templat->format) == 1 &&
    344           !(templat->bind & PIPE_BIND_DEPTH_STENCIL)) {
    345          assert(!(templat->bind & PIPE_BIND_RENDER_TARGET && want_multitiled));
    346          want_multitiled = want_supertiled = false;
    347       }
    348 
    349       layout = ETNA_LAYOUT_BIT_TILE;
    350       if (want_multitiled)
    351          layout |= ETNA_LAYOUT_BIT_MULTI;
    352       if (want_supertiled)
    353          layout |= ETNA_LAYOUT_BIT_SUPER;
    354    }
    355 
    356    if (templat->target == PIPE_TEXTURE_3D)
    357       layout = ETNA_LAYOUT_LINEAR;
    358 
    359    /* modifier is only used for scanout surfaces, so safe to use LINEAR here */
    360    return etna_resource_alloc(pscreen, layout, DRM_FORMAT_MOD_LINEAR, templat);
    361 }
    362 
    363 enum modifier_priority {
    364    MODIFIER_PRIORITY_INVALID = 0,
    365    MODIFIER_PRIORITY_LINEAR,
    366    MODIFIER_PRIORITY_SPLIT_TILED,
    367    MODIFIER_PRIORITY_SPLIT_SUPER_TILED,
    368    MODIFIER_PRIORITY_TILED,
    369    MODIFIER_PRIORITY_SUPER_TILED,
    370 };
    371 
    372 const uint64_t priority_to_modifier[] = {
    373    [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID,
    374    [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR,
    375    [MODIFIER_PRIORITY_SPLIT_TILED] = DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED,
    376    [MODIFIER_PRIORITY_SPLIT_SUPER_TILED] = DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED,
    377    [MODIFIER_PRIORITY_TILED] = DRM_FORMAT_MOD_VIVANTE_TILED,
    378    [MODIFIER_PRIORITY_SUPER_TILED] = DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
    379 };
    380 
    381 static uint64_t
    382 select_best_modifier(const struct etna_screen * screen,
    383                      const uint64_t *modifiers, const unsigned count)
    384 {
    385    enum modifier_priority prio = MODIFIER_PRIORITY_INVALID;
    386 
    387    for (int i = 0; i < count; i++) {
    388       switch (modifiers[i]) {
    389       case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
    390          if ((screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer) ||
    391              !screen->specs.can_supertile)
    392             break;
    393          prio = MAX2(prio, MODIFIER_PRIORITY_SUPER_TILED);
    394          break;
    395       case DRM_FORMAT_MOD_VIVANTE_TILED:
    396          if (screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer)
    397             break;
    398          prio = MAX2(prio, MODIFIER_PRIORITY_TILED);
    399          break;
    400       case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
    401          if ((screen->specs.pixel_pipes < 2) || !screen->specs.can_supertile)
    402             break;
    403          prio = MAX2(prio, MODIFIER_PRIORITY_SPLIT_SUPER_TILED);
    404          break;
    405       case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
    406          if (screen->specs.pixel_pipes < 2)
    407             break;
    408          prio = MAX2(prio, MODIFIER_PRIORITY_SPLIT_TILED);
    409          break;
    410       case DRM_FORMAT_MOD_LINEAR:
    411          prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR);
    412          break;
    413       case DRM_FORMAT_MOD_INVALID:
    414       default:
    415          break;
    416       }
    417    }
    418 
    419    return priority_to_modifier[prio];
    420 }
    421 
    422 static struct pipe_resource *
    423 etna_resource_create_modifiers(struct pipe_screen *pscreen,
    424                                const struct pipe_resource *templat,
    425                                const uint64_t *modifiers, int count)
    426 {
    427    struct etna_screen *screen = etna_screen(pscreen);
    428    struct pipe_resource tmpl = *templat;
    429    uint64_t modifier = select_best_modifier(screen, modifiers, count);
    430 
    431    if (modifier == DRM_FORMAT_MOD_INVALID)
    432       return NULL;
    433 
    434    /*
    435     * We currently assume that all buffers allocated through this interface
    436     * should be scanout enabled.
    437     */
    438    tmpl.bind |= PIPE_BIND_SCANOUT;
    439 
    440    return etna_resource_alloc(pscreen, modifier_to_layout(modifier),
    441                               modifier, &tmpl);
    442 }
    443 
    444 static void
    445 etna_resource_changed(struct pipe_screen *pscreen, struct pipe_resource *prsc)
    446 {
    447    struct etna_resource *res = etna_resource(prsc);
    448 
    449    if (res->external)
    450       etna_resource(res->external)->seqno++;
    451    else
    452       res->seqno++;
    453 }
    454 
    455 static void
    456 etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
    457 {
    458    struct etna_resource *rsc = etna_resource(prsc);
    459 
    460    if (rsc->bo)
    461       etna_bo_del(rsc->bo);
    462 
    463    if (rsc->ts_bo)
    464       etna_bo_del(rsc->ts_bo);
    465 
    466    if (rsc->scanout)
    467       renderonly_scanout_destroy(rsc->scanout, etna_screen(pscreen)->ro);
    468 
    469    list_delinit(&rsc->list);
    470 
    471    pipe_resource_reference(&rsc->texture, NULL);
    472    pipe_resource_reference(&rsc->external, NULL);
    473 
    474    FREE(rsc);
    475 }
    476 
    477 static struct pipe_resource *
    478 etna_resource_from_handle(struct pipe_screen *pscreen,
    479                           const struct pipe_resource *tmpl,
    480                           struct winsys_handle *handle, unsigned usage)
    481 {
    482    struct etna_screen *screen = etna_screen(pscreen);
    483    struct etna_resource *rsc;
    484    struct etna_resource_level *level;
    485    struct pipe_resource *prsc;
    486    struct pipe_resource *ptiled = NULL;
    487 
    488    DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, "
    489        "nr_samples=%u, usage=%u, bind=%x, flags=%x",
    490        tmpl->target, util_format_name(tmpl->format), tmpl->width0,
    491        tmpl->height0, tmpl->depth0, tmpl->array_size, tmpl->last_level,
    492        tmpl->nr_samples, tmpl->usage, tmpl->bind, tmpl->flags);
    493 
    494    rsc = CALLOC_STRUCT(etna_resource);
    495    if (!rsc)
    496       return NULL;
    497 
    498    level = &rsc->levels[0];
    499    prsc = &rsc->base;
    500 
    501    *prsc = *tmpl;
    502 
    503    pipe_reference_init(&prsc->reference, 1);
    504    list_inithead(&rsc->list);
    505    prsc->screen = pscreen;
    506 
    507    rsc->bo = etna_screen_bo_from_handle(pscreen, handle, &level->stride);
    508    if (!rsc->bo)
    509       goto fail;
    510 
    511    rsc->seqno = 1;
    512    rsc->layout = modifier_to_layout(handle->modifier);
    513    rsc->halign = TEXTURE_HALIGN_FOUR;
    514 
    515 
    516    level->width = tmpl->width0;
    517    level->height = tmpl->height0;
    518 
    519    /* Determine padding of the imported resource. */
    520    unsigned paddingX = 0, paddingY = 0;
    521    etna_layout_multiple(rsc->layout, screen->specs.pixel_pipes,
    522                         VIV_FEATURE(screen, chipMinorFeatures1, TEXTURE_HALIGN),
    523                         &paddingX, &paddingY, &rsc->halign);
    524 
    525    if (!screen->specs.use_blt)
    526       etna_adjust_rs_align(screen->specs.pixel_pipes, NULL, &paddingY);
    527    level->padded_width = align(level->width, paddingX);
    528    level->padded_height = align(level->height, paddingY);
    529 
    530    level->layer_stride = level->stride * util_format_get_nblocksy(prsc->format,
    531                                                                   level->padded_height);
    532    level->size = level->layer_stride;
    533 
    534    /* The DDX must give us a BO which conforms to our padding size.
    535     * The stride of the BO must be greater or equal to our padded
    536     * stride. The size of the BO must accomodate the padded height. */
    537    if (level->stride < util_format_get_stride(tmpl->format, level->padded_width)) {
    538       BUG("BO stride is too small for RS engine width padding");
    539       goto fail;
    540    }
    541    if (etna_bo_size(rsc->bo) < level->stride * level->padded_height) {
    542       BUG("BO size is too small for RS engine height padding");
    543       goto fail;
    544    }
    545 
    546    if (rsc->layout == ETNA_LAYOUT_LINEAR) {
    547       /*
    548        * Both sampler and pixel pipes can't handle linear, create a compatible
    549        * base resource, where we can attach the imported buffer as an external
    550        * resource.
    551        */
    552       struct pipe_resource tiled_templat = *tmpl;
    553 
    554       /*
    555        * Remove BIND_SCANOUT to avoid recursion, as etna_resource_create uses
    556        * this function to import the scanout buffer and get a tiled resource.
    557        */
    558       tiled_templat.bind &= ~PIPE_BIND_SCANOUT;
    559 
    560       ptiled = etna_resource_create(pscreen, &tiled_templat);
    561       if (!ptiled)
    562          goto fail;
    563 
    564       etna_resource(ptiled)->external = prsc;
    565 
    566       return ptiled;
    567    }
    568 
    569    return prsc;
    570 
    571 fail:
    572    etna_resource_destroy(pscreen, prsc);
    573    if (ptiled)
    574       etna_resource_destroy(pscreen, ptiled);
    575 
    576    return NULL;
    577 }
    578 
    579 static boolean
    580 etna_resource_get_handle(struct pipe_screen *pscreen,
    581                          struct pipe_context *pctx,
    582                          struct pipe_resource *prsc,
    583                          struct winsys_handle *handle, unsigned usage)
    584 {
    585    struct etna_resource *rsc = etna_resource(prsc);
    586    /* Scanout is always attached to the base resource */
    587    struct renderonly_scanout *scanout = rsc->scanout;
    588 
    589    /*
    590     * External resources are preferred, so a import->export chain of
    591     * render/sampler incompatible buffers yield the same handle.
    592     */
    593    if (rsc->external)
    594       rsc = etna_resource(rsc->external);
    595 
    596    handle->stride = rsc->levels[0].stride;
    597    handle->modifier = layout_to_modifier(rsc->layout);
    598 
    599    if (handle->type == DRM_API_HANDLE_TYPE_SHARED) {
    600       return etna_bo_get_name(rsc->bo, &handle->handle) == 0;
    601    } else if (handle->type == DRM_API_HANDLE_TYPE_KMS) {
    602       if (renderonly_get_handle(scanout, handle)) {
    603          return TRUE;
    604       } else {
    605          handle->handle = etna_bo_handle(rsc->bo);
    606          return TRUE;
    607       }
    608    } else if (handle->type == DRM_API_HANDLE_TYPE_FD) {
    609       handle->handle = etna_bo_dmabuf(rsc->bo);
    610       return TRUE;
    611    } else {
    612       return FALSE;
    613    }
    614 }
    615 
    616 void
    617 etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc,
    618                    enum etna_resource_status status)
    619 {
    620    struct etna_resource *rsc;
    621 
    622    if (!prsc)
    623       return;
    624 
    625    rsc = etna_resource(prsc);
    626    rsc->status |= status;
    627 
    628    /* TODO resources can actually be shared across contexts,
    629     * so I'm not sure a single list-head will do the trick? */
    630    debug_assert((rsc->pending_ctx == ctx) || !rsc->pending_ctx);
    631    list_delinit(&rsc->list);
    632    list_addtail(&rsc->list, &ctx->used_resources);
    633    rsc->pending_ctx = ctx;
    634 }
    635 
    636 bool
    637 etna_resource_has_valid_ts(struct etna_resource *rsc)
    638 {
    639    if (!rsc->ts_bo)
    640       return false;
    641 
    642    for (int level = 0; level <= rsc->base.last_level; level++)
    643       if (rsc->levels[level].ts_valid)
    644          return true;
    645 
    646    return false;
    647 }
    648 
    649 void
    650 etna_resource_screen_init(struct pipe_screen *pscreen)
    651 {
    652    pscreen->can_create_resource = etna_screen_can_create_resource;
    653    pscreen->resource_create = etna_resource_create;
    654    pscreen->resource_create_with_modifiers = etna_resource_create_modifiers;
    655    pscreen->resource_from_handle = etna_resource_from_handle;
    656    pscreen->resource_get_handle = etna_resource_get_handle;
    657    pscreen->resource_changed = etna_resource_changed;
    658    pscreen->resource_destroy = etna_resource_destroy;
    659 }
    660