tests/cursor-tests: Also test cursor rendering in screen casting
This uses the ref test infrastructure inside the cursor tests screen cast client, and verifies the content on the screen cast matches the content of the compositor, both when using the 'embedded' cursor mode, and the 'metadata' cursor mode. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3859>
This commit is contained in:
parent
bcb52960db
commit
a9a4923c03
166
src/tests/cursor-tests-screen-cast-client.c
Normal file
166
src/tests/cursor-tests-screen-cast-client.c
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "tests/remote-desktop-utils.h"
|
||||
|
||||
#include "tests/meta-ref-test-utils.h"
|
||||
|
||||
static MetaReftestFlag
|
||||
reftest_flags_from_string (const char *flags)
|
||||
{
|
||||
if (strcmp (flags, "update-ref") == 0)
|
||||
return META_REFTEST_FLAG_UPDATE_REF;
|
||||
g_assert_cmpstr (flags, ==, "");
|
||||
return META_REFTEST_FLAG_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_cursor (cairo_t *cr,
|
||||
struct spa_meta_cursor *spa_cursor)
|
||||
{
|
||||
struct spa_meta_bitmap *spa_bitmap;
|
||||
cairo_surface_t *cursor_image;
|
||||
|
||||
spa_bitmap = SPA_MEMBER (spa_cursor, spa_cursor->bitmap_offset,
|
||||
struct spa_meta_bitmap);
|
||||
g_assert_nonnull (spa_bitmap);
|
||||
|
||||
cursor_image =
|
||||
cairo_image_surface_create_for_data (SPA_MEMBER (spa_bitmap,
|
||||
spa_bitmap->offset,
|
||||
uint8_t),
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
spa_bitmap->size.width,
|
||||
spa_bitmap->size.height,
|
||||
spa_bitmap->stride);
|
||||
cairo_surface_mark_dirty (cursor_image);
|
||||
|
||||
cairo_set_source_surface (cr, cursor_image,
|
||||
spa_cursor->position.x - spa_cursor->hotspot.x,
|
||||
spa_cursor->position.y - spa_cursor->hotspot.y);
|
||||
cairo_paint (cr);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
screen_cast_adaptor_capture (gpointer adaptor_data)
|
||||
{
|
||||
Stream *stream = adaptor_data;
|
||||
struct spa_buffer *spa_buffer;
|
||||
cairo_surface_t *source_image;
|
||||
cairo_surface_t *surface;
|
||||
struct spa_meta_cursor *spa_cursor;
|
||||
cairo_t *cr;
|
||||
|
||||
g_assert_nonnull (stream->buffer);
|
||||
|
||||
spa_buffer = stream->buffer->buffer;
|
||||
g_assert_nonnull (spa_buffer->datas[0].data);
|
||||
|
||||
source_image =
|
||||
cairo_image_surface_create_for_data (spa_buffer->datas[0].data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
stream->spa_format.size.width,
|
||||
stream->spa_format.size.height,
|
||||
spa_buffer->datas[0].chunk->stride);
|
||||
cairo_surface_mark_dirty (source_image);
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
stream->spa_format.size.width,
|
||||
stream->spa_format.size.height);
|
||||
cr = cairo_create (surface);
|
||||
cairo_set_source_surface (cr, source_image, 0.0, 0.0);
|
||||
cairo_paint (cr);
|
||||
|
||||
spa_cursor = spa_buffer_find_meta_data (spa_buffer, SPA_META_Cursor,
|
||||
sizeof (*spa_cursor));
|
||||
|
||||
switch (stream->cursor_mode)
|
||||
{
|
||||
case CURSOR_MODE_HIDDEN:
|
||||
case CURSOR_MODE_EMBEDDED:
|
||||
g_assert_false (spa_meta_cursor_is_valid (spa_cursor));
|
||||
break;
|
||||
case CURSOR_MODE_METADATA:
|
||||
g_assert_true (spa_meta_cursor_is_valid (spa_cursor));
|
||||
draw_cursor (cr, spa_cursor);
|
||||
break;
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
ScreenCast *screen_cast;
|
||||
Session *session;
|
||||
Stream *stream;
|
||||
const char *test_name;
|
||||
int test_seq;
|
||||
CursorMode cursor_mode;
|
||||
MetaReftestFlag ref_test_flags;
|
||||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_assert_cmpint (argc, ==, 5);
|
||||
|
||||
test_name = argv[1];
|
||||
test_seq = atoi (argv[2]);
|
||||
cursor_mode = cursor_mode_from_string (argv[3]);
|
||||
ref_test_flags = reftest_flags_from_string (argv[4]);
|
||||
|
||||
g_debug ("Verifying screen cast cursor mode %s for test case %s",
|
||||
argv[2], test_name);
|
||||
|
||||
g_debug ("Initializing PipeWire");
|
||||
init_pipewire ();
|
||||
|
||||
g_debug ("Creating screen cast session");
|
||||
screen_cast = screen_cast_new ();
|
||||
session = screen_cast_create_session (NULL, screen_cast);
|
||||
stream = session_record_monitor (session, NULL, cursor_mode);
|
||||
|
||||
g_debug ("Starting screen cast stream");
|
||||
session_start (session);
|
||||
|
||||
stream_wait_for_render (stream);
|
||||
|
||||
meta_ref_test_verify (screen_cast_adaptor_capture,
|
||||
stream,
|
||||
test_name,
|
||||
test_seq,
|
||||
ref_test_flags);
|
||||
|
||||
g_debug ("Stopping session");
|
||||
|
||||
session_stop (session);
|
||||
stream_free (stream);
|
||||
session_free (session);
|
||||
screen_cast_free (screen_cast);
|
||||
|
||||
release_pipewire ();
|
||||
|
||||
g_debug ("Done");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
#include "backends/meta-cursor-sprite-xcursor.h"
|
||||
#include "backends/meta-cursor-tracker-private.h"
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/meta-screen-cast.h"
|
||||
#include "clutter/clutter.h"
|
||||
#include "compositor/meta-window-actor-private.h"
|
||||
#include "core/meta-fraction.h"
|
||||
@ -254,6 +255,52 @@ layout_mode_to_string (MetaLogicalMonitorLayoutMode layout_mode)
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static const char *
|
||||
cursor_mode_to_string (MetaScreenCastCursorMode cursor_mode)
|
||||
{
|
||||
switch (cursor_mode)
|
||||
{
|
||||
case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
|
||||
return "hidden";
|
||||
case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
|
||||
return "embedded";
|
||||
case META_SCREEN_CAST_CURSOR_MODE_METADATA:
|
||||
return "metadata";
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static const char *
|
||||
reftest_flags_to_string (MetaReftestFlag flags)
|
||||
{
|
||||
if (flags & META_REFTEST_FLAG_UPDATE_REF)
|
||||
return "update-ref";
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
static void
|
||||
verify_screen_cast_content (const char *ref_test_name,
|
||||
int test_seq_no,
|
||||
MetaScreenCastCursorMode cursor_mode)
|
||||
{
|
||||
g_autoptr (GSubprocess) subprocess = NULL;
|
||||
g_autofree char *test_seq_no_string = NULL;
|
||||
MetaReftestFlag reftest_flags;
|
||||
|
||||
test_seq_no_string = g_strdup_printf ("%d", test_seq_no);
|
||||
reftest_flags = META_REFTEST_FLAG_NONE;
|
||||
subprocess =
|
||||
meta_launch_test_executable ("mutter-cursor-tests-screen-cast-client",
|
||||
ref_test_name,
|
||||
test_seq_no_string,
|
||||
cursor_mode_to_string (cursor_mode),
|
||||
reftest_flags_to_string (reftest_flags),
|
||||
NULL);
|
||||
meta_wait_test_process (subprocess);
|
||||
}
|
||||
|
||||
static void
|
||||
wait_for_no_windows (void)
|
||||
{
|
||||
@ -318,6 +365,13 @@ test_client_cursor (ClutterStageView *view,
|
||||
ref_test_seq,
|
||||
ref_test_flags);
|
||||
|
||||
verify_screen_cast_content (ref_test_name,
|
||||
ref_test_seq,
|
||||
META_SCREEN_CAST_CURSOR_MODE_EMBEDDED);
|
||||
verify_screen_cast_content (ref_test_name,
|
||||
ref_test_seq,
|
||||
META_SCREEN_CAST_CURSOR_MODE_METADATA);
|
||||
|
||||
meta_wayland_test_driver_emit_sync_event (test_driver, 0);
|
||||
|
||||
g_object_add_weak_pointer (G_OBJECT (window_actor),
|
||||
@ -397,6 +451,10 @@ meta_test_native_cursor_scaling (void)
|
||||
ref_test_name,
|
||||
0,
|
||||
meta_ref_test_determine_ref_test_flag ());
|
||||
verify_screen_cast_content (ref_test_name, 0,
|
||||
META_SCREEN_CAST_CURSOR_MODE_EMBEDDED);
|
||||
verify_screen_cast_content (ref_test_name, 0,
|
||||
META_SCREEN_CAST_CURSOR_MODE_METADATA);
|
||||
|
||||
test_client_cursor (view,
|
||||
CURSOR_SCALE_METHOD_BUFFER_SCALE,
|
||||
|
@ -390,6 +390,33 @@ input_capture_client = executable('mutter-input-capture-test-client',
|
||||
install_dir: mutter_installed_tests_libexecdir,
|
||||
)
|
||||
|
||||
reftest_deps = [
|
||||
cairo_dep,
|
||||
glib_dep,
|
||||
]
|
||||
|
||||
cursor_screen_cast_client = executable('mutter-cursor-tests-screen-cast-client',
|
||||
sources: [
|
||||
'cursor-tests-screen-cast-client.c',
|
||||
'meta-ref-test-utils.c',
|
||||
'meta-ref-test-utils.h',
|
||||
remote_desktop_utils,
|
||||
],
|
||||
include_directories: tests_includes,
|
||||
c_args: [
|
||||
tests_c_args,
|
||||
'-DG_LOG_DOMAIN="mutter-cursor-tests-screen-cast-client"',
|
||||
],
|
||||
dependencies: [
|
||||
gio_dep,
|
||||
libpipewire_dep,
|
||||
reftest_deps,
|
||||
],
|
||||
install: have_installed_tests,
|
||||
install_dir: mutter_installed_tests_libexecdir,
|
||||
install_rpath: pkglibdir,
|
||||
)
|
||||
|
||||
# Native backend tests
|
||||
test_cases += [
|
||||
{
|
||||
@ -462,6 +489,7 @@ test_cases += [
|
||||
],
|
||||
'depends': [
|
||||
test_client_executables.get('cursor-tests-client'),
|
||||
cursor_screen_cast_client,
|
||||
]
|
||||
},
|
||||
]
|
||||
|
@ -430,6 +430,16 @@ stream_resize (Stream *stream,
|
||||
params, G_N_ELEMENTS (params));
|
||||
}
|
||||
|
||||
void
|
||||
stream_wait_for_render (Stream *stream)
|
||||
{
|
||||
int initial_buffer_count = stream->buffer_count;
|
||||
|
||||
g_debug ("Waiting for new buffer");
|
||||
while (stream->buffer_count == initial_buffer_count)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
on_pipewire_stream_added (MetaDBusScreenCastStream *proxy,
|
||||
unsigned int node_id,
|
||||
|
@ -82,6 +82,19 @@ typedef struct _ScreenCast
|
||||
g_assert_cmpint (stream->cursor_y, ==, (y)); \
|
||||
}
|
||||
|
||||
static inline CursorMode
|
||||
cursor_mode_from_string (const char *name)
|
||||
{
|
||||
if (strcmp (name, "hidden") == 0)
|
||||
return CURSOR_MODE_HIDDEN;
|
||||
else if (strcmp (name, "embedded") == 0)
|
||||
return CURSOR_MODE_EMBEDDED;
|
||||
else if (strcmp (name, "metadata") == 0)
|
||||
return CURSOR_MODE_METADATA;
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
void release_pipewire (void);
|
||||
|
||||
void init_pipewire (void);
|
||||
@ -90,6 +103,8 @@ void stream_resize (Stream *stream,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
void stream_wait_for_render (Stream *stream);
|
||||
|
||||
void stream_free (Stream *stream);
|
||||
|
||||
void session_notify_absolute_pointer (Session *session,
|
||||
|
@ -45,16 +45,6 @@ stream_wait_for_streaming (Stream *stream)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
stream_wait_for_render (Stream *stream)
|
||||
{
|
||||
int initial_buffer_count = stream->buffer_count;
|
||||
|
||||
g_debug ("Waiting for new buffer");
|
||||
while (stream->buffer_count == initial_buffer_count)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
|
Loading…
x
Reference in New Issue
Block a user