diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h index 5c65ff969..d727ba28e 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 1889fdb94..2fbedcb5f 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 6c9b2b299..6c90c1689 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 0f08760bd..9c43fbb4f 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 5edfd79d8..385122c32 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 791d09bbd..04d96aa03 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -76,14 +76,6 @@ typedef struct { uint32_t rotation_map[ALL_TRANSFORMS]; } MetaCRTCKms; -typedef struct -{ - int pending; - - MetaKmsFlipCallback callback; - void *user_data; -} MetaKmsFlipClosure; - typedef struct { GSource source; @@ -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 (n_connectors == 0) - continue; - - fb_in_use = TRUE; - - if (manager_kms->page_flips_not_supported) - continue; - - if (!flip_closure) + if (output->crtc == crtc) { - flip_closure = g_new0 (MetaKmsFlipClosure, 1); - *flip_closure = (MetaKmsFlipClosure) { - .pending = 0, - .callback = flip_callback, - .user_data = user_data - }; + connected_crtc_found = TRUE; + break; } + } + if (!connected_crtc_found) + return FALSE; + + return TRUE; +} + +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; + + 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); - return fb_in_use; + if (ret != 0) + return FALSE; + + g_closure_ref (flip_closure); + + 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 3f6251d9b..3386b932e 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); +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_flip_all_crtcs (MetaMonitorManagerKms *manager_kms, - uint32_t fb_id, - MetaKmsFlipCallback flip_callback, - void *user_data); +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 b4a7aa3e7..e8d74514a 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -47,9 +47,11 @@ #include #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 (!meta_renderer_native_create_surface (renderer_native, + width, height, + &onscreen_native->surface, + &egl_onscreen->egl_surface, + error)) + return FALSE; - if (!onscreen_native->surface) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_ONSCREEN, - "Failed to allocate surface"); - 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 (!meta_renderer_native_create_surface (renderer_native, + width, height, + &new_surface, + &new_egl_surface, + error)) + return FALSE; - if (!new_surface) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_ONSCREEN, - "Failed to allocate new surface"); - 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; } @@ -773,6 +980,108 @@ meta_renderer_native_create_cogl_renderer (MetaRenderer *renderer) return cogl_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, @@ -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 f7ef7bc40..37ea9e35b 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 624c5142c..c0b6d2449 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,25 +69,94 @@ 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) - { - return stage_native->pending_onscreen; - } - else - { - MetaBackend *backend = meta_get_backend (); - MetaRenderer *renderer = meta_backend_get_renderer (backend); - ClutterStageView *stage_view; - CoglFramebuffer *framebuffer; + 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; - stage_view = CLUTTER_STAGE_VIEW (get_legacy_view (renderer)); - framebuffer = clutter_stage_view_get_framebuffer (stage_view); + global_frame_counter = cogl_frame_info_get_global_frame_counter (frame_info); - return COGL_ONSCREEN (framebuffer); + switch (frame_event) + { + 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 (); } + + 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; + + 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 @@ -91,13 +166,26 @@ meta_stage_native_legacy_set_size (MetaStageNative *stage_native, { 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 { @@ -179,62 +238,26 @@ 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); +} - return cogl_onscreen_get_frame_counter (legacy_onscreen); +static void +meta_stage_native_finish_frame (ClutterStageWindow *stage_window) +{ + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + + 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 d0b87e0e9..d0886095e 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);