[mutter] Introduce regional stage rendering
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] Introduce regional stage rendering
- Date: Wed, 20 Jul 2016 06:28:18 +0000 (UTC)
commit 566c28bdaf2217e1ae82210af9c11ac250aa12f6
Author: Jonas Ådahl <jadahl gmail com>
Date: Fri May 27 11:09:24 2016 +0800
Introduce regional stage rendering
Add support for drawing a stage using multiple framebuffers each making
up one part of the stage. This works by the stage backend
(ClutterStageWindow) providing a list of views which will be for
splitting up the stage in different regions.
A view layout, for now, is a set of rectangles. The stage window (i.e.
stage "backend" will use this information when drawing a frame, using
one framebuffer for each view. The scene graph is adapted to explictly
take a view when painting the stage. It will use this view, its
assigned framebuffer and layout to offset and clip the drawing
accordingly.
This effectively removes any notion of "stage framebuffer", since each
stage now may consist of multiple framebuffers. Therefore, API
involving this has been deprecated and made no-ops; namely
clutter_stage_ensure_context(). Callers are now assumed to either
always use a framebuffer reference explicitly, or push/pop the
framebuffer of a given view where the code has not yet changed to use
the explicit-buffer-using cogl API.
Currently only the nested X11 backend supports this mode fully, and the
per view framebuffers are all offscreen. Upon frame completion, it'll
blit each view's framebuffer onto the onscreen framebuffer before
swapping.
Other backends (X11 CM and native/KMS) are adapted to manage a
full-stage view. The X11 CM backend will continue to use this method,
while the native/KMS backend will be adopted to use multiple view
drawing.
https://bugzilla.gnome.org/show_bug.cgi?id=768976
clutter/clutter/Makefile.am | 2 +
clutter/clutter/clutter-backend-private.h | 7 +-
clutter/clutter/clutter-backend.c | 103 -----
clutter/clutter/clutter-macros.h | 2 +
clutter/clutter/clutter-mutter.h | 1 +
clutter/clutter/clutter-private.h | 4 +
clutter/clutter/clutter-stage-private.h | 6 +-
clutter/clutter/clutter-stage-view.c | 188 +++++++++
clutter/clutter/clutter-stage-view.h | 55 +++
clutter/clutter/clutter-stage-window.c | 38 +--
clutter/clutter/clutter-stage-window.h | 14 +-
clutter/clutter/clutter-stage.c | 373 ++++++++++++------
clutter/clutter/clutter-stage.h | 3 -
clutter/clutter/clutter-util.c | 33 ++
clutter/clutter/cogl/clutter-stage-cogl.c | 427 +++++++++++++++------
clutter/clutter/cogl/clutter-stage-cogl.h | 19 +-
clutter/clutter/deprecated/clutter-stage.h | 3 +
clutter/clutter/x11/clutter-stage-x11.c | 67 +++-
clutter/clutter/x11/clutter-stage-x11.h | 3 +
src/Makefile.am | 2 +
src/backends/meta-backend-private.h | 2 +
src/backends/meta-renderer-view.c | 43 ++
src/backends/meta-renderer-view.h | 29 ++
src/backends/meta-renderer.c | 74 ++++-
src/backends/meta-renderer.h | 12 +
src/backends/meta-stage.c | 3 +
src/backends/meta-stage.h | 3 +
src/backends/native/meta-backend-native.c | 7 +
src/backends/native/meta-clutter-backend-native.c | 25 +-
src/backends/native/meta-clutter-backend-native.h | 3 +
src/backends/native/meta-stage-native.c | 146 ++++++--
src/backends/native/meta-stage-native.h | 4 +
src/backends/x11/meta-backend-x11.c | 3 +
src/backends/x11/meta-renderer-x11.c | 31 ++
src/backends/x11/meta-stage-x11-nested.c | 130 ++++++-
src/core/boxes-private.h | 2 +
src/core/boxes.c | 11 +
37 files changed, 1434 insertions(+), 444 deletions(-)
---
diff --git a/clutter/clutter/Makefile.am b/clutter/clutter/Makefile.am
index b9bf68d..df157df 100644
--- a/clutter/clutter/Makefile.am
+++ b/clutter/clutter/Makefile.am
@@ -114,6 +114,7 @@ source_h = \
clutter-snap-constraint.h \
clutter-stage.h \
clutter-stage-manager.h \
+ clutter-stage-view.h \
clutter-tap-action.h \
clutter-test-utils.h \
clutter-texture.h \
@@ -197,6 +198,7 @@ source_c = \
clutter-snap-constraint.c \
clutter-stage.c \
clutter-stage-manager.c \
+ clutter-stage-view.c \
clutter-stage-window.c \
clutter-tap-action.c \
clutter-test-utils.c \
diff --git a/clutter/clutter/clutter-backend-private.h b/clutter/clutter/clutter-backend-private.h
index f485cba..b808d25 100644
--- a/clutter/clutter/clutter-backend-private.h
+++ b/clutter/clutter/clutter-backend-private.h
@@ -86,8 +86,6 @@ struct _ClutterBackendClass
GError **error);
gboolean (* create_context) (ClutterBackend *backend,
GError **error);
- void (* ensure_context) (ClutterBackend *backend,
- ClutterStage *stage);
ClutterDeviceManager *(* get_device_manager) (ClutterBackend *backend);
void (* copy_event_data) (ClutterBackend *backend,
@@ -113,10 +111,6 @@ ClutterBackend * _clutter_create_backend (void);
ClutterStageWindow * _clutter_backend_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error);
-void _clutter_backend_ensure_context (ClutterBackend *backend,
- ClutterStage *stage);
-void _clutter_backend_ensure_context_internal (ClutterBackend *backend,
- ClutterStage *stage);
gboolean _clutter_backend_create_context (ClutterBackend *backend,
GError **error);
@@ -152,6 +146,7 @@ gint32 _clutter_backend_get_units_serial (Clutter
PangoDirection _clutter_backend_get_keymap_direction (ClutterBackend *backend);
+CLUTTER_AVAILABLE_IN_MUTTER
void _clutter_backend_reset_cogl_framebuffer (ClutterBackend *backend);
void clutter_set_allowed_drivers (const char *drivers);
diff --git a/clutter/clutter/clutter-backend.c b/clutter/clutter/clutter-backend.c
index c3b7295..5a1d252 100644
--- a/clutter/clutter/clutter-backend.c
+++ b/clutter/clutter/clutter-backend.c
@@ -413,27 +413,6 @@ clutter_backend_real_create_context (ClutterBackend *backend,
return TRUE;
}
-static void
-clutter_backend_real_ensure_context (ClutterBackend *backend,
- ClutterStage *stage)
-{
- ClutterStageWindow *stage_impl;
- CoglFramebuffer *framebuffer;
-
- if (stage == NULL)
- return;
-
- stage_impl = _clutter_stage_get_window (stage);
- if (stage_impl == NULL)
- return;
-
- framebuffer = _clutter_stage_window_get_active_framebuffer (stage_impl);
- if (framebuffer == NULL)
- return;
-
- cogl_set_framebuffer (framebuffer);
-}
-
static ClutterFeatureFlags
clutter_backend_real_get_features (ClutterBackend *backend)
{
@@ -697,7 +676,6 @@ clutter_backend_class_init (ClutterBackendClass *klass)
klass->get_device_manager = clutter_backend_real_get_device_manager;
klass->translate_event = clutter_backend_real_translate_event;
klass->create_context = clutter_backend_real_create_context;
- klass->ensure_context = clutter_backend_real_ensure_context;
klass->get_features = clutter_backend_real_get_features;
}
@@ -789,87 +767,6 @@ _clutter_backend_create_context (ClutterBackend *backend,
return klass->create_context (backend, error);
}
-void
-_clutter_backend_ensure_context_internal (ClutterBackend *backend,
- ClutterStage *stage)
-{
- ClutterBackendClass *klass = CLUTTER_BACKEND_GET_CLASS (backend);
- if (G_LIKELY (klass->ensure_context))
- klass->ensure_context (backend, stage);
-}
-
-void
-_clutter_backend_ensure_context (ClutterBackend *backend,
- ClutterStage *stage)
-{
- static ClutterStage *current_context_stage = NULL;
-
- g_assert (CLUTTER_IS_BACKEND (backend));
- g_assert (CLUTTER_IS_STAGE (stage));
-
- if (current_context_stage != stage ||
- !clutter_actor_is_realized (CLUTTER_ACTOR (stage)))
- {
- ClutterStage *new_stage = NULL;
-
- if (!clutter_actor_is_realized (CLUTTER_ACTOR (stage)))
- {
- new_stage = NULL;
-
- CLUTTER_NOTE (BACKEND,
- "Stage [%p] is not realized, unsetting the stage",
- stage);
- }
- else
- {
- new_stage = stage;
-
- CLUTTER_NOTE (BACKEND,
- "Setting the new stage [%p]",
- new_stage);
- }
-
- /* XXX: Until Cogl becomes fully responsible for backend windows
- * Clutter need to manually keep it informed of the current window size
- *
- * NB: This must be done after we ensure_context above because Cogl
- * always assumes there is a current GL context.
- */
- if (new_stage != NULL)
- {
- float width, height;
-
- _clutter_backend_ensure_context_internal (backend, new_stage);
-
- clutter_actor_get_size (CLUTTER_ACTOR (stage), &width, &height);
-
- cogl_onscreen_clutter_backend_set_size (width, height);
-
- /* Eventually we will have a separate CoglFramebuffer for
- * each stage and each one will track private projection
- * matrix and viewport state, but until then we need to make
- * sure we update the projection and viewport whenever we
- * switch between stages.
- *
- * This dirty mechanism will ensure they are asserted before
- * the next paint...
- */
- _clutter_stage_dirty_viewport (stage);
- _clutter_stage_dirty_projection (stage);
- }
-
- /* FIXME: With a NULL stage and thus no active context it may make more
- * sense to clean the context but then re call with the default stage
- * so at least there is some kind of context in place (as to avoid
- * potential issue of GL calls with no context).
- */
- current_context_stage = new_stage;
- }
- else
- CLUTTER_NOTE (BACKEND, "Stage is the same");
-}
-
-
ClutterFeatureFlags
_clutter_backend_get_features (ClutterBackend *backend)
{
diff --git a/clutter/clutter/clutter-macros.h b/clutter/clutter/clutter-macros.h
index 521ad43..21cb304 100644
--- a/clutter/clutter/clutter-macros.h
+++ b/clutter/clutter/clutter-macros.h
@@ -278,6 +278,8 @@
# define CLUTTER_DEPRECATED_IN_1_12_FOR(f) _CLUTTER_EXTERN
#endif
+#define CLUTTER_DEPRECATED_IN_MUTTER CLUTTER_DEPRECATED
+
#if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_12
# define CLUTTER_AVAILABLE_IN_1_12 CLUTTER_UNAVAILABLE(1, 12)
#else
diff --git a/clutter/clutter/clutter-mutter.h b/clutter/clutter/clutter-mutter.h
index ab50742..cdb6e4b 100644
--- a/clutter/clutter/clutter-mutter.h
+++ b/clutter/clutter/clutter-mutter.h
@@ -27,6 +27,7 @@
#include "clutter-backend.h"
#include "clutter-macros.h"
+#include "clutter-stage-view.h"
#include "cogl/clutter-stage-cogl.h"
#include "x11/clutter-stage-x11.h"
diff --git a/clutter/clutter/clutter-private.h b/clutter/clutter/clutter-private.h
index ab2cc97..129880d 100644
--- a/clutter/clutter/clutter-private.h
+++ b/clutter/clutter/clutter-private.h
@@ -244,6 +244,10 @@ void _clutter_util_rectangle_union (const cairo_rectangle_int_t *src1,
const cairo_rectangle_int_t *src2,
cairo_rectangle_int_t *dest);
+gboolean _clutter_util_rectangle_intersection (const cairo_rectangle_int_t *src1,
+ const cairo_rectangle_int_t *src2,
+ cairo_rectangle_int_t *dest);
+
struct _ClutterVertex4
{
diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h
index 7529cdf..6e06cf1 100644
--- a/clutter/clutter/clutter-stage-private.h
+++ b/clutter/clutter/clutter-stage-private.h
@@ -36,7 +36,8 @@ typedef struct _ClutterStageQueueRedrawEntry ClutterStageQueueRedrawEntry;
/* stage */
ClutterStageWindow *_clutter_stage_get_default_window (void);
-void _clutter_stage_do_paint (ClutterStage *stage,
+void _clutter_stage_paint_view (ClutterStage *stage,
+ ClutterStageView *view,
const cairo_rectangle_int_t *clip);
void _clutter_stage_set_window (ClutterStage *stage,
@@ -56,7 +57,8 @@ void _clutter_stage_get_viewport (ClutterStage
float *width,
float *height);
void _clutter_stage_dirty_viewport (ClutterStage *stage);
-void _clutter_stage_maybe_setup_viewport (ClutterStage *stage);
+void _clutter_stage_maybe_setup_viewport (ClutterStage *stage,
+ ClutterStageView *view);
void _clutter_stage_maybe_relayout (ClutterActor *stage);
gboolean _clutter_stage_needs_update (ClutterStage *stage);
gboolean _clutter_stage_do_update (ClutterStage *stage);
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
new file mode 100644
index 0000000..6a6cf33
--- /dev/null
+++ b/clutter/clutter/clutter-stage-view.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "clutter-build-config.h"
+
+#include "clutter/clutter-stage-view.h"
+
+#include <cairo-gobject.h>
+
+enum
+{
+ PROP_0,
+
+ PROP_LAYOUT,
+ PROP_FRAMEBUFFER,
+
+ PROP_LAST
+};
+
+static GParamSpec *obj_props[PROP_LAST];
+
+typedef struct _ClutterStageViewPrivate
+{
+ cairo_rectangle_int_t layout;
+ CoglFramebuffer *framebuffer;
+ guint dirty_viewport : 1;
+ guint dirty_projection : 1;
+} ClutterStageViewPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageView, clutter_stage_view, G_TYPE_OBJECT)
+
+void
+clutter_stage_view_get_layout (ClutterStageView *view,
+ cairo_rectangle_int_t *rect)
+{
+ ClutterStageViewPrivate *priv =
+ clutter_stage_view_get_instance_private (view);
+
+ *rect = priv->layout;
+}
+
+CoglFramebuffer *
+clutter_stage_view_get_framebuffer (ClutterStageView *view)
+{
+ ClutterStageViewPrivate *priv =
+ clutter_stage_view_get_instance_private (view);
+
+ return priv->framebuffer;
+}
+
+gboolean
+clutter_stage_view_is_dirty_viewport (ClutterStageView *view)
+{
+ ClutterStageViewPrivate *priv =
+ clutter_stage_view_get_instance_private (view);
+
+ return priv->dirty_viewport;
+}
+
+void
+clutter_stage_view_set_dirty_viewport (ClutterStageView *view,
+ gboolean dirty)
+{
+ ClutterStageViewPrivate *priv =
+ clutter_stage_view_get_instance_private (view);
+
+ priv->dirty_viewport = dirty;
+}
+
+gboolean
+clutter_stage_view_is_dirty_projection (ClutterStageView *view)
+{
+ ClutterStageViewPrivate *priv =
+ clutter_stage_view_get_instance_private (view);
+
+ return priv->dirty_projection;
+}
+
+void
+clutter_stage_view_set_dirty_projection (ClutterStageView *view,
+ gboolean dirty)
+{
+ ClutterStageViewPrivate *priv =
+ clutter_stage_view_get_instance_private (view);
+
+ priv->dirty_projection = dirty;
+}
+
+static void
+clutter_stage_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterStageView *view = CLUTTER_STAGE_VIEW (object);
+ ClutterStageViewPrivate *priv =
+ clutter_stage_view_get_instance_private (view);
+
+ switch (prop_id)
+ {
+ case PROP_LAYOUT:
+ g_value_set_boxed (value, &priv->layout);
+ break;
+ case PROP_FRAMEBUFFER:
+ g_value_set_boxed (value, priv->framebuffer);
+ break;
+ }
+}
+
+static void
+clutter_stage_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterStageView *view = CLUTTER_STAGE_VIEW (object);
+ ClutterStageViewPrivate *priv =
+ clutter_stage_view_get_instance_private (view);
+ cairo_rectangle_int_t *layout;
+
+ switch (prop_id)
+ {
+ case PROP_LAYOUT:
+ layout = g_value_get_boxed (value);
+ priv->layout = *layout;
+ break;
+ case PROP_FRAMEBUFFER:
+ priv->framebuffer = g_value_get_boxed (value);
+ break;
+ }
+}
+
+static void
+clutter_stage_view_dispose (GObject *object)
+{
+ ClutterStageView *view = CLUTTER_STAGE_VIEW (object);
+ ClutterStageViewPrivate *priv =
+ clutter_stage_view_get_instance_private (view);
+
+ g_clear_pointer (&priv->framebuffer, cogl_object_unref);
+}
+
+static void
+clutter_stage_view_init (ClutterStageView *view)
+{
+}
+
+static void
+clutter_stage_view_class_init (ClutterStageViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = clutter_stage_view_get_property;
+ object_class->set_property = clutter_stage_view_set_property;
+ object_class->dispose = clutter_stage_view_dispose;
+
+ obj_props[PROP_LAYOUT] =
+ g_param_spec_boxed ("layout",
+ "View layout",
+ "The view layout on the screen",
+ CAIRO_GOBJECT_TYPE_RECTANGLE_INT,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ obj_props[PROP_FRAMEBUFFER] =
+ g_param_spec_boxed ("framebuffer",
+ "View framebuffer",
+ "The framebuffer of the view",
+ COGL_TYPE_HANDLE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, PROP_LAST, obj_props);
+}
diff --git a/clutter/clutter/clutter-stage-view.h b/clutter/clutter/clutter-stage-view.h
new file mode 100644
index 0000000..e9fe3a0
--- /dev/null
+++ b/clutter/clutter/clutter-stage-view.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CLUTTER_STAGE_VIEW_H__
+#define __CLUTTER_STAGE_VIEW_H__
+
+#include <cairo.h>
+#include <glib-object.h>
+#include <cogl/cogl.h>
+
+#include "clutter-macros.h"
+
+#define CLUTTER_TYPE_STAGE_VIEW (clutter_stage_view_get_type ())
+CLUTTER_AVAILABLE_IN_MUTTER
+G_DECLARE_DERIVABLE_TYPE (ClutterStageView, clutter_stage_view,
+ CLUTTER, STAGE_VIEW,
+ GObject)
+
+struct _ClutterStageViewClass
+{
+ GObjectClass parent_class;
+};
+
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_stage_view_get_layout (ClutterStageView *view,
+ cairo_rectangle_int_t *rect);
+
+CLUTTER_AVAILABLE_IN_MUTTER
+CoglFramebuffer *clutter_stage_view_get_framebuffer (ClutterStageView *view);
+
+gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
+
+void clutter_stage_view_set_dirty_viewport (ClutterStageView *view,
+ gboolean dirty);
+
+gboolean clutter_stage_view_is_dirty_projection (ClutterStageView *view);
+
+void clutter_stage_view_set_dirty_projection (ClutterStageView *view,
+ gboolean dirty);
+
+#endif /* __CLUTTER_STAGE_VIEW_H__ */
diff --git a/clutter/clutter/clutter-stage-window.c b/clutter/clutter/clutter-stage-window.c
index 2efb325..c6e7780 100644
--- a/clutter/clutter/clutter-stage-window.c
+++ b/clutter/clutter/clutter-stage-window.c
@@ -274,6 +274,7 @@ _clutter_stage_window_redraw (ClutterStageWindow *window)
void
_clutter_stage_window_get_dirty_pixel (ClutterStageWindow *window,
+ ClutterStageView *view,
int *x, int *y)
{
ClutterStageWindowIface *iface;
@@ -285,27 +286,7 @@ _clutter_stage_window_get_dirty_pixel (ClutterStageWindow *window,
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
if (iface->get_dirty_pixel)
- iface->get_dirty_pixel (window, x, y);
-}
-
-/* NB: The presumption shouldn't be that a stage can't be comprised of
- * multiple internal framebuffers, so instead of simply naming this
- * function _clutter_stage_window_get_framebuffer(), the "active"
- * infix is intended to clarify that it gets the framebuffer that is
- * currently in use/being painted.
- */
-CoglFramebuffer *
-_clutter_stage_window_get_active_framebuffer (ClutterStageWindow *window)
-{
- ClutterStageWindowIface *iface;
-
- g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), NULL);
-
- iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
- if (iface->get_active_framebuffer)
- return iface->get_active_framebuffer (window);
- else
- return NULL;
+ iface->get_dirty_pixel (window, view, x, y);
}
gboolean
@@ -349,12 +330,12 @@ _clutter_stage_window_get_scale_factor (ClutterStageWindow *window)
return 1;
}
-CoglFramebuffer *
-_clutter_stage_window_get_legacy_onscreen (ClutterStageWindow *window)
+GList *
+_clutter_stage_window_get_views (ClutterStageWindow *window)
{
ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
- return iface->get_legacy_onscreen (window);
+ return iface->get_views (window);
}
CoglFrameClosure *
@@ -376,6 +357,15 @@ _clutter_stage_window_remove_frame_callback (ClutterStageWindow *window,
iface->remove_frame_callback (window, closure);
}
+void
+_clutter_stage_window_finish_frame (ClutterStageWindow *window)
+{
+ ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
+
+ if (iface->finish_frame)
+ iface->finish_frame (window);
+}
+
int64_t
_clutter_stage_window_get_frame_counter (ClutterStageWindow *window)
{
diff --git a/clutter/clutter/clutter-stage-window.h b/clutter/clutter/clutter-stage-window.h
index 863ecfc..947eb87 100644
--- a/clutter/clutter/clutter-stage-window.h
+++ b/clutter/clutter/clutter-stage-window.h
@@ -3,6 +3,7 @@
#include <cogl/cogl.h>
#include <clutter/clutter-types.h>
+#include "clutter/clutter-stage-view.h"
G_BEGIN_DECLS
@@ -77,22 +78,22 @@ struct _ClutterStageWindowIface
void (* redraw) (ClutterStageWindow *stage_window);
void (* get_dirty_pixel) (ClutterStageWindow *stage_window,
+ ClutterStageView *view,
int *x, int *y);
- CoglFramebuffer *(* get_active_framebuffer) (ClutterStageWindow *stage_window);
-
gboolean (* can_clip_redraws) (ClutterStageWindow *stage_window);
void (* set_scale_factor) (ClutterStageWindow *stage_window,
int factor);
int (* get_scale_factor) (ClutterStageWindow *stage_window);
- CoglFramebuffer *(* get_legacy_onscreen) (ClutterStageWindow *stage_window);
+ GList *(* get_views) (ClutterStageWindow *stage_window);
CoglFrameClosure *(* set_frame_callback) (ClutterStageWindow *stage_window,
CoglFrameCallback callback,
gpointer user_data);
void (* remove_frame_callback) (ClutterStageWindow *stage_window,
CoglFrameClosure *closure);
int64_t (* get_frame_counter) (ClutterStageWindow *stage_window);
+ void (* finish_frame) (ClutterStageWindow *stage_window);
};
CLUTTER_AVAILABLE_IN_MUTTER
@@ -139,17 +140,16 @@ void _clutter_stage_window_set_accept_focus (ClutterStageWin
void _clutter_stage_window_redraw (ClutterStageWindow *window);
void _clutter_stage_window_get_dirty_pixel (ClutterStageWindow *window,
+ ClutterStageView *view,
int *x, int *y);
-CoglFramebuffer *_clutter_stage_window_get_active_framebuffer (ClutterStageWindow *window);
-
gboolean _clutter_stage_window_can_clip_redraws (ClutterStageWindow *window);
void _clutter_stage_window_set_scale_factor (ClutterStageWindow *window,
int factor);
int _clutter_stage_window_get_scale_factor (ClutterStageWindow *window);
-CoglFramebuffer *_clutter_stage_window_get_legacy_onscreen (ClutterStageWindow *stage_window);
+GList * _clutter_stage_window_get_views (ClutterStageWindow *window);
CoglFrameClosure *_clutter_stage_window_set_frame_callback (ClutterStageWindow *window,
CoglFrameCallback callback,
@@ -158,6 +158,8 @@ CoglFrameClosure *_clutter_stage_window_set_frame_callback (ClutterStageWin
void _clutter_stage_window_remove_frame_callback (ClutterStageWindow *stage_winow,
CoglFrameClosure *closure);
+void _clutter_stage_window_finish_frame (ClutterStageWindow *window);
+
int64_t _clutter_stage_window_get_frame_counter (ClutterStageWindow *window);
G_END_DECLS
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
index ac5a356..6e53435 100644
--- a/clutter/clutter/clutter-stage.c
+++ b/clutter/clutter/clutter-stage.c
@@ -158,8 +158,6 @@ struct _ClutterStagePrivate
guint throttle_motion_events : 1;
guint use_alpha : 1;
guint min_size_changed : 1;
- guint dirty_viewport : 1;
- guint dirty_projection : 1;
guint accept_focus : 1;
guint motion_events_enabled : 1;
guint has_custom_perspective : 1;
@@ -602,7 +600,8 @@ _cogl_util_get_eye_planes_for_screen_poly (float *polygon,
}
static void
-_clutter_stage_update_active_framebuffer (ClutterStage *stage)
+_clutter_stage_update_active_framebuffer (ClutterStage *stage,
+ CoglFramebuffer *framebuffer)
{
ClutterStagePrivate *priv = stage->priv;
@@ -611,34 +610,27 @@ _clutter_stage_update_active_framebuffer (ClutterStage *stage)
* offscreen framebuffer.
*/
- priv->active_framebuffer =
- _clutter_stage_window_get_active_framebuffer (priv->impl);
-
- if (!priv->active_framebuffer)
- priv->active_framebuffer = cogl_get_draw_framebuffer ();
+ priv->active_framebuffer = framebuffer;
}
-/* This provides a common point of entry for painting the scenegraph
- * for picking or painting...
- *
- * XXX: Instead of having a toplevel 2D clip region, it might be
+/* XXX: Instead of having a toplevel 2D clip region, it might be
* better to have a clip volume within the view frustum. This could
* allow us to avoid projecting actors into window coordinates to
* be able to cull them.
*/
-void
-_clutter_stage_do_paint (ClutterStage *stage,
- const cairo_rectangle_int_t *clip)
+static void
+clutter_stage_do_paint_view (ClutterStage *stage,
+ ClutterStageView *view,
+ const cairo_rectangle_int_t *clip)
{
ClutterStagePrivate *priv = stage->priv;
+ CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
+ cairo_rectangle_int_t view_layout;
float clip_poly[8];
float viewport[4];
cairo_rectangle_int_t geom;
int window_scale;
- if (priv->impl == NULL)
- return;
-
_clutter_stage_window_get_geometry (priv->impl, &geom);
window_scale = _clutter_stage_window_get_scale_factor (priv->impl);
@@ -647,29 +639,26 @@ _clutter_stage_do_paint (ClutterStage *stage,
viewport[2] = priv->viewport[2] * window_scale;
viewport[3] = priv->viewport[3] * window_scale;
- if (clip)
+ if (!clip)
{
- clip_poly[0] = MAX (clip->x * window_scale, 0);
- clip_poly[1] = MAX (clip->y * window_scale, 0);
- clip_poly[2] = MIN ((clip->x + clip->width) * window_scale, geom.width * window_scale);
- clip_poly[3] = clip_poly[1];
- clip_poly[4] = clip_poly[2];
- clip_poly[5] = MIN ((clip->y + clip->height) * window_scale, geom.height * window_scale);
- clip_poly[6] = clip_poly[0];
- clip_poly[7] = clip_poly[5];
- }
- else
- {
- clip_poly[0] = 0;
- clip_poly[1] = 0;
- clip_poly[2] = geom.width * window_scale;
- clip_poly[3] = 0;
- clip_poly[4] = geom.width * window_scale;
- clip_poly[5] = geom.height * window_scale;
- clip_poly[6] = 0;
- clip_poly[7] = geom.height * window_scale;
+ clutter_stage_view_get_layout (view, &view_layout);
+ clip = &view_layout;
}
+ clip_poly[0] = MAX (clip->x * window_scale, 0);
+ clip_poly[1] = MAX (clip->y * window_scale, 0);
+
+ clip_poly[2] = MIN ((clip->x + clip->width) * window_scale,
+ geom.width * window_scale);
+ clip_poly[3] = clip_poly[1];
+
+ clip_poly[4] = clip_poly[2];
+ clip_poly[5] = MIN ((clip->y + clip->height) * window_scale,
+ geom.height * window_scale);
+
+ clip_poly[6] = clip_poly[0];
+ clip_poly[7] = clip_poly[5];
+
CLUTTER_NOTE (CLIPPING, "Setting stage clip too: "
"x=%f, y=%f, width=%f, height=%f",
clip_poly[0], clip_poly[1],
@@ -684,9 +673,24 @@ _clutter_stage_do_paint (ClutterStage *stage,
priv->current_clip_planes);
_clutter_stage_paint_volume_stack_free_all (stage);
- _clutter_stage_update_active_framebuffer (stage);
+ _clutter_stage_update_active_framebuffer (stage, framebuffer);
clutter_actor_paint (CLUTTER_ACTOR (stage));
+}
+/* This provides a common point of entry for painting the scenegraph
+ * for picking or painting...
+ */
+void
+_clutter_stage_paint_view (ClutterStage *stage,
+ ClutterStageView *view,
+ const cairo_rectangle_int_t *clip)
+{
+ ClutterStagePrivate *priv = stage->priv;
+
+ if (!priv->impl)
+ return;
+
+ clutter_stage_do_paint_view (stage, view, clip);
g_signal_emit (stage, stage_signals[AFTER_PAINT], 0);
}
@@ -736,31 +740,10 @@ clutter_stage_realize (ClutterActor *self)
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
gboolean is_realized;
- /* Make sure the viewport and projection matrix are valid for the
- * first paint (which will likely occur before the ConfigureNotify
- * is received)
- */
- priv->dirty_viewport = TRUE;
- priv->dirty_projection = TRUE;
-
g_assert (priv->impl != NULL);
is_realized = _clutter_stage_window_realize (priv->impl);
- /* ensure that the stage is using the context if the
- * realization sequence was successful
- */
- if (is_realized)
- {
- ClutterBackend *backend = clutter_get_default_backend ();
-
- /* We want to select the context without calling
- clutter_backend_ensure_context so that it doesn't call any
- Cogl functions. Otherwise it would create the Cogl context
- before we get a chance to check whether the GL version is
- valid */
- _clutter_backend_ensure_context_internal (backend, CLUTTER_STAGE (self));
- }
- else
+ if (!is_realized)
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
}
@@ -774,8 +757,6 @@ clutter_stage_unrealize (ClutterActor *self)
_clutter_stage_window_unrealize (priv->impl);
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
-
- clutter_stage_ensure_current (CLUTTER_STAGE (self));
}
static void
@@ -1106,7 +1087,6 @@ _clutter_stage_maybe_relayout (ClutterActor *actor)
static void
clutter_stage_do_redraw (ClutterStage *stage)
{
- ClutterBackend *backend = clutter_get_default_backend ();
ClutterActor *actor = CLUTTER_ACTOR (stage);
ClutterStagePrivate *priv = stage->priv;
@@ -1120,16 +1100,12 @@ clutter_stage_do_redraw (ClutterStage *stage)
_clutter_actor_get_debug_name (actor),
stage);
- _clutter_backend_ensure_context (backend, stage);
-
if (_clutter_context_get_show_fps ())
{
if (priv->fps_timer == NULL)
priv->fps_timer = g_timer_new ();
}
- _clutter_stage_maybe_setup_viewport (stage);
-
_clutter_stage_window_redraw (priv->impl);
if (_clutter_context_get_show_fps ())
@@ -1371,67 +1347,82 @@ read_pixels_to_file (char *filename_stem,
read_count++;
}
-ClutterActor *
-_clutter_stage_do_pick (ClutterStage *stage,
- gint x,
- gint y,
- ClutterPickMode mode)
+static ClutterActor *
+_clutter_stage_do_pick_on_view (ClutterStage *stage,
+ gint x,
+ gint y,
+ ClutterPickMode mode,
+ ClutterStageView *view)
{
ClutterActor *actor = CLUTTER_ACTOR (stage);
ClutterStagePrivate *priv = stage->priv;
+ CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
+ cairo_rectangle_int_t view_layout;
ClutterMainContext *context;
guchar pixel[4] = { 0xff, 0xff, 0xff, 0xff };
CoglColor stage_pick_id;
gboolean dither_enabled_save;
ClutterActor *retval;
- CoglFramebuffer *fb;
gint dirty_x;
gint dirty_y;
gint read_x;
gint read_y;
- float stage_width, stage_height;
int window_scale;
+ float fb_width, fb_height;
+ int viewport_offset_x;
+ int viewport_offset_y;
priv = stage->priv;
- if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
- return actor;
-
- if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_NOP_PICKING))
- return actor;
-
- if (G_UNLIKELY (priv->impl == NULL))
- return actor;
-
- clutter_actor_get_size (CLUTTER_ACTOR (stage), &stage_width, &stage_height);
- if (x < 0 || x >= stage_width || y < 0 || y >= stage_height)
- return actor;
-
context = _clutter_context_get_default ();
- clutter_stage_ensure_current (stage);
window_scale = _clutter_stage_window_get_scale_factor (priv->impl);
+ clutter_stage_view_get_layout (view, &view_layout);
- fb = cogl_get_draw_framebuffer ();
-
- _clutter_backend_ensure_context (context->backend, stage);
+ fb_width = view_layout.width;
+ fb_height = view_layout.height;
+ cogl_push_framebuffer (fb);
/* needed for when a context switch happens */
- _clutter_stage_maybe_setup_viewport (stage);
+ _clutter_stage_maybe_setup_viewport (stage, view);
+
+ /* FIXME: For some reason leaving the cogl clip stack empty causes the
+ * picking to not work at all, so setting it the whole framebuffer content
+ * for now. */
+ cogl_framebuffer_push_scissor_clip (fb, 0, 0,
+ view_layout.width,
+ view_layout.height);
- _clutter_stage_window_get_dirty_pixel (priv->impl, &dirty_x, &dirty_y);
+ _clutter_stage_window_get_dirty_pixel (priv->impl, view, &dirty_x, &dirty_y);
+ dirty_x -= view_layout.x;
+ dirty_y -= view_layout.y;
if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
- cogl_framebuffer_push_scissor_clip (fb, dirty_x * window_scale, dirty_y * window_scale, 1, 1);
+ {
+ CLUTTER_NOTE (PICK, "Pushing pick scissor clip x: %d, y: %d, 1x1",
+ dirty_x * window_scale,
+ dirty_y * window_scale);
+ cogl_framebuffer_push_scissor_clip (fb, dirty_x * window_scale, dirty_y * window_scale, 1, 1);
+ }
- cogl_set_viewport (priv->viewport[0] * window_scale - x * window_scale + dirty_x * window_scale,
- priv->viewport[1] * window_scale - y * window_scale + dirty_y * window_scale,
+ viewport_offset_x = x * window_scale - dirty_x * window_scale;
+ viewport_offset_y = y * window_scale - dirty_y * window_scale;
+ CLUTTER_NOTE (PICK, "Setting viewport to %f, %f, %f, %f",
+ priv->viewport[0] * window_scale - viewport_offset_x,
+ priv->viewport[1] * window_scale - viewport_offset_y,
+ priv->viewport[2] * window_scale,
+ priv->viewport[3] * window_scale);
+ cogl_set_viewport (priv->viewport[0] * window_scale - viewport_offset_x,
+ priv->viewport[1] * window_scale - viewport_offset_y,
priv->viewport[2] * window_scale,
priv->viewport[3] * window_scale);
read_x = dirty_x * window_scale;
read_y = dirty_y * window_scale;
- CLUTTER_NOTE (PICK, "Performing pick at %i,%i", x, y);
+ CLUTTER_NOTE (PICK, "Performing pick at %i,%i on view %dx%d+%d+%d",
+ x, y,
+ view_layout.width, view_layout.height,
+ view_layout.x, view_layout.y);
cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255);
cogl_clear (&stage_pick_id, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH);
@@ -1444,7 +1435,7 @@ _clutter_stage_do_pick (ClutterStage *stage,
* are drawn offscreen (as we never swap buffers)
*/
context->pick_mode = mode;
- _clutter_stage_do_paint (stage, NULL);
+ _clutter_stage_paint_view (stage, view, NULL);
context->pick_mode = CLUTTER_PICK_NONE;
/* Read the color of the screen co-ords pixel. RGBA_8888_PRE is used
@@ -1462,11 +1453,11 @@ _clutter_stage_do_pick (ClutterStage *stage,
if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
{
char *file_name =
- g_strconcat ("pick-buffer-",
- _clutter_actor_get_debug_name (actor),
- NULL);
+ g_strdup_printf ("pick-buffer-%s-view-x-%d",
+ _clutter_actor_get_debug_name (actor),
+ view_layout.x);
- read_pixels_to_file (file_name, 0, 0, stage_width, stage_height);
+ read_pixels_to_file (file_name, 0, 0, fb_width, fb_height);
g_free (file_name);
}
@@ -1477,6 +1468,8 @@ _clutter_stage_do_pick (ClutterStage *stage,
if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
cogl_framebuffer_pop_clip (fb);
+ cogl_framebuffer_pop_clip (fb);
+
_clutter_stage_dirty_viewport (stage);
if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
@@ -1486,11 +1479,74 @@ _clutter_stage_do_pick (ClutterStage *stage,
guint32 id_ = _clutter_pixel_to_id (pixel);
retval = _clutter_stage_get_actor_by_pick_id (stage, id_);
+ CLUTTER_NOTE (PICK, "Picking actor %s with id %u (pixel: 0x%x%x%x%x",
+ G_OBJECT_TYPE_NAME (retval),
+ id_,
+ pixel[0], pixel[1], pixel[2], pixel[3]);
}
+ cogl_pop_framebuffer ();
+
return retval;
}
+static ClutterStageView *
+get_view_at (ClutterStage *stage,
+ int x,
+ int y)
+{
+ ClutterStagePrivate *priv = stage->priv;
+ GList *l;
+
+ for (l = _clutter_stage_window_get_views (priv->impl); l; l = l->next)
+ {
+ ClutterStageView *view = l->data;
+ cairo_rectangle_int_t view_layout;
+
+ clutter_stage_view_get_layout (view, &view_layout);
+ if (x >= view_layout.x &&
+ x < view_layout.x + view_layout.width &&
+ y >= view_layout.y &&
+ y < view_layout.y + view_layout.height)
+ return view;
+ }
+
+ return NULL;
+}
+
+ClutterActor *
+_clutter_stage_do_pick (ClutterStage *stage,
+ gint x,
+ gint y,
+ ClutterPickMode mode)
+{
+ ClutterActor *actor = CLUTTER_ACTOR (stage);
+ ClutterStagePrivate *priv = stage->priv;
+ float stage_width, stage_height;
+ ClutterStageView *view = NULL;
+
+ priv = stage->priv;
+
+ if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
+ return actor;
+
+ if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_NOP_PICKING))
+ return actor;
+
+ if (G_UNLIKELY (priv->impl == NULL))
+ return actor;
+
+ clutter_actor_get_size (CLUTTER_ACTOR (stage), &stage_width, &stage_height);
+ if (x < 0 || x >= stage_width || y < 0 || y >= stage_height)
+ return actor;
+
+ view = get_view_at (stage, x, y);
+ if (view)
+ return _clutter_stage_do_pick_on_view (stage, x, y, mode, view);
+
+ return actor;
+}
+
static gboolean
clutter_stage_real_delete_event (ClutterStage *stage,
ClutterEvent *event)
@@ -2339,7 +2395,7 @@ clutter_stage_set_perspective_internal (ClutterStage *stage,
cogl_matrix_get_inverse (&priv->projection,
&priv->inverse_projection);
- priv->dirty_projection = TRUE;
+ _clutter_stage_dirty_projection (stage);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
}
@@ -2419,7 +2475,19 @@ _clutter_stage_get_projection_matrix (ClutterStage *stage,
void
_clutter_stage_dirty_projection (ClutterStage *stage)
{
- stage->priv->dirty_projection = TRUE;
+ ClutterStagePrivate *priv;
+ GList *l;
+
+ g_return_if_fail (CLUTTER_IS_STAGE (stage));
+
+ priv = stage->priv;
+
+ for (l = _clutter_stage_window_get_views (priv->impl); l; l = l->next)
+ {
+ ClutterStageView *view = l->data;
+
+ clutter_stage_view_set_dirty_projection (view, TRUE);
+ }
}
/*
@@ -2484,7 +2552,7 @@ _clutter_stage_set_viewport (ClutterStage *stage,
priv->viewport[2] = width;
priv->viewport[3] = height;
- priv->dirty_viewport = TRUE;
+ _clutter_stage_dirty_viewport (stage);
queue_full_redraw (stage);
}
@@ -2496,7 +2564,19 @@ _clutter_stage_set_viewport (ClutterStage *stage,
void
_clutter_stage_dirty_viewport (ClutterStage *stage)
{
- stage->priv->dirty_viewport = TRUE;
+ ClutterStagePrivate *priv;
+ GList *l;
+
+ g_return_if_fail (CLUTTER_IS_STAGE (stage));
+
+ priv = stage->priv;
+
+ for (l = _clutter_stage_window_get_views (priv->impl); l; l = l->next)
+ {
+ ClutterStageView *view = l->data;
+
+ clutter_stage_view_set_dirty_viewport (view, TRUE);
+ }
}
/*
@@ -2758,14 +2838,18 @@ clutter_stage_read_pixels (ClutterStage *stage,
gint width,
gint height)
{
+ ClutterStagePrivate *priv;
ClutterActorBox box;
- guchar *pixels;
+ GList *l;
+ ClutterStageView *view;
+ cairo_region_t *clip;
+ cairo_rectangle_int_t clip_rect;
+ CoglFramebuffer *framebuffer;
+ uint8_t *pixels;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
- /* Force a redraw of the stage before reading back pixels */
- clutter_stage_ensure_current (stage);
- clutter_actor_paint (CLUTTER_ACTOR (stage));
+ priv = stage->priv;
clutter_actor_get_allocation_box (CLUTTER_ACTOR (stage), &box);
@@ -2775,12 +2859,42 @@ clutter_stage_read_pixels (ClutterStage *stage,
if (height < 0)
height = ceilf (box.y2 - box.y1);
- pixels = g_malloc (height * width * 4);
+ l = _clutter_stage_window_get_views (priv->impl);
- cogl_read_pixels (x, y, width, height,
- COGL_READ_PIXELS_COLOR_BUFFER,
- COGL_PIXEL_FORMAT_RGBA_8888,
- pixels);
+ if (!l)
+ return NULL;
+
+ /* XXX: We only read the first view. Needs different API for multi view screen
+ * capture. */
+ view = l->data;
+
+ clutter_stage_view_get_layout (view, &clip_rect);
+ clip = cairo_region_create_rectangle (&clip_rect);
+ cairo_region_intersect_rectangle (clip,
+ &(cairo_rectangle_int_t) {
+ .x = x,
+ .y = y,
+ .width = width,
+ .height = height,
+ });
+ cairo_region_get_extents (clip, &clip_rect);
+ cairo_region_destroy (clip);
+
+ if (clip_rect.width == 0 || clip_rect.height == 0)
+ return NULL;
+
+ framebuffer = clutter_stage_view_get_framebuffer (view);
+ cogl_push_framebuffer (framebuffer);
+ clutter_stage_do_paint_view (stage, view, &clip_rect);
+
+ pixels = g_malloc0 (clip_rect.width * clip_rect.height * 4);
+ cogl_framebuffer_read_pixels (framebuffer,
+ clip_rect.x, clip_rect.y,
+ clip_rect.width, clip_rect.height,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ pixels);
+
+ cogl_pop_framebuffer ();
return pixels;
}
@@ -3241,16 +3355,12 @@ clutter_stage_new (void)
* be used by applications.
*
* Since: 0.8
+ * Deprecated: mutter: This function does not do anything.
*/
void
clutter_stage_ensure_current (ClutterStage *stage)
{
- ClutterBackend *backend;
-
g_return_if_fail (CLUTTER_IS_STAGE (stage));
-
- backend = clutter_get_default_backend ();
- _clutter_backend_ensure_context (backend, stage);
}
/**
@@ -3425,14 +3535,18 @@ calculate_z_translation (float z_near)
}
void
-_clutter_stage_maybe_setup_viewport (ClutterStage *stage)
+_clutter_stage_maybe_setup_viewport (ClutterStage *stage,
+ ClutterStageView *view)
{
ClutterStagePrivate *priv = stage->priv;
- if (priv->dirty_viewport)
+ if (clutter_stage_view_is_dirty_viewport (view))
{
+ cairo_rectangle_int_t view_layout;
ClutterPerspective perspective;
int window_scale;
+ int viewport_offset_x;
+ int viewport_offset_y;
float z_2d;
CLUTTER_NOTE (PAINT,
@@ -3441,9 +3555,12 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage)
priv->viewport[3]);
window_scale = _clutter_stage_window_get_scale_factor (priv->impl);
+ clutter_stage_view_get_layout (view, &view_layout);
- cogl_set_viewport (priv->viewport[0] * window_scale,
- priv->viewport[1] * window_scale,
+ viewport_offset_x = view_layout.x * window_scale;
+ viewport_offset_y = view_layout.y * window_scale;
+ cogl_set_viewport (priv->viewport[0] * window_scale - viewport_offset_x,
+ priv->viewport[1] * window_scale - viewport_offset_y,
priv->viewport[2] * window_scale,
priv->viewport[3] * window_scale);
@@ -3481,14 +3598,14 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage)
clutter_stage_apply_scale (stage);
- priv->dirty_viewport = FALSE;
+ clutter_stage_view_set_dirty_viewport (view, FALSE);
}
- if (priv->dirty_projection)
+ if (clutter_stage_view_is_dirty_projection (view))
{
cogl_set_projection_matrix (&priv->projection);
- priv->dirty_projection = FALSE;
+ clutter_stage_view_set_dirty_projection (view, FALSE);
}
}
diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h
index 8a55efb..47cff93 100644
--- a/clutter/clutter/clutter-stage.h
+++ b/clutter/clutter/clutter-stage.h
@@ -229,9 +229,6 @@ guchar * clutter_stage_read_pixels (ClutterStage
CLUTTER_AVAILABLE_IN_ALL
void clutter_stage_get_redraw_clip_bounds (ClutterStage *stage,
cairo_rectangle_int_t *clip);
-
-CLUTTER_AVAILABLE_IN_ALL
-void clutter_stage_ensure_current (ClutterStage *stage);
CLUTTER_AVAILABLE_IN_ALL
void clutter_stage_ensure_viewport (ClutterStage *stage);
CLUTTER_AVAILABLE_IN_ALL
diff --git a/clutter/clutter/clutter-util.c b/clutter/clutter/clutter-util.c
index 04c2ca1..14ef740 100644
--- a/clutter/clutter/clutter-util.c
+++ b/clutter/clutter/clutter-util.c
@@ -161,6 +161,39 @@ _clutter_util_rectangle_union (const cairo_rectangle_int_t *src1,
dest->y = dest_y;
}
+gboolean
+_clutter_util_rectangle_intersection (const cairo_rectangle_int_t *src1,
+ const cairo_rectangle_int_t *src2,
+ cairo_rectangle_int_t *dest)
+{
+ int x1, y1, x2, y2;
+
+ x1 = MAX (src1->x, src2->x);
+ y1 = MAX (src1->y, src2->y);
+
+ x2 = MIN (src1->x + (int) src1->width, src2->x + (int) src2->width);
+ y2 = MIN (src1->y + (int) src1->height, src2->y + (int) src2->height);
+
+ if (x1 >= x2 || y1 >= y2)
+ {
+ dest->x = 0;
+ dest->y = 0;
+ dest->width = 0;
+ dest->height = 0;
+
+ return FALSE;
+ }
+ else
+ {
+ dest->x = x1;
+ dest->y = y1;
+ dest->width = x2 - x1;
+ dest->height = y2 - y1;
+
+ return TRUE;
+ }
+}
+
float
_clutter_util_matrix_determinant (const ClutterMatrix *matrix)
{
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
index 90bc26f..07e10a2 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
@@ -36,6 +36,8 @@
#include "clutter-stage-cogl.h"
+#include <stdlib.h>
+
#include "clutter-actor-private.h"
#include "clutter-backend-private.h"
#include "clutter-debug.h"
@@ -46,6 +48,18 @@
#include "clutter-private.h"
#include "clutter-stage-private.h"
+typedef struct _ClutterStageViewCoglPrivate
+{
+ /* Stores a list of previous damaged areas in the stage coordinate space */
+#define DAMAGE_HISTORY_MAX 16
+#define DAMAGE_HISTORY(x) ((x) & (DAMAGE_HISTORY_MAX - 1))
+ cairo_rectangle_int_t damage_history[DAMAGE_HISTORY_MAX];
+ unsigned int damage_index;
+} ClutterStageViewCoglPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageViewCogl, clutter_stage_view_cogl,
+ CLUTTER_TYPE_STAGE_VIEW)
+
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterStageCogl,
@@ -74,8 +88,6 @@ clutter_stage_cogl_unrealize (ClutterStageWindow *stage_window)
stage_cogl->frame_closure);
stage_cogl->frame_closure = NULL;
}
-
- stage_cogl->pending_swaps = 0;
}
static void
@@ -340,51 +352,156 @@ clutter_stage_cogl_get_redraw_clip_bounds (ClutterStageWindow *stage_window,
}
static inline gboolean
-valid_buffer_age (ClutterStageCogl *stage_cogl, int age)
+valid_buffer_age (ClutterStageViewCogl *view_cogl,
+ int age)
{
+ ClutterStageViewCoglPrivate *view_priv =
+ clutter_stage_view_cogl_get_instance_private (view_cogl);
+
if (age <= 0)
return FALSE;
- return age < MIN (stage_cogl->damage_index, DAMAGE_HISTORY_MAX);
+ return age < MIN (view_priv->damage_index, DAMAGE_HISTORY_MAX);
+}
+
+static gboolean
+swap_framebuffer (ClutterStageWindow *stage_window,
+ ClutterStageView *view,
+ cairo_rectangle_int_t *swap_region,
+ gboolean swap_with_damage)
+{
+ CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
+ int damage[4], ndamage;
+
+ damage[0] = swap_region->x;
+ damage[1] = swap_region->y;
+ damage[2] = swap_region->width;
+ damage[3] = swap_region->height;
+
+ if (swap_region->width != 0)
+ ndamage = 1;
+ else
+ ndamage = 0;
+
+ if (cogl_is_onscreen (framebuffer))
+ {
+ CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+
+ /* push on the screen */
+ if (ndamage == 1 && !swap_with_damage)
+ {
+ CLUTTER_NOTE (BACKEND,
+ "cogl_onscreen_swap_region (onscreen: %p, "
+ "x: %d, y: %d, "
+ "width: %d, height: %d)",
+ onscreen,
+ damage[0], damage[1], damage[2], damage[3]);
+
+ cogl_onscreen_swap_region (onscreen,
+ damage, ndamage);
+
+ return FALSE;
+ }
+ else
+ {
+ CLUTTER_NOTE (BACKEND, "cogl_onscreen_swap_buffers (onscreen: %p)",
+ onscreen);
+
+ cogl_onscreen_swap_buffers_with_damage (onscreen,
+ damage, ndamage);
+
+ return TRUE;
+ }
+ }
+ else
+ {
+ CLUTTER_NOTE (BACKEND, "cogl_framebuffer_finish (framebuffer: %p)",
+ framebuffer);
+ cogl_framebuffer_finish (framebuffer);
+
+ return FALSE;
+ }
}
-/* XXX: This is basically identical to clutter_stage_glx_redraw */
static void
-clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
+paint_stage (ClutterStageCogl *stage_cogl,
+ ClutterStageView *view,
+ const cairo_rectangle_int_t *clip)
+{
+ ClutterStage *stage = stage_cogl->wrapper;
+
+ _clutter_stage_maybe_setup_viewport (stage, view);
+ _clutter_stage_paint_view (stage, view, clip);
+}
+
+static void
+fill_current_damage_history_and_step (ClutterStageView *view)
+{
+ ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
+ ClutterStageViewCoglPrivate *view_priv =
+ clutter_stage_view_cogl_get_instance_private (view_cogl);
+ cairo_rectangle_int_t view_rect;
+ cairo_rectangle_int_t *current_damage;
+
+ current_damage =
+ &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index)];
+ clutter_stage_view_get_layout (view, &view_rect);
+
+ *current_damage = view_rect;
+ view_priv->damage_index++;
+}
+
+static gboolean
+clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
+ ClutterStageView *view)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
- CoglOnscreen *onscreen;
- cairo_rectangle_int_t geom;
+ ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
+ ClutterStageViewCoglPrivate *view_priv =
+ clutter_stage_view_cogl_get_instance_private (view_cogl);
+ CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
+ cairo_rectangle_int_t view_rect;
gboolean have_clip;
gboolean may_use_clipped_redraw;
gboolean use_clipped_redraw;
gboolean can_blit_sub_buffer;
gboolean has_buffer_age;
+ gboolean do_swap_buffer;
+ gboolean swap_with_damage;
ClutterActor *wrapper;
- cairo_rectangle_int_t *clip_region;
- int damage[4], ndamage;
- gboolean force_swap;
+ cairo_rectangle_int_t redraw_clip;
+ cairo_rectangle_int_t swap_region;
+ cairo_rectangle_int_t clip_region;
+ gboolean clip_region_empty;
int window_scale;
wrapper = CLUTTER_ACTOR (stage_cogl->wrapper);
- onscreen = _clutter_stage_window_get_legacy_onscreen (stage_window);
- if (!onscreen)
- return;
+ clutter_stage_view_get_layout (view, &view_rect);
can_blit_sub_buffer =
+ cogl_is_onscreen (fb) &&
cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION);
- has_buffer_age = cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
-
- _clutter_stage_window_get_geometry (stage_window, &geom);
+ has_buffer_age =
+ cogl_is_onscreen (fb) &&
+ cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
/* NB: a zero width redraw clip == full stage redraw */
- have_clip = (stage_cogl->bounding_redraw_clip.width != 0 &&
- !(stage_cogl->bounding_redraw_clip.x == 0 &&
- stage_cogl->bounding_redraw_clip.y == 0 &&
- stage_cogl->bounding_redraw_clip.width == geom.width &&
- stage_cogl->bounding_redraw_clip.height == geom.height));
+ if (stage_cogl->bounding_redraw_clip.width == 0)
+ have_clip = FALSE;
+ else
+ {
+ redraw_clip = stage_cogl->bounding_redraw_clip;
+ _clutter_util_rectangle_intersection (&redraw_clip,
+ &view_rect,
+ &redraw_clip);
+
+ have_clip = !(redraw_clip.x == view_rect.x &&
+ redraw_clip.y == view_rect.y &&
+ redraw_clip.width == view_rect.width &&
+ redraw_clip.height == view_rect.height);
+ }
may_use_clipped_redraw = FALSE;
if (_clutter_stage_window_can_clip_redraws (stage_window) &&
@@ -392,13 +509,15 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
have_clip &&
/* some drivers struggle to get going and produce some junk
* frames when starting up... */
- stage_cogl->frame_count > 3)
+ cogl_onscreen_get_frame_counter (COGL_ONSCREEN (fb)) > 3)
{
may_use_clipped_redraw = TRUE;
- clip_region = &stage_cogl->bounding_redraw_clip;
+ clip_region = redraw_clip;
}
else
- clip_region = NULL;
+ {
+ clip_region = (cairo_rectangle_int_t){ 0 };
+ }
if (may_use_clipped_redraw &&
G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
@@ -406,70 +525,87 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
else
use_clipped_redraw = FALSE;
- force_swap = FALSE;
+ clip_region_empty = may_use_clipped_redraw && clip_region.width == 0;
window_scale = _clutter_stage_window_get_scale_factor (stage_window);
+ swap_with_damage = FALSE;
if (has_buffer_age)
{
- cairo_rectangle_int_t *current_damage =
- &stage_cogl->damage_history[DAMAGE_HISTORY (stage_cogl->damage_index++)];
-
- if (use_clipped_redraw)
- {
- int age = cogl_onscreen_get_buffer_age (onscreen), i;
-
- *current_damage = *clip_region;
-
- if (valid_buffer_age (stage_cogl, age))
- {
- for (i = 1; i <= age; i++)
- _clutter_util_rectangle_union (clip_region,
- &stage_cogl->damage_history[DAMAGE_HISTORY
(stage_cogl->damage_index - i - 1)],
- clip_region);
-
- CLUTTER_NOTE (CLIPPING, "Reusing back buffer(age=%d) - repairing region: x=%d, y=%d, width=%d,
height=%d\n",
- age,
- clip_region->x,
- clip_region->y,
- clip_region->width,
- clip_region->height);
- force_swap = TRUE;
- }
- else
- {
- CLUTTER_NOTE (CLIPPING, "Invalid back buffer(age=%d): forcing full redraw\n", age);
- use_clipped_redraw = FALSE;
- }
- }
- else
- {
- current_damage->x = 0;
- current_damage->y = 0;
- current_damage->width = geom.width;
- current_damage->height = geom.height;
- }
+ if (use_clipped_redraw && !clip_region_empty)
+ {
+ int age, i;
+ cairo_rectangle_int_t *current_damage =
+ &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index++)];
+
+ age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (fb));
+
+ if (valid_buffer_age (view_cogl, age))
+ {
+ *current_damage = clip_region;
+
+ for (i = 1; i <= age; i++)
+ {
+ cairo_rectangle_int_t *damage =
+ &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index - i - 1)];
+
+ _clutter_util_rectangle_union (&clip_region, damage, &clip_region);
+ }
+
+ /* Update the bounding redraw clip state with the extra damage. */
+ _clutter_util_rectangle_union (&stage_cogl->bounding_redraw_clip,
+ &clip_region,
+ &stage_cogl->bounding_redraw_clip);
+
+ CLUTTER_NOTE (CLIPPING, "Reusing back buffer(age=%d) - repairing region: x=%d, y=%d, width=%d,
height=%d\n",
+ age,
+ clip_region.x,
+ clip_region.y,
+ clip_region.width,
+ clip_region.height);
+
+ swap_with_damage = TRUE;
+ }
+ else
+ {
+ CLUTTER_NOTE (CLIPPING, "Invalid back buffer(age=%d): forcing full redraw\n", age);
+ use_clipped_redraw = FALSE;
+ *current_damage = view_rect;
+ }
+ }
+ else if (!use_clipped_redraw)
+ {
+ fill_current_damage_history_and_step (view);
+ }
}
- if (use_clipped_redraw)
+ cogl_push_framebuffer (fb);
+ if (use_clipped_redraw && clip_region_empty)
{
- CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
+ CLUTTER_NOTE (CLIPPING, "Empty stage output paint\n");
+ }
+ else if (use_clipped_redraw)
+ {
+ int scissor_x;
+ int scissor_y;
CLUTTER_NOTE (CLIPPING,
"Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n",
- clip_region->x,
- clip_region->y,
- clip_region->width,
- clip_region->height);
+ clip_region.x,
+ clip_region.y,
+ clip_region.width,
+ clip_region.height);
stage_cogl->using_clipped_redraw = TRUE;
+ scissor_x = (clip_region.x - view_rect.x) * window_scale;
+ scissor_y = (clip_region.y - view_rect.y) * window_scale;
cogl_framebuffer_push_scissor_clip (fb,
- clip_region->x * window_scale,
- clip_region->y * window_scale,
- clip_region->width * window_scale,
- clip_region->height * window_scale);
- _clutter_stage_do_paint (CLUTTER_STAGE (wrapper), clip_region);
+ scissor_x,
+ scissor_y,
+ clip_region.width * window_scale,
+ clip_region.height * window_scale);
+ paint_stage (stage_cogl, view, &clip_region);
cogl_framebuffer_pop_clip (fb);
stage_cogl->using_clipped_redraw = FALSE;
@@ -481,26 +617,37 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
/* If we are trying to debug redraw issues then we want to pass
* the bounding_redraw_clip so it can be visualized */
if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS) &&
- may_use_clipped_redraw)
+ may_use_clipped_redraw &&
+ !clip_region_empty)
{
- _clutter_stage_do_paint (CLUTTER_STAGE (wrapper), clip_region);
+ int scissor_x;
+ int scissor_y;
+
+ scissor_x = (clip_region.x - view_rect.x) * window_scale;;
+ scissor_y = (clip_region.y - view_rect.y) * window_scale;
+ cogl_framebuffer_push_scissor_clip (fb,
+ scissor_x,
+ scissor_y,
+ clip_region.width * window_scale,
+ clip_region.height * window_scale);
+ paint_stage (stage_cogl, view, &clip_region);
+ cogl_framebuffer_pop_clip (fb);
}
else
- _clutter_stage_do_paint (CLUTTER_STAGE (wrapper), NULL);
+ paint_stage (stage_cogl, view, &view_rect);
}
+ cogl_pop_framebuffer ();
if (may_use_clipped_redraw &&
G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)))
{
- CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
CoglContext *ctx = cogl_framebuffer_get_context (fb);
static CoglPipeline *outline = NULL;
- cairo_rectangle_int_t *clip = &stage_cogl->bounding_redraw_clip;
ClutterActor *actor = CLUTTER_ACTOR (wrapper);
- float x_1 = clip->x * window_scale;
- float x_2 = clip->x + clip->width * window_scale;
- float y_1 = clip->y * window_scale;
- float y_2 = clip->y + clip->height * window_scale;
+ float x_1 = redraw_clip.x;
+ float x_2 = redraw_clip.x + redraw_clip.width;
+ float y_1 = redraw_clip.y;
+ float y_2 = redraw_clip.y + redraw_clip.height;
CoglVertexP2 quad[4] = {
{ x_1, y_1 },
{ x_2, y_1 },
@@ -525,9 +672,7 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
cogl_matrix_init_identity (&modelview);
_clutter_actor_apply_modelview_transform (actor, &modelview);
cogl_framebuffer_set_modelview_matrix (fb, &modelview);
- cogl_framebuffer_draw_primitive (COGL_FRAMEBUFFER (onscreen),
- outline,
- prim);
+ cogl_framebuffer_draw_primitive (fb, outline, prim);
cogl_framebuffer_pop_matrix (fb);
cogl_object_unref (prim);
}
@@ -540,45 +685,77 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
* the resize anyway so it should only exhibit temporary
* artefacts.
*/
- if (use_clipped_redraw || force_swap)
+ if (use_clipped_redraw)
{
- damage[0] = clip_region->x * window_scale;
- damage[1] = clip_region->y * window_scale;
- damage[2] = clip_region->width * window_scale;
- damage[3] = clip_region->height * window_scale;
- ndamage = 1;
+ if (use_clipped_redraw && clip_region_empty)
+ {
+ do_swap_buffer = FALSE;
+ }
+ else if (use_clipped_redraw)
+ {
+ swap_region = (cairo_rectangle_int_t) {
+ .x = (clip_region.x - view_rect.x) * window_scale,
+ .y = (clip_region.y - view_rect.y) * window_scale,
+ .width = clip_region.width * window_scale,
+ .height = clip_region.height * window_scale,
+ };
+ g_assert (swap_region.width > 0);
+ do_swap_buffer = TRUE;
+ }
+ else
+ {
+ swap_region = (cairo_rectangle_int_t) {
+ .x = 0,
+ .y = 0,
+ .width = view_rect.width * window_scale,
+ .height = view_rect.height * window_scale,
+ };
+ do_swap_buffer = TRUE;
+ }
}
else
{
- ndamage = 0;
+ swap_region = (cairo_rectangle_int_t) { 0 };
+ do_swap_buffer = TRUE;
}
- /* push on the screen */
- if (use_clipped_redraw && !force_swap)
+ if (do_swap_buffer)
{
- CLUTTER_NOTE (BACKEND,
- "cogl_onscreen_swap_region (onscreen: %p, "
- "x: %d, y: %d, "
- "width: %d, height: %d)",
- onscreen,
- damage[0], damage[1], damage[2], damage[3]);
-
- cogl_onscreen_swap_region (onscreen,
- damage, ndamage);
+ return swap_framebuffer (stage_window,
+ view,
+ &swap_region,
+ swap_with_damage);
}
else
{
- CLUTTER_NOTE (BACKEND, "cogl_onscreen_swap_buffers (onscreen: %p)",
- onscreen);
+ return FALSE;
+ }
+}
+static void
+clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
+{
+ ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
+ gboolean swap_event = FALSE;
+ GList *l;
+
+ for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
+ {
+ ClutterStageView *view = l->data;
+
+ swap_event =
+ clutter_stage_cogl_redraw_view (stage_window, view) || swap_event;
+ }
+
+ _clutter_stage_window_finish_frame (stage_window);
+
+ if (swap_event)
+ {
/* If we have swap buffer events then cogl_onscreen_swap_buffers
* will return immediately and we need to track that there is a
* swap in progress... */
if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
stage_cogl->pending_swaps++;
-
- cogl_onscreen_swap_buffers_with_damage (onscreen,
- damage, ndamage);
}
/* reset the redraw clipping for the next paint... */
@@ -587,22 +764,15 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
stage_cogl->frame_count++;
}
-static CoglFramebuffer *
-clutter_stage_cogl_get_active_framebuffer (ClutterStageWindow *stage_window)
-{
- CoglOnscreen *onscreen =
- _clutter_stage_window_get_legacy_onscreen (stage_window);
-
- return COGL_FRAMEBUFFER (onscreen);
-}
-
static void
clutter_stage_cogl_get_dirty_pixel (ClutterStageWindow *stage_window,
+ ClutterStageView *view,
int *x,
int *y)
{
- ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
- gboolean has_buffer_age = cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
+ gboolean has_buffer_age =
+ cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
+ cairo_rectangle_int_t *rect;
if (!has_buffer_age)
{
@@ -611,9 +781,11 @@ clutter_stage_cogl_get_dirty_pixel (ClutterStageWindow *stage_window,
}
else
{
- cairo_rectangle_int_t *rect;
+ ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
+ ClutterStageViewCoglPrivate *view_priv =
+ clutter_stage_view_cogl_get_instance_private (view_cogl);
- rect = &stage_cogl->damage_history[DAMAGE_HISTORY (stage_cogl->damage_index-1)];
+ rect = &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index - 1)];
*x = rect->x;
*y = rect->y;
}
@@ -636,7 +808,6 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
iface->ignoring_redraw_clips = clutter_stage_cogl_ignoring_redraw_clips;
iface->get_redraw_clip_bounds = clutter_stage_cogl_get_redraw_clip_bounds;
iface->redraw = clutter_stage_cogl_redraw;
- iface->get_active_framebuffer = clutter_stage_cogl_get_active_framebuffer;
iface->get_dirty_pixel = clutter_stage_cogl_get_dirty_pixel;
}
@@ -683,3 +854,13 @@ _clutter_stage_cogl_init (ClutterStageCogl *stage)
stage->update_time = -1;
}
+
+static void
+clutter_stage_view_cogl_init (ClutterStageViewCogl *view_cogl)
+{
+}
+
+static void
+clutter_stage_view_cogl_class_init (ClutterStageViewCoglClass *klass)
+{
+}
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.h b/clutter/clutter/cogl/clutter-stage-cogl.h
index 690a012..6a4a773 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.h
+++ b/clutter/clutter/cogl/clutter-stage-cogl.h
@@ -11,6 +11,8 @@
#include <X11/Xutil.h>
#endif
+#include "clutter/clutter-stage-window.h"
+
G_BEGIN_DECLS
#define CLUTTER_TYPE_STAGE_COGL (_clutter_stage_cogl_get_type ())
@@ -25,6 +27,17 @@ typedef struct _ClutterStageCoglClass ClutterStageCoglClass;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterStageCogl, g_object_unref)
+#define CLUTTER_TYPE_STAGE_VIEW_COGL (clutter_stage_view_cogl_get_type ())
+CLUTTER_AVAILABLE_IN_MUTTER
+G_DECLARE_DERIVABLE_TYPE (ClutterStageViewCogl, clutter_stage_view_cogl,
+ CLUTTER, STAGE_VIEW_COGL,
+ ClutterStageView)
+
+struct _ClutterStageViewCoglClass
+{
+ ClutterStageViewClass parent_class;
+};
+
struct _ClutterStageCogl
{
GObject parent_instance;
@@ -50,12 +63,6 @@ struct _ClutterStageCogl
cairo_rectangle_int_t bounding_redraw_clip;
- /* Stores a list of previous damaged areas */
-#define DAMAGE_HISTORY_MAX 16
-#define DAMAGE_HISTORY(x) ((x) & (DAMAGE_HISTORY_MAX - 1))
- cairo_rectangle_int_t damage_history[DAMAGE_HISTORY_MAX];
- unsigned int damage_index;
-
guint initialized_redraw_clip : 1;
/* TRUE if the current paint cycle has a clipped redraw. In that
diff --git a/clutter/clutter/deprecated/clutter-stage.h b/clutter/clutter/deprecated/clutter-stage.h
index e56e299..1a0f288 100644
--- a/clutter/clutter/deprecated/clutter-stage.h
+++ b/clutter/clutter/deprecated/clutter-stage.h
@@ -97,6 +97,9 @@ CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_get_background_color)
void clutter_stage_get_color (ClutterStage *stage,
ClutterColor *color);
+CLUTTER_DEPRECATED_IN_MUTTER
+void clutter_stage_ensure_current (ClutterStage *stage);
+
G_END_DECLS
#endif /* __CLUTTER_STAGE_DEPRECATED_H__ */
diff --git a/clutter/clutter/x11/clutter-stage-x11.c b/clutter/clutter/x11/clutter-stage-x11.c
index cd5c3bc..2838292 100644
--- a/clutter/clutter/x11/clutter-stage-x11.c
+++ b/clutter/clutter/x11/clutter-stage-x11.c
@@ -445,6 +445,8 @@ clutter_stage_x11_unrealize (ClutterStageWindow *stage_window)
clutter_stage_window_parent_iface->unrealize (stage_window);
+ g_list_free (stage_x11->legacy_views);
+ g_clear_object (&stage_x11->legacy_view);
g_clear_pointer (&stage_x11->onscreen, cogl_object_unref);
}
@@ -626,6 +628,11 @@ clutter_stage_x11_realize (ClutterStageWindow *stage_window)
stage_x11->onscreen = cogl_onscreen_new (backend->cogl_context, width, height);
+ if (stage_x11->legacy_view)
+ g_object_set (G_OBJECT (stage_x11->legacy_view),
+ "framebuffer", stage_x11->onscreen,
+ NULL);
+
/* We just created a window of the size of the actor. No need to fix
the size of the stage, just update it. */
stage_x11->xwin_width = width;
@@ -892,12 +899,34 @@ clutter_stage_x11_get_scale_factor (ClutterStageWindow *stage_window)
return stage_x11->scale_factor;
}
-static CoglFramebuffer *
-clutter_stage_x11_get_legacy_onscreen (ClutterStageWindow *stage_window)
+static void
+ensure_legacy_view (ClutterStageWindow *stage_window)
+{
+ ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
+ cairo_rectangle_int_t view_layout;
+ CoglFramebuffer *framebuffer;
+
+ if (stage_x11->legacy_view)
+ return;
+
+ _clutter_stage_window_get_geometry (stage_window, &view_layout);
+ framebuffer = COGL_FRAMEBUFFER (stage_x11->onscreen);
+ stage_x11->legacy_view = g_object_new (CLUTTER_TYPE_STAGE_VIEW_COGL,
+ "layout", &view_layout,
+ "framebuffer", framebuffer,
+ NULL);
+ stage_x11->legacy_views = g_list_append (stage_x11->legacy_views,
+ stage_x11->legacy_view);
+}
+
+static GList *
+clutter_stage_x11_get_views (ClutterStageWindow *stage_window)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
- return stage_x11->onscreen;
+ ensure_legacy_view (stage_window);
+
+ return stage_x11->legacy_views;
}
static CoglFrameClosure *
@@ -1007,7 +1036,7 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
iface->can_clip_redraws = clutter_stage_x11_can_clip_redraws;
iface->set_scale_factor = clutter_stage_x11_set_scale_factor;
iface->get_scale_factor = clutter_stage_x11_get_scale_factor;
- iface->get_legacy_onscreen = clutter_stage_x11_get_legacy_onscreen;
+ iface->get_views = clutter_stage_x11_get_views;
iface->set_frame_callback = clutter_stage_x11_set_frame_callback;
iface->remove_frame_callback = clutter_stage_x11_remove_frame_callback;
iface->get_frame_counter = clutter_stage_x11_get_frame_counter;
@@ -1112,6 +1141,8 @@ clutter_stage_x11_translate_event (ClutterEventTranslator *translator,
if (!stage_x11->is_foreign_xwin)
{
gboolean size_changed = FALSE;
+ int stage_width;
+ int stage_height;
CLUTTER_NOTE (BACKEND, "ConfigureNotify[%x] (%d, %d)",
(unsigned int) stage_x11->xwin,
@@ -1131,9 +1162,9 @@ clutter_stage_x11_translate_event (ClutterEventTranslator *translator,
stage_x11->xwin_height = xevent->xconfigure.height;
}
- clutter_actor_set_size (CLUTTER_ACTOR (stage),
- xevent->xconfigure.width / stage_x11->scale_factor,
- xevent->xconfigure.height / stage_x11->scale_factor);
+ stage_width = xevent->xconfigure.width / stage_x11->scale_factor;
+ stage_height = xevent->xconfigure.height / stage_x11->scale_factor;
+ clutter_actor_set_size (CLUTTER_ACTOR (stage), stage_width, stage_height);
if (size_changed)
{
@@ -1194,6 +1225,22 @@ clutter_stage_x11_translate_event (ClutterEventTranslator *translator,
* to set up the GL viewport with the new size
*/
clutter_stage_ensure_viewport (stage);
+
+ /* If this was a result of the Xrandr change when running as a
+ * X11 compositing manager, we need to reset the legacy
+ * stage view, now that it has a new size.
+ */
+ if (stage_x11->legacy_view)
+ {
+ cairo_rectangle_int_t view_layout = {
+ .width = stage_width,
+ .height = stage_height
+ };
+
+ g_object_set (G_OBJECT (stage_x11->legacy_view),
+ "layout", &view_layout,
+ NULL);
+ }
}
}
break;
@@ -1463,12 +1510,6 @@ set_foreign_window_callback (ClutterActor *actor,
g_hash_table_insert (clutter_stages_by_xid,
GINT_TO_POINTER (fwd->stage_x11->xwin),
fwd->stage_x11);
-
- /* calling this with the stage unrealized will unset the stage
- * from the GL context; once the stage is realized the GL context
- * will be set again
- */
- clutter_stage_ensure_current (CLUTTER_STAGE (actor));
}
/**
diff --git a/clutter/clutter/x11/clutter-stage-x11.h b/clutter/clutter/x11/clutter-stage-x11.h
index f15ce9b..e1ee033 100644
--- a/clutter/clutter/x11/clutter-stage-x11.h
+++ b/clutter/clutter/x11/clutter-stage-x11.h
@@ -58,6 +58,9 @@ struct _ClutterStageX11
gint xwin_width;
gint xwin_height; /* FIXME target_width / height */
+ ClutterStageView *legacy_view;
+ GList *legacy_views;
+
gchar *title;
guint clipped_redraws_cool_off;
diff --git a/src/Makefile.am b/src/Makefile.am
index b378f9f..988227c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -107,6 +107,8 @@ libmutter_la_SOURCES = \
backends/meta-stage.c \
backends/meta-renderer.c \
backends/meta-renderer.h \
+ backends/meta-renderer-view.c \
+ backends/meta-renderer-view.h \
backends/edid-parse.c \
backends/edid.h \
backends/x11/meta-backend-x11.c \
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index 109e43f..08b2499 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -106,6 +106,8 @@ struct _MetaBackendClass
void meta_init_backend (MetaBackendType backend_type);
+ClutterBackend * meta_backend_get_clutter_backend (MetaBackend *backend);
+
MetaIdleMonitor * meta_backend_get_idle_monitor (MetaBackend *backend,
int device_id);
MetaMonitorManager * meta_backend_get_monitor_manager (MetaBackend *backend);
diff --git a/src/backends/meta-renderer-view.c b/src/backends/meta-renderer-view.c
new file mode 100644
index 0000000..6c9b2b2
--- /dev/null
+++ b/src/backends/meta-renderer-view.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "backends/meta-renderer-view.h"
+
+#include "backends/meta-renderer.h"
+#include "clutter/clutter-mutter.h"
+
+struct _MetaRendererView
+{
+ ClutterStageView parent;
+
+ MetaMonitorInfo *monitor_info;
+};
+
+G_DEFINE_TYPE (MetaRendererView, meta_renderer_view,
+ CLUTTER_TYPE_STAGE_VIEW_COGL)
+
+static void
+meta_renderer_view_init (MetaRendererView *view)
+{
+}
+
+static void
+meta_renderer_view_class_init (MetaRendererViewClass *klass)
+{
+}
diff --git a/src/backends/meta-renderer-view.h b/src/backends/meta-renderer-view.h
new file mode 100644
index 0000000..0f08760
--- /dev/null
+++ b/src/backends/meta-renderer-view.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef META_RENDERER_VIEW_H
+#define META_RENDERER_VIEW_H
+
+#include "backends/meta-monitor-manager-private.h"
+#include "clutter/clutter-mutter.h"
+
+#define META_TYPE_RENDERER_VIEW (meta_renderer_view_get_type ())
+G_DECLARE_FINAL_TYPE (MetaRendererView, meta_renderer_view,
+ META, RENDERER_VIEW,
+ ClutterStageViewCogl)
+
+#endif /* META_RENDERER_VIEW_H */
diff --git a/src/backends/meta-renderer.c b/src/backends/meta-renderer.c
index dd6376d..ff5fd6e 100644
--- a/src/backends/meta-renderer.c
+++ b/src/backends/meta-renderer.c
@@ -26,9 +26,15 @@
#include <glib-object.h>
+#include "backends/meta-backend-private.h"
#include "backends/meta-renderer.h"
-G_DEFINE_TYPE (MetaRenderer, meta_renderer, G_TYPE_OBJECT)
+typedef struct _MetaRendererPrivate
+{
+ GList *views;
+} MetaRendererPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (MetaRenderer, meta_renderer, G_TYPE_OBJECT)
CoglRenderer *
meta_renderer_create_cogl_renderer (MetaRenderer *renderer)
@@ -36,6 +42,69 @@ meta_renderer_create_cogl_renderer (MetaRenderer *renderer)
return META_RENDERER_GET_CLASS (renderer)->create_cogl_renderer (renderer);
}
+static MetaRendererView *
+meta_renderer_create_view (MetaRenderer *renderer,
+ MetaMonitorInfo *monitor_info)
+{
+ return META_RENDERER_GET_CLASS (renderer)->create_view (renderer,
+ monitor_info);
+}
+
+void
+meta_renderer_rebuild_views (MetaRenderer *renderer)
+{
+ MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer);
+ MetaBackend *backend = meta_get_backend ();
+ MetaMonitorManager *monitor_manager =
+ meta_backend_get_monitor_manager (backend);
+ MetaMonitorInfo *monitor_infos;
+ unsigned int num_monitor_infos;
+ unsigned int i;
+
+ g_list_free_full (priv->views, g_object_unref);
+ priv->views = NULL;
+
+ monitor_infos = meta_monitor_manager_get_monitor_infos (monitor_manager,
+ &num_monitor_infos);
+
+ for (i = 0; i < num_monitor_infos; i++)
+ {
+ MetaRendererView *view;
+
+ view = meta_renderer_create_view (renderer, &monitor_infos[i]);
+ priv->views = g_list_append (priv->views, view);
+ }
+}
+
+void
+meta_renderer_set_legacy_view (MetaRenderer *renderer,
+ MetaRendererView *legacy_view)
+{
+ MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer);
+
+ g_assert (!priv->views);
+
+ priv->views = g_list_append (priv->views, legacy_view);
+}
+
+GList *
+meta_renderer_get_views (MetaRenderer *renderer)
+{
+ MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer);
+
+ return priv->views;
+}
+
+static void
+meta_renderer_finalize (GObject *object)
+{
+ MetaRenderer *renderer = META_RENDERER (object);
+ MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer);
+
+ g_list_free_full (priv->views, g_object_unref);
+ priv->views = NULL;
+}
+
static void
meta_renderer_init (MetaRenderer *renderer)
{
@@ -44,4 +113,7 @@ meta_renderer_init (MetaRenderer *renderer)
static void
meta_renderer_class_init (MetaRendererClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = meta_renderer_finalize;
}
diff --git a/src/backends/meta-renderer.h b/src/backends/meta-renderer.h
index 3888e60..ca6868b 100644
--- a/src/backends/meta-renderer.h
+++ b/src/backends/meta-renderer.h
@@ -28,6 +28,9 @@
#include <glib-object.h>
#include "cogl/cogl.h"
+#include "clutter/clutter-mutter.h"
+#include "backends/meta-monitor-manager-private.h"
+#include "backends/meta-renderer-view.h"
#define META_TYPE_RENDERER (meta_renderer_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaRenderer, meta_renderer, META, RENDERER, GObject)
@@ -37,8 +40,17 @@ struct _MetaRendererClass
GObjectClass parent_class;
CoglRenderer * (* create_cogl_renderer) (MetaRenderer *renderer);
+ MetaRendererView * (* create_view) (MetaRenderer *renderer,
+ MetaMonitorInfo *monitor_info);
};
CoglRenderer * meta_renderer_create_cogl_renderer (MetaRenderer *renderer);
+void meta_renderer_rebuild_views (MetaRenderer *renderer);
+
+void meta_renderer_set_legacy_view (MetaRenderer *renderer,
+ MetaRendererView *legacy_view);
+
+GList * meta_renderer_get_views (MetaRenderer *renderer);
+
#endif /* META_RENDERER_H */
diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c
index 3b992d9..1bb3e1f 100644
--- a/src/backends/meta-stage.c
+++ b/src/backends/meta-stage.c
@@ -25,7 +25,10 @@
#include "meta-stage.h"
#include <meta/meta-backend.h>
+#include <meta/meta-monitor-manager.h>
#include <meta/util.h>
+#include "backends/meta-backend-private.h"
+#include "clutter/clutter-mutter.h"
struct _MetaOverlay {
gboolean enabled;
diff --git a/src/backends/meta-stage.h b/src/backends/meta-stage.h
index 5376c7a..028a347 100644
--- a/src/backends/meta-stage.h
+++ b/src/backends/meta-stage.h
@@ -63,6 +63,9 @@ void meta_stage_update_cursor_overlay (MetaStage *stage,
void meta_stage_set_active (MetaStage *stage,
gboolean is_active);
+
+void meta_stage_update_view_layout (MetaStage *stage);
+
G_END_DECLS
#endif /* META_STAGE_H */
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index 9ab9c18..5edfd79 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -38,8 +38,10 @@
#include "meta-launcher.h"
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-pointer-constraint.h"
+#include "backends/meta-stage.h"
#include "backends/native/meta-clutter-backend-native.h"
#include "backends/native/meta-renderer-native.h"
+#include "backends/native/meta-stage-native.h"
#include <stdlib.h>
@@ -383,8 +385,13 @@ static void
meta_backend_native_update_screen_size (MetaBackend *backend,
int width, int height)
{
+ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+ MetaStageNative *stage_native;
ClutterActor *stage = meta_backend_get_stage (backend);
+ stage_native = meta_clutter_backend_native_get_stage_native (clutter_backend);
+ meta_stage_native_legacy_set_size (stage_native, width, height);
+
clutter_actor_set_size (stage, width, height);
}
diff --git a/src/backends/native/meta-clutter-backend-native.c
b/src/backends/native/meta-clutter-backend-native.c
index 675395a..e932753 100644
--- a/src/backends/native/meta-clutter-backend-native.c
+++ b/src/backends/native/meta-clutter-backend-native.c
@@ -36,11 +36,22 @@
struct _MetaClutterBackendNative
{
ClutterBackendEglNative parent;
+
+ MetaStageNative *stage_native;
};
G_DEFINE_TYPE (MetaClutterBackendNative, meta_clutter_backend_native,
CLUTTER_TYPE_BACKEND_EGL_NATIVE)
+MetaStageNative *
+meta_clutter_backend_native_get_stage_native (ClutterBackend *backend)
+{
+ MetaClutterBackendNative *clutter_backend_native =
+ META_CLUTTER_BACKEND_NATIVE (backend);
+
+ return clutter_backend_native->stage_native;
+}
+
static CoglRenderer *
meta_clutter_backend_native_get_renderer (ClutterBackend *clutter_backend,
GError **error)
@@ -56,10 +67,16 @@ meta_clutter_backend_native_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error)
{
- return g_object_new (META_TYPE_STAGE_NATIVE,
- "backend", backend,
- "wrapper", wrapper,
- NULL);
+ MetaClutterBackendNative *clutter_backend_native =
+ META_CLUTTER_BACKEND_NATIVE (backend);
+
+ g_assert (!clutter_backend_native->stage_native);
+
+ clutter_backend_native->stage_native = g_object_new (META_TYPE_STAGE_NATIVE,
+ "backend", backend,
+ "wrapper", wrapper,
+ NULL);
+ return CLUTTER_STAGE_WINDOW (clutter_backend_native->stage_native);
}
static void
diff --git a/src/backends/native/meta-clutter-backend-native.h
b/src/backends/native/meta-clutter-backend-native.h
index d9124f2..2b4153e 100644
--- a/src/backends/native/meta-clutter-backend-native.h
+++ b/src/backends/native/meta-clutter-backend-native.h
@@ -29,10 +29,13 @@
#include "clutter/clutter.h"
#include "clutter/egl/clutter-backend-eglnative.h"
+#include "backends/native/meta-stage-native.h"
#define META_TYPE_CLUTTER_BACKEND_NATIVE (meta_clutter_backend_native_get_type ())
G_DECLARE_FINAL_TYPE (MetaClutterBackendNative, meta_clutter_backend_native,
META, CLUTTER_BACKEND_NATIVE,
ClutterBackendEglNative)
+MetaStageNative * meta_clutter_backend_native_get_stage_native (ClutterBackend *backend);
+
#endif /* META_CLUTTER_BACKEND_NATIVE_H */
diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c
index 12061e5..1dd3c50 100644
--- a/src/backends/native/meta-stage-native.c
+++ b/src/backends/native/meta-stage-native.c
@@ -35,7 +35,7 @@ struct _MetaStageNative
{
ClutterStageCogl parent;
- CoglOnscreen *onscreen;
+ CoglOnscreen *pending_onscreen;
};
static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
@@ -47,19 +47,79 @@ G_DEFINE_TYPE_WITH_CODE (MetaStageNative, meta_stage_native,
CLUTTER_TYPE_STAGE_COGL,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init))
+
+static MetaRendererView *
+get_legacy_view (MetaRenderer *renderer)
+{
+ GList *views;
+
+ views = meta_renderer_get_views (renderer);
+ g_assert (g_list_length (views) <= 1);
+
+ if (views)
+ return views->data;
+ else
+ return NULL;
+}
+
+static CoglOnscreen *
+get_legacy_onscreen (MetaStageNative *stage_native)
+{
+ if (stage_native->pending_onscreen)
+ {
+ return stage_native->pending_onscreen;
+ }
+ else
+ {
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ ClutterStageView *stage_view;
+ CoglFramebuffer *framebuffer;
+
+ stage_view = CLUTTER_STAGE_VIEW (get_legacy_view (renderer));
+ framebuffer = clutter_stage_view_get_framebuffer (stage_view);
+
+ return COGL_ONSCREEN (framebuffer);
+ }
+}
+
+void
+meta_stage_native_legacy_set_size (MetaStageNative *stage_native,
+ int width,
+ int height)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ MetaRendererView *legacy_view;
+ cairo_rectangle_int_t view_layout;
+
+ legacy_view = get_legacy_view (renderer);
+ if (!legacy_view)
+ return;
+
+ view_layout = (cairo_rectangle_int_t) {
+ .width = width,
+ .height = height
+ };
+ g_object_set (G_OBJECT (legacy_view),
+ "layout", &view_layout,
+ NULL);
+}
+
static gboolean
meta_stage_native_realize (ClutterStageWindow *stage_window)
{
MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
- ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
- ClutterBackend *clutter_backend = CLUTTER_BACKEND (stage_cogl->backend);
+ MetaBackend *backend = meta_get_backend ();
+ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+ CoglFramebuffer *framebuffer;
GError *error = NULL;
- stage_native->onscreen = cogl_onscreen_new (clutter_backend->cogl_context,
- 1, 1);
+ stage_native->pending_onscreen =
+ cogl_onscreen_new (clutter_backend->cogl_context, 1, 1);
- if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (stage_native->onscreen),
- &error))
+ framebuffer = COGL_FRAMEBUFFER (stage_native->pending_onscreen);
+ if (!cogl_framebuffer_allocate (framebuffer, &error))
meta_fatal ("Failed to allocate onscreen framebuffer: %s\n",
error->message);
@@ -76,7 +136,7 @@ meta_stage_native_unrealize (ClutterStageWindow *stage_window)
clutter_stage_window_parent_iface->unrealize (stage_window);
- g_clear_pointer (&stage_native->onscreen, cogl_object_unref);
+ g_clear_pointer (&stage_native->pending_onscreen, cogl_object_unref);
}
static gboolean
@@ -89,15 +149,15 @@ static void
meta_stage_native_get_geometry (ClutterStageWindow *stage_window,
cairo_rectangle_int_t *geometry)
{
- MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
- CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (stage_native->onscreen);
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ MetaRendererView *legacy_view;
- if (framebuffer)
+ legacy_view = get_legacy_view (renderer);
+ if (legacy_view)
{
- *geometry = (cairo_rectangle_int_t) {
- .width = cogl_framebuffer_get_width (framebuffer),
- .height = cogl_framebuffer_get_height (framebuffer)
- };
+ clutter_stage_view_get_layout (CLUTTER_STAGE_VIEW (legacy_view),
+ geometry);
}
else
{
@@ -108,12 +168,44 @@ meta_stage_native_get_geometry (ClutterStageWindow *stage_window,
}
}
-static CoglFramebuffer *
-meta_stage_native_get_legacy_onscreen (ClutterStageWindow *stage_window)
+static void
+ensure_legacy_view (ClutterStageWindow *stage_window)
{
MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ MetaMonitorManager *monitor_manager =
+ meta_backend_get_monitor_manager (backend);
+ MetaRendererView *legacy_view;
+ cairo_rectangle_int_t view_layout = { 0 };
+ CoglFramebuffer *framebuffer;
+
+ legacy_view = get_legacy_view (renderer);
+ if (legacy_view)
+ return;
+
+ if (!monitor_manager)
+ return;
+
+ meta_monitor_manager_get_screen_size (monitor_manager,
+ &view_layout.width,
+ &view_layout.height);
+ framebuffer = g_steal_pointer (&stage_native->pending_onscreen);
+ legacy_view = g_object_new (META_TYPE_RENDERER_VIEW,
+ "layout", &view_layout,
+ "framebuffer", framebuffer,
+ NULL);
+ meta_renderer_set_legacy_view (renderer, legacy_view);
+}
- return COGL_FRAMEBUFFER (stage_native->onscreen);
+static GList *
+meta_stage_native_get_views (ClutterStageWindow *stage_window)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+
+ ensure_legacy_view (stage_window);
+ return meta_renderer_get_views (renderer);
}
static CoglClosure *
@@ -122,11 +214,13 @@ meta_stage_native_set_frame_callback (ClutterStageWindow *stage_window,
gpointer user_data)
{
MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
+ CoglOnscreen *legacy_onscreen;
- cogl_onscreen_set_swap_throttled (stage_native->onscreen,
+ legacy_onscreen = get_legacy_onscreen (stage_native);
+ cogl_onscreen_set_swap_throttled (legacy_onscreen,
_clutter_get_sync_to_vblank ());
- return cogl_onscreen_add_frame_callback (stage_native->onscreen,
+ return cogl_onscreen_add_frame_callback (legacy_onscreen,
callback,
user_data,
NULL);
@@ -137,16 +231,22 @@ meta_stage_native_remove_frame_callback (ClutterStageWindow *stage_window,
CoglFrameClosure *closure)
{
MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
+ CoglOnscreen *legacy_onscreen;
+
+ legacy_onscreen = get_legacy_onscreen (stage_native);
- cogl_onscreen_remove_frame_callback (stage_native->onscreen, closure);
+ cogl_onscreen_remove_frame_callback (legacy_onscreen, closure);
}
static int64_t
meta_stage_native_get_frame_counter (ClutterStageWindow *stage_window)
{
MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
+ CoglOnscreen *legacy_onscreen;
+
+ legacy_onscreen = get_legacy_onscreen (stage_native);
- return cogl_onscreen_get_frame_counter (stage_native->onscreen);
+ return cogl_onscreen_get_frame_counter (legacy_onscreen);
}
static void
@@ -168,7 +268,7 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
iface->unrealize = meta_stage_native_unrealize;
iface->can_clip_redraws = meta_stage_native_can_clip_redraws;
iface->get_geometry = meta_stage_native_get_geometry;
- iface->get_legacy_onscreen = meta_stage_native_get_legacy_onscreen;
+ iface->get_views = meta_stage_native_get_views;
iface->set_frame_callback = meta_stage_native_set_frame_callback;
iface->remove_frame_callback = meta_stage_native_remove_frame_callback;
iface->get_frame_counter = meta_stage_native_get_frame_counter;
diff --git a/src/backends/native/meta-stage-native.h b/src/backends/native/meta-stage-native.h
index 95b8028..d0b87e0 100644
--- a/src/backends/native/meta-stage-native.h
+++ b/src/backends/native/meta-stage-native.h
@@ -31,4 +31,8 @@
G_DECLARE_FINAL_TYPE (MetaStageNative, meta_stage_native,
META, STAGE_NATIVE, ClutterStageCogl)
+void meta_stage_native_legacy_set_size (MetaStageNative *stage_native,
+ int width,
+ int height);
+
#endif /* META_STAGE_NATIVE_H */
diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
index 9c3bc62..24aaca3 100644
--- a/src/backends/x11/meta-backend-x11.c
+++ b/src/backends/x11/meta-backend-x11.c
@@ -41,6 +41,7 @@
#include "meta-idle-monitor-xsync.h"
#include "meta-monitor-manager-xrandr.h"
#include "backends/meta-monitor-manager-dummy.h"
+#include "backends/meta-stage.h"
#include "backends/x11/nested/meta-cursor-renderer-x11-nested.h"
#include "backends/x11/meta-clutter-backend-x11.h"
#include "backends/x11/meta-renderer-x11.h"
@@ -814,7 +815,9 @@ meta_backend_x11_update_screen_size (MetaBackend *backend,
if (priv->mode == META_BACKEND_X11_MODE_NESTED)
{
ClutterActor *stage = meta_backend_get_stage (backend);
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ meta_renderer_rebuild_views (renderer);
clutter_actor_set_size (stage, width, height);
}
else
diff --git a/src/backends/x11/meta-renderer-x11.c b/src/backends/x11/meta-renderer-x11.c
index 9dab81d..565a28e 100644
--- a/src/backends/x11/meta-renderer-x11.c
+++ b/src/backends/x11/meta-renderer-x11.c
@@ -31,8 +31,12 @@
#include "cogl/cogl-xlib.h"
#include "cogl/winsys/cogl-winsys-glx-private.h"
#include "cogl/winsys/cogl-winsys-egl-x11-private.h"
+#include "backends/meta-backend-private.h"
#include "backends/meta-renderer.h"
+#include "backends/meta-renderer-view.h"
#include "backends/x11/meta-renderer-x11.h"
+#include "core/boxes-private.h"
+#include "meta/meta-backend.h"
#include "meta/util.h"
struct _MetaRendererX11
@@ -64,6 +68,32 @@ meta_renderer_x11_create_cogl_renderer (MetaRenderer *renderer)
return cogl_renderer;
}
+static MetaRendererView *
+meta_renderer_x11_create_view (MetaRenderer *renderer,
+ MetaMonitorInfo *monitor_info)
+{
+ MetaBackend *backend = meta_get_backend ();
+ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+ CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
+ int width, height;
+ cairo_rectangle_int_t view_layout;
+ CoglTexture2D *texture_2d;
+ CoglOffscreen *offscreen;
+
+ g_assert (meta_is_wayland_compositor ());
+
+ width = monitor_info->rect.width;
+ height = monitor_info->rect.height;
+ texture_2d = cogl_texture_2d_new_with_size (cogl_context, width, height);
+ offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture_2d));
+ view_layout = meta_rectangle_to_cairo_rectangle (&monitor_info->rect);
+
+ return g_object_new (META_TYPE_RENDERER_VIEW,
+ "layout", &view_layout,
+ "framebuffer", COGL_FRAMEBUFFER (offscreen),
+ NULL);
+}
+
static void
meta_renderer_x11_init (MetaRendererX11 *renderer_x11)
{
@@ -75,4 +105,5 @@ meta_renderer_x11_class_init (MetaRendererX11Class *klass)
MetaRendererClass *renderer_class = META_RENDERER_CLASS (klass);
renderer_class->create_cogl_renderer = meta_renderer_x11_create_cogl_renderer;
+ renderer_class->create_view = meta_renderer_x11_create_view;
}
diff --git a/src/backends/x11/meta-stage-x11-nested.c b/src/backends/x11/meta-stage-x11-nested.c
index ba0173f..c9dee09 100644
--- a/src/backends/x11/meta-stage-x11-nested.c
+++ b/src/backends/x11/meta-stage-x11-nested.c
@@ -26,13 +26,127 @@
#include "backends/x11/meta-stage-x11-nested.h"
+#include "backends/meta-backend-private.h"
+#include "backends/meta-renderer.h"
+#include "clutter/clutter-mutter.h"
+
+static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
+
struct _MetaStageX11Nested
{
ClutterStageX11 parent;
+
+ CoglPipeline *pipeline;
+ GList *views;
};
-G_DEFINE_TYPE (MetaStageX11Nested, meta_stage_x11_nested,
- CLUTTER_TYPE_STAGE_X11)
+static void
+clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaStageX11Nested, meta_stage_x11_nested,
+ CLUTTER_TYPE_STAGE_X11,
+ G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
+ clutter_stage_window_iface_init))
+
+typedef struct _ClutterStageX11View
+{
+ CoglTexture *texture;
+ ClutterStageViewCogl *view;
+} MetaStageX11NestedView;
+
+static gboolean
+meta_stage_x11_nested_can_clip_redraws (ClutterStageWindow *stage_window)
+{
+ return FALSE;
+}
+
+static GList *
+meta_stage_x11_nested_get_views (ClutterStageWindow *stage_window)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+
+ return meta_renderer_get_views (renderer);
+}
+
+static void
+meta_stage_x11_nested_finish_frame (ClutterStageWindow *stage_window)
+{
+ MetaStageX11Nested *stage_nested = META_STAGE_X11_NESTED (stage_window);
+ ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+ CoglFramebuffer *onscreen = COGL_FRAMEBUFFER (stage_x11->onscreen);
+ GList *l;
+
+ if (!stage_nested->pipeline)
+ stage_nested->pipeline = cogl_pipeline_new (clutter_backend->cogl_context);
+
+ cogl_framebuffer_clear4f (onscreen,
+ COGL_BUFFER_BIT_COLOR,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+
+ for (l = meta_renderer_get_views (renderer); l; l = l->next)
+ {
+ ClutterStageView *view = l->data;
+ cairo_rectangle_int_t view_layout;
+ CoglFramebuffer *framebuffer;
+ CoglTexture *texture;
+
+ clutter_stage_view_get_layout (view, &view_layout);
+
+ framebuffer = clutter_stage_view_get_framebuffer (view);
+ texture = cogl_offscreen_get_texture (COGL_OFFSCREEN (framebuffer));
+ cogl_framebuffer_set_viewport (onscreen,
+ view_layout.x,
+ view_layout.y,
+ view_layout.width,
+ view_layout.height);
+ cogl_pipeline_set_layer_texture (stage_nested->pipeline, 0, texture);
+ cogl_framebuffer_draw_rectangle (onscreen,
+ stage_nested->pipeline,
+ -1, 1, 1, -1);
+ }
+
+ cogl_onscreen_swap_buffers (stage_x11->onscreen);
+}
+
+static void
+meta_stage_x11_nested_unrealize (ClutterStageWindow *stage_window)
+{
+ MetaStageX11Nested *stage_nested = META_STAGE_X11_NESTED (stage_window);
+ ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ GList *l;
+
+ /* Clutter still uses part of the deprecated stateful API of Cogl
+ * (in particulart cogl_set_framebuffer). It means Cogl can keep an
+ * internal reference to the onscreen object we rendered to. In the
+ * case of foreign window, we want to avoid this, as we don't know
+ * what's going to happen to that window.
+ *
+ * The following call sets the current Cogl framebuffer to a dummy
+ * 1x1 one if we're unrealizing the current one, so Cogl doesn't
+ * keep any reference to the foreign window.
+ */
+ for (l = meta_renderer_get_views (renderer); l ;l = l->next)
+ {
+ ClutterStageView *view = l->data;
+ CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
+
+ if (cogl_get_draw_framebuffer () == framebuffer)
+ {
+ _clutter_backend_reset_cogl_framebuffer (stage_cogl->backend);
+ break;
+ }
+ }
+
+ g_clear_pointer (&stage_nested->pipeline, cogl_object_unref);
+
+ clutter_stage_window_parent_iface->unrealize (stage_window);
+}
static void
meta_stage_x11_nested_init (MetaStageX11Nested *stage_x11_nested)
@@ -43,3 +157,15 @@ static void
meta_stage_x11_nested_class_init (MetaStageX11NestedClass *klass)
{
}
+
+static void
+clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
+{
+ clutter_stage_window_parent_iface = g_type_interface_peek_parent (iface);
+
+ iface->can_clip_redraws = meta_stage_x11_nested_can_clip_redraws;
+ iface->unrealize = meta_stage_x11_nested_unrealize;
+ iface->get_views = meta_stage_x11_nested_get_views;
+ iface->finish_frame = meta_stage_x11_nested_finish_frame;
+}
+
diff --git a/src/core/boxes-private.h b/src/core/boxes-private.h
index c2eec0a..315cc26 100644
--- a/src/core/boxes-private.h
+++ b/src/core/boxes-private.h
@@ -215,4 +215,6 @@ GList* meta_rectangle_find_nonintersected_monitor_edges (
const GList *monitor_rects,
const GSList *all_struts);
+cairo_rectangle_int_t meta_rectangle_to_cairo_rectangle (MetaRectangle *rect);
+
#endif /* META_BOXES_PRIVATE_H */
diff --git a/src/core/boxes.c b/src/core/boxes.c
index 2a70497..bc9a119 100644
--- a/src/core/boxes.c
+++ b/src/core/boxes.c
@@ -2013,3 +2013,14 @@ meta_rectangle_find_nonintersected_monitor_edges (
return ret;
}
+
+cairo_rectangle_int_t
+meta_rectangle_to_cairo_rectangle (MetaRectangle *rect)
+{
+ return (cairo_rectangle_int_t) {
+ .x = rect->x,
+ .y = rect->y,
+ .width = rect->width,
+ .height = rect->height
+ };
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]