ClutterStageCogl: Let the sub-classes handle the onscreen

In preperation for having allowing drawing onto multiple onscreen
framebuffers, move the onscreen framebuffer handling to the
corresponding winsys dependent backends.

Currently the onscreen framebuffer is still accessed, but, as can seen
by the usage of "legacy" in the accessor name, it should be considered
the legacy method. Eventually only the X11 Compositing Manager backend
will make use of the legacy single onscreen framebuffer API.

https://bugzilla.gnome.org/show_bug.cgi?id=768976
This commit is contained in:
Jonas Ådahl 2016-05-25 12:44:52 +08:00
parent df0805fb0a
commit 767e12125b
11 changed files with 256 additions and 88 deletions

View File

@ -62,6 +62,7 @@
#include "clutter-feature.h"
#include "clutter-main.h"
#include "clutter-master-clock.h"
#include "clutter-mutter.h"
#include "clutter-private.h"
#include "clutter-settings-private.h"
#include "clutter-stage-manager.h"

View File

@ -33,6 +33,9 @@
CLUTTER_AVAILABLE_IN_MUTTER
void clutter_set_custom_backend_func (ClutterBackend *(* func) (void));
CLUTTER_AVAILABLE_IN_MUTTER
gboolean _clutter_get_sync_to_vblank (void);
#undef __CLUTTER_H_INSIDE__
#endif /* __CLUTTER_MUTTER_H__ */

View File

@ -210,7 +210,6 @@ void _clutter_id_to_color (guint id,
ClutterColor *col);
void _clutter_set_sync_to_vblank (gboolean sync_to_vblank);
gboolean _clutter_get_sync_to_vblank (void);
/* use this function as the accumulator if you have a signal with
* a G_TYPE_BOOLEAN return value; this will stop the emission as

View File

@ -348,3 +348,41 @@ _clutter_stage_window_get_scale_factor (ClutterStageWindow *window)
return 1;
}
CoglFramebuffer *
_clutter_stage_window_get_legacy_onscreen (ClutterStageWindow *window)
{
ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
return iface->get_legacy_onscreen (window);
}
CoglFrameClosure *
_clutter_stage_window_set_frame_callback (ClutterStageWindow *window,
CoglFrameCallback callback,
gpointer user_data)
{
ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
return iface->set_frame_callback (window, callback, user_data);
}
void
_clutter_stage_window_remove_frame_callback (ClutterStageWindow *window,
CoglFrameClosure *closure)
{
ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
iface->remove_frame_callback (window, closure);
}
int64_t
_clutter_stage_window_get_frame_counter (ClutterStageWindow *window)
{
ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
if (iface->get_frame_counter)
return iface->get_frame_counter (window);
else
return 0;
}

View File

@ -86,6 +86,13 @@ struct _ClutterStageWindowIface
void (* set_scale_factor) (ClutterStageWindow *stage_window,
int factor);
int (* get_scale_factor) (ClutterStageWindow *stage_window);
CoglFramebuffer *(* get_legacy_onscreen) (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);
};
CLUTTER_AVAILABLE_IN_MUTTER
@ -142,6 +149,17 @@ void _clutter_stage_window_set_scale_factor (ClutterStageWin
int factor);
int _clutter_stage_window_get_scale_factor (ClutterStageWindow *window);
CoglFramebuffer *_clutter_stage_window_get_legacy_onscreen (ClutterStageWindow *stage_window);
CoglFrameClosure *_clutter_stage_window_set_frame_callback (ClutterStageWindow *window,
CoglFrameCallback callback,
gpointer user_data);
void _clutter_stage_window_remove_frame_callback (ClutterStageWindow *stage_winow,
CoglFrameClosure *closure);
int64_t _clutter_stage_window_get_frame_counter (ClutterStageWindow *window);
G_END_DECLS
#endif /* __CLUTTER_STAGE_WINDOW_H__ */

View File

@ -69,6 +69,7 @@
#include "clutter-main.h"
#include "clutter-marshal.h"
#include "clutter-master-clock.h"
#include "clutter-mutter.h"
#include "clutter-paint-volume-private.h"
#include "clutter-private.h"
#include "clutter-stage-manager-private.h"

View File

