xref: /OK3568_Linux_fs/external/xserver/glamor/glamor_glyphblt.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright © 2009 Intel Corporation
3  * Copyright © 1998 Keith Packard
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Zhigang Gong <zhigang.gong@gmail.com>
26  *
27  */
28 
29 #include "glamor_priv.h"
30 #include <dixfontstr.h>
31 #include "glamor_transform.h"
32 
33 static const glamor_facet glamor_facet_poly_glyph_blt = {
34     .name = "poly_glyph_blt",
35     .vs_vars = "attribute vec2 primitive;\n",
36     .vs_exec = ("       vec2 pos = vec2(0,0);\n"
37                 GLAMOR_POS(gl_Position, primitive)),
38 };
39 
40 static Bool
glamor_poly_glyph_blt_gl(DrawablePtr drawable,GCPtr gc,int start_x,int y,unsigned int nglyph,CharInfoPtr * ppci,void * pglyph_base)41 glamor_poly_glyph_blt_gl(DrawablePtr drawable, GCPtr gc,
42                          int start_x, int y, unsigned int nglyph,
43                          CharInfoPtr *ppci, void *pglyph_base)
44 {
45     ScreenPtr screen = drawable->pScreen;
46     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
47     PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
48     glamor_pixmap_private *pixmap_priv;
49     glamor_program *prog;
50     RegionPtr clip = gc->pCompositeClip;
51     int box_index;
52     Bool ret = FALSE;
53 
54     pixmap_priv = glamor_get_pixmap_private(pixmap);
55     if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
56         goto bail;
57 
58     glamor_make_current(glamor_priv);
59 
60     prog = glamor_use_program_fill(pixmap, gc,
61                                    &glamor_priv->poly_glyph_blt_progs,
62                                    &glamor_facet_poly_glyph_blt);
63     if (!prog)
64         goto bail;
65 
66     glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
67 
68     start_x += drawable->x;
69     y += drawable->y;
70 
71     glamor_pixmap_loop(pixmap_priv, box_index) {
72         int x;
73         int n;
74         int num_points, max_points;
75         INT16 *points = NULL;
76         int off_x, off_y;
77         char *vbo_offset;
78 
79         if (!glamor_set_destination_drawable(drawable, box_index, FALSE, TRUE,
80                                               prog->matrix_uniform, &off_x, &off_y))
81             goto bail;
82 
83         max_points = 500;
84         num_points = 0;
85         x = start_x;
86         for (n = 0; n < nglyph; n++) {
87             CharInfoPtr charinfo = ppci[n];
88             int w = GLYPHWIDTHPIXELS(charinfo);
89             int h = GLYPHHEIGHTPIXELS(charinfo);
90             uint8_t *glyphbits = FONTGLYPHBITS(NULL, charinfo);
91 
92             if (w && h) {
93                 int glyph_x = x + charinfo->metrics.leftSideBearing;
94                 int glyph_y = y - charinfo->metrics.ascent;
95                 int glyph_stride = GLYPHWIDTHBYTESPADDED(charinfo);
96                 int xx, yy;
97 
98                 for (yy = 0; yy < h; yy++) {
99                     uint8_t *glyph = glyphbits;
100                     for (xx = 0; xx < w; glyph += ((xx&7) == 7), xx++) {
101                         int pt_x_i = glyph_x + xx;
102                         int pt_y_i = glyph_y + yy;
103 
104                         if (!(*glyph & (1 << (xx & 7))))
105                             continue;
106 
107                         if (!RegionContainsPoint(clip, pt_x_i, pt_y_i, NULL))
108                             continue;
109 
110                         if (!num_points) {
111                             points = glamor_get_vbo_space(screen,
112                                                           max_points *
113                                                           (2 * sizeof (INT16)),
114                                                           &vbo_offset);
115 
116                             glVertexAttribPointer(GLAMOR_VERTEX_POS,
117                                                   2, GL_SHORT,
118                                                   GL_FALSE, 0, vbo_offset);
119                         }
120 
121                         *points++ = pt_x_i;
122                         *points++ = pt_y_i;
123                         num_points++;
124 
125                         if (num_points == max_points) {
126                             glamor_put_vbo_space(screen);
127                             glDrawArrays(GL_POINTS, 0, num_points);
128                             num_points = 0;
129                         }
130                     }
131                     glyphbits += glyph_stride;
132                 }
133             }
134             x += charinfo->metrics.characterWidth;
135         }
136 
137         if (num_points) {
138             glamor_put_vbo_space(screen);
139             glDrawArrays(GL_POINTS, 0, num_points);
140         }
141     }
142 
143     glamor_pixmap_invalid(pixmap);
144 
145     ret = TRUE;
146 
147 bail:
148     glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
149 
150     return ret;
151 }
152 
153 void
glamor_poly_glyph_blt(DrawablePtr drawable,GCPtr gc,int start_x,int y,unsigned int nglyph,CharInfoPtr * ppci,void * pglyph_base)154 glamor_poly_glyph_blt(DrawablePtr drawable, GCPtr gc,
155                       int start_x, int y, unsigned int nglyph,
156                       CharInfoPtr *ppci, void *pglyph_base)
157 {
158     if (GLAMOR_PREFER_GL() &&
159         glamor_poly_glyph_blt_gl(drawable, gc, start_x, y, nglyph, ppci,
160                                  pglyph_base))
161         return;
162     miPolyGlyphBlt(drawable, gc, start_x, y, nglyph,
163                    ppci, pglyph_base);
164 }
165 
166 static Bool
glamor_push_pixels_gl(GCPtr gc,PixmapPtr bitmap,DrawablePtr drawable,int w,int h,int x,int y)167 glamor_push_pixels_gl(GCPtr gc, PixmapPtr bitmap,
168                       DrawablePtr drawable, int w, int h, int x, int y)
169 {
170     ScreenPtr screen = drawable->pScreen;
171     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
172     PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
173     glamor_pixmap_private *pixmap_priv;
174     uint8_t *bitmap_data = bitmap->devPrivate.ptr;
175     int bitmap_stride = bitmap->devKind;
176     glamor_program *prog;
177     RegionPtr clip = gc->pCompositeClip;
178     int box_index;
179     int yy, xx;
180     int num_points;
181     INT16 *points = NULL;
182     char *vbo_offset;
183     Bool ret = FALSE;
184 
185     if (w * h > MAXINT / (2 * sizeof(float)))
186         goto bail;
187 
188     pixmap_priv = glamor_get_pixmap_private(pixmap);
189     if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
190         goto bail;
191 
192     glamor_make_current(glamor_priv);
193 
194     prog = glamor_use_program_fill(pixmap, gc,
195                                    &glamor_priv->poly_glyph_blt_progs,
196                                    &glamor_facet_poly_glyph_blt);
197     if (!prog)
198         goto bail;
199 
200     glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
201 
202     points = glamor_get_vbo_space(screen, w * h * sizeof(INT16) * 2,
203                                   &vbo_offset);
204     num_points = 0;
205 
206     /* Note that because fb sets miTranslate in the GC, our incoming X
207      * and Y are in screen coordinate space (same for spans, but not
208      * other operations).
209      */
210 
211     for (yy = 0; yy < h; yy++) {
212         uint8_t *bitmap_row = bitmap_data + yy * bitmap_stride;
213         for (xx = 0; xx < w; xx++) {
214             if (bitmap_row[xx / 8] & (1 << xx % 8) &&
215                 RegionContainsPoint(clip,
216                                     x + xx,
217                                     y + yy,
218                                     NULL)) {
219                 *points++ = x + xx;
220                 *points++ = y + yy;
221                 num_points++;
222             }
223         }
224     }
225     glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT,
226                           GL_FALSE, 0, vbo_offset);
227 
228     glamor_put_vbo_space(screen);
229 
230     glamor_pixmap_loop(pixmap_priv, box_index) {
231         if (!glamor_set_destination_drawable(drawable, box_index, FALSE, TRUE,
232                                              prog->matrix_uniform, NULL, NULL))
233             goto bail;
234 
235         glDrawArrays(GL_POINTS, 0, num_points);
236     }
237 
238     glamor_pixmap_invalid(pixmap);
239 
240     ret = TRUE;
241 
242 bail:
243     glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
244 
245     return ret;
246 }
247 
248 void
glamor_push_pixels(GCPtr pGC,PixmapPtr pBitmap,DrawablePtr pDrawable,int w,int h,int x,int y)249 glamor_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
250                    DrawablePtr pDrawable, int w, int h, int x, int y)
251 {
252     if (GLAMOR_PREFER_GL() &&
253         glamor_push_pixels_gl(pGC, pBitmap, pDrawable, w, h, x, y))
254         return;
255 
256     miPushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
257 }
258