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 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20  * OTHER DEALINGS IN THE 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 "nv_m2mf.xml.h"
     31 #include "nv_object.xml.h"
     32 #include "nv30/nv30_screen.h"
     33 #include "nv30/nv30_context.h"
     34 #include "nv30/nv30_resource.h"
     35 #include "nv30/nv30_transfer.h"
     36 
     37 static inline unsigned
     38 layer_offset(struct pipe_resource *pt, unsigned level, unsigned layer)
     39 {
     40    struct nv30_miptree *mt = nv30_miptree(pt);
     41    struct nv30_miptree_level *lvl = &mt->level[level];
     42 
     43    if (pt->target == PIPE_TEXTURE_CUBE)
     44       return (layer * mt->layer_size) + lvl->offset;
     45 
     46    return lvl->offset + (layer * lvl->zslice_size);
     47 }
     48 
     49 static boolean
     50 nv30_miptree_get_handle(struct pipe_screen *pscreen,
     51                         struct pipe_resource *pt,
     52                         struct winsys_handle *handle)
     53 {
     54    struct nv30_miptree *mt = nv30_miptree(pt);
     55    unsigned stride;
     56 
     57    if (!mt || !mt->base.bo)
     58       return false;
     59 
     60    stride = mt->level[0].pitch;
     61 
     62    return nouveau_screen_bo_get_handle(pscreen, mt->base.bo, stride, handle);
     63 }
     64 
     65 static void
     66 nv30_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt)
     67 {
     68    struct nv30_miptree *mt = nv30_miptree(pt);
     69 
     70    nouveau_bo_ref(NULL, &mt->base.bo);
     71    FREE(mt);
     72 }
     73 
     74 struct nv30_transfer {
     75    struct pipe_transfer base;
     76    struct nv30_rect img;
     77    struct nv30_rect tmp;
     78    unsigned nblocksx;
     79    unsigned nblocksy;
     80 };
     81 
     82 static inline struct nv30_transfer *
     83 nv30_transfer(struct pipe_transfer *ptx)
     84 {
     85    return (struct nv30_transfer *)ptx;
     86 }
     87 
     88 static inline void
     89 define_rect(struct pipe_resource *pt, unsigned level, unsigned z,
     90             unsigned x, unsigned y, unsigned w, unsigned h,
     91             struct nv30_rect *rect)
     92 {
     93    struct nv30_miptree *mt = nv30_miptree(pt);
     94    struct nv30_miptree_level *lvl = &mt->level[level];
     95 
     96    rect->w = u_minify(pt->width0, level) << mt->ms_x;
     97    rect->w = util_format_get_nblocksx(pt->format, rect->w);
     98    rect->h = u_minify(pt->height0, level) << mt->ms_y;
     99    rect->h = util_format_get_nblocksy(pt->format, rect->h);
    100    rect->d = 1;
    101    rect->z = 0;
    102    if (mt->swizzled) {
    103       if (pt->target == PIPE_TEXTURE_3D) {
    104          rect->d = u_minify(pt->depth0, level);
    105          rect->z = z; z = 0;
    106       }
    107       rect->pitch = 0;
    108    } else {
    109       rect->pitch = lvl->pitch;
    110    }
    111 
    112    rect->bo     = mt->base.bo;
    113    rect->domain = NOUVEAU_BO_VRAM;
    114    rect->offset = layer_offset(pt, level, z);
    115    rect->cpp    = util_format_get_blocksize(pt->format);
    116 
    117    rect->x0     = util_format_get_nblocksx(pt->format, x) << mt->ms_x;
    118    rect->y0     = util_format_get_nblocksy(pt->format, y) << mt->ms_y;
    119    rect->x1     = rect->x0 + (w << mt->ms_x);
    120    rect->y1     = rect->y0 + (h << mt->ms_y);
    121 }
    122 
    123 void
    124 nv30_resource_copy_region(struct pipe_context *pipe,
    125                           struct pipe_resource *dstres, unsigned dst_level,
    126                           unsigned dstx, unsigned dsty, unsigned dstz,
    127                           struct pipe_resource *srcres, unsigned src_level,
    128                           const struct pipe_box *src_box)
    129 {
    130    struct nv30_context *nv30 = nv30_context(pipe);
    131    struct nv30_rect src, dst;
    132 
    133    if (dstres->target == PIPE_BUFFER && srcres->target == PIPE_BUFFER) {
    134       nouveau_copy_buffer(&nv30->base,
    135                           nv04_resource(dstres), dstx,
    136                           nv04_resource(srcres), src_box->x, src_box->width);
    137       return;
    138    }
    139 
    140    define_rect(srcres, src_level, src_box->z, src_box->x, src_box->y,
    141                        src_box->width, src_box->height, &src);
    142    define_rect(dstres, dst_level, dstz, dstx, dsty,
    143                        src_box->width, src_box->height, &dst);
    144 
    145    nv30_transfer_rect(nv30, NEAREST, &src, &dst);
    146 }
    147 
    148 static void
    149 nv30_resource_resolve(struct nv30_context *nv30,
    150                       const struct pipe_blit_info *info)
    151 {
    152    struct nv30_miptree *src_mt = nv30_miptree(info->src.resource);
    153    struct nv30_rect src, dst;
    154    unsigned x, x0, x1, y, y1, w, h;
    155 
    156    define_rect(info->src.resource, 0, info->src.box.z, info->src.box.x,
    157       info->src.box.y, info->src.box.width, info->src.box.height, &src);
    158    define_rect(info->dst.resource, 0, info->dst.box.z, info->dst.box.x,
    159       info->dst.box.y, info->dst.box.width, info->dst.box.height, &dst);
    160 
    161    x0 = src.x0;
    162    x1 = src.x1;
    163    y1 = src.y1;
    164 
    165    /* On nv3x we must use sifm which is restricted to 1024x1024 tiles */
    166    for (y = src.y0; y < y1; y += h) {
    167       h = y1 - y;
    168       if (h > 1024)
    169          h = 1024;
    170 
    171       src.y0 = 0;
    172       src.y1 = h;
    173       src.h = h;
    174 
    175       dst.y1 = dst.y0 + (h >> src_mt->ms_y);
    176       dst.h = h >> src_mt->ms_y;
    177 
    178       for (x = x0; x < x1; x += w) {
    179          w = x1 - x;
    180          if (w > 1024)
    181             w = 1024;
    182 
    183          src.offset = y * src.pitch + x * src.cpp;
    184          src.x0 = 0;
    185          src.x1 = w;
    186          src.w = w;
    187 
    188          dst.offset = (y >> src_mt->ms_y) * dst.pitch +
    189                       (x >> src_mt->ms_x) * dst.cpp;
    190          dst.x1 = dst.x0 + (w >> src_mt->ms_x);
    191          dst.w = w >> src_mt->ms_x;
    192 
    193          nv30_transfer_rect(nv30, BILINEAR, &src, &dst);
    194       }
    195    }
    196 }
    197 
    198 void
    199 nv30_blit(struct pipe_context *pipe,
    200           const struct pipe_blit_info *blit_info)
    201 {
    202    struct nv30_context *nv30 = nv30_context(pipe);
    203    struct pipe_blit_info info = *blit_info;
    204 
    205    if (info.src.resource->nr_samples > 1 &&
    206        info.dst.resource->nr_samples <= 1 &&
    207        !util_format_is_depth_or_stencil(info.src.resource->format) &&
    208        !util_format_is_pure_integer(info.src.resource->format)) {
    209       nv30_resource_resolve(nv30, blit_info);
    210       return;
    211    }
    212 
    213    if (util_try_blit_via_copy_region(pipe, &info)) {
    214       return; /* done */
    215    }
    216 
    217    if (info.mask & PIPE_MASK_S) {
    218       debug_printf("nv30: cannot blit stencil, skipping\n");
    219       info.mask &= ~PIPE_MASK_S;
    220    }
    221 
    222    if (!util_blitter_is_blit_supported(nv30->blitter, &info)) {
    223       debug_printf("nv30: blit unsupported %s -> %s\n",
    224                    util_format_short_name(info.src.resource->format),
    225                    util_format_short_name(info.dst.resource->format));
    226       return;
    227    }
    228 
    229    /* XXX turn off occlusion queries */
    230 
    231    util_blitter_save_vertex_buffer_slot(nv30->blitter, nv30->vtxbuf);
    232    util_blitter_save_vertex_elements(nv30->blitter, nv30->vertex);
    233    util_blitter_save_vertex_shader(nv30->blitter, nv30->vertprog.program);
    234    util_blitter_save_rasterizer(nv30->blitter, nv30->rast);
    235    util_blitter_save_viewport(nv30->blitter, &nv30->viewport);
    236    util_blitter_save_scissor(nv30->blitter, &nv30->scissor);
    237    util_blitter_save_fragment_shader(nv30->blitter, nv30->fragprog.program);
    238    util_blitter_save_blend(nv30->blitter, nv30->blend);
    239    util_blitter_save_depth_stencil_alpha(nv30->blitter,
    240                                          nv30->zsa);
    241    util_blitter_save_stencil_ref(nv30->blitter, &nv30->stencil_ref);
    242    util_blitter_save_sample_mask(nv30->blitter, nv30->sample_mask);
    243    util_blitter_save_framebuffer(nv30->blitter, &nv30->framebuffer);
    244    util_blitter_save_fragment_sampler_states(nv30->blitter,
    245                      nv30->fragprog.num_samplers,
    246                      (void**)nv30->fragprog.samplers);
    247    util_blitter_save_fragment_sampler_views(nv30->blitter,
    248                      nv30->fragprog.num_textures, nv30->fragprog.textures);
    249    util_blitter_save_render_condition(nv30->blitter, nv30->render_cond_query,
    250                                       nv30->render_cond_cond, nv30->render_cond_mode);
    251    util_blitter_blit(nv30->blitter, &info);
    252 }
    253 
    254 void
    255 nv30_flush_resource(struct pipe_context *pipe,
    256                     struct pipe_resource *resource)
    257 {
    258 }
    259 
    260 static void *
    261 nv30_miptree_transfer_map(struct pipe_context *pipe, struct pipe_resource *pt,
    262                           unsigned level, unsigned usage,
    263                           const struct pipe_box *box,
    264                           struct pipe_transfer **ptransfer)
    265 {
    266    struct nv30_context *nv30 = nv30_context(pipe);
    267    struct nouveau_device *dev = nv30->screen->base.device;
    268    struct nv30_transfer *tx;
    269    unsigned access = 0;
    270    int ret;
    271 
    272    tx = CALLOC_STRUCT(nv30_transfer);
    273    if (!tx)
    274       return NULL;
    275    pipe_resource_reference(&tx->base.resource, pt);
    276    tx->base.level = level;
    277    tx->base.usage = usage;
    278    tx->base.box = *box;
    279    tx->base.stride = align(util_format_get_nblocksx(pt->format, box->width) *
    280                            util_format_get_blocksize(pt->format), 64);
    281    tx->base.layer_stride = util_format_get_nblocksy(pt->format, box->height) *
    282                            tx->base.stride;
    283 
    284    tx->nblocksx = util_format_get_nblocksx(pt->format, box->width);
    285    tx->nblocksy = util_format_get_nblocksy(pt->format, box->height);
    286 
    287    define_rect(pt, level, box->z, box->x, box->y,
    288                    tx->nblocksx, tx->nblocksy, &tx->img);
    289 
    290    ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
    291                         tx->base.layer_stride, NULL, &tx->tmp.bo);
    292    if (ret) {
    293       pipe_resource_reference(&tx->base.resource, NULL);
    294       FREE(tx);
    295       return NULL;
    296    }
    297 
    298    tx->tmp.domain = NOUVEAU_BO_GART;
    299    tx->tmp.offset = 0;
    300    tx->tmp.pitch  = tx->base.stride;
    301    tx->tmp.cpp    = tx->img.cpp;
    302    tx->tmp.w      = tx->nblocksx;
    303    tx->tmp.h      = tx->nblocksy;
    304    tx->tmp.d      = 1;
    305    tx->tmp.x0     = 0;
    306    tx->tmp.y0     = 0;
    307    tx->tmp.x1     = tx->tmp.w;
    308    tx->tmp.y1     = tx->tmp.h;
    309    tx->tmp.z      = 0;
    310 
    311    if (usage & PIPE_TRANSFER_READ)
    312       nv30_transfer_rect(nv30, NEAREST, &tx->img, &tx->tmp);
    313 
    314    if (tx->tmp.bo->map) {
    315       *ptransfer = &tx->base;
    316       return tx->tmp.bo->map;
    317    }
    318 
    319    if (usage & PIPE_TRANSFER_READ)
    320       access |= NOUVEAU_BO_RD;
    321    if (usage & PIPE_TRANSFER_WRITE)
    322       access |= NOUVEAU_BO_WR;
    323 
    324    ret = nouveau_bo_map(tx->tmp.bo, access, nv30->base.client);
    325    if (ret) {
    326       pipe_resource_reference(&tx->base.resource, NULL);
    327       FREE(tx);
    328       return NULL;
    329    }
    330 
    331    *ptransfer = &tx->base;
    332    return tx->tmp.bo->map;
    333 }
    334 
    335 static void
    336 nv30_miptree_transfer_unmap(struct pipe_context *pipe,
    337                             struct pipe_transfer *ptx)
    338 {
    339    struct nv30_context *nv30 = nv30_context(pipe);
    340    struct nv30_transfer *tx = nv30_transfer(ptx);
    341 
    342    if (ptx->usage & PIPE_TRANSFER_WRITE) {
    343       nv30_transfer_rect(nv30, NEAREST, &tx->tmp, &tx->img);
    344 
    345       /* Allow the copies above to finish executing before freeing the source */
    346       nouveau_fence_work(nv30->screen->base.fence.current,
    347                          nouveau_fence_unref_bo, tx->tmp.bo);
    348    } else {
    349       nouveau_bo_ref(NULL, &tx->tmp.bo);
    350    }
    351    pipe_resource_reference(&ptx->resource, NULL);
    352    FREE(tx);
    353 }
    354 
    355 const struct u_resource_vtbl nv30_miptree_vtbl = {
    356    nv30_miptree_get_handle,
    357    nv30_miptree_destroy,
    358    nv30_miptree_transfer_map,
    359    u_default_transfer_flush_region,
    360    nv30_miptree_transfer_unmap,
    361 };
    362 
    363 struct pipe_resource *
    364 nv30_miptree_create(struct pipe_screen *pscreen,
    365                     const struct pipe_resource *tmpl)
    366 {
    367    struct nouveau_device *dev = nouveau_screen(pscreen)->device;
    368    struct nv30_miptree *mt = CALLOC_STRUCT(nv30_miptree);
    369    struct pipe_resource *pt = &mt->base.base;
    370    unsigned blocksz, size;
    371    unsigned w, h, d, l;
    372    int ret;
    373 
    374    switch (tmpl->nr_samples) {
    375    case 4:
    376       mt->ms_mode = 0x00004000;
    377       mt->ms_x = 1;
    378       mt->ms_y = 1;
    379       break;
    380    case 2:
    381       mt->ms_mode = 0x00003000;
    382       mt->ms_x = 1;
    383       mt->ms_y = 0;
    384       break;
    385    default:
    386       mt->ms_mode = 0x00000000;
    387       mt->ms_x = 0;
    388       mt->ms_y = 0;
    389       break;
    390    }
    391 
    392    mt->base.vtbl = &nv30_miptree_vtbl;
    393    *pt = *tmpl;
    394    pipe_reference_init(&pt->reference, 1);
    395    pt->screen = pscreen;
    396 
    397    w = pt->width0 << mt->ms_x;
    398    h = pt->height0 << mt->ms_y;
    399    d = (pt->target == PIPE_TEXTURE_3D) ? pt->depth0 : 1;
    400    blocksz = util_format_get_blocksize(pt->format);
    401 
    402    if ((pt->target == PIPE_TEXTURE_RECT) ||
    403        (pt->bind & PIPE_BIND_SCANOUT) ||
    404        !util_is_power_of_two(pt->width0) ||
    405        !util_is_power_of_two(pt->height0) ||
    406        !util_is_power_of_two(pt->depth0) ||
    407        util_format_is_compressed(pt->format) ||
    408        util_format_is_float(pt->format) || mt->ms_mode) {
    409       mt->uniform_pitch = util_format_get_nblocksx(pt->format, w) * blocksz;
    410       mt->uniform_pitch = align(mt->uniform_pitch, 64);
    411       if (pt->bind & PIPE_BIND_SCANOUT) {
    412          struct nv30_screen *screen = nv30_screen(pscreen);
    413          int pitch_align = MAX2(
    414                screen->eng3d->oclass >= NV40_3D_CLASS ? 1024 : 256,
    415                /* round_down_pow2(mt->uniform_pitch / 4) */
    416                1 << (util_last_bit(mt->uniform_pitch / 4) - 1));
    417          mt->uniform_pitch = align(mt->uniform_pitch, pitch_align);
    418       }
    419    }
    420 
    421    if (!mt->uniform_pitch)
    422       mt->swizzled = true;
    423 
    424    size = 0;
    425    for (l = 0; l <= pt->last_level; l++) {
    426       struct nv30_miptree_level *lvl = &mt->level[l];
    427       unsigned nbx = util_format_get_nblocksx(pt->format, w);
    428       unsigned nby = util_format_get_nblocksx(pt->format, h);
    429 
    430       lvl->offset = size;
    431       lvl->pitch  = mt->uniform_pitch;
    432       if (!lvl->pitch)
    433          lvl->pitch = nbx * blocksz;
    434 
    435       lvl->zslice_size = lvl->pitch * nby;
    436       size += lvl->zslice_size * d;
    437 
    438       w = u_minify(w, 1);
    439       h = u_minify(h, 1);
    440       d = u_minify(d, 1);
    441    }
    442 
    443    mt->layer_size = size;
    444    if (pt->target == PIPE_TEXTURE_CUBE) {
    445       if (!mt->uniform_pitch)
    446          mt->layer_size = align(mt->layer_size, 128);
    447       size = mt->layer_size * 6;
    448    }
    449 
    450    ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 256, size, NULL, &mt->base.bo);
    451    if (ret) {
    452       FREE(mt);
    453       return NULL;
    454    }
    455 
    456    mt->base.domain = NOUVEAU_BO_VRAM;
    457    return &mt->base.base;
    458 }
    459 
    460 struct pipe_resource *
    461 nv30_miptree_from_handle(struct pipe_screen *pscreen,
    462                          const struct pipe_resource *tmpl,
    463                          struct winsys_handle *handle)
    464 {
    465    struct nv30_miptree *mt;
    466    unsigned stride;
    467 
    468    /* only supports 2D, non-mipmapped textures for the moment */
    469    if ((tmpl->target != PIPE_TEXTURE_2D &&
    470         tmpl->target != PIPE_TEXTURE_RECT) ||
    471        tmpl->last_level != 0 ||
    472        tmpl->depth0 != 1 ||
    473        tmpl->array_size > 1)
    474       return NULL;
    475 
    476    mt = CALLOC_STRUCT(nv30_miptree);
    477    if (!mt)
    478       return NULL;
    479 
    480    mt->base.bo = nouveau_screen_bo_from_handle(pscreen, handle, &stride);
    481    if (mt->base.bo == NULL) {
    482       FREE(mt);
    483       return NULL;
    484    }
    485 
    486    mt->base.base = *tmpl;
    487    mt->base.vtbl = &nv30_miptree_vtbl;
    488    pipe_reference_init(&mt->base.base.reference, 1);
    489    mt->base.base.screen = pscreen;
    490    mt->uniform_pitch = stride;
    491    mt->level[0].pitch = mt->uniform_pitch;
    492    mt->level[0].offset = 0;
    493 
    494    /* no need to adjust bo reference count */
    495    return &mt->base.base;
    496 }
    497 
    498 struct pipe_surface *
    499 nv30_miptree_surface_new(struct pipe_context *pipe,
    500                          struct pipe_resource *pt,
    501                          const struct pipe_surface *tmpl)
    502 {
    503    struct nv30_miptree *mt = nv30_miptree(pt); /* guaranteed */
    504    struct nv30_surface *ns;
    505    struct pipe_surface *ps;
    506    struct nv30_miptree_level *lvl = &mt->level[tmpl->u.tex.level];
    507 
    508    ns = CALLOC_STRUCT(nv30_surface);
    509    if (!ns)
    510       return NULL;
    511    ps = &ns->base;
    512 
    513    pipe_reference_init(&ps->reference, 1);
    514    pipe_resource_reference(&ps->texture, pt);
    515    ps->context = pipe;
    516    ps->format = tmpl->format;
    517    ps->u.tex.level = tmpl->u.tex.level;
    518    ps->u.tex.first_layer = tmpl->u.tex.first_layer;
    519    ps->u.tex.last_layer = tmpl->u.tex.last_layer;
    520 
    521    ns->width = u_minify(pt->width0, ps->u.tex.level);
    522    ns->height = u_minify(pt->height0, ps->u.tex.level);
    523    ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;
    524    ns->offset = layer_offset(pt, ps->u.tex.level, ps->u.tex.first_layer);
    525    if (mt->swizzled)
    526       ns->pitch = 4096; /* random, just something the hw won't reject.. */
    527    else
    528       ns->pitch = lvl->pitch;
    529 
    530    /* comment says there are going to be removed, but they're used by the st */
    531    ps->width = ns->width;
    532    ps->height = ns->height;
    533    return ps;
    534 }
    535 
    536 void
    537 nv30_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps)
    538 {
    539    struct nv30_surface *ns = nv30_surface(ps);
    540 
    541    pipe_resource_reference(&ps->texture, NULL);
    542    FREE(ns);
    543 }
    544