From 82e80e67650ac8ec119f2d909423ab5b707206a7 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Mon, 26 Apr 2010 10:01:43 +0100 Subject: [PATCH] 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. --- cogl/cogl-atlas-texture.c | 10 ++- cogl/cogl-material-private.h | 28 +++++++ cogl/cogl-material.c | 112 +++++++++++++++++++++++-- cogl/cogl-sub-texture.c | 6 +- cogl/cogl-texture-2d-sliced.c | 55 ++++++++---- cogl/cogl-texture-2d.c | 32 +++++-- cogl/cogl-texture-driver.h | 2 + cogl/cogl-texture-private.h | 19 +++++ cogl/cogl-texture.c | 23 +++++ cogl/driver/gl/cogl-texture-driver.c | 11 ++- cogl/driver/gles/cogl-texture-driver.c | 9 +- 11 files changed, 266 insertions(+), 41 deletions(-) diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c index b15a85c86..b414b46f3 100644 --- a/cogl/cogl-atlas-texture.c +++ b/cogl/cogl-atlas-texture.c @@ -146,7 +146,9 @@ _cogl_atlas_texture_blit_begin (CoglAtlasTextureBlitData *data, 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) @@ -274,7 +276,8 @@ _cogl_atlas_texture_free (CoglAtlasTexture *atlas_tex) cogl_handle_unref (atlas_tex->sub_texture); - g_free (atlas_tex); + /* Chain up */ + _cogl_texture_free (COGL_TEXTURE (atlas_tex)); } static int @@ -1074,5 +1077,6 @@ cogl_atlas_texture_vtable = _cogl_atlas_texture_get_format, _cogl_atlas_texture_get_gl_format, _cogl_atlas_texture_get_width, - _cogl_atlas_texture_get_height + _cogl_atlas_texture_get_height, + NULL /* is_foreign */ }; diff --git a/cogl/cogl-material-private.h b/cogl/cogl-material-private.h index ed98393ed..08ea01338 100644 --- a/cogl/cogl-material-private.h +++ b/cogl/cogl-material-private.h @@ -70,6 +70,26 @@ typedef struct _CoglTextureUnit * with a layer may represent more than one 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 * transform matrix with the texture unit. */ CoglMatrixStack *matrix_stack; @@ -123,6 +143,11 @@ _cogl_get_texture_unit (int index_); void _cogl_destroy_texture_units (void); +void +_cogl_bind_gl_texture_transient (GLenum gl_target, + GLuint gl_texture, + gboolean is_foreign); + typedef enum _CoglMaterialEqualFlags { /* 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, CoglHandle program); +void +_cogl_delete_gl_texture (GLuint gl_texture); + void _cogl_material_apply_legacy_state (CoglHandle handle); diff --git a/cogl/cogl-material.c b/cogl/cogl-material.c index fd08dd94f..fce85439f 100644 --- a/cogl/cogl-material.c +++ b/cogl/cogl-material.c @@ -962,6 +962,8 @@ texture_unit_init (CoglTextureUnit *unit, int index_) unit->enabled = FALSE; unit->enabled_gl_target = 0; unit->gl_texture = 0; + unit->is_foreign = FALSE; + unit->dirty_gl_texture = FALSE; unit->matrix_stack = _cogl_matrix_stack_new (); 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 * 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->fallback = fallback; - /* FIXME: We could be more clever here and only bind the texture - if it is different from gl_layer_info->gl_texture to avoid - redundant GL calls. However a few other places in Cogl and - Clutter call glBindTexture such as ClutterGLXTexturePixmap so - we'd need to ensure they affect the cache. Also deleting a - texture should clear it from the cache in case a new texture - is generated with the same number */ + /* NB: There are several Cogl components and some code in + * Clutter that will temporarily bind arbitrary GL textures to + * query and modify texture object parameters. If you look at + * the end of _cogl_material_flush_gl_state() you can see we + * make sure that such code always binds to texture unit 1 by + * always leaving texture unit 1 active. This means we can't + * 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)); +#endif + unit->is_foreign = _cogl_texture_is_foreign (texture); /* Disable the previous target if it was different and it's * still enabled */ @@ -3275,10 +3370,11 @@ done: /* well, almost... */ * unless multitexturing is being used. */ unit1 = _cogl_get_texture_unit (1); - if (unit1->enabled) + if (unit1->enabled && unit1->dirty_gl_texture) { set_active_texture_unit (1); 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 diff --git a/cogl/cogl-sub-texture.c b/cogl/cogl-sub-texture.c index 2af29f546..22a1c8869 100644 --- a/cogl/cogl-sub-texture.c +++ b/cogl/cogl-sub-texture.c @@ -243,7 +243,8 @@ _cogl_sub_texture_free (CoglSubTexture *sub_tex) cogl_handle_unref (sub_tex->next_texture); cogl_handle_unref (sub_tex->full_texture); - g_free (sub_tex); + /* Chain up */ + _cogl_texture_free (COGL_TEXTURE (sub_tex)); } CoglHandle @@ -556,5 +557,6 @@ cogl_sub_texture_vtable = _cogl_sub_texture_get_format, _cogl_sub_texture_get_gl_format, _cogl_sub_texture_get_width, - _cogl_sub_texture_get_height + _cogl_sub_texture_get_height, + NULL /* is_foreign */ }; diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c index c2268dff1..8a5697008 100644 --- a/cogl/cogl-texture-2d-sliced.c +++ b/cogl/cogl-texture-2d-sliced.c @@ -42,6 +42,7 @@ #include "cogl-handle.h" #include "cogl-spans.h" #include "cogl-journal-private.h" +#include "cogl-material-private.h" #include #include @@ -253,6 +254,7 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds, _cogl_texture_driver_upload_subregion_to_gl ( tex_2ds->gl_target, gl_handle, + tex_2ds->is_foreign, x_span->start, /* src x */ y_span->start, /* src y */ 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, gl_handle, + tex_2ds->is_foreign, source_x, source_y, 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); - 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, GL_TEXTURE_WRAP_S, wrap_mode_s) ); 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); /* Setup texture parameters */ - GE( glBindTexture (tex_2ds->gl_target, - gl_handles[y * n_x_slices + x] ) ); + _cogl_bind_gl_texture_transient (tex_2ds->gl_target, + gl_handles[y * n_x_slices + x], + FALSE); _cogl_texture_driver_try_setting_gl_border_color (tex_2ds->gl_target, transparent_color); @@ -882,11 +888,14 @@ _cogl_texture_2d_sliced_slices_free (CoglTexture2DSliced *tex_2ds) if (tex_2ds->slice_gl_handles != NULL) { + int i; if (tex_2ds->is_foreign == FALSE) - { - GE( glDeleteTextures (tex_2ds->slice_gl_handles->len, - (GLuint*) tex_2ds->slice_gl_handles->data) ); - } + for (i = 0; i < tex_2ds->slice_gl_handles->len; i++) + { + 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); } @@ -899,7 +908,9 @@ static void _cogl_texture_2d_sliced_free (CoglTexture2DSliced *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 @@ -1121,7 +1132,8 @@ _cogl_texture_2d_sliced_new_from_foreign (GLuint gl_handle, /* Make sure binding succeeds */ 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) 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); } +static gboolean +_cogl_texture_2d_sliced_is_foreign (CoglTexture *tex) +{ + return COGL_TEXTURE_2D_SLICED (tex)->is_foreign; +} + static int _cogl_texture_2d_sliced_get_max_waste (CoglTexture *tex) { @@ -1371,7 +1389,9 @@ _cogl_texture_2d_sliced_set_filters (CoglTexture *tex, for (i=0; islice_gl_handles->len; ++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, tex_2ds->mag_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++) { 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 */ if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) @@ -1544,7 +1566,9 @@ _cogl_texture_2d_sliced_download_from_gl ( bpp); /* 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, target_gl_format, @@ -1578,7 +1602,9 @@ _cogl_texture_2d_sliced_download_from_gl ( bpp); /* 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, target_gl_format, @@ -1737,5 +1763,6 @@ cogl_texture_2d_sliced_vtable = _cogl_texture_2d_sliced_get_format, _cogl_texture_2d_sliced_get_gl_format, _cogl_texture_2d_sliced_get_width, - _cogl_texture_2d_sliced_get_height + _cogl_texture_2d_sliced_get_height, + _cogl_texture_2d_sliced_is_foreign }; diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c index 793c5cd25..a7bcbf322 100644 --- a/cogl/cogl-texture-2d.c +++ b/cogl/cogl-texture-2d.c @@ -37,6 +37,7 @@ #include "cogl-context.h" #include "cogl-handle.h" #include "cogl-journal-private.h" +#include "cogl-material-private.h" #include #include @@ -137,7 +138,9 @@ _cogl_texture_2d_set_wrap_mode_parameters (CoglTexture *tex, if (tex_2d->wrap_mode_s != wrap_mode_s || 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_T, wrap_mode_t) ); @@ -149,8 +152,10 @@ _cogl_texture_2d_set_wrap_mode_parameters (CoglTexture *tex, static void _cogl_texture_2d_free (CoglTexture2D *tex_2d) { - GE( glDeleteTextures (1, &tex_2d->gl_texture) ); - g_free (tex_2d); + _cogl_delete_gl_texture (tex_2d->gl_texture); + + /* Chain up */ + _cogl_texture_free (COGL_TEXTURE (tex_2d)); } 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); _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, 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_upload_to_gl (GL_TEXTURE_2D, tex_2d->gl_texture, + FALSE, &dst_bmp, gl_intformat, gl_format, @@ -389,7 +397,9 @@ _cogl_texture_2d_set_filters (CoglTexture *tex, tex_2d->mag_filter = mag_filter; /* 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_MIN_FILTER, min_filter) ); } @@ -405,7 +415,9 @@ _cogl_texture_2d_ensure_mipmaps (CoglTexture *tex) if (!tex_2d->auto_mipmap || !tex_2d->mipmaps_dirty) 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 CoglTexture2D instances to be created if this feature is 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 */ _cogl_texture_driver_upload_subregion_to_gl (GL_TEXTURE_2D, tex_2d->gl_texture, + FALSE, src_x, src_y, dst_x, dst_y, 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, 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, closest_gl_format, closest_gl_type, @@ -638,5 +653,6 @@ cogl_texture_2d_vtable = _cogl_texture_2d_get_format, _cogl_texture_2d_get_gl_format, _cogl_texture_2d_get_width, - _cogl_texture_2d_get_height + _cogl_texture_2d_get_height, + NULL /* is_foreign */ }; diff --git a/cogl/cogl-texture-driver.h b/cogl/cogl-texture-driver.h index 1728ee160..725629b2b 100644 --- a/cogl/cogl-texture-driver.h +++ b/cogl/cogl-texture-driver.h @@ -61,6 +61,7 @@ _cogl_texture_driver_prep_gl_for_pixels_upload (int pixels_rowstride, void _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target, GLuint gl_handle, + gboolean is_foreign, int src_x, int src_y, int dst_x, @@ -80,6 +81,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target, void _cogl_texture_driver_upload_to_gl (GLenum gl_target, GLuint gl_handle, + gboolean is_foreign, CoglBitmap *source_bmp, GLint internal_gl_format, GLuint source_gl_format, diff --git a/cogl/cogl-texture-private.h b/cogl/cogl-texture-private.h index 0f97233ed..74ffe033f 100644 --- a/cogl/cogl-texture-private.h +++ b/cogl/cogl-texture-private.h @@ -118,6 +118,8 @@ struct _CoglTextureVtable GLenum (* get_gl_format) (CoglTexture *tex); int (* get_width) (CoglTexture *tex); int (* get_height) (CoglTexture *tex); + + gboolean (* is_foreign) (CoglTexture *tex); }; struct _CoglTexture @@ -126,6 +128,20 @@ struct _CoglTexture 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 _cogl_texture_foreach_sub_texture_in_region (CoglHandle handle, float virtual_tx_1, @@ -215,4 +231,7 @@ _cogl_texture_draw_and_read (CoglHandle handle, GLuint target_gl_format, GLuint target_gl_type); +gboolean +_cogl_texture_is_foreign (CoglHandle handle); + #endif /* __COGL_TEXTURE_PRIVATE_H */ diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index b192a8a40..1dbcbbf4e 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -102,6 +102,12 @@ cogl_texture_unref (CoglHandle handle) cogl_handle_unref (handle); } +void +_cogl_texture_free (CoglTexture *texture) +{ + g_free (texture); +} + static gboolean _cogl_texture_needs_premult_conversion (CoglPixelFormat src_format, CoglPixelFormat dst_format) @@ -471,6 +477,8 @@ cogl_texture_new_from_foreign (GLuint gl_handle, GLuint y_pot_waste, 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, gl_target, width, @@ -480,6 +488,21 @@ cogl_texture_new_from_foreign (GLuint gl_handle, 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 cogl_texture_new_from_sub_texture (CoglHandle full_texture, int sub_x, diff --git a/cogl/driver/gl/cogl-texture-driver.c b/cogl/driver/gl/cogl-texture-driver.c index 01eedc739..272610435 100644 --- a/cogl/driver/gl/cogl-texture-driver.c +++ b/cogl/driver/gl/cogl-texture-driver.c @@ -40,6 +40,7 @@ #include "cogl-context.h" #include "cogl-handle.h" #include "cogl-primitives.h" +#include "cogl-material-private.h" #include #include @@ -58,7 +59,9 @@ _cogl_texture_driver_gen (GLenum gl_target, 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) { @@ -123,6 +126,7 @@ _cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride, void _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target, GLuint gl_handle, + gboolean is_foreign, int src_x, int src_y, int dst_x, @@ -141,7 +145,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target, src_y, bpp); - GE( glBindTexture (gl_target, gl_handle) ); + _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); GE( glTexSubImage2D (gl_target, 0, dst_x, dst_y, @@ -154,6 +158,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target, void _cogl_texture_driver_upload_to_gl (GLenum gl_target, GLuint gl_handle, + gboolean is_foreign, CoglBitmap *source_bmp, GLint internal_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 */ 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, internal_gl_format, diff --git a/cogl/driver/gles/cogl-texture-driver.c b/cogl/driver/gles/cogl-texture-driver.c index ac55c873e..af03ef928 100644 --- a/cogl/driver/gles/cogl-texture-driver.c +++ b/cogl/driver/gles/cogl-texture-driver.c @@ -37,6 +37,7 @@ #include "cogl-bitmap-private.h" #include "cogl-texture-private.h" #include "cogl-material.h" +#include "cogl-material-private.h" #include "cogl-context.h" #include "cogl-handle.h" #include "cogl-primitives.h" @@ -58,7 +59,7 @@ _cogl_texture_driver_gen (GLenum gl_target, 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) { @@ -91,6 +92,7 @@ _cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride, void _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target, GLuint gl_handle, + gboolean is_foreign, int src_x, int src_y, int dst_x, @@ -131,7 +133,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target, slice_bmp.width, 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, dst_x, dst_y, @@ -147,6 +149,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target, void _cogl_texture_driver_upload_to_gl (GLenum gl_target, GLuint gl_handle, + gboolean is_foreign, CoglBitmap *source_bmp, GLint internal_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, bpp); - GE( glBindTexture (gl_target, gl_handle) ); + _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); GE( glTexImage2D (gl_target, 0, internal_gl_format,