|
|
776610 |
From 04b7954c7f04e7348f139fdf5c38e7702b387ee3 Mon Sep 17 00:00:00 2001
|
|
|
776610 |
From: Ray Strode <rstrode@redhat.com>
|
|
|
776610 |
Date: Thu, 10 Jan 2019 10:48:02 -0500
|
|
|
776610 |
Subject: [PATCH 9/9] MetaShapedTexture: save and restore textures on suspend
|
|
|
776610 |
|
|
|
776610 |
The proprietary nvidia driver garbles GPU memory on suspend.
|
|
|
776610 |
|
|
|
776610 |
In order to workaround that limitation, this commit copies all
|
|
|
776610 |
textures to host memory on suspend and restores them on resume.
|
|
|
776610 |
|
|
|
776610 |
One complication comes from external textures (such as those
|
|
|
776610 |
given to us by Xwayland for X clients). We can't just restore
|
|
|
776610 |
those textures, since they aren't writable.
|
|
|
776610 |
|
|
|
776610 |
This commit addresses that complication by keeping a local texture
|
|
|
776610 |
around for those external textures, and using it instead for parts
|
|
|
776610 |
of the window that haven't been redrawn since resume.
|
|
|
776610 |
---
|
|
|
776610 |
src/compositor/meta-shaped-texture.c | 494 +++++++++++++++++++++++++--
|
|
|
776610 |
src/meta/meta-shaped-texture.h | 2 +
|
|
|
776610 |
2 files changed, 475 insertions(+), 21 deletions(-)
|
|
|
776610 |
|
|
|
776610 |
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
|
|
|
776610 |
index d8c250fc9..8de173bf7 100644
|
|
|
776610 |
--- a/src/compositor/meta-shaped-texture.c
|
|
|
776610 |
+++ b/src/compositor/meta-shaped-texture.c
|
|
|
776610 |
@@ -2,166 +2,203 @@
|
|
|
776610 |
* Authored By Neil Roberts <neil@linux.intel.com>
|
|
|
776610 |
* and Jasper St. Pierre <jstpierre@mecheye.net>
|
|
|
776610 |
*
|
|
|
776610 |
* Copyright (C) 2008 Intel Corporation
|
|
|
776610 |
* Copyright (C) 2012 Red Hat, Inc.
|
|
|
776610 |
*
|
|
|
776610 |
* This program is free software; you can redistribute it and/or
|
|
|
776610 |
* modify it under the terms of the GNU General Public License as
|
|
|
776610 |
* published by the Free Software Foundation; either version 2 of the
|
|
|
776610 |
* License, or (at your option) any later version.
|
|
|
776610 |
*
|
|
|
776610 |
* This program is distributed in the hope that it will be useful, but
|
|
|
776610 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
776610 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
776610 |
* General Public License for more details.
|
|
|
776610 |
*
|
|
|
776610 |
* You should have received a copy of the GNU General Public License
|
|
|
776610 |
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
776610 |
*/
|
|
|
776610 |
|
|
|
776610 |
/**
|
|
|
776610 |
* SECTION:meta-shaped-texture
|
|
|
776610 |
* @title: MetaShapedTexture
|
|
|
776610 |
* @short_description: An actor to draw a masked texture.
|
|
|
776610 |
*/
|
|
|
776610 |
|
|
|
776610 |
#include <config.h>
|
|
|
776610 |
|
|
|
776610 |
#include <meta/meta-shaped-texture.h>
|
|
|
776610 |
#include "meta-shaped-texture-private.h"
|
|
|
776610 |
+#include "meta-texture-rectangle.h"
|
|
|
776610 |
|
|
|
776610 |
#include <cogl/cogl.h>
|
|
|
776610 |
#include <gdk/gdk.h> /* for gdk_rectangle_intersect() */
|
|
|
776610 |
|
|
|
776610 |
#include "clutter-utils.h"
|
|
|
776610 |
#include "meta-texture-tower.h"
|
|
|
776610 |
#include "core/boxes-private.h"
|
|
|
776610 |
|
|
|
776610 |
#include "meta-cullable.h"
|
|
|
776610 |
+#include <meta/meta-backend.h>
|
|
|
776610 |
|
|
|
776610 |
static void meta_shaped_texture_dispose (GObject *object);
|
|
|
776610 |
|
|
|
776610 |
static void meta_shaped_texture_paint (ClutterActor *actor);
|
|
|
776610 |
|
|
|
776610 |
static void meta_shaped_texture_get_preferred_width (ClutterActor *self,
|
|
|
776610 |
gfloat for_height,
|
|
|
776610 |
gfloat *min_width_p,
|
|
|
776610 |
gfloat *natural_width_p);
|
|
|
776610 |
|
|
|
776610 |
static void meta_shaped_texture_get_preferred_height (ClutterActor *self,
|
|
|
776610 |
gfloat for_width,
|
|
|
776610 |
gfloat *min_height_p,
|
|
|
776610 |
gfloat *natural_height_p);
|
|
|
776610 |
|
|
|
776610 |
static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume);
|
|
|
776610 |
|
|
|
776610 |
+static void disable_backing_store (MetaShapedTexture *stex);
|
|
|
776610 |
+
|
|
|
776610 |
static void cullable_iface_init (MetaCullableInterface *iface);
|
|
|
776610 |
|
|
|
776610 |
+static gboolean meta_debug_show_backing_store = FALSE;
|
|
|
776610 |
+
|
|
|
776610 |
G_DEFINE_TYPE_WITH_CODE (MetaShapedTexture, meta_shaped_texture, CLUTTER_TYPE_ACTOR,
|
|
|
776610 |
G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
|
|
|
776610 |
|
|
|
776610 |
#define META_SHAPED_TEXTURE_GET_PRIVATE(obj) \
|
|
|
776610 |
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_SHAPED_TEXTURE, \
|
|
|
776610 |
MetaShapedTexturePrivate))
|
|
|
776610 |
|
|
|
776610 |
enum {
|
|
|
776610 |
SIZE_CHANGED,
|
|
|
776610 |
|
|
|
776610 |
LAST_SIGNAL,
|
|
|
776610 |
};
|
|
|
776610 |
|
|
|
776610 |
static guint signals[LAST_SIGNAL];
|
|
|
776610 |
|
|
|
776610 |
+typedef struct
|
|
|
776610 |
+{
|
|
|
776610 |
+ CoglTexture *texture;
|
|
|
776610 |
+ CoglTexture *mask_texture;
|
|
|
776610 |
+ cairo_surface_t *mask_surface;
|
|
|
776610 |
+ cairo_region_t *region;
|
|
|
776610 |
+} MetaTextureBackingStore;
|
|
|
776610 |
+
|
|
|
776610 |
struct _MetaShapedTexturePrivate
|
|
|
776610 |
{
|
|
|
776610 |
MetaTextureTower *paint_tower;
|
|
|
776610 |
|
|
|
776610 |
CoglTexture *texture;
|
|
|
776610 |
CoglTexture *mask_texture;
|
|
|
776610 |
CoglSnippet *snippet;
|
|
|
776610 |
|
|
|
776610 |
CoglPipeline *base_pipeline;
|
|
|
776610 |
CoglPipeline *masked_pipeline;
|
|
|
776610 |
CoglPipeline *unblended_pipeline;
|
|
|
776610 |
|
|
|
776610 |
gboolean is_y_inverted;
|
|
|
776610 |
|
|
|
776610 |
/* The region containing only fully opaque pixels */
|
|
|
776610 |
cairo_region_t *opaque_region;
|
|
|
776610 |
|
|
|
776610 |
/* MetaCullable regions, see that documentation for more details */
|
|
|
776610 |
cairo_region_t *clip_region;
|
|
|
776610 |
cairo_region_t *unobscured_region;
|
|
|
776610 |
|
|
|
776610 |
+ /* textures get corrupted on suspend, so save them */
|
|
|
776610 |
+ cairo_surface_t *saved_base_surface;
|
|
|
776610 |
+ cairo_surface_t *saved_mask_surface;
|
|
|
776610 |
+
|
|
|
776610 |
+ /* We can't just restore external textures, so we need to track
|
|
|
776610 |
+ * which parts of the external texture are freshly drawn from
|
|
|
776610 |
+ * the client after corruption, and fill in the rest from our
|
|
|
776610 |
+ * saved snapshot */
|
|
|
776610 |
+ MetaTextureBackingStore *backing_store;
|
|
|
776610 |
+
|
|
|
776610 |
guint tex_width, tex_height;
|
|
|
776610 |
guint fallback_width, fallback_height;
|
|
|
776610 |
|
|
|
776610 |
guint create_mipmaps : 1;
|
|
|
776610 |
};
|
|
|
776610 |
|
|
|
776610 |
static void
|
|
|
776610 |
meta_shaped_texture_class_init (MetaShapedTextureClass *klass)
|
|
|
776610 |
{
|
|
|
776610 |
GObjectClass *gobject_class = (GObjectClass *) klass;
|
|
|
776610 |
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
|
|
|
776610 |
|
|
|
776610 |
gobject_class->dispose = meta_shaped_texture_dispose;
|
|
|
776610 |
|
|
|
776610 |
actor_class->get_preferred_width = meta_shaped_texture_get_preferred_width;
|
|
|
776610 |
actor_class->get_preferred_height = meta_shaped_texture_get_preferred_height;
|
|
|
776610 |
actor_class->paint = meta_shaped_texture_paint;
|
|
|
776610 |
actor_class->get_paint_volume = meta_shaped_texture_get_paint_volume;
|
|
|
776610 |
|
|
|
776610 |
signals[SIZE_CHANGED] = g_signal_new ("size-changed",
|
|
|
776610 |
G_TYPE_FROM_CLASS (gobject_class),
|
|
|
776610 |
G_SIGNAL_RUN_LAST,
|
|
|
776610 |
0,
|
|
|
776610 |
NULL, NULL, NULL,
|
|
|
776610 |
G_TYPE_NONE, 0);
|
|
|
776610 |
|
|
|
776610 |
g_type_class_add_private (klass, sizeof (MetaShapedTexturePrivate));
|
|
|
776610 |
+
|
|
|
776610 |
+ if (g_getenv ("MUTTER_DEBUG_BACKING_STORE"))
|
|
|
776610 |
+ meta_debug_show_backing_store = TRUE;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
static void
|
|
|
776610 |
meta_shaped_texture_init (MetaShapedTexture *self)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv;
|
|
|
776610 |
+ MetaBackend *backend = meta_get_backend ();
|
|
|
776610 |
+ ClutterBackend *clutter_backend = clutter_get_default_backend ();
|
|
|
776610 |
+ CoglContext *cogl_context =
|
|
|
776610 |
+ clutter_backend_get_cogl_context (clutter_backend);
|
|
|
776610 |
|
|
|
776610 |
priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
|
|
|
776610 |
|
|
|
776610 |
priv->paint_tower = meta_texture_tower_new ();
|
|
|
776610 |
|
|
|
776610 |
priv->texture = NULL;
|
|
|
776610 |
priv->mask_texture = NULL;
|
|
|
776610 |
priv->create_mipmaps = TRUE;
|
|
|
776610 |
priv->is_y_inverted = TRUE;
|
|
|
776610 |
+
|
|
|
776610 |
+ if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_UNSTABLE_TEXTURES))
|
|
|
776610 |
+ {
|
|
|
776610 |
+ g_signal_connect_object (backend, "suspending", G_CALLBACK (meta_shaped_texture_save), self, G_CONNECT_SWAPPED);
|
|
|
776610 |
+ g_signal_connect_object (backend, "resuming", G_CALLBACK (meta_shaped_texture_restore), self, G_CONNECT_SWAPPED);
|
|
|
776610 |
+ }
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
static void
|
|
|
776610 |
set_unobscured_region (MetaShapedTexture *self,
|
|
|
776610 |
cairo_region_t *unobscured_region)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv = self->priv;
|
|
|
776610 |
|
|
|
776610 |
g_clear_pointer (&priv->unobscured_region, (GDestroyNotify) cairo_region_destroy);
|
|
|
776610 |
if (unobscured_region)
|
|
|
776610 |
{
|
|
|
776610 |
guint width, height;
|
|
|
776610 |
|
|
|
776610 |
if (priv->texture)
|
|
|
776610 |
{
|
|
|
776610 |
width = priv->tex_width;
|
|
|
776610 |
height = priv->tex_height;
|
|
|
776610 |
}
|
|
|
776610 |
else
|
|
|
776610 |
{
|
|
|
776610 |
width = priv->fallback_width;
|
|
|
776610 |
height = priv->fallback_height;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
cairo_rectangle_int_t bounds = { 0, 0, width, height };
|
|
|
776610 |
priv->unobscured_region = cairo_region_copy (unobscured_region);
|
|
|
776610 |
cairo_region_intersect_rectangle (priv->unobscured_region, &bounds);
|
|
|
776610 |
}
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
@@ -183,116 +220,183 @@ meta_shaped_texture_reset_pipelines (MetaShapedTexture *stex)
|
|
|
776610 |
|
|
|
776610 |
g_clear_pointer (&priv->base_pipeline, cogl_object_unref);
|
|
|
776610 |
g_clear_pointer (&priv->masked_pipeline, cogl_object_unref);
|
|
|
776610 |
g_clear_pointer (&priv->unblended_pipeline, cogl_object_unref);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
static void
|
|
|
776610 |
meta_shaped_texture_dispose (GObject *object)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexture *self = (MetaShapedTexture *) object;
|
|
|
776610 |
MetaShapedTexturePrivate *priv = self->priv;
|
|
|
776610 |
|
|
|
776610 |
if (priv->paint_tower)
|
|
|
776610 |
meta_texture_tower_free (priv->paint_tower);
|
|
|
776610 |
priv->paint_tower = NULL;
|
|
|
776610 |
|
|
|
776610 |
g_clear_pointer (&priv->texture, cogl_object_unref);
|
|
|
776610 |
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
|
|
|
776610 |
|
|
|
776610 |
meta_shaped_texture_set_mask_texture (self, NULL);
|
|
|
776610 |
set_unobscured_region (self, NULL);
|
|
|
776610 |
set_clip_region (self, NULL);
|
|
|
776610 |
|
|
|
776610 |
meta_shaped_texture_reset_pipelines (self);
|
|
|
776610 |
|
|
|
776610 |
g_clear_pointer (&priv->snippet, cogl_object_unref);
|
|
|
776610 |
|
|
|
776610 |
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
+static int
|
|
|
776610 |
+get_layer_indices (MetaShapedTexture *stex,
|
|
|
776610 |
+ int *main_layer_index,
|
|
|
776610 |
+ int *backing_mask_layer_index,
|
|
|
776610 |
+ int *backing_layer_index,
|
|
|
776610 |
+ int *mask_layer_index)
|
|
|
776610 |
+{
|
|
|
776610 |
+ MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
+ int next_layer_index = 0;
|
|
|
776610 |
+
|
|
|
776610 |
+ if (main_layer_index)
|
|
|
776610 |
+ *main_layer_index = next_layer_index;
|
|
|
776610 |
+
|
|
|
776610 |
+ next_layer_index++;
|
|
|
776610 |
+
|
|
|
776610 |
+ if (priv->backing_store)
|
|
|
776610 |
+ {
|
|
|
776610 |
+ if (backing_mask_layer_index)
|
|
|
776610 |
+ *backing_mask_layer_index = next_layer_index;
|
|
|
776610 |
+ next_layer_index++;
|
|
|
776610 |
+ if (backing_layer_index)
|
|
|
776610 |
+ *backing_layer_index = next_layer_index;
|
|
|
776610 |
+ next_layer_index++;
|
|
|
776610 |
+ }
|
|
|
776610 |
+ else
|
|
|
776610 |
+ {
|
|
|
776610 |
+ if (backing_mask_layer_index)
|
|
|
776610 |
+ *backing_mask_layer_index = -1;
|
|
|
776610 |
+ if (backing_layer_index)
|
|
|
776610 |
+ *backing_layer_index = -1;
|
|
|
776610 |
+ }
|
|
|
776610 |
+
|
|
|
776610 |
+ if (mask_layer_index)
|
|
|
776610 |
+ *mask_layer_index = next_layer_index;
|
|
|
776610 |
+
|
|
|
776610 |
+ return next_layer_index;
|
|
|
776610 |
+}
|
|
|
776610 |
+
|
|
|
776610 |
static CoglPipeline *
|
|
|
776610 |
get_base_pipeline (MetaShapedTexture *stex,
|
|
|
776610 |
CoglContext *ctx)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
CoglPipeline *pipeline;
|
|
|
776610 |
+ int main_layer_index;
|
|
|
776610 |
+ int backing_layer_index;
|
|
|
776610 |
+ int backing_mask_layer_index;
|
|
|
776610 |
+ int i, number_of_layers;
|
|
|
776610 |
|
|
|
776610 |
if (priv->base_pipeline)
|
|
|
776610 |
return priv->base_pipeline;
|
|
|
776610 |
|
|
|
776610 |
pipeline = cogl_pipeline_new (ctx);
|
|
|
776610 |
- cogl_pipeline_set_layer_wrap_mode_s (pipeline, 0,
|
|
|
776610 |
- COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
|
|
776610 |
- cogl_pipeline_set_layer_wrap_mode_t (pipeline, 0,
|
|
|
776610 |
- COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
|
|
776610 |
- cogl_pipeline_set_layer_wrap_mode_s (pipeline, 1,
|
|
|
776610 |
- COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
|
|
776610 |
- cogl_pipeline_set_layer_wrap_mode_t (pipeline, 1,
|
|
|
776610 |
- COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
|
|
776610 |
+
|
|
|
776610 |
+ number_of_layers = get_layer_indices (stex,
|
|
|
776610 |
+ &main_layer_index,
|
|
|
776610 |
+ &backing_mask_layer_index,
|
|
|
776610 |
+ &backing_layer_index,
|
|
|
776610 |
+ NULL);
|
|
|
776610 |
+
|
|
|
776610 |
+ for (i = 0; i < number_of_layers; i++)
|
|
|
776610 |
+ {
|
|
|
776610 |
+ cogl_pipeline_set_layer_wrap_mode_s (pipeline, i,
|
|
|
776610 |
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
|
|
776610 |
+ cogl_pipeline_set_layer_wrap_mode_t (pipeline, i,
|
|
|
776610 |
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
|
|
776610 |
+ }
|
|
|
776610 |
+
|
|
|
776610 |
if (!priv->is_y_inverted)
|
|
|
776610 |
{
|
|
|
776610 |
CoglMatrix matrix;
|
|
|
776610 |
|
|
|
776610 |
cogl_matrix_init_identity (&matrix);
|
|
|
776610 |
cogl_matrix_scale (&matrix, 1, -1, 1);
|
|
|
776610 |
cogl_matrix_translate (&matrix, 0, -1, 0);
|
|
|
776610 |
- cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
|
|
|
776610 |
+ cogl_pipeline_set_layer_matrix (pipeline, main_layer_index, &matrix);
|
|
|
776610 |
+ }
|
|
|
776610 |
+
|
|
|
776610 |
+ if (priv->backing_store)
|
|
|
776610 |
+ {
|
|
|
776610 |
+ g_autofree char *backing_description = NULL;
|
|
|
776610 |
+ cogl_pipeline_set_layer_combine (pipeline, backing_mask_layer_index,
|
|
|
776610 |
+ "RGBA = REPLACE(PREVIOUS)",
|
|
|
776610 |
+ NULL);
|
|
|
776610 |
+ backing_description = g_strdup_printf ("RGBA = INTERPOLATE(PREVIOUS, TEXTURE_%d, TEXTURE_%d[A])",
|
|
|
776610 |
+ backing_layer_index,
|
|
|
776610 |
+ backing_mask_layer_index);
|
|
|
776610 |
+ cogl_pipeline_set_layer_combine (pipeline,
|
|
|
776610 |
+ backing_layer_index,
|
|
|
776610 |
+ backing_description,
|
|
|
776610 |
+ NULL);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
if (priv->snippet)
|
|
|
776610 |
- cogl_pipeline_add_layer_snippet (pipeline, 0, priv->snippet);
|
|
|
776610 |
+ cogl_pipeline_add_layer_snippet (pipeline, main_layer_index, priv->snippet);
|
|
|
776610 |
|
|
|
776610 |
priv->base_pipeline = pipeline;
|
|
|
776610 |
|
|
|
776610 |
return priv->base_pipeline;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
static CoglPipeline *
|
|
|
776610 |
get_unmasked_pipeline (MetaShapedTexture *stex,
|
|
|
776610 |
CoglContext *ctx)
|
|
|
776610 |
{
|
|
|
776610 |
return get_base_pipeline (stex, ctx);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
static CoglPipeline *
|
|
|
776610 |
get_masked_pipeline (MetaShapedTexture *stex,
|
|
|
776610 |
CoglContext *ctx)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
CoglPipeline *pipeline;
|
|
|
776610 |
+ int mask_layer_index;
|
|
|
776610 |
|
|
|
776610 |
if (priv->masked_pipeline)
|
|
|
776610 |
return priv->masked_pipeline;
|
|
|
776610 |
|
|
|
776610 |
+ get_layer_indices (stex, NULL, NULL, NULL, &mask_layer_index);
|
|
|
776610 |
+
|
|
|
776610 |
pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx));
|
|
|
776610 |
- cogl_pipeline_set_layer_combine (pipeline, 1,
|
|
|
776610 |
+ cogl_pipeline_set_layer_combine (pipeline, mask_layer_index,
|
|
|
776610 |
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
|
|
|
776610 |
NULL);
|
|
|
776610 |
|
|
|
776610 |
priv->masked_pipeline = pipeline;
|
|
|
776610 |
|
|
|
776610 |
return pipeline;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
static CoglPipeline *
|
|
|
776610 |
get_unblended_pipeline (MetaShapedTexture *stex,
|
|
|
776610 |
CoglContext *ctx)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
CoglPipeline *pipeline;
|
|
|
776610 |
CoglColor color;
|
|
|
776610 |
|
|
|
776610 |
if (priv->unblended_pipeline)
|
|
|
776610 |
return priv->unblended_pipeline;
|
|
|
776610 |
|
|
|
776610 |
pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx));
|
|
|
776610 |
cogl_color_init_from_4ub (&color, 255, 255, 255, 255);
|
|
|
776610 |
cogl_pipeline_set_blend (pipeline,
|
|
|
776610 |
"RGBA = ADD (SRC_COLOR, 0)",
|
|
|
776610 |
NULL);
|
|
|
776610 |
cogl_pipeline_set_color (pipeline, &color;;
|
|
|
776610 |
|
|
|
776610 |
priv->unblended_pipeline = pipeline;
|
|
|
776610 |
|
|
|
776610 |
return pipeline;
|
|
|
776610 |
}
|
|
|
776610 |
@@ -313,105 +417,111 @@ paint_clipped_rectangle (CoglFramebuffer *fb,
|
|
|
776610 |
|
|
|
776610 |
coords[0] = rect->x / (alloc->x2 - alloc->x1);
|
|
|
776610 |
coords[1] = rect->y / (alloc->y2 - alloc->y1);
|
|
|
776610 |
coords[2] = (rect->x + rect->width) / (alloc->x2 - alloc->x1);
|
|
|
776610 |
coords[3] = (rect->y + rect->height) / (alloc->y2 - alloc->y1);
|
|
|
776610 |
|
|
|
776610 |
coords[4] = coords[0];
|
|
|
776610 |
coords[5] = coords[1];
|
|
|
776610 |
coords[6] = coords[2];
|
|
|
776610 |
coords[7] = coords[3];
|
|
|
776610 |
|
|
|
776610 |
cogl_framebuffer_draw_multitextured_rectangle (fb, pipeline,
|
|
|
776610 |
x1, y1, x2, y2,
|
|
|
776610 |
&coords[0], 8);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
static void
|
|
|
776610 |
set_cogl_texture (MetaShapedTexture *stex,
|
|
|
776610 |
CoglTexture *cogl_tex)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv;
|
|
|
776610 |
guint width, height;
|
|
|
776610 |
|
|
|
776610 |
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
|
|
776610 |
|
|
|
776610 |
priv = stex->priv;
|
|
|
776610 |
|
|
|
776610 |
if (priv->texture)
|
|
|
776610 |
cogl_object_unref (priv->texture);
|
|
|
776610 |
|
|
|
776610 |
+ g_clear_pointer (&priv->saved_base_surface, cairo_surface_destroy);
|
|
|
776610 |
+
|
|
|
776610 |
priv->texture = cogl_tex;
|
|
|
776610 |
|
|
|
776610 |
if (cogl_tex != NULL)
|
|
|
776610 |
{
|
|
|
776610 |
cogl_object_ref (cogl_tex);
|
|
|
776610 |
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
|
|
|
776610 |
height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
|
|
|
776610 |
}
|
|
|
776610 |
else
|
|
|
776610 |
{
|
|
|
776610 |
width = 0;
|
|
|
776610 |
height = 0;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
if (priv->tex_width != width ||
|
|
|
776610 |
priv->tex_height != height)
|
|
|
776610 |
{
|
|
|
776610 |
priv->tex_width = width;
|
|
|
776610 |
priv->tex_height = height;
|
|
|
776610 |
meta_shaped_texture_set_mask_texture (stex, NULL);
|
|
|
776610 |
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
|
|
776610 |
g_signal_emit (stex, signals[SIZE_CHANGED], 0);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
/* NB: We don't queue a redraw of the actor here because we don't
|
|
|
776610 |
* know how much of the buffer has changed with respect to the
|
|
|
776610 |
* previous buffer. We only queue a redraw in response to surface
|
|
|
776610 |
* damage. */
|
|
|
776610 |
|
|
|
776610 |
if (priv->create_mipmaps)
|
|
|
776610 |
meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
static void
|
|
|
776610 |
do_paint (MetaShapedTexture *stex,
|
|
|
776610 |
CoglFramebuffer *fb,
|
|
|
776610 |
CoglTexture *paint_tex,
|
|
|
776610 |
cairo_region_t *clip_region)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
guint tex_width, tex_height;
|
|
|
776610 |
guchar opacity;
|
|
|
776610 |
CoglContext *ctx;
|
|
|
776610 |
ClutterActorBox alloc;
|
|
|
776610 |
CoglPipelineFilter filter;
|
|
|
776610 |
+ int main_layer_index;
|
|
|
776610 |
+ int backing_mask_layer_index;
|
|
|
776610 |
+ int backing_layer_index;
|
|
|
776610 |
+ int mask_layer_index;
|
|
|
776610 |
|
|
|
776610 |
tex_width = priv->tex_width;
|
|
|
776610 |
tex_height = priv->tex_height;
|
|
|
776610 |
|
|
|
776610 |
if (tex_width == 0 || tex_height == 0) /* no contents yet */
|
|
|
776610 |
return;
|
|
|
776610 |
|
|
|
776610 |
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
|
|
|
776610 |
|
|
|
776610 |
/* Use nearest-pixel interpolation if the texture is unscaled. This
|
|
|
776610 |
* improves performance, especially with software rendering.
|
|
|
776610 |
*/
|
|
|
776610 |
|
|
|
776610 |
filter = COGL_PIPELINE_FILTER_LINEAR;
|
|
|
776610 |
|
|
|
776610 |
if (meta_actor_painting_untransformed (fb,
|
|
|
776610 |
tex_width, tex_height,
|
|
|
776610 |
NULL, NULL))
|
|
|
776610 |
filter = COGL_PIPELINE_FILTER_NEAREST;
|
|
|
776610 |
|
|
|
776610 |
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
|
|
776610 |
|
|
|
776610 |
opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (stex));
|
|
|
776610 |
clutter_actor_get_allocation_box (CLUTTER_ACTOR (stex), &alloc);
|
|
|
776610 |
|
|
|
776610 |
cairo_region_t *blended_region;
|
|
|
776610 |
gboolean use_opaque_region = (priv->opaque_region != NULL && opacity == 255);
|
|
|
776610 |
|
|
|
776610 |
if (use_opaque_region)
|
|
|
776610 |
{
|
|
|
776610 |
@@ -420,123 +530,161 @@ do_paint (MetaShapedTexture *stex,
|
|
|
776610 |
else
|
|
|
776610 |
blended_region = cairo_region_create_rectangle (&tex_rect);
|
|
|
776610 |
|
|
|
776610 |
cairo_region_subtract (blended_region, priv->opaque_region);
|
|
|
776610 |
}
|
|
|
776610 |
else
|
|
|
776610 |
{
|
|
|
776610 |
if (priv->clip_region != NULL)
|
|
|
776610 |
blended_region = cairo_region_reference (priv->clip_region);
|
|
|
776610 |
else
|
|
|
776610 |
blended_region = NULL;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
/* Limit to how many separate rectangles we'll draw; beyond this just
|
|
|
776610 |
* fall back and draw the whole thing */
|
|
|
776610 |
#define MAX_RECTS 16
|
|
|
776610 |
|
|
|
776610 |
if (blended_region != NULL)
|
|
|
776610 |
{
|
|
|
776610 |
int n_rects = cairo_region_num_rectangles (blended_region);
|
|
|
776610 |
if (n_rects > MAX_RECTS)
|
|
|
776610 |
{
|
|
|
776610 |
/* Fall back to taking the fully blended path. */
|
|
|
776610 |
use_opaque_region = FALSE;
|
|
|
776610 |
|
|
|
776610 |
cairo_region_destroy (blended_region);
|
|
|
776610 |
blended_region = NULL;
|
|
|
776610 |
}
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
+ get_layer_indices (stex,
|
|
|
776610 |
+ &main_layer_index,
|
|
|
776610 |
+ &backing_mask_layer_index,
|
|
|
776610 |
+ &backing_layer_index,
|
|
|
776610 |
+ &mask_layer_index);
|
|
|
776610 |
+
|
|
|
776610 |
/* First, paint the unblended parts, which are part of the opaque region. */
|
|
|
776610 |
if (use_opaque_region)
|
|
|
776610 |
{
|
|
|
776610 |
CoglPipeline *opaque_pipeline;
|
|
|
776610 |
cairo_region_t *region;
|
|
|
776610 |
int n_rects;
|
|
|
776610 |
int i;
|
|
|
776610 |
|
|
|
776610 |
if (priv->clip_region != NULL)
|
|
|
776610 |
{
|
|
|
776610 |
region = cairo_region_copy (priv->clip_region);
|
|
|
776610 |
cairo_region_intersect (region, priv->opaque_region);
|
|
|
776610 |
}
|
|
|
776610 |
else
|
|
|
776610 |
{
|
|
|
776610 |
region = cairo_region_reference (priv->opaque_region);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
if (!cairo_region_is_empty (region))
|
|
|
776610 |
{
|
|
|
776610 |
opaque_pipeline = get_unblended_pipeline (stex, ctx);
|
|
|
776610 |
- cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex);
|
|
|
776610 |
- cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter);
|
|
|
776610 |
+ cogl_pipeline_set_layer_texture (opaque_pipeline, main_layer_index, paint_tex);
|
|
|
776610 |
+ cogl_pipeline_set_layer_filters (opaque_pipeline, main_layer_index, filter, filter);
|
|
|
776610 |
+
|
|
|
776610 |
+ if (priv->backing_store)
|
|
|
776610 |
+ {
|
|
|
776610 |
+ cogl_pipeline_set_layer_texture (opaque_pipeline,
|
|
|
776610 |
+ backing_mask_layer_index,
|
|
|
776610 |
+ priv->backing_store->mask_texture);
|
|
|
776610 |
+ cogl_pipeline_set_layer_filters (opaque_pipeline,
|
|
|
776610 |
+ backing_mask_layer_index,
|
|
|
776610 |
+ filter, filter);
|
|
|
776610 |
+ cogl_pipeline_set_layer_texture (opaque_pipeline,
|
|
|
776610 |
+ backing_layer_index,
|
|
|
776610 |
+ priv->backing_store->texture);
|
|
|
776610 |
+ cogl_pipeline_set_layer_filters (opaque_pipeline,
|
|
|
776610 |
+ backing_layer_index,
|
|
|
776610 |
+ filter, filter);
|
|
|
776610 |
+ }
|
|
|
776610 |
|
|
|
776610 |
n_rects = cairo_region_num_rectangles (region);
|
|
|
776610 |
for (i = 0; i < n_rects; i++)
|
|
|
776610 |
{
|
|
|
776610 |
cairo_rectangle_int_t rect;
|
|
|
776610 |
cairo_region_get_rectangle (region, i, &rect);
|
|
|
776610 |
paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc);
|
|
|
776610 |
}
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
cairo_region_destroy (region);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
/* Now, go ahead and paint the blended parts. */
|
|
|
776610 |
|
|
|
776610 |
/* We have three cases:
|
|
|
776610 |
* 1) blended_region has rectangles - paint the rectangles.
|
|
|
776610 |
* 2) blended_region is empty - don't paint anything
|
|
|
776610 |
* 3) blended_region is NULL - paint fully-blended.
|
|
|
776610 |
*
|
|
|
776610 |
* 1) and 3) are the times where we have to paint stuff. This tests
|
|
|
776610 |
* for 1) and 3).
|
|
|
776610 |
*/
|
|
|
776610 |
if (blended_region == NULL || !cairo_region_is_empty (blended_region))
|
|
|
776610 |
{
|
|
|
776610 |
CoglPipeline *blended_pipeline;
|
|
|
776610 |
|
|
|
776610 |
if (priv->mask_texture == NULL)
|
|
|
776610 |
{
|
|
|
776610 |
blended_pipeline = get_unmasked_pipeline (stex, ctx);
|
|
|
776610 |
}
|
|
|
776610 |
else
|
|
|
776610 |
{
|
|
|
776610 |
blended_pipeline = get_masked_pipeline (stex, ctx);
|
|
|
776610 |
- cogl_pipeline_set_layer_texture (blended_pipeline, 1, priv->mask_texture);
|
|
|
776610 |
- cogl_pipeline_set_layer_filters (blended_pipeline, 1, filter, filter);
|
|
|
776610 |
+ cogl_pipeline_set_layer_texture (blended_pipeline, mask_layer_index, priv->mask_texture);
|
|
|
776610 |
+ cogl_pipeline_set_layer_filters (blended_pipeline, mask_layer_index, filter, filter);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
- cogl_pipeline_set_layer_texture (blended_pipeline, 0, paint_tex);
|
|
|
776610 |
- cogl_pipeline_set_layer_filters (blended_pipeline, 0, filter, filter);
|
|
|
776610 |
+ cogl_pipeline_set_layer_texture (blended_pipeline, main_layer_index, paint_tex);
|
|
|
776610 |
+ cogl_pipeline_set_layer_filters (blended_pipeline, main_layer_index, filter, filter);
|
|
|
776610 |
+
|
|
|
776610 |
+ if (priv->backing_store)
|
|
|
776610 |
+ {
|
|
|
776610 |
+ cogl_pipeline_set_layer_texture (blended_pipeline,
|
|
|
776610 |
+ backing_mask_layer_index,
|
|
|
776610 |
+ priv->backing_store->mask_texture);
|
|
|
776610 |
+ cogl_pipeline_set_layer_filters (blended_pipeline,
|
|
|
776610 |
+ backing_mask_layer_index,
|
|
|
776610 |
+ filter, filter);
|
|
|
776610 |
+ cogl_pipeline_set_layer_texture (blended_pipeline,
|
|
|
776610 |
+ backing_layer_index,
|
|
|
776610 |
+ priv->backing_store->texture);
|
|
|
776610 |
+ cogl_pipeline_set_layer_filters (blended_pipeline,
|
|
|
776610 |
+ backing_layer_index,
|
|
|
776610 |
+ filter, filter);
|
|
|
776610 |
+ }
|
|
|
776610 |
|
|
|
776610 |
CoglColor color;
|
|
|
776610 |
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
|
|
|
776610 |
cogl_pipeline_set_color (blended_pipeline, &color;;
|
|
|
776610 |
|
|
|
776610 |
if (blended_region != NULL)
|
|
|
776610 |
{
|
|
|
776610 |
/* 1) blended_region is not empty. Paint the rectangles. */
|
|
|
776610 |
int i;
|
|
|
776610 |
int n_rects = cairo_region_num_rectangles (blended_region);
|
|
|
776610 |
|
|
|
776610 |
for (i = 0; i < n_rects; i++)
|
|
|
776610 |
{
|
|
|
776610 |
cairo_rectangle_int_t rect;
|
|
|
776610 |
cairo_region_get_rectangle (blended_region, i, &rect);
|
|
|
776610 |
|
|
|
776610 |
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
|
|
|
776610 |
continue;
|
|
|
776610 |
|
|
|
776610 |
paint_clipped_rectangle (fb, blended_pipeline, &rect, &alloc);
|
|
|
776610 |
}
|
|
|
776610 |
}
|
|
|
776610 |
else
|
|
|
776610 |
{
|
|
|
776610 |
/* 3) blended_region is NULL. Do a full paint. */
|
|
|
776610 |
cogl_framebuffer_draw_rectangle (fb, blended_pipeline,
|
|
|
776610 |
0, 0,
|
|
|
776610 |
alloc.x2 - alloc.x1,
|
|
|
776610 |
alloc.y2 - alloc.y1);
|
|
|
776610 |
}
|
|
|
776610 |
@@ -698,110 +846,173 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
|
|
|
776610 |
gboolean create_mipmaps)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv;
|
|
|
776610 |
|
|
|
776610 |
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
|
|
776610 |
|
|
|
776610 |
priv = stex->priv;
|
|
|
776610 |
|
|
|
776610 |
create_mipmaps = create_mipmaps != FALSE;
|
|
|
776610 |
|
|
|
776610 |
if (create_mipmaps != priv->create_mipmaps)
|
|
|
776610 |
{
|
|
|
776610 |
CoglTexture *base_texture;
|
|
|
776610 |
priv->create_mipmaps = create_mipmaps;
|
|
|
776610 |
base_texture = create_mipmaps ? priv->texture : NULL;
|
|
|
776610 |
meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
|
|
|
776610 |
}
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
void
|
|
|
776610 |
meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
|
|
|
776610 |
CoglTexture *mask_texture)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv;
|
|
|
776610 |
|
|
|
776610 |
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
|
|
776610 |
|
|
|
776610 |
priv = stex->priv;
|
|
|
776610 |
|
|
|
776610 |
g_clear_pointer (&priv->mask_texture, cogl_object_unref);
|
|
|
776610 |
+ g_clear_pointer (&priv->saved_mask_surface, cairo_surface_destroy);
|
|
|
776610 |
|
|
|
776610 |
if (mask_texture != NULL)
|
|
|
776610 |
{
|
|
|
776610 |
priv->mask_texture = mask_texture;
|
|
|
776610 |
cogl_object_ref (priv->mask_texture);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
gboolean
|
|
|
776610 |
meta_shaped_texture_is_obscured (MetaShapedTexture *self)
|
|
|
776610 |
{
|
|
|
776610 |
cairo_region_t *unobscured_region = effective_unobscured_region (self);
|
|
|
776610 |
|
|
|
776610 |
if (unobscured_region)
|
|
|
776610 |
return cairo_region_is_empty (unobscured_region);
|
|
|
776610 |
else
|
|
|
776610 |
return FALSE;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
+static void
|
|
|
776610 |
+meta_texture_backing_store_redraw_mask (MetaTextureBackingStore *backing_store)
|
|
|
776610 |
+{
|
|
|
776610 |
+ CoglError *error = NULL;
|
|
|
776610 |
+
|
|
|
776610 |
+ if (!cogl_texture_set_data (backing_store->mask_texture, COGL_PIXEL_FORMAT_A_8,
|
|
|
776610 |
+ cairo_image_surface_get_stride (backing_store->mask_surface),
|
|
|
776610 |
+ cairo_image_surface_get_data (backing_store->mask_surface), 0,
|
|
|
776610 |
+ &error))
|
|
|
776610 |
+ {
|
|
|
776610 |
+
|
|
|
776610 |
+ g_warning ("Failed to update backing mask texture");
|
|
|
776610 |
+ g_clear_pointer (&error, cogl_error_free);
|
|
|
776610 |
+ }
|
|
|
776610 |
+}
|
|
|
776610 |
+
|
|
|
776610 |
+static gboolean
|
|
|
776610 |
+meta_texture_backing_store_shrink (MetaTextureBackingStore *backing_store,
|
|
|
776610 |
+ const cairo_rectangle_int_t *area)
|
|
|
776610 |
+{
|
|
|
776610 |
+ cairo_t *cr;
|
|
|
776610 |
+
|
|
|
776610 |
+ cairo_region_subtract_rectangle (backing_store->region, area);
|
|
|
776610 |
+
|
|
|
776610 |
+ /* If the client has finally redrawn the entire surface, we can
|
|
|
776610 |
+ * ditch our snapshot
|
|
|
776610 |
+ */
|
|
|
776610 |
+ if (cairo_region_is_empty (backing_store->region))
|
|
|
776610 |
+ return FALSE;
|
|
|
776610 |
+
|
|
|
776610 |
+ cr = cairo_create (backing_store->mask_surface);
|
|
|
776610 |
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
|
|
776610 |
+ cairo_paint (cr);
|
|
|
776610 |
+ gdk_cairo_region (cr, backing_store->region);
|
|
|
776610 |
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
|
|
776610 |
+ cairo_fill (cr);
|
|
|
776610 |
+ cairo_destroy (cr);
|
|
|
776610 |
+
|
|
|
776610 |
+ meta_texture_backing_store_redraw_mask (backing_store);
|
|
|
776610 |
+
|
|
|
776610 |
+ return TRUE;
|
|
|
776610 |
+}
|
|
|
776610 |
+
|
|
|
776610 |
+static void
|
|
|
776610 |
+shrink_backing_region (MetaShapedTexture *stex,
|
|
|
776610 |
+ const cairo_rectangle_int_t *area)
|
|
|
776610 |
+{
|
|
|
776610 |
+ MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
+ gboolean still_backing_texture;
|
|
|
776610 |
+
|
|
|
776610 |
+ if (!priv->backing_store)
|
|
|
776610 |
+ return;
|
|
|
776610 |
+
|
|
|
776610 |
+ still_backing_texture =
|
|
|
776610 |
+ meta_texture_backing_store_shrink (priv->backing_store, area);
|
|
|
776610 |
+
|
|
|
776610 |
+ if (!still_backing_texture)
|
|
|
776610 |
+ disable_backing_store (stex);
|
|
|
776610 |
+}
|
|
|
776610 |
+
|
|
|
776610 |
/**
|
|
|
776610 |
* meta_shaped_texture_update_area:
|
|
|
776610 |
* @stex: #MetaShapedTexture
|
|
|
776610 |
* @x: the x coordinate of the damaged area
|
|
|
776610 |
* @y: the y coordinate of the damaged area
|
|
|
776610 |
* @width: the width of the damaged area
|
|
|
776610 |
* @height: the height of the damaged area
|
|
|
776610 |
*
|
|
|
776610 |
* Repairs the damaged area indicated by @x, @y, @width and @height
|
|
|
776610 |
* and potentially queues a redraw.
|
|
|
776610 |
*
|
|
|
776610 |
* Return value: Whether a redraw have been queued or not
|
|
|
776610 |
*/
|
|
|
776610 |
gboolean
|
|
|
776610 |
meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
|
|
776610 |
int x,
|
|
|
776610 |
int y,
|
|
|
776610 |
int width,
|
|
|
776610 |
int height)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv;
|
|
|
776610 |
cairo_region_t *unobscured_region;
|
|
|
776610 |
const cairo_rectangle_int_t clip = { x, y, width, height };
|
|
|
776610 |
|
|
|
776610 |
priv = stex->priv;
|
|
|
776610 |
|
|
|
776610 |
if (priv->texture == NULL)
|
|
|
776610 |
return FALSE;
|
|
|
776610 |
|
|
|
776610 |
+ shrink_backing_region (stex, &clip);
|
|
|
776610 |
+
|
|
|
776610 |
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
|
|
|
776610 |
|
|
|
776610 |
unobscured_region = effective_unobscured_region (stex);
|
|
|
776610 |
if (unobscured_region)
|
|
|
776610 |
{
|
|
|
776610 |
cairo_region_t *intersection;
|
|
|
776610 |
|
|
|
776610 |
if (cairo_region_is_empty (unobscured_region))
|
|
|
776610 |
return FALSE;
|
|
|
776610 |
|
|
|
776610 |
intersection = cairo_region_copy (unobscured_region);
|
|
|
776610 |
cairo_region_intersect_rectangle (intersection, &clip);
|
|
|
776610 |
|
|
|
776610 |
if (!cairo_region_is_empty (intersection))
|
|
|
776610 |
{
|
|
|
776610 |
cairo_rectangle_int_t damage_rect;
|
|
|
776610 |
cairo_region_get_extents (intersection, &damage_rect);
|
|
|
776610 |
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &damage_rect);
|
|
|
776610 |
cairo_region_destroy (intersection);
|
|
|
776610 |
return TRUE;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
cairo_region_destroy (intersection);
|
|
|
776610 |
return FALSE;
|
|
|
776610 |
}
|
|
|
776610 |
else
|
|
|
776610 |
{
|
|
|
776610 |
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
|
|
|
776610 |
return TRUE;
|
|
|
776610 |
}
|
|
|
776610 |
@@ -892,62 +1103,63 @@ meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
|
|
|
776610 |
priv = stex->priv;
|
|
|
776610 |
|
|
|
776610 |
if (priv->opaque_region)
|
|
|
776610 |
cairo_region_destroy (priv->opaque_region);
|
|
|
776610 |
|
|
|
776610 |
if (opaque_region)
|
|
|
776610 |
priv->opaque_region = cairo_region_reference (opaque_region);
|
|
|
776610 |
else
|
|
|
776610 |
priv->opaque_region = NULL;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
cairo_region_t *
|
|
|
776610 |
meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
return priv->opaque_region;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
static gboolean
|
|
|
776610 |
should_get_via_offscreen (MetaShapedTexture *stex)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
|
|
|
776610 |
if (!cogl_texture_is_get_data_supported (priv->texture))
|
|
|
776610 |
return TRUE;
|
|
|
776610 |
|
|
|
776610 |
return FALSE;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
static cairo_surface_t *
|
|
|
776610 |
-get_image_via_offscreen (MetaShapedTexture *stex,
|
|
|
776610 |
- cairo_rectangle_int_t *clip)
|
|
|
776610 |
+get_image_via_offscreen (MetaShapedTexture *stex,
|
|
|
776610 |
+ cairo_rectangle_int_t *clip,
|
|
|
776610 |
+ CoglTexture **texture)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
ClutterBackend *clutter_backend = clutter_get_default_backend ();
|
|
|
776610 |
CoglContext *cogl_context =
|
|
|
776610 |
clutter_backend_get_cogl_context (clutter_backend);
|
|
|
776610 |
CoglTexture *image_texture;
|
|
|
776610 |
GError *error = NULL;
|
|
|
776610 |
CoglOffscreen *offscreen;
|
|
|
776610 |
CoglFramebuffer *fb;
|
|
|
776610 |
CoglMatrix projection_matrix;
|
|
|
776610 |
unsigned int fb_width, fb_height;
|
|
|
776610 |
cairo_rectangle_int_t fallback_clip;
|
|
|
776610 |
CoglColor clear_color;
|
|
|
776610 |
cairo_surface_t *surface;
|
|
|
776610 |
|
|
|
776610 |
if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_TEXTURE_NPOT))
|
|
|
776610 |
{
|
|
|
776610 |
fb_width = priv->tex_width;
|
|
|
776610 |
fb_height = priv->tex_height;
|
|
|
776610 |
}
|
|
|
776610 |
else
|
|
|
776610 |
{
|
|
|
776610 |
fb_width = clutter_util_next_p2 (priv->tex_width);
|
|
|
776610 |
fb_height = clutter_util_next_p2 (priv->tex_height);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
if (!clip)
|
|
|
776610 |
{
|
|
|
776610 |
fallback_clip = (cairo_rectangle_int_t) {
|
|
|
776610 |
.width = priv->tex_width,
|
|
|
776610 |
@@ -988,184 +1200,424 @@ get_image_via_offscreen (MetaShapedTexture *stex,
|
|
|
776610 |
g_error_free (error);
|
|
|
776610 |
cogl_object_unref (fb);
|
|
|
776610 |
return FALSE;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
cogl_framebuffer_push_matrix (fb);
|
|
|
776610 |
cogl_matrix_init_identity (&projection_matrix);
|
|
|
776610 |
cogl_matrix_scale (&projection_matrix,
|
|
|
776610 |
1.0 / (priv->tex_width / 2.0),
|
|
|
776610 |
-1.0 / (priv->tex_height / 2.0), 0);
|
|
|
776610 |
cogl_matrix_translate (&projection_matrix,
|
|
|
776610 |
-(priv->tex_width / 2.0),
|
|
|
776610 |
-(priv->tex_height / 2.0), 0);
|
|
|
776610 |
|
|
|
776610 |
cogl_framebuffer_set_projection_matrix (fb, &projection_matrix);
|
|
|
776610 |
|
|
|
776610 |
cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0);
|
|
|
776610 |
cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR, &clear_color);
|
|
|
776610 |
|
|
|
776610 |
do_paint (stex, fb, priv->texture, NULL);
|
|
|
776610 |
|
|
|
776610 |
cogl_framebuffer_pop_matrix (fb);
|
|
|
776610 |
|
|
|
776610 |
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
|
776610 |
clip->width, clip->height);
|
|
|
776610 |
cogl_framebuffer_read_pixels (fb,
|
|
|
776610 |
clip->x, clip->y,
|
|
|
776610 |
clip->width, clip->height,
|
|
|
776610 |
CLUTTER_CAIRO_FORMAT_ARGB32,
|
|
|
776610 |
cairo_image_surface_get_data (surface));
|
|
|
776610 |
+ cairo_surface_mark_dirty (surface);
|
|
|
776610 |
+
|
|
|
776610 |
+ if (texture)
|
|
|
776610 |
+ {
|
|
|
776610 |
+ *texture = cogl_object_ref (image_texture);
|
|
|
776610 |
+
|
|
|
776610 |
+ if (G_UNLIKELY (meta_debug_show_backing_store))
|
|
|
776610 |
+ {
|
|
|
776610 |
+ cairo_t *cr;
|
|
|
776610 |
+
|
|
|
776610 |
+ cr = cairo_create (surface);
|
|
|
776610 |
+ cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.75);
|
|
|
776610 |
+ cairo_paint (cr);
|
|
|
776610 |
+ cairo_destroy (cr);
|
|
|
776610 |
+ }
|
|
|
776610 |
+
|
|
|
776610 |
+ cogl_texture_set_data (*texture, CLUTTER_CAIRO_FORMAT_ARGB32,
|
|
|
776610 |
+ cairo_image_surface_get_stride (surface),
|
|
|
776610 |
+ cairo_image_surface_get_data (surface), 0, NULL);
|
|
|
776610 |
+ }
|
|
|
776610 |
+
|
|
|
776610 |
cogl_object_unref (fb);
|
|
|
776610 |
|
|
|
776610 |
- cairo_surface_mark_dirty (surface);
|
|
|
776610 |
|
|
|
776610 |
return surface;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
/**
|
|
|
776610 |
* meta_shaped_texture_get_image:
|
|
|
776610 |
* @stex: A #MetaShapedTexture
|
|
|
776610 |
* @clip: A clipping rectangle, to help prevent extra processing.
|
|
|
776610 |
* In the case that the clipping rectangle is partially or fully
|
|
|
776610 |
* outside the bounds of the texture, the rectangle will be clipped.
|
|
|
776610 |
*
|
|
|
776610 |
* Flattens the two layers of the shaped texture into one ARGB32
|
|
|
776610 |
* image by alpha blending the two images, and returns the flattened
|
|
|
776610 |
* image.
|
|
|
776610 |
*
|
|
|
776610 |
* Returns: (transfer full): a new cairo surface to be freed with
|
|
|
776610 |
* cairo_surface_destroy().
|
|
|
776610 |
*/
|
|
|
776610 |
cairo_surface_t *
|
|
|
776610 |
meta_shaped_texture_get_image (MetaShapedTexture *stex,
|
|
|
776610 |
cairo_rectangle_int_t *clip)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
cairo_rectangle_int_t *transformed_clip = NULL;
|
|
|
776610 |
CoglTexture *texture, *mask_texture;
|
|
|
776610 |
cairo_surface_t *surface;
|
|
|
776610 |
|
|
|
776610 |
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL);
|
|
|
776610 |
|
|
|
776610 |
texture = COGL_TEXTURE (priv->texture);
|
|
|
776610 |
|
|
|
776610 |
if (texture == NULL)
|
|
|
776610 |
return NULL;
|
|
|
776610 |
|
|
|
776610 |
if (priv->tex_width == 0 || priv->tex_height == 0)
|
|
|
776610 |
return NULL;
|
|
|
776610 |
|
|
|
776610 |
if (clip != NULL)
|
|
|
776610 |
{
|
|
|
776610 |
double tex_scale;
|
|
|
776610 |
cairo_rectangle_int_t tex_rect;
|
|
|
776610 |
|
|
|
776610 |
transformed_clip = alloca (sizeof (cairo_rectangle_int_t));
|
|
|
776610 |
*transformed_clip = *clip;
|
|
|
776610 |
|
|
|
776610 |
clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL);
|
|
|
776610 |
meta_rectangle_scale_double (transformed_clip, 1.0 / tex_scale,
|
|
|
776610 |
META_ROUNDING_STRATEGY_GROW);
|
|
|
776610 |
|
|
|
776610 |
tex_rect = (cairo_rectangle_int_t) {
|
|
|
776610 |
.width = priv->tex_width,
|
|
|
776610 |
.height = priv->tex_height,
|
|
|
776610 |
};
|
|
|
776610 |
|
|
|
776610 |
if (!meta_rectangle_intersect (&tex_rect, transformed_clip,
|
|
|
776610 |
transformed_clip))
|
|
|
776610 |
return NULL;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
if (should_get_via_offscreen (stex))
|
|
|
776610 |
- return get_image_via_offscreen (stex, transformed_clip);
|
|
|
776610 |
+ return get_image_via_offscreen (stex, transformed_clip, NULL);
|
|
|
776610 |
|
|
|
776610 |
if (transformed_clip)
|
|
|
776610 |
texture = cogl_texture_new_from_sub_texture (texture,
|
|
|
776610 |
transformed_clip->x,
|
|
|
776610 |
transformed_clip->y,
|
|
|
776610 |
transformed_clip->width,
|
|
|
776610 |
transformed_clip->height);
|
|
|
776610 |
|
|
|
776610 |
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
|
776610 |
cogl_texture_get_width (texture),
|
|
|
776610 |
cogl_texture_get_height (texture));
|
|
|
776610 |
|
|
|
776610 |
cogl_texture_get_data (texture, CLUTTER_CAIRO_FORMAT_ARGB32,
|
|
|
776610 |
cairo_image_surface_get_stride (surface),
|
|
|
776610 |
cairo_image_surface_get_data (surface));
|
|
|
776610 |
|
|
|
776610 |
cairo_surface_mark_dirty (surface);
|
|
|
776610 |
|
|
|
776610 |
if (transformed_clip)
|
|
|
776610 |
cogl_object_unref (texture);
|
|
|
776610 |
|
|
|
776610 |
mask_texture = priv->mask_texture;
|
|
|
776610 |
if (mask_texture != NULL)
|
|
|
776610 |
{
|
|
|
776610 |
cairo_t *cr;
|
|
|
776610 |
cairo_surface_t *mask_surface;
|
|
|
776610 |
|
|
|
776610 |
if (transformed_clip)
|
|
|
776610 |
mask_texture =
|
|
|
776610 |
cogl_texture_new_from_sub_texture (mask_texture,
|
|
|
776610 |
transformed_clip->x,
|
|
|
776610 |
transformed_clip->y,
|
|
|
776610 |
transformed_clip->width,
|
|
|
776610 |
transformed_clip->height);
|
|
|
776610 |
|
|
|
776610 |
mask_surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
|
|
|
776610 |
cogl_texture_get_width (mask_texture),
|
|
|
776610 |
cogl_texture_get_height (mask_texture));
|
|
|
776610 |
|
|
|
776610 |
cogl_texture_get_data (mask_texture, COGL_PIXEL_FORMAT_A_8,
|
|
|
776610 |
cairo_image_surface_get_stride (mask_surface),
|
|
|
776610 |
cairo_image_surface_get_data (mask_surface));
|
|
|
776610 |
|
|
|
776610 |
cairo_surface_mark_dirty (mask_surface);
|
|
|
776610 |
|
|
|
776610 |
cr = cairo_create (surface);
|
|
|
776610 |
cairo_set_source_surface (cr, mask_surface, 0, 0);
|
|
|
776610 |
cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN);
|
|
|
776610 |
cairo_paint (cr);
|
|
|
776610 |
cairo_destroy (cr);
|
|
|
776610 |
|
|
|
776610 |
cairo_surface_destroy (mask_surface);
|
|
|
776610 |
|
|
|
776610 |
if (transformed_clip)
|
|
|
776610 |
cogl_object_unref (mask_texture);
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
return surface;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
+static void
|
|
|
776610 |
+meta_texture_backing_store_free (MetaTextureBackingStore *backing_store)
|
|
|
776610 |
+{
|
|
|
776610 |
+ g_clear_pointer (&backing_store->texture, cogl_object_unref);
|
|
|
776610 |
+ g_clear_pointer (&backing_store->mask_texture, cogl_object_unref);
|
|
|
776610 |
+ g_clear_pointer (&backing_store->mask_surface, cairo_surface_destroy);
|
|
|
776610 |
+ g_clear_pointer (&backing_store->region, cairo_region_destroy);
|
|
|
776610 |
+
|
|
|
776610 |
+ g_slice_free (MetaTextureBackingStore, backing_store);
|
|
|
776610 |
+}
|
|
|
776610 |
+
|
|
|
776610 |
+static MetaTextureBackingStore *
|
|
|
776610 |
+meta_texture_backing_store_new (CoglTexture *texture)
|
|
|
776610 |
+{
|
|
|
776610 |
+ MetaTextureBackingStore *backing_store = NULL;
|
|
|
776610 |
+ ClutterBackend *backend = clutter_get_default_backend ();
|
|
|
776610 |
+ CoglContext *context = clutter_backend_get_cogl_context (backend);
|
|
|
776610 |
+ CoglTexture *mask_texture = NULL;
|
|
|
776610 |
+ guchar *mask_data;
|
|
|
776610 |
+ int width, height, stride;
|
|
|
776610 |
+ cairo_surface_t *surface;
|
|
|
776610 |
+ cairo_region_t *region;
|
|
|
776610 |
+ cairo_rectangle_int_t backing_rectangle;
|
|
|
776610 |
+
|
|
|
776610 |
+ width = cogl_texture_get_width (texture);
|
|
|
776610 |
+ height = cogl_texture_get_height (texture);
|
|
|
776610 |
+ stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, width);
|
|
|
776610 |
+
|
|
|
776610 |
+ /* we start off by only letting the backing texture through, and none of the real texture */
|
|
|
776610 |
+ backing_rectangle.x = 0;
|
|
|
776610 |
+ backing_rectangle.y = 0;
|
|
|
776610 |
+ backing_rectangle.width = width;
|
|
|
776610 |
+ backing_rectangle.height = height;
|
|
|
776610 |
+
|
|
|
776610 |
+ region = cairo_region_create_rectangle (&backing_rectangle);
|
|
|
776610 |
+
|
|
|
776610 |
+ /* initialize mask to transparent, so the entire backing store shows through
|
|
|
776610 |
+ * up front
|
|
|
776610 |
+ */
|
|
|
776610 |
+ mask_data = g_malloc0 (stride * height);
|
|
|
776610 |
+ surface = cairo_image_surface_create_for_data (mask_data,
|
|
|
776610 |
+ CAIRO_FORMAT_A8,
|
|
|
776610 |
+ width,
|
|
|
776610 |
+ height,
|
|
|
776610 |
+ stride);
|
|
|
776610 |
+
|
|
|
776610 |
+ if (meta_texture_rectangle_check (texture))
|
|
|
776610 |
+ {
|
|
|
776610 |
+ mask_texture = COGL_TEXTURE (cogl_texture_rectangle_new_with_size (context,
|
|
|
776610 |
+ width,
|
|
|
776610 |
+ height));
|
|
|
776610 |
+ cogl_texture_set_components (mask_texture, COGL_TEXTURE_COMPONENTS_A);
|
|
|
776610 |
+ cogl_texture_set_region (mask_texture,
|
|
|
776610 |
+ 0, 0,
|
|
|
776610 |
+ 0, 0,
|
|
|
776610 |
+ width, height,
|
|
|
776610 |
+ width, height,
|
|
|
776610 |
+ COGL_PIXEL_FORMAT_A_8,
|
|
|
776610 |
+ stride, mask_data);
|
|
|
776610 |
+ }
|
|
|
776610 |
+ else
|
|
|
776610 |
+ {
|
|
|
776610 |
+ CoglError *error = NULL;
|
|
|
776610 |
+
|
|
|
776610 |
+ mask_texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (context, width, height,
|
|
|
776610 |
+ COGL_PIXEL_FORMAT_A_8,
|
|
|
776610 |
+ stride, mask_data, &error));
|
|
|
776610 |
+
|
|
|
776610 |
+ if (error)
|
|
|
776610 |
+ {
|
|
|
776610 |
+ g_warning ("Failed to allocate mask texture: %s", error->message);
|
|
|
776610 |
+ cogl_error_free (error);
|
|
|
776610 |
+ }
|
|
|
776610 |
+ }
|
|
|
776610 |
+
|
|
|
776610 |
+ if (mask_texture)
|
|
|
776610 |
+ {
|
|
|
776610 |
+ backing_store = g_slice_new0 (MetaTextureBackingStore);
|
|
|
776610 |
+ backing_store->texture = cogl_object_ref (texture);
|
|
|
776610 |
+ backing_store->mask_texture = mask_texture;
|
|
|
776610 |
+ backing_store->mask_surface = surface;
|
|
|
776610 |
+ backing_store->region = region;
|
|
|
776610 |
+ }
|
|
|
776610 |
+
|
|
|
776610 |
+ return backing_store;
|
|
|
776610 |
+}
|
|
|
776610 |
+
|
|
|
776610 |
+static void
|
|
|
776610 |
+enable_backing_store (MetaShapedTexture *stex,
|
|
|
776610 |
+ CoglTexture *texture)
|
|
|
776610 |
+{
|
|
|
776610 |
+ MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
+
|
|
|
776610 |
+ g_clear_pointer (&priv->backing_store, meta_texture_backing_store_free);
|
|
|
776610 |
+
|
|
|
776610 |
+ priv->backing_store = meta_texture_backing_store_new (texture);
|
|
|
776610 |
+
|
|
|
776610 |
+ meta_shaped_texture_reset_pipelines (stex);
|
|
|
776610 |
+}
|
|
|
776610 |
+
|
|
|
776610 |
+static void
|
|
|
776610 |
+disable_backing_store (MetaShapedTexture *stex)
|
|
|
776610 |
+{
|
|
|
776610 |
+ MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
+
|
|
|
776610 |
+ g_clear_pointer (&priv->backing_store, meta_texture_backing_store_free);
|
|
|
776610 |
+
|
|
|
776610 |
+ meta_shaped_texture_reset_pipelines (stex);
|
|
|
776610 |
+}
|
|
|
776610 |
+
|
|
|
776610 |
+void
|
|
|
776610 |
+meta_shaped_texture_save (MetaShapedTexture *stex)
|
|
|
776610 |
+{
|
|
|
776610 |
+
|
|
|
776610 |
+ CoglTexture *texture, *mask_texture;
|
|
|
776610 |
+ MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
+ cairo_surface_t *surface;
|
|
|
776610 |
+
|
|
|
776610 |
+ g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
|
|
776610 |
+
|
|
|
776610 |
+ texture = COGL_TEXTURE (priv->texture);
|
|
|
776610 |
+
|
|
|
776610 |
+ if (texture == NULL)
|
|
|
776610 |
+ return;
|
|
|
776610 |
+
|
|
|
776610 |
+ g_clear_pointer (&priv->saved_base_surface, cairo_surface_destroy);
|
|
|
776610 |
+ g_clear_pointer (&priv->saved_mask_surface, cairo_surface_destroy);
|
|
|
776610 |
+ g_clear_pointer (&priv->backing_store, meta_texture_backing_store_free);
|
|
|
776610 |
+
|
|
|
776610 |
+ if (should_get_via_offscreen (stex))
|
|
|
776610 |
+ {
|
|
|
776610 |
+ CoglTexture *backing_texture;
|
|
|
776610 |
+
|
|
|
776610 |
+ meta_shaped_texture_reset_pipelines (stex);
|
|
|
776610 |
+
|
|
|
776610 |
+ surface = get_image_via_offscreen (stex, NULL, &backing_texture);
|
|
|
776610 |
+
|
|
|
776610 |
+ enable_backing_store (stex, backing_texture);
|
|
|
776610 |
+ cogl_object_unref (backing_texture);
|
|
|
776610 |
+ }
|
|
|
776610 |
+ else
|
|
|
776610 |
+ {
|
|
|
776610 |
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
|
776610 |
+ cogl_texture_get_width (texture),
|
|
|
776610 |
+ cogl_texture_get_height (texture));
|
|
|
776610 |
+
|
|
|
776610 |
+ cogl_texture_get_data (texture, CLUTTER_CAIRO_FORMAT_ARGB32,
|
|
|
776610 |
+ cairo_image_surface_get_stride (surface),
|
|
|
776610 |
+ cairo_image_surface_get_data (surface));
|
|
|
776610 |
+ }
|
|
|
776610 |
+
|
|
|
776610 |
+ priv->saved_base_surface = surface;
|
|
|
776610 |
+
|
|
|
776610 |
+ mask_texture = stex->priv->mask_texture;
|
|
|
776610 |
+ if (mask_texture != NULL)
|
|
|
776610 |
+ {
|
|
|
776610 |
+ cairo_surface_t *mask_surface;
|
|
|
776610 |
+
|
|
|
776610 |
+ mask_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
|
776610 |
+ cogl_texture_get_width (mask_texture),
|
|
|
776610 |
+ cogl_texture_get_height (mask_texture));
|
|
|
776610 |
+
|
|
|
776610 |
+ cogl_texture_get_data (mask_texture, CLUTTER_CAIRO_FORMAT_ARGB32,
|
|
|
776610 |
+ cairo_image_surface_get_stride (mask_surface),
|
|
|
776610 |
+ cairo_image_surface_get_data (mask_surface));
|
|
|
776610 |
+
|
|
|
776610 |
+ cairo_surface_mark_dirty (mask_surface);
|
|
|
776610 |
+
|
|
|
776610 |
+ priv->saved_mask_surface = mask_surface;
|
|
|
776610 |
+ }
|
|
|
776610 |
+}
|
|
|
776610 |
+
|
|
|
776610 |
+void
|
|
|
776610 |
+meta_shaped_texture_restore (MetaShapedTexture *stex)
|
|
|
776610 |
+{
|
|
|
776610 |
+ MetaShapedTexturePrivate *priv = stex->priv;
|
|
|
776610 |
+ CoglTexture *texture;
|
|
|
776610 |
+ CoglError *error = NULL;
|
|
|
776610 |
+
|
|
|
776610 |
+ texture = meta_shaped_texture_get_texture (stex);
|
|
|
776610 |
+
|
|
|
776610 |
+ if (texture == NULL)
|
|
|
776610 |
+ return;
|
|
|
776610 |
+
|
|
|
776610 |
+ if (priv->mask_texture)
|
|
|
776610 |
+ {
|
|
|
776610 |
+ if (!cogl_texture_set_data (priv->mask_texture, CLUTTER_CAIRO_FORMAT_ARGB32,
|
|
|
776610 |
+ cairo_image_surface_get_stride (priv->saved_mask_surface),
|
|
|
776610 |
+ cairo_image_surface_get_data (priv->saved_mask_surface), 0,
|
|
|
776610 |
+ &error))
|
|
|
776610 |
+ {
|
|
|
776610 |
+ g_warning ("Failed to restore mask texture");
|
|
|
776610 |
+ g_clear_pointer (&error, cogl_error_free);
|
|
|
776610 |
+ }
|
|
|
776610 |
+ g_clear_pointer (&priv->saved_mask_surface, cairo_surface_destroy);
|
|
|
776610 |
+ }
|
|
|
776610 |
+
|
|
|
776610 |
+ /* if the main texture doesn't support direct writes, then
|
|
|
776610 |
+ * write to the local backing texture instead, and blend old
|
|
|
776610 |
+ * versus new at paint time.
|
|
|
776610 |
+ */
|
|
|
776610 |
+ if (priv->backing_store)
|
|
|
776610 |
+ {
|
|
|
776610 |
+ meta_texture_backing_store_redraw_mask (priv->backing_store);
|
|
|
776610 |
+ texture = priv->backing_store->texture;
|
|
|
776610 |
+ }
|
|
|
776610 |
+
|
|
|
776610 |
+ if (!cogl_texture_set_data (texture, CLUTTER_CAIRO_FORMAT_ARGB32,
|
|
|
776610 |
+ cairo_image_surface_get_stride (priv->saved_base_surface),
|
|
|
776610 |
+ cairo_image_surface_get_data (priv->saved_base_surface), 0,
|
|
|
776610 |
+ &error))
|
|
|
776610 |
+ {
|
|
|
776610 |
+ g_warning ("Failed to restore texture");
|
|
|
776610 |
+ g_clear_pointer (&error, cogl_error_free);
|
|
|
776610 |
+ }
|
|
|
776610 |
+ g_clear_pointer (&priv->saved_base_surface, cairo_surface_destroy);
|
|
|
776610 |
+
|
|
|
776610 |
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
|
|
|
776610 |
+}
|
|
|
776610 |
+
|
|
|
776610 |
void
|
|
|
776610 |
meta_shaped_texture_set_fallback_size (MetaShapedTexture *self,
|
|
|
776610 |
guint fallback_width,
|
|
|
776610 |
guint fallback_height)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexturePrivate *priv = self->priv;
|
|
|
776610 |
|
|
|
776610 |
priv->fallback_width = fallback_width;
|
|
|
776610 |
priv->fallback_height = fallback_height;
|
|
|
776610 |
}
|
|
|
776610 |
|
|
|
776610 |
static void
|
|
|
776610 |
meta_shaped_texture_cull_out (MetaCullable *cullable,
|
|
|
776610 |
cairo_region_t *unobscured_region,
|
|
|
776610 |
cairo_region_t *clip_region)
|
|
|
776610 |
{
|
|
|
776610 |
MetaShapedTexture *self = META_SHAPED_TEXTURE (cullable);
|
|
|
776610 |
MetaShapedTexturePrivate *priv = self->priv;
|
|
|
776610 |
|
|
|
776610 |
set_unobscured_region (self, unobscured_region);
|
|
|
776610 |
set_clip_region (self, clip_region);
|
|
|
776610 |
|
|
|
776610 |
if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self)) == 0xff)
|
|
|
776610 |
{
|
|
|
776610 |
if (priv->opaque_region)
|
|
|
776610 |
{
|
|
|
776610 |
if (unobscured_region)
|
|
|
776610 |
cairo_region_subtract (unobscured_region, priv->opaque_region);
|
|
|
776610 |
if (clip_region)
|
|
|
776610 |
cairo_region_subtract (clip_region, priv->opaque_region);
|
|
|
776610 |
diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h
|
|
|
776610 |
index 80b23f2ea..fc0567c9f 100644
|
|
|
776610 |
--- a/src/meta/meta-shaped-texture.h
|
|
|
776610 |
+++ b/src/meta/meta-shaped-texture.h
|
|
|
776610 |
@@ -54,33 +54,35 @@ struct _MetaShapedTextureClass
|
|
|
776610 |
*/
|
|
|
776610 |
struct _MetaShapedTexture
|
|
|
776610 |
{
|
|
|
776610 |
/*< private >*/
|
|
|
776610 |
ClutterActor parent;
|
|
|
776610 |
|
|
|
776610 |
MetaShapedTexturePrivate *priv;
|
|
|
776610 |
};
|
|
|
776610 |
|
|
|
776610 |
GType meta_shaped_texture_get_type (void) G_GNUC_CONST;
|
|
|
776610 |
|
|
|
776610 |
void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
|
|
|
776610 |
gboolean create_mipmaps);
|
|
|
776610 |
|
|
|
776610 |
gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
|
|
776610 |
int x,
|
|
|
776610 |
int y,
|
|
|
776610 |
int width,
|
|
|
776610 |
int height);
|
|
|
776610 |
|
|
|
776610 |
CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
|
|
|
776610 |
|
|
|
776610 |
void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
|
|
|
776610 |
CoglTexture *mask_texture);
|
|
|
776610 |
void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
|
|
|
776610 |
cairo_region_t *opaque_region);
|
|
|
776610 |
|
|
|
776610 |
cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture *stex,
|
|
|
776610 |
cairo_rectangle_int_t *clip);
|
|
|
776610 |
|
|
|
776610 |
+void meta_shaped_texture_save (MetaShapedTexture *self);
|
|
|
776610 |
+void meta_shaped_texture_restore (MetaShapedTexture *self);
|
|
|
776610 |
G_END_DECLS
|
|
|
776610 |
|
|
|
776610 |
#endif /* __META_SHAPED_TEXTURE_H__ */
|
|
|
776610 |
--
|
|
|
776610 |
2.18.1
|
|
|
776610 |
|