1bf215546Sopenharmony_ci 2bf215546Sopenharmony_ci#include "util/format/u_format.h" 3bf215546Sopenharmony_ci 4bf215546Sopenharmony_ci#include "nvc0/nvc0_context.h" 5bf215546Sopenharmony_ci 6bf215546Sopenharmony_cistruct nvc0_transfer { 7bf215546Sopenharmony_ci struct pipe_transfer base; 8bf215546Sopenharmony_ci struct nv50_m2mf_rect rect[2]; 9bf215546Sopenharmony_ci uint32_t nblocksx; 10bf215546Sopenharmony_ci uint16_t nblocksy; 11bf215546Sopenharmony_ci uint16_t nlayers; 12bf215546Sopenharmony_ci}; 13bf215546Sopenharmony_ci 14bf215546Sopenharmony_cistatic void 15bf215546Sopenharmony_cinvc0_m2mf_transfer_rect(struct nvc0_context *nvc0, 16bf215546Sopenharmony_ci const struct nv50_m2mf_rect *dst, 17bf215546Sopenharmony_ci const struct nv50_m2mf_rect *src, 18bf215546Sopenharmony_ci uint32_t nblocksx, uint32_t nblocksy) 19bf215546Sopenharmony_ci{ 20bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nvc0->base.pushbuf; 21bf215546Sopenharmony_ci struct nouveau_bufctx *bctx = nvc0->bufctx; 22bf215546Sopenharmony_ci const int cpp = dst->cpp; 23bf215546Sopenharmony_ci uint32_t src_ofst = src->base; 24bf215546Sopenharmony_ci uint32_t dst_ofst = dst->base; 25bf215546Sopenharmony_ci uint32_t height = nblocksy; 26bf215546Sopenharmony_ci uint32_t sy = src->y; 27bf215546Sopenharmony_ci uint32_t dy = dst->y; 28bf215546Sopenharmony_ci uint32_t exec = (1 << 20); 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci assert(dst->cpp == src->cpp); 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci nouveau_bufctx_refn(bctx, 0, src->bo, src->domain | NOUVEAU_BO_RD); 33bf215546Sopenharmony_ci nouveau_bufctx_refn(bctx, 0, dst->bo, dst->domain | NOUVEAU_BO_WR); 34bf215546Sopenharmony_ci nouveau_pushbuf_bufctx(push, bctx); 35bf215546Sopenharmony_ci nouveau_pushbuf_validate(push); 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci if (nouveau_bo_memtype(src->bo)) { 38bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(TILING_MODE_IN), 5); 39bf215546Sopenharmony_ci PUSH_DATA (push, src->tile_mode); 40bf215546Sopenharmony_ci PUSH_DATA (push, src->width * cpp); 41bf215546Sopenharmony_ci PUSH_DATA (push, src->height); 42bf215546Sopenharmony_ci PUSH_DATA (push, src->depth); 43bf215546Sopenharmony_ci PUSH_DATA (push, src->z); 44bf215546Sopenharmony_ci } else { 45bf215546Sopenharmony_ci src_ofst += src->y * src->pitch + src->x * cpp; 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(PITCH_IN), 1); 48bf215546Sopenharmony_ci PUSH_DATA (push, src->width * cpp); 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci exec |= NVC0_M2MF_EXEC_LINEAR_IN; 51bf215546Sopenharmony_ci } 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_ci if (nouveau_bo_memtype(dst->bo)) { 54bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(TILING_MODE_OUT), 5); 55bf215546Sopenharmony_ci PUSH_DATA (push, dst->tile_mode); 56bf215546Sopenharmony_ci PUSH_DATA (push, dst->width * cpp); 57bf215546Sopenharmony_ci PUSH_DATA (push, dst->height); 58bf215546Sopenharmony_ci PUSH_DATA (push, dst->depth); 59bf215546Sopenharmony_ci PUSH_DATA (push, dst->z); 60bf215546Sopenharmony_ci } else { 61bf215546Sopenharmony_ci dst_ofst += dst->y * dst->pitch + dst->x * cpp; 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(PITCH_OUT), 1); 64bf215546Sopenharmony_ci PUSH_DATA (push, dst->width * cpp); 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci exec |= NVC0_M2MF_EXEC_LINEAR_OUT; 67bf215546Sopenharmony_ci } 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci while (height) { 70bf215546Sopenharmony_ci int line_count = height > 2047 ? 2047 : height; 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(OFFSET_IN_HIGH), 2); 73bf215546Sopenharmony_ci PUSH_DATAh(push, src->bo->offset + src_ofst); 74bf215546Sopenharmony_ci PUSH_DATA (push, src->bo->offset + src_ofst); 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2); 77bf215546Sopenharmony_ci PUSH_DATAh(push, dst->bo->offset + dst_ofst); 78bf215546Sopenharmony_ci PUSH_DATA (push, dst->bo->offset + dst_ofst); 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci if (!(exec & NVC0_M2MF_EXEC_LINEAR_IN)) { 81bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(TILING_POSITION_IN_X), 2); 82bf215546Sopenharmony_ci PUSH_DATA (push, src->x * cpp); 83bf215546Sopenharmony_ci PUSH_DATA (push, sy); 84bf215546Sopenharmony_ci } else { 85bf215546Sopenharmony_ci src_ofst += line_count * src->pitch; 86bf215546Sopenharmony_ci } 87bf215546Sopenharmony_ci if (!(exec & NVC0_M2MF_EXEC_LINEAR_OUT)) { 88bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(TILING_POSITION_OUT_X), 2); 89bf215546Sopenharmony_ci PUSH_DATA (push, dst->x * cpp); 90bf215546Sopenharmony_ci PUSH_DATA (push, dy); 91bf215546Sopenharmony_ci } else { 92bf215546Sopenharmony_ci dst_ofst += line_count * dst->pitch; 93bf215546Sopenharmony_ci } 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2); 96bf215546Sopenharmony_ci PUSH_DATA (push, nblocksx * cpp); 97bf215546Sopenharmony_ci PUSH_DATA (push, line_count); 98bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1); 99bf215546Sopenharmony_ci PUSH_DATA (push, exec); 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci height -= line_count; 102bf215546Sopenharmony_ci sy += line_count; 103bf215546Sopenharmony_ci dy += line_count; 104bf215546Sopenharmony_ci } 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci nouveau_bufctx_reset(bctx, 0); 107bf215546Sopenharmony_ci} 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_cistatic void 110bf215546Sopenharmony_cinve4_m2mf_transfer_rect(struct nvc0_context *nvc0, 111bf215546Sopenharmony_ci const struct nv50_m2mf_rect *dst, 112bf215546Sopenharmony_ci const struct nv50_m2mf_rect *src, 113bf215546Sopenharmony_ci uint32_t nblocksx, uint32_t nblocksy) 114bf215546Sopenharmony_ci{ 115bf215546Sopenharmony_ci static const struct { 116bf215546Sopenharmony_ci int cs; 117bf215546Sopenharmony_ci int nc; 118bf215546Sopenharmony_ci } cpbs[] = { 119bf215546Sopenharmony_ci [ 1] = { 1, 1 }, 120bf215546Sopenharmony_ci [ 2] = { 1, 2 }, 121bf215546Sopenharmony_ci [ 3] = { 1, 3 }, 122bf215546Sopenharmony_ci [ 4] = { 1, 4 }, 123bf215546Sopenharmony_ci [ 6] = { 2, 3 }, 124bf215546Sopenharmony_ci [ 8] = { 2, 4 }, 125bf215546Sopenharmony_ci [ 9] = { 3, 3 }, 126bf215546Sopenharmony_ci [12] = { 3, 4 }, 127bf215546Sopenharmony_ci [16] = { 4, 4 }, 128bf215546Sopenharmony_ci }; 129bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nvc0->base.pushbuf; 130bf215546Sopenharmony_ci struct nouveau_bufctx *bctx = nvc0->bufctx; 131bf215546Sopenharmony_ci uint32_t exec; 132bf215546Sopenharmony_ci uint32_t src_base = src->base; 133bf215546Sopenharmony_ci uint32_t dst_base = dst->base; 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci assert(dst->cpp < ARRAY_SIZE(cpbs) && cpbs[dst->cpp].cs); 136bf215546Sopenharmony_ci assert(dst->cpp == src->cpp); 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci nouveau_bufctx_refn(bctx, 0, dst->bo, dst->domain | NOUVEAU_BO_WR); 139bf215546Sopenharmony_ci nouveau_bufctx_refn(bctx, 0, src->bo, src->domain | NOUVEAU_BO_RD); 140bf215546Sopenharmony_ci nouveau_pushbuf_bufctx(push, bctx); 141bf215546Sopenharmony_ci nouveau_pushbuf_validate(push); 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci exec = NVE4_COPY_EXEC_SWIZZLE_ENABLE | NVE4_COPY_EXEC_2D_ENABLE | NVE4_COPY_EXEC_FLUSH | NVE4_COPY_EXEC_COPY_MODE_NON_PIPELINED; 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci BEGIN_NVC0(push, NVE4_COPY(SWIZZLE), 1); 146bf215546Sopenharmony_ci PUSH_DATA (push, (cpbs[dst->cpp].nc - 1) << 24 | 147bf215546Sopenharmony_ci (cpbs[src->cpp].nc - 1) << 20 | 148bf215546Sopenharmony_ci (cpbs[src->cpp].cs - 1) << 16 | 149bf215546Sopenharmony_ci 3 << 12 /* DST_W = SRC_W */ | 150bf215546Sopenharmony_ci 2 << 8 /* DST_Z = SRC_Z */ | 151bf215546Sopenharmony_ci 1 << 4 /* DST_Y = SRC_Y */ | 152bf215546Sopenharmony_ci 0 << 0 /* DST_X = SRC_X */); 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci if (nouveau_bo_memtype(dst->bo)) { 155bf215546Sopenharmony_ci BEGIN_NVC0(push, NVE4_COPY(DST_BLOCK_DIMENSIONS), 6); 156bf215546Sopenharmony_ci PUSH_DATA (push, dst->tile_mode | NVE4_COPY_SRC_BLOCK_DIMENSIONS_GOB_HEIGHT_FERMI_8); 157bf215546Sopenharmony_ci PUSH_DATA (push, dst->width); 158bf215546Sopenharmony_ci PUSH_DATA (push, dst->height); 159bf215546Sopenharmony_ci PUSH_DATA (push, dst->depth); 160bf215546Sopenharmony_ci PUSH_DATA (push, dst->z); 161bf215546Sopenharmony_ci PUSH_DATA (push, (dst->y << 16) | dst->x); 162bf215546Sopenharmony_ci } else { 163bf215546Sopenharmony_ci assert(!dst->z); 164bf215546Sopenharmony_ci dst_base += dst->y * dst->pitch + dst->x * dst->cpp; 165bf215546Sopenharmony_ci exec |= NVE4_COPY_EXEC_DST_LAYOUT_BLOCKLINEAR; 166bf215546Sopenharmony_ci } 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci if (nouveau_bo_memtype(src->bo)) { 169bf215546Sopenharmony_ci BEGIN_NVC0(push, NVE4_COPY(SRC_BLOCK_DIMENSIONS), 6); 170bf215546Sopenharmony_ci PUSH_DATA (push, src->tile_mode | NVE4_COPY_SRC_BLOCK_DIMENSIONS_GOB_HEIGHT_FERMI_8); 171bf215546Sopenharmony_ci PUSH_DATA (push, src->width); 172bf215546Sopenharmony_ci PUSH_DATA (push, src->height); 173bf215546Sopenharmony_ci PUSH_DATA (push, src->depth); 174bf215546Sopenharmony_ci PUSH_DATA (push, src->z); 175bf215546Sopenharmony_ci PUSH_DATA (push, (src->y << 16) | src->x); 176bf215546Sopenharmony_ci } else { 177bf215546Sopenharmony_ci assert(!src->z); 178bf215546Sopenharmony_ci src_base += src->y * src->pitch + src->x * src->cpp; 179bf215546Sopenharmony_ci exec |= NVE4_COPY_EXEC_SRC_LAYOUT_BLOCKLINEAR; 180bf215546Sopenharmony_ci } 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci BEGIN_NVC0(push, NVE4_COPY(SRC_ADDRESS_HIGH), 8); 183bf215546Sopenharmony_ci PUSH_DATAh(push, src->bo->offset + src_base); 184bf215546Sopenharmony_ci PUSH_DATA (push, src->bo->offset + src_base); 185bf215546Sopenharmony_ci PUSH_DATAh(push, dst->bo->offset + dst_base); 186bf215546Sopenharmony_ci PUSH_DATA (push, dst->bo->offset + dst_base); 187bf215546Sopenharmony_ci PUSH_DATA (push, src->pitch); 188bf215546Sopenharmony_ci PUSH_DATA (push, dst->pitch); 189bf215546Sopenharmony_ci PUSH_DATA (push, nblocksx); 190bf215546Sopenharmony_ci PUSH_DATA (push, nblocksy); 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci BEGIN_NVC0(push, NVE4_COPY(EXEC), 1); 193bf215546Sopenharmony_ci PUSH_DATA (push, exec); 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci nouveau_bufctx_reset(bctx, 0); 196bf215546Sopenharmony_ci} 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_civoid 199bf215546Sopenharmony_cinvc0_m2mf_push_linear(struct nouveau_context *nv, 200bf215546Sopenharmony_ci struct nouveau_bo *dst, unsigned offset, unsigned domain, 201bf215546Sopenharmony_ci unsigned size, const void *data) 202bf215546Sopenharmony_ci{ 203bf215546Sopenharmony_ci struct nvc0_context *nvc0 = nvc0_context(&nv->pipe); 204bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nv->pushbuf; 205bf215546Sopenharmony_ci uint32_t *src = (uint32_t *)data; 206bf215546Sopenharmony_ci unsigned count = (size + 3) / 4; 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci nouveau_bufctx_refn(nvc0->bufctx, 0, dst, domain | NOUVEAU_BO_WR); 209bf215546Sopenharmony_ci nouveau_pushbuf_bufctx(push, nvc0->bufctx); 210bf215546Sopenharmony_ci nouveau_pushbuf_validate(push); 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci while (count) { 213bf215546Sopenharmony_ci unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN); 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_ci if (!PUSH_SPACE(push, nr + 9)) 216bf215546Sopenharmony_ci break; 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2); 219bf215546Sopenharmony_ci PUSH_DATAh(push, dst->offset + offset); 220bf215546Sopenharmony_ci PUSH_DATA (push, dst->offset + offset); 221bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2); 222bf215546Sopenharmony_ci PUSH_DATA (push, MIN2(size, nr * 4)); 223bf215546Sopenharmony_ci PUSH_DATA (push, 1); 224bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1); 225bf215546Sopenharmony_ci PUSH_DATA (push, 0x100111); 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci /* must not be interrupted (trap on QUERY fence, 0x50 works however) */ 228bf215546Sopenharmony_ci BEGIN_NIC0(push, NVC0_M2MF(DATA), nr); 229bf215546Sopenharmony_ci PUSH_DATAp(push, src, nr); 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci count -= nr; 232bf215546Sopenharmony_ci src += nr; 233bf215546Sopenharmony_ci offset += nr * 4; 234bf215546Sopenharmony_ci size -= nr * 4; 235bf215546Sopenharmony_ci } 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci nouveau_bufctx_reset(nvc0->bufctx, 0); 238bf215546Sopenharmony_ci} 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_civoid 241bf215546Sopenharmony_cinve4_p2mf_push_linear(struct nouveau_context *nv, 242bf215546Sopenharmony_ci struct nouveau_bo *dst, unsigned offset, unsigned domain, 243bf215546Sopenharmony_ci unsigned size, const void *data) 244bf215546Sopenharmony_ci{ 245bf215546Sopenharmony_ci struct nvc0_context *nvc0 = nvc0_context(&nv->pipe); 246bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nv->pushbuf; 247bf215546Sopenharmony_ci uint32_t *src = (uint32_t *)data; 248bf215546Sopenharmony_ci unsigned count = (size + 3) / 4; 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_ci nouveau_bufctx_refn(nvc0->bufctx, 0, dst, domain | NOUVEAU_BO_WR); 251bf215546Sopenharmony_ci nouveau_pushbuf_bufctx(push, nvc0->bufctx); 252bf215546Sopenharmony_ci nouveau_pushbuf_validate(push); 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci while (count) { 255bf215546Sopenharmony_ci unsigned nr = MIN2(count, (NV04_PFIFO_MAX_PACKET_LEN - 1)); 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_ci if (!PUSH_SPACE(push, nr + 10)) 258bf215546Sopenharmony_ci break; 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci BEGIN_NVC0(push, NVE4_P2MF(UPLOAD_DST_ADDRESS_HIGH), 2); 261bf215546Sopenharmony_ci PUSH_DATAh(push, dst->offset + offset); 262bf215546Sopenharmony_ci PUSH_DATA (push, dst->offset + offset); 263bf215546Sopenharmony_ci BEGIN_NVC0(push, NVE4_P2MF(UPLOAD_LINE_LENGTH_IN), 2); 264bf215546Sopenharmony_ci PUSH_DATA (push, MIN2(size, nr * 4)); 265bf215546Sopenharmony_ci PUSH_DATA (push, 1); 266bf215546Sopenharmony_ci /* must not be interrupted (trap on QUERY fence, 0x50 works however) */ 267bf215546Sopenharmony_ci BEGIN_1IC0(push, NVE4_P2MF(UPLOAD_EXEC), nr + 1); 268bf215546Sopenharmony_ci PUSH_DATA (push, 0x1001); 269bf215546Sopenharmony_ci PUSH_DATAp(push, src, nr); 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci count -= nr; 272bf215546Sopenharmony_ci src += nr; 273bf215546Sopenharmony_ci offset += nr * 4; 274bf215546Sopenharmony_ci size -= nr * 4; 275bf215546Sopenharmony_ci } 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci nouveau_bufctx_reset(nvc0->bufctx, 0); 278bf215546Sopenharmony_ci} 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_cistatic void 281bf215546Sopenharmony_cinvc0_m2mf_copy_linear(struct nouveau_context *nv, 282bf215546Sopenharmony_ci struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom, 283bf215546Sopenharmony_ci struct nouveau_bo *src, unsigned srcoff, unsigned srcdom, 284bf215546Sopenharmony_ci unsigned size) 285bf215546Sopenharmony_ci{ 286bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nv->pushbuf; 287bf215546Sopenharmony_ci struct nouveau_bufctx *bctx = nvc0_context(&nv->pipe)->bufctx; 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci nouveau_bufctx_refn(bctx, 0, src, srcdom | NOUVEAU_BO_RD); 290bf215546Sopenharmony_ci nouveau_bufctx_refn(bctx, 0, dst, dstdom | NOUVEAU_BO_WR); 291bf215546Sopenharmony_ci nouveau_pushbuf_bufctx(push, bctx); 292bf215546Sopenharmony_ci nouveau_pushbuf_validate(push); 293bf215546Sopenharmony_ci 294bf215546Sopenharmony_ci while (size) { 295bf215546Sopenharmony_ci unsigned bytes = MIN2(size, 1 << 17); 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2); 298bf215546Sopenharmony_ci PUSH_DATAh(push, dst->offset + dstoff); 299bf215546Sopenharmony_ci PUSH_DATA (push, dst->offset + dstoff); 300bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(OFFSET_IN_HIGH), 2); 301bf215546Sopenharmony_ci PUSH_DATAh(push, src->offset + srcoff); 302bf215546Sopenharmony_ci PUSH_DATA (push, src->offset + srcoff); 303bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2); 304bf215546Sopenharmony_ci PUSH_DATA (push, bytes); 305bf215546Sopenharmony_ci PUSH_DATA (push, 1); 306bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1); 307bf215546Sopenharmony_ci PUSH_DATA (push, NVC0_M2MF_EXEC_QUERY_SHORT | 308bf215546Sopenharmony_ci NVC0_M2MF_EXEC_LINEAR_IN | NVC0_M2MF_EXEC_LINEAR_OUT); 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci srcoff += bytes; 311bf215546Sopenharmony_ci dstoff += bytes; 312bf215546Sopenharmony_ci size -= bytes; 313bf215546Sopenharmony_ci } 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_ci nouveau_bufctx_reset(bctx, 0); 316bf215546Sopenharmony_ci} 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_cistatic void 319bf215546Sopenharmony_cinve4_m2mf_copy_linear(struct nouveau_context *nv, 320bf215546Sopenharmony_ci struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom, 321bf215546Sopenharmony_ci struct nouveau_bo *src, unsigned srcoff, unsigned srcdom, 322bf215546Sopenharmony_ci unsigned size) 323bf215546Sopenharmony_ci{ 324bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nv->pushbuf; 325bf215546Sopenharmony_ci struct nouveau_bufctx *bctx = nvc0_context(&nv->pipe)->bufctx; 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci nouveau_bufctx_refn(bctx, 0, src, srcdom | NOUVEAU_BO_RD); 328bf215546Sopenharmony_ci nouveau_bufctx_refn(bctx, 0, dst, dstdom | NOUVEAU_BO_WR); 329bf215546Sopenharmony_ci nouveau_pushbuf_bufctx(push, bctx); 330bf215546Sopenharmony_ci nouveau_pushbuf_validate(push); 331bf215546Sopenharmony_ci 332bf215546Sopenharmony_ci BEGIN_NVC0(push, NVE4_COPY(SRC_ADDRESS_HIGH), 4); 333bf215546Sopenharmony_ci PUSH_DATAh(push, src->offset + srcoff); 334bf215546Sopenharmony_ci PUSH_DATA (push, src->offset + srcoff); 335bf215546Sopenharmony_ci PUSH_DATAh(push, dst->offset + dstoff); 336bf215546Sopenharmony_ci PUSH_DATA (push, dst->offset + dstoff); 337bf215546Sopenharmony_ci BEGIN_NVC0(push, NVE4_COPY(X_COUNT), 1); 338bf215546Sopenharmony_ci PUSH_DATA (push, size); 339bf215546Sopenharmony_ci BEGIN_NVC0(push, NVE4_COPY(EXEC), 1); 340bf215546Sopenharmony_ci PUSH_DATA (push, NVE4_COPY_EXEC_COPY_MODE_NON_PIPELINED | 341bf215546Sopenharmony_ci NVE4_COPY_EXEC_FLUSH | 342bf215546Sopenharmony_ci NVE4_COPY_EXEC_SRC_LAYOUT_BLOCKLINEAR | 343bf215546Sopenharmony_ci NVE4_COPY_EXEC_DST_LAYOUT_BLOCKLINEAR); 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci nouveau_bufctx_reset(bctx, 0); 346bf215546Sopenharmony_ci} 347bf215546Sopenharmony_ci 348bf215546Sopenharmony_ci 349bf215546Sopenharmony_cistatic inline bool 350bf215546Sopenharmony_cinvc0_mt_transfer_can_map_directly(struct nv50_miptree *mt) 351bf215546Sopenharmony_ci{ 352bf215546Sopenharmony_ci if (mt->base.domain == NOUVEAU_BO_VRAM) 353bf215546Sopenharmony_ci return false; 354bf215546Sopenharmony_ci if (mt->base.base.usage != PIPE_USAGE_STAGING) 355bf215546Sopenharmony_ci return false; 356bf215546Sopenharmony_ci return !nouveau_bo_memtype(mt->base.bo); 357bf215546Sopenharmony_ci} 358bf215546Sopenharmony_ci 359bf215546Sopenharmony_cistatic inline bool 360bf215546Sopenharmony_cinvc0_mt_sync(struct nvc0_context *nvc0, struct nv50_miptree *mt, unsigned usage) 361bf215546Sopenharmony_ci{ 362bf215546Sopenharmony_ci if (!mt->base.mm) { 363bf215546Sopenharmony_ci uint32_t access = (usage & PIPE_MAP_WRITE) ? 364bf215546Sopenharmony_ci NOUVEAU_BO_WR : NOUVEAU_BO_RD; 365bf215546Sopenharmony_ci return !nouveau_bo_wait(mt->base.bo, access, nvc0->base.client); 366bf215546Sopenharmony_ci } 367bf215546Sopenharmony_ci if (usage & PIPE_MAP_WRITE) 368bf215546Sopenharmony_ci return !mt->base.fence || nouveau_fence_wait(mt->base.fence, &nvc0->base.debug); 369bf215546Sopenharmony_ci return !mt->base.fence_wr || nouveau_fence_wait(mt->base.fence_wr, &nvc0->base.debug); 370bf215546Sopenharmony_ci} 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_civoid * 373bf215546Sopenharmony_cinvc0_miptree_transfer_map(struct pipe_context *pctx, 374bf215546Sopenharmony_ci struct pipe_resource *res, 375bf215546Sopenharmony_ci unsigned level, 376bf215546Sopenharmony_ci unsigned usage, 377bf215546Sopenharmony_ci const struct pipe_box *box, 378bf215546Sopenharmony_ci struct pipe_transfer **ptransfer) 379bf215546Sopenharmony_ci{ 380bf215546Sopenharmony_ci struct nvc0_context *nvc0 = nvc0_context(pctx); 381bf215546Sopenharmony_ci struct nouveau_device *dev = nvc0->screen->base.device; 382bf215546Sopenharmony_ci struct nv50_miptree *mt = nv50_miptree(res); 383bf215546Sopenharmony_ci struct nvc0_transfer *tx; 384bf215546Sopenharmony_ci uint32_t size; 385bf215546Sopenharmony_ci int ret; 386bf215546Sopenharmony_ci unsigned flags = 0; 387bf215546Sopenharmony_ci 388bf215546Sopenharmony_ci if (nvc0_mt_transfer_can_map_directly(mt)) { 389bf215546Sopenharmony_ci ret = !nvc0_mt_sync(nvc0, mt, usage); 390bf215546Sopenharmony_ci if (!ret) 391bf215546Sopenharmony_ci ret = nouveau_bo_map(mt->base.bo, 0, NULL); 392bf215546Sopenharmony_ci if (ret && 393bf215546Sopenharmony_ci (usage & PIPE_MAP_DIRECTLY)) 394bf215546Sopenharmony_ci return NULL; 395bf215546Sopenharmony_ci if (!ret) 396bf215546Sopenharmony_ci usage |= PIPE_MAP_DIRECTLY; 397bf215546Sopenharmony_ci } else 398bf215546Sopenharmony_ci if (usage & PIPE_MAP_DIRECTLY) 399bf215546Sopenharmony_ci return NULL; 400bf215546Sopenharmony_ci 401bf215546Sopenharmony_ci tx = CALLOC_STRUCT(nvc0_transfer); 402bf215546Sopenharmony_ci if (!tx) 403bf215546Sopenharmony_ci return NULL; 404bf215546Sopenharmony_ci 405bf215546Sopenharmony_ci pipe_resource_reference(&tx->base.resource, res); 406bf215546Sopenharmony_ci 407bf215546Sopenharmony_ci tx->base.level = level; 408bf215546Sopenharmony_ci tx->base.usage = usage; 409bf215546Sopenharmony_ci tx->base.box = *box; 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci if (util_format_is_plain(res->format)) { 412bf215546Sopenharmony_ci tx->nblocksx = box->width << mt->ms_x; 413bf215546Sopenharmony_ci tx->nblocksy = box->height << mt->ms_y; 414bf215546Sopenharmony_ci } else { 415bf215546Sopenharmony_ci tx->nblocksx = util_format_get_nblocksx(res->format, box->width); 416bf215546Sopenharmony_ci tx->nblocksy = util_format_get_nblocksy(res->format, box->height); 417bf215546Sopenharmony_ci } 418bf215546Sopenharmony_ci tx->nlayers = box->depth; 419bf215546Sopenharmony_ci 420bf215546Sopenharmony_ci if (usage & PIPE_MAP_DIRECTLY) { 421bf215546Sopenharmony_ci tx->base.stride = mt->level[level].pitch; 422bf215546Sopenharmony_ci tx->base.layer_stride = mt->layer_stride; 423bf215546Sopenharmony_ci uint32_t offset = box->y * tx->base.stride + 424bf215546Sopenharmony_ci util_format_get_stride(res->format, box->x); 425bf215546Sopenharmony_ci if (!mt->layout_3d) 426bf215546Sopenharmony_ci offset += mt->layer_stride * box->z; 427bf215546Sopenharmony_ci else 428bf215546Sopenharmony_ci offset += nvc0_mt_zslice_offset(mt, level, box->z); 429bf215546Sopenharmony_ci *ptransfer = &tx->base; 430bf215546Sopenharmony_ci return mt->base.bo->map + mt->base.offset + offset; 431bf215546Sopenharmony_ci } 432bf215546Sopenharmony_ci 433bf215546Sopenharmony_ci tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format); 434bf215546Sopenharmony_ci tx->base.layer_stride = tx->nblocksy * tx->base.stride; 435bf215546Sopenharmony_ci 436bf215546Sopenharmony_ci nv50_m2mf_rect_setup(&tx->rect[0], res, level, box->x, box->y, box->z); 437bf215546Sopenharmony_ci 438bf215546Sopenharmony_ci size = tx->base.layer_stride; 439bf215546Sopenharmony_ci 440bf215546Sopenharmony_ci ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 441bf215546Sopenharmony_ci size * tx->nlayers, NULL, &tx->rect[1].bo); 442bf215546Sopenharmony_ci if (ret) { 443bf215546Sopenharmony_ci pipe_resource_reference(&tx->base.resource, NULL); 444bf215546Sopenharmony_ci FREE(tx); 445bf215546Sopenharmony_ci return NULL; 446bf215546Sopenharmony_ci } 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci tx->rect[1].cpp = tx->rect[0].cpp; 449bf215546Sopenharmony_ci tx->rect[1].width = tx->nblocksx; 450bf215546Sopenharmony_ci tx->rect[1].height = tx->nblocksy; 451bf215546Sopenharmony_ci tx->rect[1].depth = 1; 452bf215546Sopenharmony_ci tx->rect[1].pitch = tx->base.stride; 453bf215546Sopenharmony_ci tx->rect[1].domain = NOUVEAU_BO_GART; 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_ci if (usage & PIPE_MAP_READ) { 456bf215546Sopenharmony_ci unsigned base = tx->rect[0].base; 457bf215546Sopenharmony_ci unsigned z = tx->rect[0].z; 458bf215546Sopenharmony_ci unsigned i; 459bf215546Sopenharmony_ci for (i = 0; i < tx->nlayers; ++i) { 460bf215546Sopenharmony_ci nvc0->m2mf_copy_rect(nvc0, &tx->rect[1], &tx->rect[0], 461bf215546Sopenharmony_ci tx->nblocksx, tx->nblocksy); 462bf215546Sopenharmony_ci if (mt->layout_3d) 463bf215546Sopenharmony_ci tx->rect[0].z++; 464bf215546Sopenharmony_ci else 465bf215546Sopenharmony_ci tx->rect[0].base += mt->layer_stride; 466bf215546Sopenharmony_ci tx->rect[1].base += size; 467bf215546Sopenharmony_ci } 468bf215546Sopenharmony_ci tx->rect[0].z = z; 469bf215546Sopenharmony_ci tx->rect[0].base = base; 470bf215546Sopenharmony_ci tx->rect[1].base = 0; 471bf215546Sopenharmony_ci } 472bf215546Sopenharmony_ci 473bf215546Sopenharmony_ci if (tx->rect[1].bo->map) { 474bf215546Sopenharmony_ci *ptransfer = &tx->base; 475bf215546Sopenharmony_ci return tx->rect[1].bo->map; 476bf215546Sopenharmony_ci } 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_ci if (usage & PIPE_MAP_READ) 479bf215546Sopenharmony_ci flags = NOUVEAU_BO_RD; 480bf215546Sopenharmony_ci if (usage & PIPE_MAP_WRITE) 481bf215546Sopenharmony_ci flags |= NOUVEAU_BO_WR; 482bf215546Sopenharmony_ci 483bf215546Sopenharmony_ci ret = nouveau_bo_map(tx->rect[1].bo, flags, nvc0->base.client); 484bf215546Sopenharmony_ci if (ret) { 485bf215546Sopenharmony_ci pipe_resource_reference(&tx->base.resource, NULL); 486bf215546Sopenharmony_ci nouveau_bo_ref(NULL, &tx->rect[1].bo); 487bf215546Sopenharmony_ci FREE(tx); 488bf215546Sopenharmony_ci return NULL; 489bf215546Sopenharmony_ci } 490bf215546Sopenharmony_ci 491bf215546Sopenharmony_ci *ptransfer = &tx->base; 492bf215546Sopenharmony_ci return tx->rect[1].bo->map; 493bf215546Sopenharmony_ci} 494bf215546Sopenharmony_ci 495bf215546Sopenharmony_civoid 496bf215546Sopenharmony_cinvc0_miptree_transfer_unmap(struct pipe_context *pctx, 497bf215546Sopenharmony_ci struct pipe_transfer *transfer) 498bf215546Sopenharmony_ci{ 499bf215546Sopenharmony_ci struct nvc0_context *nvc0 = nvc0_context(pctx); 500bf215546Sopenharmony_ci struct nvc0_transfer *tx = (struct nvc0_transfer *)transfer; 501bf215546Sopenharmony_ci struct nv50_miptree *mt = nv50_miptree(tx->base.resource); 502bf215546Sopenharmony_ci unsigned i; 503bf215546Sopenharmony_ci 504bf215546Sopenharmony_ci if (tx->base.usage & PIPE_MAP_DIRECTLY) { 505bf215546Sopenharmony_ci pipe_resource_reference(&transfer->resource, NULL); 506bf215546Sopenharmony_ci 507bf215546Sopenharmony_ci FREE(tx); 508bf215546Sopenharmony_ci return; 509bf215546Sopenharmony_ci } 510bf215546Sopenharmony_ci 511bf215546Sopenharmony_ci if (tx->base.usage & PIPE_MAP_WRITE) { 512bf215546Sopenharmony_ci for (i = 0; i < tx->nlayers; ++i) { 513bf215546Sopenharmony_ci nvc0->m2mf_copy_rect(nvc0, &tx->rect[0], &tx->rect[1], 514bf215546Sopenharmony_ci tx->nblocksx, tx->nblocksy); 515bf215546Sopenharmony_ci if (mt->layout_3d) 516bf215546Sopenharmony_ci tx->rect[0].z++; 517bf215546Sopenharmony_ci else 518bf215546Sopenharmony_ci tx->rect[0].base += mt->layer_stride; 519bf215546Sopenharmony_ci tx->rect[1].base += tx->nblocksy * tx->base.stride; 520bf215546Sopenharmony_ci } 521bf215546Sopenharmony_ci NOUVEAU_DRV_STAT(&nvc0->screen->base, tex_transfers_wr, 1); 522bf215546Sopenharmony_ci 523bf215546Sopenharmony_ci /* Allow the copies above to finish executing before freeing the source */ 524bf215546Sopenharmony_ci nouveau_fence_work(nvc0->screen->base.fence.current, 525bf215546Sopenharmony_ci nouveau_fence_unref_bo, tx->rect[1].bo); 526bf215546Sopenharmony_ci } else { 527bf215546Sopenharmony_ci nouveau_bo_ref(NULL, &tx->rect[1].bo); 528bf215546Sopenharmony_ci } 529bf215546Sopenharmony_ci if (tx->base.usage & PIPE_MAP_READ) 530bf215546Sopenharmony_ci NOUVEAU_DRV_STAT(&nvc0->screen->base, tex_transfers_rd, 1); 531bf215546Sopenharmony_ci 532bf215546Sopenharmony_ci pipe_resource_reference(&transfer->resource, NULL); 533bf215546Sopenharmony_ci 534bf215546Sopenharmony_ci FREE(tx); 535bf215546Sopenharmony_ci} 536bf215546Sopenharmony_ci 537bf215546Sopenharmony_ci/* This happens rather often with DTD9/st. */ 538bf215546Sopenharmony_cistatic void 539bf215546Sopenharmony_cinvc0_cb_push(struct nouveau_context *nv, 540bf215546Sopenharmony_ci struct nv04_resource *res, 541bf215546Sopenharmony_ci unsigned offset, unsigned words, const uint32_t *data) 542bf215546Sopenharmony_ci{ 543bf215546Sopenharmony_ci struct nvc0_context *nvc0 = nvc0_context(&nv->pipe); 544bf215546Sopenharmony_ci struct nvc0_constbuf *cb = NULL; 545bf215546Sopenharmony_ci int s; 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci /* Go through all the constbuf binding points of this buffer and try to 548bf215546Sopenharmony_ci * find one which contains the region to be updated. 549bf215546Sopenharmony_ci */ 550bf215546Sopenharmony_ci for (s = 0; s < 6 && !cb; s++) { 551bf215546Sopenharmony_ci uint16_t bindings = res->cb_bindings[s]; 552bf215546Sopenharmony_ci while (bindings) { 553bf215546Sopenharmony_ci int i = ffs(bindings) - 1; 554bf215546Sopenharmony_ci uint32_t cb_offset = nvc0->constbuf[s][i].offset; 555bf215546Sopenharmony_ci 556bf215546Sopenharmony_ci bindings &= ~(1 << i); 557bf215546Sopenharmony_ci if (cb_offset <= offset && 558bf215546Sopenharmony_ci cb_offset + nvc0->constbuf[s][i].size >= offset + words * 4) { 559bf215546Sopenharmony_ci cb = &nvc0->constbuf[s][i]; 560bf215546Sopenharmony_ci break; 561bf215546Sopenharmony_ci } 562bf215546Sopenharmony_ci } 563bf215546Sopenharmony_ci } 564bf215546Sopenharmony_ci 565bf215546Sopenharmony_ci if (cb) { 566bf215546Sopenharmony_ci nvc0_cb_bo_push(nv, res->bo, res->domain, 567bf215546Sopenharmony_ci res->offset + cb->offset, cb->size, 568bf215546Sopenharmony_ci offset - cb->offset, words, data); 569bf215546Sopenharmony_ci } else { 570bf215546Sopenharmony_ci nv->push_data(nv, res->bo, res->offset + offset, res->domain, 571bf215546Sopenharmony_ci words * 4, data); 572bf215546Sopenharmony_ci } 573bf215546Sopenharmony_ci} 574bf215546Sopenharmony_ci 575bf215546Sopenharmony_civoid 576bf215546Sopenharmony_cinvc0_cb_bo_push(struct nouveau_context *nv, 577bf215546Sopenharmony_ci struct nouveau_bo *bo, unsigned domain, 578bf215546Sopenharmony_ci unsigned base, unsigned size, 579bf215546Sopenharmony_ci unsigned offset, unsigned words, const uint32_t *data) 580bf215546Sopenharmony_ci{ 581bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nv->pushbuf; 582bf215546Sopenharmony_ci 583bf215546Sopenharmony_ci NOUVEAU_DRV_STAT(nv->screen, constbuf_upload_count, 1); 584bf215546Sopenharmony_ci NOUVEAU_DRV_STAT(nv->screen, constbuf_upload_bytes, words * 4); 585bf215546Sopenharmony_ci 586bf215546Sopenharmony_ci assert(!(offset & 3)); 587bf215546Sopenharmony_ci size = align(size, 0x100); 588bf215546Sopenharmony_ci 589bf215546Sopenharmony_ci assert(offset < size); 590bf215546Sopenharmony_ci assert(offset + words * 4 <= size); 591bf215546Sopenharmony_ci 592bf215546Sopenharmony_ci BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3); 593bf215546Sopenharmony_ci PUSH_DATA (push, size); 594bf215546Sopenharmony_ci PUSH_DATAh(push, bo->offset + base); 595bf215546Sopenharmony_ci PUSH_DATA (push, bo->offset + base); 596bf215546Sopenharmony_ci 597bf215546Sopenharmony_ci while (words) { 598bf215546Sopenharmony_ci unsigned nr = MIN2(words, NV04_PFIFO_MAX_PACKET_LEN - 1); 599bf215546Sopenharmony_ci 600bf215546Sopenharmony_ci PUSH_SPACE(push, nr + 2); 601bf215546Sopenharmony_ci PUSH_REFN (push, bo, NOUVEAU_BO_WR | domain); 602bf215546Sopenharmony_ci BEGIN_1IC0(push, NVC0_3D(CB_POS), nr + 1); 603bf215546Sopenharmony_ci PUSH_DATA (push, offset); 604bf215546Sopenharmony_ci PUSH_DATAp(push, data, nr); 605bf215546Sopenharmony_ci 606bf215546Sopenharmony_ci words -= nr; 607bf215546Sopenharmony_ci data += nr; 608bf215546Sopenharmony_ci offset += nr * 4; 609bf215546Sopenharmony_ci } 610bf215546Sopenharmony_ci} 611bf215546Sopenharmony_ci 612bf215546Sopenharmony_civoid 613bf215546Sopenharmony_cinvc0_init_transfer_functions(struct nvc0_context *nvc0) 614bf215546Sopenharmony_ci{ 615bf215546Sopenharmony_ci if (nvc0->screen->base.class_3d >= NVE4_3D_CLASS) { 616bf215546Sopenharmony_ci nvc0->m2mf_copy_rect = nve4_m2mf_transfer_rect; 617bf215546Sopenharmony_ci nvc0->base.copy_data = nve4_m2mf_copy_linear; 618bf215546Sopenharmony_ci nvc0->base.push_data = nve4_p2mf_push_linear; 619bf215546Sopenharmony_ci } else { 620bf215546Sopenharmony_ci nvc0->m2mf_copy_rect = nvc0_m2mf_transfer_rect; 621bf215546Sopenharmony_ci nvc0->base.copy_data = nvc0_m2mf_copy_linear; 622bf215546Sopenharmony_ci nvc0->base.push_data = nvc0_m2mf_push_linear; 623bf215546Sopenharmony_ci } 624bf215546Sopenharmony_ci nvc0->base.push_cb = nvc0_cb_push; 625bf215546Sopenharmony_ci} 626