diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c index bb3d1c380..791d09bbd 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -75,11 +76,28 @@ typedef struct { uint32_t rotation_map[ALL_TRANSFORMS]; } MetaCRTCKms; +typedef struct +{ + int pending; + + MetaKmsFlipCallback callback; + void *user_data; +} MetaKmsFlipClosure; + +typedef struct +{ + GSource source; + + gpointer fd_tag; + MetaMonitorManagerKms *manager_kms; +} MetaKmsSource; + struct _MetaMonitorManagerKms { MetaMonitorManager parent_instance; int fd; + MetaKmsSource *source; drmModeConnector **connectors; unsigned int n_connectors; @@ -87,6 +105,8 @@ struct _MetaMonitorManagerKms GUdevClient *udev; GSettings *desktop_settings; + + gboolean page_flips_not_supported; }; struct _MetaMonitorManagerKmsClass @@ -954,8 +974,6 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, MetaPowerSave mode) { MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); - MetaBackend *backend; - MetaRenderer *renderer; uint64_t state; unsigned i; @@ -995,20 +1013,6 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, meta_output->name, strerror (errno)); } } - - backend = meta_get_backend (); - renderer = meta_backend_get_renderer (backend); - - for (i = 0; i < manager->n_crtcs; i++) - meta_renderer_native_set_ignore_crtc (META_RENDERER_NATIVE (renderer), - manager->crtcs[i].crtc_id, - mode != META_POWER_SAVE_ON); -} - -static void -crtc_free (CoglKmsCrtc *crtc) -{ - g_slice_free (CoglKmsCrtc, crtc); } static void @@ -1064,29 +1068,21 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, MetaBackend *backend; MetaRenderer *renderer; unsigned i; - GPtrArray *cogl_crtcs; int screen_width, screen_height; gboolean ok; GError *error; - cogl_crtcs = g_ptr_array_new_full (manager->n_crtcs, (GDestroyNotify)crtc_free); screen_width = 0; screen_height = 0; for (i = 0; i < n_crtcs; i++) { MetaCRTCInfo *crtc_info = crtcs[i]; MetaCRTC *crtc = crtc_info->crtc; MetaCRTCKms *crtc_kms = crtc->driver_private; - CoglKmsCrtc *cogl_crtc; crtc->is_dirty = TRUE; - cogl_crtc = g_slice_new0 (CoglKmsCrtc); - g_ptr_array_add (cogl_crtcs, cogl_crtc); - if (crtc_info->mode == NULL) { - cogl_crtc->id = crtc->crtc_id; - crtc->rect.x = 0; crtc->rect.y = 0; crtc->rect.width = 0; @@ -1096,24 +1092,15 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, else { MetaMonitorMode *mode; - uint32_t *connectors; - unsigned int j, n_connectors; + unsigned int j; int width, height; mode = crtc_info->mode; - n_connectors = crtc_info->outputs->len; - connectors = g_new (uint32_t, n_connectors); - - cogl_crtc->id = crtc->crtc_id; - cogl_crtc->connected = n_connectors > 0; - - for (j = 0; j < n_connectors; j++) + for (j = 0; j < crtc_info->outputs->len; j++) { MetaOutput *output = g_ptr_array_index (crtc_info->outputs, j); - connectors[j] = output->winsys_id; - output->is_dirty = TRUE; output->crtc = crtc; } @@ -1153,7 +1140,6 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, for (i = 0; i < manager->n_crtcs; i++) { MetaCRTC *crtc = &manager->crtcs[i]; - CoglKmsCrtc *cogl_crtc; crtc->logical_monitor = NULL; @@ -1163,11 +1149,6 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, continue; } - cogl_crtc = g_slice_new0 (CoglKmsCrtc); - g_ptr_array_add (cogl_crtcs, cogl_crtc); - - cogl_crtc->id = crtc->crtc_id; - crtc->rect.x = 0; crtc->rect.y = 0; crtc->rect.width = 0; @@ -1181,11 +1162,7 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, error = NULL; ok = meta_renderer_native_set_layout (META_RENDERER_NATIVE (renderer), screen_width, screen_height, - (CoglKmsCrtc**)cogl_crtcs->pdata, - cogl_crtcs->len, &error); - g_ptr_array_unref (cogl_crtcs); - if (!ok) { meta_warning ("Applying display configuration failed: %s\n", error->message); @@ -1279,12 +1256,39 @@ on_uevent (GUdevClient *client, meta_monitor_manager_on_hotplug (manager); } +static gboolean +kms_event_check (GSource *source) +{ + MetaKmsSource *kms_source = (MetaKmsSource *) source; + + return g_source_query_unix_fd (source, kms_source->fd_tag) & G_IO_IN; +} + +static gboolean +kms_event_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + MetaKmsSource *kms_source = (MetaKmsSource *) source; + + meta_monitor_manager_kms_wait_for_flip (kms_source->manager_kms); + + return G_SOURCE_CONTINUE; +} + +static GSourceFuncs kms_event_funcs = { + NULL, + kms_event_check, + kms_event_dispatch +}; + static void meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms) { MetaBackend *backend = meta_get_backend (); MetaRenderer *renderer = meta_backend_get_renderer (backend); MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); + GSource *source; manager_kms->fd = meta_renderer_native_get_kms_fd (renderer_native); @@ -1295,6 +1299,14 @@ meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms) g_signal_connect (manager_kms->udev, "uevent", G_CALLBACK (on_uevent), manager_kms); + source = g_source_new (&kms_event_funcs, sizeof (MetaKmsSource)); + manager_kms->source = (MetaKmsSource *) source; + manager_kms->source->fd_tag = g_source_add_unix_fd (source, + manager_kms->fd, + G_IO_IN | G_IO_ERR); + manager_kms->source->manager_kms = manager_kms; + g_source_attach (source, NULL); + manager_kms->desktop_settings = g_settings_new ("org.gnome.desktop.interface"); } @@ -1364,6 +1376,104 @@ meta_monitor_manager_kms_apply_crtc_modes (MetaMonitorManagerKms *manager_kms, } } +gboolean +meta_monitor_manager_kms_flip_all_crtcs (MetaMonitorManagerKms *manager_kms, + uint32_t fb_id, + MetaKmsFlipCallback flip_callback, + void *user_data) +{ + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms); + MetaKmsFlipClosure *flip_closure = NULL; + unsigned int i; + gboolean fb_in_use = FALSE; + + if (manager->power_save_mode != META_POWER_SAVE_ON) + return FALSE; + + for (i = 0; i < manager->n_crtcs; i++) + { + MetaCRTC *crtc = &manager->crtcs[i]; + uint32_t *connectors; + unsigned int n_connectors; + int ret; + + 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) + { + flip_closure = g_new0 (MetaKmsFlipClosure, 1); + *flip_closure = (MetaKmsFlipClosure) { + .pending = 0, + .callback = flip_callback, + .user_data = user_data + }; + } + + ret = drmModePageFlip (manager_kms->fd, + crtc->crtc_id, + fb_id, + DRM_MODE_PAGE_FLIP_EVENT, + flip_closure); + if (ret != 0 && ret != -EACCES) + { + 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); + } + + return fb_in_use; +} + +static void +page_flip_handler (int fd, + unsigned int frame, + unsigned int sec, + unsigned int usec, + void *data) +{ + MetaKmsFlipClosure *flip_closure = data; + + flip_closure->pending--; + if (flip_closure->pending == 0) + flip_closure->callback (flip_closure->user_data); +} + +void +meta_monitor_manager_kms_wait_for_flip (MetaMonitorManagerKms *manager_kms) +{ + drmEventContext evctx; + + if (manager_kms->page_flips_not_supported) + return; + + memset (&evctx, 0, sizeof evctx); + evctx.version = DRM_EVENT_CONTEXT_VERSION; + evctx.page_flip_handler = page_flip_handler; + drmHandleEvent (manager_kms->fd, &evctx); +} + static void meta_monitor_manager_kms_dispose (GObject *object) { @@ -1381,6 +1491,7 @@ meta_monitor_manager_kms_finalize (GObject *object) MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object); free_resources (manager_kms); + g_source_destroy ((GSource *) manager_kms->source); G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->finalize (object); } diff --git a/src/backends/native/meta-monitor-manager-kms.h b/src/backends/native/meta-monitor-manager-kms.h index a9c0c9543..3f6251d9b 100644 --- a/src/backends/native/meta-monitor-manager-kms.h +++ b/src/backends/native/meta-monitor-manager-kms.h @@ -37,7 +37,16 @@ typedef struct _MetaMonitorManagerKms MetaMonitorManagerKms; 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_wait_for_flip (MetaMonitorManagerKms *manager_kms); + #endif /* META_MONITOR_MANAGER_KMS_H */ diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 4404a42fb..b75b7d68c 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -67,9 +67,6 @@ struct _MetaRendererNative int kms_fd; struct gbm_device *gbm; CoglClosure *swap_notify_idle; - gboolean page_flips_not_supported; - - GList *crtcs; int width, height; gboolean pending_set_crtc; @@ -90,12 +87,6 @@ G_DEFINE_TYPE_WITH_CODE (MetaRendererNative, static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable; static const CoglWinsysVtable *parent_vtable; -typedef struct _CoglFlipKMS -{ - CoglOnscreen *onscreen; - int pending; -} CoglFlipKMS; - typedef struct _CoglOnscreenKMS { struct gbm_surface *surface; @@ -211,73 +202,6 @@ queue_swap_notify_for_onscreen (CoglOnscreen *onscreen) kms_onscreen->pending_swap_notify = TRUE; } -static void -process_flip (CoglFlipKMS *flip) -{ - /* We're only ready to dispatch a swap notification once all outputs - * have flipped... */ - flip->pending--; - if (flip->pending == 0) - { - CoglOnscreen *onscreen = flip->onscreen; - CoglOnscreenEGL *egl_onscreen = onscreen->winsys; - CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; - - queue_swap_notify_for_onscreen (onscreen); - - free_current_bo (onscreen); - - kms_onscreen->current_fb_id = kms_onscreen->next_fb_id; - kms_onscreen->next_fb_id = 0; - - kms_onscreen->current_bo = kms_onscreen->next_bo; - kms_onscreen->next_bo = NULL; - - cogl_object_unref (flip->onscreen); - - g_slice_free (CoglFlipKMS, flip); - } -} - -static void -page_flip_handler (int fd, - unsigned int frame, - unsigned int sec, - unsigned int usec, - void *data) -{ - CoglFlipKMS *flip = data; - - process_flip (flip); -} - -static void -handle_drm_event (MetaRendererNative *renderer_native) -{ - drmEventContext evctx; - - if (renderer_native->page_flips_not_supported) - return; - - memset (&evctx, 0, sizeof evctx); - evctx.version = DRM_EVENT_CONTEXT_VERSION; - evctx.page_flip_handler = page_flip_handler; - drmHandleEvent (renderer_native->kms_fd, &evctx); -} - -static void -dispatch_kms_events (void *user_data, int revents) -{ - CoglRenderer *renderer = user_data; - CoglRendererEGL *egl_renderer = renderer->winsys; - MetaRendererNative *renderer_native = egl_renderer->platform; - - if (!revents) - return; - - handle_drm_event (renderer_native); -} - static CoglBool _cogl_winsys_renderer_connect (CoglRenderer *cogl_renderer, CoglError **error) @@ -315,13 +239,6 @@ _cogl_winsys_renderer_connect (CoglRenderer *cogl_renderer, if (!_cogl_winsys_egl_renderer_connect_common (cogl_renderer, error)) goto fail; - _cogl_poll_renderer_add_fd (cogl_renderer, - renderer_native->kms_fd, - COGL_POLL_FD_EVENT_IN, - NULL, /* no prepare callback */ - dispatch_kms_events, - cogl_renderer); - return TRUE; fail: @@ -342,63 +259,6 @@ setup_crtc_modes (CoglDisplay *display, int fb_id) meta_monitor_manager_kms_apply_crtc_modes (monitor_manager_kms, fb_id); } -static void -flip_all_crtcs (CoglDisplay *display, CoglFlipKMS *flip, int fb_id) -{ - CoglDisplayEGL *egl_display = display->winsys; - MetaRendererNative *renderer_native = egl_display->platform; - GList *l; - gboolean needs_flip = FALSE; - - for (l = renderer_native->crtcs; l; l = l->next) - { - CoglKmsCrtc *crtc = l->data; - int ret = 0; - - if (!crtc->connected || crtc->ignore) - continue; - - needs_flip = TRUE; - - if (!renderer_native->page_flips_not_supported) - { - ret = drmModePageFlip (renderer_native->kms_fd, - crtc->id, fb_id, - DRM_MODE_PAGE_FLIP_EVENT, flip); - if (ret != 0 && ret != -EACCES) - { - g_warning ("Failed to flip: %m"); - renderer_native->page_flips_not_supported = TRUE; - break; - } - } - - if (ret == 0) - flip->pending++; - } - - if (renderer_native->page_flips_not_supported && needs_flip) - flip->pending = 1; -} - -static void -crtc_free (CoglKmsCrtc *crtc) -{ - g_slice_free (CoglKmsCrtc, crtc); -} - -static CoglKmsCrtc * -crtc_copy (CoglKmsCrtc *from) -{ - CoglKmsCrtc *new; - - new = g_slice_new (CoglKmsCrtc); - - *new = *from; - - return new; -} - static CoglBool _cogl_winsys_egl_display_setup (CoglDisplay *display, CoglError **error) @@ -490,11 +350,36 @@ _cogl_winsys_egl_cleanup_context (CoglDisplay *display) } } +static void +flip_callback (void *user_data) +{ + CoglOnscreen *onscreen = user_data; + CoglOnscreenEGL *egl_onscreen = onscreen->winsys; + CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; + + queue_swap_notify_for_onscreen (onscreen); + + free_current_bo (onscreen); + + kms_onscreen->current_fb_id = kms_onscreen->next_fb_id; + kms_onscreen->next_fb_id = 0; + + kms_onscreen->current_bo = kms_onscreen->next_bo; + kms_onscreen->next_bo = NULL; + + cogl_object_unref (onscreen); +} + static void _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, const int *rectangles, int n_rectangles) { + MetaBackend *backend = meta_get_backend (); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaMonitorManagerKms *monitor_manager_kms = + META_MONITOR_MANAGER_KMS (monitor_manager); CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglRenderer *renderer = context->display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; @@ -502,11 +387,12 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, CoglOnscreenEGL *egl_onscreen = onscreen->winsys; CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform; uint32_t handle, stride; - CoglFlipKMS *flip; + gboolean fb_in_use; + uint32_t next_fb_id; /* If we already have a pending swap then block until it completes */ while (kms_onscreen->next_fb_id != 0) - handle_drm_event (renderer_native); + meta_monitor_manager_kms_wait_for_flip (monitor_manager_kms); if (kms_onscreen->pending_egl_surface) { @@ -564,34 +450,27 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, renderer_native->pending_set_crtc = FALSE; } - flip = g_slice_new0 (CoglFlipKMS); - flip->onscreen = onscreen; + next_fb_id = kms_onscreen->next_fb_id; - flip_all_crtcs (context->display, flip, kms_onscreen->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 (flip->pending == 0) + if (!fb_in_use) { drmModeRmFB (renderer_native->kms_fd, kms_onscreen->next_fb_id); gbm_surface_release_buffer (kms_onscreen->surface, kms_onscreen->next_bo); kms_onscreen->next_bo = NULL; kms_onscreen->next_fb_id = 0; - g_slice_free (CoglFlipKMS, flip); - flip = NULL; queue_swap_notify_for_onscreen (onscreen); - } - else - { - /* Ensure the onscreen remains valid while it has any pending flips... */ - cogl_object_ref (flip->onscreen); - /* Process flip right away if we can't wait for vblank */ - if (renderer_native->page_flips_not_supported) - { - setup_crtc_modes (context->display, kms_onscreen->next_fb_id); - process_flip (flip); - } + g_object_unref (onscreen); } } @@ -764,8 +643,6 @@ gboolean meta_renderer_native_set_layout (MetaRendererNative *renderer_native, int width, int height, - CoglKmsCrtc **crtcs, - int n_crtcs, GError **error) { ClutterBackend *clutter_backend = clutter_get_default_backend (); @@ -774,8 +651,6 @@ meta_renderer_native_set_layout (MetaRendererNative *renderer_native, CoglDisplayEGL *egl_display = cogl_display->winsys; CoglRenderer *renderer = cogl_display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; - GList *crtc_list; - int i; if ((width != renderer_native->width || height != renderer_native->height) && @@ -844,39 +719,11 @@ meta_renderer_native_set_layout (MetaRendererNative *renderer_native, renderer_native->width = width; renderer_native->height = height; - g_list_free_full (renderer_native->crtcs, (GDestroyNotify) crtc_free); - - crtc_list = NULL; - for (i = 0; i < n_crtcs; i++) - { - crtc_list = g_list_prepend (crtc_list, crtc_copy (crtcs[i])); - } - crtc_list = g_list_reverse (crtc_list); - renderer_native->crtcs = crtc_list; - renderer_native->pending_set_crtc = TRUE; return TRUE; } -void -meta_renderer_native_set_ignore_crtc (MetaRendererNative *renderer_native, - uint32_t id, - gboolean ignore) -{ - GList *l; - - for (l = renderer_native->crtcs; l; l = l->next) - { - CoglKmsCrtc *crtc = l->data; - if (crtc->id == id) - { - crtc->ignore = ignore; - break; - } - } -} - static const CoglWinsysVtable * get_native_cogl_winsys_vtable (void) { @@ -966,8 +813,6 @@ meta_renderer_native_finalize (GObject *object) { MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object); - g_list_free_full (renderer_native->crtcs, (GDestroyNotify) crtc_free); - g_clear_pointer (&renderer_native->dummy_gbm_surface, gbm_surface_destroy); g_clear_pointer (&renderer_native->gbm, gbm_device_destroy); diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h index 9e01301f9..f7ef7bc40 100644 --- a/src/backends/native/meta-renderer-native.h +++ b/src/backends/native/meta-renderer-native.h @@ -30,14 +30,6 @@ #include "backends/meta-renderer.h" -typedef struct { - uint32_t id; - - gboolean connected; - - CoglBool ignore; -} CoglKmsCrtc; - #define META_TYPE_RENDERER_NATIVE (meta_renderer_native_get_type ()) G_DECLARE_FINAL_TYPE (MetaRendererNative, meta_renderer_native, META, RENDERER_NATIVE, @@ -55,8 +47,6 @@ void meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native gboolean meta_renderer_native_set_layout (MetaRendererNative *renderer_native, int width, int height, - CoglKmsCrtc **crtcs, - int n_crtcs, GError **error); void meta_renderer_native_set_ignore_crtc (MetaRendererNative *renderer_native,