xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

ephyr_draw.c (14915B)


      1 /*
      2  * Copyright © 2006 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     21  * SOFTWARE.
     22  *
     23  * Authors:
     24  *    Eric Anholt <eric@anholt.net>
     25  *
     26  */
     27 
     28 #ifdef HAVE_DIX_CONFIG_H
     29 #include <dix-config.h>
     30 #endif
     31 
     32 #include "ephyr.h"
     33 #include "exa_priv.h"
     34 #include "fbpict.h"
     35 
     36 #define EPHYR_TRACE_DRAW 0
     37 
     38 #if EPHYR_TRACE_DRAW
     39 #define TRACE_DRAW() ErrorF("%s\n", __FUNCTION__);
     40 #else
     41 #define TRACE_DRAW() do { } while (0)
     42 #endif
     43 
     44 /* Use some oddball alignments, to expose issues in alignment handling in EXA. */
     45 #define EPHYR_OFFSET_ALIGN	24
     46 #define EPHYR_PITCH_ALIGN	24
     47 
     48 #define EPHYR_OFFSCREEN_SIZE	(16 * 1024 * 1024)
     49 #define EPHYR_OFFSCREEN_BASE	(1 * 1024 * 1024)
     50 
     51 /**
     52  * Forces a real devPrivate.ptr for hidden pixmaps, so that we can call down to
     53  * fb functions.
     54  */
     55 static void
     56 ephyrPreparePipelinedAccess(PixmapPtr pPix, int index)
     57 {
     58     KdScreenPriv(pPix->drawable.pScreen);
     59     KdScreenInfo *screen = pScreenPriv->screen;
     60     EphyrScrPriv *scrpriv = screen->driver;
     61     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
     62 
     63     assert(fakexa->saved_ptrs[index] == NULL);
     64     fakexa->saved_ptrs[index] = pPix->devPrivate.ptr;
     65 
     66     if (pPix->devPrivate.ptr != NULL)
     67         return;
     68 
     69     pPix->devPrivate.ptr = fakexa->exa->memoryBase + exaGetPixmapOffset(pPix);
     70 }
     71 
     72 /**
     73  * Restores the original devPrivate.ptr of the pixmap from before we messed with
     74  * it.
     75  */
     76 static void
     77 ephyrFinishPipelinedAccess(PixmapPtr pPix, int index)
     78 {
     79     KdScreenPriv(pPix->drawable.pScreen);
     80     KdScreenInfo *screen = pScreenPriv->screen;
     81     EphyrScrPriv *scrpriv = screen->driver;
     82     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
     83 
     84     pPix->devPrivate.ptr = fakexa->saved_ptrs[index];
     85     fakexa->saved_ptrs[index] = NULL;
     86 }
     87 
     88 /**
     89  * Sets up a scratch GC for fbFill, and saves other parameters for the
     90  * ephyrSolid implementation.
     91  */
     92 static Bool
     93 ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg)
     94 {
     95     ScreenPtr pScreen = pPix->drawable.pScreen;
     96 
     97     KdScreenPriv(pScreen);
     98     KdScreenInfo *screen = pScreenPriv->screen;
     99     EphyrScrPriv *scrpriv = screen->driver;
    100     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    101     ChangeGCVal tmpval[3];
    102 
    103     ephyrPreparePipelinedAccess(pPix, EXA_PREPARE_DEST);
    104 
    105     fakexa->pDst = pPix;
    106     fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen);
    107 
    108     tmpval[0].val = alu;
    109     tmpval[1].val = pm;
    110     tmpval[2].val = fg;
    111     ChangeGC(NullClient, fakexa->pGC, GCFunction | GCPlaneMask | GCForeground,
    112              tmpval);
    113 
    114     ValidateGC(&pPix->drawable, fakexa->pGC);
    115 
    116     TRACE_DRAW();
    117 
    118     return TRUE;
    119 }
    120 
    121 /**
    122  * Does an fbFill of the rectangle to be drawn.
    123  */
    124 static void
    125 ephyrSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2)
    126 {
    127     ScreenPtr pScreen = pPix->drawable.pScreen;
    128 
    129     KdScreenPriv(pScreen);
    130     KdScreenInfo *screen = pScreenPriv->screen;
    131     EphyrScrPriv *scrpriv = screen->driver;
    132     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    133 
    134     fbFill(&fakexa->pDst->drawable, fakexa->pGC, x1, y1, x2 - x1, y2 - y1);
    135 }
    136 
    137 /**
    138  * Cleans up the scratch GC created in ephyrPrepareSolid.
    139  */
    140 static void
    141 ephyrDoneSolid(PixmapPtr pPix)
    142 {
    143     ScreenPtr pScreen = pPix->drawable.pScreen;
    144 
    145     KdScreenPriv(pScreen);
    146     KdScreenInfo *screen = pScreenPriv->screen;
    147     EphyrScrPriv *scrpriv = screen->driver;
    148     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    149 
    150     FreeScratchGC(fakexa->pGC);
    151 
    152     ephyrFinishPipelinedAccess(pPix, EXA_PREPARE_DEST);
    153 }
    154 
    155 /**
    156  * Sets up a scratch GC for fbCopyArea, and saves other parameters for the
    157  * ephyrCopy implementation.
    158  */
    159 static Bool
    160 ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu,
    161                  Pixel pm)
    162 {
    163     ScreenPtr pScreen = pDst->drawable.pScreen;
    164 
    165     KdScreenPriv(pScreen);
    166     KdScreenInfo *screen = pScreenPriv->screen;
    167     EphyrScrPriv *scrpriv = screen->driver;
    168     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    169     ChangeGCVal tmpval[2];
    170 
    171     ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
    172     ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
    173 
    174     fakexa->pSrc = pSrc;
    175     fakexa->pDst = pDst;
    176     fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen);
    177 
    178     tmpval[0].val = alu;
    179     tmpval[1].val = pm;
    180     ChangeGC(NullClient, fakexa->pGC, GCFunction | GCPlaneMask, tmpval);
    181 
    182     ValidateGC(&pDst->drawable, fakexa->pGC);
    183 
    184     TRACE_DRAW();
    185 
    186     return TRUE;
    187 }
    188 
    189 /**
    190  * Does an fbCopyArea to take care of the requested copy.
    191  */
    192 static void
    193 ephyrCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h)
    194 {
    195     ScreenPtr pScreen = pDst->drawable.pScreen;
    196 
    197     KdScreenPriv(pScreen);
    198     KdScreenInfo *screen = pScreenPriv->screen;
    199     EphyrScrPriv *scrpriv = screen->driver;
    200     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    201 
    202     fbCopyArea(&fakexa->pSrc->drawable, &fakexa->pDst->drawable, fakexa->pGC,
    203                srcX, srcY, w, h, dstX, dstY);
    204 }
    205 
    206 /**
    207  * Cleans up the scratch GC created in ephyrPrepareCopy.
    208  */
    209 static void
    210 ephyrDoneCopy(PixmapPtr pDst)
    211 {
    212     ScreenPtr pScreen = pDst->drawable.pScreen;
    213 
    214     KdScreenPriv(pScreen);
    215     KdScreenInfo *screen = pScreenPriv->screen;
    216     EphyrScrPriv *scrpriv = screen->driver;
    217     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    218 
    219     FreeScratchGC(fakexa->pGC);
    220 
    221     ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
    222     ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
    223 }
    224 
    225 /**
    226  * Reports that we can always accelerate the given operation.  This may not be
    227  * desirable from an EXA testing standpoint -- testing the fallback paths would
    228  * be useful, too.
    229  */
    230 static Bool
    231 ephyrCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
    232                     PicturePtr pDstPicture)
    233 {
    234     /* Exercise the component alpha helper, so fail on this case like a normal
    235      * driver
    236      */
    237     if (pMaskPicture && pMaskPicture->componentAlpha && op == PictOpOver)
    238         return FALSE;
    239 
    240     return TRUE;
    241 }
    242 
    243 /**
    244  * Saves off the parameters for ephyrComposite.
    245  */
    246 static Bool
    247 ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
    248                       PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask,
    249                       PixmapPtr pDst)
    250 {
    251     KdScreenPriv(pDst->drawable.pScreen);
    252     KdScreenInfo *screen = pScreenPriv->screen;
    253     EphyrScrPriv *scrpriv = screen->driver;
    254     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    255 
    256     ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
    257     if (pSrc != NULL)
    258         ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
    259     if (pMask != NULL)
    260         ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK);
    261 
    262     fakexa->op = op;
    263     fakexa->pSrcPicture = pSrcPicture;
    264     fakexa->pMaskPicture = pMaskPicture;
    265     fakexa->pDstPicture = pDstPicture;
    266     fakexa->pSrc = pSrc;
    267     fakexa->pMask = pMask;
    268     fakexa->pDst = pDst;
    269 
    270     TRACE_DRAW();
    271 
    272     return TRUE;
    273 }
    274 
    275 /**
    276  * Does an fbComposite to complete the requested drawing operation.
    277  */
    278 static void
    279 ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
    280                int dstX, int dstY, int w, int h)
    281 {
    282     KdScreenPriv(pDst->drawable.pScreen);
    283     KdScreenInfo *screen = pScreenPriv->screen;
    284     EphyrScrPriv *scrpriv = screen->driver;
    285     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    286 
    287     fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture,
    288                 fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY,
    289                 w, h);
    290 }
    291 
    292 static void
    293 ephyrDoneComposite(PixmapPtr pDst)
    294 {
    295     KdScreenPriv(pDst->drawable.pScreen);
    296     KdScreenInfo *screen = pScreenPriv->screen;
    297     EphyrScrPriv *scrpriv = screen->driver;
    298     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    299 
    300     if (fakexa->pMask != NULL)
    301         ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK);
    302     if (fakexa->pSrc != NULL)
    303         ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
    304     ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
    305 }
    306 
    307 /**
    308  * Does fake acceleration of DownloadFromScren using memcpy.
    309  */
    310 static Bool
    311 ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst,
    312                         int dst_pitch)
    313 {
    314     KdScreenPriv(pSrc->drawable.pScreen);
    315     KdScreenInfo *screen = pScreenPriv->screen;
    316     EphyrScrPriv *scrpriv = screen->driver;
    317     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    318     unsigned char *src;
    319     int src_pitch, cpp;
    320 
    321     if (pSrc->drawable.bitsPerPixel < 8)
    322         return FALSE;
    323 
    324     ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
    325 
    326     cpp = pSrc->drawable.bitsPerPixel / 8;
    327     src_pitch = exaGetPixmapPitch(pSrc);
    328     src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc);
    329     src += y * src_pitch + x * cpp;
    330 
    331     for (; h > 0; h--) {
    332         memcpy(dst, src, w * cpp);
    333         dst += dst_pitch;
    334         src += src_pitch;
    335     }
    336 
    337     exaMarkSync(pSrc->drawable.pScreen);
    338 
    339     ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC);
    340 
    341     return TRUE;
    342 }
    343 
    344 /**
    345  * Does fake acceleration of UploadToScreen using memcpy.
    346  */
    347 static Bool
    348 ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
    349                     int src_pitch)
    350 {
    351     KdScreenPriv(pDst->drawable.pScreen);
    352     KdScreenInfo *screen = pScreenPriv->screen;
    353     EphyrScrPriv *scrpriv = screen->driver;
    354     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    355     unsigned char *dst;
    356     int dst_pitch, cpp;
    357 
    358     if (pDst->drawable.bitsPerPixel < 8)
    359         return FALSE;
    360 
    361     ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
    362 
    363     cpp = pDst->drawable.bitsPerPixel / 8;
    364     dst_pitch = exaGetPixmapPitch(pDst);
    365     dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst);
    366     dst += y * dst_pitch + x * cpp;
    367 
    368     for (; h > 0; h--) {
    369         memcpy(dst, src, w * cpp);
    370         dst += dst_pitch;
    371         src += src_pitch;
    372     }
    373 
    374     exaMarkSync(pDst->drawable.pScreen);
    375 
    376     ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST);
    377 
    378     return TRUE;
    379 }
    380 
    381 static Bool
    382 ephyrPrepareAccess(PixmapPtr pPix, int index)
    383 {
    384     /* Make sure we don't somehow end up with a pointer that is in framebuffer
    385      * and hasn't been readied for us.
    386      */
    387     assert(pPix->devPrivate.ptr != NULL);
    388 
    389     return TRUE;
    390 }
    391 
    392 /**
    393  * In fakexa, we currently only track whether we have synced to the latest
    394  * "accelerated" drawing that has happened or not.  It's not used for anything
    395  * yet.
    396  */
    397 static int
    398 ephyrMarkSync(ScreenPtr pScreen)
    399 {
    400     KdScreenPriv(pScreen);
    401     KdScreenInfo *screen = pScreenPriv->screen;
    402     EphyrScrPriv *scrpriv = screen->driver;
    403     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    404 
    405     fakexa->is_synced = FALSE;
    406 
    407     return 0;
    408 }
    409 
    410 /**
    411  * Assumes that we're waiting on the latest marker.  When EXA gets smarter and
    412  * starts using markers in a fine-grained way (for example, waiting on drawing
    413  * to required pixmaps to complete, rather than waiting for all drawing to
    414  * complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker
    415  * implementation fine-grained as well.
    416  */
    417 static void
    418 ephyrWaitMarker(ScreenPtr pScreen, int marker)
    419 {
    420     KdScreenPriv(pScreen);
    421     KdScreenInfo *screen = pScreenPriv->screen;
    422     EphyrScrPriv *scrpriv = screen->driver;
    423     EphyrFakexaPriv *fakexa = scrpriv->fakexa;
    424 
    425     fakexa->is_synced = TRUE;
    426 }
    427 
    428 /**
    429  * This function initializes EXA to use the fake acceleration implementation
    430  * which just falls through to software.  The purpose is to have a reliable,
    431  * correct driver with which to test changes to the EXA core.
    432  */
    433 Bool
    434 ephyrDrawInit(ScreenPtr pScreen)
    435 {
    436     KdScreenPriv(pScreen);
    437     KdScreenInfo *screen = pScreenPriv->screen;
    438     EphyrScrPriv *scrpriv = screen->driver;
    439     EphyrPriv *priv = screen->card->driver;
    440     EphyrFakexaPriv *fakexa;
    441     Bool success;
    442 
    443     fakexa = calloc(1, sizeof(*fakexa));
    444     if (fakexa == NULL)
    445         return FALSE;
    446 
    447     fakexa->exa = exaDriverAlloc();
    448     if (fakexa->exa == NULL) {
    449         free(fakexa);
    450         return FALSE;
    451     }
    452 
    453     fakexa->exa->memoryBase = (CARD8 *) (priv->base);
    454     fakexa->exa->memorySize = priv->bytes_per_line * ephyrBufferHeight(screen);
    455     fakexa->exa->offScreenBase = priv->bytes_per_line * screen->height;
    456 
    457     /* Since we statically link against EXA, we shouldn't have to be smart about
    458      * versioning.
    459      */
    460     fakexa->exa->exa_major = 2;
    461     fakexa->exa->exa_minor = 0;
    462 
    463     fakexa->exa->PrepareSolid = ephyrPrepareSolid;
    464     fakexa->exa->Solid = ephyrSolid;
    465     fakexa->exa->DoneSolid = ephyrDoneSolid;
    466 
    467     fakexa->exa->PrepareCopy = ephyrPrepareCopy;
    468     fakexa->exa->Copy = ephyrCopy;
    469     fakexa->exa->DoneCopy = ephyrDoneCopy;
    470 
    471     fakexa->exa->CheckComposite = ephyrCheckComposite;
    472     fakexa->exa->PrepareComposite = ephyrPrepareComposite;
    473     fakexa->exa->Composite = ephyrComposite;
    474     fakexa->exa->DoneComposite = ephyrDoneComposite;
    475 
    476     fakexa->exa->DownloadFromScreen = ephyrDownloadFromScreen;
    477     fakexa->exa->UploadToScreen = ephyrUploadToScreen;
    478 
    479     fakexa->exa->MarkSync = ephyrMarkSync;
    480     fakexa->exa->WaitMarker = ephyrWaitMarker;
    481 
    482     fakexa->exa->PrepareAccess = ephyrPrepareAccess;
    483 
    484     fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN;
    485     fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN;
    486 
    487     fakexa->exa->maxX = 1023;
    488     fakexa->exa->maxY = 1023;
    489 
    490     fakexa->exa->flags = EXA_OFFSCREEN_PIXMAPS;
    491 
    492     success = exaDriverInit(pScreen, fakexa->exa);
    493     if (success) {
    494         ErrorF("Initialized fake EXA acceleration\n");
    495         scrpriv->fakexa = fakexa;
    496     }
    497     else {
    498         ErrorF("Failed to initialize EXA\n");
    499         free(fakexa->exa);
    500         free(fakexa);
    501     }
    502 
    503     return success;
    504 }
    505 
    506 void
    507 ephyrDrawEnable(ScreenPtr pScreen)
    508 {
    509 }
    510 
    511 void
    512 ephyrDrawDisable(ScreenPtr pScreen)
    513 {
    514 }
    515 
    516 void
    517 ephyrDrawFini(ScreenPtr pScreen)
    518 {
    519 }
    520 
    521 /**
    522  * exaDDXDriverInit is required by the top-level EXA module, and is used by
    523  * the xorg DDX to hook in its EnableDisableFB wrapper.  We don't need it, since
    524  * we won't be enabling/disabling the FB.
    525  */
    526 void
    527 exaDDXDriverInit(ScreenPtr pScreen)
    528 {
    529     ExaScreenPriv(pScreen);
    530 
    531     pExaScr->migration = ExaMigrationSmart;
    532     pExaScr->checkDirtyCorrectness = TRUE;
    533 }