135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2014 Keith Packard
335c4bbdfSmrg *
435c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its
535c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that
635c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright
735c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and
835c4bbdfSmrg * that the name of the copyright holders not be used in advertising or
935c4bbdfSmrg * publicity pertaining to distribution of the software without specific,
1035c4bbdfSmrg * written prior permission.  The copyright holders make no representations
1135c4bbdfSmrg * about the suitability of this software for any purpose.  It is provided "as
1235c4bbdfSmrg * is" without express or implied warranty.
1335c4bbdfSmrg *
1435c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1535c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1635c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1735c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1835c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1935c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2035c4bbdfSmrg * OF THIS SOFTWARE.
2135c4bbdfSmrg */
2235c4bbdfSmrg
2335c4bbdfSmrg#include "glamor_priv.h"
2435c4bbdfSmrg#include "glamor_font.h"
2535c4bbdfSmrg#include <dixfontstr.h>
2635c4bbdfSmrg
2735c4bbdfSmrgstatic int glamor_font_generation;
2835c4bbdfSmrgstatic int glamor_font_private_index;
2935c4bbdfSmrgstatic int glamor_font_screen_count;
3035c4bbdfSmrg
3135c4bbdfSmrgglamor_font_t *
3235c4bbdfSmrgglamor_font_get(ScreenPtr screen, FontPtr font)
3335c4bbdfSmrg{
3435c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
3535c4bbdfSmrg
3635c4bbdfSmrg    glamor_font_t       *privates;
3735c4bbdfSmrg    glamor_font_t       *glamor_font;
3835c4bbdfSmrg    int                 overall_width, overall_height;
3935c4bbdfSmrg    int                 num_rows;
4035c4bbdfSmrg    int                 num_cols;
4135c4bbdfSmrg    int                 glyph_width_pixels;
4235c4bbdfSmrg    int                 glyph_width_bytes;
4335c4bbdfSmrg    int                 glyph_height;
4435c4bbdfSmrg    int                 row, col;
4535c4bbdfSmrg    unsigned char       c[2];
4635c4bbdfSmrg    CharInfoPtr         glyph;
4735c4bbdfSmrg    unsigned long       count;
4835c4bbdfSmrg    char                *bits;
4935c4bbdfSmrg
50ed6184dfSmrg    if (!glamor_glsl_has_ints(glamor_priv))
5135c4bbdfSmrg        return NULL;
5235c4bbdfSmrg
5335c4bbdfSmrg    privates = FontGetPrivate(font, glamor_font_private_index);
5435c4bbdfSmrg    if (!privates) {
5535c4bbdfSmrg        privates = calloc(glamor_font_screen_count, sizeof (glamor_font_t));
5635c4bbdfSmrg        if (!privates)
5735c4bbdfSmrg            return NULL;
581b5d61b8Smrg        xfont2_font_set_private(font, glamor_font_private_index, privates);
5935c4bbdfSmrg    }
6035c4bbdfSmrg
6135c4bbdfSmrg    glamor_font = &privates[screen->myNum];
6235c4bbdfSmrg
6335c4bbdfSmrg    if (glamor_font->realized)
6435c4bbdfSmrg        return glamor_font;
6535c4bbdfSmrg
6635c4bbdfSmrg    /* Figure out how many glyphs are in the font */
6735c4bbdfSmrg    num_cols = font->info.lastCol - font->info.firstCol + 1;
6835c4bbdfSmrg    num_rows = font->info.lastRow - font->info.firstRow + 1;
6935c4bbdfSmrg
7035c4bbdfSmrg    /* Figure out the size of each glyph */
7135c4bbdfSmrg    glyph_width_pixels = font->info.maxbounds.rightSideBearing - font->info.minbounds.leftSideBearing;
7235c4bbdfSmrg    glyph_height = font->info.maxbounds.ascent + font->info.maxbounds.descent;
7335c4bbdfSmrg
7435c4bbdfSmrg    glyph_width_bytes = (glyph_width_pixels + 7) >> 3;
7535c4bbdfSmrg
7635c4bbdfSmrg    glamor_font->glyph_width_pixels = glyph_width_pixels;
7735c4bbdfSmrg    glamor_font->glyph_width_bytes = glyph_width_bytes;
7835c4bbdfSmrg    glamor_font->glyph_height = glyph_height;
7935c4bbdfSmrg
8035c4bbdfSmrg    /*
8135c4bbdfSmrg     * Layout the font two blocks of columns wide.
8235c4bbdfSmrg     * This avoids a problem with some fonts that are too high to fit.
8335c4bbdfSmrg     */
8435c4bbdfSmrg    glamor_font->row_width = glyph_width_bytes * num_cols;
8535c4bbdfSmrg
8635c4bbdfSmrg    if (num_rows > 1) {
8735c4bbdfSmrg       overall_width = glamor_font->row_width * 2;
8835c4bbdfSmrg       overall_height = glyph_height * ((num_rows + 1) / 2);
8935c4bbdfSmrg    } else {
9035c4bbdfSmrg       overall_width = glamor_font->row_width;
9135c4bbdfSmrg       overall_height = glyph_height;
9235c4bbdfSmrg    }
9335c4bbdfSmrg
9435c4bbdfSmrg    if (overall_width > glamor_priv->max_fbo_size ||
9535c4bbdfSmrg        overall_height > glamor_priv->max_fbo_size) {
9635c4bbdfSmrg        /* fallback if we don't fit inside a texture */
9735c4bbdfSmrg        return NULL;
9835c4bbdfSmrg    }
9935c4bbdfSmrg    bits = malloc(overall_width * overall_height);
10035c4bbdfSmrg    if (!bits)
10135c4bbdfSmrg        return NULL;
10235c4bbdfSmrg
10335c4bbdfSmrg    /* Check whether the font has a default character */
10435c4bbdfSmrg    c[0] = font->info.lastRow + 1;
10535c4bbdfSmrg    c[1] = font->info.lastCol + 1;
10635c4bbdfSmrg    (*font->get_glyphs)(font, 1, c, TwoD16Bit, &count, &glyph);
10735c4bbdfSmrg
10835c4bbdfSmrg    glamor_font->default_char = count ? glyph : NULL;
10935c4bbdfSmrg    glamor_font->default_row = font->info.defaultCh >> 8;
11035c4bbdfSmrg    glamor_font->default_col = font->info.defaultCh;
11135c4bbdfSmrg
11235c4bbdfSmrg    glamor_priv = glamor_get_screen_private(screen);
11335c4bbdfSmrg    glamor_make_current(glamor_priv);
11435c4bbdfSmrg
11535c4bbdfSmrg    glGenTextures(1, &glamor_font->texture_id);
11635c4bbdfSmrg    glActiveTexture(GL_TEXTURE0);
11735c4bbdfSmrg    glBindTexture(GL_TEXTURE_2D, glamor_font->texture_id);
11835c4bbdfSmrg
11935c4bbdfSmrg    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
12035c4bbdfSmrg    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
12135c4bbdfSmrg
12235c4bbdfSmrg    /* Paint all of the glyphs */
12335c4bbdfSmrg    for (row = 0; row < num_rows; row++) {
12435c4bbdfSmrg        for (col = 0; col < num_cols; col++) {
12535c4bbdfSmrg            c[0] = row + font->info.firstRow;
12635c4bbdfSmrg            c[1] = col + font->info.firstCol;
12735c4bbdfSmrg
12835c4bbdfSmrg            (*font->get_glyphs)(font, 1, c, TwoD16Bit, &count, &glyph);
12935c4bbdfSmrg
13035c4bbdfSmrg            if (count) {
13135c4bbdfSmrg                char *dst;
13235c4bbdfSmrg                char *src = glyph->bits;
13335c4bbdfSmrg                unsigned y;
13435c4bbdfSmrg
13535c4bbdfSmrg                dst = bits;
13635c4bbdfSmrg                /* get offset of start of first row */
13735c4bbdfSmrg                dst += (row / 2) * glyph_height * overall_width;
13835c4bbdfSmrg                /* add offset into second row */
13935c4bbdfSmrg                dst += (row & 1) ? glamor_font->row_width : 0;
14035c4bbdfSmrg
14135c4bbdfSmrg                dst += col * glyph_width_bytes;
14235c4bbdfSmrg                for (y = 0; y < GLYPHHEIGHTPIXELS(glyph); y++) {
14335c4bbdfSmrg                    memcpy(dst, src, GLYPHWIDTHBYTES(glyph));
14435c4bbdfSmrg                    dst += overall_width;
14535c4bbdfSmrg                    src += GLYPHWIDTHBYTESPADDED(glyph);
14635c4bbdfSmrg                }
14735c4bbdfSmrg            }
14835c4bbdfSmrg        }
14935c4bbdfSmrg    }
15035c4bbdfSmrg
15135c4bbdfSmrg    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
15235c4bbdfSmrg
15335c4bbdfSmrg    glamor_priv->suppress_gl_out_of_memory_logging = true;
15435c4bbdfSmrg    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, overall_width, overall_height,
15535c4bbdfSmrg                 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, bits);
15635c4bbdfSmrg    glamor_priv->suppress_gl_out_of_memory_logging = false;
15735c4bbdfSmrg    if (glGetError() == GL_OUT_OF_MEMORY)
15835c4bbdfSmrg        return NULL;
15935c4bbdfSmrg
16035c4bbdfSmrg    free(bits);
16135c4bbdfSmrg
16235c4bbdfSmrg    glamor_font->realized = TRUE;
16335c4bbdfSmrg
16435c4bbdfSmrg    return glamor_font;
16535c4bbdfSmrg}
16635c4bbdfSmrg
16735c4bbdfSmrgstatic Bool
16835c4bbdfSmrgglamor_realize_font(ScreenPtr screen, FontPtr font)
16935c4bbdfSmrg{
17035c4bbdfSmrg    return TRUE;
17135c4bbdfSmrg}
17235c4bbdfSmrg
17335c4bbdfSmrgstatic Bool
17435c4bbdfSmrgglamor_unrealize_font(ScreenPtr screen, FontPtr font)
17535c4bbdfSmrg{
17635c4bbdfSmrg    glamor_screen_private       *glamor_priv;
17735c4bbdfSmrg    glamor_font_t               *privates = FontGetPrivate(font, glamor_font_private_index);
17835c4bbdfSmrg    glamor_font_t               *glamor_font;
17935c4bbdfSmrg    int                         s;
18035c4bbdfSmrg
18135c4bbdfSmrg    if (!privates)
18235c4bbdfSmrg        return TRUE;
18335c4bbdfSmrg
18435c4bbdfSmrg    glamor_font = &privates[screen->myNum];
18535c4bbdfSmrg
18635c4bbdfSmrg    if (!glamor_font->realized)
18735c4bbdfSmrg        return TRUE;
18835c4bbdfSmrg
18935c4bbdfSmrg    /* Unrealize the font, freeing the allocated texture */
19035c4bbdfSmrg    glamor_font->realized = FALSE;
19135c4bbdfSmrg
19235c4bbdfSmrg    glamor_priv = glamor_get_screen_private(screen);
19335c4bbdfSmrg    glamor_make_current(glamor_priv);
19435c4bbdfSmrg    glDeleteTextures(1, &glamor_font->texture_id);
19535c4bbdfSmrg
19635c4bbdfSmrg    /* Check to see if all of the screens are  done with this font
19735c4bbdfSmrg     * and free the private when that happens
19835c4bbdfSmrg     */
19935c4bbdfSmrg    for (s = 0; s < glamor_font_screen_count; s++)
20035c4bbdfSmrg        if (privates[s].realized)
20135c4bbdfSmrg            return TRUE;
20235c4bbdfSmrg
20335c4bbdfSmrg    free(privates);
2041b5d61b8Smrg    xfont2_font_set_private(font, glamor_font_private_index, NULL);
20535c4bbdfSmrg    return TRUE;
20635c4bbdfSmrg}
20735c4bbdfSmrg
20835c4bbdfSmrgBool
20935c4bbdfSmrgglamor_font_init(ScreenPtr screen)
21035c4bbdfSmrg{
21135c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
21235c4bbdfSmrg
213ed6184dfSmrg    if (!glamor_glsl_has_ints(glamor_priv))
21435c4bbdfSmrg        return TRUE;
21535c4bbdfSmrg
21635c4bbdfSmrg    if (glamor_font_generation != serverGeneration) {
2171b5d61b8Smrg        glamor_font_private_index = xfont2_allocate_font_private_index();
21835c4bbdfSmrg        if (glamor_font_private_index == -1)
21935c4bbdfSmrg            return FALSE;
22035c4bbdfSmrg        glamor_font_screen_count = 0;
22135c4bbdfSmrg        glamor_font_generation = serverGeneration;
22235c4bbdfSmrg    }
22335c4bbdfSmrg
22435c4bbdfSmrg    if (screen->myNum >= glamor_font_screen_count)
22535c4bbdfSmrg        glamor_font_screen_count = screen->myNum + 1;
22635c4bbdfSmrg
22735c4bbdfSmrg    screen->RealizeFont = glamor_realize_font;
22835c4bbdfSmrg    screen->UnrealizeFont = glamor_unrealize_font;
22935c4bbdfSmrg    return TRUE;
23035c4bbdfSmrg}
231