diff options
Diffstat (limited to 'video/out')
35 files changed, 2306 insertions, 609 deletions
diff --git a/video/out/drm_common.c b/video/out/drm_common.c index 1ea0e45ae8..3462a5d4de 100644 --- a/video/out/drm_common.c +++ b/video/out/drm_common.c @@ -1,8 +1,6 @@ /* * This file is part of mpv. * - * by rr- <rr-@sakuya.pl> - * * 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 @@ -15,6 +13,11 @@ * * 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 <errno.h> @@ -35,16 +38,216 @@ #define EVT_INTERRUPT 255 #define HANDLER_ACQUIRE 0 #define HANDLER_RELEASE 1 +#define RELEASE_SIGNAL SIGUSR1 +#define ACQUIRE_SIGNAL SIGUSR2 static int vt_switcher_pipe[2]; +// KMS ------------------------------------------------------------------------ + +static bool is_connector_valid(struct kms *kms, int connector_id, + drmModeConnector *connector, bool silent) +{ + if (!connector) { + if (!silent) { + MP_ERR(kms, "Cannot get connector %d: %s\n", connector_id, + mp_strerror(errno)); + } + return false; + } + + if (connector->connection != DRM_MODE_CONNECTED) { + if (!silent) { + MP_ERR(kms, "Connector %d is disconnected\n", connector_id); + } + return false; + } + + if (connector->count_modes == 0) { + if (!silent) { + MP_ERR(kms, "Connector %d has no valid modes\n", connector_id); + } + return false; + } + + return true; +} + +static bool setup_connector( + struct kms *kms, const drmModeRes *res, int connector_id) +{ + drmModeConnector *connector = NULL; + if (connector_id == -1) { + // get the first connected connector + for (int i = 0; i < res->count_connectors; i++) { + connector = drmModeGetConnector(kms->fd, res->connectors[i]); + if (is_connector_valid(kms, i, connector, true)) { + connector_id = i; + break; + } + if (connector) { + drmModeFreeConnector(connector); + connector = NULL; + } + } + if (connector_id == -1) { + MP_ERR(kms, "No connected connectors found\n"); + return false; + } + } + + if (connector_id < 0 || connector_id >= res->count_connectors) { + MP_ERR(kms, "Bad connector ID. Max valid connector ID = %u\n", + res->count_connectors); + return false; + } + + connector = drmModeGetConnector(kms->fd, res->connectors[connector_id]); + if (!is_connector_valid(kms, connector_id, connector, false)) + return false; + + kms->connector = connector; + return true; +} + +static bool setup_crtc(struct kms *kms, const drmModeRes *res) +{ + for (unsigned int i = 0; i < kms->connector->count_encoders; ++i) { + drmModeEncoder *encoder + = drmModeGetEncoder(kms->fd, kms->connector->encoders[i]); + if (!encoder) { + MP_WARN(kms, "Cannot retrieve encoder %u:%u: %s\n", + i, kms->connector->encoders[i], mp_strerror(errno)); + continue; + } + + // iterate all global CRTCs + for (unsigned int j = 0; j < res->count_crtcs; ++j) { + // check whether this CRTC works with the encoder + if (!(encoder->possible_crtcs & (1 << j))) + continue; + + kms->encoder = encoder; + kms->crtc_id = encoder->crtc_id; + return true; + } + + drmModeFreeEncoder(encoder); + } + + MP_ERR(kms, + "Connector %u has no suitable CRTC\n", + kms->connector->connector_id); + return false; +} + +static bool setup_mode(struct kms *kms, int mode_id) +{ + if (mode_id < 0 || mode_id >= kms->connector->count_modes) { + MP_ERR( + kms, + "Bad mode ID (max = %d).\n", + kms->connector->count_modes - 1); + + MP_INFO(kms, "Available modes:\n"); + for (unsigned int i = 0; i < kms->connector->count_modes; i++) { + MP_INFO(kms, + "Mode %d: %s (%dx%d)\n", + i, + kms->connector->modes[i].name, + kms->connector->modes[i].hdisplay, + kms->connector->modes[i].vdisplay); + } + return false; + } + + kms->mode = kms->connector->modes[mode_id]; + return true; +} + + +struct kms *kms_create(struct mp_log *log) +{ + struct kms *ret = talloc(NULL, struct kms); + *ret = (struct kms) { + .log = mp_log_new(ret, log, "kms"), + .fd = -1, + .connector = NULL, + .encoder = NULL, + .mode = { 0 }, + .crtc_id = -1, + }; + return ret; +} + +bool kms_setup(struct kms *kms, const char *device_path, int connector_id, int mode_id) +{ + kms->fd = open(device_path, O_RDWR | O_CLOEXEC); + if (kms->fd < 0) { + MP_ERR(kms, "Cannot open \"%s\": %s.\n", device_path, mp_strerror(errno)); + return false; + } + + drmModeRes *res = drmModeGetResources(kms->fd); + if (!res) { + MP_ERR(kms, "Cannot retrieve DRM resources: %s\n", mp_strerror(errno)); + return false; + } + + if (!setup_connector(kms, res, mode_id)) + return false; + if (!setup_crtc(kms, res)) + return false; + if (!setup_mode(kms, mode_id)) + return false; + + return true; +} + +void kms_destroy(struct kms *kms) +{ + if (!kms) + return; + if (kms->connector) { + drmModeFreeConnector(kms->connector); + kms->connector = NULL; + } + if (kms->encoder) { + drmModeFreeEncoder(kms->encoder); + kms->encoder = NULL; + } + close(kms->fd); + talloc_free(kms); +} + + + +// VT switcher ---------------------------------------------------------------- + static void vt_switcher_sighandler(int sig) { - unsigned char event = sig == SIGUSR1 ? EVT_RELEASE : EVT_ACQUIRE; + unsigned char event = sig == RELEASE_SIGNAL ? EVT_RELEASE : EVT_ACQUIRE; write(vt_switcher_pipe[1], &event, sizeof(event)); } -int vt_switcher_init(struct vt_switcher *s, struct mp_log *log) +static bool has_signal_installed(int signo) +{ + struct sigaction act = { 0 }; + sigaction(signo, 0, &act); + return act.sa_handler != 0; +} + +static int install_signal(int signo, void (*handler)(int)) +{ + struct sigaction act = { 0 }; + act.sa_handler = handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + return sigaction(signo, &act, NULL); +} + + +bool vt_switcher_init(struct vt_switcher *s, struct mp_log *log) { s->log = log; s->tty_fd = -1; @@ -53,37 +256,48 @@ int vt_switcher_init(struct vt_switcher *s, struct mp_log *log) if (mp_make_cloexec_pipe(vt_switcher_pipe)) { MP_ERR(s, "Creating pipe failed: %s\n", mp_strerror(errno)); - return -1; + return false; } s->tty_fd = open("/dev/tty", O_RDWR | O_CLOEXEC); if (s->tty_fd < 0) { MP_ERR(s, "Can't open TTY for VT control: %s\n", mp_strerror(errno)); - return -1; + return false; } - struct sigaction act; - act.sa_handler = vt_switcher_sighandler; - act.sa_flags = SA_RESTART; - sigemptyset(&act.sa_mask); - sigaction(SIGUSR1, &act, 0); - sigaction(SIGUSR2, &act, 0); + if (has_signal_installed(RELEASE_SIGNAL)) { + MP_ERR(s, "Can't handle VT release - signal already used\n"); + return false; + } + if (has_signal_installed(ACQUIRE_SIGNAL)) { + MP_ERR(s, "Can't handle VT acquire - signal already used\n"); + return false; + } + + if (install_signal(RELEASE_SIGNAL, vt_switcher_sighandler)) { + MP_ERR(s, "Failed to install release signal: %s\n", mp_strerror(errno)); + return false; + } + if (install_signal(ACQUIRE_SIGNAL, vt_switcher_sighandler)) { + MP_ERR(s, "Failed to install acquire signal: %s\n", mp_strerror(errno)); + return false; + } struct vt_mode vt_mode; if (ioctl(s->tty_fd, VT_GETMODE, &vt_mode) < 0) { MP_ERR(s, "VT_GETMODE failed: %s\n", mp_strerror(errno)); - return -1; + return false; } vt_mode.mode = VT_PROCESS; - vt_mode.relsig = SIGUSR1; - vt_mode.acqsig = SIGUSR2; + vt_mode.relsig = RELEASE_SIGNAL; + vt_mode.acqsig = ACQUIRE_SIGNAL; if (ioctl(s->tty_fd, VT_SETMODE, &vt_mode) < 0) { MP_ERR(s, "VT_SETMODE failed: %s\n", mp_strerror(errno)); - return -1; + return false; } - return 0; + return true; } void vt_switcher_acquire(struct vt_switcher *s, @@ -108,6 +322,8 @@ void vt_switcher_interrupt_poll(struct vt_switcher *s) void vt_switcher_destroy(struct vt_switcher *s) { + install_signal(RELEASE_SIGNAL, SIG_DFL); + install_signal(ACQUIRE_SIGNAL, SIG_DFL); close(s->tty_fd); close(vt_switcher_pipe[0]); close(vt_switcher_pipe[1]); diff --git a/video/out/drm_common.h b/video/out/drm_common.h index 5e6c1915ba..98a4bad04d 100644 --- a/video/out/drm_common.h +++ b/video/out/drm_common.h @@ -18,6 +18,19 @@ #ifndef MP_VT_SWITCHER_H #define MP_VT_SWITCHER_H +#include <stdbool.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +struct kms { + struct mp_log *log; + int fd; + drmModeConnector *connector; + drmModeEncoder *encoder; + drmModeModeInfo mode; + uint32_t crtc_id; +}; + struct vt_switcher { int tty_fd; struct mp_log *log; @@ -25,7 +38,7 @@ struct vt_switcher { void *handler_data[2]; }; -int vt_switcher_init(struct vt_switcher *s, struct mp_log *log); +bool vt_switcher_init(struct vt_switcher *s, struct mp_log *log); void vt_switcher_destroy(struct vt_switcher *s); void vt_switcher_poll(struct vt_switcher *s, int timeout_ms); void vt_switcher_interrupt_poll(struct vt_switcher *s); @@ -33,4 +46,8 @@ void vt_switcher_interrupt_poll(struct vt_switcher *s); void vt_switcher_acquire(struct vt_switcher *s, void (*handler)(void*), void *user_data); void vt_switcher_release(struct vt_switcher *s, void (*handler)(void*), void *user_data); +struct kms *kms_create(struct mp_log *log); +bool kms_setup(struct kms *kms, const char *device_path, int conn_id, int mode_id); +void kms_destroy(struct kms *kms); + #endif diff --git a/video/out/opengl/common.c b/video/out/opengl/common.c index f045184373..54389e15cf 100644 --- a/video/out/opengl/common.c +++ b/video/out/opengl/common.c @@ -83,9 +83,7 @@ struct gl_functions { const char *extension; // introduced with this extension in any version int provides; // bitfield of MPGL_CAP_* constants int ver_core; // introduced as required function - int ver_removed; // removed as required function (no replacement) int ver_es_core; // introduced as required GL ES function - int ver_es_removed; // removed as required function (no replacement) const struct gl_function *functions; }; @@ -173,6 +171,7 @@ static const struct gl_functions gl_functions[] = { .ver_core = 300, .ver_es_core = 300, .functions = (const struct gl_function[]) { + DEF_FN(BindBufferBase), DEF_FN(GetStringi), // for ES 3.0 DEF_FN(GetTexLevelParameteriv), @@ -230,6 +229,16 @@ static const struct gl_functions gl_functions[] = { .extension = "GL_ARB_texture_rg", .provides = MPGL_CAP_TEX_RG, }, + { + .ver_core = 320, + .extension = "GL_ARB_sync", + .functions = (const struct gl_function[]) { + DEF_FN(FenceSync), + DEF_FN(ClientWaitSync), + DEF_FN(DeleteSync), + {0} + }, + }, // Swap control, always an OS specific extension // The OSX code loads this manually. { @@ -305,6 +314,16 @@ static const struct gl_functions gl_functions[] = { {0} }, }, + // uniform buffer object extensions, requires OpenGL 3.1. + { + .ver_core = 310, + .extension = "GL_ARB_uniform_buffer_object", + .functions = (const struct gl_function[]) { + DEF_FN(GetUniformBlockIndex), + DEF_FN(UniformBlockBinding), + {0} + }, + }, }; #undef FN_OFFS @@ -389,10 +408,6 @@ void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n), const struct gl_functions *section = &gl_functions[n]; int version = gl->es ? gl->es : gl->version; int ver_core = gl->es ? section->ver_es_core : section->ver_core; - int ver_removed = gl->es ? section->ver_es_removed : section->ver_removed; - - if (ver_removed && version >= ver_removed) - continue; // NOTE: Function entrypoints can exist, even if they do not work. // We must always check extension strings and versions. @@ -450,16 +465,12 @@ void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n), if (gl->es >= 300) gl->glsl_version = 300; } else { - if (gl->version >= 200) - gl->glsl_version = 110; - if (gl->version >= 210) - gl->glsl_version = 120; - if (gl->version >= 300) - gl->glsl_version = 130; - // Specifically needed for OSX (normally we request 3.0 contexts only, but - // OSX always creates 3.2 contexts when requesting a core context). - if (gl->version >= 320) - gl->glsl_version = 150; + gl->glsl_version = 110; + int glsl_major = 0, glsl_minor = 0; + if (sscanf(shader, "%d.%d", &glsl_major, &glsl_minor) == 2) + gl->glsl_version = glsl_major * 100 + glsl_minor; + // GLSL 400 defines "sample" as keyword - breaks custom shaders. + gl->glsl_version = MPMIN(gl->glsl_version, 330); } if (is_software_gl(gl)) { @@ -492,6 +503,7 @@ void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *), extern const struct mpgl_driver mpgl_driver_x11; extern const struct mpgl_driver mpgl_driver_x11egl; +extern const struct mpgl_driver mpgl_driver_drm_egl; extern const struct mpgl_driver mpgl_driver_cocoa; extern const struct mpgl_driver mpgl_driver_wayland; extern const struct mpgl_driver mpgl_driver_w32; @@ -513,6 +525,9 @@ static const struct mpgl_driver *const backends[] = { #if HAVE_EGL_X11 &mpgl_driver_x11egl, #endif +#if HAVE_EGL_DRM + &mpgl_driver_drm_egl, +#endif #if HAVE_GL_X11 &mpgl_driver_x11, #endif diff --git a/video/out/opengl/common.h b/video/out/opengl/common.h index 35d303e96c..d87be595ba 100644 --- a/video/out/opengl/common.h +++ b/video/out/opengl/common.h @@ -192,6 +192,7 @@ struct GL { void (GLAPIENTRY *GenBuffers)(GLsizei, GLuint *); void (GLAPIENTRY *DeleteBuffers)(GLsizei, const GLuint *); void (GLAPIENTRY *BindBuffer)(GLenum, GLuint); + void (GLAPIENTRY *BindBufferBase)(GLenum, GLuint, GLuint); GLvoid * (GLAPIENTRY * MapBuffer)(GLenum, GLenum); GLboolean (GLAPIENTRY *UnmapBuffer)(GLenum); void (GLAPIENTRY *BufferData)(GLenum, intptr_t, const GLvoid *, GLenum); @@ -244,6 +245,10 @@ struct GL { void (GLAPIENTRY *UniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat *); + GLsync (GLAPIENTRY *FenceSync)(GLenum, GLbitfield); + GLenum (GLAPIENTRY *ClientWaitSync)(GLsync, GLbitfield, GLuint64); + void (GLAPIENTRY *DeleteSync)(GLsync sync); + void (GLAPIENTRY *VDPAUInitNV)(const GLvoid *, const GLvoid *); void (GLAPIENTRY *VDPAUFiniNV)(void); GLvdpauSurfaceNV (GLAPIENTRY *VDPAURegisterOutputSurfaceNV) @@ -256,6 +261,9 @@ struct GL { GLint (GLAPIENTRY *GetVideoSync)(GLuint *); GLint (GLAPIENTRY *WaitVideoSync)(GLint, GLint, unsigned int *); + GLuint (GLAPIENTRY *GetUniformBlockIndex)(GLuint, const GLchar *); + void (GLAPIENTRY *UniformBlockBinding)(GLuint, GLuint, GLuint); + void (GLAPIENTRY *DebugMessageCallback)(MP_GLDEBUGPROC callback, const void *userParam); diff --git a/video/out/opengl/drm_egl.c b/video/out/opengl/drm_egl.c new file mode 100644 index 0000000000..f8e528201a --- /dev/null +++ b/video/out/opengl/drm_egl.c @@ -0,0 +1,439 @@ +/* + * 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 <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <sys/poll.h> +#include <time.h> +#include <unistd.h> + +#include <gbm.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GL/gl.h> + +#include "common.h" +#include "common/common.h" +#include "video/out/drm_common.h" + +#define USE_MASTER 0 + +struct framebuffer +{ + struct gbm_bo *bo; + int width, height; + int fd; + int id; +}; + +struct gbm +{ + struct gbm_surface *surface; + struct gbm_device *device; + struct gbm_bo *bo; + struct gbm_bo *next_bo; +}; + +struct egl +{ + EGLDisplay display; + EGLContext context; + EGLSurface surface; +}; + +struct priv { + struct kms *kms; + + drmEventContext ev; + drmModeCrtc *old_crtc; + + struct egl egl; + struct gbm gbm; + struct framebuffer fb; + + bool active; + bool waiting_for_flip; + + bool vt_switcher_active; + struct vt_switcher vt_switcher; +}; + +static EGLConfig select_fb_config_egl(struct MPGLContext *ctx, bool es) +{ + struct priv *p = ctx->priv; + const EGLint attributes[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 0, + EGL_DEPTH_SIZE, 1, + EGL_RENDERABLE_TYPE, es ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT, + EGL_NONE + }; + EGLint config_count; + EGLConfig config; + if (!eglChooseConfig(p->egl.display, attributes, &config, 1, &config_count)) { + MP_FATAL(ctx->vo, "Failed to configure EGL.\n"); + return NULL; + } + if (!config_count) { + MP_FATAL(ctx->vo, "Could not find EGL configuration!\n"); + return NULL; + } + return config; +} + +static bool init_egl(struct MPGLContext *ctx, bool es) +{ + struct priv *p = ctx->priv; + MP_VERBOSE(ctx->vo, "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"); + return false; + } + if (!eglInitialize(p->egl.display, NULL, NULL)) { + MP_ERR(ctx->vo, "Failed to initialize EGL.\n"); + return false; + } + if (!eglBindAPI(es ? EGL_OPENGL_ES_API : EGL_OPENGL_API)) { + MP_ERR(ctx->vo, "Failed to set EGL API version.\n"); + return false; + } + EGLConfig config = select_fb_config_egl(ctx, es); + if (!config) { + MP_ERR(ctx->vo, "Failed to configure EGL.\n"); + return false; + } + p->egl.context = eglCreateContext(p->egl.display, config, EGL_NO_CONTEXT, NULL); + if (!p->egl.context) { + MP_ERR(ctx->vo, "Failed to create EGL context.\n"); + return false; + } + MP_VERBOSE(ctx->vo, "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"); + return false; + } + return true; +} + +static bool init_gbm(struct MPGLContext *ctx) +{ + struct priv *p = ctx->priv; + MP_VERBOSE(ctx->vo, "Creating GBM device\n"); + p->gbm.device = gbm_create_device(p->kms->fd); + if (!p->gbm.device) { + MP_ERR(ctx->vo, "Failed to create GBM device.\n"); + return false; + } + + MP_VERBOSE(ctx->vo, "Initializing GBM surface (%d x %d)\n", + p->kms->mode.hdisplay, p->kms->mode.vdisplay); + p->gbm.surface = gbm_surface_create( + p->gbm.device, + p->kms->mode.hdisplay, + p->kms->mode.vdisplay, + GBM_BO_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + if (!p->gbm.surface) { + MP_ERR(ctx->vo, "Failed to create GBM surface.\n"); + return false; + } + return true; +} + +static void framebuffer_destroy_callback(struct gbm_bo *bo, void *data) +{ + struct framebuffer *fb = data; + if (fb) { + drmModeRmFB(fb->fd, fb->id); + } +} + +static void update_framebuffer_from_bo( + const struct MPGLContext *ctx, struct gbm_bo *bo) +{ + struct priv *p = ctx->priv; + p->fb.bo = bo; + p->fb.fd = p->kms->fd; + p->fb.width = gbm_bo_get_width(bo); + p->fb.height = gbm_bo_get_height(bo); + int stride = gbm_bo_get_stride(bo); + int handle = gbm_bo_get_handle(bo).u32; + + int ret = drmModeAddFB(p->kms->fd, p->fb.width, p->fb.height, + 24, 32, stride, handle, &p->fb.id); + if (ret) { + MP_ERR(ctx->vo, "Failed to create framebuffer: %s\n", mp_strerror(errno)); + } + gbm_bo_set_user_data(bo, &p->fb, framebuffer_destroy_callback); +} + +static void page_flipped(int fd, unsigned int frame, unsigned int sec, + unsigned int usec, void *data) +{ + struct priv *p = data; + p->waiting_for_flip = false; +} + +static bool crtc_setup(struct MPGLContext *ctx) +{ + struct priv *p = ctx->priv; + if (p->active) + return true; + p->old_crtc = drmModeGetCrtc(p->kms->fd, p->kms->crtc_id); + int ret = drmModeSetCrtc(p->kms->fd, p->kms->crtc_id, + p->fb.id, + 0, + 0, + &p->kms->connector->connector_id, + 1, + &p->kms->mode); + p->active = true; + return ret == 0; +} + +static void crtc_release(struct MPGLContext *ctx) +{ + struct priv *p = ctx->priv; + + if (!p->active) + return; + p->active = false; + + // wait for current page flip + while (p->waiting_for_flip) { + int ret = drmHandleEvent(p->kms->fd, &p->ev); + if (ret) { + MP_ERR(ctx->vo, "drmHandleEvent failed: %i\n", ret); + break; + } + } + + if (p->old_crtc) { + drmModeSetCrtc(p->kms->fd, + p->old_crtc->crtc_id, + p->old_crtc->buffer_id, + p->old_crtc->x, + p->old_crtc->y, + &p->kms->connector->connector_id, + 1, + &p->old_crtc->mode); + drmModeFreeCrtc(p->old_crtc); + p->old_crtc = NULL; + } +} + +static void release_vt(void *data) +{ + struct MPGLContext *ctx = data; + MP_VERBOSE(ctx->vo, "Releasing VT"); + crtc_release(ctx); + if (USE_MASTER) { + //this function enables support for switching to x, weston etc. + //however, for whatever reason, it can be called only by root users. + //until things change, this is commented. + struct priv *p = ctx->priv; + if (drmDropMaster(p->kms->fd)) { + MP_WARN(ctx->vo, "Failed to drop DRM master: %s\n", mp_strerror(errno)); + } + } +} + +static void acquire_vt(void *data) +{ + struct MPGLContext *ctx = data; + MP_VERBOSE(ctx->vo, "Acquiring VT"); + if (USE_MASTER) { + struct priv *p = ctx->priv; + if (drmSetMaster(p->kms->fd)) { + MP_WARN(ctx->vo, "Failed to acquire DRM master: %s\n", mp_strerror(errno)); + } + } + + crtc_setup(ctx); +} + +static void drm_egl_uninit(MPGLContext *ctx) +{ + struct priv *p = ctx->priv; + crtc_release(ctx); + + if (p->vt_switcher_active) + vt_switcher_destroy(&p->vt_switcher); + + eglMakeCurrent(p->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(p->egl.display, p->egl.context); + eglDestroySurface(p->egl.display, p->egl.surface); + gbm_surface_destroy(p->gbm.surface); + eglTerminate(p->egl.display); + gbm_device_destroy(p->gbm.device); + p->egl.context = EGL_NO_CONTEXT; + eglDestroyContext(p->egl.display, p->egl.context); + + if (p->kms) { + kms_destroy(p->kms); + p->kms = 0; + } +} + +static int drm_egl_init(struct MPGLContext *ctx, int flags) +{ + if (ctx->vo->probing) { + MP_VERBOSE(ctx->vo, "DRM EGL backend can be activated only manually.\n"); + return -1; + |