tests/wayland: Add more requests to test driver protocol
Add `sync_effects_completed()` and `verify_view()` in order to allow Wayland test clients to trigger verifications and add convenience functions to use them to client-utils. Notes: - `sync_effects_completed()` works in two stages in order to ensure it doesn't race with window effects. By the time `sync_effects_completed()` is processed, an effect could already have ended or not yet been scheduled. Thus we defer a check for pending effects to the next paint cycle, assuming that by then they should have been scheduled. - `meta_ref_test_verify_view()` internally triggers the `paint` signal for the stage which is why it can not be run in the after-paint signal handler. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1055>
This commit is contained in:
parent
27dbf77d19
commit
11fc5b6c6c
@ -61,6 +61,7 @@ void meta_window_actor_frame_complete (MetaWindowActor *self,
|
||||
ClutterFrameInfo *frame_info,
|
||||
gint64 presentation_time);
|
||||
|
||||
META_EXPORT_TEST
|
||||
gboolean meta_window_actor_effect_in_progress (MetaWindowActor *self);
|
||||
|
||||
MetaWindowActorChanges meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
|
||||
|
@ -21,8 +21,11 @@
|
||||
|
||||
#include <wayland-server.h>
|
||||
|
||||
#include "compositor/meta-window-actor-private.h"
|
||||
#include "tests/meta-ref-test.h"
|
||||
#include "wayland/meta-wayland-actor-surface.h"
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
#include "wayland/meta-wayland-surface.h"
|
||||
|
||||
#include "test-driver-server-protocol.h"
|
||||
|
||||
@ -49,6 +52,12 @@ struct _MetaWaylandTestDriver
|
||||
G_DEFINE_TYPE (MetaWaylandTestDriver, meta_wayland_test_driver,
|
||||
G_TYPE_OBJECT)
|
||||
|
||||
typedef struct _PendingEffectsData
|
||||
{
|
||||
MetaWaylandSurface *surface;
|
||||
struct wl_resource *callback;
|
||||
} PendingEffectsData;
|
||||
|
||||
static void
|
||||
on_actor_destroyed (ClutterActor *actor,
|
||||
struct wl_resource *callback)
|
||||
@ -82,6 +91,71 @@ sync_actor_destroy (struct wl_client *client,
|
||||
callback);
|
||||
}
|
||||
|
||||
static void
|
||||
on_effects_completed (ClutterActor *actor,
|
||||
struct wl_resource *callback)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_data (actor, callback);
|
||||
wl_callback_send_done (callback, 0);
|
||||
wl_resource_destroy (callback);
|
||||
}
|
||||
|
||||
static void
|
||||
check_for_pending_effects (ClutterStage *stage,
|
||||
ClutterStageView *view,
|
||||
PendingEffectsData *data)
|
||||
{
|
||||
MetaWindow *window;
|
||||
MetaWindowActor *window_actor;
|
||||
|
||||
g_signal_handlers_disconnect_by_data (stage, data);
|
||||
|
||||
window = meta_wayland_surface_get_window (data->surface);
|
||||
g_assert_nonnull (window);
|
||||
|
||||
window_actor = meta_window_actor_from_window (window);
|
||||
g_assert_nonnull (window_actor);
|
||||
|
||||
if (meta_window_actor_effect_in_progress (window_actor))
|
||||
{
|
||||
g_signal_connect (window_actor, "effects-completed",
|
||||
G_CALLBACK (on_effects_completed), data->callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
on_effects_completed (CLUTTER_ACTOR (window_actor), data->callback);
|
||||
}
|
||||
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
sync_effects_completed (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t id,
|
||||
struct wl_resource *surface_resource)
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
ClutterActor *stage = meta_backend_get_stage (backend);
|
||||
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
||||
PendingEffectsData *data;
|
||||
GList *stage_views;
|
||||
|
||||
g_assert_nonnull (surface);
|
||||
|
||||
data = g_new0 (PendingEffectsData, 1);
|
||||
data->surface = surface;
|
||||
data->callback = wl_resource_create (client, &wl_callback_interface, 1, id);
|
||||
|
||||
stage_views = clutter_stage_peek_stage_views (CLUTTER_STAGE (stage));
|
||||
g_assert (g_list_length (stage_views) > 0);
|
||||
|
||||
g_signal_connect (CLUTTER_STAGE (stage), "after-update",
|
||||
G_CALLBACK (check_for_pending_effects), data);
|
||||
|
||||
clutter_stage_schedule_update (CLUTTER_STAGE (stage));
|
||||
}
|
||||
|
||||
static void
|
||||
sync_point (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
@ -96,9 +170,45 @@ sync_point (struct wl_client *client,
|
||||
client);
|
||||
}
|
||||
|
||||
static void
|
||||
on_after_paint (ClutterStage *stage,
|
||||
ClutterStageView *view,
|
||||
struct wl_resource *callback)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_data (stage, callback);
|
||||
wl_callback_send_done (callback, 0);
|
||||
wl_resource_destroy (callback);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_view (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t id,
|
||||
uint32_t sequence)
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
ClutterActor *stage = meta_backend_get_stage (backend);
|
||||
GList *stage_views;
|
||||
struct wl_resource *callback;
|
||||
|
||||
stage_views = clutter_stage_peek_stage_views (CLUTTER_STAGE (stage));
|
||||
g_assert (g_list_length (stage_views) > 0);
|
||||
|
||||
callback = wl_resource_create (client, &wl_callback_interface, 1, id);
|
||||
g_signal_connect_after (CLUTTER_STAGE (stage), "after-paint",
|
||||
G_CALLBACK (on_after_paint), callback);
|
||||
|
||||
meta_ref_test_verify_view (CLUTTER_STAGE_VIEW (stage_views->data),
|
||||
g_test_get_path (),
|
||||
sequence,
|
||||
meta_ref_test_determine_ref_test_flag ());
|
||||
}
|
||||
|
||||
static const struct test_driver_interface meta_test_driver_interface = {
|
||||
sync_actor_destroy,
|
||||
sync_effects_completed,
|
||||
sync_point,
|
||||
verify_view,
|
||||
};
|
||||
|
||||
static void
|
||||
|
201
src/tests/wayland-test-clients/buffer-transform.c
Normal file
201
src/tests/wayland-test-clients/buffer-transform.c
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Collabora, Ltd.
|
||||
*
|
||||
* 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 <glib.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "wayland-test-client-utils.h"
|
||||
|
||||
static WaylandDisplay *display;
|
||||
static struct wl_surface *surface;
|
||||
static struct xdg_surface *xdg_surface;
|
||||
static struct xdg_toplevel *xdg_toplevel;
|
||||
|
||||
static gboolean waiting_for_configure = FALSE;
|
||||
static gboolean fullscreen = 0;
|
||||
static uint32_t window_width = 0;
|
||||
static uint32_t window_height = 0;
|
||||
|
||||
static void
|
||||
handle_xdg_toplevel_configure (void *data,
|
||||
struct xdg_toplevel *xdg_toplevel,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
struct wl_array *states)
|
||||
{
|
||||
uint32_t *p;
|
||||
|
||||
fullscreen = 0;
|
||||
wl_array_for_each(p, states)
|
||||
{
|
||||
uint32_t state = *p;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case XDG_TOPLEVEL_STATE_FULLSCREEN:
|
||||
fullscreen = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
window_width = width;
|
||||
window_height = height;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_xdg_toplevel_close(void *data,
|
||||
struct xdg_toplevel *xdg_toplevel)
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||
handle_xdg_toplevel_configure,
|
||||
handle_xdg_toplevel_close,
|
||||
};
|
||||
|
||||
static void
|
||||
handle_xdg_surface_configure (void *data,
|
||||
struct xdg_surface *xdg_surface,
|
||||
uint32_t serial)
|
||||
{
|
||||
xdg_surface_ack_configure (xdg_surface, serial);
|
||||
|
||||
waiting_for_configure = FALSE;
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||
handle_xdg_surface_configure,
|
||||
};
|
||||
|
||||
static void
|
||||
draw_main (void)
|
||||
{
|
||||
static uint32_t color0 = 0xffffffff;
|
||||
static uint32_t color1 = 0xff00ffff;
|
||||
static uint32_t color2 = 0xffff00ff;
|
||||
static uint32_t color3 = 0xffffff00;
|
||||
struct wl_buffer *buffer;
|
||||
void *buffer_data;
|
||||
uint32_t *pixels;
|
||||
int x, y, size;
|
||||
|
||||
if (!create_shm_buffer (display, window_width, window_height,
|
||||
&buffer, &buffer_data, &size))
|
||||
g_error ("Failed to create shm buffer");
|
||||
|
||||
pixels = buffer_data;
|
||||
for (y = 0; y < window_height; y++)
|
||||
{
|
||||
for (x = 0; x < window_width; x++)
|
||||
{
|
||||
uint32_t current_color;
|
||||
|
||||
if (y < window_height / 2)
|
||||
{
|
||||
if (x < window_width / 2)
|
||||
current_color = color0;
|
||||
else
|
||||
current_color = color1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x < window_width / 2)
|
||||
current_color = color2;
|
||||
else
|
||||
current_color = color3;
|
||||
}
|
||||
|
||||
pixels[y * window_width + x] = current_color;
|
||||
}
|
||||
}
|
||||
|
||||
wl_surface_attach (surface, buffer, 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
wait_for_configure (void)
|
||||
{
|
||||
waiting_for_configure = TRUE;
|
||||
while (waiting_for_configure || window_width == 0)
|
||||
{
|
||||
if (wl_display_dispatch (display->display) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
display = wayland_display_new (WAYLAND_DISPLAY_CAPABILITY_TEST_DRIVER);
|
||||
|
||||
surface = wl_compositor_create_surface (display->compositor);
|
||||
xdg_surface = xdg_wm_base_get_xdg_surface (display->xdg_wm_base, surface);
|
||||
xdg_surface_add_listener (xdg_surface, &xdg_surface_listener, NULL);
|
||||
xdg_toplevel = xdg_surface_get_toplevel (xdg_surface);
|
||||
xdg_toplevel_add_listener (xdg_toplevel, &xdg_toplevel_listener, NULL);
|
||||
|
||||
xdg_toplevel_set_fullscreen(xdg_toplevel, NULL);
|
||||
wl_surface_commit (surface);
|
||||
wait_for_configure ();
|
||||
|
||||
draw_main ();
|
||||
wl_surface_commit (surface);
|
||||
wait_for_effects_completed (display, surface);
|
||||
|
||||
wl_surface_set_buffer_transform (surface, WL_OUTPUT_TRANSFORM_NORMAL);
|
||||
wl_surface_commit (surface);
|
||||
wait_for_view_verified (display, 0);
|
||||
|
||||
wl_surface_set_buffer_transform (surface, WL_OUTPUT_TRANSFORM_90);
|
||||
wl_surface_commit (surface);
|
||||
wait_for_view_verified (display, 1);
|
||||
|
||||
wl_surface_set_buffer_transform (surface, WL_OUTPUT_TRANSFORM_180);
|
||||
wl_surface_commit (surface);
|
||||
wait_for_view_verified (display, 2);
|
||||
|
||||
wl_surface_set_buffer_transform (surface, WL_OUTPUT_TRANSFORM_270);
|
||||
wl_surface_commit (surface);
|
||||
wait_for_view_verified (display, 3);
|
||||
|
||||
wl_surface_set_buffer_transform (surface, WL_OUTPUT_TRANSFORM_FLIPPED);
|
||||
wl_surface_commit (surface);
|
||||
wait_for_view_verified (display, 4);
|
||||
|
||||
wl_surface_set_buffer_transform (surface, WL_OUTPUT_TRANSFORM_FLIPPED_90);
|
||||
wl_surface_commit (surface);
|
||||
wait_for_view_verified (display, 5);
|
||||
|
||||
wl_surface_set_buffer_transform (surface, WL_OUTPUT_TRANSFORM_FLIPPED_180);
|
||||
wl_surface_commit (surface);
|
||||
wait_for_view_verified (display, 6);
|
||||
|
||||
wl_surface_set_buffer_transform (surface, WL_OUTPUT_TRANSFORM_FLIPPED_270);
|
||||
wl_surface_commit (surface);
|
||||
wait_for_view_verified (display, 7);
|
||||
|
||||
g_clear_object (&display);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -6,11 +6,21 @@
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</request>
|
||||
|
||||
<request name="sync_effects_completed">
|
||||
<arg name="callback" type="new_id" interface="wl_callback"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</request>
|
||||
|
||||
<request name="sync_point">
|
||||
<arg name="sequence" type="uint"/>
|
||||
<arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
|
||||
</request>
|
||||
|
||||
<request name="verify_view">
|
||||
<arg name="callback" type="new_id" interface="wl_callback"/>
|
||||
<arg name="sequence" type="uint"/>
|
||||
</request>
|
||||
|
||||
<event name="sync_event">
|
||||
<arg name="sequence" type="uint"/>
|
||||
</event>
|
||||
|
@ -40,6 +40,8 @@ enum
|
||||
};
|
||||
|
||||
static guint signals[N_SIGNALS];
|
||||
static struct wl_callback *effects_complete_callback;
|
||||
static struct wl_callback *view_verification_callback;
|
||||
|
||||
G_DEFINE_TYPE (WaylandDisplay, wayland_display, G_TYPE_OBJECT)
|
||||
|
||||
@ -372,3 +374,62 @@ lookup_property_value (WaylandDisplay *display,
|
||||
{
|
||||
return g_hash_table_lookup (display->properties, name);
|
||||
}
|
||||
|
||||
static void
|
||||
effects_completed (void *data,
|
||||
struct wl_callback *callback,
|
||||
uint32_t serial)
|
||||
{
|
||||
wl_callback_destroy (callback);
|
||||
effects_complete_callback = NULL;
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener effects_complete_listener = {
|
||||
effects_completed,
|
||||
};
|
||||
|
||||
void
|
||||
wait_for_effects_completed (WaylandDisplay *display,
|
||||
struct wl_surface *surface)
|
||||
{
|
||||
effects_complete_callback =
|
||||
test_driver_sync_effects_completed (display->test_driver, surface);
|
||||
wl_callback_add_listener (effects_complete_callback,
|
||||
&effects_complete_listener,
|
||||
NULL);
|
||||
|
||||
while (effects_complete_callback)
|
||||
{
|
||||
if (wl_display_dispatch (display->display) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
view_verified (void *data,
|
||||
struct wl_callback *callback,
|
||||
uint32_t serial)
|
||||
{
|
||||
wl_callback_destroy (callback);
|
||||
view_verification_callback = NULL;
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener view_verification_listener = {
|
||||
view_verified,
|
||||
};
|
||||
|
||||
void
|
||||
wait_for_view_verified (WaylandDisplay *display,
|
||||
int sequence)
|
||||
{
|
||||
view_verification_callback =
|
||||
test_driver_verify_view (display->test_driver, sequence);
|
||||
wl_callback_add_listener (view_verification_callback,
|
||||
&view_verification_listener, NULL);
|
||||
|
||||
while (view_verification_callback)
|
||||
{
|
||||
if (wl_display_dispatch (display->display) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
@ -56,4 +56,10 @@ void draw_surface (WaylandDisplay *display,
|
||||
const char * lookup_property_value (WaylandDisplay *display,
|
||||
const char *name);
|
||||
|
||||
void wait_for_effects_completed (WaylandDisplay *display,
|
||||
struct wl_surface *surface);
|
||||
|
||||
void wait_for_view_verified (WaylandDisplay *display,
|
||||
int sequence);
|
||||
|
||||
#endif /* WAYLAND_TEST_CLIENT_UTILS_H */
|
||||
|
@ -300,6 +300,7 @@ void meta_wayland_surface_update_outputs (MetaWaylandSurface *sur
|
||||
|
||||
MetaWaylandSurface *meta_wayland_surface_get_toplevel (MetaWaylandSurface *surface);
|
||||
|
||||
META_EXPORT_TEST
|
||||
MetaWindow * meta_wayland_surface_get_window (MetaWaylandSurface *surface);
|
||||
|
||||
gboolean meta_wayland_surface_should_cache_state (MetaWaylandSurface *surface);
|
||||
|
Loading…
Reference in New Issue
Block a user