nouveau_exa.c revision fda9279d
1/* 2 * Copyright 2009 Nouveau Project 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23#include "nv_include.h" 24#include "exa.h" 25 26#include "hwdefs/nv_m2mf.xml.h" 27 28static inline Bool 29NVAccelMemcpyRect(char *dst, const char *src, int height, int dst_pitch, 30 int src_pitch, int line_len) 31{ 32 if ((src_pitch == line_len) && (src_pitch == dst_pitch)) { 33 memcpy(dst, src, line_len*height); 34 } else { 35 while (height--) { 36 memcpy(dst, src, line_len); 37 src += src_pitch; 38 dst += dst_pitch; 39 } 40 } 41 42 return TRUE; 43} 44 45Bool 46NVAccelM2MF(NVPtr pNv, int w, int h, int cpp, uint32_t srcoff, uint32_t dstoff, 47 struct nouveau_bo *src, int sd, int sp, int sh, int sx, int sy, 48 struct nouveau_bo *dst, int dd, int dp, int dh, int dx, int dy) 49{ 50 if (pNv->ce_rect && pNv->ce_enabled) 51 return pNv->ce_rect(pNv->ce_pushbuf, pNv->NvCopy, w, h, cpp, 52 src, srcoff, sd, sp, sh, sx, sy, 53 dst, dstoff, dd, dp, dh, dx, dy); 54 else 55 if (pNv->Architecture >= NV_KEPLER) 56 return NVE0EXARectCopy(pNv, w, h, cpp, 57 src, srcoff, sd, sp, sh, sx, sy, 58 dst, dstoff, dd, dp, dh, dx, dy); 59 else 60 if (pNv->Architecture >= NV_FERMI) 61 return NVC0EXARectM2MF(pNv, w, h, cpp, 62 src, srcoff, sd, sp, sh, sx, sy, 63 dst, dstoff, dd, dp, dh, dx, dy); 64 else 65 if (pNv->Architecture >= NV_TESLA) 66 return NV50EXARectM2MF(pNv, w, h, cpp, 67 src, srcoff, sd, sp, sh, sx, sy, 68 dst, dstoff, dd, dp, dh, dx, dy); 69 else 70 return NV04EXARectM2MF(pNv, w, h, cpp, 71 src, srcoff, sd, sp, sh, sx, sy, 72 dst, dstoff, dd, dp, dh, dx, dy); 73 return FALSE; 74} 75 76static int 77nouveau_exa_mark_sync(ScreenPtr pScreen) 78{ 79 return 0; 80} 81 82static void 83nouveau_exa_wait_marker(ScreenPtr pScreen, int marker) 84{ 85} 86 87static Bool 88nouveau_exa_prepare_access(PixmapPtr ppix, int index) 89{ 90 struct nouveau_bo *bo = nouveau_pixmap_bo(ppix); 91 NVPtr pNv = NVPTR(xf86ScreenToScrn(ppix->drawable.pScreen)); 92 93 if (nv50_style_tiled_pixmap(ppix) && !pNv->wfb_enabled) 94 return FALSE; 95 if (nouveau_bo_map(bo, NOUVEAU_BO_RDWR, pNv->client)) 96 return FALSE; 97 ppix->devPrivate.ptr = bo->map; 98 return TRUE; 99} 100 101static void 102nouveau_exa_finish_access(PixmapPtr ppix, int index) 103{ 104} 105 106static Bool 107nouveau_exa_pixmap_is_offscreen(PixmapPtr ppix) 108{ 109 return nouveau_pixmap_bo(ppix) != NULL; 110} 111 112static void * 113nouveau_exa_create_pixmap(ScreenPtr pScreen, int width, int height, int depth, 114 int usage_hint, int bitsPerPixel, int *new_pitch) 115{ 116 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 117 NVPtr pNv = NVPTR(scrn); 118 struct nouveau_pixmap *nvpix; 119 int ret; 120 121 if (!width || !height) 122 return calloc(1, sizeof(*nvpix)); 123 124 if (!pNv->exa_force_cp && pNv->dev->vram_size <= 32 * 1024 * 1024) 125 return NULL; 126 127 nvpix = calloc(1, sizeof(*nvpix)); 128 if (!nvpix) 129 return NULL; 130 131 ret = nouveau_allocate_surface(scrn, width, height, bitsPerPixel, 132 usage_hint, new_pitch, &nvpix->bo); 133 if (!ret) { 134 free(nvpix); 135 return NULL; 136 } 137 138#ifdef NOUVEAU_PIXMAP_SHARING 139 if ((usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED) 140 nvpix->shared = TRUE; 141#endif 142 143 return nvpix; 144} 145 146static void 147nouveau_exa_destroy_pixmap(ScreenPtr pScreen, void *priv) 148{ 149 struct nouveau_pixmap *nvpix = priv; 150 151 if (!nvpix) 152 return; 153 154 nouveau_bo_ref(NULL, &nvpix->bo); 155 free(nvpix); 156} 157 158#ifdef NOUVEAU_PIXMAP_SHARING 159static Bool 160nouveau_exa_share_pixmap_backing(PixmapPtr ppix, ScreenPtr slave, void **handle_p) 161{ 162 struct nouveau_bo *bo = nouveau_pixmap_bo(ppix); 163 struct nouveau_pixmap *nvpix = nouveau_pixmap(ppix); 164 int ret; 165 int handle; 166 167 ret = nouveau_bo_set_prime(bo, &handle); 168 if (ret != 0) { 169 ErrorF("%s: ret is %d errno is %d\n", __func__, ret, errno); 170 return FALSE; 171 } 172 nvpix->shared = TRUE; 173 *handle_p = (void *)(long)handle; 174 return TRUE; 175} 176 177static Bool 178nouveau_exa_set_shared_pixmap_backing(PixmapPtr ppix, void *handle) 179{ 180 ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen); 181 NVPtr pNv = NVPTR(pScrn); 182 struct nouveau_bo *bo = nouveau_pixmap_bo(ppix); 183 struct nouveau_pixmap *nvpix = nouveau_pixmap(ppix); 184 int ret; 185 int ihandle = (int)(long)(handle); 186 187 ret = nouveau_bo_prime_handle_ref(pNv->dev, ihandle, &bo); 188 if (ret) { 189 ErrorF("failed to get BO with handle %d\n", ihandle); 190 return FALSE; 191 } 192 nvpix->bo = bo; 193 nvpix->shared = TRUE; 194 close(ihandle); 195 return TRUE; 196} 197#endif 198 199bool 200nv50_style_tiled_pixmap(PixmapPtr ppix) 201{ 202 ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen); 203 NVPtr pNv = NVPTR(pScrn); 204 205 return pNv->Architecture >= NV_TESLA && 206 nouveau_pixmap_bo(ppix)->config.nv50.memtype; 207} 208 209static int 210nouveau_exa_scratch(NVPtr pNv, int size, struct nouveau_bo **pbo, int *off) 211{ 212 struct nouveau_bo *bo; 213 int ret; 214 215 if (!pNv->transfer || 216 pNv->transfer->size <= pNv->transfer_offset + size) { 217 ret = nouveau_bo_new(pNv->dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 218 0, NOUVEAU_ALIGN(size, 1 * 1024 * 1024), 219 NULL, &bo); 220 if (ret != 0) 221 return ret; 222 223 ret = nouveau_bo_map(bo, NOUVEAU_BO_RDWR, pNv->client); 224 if (ret != 0) { 225 nouveau_bo_ref(NULL, &bo); 226 return ret; 227 } 228 229 nouveau_bo_ref(bo, &pNv->transfer); 230 nouveau_bo_ref(NULL, &bo); 231 pNv->transfer_offset = 0; 232 } 233 234 *off = pNv->transfer_offset; 235 *pbo = pNv->transfer; 236 237 pNv->transfer_offset += size; 238 return 0; 239} 240 241static Bool 242nouveau_exa_download_from_screen(PixmapPtr pspix, int x, int y, int w, int h, 243 char *dst, int dst_pitch) 244{ 245 ScrnInfoPtr pScrn = xf86ScreenToScrn(pspix->drawable.pScreen); 246 NVPtr pNv = NVPTR(pScrn); 247 struct nouveau_bo *bo; 248 int src_pitch, tmp_pitch, cpp, i; 249 const char *src; 250 Bool ret; 251 252 cpp = pspix->drawable.bitsPerPixel >> 3; 253 src_pitch = exaGetPixmapPitch(pspix); 254 tmp_pitch = w * cpp; 255 256 while (h) { 257 const int lines = (h > 2047) ? 2047 : h; 258 struct nouveau_bo *tmp; 259 int tmp_offset; 260 261 if (nouveau_exa_scratch(pNv, lines * tmp_pitch, 262 &tmp, &tmp_offset)) 263 goto memcpy; 264 265 if (!NVAccelM2MF(pNv, w, lines, cpp, 0, tmp_offset, 266 nouveau_pixmap_bo(pspix), NOUVEAU_BO_VRAM, 267 src_pitch, pspix->drawable.height, x, y, 268 tmp, NOUVEAU_BO_GART, tmp_pitch, 269 lines, 0, 0)) 270 goto memcpy; 271 272 nouveau_bo_wait(tmp, NOUVEAU_BO_RD, pNv->client); 273 if (dst_pitch == tmp_pitch) { 274 memcpy(dst, tmp->map + tmp_offset, dst_pitch * lines); 275 dst += dst_pitch * lines; 276 } else { 277 src = tmp->map + tmp_offset; 278 for (i = 0; i < lines; i++) { 279 memcpy(dst, src, tmp_pitch); 280 src += tmp_pitch; 281 dst += dst_pitch; 282 } 283 } 284 285 /* next! */ 286 h -= lines; 287 y += lines; 288 } 289 return TRUE; 290 291memcpy: 292 bo = nouveau_pixmap_bo(pspix); 293 if (nv50_style_tiled_pixmap(pspix)) 294 ErrorF("%s:%d - falling back to memcpy ignores tiling\n", 295 __func__, __LINE__); 296 297 if (nouveau_bo_map(bo, NOUVEAU_BO_RD, pNv->client)) 298 return FALSE; 299 src = (char *)bo->map + (y * src_pitch) + (x * cpp); 300 ret = NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp); 301 return ret; 302} 303 304static Bool 305nouveau_exa_upload_to_screen(PixmapPtr pdpix, int x, int y, int w, int h, 306 char *src, int src_pitch) 307{ 308 ScrnInfoPtr pScrn = xf86ScreenToScrn(pdpix->drawable.pScreen); 309 NVPtr pNv = NVPTR(pScrn); 310 int dst_pitch, tmp_pitch, cpp, i; 311 struct nouveau_bo *bo; 312 char *dst; 313 Bool ret; 314 315 cpp = pdpix->drawable.bitsPerPixel >> 3; 316 dst_pitch = exaGetPixmapPitch(pdpix); 317 tmp_pitch = w * cpp; 318 319 /* try hostdata transfer */ 320 if (w * h * cpp < 16*1024) /* heuristic */ 321 { 322 if (pNv->Architecture < NV_TESLA) { 323 if (NV04EXAUploadIFC(pScrn, src, src_pitch, pdpix, 324 x, y, w, h, cpp)) { 325 return TRUE; 326 } 327 } else 328 if (pNv->Architecture < NV_FERMI) { 329 if (NV50EXAUploadSIFC(src, src_pitch, pdpix, 330 x, y, w, h, cpp)) { 331 return TRUE; 332 } 333 } else { 334 if (NVC0EXAUploadSIFC(src, src_pitch, pdpix, 335 x, y, w, h, cpp)) { 336 return TRUE; 337 } 338 } 339 } 340 341 while (h) { 342 const int lines = (h > 2047) ? 2047 : h; 343 struct nouveau_bo *tmp; 344 int tmp_offset; 345 346 if (nouveau_exa_scratch(pNv, lines * tmp_pitch, 347 &tmp, &tmp_offset)) 348 goto memcpy; 349 350 if (src_pitch == tmp_pitch) { 351 memcpy(tmp->map + tmp_offset, src, src_pitch * lines); 352 src += src_pitch * lines; 353 } else { 354 dst = tmp->map + tmp_offset; 355 for (i = 0; i < lines; i++) { 356 memcpy(dst, src, tmp_pitch); 357 src += src_pitch; 358 dst += tmp_pitch; 359 } 360 } 361 362 if (!NVAccelM2MF(pNv, w, lines, cpp, tmp_offset, 0, tmp, 363 NOUVEAU_BO_GART, tmp_pitch, lines, 0, 0, 364 nouveau_pixmap_bo(pdpix), NOUVEAU_BO_VRAM, 365 dst_pitch, pdpix->drawable.height, x, y)) 366 goto memcpy; 367 368 /* next! */ 369 h -= lines; 370 y += lines; 371 } 372 373 return TRUE; 374 375 /* fallback to memcpy-based transfer */ 376memcpy: 377 bo = nouveau_pixmap_bo(pdpix); 378 if (nv50_style_tiled_pixmap(pdpix)) 379 ErrorF("%s:%d - falling back to memcpy ignores tiling\n", 380 __func__, __LINE__); 381 382 if (nouveau_bo_map(bo, NOUVEAU_BO_WR, pNv->client)) 383 return FALSE; 384 dst = (char *)bo->map + (y * dst_pitch) + (x * cpp); 385 ret = NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp); 386 return ret; 387} 388 389Bool 390nouveau_exa_pixmap_is_onscreen(PixmapPtr ppix) 391{ 392 ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen); 393 394 if (pScrn->pScreen->GetScreenPixmap(pScrn->pScreen) == ppix) 395 return TRUE; 396 397 return FALSE; 398} 399 400static void 401nouveau_exa_flush(ScrnInfoPtr pScrn) 402{ 403 NVPtr pNv = NVPTR(pScrn); 404 nouveau_pushbuf_kick(pNv->pushbuf, pNv->pushbuf->channel); 405} 406 407Bool 408nouveau_exa_init(ScreenPtr pScreen) 409{ 410 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 411 NVPtr pNv = NVPTR(pScrn); 412 ExaDriverPtr exa; 413 414 if (!xf86LoadSubModule(pScrn, "exa")) 415 return FALSE; 416 417 exa = exaDriverAlloc(); 418 if (!exa) 419 return FALSE; 420 421 exa->exa_major = EXA_VERSION_MAJOR; 422 exa->exa_minor = EXA_VERSION_MINOR; 423 exa->flags = EXA_OFFSCREEN_PIXMAPS; 424 425#ifdef EXA_SUPPORTS_PREPARE_AUX 426 exa->flags |= EXA_SUPPORTS_PREPARE_AUX; 427#endif 428 429 exa->PixmapIsOffscreen = nouveau_exa_pixmap_is_offscreen; 430 exa->PrepareAccess = nouveau_exa_prepare_access; 431 exa->FinishAccess = nouveau_exa_finish_access; 432 433 exa->flags |= (EXA_HANDLES_PIXMAPS | EXA_MIXED_PIXMAPS); 434 exa->pixmapOffsetAlign = 256; 435 exa->pixmapPitchAlign = 64; 436 437 exa->CreatePixmap2 = nouveau_exa_create_pixmap; 438 exa->DestroyPixmap = nouveau_exa_destroy_pixmap; 439#ifdef NOUVEAU_PIXMAP_SHARING 440 exa->SharePixmapBacking = nouveau_exa_share_pixmap_backing; 441 exa->SetSharedPixmapBacking = nouveau_exa_set_shared_pixmap_backing; 442#endif 443 444 if (pNv->Architecture >= NV_TESLA) { 445 exa->maxX = 8192; 446 exa->maxY = 8192; 447 } else 448 if (pNv->Architecture >= NV_ARCH_10) { 449 exa->maxX = 4096; 450 exa->maxY = 4096; 451 } else { 452 exa->maxX = 2048; 453 exa->maxY = 2048; 454 } 455 456 exa->MarkSync = nouveau_exa_mark_sync; 457 exa->WaitMarker = nouveau_exa_wait_marker; 458 459 exa->DownloadFromScreen = nouveau_exa_download_from_screen; 460 exa->UploadToScreen = nouveau_exa_upload_to_screen; 461 462 if (pNv->Architecture < NV_TESLA) { 463 exa->PrepareCopy = NV04EXAPrepareCopy; 464 exa->Copy = NV04EXACopy; 465 exa->DoneCopy = NV04EXADoneCopy; 466 467 exa->PrepareSolid = NV04EXAPrepareSolid; 468 exa->Solid = NV04EXASolid; 469 exa->DoneSolid = NV04EXADoneSolid; 470 } else 471 if (pNv->Architecture < NV_FERMI) { 472 exa->PrepareCopy = NV50EXAPrepareCopy; 473 exa->Copy = NV50EXACopy; 474 exa->DoneCopy = NV50EXADoneCopy; 475 476 exa->PrepareSolid = NV50EXAPrepareSolid; 477 exa->Solid = NV50EXASolid; 478 exa->DoneSolid = NV50EXADoneSolid; 479 } else { 480 exa->PrepareCopy = NVC0EXAPrepareCopy; 481 exa->Copy = NVC0EXACopy; 482 exa->DoneCopy = NVC0EXADoneCopy; 483 484 exa->PrepareSolid = NVC0EXAPrepareSolid; 485 exa->Solid = NVC0EXASolid; 486 exa->DoneSolid = NVC0EXADoneSolid; 487 } 488 489 switch (pNv->Architecture) { 490 case NV_ARCH_10: 491 case NV_ARCH_20: 492 exa->CheckComposite = NV10EXACheckComposite; 493 exa->PrepareComposite = NV10EXAPrepareComposite; 494 exa->Composite = NV10EXAComposite; 495 exa->DoneComposite = NV10EXADoneComposite; 496 break; 497 case NV_ARCH_30: 498 exa->CheckComposite = NV30EXACheckComposite; 499 exa->PrepareComposite = NV30EXAPrepareComposite; 500 exa->Composite = NV30EXAComposite; 501 exa->DoneComposite = NV30EXADoneComposite; 502 break; 503 case NV_ARCH_40: 504 exa->CheckComposite = NV40EXACheckComposite; 505 exa->PrepareComposite = NV40EXAPrepareComposite; 506 exa->Composite = NV40EXAComposite; 507 exa->DoneComposite = NV40EXADoneComposite; 508 break; 509 case NV_TESLA: 510 exa->CheckComposite = NV50EXACheckComposite; 511 exa->PrepareComposite = NV50EXAPrepareComposite; 512 exa->Composite = NV50EXAComposite; 513 exa->DoneComposite = NV50EXADoneComposite; 514 break; 515 case NV_FERMI: 516 case NV_KEPLER: 517 exa->CheckComposite = NVC0EXACheckComposite; 518 exa->PrepareComposite = NVC0EXAPrepareComposite; 519 exa->Composite = NVC0EXAComposite; 520 exa->DoneComposite = NVC0EXADoneComposite; 521 break; 522 case NV_MAXWELL: 523 default: 524 break; 525 } 526 527 if (!exaDriverInit(pScreen, exa)) 528 return FALSE; 529 530 pNv->EXADriverPtr = exa; 531 pNv->Flush = nouveau_exa_flush; 532 return TRUE; 533} 534