xserver: Branch 'master' - 5 commits

Keith Packard keithp at kemper.freedesktop.org
Thu May 14 16:41:24 PDT 2015


Rebased ref, commits from common ancestor:
commit b0d2e010316d710eb4052963de3a1e2dc7ba356e
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Oct 10 09:25:51 2014 +0200

    glamor: Replace CompositeGlyphs code [v2]
    
    New composite glyphs code uses the updated glamor program
    infrastructure to create efficient shaders for drawing render text.
    
    Glyphs are cached in two atlases (one 8-bit, one 32-bit) in a simple
    linear fashion. When the atlas fills, it is discarded and a new one
    constructed.
    
    v2: Eric Anholt changed the non-GLSL 130 path to use quads instead of
    two triangles for a significant performance improvement on hardware
    with quads. Someone can fix the GLES quads emulation if they want to
    make it faster there.
    
    v3: Eric found more dead code to delete
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Eric Anholt <eric at anholt.net>

diff --git a/glamor/Makefile.am b/glamor/Makefile.am
index db72cb1..c488029 100644
--- a/glamor/Makefile.am
+++ b/glamor/Makefile.am
@@ -14,7 +14,7 @@ libglamor_la_SOURCES = \
 	glamor_font.c \
 	glamor_font.h \
 	glamor_glx.c \
-	glamor_glyphs.c \
+	glamor_composite_glyphs.c \
 	glamor_image.c \
 	glamor_lines.c \
 	glamor_segs.c \
diff --git a/glamor/glamor.c b/glamor/glamor.c
index 9d40e3c..807f28e 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -288,16 +288,6 @@ glamor_create_screen_resources(ScreenPtr screen)
         ret = screen->CreateScreenResources(screen);
     screen->CreateScreenResources = glamor_create_screen_resources;
 
-    if (!glamor_glyphs_init(screen)) {
-        ErrorF("Failed to initialize glyphs\n");
-        ret = FALSE;
-    }
-
-    if (!glamor_realize_glyph_caches(screen)) {
-        ErrorF("Failed to initialize glyph cache\n");
-        ret = FALSE;
-    }
-
     return ret;
 }
 
@@ -509,6 +499,11 @@ glamor_init(ScreenPtr screen, unsigned int flags)
     glamor_priv->saved_procs.block_handler = screen->BlockHandler;
     screen->BlockHandler = _glamor_block_handler;
 
+    if (!glamor_composite_glyphs_init(screen)) {
+        ErrorF("Failed to initialize composite masks\n");
+        goto fail;
+    }
+
     glamor_priv->saved_procs.create_gc = screen->CreateGC;
     screen->CreateGC = glamor_create_gc;
 
@@ -550,10 +545,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
     ps->CompositeRects = miCompositeRects;
 
     glamor_priv->saved_procs.glyphs = ps->Glyphs;
-    ps->Glyphs = glamor_glyphs;
-
-    glamor_priv->saved_procs.unrealize_glyph = ps->UnrealizeGlyph;
-    ps->UnrealizeGlyph = glamor_glyph_unrealize;
+    ps->Glyphs = glamor_composite_glyphs;
 
     glamor_priv->saved_procs.create_picture = ps->CreatePicture;
     ps->CreatePicture = glamor_create_picture;
@@ -634,7 +626,7 @@ glamor_close_screen(ScreenPtr screen)
 
     glamor_priv = glamor_get_screen_private(screen);
     glamor_sync_close(screen);
-    glamor_glyphs_fini(screen);
+    glamor_composite_glyphs_fini(screen);
     screen->CloseScreen = glamor_priv->saved_procs.close_screen;
     screen->CreateScreenResources =
         glamor_priv->saved_procs.create_screen_resources;
@@ -655,7 +647,6 @@ glamor_close_screen(ScreenPtr screen)
     ps->CreatePicture = glamor_priv->saved_procs.create_picture;
     ps->CompositeRects = glamor_priv->saved_procs.composite_rects;
     ps->Glyphs = glamor_priv->saved_procs.glyphs;
-    ps->UnrealizeGlyph = glamor_priv->saved_procs.unrealize_glyph;
     screen->SetWindowPixmap = glamor_priv->saved_procs.set_window_pixmap;
 
     screen_pixmap = screen->GetScreenPixmap(screen);
