lx_video.c revision 170d5fdc
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, lines) == 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 LXCopyFromSys(pGeode, buf + srcOffset, dstOffset, dstPitch, srcPitch, 338 height, pixels); 339 340 videoScratch.dstOffset = dstOffset; 341 videoScratch.dstPitch = dstPitch; 342 343 return TRUE; 344} 345 346static void 347LXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height, 348 BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH) 349{ 350 long ystart, xend, yend; 351 unsigned long lines = 0; 352 unsigned long yExtra, uvExtra = 0; 353 DF_VIDEO_POSITION vidPos; 354 DF_VIDEO_SOURCE_PARAMS vSrcParams; 355 int err; 356 357 memset(&vSrcParams, 0, sizeof(vSrcParams)); 358 359 gp_wait_until_idle(); 360 361 switch (id) { 362 case FOURCC_UYVY: 363 vSrcParams.video_format = DF_VIDFMT_UYVY; 364 break; 365 366 case FOURCC_Y800: 367 case FOURCC_YV12: 368 case FOURCC_I420: 369 vSrcParams.video_format = DF_VIDFMT_Y0Y1Y2Y3; 370 break; 371 case FOURCC_YUY2: 372 vSrcParams.video_format = DF_VIDFMT_YUYV; 373 break; 374 case FOURCC_Y2YU: 375 vSrcParams.video_format = DF_VIDFMT_Y2YU; 376 break; 377 case FOURCC_YVYU: 378 vSrcParams.video_format = DF_VIDFMT_YVYU; 379 break; 380 case FOURCC_RGB565: 381 vSrcParams.video_format = DF_VIDFMT_RGB; 382 break; 383 } 384 385 vSrcParams.width = width; 386 vSrcParams.height = height; 387 vSrcParams.y_pitch = videoScratch.dstPitch; 388 vSrcParams.uv_pitch = videoScratch.UVPitch; 389 390 /* Set up scaling */ 391 df_set_video_filter_coefficients(NULL, 1); 392 393 err = df_set_video_scale(width, height, drawW, drawH, 394 DF_SCALEFLAG_CHANGEX | DF_SCALEFLAG_CHANGEY); 395 if (err != CIM_STATUS_OK) { 396 /* Note the problem, but do nothing for now. */ 397 ErrorF("Video scale factor too large: %dx%d -> %dx%d\n", 398 width, height, drawW, drawH); 399 } 400 401 /* Figure out clipping */ 402 403 xend = dstBox->x2; 404 yend = dstBox->y2; 405 406 if (dstBox->y1 < 0) { 407 if (srcH < drawH) 408 lines = ((-dstBox->y1) * srcH) / drawH; 409 else 410 lines = (-dstBox->y1); 411 412 ystart = 0; 413 drawH += dstBox->y1; 414 } else { 415 ystart = dstBox->y1; 416 lines = 0; 417 } 418 419 yExtra = lines * videoScratch.dstPitch; 420 uvExtra = (lines >> 1) * videoScratch.UVPitch; 421 422 memset(&vidPos, 0, sizeof(vidPos)); 423 424 vidPos.x = dstBox->x1; 425 vidPos.y = ystart; 426 vidPos.width = xend - dstBox->x1; 427 vidPos.height = yend - ystart; 428 429 df_set_video_position(&vidPos); 430 431 vSrcParams.y_offset = videoScratch.dstOffset + yExtra; 432 433 switch (id) { 434 case FOURCC_Y800: 435 case FOURCC_I420: 436 vSrcParams.u_offset = videoScratch.UDstOffset + uvExtra; 437 vSrcParams.v_offset = videoScratch.VDstOffset + uvExtra; 438 break; 439 case FOURCC_YV12: 440 vSrcParams.v_offset = videoScratch.UDstOffset + uvExtra; 441 vSrcParams.u_offset = videoScratch.VDstOffset + uvExtra; 442 break; 443 444 default: 445 vSrcParams.u_offset = vSrcParams.v_offset = 0; 446 break; 447 } 448 449 vSrcParams.flags = DF_SOURCEFLAG_IMPLICITSCALING; 450 df_configure_video_source(&vSrcParams, &vSrcParams); 451 452 /* Turn on the video palette */ 453 df_set_video_palette(NULL); 454 df_set_video_enable(1, 0); 455} 456 457static int 458LXPutImage(ScrnInfoPtr pScrni, 459 short srcX, short srcY, short drawX, short drawY, 460 short srcW, short srcH, short drawW, short drawH, 461 int id, unsigned char *buf, 462 short width, short height, Bool sync, RegionPtr clipBoxes, 463 pointer data, DrawablePtr pDraw) 464{ 465 GeodeRec *pGeode = GEODEPTR(pScrni); 466 GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; 467 INT32 x1, x2, y1, y2; 468 BoxRec dstBox; 469 Bool ret; 470 471 if (pGeode->rotation != RR_Rotate_0) 472 return Success; 473 474 if (srcW <= 0 || srcH <= 0) { 475 return Success; 476 } 477 478 if (drawW <= 0 || drawH <= 0) { 479 return Success; 480 } 481 482 if (drawW > 16384) 483 drawW = 16384; 484 485 memset(&videoScratch, 0, sizeof(videoScratch)); 486 487 x1 = srcX; 488 x2 = srcX + srcW; 489 y1 = srcY; 490 y2 = srcY + srcH; 491 492 dstBox.x1 = drawX; 493 dstBox.x2 = drawX + drawW; 494 dstBox.y1 = drawY; 495 dstBox.y2 = drawY + drawH; 496 497 dstBox.x1 -= pScrni->frameX0; 498 dstBox.x2 -= pScrni->frameX0; 499 dstBox.y1 -= pScrni->frameY0; 500 dstBox.y2 -= pScrni->frameY0; 501 502 if (id == FOURCC_YV12 || id == FOURCC_I420) 503 ret = LXCopyPlanar(pScrni, id, buf, x1, y1, x2, y2, width, 504 height, data); 505 else 506 ret = LXCopyPacked(pScrni, id, buf, x1, y1, x2, y2, width, 507 height, data); 508 509 if (ret == FALSE) 510 return BadAlloc; 511 512 if (!RegionsEqual(&pPriv->clip, clipBoxes) || 513 (drawW != pPriv->pwidth || drawH != pPriv->pheight)) { 514 REGION_COPY(pScrni->pScreen, &pPriv->clip, clipBoxes); 515 516 if (pPriv->colorKeyMode == 0) { 517 xf86XVFillKeyHelper(pScrni->pScreen, pPriv->colorKey, clipBoxes); 518 } 519 520 LXDisplayVideo(pScrni, id, width, height, &dstBox, 521 srcW, srcH, drawW, drawH); 522 pPriv->pwidth = drawW; 523 pPriv->pheight = drawH; 524 } 525 526 pPriv->videoStatus = CLIENT_VIDEO_ON; 527 528 return Success; 529} 530 531static void 532LXQueryBestSize(ScrnInfoPtr pScrni, Bool motion, 533 short vidW, short vidH, short drawW, short drawH, 534 unsigned int *retW, unsigned int *retH, pointer data) 535{ 536 *retW = drawW > 16384 ? 16384 : drawW; 537 *retH = drawH; 538} 539 540static Atom xvColorKey, xvColorKeyMode, xvFilter; 541 542static int 543LXGetPortAttribute(ScrnInfoPtr pScrni, 544 Atom attribute, INT32 * value, pointer data) 545{ 546 GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; 547 548 if (attribute == xvColorKey) 549 *value = pPriv->colorKey; 550 else if (attribute == xvColorKeyMode) 551 *value = pPriv->colorKeyMode; 552 else if (attribute == xvFilter) 553 *value = pPriv->filter; 554 else 555 return BadMatch; 556 557 return Success; 558} 559 560static int 561LXSetPortAttribute(ScrnInfoPtr pScrni, 562 Atom attribute, INT32 value, pointer data) 563{ 564 GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; 565 566 gp_wait_until_idle(); 567 568 if (attribute == xvColorKey) { 569 pPriv->colorKey = value; 570 LXSetColorkey(pScrni, pPriv); 571 } else if (attribute == xvColorKeyMode) { 572 pPriv->colorKeyMode = value; 573 LXSetColorkey(pScrni, pPriv); 574 } else if (attribute == xvFilter) { 575 if ((value < 0) || (value > 1)) 576 return BadValue; 577 pPriv->filter = value; 578 } else 579 return BadMatch; 580 581 return Success; 582} 583 584static void 585LXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit) 586{ 587 GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; 588 589 if (pPriv->videoStatus == 0) 590 return; 591 592 REGION_EMPTY(pScrni->pScreen, &pPriv->clip); 593 gp_wait_until_idle(); 594 595 if (exit) { 596 if (pPriv->videoStatus & CLIENT_VIDEO_ON) { 597 unsigned int val; 598 599 df_set_video_enable(0, 0); 600 /* Put the LUT back in bypass */ 601 val = READ_VID32(DF_VID_MISC); 602 WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH); 603 } 604 605 if (pPriv->vidmem) { 606 exaOffscreenFree(pScrni->pScreen, pPriv->vidmem); 607 pPriv->vidmem = NULL; 608 } 609 610 pPriv->videoStatus = 0; 611 612 /* Eh? */ 613 } else if (pPriv->videoStatus & CLIENT_VIDEO_ON) { 614 pPriv->videoStatus |= OFF_TIMER; 615 pPriv->offTime = currentTime.milliseconds + OFF_DELAY; 616 } 617} 618 619static void 620LXResetVideo(ScrnInfoPtr pScrni) 621{ 622 GeodeRec *pGeode = GEODEPTR(pScrni); 623 624 if (!pGeode->NoAccel) { 625 GeodePortPrivRec *pPriv = pGeode->adaptor->pPortPrivates[0].ptr; 626 627 gp_wait_until_idle(); 628 df_set_video_palette(NULL); 629 630 LXSetColorkey(pScrni, pPriv); 631 } 632} 633 634static void 635LXVidBlockHandler(int i, pointer blockData, pointer pTimeout, 636 pointer pReadmask) 637{ 638 ScreenPtr pScrn = screenInfo.screens[i]; 639 ScrnInfoPtr pScrni = xf86Screens[i]; 640 GeodeRec *pGeode = GEODEPTR(pScrni); 641 GeodePortPrivRec *pPriv = GET_PORT_PRIVATE(pScrni); 642 643 pScrn->BlockHandler = pGeode->BlockHandler; 644 (*pScrn->BlockHandler) (i, blockData, pTimeout, pReadmask); 645 pScrn->BlockHandler = LXVidBlockHandler; 646 647 if (pPriv->videoStatus & TIMER_MASK) { 648 Time now = currentTime.milliseconds; 649 650 if (pPriv->videoStatus & OFF_TIMER) { 651 gp_wait_until_idle(); 652 653 if (pPriv->offTime < now) { 654 unsigned int val; 655 656 df_set_video_enable(0, 0); 657 pPriv->videoStatus = FREE_TIMER; 658 pPriv->freeTime = now + FREE_DELAY; 659 660 /* Turn off the video palette */ 661 val = READ_VID32(DF_VID_MISC); 662 WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH); 663 } 664 } else { 665 if (pPriv->freeTime < now) { 666 667 if (pPriv->vidmem) { 668 exaOffscreenFree(pScrni->pScreen, pPriv->vidmem); 669 pPriv->vidmem = NULL; 670 } 671 672 pPriv->videoStatus = 0; 673 } 674 } 675 } 676} 677 678static XF86VideoAdaptorPtr 679LXSetupImageVideo(ScreenPtr pScrn) 680{ 681 ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum]; 682 GeodeRec *pGeode = GEODEPTR(pScrni); 683 XF86VideoAdaptorPtr adapt; 684 GeodePortPrivRec *pPriv; 685 686 adapt = calloc(1, sizeof(XF86VideoAdaptorRec) + 687 sizeof(GeodePortPrivRec) + sizeof(DevUnion)); 688 689 if (adapt == NULL) { 690 ErrorF("Couldn't create the rec\n"); 691 return NULL; 692 } 693 694 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 695 adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; 696 697 adapt->name = "AMD Geode LX"; 698 adapt->nEncodings = 1; 699 adapt->pEncodings = DummyEncoding; 700 adapt->nFormats = ARRAY_SIZE(Formats); 701 adapt->pFormats = Formats; 702 adapt->nPorts = 1; 703 adapt->pPortPrivates = (DevUnion *) (&adapt[1]); 704 pPriv = (GeodePortPrivRec *) (&adapt->pPortPrivates[1]); 705 adapt->pPortPrivates[0].ptr = (pointer) (pPriv); 706 adapt->pAttributes = Attributes; 707 adapt->nImages = ARRAY_SIZE(Images); 708 adapt->nAttributes = ARRAY_SIZE(Attributes); 709 adapt->pImages = Images; 710 adapt->PutVideo = NULL; 711 adapt->PutStill = NULL; 712 adapt->GetVideo = NULL; 713 adapt->GetStill = NULL; 714 adapt->StopVideo = LXStopVideo; 715 adapt->SetPortAttribute = LXSetPortAttribute; 716 adapt->GetPortAttribute = LXGetPortAttribute; 717 adapt->QueryBestSize = LXQueryBestSize; 718 adapt->PutImage = LXPutImage; 719 720 /* Use the common function */ 721 adapt->QueryImageAttributes = GeodeQueryImageAttributes; 722 723 pPriv->vidmem = NULL; 724 pPriv->filter = 0; 725 pPriv->colorKey = 0; 726 pPriv->colorKeyMode = 0; 727 pPriv->videoStatus = 0; 728 pPriv->pwidth = 0; 729 pPriv->pheight = 0; 730 731 REGION_NULL(pScrn, &pPriv->clip); 732 733 pGeode->adaptor = adapt; 734 735 pGeode->BlockHandler = pScrn->BlockHandler; 736 pScrn->BlockHandler = LXVidBlockHandler; 737 738 xvColorKey = MAKE_ATOM("XV_COLORKEY"); 739 xvColorKeyMode = MAKE_ATOM("XV_COLORKEYMODE"); 740 xvFilter = MAKE_ATOM("XV_FILTER"); 741 742 LXResetVideo(pScrni); 743 744 return adapt; 745} 746 747/* Offscreen surface allocation */ 748 749struct OffscreenPrivRec 750{ 751 ExaOffscreenArea *vidmem; 752 Bool isOn; 753}; 754 755static int 756LXDisplaySurface(XF86SurfacePtr surface, 757 short srcX, short srcY, short drawX, short drawY, 758 short srcW, short srcH, short drawW, short drawH, RegionPtr clipBoxes) 759{ 760 struct OffscreenPrivRec *pPriv = 761 (struct OffscreenPrivRec *)surface->devPrivate.ptr; 762 763 ScrnInfoPtr pScrni = surface->pScrn; 764 GeodePortPrivRec *portPriv = GET_PORT_PRIVATE(pScrni); 765 766 BoxRec dstBox; 767 768 dstBox.x1 = drawX; 769 dstBox.x2 = drawX + drawW; 770 dstBox.y1 = drawY; 771 dstBox.y2 = drawY + drawH; 772 773 if ((drawW <= 0) | (drawH <= 0)) 774 return Success; 775 776 /* Is this still valid? */ 777 778 dstBox.x1 -= pScrni->frameX0; 779 dstBox.x2 -= pScrni->frameX0; 780 dstBox.y1 -= pScrni->frameY0; 781 dstBox.y2 -= pScrni->frameY0; 782 783 xf86XVFillKeyHelper(pScrni->pScreen, portPriv->colorKey, clipBoxes); 784 785 videoScratch.dstOffset = surface->offsets[0]; 786 videoScratch.dstPitch = surface->pitches[0]; 787 788 LXDisplayVideo(pScrni, surface->id, surface->width, surface->height, 789 &dstBox, srcW, srcH, drawW, drawH); 790 791 pPriv->isOn = TRUE; 792 793 if (portPriv->videoStatus & CLIENT_VIDEO_ON) { 794 REGION_EMPTY(pScrni->pScreen, &portPriv->clip); 795 UpdateCurrentTime(); 796 portPriv->videoStatus = FREE_TIMER; 797 portPriv->freeTime = currentTime.milliseconds + FREE_DELAY; 798 } 799 800 return Success; 801} 802 803static int 804LXAllocateSurface(ScrnInfoPtr pScrni, int id, unsigned short w, 805 unsigned short h, XF86SurfacePtr surface) 806{ 807 GeodeRec *pGeode = GEODEPTR(pScrni); 808 int pitch, lines; 809 ExaOffscreenArea *vidmem; 810 struct OffscreenPrivRec *pPriv; 811 812 if (w > 1024 || h > 1024) 813 return BadAlloc; 814 815 /* The width needs to be word aligned */ 816 w = (w + 1) & ~1; 817 818 pitch = ((w << 1) + 15) & ~15; 819 lines = ((pitch * h) + (pGeode->Pitch - 1)) / pGeode->Pitch; 820 821 vidmem = exaOffscreenAlloc(pScrni->pScreen, lines, 4, TRUE, 822 NULL, NULL); 823 824 if (vidmem == NULL) { 825 ErrorF("Error while allocating an offscreen region.\n"); 826 return BadAlloc; 827 } 828 829 surface->width = w; 830 surface->height = h; 831 832 surface->pitches = malloc(sizeof(int)); 833 834 surface->offsets = malloc(sizeof(int)); 835 836 pPriv = malloc(sizeof(struct OffscreenPrivRec)); 837 838 if (pPriv && surface->pitches && surface->offsets) { 839 840 pPriv->vidmem = vidmem; 841 842 pPriv->isOn = FALSE; 843 844 surface->pScrn = pScrni; 845 surface->id = id; 846 surface->pitches[0] = pitch; 847 surface->offsets[0] = vidmem->offset; 848 surface->devPrivate.ptr = (pointer) pPriv; 849 850 return Success; 851 } 852 853 if (surface->offsets) 854 free(surface->offsets); 855 856 if (surface->pitches) 857 free(surface->pitches); 858 859 if (vidmem) { 860 exaOffscreenFree(pScrni->pScreen, vidmem); 861 vidmem = NULL; 862 } 863 864 return BadAlloc; 865} 866 867static int 868LXStopSurface(XF86SurfacePtr surface) 869{ 870 struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *) 871 surface->devPrivate.ptr; 872 873 pPriv->isOn = FALSE; 874 return Success; 875} 876 877static int 878LXFreeSurface(XF86SurfacePtr surface) 879{ 880 struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *) 881 surface->devPrivate.ptr; 882 ScrnInfoPtr pScrni = surface->pScrn; 883 884 if (pPriv->isOn) 885 LXStopSurface(surface); 886 887 if (pPriv->vidmem) { 888 exaOffscreenFree(pScrni->pScreen, pPriv->vidmem); 889 pPriv->vidmem = NULL; 890 } 891 892 free(surface->pitches); 893 free(surface->offsets); 894 free(surface->devPrivate.ptr); 895 896 return Success; 897} 898 899static int 900LXGetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 * value) 901{ 902 return LXGetPortAttribute(pScrni, attribute, value, 903 (pointer) (GET_PORT_PRIVATE(pScrni))); 904} 905 906static int 907LXSetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value) 908{ 909 return LXSetPortAttribute(pScrni, attribute, value, 910 (pointer) (GET_PORT_PRIVATE(pScrni))); 911} 912 913static void 914LXInitOffscreenImages(ScreenPtr pScrn) 915{ 916 XF86OffscreenImagePtr offscreenImages; 917 918 /* need to free this someplace */ 919 if (!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec)))) 920 return; 921 922 offscreenImages[0].image = &Images[0]; 923 offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; 924 offscreenImages[0].alloc_surface = LXAllocateSurface; 925 offscreenImages[0].free_surface = LXFreeSurface; 926 offscreenImages[0].display = LXDisplaySurface; 927 offscreenImages[0].stop = LXStopSurface; 928 offscreenImages[0].setAttribute = LXSetSurfaceAttribute; 929 offscreenImages[0].getAttribute = LXGetSurfaceAttribute; 930 offscreenImages[0].max_width = 1024; 931 offscreenImages[0].max_height = 1024; 932 offscreenImages[0].num_attributes = ARRAY_SIZE(Attributes); 933 offscreenImages[0].attributes = Attributes; 934 935 xf86XVRegisterOffscreenImages(pScrn, offscreenImages, 1); 936} 937 938void 939LXInitVideo(ScreenPtr pScrn) 940{ 941 GeodeRec *pGeode; 942 ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum]; 943 XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; 944 XF86VideoAdaptorPtr newAdaptor = NULL; 945 int num_adaptors; 946 947 pGeode = GEODEPTR(pScrni); 948 949 if (pGeode->NoAccel) { 950 ErrorF("Cannot run Xv without accelerations!\n"); 951 return; 952 } 953 954 if (!(newAdaptor = LXSetupImageVideo(pScrn))) { 955 ErrorF("Error while setting up the adaptor.\n"); 956 return; 957 } 958 959 LXInitOffscreenImages(pScrn); 960 961 num_adaptors = xf86XVListGenericAdaptors(pScrni, &adaptors); 962 963 if (!num_adaptors) { 964 num_adaptors = 1; 965 adaptors = &newAdaptor; 966 } else { 967 newAdaptors = 968 malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *)); 969 970 if (newAdaptors) { 971 memcpy(newAdaptors, adaptors, num_adaptors * 972 sizeof(XF86VideoAdaptorPtr)); 973 newAdaptors[num_adaptors] = newAdaptor; 974 adaptors = newAdaptors; 975 num_adaptors++; 976 } else 977 ErrorF("Memory error while setting up the adaptor\n"); 978 } 979 980 if (num_adaptors) 981 xf86XVScreenInit(pScrn, adaptors, num_adaptors); 982 983 if (newAdaptors) 984 free(newAdaptors); 985} 986