material: Avoid redundant glBindTexture calls

This adds a _cogl_bind_gl_texture_transient function that should be used
instead of glBindTexture so we can have a consistent cache of the
textures bound to each texture unit so we can avoid some redundant
binding.
This commit is contained in:
Robert Bragg 2010-04-26 10:01:43 +01:00
parent acc44161c1
commit 82e80e6765
11 changed files with 266 additions and 41 deletions

View File

@ -146,7 +146,9 @@ _cogl_atlas_texture_blit_begin (CoglAtlasTextureBlitData *data,
data->fbo = 0; data->fbo = 0;
} }
GE( glBindTexture (data->dst_gl_target, dst_gl_texture) ); _cogl_bind_gl_texture_transient (data->dst_gl_target,
dst_gl_texture,
FALSE);
} }
if (data->fbo) if (data->fbo)
@ -274,7 +276,8 @@ _cogl_atlas_texture_free (CoglAtlasTexture *atlas_tex)
cogl_handle_unref (atlas_tex->sub_texture); cogl_handle_unref (atlas_tex->sub_texture);
g_free (atlas_tex); /* Chain up */
_cogl_texture_free (COGL_TEXTURE (atlas_tex));
} }
static int static int
@ -1074,5 +1077,6 @@ cogl_atlas_texture_vtable =
_cogl_atlas_texture_get_format, _cogl_atlas_texture_get_format,
_cogl_atlas_texture_get_gl_format, _cogl_atlas_texture_get_gl_format,
_cogl_atlas_texture_get_width, _cogl_atlas_texture_get_width,
_cogl_atlas_texture_get_height _cogl_atlas_texture_get_height,
NULL /* is_foreign */
}; };

View File

