From c8ddb3b55a0a0f46f1c3068fd32dba3f4b198979 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 20 Jan 2011 17:45:47 +0000 Subject: [PATCH] cogl-atlas: Try 4 different approaches for migrating textures Instead of directly banging GL to migrate textures the atlas now uses the CoglFramebuffer API. It will use one of four approaches; it can set up two FBOs and use _cogl_blit_framebuffer to copy between them; it can use a single target fbo and then render the source texture to the FBO using a Cogl draw call; it can use a single FBO and call glCopyTexSubImage2D; or it can fallback to reading all of the texture data back to system memory and uploading it again with a sub texture update. Previously GL calls were used directly because Cogl wasn't able to create a framebuffer without a stencil and depth buffer. However there is now an internal version of cogl_offscreen_new_to_texture which takes a set of flags to disable the two buffers. The code for blitting has now been moved into a separate file called cogl-blit.c because it has become quite long and it may be useful outside of the atlas at some point. The 4 different methods have a fixed order of preference which is: * Texture render between two FBOs * glBlitFramebuffer * glCopyTexSubImage2D * glGetTexImage + glTexSubImage2D Once a method is succesfully used it is tried first for all subsequent blits. The default default can be overridden by setting the environment variable COGL_ATLAS_DEFAULT_BLIT_MODE to one of the following values: * texture-render * framebuffer * copy-tex-sub-image * get-tex-data --- cogl/Makefile.am | 2 + cogl/cogl-atlas.c | 185 ++------------------- cogl/cogl-blit.c | 389 ++++++++++++++++++++++++++++++++++++++++++++ cogl/cogl-blit.h | 89 ++++++++++ cogl/cogl-context.c | 4 + cogl/cogl-context.h | 1 + 6 files changed, 501 insertions(+), 169 deletions(-) create mode 100644 cogl/cogl-blit.c create mode 100644 cogl/cogl-blit.h diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 87ed88983..e21426d2d 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -251,6 +251,8 @@ cogl_sources_c = \ $(srcdir)/cogl-atlas.c \ $(srcdir)/cogl-atlas-texture-private.h \ $(srcdir)/cogl-atlas-texture.c \ + $(srcdir)/cogl-blit.h \ + $(srcdir)/cogl-blit.c \ $(srcdir)/cogl-spans.h \ $(srcdir)/cogl-spans.c \ $(srcdir)/cogl-journal-private.h \ diff --git a/cogl/cogl-atlas.c b/cogl/cogl-atlas.c index 2b3a743a8..60be9e51d 100644 --- a/cogl/cogl-atlas.c +++ b/cogl/cogl-atlas.c @@ -37,168 +37,15 @@ #include "cogl-texture-driver.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-debug.h" +#include "cogl-framebuffer-private.h" +#include "cogl-blit.h" #include -#ifndef HAVE_COGL_GLES2 - -#define glGenFramebuffers ctx->drv.pf_glGenFramebuffers -#define glBindFramebuffer ctx->drv.pf_glBindFramebuffer -#define glFramebufferTexture2D ctx->drv.pf_glFramebufferTexture2D -#define glCheckFramebufferStatus ctx->drv.pf_glCheckFramebufferStatus -#define glDeleteFramebuffers ctx->drv.pf_glDeleteFramebuffers - -#endif /* HAVE_COGL_GLES2 */ - -#ifndef GL_FRAMEBUFFER -#define GL_FRAMEBUFFER 0x8D40 -#endif -#ifndef GL_FRAMEBUFFER_BINDING -#define GL_FRAMEBUFFER_BINDING 0x8CA6 -#endif -#ifndef GL_COLOR_ATTACHMENT0 -#define GL_COLOR_ATTACHMENT0 0x8CE0 -#endif -#ifndef GL_FRAMEBUFFER_COMPLETE -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 -#endif - static void _cogl_atlas_free (CoglAtlas *atlas); COGL_OBJECT_INTERNAL_DEFINE (Atlas, atlas); -/* If we want to do mulitple blits from a texture (such as when - reorganizing the atlas) then it's quicker to download all of the - data once and upload multiple times from that. This struct is used - to keep the image data for a series of blits */ - -typedef struct _CoglAtlasBlitData -{ - CoglHandle src_tex, dst_tex; - - /* If we're using an FBO to blit, then FBO will be non-zero and - old_fbo will be the previous framebuffer binding */ - GLuint fbo, old_fbo; - - /* If we're not using an FBO then we g_malloc a buffer and copy the - complete texture data in */ - unsigned char *image_data; - CoglPixelFormat format; - int bpp; - unsigned int src_height, src_width; - - GLenum dst_gl_target; -} CoglAtlasBlitData; - -static void -_cogl_atlas_blit_begin (CoglAtlasBlitData *data, - CoglHandle dst_tex, - CoglHandle src_tex) -{ - GLenum src_gl_target; - GLuint src_gl_texture; - GLuint dst_gl_texture; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - data->dst_tex = dst_tex; - data->src_tex = src_tex; - data->fbo = 0; - - /* If we can use an FBO then we don't need to download the data and - we can tell GL to blit directly between the textures */ - if (cogl_features_available (COGL_FEATURE_OFFSCREEN) && - !cogl_texture_is_sliced (dst_tex) && - cogl_texture_get_gl_texture (src_tex, &src_gl_texture, &src_gl_target) && - cogl_texture_get_gl_texture (dst_tex, &dst_gl_texture, - &data->dst_gl_target)) - { - /* Ideally we would use the cogl-offscreen API here, but I'd - rather avoid creating a stencil renderbuffer which you can't - currently do */ - /* Preserve the previous framebuffer binding so we don't trample - on cogl-offscreen */ - data->old_fbo = 0; - GE( glGetIntegerv (GL_FRAMEBUFFER_BINDING, (GLint *) &data->old_fbo) ); - - _cogl_texture_set_filters (src_tex, GL_NEAREST, GL_NEAREST); - - /* Create an FBO to read from the src texture */ - GE( glGenFramebuffers (1, &data->fbo) ); - GE( glBindFramebuffer (GL_FRAMEBUFFER, data->fbo) ); - GE( glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - src_gl_target, src_gl_texture, 0) ); - if (glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - { - /* The FBO failed for whatever reason so we'll fallback to - reading the texture data */ - GE( glBindFramebuffer (GL_FRAMEBUFFER, data->old_fbo) ); - GE( glDeleteFramebuffers (1, &data->fbo) ); - data->fbo = 0; - } - - _cogl_bind_gl_texture_transient (data->dst_gl_target, - dst_gl_texture, - FALSE); - } - - if (data->fbo) - COGL_NOTE (ATLAS, "Blit set up using an FBO"); - else - { - /* We need to retrieve the entire texture data (there is no - glGetTexSubImage2D) */ - - data->format = cogl_texture_get_format (src_tex); - data->bpp = _cogl_get_format_bpp (data->format); - data->src_width = cogl_texture_get_width (src_tex); - data->src_height = cogl_texture_get_height (src_tex); - - data->image_data = g_malloc (data->bpp * data->src_width * - data->src_height); - cogl_texture_get_data (src_tex, data->format, - data->src_width * data->bpp, data->image_data); - } -} - -static void -_cogl_atlas_blit (CoglAtlasBlitData *data, - unsigned int src_x, - unsigned int src_y, - unsigned int dst_x, - unsigned int dst_y, - unsigned int width, - unsigned int height) -{ - /* If we have an FBO then we can do a fast blit */ - if (data->fbo) - GE( glCopyTexSubImage2D (data->dst_gl_target, 0, dst_x, dst_y, src_x, src_y, - width, height) ); - else - cogl_texture_set_region (data->dst_tex, - src_x, src_y, - dst_x, dst_y, - width, height, - data->src_width, data->src_height, - data->format, - data->src_width * data->bpp, - data->image_data); -} - -static void -_cogl_atlas_blit_end (CoglAtlasBlitData *data) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (data->fbo) - { - GE( glBindFramebuffer (GL_FRAMEBUFFER, data->old_fbo) ); - GE( glDeleteFramebuffers (1, &data->fbo) ); - } - else - g_free (data->image_data); -} - CoglAtlas * _cogl_atlas_new (CoglPixelFormat texture_format, CoglAtlasFlags flags, @@ -249,7 +96,7 @@ _cogl_atlas_migrate (CoglAtlas *atlas, void *skip_user_data) { unsigned int i; - CoglAtlasBlitData blit_data; + CoglBlitData blit_data; /* If the 'disable migrate' flag is set then we won't actually copy the textures to their new location. Instead we'll just invoke the @@ -262,20 +109,20 @@ _cogl_atlas_migrate (CoglAtlas *atlas, &textures[i].new_position); else { - _cogl_atlas_blit_begin (&blit_data, new_texture, old_texture); + _cogl_blit_begin (&blit_data, new_texture, old_texture); for (i = 0; i < n_textures; i++) { /* Skip the texture that is being added because it doesn't contain any data yet */ if (textures[i].user_data != skip_user_data) - _cogl_atlas_blit (&blit_data, - textures[i].old_position.x, - textures[i].old_position.y, - textures[i].new_position.x, - textures[i].new_position.y, - textures[i].new_position.width, - textures[i].new_position.height); + _cogl_blit (&blit_data, + textures[i].old_position.x, + textures[i].old_position.y, + textures[i].new_position.x, + textures[i].new_position.y, + textures[i].new_position.width, + textures[i].new_position.height); /* Update the texture position */ atlas->update_position_cb (textures[i].user_data, @@ -283,7 +130,7 @@ _cogl_atlas_migrate (CoglAtlas *atlas, &textures[i].new_position); } - _cogl_atlas_blit_end (&blit_data); + _cogl_blit_end (&blit_data); } } @@ -663,7 +510,7 @@ _cogl_atlas_copy_rectangle (CoglAtlas *atlas, CoglPixelFormat format) { CoglHandle tex; - CoglAtlasBlitData blit_data; + CoglBlitData blit_data; /* Create a new texture at the right size */ tex = cogl_texture_new_with_size (width, height, flags, format); @@ -671,12 +518,12 @@ _cogl_atlas_copy_rectangle (CoglAtlas *atlas, /* Blit the data out of the atlas to the new texture. If FBOs aren't available this will end up having to copy the entire atlas texture */ - _cogl_atlas_blit_begin (&blit_data, tex, atlas->texture); - _cogl_atlas_blit (&blit_data, + _cogl_blit_begin (&blit_data, tex, atlas->texture); + _cogl_blit (&blit_data, x, y, 0, 0, width, height); - _cogl_atlas_blit_end (&blit_data); + _cogl_blit_end (&blit_data); return tex; } diff --git a/cogl/cogl-blit.c b/cogl/cogl-blit.c new file mode 100644 index 000000000..1c40e348b --- /dev/null +++ b/cogl/cogl-blit.c @@ -0,0 +1,389 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2011 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * Neil Roberts + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "cogl.h" +#include "cogl-blit.h" +#include "cogl-context.h" +#include "cogl-framebuffer-private.h" +#include "cogl-texture-2d-private.h" + +static const CoglBlitMode *_cogl_blit_default_mode = NULL; + +static gboolean +_cogl_blit_texture_render_begin (CoglBlitData *data) +{ + CoglHandle fbo; + CoglPipeline *pipeline; + unsigned int dst_width, dst_height; + + _COGL_GET_CONTEXT (ctx, FALSE); + + fbo = _cogl_offscreen_new_to_texture_full + (data->dst_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */); + + if (fbo == COGL_INVALID_HANDLE) + return FALSE; + + cogl_push_framebuffer (fbo); + cogl_handle_unref (fbo); + + dst_width = cogl_texture_get_width (data->dst_tex); + dst_height = cogl_texture_get_height (data->dst_tex); + + /* Set up an orthographic projection so we can use pixel + coordinates to render to the texture */ + cogl_ortho (0, /* left */ + dst_width, /* right */ + dst_height, /* bottom */ + 0, /* top */ + -1, /* near */ + 1 /* far */); + + /* We cache a pipeline used for migrating on to the context so + that it doesn't have to continuously regenerate a shader + program */ + if (ctx->blit_texture_pipeline == NULL) + { + ctx->blit_texture_pipeline = cogl_pipeline_new (); + + cogl_pipeline_set_layer_filters (ctx->blit_texture_pipeline, 0, + COGL_PIPELINE_FILTER_NEAREST, + COGL_PIPELINE_FILTER_NEAREST); + } + + pipeline = ctx->blit_texture_pipeline; + + cogl_pipeline_set_layer_texture (pipeline, 0, data->src_tex); + + cogl_push_source (pipeline); + + return TRUE; +} + +static void +_cogl_blit_texture_render_blit (CoglBlitData *data, + unsigned int src_x, + unsigned int src_y, + unsigned int dst_x, + unsigned int dst_y, + unsigned int width, + unsigned int height) +{ + cogl_rectangle_with_texture_coords (dst_x, dst_y, + dst_x + width, + dst_y + height, + src_x / (float) data->src_width, + src_y / (float) data->src_height, + (src_x + width) / + (float) data->src_width, + (src_y + height) / + (float) data->src_height); +} + +static void +_cogl_blit_texture_render_end (CoglBlitData *data) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + cogl_pop_source (); + cogl_pop_framebuffer (); + + /* Attach the target texture to the texture render pipeline so that + we don't keep a reference to the source texture forever. This is + assuming that the destination texture will live for a long time + which is currently the case when cogl_blit_* is used from the + atlas code. It may be better in future to keep around a set of + dummy 1x1 textures for each texture target that we could bind + instead. This would also be useful when using a pipeline as a + hash table key such as for the ARBfp program cache. */ + cogl_pipeline_set_layer_texture (ctx->blit_texture_pipeline, 0, + data->dst_tex); +} + +static gboolean +_cogl_blit_framebuffer_begin (CoglBlitData *data) +{ + CoglHandle dst_fbo, src_fbo; + + _COGL_GET_CONTEXT (ctx, FALSE); + + /* We can only blit between FBOs if both textures are the same + format and the blit framebuffer extension is supported */ + if ((cogl_texture_get_format (data->src_tex) & ~COGL_A_BIT) != + (cogl_texture_get_format (data->dst_tex) & ~COGL_A_BIT) || + !cogl_features_available (COGL_FEATURE_OFFSCREEN_BLIT)) + return FALSE; + + dst_fbo = _cogl_offscreen_new_to_texture_full + (data->dst_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */); + + if (dst_fbo == COGL_INVALID_HANDLE) + return FALSE; + + src_fbo = _cogl_offscreen_new_to_texture_full + (data->src_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */); + + if (src_fbo == COGL_INVALID_HANDLE) + { + cogl_handle_unref (dst_fbo); + return FALSE; + } + + _cogl_push_framebuffers (dst_fbo, src_fbo); + cogl_handle_unref (src_fbo); + cogl_handle_unref (dst_fbo); + + return TRUE; +} + +static void +_cogl_blit_framebuffer_blit (CoglBlitData *data, + unsigned int src_x, + unsigned int src_y, + unsigned int dst_x, + unsigned int dst_y, + unsigned int width, + unsigned int height) +{ + _cogl_blit_framebuffer (src_x, src_y, + dst_x, dst_y, + width, height); +} + +static void +_cogl_blit_framebuffer_end (CoglBlitData *data) +{ + cogl_pop_framebuffer (); +} + +static gboolean +_cogl_blit_copy_tex_sub_image_begin (CoglBlitData *data) +{ + CoglHandle fbo; + + _COGL_GET_CONTEXT (ctx, FALSE); + + /* This will only work if the target texture is a CoglTexture2D */ + if (!_cogl_is_texture_2d (data->dst_tex)) + return FALSE; + + fbo = _cogl_offscreen_new_to_texture_full + (data->src_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */); + + if (fbo == COGL_INVALID_HANDLE) + return FALSE; + + cogl_push_framebuffer (fbo); + cogl_handle_unref (fbo); + + return TRUE; +} + +static void +_cogl_blit_copy_tex_sub_image_blit (CoglBlitData *data, + unsigned int src_x, + unsigned int src_y, + unsigned int dst_x, + unsigned int dst_y, + unsigned int width, + unsigned int height) +{ + _cogl_texture_2d_copy_from_framebuffer (data->dst_tex, + dst_x, dst_y, + src_x, src_y, + width, height); +} + +static void +_cogl_blit_copy_tex_sub_image_end (CoglBlitData *data) +{ + cogl_pop_framebuffer (); +} + +static gboolean +_cogl_blit_get_tex_data_begin (CoglBlitData *data) +{ + data->format = cogl_texture_get_format (data->src_tex); + data->bpp = _cogl_get_format_bpp (data->format); + + data->image_data = g_malloc (data->bpp * data->src_width * + data->src_height); + cogl_texture_get_data (data->src_tex, data->format, + data->src_width * data->bpp, data->image_data); + + return TRUE; +} + +static void +_cogl_blit_get_tex_data_blit (CoglBlitData *data, + unsigned int src_x, + unsigned int src_y, + unsigned int dst_x, + unsigned int dst_y, + unsigned int width, + unsigned int height) +{ + cogl_texture_set_region (data->dst_tex, + src_x, src_y, + dst_x, dst_y, + width, height, + data->src_width, data->src_height, + data->format, + data->src_width * data->bpp, + data->image_data); +} + +static void +_cogl_blit_get_tex_data_end (CoglBlitData *data) +{ + g_free (data->image_data); +} + +/* These should be specified in order of preference */ +static const CoglBlitMode +_cogl_blit_modes[] = + { + { + "texture-render", + _cogl_blit_texture_render_begin, + _cogl_blit_texture_render_blit, + _cogl_blit_texture_render_end + }, + { + "framebuffer", + _cogl_blit_framebuffer_begin, + _cogl_blit_framebuffer_blit, + _cogl_blit_framebuffer_end + }, + { + "copy-tex-sub-image", + _cogl_blit_copy_tex_sub_image_begin, + _cogl_blit_copy_tex_sub_image_blit, + _cogl_blit_copy_tex_sub_image_end + }, + { + "get-tex-data", + _cogl_blit_get_tex_data_begin, + _cogl_blit_get_tex_data_blit, + _cogl_blit_get_tex_data_end + } + }; + +void +_cogl_blit_begin (CoglBlitData *data, + CoglHandle dst_tex, + CoglHandle src_tex) +{ + int i; + + if (_cogl_blit_default_mode == NULL) + { + const char *default_mode_string; + + /* Allow the default to be specified with an environment + variable. For the time being these functions are only used + when blitting between atlas textures so the environment + variable is named to be specific to the atlas code. If we + want to use the code in other places we should create another + environment variable for each specific use case */ + if ((default_mode_string = g_getenv ("COGL_ATLAS_DEFAULT_BLIT_MODE"))) + { + for (i = 0; i < G_N_ELEMENTS (_cogl_blit_modes); i++) + if (!strcmp (_cogl_blit_modes[i].name, default_mode_string)) + { + _cogl_blit_default_mode = _cogl_blit_modes + i; + break; + } + + if (i >= G_N_ELEMENTS (_cogl_blit_modes)) + { + g_warning ("Unknown blit mode %s", default_mode_string); + _cogl_blit_default_mode = _cogl_blit_modes; + } + } + else + /* Default to the first blit mode */ + _cogl_blit_default_mode = _cogl_blit_modes; + } + + data->dst_tex = dst_tex; + data->src_tex = src_tex; + + data->src_width = cogl_texture_get_width (src_tex); + data->src_height = cogl_texture_get_height (src_tex); + + /* Try the default blit mode first */ + if (!_cogl_blit_default_mode->begin_func (data)) + { + COGL_NOTE (ATLAS, "Failed to set up blit mode %s", + _cogl_blit_default_mode->name); + + /* Try all of the other modes in order */ + for (i = 0; i < G_N_ELEMENTS (_cogl_blit_modes); i++) + if (_cogl_blit_modes + i != _cogl_blit_default_mode && + _cogl_blit_modes[i].begin_func (data)) + { + /* Use this mode as the default from now on */ + _cogl_blit_default_mode = _cogl_blit_modes + i; + break; + } + else + COGL_NOTE (ATLAS, + "Failed to set up blit mode %s", + _cogl_blit_modes[i].name); + + /* The last blit mode can't fail so this should never happen */ + g_return_if_fail (i < G_N_ELEMENTS (_cogl_blit_modes)); + } + + data->blit_mode = _cogl_blit_default_mode; + + COGL_NOTE (ATLAS, "Setup blit using %s", _cogl_blit_default_mode->name); +} + +void +_cogl_blit (CoglBlitData *data, + unsigned int src_x, + unsigned int src_y, + unsigned int dst_x, + unsigned int dst_y, + unsigned int width, + unsigned int height) +{ + data->blit_mode->blit_func (data, src_x, src_y, dst_x, dst_y, width, height); +} + +void +_cogl_blit_end (CoglBlitData *data) +{ + data->blit_mode->end_func (data); +} diff --git a/cogl/cogl-blit.h b/cogl/cogl-blit.h new file mode 100644 index 000000000..95e708ea3 --- /dev/null +++ b/cogl/cogl-blit.h @@ -0,0 +1,89 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2011 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __COGL_BLIT_H +#define __COGL_BLIT_H + +#include +#include "cogl-handle.h" + +/* This structures and functions are used when a series of blits needs + to be performed between two textures. In this case there are + multiple methods we can use, most of which involve transferring + between an FBO bound to the texture. */ + +typedef struct _CoglBlitData CoglBlitData; + +typedef gboolean (* CoglBlitBeginFunc) (CoglBlitData *data); +typedef void (* CoglBlitEndFunc) (CoglBlitData *data); + +typedef void (* CoglBlitFunc) (CoglBlitData *data, + unsigned int src_x, + unsigned int src_y, + unsigned int dst_x, + unsigned int dst_y, + unsigned int width, + unsigned int height); + +typedef struct +{ + const char *name; + CoglBlitBeginFunc begin_func; + CoglBlitFunc blit_func; + CoglBlitEndFunc end_func; +} CoglBlitMode; + +struct _CoglBlitData +{ + CoglHandle src_tex, dst_tex; + + unsigned int src_width; + unsigned int src_height; + + const CoglBlitMode *blit_mode; + + /* If we're not using an FBO then we g_malloc a buffer and copy the + complete texture data in */ + unsigned char *image_data; + CoglPixelFormat format; + int bpp; +}; + +void +_cogl_blit_begin (CoglBlitData *data, + CoglHandle dst_tex, + CoglHandle src_tex); + +void +_cogl_blit (CoglBlitData *data, + unsigned int src_x, + unsigned int src_y, + unsigned int dst_x, + unsigned int dst_y, + unsigned int width, + unsigned int height); + +void +_cogl_blit_end (CoglBlitData *data); + +#endif /* __COGL_BLIT_H */ diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index bea9357bd..115fc5c67 100644 --- a/cogl/cogl-context.c +++ b/cogl/cogl-context.c @@ -244,6 +244,7 @@ cogl_create_context (void) _context->rectangle_short_indices_len = 0; _context->texture_download_pipeline = COGL_INVALID_HANDLE; + _context->blit_texture_pipeline = COGL_INVALID_HANDLE; #ifndef HAVE_COGL_GLES2 /* The default for GL_ALPHA_TEST is to always pass which is equivalent to @@ -333,6 +334,9 @@ _cogl_destroy_context (void) if (_context->texture_pipeline) cogl_handle_unref (_context->texture_pipeline); + if (_context->blit_texture_pipeline) + cogl_handle_unref (_context->blit_texture_pipeline); + if (_context->journal_flush_attributes_array) g_array_free (_context->journal_flush_attributes_array, TRUE); if (_context->journal_clip_bounds) diff --git a/cogl/cogl-context.h b/cogl/cogl-context.h index 8c0161fab..eead5dc09 100644 --- a/cogl/cogl-context.h +++ b/cogl/cogl-context.h @@ -175,6 +175,7 @@ typedef struct gboolean in_begin_gl_block; CoglPipeline *texture_download_pipeline; + CoglPipeline *blit_texture_pipeline; GSList *atlases;