diff --git a/glamor/glamor.h b/glamor/glamor.h
index d07182d..0d57fff 100644
--- a/glamor/glamor.h
+++ b/glamor/glamor.h
@@ -105,8 +105,6 @@ extern _X_EXPORT void glamor_set_screen_pixmap(PixmapPtr screen_pixmap,
 
 extern _X_EXPORT uint32_t glamor_get_pixmap_texture(PixmapPtr pixmap);
 
-extern _X_EXPORT Bool glamor_glyphs_init(ScreenPtr pScreen);
-
 extern _X_EXPORT void glamor_set_pixmap_texture(PixmapPtr pixmap,
                                                 unsigned int tex);
 
diff --git a/glamor/glamor_composite_glyphs.c b/glamor/glamor_composite_glyphs.c
new file mode 100644
index 0000000..39ed854
--- /dev/null
+++ b/glamor/glamor_composite_glyphs.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright © 2014 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+#include <stdlib.h>
+#include "Xprintf.h"
+
+#include "glamor_priv.h"
+#include "glamor_transform.h"
+#include "glamor_transfer.h"
+
+#include <mipict.h>
+
+#define DEFAULT_ATLAS_DIM       1024
+
+static DevPrivateKeyRec        glamor_glyph_private_key;
+
+struct glamor_glyph_private {
+    int16_t     x;
+    int16_t     y;
+    uint32_t    serial;
+};
+
+struct glamor_glyph_atlas {
+    PixmapPtr           atlas;
+    PictFormatPtr       format;
+    int                 x, y;
+    int                 row_height;
+    int                 nglyph;
+    uint32_t            serial;
+};
+
+static inline struct glamor_glyph_private *glamor_get_glyph_private(PixmapPtr pixmap) {
+    return dixLookupPrivate(&pixmap->devPrivates, &glamor_glyph_private_key);
+}
+
+static inline void
+glamor_copy_glyph(PixmapPtr     glyph_pixmap,
+                  DrawablePtr   atlas_draw,
+                  int16_t x,
+                  int16_t y)
+{
+    DrawablePtr glyph_draw = &glyph_pixmap->drawable;
+    BoxRec      box = {
+        .x1 = 0,
+        .y1 = 0,
+        .x2 = glyph_draw->width,
+        .y2 = glyph_draw->height,
+    };
+
+    if (glyph_pixmap->drawable.bitsPerPixel == atlas_draw->bitsPerPixel) {
+        glamor_upload_boxes((PixmapPtr) atlas_draw,
+                            &box, 1,
+                            0, 0,
+                            x, y,
+                            glyph_pixmap->devPrivate.ptr,
+                            glyph_pixmap->devKind);
+    } else {
+        GCPtr scratch_gc = GetScratchGC(atlas_draw->depth, atlas_draw->pScreen);
+        ChangeGCVal changes[2];
+        if (!scratch_gc)
+            return;
+
+        /* If we're dealing with 1-bit glyphs, we upload them to
+         * the cache as normal 8-bit alpha, since that's what GL
+         * can handle.
+         */
+        assert(glyph_draw->depth == 1);
+        assert(atlas_draw->depth == 8);
+
+        changes[0].val = 0xff;
+        changes[1].val = 0x00;
+        if (ChangeGC(NullClient, scratch_gc,
+                     GCForeground|GCBackground, changes) != Success)
+            goto bail_gc;
+        ValidateGC(atlas_draw, scratch_gc);
+
+        (*scratch_gc->ops->CopyPlane)(glyph_draw,
+                                      atlas_draw,
+                                      scratch_gc,
+                                      0, 0,
+                                      glyph_draw->width,
+                                      glyph_draw->height,
+                                      x, y, 0x1);
+
+    bail_gc:
+        FreeScratchGC(scratch_gc);
+    }
+}
+
+static Bool
+glamor_glyph_atlas_init(ScreenPtr screen, struct glamor_glyph_atlas *atlas)
+{
+    glamor_screen_private       *glamor_priv = glamor_get_screen_private(screen);
+    PictFormatPtr               format = atlas->format;
+
+    atlas->atlas = glamor_create_pixmap(screen, glamor_priv->glyph_atlas_dim,
+                                        glamor_priv->glyph_atlas_dim, format->depth, 0);
+    atlas->x = 0;
+    atlas->y = 0;
+    atlas->row_height = 0;
+    atlas->serial++;
+    atlas->nglyph = 0;
+    return TRUE;
+}
+
+static Bool
+glamor_glyph_can_add(struct glamor_glyph_atlas *atlas, int dim, DrawablePtr glyph_draw)
+{
+    /* Step down */
+    if (atlas->x + glyph_draw->width > dim) {
+        atlas->x = 0;
+        atlas->y += atlas->row_height;
+        atlas->row_height = 0;
+    }
+
+    /* Check for overfull */
+    if (atlas->y + glyph_draw->height > dim)
+        return FALSE;
+
+    return TRUE;
+}
+
+static Bool
+glamor_glyph_add(struct glamor_glyph_atlas *atlas, DrawablePtr glyph_draw)
+{
+    PixmapPtr                   glyph_pixmap = (PixmapPtr) glyph_draw;
+    struct glamor_glyph_private *glyph_priv = glamor_get_glyph_private(glyph_pixmap);
+
+    glamor_copy_glyph(glyph_pixmap, &atlas->atlas->drawable, atlas->x, atlas->y);
+
+    glyph_priv->x = atlas->x;
+    glyph_priv->y = atlas->y;
+    glyph_priv->serial = atlas->serial;
+
+    atlas->x += glyph_draw->width;
+    if (atlas->row_height < glyph_draw->height)
+        atlas->row_height = glyph_draw->height;
+
+    atlas->nglyph++;
+
+    return TRUE;
+}
+
+static const glamor_facet glamor_facet_composite_glyphs_130 = {
+    .name = "composite_glyphs",
+    .version = 130,
+    .vs_vars = ("attribute vec4 primitive;\n"
+                "attribute vec2 source;\n"
+                "varying vec2 glyph_pos;\n"),
+    .vs_exec = ("       vec2 pos = primitive.zw * vec2(gl_VertexID&1, (gl_VertexID&2)>>1);\n"
+                GLAMOR_POS(gl_Position, (primitive.xy + pos))
+                "       glyph_pos = (source + pos) * ATLAS_DIM_INV;\n"),
+    .fs_vars = ("varying vec2 glyph_pos;\n"),
+    .fs_exec = ("       vec4 mask = texture2D(atlas, glyph_pos);\n"),
+    .source_name = "source",
+    .locations = glamor_program_location_atlas,
+};
+
+static const glamor_facet glamor_facet_composite_glyphs_120 = {
+    .name = "composite_glyphs",
+    .vs_vars = ("attribute vec2 primitive;\n"
+                "attribute vec2 source;\n"
+                "varying vec2 glyph_pos;\n"),
+    .vs_exec = (GLAMOR_POS(gl_Position, primitive)
+                "       glyph_pos = source.xy * ATLAS_DIM_INV;\n"),
+    .fs_vars = ("varying vec2 glyph_pos;\n"),
+    .fs_exec = ("       vec4 mask = texture2D(atlas, glyph_pos);\n"),
+    .source_name = "source",
+    .locations = glamor_program_location_atlas,
+};
+
+static inline Bool
+glamor_glyph_use_130(glamor_screen_private *glamor_priv) {
+    return glamor_priv->glsl_version >= 130;
+}
+
+static Bool
+glamor_glyphs_init_facet(ScreenPtr screen)
+{
+    glamor_screen_private       *glamor_priv = glamor_get_screen_private(screen);
+
+    return asprintf(&glamor_priv->glyph_defines, "#define ATLAS_DIM_INV %20.18f\n", 1.0/glamor_priv->glyph_atlas_dim) > 0;
+}
+
+static void
+glamor_glyphs_fini_facet(ScreenPtr screen)
+{
+    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+
+    free(glamor_priv->glyph_defines);
+}
+
+static void
+glamor_glyphs_flush(CARD8 op, PicturePtr src, PicturePtr dst,
+                   glamor_program *prog,
+                   struct glamor_glyph_atlas *atlas, int nglyph)
+{
+    DrawablePtr drawable = dst->pDrawable;
+    glamor_screen_private *glamor_priv = glamor_get_screen_private(drawable->pScreen);
+    PixmapPtr atlas_pixmap = atlas->atlas;
+    glamor_pixmap_private *atlas_priv = glamor_get_pixmap_private(atlas_pixmap);
+    glamor_pixmap_fbo *atlas_fbo = glamor_pixmap_fbo_at(atlas_priv, 0, 0);
+    PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
+    glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
+    int box_x, box_y;
+    int off_x, off_y;
+
+    glamor_put_vbo_space(drawable->pScreen);
+
+    glEnable(GL_SCISSOR_TEST);
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_2D, atlas_fbo->tex);
+
+    for (;;) {
+        if (!glamor_use_program_render(prog, op, src, dst))
+            break;
+
+        glUniform1i(prog->atlas_uniform, 1);
+
+        glamor_pixmap_loop(pixmap_priv, box_x, box_y) {
+            BoxPtr box = RegionRects(dst->pCompositeClip);
+            int nbox = RegionNumRects(dst->pCompositeClip);
+
+            glamor_set_destination_drawable(drawable, box_x, box_y, TRUE, FALSE, prog->matrix_uniform, &off_x, &off_y);
+
+            /* Run over the clip list, drawing the glyphs
+             * in each box
+             */
+
+            while (nbox--) {
+                glScissor(box->x1 + off_x,
+                          box->y1 + off_y,
+                          box->x2 - box->x1,
+                          box->y2 - box->y1);
+                box++;
+
+                if (glamor_glyph_use_130(glamor_priv))
+                    glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nglyph);
+                else
+                    glamor_glDrawArrays_GL_QUADS(glamor_priv, nglyph * 4);
+            }
+        }
+        if (prog->alpha != glamor_program_alpha_ca_first)
+            break;
+        prog++;
+    }
+
+    glDisable(GL_SCISSOR_TEST);
+
+    glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0);
+    glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+    glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);
+    glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+    glDisable(GL_BLEND);
+}
+
+static GLshort *
+glamor_glyph_start(ScreenPtr screen, int count)
+{
+    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+    GLshort *v;
+    char *vbo_offset;
+
+    /* Set up the vertex buffers for the font and destination */
+
+    if (glamor_glyph_use_130(glamor_priv)) {
+        v = glamor_get_vbo_space(screen, count * (6 * sizeof (GLshort)), &vbo_offset);
+
+        glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+        glVertexAttribDivisor(GLAMOR_VERTEX_POS, 1);
+        glVertexAttribPointer(GLAMOR_VERTEX_POS, 4, GL_SHORT, GL_FALSE,
+                              6 * sizeof (GLshort), vbo_offset);
+
+        glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+        glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 1);
+        glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_SHORT, GL_FALSE,
+                              6 * sizeof (GLshort), vbo_offset + 4 * sizeof (GLshort));
+    } else {
+        v = glamor_get_vbo_space(screen, count * (16 * sizeof (GLshort)), &vbo_offset);
+
+        glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+        glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
+                              4 * sizeof (GLshort), vbo_offset);
+
+        glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+        glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_SHORT, GL_FALSE,
+                              4 * sizeof (GLshort), vbo_offset + 2 * sizeof (GLshort));
+    }
+    return v;
+}
+
+static inline struct glamor_glyph_atlas *
+glamor_atlas_for_glyph(glamor_screen_private *glamor_priv, DrawablePtr drawable)
+{
+    if (drawable->depth == 32)
+        return glamor_priv->glyph_atlas_argb;
+    else
+        return glamor_priv->glyph_atlas_a;
+}
+
+void
+glamor_composite_glyphs(CARD8 op,
+                        PicturePtr src,
+                        PicturePtr dst,
+                        PictFormatPtr glyph_format,
+                        INT16 x_src,
+                        INT16 y_src, int nlist, GlyphListPtr list,
+                        GlyphPtr *glyphs)
+{
+    int glyphs_queued;
+    GLshort *v = NULL;
+    DrawablePtr drawable = dst->pDrawable;
+    ScreenPtr screen = drawable->pScreen;
+    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+    glamor_program *prog = NULL;
+    PicturePtr glyph_pict = NULL;
+    DrawablePtr glyph_draw;
+    glamor_program_render       *glyphs_program = &glamor_priv->glyphs_program;
+    struct glamor_glyph_atlas    *glyph_atlas = NULL;
+    int x = 0, y = 0;
+    int n;
+    int glyph_atlas_dim = glamor_priv->glyph_atlas_dim;
+    int glyph_max_dim = glamor_priv->glyph_max_dim;
+    int nglyph = 0;
+    int screen_num = screen->myNum;
+
+    for (n = 0; n < nlist; n++)
+        nglyph += list[n].len;
+
+    glamor_make_current(glamor_priv);
+
+    glyphs_queued = 0;
+
+    while (nlist--) {
+        x += list->xOff;
+        y += list->yOff;
+        n = list->len;
+        list++;
+        while (n--) {
+            GlyphPtr glyph = *glyphs++;
+
+            /* Glyph not empty?
+             */
+            if (glyph->info.width && glyph->info.height) {
+                glamor_pixmap_private *glyph_pix_priv;
+
+                glyph_pict = GlyphPicture(glyph)[screen_num];
+                glyph_draw = glyph_pict->pDrawable;
+                glyph_pix_priv = glamor_get_pixmap_private((PixmapPtr) glyph_draw);
+
+                /* Need to draw with slow path?
+                 */
+                if (_X_UNLIKELY(glyph_draw->width > glyph_max_dim ||
+                                glyph_draw->height > glyph_max_dim ||
+                                (glyph_pix_priv != 0 && glyph_pix_priv->type != GLAMOR_MEMORY)))
+                {
+                    if (glyphs_queued) {
+                        glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued);
+                        glyphs_queued = 0;
+                    }
+                bail_one:
+                    glamor_composite(op, src, glyph_pict, dst,
+                                     x_src + (x - glyph->info.x), (y - glyph->info.y),
+                                     0, 0,
+                                     x - glyph->info.x, y - glyph->info.y,
+                                     glyph_draw->width, glyph_draw->height);
+                } else {
+                    struct glamor_glyph_private *glyph_priv = glamor_get_glyph_private((PixmapPtr)(glyph_draw));
+                    struct glamor_glyph_atlas *next_atlas = glamor_atlas_for_glyph(glamor_priv, glyph_draw);
+
+                    /* Switching source glyph format?
+                     */
+                    if (_X_UNLIKELY(next_atlas != glyph_atlas)) {
+                        if (glyphs_queued) {
+                            glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued);
+                            glyphs_queued = 0;
+                        }
+                        glyph_atlas = next_atlas;
+                    }
+
+                    /* Glyph not cached in current atlas?
+                     */
+                    if (_X_UNLIKELY(glyph_priv->serial != glyph_atlas->serial)) {
+                        if (!glamor_glyph_can_add(glyph_atlas, glyph_atlas_dim, glyph_draw)) {
+                            if (glyphs_queued) {
+                                glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued);
+                                glyphs_queued = 0;
+                            }
+                            if (glyph_atlas->atlas) {
+                                (*screen->DestroyPixmap)(glyph_atlas->atlas);
+                                glyph_atlas->atlas = NULL;
+                            }
+                        }
+                        if (!glyph_atlas->atlas)
+                            glamor_glyph_atlas_init(screen, glyph_atlas);
+                        glamor_glyph_add(glyph_atlas, glyph_draw);
+                    }
+
+                    /* First glyph in the current atlas?
+                     */
+                    if (_X_UNLIKELY(glyphs_queued == 0)) {
+                        if (glamor_glyph_use_130(glamor_priv))
+                            prog = glamor_setup_program_render(op, src, glyph_pict, dst,
+                                                               glyphs_program,
+                                                               &glamor_facet_composite_glyphs_130,
+                                                               glamor_priv->glyph_defines);
+                        else
+                            prog = glamor_setup_program_render(op, src, glyph_pict, dst,
+                                                               glyphs_program,
+                                                               &glamor_facet_composite_glyphs_120,
+                                                               glamor_priv->glyph_defines);
+                        if (!prog)
+                            goto bail_one;
+                        v = glamor_glyph_start(screen, nglyph);
+                    }
+
+                    /* Add the glyph
+                     */
+
+                    glyphs_queued++;
+                    if (_X_LIKELY(glamor_glyph_use_130(glamor_priv))) {
+                        v[0] = x - glyph->info.x;
+                        v[1] = y - glyph->info.y;
+                        v[2] = glyph_draw->width;
+                        v[3] = glyph_draw->height;
+                        v[4] = glyph_priv->x;
+                        v[5] = glyph_priv->y;
+                        v += 6;
+                    } else {
+                        v[0] = x - glyph->info.x;
+                        v[1] = y - glyph->info.y;
+                        v[2] = glyph_priv->x;
+                        v[3] = glyph_priv->y;
+                        v += 4;
+
+                        v[0] = x - glyph->info.x + glyph_draw->width;
+                        v[1] = y - glyph->info.y;
+                        v[2] = glyph_priv->x + glyph_draw->width;
+                        v[3] = glyph_priv->y;
+                        v += 4;
+
+                        v[0] = x - glyph->info.x + glyph_draw->width;
+                        v[1] = y - glyph->info.y + glyph_draw->height;
+                        v[2] = glyph_priv->x + glyph_draw->width;
+                        v[3] = glyph_priv->y + glyph_draw->height;
+                        v += 4;
+
+                        v[0] = x - glyph->info.x;
+                        v[1] = y - glyph->info.y + glyph_draw->height;
+                        v[2] = glyph_priv->x;
+                        v[3] = glyph_priv->y + glyph_draw->height;
+                        v += 4;
+                    }
+                }
+            }
+            x += glyph->info.xOff;
+            y += glyph->info.yOff;
+            nglyph--;
+        }
+    }
+
+    if (glyphs_queued)
+        glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued);
+
+    return;
+}
+
+static struct glamor_glyph_atlas *
+glamor_alloc_glyph_atlas(ScreenPtr screen, int depth, CARD32 f)
+{
+    PictFormatPtr               format;
+    struct glamor_glyph_atlas    *glyph_atlas;
+
+    format = PictureMatchFormat(screen, depth, f);
+    if (!format)
+        return NULL;
+    glyph_atlas = calloc (1, sizeof (struct glamor_glyph_atlas));
+    if (!glyph_atlas)
+        return NULL;
+    glyph_atlas->format = format;
+    glyph_atlas->serial = 1;
+
+    return glyph_atlas;
+}
+
+Bool
+glamor_composite_glyphs_init(ScreenPtr screen)
+{
+    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+
+    if (!dixRegisterPrivateKey(&glamor_glyph_private_key, PRIVATE_PIXMAP, sizeof (struct glamor_glyph_private)))
+        return FALSE;
+
+    /* Make glyph atlases of a reasonable size, but no larger than the maximum
+     * supported by the hardware
+     */
+    glamor_priv->glyph_atlas_dim = MIN(DEFAULT_ATLAS_DIM, glamor_priv->max_fbo_size);
+
+    /* Don't stick huge glyphs in the atlases */
+    glamor_priv->glyph_max_dim = glamor_priv->glyph_atlas_dim / 8;
+
+    glamor_priv->glyph_atlas_a = glamor_alloc_glyph_atlas(screen, 8, PICT_a8);
+    if (!glamor_priv->glyph_atlas_a)
+        return FALSE;
+    glamor_priv->glyph_atlas_argb = glamor_alloc_glyph_atlas(screen, 32, PICT_a8r8g8b8);
+    if (!glamor_priv->glyph_atlas_argb) {
+        free (glamor_priv->glyph_atlas_a);
+        return FALSE;
+    }
+    if (!glamor_glyphs_init_facet(screen))
+        return FALSE;
+    return TRUE;
+}
+
+static void
+glamor_free_glyph_atlas(struct glamor_glyph_atlas *atlas)
+{
+    if (!atlas)
+        return;
+    if (atlas->atlas)
+        FreePicture(atlas->atlas, 0);
+    free (atlas);
+}
+
+void
+glamor_composite_glyphs_fini(ScreenPtr screen)
+{
+    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+
+    glamor_glyphs_fini_facet(screen);
+    glamor_free_glyph_atlas(glamor_priv->glyph_atlas_a);
+    glamor_free_glyph_atlas(glamor_priv->glyph_atlas_argb);
+}
diff --git a/glamor/glamor_glyphs.c b/glamor/glamor_glyphs.c
deleted file mode 100644
index 4f3f969..0000000
--- a/glamor/glamor_glyphs.c
+++ /dev/null
@@ -1,1769 +0,0 @@
-/*
- * Copyright © 2008 Red Hat, Inc.
- * Partly based on code Copyright © 2000 SuSE, Inc.
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Red Hat not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  Red Hat makes no representations about the
- * suitability of this software for any purpose.  It is provided "as is"
- * without express or implied warranty.
- *
- * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
- * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of SuSE not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  SuSE makes no representations about the
- * suitability of this software for any purpose.  It is provided "as is"
- * without express or implied warranty.
- *
- * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
- * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Owen Taylor <otaylor at fishsoup.net>
- * Based on code by: Keith Packard
- */
-
-#include <stdlib.h>
-
-#include "glamor_priv.h"
-
-#include <mipict.h>
-
-#if DEBUG_GLYPH_CACHE
-#define DBG_GLYPH_CACHE(a) ErrorF a
-#else
-#define DBG_GLYPH_CACHE(a)
-#endif
-
-/* Width of the pixmaps we use for the caches; this should be less than
- * max texture size of the driver; this may need to actually come from
- * the driver.
- */
-
-/* Maximum number of glyphs we buffer on the stack before flushing
- * rendering to the mask or destination surface.
- */
-#define GLYPH_BUFFER_SIZE 1024
-
-typedef struct {
-    PicturePtr source;
-    glamor_composite_rect_t rects[GLYPH_BUFFER_SIZE + 4];
-    int count;
-} glamor_glyph_buffer_t;
-
-struct glamor_glyph {
-    glamor_glyph_cache_t *cache;
-    uint16_t x, y;
-    uint16_t size, pos;
-    unsigned long long left_x1_map, left_x2_map;
-    unsigned long long right_x1_map, right_x2_map;      /* Use to check real intersect or not. */
-    Bool has_edge_map;
-    Bool cached;
-};
-
-typedef enum {
-    GLAMOR_GLYPH_SUCCESS,       /* Glyph added to render buffer */
-    GLAMOR_GLYPH_FAIL,          /* out of memory, etc */
-    GLAMOR_GLYPH_NEED_FLUSH,    /* would evict a glyph already in the buffer */
-} glamor_glyph_cache_result_t;
-
-#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
-static DevPrivateKeyRec glamor_glyph_key;
-
-static inline struct glamor_glyph *
-glamor_glyph_get_private(ScreenPtr screen, GlyphPtr glyph)
-{
-    struct glamor_glyph *privates = (struct glamor_glyph*)glyph->devPrivates;
-
-    return &privates[screen->myNum];
-}
-
-/*
- * Mask cache is located at the corresponding cache picture's last row.
- * and is deadicated for the mask picture when do the glyphs_via_mask.
- *
- * As we split the glyphs list according to its overlapped or non-overlapped,
- * we can reduce the length of glyphs to do the glyphs_via_mask to 2 or 3
- * glyphs one time for most cases. Thus it give us a case to allocate a
- * small portion of the corresponding cache directly as the mask picture.
- * Then we can rendering the glyphs to this mask picture, and latter we
- * can accumulate the second steps, composite the mask to the dest with
- * the other non-overlapped glyphs's rendering process.
- * Another major benefit is we now only need to clear a relatively small mask
- * region then before. It also make us implement a bunch mask picture clearing
- * algorithm to avoid too frequently small region clearing.
- *
- * If there is no any overlapping, this method will not get performance gain.
- * If there is some overlapping, then this algorithm can get about 15% performance
- * gain.
- */
-
-static void
-clear_mask_cache_bitmap(glamor_glyph_mask_cache_t *maskcache,
-                        unsigned int clear_mask_bits)
-{
-    unsigned int i = 0;
-    BoxRec box[MASK_CACHE_WIDTH];
-    int box_cnt = 0;
-
-    assert((clear_mask_bits & ~MASK_CACHE_MASK) == 0);
-    for (i = 0; i < MASK_CACHE_WIDTH; i++) {
-        if (clear_mask_bits & (1 << i)) {
-            box[box_cnt].x1 = maskcache->mcache[i].x;
-            box[box_cnt].x2 = maskcache->mcache[i].x + MASK_CACHE_MAX_SIZE;
-            box[box_cnt].y1 = maskcache->mcache[i].y;
-            box[box_cnt].y2 = maskcache->mcache[i].y + MASK_CACHE_MAX_SIZE;
-            box_cnt++;
-        }
-    }
-    glamor_solid_boxes(maskcache->pixmap, box, box_cnt, 0);
-    maskcache->cleared_bitmap |= clear_mask_bits;
-}
-
-static void
-clear_mask_cache(glamor_glyph_mask_cache_t *maskcache)
-{
-    int x = 0;
-    int cnt = MASK_CACHE_WIDTH;
-    unsigned int i = 0;
-    struct glamor_glyph_mask_cache_entry *mce;
-
-    glamor_solid(maskcache->pixmap, 0, CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE,
-                 MASK_CACHE_MAX_SIZE, 0);
-    mce = &maskcache->mcache[0];
-    while (cnt--) {
-        mce->width = 0;
-        mce->height = 0;
-        mce->x = x;
-        mce->y = CACHE_PICTURE_SIZE;
-        mce->idx = i++;
-        x += MASK_CACHE_MAX_SIZE;
-        mce++;
-    }
-    maskcache->free_bitmap = MASK_CACHE_MASK;
-    maskcache->cleared_bitmap = MASK_CACHE_MASK;
-}
-
-static int
-find_continuous_bits(unsigned int bits, int bits_cnt, unsigned int *pbits_mask)
-{
-    int idx = 0;
-    unsigned int bits_mask;
-
-    bits_mask = ((1LL << bits_cnt) - 1);
-
-    if (_X_UNLIKELY(bits_cnt > 56)) {
-        while (bits) {
-            if ((bits & bits_mask) == bits_mask) {
-                *pbits_mask = bits_mask << idx;
-                return idx;
-            }
-            bits >>= 1;
-            idx++;
-        }
-    }
-    else {
-        idx = __fls(bits);
-        while (bits) {
-            unsigned int temp_bits;
-
-            temp_bits = bits_mask << (idx - bits_cnt + 1);
-            if ((bits & temp_bits) == temp_bits) {
-                *pbits_mask = temp_bits;
-                return (idx - bits_cnt + 1);
-            }
-            /* Find first zero. And clear the tested bit. */
-            bits &= ~(1LL << idx);
-            idx = __fls(~bits);
-            bits &= ~((1LL << idx) - 1);
-            idx--;
-        }
-    }
-    return -1;
-}
-
-static struct glamor_glyph_mask_cache_entry *
-get_mask_cache(glamor_glyph_mask_cache_t *maskcache, int blocks)
-{
-    int free_cleared_bit, idx = -1;
-    int retry_cnt = 0;
-    unsigned int bits_mask = 0;
-
-    if (maskcache->free_bitmap == 0)
-        return NULL;
- retry:
-    free_cleared_bit = maskcache->free_bitmap & maskcache->cleared_bitmap;
-    if (free_cleared_bit && blocks == 1) {
-        idx = __fls(free_cleared_bit);
-        bits_mask = 1 << idx;
-    }
-    else if (free_cleared_bit && blocks > 1) {
-        idx = find_continuous_bits(free_cleared_bit, blocks, &bits_mask);
-    }
-
-    if (idx < 0) {
-        clear_mask_cache_bitmap(maskcache, maskcache->free_bitmap);
-        if (retry_cnt++ > 2)
-            return NULL;
-        goto retry;
-    }
-
-    maskcache->cleared_bitmap &= ~bits_mask;
-    maskcache->free_bitmap &= ~bits_mask;
-    DEBUGF("get idx %d free %x clear %x \n",
-           idx, maskcache->free_bitmap, maskcache->cleared_bitmap);
-    return &maskcache->mcache[idx];
-}
-
-static void
-put_mask_cache_bitmap(glamor_glyph_mask_cache_t *maskcache,
-                      unsigned int bitmap)
-{
-    maskcache->free_bitmap |= bitmap;
-    DEBUGF("put bitmap %x free %x clear %x \n",
-           bitmap, maskcache->free_bitmap, maskcache->cleared_bitmap);
-}
-
-static void
-glamor_unrealize_glyph_caches(ScreenPtr pScreen)
-{
-    glamor_screen_private *glamor = glamor_get_screen_private(pScreen);
-    int i;
-
-    if (!glamor->glyph_caches_realized)
-        return;
-
-    for (i = 0; i < GLAMOR_NUM_GLYPH_CACHE_FORMATS; i++) {
-        glamor_glyph_cache_t *cache = &glamor->glyphCaches[i];
-
-        if (cache->picture)
-            FreePicture(cache->picture, 0);
-
-        if (cache->glyphs)
-            free(cache->glyphs);
-
-        if (glamor->mask_cache[i])
-            free(glamor->mask_cache[i]);
-    }
-    glamor->glyph_caches_realized = FALSE;
-}
-
-void
-glamor_glyphs_fini(ScreenPtr pScreen)
-{
-    glamor_unrealize_glyph_caches(pScreen);
-}
-
-/* All caches for a single format share a single pixmap for glyph storage,
- * allowing mixing glyphs of different sizes without paying a penalty
- * for switching between source pixmaps. (Note that for a size of font
- * right at the border between two sizes, we might be switching for almost
- * every glyph.)
- *
- * This function allocates the storage pixmap, and then fills in the
- * rest of the allocated structures for all caches with the given format.
- */
-
-Bool
-glamor_realize_glyph_caches(ScreenPtr pScreen)
-{
-    glamor_screen_private *glamor = glamor_get_screen_private(pScreen);
-
-    unsigned int formats[] = {
-        PIXMAN_a8,
-        PIXMAN_a8r8g8b8,
-    };
-    int i;
-
-    if (glamor->glyph_caches_realized)
-        return TRUE;
-
-    memset(glamor->glyphCaches, 0, sizeof(glamor->glyphCaches));
-
-    for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) {
-        glamor_glyph_cache_t *cache = &glamor->glyphCaches[i];
-        PixmapPtr pixmap;
-        PicturePtr picture;
-        XID component_alpha;
-        int depth = PIXMAN_FORMAT_DEPTH(formats[i]);
-        int error;
-        PictFormatPtr pPictFormat =
-            PictureMatchFormat(pScreen, depth, formats[i]);
-        if (!pPictFormat)
-            goto bail;
-
-        /* Now allocate the pixmap and picture */
-        pixmap = pScreen->CreatePixmap(pScreen,
-                                       CACHE_PICTURE_SIZE,
-                                       CACHE_PICTURE_SIZE + MASK_CACHE_MAX_SIZE,
-                                       depth, GLAMOR_CREATE_NO_LARGE);
-        if (!pixmap)
-            goto bail;
-
-        component_alpha = NeedsComponent(pPictFormat->format);
-        picture = CreatePicture(0, &pixmap->drawable, pPictFormat,
-                                CPComponentAlpha, &component_alpha,
-                                serverClient, &error);
-
-        pScreen->DestroyPixmap(pixmap);
-        if (!picture)
-            goto bail;
-
-        ValidatePicture(picture);
-
-        cache->picture = picture;
-        cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE);
-        if (!cache->glyphs)
-            goto bail;
-
-        cache->evict = rand() % GLYPH_CACHE_SIZE;
-        glamor->mask_cache[i] = calloc(1, sizeof(*glamor->mask_cache[i]));
-        glamor->mask_cache[i]->pixmap = pixmap;
-        clear_mask_cache(glamor->mask_cache[i]);
-    }
-    assert(i == GLAMOR_NUM_GLYPH_CACHE_FORMATS);
-
-    glamor->glyph_caches_realized = TRUE;
-    return TRUE;
-
- bail:
-    glamor_unrealize_glyph_caches(pScreen);
-    return FALSE;
-}
-
-/**
- * Called by glamor_create_screen_resources() to set up the glyph cache.
- *
- * This was previously required to be called by the drivers, but not
- * as of the xserver 1.16 ABI.
- */
-Bool
-glamor_glyphs_init(ScreenPtr pScreen)
-{
-    if (!dixRegisterPrivateKey(&glamor_glyph_key,
-                               PRIVATE_GLYPH,
-                               screenInfo.numScreens * sizeof(struct glamor_glyph)))
-        return FALSE;
-
-    return TRUE;
-}
-
-/* The most efficient thing to way to upload the glyph to the screen
- * is to use CopyArea; glamor pixmaps are always offscreen.
- */
-static void
-glamor_glyph_cache_upload_glyph(ScreenPtr screen,
-                                glamor_glyph_cache_t *cache,
-                                GlyphPtr glyph, int x, int y)
-{
-    PicturePtr pGlyphPicture = GlyphPicture(glyph)[screen->myNum];
-    PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
-    PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
-    PixmapPtr scratch;
-    BoxRec box;
-    GCPtr gc;
-
-    gc = GetScratchGC(pCachePixmap->drawable.depth, screen);
-    if (!gc)
-        return;
-
-    ValidateGC(&pCachePixmap->drawable, gc);
-
-    scratch = pGlyphPixmap;
-    if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) {
-
-        scratch = glamor_create_pixmap(screen,
-                                       glyph->info.width,
-                                       glyph->info.height,
-                                       pCachePixmap->drawable.depth, 0);
-        if (scratch) {
-            PicturePtr picture;
-            int error;
-
-            picture =
-                CreatePicture(0,
-                              &scratch->drawable,
-                              PictureMatchFormat
-                              (screen,
-                               pCachePixmap->drawable.depth,
-                               cache->picture->format),
-                              0, NULL, serverClient, &error);
-            if (picture) {
-                ValidatePicture(picture);
-                glamor_composite(PictOpSrc,
-                                 pGlyphPicture,
-                                 NULL, picture,
-                                 0, 0, 0, 0, 0,
-                                 0, glyph->info.width, glyph->info.height);
-                FreePicture(picture, 0);
-            }
-        }
-        else {
-            scratch = pGlyphPixmap;
-        }
-    }
-
-    box.x1 = x;
-    box.y1 = y;
-    box.x2 = x + glyph->info.width;
-    box.y2 = y + glyph->info.height;
-    glamor_copy(&scratch->drawable,
-                &pCachePixmap->drawable, NULL,
-                &box, 1, -x, -y, FALSE, FALSE, 0, NULL);
-    if (scratch != pGlyphPixmap)
-        screen->DestroyPixmap(scratch);
-
-    FreeScratchGC(gc);
-}
-
-void
-glamor_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph)
-{
-    struct glamor_glyph *priv;
-
-    /* Use Lookup in case we have not attached to this glyph. */
-    priv = glamor_glyph_get_private(screen, glyph);
-
-    if (priv->cached)
-        priv->cache->glyphs[priv->pos] = NULL;
-}
-
-/* Cut and paste from render/glyph.c - probably should export it instead */
-static void
-glamor_glyph_extents(int nlist,
-                     GlyphListPtr list, GlyphPtr *glyphs, BoxPtr extents)
-{
-    int x1, x2, y1, y2;
-    int x, y, n;
-
-    x1 = y1 = MAXSHORT;
-    x2 = y2 = MINSHORT;
-    x = y = 0;
-    while (nlist--) {
-        x += list->xOff;
-        y += list->yOff;
-        n = list->len;
-        list++;
-        while (n--) {
-            GlyphPtr glyph = *glyphs++;
-            int v;
-
-            v = x - glyph->info.x;
-            if (v < x1)
-                x1 = v;
-            v += glyph->info.width;
-            if (v > x2)
-                x2 = v;
-
-            v = y - glyph->info.y;
-            if (v < y1)
-                y1 = v;
-            v += glyph->info.height;
-            if (v > y2)
-                y2 = v;
-
-            x += glyph->info.xOff;
-            y += glyph->info.yOff;
-        }
-    }
-
-    extents->x1 = x1 < MINSHORT ? MINSHORT : x1;
-    extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2;
-    extents->y1 = y1 < MINSHORT ? MINSHORT : y1;
-    extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2;
-}
-
-static void
-glamor_glyph_priv_get_edge_map(GlyphPtr glyph, struct glamor_glyph *priv,
-                               PicturePtr glyph_picture)
-{
-    PixmapPtr glyph_pixmap = (PixmapPtr) glyph_picture->pDrawable;
-    int j;
-    unsigned long long left_x1_map = 0, left_x2_map = 0;
-    unsigned long long right_x1_map = 0, right_x2_map = 0;
-    int bitsPerPixel;
-    int stride;
-    void *bits;
-    int width;
-    unsigned int left_x1_data = 0, left_x2_data = 0;
-    unsigned int right_x1_data = 0, right_x2_data = 0;
-
-    bitsPerPixel = glyph_pixmap->drawable.bitsPerPixel;
-    stride = glyph_pixmap->devKind;
-    bits = glyph_pixmap->devPrivate.ptr;
-    width = glyph->info.width;
-
-    if (glyph_pixmap->drawable.width < 2
-        || !(glyph_pixmap->drawable.depth == 8
-             || glyph_pixmap->drawable.depth == 1
-             || glyph_pixmap->drawable.depth == 32)) {
-        priv->has_edge_map = FALSE;
-        return;
-    }
-
-    left_x1_map = left_x2_map = 0;
-    right_x1_map = right_x2_map = 0;
-
-    for (j = 0; j < glyph_pixmap->drawable.height; j++) {
-        if (bitsPerPixel == 8) {
-            unsigned char *data;
-
-            data = (unsigned char *) ((unsigned char *) bits + stride * j);
-            left_x1_data = *data++;
-            left_x2_data = *data;
-            data =
-                (unsigned char *) ((unsigned char *) bits + stride * j + width -
-                                   2);
-            right_x1_data = *data++;
-            right_x2_data = *data;
-        }
-        else if (bitsPerPixel == 32) {
-            left_x1_data = *((unsigned int *) bits + stride / 4 * j);
-            left_x2_data = *((unsigned int *) bits + stride / 4 * j + 1);
-            right_x1_data =
-                *((unsigned int *) bits + stride / 4 * j + width - 2);
-            right_x2_data =
-                *((unsigned int *) bits + stride / 4 * j + width - 1);
-        }
-        else if (bitsPerPixel == 1) {
-            unsigned char temp;
-
-            temp = *((unsigned char *) glyph_pixmap->devPrivate.ptr
-                     + glyph_pixmap->devKind * j) & 0x3;
-            left_x1_data = temp & 0x1;
-            left_x2_data = temp & 0x2;
-
-            temp = *((unsigned char *) glyph_pixmap->devPrivate.ptr
-                     + glyph_pixmap->devKind * j
-                     + (glyph_pixmap->drawable.width - 2) / 8);
-            right_x1_data = temp
-                & (1 << ((glyph_pixmap->drawable.width - 2) % 8));
-            temp = *((unsigned char *) glyph_pixmap->devPrivate.ptr
-                     + glyph_pixmap->devKind * j
-                     + (glyph_pixmap->drawable.width - 1) / 8);
-            right_x2_data = temp
-                & (1 << ((glyph_pixmap->drawable.width - 1) % 8));
-        }
-        left_x1_map |= (left_x1_data != 0) << j;
-        left_x2_map |= (left_x2_data != 0) << j;
-        right_x1_map |= (right_x1_data != 0) << j;
-        right_x2_map |= (right_x2_data != 0) << j;
-    }
-
-    priv->left_x1_map = left_x1_map;
-    priv->left_x2_map = left_x2_map;
-    priv->right_x1_map = right_x1_map;
-    priv->right_x2_map = right_x2_map;
-    priv->has_edge_map = TRUE;
-    return;
-}
-
-/**
- * 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.
- */
-
-#define INTERSECTED_TYPE_MASK 1
-#define NON_INTERSECTED 0
-#define INTERSECTED 1
-
-struct glamor_glyph_list {
-    int nlist;
-    GlyphListPtr list;
-    GlyphPtr *glyphs;
-    int type;
-};
-
-static Bool
-glyph_new_fixed_list(struct glamor_glyph_list *fixed_list,
-                     GlyphPtr *cur_glyphs,
-                     GlyphPtr ** head_glyphs,
-                     GlyphListPtr cur_list,
-                     int cur_pos, int cur_x, int cur_y,
-                     int x1, int y1, int x2, int y2,
-                     GlyphListPtr *head_list,
-                     int *head_pos,
-                     int *head_x,
-                     int *head_y, int *fixed_cnt, int type, BoxPtr prev_extents)
-{
-    int x_off = 0;
-    int y_off = 0;
-    int n_off = 0;
-    int list_cnt;
-
-    if (type == NON_INTERSECTED) {
-        if (x1 < prev_extents->x2 && x2 > prev_extents->x1
-            && y1 < prev_extents->y2 && y2 > prev_extents->y1)
-            return FALSE;
-        x_off = (*(cur_glyphs - 1))->info.xOff;
-        y_off = (*(cur_glyphs - 1))->info.yOff;
-        n_off = 1;
-    }
-
-    list_cnt = cur_list - *head_list + 1;
-    if (cur_pos <= n_off) {
-        DEBUGF("break at %d n_off %d\n", cur_pos, n_off);
-        list_cnt--;
-        if (cur_pos < n_off) {
-            /* we overlap with previous list's last glyph. */
-            x_off += cur_list->xOff;
-            y_off += cur_list->yOff;
-            cur_list--;
-            cur_pos = cur_list->len;
-            if (cur_pos <= n_off) {
-                list_cnt--;
-            }
-        }
-    }
-    DEBUGF("got %d lists\n", list_cnt);
-    if (list_cnt != 0) {
-        fixed_list->list = xallocarray(list_cnt, sizeof(*cur_list));
-        memcpy(fixed_list->list, *head_list, list_cnt * sizeof(*cur_list));
-        fixed_list->list[0].xOff = *head_x;
-        fixed_list->list[0].yOff = *head_y;
-        fixed_list->glyphs = *head_glyphs;
-        fixed_list->type = type & INTERSECTED_TYPE_MASK;
-        fixed_list->nlist = list_cnt;
-        if (cur_list != *head_list) {
-            fixed_list->list[0].len = (*head_list)->len - *head_pos;
-            if (cur_pos != n_off)
-                fixed_list->list[list_cnt - 1].len = cur_pos - n_off;
-        }
-        else
-            fixed_list->list[0].len = cur_pos - *head_pos - n_off;
-        (*fixed_cnt)++;
-    }
-
-    if (type <= INTERSECTED) {
-        *head_list = cur_list;
-        *head_pos = cur_pos - n_off;
-        *head_x = cur_x - x_off;
-        *head_y = cur_y - y_off;
-        *head_glyphs = cur_glyphs - n_off;
-    }
-    return TRUE;
-}
-
-/*
- * This function detects glyph lists's overlapping.
- *
- * If check_fake_overlap is set, then it will check the glyph's left
- * and right small boxes's real overlapping pixels. And if there is
- * no real pixel overlapping, then it will not be treated as overlapped
- * case. And we also can configured it to ignore less than 2 pixels
- * overlappig.
- *
- * This function analyzes all the lists and split the list to multiple
- * lists which are pure overlapped glyph lists or pure non-overlapped
- * list if the overlapping only ocurr on the two adjacent glyphs.
- * Otherwise, it return -1.
- *
- **/
-
-static int
-glamor_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs,
-                        PictFormatShort mask_format,
-                        ScreenPtr screen, Bool check_fake_overlap,
-                        struct glamor_glyph_list *fixed_list, int fixed_size)
-{
-    int x1, x2, y1, y2;
-    int n;
-    int x, y;
-    BoxPtr extents;
-    BoxRec prev_extents;
-    Bool first = TRUE, first_list = TRUE;
-    Bool need_free_list_region = FALSE;
-    Bool need_free_fixed_list = FALSE;
-    struct glamor_glyph *priv = NULL;
-    Bool in_non_intersected_list = -1;
-    GlyphListPtr head_list;
-    int head_x, head_y, head_pos;
-    int fixed_cnt = 0;
-    GlyphPtr *head_glyphs;
-    GlyphListPtr cur_list = list;
-    RegionRec list_region;
-    RegionRec current_region;
-    BoxRec current_box;
-
-    if (nlist > 1) {
-        pixman_region_init(&list_region);
-        need_free_list_region = TRUE;
-    }
-
-    pixman_region_init(&current_region);
-
-    extents = pixman_region_extents(&current_region);
-
-    x = 0;
-    y = 0;
-    x1 = x2 = y1 = y2 = 0;
-    n = 0;
-    extents->x1 = 0;
-    extents->y1 = 0;
-    extents->x2 = 0;
-    extents->y2 = 0;
-
-    head_list = list;
-    DEBUGF("has %d lists.\n", nlist);
-    while (nlist--) {
-        BoxRec left_box, right_box = { 0 };
-        Bool has_left_edge_box = FALSE, has_right_edge_box = FALSE;
-        Bool left_to_right;
-        struct glamor_glyph *left_priv = NULL, *right_priv = NULL;
-
-        x += list->xOff;
-        y += list->yOff;
-        n = list->len;
-        left_to_right = TRUE;
-        cur_list = list++;
-
-        if (_X_UNLIKELY(!first_list)) {
-            pixman_region_init_with_extents(&current_region, extents);
-            pixman_region_union(&list_region, &list_region, &current_region);
-            first = TRUE;
-        }
-        else {
-            head_list = cur_list;
-            head_pos = cur_list->len - n;
-            head_x = x;
-            head_y = y;
-            head_glyphs = glyphs;
-        }
-
-        DEBUGF("current list %p has %d glyphs\n", cur_list, n);
-        while (n--) {
-            GlyphPtr glyph = *glyphs++;
-
-            DEBUGF("the %dth glyph\n", cur_list->len - n - 1);
-            if (glyph->info.width == 0 || glyph->info.height == 0) {
-                x += glyph->info.xOff;
-                y += glyph->info.yOff;
-                continue;
-            }
-            if (mask_format
-                && mask_format != GlyphPicture(glyph)[screen->myNum]->format) {
-                need_free_fixed_list = TRUE;
-                goto done;
-            }
-
-            x1 = x - glyph->info.x;
-            if (x1 < MINSHORT)
-                x1 = MINSHORT;
-            y1 = y - glyph->info.y;
-            if (y1 < MINSHORT)
-                y1 = MINSHORT;
-            if (check_fake_overlap)
-                priv = glamor_glyph_get_private(screen, glyph);
-
-            x2 = x1 + glyph->info.width;
-            y2 = y1 + glyph->info.height;
-
-            if (x2 > MAXSHORT)
-                x2 = MAXSHORT;
-            if (y2 > MAXSHORT)
-                y2 = MAXSHORT;
-
-            if (first) {
-                extents->x1 = x1;
-                extents->y1 = y1;
-                extents->x2 = x2;
-                extents->y2 = y2;
-
-                prev_extents = *extents;
-
-                first = FALSE;
-                if (check_fake_overlap && priv
-                    && priv->has_edge_map && glyph->info.yOff == 0) {
-                    left_box.x1 = x1;
-                    left_box.x2 = x1 + 1;
-                    left_box.y1 = y1;
-
-                    right_box.x1 = x2 - 2;
-                    right_box.x2 = x2 - 1;
-                    right_box.y1 = y1;
-                    left_priv = right_priv = priv;
-                    has_left_edge_box = TRUE;
-                    has_right_edge_box = TRUE;
-                }
-            }
-            else {
-                if (_X_UNLIKELY(!first_list)) {
-                    current_box.x1 = x1;
-                    current_box.y1 = y1;
-                    current_box.x2 = x2;
-                    current_box.y2 = y2;
-                    if (pixman_region_contains_rectangle
-                        (&list_region, &current_box) != PIXMAN_REGION_OUT) {
-                        need_free_fixed_list = TRUE;
-                        goto done;
-                    }
-                }
-
-                if (x1 < extents->x2 && x2 > extents->x1
-                    && y1 < extents->y2 && y2 > extents->y1) {
-
-                    if (check_fake_overlap &&
-                        (has_left_edge_box || has_right_edge_box)
-                        && priv->has_edge_map && glyph->info.yOff == 0) {
-                        int left_dx, right_dx;
-                        unsigned long long intersected;
-
-                        left_dx = has_left_edge_box ? 1 : 0;
-                        right_dx = has_right_edge_box ? 1 : 0;
-                        if (x1 + 1 < extents->x2 - right_dx &&
-                            x2 - 1 > extents->x1 + left_dx)
-                            goto real_intersected;
-
-                        if (left_to_right && has_right_edge_box) {
-                            if (x1 == right_box.x1) {
-                                intersected =
-                                    ((priv->left_x1_map & right_priv->
-                                      right_x1_map)
-                                     | (priv->left_x2_map & right_priv->
-                                        right_x2_map));
-                                if (intersected)
-                                    goto real_intersected;
-                            }
-                            else if (x1 == right_box.x2) {
-                                intersected =
-                                    (priv->left_x1_map & right_priv->
-                                     right_x2_map);
-                                if (intersected) {
-#ifdef  GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK
-                                    /* tolerate with two pixels overlap. */
-                                    intersected &= ~(1 << __fls(intersected));
-                                    if ((intersected & (intersected - 1)))
-#endif
-                                        goto real_intersected;
-                                }
-                            }
-                        }
-                        else if (!left_to_right && has_left_edge_box) {
-                            if (x2 - 1 == left_box.x1) {
-                                intersected =
-                                    (priv->right_x2_map & left_priv->
-                                     left_x1_map);
-                                if (intersected) {
-#ifdef  GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK
-                                    /* tolerate with two pixels overlap. */
-                                    intersected &= ~(1 << __fls(intersected));
-                                    if ((intersected & (intersected - 1)))
-#endif
-                                        goto real_intersected;
-                                }
-                            }
-                            else if (x2 - 1 == right_box.x2) {
-                                if ((priv->right_x1_map & left_priv->
-                                     left_x1_map)
-                                    || (priv->right_x2_map & left_priv->
-                                        left_x2_map))
-                                    goto real_intersected;
-                            }
-                        }
-                        else {
-                            if (x1 < extents->x2 && x1 + 2 > extents->x1)
-                                goto real_intersected;
-                        }
-                        goto non_intersected;
-                    }
-                    else {
- real_intersected:
-                        DEBUGF("overlap with previous glyph.\n");
-                        if (in_non_intersected_list == 1) {
-                            if (fixed_cnt >= fixed_size) {
-                                need_free_fixed_list = TRUE;
-                                goto done;
-                            }
-                            if (!glyph_new_fixed_list(&fixed_list[fixed_cnt],
-                                                      glyphs - 1,
-                                                      &head_glyphs,
-                                                      cur_list,
-                                                      cur_list->len - (n + 1),
-                                                      x, y, x1, y1, x2, y2,
-                                                      &head_list, &head_pos,
-                                                      &head_x, &head_y,
-                                                      &fixed_cnt,
-                                                      NON_INTERSECTED,
-                                                      &prev_extents)) {
-                                need_free_fixed_list = TRUE;
-                                goto done;
-                            }
-                        }
-
-                        in_non_intersected_list = 0;
-
-                    }
-                }
-                else {
- non_intersected:
-                    DEBUGF("doesn't overlap with previous glyph.\n");
-                    if (in_non_intersected_list == 0) {
-                        if (fixed_cnt >= fixed_size) {
-                            need_free_fixed_list = TRUE;
-                            goto done;
-                        }
-                        if (!glyph_new_fixed_list(&fixed_list[fixed_cnt],
-                                                  glyphs - 1,
-                                                  &head_glyphs,
-                                                  cur_list,
-                                                  cur_list->len - (n + 1), x, y,
-                                                  x1, y1, x2, y2,
-                                                  &head_list,
-                                                  &head_pos,
-                                                  &head_x,
-                                                  &head_y, &fixed_cnt,
-                                                  INTERSECTED, &prev_extents)) {
-                            need_free_fixed_list = TRUE;
-                            goto done;
-                        }
-                    }
-                    in_non_intersected_list = 1;
-                }
-                prev_extents = *extents;
-            }
-
-            if (check_fake_overlap && priv
-                && priv->has_edge_map && glyph->info.yOff == 0) {
-                if (!has_left_edge_box || x1 < extents->x1) {
-                    left_box.x1 = x1;
-                    left_box.x2 = x1 + 1;
-                    left_box.y1 = y1;
-                    has_left_edge_box = TRUE;
-                    left_priv = priv;
-                }
-
-                if (!has_right_edge_box || x2 > extents->x2) {
-                    right_box.x1 = x2 - 2;
-                    right_box.x2 = x2 - 1;
-                    right_box.y1 = y1;
-                    has_right_edge_box = TRUE;
-                    right_priv = priv;
-                }
-            }
-
-            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;
-        }
-        first_list = FALSE;
-    }
-
-    if (in_non_intersected_list == 0 && fixed_cnt == 0) {
-        fixed_cnt = -1;
-        goto done;
-    }
-
-    if ((in_non_intersected_list != -1 || head_pos != n) && (fixed_cnt > 0)) {
-        if (fixed_cnt >= fixed_size) {
-            need_free_fixed_list = TRUE;
-            goto done;
-        }
-        if (!glyph_new_fixed_list(&fixed_list[fixed_cnt],
-                                  glyphs - 1,
-                                  &head_glyphs,
-                                  cur_list,
-                                  cur_list->len - (n + 1), x, y,
-                                  x1, y1, x2, y2,
-                                  &head_list,
-                                  &head_pos,
-                                  &head_x,
-                                  &head_y, &fixed_cnt,
-                                  (!in_non_intersected_list) | 0x80,
-                                  &prev_extents)) {
-            need_free_fixed_list = TRUE;
-            goto done;
-        }
-    }
-
- done:
-    if (need_free_list_region)
-        pixman_region_fini(&list_region);
-    pixman_region_fini(&current_region);
-
-    if (need_free_fixed_list && fixed_cnt >= 0) {
-        while (fixed_cnt--) {
-            free(fixed_list[fixed_cnt].list);
-        }
-    }
-
-    DEBUGF("Got %d fixed list \n", fixed_cnt);
-    return fixed_cnt;
-}
-
-static inline unsigned int
-glamor_glyph_size_to_count(int size)
-{
-    size /= GLYPH_MIN_SIZE;
-    return size * size;
-}
-
-static inline unsigned int
-glamor_glyph_count_to_mask(int count)
-{
-    return ~(count - 1);
-}
-
-static inline unsigned int
-glamor_glyph_size_to_mask(int size)
-{
-    return glamor_glyph_count_to_mask(glamor_glyph_size_to_count(size));
-}
-
-static PicturePtr
-glamor_glyph_cache(glamor_screen_private *glamor, GlyphPtr glyph, int *out_x,
-                   int *out_y)
-{
-    ScreenPtr screen = glamor->screen;
-    PicturePtr glyph_picture = GlyphPicture(glyph)[screen->myNum];
-    glamor_glyph_cache_t *cache =
-        &glamor->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) != 0];
-    struct glamor_glyph *priv = NULL, *evicted_priv = NULL;
-    int size, mask, pos, s;
-
-    if (glyph->info.width > GLYPH_MAX_SIZE
-        || glyph->info.height > GLYPH_MAX_SIZE)
-        return NULL;
-
-    for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2)
-        if (glyph->info.width <= size && glyph->info.height <= size)
-            break;
-
-    s = glamor_glyph_size_to_count(size);
-    mask = glamor_glyph_count_to_mask(s);
-    pos = (cache->count + s - 1) & mask;
-
-    priv = glamor_glyph_get_private(screen, glyph);
-    if (pos < GLYPH_CACHE_SIZE) {
-        cache->count = pos + s;
-    }
-    else {
-        for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) {
-            int i = cache->evict & glamor_glyph_size_to_mask(s);
-            GlyphPtr evicted = cache->glyphs[i];
-
-            if (evicted == NULL)
-                continue;
-
-            evicted_priv = glamor_glyph_get_private(screen, evicted);
-            assert(evicted_priv->pos == i);
-            if (evicted_priv->size >= s) {
-                cache->glyphs[i] = NULL;
-                evicted_priv->cached = FALSE;
-                pos = cache->evict & glamor_glyph_size_to_mask(size);
-            }
-            else
-                evicted_priv = NULL;
-            break;
-        }
-        if (evicted_priv == NULL) {
-            int count = glamor_glyph_size_to_count(size);
-
-            mask = glamor_glyph_count_to_mask(count);
-            pos = cache->evict & mask;
-            for (s = 0; s < count; s++) {
-                GlyphPtr evicted = cache->glyphs[pos + s];
-
-                if (evicted != NULL) {
-
-                    evicted_priv = glamor_glyph_get_private(screen, evicted);
-
-                    assert(evicted_priv->pos == pos + s);
-                    evicted_priv->cached = FALSE;
-                    cache->glyphs[pos + s] = NULL;
-                }
-            }
-
-        }
-        /* And pick a new eviction position */
-        cache->evict = rand() % GLYPH_CACHE_SIZE;
-    }
-
-    cache->glyphs[pos] = glyph;
-
-    priv->cache = cache;
-    priv->size = size;
-    priv->pos = pos;
-    s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) *
-               (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE));
-    priv->x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE;
-    priv->y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE;
-    for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) {
-        if (pos & 1)
-            priv->x += s;
-        if (pos & 2)
-            priv->y += s;
-        pos >>= 2;
-    }
-
-    glamor_glyph_cache_upload_glyph(screen, cache, glyph, priv->x, priv->y);
-#ifndef GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK
-    if (priv->has_edge_map == FALSE && glyph->info.width >= 2)
-        glamor_glyph_priv_get_edge_map(glyph, priv, glyph_picture);
-#endif
-    priv->cached = TRUE;
-
-    *out_x = priv->x;
-    *out_y = priv->y;
-    return cache->picture;
-}
-
-typedef void (*glyphs_flush_func) (void *arg);
-struct glyphs_flush_dst_arg {
-    CARD8 op;
-    PicturePtr src;
-    PicturePtr dst;
-    glamor_glyph_buffer_t *buffer;
-    int x_src, y_src;
-    int x_dst, y_dst;
-};
-
-static struct glyphs_flush_dst_arg dst_arg;
-static struct glyphs_flush_mask_arg mask_arg;
-static glamor_glyph_buffer_t dst_buffer;
-static glamor_glyph_buffer_t mask_buffer;
-unsigned long long mask_glyphs_cnt = 0;
-unsigned long long dst_glyphs_cnt = 0;
-
-#define GLYPHS_DST_MODE_VIA_MASK		0
-#define GLYPHS_DST_MODE_VIA_MASK_CACHE		1
-#define GLYPHS_DST_MODE_TO_DST			2
-#define GLYPHS_DST_MODE_MASK_TO_DST		3
-
-struct glyphs_flush_mask_arg {
-    PicturePtr mask;
-    glamor_glyph_buffer_t *buffer;
-    glamor_glyph_mask_cache_t *maskcache;
-    unsigned int used_bitmap;
-};
-
-static void
-glamor_glyphs_flush_mask(struct glyphs_flush_mask_arg *arg)
-{
-    if (arg->buffer->count > 0) {
-        glamor_composite_glyph_rects(PictOpAdd, arg->buffer->source,
-                                     NULL, arg->mask,
-                                     arg->buffer->count, arg->buffer->rects);
-    }
-    arg->buffer->count = 0;
-    arg->buffer->source = NULL;
-
-}
-
-static void
-glamor_glyphs_flush_dst(struct glyphs_flush_dst_arg *arg)
-{
-    if (!arg->buffer)
-        return;
-
-    if (mask_buffer.count > 0) {
-        glamor_glyphs_flush_mask(&mask_arg);
-    }
-    if (mask_arg.used_bitmap) {
-        put_mask_cache_bitmap(mask_arg.maskcache, mask_arg.used_bitmap);
-        mask_arg.used_bitmap = 0;
-    }
-
-    if (arg->buffer->count > 0) {
-        glamor_composite_glyph_rects(arg->op, arg->src,
-                                     arg->buffer->source, arg->dst,
-                                     arg->buffer->count,
-                                     &arg->buffer->rects[0]);
-        arg->buffer->count = 0;
-        arg->buffer->source = NULL;
-    }
-}
-
-static glamor_glyph_cache_result_t
-glamor_buffer_glyph(glamor_screen_private *glamor_priv,
-                    glamor_glyph_buffer_t *buffer,
-                    PictFormatShort format,
-                    GlyphPtr glyph, struct glamor_glyph *priv,
-                    int x_glyph, int y_glyph,
-                    int dx, int dy, int w, int h,
-                    int glyphs_dst_mode,
-                    glyphs_flush_func glyphs_flush, void *flush_arg)
-{
-    ScreenPtr screen = glamor_priv->screen;
-    glamor_composite_rect_t *rect;
-    PicturePtr source;
-    int x, y;
-    glamor_glyph_cache_t *cache;
-
-    if (glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST)
-        priv = glamor_glyph_get_private(screen, glyph);
-
-    if (PICT_FORMAT_BPP(format) == 1)
-        format = PICT_a8;
-
-    cache = &glamor_priv->glyphCaches[PICT_FORMAT_RGB(format) != 0];
-
-    if (buffer->source && buffer->source != cache->picture && glyphs_flush) {
-        (*glyphs_flush) (flush_arg);
-        glyphs_flush = NULL;
-    }
-
-    if (buffer->count == GLYPH_BUFFER_SIZE && glyphs_flush) {
-        (*glyphs_flush) (flush_arg);
-        glyphs_flush = NULL;
-    }
-
-    if (priv && priv->cached) {
-        rect = &buffer->rects[buffer->count++];
-        rect->x_src = priv->x + dx;
-        rect->y_src = priv->y + dy;
-        if (buffer->source == NULL)
-            buffer->source = priv->cache->picture;
-        if (glyphs_dst_mode <= GLYPHS_DST_MODE_VIA_MASK_CACHE)
-            assert(priv->cache->glyphs[priv->pos] == glyph);
-    }
-    else {
-        assert(glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST);
-        if (glyphs_flush)
-            (*glyphs_flush) (flush_arg);
-        source = glamor_glyph_cache(glamor_priv, glyph, &x, &y);
-
-        if (source != NULL) {
-            rect = &buffer->rects[buffer->count++];
-            rect->x_src = x + dx;
-            rect->y_src = y + dy;
-            if (buffer->source == NULL)
-                buffer->source = source;
-            if (glyphs_dst_mode == GLYPHS_DST_MODE_VIA_MASK_CACHE) {
-                /* mode 1 means we are using global mask cache,
-                 * thus we have to composite from the cache picture
-                 * to the cache picture, we need a flush here to make
-                 * sure latter we get the corret glyphs data.*/
-                glamor_make_current(glamor_priv);
-                glFlush();
-            }
-        }
-        else {
-            /* Couldn't find the glyph in the cache, use the glyph picture directly */
-            source = GlyphPicture(glyph)[screen->myNum];
-            if (buffer->source && buffer->source != source && glyphs_flush)
-                (*glyphs_flush) (flush_arg);
-            buffer->source = source;
-
-            rect = &buffer->rects[buffer->count++];
-            rect->x_src = 0 + dx;
-            rect->y_src = 0 + dy;
-        }
-        priv = glamor_glyph_get_private(screen, glyph);
-    }
-
-    rect->x_dst = x_glyph;
-    rect->y_dst = y_glyph;
-    if (glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST) {
-        rect->x_dst -= glyph->info.x;
-        rect->y_dst -= glyph->info.y;
-    }
-    rect->width = w;
-    rect->height = h;
-    if (glyphs_dst_mode > GLYPHS_DST_MODE_VIA_MASK_CACHE) {
-        rect->x_mask = rect->x_src;
-        rect->y_mask = rect->y_src;
-        rect->x_src = dst_arg.x_src + rect->x_dst - dst_arg.x_dst;
-        rect->y_src = dst_arg.y_src + rect->y_dst - dst_arg.y_dst;
-    }
-
-    return GLAMOR_GLYPH_SUCCESS;
-}
-
-static void
-glamor_buffer_glyph_clip(glamor_screen_private *glamor_priv,
-                         BoxPtr rects,
-                         int nrect, PictFormatShort format,
-                         GlyphPtr glyph, struct glamor_glyph *priv,
-                         int glyph_x, int glyph_y,
-                         int glyph_dx, int glyph_dy,
-                         int width, int height,
-                         int glyphs_mode,
-                         glyphs_flush_func flush_func, void *arg)
-{
-    int i;
-
-    for (i = 0; i < nrect; i++) {
-        int dst_x, dst_y;
-        int dx, dy;
-        int x2, y2;
-
-        dst_x = glyph_x - glyph_dx;
-        dst_y = glyph_y - glyph_dy;
-        x2 = dst_x + width;
-        y2 = dst_y + height;
-        dx = dy = 0;
-        if (rects[i].y1 >= y2)
-            break;
-
-        if (dst_x < rects[i].x1)
-            dx = rects[i].x1 - dst_x, dst_x = rects[i].x1;
-        if (x2 > rects[i].x2)
-            x2 = rects[i].x2;
-        if (dst_y < rects[i].y1)
-            dy = rects[i].y1 - dst_y, dst_y = rects[i].y1;
-        if (y2 > rects[i].y2)
-            y2 = rects[i].y2;
-        if (dst_x < x2 && dst_y < y2) {
-
-            glamor_buffer_glyph(glamor_priv,
-                                &dst_buffer,
-                                format,
-                                glyph, priv,
-                                dst_x + glyph_dx,
-                                dst_y + glyph_dy,
-                                dx, dy,
-                                x2 - dst_x, y2 - dst_y,
-                                glyphs_mode, flush_func, arg);
-        }
-    }
-}
-
-static void
-glamor_glyphs_via_mask(CARD8 op,
-                       PicturePtr src,
-                       PicturePtr dst,
-                       PictFormatPtr mask_format,
-                       INT16 x_src,
-                       INT16 y_src,
-                       int nlist, GlyphListPtr list, GlyphPtr *glyphs,
-                       Bool use_mask_cache)
-{
-    PixmapPtr mask_pixmap = 0;
-    PicturePtr mask;
-    ScreenPtr screen = dst->pDrawable->pScreen;
-    int width = 0, height = 0;
-    int x, y;
-    int x_dst = list->xOff, y_dst = list->yOff;
-    int n;
-    GlyphPtr glyph;
-    int error;
-    BoxRec extents = { 0, 0, 0, 0 };
-    XID component_alpha;
-    glamor_screen_private *glamor_priv;
-    int need_free_mask = FALSE;
-    glamor_glyph_buffer_t buffer;
-    struct glyphs_flush_mask_arg arg;
-    glamor_glyph_buffer_t *pmask_buffer;
-    struct glyphs_flush_mask_arg *pmask_arg;
-    struct glamor_glyph_mask_cache_entry *mce = NULL;
-    glamor_glyph_mask_cache_t *maskcache;
-    glamor_glyph_cache_t *cache;
-    int glyphs_dst_mode;
-
-    glamor_glyph_extents(nlist, list, glyphs, &extents);
-
-    if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
-        return;
-    glamor_priv = glamor_get_screen_private(screen);
-    width = extents.x2 - extents.x1;
-    height = extents.y2 - extents.y1;
-
-    if (mask_format->depth == 1) {
-        PictFormatPtr a8Format = PictureMatchFormat(screen, 8, PICT_a8);
-
-        if (a8Format)
-            mask_format = a8Format;
-    }
-
-    cache = &glamor_priv->glyphCaches
-        [PICT_FORMAT_RGB(mask_format->format) != 0];
-    maskcache = glamor_priv->mask_cache[PICT_FORMAT_RGB(mask_format->format) != 0];
-
-    x = -extents.x1;
-    y = -extents.y1;
-    if (!use_mask_cache || width > (CACHE_PICTURE_SIZE / 4)
-        || height > MASK_CACHE_MAX_SIZE) {
- new_mask_pixmap:
-        mask_pixmap = glamor_create_pixmap(screen, width, height,
-                                           mask_format->depth,
-                                           CREATE_PIXMAP_USAGE_SCRATCH);
-        if (!mask_pixmap) {
-            glamor_destroy_pixmap(mask_pixmap);
-            return;
-        }
-        glamor_solid(mask_pixmap, 0, 0, width, height, 0);
-        component_alpha = NeedsComponent(mask_format->format);
-        mask = CreatePicture(0, &mask_pixmap->drawable,
-                             mask_format, CPComponentAlpha,
-                             &component_alpha, serverClient, &error);
-        if (!mask)
-            return;
-        need_free_mask = TRUE;
-        pmask_arg = &arg;
-        pmask_buffer = &buffer;
-        pmask_buffer->count = 0;
-        pmask_buffer->source = NULL;
-        pmask_arg->used_bitmap = 0;
-        glyphs_dst_mode = GLYPHS_DST_MODE_VIA_MASK;
-    }
-    else {
-        int retry_cnt = 0;
-
- retry:
-        mce = get_mask_cache(maskcache,
-                             (width + MASK_CACHE_MAX_SIZE -
-                              1) / MASK_CACHE_MAX_SIZE);
-
-        if (mce == NULL) {
-            glamor_glyphs_flush_dst(&dst_arg);
-            retry_cnt++;
-            if (retry_cnt > 2) {
-                assert(0);
-                goto new_mask_pixmap;
-            }
-            goto retry;
-        }
-
-        mask = cache->picture;
-        x += mce->x;
-        y += mce->y;
-        mce->width = (width + MASK_CACHE_MAX_SIZE - 1) / MASK_CACHE_MAX_SIZE;
-        mce->height = 1;
-        if (mask_arg.mask && mask_arg.mask != mask && mask_buffer.count != 0)
-            glamor_glyphs_flush_dst(&dst_arg);
-        pmask_arg = &mask_arg;
-        pmask_buffer = &mask_buffer;
-        pmask_arg->maskcache = maskcache;
-        glyphs_dst_mode = GLYPHS_DST_MODE_VIA_MASK_CACHE;
-    }
-    pmask_arg->mask = mask;
-    pmask_arg->buffer = pmask_buffer;
-    while (nlist--) {
-        x += list->xOff;
-        y += list->yOff;
-        n = list->len;
-        mask_glyphs_cnt += n;
-        while (n--) {
-            glyph = *glyphs++;
-            if (glyph->info.width > 0 && glyph->info.height > 0) {
-                glyphs_flush_func flush_func;
-                void *temp_arg;
-
-                if (need_free_mask) {
-                    if (pmask_buffer->count)
-                        flush_func =
-                            (glyphs_flush_func) glamor_glyphs_flush_mask;
-                    else
-                        flush_func = NULL;
-                    temp_arg = pmask_arg;
-                }
-                else {
-                    /* If we are using global mask cache, then we need to
-                     * flush dst instead of mask. As some dst depends on the
-                     * previous mask result. Just flush mask can't get all previous's
-                     * overlapped glyphs.*/
-                    if (dst_buffer.count || mask_buffer.count)
-                        flush_func =
-                            (glyphs_flush_func) glamor_glyphs_flush_dst;
-                    else
-                        flush_func = NULL;
-                    temp_arg = &dst_arg;
-                }
-                glamor_buffer_glyph(glamor_priv, pmask_buffer,
-                                    mask_format->format,
-                                    glyph, NULL, x, y,
-                                    0, 0,
-                                    glyph->info.width, glyph->info.height,
-                                    glyphs_dst_mode,
-                                    flush_func, (void *) temp_arg);
-            }
-            x += glyph->info.xOff;
-            y += glyph->info.yOff;
-        }
-        list++;
-    }
-
-    x = extents.x1;
-    y = extents.y1;
-    if (need_free_mask) {
-        glamor_glyphs_flush_mask(pmask_arg);
-        CompositePicture(op,
-                         src,
-                         mask,
-                         dst,
-                         x_src + x - x_dst,
-                         y_src + y - y_dst, 0, 0, x, y, width, height);
-        FreePicture(mask, 0);
-        glamor_destroy_pixmap(mask_pixmap);
-    }
-    else {
-        struct glamor_glyph priv;
-        glyphs_flush_func flush_func;
-        BoxPtr rects;
-        int nrect;
-
-        priv.cache = cache;
-        priv.x = mce->x;
-        priv.y = mce->y;
-        priv.cached = TRUE;
-        rects = REGION_RECTS(dst->pCompositeClip);
-        nrect = REGION_NUM_RECTS(dst->pCompositeClip);
-
-        pmask_arg->used_bitmap |= ((1 << mce->width) - 1) << mce->idx;
-        dst_arg.op = op;
-        dst_arg.src = src;
-        dst_arg.dst = dst;
-        dst_arg.buffer = &dst_buffer;
-        dst_arg.x_src = x_src;
-        dst_arg.y_src = y_src;
-        dst_arg.x_dst = x_dst;
-        dst_arg.y_dst = y_dst;
-
-        if (dst_buffer.source == NULL) {
-            dst_buffer.source = cache->picture;
-        }
-        else if (dst_buffer.source != cache->picture) {
-            glamor_glyphs_flush_dst(&dst_arg);
-            dst_buffer.source = cache->picture;
-        }
-
-        x += dst->pDrawable->x;
-        y += dst->pDrawable->y;
-
-        if (dst_buffer.count || mask_buffer.count)
-            flush_func = (glyphs_flush_func) glamor_glyphs_flush_dst;
-        else
-            flush_func = NULL;
-
-        glamor_buffer_glyph_clip(glamor_priv,
-                                 rects, nrect,
-                                 mask_format->format,
-                                 NULL, &priv,
-                                 x, y,
-                                 0, 0,
-                                 width, height,
-                                 GLYPHS_DST_MODE_MASK_TO_DST,
-                                 flush_func, (void *) &dst_arg);
-    }
-}
-
-static void
-glamor_glyphs_to_dst(CARD8 op,
-                     PicturePtr src,
-                     PicturePtr dst,
-                     INT16 x_src,
-                     INT16 y_src,
-                     int nlist, GlyphListPtr list, GlyphPtr *glyphs)
-{
-    ScreenPtr screen = dst->pDrawable->pScreen;
-    int x = 0, y = 0;
-    int x_dst = list->xOff, y_dst = list->yOff;
-    int n;
-    GlyphPtr glyph;
-    BoxPtr rects;
-    int nrect;
-    glamor_screen_private *glamor_priv;
-
-    rects = REGION_RECTS(dst->pCompositeClip);
-    nrect = REGION_NUM_RECTS(dst->pCompositeClip);
-
-    glamor_priv = glamor_get_screen_private(screen);
-
-    dst_arg.op = op;
-    dst_arg.src = src;
-    dst_arg.dst = dst;
-    dst_arg.buffer = &dst_buffer;
-    dst_arg.x_src = x_src;
-    dst_arg.y_src = y_src;
-    dst_arg.x_dst = x_dst;
-    dst_arg.y_dst = y_dst;
-
-    x = dst->pDrawable->x;
-    y = dst->pDrawable->y;
-
-    while (nlist--) {
-        x += list->xOff;
-        y += list->yOff;
-        n = list->len;
-        dst_glyphs_cnt += n;
-        while (n--) {
-            glyph = *glyphs++;
-
-            if (glyph->info.width > 0 && glyph->info.height > 0) {
-                glyphs_flush_func flush_func;
-
-                if (dst_buffer.count || mask_buffer.count)
-                    flush_func = (glyphs_flush_func) glamor_glyphs_flush_dst;
-                else
-                    flush_func = NULL;
-                glamor_buffer_glyph_clip(glamor_priv,
-                                         rects, nrect,
-                                         (GlyphPicture(glyph)[screen->myNum])->
-                                         format, glyph, NULL, x, y,
-                                         glyph->info.x, glyph->info.y,
-                                         glyph->info.width, glyph->info.height,
-                                         GLYPHS_DST_MODE_TO_DST, flush_func,
-                                         (void *) &dst_arg);
-            }
-
-            x += glyph->info.xOff;
-            y += glyph->info.yOff;
-        }
-        list++;
-    }
-}
-
-#define MAX_FIXED_SIZE
-static void
-glamor_glyphs_reset_buffer(glamor_glyph_buffer_t *buffer)
-{
-    buffer->count = 0;
-    buffer->source = NULL;
-}
-
-static Bool
-_glamor_glyphs(CARD8 op,
-               PicturePtr src,
-               PicturePtr dst,
-               PictFormatPtr mask_format,
-               INT16 x_src,
-               INT16 y_src, int nlist, GlyphListPtr list,
-               GlyphPtr *glyphs, Bool fallback)
-{
-    PictFormatShort format;
-    int fixed_size, fixed_cnt = 0;
-    struct glamor_glyph_list *fixed_list = NULL;
-    Bool need_free_list = FALSE;
-
-#ifndef GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK
-    Bool check_fake_overlap = TRUE;
-
-    if (!(op == PictOpOver || op == PictOpAdd || op == PictOpXor)) {
-        /* C = (0,0,0,0) D = glyphs , SRC = A, DEST = B (faked overlapped glyphs, overlapped with (0,0,0,0)).
-         * For those op, (A IN (C ADD D)) OP B !=  (A IN D) OP ((A IN C) OP B)
-         *              or (A IN (D ADD C)) OP B != (A IN C) OP ((A IN D) OP B)
-         * We need to split the faked regions to three or two, and composite the disoverlapped small
-         * boxes one by one. For other Ops, it's safe to composite the whole box.  */
-        check_fake_overlap = FALSE;
-    }
-#else
-    Bool check_fake_overlap = FALSE;
-#endif
-    if (mask_format)
-        format = mask_format->depth << 24 | mask_format->format;
-    else
-        format = 0;
-
-    fixed_size = 32;
-    glamor_glyphs_reset_buffer(&dst_buffer);
-
-    if (!mask_format || (((nlist == 1 && list->len == 1) || op == PictOpAdd)
-                         && (dst->format ==
-                             ((mask_format->depth << 24) | mask_format->
-                              format)))) {
-        glamor_glyphs_to_dst(op, src, dst, x_src, y_src, nlist, list, glyphs);
-        goto last_flush;
-    }
-
-    glamor_glyphs_reset_buffer(&mask_buffer);
-
-    /* We have mask_format. Need to check the real overlap or not. */
-    format = mask_format->depth << 24 | mask_format->format;
-
-    fixed_list = calloc(fixed_size, sizeof(*fixed_list));
-    if (_X_UNLIKELY(fixed_list == NULL))
-        fixed_size = 0;
-    fixed_cnt = glamor_glyphs_intersect(nlist, list, glyphs,
-                                        format, dst->pDrawable->pScreen,
-                                        check_fake_overlap,
-                                        fixed_list, fixed_size);
-    if (fixed_cnt == 0)
-        mask_format = NULL;
-    need_free_list = TRUE;
-
-    if (fixed_cnt <= 0) {
-        if (mask_format == NULL) {
-            glamor_glyphs_to_dst(op, src, dst, x_src, y_src, nlist,
-                                 list, glyphs);
-            goto last_flush;
-        }
-        else {
-            glamor_glyphs_via_mask(op, src, dst, mask_format,
-                                   x_src, y_src, nlist, list, glyphs, FALSE);
-            goto free_fixed_list;
-        }
-    }
-    else {
-
-        /* We have splitted the original list to serval list, some are overlapped
-         * and some are non-overlapped. For the non-overlapped, we render it to
-         * dst directly. For the overlapped, we render it to mask picture firstly,
-         * then render the mask to dst. If we can use mask cache which is in the
-         * glyphs cache's last row, we can accumulate the rendering of mask to dst
-         * with the other dst_buffer's rendering operations thus can reduce the call
-         * of glDrawElements.
-         *
-         * */
-        struct glamor_glyph_list *saved_list;
-
-        saved_list = fixed_list;
-        mask_arg.used_bitmap = 0;
-        while (fixed_cnt--) {
-            if (fixed_list->type == NON_INTERSECTED) {
-                glamor_glyphs_to_dst(op, src, dst,
-                                     x_src, y_src,
-                                     fixed_list->nlist,
-                                     fixed_list->list, fixed_list->glyphs);
-            }
-            else
-                glamor_glyphs_via_mask(op, src, dst,
-                                       mask_format, x_src, y_src,
-                                       fixed_list->nlist,
-                                       fixed_list->list,
-                                       fixed_list->glyphs, TRUE);
-
-            free(fixed_list->list);
-            fixed_list++;
-        }
-        free(saved_list);
-        need_free_list = FALSE;
-    }
-
- last_flush:
-    if (dst_buffer.count || mask_buffer.count)
-        glamor_glyphs_flush_dst(&dst_arg);
- free_fixed_list:
-    if (need_free_list) {
-        assert(fixed_cnt <= 0);
-        free(fixed_list);
-    }
-    return TRUE;
-}
-
-void
-glamor_glyphs(CARD8 op,
-              PicturePtr src,
-              PicturePtr dst,
-              PictFormatPtr mask_format,
-              INT16 x_src,
-              INT16 y_src, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
-{
-    _glamor_glyphs(op, src, dst, mask_format, x_src,
-                   y_src, nlist, list, glyphs, TRUE);
-}
diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h
index e586fcc..480d13b 100644
--- a/glamor/glamor_priv.h
+++ b/glamor/glamor_priv.h
@@ -154,41 +154,8 @@ enum glamor_gl_flavor {
     GLAMOR_GL_ES2               // OPENGL ES2.0 API
 };
 
-#define GLAMOR_NUM_GLYPH_CACHE_FORMATS 2
-
 #define GLAMOR_COMPOSITE_VBO_VERT_CNT (64*1024)
 
-typedef struct {
-    PicturePtr picture;         /* Where the glyphs of the cache are stored */
-    GlyphPtr *glyphs;
-    uint16_t count;
-    uint16_t evict;
-} glamor_glyph_cache_t;
-
-#define CACHE_PICTURE_SIZE 1024
-#define GLYPH_MIN_SIZE 8
-#define GLYPH_MAX_SIZE	64
-#define GLYPH_CACHE_SIZE ((CACHE_PICTURE_SIZE) * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE))
-
-#define MASK_CACHE_MAX_SIZE 32
-#define MASK_CACHE_WIDTH (CACHE_PICTURE_SIZE / MASK_CACHE_MAX_SIZE)
-#define MASK_CACHE_MASK ((1LL << (MASK_CACHE_WIDTH)) - 1)
-
-struct glamor_glyph_mask_cache_entry {
-    int idx;
-    int width;
-    int height;
-    int x;
-    int y;
-};
-
-typedef struct {
-    PixmapPtr pixmap;
-    struct glamor_glyph_mask_cache_entry mcache[MASK_CACHE_WIDTH];
-    unsigned int free_bitmap;
-    unsigned int cleared_bitmap;
-} glamor_glyph_mask_cache_t;
-
 struct glamor_saved_procs {
     CloseScreenProcPtr close_screen;
     CreateScreenResourcesProcPtr create_screen_resources;
@@ -208,7 +175,6 @@ struct glamor_saved_procs {
     AddTrapsProcPtr addtraps;
     CreatePictureProcPtr create_picture;
     DestroyPictureProcPtr destroy_picture;
-    UnrealizeGlyphProcPtr unrealize_glyph;
     SetWindowPixmapProcPtr set_window_pixmap;
 #if XSYNC
     SyncScreenFuncsRec sync_screen_funcs;
@@ -274,6 +240,14 @@ typedef struct glamor_screen_private {
     glamor_program_fill on_off_dash_line_progs;
     glamor_program      double_dash_line_prog;
 
+    /* glamor composite_glyphs shaders */
+    glamor_program_render       glyphs_program;
+    struct glamor_glyph_atlas   *glyph_atlas_a;
+    struct glamor_glyph_atlas   *glyph_atlas_argb;
+    int                         glyph_atlas_dim;
+    int                         glyph_max_dim;
+    char                        *glyph_defines;
+
     /* vertext/elment_index buffer object for render */
     GLuint vbo, ebo;
     /** Next offset within the VBO that glamor_get_vbo_space() will use. */
@@ -292,9 +266,6 @@ typedef struct glamor_screen_private {
     glamor_composite_shader composite_shader[SHADER_SOURCE_COUNT]
         [SHADER_MASK_COUNT]
         [SHADER_IN_COUNT];
-    glamor_glyph_cache_t glyphCaches[GLAMOR_NUM_GLYPH_CACHE_FORMATS];
-    glamor_glyph_mask_cache_t *mask_cache[GLAMOR_NUM_GLYPH_CACHE_FORMATS];
-    Bool glyph_caches_realized;
 
     /* shaders to restore a texture to another texture. */
     GLint finish_access_prog[2];
@@ -707,17 +678,6 @@ RegionPtr glamor_bitmap_to_region(PixmapPtr pixmap);
 void
 glamor_track_stipple(GCPtr gc);
 
-/* glamor_glyphs.c */
-Bool glamor_realize_glyph_caches(ScreenPtr screen);
-void glamor_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph);
-void glamor_glyphs_fini(ScreenPtr screen);
-void glamor_glyphs(CARD8 op,
-                   PicturePtr pSrc,
-                   PicturePtr pDst,
-                   PictFormatPtr maskFormat,
-                   INT16 xSrc,
-                   INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr *glyphs);
-
 /* glamor_render.c */
 Bool glamor_composite_clipped_region(CARD8 op,
                                      PicturePtr source,
@@ -744,10 +704,6 @@ void glamor_composite(CARD8 op,
 
 void glamor_init_composite_shaders(ScreenPtr screen);
 void glamor_fini_composite_shaders(ScreenPtr screen);
-void glamor_composite_glyph_rects(CARD8 op,
-                                  PicturePtr src, PicturePtr mask,
-                                  PicturePtr dst, int nrect,
-                                  glamor_composite_rect_t *rects);
 void glamor_composite_rects(CARD8 op,
                             PicturePtr pDst,
                             xRenderColor *color, int nRect, xRectangle *rects);
@@ -994,6 +950,22 @@ void glamor_composite_rectangles(CARD8 op,
                                  xRenderColor *color,
                                  int num_rects, xRectangle *rects);
 
+/* glamor_composite_glyphs.c */
+Bool
+glamor_composite_glyphs_init(ScreenPtr pScreen);
+
+void
+glamor_composite_glyphs_fini(ScreenPtr pScreen);
+
+void
+glamor_composite_glyphs(CARD8 op,
+                        PicturePtr src,
+                        PicturePtr dst,
+                        PictFormatPtr mask_format,
+                        INT16 x_src,
+                        INT16 y_src, int nlist,
+                        GlyphListPtr list, GlyphPtr *glyphs);
+
 /* glamor_sync.c */
 Bool
 glamor_sync_init(ScreenPtr screen);
@@ -1077,8 +1049,6 @@ void glamor_xv_render(glamor_port_private *port_priv);
 #if 0
 #define MAX_FBO_SIZE 32         /* For test purpose only. */
 #endif
-//#define GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK
-#define GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK
 
 #include "glamor_font.h"
 
diff --git a/glamor/glamor_program.c b/glamor/glamor_program.c
index d091287..1dc5f19 100644
--- a/glamor/glamor_program.c
+++ b/glamor/glamor_program.c
@@ -139,6 +139,10 @@ static glamor_location_var location_vars[] = {
         .vs_vars = "uniform float dash_length;\n",
         .fs_vars = "uniform sampler2D dash;\n",
     },
+    {
+        .location = glamor_program_location_atlas,
+        .fs_vars = "uniform sampler2D atlas;\n",
+    },
 };
 
 #define NUM_LOCATION_VARS       (sizeof location_vars / sizeof location_vars[0])
@@ -355,6 +359,7 @@ glamor_build_program(ScreenPtr          screen,
     prog->bitmul_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitmul");
     prog->dash_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash");
     prog->dash_length_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash_length");
+    prog->atlas_uniform = glamor_get_uniform(prog, glamor_program_location_atlas, "atlas");
 
     free(version_string);
     free(fs_vars);
diff --git a/glamor/glamor_program.h b/glamor/glamor_program.h
index ad1e9fd..9e561cd 100644
--- a/glamor/glamor_program.h
+++ b/glamor/glamor_program.h
@@ -81,6 +81,7 @@ struct _glamor_program {
     GLint                       bitmul_uniform;
     GLint                       dash_uniform;
     GLint                       dash_length_uniform;
+    GLint                       atlas_uniform;
     glamor_program_location     locations;
     glamor_program_flag         flags;
     glamor_use                  prim_use;
diff --git a/glamor/glamor_render.c b/glamor/glamor_render.c
index 27c09fd..efca367 100644
--- a/glamor/glamor_render.c
+++ b/glamor/glamor_render.c
@@ -1701,139 +1701,3 @@ glamor_composite(CARD8 op,
     glamor_finish_access_picture(source);
     glamor_finish_access_picture(dest);
 }
-
-static void
-glamor_get_src_rect_extent(int nrect,
-                           glamor_composite_rect_t *rects, BoxPtr extent)
-{
-    extent->x1 = MAXSHORT;
-    extent->y1 = MAXSHORT;
-    extent->x2 = MINSHORT;
-    extent->y2 = MINSHORT;
-
-    while (nrect--) {
-        if (extent->x1 > rects->x_src)
-            extent->x1 = rects->x_src;
-        if (extent->y1 > rects->y_src)
-            extent->y1 = rects->y_src;
-        if (extent->x2 < rects->x_src + rects->width)
-            extent->x2 = rects->x_src + rects->width;
-        if (extent->y2 < rects->y_src + rects->height)
-            extent->y2 = rects->y_src + rects->height;
-        rects++;
-    }
-}
-
-static void
-glamor_composite_src_rect_translate(int nrect,
-                                    glamor_composite_rect_t *rects,
-                                    int x, int y)
-{
-    while (nrect--) {
-        rects->x_src += x;
-        rects->y_src += y;
-        rects++;
-    }
-}
-
-void
-glamor_composite_glyph_rects(CARD8 op,
-                             PicturePtr src, PicturePtr mask, PicturePtr dst,
-                             int nrect, glamor_composite_rect_t *rects)
-{
-    int n;
-    PicturePtr temp_src = NULL;
-    glamor_composite_rect_t *r;
-
-    ValidatePicture(src);
-    ValidatePicture(dst);
-    if (!(glamor_is_large_picture(src)
-          || (mask && glamor_is_large_picture(mask))
-          || glamor_is_large_picture(dst))) {
-        PixmapPtr src_pixmap = NULL;
-        PixmapPtr mask_pixmap = NULL;
-        PixmapPtr dst_pixmap = NULL;
-        PixmapPtr temp_src_pixmap = NULL;
-        glamor_pixmap_private *src_pixmap_priv = NULL;
-        glamor_pixmap_private *mask_pixmap_priv = NULL;
-        glamor_pixmap_private *dst_pixmap_priv;
-        glamor_pixmap_private *temp_src_priv = NULL;
-        BoxRec src_extent;
-
-        dst_pixmap = glamor_get_drawable_pixmap(dst->pDrawable);
-        dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
-
-        if (mask && mask->pDrawable) {
-            mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable);
-            mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap);
-        }
-        if (src->pDrawable) {
-            src_pixmap = glamor_get_drawable_pixmap(src->pDrawable);
-            src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
-        }
-
-        if (!src->pDrawable
-            && (src->pSourcePict->type != SourcePictTypeSolidFill)) {
-            glamor_get_src_rect_extent(nrect, rects, &src_extent);
-            temp_src = glamor_convert_gradient_picture(dst->pDrawable->pScreen,
-                                                       src,
-                                                       src_extent.x1,
-                                                       src_extent.y1,
-                                                       src_extent.x2 -
-                                                       src_extent.x1,
-                                                       src_extent.y2 -
-                                                       src_extent.y1);
-            if (!temp_src)
-                goto fallback;
-
-            temp_src_pixmap = (PixmapPtr) (temp_src->pDrawable);
-            temp_src_priv = glamor_get_pixmap_private(temp_src_pixmap);
-            glamor_composite_src_rect_translate(nrect, rects,
-                                                -src_extent.x1, -src_extent.y1);
-        }
-        else {
-            temp_src = src;
-            temp_src_pixmap = src_pixmap;
-            temp_src_priv = src_pixmap_priv;
-        }
-
-        if (mask && mask->componentAlpha) {
-            if (op == PictOpOver) {
-                if (glamor_composite_with_shader(PictOpOutReverse,
-                                                 temp_src, mask, dst,
-                                                 temp_src_pixmap, mask_pixmap, dst_pixmap,
-                                                 temp_src_priv,
-                                                 mask_pixmap_priv,
-                                                 dst_pixmap_priv, nrect, rects,
-                                                 TRUE))
-                    goto done;
-            }
-        }
-        else {
-            if (glamor_composite_with_shader
-                (op, temp_src, mask, dst,
-                 temp_src_pixmap, mask_pixmap, dst_pixmap,
-                 temp_src_priv, mask_pixmap_priv,
-                 dst_pixmap_priv, nrect, rects, FALSE))
-                goto done;
-        }
-    }
- fallback:
-    n = nrect;
-    r = rects;
-
-    while (n--) {
-        CompositePicture(op,
-                         temp_src ? temp_src : src,
-                         mask,
-                         dst,
-                         r->x_src, r->y_src,
-                         r->x_mask, r->y_mask,
-                         r->x_dst, r->y_dst, r->width, r->height);
-        r++;
-    }
-
- done:
-    if (temp_src && temp_src != src)
-        FreePicture(temp_src, 0);
-}
commit 1b745e0c1ff45e014aa21c3d8edf93227bec99bf
Author: Keith Packard <keithp at keithp.com>
Date:   Mon Oct 13 11:40:06 2014 -0700

    glamor: Adapt glamor_program API  to handle render acceleration
    
    This extends the existing API to support options needed for render
    accleration, including an additional fragment, 'combine', (which
    provides a place to perform the source IN mask operation before the
    final OP dest state) and an additional 'defines' parameter which
    provides a way to add target-dependent values without using a uniform.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Eric Anholt <eric at anholt.net>

diff --git a/glamor/glamor_copy.c b/glamor/glamor_copy.c
index 921e80e..028acf2 100644
--- a/glamor/glamor_copy.c
+++ b/glamor/glamor_copy.c
@@ -53,7 +53,7 @@ static const glamor_facet glamor_facet_copyarea = {
     .vs_exec = (GLAMOR_POS(gl_Position, primitive.xy)
                 "       fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"),
     .fs_exec = "       gl_FragColor = texture2D(sampler, fill_pos);\n",
-    .locations = glamor_program_location_fill,
+    .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
     .use = use_copyarea,
 };
 
@@ -140,7 +140,7 @@ static const glamor_facet glamor_facet_copyplane = {
                 "               gl_FragColor = fg;\n"
                 "       else\n"
                 "               gl_FragColor = bg;\n"),
-    .locations = glamor_program_location_fill|glamor_program_location_fg|glamor_program_location_bg|glamor_program_location_bitplane,
+    .locations = glamor_program_location_fillsamp|glamor_program_location_fillpos|glamor_program_location_fg|glamor_program_location_bg|glamor_program_location_bitplane,
     .use = use_copyplane,
 };
 
@@ -338,7 +338,7 @@ glamor_copy_fbo_fbo_draw(DrawablePtr src,
 
     if (!prog->prog) {
         if (!glamor_build_program(screen, prog,
-                                  copy_facet, NULL))
+                                  copy_facet, NULL, NULL, NULL))
             goto bail_ctx;
     }
 
diff --git a/glamor/glamor_dash.c b/glamor/glamor_dash.c
index 4281ff0..101228e 100644
--- a/glamor/glamor_dash.c
+++ b/glamor/glamor_dash.c
@@ -170,7 +170,7 @@ glamor_dash_setup(DrawablePtr drawable, GCPtr gc)
         if (!prog->prog) {
             if (!glamor_build_program(screen, prog,
                                       &glamor_facet_double_dash_lines,
-                                      NULL))
+                                      NULL, NULL, NULL))
                 goto bail;
         }
 
diff --git a/glamor/glamor_points.c b/glamor/glamor_points.c
index df7e5a2..3ba4a69 100644
--- a/glamor/glamor_points.c
+++ b/glamor/glamor_points.c
@@ -60,7 +60,8 @@ glamor_poly_point_gl(DrawablePtr drawable, GCPtr gc, int mode, int npt, DDXPoint
     if (!prog->prog) {
         if (!glamor_build_program(screen, prog,
                                   &glamor_facet_point,
-                                  &glamor_fill_solid))
+                                  &glamor_fill_solid,
+                                  NULL, NULL))
             goto bail;
     }
 