@ -70,6 +70,26 @@ typedef struct _CoglTextureUnit
* with a layer may represent more than one GL texture) */ * with a layer may represent more than one GL texture) */
GLuint gl_texture; GLuint gl_texture;
/* Foreign textures are those not created or deleted by Cogl. If we ever
* call glBindTexture for a foreign texture then the next time we are
* asked to glBindTexture we can't try and optimize a redundant state
* change because we don't know if the original texture name was deleted
* and now we are being asked to bind a recycled name. */
gboolean is_foreign;
/* We have many components in Cogl that need to temporarily bind arbitrary
* textures e.g. to query texture object parameters and since we don't
* want that to result in too much redundant reflushing of layer state
* when all that's needed is to re-bind the layers gl_texture we use this
* to track when the .layer_gl_texture state is invalid.
*
* XXX: as a further optimization cogl-material.c uses a convention
* of always leaving texture unit 1 active when not dealing with the
* flushing of layer state, so we can assume this is only ever TRUE
* for unit 1.
*/
gboolean dirty_gl_texture;
/* A matrix stack giving us the means to associate a texture /* A matrix stack giving us the means to associate a texture
* transform matrix with the texture unit. */ * transform matrix with the texture unit. */
CoglMatrixStack *matrix_stack; CoglMatrixStack *matrix_stack;
@ -123,6 +143,11 @@ _cogl_get_texture_unit (int index_);
void void
_cogl_destroy_texture_units (void); _cogl_destroy_texture_units (void);
void
_cogl_bind_gl_texture_transient (GLenum gl_target,
GLuint gl_texture,
gboolean is_foreign);
typedef enum _CoglMaterialEqualFlags typedef enum _CoglMaterialEqualFlags
{ {
/* Return FALSE if any component of either material isn't set to its /* Return FALSE if any component of either material isn't set to its
@ -440,6 +465,9 @@ void
_cogl_material_set_user_program (CoglHandle handle, _cogl_material_set_user_program (CoglHandle handle,
CoglHandle program); CoglHandle program);
void
_cogl_delete_gl_texture (GLuint gl_texture);
void void
_cogl_material_apply_legacy_state (CoglHandle handle); _cogl_material_apply_legacy_state (CoglHandle handle);

View File

@ -962,6 +962,8 @@ texture_unit_init (CoglTextureUnit *unit, int index_)
unit->enabled = FALSE; unit->enabled = FALSE;
unit->enabled_gl_target = 0; unit->enabled_gl_target = 0;
unit->gl_texture = 0; unit->gl_texture = 0;
unit->is_foreign = FALSE;
unit->dirty_gl_texture = FALSE;
unit->matrix_stack = _cogl_matrix_stack_new (); unit->matrix_stack = _cogl_matrix_stack_new ();
unit->layer = NULL; unit->layer = NULL;
@ -1027,6 +1029,71 @@ set_active_texture_unit (int unit_index)
} }
} }
/* Note: this conceptually has slightly different semantics to
* OpenGL's glBindTexture because Cogl never cares about tracking
* multiple textures bound to different targets on the same texture
* unit.
*
* glBindTexture lets you bind multiple textures to a single texture
* unit if they are bound to different targets. So it does something
* like:
* unit->current_texture[target] = texture;
*
* Cogl only lets you associate one texture with the currently active
* texture unit, so the target is basically a redundant parameter
* that's implicitly set on that texture.
*
* Technically this is just a thin wrapper around glBindTexture so
* actually it does have the GL semantics but it seems worth
* mentioning the conceptual difference in case anyone wonders why we
* don't associate the gl_texture with a gl_target in the
* CoglTextureUnit.
*/
void
_cogl_bind_gl_texture_transient (GLenum gl_target,
GLuint gl_texture,
gboolean is_foreign)
{
CoglTextureUnit *unit;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
unit = _cogl_get_texture_unit (ctx->active_texture_unit);
/* NB: If we have previously bound a foreign texture to this texture
* unit we don't know if that texture has since been deleted and we
* are seeing the texture name recycled */
if (unit->gl_texture == gl_texture &&
!unit->dirty_gl_texture &&
!unit->is_foreign)
return;
GE (glBindTexture (gl_target, gl_texture));
unit->dirty_gl_texture = TRUE;
unit->is_foreign = is_foreign;
}
void
_cogl_delete_gl_texture (GLuint gl_texture)
{
int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
for (i = 0; i < ctx->texture_units->len; i++)
{
CoglTextureUnit *unit =
&g_array_index (ctx->texture_units, CoglTextureUnit, i);
if (unit->gl_texture == gl_texture)
{
unit->gl_texture = 0;
unit->dirty_gl_texture = FALSE;
}
}
}
/* Asserts that a layer corresponding to the given index exists. If no /* Asserts that a layer corresponding to the given index exists. If no
* match is found, then a new empty layer is added. * match is found, then a new empty layer is added.
*/ */
@ -2926,14 +2993,42 @@ _cogl_material_flush_common_gl_state (CoglMaterial *material,
unit->layer0_overridden = layer0_override_texture ? TRUE : FALSE; unit->layer0_overridden = layer0_override_texture ? TRUE : FALSE;
unit->fallback = fallback; unit->fallback = fallback;
/* FIXME: We could be more clever here and only bind the texture /* NB: There are several Cogl components and some code in
if it is different from gl_layer_info->gl_texture to avoid * Clutter that will temporarily bind arbitrary GL textures to
redundant GL calls. However a few other places in Cogl and * query and modify texture object parameters. If you look at
Clutter call glBindTexture such as ClutterGLXTexturePixmap so * the end of _cogl_material_flush_gl_state() you can see we
we'd need to ensure they affect the cache. Also deleting a * make sure that such code always binds to texture unit 1 by
texture should clear it from the cache in case a new texture * always leaving texture unit 1 active. This means we can't
is generated with the same number */ * rely on the unit->gl_texture state if unit->index == 1.
* Because texture unit 1 is a bit special we actually defer any
* necessary glBindTexture for it until the end of
* _cogl_material_flush_gl_state().
*
* NB: we get notified whenever glDeleteTextures is used (see
* _cogl_delete_gl_texture()) where we invalidate
* unit->gl_texture references to deleted textures so it's safe
* to compare unit->gl_texture with gl_texture. (Without the
* hook it would be possible to delete a GL texture and create a
* new one with the same name and comparing unit->gl_texture and
* gl_texture wouldn't detect that.)
*
* NB: for foreign textures we don't know how the deletion of
* the GL texture objects correspond to the deletion of the
* CoglTextures so if there was previously a foreign texture
* associated with the texture unit then we can't assume that we
* aren't seeing a recycled texture name so we have to bind.
*/
#ifndef DISABLE_MATERIAL_CACHE
if (unit->gl_texture != gl_texture || unit->is_foreign)
{
if (unit->index != 1)
GE (glBindTexture (gl_target, gl_texture));
unit->gl_texture = gl_texture;
}
#else
GE (glBindTexture (gl_target, gl_texture)); GE (glBindTexture (gl_target, gl_texture));
#endif
unit->is_foreign = _cogl_texture_is_foreign (texture);
/* Disable the previous target if it was different and it's /* Disable the previous target if it was different and it's
* still enabled */ * still enabled */
@ -3275,10 +3370,11 @@ done: /* well, almost... */
* unless multitexturing is being used. * unless multitexturing is being used.
*/ */
unit1 = _cogl_get_texture_unit (1); unit1 = _cogl_get_texture_unit (1);
if (unit1->enabled) if (unit1->enabled && unit1->dirty_gl_texture)
{ {
set_active_texture_unit (1); set_active_texture_unit (1);
GE (glBindTexture (unit1->enabled_gl_target, unit1->gl_texture)); GE (glBindTexture (unit1->enabled_gl_target, unit1->gl_texture));
unit1->dirty_gl_texture = FALSE;
} }
/* Since there are several places where Cogl will temporarily bind a /* Since there are several places where Cogl will temporarily bind a

View File

@ -243,7 +243,8 @@ _cogl_sub_texture_free (CoglSubTexture *sub_tex)
cogl_handle_unref (sub_tex->next_texture); cogl_handle_unref (sub_tex->next_texture);
cogl_handle_unref (sub_tex->full_texture); cogl_handle_unref (sub_tex->full_texture);
g_free (sub_tex); /* Chain up */
_cogl_texture_free (COGL_TEXTURE (sub_tex));
} }
CoglHandle CoglHandle
@ -556,5 +557,6 @@ cogl_sub_texture_vtable =
_cogl_sub_texture_get_format, _cogl_sub_texture_get_format,
_cogl_sub_texture_get_gl_format, _cogl_sub_texture_get_gl_format,
_cogl_sub_texture_get_width, _cogl_sub_texture_get_width,
_cogl_sub_texture_get_height _cogl_sub_texture_get_height,
NULL /* is_foreign */
}; };

