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

Yuanhan Liu <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <[email protected]>
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 <[email protected]>
---
 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

--
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.