mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 18:05:37 +00:00
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
This commit is contained in:
parent
c419d17dbf
commit
b29f7d048c
2 changed files with 115 additions and 8 deletions
|
@ -261,6 +261,7 @@ get_drm_caps (GstKMSSink * self)
|
||||||
gint ret;
|
gint ret;
|
||||||
guint64 has_dumb_buffer;
|
guint64 has_dumb_buffer;
|
||||||
guint64 has_prime;
|
guint64 has_prime;
|
||||||
|
guint64 has_async_page_flip;
|
||||||
|
|
||||||
has_dumb_buffer = 0;
|
has_dumb_buffer = 0;
|
||||||
ret = drmGetCap (self->fd, DRM_CAP_DUMB_BUFFER, &has_dumb_buffer);
|
ret = drmGetCap (self->fd, DRM_CAP_DUMB_BUFFER, &has_dumb_buffer);
|
||||||
|
@ -278,8 +279,16 @@ get_drm_caps (GstKMSSink * self)
|
||||||
else
|
else
|
||||||
self->has_prime_import = (gboolean) (has_prime & DRM_PRIME_CAP_IMPORT);
|
self->has_prime_import = (gboolean) (has_prime & DRM_PRIME_CAP_IMPORT);
|
||||||
|
|
||||||
GST_INFO_OBJECT (self, "prime import (%s)",
|
has_async_page_flip = 0;
|
||||||
self->has_prime_import ? "✓" : "✗");
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -392,6 +401,7 @@ gst_kms_sink_start (GstBaseSink * bsink)
|
||||||
|
|
||||||
self->hdisplay = crtc->mode.hdisplay;
|
self->hdisplay = crtc->mode.hdisplay;
|
||||||
self->vdisplay = crtc->mode.vdisplay;
|
self->vdisplay = crtc->mode.vdisplay;
|
||||||
|
self->buffer_id = crtc->buffer_id;
|
||||||
|
|
||||||
self->mm_width = conn->mmWidth;
|
self->mm_width = conn->mmWidth;
|
||||||
self->mm_height = conn->mmHeight;
|
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",
|
GST_INFO_OBJECT (self, "display size: pixels = %dx%d / millimeters = %dx%d",
|
||||||
self->hdisplay, self->vdisplay, self->mm_width, self->mm_height);
|
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;
|
ret = TRUE;
|
||||||
|
|
||||||
bail:
|
bail:
|
||||||
|
@ -472,6 +486,10 @@ gst_kms_sink_stop (GstBaseSink * bsink)
|
||||||
gst_object_replace ((GstObject **) & self->pool, NULL);
|
gst_object_replace ((GstObject **) & self->pool, NULL);
|
||||||
gst_object_replace ((GstObject **) & self->allocator, 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) {
|
if (self->fd >= 0) {
|
||||||
drmClose (self->fd);
|
drmClose (self->fd);
|
||||||
self->fd = -1;
|
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 *
|
static GstMemory *
|
||||||
get_cached_kmsmem (GstMemory * mem)
|
get_cached_kmsmem (GstMemory * mem)
|
||||||
{
|
{
|
||||||
|
@ -961,9 +1051,12 @@ gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
||||||
GstVideoRectangle src = { 0, };
|
GstVideoRectangle src = { 0, };
|
||||||
GstVideoRectangle dst = { 0, };
|
GstVideoRectangle dst = { 0, };
|
||||||
GstVideoRectangle result;
|
GstVideoRectangle result;
|
||||||
|
GstFlowReturn res;
|
||||||
|
|
||||||
self = GST_KMS_SINK (vsink);
|
self = GST_KMS_SINK (vsink);
|
||||||
|
|
||||||
|
res = GST_FLOW_ERROR;
|
||||||
|
|
||||||
buffer = gst_kms_sink_get_input_buffer (self, buf);
|
buffer = gst_kms_sink_get_input_buffer (self, buf);
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return GST_FLOW_ERROR;
|
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,
|
result.x, result.y, result.w, result.h,
|
||||||
/* source/cropping coordinates are given in Q16 */
|
/* source/cropping coordinates are given in Q16 */
|
||||||
src.x << 16, src.y << 16, src.w << 16, src.h << 16);
|
src.x << 16, src.y << 16, src.w << 16, src.h << 16);
|
||||||
|
|
||||||
gst_buffer_unref (buffer);
|
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto set_plane_failed;
|
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 */
|
/* ERRORS */
|
||||||
buffer_invalid:
|
buffer_invalid:
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (self, "invalid buffer: it doesn't have a fb id");
|
GST_ERROR_OBJECT (self, "invalid buffer: it doesn't have a fb id");
|
||||||
return GST_FLOW_ERROR;
|
goto bail;
|
||||||
}
|
}
|
||||||
set_plane_failed:
|
set_plane_failed:
|
||||||
{
|
{
|
||||||
|
@ -1021,7 +1119,7 @@ set_plane_failed:
|
||||||
dst.h);
|
dst.h);
|
||||||
GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
|
GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
|
||||||
(NULL), ("drmModeSetPlane failed: %s (%d)", strerror (-ret), ret));
|
(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);
|
sink = GST_KMS_SINK (object);
|
||||||
g_clear_pointer (&sink->devname, g_free);
|
g_clear_pointer (&sink->devname, g_free);
|
||||||
|
gst_poll_free (sink->poll);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1081,6 +1180,8 @@ gst_kms_sink_init (GstKMSSink * sink)
|
||||||
{
|
{
|
||||||
sink->fd = -1;
|
sink->fd = -1;
|
||||||
sink->conn_id = -1;
|
sink->conn_id = -1;
|
||||||
|
gst_poll_fd_init (&sink->pollfd);
|
||||||
|
sink->poll = gst_poll_new (TRUE);
|
||||||
gst_video_info_init (&sink->vinfo);
|
gst_video_info_init (&sink->vinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,10 +53,13 @@ struct _GstKMSSink {
|
||||||
gint crtc_id;
|
gint crtc_id;
|
||||||
gint plane_id;
|
gint plane_id;
|
||||||
|
|
||||||
|
/* crtc data */
|
||||||
guint16 hdisplay, vdisplay;
|
guint16 hdisplay, vdisplay;
|
||||||
|
guint32 buffer_id;
|
||||||
|
|
||||||
/* capabilities */
|
/* capabilities */
|
||||||
gboolean has_prime_import;
|
gboolean has_prime_import;
|
||||||
|
gboolean has_async_page_flip;
|
||||||
|
|
||||||
GstVideoInfo vinfo;
|
GstVideoInfo vinfo;
|
||||||
GstCaps *allowed_caps;
|
GstCaps *allowed_caps;
|
||||||
|
@ -66,6 +69,9 @@ struct _GstKMSSink {
|
||||||
gchar *devname;
|
gchar *devname;
|
||||||
|
|
||||||
guint32 mm_width, mm_height;
|
guint32 mm_width, mm_height;
|
||||||
|
|
||||||
|
GstPoll *poll;
|
||||||
|
GstPollFD pollfd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstKMSSinkClass {
|
struct _GstKMSSinkClass {
|
||||||
|
|
Loading…
Reference in a new issue