From 44eda2177d8facb1cd064c164b16e9027529d164 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Sat, 29 Aug 2015 04:12:56 +0200 Subject: vo_opengl: remove gl_ prefixes from files in video/out/opengl This is a bit redundant with the name of the directory itself, and not in line with existing naming conventions. --- video/out/opengl/cocoa.c | 171 +++ video/out/opengl/common.c | 661 ++++++++ video/out/opengl/common.h | 277 ++++ video/out/opengl/gl_cocoa.c | 171 --- video/out/opengl/gl_common.c | 661 -------- video/out/opengl/gl_common.h | 277 ---- video/out/opengl/gl_header_fixes.h | 97 -- video/out/opengl/gl_hwdec.c | 101 -- video/out/opengl/gl_hwdec.h | 53 - video/out/opengl/gl_hwdec_dxva2.c | 64 - video/out/opengl/gl_hwdec_vaglx.c | 202 --- video/out/opengl/gl_hwdec_vda.c | 244 --- video/out/opengl/gl_hwdec_vdpau.c | 209 --- video/out/opengl/gl_lcms.c | 344 ----- video/out/opengl/gl_lcms.h | 30 - video/out/opengl/gl_osd.c | 440 ------ video/out/opengl/gl_osd.h | 22 - video/out/opengl/gl_rpi.c | 249 --- video/out/opengl/gl_rpi.h | 17 - video/out/opengl/gl_utils.c | 951 ------------ video/out/opengl/gl_utils.h | 143 -- video/out/opengl/gl_video.c | 2930 ------------------------------------ video/out/opengl/gl_video.h | 117 -- video/out/opengl/gl_w32.c | 302 ---- video/out/opengl/gl_wayland.c | 241 --- video/out/opengl/gl_x11.c | 307 ---- video/out/opengl/gl_x11egl.c | 189 --- video/out/opengl/header_fixes.h | 97 ++ video/out/opengl/hwdec.c | 101 ++ video/out/opengl/hwdec.h | 53 + video/out/opengl/hwdec_dxva2.c | 64 + video/out/opengl/hwdec_vaglx.c | 202 +++ video/out/opengl/hwdec_vda.c | 244 +++ video/out/opengl/hwdec_vdpau.c | 209 +++ video/out/opengl/lcms.c | 344 +++++ video/out/opengl/lcms.h | 30 + video/out/opengl/osd.c | 440 ++++++ video/out/opengl/osd.h | 22 + video/out/opengl/rpi.c | 249 +++ video/out/opengl/rpi.h | 17 + video/out/opengl/utils.c | 951 ++++++++++++ video/out/opengl/utils.h | 143 ++ video/out/opengl/video.c | 2930 ++++++++++++++++++++++++++++++++++++ video/out/opengl/video.h | 117 ++ video/out/opengl/w32.c | 302 ++++ video/out/opengl/wayland.c | 241 +++ video/out/opengl/x11.c | 307 ++++ video/out/opengl/x11egl.c | 189 +++ video/out/vo_opengl.c | 12 +- video/out/vo_opengl_cb.c | 6 +- wscript_build.py | 32 +- 51 files changed, 8386 insertions(+), 8386 deletions(-) create mode 100644 video/out/opengl/cocoa.c create mode 100644 video/out/opengl/common.c create mode 100644 video/out/opengl/common.h delete mode 100644 video/out/opengl/gl_cocoa.c delete mode 100644 video/out/opengl/gl_common.c delete mode 100644 video/out/opengl/gl_common.h delete mode 100644 video/out/opengl/gl_header_fixes.h delete mode 100644 video/out/opengl/gl_hwdec.c delete mode 100644 video/out/opengl/gl_hwdec.h delete mode 100644 video/out/opengl/gl_hwdec_dxva2.c delete mode 100644 video/out/opengl/gl_hwdec_vaglx.c delete mode 100644 video/out/opengl/gl_hwdec_vda.c delete mode 100644 video/out/opengl/gl_hwdec_vdpau.c delete mode 100644 video/out/opengl/gl_lcms.c delete mode 100644 video/out/opengl/gl_lcms.h delete mode 100644 video/out/opengl/gl_osd.c delete mode 100644 video/out/opengl/gl_osd.h delete mode 100644 video/out/opengl/gl_rpi.c delete mode 100644 video/out/opengl/gl_rpi.h delete mode 100644 video/out/opengl/gl_utils.c delete mode 100644 video/out/opengl/gl_utils.h delete mode 100644 video/out/opengl/gl_video.c delete mode 100644 video/out/opengl/gl_video.h delete mode 100644 video/out/opengl/gl_w32.c delete mode 100644 video/out/opengl/gl_wayland.c delete mode 100644 video/out/opengl/gl_x11.c delete mode 100644 video/out/opengl/gl_x11egl.c create mode 100644 video/out/opengl/header_fixes.h create mode 100644 video/out/opengl/hwdec.c create mode 100644 video/out/opengl/hwdec.h create mode 100644 video/out/opengl/hwdec_dxva2.c create mode 100644 video/out/opengl/hwdec_vaglx.c create mode 100644 video/out/opengl/hwdec_vda.c create mode 100644 video/out/opengl/hwdec_vdpau.c create mode 100644 video/out/opengl/lcms.c create mode 100644 video/out/opengl/lcms.h create mode 100644 video/out/opengl/osd.c create mode 100644 video/out/opengl/osd.h create mode 100644 video/out/opengl/rpi.c create mode 100644 video/out/opengl/rpi.h create mode 100644 video/out/opengl/utils.c create mode 100644 video/out/opengl/utils.h create mode 100644 video/out/opengl/video.c create mode 100644 video/out/opengl/video.h create mode 100644 video/out/opengl/w32.c create mode 100644 video/out/opengl/wayland.c create mode 100644 video/out/opengl/x11.c create mode 100644 video/out/opengl/x11egl.c diff --git a/video/out/opengl/cocoa.c b/video/out/opengl/cocoa.c new file mode 100644 index 0000000000..b3ca2854f3 --- /dev/null +++ b/video/out/opengl/cocoa.c @@ -0,0 +1,171 @@ +/* + * 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 . + * + * 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 +#include +#include "video/out/cocoa_common.h" +#include "osdep/macosx_versions.h" +#include "common.h" + +struct cgl_context { + CGLPixelFormatObj pix; + CGLContextObj ctx; +}; + +static int set_swap_interval(int enabled) +{ + CGLContextObj ctx = CGLGetCurrentContext(); + CGLError err = CGLSetParameter(ctx, kCGLCPSwapInterval, &enabled); + return (err == kCGLNoError) ? 0 : -1; +} + +static int cgl_color_size(struct MPGLContext *ctx) +{ + struct cgl_context *p = ctx->priv; + GLint value; + CGLDescribePixelFormat(p->pix, 0, kCGLPFAColorSize, &value); + return value > 16 ? 8 : 5; +} + +static void *cocoa_glgetaddr(const char *s) +{ + void *ret = NULL; + void *handle = dlopen( + "/System/Library/Frameworks/OpenGL.framework/OpenGL", + RTLD_LAZY | RTLD_LOCAL); + if (!handle) + return NULL; + ret = dlsym(handle, s); + dlclose(handle); + return ret; +} + +static CGLError test_gl_version(struct vo *vo, + CGLContextObj *ctx, + CGLPixelFormatObj *pix, + CGLOpenGLProfile version) +{ + CGLPixelFormatAttribute attrs[] = { + kCGLPFAOpenGLProfile, + (CGLPixelFormatAttribute) version, + kCGLPFADoubleBuffer, + kCGLPFAAccelerated, + #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8 + // leave this as the last entry of the array to not break the fallback + // code + kCGLPFASupportsAutomaticGraphicsSwitching, + #endif + 0 + }; + + GLint npix; + CGLError err; + err = CGLChoosePixelFormat(attrs, pix, &npix); + if (err == kCGLBadAttribute) { + // kCGLPFASupportsAutomaticGraphicsSwitching is probably not supported + // by the current hardware. Falling back to not using it. + attrs[MP_ARRAY_SIZE(attrs) - 2] = 0; + err = CGLChoosePixelFormat(attrs, pix, &npix); + } + + if (err != kCGLNoError) { + MP_ERR(vo, "error creating CGL pixel format: %s (%d)\n", + CGLErrorString(err), err); + goto error_out; + } + + err = CGLCreateContext(*pix, 0, ctx); + +error_out: + return err; +} + +static bool create_gl_context(struct MPGLContext *ctx) +{ + struct cgl_context *p = ctx->priv; + CGLError err; + + CGLOpenGLProfile gl_versions[] = { + kCGLOGLPVersion_3_2_Core, + kCGLOGLPVersion_Legacy, + }; + + for (int n = 0; n < MP_ARRAY_SIZE(gl_versions); n++) { + err = test_gl_version(ctx->vo, &p->ctx, &p->pix, gl_versions[n]); + if (err == kCGLNoError) + break; + } + + if (err != kCGLNoError) { + MP_FATAL(ctx->vo, "error creating CGL context: %s (%d)\n", + CGLErrorString(err), err); + return false; + } + + vo_cocoa_set_opengl_ctx(ctx->vo, p->ctx); + CGLSetCurrentContext(p->ctx); + + ctx->depth_r = ctx->depth_g = ctx->depth_b = cgl_color_size(ctx); + mpgl_load_functions(ctx->gl, (void *)cocoa_glgetaddr, NULL, ctx->vo->log); + + CGLReleasePixelFormat(p->pix); + + return true; +} + +static bool config_window_cocoa(struct MPGLContext *ctx, int flags) +{ + struct cgl_context *p = ctx->priv; + + if (p->ctx == NULL) + if (!create_gl_context(ctx)) + return false; + + if (!ctx->gl->SwapInterval) + ctx->gl->SwapInterval = set_swap_interval; + + vo_cocoa_config_window(ctx->vo, flags); + + return true; +} + +static void releaseGlContext_cocoa(MPGLContext *ctx) +{ + struct cgl_context *p = ctx->priv; + CGLReleaseContext(p->ctx); +} + +static void swapGlBuffers_cocoa(MPGLContext *ctx) +{ + vo_cocoa_swap_buffers(ctx->vo); +} + +void mpgl_set_backend_cocoa(MPGLContext *ctx) +{ + ctx->priv = talloc_zero(ctx, struct cgl_context); + ctx->config_window = config_window_cocoa; + ctx->releaseGlContext = releaseGlContext_cocoa; + ctx->swapGlBuffers = swapGlBuffers_cocoa; + ctx->vo_init = vo_cocoa_init; + ctx->vo_uninit = vo_cocoa_uninit; + ctx->vo_control = vo_cocoa_control; +} diff --git a/video/out/opengl/common.c b/video/out/opengl/common.c new file mode 100644 index 0000000000..6720e13f2a --- /dev/null +++ b/video/out/opengl/common.c @@ -0,0 +1,661 @@ +/* + * common OpenGL routines + * + * copyleft (C) 2005-2010 Reimar Döffinger + * Special thanks go to the xine team and Matthias Hopf, whose video_out_opengl.c + * gave me lots of good ideas. + * + * 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 . + * + * 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. + */ + +/** + * \file gl_common.c + * \brief OpenGL helper functions used by vo_gl.c and vo_gl2.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include "talloc.h" +#include "common.h" +#include "common/common.h" +#include "options/options.h" +#include "options/m_option.h" + +// This guesses if the current GL context is a suspected software renderer. +static bool is_software_gl(GL *gl) +{ + const char *renderer = gl->GetString(GL_RENDERER); + const char *vendor = gl->GetString(GL_VENDOR); + return !(renderer && vendor) || + strcmp(renderer, "Software Rasterizer") == 0 || + strstr(renderer, "llvmpipe") || + strcmp(vendor, "Microsoft Corporation") == 0 || + strcmp(renderer, "Mesa X11") == 0; +} + +static void GLAPIENTRY dummy_glBindFramebuffer(GLenum target, GLuint framebuffer) +{ + assert(framebuffer == 0); +} + +static bool check_ext(GL *gl, const char *name) +{ + const char *exts = gl->extensions; + char *s = strstr(exts, name); + char *e = s ? s + strlen(name) : NULL; + return s && (s == exts || s[-1] == ' ') && (e[0] == ' ' || !e[0]); +} + +#define FN_OFFS(name) offsetof(GL, name) + +#define DEF_FN(name) {FN_OFFS(name), "gl" # name} +#define DEF_FN_NAME(name, str) {FN_OFFS(name), str} + +struct gl_function { + ptrdiff_t offset; + char *name; +}; + +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; +}; + +#define MAX_FN_COUNT 100 // max functions per gl_functions section + +// Note: to keep the number of sections low, some functions are in multiple +// sections (if there are tricky combinations of GL/ES versions) +static const struct gl_functions gl_functions[] = { + // GL 2.1+ desktop and GLES 2.0+ (anything we support) + // Probably all of these are in GL 2.0 too, but we require GLSL 120. + { + .ver_core = 210, + .ver_es_core = 200, + .functions = (const struct gl_function[]) { + DEF_FN(ActiveTexture), + DEF_FN(AttachShader), + DEF_FN(BindAttribLocation), + DEF_FN(BindBuffer), + DEF_FN(BindTexture), + DEF_FN(BlendFuncSeparate), + DEF_FN(BufferData), + DEF_FN(Clear), + DEF_FN(ClearColor), + DEF_FN(CompileShader), + DEF_FN(CreateProgram), + DEF_FN(CreateShader), + DEF_FN(DeleteBuffers), + DEF_FN(DeleteProgram), + DEF_FN(DeleteShader), + DEF_FN(DeleteTextures), + DEF_FN(Disable), + DEF_FN(DisableVertexAttribArray), + DEF_FN(DrawArrays), + DEF_FN(Enable), + DEF_FN(EnableVertexAttribArray), + DEF_FN(Finish), + DEF_FN(Flush), + DEF_FN(GenBuffers), + DEF_FN(GenTextures), + DEF_FN(GetAttribLocation), + DEF_FN(GetError), + DEF_FN(GetIntegerv), + DEF_FN(GetProgramInfoLog), + DEF_FN(GetProgramiv), + DEF_FN(GetShaderInfoLog), + DEF_FN(GetShaderiv), + DEF_FN(GetString), + DEF_FN(GetUniformLocation), + DEF_FN(LinkProgram), + DEF_FN(PixelStorei), + DEF_FN(ReadPixels), + DEF_FN(ShaderSource), + DEF_FN(TexImage2D), + DEF_FN(TexParameteri), + DEF_FN(TexSubImage2D), + DEF_FN(Uniform1f), + DEF_FN(Uniform2f), + DEF_FN(Uniform3f), + DEF_FN(Uniform1i), + DEF_FN(UniformMatrix2fv), + DEF_FN(UniformMatrix3fv), + DEF_FN(UseProgram), + DEF_FN(VertexAttribPointer), + DEF_FN(Viewport), + {0} + }, + }, + // GL 2.1+ desktop only (and GLSL 120 shaders) + { + .ver_core = 210, + .provides = MPGL_CAP_ROW_LENGTH | MPGL_CAP_1D_TEX | MPGL_CAP_3D_TEX, + .functions = (const struct gl_function[]) { + DEF_FN(DrawBuffer), + DEF_FN(GetTexLevelParameteriv), + DEF_FN(MapBuffer), + DEF_FN(ReadBuffer), + DEF_FN(TexImage1D), + DEF_FN(TexImage3D), + DEF_FN(UnmapBuffer), + {0} + }, + }, + // GL 3.0+ and ES 3.x core only functions. + { + .ver_core = 300, + .ver_es_core = 300, + .functions = (const struct gl_function[]) { + DEF_FN(GetStringi), + // for ES 3.0 + DEF_FN(GetTexLevelParameteriv), + DEF_FN(ReadBuffer), + DEF_FN(UnmapBuffer), + {0} + }, + }, + // Useful for ES 2.0 + { + .ver_core = 110, + .ver_es_core = 300, + .extension = "GL_EXT_unpack_subimage", + .provides = MPGL_CAP_ROW_LENGTH, + }, + // Framebuffers, extension in GL 2.x, core in GL 3.x core. + { + .ver_core = 300, + .ver_es_core = 200, + .extension = "GL_ARB_framebuffer_object", + .provides = MPGL_CAP_FB, + .functions = (const struct gl_function[]) { + DEF_FN(BindFramebuffer), + DEF_FN(GenFramebuffers), + DEF_FN(DeleteFramebuffers), + DEF_FN(CheckFramebufferStatus), + DEF_FN(FramebufferTexture2D), + {0} + }, + }, + // VAOs, extension in GL 2.x, core in GL 3.x core. + { + .ver_core = 300, + .ver_es_core = 300, + .extension = "GL_ARB_vertex_array_object", + .provides = MPGL_CAP_VAO, + .functions = (const struct gl_function[]) { + DEF_FN(GenVertexArrays), + DEF_FN(BindVertexArray), + DEF_FN(DeleteVertexArrays), + {0} + } + }, + // Float textures, extension in GL 2.x, core in GL 3.x core. + { + .ver_core = 300, + .ver_es_core = 300, + .extension = "GL_ARB_texture_float", + .provides = MPGL_CAP_FLOAT_TEX, + }, + // GL_RED / GL_RG textures, extension in GL 2.x, core in GL 3.x core. + { + .ver_core = 300, + .ver_es_core = 300, + .extension = "GL_ARB_texture_rg", + .provides = MPGL_CAP_TEX_RG, + }, + // Swap control, always an OS specific extension + // The OSX code loads this manually. + { + .extension = "GLX_SGI_swap_control", + .functions = (const struct gl_function[]) { + DEF_FN_NAME(SwapInterval, "glXSwapIntervalSGI"), + {0}, + }, + }, + { + .extension = "WGL_EXT_swap_control", + .functions = (const struct gl_function[]) { + DEF_FN_NAME(SwapInterval, "wglSwapIntervalEXT"), + {0}, + }, + }, + { + .extension = "GLX_SGI_video_sync", + .functions = (const struct gl_function[]) { + DEF_FN_NAME(GetVideoSync, "glXGetVideoSyncSGI"), + DEF_FN_NAME(WaitVideoSync, "glXWaitVideoSyncSGI"), + {0}, + }, + }, + // For gl_hwdec_vdpau.c + // http://www.opengl.org/registry/specs/NV/vdpau_interop.txt + { + .extension = "GL_NV_vdpau_interop", + .provides = MPGL_CAP_VDPAU, + .functions = (const struct gl_function[]) { + // (only functions needed by us) + DEF_FN(VDPAUInitNV), + DEF_FN(VDPAUFiniNV), + DEF_FN(VDPAURegisterOutputSurfaceNV), + DEF_FN(VDPAUUnregisterSurfaceNV), + DEF_FN(VDPAUSurfaceAccessNV), + DEF_FN(VDPAUMapSurfacesNV), + DEF_FN(VDPAUUnmapSurfacesNV), + {0} + }, + }, + // Apple Packed YUV Formats + // For gl_hwdec_vda.c + // http://www.opengl.org/registry/specs/APPLE/rgb_422.txt + { + .extension = "GL_APPLE_rgb_422", + .provides = MPGL_CAP_APPLE_RGB_422, + }, + { + .ver_core = 430, + .extension = "GL_ARB_debug_output", + .provides = MPGL_CAP_DEBUG, + .functions = (const struct gl_function[]) { + // (only functions needed by us) + DEF_FN(DebugMessageCallback), + {0} + }, + }, + // These don't exist - they are for the sake of mpv internals, and libmpv + // interaction (see libmpv/opengl_cb.h). + { + .extension = "GL_MP_D3D_interfaces", + .functions = (const struct gl_function[]) { + DEF_FN(MPGetD3DInterface), + {0} + }, + }, +}; + +#undef FN_OFFS +#undef DEF_FN_HARD +#undef DEF_FN +#undef DEF_FN_NAME + + +// Fill the GL struct with function pointers and extensions from the current +// GL context. Called by the backend. +// getProcAddress: function to resolve function names, may be NULL +// ext2: an extra extension string +// log: used to output messages +// Note: if you create a CONTEXT_FORWARD_COMPATIBLE_BIT_ARB with OpenGL 3.0, +// you must append "GL_ARB_compatibility" to ext2. +void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n), + void *fn_ctx, const char *ext2, struct mp_log *log) +{ + talloc_free_children(gl); + *gl = (GL) { + .extensions = talloc_strdup(gl, ext2 ? ext2 : ""), + }; + + gl->GetString = get_fn(fn_ctx, "glGetString"); + if (!gl->GetString) { + mp_err(log, "Can't load OpenGL functions.\n"); + goto error; + } + + int major = 0, minor = 0; + const char *version_string = gl->GetString(GL_VERSION); + if (!version_string) + goto error; + mp_verbose(log, "GL_VERSION='%s'\n", version_string); + if (strncmp(version_string, "OpenGL ES ", 10) == 0) { + version_string += 10; + gl->es = 100; + } + if (sscanf(version_string, "%d.%d", &major, &minor) < 2) + goto error; + gl->version = MPGL_VER(major, minor); + mp_verbose(log, "Detected %s %d.%d.\n", gl->es ? "GLES" : "desktop OpenGL", + major, minor); + + if (gl->es) { + gl->es = gl->version; + gl->version = 0; + if (gl->es < 200) { + mp_fatal(log, "At least GLESv2 required.\n"); + goto error; + } + } + + mp_verbose(log, "GL_VENDOR='%s'\n", gl->GetString(GL_VENDOR)); + mp_verbose(log, "GL_RENDERER='%s'\n", gl->GetString(GL_RENDERER)); + const char *shader = gl->GetString(GL_SHADING_LANGUAGE_VERSION); + if (shader) + mp_verbose(log, "GL_SHADING_LANGUAGE_VERSION='%s'\n", shader); + + if (gl->version >= 300) { + gl->GetStringi = get_fn(fn_ctx, "glGetStringi"); + gl->GetIntegerv = get_fn(fn_ctx, "glGetIntegerv"); + + if (!(gl->GetStringi && gl->GetIntegerv)) + goto error; + + GLint exts; + gl->GetIntegerv(GL_NUM_EXTENSIONS, &exts); + for (int n = 0; n < exts; n++) { + const char *ext = gl->GetStringi(GL_EXTENSIONS, n); + gl->extensions = talloc_asprintf_append(gl->extensions, " %s", ext); + } + + } else { + const char *ext = (char*)gl->GetString(GL_EXTENSIONS); + gl->extensions = talloc_asprintf_append(gl->extensions, " %s", ext); + } + + mp_dbg(log, "Combined OpenGL extensions string:\n%s\n", gl->extensions); + + for (int n = 0; n < MP_ARRAY_SIZE(gl_functions); 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. + + bool exists = false, must_exist = false; + if (ver_core) + must_exist = version >= ver_core; + + if (section->extension && check_ext(gl, section->extension)) + exists = true; + + exists |= must_exist; + if (!exists) + continue; + + void *loaded[MAX_FN_COUNT] = {0}; + bool all_loaded = true; + const struct gl_function *fnlist = section->functions; + + for (int i = 0; fnlist && fnlist[i].name; i++) { + const struct gl_function *fn = &fnlist[i]; + void *ptr = get_fn(fn_ctx, fn->name); + if (!ptr) { + all_loaded = false; + mp_warn(log, "Required function '%s' not " + "found for %s OpenGL %d.%d.\n", fn->name, + section->extension ? section->extension : "builtin", + MPGL_VER_GET_MAJOR(ver_core), + MPGL_VER_GET_MINOR(ver_core)); + if (must_exist) + goto error; + break; + } + assert(i < MAX_FN_COUNT); + loaded[i] = ptr; + } + + if (all_loaded) { + gl->mpgl_caps |= section->provides; + for (int i = 0; fnlist && fnlist[i].name; i++) { + const struct gl_function *fn = &fnlist[i]; + void **funcptr = (void**)(((char*)gl) + fn->offset); + if (loaded[i]) + *funcptr = loaded[i]; + } + mp_verbose(log, "Loaded functions for %d/%s.\n", ver_core, + section->extension ? section->extension : "builtin"); + } + } + + gl->glsl_version = 0; + if (gl->es) { + if (gl->es >= 200) + gl->glsl_version = 100; + 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; + } + + if (is_software_gl(gl)) { + gl->mpgl_caps |= MPGL_CAP_SW; + mp_verbose(log, "Detected suspected software renderer.\n"); + } + + // Provided for simpler handling if no framebuffer support is available. + if (!gl->BindFramebuffer) + gl->BindFramebuffer = &dummy_glBindFramebuffer; + return; + +error: + gl->version = 0; + gl->es = 0; + gl->mpgl_caps = 0; +} + +static void *get_procaddr_wrapper(void *ctx, const char *name) +{ + void *(*getProcAddress)(const GLubyte *) = ctx; + return getProcAddress ? getProcAddress((const GLubyte*)name) : NULL; +} + +void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *), + const char *ext2, struct mp_log *log) +{ + mpgl_load_functions2(gl, get_procaddr_wrapper, getProcAddress, ext2, log); +} + +typedef void (*MPGLSetBackendFn)(MPGLContext *ctx); + +struct backend { + const char *name; + MPGLSetBackendFn init; + const struct mpgl_driver *driver; +}; + +extern const struct mpgl_driver mpgl_driver_x11; +extern const struct mpgl_driver mpgl_driver_x11egl; + +static const struct backend backends[] = { +#if HAVE_RPI + {"rpi", mpgl_set_backend_rpi}, +#endif +#if HAVE_GL_COCOA + {"cocoa", mpgl_set_backend_cocoa}, +#endif +#if HAVE_GL_WIN32 + {"win", mpgl_set_backend_w32}, +#endif + +//Add the wayland backend before x11, in order to probe for a wayland-server before a x11-server and avoid using xwayland +#if HAVE_GL_WAYLAND + {"wayland", mpgl_set_backend_wayland}, +#endif +#if HAVE_GL_X11 + {.driver = &mpgl_driver_x11}, +#endif +#if HAVE_EGL_X11 + {.driver = &mpgl_driver_x11egl}, +#endif +}; + +int mpgl_find_backend(const char *name) +{ + if (name == NULL || strcmp(name, "auto") == 0) + return -1; + for (int n = 0; n < MP_ARRAY_SIZE(backends); n++) { + const struct backend *entry = &backends[n]; + const char *ename = entry->driver ? entry->driver->name : entry->name; + if (strcmp(ename, name) == 0) + return entry - backends; + } + return -2; +} + +int mpgl_validate_backend_opt(struct mp_log *log, const struct m_option *opt, + struct bstr name, struct bstr param) +{ + if (bstr_equals0(param, "help")) { + mp_info(log, "OpenGL windowing backends:\n"); + mp_info(log, " auto (autodetect)\n"); + for (int n = 0; n < MP_ARRAY_SIZE(backends); n++) { + const struct backend *entry = &backends[n]; + const char *ename = entry->driver ? entry->driver->name : entry->name; + mp_info(log, " %s\n", ename); + } + return M_OPT_EXIT - 1; + } + char s[20]; + snprintf(s, sizeof(s), "%.*s", BSTR_P(param)); + return mpgl_find_backend(s) >= -1 ? 1 : M_OPT_INVALID; +} + +static MPGLContext *init_backend(struct vo *vo, const struct backend *backend, + bool probing, int vo_flags) +{ + MPGLContext *ctx = talloc_ptrtype(NULL, ctx); + *ctx = (MPGLContext) { + .gl = talloc_zero(ctx, GL), + .vo = vo, + .driver = backend->driver, + }; + bool old_probing = vo->probing; + vo->probing = probing; // hack; kill it once backends are separate + if (ctx->driver) { + MP_VERBOSE(vo, "Initializing OpenGL backend '%s'\n", ctx->driver->name); + ctx->priv = talloc_zero_size(ctx, ctx->driver->priv_size); + if (ctx->driver->init(ctx, vo_flags) < 0) { + talloc_free(ctx); + return NULL; + } + } else { + MP_VERBOSE(vo, "Initializing OpenGL backend '%s'\n", backend->name); + backend->init(ctx); + if (!ctx->vo_init(vo)) { + talloc_free(ctx); + return NULL; + } + } + vo->probing = old_probing; + + if (!ctx->driver && !ctx->config_window(ctx, vo_flags | VOFLAG_HIDDEN)) + goto cleanup; + + if (!ctx->gl->version && !ctx->gl->es) + goto cleanup; + + if (ctx->gl->es && vo->probing) { + MP_INFO(ctx->vo, "Skipping experimental GLES support (use --vo=opengl).\n"); + goto cleanup; + } + + if (ctx->gl->mpgl_caps & MPGL_CAP_SW) { + MP_WARN(ctx->vo, "Suspected software renderer or indirect context.\n"); + if (vo->probing) + goto cleanup; + } + + ctx->gl->debug_context = !!(vo_flags & VOFLAG_GL_DEBUG); + + return ctx; + +cleanup: + mpgl_uninit(ctx); + return NULL; +} + +// Create a VO window and create a GL context on it. +// vo_flags: passed to the backend's create window function +MPGLContext *mpgl_init(struct vo *vo, const char *backend_name, int vo_flags) +{ + MPGLContext *ctx = NULL; + int index = mpgl_find_backend(backend_name); + if (index == -1) { + for (int n = 0; n < MP_ARRAY_SIZE(backends); n++) { + ctx = init_backend(vo, &backends[n], true, vo_flags); + if (ctx) + break; + } + } else if (index >= 0) { + ctx = init_backend(vo, &backends[index], false, vo_flags); + } + return ctx; +} + +// flags: passed to the backend function +bool mpgl_reconfig_window(struct MPGLContext *ctx, int vo_flags) +{ + if (ctx->driver) { + return ctx->driver->reconfig(ctx, vo_flags) >= 0; + } else { + return ctx->config_window(ctx, vo_flags); + } +} + +int mpgl_control(struct MPGLContext *ctx, int *events, int request, void *arg) +{ + if (ctx->driver) { + return ctx->driver->control(ctx, events, request, arg); + } else { + return ctx->vo_control(ctx->vo, events, request, arg); + } +} + +void mpgl_swap_buffers(struct MPGLContext *ctx) +{ + if (ctx->driver) { + ctx->driver->swap_buffers(ctx); + } else { + ctx->swapGlBuffers(ctx); + } +} + +void mpgl_uninit(MPGLContext *ctx) +{ + if (ctx) { + if (ctx->driver) { + ctx->driver->uninit(ctx); + } else { + ctx->releaseGlContext(ctx); + ctx->vo_uninit(ctx->vo); + } + } + talloc_free(ctx); +} diff --git a/video/out/opengl/common.h b/video/out/opengl/common.h new file mode 100644 index 0000000000..083e2ca023 --- /dev/null +++ b/video/out/opengl/common.h @@ -0,0 +1,277 @@ +/* + * 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 . + * + * 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. + */ + +#ifndef MPLAYER_GL_COMMON_H +#define MPLAYER_GL_COMMON_H + +#include +#include +#include + +#include "config.h" +#include "common/msg.h" +#include "misc/bstr.h" + +#include "video/out/vo.h" +#include "video/csputils.h" + +#include "video/mp_image.h" + +#if HAVE_GL_COCOA +#define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED 1 +#include +#include +#include +#else +#include +#include +#endif + +#define MP_GET_GL_WORKAROUNDS +#include "header_fixes.h" + +struct GL; +typedef struct GL GL; + +enum { + MPGL_CAP_ROW_LENGTH = (1 << 4), // GL_[UN]PACK_ROW_LENGTH + MPGL_CAP_FB = (1 << 5), + MPGL_CAP_VAO = (1 << 6), + MPGL_CAP_FLOAT_TEX = (1 << 9), + MPGL_CAP_TEX_RG = (1 << 10), // GL_ARB_texture_rg / GL 3.x + MPGL_CAP_VDPAU = (1 << 11), // GL_NV_vdpau_interop + MPGL_CAP_APPLE_RGB_422 = (1 << 12), // GL_APPLE_rgb_422 + MPGL_CAP_1D_TEX = (1 << 14), + MPGL_CAP_3D_TEX = (1 << 15), + MPGL_CAP_DEBUG = (1 << 16), + MPGL_CAP_SW = (1 << 30), // indirect or sw renderer +}; + +// E.g. 310 means 3.1 +// Code doesn't have to use the macros; they are for convenience only. +#define MPGL_VER(major, minor) (((major) * 100) + (minor) * 10) +#define MPGL_VER_GET_MAJOR(ver) ((unsigned)(ver) / 100) +#define MPGL_VER_GET_MINOR(ver) ((unsigned)(ver) % 100 / 10) + +#define MPGL_VER_P(ver) MPGL_VER_GET_MAJOR(ver), MPGL_VER_GET_MINOR(ver) + +struct MPGLContext; + +// A backend (like X11, win32, ...), which provides OpenGL rendering. +// This should be preferred for new code, instead of setting the callbacks +// in MPGLContext directly. +struct mpgl_driver { + const char *name; + + // Size of the struct allocated for MPGLContext.priv + int priv_size; + + // Init the GL context and possibly the underlying VO backend. + // The created context should be compatible to GL 3.2 core profile, but + // some other GL versions are supported as well (e.g. GL 2.1 or GLES 2). + // Return 0 on success, negative value (-1) on error. + int (*init)(struct MPGLContext *ctx, int vo_flags); + + // Resize the window, or create a new window if there isn't one yet. + // Currently, there is an unfortunate interaction with ctx->vo, and + // display size etc. are determined by it. + // Return 0 on success, negative value (-1) on error. + int (*reconfig)(struct MPGLContext *ctx, int flags); + + // Present the frame. + void (*swap_buffers)(struct MPGLContext *ctx); + + // This behaves exactly like vo_driver.control(). + int (*control)(struct MPGLContext *ctx, int *events, int request, void *arg); + + // Destroy the GL context and possibly the underlying VO backend. + void (*uninit)(struct MPGLContext *ctx); +}; + +typedef struct MPGLContext { + GL *gl; + struct vo *vo; + const struct mpgl_driver *driver; + + // Bit size of each component in the created framebuffer. 0 if unknown. + int depth_r, depth_g, depth_b; + + // For free use by the mpgl_driver. + void *priv; + + // Warning: all callbacks below are legacy. Newer code should use + // a mpgl_driver struct, which replaces these callbacks. + + void (*swapGlBuffers)(struct MPGLContext *); + int (*vo_init)(struct vo *vo); + void (*vo_uninit)(struct vo *vo); + int (*vo_control)(struct vo *vo, int *events, int request, void *arg); + void (*releaseGlContext)(struct MPGLContext *); + + // Used on windows only, tries to vsync with the DWM, and modifies SwapInterval + // when it does so. Returns the possibly modified swapinterval value. + int (*DwmFlush)(struct MPGLContext *, int opt_dwmflush, + int opt_swapinterval, int current_swapinterval); + + + // Resize the window, or create a new window if there isn't one yet. + // On the first call, it creates a GL context. + bool (*config_window)(struct MPGLContext *ctx, int flags); +} MPGLContext; + +MPGLContext *mpgl_init(struct vo *vo, const char *backend_name, int vo_flags); +void mpgl_uninit(MPGLContext *ctx); +bool mpgl_reconfig_window(struct MPGLContext *ctx, int vo_flags); +int mpgl_control(struct MPGLContext *ctx, int *events, int request, void *arg); +void mpgl_swap_buffers(struct MPGLContext *ctx); + +int mpgl_find_backend(const char *name); + +struct m_option; +int mpgl_validate_backend_opt(struct mp_log *log, const struct m_option *opt, + struct bstr name, struct bstr param); + +void mpgl_set_backend_cocoa(MPGLContext *ctx); +void mpgl_set_backend_w32(MPGLContext *ctx); +void mpgl_set_backend_wayland(MPGLContext *ctx); +void mpgl_set_backend_rpi(MPGLContext *ctx); + +void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *), + const char *ext2, struct mp_log *log); +void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n), + void *fn_ctx, const char *ext2, struct mp_log *log); + +typedef void (GLAPIENTRY *MP_GLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, + GLsizei, const GLchar *,const void *); + +//function pointers loaded from the OpenGL library +struct GL { + int version; // MPGL_VER() mangled (e.g. 210 for 2.1) + int es; // es version (e.g. 300), 0 for desktop GL + int glsl_version; // e.g. 130 for GLSL 1.30 + char *extensions; // Equivalent to GL_EXTENSIONS + int mpgl_caps; // Bitfield of MPGL_CAP_* constants + bool debug_context; // use of e.g. GLX_CONTEXT_DEBUG_BIT_ARB + + void (GLAPIENTRY *Viewport)(GLint, GLint, GLsizei, GLsizei); + void (GLAPIENTRY *Clear)(GLbitfield); + void (GLAPIENTRY *GenTextures)(GLsizei, GLuint *); + void (GLAPIENTRY *DeleteTextures)(GLsizei, const GLuint *); + void (GLAPIENTRY *ClearColor)(GLclampf, GLclampf, GLclampf, GLclampf); + void (GLAPIENTRY *Enable)(GLenum); + void (GLAPIENTRY *Disable)(GLenum); + const GLubyte *(GLAPIENTRY * GetString)(GLenum); + void (GLAPIENTRY *DrawBuffer)(GLenum); + void (GLAPIENTRY *BlendFuncSeparate)(GLenum, GLenum, GLenum, GLenum); + void (GLAPIENTRY *Flush)(void); + void (GLAPIENTRY *Finish)(void); + void (GLAPIENTRY *PixelStorei)(GLenum, GLint); + void (GLAPIENTRY *TexImage1D)(GLenum, GLint, GLint, GLsizei, GLint, + GLenum, GLenum, const GLvoid *); + void (GLAPIENTRY *TexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, + GLint, GLenum, GLenum, const GLvoid *); + void (GLAPIENTRY *TexSubImage2D)(GLenum, GLint, GLint, GLint, + GLsizei, GLsizei, GLenum, GLenum, + const GLvoid *); + void (GLAPIENTRY *TexParameteri)(GLenum, GLenum, GLint); + void (GLAPIENTRY *GetIntegerv)(GLenum, GLint *); + void (GLAPIENTRY *ReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, + GLenum, GLvoid *); + void (GLAPIENTRY *ReadBuffer)(GLenum); + void (GLAPIENTRY *DrawArrays)(GLenum, GLint, GLsizei); + GLenum (GLAPIENTRY *GetError)(void); + void (GLAPIENTRY *GetTexLevelParameteriv)(GLenum, GLint, GLenum, GLint *); + + void (GLAPIENTRY *GenBuffers)(GLsizei, GLuint *); + void (GLAPIENTRY *DeleteBuffers)(GLsizei, const GLuint *); + void (GLAPIENTRY *BindBuffer)(GLenum, GLuint); + GLvoid * (GLAPIENTRY * MapBuffer)(GLenum, GLenum); + GLboolean (GLAPIENTRY *UnmapBuffer)(GLenum); + void (GLAPIENTRY *BufferData)(GLenum, intptr_t, const GLvoid *, GLenum); + void (GLAPIENTRY *ActiveTexture)(GLenum); + void (GLAPIENTRY *BindTexture)(GLenum, GLuint); + int (GLAPIENTRY *SwapInterval)(int); + void (GLAPIENTRY *TexImage3D)(GLenum, GLint, GLenum, GLsizei, GLsizei, + GLsizei, GLint, GLenum, GLenum, + const GLvoid *); + + void (GLAPIENTRY *GenVertexArrays)(GLsizei, GLuint *); + void (GLAPIENTRY *BindVertexArray)(GLuint); + GLint (GLAPIENTRY *GetAttribLocation)(GLuint, const GLchar *); + void (GLAPIENTRY *EnableVertexAttribArray)(GLuint); + void (GLAPIENTRY *DisableVertexAttribArray)(GLuint); + void (GLAPIENTRY *VertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, + GLsizei, const GLvoid *); + void (GLAPIENTRY *DeleteVertexArrays)(GLsizei, const GLuint *); + void (GLAPIENTRY *UseProgram)(GLuint); + GLint (GLAPIENTRY *GetUniformLocation)(GLuint, const GLchar *); + void (GLAPIENTRY *CompileShader)(GLuint); + GLuint (GLAPIENTRY *CreateProgram)(void); + GLuint (GLAPIENTRY *CreateShader)(GLenum); + void (GLAPIENTRY *ShaderSource)(GLuint, GLsizei, const GLchar **, + const GLint *); + void (GLAPIENTRY *LinkProgram)(GLuint); + void (GLAPIENTRY *AttachShader)(GLuint, GLuint); + void (GLAPIENTRY *DeleteShader)(GLuint); + void (GLAPIENTRY *DeleteProgram)(GLuint); + void (GLAPIENTRY *GetShaderInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); + void (GLAPIENTRY *GetShaderiv)(GLuint, GLenum, GLint *); + void (GLAPIENTRY *GetProgramInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); + void (GLAPIENTRY *GetProgramiv)(GLenum, GLenum, GLint *); + const GLubyte* (GLAPIENTRY *GetStringi)(GLenum, GLuint); + void (GLAPIENTRY *BindAttribLocation)(GLuint, GLuint, const GLchar *); + void (GLAPIENTRY *BindFramebuffer)(GLenum, GLuint); + void (GLAPIENTRY *GenFramebuffers)(GLsizei, GLuint *); + void (GLAPIENTRY *DeleteFramebuffers)(GLsizei, const GLuint *); + GLenum (GLAPIENTRY *CheckFramebufferStatus)(GLenum); + void (GLAPIENTRY *FramebufferTexture2D)(GLenum, GLenum, GLenum, GLuint, + GLint); + + void (GLAPIENTRY *Uniform1f)(GLint, GLfloat); + void (GLAPIENTRY *Uniform2f)(GLint, GLfloat, GLfloat); + void (GLAPIENTRY *Uniform3f)(GLint, GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY *Uniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY *Uniform1i)(GLint, GLint); + void (GLAPIENTRY *UniformMatrix2fv)(GLint, GLsizei, GLboolean, + const GLfloat *); + void (GLAPIENTRY *UniformMatrix3fv)(GLint, GLsizei, GLboolean, + const GLfloat *); + + void (GLAPIENTRY *VDPAUInitNV)(const GLvoid *, const GLvoid *); + void (GLAPIENTRY *VDPAUFiniNV)(void); + GLvdpauSurfaceNV (GLAPIENTRY *VDPAURegisterOutputSurfaceNV) + (GLvoid *, GLenum, GLsizei, const GLuint *); + void (GLAPIENTRY *VDPAUUnregisterSurfaceNV)(GLvdpauSurfaceNV); + void (GLAPIENTRY *VDPAUSurfaceAccessNV)(GLvdpauSurfaceNV, GLenum); + void (GLAPIENTRY *VDPAUMapSurfacesNV)(GLsizei, const GLvdpauSurfaceNV *); + void (GLAPIENTRY *VDPAUUnmapSurfacesNV)(GLsizei, const GLvdpauSurfaceNV *); + + GLint (GLAPIENTRY *GetVideoSync)(GLuint *); + GLint (GLAPIENTRY *WaitVideoSync)(GLint, GLint, unsigned int *); + + void (GLAPIENTRY *DebugMessageCallback)(MP_GLDEBUGPROC callback, + const void *userParam); + + void *(GLAPIENTRY *MPGetD3DInterface)(const char *name); +}; + +#endif /* MPLAYER_GL_COMMON_H */ diff --git a/video/out/opengl/gl_cocoa.c b/video/out/opengl/gl_cocoa.c deleted file mode 100644 index 48ee2d3290..0000000000 --- a/video/out/opengl/gl_cocoa.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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 . - * - * 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 -#include -#include "video/out/cocoa_common.h" -#include "osdep/macosx_versions.h" -#include "gl_common.h" - -struct cgl_context { - CGLPixelFormatObj pix; - CGLContextObj ctx; -}; - -static int set_swap_interval(int enabled) -{ - CGLContextObj ctx = CGLGetCurrentContext(); - CGLError err = CGLSetParameter(ctx, kCGLCPSwapInterval, &enabled); - return (err == kCGLNoError) ? 0 : -1; -} - -static int cgl_color_size(struct MPGLContext *ctx) -{ - struct cgl_context *p = ctx->priv; - GLint value; - CGLDescribePixelFormat(p->pix, 0, kCGLPFAColorSize, &value); - return value > 16 ? 8 : 5; -} - -static void *cocoa_glgetaddr(const char *s) -{ - void *ret = NULL; - void *handle = dlopen( - "/System/Library/Frameworks/OpenGL.framework/OpenGL", - RTLD_LAZY | RTLD_LOCAL); - if (!handle) - return NULL; - ret = dlsym(handle, s); - dlclose(handle); - return ret; -} - -static CGLError test_gl_version(struct vo *vo, - CGLContextObj *ctx, - CGLPixelFormatObj *pix, - CGLOpenGLProfile version) -{ - CGLPixelFormatAttribute attrs[] = { - kCGLPFAOpenGLProfile, - (CGLPixelFormatAttribute) version, - kCGLPFADoubleBuffer, - kCGLPFAAccelerated, - #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8 - // leave this as the last entry of the array to not break the fallback - // code - kCGLPFASupportsAutomaticGraphicsSwitching, - #endif - 0 - }; - - GLint npix; - CGLError err; - err = CGLChoosePixelFormat(attrs, pix, &npix); - if (err == kCGLBadAttribute) { - // kCGLPFASupportsAutomaticGraphicsSwitching is probably not supported - // by the current hardware. Falling back to not using it. - attrs[MP_ARRAY_SIZE(attrs) - 2] = 0; - err = CGLChoosePixelFormat(attrs, pix, &npix); - } - - if (err != kCGLNoError) { - MP_ERR(vo, "error creating CGL pixel format: %s (%d)\n", - CGLErrorString(err), err); - goto error_out; - } - - err = CGLCreateContext(*pix, 0, ctx); - -error_out: - return err; -} - -static bool create_gl_context(struct MPGLContext *ctx) -{ - struct cgl_context *p = ctx->priv; - CGLError err; - - CGLOpenGLProfile gl_versions[] = { - kCGLOGLPVersion_3_2_Core, - kCGLOGLPVersion_Legacy, - }; - - for (int n = 0; n < MP_ARRAY_SIZE(gl_versions); n++) { - err = test_gl_version(ctx->vo, &p->ctx, &p->pix, gl_versions[n]); - if (err == kCGLNoError) - break; - } - - if (err != kCGLNoError) { - MP_FATAL(ctx->vo, "error creating CGL context: %s (%d)\n", - CGLErrorString(err), err); - return false; - } - - vo_cocoa_set_opengl_ctx(ctx->vo, p->ctx); - CGLSetCurrentContext(p->ctx); - - ctx->depth_r = ctx->depth_g = ctx->depth_b = cgl_color_size(ctx); - mpgl_load_functions(ctx->gl, (void *)cocoa_glgetaddr, NULL, ctx->vo->log); - - CGLReleasePixelFormat(p->pix); - - return true; -} - -static bool config_window_cocoa(struct MPGLContext *ctx, int flags) -{ - struct cgl_context *p = ctx->priv; - - if (p->ctx == NULL) - if (!create_gl_context(ctx)) - return false; - - if (!ctx->gl->SwapInterval) - ctx->gl->SwapInterval = set_swap_interval; - - vo_cocoa_config_window(ctx->vo, flags); - - return true; -} - -static void releaseGlContext_cocoa(MPGLContext *ctx) -{ - struct cgl_context *p = ctx->priv; - CGLReleaseContext(p->ctx); -} - -static void swapGlBuffers_cocoa(MPGLContext *ctx) -{ - vo_cocoa_swap_buffers(ctx->vo); -} - -void mpgl_set_backend_cocoa(MPGLContext *ctx) -{ - ctx->priv = talloc_zero(ctx, struct cgl_context); - ctx->config_window = config_window_cocoa; - ctx->releaseGlContext = releaseGlContext_cocoa; - ctx->swapGlBuffers = swapGlBuffers_cocoa; - ctx->vo_init = vo_cocoa_init; - ctx->vo_uninit = vo_cocoa_uninit; - ctx->vo_control = vo_cocoa_control; -} diff --git a/video/out/opengl/gl_common.c b/video/out/opengl/gl_common.c deleted file mode 100644 index 2f78f11c08..0000000000 --- a/video/out/opengl/gl_common.c +++ /dev/null @@ -1,661 +0,0 @@ -/* - * common OpenGL routines - * - * copyleft (C) 2005-2010 Reimar Döffinger - * Special thanks go to the xine team and Matthias Hopf, whose video_out_opengl.c - * gave me lots of good ideas. - * - * 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 . - * - * 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. - */ - -/** - * \file gl_common.c - * \brief OpenGL helper functions used by vo_gl.c and vo_gl2.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include "talloc.h" -#include "gl_common.h" -#include "common/common.h" -#include "options/options.h" -#include "options/m_option.h" - -// This guesses if the current GL context is a suspected software renderer. -static bool is_software_gl(GL *gl) -{ - const char *renderer = gl->GetString(GL_RENDERER); - const char *vendor = gl->GetString(GL_VENDOR); - return !(renderer && vendor) || - strcmp(renderer, "Software Rasterizer") == 0 || - strstr(renderer, "llvmpipe") || - strcmp(vendor, "Microsoft Corporation") == 0 || - strcmp(renderer, "Mesa X11") == 0; -} - -static void GLAPIENTRY dummy_glBindFramebuffer(GLenum target, GLuint framebuffer) -{ - assert(framebuffer == 0); -} - -static bool check_ext(GL *gl, const char *name) -{ - const char *exts = gl->extensions; - char *s = strstr(exts, name); - char *e = s ? s + strlen(name) : NULL; - return s && (s == exts || s[-1] == ' ') && (e[0] == ' ' || !e[0]); -} - -#define FN_OFFS(name) offsetof(GL, name) - -#define DEF_FN(name) {FN_OFFS(name), "gl" # name} -#define DEF_FN_NAME(name, str) {FN_OFFS(name), str} - -struct gl_function { - ptrdiff_t offset; - char *name; -}; - -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; -}; - -#define MAX_FN_COUNT 100 // max functions per gl_functions section - -// Note: to keep the number of sections low, some functions are in multiple -// sections (if there are tricky combinations of GL/ES versions) -static const struct gl_functions gl_functions[] = { - // GL 2.1+ desktop and GLES 2.0+ (anything we support) - // Probably all of these are in GL 2.0 too, but we require GLSL 120. - { - .ver_core = 210, - .ver_es_core = 200, - .functions = (const struct gl_function[]) { - DEF_FN(ActiveTexture), - DEF_FN(AttachShader), - DEF_FN(BindAttribLocation), - DEF_FN(BindBuffer), - DEF_FN(BindTexture), - DEF_FN(BlendFuncSeparate), - DEF_FN(BufferData), - DEF_FN(Clear), - DEF_FN(ClearColor), - DEF_FN(CompileShader), - DEF_FN(CreateProgram), - DEF_FN(CreateShader), - DEF_FN(DeleteBuffers), - DEF_FN(DeleteProgram), - DEF_FN(DeleteShader), - DEF_FN(DeleteTextures), - DEF_FN(Disable), - DEF_FN(DisableVertexAttribArray), - DEF_FN(DrawArrays), - DEF_FN(Enable), - DEF_FN(EnableVertexAttribArray), - DEF_FN(Finish), - DEF_FN(Flush), - DEF_FN(GenBuffers), - DEF_FN(GenTextures), - DEF_FN(GetAttribLocation), - DEF_FN(GetError), - DEF_FN(GetIntegerv), - DEF_FN(GetProgramInfoLog), - DEF_FN(GetProgramiv), - DEF_FN(GetShaderInfoLog), - DEF_FN(GetShaderiv), - DEF_FN(GetString), - DEF_FN(GetUniformLocation), - DEF_FN(LinkProgram), - DEF_FN(PixelStorei), - DEF_FN(ReadPixels), - DEF_FN(ShaderSource), - DEF_FN(TexImage2D), - DEF_FN(TexParameteri), - DEF_FN(TexSubImage2D), - DEF_FN(Uniform1f), - DEF_FN(Uniform2f), - DEF_FN(Uniform3f), - DEF_FN(Uniform1i), - DEF_FN(UniformMatrix2fv), - DEF_FN(UniformMatrix3fv), - DEF_FN(UseProgram), - DEF_FN(VertexAttribPointer), - DEF_FN(Viewport), - {0} - }, - }, - // GL 2.1+ desktop only (and GLSL 120 shaders) - { - .ver_core = 210, - .provides = MPGL_CAP_ROW_LENGTH | MPGL_CAP_1D_TEX | MPGL_CAP_3D_TEX, - .functions = (const struct gl_function[]) { - DEF_FN(DrawBuffer), - DEF_FN(GetTexLevelParameteriv), - DEF_FN(MapBuffer), - DEF_FN(ReadBuffer), - DEF_FN(TexImage1D), - DEF_FN(TexImage3D), - DEF_FN(UnmapBuffer), - {0} - }, - }, - // GL 3.0+ and ES 3.x core only functions. - { - .ver_core = 300, - .ver_es_core = 300, - .functions = (const struct gl_function[]) { - DEF_FN(GetStringi), - // for ES 3.0 - DEF_FN(GetTexLevelParameteriv), - DEF_FN(ReadBuffer), - DEF_FN(UnmapBuffer), - {0} - }, - }, - // Useful for ES 2.0 - { - .ver_core = 110, - .ver_es_core = 300, - .extension = "GL_EXT_unpack_subimage", - .provides = MPGL_CAP_ROW_LENGTH, - }, - // Framebuffers, extension in GL 2.x, core in GL 3.x core. - { - .ver_core = 300, - .ver_es_core = 200, - .extension = "GL_ARB_framebuffer_object", - .provides = MPGL_CAP_FB, - .functions = (const struct gl_function[]) { - DEF_FN(BindFramebuffer), - DEF_FN(GenFramebuffers), - DEF_FN(DeleteFramebuffers), - DEF_FN(CheckFramebufferStatus), - DEF_FN(FramebufferTexture2D), - {0} - }, - }, - // VAOs, extension in GL 2.x, core in GL 3.x core. - { - .ver_core = 300, - .ver_es_core = 300, - .extension = "GL_ARB_vertex_array_object", - .provides = MPGL_CAP_VAO, - .functions = (const struct gl_function[]) { - DEF_FN(GenVertexArrays), - DEF_FN(BindVertexArray), - DEF_FN(DeleteVertexArrays), - {0} - } - }, - // Float textures, extension in GL 2.x, core in GL 3.x core. - { - .ver_core = 300, - .ver_es_core = 300, - .extension = "GL_ARB_texture_float", - .provides = MPGL_CAP_FLOAT_TEX, - }, - // GL_RED / GL_RG textures, extension in GL 2.x, core in GL 3.x core. - { - .ver_core = 300, - .ver_es_core = 300, - .extension = "GL_ARB_texture_rg", - .provides = MPGL_CAP_TEX_RG, - }, - // Swap control, always an OS specific extension - // The OSX code loads this manually. - { - .extension = "GLX_SGI_swap_control", - .functions = (const struct gl_function[]) { - DEF_FN_NAME(SwapInterval, "glXSwapIntervalSGI"), - {0}, - }, - }, - { - .extension = "WGL_EXT_swap_control", - .functions = (const struct gl_function[]) { - DEF_FN_NAME(SwapInterval, "wglSwapIntervalEXT"), - {0}, - }, - }, - { - .extension = "GLX_SGI_video_sync", - .functions = (const struct gl_function[]) { - DEF_FN_NAME(GetVideoSync, "glXGetVideoSyncSGI"), - DEF_FN_NAME(WaitVideoSync, "glXWaitVideoSyncSGI"), - {0}, - }, - }, - // For gl_hwdec_vdpau.c - // http://www.opengl.org/registry/specs/NV/vdpau_interop.txt - { - .extension = "GL_NV_vdpau_interop", - .provides = MPGL_CAP_VDPAU, - .functions = (const struct gl_function[]) { - // (only functions needed by us) - DEF_FN(VDPAUInitNV), - DEF_FN(VDPAUFiniNV), - DEF_FN(VDPAURegisterOutputSurfaceNV), - DEF_FN(VDPAUUnregisterSurfaceNV), - DEF_FN(VDPAUSurfaceAccessNV), - DEF_FN(VDPAUMapSurfacesNV), - DEF_FN(VDPAUUnmapSurfacesNV), - {0} - }, - }, - // Apple Packed YUV Formats - // For gl_hwdec_vda.c - // http://www.opengl.org/registry/specs/APPLE/rgb_422.txt - { - .extension = "GL_APPLE_rgb_422", - .provides = MPGL_CAP_APPLE_RGB_422, - }, - { - .ver_core = 430, - .extension = "GL_ARB_debug_output", - .provides = MPGL_CAP_DEBUG, - .functions = (const struct gl_function[]) { - // (only functions needed by us) - DEF_FN(DebugMessageCallback), - {0} - }, - }, - // These don't exist - they are for the sake of mpv internals, and libmpv - // interaction (see libmpv/opengl_cb.h). - { - .extension = "GL_MP_D3D_interfaces", - .functions = (const struct gl_function[]) { - DEF_FN(MPGetD3DInterface), - {0} - }, - }, -}; - -#undef FN_OFFS -#undef DEF_FN_HARD -#undef DEF_FN -#undef DEF_FN_NAME - - -// Fill the GL struct with function pointers and extensions from the current -// GL context. Called by the backend. -// getProcAddress: function to resolve function names, may be NULL -// ext2: an extra extension string -// log: used to output messages -// Note: if you create a CONTEXT_FORWARD_COMPATIBLE_BIT_ARB with OpenGL 3.0, -// you must append "GL_ARB_compatibility" to ext2. -void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n), - void *fn_ctx, const char *ext2, struct mp_log *log) -{ - talloc_free_children(gl); - *gl = (GL) { - .extensions = talloc_strdup(gl, ext2 ? ext2 : ""), - }; - - gl->GetString = get_fn(fn_ctx, "glGetString"); - if (!gl->GetString) { - mp_err(log, "Can't load OpenGL functions.\n"); - goto error; - } - - int major = 0, minor = 0; - const char *version_string = gl->GetString(GL_VERSION); - if (!version_string) - goto error; - mp_verbose(log, "GL_VERSION='%s'\n", version_string); - if (strncmp(version_string, "OpenGL ES ", 10) == 0) { - version_string += 10; - gl->es = 100; - } - if (sscanf(version_string, "%d.%d", &major, &minor) < 2) - goto error; - gl->version = MPGL_VER(major, minor); - mp_verbose(log, "Detected %s %d.%d.\n", gl->es ? "GLES" : "desktop OpenGL", - major, minor); - - if (gl->es) { - gl->es = gl->version; - gl->version = 0; - if (gl->es < 200) { - mp_fatal(log, "At least GLESv2 required.\n"); - goto error; - } - } - - mp_verbose(log, "GL_VENDOR='%s'\n", gl->GetString(GL_VENDOR)); - mp_verbose(log, "GL_RENDERER='%s'\n", gl->GetString(GL_RENDERER)); - const char *shader = gl->GetString(GL_SHADING_LANGUAGE_VERSION); - if (shader) - mp_verbose(log, "GL_SHADING_LANGUAGE_VERSION='%s'\n", shader); - - if (gl->version >= 300) { - gl->GetStringi = get_fn(fn_ctx, "glGetStringi"); - gl->GetIntegerv = get_fn(fn_ctx, "glGetIntegerv"); - - if (!(gl->GetStringi && gl->GetIntegerv)) - goto error; - - GLint exts; - gl->GetIntegerv(GL_NUM_EXTENSIONS, &exts); - for (int n = 0; n < exts; n++) { - const char *ext = gl->GetStringi(GL_EXTENSIONS, n); - gl->extensions = talloc_asprintf_append(gl->extensions, " %s", ext); - } - - } else { - const char *ext = (char*)gl->GetString(GL_EXTENSIONS); - gl->extensions = talloc_asprintf_append(gl->extensions, " %s", ext); - } - - mp_dbg(log, "Combined OpenGL extensions string:\n%s\n", gl->extensions); - - for (int n = 0; n < MP_ARRAY_SIZE(gl_functions); 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. - - bool exists = false, must_exist = false; - if (ver_core) - must_exist = version >= ver_core; - - if (section->extension && check_ext(gl, section->extension)) - exists = true; - - exists |= must_exist; - if (!exists) - continue; - - void *loaded[MAX_FN_COUNT] = {0}; - bool all_loaded = true; - const struct gl_function *fnlist = section->functions; - - for (int i = 0; fnlist && fnlist[i].name; i++) { - const struct gl_function *fn = &fnlist[i]; - void *ptr = get_fn(fn_ctx, fn->name); - if (!ptr) { - all_loaded = false; - mp_warn(log, "Required function '%s' not " - "found for %s OpenGL %d.%d.\n", fn->name, - section->extension ? section->extension : "builtin", - MPGL_VER_GET_MAJOR(ver_core), - MPGL_VER_GET_MINOR(ver_core)); - if (must_exist) - goto error; - break; - } - assert(i < MAX_FN_COUNT); - loaded[i] = ptr; - } - - if (all_loaded) { - gl->mpgl_caps |= section->provides; - for (int i = 0; fnlist && fnlist[i].name; i++) { - const struct gl_function *fn = &fnlist[i]; - void **funcptr = (void**)(((char*)gl) + fn->offset); - if (loaded[i]) -