summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Roberts <neil@linux.intel.com>2009-06-04 16:04:57 +0100
committerNeil Roberts <neil@linux.intel.com>2009-06-04 19:03:40 +0100
commite7e897802925346fdd3e212c425acbf2017027c2 (patch)
tree3c524ddcb56585e7d8c1e92a5ee218658bc8601d
parentb7c8f8111e86be48eb440358d13e677ccc29cf19 (diff)
downloadcogl-e7e897802925346fdd3e212c425acbf2017027c2.tar.gz
[cogl] Move the texture filters to be a property of the material layer
The texture filters are now a property of the material layer rather than the texture object. Whenever a texture is painted with a material it sets the filters on all of the GL textures in the Cogl texture. The filter is cached so that it won't be changed unnecessarily. The automatic mipmap generation has changed so that the mipmaps are only generated when the texture is painted instead of every time the data changes. Changing the texture sets a flag to mark that the mipmaps are dirty. This works better if the FBO extension is available because we can use glGenerateMipmap. If the extension is not available it will temporarily enable automatic mipmap generation and reupload the first pixel of each slice. This requires tracking the data for the first pixel. The COGL_TEXTURE_AUTO_MIPMAP flag has been replaced with COGL_TEXTURE_NO_AUTO_MIPMAP so that it will default to auto-mipmapping. The mipmap generation is now effectively free if you are not using a mipmap filter mode so you would only want to disable it if you had some special reason to generate your own mipmaps. ClutterTexture no longer has to store its own copy of the filter mode. Instead it stores it in the material and the property is directly set and read from that. This fixes problems with the filters getting out of sync when a cogl handle is set on the texture directly. It also avoids the mess of having to rerealize the texture if the filter quality changes to HIGH because Cogl will take of generating the mipmaps if needed.
-rw-r--r--cogl-material.h80
-rw-r--r--cogl-texture.h80
-rw-r--r--cogl-types.h13
-rw-r--r--common/cogl-material-private.h3
-rw-r--r--common/cogl-material.c59
-rw-r--r--common/cogl-primitives.c3
-rw-r--r--doc/reference/cogl/cogl-sections.txt7
-rw-r--r--gl/cogl-context.h1
-rw-r--r--gl/cogl-defines.h.in4
-rw-r--r--gl/cogl-texture-private.h31
-rw-r--r--gl/cogl-texture.c179
-rw-r--r--gl/cogl.c7
12 files changed, 313 insertions, 154 deletions
diff --git a/cogl-material.h b/cogl-material.h
index 504c173f..66fbd8d5 100644
--- a/cogl-material.h
+++ b/cogl-material.h
@@ -44,6 +44,52 @@ G_BEGIN_DECLS
*/
/**
+ * 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:
*
* Allocates and initializes a blank white material
@@ -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 d4cc4e81..15cadc87 100644
--- a/cogl-texture.h
+++ b/cogl-texture.h
@@ -219,72 +219,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.
*
@@ -334,20 +268,6 @@ gint cogl_texture_get_data (CoglHandle handle,
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.
* @src_x: upper left coordinate to use from source data.
diff --git a/cogl-types.h b/cogl-types.h
index 3aa6f5c3..0a1360dd 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 9b2170ec..e61ab97b 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 f3e7bb41..66a4b0c9 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 c43fbde4..03fe4318 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 f596ee04..872e02d1 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
</SECTION>
@@ -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
<SUBSECTION Private>
CoglMaterial
CoglMaterialFlags
diff --git a/gl/cogl-context.h b/gl/cogl-context.h
index 3db4c0e9..d845a6c1 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 4805ea5b..025b4cad 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 7cf6fe95..365a4792 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 80e428eb..e2c6c264 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;
@@ -1490,14 +1527,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
&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,64 +1715,88 @@ cogl_texture_get_gl_texture (CoglHandle handle,
return TRUE;
}
-CoglTextureFilter
-cogl_texture_get_min_filter (CoglHandle handle)
+void
+_cogl_texture_set_filters (CoglHandle handle,
+ GLenum min_filter,
+ GLenum mag_filter)
{
CoglTexture *tex;
+ GLuint gl_handle;
+ int i;
if (!cogl_is_texture (handle))
- return 0;
+ return;
tex = _cogl_texture_pointer_from_handle (handle);
- return tex->min_filter;
-}
-
-CoglTextureFilter
-cogl_texture_get_mag_filter (CoglHandle handle)
-{
- CoglTexture *tex;
+ /* Make sure slices were created */
+ if (tex->slice_gl_handles == NULL)
+ return;
- if (!cogl_is_texture (handle))
- return 0;
+ if (min_filter == tex->min_filter
+ && mag_filter == tex->mag_filter)
+ return;
- tex = _cogl_texture_pointer_from_handle (handle);
+ /* Store new values */
+ tex->min_filter = min_filter;
+ tex->mag_filter = mag_filter;
- return tex->mag_filter;
+ /* Apply new filters to every slice */
+ for (i=0; i<tex->slice_gl_handles->len; ++i)
+ {
+ gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i);
+ GE( glBindTexture (tex->gl_target, gl_handle) );
+ GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER,
+ tex->mag_filter) );
+ GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER,
+ tex->min_filter) );
+ }
}
void
-cogl_texture_set_filters (CoglHandle handle,
- CoglTextureFilter min_filter,
- CoglTextureFilter mag_filter)
+_cogl_texture_ensure_mipmaps (CoglHandle handle)
{
CoglTexture *tex;
- GLuint gl_handle;
int i;
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
if (!cogl_is_texture (handle))
return;
tex = _cogl_texture_pointer_from_handle (handle);
- /* Store new values */
- tex->min_filter = min_filter;
- tex->mag_filter = mag_filter;
+ /* 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;
- /* Apply new filters to every slice */
- for (i=0; i<tex->slice_gl_handles->len; ++i)
+ /* Regenerate the mipmaps on every slice */
+ for (i = 0; i < tex->slice_gl_handles->len; i++)
{
- gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i);
+ GLuint gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i);
GE( glBindTexture (tex->gl_target, gl_handle) );
- GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER,
- tex->mag_filter) );
- GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER,
- tex->min_filter) );
+
+ /* 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
diff --git a/gl/cogl.c b/gl/cogl.c
index 608bc364..748c082a 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;
}