Home | History | Annotate | Download | only in nv30
      1 /*
      2  * Copyright 2012 Red Hat Inc.
      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, sublicense,
      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 shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     20  * SOFTWARE.
     21  *
     22  * Authors: Ben Skeggs
     23  *
     24  */
     25 
     26 #include "util/u_format.h"
     27 #include "util/u_inlines.h"
     28 #include "util/u_surface.h"
     29 
     30 #include "nouveau/nv_m2mf.xml.h"
     31 #include "nv30_screen.h"
     32 #include "nv30_context.h"
     33 #include "nv30_resource.h"
     34 #include "nv30_transfer.h"
     35 
     36 static INLINE unsigned
     37 layer_offset(struct pipe_resource *pt, unsigned level, unsigned layer)
     38 {
     39    struct nv30_miptree *mt = nv30_miptree(pt);
     40    struct nv30_miptree_level *lvl = &mt->level[level];
     41 
     42    if (pt->target == PIPE_TEXTURE_CUBE)
     43       return (layer * mt->layer_size) + lvl->offset;
     44 
     45    return lvl->offset + (layer * lvl->zslice_size);
     46 }
     47 
     48 static boolean
     49 nv30_miptree_get_handle(struct pipe_screen *pscreen,
     50                         struct pipe_resource *pt,
     51                         struct winsys_handle *handle)
     52 {
     53    struct nv30_miptree *mt = nv30_miptree(pt);
     54    unsigned stride;
     55 
     56    if (!mt || !mt->base.bo)
     57       return FALSE;
     58 
     59    stride = mt->level[0].pitch;
     60 
     61    return nouveau_screen_bo_get_handle(pscreen, mt->base.bo, stride, handle);
     62 }
     63 
     64 static void
     65 nv30_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt)
     66 {
     67    struct nv30_miptree *mt = nv30_miptree(pt);
     68 
     69    nouveau_bo_ref(NULL, &mt->base.bo);
     70    FREE(mt);
     71 }
     72 
     73 struct nv30_transfer {
     74    struct pipe_transfer base;
     75    struct nv30_rect img;
     76    struct nv30_rect tmp;
     77    unsigned nblocksx;
     78    unsigned nblocksy;
     79 };
     80 
     81 static INLINE struct nv30_transfer *
     82 nv30_transfer(struct pipe_transfer *ptx)
     83 {
     84    return (struct nv30_transfer *)ptx;
     85 }
     86 
     87 static INLINE void
     88 define_rect(struct pipe_resource *pt, unsigned level, unsigned z,
     89             unsigned x, unsigned y, unsigned w, unsigned h,
     90             struct nv30_rect *rect)
     91 {
     92    struct nv30_miptree *mt = nv30_miptree(pt);
     93    struct nv30_miptree_level *lvl = &mt->level[level];
     94 
     95    rect->w = u_minify(pt->width0, level) << mt->ms_x;
     96    rect->w = util_format_get_nblocksx(pt->format, rect->w);
     97    rect->h = u_minify(pt->height0, level) << mt->ms_y;
     98    rect->h = util_format_get_nblocksy(pt->format, rect->h);
     99    rect->d = 1;
    100    rect->z = 0;
    101    if (mt->swizzled) {
    102       if (pt->target == PIPE_TEXTURE_3D) {
    103          rect->d = u_minify(pt->depth0, level);
    104          rect->z = z; z = 0;
    105       }
    106       rect->pitch = 0;
    107    } else {
    108       rect->pitch = lvl->pitch;
    109    }
    110 
    111    rect->bo     = mt->base.bo;
    112    rect->domain = NOUVEAU_BO_VRAM;
    113    rect->offset = layer_offset(pt, level, z);
    114    rect->cpp    = util_format_get_blocksize(pt->format);
    115 
    116    rect->x0     = util_format_get_nblocksx(pt->format, x) << mt->ms_x;
    117    rect->y0     = util_format_get_nblocksy(pt->format, y) << mt->ms_y;
    118    rect->x1     = rect->x0 + (w << mt->ms_x);
    119    rect->y1     = rect->y0 + (h << mt->ms_y);
    120 }
    121 
    122 void
    123 nv30_resource_copy_region(struct pipe_context *pipe,
    124                           struct pipe_resource *dstres, unsigned dst_level,
    125                           unsigned dstx, unsigned dsty, unsigned dstz,
    126                           struct pipe_resource *srcres, unsigned src_level,
    127                           const struct pipe_box *src_box)
    128 {
    129    struct nv30_context *nv30 = nv30_context(pipe);
    130    struct nv30_rect src, dst;
    131 
    132    if (dstres->target == PIPE_BUFFER && srcres->target == PIPE_BUFFER) {
    133       util_resource_copy_region(pipe, dstres, dst_level, dstx, dsty, dstz,
    134                                       srcres, src_level, src_box);
    135       return;
    136    }
    137 
    138    define_rect(srcres, src_level, src_box->z, src_box->x, src_box->y,
    139                        src_box->width, src_box->height, &src);
    140    define_rect(dstres, dst_level, dstz, dstx, dsty,
    141                        src_box->width, src_box->height, &dst);
    142 
    143    nv30_transfer_rect(nv30, NEAREST, &src, &dst);
    144 }
    145 
    146 void
    147 nv30_resource_resolve(struct pipe_context *pipe,
    148                       const struct pipe_resolve_info *info)
    149 {
    150    struct nv30_context *nv30 = nv30_context(pipe);
    151    struct nv30_rect src, dst;
    152 
    153    define_rect(info->src.res, 0, 0, info->src.x0, info->src.y0,
    154                info->src.x1 - info->src.x0, info->src.y1 - info->src.y0, &src);
    155    define_rect(info->dst.res, info->dst.level, 0, info->dst.x0, info->dst.y0,
    156                info->dst.x1 - info->dst.x0, info->dst.y1 - info->dst.y0, &dst);
    157 
    158    nv30_transfer_rect(nv30, BILINEAR, &src, &dst);
    159 }
    160 
    161 static struct pipe_transfer *
    162 nv30_miptree_transfer_new(struct pipe_context *pipe, struct pipe_resource *pt,
    163                           unsigned level, unsigned usage,
    164                           const struct pipe_box *box)
    165 {
    166    struct nv30_context *nv30 = nv30_context(pipe);
    167    struct nouveau_device *dev = nv30->screen->base.device;
    168    struct nv30_transfer *tx;
    169    int ret;
    170 
    171    tx = CALLOC_STRUCT(nv30_transfer);
    172    if (!tx)
    173       return NULL;
    174    pipe_resource_reference(&tx->base.resource, pt);
    175    tx->base.level = level;
    176    tx->base.usage = usage;
    177    tx->base.box = *box;
    178    tx->base.stride = util_format_get_nblocksx(pt->format, box->width) *
    179                      util_format_get_blocksize(pt->format);
    180    tx->base.layer_stride = util_format_get_nblocksy(pt->format, box->height) *
    181                            tx->base.stride;
    182 
    183    tx->nblocksx = util_format_get_nblocksx(pt->format, box->width);
    184    tx->nblocksy = util_format_get_nblocksy(pt->format, box->height);
    185 
    186    define_rect(pt, level, box->z, box->x, box->y,
    187                    tx->nblocksx, tx->nblocksy, &tx->img);
    188 
    189    ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
    190                         tx->base.layer_stride, NULL, &tx->tmp.bo);
    191    if (ret) {
    192       pipe_resource_reference(&tx->base.resource, NULL);
    193       FREE(tx);
    194       return NULL;
    195    }
    196 
    197    tx->tmp.domain = NOUVEAU_BO_GART;
    198    tx->tmp.offset = 0;
    199    tx->tmp.pitch  = tx->base.stride;
    200    tx->tmp.cpp    = tx->img.cpp;
    201    tx->tmp.w      = tx->nblocksx;
    202    tx->tmp.h      = tx->nblocksy;
    203    tx->tmp.d      = 1;
    204    tx->tmp.x0     = 0;
    205    tx->tmp.y0     = 0;
    206    tx->tmp.x1     = tx->tmp.w;
    207    tx->tmp.y1     = tx->tmp.h;
    208    tx->tmp.z      = 0;
    209 
    210    if (usage & PIPE_TRANSFER_READ)
    211       nv30_transfer_rect(nv30, NEAREST, &tx->img, &tx->tmp);
    212 
    213    return &tx->base;
    214 }
    215 
    216 static void
    217 nv30_miptree_transfer_del(struct pipe_context *pipe, struct pipe_transfer *ptx)
    218 {
    219    struct nv30_context *nv30 = nv30_context(pipe);
    220    struct nv30_transfer *tx = nv30_transfer(ptx);
    221 
    222    if (ptx->usage & PIPE_TRANSFER_WRITE)
    223       nv30_transfer_rect(nv30, NEAREST, &tx->tmp, &tx->img);
    224 
    225    nouveau_bo_ref(NULL, &tx->tmp.bo);
    226    pipe_resource_reference(&ptx->resource, NULL);
    227    FREE(tx);
    228 }
    229 
    230 static void *
    231 nv30_miptree_transfer_map(struct pipe_context *pipe, struct pipe_transfer *ptx)
    232 {
    233    struct nv30_context *nv30 = nv30_context(pipe);
    234    struct nv30_transfer *tx = nv30_transfer(ptx);
    235    unsigned access = 0;
    236    int ret;
    237 
    238    if (tx->tmp.bo->map)
    239       return tx->tmp.bo->map;
    240 
    241    if (ptx->usage & PIPE_TRANSFER_READ)
    242       access |= NOUVEAU_BO_RD;
    243    if (ptx->usage & PIPE_TRANSFER_WRITE)
    244       access |= NOUVEAU_BO_WR;
    245 
    246    ret = nouveau_bo_map(tx->tmp.bo, access, nv30->base.client);
    247    if (ret)
    248       return NULL;
    249    return tx->tmp.bo->map;
    250 }
    251 
    252 static void
    253 nv30_miptree_transfer_unmap(struct pipe_context *pipe,
    254                             struct pipe_transfer *ptx)
    255 {
    256 }
    257 
    258 const struct u_resource_vtbl nv30_miptree_vtbl = {
    259    nv30_miptree_get_handle,
    260    nv30_miptree_destroy,
    261    nv30_miptree_transfer_new,
    262    nv30_miptree_transfer_del,
    263    nv30_miptree_transfer_map,
    264    u_default_transfer_flush_region,
    265    nv30_miptree_transfer_unmap,
    266    u_default_transfer_inline_write
    267 };
    268 
    269 struct pipe_resource *
    270 nv30_miptree_create(struct pipe_screen *pscreen,
    271                     const struct pipe_resource *tmpl)
    272 {
    273    struct nouveau_device *dev = nouveau_screen(pscreen)->device;
    274    struct nv30_miptree *mt = CALLOC_STRUCT(nv30_miptree);
    275    struct pipe_resource *pt = &mt->base.base;
    276    unsigned blocksz, size;
    277    unsigned w, h, d, l;
    278    int ret;
    279 
    280    switch (tmpl->nr_samples) {
    281    case 4:
    282       mt->ms_mode = 0x00004000;
    283       mt->ms_x = 1;
    284       mt->ms_y = 1;
    285       break;
    286    case 2:
    287       mt->ms_mode = 0x00003000;
    288       mt->ms_x = 1;
    289       mt->ms_y = 0;
    290       break;
    291    default:
    292       mt->ms_mode = 0x00000000;
    293       mt->ms_x = 0;
    294       mt->ms_y = 0;
    295       break;
    296    }
    297 
    298    mt->base.vtbl = &nv30_miptree_vtbl;
    299    *pt = *tmpl;
    300    pipe_reference_init(&pt->reference, 1);
    301    pt->screen = pscreen;
    302 
    303    w = pt->width0 << mt->ms_x;
    304    h = pt->height0 << mt->ms_y;
    305    d = (pt->target == PIPE_TEXTURE_3D) ? pt->depth0 : 1;
    306    blocksz = util_format_get_blocksize(pt->format);
    307 
    308    if ((pt->target == PIPE_TEXTURE_RECT) ||
    309        !util_is_power_of_two(pt->width0) ||
    310        !util_is_power_of_two(pt->height0) ||
    311        !util_is_power_of_two(pt->depth0) ||
    312        util_format_is_compressed(pt->format) ||
    313        util_format_is_float(pt->format) || mt->ms_mode) {
    314       mt->uniform_pitch = util_format_get_nblocksx(pt->format, w) * blocksz;
    315       mt->uniform_pitch = align(mt->uniform_pitch, 64);
    316    }
    317 
    318    if (!mt->uniform_pitch)
    319       mt->swizzled = TRUE;
    320 
    321    size = 0;
    322    for (l = 0; l <= pt->last_level; l++) {
    323       struct nv30_miptree_level *lvl = &mt->level[l];
    324       unsigned nbx = util_format_get_nblocksx(pt->format, w);
    325       unsigned nby = util_format_get_nblocksx(pt->format, h);
    326 
    327       lvl->offset = size;
    328       lvl->pitch  = mt->uniform_pitch;
    329       if (!lvl->pitch)
    330          lvl->pitch = nbx * blocksz;
    331 
    332       lvl->zslice_size = lvl->pitch * nby;
    333       size += lvl->zslice_size * d;
    334 
    335       w = u_minify(w, 1);
    336       h = u_minify(h, 1);
    337       d = u_minify(d, 1);
    338    }
    339 
    340    mt->layer_size = size;
    341    if (pt->target == PIPE_TEXTURE_CUBE) {
    342       if (!mt->uniform_pitch)
    343          mt->layer_size = align(mt->layer_size, 128);
    344       size = mt->layer_size * 6;
    345    }
    346 
    347    ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 256, size, NULL, &mt->base.bo);
    348    if (ret) {
    349       FREE(mt);
    350       return NULL;
    351    }
    352 
    353    mt->base.domain = NOUVEAU_BO_VRAM;
    354    return &mt->base.base;
    355 }
    356 
    357 struct pipe_resource *
    358 nv30_miptree_from_handle(struct pipe_screen *pscreen,
    359                          const struct pipe_resource *tmpl,
    360                          struct winsys_handle *handle)
    361 {
    362    struct nv30_miptree *mt;
    363    unsigned stride;
    364 
    365    /* only supports 2D, non-mipmapped textures for the moment */
    366    if ((tmpl->target != PIPE_TEXTURE_2D &&
    367         tmpl->target != PIPE_TEXTURE_RECT) ||
    368        tmpl->last_level != 0 ||
    369        tmpl->depth0 != 1 ||
    370        tmpl->array_size > 1)
    371       return NULL;
    372 
    373    mt = CALLOC_STRUCT(nv30_miptree);
    374    if (!mt)
    375       return NULL;
    376 
    377    mt->base.bo = nouveau_screen_bo_from_handle(pscreen, handle, &stride);
    378    if (mt->base.bo == NULL) {
    379       FREE(mt);
    380       return NULL;
    381    }
    382 
    383    mt->base.base = *tmpl;
    384    mt->base.vtbl = &nv30_miptree_vtbl;
    385    pipe_reference_init(&mt->base.base.reference, 1);
    386    mt->base.base.screen = pscreen;
    387    mt->uniform_pitch = stride;
    388    mt->level[0].pitch = mt->uniform_pitch;
    389    mt->level[0].offset = 0;
    390 
    391    /* no need to adjust bo reference count */
    392    return &mt->base.base;
    393 }
    394 
    395 struct pipe_surface *
    396 nv30_miptree_surface_new(struct pipe_context *pipe,
    397                          struct pipe_resource *pt,
    398                          const struct pipe_surface *tmpl)
    399 {
    400    struct nv30_miptree *mt = nv30_miptree(pt); /* guaranteed */
    401    struct nv30_surface *ns;
    402    struct pipe_surface *ps;
    403    struct nv30_miptree_level *lvl = &mt->level[tmpl->u.tex.level];
    404 
    405    ns = CALLOC_STRUCT(nv30_surface);
    406    if (!ns)
    407       return NULL;
    408    ps = &ns->base;
    409 
    410    pipe_reference_init(&ps->reference, 1);
    411    pipe_resource_reference(&ps->texture, pt);
    412    ps->context = pipe;
    413    ps->format = tmpl->format;
    414    ps->usage = tmpl->usage;
    415    ps->u.tex.level = tmpl->u.tex.level;
    416    ps->u.tex.first_layer = tmpl->u.tex.first_layer;
    417    ps->u.tex.last_layer = tmpl->u.tex.last_layer;
    418 
    419    ns->width = u_minify(pt->width0, ps->u.tex.level);
    420    ns->height = u_minify(pt->height0, ps->u.tex.level);
    421    ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;
    422    ns->offset = layer_offset(pt, ps->u.tex.level, ps->u.tex.first_layer);
    423    if (mt->swizzled)
    424       ns->pitch = 4096; /* random, just something the hw won't reject.. */
    425    else
    426       ns->pitch = lvl->pitch;
    427 
    428    /* comment says there are going to be removed, but they're used by the st */
    429    ps->width = ns->width;
    430    ps->height = ns->height;
    431    return ps;
    432 }
    433 
    434 void
    435 nv30_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps)
    436 {
    437    struct nv30_surface *ns = nv30_surface(ps);
    438 
    439    pipe_resource_reference(&ps->texture, NULL);
    440    FREE(ns);
    441 }
    442