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