summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2010-04-17 02:56:19 +0200
committerBenjamin Otte <otte@redhat.com>2010-04-23 23:30:30 +0200
commit0bec1672945ac11c9a6d45aef6a19a1e2e662f70 (patch)
tree791f560a234a139f880d1b7d9305465d74023b29
parent1818c709dde0b93dd8e27a5e4da5ce77c01ed519 (diff)
gl: Add cairo_gl_surface_create_for_texture()
This creates a Cairo surface from a given texture. This allows using content previously created using OpenGL inside Cairo.
-rw-r--r--src/cairo-gl-private.h3
-rw-r--r--src/cairo-gl-surface.c133
-rw-r--r--src/cairo-gl.h5
3 files changed, 86 insertions, 55 deletions
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 803b00ac..8512ab59 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -71,6 +71,7 @@ typedef struct _cairo_gl_surface {
int width, height;
GLuint tex; /* GL texture object containing our data. */
+ cairo_bool_t owns_tex; /* TRUE if the surface created the texture */
GLuint fb; /* GL framebuffer object wrapping our data. */
} cairo_gl_surface_t;
@@ -352,6 +353,6 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
cairo_gl_shader_program_t **out_program);
slim_hidden_proto (cairo_gl_surface_create);
-slim_hidden_proto (cairo_gl_surface_make_current);
+slim_hidden_proto (cairo_gl_surface_create_for_texture);
#endif /* CAIRO_GL_PRIVATE_H */
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 64c12397..d4028d57 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -356,26 +356,6 @@ _cairo_gl_set_destination (cairo_gl_surface_t *surface)
glLoadIdentity ();
}
-void
-cairo_gl_surface_make_current (cairo_surface_t *surface)
-{
- cairo_gl_context_t *ctx = (cairo_gl_context_t *) surface->device;
-
- cairo_status_t status;
-
- if (! _cairo_surface_is_gl (surface)) {
- status = _cairo_surface_set_error (surface,
- CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
- return;
- }
-
- /* external API calling into us is bad */
- assert (ctx->current_target == NULL);
- _cairo_gl_set_destination ((cairo_gl_surface_t *) surface);
- ctx->current_target = NULL;
-}
-slim_hidden_def (cairo_gl_surface_make_current);
-
cairo_bool_t
_cairo_gl_operator_is_supported (cairo_operator_t op)
{
@@ -503,6 +483,7 @@ _cairo_gl_surface_init (cairo_device_t *device,
static cairo_surface_t *
_cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
cairo_content_t content,
+ GLuint texture_id,
int width,
int height)
{
@@ -524,36 +505,42 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
if (height < 1)
height = 1;
- switch (content) {
- default:
- ASSERT_NOT_REACHED;
- case CAIRO_CONTENT_COLOR_ALPHA:
- format = GL_RGBA;
- break;
- case CAIRO_CONTENT_ALPHA:
- /* We want to be trying GL_ALPHA framebuffer objects here. */
- format = GL_RGBA;
- break;
- case CAIRO_CONTENT_COLOR:
- /* GL_RGB is almost what we want here -- sampling 1 alpha when
- * texturing, using 1 as destination alpha factor in blending,
- * etc. However, when filtering with GL_CLAMP_TO_BORDER, the
- * alpha channel of the border color will also be clamped to
- * 1, when we actually want the border color we explicitly
- * specified. So, we have to store RGBA, and fill the alpha
- * channel with 1 when blending.
- */
- format = GL_RGBA;
- break;
- }
+ if (texture_id == 0) {
+ switch (content) {
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ format = GL_RGBA;
+ break;
+ case CAIRO_CONTENT_ALPHA:
+ /* We want to be trying GL_ALPHA framebuffer objects here. */
+ format = GL_RGBA;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ /* GL_RGB is almost what we want here -- sampling 1 alpha when
+ * texturing, using 1 as destination alpha factor in blending,
+ * etc. However, when filtering with GL_CLAMP_TO_BORDER, the
+ * alpha channel of the border color will also be clamped to
+ * 1, when we actually want the border color we explicitly
+ * specified. So, we have to store RGBA, and fill the alpha
+ * channel with 1 when blending.
+ */
+ format = GL_RGBA;
+ break;
+ }
- /* Create the texture used to store the surface's data. */
- glGenTextures (1, &surface->tex);
- glBindTexture (ctx->tex_target, surface->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, NULL);
+ /* Create the texture used to store the surface's data. */
+ glGenTextures (1, &surface->tex);
+ surface->owns_tex = TRUE;
+ glBindTexture (ctx->tex_target, surface->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, NULL);
+ } else {
+ surface->tex = texture_id;
+ surface->owns_tex = FALSE;
+ }
/* Create a framebuffer object wrapping the texture so that we can render
* to it.
@@ -627,7 +614,7 @@ cairo_gl_surface_create (cairo_device_t *abstract_device,
return _cairo_surface_create_in_error (status);
surface = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_scratch (ctx, content, width, height);
+ _cairo_gl_surface_create_scratch (ctx, content, 0, width, height);
if (unlikely (surface->base.status)) {
_cairo_gl_context_release (ctx);
return &surface->base;
@@ -647,6 +634,47 @@ cairo_gl_surface_create (cairo_device_t *abstract_device,
}
slim_hidden_def (cairo_gl_surface_create);
+cairo_surface_t *
+cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device,
+ unsigned int texture_id)
+{
+ cairo_gl_context_t *ctx = (cairo_gl_context_t *) abstract_device;
+ cairo_gl_surface_t *surface;
+ cairo_status_t status;
+ int width, height;
+
+ if (ctx == NULL || ctx->base.backend->type != CAIRO_DEVICE_TYPE_GL)
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+
+ status = _cairo_gl_context_acquire (abstract_device, &ctx);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
+
+ glBindTexture (ctx->tex_target, texture_id);
+ glGetTexLevelParameteriv (ctx->tex_target, 0, GL_TEXTURE_WIDTH, &width );
+ glGetTexLevelParameteriv (ctx->tex_target, 0, GL_TEXTURE_HEIGHT, &height);
+
+ surface = (cairo_gl_surface_t *)
+ _cairo_gl_surface_create_scratch (ctx, CAIRO_CONTENT_COLOR_ALPHA, texture_id, width, height);
+ if (unlikely (surface->base.status)) {
+ _cairo_gl_context_release (ctx);
+ return &surface->base;
+ }
+
+ /* Cairo surfaces start out initialized to transparent (black) */
+ status = _cairo_gl_surface_clear (surface);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&surface->base);
+ _cairo_gl_context_release (ctx);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ _cairo_gl_context_release (ctx);
+
+ return &surface->base;
+}
+slim_hidden_def (cairo_gl_surface_create_for_texture);
+
void
cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
int width,
@@ -748,7 +776,7 @@ _cairo_gl_surface_create_similar (void *abstract_surface,
if (unlikely (status))
return _cairo_surface_create_in_error (status);
- surface = _cairo_gl_surface_create_scratch (ctx, content, width, height);
+ surface = _cairo_gl_surface_create_scratch (ctx, content, 0, width, height);
_cairo_gl_context_release (ctx);
return surface;
@@ -1006,7 +1034,8 @@ _cairo_gl_surface_finish (void *abstract_surface)
cairo_gl_context_t *ctx = (cairo_gl_context_t *) surface->base.device;
glDeleteFramebuffersEXT (1, &surface->fb);
- glDeleteTextures (1, &surface->tex);
+ if (surface->owns_tex)
+ glDeleteTextures (1, &surface->tex);
if (ctx->current_target == surface)
ctx->current_target = NULL;
diff --git a/src/cairo-gl.h b/src/cairo-gl.h
index 50e14994..03eb5a40 100644
--- a/src/cairo-gl.h
+++ b/src/cairo-gl.h
@@ -45,8 +45,9 @@ cairo_gl_surface_create (cairo_device_t *device,
cairo_content_t content,
int width, int height);
-cairo_public void
-cairo_gl_surface_make_current (cairo_surface_t *surface);
+cairo_public cairo_surface_t *
+cairo_gl_surface_create_for_texture (cairo_device_t *device,
+ unsigned int texture_id);
cairo_public void
cairo_gl_surface_set_size (cairo_surface_t *surface, int width, int height);