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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2624>
This commit is contained in:
Jonas Ådahl 2022-09-14 23:18:37 +02:00 committed by Marge Bot
parent 85ef0d1a46
commit 6601c3b02a
2 changed files with 109 additions and 7 deletions

View File

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

View File

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