tests/kms/render: Add test for scanout failure handling

Make sure we repaint correctly if direct scanout updates fail.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2854>
This commit is contained in:
Jonas Ådahl 2022-06-10 23:21:10 +02:00 committed by Marge Bot
parent fb622974b9
commit 2dfbbf0068
4 changed files with 173 additions and 1 deletions

View File

@ -165,6 +165,7 @@ void meta_kms_plane_assignment_set_cursor_hotspot (MetaKmsPlaneAssignment *plane
int x,
int y);
META_EXPORT_TEST
void meta_kms_update_add_result_listener (MetaKmsUpdate *update,
MetaKmsResultListenerFunc func,
gpointer user_data);

View File

@ -36,6 +36,7 @@ G_DECLARE_FINAL_TYPE (MetaKms, meta_kms, META, KMS, GObject)
void meta_kms_discard_pending_updates (MetaKms *kms);
META_EXPORT_TEST
MetaKmsUpdate * meta_kms_ensure_pending_update (MetaKms *kms,
MetaKmsDevice *device);

View File

@ -567,7 +567,10 @@ if have_kvm_tests or have_tty_tests
tests_c_args,
'-DG_LOG_DOMAIN="mutter-@0@-test"'.format(test_case['name']),
],
dependencies: libmutter_test_dep,
dependencies: [
libmutter_test_dep,
drm_mock_dep
],
install: have_installed_tests,
install_dir: mutter_installed_tests_libexecdir,
install_rpath: pkglibdir,

View File

