diff --git a/cogl-material.h b/cogl-material.h index 504c173fa..66fbd8d5c 100644 --- a/cogl-material.h +++ b/cogl-material.h @@ -43,6 +43,52 @@ G_BEGIN_DECLS * blended together. */ +/** + * CoglMaterialFilter: + * @COGL_MATERIAL_FILTER_NEAREST: Measuring in manhatten distance from the, + * current pixel center, use the nearest texture + * texel. + * @COGL_MATERIAL_FILTER_LINEAR: Use the weighted average of the 4 texels + * nearest the current pixel center. + * @COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose + * texel size most closely matches + * the current pixel, and use the + * COGL_MATERIAL_FILTER_NEAREST + * criterion. + * @COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose + * texel size most closely matches + * the current pixel, and use the + * COGL_MATERIAL_FILTER_LINEAR + * criterion. + * @COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels + * whose texel size most closely + * matches the current pixel, use + * the COGL_MATERIAL_FILTER_NEAREST + * criterion on each one and take + * their weighted average. + * @COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels + * whose texel size most closely + * matches the current pixel, use + * the COGL_MATERIAL_FILTER_LINEAR + * criterion on each one and take + * their weighted average. + * + * Texture filtering is used whenever the current pixel maps either to more + * than one texture element (texel) or less than one. These filter enums + * correspond to different strategies used to come up with a pixel color, by + * possibly referring to multiple neighbouring texels and taking a weighted + * average or simply using the nearest texel. + */ +typedef enum _CoglMaterialFilter +{ + COGL_MATERIAL_FILTER_NEAREST = GL_NEAREST, + COGL_MATERIAL_FILTER_LINEAR = GL_LINEAR, + COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST, + COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST = GL_LINEAR_MIPMAP_NEAREST, + COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR = GL_NEAREST_MIPMAP_LINEAR, + COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR +} CoglMaterialFilter; + /** * cogl_material_new: * @@ -660,6 +706,40 @@ CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle); */ CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle); +/** + * cogl_material_layer_get_min_filter: + * @layer_handle: a #CoglHandle for a material layer. + * + * Query the currently set downscaling filter for a cogl material layer. + * + * Returns: the current downscaling filter for a cogl material layer. + */ +CoglMaterialFilter cogl_material_layer_get_min_filter (CoglHandle layer_handle); + +/** + * cogl_material_layer_get_mag_filter: + * @layer_handle: a #CoglHandle for a material layer. + * + * Query the currently set downscaling filter for a cogl material layer. + * + * Returns: the current downscaling filter for a cogl material layer. + */ +CoglMaterialFilter cogl_material_layer_get_mag_filter (CoglHandle layer_handle); + +/** + * cogl_material_set_layer_filters: + * @handle: a #CoglHandle to a material. + * @layer_index: the layer number to change. + * @min_filter: the filter used when scaling a texture down. + * @mag_filter: the filter used when magnifying a texture. + * + * Changes the decimation and interpolation filters used when a texture is + * drawn at other scales than 100%. + */ +void cogl_material_set_layer_filters (CoglHandle handle, + gint layer_index, + CoglMaterialFilter min_filter, + CoglMaterialFilter mag_filter); G_END_DECLS diff --git a/cogl-texture.h b/cogl-texture.h index d4cc4e812..15cadc879 100644 --- a/cogl-texture.h +++ b/cogl-texture.h @@ -218,72 +218,6 @@ guint cogl_texture_get_rowstride (CoglHandle handle); */ gint cogl_texture_get_max_waste (CoglHandle handle); -/** - * CoglTextureFilter: - * @COGL_TEXTURE_FILTER_NEAREST: Measuring in manhatten distance from the, - * current pixel center, use the nearest texture - * texel. - * @COGL_TEXTURE_FILTER_LINEAR: Use the weighted average of the 4 texels - * nearest the current pixel center. - * @COGL_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose - * texel size most closely matches - * the current pixel, and use the - * COGL_TEXTURE_FILTER_NEAREST - * criterion. - * @COGL_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose - * texel size most closely matches - * the current pixel, and use the - * COGL_TEXTURE_FILTER_LINEAR - * criterion. - * @COGL_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels - * whose texel size most closely - * matches the current pixel, use - * the COGL_TEXTURE_FILTER_NEAREST - * criterion on each one and take - * their weighted average. - * @COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels - * whose texel size most closely - * matches the current pixel, use - * the COGL_TEXTURE_FILTER_LINEAR - * criterion on each one and take - * their weighted average. - * - * Texture filtering is used whenever the current pixel maps either to more - * than one texture element (texel) or less than one. These filter enums - * correspond to different strategies used to come up with a pixel color, by - * possibly referring to multiple neighbouring texels and taking a weighted - * average or simply using the nearest texel. - */ -typedef enum _CoglTextureFilter -{ - COGL_TEXTURE_FILTER_NEAREST = GL_NEAREST, - COGL_TEXTURE_FILTER_LINEAR = GL_LINEAR, - COGL_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST, - COGL_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST = GL_LINEAR_MIPMAP_NEAREST, - COGL_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR = GL_NEAREST_MIPMAP_LINEAR, - COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR -} CoglTextureFilter; - -/** - * cogl_texture_get_min_filter: - * @handle: a #CoglHandle for a texture. - * - * Query the currently set downscaling filter for a cogl texture. - * - * Returns: the current downscaling filter for a cogl texture. - */ -CoglTextureFilter cogl_texture_get_min_filter (CoglHandle handle); - -/** - * cogl_texture_get_mag_filter: - * @handle: a #CoglHandle for a texture. - * - * Query the currently set downscaling filter for a cogl texture. - * - * Returns: the current downscaling filter for a cogl texture. - */ -CoglTextureFilter cogl_texture_get_mag_filter (CoglHandle handle); - /** * cogl_texture_is_sliced: * @handle: a #CoglHandle for a texture. @@ -333,20 +267,6 @@ gint cogl_texture_get_data (CoglHandle handle, guint rowstride, guchar *data); -/** - * cogl_texture_set_filters: - * @handle: a #CoglHandle. - * @min_filter: the filter used when scaling the texture down. - * @mag_filter: the filter used when magnifying the texture. - * - * Changes the decimation and interpolation filters used when the texture is - * drawn at other scales than 100%. - */ -void cogl_texture_set_filters (CoglHandle handle, - CoglTextureFilter min_filter, - CoglTextureFilter mag_filter); - - /** * cogl_texture_set_region: * @handle: a #CoglHandle. diff --git a/cogl-types.h b/cogl-types.h index 3aa6f5c3c..0a1360dde 100644 --- a/cogl-types.h +++ b/cogl-types.h @@ -244,8 +244,11 @@ struct _CoglTextureVertex /** * CoglTextureFlags: * @COGL_TEXTURE_NONE: No flags specified - * @COGL_TEXTURE_AUTO_MIPMAP: Enables the automatic generation of the - * mipmap pyramid from the base level image whenever it is updated + * @COGL_TEXTURE_NO_AUTO_MIPMAP: Disables the automatic generation of + * the mipmap pyramid from the base level image whenever it is + * updated. The mipmaps are only generated when the texture is + * rendered with a mipmap filter so it should be free to leave out + * this flag when using other filtering modes. * @COGL_TEXTURE_NO_SLICING: Disables the slicing of the texture * * Flags to pass to the cogl_texture_new_* family of functions. @@ -253,9 +256,9 @@ struct _CoglTextureVertex * Since: 1.0 */ typedef enum { - COGL_TEXTURE_NONE = 0, - COGL_TEXTURE_AUTO_MIPMAP = 1 << 0, - COGL_TEXTURE_NO_SLICING = 1 << 1 + COGL_TEXTURE_NONE = 0, + COGL_TEXTURE_NO_AUTO_MIPMAP = 1 << 0, + COGL_TEXTURE_NO_SLICING = 1 << 1 } CoglTextureFlags; /** diff --git a/common/cogl-material-private.h b/common/cogl-material-private.h index 9b2170ecf..e61ab97bd 100644 --- a/common/cogl-material-private.h +++ b/common/cogl-material-private.h @@ -68,6 +68,9 @@ struct _CoglMaterialLayer CoglHandle texture; /*!< The texture for this layer, or COGL_INVALID_HANDLE for an empty layer */ + CoglMaterialFilter mag_filter; + CoglMaterialFilter min_filter; + /* Determines how the color of individual texture fragments * are calculated. */ GLint texture_combine_rgb_func; diff --git a/common/cogl-material.c b/common/cogl-material.c index f3e7bb417..66a4b0c96 100644 --- a/common/cogl-material.c +++ b/common/cogl-material.c @@ -637,6 +637,8 @@ _cogl_material_get_layer (CoglMaterial *material, layer_handle = _cogl_material_layer_handle_new (layer); layer->index = index_; layer->flags = COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; + layer->mag_filter = COGL_MATERIAL_FILTER_LINEAR; + layer->min_filter = COGL_MATERIAL_FILTER_LINEAR; layer->texture = COGL_INVALID_HANDLE; /* Choose the same default combine mode as OpenGL: @@ -1014,6 +1016,15 @@ get_n_args_for_combine_func (GLint func) return 0; } +static gboolean +is_mipmap_filter (CoglMaterialFilter filter) +{ + return (filter == COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST + || filter == COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST + || filter == COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR + || filter == COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR); +} + static void _cogl_material_layer_flush_gl_sampler_state (CoglMaterialLayer *layer, CoglLayerInfo *gl_layer_info) @@ -1214,6 +1225,13 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material, GE (glActiveTexture (GL_TEXTURE0 + i)); + _cogl_texture_set_filters (layer->texture, + layer->min_filter, + layer->mag_filter); + if (is_mipmap_filter (layer->min_filter) + || is_mipmap_filter (layer->mag_filter)) + _cogl_texture_ensure_mipmaps (layer->texture); + /* 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 @@ -1474,3 +1492,44 @@ cogl_set_source_texture (CoglHandle texture_handle) cogl_set_source (ctx->default_material); } +CoglMaterialFilter +cogl_material_layer_get_min_filter (CoglHandle layer_handle) +{ + CoglMaterialLayer *layer; + + g_return_val_if_fail (cogl_is_material_layer (layer_handle), 0); + + layer = _cogl_material_layer_pointer_from_handle (layer_handle); + + return layer->min_filter; +} + +CoglMaterialFilter +cogl_material_layer_get_mag_filter (CoglHandle layer_handle) +{ + CoglMaterialLayer *layer; + + g_return_val_if_fail (cogl_is_material_layer (layer_handle), 0); + + layer = _cogl_material_layer_pointer_from_handle (layer_handle); + + return layer->mag_filter; +} + +void +cogl_material_set_layer_filters (CoglHandle handle, + gint layer_index, + CoglMaterialFilter min_filter, + CoglMaterialFilter mag_filter) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + layer = _cogl_material_get_layer (material, layer_index, TRUE); + + layer->min_filter = min_filter; + layer->mag_filter = mag_filter; +} diff --git a/common/cogl-primitives.c b/common/cogl-primitives.c index c43fbde49..03fe43180 100644 --- a/common/cogl-primitives.c +++ b/common/cogl-primitives.c @@ -1186,7 +1186,8 @@ cogl_polygon (CoglTextureVertex *vertices, use_sliced_polygon_fallback = TRUE; n_layers = 1; - if (tex->min_filter != GL_NEAREST || tex->mag_filter != GL_NEAREST) + if (cogl_material_layer_get_min_filter (layer) != GL_NEAREST + || cogl_material_layer_get_mag_filter (layer) != GL_NEAREST) { static gboolean warning_seen = FALSE; if (!warning_seen) diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index f596ee042..872e02d11 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -132,12 +132,9 @@ cogl_texture_get_height cogl_texture_get_format cogl_texture_get_rowstride cogl_texture_get_max_waste -cogl_texture_get_min_filter -cogl_texture_get_mag_filter cogl_texture_is_sliced cogl_texture_get_gl_texture cogl_texture_get_data -cogl_texture_set_filters cogl_texture_set_region @@ -366,8 +363,12 @@ cogl_material_set_layer_combine cogl_material_set_layer_combine_constant cogl_material_set_layer_matrix cogl_material_get_layers +CoglMaterialFilter +cogl_material_set_layer_filters cogl_material_layer_get_type cogl_material_layer_get_texture +cogl_material_layer_get_min_filter +cogl_material_layer_get_mag_filter CoglMaterial CoglMaterialFlags diff --git a/gl/cogl-context.h b/gl/cogl-context.h index 3db4c0e9e..d845a6c12 100644 --- a/gl/cogl-context.h +++ b/gl/cogl-context.h @@ -120,6 +120,7 @@ typedef struct COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC pf_glDeleteFramebuffersEXT; COGL_PFNGLBLITFRAMEBUFFEREXTPROC pf_glBlitFramebufferEXT; COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC pf_glRenderbufferStorageMultisampleEXT; + COGL_PFNGLGENERATEMIPMAPEXTPROC pf_glGenerateMipmapEXT; COGL_PFNGLCREATEPROGRAMOBJECTARBPROC pf_glCreateProgramObjectARB; COGL_PFNGLCREATESHADEROBJECTARBPROC pf_glCreateShaderObjectARB; diff --git a/gl/cogl-defines.h.in b/gl/cogl-defines.h.in index 4805ea5b3..025b4cad0 100644 --- a/gl/cogl-defines.h.in +++ b/gl/cogl-defines.h.in @@ -773,6 +773,10 @@ typedef void GLsizei width, GLsizei height); +typedef void + (APIENTRYP COGL_PFNGLGENERATEMIPMAPEXTPROC) + (GLenum target); + typedef GLhandleARB (APIENTRYP COGL_PFNGLCREATEPROGRAMOBJECTARBPROC) (void); diff --git a/gl/cogl-texture-private.h b/gl/cogl-texture-private.h index 7cf6fe951..365a47921 100644 --- a/gl/cogl-texture-private.h +++ b/gl/cogl-texture-private.h @@ -30,6 +30,7 @@ typedef struct _CoglTexture CoglTexture; typedef struct _CoglTexSliceSpan CoglTexSliceSpan; typedef struct _CoglSpanIter CoglSpanIter; +typedef struct _CoglTexturePixel CoglTexturePixel; struct _CoglTexSliceSpan { @@ -55,6 +56,18 @@ struct _CoglSpanIter gboolean intersects; }; +/* This is used to store the first pixel of each slice. This is only + used when glGenerateMipmap is not available */ +struct _CoglTexturePixel +{ + /* We need to store the format of the pixel because we store the + data in the source format which might end up being different for + each slice if a subregion is updated with a different format */ + GLenum gl_format; + GLenum gl_type; + guint8 data[4]; +}; + struct _CoglTexture { CoglHandleObject _parent; @@ -68,11 +81,17 @@ struct _CoglTexture GArray *slice_y_spans; GArray *slice_gl_handles; gint max_waste; - CoglTextureFilter min_filter; - CoglTextureFilter mag_filter; + GLenum min_filter; + GLenum mag_filter; gboolean is_foreign; GLint wrap_mode; gboolean auto_mipmap; + gboolean mipmaps_dirty; + + /* This holds a copy of the first pixel in each slice. It is only + used to force an automatic update of the mipmaps when + glGenerateMipmap is not available. */ + CoglTexturePixel *first_pixels; }; /* To improve batching of geometry when submitting vertices to OpenGL we @@ -93,6 +112,14 @@ void _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, GLenum wrap_mode); +void +_cogl_texture_set_filters (CoglHandle handle, + GLenum min_filter, + GLenum mag_filter); + +void +_cogl_texture_ensure_mipmaps (CoglHandle handle); + gboolean _cogl_texture_span_has_waste (CoglTexture *tex, gint x_span_index, diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index 80e428eba..e2c6c264f 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -49,6 +49,7 @@ #define glDrawRangeElements ctx->pf_glDrawRangeElements #define glActiveTexture ctx->pf_glActiveTexture #define glClientActiveTexture ctx->pf_glClientActiveTexture +#define glGenerateMipmap ctx->pf_glGenerateMipmapEXT #else @@ -247,11 +248,12 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) /* Iterate horizontal slices */ for (x = 0; x < tex->slice_x_spans->len; ++x) { + gint slice_num = y * tex->slice_x_spans->len + x; + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); /* Pick the gl texture object handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, - y * tex->slice_x_spans->len + x); + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); /* Setup gl alignment to match rowstride and top-left corner */ prep_for_gl_pixels_upload (tex->bitmap.rowstride, @@ -259,6 +261,17 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) y_span->start, bpp); + /* Keep a copy of the first pixel if needed */ + if (tex->first_pixels) + { + memcpy (tex->first_pixels[slice_num].data, + tex->bitmap.data + x_span->start * bpp + + y_span->start * tex->bitmap.rowstride, + bpp); + tex->first_pixels[slice_num].gl_format = tex->gl_format; + tex->first_pixels[slice_num].gl_type = tex->gl_type; + } + /* Upload new image data */ GE( glBindTexture (tex->gl_target, gl_handle) ); @@ -343,6 +356,8 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) if (waste_buf) g_free (waste_buf); + tex->mipmaps_dirty = TRUE; + return TRUE; } @@ -494,6 +509,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, _cogl_span_iter_next (&x_iter), source_x += inter_w ) { + gint slice_num; + /* Discard slices out of the subregion early */ if (!x_iter.intersects) { @@ -516,10 +533,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, local_y = (y_iter.intersect_start - y_iter.pos); + slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index; + /* Pick slice GL handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, - y_iter.index * tex->slice_x_spans->len + - x_iter.index); + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); /* Setup gl alignment to match rowstride and top-left corner */ prep_for_gl_pixels_upload (source_bmp->rowstride, @@ -527,6 +544,17 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, source_y, bpp); + /* Keep a copy of the first pixel if needed */ + if (tex->first_pixels && local_x == 0 && local_y == 0) + { + memcpy (tex->first_pixels[slice_num].data, + source_bmp->data + source_x * bpp + + source_y * source_bmp->rowstride, + bpp); + tex->first_pixels[slice_num].gl_format = source_gl_format; + tex->first_pixels[slice_num].gl_type = source_gl_type; + } + /* Upload new image data */ GE( glBindTexture (tex->gl_target, gl_handle) ); @@ -640,6 +668,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, if (waste_buf) g_free (waste_buf); + tex->mipmaps_dirty = TRUE; + return TRUE; } @@ -913,6 +943,14 @@ _cogl_texture_slices_create (CoglTexture *tex) g_array_set_size (tex->slice_gl_handles, n_slices); + /* Allocate some space to store a copy of the first pixel of each + slice. This is only needed to glGenerateMipmap (which is part of + the FBO extension) is not available */ + if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + tex->first_pixels = NULL; + else + tex->first_pixels = g_new (CoglTexturePixel, n_slices); + /* Wrap mode not yet set */ tex->wrap_mode = GL_FALSE; @@ -941,14 +979,6 @@ _cogl_texture_slices_create (CoglTexture *tex) /* Setup texture parameters */ GE( glBindTexture (tex->gl_target, gl_handles[y * n_x_slices + x]) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER, - tex->mag_filter) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER, - tex->min_filter) ); - - if (tex->auto_mipmap) - GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, - GL_TRUE) ); /* Use a transparent border color so that we can leave the color buffer alone when using texture co-ordinates @@ -985,6 +1015,9 @@ _cogl_texture_slices_free (CoglTexture *tex) g_array_free (tex->slice_gl_handles, TRUE); } + + if (tex->first_pixels != NULL) + g_free (tex->first_pixels); } gboolean @@ -1221,7 +1254,8 @@ cogl_texture_new_with_size (guint width, tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap.width = width; tex->bitmap.height = height; @@ -1239,8 +1273,9 @@ cogl_texture_new_with_size (guint width, else tex->max_waste = COGL_TEXTURE_MAX_WASTE; - tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; - tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* Find closest GL format match */ tex->bitmap.format = @@ -1285,7 +1320,8 @@ cogl_texture_new_from_data (guint width, tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap.width = width; tex->bitmap.height = height; @@ -1303,8 +1339,9 @@ cogl_texture_new_from_data (guint width, else tex->max_waste = COGL_TEXTURE_MAX_WASTE; - tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; - tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* FIXME: If upload fails we should set some kind of * error flag but still return texture handle (this @@ -1348,7 +1385,8 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap = *bmp; tex->bitmap_owner = TRUE; @@ -1363,8 +1401,9 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, else tex->max_waste = COGL_TEXTURE_MAX_WASTE; - tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; - tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* FIXME: If upload fails we should set some kind of * error flag but still return texture handle if the @@ -1440,8 +1479,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle, GLint gl_int_format = 0; GLint gl_width = 0; GLint gl_height = 0; - GLint gl_min_filter; - GLint gl_mag_filter; GLint gl_gen_mipmap; guint bpp; CoglTexture *tex; @@ -1489,14 +1526,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle, GL_TEXTURE_HEIGHT, &gl_height) ); - GE( glGetTexParameteriv (gl_target, - GL_TEXTURE_MIN_FILTER, - &gl_min_filter) ); - - GE( glGetTexParameteriv (gl_target, - GL_TEXTURE_MAG_FILTER, - &gl_mag_filter) ); - GE( glGetTexParameteriv (gl_target, GL_GENERATE_MIPMAP, &gl_gen_mipmap) ); @@ -1524,6 +1553,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle, /* Setup bitmap info */ tex->is_foreign = TRUE; tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE; + tex->mipmaps_dirty = TRUE; bpp = _cogl_get_format_bpp (format); tex->bitmap.format = format; @@ -1537,8 +1567,9 @@ cogl_texture_new_from_foreign (GLuint gl_handle, tex->gl_format = gl_int_format; tex->gl_type = GL_UNSIGNED_BYTE; - tex->min_filter = gl_min_filter; - tex->mag_filter = gl_mag_filter; + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; tex->max_waste = 0; /* Wrap mode not yet set */ @@ -1684,36 +1715,10 @@ cogl_texture_get_gl_texture (CoglHandle handle, return TRUE; } -CoglTextureFilter -cogl_texture_get_min_filter (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->min_filter; -} - -CoglTextureFilter -cogl_texture_get_mag_filter (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->mag_filter; -} - void -cogl_texture_set_filters (CoglHandle handle, - CoglTextureFilter min_filter, - CoglTextureFilter mag_filter) +_cogl_texture_set_filters (CoglHandle handle, + GLenum min_filter, + GLenum mag_filter) { CoglTexture *tex; GLuint gl_handle; @@ -1724,14 +1729,18 @@ cogl_texture_set_filters (CoglHandle handle, tex = _cogl_texture_pointer_from_handle (handle); - /* Store new values */ - tex->min_filter = min_filter; - tex->mag_filter = mag_filter; - /* Make sure slices were created */ if (tex->slice_gl_handles == NULL) return; + if (min_filter == tex->min_filter + && mag_filter == tex->mag_filter) + return; + + /* Store new values */ + tex->min_filter = min_filter; + tex->mag_filter = mag_filter; + /* Apply new filters to every slice */ for (i=0; islice_gl_handles->len; ++i) { @@ -1744,6 +1753,52 @@ cogl_texture_set_filters (CoglHandle handle, } } +void +_cogl_texture_ensure_mipmaps (CoglHandle handle) +{ + CoglTexture *tex; + int i; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (!cogl_is_texture (handle)) + return; + + tex = _cogl_texture_pointer_from_handle (handle); + + /* Only update if the mipmaps are dirty */ + if (!tex->auto_mipmap || !tex->mipmaps_dirty) + return; + + /* Make sure slices were created */ + if (tex->slice_gl_handles == NULL) + return; + + /* Regenerate the mipmaps on every slice */ + for (i = 0; i < tex->slice_gl_handles->len; i++) + { + GLuint gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i); + GE( glBindTexture (tex->gl_target, gl_handle) ); + + /* glGenerateMipmap is defined in the FBO extension */ + if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + GE( glGenerateMipmap (tex->gl_target) ); + else + { + CoglTexturePixel *pixel = tex->first_pixels + i; + /* Temporarily enable automatic mipmap generation and + re-upload the first pixel to cause a regeneration */ + GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_TRUE) ); + GE( glTexSubImage2D (tex->gl_target, 0, 0, 0, 1, 1, + pixel->gl_format, pixel->gl_type, + pixel->data) ); + GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_FALSE) ); + } + } + + tex->mipmaps_dirty = FALSE; +} + gboolean cogl_texture_set_region (CoglHandle handle, gint src_x, diff --git a/gl/cogl.c b/gl/cogl.c index 608bc364e..748c082ac 100644 --- a/gl/cogl.c +++ b/gl/cogl.c @@ -399,6 +399,10 @@ _cogl_features_init (void) (COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC) cogl_get_proc_address ("glDeleteFramebuffersEXT"); + ctx->pf_glGenerateMipmapEXT = + (COGL_PFNGLGENERATEMIPMAPEXTPROC) + cogl_get_proc_address ("glGenerateMipmapEXT"); + if (ctx->pf_glGenRenderbuffersEXT && ctx->pf_glBindRenderbufferEXT && ctx->pf_glRenderbufferStorageEXT && @@ -407,7 +411,8 @@ _cogl_features_init (void) ctx->pf_glFramebufferTexture2DEXT && ctx->pf_glFramebufferRenderbufferEXT && ctx->pf_glCheckFramebufferStatusEXT && - ctx->pf_glDeleteFramebuffersEXT) + ctx->pf_glDeleteFramebuffersEXT && + ctx->pf_glGenerateMipmapEXT) flags |= COGL_FEATURE_OFFSCREEN; }