Home | History | Annotate | Download | only in nvc0
      1 
      2 #include "util/u_format.h"
      3 
      4 #include "nvc0_context.h"
      5 
      6 #include "nv50/nv50_defs.xml.h"
      7 
      8 struct nvc0_transfer {
      9    struct pipe_transfer base;
     10    struct nv50_m2mf_rect rect[2];
     11    uint32_t nblocksx;
     12    uint16_t nblocksy;
     13    uint16_t nlayers;
     14 };
     15 
     16 static void
     17 nvc0_m2mf_transfer_rect(struct nvc0_context *nvc0,
     18                         const struct nv50_m2mf_rect *dst,
     19                         const struct nv50_m2mf_rect *src,
     20                         uint32_t nblocksx, uint32_t nblocksy)
     21 {
     22    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
     23    struct nouveau_bufctx *bctx = nvc0->bufctx;
     24    const int cpp = dst->cpp;
     25    uint32_t src_ofst = src->base;
     26    uint32_t dst_ofst = dst->base;
     27    uint32_t height = nblocksy;
     28    uint32_t sy = src->y;
     29    uint32_t dy = dst->y;
     30    uint32_t exec = (1 << 20);
     31 
     32    assert(dst->cpp == src->cpp);
     33 
     34    nouveau_bufctx_refn(bctx, 0, src->bo, src->domain | NOUVEAU_BO_RD);
     35    nouveau_bufctx_refn(bctx, 0, dst->bo, dst->domain | NOUVEAU_BO_WR);
     36    nouveau_pushbuf_bufctx(push, bctx);
     37    nouveau_pushbuf_validate(push);
     38 
     39    if (nouveau_bo_memtype(src->bo)) {
     40       BEGIN_NVC0(push, NVC0_M2MF(TILING_MODE_IN), 5);
     41       PUSH_DATA (push, src->tile_mode);
     42       PUSH_DATA (push, src->width * cpp);
     43       PUSH_DATA (push, src->height);
     44       PUSH_DATA (push, src->depth);
     45       PUSH_DATA (push, src->z);
     46    } else {
     47       src_ofst += src->y * src->pitch + src->x * cpp;
     48 
     49       BEGIN_NVC0(push, NVC0_M2MF(PITCH_IN), 1);
     50       PUSH_DATA (push, src->width * cpp);
     51 
     52       exec |= NVC0_M2MF_EXEC_LINEAR_IN;
     53    }
     54 
     55    if (nouveau_bo_memtype(dst->bo)) {
     56       BEGIN_NVC0(push, NVC0_M2MF(TILING_MODE_OUT), 5);
     57       PUSH_DATA (push, dst->tile_mode);
     58       PUSH_DATA (push, dst->width * cpp);
     59       PUSH_DATA (push, dst->height);
     60       PUSH_DATA (push, dst->depth);
     61       PUSH_DATA (push, dst->z);
     62    } else {
     63       dst_ofst += dst->y * dst->pitch + dst->x * cpp;
     64 
     65       BEGIN_NVC0(push, NVC0_M2MF(PITCH_OUT), 1);
     66       PUSH_DATA (push, dst->width * cpp);
     67 
     68       exec |= NVC0_M2MF_EXEC_LINEAR_OUT;
     69    }
     70 
     71    while (height) {
     72       int line_count = height > 2047 ? 2047 : height;
     73 
     74       BEGIN_NVC0(push, NVC0_M2MF(OFFSET_IN_HIGH), 2);
     75       PUSH_DATAh(push, src->bo->offset + src_ofst);
     76       PUSH_DATA (push, src->bo->offset + src_ofst);
     77 
     78       BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2);
     79       PUSH_DATAh(push, dst->bo->offset + dst_ofst);
     80       PUSH_DATA (push, dst->bo->offset + dst_ofst);
     81 
     82       if (!(exec & NVC0_M2MF_EXEC_LINEAR_IN)) {
     83          BEGIN_NVC0(push, NVC0_M2MF(TILING_POSITION_IN_X), 2);
     84          PUSH_DATA (push, src->x * cpp);
     85          PUSH_DATA (push, sy);
     86       } else {
     87          src_ofst += line_count * src->pitch;
     88       }
     89       if (!(exec & NVC0_M2MF_EXEC_LINEAR_OUT)) {
     90          BEGIN_NVC0(push, NVC0_M2MF(TILING_POSITION_OUT_X), 2);
     91          PUSH_DATA (push, dst->x * cpp);
     92          PUSH_DATA (push, dy);
     93       } else {
     94          dst_ofst += line_count * dst->pitch;
     95       }
     96 
     97       BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2);
     98       PUSH_DATA (push, nblocksx * cpp);
     99       PUSH_DATA (push, line_count);
    100       BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1);
    101       PUSH_DATA (push, exec);
    102 
    103       height -= line_count;
    104       sy += line_count;
    105       dy += line_count;
    106    }
    107 
    108    nouveau_bufctx_reset(bctx, 0);
    109 }
    110 
    111 static void
    112 nve4_m2mf_transfer_rect(struct nvc0_context *nvc0,
    113                         const struct nv50_m2mf_rect *dst,
    114                         const struct nv50_m2mf_rect *src,
    115                         uint32_t nblocksx, uint32_t nblocksy)
    116 {
    117    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    118    struct nouveau_bufctx *bctx = nvc0->bufctx;
    119    uint32_t exec;
    120    uint32_t src_base = src->base;
    121    uint32_t dst_base = dst->base;
    122    const int cpp = dst->cpp;
    123 
    124    assert(dst->cpp == src->cpp);
    125 
    126    nouveau_bufctx_refn(bctx, 0, dst->bo, dst->domain | NOUVEAU_BO_WR);
    127    nouveau_bufctx_refn(bctx, 0, src->bo, src->domain | NOUVEAU_BO_RD);
    128    nouveau_pushbuf_bufctx(push, bctx);
    129    nouveau_pushbuf_validate(push);
    130 
    131    exec = 0x200 /* 2D_ENABLE */ | 0x6 /* UNK */;
    132 
    133    if (!nouveau_bo_memtype(dst->bo)) {
    134       assert(!dst->z);
    135       dst_base += dst->y * dst->pitch + dst->x * cpp;
    136       exec |= 0x100; /* DST_MODE_2D_LINEAR */
    137    }
    138    if (!nouveau_bo_memtype(src->bo)) {
    139       assert(!src->z);
    140       src_base += src->y * src->pitch + src->x * cpp;
    141       exec |= 0x080; /* SRC_MODE_2D_LINEAR */
    142    }
    143 
    144    BEGIN_NVC0(push, SUBC_COPY(0x070c), 6);
    145    PUSH_DATA (push, 0x1000 | dst->tile_mode);
    146    PUSH_DATA (push, dst->pitch);
    147    PUSH_DATA (push, dst->height);
    148    PUSH_DATA (push, dst->depth);
    149    PUSH_DATA (push, dst->z);
    150    PUSH_DATA (push, (dst->y << 16) | (dst->x * cpp));
    151 
    152    BEGIN_NVC0(push, SUBC_COPY(0x0728), 6);
    153    PUSH_DATA (push, 0x1000 | src->tile_mode);
    154    PUSH_DATA (push, src->pitch);
    155    PUSH_DATA (push, src->height);
    156    PUSH_DATA (push, src->depth);
    157    PUSH_DATA (push, src->z);
    158    PUSH_DATA (push, (src->y << 16) | (src->x * cpp));
    159 
    160    BEGIN_NVC0(push, SUBC_COPY(0x0400), 8);
    161    PUSH_DATAh(push, src->bo->offset + src_base);
    162    PUSH_DATA (push, src->bo->offset + src_base);
    163    PUSH_DATAh(push, dst->bo->offset + dst_base);
    164    PUSH_DATA (push, dst->bo->offset + dst_base);
    165    PUSH_DATA (push, src->pitch);
    166    PUSH_DATA (push, dst->pitch);
    167    PUSH_DATA (push, nblocksx * cpp);
    168    PUSH_DATA (push, nblocksy);
    169 
    170    BEGIN_NVC0(push, SUBC_COPY(0x0300), 1);
    171    PUSH_DATA (push, exec);
    172 
    173    nouveau_bufctx_reset(bctx, 0);
    174 }
    175 
    176 void
    177 nvc0_m2mf_push_linear(struct nouveau_context *nv,
    178                       struct nouveau_bo *dst, unsigned offset, unsigned domain,
    179                       unsigned size, const void *data)
    180 {
    181    struct nvc0_context *nvc0 = nvc0_context(&nv->pipe);
    182    struct nouveau_pushbuf *push = nv->pushbuf;
    183    uint32_t *src = (uint32_t *)data;
    184    unsigned count = (size + 3) / 4;
    185 
    186    nouveau_bufctx_refn(nvc0->bufctx, 0, dst, domain | NOUVEAU_BO_WR);
    187    nouveau_pushbuf_bufctx(push, nvc0->bufctx);
    188    nouveau_pushbuf_validate(push);
    189 
    190    while (count) {
    191       unsigned nr;
    192 
    193       if (!PUSH_SPACE(push, 16))
    194          break;
    195       nr = PUSH_AVAIL(push);
    196       assert(nr >= 16);
    197       nr = MIN2(count, nr - 9);
    198       nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN);
    199 
    200       BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2);
    201       PUSH_DATAh(push, dst->offset + offset);
    202       PUSH_DATA (push, dst->offset + offset);
    203       BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2);
    204       PUSH_DATA (push, nr * 4);
    205       PUSH_DATA (push, 1);
    206       BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1);
    207       PUSH_DATA (push, 0x100111);
    208 
    209       /* must not be interrupted (trap on QUERY fence, 0x50 works however) */
    210       BEGIN_NIC0(push, NVC0_M2MF(DATA), nr);
    211       PUSH_DATAp(push, src, nr);
    212 
    213       count -= nr;
    214       src += nr;
    215       offset += nr * 4;
    216    }
    217 
    218    nouveau_bufctx_reset(nvc0->bufctx, 0);
    219 }
    220 
    221 void
    222 nve4_p2mf_push_linear(struct nouveau_context *nv,
    223                       struct nouveau_bo *dst, unsigned offset, unsigned domain,
    224                       unsigned size, const void *data)
    225 {
    226    struct nvc0_context *nvc0 = nvc0_context(&nv->pipe);
    227    struct nouveau_pushbuf *push = nv->pushbuf;
    228    uint32_t *src = (uint32_t *)data;
    229    unsigned count = (size + 3) / 4;
    230 
    231    nouveau_bufctx_refn(nvc0->bufctx, 0, dst, domain | NOUVEAU_BO_WR);
    232    nouveau_pushbuf_bufctx(push, nvc0->bufctx);
    233    nouveau_pushbuf_validate(push);
    234 
    235    while (count) {
    236       unsigned nr;
    237 
    238       if (!PUSH_SPACE(push, 16))
    239          break;
    240       nr = PUSH_AVAIL(push);
    241       assert(nr >= 16);
    242       nr = MIN2(count, nr - 8);
    243       nr = MIN2(nr, (NV04_PFIFO_MAX_PACKET_LEN - 1));
    244 
    245       BEGIN_NVC0(push, NVE4_P2MF(DST_ADDRESS_HIGH), 2);
    246       PUSH_DATAh(push, dst->offset + offset);
    247       PUSH_DATA (push, dst->offset + offset);
    248       BEGIN_NVC0(push, NVE4_P2MF(LINE_LENGTH_IN), 2);
    249       PUSH_DATA (push, nr * 4);
    250       PUSH_DATA (push, 1);
    251       /* must not be interrupted (trap on QUERY fence, 0x50 works however) */
    252       BEGIN_1IC0(push, NVE4_P2MF(EXEC), nr + 1);
    253       PUSH_DATA (push, 0x1001);
    254       PUSH_DATAp(push, src, nr);
    255 
    256       count -= nr;
    257       src += nr;
    258       offset += nr * 4;
    259    }
    260 
    261    nouveau_bufctx_reset(nvc0->bufctx, 0);
    262 }
    263 
    264 static void
    265 nvc0_m2mf_copy_linear(struct nouveau_context *nv,
    266                       struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom,
    267                       struct nouveau_bo *src, unsigned srcoff, unsigned srcdom,
    268                       unsigned size)
    269 {
    270    struct nouveau_pushbuf *push = nv->pushbuf;
    271    struct nouveau_bufctx *bctx = nvc0_context(&nv->pipe)->bufctx;
    272 
    273    nouveau_bufctx_refn(bctx, 0, src, srcdom | NOUVEAU_BO_RD);
    274    nouveau_bufctx_refn(bctx, 0, dst, dstdom | NOUVEAU_BO_WR);
    275    nouveau_pushbuf_bufctx(push, bctx);
    276    nouveau_pushbuf_validate(push);
    277 
    278    while (size) {
    279       unsigned bytes = MIN2(size, 1 << 17);
    280 
    281       BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2);
    282       PUSH_DATAh(push, dst->offset + dstoff);
    283       PUSH_DATA (push, dst->offset + dstoff);
    284       BEGIN_NVC0(push, NVC0_M2MF(OFFSET_IN_HIGH), 2);
    285       PUSH_DATAh(push, src->offset + srcoff);
    286       PUSH_DATA (push, src->offset + srcoff);
    287       BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2);
    288       PUSH_DATA (push, bytes);
    289       PUSH_DATA (push, 1);
    290       BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1);
    291       PUSH_DATA (push, (1 << NVC0_M2MF_EXEC_INC__SHIFT) |
    292                  NVC0_M2MF_EXEC_LINEAR_IN | NVC0_M2MF_EXEC_LINEAR_OUT);
    293 
    294       srcoff += bytes;
    295       dstoff += bytes;
    296       size -= bytes;
    297    }
    298 
    299    nouveau_bufctx_reset(bctx, 0);
    300 }
    301 
    302 static void
    303 nve4_m2mf_copy_linear(struct nouveau_context *nv,
    304                       struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom,
    305                       struct nouveau_bo *src, unsigned srcoff, unsigned srcdom,
    306                       unsigned size)
    307 {
    308    struct nouveau_pushbuf *push = nv->pushbuf;
    309    struct nouveau_bufctx *bctx = nvc0_context(&nv->pipe)->bufctx;
    310 
    311    nouveau_bufctx_refn(bctx, 0, src, srcdom | NOUVEAU_BO_RD);
    312    nouveau_bufctx_refn(bctx, 0, dst, dstdom | NOUVEAU_BO_WR);
    313    nouveau_pushbuf_bufctx(push, bctx);
    314    nouveau_pushbuf_validate(push);
    315 
    316    BEGIN_NVC0(push, SUBC_COPY(0x0400), 4);
    317    PUSH_DATAh(push, src->offset + srcoff);
    318    PUSH_DATA (push, src->offset + srcoff);
    319    PUSH_DATAh(push, dst->offset + dstoff);
    320    PUSH_DATA (push, dst->offset + dstoff);
    321    BEGIN_NVC0(push, SUBC_COPY(0x0418), 1);
    322    PUSH_DATA (push, size);
    323    BEGIN_NVC0(push, SUBC_COPY(0x0300), 1);
    324    PUSH_DATA (push, 0x186);
    325 
    326    nouveau_bufctx_reset(bctx, 0);
    327 }
    328 
    329 struct pipe_transfer *
    330 nvc0_miptree_transfer_new(struct pipe_context *pctx,
    331                           struct pipe_resource *res,
    332                           unsigned level,
    333                           unsigned usage,
    334                           const struct pipe_box *box)
    335 {
    336    struct nvc0_context *nvc0 = nvc0_context(pctx);
    337    struct nouveau_device *dev = nvc0->screen->base.device;
    338    struct nv50_miptree *mt = nv50_miptree(res);
    339    struct nvc0_transfer *tx;
    340    uint32_t size;
    341    int ret;
    342 
    343    if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
    344       return NULL;
    345 
    346    tx = CALLOC_STRUCT(nvc0_transfer);
    347    if (!tx)
    348       return NULL;
    349 
    350    pipe_resource_reference(&tx->base.resource, res);
    351 
    352    tx->base.level = level;
    353    tx->base.usage = usage;
    354    tx->base.box = *box;
    355 
    356    if (util_format_is_plain(res->format)) {
    357       tx->nblocksx = box->width << mt->ms_x;
    358       tx->nblocksy = box->height << mt->ms_y;
    359    } else {
    360       tx->nblocksx = util_format_get_nblocksx(res->format, box->width);
    361       tx->nblocksy = util_format_get_nblocksy(res->format, box->height);
    362    }
    363    tx->nlayers = box->depth;
    364 
    365    tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format);
    366    tx->base.layer_stride = tx->nblocksy * tx->base.stride;
    367 
    368    nv50_m2mf_rect_setup(&tx->rect[0], res, level, box->x, box->y, box->z);
    369 
    370    size = tx->base.layer_stride;
    371 
    372    ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
    373                         size * tx->nlayers, NULL, &tx->rect[1].bo);
    374    if (ret) {
    375       FREE(tx);
    376       return NULL;
    377    }
    378 
    379    tx->rect[1].cpp = tx->rect[0].cpp;
    380    tx->rect[1].width = tx->nblocksx;
    381    tx->rect[1].height = tx->nblocksy;
    382    tx->rect[1].depth = 1;
    383    tx->rect[1].pitch = tx->base.stride;
    384    tx->rect[1].domain = NOUVEAU_BO_GART;
    385 
    386    if (usage & PIPE_TRANSFER_READ) {
    387       unsigned base = tx->rect[0].base;
    388       unsigned z = tx->rect[0].z;
    389       unsigned i;
    390       for (i = 0; i < tx->nlayers; ++i) {
    391          nvc0->m2mf_copy_rect(nvc0, &tx->rect[1], &tx->rect[0],
    392                               tx->nblocksx, tx->nblocksy);
    393          if (mt->layout_3d)
    394             tx->rect[0].z++;
    395          else
    396             tx->rect[0].base += mt->layer_stride;
    397          tx->rect[1].base += size;
    398       }
    399       tx->rect[0].z = z;
    400       tx->rect[0].base = base;
    401       tx->rect[1].base = 0;
    402    }
    403 
    404    return &tx->base;
    405 }
    406 
    407 void
    408 nvc0_miptree_transfer_del(struct pipe_context *pctx,
    409                           struct pipe_transfer *transfer)
    410 {
    411    struct nvc0_context *nvc0 = nvc0_context(pctx);
    412    struct nvc0_transfer *tx = (struct nvc0_transfer *)transfer;
    413    struct nv50_miptree *mt = nv50_miptree(tx->base.resource);
    414    unsigned i;
    415 
    416    if (tx->base.usage & PIPE_TRANSFER_WRITE) {
    417       for (i = 0; i < tx->nlayers; ++i) {
    418          nvc0->m2mf_copy_rect(nvc0, &tx->rect[0], &tx->rect[1],
    419                               tx->nblocksx, tx->nblocksy);
    420          if (mt->layout_3d)
    421             tx->rect[0].z++;
    422          else
    423             tx->rect[0].base += mt->layer_stride;
    424          tx->rect[1].base += tx->nblocksy * tx->base.stride;
    425       }
    426    }
    427 
    428    nouveau_bo_ref(NULL, &tx->rect[1].bo);
    429    pipe_resource_reference(&transfer->resource, NULL);
    430 
    431    FREE(tx);
    432 }
    433 
    434 void *
    435 nvc0_miptree_transfer_map(struct pipe_context *pctx,
    436                           struct pipe_transfer *transfer)
    437 {
    438    struct nvc0_context *nvc0 = nvc0_context(pctx);
    439    struct nvc0_transfer *tx = (struct nvc0_transfer *)transfer;
    440    int ret;
    441    unsigned flags = 0;
    442 
    443    if (tx->rect[1].bo->map)
    444       return tx->rect[1].bo->map;
    445 
    446    if (transfer->usage & PIPE_TRANSFER_READ)
    447       flags = NOUVEAU_BO_RD;
    448    if (transfer->usage & PIPE_TRANSFER_WRITE)
    449       flags |= NOUVEAU_BO_WR;
    450 
    451    ret = nouveau_bo_map(tx->rect[1].bo, flags, nvc0->screen->base.client);
    452    if (ret)
    453       return NULL;
    454    return tx->rect[1].bo->map;
    455 }
    456 
    457 void
    458 nvc0_miptree_transfer_unmap(struct pipe_context *pctx,
    459                             struct pipe_transfer *transfer)
    460 {
    461 }
    462 
    463 void
    464 nvc0_cb_push(struct nouveau_context *nv,
    465              struct nouveau_bo *bo, unsigned domain,
    466              unsigned base, unsigned size,
    467              unsigned offset, unsigned words, const uint32_t *data)
    468 {
    469    struct nouveau_bufctx *bctx = nvc0_context(&nv->pipe)->bufctx;
    470    struct nouveau_pushbuf *push = nv->pushbuf;
    471 
    472    assert(!(offset & 3));
    473    size = align(size, 0x100);
    474 
    475    nouveau_bufctx_refn(bctx, 0, bo, NOUVEAU_BO_WR | domain);
    476    nouveau_pushbuf_bufctx(push, bctx);
    477    nouveau_pushbuf_validate(push);
    478 
    479    BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);
    480    PUSH_DATA (push, size);
    481    PUSH_DATAh(push, bo->offset + base);
    482    PUSH_DATA (push, bo->offset + base);
    483 
    484    while (words) {
    485       unsigned nr = PUSH_AVAIL(push);
    486       nr = MIN2(nr, words);
    487       nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN - 1);
    488 
    489       BEGIN_1IC0(push, NVC0_3D(CB_POS), nr + 1);
    490       PUSH_DATA (push, offset);
    491       PUSH_DATAp(push, data, nr);
    492 
    493       words -= nr;
    494       data += nr;
    495       offset += nr * 4;
    496    }
    497 
    498    nouveau_bufctx_reset(bctx, 0);
    499 }
    500 
    501 void
    502 nvc0_init_transfer_functions(struct nvc0_context *nvc0)
    503 {
    504    if (nvc0->screen->base.class_3d >= NVE4_3D_CLASS) {
    505       nvc0->m2mf_copy_rect = nve4_m2mf_transfer_rect;
    506       nvc0->base.copy_data = nve4_m2mf_copy_linear;
    507       nvc0->base.push_data = nve4_p2mf_push_linear;
    508    } else {
    509       nvc0->m2mf_copy_rect = nvc0_m2mf_transfer_rect;
    510       nvc0->base.copy_data = nvc0_m2mf_copy_linear;
    511       nvc0->base.push_data = nvc0_m2mf_push_linear;
    512    }
    513    nvc0->base.push_cb = nvc0_cb_push;
    514 }
    515