diff options
author | wm4 <wm4@nowhere> | 2012-10-16 07:30:30 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2012-10-16 07:30:30 +0200 |
commit | 4e89851aa128a614f59ff4885af384a266cb24e6 (patch) | |
tree | c6ab9f34ef3e9c1d58f8ec837b93e249e79bdcf6 /libvo/gl_common.c | |
parent | f45eab6faea05834c1337175dbe51437707b8d7e (diff) | |
parent | 6557f206efeb4569a42f1e4810172bc97fd64619 (diff) | |
download | mpv-4e89851aa128a614f59ff4885af384a266cb24e6.tar.bz2 mpv-4e89851aa128a614f59ff4885af384a266cb24e6.tar.xz |
Merge branch 'master' into osd_changes
Conflicts:
Makefile
command.c
libvo/gl_common.c
libvo/vo_corevideo.m
libvo/vo_opengl.c
libvo/vo_opengl_old.c
libvo/vo_opengl_shaders.glsl
sub/ass_mp.c
sub/osd_libass.c
sub/sd_ass.c
Diffstat (limited to 'libvo/gl_common.c')
-rw-r--r-- | libvo/gl_common.c | 1204 |
1 files changed, 686 insertions, 518 deletions
diff --git a/libvo/gl_common.c b/libvo/gl_common.c index 4bffc1521f..3031dc5967 100644 --- a/libvo/gl_common.c +++ b/libvo/gl_common.c @@ -38,8 +38,8 @@ #include <string.h> #include <ctype.h> #include <stdbool.h> -#include <assert.h> #include <math.h> +#include <assert.h> #include "talloc.h" #include "gl_common.h" #include "csputils.h" @@ -241,6 +241,48 @@ int glFindFormat(uint32_t fmt, int have_texture_rg, int *bpp, GLint *gl_texfmt, return supported; } +struct feature { + int id; + const char *name; +}; + +static const struct feature features[] = { + {MPGL_CAP_GL, "Basic OpenGL"}, + {MPGL_CAP_GL_LEGACY, "Legacy OpenGL"}, + {MPGL_CAP_GL2, "OpenGL 2.0"}, + {MPGL_CAP_GL21, "OpenGL 2.1"}, + {MPGL_CAP_GL3, "OpenGL 3.0"}, + {MPGL_CAP_FB, "Framebuffers"}, + {MPGL_CAP_VAO, "VAOs"}, + {MPGL_CAP_SRGB_TEX, "sRGB textures"}, + {MPGL_CAP_SRGB_FB, "sRGB framebuffers"}, + {MPGL_CAP_FLOAT_TEX, "Float textures"}, + {MPGL_CAP_TEX_RG, "RG textures"}, + {MPGL_CAP_NO_SW, "NO_SW"}, + {0}, +}; + +static void list_features(int set, int msgl, bool invert) +{ + for (const struct feature *f = &features[0]; f->id; f++) { + if (invert == !(f->id & set)) + mp_msg(MSGT_VO, msgl, " [%s]", f->name); + } + mp_msg(MSGT_VO, msgl, "\n"); +} + +// 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; +} + #ifdef HAVE_LIBDL #include <dlfcn.h> #endif @@ -262,235 +304,421 @@ static void *getdladdr(const char *s) return ret; } -typedef struct { - ptrdiff_t offset; // offset to the function pointer in struct GL - const char *extstr; - const char *funcnames[7]; +#define FN_OFFS(name) offsetof(GL, name) + +// Define the function with a "hard" reference to the function as fallback. +// (This requires linking with a compatible OpenGL library.) +#define DEF_FN_HARD(name) {FN_OFFS(name), {"gl" # name}, gl ## name} + +#define DEF_FN(name) {FN_OFFS(name), {"gl" # name}} +#define DEF_FN_NAMES(name, ...) {FN_OFFS(name), {__VA_ARGS__}} + +struct gl_function { + ptrdiff_t offset; + char *funcnames[7]; void *fallback; - bool is_gl3; -} extfunc_desc_t; - -#define DEF_FUNC_DESC(name) \ - {offsetof(GL, name), NULL, {"gl" # name}, gl ## name} -#define DEF_EXT_FUNCS(...) __VA_ARGS__ -#define DEF_EXT_DESC(name, ext, funcnames) \ - {offsetof(GL, name), ext, {DEF_EXT_FUNCS funcnames}} -// These are mostly handled the same, but needed because at least the MESA -// headers don't define any function prototypes for these. -#define DEF_GL3_DESC(name) \ - {offsetof(GL, name), NULL, {"gl" # name}, NULL, .is_gl3 = true} - -static const extfunc_desc_t extfuncs[] = { - // these aren't extension functions but we query them anyway to allow - // different "backends" with one binary - DEF_FUNC_DESC(Viewport), - DEF_FUNC_DESC(Clear), - DEF_FUNC_DESC(GenTextures), - DEF_FUNC_DESC(DeleteTextures), - DEF_FUNC_DESC(TexEnvi), - DEF_FUNC_DESC(ClearColor), - DEF_FUNC_DESC(Enable), - DEF_FUNC_DESC(Disable), - DEF_FUNC_DESC(DrawBuffer), - DEF_FUNC_DESC(DepthMask), - DEF_FUNC_DESC(BlendFunc), - DEF_FUNC_DESC(Flush), - DEF_FUNC_DESC(Finish), - DEF_FUNC_DESC(PixelStorei), - DEF_FUNC_DESC(TexImage1D), - DEF_FUNC_DESC(TexImage2D), - DEF_FUNC_DESC(TexSubImage2D), - DEF_FUNC_DESC(GetTexImage), - DEF_FUNC_DESC(TexParameteri), - DEF_FUNC_DESC(TexParameterf), - DEF_FUNC_DESC(TexParameterfv), - DEF_FUNC_DESC(GetIntegerv), - DEF_FUNC_DESC(GetBooleanv), - DEF_FUNC_DESC(ColorMask), - DEF_FUNC_DESC(ReadPixels), - DEF_FUNC_DESC(ReadBuffer), - DEF_FUNC_DESC(DrawArrays), - DEF_FUNC_DESC(GetString), - DEF_FUNC_DESC(GetError), - - // legacy GL functions (1.x - 2.x) - DEF_FUNC_DESC(Begin), - DEF_FUNC_DESC(End), - DEF_FUNC_DESC(MatrixMode), - DEF_FUNC_DESC(LoadIdentity), - DEF_FUNC_DESC(Translated), - DEF_FUNC_DESC(Scaled), - DEF_FUNC_DESC(Ortho), - DEF_FUNC_DESC(PushMatrix), - DEF_FUNC_DESC(PopMatrix), - DEF_FUNC_DESC(GenLists), - DEF_FUNC_DESC(DeleteLists), - DEF_FUNC_DESC(NewList), - DEF_FUNC_DESC(EndList), - DEF_FUNC_DESC(CallList), - DEF_FUNC_DESC(CallLists), - DEF_FUNC_DESC(Color4ub), - DEF_FUNC_DESC(Color4f), - DEF_FUNC_DESC(TexCoord2f), - DEF_FUNC_DESC(TexCoord2fv), - DEF_FUNC_DESC(Vertex2f), - DEF_FUNC_DESC(VertexPointer), - DEF_FUNC_DESC(ColorPointer), - DEF_FUNC_DESC(TexCoordPointer), - DEF_FUNC_DESC(EnableClientState), - DEF_FUNC_DESC(DisableClientState), - - // OpenGL extension functions - DEF_EXT_DESC(GenBuffers, NULL, - ("glGenBuffers", "glGenBuffersARB")), - DEF_EXT_DESC(DeleteBuffers, NULL, - ("glDeleteBuffers", "glDeleteBuffersARB")), - DEF_EXT_DESC(BindBuffer, NULL, - ("glBindBuffer", "glBindBufferARB")), - DEF_EXT_DESC(MapBuffer, NULL, - ("glMapBuffer", "glMapBufferARB")), - DEF_EXT_DESC(UnmapBuffer, NULL, - ("glUnmapBuffer", "glUnmapBufferARB")), - DEF_EXT_DESC(BufferData, NULL, - ("glBufferData", "glBufferDataARB")), - DEF_EXT_DESC(ActiveTexture, NULL, - ("glActiveTexture", "glActiveTextureARB")), - DEF_EXT_DESC(BindTexture, NULL, - ("glBindTexture", "glBindTextureARB", "glBindTextureEXT")), - DEF_EXT_DESC(MultiTexCoord2f, NULL, - ("glMultiTexCoord2f", "glMultiTexCoord2fARB")), - DEF_EXT_DESC(GenPrograms, "_program", - ("glGenProgramsARB")), - DEF_EXT_DESC(DeletePrograms, "_program", - ("glDeleteProgramsARB")), - DEF_EXT_DESC(BindProgram, "_program", - ("glBindProgramARB")), - DEF_EXT_DESC(ProgramString, "_program", - ("glProgramStringARB")), - DEF_EXT_DESC(GetProgramivARB, "_program", - ("glGetProgramivARB")), - DEF_EXT_DESC(ProgramEnvParameter4f, "_program", - ("glProgramEnvParameter4fARB")), - DEF_EXT_DESC(SwapInterval, "_swap_control", - ("glXSwapIntervalSGI", "glXSwapInterval", "wglSwapIntervalSGI", - "wglSwapInterval", "wglSwapIntervalEXT")), - DEF_EXT_DESC(TexImage3D, NULL, - ("glTexImage3D")), - - // ancient ATI extensions - DEF_EXT_DESC(BeginFragmentShader, "ATI_fragment_shader", - ("glBeginFragmentShaderATI")), - DEF_EXT_DESC(EndFragmentShader, "ATI_fragment_shader", - ("glEndFragmentShaderATI")), - DEF_EXT_DESC(SampleMap, "ATI_fragment_shader", - ("glSampleMapATI")), - DEF_EXT_DESC(ColorFragmentOp2, "ATI_fragment_shader", - ("glColorFragmentOp2ATI")), - DEF_EXT_DESC(ColorFragmentOp3, "ATI_fragment_shader", - ("glColorFragmentOp3ATI")), - DEF_EXT_DESC(SetFragmentShaderConstant, "ATI_fragment_shader", - ("glSetFragmentShaderConstantATI")), - - // GL 3, possibly in GL 2.x as well in form of extensions - DEF_GL3_DESC(GenBuffers), - DEF_GL3_DESC(DeleteBuffers), - DEF_GL3_DESC(BindBuffer), - DEF_GL3_DESC(MapBuffer), - DEF_GL3_DESC(UnmapBuffer), - DEF_GL3_DESC(BufferData), - DEF_GL3_DESC(ActiveTexture), - DEF_GL3_DESC(BindTexture), - DEF_GL3_DESC(GenVertexArrays), - DEF_GL3_DESC(BindVertexArray), - DEF_GL3_DESC(GetAttribLocation), - DEF_GL3_DESC(EnableVertexAttribArray), - DEF_GL3_DESC(DisableVertexAttribArray), - DEF_GL3_DESC(VertexAttribPointer), - DEF_GL3_DESC(DeleteVertexArrays), - DEF_GL3_DESC(UseProgram), - DEF_GL3_DESC(GetUniformLocation), - DEF_GL3_DESC(CompileShader), - DEF_GL3_DESC(CreateProgram), - DEF_GL3_DESC(CreateShader), - DEF_GL3_DESC(ShaderSource), - DEF_GL3_DESC(LinkProgram), - DEF_GL3_DESC(AttachShader), - DEF_GL3_DESC(DeleteShader), - DEF_GL3_DESC(DeleteProgram), - DEF_GL3_DESC(GetShaderInfoLog), - DEF_GL3_DESC(GetShaderiv), - DEF_GL3_DESC(GetProgramInfoLog), - DEF_GL3_DESC(GetProgramiv), - DEF_GL3_DESC(GetStringi), - DEF_GL3_DESC(BindAttribLocation), - DEF_GL3_DESC(BindFramebuffer), - DEF_GL3_DESC(GenFramebuffers), - DEF_GL3_DESC(DeleteFramebuffers), - DEF_GL3_DESC(CheckFramebufferStatus), - DEF_GL3_DESC(FramebufferTexture2D), - DEF_GL3_DESC(Uniform1f), - DEF_GL3_DESC(Uniform3f), - DEF_GL3_DESC(Uniform4f), - DEF_GL3_DESC(Uniform1i), - DEF_GL3_DESC(UniformMatrix3fv), - DEF_GL3_DESC(UniformMatrix4x3fv), - - {-1} }; +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) + bool partial_ok; // loading only some functions is ok + struct gl_function *functions; +}; + +#define MAX_FN_COUNT 50 // max functions per gl_functions section + +struct gl_functions gl_functions[] = { + // GL functions which are always available anywhere at least since 1.1 + { + .ver_core = MPGL_VER(1, 1), + .provides = MPGL_CAP_GL, + .functions = (struct gl_function[]) { + DEF_FN_HARD(Viewport), + DEF_FN_HARD(Clear), + DEF_FN_HARD(GenTextures), + DEF_FN_HARD(DeleteTextures), + DEF_FN_HARD(TexEnvi), + DEF_FN_HARD(ClearColor), + DEF_FN_HARD(Enable), + DEF_FN_HARD(Disable), + DEF_FN_HARD(DrawBuffer), + DEF_FN_HARD(DepthMask), + DEF_FN_HARD(BlendFunc), + DEF_FN_HARD(Flush), + DEF_FN_HARD(Finish), + DEF_FN_HARD(PixelStorei), + DEF_FN_HARD(TexImage1D), + DEF_FN_HARD(TexImage2D), + DEF_FN_HARD(TexSubImage2D), + DEF_FN_HARD(GetTexImage), + DEF_FN_HARD(TexParameteri), + DEF_FN_HARD(TexParameterf), + DEF_FN_HARD(TexParameterfv), + DEF_FN_HARD(GetIntegerv), + DEF_FN_HARD(GetBooleanv), + DEF_FN_HARD(ColorMask), + DEF_FN_HARD(ReadPixels), + DEF_FN_HARD(ReadBuffer), + DEF_FN_HARD(DrawArrays), + DEF_FN_HARD(GetString), + DEF_FN_HARD(GetError), + {0} + }, + }, + // GL 2.0-3.x functions + { + .ver_core = MPGL_VER(2, 0), + .provides = MPGL_CAP_GL2, + .functions = (struct gl_function[]) { + DEF_FN(GenBuffers), + DEF_FN(DeleteBuffers), + DEF_FN(BindBuffer), + DEF_FN(MapBuffer), + DEF_FN(UnmapBuffer), + DEF_FN(BufferData), + DEF_FN(ActiveTexture), + DEF_FN(BindTexture), + DEF_FN(GetAttribLocation), + DEF_FN(EnableVertexAttribArray), + DEF_FN(DisableVertexAttribArray), + DEF_FN(VertexAttribPointer), + DEF_FN(UseProgram), + DEF_FN(GetUniformLocation), + DEF_FN(CompileShader), + DEF_FN(CreateProgram), + DEF_FN(CreateShader), + DEF_FN(ShaderSource), + DEF_FN(LinkProgram), + DEF_FN(AttachShader), + DEF_FN(DeleteShader), + DEF_FN(DeleteProgram), + DEF_FN(GetShaderInfoLog), + DEF_FN(GetShaderiv), + DEF_FN(GetProgramInfoLog), + DEF_FN(GetProgramiv), + DEF_FN(BindAttribLocation), + DEF_FN(Uniform1f), + DEF_FN(Uniform2f), + DEF_FN(Uniform3f), + DEF_FN(Uniform1i), + DEF_FN(UniformMatrix3fv), + DEF_FN(TexImage3D), + {0}, + }, + }, + // GL 2.1-3.x functions (also: GLSL 120 shaders) + { + .ver_core = MPGL_VER(2, 1), + .provides = MPGL_CAP_GL21, + .functions = (struct gl_function[]) { + DEF_FN(UniformMatrix4x3fv), + {0} + }, + }, + // GL 3.x core only functions. + { + .ver_core = MPGL_VER(3, 0), + .provides = MPGL_CAP_GL3 | MPGL_CAP_SRGB_TEX | MPGL_CAP_SRGB_FB, + .functions = (struct gl_function[]) { + DEF_FN(GetStringi), + {0} + }, + }, + // Framebuffers, extension in GL 2.x, core in GL 3.x core. + { + .ver_core = MPGL_VER(3, 0), + .extension = "GL_ARB_framebuffer_object", + .provides = MPGL_CAP_FB, + .functions = (struct gl_function[]) { + DEF_FN(BindFramebuffer), + DEF_FN(GenFramebuffers), + DEF_FN(DeleteFramebuffers), + DEF_FN(CheckFramebufferStatus), + DEF_FN(FramebufferTexture2D), + {0} + }, + }, + // Framebuffers, alternative extension name. + { + .ver_removed = MPGL_VER(3, 0), // don't touch these fn names in 3.x + .extension = "GL_EXT_framebuffer_object", + .provides = MPGL_CAP_FB, + .functions = (struct gl_function[]) { + DEF_FN_NAMES(BindFramebuffer, "glBindFramebufferEXT"), + DEF_FN_NAMES(GenFramebuffers, "glGenFramebuffersEXT"), + DEF_FN_NAMES(DeleteFramebuffers, "glDeleteFramebuffersEXT"), + DEF_FN_NAMES(CheckFramebufferStatus, "glCheckFramebufferStatusEXT"), + DEF_FN_NAMES(FramebufferTexture2D, "glFramebufferTexture2DEXT"), + {0} + }, + }, + // VAOs, extension in GL 2.x, core in GL 3.x core. + { + .ver_core = MPGL_VER(3, 0), + .extension = "GL_ARB_vertex_array_object", + .provides = MPGL_CAP_VAO, + .functions = (struct gl_function[]) { + DEF_FN(GenVertexArrays), + DEF_FN(BindVertexArray), + DEF_FN(DeleteVertexArrays), + {0} + } + }, + // sRGB textures, extension in GL 2.x, core in GL 3.x core. + { + .ver_core = MPGL_VER(3, 0), + .extension = "GL_EXT_texture_sRGB", + .provides = MPGL_CAP_SRGB_TEX, + .functions = (struct gl_function[]) {{0}}, + }, + // sRGB framebuffers, extension in GL 2.x, core in GL 3.x core. + { + .ver_core = MPGL_VER(3, 0), + .extension = "GL_EXT_framebuffer_sRGB", + .provides = MPGL_CAP_SRGB_FB, + .functions = (struct gl_function[]) {{0}}, + }, + // Float textures, extension in GL 2.x, core in GL 3.x core. + { + .ver_core = MPGL_VER(3, 0), + .extension = "GL_ARB_texture_float", + .provides = MPGL_CAP_FLOAT_TEX, + .functions = (struct gl_function[]) {{0}}, + }, + // GL_RED / GL_RG textures, extension in GL 2.x, core in GL 3.x core. + { + .ver_core = MPGL_VER(3, 0), + .extension = "GL_ARB_texture_rg", + .provides = MPGL_CAP_TEX_RG, + .functions = (struct gl_function[]) {{0}}, + }, + // Swap control, always an OS specific extension + { + .extension = "_swap_control", + .functions = (struct gl_function[]) { + DEF_FN_NAMES(SwapInterval, "glXSwapIntervalSGI", "glXSwapInterval", + "wglSwapIntervalSGI", "wglSwapInterval", + "wglSwapIntervalEXT"), + {0} + }, + }, + // GL legacy functions in GL 1.x - 2.x, removed from GL 3.x + { + .ver_core = MPGL_VER(1, 1), + .ver_removed = MPGL_VER(3, 0), + .provides = MPGL_CAP_GL_LEGACY, + .functions = (struct gl_function[]) { + DEF_FN_HARD(Begin), + DEF_FN_HARD(End), + DEF_FN_HARD(MatrixMode), + DEF_FN_HARD(LoadIdentity), + DEF_FN_HARD(Translated), + DEF_FN_HARD(Scaled), + DEF_FN_HARD(Ortho), + DEF_FN_HARD(PushMatrix), + DEF_FN_HARD(PopMatrix), + DEF_FN_HARD(GenLists), + DEF_FN_HARD(DeleteLists), + DEF_FN_HARD(NewList), + DEF_FN_HARD(EndList), + DEF_FN_HARD(CallList), + DEF_FN_HARD(CallLists), + DEF_FN_HARD(Color4ub), + DEF_FN_HARD(Color4f), + DEF_FN_HARD(TexCoord2f), + DEF_FN_HARD(TexCoord2fv), + DEF_FN_HARD(Vertex2f), + DEF_FN_HARD(VertexPointer), + DEF_FN_HARD(ColorPointer), + DEF_FN_HARD(TexCoordPointer), + DEF_FN_HARD(EnableClientState), + DEF_FN_HARD(DisableClientState), + {0} + }, + }, + // Loading of old extensions, which are later added to GL 2.0. + // NOTE: actually we should be checking the extension strings: the OpenGL + // library could provide an entry point, but not implement it. + // But the previous code didn't do that, and nobody ever complained. + { + .ver_removed = MPGL_VER(2, 1), + .partial_ok = true, + .functions = (struct gl_function[]) { + DEF_FN_NAMES(GenBuffers, "glGenBuffers", "glGenBuffersARB"), + DEF_FN_NAMES(DeleteBuffers, "glDeleteBuffers", "glDeleteBuffersARB"), + DEF_FN_NAMES(BindBuffer, "glBindBuffer", "glBindBufferARB"), + DEF_FN_NAMES(MapBuffer, "glMapBuffer", "glMapBufferARB"), + DEF_FN_NAMES(UnmapBuffer, "glUnmapBuffer", "glUnmapBufferARB"), + DEF_FN_NAMES(BufferData, "glBufferData", "glBufferDataARB"), + DEF_FN_NAMES(ActiveTexture, "glActiveTexture", "glActiveTextureARB"), + DEF_FN_NAMES(BindTexture, "glBindTexture", "glBindTextureARB", "glBindTextureEXT"), + DEF_FN_NAMES(MultiTexCoord2f, "glMultiTexCoord2f", "glMultiTexCoord2fARB"), + DEF_FN_NAMES(TexImage3D, "glTexImage3D"), + {0} + }, + }, + // Ancient ARB shaders. + { + .extension = "_program", + .ver_removed = MPGL_VER(3, 0), + .functions = (struct gl_function[]) { + DEF_FN_NAMES(GenPrograms, "glGenProgramsARB"), + DEF_FN_NAMES(DeletePrograms, "glDeleteProgramsARB"), + DEF_FN_NAMES(BindProgram, "glBindProgramARB"), + DEF_FN_NAMES(ProgramString, "glProgramStringARB"), + DEF_FN_NAMES(GetProgramivARB, "glGetProgramivARB"), + DEF_FN_NAMES(ProgramEnvParameter4f, "glProgramEnvParameter4fARB"), + {0} + }, + }, + // Ancient ATI extensions. + { + .extension = "ATI_fragment_shader", + .ver_removed = MPGL_VER(3, 0), + .functions = (struct gl_function[]) { + DEF_FN_NAMES(BeginFragmentShader, "glBeginFragmentShaderATI"), + DEF_FN_NAMES(EndFragmentShader, "glEndFragmentShaderATI"), + DEF_FN_NAMES(SampleMap, "glSampleMapATI"), + DEF_FN_NAMES(ColorFragmentOp2, "glColorFragmentOp2ATI"), + DEF_FN_NAMES(ColorFragmentOp3, "glColorFragmentOp3ATI"), + DEF_FN_NAMES(SetFragmentShaderConstant, "glSetFragmentShaderConstantATI"), + {0} + }, + }, +}; + +#undef FN_OFFS +#undef DEF_FN_HARD +#undef DEF_FN +#undef DEF_FN_NAMES + + /** * \brief find the function pointers of some useful OpenGL extensions * \param getProcAddress function to resolve function names, may be NULL * \param ext2 an extra extension string */ static void getFunctions(GL *gl, void *(*getProcAddress)(const GLubyte *), - const char *ext2, bool is_gl3) + const char *ext2, bool gl3) { - const extfunc_desc_t *dsc; - char *allexts = talloc_strdup(NULL, ext2 ? ext2 : ""); - - *gl = (GL) {0}; + talloc_free_children(gl); + *gl = (GL) { + .extensions = talloc_strdup(gl, ext2 ? ext2 : ""), + }; if (!getProcAddress) getProcAddress = (void *)getdladdr; - if (is_gl3) { + GLint major = 0, minor = 0; + if (gl3) { gl->GetStringi = getProcAddress("glGetStringi"); gl->GetIntegerv = getProcAddress("glGetIntegerv"); if (!(gl->GetStringi && gl->GetIntegerv)) return; + gl->GetIntegerv(GL_MAJOR_VERSION, &major); + gl->GetIntegerv(GL_MINOR_VERSION, &minor); + GLint exts; gl->GetIntegerv(GL_NUM_EXTENSIONS, &exts); for (int n = 0; n < exts; n++) { - allexts = talloc_asprintf_append(allexts, " %s", - gl->GetStringi(GL_EXTENSIONS, n)); + gl->extensions + = talloc_asprintf_append(gl->extensions, " %s", + gl->GetStringi(GL_EXTENSIONS, n)); } } else { gl->GetString = getProcAddress("glGetString"); if (!gl->GetString) gl->GetString = glGetString; + const char *ext = (char*)gl->GetString(GL_EXTENSIONS); - allexts = talloc_asprintf_append(allexts, " %s", ext); + gl->extensions = talloc_asprintf_append(gl->extensions, " %s", ext); + + const char *version = gl->GetString(GL_VERSION); + sscanf(version, "%d.%d", &major, &minor); } + gl->version = MPGL_VER(major, minor); + + mp_msg(MSGT_VO, MSGL_V, "[gl] Detected OpenGL %d.%d.\n", major, minor); + mp_msg(MSGT_VO, MSGL_DBG2, "[gl] Combined OpenGL extensions string:\n%s\n", + gl->extensions); - mp_msg(MSGT_VO, MSGL_DBG2, "OpenGL extensions string:\n%s\n", allexts); - for (dsc = extfuncs; dsc->offset >= 0; dsc++) { - void *ptr = NULL; - if (!dsc->extstr || strstr(allexts, dsc->extstr)) { - for (int i = 0; !ptr && dsc->funcnames[i]; i++) - ptr = getProcAddress((const GLubyte *)dsc->funcnames[i]); + for (int n = 0; n < sizeof(gl_functions) / sizeof(gl_functions[0]); n++) { + struct gl_functions *section = &gl_functions[n]; + + // With gl3=false, we could have a legacy context, where functionality + // is never removed. (E.g. the context could be at version >= 3.0, but + // legacy functions like glBegin still exist and work.) + if (gl3 && section->ver_removed && gl->version >= section->ver_removed) + continue; + + bool must_exist = section->ver_core && gl->version >= section->ver_core + && !section->partial_ok; + + if (!must_exist && section->extension && + !strstr(gl->extensions, section->extension)) + continue; + + void *loaded[MAX_FN_COUNT] = {0}; + bool all_loaded = true; + + for (int i = 0; section->functions[i].funcnames[0]; i++) { + struct gl_function *fn = §ion->functions[i]; + void *ptr = NULL; + for (int x = 0; fn->funcnames[x]; x++) { + ptr = getProcAddress((const GLubyte *)fn->funcnames[x]); + if (ptr) + break; + } + if (!ptr) + ptr = fn->fallback; + if (!ptr) { + all_loaded = false; + if (must_exist) { + // Either we or the driver are not conforming to OpenGL. + mp_msg(MSGT_VO, MSGL_ERR, "[gl] Required function '%s' not " + "found.\n", fn->funcnames[0]); + talloc_free_children(gl); + *gl = (GL) {0}; + return; + } + } + assert(i < MAX_FN_COUNT); + loaded[i] = ptr; + } + + if (all_loaded || section->partial_ok) { + gl->mpgl_caps |= section->provides; + for (int i = 0; section->functions[i].funcnames[0]; i++) { + struct gl_function *fn = §ion->functions[i]; + void **funcptr = (void**)(((char*)gl) + fn->offset); + if (loaded[i]) + *funcptr = loaded[i]; + } } - if (!ptr) - ptr = dsc->fallback; - if (!ptr && !dsc->extstr && (!dsc->is_gl3 || is_gl3)) - mp_msg(MSGT_VO, MSGL_WARN, "[gl] OpenGL function not found: %s\n", - dsc->funcnames[0]); - void **funcptr = (void**)(((char*)gl) + dsc->offset); - *funcptr = ptr; - } - talloc_free(allexts); + } + + gl->glsl_version = 0; + if (gl->version >= MPGL_VER(2, 0)) + gl->glsl_version = 110; + if (gl->version >= MPGL_VER(2, 1)) + gl->glsl_version = 120; + if (gl->version >= MPGL_VER(3, 0)) + 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 >= MPGL_VER(3, 2)) + gl->glsl_version = 150; + + if (!is_software_gl(gl)) + gl->mpgl_caps |= MPGL_CAP_NO_SW; + + mp_msg(MSGT_VO, MSGL_V, "[gl] Detected OpenGL features:"); + list_features(gl->mpgl_caps, MSGL_V, false); } /** @@ -1739,35 +1967,38 @@ void glDrawTex(GL *gl, GLfloat x, GLfloat y, GLfloat w, GLfloat h, #ifdef CONFIG_GL_COCOA #include "cocoa_common.h" -static int create_window_cocoa(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags) + +static bool create_window_cocoa(struct MPGLContext *ctx, uint32_t d_width, + uint32_t d_height, uint32_t flags, bool gl3) { - if (vo_cocoa_create_window(ctx->vo, d_width, d_height, flags, 0) == 0) { - return SET_WINDOW_OK; - } else { - return SET_WINDOW_FAILED; + int rv = vo_cocoa_create_window(ctx->vo, d_width, d_height, flags, gl3); + if (rv != 0) + return false; + + getFunctions(ctx->gl, (void *)vo_cocoa_glgetaddr, NULL, gl3); + + if (gl3) { + ctx->depth_r = vo_cocoa_cgl_color_size(); + ctx->depth_g = vo_cocoa_cgl_color_size(); + ctx->depth_b = vo_cocoa_cgl_color_size(); } + + if (!ctx->gl->SwapInterval) + ctx->gl->SwapInterval = vo_cocoa_swap_interval; + + return true; } -static int create_window_cocoa_gl3(struct MPGLContext *ctx, int gl_flags, - int gl_version, uint32_t d_width, - uint32_t d_height, uint32_t flags) +static bool create_window_cocoa_old(struct MPGLContext *ctx, uint32_t d_width, + uint32_t d_height, uint32_t flags) { - int rv = vo_cocoa_create_window(ctx->vo, d_width, d_height, flags, 1); - getFunctions(ctx->gl, (void *)vo_cocoa_glgetaddr, NULL, true); - ctx->depth_r = vo_cocoa_cgl_color_size(); - ctx->depth_g = vo_cocoa_cgl_color_size(); - ctx->depth_b = vo_cocoa_cgl_color_size(); - return rv; + return create_window_cocoa(ctx, d_width, d_height, flags, false); } -static int setGlWindow_cocoa(MPGLContext *ctx) +static bool create_window_cocoa_gl3(struct MPGLContext *ctx, uint32_t d_width, + uint32_t d_height, uint32_t flags) { - vo_cocoa_change_attributes(ctx->vo); - getFunctions(ctx->gl, (void *)vo_cocoa_glgetaddr, NULL, false); - if (!ctx->gl->SwapInterval) - ctx->gl->SwapInterval = vo_cocoa_swap_interval; - return SET_WINDOW_OK; + return create_window_cocoa(ctx, d_width, d_height, flags, true); } static void releaseGlContext_cocoa(MPGLContext *ctx) @@ -1800,24 +2031,9 @@ static void cocoa_fullscreen(struct vo *vo) #include "w32_common.h" struct w32_context { - int vinfo; HGLRC context; }; -static int create_window_w32(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags) -{ - if (!vo_w32_config(ctx->vo, d_width, d_height, flags)) - return -1; - return 0; -} - -/** - * \brief little helper since wglGetProcAddress definition does not fit our - * getProcAddress - * \param procName name of function to look up - * \return function pointer returned by wglGetProcAddress - */ static void *w32gpa(const GLubyte *procName) { HMODULE oglmod; @@ -1828,17 +2044,59 @@ static void *w32gpa(const GLubyte *procName) return GetProcAddress(oglmod, procName); } -static int create_window_w32_gl3(struct MPGLContext *ctx, int gl_flags, - int gl_version, uint32_t d_width, - uint32_t d_height, uint32_t flags) { +static bool create_window_w32_old(struct MPGLContext *ctx, uint32_t d_width, + uint32_t d_height, uint32_t flags) +{ + GL *gl = ctx->gl; + + if (!vo_w32_config(ctx->vo, d_width, d_height, flags)) + return false; + + struct w32_context *w32_ctx = ctx->priv; + HGLRC *context = &w32_ctx->context; + + if (*context) { + gl->Finish(); // supposedly to prevent flickering + return true; + } + + HWND win = ctx->vo->w32->window; + HDC windc = vo_w32_get_dc(ctx->vo, win); + bool res = false; + + HGLRC new_context = wglCreateContext(windc); + if (!new_context) { + mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GL context!\n"); + goto out; + } + + if (!wglMakeCurrent(windc, new_context)) { + mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GL context!\n"); + wglDeleteContext(new_context); + goto out; + } + + *context = new_context; + + getFunctions(ctx->gl, w32gpa, NULL, false); + res = true; + +out: + vo_w32_release_dc(ctx->vo, win, windc); + return res; +} + +static bool create_window_w32_gl3(struct MPGLContext *ctx, uint32_t d_width, + uint32_t d_height, uint32_t flags) +{ if (!vo_w32_config(ctx->vo, d_width, d_height, flags)) - return -1; + return false; struct w32_context *w32_ctx = ctx->priv; HGLRC *context = &w32_ctx->context; if (*context) // reuse existing context - return 0; // not reusing it breaks gl3! + return true; // not reusing it breaks gl3! HWND win = ctx->vo->w32->window; HDC windc = vo_w32_get_dc(ctx->vo, win); @@ -1847,7 +2105,7 @@ static int create_window_w32_gl3(struct MPGLContext *ctx, int gl_flags, new_context = wglCreateContext(windc); if (!new_context) { mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GL context!\n"); - return -1; + return false; } // set context @@ -1873,6 +2131,7 @@ static int create_window_w32_gl3(struct MPGLContext *ctx, int gl_flags, if (!wglCreateContextAttribsARB) goto unsupported; + int gl_version = ctx->requested_gl_version; int attribs[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, MPGL_VER_GET_MAJOR(gl_version), WGL_CONTEXT_MINOR_VERSION_ARB, MPGL_VER_GET_MINOR(gl_version), @@ -1902,7 +2161,7 @@ static int create_window_w32_gl3(struct MPGLContext *ctx, int gl_flags, if (!wglMakeCurrent(windc, *context)) { mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GL3 context!\n"); wglDeleteContext(*context); - return -1; + return false; } /* update function pointers */ @@ -1916,86 +2175,20 @@ static int create_window_w32_gl3(struct MPGLContext *ctx, int gl_flags, ctx->depth_b = pfd.cBlueBits; } - return 0; + return true; unsupported: mp_msg(MSGT_VO, MSGL_ERR, "[gl] The current OpenGL implementation does" " not support OpenGL 3.x \n"); out: wglDeleteContext(new_context); - return -1; -} - -static int setGlWindow_w32(MPGLContext *ctx) -{ - HWND win = ctx->vo->w32->window; - struct w32_context *w32_ctx = ctx->priv; - int *vinfo = &w32_ctx->vinfo; - HGLRC *context = &w32_ctx->context; - int new_vinfo; - HDC windc = vo_w32_get_dc(ctx->vo, win); - HGLRC new_context = 0; - int keep_context = 0; - int res = SET_WINDOW_FAILED; - GL *gl = ctx->gl; - - // should only be needed when keeping context, but not doing glFinish - // can cause flickering even when we do not keep it. - if (*context) - gl->Finish(); - new_vinfo = GetPixelFormat(windc); - if (*context && *vinfo && new_vinfo && *vinfo == new_vinfo) { - // we can keep the wglContext - new_context = *context; - keep_context = 1; - } else { - // create a context - new_context = wglCreateContext(windc); - if (!new_context) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GL context!\n"); - goto out; - } - } - - // set context - if (!wglMakeCurrent(windc, new_context)) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GL context!\n"); - if (!keep_context) - wglDeleteContext(new_context); - goto out; - } - - // set new values - { - RECT rect; - GetClientRect(win, &rect); - ctx->vo->dwidth = rect.right; - ctx->vo->dheight = rect.bottom; - } - if (!keep_context) { - if (*context) - wglDeleteContext(*context); - *context = new_context; - *vinfo = new_vinfo; - - getFunctions(ctx->gl, w32gpa, NULL, false); - - // and inform that reinit is neccessary - res = SET_WINDOW_REINIT; - } else - res = SET_WINDOW_OK; - -out: - vo_w32_release_dc(ctx->vo, win, windc); - return res; + return false; } static void releaseGlContext_w32(MPGLContext *ctx) { struct w32_context *w32_ctx = ctx->priv; - int *vinfo = &w32_ctx->vinfo; HGLRC *context = &w32_ctx->context; - *vinfo = 0; if (*context) { wglMakeCurrent(0, 0); wglDeleteContext(*context); @@ -2019,155 +2212,10 @@ static void swapGlBuffers_w32(MPGLContext *ctx) struct glx_context { XVisualInfo *vinfo; GLXContext context; + GLXFBConfig fbc; }; -static int create_window_x11(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags) -{ - struct vo *vo = ctx->vo; - - |