[mutter] backends/native: Support drawing onto multiple onscreen framebuffers
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] backends/native: Support drawing onto multiple onscreen framebuffers
- Date: Wed, 20 Jul 2016 06:28:48 +0000 (UTC)
commit aecd98b847a7fdb83b4449ef2a58a9d61a165d5d
Author: Jonas Ådahl <jadahl gmail com>
Date: Wed Jun 8 17:05:31 2016 +0800
backends/native: Support drawing onto multiple onscreen framebuffers
Add support for drawing the stage using multiple stage views, where
each stage view has its own onscreen framebuffer.
https://bugzilla.gnome.org/show_bug.cgi?id=768976
src/backends/meta-backend-private.h | 2 +
src/backends/meta-backend.c | 16 +
src/backends/meta-renderer-view.c | 68 +++
src/backends/meta-renderer-view.h | 2 +
src/backends/native/meta-backend-native.c | 5 +-
src/backends/native/meta-monitor-manager-kms.c | 171 +++----
src/backends/native/meta-monitor-manager-kms.h | 22 +-
src/backends/native/meta-renderer-native.c | 622 ++++++++++++++++++------
src/backends/native/meta-renderer-native.h | 15 +-
src/backends/native/meta-stage-native.c | 233 +++++----
src/backends/native/meta-stage-native.h | 2 +
11 files changed, 799 insertions(+), 359 deletions(-)
---
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index 5c65ff9..d727ba2 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -144,4 +144,6 @@ ClutterBackend * meta_backend_get_clutter_backend (MetaBackend *backend);
void meta_backend_monitors_changed (MetaBackend *backend);
+gboolean meta_is_stage_views_enabled (void);
+
#endif /* META_BACKEND_PRIVATE_H */
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
index 1889fdb..2fbedcb 100644
--- a/src/backends/meta-backend.c
+++ b/src/backends/meta-backend.c
@@ -748,3 +748,19 @@ meta_clutter_init (void)
meta_backend_post_init (_backend);
}
+
+gboolean
+meta_is_stage_views_enabled (void)
+{
+ const gchar *mutter_stage_views;
+
+ if (!meta_is_wayland_compositor ())
+ return FALSE;
+
+ mutter_stage_views = g_getenv ("MUTTER_STAGE_VIEWS");
+
+ if (!mutter_stage_views)
+ return FALSE;
+
+ return strcmp (mutter_stage_views, "1") == 0;
+}
diff --git a/src/backends/meta-renderer-view.c b/src/backends/meta-renderer-view.c
index 6c9b2b2..6c90c16 100644
--- a/src/backends/meta-renderer-view.c
+++ b/src/backends/meta-renderer-view.c
@@ -22,6 +22,17 @@
#include "backends/meta-renderer.h"
#include "clutter/clutter-mutter.h"
+enum
+{
+ PROP_0,
+
+ PROP_MONITOR_INFO,
+
+ PROP_LAST
+};
+
+static GParamSpec *obj_props[PROP_LAST];
+
struct _MetaRendererView
{
ClutterStageView parent;
@@ -32,6 +43,50 @@ struct _MetaRendererView
G_DEFINE_TYPE (MetaRendererView, meta_renderer_view,
CLUTTER_TYPE_STAGE_VIEW_COGL)
+MetaMonitorInfo *
+meta_renderer_view_get_monitor_info (MetaRendererView *view)
+{
+ return view->monitor_info;
+}
+
+static void
+meta_renderer_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MetaRendererView *view = META_RENDERER_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_MONITOR_INFO:
+ g_value_set_pointer (value, view->monitor_info);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+meta_renderer_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MetaRendererView *view = META_RENDERER_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_MONITOR_INFO:
+ view->monitor_info = g_value_get_pointer (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
static void
meta_renderer_view_init (MetaRendererView *view)
{
@@ -40,4 +95,17 @@ meta_renderer_view_init (MetaRendererView *view)
static void
meta_renderer_view_class_init (MetaRendererViewClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = meta_renderer_view_get_property;
+ object_class->set_property = meta_renderer_view_set_property;
+
+ obj_props[PROP_MONITOR_INFO] =
+ g_param_spec_pointer ("monitor-info",
+ "MetaMonitorInfo",
+ "The monitor info of the view",
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class, PROP_LAST, obj_props);
}
diff --git a/src/backends/meta-renderer-view.h b/src/backends/meta-renderer-view.h
index 0f08760..9c43fbb 100644
--- a/src/backends/meta-renderer-view.h
+++ b/src/backends/meta-renderer-view.h
@@ -26,4 +26,6 @@ G_DECLARE_FINAL_TYPE (MetaRendererView, meta_renderer_view,
META, RENDERER_VIEW,
ClutterStageViewCogl)
+MetaMonitorInfo *meta_renderer_view_get_monitor_info (MetaRendererView *view);
+
#endif /* META_RENDERER_VIEW_H */
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index 5edfd79..385122c 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -390,7 +390,10 @@ meta_backend_native_update_screen_size (MetaBackend *backend,
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);
+ if (meta_is_stage_views_enabled ())
+ meta_stage_native_rebuild_views (stage_native);
+ else
+ meta_stage_native_legacy_set_size (stage_native, width, height);
clutter_actor_set_size (stage, width, height);
}
diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c
index 791d09b..04d96aa 100644
--- a/src/backends/native/meta-monitor-manager-kms.c
+++ b/src/backends/native/meta-monitor-manager-kms.c
@@ -78,14 +78,6 @@ typedef struct {
typedef struct
{
- int pending;
-
- MetaKmsFlipCallback callback;
- void *user_data;
-} MetaKmsFlipClosure;
-
-typedef struct
-{
GSource source;
gpointer fd_tag;
@@ -1065,12 +1057,8 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
unsigned int n_outputs)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
- MetaBackend *backend;
- MetaRenderer *renderer;
unsigned i;
int screen_width, screen_height;
- gboolean ok;
- GError *error;
screen_width = 0; screen_height = 0;
for (i = 0; i < n_crtcs; i++)
@@ -1156,20 +1144,6 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
crtc->current_mode = NULL;
}
- backend = meta_get_backend ();
- renderer = meta_backend_get_renderer (backend);
-
- error = NULL;
- ok = meta_renderer_native_set_layout (META_RENDERER_NATIVE (renderer),
- screen_width, screen_height,
- &error);
- if (!ok)
- {
- meta_warning ("Applying display configuration failed: %s\n", error->message);
- g_error_free (error);
- return;
- }
-
for (i = 0; i < n_outputs; i++)
{
MetaOutputInfo *output_info = outputs[i];
@@ -1344,79 +1318,95 @@ get_crtc_connectors (MetaMonitorManager *manager,
}
void
-meta_monitor_manager_kms_apply_crtc_modes (MetaMonitorManagerKms *manager_kms,
- uint32_t fb_id)
+meta_monitor_manager_kms_apply_crtc_mode (MetaMonitorManagerKms *manager_kms,
+ MetaCRTC *crtc,
+ int x,
+ int y,
+ uint32_t fb_id)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
- unsigned int i;
+ uint32_t *connectors;
+ unsigned int n_connectors;
+ drmModeModeInfo *mode;
- for (i = 0; i < manager->n_crtcs; i++)
- {
- MetaCRTC *crtc = &manager->crtcs[i];
- uint32_t *connectors;
- unsigned int n_connectors;
- drmModeModeInfo *mode;
+ get_crtc_connectors (manager, crtc, &connectors, &n_connectors);
- get_crtc_connectors (manager, crtc, &connectors, &n_connectors);
+ if (connectors)
+ mode = crtc->current_mode->driver_private;
+ else
+ mode = NULL;
- if (connectors)
- mode = crtc->current_mode->driver_private;
- else
- mode = NULL;
+ if (drmModeSetCrtc (manager_kms->fd,
+ crtc->crtc_id,
+ fb_id,
+ x, y,
+ connectors, n_connectors,
+ mode) != 0)
+ g_warning ("Failed to set CRTC mode %s: %m", crtc->current_mode->name);
- if (drmModeSetCrtc (manager_kms->fd,
- crtc->crtc_id,
- fb_id,
- crtc->rect.x, crtc->rect.y,
- connectors, n_connectors,
- mode) != 0)
- g_warning ("Failed to set CRTC mode %s: %m", crtc->current_mode->name);
+ g_free (connectors);
+}
- g_free (connectors);
- }
+static void
+invoke_flip_closure (GClosure *flip_closure)
+{
+ GValue param = G_VALUE_INIT;
+
+ g_value_init (¶m, G_TYPE_POINTER);
+ g_value_set_pointer (¶m, flip_closure);
+ g_closure_invoke (flip_closure, NULL, 1, ¶m, NULL);
+ g_closure_unref (flip_closure);
}
gboolean
-meta_monitor_manager_kms_flip_all_crtcs (MetaMonitorManagerKms *manager_kms,
- uint32_t fb_id,
- MetaKmsFlipCallback flip_callback,
- void *user_data)
+meta_monitor_manager_kms_is_crtc_active (MetaMonitorManagerKms *manager_kms,
+ MetaCRTC *crtc)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
- MetaKmsFlipClosure *flip_closure = NULL;
unsigned int i;
- gboolean fb_in_use = FALSE;
+ gboolean connected_crtc_found;
if (manager->power_save_mode != META_POWER_SAVE_ON)
return FALSE;
- for (i = 0; i < manager->n_crtcs; i++)
+ connected_crtc_found = FALSE;
+ for (i = 0; i < manager->n_outputs; i++)
{
- MetaCRTC *crtc = &manager->crtcs[i];
- uint32_t *connectors;
- unsigned int n_connectors;
- int ret;
+ MetaOutput *output = &manager->outputs[i];
- get_crtc_connectors (manager, crtc, &connectors, &n_connectors);
+ if (output->crtc == crtc)
+ {
+ connected_crtc_found = TRUE;
+ break;
+ }
+ }
- if (n_connectors == 0)
- continue;
+ if (!connected_crtc_found)
+ return FALSE;
- fb_in_use = TRUE;
+ return TRUE;
+}
- if (manager_kms->page_flips_not_supported)
- continue;
+gboolean
+meta_monitor_manager_kms_flip_crtc (MetaMonitorManagerKms *manager_kms,
+ MetaCRTC *crtc,
+ int x,
+ int y,
+ uint32_t fb_id,
+ GClosure *flip_closure)
+{
+ MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
+ uint32_t *connectors;
+ unsigned int n_connectors;
+ int ret = -1;
- if (!flip_closure)
- {
- flip_closure = g_new0 (MetaKmsFlipClosure, 1);
- *flip_closure = (MetaKmsFlipClosure) {
- .pending = 0,
- .callback = flip_callback,
- .user_data = user_data
- };
- }
+ g_assert (manager->power_save_mode == META_POWER_SAVE_ON);
+
+ get_crtc_connectors (manager, crtc, &connectors, &n_connectors);
+ g_assert (n_connectors > 0);
+ if (!manager_kms->page_flips_not_supported)
+ {
ret = drmModePageFlip (manager_kms->fd,
crtc->crtc_id,
fb_id,
@@ -1426,24 +1416,21 @@ meta_monitor_manager_kms_flip_all_crtcs (MetaMonitorManagerKms *manager_kms,
{
g_warning ("Failed to flip: %s", strerror (-ret));
manager_kms->page_flips_not_supported = TRUE;
- break;
}
-
- if (ret == 0)
- flip_closure->pending++;
}
- if (manager_kms->page_flips_not_supported && fb_in_use)
- {
- /* If the driver doesn't support page flipping, just set the mode directly
- * with the new framebuffer.
- */
- meta_monitor_manager_kms_apply_crtc_modes (manager_kms, fb_id);
- flip_callback (user_data);
- g_free (flip_closure);
- }
+ if (manager_kms->page_flips_not_supported)
+ meta_monitor_manager_kms_apply_crtc_mode (manager_kms,
+ crtc,
+ x, y,
+ fb_id);
+
+ if (ret != 0)
+ return FALSE;
+
+ g_closure_ref (flip_closure);
- return fb_in_use;
+ return TRUE;
}
static void
@@ -1453,11 +1440,9 @@ page_flip_handler (int fd,
unsigned int usec,
void *data)
{
- MetaKmsFlipClosure *flip_closure = data;
+ GClosure *flip_closure = data;
- flip_closure->pending--;
- if (flip_closure->pending == 0)
- flip_closure->callback (flip_closure->user_data);
+ invoke_flip_closure (flip_closure);
}
void
diff --git a/src/backends/native/meta-monitor-manager-kms.h b/src/backends/native/meta-monitor-manager-kms.h
index 3f6251d..3386b93 100644
--- a/src/backends/native/meta-monitor-manager-kms.h
+++ b/src/backends/native/meta-monitor-manager-kms.h
@@ -39,13 +39,21 @@ GType meta_monitor_manager_kms_get_type (void);
typedef void (*MetaKmsFlipCallback) (void *user_data);
-void meta_monitor_manager_kms_apply_crtc_modes (MetaMonitorManagerKms *manager_kms,
- uint32_t fb_id);
-
-gboolean meta_monitor_manager_kms_flip_all_crtcs (MetaMonitorManagerKms *manager_kms,
- uint32_t fb_id,
- MetaKmsFlipCallback flip_callback,
- void *user_data);
+void meta_monitor_manager_kms_apply_crtc_mode (MetaMonitorManagerKms *manager_kms,
+ MetaCRTC *crtc,
+ int x,
+ int y,
+ uint32_t fb_id);
+
+gboolean meta_monitor_manager_kms_is_crtc_active (MetaMonitorManagerKms *manager_kms,
+ MetaCRTC *crtc);
+
+gboolean meta_monitor_manager_kms_flip_crtc (MetaMonitorManagerKms *manager_kms,
+ MetaCRTC *crtc,
+ int x,
+ int y,
+ uint32_t fb_id,
+ GClosure *flip_closure);
void meta_monitor_manager_kms_wait_for_flip (MetaMonitorManagerKms *manager_kms);
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index b4a7aa3..e8d7451 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -47,9 +47,11 @@
#include <xf86drm.h>
#include "backends/meta-backend-private.h"
+#include "backends/meta-renderer-view.h"
#include "backends/native/meta-monitor-manager-kms.h"
#include "backends/native/meta-renderer-native.h"
#include "cogl/cogl.h"
+#include "core/boxes-private.h"
enum
{
@@ -71,6 +73,11 @@ typedef struct _MetaOnscreenNative
EGLSurface *pending_egl_surface;
struct gbm_surface *pending_surface;
+
+ gboolean pending_set_crtc;
+
+ MetaRendererView *view;
+ int pending_flips;
} MetaOnscreenNative;
struct _MetaRendererNative
@@ -81,11 +88,9 @@ struct _MetaRendererNative
struct gbm_device *gbm;
CoglClosure *swap_notify_idle;
- int width, height;
- gboolean pending_set_crtc;
- struct gbm_surface *dummy_gbm_surface;
+ int64_t frame_counter;
- CoglOnscreen *onscreen;
+ struct gbm_surface *dummy_gbm_surface;
};
static void
@@ -112,11 +117,8 @@ meta_renderer_native_disconnect (CoglRenderer *cogl_renderer)
}
static void
-flush_pending_swap_notify_cb (void *data,
- void *user_data)
+flush_pending_swap_notify (CoglFramebuffer *framebuffer)
{
- CoglFramebuffer *framebuffer = data;
-
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
@@ -130,7 +132,9 @@ flush_pending_swap_notify_cb (void *data,
_cogl_onscreen_notify_frame_sync (onscreen, info);
_cogl_onscreen_notify_complete (onscreen, info);
+
onscreen_native->pending_swap_notify = FALSE;
+ cogl_object_unref (onscreen);
cogl_object_unref (info);
}
@@ -143,15 +147,23 @@ flush_pending_swap_notify_idle (void *user_data)
CoglContext *cogl_context = user_data;
CoglRendererEGL *egl_renderer = cogl_context->display->renderer->winsys;
MetaRendererNative *renderer_native = egl_renderer->platform;
+ GList *l;
/* This needs to be disconnected before invoking the callbacks in
* case the callbacks cause it to be queued again */
_cogl_closure_disconnect (renderer_native->swap_notify_idle);
renderer_native->swap_notify_idle = NULL;
- g_list_foreach (cogl_context->framebuffers,
- flush_pending_swap_notify_cb,
- NULL);
+ l = cogl_context->framebuffers;
+ while (l)
+ {
+ GList *next = l->next;
+ CoglFramebuffer *framebuffer = l->data;
+
+ flush_pending_swap_notify (framebuffer);
+
+ l = next;
+ }
}
static void
@@ -179,11 +191,14 @@ free_current_bo (CoglOnscreen *onscreen)
}
static void
-queue_swap_notify_for_onscreen (CoglOnscreen *onscreen)
+meta_onscreen_native_queue_swap_notify (CoglOnscreen *onscreen)
{
- CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+ CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
- CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->context;
+ MetaBackend *backend = meta_get_backend ();
+ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+ CoglContext *cogl_context =
+ clutter_backend_get_cogl_context (clutter_backend);
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
CoglRendererEGL *egl_renderer = cogl_renderer->winsys;
MetaRendererNative *renderer_native = egl_renderer->platform;
@@ -200,6 +215,13 @@ queue_swap_notify_for_onscreen (CoglOnscreen *onscreen)
NULL);
}
+ /*
+ * The framebuffer will have its own referenc while the swap notify is
+ * pending. Otherwise when destroying the view would drop the pending
+ * notification with if the destruction happens before the idle callback
+ * is invoked.
+ */
+ cogl_object_ref (onscreen);
onscreen_native->pending_swap_notify = TRUE;
}
@@ -248,18 +270,6 @@ fail:
return FALSE;
}
-static void
-setup_crtc_modes (CoglDisplay *cogl_display, int fb_id)
-{
- MetaBackend *backend = meta_get_backend ();
- MetaMonitorManager *monitor_manager =
- meta_backend_get_monitor_manager (backend);
- MetaMonitorManagerKms *monitor_manager_kms =
- META_MONITOR_MANAGER_KMS (monitor_manager);
-
- meta_monitor_manager_kms_apply_crtc_modes (monitor_manager_kms, fb_id);
-}
-
static CoglBool
meta_renderer_native_setup_egl_display (CoglDisplay *cogl_display,
CoglError **error)
@@ -273,7 +283,7 @@ meta_renderer_native_setup_egl_display (CoglDisplay *cogl_display,
/* Force a full modeset / drmModeSetCrtc on
* the first swap buffers call.
*/
- renderer_native->pending_set_crtc = TRUE;
+ meta_renderer_native_queue_modes_reset (renderer_native);
return TRUE;
}
@@ -352,14 +362,11 @@ meta_renderer_native_egl_cleanup_context (CoglDisplay *cogl_display)
}
static void
-flip_callback (void *user_data)
+meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen)
{
- CoglOnscreen *onscreen = user_data;
- CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+ CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
- queue_swap_notify_for_onscreen (onscreen);
-
free_current_bo (onscreen);
onscreen_native->current_fb_id = onscreen_native->next_fb_id;
@@ -367,8 +374,205 @@ flip_callback (void *user_data)
onscreen_native->current_bo = onscreen_native->next_bo;
onscreen_native->next_bo = NULL;
+}
- cogl_object_unref (onscreen);
+static void
+on_crtc_flipped (GClosure *closure,
+ MetaRendererView *view)
+{
+ ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
+ CoglFramebuffer *framebuffer =
+ clutter_stage_view_get_framebuffer (stage_view);
+ CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+ CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+ MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
+
+ onscreen_native->pending_flips--;
+ if (onscreen_native->pending_flips == 0)
+ {
+ meta_onscreen_native_queue_swap_notify (onscreen);
+ meta_onscreen_native_swap_drm_fb (onscreen);
+ }
+}
+
+static void
+flip_closure_destroyed (MetaRendererView *view)
+{
+ ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
+ CoglFramebuffer *framebuffer =
+ clutter_stage_view_get_framebuffer (stage_view);
+ CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+ CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+ MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
+
+ if (onscreen_native->next_fb_id)
+ {
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
+
+ drmModeRmFB (renderer_native->kms_fd, onscreen_native->next_fb_id);
+ gbm_surface_release_buffer (onscreen_native->surface,
+ onscreen_native->next_bo);
+ onscreen_native->next_bo = NULL;
+ onscreen_native->next_fb_id = 0;
+
+ meta_onscreen_native_queue_swap_notify (onscreen);
+ }
+
+ g_object_unref (view);
+}
+
+static void
+meta_onscreen_native_flip_crtc (MetaOnscreenNative *onscreen_native,
+ GClosure *flip_closure,
+ MetaCRTC *crtc,
+ int x,
+ int y,
+ gboolean *fb_in_use)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaMonitorManager *monitor_manager =
+ meta_backend_get_monitor_manager (backend);
+ MetaMonitorManagerKms *monitor_manager_kms =
+ META_MONITOR_MANAGER_KMS (monitor_manager);
+
+ if (!meta_monitor_manager_kms_is_crtc_active (monitor_manager_kms,
+ crtc))
+ {
+ *fb_in_use = FALSE;
+ return;
+ }
+
+ if (meta_monitor_manager_kms_flip_crtc (monitor_manager_kms,
+ crtc,
+ x, y,
+ onscreen_native->next_fb_id,
+ flip_closure))
+ onscreen_native->pending_flips++;
+
+ *fb_in_use = TRUE;
+}
+
+static void
+meta_onscreen_native_set_crtc_modes (MetaOnscreenNative *onscreen_native)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaMonitorManager *monitor_manager =
+ meta_backend_get_monitor_manager (backend);
+ MetaMonitorManagerKms *monitor_manager_kms =
+ META_MONITOR_MANAGER_KMS (monitor_manager);
+ MetaRendererView *view = onscreen_native->view;
+ uint32_t next_fb_id = onscreen_native->next_fb_id;
+ MetaMonitorInfo *monitor_info;
+
+ monitor_info = meta_renderer_view_get_monitor_info (view);
+ if (monitor_info)
+ {
+ int i;
+
+ for (i = 0; i < monitor_info->n_outputs; i++)
+ {
+ MetaOutput *output = monitor_info->outputs[i];
+ int x = output->crtc->rect.x - monitor_info->rect.x;
+ int y = output->crtc->rect.y - monitor_info->rect.y;
+
+ meta_monitor_manager_kms_apply_crtc_mode (monitor_manager_kms,
+ output->crtc,
+ x, y,
+ next_fb_id);
+ }
+ }
+ else
+ {
+ unsigned int i;
+
+ for (i = 0; i < monitor_manager->n_crtcs; i++)
+ {
+ MetaCRTC *crtc = &monitor_manager->crtcs[i];
+
+ meta_monitor_manager_kms_apply_crtc_mode (monitor_manager_kms,
+ crtc,
+ crtc->rect.x, crtc->rect.y,
+ next_fb_id);
+ }
+ }
+}
+
+static void
+meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen)
+{
+ CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+ MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
+ MetaBackend *backend = meta_get_backend ();
+ MetaMonitorManager *monitor_manager =
+ meta_backend_get_monitor_manager (backend);
+ MetaRendererView *view = onscreen_native->view;
+ GClosure *flip_closure;
+ MetaMonitorInfo *monitor_info;
+ gboolean fb_in_use = FALSE;
+
+ /*
+ * Create a closure that either will be invoked or destructed.
+ * Invoking the closure represents a completed flip. If the closure
+ * is destructed before being invoked, the framebuffer references will be
+ * cleaned up accordingly.
+ *
+ * Each successful flip will each own one reference to the closure, thus keep
+ * it alive until either invoked or destructed. If flipping failed, the
+ * closure will be destructed before this function goes out of scope.
+ */
+ flip_closure = g_cclosure_new (G_CALLBACK (on_crtc_flipped),
+ g_object_ref (view),
+ (GClosureNotify) flip_closure_destroyed);
+ g_closure_set_marshal (flip_closure, g_cclosure_marshal_generic);
+
+ /* Either flip the CRTC's of the monitor info, if we are drawing just part
+ * of the stage, or all of the CRTC's if we are drawing the whole stage.
+ */
+ monitor_info = meta_renderer_view_get_monitor_info (view);
+ if (monitor_info)
+ {
+ int i;
+
+ for (i = 0; i < monitor_info->n_outputs; i++)
+ {
+ MetaOutput *output = monitor_info->outputs[i];
+ int x = output->crtc->rect.x - monitor_info->rect.x;
+ int y = output->crtc->rect.y - monitor_info->rect.y;
+
+ meta_onscreen_native_flip_crtc (onscreen_native, flip_closure,
+ output->crtc, x, y,
+ &fb_in_use);
+ }
+ }
+ else
+ {
+ unsigned int i;
+
+ for (i = 0; i < monitor_manager->n_crtcs; i++)
+ {
+ MetaCRTC *crtc = &monitor_manager->crtcs[i];
+
+ meta_onscreen_native_flip_crtc (onscreen_native, flip_closure,
+ crtc, crtc->rect.x, crtc->rect.y,
+ &fb_in_use);
+ }
+ }
+
+ /*
+ * If the framebuffer is in use, but we don't have any pending flips it means
+ * that flipping is not supported and we set the next framebuffer directly.
+ * Since we won't receive a flip callback, lets just notify listeners
+ * directly.
+ */
+ if (fb_in_use && onscreen_native->pending_flips == 0)
+ {
+ meta_onscreen_native_queue_swap_notify (onscreen);
+ meta_onscreen_native_swap_drm_fb (onscreen);
+ }
+
+ g_closure_unref (flip_closure);
}
static void
@@ -387,27 +591,35 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
MetaRendererNative *renderer_native = egl_renderer->platform;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
+ CoglFrameInfo *frame_info;
+ MetaRendererView *view;
+ cairo_rectangle_int_t view_layout;
uint32_t handle, stride;
- gboolean fb_in_use;
- uint32_t next_fb_id;
+
+ frame_info = g_queue_peek_tail (&onscreen->pending_frame_infos);
+ frame_info->global_frame_counter = renderer_native->frame_counter;
/* If we already have a pending swap then block until it completes */
while (onscreen_native->next_fb_id != 0)
meta_monitor_manager_kms_wait_for_flip (monitor_manager_kms);
+ view = onscreen_native->view;
+ clutter_stage_view_get_layout (CLUTTER_STAGE_VIEW (view), &view_layout);
+
if (onscreen_native->pending_egl_surface)
{
- CoglFramebuffer *fb = COGL_FRAMEBUFFER (renderer_native->onscreen);
+ CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface);
egl_onscreen->egl_surface = onscreen_native->pending_egl_surface;
onscreen_native->pending_egl_surface = NULL;
_cogl_framebuffer_winsys_update_size (fb,
- renderer_native->width,
- renderer_native->height);
+ view_layout.width,
+ view_layout.height);
cogl_context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND;
}
+
parent_vtable->onscreen_swap_buffers_with_damage (onscreen,
rectangles,
n_rectangles);
@@ -420,6 +632,7 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
onscreen_native->surface = onscreen_native->pending_surface;
onscreen_native->pending_surface = NULL;
}
+
/* Now we need to set the CRTC to whatever is the front buffer */
onscreen_native->next_bo =
gbm_surface_lock_front_buffer (onscreen_native->surface);
@@ -428,8 +641,8 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
handle = gbm_bo_get_handle (onscreen_native->next_bo).u32;
if (drmModeAddFB (renderer_native->kms_fd,
- renderer_native->width,
- renderer_native->height,
+ view_layout.width,
+ view_layout.height,
24, /* depth */
32, /* bpp */
stride,
@@ -446,34 +659,13 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
/* If this is the first framebuffer to be presented then we now setup the
* crtc modes, else we flip from the previous buffer */
- if (renderer_native->pending_set_crtc)
+ if (onscreen_native->pending_set_crtc)
{
- setup_crtc_modes (cogl_context->display, onscreen_native->next_fb_id);
- renderer_native->pending_set_crtc = FALSE;
+ meta_onscreen_native_set_crtc_modes (onscreen_native);
+ onscreen_native->pending_set_crtc = FALSE;
}
- next_fb_id = onscreen_native->next_fb_id;
-
- /* Reference will either be released in flip_callback, or if the fb
- * wasn't used, indicated by the return value below.
- */
- cogl_object_ref (onscreen);
- fb_in_use = meta_monitor_manager_kms_flip_all_crtcs (monitor_manager_kms,
- next_fb_id,
- flip_callback, onscreen);
-
- if (!fb_in_use)
- {
- drmModeRmFB (renderer_native->kms_fd, onscreen_native->next_fb_id);
- gbm_surface_release_buffer (onscreen_native->surface,
- onscreen_native->next_bo);
- onscreen_native->next_bo = NULL;
- onscreen_native->next_fb_id = 0;
-
- queue_swap_notify_for_onscreen (onscreen);
-
- g_object_unref (onscreen);
- }
+ meta_onscreen_native_flip_crtcs (onscreen);
}
static CoglBool
@@ -489,6 +681,62 @@ meta_renderer_native_init_egl_context (CoglContext *cogl_context,
COGL_FLAGS_SET (cogl_context->winsys_features,
COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT,
TRUE);
+ COGL_FLAGS_SET (cogl_context->winsys_features,
+ COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
+ TRUE);
+
+ return TRUE;
+}
+
+static gboolean
+meta_renderer_native_create_surface (MetaRendererNative *renderer_native,
+ int width,
+ int height,
+ struct gbm_surface **gbm_surface,
+ EGLSurface *egl_surface,
+ GError **error)
+{
+ MetaBackend *backend = meta_get_backend ();
+ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+ CoglContext *cogl_context =
+ clutter_backend_get_cogl_context (clutter_backend);
+ CoglDisplay *cogl_display = cogl_context->display;
+ CoglDisplayEGL *egl_display = cogl_display->winsys;
+ CoglRendererEGL *egl_renderer = cogl_display->renderer->winsys;
+ struct gbm_surface *new_gbm_surface;
+ EGLNativeWindowType egl_native_window;
+ EGLSurface new_egl_surface;
+
+ new_gbm_surface = gbm_surface_create (renderer_native->gbm,
+ width, height,
+ GBM_FORMAT_XRGB8888,
+ GBM_BO_USE_SCANOUT |
+ GBM_BO_USE_RENDERING);
+
+ if (!new_gbm_surface)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_ONSCREEN,
+ "Failed to allocate surface");
+ return FALSE;
+ }
+
+ egl_native_window = (EGLNativeWindowType) new_gbm_surface;
+ new_egl_surface = eglCreateWindowSurface (egl_renderer->edpy,
+ egl_display->egl_config,
+ egl_native_window,
+ NULL);
+ if (new_egl_surface == EGL_NO_SURFACE)
+ {
+ gbm_surface_destroy (new_gbm_surface);
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_ONSCREEN,
+ "Failed to allocate surface");
+ return FALSE;
+ }
+
+ *gbm_surface = new_gbm_surface;
+ *egl_surface = new_egl_surface;
return TRUE;
}
@@ -506,66 +754,38 @@ meta_renderer_native_init_onscreen (CoglOnscreen *onscreen,
MetaRendererNative *renderer_native = egl_renderer->platform;
CoglOnscreenEGL *egl_onscreen;
MetaOnscreenNative *onscreen_native;
+ int width;
+ int height;
_COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE);
- if (renderer_native->onscreen)
- {
- _cogl_set_error (error, COGL_WINSYS_ERROR,
- COGL_WINSYS_ERROR_CREATE_ONSCREEN,
- "Cannot have multiple onscreens in the KMS platform");
- return FALSE;
- }
-
- renderer_native->onscreen = onscreen;
-
onscreen->winsys = g_slice_new0 (CoglOnscreenEGL);
egl_onscreen = onscreen->winsys;
onscreen_native = g_slice_new0 (MetaOnscreenNative);
egl_onscreen->platform = onscreen_native;
+ onscreen_native->pending_set_crtc = TRUE;
+
/* If a kms_fd is set then the display width and height
* won't be available until meta_renderer_native_set_layout
* is called. In that case, defer creating the surface
* until then.
*/
- if (renderer_native->width == 0 ||
- renderer_native->height == 0)
+ width = cogl_framebuffer_get_width (framebuffer);
+ height = cogl_framebuffer_get_height (framebuffer);
+ if (width == 0 || height == 0)
return TRUE;
- onscreen_native->surface =
- gbm_surface_create (renderer_native->gbm,
- renderer_native->width,
- renderer_native->height,
- GBM_FORMAT_XRGB8888,
- GBM_BO_USE_SCANOUT |
- GBM_BO_USE_RENDERING);
-
- if (!onscreen_native->surface)
- {
- _cogl_set_error (error, COGL_WINSYS_ERROR,
- COGL_WINSYS_ERROR_CREATE_ONSCREEN,
- "Failed to allocate surface");
- return FALSE;
- }
+ if (!meta_renderer_native_create_surface (renderer_native,
+ width, height,
+ &onscreen_native->surface,
+ &egl_onscreen->egl_surface,
+ error))
+ return FALSE;
- egl_onscreen->egl_surface =
- eglCreateWindowSurface (egl_renderer->edpy,
- egl_display->egl_config,
- (EGLNativeWindowType) onscreen_native->surface,
- NULL);
- if (egl_onscreen->egl_surface == EGL_NO_SURFACE)
- {
- _cogl_set_error (error, COGL_WINSYS_ERROR,
- COGL_WINSYS_ERROR_CREATE_ONSCREEN,
- "Failed to allocate surface");
- return FALSE;
- }
- _cogl_framebuffer_winsys_update_size (framebuffer,
- renderer_native->width,
- renderer_native->height);
+ _cogl_framebuffer_winsys_update_size (framebuffer, width, height);
return TRUE;
}
@@ -575,9 +795,6 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
{
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
CoglContext *cogl_context = framebuffer->context;
- CoglDisplay *cogl_display = cogl_context->display;
- CoglDisplayEGL *egl_display = cogl_display->winsys;
- MetaRendererNative *renderer_native = egl_display->platform;
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
CoglRendererEGL *egl_renderer = cogl_renderer->winsys;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
@@ -587,8 +804,6 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
if (egl_onscreen == NULL)
return;
- renderer_native->onscreen = NULL;
-
onscreen_native = egl_onscreen->platform;
/* flip state takes a reference on the onscreen so there should
@@ -638,60 +853,57 @@ meta_renderer_native_get_kms_fd (MetaRendererNative *renderer_native)
void
meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native)
{
- renderer_native->pending_set_crtc = TRUE;
+ MetaRenderer *renderer = META_RENDERER (renderer_native);
+ GList *l;
+
+ for (l = meta_renderer_get_views (renderer); l; l = l->next)
+ {
+ ClutterStageView *stage_view = l->data;
+ CoglFramebuffer *framebuffer =
+ clutter_stage_view_get_framebuffer (stage_view);
+ CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+ CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+ MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
+
+ onscreen_native->pending_set_crtc = TRUE;
+ }
}
gboolean
-meta_renderer_native_set_layout (MetaRendererNative *renderer_native,
- int width,
- int height,
- GError **error)
+meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native,
+ MetaRendererView *view,
+ int width,
+ int height,
+ GError **error)
{
ClutterBackend *clutter_backend = clutter_get_default_backend ();
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
- CoglDisplayEGL *egl_display = cogl_display->winsys;
- CoglRenderer *cogl_renderer = cogl_display->renderer;
- CoglRendererEGL *egl_renderer = cogl_renderer->winsys;
+ CoglRendererEGL *egl_renderer = cogl_display->renderer->winsys;
+ ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
+ cairo_rectangle_int_t view_layout;
- if ((width != renderer_native->width ||
- height != renderer_native->height) &&
- renderer_native->onscreen)
+ clutter_stage_view_get_layout (stage_view, &view_layout);
+
+ if (width != view_layout.width || height != view_layout.height)
{
- CoglOnscreenEGL *egl_onscreen = renderer_native->onscreen->winsys;
+ CoglFramebuffer *framebuffer =
+ clutter_stage_view_get_framebuffer (stage_view);
+ CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+ CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
struct gbm_surface *new_surface;
EGLSurface new_egl_surface;
/* Need to drop the GBM surface and create a new one */
- new_surface = gbm_surface_create (renderer_native->gbm,
- width, height,
- GBM_FORMAT_XRGB8888,
- GBM_BO_USE_SCANOUT |
- GBM_BO_USE_RENDERING);
-
- if (!new_surface)
- {
- _cogl_set_error (error, COGL_WINSYS_ERROR,
- COGL_WINSYS_ERROR_CREATE_ONSCREEN,
- "Failed to allocate new surface");
- return FALSE;
- }
+ if (!meta_renderer_native_create_surface (renderer_native,
+ width, height,
+ &new_surface,
+ &new_egl_surface,
+ error))
+ return FALSE;
- new_egl_surface =
- eglCreateWindowSurface (egl_renderer->edpy,
- egl_display->egl_config,
- (EGLNativeWindowType) new_surface,
- NULL);
- if (new_egl_surface == EGL_NO_SURFACE)
- {
- _cogl_set_error (error, COGL_WINSYS_ERROR,
- COGL_WINSYS_ERROR_CREATE_ONSCREEN,
- "Failed to allocate new surface");
- gbm_surface_destroy (new_surface);
- return FALSE;
- }
if (onscreen_native->pending_egl_surface)
eglDestroySurface (egl_renderer->edpy,
@@ -710,8 +922,6 @@ meta_renderer_native_set_layout (MetaRendererNative *renderer_native,
}
else
{
- CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (renderer_native->onscreen);
-
onscreen_native->surface = new_surface;
egl_onscreen->egl_surface = new_egl_surface;
@@ -719,10 +929,7 @@ meta_renderer_native_set_layout (MetaRendererNative *renderer_native,
}
}
- renderer_native->width = width;
- renderer_native->height = height;
-
- renderer_native->pending_set_crtc = TRUE;
+ meta_renderer_native_queue_modes_reset (renderer_native);
return TRUE;
}
@@ -774,6 +981,108 @@ meta_renderer_native_create_cogl_renderer (MetaRenderer *renderer)
}
static void
+meta_onscreen_native_set_view (CoglOnscreen *onscreen,
+ MetaRendererView *view)
+{
+ CoglOnscreenEGL *egl_onscreen;
+ MetaOnscreenNative *onscreen_native;
+
+ egl_onscreen = onscreen->winsys;
+ onscreen_native = egl_onscreen->platform;
+ onscreen_native->view = view;
+}
+
+MetaRendererView *
+meta_renderer_native_create_legacy_view (MetaRendererNative *renderer_native)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaMonitorManager *monitor_manager =
+ meta_backend_get_monitor_manager (backend);
+ CoglOnscreen *onscreen;
+ CoglFramebuffer *framebuffer;
+ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+ CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
+ cairo_rectangle_int_t view_layout = { 0 };
+ MetaRendererView *view;
+ GError *error = NULL;
+
+ if (!monitor_manager)
+ return NULL;
+
+ meta_monitor_manager_get_screen_size (monitor_manager,
+ &view_layout.width,
+ &view_layout.height);
+
+ onscreen = cogl_onscreen_new (cogl_context,
+ view_layout.width,
+ view_layout.height);
+ cogl_onscreen_set_swap_throttled (onscreen,
+ _clutter_get_sync_to_vblank ());
+
+ framebuffer = COGL_FRAMEBUFFER (onscreen);
+ if (!cogl_framebuffer_allocate (framebuffer, &error))
+ meta_fatal ("Failed to allocate onscreen framebuffer: %s\n",
+ error->message);
+
+ view = g_object_new (META_TYPE_RENDERER_VIEW,
+ "layout", &view_layout,
+ "framebuffer", framebuffer,
+ NULL);
+
+ meta_onscreen_native_set_view (onscreen, view);
+
+ return view;
+}
+
+static MetaRendererView *
+meta_renderer_native_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);
+ CoglOnscreen *onscreen;
+ CoglFramebuffer *framebuffer;
+ cairo_rectangle_int_t view_layout;
+ MetaRendererView *view;
+ GError *error = NULL;
+
+ view_layout = meta_rectangle_to_cairo_rectangle (&monitor_info->rect);
+ onscreen = cogl_onscreen_new (cogl_context,
+ view_layout.width,
+ view_layout.height);
+ cogl_onscreen_set_swap_throttled (onscreen,
+ _clutter_get_sync_to_vblank ());
+
+ framebuffer = COGL_FRAMEBUFFER (onscreen);
+ if (!cogl_framebuffer_allocate (framebuffer, &error))
+ meta_fatal ("Failed to allocate onscreen framebuffer: %s\n",
+ error->message);
+
+ view = g_object_new (META_TYPE_RENDERER_VIEW,
+ "layout", &view_layout,
+ "framebuffer", framebuffer,
+ "monitor-info", monitor_info,
+ NULL);
+
+ meta_onscreen_native_set_view (onscreen, view);
+
+ return view;
+}
+
+void
+meta_renderer_native_finish_frame (MetaRendererNative *renderer_native)
+{
+ renderer_native->frame_counter++;
+}
+
+int64_t
+meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native)
+{
+ return renderer_native->frame_counter;
+}
+
+static void
meta_renderer_native_get_property (GObject *object,
guint prop_id,
GValue *value,
@@ -879,6 +1188,7 @@ meta_renderer_native_class_init (MetaRendererNativeClass *klass)
object_class->finalize = meta_renderer_native_finalize;
renderer_class->create_cogl_renderer = meta_renderer_native_create_cogl_renderer;
+ renderer_class->create_view = meta_renderer_native_create_view;
g_object_class_install_property (object_class,
PROP_KMS_FD,
diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h
index f7ef7bc..37ea9e3 100644
--- a/src/backends/native/meta-renderer-native.h
+++ b/src/backends/native/meta-renderer-native.h
@@ -44,13 +44,20 @@ int meta_renderer_native_get_kms_fd (MetaRendererNative *renderer_native);
void meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native);
-gboolean meta_renderer_native_set_layout (MetaRendererNative *renderer_native,
- int width,
- int height,
- GError **error);
+gboolean meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native,
+ MetaRendererView *view,
+ int width,
+ int height,
+ GError **error);
void meta_renderer_native_set_ignore_crtc (MetaRendererNative *renderer_native,
uint32_t id,
gboolean ignore);
+MetaRendererView * meta_renderer_native_create_legacy_view (MetaRendererNative *renderer_native);
+
+void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native);
+
+int64_t meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native);
+
#endif /* META_RENDERER_NATIVE_H */
diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c
index 624c514..c0b6d24 100644
--- a/src/backends/native/meta-stage-native.c
+++ b/src/backends/native/meta-stage-native.c
@@ -27,16 +27,22 @@
#include "backends/native/meta-stage-native.h"
#include "backends/meta-backend-private.h"
+#include "backends/native/meta-renderer-native.h"
#include "meta/meta-backend.h"
#include "meta/meta-monitor-manager.h"
#include "meta/util.h"
+static GQuark quark_view_frame_closure = 0;
+
struct _MetaStageNative
{
ClutterStageCogl parent;
CoglOnscreen *pending_onscreen;
CoglClosure *frame_closure;
+
+ int64_t presented_frame_counter_sync;
+ int64_t presented_frame_counter_complete;
};
static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
@@ -63,41 +69,123 @@ get_legacy_view (MetaRenderer *renderer)
return NULL;
}
-static CoglOnscreen *
-get_legacy_onscreen (MetaStageNative *stage_native)
+static void
+frame_cb (CoglOnscreen *onscreen,
+ CoglFrameEvent frame_event,
+ CoglFrameInfo *frame_info,
+ void *user_data)
+
{
- if (stage_native->pending_onscreen)
+ MetaStageNative *stage_native = user_data;
+ ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_native);
+ int64_t global_frame_counter;
+ int64_t presented_frame_counter;
+ ClutterFrameInfo clutter_frame_info;
+
+ global_frame_counter = cogl_frame_info_get_global_frame_counter (frame_info);
+
+ switch (frame_event)
{
- return stage_native->pending_onscreen;
+ case COGL_FRAME_EVENT_SYNC:
+ presented_frame_counter = stage_native->presented_frame_counter_sync;
+ stage_native->presented_frame_counter_sync = global_frame_counter;
+ break;
+ case COGL_FRAME_EVENT_COMPLETE:
+ presented_frame_counter = stage_native->presented_frame_counter_complete;
+ stage_native->presented_frame_counter_complete = global_frame_counter;
+ break;
+ default:
+ g_assert_not_reached ();
}
- 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);
+ if (global_frame_counter <= presented_frame_counter)
+ return;
+
+ clutter_frame_info = (ClutterFrameInfo) {
+ .frame_counter = global_frame_counter,
+ .refresh_rate = cogl_frame_info_get_refresh_rate (frame_info),
+ .presentation_time = cogl_frame_info_get_presentation_time (frame_info)
+ };
+
+ _clutter_stage_cogl_presented (stage_cogl, frame_event, &clutter_frame_info);
+}
+
+static void
+ensure_frame_callback (MetaStageNative *stage_native,
+ ClutterStageView *stage_view)
+{
+ CoglFramebuffer *framebuffer;
+ CoglOnscreen *onscreen;
+ CoglClosure *closure;
+
+ closure = g_object_get_qdata (G_OBJECT (stage_view),
+ quark_view_frame_closure);
+ if (closure)
+ return;
+
+ framebuffer = clutter_stage_view_get_framebuffer (stage_view);
+ onscreen = COGL_ONSCREEN (framebuffer);
+ closure = cogl_onscreen_add_frame_callback (onscreen,
+ frame_cb,
+ stage_native,
+ NULL);
+ g_object_set_qdata (G_OBJECT (stage_view),
+ quark_view_frame_closure,
+ closure);
+}
+
+static void
+ensure_frame_callbacks (MetaStageNative *stage_native)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ GList *l;
+
+ for (l = meta_renderer_get_views (renderer); l; l = l->next)
+ {
+ ClutterStageView *stage_view = l->data;
- return COGL_ONSCREEN (framebuffer);
+ ensure_frame_callback (stage_native, stage_view);
}
}
void
+meta_stage_native_rebuild_views (MetaStageNative *stage_native)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+
+ meta_renderer_rebuild_views (renderer);
+ ensure_frame_callbacks (stage_native);
+}
+
+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);
+ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
MetaRendererView *legacy_view;
+ GError *error = NULL;
cairo_rectangle_int_t view_layout;
legacy_view = get_legacy_view (renderer);
if (!legacy_view)
return;
+ if (!meta_renderer_native_set_legacy_view_size (renderer_native,
+ legacy_view,
+ width, height,
+ &error))
+ {
+ meta_warning ("Applying display configuration failed: %s\n",
+ error->message);
+ g_error_free (error);
+ return;
+ }
+
view_layout = (cairo_rectangle_int_t) {
.width = width,
.height = height
@@ -107,29 +195,6 @@ meta_stage_native_legacy_set_size (MetaStageNative *stage_native,
NULL);
}
-static gboolean
-meta_stage_native_realize (ClutterStageWindow *stage_window)
-{
- MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
- MetaBackend *backend = meta_get_backend ();
- ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
- CoglFramebuffer *framebuffer;
- GError *error = NULL;
-
- stage_native->pending_onscreen =
- cogl_onscreen_new (clutter_backend->cogl_context, 1, 1);
-
- framebuffer = COGL_FRAMEBUFFER (stage_native->pending_onscreen);
- if (!cogl_framebuffer_allocate (framebuffer, &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)
{
@@ -137,16 +202,6 @@ meta_stage_native_unrealize (ClutterStageWindow *stage_window)
clutter_stage_window_parent_iface->unrealize (stage_window);
- if (stage_native->frame_closure)
- {
- CoglOnscreen *onscreen;
-
- onscreen = get_legacy_onscreen (stage_native);
- cogl_onscreen_remove_frame_callback (onscreen,
- stage_native->frame_closure);
- stage_native->frame_closure = NULL;
- }
-
g_clear_pointer (&stage_native->pending_onscreen, cogl_object_unref);
}
@@ -161,14 +216,18 @@ meta_stage_native_get_geometry (ClutterStageWindow *stage_window,
cairo_rectangle_int_t *geometry)
{
MetaBackend *backend = meta_get_backend ();
- MetaRenderer *renderer = meta_backend_get_renderer (backend);
- MetaRendererView *legacy_view;
+ MetaMonitorManager *monitor_manager =
+ meta_backend_get_monitor_manager (backend);
- legacy_view = get_legacy_view (renderer);
- if (legacy_view)
+ if (monitor_manager)
{
- clutter_stage_view_get_layout (CLUTTER_STAGE_VIEW (legacy_view),
- geometry);
+ int width, height;
+
+ meta_monitor_manager_get_screen_size (monitor_manager, &width, &height);
+ *geometry = (cairo_rectangle_int_t) {
+ .width = width,
+ .height = height,
+ };
}
else
{
@@ -180,61 +239,25 @@ meta_stage_native_get_geometry (ClutterStageWindow *stage_window,
}
static void
-frame_cb (CoglOnscreen *onscreen,
- CoglFrameEvent frame_event,
- CoglFrameInfo *frame_info,
- void *user_data)
-{
- MetaStageNative *stage_native = user_data;
- ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_native);
- ClutterFrameInfo clutter_frame_info = {
- .frame_counter = cogl_frame_info_get_frame_counter (frame_info),
- .refresh_rate = cogl_frame_info_get_refresh_rate (frame_info),
- .presentation_time = cogl_frame_info_get_presentation_time (frame_info)
- };
-
- _clutter_stage_cogl_presented (stage_cogl, frame_event, &clutter_frame_info);
-}
-
-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);
+ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
MetaRendererView *legacy_view;
- cairo_rectangle_int_t view_layout = { 0 };
- CoglFramebuffer *framebuffer;
- CoglOnscreen *onscreen;
legacy_view = get_legacy_view (renderer);
if (legacy_view)
return;
- if (!monitor_manager)
+ legacy_view = meta_renderer_native_create_legacy_view (renderer_native);
+ if (!legacy_view)
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);
- onscreen = COGL_ONSCREEN (framebuffer);
- cogl_onscreen_set_swap_throttled (onscreen,
- _clutter_get_sync_to_vblank ());
-
- stage_native->frame_closure =
- cogl_onscreen_add_frame_callback (onscreen,
- frame_cb,
- stage_native,
- NULL);
+ ensure_frame_callback (stage_native, CLUTTER_STAGE_VIEW (legacy_view));
}
static GList *
@@ -243,29 +266,43 @@ 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);
+ if (!meta_is_stage_views_enabled ())
+ ensure_legacy_view (stage_window);
+
return meta_renderer_get_views (renderer);
}
static int64_t
meta_stage_native_get_frame_counter (ClutterStageWindow *stage_window)
{
- MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
- CoglOnscreen *legacy_onscreen;
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
+ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
- legacy_onscreen = get_legacy_onscreen (stage_native);
+ return meta_renderer_native_get_frame_counter (renderer_native);
+}
+
+static void
+meta_stage_native_finish_frame (ClutterStageWindow *stage_window)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaRenderer *renderer = meta_backend_get_renderer (backend);
- return cogl_onscreen_get_frame_counter (legacy_onscreen);
+ meta_renderer_native_finish_frame (META_RENDERER_NATIVE (renderer));
}
static void
meta_stage_native_init (MetaStageNative *stage_native)
{
+ stage_native->presented_frame_counter_sync = -1;
+ stage_native->presented_frame_counter_complete = -1;
}
static void
meta_stage_native_class_init (MetaStageNativeClass *klass)
{
+ quark_view_frame_closure =
+ g_quark_from_static_string ("-meta-native-stage-view-frame-closure");
}
static void
@@ -273,10 +310,10 @@ 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_views = meta_stage_native_get_views;
iface->get_frame_counter = meta_stage_native_get_frame_counter;
+ iface->finish_frame = meta_stage_native_finish_frame;
}
diff --git a/src/backends/native/meta-stage-native.h b/src/backends/native/meta-stage-native.h
index d0b87e0..d088609 100644
--- a/src/backends/native/meta-stage-native.h
+++ b/src/backends/native/meta-stage-native.h
@@ -31,6 +31,8 @@
G_DECLARE_FINAL_TYPE (MetaStageNative, meta_stage_native,
META, STAGE_NATIVE, ClutterStageCogl)
+void meta_stage_native_rebuild_views (MetaStageNative *stage_native);
+
void meta_stage_native_legacy_set_size (MetaStageNative *stage_native,
int width,
int height);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]