[cairo] [PATCH] gl: fix wrong references of texture in another gl_ctx

Yuanhan Liu yuanhan.liu at linux.intel.com
Thu May 24 04:37:49 PDT 2012


If we do something like following:

	cr1 = cairo_create(surf1);
	cr2 = cairo_create(surf2);

	... draw something to surf1 ...

	cairo_set_source_surface(cr2, surf1);
	cairo_rectangle(cr2, ..... );
	cairo_fill(cr2);

You will find the current code will reference a texture in cr1 gl
context while drawing cr2. Thus it references a null texture and results
to wrong rendering.

This patch severs as fixing this issue(like gl-surface-source test case)
by copying out the texture from cr1, then regenerating a new one to cr2.

Signed-off-by: Yuanhan Liu <yuanhan.liu at linux.intel.com>
---
 src/cairo-gl-composite.c        |   77 +++++++++++++++++++++++++++++++++++++--
 src/cairo-gl-glyphs.c           |    3 +-
 src/cairo-gl-private.h          |    4 ++-
 src/cairo-gl-spans-compositor.c |    5 +--
 src/cairo-gl-surface.c          |    7 ++++
 src/cairo-gl-traps-compositor.c |   12 ++----
 6 files changed, 91 insertions(+), 17 deletions(-)

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index bcf41ec..97c6118 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -63,12 +63,83 @@ _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
 				   sample, extents);
 }
 
+static cairo_status_t
+_cairo_gl_composite_set_source_texture_operand (cairo_gl_composite_t *setup,
+						cairo_surface_t *src)
+{
+    cairo_gl_context_t *ctx;
+    cairo_gl_surface_t *src_gl_surf = (cairo_gl_surface_t *)src;
+    cairo_status_t status;
+    GLvoid *pixels;
+    GLuint dst_tex;
+    GLint src_tex = src_gl_surf->operand.texture.tex;
+    int width = src_gl_surf->width;
+    int height = src_gl_surf->height;
+    int cpp = src_gl_surf->cpp;
+    GLenum format = src_gl_surf->format;
+
+
+    /*
+     * A flush is a need to keep things in order
+     *
+     * FIXME: or we may delay it at the draw time?
+     */
+    cairo_surface_flush(src);
+    cairo_surface_flush(&setup->dst->base);
+
+    /* Read the texture from src surface first */
+    status = _cairo_gl_context_acquire(src->device, &ctx);
+    if (unlikely(status))
+        return status;
+
+    pixels = malloc(width * height * cpp);
+    glBindTexture(ctx->tex_target, src_tex);
+    glGetTexImage(ctx->tex_target, 0, format, GL_UNSIGNED_BYTE, pixels);
+    status = _cairo_gl_context_release(ctx, status);
+    if (unlikely(status))
+        return status;
+
+
+    /* regenerate a texture in the dest surface */
+    status = _cairo_gl_context_acquire(setup->dst->base.device, &ctx);
+    if (unlikely(status))
+        goto fail;
+
+    glGenTextures(1, &dst_tex);
+    glBindTexture(ctx->tex_target, dst_tex);
+    glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexImage2D(ctx->tex_target, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, pixels);
+
+    _cairo_gl_operand_destroy(&setup->src);
+    setup->src = src_gl_surf->operand;
+    setup->src.texture.tex = dst_tex;
+
+    status = _cairo_gl_context_release(ctx, status);
+
+fail:
+    free(pixels);
+    return status;
+}
+
 void
 _cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
-					const cairo_gl_operand_t *source)
+					const cairo_surface_t *src)
 {
-    _cairo_gl_operand_destroy (&setup->src);
-    _cairo_gl_operand_copy (&setup->src, source);
+    cairo_gl_operand_t *operand = source_to_operand(src);
+
+    /*
+     * When we try to use a texture from another gl_ctx, we should
+     * handle it in a special way, like extract it from src_gl_ctx,
+     * then remake a texture in dst_gl_ctx.
+     */
+    if ((operand && operand->type == CAIRO_GL_OPERAND_TEXTURE) &&
+        (src->device && src->device != setup->dst->base.device)) {
+        _cairo_gl_composite_set_source_texture_operand(setup, src);
+    } else {
+        _cairo_gl_operand_destroy (&setup->src);
+        _cairo_gl_operand_copy (&setup->src, operand);
+    }
 }
 
 void
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index c2660ac..6afced9 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -252,8 +252,7 @@ render_glyphs (cairo_gl_surface_t *dst,
     if (source == NULL) {
 	    _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_WHITE);
     } else {
-	    _cairo_gl_composite_set_source_operand (&setup,
-						    source_to_operand (source));
+	    _cairo_gl_composite_set_source_operand (&setup, source);
 
     }
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index eb75cd9..f354c63 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -159,6 +159,8 @@ struct _cairo_gl_surface {
     cairo_gl_operand_t operand;
 
     int width, height;
+    int cpp;
+    GLenum format;
 
     GLuint tex; /* GL texture object containing our data. */
     GLuint fb; /* GL framebuffer object wrapping our data. */
@@ -506,7 +508,7 @@ _cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
 
 cairo_private void
 _cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
-					const cairo_gl_operand_t *source);
+					const cairo_surface_t *src);
 
 cairo_private cairo_int_status_t
 _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
