Accelerates text painting with GPU-based geometry computation and stippling
Signed-off-by: Keith Packard <[email protected]> --- glamor/Makefile.am | 2 + glamor/glamor.c | 4 + glamor/glamor_core.c | 8 +- glamor/glamor_font.c | 181 +++++++++++++++++++ glamor/glamor_font.h | 47 +++++ glamor/glamor_priv.h | 20 +++ glamor/glamor_text.c | 488 +++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 746 insertions(+), 4 deletions(-) create mode 100644 glamor/glamor_font.c create mode 100644 glamor/glamor_font.h create mode 100644 glamor/glamor_text.c diff --git a/glamor/Makefile.am b/glamor/Makefile.am index 19c8ddd..1baf683 100644 --- a/glamor/Makefile.am +++ b/glamor/Makefile.am @@ -13,6 +13,7 @@ libglamor_la_SOURCES = \ glamor_debug.h \ glamor_fill.c \ glamor_fillspans.c \ + glamor_font.c \ glamor_getspans.c \ glamor_glx.c \ glamor_glyphs.c \ @@ -25,6 +26,7 @@ libglamor_la_SOURCES = \ glamor_program.c \ glamor_rects.c \ glamor_spans.c \ + glamor_text.c \ glamor_transform.c \ glamor_trapezoid.c \ glamor_tile.c \ diff --git a/glamor/glamor.c b/glamor/glamor.c index 7acc212..5be6198 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -439,6 +439,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, @@ -553,6 +556,7 @@ glamor_release_screen_priv(ScreenPtr screen) glamor_fini_point_shader(screen); glamor_fini_fillspans_shader(screen); glamor_fini_polyfillrect_shader(screen); + glamor_fini_glyph_shader(screen); glamor_fini_tile_shader(screen); #ifdef GLAMOR_TRAPEZOID_SHADER glamor_fini_trapezoid_shader(screen); diff --git a/glamor/glamor_core.c b/glamor/glamor_core.c index 0144890..63cb4bf 100644 --- a/glamor/glamor_core.c +++ b/glamor/glamor_core.c @@ -423,10 +423,10 @@ GCOps glamor_gc_ops = { .FillPolygon = miFillPolygon, .PolyFillRect = glamor_polyfillrect, .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 = glamor_image_glyph_blt, //miImageGlyphBlt, .PolyGlyphBlt = glamor_poly_glyph_blt, //miPolyGlyphBlt, .PushPixels = glamor_push_pixels, //miPushPixels, diff --git a/glamor/glamor_font.c b/glamor/glamor_font.c new file mode 100644 index 0000000..4f303b9 --- /dev/null +++ b/glamor/glamor_font.c @@ -0,0 +1,181 @@ +/* + * 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->has_default = (count != 0); + + 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]; + + /* XXX actually unrealize the font */ + 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 0000000..8a7e63f --- /dev/null +++ b/glamor/glamor_font.h @@ -0,0 +1,47 @@ +/* + * 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; + Bool has_default; + + 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 cb07048..f5b9d13 100644 --- a/glamor/glamor_priv.h +++ b/glamor/glamor_priv.h @@ -235,6 +235,11 @@ typedef struct glamor_screen_private { /* glamor rect shaders */ glamor_program_fill poly_fill_rect_program; + /* 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. */ @@ -987,6 +992,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_fini_fillspans_shader(ScreenPtr screen); @@ -1079,4 +1097,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 0000000..3e795bc --- /dev/null +++ b/glamor/glamor_text.c @@ -0,0 +1,488 @@ +/* + * 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 n; + int c; + if (sixteen) { + if (glamor_font->has_default) { + GetGlyphs(font, (unsigned long) count, (unsigned char *) chars, + (FONTLASTROW(font) == 0) ? Linear16Bit : TwoD16Bit, + &n, charinfo); + } else { + for (c = 0; c < count; c++) { + GetGlyphs(font, 1, (unsigned char *) chars + 2*c, + (FONTLASTROW(font) == 0) ? Linear16Bit : TwoD16Bit, + &n, &charinfo[c]); + if (!n) + charinfo[c] = NULL; + } + } + } else { + if (glamor_font->has_default) { + GetGlyphs(font, (unsigned long) count, (unsigned char *) chars, + Linear8Bit, &n, charinfo); + } else { + for (c = 0; c < count; c++) { + GetGlyphs(font, 1, (unsigned char *) chars + c, + Linear8Bit, &n, &charinfo[c]); + if (!n) + charinfo[c] = NULL; + } + } + } +} + +/* + * Construct quads for the provided list of characters and draw them + */ + +#define GLYPHS_PER_DRAW 255 + +static int +glamor_text(DrawablePtr drawable, GCPtr gc, + glamor_font_t *glamor_font, + glamor_program *prog, + int x, int y, + int count, char *chars, CharInfoPtr *charinfo, + Bool sixteen) +{ + FontPtr font = gc->font; + int off_x, off_y; + int c; + int nbox; + BoxPtr box; + int g; + 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 */ + g = 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, col; + + x += ci->metrics.characterWidth; + + if (sixteen) { + row = *chars++; + col = *chars++; + if (FONTLASTROW(font) != 0) { + ty = (row - firstRow) * glyph_spacing_y; + } else { + col += row << 8; + row = 0; + } + } else + col = *chars++; + + 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; + g++; + } + } + glamor_put_vbo_space(drawable->pScreen); + + if (g) { + + glEnable(GL_SCISSOR_TEST); + + glamor_pixmap_loop(pixmap_priv, box_x, box_y) { + glamor_set_destination_drawable(drawable, box_x, box_y, TRUE, prog->matrix_uniform, &off_x, &off_y); + + /* Run over the clip list, drawing the glyphs + * in each box + */ + nbox = RegionNumRects(gc->pCompositeClip); + box = RegionRects(gc->pCompositeClip); + + 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, g); + } + } + glDisable(GL_SCISSOR_TEST); + } + + glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0); + glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); + glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0); + glDisableVertexAttribArray(GLAMOR_VERTEX_POS); + + return x; +} + +static const char vs_text[] = + "#version 130\n" + "in vec4 v_position;\n" // x,y,w,h + GLAMOR_DECLARE_MATRIX + "in vec2 v_texcoord0;\n" + "out vec2 tile_texture;\n" + "void main()\n" + "{\n" + " vec2 pos = v_position.zw * vec2(gl_VertexID&1, (gl_VertexID&2)>>1);\n" + GLAMOR_POS(gl_Position, (v_position.xy + pos)) + " tile_texture = v_texcoord0 + pos;\n" + "}\n"; + +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 int +glamor_poly_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; + 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; + + x = 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 x; + +bail: + if (sixteen) + return miPolyText16(drawable, gc, x, y, count, (unsigned short *) chars); + else + return miPolyText8(drawable, gc, x, y, count, chars); +} + +int +glamor_poly_text8(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, char *chars) +{ + return glamor_poly_text(drawable, gc, x, y, count, chars, FALSE); +} + +int +glamor_poly_text16(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, unsigned short *chars) +{ + return glamor_poly_text(drawable, gc, x, y, count, (char *) chars, TRUE); +} + +/* + * 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 const glamor_facet glamor_facet_null_fill = { + .name = "" +}; + +static Bool +use_image_solid(PixmapPtr pixmap, GCPtr gc, glamor_program *prog) +{ + 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) +{ + 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 = &glamor_facet_null_fill; + } 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); + + box.x1 = off_x + drawable->x + x; + box.x2 = off_x + drawable->x + x + width; + 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)) + 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: + glamor_put_context(glamor_priv); + return 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); +} + +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); +} + +void +glamor_fini_glyph_shader(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + + glamor_delete_program_fill(screen, &glamor_priv->poly_text_progs); + glamor_delete_program(screen, &glamor_priv->te_text_prog); + glamor_delete_program(screen, &glamor_priv->image_text_prog); +} + -- 1.9.0 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
