From b29f7d048cc85af4fbe74c65a3f7ba1064ed8110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Sat, 20 Feb 2016 23:13:54 +0100 Subject: [PATCH] kmssink: wait for page flip or vblank This patch requests for drmModePageFlip() for the used CRTC, if the kernel module suppports async page flip. If it does not, the element requests for a vblank event. A GstPoll waits for the event to happen. https://bugzilla.gnome.org/show_bug.cgi?id=761059 --- sys/kms/gstkmssink.c | 117 ++++++++++++++++++++++++++++++++++++++++--- sys/kms/gstkmssink.h | 6 +++ 2 files changed, 115 insertions(+), 8 deletions(-) diff --git a/sys/kms/gstkmssink.c b/sys/kms/gstkmssink.c index 66777e31ca..ec75e2496f 100644 --- a/sys/kms/gstkmssink.c +++ b/sys/kms/gstkmssink.c @@ -261,6 +261,7 @@ get_drm_caps (GstKMSSink * self) gint ret; guint64 has_dumb_buffer; guint64 has_prime; + guint64 has_async_page_flip; has_dumb_buffer = 0; ret = drmGetCap (self->fd, DRM_CAP_DUMB_BUFFER, &has_dumb_buffer); @@ -278,8 +279,16 @@ get_drm_caps (GstKMSSink * self) else self->has_prime_import = (gboolean) (has_prime & DRM_PRIME_CAP_IMPORT); - GST_INFO_OBJECT (self, "prime import (%s)", - self->has_prime_import ? "✓" : "✗"); + has_async_page_flip = 0; + ret = drmGetCap (self->fd, DRM_CAP_ASYNC_PAGE_FLIP, &has_async_page_flip); + if (ret) + GST_WARNING_OBJECT (self, "could not get async page flip capability"); + else + self->has_async_page_flip = (gboolean) has_async_page_flip; + + GST_INFO_OBJECT (self, "prime import (%s) / async page flip (%s)", + self->has_prime_import ? "✓" : "✗", + self->has_async_page_flip ? "✓" : "✗"); return TRUE; } @@ -392,6 +401,7 @@ gst_kms_sink_start (GstBaseSink * bsink) self->hdisplay = crtc->mode.hdisplay; self->vdisplay = crtc->mode.vdisplay; + self->buffer_id = crtc->buffer_id; self->mm_width = conn->mmWidth; self->mm_height = conn->mmHeight; @@ -399,6 +409,10 @@ gst_kms_sink_start (GstBaseSink * bsink) GST_INFO_OBJECT (self, "display size: pixels = %dx%d / millimeters = %dx%d", self->hdisplay, self->vdisplay, self->mm_width, self->mm_height); + self->pollfd.fd = self->fd; + gst_poll_add_fd (self->poll, &self->pollfd); + gst_poll_fd_ctl_read (self->poll, &self->pollfd, TRUE); + ret = TRUE; bail: @@ -472,6 +486,10 @@ gst_kms_sink_stop (GstBaseSink * bsink) gst_object_replace ((GstObject **) & self->pool, NULL); gst_object_replace ((GstObject **) & self->allocator, NULL); + gst_poll_remove_fd (self->poll, &self->pollfd); + gst_poll_restart (self->poll); + gst_poll_fd_init (&self->pollfd); + if (self->fd >= 0) { drmClose (self->fd); self->fd = -1; @@ -748,6 +766,78 @@ gst_kms_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, } } +static void +sync_handler (gint fd, guint frame, guint sec, guint usec, gpointer data) +{ + gboolean *waiting; + + waiting = data; + *waiting = FALSE; +} + +static gboolean +gst_kms_sink_sync (GstKMSSink * self) +{ + gint ret; + gboolean waiting; + drmEventContext evctxt = { + .version = DRM_EVENT_CONTEXT_VERSION, + .page_flip_handler = sync_handler, + .vblank_handler = sync_handler, + }; + drmVBlank vbl = { + .request = { + .type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT, + .sequence = 1, + .signal = (gulong) & waiting, + }, + }; + + waiting = TRUE; + if (!self->has_async_page_flip) { + ret = drmWaitVBlank (self->fd, &vbl); + if (ret) + goto vblank_failed; + } else { + ret = drmModePageFlip (self->fd, self->crtc_id, self->buffer_id, + DRM_MODE_PAGE_FLIP_EVENT, &waiting); + if (ret) + goto pageflip_failed; + } + + while (waiting) { + do { + ret = gst_poll_wait (self->poll, 3 * GST_SECOND); + } while (ret == -1 && (errno == EAGAIN || errno == EINTR)); + + ret = drmHandleEvent (self->fd, &evctxt); + if (ret) + goto event_failed; + } + + return TRUE; + + /* ERRORS */ +vblank_failed: + { + GST_WARNING_OBJECT (self, "drmWaitVBlank failed: %s (%d)", strerror (-ret), + ret); + return FALSE; + } +pageflip_failed: + { + GST_WARNING_OBJECT (self, "drmModePageFlip failed: %s (%d)", + strerror (-ret), ret); + return FALSE; + } +event_failed: + { + GST_ERROR_OBJECT (self, "drmHandleEvent failed: %s (%d)", strerror (-ret), + ret); + return FALSE; + } +} + static GstMemory * get_cached_kmsmem (GstMemory * mem) { @@ -961,9 +1051,12 @@ gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) GstVideoRectangle src = { 0, }; GstVideoRectangle dst = { 0, }; GstVideoRectangle result; + GstFlowReturn res; self = GST_KMS_SINK (vsink); + res = GST_FLOW_ERROR; + buffer = gst_kms_sink_get_input_buffer (self, buf); if (!buffer) return GST_FLOW_ERROR; @@ -999,19 +1092,24 @@ gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) result.x, result.y, result.w, result.h, /* source/cropping coordinates are given in Q16 */ src.x << 16, src.y << 16, src.w << 16, src.h << 16); - - gst_buffer_unref (buffer); - if (ret) goto set_plane_failed; - return GST_FLOW_OK; + /* Wait for the previous frame to complete redraw */ + if (!gst_kms_sink_sync (self)) + goto bail; + + res = GST_FLOW_OK; + +bail: + gst_buffer_unref (buffer); + return res; /* ERRORS */ buffer_invalid: { GST_ERROR_OBJECT (self, "invalid buffer: it doesn't have a fb id"); - return GST_FLOW_ERROR; + goto bail; } set_plane_failed: { @@ -1021,7 +1119,7 @@ set_plane_failed: dst.h); GST_ELEMENT_ERROR (self, RESOURCE, FAILED, (NULL), ("drmModeSetPlane failed: %s (%d)", strerror (-ret), ret)); - return GST_FLOW_ERROR; + goto bail; } } @@ -1074,6 +1172,7 @@ gst_kms_sink_finalize (GObject * object) sink = GST_KMS_SINK (object); g_clear_pointer (&sink->devname, g_free); + gst_poll_free (sink->poll); } static void @@ -1081,6 +1180,8 @@ gst_kms_sink_init (GstKMSSink * sink) { sink->fd = -1; sink->conn_id = -1; + gst_poll_fd_init (&sink->pollfd); + sink->poll = gst_poll_new (TRUE); gst_video_info_init (&sink->vinfo); } diff --git a/sys/kms/gstkmssink.h b/sys/kms/gstkmssink.h index 90700b4f0b..1f9c0e1fb0 100644 --- a/sys/kms/gstkmssink.h +++ b/sys/kms/gstkmssink.h @@ -53,10 +53,13 @@ struct _GstKMSSink { gint crtc_id; gint plane_id; + /* crtc data */ guint16 hdisplay, vdisplay; + guint32 buffer_id; /* capabilities */ gboolean has_prime_import; + gboolean has_async_page_flip; GstVideoInfo vinfo; GstCaps *allowed_caps; @@ -66,6 +69,9 @@ struct _GstKMSSink { gchar *devname; guint32 mm_width, mm_height; + + GstPoll *poll; + GstPollFD pollfd; }; struct _GstKMSSinkClass {