@ -68,14 +68,11 @@ clutter_stage_cogl_unrealize (ClutterStageWindow *stage_window)
CLUTTER_NOTE (BACKEND, "Unrealizing Cogl stage [%p]", stage_cogl);
if (stage_cogl->onscreen != NULL)
if (stage_cogl->frame_closure != NULL)
{
cogl_onscreen_remove_frame_callback (stage_cogl->onscreen,
stage_cogl->frame_closure);
_clutter_stage_window_remove_frame_callback (stage_window,
stage_cogl->frame_closure);
stage_cogl->frame_closure = NULL;
cogl_object_unref (stage_cogl->onscreen);
stage_cogl->onscreen = NULL;
}
stage_cogl->pending_swaps = 0;
@ -126,10 +123,6 @@ clutter_stage_cogl_realize (ClutterStageWindow *stage_window)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
ClutterBackend *backend;
CoglFramebuffer *framebuffer;
GError *error = NULL;
gfloat width = 800;
gfloat height = 600;
CLUTTER_NOTE (BACKEND, "Realizing stage '%s' [%p]",
G_OBJECT_TYPE_NAME (stage_cogl),
@ -143,34 +136,10 @@ clutter_stage_cogl_realize (ClutterStageWindow *stage_window)
return FALSE;
}
if (stage_cogl->onscreen == NULL)
{
stage_cogl->onscreen = cogl_onscreen_new (backend->cogl_context,
width, height);
}
cogl_onscreen_set_swap_throttled (stage_cogl->onscreen,
_clutter_get_sync_to_vblank ());
framebuffer = COGL_FRAMEBUFFER (stage_cogl->onscreen);
if (!cogl_framebuffer_allocate (framebuffer, &error))
{
g_warning ("Failed to allocate stage: %s", error->message);
g_error_free (error);
cogl_object_unref (stage_cogl->onscreen);
stage_cogl->onscreen = NULL;
return FALSE;
}
/* FIXME: for fullscreen Cogl platforms then the size we gave
* will be ignored, so we need to make sure the stage size is
* updated to this size. */
stage_cogl->frame_closure =
cogl_onscreen_add_frame_callback (stage_cogl->onscreen,
frame_cb,
stage_cogl,
NULL);
_clutter_stage_window_set_frame_callback (stage_window,
frame_cb, stage_window);
return TRUE;
}
@ -262,36 +231,6 @@ clutter_stage_cogl_hide (ClutterStageWindow *stage_window)
clutter_actor_unmap (CLUTTER_ACTOR (stage_cogl->wrapper));
}
static void
clutter_stage_cogl_get_geometry (ClutterStageWindow *stage_window,
cairo_rectangle_int_t *geometry)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
int window_scale;
window_scale = _clutter_stage_window_get_scale_factor (stage_window);
if (geometry != NULL)
{
if (stage_cogl->onscreen)
{
CoglFramebuffer *framebuffer =
COGL_FRAMEBUFFER (stage_cogl->onscreen);
geometry->x = geometry->y = 0;
geometry->width = cogl_framebuffer_get_width (framebuffer) / window_scale;
geometry->height = cogl_framebuffer_get_height (framebuffer) / window_scale;
}
else
{
geometry->x = geometry->y = 0;
geometry->width = 800;
geometry->height = 600;
}
}
}
static void
clutter_stage_cogl_resize (ClutterStageWindow *stage_window,
gint width,
@ -414,6 +353,7 @@ static void
clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
CoglOnscreen *onscreen;
cairo_rectangle_int_t geom;
gboolean have_clip;
gboolean may_use_clipped_redraw;
@ -428,7 +368,8 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
wrapper = CLUTTER_ACTOR (stage_cogl->wrapper);
if (!stage_cogl->onscreen)
onscreen = _clutter_stage_window_get_legacy_onscreen (stage_window);
if (!onscreen)
return;
can_blit_sub_buffer =
@ -476,7 +417,7 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
if (use_clipped_redraw)
{
int age = cogl_onscreen_get_buffer_age (stage_cogl->onscreen), i;
int age = cogl_onscreen_get_buffer_age (onscreen), i;
*current_damage = *clip_region;
@ -512,7 +453,7 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
if (use_clipped_redraw)
{
CoglFramebuffer *fb = COGL_FRAMEBUFFER (stage_cogl->onscreen);
CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
CLUTTER_NOTE (CLIPPING,
"Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n",
@ -551,7 +492,7 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
if (may_use_clipped_redraw &&
G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)))
{
CoglFramebuffer *fb = COGL_FRAMEBUFFER (stage_cogl->onscreen);
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;
@ -584,7 +525,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 (stage_cogl->onscreen),
cogl_framebuffer_draw_primitive (COGL_FRAMEBUFFER (onscreen),
outline,
prim);
cogl_framebuffer_pop_matrix (fb);
@ -619,16 +560,16 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
"cogl_onscreen_swap_region (onscreen: %p, "
"x: %d, y: %d, "
"width: %d, height: %d)",
stage_cogl->onscreen,
onscreen,
damage[0], damage[1], damage[2], damage[3]);
cogl_onscreen_swap_region (stage_cogl->onscreen,
cogl_onscreen_swap_region (onscreen,
damage, ndamage);
}
else
{
CLUTTER_NOTE (BACKEND, "cogl_onscreen_swap_buffers (onscreen: %p)",
stage_cogl->onscreen);
onscreen);
/* If we have swap buffer events then cogl_onscreen_swap_buffers
* will return immediately and we need to track that there is a
@ -636,7 +577,7 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
stage_cogl->pending_swaps++;
cogl_onscreen_swap_buffers_with_damage (stage_cogl->onscreen,
cogl_onscreen_swap_buffers_with_damage (onscreen,
damage, ndamage);
}
@ -649,9 +590,10 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
static CoglFramebuffer *
clutter_stage_cogl_get_active_framebuffer (ClutterStageWindow *stage_window)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
CoglOnscreen *onscreen =
_clutter_stage_window_get_legacy_onscreen (stage_window);
return COGL_FRAMEBUFFER (stage_cogl->onscreen);
return COGL_FRAMEBUFFER (onscreen);
}
static void
@ -683,7 +625,6 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
iface->realize = clutter_stage_cogl_realize;
iface->unrealize = clutter_stage_cogl_unrealize;
iface->get_wrapper = clutter_stage_cogl_get_wrapper;
iface->get_geometry = clutter_stage_cogl_get_geometry;
iface->resize = clutter_stage_cogl_resize;
iface->show = clutter_stage_cogl_show;
iface->hide = clutter_stage_cogl_hide;

View File

@ -35,8 +35,6 @@ struct _ClutterStageCogl
/* back pointer to the backend */
ClutterBackend *backend;
CoglOnscreen *onscreen;
float refresh_rate;
int pending_swaps;

View File

@ -42,6 +42,7 @@
#include "clutter-event-private.h"
#include "clutter-feature.h"
#include "clutter-main.h"
#include "clutter-mutter.h"
#include "clutter-paint-volume-private.h"
#include "clutter-private.h"
#include "clutter-stage-private.h"
@ -439,10 +440,12 @@ clutter_stage_x11_unrealize (ClutterStageWindow *stage_window)
* 1x1 one if we're unrealizing the current one, so Cogl doesn't
* keep any reference to the foreign window.
*/
if (cogl_get_draw_framebuffer () == COGL_FRAMEBUFFER (stage_cogl->onscreen))
if (cogl_get_draw_framebuffer () == COGL_FRAMEBUFFER (stage_x11->onscreen))
_clutter_backend_reset_cogl_framebuffer (stage_cogl->backend);
clutter_stage_window_parent_iface->unrealize (stage_window);
g_clear_pointer (&stage_x11->onscreen, cogl_object_unref);
}
static void
@ -608,6 +611,7 @@ clutter_stage_x11_realize (ClutterStageWindow *stage_window)
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterDeviceManager *device_manager;
gfloat width, height;
GError *error = NULL;
clutter_actor_get_size (CLUTTER_ACTOR (stage_cogl->wrapper), &width, &height);
@ -620,7 +624,7 @@ clutter_stage_x11_realize (ClutterStageWindow *stage_window)
width, height,
stage_x11->scale_factor);
stage_cogl->onscreen = cogl_onscreen_new (backend->cogl_context, width, height);
stage_x11->onscreen = cogl_onscreen_new (backend->cogl_context, width, height);
/* We just created a window of the size of the actor. No need to fix
the size of the stage, just update it. */
@ -629,21 +633,26 @@ clutter_stage_x11_realize (ClutterStageWindow *stage_window)
if (stage_x11->xwin != None)
{
cogl_x11_onscreen_set_foreign_window_xid (stage_cogl->onscreen,
cogl_x11_onscreen_set_foreign_window_xid (stage_x11->onscreen,
stage_x11->xwin,
_clutter_stage_x11_update_foreign_event_mask,
stage_x11);
}
/* Chain to the parent class now. ClutterStageCogl will call cogl_framebuffer_allocate,
which will create the X Window we need */
if (!cogl_framebuffer_allocate (stage_x11->onscreen, &error))
{
g_warning ("Failed to allocate stage: %s", error->message);
g_error_free (error);
cogl_object_unref (stage_x11->onscreen);
abort();
}
if (!(clutter_stage_window_parent_iface->realize (stage_window)))
return FALSE;
if (stage_x11->xwin == None)
stage_x11->xwin = cogl_x11_onscreen_get_window_xid (stage_cogl->onscreen);
stage_x11->xwin = cogl_x11_onscreen_get_window_xid (stage_x11->onscreen);
if (clutter_stages_by_xid == NULL)
clutter_stages_by_xid = g_hash_table_new (NULL, NULL);
@ -883,6 +892,47 @@ 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)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
return stage_x11->onscreen;
}
static CoglFrameClosure *
clutter_stage_x11_set_frame_callback (ClutterStageWindow *stage_window,
CoglFrameCallback callback,
gpointer user_data)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
cogl_onscreen_set_swap_throttled (stage_x11->onscreen,
_clutter_get_sync_to_vblank ());
return cogl_onscreen_add_frame_callback (stage_x11->onscreen,
callback,
user_data,
NULL);
}
static void
clutter_stage_x11_remove_frame_callback (ClutterStageWindow *stage_window,
CoglFrameClosure *closure)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
cogl_onscreen_remove_frame_callback (stage_x11->onscreen, closure);
}
static int64_t
clutter_stage_x11_get_frame_counter (ClutterStageWindow *stage_window)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
return cogl_onscreen_get_frame_counter (stage_x11->onscreen);
}
static void
clutter_stage_x11_finalize (GObject *gobject)
{
@ -957,6 +1007,10 @@ 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->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;
}
static inline void

