diff options
-rw-r--r-- | glamor/Makefile.am | 2 | ||||
-rw-r--r-- | glamor/glamor.c | 3 | ||||
-rw-r--r-- | glamor/glamor.h | 14 | ||||
-rw-r--r-- | glamor/glamor_core.c | 8 | ||||
-rw-r--r-- | glamor/glamor_font.c | 186 | ||||
-rw-r--r-- | glamor/glamor_font.h | 49 | ||||
-rw-r--r-- | glamor/glamor_priv.h | 20 | ||||
-rw-r--r-- | glamor/glamor_text.c | 526 |
8 files changed, 804 insertions, 4 deletions
diff --git a/glamor/Makefile.am b/glamor/Makefile.am index dccd923c5..4d0cc8138 100644 --- a/glamor/Makefile.am +++ b/glamor/Makefile.am @@ -12,6 +12,7 @@ libglamor_la_SOURCES = \ glamor_core.c \ glamor_debug.h \ glamor_fill.c \ + glamor_font.c \ glamor_glx.c \ glamor_glyphs.c \ glamor_polylines.c \ @@ -22,6 +23,7 @@ libglamor_la_SOURCES = \ glamor_program.c \ glamor_rects.c \ glamor_spans.c \ + glamor_text.c \ glamor_transfer.c \ glamor_transfer.h \ glamor_transform.c \ diff --git a/glamor/glamor.c b/glamor/glamor.c index d7192c1aa..59548b77a 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -424,6 +424,9 @@ glamor_init(ScreenPtr screen, unsigned int flags) screen->CreateScreenResources; screen->CreateScreenResources = glamor_create_screen_resources; + if (!glamor_font_init(screen)) + goto fail; + if (flags & GLAMOR_USE_SCREEN) { if (!RegisterBlockAndWakeupHandlers(_glamor_block_handler, _glamor_wakeup_handler, diff --git a/glamor/glamor.h b/glamor/glamor.h index 2ff0409f7..5d988da09 100644 --- a/glamor/glamor.h +++ b/glamor/glamor.h @@ -434,6 +434,20 @@ extern _X_EXPORT Bool glamor_poly_segment_nf(DrawablePtr pDrawable, GCPtr pGC, extern _X_EXPORT Bool glamor_poly_lines_nf(DrawablePtr drawable, GCPtr gc, int mode, int n, DDXPointPtr points); +extern _X_EXPORT Bool glamor_poly_text8_nf(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, char *chars, int *final_pos); + +extern _X_EXPORT Bool glamor_poly_text16_nf(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, unsigned short *chars, int *final_pos); + +extern _X_EXPORT Bool glamor_image_text8_nf(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, char *chars); + +extern _X_EXPORT Bool glamor_image_text16_nf(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, unsigned short *chars); + +#define HAS_GLAMOR_TEXT 1 + #ifdef GLAMOR_FOR_XORG extern _X_EXPORT XF86VideoAdaptorPtr glamor_xv_init(ScreenPtr pScreen, int num_texture_ports); diff --git a/glamor/glamor_core.c b/glamor/glamor_core.c index cdf41ec46..7b1615d2d 100644 --- a/glamor/glamor_core.c +++ b/glamor/glamor_core.c @@ -426,10 +426,10 @@ GCOps glamor_gc_ops = { .FillPolygon = miFillPolygon, .PolyFillRect = glamor_poly_fill_rect, .PolyFillArc = miPolyFillArc, - .PolyText8 = miPolyText8, - .PolyText16 = miPolyText16, - .ImageText8 = miImageText8, - .ImageText16 = miImageText16, + .PolyText8 = glamor_poly_text8, + .PolyText16 = glamor_poly_text16, + .ImageText8 = glamor_image_text8, + .ImageText16 = glamor_image_text16, .ImageGlyphBlt = miImageGlyphBlt, .PolyGlyphBlt = glamor_poly_glyph_blt, .PushPixels = glamor_push_pixels, diff --git a/glamor/glamor_font.c b/glamor/glamor_font.c new file mode 100644 index 000000000..47dfe2a69 --- /dev/null +++ b/glamor/glamor_font.c @@ -0,0 +1,186 @@ +/* + * Copyright © 2014 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "glamor_priv.h" +#include "glamor_font.h" +#include <dixfontstr.h> + +static int glamor_font_generation; +static int glamor_font_private_index; +static int glamor_font_screen_count; + +glamor_font_t * +glamor_font_get(ScreenPtr screen, FontPtr font) +{ + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + + glamor_font_t *privates; + glamor_font_t *glamor_font; + int overall_width, overall_height; + int num_rows; + int num_cols; + int glyph_width_pixels; + int glyph_width_bytes; + int glyph_height; + int row, col; + unsigned char c[2]; + CharInfoPtr glyph; + unsigned long count; + + + privates = FontGetPrivate(font, glamor_font_private_index); + if (!privates) { + privates = calloc(glamor_font_screen_count, sizeof (glamor_font_t)); + if (!privates) + return NULL; + FontSetPrivate(font, glamor_font_private_index, privates); + } + + glamor_font = &privates[screen->myNum]; + + if (glamor_font->realized) + return glamor_font; + + glamor_font->realized = TRUE; + + /* Figure out how many glyphs are in the font */ + num_cols = font->info.lastCol - font->info.firstCol + 1; + num_rows = font->info.lastRow - font->info.firstRow + 1; + + /* Figure out the size of each glyph */ + glyph_width_pixels = font->info.maxbounds.rightSideBearing - font->info.minbounds.leftSideBearing; + glyph_height = font->info.maxbounds.ascent + font->info.maxbounds.descent; + + glyph_width_bytes = (glyph_width_pixels + 7) >> 3; + + glamor_font->glyph_width_pixels = glyph_width_pixels; + glamor_font->glyph_width_bytes = glyph_width_bytes; + glamor_font->glyph_height = glyph_height; + + overall_width = glyph_width_bytes * num_cols; + overall_height = glyph_height * num_rows; + + /* Check whether the font has a default character */ + c[0] = font->info.lastRow + 1; + c[1] = font->info.lastCol + 1; + (*font->get_glyphs)(font, 1, c, TwoD16Bit, &count, &glyph); + + glamor_font->default_char = count ? glyph : NULL; + glamor_font->default_row = font->info.defaultCh >> 8; + glamor_font->default_col = font->info.defaultCh; + + glamor_priv = glamor_get_screen_private(screen); + glamor_get_context(glamor_priv); + + glGenTextures(1, &glamor_font->texture_id); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, glamor_font->texture_id); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + /* Allocate storage */ + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, overall_width, overall_height, + 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, NULL); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + + /* Paint all of the glyphs */ + for (row = 0; row < num_rows; row++) { + for (col = 0; col < num_cols; col++) { + c[0] = row + font->info.firstRow; + c[1] = col + font->info.firstCol; + + (*font->get_glyphs)(font, 1, c, TwoD16Bit, &count, &glyph); + + if (count) + glTexSubImage2D(GL_TEXTURE_2D, 0, col * glyph_width_bytes, row * glyph_height, + GLYPHWIDTHBYTES(glyph), GLYPHHEIGHTPIXELS(glyph), + GL_RED_INTEGER, GL_UNSIGNED_BYTE, glyph->bits); + } + } + + glamor_put_context(glamor_priv); + + return glamor_font; +} + +static Bool +glamor_realize_font(ScreenPtr screen, FontPtr font) +{ + return TRUE; +} + +static Bool +glamor_unrealize_font(ScreenPtr screen, FontPtr font) +{ + glamor_screen_private *glamor_priv; + glamor_font_t *privates = FontGetPrivate(font, glamor_font_private_index); + glamor_font_t *glamor_font; + int s; + + if (!privates) + return TRUE; + + glamor_font = &privates[screen->myNum]; + + if (!glamor_font->realized) + return TRUE; + + /* Unrealize the font, freeing the allocated texture */ + glamor_font->realized = FALSE; + + glamor_priv = glamor_get_screen_private(screen); + glamor_get_context(glamor_priv); + glDeleteTextures(1, &glamor_font->texture_id); + glamor_put_context(glamor_priv); + + /* Check to see if all of the screens are done with this font + * and free the private when that happens + */ + for (s = 0; s < glamor_font_screen_count; s++) + if (privates[s].realized) + return TRUE; + + free(privates); + FontSetPrivate(font, glamor_font_private_index, NULL); + return TRUE; +} + +Bool +glamor_font_init(ScreenPtr screen) +{ + if (glamor_font_generation != serverGeneration) { + glamor_font_private_index = AllocateFontPrivateIndex(); + if (glamor_font_private_index == -1) + return FALSE; + glamor_font_screen_count = 0; + glamor_font_generation = serverGeneration; + } + + if (screen->myNum >= glamor_font_screen_count) + glamor_font_screen_count = screen->myNum + 1; + + screen->RealizeFont = glamor_realize_font; + screen->UnrealizeFont = glamor_unrealize_font; + return TRUE; +} diff --git a/glamor/glamor_font.h b/glamor/glamor_font.h new file mode 100644 index 000000000..36d20624d --- /dev/null +++ b/glamor/glamor_font.h @@ -0,0 +1,49 @@ +/* + * Copyright © 2014 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _GLAMOR_FONT_H_ +#define _GLAMOR_FONT_H_ + +typedef struct { + Bool realized; + CharInfoPtr default_char; + CARD8 default_row; + CARD8 default_col; + + GLuint texture_id; + + CARD16 glyph_width_bytes; + CARD16 glyph_width_pixels; + CARD16 glyph_height; + +} glamor_font_t; + +glamor_font_t * +glamor_font_get(ScreenPtr screen, FontPtr font); + +Bool +glamor_font_init(ScreenPtr screen); + +void +glamor_fini_glyph_shader(ScreenPtr screen); + +#endif /* _GLAMOR_FONT_H_ */ diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h index 2a8cae109..47f9efecc 100644 --- a/glamor/glamor_priv.h +++ b/glamor/glamor_priv.h @@ -233,6 +233,11 @@ typedef struct glamor_screen_private { /* glamor glyphblt shaders */ glamor_program_fill poly_glyph_blt_progs; + /* glamor text shaders */ + glamor_program_fill poly_text_progs; + glamor_program te_text_prog; + glamor_program image_text_prog; + /* vertext/elment_index buffer object for render */ GLuint vbo, ebo; /** Next offset within the VBO that glamor_get_vbo_space() will use. */ @@ -959,6 +964,19 @@ RegionPtr glamor_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int dstx, int dsty, unsigned long bitPlane); +/* glamor_text.c */ +int glamor_poly_text8(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, int count, char *chars); + +int glamor_poly_text16(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, int count, unsigned short *chars); + +void glamor_image_text8(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, int count, char *chars); + +void glamor_image_text16(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, int count, unsigned short *chars); + /* glamor_spans.c */ void glamor_fill_spans(DrawablePtr drawable, @@ -1051,4 +1069,6 @@ void glamor_fini_xv_shader(ScreenPtr screen); //#define GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK #define GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK +#include "glamor_font.h" + #endif /* GLAMOR_PRIV_H */ diff --git a/glamor/glamor_text.c b/glamor/glamor_text.c new file mode 100644 index 000000000..0e4b74c56 --- /dev/null +++ b/glamor/glamor_text.c @@ -0,0 +1,526 @@ +/* + * Copyright © 2014 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "glamor_priv.h" +#include <dixfontstr.h> +#include "glamor_transform.h" + +/* + * Fill in the array of charinfo pointers for the provided characters. For + * missing characters, place a NULL in the array so that the charinfo array + * aligns exactly with chars + */ + +static void +glamor_get_glyphs(FontPtr font, glamor_font_t *glamor_font, + int count, char *chars, Bool sixteen, CharInfoPtr *charinfo) +{ + unsigned long nglyphs; + FontEncoding encoding; + int char_step; + + if (sixteen) { + char_step = 2; + if (FONTLASTROW(font) == 0) + encoding = Linear16Bit; + else + encoding = TwoD16Bit; + } else { + char_step = 1; + encoding = Linear8Bit; + } + + /* If the font has a default character, then we don't have to + * worry about missing glyphs, so just get the whole string all at + * once. Otherwise, we have to fetch chars one at a time to notice + * missing ones. + */ + if (glamor_font->default_char) { + GetGlyphs(font, (unsigned long) count, (unsigned char *) chars, + encoding, &nglyphs, charinfo); + } else { + int c; + for (c = 0; c < count; c++) { + GetGlyphs(font, 1, (unsigned char *) chars, + encoding, &nglyphs, &charinfo[c]); + if (!nglyphs) + charinfo[c] = NULL; + chars += char_step; + } + } +} + +/* + * Construct quads for the provided list of characters and draw them + */ + +static int +glamor_text(DrawablePtr drawable, GCPtr gc, + glamor_font_t *glamor_font, + glamor_program *prog, + int x, int y, + int count, char *s_chars, CharInfoPtr *charinfo, + Bool sixteen) +{ + unsigned char *chars = (unsigned char *) s_chars; + FontPtr font = gc->font; + int off_x, off_y; + int c; + int nglyph; + GLshort *v; + char *vbo_offset; + CharInfoPtr ci; + int firstRow = font->info.firstRow; + int firstCol = font->info.firstCol; + int glyph_spacing_x = glamor_font->glyph_width_bytes * 8; + int glyph_spacing_y = glamor_font->glyph_height; + int box_x, box_y; + PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); + glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); + + /* Set the font as texture 1 */ + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, glamor_font->texture_id); + glUniform1i(prog->font_uniform, 1); + + /* Set up the vertex buffers for the font and destination */ + + v = glamor_get_vbo_space(drawable->pScreen, count * (6 * sizeof (GLshort)), &vbo_offset); + + glEnableVertexAttribArray(GLAMOR_VERTEX_POS); + glVertexAttribDivisor(GLAMOR_VERTEX_POS, 1); + glVertexAttribPointer(GLAMOR_VERTEX_POS, 4, GL_SHORT, GL_FALSE, + 6 * sizeof (GLshort), vbo_offset); + + glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE); + glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 1); + glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_SHORT, GL_FALSE, + 6 * sizeof (GLshort), vbo_offset + 4 * sizeof (GLshort)); + + /* Set the vertex coordinates */ + nglyph = 0; + + for (c = 0; c < count; c++) { + if ((ci = *charinfo++)) { + int x1 = x + ci->metrics.leftSideBearing; + int y1 = y - ci->metrics.ascent; + int width = GLYPHWIDTHPIXELS(ci); + int height = GLYPHHEIGHTPIXELS(ci); + int tx, ty = 0; + int row = 0, col; + + x += ci->metrics.characterWidth; + + if (sixteen) { + if (ci == glamor_font->default_char) { + row = glamor_font->default_row; + col = glamor_font->default_col; + } else { + row = chars[0]; + col = chars[1]; + } + if (FONTLASTROW(font) != 0) + ty = (row - firstRow) * glyph_spacing_y; + else + col += row << 8; + } else { + if (ci == glamor_font->default_char) + col = glamor_font->default_col; + else + col = chars[0]; + } + + tx = (col - firstCol) * glyph_spacing_x; + + v[ 0] = x1; + v[ 1] = y1; + v[ 2] = width; + v[ 3] = height; + v[ 4] = tx; + v[ 5] = ty; + + v += 6; + nglyph++; + } + chars += 1 + sixteen; + } + glamor_put_vbo_space(drawable->pScreen); + + if (nglyph != 0) { + + glEnable(GL_SCISSOR_TEST); + + glamor_pixmap_loop(pixmap_priv, box_x, box_y) { + BoxPtr box = RegionRects(gc->pCompositeClip); + int nbox = RegionNumRects(gc->pCompositeClip); + + glamor_set_destination_drawable(drawable, box_x, box_y, TRUE, FALSE, prog->matrix_uniform, &off_x, &off_y); + + /* Run over the clip list, drawing the glyphs + * in each box + */ + + while (nbox--) { + glScissor(box->x1 + off_x, + box->y1 + off_y, + box->x2 - box->x1, + box->y2 - box->y1); + box++; + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nglyph); + } + } + glDisable(GL_SCISSOR_TEST); + } + + glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0); + glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); + glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0); + glDisableVertexAttribArray(GLAMOR_VERTEX_POS); + glDisable(GL_COLOR_LOGIC_OP); + + return x; +} + +static const char vs_vars_text[] = + "attribute vec4 primitive;\n" + "attribute vec2 source;\n" + "varying vec2 glyph_pos;\n"; + +static const char vs_exec_text[] = + " vec2 pos = primitive.zw * vec2(gl_VertexID&1, (gl_VertexID&2)>>1);\n" + GLAMOR_POS(gl_Position, (primitive.xy + pos)) + " glyph_pos = source + pos;\n"; + +static const char fs_vars_text[] = + "varying vec2 glyph_pos;\n"; + +static const char fs_exec_text[] = + " ivec2 itile_texture = ivec2(glyph_pos);\n" + " uint x = uint(itile_texture.x & 7);\n" + " itile_texture.x >>= 3;\n" + " uint texel = texelFetch(font, itile_texture, 0).x;\n" + " uint bit = (texel >> x) & uint(1);\n" + " if (bit == uint(0))\n" + " discard;\n"; + +static const char fs_exec_te[] = + " ivec2 itile_texture = ivec2(glyph_pos);\n" + " uint x = uint(itile_texture.x & 7);\n" + " itile_texture.x >>= 3;\n" + " uint texel = texelFetch(font, itile_texture, 0).x;\n" + " uint bit = (texel >> x) & uint(1);\n" + " if (bit == uint(0))\n" + " gl_FragColor = bg;\n" + " else\n" + " gl_FragColor = fg;\n"; + +static const glamor_facet glamor_facet_poly_text = { + .name = "poly_text", + .version = 130, + .vs_vars = vs_vars_text, + .vs_exec = vs_exec_text, + .fs_vars = fs_vars_text, + .fs_exec = fs_exec_text, + .source_name = "source", + .locations = glamor_program_location_font, +}; + +static Bool +glamor_poly_text(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, char *chars, Bool sixteen, int *final_pos) +{ + ScreenPtr screen = drawable->pScreen; + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); + glamor_program *prog; + glamor_pixmap_private *pixmap_priv; + glamor_font_t *glamor_font; + CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */ + + glamor_font = glamor_font_get(drawable->pScreen, gc->font); + if (!glamor_font) + goto bail; + + glamor_get_glyphs(gc->font, glamor_font, count, chars, sixteen, charinfo); + + pixmap_priv = glamor_get_pixmap_private(pixmap); + if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) + goto bail; + + glamor_get_context(glamor_priv); + + prog = glamor_use_program_fill(pixmap, gc, &glamor_priv->poly_text_progs, &glamor_facet_poly_text); + + if (!prog) + goto bail_ctx; + + x = glamor_text(drawable, gc, glamor_font, prog, + x, y, count, chars, charinfo, sixteen); + + glDisable(GL_COLOR_LOGIC_OP); + + glamor_put_context(glamor_priv); + + glamor_priv->state = RENDER_STATE; + glamor_priv->render_idle_cnt = 0; + + *final_pos = x; + return TRUE; + +bail_ctx: + glDisable(GL_COLOR_LOGIC_OP); + glamor_put_context(glamor_priv); +bail: + return FALSE; +} + +Bool +glamor_poly_text8_nf(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, char *chars, int *final_pos) +{ + if (glamor_poly_text(drawable, gc, x, y, count, chars, FALSE, final_pos)) + return TRUE; + if (glamor_ddx_fallback_check_pixmap(drawable) && glamor_ddx_fallback_check_gc(gc)) + return FALSE; + *final_pos = miPolyText8(drawable, gc, x, y, count, chars); + return TRUE; +} + +int +glamor_poly_text8(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, char *chars) +{ + int final_pos; + + if (glamor_poly_text(drawable, gc, x, y, count, chars, FALSE, &final_pos)) + return final_pos; + return miPolyText8(drawable, gc, x, y, count, chars); +} + +Bool +glamor_poly_text16_nf(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, unsigned short *chars, int *final_pos) +{ + if (glamor_poly_text(drawable, gc, x, y, count, (char *) chars, TRUE, final_pos)) + return TRUE; + + if (glamor_ddx_fallback_check_pixmap(drawable) && glamor_ddx_fallback_check_gc(gc)) + return FALSE; + *final_pos = miPolyText16(drawable, gc, x, y, count, chars); + return TRUE; +} + +int +glamor_poly_text16(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, unsigned short *chars) +{ + int final_pos; + + if (glamor_poly_text(drawable, gc, x, y, count, (char *) chars, TRUE, &final_pos)) + return final_pos; + return miPolyText16(drawable, gc, x, y, count, chars); +} + +/* + * Draw image text, which is always solid in copy mode and has the + * background cleared while painting the text. For fonts which have + * their bitmap metrics exactly equal to the area to clear, we can use + * the accelerated version which paints both fg and bg at the same + * time. Otherwise, clear the whole area and then paint the glyphs on + * top + */ + +static const glamor_facet glamor_facet_image_text = { + .name = "image_text", + .version = 130, + .vs_vars = vs_vars_text, + .vs_exec = vs_exec_text, + .fs_vars = fs_vars_text, + .fs_exec = fs_exec_text, + .source_name = "source", + .locations = glamor_program_location_font, +}; + +static Bool +use_image_solid(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg) +{ + return glamor_set_solid(pixmap, gc, FALSE, prog->fg_uniform); +} + +static const glamor_facet glamor_facet_image_fill = { + .name = "solid", + .fs_exec = " gl_FragColor = fg;\n", + .locations = glamor_program_location_fg, + .use = use_image_solid, +}; + +static Bool +glamor_te_text_use(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg) +{ + if (!glamor_set_solid(pixmap, gc, FALSE, prog->fg_uniform)) + return FALSE; + glamor_set_color(pixmap, gc->bgPixel, prog->bg_uniform); + return TRUE; +} + +static const glamor_facet glamor_facet_te_text = { + .name = "te_text", + .version = 130, + .vs_vars = vs_vars_text, + .vs_exec = vs_exec_text, + .fs_vars = fs_vars_text, + .fs_exec = fs_exec_te, + .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_font, + .source_name = "source", + .use = glamor_te_text_use, +}; + +static Bool +glamor_image_text(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, char *chars, + Bool sixteen) +{ + ScreenPtr screen = drawable->pScreen; + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); + glamor_program *prog; + glamor_pixmap_private *pixmap_priv; + glamor_font_t *glamor_font; + const glamor_facet *prim_facet; + const glamor_facet *fill_facet; + CharInfoPtr charinfo[255]; /* encoding only has 1 byte for count */ + + pixmap_priv = glamor_get_pixmap_private(pixmap); + if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) + return FALSE; + + glamor_font = glamor_font_get(drawable->pScreen, gc->font); + if (!glamor_font) + return FALSE; + + glamor_get_glyphs(gc->font, glamor_font, count, chars, sixteen, charinfo); + + glamor_get_context(glamor_priv); + + if (TERMINALFONT(gc->font)) + prog = &glamor_priv->te_text_prog; + else + prog = &glamor_priv->image_text_prog; + + if (prog->failed) + goto bail; + + if (!prog->prog) { + if (TERMINALFONT(gc->font)) { + prim_facet = &glamor_facet_te_text; + fill_facet = NULL; + } else { + prim_facet = &glamor_facet_image_text; + fill_facet = &glamor_facet_image_fill; + } + + if (!glamor_build_program(screen, prog, prim_facet, fill_facet)) + goto bail; + } + + if (!TERMINALFONT(gc->font)) { + int width = 0; + int c; + RegionRec region; + BoxRec box; + int off_x, off_y; + + /* Check planemask before drawing background to + * bail early if it's not OK + */ + if (!glamor_set_planemask(pixmap, gc->planemask)) + goto bail; + for (c = 0; c < count; c++) + if (charinfo[c]) + width += charinfo[c]->metrics.characterWidth; + + glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y); + + if (width >= 0) { + box.x1 = off_x + drawable->x + x; + box.x2 = off_x + drawable->x + x + width; + } else { + box.x1 = off_x + drawable->x + x + width; + box.x2 = off_x + drawable->x + x; + } + box.y1 = off_y + drawable->y + y - gc->font->info.fontAscent; + box.y2 = off_y + drawable->y + y + gc->font->info.fontDescent; + RegionInit(®ion, &box, 1); + RegionIntersect(®ion, ®ion, gc->pCompositeClip); + glamor_solid_boxes(pixmap, RegionRects(®ion), RegionNumRects(®ion), gc->bgPixel); + RegionUninit(®ion); + } + + if (!glamor_use_program(pixmap, gc, prog, NULL)) + goto bail; + + (void) glamor_text(drawable, gc, glamor_font, prog, + x, y, count, chars, charinfo, sixteen); + + glamor_put_context(glamor_priv); + + glamor_priv->state = RENDER_STATE; + glamor_priv->render_idle_cnt = 0; + + return TRUE; + +bail: + glDisable(GL_COLOR_LOGIC_OP); + glamor_put_context(glamor_priv); + return FALSE; +} + +Bool +glamor_image_text8_nf(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, char *chars) +{ + return glamor_image_text(drawable, gc, x, y, count, chars, FALSE); +} + +void +glamor_image_text8(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, char *chars) +{ + if (!glamor_image_text(drawable, gc, x, y, count, chars, FALSE)) + miImageText8(drawable, gc, x, y, count, chars); +} + +Bool +glamor_image_text16_nf(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, unsigned short *chars) +{ + return glamor_image_text(drawable, gc, x, y, count, (char *) chars, FALSE); +} + +void +glamor_image_text16(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, unsigned short *chars) +{ + if (!glamor_image_text(drawable, gc, x, y, count, (char *) chars, TRUE)) + miImageText16(drawable, gc, x, y, count, chars); +} |