diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c index 9d4d36ec3..4e8d53436 100644 --- a/clutter/clutter/clutter-actor.c +++ b/clutter/clutter/clutter-actor.c @@ -20020,6 +20020,23 @@ clutter_actor_get_transition (ClutterActor *self, return clos->transition; } +/** + * clutter_actor_has_transitions: (skip) + */ +gboolean +clutter_actor_has_transitions (ClutterActor *self) +{ + const ClutterAnimationInfo *info; + + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); + + info = _clutter_actor_get_animation_info_or_defaults (self); + if (info->transitions == NULL) + return FALSE; + + return g_hash_table_size (info->transitions) > 0; +} + /** * clutter_actor_save_easing_state: * @self: a #ClutterActor diff --git a/clutter/clutter/clutter-muffin.h b/clutter/clutter/clutter-muffin.h index c0d9015d8..3cffda020 100644 --- a/clutter/clutter/clutter-muffin.h +++ b/clutter/clutter/clutter-muffin.h @@ -75,6 +75,10 @@ void clutter_stage_thaw_updates (ClutterStage *stage); CLUTTER_EXPORT void clutter_stage_update_resource_scales (ClutterStage *stage); +CLUTTER_EXPORT +void clutter_stage_view_assign_next_scanout (ClutterStageView *stage_view, + CoglScanout *scanout); + CLUTTER_EXPORT gboolean clutter_actor_has_damage (ClutterActor *actor); @@ -83,6 +87,10 @@ void clutter_stage_get_device_coords (ClutterStage *stage, ClutterInputDevice *device, ClutterEventSequence *sequence, graphene_point_t *coords); + +CLUTTER_EXPORT +gboolean clutter_actor_has_transitions (ClutterActor *actor); + #undef __CLUTTER_H_INSIDE__ #endif /* __CLUTTER_MUFFIN_H__ */ diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h index 3b0d419fc..2e5ad4c53 100644 --- a/clutter/clutter/clutter-stage-view-private.h +++ b/clutter/clutter/clutter-stage-view-private.h @@ -43,4 +43,6 @@ const cairo_region_t * clutter_stage_view_peek_redraw_clip (ClutterStageView *vi cairo_region_t * clutter_stage_view_take_redraw_clip (ClutterStageView *view); +CoglScanout * clutter_stage_view_take_scanout (ClutterStageView *view); + #endif /* __CLUTTER_STAGE_VIEW_PRIVATE_H__ */ diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c index d93cf573f..2db98fa9e 100644 --- a/clutter/clutter/clutter-stage-view.c +++ b/clutter/clutter/clutter-stage-view.c @@ -24,6 +24,8 @@ #include #include "clutter/clutter-private.h" +#include "clutter/clutter-muffin.h" +#include "cogl/cogl.h" enum { @@ -52,6 +54,8 @@ typedef struct _ClutterStageViewPrivate CoglOffscreen *shadowfb; CoglPipeline *shadowfb_pipeline; + CoglScanout *next_scanout; + gboolean has_redraw_clip; cairo_region_t *redraw_clip; @@ -407,6 +411,25 @@ clutter_stage_default_get_offscreen_transformation_matrix (ClutterStageView *vie cogl_matrix_init_identity (matrix); } +void +clutter_stage_view_assign_next_scanout (ClutterStageView *view, + CoglScanout *scanout) +{ + ClutterStageViewPrivate *priv = + clutter_stage_view_get_instance_private (view); + + g_set_object (&priv->next_scanout, scanout); +} + +CoglScanout * +clutter_stage_view_take_scanout (ClutterStageView *view) +{ + ClutterStageViewPrivate *priv = + clutter_stage_view_get_instance_private (view); + + return g_steal_pointer (&priv->next_scanout); +} + static void clutter_stage_view_get_property (GObject *object, guint prop_id, diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c index bda49ee4d..172ac6014 100644 --- a/clutter/clutter/cogl/clutter-stage-cogl.c +++ b/clutter/clutter/cogl/clutter-stage-cogl.c @@ -989,6 +989,20 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window, } } +static void +clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl, + ClutterStageView *view, + CoglScanout *scanout) +{ + CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view); + CoglOnscreen *onscreen; + + g_return_if_fail (cogl_is_onscreen (framebuffer)); + + onscreen = COGL_ONSCREEN (framebuffer); + cogl_onscreen_direct_scanout (onscreen, scanout); +} + static void clutter_stage_cogl_redraw (ClutterStageWindow *stage_window) { @@ -1016,11 +1030,23 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window) for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next) { ClutterStageView *view = l->data; + g_autoptr (CoglScanout) scanout = NULL; if (!clutter_stage_view_has_redraw_clip (view)) continue; - swap_event |= clutter_stage_cogl_redraw_view (stage_window, view); + scanout = clutter_stage_view_take_scanout (view); + if (scanout) + { + clutter_stage_cogl_scanout_view (stage_cogl, + view, + scanout); + swap_event = TRUE; + } + else + { + swap_event |= clutter_stage_cogl_redraw_view (stage_window, view); + } } if (has_redraw_clip) diff --git a/cogl/cogl/cogl-onscreen.c b/cogl/cogl/cogl-onscreen.c index 704e1c44b..892a0af3b 100644 --- a/cogl/cogl/cogl-onscreen.c +++ b/cogl/cogl/cogl-onscreen.c @@ -405,6 +405,27 @@ cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen) return winsys->onscreen_get_buffer_age (onscreen); } +void +cogl_onscreen_direct_scanout (CoglOnscreen *onscreen, + CoglScanout *scanout) +{ + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + const CoglWinsysVtable *winsys; + CoglFrameInfo *info; + + g_return_if_fail (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN); + g_return_if_fail (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT)); + + info = _cogl_frame_info_new (); + info->frame_counter = onscreen->frame_counter; + g_queue_push_tail (&onscreen->pending_frame_infos, info); + + winsys = _cogl_framebuffer_get_winsys (framebuffer); + winsys->onscreen_direct_scanout (onscreen, scanout); + + onscreen->frame_counter++; +} + #ifdef COGL_HAS_X11_SUPPORT uint32_t cogl_x11_onscreen_get_window_xid (CoglOnscreen *onscreen) diff --git a/cogl/cogl/cogl-onscreen.h b/cogl/cogl/cogl-onscreen.h index a7b50e2af..e99d8d129 100644 --- a/cogl/cogl/cogl-onscreen.h +++ b/cogl/cogl/cogl-onscreen.h @@ -50,6 +50,8 @@ G_BEGIN_DECLS typedef struct _CoglOnscreen CoglOnscreen; #define COGL_ONSCREEN(X) ((CoglOnscreen *)(X)) +typedef struct _CoglScanout CoglScanout; + /** * cogl_onscreen_get_gtype: * @@ -284,6 +286,13 @@ cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, const int *rectangles, int n_rectangles); +/** + * cogl_onscreen_direct_scanout: (skip) + */ +COGL_EXPORT void +cogl_onscreen_direct_scanout (CoglOnscreen *onscreen, + CoglScanout *scanout); + /** * cogl_onscreen_swap_region: * @onscreen: A #CoglOnscreen framebuffer diff --git a/cogl/cogl/cogl-scanout.c b/cogl/cogl/cogl-scanout.c new file mode 100644 index 000000000..759cd62a4 --- /dev/null +++ b/cogl/cogl/cogl-scanout.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "cogl-config.h" + +#include "cogl-scanout.h" + +G_DEFINE_INTERFACE (CoglScanout, cogl_scanout, G_TYPE_OBJECT) + +static void +cogl_scanout_default_init (CoglScanoutInterface *iface) +{ +} diff --git a/cogl/cogl/cogl-scanout.h b/cogl/cogl/cogl-scanout.h new file mode 100644 index 000000000..63e1238f0 --- /dev/null +++ b/cogl/cogl/cogl-scanout.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef COGL_SCANOUT_H +#define COGL_SCANOUT_H + +#include "cogl/cogl-types.h" + +#include + +#define COGL_TYPE_SCANOUT (cogl_scanout_get_type ()) +COGL_EXPORT +G_DECLARE_INTERFACE (CoglScanout, cogl_scanout, + COGL, SCANOUT, GObject) + +struct _CoglScanoutInterface +{ + GTypeInterface parent_iface; +}; + +#endif /* COGL_SCANOUT_H */ diff --git a/cogl/cogl/cogl.h b/cogl/cogl/cogl.h index 3fd9b1c64..f3d3aaaae 100644 --- a/cogl/cogl/cogl.h +++ b/cogl/cogl/cogl.h @@ -122,6 +122,7 @@ #include #include #include +#include /* XXX: This will definitly go away once all the Clutter winsys * code has been migrated down into Cogl! */ #include diff --git a/cogl/cogl/meson.build b/cogl/cogl/meson.build index 55523dd3f..daea0df10 100644 --- a/cogl/cogl/meson.build +++ b/cogl/cogl/meson.build @@ -122,6 +122,7 @@ cogl_nonintrospected_headers = [ 'cogl-version.h', 'cogl-gtype-private.h', 'cogl-glib-source.h', + 'cogl-scanout.h', ] cogl_nodist_headers = [ @@ -347,6 +348,7 @@ cogl_sources = [ 'cogl-closure-list.c', 'cogl-fence.c', 'cogl-fence-private.h', + 'cogl-scanout.c', 'deprecated/cogl-material-compat.c', 'deprecated/cogl-program.c', 'deprecated/cogl-program-private.h', diff --git a/cogl/cogl/winsys/cogl-winsys-private.h b/cogl/cogl/winsys/cogl-winsys-private.h index d849ef705..01a45b765 100644 --- a/cogl/cogl/winsys/cogl-winsys-private.h +++ b/cogl/cogl/winsys/cogl-winsys-private.h @@ -33,6 +33,7 @@ #include "cogl-renderer.h" #include "cogl-onscreen.h" +#include "cogl-scanout.h" #ifdef COGL_HAS_XLIB_SUPPORT #include "cogl-texture-pixmap-x11-private.h" @@ -117,6 +118,10 @@ typedef struct _CoglWinsysVtable const int *rectangles, int n_rectangles); + void + (*onscreen_direct_scanout) (CoglOnscreen *onscreen, + CoglScanout *scanout); + void (*onscreen_set_visibility) (CoglOnscreen *onscreen, gboolean visibility); diff --git a/debian/libmuffin0.symbols b/debian/libmuffin0.symbols index 999b34fad..d6f47a4a5 100644 --- a/debian/libmuffin0.symbols +++ b/debian/libmuffin0.symbols @@ -217,6 +217,7 @@ libmuffin-clutter-0.so.0 libmuffin0 #MINVER# clutter_actor_has_mapped_clones@Base 5.3.0 clutter_actor_has_overlaps@Base 5.3.0 clutter_actor_has_pointer@Base 5.3.0 + clutter_actor_has_transitions@Base 6.4.1 clutter_actor_hide@Base 5.3.0 clutter_actor_inhibit_culling@Base 5.3.0 clutter_actor_insert_child_above@Base 5.3.0 @@ -1159,6 +1160,7 @@ libmuffin-clutter-0.so.0 libmuffin0 #MINVER# clutter_stage_state_get_type@Base 5.3.0 clutter_stage_thaw_updates@Base 5.3.0 clutter_stage_update_resource_scales@Base 5.3.0 + clutter_stage_view_assign_next_scanout@Base 6.4.1 clutter_stage_view_cogl_get_type@Base 5.3.0 clutter_stage_view_get_framebuffer@Base 5.3.0 clutter_stage_view_get_layout@Base 5.3.0 @@ -1771,6 +1773,7 @@ libmuffin-cogl-0.so.0 libmuffin0 #MINVER# cogl_onscreen_add_dirty_callback@Base 5.3.0 cogl_onscreen_add_frame_callback@Base 5.3.0 cogl_onscreen_add_resize_callback@Base 5.3.0 + cogl_onscreen_direct_scanout@Base 6.4.1 cogl_onscreen_dirty_closure_get_gtype@Base 5.3.0 cogl_onscreen_get_buffer_age@Base 5.3.0 cogl_onscreen_get_frame_counter@Base 5.3.0 @@ -1905,6 +1908,7 @@ libmuffin-cogl-0.so.0 libmuffin0 #MINVER# cogl_renderer_set_custom_winsys@Base 5.3.0 cogl_renderer_set_driver@Base 5.3.0 cogl_renderer_set_winsys_id@Base 5.3.0 + cogl_scanout_get_type@Base 6.4.1 cogl_set_backface_culling_enabled@Base 5.3.0 cogl_set_depth_test_enabled@Base 5.3.0 cogl_set_tracing_disabled_on_thread@Base 5.3.0 @@ -2681,8 +2685,6 @@ libmuffin.so.0 libmuffin0 #MINVER# meta_window_move_resize_frame@Base 5.3.0 meta_window_move_to_monitor@Base 5.3.0 meta_window_raise@Base 5.3.0 - meta_window_requested_bypass_compositor@Base 5.3.0 - meta_window_requested_dont_bypass_compositor@Base 5.3.0 meta_window_set_compositor_private@Base 5.3.0 meta_window_set_demands_attention@Base 5.3.0 meta_window_set_icon_geometry@Base 5.3.0 diff --git a/src/backends/native/meta-drm-buffer-gbm.c b/src/backends/native/meta-drm-buffer-gbm.c index b446d64e1..85f5ed598 100644 --- a/src/backends/native/meta-drm-buffer-gbm.c +++ b/src/backends/native/meta-drm-buffer-gbm.c @@ -44,7 +44,12 @@ struct _MetaDrmBufferGbm uint32_t fb_id; }; -G_DEFINE_TYPE (MetaDrmBufferGbm, meta_drm_buffer_gbm, META_TYPE_DRM_BUFFER) +static void +cogl_scanout_iface_init (CoglScanoutInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaDrmBufferGbm, meta_drm_buffer_gbm, META_TYPE_DRM_BUFFER, + G_IMPLEMENT_INTERFACE (COGL_TYPE_SCANOUT, + cogl_scanout_iface_init)) struct gbm_bo * meta_drm_buffer_gbm_get_bo (MetaDrmBufferGbm *buffer_gbm) @@ -53,22 +58,12 @@ meta_drm_buffer_gbm_get_bo (MetaDrmBufferGbm *buffer_gbm) } static gboolean -acquire_swapped_buffer (MetaDrmBufferGbm *buffer_gbm, - gboolean use_modifiers, - GError **error) +init_fb_id (MetaDrmBufferGbm *buffer_gbm, + struct gbm_bo *bo, + gboolean use_modifiers, + GError **error) { MetaGpuKmsFBArgs fb_args = { 0, }; - struct gbm_bo *bo; - - bo = gbm_surface_lock_front_buffer (buffer_gbm->surface); - if (!bo) - { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "gbm_surface_lock_front_buffer failed"); - return FALSE; - } if (gbm_bo_get_handle_for_plane (bo, 0).s32 == -1) { @@ -99,43 +94,82 @@ acquire_swapped_buffer (MetaDrmBufferGbm *buffer_gbm, use_modifiers, &fb_args, &buffer_gbm->fb_id, error)) + return FALSE; + return TRUE; +} + +static gboolean +lock_front_buffer (MetaDrmBufferGbm *buffer_gbm, + gboolean use_modifiers, + GError **error) +{ + buffer_gbm->bo = gbm_surface_lock_front_buffer (buffer_gbm->surface); + if (!buffer_gbm->bo) { - gbm_surface_release_buffer (buffer_gbm->surface, bo); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "gbm_surface_lock_front_buffer failed"); return FALSE; } + return init_fb_id (buffer_gbm, buffer_gbm->bo, use_modifiers, error); +} - buffer_gbm->bo = bo; +MetaDrmBufferGbm * +meta_drm_buffer_gbm_new_lock_front (MetaGpuKms *gpu_kms, + struct gbm_surface *gbm_surface, + gboolean use_modifiers, + GError **error) +{ + MetaDrmBufferGbm *buffer_gbm; - return TRUE; + buffer_gbm = g_object_new (META_TYPE_DRM_BUFFER_GBM, NULL); + buffer_gbm->gpu_kms = gpu_kms; + buffer_gbm->surface = gbm_surface; + + if (!lock_front_buffer (buffer_gbm, use_modifiers, error)) + { + g_object_unref (buffer_gbm); + return NULL; + } + + return buffer_gbm; } MetaDrmBufferGbm * -meta_drm_buffer_gbm_new (MetaGpuKms *gpu_kms, - struct gbm_surface *gbm_surface, - gboolean use_modifiers, - GError **error) +meta_drm_buffer_gbm_new_take (MetaGpuKms *gpu_kms, + struct gbm_bo *bo, + gboolean use_modifiers, + GError **error) { MetaDrmBufferGbm *buffer_gbm; buffer_gbm = g_object_new (META_TYPE_DRM_BUFFER_GBM, NULL); buffer_gbm->gpu_kms = gpu_kms; - buffer_gbm->surface = gbm_surface; - if (!acquire_swapped_buffer (buffer_gbm, use_modifiers, error)) + if (!init_fb_id (buffer_gbm, bo, use_modifiers, error)) { g_object_unref (buffer_gbm); return NULL; } + buffer_gbm->bo = bo; + return buffer_gbm; } + static uint32_t meta_drm_buffer_gbm_get_fb_id (MetaDrmBuffer *buffer) { return META_DRM_BUFFER_GBM (buffer)->fb_id; } +static void +cogl_scanout_iface_init (CoglScanoutInterface *iface) +{ +} + static void meta_drm_buffer_gbm_finalize (GObject *object) { @@ -150,7 +184,12 @@ meta_drm_buffer_gbm_finalize (GObject *object) } if (buffer_gbm->bo) - gbm_surface_release_buffer (buffer_gbm->surface, buffer_gbm->bo); + { + if (buffer_gbm->surface) + gbm_surface_release_buffer (buffer_gbm->surface, buffer_gbm->bo); + else + gbm_bo_destroy (buffer_gbm->bo); + } G_OBJECT_CLASS (meta_drm_buffer_gbm_parent_class)->finalize (object); } diff --git a/src/backends/native/meta-drm-buffer-gbm.h b/src/backends/native/meta-drm-buffer-gbm.h index b48cef06a..b46925ecc 100644 --- a/src/backends/native/meta-drm-buffer-gbm.h +++ b/src/backends/native/meta-drm-buffer-gbm.h @@ -33,10 +33,16 @@ G_DECLARE_FINAL_TYPE (MetaDrmBufferGbm, META, DRM_BUFFER_GBM, MetaDrmBuffer) -MetaDrmBufferGbm * meta_drm_buffer_gbm_new (MetaGpuKms *gpu_kms, - struct gbm_surface *gbm_surface, - gboolean use_modifiers, - GError **error); +MetaDrmBufferGbm * meta_drm_buffer_gbm_new_lock_front (MetaGpuKms *gpu_kms, + struct gbm_surface *gbm_surface, + gboolean use_modifiers, + GError **error); + + +MetaDrmBufferGbm * meta_drm_buffer_gbm_new_take (MetaGpuKms *gpu_kms, + struct gbm_bo *gbm_bo, + gboolean use_modifiers, + GError **error); struct gbm_bo * meta_drm_buffer_gbm_get_bo (MetaDrmBufferGbm *buffer_gbm); diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 7e75ab9fd..658053bdc 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -313,6 +313,12 @@ meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms) return renderer_gpu_data->gbm.device; } +MetaGpuKms * +meta_renderer_native_get_primary_gpu (MetaRendererNative *renderer_native) +{ + return renderer_native->primary_gpu_kms; +} + static MetaRendererNativeGpuData * meta_create_renderer_native_gpu_data (MetaGpuKms *gpu_kms) { @@ -1621,13 +1627,14 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, return; } - buffer_gbm = meta_drm_buffer_gbm_new (secondary_gpu_state->gpu_kms, + buffer_gbm = + meta_drm_buffer_gbm_new_lock_front (secondary_gpu_state->gpu_kms, secondary_gpu_state->gbm.surface, renderer_native->use_modifiers, &error); if (!buffer_gbm) { - g_warning ("meta_drm_buffer_gbm_new failed: %s", + g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s", error->message); g_error_free (error); return; @@ -2012,6 +2019,35 @@ update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen, } } +static void +ensure_crtc_modes (CoglOnscreen *onscreen, + MetaKmsUpdate *kms_update) +{ + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; + MetaOnscreenNative *onscreen_native = onscreen_egl->platform; + CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->context; + CoglRenderer *cogl_renderer = cogl_context->display->renderer; + CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; + MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; + MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; + MetaRenderer *renderer = META_RENDERER (renderer_native); + MetaBackend *backend = meta_renderer_get_backend (renderer); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaPowerSave power_save_mode; + + power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); + if (onscreen_native->pending_set_crtc && + power_save_mode == META_POWER_SAVE_ON) + { + meta_onscreen_native_set_crtc_mode (onscreen, + renderer_gpu_data, + kms_update); + onscreen_native->pending_set_crtc = FALSE; + } +} + + static MetaKmsUpdate * unset_disabled_crtcs (MetaBackend *backend, MetaKms *kms) @@ -2067,8 +2103,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; MetaRenderer *renderer = META_RENDERER (renderer_native); MetaBackend *backend = meta_renderer_get_backend (renderer); - MetaMonitorManager *monitor_manager = - meta_backend_get_monitor_manager (backend); MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); MetaKms *kms = meta_backend_native_get_kms (backend_native); CoglOnscreenEGL *onscreen_egl = onscreen->winsys; @@ -2077,7 +2111,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, CoglFrameInfo *frame_info; gboolean egl_context_changed = FALSE; MetaKmsUpdate *kms_update; - MetaPowerSave power_save_mode; g_autoptr (GError) error = NULL; MetaDrmBufferGbm *buffer_gbm; g_autoptr (MetaKmsFeedback) kms_feedback = NULL; @@ -2113,13 +2146,14 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, g_warn_if_fail (onscreen_native->gbm.next_fb == NULL); g_clear_object (&onscreen_native->gbm.next_fb); - buffer_gbm = meta_drm_buffer_gbm_new (render_gpu, + buffer_gbm = + meta_drm_buffer_gbm_new_lock_front (render_gpu, onscreen_native->gbm.surface, renderer_native->use_modifiers, &error); if (!buffer_gbm) { - g_warning ("meta_drm_buffer_gbm_new failed: %s", + g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s", error->message); return; } @@ -2135,18 +2169,7 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed); - /* If this is the first framebuffer to be presented then we now setup the - * crtc modes, else we flip from the previous buffer */ - - power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); - if (onscreen_native->pending_set_crtc && - power_save_mode == META_POWER_SAVE_ON) - { - meta_onscreen_native_set_crtc_mode (onscreen, - renderer_gpu_data, - kms_update); - onscreen_native->pending_set_crtc = FALSE; - } + ensure_crtc_modes (onscreen, kms_update); onscreen_native->pending_queue_swap_notify_frame_count = renderer_native->frame_counter; meta_onscreen_native_flip_crtcs (onscreen, kms_update); @@ -2237,6 +2260,92 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer, return NULL; } +gboolean +meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen, + uint32_t drm_format, + uint64_t drm_modifier, + uint32_t stride) +{ + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; + MetaOnscreenNative *onscreen_native = onscreen_egl->platform; + MetaDrmBuffer *fb; + struct gbm_bo *gbm_bo; + + if (onscreen_native->crtc->config->transform != META_MONITOR_TRANSFORM_NORMAL) + return FALSE; + + if (onscreen_native->secondary_gpu_state) + return FALSE; + + if (!onscreen_native->gbm.surface) + return FALSE; + + fb = onscreen_native->gbm.current_fb ? onscreen_native->gbm.current_fb + : onscreen_native->gbm.next_fb; + if (!fb) + return FALSE; + + if (!META_IS_DRM_BUFFER_GBM (fb)) + return FALSE; + + gbm_bo = meta_drm_buffer_gbm_get_bo (META_DRM_BUFFER_GBM (fb)); + + if (gbm_bo_get_format (gbm_bo) != drm_format) + return FALSE; + + if (gbm_bo_get_modifier (gbm_bo) != drm_modifier) + return FALSE; + + if (gbm_bo_get_stride (gbm_bo) != stride) + return FALSE; + + return TRUE; +} + +static void +meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, + CoglScanout *scanout) +{ + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; + MetaOnscreenNative *onscreen_native = onscreen_egl->platform; + MetaGpuKms *render_gpu = onscreen_native->render_gpu; + CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->context; + CoglRenderer *cogl_renderer = cogl_context->display->renderer; + CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; + MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; + MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; + MetaRenderer *renderer = META_RENDERER (renderer_native); + MetaBackend *backend = meta_renderer_get_backend (renderer); + MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); + MetaKms *kms = meta_backend_native_get_kms (backend_native); + CoglFrameInfo *frame_info; + MetaKmsUpdate *kms_update; + g_autoptr (GError) error = NULL; + + kms_update = meta_kms_ensure_pending_update (kms); + + wait_for_pending_flips (onscreen); + + frame_info = g_queue_peek_tail (&onscreen->pending_frame_infos); + frame_info->global_frame_counter = renderer_native->frame_counter; + + renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, + render_gpu); + + g_return_if_fail (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_GBM); + + g_warn_if_fail (!onscreen_native->gbm.next_fb); + g_set_object (&onscreen_native->gbm.next_fb, META_DRM_BUFFER (scanout)); + + ensure_crtc_modes (onscreen, kms_update); + + onscreen_native->pending_queue_swap_notify_frame_count = + renderer_native->frame_counter; + meta_onscreen_native_flip_crtcs (onscreen, kms_update); + + meta_kms_post_pending_update_sync (kms); +} + static gboolean meta_renderer_native_init_egl_context (CoglContext *cogl_context, GError **error) @@ -2960,6 +3069,7 @@ get_native_cogl_winsys_vtable (CoglRenderer *cogl_renderer) vtable.onscreen_swap_region = NULL; vtable.onscreen_swap_buffers_with_damage = meta_onscreen_native_swap_buffers_with_damage; + vtable.onscreen_direct_scanout = meta_onscreen_native_direct_scanout; vtable.context_get_clock_time = meta_renderer_native_get_clock_time; diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h index 1f61e261f..04260486a 100644 --- a/src/backends/native/meta-renderer-native.h +++ b/src/backends/native/meta-renderer-native.h @@ -51,10 +51,17 @@ MetaRendererNative * meta_renderer_native_new (MetaBackendNative *backend_nativ struct gbm_device * meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms); +MetaGpuKms * meta_renderer_native_get_primary_gpu (MetaRendererNative *renderer_native); + void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native); int64_t meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native); void meta_renderer_native_reset_modes (MetaRendererNative *renderer_native); +gboolean meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen, + uint32_t drm_format, + uint64_t drm_modifier, + uint32_t stride); + #endif /* META_RENDERER_NATIVE_H */ diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h index 488a8cc4c..42ca3f4a9 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -14,11 +14,14 @@ /* Wait 2ms after vblank before starting to draw next frame */ #define META_SYNC_DELAY 2 +typedef struct _MetaLaters MetaLaters; + struct _MetaCompositorClass { GObjectClass parent_class; - void (* manage) (MetaCompositor *compositor); + gboolean (* manage) (MetaCompositor *compositor, + GError **error); void (* unmanage) (MetaCompositor *compositor); void (* pre_paint) (MetaCompositor *compositor); void (* post_paint) (MetaCompositor *compositor); @@ -28,6 +31,9 @@ struct _MetaCompositorClass int64_t time_us); }; +gboolean meta_compositor_do_manage (MetaCompositor *compositor, + GError **error); + void meta_compositor_remove_window_actor (MetaCompositor *compositor, MetaWindowActor *window_actor); @@ -69,6 +75,8 @@ ClutterStage * meta_compositor_get_stage (MetaCompositor *compositor); gboolean meta_compositor_is_switching_workspace (MetaCompositor *compositor); +MetaLaters * meta_compositor_get_laters (MetaCompositor *compositor); + void meta_update_desklet_stacking (MetaCompositor *compositor); static inline int64_t diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 66af08546..73ff31832 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -62,6 +62,7 @@ #include "backends/x11/meta-stage-x11.h" #include "clutter/clutter-muffin.h" #include "cogl/cogl.h" +#include "compositor/meta-later-private.h" #include "compositor/meta-window-actor-x11.h" #include "compositor/meta-window-actor-private.h" #include "compositor/meta-window-group-private.h" @@ -98,6 +99,15 @@ enum static GParamSpec *obj_props[N_PROPS] = { NULL, }; +enum +{ + PRE_PAINT, + + N_SIGNALS +}; + +static guint signals[N_SIGNALS]; + typedef struct _MetaCompositorPrivate { GObject parent; @@ -132,6 +142,8 @@ typedef struct _MetaCompositorPrivate int switch_workspace_in_progress; MetaPluginManager *plugin_mgr; + + MetaLaters *laters; } MetaCompositorPrivate; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaCompositor, meta_compositor, @@ -567,8 +579,9 @@ meta_compositor_redirect_x11_windows (MetaCompositor *compositor) redirect_windows (display->x11_display); } -void -meta_compositor_manage (MetaCompositor *compositor) +gboolean +meta_compositor_do_manage (MetaCompositor *compositor, + GError **error) { MetaCompositorPrivate *priv = meta_compositor_get_instance_private (compositor); @@ -618,11 +631,23 @@ meta_compositor_manage (MetaCompositor *compositor) clutter_actor_add_child (priv->stage, priv->top_window_group); clutter_actor_add_child (priv->stage, priv->feedback_group); - META_COMPOSITOR_GET_CLASS (compositor)->manage (compositor); + if (!META_COMPOSITOR_GET_CLASS (compositor)->manage (compositor, error)) + return FALSE; priv->plugin_mgr = meta_plugin_manager_new (compositor); clutter_actor_show (priv->stage); + + return TRUE; +} + +void +meta_compositor_manage (MetaCompositor *compositor) +{ + GError *error = NULL; + + if (!meta_compositor_do_manage (compositor, &error)) + g_error ("Compositor failed to manage display: %s", error->message); } void @@ -1261,7 +1286,8 @@ meta_compositor_pre_paint (MetaCompositor *compositor) { COGL_TRACE_BEGIN_SCOPED (MetaCompositorPrePaint, "Compositor (pre-paint)"); - META_COMPOSITOR_GET_CLASS (compositor)->pre_paint (compositor); + + g_signal_emit (compositor, signals[PRE_PAINT], 0); } static gboolean @@ -1388,6 +1414,8 @@ meta_compositor_init (MetaCompositor *compositor) meta_post_paint_func, compositor, NULL); + + priv->laters = meta_laters_new (compositor); } static void @@ -1397,6 +1425,8 @@ meta_compositor_dispose (GObject *object) MetaCompositorPrivate *priv = meta_compositor_get_instance_private (compositor); + g_clear_pointer (&priv->laters, meta_laters_free); + g_clear_signal_handler (&priv->stage_after_paint_id, priv->stage); g_clear_signal_handler (&priv->stage_presented_id, priv->stage); @@ -1441,6 +1471,14 @@ meta_compositor_class_init (MetaCompositorClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, obj_props); + + signals[PRE_PAINT] = + g_signal_new ("pre-paint", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MetaCompositorClass, pre_paint), + NULL, NULL, NULL, + G_TYPE_NONE, 0); } /** @@ -1732,6 +1770,15 @@ meta_compositor_is_switching_workspace (MetaCompositor *compositor) return priv->switch_workspace_in_progress > 0; } +MetaLaters * +meta_compositor_get_laters (MetaCompositor *compositor) +{ + MetaCompositorPrivate *priv = + meta_compositor_get_instance_private (compositor); + + return priv->laters; +} + /** * meta_get_x11_background_actor_for_display: * @display: a #MetaDisplay diff --git a/src/compositor/meta-compositor-native.c b/src/compositor/meta-compositor-native.c new file mode 100644 index 000000000..0acb08c82 --- /dev/null +++ b/src/compositor/meta-compositor-native.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2019 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. + * + */ + +#include "config.h" + +#include "compositor/meta-compositor-native.h" + +#include "backends/meta-logical-monitor.h" +#include "compositor/meta-surface-actor-wayland.h" + +struct _MetaCompositorNative +{ + MetaCompositorServer parent; +}; + +G_DEFINE_TYPE (MetaCompositorNative, meta_compositor_native, + META_TYPE_COMPOSITOR_SERVER) + +static MetaRendererView * +get_window_view (MetaRenderer *renderer, + MetaWindow *window) +{ + GList *l; + MetaRendererView *view_found = NULL; + + for (l = meta_renderer_get_views (renderer); l; l = l->next) + { + ClutterStageView *stage_view = l->data; + MetaRectangle view_layout; + + clutter_stage_view_get_layout (stage_view, &view_layout); + + if (meta_rectangle_equal (&window->buffer_rect, + &view_layout)) + { + if (view_found) + return NULL; + view_found = META_RENDERER_VIEW (stage_view); + } + } + + return view_found; +} + +static void +maybe_assign_primary_plane (MetaCompositor *compositor) +{ + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaWindowActor *window_actor; + MetaWindow *window; + MetaRendererView *view; + CoglFramebuffer *framebuffer; + CoglOnscreen *onscreen; + MetaSurfaceActor *surface_actor; + MetaSurfaceActorWayland *surface_actor_wayland; + g_autoptr (CoglScanout) scanout = NULL; + + if (meta_compositor_is_unredirect_inhibited (compositor)) + return; + + window_actor = meta_compositor_get_top_window_actor (compositor); + if (!window_actor) + return; + + if (meta_window_actor_effect_in_progress (window_actor)) + return; + + if (clutter_actor_has_transitions (CLUTTER_ACTOR (window_actor))) + return; + + if (clutter_actor_get_n_children (CLUTTER_ACTOR (window_actor)) != 1) + return; + + window = meta_window_actor_get_meta_window (window_actor); + if (!window) + return; + + view = get_window_view (renderer, window); + if (!view) + return; + + framebuffer = clutter_stage_view_get_framebuffer (CLUTTER_STAGE_VIEW (view)); + if (!cogl_is_onscreen (framebuffer)) + return; + + surface_actor = meta_window_actor_get_surface (window_actor); + if (!META_IS_SURFACE_ACTOR_WAYLAND (surface_actor)) + return; + + surface_actor_wayland = META_SURFACE_ACTOR_WAYLAND (surface_actor); + onscreen = COGL_ONSCREEN (framebuffer); + scanout = meta_surface_actor_wayland_try_acquire_scanout (surface_actor_wayland, + onscreen); + if (!scanout) + return; + + clutter_stage_view_assign_next_scanout (CLUTTER_STAGE_VIEW (view), scanout); +} + +static void +meta_compositor_native_pre_paint (MetaCompositor *compositor) +{ + MetaCompositorClass *parent_class; + + maybe_assign_primary_plane (compositor); + + parent_class = META_COMPOSITOR_CLASS (meta_compositor_native_parent_class); + parent_class->pre_paint (compositor); +} + +MetaCompositorNative * +meta_compositor_native_new (MetaDisplay *display) +{ + return g_object_new (META_TYPE_COMPOSITOR_NATIVE, + "display", display, + NULL); +} + +static void +meta_compositor_native_init (MetaCompositorNative *compositor_native) +{ +} + +static void +meta_compositor_native_class_init (MetaCompositorNativeClass *klass) +{ + MetaCompositorClass *compositor_class = META_COMPOSITOR_CLASS (klass); + + compositor_class->pre_paint = meta_compositor_native_pre_paint; +} diff --git a/src/compositor/meta-compositor-native.h b/src/compositor/meta-compositor-native.h new file mode 100644 index 000000000..d276a5905 --- /dev/null +++ b/src/compositor/meta-compositor-native.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 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. + * + */ + +#ifndef META_COMPOSITOR_NATIVE_H +#define META_COMPOSITOR_NATIVE_H + +#include "compositor/meta-compositor-server.h" + +#define META_TYPE_COMPOSITOR_NATIVE (meta_compositor_native_get_type ()) +G_DECLARE_FINAL_TYPE (MetaCompositorNative, meta_compositor_native, + META, COMPOSITOR_NATIVE, MetaCompositor) + +MetaCompositorNative * meta_compositor_native_new (MetaDisplay *display); + +#endif /* META_COMPOSITOR_NATIVE_H */ diff --git a/src/compositor/meta-compositor-server.c b/src/compositor/meta-compositor-server.c index 1e1d977d5..6bfe447cf 100644 --- a/src/compositor/meta-compositor-server.c +++ b/src/compositor/meta-compositor-server.c @@ -19,19 +19,17 @@ */ #include "config.h" +#include #include "compositor/meta-compositor-server.h" -struct _MetaCompositorServer -{ - MetaCompositor parent; -}; - G_DEFINE_TYPE (MetaCompositorServer, meta_compositor_server, META_TYPE_COMPOSITOR) -static void -meta_compositor_server_manage (MetaCompositor *compositor) +static gboolean +meta_compositor_server_manage (MetaCompositor *compositor, + GError **error) { + return TRUE; } static void diff --git a/src/compositor/meta-compositor-server.h b/src/compositor/meta-compositor-server.h index 8bff05e7b..7339105f5 100644 --- a/src/compositor/meta-compositor-server.h +++ b/src/compositor/meta-compositor-server.h @@ -24,8 +24,13 @@ #include "compositor/compositor-private.h" #define META_TYPE_COMPOSITOR_SERVER (meta_compositor_server_get_type ()) -G_DECLARE_FINAL_TYPE (MetaCompositorServer, meta_compositor_server, - META, COMPOSITOR_SERVER, MetaCompositor) +G_DECLARE_DERIVABLE_TYPE (MetaCompositorServer, meta_compositor_server, + META, COMPOSITOR_SERVER, MetaCompositor) + +struct _MetaCompositorServerClass +{ + MetaCompositorClass parent_class; +}; MetaCompositorServer * meta_compositor_server_new (MetaDisplay *display); diff --git a/src/compositor/meta-compositor-x11.c b/src/compositor/meta-compositor-x11.c index c3c96a5a1..c2ee7d745 100644 --- a/src/compositor/meta-compositor-x11.c +++ b/src/compositor/meta-compositor-x11.c @@ -154,15 +154,39 @@ determine_server_clock_source (MetaCompositorX11 *compositor_x11) compositor_x11->xserver_uses_monotonic_clock = FALSE; } -static void -meta_compositor_x11_manage (MetaCompositor *compositor) +static gboolean +meta_compositor_x11_manage (MetaCompositor *compositor, + GError **error) { MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); MetaDisplay *display = meta_compositor_get_display (compositor); - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); + MetaX11Display *x11_display = display->x11_display; + Display *xdisplay = meta_x11_display_get_xdisplay (x11_display); + int composite_version; MetaBackend *backend = meta_get_backend (); Window xwindow; + if (!META_X11_DISPLAY_HAS_COMPOSITE (x11_display) || + !META_X11_DISPLAY_HAS_DAMAGE (x11_display)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing required extension %s", + !META_X11_DISPLAY_HAS_COMPOSITE (x11_display) ? + "composite" : "damage"); + return FALSE; + } + + composite_version = ((x11_display->composite_major_version * 10) + + x11_display->composite_minor_version); + if (composite_version < 3) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "COMPOSITE extension 3.0 required (found %d.%d)", + x11_display->composite_major_version, + x11_display->composite_minor_version); + return FALSE; + } + determine_server_clock_source (compositor_x11); meta_x11_display_set_cm_selection (display->x11_display); @@ -204,6 +228,8 @@ meta_compositor_x11_manage (MetaCompositor *compositor) compositor_x11->have_x11_sync_object = meta_sync_ring_init (xdisplay); meta_compositor_redirect_x11_windows (META_COMPOSITOR (compositor)); + + return TRUE; } static void diff --git a/src/compositor/meta-later-private.h b/src/compositor/meta-later-private.h new file mode 100644 index 000000000..c8d0f80a8 --- /dev/null +++ b/src/compositor/meta-later-private.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020 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, see . + */ + +#ifndef META_LATER_PRIVATE_H +#define META_LATER_PRIVATE_H + +typedef struct _MetaLaters MetaLaters; +typedef struct _MetaCompositor MetaCompositor; + +MetaLaters * meta_laters_new (MetaCompositor *compositor); + +void meta_laters_free (MetaLaters *laters); + +#endif /* META_LATER_PRIVATE_H */ diff --git a/src/compositor/meta-later.c b/src/compositor/meta-later.c new file mode 100644 index 000000000..f51e43797 --- /dev/null +++ b/src/compositor/meta-later.c @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2005 Elijah Newren + * Copyright (C) 2020 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, see . + */ + +#include "config.h" + +#include "compositor/meta-later-private.h" + +#include "cogl/cogl.h" +#include "compositor/compositor-private.h" +#include "core/display-private.h" +#include "meta/meta-later.h" + +typedef struct _MetaLater +{ + unsigned int id; + unsigned int ref_count; + MetaLaterType when; + + GSourceFunc func; + gpointer user_data; + GDestroyNotify destroy_notify; + + guint source_id; + gboolean run_once; +} MetaLater; + +#define META_LATER_N_TYPES (META_LATER_IDLE + 1) + +struct _MetaLaters +{ + MetaCompositor *compositor; + + unsigned int last_later_id; + + GSList *laters[META_LATER_N_TYPES]; + + ClutterTimeline *timeline; + gulong pre_paint_handler_id; +}; + +static MetaLater * +meta_later_ref (MetaLater *later) +{ + later->ref_count++; + return later; +} + +static void +meta_later_unref (MetaLater *later) +{ + if (--later->ref_count == 0) + { + if (later->destroy_notify) + { + later->destroy_notify (later->user_data); + later->destroy_notify = NULL; + } + + g_slice_free (MetaLater, later); + } +} + +static void +meta_later_destroy (MetaLater *later) +{ + g_clear_handle_id (&later->source_id, g_source_remove); + later->func = NULL; + meta_later_unref (later); +} + +#ifdef COGL_HAS_TRACING +static const char * +later_type_to_string (MetaLaterType when) +{ + switch (when) + { + case META_LATER_RESIZE: + return "Later (resize)"; + case META_LATER_CALC_SHOWING: + return "Later (calc-showing)"; + case META_LATER_CHECK_FULLSCREEN: + return "Later (check-fullscreen)"; + case META_LATER_SYNC_STACK: + return "Later (sync-stack)"; + case META_LATER_BEFORE_REDRAW: + return "Later (before-redraw)"; + case META_LATER_IDLE: + return "Later (idle)"; + } + + return "unknown"; +} +#endif + +static gboolean +meta_later_invoke (MetaLater *later) +{ + COGL_TRACE_BEGIN_SCOPED (later, later_type_to_string (later->when)); + return later->func (later->user_data); +} + +static gboolean +remove_later_from_list (unsigned int later_id, + GSList **laters_list) +{ + GSList *l; + + for (l = *laters_list; l; l = l->next) + { + MetaLater *later = l->data; + + if (later->id == later_id) + { + *laters_list = g_slist_delete_link (*laters_list, l); + meta_later_destroy (later); + return TRUE; + } + } + + return FALSE; +} + +static void +run_repaint_laters (GSList **laters_list) +{ + g_autoptr (GSList) laters_copy = NULL; + GSList *l; + + for (l = *laters_list; l; l = l->next) + { + MetaLater *later = l->data; + + if (!later->source_id || + (later->when <= META_LATER_BEFORE_REDRAW && !later->run_once)) + laters_copy = g_slist_prepend (laters_copy, meta_later_ref (later)); + } + laters_copy = g_slist_reverse (laters_copy); + + for (l = laters_copy; l; l = l->next) + { + MetaLater *later = l->data; + + if (!later->func) + remove_later_from_list (later->id, laters_list); + else if (!meta_later_invoke (later)) + remove_later_from_list (later->id, laters_list); + + meta_later_unref (later); + } +} + +static void +on_pre_paint (MetaCompositor *compositor, + MetaLaters *laters) +{ + unsigned int i; + GSList *l; + gboolean keep_timeline_running = FALSE; + + for (i = 0; i < G_N_ELEMENTS (laters->laters); i++) + run_repaint_laters (&laters->laters[i]); + + for (i = 0; i < G_N_ELEMENTS (laters->laters); i++) + { + for (l = laters->laters[i]; l; l = l->next) + { + MetaLater *later = l->data; + + if (!later->source_id) + keep_timeline_running = TRUE; + } + } + + if (!keep_timeline_running) + clutter_timeline_stop (laters->timeline); +} + +static void +ensure_timeline_running (MetaLaters *laters) +{ + clutter_timeline_start (laters->timeline); +} + +static gboolean +invoke_later_idle (gpointer data) +{ + MetaLater *later = data; + + if (!later->func (later->user_data)) + { + meta_later_remove (later->id); + return FALSE; + } + else + { + later->run_once = TRUE; + return TRUE; + } +} + +static unsigned int +meta_laters_add (MetaLaters *laters, + MetaLaterType when, + GSourceFunc func, + gpointer user_data, + GDestroyNotify notify) +{ + MetaLater *later = g_slice_new0 (MetaLater); + + later->id = ++laters->last_later_id; + later->ref_count = 1; + later->when = when; + later->func = func; + later->user_data = user_data; + later->destroy_notify = notify; + + laters->laters[when] = g_slist_prepend (laters->laters[when], later); + + switch (when) + { + case META_LATER_RESIZE: + later->source_id = g_idle_add_full (META_PRIORITY_RESIZE, + invoke_later_idle, + later, NULL); + g_source_set_name_by_id (later->source_id, "[muffin] invoke_later_idle"); + ensure_timeline_running (laters); + break; + case META_LATER_CALC_SHOWING: + case META_LATER_CHECK_FULLSCREEN: + case META_LATER_SYNC_STACK: + case META_LATER_BEFORE_REDRAW: + ensure_timeline_running (laters); + break; + case META_LATER_IDLE: + later->source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, + invoke_later_idle, + later, NULL); + g_source_set_name_by_id (later->source_id, "[muffin] invoke_later_idle"); + break; + } + + return later->id; +} + +/** + * meta_later_add: + * @when: enumeration value determining the phase at which to run the callback + * @func: callback to run later + * @data: data to pass to the callback + * @notify: function to call to destroy @data when it is no longer in use, or %NULL + * + * Sets up a callback to be called at some later time. @when determines the + * particular later occasion at which it is called. This is much like g_idle_add(), + * except that the functions interact properly with clutter event handling. + * If a "later" function is added from a clutter event handler, and is supposed + * to be run before the stage is redrawn, it will be run before that redraw + * of the stage, not the next one. + * + * Return value: an integer ID (guaranteed to be non-zero) that can be used + * to cancel the callback and prevent it from being run. + */ +unsigned int +meta_later_add (MetaLaterType when, + GSourceFunc func, + gpointer data, + GDestroyNotify notify) +{ + MetaDisplay *display = meta_get_display (); + MetaCompositor *compositor = display->compositor; + + return meta_laters_add (meta_compositor_get_laters (compositor), + when, func, data, notify); +} + +static void +meta_laters_remove (MetaLaters *laters, + unsigned int later_id) +{ + unsigned int i; + + for (i = 0; i < G_N_ELEMENTS (laters->laters); i++) + { + if (remove_later_from_list (later_id, &laters->laters[i])) + return; + } +} + +/** + * meta_later_remove: + * @later_id: the integer ID returned from meta_later_add() + * + * Removes a callback added with meta_later_add() + */ +void +meta_later_remove (unsigned int later_id) +{ + MetaDisplay *display = meta_get_display (); + MetaCompositor *compositor = display->compositor; + + if (!compositor) + return; + + meta_laters_remove (meta_compositor_get_laters (compositor), later_id); +} + +MetaLaters * +meta_laters_new (MetaCompositor *compositor) +{ + MetaLaters *laters; + + laters = g_new0 (MetaLaters, 1); + laters->compositor = compositor; + laters->timeline = clutter_timeline_new (G_MAXUINT); + + laters->pre_paint_handler_id = g_signal_connect (compositor, "pre-paint", + G_CALLBACK (on_pre_paint), + laters); + + return laters; +} + +void +meta_laters_free (MetaLaters *laters) +{ + unsigned int i; + + for (i = 0; i < G_N_ELEMENTS (laters->laters); i++) + g_slist_free_full (laters->laters[i], (GDestroyNotify) meta_later_unref); + + g_clear_object (&laters->timeline); + g_clear_signal_handler (&laters->pre_paint_handler_id, laters->compositor); + g_free (laters); +} diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c index e8d946e98..ce50da162 100644 --- a/src/compositor/meta-surface-actor-wayland.c +++ b/src/compositor/meta-surface-actor-wayland.c @@ -71,6 +71,21 @@ meta_surface_actor_wayland_is_opaque (MetaSurfaceActor *actor) return meta_shaped_texture_is_opaque (stex); } +CoglScanout * +meta_surface_actor_wayland_try_acquire_scanout (MetaSurfaceActorWayland *self, + CoglOnscreen *onscreen) +{ + MetaWaylandSurface *surface; + CoglScanout *scanout; + + surface = meta_surface_actor_wayland_get_surface (self); + scanout = meta_wayland_surface_try_acquire_scanout (surface, onscreen); + if (!scanout) + return NULL; + + return scanout; +} + static void meta_surface_actor_wayland_dispose (GObject *object) { diff --git a/src/compositor/meta-surface-actor-wayland.h b/src/compositor/meta-surface-actor-wayland.h index e1ad843f7..241217265 100644 --- a/src/compositor/meta-surface-actor-wayland.h +++ b/src/compositor/meta-surface-actor-wayland.h @@ -52,6 +52,10 @@ void meta_surface_actor_wayland_get_subsurface_rect (MetaSurfaceActorWayland *se void meta_surface_actor_wayland_add_frame_callbacks (MetaSurfaceActorWayland *self, struct wl_list *frame_callbacks); +CoglScanout * meta_surface_actor_wayland_try_acquire_scanout (MetaSurfaceActorWayland *self, + CoglOnscreen *onscreen); + G_END_DECLS #endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */ + diff --git a/src/compositor/meta-surface-actor-x11.c b/src/compositor/meta-surface-actor-x11.c index 7b2a742fd..3b1a250d9 100644 --- a/src/compositor/meta-surface-actor-x11.c +++ b/src/compositor/meta-surface-actor-x11.c @@ -254,33 +254,14 @@ meta_surface_actor_x11_is_opaque (MetaSurfaceActor *actor) gboolean meta_surface_actor_x11_should_unredirect (MetaSurfaceActorX11 *self) { - MetaWindow *window = self->window; - - if (meta_window_requested_dont_bypass_compositor (window)) - return FALSE; - - if (window->opacity != 0xFF) - return FALSE; - - if (window->shape_region != NULL) - return FALSE; - - if (!meta_window_is_monitor_sized (window)) - return FALSE; - - if (meta_window_requested_bypass_compositor (window)) - return TRUE; - if (!meta_surface_actor_x11_is_opaque (META_SURFACE_ACTOR (self))) return FALSE; - if (meta_window_is_override_redirect (window)) - return TRUE; - - if (self->does_full_damage && meta_prefs_get_unredirect_fullscreen_windows ()) - return TRUE; + if (!self->does_full_damage && + !meta_window_is_override_redirect (self->window)) + return FALSE; - return FALSE; + return TRUE; } static void diff --git a/src/compositor/meta-window-actor-x11.c b/src/compositor/meta-window-actor-x11.c index 0952635f0..fd1293e7d 100644 --- a/src/compositor/meta-window-actor-x11.c +++ b/src/compositor/meta-window-actor-x11.c @@ -39,6 +39,7 @@ #include "meta/meta-window-actor.h" #include "meta/meta-x11-errors.h" #include "meta/window.h" +#include "x11/window-x11.h" #include "x11/meta-x11-display-private.h" #include "x11/window-x11.h" @@ -544,12 +545,18 @@ has_shadow (MetaWindowActorX11 *actor_x11) gboolean meta_window_actor_x11_should_unredirect (MetaWindowActorX11 *actor_x11) { + MetaWindow *window = + meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); MetaSurfaceActor *surface; MetaSurfaceActorX11 *surface_x11; if (meta_window_actor_is_destroyed (META_WINDOW_ACTOR (actor_x11))) return FALSE; + if (!meta_window_x11_can_unredirect (window_x11)) + return FALSE; + surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); if (!surface) return FALSE; diff --git a/src/core/display.c b/src/core/display.c index f15f26fae..1585bd20f 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -51,6 +51,7 @@ #include "backends/x11/meta-backend-x11.h" #include "backends/x11/meta-event-x11.h" #include "backends/x11/cm/meta-backend-x11-cm.h" +#include "backends/x11/nested/meta-backend-x11-nested.h" #include "clutter/x11/clutter-x11.h" #include "compositor/compositor-private.h" #include "compositor/meta-compositor-x11.h" @@ -81,6 +82,7 @@ #include "x11/xprops.h" #ifdef HAVE_WAYLAND +#include "compositor/meta-compositor-native.h" #include "compositor/meta-compositor-server.h" #include "wayland/meta-xwayland-private.h" #include "wayland/meta-wayland-tablet-seat.h" @@ -620,44 +622,16 @@ static MetaCompositor * create_compositor (MetaDisplay *display) { #ifdef HAVE_WAYLAND - if (meta_is_wayland_compositor ()) + MetaBackend *backend = meta_get_backend (); + +#ifdef HAVE_NATIVE_BACKEND + if (META_IS_BACKEND_NATIVE (backend)) + return META_COMPOSITOR (meta_compositor_native_new (display)); +#endif + if (META_IS_BACKEND_X11_NESTED (backend)) return META_COMPOSITOR (meta_compositor_server_new (display)); - else #endif - return META_COMPOSITOR (meta_compositor_x11_new (display)); -} - -static void -enable_compositor (MetaDisplay *display) -{ - MetaX11Display *x11_display = display->x11_display; - - if (x11_display) - { - if (!META_X11_DISPLAY_HAS_COMPOSITE (x11_display) || - !META_X11_DISPLAY_HAS_DAMAGE (x11_display)) - { - meta_fatal ("Missing %s extension required for compositing", - !META_X11_DISPLAY_HAS_COMPOSITE (x11_display) ? - "composite" : "damage"); - return; - } - - int version = (x11_display->composite_major_version * 10) + - x11_display->composite_minor_version; - if (version < 3) - { - meta_fatal ("Your version of COMPOSITE (%d.%d) is too old. Version 3.0 or later required.", - x11_display->composite_major_version, - x11_display->composite_minor_version); - return; - } - } - - if (!display->compositor) - display->compositor = create_compositor (display); - - meta_compositor_manage (display->compositor); + return META_COMPOSITOR (meta_compositor_x11_new (display)); } static void @@ -933,6 +907,8 @@ meta_display_open (void) g_signal_connect (settings, "ui-scaling-factor-changed", G_CALLBACK (on_ui_scaling_factor_changed), display); + display->compositor = create_compositor (display); + meta_display_set_cursor (display, META_CURSOR_DEFAULT); display->stack = meta_stack_new (display); @@ -970,7 +946,6 @@ meta_display_open (void) display->last_focus_time = timestamp; display->last_user_time = timestamp; - display->compositor = NULL; if (!meta_is_wayland_compositor ()) meta_prop_get_window (display->x11_display, @@ -978,7 +953,11 @@ meta_display_open (void) display->x11_display->atom__NET_ACTIVE_WINDOW, &old_active_xwindow); - enable_compositor (display); + if (!meta_compositor_do_manage (display->compositor, &error)) + { + g_error ("Compositor failed to manage display: %s", + error->message); + } if (display->x11_display) { diff --git a/src/core/util.c b/src/core/util.c index 3a7f94570..32c90d409 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -50,9 +50,6 @@ meta_topic_real_valist (MetaDebugTopic topic, va_list args) G_GNUC_PRINTF(2, 0); #endif -static gboolean -meta_later_remove_from_list (guint later_id, GSList **laters_list); - static gint verbose_topics = 0; static gboolean is_debugging = FALSE; static gboolean replace_current = FALSE; @@ -704,288 +701,6 @@ meta_show_dialog (const char *type, return child_pid; } -/*************************************************************************** - * Later functions: like idles but integrated with the Clutter repaint loop - ***************************************************************************/ - -static guint last_later_id = 0; - -typedef struct -{ - guint id; - guint ref_count; - MetaLaterType when; - GSourceFunc func; - gpointer data; - GDestroyNotify notify; - int source; - gboolean run_once; -} MetaLater; - -static GSList *laters[] = { - NULL, /* META_LATER_RESIZE */ - NULL, /* META_LATER_CALC_SHOWING */ - NULL, /* META_LATER_CHECK_FULLSCREEN */ - NULL, /* META_LATER_SYNC_STACK */ - NULL, /* META_LATER_BEFORE_REDRAW */ - NULL, /* META_LATER_IDLE */ -}; -/* This is a dummy timeline used to get the Clutter master clock running */ -static ClutterTimeline *later_timeline; -static guint later_repaint_func = 0; - -static void ensure_later_repaint_func (void); - -static void -unref_later (MetaLater *later) -{ - if (--later->ref_count == 0) - { - if (later->notify) - { - later->notify (later->data); - later->notify = NULL; - } - g_slice_free (MetaLater, later); - } -} - -static void -destroy_later (MetaLater *later) -{ - g_clear_handle_id (&later->source, g_source_remove); - later->func = NULL; - unref_later (later); -} - -#ifdef COGL_HAS_TRACING -static const char * -later_type_to_string (MetaLaterType when) -{ - switch (when) - { - case META_LATER_RESIZE: - return "Later (resize)"; - case META_LATER_CALC_SHOWING: - return "Later (calc-showing)"; - case META_LATER_CHECK_FULLSCREEN: - return "Later (check-fullscreen)"; - case META_LATER_SYNC_STACK: - return "Later (sync-stack)"; - case META_LATER_BEFORE_REDRAW: - return "Later (before-redraw)"; - case META_LATER_IDLE: - return "Later (idle)"; - } - - return "unknown"; -} -#endif - -static gboolean -call_later_func (MetaLater *later) -{ - COGL_TRACE_BEGIN_SCOPED (later, later_type_to_string (later->when)); - return later->func (later->data); -} - -static void -run_repaint_laters (GSList **laters_list) -{ - GSList *laters_copy; - GSList *l; - - laters_copy = NULL; - for (l = *laters_list; l; l = l->next) - { - MetaLater *later = l->data; - if (later->source == 0 || - (later->when <= META_LATER_BEFORE_REDRAW && !later->run_once)) - { - later->ref_count++; - laters_copy = g_slist_prepend (laters_copy, later); - } - } - laters_copy = g_slist_reverse (laters_copy); - - for (l = laters_copy; l; l = l->next) - { - MetaLater *later = l->data; - - if (!later->func || !call_later_func (later)) - meta_later_remove_from_list (later->id, laters_list); - unref_later (later); - } - - g_slist_free (laters_copy); -} - -static gboolean -run_all_repaint_laters (gpointer data) -{ - guint i; - GSList *l; - gboolean keep_timeline_running = FALSE; - - for (i = 0; i < G_N_ELEMENTS (laters); i++) - { - run_repaint_laters (&laters[i]); - } - - for (i = 0; i < G_N_ELEMENTS (laters); i++) - { - for (l = laters[i]; l; l = l->next) - { - MetaLater *later = l->data; - - if (later->source == 0) - keep_timeline_running = TRUE; - } - } - - if (!keep_timeline_running) - clutter_timeline_stop (later_timeline); - - /* Just keep the repaint func around - it's cheap if the lists are empty */ - return TRUE; -} - -static void -ensure_later_repaint_func (void) -{ - if (!later_timeline) - later_timeline = clutter_timeline_new (G_MAXUINT); - - if (later_repaint_func == 0) - later_repaint_func = clutter_threads_add_repaint_func (run_all_repaint_laters, - NULL, NULL); - - /* Make sure the repaint function gets run */ - clutter_timeline_start (later_timeline); -} - -static gboolean -call_idle_later (gpointer data) -{ - MetaLater *later = data; - - if (!later->func (later->data)) - { - meta_later_remove (later->id); - return FALSE; - } - else - { - later->run_once = TRUE; - return TRUE; - } -} - -/** - * meta_later_add: - * @when: enumeration value determining the phase at which to run the callback - * @func: callback to run later - * @data: data to pass to the callback - * @notify: function to call to destroy @data when it is no longer in use, or %NULL - * - * Sets up a callback to be called at some later time. @when determines the - * particular later occasion at which it is called. This is much like g_idle_add(), - * except that the functions interact properly with clutter event handling. - * If a "later" function is added from a clutter event handler, and is supposed - * to be run before the stage is redrawn, it will be run before that redraw - * of the stage, not the next one. - * - * Return value: an integer ID (guaranteed to be non-zero) that can be used - * to cancel the callback and prevent it from being run. - */ -guint -meta_later_add (MetaLaterType when, - GSourceFunc func, - gpointer data, - GDestroyNotify notify) -{ - MetaLater *later = g_slice_new0 (MetaLater); - - later->id = ++last_later_id; - later->ref_count = 1; - later->when = when; - later->func = func; - later->data = data; - later->notify = notify; - - laters[when] = g_slist_prepend (laters[when], later); - - switch (when) - { - case META_LATER_RESIZE: - /* We add this one two ways - as a high-priority idle and as a - * repaint func. If we are in a clutter event callback, the repaint - * handler will get hit first, and we'll take care of this function - * there so it gets called before the stage is redrawn, even if - * we haven't gotten back to the main loop. Otherwise, the idle - * handler will get hit first and we want to call this function - * there so it will happen before GTK+ repaints. - */ - later->source = g_idle_add_full (META_PRIORITY_RESIZE, call_idle_later, later, NULL); - g_source_set_name_by_id (later->source, "[muffin] call_idle_later"); - ensure_later_repaint_func (); - break; - case META_LATER_CALC_SHOWING: - case META_LATER_CHECK_FULLSCREEN: - case META_LATER_SYNC_STACK: - case META_LATER_BEFORE_REDRAW: - ensure_later_repaint_func (); - break; - case META_LATER_IDLE: - later->source = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, call_idle_later, later, NULL); - g_source_set_name_by_id (later->source, "[muffin] call_idle_later"); - break; - } - - return later->id; -} - -static gboolean -meta_later_remove_from_list (guint later_id, GSList **laters_list) -{ - GSList *l; - - for (l = *laters_list; l; l = l->next) - { - MetaLater *later = l->data; - - if (later->id == later_id) - { - *laters_list = g_slist_delete_link (*laters_list, l); - /* If this was a "repaint func" later, we just let the - * repaint func run and get removed - */ - destroy_later (later); - return TRUE; - } - } - - return FALSE; -} - -/** - * meta_later_remove: - * @later_id: the integer ID returned from meta_later_add() - * - * Removes a callback added with meta_later_add() - */ -void -meta_later_remove (guint later_id) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (laters); i++) - { - if (meta_later_remove_from_list (later_id, &laters[i])) - return; - } -} - MetaLocaleDirection meta_get_locale_direction (void) { diff --git a/src/core/window-private.h b/src/core/window-private.h index 6a41f3767..a4c95ad4e 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -65,13 +65,6 @@ typedef enum #define NUMBER_OF_QUEUES 3 -typedef enum -{ - _NET_WM_BYPASS_COMPOSITOR_HINT_AUTO = 0, - _NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1, - _NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2, -} MetaBypassCompositorHintValue; - typedef enum { META_MOVE_RESIZE_CONFIGURE_REQUEST = 1 << 0, @@ -550,9 +543,6 @@ struct _MetaWindow // MetaWindow *tile_match; - /* Bypass compositor hints */ - guint bypass_compositor; - struct { MetaPlacementRule *rule; MetaPlacementState state; diff --git a/src/core/window.c b/src/core/window.c index ac8fc69c0..62baa0439 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -3165,30 +3165,6 @@ meta_window_is_on_primary_monitor (MetaWindow *window) return window->monitor->is_primary; } -/** - * meta_window_requested_bypass_compositor: - * @window: a #MetaWindow - * - * Return value: %TRUE if the window requested to bypass the compositor - */ -gboolean -meta_window_requested_bypass_compositor (MetaWindow *window) -{ - return window->bypass_compositor == _NET_WM_BYPASS_COMPOSITOR_HINT_ON; -} - -/** - * meta_window_requested_dont_bypass_compositor: - * @window: a #MetaWindow - * - * Return value: %TRUE if the window requested to opt out of unredirecting - */ -gboolean -meta_window_requested_dont_bypass_compositor (MetaWindow *window) -{ - return window->bypass_compositor == _NET_WM_BYPASS_COMPOSITOR_HINT_OFF; -} - static void get_default_tile_fractions (MetaTileMode for_mode, double *hfraction, diff --git a/src/meson.build b/src/meson.build index 10fb80dc5..904cec7b3 100644 --- a/src/meson.build +++ b/src/meson.build @@ -290,6 +290,8 @@ muffin_sources = [ 'compositor/meta-background-group.c', 'compositor/meta-background-image.c', 'compositor/meta-background-private.h', + 'compositor/meta-compositor-server.c', + 'compositor/meta-compositor-server.h', 'compositor/meta-compositor-x11.c', 'compositor/meta-compositor-x11.h', 'compositor/meta-cullable.c', @@ -299,6 +301,7 @@ muffin_sources = [ 'compositor/meta-dnd.c', 'compositor/meta-feedback-actor.c', 'compositor/meta-feedback-actor-private.h', + 'compositor/meta-later.c', 'compositor/meta-module.c', 'compositor/meta-module.h', 'compositor/meta-plugin.c', @@ -479,8 +482,6 @@ if have_wayland 'compositor/meta-surface-actor-wayland.h', 'compositor/meta-window-actor-wayland.c', 'compositor/meta-window-actor-wayland.h', - 'compositor/meta-compositor-server.c', - 'compositor/meta-compositor-server.h', 'wayland/meta-cursor-sprite-wayland.c', 'wayland/meta-cursor-sprite-wayland.h', 'wayland/meta-pointer-confinement-wayland.c', @@ -690,6 +691,8 @@ if have_native_backend 'backends/native/meta-virtual-input-device-native.h', 'backends/native/meta-xkb-utils.c', 'backends/native/meta-xkb-utils.h', + 'compositor/meta-compositor-native.c', + 'compositor/meta-compositor-native.h', ] endif diff --git a/src/meta/meson.build b/src/meta/meson.build index e3b18daf4..d895e88dc 100644 --- a/src/meta/meson.build +++ b/src/meta/meson.build @@ -19,6 +19,7 @@ muffin_public_headers = [ 'meta-idle-monitor.h', 'meta-inhibit-shortcuts-dialog.h', 'meta-launch-context.h', + 'meta-later.h', 'meta-monitor-manager.h', 'meta-plugin.h', 'meta-remote-access-controller.h', diff --git a/src/meta/meta-later.h b/src/meta/meta-later.h new file mode 100644 index 000000000..25b3f91a7 --- /dev/null +++ b/src/meta/meta-later.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2005 Elijah Newren + * Copyright (C) 2020 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, see . + */ + +#ifndef META_LATER_H +#define META_LATER_H + +/** + * MetaLaterType: + * @META_LATER_RESIZE: call in a resize processing phase that is done + * before GTK+ repainting (including window borders) is done. + * @META_LATER_CALC_SHOWING: used by Mutter to compute which windows should be mapped + * @META_LATER_CHECK_FULLSCREEN: used by Mutter to see if there's a fullscreen window + * @META_LATER_SYNC_STACK: used by Mutter to send it's idea of the stacking order to the server + * @META_LATER_BEFORE_REDRAW: call before the stage is redrawn + * @META_LATER_IDLE: call at a very low priority (can be blocked + * by running animations or redrawing applications) + **/ +typedef enum +{ + META_LATER_RESIZE, + META_LATER_CALC_SHOWING, + META_LATER_CHECK_FULLSCREEN, + META_LATER_SYNC_STACK, + META_LATER_BEFORE_REDRAW, + META_LATER_IDLE +} MetaLaterType; + +META_EXPORT +guint meta_later_add (MetaLaterType when, + GSourceFunc func, + gpointer data, + GDestroyNotify notify); + +META_EXPORT +void meta_later_remove (guint later_id); + +#endif /* META_LATER_H */ diff --git a/src/meta/util.h b/src/meta/util.h index 323898ee8..ea24b946d 100644 --- a/src/meta/util.h +++ b/src/meta/util.h @@ -27,6 +27,7 @@ #include #include +#include META_EXPORT gboolean meta_is_verbose (void); @@ -186,36 +187,6 @@ GPid meta_show_dialog (const char *type, #endif /* !WITH_VERBOSE_MODE */ -/** - * MetaLaterType: - * @META_LATER_RESIZE: call in a resize processing phase that is done - * before GTK+ repainting (including window borders) is done. - * @META_LATER_CALC_SHOWING: used by Mutter to compute which windows should be mapped - * @META_LATER_CHECK_FULLSCREEN: used by Mutter to see if there's a fullscreen window - * @META_LATER_SYNC_STACK: used by Mutter to send it's idea of the stacking order to the server - * @META_LATER_BEFORE_REDRAW: call before the stage is redrawn - * @META_LATER_IDLE: call at a very low priority (can be blocked - * by running animations or redrawing applications) - **/ -typedef enum -{ - META_LATER_RESIZE, - META_LATER_CALC_SHOWING, - META_LATER_CHECK_FULLSCREEN, - META_LATER_SYNC_STACK, - META_LATER_BEFORE_REDRAW, - META_LATER_IDLE -} MetaLaterType; - -META_EXPORT -guint meta_later_add (MetaLaterType when, - GSourceFunc func, - gpointer data, - GDestroyNotify notify); - -META_EXPORT -void meta_later_remove (guint later_id); - typedef enum { META_LOCALE_DIRECTION_LTR, diff --git a/src/meta/window.h b/src/meta/window.h index 252129f6f..04b5a89a3 100644 --- a/src/meta/window.h +++ b/src/meta/window.h @@ -283,12 +283,6 @@ gboolean meta_window_is_monitor_sized (MetaWindow *window); META_EXPORT gboolean meta_window_is_on_primary_monitor (MetaWindow *window); -META_EXPORT -gboolean meta_window_requested_bypass_compositor (MetaWindow *window); - -META_EXPORT -gboolean meta_window_requested_dont_bypass_compositor (MetaWindow *window); - META_EXPORT gboolean meta_window_get_icon_geometry (MetaWindow *window, MetaRectangle *rect); diff --git a/src/ui/frames.c b/src/ui/frames.c index 3c076b691..b49358847 100644 --- a/src/ui/frames.c +++ b/src/ui/frames.c @@ -421,7 +421,7 @@ meta_ui_frame_calc_geometry (MetaUIFrame *frame, MetaFrameType type; MetaButtonLayout button_layout; MetaWindowX11 *window_x11 = META_WINDOW_X11 (frame->meta_window); - MetaWindowX11Private *priv = window_x11->priv; + MetaRectangle client_rect; flags = meta_frame_get_flags (frame->meta_window->frame); type = meta_window_get_frame_type (frame->meta_window); @@ -430,13 +430,15 @@ meta_ui_frame_calc_geometry (MetaUIFrame *frame, meta_prefs_get_button_layout (&button_layout); + client_rect = meta_window_x11_get_client_rect (window_x11); + meta_theme_calc_geometry (meta_theme_get_default (), frame->style_info, type, frame->text_height, flags, - priv->client_rect.width, - priv->client_rect.height, + client_rect.width, + client_rect.height, &button_layout, fgeom); } @@ -1657,7 +1659,7 @@ meta_ui_frame_paint (MetaUIFrame *frame, int button_type = -1; MetaButtonLayout button_layout; MetaWindowX11 *window_x11 = META_WINDOW_X11 (frame->meta_window); - MetaWindowX11Private *priv = window_x11->priv; + MetaRectangle client_rect; for (i = 0; i < META_BUTTON_TYPE_LAST; i++) button_states[i] = META_BUTTON_STATE_NORMAL; @@ -1695,13 +1697,15 @@ meta_ui_frame_paint (MetaUIFrame *frame, meta_prefs_get_button_layout (&button_layout); + client_rect = meta_window_x11_get_client_rect (window_x11); + meta_theme_draw_frame (meta_theme_get_default (), frame->style_info, cr, type, flags, - priv->client_rect.width, - priv->client_rect.height, + client_rect.width, + client_rect.height, frame->text_layout, frame->text_height, &button_layout, diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c index f4b958673..37d3d3073 100644 --- a/src/wayland/meta-wayland-actor-surface.c +++ b/src/wayland/meta-wayland-actor-surface.c @@ -181,7 +181,7 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor surface_actor = priv->actor; stex = meta_surface_actor_get_texture (surface_actor); - buffer = surface->buffer_ref.buffer; + buffer = surface->buffer_ref->buffer; if (buffer) { CoglSnippet *snippet; diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c index 6236579e7..ccf7e54bc 100644 --- a/src/wayland/meta-wayland-buffer.c +++ b/src/wayland/meta-wayland-buffer.c @@ -58,6 +58,11 @@ #include "meta/util.h" #include "wayland/meta-wayland-dma-buf.h" +#ifdef HAVE_NATIVE_BACKEND +#include "backends/native/meta-drm-buffer-gbm.h" +#include "backends/native/meta-renderer-native.h" +#endif + #ifndef DRM_FORMAT_MOD_INVALID #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) #endif @@ -577,6 +582,93 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer, } } +static CoglScanout * +try_acquire_egl_image_scanout (MetaWaylandBuffer *buffer, + CoglOnscreen *onscreen) +{ + #ifdef HAVE_NATIVE_BACKEND + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); + MetaGpuKms *gpu_kms; + struct gbm_device *gbm_device; + struct gbm_bo *gbm_bo; + uint32_t drm_format; + uint64_t drm_modifier; + uint32_t stride; + MetaDrmBufferGbm *fb; + g_autoptr (GError) error = NULL; + + gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native); + gbm_device = meta_gbm_device_from_gpu (gpu_kms); + + gbm_bo = gbm_bo_import (gbm_device, + GBM_BO_IMPORT_WL_BUFFER, buffer->resource, + GBM_BO_USE_SCANOUT); + if (!gbm_bo) + return NULL; + + drm_format = gbm_bo_get_format (gbm_bo); + drm_modifier = gbm_bo_get_modifier (gbm_bo); + stride = gbm_bo_get_stride (gbm_bo); + if (!meta_onscreen_native_is_buffer_scanout_compatible (onscreen, + drm_format, + drm_modifier, + stride)) + { + gbm_bo_destroy (gbm_bo); + return NULL; + } + + fb = meta_drm_buffer_gbm_new_take (gpu_kms, gbm_bo, + drm_modifier != DRM_FORMAT_MOD_INVALID, + &error); + if (!fb) + { + g_debug ("Failed to create scanout buffer: %s", error->message); + gbm_bo_destroy (gbm_bo); + return NULL; + } + + return COGL_SCANOUT (fb); +#else + return NULL; +#endif +} + +CoglScanout * +meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer, + CoglOnscreen *onscreen) +{ + switch (buffer->type) + { + case META_WAYLAND_BUFFER_TYPE_SHM: + return NULL; + case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE: + return try_acquire_egl_image_scanout (buffer, onscreen); + #ifdef HAVE_WAYLAND_EGLSTREAM + case META_WAYLAND_BUFFER_TYPE_EGL_STREAM: + return NULL; + #endif + case META_WAYLAND_BUFFER_TYPE_DMA_BUF: + { + MetaWaylandDmaBufBuffer *dma_buf; + + dma_buf = meta_wayland_dma_buf_from_buffer (buffer); + if (!dma_buf) + return NULL; + + return meta_wayland_dma_buf_try_acquire_scanout (dma_buf, onscreen); + } + case META_WAYLAND_BUFFER_TYPE_UNKNOWN: + g_warn_if_reached (); + return NULL; + } + + g_assert_not_reached (); + return NULL; +} + static void meta_wayland_buffer_finalize (GObject *object) { diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h index 4a503b183..0e579fa11 100644 --- a/src/wayland/meta-wayland-buffer.h +++ b/src/wayland/meta-wayland-buffer.h @@ -89,4 +89,7 @@ void meta_wayland_buffer_process_damage (MetaWaylandBuff CoglTexture *texture, cairo_region_t *region); +CoglScanout * meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer, + CoglOnscreen *onscreen); + #endif /* META_WAYLAND_BUFFER_H */ diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c index 206605d27..c986913e0 100644 --- a/src/wayland/meta-wayland-dma-buf.c +++ b/src/wayland/meta-wayland-dma-buf.c @@ -51,6 +51,11 @@ #include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-versions.h" +#ifdef HAVE_NATIVE_BACKEND +#include "backends/native/meta-drm-buffer-gbm.h" +#include "backends/native/meta-renderer-native.h" +#endif + #include "linux-dmabuf-unstable-v1-server-protocol.h" #ifndef DRM_FORMAT_MOD_INVALID @@ -184,6 +189,122 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, return TRUE; } +#ifdef HAVE_NATIVE_BACKEND +static struct gbm_bo * +import_scanout_gbm_bo (MetaWaylandDmaBufBuffer *dma_buf, + MetaGpuKms *gpu_kms, + int n_planes, + gboolean *use_modifier) +{ + struct gbm_device *gbm_device; + + gbm_device = meta_gbm_device_from_gpu (gpu_kms); + + if (dma_buf->drm_modifier != DRM_FORMAT_MOD_INVALID || + n_planes > 1 || + dma_buf->offsets[0] > 0) + { + struct gbm_import_fd_modifier_data import_with_modifier; + + import_with_modifier = (struct gbm_import_fd_modifier_data) { + .width = dma_buf->width, + .height = dma_buf->height, + .format = dma_buf->drm_format, + .num_fds = n_planes, + .modifier = dma_buf->drm_modifier, + }; + memcpy (import_with_modifier.fds, + dma_buf->fds, + sizeof (dma_buf->fds)); + memcpy (import_with_modifier.strides, + dma_buf->strides, + sizeof (import_with_modifier.strides)); + memcpy (import_with_modifier.offsets, + dma_buf->offsets, + sizeof (import_with_modifier.offsets)); + + *use_modifier = TRUE; + return gbm_bo_import (gbm_device, GBM_BO_IMPORT_FD_MODIFIER, + &import_with_modifier, + GBM_BO_USE_SCANOUT); + } + else + { + struct gbm_import_fd_data import_legacy; + + import_legacy = (struct gbm_import_fd_data) { + .width = dma_buf->width, + .height = dma_buf->height, + .format = dma_buf->drm_format, + .stride = dma_buf->strides[0], + .fd = dma_buf->fds[0], + }; + + *use_modifier = FALSE; + return gbm_bo_import (gbm_device, GBM_BO_IMPORT_FD, + &import_legacy, + GBM_BO_USE_SCANOUT); + } +} +#endif + +CoglScanout * +meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf, + CoglOnscreen *onscreen) +{ + #ifdef HAVE_NATIVE_BACKEND + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); + MetaGpuKms *gpu_kms; + int n_planes; + uint32_t drm_format; + uint64_t drm_modifier; + uint32_t stride; + struct gbm_bo *gbm_bo; + gboolean use_modifier; + g_autoptr (GError) error = NULL; + MetaDrmBufferGbm *fb; + + for (n_planes = 0; n_planes < META_WAYLAND_DMA_BUF_MAX_FDS; n_planes++) + { + if (dma_buf->fds[n_planes] < 0) + break; + } + + drm_format = dma_buf->drm_format; + drm_modifier = dma_buf->drm_modifier; + stride = dma_buf->strides[0]; + if (!meta_onscreen_native_is_buffer_scanout_compatible (onscreen, + drm_format, + drm_modifier, + stride)) + return NULL; + + gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native); + gbm_bo = import_scanout_gbm_bo (dma_buf, gpu_kms, n_planes, &use_modifier); + if (!gbm_bo) + { + g_debug ("Failed to import scanout gbm_bo: %s", g_strerror (errno)); + return NULL; + } + + fb = meta_drm_buffer_gbm_new_take (gpu_kms, gbm_bo, + use_modifier, + &error); + if (!fb) + { + g_debug ("Failed to create scanout buffer: %s", error->message); + gbm_bo_destroy (gbm_bo); + return NULL; + } + + return COGL_SCANOUT (fb); +#else + return NULL; +#endif +} + static void buffer_params_add (struct wl_client *client, struct wl_resource *resource, @@ -288,9 +409,12 @@ static const struct wl_buffer_interface dma_buf_buffer_impl = MetaWaylandDmaBufBuffer * meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer) { + if (!buffer->resource) + return NULL; + if (wl_resource_instance_of (buffer->resource, &wl_buffer_interface, &dma_buf_buffer_impl)) - return wl_resource_get_user_data (buffer->resource); + return wl_resource_get_user_data (buffer->resource); return NULL; } @@ -460,6 +584,15 @@ static const struct zwp_linux_dmabuf_v1_interface dma_buf_implementation = dma_buf_handle_create_buffer_params, }; +static gboolean +should_send_modifiers (MetaBackend *backend) +{ + MetaSettings *settings = meta_backend_get_settings (backend); + + return meta_settings_is_experimental_feature_enabled ( + settings, META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS); +} + static void send_modifiers (struct wl_resource *resource, uint32_t format) @@ -482,6 +615,14 @@ send_modifiers (struct wl_resource *resource, if (wl_resource_get_version (resource) < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) return; + if (!should_send_modifiers (backend)) + { + zwp_linux_dmabuf_v1_send_modifier (resource, format, + DRM_FORMAT_MOD_INVALID >> 32, + DRM_FORMAT_MOD_INVALID & 0xffffffff); + return; + } + /* First query the number of available modifiers, then allocate an array, * then fill the array. */ ret = meta_egl_query_dma_buf_modifiers (egl, egl_display, format, 0, NULL, diff --git a/src/wayland/meta-wayland-dma-buf.h b/src/wayland/meta-wayland-dma-buf.h index b7f712d8d..cdc65aeb5 100644 --- a/src/wayland/meta-wayland-dma-buf.h +++ b/src/wayland/meta-wayland-dma-buf.h @@ -49,4 +49,8 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, MetaWaylandDmaBufBuffer * meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer); +CoglScanout * +meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf, + CoglOnscreen *onscreen); + #endif /* META_WAYLAND_DMA_BUF_H */ diff --git a/src/wayland/meta-wayland-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c index a1f5f36af..12d291043 100644 --- a/src/wayland/meta-wayland-shell-surface.c +++ b/src/wayland/meta-wayland-shell-surface.c @@ -245,7 +245,7 @@ meta_wayland_shell_surface_surface_pre_apply_state (MetaWaylandSurfaceRole *sur meta_wayland_surface_role_get_surface (surface_role); if (pending->newly_attached && - !surface->buffer_ref.buffer && + !surface->buffer_ref->buffer && priv->window) meta_window_queue (priv->window, META_QUEUE_CALC_SHOWING); } @@ -271,7 +271,7 @@ meta_wayland_shell_surface_surface_apply_state (MetaWaylandSurfaceRole *surface META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_shell_surface_parent_class); surface_role_class->apply_state (surface_role, pending); - buffer = surface->buffer_ref.buffer; + buffer = surface->buffer_ref->buffer; if (!buffer) return; diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c index 24d5c0a53..7ddb8b87b 100644 --- a/src/wayland/meta-wayland-subsurface.c +++ b/src/wayland/meta-wayland-subsurface.c @@ -74,7 +74,7 @@ sync_actor_subsurface_state (MetaWaylandSurface *surface) clutter_actor_set_position (actor, x, y); clutter_actor_set_reactive (actor, TRUE); - if (surface->buffer_ref.buffer) + if (surface->buffer_ref->buffer) clutter_actor_show (actor); else clutter_actor_hide (actor); @@ -147,7 +147,7 @@ meta_wayland_subsurface_union_geometry (MetaWaylandSubsurface *subsurface, .height = meta_wayland_surface_get_height (surface), }; - if (surface->buffer_ref.buffer) + if (surface->buffer_ref->buffer) meta_rectangle_union (out_geometry, &geometry, out_geometry); META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface) diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index ca6bd98cd..bcb4431e3 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -122,6 +122,58 @@ meta_wayland_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *surface static MetaWaylandSurface * meta_wayland_surface_role_get_toplevel (MetaWaylandSurfaceRole *surface_role); +static MetaWaylandBufferRef * +meta_wayland_buffer_ref_new (void) +{ + MetaWaylandBufferRef *buffer_ref; + + buffer_ref = g_new0 (MetaWaylandBufferRef, 1); + g_ref_count_init (&buffer_ref->ref_count); + + return buffer_ref; +} + +static MetaWaylandBufferRef * +meta_wayland_buffer_ref_ref (MetaWaylandBufferRef *buffer_ref) +{ + g_ref_count_inc (&buffer_ref->ref_count); + return buffer_ref; +} + +static void +meta_wayland_buffer_ref_unref (MetaWaylandBufferRef *buffer_ref) +{ + if (g_ref_count_dec (&buffer_ref->ref_count)) + { + g_warn_if_fail (buffer_ref->use_count == 0); + g_clear_object (&buffer_ref->buffer); + g_free (buffer_ref); + } +} + +static void +meta_wayland_buffer_ref_inc_use_count (MetaWaylandBufferRef *buffer_ref) +{ + g_return_if_fail (buffer_ref->buffer); + g_warn_if_fail (buffer_ref->buffer->resource); + + buffer_ref->use_count++; +} + +static void +meta_wayland_buffer_ref_dec_use_count (MetaWaylandBufferRef *buffer_ref) +{ + MetaWaylandBuffer *buffer = buffer_ref->buffer; + + g_return_if_fail (buffer_ref->use_count > 0); + g_return_if_fail (buffer); + + buffer_ref->use_count--; + + if (buffer_ref->use_count == 0 && buffer->resource) + wl_buffer_send_release (buffer->resource); +} + static void role_assignment_valist_to_properties (GType role_type, const char *first_property_name, @@ -357,31 +409,19 @@ surface_process_damage (MetaWaylandSurface *surface, MetaWaylandBuffer * meta_wayland_surface_get_buffer (MetaWaylandSurface *surface) { - return surface->buffer_ref.buffer; + return surface->buffer_ref->buffer; } void meta_wayland_surface_ref_buffer_use_count (MetaWaylandSurface *surface) { - g_return_if_fail (surface->buffer_ref.buffer); - g_warn_if_fail (surface->buffer_ref.buffer->resource); - - surface->buffer_ref.use_count++; + meta_wayland_buffer_ref_inc_use_count (surface->buffer_ref); } void meta_wayland_surface_unref_buffer_use_count (MetaWaylandSurface *surface) { - MetaWaylandBuffer *buffer = surface->buffer_ref.buffer; - - g_return_if_fail (surface->buffer_ref.use_count != 0); - - surface->buffer_ref.use_count--; - - g_return_if_fail (buffer); - - if (surface->buffer_ref.use_count == 0 && buffer->resource) - wl_buffer_send_release (buffer->resource); + meta_wayland_buffer_ref_dec_use_count (surface->buffer_ref); } static void @@ -644,7 +684,13 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, if (surface->buffer_held) meta_wayland_surface_unref_buffer_use_count (surface); - g_set_object (&surface->buffer_ref.buffer, state->buffer); + if (surface->buffer_ref->use_count > 0) + { + meta_wayland_buffer_ref_unref (surface->buffer_ref); + surface->buffer_ref = meta_wayland_buffer_ref_new (); + } + + g_set_object (&surface->buffer_ref->buffer, state->buffer); if (state->buffer) meta_wayland_surface_ref_buffer_use_count (surface); @@ -751,7 +797,8 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, * role the surface is given. That means we need to also keep a use * count for wl_buffer's that are used by unassigned wl_surface's. */ - g_set_object (&surface->unassigned.buffer, surface->buffer_ref.buffer); + g_set_object (&surface->unassigned.buffer, + surface->buffer_ref->buffer); if (surface->unassigned.buffer) meta_wayland_surface_ref_buffer_use_count (surface); } @@ -799,7 +846,7 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, * be released if no-one else has a use-reference to it. */ if (state->newly_attached && - !surface->buffer_held && surface->buffer_ref.buffer) + !surface->buffer_held && surface->buffer_ref->buffer) meta_wayland_surface_unref_buffer_use_count (surface); g_signal_emit (state, @@ -1355,7 +1402,7 @@ wl_surface_destructor (struct wl_resource *resource) if (surface->buffer_held) meta_wayland_surface_unref_buffer_use_count (surface); g_clear_pointer (&surface->texture, cogl_object_unref); - g_clear_object (&surface->buffer_ref.buffer); + g_clear_pointer (&surface->buffer_ref, meta_wayland_buffer_ref_unref); g_clear_object (&surface->cached_state); g_clear_object (&surface->pending_state); @@ -1624,6 +1671,9 @@ static void meta_wayland_surface_init (MetaWaylandSurface *surface) { surface->pending_state = g_object_new (META_TYPE_WAYLAND_SURFACE_STATE, NULL); + + surface->buffer_ref = meta_wayland_buffer_ref_new (); + surface->subsurface_branch_node = g_node_new (surface); surface->subsurface_leaf_node = g_node_prepend_data (surface->subsurface_branch_node, surface); @@ -1896,7 +1946,7 @@ meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface) cairo_region_t *region; cairo_rectangle_int_t buffer_rect; - if (!surface->buffer_ref.buffer) + if (!surface->buffer_ref->buffer) return NULL; buffer_rect = (cairo_rectangle_int_t) { @@ -2005,3 +2055,38 @@ meta_wayland_surface_get_height (MetaWaylandSurface *surface) return height / surface->scale; } } + +static void +scanout_destroyed (gpointer data, + GObject *where_the_object_was) +{ + MetaWaylandBufferRef *buffer_ref = data; + + meta_wayland_buffer_ref_dec_use_count (buffer_ref); + meta_wayland_buffer_ref_unref (buffer_ref); +} + +CoglScanout * +meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface, + CoglOnscreen *onscreen) +{ + CoglScanout *scanout; + MetaWaylandBufferRef *buffer_ref; + + if (!surface->buffer_ref->buffer) + return NULL; + + if (surface->buffer_ref->use_count == 0) + return NULL; + + scanout = meta_wayland_buffer_try_acquire_scanout (surface->buffer_ref->buffer, + onscreen); + if (!scanout) + return NULL; + + buffer_ref = meta_wayland_buffer_ref_ref (surface->buffer_ref); + meta_wayland_buffer_ref_inc_use_count (buffer_ref); + g_object_weak_ref (G_OBJECT (scanout), scanout_destroyed, buffer_ref); + + return scanout; +} diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index 7e8814c23..91497d2c8 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -140,6 +140,13 @@ struct _MetaWaylandDragDestFuncs MetaWaylandSurface *surface); }; +typedef struct _MetaWaylandBufferRef +{ + grefcount ref_count; + MetaWaylandBuffer *buffer; + unsigned int use_count; +} MetaWaylandBufferRef; + struct _MetaWaylandSurface { GObject parent; @@ -159,11 +166,7 @@ struct _MetaWaylandSurface CoglTexture *texture; - /* Buffer reference state. */ - struct { - MetaWaylandBuffer *buffer; - unsigned int use_count; - } buffer_ref; + MetaWaylandBufferRef *buffer_ref; /* Buffer renderer state. */ gboolean buffer_held; @@ -338,6 +341,9 @@ void meta_wayland_surface_update_outputs_recursively (MetaWayland int meta_wayland_surface_get_width (MetaWaylandSurface *surface); int meta_wayland_surface_get_height (MetaWaylandSurface *surface); +CoglScanout * meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface, + CoglOnscreen *onscreen); + static inline GNode * meta_get_next_subsurface_sibling (GNode *n) { diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c index 1319c74e3..d19ac3876 100644 --- a/src/wayland/meta-wayland-xdg-shell.c +++ b/src/wayland/meta-wayland-xdg-shell.c @@ -771,7 +771,7 @@ meta_wayland_xdg_toplevel_apply_state (MetaWaylandSurfaceRole *surface_role, return; } - if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached) + if (!surface->buffer_ref->buffer && xdg_surface_priv->first_buffer_attached) { meta_wayland_xdg_surface_reset (xdg_surface); meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, @@ -830,7 +830,7 @@ meta_wayland_xdg_toplevel_post_apply_state (MetaWaylandSurfaceRole *surface_rol META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_toplevel_parent_class); surface_role_class->post_apply_state (surface_role, pending); - if (!surface->buffer_ref.buffer) + if (!surface->buffer_ref->buffer) return; window_geometry = meta_wayland_xdg_surface_get_window_geometry (xdg_surface); @@ -1145,7 +1145,7 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role, if (xdg_popup->setup.parent_surface) finish_popup_setup (xdg_popup); - if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached) + if (!surface->buffer_ref->buffer && xdg_surface_priv->first_buffer_attached) { meta_wayland_xdg_surface_reset (xdg_surface); meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending); @@ -1156,7 +1156,7 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role, META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_popup_parent_class); surface_role_class->apply_state (surface_role, pending); - if (xdg_popup->dismissed_by_client && surface->buffer_ref.buffer) + if (xdg_popup->dismissed_by_client && surface->buffer_ref->buffer) { wl_resource_post_error (xdg_popup->resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, @@ -1187,7 +1187,7 @@ meta_wayland_xdg_popup_post_apply_state (MetaWaylandSurfaceRole *surface_role, if (!pending->newly_attached) return; - if (!surface->buffer_ref.buffer) + if (!surface->buffer_ref->buffer) return; surface_role_class->post_apply_state (surface_role, pending); @@ -1592,7 +1592,7 @@ meta_wayland_xdg_surface_apply_state (MetaWaylandSurfaceRole *surface_role, if (!window) return; - if (surface->buffer_ref.buffer) + if (surface->buffer_ref->buffer) priv->first_buffer_attached = TRUE; } @@ -1661,7 +1661,7 @@ meta_wayland_xdg_surface_assigned (MetaWaylandSurfaceRole *surface_role) priv->configure_sent = FALSE; priv->first_buffer_attached = FALSE; - if (surface->buffer_ref.buffer) + if (surface->buffer_ref->buffer) { wl_resource_post_error (xdg_wm_base_resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, @@ -2367,7 +2367,7 @@ xdg_wm_base_get_xdg_surface (struct wl_client *client, return; } - if (surface->buffer_ref.buffer) + if (surface->buffer_ref->buffer) { wl_resource_post_error (resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, diff --git a/src/wayland/meta-xwayland-surface.c b/src/wayland/meta-xwayland-surface.c index 4a4615a2c..c8625f414 100644 --- a/src/wayland/meta-xwayland-surface.c +++ b/src/wayland/meta-xwayland-surface.c @@ -182,7 +182,7 @@ meta_xwayland_surface_pre_apply_state (MetaWaylandSurfaceRole *surface_role, MetaXwaylandSurface *xwayland_surface = META_XWAYLAND_SURFACE (surface_role); if (pending->newly_attached && - surface->buffer_ref.buffer && + surface->buffer_ref->buffer && xwayland_surface->window) meta_window_queue (xwayland_surface->window, META_QUEUE_CALC_SHOWING); } diff --git a/src/x11/window-props.c b/src/x11/window-props.c index abc714973..07f8a281a 100644 --- a/src/x11/window-props.c +++ b/src/x11/window-props.c @@ -249,7 +249,7 @@ reload_net_wm_window_type (MetaWindow *window, { MetaX11Display *x11_display = window->display->x11_display; MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); if (value->type != META_PROP_VALUE_INVALID) { @@ -291,7 +291,7 @@ reload_icon (MetaWindow *window, Atom atom) { MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); meta_icon_cache_property_changed (&priv->icon_cache, window->display->x11_display, @@ -596,7 +596,7 @@ set_window_title (MetaWindow *window, const char *title) { MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); char *new_title = NULL; @@ -619,7 +619,7 @@ reload_net_wm_name (MetaWindow *window, gboolean initial) { MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); if (value->type != META_PROP_VALUE_INVALID) { @@ -644,7 +644,7 @@ reload_wm_name (MetaWindow *window, gboolean initial) { MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); if (priv->using_net_wm_name) { @@ -784,7 +784,7 @@ reload_net_wm_state (MetaWindow *window, { MetaX11Display *x11_display = window->display->x11_display; MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); int i; @@ -1656,7 +1656,7 @@ reload_wm_hints (MetaWindow *window, gboolean initial) { MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); - MetaWindowX11Private *priv = window_x11->priv; + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); Window old_group_leader; gboolean urgent; @@ -1847,23 +1847,28 @@ reload_bypass_compositor (MetaWindow *window, MetaPropValue *value, gboolean initial) { - int requested_value = 0; - int current_value = window->bypass_compositor; + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); + MetaBypassCompositorHint requested_value; + MetaBypassCompositorHint current_value; if (value->type != META_PROP_VALUE_INVALID) - requested_value = (int) value->v.cardinal; + requested_value = (MetaBypassCompositorHint) value->v.cardinal; + else + requested_value = META_BYPASS_COMPOSITOR_HINT_AUTO; + current_value = priv->bypass_compositor; if (requested_value == current_value) return; - if (requested_value == _NET_WM_BYPASS_COMPOSITOR_HINT_ON) + if (requested_value == META_BYPASS_COMPOSITOR_HINT_ON) meta_verbose ("Request to bypass compositor for window %s.\n", window->desc); - else if (requested_value == _NET_WM_BYPASS_COMPOSITOR_HINT_OFF) + else if (requested_value == META_BYPASS_COMPOSITOR_HINT_OFF) meta_verbose ("Request to don't bypass compositor for window %s.\n", window->desc); - else if (requested_value != _NET_WM_BYPASS_COMPOSITOR_HINT_AUTO) + else if (requested_value != META_BYPASS_COMPOSITOR_HINT_AUTO) return; - window->bypass_compositor = requested_value; + priv->bypass_compositor = requested_value; } static void diff --git a/src/x11/window-x11-private.h b/src/x11/window-x11-private.h index 906d44546..e12f83be0 100644 --- a/src/x11/window-x11-private.h +++ b/src/x11/window-x11-private.h @@ -25,26 +25,21 @@ #include "core/window-private.h" #include "x11/iconcache.h" +#include "x11/window-x11.h" G_BEGIN_DECLS -typedef struct _MetaWindowX11Private MetaWindowX11Private; - -struct _MetaWindowX11Class -{ - MetaWindowClass parent_class; - - void (*freeze_commits) (MetaWindow *window); - void (*thaw_commits) (MetaWindow *window); - gboolean (*always_update_shape) (MetaWindow *window); -}; - -struct _MetaWindowX11 +/* + * Mirrors _NET_WM_BYPASS_COMPOSITOR preference values. + */ +typedef enum _MetaBypassCompositorHint { - MetaWindow parent; + META_BYPASS_COMPOSITOR_HINT_AUTO = 0, + META_BYPASS_COMPOSITOR_HINT_ON = 1, + META_BYPASS_COMPOSITOR_HINT_OFF = 2, +} MetaBypassCompositorHint; - MetaWindowX11Private *priv; -}; +typedef struct _MetaWindowX11Private MetaWindowX11Private; struct _MetaWindowX11Private { @@ -79,8 +74,16 @@ struct _MetaWindowX11Private /* Freeze/thaw on resize (for Xwayland) */ gboolean thaw_after_paint; + + /* Bypass compositor hints */ + MetaBypassCompositorHint bypass_compositor; }; +MetaWindowX11Private * meta_window_x11_get_private (MetaWindowX11 *window_x11); + +void meta_window_x11_set_bypass_compositor_hint (MetaWindowX11 *window_x11, + MetaBypassCompositorHint requested_value); + G_END_DECLS #endif diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c index aa4435b7f..b3ea18717 100644 --- a/src/x11/window-x11.c +++ b/src/x11/window-x11.c @@ -73,7 +73,12 @@ meta_window_x11_maybe_focus_delayed (MetaWindow *window, static void meta_window_x11_init (MetaWindowX11 *window_x11) { - window_x11->priv = meta_window_x11_get_instance_private (window_x11); +} + +MetaWindowX11Private * +meta_window_x11_get_private (MetaWindowX11 *window_x11) +{ + return meta_window_x11_get_instance_private (window_x11); } static void @@ -4133,3 +4138,70 @@ meta_window_x11_surface_rect_to_client_rect (MetaWindow *window, client_rect->width -= borders.total.left + borders.total.right; client_rect->height -= borders.total.top + borders.total.bottom; } + +MetaRectangle +meta_window_x11_get_client_rect (MetaWindowX11 *window_x11) +{ + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + + return priv->client_rect; +} + +static gboolean +has_requested_bypass_compositor (MetaWindowX11 *window_x11) +{ + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + + return priv->bypass_compositor == META_BYPASS_COMPOSITOR_HINT_ON; +} + +static gboolean +has_requested_dont_bypass_compositor (MetaWindowX11 *window_x11) +{ + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + + return priv->bypass_compositor == META_BYPASS_COMPOSITOR_HINT_OFF; +} + +gboolean +meta_window_x11_can_unredirect (MetaWindowX11 *window_x11) +{ + MetaWindow *window = META_WINDOW (window_x11); + + if (has_requested_dont_bypass_compositor (window_x11)) + return FALSE; + + if (window->opacity != 0xFF) + return FALSE; + + if (window->shape_region != NULL) + return FALSE; + + if (!window->monitor) + return FALSE; + + if (window->fullscreen) + return TRUE; + + if (meta_window_is_screen_sized (window)) + return TRUE; + + if (has_requested_bypass_compositor (window_x11)) + return TRUE; + + if (window->override_redirect) + { + MetaRectangle window_rect; + MetaRectangle logical_monitor_layout; + MetaLogicalMonitor *logical_monitor = window->monitor; + + meta_window_get_frame_rect (window, &window_rect); + logical_monitor_layout = + meta_logical_monitor_get_layout (logical_monitor); + + if (meta_rectangle_equal (&window_rect, &logical_monitor_layout)) + return TRUE; + } + + return FALSE; +} diff --git a/src/x11/window-x11.h b/src/x11/window-x11.h index d41d0d156..0223af781 100644 --- a/src/x11/window-x11.h +++ b/src/x11/window-x11.h @@ -25,24 +25,24 @@ #include +#include "core/window-private.h" #include "meta/compositor.h" #include "meta/window.h" G_BEGIN_DECLS -#define META_TYPE_WINDOW_X11 (meta_window_x11_get_type()) -#define META_WINDOW_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW_X11, MetaWindowX11)) -#define META_WINDOW_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW_X11, MetaWindowX11Class)) -#define META_IS_WINDOW_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WINDOW_X11)) -#define META_IS_WINDOW_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WINDOW_X11)) -#define META_WINDOW_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WINDOW_X11, MetaWindowX11Class)) +#define META_TYPE_WINDOW_X11 (meta_window_x11_get_type()) +G_DECLARE_DERIVABLE_TYPE (MetaWindowX11, meta_window_x11, + META, WINDOW_X11, MetaWindow) -GType meta_window_x11_get_type (void); +struct _MetaWindowX11Class +{ + MetaWindowClass parent_class; -typedef struct _MetaWindowX11 MetaWindowX11; -typedef struct _MetaWindowX11Class MetaWindowX11Class; - -G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaWindowX11, g_object_unref) + void (*freeze_commits) (MetaWindow *window); + void (*thaw_commits) (MetaWindow *window); + gboolean (*always_update_shape) (MetaWindow *window); +}; MetaWindow * meta_window_x11_new (MetaDisplay *display, Window xwindow, @@ -95,4 +95,8 @@ void meta_window_x11_surface_rect_to_frame_rect (MetaWindow *window, void meta_window_x11_surface_rect_to_client_rect (MetaWindow *window, MetaRectangle *surface_rect, MetaRectangle *client_rect); + +MetaRectangle meta_window_x11_get_client_rect (MetaWindowX11 *window_x11); + +gboolean meta_window_x11_can_unredirect (MetaWindowX11 *window_x11); #endif