glamor_font.c (7769B)
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 * 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_glsl_has_ints(glamor_priv)) 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 168 glamor_realize_font(ScreenPtr screen, FontPtr font) 169 { 170 return TRUE; 171 } 172 173 static Bool 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 209 glamor_font_init(ScreenPtr screen) 210 { 211 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 212 213 if (!glamor_glsl_has_ints(glamor_priv)) 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 }