diff options
Diffstat (limited to 'exa')
-rw-r--r-- | exa/Makefile.am | 7 | ||||
-rw-r--r-- | exa/exa.c | 514 | ||||
-rw-r--r-- | exa/exa.h | 32 | ||||
-rw-r--r-- | exa/exa_accel.c | 164 | ||||
-rw-r--r-- | exa/exa_classic.c | 258 | ||||
-rw-r--r-- | exa/exa_driver.c | 214 | ||||
-rw-r--r-- | exa/exa_glyphs.c | 17 | ||||
-rw-r--r-- | exa/exa_migration_classic.c (renamed from exa/exa_migration.c) | 29 | ||||
-rw-r--r-- | exa/exa_migration_mixed.c | 194 | ||||
-rw-r--r-- | exa/exa_mixed.c | 251 | ||||
-rw-r--r-- | exa/exa_priv.h | 154 | ||||
-rw-r--r-- | exa/exa_render.c | 399 | ||||
-rw-r--r-- | exa/exa_unaccel.c | 69 |
13 files changed, 1573 insertions, 729 deletions
diff --git a/exa/Makefile.am b/exa/Makefile.am index 2b3f1e416..8b759cd76 100644 --- a/exa/Makefile.am +++ b/exa/Makefile.am @@ -17,11 +17,14 @@ AM_CFLAGS = $(XORG_CFLAGS) $(DIX_CFLAGS) libexa_la_SOURCES = \ exa.c \ exa.h \ + exa_classic.c \ + exa_migration_classic.c \ + exa_driver.c \ + exa_mixed.c \ + exa_migration_mixed.c \ exa_accel.c \ exa_glyphs.c \ - exa_migration.c \ exa_offscreen.c \ exa_render.c \ exa_priv.h \ exa_unaccel.c - @@ -48,17 +48,6 @@ DevPrivateKey exaGCPrivateKey = &exaGCPrivateKeyIndex; static ShmFuncs exaShmFuncs = { NULL, NULL }; #endif -static _X_INLINE void* -ExaGetPixmapAddress(PixmapPtr p) -{ - ExaPixmapPriv(p); - - if (pExaPixmap->offscreen && pExaPixmap->fb_ptr) - return pExaPixmap->fb_ptr; - else - return pExaPixmap->sys_ptr; -} - /** * exaGetPixmapOffset() returns the offset (in bytes) within the framebuffer of * the beginning of the given pixmap. @@ -178,45 +167,6 @@ exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2) REGION_UNINIT(pScreen, ®ion); } -static Bool -exaDestroyPixmap (PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - ExaScreenPriv(pScreen); - Bool ret; - - if (pPixmap->refcnt == 1) - { - ExaPixmapPriv (pPixmap); - - if (pExaPixmap->driverPriv) { - pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); - pExaPixmap->driverPriv = NULL; - } - - 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; - } - REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validSys); - REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validFB); - } - - swap(pExaScr, pScreen, DestroyPixmap); - ret = pScreen->DestroyPixmap (pPixmap); - swap(pExaScr, pScreen, DestroyPixmap); - - return ret; -} - static int exaLog2(int val) { @@ -229,14 +179,14 @@ exaLog2(int val) return bits - 1; } -static void +void exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap, int w, int h, int bpp) { pExaPixmap->accel_blocked = 0; if (pExaScr->info->maxPitchPixels) { - int max_pitch = pExaScr->info->maxPitchPixels * (bpp + 7) / 8; + int max_pitch = pExaScr->info->maxPitchPixels * bits_to_bytes(bpp); if (pExaPixmap->fb_pitch > max_pitch) pExaPixmap->accel_blocked |= EXA_RANGE_PITCH; @@ -253,238 +203,33 @@ exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap, pExaPixmap->accel_blocked |= EXA_RANGE_HEIGHT; } -static void +void exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap, int w, int h, int bpp) { if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1) - pExaPixmap->fb_pitch = ((1 << (exaLog2(w - 1) + 1)) * bpp + 7) / 8; + pExaPixmap->fb_pitch = bits_to_bytes((1 << (exaLog2(w - 1) + 1)) * bpp); else - pExaPixmap->fb_pitch = (w * bpp + 7) / 8; + pExaPixmap->fb_pitch = bits_to_bytes(w * bpp); pExaPixmap->fb_pitch = EXA_ALIGN(pExaPixmap->fb_pitch, pExaScr->info->pixmapPitchAlign); } /** - * 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. + * Returns TRUE if the pixmap is not movable. This is the case where it's a + * pixmap which has no private (almost always bad) or it's a scratch pixmap created by + * some X Server internal component (the score says it's pinned). */ -static PixmapPtr -exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth, - unsigned usage_hint) -{ - PixmapPtr pPixmap; - ExaPixmapPrivPtr pExaPixmap; - BoxRec box; - int driver_alloc = 0; - int bpp; - ExaScreenPriv(pScreen); - - if (w > 32767 || h > 32767) - return NullPixmap; - - swap(pExaScr, pScreen, CreatePixmap); - if (!pExaScr->info->CreatePixmap && !pExaScr->info->CreatePixmap2) { - pPixmap = pScreen->CreatePixmap (pScreen, w, h, depth, usage_hint); - } else { - driver_alloc = 1; - 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; - - if (driver_alloc) { - size_t paddedWidth, datasize; - - 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; - - /* Set this before driver hooks, to allow for !offscreen pixmaps. - * !offscreen pixmaps have a valid pointer at all times. - */ - pPixmap->devPrivate.ptr = NULL; - - if (pExaScr->info->CreatePixmap2) - pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp); - else - 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); - - } else { - 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->offscreen = 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; - REGION_INIT(pScreen, &pExaPixmap->validSys, &box, 0); - REGION_INIT(pScreen, &pExaPixmap->validFB, &box, 0); - - exaSetAccelBlock(pExaScr, pExaPixmap, - w, h, bpp); - - return pPixmap; -} - -static Bool -exaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth, - int bitsPerPixel, int devKind, pointer pPixData) +Bool +exaPixmapIsPinned (PixmapPtr pPix) { - ExaScreenPrivPtr pExaScr; - ExaPixmapPrivPtr pExaPixmap; - Bool ret; - - if (!pPixmap) - return FALSE; - - pExaScr = ExaGetScreenPriv(pPixmap->drawable.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 offscreen memory. - */ - if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && - 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->offscreen = 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 - * offscreen memory, so there's no need to track damage. - */ - if (pExaPixmap->pDamage) { - DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); - DamageDestroy(pExaPixmap->pDamage); - pExaPixmap->pDamage = NULL; - } - } - - 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 non-offscreen 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; - } - ret = pExaScr->SavedModifyPixmapHeader(pPixmap, width, height, depth, - bitsPerPixel, devKind, pPixData); + ExaPixmapPriv (pPix); -out: - /* Always NULL this, we don't want lingering pointers. */ - pPixmap->devPrivate.ptr = NULL; + if (pExaPixmap == NULL) + EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsPinned was called on a non-exa pixmap.\n"), TRUE); - return ret; + return pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED; } /** @@ -500,21 +245,15 @@ out: * @return TRUE if the given drawable is in framebuffer memory. */ Bool -exaPixmapIsOffscreen(PixmapPtr p) +exaPixmapIsOffscreen(PixmapPtr pPixmap) { - ScreenPtr pScreen = p->drawable.pScreen; + ScreenPtr pScreen = pPixmap->drawable.pScreen; ExaScreenPriv(pScreen); - ExaPixmapPriv(p); - Bool ret; - if (pExaScr->info->PixmapIsOffscreen) { - p->devPrivate.ptr = ExaGetPixmapAddress(p); - ret = pExaScr->info->PixmapIsOffscreen(p); - p->devPrivate.ptr = NULL; - } else - ret = (pExaPixmap->offscreen && pExaPixmap->fb_ptr); + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return FALSE; - return ret; + return (*pExaScr->pixmap_is_offscreen)(pPixmap); } /** @@ -554,6 +293,7 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index) PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); ExaPixmapPriv(pPixmap); Bool offscreen; + int i; if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) return FALSE; @@ -561,19 +301,25 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index) if (pExaPixmap == NULL) EXA_FatalErrorDebugWithRet(("EXA bug: ExaDoPrepareAccess was called on a non-exa pixmap.\n"), FALSE); - /* Check if we're dealing SRC == DST or similar. - * In that case the first PrepareAccess has already set pPixmap->devPrivate.ptr. - */ - if (pPixmap->devPrivate.ptr != NULL) { - int i; - for (i = 0; i < 6; i++) - if (pExaScr->prepare_access[i] == pPixmap) + /* Handle repeated / nested calls. */ + for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) { + if (pExaScr->access[i].pixmap == pPixmap) { + pExaScr->access[i].count++; + return TRUE; + } + } + + /* If slot for this index is taken, find an empty slot */ + if (pExaScr->access[index].pixmap) { + for (index = EXA_NUM_PREPARE_INDICES - 1; index >= 0; index--) + if (!pExaScr->access[index].pixmap) break; + } - /* No known PrepareAccess or double prepare on the same index. */ - if (i == 6 || i == index) - EXA_FatalErrorDebug(("EXA bug: pPixmap->devPrivate.ptr was %p, but should have been NULL.\n", - pPixmap->devPrivate.ptr)); + /* Access to this pixmap hasn't been prepared yet, so data pointer should be NULL. */ + if (pPixmap->devPrivate.ptr != NULL) { + EXA_FatalErrorDebug(("EXA bug: pPixmap->devPrivate.ptr was %p, but should have been NULL.\n", + pPixmap->devPrivate.ptr)); } offscreen = exaPixmapIsOffscreen(pPixmap); @@ -583,11 +329,22 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index) else pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; - /* Store so we can check SRC and DEST being the same. */ - pExaScr->prepare_access[index] = pPixmap; - - if (!offscreen) + /* Store so we can handle repeated / nested calls. */ + pExaScr->access[index].pixmap = pPixmap; + pExaScr->access[index].count = 1; + + if (!offscreen) { + /* Do we need to allocate our system buffer? */ + if ((pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && (pExaScr->info->flags & EXA_MIXED_PIXMAPS)) { + if (!pExaPixmap->sys_ptr && !exaPixmapIsPinned(pPixmap)) { + pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch * pDrawable->height); + if (!pExaPixmap->sys_ptr) + FatalError("EXA: malloc failed for size %d bytes\n", pExaPixmap->sys_pitch * pDrawable->height); + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + } + } return FALSE; + } exaWaitSync (pDrawable->pScreen); @@ -616,19 +373,24 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index) void exaPrepareAccessReg(DrawablePtr pDrawable, 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 = exaGetDrawablePixmap (pDrawable); - pixmaps[0].pReg = pReg; + PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); + ExaScreenPriv(pPixmap->drawable.pScreen); - exaDoMigration(pixmaps, 1, FALSE); + if (pExaScr->do_migration) { + 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); + } ExaDoPrepareAccess(pDrawable, index); } @@ -657,6 +419,7 @@ exaFinishAccess(DrawablePtr pDrawable, int index) ExaScreenPriv (pScreen); PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); ExaPixmapPriv (pPixmap); + int i; if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) return; @@ -664,11 +427,22 @@ exaFinishAccess(DrawablePtr pDrawable, int index) if (pExaPixmap == NULL) EXA_FatalErrorDebugWithRet(("EXA bug: exaFinishAccesss was called on a non-exa pixmap.\n"),); - /* Avoid mismatching indices. */ - if (pExaScr->prepare_access[index] != pPixmap) - EXA_FatalErrorDebug(("EXA bug: Calling FinishAccess on pixmap %p with index %d while " - "it should have been %p.\n", pPixmap, index, pExaScr->prepare_access[index])); - pExaScr->prepare_access[index] = NULL; + /* Handle repeated / nested calls. */ + for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) { + if (pExaScr->access[i].pixmap == pPixmap) { + if (--pExaScr->access[i].count > 0) + return; + index = i; + break; + } + } + + /* Catch unbalanced Prepare/FinishAccess calls. */ + if (i == EXA_NUM_PREPARE_INDICES) + EXA_FatalErrorDebug(("EXA bug: FinishAccess called without PrepareAccess for pixmap 0x%p.\n", + pPixmap)); + + pExaScr->access[index].pixmap = NULL; /* We always hide the devPrivate.ptr. */ pPixmap->devPrivate.ptr = NULL; @@ -763,15 +537,7 @@ exaCreatePixmapWithPrepare(ScreenPtr pScreen, int w, int h, int depth, * For EXA_HANDLES_PIXMAPS the driver will handle whatever is needed. * We want to signal that the pixmaps will be used as destination. */ - if (pExaScr->prepare_access[EXA_PREPARE_DEST] == NULL) { - ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST); - pExaScr->prepare_access[EXA_PREPARE_DEST] = pPixmap; - } else if (pExaScr->prepare_access[EXA_PREPARE_AUX_DEST] == NULL) { - ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); - pExaScr->prepare_access[EXA_PREPARE_AUX_DEST] = pPixmap; - } else { - FatalError("exaCreatePixmapWithPrepare can only accomodate two pixmaps, we're at three.\n"); - } + ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); return pPixmap; } @@ -781,12 +547,9 @@ exaDestroyPixmapWithFinish(PixmapPtr pPixmap) { ScreenPtr pScreen = pPixmap->drawable.pScreen; ExaScreenPriv(pScreen); - int i; Bool ret; - for (i = 0; i < 6; i++) - if (pExaScr->prepare_access[i] == pPixmap) - exaFinishAccess(&pPixmap->drawable, i); + exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); /* This swaps between this function and the real upper layer function. * Normally this would swap to the fb layer pointer, this is a very special case. @@ -848,8 +611,8 @@ exaValidateGC(GCPtr pGC, (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable); - if (pExaScr->prepare_access[EXA_PREPARE_SRC]) /* tile */ - exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_SRC]->drawable, EXA_PREPARE_SRC); + if (pTile) + exaFinishAccess(&pTile->drawable, EXA_PREPARE_SRC); if (pGC->stipple) exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK); @@ -863,13 +626,6 @@ exaValidateGC(GCPtr pGC, /* restore copy of fb layer pointer. */ pExaScr->SavedDestroyPixmap = old_ptr2; - if (pExaScr->prepare_access[EXA_PREPARE_DEST]) - exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_DEST]->drawable, - EXA_PREPARE_DEST); - if (pExaScr->prepare_access[EXA_PREPARE_AUX_DEST]) - exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_AUX_DEST]->drawable, - EXA_PREPARE_AUX_DEST); - EXA_GC_EPILOGUE(pGC); } @@ -979,10 +735,10 @@ exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask) ret = pScreen->ChangeWindowAttributes(pWin, mask); swap(pExaScr, pScreen, ChangeWindowAttributes); - if (pExaScr->prepare_access[EXA_PREPARE_SRC]) /* background */ - exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_SRC]->drawable, EXA_PREPARE_SRC); - if (pExaScr->prepare_access[EXA_PREPARE_MASK]) /* border */ - exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_MASK]->drawable, EXA_PREPARE_MASK); + if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap) + exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); + if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE) + exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); /* switch back to the normal upper layer. */ unwrap(pExaScr, pScreen, CreatePixmap); @@ -994,13 +750,6 @@ exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask) /* restore copy of fb layer pointer. */ pExaScr->SavedDestroyPixmap = old_ptr2; - if (pExaScr->prepare_access[EXA_PREPARE_DEST]) - exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_DEST]->drawable, - EXA_PREPARE_DEST); - if (pExaScr->prepare_access[EXA_PREPARE_AUX_DEST]) - exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_AUX_DEST]->drawable, - EXA_PREPARE_AUX_DEST); - return ret; } @@ -1313,10 +1062,33 @@ exaDriverInit (ScreenPtr pScreen, pScreen->myNum); return FALSE; } - wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap); - wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap); - - wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader); + if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) { + if (pExaScr->info->flags & EXA_MIXED_PIXMAPS) { + wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_mixed); + wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_mixed); + wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_mixed); + pExaScr->do_migration = exaDoMigration_mixed; + pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_mixed; + pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed; + pExaScr->do_move_out_pixmap = NULL; + } else { + wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver); + wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver); + wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_driver); + pExaScr->do_migration = NULL; + pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_driver; + pExaScr->do_move_in_pixmap = NULL; + pExaScr->do_move_out_pixmap = NULL; + } + } else { + wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic); + wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_classic); + wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_classic); + pExaScr->do_migration = exaDoMigration_classic; + pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_classic; + pExaScr->do_move_in_pixmap = exaMoveInPixmap_classic; + pExaScr->do_move_out_pixmap = exaMoveOutPixmap_classic; + } if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) { LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n", pScreen->myNum, @@ -1414,3 +1186,47 @@ void exaWaitSync(ScreenPtr pScreen) pExaScr->info->needsSync = FALSE; } } + +/** + * 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 (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) +{ + ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen; + ExaScreenPriv(pScreen); + + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return; + + if (pExaScr->do_migration) + (*pExaScr->do_migration)(pixmaps, npixmaps, can_accel); +} + +void +exaMoveInPixmap (PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return; + + if (pExaScr->do_move_in_pixmap) + (*pExaScr->do_move_in_pixmap)(pPixmap); +} + +void +exaMoveOutPixmap (PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return; + + if (pExaScr->do_move_out_pixmap) + (*pExaScr->do_move_out_pixmap)(pPixmap); +} @@ -586,14 +586,14 @@ typedef struct _ExaDriver { * 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, or - * #EXA_PREPARE_MASK, indicating which pixmap is in question. Since only up - * to three 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 the same pixmap may - * have PrepareAccess() called on it more than once, for example when doing - * a copy within the same pixmap (so it gets PrepareAccess as() - * #EXA_PREPARE_DEST and then as #EXA_PREPARE_SRC). + * 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() @@ -663,6 +663,7 @@ typedef struct _ExaDriver { #define EXA_PREPARE_AUX_DEST 3 #define EXA_PREPARE_AUX_SRC 4 #define EXA_PREPARE_AUX_MASK 5 + #define EXA_NUM_PREPARE_INDICES 6 /** @} */ /** @@ -707,8 +708,12 @@ typedef struct _ExaDriver { int depth, int bitsPerPixel, int devKind, pointer 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 depth, int usage_hint, int bitsPerPixel, + int *new_fb_pitch); /** @} */ } ExaDriverRec, *ExaDriverPtr; @@ -757,6 +762,13 @@ typedef struct _ExaDriver { */ #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 */ @@ -807,7 +819,7 @@ exaEnableDisableFBAccess (int index, Bool enable); extern _X_EXPORT Bool exaDrawableIsOffscreen (DrawablePtr pDrawable); -/* in exa_migration.c */ +/* in exa.c */ extern _X_EXPORT void exaMoveInPixmap (PixmapPtr pPixmap); diff --git a/exa/exa_accel.c b/exa/exa_accel.c index 001a4f0e2..33fbb9843 100644 --- a/exa/exa_accel.c +++ b/exa/exa_accel.c @@ -50,12 +50,6 @@ exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, int fullX1, fullX2, fullY1; int partX1, partX2; int off_x, off_y; - ExaMigrationRec pixmaps[1]; - - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pPixmap; - pixmaps[0].pReg = NULL; if (pExaScr->swappedOut || pGC->fillStyle != FillSolid || @@ -63,7 +57,16 @@ exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, { ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); return; - } else { + } + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = NULL; + exaDoMigration (pixmaps, 1, TRUE); } @@ -148,10 +151,9 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int nbox; int xoff, yoff; int bpp = pDrawable->bitsPerPixel; - Bool access_prepared = FALSE; Bool ret = TRUE; - if (pExaPixmap->accel_blocked) + if (pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen) return FALSE; /* Don't bother with under 8bpp, XYPixmaps. */ @@ -165,10 +167,10 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, if (pExaScr->swappedOut) return FALSE; - if (pExaPixmap->pDamage) { + if (pExaScr->do_migration) { ExaMigrationRec pixmaps[1]; - pixmaps[0].as_dst = TRUE; + pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; pixmaps[0].pPix = pPix; pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); @@ -178,7 +180,7 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); - if (!pPix || !pExaScr->info->UploadToScreen) + if (!pPix) return FALSE; x += pDrawable->x; @@ -220,9 +222,7 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, } } - if (access_prepared) - exaFinishAccess(pDrawable, EXA_PREPARE_DEST); - else + if (ret) exaMarkSync(pDrawable->pScreen); return ret; @@ -375,7 +375,6 @@ exaHWCopyNtoN (DrawablePtr pSrcDrawable, ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap; int src_off_x, src_off_y; int dst_off_x, dst_off_y; - ExaMigrationRec pixmaps[2]; RegionPtr srcregion = NULL, dstregion = NULL; xRectangle *rects; Bool ret = TRUE; @@ -425,14 +424,6 @@ exaHWCopyNtoN (DrawablePtr pSrcDrawable, } } - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pDstPixmap; - pixmaps[0].pReg = dstregion; - pixmaps[1].as_dst = FALSE; - pixmaps[1].as_src = TRUE; - pixmaps[1].pPix = pSrcPixmap; - pixmaps[1].pReg = srcregion; pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap); pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap); @@ -466,7 +457,20 @@ exaHWCopyNtoN (DrawablePtr pSrcDrawable, } } - exaDoMigration (pixmaps, 2, TRUE); + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[2]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pDstPixmap; + pixmaps[0].pReg = dstregion; + pixmaps[1].as_dst = FALSE; + pixmaps[1].as_src = TRUE; + pixmaps[1].pPix = pSrcPixmap; + pixmaps[1].pReg = srcregion; + + exaDoMigration (pixmaps, 2, TRUE); + } /* Mixed directions must be handled specially if the card is lame */ if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && @@ -766,7 +770,6 @@ exaPolyFillRect(DrawablePtr pDrawable, int xoff, yoff; int xorg, yorg; int n; - ExaMigrationRec pixmaps[2]; RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED); /* Compute intersection of rects and clip region */ @@ -777,11 +780,6 @@ exaPolyFillRect(DrawablePtr pDrawable, goto out; } - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pPixmap; - pixmaps[0].pReg = NULL; - exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); if (pExaScr->swappedOut || pExaPixmap->accel_blocked) @@ -814,7 +812,16 @@ exaPolyFillRect(DrawablePtr pDrawable, goto fallback; } - exaDoMigration (pixmaps, 1, TRUE); + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = NULL; + + exaDoMigration (pixmaps, 1, TRUE); + } if (!exaPixmapIsOffscreen (pPixmap) || !(*pExaScr->info->PrepareSolid) (pPixmap, @@ -972,23 +979,23 @@ exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); ExaPixmapPriv (pPixmap); int xoff, yoff; - ExaMigrationRec pixmaps[1]; Bool ret = FALSE; - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pPixmap; - pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid, - alu, clientClipType) - ? NULL : pRegion; - exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); if (pExaPixmap->accel_blocked) - { goto out; - } else { + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid, + alu, clientClipType) ? NULL : pRegion; + exaDoMigration (pixmaps, 1, TRUE); } @@ -1010,7 +1017,7 @@ exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, (*pExaScr->info->DoneSolid) (pPixmap); exaMarkSync(pDrawable->pScreen); - if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && + if (pExaPixmap->pDamage && pDrawable->width == 1 && pDrawable->height == 1 && pDrawable->bitsPerPixel != 24) { ExaPixmapPriv(pPixmap); @@ -1053,7 +1060,6 @@ exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile); int xoff, yoff; int tileWidth, tileHeight; - ExaMigrationRec pixmaps[2]; int nbox = REGION_NUM_RECTS (pRegion); BoxPtr pBox = REGION_RECTS (pRegion); Bool ret = FALSE; @@ -1070,23 +1076,25 @@ exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, exaGetPixmapFirstPixel (pTile), planemask, alu, clientClipType); - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); - pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled, - alu, clientClipType) - ? NULL : pRegion; - pixmaps[1].as_dst = FALSE; - pixmaps[1].as_src = TRUE; - pixmaps[1].pPix = pTile; - pixmaps[1].pReg = NULL; - + pPixmap = exaGetDrawablePixmap (pDrawable); pExaPixmap = ExaGetPixmapPriv (pPixmap); if (pExaPixmap->accel_blocked || pTileExaPixmap->accel_blocked) - { return FALSE; - } else { + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[2]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled, + alu, clientClipType) ? NULL : pRegion; + pixmaps[1].as_dst = FALSE; + pixmaps[1].as_src = TRUE; + pixmaps[1].pPix = pTile; + pixmaps[1].pReg = NULL; + exaDoMigration (pixmaps, 2, TRUE); } @@ -1225,31 +1233,36 @@ exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, unsigned int format, unsigned long planeMask, char *d) { ExaScreenPriv (pDrawable->pScreen); - ExaMigrationRec pixmaps[1]; - BoxRec Box; - RegionRec Reg; - PixmapPtr pPix; + PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); int xoff, yoff; Bool ok; - pixmaps[0].as_dst = FALSE; - pixmaps[0].as_src = TRUE; - pixmaps[0].pPix = pPix = exaGetDrawablePixmap (pDrawable); - pixmaps[0].pReg = &Reg; + if (pExaScr->swappedOut) + goto fallback; exaGetDrawableDeltas (pDrawable, pPix, &xoff, &yoff); - Box.x1 = pDrawable->y + x + xoff; - Box.y1 = pDrawable->y + y + yoff; - Box.x2 = Box.x1 + w; - Box.y2 = Box.y1 + h; + if (pExaScr->do_migration) { + BoxRec Box; + RegionRec Reg; + ExaMigrationRec pixmaps[1]; - REGION_INIT(pScreen, &Reg, &Box, 1); + Box.x1 = pDrawable->y + x + xoff; + Box.y1 = pDrawable->y + y + yoff; + Box.x2 = Box.x1 + w; + Box.y2 = Box.y1 + h; - if (pExaScr->swappedOut) - goto fallback; + REGION_INIT(pScreen, &Reg, &Box, 1); - exaDoMigration(pixmaps, 1, FALSE); + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + pixmaps[0].pPix = pPix; + pixmaps[0].pReg = &Reg; + + exaDoMigration(pixmaps, 1, FALSE); + + REGION_UNINIT(pScreen, &Reg); + } pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); @@ -1271,12 +1284,9 @@ exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, PixmapBytePad(w, pDrawable->depth)); if (ok) { exaWaitSync(pDrawable->pScreen); - goto out; + return; } fallback: ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); - -out: - REGION_UNINIT(pScreen, &Reg); } diff --git a/exa/exa_classic.c b/exa/exa_classic.c new file mode 100644 index 000000000..1eff57091 --- /dev/null +++ b/exa/exa_classic.c @@ -0,0 +1,258 @@ +/* + * 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->offscreen && 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->offscreen = 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; + REGION_INIT(pScreen, &pExaPixmap->validSys, &box, 0); + REGION_INIT(pScreen, &pExaPixmap->validFB, &box, 0); + + exaSetAccelBlock(pExaScr, pExaPixmap, + w, h, bpp); + + return pPixmap; +} + +Bool +exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPrivPtr pExaScr; + ExaPixmapPrivPtr pExaPixmap; + Bool ret; + + if (!pPixmap) + return FALSE; + + 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 offscreen 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->offscreen = 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 + * offscreen memory, so there's no need to track damage. + */ + if (pExaPixmap->pDamage) { + DamageUnregister(&pPixmap->drawable, 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); + + 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; + } + REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validSys); + REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validFB); + } + + swap(pExaScr, pScreen, DestroyPixmap); + ret = pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + + return ret; +} + +Bool +exaPixmapIsOffscreen_classic(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + ExaPixmapPriv(pPixmap); + Bool ret; + + if (pExaScr->info->PixmapIsOffscreen) { + pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); + ret = pExaScr->info->PixmapIsOffscreen(pPixmap); + pPixmap->devPrivate.ptr = NULL; + } else + ret = (pExaPixmap->offscreen && pExaPixmap->fb_ptr); + + return ret; +} diff --git a/exa/exa_driver.c b/exa/exa_driver.c new file mode 100644 index 000000000..97036955b --- /dev/null +++ b/exa/exa_driver.c @@ -0,0 +1,214 @@ +/* + * 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 !offscreen pixmaps. + * !offscreen 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); + + return pPixmap; +} + +Bool +exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPrivPtr pExaScr; + ExaPixmapPrivPtr pExaPixmap; + Bool ret; + + if (!pPixmap) + return FALSE; + + 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 non-offscreen 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); + + 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 +exaPixmapIsOffscreen_driver(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + Bool ret; + + pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); + ret = pExaScr->info->PixmapIsOffscreen(pPixmap); + pPixmap->devPrivate.ptr = NULL; + + return ret; +} diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c index b8d2e52bf..d621ccf76 100644 --- a/exa/exa_glyphs.c +++ b/exa/exa_glyphs.c @@ -372,7 +372,6 @@ exaGlyphCacheUploadGlyph(ScreenPtr pScreen, PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable; ExaPixmapPriv(pGlyphPixmap); PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable; - ExaMigrationRec pixmaps[1]; if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut || pExaPixmap->accel_blocked) goto composite; @@ -386,12 +385,16 @@ exaGlyphCacheUploadGlyph(ScreenPtr pScreen, if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel) goto composite; - /* cache pixmap must be offscreen. */ - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pCachePixmap; - pixmaps[0].pReg = NULL; - exaDoMigration (pixmaps, 1, TRUE); + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + /* cache pixmap must be offscreen. */ + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pCachePixmap; + pixmaps[0].pReg = NULL; + exaDoMigration (pixmaps, 1, TRUE); + } if (!exaPixmapIsOffscreen(pCachePixmap)) goto composite; diff --git a/exa/exa_migration.c b/exa/exa_migration_classic.c index f6805cb6e..d8e1e86da 100644 --- a/exa/exa_migration.c +++ b/exa/exa_migration_classic.c @@ -42,22 +42,6 @@ #endif /** - * Returns TRUE if the pixmap is not movable. This is the case where it's a - * pixmap which has no private (almost always bad) or it's a scratch pixmap created by - * some X Server internal component (the score says it's pinned). - */ -static Bool -exaPixmapIsPinned (PixmapPtr pPix) -{ - ExaPixmapPriv (pPix); - - if (pExaPixmap == NULL) - EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsPinned was called on a non-exa pixmap.\n"), TRUE); - - return pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED; -} - -/** * The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys * and exaCopyDirtyToFb both needed to do this loop. */ @@ -77,7 +61,7 @@ exaMemcpyBox (PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int 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 @@ -382,7 +366,7 @@ exaDoMoveInPixmap (ExaMigrationPtr migrate) } void -exaMoveInPixmap (PixmapPtr pPixmap) +exaMoveInPixmap_classic (PixmapPtr pPixmap) { static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE, .pReg = NULL }; @@ -423,7 +407,7 @@ exaDoMoveOutPixmap (ExaMigrationPtr migrate) } void -exaMoveOutPixmap (PixmapPtr pPixmap) +exaMoveOutPixmap_classic (PixmapPtr pPixmap) { static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE, .pReg = NULL }; @@ -607,17 +591,12 @@ out: * config file. */ void -exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) +exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) { ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen; ExaScreenPriv(pScreen); int i, j; - if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) - return; - if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) - return; - /* 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 diff --git a/exa/exa_migration_mixed.c b/exa/exa_migration_mixed.c new file mode 100644 index 000000000..d1ee9871b --- /dev/null +++ b/exa/exa_migration_mixed.c @@ -0,0 +1,194 @@ +/* + * 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" + +static void +exaUploadFallback(PixmapPtr pPixmap, CARD8 *src, int src_pitch) +{ + ExaPixmapPriv(pPixmap); + RegionPtr damage = DamageRegion (pExaPixmap->pDamage); + GCPtr pGC = GetScratchGC (pPixmap->drawable.depth, + pPixmap->drawable.pScreen); + int nbox, cpp = pPixmap->drawable.bitsPerPixel / 8; + DamagePtr backup = pExaPixmap->pDamage; + BoxPtr pbox; + CARD8 *src2; + + /* We don't want damage optimisations. */ + pExaPixmap->pDamage = NULL; + ValidateGC (&pPixmap->drawable, pGC); + + pbox = REGION_RECTS(damage); + nbox = REGION_NUM_RECTS(damage); + + while (nbox--) { + src2 = src + pbox->y1 * src_pitch + pbox->x1 * cpp; + + ExaCheckPutImage(&pPixmap->drawable, pGC, + pPixmap->drawable.depth, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, 0, + ZPixmap, (char*) src2); + + pbox++; + } + + FreeScratchGC (pGC); + pExaPixmap->pDamage = backup; +} + +void +exaCreateDriverPixmap_mixed(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + ExaPixmapPriv(pPixmap); + RegionPtr damage = DamageRegion (pExaPixmap->pDamage); + void *sys_buffer = pExaPixmap->sys_ptr; + 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 sys_pitch = pExaPixmap->sys_pitch; + int paddedWidth = sys_pitch; + int nbox; + BoxPtr pbox; + + /* 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; + + pExaPixmap->offscreen = TRUE; + pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr = NULL; + pExaPixmap->sys_pitch = pPixmap->devKind = 0; + + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, + paddedWidth, NULL); + + /* scratch pixmaps */ + if (!w || !h) + goto finish; + + /* we do not malloc memory by default. */ + if (!sys_buffer) + goto finish; + + if (!pExaScr->info->UploadToScreen) + goto fallback; + + pbox = REGION_RECTS(damage); + nbox = REGION_NUM_RECTS(damage); + + while (nbox--) { + if (!pExaScr->info->UploadToScreen(pPixmap, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1, (char *) (sys_buffer) + pbox->y1 * sys_pitch + pbox->x1 * (bpp / 8), sys_pitch)) + goto fallback; + + pbox++; + } + + goto finish; + +fallback: + exaUploadFallback(pPixmap, sys_buffer, sys_pitch); + +finish: + free(sys_buffer); + + /* We no longer need this. */ + if (pExaPixmap->pDamage) { + DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); + DamageDestroy(pExaPixmap->pDamage); + pExaPixmap->pDamage = 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) && + !exaPixmapIsOffscreen (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); + } +} + +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); +} diff --git a/exa/exa_mixed.c b/exa/exa_mixed.c new file mode 100644 index 000000000..01f87ba87 --- /dev/null +++ b/exa/exa_mixed.c @@ -0,0 +1,251 @@ +/* + * 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. + * A pinned pixmap implies one that is either driver based already or otherwise altered. + * Proper care is taken to free the initially allocated buffer. + */ + +static _X_INLINE void* +ExaGetPixmapAddress(PixmapPtr p) +{ + ExaPixmapPriv(p); + + return pExaPixmap->sys_ptr; +} + +/** + * exaCreatePixmap() creates a new pixmap. + * + * Pixmaps are always marked as pinned, unless the pixmap can still be transfered to a + * driver pixmaps. + */ +PixmapPtr +exaCreatePixmap_mixed(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; + + paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); + if (paddedWidth / 4 > 32767 || h > 32767) + return NullPixmap; + + datasize = h * paddedWidth; + + /* 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->offscreen = FALSE; + pExaPixmap->fb_ptr = NULL; + pExaPixmap->pDamage = NULL; + + exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp); + exaSetAccelBlock(pExaScr, pExaPixmap, + w, h, bpp); + + /* Avoid freeing sys_ptr. */ + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + + (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, + paddedWidth, NULL); + + /* We want to be able to transfer the pixmap to driver memory later on. */ + pExaPixmap->score = EXA_PIXMAP_SCORE_INIT; + + /* A scratch pixmap will become a driver pixmap right away. */ + if (!w || !h) { + exaCreateDriverPixmap_mixed(pPixmap); + } else { + /* 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); + } + + return pPixmap; +} + +Bool +exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPrivPtr pExaScr; + ExaPixmapPrivPtr pExaPixmap; + Bool ret; + + if (!pPixmap) + return FALSE; + + pExaScr = ExaGetScreenPriv(pScreen); + pExaPixmap = ExaGetPixmapPriv(pPixmap); + + if (pExaPixmap) { + if (!exaPixmapIsPinned(pPixmap)) { + free(pExaPixmap->sys_ptr); + pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr = NULL; + pExaPixmap->sys_pitch = pPixmap->devKind = 0; + + /* We no longer need this. */ + if (pExaPixmap->pDamage) { + DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); + DamageDestroy(pExaPixmap->pDamage); + pExaPixmap->pDamage = NULL; + } + } + + 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); + } + + /* Anything can happen, don't try to predict it all. */ + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + } + + /* Only pass driver pixmaps to the driver. */ + if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) { + 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 non-offscreen 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_mixed(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + Bool ret; + + if (pPixmap->refcnt == 1) + { + ExaPixmapPriv (pPixmap); + + if (pExaPixmap->driverPriv) + pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); + else if (pExaPixmap->sys_ptr && !exaPixmapIsPinned(pPixmap)) + free(pExaPixmap->sys_ptr); + pExaPixmap->driverPriv = NULL; + pExaPixmap->sys_ptr = NULL; + } + + swap(pExaScr, pScreen, DestroyPixmap); + ret = pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + + return ret; +} + +Bool +exaPixmapIsOffscreen_mixed(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + ExaPixmapPriv(pPixmap); + pointer 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; +} diff --git a/exa/exa_priv.h b/exa/exa_priv.h index b3df1a586..869cf1772 100644 --- a/exa/exa_priv.h +++ b/exa/exa_priv.h @@ -142,6 +142,13 @@ typedef struct { #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)(int, Bool); typedef struct { ExaDriverPtr info; @@ -165,7 +172,11 @@ typedef struct { TrapezoidsProcPtr SavedTrapezoids; AddTrapsProcPtr SavedAddTraps; #endif - + void (*do_migration) (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel); + Bool (*pixmap_is_offscreen) (PixmapPtr pPixmap); + void (*do_move_in_pixmap) (PixmapPtr pPixmap); + void (*do_move_out_pixmap) (PixmapPtr pPixmap); + Bool swappedOut; enum ExaMigrationHeuristic migration; Bool checkDirtyCorrectness; @@ -176,8 +187,11 @@ typedef struct { CARD32 lastDefragment; CARD32 nextDefragment; - /* Store all accessed pixmaps, so we can check for duplicates. */ - PixmapPtr prepare_access[6]; + /* Reference counting for accessed pixmaps */ + struct { + PixmapPtr pixmap; + int count; + } access[EXA_NUM_PREPARE_INDICES]; /* Holds information on fallbacks that cannot be relayed otherwise. */ unsigned int fallback_flags; @@ -300,13 +314,6 @@ typedef struct { GCFuncs *Savedfuncs; } ExaGCPrivRec, *ExaGCPrivPtr; -typedef struct _ExaMigrationRec { - Bool as_dst; - Bool as_src; - PixmapPtr pPix; - RegionPtr pReg; -} ExaMigrationRec, *ExaMigrationPtr; - typedef struct { PicturePtr pDst; INT16 xSrc; @@ -440,6 +447,34 @@ 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; #ifdef RENDER @@ -503,36 +538,77 @@ exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp); PixmapPtr exaGetDrawablePixmap(DrawablePtr pDrawable); -RegionPtr -exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, - int srcx, int srcy, int width, int height, int dstx, int dsty); +void +exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap, + int w, int h, int bpp); -Bool -exaHWCopyNtoN (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - BoxPtr pbox, - int nbox, - int dx, - int dy, - Bool reverse, - Bool upsidedown); +void +exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap, + int w, int h, int bpp); void -exaCopyNtoN (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - BoxPtr pbox, - int nbox, - int dx, - int dy, - Bool reverse, - Bool upsidedown, - Pixel bitplane, - void *closure); +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, pointer pPixData); + +Bool +exaDestroyPixmap_classic (PixmapPtr pPixmap); + +Bool +exaPixmapIsOffscreen_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, pointer pPixData); + +Bool +exaDestroyPixmap_driver (PixmapPtr pPixmap); + +Bool +exaPixmapIsOffscreen_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, pointer pPixData); + +Bool +exaDestroyPixmap_mixed(PixmapPtr pPixmap); + +Bool +exaPixmapIsOffscreen_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); + /* exa_render.c */ Bool exaOpReadsDestination (CARD8 op); @@ -587,11 +663,17 @@ exaGlyphs (CARD8 op, GlyphListPtr list, GlyphPtr *glyphs); -/* exa_migration.c */ +/* exa_migration_classic.c */ void -exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel); +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); + #endif /* EXAPRIV_H */ diff --git a/exa/exa_render.c b/exa/exa_render.c index 14d710b57..d46930130 100644 --- a/exa/exa_render.c +++ b/exa/exa_render.c @@ -54,6 +54,12 @@ static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n) case PICT_x8r8g8b8: snprintf(format, 20, "XRGB8888"); break; + case PICT_b8g8r8a8: + snprintf(format, 20, "BGRA8888"); + break; + case PICT_b8g8r8x8: + snprintf(format, 20, "BGRX8888"); + break; case PICT_r5g6b5: snprintf(format, 20, "RGB565 "); break; @@ -71,11 +77,17 @@ static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n) break; } - loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; + if (pict->pDrawable) { + loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; - snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, - pict->pDrawable->height, pict->repeat ? - " R" : ""); + snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, + pict->pDrawable->height, pict->repeat ? + " R" : ""); + } else { + loc = '-'; + + snprintf(size, 20, "%s", pict->repeat ? " R" : ""); + } snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size); } @@ -138,32 +150,26 @@ exaGetPixelFromRGBA(CARD32 *pixel, CARD16 green, CARD16 blue, CARD16 alpha, - CARD32 format) + PictFormatPtr pFormat) { int rbits, bbits, gbits, abits; int rshift, bshift, gshift, ashift; *pixel = 0; - if (!PICT_FORMAT_COLOR(format)) + if (!PICT_FORMAT_COLOR(pFormat->format) && + PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A) return FALSE; - rbits = PICT_FORMAT_R(format); - gbits = PICT_FORMAT_G(format); - bbits = PICT_FORMAT_B(format); - abits = PICT_FORMAT_A(format); - - if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { - bshift = 0; - gshift = bbits; - rshift = gshift + gbits; - ashift = rshift + rbits; - } else { /* PICT_TYPE_ABGR */ - rshift = 0; - gshift = rbits; - bshift = gshift + gbits; - ashift = bshift + bbits; - } + rbits = PICT_FORMAT_R(pFormat->format); + gbits = PICT_FORMAT_G(pFormat->format); + bbits = PICT_FORMAT_B(pFormat->format); + abits = PICT_FORMAT_A(pFormat->format); + + rshift = pFormat->direct.red; + gshift = pFormat->direct.green; + bshift = pFormat->direct.blue; + ashift = pFormat->direct.alpha; *pixel |= ( blue >> (16 - bbits)) << bshift; *pixel |= ( red >> (16 - rbits)) << rshift; @@ -179,30 +185,24 @@ exaGetRGBAFromPixel(CARD32 pixel, CARD16 *green, CARD16 *blue, CARD16 *alpha, - CARD32 format) + PictFormatPtr pFormat) { int rbits, bbits, gbits, abits; int rshift, bshift, gshift, ashift; - if (!PICT_FORMAT_COLOR(format)) + if (!PICT_FORMAT_COLOR(pFormat->format) && + PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A) return FALSE; - rbits = PICT_FORMAT_R(format); - gbits = PICT_FORMAT_G(format); - bbits = PICT_FORMAT_B(format); - abits = PICT_FORMAT_A(format); - - if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { - bshift = 0; - gshift = bbits; - rshift = gshift + gbits; - ashift = rshift + rbits; - } else { /* PICT_TYPE_ABGR */ - rshift = 0; - gshift = rbits; - bshift = gshift + gbits; - ashift = bshift + bbits; - } + rbits = PICT_FORMAT_R(pFormat->format); + gbits = PICT_FORMAT_G(pFormat->format); + bbits = PICT_FORMAT_B(pFormat->format); + abits = PICT_FORMAT_A(pFormat->format); + + rshift = pFormat->direct.red; + gshift = pFormat->direct.green; + bshift = pFormat->direct.blue; + ashift = pFormat->direct.alpha; *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); while (rbits < 16) { @@ -250,28 +250,22 @@ exaTryDriverSolidFill(PicturePtr pSrc, int nbox; int dst_off_x, dst_off_y; PixmapPtr pSrcPix, pDstPix; - ExaPixmapPrivPtr pSrcExaPix, pDstExaPix; + ExaPixmapPrivPtr pDstExaPix; CARD32 pixel; CARD16 red, green, blue, alpha; - ExaMigrationRec pixmaps[1]; pDstPix = exaGetDrawablePixmap (pDst->pDrawable); - pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); - - pSrcExaPix = ExaGetPixmapPriv(pSrcPix); pDstExaPix = ExaGetPixmapPriv(pDstPix); - /* Check whether the accelerator can use these pixmaps. + /* Check whether the accelerator can use the destination pixmap. */ - if (pSrcExaPix->accel_blocked || pDstExaPix->accel_blocked) + if (pDstExaPix->accel_blocked) { return -1; } xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, xSrc, ySrc, 0, 0, xDst, yDst, @@ -282,31 +276,37 @@ exaTryDriverSolidFill(PicturePtr pSrc, REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); - pixel = exaGetPixmapFirstPixel (pSrcPix); - - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pDstPix; - pixmaps[0].pReg = ®ion; - exaDoMigration(pixmaps, 1, TRUE); + if (pSrc->pDrawable) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; - if (!exaPixmapIsOffscreen(pDstPix)) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 0; - } + pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); + pixel = exaGetPixmapFirstPixel (pSrcPix); + } else + pixel = pSrc->pSourcePict->solidFill.color; if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha, - pSrc->format)) + pSrc->pFormat) || + !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, + pDst->pFormat)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return -1; } - if (!exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, - pDst->format)) - { + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pDstPix; + pixmaps[0].pReg = ®ion; + exaDoMigration(pixmaps, 1, TRUE); + } + + if (!exaPixmapIsOffscreen(pDstPix)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return -1; + return 0; } if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) @@ -341,17 +341,18 @@ exaTryDriverCompositeRects(CARD8 op, { ExaScreenPriv (pDst->pDrawable->pScreen); int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; - PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; - ExaPixmapPrivPtr pSrcExaPix, pMaskExaPix = NULL, pDstExaPix; - ExaMigrationRec pixmaps[3]; + PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; + ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; if (!pExaScr->info->PrepareComposite) return -1; - pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); - pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + if (pSrc->pDrawable) { + pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); + pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + } - if (pMask) { + if (pMask && pMask->pDrawable) { pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); pMaskExaPix = ExaGetPixmapPriv(pMaskPix); } @@ -363,8 +364,9 @@ exaTryDriverCompositeRects(CARD8 op, * FIXME: If it cannot, use temporary pixmaps so that the drawing * happens within limits. */ - if (pSrcExaPix->accel_blocked || pDstExaPix->accel_blocked || - (pMask && pMaskExaPix->accel_blocked)) + if (pDstExaPix->accel_blocked || + (pSrcExaPix && pSrcExaPix->accel_blocked) || + (pMaskExaPix && pMaskExaPix->accel_blocked)) { return -1; } @@ -374,36 +376,48 @@ exaTryDriverCompositeRects(CARD8 op, { return -1; } - - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = exaOpReadsDestination(op); - pixmaps[0].pPix = pDstPix; - pixmaps[0].pReg = NULL; - pixmaps[1].as_dst = FALSE; - pixmaps[1].as_src = TRUE; - pixmaps[1].pPix = pSrcPix; - pixmaps[1].pReg = NULL; - if (pMask) { - pixmaps[2].as_dst = FALSE; - pixmaps[2].as_src = TRUE; - pixmaps[2].pPix = pMaskPix; - pixmaps[2].pReg = NULL; - exaDoMigration(pixmaps, 3, TRUE); - } else - exaDoMigration(pixmaps, 2, TRUE); + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[3]; + int i = 0; + + pixmaps[i].as_dst = TRUE; + pixmaps[i].as_src = exaOpReadsDestination(op); + pixmaps[i].pPix = pDstPix; + pixmaps[i].pReg = NULL; + i++; + + if (pSrcPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pSrcPix; + pixmaps[i].pReg = NULL; + i++; + } + + if (pMaskPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pMaskPix; + pixmaps[i].pReg = NULL; + i++; + } + + exaDoMigration(pixmaps, i, TRUE); + } pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); if (!pDstPix) return 0; - - pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); - if (!pSrcPix) - return 0; + if (pSrcPix) { + pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + if (!pSrcPix) + return 0; + } - if (pMask) { + if (pMaskPix) { pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, &mask_off_y); - if (!pMaskPix) return 0; } @@ -416,15 +430,24 @@ exaTryDriverCompositeRects(CARD8 op, { INT16 xDst = rects->xDst + pDst->pDrawable->x; INT16 yDst = rects->yDst + pDst->pDrawable->y; - INT16 xMask = pMask ? rects->xMask + pMask->pDrawable->x : 0; - INT16 yMask = pMask ? rects->yMask + pMask->pDrawable->y : 0; - INT16 xSrc = rects->xSrc + pSrc->pDrawable->x; - INT16 ySrc = rects->ySrc + pSrc->pDrawable->y; - + INT16 xMask = rects->xMask; + INT16 yMask = rects->yMask; + INT16 xSrc = rects->xSrc; + INT16 ySrc = rects->ySrc; RegionRec region; BoxPtr pbox; int nbox; - + + if (pMaskPix) { + xMask += pMask->pDrawable->x; + yMask += pMask->pDrawable->y; + } + + if (pSrcPix) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + } + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, rects->width, rects->height)) @@ -482,8 +505,6 @@ exaCompositeRects(CARD8 op, ExaCompositeRectPtr rects) { ExaScreenPriv (pDst->pDrawable->pScreen); - PixmapPtr pPixmap = exaGetDrawablePixmap(pDst->pDrawable); - ExaPixmapPriv(pPixmap); int n; ExaCompositeRectPtr r; int ret; @@ -491,7 +512,7 @@ exaCompositeRects(CARD8 op, /* If we get a mask, that means we're rendering to the exaGlyphs * destination directly, so the damage layer takes care of this. */ - if (!pMask && pExaPixmap->pDamage) { + if (!pMask) { RegionRec region; int x1 = MAXSHORT; int y1 = MAXSHORT; @@ -585,7 +606,7 @@ exaCompositeRects(CARD8 op, /************************************************************/ - if (!pMask && pExaPixmap->pDamage) { + if (!pMask) { /* Now we have to flush the damage out from pendingDamage => damage * Calling DamageRegionProcessPending has that effect. */ @@ -613,17 +634,18 @@ exaTryDriverComposite(CARD8 op, BoxPtr pbox; int nbox; int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; - PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; - ExaPixmapPrivPtr pSrcExaPix, pMaskExaPix = NULL, pDstExaPix; - ExaMigrationRec pixmaps[3]; + PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; + ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; - pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); - pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + if (pSrc->pDrawable) { + pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); + pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + } pDstPix = exaGetDrawablePixmap(pDst->pDrawable); pDstExaPix = ExaGetPixmapPriv(pDstPix); - if (pMask) { + if (pMask && pMask->pDrawable) { pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); pMaskExaPix = ExaGetPixmapPriv(pMaskPix); } @@ -632,8 +654,8 @@ exaTryDriverComposite(CARD8 op, * FIXME: If it cannot, use temporary pixmaps so that the drawing * happens within limits. */ - if (pSrcExaPix->accel_blocked || - pDstExaPix->accel_blocked || + if (pDstExaPix->accel_blocked || + (pSrcExaPix && pSrcExaPix->accel_blocked) || (pMask && (pMaskExaPix->accel_blocked))) { return -1; @@ -642,13 +664,15 @@ exaTryDriverComposite(CARD8 op, xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; - if (pMask) { + if (pMaskPix) { xMask += pMask->pDrawable->x; yMask += pMask->pDrawable->y; } - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; + if (pSrcPix) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + } if (pExaScr->info->CheckComposite && !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) @@ -665,35 +689,53 @@ exaTryDriverComposite(CARD8 op, REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = exaOpReadsDestination(op); - pixmaps[0].pPix = pDstPix; - pixmaps[0].pReg = pixmaps[0].as_src ? NULL : ®ion; - pixmaps[1].as_dst = FALSE; - pixmaps[1].as_src = TRUE; - pixmaps[1].pPix = pSrcPix; - pixmaps[1].pReg = NULL; - if (pMask) { - pixmaps[2].as_dst = FALSE; - pixmaps[2].as_src = TRUE; - pixmaps[2].pPix = pMaskPix; - pixmaps[2].pReg = NULL; - exaDoMigration(pixmaps, 3, TRUE); - } else { - exaDoMigration(pixmaps, 2, TRUE); + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[3]; + int i = 0; + + pixmaps[i].as_dst = TRUE; + pixmaps[i].as_src = exaOpReadsDestination(op); + pixmaps[i].pPix = pDstPix; + pixmaps[i].pReg = pixmaps[0].as_src ? NULL : ®ion; + i++; + + if (pSrcPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pSrcPix; + pixmaps[i].pReg = NULL; + i++; + } + + if (pMaskPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pMaskPix; + pixmaps[i].pReg = NULL; + i++; + } + + exaDoMigration(pixmaps, i, TRUE); } - pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); - if (pMask) + if (pSrcPix) { + pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + if (!pSrcPix) { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 0; + } + } + + if (pMaskPix) { pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, &mask_off_y); - - if (!exaPixmapIsOffscreen(pDstPix)) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 0; + if (!pMaskPix) { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 0; + } } - if (!pSrcPix || (pMask && !pMaskPix)) { + if (!exaPixmapIsOffscreen(pDstPix)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return 0; } @@ -844,43 +886,44 @@ exaComposite(CARD8 op, Bool saveMaskRepeat = pMask ? pMask->repeat : 0; RegionRec region; - /* We currently don't support acceleration of gradients, or other pictures - * with a NULL pDrawable. - */ - if (pExaScr->swappedOut || - pSrc->pDrawable == NULL || (pMask != NULL && pMask->pDrawable == NULL)) - { + if (pExaScr->swappedOut) goto fallback; - } /* Remove repeat in source if useless */ - if (pSrc->repeat && !pSrc->transform && xSrc >= 0 && + if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 && (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && (ySrc + height) <= pSrc->pDrawable->height) pSrc->repeat = 0; - if (!pMask) + if (!pMask && !pSrc->alphaMap && !pDst->alphaMap && + (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) { - if ((op == PictOpSrc && - ((pSrc->format == pDst->format) || - (pSrc->format==PICT_a8r8g8b8 && pDst->format==PICT_x8r8g8b8) || - (pSrc->format==PICT_a8b8g8r8 && pDst->format==PICT_x8b8g8r8))) || - (op == PictOpOver && !pSrc->alphaMap && !pDst->alphaMap && - pSrc->format == pDst->format && - (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8))) + if (pSrc->pDrawable ? + (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && + pSrc->repeat) : + (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) { - if (pSrc->pDrawable->width == 1 && - pSrc->pDrawable->height == 1 && - pSrc->repeat) - { - ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, - width, height); - if (ret == 1) - goto done; - } - else if (pSrc->pDrawable != NULL && - !pSrc->repeat && - !pSrc->transform) + ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, + width, height); + if (ret == 1) + goto done; + } else if (pSrc->pDrawable && !pSrc->transform && + ((op == PictOpSrc && + (pSrc->format == pDst->format || + (PICT_FORMAT_COLOR(pDst->format) && + PICT_FORMAT_COLOR(pSrc->format) && + pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format), + PICT_FORMAT_TYPE(pSrc->format), + 0, + PICT_FORMAT_R(pSrc->format), + PICT_FORMAT_G(pSrc->format), + PICT_FORMAT_B(pSrc->format))))) || + (op == PictOpOver && pSrc->format == pDst->format && + !PICT_FORMAT_A(pSrc->format)))) + { + if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 && + (xSrc + width <= pSrc->pDrawable->width) && + (ySrc + height <= pSrc->pDrawable->height)) { Bool ret; xDst += pDst->pDrawable->x; @@ -909,10 +952,9 @@ exaComposite(CARD8 op, goto done; } - else if (pSrc->pDrawable != NULL && - pSrc->pDrawable->type == DRAWABLE_PIXMAP && - !pSrc->transform && - pSrc->repeatType == RepeatNormal) + + if (pSrc->repeat && pSrc->repeatType == RepeatNormal && + pSrc->pDrawable->type == DRAWABLE_PIXMAP) { DDXPointRec patOrg; @@ -962,9 +1004,9 @@ exaComposite(CARD8 op, } /* Remove repeat in mask if useless */ - if (pMask && pMask->repeat && !pMask->transform && xMask >= 0 && - (xMask + width) <= pMask->pDrawable->width && yMask >= 0 && - (yMask + height) <= pMask->pDrawable->height) + if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform && + xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && + yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) pMask->repeat = 0; if (pExaScr->info->PrepareComposite && @@ -980,9 +1022,10 @@ exaComposite(CARD8 op, /* For generic masks and solid src pictures, mach64 can do Over in two * passes, similar to the component-alpha case. */ - isSrcSolid = pSrc->pDrawable->width == 1 && - pSrc->pDrawable->height == 1 && - pSrc->repeat; + isSrcSolid = pSrc->pDrawable ? + (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && + pSrc->repeat) : + (pSrc->pSourcePict->type == SourcePictTypeSolidFill); /* If we couldn't do the Composite in a single pass, and it was a * component-alpha Over, see if we can do it in two passes with diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c index 0d53b67d8..f4700adac 100644 --- a/exa/exa_unaccel.c +++ b/exa/exa_unaccel.c @@ -492,58 +492,37 @@ ExaCheckAddTraps (PicturePtr pPicture, /** * 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. - * - * XXX This really belongs in fb, so it can be aware of tiling and etc. */ CARD32 exaGetPixmapFirstPixel (PixmapPtr pPixmap) { - CARD32 pixel; - void *fb; - Bool need_finish = FALSE; - BoxRec box; - RegionRec migration; - ExaPixmapPriv (pPixmap); - Bool sys_valid = pExaPixmap->pDamage && - !miPointInRegion(&pExaPixmap->validSys, 0, 0, &box); - Bool damaged = pExaPixmap->pDamage && - miPointInRegion(DamageRegion(pExaPixmap->pDamage), 0, 0, &box); - Bool offscreen = exaPixmapIsOffscreen(pPixmap); - - fb = pExaPixmap->sys_ptr; - - /* Try to avoid framebuffer readbacks */ - if ((!offscreen && !sys_valid && !damaged) || - (offscreen && (!sys_valid || damaged))) - { - box.x1 = 0; - box.y1 = 0; - box.x2 = 1; - box.y2 = 1; - REGION_INIT(pScreen, &migration, &box, 1); - - need_finish = TRUE; - - exaPrepareAccessReg(&pPixmap->drawable, EXA_PREPARE_SRC, &migration); - fb = pPixmap->devPrivate.ptr; - } - switch (pPixmap->drawable.bitsPerPixel) { case 32: - pixel = *(CARD32 *)fb; - break; + { + CARD32 pixel; + + pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1, + ZPixmap, ~0, (char*)&pixel); + return pixel; + } case 16: - pixel = *(CARD16 *)fb; - break; + { + CARD16 pixel; + + pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1, + ZPixmap, ~0, (char*)&pixel); + return pixel; + } + case 8: + { + CARD8 pixel; + + pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1, + ZPixmap, ~0, (char*)&pixel); + return pixel; + } default: - pixel = *(CARD8 *)fb; - break; + FatalError("%s called for invalid bpp %d\n", __func__, + pPixmap->drawable.bitsPerPixel); } - - if (need_finish) { - exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); - REGION_UNINIT(pScreen, &migration); - } - - return pixel; } |