stage: Clear update_scheduled
field when update discarded
clutter_stage_schedule_update() sets the field `update_scheduled` to `TRUE` as an optimization to make redundant updates a no-op. This failed if there was a pending event and if the stage was not yet mapped. What happened is: * clutter_stage_schedule_update() is called - ClutterStage::update_scheduled is set to TRUE - frame clock scheduled * frame clock dispatches - frame is discarded early, no actual stage update happens * device is created (e.g. virtual device from remote desktop session) - `device-added` event reaches ClutterStage::event_queue * stage is shown - clutter_stage_schedule_update() is called - ClutterStage::update_scheduled is TRUE - ClutterStage::event_queue has events in it - These two conditions means clutter_schedule_update() becomes a no-op At this point, no more updates will happen from clutter_stage_schedule_update(). Fix this by resetting `ClutterStage::update_scheduled` to `FALSE` even if the frame was discarded due to the stage not yet being mapped. A test case is added that replicates the above descibed events. Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3804 Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4152>
This commit is contained in:
parent
904c39116e
commit
24083e1e58
@ -62,6 +62,9 @@ void clutter_stage_emit_after_paint (ClutterStage
|
|||||||
void clutter_stage_after_update (ClutterStage *stage,
|
void clutter_stage_after_update (ClutterStage *stage,
|
||||||
ClutterStageView *view,
|
ClutterStageView *view,
|
||||||
ClutterFrame *frame);
|
ClutterFrame *frame);
|
||||||
|
void clutter_stage_frame_discarded (ClutterStage *stage,
|
||||||
|
ClutterStageView *view,
|
||||||
|
ClutterFrame *frame);
|
||||||
|
|
||||||
CLUTTER_EXPORT
|
CLUTTER_EXPORT
|
||||||
void _clutter_stage_set_window (ClutterStage *stage,
|
void _clutter_stage_set_window (ClutterStage *stage,
|
||||||
|
@ -1050,11 +1050,12 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock,
|
|||||||
if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
|
if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
|
||||||
return CLUTTER_FRAME_RESULT_IDLE;
|
return CLUTTER_FRAME_RESULT_IDLE;
|
||||||
|
|
||||||
if (!clutter_actor_is_realized (CLUTTER_ACTOR (stage)))
|
if (!clutter_actor_is_realized (CLUTTER_ACTOR (stage)) ||
|
||||||
return CLUTTER_FRAME_RESULT_IDLE;
|
!clutter_actor_is_mapped (CLUTTER_ACTOR (stage)))
|
||||||
|
{
|
||||||
if (!clutter_actor_is_mapped (CLUTTER_ACTOR (stage)))
|
clutter_stage_frame_discarded (stage, view, frame);
|
||||||
return CLUTTER_FRAME_RESULT_IDLE;
|
return CLUTTER_FRAME_RESULT_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
if (clutter_context_get_show_fps (context))
|
if (clutter_context_get_show_fps (context))
|
||||||
begin_frame_timing_measurement (view);
|
begin_frame_timing_measurement (view);
|
||||||
|
@ -535,6 +535,16 @@ clutter_stage_after_update (ClutterStage *stage,
|
|||||||
priv->update_scheduled = FALSE;
|
priv->update_scheduled = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clutter_stage_frame_discarded (ClutterStage *stage,
|
||||||
|
ClutterStageView *view,
|
||||||
|
ClutterFrame *frame)
|
||||||
|
{
|
||||||
|
ClutterStagePrivate *priv = clutter_stage_get_instance_private (stage);
|
||||||
|
|
||||||
|
priv->update_scheduled = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
clutter_stage_get_paint_volume (ClutterActor *self,
|
clutter_stage_get_paint_volume (ClutterActor *self,
|
||||||
ClutterPaintVolume *volume)
|
ClutterPaintVolume *volume)
|
||||||
|
@ -313,6 +313,11 @@ test_cases += [
|
|||||||
'--compile-schemas',
|
'--compile-schemas',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'name': 'stage',
|
||||||
|
'suite': 'backend',
|
||||||
|
'sources': [ 'stage-tests.c', ],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
screen_cast_client = executable('mutter-screen-cast-client',
|
screen_cast_client = executable('mutter-screen-cast-client',
|
||||||
|
102
src/tests/stage-tests.c
Normal file
102
src/tests/stage-tests.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* 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 "backends/meta-backend-private.h"
|
||||||
|
#include "core/meta-context-private.h"
|
||||||
|
#include "tests/meta-test-utils.h"
|
||||||
|
#include "tests/meta-test/meta-context-test.h"
|
||||||
|
|
||||||
|
static MetaContext *test_context;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
event_filter_cb (const ClutterEvent *event,
|
||||||
|
ClutterActor *event_actor,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
gboolean *saw_event = user_data;
|
||||||
|
|
||||||
|
if (clutter_event_type (event) == CLUTTER_DEVICE_ADDED)
|
||||||
|
*saw_event = TRUE;
|
||||||
|
|
||||||
|
return CLUTTER_EVENT_PROPAGATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_test_stage_scheduling_delayed_show (void)
|
||||||
|
{
|
||||||
|
MetaBackend *backend = meta_context_get_backend (test_context);
|
||||||
|
ClutterActor *stage = meta_backend_get_stage (backend);
|
||||||
|
ClutterSeat *seat = meta_backend_get_default_seat (backend);
|
||||||
|
g_autoptr (MetaVirtualMonitor) virtual_monitor = NULL;
|
||||||
|
g_autoptr (ClutterVirtualInputDevice) virtual_pointer = NULL;
|
||||||
|
guint filter_id;
|
||||||
|
gboolean saw_event = FALSE;
|
||||||
|
|
||||||
|
virtual_monitor = meta_create_test_monitor (test_context, 800, 600, 60.0f);
|
||||||
|
g_debug ("Wait for initial dummy dispatch");
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
if (!g_main_context_iteration (NULL, FALSE))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter_id = clutter_event_add_filter (NULL, event_filter_cb, NULL, &saw_event);
|
||||||
|
g_debug ("Creating virtual pointer");
|
||||||
|
virtual_pointer =
|
||||||
|
clutter_seat_create_virtual_device (seat, CLUTTER_KEYBOARD_DEVICE);
|
||||||
|
while (!saw_event)
|
||||||
|
g_main_context_iteration (NULL, TRUE);
|
||||||
|
g_debug ("Scheduling update with DEVICE_ADDED in stage queue");
|
||||||
|
clutter_stage_schedule_update (CLUTTER_STAGE (stage));
|
||||||
|
g_debug ("Showing stage");
|
||||||
|
clutter_actor_show (stage);
|
||||||
|
g_debug ("Waiting for paint");
|
||||||
|
clutter_actor_queue_redraw (stage);
|
||||||
|
meta_wait_for_paint (test_context);
|
||||||
|
clutter_event_remove_filter (filter_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc,
|
||||||
|
char **argv)
|
||||||
|
{
|
||||||
|
g_autoptr (MetaContext) context = NULL;
|
||||||
|
g_auto (GVariantBuilder) plugin_options_builder =
|
||||||
|
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
|
||||||
|
g_autoptr (GVariant) plugin_options = NULL;
|
||||||
|
|
||||||
|
context = meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS,
|
||||||
|
META_CONTEXT_TEST_FLAG_NO_X11);
|
||||||
|
g_assert (meta_context_configure (context, &argc, &argv, NULL));
|
||||||
|
|
||||||
|
g_variant_builder_add (&plugin_options_builder, "{sv}",
|
||||||
|
"show-stage", g_variant_new_boolean (FALSE));
|
||||||
|
plugin_options =
|
||||||
|
g_variant_ref_sink (g_variant_builder_end (&plugin_options_builder));
|
||||||
|
meta_context_set_plugin_options (context, plugin_options);
|
||||||
|
|
||||||
|
test_context = context;
|
||||||
|
|
||||||
|
g_test_add_func ("/stage/scheduling/delayed-show",
|
||||||
|
meta_test_stage_scheduling_delayed_show);
|
||||||
|
|
||||||
|
return meta_context_test_run_tests (META_CONTEXT_TEST (context),
|
||||||
|
META_TEST_RUN_FLAG_NONE);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user