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