From 65979986a923a8f08019b257c3fe72cd5e8ecf68 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Thu, 14 Sep 2017 08:04:55 +0200 Subject: vo_opengl: refactor into vo_gpu This is done in several steps: 1. refactor MPGLContext -> struct ra_ctx 2. move GL-specific stuff in vo_opengl into opengl/context.c 3. generalize context creation to support other APIs, and add --gpu-api 4. rename all of the --opengl- options that are no longer opengl-specific 5. move all of the stuff from opengl/* that isn't GL-specific into gpu/ (note: opengl/gl_utils.h became opengl/utils.h) 6. rename vo_opengl to vo_gpu 7. to handle window screenshots, the short-term approach was to just add it to ra_swchain_fns. Long term (and for vulkan) this has to be moved to ra itself (and vo_gpu altered to compensate), but this was a stop-gap measure to prevent this commit from getting too big 8. move ra->fns->flush to ra_gl_ctx instead 9. some other minor changes that I've probably already forgotten Note: This is one half of a major refactor, the other half of which is provided by rossy's following commit. This commit enables support for all linux platforms, while his version enables support for all non-linux platforms. Note 2: vo_opengl_cb.c also re-uses ra_gl_ctx so it benefits from the --opengl- options like --opengl-early-flush, --opengl-finish etc. Should be a strict superset of the old functionality. Disclaimer: Since I have no way of compiling mpv on all platforms, some of these ports were done blindly. Specifically, the blind ports included context_mali_fbdev.c and context_rpi.c. Since they're both based on egl_helpers, the port should have gone smoothly without any major changes required. But if somebody complains about a compile error on those platforms (assuming anybody actually uses them), you know where to complain. --- video/out/opengl/context_drm_egl.c | 194 +++++++++++++++++-------------------- 1 file changed, 89 insertions(+), 105 deletions(-) (limited to 'video/out/opengl/context_drm_egl.c') diff --git a/video/out/opengl/context_drm_egl.c b/video/out/opengl/context_drm_egl.c index e52fec451b..21b16a52d5 100644 --- a/video/out/opengl/context_drm_egl.c +++ b/video/out/opengl/context_drm_egl.c @@ -28,10 +28,12 @@ #include #include -#include "context.h" -#include "egl_helpers.h" -#include "common/common.h" #include "video/out/drm_common.h" +#include "common/common.h" + +#include "egl_helpers.h" +#include "common.h" +#include "context.h" #define USE_MASTER 0 @@ -59,6 +61,7 @@ struct egl }; struct priv { + GL gl; struct kms *kms; drmEventContext ev; @@ -75,34 +78,33 @@ struct priv { struct vt_switcher vt_switcher; }; -static bool init_egl(struct MPGLContext *ctx, int flags) +static bool init_egl(struct ra_ctx *ctx) { struct priv *p = ctx->priv; - MP_VERBOSE(ctx->vo, "Initializing EGL\n"); + MP_VERBOSE(ctx, "Initializing EGL\n"); p->egl.display = eglGetDisplay(p->gbm.device); if (p->egl.display == EGL_NO_DISPLAY) { - MP_ERR(ctx->vo, "Failed to get EGL display.\n"); + MP_ERR(ctx, "Failed to get EGL display.\n"); return false; } if (!eglInitialize(p->egl.display, NULL, NULL)) { - MP_ERR(ctx->vo, "Failed to initialize EGL.\n"); + MP_ERR(ctx, "Failed to initialize EGL.\n"); return false; } EGLConfig config; - if (!mpegl_create_context(p->egl.display, ctx->vo->log, flags, - &p->egl.context, &config)) - return -1; - MP_VERBOSE(ctx->vo, "Initializing EGL surface\n"); + if (!mpegl_create_context(ctx, p->egl.display, &p->egl.context, &config)) + return false; + MP_VERBOSE(ctx, "Initializing EGL surface\n"); p->egl.surface = eglCreateWindowSurface(p->egl.display, config, p->gbm.surface, NULL); if (p->egl.surface == EGL_NO_SURFACE) { - MP_ERR(ctx->vo, "Failed to create EGL surface.\n"); + MP_ERR(ctx, "Failed to create EGL surface.\n"); return false; } return true; } -static bool init_gbm(struct MPGLContext *ctx) +static bool init_gbm(struct ra_ctx *ctx) { struct priv *p = ctx->priv; MP_VERBOSE(ctx->vo, "Creating GBM device\n"); @@ -136,7 +138,7 @@ static void framebuffer_destroy_callback(struct gbm_bo *bo, void *data) } static void update_framebuffer_from_bo( - const struct MPGLContext *ctx, struct gbm_bo *bo) + const struct ra_ctx *ctx, struct gbm_bo *bo) { struct priv *p = ctx->priv; p->fb.bo = bo; @@ -161,7 +163,7 @@ static void page_flipped(int fd, unsigned int frame, unsigned int sec, p->waiting_for_flip = false; } -static bool crtc_setup(struct MPGLContext *ctx) +static bool crtc_setup(struct ra_ctx *ctx) { struct priv *p = ctx->priv; if (p->active) @@ -174,7 +176,7 @@ static bool crtc_setup(struct MPGLContext *ctx) return ret == 0; } -static void crtc_release(struct MPGLContext *ctx) +static void crtc_release(struct ra_ctx *ctx) { struct priv *p = ctx->priv; @@ -204,7 +206,7 @@ static void crtc_release(struct MPGLContext *ctx) static void release_vt(void *data) { - struct MPGLContext *ctx = data; + struct ra_ctx *ctx = data; MP_VERBOSE(ctx->vo, "Releasing VT"); crtc_release(ctx); if (USE_MASTER) { @@ -221,7 +223,7 @@ static void release_vt(void *data) static void acquire_vt(void *data) { - struct MPGLContext *ctx = data; + struct ra_ctx *ctx = data; MP_VERBOSE(ctx->vo, "Acquiring VT"); if (USE_MASTER) { struct priv *p = ctx->priv; @@ -234,11 +236,41 @@ static void acquire_vt(void *data) crtc_setup(ctx); } -static void drm_egl_uninit(MPGLContext *ctx) +static void drm_egl_swap_buffers(struct ra_ctx *ctx) { struct priv *p = ctx->priv; - crtc_release(ctx); + 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)); + } + + // poll page flip finish event + const int timeout_ms = 3000; + struct pollfd fds[1] = { { .events = POLLIN, .fd = p->kms->fd } }; + poll(fds, 1, timeout_ms); + if (fds[0].revents & POLLIN) { + ret = drmHandleEvent(p->kms->fd, &p->ev); + if (ret != 0) { + MP_ERR(ctx->vo, "drmHandleEvent failed: %i\n", ret); + return; + } + } + + gbm_surface_release_buffer(p->gbm.surface, p->gbm.bo); + p->gbm.bo = p->gbm.next_bo; +} +static void drm_egl_uninit(struct ra_ctx *ctx) +{ + struct priv *p = ctx->priv; + ra_gl_ctx_uninit(ctx); + + crtc_release(ctx); if (p->vt_switcher_active) vt_switcher_destroy(&p->vt_switcher); @@ -258,19 +290,14 @@ static void drm_egl_uninit(MPGLContext *ctx) } } -static int drm_egl_init(struct MPGLContext *ctx, int flags) +static bool drm_egl_init(struct ra_ctx *ctx) { - if (ctx->vo->probing) { - MP_VERBOSE(ctx->vo, "DRM EGL backend can be activated only manually.\n"); - return -1; + if (ctx->opts.probing) { + MP_VERBOSE(ctx, "DRM EGL backend can be activated only manually.\n"); + return false; } - struct priv *p = ctx->priv; - p->kms = NULL; - p->old_crtc = NULL; - p->gbm.surface = NULL; - p->gbm.device = NULL; - p->active = false; - p->waiting_for_flip = false; + + struct priv *p = ctx->priv = talloc_zero(ctx, struct priv); p->ev.version = DRM_EVENT_CONTEXT_VERSION; p->ev.page_flip_handler = page_flipped; @@ -279,79 +306,76 @@ static int drm_egl_init(struct MPGLContext *ctx, int flags) vt_switcher_acquire(&p->vt_switcher, acquire_vt, ctx); vt_switcher_release(&p->vt_switcher, release_vt, ctx); } else { - MP_WARN(ctx->vo, "Failed to set up VT switcher. Terminal switching will be unavailable.\n"); + MP_WARN(ctx, "Failed to set up VT switcher. Terminal switching will be unavailable.\n"); } - MP_VERBOSE(ctx->vo, "Initializing KMS\n"); - p->kms = kms_create(ctx->vo->log, ctx->vo->opts->drm_connector_spec, + MP_VERBOSE(ctx, "Initializing KMS\n"); + p->kms = kms_create(ctx->log, ctx->vo->opts->drm_connector_spec, ctx->vo->opts->drm_mode_id); if (!p->kms) { MP_ERR(ctx->vo, "Failed to create KMS.\n"); - return -1; + return false; } if (!init_gbm(ctx)) { MP_ERR(ctx->vo, "Failed to setup GBM.\n"); - return -1; + return false; } - if (!init_egl(ctx, flags)) { + if (!init_egl(ctx)) { MP_ERR(ctx->vo, "Failed to setup EGL.\n"); - return -1; + return false; } if (!eglMakeCurrent(p->egl.display, p->egl.surface, p->egl.surface, p->egl.context)) { MP_ERR(ctx->vo, "Failed to make context current.\n"); - return -1; + return false; } - mpegl_load_functions(ctx->gl, ctx->vo->log); - - ctx->native_display_type = "drm"; - ctx->native_display = (void *)(intptr_t)p->kms->fd; - + mpegl_load_functions(&p->gl, ctx->vo->log); // required by gbm_surface_lock_front_buffer eglSwapBuffers(p->egl.display, p->egl.surface); - MP_VERBOSE(ctx->vo, "Preparing framebuffer\n"); + MP_VERBOSE(ctx, "Preparing framebuffer\n"); p->gbm.bo = gbm_surface_lock_front_buffer(p->gbm.surface); if (!p->gbm.bo) { - MP_ERR(ctx->vo, "Failed to lock GBM surface.\n"); - return -1; + MP_ERR(ctx, "Failed to lock GBM surface.\n"); + return false; } update_framebuffer_from_bo(ctx, p->gbm.bo); if (!p->fb.id) { - MP_ERR(ctx->vo, "Failed to create framebuffer.\n"); - return -1; + MP_ERR(ctx, "Failed to create framebuffer.\n"); + return false; } if (!crtc_setup(ctx)) { - MP_ERR(ctx->vo, "Failed to set CRTC for connector %u: %s\n", + MP_ERR(ctx, "Failed to set CRTC for connector %u: %s\n", p->kms->connector->connector_id, mp_strerror(errno)); - return -1; + return false; } - return 0; -} + struct ra_gl_ctx_params params = { + .swap_buffers = drm_egl_swap_buffers, + .native_display_type = "drm", + .native_display = (void *)(intptr_t)p->kms->fd, + }; + if (!ra_gl_ctx_init(ctx, &p->gl, params)) + return false; -static int drm_egl_init_deprecated(struct MPGLContext *ctx, int flags) -{ - if (ctx->vo->probing) - return -1; - MP_WARN(ctx->vo, "'drm-egl' is deprecated, use 'drm' instead.\n"); - return drm_egl_init(ctx, flags); + return true; } -static int drm_egl_reconfig(struct MPGLContext *ctx) +static bool drm_egl_reconfig(struct ra_ctx *ctx) { struct priv *p = ctx->priv; ctx->vo->dwidth = p->fb.width; ctx->vo->dheight = p->fb.height; - return 0; + ra_gl_ctx_resize(ctx->swapchain, p->fb.width, p->fb.height, 0); + return true; } -static int drm_egl_control(struct MPGLContext *ctx, int *events, int request, +static int drm_egl_control(struct ra_ctx *ctx, int *events, int request, void *arg) { struct priv *p = ctx->priv; @@ -367,51 +391,11 @@ static int drm_egl_control(struct MPGLContext *ctx, int *events, int request, return VO_NOTIMPL; } -static void drm_egl_swap_buffers(MPGLContext *ctx) -{ - struct priv *p = ctx->priv; - 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)); - } - - // poll page flip finish event - const int timeout_ms = 3000; - struct pollfd fds[1] = { { .events = POLLIN, .fd = p->kms->fd } }; - poll(fds, 1, timeout_ms); - if (fds[0].revents & POLLIN) { - ret = drmHandleEvent(p->kms->fd, &p->ev); - if (ret != 0) { - MP_ERR(ctx->vo, "drmHandleEvent failed: %i\n", ret); - return; - } - } - - gbm_surface_release_buffer(p->gbm.surface, p->gbm.bo); - p->gbm.bo = p->gbm.next_bo; -} - -const struct mpgl_driver mpgl_driver_drm = { +const struct ra_ctx_fns ra_ctx_drm_egl = { + .type = "opengl", .name = "drm", - .priv_size = sizeof(struct priv), - .init = drm_egl_init, .reconfig = drm_egl_reconfig, - .swap_buffers = drm_egl_swap_buffers, - .control = drm_egl_control, - .uninit = drm_egl_uninit, -}; - -const struct mpgl_driver mpgl_driver_drm_egl = { - .name = "drm-egl", - .priv_size = sizeof(struct priv), - .init = drm_egl_init_deprecated, - .reconfig = drm_egl_reconfig, - .swap_buffers = drm_egl_swap_buffers, .control = drm_egl_control, + .init = drm_egl_init, .uninit = drm_egl_uninit, }; -- cgit v1.2.3