glamor: Replace CompositeGlyphs code [v2]
New composite glyphs code uses the updated glamor program infrastructure to create efficient shaders for drawing render text. Glyphs are cached in two atlases (one 8-bit, one 32-bit) in a simple linear fashion. When the atlas fills, it is discarded and a new one constructed. v2: Eric Anholt changed the non-GLSL 130 path to use quads instead of two triangles for a significant performance improvement on hardware with quads. Someone can fix the GLES quads emulation if they want to make it faster there. v3: Eric found more dead code to delete Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
		
							parent
							
								
									1b745e0c1f
								
							
						
					
					
						commit
						b0d2e01031
					
				|  | @ -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 \
 | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
| 
 | ||||
|  | @ -509,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; | ||||
| 
 | ||||
|  | @ -550,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; | ||||
|  | @ -634,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; | ||||
|  | @ -655,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); | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -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]; | ||||
|  | @ -707,17 +678,6 @@ 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" | ||||
| 
 | ||||
|  |  | |||
|  | @ -139,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]) | ||||
|  | @ -355,6 +359,7 @@ glamor_build_program(ScreenPtr          screen, | |||
|     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); | ||||
|  |  | |||
|  | @ -81,6 +81,7 @@ 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; | ||||
|  |  | |||
|  | @ -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); | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue