Skip to content
24 changes: 20 additions & 4 deletions DOCS/man/vo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -488,10 +488,19 @@ Available video output drivers are:
Mode ID to use (resolution and frame rate).
(default: 0)

``--drm-overlay=<number>``
Select the DRM overlay index to use.
Overlay index is zero based, and related to crtc.
(default: 0)
``--drm-osd-plane-id=<number>``
Copy link
Member

@xantoz xantoz Apr 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the documentation of these options (--drm-osd-plane-id, --drm-video-plane-id) from this commit, to commit 540fec5 when they are introduced in the code.
Like now the documentation will have been introduced before the options.

Select the DRM planed index to use for OSD (or OSD and video).
Index is zero based, and related to crtc.
When using this option with drm_prime renderer, it will only affect
the OSD contents. Otherwise it will set OSD & video plane.
(default: primary plane)

``--drm-video-plane-id=<number>``
Select the DRM planed index to use for video layer.
Index is zero based, and related to crtc.
This option only has effect when using the drm_prime renderer (which
supports several layers) together with ``vo=gpu`` and ``gpu-context=drm``.
(default: first overlay plane)

``--drm-format=<xrgb8888,xrgb2101010>``
Select the DRM format to use (default: xrgb8888). This allows you to
Expand All @@ -506,6 +515,13 @@ Available video output drivers are:
This currently only has an effect when used together with the ``drm``
backend for the ``gpu`` VO. The ``drm`` VO always uses xrgb8888.

``--drm-osd-size=<[WxH]>``
Sets the OSD OpenGL size to the specified size. OSD will then be upscaled
to the current screen resolution. This option can be useful when using
several layers in high resolutions with a GPU which cannot handle it.
Note : this option is only available with DRM atomic support.
(default: display resolution)

``mediacodec_embed`` (Android)
Renders ``IMGFMT_MEDIACODEC`` frames directly to an ``android.view.Surface``.
Requires ``--hwdec=mediacodec`` for hardware decoding, along with
Expand Down
3 changes: 3 additions & 0 deletions libmpv/opengl_cb.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ struct mpv_opengl_cb_drm_params {
// currently used crtc id
int crtc_id;

// currently used connector id
int connector_id;

// pointer to the drmModeAtomicReq that is being used for the renderloop.
// This atomic request pointer should be usually created at every renderloop.
struct _drmModeAtomicReq *atomic_request;
Expand Down
12 changes: 12 additions & 0 deletions libmpv/render.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,18 @@ typedef enum mpv_render_param_type {
* in the same way.
*/
MPV_RENDER_PARAM_SKIP_RENDERING = 13,
/**
* DRM display, contains drm display handles.
* Valid for mpv_render_context_create().
* Type : struct mpv_opengl_drm_params*
*/
MPV_RENDER_PARAM_DRM_DISPLAY = 14,
/**
* DRM osd size, contains osd dimensions.
* Valid for mpv_render_context_create().
* Type : struct mpv_opengl_drm_osd_size*
*/
MPV_RENDER_PARAM_DRM_OSD_SIZE = 15,
} mpv_render_param_type;

/**
Expand Down
31 changes: 31 additions & 0 deletions libmpv/render_gl.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,37 @@ typedef struct mpv_opengl_fbo {
int internal_format;
} mpv_opengl_fbo;

typedef struct mpv_opengl_drm_params {
/**
* DRM fd (int). set this to -1 if invalid.
*/
int fd;

/**
* Currently used crtc id
*/
int crtc_id;

/**
* Currently used connector id
*/
int connector_id;

/**
* Pointer to a drmModeAtomicReq pointer that is being used for the renderloop.
* This pointer should hold a pointer to the atomic request pointer
* The atomic request pointer is usually changed at every renderloop.
*/
struct _drmModeAtomicReq **atomic_request_ptr;
} mpv_opengl_drm_params;

