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