xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

glamor_composite_glyphs.c (20931B)


      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_130 = {
    181     .name = "composite_glyphs",
    182     .version = 130,
    183     .vs_vars = ("attribute vec4 primitive;\n"
    184                 "attribute vec2 source;\n"
    185                 "varying vec2 glyph_pos;\n"),
    186     .vs_exec = ("       vec2 pos = primitive.zw * vec2(gl_VertexID&1, (gl_VertexID&2)>>1);\n"
    187                 GLAMOR_POS(gl_Position, (primitive.xy + pos))
    188                 "       glyph_pos = (source + pos) * ATLAS_DIM_INV;\n"),
    189     .fs_vars = ("varying vec2 glyph_pos;\n"
    190                 "out vec4 color0;\n"
    191                 "out vec4 color1;\n"),
    192     .fs_exec = ("       vec4 mask = texture2D(atlas, glyph_pos);\n"),
    193     .source_name = "source",
    194     .locations = glamor_program_location_atlas,
    195 };
    196 
    197 static const glamor_facet glamor_facet_composite_glyphs_120 = {
    198     .name = "composite_glyphs",
    199     .vs_vars = ("attribute vec2 primitive;\n"
    200                 "attribute vec2 source;\n"
    201                 "varying vec2 glyph_pos;\n"),
    202     .vs_exec = ("       vec2 pos = vec2(0,0);\n"
    203                 GLAMOR_POS(gl_Position, primitive.xy)
    204                 "       glyph_pos = source.xy * ATLAS_DIM_INV;\n"),
    205     .fs_vars = ("varying vec2 glyph_pos;\n"),
    206     .fs_exec = ("       vec4 mask = texture2D(atlas, glyph_pos);\n"),
    207     .source_name = "source",
    208     .locations = glamor_program_location_atlas,
    209 };
    210 
    211 static Bool
    212 glamor_glyphs_init_facet(ScreenPtr screen)
    213 {
    214     glamor_screen_private       *glamor_priv = glamor_get_screen_private(screen);
    215 
    216     return asprintf(&glamor_priv->glyph_defines, "#define ATLAS_DIM_INV %20.18f\n", 1.0/glamor_priv->glyph_atlas_dim) > 0;
    217 }
    218 
    219 static void
    220 glamor_glyphs_fini_facet(ScreenPtr screen)
    221 {
    222     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    223 
    224     free(glamor_priv->glyph_defines);
    225 }
    226 
    227 static void
    228 glamor_glyphs_flush(CARD8 op, PicturePtr src, PicturePtr dst,
    229                    glamor_program *prog,
    230                    struct glamor_glyph_atlas *atlas, int nglyph)
    231 {
    232     DrawablePtr drawable = dst->pDrawable;
    233     glamor_screen_private *glamor_priv = glamor_get_screen_private(drawable->pScreen);
    234     PixmapPtr atlas_pixmap = atlas->atlas;
    235     glamor_pixmap_private *atlas_priv = glamor_get_pixmap_private(atlas_pixmap);
    236     glamor_pixmap_fbo *atlas_fbo = glamor_pixmap_fbo_at(atlas_priv, 0);
    237     PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
    238     glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
    239     int box_index;
    240     int off_x, off_y;
    241 
    242     glamor_put_vbo_space(drawable->pScreen);
    243 
    244     glEnable(GL_SCISSOR_TEST);
    245     glamor_bind_texture(glamor_priv, GL_TEXTURE1, atlas_fbo, FALSE);
    246 
    247     for (;;) {
    248         if (!glamor_use_program_render(prog, op, src, dst))
    249             break;
    250 
    251         glUniform1i(prog->atlas_uniform, 1);
    252 
    253         glamor_pixmap_loop(pixmap_priv, box_index) {
    254             BoxPtr box = RegionRects(dst->pCompositeClip);
    255             int nbox = RegionNumRects(dst->pCompositeClip);
    256 
    257             glamor_set_destination_drawable(drawable, box_index, TRUE, FALSE,
    258                                             prog->matrix_uniform,
    259                                             &off_x, &off_y);
    260 
    261             /* Run over the clip list, drawing the glyphs
    262              * in each box
    263              */
    264 
    265             while (nbox--) {
    266                 glScissor(box->x1 + off_x,
    267                           box->y1 + off_y,
    268                           box->x2 - box->x1,
    269                           box->y2 - box->y1);
    270                 box++;
    271 
    272                 if (glamor_glsl_has_ints(glamor_priv))
    273                     glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nglyph);
    274                 else
    275                     glamor_glDrawArrays_GL_QUADS(glamor_priv, nglyph);
    276             }
    277         }
    278         if (prog->alpha != glamor_program_alpha_ca_first)
    279             break;
    280         prog++;
    281     }
    282 
    283     glDisable(GL_SCISSOR_TEST);
    284 
    285     if (glamor_glsl_has_ints(glamor_priv)) {
    286         glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0);
    287         glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);
    288     }
    289     glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
    290     glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
    291     glDisable(GL_BLEND);
    292 }
    293 
    294 static GLshort *
    295 glamor_glyph_start(ScreenPtr screen, int count)
    296 {
    297     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    298     GLshort *v;
    299     char *vbo_offset;
    300 
    301     /* Set up the vertex buffers for the font and destination */
    302 
    303     if (glamor_glsl_has_ints(glamor_priv)) {
    304         v = glamor_get_vbo_space(screen, count * (6 * sizeof (GLshort)), &vbo_offset);
    305 
    306         glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
    307         glVertexAttribDivisor(GLAMOR_VERTEX_POS, 1);
    308         glVertexAttribPointer(GLAMOR_VERTEX_POS, 4, GL_SHORT, GL_FALSE,
    309                               6 * sizeof (GLshort), vbo_offset);
    310 
    311         glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
    312         glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 1);
    313         glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_SHORT, GL_FALSE,
    314                               6 * sizeof (GLshort), vbo_offset + 4 * sizeof (GLshort));
    315     } else {
    316         v = glamor_get_vbo_space(screen, count * (16 * sizeof (GLshort)), &vbo_offset);
    317 
    318         glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
    319         glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
    320                               4 * sizeof (GLshort), vbo_offset);
    321 
    322         glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
    323         glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_SHORT, GL_FALSE,
    324                               4 * sizeof (GLshort), vbo_offset + 2 * sizeof (GLshort));
    325     }
    326     return v;
    327 }
    328 
    329 static inline struct glamor_glyph_atlas *
    330 glamor_atlas_for_glyph(glamor_screen_private *glamor_priv, DrawablePtr drawable)
    331 {
    332     if (drawable->depth == 32)
    333         return glamor_priv->glyph_atlas_argb;
    334     else
    335         return glamor_priv->glyph_atlas_a;
    336 }
    337 
    338 void
    339 glamor_composite_glyphs(CARD8 op,
    340                         PicturePtr src,
    341                         PicturePtr dst,
    342                         PictFormatPtr glyph_format,
    343                         INT16 x_src,
    344                         INT16 y_src, int nlist, GlyphListPtr list,
    345                         GlyphPtr *glyphs)
    346 {
    347     int glyphs_queued;
    348     GLshort *v = NULL;
    349     DrawablePtr drawable = dst->pDrawable;
    350     ScreenPtr screen = drawable->pScreen;
    351     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    352     glamor_program *prog = NULL;
    353     glamor_program_render       *glyphs_program = &glamor_priv->glyphs_program;
    354     struct glamor_glyph_atlas    *glyph_atlas = NULL;
    355     int x = 0, y = 0;
    356     int n;
    357     int glyph_atlas_dim = glamor_priv->glyph_atlas_dim;
    358     int glyph_max_dim = glamor_priv->glyph_max_dim;
    359     int nglyph = 0;
    360     int screen_num = screen->myNum;
    361 
    362     for (n = 0; n < nlist; n++)
    363         nglyph += list[n].len;
    364 
    365     glamor_make_current(glamor_priv);
    366 
    367     glyphs_queued = 0;
    368 
    369     while (nlist--) {
    370         x += list->xOff;
    371         y += list->yOff;
    372         n = list->len;
    373         list++;
    374         while (n--) {
    375             GlyphPtr glyph = *glyphs++;
    376 
    377             /* Glyph not empty?
    378              */
    379             if (glyph->info.width && glyph->info.height) {
    380                 PicturePtr glyph_pict = GlyphPicture(glyph)[screen_num];
    381                 DrawablePtr glyph_draw = glyph_pict->pDrawable;
    382 
    383                 /* Need to draw with slow path?
    384                  */
    385                 if (_X_UNLIKELY(glyph_draw->width > glyph_max_dim ||
    386                                 glyph_draw->height > glyph_max_dim ||
    387                                 !glamor_pixmap_is_memory((PixmapPtr)glyph_draw)))
    388                 {
    389                     if (glyphs_queued) {
    390                         glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued);
    391                         glyphs_queued = 0;
    392                     }
    393                 bail_one:
    394                     glamor_composite(op, src, glyph_pict, dst,
    395                                      x_src + (x - glyph->info.x), (y - glyph->info.y),
    396                                      0, 0,
    397                                      x - glyph->info.x, y - glyph->info.y,
    398                                      glyph_draw->width, glyph_draw->height);
    399                 } else {
    400                     struct glamor_glyph_private *glyph_priv = glamor_get_glyph_private((PixmapPtr)(glyph_draw));
    401                     struct glamor_glyph_atlas *next_atlas = glamor_atlas_for_glyph(glamor_priv, glyph_draw);
    402 
    403                     /* Switching source glyph format?
    404                      */
    405                     if (_X_UNLIKELY(next_atlas != glyph_atlas)) {
    406                         if (glyphs_queued) {
    407                             glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued);
    408                             glyphs_queued = 0;
    409                         }
    410                         glyph_atlas = next_atlas;
    411                     }
    412 
    413                     /* Glyph not cached in current atlas?
    414                      */
    415                     if (_X_UNLIKELY(glyph_priv->serial != glyph_atlas->serial)) {
    416                         if (!glamor_glyph_can_add(glyph_atlas, glyph_atlas_dim, glyph_draw)) {
    417                             if (glyphs_queued) {
    418                                 glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued);
    419                                 glyphs_queued = 0;
    420                             }
    421                             if (glyph_atlas->atlas) {
    422                                 (*screen->DestroyPixmap)(glyph_atlas->atlas);
    423                                 glyph_atlas->atlas = NULL;
    424                             }
    425                         }
    426                         if (!glyph_atlas->atlas) {
    427                             glamor_glyph_atlas_init(screen, glyph_atlas);
    428                             if (!glyph_atlas->atlas)
    429                                 goto bail_one;
    430                         }
    431                         glamor_glyph_add(glyph_atlas, glyph_draw);
    432                     }
    433 
    434                     /* First glyph in the current atlas?
    435                      */
    436                     if (_X_UNLIKELY(glyphs_queued == 0)) {
    437                         if (glamor_glsl_has_ints(glamor_priv))
    438                             prog = glamor_setup_program_render(op, src, glyph_pict, dst,
    439                                                                glyphs_program,
    440                                                                &glamor_facet_composite_glyphs_130,
    441                                                                glamor_priv->glyph_defines);
    442                         else
    443                             prog = glamor_setup_program_render(op, src, glyph_pict, dst,
    444                                                                glyphs_program,
    445                                                                &glamor_facet_composite_glyphs_120,
    446                                                                glamor_priv->glyph_defines);
    447                         if (!prog)
    448                             goto bail_one;
    449                         v = glamor_glyph_start(screen, nglyph);
    450                     }
    451 
    452                     /* Add the glyph
    453                      */
    454 
    455                     glyphs_queued++;
    456                     if (_X_LIKELY(glamor_glsl_has_ints(glamor_priv))) {
    457                         v[0] = x - glyph->info.x;
    458                         v[1] = y - glyph->info.y;
    459                         v[2] = glyph_draw->width;
    460                         v[3] = glyph_draw->height;
    461                         v[4] = glyph_priv->x;
    462                         v[5] = glyph_priv->y;
    463                         v += 6;
    464                     } else {
    465                         v[0] = x - glyph->info.x;
    466                         v[1] = y - glyph->info.y;
    467                         v[2] = glyph_priv->x;
    468                         v[3] = glyph_priv->y;
    469                         v += 4;
    470 
    471                         v[0] = x - glyph->info.x + glyph_draw->width;
    472                         v[1] = y - glyph->info.y;
    473                         v[2] = glyph_priv->x + glyph_draw->width;
    474                         v[3] = glyph_priv->y;
    475                         v += 4;
    476 
    477                         v[0] = x - glyph->info.x + glyph_draw->width;
    478                         v[1] = y - glyph->info.y + glyph_draw->height;
    479                         v[2] = glyph_priv->x + glyph_draw->width;
    480                         v[3] = glyph_priv->y + glyph_draw->height;
    481                         v += 4;
    482 
    483                         v[0] = x - glyph->info.x;
    484                         v[1] = y - glyph->info.y + glyph_draw->height;
    485                         v[2] = glyph_priv->x;
    486                         v[3] = glyph_priv->y + glyph_draw->height;
    487                         v += 4;
    488                     }
    489                 }
    490             }
    491             x += glyph->info.xOff;
    492             y += glyph->info.yOff;
    493             nglyph--;
    494         }
    495     }
    496 
    497     if (glyphs_queued)
    498         glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued);
    499 
    500     return;
    501 }
    502 
    503 static struct glamor_glyph_atlas *
    504 glamor_alloc_glyph_atlas(ScreenPtr screen, int depth, CARD32 f)
    505 {
    506     PictFormatPtr               format;
    507     struct glamor_glyph_atlas    *glyph_atlas;
    508 
    509     format = PictureMatchFormat(screen, depth, f);
    510     if (!format)
    511         return NULL;
    512     glyph_atlas = calloc (1, sizeof (struct glamor_glyph_atlas));
    513     if (!glyph_atlas)
    514         return NULL;
    515     glyph_atlas->format = format;
    516     glyph_atlas->serial = 1;
    517 
    518     return glyph_atlas;
    519 }
    520 
    521 Bool
    522 glamor_composite_glyphs_init(ScreenPtr screen)
    523 {
    524     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    525 
    526     if (!dixRegisterPrivateKey(&glamor_glyph_private_key, PRIVATE_PIXMAP, sizeof (struct glamor_glyph_private)))
    527         return FALSE;
    528 
    529     /* Make glyph atlases of a reasonable size, but no larger than the maximum
    530      * supported by the hardware
    531      */
    532     glamor_priv->glyph_atlas_dim = MIN(DEFAULT_ATLAS_DIM, glamor_priv->max_fbo_size);
    533 
    534     /* Don't stick huge glyphs in the atlases */
    535     glamor_priv->glyph_max_dim = glamor_priv->glyph_atlas_dim / 8;
    536 
    537     glamor_priv->glyph_atlas_a = glamor_alloc_glyph_atlas(screen, 8, PICT_a8);
    538     if (!glamor_priv->glyph_atlas_a)
    539         return FALSE;
    540     glamor_priv->glyph_atlas_argb = glamor_alloc_glyph_atlas(screen, 32, PICT_a8r8g8b8);
    541     if (!glamor_priv->glyph_atlas_argb) {
    542         free (glamor_priv->glyph_atlas_a);
    543         return FALSE;
    544     }
    545     if (!glamor_glyphs_init_facet(screen))
    546         return FALSE;
    547     return TRUE;
    548 }
    549 
    550 static void
    551 glamor_free_glyph_atlas(struct glamor_glyph_atlas *atlas)
    552 {
    553     if (!atlas)
    554         return;
    555     if (atlas->atlas)
    556         (*atlas->atlas->drawable.pScreen->DestroyPixmap)(atlas->atlas);
    557     free (atlas);
    558 }
    559 
    560 void
    561 glamor_composite_glyphs_fini(ScreenPtr screen)
    562 {
    563     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    564 
    565     glamor_glyphs_fini_facet(screen);
    566     glamor_free_glyph_atlas(glamor_priv->glyph_atlas_a);
    567     glamor_free_glyph_atlas(glamor_priv->glyph_atlas_argb);
    568 }