1
0
Fork 0

onscreen/native: Defer posting if there's already a post in progress

And when the number of pending posts decreases we know it's safe to submit
a new one. Since KMS generally only supports one outstanding post right now,
"decreases" means equal to zero.

Signed-off-by: Mingi Sung <sungmg@saltyming.net>
This commit is contained in:
Daniel van Vugt 2021-09-17 17:59:28 +08:00 committed by Mingi Sung
parent 167b013b99
commit febb9a4261
Signed by: sungmg
GPG key ID: 41BAFD6FFD8036C5

View file

@ -105,6 +105,7 @@ struct _MetaOnscreenNative
ClutterFrame *presented_frame; ClutterFrame *presented_frame;
ClutterFrame *posted_frame; ClutterFrame *posted_frame;
ClutterFrame *stalled_frame;
ClutterFrame *next_frame; ClutterFrame *next_frame;
struct { struct {
@ -119,6 +120,9 @@ struct _MetaOnscreenNative
} egl; } egl;
#endif #endif
gboolean needs_flush;
unsigned int swaps_pending;
gboolean frame_sync_requested; gboolean frame_sync_requested;
gboolean frame_sync_enabled; gboolean frame_sync_enabled;
@ -141,7 +145,11 @@ G_DEFINE_TYPE (MetaOnscreenNative, meta_onscreen_native,
static GQuark blit_source_quark = 0; static GQuark blit_source_quark = 0;
static void static void
post_latest_swap (CoglOnscreen *onscreen); try_post_latest_swap (CoglOnscreen *onscreen);
static void
post_finish_frame (MetaOnscreenNative *onscreen_native,
MetaKmsUpdate *kms_update);
static gboolean static gboolean
init_secondary_gpu_state (MetaRendererNative *renderer_native, init_secondary_gpu_state (MetaRendererNative *renderer_native,
@ -246,6 +254,7 @@ notify_view_crtc_presented (MetaRendererView *view,
meta_onscreen_native_notify_frame_complete (onscreen); meta_onscreen_native_notify_frame_complete (onscreen);
meta_onscreen_native_swap_drm_fb (onscreen); meta_onscreen_native_swap_drm_fb (onscreen);
try_post_latest_swap (onscreen);
} }
static void static void
@ -295,15 +304,13 @@ page_flip_feedback_ready (MetaKmsCrtc *kms_crtc,
CoglFramebuffer *framebuffer = CoglFramebuffer *framebuffer =
clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view)); clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view));
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
CoglFrameInfo *frame_info; CoglFrameInfo *frame_info;
frame_info = cogl_onscreen_peek_head_frame_info (onscreen); frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
g_warn_if_fail (!onscreen_native->posted_frame);
meta_onscreen_native_notify_frame_complete (onscreen); meta_onscreen_native_notify_frame_complete (onscreen);
try_post_latest_swap (onscreen);
} }
static void static void
@ -374,6 +381,7 @@ page_flip_feedback_discarded (MetaKmsCrtc *kms_crtc,
meta_onscreen_native_notify_frame_complete (onscreen); meta_onscreen_native_notify_frame_complete (onscreen);
meta_onscreen_native_clear_posted_fb (onscreen); meta_onscreen_native_clear_posted_fb (onscreen);
try_post_latest_swap (onscreen);
} }
static const MetaKmsPageFlipListenerVtable page_flip_listener_vtable = { static const MetaKmsPageFlipListenerVtable page_flip_listener_vtable = {
@ -434,18 +442,36 @@ custom_egl_stream_page_flip (gpointer custom_page_flip_data,
} }
#endif /* HAVE_EGL_DEVICE */ #endif /* HAVE_EGL_DEVICE */
void static void
meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen) drop_stalled_swap (CoglOnscreen *onscreen)
{ {
CoglFrameInfo *frame_info; CoglFrameInfo *frame_info;
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
meta_onscreen_native_swap_drm_fb (onscreen); if (onscreen_native->swaps_pending <= 1)
return;
onscreen_native->swaps_pending--;
g_clear_pointer (&onscreen_native->stalled_frame, clutter_frame_unref);
frame_info = cogl_onscreen_peek_tail_frame_info (onscreen); frame_info = cogl_onscreen_peek_tail_frame_info (onscreen);
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
meta_onscreen_native_notify_frame_complete (onscreen); meta_onscreen_native_notify_frame_complete (onscreen);
} }
void
meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen)
{
drop_stalled_swap (onscreen);
/* If the monitor just woke up and the shell is fully idle (has nothing
* more to swap) then we just woke to an indefinitely black screen. Let's
* fix that using the last swap (which is never classified as "stalled").
*/
try_post_latest_swap (onscreen);
}
static void static void
apply_transform (MetaCrtcKms *crtc_kms, apply_transform (MetaCrtcKms *crtc_kms,
MetaKmsPlaneAssignment *kms_plane_assignment, MetaKmsPlaneAssignment *kms_plane_assignment,
@ -1359,12 +1385,38 @@ swap_buffer_result_feedback (const MetaKmsFeedback *kms_feedback,
g_warning ("Page flip failed: %s", error->message); g_warning ("Page flip failed: %s", error->message);
frame_info = cogl_onscreen_peek_head_frame_info (onscreen); frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
meta_onscreen_native_notify_frame_complete (onscreen); /* After resuming from suspend, drop_stalled_swap might have done this
* already and emptied the frame_info queue.
*/
if (frame_info)
{
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
meta_onscreen_native_notify_frame_complete (onscreen);
}
meta_onscreen_native_clear_posted_fb (onscreen); meta_onscreen_native_clear_posted_fb (onscreen);
} }
static void
assign_next_frame (MetaOnscreenNative *onscreen_native,
ClutterFrame *frame)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (onscreen_native);
if (onscreen_native->next_frame != NULL)
{
g_warn_if_fail (onscreen_native->stalled_frame == NULL);
drop_stalled_swap (onscreen);
g_warn_if_fail (onscreen_native->stalled_frame == NULL);
g_clear_pointer (&onscreen_native->stalled_frame, clutter_frame_unref);
onscreen_native->stalled_frame =
g_steal_pointer (&onscreen_native->next_frame);
}
onscreen_native->next_frame = clutter_frame_ref (frame);
}
static const MetaKmsResultListenerVtable swap_buffer_result_listener_vtable = { static const MetaKmsResultListenerVtable swap_buffer_result_listener_vtable = {
.feedback = swap_buffer_result_feedback, .feedback = swap_buffer_result_feedback,
}; };
@ -1494,14 +1546,14 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
#endif #endif
} }
g_warn_if_fail (!onscreen_native->next_frame); assign_next_frame (onscreen_native, frame);
onscreen_native->next_frame = clutter_frame_ref (frame);
clutter_frame_set_result (frame, clutter_frame_set_result (frame,
CLUTTER_FRAME_RESULT_PENDING_PRESENTED); CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
meta_frame_native_set_damage (frame_native, rectangles, n_rectangles); meta_frame_native_set_damage (frame_native, rectangles, n_rectangles);
post_latest_swap (onscreen); onscreen_native->swaps_pending++;
try_post_latest_swap (onscreen);
return; return;
swap_failed: swap_failed:
@ -1511,7 +1563,7 @@ swap_failed:
} }
static void static void
post_latest_swap (CoglOnscreen *onscreen) try_post_latest_swap (CoglOnscreen *onscreen)
{ {
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer); CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
@ -1535,16 +1587,41 @@ post_latest_swap (CoglOnscreen *onscreen)
int sync_fd; int sync_fd;
COGL_TRACE_SCOPED_ANCHOR (MetaRendererNativePostKmsUpdate); COGL_TRACE_SCOPED_ANCHOR (MetaRendererNativePostKmsUpdate);
if (onscreen_native->next_frame == NULL)
return;
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
if (power_save_mode == META_POWER_SAVE_ON) if (power_save_mode == META_POWER_SAVE_ON)
{ {
unsigned int frames_pending =
cogl_onscreen_get_pending_frame_count (onscreen);
unsigned int posts_pending;
int n_rectangles; int n_rectangles;
int *rectangles; int *rectangles;
g_assert (frames_pending >= onscreen_native->swaps_pending);
posts_pending = frames_pending - onscreen_native->swaps_pending;
if (posts_pending > 0)
return; /* wait for the next frame notification and then try again */
frame = clutter_frame_ref (onscreen_native->next_frame); frame = clutter_frame_ref (onscreen_native->next_frame);
frame_native = meta_frame_native_from_frame (frame); frame_native = meta_frame_native_from_frame (frame);
n_rectangles = meta_frame_native_get_damage (frame_native, &rectangles); n_rectangles = meta_frame_native_get_damage (frame_native, &rectangles);
if (onscreen_native->swaps_pending == 0)
{
if (frame_native)
{
kms_update = meta_frame_native_steal_kms_update (frame_native);
if (kms_update)
post_finish_frame (onscreen_native, kms_update);
}
return;
}
drop_stalled_swap (onscreen);
onscreen_native->swaps_pending--;
kms_update = meta_frame_native_ensure_kms_update (frame_native, kms_update = meta_frame_native_ensure_kms_update (frame_native,
kms_device); kms_device);
meta_kms_update_add_result_listener (kms_update, meta_kms_update_add_result_listener (kms_update,
@ -1570,7 +1647,7 @@ post_latest_swap (CoglOnscreen *onscreen)
} }
COGL_TRACE_BEGIN_ANCHORED (MetaRendererNativePostKmsUpdate, COGL_TRACE_BEGIN_ANCHORED (MetaRendererNativePostKmsUpdate,
"Meta::OnscreenNative::post_latest_swap#post_pending_update()"); "Meta::OnscreenNative::try_post_latest_swap#post_pending_update()");
switch (renderer_gpu_data->mode) switch (renderer_gpu_data->mode)
{ {
@ -1765,13 +1842,24 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
return FALSE; return FALSE;
} }
/* Our direct scanout frame counts as 1, so more than that means we would
* be jumping the queue (and post would fail).
*/
if (cogl_onscreen_get_pending_frame_count (onscreen) > 1)
{
g_set_error_literal (error,
COGL_SCANOUT_ERROR,
COGL_SCANOUT_ERROR_INHIBITED,
"Direct scanout is inhibited during triple buffering");
return FALSE;
}
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
render_gpu); render_gpu);
g_warn_if_fail (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_GBM); g_warn_if_fail (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_GBM);
g_warn_if_fail (!onscreen_native->next_frame); assign_next_frame (onscreen_native, frame);
onscreen_native->next_frame = clutter_frame_ref (frame);
meta_frame_native_set_scanout (frame_native, scanout); meta_frame_native_set_scanout (frame_native, scanout);
meta_frame_native_set_buffer (frame_native, meta_frame_native_set_buffer (frame_native,
@ -2018,22 +2106,79 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc); MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
MetaFrameNative *frame_native = meta_frame_native_from_frame (frame); MetaFrameNative *frame_native = meta_frame_native_from_frame (frame);
MetaKmsUpdate *kms_update; MetaKmsUpdate *kms_update;
unsigned int frames_pending = cogl_onscreen_get_pending_frame_count (onscreen);
unsigned int swaps_pending = onscreen_native->swaps_pending;
unsigned int posts_pending = frames_pending - swaps_pending;
kms_update = meta_frame_native_steal_kms_update (frame_native); onscreen_native->needs_flush |= meta_kms_device_handle_flush (kms_device,
if (!kms_update) kms_crtc);
if (!meta_frame_native_has_kms_update (frame_native))
{ {
if (meta_kms_device_handle_flush (kms_device, kms_crtc)) if (!onscreen_native->needs_flush || posts_pending)
{
kms_update = meta_kms_update_new (kms_device);
meta_kms_update_set_flushing (kms_update, kms_crtc);
}
else
{ {
clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE); clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE);
return; return;
} }
} }
if (posts_pending && !swaps_pending)
{
g_return_if_fail (meta_frame_native_has_kms_update (frame_native));
g_warn_if_fail (onscreen_native->next_frame == NULL);
g_clear_pointer (&onscreen_native->next_frame, clutter_frame_unref);
onscreen_native->next_frame = clutter_frame_ref (frame);
clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
return;
}
kms_update = meta_frame_native_steal_kms_update (frame_native);
if (posts_pending && swaps_pending)
{
MetaFrameNative *older_frame_native;
MetaKmsUpdate *older_kms_update;
g_return_if_fail (kms_update);
g_return_if_fail (onscreen_native->next_frame != NULL);
older_frame_native =
meta_frame_native_from_frame (onscreen_native->next_frame);
older_kms_update =
meta_frame_native_ensure_kms_update (older_frame_native, kms_device);
meta_kms_update_merge_from (older_kms_update, kms_update);
meta_kms_update_free (kms_update);
clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE);
return;
}
if (!kms_update)
{
kms_update = meta_kms_update_new (kms_device);
g_warn_if_fail (onscreen_native->needs_flush);
}
if (onscreen_native->needs_flush)
{
meta_kms_update_set_flushing (kms_update, kms_crtc);
onscreen_native->needs_flush = FALSE;
}
post_finish_frame (onscreen_native, kms_update);
clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
}
static void
post_finish_frame (MetaOnscreenNative *onscreen_native,
MetaKmsUpdate *kms_update)
{
MetaCrtc *crtc = onscreen_native->crtc;
MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
meta_kms_update_add_result_listener (kms_update, meta_kms_update_add_result_listener (kms_update,
&finish_frame_result_listener_vtable, &finish_frame_result_listener_vtable,
NULL, NULL,
@ -2056,7 +2201,6 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
meta_kms_update_set_flushing (kms_update, kms_crtc); meta_kms_update_set_flushing (kms_update, kms_crtc);
meta_kms_device_post_update (kms_device, kms_update, meta_kms_device_post_update (kms_device, kms_update,
META_KMS_UPDATE_FLAG_NONE); META_KMS_UPDATE_FLAG_NONE);
clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
} }
static gboolean static gboolean
@ -2961,6 +3105,7 @@ meta_onscreen_native_dispose (GObject *object)
meta_onscreen_native_detach (onscreen_native); meta_onscreen_native_detach (onscreen_native);
g_clear_pointer (&onscreen_native->next_frame, clutter_frame_unref); g_clear_pointer (&onscreen_native->next_frame, clutter_frame_unref);
g_clear_pointer (&onscreen_native->stalled_frame, clutter_frame_unref);
g_clear_pointer (&onscreen_native->posted_frame, clutter_frame_unref); g_clear_pointer (&onscreen_native->posted_frame, clutter_frame_unref);
g_clear_pointer (&onscreen_native->presented_frame, clutter_frame_unref); g_clear_pointer (&onscreen_native->presented_frame, clutter_frame_unref);