diff options
author | marha <marha@users.sourceforge.net> | 2015-05-15 19:14:42 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2015-05-15 19:14:42 +0200 |
commit | 843964ee791452b197e41dacb0146f5b456ffaa5 (patch) | |
tree | b1b0734c17ce1d488aa4d6e95f27363d80731e10 /xorg-server/glamor | |
parent | a71d524ecad48837e0124a03124bc05f59a48be7 (diff) | |
download | vcxsrv-843964ee791452b197e41dacb0146f5b456ffaa5.tar.gz vcxsrv-843964ee791452b197e41dacb0146f5b456ffaa5.tar.bz2 vcxsrv-843964ee791452b197e41dacb0146f5b456ffaa5.zip |
randrproto fontconfig libfontenc libxcb mesalib xserver pixman xkeyboard-config git update 15 May 2015
xserver commit bf6344e1913a5d24c2d68eaca999ea3d71e1b707
libxcb commit cb621341a62e6d2233db3e337611f6fdd4f675a6
libxcb/xcb-proto commit 4c550465934164aab2449a125f75f4ca07816233
xkeyboard-config commit 5da6d510b460cad1b31288618cc364e586576826
libX11 commit d3415d1f052530760b4617db45affcb984cfe35c
libXdmcp commit b10f382e3aa2e86cd5a2bc27d6758da55f0ab1f6
libXext commit efdcbb7634501e1117d422636a0a75d7ea84b16b
libfontenc commit 42f3a39c3085afd9ef904ae39102fd49bbc2e4a5
libXinerama commit edd95182b26eb5d576d4878c559e0f17dddaa909
libXau commit 1e4635be11154dd8262f37b379511bd627defa2a
xkbcomp commit 1ae525b3d236b59e6437b2b5433d460e18370973
pixman commit 82f9b4faaf1aa63ec26b0dfd227f1a8e5e139ae2
xextproto commit 66afec3f49e8eb0d4c2e9af7088fc3116d4bafd7
randrproto commit 895ee5264524c7c239ee4ef5e39c4e295323fb51
glproto commit bd3d751e1eb17efb39f65093271bb4ac071aa9e0
mkfontscale commit 87d628f8eec170ec13bb9feefb1ce05aed07d1d6
xwininfo commit 0c49f8f2bd56b1e77721e81030ea948386dcdf4e
libXft commit e8a83226bc10afb587f6f34daac44d2ef809c85e
libXmu commit 4459e6940fe3fdf26a8d5d4c71989498bc400a62
libxtrans commit 7cbad9fe2e61cd9d5caeaf361826a6f4bd320f03
fontconfig commit 55ff8419274fd5ce59675f220b85035a3986d6cf
mesa commit 3687d752e51829b4723c9abb07ae56d2bbcda570
Diffstat (limited to 'xorg-server/glamor')
24 files changed, 1011 insertions, 2054 deletions
diff --git a/xorg-server/glamor/Makefile.am b/xorg-server/glamor/Makefile.am index db72cb11c..c48802999 100644 --- a/xorg-server/glamor/Makefile.am +++ b/xorg-server/glamor/Makefile.am @@ -14,7 +14,7 @@ libglamor_la_SOURCES = \ glamor_font.c \ glamor_font.h \ glamor_glx.c \ - glamor_glyphs.c \ + glamor_composite_glyphs.c \ glamor_image.c \ glamor_lines.c \ glamor_segs.c \ diff --git a/xorg-server/glamor/glamor.c b/xorg-server/glamor/glamor.c index 6f4f30927..807f28ebd 100644 --- a/xorg-server/glamor/glamor.c +++ b/xorg-server/glamor/glamor.c @@ -1,5 +1,5 @@ /* - * Copyright © 2008 Intel Corporation + * Copyright © 2008,2011 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -23,7 +23,7 @@ * Authors: * Eric Anholt <eric@anholt.net> * Zhigang Gong <zhigang.gong@linux.intel.com> - * + * Chad Versace <chad.versace@linux.intel.com> */ /** @file glamor.c @@ -288,16 +288,6 @@ glamor_create_screen_resources(ScreenPtr screen) ret = screen->CreateScreenResources(screen); screen->CreateScreenResources = glamor_create_screen_resources; - if (!glamor_glyphs_init(screen)) { - ErrorF("Failed to initialize glyphs\n"); - ret = FALSE; - } - - if (!glamor_realize_glyph_caches(screen)) { - ErrorF("Failed to initialize glyph cache\n"); - ret = FALSE; - } - return ret; } @@ -336,7 +326,11 @@ glamor_init(ScreenPtr screen, unsigned int flags) { glamor_screen_private *glamor_priv; int gl_version; + int glsl_major, glsl_minor; int max_viewport_size[2]; + const char *shading_version_string; + int shading_version_offset; + PictureScreenPtr ps = GetPictureScreenIfSet(screen); if (flags & ~GLAMOR_VALID_FLAGS) { @@ -380,14 +374,40 @@ glamor_init(ScreenPtr screen, unsigned int flags) gl_version = epoxy_gl_version(); - /* Would be nice to have a cleaner test for GLSL 1.30 support, - * but for now this should suffice - */ - if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP && gl_version >= 30) - glamor_priv->glsl_version = 130; - else - glamor_priv->glsl_version = 120; + shading_version_string = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION); + + if (!shading_version_string) { + LogMessage(X_WARNING, + "glamor%d: Failed to get GLSL version\n", + screen->myNum); + goto fail; + } + + shading_version_offset = 0; + if (strncmp("OpenGL ES GLSL ES ", shading_version_string, 18) == 0) + shading_version_offset = 18; + if (sscanf(shading_version_string + shading_version_offset, + "%i.%i", + &glsl_major, + &glsl_minor) != 2) { + LogMessage(X_WARNING, + "glamor%d: Failed to parse GLSL version string %s\n", + screen->myNum, shading_version_string); + goto fail; + } + glamor_priv->glsl_version = glsl_major * 100 + glsl_minor; + + if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) { + /* Force us back to the base version of our programs on an ES + * context, anyway. Basically glamor only uses desktop 1.20 + * or 1.30 currently. 1.30's new features are also present in + * ES 3.0, but our glamor_program.c constructions use a lot of + * compatibility features (to reduce the diff between 1.20 and + * 1.30 programs). + */ + glamor_priv->glsl_version = 120; + } /* We'd like to require GL_ARB_map_buffer_range or * GL_OES_map_buffer_range, since it offers more information to @@ -479,6 +499,11 @@ glamor_init(ScreenPtr screen, unsigned int flags) glamor_priv->saved_procs.block_handler = screen->BlockHandler; screen->BlockHandler = _glamor_block_handler; + if (!glamor_composite_glyphs_init(screen)) { + ErrorF("Failed to initialize composite masks\n"); + goto fail; + } + glamor_priv->saved_procs.create_gc = screen->CreateGC; screen->CreateGC = glamor_create_gc; @@ -520,10 +545,7 @@ glamor_init(ScreenPtr screen, unsigned int flags) ps->CompositeRects = miCompositeRects; glamor_priv->saved_procs.glyphs = ps->Glyphs; - ps->Glyphs = glamor_glyphs; - - glamor_priv->saved_procs.unrealize_glyph = ps->UnrealizeGlyph; - ps->UnrealizeGlyph = glamor_glyph_unrealize; + ps->Glyphs = glamor_composite_glyphs; glamor_priv->saved_procs.create_picture = ps->CreatePicture; ps->CreatePicture = glamor_create_picture; @@ -604,7 +626,7 @@ glamor_close_screen(ScreenPtr screen) glamor_priv = glamor_get_screen_private(screen); glamor_sync_close(screen); - glamor_glyphs_fini(screen); + glamor_composite_glyphs_fini(screen); screen->CloseScreen = glamor_priv->saved_procs.close_screen; screen->CreateScreenResources = glamor_priv->saved_procs.create_screen_resources; @@ -625,7 +647,6 @@ glamor_close_screen(ScreenPtr screen) ps->CreatePicture = glamor_priv->saved_procs.create_picture; ps->CompositeRects = glamor_priv->saved_procs.composite_rects; ps->Glyphs = glamor_priv->saved_procs.glyphs; - ps->UnrealizeGlyph = glamor_priv->saved_procs.unrealize_glyph; screen->SetWindowPixmap = glamor_priv->saved_procs.set_window_pixmap; screen_pixmap = screen->GetScreenPixmap(screen); diff --git a/xorg-server/glamor/glamor.h b/xorg-server/glamor/glamor.h index d07182d9e..0d57fff88 100644 --- a/xorg-server/glamor/glamor.h +++ b/xorg-server/glamor/glamor.h @@ -105,8 +105,6 @@ extern _X_EXPORT void glamor_set_screen_pixmap(PixmapPtr screen_pixmap, extern _X_EXPORT uint32_t glamor_get_pixmap_texture(PixmapPtr pixmap); -extern _X_EXPORT Bool glamor_glyphs_init(ScreenPtr pScreen); - extern _X_EXPORT void glamor_set_pixmap_texture(PixmapPtr pixmap, unsigned int tex); diff --git a/xorg-server/glamor/glamor_composite_glyphs.c b/xorg-server/glamor/glamor_composite_glyphs.c new file mode 100644 index 000000000..39ed854bc --- /dev/null +++ b/xorg-server/glamor/glamor_composite_glyphs.c @@ -0,0 +1,551 @@ +/* + * 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 <stdlib.h> +#include "Xprintf.h" + +#include "glamor_priv.h" +#include "glamor_transform.h" +#include "glamor_transfer.h" + +#include <mipict.h> + +#define DEFAULT_ATLAS_DIM 1024 + +static DevPrivateKeyRec glamor_glyph_private_key; + +struct glamor_glyph_private { + int16_t x; + int16_t y; + uint32_t serial; +}; + +struct glamor_glyph_atlas { + PixmapPtr atlas; + PictFormatPtr format; + int x, y; + int row_height; + int nglyph; + uint32_t serial; +}; + +static inline struct glamor_glyph_private *glamor_get_glyph_private(PixmapPtr pixmap) { + return dixLookupPrivate(&pixmap->devPrivates, &glamor_glyph_private_key); +} + +static inline void +glamor_copy_glyph(PixmapPtr glyph_pixmap, + DrawablePtr atlas_draw, + int16_t x, + int16_t y) +{ + DrawablePtr glyph_draw = &glyph_pixmap->drawable; + BoxRec box = { + .x1 = 0, + .y1 = 0, + .x2 = glyph_draw->width, + .y2 = glyph_draw->height, + }; + + if (glyph_pixmap->drawable.bitsPerPixel == atlas_draw->bitsPerPixel) { + glamor_upload_boxes((PixmapPtr) atlas_draw, + &box, 1, + 0, 0, + x, y, + glyph_pixmap->devPrivate.ptr, + glyph_pixmap->devKind); + } else { + GCPtr scratch_gc = GetScratchGC(atlas_draw->depth, atlas_draw->pScreen); + ChangeGCVal changes[2]; + if (!scratch_gc) + return; + + /* If we're dealing with 1-bit glyphs, we upload them to + * the cache as normal 8-bit alpha, since that's what GL + * can handle. + */ + assert(glyph_draw->depth == 1); + assert(atlas_draw->depth == 8); + + changes[0].val = 0xff; + changes[1].val = 0x00; + if (ChangeGC(NullClient, scratch_gc, + GCForeground|GCBackground, changes) != Success) + goto bail_gc; + ValidateGC(atlas_draw, scratch_gc); + + (*scratch_gc->ops->CopyPlane)(glyph_draw, + atlas_draw, + scratch_gc, + 0, 0, + glyph_draw->width, + glyph_draw->height, + x, y, 0x1); + + bail_gc: + FreeScratchGC(scratch_gc); + } +} + +static Bool +glamor_glyph_atlas_init(ScreenPtr screen, struct glamor_glyph_atlas *atlas) +{ + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + PictFormatPtr format = atlas->format; + + atlas->atlas = glamor_create_pixmap(screen, glamor_priv->glyph_atlas_dim, + glamor_priv->glyph_atlas_dim, format->depth, 0); + atlas->x = 0; + atlas->y = 0; + atlas->row_height = 0; + atlas->serial++; + atlas->nglyph = 0; + return TRUE; +} + +static Bool +glamor_glyph_can_add(struct glamor_glyph_atlas *atlas, int dim, DrawablePtr glyph_draw) +{ + /* Step down */ + if (atlas->x + glyph_draw->width > dim) { + atlas->x = 0; + atlas->y += atlas->row_height; + atlas->row_height = 0; + } + + /* Check for overfull */ + if (atlas->y + glyph_draw->height > dim) + return FALSE; + + return TRUE; +} + +static Bool +glamor_glyph_add(struct glamor_glyph_atlas *atlas, DrawablePtr glyph_draw) +{ + PixmapPtr glyph_pixmap = (PixmapPtr) glyph_draw; + struct glamor_glyph_private *glyph_priv = glamor_get_glyph_private(glyph_pixmap); + + glamor_copy_glyph(glyph_pixmap, &atlas->atlas->drawable, atlas->x, atlas->y); + + glyph_priv->x = atlas->x; + glyph_priv->y = atlas->y; + glyph_priv->serial = atlas->serial; + + atlas->x += glyph_draw->width; + if (atlas->row_height < glyph_draw->height) + atlas->row_height = glyph_draw->height; + + atlas->nglyph++; + + return TRUE; +} + +static const glamor_facet glamor_facet_composite_glyphs_130 = { + .name = "composite_glyphs", + .version = 130, + .vs_vars = ("attribute vec4 primitive;\n" + "attribute vec2 source;\n" + "varying vec2 glyph_pos;\n"), + .vs_exec = (" vec2 pos = primitive.zw * vec2(gl_VertexID&1, (gl_VertexID&2)>>1);\n" + GLAMOR_POS(gl_Position, (primitive.xy + pos)) + " glyph_pos = (source + pos) * ATLAS_DIM_INV;\n"), + .fs_vars = ("varying vec2 glyph_pos;\n"), + .fs_exec = (" vec4 mask = texture2D(atlas, glyph_pos);\n"), + .source_name = "source", + .locations = glamor_program_location_atlas, +}; + +static const glamor_facet glamor_facet_composite_glyphs_120 = { + .name = "composite_glyphs", + .vs_vars = ("attribute vec2 primitive;\n" + "attribute vec2 source;\n" + "varying vec2 glyph_pos;\n"), + .vs_exec = (GLAMOR_POS(gl_Position, primitive) + " glyph_pos = source.xy * ATLAS_DIM_INV;\n"), + .fs_vars = ("varying vec2 glyph_pos;\n"), + .fs_exec = (" vec4 mask = texture2D(atlas, glyph_pos);\n"), + .source_name = "source", + .locations = glamor_program_location_atlas, +}; + +static inline Bool +glamor_glyph_use_130(glamor_screen_private *glamor_priv) { + return glamor_priv->glsl_version >= 130; +} + +static Bool +glamor_glyphs_init_facet(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + + return asprintf(&glamor_priv->glyph_defines, "#define ATLAS_DIM_INV %20.18f\n", 1.0/glamor_priv->glyph_atlas_dim) > 0; +} + +static void +glamor_glyphs_fini_facet(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + + free(glamor_priv->glyph_defines); +} + +static void +glamor_glyphs_flush(CARD8 op, PicturePtr src, PicturePtr dst, + glamor_program *prog, + struct glamor_glyph_atlas *atlas, int nglyph) +{ + DrawablePtr drawable = dst->pDrawable; + glamor_screen_private *glamor_priv = glamor_get_screen_private(drawable->pScreen); + PixmapPtr atlas_pixmap = atlas->atlas; + glamor_pixmap_private *atlas_priv = glamor_get_pixmap_private(atlas_pixmap); + glamor_pixmap_fbo *atlas_fbo = glamor_pixmap_fbo_at(atlas_priv, 0, 0); + PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); + glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); + int box_x, box_y; + int off_x, off_y; + + glamor_put_vbo_space(drawable->pScreen); + + glEnable(GL_SCISSOR_TEST); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, atlas_fbo->tex); + + for (;;) { + if (!glamor_use_program_render(prog, op, src, dst)) + break; + + glUniform1i(prog->atlas_uniform, 1); + + glamor_pixmap_loop(pixmap_priv, box_x, box_y) { + BoxPtr box = RegionRects(dst->pCompositeClip); + int nbox = RegionNumRects(dst->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++; + + if (glamor_glyph_use_130(glamor_priv)) + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nglyph); + else + glamor_glDrawArrays_GL_QUADS(glamor_priv, nglyph * 4); + } + } + if (prog->alpha != glamor_program_alpha_ca_first) + break; + prog++; + } + + glDisable(GL_SCISSOR_TEST); + + glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0); + glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); + glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0); + glDisableVertexAttribArray(GLAMOR_VERTEX_POS); + glDisable(GL_BLEND); +} + +static GLshort * +glamor_glyph_start(ScreenPtr screen, int count) +{ + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + GLshort *v; + char *vbo_offset; + + /* Set up the vertex buffers for the font and destination */ + + if (glamor_glyph_use_130(glamor_priv)) { + v = glamor_get_vbo_space(screen, 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)); + } else { + v = glamor_get_vbo_space(screen, count * (16 * sizeof (GLshort)), &vbo_offset); + + glEnableVertexAttribArray(GLAMOR_VERTEX_POS); + glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE, + 4 * sizeof (GLshort), vbo_offset); + + glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE); + glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_SHORT, GL_FALSE, + 4 * sizeof (GLshort), vbo_offset + 2 * sizeof (GLshort)); + } + return v; +} + +static inline struct glamor_glyph_atlas * +glamor_atlas_for_glyph(glamor_screen_private *glamor_priv, DrawablePtr drawable) +{ + if (drawable->depth == 32) + return glamor_priv->glyph_atlas_argb; + else + return glamor_priv->glyph_atlas_a; +} + +void +glamor_composite_glyphs(CARD8 op, + PicturePtr src, + PicturePtr dst, + PictFormatPtr glyph_format, + INT16 x_src, + INT16 y_src, int nlist, GlyphListPtr list, + GlyphPtr *glyphs) +{ + int glyphs_queued; + GLshort *v = NULL; + DrawablePtr drawable = dst->pDrawable; + ScreenPtr screen = drawable->pScreen; + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + glamor_program *prog = NULL; + PicturePtr glyph_pict = NULL; + DrawablePtr glyph_draw; + glamor_program_render *glyphs_program = &glamor_priv->glyphs_program; + struct glamor_glyph_atlas *glyph_atlas = NULL; + int x = 0, y = 0; + int n; + int glyph_atlas_dim = glamor_priv->glyph_atlas_dim; + int glyph_max_dim = glamor_priv->glyph_max_dim; + int nglyph = 0; + int screen_num = screen->myNum; + + for (n = 0; n < nlist; n++) + nglyph += list[n].len; + + glamor_make_current(glamor_priv); + + glyphs_queued = 0; + + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + list++; + while (n--) { + GlyphPtr glyph = *glyphs++; + + /* Glyph not empty? + */ + if (glyph->info.width && glyph->info.height) { + glamor_pixmap_private *glyph_pix_priv; + + glyph_pict = GlyphPicture(glyph)[screen_num]; + glyph_draw = glyph_pict->pDrawable; + glyph_pix_priv = glamor_get_pixmap_private((PixmapPtr) glyph_draw); + + /* Need to draw with slow path? + */ + if (_X_UNLIKELY(glyph_draw->width > glyph_max_dim || + glyph_draw->height > glyph_max_dim || + (glyph_pix_priv != 0 && glyph_pix_priv->type != GLAMOR_MEMORY))) + { + if (glyphs_queued) { + glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued); + glyphs_queued = 0; + } + bail_one: + glamor_composite(op, src, glyph_pict, dst, + x_src + (x - glyph->info.x), (y - glyph->info.y), + 0, 0, + x - glyph->info.x, y - glyph->info.y, + glyph_draw->width, glyph_draw->height); + } else { + struct glamor_glyph_private *glyph_priv = glamor_get_glyph_private((PixmapPtr)(glyph_draw)); + struct glamor_glyph_atlas *next_atlas = glamor_atlas_for_glyph(glamor_priv, glyph_draw); + + /* Switching source glyph format? + */ + if (_X_UNLIKELY(next_atlas != glyph_atlas)) { + if (glyphs_queued) { + glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued); + glyphs_queued = 0; + } + glyph_atlas = next_atlas; + } + + /* Glyph not cached in current atlas? + */ + if (_X_UNLIKELY(glyph_priv->serial != glyph_atlas->serial)) { + if (!glamor_glyph_can_add(glyph_atlas, glyph_atlas_dim, glyph_draw)) { + if (glyphs_queued) { + glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued); + glyphs_queued = 0; + } + if (glyph_atlas->atlas) { + (*screen->DestroyPixmap)(glyph_atlas->atlas); + glyph_atlas->atlas = NULL; + } + } + if (!glyph_atlas->atlas) + glamor_glyph_atlas_init(screen, glyph_atlas); + glamor_glyph_add(glyph_atlas, glyph_draw); + } + + /* First glyph in the current atlas? + */ + if (_X_UNLIKELY(glyphs_queued == 0)) { + if (glamor_glyph_use_130(glamor_priv)) + prog = glamor_setup_program_render(op, src, glyph_pict, dst, + glyphs_program, + &glamor_facet_composite_glyphs_130, + glamor_priv->glyph_defines); + else + prog = glamor_setup_program_render(op, src, glyph_pict, dst, + glyphs_program, + &glamor_facet_composite_glyphs_120, + glamor_priv->glyph_defines); + if (!prog) + goto bail_one; + v = glamor_glyph_start(screen, nglyph); + } + + /* Add the glyph + */ + + glyphs_queued++; + if (_X_LIKELY(glamor_glyph_use_130(glamor_priv))) { + v[0] = x - glyph->info.x; + v[1] = y - glyph->info.y; + v[2] = glyph_draw->width; + v[3] = glyph_draw->height; + v[4] = glyph_priv->x; + v[5] = glyph_priv->y; + v += 6; + } else { + v[0] = x - glyph->info.x; + v[1] = y - glyph->info.y; + v[2] = glyph_priv->x; + v[3] = glyph_priv->y; + v += 4; + + v[0] = x - glyph->info.x + glyph_draw->width; + v[1] = y - glyph->info.y; + v[2] = glyph_priv->x + glyph_draw->width; + v[3] = glyph_priv->y; + v += 4; + + v[0] = x - glyph->info.x + glyph_draw->width; + v[1] = y - glyph->info.y + glyph_draw->height; + v[2] = glyph_priv->x + glyph_draw->width; + v[3] = glyph_priv->y + glyph_draw->height; + v += 4; + + v[0] = x - glyph->info.x; + v[1] = y - glyph->info.y + glyph_draw->height; + v[2] = glyph_priv->x; + v[3] = glyph_priv->y + glyph_draw->height; + v += 4; + } + } + } + x += glyph->info.xOff; + y += glyph->info.yOff; + nglyph--; + } + } + + if (glyphs_queued) + glamor_glyphs_flush(op, src, dst, prog, glyph_atlas, glyphs_queued); + + return; +} + +static struct glamor_glyph_atlas * +glamor_alloc_glyph_atlas(ScreenPtr screen, int depth, CARD32 f) +{ + PictFormatPtr format; + struct glamor_glyph_atlas *glyph_atlas; + + format = PictureMatchFormat(screen, depth, f); + if (!format) + return NULL; + glyph_atlas = calloc (1, sizeof (struct glamor_glyph_atlas)); + if (!glyph_atlas) + return NULL; + glyph_atlas->format = format; + glyph_atlas->serial = 1; + + return glyph_atlas; +} + +Bool +glamor_composite_glyphs_init(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + + if (!dixRegisterPrivateKey(&glamor_glyph_private_key, PRIVATE_PIXMAP, sizeof (struct glamor_glyph_private))) + return FALSE; + + /* Make glyph atlases of a reasonable size, but no larger than the maximum + * supported by the hardware + */ + glamor_priv->glyph_atlas_dim = MIN(DEFAULT_ATLAS_DIM, glamor_priv->max_fbo_size); + + /* Don't stick huge glyphs in the atlases */ + glamor_priv->glyph_max_dim = glamor_priv->glyph_atlas_dim / 8; + + glamor_priv->glyph_atlas_a = glamor_alloc_glyph_atlas(screen, 8, PICT_a8); + if (!glamor_priv->glyph_atlas_a) + return FALSE; + glamor_priv->glyph_atlas_argb = glamor_alloc_glyph_atlas(screen, 32, PICT_a8r8g8b8); + if (!glamor_priv->glyph_atlas_argb) { + free (glamor_priv->glyph_atlas_a); + return FALSE; + } + if (!glamor_glyphs_init_facet(screen)) + return FALSE; + return TRUE; +} + +static void +glamor_free_glyph_atlas(struct glamor_glyph_atlas *atlas) +{ + if (!atlas) + return; + if (atlas->atlas) + FreePicture(atlas->atlas, 0); + free (atlas); +} + +void +glamor_composite_glyphs_fini(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + + glamor_glyphs_fini_facet(screen); + glamor_free_glyph_atlas(glamor_priv->glyph_atlas_a); + glamor_free_glyph_atlas(glamor_priv->glyph_atlas_argb); +} diff --git a/xorg-server/glamor/glamor_compositerects.c b/xorg-server/glamor/glamor_compositerects.c index e188d8a3f..885a6c065 100644 --- a/xorg-server/glamor/glamor_compositerects.c +++ b/xorg-server/glamor/glamor_compositerects.c @@ -57,7 +57,7 @@ _pixman_region_init_clipped_rectangles(pixman_region16_t * region, unsigned int i, j; if (num_rects > ARRAY_SIZE(stack_boxes)) { - boxes = malloc(sizeof(pixman_box16_t) * num_rects); + boxes = xallocarray(num_rects, sizeof(pixman_box16_t)); if (boxes == NULL) return FALSE; } diff --git a/xorg-server/glamor/glamor_copy.c b/xorg-server/glamor/glamor_copy.c index 75fe8a700..028acf239 100644 --- a/xorg-server/glamor/glamor_copy.c +++ b/xorg-server/glamor/glamor_copy.c @@ -53,7 +53,7 @@ static const glamor_facet glamor_facet_copyarea = { .vs_exec = (GLAMOR_POS(gl_Position, primitive.xy) " fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"), .fs_exec = " gl_FragColor = texture2D(sampler, fill_pos);\n", - .locations = glamor_program_location_fill, + .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos, .use = use_copyarea, }; @@ -140,7 +140,7 @@ static const glamor_facet glamor_facet_copyplane = { " gl_FragColor = fg;\n" " else\n" " gl_FragColor = bg;\n"), - .locations = glamor_program_location_fill|glamor_program_location_fg|glamor_program_location_bg|glamor_program_location_bitplane, + .locations = glamor_program_location_fillsamp|glamor_program_location_fillpos|glamor_program_location_fg|glamor_program_location_bg|glamor_program_location_bitplane, .use = use_copyplane, }; @@ -212,7 +212,7 @@ glamor_copy_cpu_fbo(DrawablePtr src, if (gc && gc->alu != GXcopy) goto bail; - if (gc && !glamor_pm_is_solid(dst, gc->planemask)) + if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask)) goto bail; glamor_make_current(glamor_priv); @@ -262,7 +262,7 @@ glamor_copy_fbo_cpu(DrawablePtr src, if (gc && gc->alu != GXcopy) goto bail; - if (gc && !glamor_pm_is_solid(dst, gc->planemask)) + if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask)) goto bail; glamor_make_current(glamor_priv); @@ -319,7 +319,7 @@ glamor_copy_fbo_fbo_draw(DrawablePtr src, glamor_make_current(glamor_priv); - if (gc && !glamor_set_planemask(dst_pixmap, gc->planemask)) + if (gc && !glamor_set_planemask(gc->depth, gc->planemask)) goto bail_ctx; if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy)) @@ -338,7 +338,7 @@ glamor_copy_fbo_fbo_draw(DrawablePtr src, if (!prog->prog) { if (!glamor_build_program(screen, prog, - copy_facet, NULL)) + copy_facet, NULL, NULL, NULL)) goto bail_ctx; } @@ -419,7 +419,6 @@ glamor_copy_fbo_fbo_temp(DrawablePtr src, { ScreenPtr screen = dst->pScreen; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); - PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst); PixmapPtr tmp_pixmap; BoxRec bounds; int n; @@ -434,7 +433,7 @@ glamor_copy_fbo_fbo_temp(DrawablePtr src, */ glamor_make_current(glamor_priv); - if (gc && !glamor_set_planemask(dst_pixmap, gc->planemask)) + if (gc && !glamor_set_planemask(gc->depth, gc->planemask)) goto bail_ctx; if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy)) diff --git a/xorg-server/glamor/glamor_core.c b/xorg-server/glamor/glamor_core.c index 55174541f..965024e68 100644 --- a/xorg-server/glamor/glamor_core.c +++ b/xorg-server/glamor/glamor_core.c @@ -35,7 +35,7 @@ #include "glamor_priv.h" -const Bool +Bool glamor_get_drawable_location(const DrawablePtr drawable) { PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); diff --git a/xorg-server/glamor/glamor_dash.c b/xorg-server/glamor/glamor_dash.c index 4281ff0a8..101228e40 100644 --- a/xorg-server/glamor/glamor_dash.c +++ b/xorg-server/glamor/glamor_dash.c @@ -170,7 +170,7 @@ glamor_dash_setup(DrawablePtr drawable, GCPtr gc) if (!prog->prog) { if (!glamor_build_program(screen, prog, &glamor_facet_double_dash_lines, - NULL)) + NULL, NULL, NULL)) goto bail; } diff --git a/xorg-server/glamor/glamor_egl.c b/xorg-server/glamor/glamor_egl.c index 6033780f8..dc5456118 100644 --- a/xorg-server/glamor/glamor_egl.c +++ b/xorg-server/glamor/glamor_egl.c @@ -595,6 +595,7 @@ glamor_egl_close_screen(ScreenPtr screen) return screen->CloseScreen(screen); } +#ifdef DRI3 static int glamor_dri3_open_client(ClientPtr client, ScreenPtr screen, @@ -651,12 +652,12 @@ static dri3_screen_info_rec glamor_dri3_info = { .pixmap_from_fd = glamor_pixmap_from_fd, .fd_from_pixmap = glamor_fd_from_pixmap, }; +#endif /* DRI3 */ void glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) { ScrnInfoPtr scrn = xf86ScreenToScrn(screen); - glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); struct glamor_egl_screen_private *glamor_egl = glamor_egl_get_screen_private(scrn); @@ -668,7 +669,9 @@ glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) glamor_ctx->make_current = glamor_egl_make_current; +#ifdef DRI3 if (glamor_egl->dri3_capable) { + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); /* Tell the core that we have the interfaces for import/export * of pixmaps. */ @@ -691,6 +694,7 @@ glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) } } } +#endif } static void diff --git a/xorg-server/glamor/glamor_glyphs.c b/xorg-server/glamor/glamor_glyphs.c deleted file mode 100644 index 2cf0c7d16..000000000 --- a/xorg-server/glamor/glamor_glyphs.c +++ /dev/null @@ -1,1769 +0,0 @@ -/* - * Copyright © 2008 Red Hat, Inc. - * Partly based on code Copyright © 2000 SuSE, Inc. - * - * 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 Red Hat not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. Red Hat makes no representations about the - * suitability of this software for any purpose. It is provided "as is" - * without express or implied warranty. - * - * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat - * 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. - * - * 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 SuSE not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. SuSE makes no representations about the - * suitability of this software for any purpose. It is provided "as is" - * without express or implied warranty. - * - * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE - * 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. - * - * Author: Owen Taylor <otaylor@fishsoup.net> - * Based on code by: Keith Packard - */ - -#include <stdlib.h> - -#include "glamor_priv.h" - -#include <mipict.h> - -#if DEBUG_GLYPH_CACHE -#define DBG_GLYPH_CACHE(a) ErrorF a -#else -#define DBG_GLYPH_CACHE(a) -#endif - -/* Width of the pixmaps we use for the caches; this should be less than - * max texture size of the driver; this may need to actually come from - * the driver. - */ - -/* Maximum number of glyphs we buffer on the stack before flushing - * rendering to the mask or destination surface. - */ -#define GLYPH_BUFFER_SIZE 1024 - -typedef struct { - PicturePtr source; - glamor_composite_rect_t rects[GLYPH_BUFFER_SIZE + 4]; - int count; -} glamor_glyph_buffer_t; - -struct glamor_glyph { - glamor_glyph_cache_t *cache; - uint16_t x, y; - uint16_t size, pos; - unsigned long long left_x1_map, left_x2_map; - unsigned long long right_x1_map, right_x2_map; /* Use to check real intersect or not. */ - Bool has_edge_map; - Bool cached; -}; - -typedef enum { - GLAMOR_GLYPH_SUCCESS, /* Glyph added to render buffer */ - GLAMOR_GLYPH_FAIL, /* out of memory, etc */ - GLAMOR_GLYPH_NEED_FLUSH, /* would evict a glyph already in the buffer */ -} glamor_glyph_cache_result_t; - -#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) -static DevPrivateKeyRec glamor_glyph_key; - -static inline struct glamor_glyph * -glamor_glyph_get_private(ScreenPtr screen, GlyphPtr glyph) -{ - struct glamor_glyph *privates = (struct glamor_glyph*)glyph->devPrivates; - - return &privates[screen->myNum]; -} - -/* - * Mask cache is located at the corresponding cache picture's last row. - * and is deadicated for the mask picture when do the glyphs_via_mask. - * - * As we split the glyphs list according to its overlapped or non-overlapped, - * we can reduce the length of glyphs to do the glyphs_via_mask to 2 or 3 - * glyphs one time for most cases. Thus it give us a case to allocate a - * small portion of the corresponding cache directly as the mask picture. - * Then we can rendering the glyphs to this mask picture, and latter we - * can accumulate the second steps, composite the mask to the dest with - * the other non-overlapped glyphs's rendering process. - * Another major benefit is we now only need to clear a relatively small mask - * region then before. It also make us implement a bunch mask picture clearing - * algorithm to avoid too frequently small region clearing. - * - * If there is no any overlapping, this method will not get performance gain. - * If there is some overlapping, then this algorithm can get about 15% performance - * gain. - */ - -static void -clear_mask_cache_bitmap(glamor_glyph_mask_cache_t *maskcache, - unsigned int clear_mask_bits) -{ - unsigned int i = 0; - BoxRec box[MASK_CACHE_WIDTH]; - int box_cnt = 0; - - assert((clear_mask_bits & ~MASK_CACHE_MASK) == 0); - for (i = 0; i < MASK_CACHE_WIDTH; i++) { - if (clear_mask_bits & (1 << i)) { - box[box_cnt].x1 = maskcache->mcache[i].x; - box[box_cnt].x2 = maskcache->mcache[i].x + MASK_CACHE_MAX_SIZE; - box[box_cnt].y1 = maskcache->mcache[i].y; - box[box_cnt].y2 = maskcache->mcache[i].y + MASK_CACHE_MAX_SIZE; - box_cnt++; - } - } - glamor_solid_boxes(maskcache->pixmap, box, box_cnt, 0); - maskcache->cleared_bitmap |= clear_mask_bits; -} - -static void -clear_mask_cache(glamor_glyph_mask_cache_t *maskcache) -{ - int x = 0; - int cnt = MASK_CACHE_WIDTH; - unsigned int i = 0; - struct glamor_glyph_mask_cache_entry *mce; - - glamor_solid(maskcache->pixmap, 0, CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE, - MASK_CACHE_MAX_SIZE, 0); - mce = &maskcache->mcache[0]; - while (cnt--) { - mce->width = 0; - mce->height = 0; - mce->x = x; - mce->y = CACHE_PICTURE_SIZE; - mce->idx = i++; - x += MASK_CACHE_MAX_SIZE; - mce++; - } - maskcache->free_bitmap = MASK_CACHE_MASK; - maskcache->cleared_bitmap = MASK_CACHE_MASK; -} - -static int -find_continuous_bits(unsigned int bits, int bits_cnt, unsigned int *pbits_mask) -{ - int idx = 0; - unsigned int bits_mask; - - bits_mask = ((1LL << bits_cnt) - 1); - - if (_X_UNLIKELY(bits_cnt > 56)) { - while (bits) { - if ((bits & bits_mask) == bits_mask) { - *pbits_mask = bits_mask << idx; - return idx; - } - bits >>= 1; - idx++; - } - } - else { - idx = __fls(bits); - while (bits) { - unsigned int temp_bits; - - temp_bits = bits_mask << (idx - bits_cnt + 1); - if ((bits & temp_bits) == temp_bits) { - *pbits_mask = temp_bits; - return (idx - bits_cnt + 1); - } - /* Find first zero. And clear the tested bit. */ - bits &= ~(1LL << idx); - idx = __fls(~bits); - bits &= ~((1LL << idx) - 1); - idx--; - } - } - return -1; -} - -static struct glamor_glyph_mask_cache_entry * -get_mask_cache(glamor_glyph_mask_cache_t *maskcache, int blocks) -{ - int free_cleared_bit, idx = -1; - int retry_cnt = 0; - unsigned int bits_mask = 0; - - if (maskcache->free_bitmap == 0) - return NULL; - retry: - free_cleared_bit = maskcache->free_bitmap & maskcache->cleared_bitmap; - if (free_cleared_bit && blocks == 1) { - idx = __fls(free_cleared_bit); - bits_mask = 1 << idx; - } - else if (free_cleared_bit && blocks > 1) { - idx = find_continuous_bits(free_cleared_bit, blocks, &bits_mask); - } - - if (idx < 0) { - clear_mask_cache_bitmap(maskcache, maskcache->free_bitmap); - if (retry_cnt++ > 2) - return NULL; - goto retry; - } - - maskcache->cleared_bitmap &= ~bits_mask; - maskcache->free_bitmap &= ~bits_mask; - DEBUGF("get idx %d free %x clear %x \n", - idx, maskcache->free_bitmap, maskcache->cleared_bitmap); - return &maskcache->mcache[idx]; -} - -static void -put_mask_cache_bitmap(glamor_glyph_mask_cache_t *maskcache, - unsigned int bitmap) -{ - maskcache->free_bitmap |= bitmap; - DEBUGF("put bitmap %x free %x clear %x \n", - bitmap, maskcache->free_bitmap, maskcache->cleared_bitmap); -} - -static void -glamor_unrealize_glyph_caches(ScreenPtr pScreen) -{ - glamor_screen_private *glamor = glamor_get_screen_private(pScreen); - int i; - - if (!glamor->glyph_caches_realized) - return; - - for (i = 0; i < GLAMOR_NUM_GLYPH_CACHE_FORMATS; i++) { - glamor_glyph_cache_t *cache = &glamor->glyphCaches[i]; - - if (cache->picture) - FreePicture(cache->picture, 0); - - if (cache->glyphs) - free(cache->glyphs); - - if (glamor->mask_cache[i]) - free(glamor->mask_cache[i]); - } - glamor->glyph_caches_realized = FALSE; -} - -void -glamor_glyphs_fini(ScreenPtr pScreen) -{ - glamor_unrealize_glyph_caches(pScreen); -} - -/* All caches for a single format share a single pixmap for glyph storage, - * allowing mixing glyphs of different sizes without paying a penalty - * for switching between source pixmaps. (Note that for a size of font - * right at the border between two sizes, we might be switching for almost - * every glyph.) - * - * This function allocates the storage pixmap, and then fills in the - * rest of the allocated structures for all caches with the given format. - */ - -Bool -glamor_realize_glyph_caches(ScreenPtr pScreen) -{ - glamor_screen_private *glamor = glamor_get_screen_private(pScreen); - - unsigned int formats[] = { - PIXMAN_a8, - PIXMAN_a8r8g8b8, - }; - int i; - - if (glamor->glyph_caches_realized) - return TRUE; - - memset(glamor->glyphCaches, 0, sizeof(glamor->glyphCaches)); - - for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { - glamor_glyph_cache_t *cache = &glamor->glyphCaches[i]; - PixmapPtr pixmap; - PicturePtr picture; - XID component_alpha; - int depth = PIXMAN_FORMAT_DEPTH(formats[i]); - int error; - PictFormatPtr pPictFormat = - PictureMatchFormat(pScreen, depth, formats[i]); - if (!pPictFormat) - goto bail; - - /* Now allocate the pixmap and picture */ - pixmap = pScreen->CreatePixmap(pScreen, - CACHE_PICTURE_SIZE, - CACHE_PICTURE_SIZE + MASK_CACHE_MAX_SIZE, - depth, GLAMOR_CREATE_NO_LARGE); - if (!pixmap) - goto bail; - - component_alpha = NeedsComponent(pPictFormat->format); - picture = CreatePicture(0, &pixmap->drawable, pPictFormat, - CPComponentAlpha, &component_alpha, - serverClient, &error); - - pScreen->DestroyPixmap(pixmap); - if (!picture) - goto bail; - - ValidatePicture(picture); - - cache->picture = picture; - cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE); - if (!cache->glyphs) - goto bail; - - cache->evict = rand() % GLYPH_CACHE_SIZE; - glamor->mask_cache[i] = calloc(1, sizeof(*glamor->mask_cache[i])); - glamor->mask_cache[i]->pixmap = pixmap; - clear_mask_cache(glamor->mask_cache[i]); - } - assert(i == GLAMOR_NUM_GLYPH_CACHE_FORMATS); - - glamor->glyph_caches_realized = TRUE; - return TRUE; - - bail: - glamor_unrealize_glyph_caches(pScreen); - return FALSE; -} - -/** - * Called by glamor_create_screen_resources() to set up the glyph cache. - * - * This was previously required to be called by the drivers, but not - * as of the xserver 1.16 ABI. - */ -Bool -glamor_glyphs_init(ScreenPtr pScreen) -{ - if (!dixRegisterPrivateKey(&glamor_glyph_key, - PRIVATE_GLYPH, - screenInfo.numScreens * sizeof(struct glamor_glyph))) - return FALSE; - - return TRUE; -} - -/* The most efficient thing to way to upload the glyph to the screen - * is to use CopyArea; glamor pixmaps are always offscreen. - */ -static void -glamor_glyph_cache_upload_glyph(ScreenPtr screen, - glamor_glyph_cache_t *cache, - GlyphPtr glyph, int x, int y) -{ - PicturePtr pGlyphPicture = GlyphPicture(glyph)[screen->myNum]; - PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable; - PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable; - PixmapPtr scratch; - BoxRec box; - GCPtr gc; - - gc = GetScratchGC(pCachePixmap->drawable.depth, screen); - if (!gc) - return; - - ValidateGC(&pCachePixmap->drawable, gc); - - scratch = pGlyphPixmap; - if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) { - - scratch = glamor_create_pixmap(screen, - glyph->info.width, - glyph->info.height, - pCachePixmap->drawable.depth, 0); - if (scratch) { - PicturePtr picture; - int error; - - picture = - CreatePicture(0, - &scratch->drawable, - PictureMatchFormat - (screen, - pCachePixmap->drawable.depth, - cache->picture->format), - 0, NULL, serverClient, &error); - if (picture) { - ValidatePicture(picture); - glamor_composite(PictOpSrc, - pGlyphPicture, - NULL, picture, - 0, 0, 0, 0, 0, - 0, glyph->info.width, glyph->info.height); - FreePicture(picture, 0); - } - } - else { - scratch = pGlyphPixmap; - } - } - - box.x1 = x; - box.y1 = y; - box.x2 = x + glyph->info.width; - box.y2 = y + glyph->info.height; - glamor_copy(&scratch->drawable, - &pCachePixmap->drawable, NULL, - &box, 1, -x, -y, FALSE, FALSE, 0, NULL); - if (scratch != pGlyphPixmap) - screen->DestroyPixmap(scratch); - - FreeScratchGC(gc); -} - -void -glamor_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph) -{ - struct glamor_glyph *priv; - - /* Use Lookup in case we have not attached to this glyph. */ - priv = glamor_glyph_get_private(screen, glyph); - - if (priv->cached) - priv->cache->glyphs[priv->pos] = NULL; -} - -/* Cut and paste from render/glyph.c - probably should export it instead */ -static void -glamor_glyph_extents(int nlist, - GlyphListPtr list, GlyphPtr *glyphs, BoxPtr extents) -{ - int x1, x2, y1, y2; - int x, y, n; - - x1 = y1 = MAXSHORT; - x2 = y2 = MINSHORT; - x = y = 0; - while (nlist--) { - x += list->xOff; - y += list->yOff; - n = list->len; - list++; - while (n--) { - GlyphPtr glyph = *glyphs++; - int v; - - v = x - glyph->info.x; - if (v < x1) - x1 = v; - v += glyph->info.width; - if (v > x2) - x2 = v; - - v = y - glyph->info.y; - if (v < y1) - y1 = v; - v += glyph->info.height; - if (v > y2) - y2 = v; - - x += glyph->info.xOff; - y += glyph->info.yOff; - } - } - - extents->x1 = x1 < MINSHORT ? MINSHORT : x1; - extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2; - extents->y1 = y1 < MINSHORT ? MINSHORT : y1; - extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2; -} - -static void -glamor_glyph_priv_get_edge_map(GlyphPtr glyph, struct glamor_glyph *priv, - PicturePtr glyph_picture) -{ - PixmapPtr glyph_pixmap = (PixmapPtr) glyph_picture->pDrawable; - int j; - unsigned long long left_x1_map = 0, left_x2_map = 0; - unsigned long long right_x1_map = 0, right_x2_map = 0; - int bitsPerPixel; - int stride; - void *bits; - int width; - unsigned int left_x1_data = 0, left_x2_data = 0; - unsigned int right_x1_data = 0, right_x2_data = 0; - - bitsPerPixel = glyph_pixmap->drawable.bitsPerPixel; - stride = glyph_pixmap->devKind; - bits = glyph_pixmap->devPrivate.ptr; - width = glyph->info.width; - - if (glyph_pixmap->drawable.width < 2 - || !(glyph_pixmap->drawable.depth == 8 - || glyph_pixmap->drawable.depth == 1 - || glyph_pixmap->drawable.depth == 32)) { - priv->has_edge_map = FALSE; - return; - } - - left_x1_map = left_x2_map = 0; - right_x1_map = right_x2_map = 0; - - for (j = 0; j < glyph_pixmap->drawable.height; j++) { - if (bitsPerPixel == 8) { - unsigned char *data; - - data = (unsigned char *) ((unsigned char *) bits + stride * j); - left_x1_data = *data++; - left_x2_data = *data; - data = - (unsigned char *) ((unsigned char *) bits + stride * j + width - - 2); - right_x1_data = *data++; - right_x2_data = *data; - } - else if (bitsPerPixel == 32) { - left_x1_data = *((unsigned int *) bits + stride / 4 * j); - left_x2_data = *((unsigned int *) bits + stride / 4 * j + 1); - right_x1_data = - *((unsigned int *) bits + stride / 4 * j + width - 2); - right_x2_data = - *((unsigned int *) bits + stride / 4 * j + width - 1); - } - else if (bitsPerPixel == 1) { - unsigned char temp; - - temp = *((unsigned char *) glyph_pixmap->devPrivate.ptr - + glyph_pixmap->devKind * j) & 0x3; - left_x1_data = temp & 0x1; - left_x2_data = temp & 0x2; - - temp = *((unsigned char *) glyph_pixmap->devPrivate.ptr - + glyph_pixmap->devKind * j - + (glyph_pixmap->drawable.width - 2) / 8); - right_x1_data = temp - & (1 << ((glyph_pixmap->drawable.width - 2) % 8)); - temp = *((unsigned char *) glyph_pixmap->devPrivate.ptr - + glyph_pixmap->devKind * j - + (glyph_pixmap->drawable.width - 1) / 8); - right_x2_data = temp - & (1 << ((glyph_pixmap->drawable.width - 1) % 8)); - } - left_x1_map |= (left_x1_data != 0) << j; - left_x2_map |= (left_x2_data != 0) << j; - right_x1_map |= (right_x1_data != 0) << j; - right_x2_map |= (right_x2_data != 0) << j; - } - - priv->left_x1_map = left_x1_map; - priv->left_x2_map = left_x2_map; - priv->right_x1_map = right_x1_map; - priv->right_x2_map = right_x2_map; - priv->has_edge_map = TRUE; - return; -} - -/** - * Returns TRUE if the glyphs in the lists intersect. Only checks based on - * bounding box, which appears to be good enough to catch most cases at least. - */ - -#define INTERSECTED_TYPE_MASK 1 -#define NON_INTERSECTED 0 -#define INTERSECTED 1 - -struct glamor_glyph_list { - int nlist; - GlyphListPtr list; - GlyphPtr *glyphs; - int type; -}; - -static Bool -glyph_new_fixed_list(struct glamor_glyph_list *fixed_list, - GlyphPtr *cur_glyphs, - GlyphPtr ** head_glyphs, - GlyphListPtr cur_list, - int cur_pos, int cur_x, int cur_y, - int x1, int y1, int x2, int y2, - GlyphListPtr *head_list, - int *head_pos, - int *head_x, - int *head_y, int *fixed_cnt, int type, BoxPtr prev_extents) -{ - int x_off = 0; - int y_off = 0; - int n_off = 0; - int list_cnt; - - if (type == NON_INTERSECTED) { - if (x1 < prev_extents->x2 && x2 > prev_extents->x1 - && y1 < prev_extents->y2 && y2 > prev_extents->y1) - return FALSE; - x_off = (*(cur_glyphs - 1))->info.xOff; - y_off = (*(cur_glyphs - 1))->info.yOff; - n_off = 1; - } - - list_cnt = cur_list - *head_list + 1; - if (cur_pos <= n_off) { - DEBUGF("break at %d n_off %d\n", cur_pos, n_off); - list_cnt--; - if (cur_pos < n_off) { - /* we overlap with previous list's last glyph. */ - x_off += cur_list->xOff; - y_off += cur_list->yOff; - cur_list--; - cur_pos = cur_list->len; - if (cur_pos <= n_off) { - list_cnt--; - } - } - } - DEBUGF("got %d lists\n", list_cnt); - if (list_cnt != 0) { - fixed_list->list = malloc(list_cnt * sizeof(*cur_list)); - memcpy(fixed_list->list, *head_list, list_cnt * sizeof(*cur_list)); - fixed_list->list[0].xOff = *head_x; - fixed_list->list[0].yOff = *head_y; - fixed_list->glyphs = *head_glyphs; - fixed_list->type = type & INTERSECTED_TYPE_MASK; - fixed_list->nlist = list_cnt; - if (cur_list != *head_list) { - fixed_list->list[0].len = (*head_list)->len - *head_pos; - if (cur_pos != n_off) - fixed_list->list[list_cnt - 1].len = cur_pos - n_off; - } - else - fixed_list->list[0].len = cur_pos - *head_pos - n_off; - (*fixed_cnt)++; - } - - if (type <= INTERSECTED) { - *head_list = cur_list; - *head_pos = cur_pos - n_off; - *head_x = cur_x - x_off; - *head_y = cur_y - y_off; - *head_glyphs = cur_glyphs - n_off; - } - return TRUE; -} - -/* - * This function detects glyph lists's overlapping. - * - * If check_fake_overlap is set, then it will check the glyph's left - * and right small boxes's real overlapping pixels. And if there is - * no real pixel overlapping, then it will not be treated as overlapped - * case. And we also can configured it to ignore less than 2 pixels - * overlappig. - * - * This function analyzes all the lists and split the list to multiple - * lists which are pure overlapped glyph lists or pure non-overlapped - * list if the overlapping only ocurr on the two adjacent glyphs. - * Otherwise, it return -1. - * - **/ - -static int -glamor_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs, - PictFormatShort mask_format, - ScreenPtr screen, Bool check_fake_overlap, - struct glamor_glyph_list *fixed_list, int fixed_size) -{ - int x1, x2, y1, y2; - int n; - int x, y; - BoxPtr extents; - BoxRec prev_extents; - Bool first = TRUE, first_list = TRUE; - Bool need_free_list_region = FALSE; - Bool need_free_fixed_list = FALSE; - struct glamor_glyph *priv = NULL; - Bool in_non_intersected_list = -1; - GlyphListPtr head_list; - int head_x, head_y, head_pos; - int fixed_cnt = 0; - GlyphPtr *head_glyphs; - GlyphListPtr cur_list = list; - RegionRec list_region; - RegionRec current_region; - BoxRec current_box; - - if (nlist > 1) { - pixman_region_init(&list_region); - need_free_list_region = TRUE; - } - - pixman_region_init(¤t_region); - - extents = pixman_region_extents(¤t_region); - - x = 0; - y = 0; - x1 = x2 = y1 = y2 = 0; - n = 0; - extents->x1 = 0; - extents->y1 = 0; - extents->x2 = 0; - extents->y2 = 0; - - head_list = list; - DEBUGF("has %d lists.\n", nlist); - while (nlist--) { - BoxRec left_box, right_box = { 0 }; - Bool has_left_edge_box = FALSE, has_right_edge_box = FALSE; - Bool left_to_right; - struct glamor_glyph *left_priv = NULL, *right_priv = NULL; - - x += list->xOff; - y += list->yOff; - n = list->len; - left_to_right = TRUE; - cur_list = list++; - - if (_X_UNLIKELY(!first_list)) { - pixman_region_init_with_extents(¤t_region, extents); - pixman_region_union(&list_region, &list_region, ¤t_region); - first = TRUE; - } - else { - head_list = cur_list; - head_pos = cur_list->len - n; - head_x = x; - head_y = y; - head_glyphs = glyphs; - } - - DEBUGF("current list %p has %d glyphs\n", cur_list, n); - while (n--) { - GlyphPtr glyph = *glyphs++; - - DEBUGF("the %dth glyph\n", cur_list->len - n - 1); - if (glyph->info.width == 0 || glyph->info.height == 0) { - x += glyph->info.xOff; - y += glyph->info.yOff; - continue; - } - if (mask_format - && mask_format != GlyphPicture(glyph)[screen->myNum]->format) { - need_free_fixed_list = TRUE; - goto done; - } - - x1 = x - glyph->info.x; - if (x1 < MINSHORT) - x1 = MINSHORT; - y1 = y - glyph->info.y; - if (y1 < MINSHORT) - y1 = MINSHORT; - if (check_fake_overlap) - priv = glamor_glyph_get_private(screen, glyph); - - x2 = x1 + glyph->info.width; - y2 = y1 + glyph->info.height; - - if (x2 > MAXSHORT) - x2 = MAXSHORT; - if (y2 > MAXSHORT) - y2 = MAXSHORT; - - if (first) { - extents->x1 = x1; - extents->y1 = y1; - extents->x2 = x2; - extents->y2 = y2; - - prev_extents = *extents; - - first = FALSE; - if (check_fake_overlap && priv - && priv->has_edge_map && glyph->info.yOff == 0) { - left_box.x1 = x1; - left_box.x2 = x1 + 1; - left_box.y1 = y1; - - right_box.x1 = x2 - 2; - right_box.x2 = x2 - 1; - right_box.y1 = y1; - left_priv = right_priv = priv; - has_left_edge_box = TRUE; - has_right_edge_box = TRUE; - } - } - else { - if (_X_UNLIKELY(!first_list)) { - current_box.x1 = x1; - current_box.y1 = y1; - current_box.x2 = x2; - current_box.y2 = y2; - if (pixman_region_contains_rectangle - (&list_region, ¤t_box) != PIXMAN_REGION_OUT) { - need_free_fixed_list = TRUE; - goto done; - } - } - - if (x1 < extents->x2 && x2 > extents->x1 - && y1 < extents->y2 && y2 > extents->y1) { - - if (check_fake_overlap && - (has_left_edge_box || has_right_edge_box) - && priv->has_edge_map && glyph->info.yOff == 0) { - int left_dx, right_dx; - unsigned long long intersected; - - left_dx = has_left_edge_box ? 1 : 0; - right_dx = has_right_edge_box ? 1 : 0; - if (x1 + 1 < extents->x2 - right_dx && - x2 - 1 > extents->x1 + left_dx) - goto real_intersected; - - if (left_to_right && has_right_edge_box) { - if (x1 == right_box.x1) { - intersected = - ((priv->left_x1_map & right_priv-> - right_x1_map) - | (priv->left_x2_map & right_priv-> - right_x2_map)); - if (intersected) - goto real_intersected; - } - else if (x1 == right_box.x2) { - intersected = - (priv->left_x1_map & right_priv-> - right_x2_map); - if (intersected) { -#ifdef GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK - /* tolerate with two pixels overlap. */ - intersected &= ~(1 << __fls(intersected)); - if ((intersected & (intersected - 1))) -#endif - goto real_intersected; - } - } - } - else if (!left_to_right && has_left_edge_box) { - if (x2 - 1 == left_box.x1) { - intersected = - (priv->right_x2_map & left_priv-> - left_x1_map); - if (intersected) { -#ifdef GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK - /* tolerate with two pixels overlap. */ - intersected &= ~(1 << __fls(intersected)); - if ((intersected & (intersected - 1))) -#endif - goto real_intersected; - } - } - else if (x2 - 1 == right_box.x2) { - if ((priv->right_x1_map & left_priv-> - left_x1_map) - || (priv->right_x2_map & left_priv-> - left_x2_map)) - goto real_intersected; - } - } - else { - if (x1 < extents->x2 && x1 + 2 > extents->x1) - goto real_intersected; - } - goto non_intersected; - } - else { - real_intersected: - DEBUGF("overlap with previous glyph.\n"); - if (in_non_intersected_list == 1) { - if (fixed_cnt >= fixed_size) { - need_free_fixed_list = TRUE; - goto done; - } - if (!glyph_new_fixed_list(&fixed_list[fixed_cnt], - glyphs - 1, - &head_glyphs, - cur_list, - cur_list->len - (n + 1), - x, y, x1, y1, x2, y2, - &head_list, &head_pos, - &head_x, &head_y, - &fixed_cnt, - NON_INTERSECTED, - &prev_extents)) { - need_free_fixed_list = TRUE; - goto done; - } - } - - in_non_intersected_list = 0; - - } - } - else { - non_intersected: - DEBUGF("doesn't overlap with previous glyph.\n"); - if (in_non_intersected_list == 0) { - if (fixed_cnt >= fixed_size) { - need_free_fixed_list = TRUE; - goto done; - } - if (!glyph_new_fixed_list(&fixed_list[fixed_cnt], - glyphs - 1, - &head_glyphs, - cur_list, - cur_list->len - (n + 1), x, y, - x1, y1, x2, y2, - &head_list, - &head_pos, - &head_x, - &head_y, &fixed_cnt, - INTERSECTED, &prev_extents)) { - need_free_fixed_list = TRUE; - goto done; - } - } - in_non_intersected_list = 1; - } - prev_extents = *extents; - } - - if (check_fake_overlap && priv - && priv->has_edge_map && glyph->info.yOff == 0) { - if (!has_left_edge_box || x1 < extents->x1) { - left_box.x1 = x1; - left_box.x2 = x1 + 1; - left_box.y1 = y1; - has_left_edge_box = TRUE; - left_priv = priv; - } - - if (!has_right_edge_box || x2 > extents->x2) { - right_box.x1 = x2 - 2; - right_box.x2 = x2 - 1; - right_box.y1 = y1; - has_right_edge_box = TRUE; - right_priv = priv; - } - } - - if (x1 < extents->x1) - extents->x1 = x1; - if (x2 > extents->x2) - extents->x2 = x2; - - if (y1 < extents->y1) - extents->y1 = y1; - if (y2 > extents->y2) - extents->y2 = y2; - - x += glyph->info.xOff; - y += glyph->info.yOff; - } - first_list = FALSE; - } - - if (in_non_intersected_list == 0 && fixed_cnt == 0) { - fixed_cnt = -1; - goto done; - } - - if ((in_non_intersected_list != -1 || head_pos != n) && (fixed_cnt > 0)) { - if (fixed_cnt >= fixed_size) { - need_free_fixed_list = TRUE; - goto done; - } - if (!glyph_new_fixed_list(&fixed_list[fixed_cnt], - glyphs - 1, - &head_glyphs, - cur_list, - cur_list->len - (n + 1), x, y, - x1, y1, x2, y2, - &head_list, - &head_pos, - &head_x, - &head_y, &fixed_cnt, - (!in_non_intersected_list) | 0x80, - &prev_extents)) { - need_free_fixed_list = TRUE; - goto done; - } - } - - done: - if (need_free_list_region) - pixman_region_fini(&list_region); - pixman_region_fini(¤t_region); - - if (need_free_fixed_list && fixed_cnt >= 0) { - while (fixed_cnt--) { - free(fixed_list[fixed_cnt].list); - } - } - - DEBUGF("Got %d fixed list \n", fixed_cnt); - return fixed_cnt; -} - -static inline unsigned int -glamor_glyph_size_to_count(int size) -{ - size /= GLYPH_MIN_SIZE; - return size * size; -} - -static inline unsigned int -glamor_glyph_count_to_mask(int count) -{ - return ~(count - 1); -} - -static inline unsigned int -glamor_glyph_size_to_mask(int size) -{ - return glamor_glyph_count_to_mask(glamor_glyph_size_to_count(size)); -} - -static PicturePtr -glamor_glyph_cache(glamor_screen_private *glamor, GlyphPtr glyph, int *out_x, - int *out_y) -{ - ScreenPtr screen = glamor->screen; - PicturePtr glyph_picture = GlyphPicture(glyph)[screen->myNum]; - glamor_glyph_cache_t *cache = - &glamor->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) != 0]; - struct glamor_glyph *priv = NULL, *evicted_priv = NULL; - int size, mask, pos, s; - - if (glyph->info.width > GLYPH_MAX_SIZE - || glyph->info.height > GLYPH_MAX_SIZE) - return NULL; - - for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2) - if (glyph->info.width <= size && glyph->info.height <= size) - break; - - s = glamor_glyph_size_to_count(size); - mask = glamor_glyph_count_to_mask(s); - pos = (cache->count + s - 1) & mask; - - priv = glamor_glyph_get_private(screen, glyph); - if (pos < GLYPH_CACHE_SIZE) { - cache->count = pos + s; - } - else { - for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) { - int i = cache->evict & glamor_glyph_size_to_mask(s); - GlyphPtr evicted = cache->glyphs[i]; - - if (evicted == NULL) - continue; - - evicted_priv = glamor_glyph_get_private(screen, evicted); - assert(evicted_priv->pos == i); - if (evicted_priv->size >= s) { - cache->glyphs[i] = NULL; - evicted_priv->cached = FALSE; - pos = cache->evict & glamor_glyph_size_to_mask(size); - } - else - evicted_priv = NULL; - break; - } - if (evicted_priv == NULL) { - int count = glamor_glyph_size_to_count(size); - - mask = glamor_glyph_count_to_mask(count); - pos = cache->evict & mask; - for (s = 0; s < count; s++) { - GlyphPtr evicted = cache->glyphs[pos + s]; - - if (evicted != NULL) { - - evicted_priv = glamor_glyph_get_private(screen, evicted); - - assert(evicted_priv->pos == pos + s); - evicted_priv->cached = FALSE; - cache->glyphs[pos + s] = NULL; - } - } - - } - /* And pick a new eviction position */ - cache->evict = rand() % GLYPH_CACHE_SIZE; - } - - cache->glyphs[pos] = glyph; - - priv->cache = cache; - priv->size = size; - priv->pos = pos; - s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * - (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE)); - priv->x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE; - priv->y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE; - for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) { - if (pos & 1) - priv->x += s; - if (pos & 2) - priv->y += s; - pos >>= 2; - } - - glamor_glyph_cache_upload_glyph(screen, cache, glyph, priv->x, priv->y); -#ifndef GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK - if (priv->has_edge_map == FALSE && glyph->info.width >= 2) - glamor_glyph_priv_get_edge_map(glyph, priv, glyph_picture); -#endif - priv->cached = TRUE; - - *out_x = priv->x; - *out_y = priv->y; - return cache->picture; -} - -typedef void (*glyphs_flush_func) (void *arg); -struct glyphs_flush_dst_arg { - CARD8 op; - PicturePtr src; - PicturePtr dst; - glamor_glyph_buffer_t *buffer; - int x_src, y_src; - int x_dst, y_dst; -}; - -static struct glyphs_flush_dst_arg dst_arg; -static struct glyphs_flush_mask_arg mask_arg; -static glamor_glyph_buffer_t dst_buffer; -static glamor_glyph_buffer_t mask_buffer; -unsigned long long mask_glyphs_cnt = 0; -unsigned long long dst_glyphs_cnt = 0; - -#define GLYPHS_DST_MODE_VIA_MASK 0 -#define GLYPHS_DST_MODE_VIA_MASK_CACHE 1 -#define GLYPHS_DST_MODE_TO_DST 2 -#define GLYPHS_DST_MODE_MASK_TO_DST 3 - -struct glyphs_flush_mask_arg { - PicturePtr mask; - glamor_glyph_buffer_t *buffer; - glamor_glyph_mask_cache_t *maskcache; - unsigned int used_bitmap; -}; - -static void -glamor_glyphs_flush_mask(struct glyphs_flush_mask_arg *arg) -{ - if (arg->buffer->count > 0) { - glamor_composite_glyph_rects(PictOpAdd, arg->buffer->source, - NULL, arg->mask, - arg->buffer->count, arg->buffer->rects); - } - arg->buffer->count = 0; - arg->buffer->source = NULL; - -} - -static void -glamor_glyphs_flush_dst(struct glyphs_flush_dst_arg *arg) -{ - if (!arg->buffer) - return; - - if (mask_buffer.count > 0) { - glamor_glyphs_flush_mask(&mask_arg); - } - if (mask_arg.used_bitmap) { - put_mask_cache_bitmap(mask_arg.maskcache, mask_arg.used_bitmap); - mask_arg.used_bitmap = 0; - } - - if (arg->buffer->count > 0) { - glamor_composite_glyph_rects(arg->op, arg->src, - arg->buffer->source, arg->dst, - arg->buffer->count, - &arg->buffer->rects[0]); - arg->buffer->count = 0; - arg->buffer->source = NULL; - } -} - -static glamor_glyph_cache_result_t -glamor_buffer_glyph(glamor_screen_private *glamor_priv, - glamor_glyph_buffer_t *buffer, - PictFormatShort format, - GlyphPtr glyph, struct glamor_glyph *priv, - int x_glyph, int y_glyph, - int dx, int dy, int w, int h, - int glyphs_dst_mode, - glyphs_flush_func glyphs_flush, void *flush_arg) -{ - ScreenPtr screen = glamor_priv->screen; - glamor_composite_rect_t *rect; - PicturePtr source; - int x, y; - glamor_glyph_cache_t *cache; - - if (glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST) - priv = glamor_glyph_get_private(screen, glyph); - - if (PICT_FORMAT_BPP(format) == 1) - format = PICT_a8; - - cache = &glamor_priv->glyphCaches[PICT_FORMAT_RGB(format) != 0]; - - if (buffer->source && buffer->source != cache->picture && glyphs_flush) { - (*glyphs_flush) (flush_arg); - glyphs_flush = NULL; - } - - if (buffer->count == GLYPH_BUFFER_SIZE && glyphs_flush) { - (*glyphs_flush) (flush_arg); - glyphs_flush = NULL; - } - - if (priv && priv->cached) { - rect = &buffer->rects[buffer->count++]; - rect->x_src = priv->x + dx; - rect->y_src = priv->y + dy; - if (buffer->source == NULL) - buffer->source = priv->cache->picture; - if (glyphs_dst_mode <= GLYPHS_DST_MODE_VIA_MASK_CACHE) - assert(priv->cache->glyphs[priv->pos] == glyph); - } - else { - assert(glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST); - if (glyphs_flush) - (*glyphs_flush) (flush_arg); - source = glamor_glyph_cache(glamor_priv, glyph, &x, &y); - - if (source != NULL) { - rect = &buffer->rects[buffer->count++]; - rect->x_src = x + dx; - rect->y_src = y + dy; - if (buffer->source == NULL) - buffer->source = source; - if (glyphs_dst_mode == GLYPHS_DST_MODE_VIA_MASK_CACHE) { - /* mode 1 means we are using global mask cache, - * thus we have to composite from the cache picture - * to the cache picture, we need a flush here to make - * sure latter we get the corret glyphs data.*/ - glamor_make_current(glamor_priv); - glFlush(); - } - } - else { - /* Couldn't find the glyph in the cache, use the glyph picture directly */ - source = GlyphPicture(glyph)[screen->myNum]; - if (buffer->source && buffer->source != source && glyphs_flush) - (*glyphs_flush) (flush_arg); - buffer->source = source; - - rect = &buffer->rects[buffer->count++]; - rect->x_src = 0 + dx; - rect->y_src = 0 + dy; - } - priv = glamor_glyph_get_private(screen, glyph); - } - - rect->x_dst = x_glyph; - rect->y_dst = y_glyph; - if (glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST) { - rect->x_dst -= glyph->info.x; - rect->y_dst -= glyph->info.y; - } - rect->width = w; - rect->height = h; - if (glyphs_dst_mode > GLYPHS_DST_MODE_VIA_MASK_CACHE) { - rect->x_mask = rect->x_src; - rect->y_mask = rect->y_src; - rect->x_src = dst_arg.x_src + rect->x_dst - dst_arg.x_dst; - rect->y_src = dst_arg.y_src + rect->y_dst - dst_arg.y_dst; - } - - return GLAMOR_GLYPH_SUCCESS; -} - -static void -glamor_buffer_glyph_clip(glamor_screen_private *glamor_priv, - BoxPtr rects, - int nrect, PictFormatShort format, - GlyphPtr glyph, struct glamor_glyph *priv, - int glyph_x, int glyph_y, - int glyph_dx, int glyph_dy, - int width, int height, - int glyphs_mode, - glyphs_flush_func flush_func, void *arg) -{ - int i; - - for (i = 0; i < nrect; i++) { - int dst_x, dst_y; - int dx, dy; - int x2, y2; - - dst_x = glyph_x - glyph_dx; - dst_y = glyph_y - glyph_dy; - x2 = dst_x + width; - y2 = dst_y + height; - dx = dy = 0; - if (rects[i].y1 >= y2) - break; - - if (dst_x < rects[i].x1) - dx = rects[i].x1 - dst_x, dst_x = rects[i].x1; - if (x2 > rects[i].x2) - x2 = rects[i].x2; - if (dst_y < rects[i].y1) - dy = rects[i].y1 - dst_y, dst_y = rects[i].y1; - if (y2 > rects[i].y2) - y2 = rects[i].y2; - if (dst_x < x2 && dst_y < y2) { - - glamor_buffer_glyph(glamor_priv, - &dst_buffer, - format, - glyph, priv, - dst_x + glyph_dx, - dst_y + glyph_dy, - dx, dy, - x2 - dst_x, y2 - dst_y, - glyphs_mode, flush_func, arg); - } - } -} - -static void -glamor_glyphs_via_mask(CARD8 op, - PicturePtr src, - PicturePtr dst, - PictFormatPtr mask_format, - INT16 x_src, - INT16 y_src, - int nlist, GlyphListPtr list, GlyphPtr *glyphs, - Bool use_mask_cache) -{ - PixmapPtr mask_pixmap = 0; - PicturePtr mask; - ScreenPtr screen = dst->pDrawable->pScreen; - int width = 0, height = 0; - int x, y; - int x_dst = list->xOff, y_dst = list->yOff; - int n; - GlyphPtr glyph; - int error; - BoxRec extents = { 0, 0, 0, 0 }; - XID component_alpha; - glamor_screen_private *glamor_priv; - int need_free_mask = FALSE; - glamor_glyph_buffer_t buffer; - struct glyphs_flush_mask_arg arg; - glamor_glyph_buffer_t *pmask_buffer; - struct glyphs_flush_mask_arg *pmask_arg; - struct glamor_glyph_mask_cache_entry *mce = NULL; - glamor_glyph_mask_cache_t *maskcache; - glamor_glyph_cache_t *cache; - int glyphs_dst_mode; - - glamor_glyph_extents(nlist, list, glyphs, &extents); - - if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) - return; - glamor_priv = glamor_get_screen_private(screen); - width = extents.x2 - extents.x1; - height = extents.y2 - extents.y1; - - if (mask_format->depth == 1) { - PictFormatPtr a8Format = PictureMatchFormat(screen, 8, PICT_a8); - - if (a8Format) - mask_format = a8Format; - } - - cache = &glamor_priv->glyphCaches - [PICT_FORMAT_RGB(mask_format->format) != 0]; - maskcache = glamor_priv->mask_cache[PICT_FORMAT_RGB(mask_format->format) != 0]; - - x = -extents.x1; - y = -extents.y1; - if (!use_mask_cache || width > (CACHE_PICTURE_SIZE / 4) - || height > MASK_CACHE_MAX_SIZE) { - new_mask_pixmap: - mask_pixmap = glamor_create_pixmap(screen, width, height, - mask_format->depth, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!mask_pixmap) { - glamor_destroy_pixmap(mask_pixmap); - return; - } - glamor_solid(mask_pixmap, 0, 0, width, height, 0); - component_alpha = NeedsComponent(mask_format->format); - mask = CreatePicture(0, &mask_pixmap->drawable, - mask_format, CPComponentAlpha, - &component_alpha, serverClient, &error); - if (!mask) - return; - need_free_mask = TRUE; - pmask_arg = &arg; - pmask_buffer = &buffer; - pmask_buffer->count = 0; - pmask_buffer->source = NULL; - pmask_arg->used_bitmap = 0; - glyphs_dst_mode = GLYPHS_DST_MODE_VIA_MASK; - } - else { - int retry_cnt = 0; - - retry: - mce = get_mask_cache(maskcache, - (width + MASK_CACHE_MAX_SIZE - - 1) / MASK_CACHE_MAX_SIZE); - - if (mce == NULL) { - glamor_glyphs_flush_dst(&dst_arg); - retry_cnt++; - if (retry_cnt > 2) { - assert(0); - goto new_mask_pixmap; - } - goto retry; - } - - mask = cache->picture; - x += mce->x; - y += mce->y; - mce->width = (width + MASK_CACHE_MAX_SIZE - 1) / MASK_CACHE_MAX_SIZE; - mce->height = 1; - if (mask_arg.mask && mask_arg.mask != mask && mask_buffer.count != 0) - glamor_glyphs_flush_dst(&dst_arg); - pmask_arg = &mask_arg; - pmask_buffer = &mask_buffer; - pmask_arg->maskcache = maskcache; - glyphs_dst_mode = GLYPHS_DST_MODE_VIA_MASK_CACHE; - } - pmask_arg->mask = mask; - pmask_arg->buffer = pmask_buffer; - while (nlist--) { - x += list->xOff; - y += list->yOff; - n = list->len; - mask_glyphs_cnt += n; - while (n--) { - glyph = *glyphs++; - if (glyph->info.width > 0 && glyph->info.height > 0) { - glyphs_flush_func flush_func; - void *temp_arg; - - if (need_free_mask) { - if (pmask_buffer->count) - flush_func = - (glyphs_flush_func) glamor_glyphs_flush_mask; - else - flush_func = NULL; - temp_arg = pmask_arg; - } - else { - /* If we are using global mask cache, then we need to - * flush dst instead of mask. As some dst depends on the - * previous mask result. Just flush mask can't get all previous's - * overlapped glyphs.*/ - if (dst_buffer.count || mask_buffer.count) - flush_func = - (glyphs_flush_func) glamor_glyphs_flush_dst; - else - flush_func = NULL; - temp_arg = &dst_arg; - } - glamor_buffer_glyph(glamor_priv, pmask_buffer, - mask_format->format, - glyph, NULL, x, y, - 0, 0, - glyph->info.width, glyph->info.height, - glyphs_dst_mode, - flush_func, (void *) temp_arg); - } - x += glyph->info.xOff; - y += glyph->info.yOff; - } - list++; - } - - x = extents.x1; - y = extents.y1; - if (need_free_mask) { - glamor_glyphs_flush_mask(pmask_arg); - CompositePicture(op, - src, - mask, - dst, - x_src + x - x_dst, - y_src + y - y_dst, 0, 0, x, y, width, height); - FreePicture(mask, 0); - glamor_destroy_pixmap(mask_pixmap); - } - else { - struct glamor_glyph priv; - glyphs_flush_func flush_func; - BoxPtr rects; - int nrect; - - priv.cache = cache; - priv.x = mce->x; - priv.y = mce->y; - priv.cached = TRUE; - rects = REGION_RECTS(dst->pCompositeClip); - nrect = REGION_NUM_RECTS(dst->pCompositeClip); - - pmask_arg->used_bitmap |= ((1 << mce->width) - 1) << mce->idx; - dst_arg.op = op; - dst_arg.src = src; - dst_arg.dst = dst; - dst_arg.buffer = &dst_buffer; - dst_arg.x_src = x_src; - dst_arg.y_src = y_src; - dst_arg.x_dst = x_dst; - dst_arg.y_dst = y_dst; - - if (dst_buffer.source == NULL) { - dst_buffer.source = cache->picture; - } - else if (dst_buffer.source != cache->picture) { - glamor_glyphs_flush_dst(&dst_arg); - dst_buffer.source = cache->picture; - } - - x += dst->pDrawable->x; - y += dst->pDrawable->y; - - if (dst_buffer.count || mask_buffer.count) - flush_func = (glyphs_flush_func) glamor_glyphs_flush_dst; - else - flush_func = NULL; - - glamor_buffer_glyph_clip(glamor_priv, - rects, nrect, - mask_format->format, - NULL, &priv, - x, y, - 0, 0, - width, height, - GLYPHS_DST_MODE_MASK_TO_DST, - flush_func, (void *) &dst_arg); - } -} - -static void -glamor_glyphs_to_dst(CARD8 op, - PicturePtr src, - PicturePtr dst, - INT16 x_src, - INT16 y_src, - int nlist, GlyphListPtr list, GlyphPtr *glyphs) -{ - ScreenPtr screen = dst->pDrawable->pScreen; - int x = 0, y = 0; - int x_dst = list->xOff, y_dst = list->yOff; - int n; - GlyphPtr glyph; - BoxPtr rects; - int nrect; - glamor_screen_private *glamor_priv; - - rects = REGION_RECTS(dst->pCompositeClip); - nrect = REGION_NUM_RECTS(dst->pCompositeClip); - - glamor_priv = glamor_get_screen_private(screen); - - dst_arg.op = op; - dst_arg.src = src; - dst_arg.dst = dst; - dst_arg.buffer = &dst_buffer; - dst_arg.x_src = x_src; - dst_arg.y_src = y_src; - dst_arg.x_dst = x_dst; - dst_arg.y_dst = y_dst; - - x = dst->pDrawable->x; - y = dst->pDrawable->y; - - while (nlist--) { - x += list->xOff; - y += list->yOff; - n = list->len; - dst_glyphs_cnt += n; - while (n--) { - glyph = *glyphs++; - - if (glyph->info.width > 0 && glyph->info.height > 0) { - glyphs_flush_func flush_func; - - if (dst_buffer.count || mask_buffer.count) - flush_func = (glyphs_flush_func) glamor_glyphs_flush_dst; - else - flush_func = NULL; - glamor_buffer_glyph_clip(glamor_priv, - rects, nrect, - (GlyphPicture(glyph)[screen->myNum])-> - format, glyph, NULL, x, y, - glyph->info.x, glyph->info.y, - glyph->info.width, glyph->info.height, - GLYPHS_DST_MODE_TO_DST, flush_func, - (void *) &dst_arg); - } - - x += glyph->info.xOff; - y += glyph->info.yOff; - } - list++; - } -} - -#define MAX_FIXED_SIZE -static void -glamor_glyphs_reset_buffer(glamor_glyph_buffer_t *buffer) -{ - buffer->count = 0; - buffer->source = NULL; -} - -static Bool -_glamor_glyphs(CARD8 op, - PicturePtr src, - PicturePtr dst, - PictFormatPtr mask_format, - INT16 x_src, - INT16 y_src, int nlist, GlyphListPtr list, - GlyphPtr *glyphs, Bool fallback) -{ - PictFormatShort format; - int fixed_size, fixed_cnt = 0; - struct glamor_glyph_list *fixed_list = NULL; - Bool need_free_list = FALSE; - -#ifndef GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK - Bool check_fake_overlap = TRUE; - - if (!(op == PictOpOver || op == PictOpAdd || op == PictOpXor)) { - /* C = (0,0,0,0) D = glyphs , SRC = A, DEST = B (faked overlapped glyphs, overlapped with (0,0,0,0)). - * For those op, (A IN (C ADD D)) OP B != (A IN D) OP ((A IN C) OP B) - * or (A IN (D ADD C)) OP B != (A IN C) OP ((A IN D) OP B) - * We need to split the faked regions to three or two, and composite the disoverlapped small - * boxes one by one. For other Ops, it's safe to composite the whole box. */ - check_fake_overlap = FALSE; - } -#else - Bool check_fake_overlap = FALSE; -#endif - if (mask_format) - format = mask_format->depth << 24 | mask_format->format; - else - format = 0; - - fixed_size = 32; - glamor_glyphs_reset_buffer(&dst_buffer); - - if (!mask_format || (((nlist == 1 && list->len == 1) || op == PictOpAdd) - && (dst->format == - ((mask_format->depth << 24) | mask_format-> - format)))) { - glamor_glyphs_to_dst(op, src, dst, x_src, y_src, nlist, list, glyphs); - goto last_flush; - } - - glamor_glyphs_reset_buffer(&mask_buffer); - - /* We have mask_format. Need to check the real overlap or not. */ - format = mask_format->depth << 24 | mask_format->format; - - fixed_list = calloc(fixed_size, sizeof(*fixed_list)); - if (_X_UNLIKELY(fixed_list == NULL)) - fixed_size = 0; - fixed_cnt = glamor_glyphs_intersect(nlist, list, glyphs, - format, dst->pDrawable->pScreen, - check_fake_overlap, - fixed_list, fixed_size); - if (fixed_cnt == 0) - mask_format = NULL; - need_free_list = TRUE; - - if (fixed_cnt <= 0) { - if (mask_format == NULL) { - glamor_glyphs_to_dst(op, src, dst, x_src, y_src, nlist, - list, glyphs); - goto last_flush; - } - else { - glamor_glyphs_via_mask(op, src, dst, mask_format, - x_src, y_src, nlist, list, glyphs, FALSE); - goto free_fixed_list; - } - } - else { - - /* We have splitted the original list to serval list, some are overlapped - * and some are non-overlapped. For the non-overlapped, we render it to - * dst directly. For the overlapped, we render it to mask picture firstly, - * then render the mask to dst. If we can use mask cache which is in the - * glyphs cache's last row, we can accumulate the rendering of mask to dst - * with the other dst_buffer's rendering operations thus can reduce the call - * of glDrawElements. - * - * */ - struct glamor_glyph_list *saved_list; - - saved_list = fixed_list; - mask_arg.used_bitmap = 0; - while (fixed_cnt--) { - if (fixed_list->type == NON_INTERSECTED) { - glamor_glyphs_to_dst(op, src, dst, - x_src, y_src, - fixed_list->nlist, - fixed_list->list, fixed_list->glyphs); - } - else - glamor_glyphs_via_mask(op, src, dst, - mask_format, x_src, y_src, - fixed_list->nlist, - fixed_list->list, - fixed_list->glyphs, TRUE); - - free(fixed_list->list); - fixed_list++; - } - free(saved_list); - need_free_list = FALSE; - } - - last_flush: - if (dst_buffer.count || mask_buffer.count) - glamor_glyphs_flush_dst(&dst_arg); - free_fixed_list: - if (need_free_list) { - assert(fixed_cnt <= 0); - free(fixed_list); - } - return TRUE; -} - -void -glamor_glyphs(CARD8 op, - PicturePtr src, - PicturePtr dst, - PictFormatPtr mask_format, - INT16 x_src, - INT16 y_src, int nlist, GlyphListPtr list, GlyphPtr *glyphs) -{ - _glamor_glyphs(op, src, dst, mask_format, x_src, - y_src, nlist, list, glyphs, TRUE); -} diff --git a/xorg-server/glamor/glamor_gradient.c b/xorg-server/glamor/glamor_gradient.c index 8ea645efc..d34131d35 100644 --- a/xorg-server/glamor/glamor_gradient.c +++ b/xorg-server/glamor/glamor_gradient.c @@ -997,13 +997,13 @@ glamor_generate_radial_gradient_picture(ScreenPtr screen, /* Set all the stops and colors to shader. */ if (stops_count > RADIAL_SMALL_STOPS) { - stop_colors = malloc(4 * stops_count * sizeof(float)); + stop_colors = xallocarray(stops_count, 4 * sizeof(float)); if (stop_colors == NULL) { ErrorF("Failed to allocate stop_colors memory.\n"); goto GRADIENT_FAIL; } - n_stops = malloc(stops_count * sizeof(float)); + n_stops = xallocarray(stops_count, sizeof(float)); if (n_stops == NULL) { ErrorF("Failed to allocate n_stops memory.\n"); goto GRADIENT_FAIL; @@ -1338,13 +1338,13 @@ glamor_generate_linear_gradient_picture(ScreenPtr screen, /* Set all the stops and colors to shader. */ if (stops_count > LINEAR_SMALL_STOPS) { - stop_colors = malloc(4 * stops_count * sizeof(float)); + stop_colors = xallocarray(stops_count, 4 * sizeof(float)); if (stop_colors == NULL) { ErrorF("Failed to allocate stop_colors memory.\n"); goto GRADIENT_FAIL; } - n_stops = malloc(stops_count * sizeof(float)); + n_stops = xallocarray(stops_count, sizeof(float)); if (n_stops == NULL) { ErrorF("Failed to allocate n_stops memory.\n"); goto GRADIENT_FAIL; diff --git a/xorg-server/glamor/glamor_image.c b/xorg-server/glamor/glamor_image.c index 5633da647..a272d5eaf 100644 --- a/xorg-server/glamor/glamor_image.c +++ b/xorg-server/glamor/glamor_image.c @@ -49,7 +49,7 @@ glamor_put_image_gl(DrawablePtr drawable, GCPtr gc, int depth, int x, int y, if (gc->alu != GXcopy) goto bail; - if (!glamor_pm_is_solid(&pixmap->drawable, gc->planemask)) + if (!glamor_pm_is_solid(gc->depth, gc->planemask)) goto bail; if (format == XYPixmap && drawable->depth == 1 && leftPad == 0) @@ -116,7 +116,7 @@ glamor_get_image_gl(DrawablePtr drawable, int x, int y, int w, int h, if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) goto bail; - if (format != ZPixmap || !glamor_pm_is_solid(drawable, plane_mask)) + if (format != ZPixmap || !glamor_pm_is_solid(drawable->depth, plane_mask)) goto bail; glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y); diff --git a/xorg-server/glamor/glamor_pixmap.c b/xorg-server/glamor/glamor_pixmap.c index 89b4c366b..4e8737172 100644 --- a/xorg-server/glamor/glamor_pixmap.c +++ b/xorg-server/glamor/glamor_pixmap.c @@ -109,9 +109,9 @@ glamor_set_destination_pixmap(PixmapPtr pixmap) } Bool -glamor_set_planemask(PixmapPtr pixmap, unsigned long planemask) +glamor_set_planemask(int depth, unsigned long planemask) { - if (glamor_pm_is_solid(&pixmap->drawable, planemask)) { + if (glamor_pm_is_solid(depth, planemask)) { return GL_TRUE; } @@ -775,7 +775,7 @@ _glamor_upload_bits_to_pixmap_texture(PixmapPtr pixmap, GLenum format, if (pixmap->drawable.depth == 1) stride = (((w * 8 + 7) / 8) + 3) & ~3; - converted_bits = malloc(h * stride); + converted_bits = xallocarray(h, stride); if (converted_bits == NULL) return FALSE; @@ -966,7 +966,7 @@ glamor_upload_sub_pixmap_to_texture(PixmapPtr pixmap, int x, int y, int w, void *sub_bits; int i, j; - sub_bits = malloc(h * stride); + sub_bits = xallocarray(h, stride); if (sub_bits == NULL) return FALSE; box.x1 = x; diff --git a/xorg-server/glamor/glamor_points.c b/xorg-server/glamor/glamor_points.c index df7e5a23f..3ba4a6927 100644 --- a/xorg-server/glamor/glamor_points.c +++ b/xorg-server/glamor/glamor_points.c @@ -60,7 +60,8 @@ glamor_poly_point_gl(DrawablePtr drawable, GCPtr gc, int mode, int npt, DDXPoint if (!prog->prog) { if (!glamor_build_program(screen, prog, &glamor_facet_point, - &glamor_fill_solid)) + &glamor_fill_solid, + NULL, NULL)) goto bail; } diff --git a/xorg-server/glamor/glamor_prepare.c b/xorg-server/glamor/glamor_prepare.c index 83ba7f16f..9bfc557e1 100644 --- a/xorg-server/glamor/glamor_prepare.c +++ b/xorg-server/glamor/glamor_prepare.c @@ -91,8 +91,8 @@ glamor_prep_pixmap_box(PixmapPtr pixmap, glamor_access_t access, BoxPtr box) pixmap->devKind * pixmap->drawable.height, NULL, gl_usage); } else { - pixmap->devPrivate.ptr = malloc(pixmap->devKind * - pixmap->drawable.height); + pixmap->devPrivate.ptr = xallocarray(pixmap->devKind, + pixmap->drawable.height); if (!pixmap->devPrivate.ptr) return FALSE; } diff --git a/xorg-server/glamor/glamor_priv.h b/xorg-server/glamor/glamor_priv.h index 898a9348a..480d13bfe 100644 --- a/xorg-server/glamor/glamor_priv.h +++ b/xorg-server/glamor/glamor_priv.h @@ -154,41 +154,8 @@ enum glamor_gl_flavor { GLAMOR_GL_ES2 // OPENGL ES2.0 API }; -#define GLAMOR_NUM_GLYPH_CACHE_FORMATS 2 - #define GLAMOR_COMPOSITE_VBO_VERT_CNT (64*1024) -typedef struct { - PicturePtr picture; /* Where the glyphs of the cache are stored */ - GlyphPtr *glyphs; - uint16_t count; - uint16_t evict; -} glamor_glyph_cache_t; - -#define CACHE_PICTURE_SIZE 1024 -#define GLYPH_MIN_SIZE 8 -#define GLYPH_MAX_SIZE 64 -#define GLYPH_CACHE_SIZE ((CACHE_PICTURE_SIZE) * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE)) - -#define MASK_CACHE_MAX_SIZE 32 -#define MASK_CACHE_WIDTH (CACHE_PICTURE_SIZE / MASK_CACHE_MAX_SIZE) -#define MASK_CACHE_MASK ((1LL << (MASK_CACHE_WIDTH)) - 1) - -struct glamor_glyph_mask_cache_entry { - int idx; - int width; - int height; - int x; - int y; -}; - -typedef struct { - PixmapPtr pixmap; - struct glamor_glyph_mask_cache_entry mcache[MASK_CACHE_WIDTH]; - unsigned int free_bitmap; - unsigned int cleared_bitmap; -} glamor_glyph_mask_cache_t; - struct glamor_saved_procs { CloseScreenProcPtr close_screen; CreateScreenResourcesProcPtr create_screen_resources; @@ -208,7 +175,6 @@ struct glamor_saved_procs { AddTrapsProcPtr addtraps; CreatePictureProcPtr create_picture; DestroyPictureProcPtr destroy_picture; - UnrealizeGlyphProcPtr unrealize_glyph; SetWindowPixmapProcPtr set_window_pixmap; #if XSYNC SyncScreenFuncsRec sync_screen_funcs; @@ -274,6 +240,14 @@ typedef struct glamor_screen_private { glamor_program_fill on_off_dash_line_progs; glamor_program double_dash_line_prog; + /* glamor composite_glyphs shaders */ + glamor_program_render glyphs_program; + struct glamor_glyph_atlas *glyph_atlas_a; + struct glamor_glyph_atlas *glyph_atlas_argb; + int glyph_atlas_dim; + int glyph_max_dim; + char *glyph_defines; + /* vertext/elment_index buffer object for render */ GLuint vbo, ebo; /** Next offset within the VBO that glamor_get_vbo_space() will use. */ @@ -292,9 +266,6 @@ typedef struct glamor_screen_private { glamor_composite_shader composite_shader[SHADER_SOURCE_COUNT] [SHADER_MASK_COUNT] [SHADER_IN_COUNT]; - glamor_glyph_cache_t glyphCaches[GLAMOR_NUM_GLYPH_CACHE_FORMATS]; - glamor_glyph_mask_cache_t *mask_cache[GLAMOR_NUM_GLYPH_CACHE_FORMATS]; - Bool glyph_caches_realized; /* shaders to restore a texture to another texture. */ GLint finish_access_prog[2]; @@ -638,10 +609,10 @@ glamor_get_gc_private(GCPtr gc) * pixel values for pDrawable. */ static inline Bool -glamor_pm_is_solid(DrawablePtr drawable, unsigned long planemask) +glamor_pm_is_solid(int depth, unsigned long planemask) { - return (planemask & FbFullMask(drawable->depth)) == - FbFullMask(drawable->depth); + return (planemask & FbFullMask(depth)) == + FbFullMask(depth); } extern int glamor_debug_level; @@ -676,7 +647,7 @@ glamor_pixmap_fbo *glamor_create_fbo_array(glamor_screen_private *glamor_priv, void glamor_init_finish_access_shaders(ScreenPtr screen); void glamor_fini_finish_access_shaders(ScreenPtr screen); -const Bool glamor_get_drawable_location(const DrawablePtr drawable); +Bool glamor_get_drawable_location(const DrawablePtr drawable); void glamor_get_drawable_deltas(DrawablePtr drawable, PixmapPtr pixmap, int *x, int *y); GLint glamor_compile_glsl_prog(GLenum type, const char *source); @@ -701,23 +672,12 @@ glamor_pixmap_fbo *glamor_es2_pixmap_read_prepare(PixmapPtr source, int x, int swap_rb); Bool glamor_set_alu(ScreenPtr screen, unsigned char alu); -Bool glamor_set_planemask(PixmapPtr pixmap, unsigned long planemask); +Bool glamor_set_planemask(int depth, unsigned long planemask); RegionPtr glamor_bitmap_to_region(PixmapPtr pixmap); void glamor_track_stipple(GCPtr gc); -/* glamor_glyphs.c */ -Bool glamor_realize_glyph_caches(ScreenPtr screen); -void glamor_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph); -void glamor_glyphs_fini(ScreenPtr screen); -void glamor_glyphs(CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr *glyphs); - /* glamor_render.c */ Bool glamor_composite_clipped_region(CARD8 op, PicturePtr source, @@ -744,10 +704,6 @@ void glamor_composite(CARD8 op, void glamor_init_composite_shaders(ScreenPtr screen); void glamor_fini_composite_shaders(ScreenPtr screen); -void glamor_composite_glyph_rects(CARD8 op, - PicturePtr src, PicturePtr mask, - PicturePtr dst, int nrect, - glamor_composite_rect_t *rects); void glamor_composite_rects(CARD8 op, PicturePtr pDst, xRenderColor *color, int nRect, xRectangle *rects); @@ -994,6 +950,22 @@ void glamor_composite_rectangles(CARD8 op, xRenderColor *color, int num_rects, xRectangle *rects); +/* glamor_composite_glyphs.c */ +Bool +glamor_composite_glyphs_init(ScreenPtr pScreen); + +void +glamor_composite_glyphs_fini(ScreenPtr pScreen); + +void +glamor_composite_glyphs(CARD8 op, + PicturePtr src, + PicturePtr dst, + PictFormatPtr mask_format, + INT16 x_src, + INT16 y_src, int nlist, + GlyphListPtr list, GlyphPtr *glyphs); + /* glamor_sync.c */ Bool glamor_sync_init(ScreenPtr screen); @@ -1077,8 +1049,6 @@ void glamor_xv_render(glamor_port_private *port_priv); #if 0 #define MAX_FBO_SIZE 32 /* For test purpose only. */ #endif -//#define GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK -#define GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK #include "glamor_font.h" diff --git a/xorg-server/glamor/glamor_program.c b/xorg-server/glamor/glamor_program.c index 8aab53f4f..1dc5f1983 100644 --- a/xorg-server/glamor/glamor_program.c +++ b/xorg-server/glamor/glamor_program.c @@ -47,7 +47,7 @@ static const glamor_facet glamor_fill_tile = { .name = "tile", .vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n", .fs_exec = " gl_FragColor = texture2D(sampler, fill_pos);\n", - .locations = glamor_program_location_fill, + .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos, .use = use_tile, }; @@ -66,7 +66,7 @@ static const glamor_facet glamor_fill_stipple = { " if (a == 0.0)\n" " discard;\n" " gl_FragColor = fg;\n"), - .locations = glamor_program_location_fg | glamor_program_location_fill, + .locations = glamor_program_location_fg | glamor_program_location_fillsamp | glamor_program_location_fillpos, .use = use_stipple, }; @@ -87,7 +87,7 @@ static const glamor_facet glamor_fill_opaque_stipple = { " gl_FragColor = bg;\n" " else\n" " gl_FragColor = fg;\n"), - .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fill, + .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fillsamp | glamor_program_location_fillpos, .use = use_opaque_stipple }; @@ -114,12 +114,15 @@ static glamor_location_var location_vars[] = { .fs_vars = "uniform vec4 bg;\n" }, { - .location = glamor_program_location_fill, + .location = glamor_program_location_fillsamp, + .fs_vars = "uniform sampler2D sampler;\n" + }, + { + .location = glamor_program_location_fillpos, .vs_vars = ("uniform vec2 fill_offset;\n" "uniform vec2 fill_size_inv;\n" "varying vec2 fill_pos;\n"), - .fs_vars = ("uniform sampler2D sampler;\n" - "uniform vec2 fill_size_inv;\n" + .fs_vars = ("uniform vec2 fill_size_inv;\n" "varying vec2 fill_pos;\n") }, { @@ -136,6 +139,10 @@ static glamor_location_var location_vars[] = { .vs_vars = "uniform float dash_length;\n", .fs_vars = "uniform sampler2D dash;\n", }, + { + .location = glamor_program_location_atlas, + .fs_vars = "uniform sampler2D atlas;\n", + }, }; #define NUM_LOCATION_VARS (sizeof location_vars / sizeof location_vars[0]) @@ -183,6 +190,7 @@ fs_location_vars(glamor_program_location locations) static const char vs_template[] = "%s" /* version */ + "%s" /* defines */ "%s" /* prim vs_vars */ "%s" /* fill vs_vars */ "%s" /* location vs_vars */ @@ -195,12 +203,14 @@ static const char vs_template[] = static const char fs_template[] = "%s" /* version */ GLAMOR_DEFAULT_PRECISION + "%s" /* defines */ "%s" /* prim fs_vars */ "%s" /* fill fs_vars */ "%s" /* location fs_vars */ "void main() {\n" "%s" /* prim fs_exec */ "%s" /* fill fs_exec */ + "%s" /* combine */ "}\n"; static const char * @@ -236,7 +246,9 @@ Bool glamor_build_program(ScreenPtr screen, glamor_program *prog, const glamor_facet *prim, - const glamor_facet *fill) + const glamor_facet *fill, + const char *combine, + const char *defines) { glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); @@ -282,6 +294,7 @@ glamor_build_program(ScreenPtr screen, if (asprintf(&vs_prog_string, vs_template, str(version_string), + str(defines), str(prim->vs_vars), str(fill->vs_vars), vs_vars, @@ -292,26 +305,30 @@ glamor_build_program(ScreenPtr screen, if (asprintf(&fs_prog_string, fs_template, str(version_string), + str(defines), str(prim->fs_vars), str(fill->fs_vars), fs_vars, str(prim->fs_exec), - str(fill->fs_exec)) < 0) + str(fill->fs_exec), + str(combine)) < 0) fs_prog_string = NULL; if (!vs_prog_string || !fs_prog_string) goto fail; + prog->prog = glCreateProgram(); #if DBG - ErrorF("\nPrograms for %s %s\nVertex shader:\n\n%s\n\nFragment Shader:\n\n%s", - prim->name, fill->name, vs_prog_string, fs_prog_string); + ErrorF("\n\tProgram %d for %s %s\n\tVertex shader:\n\n\t================\n%s\n\n\tFragment Shader:\n\n%s\t================\n", + prog->prog, prim->name, fill->name, vs_prog_string, fs_prog_string); #endif - prog->prog = glCreateProgram(); prog->flags = flags; prog->locations = locations; prog->prim_use = prim->use; + prog->prim_use_render = prim->use_render; prog->fill_use = fill->use; + prog->fill_use_render = fill->use_render; vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string); fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string); @@ -335,13 +352,14 @@ glamor_build_program(ScreenPtr screen, prog->matrix_uniform = glamor_get_uniform(prog, glamor_program_location_none, "v_matrix"); prog->fg_uniform = glamor_get_uniform(prog, glamor_program_location_fg, "fg"); prog->bg_uniform = glamor_get_uniform(prog, glamor_program_location_bg, "bg"); - prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fill, "fill_offset"); - prog->fill_size_inv_uniform = glamor_get_uniform(prog, glamor_program_location_fill, "fill_size_inv"); + prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_offset"); + prog->fill_size_inv_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_size_inv"); prog->font_uniform = glamor_get_uniform(prog, glamor_program_location_font, "font"); prog->bitplane_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitplane"); prog->bitmul_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitmul"); prog->dash_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash"); prog->dash_length_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash_length"); + prog->atlas_uniform = glamor_get_uniform(prog, glamor_program_location_atlas, "atlas"); free(version_string); free(fs_vars); @@ -396,7 +414,7 @@ glamor_use_program_fill(PixmapPtr pixmap, if (!fill) return NULL; - if (!glamor_build_program(screen, prog, prim, fill)) + if (!glamor_build_program(screen, prog, prim, fill, NULL, NULL)) return NULL; } @@ -405,3 +423,238 @@ glamor_use_program_fill(PixmapPtr pixmap, return prog; } + +static struct blendinfo composite_op_info[] = { + [PictOpClear] = {0, 0, GL_ZERO, GL_ZERO}, + [PictOpSrc] = {0, 0, GL_ONE, GL_ZERO}, + [PictOpDst] = {0, 0, GL_ZERO, GL_ONE}, + [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA}, + [PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE}, + [PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO}, + [PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA}, + [PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO}, + [PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA}, + [PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, + [PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA}, + [PictOpXor] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, + [PictOpAdd] = {0, 0, GL_ONE, GL_ONE}, +}; + +static void +glamor_set_blend(CARD8 op, glamor_program_alpha alpha, PicturePtr dst) +{ + GLenum src_blend, dst_blend; + struct blendinfo *op_info; + + switch (alpha) { + case glamor_program_alpha_ca_first: + op = PictOpOutReverse; + break; + case glamor_program_alpha_ca_second: + op = PictOpAdd; + break; + default: + break; + } + + if (op == PictOpSrc) + return; + + op_info = &composite_op_info[op]; + + src_blend = op_info->source_blend; + dst_blend = op_info->dest_blend; + + /* If there's no dst alpha channel, adjust the blend op so that we'll treat + * it as always 1. + */ + if (PICT_FORMAT_A(dst->format) == 0 && op_info->dest_alpha) { + if (src_blend == GL_DST_ALPHA) + src_blend = GL_ONE; + else if (src_blend == GL_ONE_MINUS_DST_ALPHA) + src_blend = GL_ZERO; + } + + /* Set up the source alpha value for blending in component alpha mode. */ + if (alpha != glamor_program_alpha_normal && op_info->source_alpha) { + if (dst_blend == GL_SRC_ALPHA) + dst_blend = GL_SRC_COLOR; + else if (dst_blend == GL_ONE_MINUS_SRC_ALPHA) + dst_blend = GL_ONE_MINUS_SRC_COLOR; + } + + glEnable(GL_BLEND); + glBlendFunc(src_blend, dst_blend); +} + +static Bool +use_source_solid(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog) +{ + + glamor_set_blend(op, prog->alpha, dst); + + glamor_set_color(glamor_get_drawable_pixmap(dst->pDrawable), + src->pSourcePict->solidFill.color, + prog->fg_uniform); + return TRUE; +} + +const glamor_facet glamor_source_solid = { + .name = "render_solid", + .fs_exec = " vec4 source = fg;\n", + .locations = glamor_program_location_fg, + .use_render = use_source_solid, +}; + +static Bool +use_source_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog) +{ + glamor_set_blend(op, prog->alpha, dst); + + return glamor_set_texture((PixmapPtr) src->pDrawable, + 0, 0, + prog->fill_offset_uniform, + prog->fill_size_inv_uniform); +} + +const glamor_facet glamor_source_picture = { + .name = "render_picture", + .vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n", + .fs_exec = " vec4 source = texture2D(sampler, fill_pos);\n", + .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos, + .use_render = use_source_picture, +}; + +static Bool +use_source_1x1_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog) +{ + glamor_set_blend(op, prog->alpha, dst); + + return glamor_set_texture_pixmap((PixmapPtr) src->pDrawable); +} + +const glamor_facet glamor_source_1x1_picture = { + .name = "render_picture", + .fs_exec = " vec4 source = texture2D(sampler, vec2(0.5));\n", + .locations = glamor_program_location_fillsamp, + .use_render = use_source_1x1_picture, +}; + +const glamor_facet *glamor_facet_source[glamor_program_source_count] = { + [glamor_program_source_solid] = &glamor_source_solid, + [glamor_program_source_picture] = &glamor_source_picture, + [glamor_program_source_1x1_picture] = &glamor_source_1x1_picture, +}; + +static const char *glamor_combine[] = { + [glamor_program_alpha_normal] = " gl_FragColor = source * mask.a;\n", + [glamor_program_alpha_ca_first] = " gl_FragColor = source.a * mask;\n", + [glamor_program_alpha_ca_second] = " gl_FragColor = source * mask;\n" +}; + +static Bool +glamor_setup_one_program_render(ScreenPtr screen, + glamor_program *prog, + glamor_program_source source_type, + glamor_program_alpha alpha, + const glamor_facet *prim, + const char *defines) +{ + if (prog->failed) + return FALSE; + + if (!prog->prog) { + const glamor_facet *fill = glamor_facet_source[source_type]; + + if (!fill) + return FALSE; + + if (!glamor_build_program(screen, prog, prim, fill, glamor_combine[alpha], defines)) + return FALSE; + prog->alpha = alpha; + } + + return TRUE; +} + +glamor_program * +glamor_setup_program_render(CARD8 op, + PicturePtr src, + PicturePtr mask, + PicturePtr dst, + glamor_program_render *program_render, + const glamor_facet *prim, + const char *defines) +{ + ScreenPtr screen = dst->pDrawable->pScreen; + glamor_program_alpha alpha; + glamor_program_source source_type; + glamor_program *prog; + + if (op > ARRAY_SIZE(composite_op_info)) + return NULL; + + if (glamor_is_component_alpha(mask)) { + /* This only works for PictOpOver */ + if (op != PictOpOver) + return NULL; + alpha = glamor_program_alpha_ca_first; + } else + alpha = glamor_program_alpha_normal; + + if (src->pDrawable) { + + /* Can't do transforms, alphamaps or sourcing from non-pixmaps yet */ + if (src->transform || src->alphaMap || src->pDrawable->type != DRAWABLE_PIXMAP) + return NULL; + + if (src->pDrawable->width == 1 && src->pDrawable->height == 1 && src->repeat) + source_type = glamor_program_source_1x1_picture; + else + source_type = glamor_program_source_picture; + } else { + SourcePictPtr sp = src->pSourcePict; + if (!sp) + return NULL; + switch (sp->type) { + case SourcePictTypeSolidFill: + source_type = glamor_program_source_solid; + break; + default: + return NULL; + } + } + + prog = &program_render->progs[source_type][alpha]; + if (!glamor_setup_one_program_render(screen, prog, source_type, alpha, prim, defines)) + return NULL; + + if (alpha == glamor_program_alpha_ca_first) { + + /* Make sure we can also build the second program before + * deciding to use this path. + */ + if (!glamor_setup_one_program_render(screen, + &program_render->progs[source_type][glamor_program_alpha_ca_second], + source_type, glamor_program_alpha_ca_second, prim, + defines)) + return NULL; + } + return prog; +} + +Bool +glamor_use_program_render(glamor_program *prog, + CARD8 op, + PicturePtr src, + PicturePtr dst) +{ + glUseProgram(prog->prog); + + if (prog->prim_use_render && !prog->prim_use_render(op, src, dst, prog)) + return FALSE; + + if (prog->fill_use_render && !prog->fill_use_render(op, src, dst, prog)) + return FALSE; + return TRUE; +} diff --git a/xorg-server/glamor/glamor_program.h b/xorg-server/glamor/glamor_program.h index fa3877c5d..9e561cd92 100644 --- a/xorg-server/glamor/glamor_program.h +++ b/xorg-server/glamor/glamor_program.h @@ -27,23 +27,36 @@ typedef enum { glamor_program_location_none = 0, glamor_program_location_fg = 1, glamor_program_location_bg = 2, - glamor_program_location_fill = 4, - glamor_program_location_font = 8, - glamor_program_location_bitplane = 16, - glamor_program_location_dash = 32, + glamor_program_location_fillsamp = 4, + glamor_program_location_fillpos = 8, + glamor_program_location_font = 16, + glamor_program_location_bitplane = 32, + glamor_program_location_dash = 64, + glamor_program_location_atlas = 128, } glamor_program_location; typedef enum { glamor_program_flag_none = 0, } glamor_program_flag; +typedef enum { + glamor_program_alpha_normal, + glamor_program_alpha_ca_first, + glamor_program_alpha_ca_second, + glamor_program_alpha_count +} glamor_program_alpha; + typedef struct _glamor_program glamor_program; typedef Bool (*glamor_use) (PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg); +typedef Bool (*glamor_use_render) (CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog); + typedef struct { const char *name; const int version; + char *vs_defines; + char *fs_defines; const char *vs_vars; const char *vs_exec; const char *fs_vars; @@ -52,6 +65,7 @@ typedef struct { const glamor_program_flag flags; const char *source_name; glamor_use use; + glamor_use_render use_render; } glamor_facet; struct _glamor_program { @@ -67,10 +81,14 @@ struct _glamor_program { GLint bitmul_uniform; GLint dash_uniform; GLint dash_length_uniform; + GLint atlas_uniform; glamor_program_location locations; glamor_program_flag flags; glamor_use prim_use; glamor_use fill_use; + glamor_program_alpha alpha; + glamor_use_render prim_use_render; + glamor_use_render fill_use_render; }; typedef struct { @@ -83,7 +101,9 @@ Bool glamor_build_program(ScreenPtr screen, glamor_program *prog, const glamor_facet *prim, - const glamor_facet *fill); + const glamor_facet *fill, + const char *combine, + const char *defines); Bool glamor_use_program(PixmapPtr pixmap, @@ -97,4 +117,37 @@ glamor_use_program_fill(PixmapPtr pixmap, glamor_program_fill *program_fill, const glamor_facet *prim); +typedef enum { + glamor_program_source_solid, + glamor_program_source_picture, + glamor_program_source_1x1_picture, + glamor_program_source_count, +} glamor_program_source; + +typedef struct { + glamor_program progs[glamor_program_source_count][glamor_program_alpha_count]; +} glamor_program_render; + +static inline Bool +glamor_is_component_alpha(PicturePtr mask) { + if (mask && mask->componentAlpha && PICT_FORMAT_RGB(mask->format)) + return TRUE; + return FALSE; +} + +glamor_program * +glamor_setup_program_render(CARD8 op, + PicturePtr src, + PicturePtr mask, + PicturePtr dst, + glamor_program_render *program_render, + const glamor_facet *prim, + const char *defines); + +Bool +glamor_use_program_render(glamor_program *prog, + CARD8 op, + PicturePtr src, + PicturePtr dst); + #endif /* _GLAMOR_PROGRAM_H_ */ diff --git a/xorg-server/glamor/glamor_render.c b/xorg-server/glamor/glamor_render.c index 27c09fd48..efca36744 100644 --- a/xorg-server/glamor/glamor_render.c +++ b/xorg-server/glamor/glamor_render.c @@ -1701,139 +1701,3 @@ glamor_composite(CARD8 op, glamor_finish_access_picture(source); glamor_finish_access_picture(dest); } - -static void -glamor_get_src_rect_extent(int nrect, - glamor_composite_rect_t *rects, BoxPtr extent) -{ - extent->x1 = MAXSHORT; - extent->y1 = MAXSHORT; - extent->x2 = MINSHORT; - extent->y2 = MINSHORT; - - while (nrect--) { - if (extent->x1 > rects->x_src) - extent->x1 = rects->x_src; - if (extent->y1 > rects->y_src) - extent->y1 = rects->y_src; - if (extent->x2 < rects->x_src + rects->width) - extent->x2 = rects->x_src + rects->width; - if (extent->y2 < rects->y_src + rects->height) - extent->y2 = rects->y_src + rects->height; - rects++; - } -} - -static void -glamor_composite_src_rect_translate(int nrect, - glamor_composite_rect_t *rects, - int x, int y) -{ - while (nrect--) { - rects->x_src += x; - rects->y_src += y; - rects++; - } -} - -void -glamor_composite_glyph_rects(CARD8 op, - PicturePtr src, PicturePtr mask, PicturePtr dst, - int nrect, glamor_composite_rect_t *rects) -{ - int n; - PicturePtr temp_src = NULL; - glamor_composite_rect_t *r; - - ValidatePicture(src); - ValidatePicture(dst); - if (!(glamor_is_large_picture(src) - || (mask && glamor_is_large_picture(mask)) - || glamor_is_large_picture(dst))) { - PixmapPtr src_pixmap = NULL; - PixmapPtr mask_pixmap = NULL; - PixmapPtr dst_pixmap = NULL; - PixmapPtr temp_src_pixmap = NULL; - glamor_pixmap_private *src_pixmap_priv = NULL; - glamor_pixmap_private *mask_pixmap_priv = NULL; - glamor_pixmap_private *dst_pixmap_priv; - glamor_pixmap_private *temp_src_priv = NULL; - BoxRec src_extent; - - dst_pixmap = glamor_get_drawable_pixmap(dst->pDrawable); - dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap); - - if (mask && mask->pDrawable) { - mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable); - mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap); - } - if (src->pDrawable) { - src_pixmap = glamor_get_drawable_pixmap(src->pDrawable); - src_pixmap_priv = glamor_get_pixmap_private(src_pixmap); - } - - if (!src->pDrawable - && (src->pSourcePict->type != SourcePictTypeSolidFill)) { - glamor_get_src_rect_extent(nrect, rects, &src_extent); - temp_src = glamor_convert_gradient_picture(dst->pDrawable->pScreen, - src, - src_extent.x1, - src_extent.y1, - src_extent.x2 - - src_extent.x1, - src_extent.y2 - - src_extent.y1); - if (!temp_src) - goto fallback; - - temp_src_pixmap = (PixmapPtr) (temp_src->pDrawable); - temp_src_priv = glamor_get_pixmap_private(temp_src_pixmap); - glamor_composite_src_rect_translate(nrect, rects, - -src_extent.x1, -src_extent.y1); - } - else { - temp_src = src; - temp_src_pixmap = src_pixmap; - temp_src_priv = src_pixmap_priv; - } - - if (mask && mask->componentAlpha) { - if (op == PictOpOver) { - if (glamor_composite_with_shader(PictOpOutReverse, - temp_src, mask, dst, - temp_src_pixmap, mask_pixmap, dst_pixmap, - temp_src_priv, - mask_pixmap_priv, - dst_pixmap_priv, nrect, rects, - TRUE)) - goto done; - } - } - else { - if (glamor_composite_with_shader - (op, temp_src, mask, dst, - temp_src_pixmap, mask_pixmap, dst_pixmap, - temp_src_priv, mask_pixmap_priv, - dst_pixmap_priv, nrect, rects, FALSE)) - goto done; - } - } - fallback: - n = nrect; - r = rects; - - while (n--) { - CompositePicture(op, - temp_src ? temp_src : src, - mask, - dst, - r->x_src, r->y_src, - r->x_mask, r->y_mask, - r->x_dst, r->y_dst, r->width, r->height); - r++; - } - - done: - if (temp_src && temp_src != src) - FreePicture(temp_src, 0); -} diff --git a/xorg-server/glamor/glamor_spans.c b/xorg-server/glamor/glamor_spans.c index b358c60bd..58da3edf7 100644 --- a/xorg-server/glamor/glamor_spans.c +++ b/xorg-server/glamor/glamor_spans.c @@ -279,7 +279,7 @@ glamor_set_spans_gl(DrawablePtr drawable, GCPtr gc, char *src, if (gc->alu != GXcopy) goto bail; - if (!glamor_pm_is_solid(&pixmap->drawable, gc->planemask)) + if (!glamor_pm_is_solid(gc->depth, gc->planemask)) goto bail; glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y); diff --git a/xorg-server/glamor/glamor_text.c b/xorg-server/glamor/glamor_text.c index c7c1ab738..81a22a5af 100644 --- a/xorg-server/glamor/glamor_text.c +++ b/xorg-server/glamor/glamor_text.c @@ -417,7 +417,7 @@ glamor_image_text(DrawablePtr drawable, GCPtr gc, fill_facet = &glamor_facet_image_fill; } - if (!glamor_build_program(screen, prog, prim_facet, fill_facet)) + if (!glamor_build_program(screen, prog, prim_facet, fill_facet, NULL, NULL)) goto bail; } @@ -431,7 +431,7 @@ glamor_image_text(DrawablePtr drawable, GCPtr gc, /* Check planemask before drawing background to * bail early if it's not OK */ - if (!glamor_set_planemask(pixmap, gc->planemask)) + if (!glamor_set_planemask(gc->depth, gc->planemask)) goto bail; for (c = 0; c < count; c++) if (charinfo[c]) diff --git a/xorg-server/glamor/glamor_transform.c b/xorg-server/glamor/glamor_transform.c index 6d29e9eb6..f476a99b7 100644 --- a/xorg-server/glamor/glamor_transform.c +++ b/xorg-server/glamor/glamor_transform.c @@ -129,7 +129,7 @@ glamor_set_solid(PixmapPtr pixmap, CARD32 pixel; int alu = use_alu ? gc->alu : GXcopy; - if (!glamor_set_planemask(pixmap, gc->planemask)) + if (!glamor_set_planemask(gc->depth, gc->planemask)) return FALSE; pixel = gc->fgPixel; @@ -155,12 +155,7 @@ glamor_set_solid(PixmapPtr pixmap, } Bool -glamor_set_texture(PixmapPtr pixmap, - PixmapPtr texture, - int off_x, - int off_y, - GLint offset_uniform, - GLint size_inv_uniform) +glamor_set_texture_pixmap(PixmapPtr texture) { glamor_pixmap_private *texture_priv; @@ -175,6 +170,23 @@ glamor_set_texture(PixmapPtr pixmap, glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture_priv->fbo->tex); + /* we're not setting the sampler uniform here as we always use + * GL_TEXTURE0, and the default value for uniforms is zero. So, + * save a bit of CPU time by taking advantage of that. + */ + return TRUE; +} + +Bool +glamor_set_texture(PixmapPtr texture, + int off_x, + int off_y, + GLint offset_uniform, + GLint size_inv_uniform) +{ + if (!glamor_set_texture_pixmap(texture)) + return FALSE; + glUniform2f(offset_uniform, off_x, off_y); glUniform2f(size_inv_uniform, 1.0f/texture->drawable.width, 1.0f/texture->drawable.height); return TRUE; @@ -189,11 +201,10 @@ glamor_set_tiled(PixmapPtr pixmap, if (!glamor_set_alu(pixmap->drawable.pScreen, gc->alu)) return FALSE; - if (!glamor_set_planemask(pixmap, gc->planemask)) + if (!glamor_set_planemask(gc->depth, gc->planemask)) return FALSE; - return glamor_set_texture(pixmap, - gc->tile.pixmap, + return glamor_set_texture(gc->tile.pixmap, -gc->patOrg.x, -gc->patOrg.y, offset_uniform, @@ -274,8 +285,7 @@ glamor_set_stippled(PixmapPtr pixmap, if (!glamor_set_solid(pixmap, gc, TRUE, fg_uniform)) return FALSE; - return glamor_set_texture(pixmap, - stipple, + return glamor_set_texture(stipple, -gc->patOrg.x, -gc->patOrg.y, offset_uniform, diff --git a/xorg-server/glamor/glamor_transform.h b/xorg-server/glamor/glamor_transform.h index 36b789af8..dca6a26ab 100644 --- a/xorg-server/glamor/glamor_transform.h +++ b/xorg-server/glamor/glamor_transform.h @@ -39,8 +39,10 @@ glamor_set_color(PixmapPtr pixmap, GLint uniform); Bool -glamor_set_texture(PixmapPtr pixmap, - PixmapPtr texture, +glamor_set_texture_pixmap(PixmapPtr texture); + +Bool +glamor_set_texture(PixmapPtr texture, int off_x, int off_y, GLint offset_uniform, diff --git a/xorg-server/glamor/glamor_utils.c b/xorg-server/glamor/glamor_utils.c index f06896096..d3e6fd3ff 100644 --- a/xorg-server/glamor/glamor_utils.c +++ b/xorg-server/glamor/glamor_utils.c @@ -31,7 +31,7 @@ glamor_solid_boxes(PixmapPtr pixmap, xRectangle *rect; int n; - rect = malloc(nbox * sizeof (xRectangle)); + rect = xallocarray(nbox, sizeof(xRectangle)); if (!rect) return; for (n = 0; n < nbox; n++) { |