diff options
Diffstat (limited to 'xorg-server/exa')
-rw-r--r-- | xorg-server/exa/Makefile.am | 1 | ||||
-rw-r--r-- | xorg-server/exa/Makefile.in | 82 | ||||
-rw-r--r-- | xorg-server/exa/exa.c | 105 | ||||
-rw-r--r-- | xorg-server/exa/exa.h | 46 | ||||
-rw-r--r-- | xorg-server/exa/exa_accel.c | 310 | ||||
-rw-r--r-- | xorg-server/exa/exa_glyphs.c | 902 | ||||
-rw-r--r-- | xorg-server/exa/exa_migration.c | 9 | ||||
-rw-r--r-- | xorg-server/exa/exa_priv.h | 74 | ||||
-rw-r--r-- | xorg-server/exa/exa_render.c | 318 | ||||
-rw-r--r-- | xorg-server/exa/exa_unaccel.c | 47 |
10 files changed, 1502 insertions, 392 deletions
diff --git a/xorg-server/exa/Makefile.am b/xorg-server/exa/Makefile.am index e2f7ed302..2b3f1e416 100644 --- a/xorg-server/exa/Makefile.am +++ b/xorg-server/exa/Makefile.am @@ -18,6 +18,7 @@ libexa_la_SOURCES = \ exa.c \ exa.h \ exa_accel.c \ + exa_glyphs.c \ exa_migration.c \ exa_offscreen.c \ exa_render.c \ diff --git a/xorg-server/exa/Makefile.in b/xorg-server/exa/Makefile.in index 4481cb2df..9014a1ed4 100644 --- a/xorg-server/exa/Makefile.in +++ b/xorg-server/exa/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.10.1 from Makefile.am. +# Makefile.in generated by automake 1.10.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -45,7 +45,6 @@ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/do-not-use-config.h \ $(top_builddir)/include/xorg-server.h \ $(top_builddir)/include/dix-config.h \ - $(top_builddir)/include/xgl-config.h \ $(top_builddir)/include/xorg-config.h \ $(top_builddir)/include/xkb-config.h \ $(top_builddir)/include/xwin-config.h \ @@ -53,17 +52,14 @@ CONFIG_HEADER = $(top_builddir)/include/do-not-use-config.h \ CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libexa_la_LIBADD = -am_libexa_la_OBJECTS = exa.lo exa_accel.lo exa_migration.lo \ - exa_offscreen.lo exa_render.lo exa_unaccel.lo +am_libexa_la_OBJECTS = exa.lo exa_accel.lo exa_glyphs.lo \ + exa_migration.lo exa_offscreen.lo exa_render.lo exa_unaccel.lo libexa_la_OBJECTS = $(am_libexa_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -88,8 +84,9 @@ ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ -APPDEFAULTDIR = @APPDEFAULTDIR@ 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@ @@ -110,10 +107,6 @@ CFLAGS = @CFLAGS@ COMPILEDDEFAULTFONTPATH = @COMPILEDDEFAULTFONTPATH@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DARWIN_LIBS = @DARWIN_LIBS@ DBUS_CFLAGS = @DBUS_CFLAGS@ @@ -135,6 +128,7 @@ DMXXIEXAMPLES_DEP_CFLAGS = @DMXXIEXAMPLES_DEP_CFLAGS@ DMXXIEXAMPLES_DEP_LIBS = @DMXXIEXAMPLES_DEP_LIBS@ DMXXMUEXAMPLES_DEP_CFLAGS = @DMXXMUEXAMPLES_DEP_CFLAGS@ DMXXMUEXAMPLES_DEP_LIBS = @DMXXMUEXAMPLES_DEP_LIBS@ +DOLT_BASH = @DOLT_BASH@ DRI2PROTO_CFLAGS = @DRI2PROTO_CFLAGS@ DRI2PROTO_LIBS = @DRI2PROTO_LIBS@ DRIPROTO_CFLAGS = @DRIPROTO_CFLAGS@ @@ -144,18 +138,15 @@ DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ DRI_DRIVER_PATH = @DRI_DRIVER_PATH@ DSYMUTIL = @DSYMUTIL@ DTRACE = @DTRACE@ -ECHO = @ECHO@ +DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ -F77 = @F77@ -FFLAGS = @FFLAGS@ +FGREP = @FGREP@ FILE_MAN_DIR = @FILE_MAN_DIR@ FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ -FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ -FREETYPE_LIBS = @FREETYPE_LIBS@ GLX_ARCH_DEFINES = @GLX_ARCH_DEFINES@ GLX_DEFINES = @GLX_DEFINES@ GL_CFLAGS = @GL_CFLAGS@ @@ -174,7 +165,7 @@ KDRIVE_LIBS = @KDRIVE_LIBS@ KDRIVE_LOCAL_LIBS = @KDRIVE_LOCAL_LIBS@ KDRIVE_PURE_INCS = @KDRIVE_PURE_INCS@ KDRIVE_PURE_LIBS = @KDRIVE_PURE_LIBS@ -LAUNCHD = @LAUNCHD@ +LD = @LD@ LDFLAGS = @LDFLAGS@ LD_EXPORT_SYMBOLS_FLAG = @LD_EXPORT_SYMBOLS_FLAG@ LEX = @LEX@ @@ -188,7 +179,10 @@ LIBTOOL = @LIBTOOL@ LIB_MAN_DIR = @LIB_MAN_DIR@ LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ LINUXDOC = @LINUXDOC@ +LIPO = @LIPO@ LN_S = @LN_S@ +LTCOMPILE = @LTCOMPILE@ +LTCXXCOMPILE = @LTCXXCOMPILE@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -200,8 +194,7 @@ MESA_SOURCE = @MESA_SOURCE@ MISC_MAN_DIR = @MISC_MAN_DIR@ MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ MKDIR_P = @MKDIR_P@ -MKFONTDIR = @MKFONTDIR@ -MKFONTSCALE = @MKFONTSCALE@ +NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCCLD = @OBJCCLD@ @@ -210,8 +203,8 @@ OBJCFLAGS = @OBJCFLAGS@ OBJCLINK = @OBJCLINK@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ -OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ -OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ @@ -247,7 +240,6 @@ VENDOR_NAME = @VENDOR_NAME@ VENDOR_NAME_SHORT = @VENDOR_NAME_SHORT@ VENDOR_RELEASE = @VENDOR_RELEASE@ VERSION = @VERSION@ -X11APP_ARCHS = @X11APP_ARCHS@ X11EXAMPLES_DEP_CFLAGS = @X11EXAMPLES_DEP_CFLAGS@ X11EXAMPLES_DEP_LIBS = @X11EXAMPLES_DEP_LIBS@ XDMCP_CFLAGS = @XDMCP_CFLAGS@ @@ -257,27 +249,12 @@ XDMXCONFIG_DEP_LIBS = @XDMXCONFIG_DEP_LIBS@ XDMX_CFLAGS = @XDMX_CFLAGS@ XDMX_LIBS = @XDMX_LIBS@ XDMX_SYS_LIBS = @XDMX_SYS_LIBS@ -XEGLMODULES_CFLAGS = @XEGLMODULES_CFLAGS@ -XEGL_LIBS = @XEGL_LIBS@ -XEGL_SYS_LIBS = @XEGL_SYS_LIBS@ XEPHYR_CFLAGS = @XEPHYR_CFLAGS@ -XEPHYR_DRI_LIBS = @XEPHYR_DRI_LIBS@ XEPHYR_INCS = @XEPHYR_INCS@ XEPHYR_LIBS = @XEPHYR_LIBS@ XF86CONFIGFILE = @XF86CONFIGFILE@ -XF86MISC_CFLAGS = @XF86MISC_CFLAGS@ -XF86MISC_LIBS = @XF86MISC_LIBS@ XF86VIDMODE_CFLAGS = @XF86VIDMODE_CFLAGS@ XF86VIDMODE_LIBS = @XF86VIDMODE_LIBS@ -XGLMODULES_CFLAGS = @XGLMODULES_CFLAGS@ -XGLMODULES_LIBS = @XGLMODULES_LIBS@ -XGLXMODULES_CFLAGS = @XGLXMODULES_CFLAGS@ -XGLXMODULES_LIBS = @XGLXMODULES_LIBS@ -XGLX_LIBS = @XGLX_LIBS@ -XGLX_SYS_LIBS = @XGLX_SYS_LIBS@ -XGL_LIBS = @XGL_LIBS@ -XGL_MODULE_PATH = @XGL_MODULE_PATH@ -XGL_SYS_LIBS = @XGL_SYS_LIBS@ XKB_BASE_DIRECTORY = @XKB_BASE_DIRECTORY@ XKB_BIN_DIRECTORY = @XKB_BIN_DIRECTORY@ XKB_COMPILED_DIR = @XKB_COMPILED_DIR@ @@ -288,10 +265,6 @@ XNESTMODULES_CFLAGS = @XNESTMODULES_CFLAGS@ XNESTMODULES_LIBS = @XNESTMODULES_LIBS@ XNEST_LIBS = @XNEST_LIBS@ XNEST_SYS_LIBS = @XNEST_SYS_LIBS@ -XORGCFG_DEP_CFLAGS = @XORGCFG_DEP_CFLAGS@ -XORGCFG_DEP_LIBS = @XORGCFG_DEP_LIBS@ -XORGCONFIG_DEP_CFLAGS = @XORGCONFIG_DEP_CFLAGS@ -XORGCONFIG_DEP_LIBS = @XORGCONFIG_DEP_LIBS@ XORG_CFLAGS = @XORG_CFLAGS@ XORG_INCS = @XORG_INCS@ XORG_LIBS = @XORG_LIBS@ @@ -300,13 +273,8 @@ XORG_MODULES_LIBS = @XORG_MODULES_LIBS@ XORG_OS = @XORG_OS@ XORG_OS_SUBDIR = @XORG_OS_SUBDIR@ XORG_SYS_LIBS = @XORG_SYS_LIBS@ -XPRINTMODULES_CFLAGS = @XPRINTMODULES_CFLAGS@ -XPRINTMODULES_LIBS = @XPRINTMODULES_LIBS@ -XPRINTPROTO_CFLAGS = @XPRINTPROTO_CFLAGS@ -XPRINTPROTO_LIBS = @XPRINTPROTO_LIBS@ -XPRINT_CFLAGS = @XPRINT_CFLAGS@ -XPRINT_LIBS = @XPRINT_LIBS@ -XPRINT_SYS_LIBS = @XPRINT_SYS_LIBS@ +XPBPROXY_CFLAGS = @XPBPROXY_CFLAGS@ +XPBPROXY_LIBS = @XPBPROXY_LIBS@ XRESEXAMPLES_DEP_CFLAGS = @XRESEXAMPLES_DEP_CFLAGS@ XRESEXAMPLES_DEP_LIBS = @XRESEXAMPLES_DEP_LIBS@ XSDL_INCS = @XSDL_INCS@ @@ -339,8 +307,7 @@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_F77 = @ac_ct_F77@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -360,7 +327,6 @@ driverdir = @driverdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extdir = @extdir@ -ft_config = @ft_config@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ @@ -370,12 +336,12 @@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ -launchagentsdir = @launchagentsdir@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ logdir = @logdir@ +lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ moduledir = @moduledir@ @@ -393,8 +359,6 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -xglmoduledir = @xglmoduledir@ -xpconfigdir = @xpconfigdir@ noinst_LTLIBRARIES = libexa.la @XORG_TRUE@sdk_HEADERS = exa.h INCLUDES = \ @@ -406,6 +370,7 @@ libexa_la_SOURCES = \ exa.c \ exa.h \ exa_accel.c \ + exa_glyphs.c \ exa_migration.c \ exa_offscreen.c \ exa_render.c \ @@ -420,8 +385,8 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ @@ -465,6 +430,7 @@ 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_glyphs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exa_migration.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@ @@ -519,7 +485,7 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ - $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS diff --git a/xorg-server/exa/exa.c b/xorg-server/exa/exa.c index 72539c0f3..270810766 100644 --- a/xorg-server/exa/exa.c +++ b/xorg-server/exa/exa.c @@ -35,13 +35,12 @@ #include <stdlib.h> #include "exa_priv.h" -#include <X11/fonts/fontstruct.h> -#include "dixfontstr.h" #include "exa.h" -#include "cw.h" -DevPrivateKey exaScreenPrivateKey = &exaScreenPrivateKey; -DevPrivateKey exaPixmapPrivateKey = &exaPixmapPrivateKey; +static int exaScreenPrivateKeyIndex; +DevPrivateKey exaScreenPrivateKey = &exaScreenPrivateKeyIndex; +static int exaPixmapPrivateKeyIndex; +DevPrivateKey exaPixmapPrivateKey = &exaPixmapPrivateKeyIndex; #ifdef MITSHM static ShmFuncs exaShmFuncs = { NULL, NULL }; @@ -165,7 +164,7 @@ exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2) RegionPtr pDamageReg; RegionRec region; - if (!pExaPixmap) + if (!pExaPixmap || !pExaPixmap->pDamage) return; box.x1 = max(x1, 0); @@ -315,6 +314,11 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth, 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); @@ -325,6 +329,9 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth, 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 @@ -349,21 +356,24 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth, fbDestroyPixmap(pPixmap); return NULL; } - } - - pExaPixmap->area = NULL; - /* Set up damage tracking */ - pExaPixmap->pDamage = DamageCreate (NULL, NULL, DamageReportNone, TRUE, - pScreen, pPixmap); + /* Set up damage tracking */ + pExaPixmap->pDamage = DamageCreate (NULL, NULL, + DamageReportNone, TRUE, + pScreen, pPixmap); - if (pExaPixmap->pDamage == NULL) { - fbDestroyPixmap (pPixmap); - return NULL; - } + if (pExaPixmap->pDamage == NULL) { + fbDestroyPixmap (pPixmap); + return NULL; + } - DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage); - DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE); + 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); @@ -501,6 +511,12 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index) if (pExaScr->info->PrepareAccess == NULL) return; + if (index >= EXA_PREPARE_AUX0 && + !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) { + exaMoveOutPixmap (pPixmap); + return; + } + if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) { ExaPixmapPriv (pPixmap); if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) @@ -560,6 +576,13 @@ exaFinishAccess(DrawablePtr pDrawable, int index) if (!exaPixmapIsOffscreen (pPixmap)) return; + if (index >= EXA_PREPARE_AUX0 && + !(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); } @@ -660,34 +683,25 @@ exaCreateGC (GCPtr pGC) return TRUE; } -void -exaPrepareAccessWindow(WindowPtr pWin) +static Bool +exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask) { - if (pWin->backgroundState == BackgroundPixmap) + Bool ret; + + if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap) exaPrepareAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); - if (pWin->borderIsPixel == FALSE) - exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_SRC); -} + if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE) + exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); -void -exaFinishAccessWindow(WindowPtr pWin) -{ - if (pWin->backgroundState == BackgroundPixmap) - exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); + ret = fbChangeWindowAttributes(pWin, mask); - if (pWin->borderIsPixel == FALSE) - exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_SRC); -} + if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE) + exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); -static Bool -exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask) -{ - Bool ret; + if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap) + exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); - exaPrepareAccessWindow(pWin); - ret = fbChangeWindowAttributes(pWin, mask); - exaFinishAccessWindow(pWin); return ret; } @@ -741,6 +755,9 @@ exaCloseScreen(int i, ScreenPtr pScreen) PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); #endif + if (ps->Glyphs == exaGlyphs) + exaGlyphsFini(pScreen); + pScreen->CreateGC = pExaScr->SavedCreateGC; pScreen->CloseScreen = pExaScr->SavedCloseScreen; pScreen->GetImage = pExaScr->SavedGetImage; @@ -754,7 +771,9 @@ exaCloseScreen(int i, ScreenPtr pScreen) #ifdef RENDER if (ps) { ps->Composite = pExaScr->SavedComposite; + ps->Glyphs = pExaScr->SavedGlyphs; ps->Trapezoids = pExaScr->SavedTrapezoids; + ps->Triangles = pExaScr->SavedTriangles; ps->AddTraps = pExaScr->SavedAddTraps; } #endif @@ -917,6 +936,11 @@ exaDriverInit (ScreenPtr pScreen, pExaScr->SavedComposite = ps->Composite; ps->Composite = exaComposite; + if (pScreenInfo->PrepareComposite) { + pExaScr->SavedGlyphs = ps->Glyphs; + ps->Glyphs = exaGlyphs; + } + pExaScr->SavedTriangles = ps->Triangles; ps->Triangles = exaTriangles; @@ -978,6 +1002,9 @@ exaDriverInit (ScreenPtr pScreen, } } + if (ps->Glyphs == exaGlyphs) + exaGlyphsInit(pScreen); + LogMessage(X_INFO, "EXA(%d): Driver registered support for the following" " operations:\n", pScreen->myNum); assert(pScreenInfo->PrepareSolid != NULL); diff --git a/xorg-server/exa/exa.h b/xorg-server/exa/exa.h index a3dad6965..4a96cc6f3 100644 --- a/xorg-server/exa/exa.h +++ b/xorg-server/exa/exa.h @@ -672,6 +672,13 @@ typedef struct _ExaDriver { * from. */ #define EXA_PREPARE_MASK 2 + /** + * 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 /** @} */ /** @@ -742,23 +749,45 @@ typedef struct _ExaDriver { */ #define EXA_HANDLES_PIXMAPS (1 << 3) +/** + * EXA_SUPPORTS_PREPARE_AUX indicates to EXA that the driver can handle the + * EXA_PREPARE_AUX* indices in the Prepare/FinishAccess hooks. If there are no + * such hooks, this flag has no effect. + */ +#define EXA_SUPPORTS_PREPARE_AUX (1 << 4) + /** @} */ +/* in exa.c */ ExaDriverPtr exaDriverAlloc(void); Bool -exaDriverInit(ScreenPtr pScreen, +exaDriverInit(ScreenPtr pScreen, ExaDriverPtr pScreenInfo); void -exaDriverFini(ScreenPtr pScreen); +exaDriverFini(ScreenPtr pScreen); void exaMarkSync(ScreenPtr pScreen); void exaWaitSync(ScreenPtr pScreen); +unsigned long +exaGetPixmapOffset(PixmapPtr pPix); + +unsigned long +exaGetPixmapPitch(PixmapPtr pPix); + +unsigned long +exaGetPixmapSize(PixmapPtr pPix); + +void * +exaGetPixmapDriverPrivate(PixmapPtr p); + + +/* in exa_offscreen.c */ ExaOffscreenArea * exaOffscreenAlloc(ScreenPtr pScreen, int size, int align, Bool locked, @@ -771,15 +800,6 @@ exaOffscreenFree(ScreenPtr pScreen, ExaOffscreenArea *area); void ExaOffscreenMarkUsed (PixmapPtr pPixmap); -unsigned long -exaGetPixmapOffset(PixmapPtr pPix); - -unsigned long -exaGetPixmapPitch(PixmapPtr pPix); - -unsigned long -exaGetPixmapSize(PixmapPtr pPix); - void exaEnableDisableFBAccess (int index, Bool enable); @@ -793,12 +813,12 @@ exaMoveInPixmap (PixmapPtr pPixmap); void exaMoveOutPixmap (PixmapPtr pPixmap); -void * -exaGetPixmapDriverPrivate(PixmapPtr p); +/* in exa_unaccel.c */ CARD32 exaGetPixmapFirstPixel (PixmapPtr pPixmap); + /** * Returns TRUE if the given planemask covers all the significant bits in the * pixel values for pDrawable. diff --git a/xorg-server/exa/exa_accel.c b/xorg-server/exa/exa_accel.c index c049745f2..6970382b9 100644 --- a/xorg-server/exa/exa_accel.c +++ b/xorg-server/exa/exa_accel.c @@ -34,7 +34,6 @@ #include <X11/fonts/fontstruct.h> #include "dixfontstr.h" #include "exa.h" -#include "cw.h" static void exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, @@ -144,7 +143,6 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, ExaScreenPriv (pDrawable->pScreen); PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); ExaPixmapPriv(pPix); - ExaMigrationRec pixmaps[1]; RegionPtr pClip; BoxPtr pbox; int nbox; @@ -166,11 +164,16 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, if (pExaScr->swappedOut) return FALSE; - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pPix; - pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); - exaDoMigration (pixmaps, 1, TRUE); + if (pExaPixmap->pDamage) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pPix; + pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); + + exaDoMigration (pixmaps, 1, TRUE); + } pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); @@ -398,6 +401,10 @@ exaCopyNtoN (DrawablePtr pSrcDrawable, RegionPtr srcregion = NULL, dstregion = NULL; xRectangle *rects; + /* avoid doing copy operations if no boxes */ + if (nbox == 0) + return; + pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable); pDstPixmap = exaGetDrawablePixmap (pDstDrawable); @@ -420,7 +427,8 @@ exaCopyNtoN (DrawablePtr pSrcDrawable, xfree(rects); if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask, - pGC->fillStyle, pGC->alu)) { + pGC->fillStyle, pGC->alu, + pGC->clientClipType)) { dstregion = REGION_CREATE(pScreen, NullBox, 0); REGION_COPY(pScreen, dstregion, srcregion); REGION_TRANSLATE(pScreen, dstregion, dst_off_x - dx - src_off_x, @@ -441,16 +449,36 @@ exaCopyNtoN (DrawablePtr pSrcDrawable, pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap); /* Check whether the accelerator can use this pixmap. - * FIXME: If it cannot, use temporary pixmaps so that the drawing - * happens within limits. + * If the pitch of the pixmaps is out of range, there's nothing + * we can do but fall back to software rendering. */ - if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) - { + if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH || + pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH) goto fallback; - } else { - exaDoMigration (pixmaps, 2, TRUE); + + /* If the width or the height of either of the pixmaps + * is out of range, check whether the boxes are actually out of the + * addressable range as well. If they aren't, we can still do + * the copying in hardware. + */ + if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) { + int i; + + for (i = 0; i < nbox; i++) { + /* src */ + if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX || + (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY) + goto fallback; + + /* dst */ + if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX || + (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY) + goto fallback; + } } + exaDoMigration (pixmaps, 2, TRUE); + /* Mixed directions must be handled specially if the card is lame */ if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && reverse != upsidedown) { @@ -671,7 +699,8 @@ exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg, } static Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, - Pixel pixel, CARD32 planemask, CARD32 alu); + Pixel pixel, CARD32 planemask, CARD32 alu, + unsigned int clientClipType); static void exaPolyFillRect(DrawablePtr pDrawable, @@ -724,10 +753,11 @@ exaPolyFillRect(DrawablePtr pDrawable, if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ? pGC->fgPixel : pGC->tile.pixel, pGC->planemask, - pGC->alu)) || + pGC->alu, pGC->clientClipType)) || (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, - pGC->planemask, pGC->alu))) { + pGC->planemask, pGC->alu, + pGC->clientClipType))) { goto out; } } @@ -829,132 +859,6 @@ out: REGION_DESTROY(pScreen, pReg); } -static void -exaImageGlyphBlt (DrawablePtr pDrawable, - GCPtr pGC, - int x, - int y, - unsigned int nglyph, - CharInfoPtr *ppciInit, - pointer pglyphBase) -{ - FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); - CharInfoPtr *ppci; - CharInfoPtr pci; - unsigned char *pglyph; /* pointer bits in glyph */ - int gWidth, gHeight; /* width and height of glyph */ - FbStride gStride; /* stride of glyph */ - Bool opaque; - int gx, gy; - void (*glyph) (FbBits *, - FbStride, - int, - FbStip *, - FbBits, - int, - int); - FbBits *dst; - FbStride dstStride; - int dstBpp; - int dstXoff, dstYoff; - FbBits depthMask; - PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); - ExaPixmapPriv(pPixmap); - RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); - BoxRec extents = *REGION_EXTENTS(pScreen, pending_damage); - int xoff, yoff; - - if (extents.x1 >= extents.x2 || extents.y1 >= extents.y2) - return; - - depthMask = FbFullMask(pDrawable->depth); - - if ((pGC->planemask & depthMask) != depthMask) - { - ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase); - return; - } - - glyph = NULL; - switch (pDrawable->bitsPerPixel) { - case 8: glyph = fbGlyph8; break; - case 16: glyph = fbGlyph16; break; - case 24: glyph = fbGlyph24; break; - case 32: glyph = fbGlyph32; break; - } - - x += pDrawable->x; - y += pDrawable->y; - - exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); - extents.x1 -= xoff; - extents.x2 -= xoff; - extents.y1 -= yoff; - extents.y2 -= yoff; - - exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pending_damage); - - if (TERMINALFONT (pGC->font) && !glyph) - { - opaque = TRUE; - } - else - { - FbBits fg = fbReplicatePixel (pGC->bgPixel, pDrawable->bitsPerPixel); - - fbSolidBoxClipped (pDrawable, - fbGetCompositeClip(pGC), - extents.x1, - extents.y1, - extents.x2, - extents.y2, - fbAnd (GXcopy, fg, pGC->planemask), - fbXor (GXcopy, fg, pGC->planemask)); - - opaque = FALSE; - } - - EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); - - exaPrepareAccessGC (pGC); - - fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); - - for (ppci = ppciInit; nglyph; nglyph--, x += pci->metrics.characterWidth) - { - pci = *ppci++; - gWidth = GLYPHWIDTHPIXELS(pci); - gHeight = GLYPHHEIGHTPIXELS(pci); - gx = x + pci->metrics.leftSideBearing; - gy = y - pci->metrics.ascent; - - if (!gWidth || !gHeight || (gx + gWidth) <= extents.x1 || - (gy + gHeight) <= extents.y1 || gx >= extents.x2 || - gy >= extents.y2) - continue; - - pglyph = FONTGLYPHBITS(pglyphBase, pci); - - if (glyph && gWidth <= sizeof (FbStip) * 8 && - fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) - { - (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp, - (FbStip *) pglyph, pPriv->fg, gx + dstXoff, gHeight); - } - else - { - RegionPtr pClip = fbGetCompositeClip(pGC); - - gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip); - fbPutXYImage (pDrawable, pClip, pPriv->fg, pPriv->bg, pPriv->pm, - GXcopy, opaque, gx, gy, gWidth, gHeight, - (FbStip *) pglyph, gStride, 0); - } - } - exaFinishAccessGC (pGC); - exaFinishAccess (pDrawable, EXA_PREPARE_DEST); -} - const GCOps exaOps = { exaFillSpans, ExaCheckSetSpans, @@ -973,7 +877,7 @@ const GCOps exaOps = { miPolyText16, miImageText8, miImageText16, - exaImageGlyphBlt, + ExaCheckImageGlyphBlt, ExaCheckPolyGlyphBlt, ExaCheckPushPixels, }; @@ -1006,11 +910,8 @@ exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) } static Bool -exaFillRegionSolid (DrawablePtr pDrawable, - RegionPtr pRegion, - Pixel pixel, - CARD32 planemask, - CARD32 alu) +exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, + CARD32 planemask, CARD32 alu, unsigned int clientClipType) { ExaScreenPriv(pDrawable->pScreen); PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); @@ -1023,7 +924,8 @@ exaFillRegionSolid (DrawablePtr pDrawable, pixmaps[0].as_src = FALSE; pixmaps[0].pPix = pPixmap; pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid, - alu) ? NULL : pRegion; + alu, clientClipType) + ? NULL : pRegion; exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); @@ -1086,12 +988,9 @@ out: * Based on fbFillRegionTiled(), fbTile(). */ Bool -exaFillRegionTiled (DrawablePtr pDrawable, - RegionPtr pRegion, - PixmapPtr pTile, - DDXPointPtr pPatOrg, - CARD32 planemask, - CARD32 alu) +exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, + DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu, + unsigned int clientClipType) { ExaScreenPriv(pDrawable->pScreen); PixmapPtr pPixmap; @@ -1103,6 +1002,7 @@ exaFillRegionTiled (DrawablePtr pDrawable, int nbox = REGION_NUM_RECTS (pRegion); BoxPtr pBox = REGION_RECTS (pRegion); Bool ret = FALSE; + int i; tileWidth = pTile->drawable.width; tileHeight = pTile->drawable.height; @@ -1113,26 +1013,24 @@ exaFillRegionTiled (DrawablePtr pDrawable, if (tileWidth == 1 && tileHeight == 1) return exaFillRegionSolid(pDrawable, pRegion, exaGetPixmapFirstPixel (pTile), planemask, - alu); + 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) ? NULL : pRegion; + alu, clientClipType) + ? NULL : pRegion; pixmaps[1].as_dst = FALSE; pixmaps[1].as_src = TRUE; pixmaps[1].pPix = pTile; pixmaps[1].pReg = NULL; - exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); - REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); - pExaPixmap = ExaGetPixmapPriv (pPixmap); if (pExaPixmap->accel_blocked || pTileExaPixmap->accel_blocked) { - goto out; + return FALSE; } else { exaDoMigration (pixmaps, 2, TRUE); } @@ -1140,24 +1038,33 @@ exaFillRegionTiled (DrawablePtr pDrawable, pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); if (!pPixmap || !exaPixmapIsOffscreen(pTile)) - goto out; + return FALSE; if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) { - while (nbox--) + if (xoff || yoff) + REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); + + for (i = 0; i < nbox; i++) { - int height = pBox->y2 - pBox->y1; - int dstY = pBox->y1; + int height = pBox[i].y2 - pBox[i].y1; + int dstY = pBox[i].y1; int tileY; + if (alu == GXcopy) + height = min(height, tileHeight); + modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); while (height > 0) { - int width = pBox->x2 - pBox->x1; - int dstX = pBox->x1; + int width = pBox[i].x2 - pBox[i].x1; + int dstX = pBox[i].x1; int tileX; int h = tileHeight - tileY; + if (alu == GXcopy) + width = min(width, tileWidth); + if (h > height) h = height; height -= h; @@ -1179,17 +1086,74 @@ exaFillRegionTiled (DrawablePtr pDrawable, dstY += h; tileY = 0; } - pBox++; } (*pExaScr->info->DoneCopy) (pPixmap); + + /* With GXcopy, we only need to do the basic algorithm up to the tile + * size; then, we can just keep doubling the destination in each + * direction until it fills the box. This way, the number of copy + * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where + * rx/ry is the ratio between box and tile width/height. This can make + * a big difference if each driver copy incurs a significant constant + * overhead. + */ + if (alu != GXcopy) + ret = TRUE; + else { + Bool more_copy = FALSE; + + for (i = 0; i < nbox; i++) { + int dstX = pBox[i].x1 + tileWidth; + int dstY = pBox[i].y1 + tileHeight; + + if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) { + more_copy = TRUE; + break; + } + } + + if (more_copy == FALSE) + ret = TRUE; + + if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, + 1, 1, alu, planemask)) { + for (i = 0; i < nbox; i++) + { + int dstX = pBox[i].x1 + tileWidth; + int dstY = pBox[i].y1 + tileHeight; + int width = min(pBox[i].x2 - dstX, tileWidth); + int height = min(pBox[i].y2 - pBox[i].y1, tileHeight); + + while (dstX < pBox[i].x2) { + (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, + dstX, pBox[i].y1, width, height); + dstX += width; + width = min(pBox[i].x2 - dstX, width * 2); + } + + width = pBox[i].x2 - pBox[i].x1; + height = min(pBox[i].y2 - dstY, tileHeight); + + while (dstY < pBox[i].y2) { + (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, + pBox[i].x1, dstY, width, height); + dstY += height; + height = min(pBox[i].y2 - dstY, height * 2); + } + } + + (*pExaScr->info->DoneCopy) (pPixmap); + + ret = TRUE; + } + } + exaMarkSync(pDrawable->pScreen); - ret = TRUE; + if (xoff || yoff) + REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); } -out: - REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); - return ret; } diff --git a/xorg-server/exa/exa_glyphs.c b/xorg-server/exa/exa_glyphs.c new file mode 100644 index 000000000..93b8b36ae --- /dev/null +++ b/xorg-server/exa/exa_glyphs.c @@ -0,0 +1,902 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * Partly based on code Copyright © 2000 SuSE, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Red Hat not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Red Hat makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor <otaylor@fishsoup.net> + * Based on code by: Keith Packard + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stdlib.h> + +#include "exa_priv.h" + +#include "mipict.h" + +#if DEBUG_GLYPH_CACHE +#define DBG_GLYPH_CACHE(a) ErrorF a +#else +#define DBG_GLYPH_CACHE(a) +#endif + +/* Width of the pixmaps we use for the caches; this should be less than + * max texture size of the driver; this may need to actually come from + * the driver. + */ +#define CACHE_PICTURE_WIDTH 1024 + +/* Maximum number of glyphs we buffer on the stack before flushing + * rendering to the mask or destination surface. + */ +#define GLYPH_BUFFER_SIZE 256 + +typedef struct { + PicturePtr source; + ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE]; + int count; +} ExaGlyphBuffer, *ExaGlyphBufferPtr; + +typedef enum { + ExaGlyphSuccess, /* Glyph added to render buffer */ + ExaGlyphFail, /* out of memory, etc */ + ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */ +} ExaGlyphCacheResult; + +void +exaGlyphsInit(ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + int i = 0; + + memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches)); + + pExaScr->glyphCaches[i].format = PICT_a8; + pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; + i++; + pExaScr->glyphCaches[i].format = PICT_a8; + pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; + i++; + pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; + pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; + i++; + pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; + pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; + i++; + + assert(i == EXA_NUM_GLYPH_CACHES); + + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + pExaScr->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth; + pExaScr->glyphCaches[i].size = 256; + pExaScr->glyphCaches[i].hashSize = 557; + } +} + +static void +exaUnrealizeGlyphCaches(ScreenPtr pScreen, + unsigned int format) +{ + ExaScreenPriv(pScreen); + int i; + + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + + if (cache->format != format) + continue; + + if (cache->picture) { + FreePicture ((pointer) cache->picture, (XID) 0); + cache->picture = NULL; + } + + if (cache->hashEntries) { + xfree(cache->hashEntries); + cache->hashEntries = NULL; + } + + if (cache->glyphs) { + xfree(cache->glyphs); + cache->glyphs = NULL; + } + cache->glyphCount = 0; + } +} + +#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) + +/* 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 + * right at the border between two sizes, we might be switching for almost + * every glyph.) + * + * This function allocates the storage pixmap, and then fills in the + * rest of the allocated structures for all caches with the given format. + */ +static Bool +exaRealizeGlyphCaches(ScreenPtr pScreen, + unsigned int format) +{ + ExaScreenPriv(pScreen); + + int depth = PIXMAN_FORMAT_DEPTH(format); + PictFormatPtr pPictFormat; + PixmapPtr pPixmap; + PicturePtr pPicture; + CARD32 component_alpha; + int height; + int i; + int error; + + pPictFormat = PictureMatchFormat(pScreen, depth, format); + if (!pPictFormat) + return FALSE; + + /* Compute the total vertical size needed for the format */ + + height = 0; + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + int rows; + + if (cache->format != format) + continue; + + cache->yOffset = height; + + rows = (cache->size + cache->columns - 1) / cache->columns; + height += rows * cache->glyphHeight; + } + + /* Now allocate the pixmap and picture */ + + pPixmap = (*pScreen->CreatePixmap) (pScreen, + CACHE_PICTURE_WIDTH, + height, depth, 0); + if (!pPixmap) + return FALSE; + + component_alpha = NeedsComponent(pPictFormat->format); + pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, + CPComponentAlpha, &component_alpha, serverClient, + &error); + + (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */ + + if (!pPicture) + 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; + + if (cache->format != format) + continue; + + cache->picture = pPicture; + cache->picture->refcnt++; + cache->hashEntries = xalloc(sizeof(int) * cache->hashSize); + cache->glyphs = xalloc(sizeof(ExaCachedGlyphRec) * cache->size); + cache->glyphCount = 0; + + if (!cache->hashEntries || !cache->glyphs) + goto bail; + + for (j = 0; j < cache->hashSize; j++) + cache->hashEntries[j] = -1; + + cache->evictionPosition = rand() % cache->size; + } + + /* Each cache references the picture individually */ + FreePicture ((pointer) pPicture, (XID) 0); + return TRUE; + +bail: + exaUnrealizeGlyphCaches(pScreen, format); + return FALSE; +} + +void +exaGlyphsFini (ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + int i; + + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + + if (cache->picture) + exaUnrealizeGlyphCaches(pScreen, cache->format); + } +} + +static int +exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, + GlyphPtr pGlyph) +{ + int slot; + + slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; + + while (TRUE) { /* hash table can never be full */ + int entryPos = cache->hashEntries[slot]; + if (entryPos == -1) + return -1; + + if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){ + return entryPos; + } + + slot--; + if (slot < 0) + slot = cache->hashSize - 1; + } +} + +static void +exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, + GlyphPtr pGlyph, + int pos) +{ + int slot; + + memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1)); + + slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; + + while (TRUE) { /* hash table can never be full */ + if (cache->hashEntries[slot] == -1) { + cache->hashEntries[slot] = pos; + return; + } + + slot--; + if (slot < 0) + slot = cache->hashSize - 1; + } +} + +static void +exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, + int pos) +{ + int slot; + int emptiedSlot = -1; + + slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize; + + while (TRUE) { /* hash table can never be full */ + int entryPos = cache->hashEntries[slot]; + + if (entryPos == -1) + return; + + if (entryPos == pos) { + cache->hashEntries[slot] = -1; + emptiedSlot = slot; + } else if (emptiedSlot != -1) { + /* See if we can move this entry into the emptied slot, we can't + * do that if if entry would have hashed between the current position + * and the emptied slot. (taking wrapping into account). Bad positions + * are: + * + * | XXXXXXXXXX | + * i j + * + * |XXX XXXX| + * j i + * + * i - slot, j - emptiedSlot + * + * (Knuth 6.4R) + */ + + int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize; + + if (!((entrySlot >= slot && entrySlot < emptiedSlot) || + (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot)))) + { + cache->hashEntries[emptiedSlot] = entryPos; + cache->hashEntries[slot] = -1; + emptiedSlot = slot; + } + } + + slot--; + if (slot < 0) + slot = cache->hashSize - 1; + } +} + +#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth) +#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight) + +/* 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 + * 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. + * + * We need to damage the cache pixmap manually in either case because the damage + * layer unwrapped the picture screen before calling exaGlyphs. + */ +static void +exaGlyphCacheUploadGlyph(ScreenPtr pScreen, + ExaGlyphCachePtr cache, + int pos, + GlyphPtr pGlyph) +{ + ExaScreenPriv(pScreen); + PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum]; + 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)) + 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 (!exaPixmapIsOffscreen(pCachePixmap)) + goto composite; + + /* CACHE_{X,Y} are in pixmap coordinates, no need for cache{X,Y}off */ + if (pExaScr->info->UploadToScreen(pCachePixmap, + CACHE_X(pos), + CACHE_Y(pos), + pGlyph->info.width, + pGlyph->info.height, + (char *)pExaPixmap->sys_ptr, + pExaPixmap->sys_pitch)) + goto damage; + +composite: + CompositePicture (PictOpSrc, + pGlyphPicture, + None, + cache->picture, + 0, 0, + 0, 0, + CACHE_X(pos), + CACHE_Y(pos), + 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); +} + +static ExaGlyphCacheResult +exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + ExaGlyphCachePtr cache, + ExaGlyphBufferPtr buffer, + GlyphPtr pGlyph, + int xGlyph, + int yGlyph) +{ + ExaCompositeRectPtr rect; + int pos; + + if (buffer->source && buffer->source != cache->picture) + return ExaGlyphNeedFlush; + + if (!cache->picture) { + if (!exaRealizeGlyphCaches(pScreen, cache->format)) + return ExaGlyphFail; + } + + DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n", + cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB", + (long)*(CARD32 *) pGlyph->sha1)); + + pos = exaGlyphCacheHashLookup(cache, pGlyph); + if (pos != -1) { + DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos)); + } else { + if (cache->glyphCount < cache->size) { + /* Space remaining; we fill from the start */ + pos = cache->glyphCount; + cache->glyphCount++; + DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos)); + + exaGlyphCacheHashInsert(cache, pGlyph, pos); + + } else { + /* Need to evict an entry. We have to see if any glyphs + * already in the output buffer were at this position in + * the cache + */ + + pos = cache->evictionPosition; + DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); + if (buffer->count) { + int x, y; + int i; + + x = CACHE_X(pos); + y = CACHE_Y(pos); + + for (i = 0; i < buffer->count; i++) { + if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) { + DBG_GLYPH_CACHE((" must flush buffer\n")); + return ExaGlyphNeedFlush; + } + } + } + + /* OK, we're all set, swap in the new glyph */ + exaGlyphCacheHashRemove(cache, pos); + exaGlyphCacheHashInsert(cache, pGlyph, pos); + + /* And pick a new eviction position */ + cache->evictionPosition = rand() % cache->size; + } + + exaGlyphCacheUploadGlyph(pScreen, cache, pos, pGlyph); + } + + buffer->source = 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; + rect->width = pGlyph->info.width; + rect->height = pGlyph->info.height; + + buffer->count++; + + return ExaGlyphSuccess; +} + +#undef CACHE_X +#undef CACHE_Y + +static ExaGlyphCacheResult +exaBufferGlyph(ScreenPtr pScreen, + ExaGlyphBufferPtr buffer, + GlyphPtr pGlyph, + int xGlyph, + int yGlyph) +{ + ExaScreenPriv(pScreen); + unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; + int width = pGlyph->info.width; + int height = pGlyph->info.height; + ExaCompositeRectPtr rect; + PicturePtr source; + int i; + + if (buffer->count == GLYPH_BUFFER_SIZE) + return ExaGlyphNeedFlush; + + if (PICT_FORMAT_BPP(format) == 1) + format = PICT_a8; + + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + + if (format == cache->format && + width <= cache->glyphWidth && + height <= cache->glyphHeight) { + ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen, &pExaScr->glyphCaches[i], + buffer, + pGlyph, xGlyph, yGlyph); + switch (result) { + case ExaGlyphFail: + break; + case ExaGlyphSuccess: + case ExaGlyphNeedFlush: + return result; + } + } + } + + /* Couldn't find the glyph in the cache, use the glyph picture directly */ + + source = GlyphPicture(pGlyph)[pScreen->myNum]; + if (buffer->source && buffer->source != source) + return ExaGlyphNeedFlush; + + buffer->source = source; + + 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; + + buffer->count++; + + return ExaGlyphSuccess; +} + +static void +exaGlyphsToMask(PicturePtr pMask, + ExaGlyphBufferPtr buffer) +{ + exaCompositeRects(PictOpAdd, buffer->source, pMask, + buffer->count, buffer->rects); + + buffer->count = 0; + buffer->source = NULL; +} + +static void +exaGlyphsToDst(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + ExaGlyphBufferPtr buffer, + INT16 xSrc, + INT16 ySrc, + INT16 xDst, + INT16 yDst) +{ + 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); + } + + buffer->count = 0; + buffer->source = NULL; +} + +/* Cut and paste from render/glyph.c - probably should export it instead */ +static void +GlyphExtents (int nlist, + GlyphListPtr list, + GlyphPtr *glyphs, + BoxPtr extents) +{ + int x1, x2, y1, y2; + int n; + GlyphPtr glyph; + int x, y; + + x = 0; + y = 0; + extents->x1 = MAXSHORT; + extents->x2 = MINSHORT; + extents->y1 = MAXSHORT; + extents->y2 = MINSHORT; + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + list++; + while (n--) + { + glyph = *glyphs++; + 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 (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; + } + } +} + +/** + * 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, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs) +{ + PicturePtr pPicture; + PixmapPtr pMaskPixmap = 0; + PicturePtr pMask; + ScreenPtr pScreen = pDst->pDrawable->pScreen; + int width = 0, height = 0; + int x, y; + int xDst = list->xOff, yDst = list->yOff; + int n; + GlyphPtr glyph; + int error; + BoxRec extents = {0, 0, 0, 0}; + 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) + { + GCPtr pGC; + xRectangle rect; + + GlyphExtents (nlist, list, glyphs, &extents); + + if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) + return; + width = extents.x2 - extents.x1; + height = extents.y2 - extents.y1; + + if (maskFormat->depth == 1) { + PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8); + + if (a8Format) + maskFormat = a8Format; + } + + pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pMaskPixmap) + return; + component_alpha = NeedsComponent(maskFormat->format); + pMask = CreatePicture (0, &pMaskPixmap->drawable, + maskFormat, CPComponentAlpha, &component_alpha, + serverClient, &error); + if (!pMask) + { + (*pScreen->DestroyPixmap) (pMaskPixmap); + return; + } + pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); + ValidateGC (&pMaskPixmap->drawable, pGC); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); + FreeScratchGC (pGC); + x = -extents.x1; + y = -extents.y1; + } + else + { + pMask = pDst; + x = 0; + y = 0; + } + buffer.count = 0; + buffer.source = NULL; + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + 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 (maskFormat) + exaGlyphsToMask(pMask, &buffer); + else + exaGlyphsToDst(op, pSrc, pDst, &buffer, + xSrc, ySrc, xDst, yDst); + + exaBufferGlyph(pScreen, &buffer, glyph, x, y); + } + + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + + if (buffer.count) { + if (maskFormat) + exaGlyphsToMask(pMask, &buffer); + else + exaGlyphsToDst(op, pSrc, pDst, &buffer, + xSrc, ySrc, xDst, yDst); + } + + if (maskFormat) + { + x = extents.x1; + y = extents.y1; + CompositePicture (op, + pSrc, + pMask, + pDst, + xSrc + x - xDst, + ySrc + y - yDst, + 0, 0, + x, y, + width, height); + FreePicture ((pointer) pMask, (XID) 0); + (*pScreen->DestroyPixmap) (pMaskPixmap); + } +} diff --git a/xorg-server/exa/exa_migration.c b/xorg-server/exa/exa_migration.c index adfbacc9e..17dd87e4c 100644 --- a/xorg-server/exa/exa_migration.c +++ b/xorg-server/exa/exa_migration.c @@ -33,10 +33,7 @@ #include <string.h> #include "exa_priv.h" -#include <X11/fonts/fontstruct.h> -#include "dixfontstr.h" #include "exa.h" -#include "cw.h" #if DEBUG_MIGRATE #define DBG_MIGRATE(a) ErrorF a @@ -165,6 +162,7 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, if (pExaScr->optimize_migration) { RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); +#if DEBUG_MIGRATE if (REGION_NIL(pending_damage)) { static Bool firsttime = TRUE; @@ -173,6 +171,7 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, firsttime = FALSE; } } +#endif REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, pending_damage); } @@ -212,9 +211,9 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, pBox->x1, pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, - pExaPixmap->sys_ptr + (char *) (pExaPixmap->sys_ptr + pBox->y1 * pExaPixmap->sys_pitch - + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8, + + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8), pExaPixmap->sys_pitch)) { if (!access_prepared) { diff --git a/xorg-server/exa/exa_priv.h b/xorg-server/exa/exa_priv.h index 387e751d2..0911c6d8a 100644 --- a/xorg-server/exa/exa_priv.h +++ b/xorg-server/exa/exa_priv.h @@ -61,6 +61,7 @@ #define DEBUG_MIGRATE 0 #define DEBUG_PIXMAP 0 #define DEBUG_OFFSCREEN 0 +#define DEBUG_GLYPH_CACHE 0 #if DEBUG_TRACE_FALL #define EXA_FALLBACK(x) \ @@ -95,6 +96,38 @@ enum ExaMigrationHeuristic { ExaMigrationSmart }; +typedef struct { + unsigned char sha1[20]; +} ExaCachedGlyphRec, *ExaCachedGlyphPtr; + +typedef struct { + /* The identity of the cache, statically configured at initialization */ + unsigned int format; + int glyphWidth; + int glyphHeight; + + int size; /* Size of cache; eventually this should be dynamically determined */ + + /* Hash table mapping from glyph sha1 to position in the glyph; we use + * open addressing with a hash table size determined based on size and large + * enough so that we always have a good amount of free space, so we can + * use linear probing. (Linear probing is preferrable to double hashing + * here because it allows us to easily remove entries.) + */ + int *hashEntries; + int hashSize; + + ExaCachedGlyphPtr glyphs; + int glyphCount; /* Current number of glyphs */ + + PicturePtr picture; /* Where the glyphs of the cache are stored */ + int yOffset; /* y location within the picture where the cache starts */ + int columns; /* Number of columns the glyphs are layed out in */ + int evictionPosition; /* Next random position to evict a glyph */ +} ExaGlyphCacheRec, *ExaGlyphCachePtr; + +#define EXA_NUM_GLYPH_CACHES 4 + typedef void (*EnableDisableFBAccessProcPtr)(int, Bool); typedef struct { ExaDriverPtr info; @@ -123,6 +156,8 @@ typedef struct { unsigned disableFbCount; Bool optimize_migration; unsigned offScreenCounter; + + ExaGlyphCacheRec glyphCaches[EXA_NUM_GLYPH_CACHES]; } ExaScreenPrivRec, *ExaScreenPrivPtr; /* @@ -210,18 +245,21 @@ typedef struct _ExaMigrationRec { RegionPtr pReg; } ExaMigrationRec, *ExaMigrationPtr; +typedef struct { + INT16 xSrc; + INT16 ySrc; + INT16 xDst; + INT16 yDst; + INT16 width; + INT16 height; +} ExaCompositeRectRec, *ExaCompositeRectPtr; + /** * exaDDXDriverInit must be implemented by the DDX using EXA, and is the place * to set EXA options or hook in screen functions to handle using EXA as the AA. */ void exaDDXDriverInit (ScreenPtr pScreen); -void -exaPrepareAccessWindow(WindowPtr pWin); - -void -exaFinishAccessWindow(WindowPtr pWin); - /* exa_unaccel.c */ void exaPrepareAccessGC(GCPtr pGC); @@ -305,11 +343,12 @@ ExaCheckAddTraps (PicturePtr pPicture, static _X_INLINE Bool exaGCReadsDestination(DrawablePtr pDrawable, unsigned long planemask, - unsigned int fillStyle, unsigned char alu) + unsigned int fillStyle, unsigned char alu, + unsigned int clientClipType) { - return ((alu != GXcopy && alu != GXclear &&alu != GXset && + return ((alu != GXcopy && alu != GXclear && alu != GXset && alu != GXcopyInverted) || fillStyle == FillStippled || - !EXA_PM_IS_SOLID(pDrawable, planemask)); + clientClipType != CT_NONE || !EXA_PM_IS_SOLID(pDrawable, planemask)); } void @@ -317,7 +356,8 @@ exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc); Bool exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, - DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu); + DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu, + unsigned int clientClipType); void exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, @@ -419,6 +459,13 @@ exaComposite(CARD8 op, CARD16 height); void +exaCompositeRects(CARD8 op, + PicturePtr Src, + PicturePtr pDst, + int nrect, + ExaCompositeRectPtr rects); + +void exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int ntrap, xTrapezoid *traps); @@ -428,6 +475,13 @@ exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int ntri, xTriangle *tris); +/* exa_glyph.c */ +void +exaGlyphsInit(ScreenPtr pScreen); + +void +exaGlyphsFini (ScreenPtr pScreen); + void exaGlyphs (CARD8 op, PicturePtr pSrc, diff --git a/xorg-server/exa/exa_render.c b/xorg-server/exa/exa_render.c index 1d7b8974c..9a79b4781 100644 --- a/xorg-server/exa/exa_render.c +++ b/xorg-server/exa/exa_render.c @@ -332,6 +332,227 @@ exaTryDriverSolidFill(PicturePtr pSrc, } static int +exaTryDriverCompositeRects(CARD8 op, + PicturePtr pSrc, + 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]; + + if (!pExaScr->info->PrepareComposite) + return -1; + + pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); + pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + + pDstPix = exaGetDrawablePixmap(pDst->pDrawable); + pDstExaPix = ExaGetPixmapPriv(pDstPix); + + /* Check whether the accelerator can use these pixmaps. + * FIXME: If it cannot, use temporary pixmaps so that the drawing + * happens within limits. + */ + if (pSrcExaPix->accel_blocked || + pDstExaPix->accel_blocked) + { + return -1; + } + + if (pExaScr->info->CheckComposite && + !(*pExaScr->info->CheckComposite) (op, pSrc, NULL, 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 (!pSrcPix) + return 0; + + if (!(*pExaScr->info->PrepareComposite) (op, pSrc, NULL, pDst, pSrcPix, + NULL, 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; + + RegionRec region; + BoxPtr pbox; + int nbox; + + if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, + xSrc, ySrc, 0, 0, xDst, yDst, + rects->width, rects->height)) + goto next_rect; + + REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + xSrc = xSrc + src_off_x - xDst - dst_off_x; + ySrc = ySrc + src_off_y - yDst - dst_off_y; + + while (nbox--) + { + (*pExaScr->info->Composite) (pDstPix, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + 0, 0, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + + next_rect: + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + rects++; + } + + (*pExaScr->info->DoneComposite) (pDstPix); + exaMarkSync(pDst->pDrawable->pScreen); + + return 1; +} + +/** + * 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. + */ +void +exaCompositeRects(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + int nrect, + ExaCompositeRectPtr rects) +{ + PixmapPtr pPixmap = exaGetDrawablePixmap(pDst->pDrawable); + ExaPixmapPriv(pPixmap); + int n; + ExaCompositeRectPtr r; + + if (pExaPixmap->pDamage) { + RegionRec region; + int x1 = MAXSHORT; + int y1 = MAXSHORT; + int x2 = MINSHORT; + int y2 = MINSHORT; + BoxRec box; + + /* 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. + */ + + /* Compute the overall extents of the composited region - we're making + * the assumption here that we are compositing a bunch of glyphs that + * cluster closely together and damaging each glyph individually would + * be a loss compared to damaging the bounding box. + */ + n = nrect; + r = rects; + while (n--) { + int rect_x2 = r->xDst + r->width; + int rect_y2 = r->yDst + r->height; + + if (r->xDst < x1) x1 = r->xDst; + if (r->yDst < y1) y1 = r->yDst; + if (rect_x2 > x2) x2 = rect_x2; + if (rect_y2 > y2) y2 = rect_y2; + + r++; + } + + if (x2 <= x1 || y2 <= y1) + return; + + box.x1 = x1; + box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT; + box.y1 = y1; + box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT; + + /* The pixmap migration code relies on pendingDamage indicating + * the bounds of the current rendering, so we need to force + * the actual damage into that region before we do anything, and + * (see use of DamagePendingRegion in exaCopyDirty) + */ + + REGION_INIT(pScreen, ®ion, &box, 1); + + DamageRegionAppend(pDst->pDrawable, ®ion); + + REGION_UNINIT(pScreen, ®ion); + } + + /************************************************************/ + + ValidatePicture (pSrc); + 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++; + } + } + + /************************************************************/ + + if (pExaPixmap->pDamage) { + /* Now we have to flush the damage out from pendingDamage => damage + * Calling DamageRegionProcessPending has that effect. + */ + + DamageRegionProcessPending(pDst->pDrawable); + } +} + +static int exaTryDriverComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, @@ -684,12 +905,18 @@ exaComposite(CARD8 op, ret = exaFillRegionTiled(pDst->pDrawable, ®ion, (PixmapPtr)pSrc->pDrawable, - &patOrg, FB_ALLONES, GXcopy); + &patOrg, FB_ALLONES, GXcopy, CT_NONE); REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); if (ret) goto done; + + /* Let's be correct and restore the variables to their original state. */ + xDst -= pDst->pDrawable->x; + yDst -= pDst->pDrawable->y; + xSrc -= pSrc->pDrawable->x; + ySrc -= pSrc->pDrawable->y; } } } @@ -825,50 +1052,13 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, ScreenPtr pScreen = pDst->pDrawable->pScreen; PictureScreenPtr ps = GetPictureScreen(pScreen); BoxRec bounds; - Bool direct = op == PictOpAdd && miIsSolidAlpha (pSrc); - if (maskFormat || direct) { + if (maskFormat) { miTrapezoidBounds (ntrap, traps, &bounds); if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) return; - } - /* - * Check for solid alpha add - */ - if (direct) - { - DrawablePtr pDraw = pDst->pDrawable; - PixmapPtr pixmap = exaGetDrawablePixmap (pDraw); - ExaPixmapPriv (pixmap); - RegionRec migration; - RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); - int xoff, yoff; - - exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff); - - xoff += pDraw->x; - yoff += pDraw->y; - - bounds.x1 += xoff; - bounds.y1 += yoff; - bounds.x2 += xoff; - bounds.y2 += yoff; - - REGION_INIT(pScreen, &migration, &bounds, 1); - REGION_UNION(pScreen, pending_damage, pending_damage, &migration); - REGION_UNINIT(pScreen, &migration); - - exaPrepareAccess(pDraw, EXA_PREPARE_DEST); - - for (; ntrap; ntrap--, traps++) - (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0); - - exaFinishAccess(pDraw, EXA_PREPARE_DEST); - } - else if (maskFormat) - { PicturePtr pPicture; INT16 xDst, yDst; INT16 xRel, yRel; @@ -895,9 +1085,7 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); FreePicture (pPicture, 0); - } - else - { + } else { if (pDst->polyEdge == PolyEdgeSharp) maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); else @@ -928,51 +1116,17 @@ exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, ScreenPtr pScreen = pDst->pDrawable->pScreen; PictureScreenPtr ps = GetPictureScreen(pScreen); BoxRec bounds; - Bool direct = op == PictOpAdd && miIsSolidAlpha (pSrc); - if (maskFormat || direct) { + if (maskFormat) { miTriangleBounds (ntri, tris, &bounds); if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) return; - } - /* - * Check for solid alpha add - */ - if (direct) - { - DrawablePtr pDraw = pDst->pDrawable; - PixmapPtr pixmap = exaGetDrawablePixmap (pDraw); - ExaPixmapPriv (pixmap); - RegionRec migration; - RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); - int xoff, yoff; - - exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff); - - xoff += pDraw->x; - yoff += pDraw->y; - - bounds.x1 += xoff; - bounds.y1 += yoff; - bounds.x2 += xoff; - bounds.y2 += yoff; - - REGION_INIT(pScreen, &migration, &bounds, 1); - REGION_UNION(pScreen, pending_damage, pending_damage, &migration); - REGION_UNINIT(pScreen, &migration); - - exaPrepareAccess(pDraw, EXA_PREPARE_DEST); - (*ps->AddTriangles) (pDst, 0, 0, ntri, tris); - exaFinishAccess(pDraw, EXA_PREPARE_DEST); - } - else if (maskFormat) - { PicturePtr pPicture; INT16 xDst, yDst; INT16 xRel, yRel; - + xDst = tris[0].p1.x >> 16; yDst = tris[0].p1.y >> 16; @@ -985,21 +1139,19 @@ exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); - + xRel = bounds.x1 + xSrc - xDst; yRel = bounds.y1 + ySrc - yDst; CompositePicture (op, pSrc, pPicture, pDst, xRel, yRel, 0, 0, bounds.x1, bounds.y1, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); FreePicture (pPicture, 0); - } - else - { + } else { if (pDst->polyEdge == PolyEdgeSharp) maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); else maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); - + for (; ntri; ntri--, tris++) exaTriangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); } diff --git a/xorg-server/exa/exa_unaccel.c b/xorg-server/exa/exa_unaccel.c index d7bd06cb2..a515bac1f 100644 --- a/xorg-server/exa/exa_unaccel.c +++ b/xorg-server/exa/exa_unaccel.c @@ -57,9 +57,9 @@ void exaFinishAccessGC(GCPtr pGC) { if (pGC->fillStyle == FillTiled) - exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_MASK); + exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC); if (pGC->stipple) - exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_SRC); + exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK); } #if DEBUG_TRACE_FALL @@ -97,12 +97,15 @@ ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int leftPad, int format, char *bits) { + ExaPixmapPriv(exaGetDrawablePixmap(pDrawable)); + EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); if (exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle, - pGC->alu)) + pGC->alu, pGC->clientClipType)) exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); else - ExaDoPrepareAccess (pDrawable, EXA_PREPARE_DEST); + exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pExaPixmap->pDamage ? + DamagePendingRegion(pExaPixmap->pDamage) : NULL); fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); } @@ -306,6 +309,15 @@ ExaCheckComposite (CARD8 op, 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, @@ -318,9 +330,17 @@ ExaCheckComposite (CARD8 op, REGION_TRANSLATE(pScreen, ®ion, xoff, yoff); + if (pDst->alphaMap && pDst->alphaMap->pDrawable) + exaPrepareAccessReg(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX0, + ®ion); + exaPrepareAccessReg (pDst->pDrawable, EXA_PREPARE_DEST, ®ion); - } else + } else { + if (pDst->alphaMap && pDst->alphaMap->pDrawable) + exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX0); + exaPrepareAccess (pDst->pDrawable, EXA_PREPARE_DEST); + } EXA_FALLBACK(("from picts %p/%p to pict %p\n", pSrc, pMask, pDst)); @@ -343,9 +363,15 @@ ExaCheckComposite (CARD8 op, height); 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); REGION_UNINIT(pScreen, ®ion); } @@ -373,23 +399,22 @@ ExaCheckAddTraps (PicturePtr pPicture, CARD32 exaGetPixmapFirstPixel (PixmapPtr pPixmap) { - ExaScreenPriv(pPixmap->drawable.pScreen); CARD32 pixel; void *fb; Bool need_finish = FALSE; BoxRec box; RegionRec migration; ExaPixmapPriv (pPixmap); - Bool sys_valid = !miPointInRegion(&pExaPixmap->validSys, 0, 0, &box); - Bool damaged = miPointInRegion(DamageRegion(pExaPixmap->pDamage), 0, 0, - &box); + 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 (pExaScr->info->CreatePixmap || - (!offscreen && !sys_valid && !damaged) || + if ((!offscreen && !sys_valid && !damaged) || (offscreen && (!sys_valid || damaged))) { box.x1 = 0; |