diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2010-07-27 19:02:39 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2010-07-27 19:02:39 +0000 |
commit | 269d40cbcc43b41f621ca6d91c182952f60ec48e (patch) | |
tree | 872f2fddd3f2207e57a28595e73886713ce4a77a /xserver/exa | |
parent | 917a2249b787451cad3f9697872aeccfd0da3324 (diff) |
Update to xserver 1.8. Tested by many. Ok oga@, todd@.
Diffstat (limited to 'xserver/exa')
-rw-r--r-- | xserver/exa/Makefile.am | 7 | ||||
-rw-r--r-- | xserver/exa/Makefile.in | 112 | ||||
-rw-r--r-- | xserver/exa/exa.c | 929 | ||||
-rw-r--r-- | xserver/exa/exa.h | 121 | ||||
-rw-r--r-- | xserver/exa/exa_accel.c | 382 | ||||
-rw-r--r-- | xserver/exa/exa_classic.c | 267 | ||||
-rw-r--r-- | xserver/exa/exa_driver.c | 225 | ||||
-rw-r--r-- | xserver/exa/exa_glyphs.c | 363 | ||||
-rw-r--r-- | xserver/exa/exa_migration_classic.c (renamed from xserver/exa/exa_migration.c) | 199 | ||||
-rw-r--r-- | xserver/exa/exa_migration_mixed.c | 261 | ||||
-rw-r--r-- | xserver/exa/exa_mixed.c | 291 | ||||
-rw-r--r-- | xserver/exa/exa_offscreen.c | 226 | ||||
-rw-r--r-- | xserver/exa/exa_priv.h | 274 | ||||
-rw-r--r-- | xserver/exa/exa_render.c | 549 | ||||
-rw-r--r-- | xserver/exa/exa_unaccel.c | 596 |
15 files changed, 3421 insertions, 1381 deletions
diff --git a/xserver/exa/Makefile.am b/xserver/exa/Makefile.am index 2b3f1e416..8b759cd76 100644 --- a/xserver/exa/Makefile.am +++ b/xserver/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/xserver/exa/Makefile.in b/xserver/exa/Makefile.in index fbcf99abf..eb93398ad 100644 --- a/xserver/exa/Makefile.in +++ b/xserver/exa/Makefile.in @@ -41,8 +41,8 @@ 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)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(install_sh) -d @@ -52,14 +52,16 @@ 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 = 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. -I$(srcdir) -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ @@ -95,12 +97,13 @@ ALPHA_VIDEO_TRUE = @ALPHA_VIDEO_TRUE@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ APPLE_APPLICATIONS_DIR = @APPLE_APPLICATIONS_DIR@ -APPLE_APPLICATION_ID = @APPLE_APPLICATION_ID@ APPLE_APPLICATION_NAME = @APPLE_APPLICATION_NAME@ APP_MAN_DIR = @APP_MAN_DIR@ APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ AR = @AR@ +ARM_BACKTRACE_CFLAGS = @ARM_BACKTRACE_CFLAGS@ ARM_VIDEO_FALSE = @ARM_VIDEO_FALSE@ ARM_VIDEO_TRUE = @ARM_VIDEO_TRUE@ AS = @AS@ @@ -128,6 +131,7 @@ CCAS = @CCAS@ CCASFLAGS = @CCASFLAGS@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ +CHANGELOG_CMD = @CHANGELOG_CMD@ COMPILEDDEFAULTFONTPATH = @COMPILEDDEFAULTFONTPATH@ COMPOSITE_FALSE = @COMPOSITE_FALSE@ COMPOSITE_TRUE = @COMPOSITE_TRUE@ @@ -137,8 +141,11 @@ CONFIG_HAL_FALSE = @CONFIG_HAL_FALSE@ CONFIG_HAL_TRUE = @CONFIG_HAL_TRUE@ CONFIG_NEED_DBUS_FALSE = @CONFIG_NEED_DBUS_FALSE@ CONFIG_NEED_DBUS_TRUE = @CONFIG_NEED_DBUS_TRUE@ +CONFIG_UDEV_FALSE = @CONFIG_UDEV_FALSE@ +CONFIG_UDEV_TRUE = @CONFIG_UDEV_TRUE@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CWARNFLAGS = @CWARNFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ @@ -152,6 +159,7 @@ DBUS_LIBS = @DBUS_LIBS@ DEBUG_FALSE = @DEBUG_FALSE@ DEBUG_TRUE = @DEBUG_TRUE@ DEFAULT_LIBRARY_PATH = @DEFAULT_LIBRARY_PATH@ +DEFAULT_LOGDIR = @DEFAULT_LOGDIR@ DEFAULT_LOGPREFIX = @DEFAULT_LOGPREFIX@ DEFAULT_MODULE_PATH = @DEFAULT_MODULE_PATH@ DEFS = @DEFS@ @@ -161,7 +169,9 @@ DGA_FALSE = @DGA_FALSE@ DGA_LIBS = @DGA_LIBS@ DGA_TRUE = @DGA_TRUE@ DIX_CFLAGS = @DIX_CFLAGS@ +DIX_LIB = @DIX_LIB@ DLLTOOL = @DLLTOOL@ +DLOPEN_LIBS = @DLOPEN_LIBS@ DMXEXAMPLES_DEP_CFLAGS = @DMXEXAMPLES_DEP_CFLAGS@ DMXEXAMPLES_DEP_LIBS = @DMXEXAMPLES_DEP_LIBS@ DMXMODULES_CFLAGS = @DMXMODULES_CFLAGS@ @@ -177,6 +187,7 @@ DMX_BUILD_USB_TRUE = @DMX_BUILD_USB_TRUE@ DMX_FALSE = @DMX_FALSE@ DMX_TRUE = @DMX_TRUE@ DOLT_BASH = @DOLT_BASH@ +DOXYGEN = @DOXYGEN@ DPMSExtension_FALSE = @DPMSExtension_FALSE@ DPMSExtension_TRUE = @DPMSExtension_TRUE@ DRI2PROTO_CFLAGS = @DRI2PROTO_CFLAGS@ @@ -189,8 +200,10 @@ 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_FALSE = @DRI_FALSE@ +DRI_LIBS = @DRI_LIBS@ DRI_TRUE = @DRI_TRUE@ DSYMUTIL = @DSYMUTIL@ DTRACE = @DTRACE@ @@ -206,8 +219,17 @@ FBDEVHW_TRUE = @FBDEVHW_TRUE@ FFLAGS = @FFLAGS@ FILE_MAN_DIR = @FILE_MAN_DIR@ FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +FONT100DPIDIR = @FONT100DPIDIR@ +FONT75DPIDIR = @FONT75DPIDIR@ +FONTMISCDIR = @FONTMISCDIR@ +FONTOTFDIR = @FONTOTFDIR@ +FONTROOTDIR = @FONTROOTDIR@ +FONTTTFDIR = @FONTTTFDIR@ +FONTTYPE1DIR = @FONTTYPE1DIR@ FREEBSD_KLDLOAD_FALSE = @FREEBSD_KLDLOAD_FALSE@ FREEBSD_KLDLOAD_TRUE = @FREEBSD_KLDLOAD_TRUE@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ GLX_ARCH_DEFINES = @GLX_ARCH_DEFINES@ GLX_DEFINES = @GLX_DEFINES@ GLX_FALSE = @GLX_FALSE@ @@ -217,18 +239,17 @@ GL_LIBS = @GL_LIBS@ GREP = @GREP@ HAL_CFLAGS = @HAL_CFLAGS@ HAL_LIBS = @HAL_LIBS@ -HAVE_AGL_FRAMEWORK_FALSE = @HAVE_AGL_FRAMEWORK_FALSE@ -HAVE_AGL_FRAMEWORK_TRUE = @HAVE_AGL_FRAMEWORK_TRUE@ HAVE_DBUS_FALSE = @HAVE_DBUS_FALSE@ HAVE_DBUS_TRUE = @HAVE_DBUS_TRUE@ -HAVE_XPLUGIN_FALSE = @HAVE_XPLUGIN_FALSE@ -HAVE_XPLUGIN_TRUE = @HAVE_XPLUGIN_TRUE@ +HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@ +HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@ HP300_VIDEO_FALSE = @HP300_VIDEO_FALSE@ HP300_VIDEO_TRUE = @HP300_VIDEO_TRUE@ HPPA_VIDEO_FALSE = @HPPA_VIDEO_FALSE@ HPPA_VIDEO_TRUE = @HPPA_VIDEO_TRUE@ I386_VIDEO_FALSE = @I386_VIDEO_FALSE@ I386_VIDEO_TRUE = @I386_VIDEO_TRUE@ +INSTALL_CMD = @INSTALL_CMD@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_LIBXF86CONFIG_FALSE = @INSTALL_LIBXF86CONFIG_FALSE@ INSTALL_LIBXF86CONFIG_TRUE = @INSTALL_LIBXF86CONFIG_TRUE@ @@ -237,6 +258,8 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_SETUID_FALSE = @INSTALL_SETUID_FALSE@ INSTALL_SETUID_TRUE = @INSTALL_SETUID_TRUE@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INT10MODULE_FALSE = @INT10MODULE_FALSE@ +INT10MODULE_TRUE = @INT10MODULE_TRUE@ INT10_STUB_FALSE = @INT10_STUB_FALSE@ INT10_STUB_TRUE = @INT10_STUB_TRUE@ INT10_VM86_FALSE = @INT10_VM86_FALSE@ @@ -249,20 +272,23 @@ KDRIVELINUX_FALSE = @KDRIVELINUX_FALSE@ KDRIVELINUX_TRUE = @KDRIVELINUX_TRUE@ KDRIVEOPENBSD_FALSE = @KDRIVEOPENBSD_FALSE@ KDRIVEOPENBSD_TRUE = @KDRIVEOPENBSD_TRUE@ -KDRIVEVESA_FALSE = @KDRIVEVESA_FALSE@ -KDRIVEVESA_TRUE = @KDRIVEVESA_TRUE@ KDRIVEWSCONS_FALSE = @KDRIVEWSCONS_FALSE@ KDRIVEWSCONS_TRUE = @KDRIVEWSCONS_TRUE@ KDRIVE_CFLAGS = @KDRIVE_CFLAGS@ +KDRIVE_EVDEV_FALSE = @KDRIVE_EVDEV_FALSE@ +KDRIVE_EVDEV_TRUE = @KDRIVE_EVDEV_TRUE@ KDRIVE_FALSE = @KDRIVE_FALSE@ -KDRIVE_HW_FALSE = @KDRIVE_HW_FALSE@ -KDRIVE_HW_TRUE = @KDRIVE_HW_TRUE@ KDRIVE_INCS = @KDRIVE_INCS@ +KDRIVE_KBD_FALSE = @KDRIVE_KBD_FALSE@ +KDRIVE_KBD_TRUE = @KDRIVE_KBD_TRUE@ KDRIVE_LIBS = @KDRIVE_LIBS@ KDRIVE_LOCAL_LIBS = @KDRIVE_LOCAL_LIBS@ +KDRIVE_MOUSE_FALSE = @KDRIVE_MOUSE_FALSE@ +KDRIVE_MOUSE_TRUE = @KDRIVE_MOUSE_TRUE@ KDRIVE_PURE_INCS = @KDRIVE_PURE_INCS@ KDRIVE_PURE_LIBS = @KDRIVE_PURE_LIBS@ KDRIVE_TRUE = @KDRIVE_TRUE@ +LAUNCHD_ID_PREFIX = @LAUNCHD_ID_PREFIX@ LDFLAGS = @LDFLAGS@ LD_EXPORT_SYMBOLS_FLAG = @LD_EXPORT_SYMBOLS_FLAG@ LEX = @LEX@ @@ -291,12 +317,12 @@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAIN_LIB = @MAIN_LIB@ 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@ MITSHM_FALSE = @MITSHM_FALSE@ @@ -315,6 +341,9 @@ OBJCFLAGS = @OBJCFLAGS@ OBJCLINK = @OBJCLINK@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OS_LIB = @OS_LIB@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ @@ -343,10 +372,14 @@ SCREENSAVER_TRUE = @SCREENSAVER_TRUE@ SECURE_RPC_FALSE = @SECURE_RPC_FALSE@ SECURE_RPC_TRUE = @SECURE_RPC_TRUE@ SED = @SED@ +SELINUX_CFLAGS = @SELINUX_CFLAGS@ +SELINUX_LIBS = @SELINUX_LIBS@ SERVER_MISC_CONFIG_PATH = @SERVER_MISC_CONFIG_PATH@ SET_MAKE = @SET_MAKE@ SGI_VIDEO_FALSE = @SGI_VIDEO_FALSE@ SGI_VIDEO_TRUE = @SGI_VIDEO_TRUE@ +SHA1_CFLAGS = @SHA1_CFLAGS@ +SHA1_LIBS = @SHA1_LIBS@ SHELL = @SHELL@ # Override these since EXA doesn't need them and the needed files aren't @@ -355,25 +388,38 @@ SOLARIS_ASM_CFLAGS = "" SOLARIS_ASM_INLINE_FALSE = @SOLARIS_ASM_INLINE_FALSE@ SOLARIS_ASM_INLINE_TRUE = @SOLARIS_ASM_INLINE_TRUE@ SOLARIS_INOUT_ARCH = @SOLARIS_INOUT_ARCH@ -SOLARIS_USL_CONSOLE_FALSE = @SOLARIS_USL_CONSOLE_FALSE@ -SOLARIS_USL_CONSOLE_TRUE = @SOLARIS_USL_CONSOLE_TRUE@ +SOLARIS_VT_FALSE = @SOLARIS_VT_FALSE@ +SOLARIS_VT_TRUE = @SOLARIS_VT_TRUE@ SPARC64_VIDEO_FALSE = @SPARC64_VIDEO_FALSE@ SPARC64_VIDEO_TRUE = @SPARC64_VIDEO_TRUE@ +SPECIAL_DTRACE_OBJECTS_FALSE = @SPECIAL_DTRACE_OBJECTS_FALSE@ +SPECIAL_DTRACE_OBJECTS_TRUE = @SPECIAL_DTRACE_OBJECTS_TRUE@ STANDALONE_XPBPROXY_FALSE = @STANDALONE_XPBPROXY_FALSE@ STANDALONE_XPBPROXY_TRUE = @STANDALONE_XPBPROXY_TRUE@ STRIP = @STRIP@ +SYSCONFDIR = @SYSCONFDIR@ TSLIB_CFLAGS = @TSLIB_CFLAGS@ TSLIB_FALSE = @TSLIB_FALSE@ TSLIB_LIBS = @TSLIB_LIBS@ TSLIB_TRUE = @TSLIB_TRUE@ +UDEV_CFLAGS = @UDEV_CFLAGS@ +UDEV_LIBS = @UDEV_LIBS@ +UNITTESTS_FALSE = @UNITTESTS_FALSE@ +UNITTESTS_TRUE = @UNITTESTS_TRUE@ UTILS_SYS_LIBS = @UTILS_SYS_LIBS@ -VENDOR_MAN_VERSION = @VENDOR_MAN_VERSION@ -VENDOR_NAME = @VENDOR_NAME@ +VBE_FALSE = @VBE_FALSE@ +VBE_TRUE = @VBE_TRUE@ VENDOR_NAME_SHORT = @VENDOR_NAME_SHORT@ -VENDOR_RELEASE = @VENDOR_RELEASE@ VERSION = @VERSION@ +VGAHW_FALSE = @VGAHW_FALSE@ +VGAHW_TRUE = @VGAHW_TRUE@ +WINDOWSWM_CFLAGS = @WINDOWSWM_CFLAGS@ +WINDOWSWM_LIBS = @WINDOWSWM_LIBS@ +WINDRES = @WINDRES@ X11EXAMPLES_DEP_CFLAGS = @X11EXAMPLES_DEP_CFLAGS@ X11EXAMPLES_DEP_LIBS = @X11EXAMPLES_DEP_LIBS@ +XAA_FALSE = @XAA_FALSE@ +XAA_TRUE = @XAA_TRUE@ XACE_FALSE = @XACE_FALSE@ XACE_TRUE = @XACE_TRUE@ XCALIBRATE_FALSE = @XCALIBRATE_FALSE@ @@ -398,6 +444,7 @@ XEPHYR_LIBS = @XEPHYR_LIBS@ XEPHYR_TRUE = @XEPHYR_TRUE@ XF86BIGFONT_FALSE = @XF86BIGFONT_FALSE@ XF86BIGFONT_TRUE = @XF86BIGFONT_TRUE@ +XF86CONFIGDIR = @XF86CONFIGDIR@ XF86CONFIGFILE = @XF86CONFIGFILE@ XF86UTILS_FALSE = @XF86UTILS_FALSE@ XF86UTILS_TRUE = @XF86UTILS_TRUE@ @@ -440,15 +487,14 @@ XORG_TRUE = @XORG_TRUE@ XPBPROXY_CFLAGS = @XPBPROXY_CFLAGS@ XPBPROXY_LIBS = @XPBPROXY_LIBS@ XQUARTZ_FALSE = @XQUARTZ_FALSE@ +XQUARTZ_SPARKLE = @XQUARTZ_SPARKLE@ +XQUARTZ_SPARKLE_FALSE = @XQUARTZ_SPARKLE_FALSE@ +XQUARTZ_SPARKLE_TRUE = @XQUARTZ_SPARKLE_TRUE@ XQUARTZ_TRUE = @XQUARTZ_TRUE@ XREGISTRY_FALSE = @XREGISTRY_FALSE@ XREGISTRY_TRUE = @XREGISTRY_TRUE@ XRESEXAMPLES_DEP_CFLAGS = @XRESEXAMPLES_DEP_CFLAGS@ XRESEXAMPLES_DEP_LIBS = @XRESEXAMPLES_DEP_LIBS@ -XSDLSERVER_FALSE = @XSDLSERVER_FALSE@ -XSDLSERVER_TRUE = @XSDLSERVER_TRUE@ -XSDL_INCS = @XSDL_INCS@ -XSDL_LIBS = @XSDL_LIBS@ XSELINUX_FALSE = @XSELINUX_FALSE@ XSELINUX_TRUE = @XSELINUX_TRUE@ XSERVERCFLAGS_CFLAGS = @XSERVERCFLAGS_CFLAGS@ @@ -496,10 +542,10 @@ X_PRIVSEP_FALSE = @X_PRIVSEP_FALSE@ X_PRIVSEP_TRUE = @X_PRIVSEP_TRUE@ YACC = @YACC@ YFLAGS = @YFLAGS@ +__XCONFIGDIR__ = @__XCONFIGDIR__@ __XCONFIGFILE__ = @__XCONFIGFILE__@ abi_ansic = @abi_ansic@ abi_extension = @abi_extension@ -abi_font = @abi_font@ abi_videodrv = @abi_videodrv@ abi_xinput = @abi_xinput@ ac_ct_CC = @ac_ct_CC@ @@ -554,7 +600,9 @@ psdir = @psdir@ sbindir = @sbindir@ sdkdir = @sdkdir@ sharedstatedir = @sharedstatedir@ +symbol_visibility = @symbol_visibility@ sysconfdir = @sysconfdir@ +sysconfigdir = @sysconfigdir@ target_alias = @target_alias@ noinst_LTLIBRARIES = libexa.la @XORG_TRUE@sdk_HEADERS = exa.h @@ -566,9 +614,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 \ @@ -627,8 +679,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/xserver/exa/exa.c b/xserver/exa/exa.c index 270810766..590d9a500 100644 --- a/xserver/exa/exa.c +++ b/xserver/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,226 +203,66 @@ 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; + ExaPixmapPriv (pPix); - pExaScr = ExaGetScreenPriv(pPixmap->drawable.pScreen); - pExaPixmap = ExaGetPixmapPriv(pPixmap); + if (pExaPixmap == NULL) + EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsPinned was called on a non-exa pixmap.\n"), TRUE); - 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); - if (ret == TRUE) - return ret; - } - return pExaScr->SavedModifyPixmapHeader(pPixmap, width, height, depth, - bitsPerPixel, devKind, pPixData); + return pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED; } /** - * exaPixmapIsOffscreen() is used to determine if a pixmap is in offscreen + * exaPixmapHasGpuCopy() is used to determine if a pixmap is in offscreen * memory, meaning that acceleration could probably be done to it, and that it * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it * with the CPU. * * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly * deal with moving pixmaps in and out of system memory), EXA will give drivers - * pixmaps as arguments for which exaPixmapIsOffscreen() is TRUE. + * pixmaps as arguments for which exaPixmapHasGpuCopy() is TRUE. * * @return TRUE if the given drawable is in framebuffer memory. */ Bool -exaPixmapIsOffscreen(PixmapPtr p) +exaPixmapHasGpuCopy(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_has_gpu_copy)(pPixmap); } /** - * exaDrawableIsOffscreen() is a convenience wrapper for exaPixmapIsOffscreen(). + * exaDrawableIsOffscreen() is a convenience wrapper for exaPixmapHasGpuCopy(). */ Bool exaDrawableIsOffscreen (DrawablePtr pDrawable) { - return exaPixmapIsOffscreen (exaGetDrawablePixmap (pDrawable)); + return exaPixmapHasGpuCopy (exaGetDrawablePixmap (pDrawable)); } /** @@ -484,60 +276,96 @@ exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp) exaGetDrawableDeltas (pDrawable, pPixmap, xp, yp); - if (exaPixmapIsOffscreen (pPixmap)) + if (exaPixmapHasGpuCopy (pPixmap)) return pPixmap; else return NULL; } -void -ExaDoPrepareAccess(DrawablePtr pDrawable, int index) +/** + * Returns TRUE if the pixmap GPU copy is being accessed. + */ +Bool +ExaDoPrepareAccess(PixmapPtr pPixmap, int index) { - ScreenPtr pScreen = pDrawable->pScreen; - ExaScreenPriv (pScreen); - PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); - Bool offscreen = exaPixmapIsOffscreen(pPixmap); + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv (pScreen); + ExaPixmapPriv(pPixmap); + Bool has_gpu_copy, ret; + 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); - /* Unhide pixmap pointer */ - if (pPixmap->devPrivate.ptr == NULL && !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) { - pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); + /* Handle repeated / nested calls. */ + for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) { + if (pExaScr->access[i].pixmap == pPixmap) { + pExaScr->access[i].count++; + return pExaScr->access[i].retval; + } } - if (!offscreen) - return; + /* 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; + } + + /* 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)); + } + + has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + + if (has_gpu_copy && pExaPixmap->fb_ptr) { + pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; + ret = TRUE; + } else { + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + ret = FALSE; + } + + /* Store so we can handle repeated / nested calls. */ + pExaScr->access[index].pixmap = pPixmap; + pExaScr->access[index].count = 1; + + if (!has_gpu_copy) + goto out; - exaWaitSync (pDrawable->pScreen); + exaWaitSync (pScreen); if (pExaScr->info->PrepareAccess == NULL) - return; + goto out; - 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; + ret = FALSE; + goto out; } if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) { - ExaPixmapPriv (pPixmap); - if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) - FatalError("Driver failed PrepareAccess on a pinned pixmap\n"); + if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED && + !(pExaScr->info->flags & EXA_MIXED_PIXMAPS)) + FatalError("Driver failed PrepareAccess on a pinned pixmap.\n"); exaMoveOutPixmap (pPixmap); + ret = FALSE; + goto out; } -} - -void -exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg) -{ - ExaMigrationRec pixmaps[1]; - 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; + ret = TRUE; - exaDoMigration(pixmaps, 1, FALSE); - - ExaDoPrepareAccess(pDrawable, index); +out: + pExaScr->access[index].retval = ret; + return ret; } /** @@ -549,7 +377,13 @@ exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg) void exaPrepareAccess(DrawablePtr pDrawable, int index) { - exaPrepareAccessReg(pDrawable, index, NULL); + PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); + ExaScreenPriv(pDrawable->pScreen); + + if (pExaScr->prepare_access_reg) + pExaScr->prepare_access_reg(pPixmap, index, NULL); + else + (void)ExaDoPrepareAccess(pPixmap, index); } /** @@ -564,109 +398,207 @@ 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; + break; + } } - if (pExaScr->info->FinishAccess == NULL) - return; + /* Catch unbalanced Prepare/FinishAccess calls. */ + if (i == EXA_NUM_PREPARE_INDICES) + EXA_FatalErrorDebugWithRet(("EXA bug: FinishAccess called without PrepareAccess for pixmap 0x%p.\n", + pPixmap),); + + pExaScr->access[i].pixmap = NULL; - if (!exaPixmapIsOffscreen (pPixmap)) + /* We always hide the devPrivate.ptr. */ + pPixmap->devPrivate.ptr = NULL; + + if (!pExaScr->info->FinishAccess || !exaPixmapHasGpuCopy(pPixmap)) return; - if (index >= EXA_PREPARE_AUX0 && + if (i >= 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"); return; } - (*pExaScr->info->FinishAccess) (pPixmap, index); + (*pExaScr->info->FinishAccess) (pPixmap, i); } /** - * 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 +exaDestroyGC(GCPtr pGC); + static void -exaValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +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 +}; + +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); + ExaGCPriv(pGC); + PixmapPtr pTile = NULL; + Bool finish_current_tile = FALSE; + + /* 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 && pRotatedTile->drawable.depth == pDrawable->depth) + pTile = pRotatedTile; + else + finish_current_tile = TRUE; /* CreatePixmap will be called. */ + } } - 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); + + /* Calls to Create/DestroyPixmap have to be identified as special. */ + pExaScr->fallback_counter++; + swap(pExaGC, pGC, funcs); + (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable); + swap(pExaGC, pGC, funcs); + pExaScr->fallback_counter--; + + if (pTile) + exaFinishAccess(&pTile->drawable, EXA_PREPARE_SRC); + if (finish_current_tile && pGC->tile.pixmap) + exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_AUX_DEST); + if (pGC->stipple) + exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK); +} - pGC->ops = (GCOps *) &exaOps; +/* Is exaPrepareAccessGC() needed? */ +static void +exaDestroyGC(GCPtr pGC) +{ + ExaGCPriv(pGC); + swap(pExaGC, pGC, funcs); + (*pGC->funcs->DestroyGC)(pGC); + swap(pExaGC, pGC, funcs); } -static GCFuncs exaGCFuncs = { - exaValidateGC, - miChangeGC, - miCopyGC, - miDestroyGC, - miChangeClip, - miDestroyClip, - miCopyClip -}; +static void +exaChangeGC (GCPtr pGC, + unsigned long mask) +{ + ExaGCPriv(pGC); + swap(pExaGC, pGC, funcs); + (*pGC->funcs->ChangeGC) (pGC, mask); + swap(pExaGC, pGC, funcs); +} + +static void +exaCopyGC (GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst) +{ + ExaGCPriv(pGCDst); + swap(pExaGC, pGCDst, funcs); + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + swap(pExaGC, pGCDst, funcs); +} + +static void +exaChangeClip (GCPtr pGC, + int type, + pointer pvalue, + int nrects) +{ + ExaGCPriv(pGC); + swap(pExaGC, pGC, funcs); + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + swap(pExaGC, pGC, funcs); +} + +static void +exaCopyClip(GCPtr pGCDst, GCPtr pGCSrc) +{ + ExaGCPriv(pGCDst); + swap(pExaGC, pGCDst, funcs); + (*pGCDst->funcs->CopyClip)(pGCDst, pGCSrc); + swap(pExaGC, pGCDst, funcs); +} + +static void +exaDestroyClip(GCPtr pGC) +{ + ExaGCPriv(pGC); + swap(pExaGC, pGC, funcs); + (*pGC->funcs->DestroyClip)(pGC); + swap(pExaGC, pGC, funcs); +} /** * exaCreateGC makes a new GC and hooks up its funcs handler, so that @@ -675,32 +607,44 @@ 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); 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); - - if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE) - exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); + pExaScr->fallback_counter++; + swap(pExaScr, pScreen, ChangeWindowAttributes); + ret = pScreen->ChangeWindowAttributes(pWin, mask); + swap(pExaScr, pScreen, ChangeWindowAttributes); + pExaScr->fallback_counter--; if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap) - exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); + exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); + if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE) + exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); return ret; } @@ -708,11 +652,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 +672,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 +693,58 @@ exaCreateScreenResources(ScreenPtr pScreen) return TRUE; } +static void +ExaBlockHandler(int screenNum, pointer blockData, pointer pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[screenNum]; + ExaScreenPriv(pScreen); + + /* Move any deferred results from a software fallback to the driver pixmap */ + if (pExaScr->deferred_mixed_pixmap) + exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap); + + unwrap(pExaScr, pScreen, BlockHandler); + (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); + wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler); + + /* The rest only applies to classic EXA */ + if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) + return; + + /* 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 +760,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 +843,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 +900,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 +914,40 @@ 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) || + (pExaScr->info->flags & EXA_MIXED_PIXMAPS))) + wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler); + if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) && + !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) + 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 +968,37 @@ 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_has_gpu_copy = exaPixmapHasGpuCopy_mixed; + pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed; + pExaScr->do_move_out_pixmap = NULL; + pExaScr->prepare_access_reg = exaPrepareAccessReg_mixed; + } 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_has_gpu_copy = exaPixmapHasGpuCopy_driver; + pExaScr->do_move_in_pixmap = NULL; + pExaScr->do_move_out_pixmap = NULL; + pExaScr->prepare_access_reg = 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_has_gpu_copy = exaPixmapHasGpuCopy_classic; + pExaScr->do_move_in_pixmap = exaMoveInPixmap_classic; + pExaScr->do_move_out_pixmap = exaMoveOutPixmap_classic; + pExaScr->prepare_access_reg = exaPrepareAccessReg_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 +1011,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 +1095,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/xserver/exa/exa.h b/xserver/exa/exa.h index 4a96cc6f3..8c93d156f 100644 --- a/xserver/exa/exa.h +++ b/xserver/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() @@ -640,13 +624,13 @@ typedef struct _ExaDriver { /** * PixmapIsOffscreen() is an optional driver replacement to - * exaPixmapIsOffscreen(). Set to NULL if you want the standard behaviour - * of exaPixmapIsOffscreen(). + * exaPixmapHasGpuCopy(). Set to NULL if you want the standard behaviour + * of exaPixmapHasGpuCopy(). * * @param pPix the pixmap * @return TRUE if the given drawable is in framebuffer memory. * - * exaPixmapIsOffscreen() is used to determine if a pixmap is in offscreen + * exaPixmapHasGpuCopy() is used to determine if a pixmap is in offscreen * memory, meaning that acceleration could probably be done to it, and that it * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it * with the CPU. @@ -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/xserver/exa/exa_accel.c b/xserver/exa/exa_accel.c index dac6e6c79..57029fdc5 100644 --- a/xserver/exa/exa_accel.c +++ b/xserver/exa/exa_accel.c @@ -50,20 +50,24 @@ 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 || + if (pExaScr->fallback_counter || + pExaScr->swappedOut || pGC->fillStyle != FillSolid || pExaPixmap->accel_blocked) { 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 +152,13 @@ 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 (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen) + return FALSE; + + /* If there's a system copy, we want to save the result there */ + if (pExaPixmap->pDamage) return FALSE; /* Don't bother with under 8bpp, XYPixmaps. */ @@ -164,10 +172,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 +185,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 +218,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 +364,8 @@ exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, return TRUE; } -void -exaCopyNtoN (DrawablePtr pSrcDrawable, +Bool +exaHWCopyNtoN (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, BoxPtr pbox, @@ -388,22 +373,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 +429,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 +462,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 +486,68 @@ 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 (exaPixmapHasGpuCopy(pDstPixmap)) { + /* Normal blitting. */ + if (exaPixmapHasGpuCopy(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); + /* UTS: mainly for SHM PutImage's secondary path. + * + * Only taking this path for directly accessible pixmaps. + */ + } else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) { + int bpp = pSrcDrawable->bitsPerPixel; + int src_stride = exaGetPixmapPitch(pSrcPixmap); + CARD8 *src = NULL; + + if (!pExaScr->info->UploadToScreen) + goto fallback; - (*pExaScr->info->DoneCopy) (pDstPixmap); - exaMarkSync (pDstDrawable->pScreen); + 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; + } 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 +558,40 @@ 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_counter || + (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 @@ -550,12 +600,12 @@ exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, { ExaScreenPriv (pDstDrawable->pScreen); - if (pExaScr->swappedOut) { + if (pExaScr->fallback_counter || pExaScr->swappedOut) { return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, 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); } @@ -564,13 +614,14 @@ static void exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppt) { + ExaScreenPriv (pDrawable->pScreen); int i; xRectangle *prect; /* If we can't reuse the current GC as is, don't bother accelerating the * points. */ - if (pGC->fillStyle != FillSolid) { + if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) { ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt); return; } @@ -599,10 +650,16 @@ static void exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppt) { + ExaScreenPriv (pDrawable->pScreen); xRectangle *prect; int x1, x2, y1, y2; int i; + if (pExaScr->fallback_counter) { + ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); + return; + } + /* Don't try to do wide lines or non-solid fill style. */ if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid) { @@ -660,12 +717,13 @@ static void exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment *pSeg) { + ExaScreenPriv (pDrawable->pScreen); xRectangle *prect; int i; /* Don't try to do wide lines or non-solid fill style. */ - if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || - pGC->fillStyle != FillSolid) + if (pExaScr->fallback_counter || pGC->lineWidth != 0 || + pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid) { ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); return; @@ -730,7 +788,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,14 +798,10 @@ 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) + if (pExaScr->fallback_counter || pExaScr->swappedOut || + pExaPixmap->accel_blocked) { goto fallback; } @@ -778,9 +831,18 @@ 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; - if (!exaPixmapIsOffscreen (pPixmap) || + exaDoMigration (pixmaps, 1, TRUE); + } + + if (!exaPixmapHasGpuCopy (pPixmap) || !(*pExaScr->info->PrepareSolid) (pPixmap, pGC->alu, pGC->planemask, @@ -898,6 +960,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 +975,25 @@ exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) -pPixmap->screen_x, -pPixmap->screen_y); #endif - fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable, + if (pExaScr->fallback_counter) { + pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; + goto fallback; + } + + pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW; + miCopyRegion (&pPixmap->drawable, &pPixmap->drawable, NULL, &rgnDst, dx, dy, exaCopyNtoN, 0, NULL); + pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW; +fallback: 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,27 +1004,27 @@ 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) - { + if (pExaScr->fallback_counter || 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); } - if (exaPixmapIsOffscreen (pPixmap) && + if (exaPixmapHasGpuCopy (pPixmap) && (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) { int nbox; @@ -965,10 +1042,12 @@ exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, (*pExaScr->info->DoneSolid) (pPixmap); exaMarkSync(pDrawable->pScreen); - if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && + if (pExaPixmap->pDamage && + pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP && pDrawable->width == 1 && pDrawable->height == 1 && pDrawable->bitsPerPixel != 24) { ExaPixmapPriv(pPixmap); + RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); switch (pDrawable->bitsPerPixel) { case 32: @@ -983,6 +1062,9 @@ exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, pRegion); + REGION_UNION(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB, + pRegion); + REGION_SUBTRACT(pScreen, pending_damage, pending_damage, pRegion); } ret = TRUE; @@ -1008,7 +1090,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,29 +1106,32 @@ 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) - { + if (pExaScr->fallback_counter || 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); } pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); - if (!pPixmap || !exaPixmapIsOffscreen(pTile)) + if (!pPixmap || !exaPixmapHasGpuCopy(pTile)) return FALSE; if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) @@ -1180,31 +1264,17 @@ 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); + ExaPixmapPriv(pPix); 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; - - 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); - - if (pExaScr->swappedOut) + if (pExaScr->fallback_counter || pExaScr->swappedOut) goto fallback; - exaDoMigration(pixmaps, 1, FALSE); + /* If there's a system copy, we want to save the result there */ + if (pExaPixmap->pDamage) + goto fallback; pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); @@ -1226,17 +1296,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/xserver/exa/exa_classic.c b/xserver/exa/exa_classic.c new file mode 100644 index 000000000..9bc369ec1 --- /dev/null +++ b/xserver/exa/exa_classic.c @@ -0,0 +1,267 @@ +/* + * Copyright © 2009 Maarten Maathuis + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <string.h> + +#include "exa_priv.h" +#include "exa.h" + +/* This file holds the classic exa specific implementation. */ + +static _X_INLINE void* +ExaGetPixmapAddress(PixmapPtr p) +{ + ExaPixmapPriv(p); + + if (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr) + return pExaPixmap->fb_ptr; + else + return pExaPixmap->sys_ptr; +} + +/** + * exaCreatePixmap() creates a new pixmap. + * + * If width and height are 0, this won't be a full-fledged pixmap and it will + * get ModifyPixmapHeader() called on it later. So, we mark it as pinned, because + * ModifyPixmapHeader() would break migration. These types of pixmaps are used + * for scratch pixmaps, or to represent the visible screen. + */ +PixmapPtr +exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint) +{ + PixmapPtr pPixmap; + ExaPixmapPrivPtr pExaPixmap; + BoxRec box; + int bpp; + ExaScreenPriv(pScreen); + + if (w > 32767 || h > 32767) + return NullPixmap; + + swap(pExaScr, pScreen, CreatePixmap); + pPixmap = pScreen->CreatePixmap (pScreen, w, h, depth, usage_hint); + swap(pExaScr, pScreen, CreatePixmap); + + if (!pPixmap) + return NULL; + + pExaPixmap = ExaGetPixmapPriv(pPixmap); + pExaPixmap->driverPriv = NULL; + + bpp = pPixmap->drawable.bitsPerPixel; + + pExaPixmap->driverPriv = NULL; + /* Scratch pixmaps may have w/h equal to zero, and may not be + * migrated. + */ + if (!w || !h) + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + else + pExaPixmap->score = EXA_PIXMAP_SCORE_INIT; + + pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->sys_pitch = pPixmap->devKind; + + pPixmap->devPrivate.ptr = NULL; + pExaPixmap->use_gpu_copy = FALSE; + + pExaPixmap->fb_ptr = NULL; + exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp); + pExaPixmap->fb_size = pExaPixmap->fb_pitch * h; + + if (pExaPixmap->fb_pitch > 131071) { + swap(pExaScr, pScreen, DestroyPixmap); + pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + return NULL; + } + + /* Set up damage tracking */ + pExaPixmap->pDamage = DamageCreate (NULL, NULL, + DamageReportNone, TRUE, + pScreen, pPixmap); + + if (pExaPixmap->pDamage == NULL) { + swap(pExaScr, pScreen, DestroyPixmap); + pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + return NULL; + } + + DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage); + /* This ensures that pending damage reflects the current operation. */ + /* This is used by exa to optimize migration. */ + DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE); + + pExaPixmap->area = NULL; + + /* We set the initial pixmap as completely valid for a simple reason. + * Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which + * could form single pixel rects as part of a region. Setting the complete region + * as valid is a natural defragmentation of the region. + */ + box.x1 = 0; + box.y1 = 0; + box.x2 = w; + box.y2 = h; + REGION_INIT(pScreen, &pExaPixmap->validSys, &box, 0); + REGION_INIT(pScreen, &pExaPixmap->validFB, &box, 0); + + exaSetAccelBlock(pExaScr, pExaPixmap, + w, h, bpp); + + /* During a fallback we must prepare access. */ + if (pExaScr->fallback_counter) + exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); + + return pPixmap; +} + +Bool +exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, 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 gpu memory. + */ + if (pExaScr->info->memoryBase && pPixData) { + if ((CARD8 *)pPixData >= pExaScr->info->memoryBase && + ((CARD8 *)pPixData - pExaScr->info->memoryBase) < + pExaScr->info->memorySize) { + pExaPixmap->fb_ptr = pPixData; + pExaPixmap->fb_pitch = devKind; + pExaPixmap->use_gpu_copy = TRUE; + } + } + + if (width > 0 && height > 0 && bitsPerPixel > 0) { + exaSetFbPitch(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + + exaSetAccelBlock(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + } + + /* Pixmaps subject to ModifyPixmapHeader will be pinned to system or + * gpu memory, so there's no need to track damage. + */ + if (pExaPixmap->pDamage) { + 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); + + /* During a fallback we must finish access, but we don't know the index. */ + if (pExaScr->fallback_counter) + exaFinishAccess(&pPixmap->drawable, -1); + + 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 +exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + ExaPixmapPriv(pPixmap); + Bool ret; + + if (pExaScr->info->PixmapIsOffscreen) { + void* old_ptr = pPixmap->devPrivate.ptr; + pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); + ret = pExaScr->info->PixmapIsOffscreen(pPixmap); + pPixmap->devPrivate.ptr = old_ptr; + } else + ret = (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr); + + return ret; +} diff --git a/xserver/exa/exa_driver.c b/xserver/exa/exa_driver.c new file mode 100644 index 000000000..dcf1a9860 --- /dev/null +++ b/xserver/exa/exa_driver.c @@ -0,0 +1,225 @@ +/* + * Copyright © 2009 Maarten Maathuis + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <string.h> + +#include "exa_priv.h" +#include "exa.h" + +/* This file holds the driver allocated pixmaps specific implementation. */ + +static _X_INLINE void* +ExaGetPixmapAddress(PixmapPtr p) +{ + ExaPixmapPriv(p); + + return pExaPixmap->sys_ptr; +} + +/** + * exaCreatePixmap() creates a new pixmap. + * + * Pixmaps are always marked as pinned, because exa has no control over them. + */ +PixmapPtr +exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint) +{ + PixmapPtr pPixmap; + ExaPixmapPrivPtr pExaPixmap; + int bpp; + size_t paddedWidth, datasize; + ExaScreenPriv(pScreen); + + if (w > 32767 || h > 32767) + return NullPixmap; + + swap(pExaScr, pScreen, CreatePixmap); + pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint); + swap(pExaScr, pScreen, CreatePixmap); + + if (!pPixmap) + return NULL; + + pExaPixmap = ExaGetPixmapPriv(pPixmap); + pExaPixmap->driverPriv = NULL; + + bpp = pPixmap->drawable.bitsPerPixel; + + /* Set this before driver hooks, to allow for driver pixmaps without gpu + * memory to back it. These pixmaps have a valid pointer at all times. + */ + pPixmap->devPrivate.ptr = NULL; + + if (pExaScr->info->CreatePixmap2) { + int new_pitch = 0; + pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch); + paddedWidth = pExaPixmap->fb_pitch = new_pitch; + } + else { + paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); + if (paddedWidth / 4 > 32767 || h > 32767) + return NullPixmap; + + exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp); + + if (paddedWidth < pExaPixmap->fb_pitch) + paddedWidth = pExaPixmap->fb_pitch; + datasize = h * paddedWidth; + pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, datasize, 0); + } + + if (!pExaPixmap->driverPriv) { + swap(pExaScr, pScreen, DestroyPixmap); + pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + return NULL; + } + + /* Allow ModifyPixmapHeader to set sys_ptr appropriately. */ + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + pExaPixmap->fb_ptr = NULL; + pExaPixmap->pDamage = NULL; + pExaPixmap->sys_ptr = NULL; + + (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, + paddedWidth, NULL); + + pExaPixmap->area = NULL; + + exaSetAccelBlock(pExaScr, pExaPixmap, + w, h, bpp); + + /* During a fallback we must prepare access. */ + if (pExaScr->fallback_counter) + exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); + + return pPixmap; +} + +Bool +exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, 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 + * !has_gpu_copy pixmap. We need to store the pointer, + * because PrepareAccess won't be called. + */ + if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) { + pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->sys_pitch = pPixmap->devKind; + } + if (ret == TRUE) + goto out; + } + + swap(pExaScr, pScreen, ModifyPixmapHeader); + ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData); + swap(pExaScr, pScreen, ModifyPixmapHeader); + +out: + /* Always NULL this, we don't want lingering pointers. */ + pPixmap->devPrivate.ptr = NULL; + + return ret; +} + +Bool +exaDestroyPixmap_driver (PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + Bool ret; + + if (pPixmap->refcnt == 1) + { + ExaPixmapPriv (pPixmap); + + /* During a fallback we must finish access, but we don't know the index. */ + if (pExaScr->fallback_counter) + exaFinishAccess(&pPixmap->drawable, -1); + + if (pExaPixmap->driverPriv) + pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); + pExaPixmap->driverPriv = NULL; + } + + swap(pExaScr, pScreen, DestroyPixmap); + ret = pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + + return ret; +} + +Bool +exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + pointer saved_ptr; + Bool ret; + + saved_ptr = pPixmap->devPrivate.ptr; + pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); + ret = pExaScr->info->PixmapIsOffscreen(pPixmap); + pPixmap->devPrivate.ptr = saved_ptr; + + return ret; +} diff --git a/xserver/exa/exa_glyphs.c b/xserver/exa/exa_glyphs.c index 93b8b36ae..fd14e9b87 100644 --- a/xserver/exa/exa_glyphs.c +++ b/xserver/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; @@ -354,11 +352,11 @@ exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, /* The most efficient thing to way to upload the glyph to the screen * is to use the UploadToScreen() driver hook; this allows us to - * pipeline glyph uploads and to avoid creating offscreen pixmaps for + * pipeline glyph uploads and to avoid creating gpu backed pixmaps for * glyphs that we'll never use again. * - * If we can't do it with UploadToScreen (because the glyph is offscreen, etc), - * we fall back to CompositePicture. + * If we can't do it with UploadToScreen (because the glyph has a gpu copy, + * etc), we fall back to CompositePicture. * * We need to damage the cache pixmap manually in either case because the damage * layer unwrapped the picture screen before calling exaGlyphs. @@ -366,7 +364,8 @@ exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, static void exaGlyphCacheUploadGlyph(ScreenPtr pScreen, ExaGlyphCachePtr cache, - int pos, + int x, + int y, GlyphPtr pGlyph) { ExaScreenPriv(pScreen); @@ -374,34 +373,37 @@ 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; /* If the glyph pixmap is already uploaded, no point in doing * things this way */ - if (exaPixmapIsOffscreen(pGlyphPixmap)) + if (exaPixmapHasGpuCopy(pGlyphPixmap)) goto composite; /* UploadToScreen only works if bpp match */ 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 have a gpu copy. */ + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pCachePixmap; + pixmaps[0].pReg = NULL; + exaDoMigration (pixmaps, 1, TRUE); + } - if (!exaPixmapIsOffscreen(pCachePixmap)) + if (!exaPixmapHasGpuCopy(pCachePixmap)) goto composite; - /* CACHE_{X,Y} are in pixmap coordinates, no need for cache{X,Y}off */ + /* x,y are in pixmap coordinates, no need for cache{X,Y}off */ if (pExaScr->info->UploadToScreen(pCachePixmap, - CACHE_X(pos), - CACHE_Y(pos), + x, + y, pGlyph->info.width, pGlyph->info.height, (char *)pExaPixmap->sys_ptr, @@ -415,18 +417,18 @@ composite: cache->picture, 0, 0, 0, 0, - CACHE_X(pos), - CACHE_Y(pos), + x, + y, pGlyph->info.width, pGlyph->info.height); damage: /* The cache pixmap isn't a window, so no need to offset coordinates. */ exaPixmapDirty (pCachePixmap, - CACHE_X(pos), - CACHE_Y(pos), - CACHE_X(pos) + cache->glyphWidth, - CACHE_Y(pos) + cache->glyphHeight); + x, + y, + x + cache->glyphWidth, + y + cache->glyphHeight); } static ExaGlyphCacheResult @@ -434,13 +436,20 @@ 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; + int x, y; - if (buffer->source && buffer->source != cache->picture) + if (buffer->mask && buffer->mask != cache->picture) return ExaGlyphNeedFlush; if (!cache->picture) { @@ -455,10 +464,14 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, pos = exaGlyphCacheHashLookup(cache, pGlyph); if (pos != -1) { DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos)); + x = CACHE_X(pos); + y = CACHE_Y(pos); } else { if (cache->glyphCount < cache->size) { /* Space remaining; we fill from the start */ pos = cache->glyphCount; + x = CACHE_X(pos); + y = CACHE_Y(pos); cache->glyphCount++; DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos)); @@ -469,18 +482,17 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, * already in the output buffer were at this position in * the cache */ - pos = cache->evictionPosition; + x = CACHE_X(pos); + y = CACHE_Y(pos); DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); if (buffer->count) { - int 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; } @@ -495,16 +507,31 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, cache->evictionPosition = rand() % cache->size; } - exaGlyphCacheUploadGlyph(pScreen, cache, pos, pGlyph); + exaGlyphCacheUploadGlyph(pScreen, cache, x, y, 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 = x; + rect->yMask = y; + } + else + { + rect->xSrc = x; + rect->ySrc = y; + rect->xMask = 0; + rect->yMask = 0; + } + + rect->pDst = pDst; + rect->xDst = xDst; + rect->yDst = yDst; rect->width = pGlyph->info.width; rect->height = pGlyph->info.height; @@ -520,15 +547,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 +576,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 +597,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 +622,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 +694,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, @@ -758,13 +705,12 @@ exaGlyphs (CARD8 op, GlyphListPtr list, GlyphPtr *glyphs) { - 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 +718,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 +747,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 +793,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; @@ -855,18 +806,33 @@ exaGlyphs (CARD8 op, while (n--) { 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 +845,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 +856,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/xserver/exa/exa_migration.c b/xserver/exa/exa_migration_classic.c index 4623eccdd..871679ffc 100644 --- a/xserver/exa/exa_migration.c +++ b/xserver/exa/exa_migration_classic.c @@ -42,20 +42,6 @@ #endif /** - * Returns TRUE if the pixmap is not movable. This is the case where it's a - * fake pixmap for the frontbuffer (no pixmap private) or it's a scratch - * pixmap created by some other X Server internals (the score says it's - * pinned). - */ -static Bool -exaPixmapIsPinned (PixmapPtr pPix) -{ - ExaPixmapPriv (pPix); - - return pExaPixmap == NULL || pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED; -} - -/** * The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys * and exaCopyDirtyToFb both needed to do this loop. */ @@ -75,7 +61,7 @@ exaMemcpyBox (PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch, dst += dst_pitch; } } - + /** * Returns TRUE if the pixmap is dirty (has been modified in its current * location compared to the other), or lacks a private for tracking @@ -86,8 +72,13 @@ exaPixmapIsDirty (PixmapPtr pPix) { ExaPixmapPriv (pPix); - return pExaPixmap == NULL || - REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage)) || + if (pExaPixmap == NULL) + EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE); + + if (!pExaPixmap->pDamage) + return FALSE; + + return REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage)) || !REGION_EQUAL(pScreen, &pExaPixmap->validSys, &pExaPixmap->validFB); } @@ -116,15 +107,14 @@ exaPixmapShouldBeInFB (PixmapPtr pPix) 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)) + char *sys, int sys_pitch), int fallback_index, + void (*sync) (ScreenPtr pScreen)) { PixmapPtr pPixmap = migrate->pPix; ExaPixmapPriv (pPixmap); RegionPtr damage = DamageRegion (pExaPixmap->pDamage); RegionRec CopyReg; - Bool save_offscreen; + Bool save_use_gpu_copy; int save_pitch; BoxPtr pBox; int nbox; @@ -132,7 +122,7 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, Bool need_sync = FALSE; /* Damaged bits are valid in current copy but invalid in other one */ - if (exaPixmapIsOffscreen(pPixmap)) { + if (pExaPixmap->use_gpu_copy) { REGION_UNION(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB, damage); REGION_SUBTRACT(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, @@ -173,7 +163,27 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, } #endif - REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, pending_damage); + /* 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 @@ -193,9 +203,9 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, pBox = REGION_RECTS(&CopyReg); nbox = REGION_NUM_RECTS(&CopyReg); - save_offscreen = pExaPixmap->offscreen; + save_use_gpu_copy = pExaPixmap->use_gpu_copy; save_pitch = pPixmap->devKind; - pExaPixmap->offscreen = TRUE; + pExaPixmap->use_gpu_copy = TRUE; pPixmap->devKind = pExaPixmap->fb_pitch; while (nbox--) { @@ -217,30 +227,43 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, pExaPixmap->sys_pitch)) { if (!access_prepared) { - ExaDoPrepareAccess(&pPixmap->drawable, fallback_index); + ExaDoPrepareAccess(pPixmap, fallback_index); access_prepared = TRUE; } - exaMemcpyBox (pPixmap, pBox, - fallback_src, fallback_srcpitch, - fallback_dst, fallback_dstpitch); + if (fallback_index == EXA_PREPARE_DEST) { + exaMemcpyBox (pPixmap, pBox, + pExaPixmap->sys_ptr, pExaPixmap->sys_pitch, + pPixmap->devPrivate.ptr, pPixmap->devKind); + } else { + exaMemcpyBox (pPixmap, pBox, + pPixmap->devPrivate.ptr, pPixmap->devKind, + pExaPixmap->sys_ptr, pExaPixmap->sys_pitch); + } } else need_sync = TRUE; pBox++; } - if (access_prepared) - exaFinishAccess(&pPixmap->drawable, fallback_index); - else if (need_sync) - sync (pPixmap->drawable.pScreen); - - pExaPixmap->offscreen = save_offscreen; + pExaPixmap->use_gpu_copy = save_use_gpu_copy; pPixmap->devKind = save_pitch; + /* Try to prevent source valid region from growing too many rects by + * removing parts of it which are also in the destination valid region. + * Removing anything beyond that would lead to data loss. + */ + if (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 (access_prepared) + exaFinishAccess(&pPixmap->drawable, fallback_index); + else if (need_sync && sync) + sync (pPixmap->drawable.pScreen); } /** @@ -248,7 +271,7 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, * the framebuffer memory copy to the system memory copy. Both areas must be * allocated. */ -static void +void exaCopyDirtyToSys (ExaMigrationPtr migrate) { PixmapPtr pPixmap = migrate->pPix; @@ -256,9 +279,8 @@ exaCopyDirtyToSys (ExaMigrationPtr migrate) 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); + pExaScr->info->DownloadFromScreen, EXA_PREPARE_SRC, + exaWaitSync); } /** @@ -266,7 +288,7 @@ exaCopyDirtyToSys (ExaMigrationPtr migrate) * the system memory copy to the framebuffer memory copy. Both areas must be * allocated. */ -static void +void exaCopyDirtyToFb (ExaMigrationPtr migrate) { PixmapPtr pPixmap = migrate->pPix; @@ -274,9 +296,7 @@ exaCopyDirtyToFb (ExaMigrationPtr migrate) 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, exaMarkSync); + pExaScr->info->UploadToScreen, EXA_PREPARE_DEST, NULL); } /** @@ -334,7 +354,7 @@ exaDoMoveInPixmap (ExaMigrationPtr migrate) exaCopyDirtyToFb (migrate); - if (exaPixmapIsOffscreen(pPixmap)) + if (exaPixmapHasGpuCopy(pPixmap)) return; DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap, @@ -344,14 +364,14 @@ exaDoMoveInPixmap (ExaMigrationPtr migrate) pPixmap->drawable.height, exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); - pExaPixmap->offscreen = TRUE; + pExaPixmap->use_gpu_copy = TRUE; pPixmap->devKind = pExaPixmap->fb_pitch; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; } void -exaMoveInPixmap (PixmapPtr pPixmap) +exaMoveInPixmap_classic (PixmapPtr pPixmap) { static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE, .pReg = NULL }; @@ -375,7 +395,7 @@ exaDoMoveOutPixmap (ExaMigrationPtr migrate) exaCopyDirtyToSys (migrate); - if (exaPixmapIsOffscreen(pPixmap)) { + if (exaPixmapHasGpuCopy(pPixmap)) { DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap, (void*)(ExaGetPixmapPriv(pPixmap)->area ? @@ -384,7 +404,7 @@ exaDoMoveOutPixmap (ExaMigrationPtr migrate) pPixmap->drawable.height, exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); - pExaPixmap->offscreen = FALSE; + pExaPixmap->use_gpu_copy = FALSE; pPixmap->devKind = pExaPixmap->sys_pitch; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; @@ -392,7 +412,7 @@ exaDoMoveOutPixmap (ExaMigrationPtr migrate) } void -exaMoveOutPixmap (PixmapPtr pPixmap) +exaMoveOutPixmap_classic (PixmapPtr pPixmap) { static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE, .pReg = NULL }; @@ -433,13 +453,6 @@ exaMigrateTowardFb (ExaMigrationPtr migrate) PixmapPtr pPixmap = migrate->pPix; ExaPixmapPriv (pPixmap); - if (pExaPixmap == NULL) { - DBG_MIGRATE(("UseScreen: ignoring exa-uncontrolled pixmap %p (%s)\n", - (pointer)pPixmap, - exaPixmapIsOffscreen(pPixmap) ? "s" : "m")); - return; - } - if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) { DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n", (pointer)pPixmap)); @@ -458,12 +471,16 @@ exaMigrateTowardFb (ExaMigrationPtr migrate) pExaPixmap->score++; if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN && - !exaPixmapIsOffscreen(pPixmap)) + !exaPixmapHasGpuCopy(pPixmap)) { exaDoMoveInPixmap(migrate); } - ExaOffscreenMarkUsed (pPixmap); + if (exaPixmapHasGpuCopy(pPixmap)) { + exaCopyDirtyToFb (migrate); + ExaOffscreenMarkUsed (pPixmap); + } else + exaCopyDirtyToSys (migrate); } /** @@ -476,13 +493,6 @@ exaMigrateTowardSys (ExaMigrationPtr migrate) PixmapPtr pPixmap = migrate->pPix; ExaPixmapPriv (pPixmap); - if (pExaPixmap == NULL) { - DBG_MIGRATE(("UseMem: ignoring exa-uncontrolled pixmap %p (%s)\n", - (pointer)pPixmap, - exaPixmapIsOffscreen(pPixmap) ? "s" : "m")); - return; - } - DBG_MIGRATE(("UseMem: %p score %d\n", (pointer)pPixmap, pExaPixmap->score)); if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) @@ -496,6 +506,12 @@ exaMigrateTowardSys (ExaMigrationPtr migrate) if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area) exaDoMoveOutPixmap(migrate); + + if (exaPixmapHasGpuCopy(pPixmap)) { + exaCopyDirtyToFb (migrate); + ExaOffscreenMarkUsed (pPixmap); + } else + exaCopyDirtyToSys (migrate); } /** @@ -508,9 +524,9 @@ exaAssertNotDirty (PixmapPtr pPixmap) ExaPixmapPriv (pPixmap); CARD8 *dst, *src; RegionRec ValidReg; - int dst_pitch, src_pitch, cpp, y, nbox; + int dst_pitch, src_pitch, cpp, y, nbox, save_pitch; BoxPtr pBox; - Bool ret = TRUE; + Bool ret = TRUE, save_use_gpu_copy; if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL) return ret; @@ -529,7 +545,14 @@ exaAssertNotDirty (PixmapPtr pPixmap) src_pitch = pExaPixmap->fb_pitch; cpp = pPixmap->drawable.bitsPerPixel / 8; - ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC); + save_use_gpu_copy = pExaPixmap->use_gpu_copy; + save_pitch = pPixmap->devKind; + pExaPixmap->use_gpu_copy = TRUE; + pPixmap->devKind = pExaPixmap->fb_pitch; + + if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC)) + goto skip; + while (nbox--) { int rowbytes; @@ -542,7 +565,7 @@ exaAssertNotDirty (PixmapPtr pPixmap) continue; rowbytes = (pBox->x2 - pBox->x1) * cpp; - src = pExaPixmap->fb_ptr + pBox->y1 * src_pitch + 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; @@ -555,8 +578,13 @@ exaAssertNotDirty (PixmapPtr pPixmap) } } } + +skip: exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); + pExaPixmap->use_gpu_copy = save_use_gpu_copy; + pPixmap->devKind = save_pitch; + out: REGION_UNINIT(pScreen, &ValidReg); return ret; @@ -568,15 +596,12 @@ out: * config file. */ void -exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) +exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) { ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen; ExaScreenPriv(pScreen); int i, j; - if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) - return; - /* If 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 @@ -596,7 +621,7 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) */ for (i = 0; i < npixmaps; i++) { if (exaPixmapIsPinned (pixmaps[i].pPix) && - !exaPixmapIsOffscreen (pixmaps[i].pPix)) + !exaPixmapHasGpuCopy (pixmaps[i].pPix)) { EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix, pixmaps[i].pPix->drawable.width, @@ -658,7 +683,7 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) } for (i = 0; i < npixmaps; i++) { - if (exaPixmapIsOffscreen(pixmaps[i].pPix)) { + if (exaPixmapHasGpuCopy(pixmaps[i].pPix)) { /* Found one in FB, so move all to FB. */ for (j = 0; j < npixmaps; j++) exaMigrateTowardFb(pixmaps + i); @@ -687,14 +712,34 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) /* If we couldn't fit everything in, abort */ for (i = 0; i < npixmaps; i++) { - if (!exaPixmapIsOffscreen(pixmaps[i].pPix)) { + if (!exaPixmapHasGpuCopy(pixmaps[i].pPix)) { return; } } - /* Yay, everything's offscreen, mark memory as used */ + /* Yay, everything has a gpu copy, mark memory as used */ for (i = 0; i < npixmaps; i++) { ExaOffscreenMarkUsed (pixmaps[i].pPix); } } } + +void +exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg) +{ + ExaMigrationRec pixmaps[1]; + + if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + } else { + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + } + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = pReg; + + exaDoMigration(pixmaps, 1, FALSE); + + (void)ExaDoPrepareAccess(pPixmap, index); +} diff --git a/xserver/exa/exa_migration_mixed.c b/xserver/exa/exa_migration_mixed.c new file mode 100644 index 000000000..fb4715135 --- /dev/null +++ b/xserver/exa/exa_migration_mixed.c @@ -0,0 +1,261 @@ +/* + * Copyright © 2009 Maarten Maathuis + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <string.h> + +#include "exa_priv.h" +#include "exa.h" + +void +exaCreateDriverPixmap_mixed(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + ExaPixmapPriv(pPixmap); + int w = pPixmap->drawable.width, h = pPixmap->drawable.height; + int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel; + int usage_hint = pPixmap->usage_hint; + int paddedWidth = pExaPixmap->sys_pitch; + + /* Already done. */ + if (pExaPixmap->driverPriv) + return; + + if (exaPixmapIsPinned(pPixmap)) + return; + + /* Can't accel 1/4 bpp. */ + if (pExaPixmap->accel_blocked || bpp < 8) + return; + + if (pExaScr->info->CreatePixmap2) { + int new_pitch = 0; + pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch); + paddedWidth = pExaPixmap->fb_pitch = new_pitch; + } else { + if (paddedWidth < pExaPixmap->fb_pitch) + paddedWidth = pExaPixmap->fb_pitch; + pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, paddedWidth*h, 0); + } + + if (!pExaPixmap->driverPriv) + return; + + (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, + paddedWidth, NULL); +} + +void +exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) +{ + int i; + + /* If anything is pinned in system memory, we won't be able to + * accelerate. + */ + for (i = 0; i < npixmaps; i++) { + if (exaPixmapIsPinned (pixmaps[i].pPix) && + !exaPixmapHasGpuCopy (pixmaps[i].pPix)) + { + can_accel = FALSE; + break; + } + } + + /* We can do nothing. */ + if (!can_accel) + return; + + for (i = 0; i < npixmaps; i++) { + PixmapPtr pPixmap = pixmaps[i].pPix; + ExaPixmapPriv(pPixmap); + + if (!pExaPixmap->driverPriv) + exaCreateDriverPixmap_mixed(pPixmap); + + if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) { + ExaScreenPriv(pPixmap->drawable.pScreen); + + /* This pitch is needed for proper acceleration. For some reason + * there are pixmaps without pDamage and a bad fb_pitch value. + * So setting devKind when only exaPixmapHasGpuCopy() is true + * causes corruption. Pixmaps without pDamage are not migrated + * and should have a valid devKind at all times, so that's why this + * isn't causing problems. Pixmaps have their gpu pitch set the + * first time in the MPH call from exaCreateDriverPixmap_mixed(). + */ + pPixmap->devKind = pExaPixmap->fb_pitch; + exaCopyDirtyToFb(pixmaps + i); + + if (pExaScr->deferred_mixed_pixmap == pPixmap && + !pixmaps[i].as_dst && !pixmaps[i].pReg) + pExaScr->deferred_mixed_pixmap = NULL; + } + + pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + } +} + +void +exaMoveInPixmap_mixed(PixmapPtr pPixmap) +{ + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = NULL; + + exaDoMigration(pixmaps, 1, TRUE); +} + +void +exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + PixmapPtr pPixmap = closure; + ExaPixmapPriv(pPixmap); + + /* Move back results of software rendering on system memory copy of mixed driver + * pixmap (see exaPrepareAccessReg_mixed). + * + * Defer moving the destination back into the driver pixmap, to try and save + * overhead on multiple subsequent software fallbacks. + */ + if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) { + ExaScreenPriv(pPixmap->drawable.pScreen); + + if (pExaScr->deferred_mixed_pixmap && + pExaScr->deferred_mixed_pixmap != pPixmap) + exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap); + pExaScr->deferred_mixed_pixmap = pPixmap; + } +} + +/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we + * use the DownloadFromScreen hook to retrieve contents to a copy in system + * memory, perform software rendering on that and move back the results with the + * UploadToScreen hook (see exaDamageReport_mixed). + */ +void +exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg) +{ + ExaPixmapPriv(pPixmap); + Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + Bool success; + + success = ExaDoPrepareAccess(pPixmap, index); + + if (success && has_gpu_copy && pExaPixmap->pDamage) { + /* You cannot do accelerated operations while a buffer is mapped. */ + exaFinishAccess(&pPixmap->drawable, index); + /* Update the gpu view of both deferred destination pixmaps and of + * source pixmaps that were migrated with a bounding region. + */ + exaMoveInPixmap_mixed(pPixmap); + success = ExaDoPrepareAccess(pPixmap, index); + + if (success) { + /* We have a gpu pixmap that can be accessed, we don't need the cpu + * copy anymore. Drivers that prefer DFS, should fail prepare + * access. + */ + DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); + DamageDestroy(pExaPixmap->pDamage); + pExaPixmap->pDamage = NULL; + + free(pExaPixmap->sys_ptr); + pExaPixmap->sys_ptr = NULL; + + return; + } + } + + if (!success) { + ExaMigrationRec pixmaps[1]; + + /* Do we need to allocate our system buffer? */ + if (!pExaPixmap->sys_ptr) { + pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch * + pPixmap->drawable.height); + if (!pExaPixmap->sys_ptr) + FatalError("EXA: malloc failed for size %d bytes\n", + pExaPixmap->sys_pitch * pPixmap->drawable.height); + } + + if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + } else { + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + } + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = pReg; + + if (!pExaPixmap->pDamage && + (has_gpu_copy || !exaPixmapIsPinned(pPixmap))) { + Bool as_dst = pixmaps[0].as_dst; + + /* Set up damage tracking */ + pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL, + DamageReportNonEmpty, TRUE, + pPixmap->drawable.pScreen, + pPixmap); + + DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage); + /* This ensures that pending damage reflects the current operation. */ + /* This is used by exa to optimize migration. */ + DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE); + + if (has_gpu_copy) { + exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width, + pPixmap->drawable.height); + + /* We don't know which region of the destination will be damaged, + * have to assume all of it + */ + if (as_dst) { + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + pixmaps[0].pReg = NULL; + } + exaCopyDirtyToSys(pixmaps); + } + + if (as_dst) + exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width, + pPixmap->drawable.height); + } else if (has_gpu_copy) + exaCopyDirtyToSys(pixmaps); + + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + pPixmap->devKind = pExaPixmap->sys_pitch; + pExaPixmap->use_gpu_copy = FALSE; + } +} + diff --git a/xserver/exa/exa_mixed.c b/xserver/exa/exa_mixed.c new file mode 100644 index 000000000..21cc3bd13 --- /dev/null +++ b/xserver/exa/exa_mixed.c @@ -0,0 +1,291 @@ +/* + * Copyright © 2009 Maarten Maathuis + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <string.h> + +#include "exa_priv.h" +#include "exa.h" + +/* This file holds the driver allocated pixmaps + better initial placement code. + */ + +static _X_INLINE void* +ExaGetPixmapAddress(PixmapPtr p) +{ + ExaPixmapPriv(p); + + return pExaPixmap->sys_ptr; +} + +/** + * exaCreatePixmap() creates a new pixmap. + */ +PixmapPtr +exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint) +{ + PixmapPtr pPixmap; + ExaPixmapPrivPtr pExaPixmap; + int bpp; + size_t paddedWidth; + ExaScreenPriv(pScreen); + + if (w > 32767 || h > 32767) + return NullPixmap; + + swap(pExaScr, pScreen, CreatePixmap); + pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint); + swap(pExaScr, pScreen, CreatePixmap); + + if (!pPixmap) + return NULL; + + pExaPixmap = ExaGetPixmapPriv(pPixmap); + pExaPixmap->driverPriv = NULL; + + bpp = pPixmap->drawable.bitsPerPixel; + + paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); + if (paddedWidth / 4 > 32767 || h > 32767) + return NullPixmap; + + /* We will allocate the system pixmap later if needed. */ + pPixmap->devPrivate.ptr = NULL; + pExaPixmap->sys_ptr = NULL; + pExaPixmap->sys_pitch = paddedWidth; + + pExaPixmap->area = NULL; + pExaPixmap->fb_ptr = NULL; + pExaPixmap->pDamage = NULL; + + exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp); + exaSetAccelBlock(pExaScr, pExaPixmap, + w, h, bpp); + + (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, + paddedWidth, NULL); + + /* A scratch pixmap will become a driver pixmap right away. */ + if (!w || !h) { + exaCreateDriverPixmap_mixed(pPixmap); + pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + } else { + pExaPixmap->use_gpu_copy = FALSE; + + if (w == 1 && h == 1) { + pExaPixmap->sys_ptr = malloc((pPixmap->drawable.bitsPerPixel + 7) / 8); + + /* Set up damage tracking */ + pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL, + DamageReportNonEmpty, TRUE, + pPixmap->drawable.pScreen, + pPixmap); + + DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage); + /* This ensures that pending damage reflects the current operation. */ + /* This is used by exa to optimize migration. */ + DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE); + } + } + + /* During a fallback we must prepare access. */ + if (pExaScr->fallback_counter) + exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); + + return pPixmap; +} + +Bool +exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPrivPtr pExaScr; + ExaPixmapPrivPtr pExaPixmap; + Bool ret, has_gpu_copy; + + if (!pPixmap) + return FALSE; + + pExaScr = ExaGetScreenPriv(pScreen); + pExaPixmap = ExaGetPixmapPriv(pPixmap); + + if (pPixData) { + if (pExaPixmap->driverPriv) { + if (pExaPixmap->pDamage) { + DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); + DamageDestroy(pExaPixmap->pDamage); + pExaPixmap->pDamage = NULL; + } + + pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); + pExaPixmap->driverPriv = NULL; + } + + pExaPixmap->use_gpu_copy = FALSE; + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + } + + has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + + if (width <= 0) + width = pPixmap->drawable.width; + + if (height <= 0) + height = pPixmap->drawable.height; + + if (bitsPerPixel <= 0) { + if (depth <= 0) + bitsPerPixel = pPixmap->drawable.bitsPerPixel; + else + bitsPerPixel = BitsPerPixel(depth); + } + + if (depth <= 0) + depth = pPixmap->drawable.depth; + + if (width != pPixmap->drawable.width || + height != pPixmap->drawable.height || + depth != pPixmap->drawable.depth || + bitsPerPixel != pPixmap->drawable.bitsPerPixel) { + if (pExaPixmap->driverPriv) { + exaSetFbPitch(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + + exaSetAccelBlock(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + REGION_EMPTY(pScreen, &pExaPixmap->validFB); + } + + /* Need to re-create system copy if there's also a GPU copy */ + if (has_gpu_copy && pExaPixmap->sys_ptr) { + free(pExaPixmap->sys_ptr); + pExaPixmap->sys_ptr = NULL; + pExaPixmap->sys_pitch = devKind > 0 ? devKind : + PixmapBytePad(width, depth); + DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); + DamageDestroy(pExaPixmap->pDamage); + pExaPixmap->pDamage = NULL; + REGION_EMPTY(pScreen, &pExaPixmap->validSys); + + if (pExaScr->deferred_mixed_pixmap == pPixmap) + pExaScr->deferred_mixed_pixmap = NULL; + } + } + + if (has_gpu_copy) { + pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; + pPixmap->devKind = pExaPixmap->fb_pitch; + } else { + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + pPixmap->devKind = pExaPixmap->sys_pitch; + } + + /* Only pass driver pixmaps to the driver. */ + if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) { + ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData); + if (ret == TRUE) + goto out; + } + + swap(pExaScr, pScreen, ModifyPixmapHeader); + ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData); + swap(pExaScr, pScreen, ModifyPixmapHeader); + +out: + if (has_gpu_copy) { + pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->fb_pitch = pPixmap->devKind; + } else { + pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->sys_pitch = pPixmap->devKind; + } + /* Always NULL this, we don't want lingering pointers. */ + pPixmap->devPrivate.ptr = NULL; + + return ret; +} + +Bool +exaDestroyPixmap_mixed(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + Bool ret; + + if (pPixmap->refcnt == 1) + { + ExaPixmapPriv (pPixmap); + + /* During a fallback we must finish access, but we don't know the index. */ + if (pExaScr->fallback_counter) + exaFinishAccess(&pPixmap->drawable, -1); + + if (pExaScr->deferred_mixed_pixmap == pPixmap) + pExaScr->deferred_mixed_pixmap = NULL; + + if (pExaPixmap->driverPriv) + pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); + pExaPixmap->driverPriv = NULL; + + if (pExaPixmap->pDamage) { + if (pExaPixmap->sys_ptr) + free(pExaPixmap->sys_ptr); + pExaPixmap->sys_ptr = NULL; + pExaPixmap->pDamage = NULL; + } + } + + swap(pExaScr, pScreen, DestroyPixmap); + ret = pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + + return ret; +} + +Bool +exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + ExaPixmapPriv(pPixmap); + 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/xserver/exa/exa_offscreen.c b/xserver/exa/exa_offscreen.c index 4aaa2c132..e3a9ab2f6 100644 --- a/xserver/exa/exa_offscreen.c +++ b/xserver/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, largest_avail = 0; #if DEBUG_OFFSCREEN static int number = 0; ErrorF("================= ============ allocating a new pixmap %d\n", ++number); @@ -205,14 +202,14 @@ 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; + + if (area->size > largest_avail) + largest_avail = area->size; } if (!area) @@ -228,10 +225,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 +248,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 +281,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 +376,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 +396,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 +404,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 +447,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 +480,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->use_gpu_copy = TRUE; + + for (area = pExaScr->info->offScreenAreas->prev; + area != pExaScr->info->offScreenAreas; + ) + { + ExaOffscreenArea *prev = area->prev; + PixmapPtr pSrcPix; + ExaPixmapPrivPtr pExaSrcPix; + Bool save_use_gpu_copy; + int save_pitch; + + if (area->state != ExaOffscreenAvail || + prev->state == ExaOffscreenLocked || + (prev->state == ExaOffscreenRemovable && + prev->save != exaPixmapSave)) { + area = prev; + continue; + } + + if (prev->state == ExaOffscreenAvail) { + if (area == largest_available) { + largest_available = prev; + largest_size += prev->size; + } + area = prev; + ExaOffscreenMerge (pExaScr, area); + continue; + } + + if (area->size > largest_size) { + largest_available = area; + largest_size = area->size; + } + + pSrcPix = prev->privData; + pExaSrcPix = ExaGetPixmapPriv (pSrcPix); + + pExaDstPix->fb_ptr = pExaScr->info->memoryBase + + area->base_offset + area->size - prev->size + prev->base_offset - + prev->offset; + pExaDstPix->fb_ptr -= (unsigned long)pExaDstPix->fb_ptr % prev->align; + + if (pExaDstPix->fb_ptr <= pExaSrcPix->fb_ptr) { + area = prev; + continue; + } + + if (!(pExaScr->info->flags & EXA_SUPPORTS_OFFSCREEN_OVERLAPS) && + (pExaSrcPix->fb_ptr + prev->size) > pExaDstPix->fb_ptr) { + area = prev; + continue; + } + + save_use_gpu_copy = pExaSrcPix->use_gpu_copy; + save_pitch = pSrcPix->devKind; + + pExaSrcPix->use_gpu_copy = TRUE; + pSrcPix->devKind = pExaSrcPix->fb_pitch; + + pDstPix->drawable.width = pSrcPix->drawable.width; + pDstPix->devKind = pSrcPix->devKind; + pDstPix->drawable.height = pSrcPix->drawable.height; + pDstPix->drawable.depth = pSrcPix->drawable.depth; + pDstPix->drawable.bitsPerPixel = pSrcPix->drawable.bitsPerPixel; + + if (!pExaScr->info->PrepareCopy (pSrcPix, pDstPix, -1, -1, GXcopy, ~0)) { + pExaSrcPix->use_gpu_copy = save_use_gpu_copy; + pSrcPix->devKind = save_pitch; + area = prev; + continue; + } + + pExaScr->info->Copy (pDstPix, 0, 0, 0, 0, pDstPix->drawable.width, + pDstPix->drawable.height); + pExaScr->info->DoneCopy (pDstPix); + exaMarkSync (pScreen); + + DBG_OFFSCREEN(("Before swap: prev=0x%08x-0x%08x-0x%08x area=0x%08x-0x%08x-0x%08x\n", + prev->base_offset, prev->offset, prev->base_offset + prev->size, + area->base_offset, area->offset, area->base_offset + area->size)); + + /* Calculate swapped area offsets and sizes */ + area->base_offset = prev->base_offset; + area->offset = area->base_offset; + prev->offset += pExaDstPix->fb_ptr - pExaSrcPix->fb_ptr; + assert(prev->offset >= pExaScr->info->offScreenBase && + prev->offset < pExaScr->info->memorySize); + prev->base_offset = prev->offset; + if (area->next) + prev->size = area->next->base_offset - prev->base_offset; + else + prev->size = pExaScr->info->memorySize - prev->base_offset; + area->size = prev->base_offset - area->base_offset; + + DBG_OFFSCREEN(("After swap: area=0x%08x-0x%08x-0x%08x prev=0x%08x-0x%08x-0x%08x\n", + area->base_offset, area->offset, area->base_offset + area->size, + prev->base_offset, prev->offset, prev->base_offset + prev->size)); + + /* Swap areas in list */ + if (area->next) + area->next->prev = prev; + else + pExaScr->info->offScreenAreas->prev = prev; + if (prev->prev->next) + prev->prev->next = area; + else + pExaScr->info->offScreenAreas = area; + prev->next = area->next; + area->next = prev; + area->prev = prev->prev; + prev->prev = area; + if (!area->prev->next) + pExaScr->info->offScreenAreas = area; + +#if DEBUG_OFFSCREEN + if (prev->prev == prev || prev->next == prev) + ErrorF("Whoops, prev points to itself!\n"); + + if (area->prev == area || area->next == area) + ErrorF("Whoops, area points to itself!\n"); +#endif + + pExaSrcPix->fb_ptr = pExaDstPix->fb_ptr; + pExaSrcPix->use_gpu_copy = save_use_gpu_copy; + pSrcPix->devKind = save_pitch; + } + + pDstPix->drawable.width = 0; + pDstPix->drawable.height = 0; + pDstPix->drawable.depth = 0; + pDstPix->drawable.bitsPerPixel = 0; + + (*pScreen->DestroyPixmap) (pDstPix); + + if (area->state == ExaOffscreenAvail && area->size > largest_size) + return area; + + return largest_available; +} + +/** * exaOffscreenInit initializes the offscreen memory manager. * * @param pScreen current screen @@ -488,15 +663,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/xserver/exa/exa_priv.h b/xserver/exa/exa_priv.h index 0911c6d8a..21d964683 100644 --- a/xserver/exa/exa_priv.h +++ b/xserver/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; @@ -142,6 +165,7 @@ typedef struct { BitmapToRegionProcPtr SavedBitmapToRegion; CreateScreenResourcesProcPtr SavedCreateScreenResources; ModifyPixmapHeaderProcPtr SavedModifyPixmapHeader; + SourceValidateProcPtr SavedSourceValidate; #ifdef RENDER CompositeProcPtr SavedComposite; TrianglesProcPtr SavedTriangles; @@ -149,15 +173,44 @@ typedef struct { TrapezoidsProcPtr SavedTrapezoids; AddTrapsProcPtr SavedAddTraps; #endif - + void (*do_migration) (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel); + Bool (*pixmap_has_gpu_copy) (PixmapPtr pPixmap); + void (*do_move_in_pixmap) (PixmapPtr pPixmap); + void (*do_move_out_pixmap) (PixmapPtr pPixmap); + void (*prepare_access_reg)(PixmapPtr pPixmap, int index, RegionPtr pReg); + Bool swappedOut; enum ExaMigrationHeuristic migration; Bool checkDirtyCorrectness; unsigned disableFbCount; Bool optimize_migration; unsigned offScreenCounter; + unsigned numOffscreenAvailable; + CARD32 lastDefragment; + CARD32 nextDefragment; + PixmapPtr deferred_mixed_pixmap; + + /* Reference counting for accessed pixmaps */ + struct { + PixmapPtr pixmap; + int count; + Bool retval; + } access[EXA_NUM_PREPARE_INDICES]; + + /* Holds information on fallbacks that cannot be relayed otherwise. */ + unsigned int fallback_flags; + unsigned int fallback_counter; ExaGlyphCacheRec glyphCaches[EXA_NUM_GLYPH_CACHES]; + + /** + * Regions affected by fallback composite source / mask operations. + */ + + RegionRec srcReg; + RegionRec maskReg; + PixmapPtr srcPix; + } ExaScreenPrivRec, *ExaScreenPrivPtr; /* @@ -174,9 +227,48 @@ 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_PRE_FALLBACK(_screen_) \ + ExaScreenPriv(_screen_); \ + pExaScr->fallback_counter++; + +#define EXA_POST_FALLBACK(_screen_) \ + pExaScr->fallback_counter--; + +#define EXA_PRE_FALLBACK_GC(_gc_) \ + ExaScreenPriv(_gc_->pScreen); \ + ExaGCPriv(_gc_); \ + pExaScr->fallback_counter++; \ + swap(pExaGC, _gc_, ops); + +#define EXA_POST_FALLBACK_GC(_gc_) \ + pExaScr->fallback_counter--; \ + swap(pExaGC, _gc_, ops); + /** Align an offset to an arbitrary alignment */ #define EXA_ALIGN(offset, align) (((offset) + (align) - 1) - \ (((offset) + (align) - 1) % (align))) @@ -201,7 +293,7 @@ extern DevPrivateKey exaPixmapPrivateKey; typedef struct { ExaOffscreenArea *area; int score; /**< score for the move-in vs move-out heuristic */ - Bool offscreen; + Bool use_gpu_copy; CARD8 *sys_ptr; /**< pointer to pixmap data in system memory */ int sys_pitch; /**< pitch of pixmap in system memory */ @@ -237,17 +329,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 +374,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 +424,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 +469,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 +522,9 @@ ExaOffscreenSwapOut (ScreenPtr pScreen); void ExaOffscreenSwapIn (ScreenPtr pScreen); +ExaOffscreenArea* +ExaOffscreenDefragment (ScreenPtr pScreen); + Bool exaOffscreenInit(ScreenPtr pScreen); @@ -395,11 +532,8 @@ void ExaOffscreenFini (ScreenPtr pScreen); /* exa.c */ -void -ExaDoPrepareAccess(DrawablePtr pDrawable, int index); - -void -exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg); +Bool +ExaDoPrepareAccess(PixmapPtr pPixmap, int index); void exaPrepareAccess(DrawablePtr pDrawable, int index); @@ -415,7 +549,7 @@ exaGetDrawableDeltas (DrawablePtr pDrawable, PixmapPtr pPixmap, int *xp, int *yp); Bool -exaPixmapIsOffscreen(PixmapPtr p); +exaPixmapHasGpuCopy(PixmapPtr p); PixmapPtr exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp); @@ -423,22 +557,82 @@ 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 +exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap); + +/* exa_driver.c */ +PixmapPtr +exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint); + +Bool +exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData); + +Bool +exaDestroyPixmap_driver (PixmapPtr pPixmap); + +Bool +exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap); + +/* exa_mixed.c */ +PixmapPtr +exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint); + +Bool +exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData); + +Bool +exaDestroyPixmap_mixed(PixmapPtr pPixmap); + +Bool +exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap); + +/* exa_migration_mixed.c */ +void +exaCreateDriverPixmap_mixed(PixmapPtr pPixmap); + +void +exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel); + +void +exaMoveInPixmap_mixed(PixmapPtr pPixmap); + +void +exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure); + +void +exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg); /* exa_render.c */ Bool @@ -461,6 +655,7 @@ exaComposite(CARD8 op, void exaCompositeRects(CARD8 op, PicturePtr Src, + PicturePtr pMask, PicturePtr pDst, int nrect, ExaCompositeRectPtr rects); @@ -493,11 +688,26 @@ exaGlyphs (CARD8 op, GlyphListPtr list, GlyphPtr *glyphs); -/* exa_migration.c */ +/* exa_migration_classic.c */ void -exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel); +exaCopyDirtyToSys (ExaMigrationPtr migrate); + +void +exaCopyDirtyToFb (ExaMigrationPtr migrate); + +void +exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel); void exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area); +void +exaMoveOutPixmap_classic (PixmapPtr pPixmap); + +void +exaMoveInPixmap_classic (PixmapPtr pPixmap); + +void +exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg); + #endif /* EXAPRIV_H */ diff --git a/xserver/exa/exa_render.c b/xserver/exa/exa_render.c index 8c6bbf0f6..1b68e1cdc 100644 --- a/xserver/exa/exa_render.c +++ b/xserver/exa/exa_render.c @@ -54,6 +54,12 @@ static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n) case PICT_x8r8g8b8: snprintf(format, 20, "XRGB8888"); break; + case PICT_b8g8r8a8: + snprintf(format, 20, "BGRA8888"); + break; + case PICT_b8g8r8x8: + snprintf(format, 20, "BGRX8888"); + break; case PICT_r5g6b5: snprintf(format, 20, "RGB565 "); break; @@ -71,11 +77,17 @@ static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n) break; } - loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; + if (pict->pDrawable) { + loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; + + snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, + pict->pDrawable->height, pict->repeat ? + " R" : ""); + } else { + loc = '-'; - snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, - pict->pDrawable->height, pict->repeat ? - " R" : ""); + snprintf(size, 20, "%s", pict->repeat ? " R" : ""); + } snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size); } @@ -138,32 +150,26 @@ exaGetPixelFromRGBA(CARD32 *pixel, CARD16 green, CARD16 blue, CARD16 alpha, - CARD32 format) + PictFormatPtr pFormat) { int rbits, bbits, gbits, abits; int rshift, bshift, gshift, ashift; *pixel = 0; - if (!PICT_FORMAT_COLOR(format)) + if (!PICT_FORMAT_COLOR(pFormat->format) && + PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A) return FALSE; - rbits = PICT_FORMAT_R(format); - gbits = PICT_FORMAT_G(format); - bbits = PICT_FORMAT_B(format); - abits = PICT_FORMAT_A(format); + rbits = PICT_FORMAT_R(pFormat->format); + gbits = PICT_FORMAT_G(pFormat->format); + bbits = PICT_FORMAT_B(pFormat->format); + abits = PICT_FORMAT_A(pFormat->format); - if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { - bshift = 0; - gshift = bbits; - rshift = gshift + gbits; - ashift = rshift + rbits; - } else { /* PICT_TYPE_ABGR */ - rshift = 0; - gshift = rbits; - bshift = gshift + gbits; - ashift = bshift + bbits; - } + rshift = pFormat->direct.red; + gshift = pFormat->direct.green; + bshift = pFormat->direct.blue; + ashift = pFormat->direct.alpha; *pixel |= ( blue >> (16 - bbits)) << bshift; *pixel |= ( red >> (16 - rbits)) << rshift; @@ -179,12 +185,13 @@ exaGetRGBAFromPixel(CARD32 pixel, CARD16 *green, CARD16 *blue, CARD16 *alpha, - CARD32 format) + PictFormatPtr pFormat, + PictFormatShort format) { int rbits, bbits, gbits, abits; int rshift, bshift, gshift, ashift; - if (!PICT_FORMAT_COLOR(format)) + if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A) return FALSE; rbits = PICT_FORMAT_R(format); @@ -192,34 +199,42 @@ exaGetRGBAFromPixel(CARD32 pixel, bbits = PICT_FORMAT_B(format); abits = PICT_FORMAT_A(format); - if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { + if (pFormat) { + rshift = pFormat->direct.red; + gshift = pFormat->direct.green; + bshift = pFormat->direct.blue; + ashift = pFormat->direct.alpha; + } else if (format == PICT_a8r8g8b8) { + rshift = 16; + gshift = 8; bshift = 0; - gshift = bbits; - rshift = gshift + gbits; - ashift = rshift + rbits; - } else { /* PICT_TYPE_ABGR */ - rshift = 0; - gshift = rbits; - bshift = gshift + gbits; - ashift = bshift + bbits; - } - - *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); - while (rbits < 16) { - *red |= *red >> rbits; - rbits <<= 1; - } + ashift = 24; + } else + FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match " + "createSourcePicture()\n"); + + if (rbits) { + *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); + while (rbits < 16) { + *red |= *red >> rbits; + rbits <<= 1; + } - *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); - while (gbits < 16) { - *green |= *green >> gbits; - gbits <<= 1; - } + *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); + while (gbits < 16) { + *green |= *green >> gbits; + gbits <<= 1; + } - *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); - while (bbits < 16) { - *blue |= *blue >> bbits; - bbits <<= 1; + *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); + while (bbits < 16) { + *blue |= *blue >> bbits; + bbits <<= 1; + } + } else { + *red = 0x0000; + *green = 0x0000; + *blue = 0x0000; } if (abits) { @@ -250,28 +265,26 @@ exaTryDriverSolidFill(PicturePtr pSrc, int nbox; int dst_off_x, dst_off_y; PixmapPtr pSrcPix, pDstPix; - ExaPixmapPrivPtr pSrcExaPix, pDstExaPix; + ExaPixmapPrivPtr pDstExaPix; CARD32 pixel; CARD16 red, green, blue, alpha; - ExaMigrationRec pixmaps[1]; pDstPix = exaGetDrawablePixmap (pDst->pDrawable); - pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); - - pSrcExaPix = ExaGetPixmapPriv(pSrcPix); pDstExaPix = ExaGetPixmapPriv(pDstPix); - /* Check whether the accelerator can use these pixmaps. + /* Check whether the accelerator can use the destination pixmap. */ - if (pSrcExaPix->accel_blocked || pDstExaPix->accel_blocked) + if (pDstExaPix->accel_blocked) { return -1; } xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; + if (pSrc->pDrawable) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + } if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, xSrc, ySrc, 0, 0, xDst, yDst, @@ -282,31 +295,34 @@ exaTryDriverSolidFill(PicturePtr pSrc, REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); - pixel = exaGetPixmapFirstPixel (pSrcPix); - - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pDstPix; - pixmaps[0].pReg = ®ion; - exaDoMigration(pixmaps, 1, TRUE); - - if (!exaPixmapIsOffscreen(pDstPix)) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 0; - } + if (pSrc->pDrawable) { + pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); + pixel = exaGetPixmapFirstPixel (pSrcPix); + } else + pixel = pSrc->pSourcePict->solidFill.color; if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha, - pSrc->format)) + pSrc->pFormat, pSrc->format) || + !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, + pDst->pFormat)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return -1; } - if (!exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, - pDst->format)) - { + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pDstPix; + pixmaps[0].pReg = ®ion; + exaDoMigration(pixmaps, 1, TRUE); + } + + if (!exaPixmapHasGpuCopy(pDstPix)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return -1; + return 0; } if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) @@ -334,22 +350,29 @@ 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 = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0; + int dst_off_x, dst_off_y; + PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; + ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; if (!pExaScr->info->PrepareComposite) return -1; - pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); - pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + if (pSrc->pDrawable) { + pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); + pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + } + + if (pMask && pMask->pDrawable) { + pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); + pMaskExaPix = ExaGetPixmapPriv(pMaskPix); + } pDstPix = exaGetDrawablePixmap(pDst->pDrawable); pDstExaPix = ExaGetPixmapPriv(pDstPix); @@ -358,61 +381,92 @@ 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 (pDstExaPix->accel_blocked || + (pSrcExaPix && pSrcExaPix->accel_blocked) || + (pMaskExaPix && 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); - - pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); - if (!exaPixmapIsOffscreen(pDstPix)) - return 0; - - if (!pSrcPix && pExaScr->info->UploadToScratch) - { - pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); - if ((*pExaScr->info->UploadToScratch) (pSrcPix, &scratch)) - pSrcPix = &scratch; + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[3]; + int i = 0; + + pixmaps[i].as_dst = TRUE; + pixmaps[i].as_src = exaOpReadsDestination(op); + pixmaps[i].pPix = pDstPix; + pixmaps[i].pReg = NULL; + i++; + + if (pSrcPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pSrcPix; + pixmaps[i].pReg = NULL; + i++; + } + + if (pMaskPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pMaskPix; + pixmaps[i].pReg = NULL; + i++; + } + + exaDoMigration(pixmaps, i, TRUE); } - if (!pSrcPix) + pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); + if (!pDstPix) return 0; - if (!(*pExaScr->info->PrepareComposite) (op, pSrc, NULL, pDst, pSrcPix, - NULL, pDstPix)) + if (pSrcPix) { + pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + if (!pSrcPix) + return 0; + } + + if (pMaskPix) { + 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 xSrc = rects->xSrc + pSrc->pDrawable->x; - INT16 ySrc = rects->ySrc + pSrc->pDrawable->y; - + INT16 xMask = rects->xMask; + INT16 yMask = rects->yMask; + INT16 xSrc = rects->xSrc; + INT16 ySrc = rects->ySrc; RegionRec region; BoxPtr pbox; int nbox; - if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, - xSrc, ySrc, 0, 0, xDst, yDst, + if (pMaskPix) { + xMask += pMask->pDrawable->x; + yMask += pMask->pDrawable->y; + } + + if (pSrcPix) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + } + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, rects->width, rects->height)) goto next_rect; @@ -421,6 +475,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 +485,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 +508,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; @@ -480,7 +540,7 @@ exaCompositeRects(CARD8 op, /* We have to manage the damage ourselves, since CompositeRects isn't * something in the screen that can be managed by the damage extension, * and EXA depends on damage to track what needs to be migrated between - * offscreen and onscreen. + * the gpu and the cpu. */ /* Compute the overall extents of the composited region - we're making @@ -526,24 +586,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. */ @@ -571,18 +651,18 @@ exaTryDriverComposite(CARD8 op, BoxPtr pbox; int nbox; int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; - PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; - ExaPixmapPrivPtr pSrcExaPix, pMaskExaPix = NULL, pDstExaPix; - struct _Pixmap scratch; - ExaMigrationRec pixmaps[3]; + PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; + ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; - pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); - pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + if (pSrc->pDrawable) { + pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); + pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + } pDstPix = exaGetDrawablePixmap(pDst->pDrawable); pDstExaPix = ExaGetPixmapPriv(pDstPix); - if (pMask) { + if (pMask && pMask->pDrawable) { pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); pMaskExaPix = ExaGetPixmapPriv(pMaskPix); } @@ -591,9 +671,9 @@ exaTryDriverComposite(CARD8 op, * FIXME: If it cannot, use temporary pixmaps so that the drawing * happens within limits. */ - if (pSrcExaPix->accel_blocked || - pDstExaPix->accel_blocked || - (pMask && (pMaskExaPix->accel_blocked))) + if (pDstExaPix->accel_blocked || + (pSrcExaPix && pSrcExaPix->accel_blocked) || + (pMaskExaPix && (pMaskExaPix->accel_blocked))) { return -1; } @@ -601,13 +681,15 @@ exaTryDriverComposite(CARD8 op, xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; - if (pMask) { + if (pMaskPix) { xMask += pMask->pDrawable->x; yMask += pMask->pDrawable->y; } - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; + if (pSrcPix) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + } if (pExaScr->info->CheckComposite && !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) @@ -624,45 +706,53 @@ exaTryDriverComposite(CARD8 op, REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = exaOpReadsDestination(op); - pixmaps[0].pPix = pDstPix; - pixmaps[0].pReg = pixmaps[0].as_src ? NULL : ®ion; - pixmaps[1].as_dst = FALSE; - pixmaps[1].as_src = TRUE; - pixmaps[1].pPix = pSrcPix; - pixmaps[1].pReg = NULL; - if (pMask) { - pixmaps[2].as_dst = FALSE; - pixmaps[2].as_src = TRUE; - pixmaps[2].pPix = pMaskPix; - pixmaps[2].pReg = NULL; - exaDoMigration(pixmaps, 3, TRUE); - } else { - exaDoMigration(pixmaps, 2, TRUE); - } + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[3]; + int i = 0; + + pixmaps[i].as_dst = TRUE; + pixmaps[i].as_src = exaOpReadsDestination(op); + pixmaps[i].pPix = pDstPix; + pixmaps[i].pReg = pixmaps[0].as_src ? NULL : ®ion; + i++; + + if (pSrcPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pSrcPix; + pixmaps[i].pReg = NULL; + i++; + } - pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); - if (pMask) - pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, - &mask_off_y); + if (pMaskPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pMaskPix; + pixmaps[i].pReg = NULL; + i++; + } - if (!exaPixmapIsOffscreen(pDstPix)) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 0; + exaDoMigration(pixmaps, i, TRUE); } - 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) { + pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + if (!pSrcPix) { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 0; + } } - if (!pSrcPix || (pMask && !pMaskPix)) { + if (pMaskPix) { + pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, + &mask_off_y); + if (!pMaskPix) { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 0; + } + } + + if (!exaPixmapHasGpuCopy(pDstPix)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return 0; } @@ -813,44 +903,46 @@ exaComposite(CARD8 op, Bool saveMaskRepeat = pMask ? pMask->repeat : 0; RegionRec region; - /* We currently don't support acceleration of gradients, or other pictures - * with a NULL pDrawable. - */ - if (pExaScr->swappedOut || - pSrc->pDrawable == NULL || (pMask != NULL && pMask->pDrawable == NULL)) - { + if (pExaScr->swappedOut) goto fallback; - } /* Remove repeat in source if useless */ - if (pSrc->repeat && !pSrc->transform && xSrc >= 0 && + if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 && (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && (ySrc + height) <= pSrc->pDrawable->height) pSrc->repeat = 0; - if (!pMask) + if (!pMask && !pSrc->alphaMap && !pDst->alphaMap && + (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) { - if ((op == PictOpSrc && - ((pSrc->format == pDst->format) || - (pSrc->format==PICT_a8r8g8b8 && pDst->format==PICT_x8r8g8b8) || - (pSrc->format==PICT_a8b8g8r8 && pDst->format==PICT_x8b8g8r8))) || - (op == PictOpOver && !pSrc->alphaMap && !pDst->alphaMap && - pSrc->format == pDst->format && - (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8))) + if (pSrc->pDrawable ? + (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && + pSrc->repeat) : + (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) { - if (pSrc->pDrawable->width == 1 && - pSrc->pDrawable->height == 1 && - pSrc->repeat) - { - ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, - width, height); - if (ret == 1) - goto done; - } - else if (pSrc->pDrawable != NULL && - !pSrc->repeat && - !pSrc->transform) + ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, + width, height); + if (ret == 1) + goto done; + } else if (pSrc->pDrawable && !pSrc->transform && + ((op == PictOpSrc && + (pSrc->format == pDst->format || + (PICT_FORMAT_COLOR(pDst->format) && + PICT_FORMAT_COLOR(pSrc->format) && + pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format), + PICT_FORMAT_TYPE(pSrc->format), + 0, + PICT_FORMAT_R(pSrc->format), + PICT_FORMAT_G(pSrc->format), + PICT_FORMAT_B(pSrc->format))))) || + (op == PictOpOver && pSrc->format == pDst->format && + !PICT_FORMAT_A(pSrc->format)))) + { + if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 && + (xSrc + width <= pSrc->pDrawable->width) && + (ySrc + height <= pSrc->pDrawable->height)) { + Bool ret; xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; xSrc += pSrc->pDrawable->x; @@ -861,18 +953,25 @@ 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 && - pSrc->pDrawable->type == DRAWABLE_PIXMAP && - !pSrc->transform && - pSrc->repeatType == RepeatNormal) + + if (pSrc->repeat && pSrc->repeatType == RepeatNormal && + pSrc->pDrawable->type == DRAWABLE_PIXMAP) { DDXPointRec patOrg; @@ -922,9 +1021,9 @@ exaComposite(CARD8 op, } /* Remove repeat in mask if useless */ - if (pMask && pMask->repeat && !pMask->transform && xMask >= 0 && - (xMask + width) <= pMask->pDrawable->width && yMask >= 0 && - (yMask + height) <= pMask->pDrawable->height) + if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform && + xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && + yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) pMask->repeat = 0; if (pExaScr->info->PrepareComposite && @@ -940,9 +1039,10 @@ exaComposite(CARD8 op, /* For generic masks and solid src pictures, mach64 can do Over in two * passes, similar to the component-alpha case. */ - isSrcSolid = pSrc->pDrawable->width == 1 && - pSrc->pDrawable->height == 1 && - pSrc->repeat; + isSrcSolid = pSrc->pDrawable ? + (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && + pSrc->repeat) : + (pSrc->pSourcePict->type == SourcePictTypeSolidFill); /* If we couldn't do the Composite in a single pass, and it was a * component-alpha Over, see if we can do it in two passes with @@ -1063,7 +1163,6 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) return; - xDst = traps[0].left.p1.x >> 16; yDst = traps[0].left.p1.y >> 16; diff --git a/xserver/exa/exa_unaccel.c b/xserver/exa/exa_unaccel.c index a515bac1f..8d7009813 100644 --- a/xserver/exa/exa_unaccel.c +++ b/xserver/exa/exa_unaccel.c @@ -74,22 +74,26 @@ void ExaCheckFillSpans (DrawablePtr pDrawable, GCPtr pGC, int nspans, DDXPointPtr ppt, int *pwidth, int fSorted) { + EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC (pGC); - fbFillSpans (pDrawable, pGC, nspans, ppt, pwidth, fSorted); + pGC->ops->FillSpans (pDrawable, pGC, nspans, ppt, pwidth, fSorted); exaFinishAccessGC (pGC); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_POST_FALLBACK_GC(pGC); } void ExaCheckSetSpans (DrawablePtr pDrawable, GCPtr pGC, char *psrc, DDXPointPtr ppt, int *pwidth, int nspans, int fSorted) { + EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); - fbSetSpans (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); + pGC->ops->SetSpans (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_POST_FALLBACK_GC(pGC); } void @@ -97,32 +101,120 @@ ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int leftPad, int format, char *bits) { - ExaPixmapPriv(exaGetDrawablePixmap(pDrawable)); + PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); + ExaPixmapPriv(pPixmap); + EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); - if (exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle, + if (!pExaScr->prepare_access_reg || !pExaPixmap->pDamage || + exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle, pGC->alu, pGC->clientClipType)) exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); else - exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pExaPixmap->pDamage ? - DamagePendingRegion(pExaPixmap->pDamage) : NULL); - fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); + pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST, + DamagePendingRegion(pExaPixmap->pDamage)); + pGC->ops->PutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_POST_FALLBACK_GC(pGC); } +void +ExaCheckCopyNtoN (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + BoxPtr pbox, int nbox, int dx, int dy, Bool reverse, + Bool upsidedown, Pixel bitplane, void *closure) +{ + RegionRec reg; + int xoff, yoff; + EXA_PRE_FALLBACK_GC(pGC); + EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst, + exaDrawableLocation(pSrc), exaDrawableLocation(pDst))); + + if (pExaScr->prepare_access_reg) { + PixmapPtr pPixmap = exaGetDrawablePixmap(pSrc); + + exaGetDrawableDeltas(pSrc, pPixmap, &xoff, &yoff); + REGION_INIT(pScreen, ®, pbox, nbox); + REGION_TRANSLATE(pScreen, ®, xoff + dx, yoff + dy); + pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, ®); + REGION_UNINIT(pScreen, ®); + } else + exaPrepareAccess (pSrc, EXA_PREPARE_SRC); + + if (pExaScr->prepare_access_reg && + !exaGCReadsDestination(pDst, pGC->planemask, pGC->fillStyle, + pGC->alu, pGC->clientClipType)) { + PixmapPtr pPixmap = exaGetDrawablePixmap(pDst); + + exaGetDrawableDeltas(pSrc, pPixmap, &xoff, &yoff); + REGION_INIT(pScreen, ®, pbox, nbox); + REGION_TRANSLATE(pScreen, ®, xoff, yoff); + pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST, ®); + REGION_UNINIT(pScreen, ®); + } else + exaPrepareAccess (pDst, EXA_PREPARE_DEST); + + /* This will eventually call fbCopyNtoN, with some calculation overhead. */ + while (nbox--) { + pGC->ops->CopyArea (pSrc, pDst, pGC, pbox->x1 - pSrc->x + dx, pbox->y1 - pSrc->y + dy, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, pbox->x1 - pDst->x, pbox->y1 - pDst->y); + pbox++; + } + exaFinishAccess (pSrc, EXA_PREPARE_SRC); + exaFinishAccess (pDst, EXA_PREPARE_DEST); + EXA_POST_FALLBACK_GC(pGC); +} + +static void +ExaFallbackPrepareReg(DrawablePtr pDrawable, + GCPtr pGC, + int x, int y, int width, int height, + int index, Bool checkReads) +{ + ScreenPtr pScreen = pDrawable->pScreen; + ExaScreenPriv(pScreen); + + if (pExaScr->prepare_access_reg && + !(checkReads && exaGCReadsDestination(pDrawable, + pGC->planemask, + pGC->fillStyle, + pGC->alu, + pGC->clientClipType))) { + BoxRec box; + RegionRec reg; + int xoff, yoff; + PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); + + exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); + box.x1 = pDrawable->x + x + xoff; + box.y1 = pDrawable->y + y + yoff; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + + REGION_INIT(pScreen, ®, &box, 1); + pExaScr->prepare_access_reg(pPixmap, index, ®); + REGION_UNINIT(pScreen, ®); + } else + exaPrepareAccess(pDrawable, index); +} + + RegionPtr ExaCheckCopyArea (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty) { RegionPtr ret; + EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst, exaDrawableLocation(pSrc), exaDrawableLocation(pDst))); - exaPrepareAccess (pDst, EXA_PREPARE_DEST); - exaPrepareAccess (pSrc, EXA_PREPARE_SRC); - ret = fbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); + ExaFallbackPrepareReg(pSrc, pGC, srcx, srcy, w, h, + EXA_PREPARE_SRC, FALSE); + ExaFallbackPrepareReg(pDst, pGC, dstx, dsty, w, h, + EXA_PREPARE_DEST, TRUE); + ret = pGC->ops->CopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); exaFinishAccess (pSrc, EXA_PREPARE_SRC); exaFinishAccess (pDst, EXA_PREPARE_DEST); + EXA_POST_FALLBACK_GC(pGC); return ret; } @@ -134,14 +226,18 @@ ExaCheckCopyPlane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, { RegionPtr ret; + EXA_PRE_FALLBACK_GC(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, + ExaFallbackPrepareReg(pSrc, pGC, srcx, srcy, w, h, + EXA_PREPARE_SRC, FALSE); + ExaFallbackPrepareReg(pDst, pGC, dstx, dsty, w, h, + EXA_PREPARE_DEST, TRUE); + ret = pGC->ops->CopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, bitPlane); exaFinishAccess (pSrc, EXA_PREPARE_SRC); exaFinishAccess (pDst, EXA_PREPARE_DEST); + EXA_POST_FALLBACK_GC(pGC); return ret; } @@ -150,85 +246,75 @@ void ExaCheckPolyPoint (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr pptInit) { + EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); - fbPolyPoint (pDrawable, pGC, mode, npt, pptInit); + pGC->ops->PolyPoint (pDrawable, pGC, mode, npt, pptInit); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_POST_FALLBACK_GC(pGC); } void ExaCheckPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppt) { + EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n", pDrawable, exaDrawableLocation(pDrawable), pGC->lineWidth, mode, npt)); - 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_POST_FALLBACK_GC(pGC); } void ExaCheckPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nsegInit, xSegment *pSegInit) { + EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable, exaDrawableLocation(pDrawable), pGC->lineWidth, nsegInit)); - 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_POST_FALLBACK_GC(pGC); } void ExaCheckPolyArc (DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *pArcs) { + EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); - /* 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_POST_FALLBACK_GC(pGC); } void ExaCheckPolyFillRect (DrawablePtr pDrawable, GCPtr pGC, int nrect, xRectangle *prect) { + EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC (pGC); - fbPolyFillRect (pDrawable, pGC, nrect, prect); + pGC->ops->PolyFillRect (pDrawable, pGC, nrect, prect); exaFinishAccessGC (pGC); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + EXA_POST_FALLBACK_GC(pGC); } void @@ -236,13 +322,15 @@ ExaCheckImageGlyphBlt (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase) { + EXA_PRE_FALLBACK_GC(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_POST_FALLBACK_GC(pGC); } void @@ -250,13 +338,15 @@ ExaCheckPolyGlyphBlt (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase) { + EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable, exaDrawableLocation(pDrawable), pGC->fillStyle, pGC->alu)); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC (pGC); - 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_POST_FALLBACK_GC(pGC); } void @@ -264,16 +354,65 @@ ExaCheckPushPixels (GCPtr pGC, PixmapPtr pBitmap, DrawablePtr pDrawable, int w, int h, int x, int y) { + EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable, exaDrawableLocation(&pBitmap->drawable), exaDrawableLocation(pDrawable))); - exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); - exaPrepareAccess (&pBitmap->drawable, EXA_PREPARE_SRC); + ExaFallbackPrepareReg(pDrawable, pGC, x, y, w, h, + EXA_PREPARE_DEST, TRUE); + ExaFallbackPrepareReg(&pBitmap->drawable, pGC, 0, 0, w, h, + EXA_PREPARE_SRC, FALSE); exaPrepareAccessGC (pGC); - 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_POST_FALLBACK_GC(pGC); +} + +void +ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + DrawablePtr pDrawable = &pWin->drawable; + ScreenPtr pScreen = pDrawable->pScreen; + EXA_PRE_FALLBACK(pScreen); + EXA_FALLBACK(("from %p\n", pWin)); + + /* Only need the source bits, the destination region will be overwritten */ + if (pExaScr->prepare_access_reg) { + PixmapPtr pPixmap = pScreen->GetWindowPixmap(pWin); + int xoff, yoff; + + exaGetDrawableDeltas(&pWin->drawable, pPixmap, &xoff, &yoff); + REGION_TRANSLATE(pScreen, prgnSrc, xoff, yoff); + pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, prgnSrc); + REGION_TRANSLATE(pScreen, prgnSrc, -xoff, -yoff); + } else + exaPrepareAccess(pDrawable, EXA_PREPARE_SRC); + + swap(pExaScr, pScreen, CopyWindow); + pScreen->CopyWindow (pWin, ptOldOrg, prgnSrc); + swap(pExaScr, pScreen, CopyWindow); + exaFinishAccess (pDrawable, EXA_PREPARE_SRC); + EXA_POST_FALLBACK(pScreen); +} + +void +ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *d) +{ + ScreenPtr pScreen = pDrawable->pScreen; + EXA_PRE_FALLBACK(pScreen); + EXA_FALLBACK(("from %p (%c)\n", pDrawable, + exaDrawableLocation(pDrawable))); + + ExaFallbackPrepareReg(pDrawable, NULL, x, y, w, h, + EXA_PREPARE_SRC, FALSE); + swap(pExaScr, pScreen, GetImage); + pScreen->GetImage (pDrawable, x, y, w, h, format, planeMask, d); + swap(pExaScr, pScreen, GetImage); + exaFinishAccess (pDrawable, EXA_PREPARE_SRC); + EXA_POST_FALLBACK(pScreen); } void @@ -284,10 +423,185 @@ ExaCheckGetSpans (DrawablePtr pDrawable, int nspans, char *pdstStart) { + ScreenPtr pScreen = pDrawable->pScreen; + + EXA_PRE_FALLBACK(pScreen); EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess (pDrawable, EXA_PREPARE_SRC); - 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); + EXA_POST_FALLBACK(pScreen); +} + +static void +ExaSrcValidate(DrawablePtr pDrawable, + int x, + int y, + int width, + int height) +{ + ScreenPtr pScreen = pDrawable->pScreen; + ExaScreenPriv(pScreen); + PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); + BoxRec box; + RegionRec reg; + RegionPtr dst; + int xoff, yoff; + + exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff); + + box.x1 = x + xoff; + box.y1 = y + yoff; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + + dst = (pExaScr->srcPix == pPix) ? &pExaScr->srcReg : + &pExaScr->maskReg; + + REGION_INIT(pScreen, ®, &box, 1); + REGION_UNION(pScreen, dst, dst, ®); + REGION_UNINIT(pScreen, ®); + + if (pExaScr->SavedSourceValidate) { + swap(pExaScr, pScreen, SourceValidate); + pScreen->SourceValidate(pDrawable, x, y, width, height); + swap(pExaScr, pScreen, SourceValidate); + } +} + +static Bool +ExaPrepareCompositeReg(ScreenPtr pScreen, + CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + RegionRec region; + RegionPtr dstReg = NULL; + RegionPtr srcReg = NULL; + RegionPtr maskReg = NULL; + PixmapPtr pSrcPix = NULL; + PixmapPtr pMaskPix = NULL; + PixmapPtr pDstPix; + ExaScreenPriv(pScreen); + Bool ret; + + + REGION_NULL(pScreen, ®ion); + + if (pSrc->pDrawable) { + pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); + REGION_NULL(pScreen, &pExaScr->srcReg); + srcReg = &pExaScr->srcReg; + pExaScr->srcPix = pSrcPix; + if (pSrc != pDst) + REGION_TRANSLATE(pScreen, pSrc->pCompositeClip, + -pSrc->pDrawable->x, + -pSrc->pDrawable->y); + } + + if (pMask && pMask->pDrawable) { + pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); + REGION_NULL(pScreen, &pExaScr->maskReg); + maskReg = &pExaScr->maskReg; + if (pMask != pDst && pMask != pSrc) + REGION_TRANSLATE(pScreen, pMask->pCompositeClip, + -pMask->pDrawable->x, + -pMask->pDrawable->y); + } + + REGION_TRANSLATE(pScreen, pDst->pCompositeClip, + -pDst->pDrawable->x, + -pDst->pDrawable->y); + + pExaScr->SavedSourceValidate = ExaSrcValidate; + swap(pExaScr, pScreen, SourceValidate); + ret = miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, + xDst, + yDst, + width, height); + swap(pExaScr, pScreen, SourceValidate); + + REGION_TRANSLATE(pScreen, pDst->pCompositeClip, + pDst->pDrawable->x, + pDst->pDrawable->y); + if (pSrc->pDrawable && pSrc != pDst) + REGION_TRANSLATE(pScreen, pSrc->pCompositeClip, + pSrc->pDrawable->x, + pSrc->pDrawable->y); + if (pMask && pMask->pDrawable && pMask != pDst && pMask != pSrc) + REGION_TRANSLATE(pScreen, pMask->pCompositeClip, + pMask->pDrawable->x, + pMask->pDrawable->y); + + if (!ret) { + if (srcReg) + REGION_UNINIT(pScreen, srcReg); + if (maskReg) + REGION_UNINIT(pScreen, maskReg); + + return FALSE; + } + + /** + * Don't limit alphamaps readbacks for now until we've figured out how that + * should be done. + */ + + if (pSrc->alphaMap && pSrc->alphaMap->pDrawable) + pExaScr->prepare_access_reg(exaGetDrawablePixmap(pSrc->alphaMap->pDrawable), + EXA_PREPARE_AUX_SRC, + NULL); + if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable) + pExaScr->prepare_access_reg(exaGetDrawablePixmap(pMask->alphaMap->pDrawable), + EXA_PREPARE_AUX_MASK, + NULL); + + if (pSrcPix) + pExaScr->prepare_access_reg(pSrcPix, + EXA_PREPARE_SRC, + srcReg); + + if (pMaskPix) + pExaScr->prepare_access_reg(pMaskPix, + EXA_PREPARE_MASK, + maskReg); + + if (srcReg) + REGION_UNINIT(pScreen, srcReg); + if (maskReg) + REGION_UNINIT(pScreen, maskReg); + + pDstPix = exaGetDrawablePixmap(pDst->pDrawable); + if (!exaOpReadsDestination(op)) { + int xoff; + int yoff; + + exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &xoff, &yoff); + REGION_TRANSLATE(pScreen, ®ion, pDst->pDrawable->x + xoff, + pDst->pDrawable->y + yoff); + dstReg = ®ion; + } + + if (pDst->alphaMap && pDst->alphaMap->pDrawable) + pExaScr->prepare_access_reg(exaGetDrawablePixmap(pDst->alphaMap->pDrawable), + EXA_PREPARE_AUX_DEST, + dstReg); + pExaScr->prepare_access_reg(pDstPix, EXA_PREPARE_DEST, dstReg); + + REGION_UNINIT(pScreen, ®ion); + return TRUE; } void @@ -304,52 +618,45 @@ ExaCheckComposite (CARD8 op, CARD16 width, CARD16 height) { - RegionRec region; - int xoff, yoff; - - REGION_NULL(pScreen, ®ion); - - /* We need to prepare access to any separate alpha maps first, in case the - * driver doesn't support EXA_PREPARE_AUX*, in which case EXA_PREPARE_SRC - * may be used for moving them out. - */ - if (pSrc->alphaMap && pSrc->alphaMap->pDrawable) - exaPrepareAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX2); - if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable) - exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX1); - - if (!exaOpReadsDestination(op)) { - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, - xSrc, ySrc, xMask, yMask, xDst, yDst, - width, height)) - return; - - exaGetDrawableDeltas (pDst->pDrawable, - exaGetDrawablePixmap(pDst->pDrawable), - &xoff, &yoff); - - REGION_TRANSLATE(pScreen, ®ion, xoff, yoff); + ScreenPtr pScreen = pDst->pDrawable->pScreen; +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreen(pScreen); +#endif /* RENDER */ + EXA_PRE_FALLBACK(pScreen); + + if (pExaScr->prepare_access_reg) { + if (!ExaPrepareCompositeReg(pScreen, op, pSrc, pMask, pDst, xSrc, + ySrc, xMask, yMask, xDst, yDst, width, + height)) + goto out_no_clip; + } else { - if (pDst->alphaMap && pDst->alphaMap->pDrawable) - exaPrepareAccessReg(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX0, - ®ion); + /* We need to prepare access to any separate alpha maps first, + * in case the driver doesn't support EXA_PREPARE_AUX*, + * in which case EXA_PREPARE_SRC may be used for moving them out. + */ - exaPrepareAccessReg (pDst->pDrawable, EXA_PREPARE_DEST, ®ion); - } else { + if (pSrc->alphaMap && pSrc->alphaMap->pDrawable) + exaPrepareAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC); + if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable) + exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK); if (pDst->alphaMap && pDst->alphaMap->pDrawable) - exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX0); + exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST); exaPrepareAccess (pDst->pDrawable, EXA_PREPARE_DEST); - } - EXA_FALLBACK(("from picts %p/%p to pict %p\n", - pSrc, pMask, pDst)); + EXA_FALLBACK(("from picts %p/%p to pict %p\n", + pSrc, pMask, pDst)); - if (pSrc->pDrawable != NULL) - exaPrepareAccess (pSrc->pDrawable, EXA_PREPARE_SRC); - if (pMask && pMask->pDrawable != NULL) - exaPrepareAccess (pMask->pDrawable, EXA_PREPARE_MASK); - fbComposite (op, + if (pSrc->pDrawable != NULL) + exaPrepareAccess (pSrc->pDrawable, EXA_PREPARE_SRC); + if (pMask && pMask->pDrawable != NULL) + exaPrepareAccess (pMask->pDrawable, EXA_PREPARE_MASK); + } + +#ifdef RENDER + swap(pExaScr, ps, Composite); + ps->Composite (op, pSrc, pMask, pDst, @@ -361,19 +668,22 @@ 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); + 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); +out_no_clip: + EXA_POST_FALLBACK(pScreen); } void @@ -383,68 +693,58 @@ ExaCheckAddTraps (PicturePtr pPicture, int ntrap, xTrap *traps) { + ScreenPtr pScreen = pPicture->pDrawable->pScreen; +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreen(pScreen); +#endif /* RENDER */ + EXA_PRE_FALLBACK(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); + EXA_POST_FALLBACK(pScreen); } /** * Gets the 0,0 pixel of a pixmap. Used for doing solid fills of tiled pixmaps * that happen to be 1x1. Pixmap must be at least 8bpp. - * - * XXX This really belongs in fb, so it can be aware of tiling and etc. */ CARD32 exaGetPixmapFirstPixel (PixmapPtr pPixmap) { - CARD32 pixel; - void *fb; - Bool need_finish = FALSE; - BoxRec box; - RegionRec migration; - ExaPixmapPriv (pPixmap); - Bool sys_valid = pExaPixmap->pDamage && - !miPointInRegion(&pExaPixmap->validSys, 0, 0, &box); - Bool damaged = pExaPixmap->pDamage && - miPointInRegion(DamageRegion(pExaPixmap->pDamage), 0, 0, &box); - Bool offscreen = exaPixmapIsOffscreen(pPixmap); - - fb = pExaPixmap->sys_ptr; - - /* Try to avoid framebuffer readbacks */ - if ((!offscreen && !sys_valid && !damaged) || - (offscreen && (!sys_valid || damaged))) - { - box.x1 = 0; - box.y1 = 0; - box.x2 = 1; - box.y2 = 1; - REGION_INIT(pScreen, &migration, &box, 1); - - need_finish = TRUE; - - exaPrepareAccessReg(&pPixmap->drawable, EXA_PREPARE_SRC, &migration); - fb = pPixmap->devPrivate.ptr; - } - switch (pPixmap->drawable.bitsPerPixel) { case 32: - pixel = *(CARD32 *)fb; - break; + { + CARD32 pixel; + + pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1, + ZPixmap, ~0, (char*)&pixel); + return pixel; + } case 16: - pixel = *(CARD16 *)fb; - break; + { + CARD16 pixel; + + pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1, + ZPixmap, ~0, (char*)&pixel); + return pixel; + } + case 8: + { + CARD8 pixel; + + pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1, + ZPixmap, ~0, (char*)&pixel); + return pixel; + } default: - pixel = *(CARD8 *)fb; - break; + FatalError("%s called for invalid bpp %d\n", __func__, + pPixmap->drawable.bitsPerPixel); } - - if (need_finish) { - exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); - REGION_UNINIT(pScreen, &migration); - } - - return pixel; } |