summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Ã…dahl <jadahl@gmail.com>2021-06-18 15:01:35 +0200
committerMarge Bot <marge-bot@gnome.org>2023-03-01 23:57:32 +0000
commit9dcb28ffd1cdf2fca7c5bcfc425717c5f75862c8 (patch)
treea66d05743402805b179057c474a14510fd5e93f0
parent3e3611d1712b353ac48c7ca4a1344301c91e4934 (diff)
downloadmutter-9dcb28ffd1cdf2fca7c5bcfc425717c5f75862c8.tar.gz
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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2854>
-rw-r--r--src/backends/meta-crtc.h1
-rw-r--r--src/backends/native/meta-kms-update-private.h4
-rw-r--r--src/backends/native/meta-kms-update.c148
-rw-r--r--src/backends/native/meta-kms-update.h1
-rw-r--r--src/tests/native-kms-updates.c189
5 files changed, 343 insertions, 0 deletions
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 <dlfcn.h>
+
#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)
{
@@ -369,6 +392,170 @@ meta_test_kms_update_page_flip (void)
}
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)
{
g_test_add_func ("/backends/native/kms/update/sanity",
@@ -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