lx_video.c revision 7aef237f
1/* Copyright (c) 2007-2008 Advanced Micro Devices, Inc. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 * 21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its 22 * contributors may be used to endorse or promote products derived from this 23 * software without specific prior written permission. 24 */ 25 26/* TODO: 27 Add rotation 28 Add back in double buffering? 29 30*/ 31 32#ifdef HAVE_CONFIG_H 33#include "config.h" 34#endif 35 36#include <stdlib.h> 37#include <string.h> 38 39#include "xf86.h" 40#include "xf86_OSproc.h" 41#include "compiler.h" 42#include "xf86PciInfo.h" 43#include "xf86Pci.h" 44#include "xf86fbman.h" 45#include "regionstr.h" 46#include "dixstruct.h" 47 48#include "geode.h" 49#include "xf86xv.h" 50#include <X11/extensions/Xv.h> 51#include "fourcc.h" 52#include "geode_fourcc.h" 53#include "cim/cim_defs.h" 54#include "cim/cim_regs.h" 55 56#define OFF_DELAY 200 57#define FREE_DELAY 60000 58#define OFF_TIMER 0x01 59#define FREE_TIMER 0x02 60#define CLIENT_VIDEO_ON 0x04 61#define TIMER_MASK (OFF_TIMER | FREE_TIMER) 62 63#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) 64#define ARRAY_SIZE(a) (sizeof((a)) / (sizeof(*(a)))) 65 66/* Local function prototypes */ 67static void LXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit); 68 69static void 70LXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height, 71 BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH); 72 73static void LXResetVideo(ScrnInfoPtr pScrni); 74 75static XF86VideoEncodingRec DummyEncoding[1] = { 76 {0, "XV_IMAGE", 1024, 1024, {1, 1}} 77}; 78 79static XF86VideoFormatRec Formats[] = { 80 {8, PseudoColor}, {15, TrueColor}, {16, TrueColor}, {24, TrueColor} 81}; 82 83static XF86AttributeRec Attributes[] = { 84 {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, 85 {XvSettable | XvGettable, 0, 1, "XV_FILTER"}, 86 {XvSettable | XvGettable, 0, 1, "XV_COLORKEYMODE"} 87}; 88 89static XF86ImageRec Images[] = { 90 XVIMAGE_UYVY, 91 XVIMAGE_YUY2, 92 XVIMAGE_Y2YU, 93 XVIMAGE_YVYU, 94 XVIMAGE_Y800, 95 XVIMAGE_I420, 96 XVIMAGE_YV12, 97 XVIMAGE_RGB565 98}; 99 100typedef struct 101{ 102 ExaOffscreenArea *vidmem; 103 RegionRec clip; 104 CARD32 filter; 105 CARD32 colorKey; 106 CARD32 colorKeyMode; 107 CARD32 videoStatus; 108 Time offTime; 109 Time freeTime; 110 short pwidth, pheight; 111} GeodePortPrivRec, *GeodePortPrivPtr; 112 113#define GET_PORT_PRIVATE(pScrni) \ 114 (GeodePortPrivRec *)((GEODEPTR(pScrni))->adaptor->pPortPrivates[0].ptr) 115 116static void 117LXCopyFromSys(GeodeRec * pGeode, unsigned char *src, unsigned int dst, 118 int dstPitch, int srcPitch, int h, int w) 119{ 120 121 gp_declare_blt(0); 122 gp_set_bpp((srcPitch / w) << 3); 123 124 gp_set_raster_operation(0xCC); 125 gp_set_strides(dstPitch, srcPitch); 126 gp_set_solid_pattern(0); 127 128 gp_color_bitmap_to_screen_blt(dst, 0, w, h, src, srcPitch); 129} 130 131static void 132LXSetColorkey(ScrnInfoPtr pScrni, GeodePortPrivRec * pPriv) 133{ 134 int red, green, blue; 135 unsigned long key; 136 137 switch (pScrni->depth) { 138 case 8: 139 vg_get_display_palette_entry(pPriv->colorKey & 0xFF, &key); 140 red = ((key >> 16) & 0xFF); 141 green = ((key >> 8) & 0xFF); 142 blue = (key & 0xFF); 143 break; 144 case 16: 145 red = (pPriv->colorKey & pScrni->mask.red) >> 146 pScrni->offset.red << (8 - pScrni->weight.red); 147 green = (pPriv->colorKey & pScrni->mask.green) >> 148 pScrni->offset.green << (8 - pScrni->weight.green); 149 blue = (pPriv->colorKey & pScrni->mask.blue) >> 150 pScrni->offset.blue << (8 - pScrni->weight.blue); 151 break; 152 default: 153 /* for > 16 bpp we send in the mask in xf86SetWeight. This 154 * function is providing the offset by 1 more. So we take 155 * this as a special case and subtract 1 for > 16 156 */ 157 158 red = (pPriv->colorKey & pScrni->mask.red) >> 159 (pScrni->offset.red - 1) << (8 - pScrni->weight.red); 160 green = (pPriv->colorKey & pScrni->mask.green) >> 161 (pScrni->offset.green - 1) << (8 - pScrni->weight.green); 162 blue = (pPriv->colorKey & pScrni->mask.blue) >> 163 (pScrni->offset.blue - 1) << (8 - pScrni->weight.blue); 164 break; 165 } 166 167 df_set_video_color_key((blue | (green << 8) | (red << 16)), 168 0xFFFFFF, (pPriv->colorKeyMode == 0)); 169 170 REGION_EMPTY(pScrni->pScreen, &pPriv->clip); 171} 172 173/* A structure full of the scratch information that originates in the copy routines, 174 but is needed for the video display - maybe we should figure out a way to attach 175 this to structures? I hate to put it in pGeode since it will increase the size of 176 the structure, and possibly cause us cache issues. 177*/ 178 179struct 180{ 181 unsigned int dstOffset; 182 unsigned int dstPitch; 183 unsigned int UVPitch; 184 unsigned int UDstOffset; 185 unsigned int VDstOffset; 186} videoScratch; 187 188/* Copy planar YUV data */ 189 190static Bool 191LXAllocateVidMem(ScrnInfoPtr pScrni, GeodePortPrivRec *pPriv, int size) 192{ 193 if (!pPriv->vidmem || pPriv->vidmem->size < size) { 194 if (pPriv->vidmem) { 195 exaOffscreenFree(pScrni->pScreen, pPriv->vidmem); 196 pPriv->vidmem = NULL; 197 } 198 199 pPriv->vidmem = exaOffscreenAlloc(pScrni->pScreen, size, 4, 200 TRUE, NULL, NULL); 201 202 if (pPriv->vidmem == NULL) { 203 ErrorF("Could not allocate memory for the video\n"); 204 return FALSE; 205 } 206 } 207 208 return TRUE; 209} 210 211static Bool 212LXCopyPlanar(ScrnInfoPtr pScrni, int id, unsigned char *buf, 213 short x1, short y1, short x2, short y2, 214 int width, int height, pointer data) 215{ 216 GeodeRec *pGeode = GEODEPTR(pScrni); 217 GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; 218 219 unsigned int YSrcPitch, YDstPitch; 220 unsigned int UVSrcPitch, UVDstPitch; 221 unsigned int YSrcOffset, YDstOffset; 222 unsigned int USrcOffset, UDstOffset; 223 unsigned int VSrcOffset, VDstOffset; 224 225 unsigned int size, lines, top, left, pixels; 226 227 YSrcPitch = (width + 3) & ~3; 228 YDstPitch = (width + 31) & ~31; 229 230 UVSrcPitch = ((width >> 1) + 3) & ~3; 231 UVDstPitch = ((width >> 1) + 15) & ~15; 232 233 USrcOffset = YSrcPitch * height; 234 VSrcOffset = USrcOffset + (UVSrcPitch * (height >> 1)); 235 236 UDstOffset = YDstPitch * height; 237 VDstOffset = UDstOffset + (UVDstPitch * (height >> 1)); 238 239 size = YDstPitch * height; 240 size += UVDstPitch * height; 241 242 if (LXAllocateVidMem(pScrni, pPriv, size) == FALSE) { 243 ErrorF("Error allocating an offscreen Planar region.\n"); 244 return FALSE; 245 } 246 247 /* The top of the source region we want to copy */ 248 top = y1 & ~1; 249 250 /* The left hand side of the source region, aligned on a word */ 251 left = x1 & ~1; 252 253 /* Number of bytes to copy, also word aligned */ 254 pixels = ((x2 + 1) & ~1) - left; 255 256 /* Calculate the source offset */ 257 YSrcOffset = (top * YSrcPitch) + left; 258 USrcOffset += ((top >> 1) * UVSrcPitch) + (left >> 1); 259 VSrcOffset += ((top >> 1) * UVSrcPitch) + (left >> 1); 260 261 /* Calculate the destination offset */ 262 YDstOffset = (top * YDstPitch) + left; 263 UDstOffset += ((top >> 1) * UVDstPitch) + (left >> 1); 264 VDstOffset += ((top >> 1) * UVDstPitch) + (left >> 1); 265 266 lines = ((y2 + 1) & ~1) - top; 267 268 /* Copy Y */ 269 270 LXCopyFromSys(pGeode, buf + YSrcOffset, 271 pPriv->vidmem->offset + YDstOffset, YDstPitch, YSrcPitch, lines, 272 pixels); 273 274 /* Copy U + V at the same time */ 275 276 LXCopyFromSys(pGeode, buf + USrcOffset, 277 pPriv->vidmem->offset + UDstOffset, UVDstPitch, UVSrcPitch, lines, 278 pixels >> 1); 279 280 videoScratch.dstOffset = pPriv->vidmem->offset + YDstOffset; 281 videoScratch.dstPitch = YDstPitch; 282 videoScratch.UVPitch = UVDstPitch; 283 videoScratch.UDstOffset = pPriv->vidmem->offset + UDstOffset; 284 videoScratch.VDstOffset = pPriv->vidmem->offset + VDstOffset; 285 286 return TRUE; 287} 288 289static Bool 290LXCopyPacked(ScrnInfoPtr pScrni, int id, unsigned char *buf, 291 short x1, short y1, short x2, short y2, 292 int width, int height, pointer data) 293{ 294 GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; 295 GeodeRec *pGeode = GEODEPTR(pScrni); 296 unsigned int dstPitch, srcPitch; 297 unsigned int srcOffset, dstOffset; 298 unsigned int lines, top, left, pixels; 299 300 dstPitch = ((width << 1) + 3) & ~3; 301 srcPitch = (width << 1); 302 303 lines = ((dstPitch * height) + pGeode->Pitch - 1) / pGeode->Pitch; 304 305 if (LXAllocateVidMem(pScrni, pPriv, dstPitch * height) == FALSE) { 306 ErrorF("Error allocating an offscreen Packed region.\n"); 307 return FALSE; 308 } 309 310 /* The top of the source region we want to copy */ 311 top = y1; 312 313 /* The left hand side of the source region, aligned on a word */ 314 left = x1 & ~1; 315 316 /* Number of bytes to copy, also word aligned */ 317 pixels = ((x2 + 1) & ~1) - left; 318 319 /* Adjust the incoming buffer */ 320 srcOffset = (top * srcPitch) + left; 321 322 /* Calculate the destination offset */ 323 dstOffset = pPriv->vidmem->offset + (top * dstPitch) + left; 324 325 /* Make the copy happen */ 326 327 if (id == FOURCC_Y800) { 328 329 /* Use the shared (unaccelerated) greyscale copy - you could probably 330 * accelerate it using a 2 pass blit and patterns, but it doesn't really 331 * seem worth it 332 */ 333 334 GeodeCopyGreyscale(buf + srcOffset, pGeode->FBBase + dstOffset, 335 srcPitch, dstPitch, height, pixels >> 1); 336 } else 337 /* FIXME: should lines be used here instead of height? */ 338 LXCopyFromSys(pGeode, buf + srcOffset, dstOffset, dstPitch, srcPitch, 339 height, pixels); 340 341 videoScratch.dstOffset = dstOffset; 342 videoScratch.dstPitch = dstPitch; 343 344 return TRUE; 345} 346 347static void 348LXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height, 349 BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH) 350{ 351 long ystart, xend, yend; 352 unsigned long lines = 0; 353 unsigned long yExtra, uvExtra = 0; 354 DF_VIDEO_POSITION vidPos; 355 DF_VIDEO_SOURCE_PARAMS vSrcParams; 356 int err; 357 358 memset(&vSrcParams, 0, sizeof(vSrcParams)); 359 360 gp_wait_until_idle(); 361 362 switch (id) { 363 case FOURCC_UYVY: 364 vSrcParams.video_format = DF_VIDFMT_UYVY; 365 break; 366 367 case FOURCC_Y800: 368 case FOURCC_YV12: 369 case FOURCC_I420: 370 vSrcParams.video_format = DF_VIDFMT_Y0Y1Y2Y3; 371 break; 372 case FOURCC_YUY2: 373 vSrcParams.video_format = DF_VIDFMT_YUYV; 374 break; 375 case FOURCC_Y2YU: 376 vSrcParams.video_format = DF_VIDFMT_Y2YU; 377 break; 378 case FOURCC_YVYU: 379 vSrcParams.video_format = DF_VIDFMT_YVYU; 380 break; 381 case FOURCC_RGB565: 382 vSrcParams.video_format = DF_VIDFMT_RGB; 383 break; 384 } 385 386 vSrcParams.width = width; 387 vSrcParams.height = height; 388 vSrcParams.y_pitch = videoScratch.dstPitch; 389 vSrcParams.uv_pitch = videoScratch.UVPitch; 390 391 /* Set up scaling */ 392 df_set_video_filter_coefficients(NULL, 1); 393 394 err = df_set_video_scale(width, height, drawW, drawH, 395 DF_SCALEFLAG_CHANGEX | DF_SCALEFLAG_CHANGEY); 396 if (err != CIM_STATUS_OK) { 397 /* Note the problem, but do nothing for now. */ 398 ErrorF("Video scale factor too large: %dx%d -> %dx%d\n", 399 width, height, drawW, drawH); 400 } 401 402 /* Figure out clipping */ 403 404 xend = dstBox->x2; 405 yend = dstBox->y2; 406 407 if (dstBox->y1 < 0) { 408 if (srcH < drawH) 409 lines = ((-dstBox->y1) * srcH) / drawH; 410 else 411 lines = (-dstBox->y1); 412 413 ystart = 0; 414 drawH += dstBox->y1; 415 } else { 416 ystart = dstBox->y1; 417 lines = 0; 418 } 419 420 yExtra = lines * videoScratch.dstPitch; 421 uvExtra = (lines >> 1) * videoScratch.UVPitch; 422 423 memset(&vidPos, 0, sizeof(vidPos)); 424 425 vidPos.x = dstBox->x1; 426 vidPos.y = ystart; 427 vidPos.width = xend - dstBox->x1; 428 vidPos.height = yend - ystart; 429 430 df_set_video_position(&vidPos); 431 432 vSrcParams.y_offset = videoScratch.dstOffset + yExtra; 433 434 switch (id) { 435 case FOURCC_Y800: 436 case FOURCC_I420: 437 vSrcParams.u_offset = videoScratch.UDstOffset + uvExtra; 438 vSrcParams.v_offset = videoScratch.VDstOffset + uvExtra; 439 break; 440 case FOURCC_YV12: 441 vSrcParams.v_offset = videoScratch.UDstOffset + uvExtra; 442 vSrcParams.u_offset = videoScratch.VDstOffset + uvExtra; 443 break; 444 445 default: 446 vSrcParams.u_offset = vSrcParams.v_offset = 0; 447 break; 448 } 449 450 vSrcParams.flags = DF_SOURCEFLAG_IMPLICITSCALING; 451 df_configure_video_source(&vSrcParams, &vSrcParams); 452 453 /* Turn on the video palette */ 454 df_set_video_palette(NULL); 455 df_set_video_enable(1, 0); 456} 457 458static int 459LXPutImage(ScrnInfoPtr pScrni, 460 short srcX, short srcY, short drawX, short drawY, 461 short srcW, short srcH, short drawW, short drawH, 462 int id, unsigned char *buf, 463 short width, short height, Bool sync, RegionPtr clipBoxes, 464 pointer data, DrawablePtr pDraw) 465{ 466 GeodeRec *pGeode = GEODEPTR(pScrni); 467 GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; 468 INT32 x1, x2, y1, y2; 469 BoxRec dstBox; 470 Bool ret; 471 472 if (pGeode->rotation != RR_Rotate_0) 473 return Success; 474 475 if (srcW <= 0 || srcH <= 0) { 476 return Success; 477 } 478 479 if (drawW <= 0 || drawH <= 0) { 480 return Success; 481 } 482 483 if (drawW > 16384) 484 drawW = 16384; 485 486 memset(&videoScratch, 0, sizeof(videoScratch)); 487 488 x1 = srcX; 489 x2 = srcX + srcW; 490 y1 = srcY; 491 y2 = srcY + srcH; 492 493 dstBox.x1 = drawX; 494 dstBox.x2 = drawX + drawW; 495 dstBox.y1 = drawY; 496 dstBox.y2 = drawY + drawH; 497 498 dstBox.x1 -= pScrni->frameX0; 499 dstBox.x2 -= pScrni->frameX0; 500 dstBox.y1 -= pScrni->frameY0; 501 dstBox.y2 -= pScrni->frameY0; 502 503 if (id == FOURCC_YV12 || id == FOURCC_I420) 504 ret = LXCopyPlanar(pScrni, id, buf, x1, y1, x2, y2, width, 505 height, data); 506 else 507 ret = LXCopyPacked(pScrni, id, buf, x1, y1, x2, y2, width, 508 height, data); 509 510 if (ret == FALSE) 511 return BadAlloc; 512 513 if (!RegionsEqual(&pPriv->clip, clipBoxes) || 514 (drawW != pPriv->pwidth || drawH != pPriv->pheight)) { 515 REGION_COPY(pScrni->pScreen, &pPriv->clip, clipBoxes); 516 517 if (pPriv->colorKeyMode == 0) { 518 xf86XVFillKeyHelper(pScrni->pScreen, pPriv->colorKey, clipBoxes); 519 } 520 521 LXDisplayVideo(pScrni, id, width, height, &dstBox, 522 srcW, srcH, drawW, drawH); 523 pPriv->pwidth = drawW; 524 pPriv->pheight = drawH; 525 } 526 527 pPriv->videoStatus = CLIENT_VIDEO_ON; 528 529 return Success; 530} 531 532static void 533LXQueryBestSize(ScrnInfoPtr pScrni, Bool motion, 534 short vidW, short vidH, short drawW, short drawH, 535 unsigned int *retW, unsigned int *retH, pointer data) 536{ 537 *retW = drawW > 16384 ? 16384 : drawW; 538 *retH = drawH; 539} 540 541static Atom xvColorKey, xvColorKeyMode, xvFilter; 542 543static int 544LXGetPortAttribute(ScrnInfoPtr pScrni, 545 Atom attribute, INT32 * value, pointer data) 546{ 547 GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; 548 549 if (attribute == xvColorKey) 550 *value = pPriv->colorKey; 551 else if (attribute == xvColorKeyMode) 552 *value = pPriv->colorKeyMode; 553 else if (attribute == xvFilter) 554 *value = pPriv->filter; 555 else 556 return BadMatch; 557 558 return Success; 559} 560 561static int 562LXSetPortAttribute(ScrnInfoPtr pScrni, 563 Atom attribute, INT32 value, pointer data) 564{ 565 GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; 566 567 gp_wait_until_idle(); 568 569 if (attribute == xvColorKey) { 570 pPriv->colorKey = value; 571 LXSetColorkey(pScrni, pPriv); 572 } else if (attribute == xvColorKeyMode) { 573 pPriv->colorKeyMode = value; 574 LXSetColorkey(pScrni, pPriv); 575 } else if (attribute == xvFilter) { 576 if ((value < 0) || (value > 1)) 577 return BadValue; 578 pPriv->filter = value; 579 } else 580 return BadMatch; 581 582 return Success; 583} 584 585static void 586LXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit) 587{ 588 GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; 589 590 if (pPriv->videoStatus == 0) 591 return; 592 593 REGION_EMPTY(pScrni->pScreen, &pPriv->clip); 594 gp_wait_until_idle(); 595 596 if (exit) { 597 if (pPriv->videoStatus & CLIENT_VIDEO_ON) { 598 unsigned int val; 599 600 df_set_video_enable(0, 0); 601 /* Put the LUT back in bypass */ 602 val = READ_VID32(DF_VID_MISC); 603 WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH); 604 } 605 606 if (pPriv->vidmem) { 607 exaOffscreenFree(pScrni->pScreen, pPriv->vidmem); 608 pPriv->vidmem = NULL; 609 } 610 611 pPriv->videoStatus = 0; 612 613 /* Eh? */ 614 } else if (pPriv->videoStatus & CLIENT_VIDEO_ON) { 615 pPriv->videoStatus |= OFF_TIMER; 616 pPriv->offTime = currentTime.milliseconds + OFF_DELAY; 617 } 618} 619 620static void 621LXResetVideo(ScrnInfoPtr pScrni) 622{ 623 GeodeRec *pGeode = GEODEPTR(pScrni); 624 625 if (!pGeode->NoAccel) { 626 GeodePortPrivRec *pPriv = pGeode->adaptor->pPortPrivates[0].ptr; 627 628 gp_wait_until_idle(); 629 df_set_video_palette(NULL); 630 631 LXSetColorkey(pScrni, pPriv); 632 } 633} 634 635static void 636LXVidBlockHandler(int i, pointer blockData, pointer pTimeout, 637 pointer pReadmask) 638{ 639 ScreenPtr pScrn = screenInfo.screens[i]; 640 ScrnInfoPtr pScrni = xf86Screens[i]; 641 GeodeRec *pGeode = GEODEPTR(pScrni); 642 GeodePortPrivRec *pPriv = GET_PORT_PRIVATE(pScrni); 643 644 pScrn->BlockHandler = pGeode->BlockHandler; 645 (*pScrn->BlockHandler) (i, blockData, pTimeout, pReadmask); 646 pScrn->BlockHandler = LXVidBlockHandler; 647 648 if (pPriv->videoStatus & TIMER_MASK) { 649 Time now = currentTime.milliseconds; 650 651 if (pPriv->videoStatus & OFF_TIMER) { 652 gp_wait_until_idle(); 653 654 if (pPriv->offTime < now) { 655 unsigned int val; 656 657 df_set_video_enable(0, 0); 658 pPriv->videoStatus = FREE_TIMER; 659 pPriv->freeTime = now + FREE_DELAY; 660 661 /* Turn off the video palette */ 662 val = READ_VID32(DF_VID_MISC); 663 WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH); 664 } 665 } else { 666 if (pPriv->freeTime < now) { 667 668 if (pPriv->vidmem) { 669 exaOffscreenFree(pScrni->pScreen, pPriv->vidmem); 670 pPriv->vidmem = NULL; 671 } 672 673 pPriv->videoStatus = 0; 674 } 675 } 676 } 677} 678 679static XF86VideoAdaptorPtr 680LXSetupImageVideo(ScreenPtr pScrn) 681{ 682 ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum]; 683 GeodeRec *pGeode = GEODEPTR(pScrni); 684 XF86VideoAdaptorPtr adapt; 685 GeodePortPrivRec *pPriv; 686 687 adapt = calloc(1, sizeof(XF86VideoAdaptorRec) + 688 sizeof(GeodePortPrivRec) + sizeof(DevUnion)); 689 690 if (adapt == NULL) { 691 ErrorF("Couldn't create the rec\n"); 692 return NULL; 693 } 694 695 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 696 adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; 697 698 adapt->name = "AMD Geode LX"; 699 adapt->nEncodings = 1; 700 adapt->pEncodings = DummyEncoding; 701 adapt->nFormats = ARRAY_SIZE(Formats); 702 adapt->pFormats = Formats; 703 adapt->nPorts = 1; 704 adapt->pPortPrivates = (DevUnion *) (&adapt[1]); 705 pPriv = (GeodePortPrivRec *) (&adapt->pPortPrivates[1]); 706 adapt->pPortPrivates[0].ptr = (pointer) (pPriv); 707 adapt->pAttributes = Attributes; 708 adapt->nImages = ARRAY_SIZE(Images); 709 adapt->nAttributes = ARRAY_SIZE(Attributes); 710 adapt->pImages = Images; 711 adapt->PutVideo = NULL; 712 adapt->PutStill = NULL; 713 adapt->GetVideo = NULL; 714 adapt->GetStill = NULL; 715 adapt->StopVideo = LXStopVideo; 716 adapt->SetPortAttribute = LXSetPortAttribute; 717 adapt->GetPortAttribute = LXGetPortAttribute; 718 adapt->QueryBestSize = LXQueryBestSize; 719 adapt->PutImage = LXPutImage; 720 721 /* Use the common function */ 722 adapt->QueryImageAttributes = GeodeQueryImageAttributes; 723 724 pPriv->vidmem = NULL; 725 pPriv->filter = 0; 726 pPriv->colorKey = 0; 727 pPriv->colorKeyMode = 0; 728 pPriv->videoStatus = 0; 729 pPriv->pwidth = 0; 730 pPriv->pheight = 0; 731 732 REGION_NULL(pScrn, &pPriv->clip); 733 734 pGeode->adaptor = adapt; 735 736 pGeode->BlockHandler = pScrn->BlockHandler; 737 pScrn->BlockHandler = LXVidBlockHandler; 738 739 xvColorKey = MAKE_ATOM("XV_COLORKEY"); 740 xvColorKeyMode = MAKE_ATOM("XV_COLORKEYMODE"); 741 xvFilter = MAKE_ATOM("XV_FILTER"); 742 743 LXResetVideo(pScrni); 744 745 return adapt; 746} 747 748/* Offscreen surface allocation */ 749 750struct OffscreenPrivRec 751{ 752 ExaOffscreenArea *vidmem; 753 Bool isOn; 754}; 755 756static int 757LXDisplaySurface(XF86SurfacePtr surface, 758 short srcX, short srcY, short drawX, short drawY, 759 short srcW, short srcH, short drawW, short drawH, RegionPtr clipBoxes) 760{ 761 struct OffscreenPrivRec *pPriv = 762 (struct OffscreenPrivRec *)surface->devPrivate.ptr; 763 764 ScrnInfoPtr pScrni = surface->pScrn; 765 GeodePortPrivRec *portPriv = GET_PORT_PRIVATE(pScrni); 766 767 BoxRec dstBox; 768 769 dstBox.x1 = drawX; 770 dstBox.x2 = drawX + drawW; 771 dstBox.y1 = drawY; 772 dstBox.y2 = drawY + drawH; 773 774 if ((drawW <= 0) | (drawH <= 0)) 775 return Success; 776 777 /* Is this still valid? */ 778 779 dstBox.x1 -= pScrni->frameX0; 780 dstBox.x2 -= pScrni->frameX0; 781 dstBox.y1 -= pScrni->frameY0; 782 dstBox.y2 -= pScrni->frameY0; 783 784 xf86XVFillKeyHelper(pScrni->pScreen, portPriv->colorKey, clipBoxes); 785 786 videoScratch.dstOffset = surface->offsets[0]; 787 videoScratch.dstPitch = surface->pitches[0]; 788 789 LXDisplayVideo(pScrni, surface->id, surface->width, surface->height, 790 &dstBox, srcW, srcH, drawW, drawH); 791 792 pPriv->isOn = TRUE; 793 794 if (portPriv->videoStatus & CLIENT_VIDEO_ON) { 795 REGION_EMPTY(pScrni->pScreen, &portPriv->clip); 796 UpdateCurrentTime(); 797 portPriv->videoStatus = FREE_TIMER; 798 portPriv->freeTime = currentTime.milliseconds + FREE_DELAY; 799 } 800 801 return Success; 802} 803 804static int 805LXAllocateSurface(ScrnInfoPtr pScrni, int id, unsigned short w, 806 unsigned short h, XF86SurfacePtr surface) 807{ 808 GeodeRec *pGeode = GEODEPTR(pScrni); 809 int pitch, lines; 810 ExaOffscreenArea *vidmem; 811 struct OffscreenPrivRec *pPriv; 812 813 if (w > 1024 || h > 1024) 814 return BadAlloc; 815 816 /* The width needs to be word aligned */ 817 w = (w + 1) & ~1; 818 819 pitch = ((w << 1) + 15) & ~15; 820 lines = ((pitch * h) + (pGeode->Pitch - 1)) / pGeode->Pitch; 821 822 /* FIXME: is lines the right parameter to use here, 823 * or should it be height * pitch? */ 824 vidmem = exaOffscreenAlloc(pScrni->pScreen, lines, 4, TRUE, 825 NULL, NULL); 826 827 if (vidmem == NULL) { 828 ErrorF("Error while allocating an offscreen region.\n"); 829 return BadAlloc; 830 } 831 832 surface->width = w; 833 surface->height = h; 834 835 surface->pitches = malloc(sizeof(int)); 836 837 surface->offsets = malloc(sizeof(int)); 838 839 pPriv = malloc(sizeof(struct OffscreenPrivRec)); 840 841 if (pPriv && surface->pitches && surface->offsets) { 842 843 pPriv->vidmem = vidmem; 844 845 pPriv->isOn = FALSE; 846 847 surface->pScrn = pScrni; 848 surface->id = id; 849 surface->pitches[0] = pitch; 850 surface->offsets[0] = vidmem->offset; 851 surface->devPrivate.ptr = (pointer) pPriv; 852 853 return Success; 854 } 855 856 if (surface->offsets) 857 free(surface->offsets); 858 859 if (surface->pitches) 860 free(surface->pitches); 861 862 if (vidmem) { 863 exaOffscreenFree(pScrni->pScreen, vidmem); 864 vidmem = NULL; 865 } 866 867 return BadAlloc; 868} 869 870static int 871LXStopSurface(XF86SurfacePtr surface) 872{ 873 struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *) 874 surface->devPrivate.ptr; 875 876 pPriv->isOn = FALSE; 877 return Success; 878} 879 880static int 881LXFreeSurface(XF86SurfacePtr surface) 882{ 883 struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *) 884 surface->devPrivate.ptr; 885 ScrnInfoPtr pScrni = surface->pScrn; 886 887 if (pPriv->isOn) 888 LXStopSurface(surface); 889 890 if (pPriv->vidmem) { 891 exaOffscreenFree(pScrni->pScreen, pPriv->vidmem); 892 pPriv->vidmem = NULL; 893 } 894 895 free(surface->pitches); 896 free(surface->offsets); 897 free(surface->devPrivate.ptr); 898 899 return Success; 900} 901 902static int 903LXGetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 * value) 904{ 905 return LXGetPortAttribute(pScrni, attribute, value, 906 (pointer) (GET_PORT_PRIVATE(pScrni))); 907} 908 909static int 910LXSetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value) 911{ 912 return LXSetPortAttribute(pScrni, attribute, value, 913 (pointer) (GET_PORT_PRIVATE(pScrni))); 914} 915 916static void 917LXInitOffscreenImages(ScreenPtr pScrn) 918{ 919 XF86OffscreenImagePtr offscreenImages; 920 921 /* need to free this someplace */ 922 if (!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec)))) 923 return; 924 925 offscreenImages[0].image = &Images[0]; 926 offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; 927 offscreenImages[0].alloc_surface = LXAllocateSurface; 928 offscreenImages[0].free_surface = LXFreeSurface; 929 offscreenImages[0].display = LXDisplaySurface; 930 offscreenImages[0].stop = LXStopSurface; 931 offscreenImages[0].setAttribute = LXSetSurfaceAttribute; 932 offscreenImages[0].getAttribute = LXGetSurfaceAttribute; 933 offscreenImages[0].max_width = 1024; 934 offscreenImages[0].max_height = 1024; 935 offscreenImages[0].num_attributes = ARRAY_SIZE(Attributes); 936 offscreenImages[0].attributes = Attributes; 937 938 xf86XVRegisterOffscreenImages(pScrn, offscreenImages, 1); 939} 940 941void 942LXInitVideo(ScreenPtr pScrn) 943{ 944 GeodeRec *pGeode; 945 ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum]; 946 XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; 947 XF86VideoAdaptorPtr newAdaptor = NULL; 948 int num_adaptors; 949 950 pGeode = GEODEPTR(pScrni); 951 952 if (pGeode->NoAccel) { 953 ErrorF("Cannot run Xv without accelerations!\n"); 954 return; 955 } 956 957 if (!(newAdaptor = LXSetupImageVideo(pScrn))) { 958 ErrorF("Error while setting up the adaptor.\n"); 959 return; 960 } 961 962 LXInitOffscreenImages(pScrn); 963 964 num_adaptors = xf86XVListGenericAdaptors(pScrni, &adaptors); 965 966 if (!num_adaptors) { 967 num_adaptors = 1; 968 adaptors = &newAdaptor; 969 } else { 970 newAdaptors = 971 malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *)); 972 973 if (newAdaptors) { 974 memcpy(newAdaptors, adaptors, num_adaptors * 975 sizeof(XF86VideoAdaptorPtr)); 976 newAdaptors[num_adaptors] = newAdaptor; 977 adaptors = newAdaptors; 978 num_adaptors++; 979 } else 980 ErrorF("Memory error while setting up the adaptor\n"); 981 } 982 983 if (num_adaptors) 984 xf86XVScreenInit(pScrn, adaptors, num_adaptors); 985 986 if (newAdaptors) 987 free(newAdaptors); 988} 989