aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/exa
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/exa')
-rw-r--r--xorg-server/exa/Makefile.am1
-rw-r--r--xorg-server/exa/Makefile.in82
-rw-r--r--xorg-server/exa/exa.c105
-rw-r--r--xorg-server/exa/exa.h46
-rw-r--r--xorg-server/exa/exa_accel.c310
-rw-r--r--xorg-server/exa/exa_glyphs.c902
-rw-r--r--xorg-server/exa/exa_migration.c9
-rw-r--r--xorg-server/exa/exa_priv.h74
-rw-r--r--xorg-server/exa/exa_render.c318
-rw-r--r--xorg-server/exa/exa_unaccel.c47
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 3ec96253d..a50696d90 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 b7cc06240..4623eccdd 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 (&region, pSrc, NULL, pDst,
+ xSrc, ySrc, 0, 0, xDst, yDst,
+ rects->width, rects->height))
+ goto next_rect;
+
+ REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+
+ 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, &region);
+
+ 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, &region, &box, 1);
+
+ DamageRegionAppend(pDst->pDrawable, &region);
+
+ REGION_UNINIT(pScreen, &region);
+ }
+
+ /************************************************************/
+
+ 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, &region,
(PixmapPtr)pSrc->pDrawable,
- &patOrg, FB_ALLONES, GXcopy);
+ &patOrg, FB_ALLONES, GXcopy, CT_NONE);
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
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, &region);
+ /* 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 (&region, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask, xDst, yDst,
@@ -318,9 +330,17 @@ ExaCheckComposite (CARD8 op,
REGION_TRANSLATE(pScreen, &region, xoff, yoff);
+ if (pDst->alphaMap && pDst->alphaMap->pDrawable)
+ exaPrepareAccessReg(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX0,
+ &region);
+
exaPrepareAccessReg (pDst->pDrawable, EXA_PREPARE_DEST, &region);
- } 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, &region);
}
@@ -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;