From 6601c3b02ab9d3fddce71c26618138122bc3fe7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 14 Sep 2022 23:18:37 +0200 Subject: [PATCH] tests: Add partial-overlapping scanout test Make sure that if we wiggle a scan-out capable surface a bit, it won't scan out if it's not exactly in the right position. Do this by first making the window not fullscreen, then moving it back and forth, verifying the correct scanout state for each presented frame. This test addition reproduces the issue described in https://gitlab.gnome.org/GNOME/mutter/-/issues/2387. Part-of: --- src/tests/native-kms-render.c | 70 +++++++++++++++++-- .../wayland-test-clients/dma-buf-scanout.c | 46 +++++++++++- 2 files changed, 109 insertions(+), 7 deletions(-) diff --git a/src/tests/native-kms-render.c b/src/tests/native-kms-render.c index 278edf4bd..6595eb5a2 100644 --- a/src/tests/native-kms-render.c +++ b/src/tests/native-kms-render.c @@ -32,6 +32,7 @@ #include "core/display-private.h" #include "meta/meta-backend.h" #include "meta-test/meta-context-test.h" +#include "tests/meta-test-utils.h" #include "tests/meta-wayland-test-driver.h" #include "tests/meta-wayland-test-utils.h" @@ -44,6 +45,8 @@ typedef struct int n_paints; uint32_t fb_id; } scanout; + + gboolean wait_for_scanout; } KmsRenderingTest; static MetaContext *test_context; @@ -139,7 +142,7 @@ on_scanout_presented (ClutterStage *stage, if (test->scanout.n_paints > 0) return; - if (test->scanout.fb_id == 0) + if (test->wait_for_scanout && test->scanout.fb_id == 0) return; device_pool = meta_backend_native_get_device_pool (backend_native); @@ -159,7 +162,10 @@ on_scanout_presented (ClutterStage *stage, drm_crtc = drmModeGetCrtc (meta_device_file_get_fd (device_file), meta_kms_crtc_get_id (kms_crtc)); g_assert_nonnull (drm_crtc); - g_assert_cmpuint (drm_crtc->buffer_id, ==, test->scanout.fb_id); + if (test->scanout.fb_id == 0) + g_assert_cmpuint (drm_crtc->buffer_id, !=, test->scanout.fb_id); + else + g_assert_cmpuint (drm_crtc->buffer_id, ==, test->scanout.fb_id); drmModeFreeCrtc (drm_crtc); meta_device_file_release (device_file); @@ -167,13 +173,19 @@ on_scanout_presented (ClutterStage *stage, g_main_loop_quit (test->loop); } +typedef enum +{ + SCANOUT_WINDOW_STATE_NONE, + SCANOUT_WINDOW_STATE_FULLSCREEN, +} ScanoutWindowState; + static void meta_test_kms_render_client_scanout (void) { MetaBackend *backend = meta_context_get_backend (test_context); MetaWaylandCompositor *wayland_compositor = meta_context_get_wayland_compositor (test_context); - ClutterActor *stage = meta_backend_get_stage (backend); + ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); MetaKms *kms = meta_backend_native_get_kms (META_BACKEND_NATIVE (backend)); MetaKmsDevice *kms_device = meta_kms_get_devices (kms)->data; KmsRenderingTest test; @@ -183,6 +195,9 @@ meta_test_kms_render_client_scanout (void) gulong before_paint_handler_id; gulong paint_view_handler_id; gulong presented_handler_id; + MetaWindow *window; + MetaRectangle view_rect; + MetaRectangle buffer_rect; test_driver = meta_wayland_test_driver_new (wayland_compositor); meta_wayland_test_driver_set_property (test_driver, @@ -195,8 +210,15 @@ meta_test_kms_render_client_scanout (void) test = (KmsRenderingTest) { .loop = g_main_loop_new (NULL, FALSE), + .wait_for_scanout = TRUE, }; + g_assert_cmpuint (g_list_length (clutter_stage_peek_stage_views (stage)), + ==, + 1); + clutter_stage_view_get_layout (clutter_stage_peek_stage_views (stage)->data, + &view_rect); + paint_view_handler_id = g_signal_connect (stage, "paint-view", G_CALLBACK (on_scanout_paint_view), &test); @@ -212,7 +234,46 @@ meta_test_kms_render_client_scanout (void) clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); g_main_loop_run (test.loop); - g_main_loop_unref (test.loop); + + g_assert_cmpuint (test.scanout.fb_id, >, 0); + + g_debug ("Unmake fullscreen"); + window = meta_find_window_from_title (test_context, "dma-buf-scanout-test"); + g_assert_true (meta_window_is_fullscreen (window)); + meta_window_unmake_fullscreen (window); + + g_debug ("Wait for fullscreen"); + meta_wayland_test_driver_wait_for_sync_point (test_driver, + SCANOUT_WINDOW_STATE_NONE); + g_assert_false (meta_window_is_fullscreen (window)); + + g_debug ("Moving to 10, 10"); + meta_window_move_frame (window, TRUE, 10, 10); + + meta_window_get_buffer_rect (window, &buffer_rect); + g_assert_cmpint (buffer_rect.width, ==, view_rect.width); + g_assert_cmpint (buffer_rect.height, ==, view_rect.height); + g_assert_cmpint (buffer_rect.x, ==, 10); + g_assert_cmpint (buffer_rect.y, ==, 10); + + test.wait_for_scanout = FALSE; + clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); + g_main_loop_run (test.loop); + + g_assert_cmpuint (test.scanout.fb_id, ==, 0); + + g_debug ("Moving back to 0, 0"); + meta_window_move_frame (window, TRUE, 0, 0); + + meta_window_get_buffer_rect (window, &buffer_rect); + g_assert_cmpint (buffer_rect.width, ==, view_rect.width); + g_assert_cmpint (buffer_rect.height, ==, view_rect.height); + g_assert_cmpint (buffer_rect.x, ==, 0); + g_assert_cmpint (buffer_rect.y, ==, 0); + + test.wait_for_scanout = TRUE; + clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); + g_main_loop_run (test.loop); g_assert_cmpuint (test.scanout.fb_id, >, 0); @@ -223,6 +284,7 @@ meta_test_kms_render_client_scanout (void) meta_wayland_test_driver_emit_sync_event (test_driver, 0); meta_wayland_test_client_finish (wayland_test_client); + g_main_loop_unref (test.loop); } static void diff --git a/src/tests/wayland-test-clients/dma-buf-scanout.c b/src/tests/wayland-test-clients/dma-buf-scanout.c index 25b906696..273413f43 100644 --- a/src/tests/wayland-test-clients/dma-buf-scanout.c +++ b/src/tests/wayland-test-clients/dma-buf-scanout.c @@ -53,6 +53,12 @@ #include "linux-dmabuf-unstable-v1-client-protocol.h" +typedef enum +{ + WINDOW_STATE_NONE, + WINDOW_STATE_FULLSCREEN, +} WindowState; + typedef struct _Buffer { struct wl_buffer *buffer; @@ -78,6 +84,10 @@ struct gbm_device *gbm_device; static GList *active_buffers; +static int prev_width; +static int prev_height; +static WindowState window_state; + static struct { uint32_t format; @@ -214,15 +224,44 @@ draw_main (int width, wl_surface_attach (surface, buffer->buffer, 0, 0); } +static WindowState +parse_xdg_toplevel_state (struct wl_array *states) +{ + uint32_t *state_ptr; + + wl_array_for_each (state_ptr, states) + { + uint32_t state = *state_ptr; + + if (state == XDG_TOPLEVEL_STATE_FULLSCREEN) + return WINDOW_STATE_FULLSCREEN; + } + + return WINDOW_STATE_NONE; +} + static void handle_xdg_toplevel_configure (void *user_data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, - struct wl_array *state) + struct wl_array *states) { - g_assert_cmpint (width, >, 0); - g_assert_cmpint (height, >, 0); + g_assert (width > 0 || prev_width > 0); + g_assert (height > 0 || prev_width > 0); + + if (width > 0 && height > 0) + { + prev_width = width; + prev_height = height; + } + else + { + width = prev_width; + height = prev_height; + } + + window_state = parse_xdg_toplevel_state (states); draw_main (width, height); } @@ -270,6 +309,7 @@ handle_xdg_surface_configure (void *user_data, frame_callback = wl_surface_frame (surface); wl_callback_add_listener (frame_callback, &frame_listener, NULL); wl_surface_commit (surface); + test_driver_sync_point (display->test_driver, window_state, NULL); wl_display_flush (display->display); }