#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#ifdef MITSHM
#include "shmint.h"
#endif
#include <stdlib.h>
#include "exa_priv.h"
#include <X11/fonts/fontstruct.h>
#include "dixfontstr.h"
#include "exa.h"
#include "cw.h"
static int exaGeneration;
int exaScreenPrivateIndex;
int exaPixmapPrivateIndex;
unsigned long
exaGetPixmapOffset(PixmapPtr pPix)
{
ExaScreenPriv (pPix->drawable.pScreen);
ExaPixmapPriv (pPix);
void *ptr;
if (pPix->devPrivate.ptr == NULL)
ptr = pExaPixmap->fb_ptr;
else
ptr = pPix->devPrivate.ptr;
return ((unsigned long)ptr - (unsigned long)pExaScr->info->memoryBase);
}
unsigned long
exaGetPixmapPitch(PixmapPtr pPix)
{
return pPix->devKind;
}
unsigned long
exaGetPixmapSize(PixmapPtr pPix)
{
ExaPixmapPrivPtr pExaPixmap;
pExaPixmap = ExaGetPixmapPriv(pPix);
if (pExaPixmap != NULL)
return pExaPixmap->fb_size;
return 0;
}
PixmapPtr
exaGetDrawablePixmap(DrawablePtr pDrawable)
{
if (pDrawable->type == DRAWABLE_WINDOW)
return pDrawable->pScreen->GetWindowPixmap ((WindowPtr) pDrawable);
else
return (PixmapPtr) pDrawable;
}
void
exaGetDrawableDeltas (DrawablePtr pDrawable, PixmapPtr pPixmap,
int *xp, int *yp)
{
#ifdef COMPOSITE
if (pDrawable->type == DRAWABLE_WINDOW) {
*xp = -pPixmap->screen_x;
*yp = -pPixmap->screen_y;
return;
}
#endif
*xp = 0;
*yp = 0;
}
void
exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2)
{
ExaPixmapPriv(pPix);
BoxRec box;
RegionPtr pDamageReg;
RegionRec region;
if (!pExaPixmap)
return;
box.x1 = max(x1, 0);
box.y1 = max(y1, 0);
box.x2 = min(x2, pPix->drawable.width);
box.y2 = min(y2, pPix->drawable.height);
if (box.x1 >= box.x2 || box.y1 >= box.y2)
return;
pDamageReg = DamageRegion(pExaPixmap->pDamage);
REGION_INIT(pScreen, ®ion, &box, 1);
REGION_UNION(pScreen, pDamageReg, pDamageReg, ®ion);
REGION_UNINIT(pScreen, ®ion);
}
static Bool
exaDestroyPixmap (PixmapPtr pPixmap)
{
if (pPixmap->refcnt == 1)
{
ExaPixmapPriv (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));
exaOffscreenFree (pPixmap->drawable.pScreen, pExaPixmap->area);
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
pPixmap->devKind = pExaPixmap->sys_pitch;
}
REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validReg);
}
return fbDestroyPixmap (pPixmap);
}
static int
exaLog2(int val)
{
int bits;
if (val <= 0)
return 0;
for (bits = 0; val != 0; bits++)
val >>= 1;
return bits - 1;
}
static PixmapPtr
exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth)
{
PixmapPtr pPixmap;
ExaPixmapPrivPtr pExaPixmap;
int bpp;
ExaScreenPriv(pScreen);
if (w > 32767 || h > 32767)
return NullPixmap;
pPixmap = fbCreatePixmap (pScreen, w, h, depth);
if (!pPixmap)
return NULL;
pExaPixmap = ExaGetPixmapPriv(pPixmap);
bpp = pPixmap->drawable.bitsPerPixel;
if (!w || !h)
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
else
pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
pExaPixmap->area = NULL;
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
pExaPixmap->sys_pitch = pPixmap->devKind;
pExaPixmap->fb_ptr = NULL;
if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
pExaPixmap->fb_pitch = (1 << (exaLog2(w - 1) + 1)) * bpp / 8;
else
pExaPixmap->fb_pitch = w * bpp / 8;
pExaPixmap->fb_pitch = EXA_ALIGN(pExaPixmap->fb_pitch,
pExaScr->info->pixmapPitchAlign);
pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;
if (pExaPixmap->fb_pitch > 131071) {
fbDestroyPixmap(pPixmap);
return NULL;
}
pExaPixmap->pDamage = DamageCreate (NULL, NULL, DamageReportNone, TRUE,
pScreen, pPixmap);
if (pExaPixmap->pDamage == NULL) {
fbDestroyPixmap (pPixmap);
return NULL;
}
DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage);
DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE);
REGION_NULL(pScreen, &pExaPixmap->validReg);
return pPixmap;
}
Bool
exaPixmapIsOffscreen(PixmapPtr p)
{
ScreenPtr pScreen = p->drawable.pScreen;
ExaScreenPriv(pScreen);
if (p->devPrivate.ptr == NULL)
return TRUE;
if (pExaScr->info->PixmapIsOffscreen)
return pExaScr->info->PixmapIsOffscreen(p);
return ((unsigned long) ((CARD8 *) p->devPrivate.ptr -
(CARD8 *) pExaScr->info->memoryBase) <
pExaScr->info->memorySize);
}
Bool
exaDrawableIsOffscreen (DrawablePtr pDrawable)
{
return exaPixmapIsOffscreen (exaGetDrawablePixmap (pDrawable));
}
PixmapPtr
exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
{
PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
exaGetDrawableDeltas (pDrawable, pPixmap, xp, yp);
if (exaPixmapIsOffscreen (pPixmap))
return pPixmap;
else
return NULL;
}
void
exaPrepareAccess(DrawablePtr pDrawable, int index)
{
ScreenPtr pScreen = pDrawable->pScreen;
ExaScreenPriv (pScreen);
PixmapPtr pPixmap;
pPixmap = exaGetDrawablePixmap (pDrawable);
if (exaPixmapIsOffscreen (pPixmap))
exaWaitSync (pDrawable->pScreen);
else
return;
if (pPixmap->devPrivate.ptr == NULL) {
ExaPixmapPriv (pPixmap);
pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
}
if (pExaScr->info->PrepareAccess == NULL)
return;
if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) {
ExaPixmapPriv (pPixmap);
if (pExaPixmap->score != EXA_PIXMAP_SCORE_PINNED)
FatalError("Driver failed PrepareAccess on a pinned pixmap\n");
exaMoveOutPixmap (pPixmap);
}
}
void
exaFinishAccess(DrawablePtr pDrawable, int index)
{
ScreenPtr pScreen = pDrawable->pScreen;
ExaScreenPriv (pScreen);
PixmapPtr pPixmap;
ExaPixmapPrivPtr pExaPixmap;
pPixmap = exaGetDrawablePixmap (pDrawable);
pExaPixmap = ExaGetPixmapPriv(pPixmap);
if (pExaPixmap != NULL && pExaScr->hideOffscreenPixmapData &&
pExaPixmap->fb_ptr == pPixmap->devPrivate.ptr)
{
pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
}
if (pExaScr->info->FinishAccess == NULL)
return;
if (!exaPixmapIsOffscreen (pPixmap))
return;
(*pExaScr->info->FinishAccess) (pPixmap, index);
}
static void
exaValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
{
#ifdef FB_24_32BIT
if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) {
(*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
fbGetRotatedPixmap(pGC) = 0;
}
if (pGC->fillStyle == FillTiled) {
PixmapPtr pOldTile, pNewTile;
pOldTile = pGC->tile.pixmap;
if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
{
pNewTile = fbGetRotatedPixmap(pGC);
if (!pNewTile ||
pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
{
if (pNewTile)
(*pGC->pScreen->DestroyPixmap) (pNewTile);
exaPrepareAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
pNewTile = fb24_32ReformatTile (pOldTile,
pDrawable->bitsPerPixel);
exaPixmapDirty(pNewTile, 0, 0, pNewTile->drawable.width, pNewTile->drawable.height);
exaFinishAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
}
if (pNewTile)
{
fbGetRotatedPixmap(pGC) = pOldTile;
pGC->tile.pixmap = pNewTile;
changes |= GCTile;
}
}
}
#endif
if (changes & GCTile) {
if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width *
pDrawable->bitsPerPixel))
{
exaMoveOutPixmap(pGC->tile.pixmap);
fbPadPixmap (pGC->tile.pixmap);
exaPixmapDirty(pGC->tile.pixmap, 0, 0,
pGC->tile.pixmap->drawable.width,
pGC->tile.pixmap->drawable.height);
}
changes &= ~GCTile;
}
fbValidateGC (pGC, changes, pDrawable);
pGC->ops = (GCOps *) &exaOps;
}
static GCFuncs exaGCFuncs = {
exaValidateGC,
miChangeGC,
miCopyGC,
miDestroyGC,
miChangeClip,
miDestroyClip,
miCopyClip
};
static int
exaCreateGC (GCPtr pGC)
{
if (!fbCreateGC (pGC))
return FALSE;
pGC->funcs = &exaGCFuncs;
return TRUE;
}
static Bool
exaCloseScreen(int i, ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
#ifdef RENDER
PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
#endif
pScreen->CreateGC = pExaScr->SavedCreateGC;
pScreen->CloseScreen = pExaScr->SavedCloseScreen;
pScreen->GetImage = pExaScr->SavedGetImage;
pScreen->GetSpans = pExaScr->SavedGetSpans;
pScreen->PaintWindowBackground = pExaScr->SavedPaintWindowBackground;
pScreen->PaintWindowBorder = pExaScr->SavedPaintWindowBorder;
pScreen->CreatePixmap = pExaScr->SavedCreatePixmap;
pScreen->DestroyPixmap = pExaScr->SavedDestroyPixmap;
pScreen->CopyWindow = pExaScr->SavedCopyWindow;
#ifdef RENDER
if (ps) {
ps->Composite = pExaScr->SavedComposite;
ps->Glyphs = pExaScr->SavedGlyphs;
ps->Trapezoids = pExaScr->SavedTrapezoids;
}
#endif
xfree (pExaScr);
return (*pScreen->CloseScreen) (i, pScreen);
}
ExaDriverPtr
exaDriverAlloc(void)
{
return xcalloc(1, sizeof(ExaDriverRec));
}
Bool
exaDriverInit (ScreenPtr pScreen,
ExaDriverPtr pScreenInfo)
{
ExaScreenPrivPtr pExaScr;
#ifdef RENDER
PictureScreenPtr ps;
#endif
if (!pScreenInfo)
return FALSE;
if (!pScreenInfo->memoryBase) {
LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memoryBase must be "
"non-zero\n", pScreen->myNum);
return FALSE;
}
if (!pScreenInfo->memorySize) {
LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memorySize must be "
"non-zero\n", pScreen->myNum);
return FALSE;
}
if (pScreenInfo->offScreenBase > pScreenInfo->memorySize) {
LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::offScreenBase must be <= "
"ExaDriverRec::memorySize\n", pScreen->myNum);
return FALSE;
}
if (!pScreenInfo->PrepareSolid) {
LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareSolid must be "
"non-NULL\n", pScreen->myNum);
return FALSE;
}
if (!pScreenInfo->PrepareCopy) {
LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::PrepareCopy must be "
"non-NULL\n", pScreen->myNum);
return FALSE;
}
if (!pScreenInfo->WaitMarker) {
LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::WaitMarker must be "
"non-NULL\n", pScreen->myNum);
return FALSE;
}
if (pScreenInfo->exa_major != EXA_VERSION_MAJOR ||
pScreenInfo->exa_minor > EXA_VERSION_MINOR)
{
LogMessage(X_ERROR, "EXA(%d): driver's EXA version requirements "
"(%d.%d) are incompatible with EXA version (%d.%d)\n",
pScreen->myNum,
pScreenInfo->exa_major, pScreenInfo->exa_minor,
EXA_VERSION_MAJOR, EXA_VERSION_MINOR);
return FALSE;
}
#ifdef RENDER
ps = GetPictureScreenIfSet(pScreen);
#endif
if (exaGeneration != serverGeneration)
{
exaScreenPrivateIndex = AllocateScreenPrivateIndex();
exaPixmapPrivateIndex = AllocatePixmapPrivateIndex();
exaGeneration = serverGeneration;
}
pExaScr = xcalloc (sizeof (ExaScreenPrivRec), 1);
if (!pExaScr) {
LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n",
pScreen->myNum);
return FALSE;
}
pExaScr->info = pScreenInfo;
pScreen->devPrivates[exaScreenPrivateIndex].ptr = (pointer) pExaScr;
pExaScr->migration = ExaMigrationAlways;
exaDDXDriverInit(pScreen);
pExaScr->SavedCloseScreen = pScreen->CloseScreen;
pScreen->CloseScreen = exaCloseScreen;
pExaScr->SavedCreateGC = pScreen->CreateGC;
pScreen->CreateGC = exaCreateGC;
pExaScr->SavedGetImage = pScreen->GetImage;
pScreen->GetImage = exaGetImage;
pExaScr->SavedGetSpans = pScreen->GetSpans;
pScreen->GetSpans = exaGetSpans;
pExaScr->SavedCopyWindow = pScreen->CopyWindow;
pScreen->CopyWindow = exaCopyWindow;
pExaScr->SavedPaintWindowBackground = pScreen->PaintWindowBackground;
pScreen->PaintWindowBackground = exaPaintWindow;
pExaScr->SavedPaintWindowBorder = pScreen->PaintWindowBorder;
pScreen->PaintWindowBorder = exaPaintWindow;
pScreen->BackingStoreFuncs.SaveAreas = ExaCheckSaveAreas;
pScreen->BackingStoreFuncs.RestoreAreas = ExaCheckRestoreAreas;
#ifdef RENDER
if (ps) {
pExaScr->SavedComposite = ps->Composite;
ps->Composite = exaComposite;
pExaScr->SavedRasterizeTrapezoid = ps->RasterizeTrapezoid;
ps->RasterizeTrapezoid = exaRasterizeTrapezoid;
pExaScr->SavedAddTriangles = ps->AddTriangles;
ps->AddTriangles = exaAddTriangles;
pExaScr->SavedGlyphs = ps->Glyphs;
ps->Glyphs = exaGlyphs;
pExaScr->SavedTrapezoids = ps->Trapezoids;
ps->Trapezoids = exaTrapezoids;
}
#endif
#ifdef MITSHM
ShmRegisterFuncs(pScreen, NULL);
#endif
if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) &&
pExaScr->info->offScreenBase < pExaScr->info->memorySize)
{
if (!AllocatePixmapPrivate(pScreen, exaPixmapPrivateIndex,
sizeof (ExaPixmapPrivRec))) {
LogMessage(X_WARNING,
"EXA(%d): Failed to allocate pixmap private\n",
pScreen->myNum);
return FALSE;
}
pExaScr->SavedCreatePixmap = pScreen->CreatePixmap;
pScreen->CreatePixmap = exaCreatePixmap;
pExaScr->SavedDestroyPixmap = pScreen->DestroyPixmap;
pScreen->DestroyPixmap = exaDestroyPixmap;
LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %d bytes\n",
pScreen->myNum,
pExaScr->info->memorySize - pExaScr->info->offScreenBase);
}
else
{
LogMessage(X_INFO, "EXA(%d): No offscreen pixmaps\n", pScreen->myNum);
if (!AllocatePixmapPrivate(pScreen, exaPixmapPrivateIndex, 0))
return FALSE;
}
DBG_PIXMAP(("============== %ld < %ld\n", pExaScr->info->offScreenBase,
pExaScr->info->memorySize));
if (pExaScr->info->offScreenBase < pExaScr->info->memorySize) {
if (!exaOffscreenInit (pScreen)) {
LogMessage(X_WARNING, "EXA(%d): Offscreen pixmap setup failed\n",
pScreen->myNum);
return FALSE;
}
}
LogMessage(X_INFO, "EXA(%d): Driver registered support for the following"
" operations:\n", pScreen->myNum);
assert(pScreenInfo->PrepareSolid != NULL);
LogMessage(X_INFO, " Solid\n");
assert(pScreenInfo->PrepareCopy != NULL);
LogMessage(X_INFO, " Copy\n");
if (pScreenInfo->PrepareComposite != NULL) {
LogMessage(X_INFO, " Composite (RENDER acceleration)\n");
}
if (pScreenInfo->UploadToScreen != NULL) {
LogMessage(X_INFO, " UploadToScreen\n");
}
if (pScreenInfo->DownloadFromScreen != NULL) {
LogMessage(X_INFO, " DownloadFromScreen\n");
}
return TRUE;
}
void
exaDriverFini (ScreenPtr pScreen)
{
}
void exaMarkSync(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
pExaScr->info->needsSync = TRUE;
if (pExaScr->info->MarkSync != NULL) {
pExaScr->info->lastMarker = (*pExaScr->info->MarkSync)(pScreen);
}
}
void exaWaitSync(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
if (pExaScr->info->needsSync && !pExaScr->swappedOut) {
(*pExaScr->info->WaitMarker)(pScreen, pExaScr->info->lastMarker);
pExaScr->info->needsSync = FALSE;
}
}