mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
kmssink: add mode setting and base plane rendering
The kmssink assumed that the mode was already set by another application and used an overlay plane for displaying the frames. Use the preferred mode of the monitor and render to the base plane if the crtc does not have a valid mode. https://bugzilla.gnome.org/show_bug.cgi?id=773473 Signed-off-by: Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
This commit is contained in:
parent
e27fc343cc
commit
f52baadd1e
2 changed files with 94 additions and 1 deletions
|
@ -137,6 +137,7 @@ find_crtc_for_connector (int fd, drmModeRes * res, drmModeConnector * conn,
|
||||||
int crtc_id;
|
int crtc_id;
|
||||||
drmModeEncoder *enc;
|
drmModeEncoder *enc;
|
||||||
drmModeCrtc *crtc;
|
drmModeCrtc *crtc;
|
||||||
|
guint32 crtcs_for_connector = 0;
|
||||||
|
|
||||||
crtc_id = -1;
|
crtc_id = -1;
|
||||||
for (i = 0; i < res->count_encoders; i++) {
|
for (i = 0; i < res->count_encoders; i++) {
|
||||||
|
@ -151,6 +152,18 @@ find_crtc_for_connector (int fd, drmModeRes * res, drmModeConnector * conn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If no active crtc was found, pick the first possible crtc */
|
||||||
|
if (crtc_id == -1) {
|
||||||
|
for (i = 0; i < conn->count_encoders; i++) {
|
||||||
|
enc = drmModeGetEncoder (fd, conn->encoders[i]);
|
||||||
|
crtcs_for_connector |= enc->possible_crtcs;
|
||||||
|
drmModeFreeEncoder (enc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crtcs_for_connector != 0)
|
||||||
|
crtc_id = res->crtcs[ffs (crtcs_for_connector) - 1];
|
||||||
|
}
|
||||||
|
|
||||||
if (crtc_id == -1)
|
if (crtc_id == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -241,6 +254,10 @@ find_main_monitor (int fd, drmModeRes * res)
|
||||||
if (!conn)
|
if (!conn)
|
||||||
conn = find_first_used_connector (fd, res);
|
conn = find_first_used_connector (fd, res);
|
||||||
|
|
||||||
|
/* if no connector is used, grab the first one */
|
||||||
|
if (!conn)
|
||||||
|
conn = drmModeGetConnector (fd, res->connectors[0]);
|
||||||
|
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,6 +319,51 @@ get_drm_caps (GstKMSSink * self)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
configure_mode_setting (GstKMSSink * self, guint32 fb_id)
|
||||||
|
{
|
||||||
|
gboolean ret;
|
||||||
|
drmModeConnector *conn;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
ret = FALSE;
|
||||||
|
conn = NULL;
|
||||||
|
|
||||||
|
if (self->conn_id < 0)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
GST_INFO_OBJECT (self, "configuring mode setting");
|
||||||
|
|
||||||
|
conn = drmModeGetConnector (self->fd, self->conn_id);
|
||||||
|
if (!conn)
|
||||||
|
goto connector_failed;
|
||||||
|
|
||||||
|
err = drmModeSetCrtc (self->fd, self->crtc_id, fb_id, 0, 0,
|
||||||
|
(uint32_t *) & self->conn_id, 1, &conn->modes[0]);
|
||||||
|
if (err)
|
||||||
|
goto modesetting_failed;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
|
||||||
|
bail:
|
||||||
|
if (conn)
|
||||||
|
drmModeFreeConnector (conn);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
connector_failed:
|
||||||
|
{
|
||||||
|
GST_ERROR_OBJECT (self, "Could not find a valid monitor connector");
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
modesetting_failed:
|
||||||
|
{
|
||||||
|
GST_ERROR_OBJECT (self, "Failed to set mode: %s", strerror (errno));
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
ensure_allowed_caps (GstKMSSink * self, drmModePlane * plane, drmModeRes * res)
|
ensure_allowed_caps (GstKMSSink * self, drmModePlane * plane, drmModeRes * res)
|
||||||
{
|
{
|
||||||
|
@ -391,6 +453,12 @@ gst_kms_sink_start (GstBaseSink * bsink)
|
||||||
if (!crtc)
|
if (!crtc)
|
||||||
goto crtc_failed;
|
goto crtc_failed;
|
||||||
|
|
||||||
|
if (!crtc->mode_valid) {
|
||||||
|
GST_DEBUG_OBJECT (self, "crtc has no valid mode: enabling modesetting");
|
||||||
|
self->modesetting_enabled = TRUE;
|
||||||
|
universal_planes = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
retry_find_plane:
|
retry_find_plane:
|
||||||
if (universal_planes &&
|
if (universal_planes &&
|
||||||
drmSetClientCap (self->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1))
|
drmSetClientCap (self->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1))
|
||||||
|
@ -807,7 +875,7 @@ gst_kms_sink_sync (GstKMSSink * self)
|
||||||
vbl.request.type |= self->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
|
vbl.request.type |= self->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
|
||||||
|
|
||||||
waiting = TRUE;
|
waiting = TRUE;
|
||||||
if (!self->has_async_page_flip) {
|
if (!self->has_async_page_flip && !self->modesetting_enabled) {
|
||||||
ret = drmWaitVBlank (self->fd, &vbl);
|
ret = drmWaitVBlank (self->fd, &vbl);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto vblank_failed;
|
goto vblank_failed;
|
||||||
|
@ -1038,6 +1106,7 @@ error_map_src_buffer:
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
|
static gboolean setup = FALSE;
|
||||||
gint ret;
|
gint ret;
|
||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
guint32 fb_id;
|
guint32 fb_id;
|
||||||
|
@ -1061,6 +1130,22 @@ gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
||||||
|
|
||||||
GST_TRACE_OBJECT (self, "displaying fb %d", fb_id);
|
GST_TRACE_OBJECT (self, "displaying fb %d", fb_id);
|
||||||
|
|
||||||
|
if (self->modesetting_enabled) {
|
||||||
|
/* Use the current buffer object for configuring the mode, if the mode is
|
||||||
|
* not configured. Preferably the display mode should be set when
|
||||||
|
* configuring the pipeline (during set_caps), but we do not have a buffer
|
||||||
|
* object at that time. */
|
||||||
|
if (!setup) {
|
||||||
|
ret = configure_mode_setting (self, fb_id);
|
||||||
|
if (!ret)
|
||||||
|
goto modesetting_failed;
|
||||||
|
setup = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->buffer_id = fb_id;
|
||||||
|
goto sync_frame;
|
||||||
|
}
|
||||||
|
|
||||||
if ((crop = gst_buffer_get_video_crop_meta (buffer))) {
|
if ((crop = gst_buffer_get_video_crop_meta (buffer))) {
|
||||||
GstVideoInfo vinfo = self->vinfo;
|
GstVideoInfo vinfo = self->vinfo;
|
||||||
vinfo.width = crop->width;
|
vinfo.width = crop->width;
|
||||||
|
@ -1100,6 +1185,7 @@ gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto set_plane_failed;
|
goto set_plane_failed;
|
||||||
|
|
||||||
|
sync_frame:
|
||||||
/* Wait for the previous frame to complete redraw */
|
/* Wait for the previous frame to complete redraw */
|
||||||
if (!gst_kms_sink_sync (self))
|
if (!gst_kms_sink_sync (self))
|
||||||
goto bail;
|
goto bail;
|
||||||
|
@ -1118,6 +1204,11 @@ 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");
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
modesetting_failed:
|
||||||
|
{
|
||||||
|
GST_ERROR_OBJECT (self, "failed to configure display mode");
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
set_plane_failed:
|
set_plane_failed:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (self, "result = { %d, %d, %d, %d} / "
|
GST_DEBUG_OBJECT (self, "result = { %d, %d, %d, %d} / "
|
||||||
|
|
|
@ -62,6 +62,8 @@ struct _GstKMSSink {
|
||||||
gboolean has_prime_import;
|
gboolean has_prime_import;
|
||||||
gboolean has_async_page_flip;
|
gboolean has_async_page_flip;
|
||||||
|
|
||||||
|
gboolean modesetting_enabled;
|
||||||
|
|
||||||
GstVideoInfo vinfo;
|
GstVideoInfo vinfo;
|
||||||
GstCaps *allowed_caps;
|
GstCaps *allowed_caps;
|
||||||
GstBufferPool *pool;
|
GstBufferPool *pool;
|
||||||
|
|
Loading…
Reference in a new issue