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