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>
This commit is contained in:
Jonas Ådahl 2021-06-18 15:01:35 +02:00 committed by Marge Bot
parent 3e3611d171
commit 9dcb28ffd1
5 changed files with 343 additions and 0 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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)
{
@ -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