summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compositor/meta-shaped-texture.c88
1 files changed, 82 insertions, 6 deletions
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
index 98346c6ae..0240c067c 100644
--- a/src/compositor/meta-shaped-texture.c
+++ b/src/compositor/meta-shaped-texture.c
@@ -38,6 +38,20 @@
#include "meta-cullable.h"
+/* MAX_MIPMAPPING_FPS needs to be as small as possible for the best GPU
+ * performance, but higher than the refresh rate of commonly slow updating
+ * windows like top or a blinking cursor, so that such windows do get
+ * mipmapped.
+ */
+#define MAX_MIPMAPPING_FPS 5
+#define MIN_MIPMAP_AGE_USEC (G_USEC_PER_SEC / MAX_MIPMAPPING_FPS)
+
+/* MIN_FAST_UPDATES_BEFORE_UNMIPMAP allows windows to update themselves
+ * occasionally without causing mipmapping to be disabled, so long as such
+ * an update takes fewer update_area calls than:
+ */
+#define MIN_FAST_UPDATES_BEFORE_UNMIPMAP 20
+
static void meta_shaped_texture_dispose (GObject *object);
static void meta_shaped_texture_paint (ClutterActor *actor);
@@ -95,6 +109,11 @@ struct _MetaShapedTexturePrivate
guint tex_width, tex_height;
guint fallback_width, fallback_height;
+ gint64 prev_invalidation, last_invalidation;
+ guint fast_updates;
+ guint remipmap_timeout_id;
+ gint64 earliest_remipmap;
+
guint create_mipmaps : 1;
};
@@ -191,6 +210,12 @@ meta_shaped_texture_dispose (GObject *object)
MetaShapedTexture *self = (MetaShapedTexture *) object;
MetaShapedTexturePrivate *priv = self->priv;
+ if (priv->remipmap_timeout_id)
+ {
+ g_source_remove (priv->remipmap_timeout_id);
+ priv->remipmap_timeout_id = 0;
+ }
+
if (priv->paint_tower)
meta_texture_tower_free (priv->paint_tower);
priv->paint_tower = NULL;
@@ -372,6 +397,21 @@ set_cogl_texture (MetaShapedTexture *stex,
meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
}
+static gboolean
+texture_is_idle_and_not_mipmapped (gpointer user_data)
+{
+ MetaShapedTexture *stex = META_SHAPED_TEXTURE (user_data);
+ MetaShapedTexturePrivate *priv = stex->priv;
+
+ if ((g_get_monotonic_time () - priv->earliest_remipmap) < 0)
+ return G_SOURCE_CONTINUE;
+
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
+ priv->remipmap_timeout_id = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
static void
meta_shaped_texture_paint (ClutterActor *actor)
{
@@ -381,9 +421,10 @@ meta_shaped_texture_paint (ClutterActor *actor)
guchar opacity;
CoglContext *ctx;
CoglFramebuffer *fb;
- CoglTexture *paint_tex;
+ CoglTexture *paint_tex = NULL;
ClutterActorBox alloc;
CoglPipelineFilter filter;
+ gint64 now = g_get_monotonic_time ();
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
return;
@@ -406,13 +447,34 @@ meta_shaped_texture_paint (ClutterActor *actor)
* Setting the texture quality to high without SGIS_generate_mipmap
* support for TFP textures will result in fallbacks to XGetImage.
*/
- if (priv->create_mipmaps)
- paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
- else
- paint_tex = COGL_TEXTURE (priv->texture);
+ if (priv->create_mipmaps && priv->last_invalidation)
+ {
+ gint64 age = now - priv->last_invalidation;
+
+ if (age >= MIN_MIPMAP_AGE_USEC ||
+ priv->fast_updates < MIN_FAST_UPDATES_BEFORE_UNMIPMAP)
+ paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
+ }
if (paint_tex == NULL)
- return;
+ {
+ paint_tex = COGL_TEXTURE (priv->texture);
+
+ if (paint_tex == NULL)
+ return;
+
+ if (priv->create_mipmaps)
+ {
+ /* Minus 1000 to ensure we don't fail the age test in timeout */
+ priv->earliest_remipmap = now + MIN_MIPMAP_AGE_USEC - 1000;
+
+ if (!priv->remipmap_timeout_id)
+ priv->remipmap_timeout_id =
+ g_timeout_add (MIN_MIPMAP_AGE_USEC / 1000,
+ texture_is_idle_and_not_mipmapped,
+ stex);
+ }
+ }
tex_width = priv->tex_width;
tex_height = priv->tex_height;
@@ -758,6 +820,20 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
+ priv->prev_invalidation = priv->last_invalidation;
+ priv->last_invalidation = g_get_monotonic_time ();
+
+ if (priv->prev_invalidation)
+ {
+ gint64 interval = priv->last_invalidation - priv->prev_invalidation;
+ gboolean fast_update = interval < MIN_MIPMAP_AGE_USEC;
+
+ if (!fast_update)
+ priv->fast_updates = 0;
+ else if (priv->fast_updates < MIN_FAST_UPDATES_BEFORE_UNMIPMAP)
+ priv->fast_updates++;
+ }
+
unobscured_region = effective_unobscured_region (stex);
if (unobscured_region)
{