nouveau_xv.c revision 1090d90a
1/* 2 * Copyright 2007 Arthur Huillet 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 24#ifdef HAVE_CONFIG_H 25#include "config.h" 26#endif 27 28#ifdef __SSE2__ 29#include <immintrin.h> 30#endif 31 32#include "xorg-config.h" 33#include "xf86xv.h" 34#include <X11/extensions/Xv.h> 35#include "exa.h" 36#include "damage.h" 37#include "dixstruct.h" 38#include "fourcc.h" 39 40#include "nv_include.h" 41#include "nv_dma.h" 42 43#include "vl_hwmc.h" 44 45#include "hwdefs/nv_m2mf.xml.h" 46 47#define IMAGE_MAX_W 2046 48#define IMAGE_MAX_H 2046 49 50#define TEX_IMAGE_MAX_W 4096 51#define TEX_IMAGE_MAX_H 4096 52 53#define OFF_DELAY 500 /* milliseconds */ 54#define FREE_DELAY 5000 55 56#define NUM_BLIT_PORTS 16 57#define NUM_TEXTURE_PORTS 32 58 59 60#define NVStopOverlay(X) (((pNv->Architecture == NV_ARCH_04) ? NV04StopOverlay(X) : NV10StopOverlay(X))) 61 62/* Value taken by pPriv -> currentHostBuffer when we failed to allocate the two private buffers in TT memory, so that we can catch this case 63and attempt no other allocation afterwards (performance reasons) */ 64#define NO_PRIV_HOST_BUFFER_AVAILABLE 9999 65 66/* NVPutImage action flags */ 67enum { 68 IS_YV12 = 1, 69 IS_YUY2 = 2, 70 CONVERT_TO_YUY2=4, 71 USE_OVERLAY=8, 72 USE_TEXTURE=16, 73 SWAP_UV=32, 74 IS_RGB=64, //I am not sure how long we will support it 75}; 76 77#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) 78 79Atom xvBrightness, xvContrast, xvColorKey, xvSaturation; 80Atom xvHue, xvAutopaintColorKey, xvSetDefaults, xvDoubleBuffer; 81Atom xvITURBT709, xvSyncToVBlank, xvOnCRTCNb; 82 83/* client libraries expect an encoding */ 84static XF86VideoEncodingRec DummyEncoding = 85{ 86 0, 87 "XV_IMAGE", 88 IMAGE_MAX_W, IMAGE_MAX_H, 89 {1, 1} 90}; 91 92static XF86VideoEncodingRec DummyEncodingTex = 93{ 94 0, 95 "XV_IMAGE", 96 TEX_IMAGE_MAX_W, TEX_IMAGE_MAX_H, 97 {1, 1} 98}; 99 100static XF86VideoEncodingRec DummyEncodingNV50 = 101{ 102 0, 103 "XV_IMAGE", 104 8192, 8192, 105 {1, 1} 106}; 107 108#define NUM_FORMATS_ALL 6 109 110XF86VideoFormatRec NVFormats[NUM_FORMATS_ALL] = 111{ 112 {15, TrueColor}, {16, TrueColor}, {24, TrueColor}, 113 {15, DirectColor}, {16, DirectColor}, {24, DirectColor} 114}; 115 116#define NUM_NV04_OVERLAY_ATTRIBUTES 4 117XF86AttributeRec NV04OverlayAttributes[NUM_NV04_OVERLAY_ATTRIBUTES] = 118{ 119 {XvSettable | XvGettable, -512, 511, "XV_BRIGHTNESS"}, 120 {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, 121 {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"}, 122 {XvSettable , 0, 0, "XV_SET_DEFAULTS"}, 123}; 124 125 126#define NUM_NV10_OVERLAY_ATTRIBUTES 10 127XF86AttributeRec NV10OverlayAttributes[NUM_NV10_OVERLAY_ATTRIBUTES] = 128{ 129 {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"}, 130 {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, 131 {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"}, 132 {XvSettable , 0, 0, "XV_SET_DEFAULTS"}, 133 {XvSettable | XvGettable, -512, 511, "XV_BRIGHTNESS"}, 134 {XvSettable | XvGettable, 0, 8191, "XV_CONTRAST"}, 135 {XvSettable | XvGettable, 0, 8191, "XV_SATURATION"}, 136 {XvSettable | XvGettable, 0, 360, "XV_HUE"}, 137 {XvSettable | XvGettable, 0, 1, "XV_ITURBT_709"}, 138 {XvSettable | XvGettable, 0, 1, "XV_ON_CRTC_NB"}, 139}; 140 141#define NUM_BLIT_ATTRIBUTES 2 142XF86AttributeRec NVBlitAttributes[NUM_BLIT_ATTRIBUTES] = 143{ 144 {XvSettable , 0, 0, "XV_SET_DEFAULTS"}, 145 {XvSettable | XvGettable, 0, 1, "XV_SYNC_TO_VBLANK"} 146}; 147 148#define NUM_TEXTURED_ATTRIBUTES 2 149XF86AttributeRec NVTexturedAttributes[NUM_TEXTURED_ATTRIBUTES] = 150{ 151 {XvSettable , 0, 0, "XV_SET_DEFAULTS"}, 152 {XvSettable | XvGettable, 0, 1, "XV_SYNC_TO_VBLANK"} 153}; 154 155#define NUM_TEXTURED_ATTRIBUTES_NV50 7 156XF86AttributeRec NVTexturedAttributesNV50[NUM_TEXTURED_ATTRIBUTES_NV50] = 157{ 158 { XvSettable , 0, 0, "XV_SET_DEFAULTS" }, 159 { XvSettable | XvGettable, 0, 1, "XV_SYNC_TO_VBLANK" }, 160 { XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS" }, 161 { XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST" }, 162 { XvSettable | XvGettable, -1000, 1000, "XV_SATURATION" }, 163 { XvSettable | XvGettable, -1000, 1000, "XV_HUE" }, 164 { XvSettable | XvGettable, 0, 1, "XV_ITURBT_709" } 165}; 166 167#define NUM_IMAGES_YUV 4 168#define NUM_IMAGES_ALL 5 169 170#define FOURCC_RGB 0x0000003 171#define XVIMAGE_RGB \ 172 { \ 173 FOURCC_RGB, \ 174 XvRGB, \ 175 LSBFirst, \ 176 { 0x03, 0x00, 0x00, 0x00, \ 177 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ 178 32, \ 179 XvPacked, \ 180 1, \ 181 24, 0x00ff0000, 0x0000ff00, 0x000000ff, \ 182 0, 0, 0, \ 183 0, 0, 0, \ 184 0, 0, 0, \ 185 {'B','G','R','X',\ 186 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \ 187 XvTopToBottom \ 188 } 189 190static XF86ImageRec NVImages[NUM_IMAGES_ALL] = 191{ 192 XVIMAGE_YUY2, 193 XVIMAGE_YV12, 194 XVIMAGE_UYVY, 195 XVIMAGE_I420, 196 XVIMAGE_RGB 197}; 198 199static void 200nouveau_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) 201{ 202 dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; 203 dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; 204 dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; 205 dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; 206 207 if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) 208 dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 209} 210 211static void 212nouveau_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) 213{ 214 if (crtc->enabled) { 215 crtc_box->x1 = crtc->x; 216 crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); 217 crtc_box->y1 = crtc->y; 218 crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); 219 } else 220 crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; 221} 222 223static int 224nouveau_box_area(BoxPtr box) 225{ 226 return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); 227} 228 229xf86CrtcPtr 230nouveau_pick_best_crtc(ScrnInfoPtr pScrn, Bool consider_disabled, 231 int x, int y, int w, int h) 232{ 233 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 234 int coverage, best_coverage, c; 235 BoxRec box, crtc_box, cover_box; 236 RROutputPtr primary_output = NULL; 237 xf86CrtcPtr best_crtc = NULL, primary_crtc = NULL; 238 239 if (!pScrn->vtSema) 240 return NULL; 241 242 box.x1 = x; 243 box.x2 = x + w; 244 box.y1 = y; 245 box.y2 = y + h; 246 best_coverage = 0; 247 248 /* Prefer the CRTC of the primary output */ 249#ifdef HAS_DIXREGISTERPRIVATEKEY 250 if (dixPrivateKeyRegistered(rrPrivKey)) 251#endif 252 { 253 primary_output = RRFirstOutput(pScrn->pScreen); 254 } 255 if (primary_output && primary_output->crtc) 256 primary_crtc = primary_output->crtc->devPrivate; 257 258 /* first consider only enabled CRTCs */ 259 for (c = 0; c < xf86_config->num_crtc; c++) { 260 xf86CrtcPtr crtc = xf86_config->crtc[c]; 261 262 if (!crtc->enabled) 263 continue; 264 265 nouveau_crtc_box(crtc, &crtc_box); 266 nouveau_box_intersect(&cover_box, &crtc_box, &box); 267 coverage = nouveau_box_area(&cover_box); 268 if (coverage > best_coverage || 269 (coverage == best_coverage && crtc == primary_crtc)) { 270 best_crtc = crtc; 271 best_coverage = coverage; 272 } 273 } 274 if (best_crtc || !consider_disabled) 275 return best_crtc; 276 277 /* if we found nothing, repeat the search including disabled CRTCs */ 278 for (c = 0; c < xf86_config->num_crtc; c++) { 279 xf86CrtcPtr crtc = xf86_config->crtc[c]; 280 281 nouveau_crtc_box(crtc, &crtc_box); 282 nouveau_box_intersect(&cover_box, &crtc_box, &box); 283 coverage = nouveau_box_area(&cover_box); 284 if (coverage > best_coverage || 285 (coverage == best_coverage && crtc == primary_crtc)) { 286 best_crtc = crtc; 287 best_coverage = coverage; 288 } 289 } 290 return best_crtc; 291} 292 293unsigned int 294nv_window_belongs_to_crtc(ScrnInfoPtr pScrn, int x, int y, int w, int h) 295{ 296 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 297 unsigned int mask = 0; 298 int i; 299 300 for (i = 0; i < xf86_config->num_crtc; i++) { 301 xf86CrtcPtr crtc = xf86_config->crtc[i]; 302 303 if (!drmmode_crtc_on(crtc)) 304 continue; 305 306 if ((x < (crtc->x + crtc->mode.HDisplay)) && 307 (y < (crtc->y + crtc->mode.VDisplay)) && 308 ((x + w) > crtc->x) && 309 ((y + h) > crtc->y)) 310 mask |= 1 << i; 311 } 312 313 return mask; 314} 315 316/** 317 * NVSetPortDefaults 318 * set attributes of port "pPriv" to compiled-in (except for colorKey) defaults 319 * this function does not care about the kind of adapter the port is for 320 * 321 * @param pScrn screen to get the default colorKey from 322 * @param pPriv port to reset to defaults 323 */ 324void 325NVSetPortDefaults (ScrnInfoPtr pScrn, NVPortPrivPtr pPriv) 326{ 327 NVPtr pNv = NVPTR(pScrn); 328 329 pPriv->brightness = 0; 330 pPriv->contrast = 4096; 331 pPriv->saturation = 4096; 332 pPriv->hue = 0; 333 pPriv->colorKey = pNv->videoKey; 334 pPriv->autopaintColorKey = TRUE; 335 pPriv->doubleBuffer = pNv->Architecture != NV_ARCH_04; 336 pPriv->iturbt_709 = FALSE; 337 pPriv->currentHostBuffer = 0; 338} 339 340static int 341nouveau_xv_bo_realloc(ScrnInfoPtr pScrn, unsigned flags, unsigned size, 342 struct nouveau_bo **pbo) 343{ 344 union nouveau_bo_config config = {}; 345 NVPtr pNv = NVPTR(pScrn); 346 347 if (*pbo) { 348 if ((*pbo)->size >= size) 349 return 0; 350 nouveau_bo_ref(NULL, pbo); 351 } 352 353 if (flags & NOUVEAU_BO_VRAM) { 354 if (pNv->Architecture == NV_TESLA) 355 config.nv50.memtype = 0x70; 356 else 357 if (pNv->Architecture >= NV_FERMI) 358 config.nvc0.memtype = 0xfe; 359 } 360 flags |= NOUVEAU_BO_MAP; 361 362 return nouveau_bo_new(pNv->dev, flags, 0, size, &config, pbo); 363} 364 365/** 366 * NVFreePortMemory 367 * frees memory held by a given port 368 * 369 * @param pScrn screen whose port wants to free memory 370 * @param pPriv port to free memory of 371 */ 372static void 373NVFreePortMemory(ScrnInfoPtr pScrn, NVPortPrivPtr pPriv) 374{ 375 nouveau_bo_ref(NULL, &pPriv->video_mem); 376 nouveau_bo_ref(NULL, &pPriv->TT_mem_chunk[0]); 377 nouveau_bo_ref(NULL, &pPriv->TT_mem_chunk[1]); 378} 379 380/** 381 * NVFreeOverlayMemory 382 * frees memory held by the overlay port 383 * 384 * @param pScrn screen whose overlay port wants to free memory 385 */ 386static void 387NVFreeOverlayMemory(ScrnInfoPtr pScrn) 388{ 389 NVPtr pNv = NVPTR(pScrn); 390 NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); 391 392 NVFreePortMemory(pScrn, pPriv); 393#if NVOVL_SUPPORT 394 /* "power cycle" the overlay */ 395 nvWriteMC(pNv, NV_PMC_ENABLE, 396 (nvReadMC(pNv, NV_PMC_ENABLE) & 0xEFFFFFFF)); 397 nvWriteMC(pNv, NV_PMC_ENABLE, 398 (nvReadMC(pNv, NV_PMC_ENABLE) | 0x10000000)); 399#endif 400} 401 402/** 403 * NVFreeBlitMemory 404 * frees memory held by the blit port 405 * 406 * @param pScrn screen whose blit port wants to free memory 407 */ 408static void 409NVFreeBlitMemory(ScrnInfoPtr pScrn) 410{ 411 NVPtr pNv = NVPTR(pScrn); 412 NVPortPrivPtr pPriv = GET_BLIT_PRIVATE(pNv); 413 414 NVFreePortMemory(pScrn, pPriv); 415} 416 417/** 418 * NVVideoTimerCallback 419 * callback function which perform cleanup tasks (stop overlay, free memory). 420 * within the driver 421 * purpose and use is unknown 422 */ 423void 424NVVideoTimerCallback(ScrnInfoPtr pScrn, Time currentTime) 425{ 426 NVPtr pNv = NVPTR(pScrn); 427 NVPortPrivPtr pOverPriv = NULL; 428 NVPortPrivPtr pBlitPriv = NULL; 429 Bool needCallback = FALSE; 430 431 if (!pScrn->vtSema) 432 return; 433 434 if (pNv->overlayAdaptor) { 435 pOverPriv = GET_OVERLAY_PRIVATE(pNv); 436 if (!pOverPriv->videoStatus) 437 pOverPriv = NULL; 438 } 439 440 if (pNv->blitAdaptor) { 441 pBlitPriv = GET_BLIT_PRIVATE(pNv); 442 if (!pBlitPriv->videoStatus) 443 pBlitPriv = NULL; 444 } 445 446 if (pOverPriv) { 447 if (pOverPriv->videoTime < currentTime) { 448 if (pOverPriv->videoStatus & OFF_TIMER) { 449 NVStopOverlay(pScrn); 450 pOverPriv->videoStatus = FREE_TIMER; 451 pOverPriv->videoTime = currentTime + FREE_DELAY; 452 needCallback = TRUE; 453 } else 454 if (pOverPriv->videoStatus & FREE_TIMER) { 455 NVFreeOverlayMemory(pScrn); 456 pOverPriv->videoStatus = 0; 457 } 458 } else { 459 needCallback = TRUE; 460 } 461 } 462 463 if (pBlitPriv) { 464 if (pBlitPriv->videoTime < currentTime) { 465 NVFreeBlitMemory(pScrn); 466 pBlitPriv->videoStatus = 0; 467 } else { 468 needCallback = TRUE; 469 } 470 } 471 472 pNv->VideoTimerCallback = needCallback ? NVVideoTimerCallback : NULL; 473} 474 475#ifndef ExaOffscreenMarkUsed 476extern void ExaOffscreenMarkUsed(PixmapPtr); 477#endif 478 479/* 480 * StopVideo 481 */ 482static void 483NVStopOverlayVideo(ScrnInfoPtr pScrn, pointer data, Bool Exit) 484{ 485 NVPtr pNv = NVPTR(pScrn); 486 NVPortPrivPtr pPriv = (NVPortPrivPtr)data; 487 488 if (pPriv->grabbedByV4L) 489 return; 490 491 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); 492 493 if(Exit) { 494 if (pPriv->videoStatus & CLIENT_VIDEO_ON) 495 NVStopOverlay(pScrn); 496 NVFreeOverlayMemory(pScrn); 497 pPriv->videoStatus = 0; 498 } else { 499 if (pPriv->videoStatus & CLIENT_VIDEO_ON) { 500 pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON; 501 pPriv->videoTime = currentTime.milliseconds + OFF_DELAY; 502 pNv->VideoTimerCallback = NVVideoTimerCallback; 503 } 504 } 505} 506 507/** 508 * QueryBestSize 509 * used by client applications to ask the driver: 510 * how would you actually scale a video of dimensions 511 * vid_w, vid_h, if i wanted you to scale it to dimensions 512 * drw_w, drw_h? 513 * function stores actual scaling size in pointers p_w, p_h. 514 * 515 * 516 * @param pScrn unused 517 * @param motion unused 518 * @param vid_w width of source video 519 * @param vid_h height of source video 520 * @param drw_w desired scaled width as requested by client 521 * @param drw_h desired scaled height as requested by client 522 * @param p_w actual scaled width as the driver is capable of 523 * @param p_h actual scaled height as the driver is capable of 524 * @param data unused 525 */ 526static void 527NVQueryBestSize(ScrnInfoPtr pScrn, Bool motion, 528 short vid_w, short vid_h, 529 short drw_w, short drw_h, 530 unsigned int *p_w, unsigned int *p_h, 531 pointer data) 532{ 533 if(vid_w > (drw_w << 3)) 534 drw_w = vid_w >> 3; 535 if(vid_h > (drw_h << 3)) 536 drw_h = vid_h >> 3; 537 538 *p_w = drw_w; 539 *p_h = drw_h; 540} 541 542/** 543 * NVCopyData420 544 * used to convert YV12 to YUY2 for the blitter and NV04 overlay. 545 * The U and V samples generated are linearly interpolated on the vertical 546 * axis for better quality 547 * 548 * @param src1 source buffer of luma 549 * @param src2 source buffer of chroma1 550 * @param src3 source buffer of chroma2 551 * @param dst1 destination buffer 552 * @param srcPitch pitch of src1 553 * @param srcPitch2 pitch of src2, src3 554 * @param dstPitch pitch of dst1 555 * @param h number of lines to copy 556 * @param w length of lines to copy 557 */ 558static inline void 559NVCopyData420(unsigned char *src1, unsigned char *src2, unsigned char *src3, 560 unsigned char *dst1, int srcPitch, int srcPitch2, int dstPitch, 561 int h, int w) 562{ 563 CARD32 *dst; 564 CARD8 *s1, *s2, *s3; 565 int i, j; 566 567#define su(X) (((j & 1) && j < (h-1)) ? ((unsigned)((signed int)s2[X] + \ 568 (signed int)(s2 + srcPitch2)[X]) / 2) : (s2[X])) 569#define sv(X) (((j & 1) && j < (h-1)) ? ((unsigned)((signed int)s3[X] + \ 570 (signed int)(s3 + srcPitch2)[X]) / 2) : (s3[X])) 571 572 w >>= 1; 573 574 for (j = 0; j < h; j++) { 575 dst = (CARD32*)dst1; 576 s1 = src1; s2 = src2; s3 = src3; 577 i = w; 578 579 while (i > 4) { 580#if X_BYTE_ORDER == X_BIG_ENDIAN 581 dst[0] = (s1[0] << 24) | (s1[1] << 8) | (sv(0) << 16) | su(0); 582 dst[1] = (s1[2] << 24) | (s1[3] << 8) | (sv(1) << 16) | su(1); 583 dst[2] = (s1[4] << 24) | (s1[5] << 8) | (sv(2) << 16) | su(2); 584 dst[3] = (s1[6] << 24) | (s1[7] << 8) | (sv(3) << 16) | su(3); 585#else 586 dst[0] = s1[0] | (s1[1] << 16) | (sv(0) << 8) | (su(0) << 24); 587 dst[1] = s1[2] | (s1[3] << 16) | (sv(1) << 8) | (su(1) << 24); 588 dst[2] = s1[4] | (s1[5] << 16) | (sv(2) << 8) | (su(2) << 24); 589 dst[3] = s1[6] | (s1[7] << 16) | (sv(3) << 8) | (su(3) << 24); 590#endif 591 dst += 4; s2 += 4; s3 += 4; s1 += 8; 592 i -= 4; 593 } 594 595 while (i--) { 596#if X_BYTE_ORDER == X_BIG_ENDIAN 597 dst[0] = (s1[0] << 24) | (s1[1] << 8) | (sv(0) << 16) | su(0); 598#else 599 dst[0] = s1[0] | (s1[1] << 16) | (sv(0) << 8) | (su(0) << 24); 600#endif 601 dst++; s2++; s3++; 602 s1 += 2; 603 } 604 605 dst1 += dstPitch; 606 src1 += srcPitch; 607 if (j & 1) { 608 src2 += srcPitch2; 609 src3 += srcPitch2; 610 } 611 } 612} 613 614/** 615 * NVCopyNV12ColorPlanes 616 * Used to convert YV12 color planes to NV12 (interleaved UV) for the overlay 617 * 618 * @param src1 source buffer of chroma1 619 * @param dst1 destination buffer 620 * @param h number of lines to copy 621 * @param w length of lines to copy 622 * @param id source pixel format (YV12 or I420) 623 */ 624static inline void 625NVCopyNV12ColorPlanes(unsigned char *src1, unsigned char *src2, 626 unsigned char *dst, int dstPitch, int srcPitch2, 627 int h, int w) 628{ 629 int i, j, l, e; 630 631 w >>= 1; 632 h >>= 1; 633#ifdef __SSE2__ 634 l = w >> 3; 635 e = w & 7; 636#else 637 l = w >> 1; 638 e = w & 1; 639#endif 640 641 for (j = 0; j < h; j++) { 642 unsigned char *us = src1; 643 unsigned char *vs = src2; 644 unsigned int *vuvud = (unsigned int *) dst; 645 unsigned short *vud; 646 647 for (i = 0; i < l; i++) { 648#ifdef __SSE2__ 649 _mm_storeu_si128( 650 (void*)vuvud, 651 _mm_unpacklo_epi8( 652 _mm_loadl_epi64((void*)vs), 653 _mm_loadl_epi64((void*)us))); 654 vuvud+=4; 655 us+=8; 656 vs+=8; 657#else /* __SSE2__ */ 658# if X_BYTE_ORDER == X_BIG_ENDIAN 659 *vuvud++ = (vs[0]<<24) | (us[0]<<16) | (vs[1]<<8) | us[1]; 660# else 661 *vuvud++ = vs[0] | (us[0]<<8) | (vs[1]<<16) | (us[1]<<24); 662# endif 663 us+=2; 664 vs+=2; 665#endif /* __SSE2__ */ 666 } 667 668 vud = (unsigned short *)vuvud; 669 for (i = 0; i < e; i++) { 670#if X_BYTE_ORDER == X_BIG_ENDIAN 671 vud[i] = us[i] | (vs[i]<<8); 672#else 673 vud[i] = vs[i] | (us[i]<<8); 674#endif 675 } 676 677 dst += dstPitch; 678 src1 += srcPitch2; 679 src2 += srcPitch2; 680 } 681 682} 683 684 685static int 686NV_set_dimensions(ScrnInfoPtr pScrn, int action_flags, INT32 *xa, INT32 *xb, 687 INT32 *ya, INT32 *yb, short *src_x, short *src_y, 688 short *src_w, short *src_h, short *drw_x, short *drw_y, 689 short *drw_w, short *drw_h, int *left, int *top, int *right, 690 int *bottom, BoxRec *dstBox, int *npixels, int *nlines, 691 RegionPtr clipBoxes, short width, short height) 692{ 693 NVPtr pNv = NVPTR(pScrn); 694 695 if (action_flags & USE_OVERLAY) { 696 switch (pNv->Architecture) { 697 case NV_ARCH_04: 698 /* NV0x overlay can't scale down. at all. */ 699 if (*drw_w < *src_w) 700 *drw_w = *src_w; 701 if (*drw_h < *src_h) 702 *drw_h = *src_h; 703 break; 704 case NV_ARCH_30: 705 /* According to DirectFB, NV3x can't scale down by 706 * a ratio > 2 707 */ 708 if (*drw_w < (*src_w) >> 1) 709 *drw_w = *src_w; 710 if (*drw_h < (*src_h) >> 1) 711 *drw_h = *src_h; 712 break; 713 default: /*NV10, NV20*/ 714 /* NV1x overlay can't scale down by a ratio > 8 */ 715 if (*drw_w < (*src_w) >> 3) 716 *drw_w = *src_w >> 3; 717 if (*drw_h < (*src_h >> 3)) 718 *drw_h = *src_h >> 3; 719 } 720 } 721 722 /* Clip */ 723 *xa = *src_x; 724 *xb = *src_x + *src_w; 725 *ya = *src_y; 726 *yb = *src_y + *src_h; 727 728 dstBox->x1 = *drw_x; 729 dstBox->x2 = *drw_x + *drw_w; 730 dstBox->y1 = *drw_y; 731 dstBox->y2 = *drw_y + *drw_h; 732 733 /* In randr 1.2 mode VIDEO_CLIP_TO_VIEWPORT is broken (hence it is not 734 * set in the overlay adapter flags) since pScrn->frame{X,Y}1 do not get 735 * updated. Hence manual clipping against the CRTC dimensions 736 */ 737 if (action_flags & USE_OVERLAY) { 738 NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); 739 unsigned id = pPriv->overlayCRTC; 740 xf86CrtcPtr crtc = XF86_CRTC_CONFIG_PTR(pScrn)->crtc[id]; 741 RegionRec VPReg; 742 BoxRec VPBox; 743 744 VPBox.x1 = crtc->x; 745 VPBox.y1 = crtc->y; 746 VPBox.x2 = crtc->x + crtc->mode.HDisplay; 747 VPBox.y2 = crtc->y + crtc->mode.VDisplay; 748 749 REGION_INIT(pScreen, &VPReg, &VPBox, 1); 750 REGION_INTERSECT(pScreen, clipBoxes, clipBoxes, &VPReg); 751 REGION_UNINIT(pScreen, &VPReg); 752 } 753 754 if (!xf86XVClipVideoHelper(dstBox, xa, xb, ya, yb, clipBoxes, 755 width, height)) 756 return -1; 757 758 if (action_flags & USE_OVERLAY) { 759 xf86CrtcConfigPtr xf86_config = 760 XF86_CRTC_CONFIG_PTR(pScrn); 761 NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); 762 763 dstBox->x1 -= xf86_config->crtc[pPriv->overlayCRTC]->x; 764 dstBox->x2 -= xf86_config->crtc[pPriv->overlayCRTC]->x; 765 dstBox->y1 -= xf86_config->crtc[pPriv->overlayCRTC]->y; 766 dstBox->y2 -= xf86_config->crtc[pPriv->overlayCRTC]->y; 767 } 768 769 /* Convert fixed point to integer, as xf86XVClipVideoHelper probably 770 * turns its parameter into fixed point values 771 */ 772 *left = (*xa) >> 16; 773 if (*left < 0) 774 *left = 0; 775 776 *top = (*ya) >> 16; 777 if (*top < 0) 778 *top = 0; 779 780 *right = (*xb) >> 16; 781 if (*right > width) 782 *right = width; 783 784 *bottom = (*yb) >> 16; 785 if (*bottom > height) 786 *bottom = height; 787 788 if (action_flags & IS_YV12) { 789 /* even "left", even "top", even number of pixels per line 790 * and even number of lines 791 */ 792 *left &= ~1; 793 *npixels = ((*right + 1) & ~1) - *left; 794 *top &= ~1; 795 *nlines = ((*bottom + 1) & ~1) - *top; 796 } else 797 if (action_flags & IS_YUY2) { 798 /* even "left" */ 799 *left &= ~1; 800 /* even number of pixels per line */ 801 *npixels = ((*right + 1) & ~1) - *left; 802 *nlines = *bottom - *top; 803 /* 16bpp */ 804 *left <<= 1; 805 } else 806 if (action_flags & IS_RGB) { 807 *npixels = *right - *left; 808 *nlines = *bottom - *top; 809 /* 32bpp */ 810 *left <<= 2; 811 } 812 813 return 0; 814} 815 816static int 817NV_calculate_pitches_and_mem_size(NVPtr pNv, int action_flags, int *srcPitch, 818 int *srcPitch2, int *dstPitch, int *s2offset, 819 int *s3offset, int *uv_offset, 820 int *newFBSize, int *newTTSize, 821 int *line_len, int npixels, int nlines, 822 int width, int height) 823{ 824 int tmp; 825 826 if (pNv->Architecture >= NV_TESLA) { 827 npixels = (npixels + 7) & ~7; 828 nlines = (nlines + 7) & ~7; 829 } 830 831 if (action_flags & IS_YV12) { 832 *srcPitch = (width + 3) & ~3; /* of luma */ 833 *s2offset = *srcPitch * height; 834 *srcPitch2 = ((width >> 1) + 3) & ~3; /*of chroma*/ 835 *s3offset = (*srcPitch2 * (height >> 1)) + *s2offset; 836 *dstPitch = (npixels + 63) & ~63; /*luma and chroma pitch*/ 837 *line_len = npixels; 838 *uv_offset = nlines * *dstPitch; 839 *newFBSize = *uv_offset + (nlines >> 1) * *dstPitch; 840 *newTTSize = *uv_offset + (nlines >> 1) * *dstPitch; 841 } else 842 if (action_flags & IS_YUY2) { 843 *srcPitch = width << 1; /* one luma, one chroma per pixel */ 844 *dstPitch = ((npixels << 1) + 63) & ~63; 845 *line_len = npixels << 1; 846 *newFBSize = nlines * *dstPitch; 847 *newTTSize = nlines * *line_len; 848 } else 849 if (action_flags & IS_RGB) { 850 /* one R, one G, one B, one X per pixel */ 851 *srcPitch = width << 2; 852 *dstPitch = ((npixels << 2) + 63) & ~63; 853 *line_len = npixels << 2; 854 *newFBSize = nlines * *dstPitch; 855 *newTTSize = nlines * *dstPitch; 856 } 857 858 if (action_flags & CONVERT_TO_YUY2) { 859 *dstPitch = ((npixels << 1) + 63) & ~63; 860 *line_len = npixels << 1; 861 *newFBSize = nlines * *dstPitch; 862 *newTTSize = nlines * *line_len; 863 *uv_offset = 0; 864 } 865 866 if (action_flags & SWAP_UV) { 867 /* I420 swaps U and V */ 868 tmp = *s2offset; 869 *s2offset = *s3offset; 870 *s3offset = tmp; 871 } 872 873 /* Overlay double buffering... */ 874 if (action_flags & USE_OVERLAY) 875 (*newFBSize) <<= 1; 876 877 return 0; 878} 879 880 881/** 882 * NV_set_action_flags 883 * This function computes the action flags from the input image, 884 * that is, it decides what NVPutImage and its helpers must do. 885 * This eases readability by avoiding lots of switch-case statements in the 886 * core NVPutImage 887 */ 888static void 889NV_set_action_flags(ScrnInfoPtr pScrn, DrawablePtr pDraw, NVPortPrivPtr pPriv, 890 int id, short drw_x, short drw_y, short drw_w, short drw_h, 891 int *action_flags) 892{ 893 NVPtr pNv = NVPTR(pScrn); 894 895#define USING_OVERLAY (*action_flags & USE_OVERLAY) 896#define USING_TEXTURE (*action_flags & USE_TEXTURE) 897#define USING_BLITTER ((!(*action_flags & USE_OVERLAY)) && \ 898 (!(*action_flags & USE_TEXTURE))) 899 900 *action_flags = 0; 901 902 /* Pixel format-related bits */ 903 if (id == FOURCC_YUY2 || id == FOURCC_UYVY) 904 *action_flags |= IS_YUY2; 905 906 if (id == FOURCC_YV12 || id == FOURCC_I420) 907 *action_flags |= IS_YV12; 908 909 if (id == FOURCC_RGB) /*How long will we support it?*/ 910 *action_flags |= IS_RGB; 911 912 if (id == FOURCC_I420) /* I420 is YV12 with swapped UV */ 913 *action_flags |= SWAP_UV; 914 915 /* Desired adapter */ 916 if (!pPriv->blitter && !pPriv->texture) 917 *action_flags |= USE_OVERLAY; 918 919 if (!pPriv->blitter && pPriv->texture) 920 *action_flags |= USE_TEXTURE; 921 922 /* Adapter fallbacks (when the desired one can't be used)*/ 923#ifdef COMPOSITE 924 { 925 PixmapPtr ppix = NVGetDrawablePixmap(pDraw); 926 927 /* this is whether ppix is in the viewable fb, not related to 928 the EXA "offscreen" stuff */ 929 if (!nouveau_exa_pixmap_is_onscreen(ppix)) 930 *action_flags &= ~USE_OVERLAY; 931 } 932#endif 933 934#ifdef NVOVL_SUPPORT 935 if (USING_OVERLAY) { 936 char crtc = nv_window_belongs_to_crtc(pScrn, drw_x, drw_y, 937 drw_w, drw_h); 938 939 if ((crtc & (1 << 0)) && (crtc & (1 << 1))) { 940 /* The overlay cannot be used on two CRTCs at a time, 941 * so we need to fallback on the blitter 942 */ 943 *action_flags &= ~USE_OVERLAY; 944 } else 945 if ((crtc & (1 << 0))) { 946 /* We need to put the overlay on CRTC0 - if it's not 947 * already here 948 */ 949 if (pPriv->overlayCRTC == 1) { 950 NVWriteCRTC(pNv, 0, NV_PCRTC_ENGINE_CTRL, 951 NVReadCRTC(pNv, 0, NV_PCRTC_ENGINE_CTRL) | 952 NV_CRTC_FSEL_OVERLAY); 953 NVWriteCRTC(pNv, 1, NV_PCRTC_ENGINE_CTRL, 954 NVReadCRTC(pNv, 1, NV_PCRTC_ENGINE_CTRL) & 955 ~NV_CRTC_FSEL_OVERLAY); 956 pPriv->overlayCRTC = 0; 957 } 958 } else 959 if ((crtc & (1 << 1))) { 960 if (pPriv->overlayCRTC == 0) { 961 NVWriteCRTC(pNv, 1, NV_PCRTC_ENGINE_CTRL, 962 NVReadCRTC(pNv, 1, NV_PCRTC_ENGINE_CTRL) | 963 NV_CRTC_FSEL_OVERLAY); 964 NVWriteCRTC(pNv, 0, NV_PCRTC_ENGINE_CTRL, 965 NVReadCRTC(pNv, 0, NV_PCRTC_ENGINE_CTRL) & 966 ~NV_CRTC_FSEL_OVERLAY); 967 pPriv->overlayCRTC = 1; 968 } 969 } 970 971 if (XF86_CRTC_CONFIG_PTR(pScrn)->crtc[pPriv->overlayCRTC] 972 ->rotation != RR_Rotate_0) 973 *action_flags &= ~USE_OVERLAY; 974 } 975#endif 976 977 /* At this point the adapter we're going to use is _known_. 978 * You cannot change it now. 979 */ 980 981 /* Card/adapter format restrictions */ 982 if (USING_BLITTER) { 983 /* The blitter does not handle YV12 natively */ 984 if (id == FOURCC_YV12 || id == FOURCC_I420) 985 *action_flags |= CONVERT_TO_YUY2; 986 } 987 988 if (USING_OVERLAY && (pNv->Architecture == NV_ARCH_04)) { 989 /* NV04-05 don't support YV12, only YUY2 and ITU-R BT.601 */ 990 if (*action_flags & IS_YV12) 991 *action_flags |= CONVERT_TO_YUY2; 992 } 993 994 if (USING_OVERLAY && (pNv->Architecture == NV_ARCH_10 || 995 pNv->Architecture == NV_ARCH_20)) { 996 /* No YV12 overlay on NV10, 11, 15, 20, NFORCE */ 997 switch (pNv->dev->chipset) { 998 case 0x10: 999 case 0x11: 1000 case 0x15: 1001 case 0x1a: /*XXX: unsure about nforce */ 1002 case 0x20: 1003 *action_flags |= CONVERT_TO_YUY2; 1004 break; 1005 default: 1006 break; 1007 } 1008 } 1009} 1010 1011 1012/** 1013 * NVPutImage 1014 * PutImage is "the" important function of the Xv extension. 1015 * a client (e.g. video player) calls this function for every 1016 * image (of the video) to be displayed. this function then 1017 * scales and displays the image. 1018 * 1019 * @param pScrn screen which hold the port where the image is put 1020 * @param src_x source point in the source image to start displaying from 1021 * @param src_y see above 1022 * @param src_w width of the source image to display 1023 * @param src_h see above 1024 * @param drw_x screen point to display to 1025 * @param drw_y 1026 * @param drw_w width of the screen drawable 1027 * @param drw_h 1028 * @param id pixel format of image 1029 * @param buf pointer to buffer containing the source image 1030 * @param width total width of the source image we are passed 1031 * @param height 1032 * @param Sync unused 1033 * @param clipBoxes ?? 1034 * @param data pointer to port 1035 * @param pDraw drawable pointer 1036 */ 1037static int 1038NVPutImage(ScrnInfoPtr pScrn, short src_x, short src_y, short drw_x, 1039 short drw_y, short src_w, short src_h, short drw_w, short drw_h, 1040 int id, unsigned char *buf, short width, short height, 1041 Bool Sync, RegionPtr clipBoxes, pointer data, DrawablePtr pDraw) 1042{ 1043 NVPortPrivPtr pPriv = (NVPortPrivPtr)data; 1044 NVPtr pNv = NVPTR(pScrn); 1045 PixmapPtr ppix; 1046 /* source box */ 1047 INT32 xa = 0, xb = 0, ya = 0, yb = 0; 1048 /* size to allocate in VRAM and in GART respectively */ 1049 int newFBSize = 0, newTTSize = 0; 1050 /* card VRAM offsets, source offsets for U and V planes */ 1051 int offset = 0, uv_offset = 0, s2offset = 0, s3offset = 0; 1052 /* source pitch, source pitch of U and V planes in case of YV12, 1053 * VRAM destination pitch 1054 */ 1055 int srcPitch = 0, srcPitch2 = 0, dstPitch = 0; 1056 /* position of the given source data (using src_*), number of pixels 1057 * and lines we are interested in 1058 */ 1059 int top = 0, left = 0, right = 0, bottom = 0, npixels = 0, nlines = 0; 1060 Bool skip = FALSE; 1061 BoxRec dstBox; 1062 CARD32 tmp = 0; 1063 int line_len = 0; /* length of a line, like npixels, but in bytes */ 1064 struct nouveau_bo *destination_buffer = NULL; 1065 int action_flags; /* what shall we do? */ 1066 unsigned char *map; 1067 int ret, i; 1068 1069 if (pPriv->grabbedByV4L) 1070 return Success; 1071 1072 if (width > pPriv->max_image_dim || height > pPriv->max_image_dim) 1073 return BadMatch; 1074 1075 NV_set_action_flags(pScrn, pDraw, pPriv, id, drw_x, drw_y, drw_w, 1076 drw_h, &action_flags); 1077 1078 if (NV_set_dimensions(pScrn, action_flags, &xa, &xb, &ya, &yb, 1079 &src_x, &src_y, &src_w, &src_h, 1080 &drw_x, &drw_y, &drw_w, &drw_h, 1081 &left, &top, &right, &bottom, &dstBox, 1082 &npixels, &nlines, clipBoxes, width, height)) 1083 return Success; 1084 1085 if (NV_calculate_pitches_and_mem_size(pNv, action_flags, &srcPitch, 1086 &srcPitch2, &dstPitch, &s2offset, 1087 &s3offset, &uv_offset, 1088 &newFBSize, &newTTSize, 1089 &line_len, npixels, nlines, 1090 width, height)) 1091 return BadImplementation; 1092 1093 /* There are some cases (tvtime with overscan for example) where the 1094 * input image is larger (width/height) than the source rectangle for 1095 * the overlay (src_w, src_h). In those cases, we try to do something 1096 * optimal by uploading only the necessary data. 1097 */ 1098 if (action_flags & IS_YUY2 || action_flags & IS_RGB) 1099 buf += (top * srcPitch) + left; 1100 1101 if (action_flags & IS_YV12) { 1102 tmp = ((top >> 1) * srcPitch2) + (left >> 1); 1103 s2offset += tmp; 1104 s3offset += tmp; 1105 } 1106 1107 ret = nouveau_xv_bo_realloc(pScrn, NOUVEAU_BO_VRAM, newFBSize, 1108 &pPriv->video_mem); 1109 if (ret) 1110 return BadAlloc; 1111 1112#ifdef NVOVL_SUPPORT 1113 if (action_flags & USE_OVERLAY) { 1114 ret = nouveau_bo_pin(pPriv->video_mem, NOUVEAU_BO_VRAM); 1115 if (ret) { 1116 nouveau_bo_ref(NULL, &pPriv->video_mem); 1117 return BadAlloc; 1118 } 1119 } 1120#endif 1121 1122 /* The overlay supports hardware double buffering. We handle this here*/ 1123 offset = 0; 1124#ifdef NVOVL_SUPPORT 1125 if (pPriv->doubleBuffer) { 1126 int mask = 1 << (pPriv->currentBuffer << 2); 1127 1128 /* overwrite the newest buffer if there's not one free */ 1129 if (nvReadVIDEO(pNv, NV_PVIDEO_BUFFER) & mask) { 1130 if (!pPriv->currentBuffer) 1131 offset += newFBSize >> 1; 1132 skip = TRUE; 1133 } else { 1134 if (pPriv->currentBuffer) 1135 offset += newFBSize >> 1; 1136 } 1137 } 1138#endif 1139 1140 /* Now we take a decision regarding the way we send the data to the 1141 * card. 1142 * 1143 * Either we use double buffering of "private" TT memory 1144 * Either we rely on X's GARTScratch 1145 * Either we fallback on CPU copy 1146 */ 1147 1148 /* Try to allocate host-side double buffers, unless we have already 1149 * failed 1150 */ 1151 1152 /* We take only nlines * line_len bytes - that is, only the pixel 1153 * data we are interested in - because the stuff in the GART is 1154 * written contiguously 1155 */ 1156 if (pPriv->currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE) { 1157 ret = nouveau_xv_bo_realloc(pScrn, NOUVEAU_BO_GART, newTTSize, 1158 &pPriv->TT_mem_chunk[0]); 1159 if (ret == 0) { 1160 ret = nouveau_xv_bo_realloc(pScrn, NOUVEAU_BO_GART, 1161 newTTSize, 1162 &pPriv->TT_mem_chunk[1]); 1163 if (ret) { 1164 nouveau_bo_ref(NULL, &pPriv->TT_mem_chunk[0]); 1165 pPriv->currentHostBuffer = 1166 NO_PRIV_HOST_BUFFER_AVAILABLE; 1167 } 1168 } else { 1169 pPriv->currentHostBuffer = 1170 NO_PRIV_HOST_BUFFER_AVAILABLE; 1171 } 1172 } 1173 1174 if (pPriv->currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE) { 1175 destination_buffer = 1176 pPriv->TT_mem_chunk[pPriv->currentHostBuffer]; 1177 } 1178 if (!destination_buffer) { 1179 if (pNv->Architecture >= NV_TESLA) { 1180 NOUVEAU_ERR("No scratch buffer for tiled upload\n"); 1181 return BadAlloc; 1182 } 1183 1184 goto CPU_copy; 1185 } 1186 1187 if (newTTSize <= destination_buffer->size) { 1188 unsigned char *dst; 1189 int i = 0; 1190 1191 /* Upload to GART */ 1192 nouveau_bo_map(destination_buffer, NOUVEAU_BO_WR, pNv->client); 1193 dst = destination_buffer->map; 1194 1195 if (action_flags & IS_YV12) { 1196 if (action_flags & CONVERT_TO_YUY2) { 1197 NVCopyData420(buf + (top * srcPitch) + left, 1198 buf + s2offset, buf + s3offset, 1199 dst, srcPitch, srcPitch2, 1200 line_len, nlines, npixels); 1201 } else { 1202 /* Native YV12 */ 1203 unsigned char *tbuf = buf + top * 1204 srcPitch + left; 1205 unsigned char *tdst = dst; 1206 1207 /* luma upload */ 1208 for (i = 0; i < nlines; i++) { 1209 memcpy(tdst, tbuf, line_len); 1210 tdst += line_len; 1211 tbuf += srcPitch; 1212 } 1213 dst += line_len * nlines; 1214 1215 NVCopyNV12ColorPlanes(buf + s2offset, 1216 buf + s3offset, dst, 1217 line_len, srcPitch2, 1218 nlines, npixels); 1219 } 1220 } else { 1221 for (i = 0; i < nlines; i++) { 1222 memcpy(dst, buf, line_len); 1223 dst += line_len; 1224 buf += srcPitch; 1225 } 1226 } 1227 1228 if (uv_offset) { 1229 NVAccelM2MF(pNv, line_len, nlines / 2, 1, 1230 line_len * nlines, uv_offset, 1231 destination_buffer, NOUVEAU_BO_GART, 1232 line_len, nlines >> 1, 0, 0, 1233 pPriv->video_mem, NOUVEAU_BO_VRAM, 1234 dstPitch, nlines >> 1, 0, 0); 1235 } 1236 1237 NVAccelM2MF(pNv, line_len, nlines, 1, 0, 0, 1238 destination_buffer, NOUVEAU_BO_GART, 1239 line_len, nlines, 0, 0, 1240 pPriv->video_mem, NOUVEAU_BO_VRAM, 1241 dstPitch, nlines, 0, 0); 1242 1243 } else { 1244CPU_copy: 1245 nouveau_bo_map(pPriv->video_mem, NOUVEAU_BO_WR, pNv->client); 1246 map = pPriv->video_mem->map + offset; 1247 1248 if (action_flags & IS_YV12) { 1249 if (action_flags & CONVERT_TO_YUY2) { 1250 NVCopyData420(buf + (top * srcPitch) + left, 1251 buf + s2offset, buf + s3offset, 1252 map, srcPitch, srcPitch2, 1253 dstPitch, nlines, npixels); 1254 } else { 1255 unsigned char *tbuf = 1256 buf + left + top * srcPitch; 1257 1258 for (i = 0; i < nlines; i++) { 1259 int dwords = npixels << 1; 1260 1261 while (dwords & ~0x03) { 1262 *map = *tbuf; 1263 *(map + 1) = *(tbuf + 1); 1264 *(map + 2) = *(tbuf + 2); 1265 *(map + 3) = *(tbuf + 3); 1266 map += 4; 1267 tbuf += 4; 1268 dwords -= 4; 1269 } 1270 1271 switch (dwords) { 1272 case 3: *(map + 2) = *(tbuf + 2); 1273 case 2: *(map + 1) = *(tbuf + 1); 1274 case 1: *map = *tbuf; 1275 } 1276 1277 map += dstPitch - (npixels << 1); 1278 tbuf += srcPitch - (npixels << 1); 1279 } 1280 1281 NVCopyNV12ColorPlanes(buf + s2offset, 1282 buf + s3offset, 1283 map, dstPitch, srcPitch2, 1284 nlines, npixels); 1285 } 1286 } else { 1287 /* YUY2 and RGB */ 1288 for (i = 0; i < nlines; i++) { 1289 int dwords = npixels << 1; 1290 1291 while (dwords & ~0x03) { 1292 *map = *buf; 1293 *(map + 1) = *(buf + 1); 1294 *(map + 2) = *(buf + 2); 1295 *(map + 3) = *(buf + 3); 1296 map += 4; 1297 buf += 4; 1298 dwords -= 4; 1299 } 1300 1301 switch (dwords) { 1302 case 3: *(map + 2) = *(buf + 2); 1303 case 2: *(map + 1) = *(buf + 1); 1304 case 1: *map = *buf; 1305 } 1306 1307 map += dstPitch - (npixels << 1); 1308 buf += srcPitch - (npixels << 1); 1309 } 1310 } 1311 } 1312 1313 if (skip) 1314 return Success; 1315 1316 if (pPriv->currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE) 1317 pPriv->currentHostBuffer ^= 1; 1318 1319 /* If we're not using the hw overlay, we're rendering into a pixmap 1320 * and need to take a couple of additional steps... 1321 */ 1322 if (!(action_flags & USE_OVERLAY)) { 1323 ppix = NVGetDrawablePixmap(pDraw); 1324 1325 /* Ensure pixmap is in offscreen memory */ 1326 pNv->exa_force_cp = TRUE; 1327 exaMoveInPixmap(ppix); 1328 pNv->exa_force_cp = FALSE; 1329 1330 if (!exaGetPixmapDriverPrivate(ppix)) 1331 return BadAlloc; 1332 1333#ifdef COMPOSITE 1334 /* Convert screen coords to pixmap coords */ 1335 if (ppix->screen_x || ppix->screen_y) { 1336 REGION_TRANSLATE(pScrn->pScreen, clipBoxes, 1337 -ppix->screen_x, -ppix->screen_y); 1338 dstBox.x1 -= ppix->screen_x; 1339 dstBox.x2 -= ppix->screen_x; 1340 dstBox.y1 -= ppix->screen_y; 1341 dstBox.y2 -= ppix->screen_y; 1342 } 1343#endif 1344 } 1345 1346 if (action_flags & USE_OVERLAY) { 1347 if (pNv->Architecture == NV_ARCH_04) { 1348 NV04PutOverlayImage(pScrn, pPriv->video_mem, offset, 1349 id, dstPitch, &dstBox, 0, 0, 1350 xb, yb, npixels, nlines, 1351 src_w, src_h, drw_w, drw_h, 1352 clipBoxes); 1353 } else { 1354 NV10PutOverlayImage(pScrn, pPriv->video_mem, offset, 1355 uv_offset, id, dstPitch, &dstBox, 1356 0, 0, xb, yb, 1357 npixels, nlines, src_w, src_h, 1358 drw_w, drw_h, clipBoxes); 1359 } 1360 1361 pPriv->currentBuffer ^= 1; 1362 } else 1363 if (action_flags & USE_TEXTURE) { 1364 int ret = BadImplementation; 1365 1366 if (pNv->Architecture == NV_ARCH_30) { 1367 ret = NV30PutTextureImage(pScrn, pPriv->video_mem, 1368 offset, uv_offset, 1369 id, dstPitch, &dstBox, 0, 0, 1370 xb, yb, npixels, nlines, 1371 src_w, src_h, drw_w, drw_h, 1372 clipBoxes, ppix, pPriv); 1373 } else 1374 if (pNv->Architecture == NV_ARCH_40) { 1375 ret = NV40PutTextureImage(pScrn, pPriv->video_mem, 1376 offset, uv_offset, 1377 id, dstPitch, &dstBox, 0, 0, 1378 xb, yb, npixels, nlines, 1379 src_w, src_h, drw_w, drw_h, 1380 clipBoxes, ppix, pPriv); 1381 } else 1382 if (pNv->Architecture == NV_TESLA) { 1383 ret = nv50_xv_image_put(pScrn, pPriv->video_mem, 1384 offset, uv_offset, 1385 id, dstPitch, &dstBox, 0, 0, 1386 xb, yb, npixels, nlines, 1387 src_w, src_h, drw_w, drw_h, 1388 clipBoxes, ppix, pPriv); 1389 } else { 1390 ret = nvc0_xv_image_put(pScrn, pPriv->video_mem, 1391 offset, uv_offset, 1392 id, dstPitch, &dstBox, 0, 0, 1393 xb, yb, npixels, nlines, 1394 src_w, src_h, drw_w, drw_h, 1395 clipBoxes, ppix, pPriv); 1396 } 1397 1398 if (ret != Success) 1399 return ret; 1400 } else { 1401 ret = NVPutBlitImage(pScrn, pPriv->video_mem, offset, id, 1402 dstPitch, &dstBox, 0, 0, xb, yb, npixels, 1403 nlines, src_w, src_h, drw_w, drw_h, 1404 clipBoxes, ppix); 1405 if (ret != Success) 1406 return ret; 1407 } 1408 1409#ifdef COMPOSITE 1410 /* Damage tracking */ 1411 if (!(action_flags & USE_OVERLAY)) 1412 DamageDamageRegion(&ppix->drawable, clipBoxes); 1413#endif 1414 1415 return Success; 1416} 1417 1418/** 1419 * QueryImageAttributes 1420 * 1421 * calculates 1422 * - size (memory required to store image), 1423 * - pitches, 1424 * - offsets 1425 * of image 1426 * depending on colorspace (id) and dimensions (w,h) of image 1427 * values of 1428 * - w, 1429 * - h 1430 * may be adjusted as needed 1431 * 1432 * @param pScrn unused 1433 * @param id colorspace of image 1434 * @param w pointer to width of image 1435 * @param h pointer to height of image 1436 * @param pitches pitches[i] = length of a scanline in plane[i] 1437 * @param offsets offsets[i] = offset of plane i from the beginning of the image 1438 * @return size of the memory required for the XvImage queried 1439 */ 1440static int 1441NVQueryImageAttributes(ScrnInfoPtr pScrn, int id, 1442 unsigned short *w, unsigned short *h, 1443 int *pitches, int *offsets) 1444{ 1445 int size, tmp; 1446 1447 *w = (*w + 1) & ~1; // width rounded up to an even number 1448 if (offsets) 1449 offsets[0] = 0; 1450 1451 switch (id) { 1452 case FOURCC_YV12: 1453 case FOURCC_I420: 1454 *h = (*h + 1) & ~1; // height rounded up to an even number 1455 size = (*w + 3) & ~3; // width rounded up to a multiple of 4 1456 if (pitches) 1457 pitches[0] = size; // width rounded up to a multiple of 4 1458 size *= *h; 1459 if (offsets) 1460 offsets[1] = size; // number of pixels in "rounded up" image 1461 tmp = ((*w >> 1) + 3) & ~3; // width/2 rounded up to a multiple of 4 1462 if (pitches) 1463 pitches[1] = pitches[2] = tmp; // width/2 rounded up to a multiple of 4 1464 tmp *= (*h >> 1); // 1/4*number of pixels in "rounded up" image 1465 size += tmp; // 5/4*number of pixels in "rounded up" image 1466 if (offsets) 1467 offsets[2] = size; // 5/4*number of pixels in "rounded up" image 1468 size += tmp; // = 3/2*number of pixels in "rounded up" image 1469 break; 1470 case FOURCC_UYVY: 1471 case FOURCC_YUY2: 1472 size = *w << 1; // 2*width 1473 if (pitches) 1474 pitches[0] = size; // 2*width 1475 size *= *h; // 2*width*height 1476 break; 1477 case FOURCC_RGB: 1478 size = *w << 2; // 4*width (32 bit per pixel) 1479 if (pitches) 1480 pitches[0] = size; // 4*width 1481 size *= *h; // 4*width*height 1482 break; 1483 case FOURCC_AI44: 1484 case FOURCC_IA44: 1485 size = *w; // width 1486 if (pitches) 1487 pitches[0] = size; // width 1488 size *= *h; // width*height 1489 break; 1490 default: 1491 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown colorspace: %x\n", id); 1492 *w = *h = size = 0; 1493 break; 1494 } 1495 1496 return size; 1497} 1498 1499/***** Exported offscreen surface stuff ****/ 1500 1501 1502static int 1503NVAllocSurface(ScrnInfoPtr pScrn, int id, 1504 unsigned short w, unsigned short h, 1505 XF86SurfacePtr surface) 1506{ 1507 NVPtr pNv = NVPTR(pScrn); 1508 NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); 1509 int size, bpp, ret; 1510 1511 bpp = pScrn->bitsPerPixel >> 3; 1512 1513 if (pPriv->grabbedByV4L) 1514 return BadAlloc; 1515 1516 if ((w > IMAGE_MAX_W) || (h > IMAGE_MAX_H)) 1517 return BadValue; 1518 1519 w = (w + 1) & ~1; 1520 pPriv->pitch = ((w << 1) + 63) & ~63; 1521 size = h * pPriv->pitch / bpp; 1522 1523 ret = nouveau_xv_bo_realloc(pScrn, NOUVEAU_BO_VRAM, size, 1524 &pPriv->video_mem); 1525 if (ret) 1526 return BadAlloc; 1527 pPriv->offset = 0; 1528 1529 surface->width = w; 1530 surface->height = h; 1531 surface->pScrn = pScrn; 1532 surface->pitches = &pPriv->pitch; 1533 surface->offsets = &pPriv->offset; 1534 surface->devPrivate.ptr = (pointer)pPriv; 1535 surface->id = id; 1536 1537 /* grab the video */ 1538 NVStopOverlay(pScrn); 1539 pPriv->videoStatus = 0; 1540 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); 1541 pPriv->grabbedByV4L = TRUE; 1542 1543 return Success; 1544} 1545 1546static int 1547NVStopSurface(XF86SurfacePtr surface) 1548{ 1549 NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr); 1550 1551 if (pPriv->grabbedByV4L && pPriv->videoStatus) { 1552 NV10StopOverlay(surface->pScrn); 1553 pPriv->videoStatus = 0; 1554 } 1555 1556 return Success; 1557} 1558 1559static int 1560NVFreeSurface(XF86SurfacePtr surface) 1561{ 1562 NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr); 1563 1564 if (pPriv->grabbedByV4L) { 1565 NVStopSurface(surface); 1566 NVFreeOverlayMemory(surface->pScrn); 1567 pPriv->grabbedByV4L = FALSE; 1568 } 1569 1570 return Success; 1571} 1572 1573static int 1574NVGetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value) 1575{ 1576 NVPtr pNv = NVPTR(pScrn); 1577 NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); 1578 1579 return NV10GetOverlayPortAttribute(pScrn, attribute, 1580 value, (pointer)pPriv); 1581} 1582 1583static int 1584NVSetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value) 1585{ 1586 NVPtr pNv = NVPTR(pScrn); 1587 NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); 1588 1589 return NV10SetOverlayPortAttribute(pScrn, attribute, 1590 value, (pointer)pPriv); 1591} 1592 1593static int 1594NVDisplaySurface(XF86SurfacePtr surface, 1595 short src_x, short src_y, 1596 short drw_x, short drw_y, 1597 short src_w, short src_h, 1598 short drw_w, short drw_h, 1599 RegionPtr clipBoxes) 1600{ 1601 ScrnInfoPtr pScrn = surface->pScrn; 1602 NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr); 1603 INT32 xa, xb, ya, yb; 1604 BoxRec dstBox; 1605 1606 if (!pPriv->grabbedByV4L) 1607 return Success; 1608 1609 if (src_w > (drw_w << 3)) 1610 drw_w = src_w >> 3; 1611 if (src_h > (drw_h << 3)) 1612 drw_h = src_h >> 3; 1613 1614 /* Clip */ 1615 xa = src_x; 1616 xb = src_x + src_w; 1617 ya = src_y; 1618 yb = src_y + src_h; 1619 1620 dstBox.x1 = drw_x; 1621 dstBox.x2 = drw_x + drw_w; 1622 dstBox.y1 = drw_y; 1623 dstBox.y2 = drw_y + drw_h; 1624 1625 if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes, 1626 surface->width, surface->height)) 1627 return Success; 1628 1629 dstBox.x1 -= pScrn->frameX0; 1630 dstBox.x2 -= pScrn->frameX0; 1631 dstBox.y1 -= pScrn->frameY0; 1632 dstBox.y2 -= pScrn->frameY0; 1633 1634 pPriv->currentBuffer = 0; 1635 1636 NV10PutOverlayImage(pScrn, pPriv->video_mem, surface->offsets[0], 1637 0, surface->id, surface->pitches[0], &dstBox, 1638 xa, ya, xb, yb, surface->width, surface->height, 1639 src_w, src_h, drw_w, drw_h, clipBoxes); 1640 1641 return Success; 1642} 1643 1644/** 1645 * NVSetupBlitVideo 1646 * this function does all the work setting up a blit port 1647 * 1648 * @return blit port 1649 */ 1650static XF86VideoAdaptorPtr 1651NVSetupBlitVideo (ScreenPtr pScreen) 1652{ 1653 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1654 NVPtr pNv = NVPTR(pScrn); 1655 XF86VideoAdaptorPtr adapt; 1656 NVPortPrivPtr pPriv; 1657 int i; 1658 1659 if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) + 1660 sizeof(NVPortPrivRec) + 1661 (sizeof(DevUnion) * NUM_BLIT_PORTS)))) { 1662 return NULL; 1663 } 1664 1665 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 1666 adapt->flags = 0; 1667 adapt->name = "NV Video Blitter"; 1668 adapt->nEncodings = 1; 1669 adapt->pEncodings = &DummyEncoding; 1670 adapt->nFormats = NUM_FORMATS_ALL; 1671 adapt->pFormats = NVFormats; 1672 adapt->nPorts = NUM_BLIT_PORTS; 1673 adapt->pPortPrivates = (DevUnion*)(&adapt[1]); 1674 1675 pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_BLIT_PORTS]); 1676 for(i = 0; i < NUM_BLIT_PORTS; i++) 1677 adapt->pPortPrivates[i].ptr = (pointer)(pPriv); 1678 1679 if (pNv->dev->chipset >= 0x11) { 1680 adapt->pAttributes = NVBlitAttributes; 1681 adapt->nAttributes = NUM_BLIT_ATTRIBUTES; 1682 } else { 1683 adapt->pAttributes = NULL; 1684 adapt->nAttributes = 0; 1685 } 1686 1687 adapt->pImages = NVImages; 1688 adapt->nImages = NUM_IMAGES_ALL; 1689 adapt->PutVideo = NULL; 1690 adapt->PutStill = NULL; 1691 adapt->GetVideo = NULL; 1692 adapt->GetStill = NULL; 1693 adapt->StopVideo = NVStopBlitVideo; 1694 adapt->SetPortAttribute = NVSetBlitPortAttribute; 1695 adapt->GetPortAttribute = NVGetBlitPortAttribute; 1696 adapt->QueryBestSize = NVQueryBestSize; 1697 adapt->PutImage = NVPutImage; 1698 adapt->QueryImageAttributes = NVQueryImageAttributes; 1699 1700 pPriv->videoStatus = 0; 1701 pPriv->grabbedByV4L = FALSE; 1702 pPriv->blitter = TRUE; 1703 pPriv->texture = FALSE; 1704 pPriv->bicubic = FALSE; 1705 pPriv->doubleBuffer = FALSE; 1706 pPriv->SyncToVBlank = (pNv->dev->chipset >= 0x11); 1707 pPriv->max_image_dim = 2048; 1708 1709 pNv->blitAdaptor = adapt; 1710 1711 return adapt; 1712} 1713 1714/** 1715 * NVSetupOverlayVideo 1716 * this function does all the work setting up an overlay port 1717 * 1718 * @return overlay port 1719 */ 1720static XF86VideoAdaptorPtr 1721NVSetupOverlayVideoAdapter(ScreenPtr pScreen) 1722{ 1723 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1724 NVPtr pNv = NVPTR(pScrn); 1725 XF86VideoAdaptorPtr adapt; 1726 NVPortPrivPtr pPriv; 1727 1728 if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) + 1729 sizeof(NVPortPrivRec) + 1730 sizeof(DevUnion)))) { 1731 return NULL; 1732 } 1733 1734 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 1735 adapt->flags = VIDEO_OVERLAID_IMAGES; 1736 adapt->name = "NV Video Overlay"; 1737 adapt->nEncodings = 1; 1738 adapt->pEncodings = &DummyEncoding; 1739 adapt->nFormats = NUM_FORMATS_ALL; 1740 adapt->pFormats = NVFormats; 1741 adapt->nPorts = 1; 1742 adapt->pPortPrivates = (DevUnion*)(&adapt[1]); 1743 1744 pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[1]); 1745 adapt->pPortPrivates[0].ptr = (pointer)(pPriv); 1746 1747 adapt->pAttributes = (pNv->Architecture != NV_ARCH_04) ? NV10OverlayAttributes : NV04OverlayAttributes; 1748 adapt->nAttributes = (pNv->Architecture != NV_ARCH_04) ? NUM_NV10_OVERLAY_ATTRIBUTES : NUM_NV04_OVERLAY_ATTRIBUTES; 1749 adapt->pImages = NVImages; 1750 adapt->nImages = NUM_IMAGES_YUV; 1751 adapt->PutVideo = NULL; 1752 adapt->PutStill = NULL; 1753 adapt->GetVideo = NULL; 1754 adapt->GetStill = NULL; 1755 adapt->StopVideo = NVStopOverlayVideo; 1756 adapt->SetPortAttribute = (pNv->Architecture != NV_ARCH_04) ? NV10SetOverlayPortAttribute : NV04SetOverlayPortAttribute; 1757 adapt->GetPortAttribute = (pNv->Architecture != NV_ARCH_04) ? NV10GetOverlayPortAttribute : NV04GetOverlayPortAttribute; 1758 adapt->QueryBestSize = NVQueryBestSize; 1759 adapt->PutImage = NVPutImage; 1760 adapt->QueryImageAttributes = NVQueryImageAttributes; 1761 1762 pPriv->videoStatus = 0; 1763 pPriv->currentBuffer = 0; 1764 pPriv->grabbedByV4L = FALSE; 1765 pPriv->blitter = FALSE; 1766 pPriv->texture = FALSE; 1767 pPriv->bicubic = FALSE; 1768 pPriv->max_image_dim = 2048; 1769 1770 NVSetPortDefaults (pScrn, pPriv); 1771 1772 /* gotta uninit this someplace */ 1773 REGION_NULL(pScreen, &pPriv->clip); 1774 1775 pNv->overlayAdaptor = adapt; 1776 1777 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); 1778 xvColorKey = MAKE_ATOM("XV_COLORKEY"); 1779 xvAutopaintColorKey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY"); 1780 xvSetDefaults = MAKE_ATOM("XV_SET_DEFAULTS"); 1781 1782 if ( pNv->Architecture != NV_ARCH_04 ) 1783 { 1784 xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER"); 1785 xvContrast = MAKE_ATOM("XV_CONTRAST"); 1786 xvSaturation = MAKE_ATOM("XV_SATURATION"); 1787 xvHue = MAKE_ATOM("XV_HUE"); 1788 xvITURBT709 = MAKE_ATOM("XV_ITURBT_709"); 1789 xvOnCRTCNb = MAKE_ATOM("XV_ON_CRTC_NB"); 1790 NV10WriteOverlayParameters(pScrn); 1791 } 1792 1793 return adapt; 1794} 1795 1796 1797XF86OffscreenImageRec NVOffscreenImages[2] = { 1798 { 1799 &NVImages[0], 1800 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT, 1801 NVAllocSurface, 1802 NVFreeSurface, 1803 NVDisplaySurface, 1804 NVStopSurface, 1805 NVGetSurfaceAttribute, 1806 NVSetSurfaceAttribute, 1807 IMAGE_MAX_W, IMAGE_MAX_H, 1808 NUM_NV10_OVERLAY_ATTRIBUTES - 1, 1809 &NV10OverlayAttributes[1] 1810 }, 1811 { 1812 &NVImages[2], 1813 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT, 1814 NVAllocSurface, 1815 NVFreeSurface, 1816 NVDisplaySurface, 1817 NVStopSurface, 1818 NVGetSurfaceAttribute, 1819 NVSetSurfaceAttribute, 1820 IMAGE_MAX_W, IMAGE_MAX_H, 1821 NUM_NV10_OVERLAY_ATTRIBUTES - 1, 1822 &NV10OverlayAttributes[1] 1823 } 1824}; 1825 1826static void 1827NVInitOffscreenImages (ScreenPtr pScreen) 1828{ 1829 xf86XVRegisterOffscreenImages(pScreen, NVOffscreenImages, 2); 1830} 1831 1832/** 1833 * NVChipsetHasOverlay 1834 * 1835 * newer chips don't support overlay anymore. 1836 * overlay feature is emulated via textures. 1837 * 1838 * @param pNv 1839 * @return true, if chipset supports overlay 1840 */ 1841static Bool 1842NVChipsetHasOverlay(NVPtr pNv) 1843{ 1844 switch (pNv->Architecture) { 1845 case NV_ARCH_04: /*NV04 has a different overlay than NV10+*/ 1846 case NV_ARCH_10: 1847 case NV_ARCH_20: 1848 case NV_ARCH_30: 1849 return TRUE; 1850 case NV_ARCH_40: 1851 if (pNv->dev->chipset == 0x40) 1852 return TRUE; 1853 break; 1854 default: 1855 break; 1856 } 1857 1858 return FALSE; 1859} 1860 1861/** 1862 * NVSetupOverlayVideo 1863 * check if chipset supports Overla 1864 * if so, setup overlay port 1865 * 1866 * @return overlay port 1867 * @see NVChipsetHasOverlay(NVPtr pNv) 1868 * @see NV10SetupOverlayVideo(ScreenPtr pScreen) 1869 * @see NVInitOffscreenImages(ScreenPtr pScreen) 1870 */ 1871static XF86VideoAdaptorPtr 1872NVSetupOverlayVideo(ScreenPtr pScreen) 1873{ 1874 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1875 XF86VideoAdaptorPtr overlayAdaptor = NULL; 1876 NVPtr pNv = NVPTR(pScrn); 1877 1878 if (1 /*pNv->kms_enable*/ || !NVChipsetHasOverlay(pNv)) 1879 return NULL; 1880 1881 overlayAdaptor = NVSetupOverlayVideoAdapter(pScreen); 1882 /* I am not sure what this call does. */ 1883 if (overlayAdaptor && pNv->Architecture != NV_ARCH_04 ) 1884 NVInitOffscreenImages(pScreen); 1885 1886 #ifdef COMPOSITE 1887 if (!noCompositeExtension) { 1888 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1889 "Xv: Composite is enabled, enabling overlay with " 1890 "smart blitter fallback\n"); 1891 overlayAdaptor->name = "NV Video Overlay with Composite"; 1892 } 1893 #endif 1894 1895 return overlayAdaptor; 1896} 1897 1898/** 1899 * NV30 texture adapter. 1900 */ 1901 1902#define NUM_FORMAT_TEXTURED 2 1903 1904static XF86ImageRec NV30TexturedImages[NUM_FORMAT_TEXTURED] = 1905{ 1906 XVIMAGE_YV12, 1907 XVIMAGE_I420, 1908}; 1909 1910/** 1911 * NV30SetupTexturedVideo 1912 * this function does all the work setting up textured video port 1913 * 1914 * @return texture port 1915 */ 1916static XF86VideoAdaptorPtr 1917NV30SetupTexturedVideo (ScreenPtr pScreen, Bool bicubic) 1918{ 1919 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1920 NVPtr pNv = NVPTR(pScrn); 1921 XF86VideoAdaptorPtr adapt; 1922 NVPortPrivPtr pPriv; 1923 int i; 1924 1925 if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) + 1926 sizeof(NVPortPrivRec) + 1927 (sizeof(DevUnion) * NUM_TEXTURE_PORTS)))) { 1928 return NULL; 1929 } 1930 1931 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 1932 adapt->flags = 0; 1933 if (bicubic) 1934 adapt->name = "NV30 high quality adapter"; 1935 else 1936 adapt->name = "NV30 texture adapter"; 1937 adapt->nEncodings = 1; 1938 adapt->pEncodings = &DummyEncodingTex; 1939 adapt->nFormats = NUM_FORMATS_ALL; 1940 adapt->pFormats = NVFormats; 1941 adapt->nPorts = NUM_TEXTURE_PORTS; 1942 adapt->pPortPrivates = (DevUnion*)(&adapt[1]); 1943 1944 pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_TEXTURE_PORTS]); 1945 for(i = 0; i < NUM_TEXTURE_PORTS; i++) 1946 adapt->pPortPrivates[i].ptr = (pointer)(pPriv); 1947 1948 adapt->pAttributes = NVTexturedAttributes; 1949 adapt->nAttributes = NUM_TEXTURED_ATTRIBUTES; 1950 adapt->pImages = NV30TexturedImages; 1951 adapt->nImages = NUM_FORMAT_TEXTURED; 1952 adapt->PutVideo = NULL; 1953 adapt->PutStill = NULL; 1954 adapt->GetVideo = NULL; 1955 adapt->GetStill = NULL; 1956 adapt->StopVideo = NV30StopTexturedVideo; 1957 adapt->SetPortAttribute = NV30SetTexturePortAttribute; 1958 adapt->GetPortAttribute = NV30GetTexturePortAttribute; 1959 adapt->QueryBestSize = NVQueryBestSize; 1960 adapt->PutImage = NVPutImage; 1961 adapt->QueryImageAttributes = NVQueryImageAttributes; 1962 1963 pPriv->videoStatus = 0; 1964 pPriv->grabbedByV4L = FALSE; 1965 pPriv->blitter = FALSE; 1966 pPriv->texture = TRUE; 1967 pPriv->bicubic = bicubic; 1968 pPriv->doubleBuffer = FALSE; 1969 pPriv->SyncToVBlank = TRUE; 1970 pPriv->max_image_dim = 4096; 1971 1972 if (bicubic) 1973 pNv->textureAdaptor[1] = adapt; 1974 else 1975 pNv->textureAdaptor[0] = adapt; 1976 1977 return adapt; 1978} 1979 1980/** 1981 * NV40 texture adapter. 1982 */ 1983 1984#define NUM_FORMAT_TEXTURED 2 1985 1986static XF86ImageRec NV40TexturedImages[NUM_FORMAT_TEXTURED] = 1987{ 1988 XVIMAGE_YV12, 1989 XVIMAGE_I420, 1990}; 1991 1992/** 1993 * NV40SetupTexturedVideo 1994 * this function does all the work setting up textured video port 1995 * 1996 * @return texture port 1997 */ 1998static XF86VideoAdaptorPtr 1999NV40SetupTexturedVideo (ScreenPtr pScreen, Bool bicubic) 2000{ 2001 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 2002 NVPtr pNv = NVPTR(pScrn); 2003 XF86VideoAdaptorPtr adapt; 2004 NVPortPrivPtr pPriv; 2005 int i; 2006 2007 if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) + 2008 sizeof(NVPortPrivRec) + 2009 (sizeof(DevUnion) * NUM_TEXTURE_PORTS)))) { 2010 return NULL; 2011 } 2012 2013 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 2014 adapt->flags = 0; 2015 if (bicubic) 2016 adapt->name = "NV40 high quality adapter"; 2017 else 2018 adapt->name = "NV40 texture adapter"; 2019 adapt->nEncodings = 1; 2020 adapt->pEncodings = &DummyEncodingTex; 2021 adapt->nFormats = NUM_FORMATS_ALL; 2022 adapt->pFormats = NVFormats; 2023 adapt->nPorts = NUM_TEXTURE_PORTS; 2024 adapt->pPortPrivates = (DevUnion*)(&adapt[1]); 2025 2026 pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_TEXTURE_PORTS]); 2027 for(i = 0; i < NUM_TEXTURE_PORTS; i++) 2028 adapt->pPortPrivates[i].ptr = (pointer)(pPriv); 2029 2030 adapt->pAttributes = NVTexturedAttributes; 2031 adapt->nAttributes = NUM_TEXTURED_ATTRIBUTES; 2032 adapt->pImages = NV40TexturedImages; 2033 adapt->nImages = NUM_FORMAT_TEXTURED; 2034 adapt->PutVideo = NULL; 2035 adapt->PutStill = NULL; 2036 adapt->GetVideo = NULL; 2037 adapt->GetStill = NULL; 2038 adapt->StopVideo = NV40StopTexturedVideo; 2039 adapt->SetPortAttribute = NV40SetTexturePortAttribute; 2040 adapt->GetPortAttribute = NV40GetTexturePortAttribute; 2041 adapt->QueryBestSize = NVQueryBestSize; 2042 adapt->PutImage = NVPutImage; 2043 adapt->QueryImageAttributes = NVQueryImageAttributes; 2044 2045 pPriv->videoStatus = 0; 2046 pPriv->grabbedByV4L = FALSE; 2047 pPriv->blitter = FALSE; 2048 pPriv->texture = TRUE; 2049 pPriv->bicubic = bicubic; 2050 pPriv->doubleBuffer = FALSE; 2051 pPriv->SyncToVBlank = TRUE; 2052 pPriv->max_image_dim = 4096; 2053 2054 if (bicubic) 2055 pNv->textureAdaptor[1] = adapt; 2056 else 2057 pNv->textureAdaptor[0] = adapt; 2058 2059 return adapt; 2060} 2061 2062static XF86ImageRec 2063NV50TexturedImages[] = 2064{ 2065 XVIMAGE_YV12, 2066 XVIMAGE_I420, 2067 XVIMAGE_YUY2, 2068 XVIMAGE_UYVY 2069}; 2070 2071static XF86VideoAdaptorPtr 2072NV50SetupTexturedVideo (ScreenPtr pScreen) 2073{ 2074 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 2075 NVPtr pNv = NVPTR(pScrn); 2076 XF86VideoAdaptorPtr adapt; 2077 NVPortPrivPtr pPriv; 2078 int i; 2079 2080 if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) + 2081 sizeof(NVPortPrivRec) + 2082 (sizeof(DevUnion) * NUM_TEXTURE_PORTS)))) { 2083 return NULL; 2084 } 2085 2086 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 2087 adapt->flags = 0; 2088 adapt->name = "Nouveau GeForce 8/9 Textured Video"; 2089 adapt->nEncodings = 1; 2090 adapt->pEncodings = &DummyEncodingNV50; 2091 adapt->nFormats = NUM_FORMATS_ALL; 2092 adapt->pFormats = NVFormats; 2093 adapt->nPorts = NUM_TEXTURE_PORTS; 2094 adapt->pPortPrivates = (DevUnion*)(&adapt[1]); 2095 2096 pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_TEXTURE_PORTS]); 2097 for(i = 0; i < NUM_TEXTURE_PORTS; i++) 2098 adapt->pPortPrivates[i].ptr = (pointer)(pPriv); 2099 2100 adapt->pAttributes = NVTexturedAttributesNV50; 2101 adapt->nAttributes = NUM_TEXTURED_ATTRIBUTES_NV50; 2102 adapt->pImages = NV50TexturedImages; 2103 adapt->nImages = sizeof(NV50TexturedImages) / 2104 sizeof(NV50TexturedImages[0]); 2105 adapt->PutVideo = NULL; 2106 adapt->PutStill = NULL; 2107 adapt->GetVideo = NULL; 2108 adapt->GetStill = NULL; 2109 adapt->StopVideo = nv50_xv_video_stop; 2110 adapt->SetPortAttribute = nv50_xv_port_attribute_set; 2111 adapt->GetPortAttribute = nv50_xv_port_attribute_get; 2112 adapt->QueryBestSize = NVQueryBestSize; 2113 adapt->PutImage = NVPutImage; 2114 adapt->QueryImageAttributes = NVQueryImageAttributes; 2115 2116 pNv->textureAdaptor[0] = adapt; 2117 2118 nv50_xv_set_port_defaults(pScrn, pPriv); 2119 nv50_xv_csc_update(pScrn, pPriv); 2120 2121 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); 2122 xvContrast = MAKE_ATOM("XV_CONTRAST"); 2123 xvSaturation = MAKE_ATOM("XV_SATURATION"); 2124 xvHue = MAKE_ATOM("XV_HUE"); 2125 xvITURBT709 = MAKE_ATOM("XV_ITURBT_709"); 2126 return adapt; 2127} 2128 2129void 2130NVSetupTexturedVideo (ScreenPtr pScreen, XF86VideoAdaptorPtr *textureAdaptor) 2131{ 2132 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 2133 NVPtr pNv = NVPTR(pScrn); 2134 2135 if (!pNv->Nv3D) 2136 return; 2137 2138 if (pNv->Architecture == NV_ARCH_30) { 2139 textureAdaptor[0] = NV30SetupTexturedVideo(pScreen, FALSE); 2140 textureAdaptor[1] = NV30SetupTexturedVideo(pScreen, TRUE); 2141 } else 2142 if (pNv->Architecture == NV_ARCH_40) { 2143 textureAdaptor[0] = NV40SetupTexturedVideo(pScreen, FALSE); 2144 textureAdaptor[1] = NV40SetupTexturedVideo(pScreen, TRUE); 2145 } else 2146 if (pNv->Architecture >= NV_TESLA) { 2147 textureAdaptor[0] = NV50SetupTexturedVideo(pScreen); 2148 } 2149} 2150 2151/** 2152 * NVInitVideo 2153 * tries to initialize the various supported adapters 2154 * and add them to the list of ports on screen "pScreen". 2155 * 2156 * @param pScreen 2157 * @see NVSetupOverlayVideo(ScreenPtr pScreen) 2158 * @see NVSetupBlitVideo(ScreenPtr pScreen) 2159 */ 2160void 2161NVInitVideo(ScreenPtr pScreen) 2162{ 2163 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 2164 NVPtr pNv = NVPTR(pScrn); 2165 XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; 2166 XF86VideoAdaptorPtr overlayAdaptor = NULL; 2167 XF86VideoAdaptorPtr blitAdaptor = NULL; 2168 XF86VideoAdaptorPtr textureAdaptor[2] = {NULL, NULL}; 2169 int num_adaptors; 2170 2171 /* 2172 * Driving the blitter requires the DMA FIFO. Using the FIFO 2173 * without accel causes DMA errors. While the overlay might 2174 * might work without accel, we also disable it for now when 2175 * acceleration is disabled: 2176 */ 2177 if (pScrn->bitsPerPixel != 8 && pNv->AccelMethod == EXA) { 2178 xvSyncToVBlank = MAKE_ATOM("XV_SYNC_TO_VBLANK"); 2179 2180 if (pNv->Architecture < NV_TESLA) { 2181 overlayAdaptor = NVSetupOverlayVideo(pScreen); 2182 blitAdaptor = NVSetupBlitVideo(pScreen); 2183 } 2184 2185 NVSetupTexturedVideo(pScreen, textureAdaptor); 2186 } 2187 2188 num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); 2189 if (blitAdaptor || overlayAdaptor || textureAdaptor[0]) { 2190 int size = num_adaptors; 2191 2192 if(overlayAdaptor) size++; 2193 if(blitAdaptor) size++; 2194 if(textureAdaptor[0]) size++; 2195 if(textureAdaptor[1]) size++; 2196 2197 newAdaptors = malloc(size * sizeof(XF86VideoAdaptorPtr *)); 2198 if(newAdaptors) { 2199 if(num_adaptors) { 2200 memcpy(newAdaptors, adaptors, num_adaptors * 2201 sizeof(XF86VideoAdaptorPtr)); 2202 } 2203 2204 if(overlayAdaptor) { 2205 newAdaptors[num_adaptors] = overlayAdaptor; 2206 num_adaptors++; 2207 } 2208 2209 if (textureAdaptor[0]) { /* bilinear */ 2210 newAdaptors[num_adaptors] = textureAdaptor[0]; 2211 num_adaptors++; 2212 } 2213 2214 if (textureAdaptor[1]) { /* bicubic */ 2215 newAdaptors[num_adaptors] = textureAdaptor[1]; 2216 num_adaptors++; 2217 } 2218 2219 if(blitAdaptor) { 2220 newAdaptors[num_adaptors] = blitAdaptor; 2221 num_adaptors++; 2222 } 2223 2224 adaptors = newAdaptors; 2225 } 2226 } 2227 2228 if (num_adaptors) 2229 xf86XVScreenInit(pScreen, adaptors, num_adaptors); 2230 if (newAdaptors) 2231 free(newAdaptors); 2232 2233 /* 2234 * For now we associate with the plain texture adapter since it is logical, but we can 2235 * associate with any/all adapters since VL doesn't depend on Xv for color conversion. 2236 */ 2237 if (textureAdaptor[0]) { 2238 XF86MCAdaptorPtr *adaptorsXvMC = malloc(sizeof(XF86MCAdaptorPtr)); 2239 2240 if (adaptorsXvMC) { 2241 adaptorsXvMC[0] = vlCreateAdaptorXvMC(pScreen, textureAdaptor[0]->name); 2242 2243 if (adaptorsXvMC[0]) { 2244 vlInitXvMC(pScreen, 1, adaptorsXvMC); 2245 vlDestroyAdaptorXvMC(adaptorsXvMC[0]); 2246 } 2247 2248 free(adaptorsXvMC); 2249 } 2250 } 2251} 2252 2253void 2254NVTakedownVideo(ScrnInfoPtr pScrn) 2255{ 2256 NVPtr pNv = NVPTR(pScrn); 2257 2258 if (pNv->blitAdaptor) 2259 NVFreePortMemory(pScrn, GET_BLIT_PRIVATE(pNv)); 2260 if (pNv->textureAdaptor[0]) { 2261 NVFreePortMemory(pScrn, 2262 pNv->textureAdaptor[0]->pPortPrivates[0].ptr); 2263 } 2264 if (pNv->textureAdaptor[1]) { 2265 NVFreePortMemory(pScrn, 2266 pNv->textureAdaptor[1]->pPortPrivates[0].ptr); 2267 } 2268} 2269 2270/* The filtering function used for video scaling. We use a cubic filter as 2271 * defined in "Reconstruction Filters in Computer Graphics" Mitchell & 2272 * Netravali in SIGGRAPH '88 2273 */ 2274static float filter_func(float x) 2275{ 2276 const double B=0.75; 2277 const double C=(1.0-B)/2.0; 2278 double x1=fabs(x); 2279 double x2=fabs(x)*x1; 2280 double x3=fabs(x)*x2; 2281 2282 if (fabs(x)<1.0) 2283 return ( (12.0-9.0*B-6.0*C)*x3+(-18.0+12.0*B+6.0*C)*x2+(6.0-2.0*B) )/6.0; 2284 else 2285 return ( (-B-6.0*C)*x3+(6.0*B+30.0*C)*x2+(-12.0*B-48.0*C)*x1+(8.0*B+24.0*C) )/6.0; 2286} 2287 2288static int8_t f32tosb8(float v) 2289{ 2290 return (int8_t)(v*127.0); 2291} 2292 2293void 2294NVXVComputeBicubicFilter(struct nouveau_bo *bo, unsigned offset, unsigned size) 2295{ 2296 int8_t *t = (int8_t *)(bo->map + offset); 2297 int i; 2298 2299 for(i = 0; i < size; i++) { 2300 float x = (i + 0.5) / size; 2301 float w0 = filter_func(x+1.0); 2302 float w1 = filter_func(x); 2303 float w2 = filter_func(x-1.0); 2304 float w3 = filter_func(x-2.0); 2305 2306 t[4*i+2]=f32tosb8(1.0+x-w1/(w0+w1)); 2307 t[4*i+1]=f32tosb8(1.0-x+w3/(w2+w3)); 2308 t[4*i+0]=f32tosb8(w0+w1); 2309 t[4*i+3]=f32tosb8(0.0); 2310 } 2311} 2312