Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nvc0/nvc0_transfer.c
4574 views
1#include "util/format/u_format.h"23#include "nvc0/nvc0_context.h"45struct nvc0_transfer {6struct pipe_transfer base;7struct nv50_m2mf_rect rect[2];8uint32_t nblocksx;9uint16_t nblocksy;10uint16_t nlayers;11};1213static void14nvc0_m2mf_transfer_rect(struct nvc0_context *nvc0,15const struct nv50_m2mf_rect *dst,16const struct nv50_m2mf_rect *src,17uint32_t nblocksx, uint32_t nblocksy)18{19struct nouveau_pushbuf *push = nvc0->base.pushbuf;20struct nouveau_bufctx *bctx = nvc0->bufctx;21const int cpp = dst->cpp;22uint32_t src_ofst = src->base;23uint32_t dst_ofst = dst->base;24uint32_t height = nblocksy;25uint32_t sy = src->y;26uint32_t dy = dst->y;27uint32_t exec = (1 << 20);2829assert(dst->cpp == src->cpp);3031nouveau_bufctx_refn(bctx, 0, src->bo, src->domain | NOUVEAU_BO_RD);32nouveau_bufctx_refn(bctx, 0, dst->bo, dst->domain | NOUVEAU_BO_WR);33nouveau_pushbuf_bufctx(push, bctx);34nouveau_pushbuf_validate(push);3536if (nouveau_bo_memtype(src->bo)) {37BEGIN_NVC0(push, NVC0_M2MF(TILING_MODE_IN), 5);38PUSH_DATA (push, src->tile_mode);39PUSH_DATA (push, src->width * cpp);40PUSH_DATA (push, src->height);41PUSH_DATA (push, src->depth);42PUSH_DATA (push, src->z);43} else {44src_ofst += src->y * src->pitch + src->x * cpp;4546BEGIN_NVC0(push, NVC0_M2MF(PITCH_IN), 1);47PUSH_DATA (push, src->width * cpp);4849exec |= NVC0_M2MF_EXEC_LINEAR_IN;50}5152if (nouveau_bo_memtype(dst->bo)) {53BEGIN_NVC0(push, NVC0_M2MF(TILING_MODE_OUT), 5);54PUSH_DATA (push, dst->tile_mode);55PUSH_DATA (push, dst->width * cpp);56PUSH_DATA (push, dst->height);57PUSH_DATA (push, dst->depth);58PUSH_DATA (push, dst->z);59} else {60dst_ofst += dst->y * dst->pitch + dst->x * cpp;6162BEGIN_NVC0(push, NVC0_M2MF(PITCH_OUT), 1);63PUSH_DATA (push, dst->width * cpp);6465exec |= NVC0_M2MF_EXEC_LINEAR_OUT;66}6768while (height) {69int line_count = height > 2047 ? 2047 : height;7071BEGIN_NVC0(push, NVC0_M2MF(OFFSET_IN_HIGH), 2);72PUSH_DATAh(push, src->bo->offset + src_ofst);73PUSH_DATA (push, src->bo->offset + src_ofst);7475BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2);76PUSH_DATAh(push, dst->bo->offset + dst_ofst);77PUSH_DATA (push, dst->bo->offset + dst_ofst);7879if (!(exec & NVC0_M2MF_EXEC_LINEAR_IN)) {80BEGIN_NVC0(push, NVC0_M2MF(TILING_POSITION_IN_X), 2);81PUSH_DATA (push, src->x * cpp);82PUSH_DATA (push, sy);83} else {84src_ofst += line_count * src->pitch;85}86if (!(exec & NVC0_M2MF_EXEC_LINEAR_OUT)) {87BEGIN_NVC0(push, NVC0_M2MF(TILING_POSITION_OUT_X), 2);88PUSH_DATA (push, dst->x * cpp);89PUSH_DATA (push, dy);90} else {91dst_ofst += line_count * dst->pitch;92}9394BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2);95PUSH_DATA (push, nblocksx * cpp);96PUSH_DATA (push, line_count);97BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1);98PUSH_DATA (push, exec);99100height -= line_count;101sy += line_count;102dy += line_count;103}104105nouveau_bufctx_reset(bctx, 0);106}107108static void109nve4_m2mf_transfer_rect(struct nvc0_context *nvc0,110const struct nv50_m2mf_rect *dst,111const struct nv50_m2mf_rect *src,112uint32_t nblocksx, uint32_t nblocksy)113{114static const struct {115int cs;116int nc;117} cpbs[] = {118[ 1] = { 1, 1 },119[ 2] = { 1, 2 },120[ 3] = { 1, 3 },121[ 4] = { 1, 4 },122[ 6] = { 2, 3 },123[ 8] = { 2, 4 },124[ 9] = { 3, 3 },125[12] = { 3, 4 },126[16] = { 4, 4 },127};128struct nouveau_pushbuf *push = nvc0->base.pushbuf;129struct nouveau_bufctx *bctx = nvc0->bufctx;130uint32_t exec;131uint32_t src_base = src->base;132uint32_t dst_base = dst->base;133134assert(dst->cpp < ARRAY_SIZE(cpbs) && cpbs[dst->cpp].cs);135assert(dst->cpp == src->cpp);136137nouveau_bufctx_refn(bctx, 0, dst->bo, dst->domain | NOUVEAU_BO_WR);138nouveau_bufctx_refn(bctx, 0, src->bo, src->domain | NOUVEAU_BO_RD);139nouveau_pushbuf_bufctx(push, bctx);140nouveau_pushbuf_validate(push);141142exec = NVE4_COPY_EXEC_SWIZZLE_ENABLE | NVE4_COPY_EXEC_2D_ENABLE | NVE4_COPY_EXEC_FLUSH | NVE4_COPY_EXEC_COPY_MODE_NON_PIPELINED;143144BEGIN_NVC0(push, NVE4_COPY(SWIZZLE), 1);145PUSH_DATA (push, (cpbs[dst->cpp].nc - 1) << 24 |146(cpbs[src->cpp].nc - 1) << 20 |147(cpbs[src->cpp].cs - 1) << 16 |1483 << 12 /* DST_W = SRC_W */ |1492 << 8 /* DST_Z = SRC_Z */ |1501 << 4 /* DST_Y = SRC_Y */ |1510 << 0 /* DST_X = SRC_X */);152153if (nouveau_bo_memtype(dst->bo)) {154BEGIN_NVC0(push, NVE4_COPY(DST_BLOCK_DIMENSIONS), 6);155PUSH_DATA (push, dst->tile_mode | NVE4_COPY_SRC_BLOCK_DIMENSIONS_GOB_HEIGHT_FERMI_8);156PUSH_DATA (push, dst->width);157PUSH_DATA (push, dst->height);158PUSH_DATA (push, dst->depth);159PUSH_DATA (push, dst->z);160PUSH_DATA (push, (dst->y << 16) | dst->x);161} else {162assert(!dst->z);163dst_base += dst->y * dst->pitch + dst->x * dst->cpp;164exec |= NVE4_COPY_EXEC_DST_LAYOUT_BLOCKLINEAR;165}166167if (nouveau_bo_memtype(src->bo)) {168BEGIN_NVC0(push, NVE4_COPY(SRC_BLOCK_DIMENSIONS), 6);169PUSH_DATA (push, src->tile_mode | NVE4_COPY_SRC_BLOCK_DIMENSIONS_GOB_HEIGHT_FERMI_8);170PUSH_DATA (push, src->width);171PUSH_DATA (push, src->height);172PUSH_DATA (push, src->depth);173PUSH_DATA (push, src->z);174PUSH_DATA (push, (src->y << 16) | src->x);175} else {176assert(!src->z);177src_base += src->y * src->pitch + src->x * src->cpp;178exec |= NVE4_COPY_EXEC_SRC_LAYOUT_BLOCKLINEAR;179}180181BEGIN_NVC0(push, NVE4_COPY(SRC_ADDRESS_HIGH), 8);182PUSH_DATAh(push, src->bo->offset + src_base);183PUSH_DATA (push, src->bo->offset + src_base);184PUSH_DATAh(push, dst->bo->offset + dst_base);185PUSH_DATA (push, dst->bo->offset + dst_base);186PUSH_DATA (push, src->pitch);187PUSH_DATA (push, dst->pitch);188PUSH_DATA (push, nblocksx);189PUSH_DATA (push, nblocksy);190191BEGIN_NVC0(push, NVE4_COPY(EXEC), 1);192PUSH_DATA (push, exec);193194nouveau_bufctx_reset(bctx, 0);195}196197void198nvc0_m2mf_push_linear(struct nouveau_context *nv,199struct nouveau_bo *dst, unsigned offset, unsigned domain,200unsigned size, const void *data)201{202struct nvc0_context *nvc0 = nvc0_context(&nv->pipe);203struct nouveau_pushbuf *push = nv->pushbuf;204uint32_t *src = (uint32_t *)data;205unsigned count = (size + 3) / 4;206207nouveau_bufctx_refn(nvc0->bufctx, 0, dst, domain | NOUVEAU_BO_WR);208nouveau_pushbuf_bufctx(push, nvc0->bufctx);209nouveau_pushbuf_validate(push);210211while (count) {212unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN);213214if (!PUSH_SPACE(push, nr + 9))215break;216217BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2);218PUSH_DATAh(push, dst->offset + offset);219PUSH_DATA (push, dst->offset + offset);220BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2);221PUSH_DATA (push, MIN2(size, nr * 4));222PUSH_DATA (push, 1);223BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1);224PUSH_DATA (push, 0x100111);225226/* must not be interrupted (trap on QUERY fence, 0x50 works however) */227BEGIN_NIC0(push, NVC0_M2MF(DATA), nr);228PUSH_DATAp(push, src, nr);229230count -= nr;231src += nr;232offset += nr * 4;233size -= nr * 4;234}235236nouveau_bufctx_reset(nvc0->bufctx, 0);237}238239void240nve4_p2mf_push_linear(struct nouveau_context *nv,241struct nouveau_bo *dst, unsigned offset, unsigned domain,242unsigned size, const void *data)243{244struct nvc0_context *nvc0 = nvc0_context(&nv->pipe);245struct nouveau_pushbuf *push = nv->pushbuf;246uint32_t *src = (uint32_t *)data;247unsigned count = (size + 3) / 4;248249nouveau_bufctx_refn(nvc0->bufctx, 0, dst, domain | NOUVEAU_BO_WR);250nouveau_pushbuf_bufctx(push, nvc0->bufctx);251nouveau_pushbuf_validate(push);252253while (count) {254unsigned nr = MIN2(count, (NV04_PFIFO_MAX_PACKET_LEN - 1));255256if (!PUSH_SPACE(push, nr + 10))257break;258259BEGIN_NVC0(push, NVE4_P2MF(UPLOAD_DST_ADDRESS_HIGH), 2);260PUSH_DATAh(push, dst->offset + offset);261PUSH_DATA (push, dst->offset + offset);262BEGIN_NVC0(push, NVE4_P2MF(UPLOAD_LINE_LENGTH_IN), 2);263PUSH_DATA (push, MIN2(size, nr * 4));264PUSH_DATA (push, 1);265/* must not be interrupted (trap on QUERY fence, 0x50 works however) */266BEGIN_1IC0(push, NVE4_P2MF(UPLOAD_EXEC), nr + 1);267PUSH_DATA (push, 0x1001);268PUSH_DATAp(push, src, nr);269270count -= nr;271src += nr;272offset += nr * 4;273size -= nr * 4;274}275276nouveau_bufctx_reset(nvc0->bufctx, 0);277}278279static void280nvc0_m2mf_copy_linear(struct nouveau_context *nv,281struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom,282struct nouveau_bo *src, unsigned srcoff, unsigned srcdom,283unsigned size)284{285struct nouveau_pushbuf *push = nv->pushbuf;286struct nouveau_bufctx *bctx = nvc0_context(&nv->pipe)->bufctx;287288nouveau_bufctx_refn(bctx, 0, src, srcdom | NOUVEAU_BO_RD);289nouveau_bufctx_refn(bctx, 0, dst, dstdom | NOUVEAU_BO_WR);290nouveau_pushbuf_bufctx(push, bctx);291nouveau_pushbuf_validate(push);292293while (size) {294unsigned bytes = MIN2(size, 1 << 17);295296BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2);297PUSH_DATAh(push, dst->offset + dstoff);298PUSH_DATA (push, dst->offset + dstoff);299BEGIN_NVC0(push, NVC0_M2MF(OFFSET_IN_HIGH), 2);300PUSH_DATAh(push, src->offset + srcoff);301PUSH_DATA (push, src->offset + srcoff);302BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2);303PUSH_DATA (push, bytes);304PUSH_DATA (push, 1);305BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1);306PUSH_DATA (push, NVC0_M2MF_EXEC_QUERY_SHORT |307NVC0_M2MF_EXEC_LINEAR_IN | NVC0_M2MF_EXEC_LINEAR_OUT);308309srcoff += bytes;310dstoff += bytes;311size -= bytes;312}313314nouveau_bufctx_reset(bctx, 0);315}316317static void318nve4_m2mf_copy_linear(struct nouveau_context *nv,319struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom,320struct nouveau_bo *src, unsigned srcoff, unsigned srcdom,321unsigned size)322{323struct nouveau_pushbuf *push = nv->pushbuf;324struct nouveau_bufctx *bctx = nvc0_context(&nv->pipe)->bufctx;325326nouveau_bufctx_refn(bctx, 0, src, srcdom | NOUVEAU_BO_RD);327nouveau_bufctx_refn(bctx, 0, dst, dstdom | NOUVEAU_BO_WR);328nouveau_pushbuf_bufctx(push, bctx);329nouveau_pushbuf_validate(push);330331BEGIN_NVC0(push, NVE4_COPY(SRC_ADDRESS_HIGH), 4);332PUSH_DATAh(push, src->offset + srcoff);333PUSH_DATA (push, src->offset + srcoff);334PUSH_DATAh(push, dst->offset + dstoff);335PUSH_DATA (push, dst->offset + dstoff);336BEGIN_NVC0(push, NVE4_COPY(X_COUNT), 1);337PUSH_DATA (push, size);338BEGIN_NVC0(push, NVE4_COPY(EXEC), 1);339PUSH_DATA (push, NVE4_COPY_EXEC_COPY_MODE_NON_PIPELINED |340NVE4_COPY_EXEC_FLUSH |341NVE4_COPY_EXEC_SRC_LAYOUT_BLOCKLINEAR |342NVE4_COPY_EXEC_DST_LAYOUT_BLOCKLINEAR);343344nouveau_bufctx_reset(bctx, 0);345}346347348static inline bool349nvc0_mt_transfer_can_map_directly(struct nv50_miptree *mt)350{351if (mt->base.domain == NOUVEAU_BO_VRAM)352return false;353if (mt->base.base.usage != PIPE_USAGE_STAGING)354return false;355return !nouveau_bo_memtype(mt->base.bo);356}357358static inline bool359nvc0_mt_sync(struct nvc0_context *nvc0, struct nv50_miptree *mt, unsigned usage)360{361if (!mt->base.mm) {362uint32_t access = (usage & PIPE_MAP_WRITE) ?363NOUVEAU_BO_WR : NOUVEAU_BO_RD;364return !nouveau_bo_wait(mt->base.bo, access, nvc0->base.client);365}366if (usage & PIPE_MAP_WRITE)367return !mt->base.fence || nouveau_fence_wait(mt->base.fence, &nvc0->base.debug);368return !mt->base.fence_wr || nouveau_fence_wait(mt->base.fence_wr, &nvc0->base.debug);369}370371void *372nvc0_miptree_transfer_map(struct pipe_context *pctx,373struct pipe_resource *res,374unsigned level,375unsigned usage,376const struct pipe_box *box,377struct pipe_transfer **ptransfer)378{379struct nvc0_context *nvc0 = nvc0_context(pctx);380struct nouveau_device *dev = nvc0->screen->base.device;381struct nv50_miptree *mt = nv50_miptree(res);382struct nvc0_transfer *tx;383uint32_t size;384int ret;385unsigned flags = 0;386387if (nvc0_mt_transfer_can_map_directly(mt)) {388ret = !nvc0_mt_sync(nvc0, mt, usage);389if (!ret)390ret = nouveau_bo_map(mt->base.bo, 0, NULL);391if (ret &&392(usage & PIPE_MAP_DIRECTLY))393return NULL;394if (!ret)395usage |= PIPE_MAP_DIRECTLY;396} else397if (usage & PIPE_MAP_DIRECTLY)398return NULL;399400tx = CALLOC_STRUCT(nvc0_transfer);401if (!tx)402return NULL;403404pipe_resource_reference(&tx->base.resource, res);405406tx->base.level = level;407tx->base.usage = usage;408tx->base.box = *box;409410if (util_format_is_plain(res->format)) {411tx->nblocksx = box->width << mt->ms_x;412tx->nblocksy = box->height << mt->ms_y;413} else {414tx->nblocksx = util_format_get_nblocksx(res->format, box->width);415tx->nblocksy = util_format_get_nblocksy(res->format, box->height);416}417tx->nlayers = box->depth;418419if (usage & PIPE_MAP_DIRECTLY) {420tx->base.stride = mt->level[level].pitch;421tx->base.layer_stride = mt->layer_stride;422uint32_t offset = box->y * tx->base.stride +423util_format_get_stride(res->format, box->x);424if (!mt->layout_3d)425offset += mt->layer_stride * box->z;426else427offset += nvc0_mt_zslice_offset(mt, level, box->z);428*ptransfer = &tx->base;429return mt->base.bo->map + mt->base.offset + offset;430}431432tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format);433tx->base.layer_stride = tx->nblocksy * tx->base.stride;434435nv50_m2mf_rect_setup(&tx->rect[0], res, level, box->x, box->y, box->z);436437size = tx->base.layer_stride;438439ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,440size * tx->nlayers, NULL, &tx->rect[1].bo);441if (ret) {442pipe_resource_reference(&tx->base.resource, NULL);443FREE(tx);444return NULL;445}446447tx->rect[1].cpp = tx->rect[0].cpp;448tx->rect[1].width = tx->nblocksx;449tx->rect[1].height = tx->nblocksy;450tx->rect[1].depth = 1;451tx->rect[1].pitch = tx->base.stride;452tx->rect[1].domain = NOUVEAU_BO_GART;453454if (usage & PIPE_MAP_READ) {455unsigned base = tx->rect[0].base;456unsigned z = tx->rect[0].z;457unsigned i;458for (i = 0; i < tx->nlayers; ++i) {459nvc0->m2mf_copy_rect(nvc0, &tx->rect[1], &tx->rect[0],460tx->nblocksx, tx->nblocksy);461if (mt->layout_3d)462tx->rect[0].z++;463else464tx->rect[0].base += mt->layer_stride;465tx->rect[1].base += size;466}467tx->rect[0].z = z;468tx->rect[0].base = base;469tx->rect[1].base = 0;470}471472if (tx->rect[1].bo->map) {473*ptransfer = &tx->base;474return tx->rect[1].bo->map;475}476477if (usage & PIPE_MAP_READ)478flags = NOUVEAU_BO_RD;479if (usage & PIPE_MAP_WRITE)480flags |= NOUVEAU_BO_WR;481482ret = nouveau_bo_map(tx->rect[1].bo, flags, nvc0->screen->base.client);483if (ret) {484pipe_resource_reference(&tx->base.resource, NULL);485nouveau_bo_ref(NULL, &tx->rect[1].bo);486FREE(tx);487return NULL;488}489490*ptransfer = &tx->base;491return tx->rect[1].bo->map;492}493494void495nvc0_miptree_transfer_unmap(struct pipe_context *pctx,496struct pipe_transfer *transfer)497{498struct nvc0_context *nvc0 = nvc0_context(pctx);499struct nvc0_transfer *tx = (struct nvc0_transfer *)transfer;500struct nv50_miptree *mt = nv50_miptree(tx->base.resource);501unsigned i;502503if (tx->base.usage & PIPE_MAP_DIRECTLY) {504pipe_resource_reference(&transfer->resource, NULL);505506FREE(tx);507return;508}509510if (tx->base.usage & PIPE_MAP_WRITE) {511for (i = 0; i < tx->nlayers; ++i) {512nvc0->m2mf_copy_rect(nvc0, &tx->rect[0], &tx->rect[1],513tx->nblocksx, tx->nblocksy);514if (mt->layout_3d)515tx->rect[0].z++;516else517tx->rect[0].base += mt->layer_stride;518tx->rect[1].base += tx->nblocksy * tx->base.stride;519}520NOUVEAU_DRV_STAT(&nvc0->screen->base, tex_transfers_wr, 1);521522/* Allow the copies above to finish executing before freeing the source */523nouveau_fence_work(nvc0->screen->base.fence.current,524nouveau_fence_unref_bo, tx->rect[1].bo);525} else {526nouveau_bo_ref(NULL, &tx->rect[1].bo);527}528if (tx->base.usage & PIPE_MAP_READ)529NOUVEAU_DRV_STAT(&nvc0->screen->base, tex_transfers_rd, 1);530531pipe_resource_reference(&transfer->resource, NULL);532533FREE(tx);534}535536/* This happens rather often with DTD9/st. */537static void538nvc0_cb_push(struct nouveau_context *nv,539struct nv04_resource *res,540unsigned offset, unsigned words, const uint32_t *data)541{542struct nvc0_context *nvc0 = nvc0_context(&nv->pipe);543struct nvc0_constbuf *cb = NULL;544int s;545546/* Go through all the constbuf binding points of this buffer and try to547* find one which contains the region to be updated.548*/549for (s = 0; s < 6 && !cb; s++) {550uint16_t bindings = res->cb_bindings[s];551while (bindings) {552int i = ffs(bindings) - 1;553uint32_t cb_offset = nvc0->constbuf[s][i].offset;554555bindings &= ~(1 << i);556if (cb_offset <= offset &&557cb_offset + nvc0->constbuf[s][i].size >= offset + words * 4) {558cb = &nvc0->constbuf[s][i];559break;560}561}562}563564if (cb) {565nvc0_cb_bo_push(nv, res->bo, res->domain,566res->offset + cb->offset, cb->size,567offset - cb->offset, words, data);568} else {569nv->push_data(nv, res->bo, res->offset + offset, res->domain,570words * 4, data);571}572}573574void575nvc0_cb_bo_push(struct nouveau_context *nv,576struct nouveau_bo *bo, unsigned domain,577unsigned base, unsigned size,578unsigned offset, unsigned words, const uint32_t *data)579{580struct nouveau_pushbuf *push = nv->pushbuf;581582NOUVEAU_DRV_STAT(nv->screen, constbuf_upload_count, 1);583NOUVEAU_DRV_STAT(nv->screen, constbuf_upload_bytes, words * 4);584585assert(!(offset & 3));586size = align(size, 0x100);587588assert(offset < size);589assert(offset + words * 4 <= size);590591BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);592PUSH_DATA (push, size);593PUSH_DATAh(push, bo->offset + base);594PUSH_DATA (push, bo->offset + base);595596while (words) {597unsigned nr = MIN2(words, NV04_PFIFO_MAX_PACKET_LEN - 1);598599PUSH_SPACE(push, nr + 2);600PUSH_REFN (push, bo, NOUVEAU_BO_WR | domain);601BEGIN_1IC0(push, NVC0_3D(CB_POS), nr + 1);602PUSH_DATA (push, offset);603PUSH_DATAp(push, data, nr);604605words -= nr;606data += nr;607offset += nr * 4;608}609}610611void612nvc0_init_transfer_functions(struct nvc0_context *nvc0)613{614if (nvc0->screen->base.class_3d >= NVE4_3D_CLASS) {615nvc0->m2mf_copy_rect = nve4_m2mf_transfer_rect;616nvc0->base.copy_data = nve4_m2mf_copy_linear;617nvc0->base.push_data = nve4_p2mf_push_linear;618} else {619nvc0->m2mf_copy_rect = nvc0_m2mf_transfer_rect;620nvc0->base.copy_data = nvc0_m2mf_copy_linear;621nvc0->base.push_data = nvc0_m2mf_push_linear;622}623nvc0->base.push_cb = nvc0_cb_push;624}625626627