typedef struct mpv_opengl_drm_osd_size {
/**
* size of the OSD in pixels.
*/
int width, height;
} mpv_opengl_drm_osd_size;

#ifdef __cplusplus
}
#endif
Expand Down
102 changes: 78 additions & 24 deletions video/out/drm_atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ int drm_object_get_property(struct drm_object *object, char *name, uint64_t *val
return -EINVAL;
}

drmModePropertyBlobPtr drm_object_get_property_blob(struct drm_object *object, char *name)
{
uint64_t blob_id;

if (!drm_object_get_property(object, name, &blob_id)) {
return drmModeGetPropertyBlob(object->fd, blob_id);
}

return NULL;
}

int drm_object_set_property(drmModeAtomicReq *request, struct drm_object *object,
char *name, uint64_t value)
{
Expand All @@ -98,6 +109,7 @@ struct drm_object * drm_object_create(struct mp_log *log, int fd,
obj = talloc_zero(NULL, struct drm_object);
obj->id = object_id;
obj->type = type;
obj->fd = fd;

if (drm_object_create_properties(log, fd, obj)) {
talloc_free(obj);
Expand Down Expand Up @@ -125,16 +137,19 @@ void drm_object_print_info(struct mp_log *log, struct drm_object *object)
(long long)object->props->prop_values[i]);
}

struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd,
int crtc_id, int overlay_id)
struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd, int crtc_id,
int connector_id, int osd_plane_id, int video_plane_id)
{
drmModePlane *drmplane = NULL;
drmModePlaneRes *plane_res = NULL;
drmModeRes *res = NULL;
struct drm_object *plane = NULL;
struct drm_atomic_context *ctx;
int crtc_index = -1;
int layercount = 0;
int layercount = -1;
int primary_id = 0;
int overlay_id = 0;

uint64_t value;

res = drmModeGetResources(fd);
Expand Down Expand Up @@ -169,6 +184,19 @@ struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd,
}
}

for (int i = 0; i < res->count_connectors; i++) {
drmModeConnector *connector = drmModeGetConnector(fd, res->connectors[i]);
if (connector) {
if (connector->connector_id == connector_id)
ctx->connector = drm_object_create(log, ctx->fd, connector->connector_id,
DRM_MODE_OBJECT_CONNECTOR);

drmModeFreeConnector(connector);
if (ctx->connector)
break;
}
}