diff --git a/src/cairo-gl-spans-compositor.c b/src/cairo-gl-spans-compositor.c
index 4c5cef6..ae8668f 100644
--- a/src/cairo-gl-spans-compositor.c
+++ b/src/cairo-gl-spans-compositor.c
@@ -327,7 +327,7 @@ static cairo_int_status_t copy_boxes (void *_dst,
     if (unlikely (status))
         goto FAIL;
 
-    _cairo_gl_composite_set_source_operand (&setup, source_to_operand (src));
+    _cairo_gl_composite_set_source_operand (&setup, src);
     _cairo_gl_operand_translate (&setup.src, -dx, -dy);
 
     status = _cairo_gl_composite_begin (&setup, &ctx);
@@ -382,8 +382,7 @@ composite_boxes (void			*_dst,
     if (unlikely (status))
         goto FAIL;
 
-    _cairo_gl_composite_set_source_operand (&setup,
-					    src_operand);
+    _cairo_gl_composite_set_source_operand(&setup, abstract_src);
     _cairo_gl_operand_translate (&setup.src, -src_x, -src_y);
 
     _cairo_gl_composite_set_mask_operand (&setup,
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index c2e9687..494363b 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -433,6 +433,7 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
     cairo_gl_surface_t *surface;
     GLenum format;
     GLuint tex;
+    int cpp;
 
     glGenTextures (1, &tex);
     surface = (cairo_gl_surface_t *)
@@ -454,10 +455,12 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
 	ASSERT_NOT_REACHED;
     case CAIRO_CONTENT_COLOR_ALPHA:
 	format = GL_RGBA;
+	cpp = 4;
 	break;
     case CAIRO_CONTENT_ALPHA:
 	/* We want to be trying GL_ALPHA framebuffer objects here. */
 	format = GL_RGBA;
+	cpp = 4;
 	break;
     case CAIRO_CONTENT_COLOR:
 	/* GL_RGB is almost what we want here -- sampling 1 alpha when
@@ -469,12 +472,16 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
 	 * channel with 1 when blending.
 	 */
 	format = GL_RGBA;
+	cpp = 4;
 	break;
     }
 
     glTexImage2D (ctx->tex_target, 0, format, width, height, 0,
 		  format, GL_UNSIGNED_BYTE, NULL);
 
+    surface->format = format;
+    surface->cpp = cpp;
+
     return &surface->base;
 }
 
diff --git a/src/cairo-gl-traps-compositor.c b/src/cairo-gl-traps-compositor.c
index 776b74c..b0f5bf8 100644
--- a/src/cairo-gl-traps-compositor.c
+++ b/src/cairo-gl-traps-compositor.c
@@ -172,8 +172,7 @@ composite_boxes (void			*_dst,
     if (unlikely (status))
         goto FAIL;
 
-    _cairo_gl_composite_set_source_operand (&setup,
-					    source_to_operand (abstract_src));
+    _cairo_gl_composite_set_source_operand (&setup, abstract_src);
 
     _cairo_gl_composite_set_mask_operand (&setup,
 					  source_to_operand (abstract_mask));
@@ -212,8 +211,7 @@ composite (void			*_dst,
     if (unlikely (status))
         goto FAIL;
 
-    _cairo_gl_composite_set_source_operand (&setup,
-					    source_to_operand (abstract_src));
+    _cairo_gl_composite_set_source_operand (&setup, abstract_src);
 
     _cairo_gl_composite_set_mask_operand (&setup,
 					  source_to_operand (abstract_mask));
@@ -354,8 +352,7 @@ composite_traps (void			*_dst,
     if (unlikely (status))
         goto FAIL;
 
-    _cairo_gl_composite_set_source_operand (&setup,
-					    source_to_operand (abstract_src));
+    _cairo_gl_composite_set_source_operand (&setup, abstract_src);
     status = traps_to_operand (_dst, extents, antialias, traps, &setup.mask);
     if (unlikely (status))
 	goto FAIL;
@@ -451,8 +448,7 @@ composite_tristrip (void		*_dst,
     if (unlikely (status))
         goto FAIL;
 
-    _cairo_gl_composite_set_source_operand (&setup,
-					    source_to_operand (abstract_src));
+    _cairo_gl_composite_set_source_operand (&setup, abstract_src);
 
     //_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0);
 
-- 
1.7.7.6



More information about the cairo mailing list