diff --git a/glamor/glamor_program.c b/glamor/glamor_program.c
index 8aab53f..d091287 100644
--- a/glamor/glamor_program.c
+++ b/glamor/glamor_program.c
@@ -47,7 +47,7 @@ static const glamor_facet glamor_fill_tile = {
     .name = "tile",
     .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
     .fs_exec =  "       gl_FragColor = texture2D(sampler, fill_pos);\n",
-    .locations = glamor_program_location_fill,
+    .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
     .use = use_tile,
 };
 
@@ -66,7 +66,7 @@ static const glamor_facet glamor_fill_stipple = {
                 "       if (a == 0.0)\n"
                 "               discard;\n"
                 "       gl_FragColor = fg;\n"),
-    .locations = glamor_program_location_fg | glamor_program_location_fill,
+    .locations = glamor_program_location_fg | glamor_program_location_fillsamp | glamor_program_location_fillpos,
     .use = use_stipple,
 };
 
@@ -87,7 +87,7 @@ static const glamor_facet glamor_fill_opaque_stipple = {
                 "               gl_FragColor = bg;\n"
                 "       else\n"
                 "               gl_FragColor = fg;\n"),
-    .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fill,
+    .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fillsamp | glamor_program_location_fillpos,
     .use = use_opaque_stipple
 };
 
