]> git.pld-linux.org Git - packages/xorg-xserver-server.git/commitdiff
- more updates
authorArkadiusz Miśkiewicz <arekm@maven.pl>
Sun, 2 Nov 2008 15:03:26 +0000 (15:03 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    xorg-xserver-server-edid.patch -> 1.2
    xorg-xserver-server-exa.patch -> 1.3
    xorg-xserver-server-fb-size.patch -> 1.1
    xorg-xserver-server-glyph.patch -> 1.4
    xorg-xserver-server-pic-libxf86config.patch -> 1.1

xorg-xserver-server-edid.patch
xorg-xserver-server-exa.patch [moved from xorg-xserver-server-glyph.patch with 56% similarity]
xorg-xserver-server-fb-size.patch [new file with mode: 0644]
xorg-xserver-server-pic-libxf86config.patch [new file with mode: 0644]

index e7d8b8196dc8a48c71c8567ec1a14d7fc9bfbd80..297c8c02dc1c175225adf139d1e4682e4476fa11 100644 (file)
@@ -1,3 +1,979 @@
+From 2a0e3188588bce1759d3cef4d190909df2ca07ff Mon Sep 17 00:00:00 2001
+From: Adam Jackson <ajax@redhat.com>
+Date: Mon, 25 Aug 2008 12:55:56 -0400
+Subject: [PATCH] EDID backport from master.
+
+---
+ hw/xfree86/common/Makefile.am    |    3 +-
+ hw/xfree86/common/xf86Mode.c     |   14 +--
+ hw/xfree86/ddc/ddcProperty.c     |   11 ++-
+ hw/xfree86/ddc/edid.h            |    5 +-
+ hw/xfree86/ddc/interpret_edid.c  |   14 +++
+ hw/xfree86/ddc/print_edid.c      |   28 +++--
+ hw/xfree86/ddc/xf86DDC.c         |  241 +++++++++++++++++++++++---------------
+ hw/xfree86/ddc/xf86DDC.h         |    6 +
+ hw/xfree86/loader/xf86sym.c      |    1 +
+ hw/xfree86/modes/xf86Crtc.c      |   11 +-
+ hw/xfree86/modes/xf86EdidModes.c |  228 +++++++++++++++++++++++++++++++-----
+ hw/xfree86/modes/xf86Modes.c     |   12 ++
+ hw/xfree86/modes/xf86Modes.h     |    3 +
+ 13 files changed, 422 insertions(+), 155 deletions(-)
+
+diff --git a/hw/xfree86/common/Makefile.am b/hw/xfree86/common/Makefile.am
+index 0f44075..8aa3adc 100644
+--- a/hw/xfree86/common/Makefile.am
++++ b/hw/xfree86/common/Makefile.am
+@@ -45,7 +45,8 @@ libinit_a_SOURCES = xf86Build.h xf86Init.c
+ INCLUDES = $(XORG_INCS) -I$(srcdir)/../ddc -I$(srcdir)/../i2c \
+          -I$(srcdir)/../loader -I$(srcdir)/../rac -I$(srcdir)/../parser \
+            -I$(srcdir)/../vbe -I$(srcdir)/../int10 \
+-         -I$(srcdir)/../vgahw -I$(srcdir)/../dixmods/extmod
++         -I$(srcdir)/../vgahw -I$(srcdir)/../dixmods/extmod \
++         -I$(srcdir)/../modes
+ sdk_HEADERS = compiler.h fourcc.h xf86.h xf86Module.h xf86Opt.h \
+               xf86PciInfo.h xf86Priv.h xf86Privstr.h xf86Resources.h \
+diff --git a/hw/xfree86/common/xf86Mode.c b/hw/xfree86/common/xf86Mode.c
+index c1b0a5f..24a431d 100644
+--- a/hw/xfree86/common/xf86Mode.c
++++ b/hw/xfree86/common/xf86Mode.c
+@@ -39,6 +39,7 @@
+ #endif
+ #include <X11/X.h>
++#include "xf86Modes.h"
+ #include "os.h"
+ #include "servermd.h"
+ #include "mibank.h"
+@@ -705,16 +706,9 @@ xf86CheckModeForMonitor(DisplayModePtr mode, MonPtr monitor)
+      * -- libv
+      */
+-    /* Is the horizontal blanking a bit lowish? */
+-    if (((mode->HDisplay * 5 / 4) & ~0x07) > mode->HTotal) {
+-        /* is this a cvt -r mode, and only a cvt -r mode? */
+-        if (((mode->HTotal - mode->HDisplay) == 160) &&
+-            ((mode->HSyncEnd - mode->HDisplay) == 80) &&
+-            ((mode->HSyncEnd - mode->HSyncStart) == 32) &&
+-            ((mode->VSyncStart - mode->VDisplay) == 3)) {
+-            if (!monitor->reducedblanking && !(mode->type & M_T_DRIVER))
+-                return MODE_NO_REDUCED;
+-        }
++    if (xf86ModeIsReduced(mode)) {
++        if (!monitor->reducedblanking && !(mode->type & M_T_DRIVER))
++            return MODE_NO_REDUCED;
+     }
+     if ((monitor->maxPixClock) && (mode->Clock > monitor->maxPixClock))
+diff --git a/hw/xfree86/ddc/ddcProperty.c b/hw/xfree86/ddc/ddcProperty.c
+index 02125df..a4384f1 100644
+--- a/hw/xfree86/ddc/ddcProperty.c
++++ b/hw/xfree86/ddc/ddcProperty.c
+@@ -83,13 +83,18 @@ addRootWindowProperties(ScrnInfoPtr pScrn, xf86MonPtr DDC)
+     }
+     if (makeEDID1prop) {
+-      if ((EDID1rawdata = xalloc(128*sizeof(CARD8)))==NULL)
++      int size = 128;
++
++      if (DDC->flags & EDID_COMPLETE_RAWDATA)
++          size += DDC->no_sections * 128;
++
++      if ((EDID1rawdata = xalloc(size*sizeof(CARD8)))==NULL)
+           return;
+       EDID1Atom = MakeAtom(EDID1_ATOM_NAME, sizeof(EDID1_ATOM_NAME) - 1, TRUE);
+-      memcpy(EDID1rawdata, DDC->rawData, 128);
++      memcpy(EDID1rawdata, DDC->rawData, size);
+       xf86RegisterRootWindowProperty(scrnIndex, EDID1Atom, XA_INTEGER, 8,
+-              128, (unsigned char *)EDID1rawdata);
++              size, (unsigned char *)EDID1rawdata);
+     } 
+     if (makeEDID2prop) {
+diff --git a/hw/xfree86/ddc/edid.h b/hw/xfree86/ddc/edid.h
+index a4e79da..45caf6e 100644
+--- a/hw/xfree86/ddc/edid.h
++++ b/hw/xfree86/ddc/edid.h
+@@ -531,6 +531,9 @@ struct detailed_monitor_section {
+   } section;                          /* max: 80 */
+ };
++/* flags */
++#define EDID_COMPLETE_RAWDATA 0x1
++
+ typedef struct {
+   int scrnIndex;
+   struct vendor vendor;
+@@ -539,7 +542,7 @@ typedef struct {
+   struct established_timings timings1;
+   struct std_timings timings2[8];
+   struct detailed_monitor_section det_mon[4];
+-  void *vdif; /* unused */
++  unsigned long flags;
+   int no_sections;
+   Uchar *rawData;
+ } xf86Monitor, *xf86MonPtr;
+diff --git a/hw/xfree86/ddc/interpret_edid.c b/hw/xfree86/ddc/interpret_edid.c
+index 21391dd..d293861 100644
+--- a/hw/xfree86/ddc/interpret_edid.c
++++ b/hw/xfree86/ddc/interpret_edid.c
+@@ -118,6 +118,20 @@ xf86InterpretEDID(int scrnIndex, Uchar *block)
+     return NULL;
+ }
++xf86MonPtr
++xf86InterpretEEDID(int scrnIndex, Uchar *block)
++{
++    xf86MonPtr m;
++
++    m = xf86InterpretEDID(scrnIndex, block);
++    if (!m)
++      return NULL;
++
++    /* extension parse */
++
++    return m;
++}
++
+ static void
+ get_vendor_section(Uchar *c, struct vendor *r)
+ {
+diff --git a/hw/xfree86/ddc/print_edid.c b/hw/xfree86/ddc/print_edid.c
+index f5442ad..5e89b40 100644
+--- a/hw/xfree86/ddc/print_edid.c
++++ b/hw/xfree86/ddc/print_edid.c
+@@ -462,22 +462,28 @@ print_number_sections(int scrnIndex, int num)
+ xf86MonPtr
+ xf86PrintEDID(xf86MonPtr m)
+ {
+-    CARD16 i, j;
++    CARD16 i, j, n;
+     char buf[EDID_WIDTH * 2 + 1];
+-    if (!(m)) return NULL;
++    if (!m) return NULL;
+-    print_vendor(m->scrnIndex,&m->vendor);
+-    print_version(m->scrnIndex,&m->ver);
+-    print_display(m->scrnIndex,&m->features, &m->ver);
+-    print_established_timings(m->scrnIndex,&m->timings1);
+-    print_std_timings(m->scrnIndex,m->timings2);
+-    print_detailed_monitor_section(m->scrnIndex,m->det_mon);
+-    print_number_sections(m->scrnIndex,m->no_sections);
++    print_vendor(m->scrnIndex, &m->vendor);
++    print_version(m->scrnIndex, &m->ver);
++    print_display(m->scrnIndex, &m->features, &m->ver);
++    print_established_timings(m->scrnIndex, &m->timings1);
++    print_std_timings(m->scrnIndex, m->timings2);
++    print_detailed_monitor_section(m->scrnIndex, m->det_mon);
++    print_number_sections(m->scrnIndex, m->no_sections);
++
++    /* extension block section stuff */
+     xf86DrvMsg(m->scrnIndex, X_INFO, "EDID (in hex):\n");
+- 
+-    for (i = 0; i < 128; i += j) {
++
++    n = 128;
++    if (m->flags & EDID_COMPLETE_RAWDATA)
++      n += m->no_sections * 128;
++
++    for (i = 0; i < n; i += j) {
+       for (j = 0; j < EDID_WIDTH; ++j) {
+           sprintf(&buf[j * 2], "%02x", m->rawData[i + j]);
+       }
+diff --git a/hw/xfree86/ddc/xf86DDC.c b/hw/xfree86/ddc/xf86DDC.c
+index 28e2ead..0d86776 100644
+--- a/hw/xfree86/ddc/xf86DDC.c
++++ b/hw/xfree86/ddc/xf86DDC.c
+@@ -2,6 +2,14 @@
+  * 
+  * Copyright 1998,1999 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
+  */
++
++/*
++ * Note that DDC1 does not define any method for returning blocks beyond
++ * the first.  DDC2 does, but the original implementation would only ever
++ * read the first block.  If you want to read and parse all blocks, use
++ * xf86DoEEDID().
++ */
++
+ #ifdef HAVE_XORG_CONFIG_H
+ #include <xorg-config.h>
+ #endif
+@@ -31,18 +39,6 @@ static unsigned int *FetchEDID_DDC1(
+     register unsigned int (*)(ScrnInfoPtr)
+ );
+-static unsigned char* EDID1Read_DDC2(
+-    int scrnIndex, 
+-    I2CBusPtr pBus
+-);
+-
+-static unsigned char * DDCRead_DDC2(
+-    int scrnIndex,
+-    I2CBusPtr pBus, 
+-    int start, 
+-    int len
+-);
+-
+ typedef enum {
+     DDCOPT_NODDC1,
+     DDCOPT_NODDC2,
+@@ -107,10 +103,102 @@ xf86DoEDID_DDC1(
+       return tmp;
+ }
++static I2CDevPtr
++DDC2MakeDevice(I2CBusPtr pBus, int address, char *name)
++{
++    I2CDevPtr dev = NULL;
++
++    if (!(dev = xf86I2CFindDev(pBus, address))) {
++      dev = xf86CreateI2CDevRec();
++      dev->DevName = name;
++      dev->SlaveAddr = address;
++      dev->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
++      dev->StartTimeout = 550;
++      dev->BitTimeout = 40;
++      dev->AcknTimeout = 40;
++
++      dev->pI2CBus = pBus;
++      if (!xf86I2CDevInit(dev)) {
++          xf86DrvMsg(pBus->scrnIndex, X_PROBED, "No DDC2 device\n");
++          return NULL;
++      }
++    }
++
++    return dev;
++}
++
++static I2CDevPtr
++DDC2Init(int scrnIndex, I2CBusPtr pBus)
++{
++    I2CDevPtr dev = NULL;
++
++    /*
++     * Slow down the bus so that older monitors don't 
++     * miss things.
++     */
++    pBus->RiseFallTime = 20;
++ 
++    DDC2MakeDevice(pBus, 0x0060, "E-EDID segment register");
++    dev = DDC2MakeDevice(pBus, 0x00A0, "ddc2");
++
++    return dev;
++}
++
++/* Mmmm, smell the hacks */
++static void
++EEDIDStop(I2CDevPtr d)
++{
++}
++
++/* block is the EDID block number.  a segment is two blocks. */
++static Bool
++DDC2Read(I2CDevPtr dev, int block, unsigned char *R_Buffer)
++{
++    unsigned char W_Buffer[1];
++    int i, segment;
++    I2CDevPtr seg;
++    void (*stop)(I2CDevPtr);
++
++    for (i = 0; i < RETRIES; i++) {
++      /* Stop bits reset the segment pointer to 0, so be careful here. */
++      segment = block >> 1;
++      if (segment) {
++          Bool b;
++          
++          if (!(seg = xf86I2CFindDev(dev->pI2CBus, 0x0060)))
++              return FALSE;
++
++          W_Buffer[0] = segment;
++
++          stop = dev->pI2CBus->I2CStop;
++          dev->pI2CBus->I2CStop = EEDIDStop;
++
++          b = xf86I2CWriteRead(seg, W_Buffer, 1, NULL, 0);
++
++          dev->pI2CBus->I2CStop = stop;
++          if (!b) {
++              dev->pI2CBus->I2CStop(dev);
++              continue;
++          }
++      }
++
++      W_Buffer[0] = (block & 0x01) * EDID1_LEN;
++
++      if (xf86I2CWriteRead(dev, W_Buffer, 1, R_Buffer, EDID1_LEN)) {
++          if (!DDC_checksum(R_Buffer, EDID1_LEN))
++              return TRUE;
++      }
++    }
++ 
++    return FALSE;
++}
++
+ /**
+  * Attempts to probe the monitor for EDID information, if NoDDC and NoDDC2 are
+  * unset.  EDID information blocks are interpreted and the results returned in
+- * an xf86MonPtr.
++ * an xf86MonPtr.  Unlike xf86DoEDID_DDC[12](), this function will return
++ * the complete EDID data, including all extension blocks, if the 'complete'
++ * parameter is TRUE;
+  *
+  * This function does not affect the list of modes used by drivers -- it is up
+  * to the driver to decide policy on what to do with EDID information.
+@@ -119,46 +207,72 @@ xf86DoEDID_DDC1(
+  * @return NULL if no monitor attached or failure to interpret the EDID.
+  */
+ xf86MonPtr
+-xf86DoEDID_DDC2(int scrnIndex, I2CBusPtr pBus)
++xf86DoEEDID(int scrnIndex, I2CBusPtr pBus, Bool complete)
+ {
+     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+     unsigned char *EDID_block = NULL;
+     xf86MonPtr tmp = NULL;
++    I2CDevPtr dev = NULL;
+     /* Default DDC and DDC2 to enabled. */
+     Bool noddc = FALSE, noddc2 = FALSE;
+     OptionInfoPtr options;
+-    options = xnfalloc(sizeof(DDCOptions));
+-    (void)memcpy(options, DDCOptions, sizeof(DDCOptions));
++    options = xalloc(sizeof(DDCOptions));
++    if (!options)
++      return NULL;
++    memcpy(options, DDCOptions, sizeof(DDCOptions));
+     xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options);
+     xf86GetOptValBool(options, DDCOPT_NODDC, &noddc);
+     xf86GetOptValBool(options, DDCOPT_NODDC2, &noddc2);
+     xfree(options);
+-    
++
+     if (noddc || noddc2)
+       return NULL;
+-    EDID_block = EDID1Read_DDC2(scrnIndex,pBus);
++    if (!(dev = DDC2Init(scrnIndex, pBus)))
++      return NULL;
+-    if (EDID_block){
+-      tmp = xf86InterpretEDID(scrnIndex,EDID_block);
+-    } else {
+-#ifdef DEBUG
+-      ErrorF("No EDID block returned\n");
+-#endif
++    EDID_block = xcalloc(1, EDID1_LEN);
++    if (!EDID_block)
+       return NULL;
++
++    if (DDC2Read(dev, 0, EDID_block)) {
++      int i, n = EDID_block[0x7e];
++
++      if (complete && n) {
++          EDID_block = xrealloc(EDID_block, EDID1_LEN * (1+n));
++
++          for (i = 0; i < n; i++)
++              DDC2Read(dev, i+1, EDID_block + (EDID1_LEN * (1+i)));
++      }
++
++      tmp = xf86InterpretEEDID(scrnIndex, EDID_block);
+     }
+-#ifdef DEBUG
+-    if (!tmp)
+-      ErrorF("Cannot interpret EDID block\n");
+-    else
+-        ErrorF("Sections to follow: %i\n",tmp->no_sections);
+-#endif
+-    
++
++    if (tmp && complete)
++      tmp->flags |= EDID_COMPLETE_RAWDATA;
++
+     return tmp;
+ }
++/**
++ * Attempts to probe the monitor for EDID information, if NoDDC and NoDDC2 are
++ * unset.  EDID information blocks are interpreted and the results returned in
++ * an xf86MonPtr.
++ *
++ * This function does not affect the list of modes used by drivers -- it is up
++ * to the driver to decide policy on what to do with EDID information.
++ *
++ * @return pointer to a new xf86MonPtr containing the EDID information.
++ * @return NULL if no monitor attached or failure to interpret the EDID.
++ */
++xf86MonPtr
++xf86DoEDID_DDC2(int scrnIndex, I2CBusPtr pBus)
++{
++    return xf86DoEEDID(scrnIndex, pBus, FALSE);
++}
++
+ /* 
+  * read EDID record , pass it to callback function to interpret.
+  * callback function will store it for further use by calling
+@@ -225,68 +339,3 @@ FetchEDID_DDC1(register ScrnInfoPtr pScrn,
+     } while(--count);
+     return (ptr);
+ }
+-
+-static unsigned char*
+-EDID1Read_DDC2(int scrnIndex, I2CBusPtr pBus)
+-{
+-    return  DDCRead_DDC2(scrnIndex, pBus, 0, EDID1_LEN);
+-}
+-
+-static unsigned char *
+-DDCRead_DDC2(int scrnIndex, I2CBusPtr pBus, int start, int len)
+-{
+-    I2CDevPtr dev;
+-    unsigned char W_Buffer[2];
+-    int w_bytes;
+-    unsigned char *R_Buffer;
+-    int i;
+-    
+-    /*
+-     * Slow down the bus so that older monitors don't 
+-     * miss things.
+-     */
+-    pBus->RiseFallTime = 20;
+-    
+-    if (!(dev = xf86I2CFindDev(pBus, 0x00A0))) {
+-      dev = xf86CreateI2CDevRec();
+-      dev->DevName = "ddc2";
+-      dev->SlaveAddr = 0xA0;
+-      dev->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
+-      dev->StartTimeout = 550;
+-      dev->BitTimeout = 40;
+-      dev->AcknTimeout = 40;
+-
+-      dev->pI2CBus = pBus;
+-      if (!xf86I2CDevInit(dev)) {
+-          xf86DrvMsg(scrnIndex, X_PROBED, "No DDC2 device\n");
+-          return NULL;
+-      }
+-    }
+-    if (start < 0x100) {
+-      w_bytes = 1;
+-      W_Buffer[0] = start;
+-    } else {
+-      w_bytes = 2;
+-      W_Buffer[0] = start & 0xFF;
+-      W_Buffer[1] = (start & 0xFF00) >> 8;
+-    }
+-    R_Buffer = xcalloc(1,sizeof(unsigned char) 
+-                                      * (len));
+-    for (i=0; i<RETRIES; i++) {
+-      if (xf86I2CWriteRead(dev, W_Buffer,w_bytes, R_Buffer,len)) {
+-          if (!DDC_checksum(R_Buffer,len))
+-              return R_Buffer;
+-
+-#ifdef DEBUG
+-          else ErrorF("Checksum error in EDID block\n");
+-#endif
+-      }
+-#ifdef DEBUG
+-      else ErrorF("Error reading EDID block\n");
+-#endif
+-    }
+-    
+-    xf86DestroyI2CDevRec(dev,TRUE);
+-    xfree(R_Buffer);
+-    return NULL;
+-}
+diff --git a/hw/xfree86/ddc/xf86DDC.h b/hw/xfree86/ddc/xf86DDC.h
+index 3b072dd..42d9ce6 100644
+--- a/hw/xfree86/ddc/xf86DDC.h
++++ b/hw/xfree86/ddc/xf86DDC.h
+@@ -35,6 +35,8 @@ extern xf86MonPtr xf86DoEDID_DDC2(
+    I2CBusPtr pBus
+ );
++extern xf86MonPtr xf86DoEEDID(int scrnIndex, I2CBusPtr pBus, Bool);
++
+ extern xf86MonPtr xf86PrintEDID(
+     xf86MonPtr monPtr
+ );
+@@ -43,6 +45,10 @@ extern xf86MonPtr xf86InterpretEDID(
+     int screenIndex, Uchar *block
+ );
++extern xf86MonPtr xf86InterpretEEDID(
++    int screenIndex, Uchar *block
++);
++
+ extern void 
+ xf86DDCMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC);
+diff --git a/hw/xfree86/loader/xf86sym.c b/hw/xfree86/loader/xf86sym.c
+index 24fc44c..77d7d45 100644
+--- a/hw/xfree86/loader/xf86sym.c
++++ b/hw/xfree86/loader/xf86sym.c
+@@ -1009,6 +1009,7 @@ _X_HIDDEN void *xfree86LookupTab[] = {
+     SYMFUNC(xf86DoEDID_DDC2)
+     SYMFUNC(xf86InterpretEDID)
+     SYMFUNC(xf86PrintEDID)
++    SYMFUNC(xf86DoEEDID)
+     SYMFUNC(xf86DDCMonitorSet)
+     SYMFUNC(xf86SetDDCproperties)
+diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
+index 91ba1b7..2941b8b 100644
+--- a/hw/xfree86/modes/xf86Crtc.c
++++ b/hw/xfree86/modes/xf86Crtc.c
+@@ -2575,9 +2575,11 @@ xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon)
+     size = 0;
+     if (edid_mon)
+     {
+-      if (edid_mon->ver.version == 1)
++      if (edid_mon->ver.version == 1) {
+           size = 128;
+-      else if (edid_mon->ver.version == 2)
++          if (edid_mon->flags & EDID_COMPLETE_RAWDATA)
++              size += edid_mon->no_sections * 128;
++      } else if (edid_mon->ver.version == 2)
+           size = 256;
+     }
+     xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size);
+@@ -2622,15 +2624,16 @@ xf86OutputGetEDIDModes (xf86OutputPtr output)
+     return xf86DDCGetModes(scrn->scrnIndex, edid_mon);
+ }
++/* maybe we should care about DDC1?  meh. */
+ _X_EXPORT xf86MonPtr
+ xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus)
+ {
+     ScrnInfoPtr       scrn = output->scrn;
+     xf86MonPtr mon;
+-    mon = xf86DoEDID_DDC2 (scrn->scrnIndex, pDDCBus);
++    mon = xf86DoEEDID(scrn->scrnIndex, pDDCBus, TRUE);
+     if (mon)
+-        xf86DDCApplyQuirks (scrn->scrnIndex, mon);
++        xf86DDCApplyQuirks(scrn->scrnIndex, mon);
+     return mon;
+ }
+diff --git a/hw/xfree86/modes/xf86EdidModes.c b/hw/xfree86/modes/xf86EdidModes.c
+index bf0ea3f..7e80601 100644
+--- a/hw/xfree86/modes/xf86EdidModes.c
++++ b/hw/xfree86/modes/xf86EdidModes.c
+@@ -1,5 +1,6 @@
+ /*
+  * Copyright 2006 Luc Verhaegen.
++ * Copyright 2008 Red Hat, Inc.
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+  * copy of this software and associated documentation files (the "Software"),
+@@ -34,16 +35,39 @@
+ #endif
+ #endif
++#define _PARSE_EDID_
+ #include "xf86.h"
+ #include "xf86DDC.h"
+ #include <X11/Xatom.h>
+ #include "property.h"
+ #include "propertyst.h"
+-#include "xf86DDC.h"
+ #include "xf86Crtc.h"
+ #include <string.h>
+ #include <math.h>
++static Bool
++xf86MonitorSupportsReducedBlanking(xf86MonPtr DDC)
++{
++    /* EDID 1.4 explicitly defines RB support */
++    if (DDC->ver.revision >= 4) {
++      int i;
++      for (i = 0; i < DET_TIMINGS; i++) {
++          struct detailed_monitor_section *det_mon = &DDC->det_mon[i];
++          if (det_mon->type == DS_RANGES)
++              if (det_mon->section.ranges.supported_blanking & CVT_REDUCED)
++                  return TRUE;
++      }
++      
++      return FALSE;
++    }
++
++    /* For anything older, assume digital means RB support. Boo. */
++    if (DDC->features.input_type)
++        return TRUE;
++
++    return FALSE;
++}
++
+ /*
+  * Quirks to work around broken EDID data from various monitors.
+  */
+@@ -68,6 +92,8 @@ typedef enum {
+     DDC_QUIRK_FIRST_DETAILED_PREFERRED = 1 << 6,
+     /* use +hsync +vsync for detailed mode */
+     DDC_QUIRK_DETAILED_SYNC_PP = 1 << 7,
++    /* Force single-link DVI bandwidth limit */
++    DDC_QUIRK_DVI_SINGLE_LINK = 1 << 8,
+ } ddc_quirk_t;
+ static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC)
+@@ -181,6 +207,16 @@ static Bool quirk_detailed_sync_pp(int scrnIndex, xf86MonPtr DDC)
+     return FALSE;
+ }
++/* This should probably be made more generic */
++static Bool quirk_dvi_single_link(int scrnIndex, xf86MonPtr DDC)
++{
++    /* Red Hat bug #453106: Apple 23" Cinema Display */
++    if (memcmp (DDC->vendor.name, "APL", 4) == 0 &&
++      DDC->vendor.prod_id == 0x921c)
++      return TRUE;
++    return FALSE;
++}
++
+ typedef struct {
+     Bool      (*detect) (int scrnIndex, xf86MonPtr DDC);
+     ddc_quirk_t       quirk;
+@@ -220,6 +256,10 @@ static const ddc_quirk_map_t ddc_quirks[] = {
+       quirk_detailed_sync_pp, DDC_QUIRK_DETAILED_SYNC_PP,
+       "Use +hsync +vsync for detailed timing."
+     },
++    {
++      quirk_dvi_single_link, DDC_QUIRK_DVI_SINGLE_LINK,
++      "Forcing maximum pixel clock to single DVI link."
++    },
+     { 
+       NULL,           DDC_QUIRK_NONE,
+       "No known quirks"
+@@ -227,8 +267,13 @@ static const ddc_quirk_map_t ddc_quirks[] = {
+ };
+ /*
+- * TODO:
+- *  - for those with access to the VESA DMT standard; review please.
++ * These more or less come from the DMT spec.  The 720x400 modes are
++ * inferred from historical 80x25 practice.  The 640x480@67 and 832x624@75
++ * modes are old-school Mac modes.  The EDID spec says the 1152x864@75 mode
++ * should be 1152x870, again for the Mac, but instead we use the x864 DMT
++ * mode.
++ *
++ * The DMT modes have been fact-checked; the rest are mild guesses.
+  */
+ #define MODEPREFIX NULL, NULL, NULL, 0, M_T_DRIVER
+ #define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0
+@@ -237,16 +282,16 @@ static const DisplayModeRec DDCEstablishedModes[17] = {
+     { MODEPREFIX,    40000,  800,  840,  968, 1056, 0,  600,  601,  605,  628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */
+     { MODEPREFIX,    36000,  800,  824,  896, 1024, 0,  600,  601,  603,  625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */
+     { MODEPREFIX,    31500,  640,  656,  720,  840, 0,  480,  481,  484,  500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */
+-    { MODEPREFIX,    31500,  640,  664,  704,  832, 0,  480,  489,  491,  520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */
++    { MODEPREFIX,    31500,  640,  664,  704,  832, 0,  480,  489,  492,  520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */
+     { MODEPREFIX,    30240,  640,  704,  768,  864, 0,  480,  483,  486,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@67Hz */
+-    { MODEPREFIX,    25200,  640,  656,  752,  800, 0,  480,  490,  492,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */
++    { MODEPREFIX,    25175,  640,  656,  752,  800, 0,  480,  490,  492,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */
+     { MODEPREFIX,    35500,  720,  738,  846,  900, 0,  400,  421,  423,  449, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 720x400@88Hz */
+     { MODEPREFIX,    28320,  720,  738,  846,  900, 0,  400,  412,  414,  449, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@70Hz */
+     { MODEPREFIX,   135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */
+-    { MODEPREFIX,    78800, 1024, 1040, 1136, 1312, 0,  768,  769,  772,  800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */
++    { MODEPREFIX,    78750, 1024, 1040, 1136, 1312, 0,  768,  769,  772,  800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */
+     { MODEPREFIX,    75000, 1024, 1048, 1184, 1328, 0,  768,  771,  777,  806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */
+     { MODEPREFIX,    65000, 1024, 1048, 1184, 1344, 0,  768,  771,  777,  806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */
+-    { MODEPREFIX,    44900, 1024, 1032, 1208, 1264, 0,  768,  768,  776,  817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz */
++    { MODEPREFIX,    44900, 1024, 1032, 1208, 1264, 0,  768,  768,  772,  817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz */
+     { MODEPREFIX,    57284,  832,  864,  928, 1152, 0,  624,  625,  628,  667, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 832x624@75Hz */
+     { MODEPREFIX,    49500,  800,  816,  896, 1056, 0,  600,  601,  604,  625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */
+     { MODEPREFIX,    50000,  800,  856,  976, 1040, 0,  600,  637,  643,  666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */
+@@ -272,6 +317,90 @@ DDCModesFromEstablished(int scrnIndex, struct established_timings *timing,
+     return Modes;
+ }
++/* Autogenerated from the DMT spec */
++static const DisplayModeRec DMTModes[] = {
++    { MODEPREFIX,    31500,  640,  672,  736,  832, 0,  350,  382,  385,  445, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x350@85Hz */
++    { MODEPREFIX,    31500,  640,  672,  736,  832, 0,  400,  401,  404,  445, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 640x400@85Hz */
++    { MODEPREFIX,    35500,  720,  756,  828,  936, 0,  400,  401,  404,  446, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@85Hz */
++    { MODEPREFIX,    25175,  640,  656,  752,  800, 0,  480,  490,  492,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */
++    { MODEPREFIX,    31500,  640,  664,  704,  832, 0,  480,  489,  492,  520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */
++    { MODEPREFIX,    31500,  640,  656,  720,  840, 0,  480,  481,  484,  500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */
++    { MODEPREFIX,    36000,  640,  696,  752,  832, 0,  480,  481,  484,  509, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@85Hz */
++    { MODEPREFIX,    36000,  800,  824,  896, 1024, 0,  600,  601,  603,  625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */
++    { MODEPREFIX,    40000,  800,  840,  968, 1056, 0,  600,  601,  605,  628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */
++    { MODEPREFIX,    50000,  800,  856,  976, 1040, 0,  600,  637,  643,  666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */
++    { MODEPREFIX,    49500,  800,  816,  896, 1056, 0,  600,  601,  604,  625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */
++    { MODEPREFIX,    56250,  800,  832,  896, 1048, 0,  600,  601,  604,  631, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@85Hz */
++    { MODEPREFIX,    73250,  800,  848,  880,  960, 0,  600,  603,  607,  636, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 800x600@120Hz RB */
++    { MODEPREFIX,    33750,  848,  864,  976, 1088, 0,  480,  486,  494,  517, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 848x480@60Hz */
++    { MODEPREFIX,    44900, 1024, 1032, 1208, 1264, 0,  768,  768,  772,  817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz (interlaced) */
++    { MODEPREFIX,    65000, 1024, 1048, 1184, 1344, 0,  768,  771,  777,  806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */
++    { MODEPREFIX,    75000, 1024, 1048, 1184, 1328, 0,  768,  771,  777,  806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */
++    { MODEPREFIX,    78750, 1024, 1040, 1136, 1312, 0,  768,  769,  772,  800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */
++    { MODEPREFIX,    94500, 1024, 1072, 1168, 1376, 0,  768,  769,  772,  808, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@85Hz */
++    { MODEPREFIX,   115500, 1024, 1072, 1104, 1184, 0,  768,  771,  775,  813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@120Hz RB */
++    { MODEPREFIX,   108000, 1152, 1216, 1344, 1600, 0,  864,  865,  868,  900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */
++    { MODEPREFIX,    68250, 1280, 1328, 1360, 1440, 0,  768,  771,  778,  790, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x768@60Hz RB */
++    { MODEPREFIX,    79500, 1280, 1344, 1472, 1664, 0,  768,  771,  778,  798, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@60Hz */
++    { MODEPREFIX,   102250, 1280, 1360, 1488, 1696, 0,  768,  771,  778,  805, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@75Hz */
++    { MODEPREFIX,   117500, 1280, 1360, 1496, 1712, 0,  768,  771,  778,  809, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@85Hz */
++    { MODEPREFIX,   140250, 1280, 1328, 1360, 1440, 0,  768,  771,  778,  813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x768@120Hz RB */
++    { MODEPREFIX,    71000, 1280, 1328, 1360, 1440, 0,  800,  803,  809,  823, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x800@60Hz RB */
++    { MODEPREFIX,    83500, 1280, 1352, 1480, 1680, 0,  800,  803,  809,  831, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@60Hz */
++    { MODEPREFIX,   106500, 1280, 1360, 1488, 1696, 0,  800,  803,  809,  838, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@75Hz */
++    { MODEPREFIX,   122500, 1280, 1360, 1496, 1712, 0,  800,  803,  809,  843, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@85Hz */
++    { MODEPREFIX,   146250, 1280, 1328, 1360, 1440, 0,  800,  803,  809,  847, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x800@120Hz RB */
++    { MODEPREFIX,   108000, 1280, 1376, 1488, 1800, 0,  960,  961,  964, 1000, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x960@60Hz */
++    { MODEPREFIX,   148500, 1280, 1344, 1504, 1728, 0,  960,  961,  964, 1011, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x960@85Hz */
++    { MODEPREFIX,   175500, 1280, 1328, 1360, 1440, 0,  960,  963,  967, 1017, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x960@120Hz RB */
++    { MODEPREFIX,   108000, 1280, 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@60Hz */
++    { MODEPREFIX,   135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */
++    { MODEPREFIX,   157500, 1280, 1344, 1504, 1728, 0, 1024, 1025, 1028, 1072, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@85Hz */
++    { MODEPREFIX,   187250, 1280, 1328, 1360, 1440, 0, 1024, 1027, 1034, 1084, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x1024@120Hz RB */
++    { MODEPREFIX,    85500, 1360, 1424, 1536, 1792, 0,  768,  771,  777,  795, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1360x768@60Hz */
++    { MODEPREFIX,   148250, 1360, 1408, 1440, 1520, 0,  768,  771,  776,  813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1360x768@120Hz RB */
++    { MODEPREFIX,   101000, 1400, 1448, 1480, 1560, 0, 1050, 1053, 1057, 1080, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1400x1050@60Hz RB */
++    { MODEPREFIX,   121750, 1400, 1488, 1632, 1864, 0, 1050, 1053, 1057, 1089, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@60Hz */
++    { MODEPREFIX,   156000, 1400, 1504, 1648, 1896, 0, 1050, 1053, 1057, 1099, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@75Hz */
++    { MODEPREFIX,   179500, 1400, 1504, 1656, 1912, 0, 1050, 1053, 1057, 1105, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@85Hz */
++    { MODEPREFIX,   208000, 1400, 1448, 1480, 1560, 0, 1050, 1053, 1057, 1112, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1400x1050@120Hz RB */
++    { MODEPREFIX,    88750, 1440, 1488, 1520, 1600, 0,  900,  903,  909,  926, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1440x900@60Hz RB */
++    { MODEPREFIX,   106500, 1440, 1520, 1672, 1904, 0,  900,  903,  909,  934, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@60Hz */
++    { MODEPREFIX,   136750, 1440, 1536, 1688, 1936, 0,  900,  903,  909,  942, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@75Hz */
++    { MODEPREFIX,   157000, 1440, 1544, 1696, 1952, 0,  900,  903,  909,  948, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@85Hz */
++    { MODEPREFIX,   182750, 1440, 1488, 1520, 1600, 0,  900,  903,  909,  953, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1440x900@120Hz RB */
++    { MODEPREFIX,   162000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@60Hz */
++    { MODEPREFIX,   175500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@65Hz */
++    { MODEPREFIX,   189000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@70Hz */
++    { MODEPREFIX,   202500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@75Hz */
++    { MODEPREFIX,   229500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@85Hz */
++    { MODEPREFIX,   268250, 1600, 1648, 1680, 1760, 0, 1200, 1203, 1207, 1271, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1600x1200@120Hz RB */
++    { MODEPREFIX,   119000, 1680, 1728, 1760, 1840, 0, 1050, 1053, 1059, 1080, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1680x1050@60Hz RB */
++    { MODEPREFIX,   146250, 1680, 1784, 1960, 2240, 0, 1050, 1053, 1059, 1089, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@60Hz */
++    { MODEPREFIX,   187000, 1680, 1800, 1976, 2272, 0, 1050, 1053, 1059, 1099, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@75Hz */
++    { MODEPREFIX,   214750, 1680, 1808, 1984, 2288, 0, 1050, 1053, 1059, 1105, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@85Hz */
++    { MODEPREFIX,   245500, 1680, 1728, 1760, 1840, 0, 1050, 1053, 1059, 1112, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1680x1050@120Hz RB */
++    { MODEPREFIX,   204750, 1792, 1920, 2120, 2448, 0, 1344, 1345, 1348, 1394, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1792x1344@60Hz */
++    { MODEPREFIX,   261000, 1792, 1888, 2104, 2456, 0, 1344, 1345, 1348, 1417, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1792x1344@75Hz */
++    { MODEPREFIX,   333250, 1792, 1840, 1872, 1952, 0, 1344, 1347, 1351, 1423, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1792x1344@120Hz RB */
++    { MODEPREFIX,   218250, 1856, 1952, 2176, 2528, 0, 1392, 1393, 1396, 1439, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1856x1392@60Hz */
++    { MODEPREFIX,   288000, 1856, 1984, 2208, 2560, 0, 1392, 1393, 1396, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1856x1392@75Hz */
++    { MODEPREFIX,   356500, 1856, 1904, 1936, 2016, 0, 1392, 1395, 1399, 1474, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1856x1392@120Hz RB */
++    { MODEPREFIX,   154000, 1920, 1968, 2000, 2080, 0, 1200, 1203, 1209, 1235, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1200@60Hz RB */
++    { MODEPREFIX,   193250, 1920, 2056, 2256, 2592, 0, 1200, 1203, 1209, 1245, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@60Hz */
++    { MODEPREFIX,   245250, 1920, 2056, 2264, 2608, 0, 1200, 1203, 1209, 1255, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@75Hz */
++    { MODEPREFIX,   281250, 1920, 2064, 2272, 2624, 0, 1200, 1203, 1209, 1262, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@85Hz */
++    { MODEPREFIX,   317000, 1920, 1968, 2000, 2080, 0, 1200, 1203, 1209, 1271, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1200@120Hz RB */
++    { MODEPREFIX,   234000, 1920, 2048, 2256, 2600, 0, 1440, 1441, 1444, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1440@60Hz */
++    { MODEPREFIX,   297000, 1920, 2064, 2288, 2640, 0, 1440, 1441, 1444, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1440@75Hz */
++    { MODEPREFIX,   380500, 1920, 1968, 2000, 2080, 0, 1440, 1443, 1447, 1525, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1440@120Hz RB */
++    { MODEPREFIX,   268500, 2560, 2608, 2640, 2720, 0, 1600, 1603, 1609, 1646, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 2560x1600@60Hz RB */
++    { MODEPREFIX,   348500, 2560, 2752, 3032, 3504, 0, 1600, 1603, 1609, 1658, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@60Hz */
++    { MODEPREFIX,   443250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1672, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@75Hz */
++    { MODEPREFIX,   505250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@85Hz */
++    { MODEPREFIX,   552750, 2560, 2608, 2640, 2720, 0, 1600, 1603, 1609, 1694, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 2560x1600@120Hz RB */
++};
++
+ #define LEVEL_DMT 0
+ #define LEVEL_GTF 1
+ #define LEVEL_CVT 2
+@@ -288,12 +417,43 @@ MonitorStandardTimingLevel(xf86MonPtr DDC)
+     return LEVEL_DMT;
+ }
++static int
++ModeRefresh(DisplayModePtr mode)
++{
++    return (int)(xf86ModeVRefresh(mode) + 0.5);
++}
++
+ /*
+- * This is not really correct.  Appendix B of the EDID 1.4 spec defines
+- * the right thing to do here.  If the timing given here matches a mode
+- * defined in the VESA DMT standard, we _must_ use that.  If the device
+- * supports CVT modes, then we should generate a CVT timing.  If both
+- * of the above fail, use GTF.
++ * If rb is not set, then we'll not consider reduced-blanking modes as
++ * part of the DMT pool.  For the 'standard' EDID mode descriptor there's
++ * no way to specify whether the mode should be RB or not.
++ */
++static DisplayModePtr
++FindDMTMode(int hsize, int vsize, int refresh, Bool rb)
++{
++    int i;
++    DisplayModePtr ret;
++
++    for (i = 0; i < sizeof(DMTModes) / sizeof(DisplayModeRec); i++) {
++      ret = &DMTModes[i];
++
++      if (!rb && xf86ModeIsReduced(ret))
++          continue;
++
++      if (ret->HDisplay == hsize &&
++          ret->VDisplay == vsize &&
++          refresh == ModeRefresh(ret))
++          return xf86DuplicateMode(ret);
++    }
++
++    return NULL;
++}
++
++/*
++ * Appendix B of the EDID 1.4 spec defines the right thing to do here.
++ * If the timing given here matches a mode defined in the VESA DMT standard,
++ * we _must_ use that.  If the device supports CVT modes, then we should
++ * generate a CVT timing.  If both of the above fail, use GTF.
+  *
+  * There are some wrinkles here.  EDID 1.1 and 1.0 sinks can't really
+  * "support" GTF, since it wasn't a standard yet; so if they ask for a
+@@ -308,20 +468,28 @@ MonitorStandardTimingLevel(xf86MonPtr DDC)
+  */
+ static DisplayModePtr
+ DDCModesFromStandardTiming(struct std_timings *timing, ddc_quirk_t quirks,
+-                         int timing_level)
++                         int timing_level, Bool rb)
+ {
+     DisplayModePtr Modes = NULL, Mode = NULL;
+     int i;
+     for (i = 0; i < STD_TIMINGS; i++) {
+         if (timing[i].hsize && timing[i].vsize && timing[i].refresh) {
+-          /* XXX check for DMT first, else... */
+-          if (timing_level == LEVEL_CVT)
+-              Mode = xf86CVTMode(timing[i].hsize, timing[i].vsize,
+-                                 timing[i].refresh, FALSE, FALSE);
+-          else
+-              Mode = xf86GTFMode(timing[i].hsize, timing[i].vsize,
+-                                 timing[i].refresh, FALSE, FALSE);
++          Mode = FindDMTMode(timing[i].hsize, timing[i].vsize,
++                             timing[i].refresh, rb);
++
++          if (!Mode) {
++              if (timing_level == LEVEL_CVT)
++                  /* pass rb here too? */
++                  Mode = xf86CVTMode(timing[i].hsize, timing[i].vsize,
++                                     timing[i].refresh, FALSE, FALSE);
++              else if (timing_level == LEVEL_GTF)
++                  Mode = xf86GTFMode(timing[i].hsize, timing[i].vsize,
++                                     timing[i].refresh, FALSE, FALSE);
++          }
++
++          if (!Mode)
++              continue;
+           Mode->type = M_T_DRIVER;
+             Modes = xf86ModesAdd(Modes, Mode);
+@@ -595,7 +763,7 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
+     int                   i;
+     DisplayModePtr  Modes = NULL, Mode;
+     ddc_quirk_t           quirks;
+-    Bool          preferred;
++    Bool          preferred, rb;
+     int                   timing_level;
+     xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n",
+@@ -611,6 +779,8 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
+     if (quirks & (DDC_QUIRK_PREFER_LARGE_60 | DDC_QUIRK_PREFER_LARGE_75))
+       preferred = FALSE;
++    rb = xf86MonitorSupportsReducedBlanking(DDC);
++
+     timing_level = MonitorStandardTimingLevel(DDC);
+     for (i = 0; i < DET_TIMINGS; i++) {
+@@ -627,7 +797,7 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
+             break;
+         case DS_STD_TIMINGS:
+             Mode = DDCModesFromStandardTiming(det_mon->section.std_t,
+-                                            quirks, timing_level);
++                                            quirks, timing_level, rb);
+             Modes = xf86ModesAdd(Modes, Mode);
+             break;
+       case DS_CVT:
+@@ -644,7 +814,7 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
+     Modes = xf86ModesAdd(Modes, Mode);
+     /* Add standard timings */
+-    Mode = DDCModesFromStandardTiming(DDC->timings2, quirks, timing_level);
++    Mode = DDCModesFromStandardTiming(DDC->timings2, quirks, timing_level, rb);
+     Modes = xf86ModesAdd(Modes, Mode);
+     if (quirks & DDC_QUIRK_PREFER_LARGE_60)
+@@ -665,23 +835,21 @@ xf86DDCMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC)
+     DisplayModePtr Modes = NULL, Mode;
+     int i, clock;
+     Bool have_hsync = FALSE, have_vrefresh = FALSE, have_maxpixclock = FALSE;
++    ddc_quirk_t quirks;
+     if (!Monitor || !DDC)
+         return;
+     Monitor->DDC = DDC;
++    quirks = xf86DDCDetectQuirks(scrnIndex, DDC, FALSE);
++
+     if (Monitor->widthmm <= 0 && Monitor->heightmm <= 0) {
+       Monitor->widthmm = 10 * DDC->features.hsize;
+       Monitor->heightmm = 10 * DDC->features.vsize;
+     }
+-    /*
+-     * If this is a digital display, then we can use reduced blanking.
+-     * XXX This is a 1.3 heuristic.  1.4 explicitly defines rb support.
+-     */
+-    if (DDC->features.input_type)
+-        Monitor->reducedblanking = TRUE;
++    Monitor->reducedblanking = xf86MonitorSupportsReducedBlanking(DDC);
+     Modes = xf86DDCGetModes(scrnIndex, DDC);
+@@ -723,6 +891,8 @@ xf86DDCMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC)
+           }
+           clock = DDC->det_mon[i].section.ranges.max_clock * 1000;
++          if (quirks & DDC_QUIRK_DVI_SINGLE_LINK)
++              clock = min(clock, 165000);
+           if (!have_maxpixclock && clock > Monitor->maxPixClock)
+               Monitor->maxPixClock = clock;
+diff --git a/hw/xfree86/modes/xf86Modes.c b/hw/xfree86/modes/xf86Modes.c
+index ea398ad..da25273 100644
+--- a/hw/xfree86/modes/xf86Modes.c
++++ b/hw/xfree86/modes/xf86Modes.c
+@@ -513,6 +513,18 @@ xf86ValidateModesBandwidth(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+     }
+ }
++Bool
++xf86ModeIsReduced(DisplayModePtr mode)
++{
++    if ((((mode->HDisplay * 5 / 4) & ~0x07) > mode->HTotal) &&
++        ((mode->HTotal - mode->HDisplay) == 160) &&
++      ((mode->HSyncEnd - mode->HDisplay) == 80) &&
++      ((mode->HSyncEnd - mode->HSyncStart) == 32) &&
++      ((mode->VSyncStart - mode->VDisplay) == 3))
++      return TRUE;
++    return FALSE;
++}
++
+ /**
+  * Marks as bad any reduced-blanking modes.
+  *
+diff --git a/hw/xfree86/modes/xf86Modes.h b/hw/xfree86/modes/xf86Modes.h
+index acdea65..af5987b 100644
+--- a/hw/xfree86/modes/xf86Modes.h
++++ b/hw/xfree86/modes/xf86Modes.h
+@@ -64,6 +64,9 @@ DisplayModePtr xf86CVTMode(int HDisplay, int VDisplay, float VRefresh,
+                          Bool Reduced, Bool Interlaced);
+ DisplayModePtr xf86GTFMode(int h_pixels, int v_lines, float freq, int interlaced, int margins);
++Bool
++xf86ModeIsReduced(DisplayModePtr mode);
++
+ void
+ xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+                      int flags);
+-- 
+1.5.6.4
+
 From bd9c6b3a4d726a3f83ac6d8cf7211eddbc28f25a Mon Sep 17 00:00:00 2001
 From: Adam Jackson <ajax@redhat.com>
 Date: Tue, 14 Oct 2008 14:04:01 -0400
similarity index 56%
rename from xorg-xserver-server-glyph.patch
rename to xorg-xserver-server-exa.patch
index 31ec7cd263f5d00b0066b09c0e9a5aec3329c0e1..b50db2f6b923fb3b5a05fa16e63d88b03d5025e5 100644 (file)
@@ -1,14 +1,10 @@
-commit 54184110f6f3e5d7276d5431e739a4fcf0c3523e
-Author: Owen Taylor <otaylor@huygens.home.fishsoup.net>
-Date:   Mon Apr 28 21:00:54 2008 +0200
+From e99347a3e82e6db47dd482169b6799968afc3893 Mon Sep 17 00:00:00 2001
+From: Dave Airlie <airlied@redhat.com>
+Date: Wed, 20 Aug 2008 10:11:07 -0400
+Subject: [PATCH] Upgrade to master EXA
+
+---
 
-    EXA: Use a single large glyph cache pixmap
-    
-    Add back exaGlyphs(); the new version copies the glyph images
-    onto a single large glyph pixmap and draws from their to the
-    destination surface. This reduces the management of small
-    offscreen areas and will allow us to avoid texture unit setup
-    between each glyph.
 
 diff --git a/exa/Makefile.am b/exa/Makefile.am
 index e2f7ed3..2b3f1e4 100644
@@ -23,53 +19,508 @@ index e2f7ed3..2b3f1e4 100644
        exa_offscreen.c \
        exa_render.c \
 diff --git a/exa/exa.c b/exa/exa.c
-index 3a6ad98..809fb4b 100644
+index ccf148a..12c1549 100644
 --- a/exa/exa.c
 +++ b/exa/exa.c
-@@ -739,6 +739,8 @@ exaCloseScreen(int i, ScreenPtr pScreen)
+@@ -35,8 +35,6 @@
+ #include <stdlib.h>
+ #include "exa_priv.h"
+-#include <X11/fonts/fontstruct.h>
+-#include "dixfontstr.h"
+ #include "exa.h"
+ #include "cw.h"
+@@ -161,7 +159,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);
+@@ -261,6 +259,21 @@ exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
+                                      pExaScr->info->pixmapPitchAlign);
+ }
++
++static void
++ExaDamageReport(DamagePtr pDamage, RegionPtr pReg, void *pClosure)
++{
++    PixmapPtr pPixmap = pClosure;
++    ExaPixmapPriv(pPixmap);
++    RegionPtr pDamageReg = DamageRegion(pDamage);
++
++    if (pExaPixmap->pendingDamage) {
++      REGION_UNION(pScreen, pDamageReg, pDamageReg, pReg);
++      pExaPixmap->pendingDamage = FALSE;
++    }
++}
++
++
+ /**
+  * exaCreatePixmap() creates a new pixmap.
+  *
+@@ -321,6 +334,7 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth,
+                                        paddedWidth, NULL);
+         pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+         pExaPixmap->fb_ptr = NULL;
++        pExaPixmap->pDamage = NULL;
+     } else {
+         pExaPixmap->driverPriv = NULL;
+         /* Scratch pixmaps may have w/h equal to zero, and may not be
+@@ -345,21 +359,22 @@ 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 (ExaDamageReport, NULL,
++                                          DamageReportRawRegion, 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);
++      DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE);
++    }
++ 
++    pExaPixmap->area = NULL;
+     /* None of the pixmap bits are valid initially */
+     REGION_NULL(pScreen, &pExaPixmap->validSys);
+@@ -656,34 +671,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;
+ }
+@@ -737,6 +743,9 @@ exaCloseScreen(int i, ScreenPtr pScreen)
      PictureScreenPtr  ps = GetPictureScreenIfSet(pScreen);
  #endif
  
-+    exaGlyphsFini(pScreen);
++    if (ps->Glyphs == exaGlyphs)
++      exaGlyphsFini(pScreen);
 +
      pScreen->CreateGC = pExaScr->SavedCreateGC;
      pScreen->CloseScreen = pExaScr->SavedCloseScreen;
      pScreen->GetImage = pExaScr->SavedGetImage;
-@@ -754,7 +754,9 @@
+@@ -750,8 +759,9 @@ exaCloseScreen(int i, ScreenPtr pScreen)
  #ifdef RENDER
      if (ps) {
        ps->Composite = pExaScr->SavedComposite;
 +      ps->Glyphs = pExaScr->SavedGlyphs;
        ps->Trapezoids = pExaScr->SavedTrapezoids;
+-      ps->AddTraps = pExaScr->SavedAddTraps;
 +      ps->Triangles = pExaScr->SavedTriangles;
-       ps->AddTraps = pExaScr->SavedAddTraps;
      }
  #endif
-@@ -914,6 +918,9 @@ exaDriverInit (ScreenPtr           pScreen,
+@@ -913,14 +923,16 @@ exaDriverInit (ScreenPtr         pScreen,
          pExaScr->SavedComposite = ps->Composite;
        ps->Composite = exaComposite;
  
-+      pExaScr->SavedGlyphs = ps->Glyphs;
-+      ps->Glyphs = exaGlyphs;
++      if (pScreenInfo->PrepareComposite) {
++          pExaScr->SavedGlyphs = ps->Glyphs;
++          ps->Glyphs = exaGlyphs;
++      }
 +      
        pExaScr->SavedTriangles = ps->Triangles;
        ps->Triangles = exaTriangles;
  
-@@ -973,6 +980,8 @@ exaDriverInit (ScreenPtr           pScreen,
+       pExaScr->SavedTrapezoids = ps->Trapezoids;
+       ps->Trapezoids = exaTrapezoids;
+-
+-      pExaScr->SavedAddTraps = ps->AddTraps;
+-      ps->AddTraps = ExaCheckAddTraps;
+     }
+ #endif
+@@ -968,6 +980,9 @@ exaDriverInit (ScreenPtr           pScreen,
        }
      }
  
-+    exaGlyphsInit(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/exa/exa.h b/exa/exa.h
+index 2562094..8d9bcea 100644
+--- a/exa/exa.h
++++ b/exa/exa.h
+@@ -744,21 +744,36 @@ typedef struct _ExaDriver {
+ /** @} */
++/* 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,30 +786,23 @@ 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);
++
++/* in exa_migration.c */
+ void
+ 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/exa/exa_accel.c b/exa/exa_accel.c
+index 3ec9625..1c07a0b 100644
+--- a/exa/exa_accel.c
++++ b/exa/exa_accel.c
+@@ -144,7 +144,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 +165,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);
+@@ -441,16 +445,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) {
+@@ -860,16 +884,23 @@ exaImageGlyphBlt (DrawablePtr    pDrawable,
+     FbBits        depthMask;
+     PixmapPtr     pPixmap = exaGetDrawablePixmap(pDrawable);
+     ExaPixmapPriv(pPixmap);
+-    RegionPtr     pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
+-    BoxRec        extents = *REGION_EXTENTS(pScreen, pending_damage);
++    RegionPtr     pending_damage = NULL;
++    BoxRec        extents;
+     int                   xoff, yoff;
+-    if (extents.x1 >= extents.x2 || extents.y1 >= extents.y2)
+-      return;
++    if (pExaPixmap->pDamage)
++      pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
++
++    if (pending_damage) {
++      extents = *REGION_EXTENTS(pScreen, pending_damage);
++
++      if (extents.x1 >= extents.x2 || extents.y1 >= extents.y2)
++          return;
+-    depthMask = FbFullMask(pDrawable->depth);
++      depthMask = FbFullMask(pDrawable->depth);
++    }
+-    if ((pGC->planemask & depthMask) != depthMask)
++    if (!pending_damage || (pGC->planemask & depthMask) != depthMask)
+     {
+       ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase);
+       return;
+@@ -1103,6 +1134,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;
+@@ -1125,14 +1157,11 @@ exaFillRegionTiled (DrawablePtr        pDrawable,
+     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 +1169,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 +1217,57 @@ 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 if ((*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/exa/exa_glyphs.c b/exa/exa_glyphs.c
 new file mode 100644
-index 0000000..3fe433a
+index 0000000..b23e7f6
 --- /dev/null
 +++ b/exa/exa_glyphs.c
-@@ -0,0 +1,745 @@
+@@ -0,0 +1,897 @@
 +/*
 + * Copyright © 2008 Red Hat, Inc.
 + * Partly based on code Copyright © 2000 SuSE, Inc.
@@ -128,16 +579,6 @@ index 0000000..3fe433a
 +#define DBG_GLYPH_CACHE(a)
 +#endif
 +
-+/* Instructions for rendering a single glyph */
-+typedef struct {
-+    INT16 xSrc;
-+    INT16 ySrc;
-+    INT16 xDst;
-+    INT16 yDst;
-+    INT16 width;
-+    INT16 height;
-+} ExaGlyphRenderRec, *ExaGlyphRenderPtr;
-+
 +/* 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.
@@ -151,7 +592,7 @@ index 0000000..3fe433a
 +
 +typedef struct {
 +    PicturePtr source;
-+    ExaGlyphRenderRec glyphs[GLYPH_BUFFER_SIZE];
++    ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE];
 +    int count;
 +} ExaGlyphBuffer, *ExaGlyphBufferPtr;
 +
@@ -255,12 +696,13 @@ index 0000000..3fe433a
 +    for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
 +      ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
 +      int rows;
-+      
++
 +      if (cache->format != format)
 +          continue;
 +
-+      rows = (cache->size + cache->columns - 1) / cache->columns;
++      cache->yOffset = height;
 +
++      rows = (cache->size + cache->columns - 1) / cache->columns;
 +      height += rows * cache->glyphHeight;
 +    }
 +
@@ -341,11 +783,9 @@ index 0000000..3fe433a
 +          return -1;
 +
 +      if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){
-+          DBG_GLYPH_CACHE((" found entry at %d\n", slot));
 +          return entryPos;
 +      }
 +          
-+      DBG_GLYPH_CACHE((" lookup linear probe bumpalong\n"));
 +      slot--;
 +      if (slot < 0)
 +          slot = cache->hashSize - 1;
@@ -365,7 +805,6 @@ index 0000000..3fe433a
 +    
 +    while (TRUE) { /* hash table can never be full */
 +      if (cache->hashEntries[slot] == -1) {
-+          DBG_GLYPH_CACHE((" inserting entry at %d\n", slot));
 +          cache->hashEntries[slot] = pos;
 +          return;
 +      }
@@ -428,6 +867,69 @@ index 0000000..3fe433a
 +    }
 +}
 +
++#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.
++ */
++static Bool
++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)
++      return FALSE;
++
++    /* If the glyph pixmap is already uploaded, no point in doing
++     * things this way */
++    if (exaPixmapIsOffscreen(pGlyphPixmap))
++      return FALSE;
++
++    /* UploadToScreen only works if bpp match */
++    if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel)
++      return FALSE;
++
++    /* 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))
++      return FALSE;
++
++    /* 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))
++      return FALSE;
++
++    /* This pixmap should never be bound to a window, so no need to offset coordinates. */
++    exaPixmapDirty (pCachePixmap,
++                  CACHE_X(pos),
++                  CACHE_Y(pos),
++                  CACHE_X(pos) + pGlyph->info.width,
++                  CACHE_Y(pos) + pGlyph->info.height);
++
++    return TRUE;
++}
++
 +static ExaGlyphCacheResult
 +exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
 +                       ExaGlyphCachePtr  cache,
@@ -436,7 +938,7 @@ index 0000000..3fe433a
 +                       int               xGlyph,
 +                       int               yGlyph)
 +{
-+    ExaGlyphRenderPtr glyphRec;
++    ExaCompositeRectPtr rect;
 +    int pos;
 +    
 +    if (buffer->source && buffer->source != cache->picture)
@@ -475,11 +977,11 @@ index 0000000..3fe433a
 +              int x, y;
 +              int i;
 +              
-+              x = (pos % cache->columns) * cache->glyphWidth;
-+              y = (pos / cache->columns) * cache->glyphHeight;
++              x = CACHE_X(pos);
++              y = CACHE_Y(pos);
 +
 +              for (i = 0; i < buffer->count; i++) {
-+                  if (buffer->glyphs[i].xSrc == x && buffer->glyphs[i].ySrc == y) {
++                  if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) {
 +                      DBG_GLYPH_CACHE(("  must flush buffer\n"));
 +                      return ExaGlyphNeedFlush;
 +                  }
@@ -494,36 +996,44 @@ index 0000000..3fe433a
 +          cache->evictionPosition = rand() % cache->size;
 +      }
 +
-+      /* Now actually upload the glyph into the cache picture */
++      /* Now actually upload the glyph into the cache picture; if
++       * we can't do it with UploadToScreen (because the glyph is
++       * offscreen, etc), we fall back to CompositePicture.
++       */
++      if (!exaGlyphCacheUploadGlyph(pScreen, cache, pos, pGlyph)) {
++          CompositePicture (PictOpSrc,
++                            GlyphPicture(pGlyph)[pScreen->myNum],
++                            None,
++                            cache->picture,
++                            0, 0,
++                            0, 0,
++                            CACHE_X(pos),
++                            CACHE_Y(pos),
++                            pGlyph->info.width,
++                            pGlyph->info.height);
++      }
 +
-+      CompositePicture (PictOpSrc,
-+                        GlyphPicture(pGlyph)[pScreen->myNum],
-+                        None,
-+                        cache->picture,
-+                        0, 0,
-+                        0, 0,
-+                        (pos % cache->columns) * cache->glyphWidth,
-+                        (pos / cache->columns) * cache->glyphHeight,
-+                        pGlyph->info.width,
-+                        pGlyph->info.height);
 +    }
 +    
 +
 +    buffer->source = cache->picture;
 +          
-+    glyphRec = &buffer->glyphs[buffer->count];
-+    glyphRec->xSrc = (pos % cache->columns) * cache->glyphWidth;
-+    glyphRec->ySrc = (pos / cache->columns) * cache->glyphHeight;
-+    glyphRec->xDst = xGlyph - pGlyph->info.x;
-+    glyphRec->yDst = yGlyph - pGlyph->info.y;
-+    glyphRec->width = pGlyph->info.width;
-+    glyphRec->height = pGlyph->info.height;
++    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,
@@ -534,13 +1044,16 @@ index 0000000..3fe433a
 +    ExaScreenPriv(pScreen);
 +    unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format;
 +    int width = pGlyph->info.width;
-+    int height = pGlyph->info.width;
-+    ExaGlyphRenderPtr glyphRec;
++    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];
@@ -569,13 +1082,13 @@ index 0000000..3fe433a
 +
 +    buffer->source = source;
 +    
-+    glyphRec = &buffer->glyphs[buffer->count];
-+    glyphRec->xSrc = 0;
-+    glyphRec->ySrc = 0;
-+    glyphRec->xDst = xGlyph - pGlyph->info.x;
-+    glyphRec->yDst = yGlyph - pGlyph->info.y;
-+    glyphRec->width = pGlyph->info.width;
-+    glyphRec->height = pGlyph->info.height;
++    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++;
 +
@@ -586,27 +1099,12 @@ index 0000000..3fe433a
 +exaGlyphsToMask(PicturePtr        pMask,
 +              ExaGlyphBufferPtr buffer)
 +{
-+    int i;
-+
-+    for (i = 0; i < buffer->count; i++) {
-+      ExaGlyphRenderPtr glyphRec = &buffer->glyphs[i];
-+      
-+      CompositePicture (PictOpAdd,
-+                        buffer->source,
-+                        None,
-+                        pMask,
-+                        glyphRec->xSrc,
-+                        glyphRec->ySrc,
-+                        0, 0,
-+                        glyphRec->xDst,
-+                        glyphRec->yDst,
-+                        glyphRec->width,
-+                        glyphRec->height);
-+    }
-+    
-+    buffer->count = 0;
-+    buffer->source = NULL;
-+}
++    exaCompositeRects(PictOpAdd, buffer->source, pMask,
++                    buffer->count, buffer->rects);
++    
++    buffer->count = 0;
++    buffer->source = NULL;
++}
 +
 +static void
 +exaGlyphsToDst(CARD8           op,
@@ -621,20 +1119,20 @@ index 0000000..3fe433a
 +    int i;
 +
 +    for (i = 0; i < buffer->count; i++) {
-+      ExaGlyphRenderPtr glyphRec = &buffer->glyphs[i];
++      ExaCompositeRectPtr rect = &buffer->rects[i];
 +      
 +      CompositePicture (op,
 +                        pSrc,
 +                        buffer->source,
 +                        pDst,
-+                        xSrc + glyphRec->xDst - xDst,
-+                        ySrc + glyphRec->yDst - yDst,
-+                        glyphRec->xSrc,
-+                        glyphRec->ySrc,
-+                        glyphRec->xDst,
-+                        glyphRec->yDst,
-+                        glyphRec->width,
-+                        glyphRec->height);
++                        xSrc + rect->xDst - xDst,
++                        ySrc + rect->yDst - yDst,
++                        rect->xSrc,
++                        rect->ySrc,
++                        rect->xDst,
++                        rect->yDst,
++                        rect->width,
++                        rect->height);
 +    }
 +    
 +    buffer->count = 0;
@@ -694,6 +1192,79 @@ index 0000000..3fe433a
 +    }
 +}
 +
++/**
++ * 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;
++}
++
 +#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
 +
 +void
@@ -721,6 +1292,29 @@ index 0000000..3fe433a
 +    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;
@@ -732,6 +1326,14 @@ index 0000000..3fe433a
 +          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);
@@ -775,7 +1377,8 @@ index 0000000..3fe433a
 +          glyph = *glyphs++;
 +          pPicture = GlyphPicture (glyph)[pScreen->myNum];
 +
-+          if (exaBufferGlyph(pScreen, &buffer, glyph, x, y) == ExaGlyphNeedFlush)
++          if (glyph->info.width > 0 && glyph->info.height > 0 &&
++              exaBufferGlyph(pScreen, &buffer, glyph, x, y) == ExaGlyphNeedFlush)
 +          {
 +              if (maskFormat)
 +                  exaGlyphsToMask(pMask, &buffer);
@@ -815,8 +1418,93 @@ index 0000000..3fe433a
 +      (*pScreen->DestroyPixmap) (pMaskPixmap);
 +    }
 +}
+diff --git a/exa/exa_migration.c b/exa/exa_migration.c
+index 5f22474..2bb2ad9 100644
+--- a/exa/exa_migration.c
++++ b/exa/exa_migration.c
+@@ -33,8 +33,6 @@
+ #include <string.h>
+ #include "exa_priv.h"
+-#include <X11/fonts/fontstruct.h>
+-#include "dixfontstr.h"
+ #include "exa.h"
+ #include "cw.h"
+@@ -45,6 +43,39 @@
+ #endif
+ /**
++ * Returns TRUE if the pixmap has damage.
++ * EXA only migrates the parts of a destination 
++ * that are affected by rendering.
++ * It uses the current damage as indication.
++ * So anything that does not need to be updated won't be.
++ * For clarity this seperate function was made.
++ * Note that some situations don't use this, 
++ * because their calls are wrapped by the damage layer.
++ */
++Bool
++exaDamageDestForMigration(DrawablePtr pDrawable, PixmapPtr pPix, RegionPtr region)
++{
++    ScreenPtr pScreen = pDrawable->pScreen;
++    (void) pScreen; /* the macros don't use pScreen currently */
++    ExaPixmapPriv (pPix);
++    int x_offset, y_offset;
++    RegionPtr pending_damage;
++
++    if (!pExaPixmap->pDamage)
++      return FALSE;
++
++    exaGetDrawableDeltas(pDrawable, pPix, &x_offset, &y_offset);
++
++    REGION_TRANSLATE(pScreen, region, x_offset, y_offset);
++    pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
++    REGION_UNION(pScreen, pending_damage, pending_damage, region);
++    /* Restore region as we got it. */
++    REGION_TRANSLATE(pScreen, region, -x_offset, -y_offset);
++
++    return TRUE;
++}
++
++/**
+  * Returns TRUE if the pixmap is not movable.  This is the case where it's a
+  * fake pixmap for the frontbuffer (no pixmap private) or it's a scratch
+  * pixmap created by some other X Server internals (the score says it's
+@@ -211,9 +242,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) {
+@@ -301,6 +332,9 @@ exaDoMoveInPixmap (ExaMigrationPtr migrate)
+     ExaScreenPriv (pScreen);
+     ExaPixmapPriv (pPixmap);
++    if (migrate->as_dst)
++      pExaPixmap->pendingDamage = TRUE;
++
+     /* If we're VT-switched away, no touching card memory allowed. */
+     if (pExaScr->swappedOut)
+       return;
+@@ -369,6 +403,9 @@ exaDoMoveOutPixmap (ExaMigrationPtr migrate)
+     PixmapPtr pPixmap = migrate->pPix;
+     ExaPixmapPriv (pPixmap);
++    if (migrate->as_dst)
++      pExaPixmap->pendingDamage = TRUE;
++
+     if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
+       return;
 diff --git a/exa/exa_priv.h b/exa/exa_priv.h
-index 0138e4a..aaceeb8 100644
+index e4b6b54..0ebe07b 100644
 --- a/exa/exa_priv.h
 +++ b/exa/exa_priv.h
 @@ -61,6 +61,7 @@
@@ -827,7 +1515,7 @@ index 0138e4a..aaceeb8 100644
  
  #if DEBUG_TRACE_FALL
  #define EXA_FALLBACK(x)                                       \
-@@ -95,6 +96,37 @@ enum ExaMigrationHeuristic {
+@@ -95,6 +96,38 @@ enum ExaMigrationHeuristic {
      ExaMigrationSmart
  };
  
@@ -856,6 +1544,7 @@ index 0138e4a..aaceeb8 100644
 +    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;
@@ -865,7 +1554,15 @@ index 0138e4a..aaceeb8 100644
  typedef void (*EnableDisableFBAccessProcPtr)(int, Bool);
  typedef struct {
      ExaDriverPtr info;
-@@ -122,6 +154,8 @@ typedef struct {
+@@ -114,7 +147,6 @@ typedef struct {
+     TrianglesProcPtr           SavedTriangles;
+     GlyphsProcPtr                SavedGlyphs;
+     TrapezoidsProcPtr            SavedTrapezoids;
+-    AddTrapsProcPtr            SavedAddTraps;
+ #endif
+   
+     Bool                       swappedOut;
+@@ -123,6 +155,8 @@ typedef struct {
      unsigned                   disableFbCount;
      Bool                       optimize_migration;
      unsigned                   offScreenCounter;
@@ -874,190 +1571,15 @@ index 0138e4a..aaceeb8 100644
  } ExaScreenPrivRec, *ExaScreenPrivPtr;
  
  /*
-@@ -432,6 +466,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,
-commit 40eb14c9482457969e0bde97c49edad536285e02
-Author: Owen Taylor <otaylor@huygens.home.fishsoup.net>
-Date:   Mon Apr 28 21:00:54 2008 +0200
-
-    EXA: Add exaCompositeRects()
-    
-    Add a function to composite multiple independent rectangles
-    from the same source to the same destination in a single
-    operation: this is useful for building a glyph mask.
-
-diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c
-index 3fe433a..55fdb01 100644
---- a/exa/exa_glyphs.c
-+++ b/exa/exa_glyphs.c
-@@ -56,16 +56,6 @@
- #define DBG_GLYPH_CACHE(a)
- #endif
--/* Instructions for rendering a single glyph */
--typedef struct {
--    INT16 xSrc;
--    INT16 ySrc;
--    INT16 xDst;
--    INT16 yDst;
--    INT16 width;
--    INT16 height;
--} ExaGlyphRenderRec, *ExaGlyphRenderPtr;
--
- /* 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.
-@@ -79,7 +69,7 @@ typedef struct {
- typedef struct {
-     PicturePtr source;
--    ExaGlyphRenderRec glyphs[GLYPH_BUFFER_SIZE];
-+    ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE];
-     int count;
- } ExaGlyphBuffer, *ExaGlyphBufferPtr;
-@@ -364,7 +354,7 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
-                        int               xGlyph,
-                        int               yGlyph)
- {
--    ExaGlyphRenderPtr glyphRec;
-+    ExaCompositeRectPtr rect;
-     int pos;
-     
-     if (buffer->source && buffer->source != cache->picture)
-@@ -407,7 +397,7 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
-               y = (pos / cache->columns) * cache->glyphHeight;
-               for (i = 0; i < buffer->count; i++) {
--                  if (buffer->glyphs[i].xSrc == x && buffer->glyphs[i].ySrc == y) {
-+                  if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) {
-                       DBG_GLYPH_CACHE(("  must flush buffer\n"));
-                       return ExaGlyphNeedFlush;
-                   }
-@@ -439,13 +429,13 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
-     buffer->source = cache->picture;
-           
--    glyphRec = &buffer->glyphs[buffer->count];
--    glyphRec->xSrc = (pos % cache->columns) * cache->glyphWidth;
--    glyphRec->ySrc = (pos / cache->columns) * cache->glyphHeight;
--    glyphRec->xDst = xGlyph - pGlyph->info.x;
--    glyphRec->yDst = yGlyph - pGlyph->info.y;
--    glyphRec->width = pGlyph->info.width;
--    glyphRec->height = pGlyph->info.height;
-+    rect = &buffer->rects[buffer->count];
-+    rect->xSrc = (pos % cache->columns) * cache->glyphWidth;
-+    rect->ySrc = (pos / cache->columns) * cache->glyphHeight;
-+    rect->xDst = xGlyph - pGlyph->info.x;
-+    rect->yDst = yGlyph - pGlyph->info.y;
-+    rect->width = pGlyph->info.width;
-+    rect->height = pGlyph->info.height;
-           
-     buffer->count++;
-@@ -463,7 +453,7 @@ exaBufferGlyph(ScreenPtr         pScreen,
-     unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format;
-     int width = pGlyph->info.width;
-     int height = pGlyph->info.width;
--    ExaGlyphRenderPtr glyphRec;
-+    ExaCompositeRectPtr rect;
-     PicturePtr source;
-     int i;
-@@ -497,13 +487,13 @@ exaBufferGlyph(ScreenPtr         pScreen,
-     buffer->source = source;
-     
--    glyphRec = &buffer->glyphs[buffer->count];
--    glyphRec->xSrc = 0;
--    glyphRec->ySrc = 0;
--    glyphRec->xDst = xGlyph - pGlyph->info.x;
--    glyphRec->yDst = yGlyph - pGlyph->info.y;
--    glyphRec->width = pGlyph->info.width;
--    glyphRec->height = pGlyph->info.height;
-+    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++;
-@@ -514,23 +504,8 @@ static void
- exaGlyphsToMask(PicturePtr        pMask,
-               ExaGlyphBufferPtr buffer)
- {
--    int i;
--
--    for (i = 0; i < buffer->count; i++) {
--      ExaGlyphRenderPtr glyphRec = &buffer->glyphs[i];
--      
--      CompositePicture (PictOpAdd,
--                        buffer->source,
--                        None,
--                        pMask,
--                        glyphRec->xSrc,
--                        glyphRec->ySrc,
--                        0, 0,
--                        glyphRec->xDst,
--                        glyphRec->yDst,
--                        glyphRec->width,
--                        glyphRec->height);
--    }
-+    exaCompositeRects(PictOpAdd, buffer->source, pMask,
-+                    buffer->count, buffer->rects);
-     
-     buffer->count = 0;
-     buffer->source = NULL;
-@@ -549,20 +524,20 @@ exaGlyphsToDst(CARD8              op,
-     int i;
-     for (i = 0; i < buffer->count; i++) {
--      ExaGlyphRenderPtr glyphRec = &buffer->glyphs[i];
-+      ExaCompositeRectPtr rect = &buffer->rects[i];
-       
-       CompositePicture (op,
-                         pSrc,
-                         buffer->source,
-                         pDst,
--                        xSrc + glyphRec->xDst - xDst,
--                        ySrc + glyphRec->yDst - yDst,
--                        glyphRec->xSrc,
--                        glyphRec->ySrc,
--                        glyphRec->xDst,
--                        glyphRec->yDst,
--                        glyphRec->width,
--                        glyphRec->height);
-+                        xSrc + rect->xDst - xDst,
-+                        ySrc + rect->yDst - yDst,
-+                        rect->xSrc,
-+                        rect->ySrc,
-+                        rect->xDst,
-+                        rect->yDst,
-+                        rect->width,
-+                        rect->height);
-     }
-     
-     buffer->count = 0;
-diff --git a/exa/exa_priv.h b/exa/exa_priv.h
-index aaceeb8..0d5d0f5 100644
---- a/exa/exa_priv.h
-+++ b/exa/exa_priv.h
-@@ -243,6 +243,15 @@ typedef struct _ExaMigrationRec {
+@@ -192,6 +226,7 @@ typedef struct {
+      * location.
+      */
+     DamagePtr     pDamage;
++    Bool          pendingDamage;
+     /**
+      * The valid regions mark the valid bits (at least, as they're derived from
+      * damage, which may be overreported) of a pixmap's system and FB copies.
+@@ -210,18 +245,21 @@ typedef struct _ExaMigrationRec {
      RegionPtr pReg;
  } ExaMigrationRec, *ExaMigrationPtr;
  
@@ -1073,7 +1595,33 @@ index aaceeb8..0d5d0f5 100644
  /**
   * 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.
-@@ -457,6 +466,13 @@ exaComposite(CARD8        op,
+   */
+ void exaDDXDriverInit (ScreenPtr pScreen);
+-void
+-exaPrepareAccessWindow(WindowPtr pWin);
+-
+-void
+-exaFinishAccessWindow(WindowPtr pWin);
+-
+ /* exa_unaccel.c */
+ void
+ exaPrepareAccessGC(GCPtr pGC);
+@@ -294,13 +332,6 @@ ExaCheckGetSpans (DrawablePtr pDrawable,
+                int nspans,
+                char *pdstStart);
+-void
+-ExaCheckAddTraps (PicturePtr  pPicture,
+-                INT16         x_off,
+-                INT16         y_off,
+-                int           ntrap,
+-                xTrap         *traps);
+-
+ /* exa_accel.c */
+ static _X_INLINE Bool
+@@ -422,6 +453,13 @@ exaComposite(CARD8        op,
             CARD16     height);
  
  void
@@ -1087,8 +1635,30 @@ index aaceeb8..0d5d0f5 100644
  exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
                 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
                 int ntrap, xTrapezoid *traps);
+@@ -431,6 +469,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,
+@@ -449,4 +494,7 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
+ void
+ exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area);
++Bool
++exaDamageDestForMigration(DrawablePtr pDrawable, PixmapPtr pPix, RegionPtr region);
++
+ #endif /* EXAPRIV_H */
 diff --git a/exa/exa_render.c b/exa/exa_render.c
-index 1d7b897..43b0029 100644
+index 1d7b897..bafa309 100644
 --- a/exa/exa_render.c
 +++ b/exa/exa_render.c
 @@ -332,6 +332,228 @@ exaTryDriverSolidFill(PicturePtr pSrc,
@@ -1108,6 +1678,9 @@ index 1d7b897..43b0029 100644
 +    struct _Pixmap scratch;
 +    ExaMigrationRec pixmaps[2];
 +
++    if (!pExaScr->info->PrepareComposite)
++      return -1;
++
 +    pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
 +    pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
 +
@@ -1226,65 +1799,60 @@ index 1d7b897..43b0029 100644
 +{
 +    PixmapPtr pPixmap = exaGetDrawablePixmap(pDst->pDrawable);
 +    ExaPixmapPriv(pPixmap);
-+    
-+    int xoff, yoff;
-+    int x1 = MAXSHORT;
-+    int y1 = MAXSHORT;
-+    int x2 = MINSHORT;
-+    int y2 = MINSHORT;
 +    RegionRec region;
-+    RegionPtr pending_damage;
-+    BoxRec box;
 +    int n;
 +    ExaCompositeRectPtr r;
 +    
-+    /* 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.
-+     */
++    if (pExaPixmap->pDamage) {
++      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->width;
-+
-+      if (r->xDst < x1) x1 = r->xDst;
-+      if (r->xDst < y1) y1 = r->xDst;
-+      if (rect_x2 > x2) x2 = rect_x2;
-+      if (rect_y2 > y2) y2 = rect_y2;
-+      
-+      r++;
-+    }
++      /* 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->width;
 +
-+    if (x2 <= x1 && y2 <= y1)
-+      return;
++          if (r->xDst < x1) x1 = r->xDst;
++          if (r->xDst < y1) y1 = r->xDst;
++          if (rect_x2 > x2) x2 = rect_x2;
++          if (rect_y2 > y2) y2 = rect_y2;
 +
-+    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);
-+    
-+    exaGetDrawableDeltas(pDst->pDrawable, pPixmap, &xoff, &yoff);
++          r++;
++      }
 +
-+    REGION_TRANSLATE(pScreen, &region, xoff, yoff);
-+    pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
-+    REGION_UNION(pScreen, pending_damage, pending_damage, &region);
-+    REGION_TRANSLATE(pScreen, &region, -xoff, -yoff);
++      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);
++    
++      exaDamageDestForMigration(pDst->pDrawable, pPixmap, &region);
++    }
 +    
 +    /************************************************************/
 +    
@@ -1306,413 +1874,111 @@ index 1d7b897..43b0029 100644
 +    
 +    /************************************************************/
 +
-+    /* Now we have to flush the damage out from pendingDamage => damage 
-+     * Calling DamageDamageRegion has that effect. (We could pass
-+     * in an empty region here, but we pass in the same region we
-+     * use above; the effect is the same.)
-+     */
++    if (pExaPixmap->pDamage) {
++      /* Now we have to flush the damage out from pendingDamage => damage 
++       * Calling DamageDamageRegion has that effect. (We could pass
++       * in an empty region here, but we pass in the same region we
++       * use above; the effect is the same.)
++       */
 +
-+    DamageDamageRegion(pDst->pDrawable, &region);
-+    REGION_UNINIT(pScreen, &region);
++      DamageDamageRegion(pDst->pDrawable, &region);
++      REGION_UNINIT(pScreen, &region);
++    }
 +}
 +
 +static int
  exaTryDriverComposite(CARD8           op,
                      PicturePtr        pSrc,
                      PicturePtr        pMask,
-commit fcb5949928f1c27f67f40c094c3c673786574422
-Author: Owen Taylor <otaylor@huygens.home.fishsoup.net>
-Date:   Mon Apr 28 21:00:54 2008 +0200
-
-    EXA: Fix overlapping glyphs in glyph cache
-    
-    Allocate each cache at a different vertical position in the
-    per-format pixmap. Fix width/height confusion when choosing
-    the cache for a glyph.
-
-diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c
-index 55fdb01..851e439 100644
---- a/exa/exa_glyphs.c
-+++ b/exa/exa_glyphs.c
-@@ -173,12 +173,13 @@ exaRealizeGlyphCaches(ScreenPtr    pScreen,
-     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
-       ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
-       int rows;
--      
-+
-       if (cache->format != format)
-           continue;
--      rows = (cache->size + cache->columns - 1) / cache->columns;
-+      cache->yOffset = height;
-+      rows = (cache->size + cache->columns - 1) / cache->columns;
-       height += rows * cache->glyphHeight;
-     }
+@@ -843,22 +1065,16 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+       PixmapPtr pixmap = exaGetDrawablePixmap (pDraw);
+       ExaPixmapPriv (pixmap);
+       RegionRec migration;
+-      RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
+-      int xoff, yoff;
+-
+-      exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff);
  
-@@ -346,6 +347,9 @@ exaGlyphCacheHashRemove(ExaGlyphCachePtr cache,
-     }
- }
+-      xoff += pDraw->x;
+-      yoff += pDraw->y;
++      if (pExaPixmap->pDamage) {
++          bounds.x1 += pDraw->x;
++          bounds.y1 += pDraw->y;
++          bounds.x2 += pDraw->x;
++          bounds.y2 += pDraw->y;
  
-+#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth)
-+#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight)
-+
- static ExaGlyphCacheResult
- exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
-                        ExaGlyphCachePtr  cache,
-@@ -393,8 +397,8 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
-               int x, y;
-               int i;
-               
--              x = (pos % cache->columns) * cache->glyphWidth;
--              y = (pos / cache->columns) * cache->glyphHeight;
-+              x = CACHE_X(pos);
-+              y = CACHE_Y(pos);
+-      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);
++          REGION_INIT(pScreen, &migration, &bounds, 1);
++          exaDamageDestForMigration(pDraw, pixmap, &migration);
++      }
  
-               for (i = 0; i < buffer->count; i++) {
-                   if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) {
-@@ -420,8 +424,8 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
-                         cache->picture,
-                         0, 0,
-                         0, 0,
--                        (pos % cache->columns) * cache->glyphWidth,
--                        (pos / cache->columns) * cache->glyphHeight,
-+                        CACHE_X(pos),
-+                        CACHE_Y(pos),
-                         pGlyph->info.width,
-                         pGlyph->info.height);
-     }
-@@ -430,8 +434,8 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
-     buffer->source = cache->picture;
-           
-     rect = &buffer->rects[buffer->count];
--    rect->xSrc = (pos % cache->columns) * cache->glyphWidth;
--    rect->ySrc = (pos / cache->columns) * cache->glyphHeight;
-+    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;
-@@ -442,6 +446,9 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
-     return ExaGlyphSuccess;
- }
+       exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
  
-+#undef CACHE_X
-+#undef CACHE_Y
-+
- static ExaGlyphCacheResult
- exaBufferGlyph(ScreenPtr         pScreen,
-              ExaGlyphBufferPtr buffer,
-@@ -452,7 +459,7 @@ exaBufferGlyph(ScreenPtr         pScreen,
-     ExaScreenPriv(pScreen);
-     unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format;
-     int width = pGlyph->info.width;
--    int height = pGlyph->info.width;
-+    int height = pGlyph->info.height;
-     ExaCompositeRectPtr rect;
-     PicturePtr source;
-     int i;
-diff --git a/exa/exa_priv.h b/exa/exa_priv.h
-index 0d5d0f5..8a17f65 100644
---- a/exa/exa_priv.h
-+++ b/exa/exa_priv.h
-@@ -61,7 +61,7 @@
- #define DEBUG_MIGRATE         0
- #define DEBUG_PIXMAP          0
- #define DEBUG_OFFSCREEN               0
--#define DEBUG_GLYPH_CACHE     0
-+#define DEBUG_GLYPH_CACHE     1
+@@ -866,6 +1082,13 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+           (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0);
  
- #if DEBUG_TRACE_FALL
- #define EXA_FALLBACK(x)                                       \
-@@ -121,6 +121,7 @@ typedef struct {
-     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;
-commit cc08c06665ffe29ad44d023d75d0f86e5338875d
-Author: Owen Taylor <otaylor@huygens.home.fishsoup.net>
-Date:   Mon Apr 28 21:00:55 2008 +0200
-
-    EXA: Use UploadToScreen() for uploads to glyph cache
-    
-    When possible, use UploadToScreen() rather than CompositePicture()
-    to upload glyphs onto the glyph cache pixmap. This avoids allocating
-    offscreen memory for each glyph making management of offscreen
-    areas much more efficient.
-
-diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c
-index 27ecd4a..95ff4d8 100644
---- a/exa/exa_glyphs.c
-+++ b/exa/exa_glyphs.c
-@@ -347,6 +347,56 @@ exaGlyphCacheHashRemove(ExaGlyphCachePtr cache,
- #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.
-+ */
-+static Bool
-+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];
-+    int cacheXoff, cacheYoff;
-+
-+    if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut || pExaPixmap->accel_blocked)
-+      return FALSE;
-+
-+    /* If the glyph pixmap is already uploaded, no point in doing
-+     * things this way */
-+    if (exaPixmapIsOffscreen(pGlyphPixmap))
-+      return FALSE;
+       exaFinishAccess(pDraw, EXA_PREPARE_DEST);
 +
-+    /* 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);
-+
-+    pCachePixmap = exaGetOffscreenPixmap ((DrawablePtr)pCachePixmap, &cacheXoff, &cacheYoff);
-+    if (!pCachePixmap)
-+      return FALSE;
-+
-+    if (!pExaScr->info->UploadToScreen(pCachePixmap,
-+                                     CACHE_X(pos) + cacheXoff,
-+                                     CACHE_Y(pos) + cacheYoff,
-+                                     pGlyph->info.width,
-+                                     pGlyph->info.height,
-+                                     (char *)pExaPixmap->sys_ptr,
-+                                     pExaPixmap->sys_pitch))
-+      return FALSE;
-+
-+    return TRUE;
-+}
-+
- static ExaGlyphCacheResult
- exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
-                        ExaGlyphCachePtr  cache,
-@@ -413,18 +463,23 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
-           cache->evictionPosition = rand() % cache->size;
-       }
--      /* Now actually upload the glyph into the cache picture */
-+      /* Now actually upload the glyph into the cache picture; if
-+       * we can't do it with UploadToScreen (because the glyph is
-+       * offscreen, etc), we fall back to CompositePicture.
-+       */
-+      if (!exaGlyphCacheUploadGlyph(pScreen, cache, pos, pGlyph)) {
-+          CompositePicture (PictOpSrc,
-+                            GlyphPicture(pGlyph)[pScreen->myNum],
-+                            None,
-+                            cache->picture,
-+                            0, 0,
-+                            0, 0,
-+                            CACHE_X(pos),
-+                            CACHE_Y(pos),
-+                            pGlyph->info.width,
-+                            pGlyph->info.height);
++      /* Damage manually, because Trapezoids expects to hit Composite normally. */
++      /* Composite is wrapped by damage, but Trapezoids isn't. */
++      if (pExaPixmap->pDamage) {
++          DamageDamageRegion(pDraw, &migration);
++          REGION_UNINIT(pScreen, &migration);
 +      }
--      CompositePicture (PictOpSrc,
--                        GlyphPicture(pGlyph)[pScreen->myNum],
--                        None,
--                        cache->picture,
--                        0, 0,
--                        0, 0,
--                        CACHE_X(pos),
--                        CACHE_Y(pos),
--                        pGlyph->info.width,
--                        pGlyph->info.height);
      }
-     
-commit e7eaac59c424a205dd106fc7d70734ff4b390f28
-Author: Michel Dänzer <michel@tungstengraphics.com>
-Date:   Mon Apr 28 21:00:55 2008 +0200
-
-    EXA: Glyph cache upload tweaks.
-    
-    Track damage after using UploadToScreen directly.
-    
-    Don't waste any effort on empty glyphs.
-
-diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c
-index 95ff4d8..b618365 100644
---- a/exa/exa_glyphs.c
-+++ b/exa/exa_glyphs.c
-@@ -394,6 +394,12 @@ exaGlyphCacheUploadGlyph(ScreenPtr         pScreen,
-                                      pExaPixmap->sys_pitch))
-       return FALSE;
-+    exaPixmapDirty (pCachePixmap,
-+                  CACHE_X(pos) + cacheXoff,
-+                  CACHE_Y(pos) + cacheYoff,
-+                  CACHE_X(pos) + cacheXoff + pGlyph->info.width,
-+                  CACHE_Y(pos) + cacheYoff + pGlyph->info.height);
-+
-     return TRUE;
- }
-@@ -737,7 +743,8 @@ exaGlyphs (CARD8    op,
-           glyph = *glyphs++;
-           pPicture = GlyphPicture (glyph)[pScreen->myNum];
--          if (exaBufferGlyph(pScreen, &buffer, glyph, x, y) == ExaGlyphNeedFlush)
-+          if (glyph->info.width > 0 && glyph->info.height > 0 &&
-+              exaBufferGlyph(pScreen, &buffer, glyph, x, y) == ExaGlyphNeedFlush)
-           {
-               if (maskFormat)
-                   exaGlyphsToMask(pMask, &buffer);
-commit 8349732a6720652bfbad7874a952be73a0e8e77b
-Author: Michel Dänzer <michel@tungstengraphics.com>
-Date:   Mon Apr 28 21:09:35 2008 +0200
-
-    EXA: Try to accelerate non-antialiased text via the glyph cache as well.
-    
-    Treat 1 bit glyphs and masks as PICT_a8 in the glyph cache. We're not able to
-    accelerate them otherwise.
-
-diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c
-index 08ec097..ff665d5 100644
---- a/exa/exa_glyphs.c
-+++ b/exa/exa_glyphs.c
-@@ -374,6 +374,10 @@ exaGlyphCacheUploadGlyph(ScreenPtr         pScreen,
-     if (exaPixmapIsOffscreen(pGlyphPixmap))
-       return FALSE;
+     else if (maskFormat)
+     {
+@@ -946,26 +1169,27 @@ exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+       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;
  
-+    /* UploadToScreen only works if bpp match */
-+    if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel)
-+      return FALSE;
-+
-     /* cache pixmap must be offscreen. */
-     pixmaps[0].as_dst = TRUE;
-     pixmaps[0].as_src = FALSE;
-@@ -524,6 +528,9 @@ exaBufferGlyph(ScreenPtr         pScreen,
+-      bounds.x1 += xoff;
+-      bounds.y1 += yoff;
+-      bounds.x2 += xoff;
+-      bounds.y2 += yoff;
++      if (pExaPixmap->pDamage) {
++          bounds.x1 += pDraw->x;
++          bounds.y1 += pDraw->y;
++          bounds.x2 += pDraw->x;
++          bounds.y2 += pDraw->y;
  
-     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];
-@@ -796,6 +803,14 @@ exaGlyphs (CARD8   op,
-           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;
+-      REGION_INIT(pScreen, &migration, &bounds, 1);
+-      REGION_UNION(pScreen, pending_damage, pending_damage, &migration);
+-      REGION_UNINIT(pScreen, &migration);
++          REGION_INIT(pScreen, &migration, &bounds, 1);
++          exaDamageDestForMigration(pDraw, pixmap, &migration);
 +      }
-+
-       pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
-                                               maskFormat->depth,
-                                               CREATE_PIXMAP_USAGE_SCRATCH);
-
-commit 29586101dc11d498b212510f8dedbfeca7f8c859
-Author: Michel Dänzer <michel@tungstengraphics.com>
-Date:   Sat May 24 20:01:41 2008 +0200
-
-    EXA: Only record damage generated by rendering operations.
-    
-    Recording damage from other operations (e.g. creating a client damage record)
-    may confuse the migration code resulting in corruption.
-    
-    Option "EXAOptimizeMigration" appears safe now, so enable it by default. Also
-    remove it from the manpage, as it should only be necessary on request in the
-    course of bug report diagnostics anymore.
-
-diff --git a/exa/exa.c b/exa/exa.c
-index 809fb4b..fc04748 100644
---- a/exa/exa.c
-+++ b/exa/exa.c
-@@ -261,6 +261,21 @@ exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
-                                      pExaScr->info->pixmapPitchAlign);
- }
-+
-+static void
-+ExaDamageReport(DamagePtr pDamage, RegionPtr pReg, void *pClosure)
-+{
-+    PixmapPtr pPixmap = pClosure;
-+    ExaPixmapPriv(pPixmap);
-+    RegionPtr pDamageReg = DamageRegion(pDamage);
-+
-+    if (pExaPixmap->pendingDamage) {
-+      REGION_UNION(pScreen, pDamageReg, pDamageReg, pReg);
-+      pExaPixmap->pendingDamage = FALSE;
-+    }
-+}
-+
-+
- /**
-  * exaCreatePixmap() creates a new pixmap.
-  *
-@@ -352,7 +367,7 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth,
-     pExaPixmap->area = NULL;
-     /* Set up damage tracking */
--    pExaPixmap->pDamage = DamageCreate (NULL, NULL, DamageReportNone, TRUE,
-+    pExaPixmap->pDamage = DamageCreate (ExaDamageReport, NULL, DamageReportRawRegion, TRUE,
-                                       pScreen, pPixmap);
-     if (pExaPixmap->pDamage == NULL) {
-diff --git a/exa/exa_migration.c b/exa/exa_migration.c
-index 5f22474..3c79f68 100644
---- a/exa/exa_migration.c
-+++ b/exa/exa_migration.c
-@@ -301,6 +301,9 @@ exaDoMoveInPixmap (ExaMigrationPtr migrate)
-     ExaScreenPriv (pScreen);
-     ExaPixmapPriv (pPixmap);
  
-+    if (migrate->as_dst)
-+      pExaPixmap->pendingDamage = TRUE;
-+
-     /* If we're VT-switched away, no touching card memory allowed. */
-     if (pExaScr->swappedOut)
-       return;
-@@ -369,6 +372,9 @@ exaDoMoveOutPixmap (ExaMigrationPtr migrate)
-     PixmapPtr pPixmap = migrate->pPix;
-     ExaPixmapPriv (pPixmap);
-+    if (migrate->as_dst)
-+      pExaPixmap->pendingDamage = TRUE;
-+
-     if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
-       return;
-diff --git a/exa/exa_priv.h b/exa/exa_priv.h
-index f3b72ae..9ec2a56 100644
---- a/exa/exa_priv.h
-+++ b/exa/exa_priv.h
-@@ -226,6 +226,7 @@ typedef struct {
-      * location.
-      */
-     DamagePtr     pDamage;
-+    Bool          pendingDamage;
-     /**
-      * The valid regions mark the valid bits (at least, as they're derived from
-      * damage, which may be overreported) of a pixmap's system and FB copies.
+       exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
+       (*ps->AddTriangles) (pDst, 0, 0, ntri, tris);
+       exaFinishAccess(pDraw, EXA_PREPARE_DEST);
++
++      /* Damage manually, because Triangles expects to hit Composite normally. */
++      /* Composite is wrapped by damage, but Triangles isn't. */
++      if (pExaPixmap->pDamage) {
++          DamageDamageRegion(pDraw, &migration);
++          REGION_UNINIT(pScreen, &migration);
++      }
+     }
+     else if (maskFormat)
+     {
 diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
-index c55ef03..5a25764 100644
+index d7bd06c..d5d6a30 100644
 --- a/exa/exa_unaccel.c
 +++ b/exa/exa_unaccel.c
 @@ -97,12 +97,15 @@ ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth,
@@ -1727,11 +1993,61 @@ index c55ef03..5a25764 100644
        exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
      else
 -      ExaDoPrepareAccess (pDrawable, EXA_PREPARE_DEST);
-+      exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST,
-+                           DamagePendingRegion(pExaPixmap->pDamage));
++      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);
  }
+@@ -350,20 +353,6 @@ ExaCheckComposite (CARD8      op,
+     REGION_UNINIT(pScreen, &region);
+ }
+-void
+-ExaCheckAddTraps (PicturePtr  pPicture,
+-                INT16         x_off,
+-                INT16         y_off,
+-                int           ntrap,
+-                xTrap         *traps)
+-{
+-    EXA_FALLBACK(("to pict %p (%c)\n",
+-                exaDrawableLocation(pPicture->pDrawable)));
+-    exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
+-    fbAddTraps (pPicture, x_off, y_off, ntrap, traps);
+-    exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
+-}
+-
+ /**
+  * Gets the 0,0 pixel of a pixmap.  Used for doing solid fills of tiled pixmaps
+  * that happen to be 1x1.  Pixmap must be at least 8bpp.
+@@ -373,23 +362,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;
 diff --git a/hw/xfree86/exa/exa.man.pre b/hw/xfree86/exa/exa.man.pre
 index 14859bc..31e1cfe 100644
 --- a/hw/xfree86/exa/exa.man.pre
@@ -1750,7 +2066,7 @@ index 14859bc..31e1cfe 100644
  Chooses an alternate pixmap migration heuristic, for debugging purposes.  The
  default is intended to be the best performing one for general use, though others
 diff --git a/hw/xfree86/exa/examodule.c b/hw/xfree86/exa/examodule.c
-index e18da0a..63ea8c5 100644
+index e18da0a..4a8d8f2 100644
 --- a/hw/xfree86/exa/examodule.c
 +++ b/hw/xfree86/exa/examodule.c
 @@ -145,7 +145,7 @@ exaDDXDriverInit(ScreenPtr pScreen)
@@ -1762,46 +2078,54 @@ index e18da0a..63ea8c5 100644
      }
  
      if (xf86ReturnOptValBool(pScreenPriv->options,
-commit 13fd2256300b61d88b840952d838f834523f5dd7
-Author: Owen Taylor <otaylor@huygens.home.fishsoup.net>
-Date:   Mon Apr 28 21:00:55 2008 +0200
+@@ -179,13 +179,6 @@ exaDDXDriverInit(ScreenPtr pScreen)
+     
+ }
+-/*ARGSUSED*/
+-static const OptionInfoRec *
+-EXAAvailableOptions(void *unused)
+-{
+-    return (EXAOptions);
+-}
+-
+ static XF86ModuleVersionInfo exaVersRec =
+ {
+       "exa",
+From 5ab230373909541945d373252a3f244b68a6f7af Mon Sep 17 00:00:00 2001
+From: Fedora X Ninjas <x@fedoraproject.org>
+Date: Mon, 6 Oct 2008 11:43:05 +1000
+Subject: [PATCH] exa: fix case where glyphs get flushed on last loop of previous cycle.
 
-    EXA: Clean up debug messages
+we segfault here in exaCompositeRects as we have no source as already
+flushed just before the loop finished.
+---
+ exa/exa_glyphs.c |   12 +++++++-----
+ 1 files changed, 7 insertions(+), 5 deletions(-)
 
 diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c
-index 851e439..27ecd4a 100644
+index b23e7f6..2efc42d 100644
 --- a/exa/exa_glyphs.c
 +++ b/exa/exa_glyphs.c
-@@ -260,11 +260,9 @@ exaGlyphCacheHashLookup(ExaGlyphCachePtr cache,
-           return -1;
-       if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){
--          DBG_GLYPH_CACHE((" found entry at %d\n", slot));
-           return entryPos;
-       }
-           
--      DBG_GLYPH_CACHE((" lookup linear probe bumpalong\n"));
-       slot--;
-       if (slot < 0)
-           slot = cache->hashSize - 1;
-@@ -284,7 +282,6 @@ exaGlyphCacheHashInsert(ExaGlyphCachePtr cache,
+@@ -872,11 +872,13 @@ exaGlyphs (CARD8          op,
+       list++;
+     }
      
-     while (TRUE) { /* hash table can never be full */
-       if (cache->hashEntries[slot] == -1) {
--          DBG_GLYPH_CACHE((" inserting entry at %d\n", slot));
-           cache->hashEntries[slot] = pos;
-           return;
-       }
-diff --git a/exa/exa_priv.h b/exa/exa_priv.h
-index 8a17f65..f3b72ae 100644
---- a/exa/exa_priv.h
-+++ b/exa/exa_priv.h
-@@ -61,7 +61,7 @@
- #define DEBUG_MIGRATE         0
- #define DEBUG_PIXMAP          0
- #define DEBUG_OFFSCREEN               0
--#define DEBUG_GLYPH_CACHE     1
-+#define DEBUG_GLYPH_CACHE     0
- #if DEBUG_TRACE_FALL
- #define EXA_FALLBACK(x)                                       \
+-    if (maskFormat)
+-      exaGlyphsToMask(pMask, &buffer);
+-    else
+-      exaGlyphsToDst(op, pSrc, pDst, &buffer,
+-                     xSrc, ySrc, xDst, yDst);
++    if (buffer.count && buffer.source) {
++        if (maskFormat)
++          exaGlyphsToMask(pMask, &buffer);
++        else
++          exaGlyphsToDst(op, pSrc, pDst, &buffer,
++                         xSrc, ySrc, xDst, yDst);
++    }
+     
+     if (maskFormat)
+     {
+-- 
+1.5.5.1
+
diff --git a/xorg-xserver-server-fb-size.patch b/xorg-xserver-server-fb-size.patch
new file mode 100644 (file)
index 0000000..c6178b8
--- /dev/null
@@ -0,0 +1,32 @@
+From dc5cedd61e00afec33cbfaa7fdfbb6c357074dbd Mon Sep 17 00:00:00 2001
+From: =?utf-8?q?S=C3=B8ren=20Sandmann=20Pedersen?= <sandmann@redhat.com>
+Date: Thu, 11 Sep 2008 12:51:31 -0400
+Subject: [PATCH] Make room for an external monitor if we have enough video RAM
+
+---
+ hw/xfree86/modes/xf86Crtc.c |    9 +++++++++
+ 1 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
+index 4de7e05..9bcf81b 100644
+--- a/hw/xfree86/modes/xf86Crtc.c
++++ b/hw/xfree86/modes/xf86Crtc.c
+@@ -987,6 +987,15 @@ xf86DefaultScreenLimits (ScrnInfoPtr scrn, int *widthp, int *heightp,
+       if (crtc_height > height)
+           height = crtc_height;
+     }
++
++    /* Make room for an external monitor if we have enough video ram */
++    if (scrn->videoRam >= 65536)
++        width += 1920;
++    else if (scrn->videoRam >= 32768)
++        width += 1280;
++    else if (scrn->videoRam >= 16384)
++        width += 1024;
++
+     if (config->maxWidth && width > config->maxWidth) width = config->maxWidth;
+     if (config->maxHeight && height > config->maxHeight) height = config->maxHeight;
+     if (config->minWidth && width < config->minWidth) width = config->minWidth;
+-- 
+1.6.0.1
+
diff --git a/xorg-xserver-server-pic-libxf86config.patch b/xorg-xserver-server-pic-libxf86config.patch
new file mode 100644 (file)
index 0000000..efdd2db
--- /dev/null
@@ -0,0 +1,25 @@
+From 6344659a33a7c192dffe6e796c771d02f78da5e5 Mon Sep 17 00:00:00 2001
+From: Adam Jackson <ajax@redhat.com>
+Date: Thu, 1 Nov 2007 15:02:24 -0400
+Subject: [PATCH] Build libxf86config with -fPIC.
+
+---
+ hw/xfree86/parser/Makefile.am |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/hw/xfree86/parser/Makefile.am b/hw/xfree86/parser/Makefile.am
+index 849ee8b..0691158 100644
+--- a/hw/xfree86/parser/Makefile.am
++++ b/hw/xfree86/parser/Makefile.am
+@@ -25,7 +25,7 @@ libxf86config_a_SOURCES = \
+       DRI.c \
+       Extensions.c
+-AM_CFLAGS = $(DIX_CFLAGS) $(XORG_CFLAGS)
++AM_CFLAGS = $(DIX_CFLAGS) $(XORG_CFLAGS) -fPIC -fvisibility=hidden
+ EXTRA_DIST = \
+       Configint.h \
+-- 
+1.5.3.4
+
This page took 1.811457 seconds and 4 git commands to generate.