[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.
This commit is contained in:
Neil Roberts 2009-06-04 16:04:57 +01:00
parent c27f429819
commit 54d8aadf1d
21 changed files with 427 additions and 322 deletions

View File

@ -79,7 +79,6 @@ struct _ClutterTexturePrivate
{ {
gfloat width; gfloat width;
gfloat height; gfloat height;
ClutterTextureQuality filter_quality;
CoglHandle material; CoglHandle material;
gboolean no_slice; gboolean no_slice;
@ -176,36 +175,35 @@ clutter_texture_error_quark (void)
return g_quark_from_static_string ("clutter-texture-error-quark"); return g_quark_from_static_string ("clutter-texture-error-quark");
} }
static const struct
{
gint min_filter;
gint mag_filter;
}
clutter_texture_quality_filters[] =
{
/* CLUTTER_TEXTURE_QUALITY_LOW */
{ COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST },
/* CLUTTER_TEXTURE_QUALITY_MEDIUM */
{ COGL_MATERIAL_FILTER_LINEAR, COGL_MATERIAL_FILTER_LINEAR },
/* CLUTTER_TEXTURE_QUALITY_HIGH */
{ COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR, COGL_MATERIAL_FILTER_LINEAR }
};
static inline void static inline void
clutter_texture_quality_to_filters (ClutterTextureQuality quality, clutter_texture_quality_to_filters (ClutterTextureQuality quality,
gint *min_filter_p, gint *min_filter_p,
gint *mag_filter_p) gint *mag_filter_p)
{ {
gint min_filter, mag_filter; g_return_if_fail (quality < G_N_ELEMENTS (clutter_texture_quality_filters));
switch (quality)
{
case CLUTTER_TEXTURE_QUALITY_LOW:
min_filter = COGL_TEXTURE_FILTER_NEAREST;
mag_filter = COGL_TEXTURE_FILTER_NEAREST;
break;
case CLUTTER_TEXTURE_QUALITY_MEDIUM:
min_filter = COGL_TEXTURE_FILTER_LINEAR;
mag_filter = COGL_TEXTURE_FILTER_LINEAR;
break;
case CLUTTER_TEXTURE_QUALITY_HIGH:
min_filter = COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR;
mag_filter = COGL_TEXTURE_FILTER_LINEAR;
break;
}
if (min_filter_p) if (min_filter_p)
*min_filter_p = min_filter; *min_filter_p = clutter_texture_quality_filters[quality].min_filter;
if (mag_filter_p) if (mag_filter_p)
*mag_filter_p = mag_filter; *mag_filter_p = clutter_texture_quality_filters[quality].mag_filter;
} }
static void static void
@ -216,7 +214,10 @@ texture_free_gl_resources (ClutterTexture *texture)
CLUTTER_MARK(); CLUTTER_MARK();
if (priv->material != COGL_INVALID_HANDLE) if (priv->material != COGL_INVALID_HANDLE)
cogl_material_remove_layer (priv->material, 0); /* We want to keep the layer so that the filter settings will
remain but we want to free its resources so we clear the
texture handle */
cogl_material_set_layer (priv->material, 0, COGL_INVALID_HANDLE);
} }
static void static void
@ -285,7 +286,6 @@ clutter_texture_realize (ClutterActor *actor)
if (priv->fbo_source) if (priv->fbo_source)
{ {
CoglTextureFlags flags = COGL_TEXTURE_NONE; CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint min_filter, mag_filter;
CoglHandle tex; CoglHandle tex;
/* Handle FBO's */ /* Handle FBO's */
@ -293,9 +293,6 @@ clutter_texture_realize (ClutterActor *actor)
if (priv->no_slice) if (priv->no_slice)
flags |= COGL_TEXTURE_NO_SLICING; flags |= COGL_TEXTURE_NO_SLICING;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
tex = cogl_texture_new_with_size (priv->width, tex = cogl_texture_new_with_size (priv->width,
priv->height, priv->height,
flags, flags,
@ -303,12 +300,6 @@ clutter_texture_realize (ClutterActor *actor)
cogl_material_set_layer (priv->material, 0, tex); cogl_material_set_layer (priv->material, 0, tex);
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
cogl_texture_set_filters (tex, min_filter, mag_filter);
priv->fbo_handle = cogl_offscreen_new_to_texture (tex); priv->fbo_handle = cogl_offscreen_new_to_texture (tex);
/* The material now has a reference to the texture so it will /* The material now has a reference to the texture so it will
@ -1189,7 +1180,6 @@ clutter_texture_init (ClutterTexture *self)
self->priv = priv = CLUTTER_TEXTURE_GET_PRIVATE (self); self->priv = priv = CLUTTER_TEXTURE_GET_PRIVATE (self);
priv->filter_quality = CLUTTER_TEXTURE_QUALITY_MEDIUM;
priv->repeat_x = FALSE; priv->repeat_x = FALSE;
priv->repeat_y = FALSE; priv->repeat_y = FALSE;
priv->sync_actor_size = TRUE; priv->sync_actor_size = TRUE;
@ -1229,11 +1219,6 @@ clutter_texture_save_to_local_data (ClutterTexture *texture)
/* Align to 4 bytes */ /* Align to 4 bytes */
priv->local_data_rowstride = (priv->local_data_width * bpp + 3) & ~3; priv->local_data_rowstride = (priv->local_data_width * bpp + 3) & ~3;
/* Store the filter quality from the texture properties so that
* they will be restored the data is loaded again
*/
priv->filter_quality = clutter_texture_get_filter_quality (texture);
priv->local_data = g_malloc (priv->local_data_rowstride priv->local_data = g_malloc (priv->local_data_rowstride
* priv->local_data_height); * priv->local_data_height);
@ -1465,14 +1450,10 @@ clutter_texture_set_from_data (ClutterTexture *texture,
ClutterTexturePrivate *priv = texture->priv; ClutterTexturePrivate *priv = texture->priv;
CoglHandle new_texture = COGL_INVALID_HANDLE; CoglHandle new_texture = COGL_INVALID_HANDLE;
CoglTextureFlags flags = COGL_TEXTURE_NONE; CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint min_filter, mag_filter;
if (priv->no_slice) if (priv->no_slice)
flags |= COGL_TEXTURE_NO_SLICING; flags |= COGL_TEXTURE_NO_SLICING;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
/* FIXME if we are not realized, we should store the data /* FIXME if we are not realized, we should store the data
* for future use, instead of creating the texture. * for future use, instead of creating the texture.
*/ */
@ -1493,12 +1474,6 @@ clutter_texture_set_from_data (ClutterTexture *texture,
return FALSE; return FALSE;
} }
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
cogl_texture_set_filters (new_texture, min_filter, mag_filter);
clutter_texture_set_cogl_texture (texture, new_texture); clutter_texture_set_cogl_texture (texture, new_texture);
cogl_handle_unref (new_texture); cogl_handle_unref (new_texture);
@ -1669,9 +1644,6 @@ clutter_texture_async_load_complete (ClutterTexture *self,
if (priv->no_slice) if (priv->no_slice)
flags |= COGL_TEXTURE_NO_SLICING; flags |= COGL_TEXTURE_NO_SLICING;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
handle = cogl_texture_new_from_bitmap (bitmap, handle = cogl_texture_new_from_bitmap (bitmap,
flags, flags,
COGL_PIXEL_FORMAT_ANY); COGL_PIXEL_FORMAT_ANY);
@ -1905,7 +1877,6 @@ clutter_texture_set_from_file (ClutterTexture *texture,
CoglHandle new_texture = COGL_INVALID_HANDLE; CoglHandle new_texture = COGL_INVALID_HANDLE;
GError *internal_error = NULL; GError *internal_error = NULL;
CoglTextureFlags flags = COGL_TEXTURE_NONE; CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint min_filter, mag_filter;
priv = texture->priv; priv = texture->priv;
@ -1917,9 +1888,6 @@ clutter_texture_set_from_file (ClutterTexture *texture,
if (priv->no_slice) if (priv->no_slice)
flags |= COGL_TEXTURE_NO_SLICING; flags |= COGL_TEXTURE_NO_SLICING;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
new_texture = cogl_texture_new_from_file (filename, new_texture = cogl_texture_new_from_file (filename,
flags, flags,
COGL_PIXEL_FORMAT_ANY, COGL_PIXEL_FORMAT_ANY,
@ -1941,12 +1909,6 @@ clutter_texture_set_from_file (ClutterTexture *texture,
return FALSE; return FALSE;
} }
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
cogl_texture_set_filters (new_texture, min_filter, mag_filter);
clutter_texture_set_cogl_texture (texture, new_texture); clutter_texture_set_cogl_texture (texture, new_texture);
cogl_handle_unref (new_texture); cogl_handle_unref (new_texture);
@ -1987,26 +1949,14 @@ clutter_texture_set_filter_quality (ClutterTexture *texture,
if (filter_quality != old_quality) if (filter_quality != old_quality)
{ {
CoglHandle cogl_texture = clutter_texture_get_cogl_texture (texture);
gint min_filter, mag_filter; gint min_filter, mag_filter;
priv->filter_quality = filter_quality; clutter_texture_quality_to_filters (filter_quality,
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter, &min_filter,
&mag_filter); &mag_filter);
/* Is this actually needed - causes problems with TFP mipmaps */ cogl_material_set_layer_filters (priv->material, 0,
if (cogl_texture != COGL_INVALID_HANDLE) min_filter, mag_filter);
cogl_texture_set_filters (cogl_texture, min_filter, mag_filter);
if ((old_quality == CLUTTER_TEXTURE_QUALITY_HIGH ||
filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) &&
CLUTTER_ACTOR_IS_REALIZED (texture))
{
_clutter_actor_rerealize (CLUTTER_ACTOR (texture),
NULL, NULL);
}
g_object_notify (G_OBJECT (texture), "filter-quality"); g_object_notify (G_OBJECT (texture), "filter-quality");
@ -2029,12 +1979,28 @@ ClutterTextureQuality
clutter_texture_get_filter_quality (ClutterTexture *texture) clutter_texture_get_filter_quality (ClutterTexture *texture)
{ {
ClutterTexturePrivate *priv; ClutterTexturePrivate *priv;
const GList *layers;
CoglMaterialFilter min_filter, mag_filter;
int i;
g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), 0); g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), 0);
priv = texture->priv; priv = texture->priv;
return priv->filter_quality; layers = cogl_material_get_layers (priv->material);
if (layers == NULL)
return CLUTTER_TEXTURE_QUALITY_MEDIUM;
min_filter = cogl_material_layer_get_min_filter (layers->data);
mag_filter = cogl_material_layer_get_mag_filter (layers->data);
for (i = 0; i < G_N_ELEMENTS (clutter_texture_quality_filters); i++)
if (clutter_texture_quality_filters[i].min_filter == min_filter
&& clutter_texture_quality_filters[i].mag_filter == mag_filter)
return i;
/* Unknown filter combination */
return CLUTTER_TEXTURE_QUALITY_LOW;
} }
/** /**
@ -2255,7 +2221,6 @@ on_fbo_source_size_change (GObject *object,
if (w != priv->width || h != priv->height) if (w != priv->width || h != priv->height)
{ {
CoglTextureFlags flags = COGL_TEXTURE_NONE; CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint min_filter, mag_filter;
CoglHandle tex; CoglHandle tex;
/* tear down the FBO */ /* tear down the FBO */
@ -2269,9 +2234,6 @@ on_fbo_source_size_change (GObject *object,
flags |= COGL_TEXTURE_NO_SLICING; flags |= COGL_TEXTURE_NO_SLICING;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
tex = cogl_texture_new_with_size (MAX (priv->width, 1), tex = cogl_texture_new_with_size (MAX (priv->width, 1),
MAX (priv->height, 1), MAX (priv->height, 1),
flags, flags,
@ -2279,12 +2241,6 @@ on_fbo_source_size_change (GObject *object,
cogl_material_set_layer (priv->material, 0, tex); cogl_material_set_layer (priv->material, 0, tex);
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
cogl_texture_set_filters (tex, min_filter, mag_filter);
priv->fbo_handle = cogl_offscreen_new_to_texture (tex); priv->fbo_handle = cogl_offscreen_new_to_texture (tex);
/* The material now has a reference to the texture so it will /* The material now has a reference to the texture so it will

View File

@ -43,6 +43,52 @@ G_BEGIN_DECLS
* blended together. * 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: * 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); 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 G_END_DECLS

View File

@ -218,72 +218,6 @@ guint cogl_texture_get_rowstride (CoglHandle handle);
*/ */
gint cogl_texture_get_max_waste (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: * cogl_texture_is_sliced:
* @handle: a #CoglHandle for a texture. * @handle: a #CoglHandle for a texture.
@ -333,20 +267,6 @@ gint cogl_texture_get_data (CoglHandle handle,
guint rowstride, guint rowstride,
guchar *data); 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: * cogl_texture_set_region:
* @handle: a #CoglHandle. * @handle: a #CoglHandle.

View File

@ -244,8 +244,11 @@ struct _CoglTextureVertex
/** /**
* CoglTextureFlags: * CoglTextureFlags:
* @COGL_TEXTURE_NONE: No flags specified * @COGL_TEXTURE_NONE: No flags specified
* @COGL_TEXTURE_AUTO_MIPMAP: Enables the automatic generation of the * @COGL_TEXTURE_NO_AUTO_MIPMAP: Disables the automatic generation of
* mipmap pyramid from the base level image whenever it is updated * 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 * @COGL_TEXTURE_NO_SLICING: Disables the slicing of the texture
* *
* Flags to pass to the cogl_texture_new_* family of functions. * Flags to pass to the cogl_texture_new_* family of functions.
@ -253,9 +256,9 @@ struct _CoglTextureVertex
* Since: 1.0 * Since: 1.0
*/ */
typedef enum { typedef enum {
COGL_TEXTURE_NONE = 0, COGL_TEXTURE_NONE = 0,
COGL_TEXTURE_AUTO_MIPMAP = 1 << 0, COGL_TEXTURE_NO_AUTO_MIPMAP = 1 << 0,
COGL_TEXTURE_NO_SLICING = 1 << 1 COGL_TEXTURE_NO_SLICING = 1 << 1
} CoglTextureFlags; } CoglTextureFlags;
/** /**

View File

@ -68,6 +68,9 @@ struct _CoglMaterialLayer
CoglHandle texture; /*!< The texture for this layer, or COGL_INVALID_HANDLE CoglHandle texture; /*!< The texture for this layer, or COGL_INVALID_HANDLE
for an empty layer */ for an empty layer */
CoglMaterialFilter mag_filter;
CoglMaterialFilter min_filter;
/* Determines how the color of individual texture fragments /* Determines how the color of individual texture fragments
* are calculated. */ * are calculated. */
GLint texture_combine_rgb_func; GLint texture_combine_rgb_func;

View File

@ -637,6 +637,8 @@ _cogl_material_get_layer (CoglMaterial *material,
layer_handle = _cogl_material_layer_handle_new (layer); layer_handle = _cogl_material_layer_handle_new (layer);
layer->index = index_; layer->index = index_;
layer->flags = COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; 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; layer->texture = COGL_INVALID_HANDLE;
/* Choose the same default combine mode as OpenGL: /* Choose the same default combine mode as OpenGL:
@ -1014,6 +1016,15 @@ get_n_args_for_combine_func (GLint func)
return 0; 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 static void
_cogl_material_layer_flush_gl_sampler_state (CoglMaterialLayer *layer, _cogl_material_layer_flush_gl_sampler_state (CoglMaterialLayer *layer,
CoglLayerInfo *gl_layer_info) CoglLayerInfo *gl_layer_info)
@ -1214,6 +1225,13 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
GE (glActiveTexture (GL_TEXTURE0 + i)); 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 /* FIXME: We could be more clever here and only bind the texture
if it is different from gl_layer_info->gl_texture to avoid if it is different from gl_layer_info->gl_texture to avoid
redundant GL calls. However a few other places in Cogl and 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); 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;
}

View File

@ -1186,7 +1186,8 @@ cogl_polygon (CoglTextureVertex *vertices,
use_sliced_polygon_fallback = TRUE; use_sliced_polygon_fallback = TRUE;
n_layers = 1; 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; static gboolean warning_seen = FALSE;
if (!warning_seen) if (!warning_seen)

View File

@ -120,6 +120,7 @@ typedef struct
COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC pf_glDeleteFramebuffersEXT; COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC pf_glDeleteFramebuffersEXT;
COGL_PFNGLBLITFRAMEBUFFEREXTPROC pf_glBlitFramebufferEXT; COGL_PFNGLBLITFRAMEBUFFEREXTPROC pf_glBlitFramebufferEXT;
COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC pf_glRenderbufferStorageMultisampleEXT; COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC pf_glRenderbufferStorageMultisampleEXT;
COGL_PFNGLGENERATEMIPMAPEXTPROC pf_glGenerateMipmapEXT;
COGL_PFNGLCREATEPROGRAMOBJECTARBPROC pf_glCreateProgramObjectARB; COGL_PFNGLCREATEPROGRAMOBJECTARBPROC pf_glCreateProgramObjectARB;
COGL_PFNGLCREATESHADEROBJECTARBPROC pf_glCreateShaderObjectARB; COGL_PFNGLCREATESHADEROBJECTARBPROC pf_glCreateShaderObjectARB;

View File

@ -773,6 +773,10 @@ typedef void
GLsizei width, GLsizei width,
GLsizei height); GLsizei height);
typedef void
(APIENTRYP COGL_PFNGLGENERATEMIPMAPEXTPROC)
(GLenum target);
typedef GLhandleARB typedef GLhandleARB
(APIENTRYP COGL_PFNGLCREATEPROGRAMOBJECTARBPROC) (APIENTRYP COGL_PFNGLCREATEPROGRAMOBJECTARBPROC)
(void); (void);

View File

@ -30,6 +30,7 @@
typedef struct _CoglTexture CoglTexture; typedef struct _CoglTexture CoglTexture;
typedef struct _CoglTexSliceSpan CoglTexSliceSpan; typedef struct _CoglTexSliceSpan CoglTexSliceSpan;
typedef struct _CoglSpanIter CoglSpanIter; typedef struct _CoglSpanIter CoglSpanIter;
typedef struct _CoglTexturePixel CoglTexturePixel;
struct _CoglTexSliceSpan struct _CoglTexSliceSpan
{ {
@ -55,6 +56,18 @@ struct _CoglSpanIter
gboolean intersects; 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 struct _CoglTexture
{ {
CoglHandleObject _parent; CoglHandleObject _parent;
@ -68,11 +81,17 @@ struct _CoglTexture
GArray *slice_y_spans; GArray *slice_y_spans;
GArray *slice_gl_handles; GArray *slice_gl_handles;
gint max_waste; gint max_waste;
CoglTextureFilter min_filter; GLenum min_filter;
CoglTextureFilter mag_filter; GLenum mag_filter;
gboolean is_foreign; gboolean is_foreign;
GLint wrap_mode; GLint wrap_mode;
gboolean auto_mipmap; 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 /* To improve batching of geometry when submitting vertices to OpenGL we
@ -93,6 +112,14 @@ void
_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex,
GLenum wrap_mode); GLenum wrap_mode);
void
_cogl_texture_set_filters (CoglHandle handle,
GLenum min_filter,
GLenum mag_filter);
void
_cogl_texture_ensure_mipmaps (CoglHandle handle);
gboolean gboolean
_cogl_texture_span_has_waste (CoglTexture *tex, _cogl_texture_span_has_waste (CoglTexture *tex,
gint x_span_index, gint x_span_index,

View File

@ -49,6 +49,7 @@
#define glDrawRangeElements ctx->pf_glDrawRangeElements #define glDrawRangeElements ctx->pf_glDrawRangeElements
#define glActiveTexture ctx->pf_glActiveTexture #define glActiveTexture ctx->pf_glActiveTexture
#define glClientActiveTexture ctx->pf_glClientActiveTexture #define glClientActiveTexture ctx->pf_glClientActiveTexture
#define glGenerateMipmap ctx->pf_glGenerateMipmapEXT
#else #else
@ -247,11 +248,12 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
/* Iterate horizontal slices */ /* Iterate horizontal slices */
for (x = 0; x < tex->slice_x_spans->len; ++x) 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); x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
/* Pick the gl texture object handle */ /* Pick the gl texture object handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num);
y * tex->slice_x_spans->len + x);
/* Setup gl alignment to match rowstride and top-left corner */ /* Setup gl alignment to match rowstride and top-left corner */
prep_for_gl_pixels_upload (tex->bitmap.rowstride, prep_for_gl_pixels_upload (tex->bitmap.rowstride,
@ -259,6 +261,17 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
y_span->start, y_span->start,
bpp); 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 */ /* Upload new image data */
GE( glBindTexture (tex->gl_target, gl_handle) ); GE( glBindTexture (tex->gl_target, gl_handle) );
@ -343,6 +356,8 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
if (waste_buf) if (waste_buf)
g_free (waste_buf); g_free (waste_buf);
tex->mipmaps_dirty = TRUE;
return TRUE; return TRUE;
} }
@ -494,6 +509,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
_cogl_span_iter_next (&x_iter), _cogl_span_iter_next (&x_iter),
source_x += inter_w ) source_x += inter_w )
{ {
gint slice_num;
/* Discard slices out of the subregion early */ /* Discard slices out of the subregion early */
if (!x_iter.intersects) if (!x_iter.intersects)
{ {
@ -516,10 +533,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
local_y = (y_iter.intersect_start - local_y = (y_iter.intersect_start -
y_iter.pos); y_iter.pos);
slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index;
/* Pick slice GL handle */ /* Pick slice GL handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num);
y_iter.index * tex->slice_x_spans->len +
x_iter.index);
/* Setup gl alignment to match rowstride and top-left corner */ /* Setup gl alignment to match rowstride and top-left corner */
prep_for_gl_pixels_upload (source_bmp->rowstride, prep_for_gl_pixels_upload (source_bmp->rowstride,
@ -527,6 +544,17 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
source_y, source_y,
bpp); 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 */ /* Upload new image data */
GE( glBindTexture (tex->gl_target, gl_handle) ); GE( glBindTexture (tex->gl_target, gl_handle) );
@ -640,6 +668,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
if (waste_buf) if (waste_buf)
g_free (waste_buf); g_free (waste_buf);
tex->mipmaps_dirty = TRUE;
return TRUE; return TRUE;
} }
@ -913,6 +943,14 @@ _cogl_texture_slices_create (CoglTexture *tex)
g_array_set_size (tex->slice_gl_handles, n_slices); 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 */ /* Wrap mode not yet set */
tex->wrap_mode = GL_FALSE; tex->wrap_mode = GL_FALSE;
@ -941,14 +979,6 @@ _cogl_texture_slices_create (CoglTexture *tex)
/* Setup texture parameters */ /* Setup texture parameters */
GE( glBindTexture (tex->gl_target, GE( glBindTexture (tex->gl_target,
gl_handles[y * n_x_slices + x]) ); 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 /* Use a transparent border color so that we can leave the
color buffer alone when using texture co-ordinates 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); g_array_free (tex->slice_gl_handles, TRUE);
} }
if (tex->first_pixels != NULL)
g_free (tex->first_pixels);
} }
gboolean gboolean
@ -1221,7 +1254,8 @@ cogl_texture_new_with_size (guint width,
tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex = (CoglTexture*) g_malloc (sizeof (CoglTexture));
tex->is_foreign = FALSE; 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.width = width;
tex->bitmap.height = height; tex->bitmap.height = height;
@ -1239,8 +1273,9 @@ cogl_texture_new_with_size (guint width,
else else
tex->max_waste = COGL_TEXTURE_MAX_WASTE; tex->max_waste = COGL_TEXTURE_MAX_WASTE;
tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; /* Unknown filter */
tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
/* Find closest GL format match */ /* Find closest GL format match */
tex->bitmap.format = tex->bitmap.format =
@ -1285,7 +1320,8 @@ cogl_texture_new_from_data (guint width,
tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex = (CoglTexture*) g_malloc (sizeof (CoglTexture));
tex->is_foreign = FALSE; 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.width = width;
tex->bitmap.height = height; tex->bitmap.height = height;
@ -1303,8 +1339,9 @@ cogl_texture_new_from_data (guint width,
else else
tex->max_waste = COGL_TEXTURE_MAX_WASTE; tex->max_waste = COGL_TEXTURE_MAX_WASTE;
tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; /* Unknown filter */
tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
/* FIXME: If upload fails we should set some kind of /* FIXME: If upload fails we should set some kind of
* error flag but still return texture handle (this * 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 = (CoglTexture*) g_malloc ( sizeof (CoglTexture));
tex->is_foreign = FALSE; 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 = *bmp;
tex->bitmap_owner = TRUE; tex->bitmap_owner = TRUE;
@ -1363,8 +1401,9 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
else else
tex->max_waste = COGL_TEXTURE_MAX_WASTE; tex->max_waste = COGL_TEXTURE_MAX_WASTE;
tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; /* Unknown filter */
tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
/* FIXME: If upload fails we should set some kind of /* FIXME: If upload fails we should set some kind of
* error flag but still return texture handle if the * 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_int_format = 0;
GLint gl_width = 0; GLint gl_width = 0;
GLint gl_height = 0; GLint gl_height = 0;
GLint gl_min_filter;
GLint gl_mag_filter;
GLint gl_gen_mipmap; GLint gl_gen_mipmap;
guint bpp; guint bpp;
CoglTexture *tex; CoglTexture *tex;
@ -1489,14 +1526,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
GL_TEXTURE_HEIGHT, GL_TEXTURE_HEIGHT,
&gl_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, GE( glGetTexParameteriv (gl_target,
GL_GENERATE_MIPMAP, GL_GENERATE_MIPMAP,
&gl_gen_mipmap) ); &gl_gen_mipmap) );
@ -1524,6 +1553,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
/* Setup bitmap info */ /* Setup bitmap info */
tex->is_foreign = TRUE; tex->is_foreign = TRUE;
tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE; tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE;
tex->mipmaps_dirty = TRUE;
bpp = _cogl_get_format_bpp (format); bpp = _cogl_get_format_bpp (format);
tex->bitmap.format = 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_format = gl_int_format;
tex->gl_type = GL_UNSIGNED_BYTE; tex->gl_type = GL_UNSIGNED_BYTE;
tex->min_filter = gl_min_filter; /* Unknown filter */
tex->mag_filter = gl_mag_filter; tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
tex->max_waste = 0; tex->max_waste = 0;
/* Wrap mode not yet set */ /* Wrap mode not yet set */
@ -1684,36 +1715,10 @@ cogl_texture_get_gl_texture (CoglHandle handle,
return TRUE; 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 void
cogl_texture_set_filters (CoglHandle handle, _cogl_texture_set_filters (CoglHandle handle,
CoglTextureFilter min_filter, GLenum min_filter,
CoglTextureFilter mag_filter) GLenum mag_filter)
{ {
CoglTexture *tex; CoglTexture *tex;
GLuint gl_handle; GLuint gl_handle;
@ -1724,14 +1729,18 @@ cogl_texture_set_filters (CoglHandle handle,
tex = _cogl_texture_pointer_from_handle (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 */ /* Make sure slices were created */
if (tex->slice_gl_handles == NULL) if (tex->slice_gl_handles == NULL)
return; 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 */ /* Apply new filters to every slice */
for (i=0; i<tex->slice_gl_handles->len; ++i) for (i=0; i<tex->slice_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 gboolean
cogl_texture_set_region (CoglHandle handle, cogl_texture_set_region (CoglHandle handle,
gint src_x, gint src_x,

View File

@ -399,6 +399,10 @@ _cogl_features_init (void)
(COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC) (COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC)
cogl_get_proc_address ("glDeleteFramebuffersEXT"); cogl_get_proc_address ("glDeleteFramebuffersEXT");
ctx->pf_glGenerateMipmapEXT =
(COGL_PFNGLGENERATEMIPMAPEXTPROC)
cogl_get_proc_address ("glGenerateMipmapEXT");
if (ctx->pf_glGenRenderbuffersEXT && if (ctx->pf_glGenRenderbuffersEXT &&
ctx->pf_glBindRenderbufferEXT && ctx->pf_glBindRenderbufferEXT &&
ctx->pf_glRenderbufferStorageEXT && ctx->pf_glRenderbufferStorageEXT &&
@ -407,7 +411,8 @@ _cogl_features_init (void)
ctx->pf_glFramebufferTexture2DEXT && ctx->pf_glFramebufferTexture2DEXT &&
ctx->pf_glFramebufferRenderbufferEXT && ctx->pf_glFramebufferRenderbufferEXT &&
ctx->pf_glCheckFramebufferStatusEXT && ctx->pf_glCheckFramebufferStatusEXT &&
ctx->pf_glDeleteFramebuffersEXT) ctx->pf_glDeleteFramebuffersEXT &&
ctx->pf_glGenerateMipmapEXT)
flags |= COGL_FEATURE_OFFSCREEN; flags |= COGL_FEATURE_OFFSCREEN;
} }

View File

@ -135,14 +135,6 @@ texture_bind (ClutterGLXTexturePixmap *tex)
/* FIXME: fire off an error here? */ /* FIXME: fire off an error here? */
glBindTexture (target, handle); glBindTexture (target, handle);
if (clutter_texture_get_filter_quality (CLUTTER_TEXTURE (tex))
== CLUTTER_TEXTURE_QUALITY_HIGH && tex->priv->can_mipmap)
{
cogl_texture_set_filters (cogl_tex,
COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR,
COGL_TEXTURE_FILTER_LINEAR);
}
return TRUE; return TRUE;
} }
@ -167,6 +159,18 @@ on_glx_texture_pixmap_pre_paint (ClutterGLXTexturePixmap *texture,
texture->priv->mipmap_generate_queued = 0; texture->priv->mipmap_generate_queued = 0;
} }
/* Disable mipmaps if we can't support them */
if (clutter_texture_get_filter_quality (CLUTTER_TEXTURE (texture))
== CLUTTER_TEXTURE_QUALITY_HIGH
&& !texture->priv->can_mipmap)
{
CoglHandle material
= clutter_texture_get_cogl_material (CLUTTER_TEXTURE (texture));
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_LINEAR,
COGL_MATERIAL_FILTER_LINEAR);
}
} }
static void static void

View File

@ -51,10 +51,6 @@ struct _CoglPangoGlyphCache
/* List of horizontal bands of glyphs */ /* List of horizontal bands of glyphs */
CoglPangoGlyphCacheBand *bands; CoglPangoGlyphCacheBand *bands;
/* If TRUE all of the textures will be created with automatic mipmap
generation enabled */
gboolean use_mipmapping;
}; };
struct _CoglPangoGlyphCacheKey struct _CoglPangoGlyphCacheKey
@ -177,7 +173,7 @@ cogl_pango_glyph_cache_free_bands (CoglPangoGlyphCacheBand *node)
} }
CoglPangoGlyphCache * CoglPangoGlyphCache *
cogl_pango_glyph_cache_new (gboolean use_mipmapping) cogl_pango_glyph_cache_new (void)
{ {
CoglPangoGlyphCache *cache; CoglPangoGlyphCache *cache;
@ -191,7 +187,6 @@ cogl_pango_glyph_cache_new (gboolean use_mipmapping)
cache->textures = NULL; cache->textures = NULL;
cache->bands = NULL; cache->bands = NULL;
cache->use_mipmapping = use_mipmapping;
return cache; return cache;
} }
@ -272,7 +267,6 @@ cogl_pango_glyph_cache_set (CoglPangoGlyphCache *cache,
texture = texture->next); texture = texture->next);
if (texture == NULL) if (texture == NULL)
{ {
CoglTextureFlags flags = COGL_TEXTURE_NONE;
guchar *clear_data; guchar *clear_data;
/* Allocate a new texture that is the nearest power of two /* Allocate a new texture that is the nearest power of two
@ -291,13 +285,10 @@ cogl_pango_glyph_cache_set (CoglPangoGlyphCache *cache,
clear_data = clear_data =
g_malloc0 (texture->texture_size * texture->texture_size); g_malloc0 (texture->texture_size * texture->texture_size);
if (cache->use_mipmapping)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
texture->texture = texture->texture =
cogl_texture_new_from_data (texture->texture_size, cogl_texture_new_from_data (texture->texture_size,
texture->texture_size, texture->texture_size,
flags, COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_A_8, COGL_PIXEL_FORMAT_A_8,
COGL_PIXEL_FORMAT_A_8, COGL_PIXEL_FORMAT_A_8,
texture->texture_size, texture->texture_size,
@ -308,15 +299,6 @@ cogl_pango_glyph_cache_set (CoglPangoGlyphCache *cache,
texture->space_remaining = texture->texture_size; texture->space_remaining = texture->texture_size;
texture->next = cache->textures; texture->next = cache->textures;
cache->textures = texture; cache->textures = texture;
if (cache->use_mipmapping)
cogl_texture_set_filters (texture->texture,
COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR,
COGL_TEXTURE_FILTER_LINEAR);
else
cogl_texture_set_filters (texture->texture,
COGL_TEXTURE_FILTER_LINEAR,
COGL_TEXTURE_FILTER_LINEAR);
} }
band = g_slice_new (CoglPangoGlyphCacheBand); band = g_slice_new (CoglPangoGlyphCacheBand);

View File

@ -49,7 +49,7 @@ struct _CoglPangoGlyphCacheValue
}; };
CoglPangoGlyphCache * CoglPangoGlyphCache *
cogl_pango_glyph_cache_new (gboolean use_mipmapping); cogl_pango_glyph_cache_new (void);
void void
cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache); cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache);

View File

@ -49,12 +49,8 @@ struct _CoglPangoRenderer
/* The material used for solid fills. (boxes, rectangles + trapezoids) */ /* The material used for solid fills. (boxes, rectangles + trapezoids) */
CoglHandle solid_material; CoglHandle solid_material;
/* Two caches of glyphs as textures, one with mipmapped textures and /* Caches of glyphs as textures */
one without */
CoglPangoGlyphCache *glyph_cache; CoglPangoGlyphCache *glyph_cache;
CoglPangoGlyphCache *mipmapped_glyph_cache;
gboolean use_mipmapping;
/* The current display list that is being built */ /* The current display list that is being built */
CoglPangoDisplayList *display_list; CoglPangoDisplayList *display_list;
@ -144,9 +140,9 @@ cogl_pango_renderer_init (CoglPangoRenderer *priv)
priv->solid_material = cogl_material_new (); priv->solid_material = cogl_material_new ();
priv->glyph_cache = cogl_pango_glyph_cache_new (FALSE); priv->glyph_cache = cogl_pango_glyph_cache_new ();
priv->mipmapped_glyph_cache = cogl_pango_glyph_cache_new (TRUE);
priv->use_mipmapping = FALSE; _cogl_pango_renderer_set_use_mipmapping (priv, FALSE);
} }
static void static void
@ -167,7 +163,6 @@ cogl_pango_renderer_finalize (GObject *object)
{ {
CoglPangoRenderer *priv = COGL_PANGO_RENDERER (object); CoglPangoRenderer *priv = COGL_PANGO_RENDERER (object);
cogl_pango_glyph_cache_free (priv->mipmapped_glyph_cache);
cogl_pango_glyph_cache_free (priv->glyph_cache); cogl_pango_glyph_cache_free (priv->glyph_cache);
G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->finalize (object); G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->finalize (object);
@ -363,20 +358,31 @@ void
_cogl_pango_renderer_clear_glyph_cache (CoglPangoRenderer *renderer) _cogl_pango_renderer_clear_glyph_cache (CoglPangoRenderer *renderer)
{ {
cogl_pango_glyph_cache_clear (renderer->glyph_cache); cogl_pango_glyph_cache_clear (renderer->glyph_cache);
cogl_pango_glyph_cache_clear (renderer->mipmapped_glyph_cache);
} }
void void
_cogl_pango_renderer_set_use_mipmapping (CoglPangoRenderer *renderer, _cogl_pango_renderer_set_use_mipmapping (CoglPangoRenderer *renderer,
gboolean value) gboolean value)
{ {
renderer->use_mipmapping = value; if (value)
cogl_material_set_layer_filters (renderer->glyph_material, 0,
COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR,
COGL_MATERIAL_FILTER_LINEAR);
else
cogl_material_set_layer_filters (renderer->glyph_material, 0,
COGL_MATERIAL_FILTER_LINEAR,
COGL_MATERIAL_FILTER_LINEAR);
} }
gboolean gboolean
_cogl_pango_renderer_get_use_mipmapping (CoglPangoRenderer *renderer) _cogl_pango_renderer_get_use_mipmapping (CoglPangoRenderer *renderer)
{ {
return renderer->use_mipmapping; const GList *layers = cogl_material_get_layers (renderer->glyph_material);
g_return_val_if_fail (layers != NULL, FALSE);
return (cogl_material_layer_get_min_filter (layers->data)
== COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR);
} }
static CoglPangoGlyphCacheValue * static CoglPangoGlyphCacheValue *
@ -386,12 +392,8 @@ cogl_pango_renderer_get_cached_glyph (PangoRenderer *renderer,
{ {
CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer);
CoglPangoGlyphCacheValue *value; CoglPangoGlyphCacheValue *value;
CoglPangoGlyphCache *glyph_cache;
glyph_cache = priv->use_mipmapping ? priv->mipmapped_glyph_cache value = cogl_pango_glyph_cache_lookup (priv->glyph_cache, font, glyph);
: priv->glyph_cache;
value = cogl_pango_glyph_cache_lookup (glyph_cache, font, glyph);
if (value == NULL) if (value == NULL)
{ {
cairo_surface_t *surface; cairo_surface_t *surface;
@ -423,7 +425,7 @@ cogl_pango_renderer_get_cached_glyph (PangoRenderer *renderer,
/* Copy the glyph to the cache */ /* Copy the glyph to the cache */
value = value =
cogl_pango_glyph_cache_set (glyph_cache, font, glyph, cogl_pango_glyph_cache_set (priv->glyph_cache, font, glyph,
cairo_image_surface_get_data (surface), cairo_image_surface_get_data (surface),
cairo_image_surface_get_width (surface), cairo_image_surface_get_width (surface),
cairo_image_surface_get_height (surface), cairo_image_surface_get_height (surface),

View File

@ -132,12 +132,9 @@ cogl_texture_get_height
cogl_texture_get_format cogl_texture_get_format
cogl_texture_get_rowstride cogl_texture_get_rowstride
cogl_texture_get_max_waste cogl_texture_get_max_waste
cogl_texture_get_min_filter
cogl_texture_get_mag_filter
cogl_texture_is_sliced cogl_texture_is_sliced
cogl_texture_get_gl_texture cogl_texture_get_gl_texture
cogl_texture_get_data cogl_texture_get_data
cogl_texture_set_filters
cogl_texture_set_region cogl_texture_set_region
</SECTION> </SECTION>
@ -366,8 +363,12 @@ cogl_material_set_layer_combine
cogl_material_set_layer_combine_constant cogl_material_set_layer_combine_constant
cogl_material_set_layer_matrix cogl_material_set_layer_matrix
cogl_material_get_layers cogl_material_get_layers
CoglMaterialFilter
cogl_material_set_layer_filters
cogl_material_layer_get_type cogl_material_layer_get_type
cogl_material_layer_get_texture cogl_material_layer_get_texture
cogl_material_layer_get_min_filter
cogl_material_layer_get_mag_filter
<SUBSECTION Private> <SUBSECTION Private>
CoglMaterial CoglMaterial
CoglMaterialFlags CoglMaterialFlags

View File

@ -107,6 +107,11 @@ on_paint (ClutterActor *actor, TestState *state)
{ {
int i; int i;
int frame_num; int frame_num;
CoglHandle material = cogl_material_new ();
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_set_backface_culling_enabled (TRUE); cogl_set_backface_culling_enabled (TRUE);
@ -120,24 +125,21 @@ on_paint (ClutterActor *actor, TestState *state)
float x1 = 0, x2, y1 = 0, y2 = (float)(TEXTURE_RENDER_SIZE); float x1 = 0, x2, y1 = 0, y2 = (float)(TEXTURE_RENDER_SIZE);
CoglTextureVertex verts[4]; CoglTextureVertex verts[4];
memset (verts, 0, sizeof (verts)); cogl_set_source (material);
/* Set the color to white so that all the textures will be drawn memset (verts, 0, sizeof (verts));
at their own color */
cogl_set_source_color4f (1.0, 1.0,
1.0, 1.0);
x2 = x1 + (float)(TEXTURE_RENDER_SIZE); x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
/* Draw a front-facing texture */ /* Draw a front-facing texture */
cogl_set_source_texture (state->texture); cogl_material_set_layer (material, 0, state->texture);
cogl_rectangle (x1, y1, x2, y2); cogl_rectangle (x1, y1, x2, y2);
x1 = x2; x1 = x2;
x2 = x1 + (float)(TEXTURE_RENDER_SIZE); x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
/* Draw a back-facing texture */ /* Draw a back-facing texture */
cogl_set_source_texture (state->texture); cogl_material_set_layer (material, 0, state->texture);
cogl_rectangle (x2, y1, x1, y2); cogl_rectangle (x2, y1, x1, y2);
x1 = x2; x1 = x2;
@ -152,7 +154,7 @@ on_paint (ClutterActor *actor, TestState *state)
verts[1].tx = 1.0; verts[1].ty = 0; verts[1].tx = 1.0; verts[1].ty = 0;
verts[2].tx = 1.0; verts[2].ty = 1.0; verts[2].tx = 1.0; verts[2].ty = 1.0;
verts[3].tx = 0; verts[3].ty = 1.0; verts[3].tx = 0; verts[3].ty = 1.0;
cogl_set_source_texture (state->texture); cogl_material_set_layer (material, 0, state->texture);
cogl_polygon (verts, 4, FALSE); cogl_polygon (verts, 4, FALSE);
x1 = x2; x1 = x2;
@ -167,7 +169,7 @@ on_paint (ClutterActor *actor, TestState *state)
verts[1].tx = 1.0; verts[1].ty = 0; verts[1].tx = 1.0; verts[1].ty = 0;
verts[2].tx = 1.0; verts[2].ty = 1.0; verts[2].tx = 1.0; verts[2].ty = 1.0;
verts[3].tx = 0; verts[3].ty = 1.0; verts[3].tx = 0; verts[3].ty = 1.0;
cogl_set_source_texture (state->texture); cogl_material_set_layer (material, 0, state->texture);
cogl_polygon (verts, 4, FALSE); cogl_polygon (verts, 4, FALSE);
x1 = x2; x1 = x2;
@ -185,6 +187,8 @@ on_paint (ClutterActor *actor, TestState *state)
cogl_pop_matrix (); cogl_pop_matrix ();
cogl_handle_unref (material);
/* XXX: Experiments have shown that for some buggy drivers, when using /* XXX: Experiments have shown that for some buggy drivers, when using
* glReadPixels there is some kind of race, so we delay our test for a * glReadPixels there is some kind of race, so we delay our test for a
* few frames and a few seconds: * few frames and a few seconds:

View File

@ -87,20 +87,17 @@ test_cogl_multitexture_main (int argc, char *argv[])
state->alpha_tex = state->alpha_tex =
cogl_texture_new_from_file ("redhand_alpha.png", cogl_texture_new_from_file ("redhand_alpha.png",
COGL_TEXTURE_NO_SLICING | COGL_TEXTURE_NO_SLICING,
COGL_TEXTURE_AUTO_MIPMAP,
COGL_PIXEL_FORMAT_ANY, COGL_PIXEL_FORMAT_ANY,
NULL); NULL);
state->redhand_tex = state->redhand_tex =
cogl_texture_new_from_file ("redhand.png", cogl_texture_new_from_file ("redhand.png",
COGL_TEXTURE_NO_SLICING | COGL_TEXTURE_NO_SLICING,
COGL_TEXTURE_AUTO_MIPMAP,
COGL_PIXEL_FORMAT_ANY, COGL_PIXEL_FORMAT_ANY,
NULL); NULL);
state->light_tex0 = state->light_tex0 =
cogl_texture_new_from_file ("light0.png", cogl_texture_new_from_file ("light0.png",
COGL_TEXTURE_NO_SLICING | COGL_TEXTURE_NO_SLICING,
COGL_TEXTURE_AUTO_MIPMAP,
COGL_PIXEL_FORMAT_ANY, COGL_PIXEL_FORMAT_ANY,
NULL); NULL);

View File

@ -173,14 +173,17 @@ test_coglbox_paint (ClutterActor *self)
: priv->not_sliced_tex; : priv->not_sliced_tex;
int tex_width = cogl_texture_get_width (tex_handle); int tex_width = cogl_texture_get_width (tex_handle);
int tex_height = cogl_texture_get_height (tex_handle); int tex_height = cogl_texture_get_height (tex_handle);
CoglHandle material = cogl_material_new ();
cogl_texture_set_filters (tex_handle, cogl_material_set_layer (material, 0, tex_handle);
priv->use_linear_filtering
? COGL_TEXTURE_FILTER_LINEAR : cogl_material_set_layer_filters (material, 0,
COGL_TEXTURE_FILTER_NEAREST, priv->use_linear_filtering
priv->use_linear_filtering ? COGL_MATERIAL_FILTER_LINEAR :
? COGL_TEXTURE_FILTER_LINEAR : COGL_MATERIAL_FILTER_NEAREST,
COGL_TEXTURE_FILTER_NEAREST); priv->use_linear_filtering
? COGL_MATERIAL_FILTER_LINEAR :
COGL_MATERIAL_FILTER_NEAREST);
cogl_push_matrix (); cogl_push_matrix ();
cogl_translate (tex_width / 2, 0, 0); cogl_translate (tex_width / 2, 0, 0);
@ -188,7 +191,7 @@ test_coglbox_paint (ClutterActor *self)
cogl_translate (-tex_width / 2, 0, 0); cogl_translate (-tex_width / 2, 0, 0);
/* Draw a hand and refect it */ /* Draw a hand and refect it */
cogl_set_source_texture (tex_handle); cogl_set_source (material);
cogl_rectangle_with_texture_coords (0, 0, tex_width, tex_height, cogl_rectangle_with_texture_coords (0, 0, tex_width, tex_height,
0, 0, 1, 1); 0, 0, 1, 1);
test_coglbox_fade_texture (tex_handle, test_coglbox_fade_texture (tex_handle,
@ -217,6 +220,8 @@ test_coglbox_paint (ClutterActor *self)
1, 1); 1, 1);
cogl_pop_matrix (); cogl_pop_matrix ();
cogl_handle_unref (material);
} }
static void static void

View File

@ -147,10 +147,6 @@ test_coglbox_init (TestCoglbox *self)
COGL_TEXTURE_NONE, COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_ANY, COGL_PIXEL_FORMAT_ANY,
NULL); NULL);
cogl_texture_set_filters (priv->cogl_tex_id,
COGL_TEXTURE_FILTER_LINEAR,
COGL_TEXTURE_FILTER_LINEAR);
} }
static void static void