Home | History | Annotate | Download | only in nv50
      1 
      2 #include "util/u_format.h"
      3 
      4 #include "nv50/nv50_context.h"
      5 
      6 #include "nv50/g80_defs.xml.h"
      7 
      8 struct nv50_transfer {
      9    struct pipe_transfer base;
     10    struct nv50_m2mf_rect rect[2];
     11    uint32_t nblocksx;
     12    uint32_t nblocksy;
     13 };
     14 
     15 void
     16 nv50_m2mf_rect_setup(struct nv50_m2mf_rect *rect,
     17                      struct pipe_resource *restrict res, unsigned l,
     18                      unsigned x, unsigned y, unsigned z)
     19 {
     20    struct nv50_miptree *mt = nv50_miptree(res);
     21    const unsigned w = u_minify(res->width0, l);
     22    const unsigned h = u_minify(res->height0, l);
     23 
     24    rect->bo = mt->base.bo;
     25    rect->domain = mt->base.domain;
     26    rect->base = mt->level[l].offset;
     27    if (mt->base.bo->offset != mt->base.address)
     28       rect->base += mt->base.address - mt->base.bo->offset;
     29    rect->pitch = mt->level[l].pitch;
     30    if (util_format_is_plain(res->format)) {
     31       rect->width = w << mt->ms_x;
     32       rect->height = h << mt->ms_y;
     33       rect->x = x << mt->ms_x;
     34       rect->y = y << mt->ms_y;
     35    } else {
     36       rect->width = util_format_get_nblocksx(res->format, w);
     37       rect->height = util_format_get_nblocksy(res->format, h);
     38       rect->x = util_format_get_nblocksx(res->format, x);
     39       rect->y = util_format_get_nblocksy(res->format, y);
     40    }
     41    rect->tile_mode = mt->level[l].tile_mode;
     42    rect->cpp = util_format_get_blocksize(res->format);
     43 
     44    if (mt->layout_3d) {
     45       rect->z = z;
     46       rect->depth = u_minify(res->depth0, l);
     47    } else {
     48       rect->base += z * mt->layer_stride;
     49       rect->z = 0;
     50       rect->depth = 1;
     51    }
     52 }
     53 
     54 void
     55 nv50_m2mf_transfer_rect(struct nv50_context *nv50,
     56                         const struct nv50_m2mf_rect *dst,
     57                         const struct nv50_m2mf_rect *src,
     58                         uint32_t nblocksx, uint32_t nblocksy)
     59 {
     60    struct nouveau_pushbuf *push = nv50->base.pushbuf;
     61    struct nouveau_bufctx *bctx = nv50->bufctx;
     62    const int cpp = dst->cpp;
     63    uint32_t src_ofst = src->base;
     64    uint32_t dst_ofst = dst->base;
     65    uint32_t height = nblocksy;
     66    uint32_t sy = src->y;
     67    uint32_t dy = dst->y;
     68 
     69    assert(dst->cpp == src->cpp);
     70 
     71    nouveau_bufctx_refn(bctx, 0, src->bo, src->domain | NOUVEAU_BO_RD);
     72    nouveau_bufctx_refn(bctx, 0, dst->bo, dst->domain | NOUVEAU_BO_WR);
     73    nouveau_pushbuf_bufctx(push, bctx);
     74    nouveau_pushbuf_validate(push);
     75 
     76    if (nouveau_bo_memtype(src->bo)) {
     77       BEGIN_NV04(push, NV50_M2MF(LINEAR_IN), 6);
     78       PUSH_DATA (push, 0);
     79       PUSH_DATA (push, src->tile_mode);
     80       PUSH_DATA (push, src->width * cpp);
     81       PUSH_DATA (push, src->height);
     82       PUSH_DATA (push, src->depth);
     83       PUSH_DATA (push, src->z);
     84    } else {
     85       src_ofst += src->y * src->pitch + src->x * cpp;
     86 
     87       BEGIN_NV04(push, NV50_M2MF(LINEAR_IN), 1);
     88       PUSH_DATA (push, 1);
     89       BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_PITCH_IN), 1);
     90       PUSH_DATA (push, src->pitch);
     91    }
     92 
     93    if (nouveau_bo_memtype(dst->bo)) {
     94       BEGIN_NV04(push, NV50_M2MF(LINEAR_OUT), 6);
     95       PUSH_DATA (push, 0);
     96       PUSH_DATA (push, dst->tile_mode);
     97       PUSH_DATA (push, dst->width * cpp);
     98       PUSH_DATA (push, dst->height);
     99       PUSH_DATA (push, dst->depth);
    100       PUSH_DATA (push, dst->z);
    101    } else {
    102       dst_ofst += dst->y * dst->pitch + dst->x * cpp;
    103 
    104       BEGIN_NV04(push, NV50_M2MF(LINEAR_OUT), 1);
    105       PUSH_DATA (push, 1);
    106       BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_PITCH_OUT), 1);
    107       PUSH_DATA (push, dst->pitch);
    108    }
    109 
    110    while (height) {
    111       int line_count = height > 2047 ? 2047 : height;
    112 
    113       BEGIN_NV04(push, NV50_M2MF(OFFSET_IN_HIGH), 2);
    114       PUSH_DATAh(push, src->bo->offset + src_ofst);
    115       PUSH_DATAh(push, dst->bo->offset + dst_ofst);
    116 
    117       BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_OFFSET_IN), 2);
    118       PUSH_DATA (push, src->bo->offset + src_ofst);
    119       PUSH_DATA (push, dst->bo->offset + dst_ofst);
    120 
    121       if (nouveau_bo_memtype(src->bo)) {
    122          BEGIN_NV04(push, NV50_M2MF(TILING_POSITION_IN), 1);
    123          PUSH_DATA (push, (sy << 16) | (src->x * cpp));
    124       } else {
    125          src_ofst += line_count * src->pitch;
    126       }
    127       if (nouveau_bo_memtype(dst->bo)) {
    128          BEGIN_NV04(push, NV50_M2MF(TILING_POSITION_OUT), 1);
    129          PUSH_DATA (push, (dy << 16) | (dst->x * cpp));
    130       } else {
    131          dst_ofst += line_count * dst->pitch;
    132       }
    133 
    134       BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_LINE_LENGTH_IN), 4);
    135       PUSH_DATA (push, nblocksx * cpp);
    136       PUSH_DATA (push, line_count);
    137       PUSH_DATA (push, (1 << 8) | (1 << 0));
    138       PUSH_DATA (push, 0);
    139 
    140       height -= line_count;
    141       sy += line_count;
    142       dy += line_count;
    143    }
    144 
    145    nouveau_bufctx_reset(bctx, 0);
    146 }
    147 
    148 void
    149 nv50_sifc_linear_u8(struct nouveau_context *nv,
    150                     struct nouveau_bo *dst, unsigned offset, unsigned domain,
    151                     unsigned size, const void *data)
    152 {
    153    struct nv50_context *nv50 = nv50_context(&nv->pipe);
    154    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    155    uint32_t *src = (uint32_t *)data;
    156    unsigned count = (size + 3) / 4;
    157    unsigned xcoord = offset & 0xff;
    158 
    159    nouveau_bufctx_refn(nv50->bufctx, 0, dst, domain | NOUVEAU_BO_WR);
    160    nouveau_pushbuf_bufctx(push, nv50->bufctx);
    161    nouveau_pushbuf_validate(push);
    162 
    163    offset &= ~0xff;
    164 
    165    BEGIN_NV04(push, NV50_2D(DST_FORMAT), 2);
    166    PUSH_DATA (push, G80_SURFACE_FORMAT_R8_UNORM);
    167    PUSH_DATA (push, 1);
    168    BEGIN_NV04(push, NV50_2D(DST_PITCH), 5);
    169    PUSH_DATA (push, 262144);
    170    PUSH_DATA (push, 65536);
    171    PUSH_DATA (push, 1);
    172    PUSH_DATAh(push, dst->offset + offset);
    173    PUSH_DATA (push, dst->offset + offset);
    174    BEGIN_NV04(push, NV50_2D(SIFC_BITMAP_ENABLE), 2);
    175    PUSH_DATA (push, 0);
    176    PUSH_DATA (push, G80_SURFACE_FORMAT_R8_UNORM);
    177    BEGIN_NV04(push, NV50_2D(SIFC_WIDTH), 10);
    178    PUSH_DATA (push, size);
    179    PUSH_DATA (push, 1);
    180    PUSH_DATA (push, 0);
    181    PUSH_DATA (push, 1);
    182    PUSH_DATA (push, 0);
    183    PUSH_DATA (push, 1);
    184    PUSH_DATA (push, 0);
    185    PUSH_DATA (push, xcoord);
    186    PUSH_DATA (push, 0);
    187    PUSH_DATA (push, 0);
    188 
    189    while (count) {
    190       unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN);
    191 
    192       BEGIN_NI04(push, NV50_2D(SIFC_DATA), nr);
    193       PUSH_DATAp(push, src, nr);
    194 
    195       src += nr;
    196       count -= nr;
    197    }
    198 
    199    nouveau_bufctx_reset(nv50->bufctx, 0);
    200 }
    201 
    202 void
    203 nv50_m2mf_copy_linear(struct nouveau_context *nv,
    204                       struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom,
    205                       struct nouveau_bo *src, unsigned srcoff, unsigned srcdom,
    206                       unsigned size)
    207 {
    208    struct nouveau_pushbuf *push = nv->pushbuf;
    209    struct nouveau_bufctx *bctx = nv50_context(&nv->pipe)->bufctx;
    210 
    211    nouveau_bufctx_refn(bctx, 0, src, srcdom | NOUVEAU_BO_RD);
    212    nouveau_bufctx_refn(bctx, 0, dst, dstdom | NOUVEAU_BO_WR);
    213    nouveau_pushbuf_bufctx(push, bctx);
    214    nouveau_pushbuf_validate(push);
    215 
    216    BEGIN_NV04(push, NV50_M2MF(LINEAR_IN), 1);
    217    PUSH_DATA (push, 1);
    218    BEGIN_NV04(push, NV50_M2MF(LINEAR_OUT), 1);
    219    PUSH_DATA (push, 1);
    220 
    221    while (size) {
    222       unsigned bytes = MIN2(size, 1 << 17);
    223 
    224       BEGIN_NV04(push, NV50_M2MF(OFFSET_IN_HIGH), 2);
    225       PUSH_DATAh(push, src->offset + srcoff);
    226       PUSH_DATAh(push, dst->offset + dstoff);
    227       BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_OFFSET_IN), 2);
    228       PUSH_DATA (push, src->offset + srcoff);
    229       PUSH_DATA (push, dst->offset + dstoff);
    230       BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_LINE_LENGTH_IN), 4);
    231       PUSH_DATA (push, bytes);
    232       PUSH_DATA (push, 1);
    233       PUSH_DATA (push, (1 << 8) | (1 << 0));
    234       PUSH_DATA (push, 0);
    235 
    236       srcoff += bytes;
    237       dstoff += bytes;
    238       size -= bytes;
    239    }
    240 
    241    nouveau_bufctx_reset(bctx, 0);
    242 }
    243 
    244 void *
    245 nv50_miptree_transfer_map(struct pipe_context *pctx,
    246                           struct pipe_resource *res,
    247                           unsigned level,
    248                           unsigned usage,
    249                           const struct pipe_box *box,
    250                           struct pipe_transfer **ptransfer)
    251 {
    252    struct nv50_screen *screen = nv50_screen(pctx->screen);
    253    struct nv50_context *nv50 = nv50_context(pctx);
    254    struct nouveau_device *dev = nv50->screen->base.device;
    255    const struct nv50_miptree *mt = nv50_miptree(res);
    256    struct nv50_transfer *tx;
    257    uint32_t size;
    258    int ret;
    259    unsigned flags = 0;
    260 
    261    if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
    262       return NULL;
    263 
    264    tx = CALLOC_STRUCT(nv50_transfer);
    265    if (!tx)
    266       return NULL;
    267 
    268    pipe_resource_reference(&tx->base.resource, res);
    269 
    270    tx->base.level = level;
    271    tx->base.usage = usage;
    272    tx->base.box = *box;
    273 
    274    if (util_format_is_plain(res->format)) {
    275       tx->nblocksx = box->width << mt->ms_x;
    276       tx->nblocksy = box->height << mt->ms_y;
    277    } else {
    278       tx->nblocksx = util_format_get_nblocksx(res->format, box->width);
    279       tx->nblocksy = util_format_get_nblocksy(res->format, box->height);
    280    }
    281 
    282    tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format);
    283    tx->base.layer_stride = tx->nblocksy * tx->base.stride;
    284 
    285    nv50_m2mf_rect_setup(&tx->rect[0], res, level, box->x, box->y, box->z);
    286 
    287    size = tx->base.layer_stride;
    288 
    289    ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
    290                         size * tx->base.box.depth, NULL, &tx->rect[1].bo);
    291    if (ret) {
    292       FREE(tx);
    293       return NULL;
    294    }
    295 
    296    tx->rect[1].cpp = tx->rect[0].cpp;
    297    tx->rect[1].width = tx->nblocksx;
    298    tx->rect[1].height = tx->nblocksy;
    299    tx->rect[1].depth = 1;
    300    tx->rect[1].pitch = tx->base.stride;
    301    tx->rect[1].domain = NOUVEAU_BO_GART;
    302 
    303    if (usage & PIPE_TRANSFER_READ) {
    304       unsigned base = tx->rect[0].base;
    305       unsigned z = tx->rect[0].z;
    306       unsigned i;
    307       for (i = 0; i < box->depth; ++i) {
    308          nv50_m2mf_transfer_rect(nv50, &tx->rect[1], &tx->rect[0],
    309                                  tx->nblocksx, tx->nblocksy);
    310          if (mt->layout_3d)
    311             tx->rect[0].z++;
    312          else
    313             tx->rect[0].base += mt->layer_stride;
    314          tx->rect[1].base += size;
    315       }
    316       tx->rect[0].z = z;
    317       tx->rect[0].base = base;
    318       tx->rect[1].base = 0;
    319    }
    320 
    321    if (tx->rect[1].bo->map) {
    322       *ptransfer = &tx->base;
    323       return tx->rect[1].bo->map;
    324    }
    325 
    326    if (usage & PIPE_TRANSFER_READ)
    327       flags = NOUVEAU_BO_RD;
    328    if (usage & PIPE_TRANSFER_WRITE)
    329       flags |= NOUVEAU_BO_WR;
    330 
    331    ret = nouveau_bo_map(tx->rect[1].bo, flags, screen->base.client);
    332    if (ret) {
    333       nouveau_bo_ref(NULL, &tx->rect[1].bo);
    334       FREE(tx);
    335       return NULL;
    336    }
    337 
    338    *ptransfer = &tx->base;
    339    return tx->rect[1].bo->map;
    340 }
    341 
    342 void
    343 nv50_miptree_transfer_unmap(struct pipe_context *pctx,
    344                             struct pipe_transfer *transfer)
    345 {
    346    struct nv50_context *nv50 = nv50_context(pctx);
    347    struct nv50_transfer *tx = (struct nv50_transfer *)transfer;
    348    struct nv50_miptree *mt = nv50_miptree(tx->base.resource);
    349    unsigned i;
    350 
    351    if (tx->base.usage & PIPE_TRANSFER_WRITE) {
    352       for (i = 0; i < tx->base.box.depth; ++i) {
    353          nv50_m2mf_transfer_rect(nv50, &tx->rect[0], &tx->rect[1],
    354                                  tx->nblocksx, tx->nblocksy);
    355          if (mt->layout_3d)
    356             tx->rect[0].z++;
    357          else
    358             tx->rect[0].base += mt->layer_stride;
    359          tx->rect[1].base += tx->nblocksy * tx->base.stride;
    360       }
    361 
    362       /* Allow the copies above to finish executing before freeing the source */
    363       nouveau_fence_work(nv50->screen->base.fence.current,
    364                          nouveau_fence_unref_bo, tx->rect[1].bo);
    365    } else {
    366       nouveau_bo_ref(NULL, &tx->rect[1].bo);
    367    }
    368 
    369    pipe_resource_reference(&transfer->resource, NULL);
    370 
    371    FREE(tx);
    372 }
    373 
    374 static void
    375 nv50_cb_bo_push(struct nouveau_context *nv,
    376                 struct nouveau_bo *bo, unsigned domain,
    377                 unsigned bufid,
    378                 unsigned offset, unsigned words,
    379                 const uint32_t *data)
    380 {
    381    struct nouveau_pushbuf *push = nv->pushbuf;
    382 
    383    assert(!(offset & 3));
    384 
    385    while (words) {
    386       unsigned nr = MIN2(words, NV04_PFIFO_MAX_PACKET_LEN);
    387 
    388       PUSH_SPACE(push, nr + 3);
    389       PUSH_REFN (push, bo, NOUVEAU_BO_WR | domain);
    390       BEGIN_NV04(push, NV50_3D(CB_ADDR), 1);
    391       PUSH_DATA (push, (offset << 6) | bufid);
    392       BEGIN_NI04(push, NV50_3D(CB_DATA(0)), nr);
    393       PUSH_DATAp(push, data, nr);
    394 
    395       words -= nr;
    396       data += nr;
    397       offset += nr * 4;
    398    }
    399 }
    400 
    401 void
    402 nv50_cb_push(struct nouveau_context *nv,
    403              struct nv04_resource *res,
    404              unsigned offset, unsigned words, const uint32_t *data)
    405 {
    406    struct nv50_context *nv50 = nv50_context(&nv->pipe);
    407    struct nv50_constbuf *cb = NULL;
    408    int s, bufid;
    409    /* Go through all the constbuf binding points of this buffer and try to
    410     * find one which contains the region to be updated.
    411     */
    412    /* XXX compute? */
    413    for (s = 0; s < 3 && !cb; s++) {
    414       uint16_t bindings = res->cb_bindings[s];
    415       while (bindings) {
    416          int i = ffs(bindings) - 1;
    417          uint32_t cb_offset = nv50->constbuf[s][i].offset;
    418 
    419          bindings &= ~(1 << i);
    420          if (cb_offset <= offset &&
    421              cb_offset + nv50->constbuf[s][i].size >= offset + words * 4) {
    422             cb = &nv50->constbuf[s][i];
    423             bufid = s * 16 + i;
    424             break;
    425          }
    426       }
    427    }
    428 
    429    if (cb) {
    430       nv50_cb_bo_push(nv, res->bo, res->domain,
    431                       bufid, offset - cb->offset, words, data);
    432    } else {
    433       nv->push_data(nv, res->bo, res->offset + offset, res->domain,
    434                     words * 4, data);
    435    }
    436 }
    437