Commits (14)
  • Georges Basile Stavracas Neto's avatar
    monitor-manager-kms: Use g_autoptr for error · de294f34
    Georges Basile Stavracas Neto authored
    A minor code cleanup.
  • Georges Basile Stavracas Neto's avatar
    monitor-manager-kms: Don't add GPU if it fails · e99b0b93
    Georges Basile Stavracas Neto authored
    This is a small mistake spotted while working on a solution
    for #77. When a GPU fails to initialize, we're adding them
    anyway, which might have pretty bad consequences when trying
    to use these NULL GPUs.
    Issue: #77
  • Georges Basile Stavracas Neto's avatar
    gpu-kms: Return NULL, not FALSE · 14b7e79d
    Georges Basile Stavracas Neto authored
    Another small mistake spotted while working on #77. This
    function returns a pointer, thus we should return NULL,
    not FALSE.
    Issue: #77
  • Georges Basile Stavracas Neto's avatar
    gpu-kms: Ignore GPUs with no connectors · 3832c6b6
    Georges Basile Stavracas Neto authored
    Mutter recently gained the ability to deal with multiple GPUs
    rendering at different displays. These GPUs would have a display
    connected to them, and Mutter was adapted in order to be aware
    of different GPUs and their outputs.
    However, one specific edge case appeared: PRIME systems. PRIME
    systems have two GPUs:
     * The integrated GPU (iGPU), usually Intel, which has connectors
       and deals with the routine load.
     * The dedicated GPU (dGPU), usually AMD or NVidia, which has no
       connectors at all and are there just to aid heavy loads.
    On those systems, the dGPU is aggressively put to sleep by the
    kernel to avoid energy waste. Waking it up is a costly operation.
    With Mutter's adaptation to deal with multiple GPUs, Mutter began
    wakening the dGPU every time some rendering had to be done. This
    was causing stuttering every time the dGPU was put to sleep, and
    Mutter asked it to wake up again.
    To fix this situation, this commit ignores GPUs with no connectors
    Issue: #77
  • Carlos Garnacho's avatar
    cogl: Read pixels as per the stored format · 44a7f74d
    Carlos Garnacho authored
    By the looks of it, commit 95e9fa10 was taping over an Intel DRI bug
    that would make it return post-swizzling pixel data on glReadPixels().
    There's been reports over time of that commit resulting in wrong colors
    on other drivers, and lately Mesa >17.3 started showing the same symptoms
    on Intel.
    But texture swizzling works by changing parameters before fragment shaders
    and reading pixels from an already drawn FBO/texture doesn't involve those.
    This should thus use pixel_format_to_gl_with_target(), which will result in
    correctly requesting the same pixel format than the underlying texture,
    while still considering it BGRA for the upper layers in the swizzling case.
    Closes: #72
  • Rasmus Thomsen's avatar
    mutter: allow building with elogind · b096c0ac
    Rasmus Thomsen authored
    This commit allows building mutter with elogind, which is
    systemd-logind extracted into a standalone package. This
    allows using mutter with its native-backend ( and consequently
    wayland ) enabled on distros which use init systems other than
  • Yussuf Khalil's avatar
    clutter: Avoid unnecessary relayouts in ClutterText · 31779404
    Yussuf Khalil authored
    We can save an unnecessary relayout if the required size to fully draw the text
    is equal to the currently allocated size after the underlying text buffer or
    attributes that only affect the PangoLayout have changed.
  • Georges Basile Stavracas Neto's avatar
    window: Fix a small memory leak · 2da2489d
    Georges Basile Stavracas Neto authored
    (cherry picked from commit 63e2c032)
  • Daniel van Vugt's avatar
    renderer-native: Swap then await earlier flips. · b2f9de98
    Daniel van Vugt authored
    Rendering the next frame (which mostly happens as part of the flush done
    in swap buffers) is a task that the GPU can complete independently of
    the CPU having to wait for previous page flips. So reverse their order
    to get the GPU started earlier, with the aim of greater GPU-CPU
    (cherry picked from commit 6e415353)
  • Olivier Fourdan's avatar
    cursor-renderer-native: take rotation into account · 8696a794
    Olivier Fourdan authored
    Rotating an output would show duplicate cursors when the pointer is
    located over an area which would be within the output if not rotated.
    Make sure to swap the width/height of the output when rotated.
    Closes: #85
    (cherry picked from commit ebff7fd7)
  • Alberts Muktupāvels's avatar
    input-settings: Fix a typo in tap-and-drag setting · 7ac551cd
    Alberts Muktupāvels authored
    (cherry picked from commit 31b50590)
  • Carlos Garnacho's avatar
    clutter: Apply input hints/purpose on ClutterTextInputFocus focus in · de7d7bbf
    Carlos Garnacho authored
    And make the ClutterText-level properties independent from the input
    focus, as those properties can be set anytime, not just when the
    ClutterText actor is focused.
    Closes: #66
    (cherry picked from commit 3684f6b0)
  • Daniel Stone's avatar
    renderer-native: Fall back to non-modifier GBM surfaces · 1851fa2b
    Daniel Stone authored
    If we attempt GBM surface allocation with a set of modifiers but the
    allocation fails, fall back to non-modifier allocations. This fixes
    startup on Pineview-based Atom systems, where KMS provides us a set of
    modifiers but the GBM implementation doesn't support modifier use.
    Closes: GNOME/mutter#84
    (cherry picked from commit e6109cfc)
  • Marco Trevisan's avatar
    theme: add ".appmenu" class to the appmenu button · 84184354
    Marco Trevisan authored
    So it does gtk headerbar, so mutter should do.
    (cherry picked from commit 96141e28)
