1From 379ba7eeda0a213093100e910e73eef86444356a Mon Sep 17 00:00:00 2001
2From: Jeffy Chen <jeffy.chen@rock-chips.com>
3Date: Tue, 16 Jun 2020 17:14:54 +0800
4Subject: [PATCH 4/4] vo_opengl: x11egl: Support drm hwdec
5
6Tested with:
7mpv --hwdec=rkmpp --vo=opengl test.mp4
8
9Change-Id: Ic49e2acaa288496180037d2ca648eb824d4a663c
10Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
11---
12 libmpv/render_gl.h                    |   3 +
13 video/out/opengl/context_x11egl.c     | 145 ++++++++++++++++++++++++++
14 video/out/opengl/hwdec_drmprime_drm.c |  11 +-
15 3 files changed, 156 insertions(+), 3 deletions(-)
16
17diff --git a/libmpv/render_gl.h b/libmpv/render_gl.h
18index 4d771f2958..da3bbccfc4 100644
19--- a/libmpv/render_gl.h
20+++ b/libmpv/render_gl.h
21@@ -175,6 +175,9 @@ typedef struct mpv_opengl_drm_params {
22      * Set to a negative number if invalid.
23      */
24     int render_fd;
25+
26+    int x;
27+    int y;
28 } mpv_opengl_drm_params;
29
30 typedef struct mpv_opengl_drm_osd_size {
31diff --git a/video/out/opengl/context_x11egl.c b/video/out/opengl/context_x11egl.c
32index 32530cc11d..5ced169cd2 100644
33--- a/video/out/opengl/context_x11egl.c
34+++ b/video/out/opengl/context_x11egl.c
35@@ -31,16 +31,45 @@
36 #include "context.h"
37 #include "egl_helpers.h"
38
39+#if HAVE_DRM
40+#include <errno.h>
41+#include <fcntl.h>
42+#include <unistd.h>
43+
44+#include "libmpv/render_gl.h"
45+#include "video/out/drm_common.h"
46+#endif
47+
48 struct priv {
49     GL gl;
50     EGLDisplay egl_display;
51     EGLContext egl_context;
52     EGLSurface egl_surface;
53+
54+#if HAVE_DRM
55+    struct kms *kms;
56+    struct mpv_opengl_drm_params drm_params;
57+
58+    int x;
59+    int y;
60+#endif
61 };
62
63 static void mpegl_uninit(struct ra_ctx *ctx)
64 {
65     struct priv *p = ctx->priv;
66+
67+#if HAVE_DRM
68+    struct drm_atomic_context *atomic_ctx = p->kms->atomic_context;
69+
70+    if (atomic_ctx) {
71+        int ret = drmModeAtomicCommit(p->kms->fd, atomic_ctx->request, 0, NULL);
72+        if (ret)
73+            MP_ERR(ctx->vo, "Failed to commit atomic request (%d)\n", ret);
74+        drmModeAtomicFree(atomic_ctx->request);
75+    }
76+#endif
77+
78     ra_gl_ctx_uninit(ctx);
79
80     if (p->egl_context) {
81@@ -49,7 +78,20 @@ static void mpegl_uninit(struct ra_ctx *ctx)
82         eglDestroyContext(p->egl_display, p->egl_context);
83     }
84     p->egl_context = EGL_NO_CONTEXT;
85+    if (p->egl_display != EGL_NO_DISPLAY)
86+        eglTerminate(p->egl_display);
87+    p->egl_display = EGL_NO_DISPLAY;
88+
89     vo_x11_uninit(ctx->vo);
90+
91+#if HAVE_DRM
92+    close(p->drm_params.render_fd);
93+
94+    if (p->kms) {
95+        kms_destroy(p->kms);
96+        p->kms = 0;
97+    }
98+#endif
99 }
100
101 static int pick_xrgba_config(void *user_data, EGLConfig *configs, int num_configs)
102@@ -75,9 +117,65 @@ static int pick_xrgba_config(void *user_data, EGLConfig *configs, int num_config
103     return 0;
104 }
105
106+#if HAVE_DRM
107+static bool mpegl_update_position(struct ra_ctx *ctx)
108+{
109+    struct priv *p = ctx->priv;
110+    struct vo_x11_state *x11 = ctx->vo->x11;
111+    int x = 0, y = 0;
112+    bool moved = false;
113+    Window dummy_win;
114+    Window win = x11->parent ? x11->parent : x11->window;
115+
116+    if (win)
117+        XTranslateCoordinates(x11->display, win, x11->rootwin, 0, 0,
118+                              &x, &y, &dummy_win);
119+
120+    moved = p->x != x || p->y != y;
121+    p->drm_params.x = p->x = x;
122+    p->drm_params.y = p->y = y;
123+
124+    return moved;
125+}
126+
127+static bool drm_atomic_egl_start_frame(struct ra_swapchain *sw, struct ra_fbo *out_fbo)
128+{
129+    struct priv *p = sw->ctx->priv;
130+
131+    mpegl_update_position(sw->ctx);
132+
133+    if (p->kms->atomic_context) {
134+        if (!p->kms->atomic_context->request) {
135+            p->kms->atomic_context->request = drmModeAtomicAlloc();
136+            p->drm_params.atomic_request_ptr = &p->kms->atomic_context->request;
137+        }
138+        return ra_gl_ctx_start_frame(sw, out_fbo);
139+    }
140+    return false;
141+}
142+
143+static const struct ra_swapchain_fns drm_atomic_swapchain = {
144+    .start_frame   = drm_atomic_egl_start_frame,
145+};
146+#endif
147+
148 static void mpegl_swap_buffers(struct ra_ctx *ctx)
149 {
150     struct priv *p = ctx->priv;
151+#if HAVE_DRM
152+    struct drm_atomic_context *atomic_ctx = p->kms->atomic_context;
153+    int ret;
154+
155+    if (atomic_ctx) {
156+        ret = drmModeAtomicCommit(p->kms->fd, atomic_ctx->request, 0, NULL);
157+        if (ret)
158+            MP_WARN(ctx->vo, "Failed to commit atomic request (%d)\n", ret);
159+
160+        drmModeAtomicFree(atomic_ctx->request);
161+        atomic_ctx->request = drmModeAtomicAlloc();
162+    }
163+#endif
164+
165     eglSwapBuffers(p->egl_display, p->egl_surface);
166 }
167
168@@ -140,15 +238,56 @@ static bool mpegl_init(struct ra_ctx *ctx)
169
170     mpegl_load_functions(&p->gl, ctx->log);
171
172+#if HAVE_DRM
173+    MP_VERBOSE(ctx, "Initializing KMS\n");
174+    p->kms = kms_create(ctx->log, ctx->vo->opts->drm_opts->drm_connector_spec,
175+                        ctx->vo->opts->drm_opts->drm_mode_id,
176+                        ctx->vo->opts->drm_opts->drm_osd_plane_id,
177+                        ctx->vo->opts->drm_opts->drm_video_plane_id);
178+    if (!p->kms) {
179+        MP_ERR(ctx, "Failed to create KMS.\n");
180+        return false;
181+    }
182+
183+    p->drm_params.fd = p->kms->fd;
184+    p->drm_params.crtc_id = p->kms->crtc_id;
185+    p->drm_params.connector_id = p->kms->connector->connector_id;
186+    if (p->kms->atomic_context)
187+        p->drm_params.atomic_request_ptr = &p->kms->atomic_context->request;
188+    char *rendernode_path = drmGetRenderDeviceNameFromFd(p->kms->fd);
189+    if (rendernode_path) {
190+        MP_VERBOSE(ctx, "Opening render node \"%s\"\n", rendernode_path);
191+        p->drm_params.render_fd = open(rendernode_path, O_RDWR | O_CLOEXEC);
192+        if (p->drm_params.render_fd < 0) {
193+            MP_WARN(ctx, "Cannot open render node \"%s\": %s. VAAPI hwdec will be disabled\n",
194+                    rendernode_path, mp_strerror(errno));
195+        }
196+        free(rendernode_path);
197+    } else {
198+        p->drm_params.render_fd = -1;
199+        MP_VERBOSE(ctx, "Could not find path to render node. VAAPI hwdec will be disabled\n");
200+    }
201+
202+    struct ra_gl_ctx_params params = {
203+        .swap_buffers = mpegl_swap_buffers,
204+        .external_swapchain = p->kms->atomic_context ? &drm_atomic_swapchain :
205+                                                       NULL,
206+    };
207+#else
208     struct ra_gl_ctx_params params = {
209         .swap_buffers = mpegl_swap_buffers,
210     };
211+#endif
212
213     if (!ra_gl_ctx_init(ctx, &p->gl, params))
214         goto uninit;
215
216     ra_add_native_resource(ctx->ra, "x11", vo->x11->display);
217
218+#if HAVE_DRM
219+    ra_add_native_resource(ctx->ra, "drm_params", &p->drm_params);
220+#endif
221+
222     return true;
223
224 uninit:
225@@ -174,6 +313,12 @@ static int mpegl_control(struct ra_ctx *ctx, int *events, int request,
226     int ret = vo_x11_control(ctx->vo, events, request, arg);
227     if (*events & VO_EVENT_RESIZE)
228         resize(ctx);
229+
230+#if HAVE_DRM
231+    if (mpegl_update_position(ctx))
232+        ctx->vo->want_redraw = true;
233+#endif
234+
235     return ret;
236 }
237
238diff --git a/video/out/opengl/hwdec_drmprime_drm.c b/video/out/opengl/hwdec_drmprime_drm.c
239index d4543b0f47..2b34f7781c 100644
240--- a/video/out/opengl/hwdec_drmprime_drm.c
241+++ b/video/out/opengl/hwdec_drmprime_drm.c
242@@ -139,6 +139,8 @@ static int overlay_frame(struct ra_hwdec *hw, struct mp_image *hw_image,
243     AVDRMFrameDescriptor *desc = NULL;
244     drmModeAtomicReq *request = NULL;
245     struct drm_frame next_frame = {0};
246+    int dx = dst ? dst->x0 : 0;
247+    int dy = dst ? dst->y0 : 0;
248     int ret;
249
250     // grab atomic request from native resources
251@@ -155,6 +157,9 @@ static int overlay_frame(struct ra_hwdec *hw, struct mp_image *hw_image,
252             MP_ERR(hw, "drm params pointer to atomic request is invalid");
253             return -1;
254         }
255+
256+        dx += drm_params->x;
257+        dy += drm_params->y;
258     }
259
260     if (hw_image) {
261@@ -190,14 +195,14 @@ static int overlay_frame(struct ra_hwdec *hw, struct mp_image *hw_image,
262                 drm_object_set_property(request,  p->ctx->video_plane, "SRC_Y",   p->src.y0 << 16);
263                 drm_object_set_property(request,  p->ctx->video_plane, "SRC_W",   srcw << 16);
264                 drm_object_set_property(request,  p->ctx->video_plane, "SRC_H",   srch << 16);
265-                drm_object_set_property(request,  p->ctx->video_plane, "CRTC_X",  MP_ALIGN_DOWN(p->dst.x0, 2));
266-                drm_object_set_property(request,  p->ctx->video_plane, "CRTC_Y",  MP_ALIGN_DOWN(p->dst.y0, 2));
267+                drm_object_set_property(request,  p->ctx->video_plane, "CRTC_X",  MP_ALIGN_DOWN(dx, 2));
268+                drm_object_set_property(request,  p->ctx->video_plane, "CRTC_Y",  MP_ALIGN_DOWN(dy, 2));
269                 drm_object_set_property(request,  p->ctx->video_plane, "CRTC_W",  dstw);
270                 drm_object_set_property(request,  p->ctx->video_plane, "CRTC_H",  dsth);
271                 drm_object_set_property(request,  p->ctx->video_plane, "ZPOS",    0);
272             } else {
273                 ret = drmModeSetPlane(p->ctx->fd, p->ctx->video_plane->id, p->ctx->crtc->id, next_frame.fb.fb_id, 0,
274-                                      MP_ALIGN_DOWN(p->dst.x0, 2), MP_ALIGN_DOWN(p->dst.y0, 2), dstw, dsth,
275+                                      MP_ALIGN_DOWN(dx, 2), MP_ALIGN_DOWN(dy, 2), dstw, dsth,
276                                       p->src.x0 << 16, p->src.y0 << 16 , srcw << 16, srch << 16);
277                 if (ret < 0) {
278                     MP_ERR(hw, "Failed to set the plane %d (buffer %d).\n", p->ctx->video_plane->id,
279--
2802.17.1
281
282