6e1bcfb3c6
tested by krw@ and dcoppa@ ok dcoppa@
573 lines
20 KiB
C
573 lines
20 KiB
C
/*
|
|
* 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,
|
|
};
|
|
PixmapPtr upload_pixmap = glyph_pixmap;
|
|
|
|
if (glyph_pixmap->drawable.bitsPerPixel != atlas_draw->bitsPerPixel) {
|
|
|
|
/* If we're dealing with 1-bit glyphs, we copy them to a
|
|
* temporary 8-bit pixmap and upload them from there, since
|
|
* that's what GL can handle.
|
|
*/
|
|
ScreenPtr screen = atlas_draw->pScreen;
|
|
GCPtr scratch_gc;
|
|
ChangeGCVal changes[2];
|
|
|
|
upload_pixmap = glamor_create_pixmap(screen,
|
|
glyph_draw->width,
|
|
glyph_draw->height,
|
|
atlas_draw->depth,
|
|
GLAMOR_CREATE_PIXMAP_CPU);
|
|
if (!upload_pixmap)
|
|
return;
|
|
|
|
scratch_gc = GetScratchGC(upload_pixmap->drawable.depth, screen);
|
|
if (!scratch_gc) {
|
|
glamor_destroy_pixmap(upload_pixmap);
|
|
return;
|
|
}
|
|
changes[0].val = 0xff;
|
|
changes[1].val = 0x00;
|
|
if (ChangeGC(NullClient, scratch_gc,
|
|
GCForeground|GCBackground, changes) != Success) {
|
|
glamor_destroy_pixmap(upload_pixmap);
|
|
FreeScratchGC(scratch_gc);
|
|
return;
|
|
}
|
|
ValidateGC(&upload_pixmap->drawable, scratch_gc);
|
|
|
|
(*scratch_gc->ops->CopyPlane)(glyph_draw,
|
|
&upload_pixmap->drawable,
|
|
scratch_gc,
|
|
0, 0,
|
|
glyph_draw->width,
|
|
glyph_draw->height,
|
|
0, 0, 0x1);
|
|
}
|
|
glamor_upload_boxes((PixmapPtr) atlas_draw,
|
|
&box, 1,
|
|
0, 0,
|
|
x, y,
|
|
upload_pixmap->devPrivate.ptr,
|
|
upload_pixmap->devKind);
|
|
|
|
if (upload_pixmap != glyph_pixmap)
|
|
glamor_destroy_pixmap(upload_pixmap);
|
|
}
|
|
|
|
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,
|
|
GLAMOR_CREATE_FBO_NO_FBO);
|
|
if (!glamor_pixmap_has_fbo(atlas->atlas)) {
|
|
glamor_destroy_pixmap(atlas->atlas);
|
|
atlas->atlas = NULL;
|
|
}
|
|
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"
|
|
"out vec4 color0;\n"
|
|
"out vec4 color1;\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);
|
|
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
|
|
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
|
|
int box_index;
|
|
int off_x, off_y;
|
|
|
|
glamor_put_vbo_space(drawable->pScreen);
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
glamor_bind_texture(glamor_priv, GL_TEXTURE1, atlas_fbo, FALSE);
|
|
|
|
for (;;) {
|
|
if (!glamor_use_program_render(prog, op, src, dst))
|
|
break;
|
|
|
|
glUniform1i(prog->atlas_uniform, 1);
|
|
|
|
glamor_pixmap_loop(pixmap_priv, box_index) {
|
|
BoxPtr box = RegionRects(dst->pCompositeClip);
|
|
int nbox = RegionNumRects(dst->pCompositeClip);
|
|
|
|
glamor_set_destination_drawable(drawable, box_index, 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);
|
|
}
|
|
}
|
|
if (prog->alpha != glamor_program_alpha_ca_first)
|
|
break;
|
|
prog++;
|
|
}
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
if (glamor_glyph_use_130(glamor_priv)) {
|
|
glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0);
|
|
glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);
|
|
}
|
|
glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
|
|
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;
|
|
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) {
|
|
PicturePtr glyph_pict = GlyphPicture(glyph)[screen_num];
|
|
DrawablePtr glyph_draw = glyph_pict->pDrawable;
|
|
|
|
/* Need to draw with slow path?
|
|
*/
|
|
if (_X_UNLIKELY(glyph_draw->width > glyph_max_dim ||
|
|
glyph_draw->height > glyph_max_dim ||
|
|
!glamor_pixmap_is_memory((PixmapPtr)glyph_draw)))
|
|
{
|
|
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);
|
|
if (!glyph_atlas->atlas)
|
|
goto bail_one;
|
|
}
|
|
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)
|
|
(*atlas->atlas->drawable.pScreen->DestroyPixmap)(atlas->atlas);
|
|
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);
|
|
}
|