summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLionel CHAZALLON <LongChair@hotmail.com>2017-10-23 08:51:49 -0700
committerwm4 <wm4@nowhere>2017-10-23 21:07:24 +0200
commitcfcee4cfe70536faeb9f2aaa87257d067e902b70 (patch)
treeb6dfc61144a7394974657b5dfdfc34d9fcf1576a
parent762b8cc30007480f06d338ac77d6e91cc04cd320 (diff)
downloadmpv-cfcee4cfe70536faeb9f2aaa87257d067e902b70.tar.bz2
mpv-cfcee4cfe70536faeb9f2aaa87257d067e902b70.tar.xz
Add DRM_PRIME Format Handling and Display for RockChip MPP decoders
This commit allows to use the AV_PIX_FMT_DRM_PRIME newly introduced format in ffmpeg that allows decoders to provide an AVDRMFrameDescriptor struct. That struct holds dmabuf fds and information allowing zerocopy rendering using KMS / DRM Atomic. This has been tested on RockChip ROCK64 device.
-rw-r--r--DOCS/man/vo.rst5
-rw-r--r--libmpv/opengl_cb.h38
-rw-r--r--options/options.c2
-rw-r--r--options/options.h1
-rw-r--r--video/decode/vd_lavc.c7
-rw-r--r--video/fmt-conversion.c3
-rw-r--r--video/hwdec.h1
-rw-r--r--video/img_format.h1
-rw-r--r--video/out/drm_atomic.c244
-rw-r--r--video/out/drm_atomic.h55
-rw-r--r--video/out/drm_common.c23
-rw-r--r--video/out/drm_common.h4
-rw-r--r--video/out/drm_prime.c85
-rw-r--r--video/out/drm_prime.h33
-rw-r--r--video/out/gpu/hwdec.c7
-rw-r--r--video/out/opengl/context_drm_egl.c69
-rw-r--r--video/out/opengl/hwdec_drmprime_drm.c258
-rw-r--r--video/out/vo_drm.c2
-rw-r--r--wscript5
-rw-r--r--wscript_build.py3
20 files changed, 823 insertions, 23 deletions
diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst
index 5d22ab15e7..f4ebb64629 100644
--- a/DOCS/man/vo.rst
+++ b/DOCS/man/vo.rst
@@ -504,6 +504,11 @@ Available video output drivers are:
Mode ID to use (resolution, bit depth 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)
+
``mediacodec_embed`` (Android)
Renders ``IMGFMT_MEDIACODEC`` frames directly to an ``android.view.Surface``.
Requires ``--hwdec=mediacodec`` for hardware decoding, along with
diff --git a/libmpv/opengl_cb.h b/libmpv/opengl_cb.h
index 799e353a41..1434c6cee3 100644
--- a/libmpv/opengl_cb.h
+++ b/libmpv/opengl_cb.h
@@ -151,6 +151,24 @@ extern "C" {
* up until mpv_opengl_cb_uninit_gl() is called. If the name is not anything
* you know/expected, return NULL from the function.
*
+ * * Windowing system scaling
+ * ------------------------------------
+ *
+ * When using GL, sometimes GL rendering window is upscaled to display buffer.
+ * Typically with drm where GL framebuffer can be upscaled at later stage.
+ * In That case glMPGetNativeDisplay("opengl-cb-window-pos") should return an
+ * mpv_opengl_cb_window_pos struct pointer defined below.
+ * Note : The intended use is for hardware overlays that might require
+ * upscaling features (typically upscaling GL windows with drm to screen size).
+ */
+struct mpv_opengl_cb_window_pos {
+ int x; // left coordinates of window (usually 0)
+ int y; // top coordinates of window (usually 0)
+ int width; // width of GL window
+ int height; // height of GL window
+};
+
+/**
* Windowing system interop on Intel/Linux with VAAPI
* --------------------------------------------------
*
@@ -163,10 +181,22 @@ extern "C" {
*
* glMPGetNativeDisplay("wl") should return a Wayland "struct wl_display *".
*
- * glMPGetNativeDisplay("drm") should return a DRM FD casted to intptr_t (note
- * that a 0 FD is not supported - if this can happen in your case, you must
- * dup2() it to a non-0 FD).
- *
+ * glMPGetNativeDisplay("opengl-cb-drm-params") should return an
+ * mpv_opengl_cb_drm_params structure pointer :
+ */
+struct mpv_opengl_cb_drm_params {
+ // DRM fd (int). set this to -1 if invalid.
+ int fd;
+
+ // currently used crtc id
+ int crtc_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;
+};
+
+/**
* nVidia/Linux via VDPAU requires GLX, which does not have this problem (the
* GLX API can return the current X11 Display).
*
diff --git a/options/options.c b/options/options.c
index 2f26402526..a79a57f449 100644
--- a/options/options.c
+++ b/options/options.c
@@ -111,6 +111,7 @@ const struct m_opt_choice_alternatives mp_hwdec_names[] = {
{"d3d11va-copy",HWDEC_D3D11VA_COPY},
{"rpi", HWDEC_RPI},
{"rpi-copy", HWDEC_RPI_COPY},
+ {"rkmpp", HWDEC_RKMPP},
{"mediacodec", HWDEC_MEDIACODEC},
{"mediacodec-copy",HWDEC_MEDIACODEC_COPY},
{"cuda", HWDEC_CUDA},
@@ -181,6 +182,7 @@ static const m_option_t mp_vo_opt_list[] = {
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),
#endif
OPT_STRING_VALIDATE("opengl-hwdec-interop", gl_hwdec_interop, 0,
ra_hwdec_validate_opt),
diff --git a/options/options.h b/options/options.h
index e56ed7d619..008111ade3 100644
--- a/options/options.h
+++ b/options/options.h
@@ -57,6 +57,7 @@ typedef struct mp_vo_opts {
// vo_drm
char *drm_connector_spec;
int drm_mode_id;
+ int drm_overlay_id;
} mp_vo_opts;
struct mp_cache_opts {
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index 513eded9a4..bf610e83e4 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -151,6 +151,12 @@ static const struct vd_lavc_hwdec mp_vd_lavc_rpi_copy = {
};
#endif
+static const struct vd_lavc_hwdec mp_vd_lavc_rkmpp = {
+ .type = HWDEC_RKMPP,
+ .lavc_suffix = "_rkmpp",
+ .image_format = IMGFMT_DRMPRIME,
+};
+
#if HAVE_CUDA_HWACCEL
static const struct vd_lavc_hwdec mp_vd_lavc_cuda = {
.type = HWDEC_CUDA,
@@ -270,6 +276,7 @@ static const struct vd_lavc_hwdec *const hwdec_list[] = {
&mp_vd_lavc_cuda_copy,
#endif
&mp_vd_lavc_crystalhd,
+ &mp_vd_lavc_rkmpp,
NULL
};
diff --git a/video/fmt-conversion.c b/video/fmt-conversion.c
index 0bdbd109bb..e89ea6cd59 100644
--- a/video/fmt-conversion.c
+++ b/video/fmt-conversion.c
@@ -75,6 +75,9 @@ static const struct {
{IMGFMT_CUDA, AV_PIX_FMT_CUDA},
#endif
{IMGFMT_P010, AV_PIX_FMT_P010},
+#if HAVE_DRMPRIME
+ {IMGFMT_DRMPRIME, AV_PIX_FMT_DRM_PRIME},
+#endif
{0, AV_PIX_FMT_NONE}
};
diff --git a/video/hwdec.h b/video/hwdec.h
index a432ecce2c..81ba4794b2 100644
--- a/video/hwdec.h
+++ b/video/hwdec.h
@@ -27,6 +27,7 @@ enum hwdec_type {
HWDEC_CUDA,
HWDEC_CUDA_COPY,
HWDEC_CRYSTALHD,
+ HWDEC_RKMPP,
};
#define HWDEC_IS_AUTO(x) ((x) == HWDEC_AUTO || (x) == HWDEC_AUTO_COPY)
diff --git a/video/img_format.h b/video/img_format.h
index 01d101aa8e..123c8ba55e 100644
--- a/video/img_format.h
+++ b/video/img_format.h
@@ -204,6 +204,7 @@ enum mp_imgfmt {
IMGFMT_MMAL, // MMAL_BUFFER_HEADER_T
IMGFMT_VIDEOTOOLBOX, // CVPixelBufferRef
IMGFMT_MEDIACODEC, // AVMediaCodecBuffer
+ IMGFMT_DRMPRIME, // AVDRMFrameDescriptor
IMGFMT_CUDA, // CUDA Buffer
// Generic pass-through of AV_PIX_FMT_*. Used for formats which don't have
diff --git a/video/out/drm_atomic.c b/video/out/drm_atomic.c
new file mode 100644
index 0000000000..a908826677
--- /dev/null
+++ b/video/out/drm_atomic.c
@@ -0,0 +1,244 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+
+#include "common/common.h"
+#include "common/msg.h"
+#include "drm_atomic.h"
+
+int drm_object_create_properties(struct mp_log *log, int fd,
+ struct drm_object *object)
+{
+ object->props = drmModeObjectGetProperties(fd, object->id, object->type);
+ if (object->props) {
+ object->props_info = talloc_zero_size(NULL, object->props->count_props
+ * sizeof(object->props_info));
+ if (object->props_info) {
+ for (int i = 0; i < object->props->count_props; i++)
+ object->props_info[i] = drmModeGetProperty(fd, object->props->props[i]);
+ } else {
+ mp_err(log, "Out of memory\n");
+ goto fail;
+ }
+ } else {
+ mp_err(log, "Failed to retrieve properties for object id %d\n", object->id);
+ goto fail;
+ }
+
+ return 0;
+
+ fail:
+ drm_object_free_properties(object);
+ return -1;
+}
+
+void drm_object_free_properties(struct drm_object *object)
+{
+ if (object->props) {
+ for (int i = 0; i < object->props->count_props; i++) {
+ if (object->props_info[i]) {
+ drmModeFreeProperty(object->props_info[i]);
+ object->props_info[i] = NULL;
+ }
+ }
+
+ talloc_free(object->props_info);
+ object->props_info = NULL;
+
+ drmModeFreeObjectProperties(object->props);
+ object->props = NULL;
+ }
+}
+
+int drm_object_get_property(struct drm_object *object, char *name, uint64_t *value)
+{
+ for (int i = 0; i < object->props->count_props; i++) {
+ if (strcasecmp(name, object->props_info[i]->name) == 0) {
+ *value = object->props->prop_values[i];
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+int drm_object_set_property(drmModeAtomicReq *request, struct drm_object *object,
+ char *name, uint64_t value)
+{
+ for (int i = 0; i < object->props->count_props; i++) {
+ if (strcasecmp(name, object->props_info[i]->name) == 0) {
+ return drmModeAtomicAddProperty(request, object->id,
+ object->props_info[i]->prop_id, value);
+ }
+ }
+
+ return -EINVAL;
+}
+
+struct drm_object * drm_object_create(struct mp_log *log, int fd,
+ uint32_t object_id, uint32_t type)
+{
+ struct drm_object *obj = NULL;
+ obj = talloc_zero(NULL, struct drm_object);
+ obj->id = object_id;
+ obj->type = type;
+
+ if (drm_object_create_properties(log, fd, obj)) {
+ talloc_free(obj);
+ return NULL;
+ }
+
+ return obj;
+}
+
+void drm_object_free(struct drm_object *object)
+{
+ if (object) {
+ drm_object_free_properties(object);
+ talloc_free(object);
+ }
+}
+
+void drm_object_print_info(struct mp_log *log, struct drm_object *object)
+{
+ mp_err(log, "Object ID = %d (type = %x) has %d properties\n",
+ object->id, object->type, object->props->count_props);
+
+ for (int i = 0; i < object->props->count_props; i++)
+ mp_err(log, " Property '%s' = %lld\n", object->props_info[i]->name,
+ (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)
+{
+ 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;
+ uint64_t value;
+
+ res = drmModeGetResources(fd);
+ if (!res) {
+ mp_err(log, "Cannot retrieve DRM resources: %s\n", mp_strerror(errno));
+ goto fail;
+ }
+
+ plane_res = drmModeGetPlaneResources(fd);
+ if (!plane_res) {
+ mp_err(log, "Cannot retrieve plane ressources: %s\n", mp_strerror(errno));
+ goto fail;
+ }
+
+ ctx = talloc_zero(NULL, struct drm_atomic_context);
+ if (!ctx) {
+ mp_err(log, "Out of memory\n");
+ goto fail;
+ }
+
+ ctx->fd = fd;
+ ctx->crtc = drm_object_create(log, ctx->fd, crtc_id, DRM_MODE_OBJECT_CRTC);
+ if (!ctx->crtc) {
+ mp_err(log, "Failed to create CRTC object\n");
+ goto fail;
+ }
+
+ for (int i = 0; i < res->count_crtcs; i++) {
+ if (res->crtcs[i] == crtc_id) {
+ crtc_index = i;
+ break;
+ }
+ }
+
+ for (unsigned int j = 0; j < plane_res->count_planes; j++) {
+
+ drmplane = drmModeGetPlane (ctx->fd, plane_res->planes[j]);
+ if (drmplane->possible_crtcs & (1 << crtc_index)) {
+ plane = drm_object_create(log, ctx->fd, drmplane->plane_id,
+ DRM_MODE_OBJECT_PLANE);
+
+ if (plane) {
+ if (drm_object_get_property(plane, "TYPE", &value) == -EINVAL) {
+ 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;
+ }
+ else {
+ drm_object_free(plane);
+ plane = NULL;
+ }
+
+ if (value == DRM_PLANE_TYPE_OVERLAY)
+ layercount++;
+ }
+ } else {
+ mp_err(log, "Failed to create Plane object from plane ID %d\n",
+ drmplane->plane_id);
+ goto fail;
+ }
+ }
+ drmModeFreePlane(drmplane);
+ }
+
+ if (!ctx->primary_plane) {
+ mp_err(log, "Failed to find primary plane\n");
+ goto fail;
+ }
+
+ if (!ctx->overlay_plane) {
+ mp_err(log, "Failed to find overlay plane with id=%d\n", overlay_id);
+ goto fail;
+ }
+
+ mp_verbose(log, "Found Primary plane with ID %d, overlay with ID %d\n",
+ ctx->primary_plane->id, ctx->overlay_plane->id);
+
+ drmModeFreePlaneResources(plane_res);
+ drmModeFreeResources(res);
+ return ctx;
+
+
+fail:
+ if (res)
+ drmModeFreeResources(res);
+ if (plane_res)
+ drmModeFreePlaneResources(plane_res);
+ if (drmplane)
+ drmModeFreePlane(drmplane);
+ if (plane)
+ drm_object_free(plane);
+ return false;
+}
+
+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);
+ talloc_free(ctx);
+}
diff --git a/video/out/drm_atomic.h b/video/out/drm_atomic.h
new file mode 100644
index 0000000000..d0ebdb910e
--- /dev/null
+++ b/video/out/drm_atomic.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MP_DRMATOMIC_H
+#define MP_DRMATOMIC_H
+
+#include <stdlib.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "common/msg.h"
+
+struct drm_object {
+ uint32_t id;
+ uint32_t type;
+ drmModeObjectProperties *props;
+ drmModePropertyRes **props_info;
+};
+
+struct drm_atomic_context {
+ int fd;
+
+ struct drm_object *crtc;
+ struct drm_object *primary_plane;
+ struct drm_object *overlay_plane;
+
+ drmModeAtomicReq *request;
+};
+
+
+int drm_object_create_properties(struct mp_log *log, int fd, struct drm_object *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);
+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);
+void drm_atomic_destroy_context(struct drm_atomic_context *ctx);
+
+#endif // MP_DRMATOMIC_H
diff --git a/video/out/drm_common.c b/video/out/drm_common.c
index aea4afaa09..c1f374118a 100644
--- a/video/out/drm_common.c
+++ b/video/out/drm_common.c
@@ -222,7 +222,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 mode_id, int overlay_id)
{
int card_no = -1;
char *connector_name = NULL;
@@ -260,6 +260,23 @@ struct kms *kms_create(struct mp_log *log, const char *connector_spec,
if (!setup_mode(kms, mode_id))
goto err;
+ // Universal planes allows accessing all the planes (including primary)
+ if (drmSetClientCap(kms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) {
+ mp_err(log, "Failed to set Universal planes capability\n");
+ }
+
+ if (drmSetClientCap(kms->fd, DRM_CLIENT_CAP_ATOMIC, 1)) {
+ 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);
+ if (!kms->atomic_context) {
+ mp_err(log, "Failed to create DRM atomic context\n");
+ goto err;
+ }
+ }
+
+
drmModeFreeResources(res);
return kms;
@@ -284,6 +301,10 @@ void kms_destroy(struct kms *kms)
drmModeFreeEncoder(kms->encoder);
kms->encoder = NULL;
}
+ if (kms->atomic_context) {
+ drm_atomic_destroy_context(kms->atomic_context);
+ }
+
close(kms->fd);
talloc_free(kms);
}
diff --git a/video/out/drm_common.h b/video/out/drm_common.h
index 6796472cfc..0e6e76d03e 100644
--- a/video/out/drm_common.h
+++ b/video/out/drm_common.h
@@ -22,6 +22,7 @@
#include <xf86drm.h>
#include <xf86drmMode.h>
#include "options/m_option.h"
+#include "drm_atomic.h"
struct kms {
struct mp_log *log;
@@ -31,6 +32,7 @@ struct kms {
drmModeModeInfo mode;
uint32_t crtc_id;
int card_no;
+ struct drm_atomic_context *atomic_context;
};
struct vt_switcher {
@@ -51,7 +53,7 @@ void vt_switcher_release(struct vt_switcher *s, void (*handler)(void*),
void *user_data);
struct kms *kms_create(struct mp_log *log, const char *connector_spec,
- int mode_id);
+ int mode_id, int overlay_id);
void kms_destroy(struct kms *kms);
double kms_get_display_fps(const struct kms *kms);
diff --git a/video/out/drm_prime.c b/video/out/drm_prime.c
new file mode 100644
index 0000000000..253fbb6c40
--- /dev/null
+++ b/video/out/drm_prime.c
@@ -0,0 +1,85 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <unistd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "common/msg.h"
+#include "drm_common.h"
+#include "drm_prime.h"
+
+int drm_prime_create_framebuffer(struct mp_log *log, int fd, AVDRMFrameDescriptor *descriptor, int width, int height,
+ struct drm_prime_framebuffer *framebuffer)
+{
+ AVDRMLayerDescriptor *layer = NULL;
+ uint32_t pitches[4], offsets[4], handles[4];
+ int ret, layer_fd;
+
+ if (descriptor && descriptor->nb_layers) {
+ *framebuffer = (struct drm_prime_framebuffer){0};
+
+ for (int object = 0; object < descriptor->nb_objects; object++) {
+ ret = drmPrimeFDToHandle(fd, descriptor->objects[object].fd, &framebuffer->gem_handles[object]);
+ if (ret < 0) {
+ mp_err(log, "Failed to retrieve the Prime Handle from handle %d (%d).\n", object, descriptor->objects[object].fd);
+ goto fail;
+ }
+ }
+
+ layer = &descriptor->layers[0];
+
+ for (int plane = 0; plane < AV_DRM_MAX_PLANES; plane++) {
+ layer_fd = framebuffer->gem_handles[layer->planes[plane].object_index];
+ if (layer_fd && layer->planes[plane].pitch) {
+ pitches[plane] = layer->planes[plane].pitch;
+ offsets[plane] = layer->planes[plane].offset;
+ handles[plane] = layer_fd;
+ } else {
+ pitches[plane] = 0;
+ offsets[plane] = 0;
+ handles[plane] = 0;
+ }
+ }
+
+ ret = drmModeAddFB2(fd, width, height, layer->format,
+ handles, pitches, offsets, &framebuffer->fb_id, 0);
+ if (ret < 0) {
+ mp_err(log, "Failed to create framebuffer on layer %d.\n", 0);
+ goto fail;
+ }
+ }
+
+ return 0;
+
+fail:
+ memset(framebuffer, 0, sizeof(*framebuffer));
+ return -1;
+}
+
+void drm_prime_destroy_framebuffer(struct mp_log *log, int fd, struct drm_prime_framebuffer *framebuffer)
+{
+ if (framebuffer->fb_id)
+ drmModeRmFB(fd, framebuffer->fb_id);
+
+ for (int i = 0; i < AV_DRM_MAX_PLANES; i++) {
+ if (framebuffer->gem_handles[i])
+ drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &framebuffer->gem_handles[i]);
+ }
+
+ memset(framebuffer, 0, sizeof(*framebuffer));
+}
diff --git a/video/out/drm_prime.h b/video/out/drm_prime.h
new file mode 100644
index 0000000000..0653fdbebf
--- /dev/null
+++ b/video/out/drm_prime.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRM_PRIME_H
+#define DRM_PRIME_H
+
+#include <libavutil/hwcontext_drm.h>
+
+#include "common/msg.h"
+
+struct drm_prime_framebuffer {
+ uint32_t fb_id;
+ uint32_t gem_handles[AV_DRM_MAX_PLANES];
+};
+
+int drm_prime_create_framebuffer(struct mp_log *log, int fd, AVDRMFrameDescriptor *descriptor, int width, int height,
+ struct drm_prime_framebuffer *framebuffers);
+void drm_prime_destroy_framebuffer(struct mp_log *log, int fd, struct drm_prime_framebuffer *framebuffers);
+#endif // DRM_PRIME_H
diff --git a/video/out/gpu/hwdec.c b/video/out/gpu/hwdec.c
index 5fbc1aa4a9..9eefe3e287 100644
--- a/video/out/gpu/hwdec.c
+++ b/video/out/gpu/hwdec.c
@@ -36,6 +36,9 @@ extern const struct ra_hwdec_driver ra_hwdec_dxva2gldx;
extern const struct ra_hwdec_driver ra_hwdec_dxva2;
extern const struct ra_hwdec_driver ra_hwdec_cuda;
extern const struct ra_hwdec_driver ra_hwdec_rpi_overlay;
+#if HAVE_DRMPRIME && HAVE_DRM
+extern const struct ra_hwdec_driver ra_hwdec_drmprime_drm;
+#endif
static const struct ra_hwdec_driver *const mpgl_hwdec_drivers[] = {
#if HAVE_VAAPI_EGL
@@ -66,6 +69,10 @@ static const struct ra_hwdec_driver *const mpgl_hwdec_drivers[] = {
#if HAVE_RPI
&ra_hwdec_rpi_overlay,
#endif
+#if HAVE_DRMPRIME && HAVE_DRM
+ &ra_hwdec_drmprime_drm,
+#endif
+
NULL
};
diff --git a/video/out/opengl/context_drm_egl.c b/video/out/opengl/context_drm_egl.c
index 071702bb08..c7de762e28 100644
--- a/video/out/opengl/context_drm_egl.c
+++ b/video/out/opengl/context_drm_egl.c
@@ -28,6 +28,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include "libmpv/opengl_cb.h"
#include "video/out/drm_common.h"
#include "common/common.h"
@@ -75,6 +76,8 @@ struct priv {
bool vt_switcher_active;
struct vt_switcher vt_switcher;
+
+ struct mpv_opengl_cb_drm_params drm_params;
};
static bool init_egl(struct ra_ctx *ctx)
@@ -161,13 +164,6 @@ static void update_framebuffer_from_bo(struct ra_ctx *ctx, struct gbm_bo *bo)
p->fb = fb;
}
-static void page_flipped(int fd, unsigned int frame, unsigned int sec,
- unsigned int usec, void *data)
-{
- struct priv *p = data;
- p->waiting_for_flip = false;
-}
-
static bool crtc_setup(struct ra_ctx *ctx)
{
struct priv *p = ctx->priv;
@@ -241,17 +237,47 @@ static void acquire_vt(void *data)
crtc_setup(ctx);
}
+static bool drm_atomic_egl_start_frame(struct ra_swapchain *sw, struct ra_fbo *out_fbo)
+{
+ struct priv *p = sw->ctx->priv;
+ if (p->kms->atomic_context) {
+ p->kms->atomic_context->request = drmModeAtomicAlloc();
+ p->drm_params.atomic_request = p->kms->atomic_context->request;
+ return ra_gl_ctx_start_frame(sw, out_fbo);
+ }
+ return false;
+}
+
+static const struct ra_swapchain_fns drm_atomic_swapchain = {
+ .start_frame = drm_atomic_egl_start_frame,
+};
+
static void drm_egl_swap_buffers(struct ra_ctx *ctx)
{
struct priv *p = ctx->priv;
+ struct drm_atomic_context *atomic_ctx = p->kms->atomic_context;
+ int ret;
+
eglSwapBuffers(p->egl.display, p->egl.surface);
p->gbm.next_bo = gbm_surface_lock_front_buffer(p->gbm.surface);
p->waiting_for_flip = true;
update_framebuffer_from_bo(ctx, p->gbm.next_bo);
- int ret = drmModePageFlip(p->kms->fd, p->kms->crtc_id, p->fb->id,
- DRM_MODE_PAGE_FLIP_EVENT, p);
- if (ret) {
- MP_WARN(ctx->vo, "Failed to queue page flip: %s\n", mp_strerror(errno));
+
+ if (atomic_ctx) {
+ drm_object_set_property(atomic_ctx->request, atomic_ctx->primary_plane, "FB_ID", p->fb->id);
+ drm_object_set_property(atomic_ctx->request, atomic_ctx->primary_plane, "CRTC_ID", atomic_ctx->crtc->id);
+ drm_object_set_property(atomic_ctx->request, atomic_ctx->primary_plane, "ZPOS", 1);
+
+ ret = drmModeAtomicCommit(p->kms->fd, atomic_ctx->request,
+ DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, NULL);
+ if (ret)
+ MP_WARN(ctx->vo, "Failed to commit atomic request (%d)\n", ret);
+ } else {
+ ret = drmModePageFlip(p->kms->fd, p->kms->crtc_id, p->fb->id,
+ DRM_MODE_PAGE_FLIP_EVENT, p);
+ if (ret) {
+ MP_WARN(ctx->vo, "Failed to queue page flip: %s\n", mp_strerror(errno));
+ }
}
// poll page flip finish event
@@ -262,9 +288,16 @@ static void drm_egl_swap_buffers(struct ra_ctx *ctx)
ret = drmHandleEvent(p->kms->fd, &p->ev);
if (ret != 0) {
MP_ERR(ctx->vo, "drmHandleEvent failed: %i\n", ret);
+ p->waiting_for_flip = false;
return;
}
}
+ p->waiting_for_flip = false;
+
+ if (atomic_ctx) {
+ drmModeAtomicFree(atomic_ctx->request);
+ p->drm_params.atomic_request = atomic_ctx->request = NULL;
+ }
gbm_surface_release_buffer(p->gbm.surface, p->gbm.bo);
p->gbm.bo = p->gbm.next_bo;
@@ -304,7 +337,6 @@ static bool drm_egl_init(struct ra_ctx *ctx)
struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);
p->ev.version = DRM_EVENT_CONTEXT_VERSION;
- p->ev.page_flip_handler = page_flipped;
p->vt_switcher_active = vt_switcher_init(&p->vt_switcher, ctx->vo->log);
if (p->vt_switcher_active) {
@@ -316,9 +348,9 @@ static bool drm_egl_init(struct ra_ctx *ctx)
MP_VERBOSE(ctx, "Initializing KMS\n");
p->kms = kms_create(ctx->log, ctx->vo->opts->drm_connector_spec,
- ctx->vo->opts->drm_mode_id);
+ ctx->vo->opts->drm_mode_id, ctx->vo->op