diff options
author | Benjamin Otte <otte@redhat.com> | 2010-04-17 02:56:19 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2010-04-23 23:30:30 +0200 |
commit | 0bec1672945ac11c9a6d45aef6a19a1e2e662f70 (patch) | |
tree | 791f560a234a139f880d1b7d9305465d74023b29 | |
parent | 1818c709dde0b93dd8e27a5e4da5ce77c01ed519 (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.h | 3 | ||||
-rw-r--r-- | src/cairo-gl-surface.c | 133 | ||||
-rw-r--r-- | src/cairo-gl.h | 5 |
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); |