View File

@ -42,6 +42,7 @@
#include "cogl-handle.h" #include "cogl-handle.h"
#include "cogl-spans.h" #include "cogl-spans.h"
#include "cogl-journal-private.h" #include "cogl-journal-private.h"
#include "cogl-material-private.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -253,6 +254,7 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
_cogl_texture_driver_upload_subregion_to_gl ( _cogl_texture_driver_upload_subregion_to_gl (
tex_2ds->gl_target, tex_2ds->gl_target,
gl_handle, gl_handle,
tex_2ds->is_foreign,
x_span->start, /* src x */ x_span->start, /* src x */
y_span->start, /* src y */ y_span->start, /* src y */
0, /* dst x */ 0, /* dst x */
@ -441,6 +443,7 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
_cogl_texture_driver_upload_subregion_to_gl (tex_2ds->gl_target, _cogl_texture_driver_upload_subregion_to_gl (tex_2ds->gl_target,
gl_handle, gl_handle,
tex_2ds->is_foreign,
source_x, source_x,
source_y, source_y,
local_x, /* dst x */ local_x, /* dst x */
@ -680,7 +683,9 @@ _cogl_texture_2d_sliced_set_wrap_mode_parameters (CoglTexture *tex,
{ {
GLuint texnum = g_array_index (tex_2ds->slice_gl_handles, GLuint, i); GLuint texnum = g_array_index (tex_2ds->slice_gl_handles, GLuint, i);
GE( glBindTexture (tex_2ds->gl_target, texnum) ); _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
texnum,
tex_2ds->is_foreign);
GE( glTexParameteri (tex_2ds->gl_target, GE( glTexParameteri (tex_2ds->gl_target,
GL_TEXTURE_WRAP_S, wrap_mode_s) ); GL_TEXTURE_WRAP_S, wrap_mode_s) );
GE( glTexParameteri (tex_2ds->gl_target, GE( glTexParameteri (tex_2ds->gl_target,
@ -855,8 +860,9 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
y_span->size - y_span->waste); y_span->size - y_span->waste);
/* Setup texture parameters */ /* Setup texture parameters */
GE( glBindTexture (tex_2ds->gl_target, _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
gl_handles[y * n_x_slices + x] ) ); gl_handles[y * n_x_slices + x],
FALSE);
_cogl_texture_driver_try_setting_gl_border_color (tex_2ds->gl_target, _cogl_texture_driver_try_setting_gl_border_color (tex_2ds->gl_target,
transparent_color); transparent_color);
@ -882,11 +888,14 @@ _cogl_texture_2d_sliced_slices_free (CoglTexture2DSliced *tex_2ds)
if (tex_2ds->slice_gl_handles != NULL) if (tex_2ds->slice_gl_handles != NULL)
{ {
int i;
if (tex_2ds->is_foreign == FALSE) if (tex_2ds->is_foreign == FALSE)
{ for (i = 0; i < tex_2ds->slice_gl_handles->len; i++)
GE( glDeleteTextures (tex_2ds->slice_gl_handles->len, {
(GLuint*) tex_2ds->slice_gl_handles->data) ); GLuint texture =
} g_array_index (tex_2ds->slice_gl_handles, GLuint, i);
_cogl_delete_gl_texture (texture);
}
g_array_free (tex_2ds->slice_gl_handles, TRUE); g_array_free (tex_2ds->slice_gl_handles, TRUE);
} }
@ -899,7 +908,9 @@ static void
_cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds) _cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds)
{ {
_cogl_texture_2d_sliced_slices_free (tex_2ds); _cogl_texture_2d_sliced_slices_free (tex_2ds);
g_free (tex_2ds);
/* Chain up */
_cogl_texture_free (COGL_TEXTURE (tex_2ds));
} }
static gboolean static gboolean
@ -1121,7 +1132,8 @@ _cogl_texture_2d_sliced_new_from_foreign (GLuint gl_handle,
/* Make sure binding succeeds */ /* Make sure binding succeeds */
while ((gl_error = glGetError ()) != GL_NO_ERROR) while ((gl_error = glGetError ()) != GL_NO_ERROR)
; ;
glBindTexture (gl_target, gl_handle);
_cogl_bind_gl_texture_transient (gl_target, gl_handle, TRUE);
if (glGetError () != GL_NO_ERROR) if (glGetError () != GL_NO_ERROR)
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
@ -1226,6 +1238,12 @@ _cogl_texture_2d_sliced_new_from_foreign (GLuint gl_handle,
return _cogl_texture_2d_sliced_handle_new (tex_2ds); return _cogl_texture_2d_sliced_handle_new (tex_2ds);
} }
static gboolean
_cogl_texture_2d_sliced_is_foreign (CoglTexture *tex)
{
return COGL_TEXTURE_2D_SLICED (tex)->is_foreign;
}
static int static int
_cogl_texture_2d_sliced_get_max_waste (CoglTexture *tex) _cogl_texture_2d_sliced_get_max_waste (CoglTexture *tex)
{ {
@ -1371,7 +1389,9 @@ _cogl_texture_2d_sliced_set_filters (CoglTexture *tex,
for (i=0; i<tex_2ds->slice_gl_handles->len; ++i) for (i=0; i<tex_2ds->slice_gl_handles->len; ++i)
{ {
gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint, i); gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint, i);
GE( glBindTexture (tex_2ds->gl_target, gl_handle) ); _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
gl_handle,
tex_2ds->is_foreign);
GE( glTexParameteri (tex_2ds->gl_target, GL_TEXTURE_MAG_FILTER, GE( glTexParameteri (tex_2ds->gl_target, GL_TEXTURE_MAG_FILTER,
tex_2ds->mag_filter) ); tex_2ds->mag_filter) );
GE( glTexParameteri (tex_2ds->gl_target, GL_TEXTURE_MIN_FILTER, GE( glTexParameteri (tex_2ds->gl_target, GL_TEXTURE_MIN_FILTER,
@ -1399,7 +1419,9 @@ _cogl_texture_2d_sliced_ensure_mipmaps (CoglTexture *tex)
for (i = 0; i < tex_2ds->slice_gl_handles->len; i++) for (i = 0; i < tex_2ds->slice_gl_handles->len; i++)
{ {
GLuint gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint, i); GLuint gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint, i);
GE( glBindTexture (tex_2ds->gl_target, gl_handle) ); _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
gl_handle,
tex_2ds->is_foreign);
/* glGenerateMipmap is defined in the FBO extension */ /* glGenerateMipmap is defined in the FBO extension */
if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
@ -1544,7 +1566,9 @@ _cogl_texture_2d_sliced_download_from_gl (
bpp); bpp);
/* Download slice image data into temp bmp */ /* Download slice image data into temp bmp */
GE( glBindTexture (tex_2ds->gl_target, gl_handle) ); _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
gl_handle,
tex_2ds->is_foreign);
if (!_cogl_texture_driver_gl_get_tex_image (tex_2ds->gl_target, if (!_cogl_texture_driver_gl_get_tex_image (tex_2ds->gl_target,
target_gl_format, target_gl_format,
@ -1578,7 +1602,9 @@ _cogl_texture_2d_sliced_download_from_gl (
bpp); bpp);
/* Download slice image data */ /* Download slice image data */
GE( glBindTexture (tex_2ds->gl_target, gl_handle) ); _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
gl_handle,
tex_2ds->is_foreign);
if (!_cogl_texture_driver_gl_get_tex_image (tex_2ds->gl_target, if (!_cogl_texture_driver_gl_get_tex_image (tex_2ds->gl_target,
target_gl_format, target_gl_format,
@ -1737,5 +1763,6 @@ cogl_texture_2d_sliced_vtable =
_cogl_texture_2d_sliced_get_format, _cogl_texture_2d_sliced_get_format,
_cogl_texture_2d_sliced_get_gl_format, _cogl_texture_2d_sliced_get_gl_format,
_cogl_texture_2d_sliced_get_width, _cogl_texture_2d_sliced_get_width,
_cogl_texture_2d_sliced_get_height _cogl_texture_2d_sliced_get_height,
_cogl_texture_2d_sliced_is_foreign
}; };

View File

@ -37,6 +37,7 @@
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-handle.h" #include "cogl-handle.h"
#include "cogl-journal-private.h" #include "cogl-journal-private.h"
#include "cogl-material-private.h"
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
@ -137,7 +138,9 @@ _cogl_texture_2d_set_wrap_mode_parameters (CoglTexture *tex,
if (tex_2d->wrap_mode_s != wrap_mode_s || if (tex_2d->wrap_mode_s != wrap_mode_s ||
tex_2d->wrap_mode_t != wrap_mode_t) tex_2d->wrap_mode_t != wrap_mode_t)
{ {
GE( glBindTexture (GL_TEXTURE_2D, tex_2d->gl_texture) ); _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
tex_2d->gl_texture,
FALSE);
GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode_s) ); GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode_s) );
GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode_t) ); GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode_t) );
@ -149,8 +152,10 @@ _cogl_texture_2d_set_wrap_mode_parameters (CoglTexture *tex,
static void static void
_cogl_texture_2d_free (CoglTexture2D *tex_2d) _cogl_texture_2d_free (CoglTexture2D *tex_2d)
{ {
GE( glDeleteTextures (1, &tex_2d->gl_texture) ); _cogl_delete_gl_texture (tex_2d->gl_texture);
g_free (tex_2d);
/* Chain up */
_cogl_texture_free (COGL_TEXTURE (tex_2d));
} }
static gboolean static gboolean
@ -253,7 +258,9 @@ _cogl_texture_2d_new_with_size (unsigned int width,
tex_2d = _cogl_texture_2d_create_base (width, height, flags, internal_format); tex_2d = _cogl_texture_2d_create_base (width, height, flags, internal_format);
_cogl_texture_driver_gen (GL_TEXTURE_2D, 1, &tex_2d->gl_texture); _cogl_texture_driver_gen (GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
GE( glBindTexture (GL_TEXTURE_2D, tex_2d->gl_texture) ); _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
tex_2d->gl_texture,
FALSE);
GE( glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat, GE( glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat,
width, height, 0, gl_format, gl_type, NULL) ); width, height, 0, gl_format, gl_type, NULL) );
@ -299,6 +306,7 @@ _cogl_texture_2d_new_from_bitmap (CoglHandle bmp_handle,
_cogl_texture_driver_gen (GL_TEXTURE_2D, 1, &tex_2d->gl_texture); _cogl_texture_driver_gen (GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
_cogl_texture_driver_upload_to_gl (GL_TEXTURE_2D, _cogl_texture_driver_upload_to_gl (GL_TEXTURE_2D,
tex_2d->gl_texture, tex_2d->gl_texture,
FALSE,
&dst_bmp, &dst_bmp,
gl_intformat, gl_intformat,
gl_format, gl_format,
@ -389,7 +397,9 @@ _cogl_texture_2d_set_filters (CoglTexture *tex,
tex_2d->mag_filter = mag_filter; tex_2d->mag_filter = mag_filter;
/* Apply new filters to the texture */ /* Apply new filters to the texture */
GE( glBindTexture (GL_TEXTURE_2D, tex_2d->gl_texture) ); _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
tex_2d->gl_texture,
FALSE);
GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter) ); GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter) );
GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter) ); GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter) );
} }
@ -405,7 +415,9 @@ _cogl_texture_2d_ensure_mipmaps (CoglTexture *tex)
if (!tex_2d->auto_mipmap || !tex_2d->mipmaps_dirty) if (!tex_2d->auto_mipmap || !tex_2d->mipmaps_dirty)
return; return;
GE( glBindTexture (GL_TEXTURE_2D, tex_2d->gl_texture) ); _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
tex_2d->gl_texture,
FALSE);
/* glGenerateMipmap is defined in the FBO extension. We only allow /* glGenerateMipmap is defined in the FBO extension. We only allow
CoglTexture2D instances to be created if this feature is CoglTexture2D instances to be created if this feature is
available so we don't need to check for the extension */ available so we don't need to check for the extension */
@ -474,6 +486,7 @@ _cogl_texture_2d_set_region (CoglTexture *tex,
/* Send data to GL */ /* Send data to GL */
_cogl_texture_driver_upload_subregion_to_gl (GL_TEXTURE_2D, _cogl_texture_driver_upload_subregion_to_gl (GL_TEXTURE_2D,
tex_2d->gl_texture, tex_2d->gl_texture,
FALSE,
src_x, src_y, src_x, src_y,
dst_x, dst_y, dst_x, dst_y,
dst_width, dst_height, dst_width, dst_height,
@ -552,7 +565,9 @@ _cogl_texture_2d_get_data (CoglTexture *tex,
_cogl_texture_driver_prep_gl_for_pixels_download (target_bmp.rowstride, _cogl_texture_driver_prep_gl_for_pixels_download (target_bmp.rowstride,
closest_bpp); closest_bpp);
GE( glBindTexture (GL_TEXTURE_2D, tex_2d->gl_texture) ); _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
tex_2d->gl_texture,
FALSE);
if (!_cogl_texture_driver_gl_get_tex_image (GL_TEXTURE_2D, if (!_cogl_texture_driver_gl_get_tex_image (GL_TEXTURE_2D,
closest_gl_format, closest_gl_format,
closest_gl_type, closest_gl_type,
@ -638,5 +653,6 @@ cogl_texture_2d_vtable =
_cogl_texture_2d_get_format, _cogl_texture_2d_get_format,
_cogl_texture_2d_get_gl_format, _cogl_texture_2d_get_gl_format,
_cogl_texture_2d_get_width, _cogl_texture_2d_get_width,
_cogl_texture_2d_get_height _cogl_texture_2d_get_height,
NULL /* is_foreign */
}; };

View File

@ -61,6 +61,7 @@ _cogl_texture_driver_prep_gl_for_pixels_upload (int pixels_rowstride,
void void
_cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target, _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
gboolean is_foreign,
int src_x, int src_x,
int src_y, int src_y,
int dst_x, int dst_x,
@ -80,6 +81,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target,
void void
_cogl_texture_driver_upload_to_gl (GLenum gl_target, _cogl_texture_driver_upload_to_gl (GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
gboolean is_foreign,
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLint internal_gl_format, GLint internal_gl_format,
GLuint source_gl_format, GLuint source_gl_format,

View File

@ -118,6 +118,8 @@ struct _CoglTextureVtable
GLenum (* get_gl_format) (CoglTexture *tex); GLenum (* get_gl_format) (CoglTexture *tex);
int (* get_width) (CoglTexture *tex); int (* get_width) (CoglTexture *tex);
int (* get_height) (CoglTexture *tex); int (* get_height) (CoglTexture *tex);
gboolean (* is_foreign) (CoglTexture *tex);
}; };
struct _CoglTexture struct _CoglTexture
@ -126,6 +128,20 @@ struct _CoglTexture
const CoglTextureVtable *vtable; const CoglTextureVtable *vtable;
}; };
typedef enum _CoglTextureChangeFlags
{
/* Whenever the internals of a texture are changed such that the
* underlying GL textures that represent the CoglTexture change then
* we notify cogl-material.c via
* _cogl_material_texture_pre_change_notify
*/
COGL_TEXTURE_CHANGE_GL_TEXTURES
} CoglTextureChangeFlags;
void
_cogl_texture_free (CoglTexture *texture);
void void
_cogl_texture_foreach_sub_texture_in_region (CoglHandle handle, _cogl_texture_foreach_sub_texture_in_region (CoglHandle handle,
float virtual_tx_1, float virtual_tx_1,
@ -215,4 +231,7 @@ _cogl_texture_draw_and_read (CoglHandle handle,
GLuint target_gl_format, GLuint target_gl_format,
GLuint target_gl_type); GLuint target_gl_type);
gboolean
_cogl_texture_is_foreign (CoglHandle handle);
#endif /* __COGL_TEXTURE_PRIVATE_H */ #endif /* __COGL_TEXTURE_PRIVATE_H */

View File

@ -102,6 +102,12 @@ cogl_texture_unref (CoglHandle handle)
cogl_handle_unref (handle); cogl_handle_unref (handle);
} }
void
_cogl_texture_free (CoglTexture *texture)
{
g_free (texture);
}
static gboolean static gboolean
_cogl_texture_needs_premult_conversion (CoglPixelFormat src_format, _cogl_texture_needs_premult_conversion (CoglPixelFormat src_format,
CoglPixelFormat dst_format) CoglPixelFormat dst_format)
@ -471,6 +477,8 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
GLuint y_pot_waste, GLuint y_pot_waste,
CoglPixelFormat format) CoglPixelFormat format)
{ {
/* FIXME: only create a sliced texture if x or y waste was specified
*/
return _cogl_texture_2d_sliced_new_from_foreign (gl_handle, return _cogl_texture_2d_sliced_new_from_foreign (gl_handle,
gl_target, gl_target,
width, width,
@ -480,6 +488,21 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
format); format);
} }
gboolean
_cogl_texture_is_foreign (CoglHandle handle)
{
CoglTexture *tex;
g_return_val_if_fail (cogl_is_texture (handle), FALSE);
tex = COGL_TEXTURE (handle);
if (tex->vtable->is_foreign)
return tex->vtable->is_foreign (tex);
else
return FALSE;
}
CoglHandle CoglHandle
cogl_texture_new_from_sub_texture (CoglHandle full_texture, cogl_texture_new_from_sub_texture (CoglHandle full_texture,
int sub_x, int sub_x,

View File

@ -40,6 +40,7 @@
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-handle.h" #include "cogl-handle.h"
#include "cogl-primitives.h" #include "cogl-primitives.h"
#include "cogl-material-private.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -58,7 +59,9 @@ _cogl_texture_driver_gen (GLenum gl_target,
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
{ {
GE (glBindTexture (gl_target, textures[i])); _cogl_bind_gl_texture_transient (gl_target,
textures[i],
FALSE);
switch (gl_target) switch (gl_target)
{ {
@ -123,6 +126,7 @@ _cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride,
void void
_cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target, _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
gboolean is_foreign,
int src_x, int src_x,
int src_y, int src_y,
int dst_x, int dst_x,
@ -141,7 +145,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target,
src_y, src_y,
bpp); bpp);
GE( glBindTexture (gl_target, gl_handle) ); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
GE( glTexSubImage2D (gl_target, 0, GE( glTexSubImage2D (gl_target, 0,
dst_x, dst_y, dst_x, dst_y,
@ -154,6 +158,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target,
void void
_cogl_texture_driver_upload_to_gl (GLenum gl_target, _cogl_texture_driver_upload_to_gl (GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
gboolean is_foreign,
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLint internal_gl_format, GLint internal_gl_format,
GLuint source_gl_format, GLuint source_gl_format,
@ -164,7 +169,7 @@ _cogl_texture_driver_upload_to_gl (GLenum gl_target,
/* Setup gl alignment to match rowstride and top-left corner */ /* Setup gl alignment to match rowstride and top-left corner */
prep_gl_for_pixels_upload_full (source_bmp->rowstride, 0, 0, bpp); prep_gl_for_pixels_upload_full (source_bmp->rowstride, 0, 0, bpp);
GE( glBindTexture (gl_target, gl_handle) ); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
GE( glTexImage2D (gl_target, 0, GE( glTexImage2D (gl_target, 0,
internal_gl_format, internal_gl_format,

View File

@ -37,6 +37,7 @@
#include "cogl-bitmap-private.h" #include "cogl-bitmap-private.h"
#include "cogl-texture-private.h" #include "cogl-texture-private.h"
#include "cogl-material.h" #include "cogl-material.h"
#include "cogl-material-private.h"
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-handle.h" #include "cogl-handle.h"
#include "cogl-primitives.h" #include "cogl-primitives.h"
@ -58,7 +59,7 @@ _cogl_texture_driver_gen (GLenum gl_target,
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
{ {
GE (glBindTexture (gl_target, textures[i])); _cogl_bind_gl_texture_transient (gl_target, textures[i], FALSE);
switch (gl_target) switch (gl_target)
{ {
@ -91,6 +92,7 @@ _cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride,
void void
_cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target, _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
gboolean is_foreign,
int src_x, int src_x,
int src_y, int src_y,
int dst_x, int dst_x,
@ -131,7 +133,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target,
slice_bmp.width, slice_bmp.width,
slice_bmp.height); slice_bmp.height);
GE( glBindTexture (gl_target, gl_handle) ); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
GE( glTexSubImage2D (gl_target, 0, GE( glTexSubImage2D (gl_target, 0,
dst_x, dst_y, dst_x, dst_y,
@ -147,6 +149,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target,
void void
_cogl_texture_driver_upload_to_gl (GLenum gl_target, _cogl_texture_driver_upload_to_gl (GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
gboolean is_foreign,
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLint internal_gl_format, GLint internal_gl_format,
GLuint source_gl_format, GLuint source_gl_format,
@ -175,7 +178,7 @@ _cogl_texture_driver_upload_to_gl (GLenum gl_target,
_cogl_texture_driver_prep_gl_for_pixels_upload (bmp.rowstride, _cogl_texture_driver_prep_gl_for_pixels_upload (bmp.rowstride,
bpp); bpp);
GE( glBindTexture (gl_target, gl_handle) ); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
GE( glTexImage2D (gl_target, 0, GE( glTexImage2D (gl_target, 0,
internal_gl_format, internal_gl_format,