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.
This commit is contained in:
parent
f5a36efe3a
commit
d6d0fa3f3c
1 changed files with 164 additions and 28 deletions
|
@ -100,9 +100,11 @@ struct _MetaOnscreenNative
|
|||
MetaDrmBuffer *current_fb;
|
||||
MetaDrmBuffer *posted_fb;
|
||||
MetaDrmBuffer *next_fb;
|
||||
MetaDrmBuffer *stalled_fb;
|
||||
CoglScanout *current_scanout;
|
||||
CoglScanout *posted_scanout;
|
||||
CoglScanout *next_scanout;
|
||||
CoglScanout *stalled_scanout;
|
||||
} gbm;
|
||||
|
||||
#ifdef HAVE_EGL_DEVICE
|
||||
|
@ -128,6 +130,10 @@ struct _MetaOnscreenNative
|
|||
gulong color_space_changed_handler_id;
|
||||
gulong hdr_metadata_changed_handler_id;
|
||||
|
||||
gboolean needs_flush;
|
||||
|
||||
unsigned int swaps_pending;
|
||||
|
||||
struct {
|
||||
int *rectangles; /* 4 x n_rectangles */
|
||||
int n_rectangles;
|
||||
|
@ -141,7 +147,11 @@ G_DEFINE_TYPE (MetaOnscreenNative, meta_onscreen_native,
|
|||
static GQuark blit_source_quark = 0;
|
||||
|
||||
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
|
||||
init_secondary_gpu_state (MetaRendererNative *renderer_native,
|
||||
|
@ -245,6 +255,7 @@ notify_view_crtc_presented (MetaRendererView *view,
|
|||
|
||||
meta_onscreen_native_notify_frame_complete (onscreen);
|
||||
meta_onscreen_native_swap_drm_fb (onscreen);
|
||||
try_post_latest_swap (onscreen);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -294,15 +305,13 @@ page_flip_feedback_ready (MetaKmsCrtc *kms_crtc,
|
|||
CoglFramebuffer *framebuffer =
|
||||
clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view));
|
||||
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
|
||||
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
|
||||
CoglFrameInfo *frame_info;
|
||||
|
||||
frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
|
||||
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
|
||||
|
||||
g_warn_if_fail (!onscreen_native->gbm.next_fb);
|
||||
|
||||
meta_onscreen_native_notify_frame_complete (onscreen);
|
||||
try_post_latest_swap (onscreen);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -353,6 +362,7 @@ page_flip_feedback_discarded (MetaKmsCrtc *kms_crtc,
|
|||
|
||||
meta_onscreen_native_notify_frame_complete (onscreen);
|
||||
meta_onscreen_native_clear_posted_fb (onscreen);
|
||||
try_post_latest_swap (onscreen);
|
||||
}
|
||||
|
||||
static const MetaKmsPageFlipListenerVtable page_flip_listener_vtable = {
|
||||
|
@ -413,18 +423,41 @@ custom_egl_stream_page_flip (gpointer custom_page_flip_data,
|
|||
}
|
||||
#endif /* HAVE_EGL_DEVICE */
|
||||
|
||||
void
|
||||
meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen)
|
||||
static void
|
||||
drop_stalled_swap (CoglOnscreen *onscreen)
|
||||
{
|
||||
CoglFrameInfo *frame_info;
|
||||
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
|
||||
|
||||
meta_onscreen_native_swap_drm_fb (onscreen);
|
||||
/* Remember we can't compare stalled_fb because it's not used by
|
||||
* META_RENDERER_NATIVE_MODE_EGL_DEVICE. So we judge stalled to be whenever
|
||||
* swaps_pending > 1.
|
||||
*/
|
||||
if (onscreen_native->swaps_pending <= 1)
|
||||
return;
|
||||
|
||||
onscreen_native->swaps_pending--;
|
||||
|
||||
g_clear_object (&onscreen_native->gbm.stalled_fb);
|
||||
g_clear_object (&onscreen_native->gbm.stalled_scanout);
|
||||
|
||||
frame_info = cogl_onscreen_peek_tail_frame_info (onscreen);
|
||||
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
|
||||
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
|
||||
apply_transform (MetaCrtcKms *crtc_kms,
|
||||
MetaKmsPlaneAssignment *kms_plane_assignment,
|
||||
|
@ -1265,9 +1298,16 @@ swap_buffer_result_feedback (const MetaKmsFeedback *kms_feedback,
|
|||
g_warning ("Page flip failed: %s", error->message);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1394,14 +1434,15 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
|||
switch (renderer_gpu_data->mode)
|
||||
{
|
||||
case META_RENDERER_NATIVE_MODE_GBM:
|
||||
g_warn_if_fail (onscreen_native->gbm.next_fb == NULL);
|
||||
if (onscreen_native->gbm.next_fb != NULL)
|
||||
{
|
||||
CoglFrameInfo *frame_info;
|
||||
|
||||
frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
|
||||
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
|
||||
meta_onscreen_native_notify_frame_complete (onscreen);
|
||||
g_warn_if_fail (onscreen_native->gbm.stalled_fb == NULL);
|
||||
drop_stalled_swap (onscreen);
|
||||
g_assert (onscreen_native->gbm.stalled_fb == NULL);
|
||||
onscreen_native->gbm.stalled_fb =
|
||||
g_steal_pointer (&onscreen_native->gbm.next_fb);
|
||||
onscreen_native->gbm.stalled_scanout =
|
||||
g_steal_pointer (&onscreen_native->gbm.next_scanout);
|
||||
}
|
||||
|
||||
if (onscreen_native->secondary_gpu_state)
|
||||
|
@ -1449,11 +1490,12 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
|||
g_clear_pointer (&onscreen_native->next_post.frame, clutter_frame_unref);
|
||||
onscreen_native->next_post.frame = clutter_frame_ref (frame);
|
||||
|
||||
post_latest_swap (onscreen);
|
||||
onscreen_native->swaps_pending++;
|
||||
try_post_latest_swap (onscreen);
|
||||
}
|
||||
|
||||
static void
|
||||
post_latest_swap (CoglOnscreen *onscreen)
|
||||
try_post_latest_swap (CoglOnscreen *onscreen)
|
||||
{
|
||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
|
||||
|
@ -1472,15 +1514,41 @@ post_latest_swap (CoglOnscreen *onscreen)
|
|||
MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
|
||||
MetaKmsUpdate *kms_update;
|
||||
g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
|
||||
g_autoptr (ClutterFrame) frame =
|
||||
g_steal_pointer (&onscreen_native->next_post.frame);
|
||||
g_autoptr (ClutterFrame) frame = NULL;
|
||||
MetaFrameNative *frame_native;
|
||||
|
||||
if (onscreen_native->next_post.frame == NULL)
|
||||
return;
|
||||
|
||||
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
|
||||
if (power_save_mode == META_POWER_SAVE_ON)
|
||||
{
|
||||
unsigned int frames_pending =
|
||||
cogl_onscreen_count_pending_frames (onscreen);
|
||||
unsigned int posts_pending;
|
||||
|
||||
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 = g_steal_pointer (&onscreen_native->next_post.frame);
|
||||
frame_native = meta_frame_native_from_frame (frame);
|
||||
|
||||
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_device);
|
||||
meta_kms_update_add_result_listener (kms_update,
|
||||
|
@ -1695,6 +1763,18 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
|
|||
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_count_pending_frames (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,
|
||||
render_gpu);
|
||||
|
||||
|
@ -1930,22 +2010,79 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
|
|||
MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
|
||||
MetaFrameNative *frame_native = meta_frame_native_from_frame (frame);
|
||||
MetaKmsUpdate *kms_update;
|
||||
unsigned int frames_pending = cogl_onscreen_count_pending_frames (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);
|
||||
if (!kms_update)
|
||||
onscreen_native->needs_flush |= meta_kms_device_handle_flush (kms_device,
|
||||
kms_crtc);
|
||||
|
||||
if (!meta_frame_native_has_kms_update (frame_native))
|
||||
{
|
||||
if (meta_kms_device_handle_flush (kms_device, kms_crtc))
|
||||
{
|
||||
kms_update = meta_kms_update_new (kms_device);
|
||||
meta_kms_update_set_flushing (kms_update, kms_crtc);
|
||||
}
|
||||
else
|
||||
if (!onscreen_native->needs_flush || posts_pending)
|
||||
{
|
||||
clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE);
|
||||
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_post.frame == NULL);
|
||||
|
||||
g_clear_pointer (&onscreen_native->next_post.frame, clutter_frame_unref);
|
||||
onscreen_native->next_post.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_post.frame != NULL);
|
||||
|
||||
older_frame_native =
|
||||
meta_frame_native_from_frame (onscreen_native->next_post.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,
|
||||
&finish_frame_result_listener_vtable,
|
||||
NULL,
|
||||
|
@ -1968,7 +2105,6 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
|
|||
meta_kms_update_set_flushing (kms_update, kms_crtc);
|
||||
meta_kms_device_post_update (kms_device, kms_update,
|
||||
META_KMS_UPDATE_FLAG_NONE);
|
||||
clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
Loading…
Reference in a new issue