From 9dcb28ffd1cdf2fca7c5bcfc425717c5f75862c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 18 Jun 2021 15:01:35 +0200 Subject: [PATCH] kms/update: Add API to merge two updates This is intended to be used only for plane assignment, and CRTC like changes, so that one can e.g. change a cursor plane on a pending update that changes the primary plane, before it has been committed to KMS. The kms-updates test overrides the get-state function MetaKmsCrtc. This is needd to not have the update mechanism not clamp the gamma size to 0, as vkms reports the gamma length 0. By pretending it's 3, we can test a simple and small gamma lut is merged correctly when merging updates. Part-of: --- src/backends/meta-crtc.h | 1 + src/backends/native/meta-kms-update-private.h | 4 + src/backends/native/meta-kms-update.c | 148 ++++++++++++++ src/backends/native/meta-kms-update.h | 1 + src/tests/native-kms-updates.c | 189 ++++++++++++++++++ 5 files changed, 343 insertions(+) diff --git a/src/backends/meta-crtc.h b/src/backends/meta-crtc.h index 77b4b6bc5..0a99e0287 100644 --- a/src/backends/meta-crtc.h +++ b/src/backends/meta-crtc.h @@ -94,6 +94,7 @@ void meta_crtc_set_gamma_lut (MetaCrtc *crtc, META_EXPORT_TEST void meta_gamma_lut_free (MetaGammaLut *lut); +META_EXPORT_TEST MetaGammaLut * meta_gamma_lut_new (int size, const uint16_t *red, const uint16_t *green, diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h index 06c188d73..7a48e3e41 100644 --- a/src/backends/native/meta-kms-update-private.h +++ b/src/backends/native/meta-kms-update-private.h @@ -181,6 +181,10 @@ void meta_kms_update_drop_plane_assignment (MetaKmsUpdate *update, GList * meta_kms_update_take_result_listeners (MetaKmsUpdate *update); +META_EXPORT_TEST +void meta_kms_update_merge_from (MetaKmsUpdate *update, + MetaKmsUpdate *other_update); + void meta_kms_result_listener_notify (MetaKmsResultListener *listener, const MetaKmsFeedback *feedback); diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c index a4fbef85e..c6b090d94 100644 --- a/src/backends/native/meta-kms-update.c +++ b/src/backends/native/meta-kms-update.c @@ -671,6 +671,154 @@ meta_kms_custom_page_flip_free (MetaKmsCustomPageFlip *custom_page_flip) g_free (custom_page_flip); } +static GList * +find_plane_assignment_link_for (MetaKmsUpdate *update, + MetaKmsPlane *plane) +{ + GList *l; + + for (l = update->plane_assignments; l; l = l->next) + { + MetaKmsPlaneAssignment *plane_assignment = l->data; + + if (plane_assignment->plane == plane) + return l; + } + + return NULL; +} + +static void +merge_plane_assignments_from (MetaKmsUpdate *update, + MetaKmsUpdate *other_update) +{ + while (other_update->plane_assignments) + { + GList *l = other_update->plane_assignments; + MetaKmsPlaneAssignment *other_plane_assignment = l->data; + MetaKmsPlane *plane = other_plane_assignment->plane; + GList *el; + + other_update->plane_assignments = + g_list_remove_link (other_update->plane_assignments, l); + + el = find_plane_assignment_link_for (update, plane); + if (el) + { + meta_kms_plane_assignment_free (el->data); + update->plane_assignments = + g_list_insert_before_link (update->plane_assignments, el, l); + update->plane_assignments = + g_list_delete_link (update->plane_assignments, el); + } + else + { + update->plane_assignments = + g_list_insert_before_link (update->plane_assignments, + update->plane_assignments, + l); + } + other_plane_assignment->update = update; + } +} + +static GList * +find_color_update_link_for (MetaKmsUpdate *update, + MetaKmsCrtc *crtc) +{ + GList *l; + + for (l = update->crtc_color_updates; l; l = l->next) + { + MetaKmsCrtcColorUpdate *color_update = l->data; + + if (color_update->crtc == crtc) + return l; + } + + return NULL; +} + +static void +merge_crtc_color_updates_from (MetaKmsUpdate *update, + MetaKmsUpdate *other_update) +{ + while (other_update->crtc_color_updates) + { + GList *l = other_update->crtc_color_updates; + MetaKmsCrtcColorUpdate *other_crtc_color_update = l->data; + MetaKmsCrtc *crtc = other_crtc_color_update->crtc; + GList *el; + + other_update->crtc_color_updates = + g_list_remove_link (other_update->crtc_color_updates, l); + + el = find_color_update_link_for (update, crtc); + if (el) + { + meta_kms_crtc_color_updates_free (el->data); + update->crtc_color_updates = + g_list_insert_before_link (update->crtc_color_updates, el, l); + update->crtc_color_updates = + g_list_delete_link (update->crtc_color_updates, el); + } + else + { + update->crtc_color_updates = + g_list_insert_before_link (update->crtc_color_updates, + update->crtc_color_updates, + l); + } + } +} + +static void +merge_custom_page_flip_from (MetaKmsUpdate *update, + MetaKmsUpdate *other_update) +{ + g_warn_if_fail ((!update->custom_page_flip && + !other_update->custom_page_flip) || + ((!!update->custom_page_flip) ^ + (!!other_update->custom_page_flip))); + + g_clear_pointer (&update->custom_page_flip, meta_kms_custom_page_flip_free); + update->custom_page_flip = g_steal_pointer (&other_update->custom_page_flip); +} + +static void +merge_page_flip_listeners_from (MetaKmsUpdate *update, + MetaKmsUpdate *other_update) +{ + update->page_flip_listeners = + g_list_concat (update->page_flip_listeners, + g_steal_pointer (&other_update->page_flip_listeners)); +} + +static void +merge_result_listeners_from (MetaKmsUpdate *update, + MetaKmsUpdate *other_update) +{ + update->result_listeners = + g_list_concat (update->result_listeners, + g_steal_pointer (&other_update->result_listeners)); +} + +void +meta_kms_update_merge_from (MetaKmsUpdate *update, + MetaKmsUpdate *other_update) +{ + g_return_if_fail (update->device == other_update->device); + g_return_if_fail (!update->mode_sets && !other_update->mode_sets); + g_return_if_fail (!update->connector_updates && + !other_update->connector_updates); + + merge_plane_assignments_from (update, other_update); + merge_crtc_color_updates_from (update, other_update); + merge_custom_page_flip_from (update, other_update); + merge_page_flip_listeners_from (update, other_update); + merge_result_listeners_from (update, other_update); +} + MetaKmsUpdate * meta_kms_update_new (MetaKmsDevice *device) { diff --git a/src/backends/native/meta-kms-update.h b/src/backends/native/meta-kms-update.h index 61c148256..986eab636 100644 --- a/src/backends/native/meta-kms-update.h +++ b/src/backends/native/meta-kms-update.h @@ -121,6 +121,7 @@ void meta_kms_update_mode_set (MetaKmsUpdate *update, GList *connectors, MetaKmsMode *mode); +META_EXPORT_TEST void meta_kms_update_set_crtc_gamma (MetaKmsUpdate *update, MetaKmsCrtc *crtc, const MetaGammaLut *gamma); diff --git a/src/tests/native-kms-updates.c b/src/tests/native-kms-updates.c index b0b9aabec..231a253d1 100644 --- a/src/tests/native-kms-updates.c +++ b/src/tests/native-kms-updates.c @@ -20,6 +20,8 @@ #include "config.h" +#include + #include "backends/native/meta-kms-connector.h" #include "backends/native/meta-kms-crtc.h" #include "backends/native/meta-kms-device.h" @@ -31,6 +33,27 @@ static MetaContext *test_context; +const MetaKmsCrtcState * +meta_kms_crtc_get_current_state (MetaKmsCrtc *crtc) +{ + static MetaKmsCrtcState mock_state; + static const MetaKmsCrtcState * + (* real_get_current_state) (MetaKmsCrtc *crtc) = NULL; + const MetaKmsCrtcState *state; + + if (!real_get_current_state) + real_get_current_state = dlsym (RTLD_NEXT, __func__); + + state = real_get_current_state (crtc); + if (!state) + return NULL; + + mock_state = *state; + mock_state.gamma.size = 3; + + return &mock_state; +} + static void meta_test_kms_update_sanity (void) { @@ -368,6 +391,170 @@ meta_test_kms_update_page_flip (void) g_main_loop_unref (data.loop); } +static void +meta_test_kms_update_merge (void) +{ + MetaKmsDevice *device; + MetaKmsUpdate *update1; + MetaKmsCrtc *crtc; + MetaKmsConnector *connector; + MetaKmsPlane *primary_plane; + MetaKmsPlane *cursor_plane; + MetaKmsMode *mode; + int mode_width, mode_height; + g_autoptr (MetaDrmBuffer) primary_buffer1 = NULL; + g_autoptr (MetaDrmBuffer) cursor_buffer1 = NULL; + MetaKmsPlaneAssignment *cursor_plane_assignment; + MetaKmsUpdate *update2; + g_autoptr (MetaGammaLut) lut = NULL; + g_autoptr (MetaDrmBuffer) cursor_buffer2 = NULL; + GList *plane_assignments; + MetaKmsPlaneAssignment *plane_assignment; + GList *crtc_color_updates; + MetaKmsCrtcColorUpdate *crtc_color_update; + MetaGammaLut *crtc_gamma; + + device = meta_get_test_kms_device (test_context); + crtc = meta_get_test_kms_crtc (device); + connector = meta_get_test_kms_connector (device); + primary_plane = meta_kms_device_get_primary_plane_for (device, crtc); + cursor_plane = meta_kms_device_get_cursor_plane_for (device, crtc); + + mode = meta_kms_connector_get_preferred_mode (connector); + + /* + * Create an update1 with buffer 1 on the primary plane, and cursor buffer 1 + * on the cursor plane at at (24, 48) + */ + + update1 = meta_kms_update_new (device); + + mode_width = meta_kms_mode_get_width (mode); + mode_height = meta_kms_mode_get_height (mode); + primary_buffer1 = meta_create_test_mode_dumb_buffer (device, mode); + + meta_kms_update_assign_plane (update1, + crtc, + primary_plane, + primary_buffer1, + meta_get_mode_fixed_rect_16 (mode), + meta_get_mode_rect (mode), + META_KMS_ASSIGN_PLANE_FLAG_NONE); + + cursor_buffer1 = meta_create_test_dumb_buffer (device, 64, 64); + + cursor_plane_assignment = + meta_kms_update_assign_plane (update1, + crtc, + cursor_plane, + cursor_buffer1, + META_FIXED_16_RECTANGLE_INIT_INT (0, 0, + 64, 64), + META_RECTANGLE_INIT (24, 48, 64, 64), + META_KMS_ASSIGN_PLANE_FLAG_NONE); + meta_kms_plane_assignment_set_cursor_hotspot (cursor_plane_assignment, + 10, 11); + + /* + * Create an update2 with with cursor buffer 2 + * on the cursor plane at at (32, 56), and a new CRTC gamma. + */ + + update2 = meta_kms_update_new (device); + + lut = meta_gamma_lut_new (3, + (uint16_t[]) { 1, 2, 3 }, + (uint16_t[]) { 4, 5, 6 }, + (uint16_t[]) { 7, 8, 9 }); + meta_kms_update_set_crtc_gamma (update2, crtc, lut); + + cursor_buffer2 = meta_create_test_dumb_buffer (device, 64, 64); + cursor_plane_assignment = + meta_kms_update_assign_plane (update2, + crtc, + cursor_plane, + cursor_buffer2, + META_FIXED_16_RECTANGLE_INIT_INT (0, 0, + 64, 64), + META_RECTANGLE_INIT (32, 56, 64, 64), + META_KMS_ASSIGN_PLANE_FLAG_NONE); + meta_kms_plane_assignment_set_cursor_hotspot (cursor_plane_assignment, + 9, 7); + + /* + * Merge and check result. + */ + + meta_kms_update_merge_from (update1, update2); + meta_kms_update_free (update2); + + plane_assignments = meta_kms_update_get_plane_assignments (update1); + g_assert_cmpuint (g_list_length (plane_assignments), ==, 2); + plane_assignment = meta_kms_update_get_primary_plane_assignment (update1, + crtc); + g_assert_nonnull (plane_assignment); + g_assert (plane_assignment->update == update1); + g_assert (plane_assignment->crtc == crtc); + g_assert (plane_assignment->plane == primary_plane); + g_assert (plane_assignment->buffer == primary_buffer1); + g_assert_false (plane_assignment->cursor_hotspot.is_valid); + g_assert_cmpint (plane_assignment->src_rect.x, ==, 0); + g_assert_cmpint (plane_assignment->src_rect.y, ==, 0); + g_assert_cmpint (plane_assignment->src_rect.width, + ==, + meta_fixed_16_from_int (mode_width)); + g_assert_cmpint (plane_assignment->src_rect.height, + ==, + meta_fixed_16_from_int (mode_height)); + g_assert_cmpint (plane_assignment->dst_rect.x, ==, 0); + g_assert_cmpint (plane_assignment->dst_rect.y, ==, 0); + g_assert_cmpint (plane_assignment->dst_rect.width, ==, mode_width); + g_assert_cmpint (plane_assignment->dst_rect.height, ==, mode_height); + + plane_assignment = meta_kms_update_get_cursor_plane_assignment (update1, + crtc); + g_assert_nonnull (plane_assignment); + g_assert (plane_assignment->update == update1); + g_assert (plane_assignment->crtc == crtc); + g_assert (plane_assignment->plane == cursor_plane); + g_assert (plane_assignment->buffer == META_DRM_BUFFER (cursor_buffer2)); + g_assert_true (plane_assignment->cursor_hotspot.is_valid); + g_assert_cmpint (plane_assignment->cursor_hotspot.x, ==, 9); + g_assert_cmpint (plane_assignment->cursor_hotspot.y, ==, 7); + g_assert_cmpint (plane_assignment->src_rect.x, ==, 0); + g_assert_cmpint (plane_assignment->src_rect.y, ==, 0); + g_assert_cmpint (plane_assignment->src_rect.width, + ==, + meta_fixed_16_from_int (64)); + g_assert_cmpint (plane_assignment->src_rect.height, + ==, + meta_fixed_16_from_int (64)); + g_assert_cmpint (plane_assignment->dst_rect.x, ==, 32); + g_assert_cmpint (plane_assignment->dst_rect.y, ==, 56); + g_assert_cmpint (plane_assignment->dst_rect.width, ==, 64); + g_assert_cmpint (plane_assignment->dst_rect.height, ==, 64); + + crtc_color_updates = meta_kms_update_get_crtc_color_updates (update1); + g_assert_cmpuint (g_list_length (crtc_color_updates), ==, 1); + crtc_color_update = crtc_color_updates->data; + crtc_gamma = crtc_color_update->gamma.state; + g_assert_nonnull (crtc_gamma); + + g_assert_nonnull (crtc_gamma); + g_assert_cmpint (crtc_gamma->size, ==, 3); + g_assert_cmpuint (crtc_gamma->red[0], ==, 1); + g_assert_cmpuint (crtc_gamma->red[1], ==, 2); + g_assert_cmpuint (crtc_gamma->red[2], ==, 3); + g_assert_cmpuint (crtc_gamma->green[0], ==, 4); + g_assert_cmpuint (crtc_gamma->green[1], ==, 5); + g_assert_cmpuint (crtc_gamma->green[2], ==, 6); + g_assert_cmpuint (crtc_gamma->blue[0], ==, 7); + g_assert_cmpuint (crtc_gamma->blue[1], ==, 8); + g_assert_cmpuint (crtc_gamma->blue[2], ==, 9); + + meta_kms_update_free (update1); +} + static void init_tests (void) { @@ -381,6 +568,8 @@ init_tests (void) meta_test_kms_update_mode_sets); g_test_add_func ("/backends/native/kms/update/page-flip", meta_test_kms_update_page_flip); + g_test_add_func ("/backends/native/kms/update/merge", + meta_test_kms_update_merge); } int