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