......@@ -2830,6 +2830,10 @@ clutter_text_key_focus_in (ClutterActor *actor)
if (method && priv->editable)
clutter_input_method_focus_in (method, priv->input_focus);
clutter_input_focus_set_content_purpose (priv->input_focus,
clutter_input_focus_set_content_hints (priv->input_focus,
update_cursor_location (CLUTTER_TEXT (actor));
......@@ -4511,6 +4515,27 @@ buffer_deleted_text (ClutterTextBuffer *buffer,
static void
clutter_text_queue_redraw_or_relayout (ClutterText *self)
ClutterActor *actor = CLUTTER_ACTOR (self);
gfloat preferred_width;
gfloat preferred_height;
clutter_text_dirty_cache (self);
/* we're using our private implementations here to avoid the caching done by ClutterActor */
clutter_text_get_preferred_width (actor, -1, NULL, &preferred_width);
clutter_text_get_preferred_height (actor, preferred_width, NULL, &preferred_height);
if (clutter_actor_has_allocation (actor) &&
(fabsf (preferred_width - clutter_actor_get_width (actor)) > 0.001 ||
fabsf (preferred_height - clutter_actor_get_height (actor)) > 0.001))
clutter_actor_queue_relayout (actor);
clutter_text_queue_redraw (actor);
static void
buffer_notify_text (ClutterTextBuffer *buffer,
GParamSpec *spec,
......@@ -4518,9 +4543,7 @@ buffer_notify_text (ClutterTextBuffer *buffer,
g_object_freeze_notify (G_OBJECT (self));
clutter_text_dirty_cache (self);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
clutter_text_queue_redraw_or_relayout (self);
g_signal_emit (self, text_signals[TEXT_CHANGED], 0);
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT]);
......@@ -4872,8 +4895,7 @@ clutter_text_set_cursor_visible (ClutterText *self,
priv->cursor_visible = cursor_visible;
clutter_text_dirty_cache (self);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
clutter_text_queue_redraw_or_relayout (self);
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_VISIBLE]);
......@@ -5774,9 +5796,7 @@ clutter_text_set_line_alignment (ClutterText *self,
priv->alignment = alignment;
clutter_text_dirty_cache (self);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
clutter_text_queue_redraw_or_relayout (self);
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_ALIGNMENT]);
......@@ -5831,9 +5851,7 @@ clutter_text_set_use_markup (ClutterText *self,
if (setting)
clutter_text_set_markup_internal (self, text);
clutter_text_dirty_cache (self);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
clutter_text_queue_redraw_or_relayout (self);
......@@ -5880,9 +5898,7 @@ clutter_text_set_justify (ClutterText *self,
priv->justify = justify;
clutter_text_dirty_cache (self);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
clutter_text_queue_redraw_or_relayout (self);
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_JUSTIFY]);
......@@ -6449,8 +6465,7 @@ clutter_text_set_preedit_string (ClutterText *self,
priv->preedit_set = TRUE;
clutter_text_dirty_cache (self);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
clutter_text_queue_redraw_or_relayout (self);
......@@ -6512,7 +6527,9 @@ clutter_text_set_input_hints (ClutterText *self,
g_return_if_fail (CLUTTER_IS_TEXT (self));
self->priv->input_hints = hints;
clutter_input_focus_set_content_hints (self->priv->input_focus, hints);
if (clutter_input_focus_is_focused (self->priv->input_focus))
clutter_input_focus_set_content_hints (self->priv->input_focus, hints);
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_INPUT_HINTS]);
......@@ -6531,7 +6548,9 @@ clutter_text_set_input_purpose (ClutterText *self,
g_return_if_fail (CLUTTER_IS_TEXT (self));
self->priv->input_purpose = purpose;
clutter_input_focus_set_content_purpose (self->priv->input_focus, purpose);
if (clutter_input_focus_is_focused (self->priv->input_focus))
clutter_input_focus_set_content_purpose (self->priv->input_focus, purpose);
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_INPUT_PURPOSE]);
......@@ -1412,22 +1412,12 @@ _cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
if (!cogl_is_offscreen (framebuffer))
y = framebuffer_height - y - height;
required_format = ctx->driver_vtable->pixel_format_to_gl (ctx,
/* As we are reading pixels, we want to consider the bitmap according to
* its real pixel format, not the swizzled channels we pretend face to the
* pipeline.
if ((ctx->driver == COGL_DRIVER_GL || ctx->driver == COGL_DRIVER_GL3) &&
(format == COGL_PIXEL_FORMAT_BGRA_8888 ||
format == COGL_PIXEL_FORMAT_BGRA_8888_PRE) &&
_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE))
gl_format = GL_BGRA;
required_format = ctx->driver_vtable->pixel_format_to_gl_with_target (ctx,
/* NB: All offscreen rendering is done upside down so there is no need
* to flip in this case... */
......@@ -262,7 +262,22 @@ AC_SUBST(XWAYLAND_PATH)
MUTTER_NATIVE_BACKEND_MODULES="libdrm >= 2.4.83 libsystemd libinput >= 1.4 gudev-1.0 gbm >= 17.1"
PKG_CHECK_MODULES(ELOGIND, [libelogind], [have_elogind=yes], [have_elogind=no])
if test x$have_elogind = xyes; then
PKG_CHECK_MODULES(SYSTEMD, [libsystemd], [have_systemd=yes], [have_systemd=no])
if test x$have_systemd = xyes; then
AS_IF([test -z "$logind_provider"],
AC_MSG_ERROR([Could not find either systemd or elogind as logind provider])])
MUTTER_NATIVE_BACKEND_MODULES="libdrm $logind_provider libinput >= 1.4 gudev-1.0 gbm >= 10.3"
AS_HELP_STRING([--disable-native-backend], [disable mutter native (KMS) backend]),,
......@@ -1088,7 +1088,7 @@ meta_input_settings_changed_cb (GSettings *settings,
update_device_natural_scroll (input_settings, NULL);
else if (strcmp (key, "tap-to-click") == 0)
update_touchpad_tap_enabled (input_settings, NULL);
else if (strcmp (key, "tap-and_drag") == 0)
else if (strcmp (key, "tap-and-drag") == 0)
update_touchpad_tap_and_drag_enabled (input_settings, NULL);
else if (strcmp(key, "disable-while-typing") == 0)
update_touchpad_disable_while_typing (input_settings, NULL);
......@@ -291,9 +291,11 @@ update_monitor_crtc_cursor (MetaMonitor *monitor,
MetaCursorRendererNativePrivate *priv =
meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
MetaMonitorTransform transform;
ClutterRect scaled_crtc_rect;
float scale;
int crtc_x, crtc_y;
int crtc_width, crtc_height;
if (meta_is_stage_views_scaled ())
scale = meta_logical_monitor_get_scale (data->in_logical_monitor);
......@@ -305,14 +307,26 @@ update_monitor_crtc_cursor (MetaMonitor *monitor,
&crtc_x, &crtc_y);
transform = meta_logical_monitor_get_transform (data->in_logical_monitor);
if (meta_monitor_transform_is_rotated (transform))
crtc_width = monitor_crtc_mode->crtc_mode->height;
crtc_height = monitor_crtc_mode->crtc_mode->width;
crtc_width = monitor_crtc_mode->crtc_mode->width;
crtc_height = monitor_crtc_mode->crtc_mode->height;
scaled_crtc_rect = (ClutterRect) {
.origin = {
.x = crtc_x / scale,
.y = crtc_y / scale
.size = {
.width = monitor_crtc_mode->crtc_mode->width / scale,
.height = monitor_crtc_mode->crtc_mode->height / scale
.width = crtc_width / scale,
.height = crtc_height / scale
......@@ -64,6 +64,7 @@ struct _MetaGpuKms
gboolean page_flips_not_supported;
G_DEFINE_QUARK (MetaGpuKmsError, meta_gpu_kms_error)
G_DEFINE_TYPE (MetaGpuKms, meta_gpu_kms, META_TYPE_GPU)
static gboolean
......@@ -751,6 +752,8 @@ meta_gpu_kms_read_current (MetaGpu *gpu,
are freed by the platform-independent layer. */
free_resources (gpu_kms);
g_assert (resources.resources->count_connectors > 0);
init_connectors (gpu_kms, resources.resources);
init_modes (gpu_kms, resources.resources);
init_crtcs (gpu_kms, &resources);
......@@ -774,11 +777,39 @@ meta_gpu_kms_new (MetaMonitorManagerKms *monitor_manager_kms,
GSource *source;
MetaKmsSource *kms_source;
MetaGpuKms *gpu_kms;
drmModeRes *drm_resources;
guint n_connectors;
int kms_fd;
kms_fd = meta_launcher_open_restricted (launcher, kms_file_path, error);
if (kms_fd == -1)
return FALSE;
return NULL;
/* Some GPUs might have no connectors, for example dedicated GPUs on PRIME (hybrid) laptops.
* These GPUs cannot render anything on separate screens, and they are aggressively switched
* off by the kernel.
* If we add these PRIME GPUs to the GPU list anyway, Mutter keeps awakening the secondary GPU,
* and doing this causes a considerable stuttering. These GPUs are usually put to sleep again
* after ~2s without a workload.
* For now, to avoid this situation, only create the MetaGpuKms when the GPU has any connectors.
drm_resources = drmModeGetResources (kms_fd);
n_connectors = drm_resources->count_connectors;
drmModeFreeResources (drm_resources);
if (n_connectors == 0)
g_set_error (error,
"No connectors available in this GPU. This is probably a dedicated GPU in a hybrid setup.");
meta_launcher_close_restricted (launcher, kms_fd);
return NULL;
gpu_kms = g_object_new (META_TYPE_GPU_KMS,
"monitor-manager", monitor_manager_kms,
......@@ -29,6 +29,14 @@
#include "backends/meta-gpu.h"
#include "backends/native/meta-monitor-manager-kms.h"
typedef enum
} MetaGpuKmsError;
#define META_GPU_KMS_ERROR (meta_gpu_kms_error_quark ())
GQuark meta_gpu_kms_error_quark (void);
#define META_TYPE_GPU_KMS (meta_gpu_kms_get_type ())
G_DECLARE_FINAL_TYPE (MetaGpuKms, meta_gpu_kms, META, GPU_KMS, MetaGpu)
......@@ -674,16 +674,19 @@ meta_monitor_manager_kms_initable_init (GInitable *initable,
gpu_paths = get_gpu_paths (manager_kms, GPU_TYPE_SECONDARY, primary_gpu_path);
for (l = gpu_paths; l; l = l->next)
GError *secondary_error = NULL;
g_autoptr (GError) secondary_error = NULL;
char *gpu_path = l->data;
MetaGpuKms *gpu_kms;
gpu_kms = meta_gpu_kms_new (manager_kms, gpu_path, &secondary_error);
if (!gpu_kms)
g_warning ("Failed to open secondary gpu '%s': %s",
gpu_path, secondary_error->message);
g_error_free (secondary_error);
if (g_error_matches (secondary_error, META_GPU_KMS_ERROR, META_GPU_KMS_ERROR_NO_CONNECTORS))
g_message ("Ignoring GPU %s due to the lack of connectors", gpu_path);
g_warning ("Failed to open secondary gpu '%s': %s", gpu_path, secondary_error->message);
meta_monitor_manager_add_gpu (META_MONITOR_MANAGER (manager_kms),
......@@ -1854,18 +1854,18 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
frame_info = g_queue_peek_tail (&onscreen->pending_frame_infos);
frame_info->global_frame_counter = renderer_native->frame_counter;
* Wait for the flip callback before continuing, as we might have started the
* animation earlier due to the animation being driven by some other monitor.
wait_for_pending_flips (onscreen);
update_secondary_gpu_state_pre_swap_buffers (onscreen);
parent_vtable->onscreen_swap_buffers_with_damage (onscreen,
* Wait for the flip callback before continuing, as we might have started the
* animation earlier due to the animation being driven by some other monitor.
wait_for_pending_flips (onscreen);
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
switch (renderer_gpu_data->mode)
......@@ -1996,7 +1996,7 @@ meta_renderer_native_create_surface_gbm (CoglOnscreen *onscreen,
CoglRenderer *cogl_renderer = cogl_display->renderer;
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
struct gbm_surface *new_gbm_surface;
struct gbm_surface *new_gbm_surface = NULL;
EGLNativeWindowType egl_native_window;
EGLSurface new_egl_surface;
uint32_t format = GBM_FORMAT_XRGB8888;
......@@ -2017,7 +2017,8 @@ meta_renderer_native_create_surface_gbm (CoglOnscreen *onscreen,
g_array_free (modifiers, TRUE);
if (!new_gbm_surface)
......@@ -5268,7 +5268,7 @@ static cairo_surface_t *
load_default_window_icon (int size)
GtkIconTheme *theme = gtk_icon_theme_get_default ();
GdkPixbuf *pixbuf;
g_autoptr (GdkPixbuf) pixbuf = NULL;
const char *icon_name;
if (gtk_icon_theme_has_icon (theme, META_DEFAULT_ICON_NAME))
......@@ -712,6 +712,8 @@ get_class_from_button_type (MetaButtonType type)
return "maximize";
return "minimize";
return "appmenu";
return NULL;