1
0
mirror of https://github.com/mpv-player/mpv synced 2025-01-10 08:59:45 +00:00
mpv/video/out/opengl/x11egl.c
wm4 7c5f41ff5f x11: separate window creation and configuration
This gets rid of an old hack, VOFLAG_HIDDEN. Although handling of it has
been sane for a while, it used to cause much pain, and is still
unintuitive and weird even today.

The main reason for this hack is that OpenGL selects a X11 Visual for
you, and you're supposed to use this Visual when creating the X window
for the OpenGL context. Which means the X window can't be created early
in the common X11 init code, but the OpenGL code needs to do something
before that. API-wise you need separate functions for X11 init and X11
window creation. The VOFLAG_HIDDEN hack conflated window creation and
the entrypoint for resizing on video resolution change into one
function, vo_x11_config_vo_window(). This required all platform backends
to handle this flag, even if they didn't need this mechanism.

Wayland still uses this for minor reasons (alpha support?), so the
wayland backend must be changed before the flag can be entirely removed.
2015-09-30 23:31:34 +02:00

197 lines
5.4 KiB
C

/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*
* You can alternatively redistribute this file 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.
*/
#include <assert.h>
#include <X11/Xlib.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "common/common.h"
#include "video/out/x11_common.h"
#include "common.h"
struct priv {
EGLDisplay egl_display;
EGLContext egl_context;
EGLSurface egl_surface;
};
static void mpegl_uninit(MPGLContext *ctx)
{
struct priv *p = ctx->priv;
if (p->egl_context) {
eglMakeCurrent(p->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
eglDestroyContext(p->egl_display, p->egl_context);
}
p->egl_context = EGL_NO_CONTEXT;
vo_x11_uninit(ctx->vo);
}
static EGLConfig select_fb_config_egl(struct MPGLContext *ctx, bool es)
{
struct priv *p = ctx->priv;
EGLint attributes[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 0,
EGL_RENDERABLE_TYPE, es ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT,
EGL_NONE
};
EGLint config_count;
EGLConfig config;
eglChooseConfig(p->egl_display, attributes, &config, 1, &config_count);
if (!config_count) {
MP_FATAL(ctx->vo, "Could find EGL configuration!\n");
return NULL;
}
return config;
}
static bool create_context_egl(MPGLContext *ctx, EGLConfig config,
EGLNativeWindowType window, bool es)
{
struct priv *p = ctx->priv;
EGLint context_attributes[] = {
// aka EGL_CONTEXT_MAJOR_VERSION_KHR
EGL_CONTEXT_CLIENT_VERSION, es ? 2 : 3,
EGL_NONE
};
p->egl_surface = eglCreateWindowSurface(p->egl_display, config, window, NULL);
if (p->egl_surface == EGL_NO_SURFACE) {
MP_FATAL(ctx->vo, "Could not create EGL surface!\n");
return false;
}
p->egl_context = eglCreateContext(p->egl_display, config,
EGL_NO_CONTEXT, context_attributes);
if (p->egl_context == EGL_NO_CONTEXT) {
MP_FATAL(ctx->vo, "Could not create EGL context!\n");
return false;
}
eglMakeCurrent(p->egl_display, p->egl_surface, p->egl_surface,
p->egl_context);
return true;
}
static int mpegl_init(struct MPGLContext *ctx, int flags)
{
struct priv *p = ctx->priv;
struct vo *vo = ctx->vo;
bool es = flags & VOFLAG_GLES;
int msgl = vo->probing ? MSGL_V : MSGL_FATAL;
if (!vo_x11_init(vo))
goto uninit;
if (!eglBindAPI(es ? EGL_OPENGL_ES_API : EGL_OPENGL_API)) {
mp_msg(vo->log, msgl, "Could not bind API (%s).\n", es ? "GLES" : "GL");
goto uninit;
}
p->egl_display = eglGetDisplay(vo->x11->display);
if (!eglInitialize(p->egl_display, NULL, NULL)) {
mp_msg(vo->log, msgl, "Could not initialize EGL.\n");
goto uninit;
}
EGLConfig config = select_fb_config_egl(ctx, es);
if (!config)
goto uninit;
int vID, n;
eglGetConfigAttrib(p->egl_display, config, EGL_NATIVE_VISUAL_ID, &vID);
XVisualInfo template = {.visualid = vID};
XVisualInfo *vi = XGetVisualInfo(vo->x11->display, VisualIDMask, &template, &n);
if (!vi) {
MP_FATAL(vo, "Getting X visual failed!\n");
goto uninit;
}
if (!vo_x11_create_vo_window(vo, vi, "gl")) {
XFree(vi);
goto uninit;
}
XFree(vi);
if (!create_context_egl(ctx, config, (EGLNativeWindowType)vo->x11->window, es))
goto uninit;
const char *egl_exts = eglQueryString(p->egl_display, EGL_EXTENSIONS);
void *(*gpa)(const GLubyte*) = (void *(*)(const GLubyte*))eglGetProcAddress;
mpgl_load_functions(ctx->gl, gpa, egl_exts, vo->log);
ctx->native_display_type = "x11";
ctx->native_display = vo->x11->display;
return true;
uninit:
mpegl_uninit(ctx);
return false;
}
static int mpegl_reconfig(struct MPGLContext *ctx, int flags)
{
vo_x11_config_vo_window(ctx->vo);
return 0;
}
static int mpegl_control(struct MPGLContext *ctx, int *events, int request,
void *arg)
{
return vo_x11_control(ctx->vo, events, request, arg);
}
static void mpegl_swap_buffers(MPGLContext *ctx)
{
struct priv *p = ctx->priv;
eglSwapBuffers(p->egl_display, p->egl_surface);
}
const struct mpgl_driver mpgl_driver_x11egl = {
.name = "x11egl",
.priv_size = sizeof(struct priv),
.init = mpegl_init,
.reconfig = mpegl_reconfig,
.swap_buffers = mpegl_swap_buffers,
.control = mpegl_control,
.uninit = mpegl_uninit,
};