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
This commit is contained in:
parent
749237a28e
commit
566c28bdaf
@ -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 \
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
188
clutter/clutter/clutter-stage-view.c
Normal file
188
clutter/clutter/clutter-stage-view.c
Normal file
@ -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);
|
||||
}
|
55
clutter/clutter/clutter-stage-view.h
Normal file
55
clutter/clutter/clutter-stage-view.h
Normal file
@ -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__ */
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
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,28 +639,25 @@ _clutter_stage_do_paint (ClutterStage *stage,
|
||||
viewport[2] = priv->viewport[2] * window_scale;
|
||||
viewport[3] = priv->viewport[3] * window_scale;
|
||||
|
||||
if (clip)
|
||||
if (!clip)
|
||||
{
|
||||
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[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[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_NOTE (CLIPPING, "Setting stage clip too: "
|
||||
"x=%f, y=%f, width=%f, height=%f",
|
||||
@ -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,
|
||||
static ClutterActor *
|
||||
_clutter_stage_do_pick_on_view (ClutterStage *stage,
|
||||
gint x,
|
||||
gint y,
|
||||
ClutterPickMode mode)
|
||||
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);
|
||||
|
||||
_clutter_stage_window_get_dirty_pixel (priv->impl, &dirty_x, &dirty_y);
|
||||
/* 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, 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)))
|
||||
{
|
||||
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-",
|
||||
g_strdup_printf ("pick-buffer-%s-view-x-%d",
|
||||
_clutter_actor_get_debug_name (actor),
|
||||
NULL);
|
||||
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,13 +2859,43 @@ 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,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
if (use_clipped_redraw && !clip_region_empty)
|
||||
{
|
||||
int age, i;
|
||||
cairo_rectangle_int_t *current_damage =
|
||||
&stage_cogl->damage_history[DAMAGE_HISTORY (stage_cogl->damage_index++)];
|
||||
&view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index++)];
|
||||
|
||||
if (use_clipped_redraw)
|
||||
age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (fb));
|
||||
|
||||
if (valid_buffer_age (view_cogl, age))
|
||||
{
|
||||
int age = cogl_onscreen_get_buffer_age (onscreen), i;
|
||||
*current_damage = clip_region;
|
||||
|
||||
*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);
|
||||
{
|
||||
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);
|
||||
force_swap = TRUE;
|
||||
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
|
||||
else if (!use_clipped_redraw)
|
||||
{
|
||||
current_damage->x = 0;
|
||||
current_damage->y = 0;
|
||||
current_damage->width = geom.width;
|
||||
current_damage->height = geom.height;
|
||||
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
|
||||
{
|
||||
ndamage = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
/* push on the screen */
|
||||
if (use_clipped_redraw && !force_swap)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "cogl_onscreen_swap_buffers (onscreen: %p)",
|
||||
onscreen);
|
||||
swap_region = (cairo_rectangle_int_t) { 0 };
|
||||
do_swap_buffer = TRUE;
|
||||
}
|
||||
|
||||
if (do_swap_buffer)
|
||||
{
|
||||
return swap_framebuffer (stage_window,
|
||||
view,
|
||||
&swap_region,
|
||||
swap_with_damage);
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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__ */
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
|
43
src/backends/meta-renderer-view.c
Normal file
43
src/backends/meta-renderer-view.c
Normal file
@ -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)
|
||||
{
|
||||
}
|
29
src/backends/meta-renderer-view.h
Normal file
29
src/backends/meta-renderer-view.h
Normal file
@ -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 */
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
return COGL_FRAMEBUFFER (stage_native->onscreen);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
cogl_onscreen_remove_frame_callback (stage_native->onscreen, closure);
|
||||
legacy_onscreen = get_legacy_onscreen (stage_native);
|
||||
|
||||
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;
|
||||
|
||||
return cogl_onscreen_get_frame_counter (stage_native->onscreen);
|
||||
legacy_onscreen = get_legacy_onscreen (stage_native);
|
||||
|
||||
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;
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user