r128_video.c revision 0496e070
1 2#ifdef HAVE_CONFIG_H 3#include "config.h" 4#endif 5 6#include <string.h> 7 8#include "r128.h" 9#include "r128_reg.h" 10 11#ifdef R128DRI 12#include "r128_common.h" 13#include "r128_sarea.h" 14#endif 15 16#include "xf86.h" 17#include "dixstruct.h" 18 19#include <X11/extensions/Xv.h> 20#include "fourcc.h" 21 22#define OFF_DELAY 250 /* milliseconds */ 23#define FREE_DELAY 15000 24 25#define OFF_TIMER 0x01 26#define FREE_TIMER 0x02 27#define CLIENT_VIDEO_ON 0x04 28 29#define TIMER_MASK (OFF_TIMER | FREE_TIMER) 30 31static XF86VideoAdaptorPtr R128SetupImageVideo(ScreenPtr); 32static int R128SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer); 33static int R128GetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer); 34static void R128StopVideo(ScrnInfoPtr, pointer, Bool); 35static void R128QueryBestSize(ScrnInfoPtr, Bool, short, short, short, short, 36 unsigned int *, unsigned int *, pointer); 37static int R128PutImage(ScrnInfoPtr, short, short, short, short, short, 38 short, short, short, int, unsigned char*, short, 39 short, Bool, RegionPtr, pointer, DrawablePtr); 40static int R128QueryImageAttributes(ScrnInfoPtr, int, unsigned short *, 41 unsigned short *, int *, int *); 42 43 44static void R128ResetVideo(ScrnInfoPtr); 45 46static void R128VideoTimerCallback(ScrnInfoPtr pScrn, Time now); 47 48 49#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) 50 51static Atom xvBrightness, xvColorKey, xvSaturation, xvDoubleBuffer; 52 53 54typedef struct { 55 int brightness; 56 int saturation; 57 Bool doubleBuffer; 58 unsigned char currentBuffer; 59 void* BufferHandle; 60 int videoOffset; 61 RegionRec clip; 62 CARD32 colorKey; 63 CARD32 videoStatus; 64 Time offTime; 65 Time freeTime; 66 int ecp_div; 67} R128PortPrivRec, *R128PortPrivPtr; 68 69static void R128ECP(ScrnInfoPtr pScrn, R128PortPrivPtr pPriv) 70{ 71 R128InfoPtr info = R128PTR(pScrn); 72 unsigned char *R128MMIO = info->MMIO; 73 int dot_clock = info->ModeReg.dot_clock_freq; 74 75 if (dot_clock < 12500) pPriv->ecp_div = 0; 76 else if (dot_clock < 25000) pPriv->ecp_div = 1; 77 else pPriv->ecp_div = 2; 78 79 OUTPLLP(pScrn, R128_VCLK_ECP_CNTL, pPriv->ecp_div<<8, ~R128_ECP_DIV_MASK); 80} 81 82void R128InitVideo(ScreenPtr pScreen) 83{ 84 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 85 XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; 86 XF86VideoAdaptorPtr newAdaptor = NULL; 87 int num_adaptors; 88 89 newAdaptor = R128SetupImageVideo(pScreen); 90 91 num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); 92 93 if(newAdaptor) { 94 if(!num_adaptors) { 95 num_adaptors = 1; 96 adaptors = &newAdaptor; 97 } else { 98 newAdaptors = /* need to free this someplace */ 99 malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*)); 100 if(newAdaptors) { 101 memcpy(newAdaptors, adaptors, num_adaptors * 102 sizeof(XF86VideoAdaptorPtr)); 103 newAdaptors[num_adaptors] = newAdaptor; 104 adaptors = newAdaptors; 105 num_adaptors++; 106 } 107 } 108 } 109 110 if(num_adaptors) 111 xf86XVScreenInit(pScreen, adaptors, num_adaptors); 112 113 if(newAdaptors) 114 free(newAdaptors); 115} 116 117#define MAXWIDTH 2048 118#define MAXHEIGHT 2048 119 120/* client libraries expect an encoding */ 121static XF86VideoEncodingRec DummyEncoding = 122{ 123 0, 124 "XV_IMAGE", 125 MAXWIDTH, MAXHEIGHT, 126 {1, 1} 127}; 128 129#define NUM_FORMATS 12 130 131static XF86VideoFormatRec Formats[NUM_FORMATS] = 132{ 133 {8, TrueColor}, {8, DirectColor}, {8, PseudoColor}, 134 {8, GrayScale}, {8, StaticGray}, {8, StaticColor}, 135 {15, TrueColor}, {16, TrueColor}, {24, TrueColor}, 136 {15, DirectColor}, {16, DirectColor}, {24, DirectColor} 137}; 138 139 140#define NUM_ATTRIBUTES 4 141 142static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = 143{ 144 {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, 145 {XvSettable | XvGettable, -64, 63, "XV_BRIGHTNESS"}, 146 {XvSettable | XvGettable, 0, 31, "XV_SATURATION"}, 147 {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"} 148}; 149 150#define NUM_IMAGES 4 151 152static XF86ImageRec Images[NUM_IMAGES] = 153{ 154 XVIMAGE_YUY2, 155 XVIMAGE_UYVY, 156 XVIMAGE_YV12, 157 XVIMAGE_I420 158}; 159 160static void 161R128ResetVideo(ScrnInfoPtr pScrn) 162{ 163 R128InfoPtr info = R128PTR(pScrn); 164 unsigned char *R128MMIO = info->MMIO; 165 R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr; 166 167 168 OUTREG(R128_OV0_SCALE_CNTL, 0x80000000); 169 OUTREG(R128_OV0_EXCLUSIVE_HORZ, 0); 170 OUTREG(R128_OV0_AUTO_FLIP_CNTL, 0); /* maybe */ 171 OUTREG(R128_OV0_FILTER_CNTL, 0x0000000f); 172 OUTREG(R128_OV0_COLOUR_CNTL, (pPriv->brightness & 0x7f) | 173 (pPriv->saturation << 8) | 174 (pPriv->saturation << 16)); 175 OUTREG(R128_OV0_GRAPHICS_KEY_MSK, (1 << pScrn->depth) - 1); 176 OUTREG(R128_OV0_GRAPHICS_KEY_CLR, pPriv->colorKey); 177 OUTREG(R128_OV0_KEY_CNTL, R128_GRAPHIC_KEY_FN_NE); 178 OUTREG(R128_OV0_TEST, 0); 179} 180 181 182static XF86VideoAdaptorPtr 183R128AllocAdaptor(ScrnInfoPtr pScrn) 184{ 185 XF86VideoAdaptorPtr adapt; 186 R128InfoPtr info = R128PTR(pScrn); 187 R128PortPrivPtr pPriv; 188 189 if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn))) 190 return NULL; 191 192 if(!(pPriv = calloc(1, sizeof(R128PortPrivRec) + sizeof(DevUnion)))) 193 { 194 free(adapt); 195 return NULL; 196 } 197 198 adapt->pPortPrivates = (DevUnion*)(&pPriv[1]); 199 adapt->pPortPrivates[0].ptr = (pointer)pPriv; 200 201 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); 202 xvSaturation = MAKE_ATOM("XV_SATURATION"); 203 xvColorKey = MAKE_ATOM("XV_COLORKEY"); 204 xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER"); 205 206 pPriv->colorKey = info->videoKey; 207 pPriv->doubleBuffer = TRUE; 208 pPriv->videoStatus = 0; 209 pPriv->brightness = 0; 210 pPriv->saturation = 16; 211 pPriv->currentBuffer = 0; 212 R128ECP(pScrn, pPriv); 213 214 return adapt; 215} 216 217static XF86VideoAdaptorPtr 218R128SetupImageVideo(ScreenPtr pScreen) 219{ 220 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 221 R128InfoPtr info = R128PTR(pScrn); 222 R128PortPrivPtr pPriv; 223 XF86VideoAdaptorPtr adapt; 224 225 if(!(adapt = R128AllocAdaptor(pScrn))) 226 return NULL; 227 228 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 229 adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; 230 adapt->name = "ATI Rage128 Video Overlay"; 231 adapt->nEncodings = 1; 232 adapt->pEncodings = &DummyEncoding; 233 adapt->nFormats = NUM_FORMATS; 234 adapt->pFormats = Formats; 235 adapt->nPorts = 1; 236 adapt->nAttributes = NUM_ATTRIBUTES; 237 adapt->pAttributes = Attributes; 238 adapt->nImages = NUM_IMAGES; 239 adapt->pImages = Images; 240 adapt->PutVideo = NULL; 241 adapt->PutStill = NULL; 242 adapt->GetVideo = NULL; 243 adapt->GetStill = NULL; 244 adapt->StopVideo = R128StopVideo; 245 adapt->SetPortAttribute = R128SetPortAttribute; 246 adapt->GetPortAttribute = R128GetPortAttribute; 247 adapt->QueryBestSize = R128QueryBestSize; 248 adapt->PutImage = R128PutImage; 249 adapt->QueryImageAttributes = R128QueryImageAttributes; 250 251 info->adaptor = adapt; 252 253 pPriv = (R128PortPrivPtr)(adapt->pPortPrivates[0].ptr); 254 REGION_NULL(pScreen, &(pPriv->clip)); 255 256 R128ResetVideo(pScrn); 257 258 return adapt; 259} 260 261static void 262R128StopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup) 263{ 264 R128InfoPtr info = R128PTR(pScrn); 265 unsigned char *R128MMIO = info->MMIO; 266 R128PortPrivPtr pPriv = (R128PortPrivPtr)data; 267 268 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); 269 270 if(cleanup) { 271 if(pPriv->videoStatus & CLIENT_VIDEO_ON) { 272 OUTREG(R128_OV0_SCALE_CNTL, 0); 273 } 274 if(pPriv->BufferHandle) { 275 if (!info->useEXA) { 276 xf86FreeOffscreenLinear((FBLinearPtr) pPriv->BufferHandle); 277 } 278#ifdef USE_EXA 279 else { 280 exaOffscreenFree(pScrn->pScreen, (ExaOffscreenArea *) pPriv->BufferHandle); 281 } 282#endif 283 pPriv->BufferHandle = NULL; 284 } 285 pPriv->videoStatus = 0; 286 } else { 287 if(pPriv->videoStatus & CLIENT_VIDEO_ON) { 288 pPriv->videoStatus |= OFF_TIMER; 289 pPriv->offTime = currentTime.milliseconds + OFF_DELAY; 290 } 291 } 292} 293 294static int 295R128SetPortAttribute( 296 ScrnInfoPtr pScrn, 297 Atom attribute, 298 INT32 value, 299 pointer data 300){ 301 R128InfoPtr info = R128PTR(pScrn); 302 unsigned char *R128MMIO = info->MMIO; 303 R128PortPrivPtr pPriv = (R128PortPrivPtr)data; 304 305 if(attribute == xvBrightness) { 306 if((value < -64) || (value > 63)) 307 return BadValue; 308 pPriv->brightness = value; 309 310 OUTREG(R128_OV0_COLOUR_CNTL, (pPriv->brightness & 0x7f) | 311 (pPriv->saturation << 8) | 312 (pPriv->saturation << 16)); 313 } else 314 if(attribute == xvSaturation) { 315 if((value < 0) || (value > 31)) 316 return BadValue; 317 pPriv->saturation = value; 318 319 OUTREG(R128_OV0_COLOUR_CNTL, (pPriv->brightness & 0x7f) | 320 (pPriv->saturation << 8) | 321 (pPriv->saturation << 16)); 322 } else 323 if(attribute == xvDoubleBuffer) { 324 if((value < 0) || (value > 1)) 325 return BadValue; 326 pPriv->doubleBuffer = value; 327 } else 328 if(attribute == xvColorKey) { 329 pPriv->colorKey = value; 330 OUTREG(R128_OV0_GRAPHICS_KEY_CLR, pPriv->colorKey); 331 332 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); 333 } else return BadMatch; 334 335 return Success; 336} 337 338static int 339R128GetPortAttribute( 340 ScrnInfoPtr pScrn, 341 Atom attribute, 342 INT32 *value, 343 pointer data 344){ 345 R128PortPrivPtr pPriv = (R128PortPrivPtr)data; 346 347 if(attribute == xvBrightness) { 348 *value = pPriv->brightness; 349 } else 350 if(attribute == xvSaturation) { 351 *value = pPriv->saturation; 352 } else 353 if(attribute == xvDoubleBuffer) { 354 *value = pPriv->doubleBuffer ? 1 : 0; 355 } else 356 if(attribute == xvColorKey) { 357 *value = pPriv->colorKey; 358 } else return BadMatch; 359 360 return Success; 361} 362 363 364static void 365R128QueryBestSize( 366 ScrnInfoPtr pScrn, 367 Bool motion, 368 short vid_w, short vid_h, 369 short drw_w, short drw_h, 370 unsigned int *p_w, unsigned int *p_h, 371 pointer data 372){ 373 if(vid_w > (drw_w << 4)) 374 drw_w = vid_w >> 4; 375 if(vid_h > (drw_h << 4)) 376 drw_h = vid_h >> 4; 377 378 *p_w = drw_w; 379 *p_h = drw_h; 380} 381 382 383/* 384 * 385 * R128DMA - abuse the texture blit ioctl to transfer rectangular blocks 386 * 387 * The block is split into 'passes' pieces of 'hpass' lines which fit entirely 388 * into an indirect buffer 389 * 390 */ 391 392Bool 393R128DMA( 394 R128InfoPtr info, 395 unsigned char *src, 396 unsigned char *dst, 397 int srcPitch, 398 int dstPitch, 399 int h, 400 int w 401){ 402 403#ifdef R128DRI 404 405#define BUFSIZE (R128_BUFFER_SIZE - R128_HOSTDATA_BLIT_OFFSET) 406#define MAXPASSES (MAXHEIGHT/(BUFSIZE/(MAXWIDTH*2))+1) 407 408 unsigned char *fb = (CARD8*)info->FB; 409 unsigned char *buf; 410 int err=-1, i, idx, offset, hpass, passes, srcpassbytes, dstpassbytes; 411 int sizes[MAXPASSES], list[MAXPASSES]; 412 drmDMAReq req; 413 drmR128Blit blit; 414 415 /* Verify conditions and bail out as early as possible */ 416 if (!info->directRenderingEnabled || !info->DMAForXv) 417 return FALSE; 418 419 if ((hpass = min(h,(BUFSIZE/w))) == 0) 420 return FALSE; 421 422 if ((passes = (h+hpass-1)/hpass) > MAXPASSES) 423 return FALSE; 424 425 /* Request indirect buffers */ 426 srcpassbytes = w*hpass; 427 428 req.context = info->drmCtx; 429 req.send_count = 0; 430 req.send_list = NULL; 431 req.send_sizes = NULL; 432 req.flags = DRM_DMA_LARGER_OK; 433 req.request_count = passes; 434 req.request_size = srcpassbytes + R128_HOSTDATA_BLIT_OFFSET; 435 req.request_list = &list[0]; 436 req.request_sizes = &sizes[0]; 437 req.granted_count = 0; 438 439 if (drmDMA(info->drmFD, &req)) 440 return FALSE; 441 442 if (req.granted_count < passes) { 443 drmFreeBufs(info->drmFD, req.granted_count, req.request_list); 444 return FALSE; 445 } 446 447 /* Copy parts of the block into buffers and fire them */ 448 dstpassbytes = hpass*dstPitch; 449 dstPitch /= 8; 450 451 for (i=0, offset=dst-fb; i<passes; i++, offset+=dstpassbytes) { 452 if (i == (passes-1) && (h % hpass) != 0) { 453 hpass = h % hpass; 454 srcpassbytes = w*hpass; 455 } 456 457 idx = req.request_list[i]; 458 buf = (unsigned char *) info->buffers->list[idx].address + R128_HOSTDATA_BLIT_OFFSET; 459 460 if (srcPitch == w) { 461 memcpy(buf, src, srcpassbytes); 462 src += srcpassbytes; 463 } else { 464 int count = hpass; 465 while(count--) { 466 memcpy(buf, src, w); 467 src += srcPitch; 468 buf += w; 469 } 470 } 471 472 blit.idx = idx; 473 blit.offset = offset; 474 blit.pitch = dstPitch; 475 blit.format = (R128_DATATYPE_CI8 >> 16); 476 blit.x = (offset % 32); 477 blit.y = 0; 478 blit.width = w; 479 blit.height = hpass; 480 481 if ((err = drmCommandWrite(info->drmFD, DRM_R128_BLIT, 482 &blit, sizeof(drmR128Blit))) < 0) 483 break; 484 } 485 486 drmFreeBufs(info->drmFD, req.granted_count, req.request_list); 487 488 return (err==0) ? TRUE : FALSE; 489 490#else 491 492 /* This is to avoid cluttering the rest of the code with '#ifdef R128DRI' */ 493 return FALSE; 494 495#endif /* R128DRI */ 496 497} 498 499 500static void 501R128CopyData422( 502 R128InfoPtr info, 503 unsigned char *src, 504 unsigned char *dst, 505 int srcPitch, 506 int dstPitch, 507 int h, 508 int w 509){ 510 w <<= 1; 511 512 /* Attempt data transfer with DMA and fall back to memcpy */ 513 514 if (!R128DMA(info, src, dst, srcPitch, dstPitch, h, w)) { 515 while(h--) { 516 memcpy(dst, src, w); 517 src += srcPitch; 518 dst += dstPitch; 519 } 520 } 521} 522 523static void 524R128CopyData420( 525 R128InfoPtr info, 526 unsigned char *src1, 527 unsigned char *src2, 528 unsigned char *src3, 529 unsigned char *dst1, 530 unsigned char *dst2, 531 unsigned char *dst3, 532 int srcPitch, 533 int srcPitch2, 534 int dstPitch, 535 int h, 536 int w 537){ 538 int count; 539 540 /* Attempt data transfer with DMA and fall back to memcpy */ 541 542 if (!R128DMA(info, src1, dst1, srcPitch, dstPitch, h, w)) { 543 count = h; 544 while(count--) { 545 memcpy(dst1, src1, w); 546 src1 += srcPitch; 547 dst1 += dstPitch; 548 } 549 } 550 551 w >>= 1; 552 h >>= 1; 553 dstPitch >>= 1; 554 555 if (!R128DMA(info, src2, dst2, srcPitch2, dstPitch, h, w)) { 556 count = h; 557 while(count--) { 558 memcpy(dst2, src2, w); 559 src2 += srcPitch2; 560 dst2 += dstPitch; 561 } 562 } 563 564 if (!R128DMA(info, src3, dst3, srcPitch2, dstPitch, h, w)) { 565 count = h; 566 while(count--) { 567 memcpy(dst3, src3, w); 568 src3 += srcPitch2; 569 dst3 += dstPitch; 570 } 571 } 572} 573 574 575static CARD32 576R128AllocateMemory( 577 ScrnInfoPtr pScrn, 578 void **mem_struct, 579 int size 580){ 581 R128InfoPtr info = R128PTR(pScrn); 582 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 583 int offset = 0; 584 585 if(!info->useEXA) { 586 FBLinearPtr linear = *mem_struct; 587 int cpp = info->CurrentLayout.pixel_bytes; 588 589 /* XAA allocates in units of pixels at the screen bpp, so adjust size appropriately. */ 590 size = (size + cpp - 1) / cpp; 591 592 if(linear) { 593 if(linear->size >= size) 594 return linear->offset * cpp; 595 596 if(xf86ResizeOffscreenLinear(linear, size)) 597 return linear->offset * cpp; 598 599 xf86FreeOffscreenLinear(linear); 600 } 601 602 603 linear = xf86AllocateOffscreenLinear(pScreen, size, 8, 604 NULL, NULL, NULL); 605 *mem_struct = linear; 606 607 if(!linear) { 608 int max_size; 609 610 xf86QueryLargestOffscreenLinear(pScreen, &max_size, 8, 611 PRIORITY_EXTREME); 612 613 if(max_size < size) 614 return 0; 615 616 xf86PurgeUnlockedOffscreenAreas(pScreen); 617 linear = xf86AllocateOffscreenLinear(pScreen, size, 8, 618 NULL, NULL, NULL); 619 620 if(!linear) return 0; 621 } 622 623 offset = linear->offset * cpp; 624 } 625#ifdef USE_EXA 626 else { 627 /* EXA support based on mga driver */ 628 ExaOffscreenArea *area = *mem_struct; 629 630 if(area) { 631 if(area->size >= size) 632 return area->offset; 633 634 exaOffscreenFree(pScrn->pScreen, area); 635 } 636 637 area = exaOffscreenAlloc(pScrn->pScreen, size, 64, TRUE, NULL, NULL); 638 *mem_struct = area; 639 640 if(!area) return 0; 641 642 offset = area->offset; 643 } 644#endif 645 646 return offset; 647} 648 649static void 650R128DisplayVideo422( 651 ScrnInfoPtr pScrn, 652 int id, 653 int offset, 654 short width, short height, 655 int pitch, 656 int left, int right, int top, 657 BoxPtr dstBox, 658 short src_w, short src_h, 659 short drw_w, short drw_h 660){ 661 R128InfoPtr info = R128PTR(pScrn); 662 unsigned char *R128MMIO = info->MMIO; 663 R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr; 664 int v_inc, h_inc, step_by, tmp, v_inc_shift; 665 int p1_h_accum_init, p23_h_accum_init; 666 int p1_v_accum_init; 667 Bool rmx_active; 668 669 R128ECP(pScrn, pPriv); 670 671 v_inc_shift = 20; 672 if (pScrn->currentMode->Flags & V_INTERLACE) 673 v_inc_shift++; 674 if (pScrn->currentMode->Flags & V_DBLSCAN) 675 v_inc_shift--; 676 677 rmx_active = INREG(R128_FP_VERT_STRETCH) & R128_VERT_STRETCH_ENABLE; 678 if (rmx_active) { 679 v_inc = ((src_h * pScrn->currentMode->CrtcVDisplay / info->PanelYRes) << v_inc_shift) / drw_h; 680 } else { 681 v_inc = (src_h << v_inc_shift) / drw_h; 682 } 683 h_inc = (src_w << (12 + pPriv->ecp_div)) / drw_w; 684 step_by = 1; 685 686 while(h_inc >= (2 << 12)) { 687 step_by++; 688 h_inc >>= 1; 689 } 690 691 /* keep everything in 16.16 */ 692 693 offset += ((left >> 16) & ~7) << 1; 694 695 tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3); 696 p1_h_accum_init = ((tmp << 4) & 0x000f8000) | 697 ((tmp << 12) & 0xf0000000); 698 699 tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2); 700 p23_h_accum_init = ((tmp << 4) & 0x000f8000) | 701 ((tmp << 12) & 0x70000000); 702 703 tmp = (top & 0x0000ffff) + 0x00018000; 704 p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001; 705 706 left = (left >> 16) & 7; 707 708 OUTREG(R128_OV0_REG_LOAD_CNTL, 1); 709 while(!(INREG(R128_OV0_REG_LOAD_CNTL) & (1 << 3))); 710 711 OUTREG(R128_OV0_H_INC, h_inc | ((h_inc >> 1) << 16)); 712 OUTREG(R128_OV0_STEP_BY, step_by | (step_by << 8)); 713 OUTREG(R128_OV0_Y_X_START, dstBox->x1 | (dstBox->y1 << 16)); 714 OUTREG(R128_OV0_Y_X_END, dstBox->x2 | (dstBox->y2 << 16)); 715 OUTREG(R128_OV0_V_INC, v_inc); 716 OUTREG(R128_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16)); 717 OUTREG(R128_OV0_VID_BUF_PITCH0_VALUE, pitch); 718 OUTREG(R128_OV0_P1_X_START_END, (width - 1) | (left << 16)); 719 left >>= 1; width >>= 1; 720 OUTREG(R128_OV0_P2_X_START_END, (width - 1) | (left << 16)); 721 OUTREG(R128_OV0_P3_X_START_END, (width - 1) | (left << 16)); 722 OUTREG(R128_OV0_VID_BUF0_BASE_ADRS, offset & 0xfffffff0); 723 OUTREG(R128_OV0_P1_V_ACCUM_INIT, p1_v_accum_init); 724 OUTREG(R128_OV0_P23_V_ACCUM_INIT, 0); 725 OUTREG(R128_OV0_P1_H_ACCUM_INIT, p1_h_accum_init); 726 OUTREG(R128_OV0_P23_H_ACCUM_INIT, p23_h_accum_init); 727 728 if(id == FOURCC_UYVY) 729 OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8C03); 730 else 731 OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8B03); 732 733 OUTREG(R128_OV0_REG_LOAD_CNTL, 0); 734} 735 736static void 737R128DisplayVideo420( 738 ScrnInfoPtr pScrn, 739 short width, short height, 740 int pitch, 741 int offset1, int offset2, int offset3, 742 int left, int right, int top, 743 BoxPtr dstBox, 744 short src_w, short src_h, 745 short drw_w, short drw_h 746){ 747 R128InfoPtr info = R128PTR(pScrn); 748 unsigned char *R128MMIO = info->MMIO; 749 R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr; 750 int v_inc, h_inc, step_by, tmp, leftUV, v_inc_shift; 751 int p1_h_accum_init, p23_h_accum_init; 752 int p1_v_accum_init, p23_v_accum_init; 753 Bool rmx_active; 754 755 v_inc_shift = 20; 756 if (pScrn->currentMode->Flags & V_INTERLACE) 757 v_inc_shift++; 758 if (pScrn->currentMode->Flags & V_DBLSCAN) 759 v_inc_shift--; 760 761 rmx_active = INREG(R128_FP_VERT_STRETCH) & R128_VERT_STRETCH_ENABLE; 762 if (rmx_active) { 763 v_inc = ((src_h * pScrn->currentMode->CrtcVDisplay / info->PanelYRes) << v_inc_shift) / drw_h; 764 } else { 765 v_inc = (src_h << v_inc_shift) / drw_h; 766 } 767 h_inc = (src_w << (12 + pPriv->ecp_div)) / drw_w; 768 step_by = 1; 769 770 while(h_inc >= (2 << 12)) { 771 step_by++; 772 h_inc >>= 1; 773 } 774 775 /* keep everything in 16.16 */ 776 777 offset1 += (left >> 16) & ~15; 778 offset2 += (left >> 17) & ~15; 779 offset3 += (left >> 17) & ~15; 780 781 tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3); 782 p1_h_accum_init = ((tmp << 4) & 0x000f8000) | 783 ((tmp << 12) & 0xf0000000); 784 785 tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2); 786 p23_h_accum_init = ((tmp << 4) & 0x000f8000) | 787 ((tmp << 12) & 0x70000000); 788 789 tmp = (top & 0x0000ffff) + 0x00018000; 790 p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001; 791 792 tmp = ((top >> 1) & 0x0000ffff) + 0x00018000; 793 p23_v_accum_init = ((tmp << 4) & 0x01ff8000) | 0x00000001; 794 795 leftUV = (left >> 17) & 15; 796 left = (left >> 16) & 15; 797 798 OUTREG(R128_OV0_REG_LOAD_CNTL, 1); 799 while(!(INREG(R128_OV0_REG_LOAD_CNTL) & (1 << 3))); 800 801 OUTREG(R128_OV0_H_INC, h_inc | ((h_inc >> 1) << 16)); 802 OUTREG(R128_OV0_STEP_BY, step_by | (step_by << 8)); 803 OUTREG(R128_OV0_Y_X_START, dstBox->x1 | (dstBox->y1 << 16)); 804 OUTREG(R128_OV0_Y_X_END, dstBox->x2 | (dstBox->y2 << 16)); 805 OUTREG(R128_OV0_V_INC, v_inc); 806 OUTREG(R128_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16)); 807 src_h = (src_h + 1) >> 1; 808 OUTREG(R128_OV0_P23_BLANK_LINES_AT_TOP, 0x000007ff | ((src_h - 1) << 16)); 809 OUTREG(R128_OV0_VID_BUF_PITCH0_VALUE, pitch); 810 OUTREG(R128_OV0_VID_BUF_PITCH1_VALUE, pitch >> 1); 811 OUTREG(R128_OV0_P1_X_START_END, (width - 1) | (left << 16)); 812 width >>= 1; 813 OUTREG(R128_OV0_P2_X_START_END, (width - 1) | (leftUV << 16)); 814 OUTREG(R128_OV0_P3_X_START_END, (width - 1) | (leftUV << 16)); 815 OUTREG(R128_OV0_VID_BUF0_BASE_ADRS, offset1 & 0xfffffff0); 816 OUTREG(R128_OV0_VID_BUF1_BASE_ADRS, (offset2 & 0xfffffff0) | 0x00000001); 817 OUTREG(R128_OV0_VID_BUF2_BASE_ADRS, (offset3 & 0xfffffff0) | 0x00000001); 818 OUTREG(R128_OV0_P1_V_ACCUM_INIT, p1_v_accum_init); 819 OUTREG(R128_OV0_P23_V_ACCUM_INIT, p23_v_accum_init); 820 OUTREG(R128_OV0_P1_H_ACCUM_INIT, p1_h_accum_init); 821 OUTREG(R128_OV0_P23_H_ACCUM_INIT, p23_h_accum_init); 822 OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8A03); 823 824 OUTREG(R128_OV0_REG_LOAD_CNTL, 0); 825} 826 827 828 829static int 830R128PutImage( 831 ScrnInfoPtr pScrn, 832 short src_x, short src_y, 833 short drw_x, short drw_y, 834 short src_w, short src_h, 835 short drw_w, short drw_h, 836 int id, unsigned char* buf, 837 short width, short height, 838 Bool Sync, 839 RegionPtr clipBoxes, pointer data, 840 DrawablePtr pDraw 841){ 842 R128InfoPtr info = R128PTR(pScrn); 843 R128PortPrivPtr pPriv = (R128PortPrivPtr)data; 844 unsigned char *fb = (CARD8*)info->FB; 845 INT32 xa, xb, ya, yb; 846 int new_size, offset, s1offset, s2offset, s3offset; 847 int srcPitch, srcPitch2, dstPitch; 848 int d1line, d2line, d3line, d1offset, d2offset, d3offset; 849 int top, left, npixels, nlines; 850 BoxRec dstBox; 851 CARD32 tmp; 852#if X_BYTE_ORDER == X_BIG_ENDIAN 853 unsigned char *R128MMIO = info->MMIO; 854 CARD32 config_cntl = INREG(R128_CONFIG_CNTL); 855 856 /* We need to disable byte swapping, or the data gets mangled */ 857 OUTREG(R128_CONFIG_CNTL, config_cntl & 858 ~(APER_0_BIG_ENDIAN_16BPP_SWAP | APER_0_BIG_ENDIAN_32BPP_SWAP)); 859#endif 860 861 /* 862 * s1offset, s2offset, s3offset - byte offsets to the Y, U and V planes 863 * of the source. 864 * 865 * d1offset, d2offset, d3offset - byte offsets to the Y, U and V planes 866 * of the destination. 867 * 868 * offset - byte offset within the framebuffer to where the destination 869 * is stored. 870 * 871 * d1line, d2line, d3line - byte offsets within the destination to the 872 * first displayed scanline in each plane. 873 * 874 */ 875 876 if(src_w > (drw_w << 4)) 877 drw_w = src_w >> 4; 878 if(src_h > (drw_h << 4)) 879 drw_h = src_h >> 4; 880 881 /* Clip */ 882 xa = src_x; 883 xb = src_x + src_w; 884 ya = src_y; 885 yb = src_y + src_h; 886 887 dstBox.x1 = drw_x; 888 dstBox.x2 = drw_x + drw_w; 889 dstBox.y1 = drw_y; 890 dstBox.y2 = drw_y + drw_h; 891 892 if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, 893 clipBoxes, width, height)) 894 return Success; 895 896 dstBox.x1 -= pScrn->frameX0; 897 dstBox.x2 -= pScrn->frameX0; 898 dstBox.y1 -= pScrn->frameY0; 899 dstBox.y2 -= pScrn->frameY0; 900 901 switch(id) { 902 case FOURCC_YV12: 903 case FOURCC_I420: 904 srcPitch = (width + 3) & ~3; 905 srcPitch2 = ((width >> 1) + 3) & ~3; 906 dstPitch = (width + 31) & ~31; /* of luma */ 907 new_size = dstPitch * (height + (height >> 1)); 908 s1offset = 0; 909 s2offset = srcPitch * height; 910 s3offset = (srcPitch2 * (height >> 1)) + s2offset; 911 break; 912 case FOURCC_UYVY: 913 case FOURCC_YUY2: 914 default: 915 srcPitch = width << 1; 916 srcPitch2 = 0; 917 dstPitch = ((width << 1) + 15) & ~15; 918 new_size = dstPitch * height; 919 s1offset = 0; 920 s2offset = 0; 921 s3offset = 0; 922 break; 923 } 924 925 if(!(pPriv->videoOffset = R128AllocateMemory(pScrn, &(pPriv->BufferHandle), 926 pPriv->doubleBuffer ? (new_size << 1) : new_size))) 927 { 928 return BadAlloc; 929 } 930 931 pPriv->currentBuffer ^= 1; 932 933 /* copy data */ 934 top = ya >> 16; 935 left = (xa >> 16) & ~1; 936 npixels = ((((xb + 0xffff) >> 16) + 1) & ~1) - left; 937 938 offset = pPriv->videoOffset; 939 if(pPriv->doubleBuffer) 940 offset += pPriv->currentBuffer * new_size; 941 942 switch(id) { 943 case FOURCC_YV12: 944 case FOURCC_I420: 945 d1line = top * dstPitch; 946 d2line = (height * dstPitch) + ((top >> 1) * (dstPitch >> 1)); 947 d3line = d2line + ((height >> 1) * (dstPitch >> 1)); 948 949 top &= ~1; 950 951 d1offset = (top * dstPitch) + left + offset; 952 d2offset = d2line + (left >> 1) + offset; 953 d3offset = d3line + (left >> 1) + offset; 954 955 s1offset += (top * srcPitch) + left; 956 tmp = ((top >> 1) * srcPitch2) + (left >> 1); 957 s2offset += tmp; 958 s3offset += tmp; 959 if(id == FOURCC_YV12) { 960 tmp = s2offset; 961 s2offset = s3offset; 962 s3offset = tmp; 963 } 964 965 nlines = ((((yb + 0xffff) >> 16) + 1) & ~1) - top; 966 R128CopyData420(info, buf + s1offset, buf + s2offset, buf + s3offset, 967 fb + d1offset, fb + d2offset, fb + d3offset, 968 srcPitch, srcPitch2, dstPitch, nlines, npixels); 969 break; 970 case FOURCC_UYVY: 971 case FOURCC_YUY2: 972 default: 973 left <<= 1; 974 d1line = top * dstPitch; 975 d2line = 0; 976 d3line = 0; 977 d1offset = d1line + left + offset; 978 d2offset = 0; 979 d3offset = 0; 980 s1offset += (top * srcPitch) + left; 981 nlines = ((yb + 0xffff) >> 16) - top; 982 R128CopyData422(info, buf + s1offset, fb + d1offset, 983 srcPitch, dstPitch, nlines, npixels); 984 break; 985 } 986 987#if X_BYTE_ORDER == X_BIG_ENDIAN 988 /* restore byte swapping */ 989 OUTREG(R128_CONFIG_CNTL, config_cntl); 990#endif 991 992 /* update cliplist */ 993 if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) { 994 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); 995 /* draw these */ 996 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes); 997 } 998 999 1000 switch(id) { 1001 case FOURCC_YV12: 1002 case FOURCC_I420: 1003 R128DisplayVideo420(pScrn, width, height, dstPitch, 1004 offset + d1line, offset + d2line, offset + d3line, 1005 xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h); 1006 break; 1007 case FOURCC_UYVY: 1008 case FOURCC_YUY2: 1009 default: 1010 R128DisplayVideo422(pScrn, id, offset + d1line, width, height, dstPitch, 1011 xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h); 1012 break; 1013 } 1014 1015 pPriv->videoStatus = CLIENT_VIDEO_ON; 1016 1017 info->VideoTimerCallback = R128VideoTimerCallback; 1018 1019 return Success; 1020} 1021 1022 1023static int 1024R128QueryImageAttributes( 1025 ScrnInfoPtr pScrn, 1026 int id, 1027 unsigned short *w, unsigned short *h, 1028 int *pitches, int *offsets 1029){ 1030 int size, tmp; 1031 1032 if(*w > MAXWIDTH) *w = MAXWIDTH; 1033 if(*h > MAXHEIGHT) *h = MAXHEIGHT; 1034 1035 *w = (*w + 1) & ~1; 1036 if(offsets) offsets[0] = 0; 1037 1038 switch(id) { 1039 case FOURCC_YV12: 1040 case FOURCC_I420: 1041 *h = (*h + 1) & ~1; 1042 size = (*w + 3) & ~3; 1043 if(pitches) pitches[0] = size; 1044 size *= *h; 1045 if(offsets) offsets[1] = size; 1046 tmp = ((*w >> 1) + 3) & ~3; 1047 if(pitches) pitches[1] = pitches[2] = tmp; 1048 tmp *= (*h >> 1); 1049 size += tmp; 1050 if(offsets) offsets[2] = size; 1051 size += tmp; 1052 break; 1053 case FOURCC_UYVY: 1054 case FOURCC_YUY2: 1055 default: 1056 size = *w << 1; 1057 if(pitches) pitches[0] = size; 1058 size *= *h; 1059 break; 1060 } 1061 1062 return size; 1063} 1064 1065static void 1066R128VideoTimerCallback(ScrnInfoPtr pScrn, Time now) 1067{ 1068 R128InfoPtr info = R128PTR(pScrn); 1069 R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr; 1070 1071 if(pPriv->videoStatus & TIMER_MASK) { 1072 if(pPriv->videoStatus & OFF_TIMER) { 1073 if(pPriv->offTime < now) { 1074 unsigned char *R128MMIO = info->MMIO; 1075 OUTREG(R128_OV0_SCALE_CNTL, 0); 1076 pPriv->videoStatus = FREE_TIMER; 1077 pPriv->freeTime = now + FREE_DELAY; 1078 } 1079 } else { /* FREE_TIMER */ 1080 if(pPriv->freeTime < now) { 1081 if(pPriv->BufferHandle) { 1082 if (!info->useEXA) { 1083 xf86FreeOffscreenLinear((FBLinearPtr) pPriv->BufferHandle); 1084 } 1085#ifdef USE_EXA 1086 else { 1087 exaOffscreenFree(pScrn->pScreen, (ExaOffscreenArea *) pPriv->BufferHandle); 1088 } 1089#endif 1090 pPriv->BufferHandle = NULL; 1091 } 1092 pPriv->videoStatus = 0; 1093 info->VideoTimerCallback = NULL; 1094 } 1095 } 1096 } else /* shouldn't get here */ 1097 info->VideoTimerCallback = NULL; 1098} 1099