Home | History | Annotate | Line # | Download | only in src
      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 */
     71 static void LXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit);
     72 
     73 static void
     74 
     75 
     76 LXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height,
     77                BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH);
     78 
     79 static void LXResetVideo(ScrnInfoPtr pScrni);
     80 
     81 static XF86VideoEncodingRec DummyEncoding[1] = {
     82     {0, "XV_IMAGE", 1024, 1024, {1, 1}}
     83 };
     84 
     85 static XF86VideoFormatRec Formats[] = {
     86     {8, PseudoColor}, {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
     87 };
     88 
     89 static 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 
     95 static 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 
    106 typedef 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 
    121 static void
    122 LXCopyFromSys(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 
    136 static void
    137 LXSetColorkey(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 
    184 struct {
    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 
    194 static Bool
    195 LXAllocateVidMem(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 
    215 static Bool
    216 LXCopyPlanar(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 
    293 static Bool
    294 LXCopyPacked(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 
    352 static void
    353 LXDisplayVideo(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 
    464 static int
    465 LXPutImage(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 
    538 static void
    539 LXQueryBestSize(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 
    547 static Atom xvColorKey, xvColorKeyMode, xvFilter;
    548 
    549 static int
    550 LXGetPortAttribute(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 
    567 static int
    568 LXSetPortAttribute(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 
    594 static void
    595 LXStopVideo(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 
    630 static void
    631 LXResetVideo(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 
    645 static void
    646 LXVidBlockHandler(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 
    689 static XF86VideoAdaptorPtr
    690 LXSetupImageVideo(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 
    760 struct OffscreenPrivRec {
    761     ExaOffscreenArea *vidmem;
    762     Bool isOn;
    763 };
    764 
    765 static int
    766 LXDisplaySurface(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 
    814 static int
    815 LXAllocateSurface(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 
    879 static int
    880 LXStopSurface(XF86SurfacePtr surface)
    881 {
    882     struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *)
    883         surface->devPrivate.ptr;
    884 
    885     pPriv->isOn = FALSE;
    886     return Success;
    887 }
    888 
    889 static int
    890 LXFreeSurface(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 
    911 static int
    912 LXGetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 *value)
    913 {
    914     return LXGetPortAttribute(pScrni, attribute, value,
    915                               (pointer) (GET_PORT_PRIVATE(pScrni)));
    916 }
    917 
    918 static int
    919 LXSetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value)
    920 {
    921     return LXSetPortAttribute(pScrni, attribute, value,
    922                               (pointer) (GET_PORT_PRIVATE(pScrni)));
    923 }
    924 
    925 static void
    926 LXInitOffscreenImages(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 
    950 void
    951 LXInitVideo(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