mutter/src/backends/meta-stage-view.c
Robert Mader aaae07f9dd onscreen/native: Mark GPU rendering duration as valid if supported
Since commit e30eb788916d `ClutterFrameClock` assumes that a valid CPU time
implies timestamp query support, which is also checked in
`cogl_onscreen_egl_swap_buffers_with_damage()`.

Unconditionally setting the CPU time on direct scanout meant that the
compositing path would be stuck on the last (direct scanout optimized)
result on GL implementations without timestamp query support since.

be0aa2976e (clutter/frame-clock: Avoid rapidly toggling dynamic max render time)

Fix that by explicitly marking the gpu rendering duration as valid when
querying the GPU timestamps is supported and check for it ClutterFrameClock.

Fixes: 56580ea7c9 ("backends/native: Assume zero rendering time for direct scanout buffers")
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3655>
2024-03-13 16:37:16 +01:00

255 lines
7.5 KiB
C

/*
* Copyright (C) 2007,2008,2009,2010,2011 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Authors:
* Matthew Allum
* Robert Bragg
* Neil Roberts
* Emmanuele Bassi
*/
#include "config.h"
#include "backends/meta-stage-view-private.h"
typedef struct _MetaStageViewPrivate
{
/* Damage history, in stage view render target framebuffer coordinate space.
*/
ClutterDamageHistory *damage_history;
guint notify_presented_handle_id;
CoglFrameClosure *frame_cb_closure;
int inhibit_cursor_overlay_count;
} MetaStageViewPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaStageView, meta_stage_view,
CLUTTER_TYPE_STAGE_VIEW)
static void
frame_cb (CoglOnscreen *onscreen,
CoglFrameEvent frame_event,
CoglFrameInfo *frame_info,
void *user_data)
{
ClutterStageView *view = user_data;
if (frame_event == COGL_FRAME_EVENT_SYNC)
return;
if (cogl_frame_info_get_is_symbolic (frame_info))
{
clutter_stage_view_notify_ready (view);
}
else
{
ClutterFrameInfo clutter_frame_info;
ClutterFrameInfoFlag flags = CLUTTER_FRAME_INFO_FLAG_NONE;
if (cogl_frame_info_is_hw_clock (frame_info))
flags |= CLUTTER_FRAME_INFO_FLAG_HW_CLOCK;
if (cogl_frame_info_is_zero_copy (frame_info))
flags |= CLUTTER_FRAME_INFO_FLAG_ZERO_COPY;
if (cogl_frame_info_is_vsync (frame_info))
flags |= CLUTTER_FRAME_INFO_FLAG_VSYNC;
clutter_frame_info = (ClutterFrameInfo) {
.frame_counter = cogl_frame_info_get_global_frame_counter (frame_info),
.refresh_rate = cogl_frame_info_get_refresh_rate (frame_info),
.presentation_time =
cogl_frame_info_get_presentation_time_us (frame_info),
.flags = flags,
.sequence = cogl_frame_info_get_sequence (frame_info),
.has_valid_gpu_rendering_duration =
cogl_frame_info_has_valid_gpu_rendering_duration (frame_info),
.gpu_rendering_duration_ns =
cogl_frame_info_get_rendering_duration_ns (frame_info),
.cpu_time_before_buffer_swap_us =
cogl_frame_info_get_time_before_buffer_swap_us (frame_info),
};
clutter_stage_view_notify_presented (view, &clutter_frame_info);
}
}
static void
meta_stage_view_dispose (GObject *object)
{
MetaStageView *view = META_STAGE_VIEW (object);
MetaStageViewPrivate *priv =
meta_stage_view_get_instance_private (view);
ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
g_clear_handle_id (&priv->notify_presented_handle_id, g_source_remove);
g_clear_pointer (&priv->damage_history, clutter_damage_history_free);
if (priv->frame_cb_closure)
{
CoglFramebuffer *framebuffer;
framebuffer = clutter_stage_view_get_onscreen (stage_view);
cogl_onscreen_remove_frame_callback (COGL_ONSCREEN (framebuffer),
priv->frame_cb_closure);
priv->frame_cb_closure = NULL;
}
G_OBJECT_CLASS (meta_stage_view_parent_class)->dispose (object);
}
static void
meta_stage_view_constructed (GObject *object)
{
MetaStageView *view = META_STAGE_VIEW (object);
MetaStageViewPrivate *priv =
meta_stage_view_get_instance_private (view);
ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
CoglFramebuffer *framebuffer;
framebuffer = clutter_stage_view_get_onscreen (stage_view);
if (framebuffer && COGL_IS_ONSCREEN (framebuffer))
{
priv->frame_cb_closure =
cogl_onscreen_add_frame_callback (COGL_ONSCREEN (framebuffer),
frame_cb,
view,
NULL);
}
G_OBJECT_CLASS (meta_stage_view_parent_class)->constructed (object);
}
static ClutterPaintFlag
meta_stage_view_get_default_paint_flags (ClutterStageView *clutter_view)
{
MetaStageView *view = META_STAGE_VIEW (clutter_view);
MetaStageViewPrivate *priv =
meta_stage_view_get_instance_private (view);
if (priv->inhibit_cursor_overlay_count > 0)
return CLUTTER_PAINT_FLAG_NO_CURSORS;
else
return CLUTTER_PAINT_FLAG_NONE;
}
static void
meta_stage_view_init (MetaStageView *view)
{
MetaStageViewPrivate *priv =
meta_stage_view_get_instance_private (view);
priv->damage_history = clutter_damage_history_new ();
}
static void
meta_stage_view_class_init (MetaStageViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterStageViewClass *view_class = CLUTTER_STAGE_VIEW_CLASS (klass);
object_class->constructed = meta_stage_view_constructed;
object_class->dispose = meta_stage_view_dispose;
view_class->get_default_paint_flags =
meta_stage_view_get_default_paint_flags;
}
ClutterDamageHistory *
meta_stage_view_get_damage_history (MetaStageView *view)
{
MetaStageViewPrivate *priv =
meta_stage_view_get_instance_private (view);
return priv->damage_history;
}
typedef struct _NotifyPresentedClosure
{
ClutterStageView *view;
ClutterFrameInfo frame_info;
} NotifyPresentedClosure;
static gboolean
notify_presented_idle (gpointer user_data)
{
NotifyPresentedClosure *closure = user_data;
MetaStageView *view = META_STAGE_VIEW (closure->view);
MetaStageViewPrivate *priv =
meta_stage_view_get_instance_private (view);
priv->notify_presented_handle_id = 0;
clutter_stage_view_notify_presented (closure->view, &closure->frame_info);
return G_SOURCE_REMOVE;
}
void
meta_stage_view_perform_fake_swap (MetaStageView *view,
int64_t counter)
{
ClutterStageView *clutter_view = CLUTTER_STAGE_VIEW (view);
MetaStageViewPrivate *priv =
meta_stage_view_get_instance_private (view);
NotifyPresentedClosure *closure;
closure = g_new0 (NotifyPresentedClosure, 1);
closure->view = clutter_view;
closure->frame_info = (ClutterFrameInfo) {
.frame_counter = counter,
.refresh_rate = clutter_stage_view_get_refresh_rate (clutter_view),
.presentation_time = g_get_monotonic_time (),
.flags = CLUTTER_FRAME_INFO_FLAG_NONE,
.sequence = 0,
};
g_warn_if_fail (priv->notify_presented_handle_id == 0);
priv->notify_presented_handle_id =
g_idle_add_full (G_PRIORITY_DEFAULT,
notify_presented_idle,
closure, g_free);
}
void
meta_stage_view_inhibit_cursor_overlay (MetaStageView *view)
{
MetaStageViewPrivate *priv =
meta_stage_view_get_instance_private (view);
priv->inhibit_cursor_overlay_count++;
}
void
meta_stage_view_uninhibit_cursor_overlay (MetaStageView *view)
{
MetaStageViewPrivate *priv =
meta_stage_view_get_instance_private (view);
g_return_if_fail (priv->inhibit_cursor_overlay_count > 0);
priv->inhibit_cursor_overlay_count--;
}
gboolean
meta_stage_view_is_cursor_overlay_inhibited (MetaStageView *view)
{
MetaStageViewPrivate *priv =
meta_stage_view_get_instance_private (view);
return priv->inhibit_cursor_overlay_count > 0;
}