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
23 #include "glamor_priv.h"
24 #include "glamor_font.h"
25 #include <dixfontstr.h>
26
27 static int glamor_font_generation;
28 static int glamor_font_private_index;
29 static int glamor_font_screen_count;
30
31 glamor_font_t *
glamor_font_get(ScreenPtr screen,FontPtr font)32 glamor_font_get(ScreenPtr screen, FontPtr font)
33 {
34 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
35
36 glamor_font_t *privates;
37 glamor_font_t *glamor_font;
38 int overall_width, overall_height;
39 int num_rows;
40 int num_cols;
41 int glyph_width_pixels;
42 int glyph_width_bytes;
43 int glyph_height;
44 int row, col;
45 unsigned char c[2];
46 CharInfoPtr glyph;
47 unsigned long count;
48 char *bits;
49
50 if (glamor_priv->glsl_version < 130)
51 return NULL;
52
53 privates = FontGetPrivate(font, glamor_font_private_index);
54 if (!privates) {
55 privates = calloc(glamor_font_screen_count, sizeof (glamor_font_t));
56 if (!privates)
57 return NULL;
58 xfont2_font_set_private(font, glamor_font_private_index, privates);
59 }
60
61 glamor_font = &privates[screen->myNum];
62
63 if (glamor_font->realized)
64 return glamor_font;
65
66 /* Figure out how many glyphs are in the font */
67 num_cols = font->info.lastCol - font->info.firstCol + 1;
68 num_rows = font->info.lastRow - font->info.firstRow + 1;
69
70 /* Figure out the size of each glyph */
71 glyph_width_pixels = font->info.maxbounds.rightSideBearing - font->info.minbounds.leftSideBearing;
72 glyph_height = font->info.maxbounds.ascent + font->info.maxbounds.descent;
73
74 glyph_width_bytes = (glyph_width_pixels + 7) >> 3;
75
76 glamor_font->glyph_width_pixels = glyph_width_pixels;
77 glamor_font->glyph_width_bytes = glyph_width_bytes;
78 glamor_font->glyph_height = glyph_height;
79
80 /*
81 * Layout the font two blocks of columns wide.
82 * This avoids a problem with some fonts that are too high to fit.
83 */
84 glamor_font->row_width = glyph_width_bytes * num_cols;
85
86 if (num_rows > 1) {
87 overall_width = glamor_font->row_width * 2;
88 overall_height = glyph_height * ((num_rows + 1) / 2);
89 } else {
90 overall_width = glamor_font->row_width;
91 overall_height = glyph_height;
92 }
93
94 if (overall_width > glamor_priv->max_fbo_size ||
95 overall_height > glamor_priv->max_fbo_size) {
96 /* fallback if we don't fit inside a texture */
97 return NULL;
98 }
99 bits = malloc(overall_width * overall_height);
100 if (!bits)
101 return NULL;
102
103 /* Check whether the font has a default character */
104 c[0] = font->info.lastRow + 1;
105 c[1] = font->info.lastCol + 1;
106 (*font->get_glyphs)(font, 1, c, TwoD16Bit, &count, &glyph);
107
108 glamor_font->default_char = count ? glyph : NULL;
109 glamor_font->default_row = font->info.defaultCh >> 8;
110 glamor_font->default_col = font->info.defaultCh;
111
112 glamor_priv = glamor_get_screen_private(screen);
113 glamor_make_current(glamor_priv);
114
115 glGenTextures(1, &glamor_font->texture_id);
116 glActiveTexture(GL_TEXTURE0);
117 glBindTexture(GL_TEXTURE_2D, glamor_font->texture_id);
118
119 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
120 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
121
122 /* Paint all of the glyphs */
123 for (row = 0; row < num_rows; row++) {
124 for (col = 0; col < num_cols; col++) {
125 c[0] = row + font->info.firstRow;
126 c[1] = col + font->info.firstCol;
127
128 (*font->get_glyphs)(font, 1, c, TwoD16Bit, &count, &glyph);
129
130 if (count) {
131 char *dst;
132 char *src = glyph->bits;
133 unsigned y;
134
135 dst = bits;
136 /* get offset of start of first row */
137 dst += (row / 2) * glyph_height * overall_width;
138 /* add offset into second row */
139 dst += (row & 1) ? glamor_font->row_width : 0;
140
141 dst += col * glyph_width_bytes;
142 for (y = 0; y < GLYPHHEIGHTPIXELS(glyph); y++) {
143 memcpy(dst, src, GLYPHWIDTHBYTES(glyph));
144 dst += overall_width;
145 src += GLYPHWIDTHBYTESPADDED(glyph);
146 }
147 }
148 }
149 }
150
151 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
152
153 glamor_priv->suppress_gl_out_of_memory_logging = true;
154 glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, overall_width, overall_height,
155 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, bits);
156 glamor_priv->suppress_gl_out_of_memory_logging = false;
157 if (glGetError() == GL_OUT_OF_MEMORY)
158 return NULL;
159
160 free(bits);
161
162 glamor_font->realized = TRUE;
163
164 return glamor_font;
165 }
166
167 static Bool
glamor_realize_font(ScreenPtr screen,FontPtr font)168 glamor_realize_font(ScreenPtr screen, FontPtr font)
169 {
170 return TRUE;
171 }
172
173 static Bool
glamor_unrealize_font(ScreenPtr screen,FontPtr font)174 glamor_unrealize_font(ScreenPtr screen, FontPtr font)
175 {
176 glamor_screen_private *glamor_priv;
177 glamor_font_t *privates = FontGetPrivate(font, glamor_font_private_index);
178 glamor_font_t *glamor_font;
179 int s;
180
181 if (!privates)
182 return TRUE;
183
184 glamor_font = &privates[screen->myNum];
185
186 if (!glamor_font->realized)
187 return TRUE;
188
189 /* Unrealize the font, freeing the allocated texture */
190 glamor_font->realized = FALSE;
191
192 glamor_priv = glamor_get_screen_private(screen);
193 glamor_make_current(glamor_priv);
194 glDeleteTextures(1, &glamor_font->texture_id);
195
196 /* Check to see if all of the screens are done with this font
197 * and free the private when that happens
198 */
199 for (s = 0; s < glamor_font_screen_count; s++)
200 if (privates[s].realized)
201 return TRUE;
202
203 free(privates);
204 xfont2_font_set_private(font, glamor_font_private_index, NULL);
205 return TRUE;
206 }
207
208 Bool
glamor_font_init(ScreenPtr screen)209 glamor_font_init(ScreenPtr screen)
210 {
211 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
212
213 if (glamor_priv->glsl_version < 130)
214 return TRUE;
215
216 if (glamor_font_generation != serverGeneration) {
217 glamor_font_private_index = xfont2_allocate_font_private_index();
218 if (glamor_font_private_index == -1)
219 return FALSE;
220 glamor_font_screen_count = 0;
221 glamor_font_generation = serverGeneration;
222 }
223
224 if (screen->myNum >= glamor_font_screen_count)
225 glamor_font_screen_count = screen->myNum + 1;
226
227 screen->RealizeFont = glamor_realize_font;
228 screen->UnrealizeFont = glamor_unrealize_font;
229 return TRUE;
230 }
231