diff options
Diffstat (limited to 'xorg-server/exa')
-rw-r--r-- | xorg-server/exa/Makefile.am | 7 | ||||
-rw-r--r-- | xorg-server/exa/Makefile.in | 52 | ||||
-rw-r--r-- | xorg-server/exa/exa.c | 978 | ||||
-rw-r--r-- | xorg-server/exa/exa.h | 115 | ||||
-rw-r--r-- | xorg-server/exa/exa_accel.c | 340 | ||||
-rw-r--r-- | xorg-server/exa/exa_classic.c | 258 | ||||
-rw-r--r-- | xorg-server/exa/exa_driver.c | 214 | ||||
-rw-r--r-- | xorg-server/exa/exa_glyphs.c | 319 | ||||
-rw-r--r-- | xorg-server/exa/exa_migration_classic.c | 720 | ||||
-rw-r--r-- | xorg-server/exa/exa_migration_mixed.c | 194 | ||||
-rw-r--r-- | xorg-server/exa/exa_mixed.c | 251 | ||||
-rw-r--r-- | xorg-server/exa/exa_offscreen.c | 249 | ||||
-rw-r--r-- | xorg-server/exa/exa_priv.h | 228 | ||||
-rw-r--r-- | xorg-server/exa/exa_render.c | 276 | ||||
-rw-r--r-- | xorg-server/exa/exa_unaccel.c | 286 |
15 files changed, 3428 insertions, 1059 deletions
diff --git a/xorg-server/exa/Makefile.am b/xorg-server/exa/Makefile.am index 2b3f1e416..8b759cd76 100644 --- a/xorg-server/exa/Makefile.am +++ b/xorg-server/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 - diff --git a/xorg-server/exa/Makefile.in b/xorg-server/exa/Makefile.in index 3aadbe086..5826ae817 100644 --- a/xorg-server/exa/Makefile.in +++ b/xorg-server/exa/Makefile.in @@ -39,8 +39,11 @@ subdir = exa DIST_COMMON = $(am__sdk_HEADERS_DIST) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ - $(top_srcdir)/configure.ac +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_define_dir.m4 \ + $(top_srcdir)/m4/dolt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/shave.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -50,13 +53,15 @@ CONFIG_HEADER = $(top_builddir)/include/do-not-use-config.h \ $(top_builddir)/include/xorg-config.h \ $(top_builddir)/include/xkb-config.h \ $(top_builddir)/include/xwin-config.h \ - $(top_builddir)/include/kdrive-config.h + $(top_builddir)/include/kdrive-config.h \ + $(top_builddir)/include/version-config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libexa_la_LIBADD = -am_libexa_la_OBJECTS = exa.lo exa_accel.lo exa_glyphs.lo \ - exa_migration.lo exa_offscreen.lo exa_render.lo exa_unaccel.lo +am_libexa_la_OBJECTS = exa.lo exa_classic.lo exa_migration_classic.lo \ + exa_driver.lo exa_mixed.lo exa_migration_mixed.lo exa_accel.lo \ + exa_glyphs.lo exa_offscreen.lo exa_render.lo exa_unaccel.lo libexa_la_OBJECTS = $(am_libexa_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp @@ -102,6 +107,7 @@ ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ +AM_MAKEFLAGS = @AM_MAKEFLAGS@ APPLE_APPLICATIONS_DIR = @APPLE_APPLICATIONS_DIR@ APPLE_APPLICATION_ID = @APPLE_APPLICATION_ID@ APPLE_APPLICATION_NAME = @APPLE_APPLICATION_NAME@ @@ -122,9 +128,12 @@ CCASDEPMODE = @CCASDEPMODE@ CCASFLAGS = @CCASFLAGS@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ +CHANGELOG_CMD = @CHANGELOG_CMD@ COMPILEDDEFAULTFONTPATH = @COMPILEDDEFAULTFONTPATH@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CWARNFLAGS = @CWARNFLAGS@ +CXX = @CXX@ CYGPATH_W = @CYGPATH_W@ DARWIN_LIBS = @DARWIN_LIBS@ DBUS_CFLAGS = @DBUS_CFLAGS@ @@ -153,7 +162,9 @@ DRIPROTO_CFLAGS = @DRIPROTO_CFLAGS@ DRIPROTO_LIBS = @DRIPROTO_LIBS@ DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ +DRI_CFLAGS = @DRI_CFLAGS@ DRI_DRIVER_PATH = @DRI_DRIVER_PATH@ +DRI_LIBS = @DRI_LIBS@ DSYMUTIL = @DSYMUTIL@ DTRACE = @DTRACE@ DUMPBIN = @DUMPBIN@ @@ -162,9 +173,13 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +F77 = @F77@ +FC = @FC@ FGREP = @FGREP@ FILE_MAN_DIR = @FILE_MAN_DIR@ FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ GLX_ARCH_DEFINES = @GLX_ARCH_DEFINES@ GLX_DEFINES = @GLX_DEFINES@ GL_CFLAGS = @GL_CFLAGS@ @@ -203,12 +218,13 @@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ +MAIN_LIB = @MAIN_LIB@ +MAKEFLAGS = @MAKEFLAGS@ MAKEINFO = @MAKEINFO@ MAKE_HTML = @MAKE_HTML@ MAKE_PDF = @MAKE_PDF@ MAKE_PS = @MAKE_PS@ MAKE_TEXT = @MAKE_TEXT@ -MESA_SOURCE = @MESA_SOURCE@ MISC_MAN_DIR = @MISC_MAN_DIR@ MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ MKDIR_P = @MKDIR_P@ @@ -228,7 +244,6 @@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@ @@ -238,6 +253,7 @@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ PROJECTROOT = @PROJECTROOT@ PS2PDF = @PS2PDF@ +Q = @Q@ RANLIB = @RANLIB@ RAWCPP = @RAWCPP@ RAWCPPFLAGS = @RAWCPPFLAGS@ @@ -254,11 +270,10 @@ STRIP = @STRIP@ TSLIB_CFLAGS = @TSLIB_CFLAGS@ TSLIB_LIBS = @TSLIB_LIBS@ UTILS_SYS_LIBS = @UTILS_SYS_LIBS@ -VENDOR_MAN_VERSION = @VENDOR_MAN_VERSION@ -VENDOR_NAME = @VENDOR_NAME@ +V = @V@ VENDOR_NAME_SHORT = @VENDOR_NAME_SHORT@ -VENDOR_RELEASE = @VENDOR_RELEASE@ VERSION = @VERSION@ +WINDRES = @WINDRES@ X11EXAMPLES_DEP_CFLAGS = @X11EXAMPLES_DEP_CFLAGS@ X11EXAMPLES_DEP_LIBS = @X11EXAMPLES_DEP_LIBS@ XDMCP_CFLAGS = @XDMCP_CFLAGS@ @@ -294,6 +309,7 @@ XORG_OS_SUBDIR = @XORG_OS_SUBDIR@ XORG_SYS_LIBS = @XORG_SYS_LIBS@ XPBPROXY_CFLAGS = @XPBPROXY_CFLAGS@ XPBPROXY_LIBS = @XPBPROXY_LIBS@ +XQUARTZ_SPARKLE = @XQUARTZ_SPARKLE@ XRESEXAMPLES_DEP_CFLAGS = @XRESEXAMPLES_DEP_CFLAGS@ XRESEXAMPLES_DEP_LIBS = @XRESEXAMPLES_DEP_LIBS@ XSDL_INCS = @XSDL_INCS@ @@ -318,7 +334,6 @@ YFLAGS = @YFLAGS@ __XCONFIGFILE__ = @__XCONFIGFILE__@ abi_ansic = @abi_ansic@ abi_extension = @abi_extension@ -abi_font = @abi_font@ abi_videodrv = @abi_videodrv@ abi_xinput = @abi_xinput@ abs_builddir = @abs_builddir@ @@ -341,6 +356,7 @@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ +distcleancheck_listfiles = @distcleancheck_listfiles@ docdir = @docdir@ driverdir = @driverdir@ dvidir = @dvidir@ @@ -372,7 +388,9 @@ psdir = @psdir@ sbindir = @sbindir@ sdkdir = @sdkdir@ sharedstatedir = @sharedstatedir@ +shavedir = @shavedir@ srcdir = @srcdir@ +symbol_visibility = @symbol_visibility@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ @@ -388,9 +406,13 @@ 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 \ @@ -450,8 +472,12 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa_accel.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa_classic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa_driver.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa_glyphs.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa_migration.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa_migration_classic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa_migration_mixed.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa_mixed.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa_offscreen.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa_render.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa_unaccel.Plo@am__quote@ diff --git a/xorg-server/exa/exa.c b/xorg-server/exa/exa.c index 270810766..483e3b4eb 100644 --- a/xorg-server/exa/exa.c +++ b/xorg-server/exa/exa.c @@ -41,22 +41,13 @@ static int exaScreenPrivateKeyIndex; DevPrivateKey exaScreenPrivateKey = &exaScreenPrivateKeyIndex; static int exaPixmapPrivateKeyIndex; DevPrivateKey exaPixmapPrivateKey = &exaPixmapPrivateKeyIndex; +static int exaGCPrivateKeyIndex; +DevPrivateKey exaGCPrivateKey = &exaGCPrivateKeyIndex; #ifdef MITSHM 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. @@ -71,9 +62,9 @@ unsigned long exaGetPixmapOffset(PixmapPtr pPix) { ExaScreenPriv (pPix->drawable.pScreen); + ExaPixmapPriv (pPix); - return ((unsigned long)ExaGetPixmapAddress(pPix) - - (unsigned long)pExaScr->info->memoryBase); + return (CARD8 *)pExaPixmap->fb_ptr - pExaScr->info->memoryBase; } void * @@ -129,7 +120,7 @@ exaGetDrawablePixmap(DrawablePtr pDrawable) return pDrawable->pScreen->GetWindowPixmap ((WindowPtr) pDrawable); else return (PixmapPtr) pDrawable; -} +} /** * Sets the offsets to add to coordinates to make them address the same bits in @@ -159,14 +150,9 @@ exaGetDrawableDeltas (DrawablePtr pDrawable, PixmapPtr pPixmap, void exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2) { - ExaPixmapPriv(pPix); BoxRec box; - RegionPtr pDamageReg; RegionRec region; - if (!pExaPixmap || !pExaPixmap->pDamage) - return; - box.x1 = max(x1, 0); box.y1 = max(y1, 0); box.x2 = min(x2, pPix->drawable.width); @@ -175,46 +161,12 @@ exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2) if (box.x1 >= box.x2 || box.y1 >= box.y2) return; - pDamageReg = DamageRegion(pExaPixmap->pDamage); - REGION_INIT(pScreen, ®ion, &box, 1); - REGION_UNION(pScreen, pDamageReg, pDamageReg, ®ion); + DamageRegionAppend(&pPix->drawable, ®ion); + DamageRegionProcessPending(&pPix->drawable); REGION_UNINIT(pScreen, ®ion); } -static Bool -exaDestroyPixmap (PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - ExaScreenPriv(pScreen); - - 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); - } - return fbDestroyPixmap (pPixmap); -} - static int exaLog2(int val) { @@ -227,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; @@ -251,179 +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 / 8; + pExaPixmap->fb_pitch = bits_to_bytes((1 << (exaLog2(w - 1) + 1)) * bpp); else - pExaPixmap->fb_pitch = w * bpp / 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; - int driver_alloc = 0; - int bpp; - ExaScreenPriv(pScreen); - - if (w > 32767 || h > 32767) - return NullPixmap; - - if (!pExaScr->info->CreatePixmap) { - pPixmap = fbCreatePixmap (pScreen, w, h, depth, usage_hint); - } else { - driver_alloc = 1; - pPixmap = fbCreatePixmap(pScreen, 0, 0, depth, usage_hint); - } - - 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; - - pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, datasize, 0); - if (!pExaPixmap->driverPriv) { - fbDestroyPixmap(pPixmap); - return NULL; - } - - (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, - paddedWidth, NULL); - pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; - pExaPixmap->fb_ptr = NULL; - pExaPixmap->pDamage = NULL; - pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; - - } 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) { - fbDestroyPixmap(pPixmap); - return NULL; - } - - /* Set up damage tracking */ - pExaPixmap->pDamage = DamageCreate (NULL, NULL, - DamageReportNone, TRUE, - pScreen, pPixmap); - - if (pExaPixmap->pDamage == NULL) { - fbDestroyPixmap (pPixmap); - 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; - - /* None of the pixmap bits are valid initially */ - REGION_NULL(pScreen, &pExaPixmap->validSys); - REGION_NULL(pScreen, &pExaPixmap->validFB); - - 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; + ExaPixmapPriv (pPix); - if (devKind > 0) - pExaPixmap->sys_pitch = devKind; + if (pExaPixmap == NULL) + EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsPinned was called on a non-exa pixmap.\n"), TRUE); - 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); - if (ret == TRUE) - return ret; - } - return pExaScr->SavedModifyPixmapHeader(pPixmap, width, height, depth, - bitsPerPixel, devKind, pPixData); + return pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED; } /** @@ -439,29 +245,15 @@ exaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth, * @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); - void *save_ptr; - Bool ret; - - save_ptr = p->devPrivate.ptr; - - if (!save_ptr && pExaPixmap && !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) - p->devPrivate.ptr = ExaGetPixmapAddress(p); - if (pExaScr->info->PixmapIsOffscreen) - ret = pExaScr->info->PixmapIsOffscreen(p); - else - ret = ((unsigned long) ((CARD8 *) p->devPrivate.ptr - - (CARD8 *) pExaScr->info->memoryBase) < - pExaScr->info->memorySize); - - p->devPrivate.ptr = save_ptr; + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return FALSE; - return ret; + return (*pExaScr->pixmap_is_offscreen)(pPixmap); } /** @@ -490,52 +282,115 @@ exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp) return NULL; } -void +/** + * Returns TRUE if pixmap can be accessed offscreen. + */ +Bool ExaDoPrepareAccess(DrawablePtr pDrawable, int index) { - ScreenPtr pScreen = pDrawable->pScreen; - ExaScreenPriv (pScreen); - PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); - Bool offscreen = exaPixmapIsOffscreen(pPixmap); + ScreenPtr pScreen = pDrawable->pScreen; + ExaScreenPriv (pScreen); + PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); + ExaPixmapPriv(pPixmap); + Bool offscreen; + int i; + + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return FALSE; + + if (pExaPixmap == NULL) + EXA_FatalErrorDebugWithRet(("EXA bug: ExaDoPrepareAccess was called on a non-exa pixmap.\n"), FALSE); + + /* 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; + } + } - /* Unhide pixmap pointer */ - if (pPixmap->devPrivate.ptr == NULL && !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) { - pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); + /* 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; } - if (!offscreen) - return; + /* 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); + + if (offscreen) + pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; + else + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + + /* 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); if (pExaScr->info->PrepareAccess == NULL) - return; + return TRUE; - if (index >= EXA_PREPARE_AUX0 && + if (index >= EXA_PREPARE_AUX_DEST && !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) { + if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) + FatalError("Unsupported AUX indices used on a pinned pixmap.\n"); exaMoveOutPixmap (pPixmap); - return; + return FALSE; } if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) { - ExaPixmapPriv (pPixmap); if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) - FatalError("Driver failed PrepareAccess on a pinned pixmap\n"); + FatalError("Driver failed PrepareAccess on a pinned pixmap.\n"); exaMoveOutPixmap (pPixmap); + + return FALSE; } + + return TRUE; } void exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg) { - ExaMigrationRec pixmaps[1]; + PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); + ExaScreenPriv(pPixmap->drawable.pScreen); - pixmaps[0].as_dst = index == EXA_PREPARE_DEST; - pixmaps[0].as_src = index != EXA_PREPARE_DEST; - pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable); - pixmaps[0].pReg = pReg; + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; - exaDoMigration(pixmaps, 1, FALSE); + 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); } @@ -564,19 +419,41 @@ exaFinishAccess(DrawablePtr pDrawable, int index) ExaScreenPriv (pScreen); PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); ExaPixmapPriv (pPixmap); + int i; - /* Rehide pixmap pointer if we're doing that. */ - if (pExaPixmap && !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) { - pPixmap->devPrivate.ptr = NULL; + if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS)) + return; + + if (pExaPixmap == NULL) + EXA_FatalErrorDebugWithRet(("EXA bug: exaFinishAccesss was called on a non-exa pixmap.\n"),); + + /* 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; + if (pExaScr->info->FinishAccess == NULL) return; if (!exaPixmapIsOffscreen (pPixmap)) return; - if (index >= EXA_PREPARE_AUX0 && + if (index >= EXA_PREPARE_AUX_DEST && !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) { ErrorF("EXA bug: Trying to call driver FinishAccess hook with " "unsupported index EXA_PREPARE_AUX*\n"); @@ -587,86 +464,225 @@ exaFinishAccess(DrawablePtr pDrawable, int index) } /** - * exaValidateGC() sets the ops to EXA's implementations, which may be - * accelerated or may sync the card and fall back to fb. + * Here begins EXA's GC code. + * Do not ever access the fb/mi layer directly. */ + +static void +exaValidateGC(GCPtr pGC, + unsigned long changes, + DrawablePtr pDrawable); + static void -exaValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +exaDestroyGC(GCPtr pGC); + +static void +exaChangeGC (GCPtr pGC, + unsigned long mask); + +static void +exaCopyGC (GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst); + +static void +exaChangeClip (GCPtr pGC, + int type, + pointer pvalue, + int nrects); + +static void +exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc); + +static void +exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc); + +static void +exaDestroyClip(GCPtr pGC); + +const GCFuncs exaGCFuncs = { + exaValidateGC, + exaChangeGC, + exaCopyGC, + exaDestroyGC, + exaChangeClip, + exaDestroyClip, + exaCopyClip +}; + +/* + * This wrapper exists to allow fbValidateGC to work. + * Note that we no longer assume newly created pixmaps to be in normal ram. + * This assumption is certainly not garuanteed with driver allocated pixmaps. + */ +static PixmapPtr +exaCreatePixmapWithPrepare(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint) +{ + PixmapPtr pPixmap; + ExaScreenPriv(pScreen); + + /* 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. + */ + swap(pExaScr, pScreen, CreatePixmap); + pPixmap = pScreen->CreatePixmap(pScreen, w, h, depth, usage_hint); + swap(pExaScr, pScreen, CreatePixmap); + + if (!pPixmap) + return NULL; + + /* Note the usage of ExaDoPrepareAccess, this allowed because: + * The pixmap is new, so not offscreen in the classic exa case. + * For EXA_HANDLES_PIXMAPS the driver will handle whatever is needed. + * We want to signal that the pixmaps will be used as destination. + */ + ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); + + return pPixmap; +} + +static Bool +exaDestroyPixmapWithFinish(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + Bool ret; + + 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. + */ + swap(pExaScr, pScreen, DestroyPixmap); + ret = pScreen->DestroyPixmap(pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + + return ret; +} + +static void +exaValidateGC(GCPtr pGC, + unsigned long changes, + DrawablePtr pDrawable) { /* fbValidateGC will do direct access to pixmaps if the tiling has changed. - * Preempt fbValidateGC by doing its work and masking the change out, so - * that we can do the Prepare/FinishAccess. + * Do a few smart things so fbValidateGC can do it's work. */ -#ifdef FB_24_32BIT - if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) { - (*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC)); - fbGetRotatedPixmap(pGC) = 0; - } - - if (pGC->fillStyle == FillTiled) { - PixmapPtr pOldTile, pNewTile; - - pOldTile = pGC->tile.pixmap; - if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel) - { - pNewTile = fbGetRotatedPixmap(pGC); - if (!pNewTile || - pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel) - { - if (pNewTile) - (*pGC->pScreen->DestroyPixmap) (pNewTile); - /* fb24_32ReformatTile will do direct access of a newly- - * allocated pixmap. This isn't a problem yet, since we don't - * put pixmaps in FB until at least one accelerated EXA op. - */ - exaPrepareAccess(&pOldTile->drawable, EXA_PREPARE_SRC); - pNewTile = fb24_32ReformatTile (pOldTile, - pDrawable->bitsPerPixel); - exaPixmapDirty(pNewTile, 0, 0, pNewTile->drawable.width, pNewTile->drawable.height); - exaFinishAccess(&pOldTile->drawable, EXA_PREPARE_SRC); - } - if (pNewTile) - { - fbGetRotatedPixmap(pGC) = pOldTile; - pGC->tile.pixmap = pNewTile; - changes |= GCTile; - } - } - } -#endif - if (changes & GCTile) { - if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width * - pDrawable->bitsPerPixel)) - { - exaPrepareAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC); - fbPadPixmap (pGC->tile.pixmap); - exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC); - exaPixmapDirty(pGC->tile.pixmap, 0, 0, - pGC->tile.pixmap->drawable.width, - pGC->tile.pixmap->drawable.height); - } - /* Mask out the GCTile change notification, now that we've done FB's - * job for it. + + ScreenPtr pScreen = pDrawable->pScreen; + ExaScreenPriv(pScreen); + CreatePixmapProcPtr old_ptr = NULL; + DestroyPixmapProcPtr old_ptr2 = NULL; + PixmapPtr pTile = NULL; + EXA_GC_PROLOGUE(pGC); + + /* save the "fb" pointer. */ + old_ptr = pExaScr->SavedCreatePixmap; + /* create a new upper layer pointer. */ + wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmapWithPrepare); + + /* save the "fb" pointer. */ + old_ptr2 = pExaScr->SavedDestroyPixmap; + /* create a new upper layer pointer. */ + wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmapWithFinish); + + /* Either of these conditions is enough to trigger access to a tile pixmap. */ + /* With pGC->tileIsPixel == 1, you run the risk of dereferencing an invalid tile pixmap pointer. */ + if (pGC->fillStyle == FillTiled || ((changes & GCTile) && !pGC->tileIsPixel)) { + pTile = pGC->tile.pixmap; + + /* Sometimes tile pixmaps are swapped, you need access to: + * - The current tile if it depth matches. + * - Or the rotated tile if that one matches depth and !(changes & GCTile). + * - Or the current tile pixmap and a newly created one. */ - changes &= ~GCTile; + if (pTile && pTile->drawable.depth != pDrawable->depth && !(changes & GCTile)) { + PixmapPtr pRotatedTile = fbGetRotatedPixmap(pGC); + if (pRotatedTile->drawable.depth == pDrawable->depth) + pTile = pRotatedTile; + } } - exaPrepareAccessGC(pGC); - fbValidateGC (pGC, changes, pDrawable); - exaFinishAccessGC(pGC); + if (pGC->stipple) + exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK); + if (pTile) + exaPrepareAccess(&pTile->drawable, EXA_PREPARE_SRC); + + (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable); - pGC->ops = (GCOps *) &exaOps; + if (pTile) + exaFinishAccess(&pTile->drawable, EXA_PREPARE_SRC); + if (pGC->stipple) + exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK); + + /* switch back to the normal upper layer. */ + unwrap(pExaScr, pScreen, CreatePixmap); + /* restore copy of fb layer pointer. */ + pExaScr->SavedCreatePixmap = old_ptr; + + /* switch back to the normal upper layer. */ + unwrap(pExaScr, pScreen, DestroyPixmap); + /* restore copy of fb layer pointer. */ + pExaScr->SavedDestroyPixmap = old_ptr2; + + EXA_GC_EPILOGUE(pGC); } -static GCFuncs exaGCFuncs = { - exaValidateGC, - miChangeGC, - miCopyGC, - miDestroyGC, - miChangeClip, - miDestroyClip, - miCopyClip -}; +/* Is exaPrepareAccessGC() needed? */ +static void +exaDestroyGC(GCPtr pGC) +{ + EXA_GC_PROLOGUE (pGC); + (*pGC->funcs->DestroyGC)(pGC); + EXA_GC_EPILOGUE (pGC); +} + +static void +exaChangeGC (GCPtr pGC, + unsigned long mask) +{ + EXA_GC_PROLOGUE (pGC); + (*pGC->funcs->ChangeGC) (pGC, mask); + EXA_GC_EPILOGUE (pGC); +} + +static void +exaCopyGC (GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst) +{ + EXA_GC_PROLOGUE (pGCDst); + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + EXA_GC_EPILOGUE (pGCDst); +} + +static void +exaChangeClip (GCPtr pGC, + int type, + pointer pvalue, + int nrects) +{ + EXA_GC_PROLOGUE (pGC); + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + EXA_GC_EPILOGUE (pGC); +} + +static void +exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc) +{ + EXA_GC_PROLOGUE (pGCDst); + (*pGCDst->funcs->CopyClip)(pGCDst, pGCSrc); + EXA_GC_EPILOGUE (pGCDst); +} + +static void +exaDestroyClip(GCPtr pGC) +{ + EXA_GC_PROLOGUE (pGC); + (*pGC->funcs->DestroyClip)(pGC); + EXA_GC_EPILOGUE (pGC); +} /** * exaCreateGC makes a new GC and hooks up its funcs handler, so that @@ -675,32 +691,64 @@ static GCFuncs exaGCFuncs = { static int exaCreateGC (GCPtr pGC) { - if (!fbCreateGC (pGC)) - return FALSE; + ScreenPtr pScreen = pGC->pScreen; + ExaScreenPriv(pScreen); + ExaGCPriv(pGC); + Bool ret; - pGC->funcs = &exaGCFuncs; + swap(pExaScr, pScreen, CreateGC); + if ((ret = (*pScreen->CreateGC) (pGC))) { + wrap(pExaGC, pGC, funcs, (GCFuncs *) &exaGCFuncs); + wrap(pExaGC, pGC, ops, (GCOps *) &exaOps); + } + swap(pExaScr, pScreen, CreateGC); - return TRUE; + return ret; } static Bool exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask) { Bool ret; + ScreenPtr pScreen = pWin->drawable.pScreen; + ExaScreenPriv(pScreen); + CreatePixmapProcPtr old_ptr = NULL; + DestroyPixmapProcPtr old_ptr2 = NULL; + + /* save the "fb" pointer. */ + old_ptr = pExaScr->SavedCreatePixmap; + /* create a new upper layer pointer. */ + wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmapWithPrepare); + + /* save the "fb" pointer. */ + old_ptr2 = pExaScr->SavedDestroyPixmap; + /* create a new upper layer pointer. */ + wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmapWithFinish); if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap) - exaPrepareAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); + exaPrepareAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE) - exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); + exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); - ret = fbChangeWindowAttributes(pWin, mask); + swap(pExaScr, pScreen, ChangeWindowAttributes); + ret = pScreen->ChangeWindowAttributes(pWin, mask); + swap(pExaScr, pScreen, ChangeWindowAttributes); + 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); + exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); - if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap) - exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); + /* switch back to the normal upper layer. */ + unwrap(pExaScr, pScreen, CreatePixmap); + /* restore copy of fb layer pointer. */ + pExaScr->SavedCreatePixmap = old_ptr; + + /* switch back to the normal upper layer. */ + unwrap(pExaScr, pScreen, DestroyPixmap); + /* restore copy of fb layer pointer. */ + pExaScr->SavedDestroyPixmap = old_ptr2; return ret; } @@ -708,11 +756,17 @@ exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask) static RegionPtr exaBitmapToRegion(PixmapPtr pPix) { - RegionPtr ret; - exaPrepareAccess(&pPix->drawable, EXA_PREPARE_SRC); - ret = fbPixmapToRegion(pPix); - exaFinishAccess(&pPix->drawable, EXA_PREPARE_SRC); - return ret; + RegionPtr ret; + ScreenPtr pScreen = pPix->drawable.pScreen; + ExaScreenPriv(pScreen); + + exaPrepareAccess(&pPix->drawable, EXA_PREPARE_SRC); + swap(pExaScr, pScreen, BitmapToRegion); + ret = pScreen->BitmapToRegion(pPix); + swap(pExaScr, pScreen, BitmapToRegion); + exaFinishAccess(&pPix->drawable, EXA_PREPARE_SRC); + + return ret; } static Bool @@ -722,9 +776,9 @@ exaCreateScreenResources(ScreenPtr pScreen) PixmapPtr pScreenPixmap; Bool b; - pScreen->CreateScreenResources = pExaScr->SavedCreateScreenResources; + swap(pExaScr, pScreen, CreateScreenResources); b = pScreen->CreateScreenResources(pScreen); - pScreen->CreateScreenResources = exaCreateScreenResources; + swap(pExaScr, pScreen, CreateScreenResources); if (!b) return FALSE; @@ -743,6 +797,50 @@ exaCreateScreenResources(ScreenPtr pScreen) return TRUE; } +static void +ExaBlockHandler(int screenNum, pointer blockData, pointer pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[screenNum]; + ExaScreenPriv(pScreen); + + unwrap(pExaScr, pScreen, BlockHandler); + (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); + wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler); + + /* Try and keep the offscreen memory area tidy every now and then (at most + * once per second) when the server has been idle for at least 100ms. + */ + if (pExaScr->numOffscreenAvailable > 1) { + CARD32 now = GetTimeInMillis(); + + pExaScr->nextDefragment = now + + max(100, (INT32)(pExaScr->lastDefragment + 1000 - now)); + AdjustWaitForDelay(pTimeout, pExaScr->nextDefragment - now); + } +} + +static void +ExaWakeupHandler(int screenNum, pointer wakeupData, unsigned long result, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[screenNum]; + ExaScreenPriv(pScreen); + + unwrap(pExaScr, pScreen, WakeupHandler); + (*pScreen->WakeupHandler) (screenNum, wakeupData, result, pReadmask); + wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler); + + if (result == 0 && pExaScr->numOffscreenAvailable > 1) { + CARD32 now = GetTimeInMillis(); + + if ((int)(now - pExaScr->nextDefragment) > 0) { + ExaOffscreenDefragment(pScreen); + pExaScr->lastDefragment = now; + } + } +} + /** * exaCloseScreen() unwraps its wrapped screen functions and tears down EXA's * screen private, before calling down to the next CloseSccreen. @@ -758,23 +856,32 @@ exaCloseScreen(int i, ScreenPtr pScreen) if (ps->Glyphs == exaGlyphs) exaGlyphsFini(pScreen); - pScreen->CreateGC = pExaScr->SavedCreateGC; - pScreen->CloseScreen = pExaScr->SavedCloseScreen; - pScreen->GetImage = pExaScr->SavedGetImage; - pScreen->GetSpans = pExaScr->SavedGetSpans; - pScreen->CreatePixmap = pExaScr->SavedCreatePixmap; - pScreen->DestroyPixmap = pExaScr->SavedDestroyPixmap; - pScreen->CopyWindow = pExaScr->SavedCopyWindow; - pScreen->ChangeWindowAttributes = pExaScr->SavedChangeWindowAttributes; - pScreen->BitmapToRegion = pExaScr->SavedBitmapToRegion; - pScreen->CreateScreenResources = pExaScr->SavedCreateScreenResources; + if (pScreen->BlockHandler == ExaBlockHandler) + unwrap(pExaScr, pScreen, BlockHandler); + if (pScreen->WakeupHandler == ExaWakeupHandler) + unwrap(pExaScr, pScreen, WakeupHandler); + unwrap(pExaScr, pScreen, CreateGC); + unwrap(pExaScr, pScreen, CloseScreen); + unwrap(pExaScr, pScreen, GetImage); + unwrap(pExaScr, pScreen, GetSpans); + if (pExaScr->SavedCreatePixmap) + unwrap(pExaScr, pScreen, CreatePixmap); + if (pExaScr->SavedDestroyPixmap) + unwrap(pExaScr, pScreen, DestroyPixmap); + if (pExaScr->SavedModifyPixmapHeader) + unwrap(pExaScr, pScreen, ModifyPixmapHeader); + unwrap(pExaScr, pScreen, CopyWindow); + unwrap(pExaScr, pScreen, ChangeWindowAttributes); + unwrap(pExaScr, pScreen, BitmapToRegion); + unwrap(pExaScr, pScreen, CreateScreenResources); #ifdef RENDER if (ps) { - ps->Composite = pExaScr->SavedComposite; - ps->Glyphs = pExaScr->SavedGlyphs; - ps->Trapezoids = pExaScr->SavedTrapezoids; - ps->Triangles = pExaScr->SavedTriangles; - ps->AddTraps = pExaScr->SavedAddTraps; + unwrap(pExaScr, ps, Composite); + if (pExaScr->SavedGlyphs) + unwrap(pExaScr, ps, Glyphs); + unwrap(pExaScr, ps, Trapezoids); + unwrap(pExaScr, ps, Triangles); + unwrap(pExaScr, ps, AddTraps); } #endif @@ -832,7 +939,7 @@ exaDriverInit (ScreenPtr pScreen, return FALSE; } - if (!pScreenInfo->CreatePixmap) { + if (!pScreenInfo->CreatePixmap && !pScreenInfo->CreatePixmap2) { if (!pScreenInfo->memoryBase) { LogMessage(X_ERROR, "EXA(%d): ExaDriverRec::memoryBase " "must be non-zero\n", pScreen->myNum); @@ -889,7 +996,6 @@ exaDriverInit (ScreenPtr pScreen, #endif pExaScr = xcalloc (sizeof (ExaScreenPrivRec), 1); - if (!pExaScr) { LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n", pScreen->myNum); @@ -904,51 +1010,38 @@ exaDriverInit (ScreenPtr pScreen, exaDDXDriverInit(pScreen); + if (!dixRequestPrivate(exaGCPrivateKey, sizeof(ExaGCPrivRec))) { + LogMessage(X_WARNING, + "EXA(%d): Failed to allocate GC private\n", + pScreen->myNum); + return FALSE; + } + /* * Replace various fb screen functions */ - pExaScr->SavedCloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = exaCloseScreen; - - pExaScr->SavedCreateGC = pScreen->CreateGC; - pScreen->CreateGC = exaCreateGC; - - pExaScr->SavedGetImage = pScreen->GetImage; - pScreen->GetImage = exaGetImage; - - pExaScr->SavedGetSpans = pScreen->GetSpans; - pScreen->GetSpans = ExaCheckGetSpans; - - pExaScr->SavedCopyWindow = pScreen->CopyWindow; - pScreen->CopyWindow = exaCopyWindow; - - pExaScr->SavedChangeWindowAttributes = pScreen->ChangeWindowAttributes; - pScreen->ChangeWindowAttributes = exaChangeWindowAttributes; - - pExaScr->SavedBitmapToRegion = pScreen->BitmapToRegion; - pScreen->BitmapToRegion = exaBitmapToRegion; - - pExaScr->SavedCreateScreenResources = pScreen->CreateScreenResources; - pScreen->CreateScreenResources = exaCreateScreenResources; + if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) && + !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) { + wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler); + wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler); + } + wrap(pExaScr, pScreen, CreateGC, exaCreateGC); + wrap(pExaScr, pScreen, CloseScreen, exaCloseScreen); + wrap(pExaScr, pScreen, GetImage, exaGetImage); + wrap(pExaScr, pScreen, GetSpans, ExaCheckGetSpans); + wrap(pExaScr, pScreen, CopyWindow, exaCopyWindow); + wrap(pExaScr, pScreen, ChangeWindowAttributes, exaChangeWindowAttributes); + wrap(pExaScr, pScreen, BitmapToRegion, exaBitmapToRegion); + wrap(pExaScr, pScreen, CreateScreenResources, exaCreateScreenResources); #ifdef RENDER if (ps) { - pExaScr->SavedComposite = ps->Composite; - ps->Composite = exaComposite; - - if (pScreenInfo->PrepareComposite) { - pExaScr->SavedGlyphs = ps->Glyphs; - ps->Glyphs = exaGlyphs; - } - - pExaScr->SavedTriangles = ps->Triangles; - ps->Triangles = exaTriangles; - - pExaScr->SavedTrapezoids = ps->Trapezoids; - ps->Trapezoids = exaTrapezoids; - - pExaScr->SavedAddTraps = ps->AddTraps; - ps->AddTraps = ExaCheckAddTraps; + wrap(pExaScr, ps, Composite, exaComposite); + if (pScreenInfo->PrepareComposite) + wrap(pExaScr, ps, Glyphs, exaGlyphs); + wrap(pExaScr, ps, Trapezoids, exaTrapezoids); + wrap(pExaScr, ps, Triangles, exaTriangles); + wrap(pExaScr, ps, AddTraps, ExaCheckAddTraps); } #endif @@ -969,15 +1062,34 @@ exaDriverInit (ScreenPtr pScreen, pScreen->myNum); return FALSE; } - pExaScr->SavedCreatePixmap = pScreen->CreatePixmap; - pScreen->CreatePixmap = exaCreatePixmap; - - pExaScr->SavedDestroyPixmap = pScreen->DestroyPixmap; - pScreen->DestroyPixmap = exaDestroyPixmap; - - pExaScr->SavedModifyPixmapHeader = pScreen->ModifyPixmapHeader; - pScreen->ModifyPixmapHeader = exaModifyPixmapHeader; - if (!pExaScr->info->CreatePixmap) { + 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, pExaScr->info->memorySize - pExaScr->info->offScreenBase); @@ -990,7 +1102,7 @@ exaDriverInit (ScreenPtr pScreen, else LogMessage(X_INFO, "EXA(%d): No offscreen pixmaps\n", pScreen->myNum); - if (!pExaScr->info->CreatePixmap) { + if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) { DBG_PIXMAP(("============== %ld < %ld\n", pExaScr->info->offScreenBase, pExaScr->info->memorySize)); if (pExaScr->info->offScreenBase < pExaScr->info->memorySize) { @@ -1074,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); +} diff --git a/xorg-server/exa/exa.h b/xorg-server/exa/exa.h index 4a96cc6f3..4b3947327 100644 --- a/xorg-server/exa/exa.h +++ b/xorg-server/exa/exa.h @@ -39,7 +39,7 @@ #include "fb.h" #define EXA_VERSION_MAJOR 2 -#define EXA_VERSION_MINOR 4 +#define EXA_VERSION_MINOR 5 #define EXA_VERSION_RELEASE 0 typedef struct _ExaOffscreenArea ExaOffscreenArea; @@ -66,6 +66,9 @@ struct _ExaOffscreenArea { ExaOffscreenArea *next; unsigned eviction_cost; + + ExaOffscreenArea *prev; /* Double-linked list for defragmentation */ + int align; /* required alignment */ }; /** @@ -499,27 +502,8 @@ typedef struct _ExaDriver { int src_pitch); /** - * UploadToScratch() is used to upload a pixmap to a scratch area for - * acceleration. - * - * @param pSrc source pixmap in host memory - * @param pDst fake, scratch pixmap to be set up in offscreen memory. - * - * The UploadToScratch() call was added to support Xati before Xati had - * support for hostdata uploads and before exaGlyphs() was written. It - * behaves incorrectly (uses an invalid pixmap as pDst), - * and UploadToScreen() should be implemented instead. - * - * Drivers implementing UploadToScratch() had to set up space (likely in a - * statically allocated area) in offscreen memory, copy pSrc to that - * scratch area, and adust pDst->devKind for the pitch and - * pDst->devPrivate.ptr for the pointer to that scratch area. The driver - * was responsible for syncing (as it was implemented using memcpy() in - * Xati), and only the data from the last UploadToScratch() was guaranteed - * to be valid at any given time. - * - * UploadToScratch() should not be implemented by drivers, and will likely - * be removed in a future version of EXA. + * UploadToScratch() is no longer used and will be removed next time the EXA + * major version needs to be bumped. */ Bool (*UploadToScratch) (PixmapPtr pSrc, PixmapPtr pDst); @@ -602,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() @@ -676,9 +660,10 @@ typedef struct _ExaDriver { * EXA_PREPARE_AUX* are additional indices for other purposes, e.g. * separate alpha maps with Composite operations. */ - #define EXA_PREPARE_AUX0 3 - #define EXA_PREPARE_AUX1 4 - #define EXA_PREPARE_AUX2 5 + #define EXA_PREPARE_AUX_DEST 3 + #define EXA_PREPARE_AUX_SRC 4 + #define EXA_PREPARE_AUX_MASK 5 + #define EXA_NUM_PREPARE_INDICES 6 /** @} */ /** @@ -714,10 +699,21 @@ typedef struct _ExaDriver { /* Hooks to allow driver to its own pixmap memory management */ void *(*CreatePixmap)(ScreenPtr pScreen, int size, int align); void (*DestroyPixmap)(ScreenPtr pScreen, void *driverPriv); + /** + * Returning a pixmap with non-NULL devPrivate.ptr implies a pixmap which is + * not offscreen, which will never be accelerated and Prepare/FinishAccess won't + * be called. + */ Bool (*ModifyPixmapHeader)(PixmapPtr pPixmap, int width, int height, int depth, int bitsPerPixel, int devKind, 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 *new_fb_pitch); /** @} */ } ExaDriverRec, *ExaDriverPtr; @@ -756,66 +752,83 @@ typedef struct _ExaDriver { */ #define EXA_SUPPORTS_PREPARE_AUX (1 << 4) +/** + * EXA_SUPPORTS_OFFSCREEN_OVERLAPS indicates to EXA that the driver Copy hooks + * can handle the source and destination occupying overlapping offscreen memory + * areas. This allows the offscreen memory defragmentation code to defragment + * areas where the defragmented position overlaps the fragmented position. + * + * Typically this is supported by traditional 2D engines but not by 3D engines. + */ +#define EXA_SUPPORTS_OFFSCREEN_OVERLAPS (1 << 5) + +/** + * EXA_MIXED_PIXMAPS will hide unacceleratable pixmaps from drivers and manage the + * problem known software fallbacks like trapezoids. This only migrates pixmaps one way + * into a driver pixmap and then pins it. + */ +#define EXA_MIXED_PIXMAPS (1 << 6) + /** @} */ /* in exa.c */ -ExaDriverPtr +extern _X_EXPORT ExaDriverPtr exaDriverAlloc(void); -Bool +extern _X_EXPORT Bool exaDriverInit(ScreenPtr pScreen, ExaDriverPtr pScreenInfo); -void +extern _X_EXPORT void exaDriverFini(ScreenPtr pScreen); -void +extern _X_EXPORT void exaMarkSync(ScreenPtr pScreen); -void +extern _X_EXPORT void exaWaitSync(ScreenPtr pScreen); -unsigned long +extern _X_EXPORT unsigned long exaGetPixmapOffset(PixmapPtr pPix); -unsigned long +extern _X_EXPORT unsigned long exaGetPixmapPitch(PixmapPtr pPix); -unsigned long +extern _X_EXPORT unsigned long exaGetPixmapSize(PixmapPtr pPix); -void * +extern _X_EXPORT void * exaGetPixmapDriverPrivate(PixmapPtr p); /* in exa_offscreen.c */ -ExaOffscreenArea * +extern _X_EXPORT ExaOffscreenArea * exaOffscreenAlloc(ScreenPtr pScreen, int size, int align, Bool locked, ExaOffscreenSaveProc save, pointer privData); -ExaOffscreenArea * +extern _X_EXPORT ExaOffscreenArea * exaOffscreenFree(ScreenPtr pScreen, ExaOffscreenArea *area); -void +extern _X_EXPORT void ExaOffscreenMarkUsed (PixmapPtr pPixmap); -void +extern _X_EXPORT void exaEnableDisableFBAccess (int index, Bool enable); -Bool +extern _X_EXPORT Bool exaDrawableIsOffscreen (DrawablePtr pDrawable); -/* in exa_migration.c */ -void +/* in exa.c */ +extern _X_EXPORT void exaMoveInPixmap (PixmapPtr pPixmap); -void +extern _X_EXPORT void exaMoveOutPixmap (PixmapPtr pPixmap); /* in exa_unaccel.c */ -CARD32 +extern _X_EXPORT CARD32 exaGetPixmapFirstPixel (PixmapPtr pPixmap); diff --git a/xorg-server/exa/exa_accel.c b/xorg-server/exa/exa_accel.c index dac6e6c79..33fbb9843 100644 --- a/xorg-server/exa/exa_accel.c +++ b/xorg-server/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,9 +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. */ @@ -164,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); @@ -177,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; @@ -210,42 +213,19 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, x2 - x1, y2 - y1, src, src_stride); - /* If we fail to accelerate the upload, fall back to using unaccelerated - * fb calls. + /* We have to fall back completely, and ignore what has already been completed. + * Messing with the fb layer directly like we used to is completely unacceptable. */ if (!ok) { - FbStip *dst; - FbStride dst_stride; - int dstBpp; - int dstXoff, dstYoff; - - if (!access_prepared) { - ExaDoPrepareAccess(pDrawable, EXA_PREPARE_DEST); - - access_prepared = TRUE; - } - - fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp, - dstXoff, dstYoff); - - fbBltStip((FbStip *)bits + (y1 - y) * (src_stride / sizeof(FbStip)), - src_stride / sizeof(FbStip), - (x1 - x) * dstBpp, - dst + (y1 + dstYoff) * dst_stride, - dst_stride, - (x1 + dstXoff) * dstBpp, - (x2 - x1) * dstBpp, - y2 - y1, - GXcopy, FB_ALLONES, dstBpp); + ret = FALSE; + break; } } - if (access_prepared) - exaFinishAccess(pDrawable, EXA_PREPARE_DEST); - else + if (ret) exaMarkSync(pDrawable->pScreen); - return TRUE; + return ret; } static void @@ -379,8 +359,8 @@ exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, return TRUE; } -void -exaCopyNtoN (DrawablePtr pSrcDrawable, +Bool +exaHWCopyNtoN (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, BoxPtr pbox, @@ -388,22 +368,20 @@ exaCopyNtoN (DrawablePtr pSrcDrawable, int dx, int dy, Bool reverse, - Bool upsidedown, - Pixel bitplane, - void *closure) + Bool upsidedown) { ExaScreenPriv (pDstDrawable->pScreen); PixmapPtr pSrcPixmap, pDstPixmap; 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; /* avoid doing copy operations if no boxes */ if (nbox == 0) - return; + return TRUE; pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable); pDstPixmap = exaGetDrawablePixmap (pDstDrawable); @@ -446,14 +424,6 @@ exaCopyNtoN (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); @@ -487,7 +457,20 @@ exaCopyNtoN (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) && @@ -498,40 +481,64 @@ exaCopyNtoN (DrawablePtr pSrcDrawable, goto fallback; } - if (!exaPixmapIsOffscreen(pSrcPixmap) || - !exaPixmapIsOffscreen(pDstPixmap) || - !(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, - upsidedown ? -1 : 1, - pGC ? pGC->alu : GXcopy, - pGC ? pGC->planemask : FB_ALLONES)) { - goto fallback; - } + if (exaPixmapIsOffscreen(pDstPixmap)) { + /* Normal blitting. */ + if (exaPixmapIsOffscreen(pSrcPixmap)) { + if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, + upsidedown ? -1 : 1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : FB_ALLONES)) { + goto fallback; + } - while (nbox--) - { - (*pExaScr->info->Copy) (pDstPixmap, - pbox->x1 + dx + src_off_x, - pbox->y1 + dy + src_off_y, - pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); - pbox++; - } + while (nbox--) + { + (*pExaScr->info->Copy) (pDstPixmap, + pbox->x1 + dx + src_off_x, + pbox->y1 + dy + src_off_y, + pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + pbox++; + } - (*pExaScr->info->DoneCopy) (pDstPixmap); - exaMarkSync (pDstDrawable->pScreen); + (*pExaScr->info->DoneCopy) (pDstPixmap); + exaMarkSync (pDstDrawable->pScreen); + /* UTS: mainly for SHM PutImage's secondary path. */ + } else { + int bpp = pSrcDrawable->bitsPerPixel; + int src_stride = exaGetPixmapPitch(pSrcPixmap); + CARD8 *src = NULL; + + if (!pExaScr->info->UploadToScreen) + goto fallback; + + if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel) + goto fallback; + + if (pSrcDrawable->bitsPerPixel < 8) + goto fallback; + + if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask))) + goto fallback; + + while (nbox--) + { + src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8); + if (!pExaScr->info->UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x, + pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, + (char *) src, src_stride)) + goto fallback; + + pbox++; + } + } + } else + goto fallback; goto out; fallback: - EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable, - exaDrawableLocation(pSrcDrawable), - exaDrawableLocation(pDstDrawable))); - exaPrepareAccessReg (pDstDrawable, EXA_PREPARE_DEST, dstregion); - exaPrepareAccessReg (pSrcDrawable, EXA_PREPARE_SRC, srcregion); - fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, - upsidedown, bitplane, closure); - exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC); - exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST); + ret = FALSE; out: if (dstregion) { @@ -542,6 +549,39 @@ out: REGION_UNINIT(pScreen, srcregion); REGION_DESTROY(pScreen, srcregion); } + + return ret; +} + +void +exaCopyNtoN (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pbox, + int nbox, + int dx, + int dy, + Bool reverse, + Bool upsidedown, + Pixel bitplane, + void *closure) +{ + ExaScreenPriv(pDstDrawable->pScreen); + + if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) + return; + + if (exaHWCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown)) + return; + + /* This is a CopyWindow, it's cleaner to fallback at the original call. */ + if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) { + pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; + return; + } + + /* fallback */ + ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure); } RegionPtr @@ -555,7 +595,7 @@ exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, srcx, srcy, width, height, dstx, dsty); } - return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, + return miDoCopy (pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty, exaCopyNtoN, 0, NULL); } @@ -730,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 */ @@ -741,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) @@ -778,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, @@ -898,6 +941,7 @@ exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) RegionRec rgnDst; int dx, dy; PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); + ExaScreenPriv(pWin->drawable.pScreen); dx = ptOldOrg.x - pWin->drawable.x; dy = ptOldOrg.y - pWin->drawable.y; @@ -912,11 +956,19 @@ exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) -pPixmap->screen_x, -pPixmap->screen_y); #endif - fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable, + pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW; + miCopyRegion (&pPixmap->drawable, &pPixmap->drawable, NULL, &rgnDst, dx, dy, exaCopyNtoN, 0, NULL); + pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW; REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); + + if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) { + pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW; + REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, dx, dy); + ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc); + } } static Bool @@ -927,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); } @@ -965,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); @@ -1008,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; @@ -1025,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); } @@ -1180,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); @@ -1226,17 +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: - EXA_FALLBACK(("from %p (%c)\n", pDrawable, - exaDrawableLocation(pDrawable))); - - exaPrepareAccessReg (pDrawable, EXA_PREPARE_SRC, &Reg); - fbGetImage (pDrawable, x, y, w, h, format, planeMask, d); - exaFinishAccess (pDrawable, EXA_PREPARE_SRC); - -out: - REGION_UNINIT(pScreen, &Reg); + ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); } diff --git a/xorg-server/exa/exa_classic.c b/xorg-server/exa/exa_classic.c new file mode 100644 index 000000000..1eff57091 --- /dev/null +++ b/xorg-server/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/xorg-server/exa/exa_driver.c b/xorg-server/exa/exa_driver.c new file mode 100644 index 000000000..97036955b --- /dev/null +++ b/xorg-server/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/xorg-server/exa/exa_glyphs.c b/xorg-server/exa/exa_glyphs.c index 93b8b36ae..d621ccf76 100644 --- a/xorg-server/exa/exa_glyphs.c +++ b/xorg-server/exa/exa_glyphs.c @@ -68,7 +68,7 @@ #define GLYPH_BUFFER_SIZE 256 typedef struct { - PicturePtr source; + PicturePtr mask; ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE]; int count; } ExaGlyphBuffer, *ExaGlyphBufferPtr; @@ -144,7 +144,7 @@ exaUnrealizeGlyphCaches(ScreenPtr pScreen, /* All caches for a single format share a single pixmap for glyph storage, * allowing mixing glyphs of different sizes without paying a penalty - * for switching between source pixmaps. (Note that for a size of font + * for switching between mask pixmaps. (Note that for a size of font * right at the border between two sizes, we might be switching for almost * every glyph.) * @@ -187,7 +187,6 @@ exaRealizeGlyphCaches(ScreenPtr pScreen, } /* Now allocate the pixmap and picture */ - pPixmap = (*pScreen->CreatePixmap) (pScreen, CACHE_PICTURE_WIDTH, height, depth, 0); @@ -205,7 +204,6 @@ exaRealizeGlyphCaches(ScreenPtr pScreen, return FALSE; /* And store the picture in all the caches for the format */ - for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; int j; @@ -374,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; @@ -388,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; @@ -434,13 +435,19 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, ExaGlyphCachePtr cache, ExaGlyphBufferPtr buffer, GlyphPtr pGlyph, - int xGlyph, - int yGlyph) + PicturePtr pSrc, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst) { ExaCompositeRectPtr rect; int pos; - if (buffer->source && buffer->source != cache->picture) + if (buffer->mask && buffer->mask != cache->picture) return ExaGlyphNeedFlush; if (!cache->picture) { @@ -469,18 +476,19 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, * already in the output buffer were at this position in * the cache */ - pos = cache->evictionPosition; DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); if (buffer->count) { int x, y; int i; - + x = CACHE_X(pos); y = CACHE_Y(pos); for (i = 0; i < buffer->count; i++) { - if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) { + if (pSrc ? + (buffer->rects[i].xMask == x && buffer->rects[i].yMask == y) : + (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y)) { DBG_GLYPH_CACHE((" must flush buffer\n")); return ExaGlyphNeedFlush; } @@ -498,13 +506,28 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, exaGlyphCacheUploadGlyph(pScreen, cache, pos, pGlyph); } - buffer->source = cache->picture; + buffer->mask = cache->picture; rect = &buffer->rects[buffer->count]; - rect->xSrc = CACHE_X(pos); - rect->ySrc = CACHE_Y(pos); - rect->xDst = xGlyph - pGlyph->info.x; - rect->yDst = yGlyph - pGlyph->info.y; + + if (pSrc) + { + rect->xSrc = xSrc; + rect->ySrc = ySrc; + rect->xMask = CACHE_X(pos); + rect->yMask = CACHE_Y(pos); + } + else + { + rect->xSrc = CACHE_X(pos); + rect->ySrc = CACHE_Y(pos); + rect->xMask = 0; + rect->yMask = 0; + } + + rect->pDst = pDst; + rect->xDst = xDst; + rect->yDst = yDst; rect->width = pGlyph->info.width; rect->height = pGlyph->info.height; @@ -520,15 +543,21 @@ static ExaGlyphCacheResult exaBufferGlyph(ScreenPtr pScreen, ExaGlyphBufferPtr buffer, GlyphPtr pGlyph, - int xGlyph, - int yGlyph) + PicturePtr pSrc, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst) { ExaScreenPriv(pScreen); unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; int width = pGlyph->info.width; int height = pGlyph->info.height; ExaCompositeRectPtr rect; - PicturePtr source; + PicturePtr mask; int i; if (buffer->count == GLYPH_BUFFER_SIZE) @@ -543,9 +572,15 @@ exaBufferGlyph(ScreenPtr pScreen, if (format == cache->format && width <= cache->glyphWidth && height <= cache->glyphHeight) { - ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen, &pExaScr->glyphCaches[i], + ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen, + &pExaScr->glyphCaches[i], buffer, - pGlyph, xGlyph, yGlyph); + pGlyph, + pSrc, + pDst, + xSrc, ySrc, + xMask, yMask, + xDst, yDst); switch (result) { case ExaGlyphFail: break; @@ -558,19 +593,21 @@ exaBufferGlyph(ScreenPtr pScreen, /* Couldn't find the glyph in the cache, use the glyph picture directly */ - source = GlyphPicture(pGlyph)[pScreen->myNum]; - if (buffer->source && buffer->source != source) + mask = GlyphPicture(pGlyph)[pScreen->myNum]; + if (buffer->mask && buffer->mask != mask) return ExaGlyphNeedFlush; - buffer->source = source; - + buffer->mask = mask; + rect = &buffer->rects[buffer->count]; - rect->xSrc = 0; - rect->ySrc = 0; - rect->xDst = xGlyph - pGlyph->info.x; - rect->yDst = yGlyph - pGlyph->info.y; - rect->width = pGlyph->info.width; - rect->height = pGlyph->info.height; + rect->xSrc = xSrc; + rect->ySrc = ySrc; + rect->xMask = xMask; + rect->yMask = yMask; + rect->xDst = xDst; + rect->yDst = yDst; + rect->width = width; + rect->height = height; buffer->count++; @@ -581,44 +618,23 @@ static void exaGlyphsToMask(PicturePtr pMask, ExaGlyphBufferPtr buffer) { - exaCompositeRects(PictOpAdd, buffer->source, pMask, + exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask, buffer->count, buffer->rects); buffer->count = 0; - buffer->source = NULL; + buffer->mask = NULL; } static void -exaGlyphsToDst(CARD8 op, - PicturePtr pSrc, +exaGlyphsToDst(PicturePtr pSrc, PicturePtr pDst, - ExaGlyphBufferPtr buffer, - INT16 xSrc, - INT16 ySrc, - INT16 xDst, - INT16 yDst) + ExaGlyphBufferPtr buffer) { - int i; - - for (i = 0; i < buffer->count; i++) { - ExaCompositeRectPtr rect = &buffer->rects[i]; - - CompositePicture (op, - pSrc, - buffer->source, - pDst, - xSrc + rect->xDst - xDst, - ySrc + rect->yDst - yDst, - rect->xSrc, - rect->ySrc, - rect->xDst, - rect->yDst, - rect->width, - rect->height); - } + exaCompositeRects(PictOpOver, pSrc, buffer->mask, pDst, buffer->count, + buffer->rects); buffer->count = 0; - buffer->source = NULL; + buffer->mask = NULL; } /* Cut and paste from render/glyph.c - probably should export it instead */ @@ -674,79 +690,6 @@ GlyphExtents (int nlist, } } -/** - * Returns TRUE if the glyphs in the lists intersect. Only checks based on - * bounding box, which appears to be good enough to catch most cases at least. - */ -static Bool -exaGlyphsIntersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs) -{ - int x1, x2, y1, y2; - int n; - GlyphPtr glyph; - int x, y; - BoxRec extents; - Bool first = TRUE; - - x = 0; - y = 0; - while (nlist--) { - x += list->xOff; - y += list->yOff; - n = list->len; - list++; - while (n--) { - glyph = *glyphs++; - - if (glyph->info.width == 0 || glyph->info.height == 0) { - x += glyph->info.xOff; - y += glyph->info.yOff; - continue; - } - - x1 = x - glyph->info.x; - if (x1 < MINSHORT) - x1 = MINSHORT; - y1 = y - glyph->info.y; - if (y1 < MINSHORT) - y1 = MINSHORT; - x2 = x1 + glyph->info.width; - if (x2 > MAXSHORT) - x2 = MAXSHORT; - y2 = y1 + glyph->info.height; - if (y2 > MAXSHORT) - y2 = MAXSHORT; - - if (first) { - extents.x1 = x1; - extents.y1 = y1; - extents.x2 = x2; - extents.y2 = y2; - first = FALSE; - } else { - if (x1 < extents.x2 && x2 > extents.x1 && - y1 < extents.y2 && y2 > extents.y1) - { - return TRUE; - } - - if (x1 < extents.x1) - extents.x1 = x1; - if (x2 > extents.x2) - extents.x2 = x2; - if (y1 < extents.y1) - extents.y1 = y1; - if (y2 > extents.y2) - extents.y2 = y2; - } - x += glyph->info.xOff; - y += glyph->info.yOff; - } - } - - return FALSE; -} - void exaGlyphs (CARD8 op, PicturePtr pSrc, @@ -760,11 +703,11 @@ exaGlyphs (CARD8 op, { PicturePtr pPicture; PixmapPtr pMaskPixmap = 0; - PicturePtr pMask; + PicturePtr pMask = NULL; ScreenPtr pScreen = pDst->pDrawable->pScreen; int width = 0, height = 0; int x, y; - int xDst = list->xOff, yDst = list->yOff; + int first_xOff = list->xOff, first_yOff = list->yOff; int n; GlyphPtr glyph; int error; @@ -772,31 +715,9 @@ exaGlyphs (CARD8 op, CARD32 component_alpha; ExaGlyphBuffer buffer; - /* If we don't have a mask format but all the glyphs have the same format - * and don't intersect, use the glyph format as mask format for the full - * benefits of the glyph cache. - */ - if (!maskFormat) { - Bool sameFormat = TRUE; - int i; - - maskFormat = list[0].format; - - for (i = 0; i < nlist; i++) { - if (maskFormat->format != list[i].format->format) { - sameFormat = FALSE; - break; - } - } - - if (!sameFormat || (maskFormat->depth != 1 && - exaGlyphsIntersect(nlist, list, glyphs))) { - maskFormat = NULL; - } - } - if (maskFormat) { + ExaScreenPriv(pScreen); GCPtr pGC; xRectangle rect; @@ -823,10 +744,38 @@ exaGlyphs (CARD8 op, pMask = CreatePicture (0, &pMaskPixmap->drawable, maskFormat, CPComponentAlpha, &component_alpha, serverClient, &error); - if (!pMask) + if (!pMask || + (!component_alpha && pExaScr->info->CheckComposite && + !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask))) { + PictFormatPtr argbFormat; + (*pScreen->DestroyPixmap) (pMaskPixmap); - return; + + if (!pMask) + return; + + /* The driver can't seem to composite to a8, let's try argb (but + * without component-alpha) */ + FreePicture ((pointer) pMask, (XID) 0); + + argbFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); + + if (argbFormat) + maskFormat = argbFormat; + + pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pMaskPixmap) + return; + + pMask = CreatePicture (0, &pMaskPixmap->drawable, maskFormat, 0, 0, + serverClient, &error); + if (!pMask) { + (*pScreen->DestroyPixmap) (pMaskPixmap); + return; + } } pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); ValidateGC (&pMaskPixmap->drawable, pGC); @@ -841,12 +790,11 @@ exaGlyphs (CARD8 op, } else { - pMask = pDst; x = 0; y = 0; } buffer.count = 0; - buffer.source = NULL; + buffer.mask = NULL; while (nlist--) { x += list->xOff; @@ -857,16 +805,32 @@ exaGlyphs (CARD8 op, glyph = *glyphs++; pPicture = GlyphPicture (glyph)[pScreen->myNum]; - if (glyph->info.width > 0 && glyph->info.height > 0 && - exaBufferGlyph(pScreen, &buffer, glyph, x, y) == ExaGlyphNeedFlush) + if (glyph->info.width > 0 && glyph->info.height > 0) { + /* pGlyph->info.{x,y} compensate for empty space in the glyph. */ if (maskFormat) - exaGlyphsToMask(pMask, &buffer); + { + if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, + 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y) == ExaGlyphNeedFlush) + { + exaGlyphsToMask(pMask, &buffer); + exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, + 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y); + } + } else - exaGlyphsToDst(op, pSrc, pDst, &buffer, - xSrc, ySrc, xDst, yDst); - - exaBufferGlyph(pScreen, &buffer, glyph, x, y); + { + if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, + xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, + 0, 0, x - glyph->info.x, y - glyph->info.y) + == ExaGlyphNeedFlush) + { + exaGlyphsToDst(pSrc, pDst, &buffer); + exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, + xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, + 0, 0, x - glyph->info.x, y - glyph->info.y); + } + } } x += glyph->info.xOff; @@ -879,8 +843,7 @@ exaGlyphs (CARD8 op, if (maskFormat) exaGlyphsToMask(pMask, &buffer); else - exaGlyphsToDst(op, pSrc, pDst, &buffer, - xSrc, ySrc, xDst, yDst); + exaGlyphsToDst(pSrc, pDst, &buffer); } if (maskFormat) @@ -891,8 +854,8 @@ exaGlyphs (CARD8 op, pSrc, pMask, pDst, - xSrc + x - xDst, - ySrc + y - yDst, + xSrc + x - first_xOff, + ySrc + y - first_yOff, 0, 0, x, y, width, height); diff --git a/xorg-server/exa/exa_migration_classic.c b/xorg-server/exa/exa_migration_classic.c new file mode 100644 index 000000000..d8e1e86da --- /dev/null +++ b/xorg-server/exa/exa_migration_classic.c @@ -0,0 +1,720 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * Michel Dänzer <michel@tungstengraphics.com> + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <string.h> + +#include "exa_priv.h" +#include "exa.h" + +#if DEBUG_MIGRATE +#define DBG_MIGRATE(a) ErrorF a +#else +#define DBG_MIGRATE(a) +#endif + +/** + * The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys + * and exaCopyDirtyToFb both needed to do this loop. + */ +static void +exaMemcpyBox (PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch, + CARD8 *dst, int dst_pitch) + { + int i, cpp = pPixmap->drawable.bitsPerPixel / 8; + int bytes = (pbox->x2 - pbox->x1) * cpp; + + src += pbox->y1 * src_pitch + pbox->x1 * cpp; + dst += pbox->y1 * dst_pitch + pbox->x1 * cpp; + + for (i = pbox->y2 - pbox->y1; i; i--) { + memcpy (dst, src, bytes); + src += src_pitch; + dst += dst_pitch; + } +} + +/** + * Returns TRUE if the pixmap is dirty (has been modified in its current + * location compared to the other), or lacks a private for tracking + * dirtiness. + */ +static Bool +exaPixmapIsDirty (PixmapPtr pPix) +{ + ExaPixmapPriv (pPix); + + if (pExaPixmap == NULL) + EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE); + + return REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage)) || + !REGION_EQUAL(pScreen, &pExaPixmap->validSys, &pExaPixmap->validFB); +} + +/** + * Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score + * to be considered "should be in framebuffer". That's just anything that has + * had more acceleration than fallbacks, or has no score yet. + * + * Only valid if using a migration scheme that tracks score. + */ +static Bool +exaPixmapShouldBeInFB (PixmapPtr pPix) +{ + ExaPixmapPriv (pPix); + + if (exaPixmapIsPinned (pPix)) + return TRUE; + + return pExaPixmap->score >= 0; +} + +/** + * If the pixmap is currently dirty, this copies at least the dirty area from + * FB to system or vice versa. Both areas must be allocated. + */ +static void +exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, + Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h, + char *sys, int sys_pitch), CARD8 *fallback_src, + CARD8 *fallback_dst, int fallback_srcpitch, int fallback_dstpitch, + int fallback_index, void (*sync) (ScreenPtr pScreen)) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + RegionPtr damage = DamageRegion (pExaPixmap->pDamage); + RegionRec CopyReg; + Bool save_offscreen; + int save_pitch; + BoxPtr pBox; + int nbox; + Bool access_prepared = FALSE; + Bool need_sync = FALSE; + + /* Damaged bits are valid in current copy but invalid in other one */ + if (exaPixmapIsOffscreen(pPixmap)) { + REGION_UNION(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB, + damage); + REGION_SUBTRACT(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, + damage); + } else { + REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, + damage); + REGION_SUBTRACT(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB, + damage); + } + + REGION_EMPTY(pScreen, damage); + + /* Copy bits valid in source but not in destination */ + REGION_NULL(pScreen, &CopyReg); + REGION_SUBTRACT(pScreen, &CopyReg, pValidSrc, pValidDst); + + if (migrate->as_dst) { + ExaScreenPriv (pPixmap->drawable.pScreen); + + /* XXX: The pending damage region will be marked as damaged after the + * operation, so it should serve as an upper bound for the region that + * needs to be synchronized for the operation. Unfortunately, this + * causes corruption in some cases, e.g. when starting compiz. See + * https://bugs.freedesktop.org/show_bug.cgi?id=12916 . + */ + if (pExaScr->optimize_migration) { + RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); + +#if DEBUG_MIGRATE + if (REGION_NIL(pending_damage)) { + static Bool firsttime = TRUE; + + if (firsttime) { + ErrorF("%s: Pending damage region empty!\n", __func__); + firsttime = FALSE; + } + } +#endif + + /* Try to prevent destination valid region from growing too many + * rects by filling it up to the extents of the union of the + * destination valid region and the pending damage region. + */ + if (REGION_NUM_RECTS(pValidDst) > 10) { + BoxRec box; + BoxPtr pValidExt, pDamageExt; + RegionRec closure; + + pValidExt = REGION_EXTENTS(pScreen, pValidDst); + pDamageExt = REGION_EXTENTS(pScreen, pending_damage); + + box.x1 = min(pValidExt->x1, pDamageExt->x1); + box.y1 = min(pValidExt->y1, pDamageExt->y1); + box.x2 = max(pValidExt->x2, pDamageExt->x2); + box.y2 = max(pValidExt->y2, pDamageExt->y2); + + REGION_INIT(pScreen, &closure, &box, 0); + REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, &closure); + } else + REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, pending_damage); + } + + /* The caller may provide a region to be subtracted from the calculated + * dirty region. This is to avoid migration of bits that don't + * contribute to the result of the operation. + */ + if (migrate->pReg) + REGION_SUBTRACT(pScreen, &CopyReg, &CopyReg, migrate->pReg); + } else { + /* The caller may restrict the region to be migrated for source pixmaps + * to what's relevant for the operation. + */ + if (migrate->pReg) + REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, migrate->pReg); + } + + pBox = REGION_RECTS(&CopyReg); + nbox = REGION_NUM_RECTS(&CopyReg); + + save_offscreen = pExaPixmap->offscreen; + save_pitch = pPixmap->devKind; + pExaPixmap->offscreen = TRUE; + pPixmap->devKind = pExaPixmap->fb_pitch; + + while (nbox--) { + pBox->x1 = max(pBox->x1, 0); + pBox->y1 = max(pBox->y1, 0); + pBox->x2 = min(pBox->x2, pPixmap->drawable.width); + pBox->y2 = min(pBox->y2, pPixmap->drawable.height); + + if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) + continue; + + if (!transfer || !transfer (pPixmap, + pBox->x1, pBox->y1, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1, + (char *) (pExaPixmap->sys_ptr + + pBox->y1 * pExaPixmap->sys_pitch + + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8), + pExaPixmap->sys_pitch)) + { + if (!access_prepared) { + ExaDoPrepareAccess(&pPixmap->drawable, fallback_index); + access_prepared = TRUE; + } + exaMemcpyBox (pPixmap, pBox, + fallback_src, fallback_srcpitch, + fallback_dst, fallback_dstpitch); + } else + need_sync = TRUE; + + pBox++; + } + + if (access_prepared) + exaFinishAccess(&pPixmap->drawable, fallback_index); + else if (need_sync && sync) + sync (pPixmap->drawable.pScreen); + + pExaPixmap->offscreen = save_offscreen; + pPixmap->devKind = save_pitch; + + /* Try to prevent source valid region from growing too many rects by + * removing parts of it which are also in the destination valid region. + * Removing anything beyond that would lead to data loss. + */ + if (REGION_NUM_RECTS(pValidSrc) > 20) + REGION_SUBTRACT(pScreen, pValidSrc, pValidSrc, pValidDst); + + /* The copied bits are now valid in destination */ + REGION_UNION(pScreen, pValidDst, pValidDst, &CopyReg); + + REGION_UNINIT(pScreen, &CopyReg); +} + +/** + * 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 (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaScreenPriv (pPixmap->drawable.pScreen); + ExaPixmapPriv (pPixmap); + + exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB, + pExaScr->info->DownloadFromScreen, pExaPixmap->fb_ptr, + pExaPixmap->sys_ptr, pExaPixmap->fb_pitch, + pExaPixmap->sys_pitch, EXA_PREPARE_SRC, exaWaitSync); +} + +/** + * If the pixmap is currently dirty, this copies at least the dirty area from + * the system memory copy to the framebuffer memory copy. Both areas must be + * allocated. + */ +static void +exaCopyDirtyToFb (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaScreenPriv (pPixmap->drawable.pScreen); + ExaPixmapPriv (pPixmap); + + exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys, + pExaScr->info->UploadToScreen, pExaPixmap->sys_ptr, + pExaPixmap->fb_ptr, pExaPixmap->sys_pitch, + pExaPixmap->fb_pitch, EXA_PREPARE_DEST, NULL); +} + +/** + * Allocates a framebuffer copy of the pixmap if necessary, and then copies + * any necessary pixmap data into the framebuffer copy and points the pixmap at + * it. + * + * Note that when first allocated, a pixmap will have FALSE dirty flag. + * This is intentional because pixmap data starts out undefined. So if we move + * it in due to the first operation against it being accelerated, it will have + * undefined framebuffer contents that we didn't have to upload. If we do + * moveouts (and moveins) after the first movein, then we will only have to copy + * back and forth if the pixmap was written to after the last synchronization of + * the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away) + * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move + * all the data, since it's almost surely all valid now. + */ +static void +exaDoMoveInPixmap (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv (pScreen); + ExaPixmapPriv (pPixmap); + + /* If we're VT-switched away, no touching card memory allowed. */ + if (pExaScr->swappedOut) + return; + + /* If we're not allowed to move, then fail. */ + if (exaPixmapIsPinned(pPixmap)) + return; + + /* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of + * fragility in EXA, and <8bpp is probably not used enough any more to care + * (at least, not in acceleratd paths). + */ + if (pPixmap->drawable.bitsPerPixel < 8) + return; + + if (pExaPixmap->accel_blocked) + return; + + if (pExaPixmap->area == NULL) { + pExaPixmap->area = + exaOffscreenAlloc (pScreen, pExaPixmap->fb_size, + pExaScr->info->pixmapOffsetAlign, FALSE, + exaPixmapSave, (pointer) pPixmap); + if (pExaPixmap->area == NULL) + return; + + pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase + + pExaPixmap->area->offset; + } + + exaCopyDirtyToFb (migrate); + + if (exaPixmapIsOffscreen(pPixmap)) + return; + + DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap, + (ExaGetPixmapPriv(pPixmap)->area ? + ExaGetPixmapPriv(pPixmap)->area->offset : 0), + pPixmap->drawable.width, + pPixmap->drawable.height, + exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); + + pExaPixmap->offscreen = TRUE; + + pPixmap->devKind = pExaPixmap->fb_pitch; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; +} + +void +exaMoveInPixmap_classic (PixmapPtr pPixmap) +{ + static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE, + .pReg = NULL }; + + migrate.pPix = pPixmap; + exaDoMoveInPixmap (&migrate); +} + +/** + * Switches the current active location of the pixmap to system memory, copying + * updated data out if necessary. + */ +static void +exaDoMoveOutPixmap (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + + if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap)) + return; + + exaCopyDirtyToSys (migrate); + + if (exaPixmapIsOffscreen(pPixmap)) { + + DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap, + (void*)(ExaGetPixmapPriv(pPixmap)->area ? + ExaGetPixmapPriv(pPixmap)->area->offset : 0), + pPixmap->drawable.width, + pPixmap->drawable.height, + exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); + + pExaPixmap->offscreen = FALSE; + + pPixmap->devKind = pExaPixmap->sys_pitch; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + } +} + +void +exaMoveOutPixmap_classic (PixmapPtr pPixmap) +{ + static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE, + .pReg = NULL }; + + migrate.pPix = pPixmap; + exaDoMoveOutPixmap (&migrate); +} + + +/** + * Copies out important pixmap data and removes references to framebuffer area. + * Called when the memory manager decides it's time to kick the pixmap out of + * framebuffer entirely. + */ +void +exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area) +{ + PixmapPtr pPixmap = area->privData; + ExaPixmapPriv(pPixmap); + + exaMoveOutPixmap(pPixmap); + + pExaPixmap->fb_ptr = NULL; + pExaPixmap->area = NULL; + + /* Mark all FB bits as invalid, so all valid system bits get copied to FB + * next time */ + REGION_EMPTY(pPixmap->drawable.pScreen, &pExaPixmap->validFB); +} + +/** + * For the "greedy" migration scheme, pushes the pixmap toward being located in + * framebuffer memory. + */ +static void +exaMigrateTowardFb (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + + if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) { + DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n", + (pointer)pPixmap)); + return; + } + + DBG_MIGRATE(("UseScreen %p score %d\n", + (pointer)pPixmap, pExaPixmap->score)); + + if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) { + exaDoMoveInPixmap(migrate); + pExaPixmap->score = 0; + } + + if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX) + pExaPixmap->score++; + + if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN && + !exaPixmapIsOffscreen(pPixmap)) + { + exaDoMoveInPixmap(migrate); + } + + if (exaPixmapIsOffscreen(pPixmap)) { + exaCopyDirtyToFb (migrate); + ExaOffscreenMarkUsed (pPixmap); + } else + exaCopyDirtyToSys (migrate); +} + +/** + * For the "greedy" migration scheme, pushes the pixmap toward being located in + * system memory. + */ +static void +exaMigrateTowardSys (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + + DBG_MIGRATE(("UseMem: %p score %d\n", (pointer)pPixmap, pExaPixmap->score)); + + if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) + return; + + if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) + pExaPixmap->score = 0; + + if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN) + pExaPixmap->score--; + + if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area) + exaDoMoveOutPixmap(migrate); + + if (exaPixmapIsOffscreen(pPixmap)) { + exaCopyDirtyToFb (migrate); + ExaOffscreenMarkUsed (pPixmap); + } else + exaCopyDirtyToSys (migrate); +} + +/** + * If the pixmap has both a framebuffer and system memory copy, this function + * asserts that both of them are the same. + */ +static Bool +exaAssertNotDirty (PixmapPtr pPixmap) +{ + ExaPixmapPriv (pPixmap); + CARD8 *dst, *src; + RegionRec ValidReg; + int dst_pitch, src_pitch, cpp, y, nbox, save_pitch; + BoxPtr pBox; + Bool ret = TRUE, save_offscreen; + + if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL) + return ret; + + REGION_NULL(pScreen, &ValidReg); + REGION_INTERSECT(pScreen, &ValidReg, &pExaPixmap->validFB, + &pExaPixmap->validSys); + nbox = REGION_NUM_RECTS(&ValidReg); + + if (!nbox) + goto out; + + pBox = REGION_RECTS(&ValidReg); + + dst_pitch = pExaPixmap->sys_pitch; + src_pitch = pExaPixmap->fb_pitch; + cpp = pPixmap->drawable.bitsPerPixel / 8; + + save_offscreen = pExaPixmap->offscreen; + save_pitch = pPixmap->devKind; + pExaPixmap->offscreen = TRUE; + pPixmap->devKind = pExaPixmap->fb_pitch; + + if (!ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC)) + goto skip; + + while (nbox--) { + int rowbytes; + + pBox->x1 = max(pBox->x1, 0); + pBox->y1 = max(pBox->y1, 0); + pBox->x2 = min(pBox->x2, pPixmap->drawable.width); + pBox->y2 = min(pBox->y2, pPixmap->drawable.height); + + if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) + continue; + + rowbytes = (pBox->x2 - pBox->x1) * cpp; + src = (CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch + pBox->x1 * cpp; + dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp; + + for (y = pBox->y1; y < pBox->y2; + y++, src += src_pitch, dst += dst_pitch) { + if (memcmp(dst, src, rowbytes) != 0) { + ret = FALSE; + exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2, + pBox->y2); + break; + } + } + } + +skip: + exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); + + pExaPixmap->offscreen = save_offscreen; + pPixmap->devKind = save_pitch; + +out: + REGION_UNINIT(pScreen, &ValidReg); + return ret; +} + +/** + * Performs migration of the pixmaps according to the operation information + * provided in pixmaps and can_accel and the migration scheme chosen in the + * config file. + */ +void +exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) +{ + ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen; + ExaScreenPriv(pScreen); + int i, j; + + /* If this debugging flag is set, check each pixmap for whether it is marked + * as clean, and if so, actually check if that's the case. This should help + * catch issues with failing to mark a drawable as dirty. While it will + * catch them late (after the operation happened), it at least explains what + * went wrong, and instrumenting the code to find what operation happened + * to the pixmap last shouldn't be hard. + */ + if (pExaScr->checkDirtyCorrectness) { + for (i = 0; i < npixmaps; i++) { + if (!exaPixmapIsDirty (pixmaps[i].pPix) && + !exaAssertNotDirty (pixmaps[i].pPix)) + ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i); + } + } + /* If anything is pinned in system memory, we won't be able to + * accelerate. + */ + for (i = 0; i < npixmaps; i++) { + if (exaPixmapIsPinned (pixmaps[i].pPix) && + !exaPixmapIsOffscreen (pixmaps[i].pPix)) + { + EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix, + pixmaps[i].pPix->drawable.width, + pixmaps[i].pPix->drawable.height)); + can_accel = FALSE; + break; + } + } + + if (pExaScr->migration == ExaMigrationSmart) { + /* If we've got something as a destination that we shouldn't cause to + * become newly dirtied, take the unaccelerated route. + */ + for (i = 0; i < npixmaps; i++) { + if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB (pixmaps[i].pPix) && + !exaPixmapIsDirty (pixmaps[i].pPix)) + { + for (i = 0; i < npixmaps; i++) { + if (!exaPixmapIsDirty (pixmaps[i].pPix)) + exaDoMoveOutPixmap (pixmaps + i); + } + return; + } + } + + /* If we aren't going to accelerate, then we migrate everybody toward + * system memory, and kick out if it's free. + */ + if (!can_accel) { + for (i = 0; i < npixmaps; i++) { + exaMigrateTowardSys (pixmaps + i); + if (!exaPixmapIsDirty (pixmaps[i].pPix)) + exaDoMoveOutPixmap (pixmaps + i); + } + return; + } + + /* Finally, the acceleration path. Move them all in. */ + for (i = 0; i < npixmaps; i++) { + exaMigrateTowardFb(pixmaps + i); + exaDoMoveInPixmap(pixmaps + i); + } + } else if (pExaScr->migration == ExaMigrationGreedy) { + /* If we can't accelerate, either because the driver can't or because one of + * the pixmaps is pinned in system memory, then we migrate everybody toward + * system memory. + * + * We also migrate toward system if all pixmaps involved are currently in + * system memory -- this can mitigate thrashing when there are significantly + * more pixmaps active than would fit in memory. + * + * If not, then we migrate toward FB so that hopefully acceleration can + * happen. + */ + if (!can_accel) { + for (i = 0; i < npixmaps; i++) + exaMigrateTowardSys (pixmaps + i); + return; + } + + for (i = 0; i < npixmaps; i++) { + if (exaPixmapIsOffscreen(pixmaps[i].pPix)) { + /* Found one in FB, so move all to FB. */ + for (j = 0; j < npixmaps; j++) + exaMigrateTowardFb(pixmaps + i); + return; + } + } + + /* Nobody's in FB, so move all away from FB. */ + for (i = 0; i < npixmaps; i++) + exaMigrateTowardSys(pixmaps + i); + } else if (pExaScr->migration == ExaMigrationAlways) { + /* Always move the pixmaps out if we can't accelerate. If we can + * accelerate, try to move them all in. If that fails, then move them + * back out. + */ + if (!can_accel) { + for (i = 0; i < npixmaps; i++) + exaDoMoveOutPixmap(pixmaps + i); + return; + } + + /* Now, try to move them all into FB */ + for (i = 0; i < npixmaps; i++) { + exaDoMoveInPixmap(pixmaps + i); + } + + /* If we couldn't fit everything in, abort */ + for (i = 0; i < npixmaps; i++) { + if (!exaPixmapIsOffscreen(pixmaps[i].pPix)) { + return; + } + } + + /* Yay, everything's offscreen, mark memory as used */ + for (i = 0; i < npixmaps; i++) { + ExaOffscreenMarkUsed (pixmaps[i].pPix); + } + } +} diff --git a/xorg-server/exa/exa_migration_mixed.c b/xorg-server/exa/exa_migration_mixed.c new file mode 100644 index 000000000..d1ee9871b --- /dev/null +++ b/xorg-server/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/xorg-server/exa/exa_mixed.c b/xorg-server/exa/exa_mixed.c new file mode 100644 index 000000000..01f87ba87 --- /dev/null +++ b/xorg-server/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/xorg-server/exa/exa_offscreen.c b/xorg-server/exa/exa_offscreen.c index 4aaa2c132..eb53b2a30 100644 --- a/xorg-server/exa/exa_offscreen.c +++ b/xorg-server/exa/exa_offscreen.c @@ -93,7 +93,7 @@ exaFindAreaToEvict(ExaScreenPrivPtr pExaScr, int size, int align) { ExaOffscreenArea *begin, *end, *best; unsigned cost, best_cost; - int avail, real_size, tmp; + int avail, real_size; best_cost = UINT_MAX; begin = end = pExaScr->info->offScreenAreas; @@ -111,10 +111,7 @@ exaFindAreaToEvict(ExaScreenPrivPtr pExaScr, int size, int align) break; /* adjust size needed to account for alignment loss for this area */ - real_size = size; - tmp = begin->base_offset % align; - if (tmp) - real_size += (align - tmp); + real_size = size + (begin->base_offset + begin->size - size) % align; while (avail < real_size && end != NULL) { @@ -172,7 +169,7 @@ exaOffscreenAlloc (ScreenPtr pScreen, int size, int align, { ExaOffscreenArea *area; ExaScreenPriv (pScreen); - int tmp, real_size = 0; + int real_size = 0, free_total = 0, largest_avail = 0; #if DEBUG_OFFSCREEN static int number = 0; ErrorF("================= ============ allocating a new pixmap %d\n", ++number); @@ -205,14 +202,37 @@ exaOffscreenAlloc (ScreenPtr pScreen, int size, int align, continue; /* adjust size to match alignment requirement */ - real_size = size; - tmp = area->base_offset % align; - if (tmp) - real_size += (align - tmp); + real_size = size + (area->base_offset + area->size - size) % align; /* does it fit? */ if (real_size <= area->size) break; + + free_total += area->size; + + if (area->size > largest_avail) + largest_avail = area->size; + } + + if (!area && free_total >= size) { + CARD32 now = GetTimeInMillis(); + + /* Don't defragment more than once per second, to avoid adding more + * overhead than we're trying to prevent + */ + if (abs((INT32) (now - pExaScr->lastDefragment)) > 1000) { + area = ExaOffscreenDefragment(pScreen); + pExaScr->lastDefragment = now; + + if (area) { + /* adjust size to match alignment requirement */ + real_size = size + (area->base_offset + area->size - size) % align; + + /* does it fit? */ + if (real_size > area->size) + area = NULL; + } + } } if (!area) @@ -228,10 +248,7 @@ exaOffscreenAlloc (ScreenPtr pScreen, int size, int align, } /* adjust size needed to account for alignment loss for this area */ - real_size = size; - tmp = area->base_offset % align; - if (tmp) - real_size += (align - tmp); + real_size = size + (area->base_offset + area->size - size) % align; /* * Kick out first area if in use @@ -254,17 +271,27 @@ exaOffscreenAlloc (ScreenPtr pScreen, int size, int align, ExaOffscreenArea *new_area = xalloc (sizeof (ExaOffscreenArea)); if (!new_area) return NULL; - new_area->base_offset = area->base_offset + real_size; + new_area->base_offset = area->base_offset; + new_area->offset = new_area->base_offset; + new_area->align = 0; new_area->size = area->size - real_size; new_area->state = ExaOffscreenAvail; new_area->save = NULL; new_area->last_use = 0; new_area->eviction_cost = 0; - new_area->next = area->next; - area->next = new_area; + new_area->next = area; + new_area->prev = area->prev; + if (area->prev->next) + area->prev->next = new_area; + else + pExaScr->info->offScreenAreas = new_area; + area->prev = new_area; + area->base_offset = new_area->base_offset + new_area->size; area->size = real_size; - } + } else + pExaScr->numOffscreenAvailable--; + /* * Mark this area as in use */ @@ -277,6 +304,7 @@ exaOffscreenAlloc (ScreenPtr pScreen, int size, int align, area->last_use = pExaScr->offScreenCounter++; area->offset = (area->base_offset + align - 1); area->offset -= area->offset % align; + area->align = align; ExaOffscreenValidate (pScreen); @@ -371,6 +399,9 @@ exaEnableDisableFBAccess (int index, Bool enable) ScreenPtr pScreen = screenInfo.screens[index]; ExaScreenPriv (pScreen); + if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) + return; + if (!enable && pExaScr->disableFbCount++ == 0) { if (pExaScr->info->exa_minor < 1) ExaOffscreenSwapOut (pScreen); @@ -388,7 +419,7 @@ exaEnableDisableFBAccess (int index, Bool enable) /* merge the next free area into this one */ static void -ExaOffscreenMerge (ExaOffscreenArea *area) +ExaOffscreenMerge (ExaScreenPrivPtr pExaScr, ExaOffscreenArea *area) { ExaOffscreenArea *next = area->next; @@ -396,7 +427,13 @@ ExaOffscreenMerge (ExaOffscreenArea *area) area->size += next->size; /* frob pointer */ area->next = next->next; + if (area->next) + area->next->prev = area; + else + pExaScr->info->offScreenAreas->prev = area; xfree (next); + + pExaScr->numOffscreenAvailable--; } /** @@ -433,19 +470,19 @@ exaOffscreenFree (ScreenPtr pScreen, ExaOffscreenArea *area) if (area == pExaScr->info->offScreenAreas) prev = NULL; else - for (prev = pExaScr->info->offScreenAreas; prev; prev = prev->next) - if (prev->next == area) - break; + prev = area->prev; + + pExaScr->numOffscreenAvailable++; /* link with next area if free */ if (next && next->state == ExaOffscreenAvail) - ExaOffscreenMerge (area); + ExaOffscreenMerge (pExaScr, area); /* link with prev area if free */ if (prev && prev->state == ExaOffscreenAvail) { area = prev; - ExaOffscreenMerge (area); + ExaOffscreenMerge (pExaScr, area); } ExaOffscreenValidate (pScreen); @@ -466,6 +503,167 @@ ExaOffscreenMarkUsed (PixmapPtr pPixmap) } /** + * Defragment offscreen memory by compacting allocated areas at the end of it, + * leaving the total amount of memory available as a single area at the + * beginning (when there are no pinned allocations). + */ +_X_HIDDEN ExaOffscreenArea* +ExaOffscreenDefragment (ScreenPtr pScreen) +{ + ExaScreenPriv (pScreen); + ExaOffscreenArea *area, *largest_available = NULL; + int largest_size = 0; + PixmapPtr pDstPix; + ExaPixmapPrivPtr pExaDstPix; + + pDstPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, 0, 0); + + if (!pDstPix) + return NULL; + + pExaDstPix = ExaGetPixmapPriv (pDstPix); + pExaDstPix->offscreen = TRUE; + + for (area = pExaScr->info->offScreenAreas->prev; + area != pExaScr->info->offScreenAreas; + ) + { + ExaOffscreenArea *prev = area->prev; + PixmapPtr pSrcPix; + ExaPixmapPrivPtr pExaSrcPix; + Bool save_offscreen; + int save_pitch; + + if (area->state != ExaOffscreenAvail || + prev->state == ExaOffscreenLocked || + (prev->state == ExaOffscreenRemovable && + prev->save != exaPixmapSave)) { + area = prev; + continue; + } + + if (prev->state == ExaOffscreenAvail) { + if (area == largest_available) { + largest_available = prev; + largest_size += prev->size; + } + area = prev; + ExaOffscreenMerge (pExaScr, area); + continue; + } + + if (area->size > largest_size) { + largest_available = area; + largest_size = area->size; + } + + pSrcPix = prev->privData; + pExaSrcPix = ExaGetPixmapPriv (pSrcPix); + + pExaDstPix->fb_ptr = pExaScr->info->memoryBase + + area->base_offset + area->size - prev->size + prev->base_offset - + prev->offset; + pExaDstPix->fb_ptr -= (unsigned long)pExaDstPix->fb_ptr % prev->align; + + if (pExaDstPix->fb_ptr <= pExaSrcPix->fb_ptr) { + area = prev; + continue; + } + + if (!(pExaScr->info->flags & EXA_SUPPORTS_OFFSCREEN_OVERLAPS) && + (pExaSrcPix->fb_ptr + prev->size) > pExaDstPix->fb_ptr) { + area = prev; + continue; + } + + save_offscreen = pExaSrcPix->offscreen; + save_pitch = pSrcPix->devKind; + + pExaSrcPix->offscreen = TRUE; + pSrcPix->devKind = pExaSrcPix->fb_pitch; + + pDstPix->drawable.width = pSrcPix->drawable.width; + pDstPix->devKind = pSrcPix->devKind; + pDstPix->drawable.height = pSrcPix->drawable.height; + pDstPix->drawable.depth = pSrcPix->drawable.depth; + pDstPix->drawable.bitsPerPixel = pSrcPix->drawable.bitsPerPixel; + + if (!pExaScr->info->PrepareCopy (pSrcPix, pDstPix, -1, -1, GXcopy, ~0)) { + pExaSrcPix->offscreen = save_offscreen; + pSrcPix->devKind = save_pitch; + area = prev; + continue; + } + + pExaScr->info->Copy (pDstPix, 0, 0, 0, 0, pDstPix->drawable.width, + pDstPix->drawable.height); + pExaScr->info->DoneCopy (pDstPix); + exaMarkSync (pScreen); + + DBG_OFFSCREEN(("Before swap: prev=0x%08x-0x%08x-0x%08x area=0x%08x-0x%08x-0x%08x\n", + prev->base_offset, prev->offset, prev->base_offset + prev->size, + area->base_offset, area->offset, area->base_offset + area->size)); + + /* Calculate swapped area offsets and sizes */ + area->base_offset = prev->base_offset; + area->offset = area->base_offset; + prev->offset += pExaDstPix->fb_ptr - pExaSrcPix->fb_ptr; + assert(prev->offset >= pExaScr->info->offScreenBase && + prev->offset < pExaScr->info->memorySize); + prev->base_offset = prev->offset; + if (area->next) + prev->size = area->next->base_offset - prev->base_offset; + else + prev->size = pExaScr->info->memorySize - prev->base_offset; + area->size = prev->base_offset - area->base_offset; + + DBG_OFFSCREEN(("After swap: area=0x%08x-0x%08x-0x%08x prev=0x%08x-0x%08x-0x%08x\n", + area->base_offset, area->offset, area->base_offset + area->size, + prev->base_offset, prev->offset, prev->base_offset + prev->size)); + + /* Swap areas in list */ + if (area->next) + area->next->prev = prev; + else + pExaScr->info->offScreenAreas->prev = prev; + if (prev->prev->next) + prev->prev->next = area; + else + pExaScr->info->offScreenAreas = area; + prev->next = area->next; + area->next = prev; + area->prev = prev->prev; + prev->prev = area; + if (!area->prev->next) + pExaScr->info->offScreenAreas = area; + +#if DEBUG_OFFSCREEN + if (prev->prev == prev || prev->next == prev) + ErrorF("Whoops, prev points to itself!\n"); + + if (area->prev == area || area->next == area) + ErrorF("Whoops, area points to itself!\n"); +#endif + + pExaSrcPix->fb_ptr = pExaDstPix->fb_ptr; + pExaSrcPix->offscreen = save_offscreen; + pSrcPix->devKind = save_pitch; + } + + pDstPix->drawable.width = 0; + pDstPix->drawable.height = 0; + pDstPix->drawable.depth = 0; + pDstPix->drawable.bitsPerPixel = 0; + + (*pScreen->DestroyPixmap) (pDstPix); + + if (area->state == ExaOffscreenAvail && area->size > largest_size) + return area; + + return largest_available; +} + +/** * exaOffscreenInit initializes the offscreen memory manager. * * @param pScreen current screen @@ -488,15 +686,18 @@ exaOffscreenInit (ScreenPtr pScreen) area->state = ExaOffscreenAvail; area->base_offset = pExaScr->info->offScreenBase; area->offset = area->base_offset; + area->align = 0; area->size = pExaScr->info->memorySize - area->base_offset; area->save = NULL; area->next = NULL; + area->prev = area; area->last_use = 0; area->eviction_cost = 0; /* Add it to the free areas */ pExaScr->info->offScreenAreas = area; pExaScr->offScreenCounter = 1; + pExaScr->numOffscreenAvailable = 1; ExaOffscreenValidate (pScreen); diff --git a/xorg-server/exa/exa_priv.h b/xorg-server/exa/exa_priv.h index 0911c6d8a..869cf1772 100644 --- a/xorg-server/exa/exa_priv.h +++ b/xorg-server/exa/exa_priv.h @@ -33,7 +33,6 @@ #include "exa.h" #include <X11/X.h> -#define NEED_EVENTS #include <X11/Xproto.h> #ifdef MITSHM #include "shmint.h" @@ -86,6 +85,18 @@ exaDrawableLocation(DrawablePtr pDrawable); #define EXA_MAX_FB FB_OVERLAY_MAX #endif +#ifdef DEBUG +#define EXA_FatalErrorDebug(x) FatalError x +#define EXA_FatalErrorDebugWithRet(x, ret) FatalError x +#else +#define EXA_FatalErrorDebug(x) ErrorF x +#define EXA_FatalErrorDebugWithRet(x, ret) \ +do { \ + ErrorF x; \ + return ret; \ +} while (0) +#endif + /** * This is the list of migration heuristics supported by EXA. See * exaDoMigration() for what their implementations do. @@ -128,9 +139,21 @@ typedef struct { #define EXA_NUM_GLYPH_CACHES 4 +#define EXA_FALLBACK_COPYWINDOW (1 << 0) +#define EXA_ACCEL_COPYWINDOW (1 << 1) + +typedef struct _ExaMigrationRec { + Bool as_dst; + Bool as_src; + PixmapPtr pPix; + RegionPtr pReg; +} ExaMigrationRec, *ExaMigrationPtr; + typedef void (*EnableDisableFBAccessProcPtr)(int, Bool); typedef struct { ExaDriverPtr info; + ScreenBlockHandlerProcPtr SavedBlockHandler; + ScreenWakeupHandlerProcPtr SavedWakeupHandler; CreateGCProcPtr SavedCreateGC; CloseScreenProcPtr SavedCloseScreen; GetImageProcPtr SavedGetImage; @@ -149,13 +172,29 @@ 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; unsigned disableFbCount; Bool optimize_migration; unsigned offScreenCounter; + unsigned numOffscreenAvailable; + CARD32 lastDefragment; + CARD32 nextDefragment; + + /* 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; ExaGlyphCacheRec glyphCaches[EXA_NUM_GLYPH_CACHES]; } ExaScreenPrivRec, *ExaScreenPrivPtr; @@ -174,9 +213,40 @@ typedef struct { extern DevPrivateKey exaScreenPrivateKey; extern DevPrivateKey exaPixmapPrivateKey; +extern DevPrivateKey exaGCPrivateKey; #define ExaGetScreenPriv(s) ((ExaScreenPrivPtr)dixLookupPrivate(&(s)->devPrivates, exaScreenPrivateKey)) #define ExaScreenPriv(s) ExaScreenPrivPtr pExaScr = ExaGetScreenPriv(s) +#define ExaGetGCPriv(gc) ((ExaGCPrivPtr)dixLookupPrivate(&(gc)->devPrivates, exaGCPrivateKey)) +#define ExaGCPriv(gc) ExaGCPrivPtr pExaGC = ExaGetGCPriv(gc) + +/* + * Some macros to deal with function wrapping. + */ +#define wrap(priv, real, mem, func) {\ + priv->Saved##mem = real->mem; \ + real->mem = func; \ +} + +#define unwrap(priv, real, mem) {\ + real->mem = priv->Saved##mem; \ +} + +#define swap(priv, real, mem) {\ + void *tmp = priv->Saved##mem; \ + priv->Saved##mem = real->mem; \ + real->mem = tmp; \ +} + +#define EXA_GC_PROLOGUE(_gc_) \ + ExaGCPriv(_gc_); \ + swap(pExaGC, _gc_, funcs); \ + swap(pExaGC, _gc_, ops); + +#define EXA_GC_EPILOGUE(_gc_) \ + swap(pExaGC, _gc_, funcs); \ + swap(pExaGC, _gc_, ops); + /** Align an offset to an arbitrary alignment */ #define EXA_ALIGN(offset, align) (((offset) + (align) - 1) - \ (((offset) + (align) - 1) % (align))) @@ -237,17 +307,19 @@ typedef struct { */ void *driverPriv; } ExaPixmapPrivRec, *ExaPixmapPrivPtr; - -typedef struct _ExaMigrationRec { - Bool as_dst; - Bool as_src; - PixmapPtr pPix; - RegionPtr pReg; -} ExaMigrationRec, *ExaMigrationPtr; typedef struct { + /* GC values from the layer below. */ + GCOps *Savedops; + GCFuncs *Savedfuncs; +} ExaGCPrivRec, *ExaGCPrivPtr; + +typedef struct { + PicturePtr pDst; INT16 xSrc; INT16 ySrc; + INT16 xMask; + INT16 yMask; INT16 xDst; INT16 yDst; INT16 width; @@ -280,6 +352,11 @@ ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int leftPad, int format, char *bits); +void +ExaCheckCopyNtoN (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + BoxPtr pbox, int nbox, int dx, int dy, Bool reverse, + Bool upsidedown, Pixel bitplane, void *closure); + RegionPtr ExaCheckCopyArea (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty); @@ -325,6 +402,13 @@ ExaCheckPushPixels (GCPtr pGC, PixmapPtr pBitmap, int w, int h, int x, int y); void +ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc); + +void +ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *d); + +void ExaCheckGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, @@ -363,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 @@ -388,6 +500,9 @@ ExaOffscreenSwapOut (ScreenPtr pScreen); void ExaOffscreenSwapIn (ScreenPtr pScreen); +ExaOffscreenArea* +ExaOffscreenDefragment (ScreenPtr pScreen); + Bool exaOffscreenInit(ScreenPtr pScreen); @@ -395,7 +510,7 @@ void ExaOffscreenFini (ScreenPtr pScreen); /* exa.c */ -void +Bool ExaDoPrepareAccess(DrawablePtr pDrawable, int index); void @@ -423,22 +538,76 @@ 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); void -exaCopyNtoN (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - GCPtr pGC, - BoxPtr pbox, - int nbox, - int dx, - int dy, - Bool reverse, - Bool upsidedown, - Pixel bitplane, - void *closure); +exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap, + int w, int h, int bpp); + +void +exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel); + +Bool +exaPixmapIsPinned (PixmapPtr pPix); + +extern const GCFuncs exaGCFuncs; + +/* exa_classic.c */ +PixmapPtr +exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint); + +Bool +exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, 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 @@ -461,6 +630,7 @@ exaComposite(CARD8 op, void exaCompositeRects(CARD8 op, PicturePtr Src, + PicturePtr pMask, PicturePtr pDst, int nrect, ExaCompositeRectPtr rects); @@ -493,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/xorg-server/exa/exa_render.c b/xorg-server/exa/exa_render.c index 9a79b4781..1ac29f233 100644 --- a/xorg-server/exa/exa_render.c +++ b/xorg-server/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; @@ -158,12 +164,18 @@ exaGetPixelFromRGBA(CARD32 *pixel, gshift = bbits; rshift = gshift + gbits; ashift = rshift + rbits; - } else { /* PICT_TYPE_ABGR */ + } else if(PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { rshift = 0; gshift = rbits; bshift = gshift + gbits; ashift = bshift + bbits; - } + } else if(PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { + bshift = PICT_FORMAT_BPP(format) - bbits; + gshift = bshift - gbits; + rshift = gshift - rbits; + ashift = 0; + } else + return FALSE; *pixel |= ( blue >> (16 - bbits)) << bshift; *pixel |= ( red >> (16 - rbits)) << rshift; @@ -197,12 +209,18 @@ exaGetRGBAFromPixel(CARD32 pixel, gshift = bbits; rshift = gshift + gbits; ashift = rshift + rbits; - } else { /* PICT_TYPE_ABGR */ + } else if(PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { rshift = 0; gshift = rbits; bshift = gshift + gbits; ashift = bshift + bbits; - } + } else if(PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { + bshift = PICT_FORMAT_BPP(format) - bbits; + gshift = bshift - gbits; + rshift = gshift - rbits; + ashift = 0; + } else + return FALSE; *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); while (rbits < 16) { @@ -253,7 +271,6 @@ exaTryDriverSolidFill(PicturePtr pSrc, ExaPixmapPrivPtr pSrcExaPix, pDstExaPix; CARD32 pixel; CARD16 red, green, blue, alpha; - ExaMigrationRec pixmaps[1]; pDstPix = exaGetDrawablePixmap (pDst->pDrawable); pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); @@ -284,11 +301,15 @@ exaTryDriverSolidFill(PicturePtr pSrc, 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 (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); @@ -334,16 +355,15 @@ exaTryDriverSolidFill(PicturePtr pSrc, static int exaTryDriverCompositeRects(CARD8 op, PicturePtr pSrc, + PicturePtr pMask, PicturePtr pDst, int nrect, ExaCompositeRectPtr rects) { ExaScreenPriv (pDst->pDrawable->pScreen); - int src_off_x, src_off_y, dst_off_x, dst_off_y; - PixmapPtr pSrcPix, pDstPix; - ExaPixmapPrivPtr pSrcExaPix, pDstExaPix; - struct _Pixmap scratch; - ExaMigrationRec pixmaps[2]; + 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; if (!pExaScr->info->PrepareComposite) return -1; @@ -351,6 +371,11 @@ exaTryDriverCompositeRects(CARD8 op, pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + if (pMask) { + pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); + pMaskExaPix = ExaGetPixmapPriv(pMaskPix); + } + pDstPix = exaGetDrawablePixmap(pDst->pDrawable); pDstExaPix = ExaGetPixmapPriv(pDstPix); @@ -358,61 +383,74 @@ exaTryDriverCompositeRects(CARD8 op, * FIXME: If it cannot, use temporary pixmaps so that the drawing * happens within limits. */ - if (pSrcExaPix->accel_blocked || - pDstExaPix->accel_blocked) + if (pSrcExaPix->accel_blocked || pDstExaPix->accel_blocked || + (pMask && pMaskExaPix->accel_blocked)) { return -1; } if (pExaScr->info->CheckComposite && - !(*pExaScr->info->CheckComposite) (op, pSrc, NULL, pDst)) + !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) { return -1; } - - exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); - 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; - exaDoMigration(pixmaps, 2, TRUE); + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[3]; + + 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); + } - pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); - if (!exaPixmapIsOffscreen(pDstPix)) + pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); + if (!pDstPix) return 0; - if (!pSrcPix && pExaScr->info->UploadToScratch) - { - pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); - if ((*pExaScr->info->UploadToScratch) (pSrcPix, &scratch)) - pSrcPix = &scratch; - } + pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); if (!pSrcPix) return 0; - if (!(*pExaScr->info->PrepareComposite) (op, pSrc, NULL, pDst, pSrcPix, - NULL, pDstPix)) + if (pMask) { + pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, &mask_off_y); + + if (!pMaskPix) + return 0; + } + + if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, + pMaskPix, pDstPix)) return -1; while (nrect--) { 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; RegionRec region; BoxPtr pbox; int nbox; - - if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, - xSrc, ySrc, 0, 0, xDst, yDst, + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, rects->width, rects->height)) goto next_rect; @@ -421,6 +459,8 @@ exaTryDriverCompositeRects(CARD8 op, nbox = REGION_NUM_RECTS(®ion); pbox = REGION_RECTS(®ion); + xMask = xMask + mask_off_x - xDst - dst_off_x; + yMask = yMask + mask_off_y - yDst - dst_off_y; xSrc = xSrc + src_off_x - xDst - dst_off_x; ySrc = ySrc + src_off_y - yDst - dst_off_y; @@ -429,7 +469,8 @@ exaTryDriverCompositeRects(CARD8 op, (*pExaScr->info->Composite) (pDstPix, pbox->x1 + xSrc, pbox->y1 + ySrc, - 0, 0, + pbox->x1 + xMask, + pbox->y1 + yMask, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, @@ -451,25 +492,28 @@ exaTryDriverCompositeRects(CARD8 op, /** * Copy a number of rectangles from source to destination in a single - * operation. This is specialized for building a glyph mask: we don'y - * have a mask argument because we don't need it for that, and we - * don't have he special-case fallbacks found in exaComposite() - if the - * driver can support it, we use the driver functionality, otherwise we - * fallback straight to software. + * operation. This is specialized for glyph rendering: we don't have the + * special-case fallbacks found in exaComposite() - if the driver can support + * it, we use the driver functionality, otherwise we fall back straight to + * software. */ void exaCompositeRects(CARD8 op, PicturePtr pSrc, + PicturePtr pMask, PicturePtr pDst, int nrect, ExaCompositeRectPtr rects) { - PixmapPtr pPixmap = exaGetDrawablePixmap(pDst->pDrawable); - ExaPixmapPriv(pPixmap); + ExaScreenPriv (pDst->pDrawable->pScreen); int n; ExaCompositeRectPtr r; - - if (pExaPixmap->pDamage) { + int ret; + + /* 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) { RegionRec region; int x1 = MAXSHORT; int y1 = MAXSHORT; @@ -526,24 +570,44 @@ exaCompositeRects(CARD8 op, /************************************************************/ ValidatePicture (pSrc); + if (pMask) + ValidatePicture (pMask); ValidatePicture (pDst); - - if (exaTryDriverCompositeRects(op, pSrc, pDst, nrect, rects) != 1) { - n = nrect; - r = rects; - while (n--) { - ExaCheckComposite (op, pSrc, NULL, pDst, - r->xSrc, r->ySrc, - 0, 0, - r->xDst, r->yDst, - r->width, r->height); - r++; + + ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects); + + if (ret != 1) { + if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha && + (!pExaScr->info->CheckComposite || + ((*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, + pDst) && + (*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))) { + ret = exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask, + pDst, nrect, rects); + if (ret == 1) { + op = PictOpAdd; + ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, + rects); + } + } + + if (ret != 1) { + n = nrect; + r = rects; + while (n--) { + ExaCheckComposite (op, pSrc, pMask, pDst, + r->xSrc, r->ySrc, + r->xMask, r->yMask, + r->xDst, r->yDst, + r->width, r->height); + r++; + } } } /************************************************************/ - if (pExaPixmap->pDamage) { + if (!pMask) { /* Now we have to flush the damage out from pendingDamage => damage * Calling DamageRegionProcessPending has that effect. */ @@ -573,8 +637,6 @@ exaTryDriverComposite(CARD8 op, 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; - struct _Pixmap scratch; - ExaMigrationRec pixmaps[3]; pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); pSrcExaPix = ExaGetPixmapPriv(pSrcPix); @@ -624,22 +686,25 @@ 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]; + + 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); } pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); @@ -652,16 +717,6 @@ exaTryDriverComposite(CARD8 op, return 0; } - if (!pSrcPix && (!pMask || pMaskPix) && pExaScr->info->UploadToScratch) { - pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); - if ((*pExaScr->info->UploadToScratch) (pSrcPix, &scratch)) - pSrcPix = &scratch; - } else if (pSrcPix && pMask && !pMaskPix && pExaScr->info->UploadToScratch) { - pMaskPix = exaGetDrawablePixmap (pMask->pDrawable); - if ((*pExaScr->info->UploadToScratch) (pMaskPix, &scratch)) - pMaskPix = &scratch; - } - if (!pSrcPix || (pMask && !pMaskPix)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return 0; @@ -832,11 +887,13 @@ exaComposite(CARD8 op, { if ((op == PictOpSrc && ((pSrc->format == pDst->format) || + (pSrc->format==PICT_b8g8r8a8 && pDst->format==PICT_b8g8r8x8) || (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))) + (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8 || + pSrc->format==PICT_b8g8r8x8))) { if (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && @@ -851,6 +908,7 @@ exaComposite(CARD8 op, !pSrc->repeat && !pSrc->transform) { + Bool ret; xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; xSrc += pSrc->pDrawable->x; @@ -861,12 +919,20 @@ exaComposite(CARD8 op, yDst, width, height)) goto done; - - exaCopyNtoN (pSrc->pDrawable, pDst->pDrawable, NULL, + ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL, REGION_RECTS(®ion), REGION_NUM_RECTS(®ion), - xSrc - xDst, ySrc - yDst, - FALSE, FALSE, 0, NULL); + xSrc - xDst, ySrc - yDst, FALSE, FALSE); REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + /* Reset values to their original values. */ + xDst -= pDst->pDrawable->x; + yDst -= pDst->pDrawable->y; + xSrc -= pSrc->pDrawable->x; + ySrc -= pSrc->pDrawable->y; + + if (!ret) + goto fallback; + goto done; } else if (pSrc->pDrawable != NULL && @@ -1054,15 +1120,15 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, BoxRec bounds; if (maskFormat) { + PicturePtr pPicture; + INT16 xDst, yDst; + INT16 xRel, yRel; + miTrapezoidBounds (ntrap, traps, &bounds); if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) return; - PicturePtr pPicture; - INT16 xDst, yDst; - INT16 xRel, yRel; - xDst = traps[0].left.p1.x >> 16; yDst = traps[0].left.p1.y >> 16; @@ -1118,15 +1184,15 @@ exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, BoxRec bounds; if (maskFormat) { + PicturePtr pPicture; + INT16 xDst, yDst; + INT16 xRel, yRel; + miTriangleBounds (ntri, tris, &bounds); if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) return; - PicturePtr pPicture; - INT16 xDst, yDst; - INT16 xRel, yRel; - xDst = tris[0].p1.x >> 16; yDst = tris[0].p1.y >> 16; diff --git a/xorg-server/exa/exa_unaccel.c b/xorg-server/exa/exa_unaccel.c index a515bac1f..f4700adac 100644 --- a/xorg-server/exa/exa_unaccel.c +++ b/xorg-server/exa/exa_unaccel.c @@ -74,22 +74,26 @@ void ExaCheckFillSpans (DrawablePtr pDrawable, GCPtr pGC, int nspans, DDXPointPtr ppt, int *pwidth, int fSorted) { + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC (pGC); - fbFillSpans (pDrawable, pGC, nspans, ppt, pwidth, fSorted); + pGC->ops->FillSpans (pDrawable, pGC, nspans, ppt, pwidth, fSorted); exaFinishAccessGC (pGC); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); } void ExaCheckSetSpans (DrawablePtr pDrawable, GCPtr pGC, char *psrc, DDXPointPtr ppt, int *pwidth, int nspans, int fSorted) { + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); - fbSetSpans (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); + pGC->ops->SetSpans (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); } void @@ -99,6 +103,7 @@ ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, { ExaPixmapPriv(exaGetDrawablePixmap(pDrawable)); + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); if (exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle, pGC->alu, pGC->clientClipType)) @@ -106,8 +111,30 @@ ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, else exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pExaPixmap->pDamage ? DamagePendingRegion(pExaPixmap->pDamage) : NULL); - fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); + pGC->ops->PutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); +} + +void +ExaCheckCopyNtoN (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + BoxPtr pbox, int nbox, int dx, int dy, Bool reverse, + Bool upsidedown, Pixel bitplane, void *closure) +{ + EXA_GC_PROLOGUE(pGC); + EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst, + exaDrawableLocation(pSrc), exaDrawableLocation(pDst))); + exaPrepareAccess (pDst, EXA_PREPARE_DEST); + exaPrepareAccess (pSrc, EXA_PREPARE_SRC); + /* This will eventually call fbCopyNtoN, with some calculation overhead. */ + while (nbox--) { + pGC->ops->CopyArea (pSrc, pDst, pGC, pbox->x1 - pSrc->x + dx, pbox->y1 - pSrc->y + dy, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, pbox->x1 - pDst->x, pbox->y1 - pDst->y); + pbox++; + } + exaFinishAccess (pSrc, EXA_PREPARE_SRC); + exaFinishAccess (pDst, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); } RegionPtr @@ -116,13 +143,15 @@ ExaCheckCopyArea (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, { RegionPtr ret; + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst, exaDrawableLocation(pSrc), exaDrawableLocation(pDst))); exaPrepareAccess (pDst, EXA_PREPARE_DEST); exaPrepareAccess (pSrc, EXA_PREPARE_SRC); - ret = fbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); + ret = pGC->ops->CopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); exaFinishAccess (pSrc, EXA_PREPARE_SRC); exaFinishAccess (pDst, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); return ret; } @@ -134,14 +163,16 @@ ExaCheckCopyPlane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, { RegionPtr ret; + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst, exaDrawableLocation(pSrc), exaDrawableLocation(pDst))); exaPrepareAccess (pDst, EXA_PREPARE_DEST); exaPrepareAccess (pSrc, EXA_PREPARE_SRC); - ret = fbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, + ret = pGC->ops->CopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, bitPlane); exaFinishAccess (pSrc, EXA_PREPARE_SRC); exaFinishAccess (pDst, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); return ret; } @@ -150,85 +181,75 @@ void ExaCheckPolyPoint (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr pptInit) { + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); - fbPolyPoint (pDrawable, pGC, mode, npt, pptInit); + pGC->ops->PolyPoint (pDrawable, pGC, mode, npt, pptInit); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); } void ExaCheckPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppt) { + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n", pDrawable, exaDrawableLocation(pDrawable), pGC->lineWidth, mode, npt)); - if (pGC->lineWidth == 0) { - exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); - exaPrepareAccessGC (pGC); - fbPolyLine (pDrawable, pGC, mode, npt, ppt); - exaFinishAccessGC (pGC); - exaFinishAccess (pDrawable, EXA_PREPARE_DEST); - return; - } - /* fb calls mi functions in the lineWidth != 0 case. */ - fbPolyLine (pDrawable, pGC, mode, npt, ppt); + exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); + exaPrepareAccessGC (pGC); + pGC->ops->Polylines (pDrawable, pGC, mode, npt, ppt); + exaFinishAccessGC (pGC); + exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); } void ExaCheckPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nsegInit, xSegment *pSegInit) { + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable, exaDrawableLocation(pDrawable), pGC->lineWidth, nsegInit)); - if (pGC->lineWidth == 0) { - exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); - exaPrepareAccessGC (pGC); - fbPolySegment (pDrawable, pGC, nsegInit, pSegInit); - exaFinishAccessGC (pGC); - exaFinishAccess (pDrawable, EXA_PREPARE_DEST); - return; - } - /* fb calls mi functions in the lineWidth != 0 case. */ - fbPolySegment (pDrawable, pGC, nsegInit, pSegInit); + + exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); + exaPrepareAccessGC (pGC); + pGC->ops->PolySegment (pDrawable, pGC, nsegInit, pSegInit); + exaFinishAccessGC (pGC); + exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); } void ExaCheckPolyArc (DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *pArcs) { + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); - /* Disable this as fbPolyArc can call miZeroPolyArc which in turn - * can call accelerated functions, that as yet, haven't been notified - * with exaFinishAccess(). - */ -#if 0 - if (pGC->lineWidth == 0) - { - exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); - exaPrepareAccessGC (pGC); - fbPolyArc (pDrawable, pGC, narcs, pArcs); - exaFinishAccessGC (pGC); - exaFinishAccess (pDrawable, EXA_PREPARE_DEST); - return; - } -#endif - miPolyArc (pDrawable, pGC, narcs, pArcs); + exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); + exaPrepareAccessGC (pGC); + pGC->ops->PolyArc (pDrawable, pGC, narcs, pArcs); + exaFinishAccessGC (pGC); + exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); } void ExaCheckPolyFillRect (DrawablePtr pDrawable, GCPtr pGC, int nrect, xRectangle *prect) { + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC (pGC); - fbPolyFillRect (pDrawable, pGC, nrect, prect); + pGC->ops->PolyFillRect (pDrawable, pGC, nrect, prect); exaFinishAccessGC (pGC); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); } void @@ -236,13 +257,15 @@ ExaCheckImageGlyphBlt (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase) { + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC (pGC); - fbImageGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + pGC->ops->ImageGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); exaFinishAccessGC (pGC); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); } void @@ -250,13 +273,15 @@ ExaCheckPolyGlyphBlt (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase) { + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable, exaDrawableLocation(pDrawable), pGC->fillStyle, pGC->alu)); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC (pGC); - fbPolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + pGC->ops->PolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); exaFinishAccessGC (pGC); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); } void @@ -264,16 +289,64 @@ ExaCheckPushPixels (GCPtr pGC, PixmapPtr pBitmap, DrawablePtr pDrawable, int w, int h, int x, int y) { + EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable, exaDrawableLocation(&pBitmap->drawable), exaDrawableLocation(pDrawable))); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccess (&pBitmap->drawable, EXA_PREPARE_SRC); exaPrepareAccessGC (pGC); - fbPushPixels (pGC, pBitmap, pDrawable, w, h, x, y); + pGC->ops->PushPixels (pGC, pBitmap, pDrawable, w, h, x, y); exaFinishAccessGC (pGC); exaFinishAccess (&pBitmap->drawable, EXA_PREPARE_SRC); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_GC_EPILOGUE(pGC); +} + +void +ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + DrawablePtr pDrawable = &pWin->drawable; + ScreenPtr pScreen = pDrawable->pScreen; + ExaScreenPriv(pScreen); + EXA_FALLBACK(("from %p\n", pWin)); + + /* being both src and dest, src is safest. */ + exaPrepareAccess(pDrawable, EXA_PREPARE_SRC); + swap(pExaScr, pScreen, CopyWindow); + pScreen->CopyWindow (pWin, ptOldOrg, prgnSrc); + swap(pExaScr, pScreen, CopyWindow); + exaFinishAccess (pDrawable, EXA_PREPARE_SRC); +} + +void +ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *d) +{ + BoxRec Box; + RegionRec Reg; + int xoff, yoff; + ScreenPtr pScreen = pDrawable->pScreen; + PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); + ExaScreenPriv(pScreen); + + EXA_FALLBACK(("from %p (%c)\n", pDrawable, + exaDrawableLocation(pDrawable))); + + 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; + + REGION_INIT(pScreen, &Reg, &Box, 1); + + exaPrepareAccessReg (pDrawable, EXA_PREPARE_SRC, &Reg); + swap(pExaScr, pScreen, GetImage); + pScreen->GetImage (pDrawable, x, y, w, h, format, planeMask, d); + swap(pExaScr, pScreen, GetImage); + exaFinishAccess (pDrawable, EXA_PREPARE_SRC); } void @@ -284,9 +357,14 @@ ExaCheckGetSpans (DrawablePtr pDrawable, int nspans, char *pdstStart) { + ScreenPtr pScreen = pDrawable->pScreen; + ExaScreenPriv(pScreen); + EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess (pDrawable, EXA_PREPARE_SRC); - fbGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + swap(pExaScr, pScreen, GetSpans); + pScreen->GetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + swap(pExaScr, pScreen, GetSpans); exaFinishAccess (pDrawable, EXA_PREPARE_SRC); } @@ -304,6 +382,11 @@ ExaCheckComposite (CARD8 op, CARD16 width, CARD16 height) { + ScreenPtr pScreen = pDst->pDrawable->pScreen; +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreen(pScreen); +#endif /* RENDER */ + ExaScreenPriv(pScreen); RegionRec region; int xoff, yoff; @@ -314,15 +397,15 @@ ExaCheckComposite (CARD8 op, * may be used for moving them out. */ if (pSrc->alphaMap && pSrc->alphaMap->pDrawable) - exaPrepareAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX2); + exaPrepareAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC); if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable) - exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX1); + exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK); if (!exaOpReadsDestination(op)) { if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height)) - return; + goto skip; exaGetDrawableDeltas (pDst->pDrawable, exaGetDrawablePixmap(pDst->pDrawable), @@ -331,13 +414,13 @@ ExaCheckComposite (CARD8 op, REGION_TRANSLATE(pScreen, ®ion, xoff, yoff); if (pDst->alphaMap && pDst->alphaMap->pDrawable) - exaPrepareAccessReg(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX0, + exaPrepareAccessReg(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST, ®ion); exaPrepareAccessReg (pDst->pDrawable, EXA_PREPARE_DEST, ®ion); } else { if (pDst->alphaMap && pDst->alphaMap->pDrawable) - exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX0); + exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST); exaPrepareAccess (pDst->pDrawable, EXA_PREPARE_DEST); } @@ -349,7 +432,9 @@ ExaCheckComposite (CARD8 op, exaPrepareAccess (pSrc->pDrawable, EXA_PREPARE_SRC); if (pMask && pMask->pDrawable != NULL) exaPrepareAccess (pMask->pDrawable, EXA_PREPARE_MASK); - fbComposite (op, +#ifdef RENDER + swap(pExaScr, ps, Composite); + ps->Composite (op, pSrc, pMask, pDst, @@ -361,17 +446,21 @@ ExaCheckComposite (CARD8 op, yDst, width, height); + swap(pExaScr, ps, Composite); +#endif /* RENDER */ if (pMask && pMask->pDrawable != NULL) exaFinishAccess (pMask->pDrawable, EXA_PREPARE_MASK); - if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable) - exaFinishAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX1); if (pSrc->pDrawable != NULL) exaFinishAccess (pSrc->pDrawable, EXA_PREPARE_SRC); - if (pSrc->alphaMap && pSrc->alphaMap->pDrawable) - exaFinishAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX2); exaFinishAccess (pDst->pDrawable, EXA_PREPARE_DEST); if (pDst->alphaMap && pDst->alphaMap->pDrawable) - exaFinishAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX0); + exaFinishAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST); + +skip: + if (pSrc->alphaMap && pSrc->alphaMap->pDrawable) + exaFinishAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC); + if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable) + exaFinishAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK); REGION_UNINIT(pScreen, ®ion); } @@ -383,68 +472,57 @@ ExaCheckAddTraps (PicturePtr pPicture, int ntrap, xTrap *traps) { + ScreenPtr pScreen = pPicture->pDrawable->pScreen; +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreen(pScreen); +#endif /* RENDER */ + ExaScreenPriv(pScreen); + EXA_FALLBACK(("to pict %p (%c)\n", exaDrawableLocation(pPicture->pDrawable))); exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); - fbAddTraps (pPicture, x_off, y_off, ntrap, traps); +#ifdef RENDER + swap(pExaScr, ps, AddTraps); + ps->AddTraps (pPicture, x_off, y_off, ntrap, traps); + swap(pExaScr, ps, AddTraps); +#endif /* RENDER */ exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); } /** * 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; - } - - if (need_finish) { - exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); - REGION_UNINIT(pScreen, &migration); + FatalError("%s called for invalid bpp %d\n", __func__, + pPixmap->drawable.bitsPerPixel); } - - return pixel; } |