View File

@ -53,6 +53,7 @@ struct _ClutterStageX11
{
ClutterStageCogl parent_instance;
CoglOnscreen *onscreen;
Window xwin;
gint xwin_width;
gint xwin_height; /* FIXME target_width / height */

View File

@ -26,11 +26,20 @@
#include "backends/native/meta-stage-native.h"
#include "backends/meta-backend-private.h"
#include "meta/meta-backend.h"
#include "meta/meta-monitor-manager.h"
#include "meta/util.h"
struct _MetaStageNative
{
ClutterStageCogl parent;
CoglOnscreen *onscreen;
};
static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
@ -38,12 +47,108 @@ 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 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);
GError *error = NULL;
stage_native->onscreen = cogl_onscreen_new (clutter_backend->cogl_context,
1, 1);
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (stage_native->onscreen),
&error))
meta_fatal ("Failed to allocate onscreen framebuffer: %s\n",
error->message);
if (!(clutter_stage_window_parent_iface->realize (stage_window)))
meta_fatal ("Failed to realize native stage window");
return TRUE;
}
static void
meta_stage_native_unrealize (ClutterStageWindow *stage_window)
{
MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
clutter_stage_window_parent_iface->unrealize (stage_window);
g_clear_pointer (&stage_native->onscreen, cogl_object_unref);
}
static gboolean
meta_stage_native_can_clip_redraws (ClutterStageWindow *stage_window)
{
return TRUE;
}
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);
if (framebuffer)
{
*geometry = (cairo_rectangle_int_t) {
.width = cogl_framebuffer_get_width (framebuffer),
.height = cogl_framebuffer_get_height (framebuffer)
};
}
else
{
*geometry = (cairo_rectangle_int_t) {
.width = 1,
.height = 1,
};
}
}
static CoglFramebuffer *
meta_stage_native_get_legacy_onscreen (ClutterStageWindow *stage_window)
{
MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
return COGL_FRAMEBUFFER (stage_native->onscreen);
}
static CoglClosure *
meta_stage_native_set_frame_callback (ClutterStageWindow *stage_window,
CoglFrameCallback callback,
gpointer user_data)
{
MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
cogl_onscreen_set_swap_throttled (stage_native->onscreen,
_clutter_get_sync_to_vblank ());
return cogl_onscreen_add_frame_callback (stage_native->onscreen,
callback,
user_data,
NULL);
}
static void
meta_stage_native_remove_frame_callback (ClutterStageWindow *stage_window,
CoglFrameClosure *closure)
{
MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
cogl_onscreen_remove_frame_callback (stage_native->onscreen, closure);
}
static int64_t
meta_stage_native_get_frame_counter (ClutterStageWindow *stage_window)
{
MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
return cogl_onscreen_get_frame_counter (stage_native->onscreen);
}
static void
meta_stage_native_init (MetaStageNative *stage_native)
{
@ -57,5 +162,14 @@ meta_stage_native_class_init (MetaStageNativeClass *klass)
static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{
clutter_stage_window_parent_iface = g_type_interface_peek_parent (iface);
iface->realize = meta_stage_native_realize;
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->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;
}