From 7c3172a0afaebd181ae3582e01a5028d497599fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 9 Nov 2019 00:17:33 +0100 Subject: [PATCH] kms/impl-simple: Add cursor plane processing A cursor plane can now be assigned, and for the simple KMS implementation, it'll translate into drmModeSetCursor() and drmModeMoveCursor() calls. When assignments failed, the cursor planes that failed to be assigned are communicated via the feedback object. https://gitlab.gnome.org/GNOME/mutter/merge_requests/930 --- src/backends/native/meta-kms-impl-simple.c | 168 +++++++++++++++++- src/backends/native/meta-kms-update-private.h | 13 +- src/backends/native/meta-kms-update.c | 36 +++- src/backends/native/meta-kms-update.h | 10 ++ 4 files changed, 219 insertions(+), 8 deletions(-) diff --git a/src/backends/native/meta-kms-impl-simple.c b/src/backends/native/meta-kms-impl-simple.c index c3a9698ba..2b6df146a 100644 --- a/src/backends/native/meta-kms-impl-simple.c +++ b/src/backends/native/meta-kms-impl-simple.c @@ -747,11 +747,156 @@ process_entries (MetaKmsImpl *impl, return TRUE; } +static gboolean +process_cursor_plane_assignment (MetaKmsImpl *impl, + MetaKmsUpdate *update, + MetaKmsPlaneAssignment *plane_assignment, + GError **error) +{ + MetaKmsPlane *plane; + MetaKmsDevice *device; + MetaKmsImplDevice *impl_device; + int fd; + + plane = plane_assignment->plane; + device = meta_kms_plane_get_device (plane); + impl_device = meta_kms_device_get_impl_device (device); + fd = meta_kms_impl_device_get_fd (impl_device); + + if (!(plane_assignment->flags & META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED)) + { + int width, height; + int ret; + + width = meta_fixed_16_to_int (plane_assignment->dst_rect.width); + height = meta_fixed_16_to_int (plane_assignment->dst_rect.height); + + ret = drmModeSetCursor (fd, meta_kms_crtc_get_id (plane_assignment->crtc), + plane_assignment->fb_id, + width, height); + if (ret != 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret), + "drmModeSetCursor failed: %s", g_strerror (-ret)); + return FALSE; + } + } + + drmModeMoveCursor (fd, + meta_kms_crtc_get_id (plane_assignment->crtc), + meta_fixed_16_to_int (plane_assignment->dst_rect.x), + meta_fixed_16_to_int (plane_assignment->dst_rect.y)); + + return TRUE; +} + +static gboolean +process_plane_assignment (MetaKmsImpl *impl, + MetaKmsUpdate *update, + MetaKmsPlaneAssignment *plane_assignment, + MetaKmsPlaneFeedback **plane_feedback) +{ + MetaKmsPlane *plane; + MetaKmsPlaneType plane_type; + GError *error = NULL; + + plane = plane_assignment->plane; + plane_type = meta_kms_plane_get_plane_type (plane); + switch (plane_type) + { + case META_KMS_PLANE_TYPE_PRIMARY: + /* Handled as part of the mode-set and page flip. */ + return TRUE; + case META_KMS_PLANE_TYPE_CURSOR: + if (!process_cursor_plane_assignment (impl, update, + plane_assignment, + &error)) + { + *plane_feedback = + meta_kms_plane_feedback_new_take_error (plane, + plane_assignment->crtc, + g_steal_pointer (&error)); + return FALSE; + } + else + { + return TRUE; + } + case META_KMS_PLANE_TYPE_OVERLAY: + error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, + "Overlay planes cannot be assigned"); + *plane_feedback = + meta_kms_plane_feedback_new_take_error (plane, + plane_assignment->crtc, + g_steal_pointer (&error)); + return TRUE; + } + + g_assert_not_reached (); +} + +static GList * +process_plane_assignments (MetaKmsImpl *impl, + MetaKmsUpdate *update) +{ + GList *failed_planes = NULL; + GList *l; + + for (l = meta_kms_update_get_plane_assignments (update); l; l = l->next) + { + MetaKmsPlaneAssignment *plane_assignment = l->data; + MetaKmsPlaneFeedback *plane_feedback; + + if (!process_plane_assignment (impl, update, plane_assignment, + &plane_feedback)) + failed_planes = g_list_prepend (failed_planes, plane_feedback); + } + + return failed_planes; +} + +static GList * +generate_all_failed_feedbacks (MetaKmsUpdate *update) +{ + GList *failed_planes = NULL; + GList *l; + + for (l = meta_kms_update_get_plane_assignments (update); l; l = l->next) + { + MetaKmsPlaneAssignment *plane_assignment = l->data; + MetaKmsPlane *plane; + MetaKmsPlaneType plane_type; + MetaKmsPlaneFeedback *plane_feedback; + + plane = plane_assignment->plane; + plane_type = meta_kms_plane_get_plane_type (plane); + switch (plane_type) + { + case META_KMS_PLANE_TYPE_PRIMARY: + continue; + case META_KMS_PLANE_TYPE_CURSOR: + case META_KMS_PLANE_TYPE_OVERLAY: + break; + } + + plane_feedback = + meta_kms_plane_feedback_new_take_error (plane_assignment->plane, + plane_assignment->crtc, + g_error_new (G_IO_ERROR, + G_IO_ERROR_FAILED, + "Discarded")); + failed_planes = g_list_prepend (failed_planes, plane_feedback); + } + + return failed_planes; +} + static MetaKmsFeedback * meta_kms_impl_simple_process_update (MetaKmsImpl *impl, MetaKmsUpdate *update) { GError *error = NULL; + GList *failed_planes; GList *l; meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl)); @@ -761,32 +906,43 @@ meta_kms_impl_simple_process_update (MetaKmsImpl *impl, meta_kms_update_get_connector_properties (update), process_connector_property, &error)) - goto discard_page_flips; + goto err_planes_not_assigned; if (!process_entries (impl, update, meta_kms_update_get_mode_sets (update), process_mode_set, &error)) - goto discard_page_flips; + goto err_planes_not_assigned; if (!process_entries (impl, update, meta_kms_update_get_crtc_gammas (update), process_crtc_gamma, &error)) - goto discard_page_flips; + goto err_planes_not_assigned; + + failed_planes = process_plane_assignments (impl, update); + if (failed_planes) + { + g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to assign one or more planes"); + goto err_planes_assigned; + } if (!process_entries (impl, update, meta_kms_update_get_page_flips (update), process_page_flip, &error)) - goto discard_page_flips; + goto err_planes_assigned; return meta_kms_feedback_new_passed (); -discard_page_flips: +err_planes_not_assigned: + failed_planes = generate_all_failed_feedbacks (update); + +err_planes_assigned: for (l = meta_kms_update_get_page_flips (update); l; l = l->next) { MetaKmsPageFlip *page_flip = l->data; @@ -794,7 +950,7 @@ discard_page_flips: discard_page_flip (impl, update, page_flip); } - return meta_kms_feedback_new_failed (error); + return meta_kms_feedback_new_failed (failed_planes, error); } static void diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h index f1046fb22..91a1de6dc 100644 --- a/src/backends/native/meta-kms-update-private.h +++ b/src/backends/native/meta-kms-update-private.h @@ -30,6 +30,7 @@ typedef struct _MetaKmsFeedback { MetaKmsFeedbackResult result; + GList *failed_planes; GError *error; } MetaKmsFeedback; @@ -85,9 +86,16 @@ typedef struct _MetaKmsPageFlip gpointer custom_page_flip_user_data; } MetaKmsPageFlip; +void meta_kms_plane_feedback_free (MetaKmsPlaneFeedback *plane_feedback); + +MetaKmsPlaneFeedback * meta_kms_plane_feedback_new_take_error (MetaKmsPlane *plane, + MetaKmsCrtc *crtc, + GError *error); + MetaKmsFeedback * meta_kms_feedback_new_passed (void); -MetaKmsFeedback * meta_kms_feedback_new_failed (GError *error); +MetaKmsFeedback * meta_kms_feedback_new_failed (GList *failed_planes, + GError *error); void meta_kms_update_seal (MetaKmsUpdate *update); @@ -122,4 +130,7 @@ GList * meta_kms_update_get_connector_properties (MetaKmsUpdate *update); GList * meta_kms_update_get_crtc_gammas (MetaKmsUpdate *update); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaKmsPlaneFeedback, + meta_kms_plane_feedback_free) + #endif /* META_KMS_UPDATE_PRIVATE_H */ diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c index ffabc948f..0371782b7 100644 --- a/src/backends/native/meta-kms-update.c +++ b/src/backends/native/meta-kms-update.c @@ -37,6 +37,30 @@ struct _MetaKmsUpdate GList *crtc_gammas; }; +void +meta_kms_plane_feedback_free (MetaKmsPlaneFeedback *plane_feedback) +{ + g_error_free (plane_feedback->error); + g_free (plane_feedback); +} + +MetaKmsPlaneFeedback * +meta_kms_plane_feedback_new_take_error (MetaKmsPlane *plane, + MetaKmsCrtc *crtc, + GError *error) +{ + MetaKmsPlaneFeedback *plane_feedback; + + plane_feedback = g_new0 (MetaKmsPlaneFeedback, 1); + *plane_feedback = (MetaKmsPlaneFeedback) { + .plane = plane, + .crtc = crtc, + .error = error, + }; + + return plane_feedback; +} + MetaKmsFeedback * meta_kms_feedback_new_passed (void) { @@ -51,7 +75,8 @@ meta_kms_feedback_new_passed (void) } MetaKmsFeedback * -meta_kms_feedback_new_failed (GError *error) +meta_kms_feedback_new_failed (GList *failed_planes, + GError *error) { MetaKmsFeedback *feedback; @@ -59,6 +84,7 @@ meta_kms_feedback_new_failed (GError *error) *feedback = (MetaKmsFeedback) { .result = META_KMS_FEEDBACK_FAILED, .error = error, + .failed_planes = failed_planes, }; return feedback; @@ -67,6 +93,8 @@ meta_kms_feedback_new_failed (GError *error) void meta_kms_feedback_free (MetaKmsFeedback *feedback) { + g_list_free_full (feedback->failed_planes, + (GDestroyNotify) meta_kms_plane_feedback_free); g_clear_error (&feedback->error); g_free (feedback); } @@ -77,6 +105,12 @@ meta_kms_feedback_get_result (MetaKmsFeedback *feedback) return feedback->result; } +GList * +meta_kms_feedback_get_failed_planes (MetaKmsFeedback *feedback) +{ + return feedback->failed_planes; +} + const GError * meta_kms_feedback_get_error (MetaKmsFeedback *feedback) { diff --git a/src/backends/native/meta-kms-update.h b/src/backends/native/meta-kms-update.h index 9f92050e3..cd1822e4a 100644 --- a/src/backends/native/meta-kms-update.h +++ b/src/backends/native/meta-kms-update.h @@ -38,6 +38,7 @@ typedef enum _MetaKmsFeedbackResult typedef enum _MetaKmsAssignPlaneFlag { META_KMS_ASSIGN_PLANE_FLAG_NONE = 0, + META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED = 1 << 0, } MetaKmsAssignPlaneFlag; struct _MetaKmsPageFlipFeedback @@ -59,10 +60,19 @@ struct _MetaKmsPageFlipFeedback typedef int (* MetaKmsCustomPageFlipFunc) (gpointer custom_page_flip_data, gpointer user_data); +typedef struct _MetaKmsPlaneFeedback +{ + MetaKmsPlane *plane; + MetaKmsCrtc *crtc; + GError *error; +} MetaKmsPlaneFeedback; + void meta_kms_feedback_free (MetaKmsFeedback *feedback); MetaKmsFeedbackResult meta_kms_feedback_get_result (MetaKmsFeedback *feedback); +GList * meta_kms_feedback_get_failed_planes (MetaKmsFeedback *feedback); + const GError * meta_kms_feedback_get_error (MetaKmsFeedback *feedback); MetaKmsUpdate * meta_kms_update_new (void);