@ -29,9 +29,12 @@
#include "backends/native/meta-onscreen-native.h"
#include "backends/native/meta-kms.h"
#include "backends/native/meta-kms-device.h"
#include "backends/native/meta-kms-device-private.h"
#include "backends/native/meta-kms-impl-device-atomic.h"
#include "core/display-private.h"
#include "meta/meta-backend.h"
#include "meta-test/meta-context-test.h"
#include "tests/drm-mock/drm-mock.h"
#include "tests/meta-test-utils.h"
#include "tests/meta-wayland-test-driver.h"
#include "tests/meta-wayland-test-utils.h"
@ -47,10 +50,27 @@ typedef struct
} scanout;
gboolean wait_for_scanout;
struct {
gboolean scanout_sabotaged;
gboolean fallback_painted;
guint repaint_guard_id;
ClutterStageView *scanout_failed_view;
} scanout_fallback;
} KmsRenderingTest;
static MetaContext *test_context;
static gboolean
is_atomic_mode_setting (MetaKmsDevice *kms_device)
{
MetaKmsImplDevice *kms_impl_device;
kms_impl_device = meta_kms_device_get_impl_device (kms_device);
return META_IS_KMS_IMPL_DEVICE_ATOMIC (kms_impl_device);
}
static void
on_after_update (ClutterStage *stage,
ClutterStageView *stage_view,
@ -292,6 +312,151 @@ meta_test_kms_render_client_scanout (void)
g_main_loop_unref (test.loop);
}
static gboolean
needs_repainted_guard (gpointer user_data)
{
g_assert_not_reached ();
return G_SOURCE_REMOVE;
}
static void
on_scanout_fallback_result (const MetaKmsFeedback *kms_feedback,
gpointer user_data)
{
KmsRenderingTest *test = user_data;
g_assert_cmpuint (test->scanout_fallback.repaint_guard_id, ==, 0);
g_assert_nonnull (test->scanout_fallback.scanout_failed_view);
test->scanout_fallback.repaint_guard_id =
g_idle_add_full (G_PRIORITY_LOW, needs_repainted_guard, test, NULL);
}
static void
on_scanout_fallback_before_paint (ClutterStage *stage,
ClutterStageView *stage_view,
ClutterFrame *frame,
KmsRenderingTest *test)
{
MetaRendererView *view = META_RENDERER_VIEW (stage_view);
MetaCrtc *crtc = meta_renderer_view_get_crtc (view);
MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
MetaKms *kms = meta_kms_device_get_kms (kms_device);
CoglScanout *scanout;
MetaKmsUpdate *kms_update;
scanout = clutter_stage_view_peek_scanout (stage_view);
if (!scanout)
return;
g_assert_false (test->scanout_fallback.scanout_sabotaged);
if (is_atomic_mode_setting (kms_device))
{
drm_mock_queue_error (DRM_MOCK_CALL_ATOMIC_COMMIT, EINVAL);
}
else
{
drm_mock_queue_error (DRM_MOCK_CALL_PAGE_FLIP, EINVAL);
drm_mock_queue_error (DRM_MOCK_CALL_SET_CRTC, EINVAL);
}
test->scanout_fallback.scanout_sabotaged = TRUE;
kms_update = meta_kms_ensure_pending_update (kms, kms_device);
meta_kms_update_add_result_listener (kms_update,
on_scanout_fallback_result, test);
test->scanout_fallback.scanout_failed_view = stage_view;
}
static void
on_scanout_fallback_paint_view (ClutterStage *stage,
ClutterStageView *stage_view,
cairo_region_t *region,
ClutterFrame *frame,
KmsRenderingTest *test)
{
if (test->scanout_fallback.scanout_sabotaged)
{
g_assert_cmpuint (test->scanout_fallback.repaint_guard_id, !=, 0);
g_clear_handle_id (&test->scanout_fallback.repaint_guard_id,
g_source_remove);
test->scanout_fallback.fallback_painted = TRUE;
}
}
static void
on_scanout_fallback_presented (ClutterStage *stage,
ClutterStageView *stage_view,
ClutterFrameInfo *frame_info,
KmsRenderingTest *test)
{
if (!test->scanout_fallback.scanout_sabotaged)
return;
g_assert_true (test->scanout_fallback.fallback_painted);
g_main_loop_quit (test->loop);
}
static void
meta_test_kms_render_client_scanout_fallback (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);
MetaKms *kms = meta_backend_native_get_kms (META_BACKEND_NATIVE (backend));
MetaKmsDevice *kms_device = meta_kms_get_devices (kms)->data;
KmsRenderingTest test;
MetaWaylandTestClient *wayland_test_client;
g_autoptr (MetaWaylandTestDriver) test_driver = NULL;
gulong before_paint_handler_id;
gulong paint_view_handler_id;
gulong presented_handler_id;
test_driver = meta_wayland_test_driver_new (wayland_compositor);
meta_wayland_test_driver_set_property (test_driver,
"gpu-path",
meta_kms_device_get_path (kms_device));
wayland_test_client =
meta_wayland_test_client_new (test_context, "dma-buf-scanout");
g_assert_nonnull (wayland_test_client);
test = (KmsRenderingTest) {
.loop = g_main_loop_new (NULL, FALSE),
};
before_paint_handler_id =
g_signal_connect (stage, "before-paint",
G_CALLBACK (on_scanout_fallback_before_paint), &test);
paint_view_handler_id =
g_signal_connect (stage, "paint-view",
G_CALLBACK (on_scanout_fallback_paint_view), &test);
presented_handler_id =
g_signal_connect (stage, "presented",
G_CALLBACK (on_scanout_fallback_presented), &test);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
g_test_expect_message ("libmutter", G_LOG_LEVEL_WARNING,
"*Direct scanout page flip failed*");
g_main_loop_run (test.loop);
g_main_loop_unref (test.loop);
g_test_assert_expected_messages ();
g_signal_handler_disconnect (stage, before_paint_handler_id);
g_signal_handler_disconnect (stage, paint_view_handler_id);
g_signal_handler_disconnect (stage, presented_handler_id);
meta_wayland_test_driver_emit_sync_event (test_driver, 0);
meta_wayland_test_client_finish (wayland_test_client);
}
static void
init_tests (void)
{
@ -299,6 +464,8 @@ init_tests (void)
meta_test_kms_render_basic);
g_test_add_func ("/backends/native/kms/render/client-scanout",
meta_test_kms_render_client_scanout);
g_test_add_func ("/backends/native/kms/render/client-scanout-fallabck",
meta_test_kms_render_client_scanout_fallback);
}
int