summaryrefslogtreecommitdiff
path: root/exa
diff options
context:
space:
mode:
Diffstat (limited to 'exa')
-rw-r--r--exa/exa.c38
-rw-r--r--exa/exa_migration.c362
-rw-r--r--exa/exa_priv.h29
3 files changed, 262 insertions, 167 deletions
diff --git a/exa/exa.c b/exa/exa.c
index 548f76ad9..f83fdf58e 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -86,7 +86,7 @@ exaGetPixmapSize(PixmapPtr pPix)
pExaPixmap = ExaGetPixmapPriv(pPix);
if (pExaPixmap != NULL)
- return pExaPixmap->size;
+ return pExaPixmap->fb_size;
return 0;
}
@@ -139,13 +139,25 @@ exaDestroyPixmap (PixmapPtr pPixmap)
pPixmap->drawable.height));
/* Free the offscreen area */
exaOffscreenFree (pPixmap->drawable.pScreen, pExaPixmap->area);
- pPixmap->devPrivate = pExaPixmap->devPrivate;
- pPixmap->devKind = pExaPixmap->devKind;
+ pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
+ pPixmap->devKind = pExaPixmap->sys_pitch;
}
}
return fbDestroyPixmap (pPixmap);
}
+static int
+exaLog2(int val)
+{
+ int bits;
+
+ if (!val)
+ return 0;
+ for (bits = 0; val != 0; bits++)
+ val >>= 1;
+ return bits - 1;
+}
+
/**
* exaCreatePixmap() creates a new pixmap.
*
@@ -170,6 +182,8 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth)
return NULL;
pExaPixmap = ExaGetPixmapPriv(pPixmap);
+ bpp = pPixmap->drawable.bitsPerPixel;
+
/* Glyphs have w/h equal to zero, and may not be migrated. See exaGlyphs. */
if (!w || !h)
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
@@ -177,6 +191,24 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth)
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 > 32767) {
+ fbDestroyPixmap(pPixmap);
+ return NULL;
+ }
+
pExaPixmap->dirty = FALSE;
return pPixmap;
diff --git a/exa/exa_migration.c b/exa/exa_migration.c
index 68f88047c..e7c180219 100644
--- a/exa/exa_migration.c
+++ b/exa/exa_migration.c
@@ -1,25 +1,28 @@
/*
- * Copyright © 2001 Keith Packard
+ * Copyright © 2006 Intel Corporation
*
- * Partly based on code that is Copyright © The XFree86 Project Inc.
+ * 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:
*
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
*
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_DIX_CONFIG_H
@@ -54,15 +57,131 @@ exaPixmapIsPinned (PixmapPtr pPix)
return pExaPixmap == NULL || pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED;
}
+/**
+ * If the pixmap is currently dirty, this copies at least the dirty area from
+ * the framebuffer memory copy to the system memory copy. Both areas must be
+ * allocated.
+ */
+static void
+exaCopyDirtyToSys (PixmapPtr pPixmap)
+{
+ ExaScreenPriv (pPixmap->drawable.pScreen);
+ ExaPixmapPriv (pPixmap);
+ CARD8 *save_ptr;
+ int save_pitch;
+
+ if (!pExaPixmap->dirty)
+ return;
+
+ save_ptr = pPixmap->devPrivate.ptr;
+ save_pitch = pPixmap->devKind;
+ pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
+ pPixmap->devKind = pExaPixmap->fb_pitch;
+
+ if (pExaScr->info->DownloadFromScreen == NULL ||
+ !pExaScr->info->DownloadFromScreen (pPixmap,
+ 0,
+ 0,
+ pPixmap->drawable.width,
+ pPixmap->drawable.height,
+ pExaPixmap->sys_ptr,
+ pExaPixmap->sys_pitch))
+ {
+ char *src, *dst;
+ int src_pitch, dst_pitch, i, bytes;
+
+ exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+
+ dst = pExaPixmap->sys_ptr;
+ dst_pitch = pExaPixmap->sys_pitch;
+ src = pExaPixmap->fb_ptr;
+ src_pitch = pExaPixmap->fb_pitch;
+ bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
+
+ for (i = 0; i < pPixmap->drawable.height; i++) {
+ memcpy (dst, src, bytes);
+ dst += dst_pitch;
+ src += src_pitch;
+ }
+ exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+ }
+
+ /* Make sure the bits have actually landed, since we don't necessarily sync
+ * when accessing pixmaps in system memory.
+ */
+ exaWaitSync (pPixmap->drawable.pScreen);
+
+ pPixmap->devPrivate.ptr = save_ptr;
+ pPixmap->devKind = save_pitch;
+
+ pExaPixmap->dirty = FALSE;
+}
+
+/**
+ * If the pixmap is currently dirty, this copies at least the dirty area from
+ * the system memory copy to the framebuffer memory copy. Both areas must be
+ * allocated.
+ */
+static void
+exaCopyDirtyToFb (PixmapPtr pPixmap)
+{
+ ExaScreenPriv (pPixmap->drawable.pScreen);
+ ExaPixmapPriv (pPixmap);
+ CARD8 *save_ptr;
+ int save_pitch;
+
+ if (!pExaPixmap->dirty)
+ return;
+
+ save_ptr = pPixmap->devPrivate.ptr;
+ save_pitch = pPixmap->devKind;
+ pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
+ pPixmap->devKind = pExaPixmap->fb_pitch;
+
+ if (pExaScr->info->UploadToScreen == NULL ||
+ !pExaScr->info->UploadToScreen (pPixmap,
+ 0,
+ 0,
+ pPixmap->drawable.width,
+ pPixmap->drawable.height,
+ pExaPixmap->sys_ptr,
+ pExaPixmap->sys_pitch))
+ {
+ char *src, *dst;
+ int src_pitch, dst_pitch, i, bytes;
+
+ exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
+
+ dst = pExaPixmap->fb_ptr;
+ dst_pitch = pExaPixmap->fb_pitch;
+ src = pExaPixmap->sys_ptr;
+ src_pitch = pExaPixmap->sys_pitch;
+ bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
+
+ for (i = 0; i < pPixmap->drawable.height; i++) {
+ memcpy (dst, src, bytes);
+ dst += dst_pitch;
+ src += src_pitch;
+ }
+ exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
+ }
+
+ pPixmap->devPrivate.ptr = save_ptr;
+ pPixmap->devKind = save_pitch;
+
+ pExaPixmap->dirty = FALSE;
+}
+
+/**
+ * Copies out important pixmap data and removes references to framebuffer area.
+ * Called when the memory manager decides it's time to kick the pixmap out of
+ * framebuffer entirely.
+ */
static void
exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
{
PixmapPtr pPixmap = area->privData;
- ExaScreenPriv (pScreen);
ExaPixmapPriv(pPixmap);
- int dst_pitch, src_pitch, bytes;
- char *dst, *src;
- int i;
DBG_MIGRATE (("Save %p (%p) (%dx%d)\n",
(void*)pPixmap->drawable.id,
@@ -71,171 +190,99 @@ exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
pPixmap->drawable.width,
pPixmap->drawable.height));
- src_pitch = pPixmap->devKind;
- dst_pitch = pExaPixmap->devKind;
-
- src = pPixmap->devPrivate.ptr;
- dst = pExaPixmap->devPrivate.ptr;
-
- if (pExaPixmap->dirty) {
- if (pExaScr->info->DownloadFromScreen &&
- (*pExaScr->info->DownloadFromScreen) (pPixmap,
- pPixmap->drawable.x,
- pPixmap->drawable.y,
- pPixmap->drawable.width,
- pPixmap->drawable.height,
- dst, dst_pitch)) {
-
- } else {
- exaWaitSync (pPixmap->drawable.pScreen);
-
- bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
-
- i = pPixmap->drawable.height;
- while (i--) {
- memcpy (dst, src, bytes);
- dst += dst_pitch;
- src += src_pitch;
- }
- }
+ if (pPixmap->devPrivate.ptr == pExaPixmap->fb_ptr) {
+ exaCopyDirtyToSys (pPixmap);
+ pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
+ pPixmap->devKind = pExaPixmap->sys_pitch;
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
- pPixmap->devKind = dst_pitch;
- pPixmap->devPrivate.ptr = pExaPixmap->devPrivate.ptr;
- pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ pExaPixmap->fb_ptr = NULL;
pExaPixmap->area = NULL;
+
/* Mark it dirty now, to say that there is important data in the
* system-memory copy.
*/
pExaPixmap->dirty = TRUE;
}
-static int
-exaLog2(int val)
-{
- int bits;
-
- if (!val)
- return 0;
- for (bits = 0; val != 0; bits++)
- val >>= 1;
- return bits - 1;
-}
-
-static Bool
-exaPixmapAllocArea (PixmapPtr pPixmap)
-{
- ScreenPtr pScreen = pPixmap->drawable.pScreen;
- ExaScreenPriv (pScreen);
- ExaPixmapPriv (pPixmap);
- int bpp = pPixmap->drawable.bitsPerPixel;
- CARD16 h = pPixmap->drawable.height;
- CARD16 w = pPixmap->drawable.width;
- int pitch;
-
- if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
- w = 1 << (exaLog2(w - 1) + 1);
- pitch = (w * bpp / 8) + (pExaScr->info->pixmapPitchAlign - 1);
- pitch -= pitch % pExaScr->info->pixmapPitchAlign;
-
- pExaPixmap->size = pitch * h;
- pExaPixmap->devKind = pPixmap->devKind;
- pExaPixmap->devPrivate = pPixmap->devPrivate;
- pExaPixmap->area = exaOffscreenAlloc (pScreen, pitch * h,
- pExaScr->info->pixmapOffsetAlign,
- FALSE,
- exaPixmapSave, (pointer) pPixmap);
- if (!pExaPixmap->area)
- return FALSE;
-
- DBG_PIXMAP(("++ 0x%lx (0x%x) (%dx%d)\n", pPixmap->drawable.id,
- (ExaGetPixmapPriv(pPixmap)->area ?
- ExaGetPixmapPriv(pPixmap)->area->offset : 0),
- pPixmap->drawable.width,
- pPixmap->drawable.height));
- pPixmap->devKind = pitch;
-
- pPixmap->devPrivate.ptr = (pointer) ((CARD8 *) pExaScr->info->memoryBase +
- pExaPixmap->area->offset);
- pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
- return TRUE;
-}
-
+/**
+ * Allocates a framebuffer copy of the pixmap if necessary, and then copies
+ * any necessary pixmap data into the framebuffer copy and points the pixmap at
+ * it.
+ *
+ * Note that when first allocated, a pixmap will have FALSE dirty flag.
+ * This is intentional because pixmap data starts out undefined. So if we move
+ * it in due to the first operation against it being accelerated, it will have
+ * undefined framebuffer contents that we didn't have to upload. If we do
+ * moveouts (and moveins) after the first movein, then we will only have to copy
+ * back and forth if the pixmap was written to after the last synchronization of
+ * the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away)
+ * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
+ * all the data, since it's almost surely all valid now.
+ */
void
exaMoveInPixmap (PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv (pScreen);
ExaPixmapPriv (pPixmap);
- int dst_pitch, src_pitch, bytes;
- char *dst, *src;
- int i;
- if (exaPixmapIsPinned(pPixmap))
+ /* If we're VT-switched away, no touching card memory allowed. */
+ if (pExaScr->swappedOut)
return;
- DBG_MIGRATE (("-> 0x%lx (0x%x) (%dx%d)\n", pPixmap->drawable.id,
- (ExaGetPixmapPriv(pPixmap)->area ?
- ExaGetPixmapPriv(pPixmap)->area->offset : 0),
- pPixmap->drawable.width,
- pPixmap->drawable.height));
-
- src = pPixmap->devPrivate.ptr;
- src_pitch = pPixmap->devKind;
+ /* If we're already in FB, our work is done. */
+ if (pPixmap->devPrivate.ptr == pExaPixmap->fb_ptr)
+ return;
- if (!exaPixmapAllocArea (pPixmap)) {
- DBG_MIGRATE (("failed to allocate fb for pixmap %p (%dx%dx%d)\n",
- (pointer)pPixmap,
- pPixmap->drawable.width, pPixmap->drawable.height,
- pPixmap->drawable.bitsPerPixel));
+ /* If we're not allowed to move, then fail. */
+ if (exaPixmapIsPinned(pPixmap))
return;
- }
- /* If the "dirty" flag has never been set on the in-memory pixmap, then
- * nothing has been written to it, so the contents are undefined and we can
- * avoid the upload.
+ /* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of
+ * fragility in EXA, and <8bpp is probably not used enough any more to care
+ * (at least, not in acceleratd paths).
*/
- if (!pExaPixmap->dirty) {
- DBG_MIGRATE(("saved upload of %dx%d\n", pPixmap->drawable.width,
- pPixmap->drawable.height));
+ if (pPixmap->drawable.bitsPerPixel < 8)
return;
- }
- pExaPixmap->dirty = FALSE;
-
- if (pExaScr->info->UploadToScreen)
- {
- if (pExaScr->info->UploadToScreen(pPixmap, 0, 0,
- pPixmap->drawable.width,
- pPixmap->drawable.height,
- src, src_pitch))
+ if (pExaPixmap->area == NULL) {
+ pExaPixmap->area =
+ exaOffscreenAlloc (pScreen, pExaPixmap->fb_size,
+ pExaScr->info->pixmapOffsetAlign, FALSE,
+ exaPixmapSave, (pointer) pPixmap);
+ if (pExaPixmap->area == NULL)
return;
- }
- dst = pPixmap->devPrivate.ptr;
- dst_pitch = pPixmap->devKind;
-
- bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
+ pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
+ pExaPixmap->area->offset;
+ }
- exaWaitSync (pPixmap->drawable.pScreen);
+ DBG_MIGRATE (("-> 0x%lx (0x%x) (%dx%d)\n", pPixmap->drawable.id,
+ (ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
- i = pPixmap->drawable.height;
- DBG_PIXMAP(("dst = %p, src = %p,(%d, %d) height = %d, mem_base = %p, offset = %d\n",
- dst, src, dst_pitch, src_pitch,
- i, pExaScr->info->memoryBase, pExaPixmap->area->offset));
+ exaCopyDirtyToFb (pPixmap);
- while (i--) {
- memcpy (dst, src, bytes);
- dst += dst_pitch;
- src += src_pitch;
- }
+ pPixmap->devPrivate.ptr = (pointer) pExaPixmap->fb_ptr;
+ pPixmap->devKind = pExaPixmap->fb_pitch;
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
+/**
+ * Switches the current active location of the pixmap to system memory, copying
+ * updated data out if necessary.
+ */
void
exaMoveOutPixmap (PixmapPtr pPixmap)
{
ExaPixmapPriv (pPixmap);
- ExaOffscreenArea *area = pExaPixmap->area;
+
+ if (exaPixmapIsPinned(pPixmap))
+ return;
DBG_MIGRATE (("<- 0x%p (0x%p) (%dx%d)\n",
(void*)pPixmap->drawable.id,
@@ -243,10 +290,13 @@ exaMoveOutPixmap (PixmapPtr pPixmap)
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
pPixmap->drawable.width,
pPixmap->drawable.height));
- if (area)
- {
- exaPixmapSave (pPixmap->drawable.pScreen, area);
- exaOffscreenFree (pPixmap->drawable.pScreen, area);
+
+ if (pPixmap->devPrivate.ptr == pExaPixmap->fb_ptr) {
+ exaCopyDirtyToSys (pPixmap);
+
+ pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
+ pPixmap->devKind = pExaPixmap->sys_pitch;
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
}
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index f199cab88..c52ee8c44 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -123,6 +123,12 @@ extern int exaPixmapPrivateIndex;
#define ExaGetScreenPriv(s) ((ExaScreenPrivPtr)(s)->devPrivates[exaScreenPrivateIndex].ptr)
#define ExaScreenPriv(s) ExaScreenPrivPtr pExaScr = ExaGetScreenPriv(s)
+/** Align an offset to an arbitrary alignment */
+#define EXA_ALIGN(offset, align) (((offset) + (align) - 1) - \
+ (((offset) + (align) - 1) % (align)))
+/** Align an offset to a power-of-two alignment */
+#define EXA_ALIGN2(offset, align) (((offset) + (align) - 1) & ~((align) - 1))
+
#define EXA_PIXMAP_SCORE_MOVE_IN 10
#define EXA_PIXMAP_SCORE_MAX 20
#define EXA_PIXMAP_SCORE_MOVE_OUT -10
@@ -136,19 +142,26 @@ extern int exaPixmapPrivateIndex;
typedef struct {
ExaOffscreenArea *area;
- int score;
- int devKind;
- DevUnion devPrivate;
+ int score; /**< score for the move-in vs move-out heuristic */
+
+ CARD8 *sys_ptr; /**< pointer to pixmap data in system memory */
+ int sys_pitch; /**< pitch of pixmap in system memory */
+
+ CARD8 *fb_ptr; /**< pointer to pixmap data in framebuffer memory */
+ int fb_pitch; /**< pitch of pixmap in framebuffer memory */
+ unsigned int fb_size; /**< size of pixmap in framebuffer memory */
- /* If area is NULL, then dirty == TRUE means that the pixmap has been
+ /**
+ * If area is NULL, then dirty == TRUE means that the pixmap has been
* modified, so the contents are defined. Used to avoid uploads of
* undefined data.
- * If area is non-NULL, then dirty == TRUE means that the in-framebuffer
- * copy has been changed from the system-memory copy. Used to avoid
- * downloads of unmodified data.
+ *
+ * If area is non-NULL, then dirty == TRUE means that the pixmap data at
+ * pPixmap->devPrivate.ptr (either fb_ptr or sys_ptr) has been changed
+ * compared to the copy in the other location. This is used to avoid
+ * uploads/downloads of unmodified data.
*/
Bool dirty;
- unsigned int size;
} ExaPixmapPrivRec, *ExaPixmapPrivPtr;
typedef struct _ExaMigrationRec {