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
This commit is contained in:
parent
7b369445b3
commit
e90ded6c23
@ -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 \
|
||||
|
@ -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 <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
389
clutter/cogl/cogl/cogl-blit.c
Normal file
389
clutter/cogl/cogl/cogl-blit.c
Normal file
@ -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 <neil@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
89
clutter/cogl/cogl/cogl-blit.h
Normal file
89
clutter/cogl/cogl/cogl-blit.h
Normal file
@ -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 <glib.h>
|
||||
#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 */
|
@ -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)
|
||||
|
@ -175,6 +175,7 @@ typedef struct
|
||||
gboolean in_begin_gl_block;
|
||||
|
||||
CoglPipeline *texture_download_pipeline;
|
||||
CoglPipeline *blit_texture_pipeline;
|
||||
|
||||
GSList *atlases;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user