From 379ba7eeda0a213093100e910e73eef86444356a Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Tue, 16 Jun 2020 17:14:54 +0800 Subject: [PATCH 4/4] vo_opengl: x11egl: Support drm hwdec Tested with: mpv --hwdec=rkmpp --vo=opengl test.mp4 Change-Id: Ic49e2acaa288496180037d2ca648eb824d4a663c Signed-off-by: Jeffy Chen --- libmpv/render_gl.h | 3 + video/out/opengl/context_x11egl.c | 145 ++++++++++++++++++++++++++ video/out/opengl/hwdec_drmprime_drm.c | 11 +- 3 files changed, 156 insertions(+), 3 deletions(-) diff --git a/libmpv/render_gl.h b/libmpv/render_gl.h index 4d771f2958..da3bbccfc4 100644 --- a/libmpv/render_gl.h +++ b/libmpv/render_gl.h @@ -175,6 +175,9 @@ typedef struct mpv_opengl_drm_params { * Set to a negative number if invalid. */ int render_fd; + + int x; + int y; } mpv_opengl_drm_params; typedef struct mpv_opengl_drm_osd_size { diff --git a/video/out/opengl/context_x11egl.c b/video/out/opengl/context_x11egl.c index 32530cc11d..5ced169cd2 100644 --- a/video/out/opengl/context_x11egl.c +++ b/video/out/opengl/context_x11egl.c @@ -31,16 +31,45 @@ #include "context.h" #include "egl_helpers.h" +#if HAVE_DRM +#include +#include +#include + +#include "libmpv/render_gl.h" +#include "video/out/drm_common.h" +#endif + struct priv { GL gl; EGLDisplay egl_display; EGLContext egl_context; EGLSurface egl_surface; + +#if HAVE_DRM + struct kms *kms; + struct mpv_opengl_drm_params drm_params; + + int x; + int y; +#endif }; static void mpegl_uninit(struct ra_ctx *ctx) { struct priv *p = ctx->priv; + +#if HAVE_DRM + struct drm_atomic_context *atomic_ctx = p->kms->atomic_context; + + if (atomic_ctx) { + int ret = drmModeAtomicCommit(p->kms->fd, atomic_ctx->request, 0, NULL); + if (ret) + MP_ERR(ctx->vo, "Failed to commit atomic request (%d)\n", ret); + drmModeAtomicFree(atomic_ctx->request); + } +#endif + ra_gl_ctx_uninit(ctx); if (p->egl_context) { @@ -49,7 +78,20 @@ static void mpegl_uninit(struct ra_ctx *ctx) eglDestroyContext(p->egl_display, p->egl_context); } p->egl_context = EGL_NO_CONTEXT; + if (p->egl_display != EGL_NO_DISPLAY) + eglTerminate(p->egl_display); + p->egl_display = EGL_NO_DISPLAY; + vo_x11_uninit(ctx->vo); + +#if HAVE_DRM + close(p->drm_params.render_fd); + + if (p->kms) { + kms_destroy(p->kms); + p->kms = 0; + } +#endif } static int pick_xrgba_config(void *user_data, EGLConfig *configs, int num_configs) @@ -75,9 +117,65 @@ static int pick_xrgba_config(void *user_data, EGLConfig *configs, int num_config return 0; } +#if HAVE_DRM +static bool mpegl_update_position(struct ra_ctx *ctx) +{ + struct priv *p = ctx->priv; + struct vo_x11_state *x11 = ctx->vo->x11; + int x = 0, y = 0; + bool moved = false; + Window dummy_win; + Window win = x11->parent ? x11->parent : x11->window; + + if (win) + XTranslateCoordinates(x11->display, win, x11->rootwin, 0, 0, + &x, &y, &dummy_win); + + moved = p->x != x || p->y != y; + p->drm_params.x = p->x = x; + p->drm_params.y = p->y = y; + + return moved; +} + +static bool drm_atomic_egl_start_frame(struct ra_swapchain *sw, struct ra_fbo *out_fbo) +{ + struct priv *p = sw->ctx->priv; + + mpegl_update_position(sw->ctx); + + if (p->kms->atomic_context) { + if (!p->kms->atomic_context->request) { + p->kms->atomic_context->request = drmModeAtomicAlloc(); + p->drm_params.atomic_request_ptr = &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, +}; +#endif + static void mpegl_swap_buffers(struct ra_ctx *ctx) { struct priv *p = ctx->priv; +#if HAVE_DRM + struct drm_atomic_context *atomic_ctx = p->kms->atomic_context; + int ret; + + if (atomic_ctx) { + ret = drmModeAtomicCommit(p->kms->fd, atomic_ctx->request, 0, NULL); + if (ret) + MP_WARN(ctx->vo, "Failed to commit atomic request (%d)\n", ret); + + drmModeAtomicFree(atomic_ctx->request); + atomic_ctx->request = drmModeAtomicAlloc(); + } +#endif + eglSwapBuffers(p->egl_display, p->egl_surface); } @@ -140,15 +238,56 @@ static bool mpegl_init(struct ra_ctx *ctx) mpegl_load_functions(&p->gl, ctx->log); +#if HAVE_DRM + MP_VERBOSE(ctx, "Initializing KMS\n"); + p->kms = kms_create(ctx->log, ctx->vo->opts->drm_opts->drm_connector_spec, + ctx->vo->opts->drm_opts->drm_mode_id, + ctx->vo->opts->drm_opts->drm_osd_plane_id, + ctx->vo->opts->drm_opts->drm_video_plane_id); + if (!p->kms) { + MP_ERR(ctx, "Failed to create KMS.\n"); + return false; + } + + p->drm_params.fd = p->kms->fd; + p->drm_params.crtc_id = p->kms->crtc_id; + p->drm_params.connector_id = p->kms->connector->connector_id; + if (p->kms->atomic_context) + p->drm_params.atomic_request_ptr = &p->kms->atomic_context->request; + char *rendernode_path = drmGetRenderDeviceNameFromFd(p->kms->fd); + if (rendernode_path) { + MP_VERBOSE(ctx, "Opening render node \"%s\"\n", rendernode_path); + p->drm_params.render_fd = open(rendernode_path, O_RDWR | O_CLOEXEC); + if (p->drm_params.render_fd < 0) { + MP_WARN(ctx, "Cannot open render node \"%s\": %s. VAAPI hwdec will be disabled\n", + rendernode_path, mp_strerror(errno)); + } + free(rendernode_path); + } else { + p->drm_params.render_fd = -1; + MP_VERBOSE(ctx, "Could not find path to render node. VAAPI hwdec will be disabled\n"); + } + + struct ra_gl_ctx_params params = { + .swap_buffers = mpegl_swap_buffers, + .external_swapchain = p->kms->atomic_context ? &drm_atomic_swapchain : + NULL, + }; +#else struct ra_gl_ctx_params params = { .swap_buffers = mpegl_swap_buffers, }; +#endif if (!ra_gl_ctx_init(ctx, &p->gl, params)) goto uninit; ra_add_native_resource(ctx->ra, "x11", vo->x11->display); +#if HAVE_DRM + ra_add_native_resource(ctx->ra, "drm_params", &p->drm_params); +#endif + return true; uninit: @@ -174,6 +313,12 @@ static int mpegl_control(struct ra_ctx *ctx, int *events, int request, int ret = vo_x11_control(ctx->vo, events, request, arg); if (*events & VO_EVENT_RESIZE) resize(ctx); + +#if HAVE_DRM + if (mpegl_update_position(ctx)) + ctx->vo->want_redraw = true; +#endif + return ret; } diff --git a/video/out/opengl/hwdec_drmprime_drm.c b/video/out/opengl/hwdec_drmprime_drm.c index d4543b0f47..2b34f7781c 100644 --- a/video/out/opengl/hwdec_drmprime_drm.c +++ b/video/out/opengl/hwdec_drmprime_drm.c @@ -139,6 +139,8 @@ static int overlay_frame(struct ra_hwdec *hw, struct mp_image *hw_image, AVDRMFrameDescriptor *desc = NULL; drmModeAtomicReq *request = NULL; struct drm_frame next_frame = {0}; + int dx = dst ? dst->x0 : 0; + int dy = dst ? dst->y0 : 0; int ret; // grab atomic request from native resources @@ -155,6 +157,9 @@ static int overlay_frame(struct ra_hwdec *hw, struct mp_image *hw_image, MP_ERR(hw, "drm params pointer to atomic request is invalid"); return -1; } + + dx += drm_params->x; + dy += drm_params->y; } if (hw_image) { @@ -190,14 +195,14 @@ static int overlay_frame(struct ra_hwdec *hw, struct mp_image *hw_image, drm_object_set_property(request, p->ctx->video_plane, "SRC_Y", p->src.y0 << 16); drm_object_set_property(request, p->ctx->video_plane, "SRC_W", srcw << 16); drm_object_set_property(request, p->ctx->video_plane, "SRC_H", srch << 16); - drm_object_set_property(request, p->ctx->video_plane, "CRTC_X", MP_ALIGN_DOWN(p->dst.x0, 2)); - drm_object_set_property(request, p->ctx->video_plane, "CRTC_Y", MP_ALIGN_DOWN(p->dst.y0, 2)); + drm_object_set_property(request, p->ctx->video_plane, "CRTC_X", MP_ALIGN_DOWN(dx, 2)); + drm_object_set_property(request, p->ctx->video_plane, "CRTC_Y", MP_ALIGN_DOWN(dy, 2)); drm_object_set_property(request, p->ctx->video_plane, "CRTC_W", dstw); drm_object_set_property(request, p->ctx->video_plane, "CRTC_H", dsth); drm_object_set_property(request, p->ctx->video_plane, "ZPOS", 0); } else { ret = drmModeSetPlane(p->ctx->fd, p->ctx->video_plane->id, p->ctx->crtc->id, next_frame.fb.fb_id, 0, - MP_ALIGN_DOWN(p->dst.x0, 2), MP_ALIGN_DOWN(p->dst.y0, 2), dstw, dsth, + MP_ALIGN_DOWN(dx, 2), MP_ALIGN_DOWN(dy, 2), dstw, dsth, p->src.x0 << 16, p->src.y0 << 16 , srcw << 16, srch << 16); if (ret < 0) { MP_ERR(hw, "Failed to set the plane %d (buffer %d).\n", p->ctx->video_plane->id, -- 2.17.1