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