Home | History | Annotate | Line # | Download | only in glamor
      1 /*
      2  * Copyright  2014 Keith Packard
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that copyright
      7  * notice and this permission notice appear in supporting documentation, and
      8  * that the name of the copyright holders not be used in advertising or
      9  * publicity pertaining to distribution of the software without specific,
     10  * written prior permission.  The copyright holders make no representations
     11  * about the suitability of this software for any purpose.  It is provided "as
     12  * is" without express or implied warranty.
     13  *
     14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     20  * OF THIS SOFTWARE.
     21  */
     22 #include <stdlib.h>
     23 #include "Xprintf.h"
     24 
     25 #include "glamor_priv.h"
     26 #include "glamor_transform.h"
     27 #include "glamor_transfer.h"
     28 
     29 #include <mipict.h>
     30 
     31 #define DEFAULT_ATLAS_DIM       1024
     32 
     33 static DevPrivateKeyRec        glamor_glyph_private_key;
     34 
     35 struct glamor_glyph_private {
     36     int16_t     x;
     37     int16_t     y;
     38     uint32_t    serial;
     39 };
     40 
     41 struct glamor_glyph_atlas {
     42     PixmapPtr           atlas;
     43     PictFormatPtr       format;
     44     int                 x, y;
     45     int                 row_height;
     46     int                 nglyph;
     47     uint32_t            serial;
     48 };
     49 
     50 static inline struct glamor_glyph_private *glamor_get_glyph_private(PixmapPtr pixmap) {
     51     return dixLookupPrivate(&pixmap->devPrivates, &glamor_glyph_private_key);
     52 }
     53 
     54 static inline void
     55 glamor_copy_glyph(PixmapPtr     glyph_pixmap,
     56                   DrawablePtr   atlas_draw,
     57                   int16_t x,
     58                   int16_t y)
     59 {
     60     DrawablePtr glyph_draw = &glyph_pixmap->drawable;
     61     BoxRec      box = {
     62         .x1 = 0,
     63         .y1 = 0,
     64         .x2 = glyph_draw->width,
     65         .y2 = glyph_draw->height,
     66     };
     67     PixmapPtr upload_pixmap = glyph_pixmap;
     68 
     69     if (glyph_pixmap->drawable.bitsPerPixel != atlas_draw->bitsPerPixel) {
     70 
     71         /* If we're dealing with 1-bit glyphs, we copy them to a
     72          * temporary 8-bit pixmap and upload them from there, since
     73          * that's what GL can handle.
     74          */
     75         ScreenPtr       screen = atlas_draw->pScreen;
     76         GCPtr           scratch_gc;
     77         ChangeGCVal     changes[2];
     78 
     79         upload_pixmap = glamor_create_pixmap(screen,
     80                                              glyph_draw->width,
     81                                              glyph_draw->height,
     82                                              atlas_draw->depth,
     83                                              GLAMOR_CREATE_PIXMAP_CPU);
     84         if (!upload_pixmap)
     85             return;
     86 
     87         scratch_gc = GetScratchGC(upload_pixmap->drawable.depth, screen);
     88         if (!scratch_gc) {
     89             glamor_destroy_pixmap(upload_pixmap);
     90             return;
     91         }
     92         changes[0].val = 0xff;
     93         changes[1].val = 0x00;
     94         if (ChangeGC(NullClient, scratch_gc,
     95                      GCForeground|GCBackground, changes) != Success) {
     96             glamor_destroy_pixmap(upload_pixmap);
     97             FreeScratchGC(scratch_gc);
     98             return;
     99         }
    100         ValidateGC(&upload_pixmap->drawable, scratch_gc);
    101 
    102         (*scratch_gc->ops->CopyPlane)(glyph_draw,
    103                                       &upload_pixmap->drawable,
    104                                       scratch_gc,
    105                                       0, 0,
    106                                       glyph_draw->width,
    107                                       glyph_draw->height,
    108                                       0, 0, 0x1);
    109     }
    110     glamor_upload_boxes((PixmapPtr) atlas_draw,
    111                         &box, 1,
    112                         0, 0,
    113                         x, y,
    114                         upload_pixmap->devPrivate.ptr,
    115                         upload_pixmap->devKind);
    116 
    117     if (upload_pixmap != glyph_pixmap)
    118         glamor_destroy_pixmap(upload_pixmap);
    119 }
    120 
    121 static Bool
    122 glamor_glyph_atlas_init(ScreenPtr screen, struct glamor_glyph_atlas *atlas)
    123 {
    124     glamor_screen_private       *glamor_priv = glamor_get_screen_private(screen);
    125     PictFormatPtr               format = atlas->format;
    126 
    127     atlas->atlas = glamor_create_pixmap(screen, glamor_priv->glyph_atlas_dim,
    128                                         glamor_priv->glyph_atlas_dim, format->depth,
    129                                         GLAMOR_CREATE_FBO_NO_FBO);
    130     if (!glamor_pixmap_has_fbo(atlas->atlas)) {
    131         glamor_destroy_pixmap(atlas->atlas);
    132         atlas->atlas = NULL;
    133     }
    134     atlas->x = 0;
    135     atlas->y = 0;
    136     atlas->row_height = 0;
    137     atlas->serial++;
    138     atlas->nglyph = 0;
    139     return TRUE;
    140 }
    141 
    142 static Bool
    143 glamor_glyph_can_add(struct glamor_glyph_atlas *atlas, int dim, DrawablePtr glyph_draw)
    144 {
    145     /* Step down */
    146     if (atlas->x + glyph_draw->width > dim) {
    147         atlas->x = 0;
    148         atlas->y += atlas->row_height;
    149         atlas->row_height = 0;
    150     }
    151 
    152     /* Check for overfull */
    153     if (atlas->y + glyph_draw->height > dim)
    154         return FALSE;
    155 
    156     return TRUE;
    157 }
    158 
    159 static Bool
    160 glamor_glyph_add(struct glamor_glyph_atlas *atlas, DrawablePtr glyph_draw)
    161 {
    162     PixmapPtr                   glyph_pixmap = (PixmapPtr) glyph_draw;
    163     struct glamor_glyph_private *glyph_priv = glamor_get_glyph_private(glyph_pixmap);
    164 
    165     glamor_copy_glyph(glyph_pixmap, &atlas->atlas->drawable, atlas->x, atlas->y);
    166 
    167     glyph_priv->x = atlas->x;
    168     glyph_priv->y = atlas->y;
    169     glyph_priv->serial = atlas->serial;
    170 
    171     atlas->x += glyph_draw->width;
    172     if (atlas->row_height < glyph_draw->height)
    173         atlas->row_height = glyph_draw->height;
    174 
    175     atlas->nglyph++;
    176 
    177     return TRUE;
    178 }
    179 
    180 static const glamor_facet glamor_facet_composite_glyphs_es300 = {
    181     .name = "composite_glyphs",
    182     .version = 130,
    183     .fs_extensions = ("#extension GL_EXT_blend_func_extended : enable\n"),
    184     .vs_vars = ("in vec4 primitive;\n"
    185                 "in vec2 source;\n"
    186                 "out vec2 glyph_pos;\n"),
    187     .vs_exec = ("       vec2 pos = primitive.zw * vec2(gl_VertexID&1, (gl_VertexID&2)>>1);\n"
    188                 GLAMOR_POS(gl_Position, (primitive.xy + pos))
    189                 "       glyph_pos = (source + pos) * ATLAS_DIM_INV;\n"),
    190     .fs_vars = ("in vec2 glyph_pos;\n"
    191                 "out vec4 color0;\n"
    192                 "out vec4 color1;\n"),
    193     .fs_exec = ("       vec4 mask = texture(atlas, glyph_pos);\n"),
    194     .source_name = "source",
    195     .locations = glamor_program_location_atlas,
    196 };
    197 
    198 static const glamor_facet glamor_facet_composite_glyphs_130 = {
    199     .name = "composite_glyphs",
    200     .version = 130,
    201     .vs_vars = ("in vec4 primitive;\n"
    202                 "in vec2 source;\n"
    203                 "out vec2 glyph_pos;\n"),
    204     .vs_exec = ("       vec2 pos = primitive.zw * vec2(gl_VertexID&1, (gl_VertexID&2)>>1);\n"
    205                 GLAMOR_POS(gl_Position, (primitive.xy + pos))
    206                 "       glyph_pos = (source + pos) * ATLAS_DIM_INV;\n"),
    207     .fs_vars = ("in vec2 glyph_pos;\n"
    208                 "out vec4 color0;\n"
    209                 "out vec4 color1;\n"),
    210     .fs_exec = ("       vec4 mask = texture(atlas, glyph_pos);\n"),
    211     .source_name = "source",
    212     .locations = glamor_program_location_atlas,
    213 };
    214 
    215 static const glamor_facet glamor_facet_composite_glyphs_120 = {
    216     .name = "composite_glyphs",
    217     .vs_vars = ("attribute vec2 primitive;\n"
    218                 "attribute vec2 source;\n"
    219                 "varying vec2 glyph_pos;\n"),
    220     .vs_exec = ("       vec2 pos = vec2(0,0);\n"
    221                 GLAMOR_POS(gl_Position, primitive.xy)
    222                 "       glyph_pos = source.xy * ATLAS_DIM_INV;\n"),
    223     .fs_vars = ("varying vec2 glyph_pos;\n"),
    224     .fs_exec = ("       vec4 mask = texture2D(atlas, glyph_pos);\n"),
    225     .source_name = "source",
    226     .locations = glamor_program_location_atlas,
    227 };
    228 
    229 static const glamor_facet glamor_facet_composite_glyphs_gles2 = {
    230     .name = "composite_glyphs",
    231     .version = 100,
    232     .fs_extensions = ("#extension GL_EXT_blend_func_extended : enable\n"),
    233     .vs_vars = ("attribute vec2 primitive;\n"
    234                 "attribute vec2 source;\n"
    235                 "varying vec2 glyph_pos;\n"),
    236     .vs_exec = ("       vec2 pos = vec2(0,0);\n"
    237                 GLAMOR_POS(gl_Position, primitive.xy)
    238                 "       glyph_pos = source.xy * ATLAS_DIM_INV;\n"),
    239     .fs_vars = ("varying vec2 glyph_pos;\n"),
    240     .fs_exec = ("       vec4 mask = texture2D(atlas, glyph_pos);\n"),
    241     .source_name = "source",
    242     .locations = glamor_program_location_atlas,
    243 };
    244 
    245 static Bool
    246 glamor_glyphs_init_facet(ScreenPtr screen)
    247 {
    248     glamor_screen_private       *glamor_priv = glamor_get_screen_private(screen);
    249 
    250     return asprintf(&glamor_priv->glyph_defines, "#define ATLAS_DIM_INV %20.18f\n", 1.0/glamor_priv->glyph_atlas_dim) > 0;
    251 }
    252 
    253 static void
    254 glamor_glyphs_fini_facet(ScreenPtr screen)
    255 {
    256     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    257 
    258     free(glamor_priv->glyph_defines);
    259 }
    260 
    261 static void
    262 glamor_glyphs_flush(CARD8 op, PicturePtr src, PicturePtr dst,
    263                    glamor_program *prog,
    264                    struct glamor_glyph_atlas *atlas, int nglyph)
    265 {
    266     DrawablePtr drawable = dst->pDrawable;
    267     glamor_screen_private *glamor_priv = glamor_get_screen_private(drawable->pScreen);
    268     PixmapPtr atlas_pixmap = atlas->atlas;
    269     glamor_pixmap_private *atlas_priv = glamor_get_pixmap_private(atlas_pixmap);
    270     glamor_pixmap_fbo *atlas_fbo = glamor_pixmap_fbo_at(atlas_priv, 0);
    271     PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
    272     glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
    273     int box_index;
    274     int off_x, off_y;
    275 
    276     glamor_put_vbo_space(drawable->pScreen);
    277 
    278     glEnable(GL_SCISSOR_TEST);
    279     glamor_bind_texture(glamor_priv, GL_TEXTURE1, atlas_fbo, FALSE);
    280 
    281     for (;;) {
    282         if (!glamor_use_program_render(prog, op, src, dst))
    283             break;
    284 
    285         glUniform1i(prog->atlas_uniform, 1);
    286 
    287         glamor_pixmap_loop(pixmap_priv, box_index) {
    288             BoxPtr box = RegionRects(dst->pCompositeClip);
    289             int nbox = RegionNumRects(dst->pCompositeClip);
    290 
    291             glamor_set_destination_drawable(drawable, box_index, TRUE, FALSE,
    292                                             prog->matrix_uniform,
    293                                             &off_x, &off_y);
    294 
    295             /* Run over the clip list, drawing the glyphs
    296              * in each box
    297              */
    298 
    299             while (nbox--) {
    300                 glScissor(box->x1 + off_x,
    301                           box->y1 + off_y,
    302                           box->x2 - box->x1,
    303                           box->y2 - box->y1);
    304                 box++;
    305 
    306                 if (glamor_glsl_has_ints(glamor_priv))
    307                     glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nglyph);
    308                 else
    309                     glamor_glDrawArrays_GL_QUADS(glamor_priv, nglyph);
    310             }
    311         }
    312         if (prog->alpha != glamor_program_alpha_ca_first)
    313             break;
    314         prog++;
    315     }
    316 
    317     glDisable(GL_SCISSOR_TEST);
    318 
    319     if (glamor_glsl_has_ints(glamor_priv)) {
    320         glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0);
    321         glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);
    322     }
    323     glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
    324     glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
    325     glDisable(GL_BLEND);
    326 }
    327 
    328 static GLshort *
    329 glamor_glyph_start(ScreenPtr screen, int count)
    330 {
    331     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    332     GLshort *v;
    333     char *vbo_offset;
    334 
    335     /* Set up the vertex buffers for the font and destination */
    336 
    337     if (glamor_glsl_has_ints(glamor_priv)) {
    338         v = glamor_get_vbo_space(screen, count * (6 * sizeof (GLshort)), &vbo_offset);
    339 
    340         glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
    341         glVertexAttribDivisor(GLAMOR_VERTEX_POS, 1);
    342         glVertexAttribPointer(GLAMOR_VERTEX_POS, 4, GL_SHORT, GL_FALSE,
    343                               6 * sizeof (GLshort), vbo_offset);
    344 
    345         glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
    346         glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 1);
    347         glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_SHORT, GL_FALSE,
    348                               6 * sizeof (GLshort), vbo_offset + 4 * sizeof (GLshort));
    349     } else {
    350         v = glamor_get_vbo_space(screen, count * (16 * sizeof (GLshort)), &vbo_offset);
    351 
    352         glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
    353         glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
    354                               4 * sizeof (GLshort), vbo_offset);
    355 
    356         glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
    357         glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_SHORT, GL_FALSE,
    358                               4 * sizeof (GLshort), vbo_offset + 2 * sizeof (GLshort));
    359     }
    360     return v;
    361 }
    362 
    363 static inline struct glamor_glyph_atlas *
    364 glamor_atlas_for_glyph(glamor_screen_private *glamor_priv, DrawablePtr drawable)
    365 {
    366     if (drawable->depth == 32)
    367         return glamor_priv->glyph_atlas_argb;
    368     else
    369         return glamor_priv->glyph_atlas_a;
    370 }
    371 
    372 void
    373 glamor_composite_glyphs(CARD8 op,
    374                         PicturePtr src,
    375                         PicturePtr dst,
    376                         PictFormatPtr glyph_format,
    377                         INT16 x_src,
    378                         INT16 y_src, int nlist, GlyphListPtr list,
    379                         GlyphPtr *glyphs)
    380 {
    381     int glyphs_queued;
    382     GLshort *v = NULL;
    383     DrawablePtr drawable = dst->pDrawable;
    384     ScreenPtr screen = drawable->pScreen;
    385     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    386     glamor_program *prog = NULL;
    387     glamor_program_render       *glyphs_program = &glamor_priv->glyphs_program;
    388     struct glamor_glyph_atlas    *glyph_atlas = NULL;
    389     int x = 0, y = 0;
    390     int n;
    391     int glyph_atlas_dim = glamor_priv->glyph_atlas_dim;
    392     int glyph_max_dim = glamor_priv->glyph_max_dim;
    393     int nglyph = 0;
    394     int screen_num = screen->myNum;
    395 
    396     for (n = 0; n < nlist; n++)
    397         nglyph += list[n].len;
    398 
    399     glamor_make_current(glamor_priv);
    400 
    401     glyphs_queued = 0;
    402 
    403     while (nlist--) {
    404         x += list->xOff;
    405         y += list->yOff;
    406         n = list->len;
    407         list++;
    408         while (n--) {
    409             GlyphPtr glyph = *glyphs++;
    410 
    411             /* Glyph not empty?
    412              */
    413             if (glyph->info.width && glyph->info.height) {
    414                 PicturePtr glyph_pict = GlyphPicture(glyph)[screen_num];
    415                 DrawablePtr glyph_draw = glyph_pict->pDrawable;
    416 
    417                 /* Need to draw with slow path?
    418                  */
    419                 if (_X_UNLIKELY(glyph_draw->width > glyph_max_dim ||
    420                                 glyph_draw->height > glyph_max_dim ||
    421                                 !glamor_pixmap_is_memory((PixmapPtr)glyph_draw)))
    422                 {
    423                     if (glyphs_queued) {
    424                         glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued);
    425                         glyphs_queued = 0;
    426                     }
    427                 bail_one:
    428                     glamor_composite(op, src, glyph_pict, dst,
    429                                      x_src + (x - glyph->info.x), (y - glyph->info.y),
    430                                      0, 0,
    431                                      x - glyph->info.x, y - glyph->info.y,
    432                                      glyph_draw->width, glyph_draw->height);
    433                 } else {
    434                     struct glamor_glyph_private *glyph_priv = glamor_get_glyph_private((PixmapPtr)(glyph_draw));
    435                     struct glamor_glyph_atlas *next_atlas = glamor_atlas_for_glyph(glamor_priv, glyph_draw);
    436 
    437                     /* Switching source glyph format?
    438                      */
    439                     if (_X_UNLIKELY(next_atlas != glyph_atlas)) {
    440                         if (glyphs_queued) {
    441                             glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued);
    442                             glyphs_queued = 0;
    443                         }
    444                         glyph_atlas = next_atlas;
    445                     }
    446 
    447                     /* Glyph not cached in current atlas?
    448                      */
    449                     if (_X_UNLIKELY(glyph_priv->serial != glyph_atlas->serial)) {
    450                         if (!glamor_glyph_can_add(glyph_atlas, glyph_atlas_dim, glyph_draw)) {
    451                             if (glyphs_queued) {
    452                                 glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued);
    453                                 glyphs_queued = 0;
    454                             }
    455                             if (glyph_atlas->atlas) {
    456                                 (*screen->DestroyPixmap)(glyph_atlas->atlas);
    457                                 glyph_atlas->atlas = NULL;
    458                             }
    459                         }
    460                         if (!glyph_atlas->atlas) {
    461                             glamor_glyph_atlas_init(screen, glyph_atlas);
    462                             if (!glyph_atlas->atlas)
    463                                 goto bail_one;
    464                         }
    465                         glamor_glyph_add(glyph_atlas, glyph_draw);
    466                     }
    467 
    468                     /* First glyph in the current atlas?
    469                      */
    470                     if (_X_UNLIKELY(glyphs_queued == 0)) {
    471                         if (glamor_glsl_has_ints(glamor_priv))
    472                             prog = glamor_setup_program_render(op, src, glyph_pict, dst,
    473                                                                glyphs_program,
    474                                                                glamor_priv->is_gles ?
    475                                                                    &glamor_facet_composite_glyphs_es300 :
    476                                                                    &glamor_facet_composite_glyphs_130,
    477                                                                glamor_priv->glyph_defines);
    478                         else
    479                             prog = glamor_setup_program_render(op, src, glyph_pict, dst,
    480                                                                glyphs_program,
    481                                                                glamor_priv->has_dual_blend ?
    482                                                                    &glamor_facet_composite_glyphs_gles2 :
    483                                                                    &glamor_facet_composite_glyphs_120,
    484                                                                glamor_priv->glyph_defines);
    485                         if (!prog)
    486                             goto bail_one;
    487                         v = glamor_glyph_start(screen, nglyph);
    488                     }
    489 
    490                     /* Add the glyph
    491                      */
    492 
    493                     glyphs_queued++;
    494                     if (_X_LIKELY(glamor_glsl_has_ints(glamor_priv))) {
    495                         v[0] = x - glyph->info.x;
    496                         v[1] = y - glyph->info.y;
    497                         v[2] = glyph_draw->width;
    498                         v[3] = glyph_draw->height;
    499                         v[4] = glyph_priv->x;
    500                         v[5] = glyph_priv->y;
    501                         v += 6;
    502                     } else {
    503                         v[0] = x - glyph->info.x;
    504                         v[1] = y - glyph->info.y;
    505                         v[2] = glyph_priv->x;
    506                         v[3] = glyph_priv->y;
    507                         v += 4;
    508 
    509                         v[0] = x - glyph->info.x + glyph_draw->width;
    510                         v[1] = y - glyph->info.y;
    511                         v[2] = glyph_priv->x + glyph_draw->width;
    512                         v[3] = glyph_priv->y;
    513                         v += 4;
    514 
    515                         v[0] = x - glyph->info.x + glyph_draw->width;
    516                         v[1] = y - glyph->info.y + glyph_draw->height;
    517                         v[2] = glyph_priv->x + glyph_draw->width;
    518                         v[3] = glyph_priv->y + glyph_draw->height;
    519                         v += 4;
    520 
    521                         v[0] = x - glyph->info.x;
    522                         v[1] = y - glyph->info.y + glyph_draw->height;
    523                         v[2] = glyph_priv->x;
    524                         v[3] = glyph_priv->y + glyph_draw->height;
    525                         v += 4;
    526                     }
    527                 }
    528             }
    529             x += glyph->info.xOff;
    530             y += glyph->info.yOff;
    531             nglyph--;
    532         }
    533     }
    534 
    535     if (glyphs_queued)
    536         glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued);
    537 
    538     return;
    539 }
    540 
    541 static struct glamor_glyph_atlas *
    542 glamor_alloc_glyph_atlas(ScreenPtr screen, int depth, CARD32 f)
    543 {
    544     PictFormatPtr               format;
    545     struct glamor_glyph_atlas    *glyph_atlas;
    546 
    547     format = PictureMatchFormat(screen, depth, f);
    548     if (!format)
    549         return NULL;
    550     glyph_atlas = calloc (1, sizeof (struct glamor_glyph_atlas));
    551     if (!glyph_atlas)
    552         return NULL;
    553     glyph_atlas->format = format;
    554     glyph_atlas->serial = 1;
    555 
    556     return glyph_atlas;
    557 }
    558 
    559 Bool
    560 glamor_composite_glyphs_init(ScreenPtr screen)
    561 {
    562     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    563 
    564     if (!dixRegisterPrivateKey(&glamor_glyph_private_key, PRIVATE_PIXMAP, sizeof (struct glamor_glyph_private)))
    565         return FALSE;
    566 
    567     /* Make glyph atlases of a reasonable size, but no larger than the maximum
    568      * supported by the hardware
    569      */
    570     glamor_priv->glyph_atlas_dim = MIN(DEFAULT_ATLAS_DIM, glamor_priv->max_fbo_size);
    571 
    572     /* Don't stick huge glyphs in the atlases */
    573     glamor_priv->glyph_max_dim = glamor_priv->glyph_atlas_dim / 8;
    574 
    575     glamor_priv->glyph_atlas_a = glamor_alloc_glyph_atlas(screen, 8, PICT_a8);
    576     if (!glamor_priv->glyph_atlas_a)
    577         return FALSE;
    578     glamor_priv->glyph_atlas_argb = glamor_alloc_glyph_atlas(screen, 32, PICT_a8r8g8b8);
    579     if (!glamor_priv->glyph_atlas_argb) {
    580         free (glamor_priv->glyph_atlas_a);
    581         return FALSE;
    582     }
    583     if (!glamor_glyphs_init_facet(screen))
    584         return FALSE;
    585     return TRUE;
    586 }
    587 
    588 static void
    589 glamor_free_glyph_atlas(struct glamor_glyph_atlas *atlas)
    590 {
    591     if (!atlas)
    592         return;
    593     if (atlas->atlas)
    594         (*atlas->atlas->drawable.pScreen->DestroyPixmap)(atlas->atlas);
    595     free (atlas);
    596 }
    597 
    598 void
    599 glamor_composite_glyphs_fini(ScreenPtr screen)
    600 {
    601     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    602 
    603     glamor_glyphs_fini_facet(screen);
    604     glamor_free_glyph_atlas(glamor_priv->glyph_atlas_a);
    605     glamor_free_glyph_atlas(glamor_priv->glyph_atlas_argb);
    606 }
    607