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