diff --git a/ChangeLog b/ChangeLog index 0e78b32c2..357977d4f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2006-03-07 Eric Anholt + + * hw/kdrive/ephyr/Makefile.am: + * hw/kdrive/ephyr/ephyr.h: + * hw/kdrive/ephyr/ephyr_draw.c: (ephyrPrepareSolid), (ephyrSolid), + (ephyrDoneSolid), (ephyrPrepareCopy), (ephyrCopy), (ephyrDoneCopy), + (ephyrCheckComposite), (ephyrPrepareComposite), (ephyrComposite), + (ephyrDoneComposite), (ephyrMarkSync), (ephyrWaitMarker), + (ephyrDrawInit), (ephyrDrawEnable), (ephyrDrawDisable), + (ephyrDrawFini), (exaDDXDriverInit): + Add a new flag to ephyr, "-fakexa", which turns on an EXA acceleration + implementation that calls fb to get its work done. The purpose is to + have a trusted EXA driver for use with testing changes to the core of + EXA. However, fakexa has not received much testing yet, lacks offscreen + pixmaps support, and doesn't reliably provide garbage when EXA doesn't + get its syncing right. All of these should be fixed soon. + 2006-03-07 Eric Anholt * hw/xfree86/exa/exa.c: diff --git a/hw/kdrive/ephyr/Makefile.am b/hw/kdrive/ephyr/Makefile.am index 1cc5e6872..2fb1fc2e5 100644 --- a/hw/kdrive/ephyr/Makefile.am +++ b/hw/kdrive/ephyr/Makefile.am @@ -1,6 +1,7 @@ INCLUDES = \ @KDRIVE_INCS@ \ - @KDRIVE_CFLAGS@ + @KDRIVE_CFLAGS@ \ + -I$(srcdir)/../../../exa noinst_LIBRARIES = libxephyr.a libxephyr-hostx.a @@ -13,6 +14,7 @@ bin_PROGRAMS = Xephyr libxephyr_a_SOURCES = \ ephyr.c \ + ephyr_draw.c \ os.c \ hostx.h \ ephyr.h @@ -32,11 +34,10 @@ Xephyr_LDADD = \ @KDRIVE_LIBS@ \ @KDRIVE_LIBS@ \ $(TSLIB_LIBS) \ - @XEPHYR_LIBS@ - + @XEPHYR_LIBS@ \ + ../../../exa/libexa.la Xephyr_DEPENDENCIES = \ libxephyr.a \ libxephyr-hostx.a \ @KDRIVE_LIBS@ - diff --git a/hw/kdrive/ephyr/ephyr.h b/hw/kdrive/ephyr/ephyr.h index 93c210795..d1ee50090 100644 --- a/hw/kdrive/ephyr/ephyr.h +++ b/hw/kdrive/ephyr/ephyr.h @@ -33,6 +33,7 @@ #include "kdrive.h" #include "kkeymap.h" #include "hostx.h" +#include "exa.h" #ifdef RANDR #include "randrstr.h" @@ -44,12 +45,26 @@ typedef struct _ephyrPriv { CARD8 *base; int bytes_per_line; } EphyrPriv; - + +typedef struct _ephyrFakexaPriv { + ExaDriverRec exa; + Bool is_synced; + + /* The following are arguments and other information from Prepare* calls + * which are stored for use in the inner calls. + */ + int op; + PicturePtr pSrcPicture, pMaskPicture, pDstPicture; + PixmapPtr pSrc, pDst; + GCPtr pGC; +} EphyrFakexaPriv; + typedef struct _ephyrScrPriv { Rotation randr; Bool shadow; PixmapPtr pShadow; DamagePtr pDamage; + EphyrFakexaPriv *fakexa; } EphyrScrPriv; extern KdCardFuncs ephyrFuncs; @@ -161,5 +176,18 @@ extern Bool ephyrCursorInit(ScreenPtr pScreen); extern void ephyrCursorEnable(ScreenPtr pScreen); +/* ephyr_draw.c */ + +Bool +ephyrDrawInit(ScreenPtr pScreen); + +void +ephyrDrawEnable(ScreenPtr pScreen); + +void +ephyrDrawDisable(ScreenPtr pScreen); + +void +ephyrDrawFini(ScreenPtr pScreen); #endif diff --git a/hw/kdrive/ephyr/ephyr_draw.c b/hw/kdrive/ephyr/ephyr_draw.c new file mode 100644 index 000000000..7a0c02646 --- /dev/null +++ b/hw/kdrive/ephyr/ephyr_draw.c @@ -0,0 +1,340 @@ +#ifdef HAVE_CONFIG_H +#include +#endif +#include "ephyr.h" +#include "exa_priv.h" +#include "fbpict.h" + +#define EPHYR_TRACE_DRAW 0 + +#if EPHYR_TRACE_DRAW +#define TRACE_DRAW() ErrorF("%s\n", __FUNCTION__); +#else +#define TRACE_DRAW() do { } while (0) +#endif + +/* Use some oddball alignments, to expose issues in alignment handling in EXA. */ +#define EPHYR_OFFSET_ALIGN 11 +#define EPHYR_PITCH_ALIGN 9 + +#define EPHYR_OFFSCREEN_SIZE (16 * 1024 * 1024) +#define EPHYR_OFFSCREEN_BASE (1 * 1024 * 1024) + +/** + * Sets up a scratch GC for fbFill, and saves other parameters for the + * ephyrSolid implementation. + */ +static Bool +ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + CARD32 tmpval[3]; + + fakexa->pDst = pPix; + fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen); + + tmpval[0] = alu; + tmpval[1] = pm; + tmpval[2] = fg; + ChangeGC(fakexa->pGC, GCFunction | GCPlaneMask | GCForeground, + tmpval); + + ValidateGC(&pPix->drawable, fakexa->pGC); + + TRACE_DRAW(); + + return TRUE; +} + +/** + * Does an fbFill of the rectangle to be drawn. + */ +static void +ephyrSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fbFill(&fakexa->pDst->drawable, fakexa->pGC, x1, y1, x2 - x1, y2 - y1); +} + +/** + * Cleans up the scratch GC created in ephyrPrepareSolid. + */ +static void +ephyrDoneSolid(PixmapPtr pPix) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + FreeScratchGC(fakexa->pGC); +} + +/** + * Sets up a scratch GC for fbCopyArea, and saves other parameters for the + * ephyrCopy implementation. + */ +static Bool +ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu, + Pixel pm) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + CARD32 tmpval[2]; + + fakexa->pSrc = pSrc; + fakexa->pDst = pDst; + fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen); + + tmpval[0] = alu; + tmpval[1] = pm; + ChangeGC (fakexa->pGC, GCFunction | GCPlaneMask, tmpval); + + ValidateGC(&pDst->drawable, fakexa->pGC); + + TRACE_DRAW(); + + return TRUE; +} + +/** + * Does an fbCopyArea to take care of the requested copy. + */ +static void +ephyrCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fbCopyArea(&fakexa->pSrc->drawable, &fakexa->pDst->drawable, fakexa->pGC, + srcX, srcY, w, h, dstX, dstY); +} + +/** + * Cleans up the scratch GC created in ephyrPrepareCopy. + */ +static void +ephyrDoneCopy(PixmapPtr pDst) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + FreeScratchGC (fakexa->pGC); +} + +/** + * Reports that we can always accelerate the given operation. This may not be + * desirable from an EXA testing standpoint -- testing the fallback paths would + * be useful, too. + */ +static Bool +ephyrCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + return TRUE; +} + +/** + * Saves off the parameters for ephyrComposite. + */ +static Bool +ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, + PixmapPtr pDst) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + op = op; + fakexa->pSrcPicture = pSrcPicture; + fakexa->pMaskPicture = pMaskPicture; + fakexa->pDstPicture = pDstPicture; + + TRACE_DRAW(); + + return TRUE; +} + +/** + * Does an fbComposite to complete the requested drawing operation. + */ +static void +ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int w, int h) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture, + fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY, + w, h); +} + +static void +ephyrDoneComposite(PixmapPtr pDst) +{ +} + +/** + * In fakexa, we currently only track whether we have synced to the latest + * "accelerated" drawing that has happened or not. This will be used by an + * ephyrPrepareAccess for the purpose of reliably providing garbage when + * reading/writing when we haven't synced. + */ +static int +ephyrMarkSync(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fakexa->is_synced = FALSE; + + return 0; +} + +/** + * Assumes that we're waiting on the latest marker. When EXA gets smarter and + * starts using markers in a fine-grained way (for example, waiting on drawing + * to required pixmaps to complete, rather than waiting for all drawing to + * complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker + * implementation fine-grained as well. + */ +static void +ephyrWaitMarker(ScreenPtr pScreen, int marker) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fakexa->is_synced = TRUE; +} + +/** + * This function initializes EXA to use the fake acceleration implementation + * which just falls through to software. The purpose is to have a reliable, + * correct driver with which to test changes to the EXA core. + */ +Bool +ephyrDrawInit(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa; + Bool success; + + fakexa = xcalloc(1, sizeof(*fakexa)); + if (fakexa == NULL) + return FALSE; + +#if 0 + /* Currently, EXA isn't ready for what we want to do here. We want one + * pointer to the framebuffer (which is set in exaMapFramebuffer) to be + * considered "in framebuffer", and a separate pointer to offscreen memory, + * which is also considered to be in framebuffer. The alternative would be + * to extend the XImage data area set up in hostx.c from exaMapFramebuffer, + * but that may be complicated. + */ + fakexa->exa.card.memoryBase = xalloc(EPHYR_OFFSCREEN_SIZE); + if (fakexa->exa.card.memoryBase == NULL) { + xfree(fakexa); + return FALSE; + } + fakexa->exa.card.memorySize = EPHYR_OFFSCREEN_SIZE; + fakexa->exa.card.offScreenBase = EPHYR_OFFSCREEN_BASE; +#else + /* Tell EXA that there's a single framebuffer area, which happens to cover + * exactly what the front buffer is. + */ + fakexa->exa.card.memoryBase = screen->memory_base; + fakexa->exa.card.memorySize = screen->off_screen_base; + fakexa->exa.card.offScreenBase = screen->off_screen_base; +#endif + + fakexa->exa.accel.PrepareSolid = ephyrPrepareSolid; + fakexa->exa.accel.Solid = ephyrSolid; + fakexa->exa.accel.DoneSolid = ephyrDoneSolid; + + fakexa->exa.accel.PrepareCopy = ephyrPrepareCopy; + fakexa->exa.accel.Copy = ephyrCopy; + fakexa->exa.accel.DoneCopy = ephyrDoneCopy; + + fakexa->exa.accel.CheckComposite = ephyrCheckComposite; + fakexa->exa.accel.PrepareComposite = ephyrPrepareComposite; + fakexa->exa.accel.Composite = ephyrComposite; + fakexa->exa.accel.DoneComposite = ephyrDoneComposite; + + fakexa->exa.accel.MarkSync = ephyrMarkSync; + fakexa->exa.accel.WaitMarker = ephyrWaitMarker; + + fakexa->exa.card.pixmapOffsetAlign = EPHYR_OFFSET_ALIGN; + fakexa->exa.card.pixmapPitchAlign = EPHYR_PITCH_ALIGN; + + fakexa->exa.card.maxX = 1023; + fakexa->exa.card.maxY = 1023; + + fakexa->exa.card.flags = EXA_OFFSCREEN_PIXMAPS; + + success = exaDriverInit(pScreen, &fakexa->exa); + if (success) { + ErrorF("Initialized fake EXA acceleration\n"); + scrpriv->fakexa = fakexa; + } else { + ErrorF("Failed to initialize EXA\n"); + xfree(fakexa->exa.card.memoryBase); + xfree(fakexa); + } + + return success; +} + +void +ephyrDrawEnable(ScreenPtr pScreen) +{ +} + +void +ephyrDrawDisable(ScreenPtr pScreen) +{ +} + +void +ephyrDrawFini(ScreenPtr pScreen) +{ +} + +/** + * exaDDXDriverInit is required by the top-level EXA module, and is used by + * the xorg DDX to hook in its EnableDisableFB wrapper. We don't need it, since + * we won't be enabling/disabling the FB. + */ +void +exaDDXDriverInit(ScreenPtr pScreen) +{ +} diff --git a/hw/kdrive/ephyr/ephyrinit.c b/hw/kdrive/ephyr/ephyrinit.c index 28deee826..58478e690 100644 --- a/hw/kdrive/ephyr/ephyrinit.c +++ b/hw/kdrive/ephyr/ephyrinit.c @@ -62,6 +62,7 @@ ddxUseMsg (void) ErrorF("-parent XID Use existing window as Xephyr root win\n"); ErrorF("-host-cursor Re-use exisiting X host server cursor\n"); ErrorF("-fullscreen Attempt to run Xephyr fullscreen\n"); + ErrorF("-fakexa Simulate acceleration using software rendering\n"); ErrorF("\n"); exit(1); @@ -93,6 +94,14 @@ ddxProcessArgument (int argc, char **argv, int i) hostx_use_fullscreen(); return 1; } + else if (!strcmp (argv[i], "-fakexa")) + { + ephyrFuncs.initAccel = ephyrDrawInit; + ephyrFuncs.enableAccel = ephyrDrawEnable; + ephyrFuncs.disableAccel = ephyrDrawDisable; + ephyrFuncs.finiAccel = ephyrDrawFini; + return 1; + } else if (argv[i][0] == ':') { hostx_set_display_name(argv[i]);