From 3606227c07773c819d99fa8c135215a4a175d5f0 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 11 May 2015 16:53:41 -0400 Subject: [PATCH] Force cursor update after applying configuration The qxl kms driver has a bug where the cursor gets hidden implicitly after a drmModeSetCrtc call. This commit works around the bug by forcing a drmModeSetCursor2 call after the drmModeSetCrtc calls. This is pretty hacky and won't ever go upstream. https://bugzilla.gnome.org/show_bug.cgi?id=746078 --- src/backends/native/meta-launcher.c | 37 +++++++++++++++++++++++++ src/backends/native/meta-monitor-manager-kms.c | 38 ++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c index d7da9e8..013f40e 100644 --- a/src/backends/native/meta-launcher.c +++ b/src/backends/native/meta-launcher.c @@ -83,85 +83,122 @@ get_session_proxy (GCancellable *cancellable) session_proxy = login1_session_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, "org.freedesktop.login1", proxy_path, cancellable, &error); if (!session_proxy) report_error_and_die ("Failed getting session proxy", error); free (proxy_path); return session_proxy; } static Login1Seat * get_seat_proxy (GCancellable *cancellable) { GError *error = NULL; Login1Seat *seat = login1_seat_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, "org.freedesktop.login1", "/org/freedesktop/login1/seat/self", cancellable, &error); if (!seat) report_error_and_die ("Could not get seat proxy", error); return seat; } static void +frame_callback (CoglOnscreen *onscreen, + CoglFrameEvent event, + CoglFrameInfo *frame_info, + void *user_data) +{ + CoglFrameClosure **frame_closure = user_data; + + MetaBackend *backend = meta_get_backend (); + MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (backend); + CoglOnscreen *cogl_onscreen; + + if (event != COGL_FRAME_EVENT_COMPLETE) + return; + + meta_cursor_renderer_native_force_update (META_CURSOR_RENDERER_NATIVE (renderer)); + + cogl_onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer ()); + cogl_onscreen_remove_frame_callback (cogl_onscreen, + *frame_closure); + + *frame_closure = NULL; +} + +static void session_unpause (void) { ClutterBackend *clutter_backend; CoglContext *cogl_context; CoglDisplay *cogl_display; clutter_backend = clutter_get_default_backend (); cogl_context = clutter_backend_get_cogl_context (clutter_backend); cogl_display = cogl_context_get_display (cogl_context); cogl_kms_display_queue_modes_reset (cogl_display); clutter_evdev_reclaim_devices (); clutter_egl_thaw_master_clock (); { MetaBackend *backend = meta_get_backend (); MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (backend); ClutterActor *stage = meta_backend_get_stage (backend); + CoglOnscreen *cogl_onscreen; + static CoglFrameClosure *frame_closure = NULL; /* When we mode-switch back, we need to immediately queue a redraw * in case nothing else queued one for us, and force the cursor to * update. */ clutter_actor_queue_redraw (stage); meta_cursor_renderer_native_force_update (META_CURSOR_RENDERER_NATIVE (renderer)); + + cogl_onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer ()); + + if (frame_closure) + cogl_onscreen_remove_frame_callback (cogl_onscreen, frame_closure); + + frame_closure = cogl_onscreen_add_frame_callback (cogl_onscreen, + frame_callback, + &frame_closure, + NULL); + meta_idle_monitor_native_reset_idletime (meta_idle_monitor_get_core ()); } } static void session_pause (void) { clutter_evdev_release_devices (); clutter_egl_freeze_master_clock (); } static gboolean take_device (Login1Session *session_proxy, int dev_major, int dev_minor, int *out_fd, GCancellable *cancellable, GError **error) { g_autoptr (GVariant) fd_variant = NULL; g_autoptr (GUnixFDList) fd_list = NULL; int fd = -1; if (!login1_session_call_take_device_sync (session_proxy, dev_major, dev_minor, NULL, &fd_variant, NULL, /* paused */ &fd_list, diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c index cc2b18e..b56d6d3 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -1,109 +1,114 @@ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Author: Giovanni Campagna */ #include "config.h" #include "meta-monitor-manager-kms.h" #include "meta-monitor-config.h" +#include "backends/meta-backend-private.h" +#include "meta-cursor-renderer-native.h" #include #include #include #include #include #include #include #include #include #include #include #include typedef struct { drmModeConnector *connector; unsigned n_encoders; drmModeEncoderPtr *encoders; drmModeEncoderPtr current_encoder; /* bitmasks of encoder position in the resources array */ uint32_t encoder_mask; uint32_t enc_clone_mask; uint32_t dpms_prop_id; uint32_t edid_blob_id; uint32_t tile_blob_id; int suggested_x; int suggested_y; uint32_t hotplug_mode_update; } MetaOutputKms; typedef struct { uint32_t underscan_prop_id; uint32_t underscan_hborder_prop_id; uint32_t underscan_vborder_prop_id; } MetaCRTCKms; struct _MetaMonitorManagerKms { MetaMonitorManager parent_instance; int fd; drmModeConnector **connectors; unsigned int n_connectors; + /* used to find out when configuration has been applied */ + CoglFrameClosure *frame_closure; + GUdevClient *udev; GSettings *desktop_settings; }; struct _MetaMonitorManagerKmsClass { MetaMonitorManagerClass parent_class; }; G_DEFINE_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms, META_TYPE_MONITOR_MANAGER); static void free_resources (MetaMonitorManagerKms *manager_kms) { unsigned i; for (i = 0; i < manager_kms->n_connectors; i++) drmModeFreeConnector (manager_kms->connectors[i]); g_free (manager_kms->connectors); } static int compare_outputs (const void *one, const void *two) { const MetaOutput *o_one = one, *o_two = two; return strcmp (o_one->name, o_two->name); @@ -879,70 +884,94 @@ set_underscan (MetaMonitorManagerKms *manager_kms, { drmModeObjectSetProperty (manager_kms->fd, crtc->crtc_id, DRM_MODE_OBJECT_CRTC, crtc_kms->underscan_prop_id, (uint64_t) 1); if (crtc_kms->underscan_hborder_prop_id) { uint64_t value = crtc->current_mode->width * 0.05; drmModeObjectSetProperty (manager_kms->fd, crtc->crtc_id, DRM_MODE_OBJECT_CRTC, crtc_kms->underscan_hborder_prop_id, value); } if (crtc_kms->underscan_vborder_prop_id) { uint64_t value = crtc->current_mode->height * 0.05; drmModeObjectSetProperty (manager_kms->fd, crtc->crtc_id, DRM_MODE_OBJECT_CRTC, crtc_kms->underscan_vborder_prop_id, value); } } else { drmModeObjectSetProperty (manager_kms->fd, crtc->crtc_id, DRM_MODE_OBJECT_CRTC, crtc_kms->underscan_prop_id, (uint64_t) 0); } } static void +frame_callback (CoglOnscreen *onscreen, + CoglFrameEvent event, + CoglFrameInfo *frame_info, + void *user_data) +{ + MetaMonitorManagerKms *manager_kms = user_data; + MetaBackend *backend = meta_get_backend (); + MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (backend); + CoglOnscreen *cogl_onscreen; + + if (event != COGL_FRAME_EVENT_COMPLETE) + return; + + meta_cursor_renderer_native_force_update (META_CURSOR_RENDERER_NATIVE (renderer)); + + cogl_onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer ()); + cogl_onscreen_remove_frame_callback (cogl_onscreen, + manager_kms->frame_closure); + + manager_kms->frame_closure = NULL; +} + +static void meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, MetaCRTCInfo **crtcs, unsigned int n_crtcs, MetaOutputInfo **outputs, unsigned int n_outputs) { MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); ClutterBackend *backend; CoglContext *cogl_context; CoglDisplay *cogl_display; + CoglOnscreen *cogl_onscreen; 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; 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; cogl_crtc->x = 0; cogl_crtc->y = 0; cogl_crtc->count = 0; memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo)); cogl_crtc->connectors = NULL; cogl_crtc->count = 0; crtc->rect.x = 0; @@ -1024,60 +1053,69 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, cogl_crtc->x = 0; cogl_crtc->y = 0; cogl_crtc->count = 0; memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo)); cogl_crtc->connectors = NULL; cogl_crtc->count = 0; crtc->rect.x = 0; crtc->rect.y = 0; crtc->rect.width = 0; crtc->rect.height = 0; crtc->current_mode = NULL; } backend = clutter_get_default_backend (); cogl_context = clutter_backend_get_cogl_context (backend); cogl_display = cogl_context_get_display (cogl_context); error = NULL; ok = cogl_kms_display_set_layout (cogl_display, 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); g_error_free (error); return; } + cogl_onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer ()); + if (manager_kms->frame_closure) + cogl_onscreen_remove_frame_callback (cogl_onscreen, + manager_kms->frame_closure); + manager_kms->frame_closure = cogl_onscreen_add_frame_callback (cogl_onscreen, + frame_callback, + manager, + NULL); + for (i = 0; i < n_outputs; i++) { MetaOutputInfo *output_info = outputs[i]; MetaOutput *output = output_info->output; output->is_primary = output_info->is_primary; output->is_presentation = output_info->is_presentation; output->is_underscanning = output_info->is_underscanning; set_underscan (manager_kms, output); } /* Disable outputs not mentioned in the list */ for (i = 0; i < manager->n_outputs; i++) { MetaOutput *output = &manager->outputs[i]; if (output->is_dirty) { output->is_dirty = FALSE; continue; } output->crtc = NULL; output->is_primary = FALSE; } manager->screen_width = screen_width; manager->screen_height = screen_height; -- 2.5.0