From bb749e91ad812b38c867f96088fb8e5dc629d3a7 Mon Sep 17 00:00:00 2001 From: Robert Mader Date: Tue, 3 Oct 2023 00:19:42 +0200 Subject: [PATCH] Allow direct scanout for non-fullscreen clients using overlay planes So we can skip compositing in common cases such as maximized clients. Currently only works as long as there is no stage damage outside the choosen surface. --- clutter/clutter/clutter-stage-view-private.h | 3 + clutter/clutter/clutter-stage-view.c | 9 + cogl/cogl/cogl-scanout.c | 14 ++ cogl/cogl/cogl-scanout.h | 7 + src/backends/meta-stage-impl.c | 57 ++++- src/backends/native/meta-crtc-kms.h | 16 ++ src/backends/native/meta-drm-buffer.c | 3 + src/backends/native/meta-onscreen-native.c | 236 +++++++++++++++---- src/compositor/meta-compositor-view-native.c | 12 +- src/compositor/meta-window-actor-wayland.c | 63 +---- src/wayland/meta-wayland-dma-buf.c | 4 +- 11 files changed, 301 insertions(+), 123 deletions(-) diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h index 31ac7e144ea..b143912f581 100644 --- a/clutter/clutter/clutter-stage-view-private.h +++ b/clutter/clutter/clutter-stage-view-private.h @@ -54,6 +54,9 @@ gboolean clutter_stage_view_has_full_redraw_clip (ClutterStageView *view); gboolean clutter_stage_view_has_redraw_clip (ClutterStageView *view); +CLUTTER_EXPORT +const MtkRegion * clutter_stage_view_peek_redraw_clip (ClutterStageView *view); + CLUTTER_EXPORT MtkRegion * clutter_stage_view_take_accumulated_redraw_clip (ClutterStageView *view); diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c index 88cffec851d..a1940d0df2c 100644 --- a/clutter/clutter/clutter-stage-view.c +++ b/clutter/clutter/clutter-stage-view.c @@ -857,6 +857,15 @@ clutter_stage_view_has_full_redraw_clip (ClutterStageView *view) return priv->has_redraw_clip && !priv->redraw_clip; } +const MtkRegion * +clutter_stage_view_peek_redraw_clip (ClutterStageView *view) +{ + ClutterStageViewPrivate *priv = + clutter_stage_view_get_instance_private (view); + + return priv->redraw_clip; +} + MtkRegion * clutter_stage_view_take_accumulated_redraw_clip (ClutterStageView *view) { diff --git a/cogl/cogl/cogl-scanout.c b/cogl/cogl/cogl-scanout.c index f9b44ff8529..fd2597f82c1 100644 --- a/cogl/cogl/cogl-scanout.c +++ b/cogl/cogl/cogl-scanout.c @@ -45,6 +45,7 @@ struct _CoglScanout GObject parent; CoglScanoutBuffer *scanout_buffer; + uint32_t plane_id; gboolean has_src_rect; graphene_rect_t src_rect; @@ -148,6 +149,19 @@ cogl_scanout_get_dst_rect (CoglScanout *scanout, *dst_rect = scanout->dst_rect; } +uint32_t +cogl_scanout_get_plane_id (CoglScanout *scanout) +{ + return scanout->plane_id; +} + +void +cogl_scanout_set_plane_id (CoglScanout *scanout, + uint32_t plane_id) +{ + scanout->plane_id = plane_id; +} + static void cogl_scanout_finalize (GObject *object) { diff --git a/cogl/cogl/cogl-scanout.h b/cogl/cogl/cogl-scanout.h index 5b64bfdd6f2..41f57a76237 100644 --- a/cogl/cogl/cogl-scanout.h +++ b/cogl/cogl/cogl-scanout.h @@ -91,3 +91,10 @@ void cogl_scanout_set_src_rect (CoglScanout *scanout, COGL_EXPORT void cogl_scanout_get_dst_rect (CoglScanout *scanout, MtkRectangle *dst_rect); + +COGL_EXPORT +uint32_t cogl_scanout_get_plane_id (CoglScanout *scanout); + +COGL_EXPORT +void cogl_scanout_set_plane_id (CoglScanout *scanout, + uint32_t plane_id); diff --git a/src/backends/meta-stage-impl.c b/src/backends/meta-stage-impl.c index e6f3b18a0a4..8bff76a00d5 100644 --- a/src/backends/meta-stage-impl.c +++ b/src/backends/meta-stage-impl.c @@ -782,22 +782,53 @@ meta_stage_impl_redraw_view (ClutterStageWindow *stage_window, scanout = clutter_stage_view_take_scanout (stage_view); if (scanout) { - g_autoptr (GError) error = NULL; + const MtkRegion *redraw_clip; + MtkRectangle redraw_clip_rect; + MtkRectangle scanout_rect; - if (meta_stage_impl_scanout_view (stage_impl, - stage_view, - scanout, - frame, - &error)) + redraw_clip = clutter_stage_view_peek_redraw_clip (stage_view); + if (redraw_clip) + redraw_clip_rect = mtk_region_get_extents (redraw_clip); + else + clutter_stage_view_get_layout (stage_view, &redraw_clip_rect); + cogl_scanout_get_dst_rect (scanout, &scanout_rect); + + if (mtk_rectangle_contains_rect (&scanout_rect, &redraw_clip_rect)) { - clutter_stage_view_accumulate_redraw_clip (stage_view); - return; - } + g_autoptr (GError) error = NULL; - if (!g_error_matches (error, - COGL_SCANOUT_ERROR, - COGL_SCANOUT_ERROR_INHIBITED)) - g_warning ("Failed to scan out client buffer: %s", error->message); + if (meta_stage_impl_scanout_view (stage_impl, + stage_view, + scanout, + frame, + &error)) + { + clutter_stage_view_accumulate_redraw_clip (stage_view); + return; + } + + if (g_error_matches (error, + COGL_SCANOUT_ERROR, + COGL_SCANOUT_ERROR_INHIBITED)) + { + meta_topic (META_DEBUG_RENDER, + "Skipping scanout: inhibited"); + } + else + { + g_warning ("Failed to scan out client buffer: %s", error->message); + } + } + else + { + meta_topic (META_DEBUG_RENDER, + "Skipping scanout: redraw clip (%d,%d,%d,%d) exceeds " + "scanout area (%d,%d,%d,%d)", + redraw_clip_rect.x, redraw_clip_rect.y, + redraw_clip_rect.width, redraw_clip_rect.height, + scanout_rect.x, scanout_rect.y, + scanout_rect.width, scanout_rect.height); + } } meta_stage_impl_redraw_view_primary (stage_impl, stage_view, frame); diff --git a/src/backends/native/meta-crtc-kms.h b/src/backends/native/meta-crtc-kms.h index 38298253462..7e125a9eec9 100644 --- a/src/backends/native/meta-crtc-kms.h +++ b/src/backends/native/meta-crtc-kms.h @@ -39,6 +39,22 @@ G_DECLARE_FINAL_TYPE (MetaCrtcKms, meta_crtc_kms, MetaKmsPlane * meta_crtc_kms_get_assigned_primary_plane (MetaCrtcKms *crtc_kms); +MetaKmsPlaneAssignment * meta_crtc_kms_assign_plane_by_id (MetaCrtcKms *crtc_kms, + uint32_t plane_id, + MetaDrmBuffer *buffer, + MetaKmsUpdate *kms_update, + MetaKmsAssignPlaneFlag flags, + const MtkRectangle *src_rect, + const MtkRectangle *dst_rect); + +MetaKmsPlaneAssignment * meta_crtc_kms_assign_plane (MetaCrtcKms *crtc_kms, + MetaKmsPlane *kms_plane, + MetaDrmBuffer *buffer, + MetaKmsUpdate *kms_update, + MetaKmsAssignPlaneFlag flags, + const MtkRectangle *src_rect, + const MtkRectangle *dst_rect); + MetaKmsPlane * meta_crtc_kms_get_assigned_cursor_plane (MetaCrtcKms *crtc_kms); void meta_crtc_kms_assign_planes (MetaCrtcKms *crtc_kms, diff --git a/src/backends/native/meta-drm-buffer.c b/src/backends/native/meta-drm-buffer.c index 1c83984c94f..9c896aeb897 100644 --- a/src/backends/native/meta-drm-buffer.c +++ b/src/backends/native/meta-drm-buffer.c @@ -53,6 +53,9 @@ typedef struct _MetaDrmBufferPrivate uint32_t fb_id; uint32_t handle; + + MtkRectangle src_rect; + MtkRectangle dst_rect; } MetaDrmBufferPrivate; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaDrmBuffer, meta_drm_buffer, diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c index 3e4d8c3dd70..06600400ced 100644 --- a/src/backends/native/meta-onscreen-native.c +++ b/src/backends/native/meta-onscreen-native.c @@ -548,17 +548,17 @@ apply_color_range (MetaKmsPlaneAssignment *kms_plane_assignment, } static MetaKmsPlaneAssignment * -assign_primary_plane (MetaCrtcKms *crtc_kms, - MetaDrmBuffer *buffer, - MetaKmsUpdate *kms_update, - MetaKmsAssignPlaneFlag flags, - const graphene_rect_t *src_rect, - const MtkRectangle *dst_rect) +assign_plane (MetaCrtcKms *crtc_kms, + MetaKmsPlane *kms_plane, + MetaDrmBuffer *buffer, + MetaKmsUpdate *kms_update, + MetaKmsAssignPlaneFlag flags, + const graphene_rect_t *src_rect, + const MtkRectangle *dst_rect) { MetaCrtc *crtc = META_CRTC (crtc_kms); MetaFixed16Rectangle src_rect_fixed16; MetaKmsCrtc *kms_crtc; - MetaKmsPlane *primary_kms_plane; MetaKmsPlaneAssignment *plane_assignment; src_rect_fixed16 = (MetaFixed16Rectangle) { @@ -577,21 +577,78 @@ assign_primary_plane (MetaCrtcKms *crtc_kms, dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height); kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); - primary_kms_plane = meta_crtc_kms_get_assigned_primary_plane (crtc_kms); plane_assignment = meta_kms_update_assign_plane (kms_update, kms_crtc, - primary_kms_plane, + kms_plane, buffer, src_rect_fixed16, *dst_rect, flags); - apply_transform (crtc_kms, plane_assignment, primary_kms_plane); - apply_color_encoding (plane_assignment, primary_kms_plane); - apply_color_range (plane_assignment, primary_kms_plane); + apply_transform (crtc_kms, plane_assignment, kms_plane); + apply_color_encoding (plane_assignment, kms_plane); + apply_color_range (plane_assignment, kms_plane); return plane_assignment; } +static MetaKmsPlaneAssignment * +assign_primary_plane (MetaCrtcKms *crtc_kms, + MetaDrmBuffer *buffer, + MetaKmsUpdate *kms_update, + MetaKmsAssignPlaneFlag flags, + const graphene_rect_t *src_rect, + const MtkRectangle *dst_rect) +{ + MetaKmsPlane *primary_kms_plane; + + primary_kms_plane = meta_crtc_kms_get_assigned_primary_plane (crtc_kms); + + return assign_plane (crtc_kms, + primary_kms_plane, + buffer, + kms_update, + flags, + src_rect, + dst_rect); +} + +static MetaKmsPlaneAssignment * +assign_plane_by_id (MetaCrtcKms *crtc_kms, + uint32_t plane_id, + MetaDrmBuffer *buffer, + MetaKmsUpdate *kms_update, + MetaKmsAssignPlaneFlag flags, + const graphene_rect_t *src_rect, + const MtkRectangle *dst_rect) +{ + MetaKmsCrtc *kms_crtc; + MetaKmsDevice *kms_device; + MetaKmsPlane *plane = NULL; + GList *l; + + kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); + kms_device = meta_kms_crtc_get_device (kms_crtc); + + for (l = meta_kms_device_get_planes (kms_device); l; l = l->next) + { + MetaKmsPlane *current_plane = l->data; + + if (meta_kms_plane_get_id (current_plane) == plane_id) + plane = current_plane; + } + + if (!plane) + return NULL; + + return assign_plane (crtc_kms, + plane, + buffer, + kms_update, + flags, + src_rect, + dst_rect); +} + static gboolean meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, ClutterFrame *frame, @@ -638,10 +695,56 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, scanout = meta_frame_native_get_scanout (frame_native); + /* Unset the previously used overlay plane if required */ + if (onscreen_native->presented_frame) + { + MetaFrameNative* frame_native_presented; + CoglScanout *scanout_presented; + + frame_native_presented = + meta_frame_native_from_frame (onscreen_native->presented_frame); + scanout_presented = meta_frame_native_get_scanout (frame_native_presented); + + if (scanout_presented) + { + uint32_t plane_id_presented; + uint32_t plane_id_next = 0; + + plane_id_presented = cogl_scanout_get_plane_id (scanout_presented); + + if (scanout) + plane_id_next = cogl_scanout_get_plane_id (scanout); + + if (plane_id_presented != plane_id_next) + { + plane_assignment = assign_plane_by_id (crtc_kms, + plane_id_presented, + NULL, + kms_update, + 0, + &src_rect, + &dst_rect); + } + } + } + if (scanout) { + uint32_t plane_id; + + plane_id = cogl_scanout_get_plane_id (scanout); + cogl_scanout_get_src_rect (scanout, &src_rect); cogl_scanout_get_dst_rect (scanout, &dst_rect); + + plane_assignment = assign_plane_by_id (crtc_kms, + plane_id, + buffer, + kms_update, + flags, + &src_rect, + &dst_rect); + g_assert (plane_assignment); } else { @@ -657,17 +760,17 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, .width = meta_drm_buffer_get_width (buffer), .height = meta_drm_buffer_get_height (buffer) }; - } - plane_assignment = assign_primary_plane (crtc_kms, - buffer, - kms_update, - flags, - &src_rect, - &dst_rect); + plane_assignment = assign_primary_plane (crtc_kms, + buffer, + kms_update, + flags, + &src_rect, + &dst_rect); - if (region && !mtk_region_is_empty (region)) - meta_kms_plane_assignment_set_fb_damage (plane_assignment, region); + if (region && !mtk_region_is_empty (region)) + meta_kms_plane_assignment_set_fb_damage (plane_assignment, region); + } break; case META_RENDERER_NATIVE_MODE_SURFACELESS: g_assert_not_reached (); @@ -1926,38 +2029,91 @@ meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen, MetaKmsUpdate *test_update; MetaDrmBuffer *buffer; g_autoptr (MetaKmsFeedback) kms_feedback = NULL; - MetaKmsFeedbackResult result; + MetaKmsFeedbackResult result = META_KMS_FEEDBACK_FAILED; graphene_rect_t src_rect; MtkRectangle dst_rect; + MetaKmsPlane *kms_plane; + GList *l; gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); kms_device = meta_gpu_kms_get_kms_device (gpu_kms); kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); - test_update = meta_kms_update_new (kms_device); - + buffer = META_DRM_BUFFER (cogl_scanout_get_buffer (scanout)); cogl_scanout_get_src_rect (scanout, &src_rect); cogl_scanout_get_dst_rect (scanout, &dst_rect); - buffer = META_DRM_BUFFER (cogl_scanout_get_buffer (scanout)); - assign_primary_plane (crtc_kms, - buffer, - test_update, - META_KMS_ASSIGN_PLANE_FLAG_DISABLE_IMPLICIT_SYNC, - &src_rect, - &dst_rect); + for (l = meta_kms_device_get_planes (kms_device); l; l = l->next) + { + kms_plane = l->data; + const GError *error; - meta_topic (META_DEBUG_KMS, - "Posting direct scanout test update for CRTC %u (%s) synchronously", - meta_kms_crtc_get_id (kms_crtc), - meta_kms_device_get_path (kms_device)); + if (meta_kms_plane_get_plane_type (kms_plane) != META_KMS_PLANE_TYPE_OVERLAY) + continue; + + if (!meta_kms_plane_is_usable_with (kms_plane, kms_crtc)) + continue; + + test_update = meta_kms_update_new (kms_device); + assign_plane (crtc_kms, + kms_plane, + buffer, + test_update, + META_KMS_ASSIGN_PLANE_FLAG_DISABLE_IMPLICIT_SYNC, + &src_rect, + &dst_rect); + kms_feedback = + meta_kms_device_process_update_sync (kms_device, test_update, + META_KMS_UPDATE_FLAG_TEST_ONLY); + + result = meta_kms_feedback_get_result (kms_feedback); + if (result == META_KMS_FEEDBACK_PASSED) + { + cogl_scanout_set_plane_id (scanout, + meta_kms_plane_get_id (kms_plane)); + return TRUE; + } + + error = meta_kms_feedback_get_error (kms_feedback); + meta_topic (META_DEBUG_KMS, + "Test update for overlay plane %d failed: %s", + meta_kms_plane_get_id (kms_plane), + error ? error->message : NULL); + } + + /*if (FALSE) + { + const GError *error; + + kms_plane = meta_kms_device_get_primary_plane_for (kms_device, kms_crtc); + + test_update = meta_kms_update_new (kms_device); + assign_primary_plane (crtc_kms, + kms_plane, + buffer, + test_update, + META_KMS_ASSIGN_PLANE_FLAG_DISABLE_IMPLICIT_SYNC, + &src_rect, + &dst_rect); + kms_feedback = + meta_kms_device_process_update_sync (kms_device, test_update, + META_KMS_UPDATE_FLAG_TEST_ONLY); - kms_feedback = - meta_kms_device_process_update_sync (kms_device, test_update, - META_KMS_UPDATE_FLAG_TEST_ONLY); + result = meta_kms_feedback_get_result (kms_feedback); + if (result == META_KMS_FEEDBACK_PASSED) + { + cogl_scanout_set_plane_id (scanout, + meta_kms_plane_get_id (kms_plane)); + return TRUE; + } - result = meta_kms_feedback_get_result (kms_feedback); - return result == META_KMS_FEEDBACK_PASSED; + error = meta_kms_feedback_get_error (kms_feedback); + meta_topic (META_DEBUG_KMS, + "Test update for primary plane failed: %s", + error ? error->message : NULL); + }*/ + + return FALSE; } static void diff --git a/src/compositor/meta-compositor-view-native.c b/src/compositor/meta-compositor-view-native.c index 9c52182cac5..9d87b151e23 100644 --- a/src/compositor/meta-compositor-view-native.c +++ b/src/compositor/meta-compositor-view-native.c @@ -162,14 +162,10 @@ find_candidate (MetaCompositorView *compositor_view, return NULL; } - if (!G_APPROX_VALUE (actor_box.x1, view_rect.x, - CLUTTER_COORDINATE_EPSILON) || - !G_APPROX_VALUE (actor_box.y1, view_rect.y, - CLUTTER_COORDINATE_EPSILON) || - !G_APPROX_VALUE (actor_box.x2, view_rect.x + view_rect.width, - CLUTTER_COORDINATE_EPSILON) || - !G_APPROX_VALUE (actor_box.y2, view_rect.y + view_rect.height, - CLUTTER_COORDINATE_EPSILON)) + if (actor_box.x1 < view_rect.x || + actor_box.y1 < view_rect.y || + actor_box.x2 > view_rect.x + view_rect.width || + actor_box.y2 > view_rect.y + view_rect.height) { meta_topic (META_DEBUG_RENDER, "No %s candidate: paint-box (%f,%f,%f,%f) does " diff --git a/src/compositor/meta-window-actor-wayland.c b/src/compositor/meta-window-actor-wayland.c index 540975a6a3e..9eea255dff7 100644 --- a/src/compositor/meta-window-actor-wayland.c +++ b/src/compositor/meta-window-actor-wayland.c @@ -352,10 +352,6 @@ meta_window_actor_wayland_get_scanout_candidate (MetaWindowActor *actor) ClutterActor *child_actor; ClutterActorIter iter; MetaSurfaceActor *topmost_surface_actor = NULL; - int n_visible_surface_actors = 0; - MetaWindow *window; - ClutterActorBox window_box; - ClutterActorBox surface_box; if (clutter_actor_get_last_child (CLUTTER_ACTOR (self)) != surface_container) { @@ -377,66 +373,13 @@ meta_window_actor_wayland_get_scanout_candidate (MetaWindowActor *actor) continue; topmost_surface_actor = surface_actor; - n_visible_surface_actors++; } if (!topmost_surface_actor) - { - meta_topic (META_DEBUG_RENDER, - "No surface-actor for window-actor"); - return NULL; - } - - window = meta_window_actor_get_meta_window (actor); - if (meta_window_is_fullscreen (window) && n_visible_surface_actors == 1) - return topmost_surface_actor; - - if (meta_window_is_fullscreen (window) && n_visible_surface_actors == 2) - { - MetaSurfaceActorWayland *bg_surface_actor = NULL; - MetaWaylandSurface *bg_surface; - MetaWaylandBuffer *buffer; - MetaWaylandSinglePixelBuffer *sp_buffer; - - clutter_actor_iter_init (&iter, surface_container); - while (clutter_actor_iter_next (&iter, &child_actor)) - { - MetaSurfaceActor *surface_actor; - - if (!clutter_actor_is_mapped (child_actor)) - continue; - - surface_actor = META_SURFACE_ACTOR (child_actor); - if (meta_surface_actor_is_obscured (surface_actor)) - continue; - - bg_surface_actor = META_SURFACE_ACTOR_WAYLAND (surface_actor); - break; - } - g_assert (bg_surface_actor); - - bg_surface = meta_surface_actor_wayland_get_surface (bg_surface_actor); - buffer = meta_wayland_surface_get_buffer (bg_surface); - - sp_buffer = buffer->single_pixel.single_pixel_buffer; - if (sp_buffer && - meta_wayland_single_pixel_buffer_is_opaque_black (sp_buffer)) - return topmost_surface_actor; - } + meta_topic (META_DEBUG_RENDER, + "No surface-actor for window-actor"); - if (meta_surface_actor_is_opaque (topmost_surface_actor) && - clutter_actor_get_paint_box (CLUTTER_ACTOR (actor), &window_box) && - clutter_actor_get_paint_box (CLUTTER_ACTOR (topmost_surface_actor), - &surface_box) && - G_APPROX_VALUE (window_box.x1, surface_box.x1, CLUTTER_COORDINATE_EPSILON) && - G_APPROX_VALUE (window_box.y1, surface_box.y1, CLUTTER_COORDINATE_EPSILON) && - G_APPROX_VALUE (window_box.x2, surface_box.x2, CLUTTER_COORDINATE_EPSILON) && - G_APPROX_VALUE (window_box.y2, surface_box.y2, CLUTTER_COORDINATE_EPSILON)) - return topmost_surface_actor; - - meta_topic (META_DEBUG_RENDER, - "Could not find suitable scanout candidate for window-actor"); - return NULL; + return topmost_surface_actor; } static void diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c index 08e37dfd599..e2c645aa52c 100644 --- a/src/wayland/meta-wayland-dma-buf.c +++ b/src/wayland/meta-wayland-dma-buf.c @@ -691,10 +691,10 @@ meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandBuffer *buffer, format_info = meta_format_info_from_drm_format (dma_buf->drm_format); g_assert (format_info); - if (format_info->opaque_substitute != DRM_FORMAT_INVALID && + if (FALSE /*format_info->opaque_substitute != DRM_FORMAT_INVALID && crtc_supports_modifier (crtc_kms, format_info->opaque_substitute, - dma_buf->drm_modifier)) + dma_buf->drm_modifier)*/) { drm_format = format_info->opaque_substitute; } -- GitLab