summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/vo.rst18
-rw-r--r--libvo/gl_common.c1128
-rw-r--r--libvo/gl_common.h90
-rw-r--r--libvo/video_out.h1
-rw-r--r--libvo/vo_corevideo.m9
-rw-r--r--libvo/vo_gl.c55
-rw-r--r--libvo/vo_gl3.c221
-rw-r--r--libvo/vo_gl3_shaders.glsl94
8 files changed, 966 insertions, 650 deletions
diff --git a/DOCS/man/en/vo.rst b/DOCS/man/en/vo.rst
index 0ba7fe8b9f..34b547c4bc 100644
--- a/DOCS/man/en/vo.rst
+++ b/DOCS/man/en/vo.rst
@@ -413,6 +413,9 @@ gl
enabled). This option is for testing; to disable the OSD use
``--osdlevel=0`` instead.
+ sw
+ Continue even if a software renderer is detected.
+
backend=<sys>
auto
auto-select (default)
@@ -424,9 +427,7 @@ gl
X11/GLX
gl3
- OpenGL video output driver, extended version. The requires an OpenGL 3
- capable graphics driver. (Note: this is only because of developer pedantry.
- The dependency on actual OpenGL 3 features is rather low.)
+ OpenGL video output driver, extended version.
It supports extended scaling methods, dithering and color management.
It tries to use sane defaults for good quality output.
@@ -434,6 +435,8 @@ gl3
Note that some cheaper LCDs do dithering that gravely interferes with
vo_gl3's dithering. Disabling dithering with ``dither-depth=-1`` helps.
+ Some features are available with OpenGL 3 capable graphics drivers only.
+
lscale=<filter>
Set the scaling filter. Possible choices:
bilinear
@@ -579,6 +582,9 @@ gl3
glfinish
Call glFinish() before swapping buffers
+ sw
+ Continue even if a software renderer is detected.
+
backend=<sys>
auto
auto-select (default)
@@ -600,16 +606,12 @@ gl3
fbo-format=<fmt>
Selects the internal format of any FBO textures used.
- fmt can be one of: rgb, rgba, rgb8, rgb16, rgb16f, rgb32f
+ fmt can be one of: rgb, rgba, rgb8, rgb10, rgb16, rgb16f, rgb32f
Default: rgb16.
gamma
Always enable gamma control. (Disables delayed enabling.)
- force-gl2
- Create a legacy GL context. This will randomly malfunction
- if the proper extensions are not supported.
-
icc-profile=<file>
Load an ICC profile and use it to transform linear RGB to
screen output. Needs LittleCMS2 support compiled in.
diff --git a/libvo/gl_common.c b/libvo/gl_common.c
index 1ad7017e10..1593f07c50 100644
--- a/libvo/gl_common.c
+++ b/libvo/gl_common.c
@@ -39,6 +39,7 @@
#include <ctype.h>
#include <stdbool.h>
#include <math.h>
+#include <assert.h>
#include "talloc.h"
#include "gl_common.h"
#include "csputils.h"
@@ -238,6 +239,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
@@ -259,234 +302,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(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);
+
+ 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;
- 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]);
+ 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 = &section->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 = &section->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);
}
/**
@@ -1710,35 +1940,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)
@@ -1771,24 +2004,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;
@@ -1799,17 +2017,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 -1;
+ 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 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);
@@ -1818,7 +2078,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
@@ -1844,6 +2104,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),
@@ -1873,7 +2134,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 */
@@ -1887,86 +2148,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