diff --git a/hw/xfree86/doc/devel/exa-driver.txt b/hw/xfree86/doc/devel/exa-driver.txt new file mode 100644 index 000000000..2b9481ee0 --- /dev/null +++ b/hw/xfree86/doc/devel/exa-driver.txt @@ -0,0 +1,613 @@ +Adding EXA support to your X.Org video driver +--------------------------------------------- +EXA (for EXcellent Architecture or Ex-kaa aXeleration Architecture or +whatever) aims to extend the life of the venerable XFree86 video drivers by +introducing hooks that they can implement to more efficiently accelerate the X +Render extension: solid fills, blits within screen memory and to and from +system memory, and Porter-Duff compositing and transform operations. + +Globals +------- +XF86EXA will be defined to a nonzero value if your X server codebase supports +the EXA API. Use it to conditionalize your new EXA code if your driver is +shared with a non-EXA codebases. If present, necessary functions, structures +and defines will be located in "exa.h". + +AccelMethod +----------- +A new config file option, AccelMethod, should be used in your driver to select +between the EXA and XAA acceleration APIs. The default should be XAA for +6.9/7.0 drivers. + +Some drivers implement a per-instance useEXA flag to track whether EXA is +active or not. It can be helpful to also conditionalize XAA support so that +it can easily be turned off/removed in the future. Setting the flag and +checking for AccelMethod can be done in the driver's Options routine (a +friendly printf is be a nice way of letting the user know which method is in +use). + +Core EXA functions +------------------ +The following functions are provided, for use by your driver, to do +allocation, initialization, version checking, etc. + + /** + * exaGetVersion - retrieve EXA version number from server + * + * Simply returns the EXA version number, useful for checking for EXA + * features at runtime. + */ + unsigned int exaGetVersion(void) + + /** + * exaDriverInit - tell EXA about a new EXA driver + * @pScreen - current screen + * @pScreenInfo - driver structure + * + * Tell EXA about the driver described by @pScreenInfo. + * + * Returns TRUE for success, FALSE for failure. + */ + Bool exaDriverInit(ScreenPtr pScreen, ExaDriverPtr pScreenInfo) + + /** + * exaDriverFini - teardown an EXA driver + * @pScreen: current screen + * + * Tell EXA that an EXA driver associated with @pScreen is gone. + */ + void exaDriverFini(ScreenPtr pScreen) + + + /** + * exaOffscreenAlloc - allocate offscreen memory + * @pScreen: current screen + * @size: size in bytes + * @align: alignment constraints, must be a power of two + * @locked: allocate the memory as locked? + * @save: offscreen save routine + * @privdata: private driver data for @save routine + * + * Allocate some offscreen memory from the device associated with @pScreen. + * @size and @align determine where and how large the section is, and + * @locked will determine whether the new memory should be freed later on or + * if it should be kept in card memory until freed explicitly. @save and + * @privData are used to make room for the new allocation in scratch space, + * if necessary, and only need to be passed in if your driver doesn't + * support UploadToScreen and uses scratch space instead. + * + * Note that @align must be a power of two, currently. + * + * Returns NULL on failure, or a pointer to the new offscreen memory on + * success. + */ + ExaOffscreenArea *exaOffscreenAlloc(ScreenPtr pScreen, int size, int align, + Bool locked, ExaOffscreenSaveProc save, + pointer privData); + + /** + * exaOffscreenFree - free offscreen memory + * @pScreen: current screen + * @area: area to free + * + * Free some offscreen memory previously allocated with exaOffscreenAlloc, + * described by @area. + * + * Returns a pointer to to the freed area. + */ + ExaOffscreenArea *exaOffscreenFree(ScreenPtr pScreen, ExaOffscreenArea *area) + + /** + * exaInitCard - initialize EXA card structure + * @exa: card structure to initialize + * @sync: card needs sync? + * @memory_base: pointer to beginning of framebuffer memory + * @off_screen_base: offset to the first free byte of offscreen memory + * @memory_size: size of framebuffer memory + * @offscreen_byte_align: card alignment restriction, in bytes + * @offscreen_pitch: card pitch alignment restriction, in bytes + * @flags: flags + * @max_x: maximum width of screen + * @max_y: maximum height of screen + * + * This is just a wrapper around the initialization of the EXA driver's card + * structure. + * + * The flags argument specifies what features the card supports, two flags + * are currently defined: + * %EXA_OFFSCREEN_PIXMAPS - offscreen pixmaps are supported + * %EXA_OFFSCREEN_ALIGN_POT - offscreen objects must hve a power of two + * alignment of their pitch + * + * This routine is just a macro, and so it can't fail (unless it causes a + * compile failure). + * + * [This macro appears broken in the current tree, s/Sync/needsSync/.] + */ + void exaInitCard(EXADriverPtr *exa, Bool sync, CARD8 *memory_base, + unsigned longoff_screen_base, unsigned long memory_size, + int offscreen_byte_align, int offscreen_pitch, int flags, + int max_x, int max_y) + + /** + * exaMarkSync - mark a sync point + * @pScreen: current screen + * + * Record a marker for later synchronization. May be useful to drivers that + * need to tell EXA that they've used the accelerator. + */ + void exaMarkSync(ScreenPtr pScreen) + + /** + * exaWaitSync - wait for the last marker to complete + * @pScreen: current screen + * + * Wait until the device associated with @pScreen is done with the operation + * associated with the last exaMarkSync() call. + */ + void exaWaitSync(ScreenPtr pScreen) + + /** + * exaOffscreenInit - initialize offscreen memory + * @pScreen: current screen + * + * Private, core server use only (unless someone comes up with a good + * reason for it to be otherwise). + */ + Bool exaOffscreenInit(ScreenPtr pScreen) + +Some helper functions are also available to make common EXA related functions +easier. + + /** + * exaGetPixmapPitch - return the pitch for a pixmap + * @p: pixmap + * + * exaGetPixmapPitch() will calculate and return the pitch for the pixmap @p. + */ + int exaGetPixmapPitch(PixmapPtr p) + + /** + * exaGetPixmapOffset - return the offset of a pixmap + * @p: pixmap + * + * exaGetPixmapOffset() will calculate and return the offset in video memory + * of the pixmap @p. + */ + unsigned int exaGetPixmapOffset(PixmapPtr p) + +Driver EXA routines +------------------- +EXA requires the addition of new routines to your driver's acceleration +implementation. The following structure defines the EXA acceleration API, +some are required to be implemented in your driver, others are optional. + +Note that for routines that take a source and destination pixmap, the pitches +may be different. + + typedef struct _ExaAccelInfo { + /** + * PrepareSolid - setup for solid fill + * @pPixmap: Pixmap destination + * @alu: raster operation + * @planemask: mask for fill + * @fg: foreground color + * + * Setup the card's engine for a solid fill operation into @pPixmap. + * @alu specifies the raster op for the fill, @planemask specifies an + * optional mask, and @fg specifies the foreground color for the fill. + * + * You can add additional fields to your driver record structure to store + * state needed by this routine, if necessary. + * + * Return TRUE for if your driver can accelerate the operation with the + * parameters given, or FALSE if EXA should fallback to manual rendering. + * + * Required. + */ + Bool (*PrepareSolid)(PixmapPtr pPixmap, int alu, Pixel planemask, + Pixel fg); + + /** + * Solid - solid fill operation + * @pPixmap: Pixmap destination + * @x1: left coordinate + * @y1: top coordinate + * @x2: right coordinate + * @y2: bottom coordinate + * + * Perform the fill as specified by PrepareSolid, from x1,y1 to x2,y2 within + * @pPixmap. Many devices just need the offset, pitch, start x,y, height + * and width to do the fill; others may require you to calculate the + * destination address including the offset plus the adjustment for the + * pitch, x and y. Check out a few driver implementations for ideas about + * what might work best for your particular device. + * + * Must not fail. + * + * Required. + */ + void (*Solid)(PixmapPtr pPixmap, int x1, int y1, int x2, int y2); + + /** + * DoneSolid - finish a solid fill + * @pPixmap: Pixmap to finish + * + * Finish the solid fills done in the preceeding Solid calls. + * + * Must not fail. + * + * Required. + */ + void (*DoneSolid)(PixmapPtr pPixmap); + + /** + * PrepareCopy - setup a copy operation + * @pSrcPixmap: source Pixmap + * @pDstPixmap: destination Pixmap + * @xdir: x direction for the copy + * @ydir: y direction for the copy + * @alu: raster operation + * @planemask: optional planemask for the copy + * + * Copy @pSrcPixmap to @pDstPixmap in the x and y direction specified, + * with the raster operation @alu. @planemask specifies an optional + * color plane mask for the copy. Note that pSrcPixmap isn't available in + * the subsequent Copy routine, so you may have to store some of its values + * elsewhere for later use. + * + * You can add additional fields to your driver record structure to store + * state needed by this routine, if necessary, for instance calculating the + * framebuffer offset in PrepareCopy and then using it in the subsequent + * Copy call. + * + * Return TRUE if your driver can accelerate the copy operation with the + * parameters given, or FALSE if EXA should fallback to manual rendering. + * + * Required. + */ + Bool (*PrepareCopy)(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, + int ydir, int alu, Pixel planemask); + + /** + * Copy - perform a copy between two pixmaps + * @pDstPixmap: destination Pixmap + * @srcX: source X coordinate + * @srcY: source Y coordinate + * @dstX: destination X coordinate + * @dstY: destination Y coordinate + * @width: copy width + * @height: copy height + * + * Perform the copy setup by the previous PrepareCopy call, from + * (@srcX,@srcY) in the source pixmap to (@dstX,@dstY) in pDstPixmap using + * @width and @height to determine the quantity of the copy. + * + * Must not fail. + * + * Required. + */ + void (*Copy)(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, + int width, int height); + + /** + * DoneCopy - finish a copy operation + * @pDstPixmap: Pixmap to complete + * + * Tear down the copy operation for @pDstPixmap, if necessary. + * + * Must not fail. + * + * Required. + */ + void (*DoneCopy)(PixmapPtr pDstPixmap); + + /** + * CheckComposite - check to see if a composite operation is doable + * @op: composite operation + * @pSrcPicture: source Picture + * @pMaskPicture: mask Picture + * @pDstPicture: destination Picture + * + * Check to see if @pSrcPicture can be composited onto @pDstPicture with + * @pMaskPicture as a mask. + * + * Return TRUE if it should be possible to accelerate the given operation + * once the pixmap is migrated (so don't fail just because it looks like the + * pixmap is in the wrong place), or FALSE if it can't be accelerated. + * + * [Insert implementation hints here.] + * + * Optional but recommended. + */ + Bool (*CheckComposite)(int op, PicturePtr pSrcPicture, + PicturePtr pMaskPicture, PicturePtr pDstPicture); + + /** + * PrepareComposite - setup a composite operation + * @op: composite operation + * @pSrcPicture: source Picture + * @pMaskPicture: mask Picture + * @pDstPicture: destination Picture + * @pSrc: Pixmap source + * @pMask: Pixmap mask + * @pDst: Pixmap destination + * + * Setup the Porter-Duff compositing operation, @op, with the passed in + * parameters. + * + * Return TRUE if the operation can be accelerated, or FALSE if the driver + * can't accelerate the operation (e.g. if the pixmaps are incompatible with + * acceleration). + * + * Optional. + */ + Bool (*PrepareComposite)(int op, PicturePtr pSrcPicture, + PicturePtr pMaskPicture, PicturePtr pDstPicture, + PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst); + + /** + * Composite - perform a composite operation + * @pDst: destination Pixmap + * @srcX: source X coordinate + * @srcY: source Y coordinate + * @maskX: X coordinate of mask + * @maskY: Y coordinate of mask + * @dstX: destination X coordinate + * @dstY: destination Y coordinate + * @width: operation width + * @height: operation height + * + * Perform a composite operation setup by the last PrepareComposite call. + * + * Must not fail. + * + * Optional. + */ + void (*Composite)(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height); + + /** + * DoneComposite - composite operation teardown + * @pDst: Pixmap in question + * + * Finish and teardown the composite operation performed by the last + * Composite call. + * + * Must not fail. + * + * Optional. + */ + void (*DoneComposite)(PixmapPtr pDst); + + /** + * UploadToScreen - load memory into video RAM + * @pDst: destination Pixmap + * @src: source in system memory + * @src_pitch: width of source + * + * Copy system memory from @src to the PixmapPtr @pDst @src_pitch + * bytes at a time. UploadToScreen is used to move Pixmaps from system + * memory to the framebuffer, where alignment restrictions may increase the + * pitch. + * + * Return TRUE if the operation can be accelerated (e.g. the driver can DMA + * @src into the framebuffer) or FALSE if EXA should just memcpy it. + * + * Optional but recommended. + */ + Bool (*UploadToScreen)(PixmapPtr pDst, char *src, int src_pitch); + + /** + * UploadToScratch - load memory into video RAM + * @pSrc: source Pixmap + * @pDst: destination Pixmap + * + * Recommended in the absence of UploadToScreen, otherwise don't bother. + * Must setup space (likely reserved at driver startup time) in framebuffer + * memory, copy @pSrc from system memory into @pDst in framebuffer memory, + * and adjust pDst->devKind to the pitch of the destination and + * pDst->devPrivate.ptr to the pointer to the area. The driver is + * responsbile for syncing UploadToScratch. Only data from the last + * UploadToScratch is required to be valid at any given time. + * + * Return TRUE for success, FALSE for failure. + * + * Optional, recommended only if UploadToScreen isn't available. + */ + Bool (*UploadToScratch)(PixmapPtr pSrc, PixmapPtr pDst); + + /** + * DownloadFromScreen - copy from video RAM to system memory + * @pSrc: source Pixmap + * @x: starting X coordinate in Pixmap + * @y: starting Y coordinate in Pixmap + * @w: copy width + * @h: copy height + * @dst: destination in system memory + * @dst_pitch: target width + * + * Just copy (x,y)->(x+w,y+h) from @pSrc to @dst using @dst_pitch + * width? + * + * Return TRUE for success, FALSE for failure. + * + * Optional but recommended. + */ + Bool (*DownloadFromScreen)(PixmapPtr pSrc, int x, int y, int w, int h, + char *dst, int dst_pitch); + + /** + * MarkSync - return a marker for later use by WaitMarker + * @pScreen: current screen + * + * Return a command marker for use by WaitMarker. This is an optional + * optmization that can keep WaitMarker from having to idle the whole + * engine. + * + * Returns an integer command id marker. + * + * Optional. + */ + int (*MarkSync)(ScreenPtr screen); + + /** + * WaitMarker - finish the last command + * @pScreen: current screen + * @marker: command marker + * + * Return after the command specified by @marker is done, or just idle + * the whole engine (the latter is your only option unless you implement + * MarkSync()). + * + * Must not fail. + * + * Required. + */ + void (*WaitMarker)(ScreenPtr pScreen, int marker); + } ExaAccelInfoRec, *ExaAccelInfoPtr; + +This is an extra, optional routine, used as a callback to the offscreen +allocation function. + + /** + * ScratchSave - save the scratch area, or just throw it away + * @pScreen: ScreenPtr for this screen + * @area: offscreen area pointer to save + * + * This routine is responsible for saving the scratch area for later + * use, but can optionally just throw it away by setting the driver's + * exa_scratch field to NULL. This is the routine that should be passed to + * exaOffscreenAlloc so it can save the scratch area if necessary. It might + * be implemented as a copy from video RAM to AGP space, for example, or + * just free the scratch space, track that in the driver, and then + * reallocate it later. + * + * Must not fail. + * + * Optional and not recommended since you should be implementing + * UploadToScreen instead of using scratch space! + */ + void ScratchSave(ScreenPtr pScreen, ExaOffscreenArea *area); + +EXA driver fields +----------------- +Each driver record structure also needs a few additional fields if EXA +support is to be used, e.g.: + + #if XF86EXA + /* Container structure, describes card and accel. hooks */ + ExaDriverPtr EXADriverPtr; + #endif + +EXA initialization +------------------ +Your driver's AccelInit routine has to initialize the EXADriverPtr if EXA +support is enabled, with appropriate error handling (i.e. NoAccel and +NoXvideo should be set to true if EXA fails to initialize for whatever +reason). + +A few, card specific fields need to be initialized: + + /* + * EXA uses memoryBase to access the framebuffer, while memorySize and + * offscreenBase are used in accessing offscreen memory. EXA will allocate + * memory from memoryBase + offscreenBase to memoryBase + memorySize, so be + * sure to set them accordingly as each device's memory map is different. + */ + EXADriverPtr->card.memoryBase = ? /* base of the framebuffer */ + EXADriverPtr->card.memorySize = ? /* end of offscreen memory */ + /* offset of offscreen memory relative to memoryBase */ + EXADriverPtr->card.offScreenBase = ? + /* + * If your offscreen memory is just after your framebuffer, which is at the + * start of memory, it may be something like: + * pScrn->virtualX * pScrn->virtualY * ((pScrn->bitsPerPixel * + 7) / 8) + * should use the X value from the adjusted width based on virtualX, after + * accounting for the accelerator's pitch alignment constraints + */ + + /* + * Alignment settings for pixmaps, to allow for hardware acceleration on + * them. Not applied to all pixmaps--the visible screen is an exception, + * and thus Prepare* acceleration hooks should test for these and fail + * appropriately. pixmapOffsetAlign is the value that the pixmap's offset + * from the beginning of the framebuffer must be aligned to. pixmapPitchAlign + * is the value that the pitch of a pixmap must be aligned to (along with + * ALIGN_POT). + */ + EXADriverPtr->card.pixmapOffsetAlign = ? + /* also called stride */ + EXADriverPtr->card.pixmapPitchAlign = ? + + /* Max screen size supported by the card? */ + EXADriverPtr->card.maxX = ? + EXADriverPtr->card.maxY = ? + +The AccelInit routine also needs to make sure that there's enough offscreen +memory for certain operations to function, like Xvideo, which should advertise +a maximum size no larger than can be dealt with given the amount of offscreen +memory available. + +And of course all the callbacks you implemented as described above (with +whatever names you've chosen): + + EXADriverPtr->accel.WaitMarker = WaitMarker; + + /* Solid fill & copy, the bare minimum */ + EXADriverPtr->accel.PrepareSolid = PrepareSolid; + EXADriverPtr->accel.Solid = Solid; + EXADriverPtr->accel.DoneSolid = DoneSolid; + EXADriverPtr->accel.PrepareCopy = PrepareCopy; + EXADriverPtr->accel.Copy = Copy; + EXADriverPtr->accel.DoneCopy = DoneCopy; + + /* Composite pointers if implemented... */ + + /* Upload, download to/from Screen, optional */ + EXADriverPtr->accel.UploadToScreen = UploadToScreen; + EXADriverPtr->accel.DownloadFromScreen = DownloadFromScreen; + +After setting up the above, AccelInit should call exaDriverInit and pass in +the current Screen and the new EXADriverPtr that was just allocated and filled +out (don't forget to check for errors as that routine can fail). + +If your driver doesn't support UploadToScreen, you should allocate some +scratch space for use by commonly used pixmaps (e.g. glyphs). Note that it's +much better to implement UploadToScreen than to allocate scratch space, but if +necessary allocate about as much as you'd need for a line of text. + + pDrv->exa_scratch = exaOffscreenAlloc(pScreen, 128 * 1024, 16, TRUE, + ScratchSave, pDrv); + + /* Why is this required? Shouldn't exaOffscreenAlloc take care of it? */ + if(pDrv->exa_scratch) { + pDrv->exa_scratch_next = pDrv->exa_scratch->offset; + pDrv->EXADriverPtr->accel.UploadToScratch = UploadToScratch; + } + +EXA and Xv +---------- +Video support becomes easier with EXA since AllocateFBMemory can use +exaOffscreenAlloc directly, freeing a previous area if necessary and +allocating a new one. Likewise, FreeFBMemory can call exaOffscreenFree. + +EXA symbols +----------- +Drivers implementing EXA will also need some additional symbols from the +X core: exaGetVersion, exaDriverInit, exaDriverFini, exaOffscreenAlloc, +and exaOffscreenFree. These must be added to your LoaderRefSymLists +call at setup time. + +EXA teardown +------------ +At screen close time, EXA drivers should, call exaDriverFini with their screen +pointer, free their EXADriver structure, and do any other necessary teardown. + +EXA misc. +--------- +In many drivers, DGA support will need to be changed to be aware of the new +EXA support. + +Send updates and corrections to Jesse Barnes or +just check them in if you have permission.