@@ -114,12 +114,15 @@ static glamor_location_var location_vars[] = {
         .fs_vars = "uniform vec4 bg;\n"
     },
     {
-        .location = glamor_program_location_fill,
+        .location = glamor_program_location_fillsamp,
+        .fs_vars = "uniform sampler2D sampler;\n"
+    },
+    {
+        .location = glamor_program_location_fillpos,
         .vs_vars = ("uniform vec2 fill_offset;\n"
                     "uniform vec2 fill_size_inv;\n"
                     "varying vec2 fill_pos;\n"),
-        .fs_vars = ("uniform sampler2D sampler;\n"
-                    "uniform vec2 fill_size_inv;\n"
+        .fs_vars = ("uniform vec2 fill_size_inv;\n"
                     "varying vec2 fill_pos;\n")
     },
     {
@@ -183,6 +186,7 @@ fs_location_vars(glamor_program_location locations)
 
 static const char vs_template[] =
     "%s"                                /* version */
+    "%s"                                /* defines */
     "%s"                                /* prim vs_vars */
     "%s"                                /* fill vs_vars */
     "%s"                                /* location vs_vars */
@@ -195,12 +199,14 @@ static const char vs_template[] =
 static const char fs_template[] =
     "%s"                                /* version */
     GLAMOR_DEFAULT_PRECISION
+    "%s"                                /* defines */
     "%s"                                /* prim fs_vars */
     "%s"                                /* fill fs_vars */
     "%s"                                /* location fs_vars */
     "void main() {\n"
     "%s"                                /* prim fs_exec */
     "%s"                                /* fill fs_exec */
+    "%s"                                /* combine */
     "}\n";
 
 static const char *
@@ -236,7 +242,9 @@ Bool
 glamor_build_program(ScreenPtr          screen,
                      glamor_program     *prog,
                      const glamor_facet *prim,
-                     const glamor_facet *fill)
+                     const glamor_facet *fill,
+                     const char         *combine,
+                     const char         *defines)
 {
     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 
@@ -282,6 +290,7 @@ glamor_build_program(ScreenPtr          screen,
     if (asprintf(&vs_prog_string,
                  vs_template,
                  str(version_string),
+                 str(defines),
                  str(prim->vs_vars),
                  str(fill->vs_vars),
                  vs_vars,
@@ -292,26 +301,30 @@ glamor_build_program(ScreenPtr          screen,
     if (asprintf(&fs_prog_string,
                  fs_template,
                  str(version_string),
+                 str(defines),
                  str(prim->fs_vars),
                  str(fill->fs_vars),
                  fs_vars,
                  str(prim->fs_exec),
-                 str(fill->fs_exec)) < 0)
+                 str(fill->fs_exec),
+                 str(combine)) < 0)
         fs_prog_string = NULL;
 
     if (!vs_prog_string || !fs_prog_string)
         goto fail;
 
+    prog->prog = glCreateProgram();
 #if DBG
-    ErrorF("\nPrograms for %s %s\nVertex shader:\n\n%s\n\nFragment Shader:\n\n%s",
-           prim->name, fill->name, vs_prog_string, fs_prog_string);
+    ErrorF("\n\tProgram %d for %s %s\n\tVertex shader:\n\n\t================\n%s\n\n\tFragment Shader:\n\n%s\t================\n",
+           prog->prog, prim->name, fill->name, vs_prog_string, fs_prog_string);
 #endif
 
-    prog->prog = glCreateProgram();
     prog->flags = flags;
     prog->locations = locations;
     prog->prim_use = prim->use;
+    prog->prim_use_render = prim->use_render;
     prog->fill_use = fill->use;
+    prog->fill_use_render = fill->use_render;
 
     vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string);
     fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string);
@@ -335,8 +348,8 @@ glamor_build_program(ScreenPtr          screen,
     prog->matrix_uniform = glamor_get_uniform(prog, glamor_program_location_none, "v_matrix");
     prog->fg_uniform = glamor_get_uniform(prog, glamor_program_location_fg, "fg");
     prog->bg_uniform = glamor_get_uniform(prog, glamor_program_location_bg, "bg");
-    prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fill, "fill_offset");
-    prog->fill_size_inv_uniform = glamor_get_uniform(prog, glamor_program_location_fill, "fill_size_inv");
+    prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_offset");
+    prog->fill_size_inv_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_size_inv");
     prog->font_uniform = glamor_get_uniform(prog, glamor_program_location_font, "font");
     prog->bitplane_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitplane");
     prog->bitmul_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitmul");
@@ -396,7 +409,7 @@ glamor_use_program_fill(PixmapPtr               pixmap,
         if (!fill)
             return NULL;
 
-        if (!glamor_build_program(screen, prog, prim, fill))
+        if (!glamor_build_program(screen, prog, prim, fill, NULL, NULL))
             return NULL;
     }
 
@@ -405,3 +418,238 @@ glamor_use_program_fill(PixmapPtr               pixmap,
 
     return prog;
 }
+
+static struct blendinfo composite_op_info[] = {
+    [PictOpClear] = {0, 0, GL_ZERO, GL_ZERO},
+    [PictOpSrc] = {0, 0, GL_ONE, GL_ZERO},
+    [PictOpDst] = {0, 0, GL_ZERO, GL_ONE},
+    [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
+    [PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
+    [PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO},
+    [PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA},
+    [PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
+    [PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
+    [PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+    [PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
+    [PictOpXor] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+    [PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
+};
+
+static void
+glamor_set_blend(CARD8 op, glamor_program_alpha alpha, PicturePtr dst)
+{
+    GLenum src_blend, dst_blend;
+    struct blendinfo *op_info;
+
+    switch (alpha) {
+    case glamor_program_alpha_ca_first:
+        op = PictOpOutReverse;
+        break;
+    case glamor_program_alpha_ca_second:
+        op = PictOpAdd;
+        break;
+    default:
+        break;
+    }
+
+    if (op == PictOpSrc)
+        return;
+
+    op_info = &composite_op_info[op];
+
+    src_blend = op_info->source_blend;
+    dst_blend = op_info->dest_blend;
+
+    /* If there's no dst alpha channel, adjust the blend op so that we'll treat
+     * it as always 1.
+     */
+    if (PICT_FORMAT_A(dst->format) == 0 && op_info->dest_alpha) {
+        if (src_blend == GL_DST_ALPHA)
+            src_blend = GL_ONE;
+        else if (src_blend == GL_ONE_MINUS_DST_ALPHA)
+            src_blend = GL_ZERO;
+    }
+
+    /* Set up the source alpha value for blending in component alpha mode. */
+    if (alpha != glamor_program_alpha_normal && op_info->source_alpha) {
+        if (dst_blend == GL_SRC_ALPHA)
+            dst_blend = GL_SRC_COLOR;
+        else if (dst_blend == GL_ONE_MINUS_SRC_ALPHA)
+            dst_blend = GL_ONE_MINUS_SRC_COLOR;
+    }
+
+    glEnable(GL_BLEND);
+    glBlendFunc(src_blend, dst_blend);
+}
+
+static Bool
+use_source_solid(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
+{
+
+    glamor_set_blend(op, prog->alpha, dst);
+
+    glamor_set_color(glamor_get_drawable_pixmap(dst->pDrawable),
+                     src->pSourcePict->solidFill.color,
+                     prog->fg_uniform);
+    return TRUE;
+}
+
+const glamor_facet glamor_source_solid = {
+    .name = "render_solid",
+    .fs_exec = "       vec4 source = fg;\n",
+    .locations = glamor_program_location_fg,
+    .use_render = use_source_solid,
+};
+
+static Bool
+use_source_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
+{
+    glamor_set_blend(op, prog->alpha, dst);
+
+    return glamor_set_texture((PixmapPtr) src->pDrawable,
+                              0, 0,
+                              prog->fill_offset_uniform,
+                              prog->fill_size_inv_uniform);
+}
+
+const glamor_facet glamor_source_picture = {
+    .name = "render_picture",
+    .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
+    .fs_exec =  "       vec4 source = texture2D(sampler, fill_pos);\n",
+    .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
+    .use_render = use_source_picture,
+};
+
+static Bool
+use_source_1x1_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
+{
+    glamor_set_blend(op, prog->alpha, dst);
+
+    return glamor_set_texture_pixmap((PixmapPtr) src->pDrawable);
+}
+
+const glamor_facet glamor_source_1x1_picture = {
+    .name = "render_picture",
+    .fs_exec =  "       vec4 source = texture2D(sampler, vec2(0.5));\n",
+    .locations = glamor_program_location_fillsamp,
+    .use_render = use_source_1x1_picture,
+};
+
+const glamor_facet *glamor_facet_source[glamor_program_source_count] = {
+    [glamor_program_source_solid] = &glamor_source_solid,
+    [glamor_program_source_picture] = &glamor_source_picture,
+    [glamor_program_source_1x1_picture] = &glamor_source_1x1_picture,
+};
+
+static const char *glamor_combine[] = {
+    [glamor_program_alpha_normal]    = "       gl_FragColor = source * mask.a;\n",
+    [glamor_program_alpha_ca_first]  = "       gl_FragColor = source.a * mask;\n",
+    [glamor_program_alpha_ca_second] = "       gl_FragColor = source * mask;\n"
+};
+
+static Bool
+glamor_setup_one_program_render(ScreenPtr               screen,
+                                glamor_program          *prog,
+                                glamor_program_source   source_type,
+                                glamor_program_alpha    alpha,
+                                const glamor_facet      *prim,
+                                const char              *defines)
+{
+    if (prog->failed)
+        return FALSE;
+
+    if (!prog->prog) {
+        const glamor_facet      *fill = glamor_facet_source[source_type];
+
+        if (!fill)
+            return FALSE;
+
+        if (!glamor_build_program(screen, prog, prim, fill, glamor_combine[alpha], defines))
+            return FALSE;
+        prog->alpha = alpha;
+    }
+
+    return TRUE;
+}
+
+glamor_program *
+glamor_setup_program_render(CARD8                 op,
+                            PicturePtr            src,
+                            PicturePtr            mask,
+                            PicturePtr            dst,
+                            glamor_program_render *program_render,
+                            const glamor_facet    *prim,
+                            const char            *defines)
+{
+    ScreenPtr                   screen = dst->pDrawable->pScreen;
+    glamor_program_alpha        alpha;
+    glamor_program_source       source_type;
+    glamor_program              *prog;
+
+    if (op > ARRAY_SIZE(composite_op_info))
+        return NULL;
+
+    if (glamor_is_component_alpha(mask)) {
+        /* This only works for PictOpOver */
+        if (op != PictOpOver)
+            return NULL;
+        alpha = glamor_program_alpha_ca_first;
+    } else
+        alpha = glamor_program_alpha_normal;
+
+    if (src->pDrawable) {
+
+        /* Can't do transforms, alphamaps or sourcing from non-pixmaps yet */
+        if (src->transform || src->alphaMap || src->pDrawable->type != DRAWABLE_PIXMAP)
+            return NULL;
+
+        if (src->pDrawable->width == 1 && src->pDrawable->height == 1 && src->repeat)
+            source_type = glamor_program_source_1x1_picture;
+        else
+            source_type = glamor_program_source_picture;
+    } else {
+        SourcePictPtr   sp = src->pSourcePict;
+        if (!sp)
+            return NULL;
+        switch (sp->type) {
+        case SourcePictTypeSolidFill:
+            source_type = glamor_program_source_solid;
+            break;
+        default:
+            return NULL;
+        }
+    }
+
+    prog = &program_render->progs[source_type][alpha];
+    if (!glamor_setup_one_program_render(screen, prog, source_type, alpha, prim, defines))
+        return NULL;
+
+    if (alpha == glamor_program_alpha_ca_first) {
+
+	  /* Make sure we can also build the second program before
+	   * deciding to use this path.
+	   */
+	  if (!glamor_setup_one_program_render(screen,
+					       &program_render->progs[source_type][glamor_program_alpha_ca_second],
+					       source_type, glamor_program_alpha_ca_second, prim,
+					       defines))
+	      return NULL;
+    }
+    return prog;
+}
+
+Bool
+glamor_use_program_render(glamor_program        *prog,
+                          CARD8                 op,
+                          PicturePtr            src,
+                          PicturePtr            dst)
+{
+    glUseProgram(prog->prog);
+
+    if (prog->prim_use_render && !prog->prim_use_render(op, src, dst, prog))
+        return FALSE;
+
+    if (prog->fill_use_render && !prog->fill_use_render(op, src, dst, prog))
+        return FALSE;
+    return TRUE;
+}
diff --git a/glamor/glamor_program.h b/glamor/glamor_program.h
index fa3877c..ad1e9fd 100644
--- a/glamor/glamor_program.h
+++ b/glamor/glamor_program.h
@@ -27,23 +27,36 @@ typedef enum {
     glamor_program_location_none = 0,
     glamor_program_location_fg = 1,
     glamor_program_location_bg = 2,
-    glamor_program_location_fill = 4,
-    glamor_program_location_font = 8,
-    glamor_program_location_bitplane = 16,
-    glamor_program_location_dash = 32,
+    glamor_program_location_fillsamp = 4,
+    glamor_program_location_fillpos = 8,
+    glamor_program_location_font = 16,
+    glamor_program_location_bitplane = 32,
+    glamor_program_location_dash = 64,
+    glamor_program_location_atlas = 128,
 } glamor_program_location;
 
 typedef enum {
     glamor_program_flag_none = 0,
 } glamor_program_flag;
 
+typedef enum {
+    glamor_program_alpha_normal,
+    glamor_program_alpha_ca_first,
+    glamor_program_alpha_ca_second,
+    glamor_program_alpha_count
+} glamor_program_alpha;
+
 typedef struct _glamor_program glamor_program;
 
 typedef Bool (*glamor_use) (PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg);
 
+typedef Bool (*glamor_use_render) (CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog);
+
 typedef struct {
     const char                          *name;
     const int                           version;
+    char                                *vs_defines;
+    char                                *fs_defines;
     const char                          *vs_vars;
     const char                          *vs_exec;
     const char                          *fs_vars;
@@ -52,6 +65,7 @@ typedef struct {
     const glamor_program_flag           flags;
     const char                          *source_name;
     glamor_use                          use;
+    glamor_use_render                   use_render;
 } glamor_facet;
 
 struct _glamor_program {
@@ -71,6 +85,9 @@ struct _glamor_program {
     glamor_program_flag         flags;
     glamor_use                  prim_use;
     glamor_use                  fill_use;
+    glamor_program_alpha        alpha;
+    glamor_use_render           prim_use_render;
+    glamor_use_render           fill_use_render;
 };
 
 typedef struct {
@@ -83,7 +100,9 @@ Bool
 glamor_build_program(ScreenPtr          screen,
                      glamor_program     *prog,
                      const glamor_facet *prim,
-                     const glamor_facet *fill);
+                     const glamor_facet *fill,
+                     const char         *combine,
+                     const char         *defines);
 
 Bool
 glamor_use_program(PixmapPtr            pixmap,
@@ -97,4 +116,37 @@ glamor_use_program_fill(PixmapPtr               pixmap,
                         glamor_program_fill     *program_fill,
                         const glamor_facet      *prim);
 
+typedef enum {
+    glamor_program_source_solid,
+    glamor_program_source_picture,
+    glamor_program_source_1x1_picture,
+    glamor_program_source_count,
+} glamor_program_source;
+
+typedef struct {
+    glamor_program      progs[glamor_program_source_count][glamor_program_alpha_count];
+} glamor_program_render;
+
+static inline Bool
+glamor_is_component_alpha(PicturePtr mask) {
+    if (mask && mask->componentAlpha && PICT_FORMAT_RGB(mask->format))
+        return TRUE;
+    return FALSE;
+}
+
+glamor_program *
+glamor_setup_program_render(CARD8                 op,
+                            PicturePtr            src,
+                            PicturePtr            mask,
+                            PicturePtr            dst,
+                            glamor_program_render *program_render,
+                            const glamor_facet    *prim,
+                            const char            *defines);
+
+Bool
+glamor_use_program_render(glamor_program        *prog,
+                          CARD8                 op,
+                          PicturePtr            src,
+                          PicturePtr            dst);
+
 #endif /* _GLAMOR_PROGRAM_H_ */
diff --git a/glamor/glamor_text.c b/glamor/glamor_text.c
index 8d8c970..81a22a5 100644
--- a/glamor/glamor_text.c
+++ b/glamor/glamor_text.c
@@ -417,7 +417,7 @@ glamor_image_text(DrawablePtr drawable, GCPtr gc,
             fill_facet = &glamor_facet_image_fill;
         }
 
-        if (!glamor_build_program(screen, prog, prim_facet, fill_facet))
+        if (!glamor_build_program(screen, prog, prim_facet, fill_facet, NULL, NULL))
             goto bail;
     }
 
diff --git a/glamor/glamor_transform.c b/glamor/glamor_transform.c
index e94bca8..f476a99 100644
--- a/glamor/glamor_transform.c
+++ b/glamor/glamor_transform.c
@@ -155,11 +155,7 @@ glamor_set_solid(PixmapPtr      pixmap,
 }
 
 Bool
-glamor_set_texture(PixmapPtr    texture,
-                   int          off_x,
-                   int          off_y,
-                   GLint        offset_uniform,
-                   GLint        size_inv_uniform)
+glamor_set_texture_pixmap(PixmapPtr texture)
 {
     glamor_pixmap_private *texture_priv;
 
@@ -174,6 +170,23 @@ glamor_set_texture(PixmapPtr    texture,
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, texture_priv->fbo->tex);
 
+    /* we're not setting the sampler uniform here as we always use
+     * GL_TEXTURE0, and the default value for uniforms is zero. So,
+     * save a bit of CPU time by taking advantage of that.
+     */
+    return TRUE;
+}
+
+Bool
+glamor_set_texture(PixmapPtr    texture,
+                   int          off_x,
+                   int          off_y,
+                   GLint        offset_uniform,
+                   GLint        size_inv_uniform)
+{
+    if (!glamor_set_texture_pixmap(texture))
+        return FALSE;
+
     glUniform2f(offset_uniform, off_x, off_y);
     glUniform2f(size_inv_uniform, 1.0f/texture->drawable.width, 1.0f/texture->drawable.height);
     return TRUE;
diff --git a/glamor/glamor_transform.h b/glamor/glamor_transform.h
index 1d8eed4..dca6a26 100644
--- a/glamor/glamor_transform.h
+++ b/glamor/glamor_transform.h
@@ -39,6 +39,9 @@ glamor_set_color(PixmapPtr      pixmap,
                  GLint          uniform);
 
 Bool
+glamor_set_texture_pixmap(PixmapPtr    texture);
+
+Bool
 glamor_set_texture(PixmapPtr    texture,
                    int          off_x,
                    int          off_y,
commit ff3195aadde95c8e89f77f389a7dfb418dd2426c
Author: Keith Packard <keithp at keithp.com>
Date:   Mon Oct 20 21:31:56 2014 -0700

    glamor: Compute GLSL version from GL_SHADING_LANGUAGE_VERSION (v3)
    
    Use code from Piglit project to compute GLSL version for either GL or
    GLES. The Piglit code was originally written by Chad Versace.
    
    v2: bail if the parse fails (requested by Eric Anholt)
    v3: Use version 1.20 for GLES until we fix our programs (Eric Anholt)
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Eric Anholt <eric at anholt.net>

diff --git a/glamor/glamor.c b/glamor/glamor.c
index 6f4f309..9d40e3c 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2008 Intel Corporation
+ * Copyright © 2008,2011 Intel Corporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -23,7 +23,7 @@
  * Authors:
  *    Eric Anholt <eric at anholt.net>
  *    Zhigang Gong <zhigang.gong at linux.intel.com>
- *
+ *    Chad Versace <chad.versace at linux.intel.com>
  */
 
 /** @file glamor.c
@@ -336,7 +336,11 @@ glamor_init(ScreenPtr screen, unsigned int flags)
 {
     glamor_screen_private *glamor_priv;
     int gl_version;
+    int glsl_major, glsl_minor;
     int max_viewport_size[2];
+    const char *shading_version_string;
+    int shading_version_offset;
+
     PictureScreenPtr ps = GetPictureScreenIfSet(screen);
 
     if (flags & ~GLAMOR_VALID_FLAGS) {
@@ -380,14 +384,40 @@ glamor_init(ScreenPtr screen, unsigned int flags)
 
     gl_version = epoxy_gl_version();
 
-    /* Would be nice to have a cleaner test for GLSL 1.30 support,
-     * but for now this should suffice
-     */
-    if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP && gl_version >= 30)
-        glamor_priv->glsl_version = 130;
-    else
-        glamor_priv->glsl_version = 120;
+    shading_version_string = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
+
+    if (!shading_version_string) {
+        LogMessage(X_WARNING,
+                   "glamor%d: Failed to get GLSL version\n",
+                   screen->myNum);
+        goto fail;
+    }
 
+    shading_version_offset = 0;
+    if (strncmp("OpenGL ES GLSL ES ", shading_version_string, 18) == 0)
+        shading_version_offset = 18;
+
+    if (sscanf(shading_version_string + shading_version_offset,
+               "%i.%i",
+               &glsl_major,
+               &glsl_minor) != 2) {
+        LogMessage(X_WARNING,
+                   "glamor%d: Failed to parse GLSL version string %s\n",
+                   screen->myNum, shading_version_string);
+        goto fail;
+    }
+    glamor_priv->glsl_version = glsl_major * 100 + glsl_minor;
+
+    if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) {
+        /* Force us back to the base version of our programs on an ES
+         * context, anyway.  Basically glamor only uses desktop 1.20
+         * or 1.30 currently.  1.30's new features are also present in
+         * ES 3.0, but our glamor_program.c constructions use a lot of
+         * compatibility features (to reduce the diff between 1.20 and
+         * 1.30 programs).
+         */
+        glamor_priv->glsl_version = 120;
+    }
 
     /* We'd like to require GL_ARB_map_buffer_range or
      * GL_OES_map_buffer_range, since it offers more information to
commit dcb3d74ba8861e7b0a592e92b5b2247b84e843f3
Author: Keith Packard <keithp at keithp.com>
Date:   Mon Oct 13 12:35:40 2014 -0700

    glamor: Remove destination drawable argument from glamor_set_texture
    
    This argument wasn't used at all.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Eric Anholt <eric at anholt.net>

diff --git a/glamor/glamor_transform.c b/glamor/glamor_transform.c
index 3036a06..e94bca8 100644
--- a/glamor/glamor_transform.c
+++ b/glamor/glamor_transform.c
@@ -155,8 +155,7 @@ glamor_set_solid(PixmapPtr      pixmap,
 }
 
 Bool
-glamor_set_texture(PixmapPtr    pixmap,
-                   PixmapPtr    texture,
+glamor_set_texture(PixmapPtr    texture,
                    int          off_x,
                    int          off_y,
                    GLint        offset_uniform,
@@ -192,8 +191,7 @@ glamor_set_tiled(PixmapPtr      pixmap,
     if (!glamor_set_planemask(gc->depth, gc->planemask))
         return FALSE;
 
-    return glamor_set_texture(pixmap,
-                              gc->tile.pixmap,
+    return glamor_set_texture(gc->tile.pixmap,
                               -gc->patOrg.x,
                               -gc->patOrg.y,
                               offset_uniform,
@@ -274,8 +272,7 @@ glamor_set_stippled(PixmapPtr      pixmap,
     if (!glamor_set_solid(pixmap, gc, TRUE, fg_uniform))
         return FALSE;
 
-    return glamor_set_texture(pixmap,
-                              stipple,
+    return glamor_set_texture(stipple,
                               -gc->patOrg.x,
                               -gc->patOrg.y,
                               offset_uniform,
diff --git a/glamor/glamor_transform.h b/glamor/glamor_transform.h
index 36b789a..1d8eed4 100644
--- a/glamor/glamor_transform.h
+++ b/glamor/glamor_transform.h
@@ -39,8 +39,7 @@ glamor_set_color(PixmapPtr      pixmap,
                  GLint          uniform);
 
 Bool
-glamor_set_texture(PixmapPtr    pixmap,
-                   PixmapPtr    texture,
+glamor_set_texture(PixmapPtr    texture,
                    int          off_x,
                    int          off_y,
                    GLint        offset_uniform,
commit 2bf34fe8d9b7628d164392c2d11ace78f7cf17b9
Author: Keith Packard <keithp at keithp.com>
Date:   Mon Oct 13 12:32:27 2014 -0700

    glamor: Pass depth to glamor_pm_is_solid and glamor_set_planemask
    
    Instead of passing the destination drawable, just pass the depth, as
    the underlying functions need only that to check whether the planemask
    is going to work.
    
    This API change will allow higher level functions to not need the
    destination pixmap.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Eric Anholt <eric at anholt.net>

diff --git a/glamor/glamor_copy.c b/glamor/glamor_copy.c
index 75fe8a7..921e80e 100644
--- a/glamor/glamor_copy.c
+++ b/glamor/glamor_copy.c
@@ -212,7 +212,7 @@ glamor_copy_cpu_fbo(DrawablePtr src,
     if (gc && gc->alu != GXcopy)
         goto bail;
 
-    if (gc && !glamor_pm_is_solid(dst, gc->planemask))
+    if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask))
         goto bail;
 
     glamor_make_current(glamor_priv);
@@ -262,7 +262,7 @@ glamor_copy_fbo_cpu(DrawablePtr src,
     if (gc && gc->alu != GXcopy)
         goto bail;
 
-    if (gc && !glamor_pm_is_solid(dst, gc->planemask))
+    if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask))
         goto bail;
 
     glamor_make_current(glamor_priv);
@@ -319,7 +319,7 @@ glamor_copy_fbo_fbo_draw(DrawablePtr src,
 
     glamor_make_current(glamor_priv);
 
-    if (gc && !glamor_set_planemask(dst_pixmap, gc->planemask))
+    if (gc && !glamor_set_planemask(gc->depth, gc->planemask))
         goto bail_ctx;
 
     if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
@@ -419,7 +419,6 @@ glamor_copy_fbo_fbo_temp(DrawablePtr src,
 {
     ScreenPtr screen = dst->pScreen;
     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
-    PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
     PixmapPtr tmp_pixmap;
     BoxRec bounds;
     int n;
@@ -434,7 +433,7 @@ glamor_copy_fbo_fbo_temp(DrawablePtr src,
      */
     glamor_make_current(glamor_priv);
 
-    if (gc && !glamor_set_planemask(dst_pixmap, gc->planemask))
+    if (gc && !glamor_set_planemask(gc->depth, gc->planemask))
         goto bail_ctx;
 
     if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
diff --git a/glamor/glamor_image.c b/glamor/glamor_image.c
index 5633da6..a272d5e 100644
--- a/glamor/glamor_image.c
+++ b/glamor/glamor_image.c
@@ -49,7 +49,7 @@ glamor_put_image_gl(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
     if (gc->alu != GXcopy)
         goto bail;
 
-    if (!glamor_pm_is_solid(&pixmap->drawable, gc->planemask))
+    if (!glamor_pm_is_solid(gc->depth, gc->planemask))
         goto bail;
 
     if (format == XYPixmap && drawable->depth == 1 && leftPad == 0)
@@ -116,7 +116,7 @@ glamor_get_image_gl(DrawablePtr drawable, int x, int y, int w, int h,
     if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
         goto bail;
 
-    if (format != ZPixmap || !glamor_pm_is_solid(drawable, plane_mask))
+    if (format != ZPixmap || !glamor_pm_is_solid(drawable->depth, plane_mask))
         goto bail;
 
     glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
diff --git a/glamor/glamor_pixmap.c b/glamor/glamor_pixmap.c
index 6235747..4e87371 100644
--- a/glamor/glamor_pixmap.c
+++ b/glamor/glamor_pixmap.c
@@ -109,9 +109,9 @@ glamor_set_destination_pixmap(PixmapPtr pixmap)
 }
 
 Bool
-glamor_set_planemask(PixmapPtr pixmap, unsigned long planemask)
+glamor_set_planemask(int depth, unsigned long planemask)
 {
-    if (glamor_pm_is_solid(&pixmap->drawable, planemask)) {
+    if (glamor_pm_is_solid(depth, planemask)) {
         return GL_TRUE;
     }
 
diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h
index 4b9ba4d..e586fcc 100644
--- a/glamor/glamor_priv.h
+++ b/glamor/glamor_priv.h
@@ -638,10 +638,10 @@ glamor_get_gc_private(GCPtr gc)
  * pixel values for pDrawable.
  */
 static inline Bool
-glamor_pm_is_solid(DrawablePtr drawable, unsigned long planemask)
+glamor_pm_is_solid(int depth, unsigned long planemask)
 {
-    return (planemask & FbFullMask(drawable->depth)) ==
-        FbFullMask(drawable->depth);
+    return (planemask & FbFullMask(depth)) ==
+        FbFullMask(depth);
 }
 
 extern int glamor_debug_level;
@@ -701,7 +701,7 @@ glamor_pixmap_fbo *glamor_es2_pixmap_read_prepare(PixmapPtr source, int x,
                                                   int swap_rb);
 
 Bool glamor_set_alu(ScreenPtr screen, unsigned char alu);
-Bool glamor_set_planemask(PixmapPtr pixmap, unsigned long planemask);
+Bool glamor_set_planemask(int depth, unsigned long planemask);
 RegionPtr glamor_bitmap_to_region(PixmapPtr pixmap);
 
 void
diff --git a/glamor/glamor_spans.c b/glamor/glamor_spans.c
index b358c60..58da3ed 100644
--- a/glamor/glamor_spans.c
+++ b/glamor/glamor_spans.c
@@ -279,7 +279,7 @@ glamor_set_spans_gl(DrawablePtr drawable, GCPtr gc, char *src,
     if (gc->alu != GXcopy)
         goto bail;
 
-    if (!glamor_pm_is_solid(&pixmap->drawable, gc->planemask))
+    if (!glamor_pm_is_solid(gc->depth, gc->planemask))
         goto bail;
 
     glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
diff --git a/glamor/glamor_text.c b/glamor/glamor_text.c
index c7c1ab7..8d8c970 100644
--- a/glamor/glamor_text.c
+++ b/glamor/glamor_text.c
@@ -431,7 +431,7 @@ glamor_image_text(DrawablePtr drawable, GCPtr gc,
         /* Check planemask before drawing background to
          * bail early if it's not OK
          */
-        if (!glamor_set_planemask(pixmap, gc->planemask))
+        if (!glamor_set_planemask(gc->depth, gc->planemask))
             goto bail;
         for (c = 0; c < count; c++)
             if (charinfo[c])
diff --git a/glamor/glamor_transform.c b/glamor/glamor_transform.c
index 6d29e9e..3036a06 100644
--- a/glamor/glamor_transform.c
+++ b/glamor/glamor_transform.c
@@ -129,7 +129,7 @@ glamor_set_solid(PixmapPtr      pixmap,
     CARD32      pixel;
     int         alu = use_alu ? gc->alu : GXcopy;
 
-    if (!glamor_set_planemask(pixmap, gc->planemask))
+    if (!glamor_set_planemask(gc->depth, gc->planemask))
         return FALSE;
 
     pixel = gc->fgPixel;
@@ -189,7 +189,7 @@ glamor_set_tiled(PixmapPtr      pixmap,
     if (!glamor_set_alu(pixmap->drawable.pScreen, gc->alu))
         return FALSE;
 
-    if (!glamor_set_planemask(pixmap, gc->planemask))
+    if (!glamor_set_planemask(gc->depth, gc->planemask))
         return FALSE;
 
     return glamor_set_texture(pixmap,


More information about the xorg-commit mailing list