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