for (unsigned int j = 0; j < plane_res->count_planes; j++) {

drmplane = drmModeGetPlane (ctx->fd, plane_res->planes[j]);
Expand All @@ -181,20 +209,29 @@ struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd,
mp_err(log, "Unable to retrieve type property from plane %d\n", j);
goto fail;
} else {
if ((value == DRM_PLANE_TYPE_OVERLAY) &&
(layercount == overlay_id)) {
ctx->overlay_plane = plane;
}
else if (value == DRM_PLANE_TYPE_PRIMARY) {
ctx->primary_plane = plane;
if (value == DRM_PLANE_TYPE_CURSOR) // Skip cursor planes
continue;

layercount++;

if ((!primary_id) && (value == DRM_PLANE_TYPE_PRIMARY))
primary_id = drmplane->plane_id;

if ((!overlay_id) && (value == DRM_PLANE_TYPE_OVERLAY))
overlay_id = drmplane->plane_id;

if (layercount == osd_plane_id) {
ctx->osd_plane = plane;
continue;
}
else {
drm_object_free(plane);
plane = NULL;

if (layercount == video_plane_id) {
ctx->video_plane = plane;
continue;
}

if (value == DRM_PLANE_TYPE_OVERLAY)
layercount++;
drm_object_free(plane);
plane = NULL;
}
} else {
mp_err(log, "Failed to create Plane object from plane ID %d\n",
Expand All @@ -206,18 +243,34 @@ struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd,
drmplane = NULL;
}

if (!ctx->primary_plane) {
mp_err(log, "Failed to find primary plane\n");
goto fail;
// default OSD plane to primary if unspecified
if (!ctx->osd_plane) {
if (primary_id) {
mp_verbose(log, "Using default plane %d for OSD\n", primary_id);
ctx->osd_plane = drm_object_create(log, ctx->fd, primary_id, DRM_MODE_OBJECT_PLANE);
} else {
mp_err(log, "Failed to find OSD plane with id=%d\n", osd_plane_id);
goto fail;
}
} else {
mp_verbose(log, "Found OSD plane with ID %d\n", ctx->osd_plane->id);
}

if (!ctx->overlay_plane) {
mp_err(log, "Failed to find overlay plane with id=%d\n", overlay_id);
goto fail;
// default video plane to overlay if unspecified
if (!ctx->video_plane) {
if (overlay_id) {
mp_verbose(log, "Using default plane %d for video\n", overlay_id);
ctx->video_plane = drm_object_create(log, ctx->fd, overlay_id, DRM_MODE_OBJECT_PLANE);
} else {
mp_err(log, "Failed to find video plane with id=%d\n", video_plane_id);
goto fail;
}
} else {
mp_verbose(log, "Found video plane with ID %d\n", ctx->video_plane->id);
}

mp_verbose(log, "Found Primary plane with ID %d, overlay with ID %d\n",
ctx->primary_plane->id, ctx->overlay_plane->id);
mp_verbose(log, "Found Video plane with ID %d, OSD with ID %d\n",
ctx->video_plane->id, ctx->osd_plane->id);

drmModeFreePlaneResources(plane_res);
drmModeFreeResources(res);
Expand All @@ -239,7 +292,8 @@ struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd,
void drm_atomic_destroy_context(struct drm_atomic_context *ctx)
{
drm_object_free(ctx->crtc);
drm_object_free(ctx->primary_plane);
drm_object_free(ctx->overlay_plane);
drm_object_free(ctx->connector);
drm_object_free(ctx->osd_plane);
drm_object_free(ctx->video_plane);
talloc_free(ctx);
}
10 changes: 7 additions & 3 deletions video/out/drm_atomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "common/msg.h"

struct drm_object {
int fd;
uint32_t id;
uint32_t type;
drmModeObjectProperties *props;
Expand All @@ -35,8 +36,9 @@ struct drm_atomic_context {
int fd;

struct drm_object *crtc;
struct drm_object *primary_plane;
struct drm_object *overlay_plane;
struct drm_object *connector;
struct drm_object *osd_plane;
struct drm_object *video_plane;

drmModeAtomicReq *request;
};
Expand All @@ -46,10 +48,12 @@ int drm_object_create_properties(struct mp_log *log, int fd, struct drm_object *
void drm_object_free_properties(struct drm_object *object);
int drm_object_get_property(struct drm_object *object, char *name, uint64_t *value);
int drm_object_set_property(drmModeAtomicReq *request, struct drm_object *object, char *name, uint64_t value);
drmModePropertyBlobPtr drm_object_get_property_blob(struct drm_object *object, char *name);
struct drm_object * drm_object_create(struct mp_log *log, int fd, uint32_t object_id, uint32_t type);
void drm_object_free(struct drm_object *object);
void drm_object_print_info(struct mp_log *log, struct drm_object *object);
struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd, int crtc_id, int overlay_id);
struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd, int crtc_id, int connector_id,
int osd_plane_id, int video_plane_id);
void drm_atomic_destroy_context(struct drm_atomic_context *ctx);

#endif // MP_DRMATOMIC_H
41 changes: 37 additions & 4 deletions video/out/drm_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,18 @@ const struct m_sub_options drm_conf = {
OPT_STRING_VALIDATE("drm-connector", drm_connector_spec,
0, drm_validate_connector_opt),
OPT_INT("drm-mode", drm_mode_id, 0),
OPT_INT("drm-overlay", drm_overlay_id, 0),
OPT_INT("drm-osd-plane-id", drm_osd_plane_id, 0),
Copy link
Member

@xantoz xantoz Apr 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we not document these options as well? If we do we probably also need to clarify when what plane is used. That only when using drmprime hwdec is the video actually rendered to the video plane, and the "overlay plane" is the normal plane &c.

I guess we could consider it internal/primarily for API use due to the confusing nature...

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All options must be documented.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, I thought I had done it, but will add it.

OPT_INT("drm-video-plane-id", drm_video_plane_id, 0),
OPT_CHOICE("drm-format", drm_format, 0,
({"xrgb8888", DRM_OPTS_FORMAT_XRGB8888},
{"xrgb2101010", DRM_OPTS_FORMAT_XRGB2101010})),
OPT_SIZE_BOX("drm-osd-size", drm_osd_size, 0),
{0},
},
.defaults = &(const struct drm_opts) {
.drm_osd_plane_id = -1,
.drm_video_plane_id = -1,
},
.size = sizeof(struct drm_opts),
};

Expand Down Expand Up @@ -167,6 +173,27 @@ static bool setup_connector(struct kms *kms, const drmModeRes *res,

static bool setup_crtc(struct kms *kms, const drmModeRes *res)
{
// First try to find currently connected encoder and its current CRTC
for (unsigned int i = 0; i < res->count_encoders; i++) {
drmModeEncoder *encoder = drmModeGetEncoder(kms->fd, res->encoders[i]);
if (!encoder) {
MP_WARN(kms, "Cannot retrieve encoder %u:%u: %s\n",
i, res->encoders[i], mp_strerror(errno));
continue;
}

if (encoder->encoder_id == kms->connector->encoder_id && encoder->crtc_id != 0) {
MP_VERBOSE(kms, "Connector %u currently connected to encoder %u\n",
kms->connector->connector_id, kms->connector->encoder_id);
kms->encoder = encoder;
kms->crtc_id = encoder->crtc_id;
goto success;
}

drmModeFreeEncoder(encoder);
}

// Otherwise pick first legal encoder and CRTC combo for the connector
for (unsigned int i = 0; i < kms->connector->count_encoders; ++i) {
drmModeEncoder *encoder
= drmModeGetEncoder(kms->fd, kms->connector->encoders[i]);
Expand All @@ -184,7 +211,7 @@ static bool setup_crtc(struct kms *kms, const drmModeRes *res)

kms->encoder = encoder;
kms->crtc_id = res->crtcs[j];
return true;
goto success;
}

drmModeFreeEncoder(encoder);
Expand All @@ -193,6 +220,11 @@ static bool setup_crtc(struct kms *kms, const drmModeRes *res)
MP_ERR(kms, "Connector %u has no suitable CRTC\n",
kms->connector->connector_id);
return false;

success:
MP_VERBOSE(kms, "Selected Encoder %u with CRTC %u\n",
kms->encoder->encoder_id, kms->crtc_id);
return true;
}

static bool setup_mode(struct kms *kms, int mode_id)
Expand Down Expand Up @@ -237,7 +269,7 @@ static void parse_connector_spec(struct mp_log *log,


struct kms *kms_create(struct mp_log *log, const char *connector_spec,
int mode_id, int overlay_id)
int mode_id, int osd_plane_id, int video_plane_id)
{
int card_no = -1;
char *connector_name = NULL;
Expand Down Expand Up @@ -284,7 +316,8 @@ struct kms *kms_create(struct mp_log *log, const char *connector_spec,
mp_verbose(log, "No DRM Atomic support found\n");
} else {
mp_verbose(log, "DRM Atomic support found\n");
kms->atomic_context = drm_atomic_create_context(kms->log, kms->fd, kms->crtc_id, overlay_id);
kms->atomic_context = drm_atomic_create_context(kms->log, kms->fd, kms->crtc_id,
kms->connector->connector_id, osd_plane_id, video_plane_id);
if (!kms->atomic_context) {
mp_err(log, "Failed to create DRM atomic context\n");
goto err;
Expand Down
Loading