Drop EXA code
Not used on this branch.
This commit is contained in:
parent
23296633bb
commit
aa49cd5ab7
820
exa/exa.h
820
exa/exa.h
|
@ -1,820 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (C) 2000 Keith Packard
|
||||
* 2004 Eric Anholt
|
||||
* 2005 Zack Rusin
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. Copyright holders make no
|
||||
* representations about the suitability of this software for any purpose. It
|
||||
* is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* This is the header containing the public API of EXA for exa drivers.
|
||||
*/
|
||||
|
||||
#ifndef EXA_H
|
||||
#define EXA_H
|
||||
|
||||
#include "scrnintstr.h"
|
||||
#include "pixmapstr.h"
|
||||
#include "windowstr.h"
|
||||
#include "gcstruct.h"
|
||||
#include "picturestr.h"
|
||||
#include "fb.h"
|
||||
|
||||
#define EXA_VERSION_MAJOR 2
|
||||
#define EXA_VERSION_MINOR 6
|
||||
#define EXA_VERSION_RELEASE 0
|
||||
|
||||
typedef struct _ExaOffscreenArea ExaOffscreenArea;
|
||||
|
||||
typedef void (*ExaOffscreenSaveProc) (ScreenPtr pScreen,
|
||||
ExaOffscreenArea * area);
|
||||
|
||||
typedef enum _ExaOffscreenState {
|
||||
ExaOffscreenAvail,
|
||||
ExaOffscreenRemovable,
|
||||
ExaOffscreenLocked
|
||||
} ExaOffscreenState;
|
||||
|
||||
struct _ExaOffscreenArea {
|
||||
int base_offset; /* allocation base */
|
||||
int offset; /* aligned offset */
|
||||
int size; /* total allocation size */
|
||||
unsigned last_use;
|
||||
void *privData;
|
||||
|
||||
ExaOffscreenSaveProc save;
|
||||
|
||||
ExaOffscreenState state;
|
||||
|
||||
ExaOffscreenArea *next;
|
||||
|
||||
unsigned eviction_cost;
|
||||
|
||||
ExaOffscreenArea *prev; /* Double-linked list for defragmentation */
|
||||
int align; /* required alignment */
|
||||
};
|
||||
|
||||
/**
|
||||
* The ExaDriver structure is allocated through exaDriverAlloc(), and then
|
||||
* fllled in by drivers.
|
||||
*/
|
||||
typedef struct _ExaDriver {
|
||||
/**
|
||||
* exa_major and exa_minor should be set by the driver to the version of
|
||||
* EXA which the driver was compiled for (or configures itself at runtime
|
||||
* to support). This allows EXA to extend the structure for new features
|
||||
* without breaking ABI for drivers compiled against older versions.
|
||||
*/
|
||||
int exa_major, exa_minor;
|
||||
|
||||
/**
|
||||
* memoryBase is the address of the beginning of framebuffer memory.
|
||||
* The visible screen should be within memoryBase to memoryBase +
|
||||
* memorySize.
|
||||
*/
|
||||
CARD8 *memoryBase;
|
||||
|
||||
/**
|
||||
* offScreenBase is the offset from memoryBase of the beginning of the area
|
||||
* to be managed by EXA's linear offscreen memory manager.
|
||||
*
|
||||
* In XFree86 DDX drivers, this is probably:
|
||||
* (pScrn->displayWidth * cpp * pScrn->virtualY)
|
||||
*/
|
||||
unsigned long offScreenBase;
|
||||
|
||||
/**
|
||||
* memorySize is the length (in bytes) of framebuffer memory beginning
|
||||
* from memoryBase.
|
||||
*
|
||||
* The offscreen memory manager will manage the area beginning at
|
||||
* (memoryBase + offScreenBase), with a length of (memorySize -
|
||||
* offScreenBase)
|
||||
*
|
||||
* In XFree86 DDX drivers, this is probably (pScrn->videoRam * 1024)
|
||||
*/
|
||||
unsigned long memorySize;
|
||||
|
||||
/**
|
||||
* pixmapOffsetAlign is the byte alignment necessary for pixmap offsets
|
||||
* within framebuffer.
|
||||
*
|
||||
* Hardware typically has a required alignment of offsets, which may or may
|
||||
* not be a power of two. EXA will ensure that pixmaps managed by the
|
||||
* offscreen memory manager meet this alignment requirement.
|
||||
*/
|
||||
int pixmapOffsetAlign;
|
||||
|
||||
/**
|
||||
* pixmapPitchAlign is the byte alignment necessary for pixmap pitches
|
||||
* within the framebuffer.
|
||||
*
|
||||
* Hardware typically has a required alignment of pitches for acceleration.
|
||||
* For 3D hardware, Composite acceleration often requires that source and
|
||||
* mask pixmaps (textures) have a power-of-two pitch, which can be demanded
|
||||
* using EXA_OFFSCREEN_ALIGN_POT. These pitch requirements only apply to
|
||||
* pixmaps managed by the offscreen memory manager. Thus, it is up to the
|
||||
* driver to ensure that the visible screen has an appropriate pitch for
|
||||
* acceleration.
|
||||
*/
|
||||
int pixmapPitchAlign;
|
||||
|
||||
/**
|
||||
* The flags field is bitfield of boolean values controlling EXA's behavior.
|
||||
*
|
||||
* The flags include EXA_OFFSCREEN_PIXMAPS, EXA_OFFSCREEN_ALIGN_POT, and
|
||||
* EXA_TWO_BITBLT_DIRECTIONS.
|
||||
*/
|
||||
int flags;
|
||||
|
||||
/** @{ */
|
||||
/**
|
||||
* maxX controls the X coordinate limitation for rendering from the card.
|
||||
* The driver should never receive a request for rendering beyond maxX
|
||||
* in the X direction from the origin of a pixmap.
|
||||
*/
|
||||
int maxX;
|
||||
|
||||
/**
|
||||
* maxY controls the Y coordinate limitation for rendering from the card.
|
||||
* The driver should never receive a request for rendering beyond maxY
|
||||
* in the Y direction from the origin of a pixmap.
|
||||
*/
|
||||
int maxY;
|
||||
/** @} */
|
||||
|
||||
/* private */
|
||||
ExaOffscreenArea *offScreenAreas;
|
||||
Bool needsSync;
|
||||
int lastMarker;
|
||||
|
||||
/** @name Solid
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* PrepareSolid() sets up the driver for doing a solid fill.
|
||||
* @param pPixmap Destination pixmap
|
||||
* @param alu raster operation
|
||||
* @param planemask write mask for the fill
|
||||
* @param fg "foreground" color for the fill
|
||||
*
|
||||
* This call should set up the driver for doing a series of solid fills
|
||||
* through the Solid() call. The alu raster op is one of the GX*
|
||||
* graphics functions listed in X.h, and typically maps to a similar
|
||||
* single-byte "ROP" setting in all hardware. The planemask controls
|
||||
* which bits of the destination should be affected, and will only represent
|
||||
* the bits up to the depth of pPixmap. The fg is the pixel value of the
|
||||
* foreground color referred to in ROP descriptions.
|
||||
*
|
||||
* Note that many drivers will need to store some of the data in the driver
|
||||
* private record, for sending to the hardware with each drawing command.
|
||||
*
|
||||
* The PrepareSolid() call is required of all drivers, but it may fail for any
|
||||
* reason. Failure results in a fallback to software rendering.
|
||||
*/
|
||||
Bool (*PrepareSolid) (PixmapPtr pPixmap,
|
||||
int alu, Pixel planemask, Pixel fg);
|
||||
|
||||
/**
|
||||
* Solid() performs a solid fill set up in the last PrepareSolid() call.
|
||||
*
|
||||
* @param pPixmap destination pixmap
|
||||
* @param x1 left coordinate
|
||||
* @param y1 top coordinate
|
||||
* @param x2 right coordinate
|
||||
* @param y2 bottom coordinate
|
||||
*
|
||||
* Performs the fill set up by the last PrepareSolid() call, covering the
|
||||
* area from (x1,y1) to (x2,y2) in pPixmap. Note that the coordinates are
|
||||
* in the coordinate space of the destination pixmap, so the driver will
|
||||
* need to set up the hardware's offset and pitch for the destination
|
||||
* coordinates according to the pixmap's offset and pitch within
|
||||
* framebuffer. This likely means using exaGetPixmapOffset() and
|
||||
* exaGetPixmapPitch().
|
||||
*
|
||||
* This call is required if PrepareSolid() ever succeeds.
|
||||
*/
|
||||
void (*Solid) (PixmapPtr pPixmap, int x1, int y1, int x2, int y2);
|
||||
|
||||
/**
|
||||
* DoneSolid() finishes a set of solid fills.
|
||||
*
|
||||
* @param pPixmap destination pixmap.
|
||||
*
|
||||
* The DoneSolid() call is called at the end of a series of consecutive
|
||||
* Solid() calls following a successful PrepareSolid(). This allows drivers
|
||||
* to finish up emitting drawing commands that were buffered, or clean up
|
||||
* state from PrepareSolid().
|
||||
*
|
||||
* This call is required if PrepareSolid() ever succeeds.
|
||||
*/
|
||||
void (*DoneSolid) (PixmapPtr pPixmap);
|
||||
/** @} */
|
||||
|
||||
/** @name Copy
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* PrepareCopy() sets up the driver for doing a copy within video
|
||||
* memory.
|
||||
*
|
||||
* @param pSrcPixmap source pixmap
|
||||
* @param pDstPixmap destination pixmap
|
||||
* @param dx X copy direction
|
||||
* @param dy Y copy direction
|
||||
* @param alu raster operation
|
||||
* @param planemask write mask for the fill
|
||||
*
|
||||
* This call should set up the driver for doing a series of copies from the
|
||||
* the pSrcPixmap to the pDstPixmap. The dx flag will be positive if the
|
||||
* hardware should do the copy from the left to the right, and dy will be
|
||||
* positive if the copy should be done from the top to the bottom. This
|
||||
* is to deal with self-overlapping copies when pSrcPixmap == pDstPixmap.
|
||||
* If your hardware can only support blits that are (left to right, top to
|
||||
* bottom) or (right to left, bottom to top), then you should set
|
||||
* #EXA_TWO_BITBLT_DIRECTIONS, and EXA will break down Copy operations to
|
||||
* ones that meet those requirements. The alu raster op is one of the GX*
|
||||
* graphics functions listed in X.h, and typically maps to a similar
|
||||
* single-byte "ROP" setting in all hardware. The planemask controls which
|
||||
* bits of the destination should be affected, and will only represent the
|
||||
* bits up to the depth of pPixmap.
|
||||
*
|
||||
* Note that many drivers will need to store some of the data in the driver
|
||||
* private record, for sending to the hardware with each drawing command.
|
||||
*
|
||||
* The PrepareCopy() call is required of all drivers, but it may fail for any
|
||||
* reason. Failure results in a fallback to software rendering.
|
||||
*/
|
||||
Bool (*PrepareCopy) (PixmapPtr pSrcPixmap,
|
||||
PixmapPtr pDstPixmap,
|
||||
int dx, int dy, int alu, Pixel planemask);
|
||||
|
||||
/**
|
||||
* Copy() performs a copy set up in the last PrepareCopy call.
|
||||
*
|
||||
* @param pDstPixmap destination pixmap
|
||||
* @param srcX source X coordinate
|
||||
* @param srcY source Y coordinate
|
||||
* @param dstX destination X coordinate
|
||||
* @param dstY destination Y coordinate
|
||||
* @param width width of the rectangle to be copied
|
||||
* @param height height of the rectangle to be copied.
|
||||
*
|
||||
* Performs the copy set up by the last PrepareCopy() call, copying the
|
||||
* rectangle from (srcX, srcY) to (srcX + width, srcY + width) in the source
|
||||
* pixmap to the same-sized rectangle at (dstX, dstY) in the destination
|
||||
* pixmap. Those rectangles may overlap in memory, if
|
||||
* pSrcPixmap == pDstPixmap. Note that this call does not receive the
|
||||
* pSrcPixmap as an argument -- if it's needed in this function, it should
|
||||
* be stored in the driver private during PrepareCopy(). As with Solid(),
|
||||
* the coordinates are in the coordinate space of each pixmap, so the driver
|
||||
* will need to set up source and destination pitches and offsets from those
|
||||
* pixmaps, probably using exaGetPixmapOffset() and exaGetPixmapPitch().
|
||||
*
|
||||
* This call is required if PrepareCopy ever succeeds.
|
||||
*/
|
||||
void (*Copy) (PixmapPtr pDstPixmap,
|
||||
int srcX,
|
||||
int srcY, int dstX, int dstY, int width, int height);
|
||||
|
||||
/**
|
||||
* DoneCopy() finishes a set of copies.
|
||||
*
|
||||
* @param pPixmap destination pixmap.
|
||||
*
|
||||
* The DoneCopy() call is called at the end of a series of consecutive
|
||||
* Copy() calls following a successful PrepareCopy(). This allows drivers
|
||||
* to finish up emitting drawing commands that were buffered, or clean up
|
||||
* state from PrepareCopy().
|
||||
*
|
||||
* This call is required if PrepareCopy() ever succeeds.
|
||||
*/
|
||||
void (*DoneCopy) (PixmapPtr pDstPixmap);
|
||||
/** @} */
|
||||
|
||||
/** @name Composite
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* CheckComposite() checks to see if a composite operation could be
|
||||
* accelerated.
|
||||
*
|
||||
* @param op Render operation
|
||||
* @param pSrcPicture source Picture
|
||||
* @param pMaskPicture mask picture
|
||||
* @param pDstPicture destination Picture
|
||||
*
|
||||
* The CheckComposite() call checks if the driver could handle acceleration
|
||||
* of op with the given source, mask, and destination pictures. This allows
|
||||
* drivers to check source and destination formats, supported operations,
|
||||
* transformations, and component alpha state, and send operations it can't
|
||||
* support to software rendering early on. This avoids costly pixmap
|
||||
* migration to the wrong places when the driver can't accelerate
|
||||
* operations. Note that because migration hasn't happened, the driver
|
||||
* can't know during CheckComposite() what the offsets and pitches of the
|
||||
* pixmaps are going to be.
|
||||
*
|
||||
* See PrepareComposite() for more details on likely issues that drivers
|
||||
* will have in accelerating Composite operations.
|
||||
*
|
||||
* The CheckComposite() call is recommended if PrepareComposite() is
|
||||
* implemented, but is not required.
|
||||
*/
|
||||
Bool (*CheckComposite) (int op,
|
||||
PicturePtr pSrcPicture,
|
||||
PicturePtr pMaskPicture, PicturePtr pDstPicture);
|
||||
|
||||
/**
|
||||
* PrepareComposite() sets up the driver for doing a Composite operation
|
||||
* described in the Render extension protocol spec.
|
||||
*
|
||||
* @param op Render operation
|
||||
* @param pSrcPicture source Picture
|
||||
* @param pMaskPicture mask picture
|
||||
* @param pDstPicture destination Picture
|
||||
* @param pSrc source pixmap
|
||||
* @param pMask mask pixmap
|
||||
* @param pDst destination pixmap
|
||||
*
|
||||
* This call should set up the driver for doing a series of Composite
|
||||
* operations, as described in the Render protocol spec, with the given
|
||||
* pSrcPicture, pMaskPicture, and pDstPicture. The pSrc, pMask, and
|
||||
* pDst are the pixmaps containing the pixel data, and should be used for
|
||||
* setting the offset and pitch used for the coordinate spaces for each of
|
||||
* the Pictures.
|
||||
*
|
||||
* Notes on interpreting Picture structures:
|
||||
* - The Picture structures will always have a valid pDrawable.
|
||||
* - The Picture structures will never have alphaMap set.
|
||||
* - The mask Picture (and therefore pMask) may be NULL, in which case the
|
||||
* operation is simply src OP dst instead of src IN mask OP dst, and
|
||||
* mask coordinates should be ignored.
|
||||
* - pMarkPicture may have componentAlpha set, which greatly changes
|
||||
* the behavior of the Composite operation. componentAlpha has no effect
|
||||
* when set on pSrcPicture or pDstPicture.
|
||||
* - The source and mask Pictures may have a transformation set
|
||||
* (Picture->transform != NULL), which means that the source coordinates
|
||||
* should be transformed by that transformation, resulting in scaling,
|
||||
* rotation, etc. The PictureTransformPoint() call can transform
|
||||
* coordinates for you. Transforms have no effect on Pictures when used
|
||||
* as a destination.
|
||||
* - The source and mask pictures may have a filter set. PictFilterNearest
|
||||
* and PictFilterBilinear are defined in the Render protocol, but others
|
||||
* may be encountered, and must be handled correctly (usually by
|
||||
* PrepareComposite failing, and falling back to software). Filters have
|
||||
* no effect on Pictures when used as a destination.
|
||||
* - The source and mask Pictures may have repeating set, which must be
|
||||
* respected. Many chipsets will be unable to support repeating on
|
||||
* pixmaps that have a width or height that is not a power of two.
|
||||
*
|
||||
* If your hardware can't support source pictures (textures) with
|
||||
* non-power-of-two pitches, you should set #EXA_OFFSCREEN_ALIGN_POT.
|
||||
*
|
||||
* Note that many drivers will need to store some of the data in the driver
|
||||
* private record, for sending to the hardware with each drawing command.
|
||||
*
|
||||
* The PrepareComposite() call is not required. However, it is highly
|
||||
* recommended for performance of antialiased font rendering and performance
|
||||
* of cairo applications. Failure results in a fallback to software
|
||||
* rendering.
|
||||
*/
|
||||
Bool (*PrepareComposite) (int op,
|
||||
PicturePtr pSrcPicture,
|
||||
PicturePtr pMaskPicture,
|
||||
PicturePtr pDstPicture,
|
||||
PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst);
|
||||
|
||||
/**
|
||||
* Composite() performs a Composite operation set up in the last
|
||||
* PrepareComposite() call.
|
||||
*
|
||||
* @param pDstPixmap destination pixmap
|
||||
* @param srcX source X coordinate
|
||||
* @param srcY source Y coordinate
|
||||
* @param maskX source X coordinate
|
||||
* @param maskY source Y coordinate
|
||||
* @param dstX destination X coordinate
|
||||
* @param dstY destination Y coordinate
|
||||
* @param width destination rectangle width
|
||||
* @param height destination rectangle height
|
||||
*
|
||||
* Performs the Composite operation set up by the last PrepareComposite()
|
||||
* call, to the rectangle from (dstX, dstY) to (dstX + width, dstY + height)
|
||||
* in the destination Pixmap. Note that if a transformation was set on
|
||||
* the source or mask Pictures, the source rectangles may not be the same
|
||||
* size as the destination rectangles and filtering. Getting the coordinate
|
||||
* transformation right at the subpixel level can be tricky, and rendercheck
|
||||
* can test this for you.
|
||||
*
|
||||
* This call is required if PrepareComposite() ever succeeds.
|
||||
*/
|
||||
void (*Composite) (PixmapPtr pDst,
|
||||
int srcX,
|
||||
int srcY,
|
||||
int maskX,
|
||||
int maskY, int dstX, int dstY, int width, int height);
|
||||
|
||||
/**
|
||||
* DoneComposite() finishes a set of Composite operations.
|
||||
*
|
||||
* @param pPixmap destination pixmap.
|
||||
*
|
||||
* The DoneComposite() call is called at the end of a series of consecutive
|
||||
* Composite() calls following a successful PrepareComposite(). This allows
|
||||
* drivers to finish up emitting drawing commands that were buffered, or
|
||||
* clean up state from PrepareComposite().
|
||||
*
|
||||
* This call is required if PrepareComposite() ever succeeds.
|
||||
*/
|
||||
void (*DoneComposite) (PixmapPtr pDst);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* UploadToScreen() loads a rectangle of data from src into pDst.
|
||||
*
|
||||
* @param pDst destination pixmap
|
||||
* @param x destination X coordinate.
|
||||
* @param y destination Y coordinate
|
||||
* @param width width of the rectangle to be copied
|
||||
* @param height height of the rectangle to be copied
|
||||
* @param src pointer to the beginning of the source data
|
||||
* @param src_pitch pitch (in bytes) of the lines of source data.
|
||||
*
|
||||
* UploadToScreen() copies data in system memory beginning at src (with
|
||||
* pitch src_pitch) into the destination pixmap from (x, y) to
|
||||
* (x + width, y + height). This is typically done with hostdata uploads,
|
||||
* where the CPU sets up a blit command on the hardware with instructions
|
||||
* that the blit data will be fed through some sort of aperture on the card.
|
||||
*
|
||||
* If UploadToScreen() is performed asynchronously, it is up to the driver
|
||||
* to call exaMarkSync(). This is in contrast to most other acceleration
|
||||
* calls in EXA.
|
||||
*
|
||||
* UploadToScreen() can aid in pixmap migration, but is most important for
|
||||
* the performance of exaGlyphs() (antialiased font drawing) by allowing
|
||||
* pipelining of data uploads, avoiding a sync of the card after each glyph.
|
||||
*
|
||||
* @return TRUE if the driver successfully uploaded the data. FALSE
|
||||
* indicates that EXA should fall back to doing the upload in software.
|
||||
*
|
||||
* UploadToScreen() is not required, but is recommended if Composite
|
||||
* acceleration is supported.
|
||||
*/
|
||||
Bool (*UploadToScreen) (PixmapPtr pDst,
|
||||
int x,
|
||||
int y, int w, int h, char *src, int src_pitch);
|
||||
|
||||
/**
|
||||
* UploadToScratch() is no longer used and will be removed next time the EXA
|
||||
* major version needs to be bumped.
|
||||
*/
|
||||
Bool (*UploadToScratch) (PixmapPtr pSrc, PixmapPtr pDst);
|
||||
|
||||
/**
|
||||
* DownloadFromScreen() loads a rectangle of data from pSrc into dst
|
||||
*
|
||||
* @param pSrc source pixmap
|
||||
* @param x source X coordinate.
|
||||
* @param y source Y coordinate
|
||||
* @param width width of the rectangle to be copied
|
||||
* @param height height of the rectangle to be copied
|
||||
* @param dst pointer to the beginning of the destination data
|
||||
* @param dst_pitch pitch (in bytes) of the lines of destination data.
|
||||
*
|
||||
* DownloadFromScreen() copies data from offscreen memory in pSrc from
|
||||
* (x, y) to (x + width, y + height), to system memory starting at
|
||||
* dst (with pitch dst_pitch). This would usually be done
|
||||
* using scatter-gather DMA, supported by a DRM call, or by blitting to AGP
|
||||
* and then synchronously reading from AGP. Because the implementation
|
||||
* might be synchronous, EXA leaves it up to the driver to call
|
||||
* exaMarkSync() if DownloadFromScreen() was asynchronous. This is in
|
||||
* contrast to most other acceleration calls in EXA.
|
||||
*
|
||||
* DownloadFromScreen() can aid in the largest bottleneck in pixmap
|
||||
* migration, which is the read from framebuffer when evicting pixmaps from
|
||||
* framebuffer memory. Thus, it is highly recommended, even though
|
||||
* implementations are typically complicated.
|
||||
*
|
||||
* @return TRUE if the driver successfully downloaded the data. FALSE
|
||||
* indicates that EXA should fall back to doing the download in software.
|
||||
*
|
||||
* DownloadFromScreen() is not required, but is highly recommended.
|
||||
*/
|
||||
Bool (*DownloadFromScreen) (PixmapPtr pSrc,
|
||||
int x, int y,
|
||||
int w, int h, char *dst, int dst_pitch);
|
||||
|
||||
/**
|
||||
* MarkSync() requests that the driver mark a synchronization point,
|
||||
* returning an driver-defined integer marker which could be requested for
|
||||
* synchronization to later in WaitMarker(). This might be used in the
|
||||
* future to avoid waiting for full hardware stalls before accessing pixmap
|
||||
* data with the CPU, but is not important in the current incarnation of
|
||||
* EXA.
|
||||
*
|
||||
* Note that drivers should call exaMarkSync() when they have done some
|
||||
* acceleration, rather than their own MarkSync() handler, as otherwise EXA
|
||||
* will be unaware of the driver's acceleration and not sync to it during
|
||||
* fallbacks.
|
||||
*
|
||||
* MarkSync() is optional.
|
||||
*/
|
||||
int (*MarkSync) (ScreenPtr pScreen);
|
||||
|
||||
/**
|
||||
* WaitMarker() waits for all rendering before the given marker to have
|
||||
* completed. If the driver does not implement MarkSync(), marker is
|
||||
* meaningless, and all rendering by the hardware should be completed before
|
||||
* WaitMarker() returns.
|
||||
*
|
||||
* Note that drivers should call exaWaitSync() to wait for all acceleration
|
||||
* to finish, as otherwise EXA will be unaware of the driver having
|
||||
* synchronized, resulting in excessive WaitMarker() calls.
|
||||
*
|
||||
* WaitMarker() is required of all drivers.
|
||||
*/
|
||||
void (*WaitMarker) (ScreenPtr pScreen, int marker);
|
||||
|
||||
/** @{ */
|
||||
/**
|
||||
* PrepareAccess() is called before CPU access to an offscreen pixmap.
|
||||
*
|
||||
* @param pPix the pixmap being accessed
|
||||
* @param index the index of the pixmap being accessed.
|
||||
*
|
||||
* PrepareAccess() will be called before CPU access to an offscreen pixmap.
|
||||
* This can be used to set up hardware surfaces for byteswapping or
|
||||
* untiling, or to adjust the pixmap's devPrivate.ptr for the purpose of
|
||||
* making CPU access use a different aperture.
|
||||
*
|
||||
* The index is one of #EXA_PREPARE_DEST, #EXA_PREPARE_SRC,
|
||||
* #EXA_PREPARE_MASK, #EXA_PREPARE_AUX_DEST, #EXA_PREPARE_AUX_SRC, or
|
||||
* #EXA_PREPARE_AUX_MASK. Since only up to #EXA_NUM_PREPARE_INDICES pixmaps
|
||||
* will have PrepareAccess() called on them per operation, drivers can have
|
||||
* a small, statically-allocated space to maintain state for PrepareAccess()
|
||||
* and FinishAccess() in. Note that PrepareAccess() is only called once per
|
||||
* pixmap and operation, regardless of whether the pixmap is used as a
|
||||
* destination and/or source, and the index may not reflect the usage.
|
||||
*
|
||||
* PrepareAccess() may fail. An example might be the case of hardware that
|
||||
* can set up 1 or 2 surfaces for CPU access, but not 3. If PrepareAccess()
|
||||
* fails, EXA will migrate the pixmap to system memory.
|
||||
* DownloadFromScreen() must be implemented and must not fail if a driver
|
||||
* wishes to fail in PrepareAccess(). PrepareAccess() must not fail when
|
||||
* pPix is the visible screen, because the visible screen can not be
|
||||
* migrated.
|
||||
*
|
||||
* @return TRUE if PrepareAccess() successfully prepared the pixmap for CPU
|
||||
* drawing.
|
||||
* @return FALSE if PrepareAccess() is unsuccessful and EXA should use
|
||||
* DownloadFromScreen() to migate the pixmap out.
|
||||
*/
|
||||
Bool (*PrepareAccess) (PixmapPtr pPix, int index);
|
||||
|
||||
/**
|
||||
* FinishAccess() is called after CPU access to an offscreen pixmap.
|
||||
*
|
||||
* @param pPix the pixmap being accessed
|
||||
* @param index the index of the pixmap being accessed.
|
||||
*
|
||||
* FinishAccess() will be called after finishing CPU access of an offscreen
|
||||
* pixmap set up by PrepareAccess(). Note that the FinishAccess() will not be
|
||||
* called if PrepareAccess() failed and the pixmap was migrated out.
|
||||
*/
|
||||
void (*FinishAccess) (PixmapPtr pPix, int index);
|
||||
|
||||
/**
|
||||
* PixmapIsOffscreen() is an optional driver replacement to
|
||||
* exaPixmapHasGpuCopy(). Set to NULL if you want the standard behaviour
|
||||
* of exaPixmapHasGpuCopy().
|
||||
*
|
||||
* @param pPix the pixmap
|
||||
* @return TRUE if the given drawable is in framebuffer memory.
|
||||
*
|
||||
* exaPixmapHasGpuCopy() is used to determine if a pixmap is in offscreen
|
||||
* memory, meaning that acceleration could probably be done to it, and that it
|
||||
* will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
|
||||
* with the CPU.
|
||||
*
|
||||
*
|
||||
*/
|
||||
Bool (*PixmapIsOffscreen) (PixmapPtr pPix);
|
||||
|
||||
/** @name PrepareAccess() and FinishAccess() indices
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* EXA_PREPARE_DEST is the index for a pixmap that may be drawn to or
|
||||
* read from.
|
||||
*/
|
||||
#define EXA_PREPARE_DEST 0
|
||||
/**
|
||||
* EXA_PREPARE_SRC is the index for a pixmap that may be read from
|
||||
*/
|
||||
#define EXA_PREPARE_SRC 1
|
||||
/**
|
||||
* EXA_PREPARE_SRC is the index for a second pixmap that may be read
|
||||
* from.
|
||||
*/
|
||||
#define EXA_PREPARE_MASK 2
|
||||
/**
|
||||
* EXA_PREPARE_AUX* are additional indices for other purposes, e.g.
|
||||
* separate alpha maps with Composite operations.
|
||||
*/
|
||||
#define EXA_PREPARE_AUX_DEST 3
|
||||
#define EXA_PREPARE_AUX_SRC 4
|
||||
#define EXA_PREPARE_AUX_MASK 5
|
||||
#define EXA_NUM_PREPARE_INDICES 6
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* maxPitchPixels controls the pitch limitation for rendering from
|
||||
* the card.
|
||||
* The driver should never receive a request for rendering a pixmap
|
||||
* that has a pitch (in pixels) beyond maxPitchPixels.
|
||||
*
|
||||
* Setting this field is optional -- if your hardware doesn't have
|
||||
* a pitch limitation in pixels, don't set this. If neither this value
|
||||
* nor maxPitchBytes is set, then maxPitchPixels is set to maxX.
|
||||
* If set, it must not be smaller than maxX.
|
||||
*
|
||||
* @sa maxPitchBytes
|
||||
*/
|
||||
int maxPitchPixels;
|
||||
|
||||
/**
|
||||
* maxPitchBytes controls the pitch limitation for rendering from
|
||||
* the card.
|
||||
* The driver should never receive a request for rendering a pixmap
|
||||
* that has a pitch (in bytes) beyond maxPitchBytes.
|
||||
*
|
||||
* Setting this field is optional -- if your hardware doesn't have
|
||||
* a pitch limitation in bytes, don't set this.
|
||||
* If set, it must not be smaller than maxX * 4.
|
||||
* There's no default value for maxPitchBytes.
|
||||
*
|
||||
* @sa maxPitchPixels
|
||||
*/
|
||||
int maxPitchBytes;
|
||||
|
||||
/* Hooks to allow driver to its own pixmap memory management */
|
||||
void *(*CreatePixmap) (ScreenPtr pScreen, int size, int align);
|
||||
void (*DestroyPixmap) (ScreenPtr pScreen, void *driverPriv);
|
||||
/**
|
||||
* Returning a pixmap with non-NULL devPrivate.ptr implies a pixmap which is
|
||||
* not offscreen, which will never be accelerated and Prepare/FinishAccess won't
|
||||
* be called.
|
||||
*/
|
||||
Bool (*ModifyPixmapHeader) (PixmapPtr pPixmap, int width, int height,
|
||||
int depth, int bitsPerPixel, int devKind,
|
||||
void *pPixData);
|
||||
|
||||
/* hooks for drivers with tiling support:
|
||||
* driver MUST fill out new_fb_pitch with valid pitch of pixmap
|
||||
*/
|
||||
void *(*CreatePixmap2) (ScreenPtr pScreen, int width, int height,
|
||||
int depth, int usage_hint, int bitsPerPixel,
|
||||
int *new_fb_pitch);
|
||||
/** @} */
|
||||
Bool (*SharePixmapBacking)(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p);
|
||||
|
||||
Bool (*SetSharedPixmapBacking)(PixmapPtr pPixmap, void *handle);
|
||||
|
||||
} ExaDriverRec, *ExaDriverPtr;
|
||||
|
||||
/** @name EXA driver flags
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* EXA_OFFSCREEN_PIXMAPS indicates to EXA that the driver can support
|
||||
* offscreen pixmaps.
|
||||
*/
|
||||
#define EXA_OFFSCREEN_PIXMAPS (1 << 0)
|
||||
|
||||
/**
|
||||
* EXA_OFFSCREEN_ALIGN_POT indicates to EXA that the driver needs pixmaps
|
||||
* to have a power-of-two pitch.
|
||||
*/
|
||||
#define EXA_OFFSCREEN_ALIGN_POT (1 << 1)
|
||||
|
||||
/**
|
||||
* EXA_TWO_BITBLT_DIRECTIONS indicates to EXA that the driver can only
|
||||
* support copies that are (left-to-right, top-to-bottom) or
|
||||
* (right-to-left, bottom-to-top).
|
||||
*/
|
||||
#define EXA_TWO_BITBLT_DIRECTIONS (1 << 2)
|
||||
|
||||
/**
|
||||
* EXA_HANDLES_PIXMAPS indicates to EXA that the driver can handle
|
||||
* all pixmap addressing and migration.
|
||||
*/
|
||||
#define EXA_HANDLES_PIXMAPS (1 << 3)
|
||||
|
||||
/**
|
||||
* EXA_SUPPORTS_PREPARE_AUX indicates to EXA that the driver can handle the
|
||||
* EXA_PREPARE_AUX* indices in the Prepare/FinishAccess hooks. If there are no
|
||||
* such hooks, this flag has no effect.
|
||||
*/
|
||||
#define EXA_SUPPORTS_PREPARE_AUX (1 << 4)
|
||||
|
||||
/**
|
||||
* EXA_SUPPORTS_OFFSCREEN_OVERLAPS indicates to EXA that the driver Copy hooks
|
||||
* can handle the source and destination occupying overlapping offscreen memory
|
||||
* areas. This allows the offscreen memory defragmentation code to defragment
|
||||
* areas where the defragmented position overlaps the fragmented position.
|
||||
*
|
||||
* Typically this is supported by traditional 2D engines but not by 3D engines.
|
||||
*/
|
||||
#define EXA_SUPPORTS_OFFSCREEN_OVERLAPS (1 << 5)
|
||||
|
||||
/**
|
||||
* EXA_MIXED_PIXMAPS will hide unacceleratable pixmaps from drivers and manage the
|
||||
* problem known software fallbacks like trapezoids. This only migrates pixmaps one way
|
||||
* into a driver pixmap and then pins it.
|
||||
*/
|
||||
#define EXA_MIXED_PIXMAPS (1 << 6)
|
||||
|
||||
/** @} */
|
||||
|
||||
/* in exa.c */
|
||||
extern _X_EXPORT ExaDriverPtr exaDriverAlloc(void);
|
||||
|
||||
extern _X_EXPORT Bool
|
||||
exaDriverInit(ScreenPtr pScreen, ExaDriverPtr pScreenInfo);
|
||||
|
||||
extern _X_EXPORT void
|
||||
exaDriverFini(ScreenPtr pScreen);
|
||||
|
||||
extern _X_EXPORT void
|
||||
exaMarkSync(ScreenPtr pScreen);
|
||||
extern _X_EXPORT void
|
||||
exaWaitSync(ScreenPtr pScreen);
|
||||
|
||||
extern _X_EXPORT unsigned long
|
||||
exaGetPixmapOffset(PixmapPtr pPix);
|
||||
|
||||
extern _X_EXPORT unsigned long
|
||||
exaGetPixmapPitch(PixmapPtr pPix);
|
||||
|
||||
extern _X_EXPORT unsigned long
|
||||
exaGetPixmapSize(PixmapPtr pPix);
|
||||
|
||||
extern _X_EXPORT void *exaGetPixmapDriverPrivate(PixmapPtr p);
|
||||
|
||||
/* in exa_offscreen.c */
|
||||
extern _X_EXPORT ExaOffscreenArea *exaOffscreenAlloc(ScreenPtr pScreen,
|
||||
int size, int align,
|
||||
Bool locked,
|
||||
ExaOffscreenSaveProc save,
|
||||
void *privData);
|
||||
|
||||
extern _X_EXPORT ExaOffscreenArea *exaOffscreenFree(ScreenPtr pScreen,
|
||||
ExaOffscreenArea * area);
|
||||
|
||||
extern _X_EXPORT void
|
||||
ExaOffscreenMarkUsed(PixmapPtr pPixmap);
|
||||
|
||||
extern _X_EXPORT void
|
||||
exaEnableDisableFBAccess(ScreenPtr pScreen, Bool enable);
|
||||
|
||||
extern _X_EXPORT Bool
|
||||
exaDrawableIsOffscreen(DrawablePtr pDrawable);
|
||||
|
||||
/* in exa.c */
|
||||
extern _X_EXPORT void
|
||||
exaMoveInPixmap(PixmapPtr pPixmap);
|
||||
|
||||
extern _X_EXPORT void
|
||||
exaMoveOutPixmap(PixmapPtr pPixmap);
|
||||
|
||||
/* in exa_unaccel.c */
|
||||
extern _X_EXPORT CARD32
|
||||
exaGetPixmapFirstPixel(PixmapPtr pPixmap);
|
||||
|
||||
/**
|
||||
* Returns TRUE if the given planemask covers all the significant bits in the
|
||||
* pixel values for pDrawable.
|
||||
*/
|
||||
#define EXA_PM_IS_SOLID(_pDrawable, _pm) \
|
||||
(((_pm) & FbFullMask((_pDrawable)->depth)) == \
|
||||
FbFullMask((_pDrawable)->depth))
|
||||
|
||||
#endif /* EXA_H */
|
1297
exa/exa_accel.c
1297
exa/exa_accel.c
File diff suppressed because it is too large
Load Diff
|
@ -1,265 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2009 Maarten Maathuis
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "exa_priv.h"
|
||||
#include "exa.h"
|
||||
|
||||
/* This file holds the classic exa specific implementation. */
|
||||
|
||||
static _X_INLINE void *
|
||||
ExaGetPixmapAddress(PixmapPtr p)
|
||||
{
|
||||
ExaPixmapPriv(p);
|
||||
|
||||
if (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr)
|
||||
return pExaPixmap->fb_ptr;
|
||||
else
|
||||
return pExaPixmap->sys_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* exaCreatePixmap() creates a new pixmap.
|
||||
*
|
||||
* If width and height are 0, this won't be a full-fledged pixmap and it will
|
||||
* get ModifyPixmapHeader() called on it later. So, we mark it as pinned, because
|
||||
* ModifyPixmapHeader() would break migration. These types of pixmaps are used
|
||||
* for scratch pixmaps, or to represent the visible screen.
|
||||
*/
|
||||
PixmapPtr
|
||||
exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
|
||||
unsigned usage_hint)
|
||||
{
|
||||
PixmapPtr pPixmap;
|
||||
ExaPixmapPrivPtr pExaPixmap;
|
||||
BoxRec box;
|
||||
int bpp;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
if (w > 32767 || h > 32767)
|
||||
return NullPixmap;
|
||||
|
||||
swap(pExaScr, pScreen, CreatePixmap);
|
||||
pPixmap = pScreen->CreatePixmap(pScreen, w, h, depth, usage_hint);
|
||||
swap(pExaScr, pScreen, CreatePixmap);
|
||||
|
||||
if (!pPixmap)
|
||||
return NULL;
|
||||
|
||||
pExaPixmap = ExaGetPixmapPriv(pPixmap);
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
|
||||
bpp = pPixmap->drawable.bitsPerPixel;
|
||||
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
/* Scratch pixmaps may have w/h equal to zero, and may not be
|
||||
* migrated.
|
||||
*/
|
||||
if (!w || !h)
|
||||
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
|
||||
else
|
||||
pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
|
||||
|
||||
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
|
||||
pExaPixmap->sys_pitch = pPixmap->devKind;
|
||||
|
||||
pPixmap->devPrivate.ptr = NULL;
|
||||
pExaPixmap->use_gpu_copy = FALSE;
|
||||
|
||||
pExaPixmap->fb_ptr = NULL;
|
||||
exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
|
||||
pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;
|
||||
|
||||
if (pExaPixmap->fb_pitch > 131071) {
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
pScreen->DestroyPixmap(pPixmap);
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set up damage tracking */
|
||||
pExaPixmap->pDamage = DamageCreate(NULL, NULL,
|
||||
DamageReportNone, TRUE,
|
||||
pScreen, pPixmap);
|
||||
|
||||
if (pExaPixmap->pDamage == NULL) {
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
pScreen->DestroyPixmap(pPixmap);
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
|
||||
/* This ensures that pending damage reflects the current operation. */
|
||||
/* This is used by exa to optimize migration. */
|
||||
DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
|
||||
|
||||
pExaPixmap->area = NULL;
|
||||
|
||||
/* We set the initial pixmap as completely valid for a simple reason.
|
||||
* Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which
|
||||
* could form single pixel rects as part of a region. Setting the complete region
|
||||
* as valid is a natural defragmentation of the region.
|
||||
*/
|
||||
box.x1 = 0;
|
||||
box.y1 = 0;
|
||||
box.x2 = w;
|
||||
box.y2 = h;
|
||||
RegionInit(&pExaPixmap->validSys, &box, 0);
|
||||
RegionInit(&pExaPixmap->validFB, &box, 0);
|
||||
|
||||
exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
|
||||
|
||||
/* During a fallback we must prepare access. */
|
||||
if (pExaScr->fallback_counter)
|
||||
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
|
||||
|
||||
return pPixmap;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height,
|
||||
int depth, int bitsPerPixel, int devKind,
|
||||
void *pPixData)
|
||||
{
|
||||
ScreenPtr pScreen;
|
||||
ExaScreenPrivPtr pExaScr;
|
||||
ExaPixmapPrivPtr pExaPixmap;
|
||||
Bool ret;
|
||||
|
||||
if (!pPixmap)
|
||||
return FALSE;
|
||||
|
||||
pScreen = pPixmap->drawable.pScreen;
|
||||
pExaScr = ExaGetScreenPriv(pScreen);
|
||||
pExaPixmap = ExaGetPixmapPriv(pPixmap);
|
||||
|
||||
if (pExaPixmap) {
|
||||
if (pPixData)
|
||||
pExaPixmap->sys_ptr = pPixData;
|
||||
|
||||
if (devKind > 0)
|
||||
pExaPixmap->sys_pitch = devKind;
|
||||
|
||||
/* Classic EXA:
|
||||
* - Framebuffer.
|
||||
* - Scratch pixmap with gpu memory.
|
||||
*/
|
||||
if (pExaScr->info->memoryBase && pPixData) {
|
||||
if ((CARD8 *) pPixData >= pExaScr->info->memoryBase &&
|
||||
((CARD8 *) pPixData - pExaScr->info->memoryBase) <
|
||||
pExaScr->info->memorySize) {
|
||||
pExaPixmap->fb_ptr = pPixData;
|
||||
pExaPixmap->fb_pitch = devKind;
|
||||
pExaPixmap->use_gpu_copy = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (width > 0 && height > 0 && bitsPerPixel > 0) {
|
||||
exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
|
||||
|
||||
exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
|
||||
}
|
||||
|
||||
/* Pixmaps subject to ModifyPixmapHeader will be pinned to system or
|
||||
* gpu memory, so there's no need to track damage.
|
||||
*/
|
||||
if (pExaPixmap->pDamage) {
|
||||
DamageDestroy(pExaPixmap->pDamage);
|
||||
pExaPixmap->pDamage = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
swap(pExaScr, pScreen, ModifyPixmapHeader);
|
||||
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
|
||||
bitsPerPixel, devKind, pPixData);
|
||||
swap(pExaScr, pScreen, ModifyPixmapHeader);
|
||||
|
||||
/* Always NULL this, we don't want lingering pointers. */
|
||||
pPixmap->devPrivate.ptr = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaDestroyPixmap_classic(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
Bool ret;
|
||||
|
||||
if (pPixmap->refcnt == 1) {
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
exaDestroyPixmap(pPixmap);
|
||||
|
||||
if (pExaPixmap->area) {
|
||||
DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
|
||||
(void *) pPixmap->drawable.id,
|
||||
ExaGetPixmapPriv(pPixmap)->area->offset,
|
||||
pPixmap->drawable.width, pPixmap->drawable.height));
|
||||
/* Free the offscreen area */
|
||||
exaOffscreenFree(pPixmap->drawable.pScreen, pExaPixmap->area);
|
||||
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
|
||||
pPixmap->devKind = pExaPixmap->sys_pitch;
|
||||
}
|
||||
RegionUninit(&pExaPixmap->validSys);
|
||||
RegionUninit(&pExaPixmap->validFB);
|
||||
}
|
||||
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
ret = pScreen->DestroyPixmap(pPixmap);
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaPixmapPriv(pPixmap);
|
||||
Bool ret;
|
||||
|
||||
if (pExaScr->info->PixmapIsOffscreen) {
|
||||
void *old_ptr = pPixmap->devPrivate.ptr;
|
||||
|
||||
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
|
||||
ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
|
||||
pPixmap->devPrivate.ptr = old_ptr;
|
||||
}
|
||||
else
|
||||
ret = (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr);
|
||||
|
||||
return ret;
|
||||
}
|
230
exa/exa_driver.c
230
exa/exa_driver.c
|
@ -1,230 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2009 Maarten Maathuis
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "exa_priv.h"
|
||||
#include "exa.h"
|
||||
|
||||
/* This file holds the driver allocated pixmaps specific implementation. */
|
||||
|
||||
static _X_INLINE void *
|
||||
ExaGetPixmapAddress(PixmapPtr p)
|
||||
{
|
||||
ExaPixmapPriv(p);
|
||||
|
||||
return pExaPixmap->sys_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* exaCreatePixmap() creates a new pixmap.
|
||||
*
|
||||
* Pixmaps are always marked as pinned, because exa has no control over them.
|
||||
*/
|
||||
PixmapPtr
|
||||
exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
|
||||
unsigned usage_hint)
|
||||
{
|
||||
PixmapPtr pPixmap;
|
||||
ExaPixmapPrivPtr pExaPixmap;
|
||||
int bpp;
|
||||
size_t paddedWidth, datasize;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
if (w > 32767 || h > 32767)
|
||||
return NullPixmap;
|
||||
|
||||
swap(pExaScr, pScreen, CreatePixmap);
|
||||
pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
|
||||
swap(pExaScr, pScreen, CreatePixmap);
|
||||
|
||||
if (!pPixmap)
|
||||
return NULL;
|
||||
|
||||
pExaPixmap = ExaGetPixmapPriv(pPixmap);
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
|
||||
bpp = pPixmap->drawable.bitsPerPixel;
|
||||
|
||||
/* Set this before driver hooks, to allow for driver pixmaps without gpu
|
||||
* memory to back it. These pixmaps have a valid pointer at all times.
|
||||
*/
|
||||
pPixmap->devPrivate.ptr = NULL;
|
||||
|
||||
if (pExaScr->info->CreatePixmap2) {
|
||||
int new_pitch = 0;
|
||||
|
||||
pExaPixmap->driverPriv =
|
||||
pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp,
|
||||
&new_pitch);
|
||||
paddedWidth = pExaPixmap->fb_pitch = new_pitch;
|
||||
}
|
||||
else {
|
||||
paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
|
||||
if (paddedWidth / 4 > 32767 || h > 32767)
|
||||
return NullPixmap;
|
||||
|
||||
exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
|
||||
|
||||
if (paddedWidth < pExaPixmap->fb_pitch)
|
||||
paddedWidth = pExaPixmap->fb_pitch;
|
||||
datasize = h * paddedWidth;
|
||||
pExaPixmap->driverPriv =
|
||||
pExaScr->info->CreatePixmap(pScreen, datasize, 0);
|
||||
}
|
||||
|
||||
if (!pExaPixmap->driverPriv) {
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
pScreen->DestroyPixmap(pPixmap);
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allow ModifyPixmapHeader to set sys_ptr appropriately. */
|
||||
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
|
||||
pExaPixmap->fb_ptr = NULL;
|
||||
pExaPixmap->pDamage = NULL;
|
||||
pExaPixmap->sys_ptr = NULL;
|
||||
|
||||
(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
|
||||
|
||||
pExaPixmap->area = NULL;
|
||||
|
||||
exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
|
||||
|
||||
pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
|
||||
|
||||
/* During a fallback we must prepare access. */
|
||||
if (pExaScr->fallback_counter)
|
||||
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
|
||||
|
||||
return pPixmap;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height,
|
||||
int depth, int bitsPerPixel, int devKind,
|
||||
void *pPixData)
|
||||
{
|
||||
ScreenPtr pScreen;
|
||||
ExaScreenPrivPtr pExaScr;
|
||||
ExaPixmapPrivPtr pExaPixmap;
|
||||
Bool ret;
|
||||
|
||||
if (!pPixmap)
|
||||
return FALSE;
|
||||
|
||||
pScreen = pPixmap->drawable.pScreen;
|
||||
pExaScr = ExaGetScreenPriv(pScreen);
|
||||
pExaPixmap = ExaGetPixmapPriv(pPixmap);
|
||||
|
||||
if (pExaPixmap) {
|
||||
if (pPixData)
|
||||
pExaPixmap->sys_ptr = pPixData;
|
||||
|
||||
if (devKind > 0)
|
||||
pExaPixmap->sys_pitch = devKind;
|
||||
|
||||
if (width > 0 && height > 0 && bitsPerPixel > 0) {
|
||||
exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
|
||||
|
||||
exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
if (pExaScr->info->ModifyPixmapHeader) {
|
||||
ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
|
||||
bitsPerPixel, devKind,
|
||||
pPixData);
|
||||
/* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL.
|
||||
* If pPixmap->devPrivate.ptr is non-NULL, then we've got a
|
||||
* !has_gpu_copy pixmap. We need to store the pointer,
|
||||
* because PrepareAccess won't be called.
|
||||
*/
|
||||
if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) {
|
||||
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
|
||||
pExaPixmap->sys_pitch = pPixmap->devKind;
|
||||
}
|
||||
if (ret == TRUE)
|
||||
goto out;
|
||||
}
|
||||
|
||||
swap(pExaScr, pScreen, ModifyPixmapHeader);
|
||||
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
|
||||
bitsPerPixel, devKind, pPixData);
|
||||
swap(pExaScr, pScreen, ModifyPixmapHeader);
|
||||
|
||||
out:
|
||||
/* Always NULL this, we don't want lingering pointers. */
|
||||
pPixmap->devPrivate.ptr = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaDestroyPixmap_driver(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
Bool ret;
|
||||
|
||||
if (pPixmap->refcnt == 1) {
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
exaDestroyPixmap(pPixmap);
|
||||
|
||||
if (pExaPixmap->driverPriv)
|
||||
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
}
|
||||
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
ret = pScreen->DestroyPixmap(pPixmap);
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
void *saved_ptr;
|
||||
Bool ret;
|
||||
|
||||
saved_ptr = pPixmap->devPrivate.ptr;
|
||||
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
|
||||
ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
|
||||
pPixmap->devPrivate.ptr = saved_ptr;
|
||||
|
||||
return ret;
|
||||
}
|
839
exa/exa_glyphs.c
839
exa/exa_glyphs.c
|
@ -1,839 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2008 Red Hat, Inc.
|
||||
* Partly based on code Copyright © 2000 SuSE, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of Red Hat not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. Red Hat makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as is"
|
||||
* without express or implied warranty.
|
||||
*
|
||||
* Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
|
||||
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of SuSE not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. SuSE makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as is"
|
||||
* without express or implied warranty.
|
||||
*
|
||||
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
|
||||
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Owen Taylor <otaylor@fishsoup.net>
|
||||
* Based on code by: Keith Packard
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "exa_priv.h"
|
||||
|
||||
#include "mipict.h"
|
||||
|
||||
#if DEBUG_GLYPH_CACHE
|
||||
#define DBG_GLYPH_CACHE(a) ErrorF a
|
||||
#else
|
||||
#define DBG_GLYPH_CACHE(a)
|
||||
#endif
|
||||
|
||||
/* Width of the pixmaps we use for the caches; this should be less than
|
||||
* max texture size of the driver; this may need to actually come from
|
||||
* the driver.
|
||||
*/
|
||||
#define CACHE_PICTURE_WIDTH 1024
|
||||
|
||||
/* Maximum number of glyphs we buffer on the stack before flushing
|
||||
* rendering to the mask or destination surface.
|
||||
*/
|
||||
#define GLYPH_BUFFER_SIZE 256
|
||||
|
||||
typedef struct {
|
||||
PicturePtr mask;
|
||||
ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE];
|
||||
int count;
|
||||
} ExaGlyphBuffer, *ExaGlyphBufferPtr;
|
||||
|
||||
typedef enum {
|
||||
ExaGlyphSuccess, /* Glyph added to render buffer */
|
||||
ExaGlyphFail, /* out of memory, etc */
|
||||
ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */
|
||||
} ExaGlyphCacheResult;
|
||||
|
||||
void
|
||||
exaGlyphsInit(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
int i = 0;
|
||||
|
||||
memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches));
|
||||
|
||||
pExaScr->glyphCaches[i].format = PICT_a8;
|
||||
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
|
||||
16;
|
||||
i++;
|
||||
pExaScr->glyphCaches[i].format = PICT_a8;
|
||||
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
|
||||
32;
|
||||
i++;
|
||||
pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
|
||||
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
|
||||
16;
|
||||
i++;
|
||||
pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
|
||||
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
|
||||
32;
|
||||
i++;
|
||||
|
||||
assert(i == EXA_NUM_GLYPH_CACHES);
|
||||
|
||||
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
|
||||
pExaScr->glyphCaches[i].columns =
|
||||
CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth;
|
||||
pExaScr->glyphCaches[i].size = 256;
|
||||
pExaScr->glyphCaches[i].hashSize = 557;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
exaUnrealizeGlyphCaches(ScreenPtr pScreen, unsigned int format)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
|
||||
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
|
||||
|
||||
if (cache->format != format)
|
||||
continue;
|
||||
|
||||
if (cache->picture) {
|
||||
FreePicture((void *) cache->picture, (XID) 0);
|
||||
cache->picture = NULL;
|
||||
}
|
||||
|
||||
free(cache->hashEntries);
|
||||
cache->hashEntries = NULL;
|
||||
|
||||
free(cache->glyphs);
|
||||
cache->glyphs = NULL;
|
||||
cache->glyphCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
|
||||
|
||||
/* All caches for a single format share a single pixmap for glyph storage,
|
||||
* allowing mixing glyphs of different sizes without paying a penalty
|
||||
* for switching between mask pixmaps. (Note that for a size of font
|
||||
* right at the border between two sizes, we might be switching for almost
|
||||
* every glyph.)
|
||||
*
|
||||
* This function allocates the storage pixmap, and then fills in the
|
||||
* rest of the allocated structures for all caches with the given format.
|
||||
*/
|
||||
static Bool
|
||||
exaRealizeGlyphCaches(ScreenPtr pScreen, unsigned int format)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
int depth = PIXMAN_FORMAT_DEPTH(format);
|
||||
PictFormatPtr pPictFormat;
|
||||
PixmapPtr pPixmap;
|
||||
PicturePtr pPicture;
|
||||
CARD32 component_alpha;
|
||||
int height;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
pPictFormat = PictureMatchFormat(pScreen, depth, format);
|
||||
if (!pPictFormat)
|
||||
return FALSE;
|
||||
|
||||
/* Compute the total vertical size needed for the format */
|
||||
|
||||
height = 0;
|
||||
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
|
||||
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
|
||||
int rows;
|
||||
|
||||
if (cache->format != format)
|
||||
continue;
|
||||
|
||||
cache->yOffset = height;
|
||||
|
||||
rows = (cache->size + cache->columns - 1) / cache->columns;
|
||||
height += rows * cache->glyphHeight;
|
||||
}
|
||||
|
||||
/* Now allocate the pixmap and picture */
|
||||
pPixmap = (*pScreen->CreatePixmap) (pScreen,
|
||||
CACHE_PICTURE_WIDTH, height, depth, 0);
|
||||
if (!pPixmap)
|
||||
return FALSE;
|
||||
|
||||
component_alpha = NeedsComponent(pPictFormat->format);
|
||||
pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
|
||||
CPComponentAlpha, &component_alpha, serverClient,
|
||||
&error);
|
||||
|
||||
(*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */
|
||||
|
||||
if (!pPicture)
|
||||
return FALSE;
|
||||
|
||||
/* And store the picture in all the caches for the format */
|
||||
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
|
||||
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
|
||||
int j;
|
||||
|
||||
if (cache->format != format)
|
||||
continue;
|
||||
|
||||
cache->picture = pPicture;
|
||||
cache->picture->refcnt++;
|
||||
cache->hashEntries = xallocarray(cache->hashSize, sizeof(int));
|
||||
cache->glyphs = xallocarray(cache->size, sizeof(ExaCachedGlyphRec));
|
||||
cache->glyphCount = 0;
|
||||
|
||||
if (!cache->hashEntries || !cache->glyphs)
|
||||
goto bail;
|
||||
|
||||
for (j = 0; j < cache->hashSize; j++)
|
||||
cache->hashEntries[j] = -1;
|
||||
|
||||
cache->evictionPosition = rand() % cache->size;
|
||||
}
|
||||
|
||||
/* Each cache references the picture individually */
|
||||
FreePicture((void *) pPicture, (XID) 0);
|
||||
return TRUE;
|
||||
|
||||
bail:
|
||||
exaUnrealizeGlyphCaches(pScreen, format);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
exaGlyphsFini(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
|
||||
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
|
||||
|
||||
if (cache->picture)
|
||||
exaUnrealizeGlyphCaches(pScreen, cache->format);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, GlyphPtr pGlyph)
|
||||
{
|
||||
int slot;
|
||||
|
||||
slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
|
||||
|
||||
while (TRUE) { /* hash table can never be full */
|
||||
int entryPos = cache->hashEntries[slot];
|
||||
|
||||
if (entryPos == -1)
|
||||
return -1;
|
||||
|
||||
if (memcmp
|
||||
(pGlyph->sha1, cache->glyphs[entryPos].sha1,
|
||||
sizeof(pGlyph->sha1)) == 0) {
|
||||
return entryPos;
|
||||
}
|
||||
|
||||
slot--;
|
||||
if (slot < 0)
|
||||
slot = cache->hashSize - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, GlyphPtr pGlyph, int pos)
|
||||
{
|
||||
int slot;
|
||||
|
||||
memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1));
|
||||
|
||||
slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
|
||||
|
||||
while (TRUE) { /* hash table can never be full */
|
||||
if (cache->hashEntries[slot] == -1) {
|
||||
cache->hashEntries[slot] = pos;
|
||||
return;
|
||||
}
|
||||
|
||||
slot--;
|
||||
if (slot < 0)
|
||||
slot = cache->hashSize - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, int pos)
|
||||
{
|
||||
int slot;
|
||||
int emptiedSlot = -1;
|
||||
|
||||
slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize;
|
||||
|
||||
while (TRUE) { /* hash table can never be full */
|
||||
int entryPos = cache->hashEntries[slot];
|
||||
|
||||
if (entryPos == -1)
|
||||
return;
|
||||
|
||||
if (entryPos == pos) {
|
||||
cache->hashEntries[slot] = -1;
|
||||
emptiedSlot = slot;
|
||||
}
|
||||
else if (emptiedSlot != -1) {
|
||||
/* See if we can move this entry into the emptied slot, we can't
|
||||
* do that if if entry would have hashed between the current position
|
||||
* and the emptied slot. (taking wrapping into account). Bad positions
|
||||
* are:
|
||||
*
|
||||
* | XXXXXXXXXX |
|
||||
* i j
|
||||
*
|
||||
* |XXX XXXX|
|
||||
* j i
|
||||
*
|
||||
* i - slot, j - emptiedSlot
|
||||
*
|
||||
* (Knuth 6.4R)
|
||||
*/
|
||||
|
||||
int entrySlot =
|
||||
(*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize;
|
||||
|
||||
if (!((entrySlot >= slot && entrySlot < emptiedSlot) ||
|
||||
(emptiedSlot < slot &&
|
||||
(entrySlot < emptiedSlot || entrySlot >= slot)))) {
|
||||
cache->hashEntries[emptiedSlot] = entryPos;
|
||||
cache->hashEntries[slot] = -1;
|
||||
emptiedSlot = slot;
|
||||
}
|
||||
}
|
||||
|
||||
slot--;
|
||||
if (slot < 0)
|
||||
slot = cache->hashSize - 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth)
|
||||
#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight)
|
||||
|
||||
/* The most efficient thing to way to upload the glyph to the screen
|
||||
* is to use the UploadToScreen() driver hook; this allows us to
|
||||
* pipeline glyph uploads and to avoid creating gpu backed pixmaps for
|
||||
* glyphs that we'll never use again.
|
||||
*
|
||||
* If we can't do it with UploadToScreen (because the glyph has a gpu copy,
|
||||
* etc), we fall back to CompositePicture.
|
||||
*
|
||||
* We need to damage the cache pixmap manually in either case because the damage
|
||||
* layer unwrapped the picture screen before calling exaGlyphs.
|
||||
*/
|
||||
static void
|
||||
exaGlyphCacheUploadGlyph(ScreenPtr pScreen,
|
||||
ExaGlyphCachePtr cache, int x, int y, GlyphPtr pGlyph)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
PicturePtr pGlyphPicture = GetGlyphPicture(pGlyph, pScreen);
|
||||
PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
|
||||
|
||||
ExaPixmapPriv(pGlyphPixmap);
|
||||
PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
|
||||
|
||||
if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut ||
|
||||
pExaPixmap->accel_blocked)
|
||||
goto composite;
|
||||
|
||||
/* If the glyph pixmap is already uploaded, no point in doing
|
||||
* things this way */
|
||||
if (exaPixmapHasGpuCopy(pGlyphPixmap))
|
||||
goto composite;
|
||||
|
||||
/* UploadToScreen only works if bpp match */
|
||||
if (pGlyphPixmap->drawable.bitsPerPixel !=
|
||||
pCachePixmap->drawable.bitsPerPixel)
|
||||
goto composite;
|
||||
|
||||
if (pExaScr->do_migration) {
|
||||
ExaMigrationRec pixmaps[1];
|
||||
|
||||
/* cache pixmap must have a gpu copy. */
|
||||
pixmaps[0].as_dst = TRUE;
|
||||
pixmaps[0].as_src = FALSE;
|
||||
pixmaps[0].pPix = pCachePixmap;
|
||||
pixmaps[0].pReg = NULL;
|
||||
exaDoMigration(pixmaps, 1, TRUE);
|
||||
}
|
||||
|
||||
if (!exaPixmapHasGpuCopy(pCachePixmap))
|
||||
goto composite;
|
||||
|
||||
/* x,y are in pixmap coordinates, no need for cache{X,Y}off */
|
||||
if (pExaScr->info->UploadToScreen(pCachePixmap,
|
||||
x,
|
||||
y,
|
||||
pGlyph->info.width,
|
||||
pGlyph->info.height,
|
||||
(char *) pExaPixmap->sys_ptr,
|
||||
pExaPixmap->sys_pitch))
|
||||
goto damage;
|
||||
|
||||
composite:
|
||||
CompositePicture(PictOpSrc,
|
||||
pGlyphPicture,
|
||||
None,
|
||||
cache->picture,
|
||||
0, 0, 0, 0, x, y, pGlyph->info.width, pGlyph->info.height);
|
||||
|
||||
damage:
|
||||
/* The cache pixmap isn't a window, so no need to offset coordinates. */
|
||||
exaPixmapDirty(pCachePixmap,
|
||||
x, y, x + cache->glyphWidth, y + cache->glyphHeight);
|
||||
}
|
||||
|
||||
static ExaGlyphCacheResult
|
||||
exaGlyphCacheBufferGlyph(ScreenPtr pScreen,
|
||||
ExaGlyphCachePtr cache,
|
||||
ExaGlyphBufferPtr buffer,
|
||||
GlyphPtr pGlyph,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pDst,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc,
|
||||
INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst)
|
||||
{
|
||||
ExaCompositeRectPtr rect;
|
||||
int pos;
|
||||
int x, y;
|
||||
|
||||
if (buffer->mask && buffer->mask != cache->picture)
|
||||
return ExaGlyphNeedFlush;
|
||||
|
||||
if (!cache->picture) {
|
||||
if (!exaRealizeGlyphCaches(pScreen, cache->format))
|
||||
return ExaGlyphFail;
|
||||
}
|
||||
|
||||
DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n",
|
||||
cache->glyphWidth, cache->glyphHeight,
|
||||
cache->format == PICT_a8 ? "A" : "ARGB",
|
||||
(long) *(CARD32 *) pGlyph->sha1));
|
||||
|
||||
pos = exaGlyphCacheHashLookup(cache, pGlyph);
|
||||
if (pos != -1) {
|
||||
DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos));
|
||||
x = CACHE_X(pos);
|
||||
y = CACHE_Y(pos);
|
||||
}
|
||||
else {
|
||||
if (cache->glyphCount < cache->size) {
|
||||
/* Space remaining; we fill from the start */
|
||||
pos = cache->glyphCount;
|
||||
x = CACHE_X(pos);
|
||||
y = CACHE_Y(pos);
|
||||
cache->glyphCount++;
|
||||
DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos));
|
||||
|
||||
exaGlyphCacheHashInsert(cache, pGlyph, pos);
|
||||
|
||||
}
|
||||
else {
|
||||
/* Need to evict an entry. We have to see if any glyphs
|
||||
* already in the output buffer were at this position in
|
||||
* the cache
|
||||
*/
|
||||
pos = cache->evictionPosition;
|
||||
x = CACHE_X(pos);
|
||||
y = CACHE_Y(pos);
|
||||
DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos));
|
||||
if (buffer->count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < buffer->count; i++) {
|
||||
if (pSrc ?
|
||||
(buffer->rects[i].xMask == x &&
|
||||
buffer->rects[i].yMask ==
|
||||
y) : (buffer->rects[i].xSrc == x &&
|
||||
buffer->rects[i].ySrc == y)) {
|
||||
DBG_GLYPH_CACHE((" must flush buffer\n"));
|
||||
return ExaGlyphNeedFlush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* OK, we're all set, swap in the new glyph */
|
||||
exaGlyphCacheHashRemove(cache, pos);
|
||||
exaGlyphCacheHashInsert(cache, pGlyph, pos);
|
||||
|
||||
/* And pick a new eviction position */
|
||||
cache->evictionPosition = rand() % cache->size;
|
||||
}
|
||||
|
||||
exaGlyphCacheUploadGlyph(pScreen, cache, x, y, pGlyph);
|
||||
}
|
||||
|
||||
buffer->mask = cache->picture;
|
||||
|
||||
rect = &buffer->rects[buffer->count];
|
||||
|
||||
if (pSrc) {
|
||||
rect->xSrc = xSrc;
|
||||
rect->ySrc = ySrc;
|
||||
rect->xMask = x;
|
||||
rect->yMask = y;
|
||||
}
|
||||
else {
|
||||
rect->xSrc = x;
|
||||
rect->ySrc = y;
|
||||
rect->xMask = 0;
|
||||
rect->yMask = 0;
|
||||
}
|
||||
|
||||
rect->pDst = pDst;
|
||||
rect->xDst = xDst;
|
||||
rect->yDst = yDst;
|
||||
rect->width = pGlyph->info.width;
|
||||
rect->height = pGlyph->info.height;
|
||||
|
||||
buffer->count++;
|
||||
|
||||
return ExaGlyphSuccess;
|
||||
}
|
||||
|
||||
#undef CACHE_X
|
||||
#undef CACHE_Y
|
||||
|
||||
static ExaGlyphCacheResult
|
||||
exaBufferGlyph(ScreenPtr pScreen,
|
||||
ExaGlyphBufferPtr buffer,
|
||||
GlyphPtr pGlyph,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pDst,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
unsigned int format = (GetGlyphPicture(pGlyph, pScreen))->format;
|
||||
int width = pGlyph->info.width;
|
||||
int height = pGlyph->info.height;
|
||||
ExaCompositeRectPtr rect;
|
||||
PicturePtr mask;
|
||||
int i;
|
||||
|
||||
if (buffer->count == GLYPH_BUFFER_SIZE)
|
||||
return ExaGlyphNeedFlush;
|
||||
|
||||
if (PICT_FORMAT_BPP(format) == 1)
|
||||
format = PICT_a8;
|
||||
|
||||
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
|
||||
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
|
||||
|
||||
if (format == cache->format &&
|
||||
width <= cache->glyphWidth && height <= cache->glyphHeight) {
|
||||
ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen,
|
||||
&pExaScr->
|
||||
glyphCaches
|
||||
[i],
|
||||
buffer,
|
||||
pGlyph,
|
||||
pSrc,
|
||||
pDst,
|
||||
xSrc, ySrc,
|
||||
xMask, yMask,
|
||||
xDst, yDst);
|
||||
|
||||
switch (result) {
|
||||
case ExaGlyphFail:
|
||||
break;
|
||||
case ExaGlyphSuccess:
|
||||
case ExaGlyphNeedFlush:
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Couldn't find the glyph in the cache, use the glyph picture directly */
|
||||
|
||||
mask = GetGlyphPicture(pGlyph, pScreen);
|
||||
if (buffer->mask && buffer->mask != mask)
|
||||
return ExaGlyphNeedFlush;
|
||||
|
||||
buffer->mask = mask;
|
||||
|
||||
rect = &buffer->rects[buffer->count];
|
||||
rect->xSrc = xSrc;
|
||||
rect->ySrc = ySrc;
|
||||
rect->xMask = xMask;
|
||||
rect->yMask = yMask;
|
||||
rect->xDst = xDst;
|
||||
rect->yDst = yDst;
|
||||
rect->width = width;
|
||||
rect->height = height;
|
||||
|
||||
buffer->count++;
|
||||
|
||||
return ExaGlyphSuccess;
|
||||
}
|
||||
|
||||
static void
|
||||
exaGlyphsToMask(PicturePtr pMask, ExaGlyphBufferPtr buffer)
|
||||
{
|
||||
exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask,
|
||||
buffer->count, buffer->rects);
|
||||
|
||||
buffer->count = 0;
|
||||
buffer->mask = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
exaGlyphsToDst(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ExaGlyphBufferPtr buffer)
|
||||
{
|
||||
exaCompositeRects(op, pSrc, buffer->mask, pDst, buffer->count,
|
||||
buffer->rects);
|
||||
|
||||
buffer->count = 0;
|
||||
buffer->mask = NULL;
|
||||
}
|
||||
|
||||
/* Cut and paste from render/glyph.c - probably should export it instead */
|
||||
static void
|
||||
GlyphExtents(int nlist, GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents)
|
||||
{
|
||||
int x1, x2, y1, y2;
|
||||
int n;
|
||||
GlyphPtr glyph;
|
||||
int x, y;
|
||||
|
||||
x = 0;
|
||||
y = 0;
|
||||
extents->x1 = MAXSHORT;
|
||||
extents->x2 = MINSHORT;
|
||||
extents->y1 = MAXSHORT;
|
||||
extents->y2 = MINSHORT;
|
||||
while (nlist--) {
|
||||
x += list->xOff;
|
||||
y += list->yOff;
|
||||
n = list->len;
|
||||
list++;
|
||||
while (n--) {
|
||||
glyph = *glyphs++;
|
||||
x1 = x - glyph->info.x;
|
||||
if (x1 < MINSHORT)
|
||||
x1 = MINSHORT;
|
||||
y1 = y - glyph->info.y;
|
||||
if (y1 < MINSHORT)
|
||||
y1 = MINSHORT;
|
||||
x2 = x1 + glyph->info.width;
|
||||
if (x2 > MAXSHORT)
|
||||
x2 = MAXSHORT;
|
||||
y2 = y1 + glyph->info.height;
|
||||
if (y2 > MAXSHORT)
|
||||
y2 = MAXSHORT;
|
||||
if (x1 < extents->x1)
|
||||
extents->x1 = x1;
|
||||
if (x2 > extents->x2)
|
||||
extents->x2 = x2;
|
||||
if (y1 < extents->y1)
|
||||
extents->y1 = y1;
|
||||
if (y2 > extents->y2)
|
||||
extents->y2 = y2;
|
||||
x += glyph->info.xOff;
|
||||
y += glyph->info.yOff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
exaGlyphs(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pDst,
|
||||
PictFormatPtr maskFormat,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
|
||||
{
|
||||
PixmapPtr pMaskPixmap = 0;
|
||||
PicturePtr pMask = NULL;
|
||||
ScreenPtr pScreen = pDst->pDrawable->pScreen;
|
||||
int width = 0, height = 0;
|
||||
int x, y;
|
||||
int first_xOff = list->xOff, first_yOff = list->yOff;
|
||||
int n;
|
||||
GlyphPtr glyph;
|
||||
int error;
|
||||
BoxRec extents = { 0, 0, 0, 0 };
|
||||
CARD32 component_alpha;
|
||||
ExaGlyphBuffer buffer;
|
||||
|
||||
if (maskFormat) {
|
||||
ExaScreenPriv(pScreen);
|
||||
GCPtr pGC;
|
||||
xRectangle rect;
|
||||
|
||||
GlyphExtents(nlist, list, glyphs, &extents);
|
||||
|
||||
if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
|
||||
return;
|
||||
width = extents.x2 - extents.x1;
|
||||
height = extents.y2 - extents.y1;
|
||||
|
||||
if (maskFormat->depth == 1) {
|
||||
PictFormatPtr a8Format = PictureMatchFormat(pScreen, 8, PICT_a8);
|
||||
|
||||
if (a8Format)
|
||||
maskFormat = a8Format;
|
||||
}
|
||||
|
||||
pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
|
||||
maskFormat->depth,
|
||||
CREATE_PIXMAP_USAGE_SCRATCH);
|
||||
if (!pMaskPixmap)
|
||||
return;
|
||||
component_alpha = NeedsComponent(maskFormat->format);
|
||||
pMask = CreatePicture(0, &pMaskPixmap->drawable,
|
||||
maskFormat, CPComponentAlpha, &component_alpha,
|
||||
serverClient, &error);
|
||||
if (!pMask ||
|
||||
(!component_alpha && pExaScr->info->CheckComposite &&
|
||||
!(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask)))
|
||||
{
|
||||
PictFormatPtr argbFormat;
|
||||
|
||||
(*pScreen->DestroyPixmap) (pMaskPixmap);
|
||||
|
||||
if (!pMask)
|
||||
return;
|
||||
|
||||
/* The driver can't seem to composite to a8, let's try argb (but
|
||||
* without component-alpha) */
|
||||
FreePicture((void *) pMask, (XID) 0);
|
||||
|
||||
argbFormat = PictureMatchFormat(pScreen, 32, PICT_a8r8g8b8);
|
||||
|
||||
if (argbFormat)
|
||||
maskFormat = argbFormat;
|
||||
|
||||
pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
|
||||
maskFormat->depth,
|
||||
CREATE_PIXMAP_USAGE_SCRATCH);
|
||||
if (!pMaskPixmap)
|
||||
return;
|
||||
|
||||
pMask = CreatePicture(0, &pMaskPixmap->drawable, maskFormat, 0, 0,
|
||||
serverClient, &error);
|
||||
if (!pMask) {
|
||||
(*pScreen->DestroyPixmap) (pMaskPixmap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pGC = GetScratchGC(pMaskPixmap->drawable.depth, pScreen);
|
||||
ValidateGC(&pMaskPixmap->drawable, pGC);
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = width;
|
||||
rect.height = height;
|
||||
(*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
|
||||
FreeScratchGC(pGC);
|
||||
x = -extents.x1;
|
||||
y = -extents.y1;
|
||||
}
|
||||
else {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
buffer.count = 0;
|
||||
buffer.mask = NULL;
|
||||
while (nlist--) {
|
||||
x += list->xOff;
|
||||
y += list->yOff;
|
||||
n = list->len;
|
||||
while (n--) {
|
||||
glyph = *glyphs++;
|
||||
|
||||
if (glyph->info.width > 0 && glyph->info.height > 0) {
|
||||
/* pGlyph->info.{x,y} compensate for empty space in the glyph. */
|
||||
if (maskFormat) {
|
||||
if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
|
||||
0, 0, 0, 0, x - glyph->info.x,
|
||||
y - glyph->info.y) ==
|
||||
ExaGlyphNeedFlush) {
|
||||
exaGlyphsToMask(pMask, &buffer);
|
||||
exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
|
||||
0, 0, 0, 0, x - glyph->info.x,
|
||||
y - glyph->info.y);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
|
||||
xSrc + (x - glyph->info.x) - first_xOff,
|
||||
ySrc + (y - glyph->info.y) - first_yOff,
|
||||
0, 0, x - glyph->info.x,
|
||||
y - glyph->info.y)
|
||||
== ExaGlyphNeedFlush) {
|
||||
exaGlyphsToDst(op, pSrc, pDst, &buffer);
|
||||
exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
|
||||
xSrc + (x - glyph->info.x) - first_xOff,
|
||||
ySrc + (y - glyph->info.y) - first_yOff,
|
||||
0, 0, x - glyph->info.x,
|
||||
y - glyph->info.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x += glyph->info.xOff;
|
||||
y += glyph->info.yOff;
|
||||
}
|
||||
list++;
|
||||
}
|
||||
|
||||
if (buffer.count) {
|
||||
if (maskFormat)
|
||||
exaGlyphsToMask(pMask, &buffer);
|
||||
else
|
||||
exaGlyphsToDst(op, pSrc, pDst, &buffer);
|
||||
}
|
||||
|
||||
if (maskFormat) {
|
||||
x = extents.x1;
|
||||
y = extents.y1;
|
||||
CompositePicture(op,
|
||||
pSrc,
|
||||
pMask,
|
||||
pDst,
|
||||
xSrc + x - first_xOff,
|
||||
ySrc + y - first_yOff, 0, 0, x, y, width, height);
|
||||
FreePicture((void *) pMask, (XID) 0);
|
||||
(*pScreen->DestroyPixmap) (pMaskPixmap);
|
||||
}
|
||||
}
|
|
@ -1,761 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2006 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Michel Dänzer <michel@tungstengraphics.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "exa_priv.h"
|
||||
#include "exa.h"
|
||||
|
||||
#if DEBUG_MIGRATE
|
||||
#define DBG_MIGRATE(a) ErrorF a
|
||||
#else
|
||||
#define DBG_MIGRATE(a)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys
|
||||
* and exaCopyDirtyToFb both needed to do this loop.
|
||||
*/
|
||||
static void
|
||||
exaMemcpyBox(PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch,
|
||||
CARD8 *dst, int dst_pitch)
|
||||
{
|
||||
int i, cpp = pPixmap->drawable.bitsPerPixel / 8;
|
||||
int bytes = (pbox->x2 - pbox->x1) * cpp;
|
||||
|
||||
src += pbox->y1 * src_pitch + pbox->x1 * cpp;
|
||||
dst += pbox->y1 * dst_pitch + pbox->x1 * cpp;
|
||||
|
||||
for (i = pbox->y2 - pbox->y1; i; i--) {
|
||||
memcpy(dst, src, bytes);
|
||||
src += src_pitch;
|
||||
dst += dst_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if the pixmap is dirty (has been modified in its current
|
||||
* location compared to the other), or lacks a private for tracking
|
||||
* dirtiness.
|
||||
*/
|
||||
static Bool
|
||||
exaPixmapIsDirty(PixmapPtr pPix)
|
||||
{
|
||||
ExaPixmapPriv(pPix);
|
||||
|
||||
if (pExaPixmap == NULL)
|
||||
EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE);
|
||||
|
||||
if (!pExaPixmap->pDamage)
|
||||
return FALSE;
|
||||
|
||||
return RegionNotEmpty(DamageRegion(pExaPixmap->pDamage)) ||
|
||||
!RegionEqual(&pExaPixmap->validSys, &pExaPixmap->validFB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score
|
||||
* to be considered "should be in framebuffer". That's just anything that has
|
||||
* had more acceleration than fallbacks, or has no score yet.
|
||||
*
|
||||
* Only valid if using a migration scheme that tracks score.
|
||||
*/
|
||||
static Bool
|
||||
exaPixmapShouldBeInFB(PixmapPtr pPix)
|
||||
{
|
||||
ExaPixmapPriv(pPix);
|
||||
|
||||
if (exaPixmapIsPinned(pPix))
|
||||
return TRUE;
|
||||
|
||||
return pExaPixmap->score >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the pixmap is currently dirty, this copies at least the dirty area from
|
||||
* FB to system or vice versa. Both areas must be allocated.
|
||||
*/
|
||||
static void
|
||||
exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
|
||||
Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h,
|
||||
char *sys, int sys_pitch), int fallback_index,
|
||||
void (*sync) (ScreenPtr pScreen))
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
RegionPtr damage = DamageRegion(pExaPixmap->pDamage);
|
||||
RegionRec CopyReg;
|
||||
Bool save_use_gpu_copy;
|
||||
int save_pitch;
|
||||
BoxPtr pBox;
|
||||
int nbox;
|
||||
Bool access_prepared = FALSE;
|
||||
Bool need_sync = FALSE;
|
||||
|
||||
/* Damaged bits are valid in current copy but invalid in other one */
|
||||
if (pExaPixmap->use_gpu_copy) {
|
||||
RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, damage);
|
||||
RegionSubtract(&pExaPixmap->validSys, &pExaPixmap->validSys, damage);
|
||||
}
|
||||
else {
|
||||
RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, damage);
|
||||
RegionSubtract(&pExaPixmap->validFB, &pExaPixmap->validFB, damage);
|
||||
}
|
||||
|
||||
RegionEmpty(damage);
|
||||
|
||||
/* Copy bits valid in source but not in destination */
|
||||
RegionNull(&CopyReg);
|
||||
RegionSubtract(&CopyReg, pValidSrc, pValidDst);
|
||||
|
||||
if (migrate->as_dst) {
|
||||
ExaScreenPriv(pPixmap->drawable.pScreen);
|
||||
|
||||
/* XXX: The pending damage region will be marked as damaged after the
|
||||
* operation, so it should serve as an upper bound for the region that
|
||||
* needs to be synchronized for the operation. Unfortunately, this
|
||||
* causes corruption in some cases, e.g. when starting compiz. See
|
||||
* https://bugs.freedesktop.org/show_bug.cgi?id=12916 .
|
||||
*/
|
||||
if (pExaScr->optimize_migration) {
|
||||
RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
|
||||
|
||||
#if DEBUG_MIGRATE
|
||||
if (RegionNil(pending_damage)) {
|
||||
static Bool firsttime = TRUE;
|
||||
|
||||
if (firsttime) {
|
||||
ErrorF("%s: Pending damage region empty!\n", __func__);
|
||||
firsttime = FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Try to prevent destination valid region from growing too many
|
||||
* rects by filling it up to the extents of the union of the
|
||||
* destination valid region and the pending damage region.
|
||||
*/
|
||||
if (RegionNumRects(pValidDst) > 10) {
|
||||
BoxRec box;
|
||||
BoxPtr pValidExt, pDamageExt;
|
||||
RegionRec closure;
|
||||
|
||||
pValidExt = RegionExtents(pValidDst);
|
||||
pDamageExt = RegionExtents(pending_damage);
|
||||
|
||||
box.x1 = min(pValidExt->x1, pDamageExt->x1);
|
||||
box.y1 = min(pValidExt->y1, pDamageExt->y1);
|
||||
box.x2 = max(pValidExt->x2, pDamageExt->x2);
|
||||
box.y2 = max(pValidExt->y2, pDamageExt->y2);
|
||||
|
||||
RegionInit(&closure, &box, 0);
|
||||
RegionIntersect(&CopyReg, &CopyReg, &closure);
|
||||
}
|
||||
else
|
||||
RegionIntersect(&CopyReg, &CopyReg, pending_damage);
|
||||
}
|
||||
|
||||
/* The caller may provide a region to be subtracted from the calculated
|
||||
* dirty region. This is to avoid migration of bits that don't
|
||||
* contribute to the result of the operation.
|
||||
*/
|
||||
if (migrate->pReg)
|
||||
RegionSubtract(&CopyReg, &CopyReg, migrate->pReg);
|
||||
}
|
||||
else {
|
||||
/* The caller may restrict the region to be migrated for source pixmaps
|
||||
* to what's relevant for the operation.
|
||||
*/
|
||||
if (migrate->pReg)
|
||||
RegionIntersect(&CopyReg, &CopyReg, migrate->pReg);
|
||||
}
|
||||
|
||||
pBox = RegionRects(&CopyReg);
|
||||
nbox = RegionNumRects(&CopyReg);
|
||||
|
||||
save_use_gpu_copy = pExaPixmap->use_gpu_copy;
|
||||
save_pitch = pPixmap->devKind;
|
||||
pExaPixmap->use_gpu_copy = TRUE;
|
||||
pPixmap->devKind = pExaPixmap->fb_pitch;
|
||||
|
||||
while (nbox--) {
|
||||
pBox->x1 = max(pBox->x1, 0);
|
||||
pBox->y1 = max(pBox->y1, 0);
|
||||
pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
|
||||
pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
|
||||
|
||||
if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
|
||||
continue;
|
||||
|
||||
if (!transfer || !transfer(pPixmap,
|
||||
pBox->x1, pBox->y1,
|
||||
pBox->x2 - pBox->x1,
|
||||
pBox->y2 - pBox->y1,
|
||||
(char *) (pExaPixmap->sys_ptr
|
||||
+ pBox->y1 * pExaPixmap->sys_pitch
|
||||
+
|
||||
pBox->x1 *
|
||||
pPixmap->drawable.bitsPerPixel /
|
||||
8), pExaPixmap->sys_pitch)) {
|
||||
if (!access_prepared) {
|
||||
ExaDoPrepareAccess(pPixmap, fallback_index);
|
||||
access_prepared = TRUE;
|
||||
}
|
||||
if (fallback_index == EXA_PREPARE_DEST) {
|
||||
exaMemcpyBox(pPixmap, pBox,
|
||||
pExaPixmap->sys_ptr, pExaPixmap->sys_pitch,
|
||||
pPixmap->devPrivate.ptr, pPixmap->devKind);
|
||||
}
|
||||
else {
|
||||
exaMemcpyBox(pPixmap, pBox,
|
||||
pPixmap->devPrivate.ptr, pPixmap->devKind,
|
||||
pExaPixmap->sys_ptr, pExaPixmap->sys_pitch);
|
||||
}
|
||||
}
|
||||
else
|
||||
need_sync = TRUE;
|
||||
|
||||
pBox++;
|
||||
}
|
||||
|
||||
pExaPixmap->use_gpu_copy = save_use_gpu_copy;
|
||||
pPixmap->devKind = save_pitch;
|
||||
|
||||
/* Try to prevent source valid region from growing too many rects by
|
||||
* removing parts of it which are also in the destination valid region.
|
||||
* Removing anything beyond that would lead to data loss.
|
||||
*/
|
||||
if (RegionNumRects(pValidSrc) > 20)
|
||||
RegionSubtract(pValidSrc, pValidSrc, pValidDst);
|
||||
|
||||
/* The copied bits are now valid in destination */
|
||||
RegionUnion(pValidDst, pValidDst, &CopyReg);
|
||||
|
||||
RegionUninit(&CopyReg);
|
||||
|
||||
if (access_prepared)
|
||||
exaFinishAccess(&pPixmap->drawable, fallback_index);
|
||||
else if (need_sync && sync)
|
||||
sync(pPixmap->drawable.pScreen);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the pixmap is currently dirty, this copies at least the dirty area from
|
||||
* the framebuffer memory copy to the system memory copy. Both areas must be
|
||||
* allocated.
|
||||
*/
|
||||
void
|
||||
exaCopyDirtyToSys(ExaMigrationPtr migrate)
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
|
||||
ExaScreenPriv(pPixmap->drawable.pScreen);
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB,
|
||||
pExaScr->info->DownloadFromScreen, EXA_PREPARE_SRC,
|
||||
exaWaitSync);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the pixmap is currently dirty, this copies at least the dirty area from
|
||||
* the system memory copy to the framebuffer memory copy. Both areas must be
|
||||
* allocated.
|
||||
*/
|
||||
void
|
||||
exaCopyDirtyToFb(ExaMigrationPtr migrate)
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
|
||||
ExaScreenPriv(pPixmap->drawable.pScreen);
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys,
|
||||
pExaScr->info->UploadToScreen, EXA_PREPARE_DEST, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a framebuffer copy of the pixmap if necessary, and then copies
|
||||
* any necessary pixmap data into the framebuffer copy and points the pixmap at
|
||||
* it.
|
||||
*
|
||||
* Note that when first allocated, a pixmap will have FALSE dirty flag.
|
||||
* This is intentional because pixmap data starts out undefined. So if we move
|
||||
* it in due to the first operation against it being accelerated, it will have
|
||||
* undefined framebuffer contents that we didn't have to upload. If we do
|
||||
* moveouts (and moveins) after the first movein, then we will only have to copy
|
||||
* back and forth if the pixmap was written to after the last synchronization of
|
||||
* the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away)
|
||||
* we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
|
||||
* all the data, since it's almost surely all valid now.
|
||||
*/
|
||||
static void
|
||||
exaDoMoveInPixmap(ExaMigrationPtr migrate)
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
/* If we're VT-switched away, no touching card memory allowed. */
|
||||
if (pExaScr->swappedOut)
|
||||
return;
|
||||
|
||||
/* If we're not allowed to move, then fail. */
|
||||
if (exaPixmapIsPinned(pPixmap))
|
||||
return;
|
||||
|
||||
/* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of
|
||||
* fragility in EXA, and <8bpp is probably not used enough any more to care
|
||||
* (at least, not in acceleratd paths).
|
||||
*/
|
||||
if (pPixmap->drawable.bitsPerPixel < 8)
|
||||
return;
|
||||
|
||||
if (pExaPixmap->accel_blocked)
|
||||
return;
|
||||
|
||||
if (pExaPixmap->area == NULL) {
|
||||
pExaPixmap->area =
|
||||
exaOffscreenAlloc(pScreen, pExaPixmap->fb_size,
|
||||
pExaScr->info->pixmapOffsetAlign, FALSE,
|
||||
exaPixmapSave, (void *) pPixmap);
|
||||
if (pExaPixmap->area == NULL)
|
||||
return;
|
||||
|
||||
pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
|
||||
pExaPixmap->area->offset;
|
||||
}
|
||||
|
||||
exaCopyDirtyToFb(migrate);
|
||||
|
||||
if (exaPixmapHasGpuCopy(pPixmap))
|
||||
return;
|
||||
|
||||
DBG_MIGRATE(("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
|
||||
(ExaGetPixmapPriv(pPixmap)->area ?
|
||||
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
|
||||
pPixmap->drawable.width,
|
||||
pPixmap->drawable.height,
|
||||
exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
|
||||
|
||||
pExaPixmap->use_gpu_copy = TRUE;
|
||||
|
||||
pPixmap->devKind = pExaPixmap->fb_pitch;
|
||||
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
|
||||
}
|
||||
|
||||
void
|
||||
exaMoveInPixmap_classic(PixmapPtr pPixmap)
|
||||
{
|
||||
static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE,
|
||||
.pReg = NULL
|
||||
};
|
||||
|
||||
migrate.pPix = pPixmap;
|
||||
exaDoMoveInPixmap(&migrate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the current active location of the pixmap to system memory, copying
|
||||
* updated data out if necessary.
|
||||
*/
|
||||
static void
|
||||
exaDoMoveOutPixmap(ExaMigrationPtr migrate)
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
|
||||
return;
|
||||
|
||||
exaCopyDirtyToSys(migrate);
|
||||
|
||||
if (exaPixmapHasGpuCopy(pPixmap)) {
|
||||
|
||||
DBG_MIGRATE(("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
|
||||
(void *) (ExaGetPixmapPriv(pPixmap)->area ?
|
||||
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
|
||||
pPixmap->drawable.width,
|
||||
pPixmap->drawable.height,
|
||||
exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
|
||||
|
||||
pExaPixmap->use_gpu_copy = FALSE;
|
||||
|
||||
pPixmap->devKind = pExaPixmap->sys_pitch;
|
||||
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
exaMoveOutPixmap_classic(PixmapPtr pPixmap)
|
||||
{
|
||||
static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE,
|
||||
.pReg = NULL
|
||||
};
|
||||
|
||||
migrate.pPix = pPixmap;
|
||||
exaDoMoveOutPixmap(&migrate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies out important pixmap data and removes references to framebuffer area.
|
||||
* Called when the memory manager decides it's time to kick the pixmap out of
|
||||
* framebuffer entirely.
|
||||
*/
|
||||
void
|
||||
exaPixmapSave(ScreenPtr pScreen, ExaOffscreenArea * area)
|
||||
{
|
||||
PixmapPtr pPixmap = area->privData;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
exaMoveOutPixmap(pPixmap);
|
||||
|
||||
pExaPixmap->fb_ptr = NULL;
|
||||
pExaPixmap->area = NULL;
|
||||
|
||||
/* Mark all FB bits as invalid, so all valid system bits get copied to FB
|
||||
* next time */
|
||||
RegionEmpty(&pExaPixmap->validFB);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the "greedy" migration scheme, pushes the pixmap toward being located in
|
||||
* framebuffer memory.
|
||||
*/
|
||||
static void
|
||||
exaMigrateTowardFb(ExaMigrationPtr migrate)
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) {
|
||||
DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n",
|
||||
(void *) pPixmap));
|
||||
return;
|
||||
}
|
||||
|
||||
DBG_MIGRATE(("UseScreen %p score %d\n",
|
||||
(void *) pPixmap, pExaPixmap->score));
|
||||
|
||||
if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
|
||||
exaDoMoveInPixmap(migrate);
|
||||
pExaPixmap->score = 0;
|
||||
}
|
||||
|
||||
if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
|
||||
pExaPixmap->score++;
|
||||
|
||||
if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
|
||||
!exaPixmapHasGpuCopy(pPixmap)) {
|
||||
exaDoMoveInPixmap(migrate);
|
||||
}
|
||||
|
||||
if (exaPixmapHasGpuCopy(pPixmap)) {
|
||||
exaCopyDirtyToFb(migrate);
|
||||
ExaOffscreenMarkUsed(pPixmap);
|
||||
}
|
||||
else
|
||||
exaCopyDirtyToSys(migrate);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the "greedy" migration scheme, pushes the pixmap toward being located in
|
||||
* system memory.
|
||||
*/
|
||||
static void
|
||||
exaMigrateTowardSys(ExaMigrationPtr migrate)
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
DBG_MIGRATE(("UseMem: %p score %d\n", (void *) pPixmap,
|
||||
pExaPixmap->score));
|
||||
|
||||
if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
|
||||
return;
|
||||
|
||||
if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT)
|
||||
pExaPixmap->score = 0;
|
||||
|
||||
if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN)
|
||||
pExaPixmap->score--;
|
||||
|
||||
if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
|
||||
exaDoMoveOutPixmap(migrate);
|
||||
|
||||
if (exaPixmapHasGpuCopy(pPixmap)) {
|
||||
exaCopyDirtyToFb(migrate);
|
||||
ExaOffscreenMarkUsed(pPixmap);
|
||||
}
|
||||
else
|
||||
exaCopyDirtyToSys(migrate);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the pixmap has both a framebuffer and system memory copy, this function
|
||||
* asserts that both of them are the same.
|
||||
*/
|
||||
static Bool
|
||||
exaAssertNotDirty(PixmapPtr pPixmap)
|
||||
{
|
||||
ExaPixmapPriv(pPixmap);
|
||||
CARD8 *dst, *src;
|
||||
RegionRec ValidReg;
|
||||
int dst_pitch, src_pitch, cpp, y, nbox, save_pitch;
|
||||
BoxPtr pBox;
|
||||
Bool ret = TRUE, save_use_gpu_copy;
|
||||
|
||||
if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL)
|
||||
return ret;
|
||||
|
||||
RegionNull(&ValidReg);
|
||||
RegionIntersect(&ValidReg, &pExaPixmap->validFB, &pExaPixmap->validSys);
|
||||
nbox = RegionNumRects(&ValidReg);
|
||||
|
||||
if (!nbox)
|
||||
goto out;
|
||||
|
||||
pBox = RegionRects(&ValidReg);
|
||||
|
||||
dst_pitch = pExaPixmap->sys_pitch;
|
||||
src_pitch = pExaPixmap->fb_pitch;
|
||||
cpp = pPixmap->drawable.bitsPerPixel / 8;
|
||||
|
||||
save_use_gpu_copy = pExaPixmap->use_gpu_copy;
|
||||
save_pitch = pPixmap->devKind;
|
||||
pExaPixmap->use_gpu_copy = TRUE;
|
||||
pPixmap->devKind = pExaPixmap->fb_pitch;
|
||||
|
||||
if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC))
|
||||
goto skip;
|
||||
|
||||
while (nbox--) {
|
||||
int rowbytes;
|
||||
|
||||
pBox->x1 = max(pBox->x1, 0);
|
||||
pBox->y1 = max(pBox->y1, 0);
|
||||
pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
|
||||
pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
|
||||
|
||||
if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
|
||||
continue;
|
||||
|
||||
rowbytes = (pBox->x2 - pBox->x1) * cpp;
|
||||
src =
|
||||
(CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch +
|
||||
pBox->x1 * cpp;
|
||||
dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp;
|
||||
|
||||
for (y = pBox->y1; y < pBox->y2;
|
||||
y++, src += src_pitch, dst += dst_pitch) {
|
||||
if (memcmp(dst, src, rowbytes) != 0) {
|
||||
ret = FALSE;
|
||||
exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2, pBox->y2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skip:
|
||||
exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
|
||||
|
||||
pExaPixmap->use_gpu_copy = save_use_gpu_copy;
|
||||
pPixmap->devKind = save_pitch;
|
||||
|
||||
out:
|
||||
RegionUninit(&ValidReg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs migration of the pixmaps according to the operation information
|
||||
* provided in pixmaps and can_accel and the migration scheme chosen in the
|
||||
* config file.
|
||||
*/
|
||||
void
|
||||
exaDoMigration_classic(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
|
||||
{
|
||||
ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
int i, j;
|
||||
|
||||
/* If this debugging flag is set, check each pixmap for whether it is marked
|
||||
* as clean, and if so, actually check if that's the case. This should help
|
||||
* catch issues with failing to mark a drawable as dirty. While it will
|
||||
* catch them late (after the operation happened), it at least explains what
|
||||
* went wrong, and instrumenting the code to find what operation happened
|
||||
* to the pixmap last shouldn't be hard.
|
||||
*/
|
||||
if (pExaScr->checkDirtyCorrectness) {
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (!exaPixmapIsDirty(pixmaps[i].pPix) &&
|
||||
!exaAssertNotDirty(pixmaps[i].pPix))
|
||||
ErrorF("%s: Pixmap %d dirty but not marked as such!\n",
|
||||
__func__, i);
|
||||
}
|
||||
}
|
||||
/* If anything is pinned in system memory, we won't be able to
|
||||
* accelerate.
|
||||
*/
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (exaPixmapIsPinned(pixmaps[i].pPix) &&
|
||||
!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
|
||||
EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix,
|
||||
pixmaps[i].pPix->drawable.width,
|
||||
pixmaps[i].pPix->drawable.height));
|
||||
can_accel = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pExaScr->migration == ExaMigrationSmart) {
|
||||
/* If we've got something as a destination that we shouldn't cause to
|
||||
* become newly dirtied, take the unaccelerated route.
|
||||
*/
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB(pixmaps[i].pPix) &&
|
||||
!exaPixmapIsDirty(pixmaps[i].pPix)) {
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (!exaPixmapIsDirty(pixmaps[i].pPix))
|
||||
exaDoMoveOutPixmap(pixmaps + i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we aren't going to accelerate, then we migrate everybody toward
|
||||
* system memory, and kick out if it's free.
|
||||
*/
|
||||
if (!can_accel) {
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
exaMigrateTowardSys(pixmaps + i);
|
||||
if (!exaPixmapIsDirty(pixmaps[i].pPix))
|
||||
exaDoMoveOutPixmap(pixmaps + i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Finally, the acceleration path. Move them all in. */
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
exaMigrateTowardFb(pixmaps + i);
|
||||
exaDoMoveInPixmap(pixmaps + i);
|
||||
}
|
||||
}
|
||||
else if (pExaScr->migration == ExaMigrationGreedy) {
|
||||
/* If we can't accelerate, either because the driver can't or because one of
|
||||
* the pixmaps is pinned in system memory, then we migrate everybody toward
|
||||
* system memory.
|
||||
*
|
||||
* We also migrate toward system if all pixmaps involved are currently in
|
||||
* system memory -- this can mitigate thrashing when there are significantly
|
||||
* more pixmaps active than would fit in memory.
|
||||
*
|
||||
* If not, then we migrate toward FB so that hopefully acceleration can
|
||||
* happen.
|
||||
*/
|
||||
if (!can_accel) {
|
||||
for (i = 0; i < npixmaps; i++)
|
||||
exaMigrateTowardSys(pixmaps + i);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
|
||||
/* Found one in FB, so move all to FB. */
|
||||
for (j = 0; j < npixmaps; j++)
|
||||
exaMigrateTowardFb(pixmaps + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Nobody's in FB, so move all away from FB. */
|
||||
for (i = 0; i < npixmaps; i++)
|
||||
exaMigrateTowardSys(pixmaps + i);
|
||||
}
|
||||
else if (pExaScr->migration == ExaMigrationAlways) {
|
||||
/* Always move the pixmaps out if we can't accelerate. If we can
|
||||
* accelerate, try to move them all in. If that fails, then move them
|
||||
* back out.
|
||||
*/
|
||||
if (!can_accel) {
|
||||
for (i = 0; i < npixmaps; i++)
|
||||
exaDoMoveOutPixmap(pixmaps + i);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now, try to move them all into FB */
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
exaDoMoveInPixmap(pixmaps + i);
|
||||
}
|
||||
|
||||
/* If we couldn't fit everything in, abort */
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Yay, everything has a gpu copy, mark memory as used */
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
ExaOffscreenMarkUsed(pixmaps[i].pPix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg)
|
||||
{
|
||||
ExaMigrationRec pixmaps[1];
|
||||
|
||||
if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
|
||||
pixmaps[0].as_dst = TRUE;
|
||||
pixmaps[0].as_src = FALSE;
|
||||
}
|
||||
else {
|
||||
pixmaps[0].as_dst = FALSE;
|
||||
pixmaps[0].as_src = TRUE;
|
||||
}
|
||||
pixmaps[0].pPix = pPixmap;
|
||||
pixmaps[0].pReg = pReg;
|
||||
|
||||
exaDoMigration(pixmaps, 1, FALSE);
|
||||
|
||||
(void) ExaDoPrepareAccess(pPixmap, index);
|
||||
}
|
|
@ -1,270 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2009 Maarten Maathuis
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "exa_priv.h"
|
||||
#include "exa.h"
|
||||
|
||||
void
|
||||
exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaPixmapPriv(pPixmap);
|
||||
int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
|
||||
int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
|
||||
int usage_hint = pPixmap->usage_hint;
|
||||
int paddedWidth = pExaPixmap->sys_pitch;
|
||||
|
||||
/* Already done. */
|
||||
if (pExaPixmap->driverPriv)
|
||||
return;
|
||||
|
||||
if (exaPixmapIsPinned(pPixmap))
|
||||
return;
|
||||
|
||||
/* Can't accel 1/4 bpp. */
|
||||
if (pExaPixmap->accel_blocked || bpp < 8)
|
||||
return;
|
||||
|
||||
if (pExaScr->info->CreatePixmap2) {
|
||||
int new_pitch = 0;
|
||||
|
||||
pExaPixmap->driverPriv =
|
||||
pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp,
|
||||
&new_pitch);
|
||||
paddedWidth = pExaPixmap->fb_pitch = new_pitch;
|
||||
}
|
||||
else {
|
||||
if (paddedWidth < pExaPixmap->fb_pitch)
|
||||
paddedWidth = pExaPixmap->fb_pitch;
|
||||
pExaPixmap->driverPriv =
|
||||
pExaScr->info->CreatePixmap(pScreen, paddedWidth * h, 0);
|
||||
}
|
||||
|
||||
if (!pExaPixmap->driverPriv)
|
||||
return;
|
||||
|
||||
(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* If anything is pinned in system memory, we won't be able to
|
||||
* accelerate.
|
||||
*/
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (exaPixmapIsPinned(pixmaps[i].pPix) &&
|
||||
!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
|
||||
can_accel = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We can do nothing. */
|
||||
if (!can_accel)
|
||||
return;
|
||||
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
PixmapPtr pPixmap = pixmaps[i].pPix;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
if (!pExaPixmap->driverPriv)
|
||||
exaCreateDriverPixmap_mixed(pPixmap);
|
||||
|
||||
if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) {
|
||||
ExaScreenPriv(pPixmap->drawable.pScreen);
|
||||
|
||||
/* This pitch is needed for proper acceleration. For some reason
|
||||
* there are pixmaps without pDamage and a bad fb_pitch value.
|
||||
* So setting devKind when only exaPixmapHasGpuCopy() is true
|
||||
* causes corruption. Pixmaps without pDamage are not migrated
|
||||
* and should have a valid devKind at all times, so that's why this
|
||||
* isn't causing problems. Pixmaps have their gpu pitch set the
|
||||
* first time in the MPH call from exaCreateDriverPixmap_mixed().
|
||||
*/
|
||||
pPixmap->devKind = pExaPixmap->fb_pitch;
|
||||
exaCopyDirtyToFb(pixmaps + i);
|
||||
|
||||
if (pExaScr->deferred_mixed_pixmap == pPixmap &&
|
||||
!pixmaps[i].as_dst && !pixmaps[i].pReg)
|
||||
pExaScr->deferred_mixed_pixmap = NULL;
|
||||
}
|
||||
|
||||
pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
exaMoveInPixmap_mixed(PixmapPtr pPixmap)
|
||||
{
|
||||
ExaMigrationRec pixmaps[1];
|
||||
|
||||
pixmaps[0].as_dst = FALSE;
|
||||
pixmaps[0].as_src = TRUE;
|
||||
pixmaps[0].pPix = pPixmap;
|
||||
pixmaps[0].pReg = NULL;
|
||||
|
||||
exaDoMigration(pixmaps, 1, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure)
|
||||
{
|
||||
PixmapPtr pPixmap = closure;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
/* Move back results of software rendering on system memory copy of mixed driver
|
||||
* pixmap (see exaPrepareAccessReg_mixed).
|
||||
*
|
||||
* Defer moving the destination back into the driver pixmap, to try and save
|
||||
* overhead on multiple subsequent software fallbacks.
|
||||
*/
|
||||
if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) {
|
||||
ExaScreenPriv(pPixmap->drawable.pScreen);
|
||||
|
||||
if (pExaScr->deferred_mixed_pixmap &&
|
||||
pExaScr->deferred_mixed_pixmap != pPixmap)
|
||||
exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
|
||||
pExaScr->deferred_mixed_pixmap = pPixmap;
|
||||
}
|
||||
}
|
||||
|
||||
/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we
|
||||
* use the DownloadFromScreen hook to retrieve contents to a copy in system
|
||||
* memory, perform software rendering on that and move back the results with the
|
||||
* UploadToScreen hook (see exaDamageReport_mixed).
|
||||
*/
|
||||
void
|
||||
exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg)
|
||||
{
|
||||
ExaPixmapPriv(pPixmap);
|
||||
Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
|
||||
Bool success;
|
||||
|
||||
success = ExaDoPrepareAccess(pPixmap, index);
|
||||
|
||||
if (success && has_gpu_copy && pExaPixmap->pDamage) {
|
||||
/* You cannot do accelerated operations while a buffer is mapped. */
|
||||
exaFinishAccess(&pPixmap->drawable, index);
|
||||
/* Update the gpu view of both deferred destination pixmaps and of
|
||||
* source pixmaps that were migrated with a bounding region.
|
||||
*/
|
||||
exaMoveInPixmap_mixed(pPixmap);
|
||||
success = ExaDoPrepareAccess(pPixmap, index);
|
||||
|
||||
if (success) {
|
||||
/* We have a gpu pixmap that can be accessed, we don't need the cpu
|
||||
* copy anymore. Drivers that prefer DFS, should fail prepare
|
||||
* access.
|
||||
*/
|
||||
DamageDestroy(pExaPixmap->pDamage);
|
||||
pExaPixmap->pDamage = NULL;
|
||||
|
||||
free(pExaPixmap->sys_ptr);
|
||||
pExaPixmap->sys_ptr = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
ExaMigrationRec pixmaps[1];
|
||||
|
||||
/* Do we need to allocate our system buffer? */
|
||||
if (!pExaPixmap->sys_ptr) {
|
||||
pExaPixmap->sys_ptr = xallocarray(pExaPixmap->sys_pitch,
|
||||
pPixmap->drawable.height);
|
||||
if (!pExaPixmap->sys_ptr)
|
||||
FatalError("EXA: malloc failed for size %d bytes\n",
|
||||
pExaPixmap->sys_pitch * pPixmap->drawable.height);
|
||||
}
|
||||
|
||||
if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
|
||||
pixmaps[0].as_dst = TRUE;
|
||||
pixmaps[0].as_src = FALSE;
|
||||
}
|
||||
else {
|
||||
pixmaps[0].as_dst = FALSE;
|
||||
pixmaps[0].as_src = TRUE;
|
||||
}
|
||||
pixmaps[0].pPix = pPixmap;
|
||||
pixmaps[0].pReg = pReg;
|
||||
|
||||
if (!pExaPixmap->pDamage &&
|
||||
(has_gpu_copy || !exaPixmapIsPinned(pPixmap))) {
|
||||
Bool as_dst = pixmaps[0].as_dst;
|
||||
|
||||
/* Set up damage tracking */
|
||||
pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
|
||||
DamageReportNonEmpty, TRUE,
|
||||
pPixmap->drawable.pScreen,
|
||||
pPixmap);
|
||||
|
||||
if (pExaPixmap->pDamage) {
|
||||
DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
|
||||
/* This ensures that pending damage reflects the current
|
||||
* operation. This is used by exa to optimize migration.
|
||||
*/
|
||||
DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
|
||||
}
|
||||
|
||||
if (has_gpu_copy) {
|
||||
exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
|
||||
pPixmap->drawable.height);
|
||||
|
||||
/* We don't know which region of the destination will be damaged,
|
||||
* have to assume all of it
|
||||
*/
|
||||
if (as_dst) {
|
||||
pixmaps[0].as_dst = FALSE;
|
||||
pixmaps[0].as_src = TRUE;
|
||||
pixmaps[0].pReg = NULL;
|
||||
}
|
||||
exaCopyDirtyToSys(pixmaps);
|
||||
}
|
||||
|
||||
if (as_dst)
|
||||
exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
|
||||
pPixmap->drawable.height);
|
||||
}
|
||||
else if (has_gpu_copy)
|
||||
exaCopyDirtyToSys(pixmaps);
|
||||
|
||||
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
|
||||
pPixmap->devKind = pExaPixmap->sys_pitch;
|
||||
pExaPixmap->use_gpu_copy = FALSE;
|
||||
}
|
||||
}
|
330
exa/exa_mixed.c
330
exa/exa_mixed.c
|
@ -1,330 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2009 Maarten Maathuis
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "exa_priv.h"
|
||||
#include "exa.h"
|
||||
|
||||
/* This file holds the driver allocated pixmaps + better initial placement code.
|
||||
*/
|
||||
|
||||
static _X_INLINE void *
|
||||
ExaGetPixmapAddress(PixmapPtr p)
|
||||
{
|
||||
ExaPixmapPriv(p);
|
||||
|
||||
return pExaPixmap->sys_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* exaCreatePixmap() creates a new pixmap.
|
||||
*/
|
||||
PixmapPtr
|
||||
exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
|
||||
unsigned usage_hint)
|
||||
{
|
||||
PixmapPtr pPixmap;
|
||||
ExaPixmapPrivPtr pExaPixmap;
|
||||
int bpp;
|
||||
size_t paddedWidth;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
if (w > 32767 || h > 32767)
|
||||
return NullPixmap;
|
||||
|
||||
swap(pExaScr, pScreen, CreatePixmap);
|
||||
pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
|
||||
swap(pExaScr, pScreen, CreatePixmap);
|
||||
|
||||
if (!pPixmap)
|
||||
return NULL;
|
||||
|
||||
pExaPixmap = ExaGetPixmapPriv(pPixmap);
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
|
||||
bpp = pPixmap->drawable.bitsPerPixel;
|
||||
|
||||
paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
|
||||
if (paddedWidth / 4 > 32767 || h > 32767)
|
||||
return NullPixmap;
|
||||
|
||||
/* We will allocate the system pixmap later if needed. */
|
||||
pPixmap->devPrivate.ptr = NULL;
|
||||
pExaPixmap->sys_ptr = NULL;
|
||||
pExaPixmap->sys_pitch = paddedWidth;
|
||||
|
||||
pExaPixmap->area = NULL;
|
||||
pExaPixmap->fb_ptr = NULL;
|
||||
pExaPixmap->pDamage = NULL;
|
||||
|
||||
exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
|
||||
exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
|
||||
|
||||
(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
|
||||
|
||||
/* A scratch pixmap will become a driver pixmap right away. */
|
||||
if (!w || !h) {
|
||||
exaCreateDriverPixmap_mixed(pPixmap);
|
||||
pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
|
||||
}
|
||||
else {
|
||||
pExaPixmap->use_gpu_copy = FALSE;
|
||||
|
||||
if (w == 1 && h == 1) {
|
||||
pExaPixmap->sys_ptr = malloc(paddedWidth);
|
||||
|
||||
/* Set up damage tracking */
|
||||
pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
|
||||
DamageReportNonEmpty, TRUE,
|
||||
pPixmap->drawable.pScreen,
|
||||
pPixmap);
|
||||
|
||||
if (pExaPixmap->pDamage) {
|
||||
DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
|
||||
/* This ensures that pending damage reflects the current
|
||||
* operation. This is used by exa to optimize migration.
|
||||
*/
|
||||
DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* During a fallback we must prepare access. */
|
||||
if (pExaScr->fallback_counter)
|
||||
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
|
||||
|
||||
return pPixmap;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
|
||||
int bitsPerPixel, int devKind, void *pPixData)
|
||||
{
|
||||
ScreenPtr pScreen;
|
||||
ExaScreenPrivPtr pExaScr;
|
||||
ExaPixmapPrivPtr pExaPixmap;
|
||||
Bool ret, has_gpu_copy;
|
||||
|
||||
if (!pPixmap)
|
||||
return FALSE;
|
||||
|
||||
pScreen = pPixmap->drawable.pScreen;
|
||||
pExaScr = ExaGetScreenPriv(pScreen);
|
||||
pExaPixmap = ExaGetPixmapPriv(pPixmap);
|
||||
|
||||
if (pPixData) {
|
||||
if (pExaPixmap->driverPriv) {
|
||||
if (pExaPixmap->pDamage) {
|
||||
DamageDestroy(pExaPixmap->pDamage);
|
||||
pExaPixmap->pDamage = NULL;
|
||||
}
|
||||
|
||||
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
}
|
||||
|
||||
pExaPixmap->use_gpu_copy = FALSE;
|
||||
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
|
||||
}
|
||||
|
||||
has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
|
||||
|
||||
if (width <= 0)
|
||||
width = pPixmap->drawable.width;
|
||||
|
||||
if (height <= 0)
|
||||
height = pPixmap->drawable.height;
|
||||
|
||||
if (bitsPerPixel <= 0) {
|
||||
if (depth <= 0)
|
||||
bitsPerPixel = pPixmap->drawable.bitsPerPixel;
|
||||
else
|
||||
bitsPerPixel = BitsPerPixel(depth);
|
||||
}
|
||||
|
||||
if (depth <= 0)
|
||||
depth = pPixmap->drawable.depth;
|
||||
|
||||
if (width != pPixmap->drawable.width ||
|
||||
height != pPixmap->drawable.height ||
|
||||
depth != pPixmap->drawable.depth ||
|
||||
bitsPerPixel != pPixmap->drawable.bitsPerPixel) {
|
||||
if (pExaPixmap->driverPriv) {
|
||||
if (devKind > 0)
|
||||
pExaPixmap->fb_pitch = devKind;
|
||||
else
|
||||
exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
|
||||
|
||||
exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
|
||||
RegionEmpty(&pExaPixmap->validFB);
|
||||
}
|
||||
|
||||
/* Need to re-create system copy if there's also a GPU copy */
|
||||
if (has_gpu_copy) {
|
||||
if (pExaPixmap->sys_ptr) {
|
||||
free(pExaPixmap->sys_ptr);
|
||||
pExaPixmap->sys_ptr = NULL;
|
||||
DamageDestroy(pExaPixmap->pDamage);
|
||||
pExaPixmap->pDamage = NULL;
|
||||
RegionEmpty(&pExaPixmap->validSys);
|
||||
|
||||
if (pExaScr->deferred_mixed_pixmap == pPixmap)
|
||||
pExaScr->deferred_mixed_pixmap = NULL;
|
||||
}
|
||||
|
||||
pExaPixmap->sys_pitch = PixmapBytePad(width, depth);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_gpu_copy) {
|
||||
pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
|
||||
pPixmap->devKind = pExaPixmap->fb_pitch;
|
||||
}
|
||||
else {
|
||||
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
|
||||
pPixmap->devKind = pExaPixmap->sys_pitch;
|
||||
}
|
||||
|
||||
/* Only pass driver pixmaps to the driver. */
|
||||
if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) {
|
||||
ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
|
||||
bitsPerPixel, devKind,
|
||||
pPixData);
|
||||
if (ret == TRUE)
|
||||
goto out;
|
||||
}
|
||||
|
||||
swap(pExaScr, pScreen, ModifyPixmapHeader);
|
||||
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
|
||||
bitsPerPixel, devKind, pPixData);
|
||||
swap(pExaScr, pScreen, ModifyPixmapHeader);
|
||||
|
||||
out:
|
||||
if (has_gpu_copy) {
|
||||
pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr;
|
||||
pExaPixmap->fb_pitch = pPixmap->devKind;
|
||||
}
|
||||
else {
|
||||
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
|
||||
pExaPixmap->sys_pitch = pPixmap->devKind;
|
||||
}
|
||||
/* Always NULL this, we don't want lingering pointers. */
|
||||
pPixmap->devPrivate.ptr = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaDestroyPixmap_mixed(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
Bool ret;
|
||||
|
||||
if (pPixmap->refcnt == 1) {
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
exaDestroyPixmap(pPixmap);
|
||||
|
||||
if (pExaScr->deferred_mixed_pixmap == pPixmap)
|
||||
pExaScr->deferred_mixed_pixmap = NULL;
|
||||
|
||||
if (pExaPixmap->driverPriv)
|
||||
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
|
||||
if (pExaPixmap->pDamage) {
|
||||
free(pExaPixmap->sys_ptr);
|
||||
pExaPixmap->sys_ptr = NULL;
|
||||
pExaPixmap->pDamage = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
ret = pScreen->DestroyPixmap(pPixmap);
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaPixmapPriv(pPixmap);
|
||||
void *saved_ptr;
|
||||
Bool ret;
|
||||
|
||||
if (!pExaPixmap->driverPriv)
|
||||
return FALSE;
|
||||
|
||||
saved_ptr = pPixmap->devPrivate.ptr;
|
||||
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
|
||||
ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
|
||||
pPixmap->devPrivate.ptr = saved_ptr;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaSharePixmapBacking_mixed(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
ExaScreenPriv(pScreen);
|
||||
Bool ret = FALSE;
|
||||
|
||||
exaMoveInPixmap(pPixmap);
|
||||
/* get the driver to give us a handle */
|
||||
if (pExaScr->info->SharePixmapBacking)
|
||||
ret = pExaScr->info->SharePixmapBacking(pPixmap, secondary, handle_p);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap, void *handle)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
ExaScreenPriv(pScreen);
|
||||
Bool ret = FALSE;
|
||||
|
||||
if (pExaScr->info->SetSharedPixmapBacking)
|
||||
ret = pExaScr->info->SetSharedPixmapBacking(pPixmap, handle);
|
||||
|
||||
if (ret == TRUE)
|
||||
exaMoveInPixmap(pPixmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1,677 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2003 Anders Carlsson
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of Anders Carlsson not be used in
|
||||
* advertising or publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. Anders Carlsson makes no
|
||||
* representations about the suitability of this software for any purpose. It
|
||||
* is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* ANDERS CARLSSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL ANDERS CARLSSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* This allocator allocates blocks of memory by maintaining a list of areas.
|
||||
* When allocating, the contiguous block of areas with the minimum eviction
|
||||
* cost is found and evicted in order to make room for the new allocation.
|
||||
*/
|
||||
|
||||
#include "exa_priv.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if DEBUG_OFFSCREEN
|
||||
#define DBG_OFFSCREEN(a) ErrorF a
|
||||
#else
|
||||
#define DBG_OFFSCREEN(a)
|
||||
#endif
|
||||
|
||||
#if DEBUG_OFFSCREEN
|
||||
static void
|
||||
ExaOffscreenValidate(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaOffscreenArea *prev = 0, *area;
|
||||
|
||||
assert(pExaScr->info->offScreenAreas->base_offset ==
|
||||
pExaScr->info->offScreenBase);
|
||||
for (area = pExaScr->info->offScreenAreas; area; area = area->next) {
|
||||
assert(area->offset >= area->base_offset);
|
||||
assert(area->offset < (area->base_offset + area->size));
|
||||
if (prev)
|
||||
assert(prev->base_offset + prev->size == area->base_offset);
|
||||
prev = area;
|
||||
}
|
||||
assert(prev->base_offset + prev->size == pExaScr->info->memorySize);
|
||||
}
|
||||
#else
|
||||
#define ExaOffscreenValidate(s)
|
||||
#endif
|
||||
|
||||
static ExaOffscreenArea *
|
||||
ExaOffscreenKickOut(ScreenPtr pScreen, ExaOffscreenArea * area)
|
||||
{
|
||||
if (area->save)
|
||||
(*area->save) (pScreen, area);
|
||||
return exaOffscreenFree(pScreen, area);
|
||||
}
|
||||
|
||||
static void
|
||||
exaUpdateEvictionCost(ExaOffscreenArea * area, unsigned offScreenCounter)
|
||||
{
|
||||
unsigned age;
|
||||
|
||||
if (area->state == ExaOffscreenAvail)
|
||||
return;
|
||||
|
||||
age = offScreenCounter - area->last_use;
|
||||
|
||||
/* This is unlikely to happen, but could result in a division by zero... */
|
||||
if (age > (UINT_MAX / 2)) {
|
||||
age = UINT_MAX / 2;
|
||||
area->last_use = offScreenCounter - age;
|
||||
}
|
||||
|
||||
area->eviction_cost = area->size / age;
|
||||
}
|
||||
|
||||
static ExaOffscreenArea *
|
||||
exaFindAreaToEvict(ExaScreenPrivPtr pExaScr, int size, int align)
|
||||
{
|
||||
ExaOffscreenArea *begin, *end, *best;
|
||||
unsigned cost, best_cost;
|
||||
int avail, real_size;
|
||||
|
||||
best_cost = UINT_MAX;
|
||||
begin = end = pExaScr->info->offScreenAreas;
|
||||
avail = 0;
|
||||
cost = 0;
|
||||
best = 0;
|
||||
|
||||
while (end != NULL) {
|
||||
restart:
|
||||
while (begin != NULL && begin->state == ExaOffscreenLocked)
|
||||
begin = end = begin->next;
|
||||
|
||||
if (begin == NULL)
|
||||
break;
|
||||
|
||||
/* adjust size needed to account for alignment loss for this area */
|
||||
real_size = size + (begin->base_offset + begin->size - size) % align;
|
||||
|
||||
while (avail < real_size && end != NULL) {
|
||||
if (end->state == ExaOffscreenLocked) {
|
||||
/* Can't more room here, restart after this locked area */
|
||||
avail = 0;
|
||||
cost = 0;
|
||||
begin = end;
|
||||
goto restart;
|
||||
}
|
||||
avail += end->size;
|
||||
exaUpdateEvictionCost(end, pExaScr->offScreenCounter);
|
||||
cost += end->eviction_cost;
|
||||
end = end->next;
|
||||
}
|
||||
|
||||
/* Check the cost, update best */
|
||||
if (avail >= real_size && cost < best_cost) {
|
||||
best = begin;
|
||||
best_cost = cost;
|
||||
}
|
||||
|
||||
avail -= begin->size;
|
||||
cost -= begin->eviction_cost;
|
||||
begin = begin->next;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
/**
|
||||
* exaOffscreenAlloc allocates offscreen memory
|
||||
*
|
||||
* @param pScreen current screen
|
||||
* @param size size in bytes of the allocation
|
||||
* @param align byte alignment requirement for the offset of the allocated area
|
||||
* @param locked whether the allocated area is locked and can't be kicked out
|
||||
* @param save callback for when the area is evicted from memory
|
||||
* @param privdata private data for the save callback.
|
||||
*
|
||||
* Allocates offscreen memory from the device associated with pScreen. size
|
||||
* and align determine where and how large the allocated area is, and locked
|
||||
* will mark whether it should be held in card memory. privdata may be any
|
||||
* pointer for the save callback when the area is removed.
|
||||
*
|
||||
* Note that locked areas do get evicted on VT switch unless the driver
|
||||
* requested version 2.1 or newer behavior. In that case, the save callback is
|
||||
* still called.
|
||||
*/
|
||||
ExaOffscreenArea *
|
||||
exaOffscreenAlloc(ScreenPtr pScreen, int size, int align,
|
||||
Bool locked, ExaOffscreenSaveProc save, void *privData)
|
||||
{
|
||||
ExaOffscreenArea *area;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
int real_size = 0, largest_avail = 0;
|
||||
|
||||
#if DEBUG_OFFSCREEN
|
||||
static int number = 0;
|
||||
|
||||
ErrorF("================= ============ allocating a new pixmap %d\n",
|
||||
++number);
|
||||
#endif
|
||||
|
||||
ExaOffscreenValidate(pScreen);
|
||||
if (!align)
|
||||
align = 1;
|
||||
|
||||
if (!size) {
|
||||
DBG_OFFSCREEN(("Alloc 0x%x -> EMPTY\n", size));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* throw out requests that cannot fit */
|
||||
if (size > (pExaScr->info->memorySize - pExaScr->info->offScreenBase)) {
|
||||
DBG_OFFSCREEN(("Alloc 0x%x vs (0x%lx) -> TOBIG\n", size,
|
||||
pExaScr->info->memorySize -
|
||||
pExaScr->info->offScreenBase));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Try to find a free space that'll fit. */
|
||||
for (area = pExaScr->info->offScreenAreas; area; area = area->next) {
|
||||
/* skip allocated areas */
|
||||
if (area->state != ExaOffscreenAvail)
|
||||
continue;
|
||||
|
||||
/* adjust size to match alignment requirement */
|
||||
real_size = size + (area->base_offset + area->size - size) % align;
|
||||
|
||||
/* does it fit? */
|
||||
if (real_size <= area->size)
|
||||
break;
|
||||
|
||||
if (area->size > largest_avail)
|
||||
largest_avail = area->size;
|
||||
}
|
||||
|
||||
if (!area) {
|
||||
area = exaFindAreaToEvict(pExaScr, size, align);
|
||||
|
||||
if (!area) {
|
||||
DBG_OFFSCREEN(("Alloc 0x%x -> NOSPACE\n", size));
|
||||
/* Could not allocate memory */
|
||||
ExaOffscreenValidate(pScreen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* adjust size needed to account for alignment loss for this area */
|
||||
real_size = size + (area->base_offset + area->size - size) % align;
|
||||
|
||||
/*
|
||||
* Kick out first area if in use
|
||||
*/
|
||||
if (area->state != ExaOffscreenAvail)
|
||||
area = ExaOffscreenKickOut(pScreen, area);
|
||||
/*
|
||||
* Now get the system to merge the other needed areas together
|
||||
*/
|
||||
while (area->size < real_size) {
|
||||
assert(area->next);
|
||||
assert(area->next->state == ExaOffscreenRemovable);
|
||||
(void) ExaOffscreenKickOut(pScreen, area->next);
|
||||
}
|
||||
}
|
||||
|
||||
/* save extra space in new area */
|
||||
if (real_size < area->size) {
|
||||
ExaOffscreenArea *new_area = malloc(sizeof(ExaOffscreenArea));
|
||||
|
||||
if (!new_area)
|
||||
return NULL;
|
||||
new_area->base_offset = area->base_offset;
|
||||
|
||||
new_area->offset = new_area->base_offset;
|
||||
new_area->align = 0;
|
||||
new_area->size = area->size - real_size;
|
||||
new_area->state = ExaOffscreenAvail;
|
||||
new_area->save = NULL;
|
||||
new_area->last_use = 0;
|
||||
new_area->eviction_cost = 0;
|
||||
new_area->next = area;
|
||||
new_area->prev = area->prev;
|
||||
if (area->prev->next)
|
||||
area->prev->next = new_area;
|
||||
else
|
||||
pExaScr->info->offScreenAreas = new_area;
|
||||
area->prev = new_area;
|
||||
area->base_offset = new_area->base_offset + new_area->size;
|
||||
area->size = real_size;
|
||||
}
|
||||
else
|
||||
pExaScr->numOffscreenAvailable--;
|
||||
|
||||
/*
|
||||
* Mark this area as in use
|
||||
*/
|
||||
if (locked)
|
||||
area->state = ExaOffscreenLocked;
|
||||
else
|
||||
area->state = ExaOffscreenRemovable;
|
||||
area->privData = privData;
|
||||
area->save = save;
|
||||
area->last_use = pExaScr->offScreenCounter++;
|
||||
area->offset = (area->base_offset + align - 1);
|
||||
area->offset -= area->offset % align;
|
||||
area->align = align;
|
||||
|
||||
ExaOffscreenValidate(pScreen);
|
||||
|
||||
DBG_OFFSCREEN(("Alloc 0x%x -> 0x%x (0x%x)\n", size,
|
||||
area->base_offset, area->offset));
|
||||
return area;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejects all offscreen areas, and uninitializes the offscreen memory manager.
|
||||
*/
|
||||
void
|
||||
ExaOffscreenSwapOut(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
ExaOffscreenValidate(pScreen);
|
||||
/* loop until a single free area spans the space */
|
||||
for (;;) {
|
||||
ExaOffscreenArea *area = pExaScr->info->offScreenAreas;
|
||||
|
||||
if (!area)
|
||||
break;
|
||||
if (area->state == ExaOffscreenAvail) {
|
||||
area = area->next;
|
||||
if (!area)
|
||||
break;
|
||||
}
|
||||
assert(area->state != ExaOffscreenAvail);
|
||||
(void) ExaOffscreenKickOut(pScreen, area);
|
||||
ExaOffscreenValidate(pScreen);
|
||||
}
|
||||
ExaOffscreenValidate(pScreen);
|
||||
ExaOffscreenFini(pScreen);
|
||||
}
|
||||
|
||||
/** Ejects all pixmaps managed by EXA. */
|
||||
static void
|
||||
ExaOffscreenEjectPixmaps(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
ExaOffscreenValidate(pScreen);
|
||||
/* loop until a single free area spans the space */
|
||||
for (;;) {
|
||||
ExaOffscreenArea *area;
|
||||
|
||||
for (area = pExaScr->info->offScreenAreas; area != NULL;
|
||||
area = area->next) {
|
||||
if (area->state == ExaOffscreenRemovable &&
|
||||
area->save == exaPixmapSave) {
|
||||
(void) ExaOffscreenKickOut(pScreen, area);
|
||||
ExaOffscreenValidate(pScreen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (area == NULL)
|
||||
break;
|
||||
}
|
||||
ExaOffscreenValidate(pScreen);
|
||||
}
|
||||
|
||||
void
|
||||
ExaOffscreenSwapIn(ScreenPtr pScreen)
|
||||
{
|
||||
exaOffscreenInit(pScreen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares EXA for disabling of FB access, or restoring it.
|
||||
*
|
||||
* In version 2.1, the disabling results in pixmaps being ejected, while other
|
||||
* allocations remain. With this plus the prevention of migration while
|
||||
* swappedOut is set, EXA by itself should not cause any access of the
|
||||
* framebuffer to occur while swapped out. Any remaining issues are the
|
||||
* responsibility of the driver.
|
||||
*
|
||||
* Prior to version 2.1, all allocations, including locked ones, are ejected
|
||||
* when access is disabled, and the allocator is torn down while swappedOut
|
||||
* is set. This is more drastic, and caused implementation difficulties for
|
||||
* many drivers that could otherwise handle the lack of FB access while
|
||||
* swapped out.
|
||||
*/
|
||||
void
|
||||
exaEnableDisableFBAccess(ScreenPtr pScreen, Bool enable)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS)
|
||||
return;
|
||||
|
||||
if (!enable && pExaScr->disableFbCount++ == 0) {
|
||||
if (pExaScr->info->exa_minor < 1)
|
||||
ExaOffscreenSwapOut(pScreen);
|
||||
else
|
||||
ExaOffscreenEjectPixmaps(pScreen);
|
||||
pExaScr->swappedOut = TRUE;
|
||||
}
|
||||
|
||||
if (enable && --pExaScr->disableFbCount == 0) {
|
||||
if (pExaScr->info->exa_minor < 1)
|
||||
ExaOffscreenSwapIn(pScreen);
|
||||
pExaScr->swappedOut = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* merge the next free area into this one */
|
||||
static void
|
||||
ExaOffscreenMerge(ExaScreenPrivPtr pExaScr, ExaOffscreenArea * area)
|
||||
{
|
||||
ExaOffscreenArea *next = area->next;
|
||||
|
||||
/* account for space */
|
||||
area->size += next->size;
|
||||
/* frob pointer */
|
||||
area->next = next->next;
|
||||
if (area->next)
|
||||
area->next->prev = area;
|
||||
else
|
||||
pExaScr->info->offScreenAreas->prev = area;
|
||||
free(next);
|
||||
|
||||
pExaScr->numOffscreenAvailable--;
|
||||
}
|
||||
|
||||
/**
|
||||
* exaOffscreenFree frees an allocation.
|
||||
*
|
||||
* @param pScreen current screen
|
||||
* @param area offscreen area to free
|
||||
*
|
||||
* exaOffscreenFree frees an allocation created by exaOffscreenAlloc. Note that
|
||||
* the save callback of the area is not called, and it is up to the driver to
|
||||
* do any cleanup necessary as a result.
|
||||
*
|
||||
* @return pointer to the newly freed area. This behavior should not be relied
|
||||
* on.
|
||||
*/
|
||||
ExaOffscreenArea *
|
||||
exaOffscreenFree(ScreenPtr pScreen, ExaOffscreenArea * area)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaOffscreenArea *next = area->next;
|
||||
ExaOffscreenArea *prev;
|
||||
|
||||
DBG_OFFSCREEN(("Free 0x%x -> 0x%x (0x%x)\n", area->size,
|
||||
area->base_offset, area->offset));
|
||||
ExaOffscreenValidate(pScreen);
|
||||
|
||||
area->state = ExaOffscreenAvail;
|
||||
area->save = NULL;
|
||||
area->last_use = 0;
|
||||
area->eviction_cost = 0;
|
||||
/*
|
||||
* Find previous area
|
||||
*/
|
||||
if (area == pExaScr->info->offScreenAreas)
|
||||
prev = NULL;
|
||||
else
|
||||
prev = area->prev;
|
||||
|
||||
pExaScr->numOffscreenAvailable++;
|
||||
|
||||
/* link with next area if free */
|
||||
if (next && next->state == ExaOffscreenAvail)
|
||||
ExaOffscreenMerge(pExaScr, area);
|
||||
|
||||
/* link with prev area if free */
|
||||
if (prev && prev->state == ExaOffscreenAvail) {
|
||||
area = prev;
|
||||
ExaOffscreenMerge(pExaScr, area);
|
||||
}
|
||||
|
||||
ExaOffscreenValidate(pScreen);
|
||||
DBG_OFFSCREEN(("\tdone freeing\n"));
|
||||
return area;
|
||||
}
|
||||
|
||||
void
|
||||
ExaOffscreenMarkUsed(PixmapPtr pPixmap)
|
||||
{
|
||||
ExaPixmapPriv(pPixmap);
|
||||
ExaScreenPriv(pPixmap->drawable.pScreen);
|
||||
|
||||
if (!pExaPixmap || !pExaPixmap->area)
|
||||
return;
|
||||
|
||||
pExaPixmap->area->last_use = pExaScr->offScreenCounter++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defragment offscreen memory by compacting allocated areas at the end of it,
|
||||
* leaving the total amount of memory available as a single area at the
|
||||
* beginning (when there are no pinned allocations).
|
||||
*/
|
||||
_X_HIDDEN ExaOffscreenArea *
|
||||
ExaOffscreenDefragment(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaOffscreenArea *area, *largest_available = NULL;
|
||||
int largest_size = 0;
|
||||
PixmapPtr pDstPix;
|
||||
ExaPixmapPrivPtr pExaDstPix;
|
||||
|
||||
pDstPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, 0, 0);
|
||||
|
||||
if (!pDstPix)
|
||||
return NULL;
|
||||
|
||||
pExaDstPix = ExaGetPixmapPriv(pDstPix);
|
||||
pExaDstPix->use_gpu_copy = TRUE;
|
||||
|
||||
for (area = pExaScr->info->offScreenAreas->prev;
|
||||
area != pExaScr->info->offScreenAreas;) {
|
||||
ExaOffscreenArea *prev = area->prev;
|
||||
PixmapPtr pSrcPix;
|
||||
ExaPixmapPrivPtr pExaSrcPix;
|
||||
Bool save_use_gpu_copy;
|
||||
int save_pitch;
|
||||
|
||||
if (area->state != ExaOffscreenAvail ||
|
||||
prev->state == ExaOffscreenLocked ||
|
||||
(prev->state == ExaOffscreenRemovable &&
|
||||
prev->save != exaPixmapSave)) {
|
||||
area = prev;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prev->state == ExaOffscreenAvail) {
|
||||
if (area == largest_available) {
|
||||
largest_available = prev;
|
||||
largest_size += prev->size;
|
||||
}
|
||||
area = prev;
|
||||
ExaOffscreenMerge(pExaScr, area);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (area->size > largest_size) {
|
||||
largest_available = area;
|
||||
largest_size = area->size;
|
||||
}
|
||||
|
||||
pSrcPix = prev->privData;
|
||||
pExaSrcPix = ExaGetPixmapPriv(pSrcPix);
|
||||
|
||||
pExaDstPix->fb_ptr = pExaScr->info->memoryBase +
|
||||
area->base_offset + area->size - prev->size + prev->base_offset -
|
||||
prev->offset;
|
||||
pExaDstPix->fb_ptr -= (unsigned long) pExaDstPix->fb_ptr % prev->align;
|
||||
|
||||
if (pExaDstPix->fb_ptr <= pExaSrcPix->fb_ptr) {
|
||||
area = prev;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(pExaScr->info->flags & EXA_SUPPORTS_OFFSCREEN_OVERLAPS) &&
|
||||
(pExaSrcPix->fb_ptr + prev->size) > pExaDstPix->fb_ptr) {
|
||||
area = prev;
|
||||
continue;
|
||||
}
|
||||
|
||||
save_use_gpu_copy = pExaSrcPix->use_gpu_copy;
|
||||
save_pitch = pSrcPix->devKind;
|
||||
|
||||
pExaSrcPix->use_gpu_copy = TRUE;
|
||||
pSrcPix->devKind = pExaSrcPix->fb_pitch;
|
||||
|
||||
pDstPix->drawable.width = pSrcPix->drawable.width;
|
||||
pDstPix->devKind = pSrcPix->devKind;
|
||||
pDstPix->drawable.height = pSrcPix->drawable.height;
|
||||
pDstPix->drawable.depth = pSrcPix->drawable.depth;
|
||||
pDstPix->drawable.bitsPerPixel = pSrcPix->drawable.bitsPerPixel;
|
||||
|
||||
if (!pExaScr->info->PrepareCopy(pSrcPix, pDstPix, -1, -1, GXcopy, ~0)) {
|
||||
pExaSrcPix->use_gpu_copy = save_use_gpu_copy;
|
||||
pSrcPix->devKind = save_pitch;
|
||||
area = prev;
|
||||
continue;
|
||||
}
|
||||
|
||||
pExaScr->info->Copy(pDstPix, 0, 0, 0, 0, pDstPix->drawable.width,
|
||||
pDstPix->drawable.height);
|
||||
pExaScr->info->DoneCopy(pDstPix);
|
||||
exaMarkSync(pScreen);
|
||||
|
||||
DBG_OFFSCREEN(("Before swap: prev=0x%08x-0x%08x-0x%08x area=0x%08x-0x%08x-0x%08x\n", prev->base_offset, prev->offset, prev->base_offset + prev->size, area->base_offset, area->offset, area->base_offset + area->size));
|
||||
|
||||
/* Calculate swapped area offsets and sizes */
|
||||
area->base_offset = prev->base_offset;
|
||||
area->offset = area->base_offset;
|
||||
prev->offset += pExaDstPix->fb_ptr - pExaSrcPix->fb_ptr;
|
||||
assert(prev->offset >= pExaScr->info->offScreenBase);
|
||||
assert(prev->offset < pExaScr->info->memorySize);
|
||||
prev->base_offset = prev->offset;
|
||||
if (area->next)
|
||||
prev->size = area->next->base_offset - prev->base_offset;
|
||||
else
|
||||
prev->size = pExaScr->info->memorySize - prev->base_offset;
|
||||
area->size = prev->base_offset - area->base_offset;
|
||||
|
||||
DBG_OFFSCREEN(("After swap: area=0x%08x-0x%08x-0x%08x prev=0x%08x-0x%08x-0x%08x\n", area->base_offset, area->offset, area->base_offset + area->size, prev->base_offset, prev->offset, prev->base_offset + prev->size));
|
||||
|
||||
/* Swap areas in list */
|
||||
if (area->next)
|
||||
area->next->prev = prev;
|
||||
else
|
||||
pExaScr->info->offScreenAreas->prev = prev;
|
||||
if (prev->prev->next)
|
||||
prev->prev->next = area;
|
||||
else
|
||||
pExaScr->info->offScreenAreas = area;
|
||||
prev->next = area->next;
|
||||
area->next = prev;
|
||||
area->prev = prev->prev;
|
||||
prev->prev = area;
|
||||
if (!area->prev->next)
|
||||
pExaScr->info->offScreenAreas = area;
|
||||
|
||||
#if DEBUG_OFFSCREEN
|
||||
if (prev->prev == prev || prev->next == prev)
|
||||
ErrorF("Whoops, prev points to itself!\n");
|
||||
|
||||
if (area->prev == area || area->next == area)
|
||||
ErrorF("Whoops, area points to itself!\n");
|
||||
#endif
|
||||
|
||||
pExaSrcPix->fb_ptr = pExaDstPix->fb_ptr;
|
||||
pExaSrcPix->use_gpu_copy = save_use_gpu_copy;
|
||||
pSrcPix->devKind = save_pitch;
|
||||
}
|
||||
|
||||
pDstPix->drawable.width = 0;
|
||||
pDstPix->drawable.height = 0;
|
||||
pDstPix->drawable.depth = 0;
|
||||
pDstPix->drawable.bitsPerPixel = 0;
|
||||
|
||||
(*pScreen->DestroyPixmap) (pDstPix);
|
||||
|
||||
if (area->state == ExaOffscreenAvail && area->size > largest_size)
|
||||
return area;
|
||||
|
||||
return largest_available;
|
||||
}
|
||||
|
||||
/**
|
||||
* exaOffscreenInit initializes the offscreen memory manager.
|
||||
*
|
||||
* @param pScreen current screen
|
||||
*
|
||||
* exaOffscreenInit is called by exaDriverInit to set up the memory manager for
|
||||
* the screen, if any offscreen memory is available.
|
||||
*/
|
||||
Bool
|
||||
exaOffscreenInit(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaOffscreenArea *area;
|
||||
|
||||
/* Allocate a big free area */
|
||||
area = malloc(sizeof(ExaOffscreenArea));
|
||||
|
||||
if (!area)
|
||||
return FALSE;
|
||||
|
||||
area->state = ExaOffscreenAvail;
|
||||
area->base_offset = pExaScr->info->offScreenBase;
|
||||
area->offset = area->base_offset;
|
||||
area->align = 0;
|
||||
area->size = pExaScr->info->memorySize - area->base_offset;
|
||||
area->save = NULL;
|
||||
area->next = NULL;
|
||||
area->prev = area;
|
||||
area->last_use = 0;
|
||||
area->eviction_cost = 0;
|
||||
|
||||
/* Add it to the free areas */
|
||||
pExaScr->info->offScreenAreas = area;
|
||||
pExaScr->offScreenCounter = 1;
|
||||
pExaScr->numOffscreenAvailable = 1;
|
||||
|
||||
ExaOffscreenValidate(pScreen);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
ExaOffscreenFini(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaOffscreenArea *area;
|
||||
|
||||
/* just free all of the area records */
|
||||
while ((area = pExaScr->info->offScreenAreas)) {
|
||||
pExaScr->info->offScreenAreas = area->next;
|
||||
free(area);
|
||||
}
|
||||
}
|
735
exa/exa_priv.h
735
exa/exa_priv.h
|
@ -1,735 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (C) 2000 Keith Packard, member of The XFree86 Project, Inc.
|
||||
* 2005 Zack Rusin, Trolltech
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of Keith Packard not be used in
|
||||
* advertising or publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. Keith Packard makes no
|
||||
* representations about the suitability of this software for any purpose. It
|
||||
* is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef EXAPRIV_H
|
||||
#define EXAPRIV_H
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include "exa.h"
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xproto.h>
|
||||
#ifdef MITSHM
|
||||
#include "shmint.h"
|
||||
#endif
|
||||
#include "scrnintstr.h"
|
||||
#include "pixmapstr.h"
|
||||
#include "windowstr.h"
|
||||
#include "servermd.h"
|
||||
#include "colormapst.h"
|
||||
#include "gcstruct.h"
|
||||
#include "input.h"
|
||||
#include "mipointer.h"
|
||||
#include "mi.h"
|
||||
#include "dix.h"
|
||||
#include "fb.h"
|
||||
#include "fboverlay.h"
|
||||
#include "fbpict.h"
|
||||
#include "glyphstr.h"
|
||||
#include "damage.h"
|
||||
|
||||
#define DEBUG_TRACE_FALL 0
|
||||
#define DEBUG_MIGRATE 0
|
||||
#define DEBUG_PIXMAP 0
|
||||
#define DEBUG_OFFSCREEN 0
|
||||
#define DEBUG_GLYPH_CACHE 0
|
||||
|
||||
#if DEBUG_TRACE_FALL
|
||||
#define EXA_FALLBACK(x) \
|
||||
do { \
|
||||
ErrorF("EXA fallback at %s: ", __FUNCTION__); \
|
||||
ErrorF x; \
|
||||
} while (0)
|
||||
|
||||
char
|
||||
exaDrawableLocation(DrawablePtr pDrawable);
|
||||
#else
|
||||
#define EXA_FALLBACK(x)
|
||||
#endif
|
||||
|
||||
#if DEBUG_PIXMAP
|
||||
#define DBG_PIXMAP(a) ErrorF a
|
||||
#else
|
||||
#define DBG_PIXMAP(a)
|
||||
#endif
|
||||
|
||||
#ifndef EXA_MAX_FB
|
||||
#define EXA_MAX_FB FB_OVERLAY_MAX
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define EXA_FatalErrorDebug(x) FatalError x
|
||||
#define EXA_FatalErrorDebugWithRet(x, ret) FatalError x
|
||||
#else
|
||||
#define EXA_FatalErrorDebug(x) ErrorF x
|
||||
#define EXA_FatalErrorDebugWithRet(x, ret) \
|
||||
do { \
|
||||
ErrorF x; \
|
||||
return ret; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This is the list of migration heuristics supported by EXA. See
|
||||
* exaDoMigration() for what their implementations do.
|
||||
*/
|
||||
enum ExaMigrationHeuristic {
|
||||
ExaMigrationGreedy,
|
||||
ExaMigrationAlways,
|
||||
ExaMigrationSmart
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned char sha1[20];
|
||||
} ExaCachedGlyphRec, *ExaCachedGlyphPtr;
|
||||
|
||||
typedef struct {
|
||||
/* The identity of the cache, statically configured at initialization */
|
||||
unsigned int format;
|
||||
int glyphWidth;
|
||||
int glyphHeight;
|
||||
|
||||
int size; /* Size of cache; eventually this should be dynamically determined */
|
||||
|
||||
/* Hash table mapping from glyph sha1 to position in the glyph; we use
|
||||
* open addressing with a hash table size determined based on size and large
|
||||
* enough so that we always have a good amount of free space, so we can
|
||||
* use linear probing. (Linear probing is preferable to double hashing
|
||||
* here because it allows us to easily remove entries.)
|
||||
*/
|
||||
int *hashEntries;
|
||||
int hashSize;
|
||||
|
||||
ExaCachedGlyphPtr glyphs;
|
||||
int glyphCount; /* Current number of glyphs */
|
||||
|
||||
PicturePtr picture; /* Where the glyphs of the cache are stored */
|
||||
int yOffset; /* y location within the picture where the cache starts */
|
||||
int columns; /* Number of columns the glyphs are laid out in */
|
||||
int evictionPosition; /* Next random position to evict a glyph */
|
||||
} ExaGlyphCacheRec, *ExaGlyphCachePtr;
|
||||
|
||||
#define EXA_NUM_GLYPH_CACHES 4
|
||||
|
||||
#define EXA_FALLBACK_COPYWINDOW (1 << 0)
|
||||
#define EXA_ACCEL_COPYWINDOW (1 << 1)
|
||||
|
||||
typedef struct _ExaMigrationRec {
|
||||
Bool as_dst;
|
||||
Bool as_src;
|
||||
PixmapPtr pPix;
|
||||
RegionPtr pReg;
|
||||
} ExaMigrationRec, *ExaMigrationPtr;
|
||||
|
||||
typedef void (*EnableDisableFBAccessProcPtr) (ScreenPtr, Bool);
|
||||
typedef struct {
|
||||
ExaDriverPtr info;
|
||||
ScreenBlockHandlerProcPtr SavedBlockHandler;
|
||||
ScreenWakeupHandlerProcPtr SavedWakeupHandler;
|
||||
CreateGCProcPtr SavedCreateGC;
|
||||
CloseScreenProcPtr SavedCloseScreen;
|
||||
GetImageProcPtr SavedGetImage;
|
||||
GetSpansProcPtr SavedGetSpans;
|
||||
CreatePixmapProcPtr SavedCreatePixmap;
|
||||
DestroyPixmapProcPtr SavedDestroyPixmap;
|
||||
CopyWindowProcPtr SavedCopyWindow;
|
||||
ChangeWindowAttributesProcPtr SavedChangeWindowAttributes;
|
||||
BitmapToRegionProcPtr SavedBitmapToRegion;
|
||||
CreateScreenResourcesProcPtr SavedCreateScreenResources;
|
||||
ModifyPixmapHeaderProcPtr SavedModifyPixmapHeader;
|
||||
SharePixmapBackingProcPtr SavedSharePixmapBacking;
|
||||
SetSharedPixmapBackingProcPtr SavedSetSharedPixmapBacking;
|
||||
SourceValidateProcPtr SavedSourceValidate;
|
||||
CompositeProcPtr SavedComposite;
|
||||
TrianglesProcPtr SavedTriangles;
|
||||
GlyphsProcPtr SavedGlyphs;
|
||||
TrapezoidsProcPtr SavedTrapezoids;
|
||||
AddTrapsProcPtr SavedAddTraps;
|
||||
void (*do_migration) (ExaMigrationPtr pixmaps, int npixmaps,
|
||||
Bool can_accel);
|
||||
Bool (*pixmap_has_gpu_copy) (PixmapPtr pPixmap);
|
||||
void (*do_move_in_pixmap) (PixmapPtr pPixmap);
|
||||
void (*do_move_out_pixmap) (PixmapPtr pPixmap);
|
||||
void (*prepare_access_reg) (PixmapPtr pPixmap, int index, RegionPtr pReg);
|
||||
|
||||
Bool swappedOut;
|
||||
enum ExaMigrationHeuristic migration;
|
||||
Bool checkDirtyCorrectness;
|
||||
unsigned disableFbCount;
|
||||
Bool optimize_migration;
|
||||
unsigned offScreenCounter;
|
||||
unsigned numOffscreenAvailable;
|
||||
CARD32 lastDefragment;
|
||||
CARD32 nextDefragment;
|
||||
PixmapPtr deferred_mixed_pixmap;
|
||||
|
||||
/* Reference counting for accessed pixmaps */
|
||||
struct {
|
||||
PixmapPtr pixmap;
|
||||
int count;
|
||||
Bool retval;
|
||||
} access[EXA_NUM_PREPARE_INDICES];
|
||||
|
||||
/* Holds information on fallbacks that cannot be relayed otherwise. */
|
||||
unsigned int fallback_flags;
|
||||
unsigned int fallback_counter;
|
||||
|
||||
ExaGlyphCacheRec glyphCaches[EXA_NUM_GLYPH_CACHES];
|
||||
|
||||
/**
|
||||
* Regions affected by fallback composite source / mask operations.
|
||||
*/
|
||||
|
||||
RegionRec srcReg;
|
||||
RegionRec maskReg;
|
||||
PixmapPtr srcPix;
|
||||
PixmapPtr maskPix;
|
||||
|
||||
DevPrivateKeyRec pixmapPrivateKeyRec;
|
||||
DevPrivateKeyRec gcPrivateKeyRec;
|
||||
} ExaScreenPrivRec, *ExaScreenPrivPtr;
|
||||
|
||||
extern DevPrivateKeyRec exaScreenPrivateKeyRec;
|
||||
|
||||
#define exaScreenPrivateKey (&exaScreenPrivateKeyRec)
|
||||
|
||||
#define ExaGetScreenPriv(s) ((ExaScreenPrivPtr)dixGetPrivate(&(s)->devPrivates, exaScreenPrivateKey))
|
||||
#define ExaScreenPriv(s) ExaScreenPrivPtr pExaScr = ExaGetScreenPriv(s)
|
||||
|
||||
#define ExaGetGCPriv(gc) ((ExaGCPrivPtr)dixGetPrivateAddr(&(gc)->devPrivates, &ExaGetScreenPriv(gc->pScreen)->gcPrivateKeyRec))
|
||||
#define ExaGCPriv(gc) ExaGCPrivPtr pExaGC = ExaGetGCPriv(gc)
|
||||
|
||||
/*
|
||||
* Some macros to deal with function wrapping.
|
||||
*/
|
||||
#define wrap(priv, real, mem, func) {\
|
||||
priv->Saved##mem = real->mem; \
|
||||
real->mem = func; \
|
||||
}
|
||||
|
||||
#define unwrap(priv, real, mem) {\
|
||||
real->mem = priv->Saved##mem; \
|
||||
}
|
||||
|
||||
#ifdef HAVE_TYPEOF
|
||||
#define swap(priv, real, mem) {\
|
||||
typeof(real->mem) tmp = priv->Saved##mem; \
|
||||
priv->Saved##mem = real->mem; \
|
||||
real->mem = tmp; \
|
||||
}
|
||||
#else
|
||||
#define swap(priv, real, mem) {\
|
||||
const void *tmp = priv->Saved##mem; \
|
||||
priv->Saved##mem = real->mem; \
|
||||
real->mem = tmp; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define EXA_PRE_FALLBACK(_screen_) \
|
||||
ExaScreenPriv(_screen_); \
|
||||
pExaScr->fallback_counter++;
|
||||
|
||||
#define EXA_POST_FALLBACK(_screen_) \
|
||||
pExaScr->fallback_counter--;
|
||||
|
||||
#define EXA_PRE_FALLBACK_GC(_gc_) \
|
||||
ExaScreenPriv(_gc_->pScreen); \
|
||||
ExaGCPriv(_gc_); \
|
||||
pExaScr->fallback_counter++; \
|
||||
swap(pExaGC, _gc_, ops);
|
||||
|
||||
#define EXA_POST_FALLBACK_GC(_gc_) \
|
||||
pExaScr->fallback_counter--; \
|
||||
swap(pExaGC, _gc_, ops);
|
||||
|
||||
/** Align an offset to an arbitrary alignment */
|
||||
#define EXA_ALIGN(offset, align) (((offset) + (align) - 1) - \
|
||||
(((offset) + (align) - 1) % (align)))
|
||||
/** Align an offset to a power-of-two alignment */
|
||||
#define EXA_ALIGN2(offset, align) (((offset) + (align) - 1) & ~((align) - 1))
|
||||
|
||||
#define EXA_PIXMAP_SCORE_MOVE_IN 10
|
||||
#define EXA_PIXMAP_SCORE_MAX 20
|
||||
#define EXA_PIXMAP_SCORE_MOVE_OUT -10
|
||||
#define EXA_PIXMAP_SCORE_MIN -20
|
||||
#define EXA_PIXMAP_SCORE_PINNED 1000
|
||||
#define EXA_PIXMAP_SCORE_INIT 1001
|
||||
|
||||
#define ExaGetPixmapPriv(p) ((ExaPixmapPrivPtr)dixGetPrivateAddr(&(p)->devPrivates, &ExaGetScreenPriv((p)->drawable.pScreen)->pixmapPrivateKeyRec))
|
||||
#define ExaPixmapPriv(p) ExaPixmapPrivPtr pExaPixmap = ExaGetPixmapPriv(p)
|
||||
|
||||
#define EXA_RANGE_PITCH (1 << 0)
|
||||
#define EXA_RANGE_WIDTH (1 << 1)
|
||||
#define EXA_RANGE_HEIGHT (1 << 2)
|
||||
|
||||
typedef struct {
|
||||
ExaOffscreenArea *area;
|
||||
int score; /**< score for the move-in vs move-out heuristic */
|
||||
Bool use_gpu_copy;
|
||||
|
||||
CARD8 *sys_ptr; /**< pointer to pixmap data in system memory */
|
||||
int sys_pitch; /**< pitch of pixmap in system memory */
|
||||
|
||||
CARD8 *fb_ptr; /**< pointer to pixmap data in framebuffer memory */
|
||||
int fb_pitch; /**< pitch of pixmap in framebuffer memory */
|
||||
unsigned int fb_size; /**< size of pixmap in framebuffer memory */
|
||||
|
||||
/**
|
||||
* Holds information about whether this pixmap can be used for
|
||||
* acceleration (== 0) or not (> 0).
|
||||
*
|
||||
* Contains a OR'ed combination of the following values:
|
||||
* EXA_RANGE_PITCH - set if the pixmap's pitch is out of range
|
||||
* EXA_RANGE_WIDTH - set if the pixmap's width is out of range
|
||||
* EXA_RANGE_HEIGHT - set if the pixmap's height is out of range
|
||||
*/
|
||||
unsigned int accel_blocked;
|
||||
|
||||
/**
|
||||
* The damage record contains the areas of the pixmap's current location
|
||||
* (framebuffer or system) that have been damaged compared to the other
|
||||
* location.
|
||||
*/
|
||||
DamagePtr pDamage;
|
||||
/**
|
||||
* The valid regions mark the valid bits (at least, as they're derived from
|
||||
* damage, which may be overreported) of a pixmap's system and FB copies.
|
||||
*/
|
||||
RegionRec validSys, validFB;
|
||||
/**
|
||||
* Driver private storage per EXA pixmap
|
||||
*/
|
||||
void *driverPriv;
|
||||
} ExaPixmapPrivRec, *ExaPixmapPrivPtr;
|
||||
|
||||
typedef struct {
|
||||
/* GC values from the layer below. */
|
||||
const GCOps *Savedops;
|
||||
const GCFuncs *Savedfuncs;
|
||||
} ExaGCPrivRec, *ExaGCPrivPtr;
|
||||
|
||||
typedef struct {
|
||||
PicturePtr pDst;
|
||||
INT16 xSrc;
|
||||
INT16 ySrc;
|
||||
INT16 xMask;
|
||||
INT16 yMask;
|
||||
INT16 xDst;
|
||||
INT16 yDst;
|
||||
INT16 width;
|
||||
INT16 height;
|
||||
} ExaCompositeRectRec, *ExaCompositeRectPtr;
|
||||
|
||||
/**
|
||||
* exaDDXDriverInit must be implemented by the DDX using EXA, and is the place
|
||||
* to set EXA options or hook in screen functions to handle using EXA as the AA.
|
||||
*/
|
||||
void exaDDXDriverInit(ScreenPtr pScreen);
|
||||
|
||||
/* exa_unaccel.c */
|
||||
void
|
||||
exaPrepareAccessGC(GCPtr pGC);
|
||||
|
||||
void
|
||||
exaFinishAccessGC(GCPtr pGC);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
|
||||
DDXPointPtr ppt, int *pwidth, int fSorted);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
|
||||
DDXPointPtr ppt, int *pwidth, int nspans, int fSorted);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
|
||||
int x, int y, int w, int h, int leftPad, int format,
|
||||
char *bits);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckCopyNtoN(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
|
||||
BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
|
||||
Bool upsidedown, Pixel bitplane, void *closure);
|
||||
|
||||
RegionPtr
|
||||
|
||||
ExaCheckCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
|
||||
int srcx, int srcy, int w, int h, int dstx, int dsty);
|
||||
|
||||
RegionPtr
|
||||
|
||||
ExaCheckCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
|
||||
int srcx, int srcy, int w, int h, int dstx, int dsty,
|
||||
unsigned long bitPlane);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
|
||||
DDXPointPtr pptInit);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPolylines(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int mode, int npt, DDXPointPtr ppt);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPolySegment(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int nsegInit, xSegment * pSegInit);
|
||||
|
||||
void
|
||||
ExaCheckPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int nrect, xRectangle *prect);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int x, int y, unsigned int nglyph,
|
||||
CharInfoPtr * ppci, void *pglyphBase);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int x, int y, unsigned int nglyph,
|
||||
CharInfoPtr * ppci, void *pglyphBase);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPushPixels(GCPtr pGC, PixmapPtr pBitmap,
|
||||
DrawablePtr pDrawable, int w, int h, int x, int y);
|
||||
|
||||
void
|
||||
ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
|
||||
unsigned int format, unsigned long planeMask, char *d);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckGetSpans(DrawablePtr pDrawable,
|
||||
int wMax,
|
||||
DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckAddTraps(PicturePtr pPicture,
|
||||
INT16 x_off, INT16 y_off, int ntrap, xTrap * traps);
|
||||
|
||||
/* exa_accel.c */
|
||||
|
||||
static _X_INLINE Bool
|
||||
exaGCReadsDestination(DrawablePtr pDrawable, unsigned long planemask,
|
||||
unsigned int fillStyle, unsigned char alu,
|
||||
Bool clientClip)
|
||||
{
|
||||
return ((alu != GXcopy && alu != GXclear && alu != GXset &&
|
||||
alu != GXcopyInverted) || fillStyle == FillStippled ||
|
||||
clientClip != FALSE || !EXA_PM_IS_SOLID(pDrawable, planemask));
|
||||
}
|
||||
|
||||
void
|
||||
exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
|
||||
|
||||
Bool
|
||||
|
||||
exaFillRegionTiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
|
||||
DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
|
||||
Bool clientClip);
|
||||
|
||||
void
|
||||
|
||||
exaGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
|
||||
unsigned int format, unsigned long planeMask, char *d);
|
||||
|
||||
RegionPtr
|
||||
|
||||
exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
|
||||
int srcx, int srcy, int width, int height, int dstx, int dsty);
|
||||
|
||||
Bool
|
||||
|
||||
exaHWCopyNtoN(DrawablePtr pSrcDrawable,
|
||||
DrawablePtr pDstDrawable,
|
||||
GCPtr pGC,
|
||||
BoxPtr pbox,
|
||||
int nbox, int dx, int dy, Bool reverse, Bool upsidedown);
|
||||
|
||||
void
|
||||
|
||||
exaCopyNtoN(DrawablePtr pSrcDrawable,
|
||||
DrawablePtr pDstDrawable,
|
||||
GCPtr pGC,
|
||||
BoxPtr pbox,
|
||||
int nbox,
|
||||
int dx,
|
||||
int dy,
|
||||
Bool reverse, Bool upsidedown, Pixel bitplane, void *closure);
|
||||
|
||||
extern const GCOps exaOps;
|
||||
|
||||
void
|
||||
|
||||
ExaCheckComposite(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pMask,
|
||||
PicturePtr pDst,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc,
|
||||
INT16 xMask,
|
||||
INT16 yMask,
|
||||
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckGlyphs(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pDst,
|
||||
PictFormatPtr maskFormat,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs);
|
||||
|
||||
/* exa_offscreen.c */
|
||||
void
|
||||
ExaOffscreenSwapOut(ScreenPtr pScreen);
|
||||
|
||||
void
|
||||
ExaOffscreenSwapIn(ScreenPtr pScreen);
|
||||
|
||||
ExaOffscreenArea *ExaOffscreenDefragment(ScreenPtr pScreen);
|
||||
|
||||
Bool
|
||||
exaOffscreenInit(ScreenPtr pScreen);
|
||||
|
||||
void
|
||||
ExaOffscreenFini(ScreenPtr pScreen);
|
||||
|
||||
/* exa.c */
|
||||
Bool
|
||||
ExaDoPrepareAccess(PixmapPtr pPixmap, int index);
|
||||
|
||||
void
|
||||
exaPrepareAccess(DrawablePtr pDrawable, int index);
|
||||
|
||||
void
|
||||
exaFinishAccess(DrawablePtr pDrawable, int index);
|
||||
|
||||
void
|
||||
exaDestroyPixmap(PixmapPtr pPixmap);
|
||||
|
||||
void
|
||||
exaPixmapDirty(PixmapPtr pPix, int x1, int y1, int x2, int y2);
|
||||
|
||||
void
|
||||
|
||||
exaGetDrawableDeltas(DrawablePtr pDrawable, PixmapPtr pPixmap,
|
||||
int *xp, int *yp);
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy(PixmapPtr p);
|
||||
|
||||
PixmapPtr
|
||||
exaGetOffscreenPixmap(DrawablePtr pDrawable, int *xp, int *yp);
|
||||
|
||||
PixmapPtr
|
||||
exaGetDrawablePixmap(DrawablePtr pDrawable);
|
||||
|
||||
void
|
||||
|
||||
exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
|
||||
int w, int h, int bpp);
|
||||
|
||||
void
|
||||
|
||||
exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
|
||||
int w, int h, int bpp);
|
||||
|
||||
void
|
||||
exaDoMigration(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
|
||||
|
||||
Bool
|
||||
exaPixmapIsPinned(PixmapPtr pPix);
|
||||
|
||||
extern const GCFuncs exaGCFuncs;
|
||||
|
||||
/* exa_classic.c */
|
||||
PixmapPtr
|
||||
|
||||
exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
|
||||
unsigned usage_hint);
|
||||
|
||||
Bool
|
||||
|
||||
exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height,
|
||||
int depth, int bitsPerPixel, int devKind,
|
||||
void *pPixData);
|
||||
|
||||
Bool
|
||||
exaDestroyPixmap_classic(PixmapPtr pPixmap);
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap);
|
||||
|
||||
/* exa_driver.c */
|
||||
PixmapPtr
|
||||
|
||||
exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
|
||||
unsigned usage_hint);
|
||||
|
||||
Bool
|
||||
|
||||
exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height,
|
||||
int depth, int bitsPerPixel, int devKind,
|
||||
void *pPixData);
|
||||
|
||||
Bool
|
||||
exaDestroyPixmap_driver(PixmapPtr pPixmap);
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap);
|
||||
|
||||
/* exa_mixed.c */
|
||||
PixmapPtr
|
||||
|
||||
exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
|
||||
unsigned usage_hint);
|
||||
|
||||
Bool
|
||||
|
||||
exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
|
||||
int bitsPerPixel, int devKind, void *pPixData);
|
||||
|
||||
Bool
|
||||
exaDestroyPixmap_mixed(PixmapPtr pPixmap);
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap);
|
||||
|
||||
/* exa_migration_mixed.c */
|
||||
void
|
||||
exaCreateDriverPixmap_mixed(PixmapPtr pPixmap);
|
||||
|
||||
void
|
||||
exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
|
||||
|
||||
void
|
||||
exaMoveInPixmap_mixed(PixmapPtr pPixmap);
|
||||
|
||||
void
|
||||
exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure);
|
||||
|
||||
void
|
||||
exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg);
|
||||
|
||||
Bool
|
||||
exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap, void *handle);
|
||||
Bool
|
||||
exaSharePixmapBacking_mixed(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p);
|
||||
|
||||
/* exa_render.c */
|
||||
Bool
|
||||
exaOpReadsDestination(CARD8 op);
|
||||
|
||||
void
|
||||
|
||||
exaComposite(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pMask,
|
||||
PicturePtr pDst,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc,
|
||||
INT16 xMask,
|
||||
INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
|
||||
|
||||
void
|
||||
|
||||
exaCompositeRects(CARD8 op,
|
||||
PicturePtr Src,
|
||||
PicturePtr pMask,
|
||||
PicturePtr pDst, int nrect, ExaCompositeRectPtr rects);
|
||||
|
||||
void
|
||||
|
||||
exaTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
|
||||
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
|
||||
int ntrap, xTrapezoid * traps);
|
||||
|
||||
void
|
||||
|
||||
exaTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
|
||||
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
|
||||
int ntri, xTriangle * tris);
|
||||
|
||||
/* exa_glyph.c */
|
||||
void
|
||||
exaGlyphsInit(ScreenPtr pScreen);
|
||||
|
||||
void
|
||||
exaGlyphsFini(ScreenPtr pScreen);
|
||||
|
||||
void
|
||||
|
||||
exaGlyphs(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pDst,
|
||||
PictFormatPtr maskFormat,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs);
|
||||
|
||||
/* exa_migration_classic.c */
|
||||
void
|
||||
exaCopyDirtyToSys(ExaMigrationPtr migrate);
|
||||
|
||||
void
|
||||
exaCopyDirtyToFb(ExaMigrationPtr migrate);
|
||||
|
||||
void
|
||||
exaDoMigration_classic(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
|
||||
|
||||
void
|
||||
exaPixmapSave(ScreenPtr pScreen, ExaOffscreenArea * area);
|
||||
|
||||
void
|
||||
exaMoveOutPixmap_classic(PixmapPtr pPixmap);
|
||||
|
||||
void
|
||||
exaMoveInPixmap_classic(PixmapPtr pPixmap);
|
||||
|
||||
void
|
||||
exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg);
|
||||
|
||||
#endif /* EXAPRIV_H */
|
1229
exa/exa_render.c
1229
exa/exa_render.c
File diff suppressed because it is too large
Load Diff
|
@ -1,733 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright © 1999 Keith Packard
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of Keith Packard not be used in
|
||||
* advertising or publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. Keith Packard makes no
|
||||
* representations about the suitability of this software for any purpose. It
|
||||
* is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "exa_priv.h"
|
||||
|
||||
#include "mipict.h"
|
||||
|
||||
/*
|
||||
* These functions wrap the low-level fb rendering functions and
|
||||
* synchronize framebuffer/accelerated drawing by stalling until
|
||||
* the accelerator is idle
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calls exaPrepareAccess with EXA_PREPARE_SRC for the tile, if that is the
|
||||
* current fill style.
|
||||
*
|
||||
* Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
|
||||
* 1bpp and never in fb, so we don't worry about them.
|
||||
* We should worry about them for completeness sake and going forward.
|
||||
*/
|
||||
void
|
||||
exaPrepareAccessGC(GCPtr pGC)
|
||||
{
|
||||
if (pGC->stipple)
|
||||
exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
|
||||
if (pGC->fillStyle == FillTiled)
|
||||
exaPrepareAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes access to the tile in the GC, if used.
|
||||
*/
|
||||
void
|
||||
exaFinishAccessGC(GCPtr pGC)
|
||||
{
|
||||
if (pGC->fillStyle == FillTiled)
|
||||
exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
|
||||
if (pGC->stipple)
|
||||
exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
|
||||
}
|
||||
|
||||
#if DEBUG_TRACE_FALL
|
||||
char
|
||||
exaDrawableLocation(DrawablePtr pDrawable)
|
||||
{
|
||||
return exaDrawableIsOffscreen(pDrawable) ? 's' : 'm';
|
||||
}
|
||||
#endif /* DEBUG_TRACE_FALL */
|
||||
|
||||
void
|
||||
ExaCheckFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
|
||||
DDXPointPtr ppt, int *pwidth, int fSorted)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->FillSpans(pDrawable, pGC, nspans, ppt, pwidth, fSorted);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
|
||||
DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
pGC->ops->SetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
|
||||
int x, int y, int w, int h, int leftPad, int format,
|
||||
char *bits)
|
||||
{
|
||||
PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
if (!pExaScr->prepare_access_reg || !pExaPixmap->pDamage ||
|
||||
exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle,
|
||||
pGC->alu, pGC->clientClip != NULL))
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
else
|
||||
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST,
|
||||
DamagePendingRegion(pExaPixmap->pDamage));
|
||||
pGC->ops->PutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
|
||||
bits);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckCopyNtoN(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
|
||||
BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
|
||||
Bool upsidedown, Pixel bitplane, void *closure)
|
||||
{
|
||||
RegionRec reg;
|
||||
int xoff, yoff;
|
||||
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
|
||||
exaDrawableLocation(pSrc), exaDrawableLocation(pDst)));
|
||||
|
||||
if (pExaScr->prepare_access_reg && RegionInitBoxes(®, pbox, nbox)) {
|
||||
PixmapPtr pPixmap = exaGetDrawablePixmap(pSrc);
|
||||
|
||||
exaGetDrawableDeltas(pSrc, pPixmap, &xoff, &yoff);
|
||||
RegionTranslate(®, xoff + dx, yoff + dy);
|
||||
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, ®);
|
||||
RegionUninit(®);
|
||||
}
|
||||
else
|
||||
exaPrepareAccess(pSrc, EXA_PREPARE_SRC);
|
||||
|
||||
if (pExaScr->prepare_access_reg &&
|
||||
!exaGCReadsDestination(pDst, pGC->planemask, pGC->fillStyle,
|
||||
pGC->alu, pGC->clientClip != NULL) &&
|
||||
RegionInitBoxes(®, pbox, nbox)) {
|
||||
PixmapPtr pPixmap = exaGetDrawablePixmap(pDst);
|
||||
|
||||
exaGetDrawableDeltas(pDst, pPixmap, &xoff, &yoff);
|
||||
RegionTranslate(®, xoff, yoff);
|
||||
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST, ®);
|
||||
RegionUninit(®);
|
||||
}
|
||||
else
|
||||
exaPrepareAccess(pDst, EXA_PREPARE_DEST);
|
||||
|
||||
/* This will eventually call fbCopyNtoN, with some calculation overhead. */
|
||||
while (nbox--) {
|
||||
pGC->ops->CopyArea(pSrc, pDst, pGC, pbox->x1 - pSrc->x + dx,
|
||||
pbox->y1 - pSrc->y + dy, pbox->x2 - pbox->x1,
|
||||
pbox->y2 - pbox->y1, pbox->x1 - pDst->x,
|
||||
pbox->y1 - pDst->y);
|
||||
pbox++;
|
||||
}
|
||||
exaFinishAccess(pSrc, EXA_PREPARE_SRC);
|
||||
exaFinishAccess(pDst, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
static void
|
||||
ExaFallbackPrepareReg(DrawablePtr pDrawable,
|
||||
GCPtr pGC,
|
||||
int x, int y, int width, int height,
|
||||
int index, Bool checkReads)
|
||||
{
|
||||
ScreenPtr pScreen = pDrawable->pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
if (pExaScr->prepare_access_reg &&
|
||||
!(checkReads && exaGCReadsDestination(pDrawable, pGC->planemask,
|
||||
pGC->fillStyle, pGC->alu,
|
||||
pGC->clientClip != NULL))) {
|
||||
BoxRec box;
|
||||
RegionRec reg;
|
||||
int xoff, yoff;
|
||||
PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
|
||||
|
||||
exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
|
||||
box.x1 = pDrawable->x + x + xoff;
|
||||
box.y1 = pDrawable->y + y + yoff;
|
||||
box.x2 = box.x1 + width;
|
||||
box.y2 = box.y1 + height;
|
||||
|
||||
RegionInit(®, &box, 1);
|
||||
pExaScr->prepare_access_reg(pPixmap, index, ®);
|
||||
RegionUninit(®);
|
||||
}
|
||||
else
|
||||
exaPrepareAccess(pDrawable, index);
|
||||
}
|
||||
|
||||
RegionPtr
|
||||
ExaCheckCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
|
||||
int srcx, int srcy, int w, int h, int dstx, int dsty)
|
||||
{
|
||||
RegionPtr ret;
|
||||
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
|
||||
exaDrawableLocation(pSrc), exaDrawableLocation(pDst)));
|
||||
ExaFallbackPrepareReg(pSrc, pGC, srcx, srcy, w, h, EXA_PREPARE_SRC, FALSE);
|
||||
ExaFallbackPrepareReg(pDst, pGC, dstx, dsty, w, h, EXA_PREPARE_DEST, TRUE);
|
||||
ret = pGC->ops->CopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
|
||||
exaFinishAccess(pSrc, EXA_PREPARE_SRC);
|
||||
exaFinishAccess(pDst, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
RegionPtr
|
||||
ExaCheckCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
|
||||
int srcx, int srcy, int w, int h, int dstx, int dsty,
|
||||
unsigned long bitPlane)
|
||||
{
|
||||
RegionPtr ret;
|
||||
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
|
||||
exaDrawableLocation(pSrc), exaDrawableLocation(pDst)));
|
||||
ExaFallbackPrepareReg(pSrc, pGC, srcx, srcy, w, h, EXA_PREPARE_SRC, FALSE);
|
||||
ExaFallbackPrepareReg(pDst, pGC, dstx, dsty, w, h, EXA_PREPARE_DEST, TRUE);
|
||||
ret = pGC->ops->CopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty,
|
||||
bitPlane);
|
||||
exaFinishAccess(pSrc, EXA_PREPARE_SRC);
|
||||
exaFinishAccess(pDst, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
|
||||
DDXPointPtr pptInit)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
pGC->ops->PolyPoint(pDrawable, pGC, mode, npt, pptInit);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPolylines(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int mode, int npt, DDXPointPtr ppt)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n",
|
||||
pDrawable, exaDrawableLocation(pDrawable),
|
||||
pGC->lineWidth, mode, npt));
|
||||
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->Polylines(pDrawable, pGC, mode, npt, ppt);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPolySegment(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int nsegInit, xSegment * pSegInit)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
|
||||
exaDrawableLocation(pDrawable), pGC->lineWidth, nsegInit));
|
||||
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->PolySegment(pDrawable, pGC, nsegInit, pSegInit);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->PolyArc(pDrawable, pGC, narcs, pArcs);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int nrect, xRectangle *prect)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->PolyFillRect(pDrawable, pGC, nrect, prect);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int x, int y, unsigned int nglyph,
|
||||
CharInfoPtr * ppci, void *pglyphBase)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->ImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int x, int y, unsigned int nglyph,
|
||||
CharInfoPtr * ppci, void *pglyphBase)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
|
||||
exaDrawableLocation(pDrawable), pGC->fillStyle, pGC->alu));
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->PolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPushPixels(GCPtr pGC, PixmapPtr pBitmap,
|
||||
DrawablePtr pDrawable, int w, int h, int x, int y)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
|
||||
exaDrawableLocation(&pBitmap->drawable),
|
||||
exaDrawableLocation(pDrawable)));
|
||||
ExaFallbackPrepareReg(pDrawable, pGC, x, y, w, h, EXA_PREPARE_DEST, TRUE);
|
||||
ExaFallbackPrepareReg(&pBitmap->drawable, pGC, 0, 0, w, h,
|
||||
EXA_PREPARE_SRC, FALSE);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->PushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(&pBitmap->drawable, EXA_PREPARE_SRC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
|
||||
{
|
||||
DrawablePtr pDrawable = &pWin->drawable;
|
||||
ScreenPtr pScreen = pDrawable->pScreen;
|
||||
|
||||
EXA_PRE_FALLBACK(pScreen);
|
||||
EXA_FALLBACK(("from %p\n", pWin));
|
||||
|
||||
/* Only need the source bits, the destination region will be overwritten */
|
||||
if (pExaScr->prepare_access_reg) {
|
||||
PixmapPtr pPixmap = pScreen->GetWindowPixmap(pWin);
|
||||
int xoff, yoff;
|
||||
|
||||
exaGetDrawableDeltas(&pWin->drawable, pPixmap, &xoff, &yoff);
|
||||
RegionTranslate(prgnSrc, xoff, yoff);
|
||||
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, prgnSrc);
|
||||
RegionTranslate(prgnSrc, -xoff, -yoff);
|
||||
}
|
||||
else
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_SRC);
|
||||
|
||||
swap(pExaScr, pScreen, CopyWindow);
|
||||
pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc);
|
||||
swap(pExaScr, pScreen, CopyWindow);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_SRC);
|
||||
EXA_POST_FALLBACK(pScreen);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
|
||||
unsigned int format, unsigned long planeMask, char *d)
|
||||
{
|
||||
ScreenPtr pScreen = pDrawable->pScreen;
|
||||
|
||||
EXA_PRE_FALLBACK(pScreen);
|
||||
EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
|
||||
ExaFallbackPrepareReg(pDrawable, NULL, x, y, w, h, EXA_PREPARE_SRC, FALSE);
|
||||
swap(pExaScr, pScreen, GetImage);
|
||||
pScreen->GetImage(pDrawable, x, y, w, h, format, planeMask, d);
|
||||
swap(pExaScr, pScreen, GetImage);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_SRC);
|
||||
EXA_POST_FALLBACK(pScreen);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckGetSpans(DrawablePtr pDrawable,
|
||||
int wMax,
|
||||
DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
|
||||
{
|
||||
ScreenPtr pScreen = pDrawable->pScreen;
|
||||
|
||||
EXA_PRE_FALLBACK(pScreen);
|
||||
EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_SRC);
|
||||
swap(pExaScr, pScreen, GetSpans);
|
||||
pScreen->GetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
|
||||
swap(pExaScr, pScreen, GetSpans);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_SRC);
|
||||
EXA_POST_FALLBACK(pScreen);
|
||||
}
|
||||
|
||||
static void
|
||||
ExaSrcValidate(DrawablePtr pDrawable,
|
||||
int x, int y, int width, int height, unsigned int subWindowMode)
|
||||
{
|
||||
ScreenPtr pScreen = pDrawable->pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);
|
||||
BoxRec box;
|
||||
RegionRec reg;
|
||||
RegionPtr dst;
|
||||
int xoff, yoff;
|
||||
|
||||
if (pExaScr->srcPix == pPix)
|
||||
dst = &pExaScr->srcReg;
|
||||
else if (pExaScr->maskPix == pPix)
|
||||
dst = &pExaScr->maskReg;
|
||||
else
|
||||
return;
|
||||
|
||||
exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff);
|
||||
|
||||
box.x1 = x + xoff;
|
||||
box.y1 = y + yoff;
|
||||
box.x2 = box.x1 + width;
|
||||
box.y2 = box.y1 + height;
|
||||
|
||||
RegionInit(®, &box, 1);
|
||||
RegionUnion(dst, dst, ®);
|
||||
RegionUninit(®);
|
||||
|
||||
swap(pExaScr, pScreen, SourceValidate);
|
||||
pScreen->SourceValidate(pDrawable, x, y, width, height, subWindowMode);
|
||||
swap(pExaScr, pScreen, SourceValidate);
|
||||
}
|
||||
|
||||
static Bool
|
||||
ExaPrepareCompositeReg(ScreenPtr pScreen,
|
||||
CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pMask,
|
||||
PicturePtr pDst,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc,
|
||||
INT16 xMask,
|
||||
INT16 yMask,
|
||||
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
|
||||
{
|
||||
RegionRec region;
|
||||
RegionPtr dstReg = NULL;
|
||||
RegionPtr srcReg = NULL;
|
||||
RegionPtr maskReg = NULL;
|
||||
PixmapPtr pSrcPix = NULL;
|
||||
PixmapPtr pMaskPix = NULL;
|
||||
PixmapPtr pDstPix;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
Bool ret;
|
||||
|
||||
RegionNull(®ion);
|
||||
|
||||
if (pSrc->pDrawable) {
|
||||
pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
|
||||
RegionNull(&pExaScr->srcReg);
|
||||
srcReg = &pExaScr->srcReg;
|
||||
pExaScr->srcPix = pSrcPix;
|
||||
if (pSrc != pDst)
|
||||
RegionTranslate(pSrc->pCompositeClip,
|
||||
-pSrc->pDrawable->x, -pSrc->pDrawable->y);
|
||||
} else
|
||||
pExaScr->srcPix = NULL;
|
||||
|
||||
if (pMask && pMask->pDrawable) {
|
||||
pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
|
||||
RegionNull(&pExaScr->maskReg);
|
||||
maskReg = &pExaScr->maskReg;
|
||||
pExaScr->maskPix = pMaskPix;
|
||||
if (pMask != pDst && pMask != pSrc)
|
||||
RegionTranslate(pMask->pCompositeClip,
|
||||
-pMask->pDrawable->x, -pMask->pDrawable->y);
|
||||
} else
|
||||
pExaScr->maskPix = NULL;
|
||||
|
||||
RegionTranslate(pDst->pCompositeClip,
|
||||
-pDst->pDrawable->x, -pDst->pDrawable->y);
|
||||
|
||||
pExaScr->SavedSourceValidate = ExaSrcValidate;
|
||||
swap(pExaScr, pScreen, SourceValidate);
|
||||
ret = miComputeCompositeRegion(®ion, pSrc, pMask, pDst,
|
||||
xSrc, ySrc, xMask, yMask,
|
||||
xDst, yDst, width, height);
|
||||
swap(pExaScr, pScreen, SourceValidate);
|
||||
|
||||
RegionTranslate(pDst->pCompositeClip,
|
||||
pDst->pDrawable->x, pDst->pDrawable->y);
|
||||
if (pSrc->pDrawable && pSrc != pDst)
|
||||
RegionTranslate(pSrc->pCompositeClip,
|
||||
pSrc->pDrawable->x, pSrc->pDrawable->y);
|
||||
if (pMask && pMask->pDrawable && pMask != pDst && pMask != pSrc)
|
||||
RegionTranslate(pMask->pCompositeClip,
|
||||
pMask->pDrawable->x, pMask->pDrawable->y);
|
||||
|
||||
if (!ret) {
|
||||
if (srcReg)
|
||||
RegionUninit(srcReg);
|
||||
if (maskReg)
|
||||
RegionUninit(maskReg);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't limit alphamaps readbacks for now until we've figured out how that
|
||||
* should be done.
|
||||
*/
|
||||
|
||||
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
|
||||
pExaScr->
|
||||
prepare_access_reg(exaGetDrawablePixmap(pSrc->alphaMap->pDrawable),
|
||||
EXA_PREPARE_AUX_SRC, NULL);
|
||||
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
|
||||
pExaScr->
|
||||
prepare_access_reg(exaGetDrawablePixmap(pMask->alphaMap->pDrawable),
|
||||
EXA_PREPARE_AUX_MASK, NULL);
|
||||
|
||||
if (pSrcPix)
|
||||
pExaScr->prepare_access_reg(pSrcPix, EXA_PREPARE_SRC, srcReg);
|
||||
|
||||
if (pMaskPix)
|
||||
pExaScr->prepare_access_reg(pMaskPix, EXA_PREPARE_MASK, maskReg);
|
||||
|
||||
if (srcReg)
|
||||
RegionUninit(srcReg);
|
||||
if (maskReg)
|
||||
RegionUninit(maskReg);
|
||||
|
||||
pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
|
||||
if (!exaOpReadsDestination(op)) {
|
||||
int xoff;
|
||||
int yoff;
|
||||
|
||||
exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &xoff, &yoff);
|
||||
RegionTranslate(®ion, pDst->pDrawable->x + xoff,
|
||||
pDst->pDrawable->y + yoff);
|
||||
dstReg = ®ion;
|
||||
}
|
||||
|
||||
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
|
||||
pExaScr->
|
||||
prepare_access_reg(exaGetDrawablePixmap(pDst->alphaMap->pDrawable),
|
||||
EXA_PREPARE_AUX_DEST, dstReg);
|
||||
pExaScr->prepare_access_reg(pDstPix, EXA_PREPARE_DEST, dstReg);
|
||||
|
||||
RegionUninit(®ion);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckComposite(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pMask,
|
||||
PicturePtr pDst,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc,
|
||||
INT16 xMask,
|
||||
INT16 yMask,
|
||||
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
|
||||
{
|
||||
ScreenPtr pScreen = pDst->pDrawable->pScreen;
|
||||
PictureScreenPtr ps = GetPictureScreen(pScreen);
|
||||
|
||||
EXA_PRE_FALLBACK(pScreen);
|
||||
|
||||
if (pExaScr->prepare_access_reg) {
|
||||
if (!ExaPrepareCompositeReg(pScreen, op, pSrc, pMask, pDst, xSrc,
|
||||
ySrc, xMask, yMask, xDst, yDst, width,
|
||||
height))
|
||||
goto out_no_clip;
|
||||
}
|
||||
else {
|
||||
|
||||
/* We need to prepare access to any separate alpha maps first,
|
||||
* in case the driver doesn't support EXA_PREPARE_AUX*,
|
||||
* in which case EXA_PREPARE_SRC may be used for moving them out.
|
||||
*/
|
||||
|
||||
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
|
||||
exaPrepareAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC);
|
||||
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
|
||||
exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK);
|
||||
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
|
||||
exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST);
|
||||
|
||||
exaPrepareAccess(pDst->pDrawable, EXA_PREPARE_DEST);
|
||||
|
||||
EXA_FALLBACK(("from picts %p/%p to pict %p\n", pSrc, pMask, pDst));
|
||||
|
||||
if (pSrc->pDrawable != NULL)
|
||||
exaPrepareAccess(pSrc->pDrawable, EXA_PREPARE_SRC);
|
||||
if (pMask && pMask->pDrawable != NULL)
|
||||
exaPrepareAccess(pMask->pDrawable, EXA_PREPARE_MASK);
|
||||
}
|
||||
|
||||
swap(pExaScr, ps, Composite);
|
||||
ps->Composite(op,
|
||||
pSrc,
|
||||
pMask,
|
||||
pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
|
||||
swap(pExaScr, ps, Composite);
|
||||
if (pMask && pMask->pDrawable != NULL)
|
||||
exaFinishAccess(pMask->pDrawable, EXA_PREPARE_MASK);
|
||||
if (pSrc->pDrawable != NULL)
|
||||
exaFinishAccess(pSrc->pDrawable, EXA_PREPARE_SRC);
|
||||
exaFinishAccess(pDst->pDrawable, EXA_PREPARE_DEST);
|
||||
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
|
||||
exaFinishAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST);
|
||||
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
|
||||
exaFinishAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC);
|
||||
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
|
||||
exaFinishAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK);
|
||||
|
||||
out_no_clip:
|
||||
EXA_POST_FALLBACK(pScreen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid migration ping-pong when using a mask.
|
||||
*/
|
||||
void
|
||||
ExaCheckGlyphs(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pDst,
|
||||
PictFormatPtr maskFormat,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
|
||||
{
|
||||
ScreenPtr pScreen = pDst->pDrawable->pScreen;
|
||||
|
||||
EXA_PRE_FALLBACK(pScreen);
|
||||
|
||||
miGlyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
|
||||
|
||||
EXA_POST_FALLBACK(pScreen);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckAddTraps(PicturePtr pPicture,
|
||||
INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
|
||||
{
|
||||
ScreenPtr pScreen = pPicture->pDrawable->pScreen;
|
||||
PictureScreenPtr ps = GetPictureScreen(pScreen);
|
||||
|
||||
EXA_PRE_FALLBACK(pScreen);
|
||||
|
||||
EXA_FALLBACK(("to pict %p (%c)\n", pPicture,
|
||||
exaDrawableLocation(pPicture->pDrawable)));
|
||||
exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
|
||||
swap(pExaScr, ps, AddTraps);
|
||||
ps->AddTraps(pPicture, x_off, y_off, ntrap, traps);
|
||||
swap(pExaScr, ps, AddTraps);
|
||||
exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK(pScreen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 0,0 pixel of a pixmap. Used for doing solid fills of tiled pixmaps
|
||||
* that happen to be 1x1. Pixmap must be at least 8bpp.
|
||||
*/
|
||||
CARD32
|
||||
exaGetPixmapFirstPixel(PixmapPtr pPixmap)
|
||||
{
|
||||
switch (pPixmap->drawable.bitsPerPixel) {
|
||||
case 32:
|
||||
{
|
||||
CARD32 pixel;
|
||||
|
||||
pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1,
|
||||
ZPixmap, ~0, (char *) &pixel);
|
||||
return pixel;
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
CARD16 pixel;
|
||||
|
||||
pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1,
|
||||
ZPixmap, ~0, (char *) &pixel);
|
||||
return pixel;
|
||||
}
|
||||
case 8:
|
||||
case 4:
|
||||
case 1:
|
||||
{
|
||||
CARD8 pixel;
|
||||
|
||||
pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1,
|
||||
ZPixmap, ~0, (char *) &pixel);
|
||||
return pixel;
|
||||
}
|
||||
default:
|
||||
FatalError("%s called for invalid bpp %d\n", __func__,
|
||||
pPixmap->drawable.bitsPerPixel);
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
srcs_exa = [
|
||||
'exa.c',
|
||||
'exa_classic.c',
|
||||
'exa_migration_classic.c',
|
||||
'exa_driver.c',
|
||||
'exa_mixed.c',
|
||||
'exa_migration_mixed.c',
|
||||
'exa_accel.c',
|
||||
'exa_glyphs.c',
|
||||
'exa_offscreen.c',
|
||||
'exa_render.c',
|
||||
'exa_unaccel.c',
|
||||
]
|
||||
|
||||
libxserver_exa = static_library('libxserver_exa',
|
||||
srcs_exa,
|
||||
include_directories: inc,
|
||||
dependencies: common_dep,
|
||||
)
|
|
@ -410,7 +410,6 @@ inc = include_directories(
|
|||
'Xi',
|
||||
'composite',
|
||||
'damageext',
|
||||
'exa',
|
||||
'fb',
|
||||
'glamor',
|
||||
'mi',
|
||||
|
|
Loading…
Reference in New Issue
Block a user