aboutsummaryrefslogtreecommitdiffhomepage
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
- 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);
@@ -1992,10 +2187,35 @@ struct glx_context {
GLXContext context;
};
-static int create_window_x11(struct MPGLContext *ctx, uint32_t d_width,
- uint32_t d_height, uint32_t flags)
+// Returns the XVisualInfo associated with Window win.
+static XVisualInfo *getWindowVisualInfo(MPGLContext *ctx, Window win)
{
+ XWindowAttributes xw_attr;
+ XVisualInfo vinfo_template;
+ int tmp;
+ XGetWindowAttributes(ctx->vo->x11->display, win, &xw_attr);
+ vinfo_template.visualid = XVisualIDFromVisual(xw_attr.visual);
+ return XGetVisualInfo(ctx->vo->x11->display, VisualIDMask, &vinfo_template, &tmp);
+}
+
+static bool create_window_x11_old(struct MPGLContext *ctx, uint32_t d_width,
+ uint32_t d_height, uint32_t flags)
+{
+ struct glx_context *glx_ctx = ctx->priv;
+ Display *display = ctx->vo->x11->display;
struct vo *vo = ctx->vo;
+ GL *gl = ctx->gl;
+
+ if (glx_ctx->context) {
+ // GL context and window already exist.
+ // Only update window geometry etc.
+ Colormap colormap = XCreateColormap(display, vo->x11->rootwin,
+ glx_ctx->vinfo->visual, AllocNone);
+ vo_x11_create_vo_window(vo, glx_ctx->vinfo, vo->dx, vo->dy, d_width,
+ d_height, flags, colormap, "gl");
+ XFreeColormap(display, colormap);
+ return true;
+ }
static int default_glx_attribs[] = {
GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
@@ -2007,135 +2227,69 @@ static int create_window_x11(struct MPGLContext *ctx, uint32_t d_width,
};
XVisualInfo *vinfo = NULL;
if (flags & VOFLAG_STEREO) {
- vinfo = glXChooseVisual(vo->x11->display, vo->x11->screen,
- stereo_glx_attribs);
+ vinfo = glXChooseVisual(display, vo->x11->screen, stereo_glx_attribs);
if (!vinfo)
mp_msg(MSGT_VO, MSGL_ERR, "[gl] Could not find a stereo visual,"
" 3D will probably not work!\n");
}
if (!vinfo)
- vinfo = glXChooseVisual(vo->x11->display, vo->x11->screen,
- default_glx_attribs);
+ vinfo = glXChooseVisual(display, vo->x11->screen, default_glx_attribs);
if (!vinfo) {
mp_msg(MSGT_VO, MSGL_ERR, "[gl] no GLX support present\n");
- return -1;
+ return false;
}
mp_msg(MSGT_VO, MSGL_V, "[gl] GLX chose visual with ID 0x%x\n",
(int)vinfo->visualid);
- Colormap colormap = XCreateColormap(vo->x11->display, vo->x11->rootwin,
+ Colormap colormap = XCreateColormap(display, vo->x11->rootwin,
vinfo->visual, AllocNone);
vo_x11_create_vo_window(vo, vinfo, vo->dx, vo->dy, d_width, d_height,
flags, colormap, "gl");
- return 0;
-}
-
-/**
- * \brief Returns the XVisualInfo associated with Window win.
- * \param win Window whose XVisualInfo is returne.
- * \return XVisualInfo of the window. Caller must use XFree to free it.
- */
-static XVisualInfo *getWindowVisualInfo(MPGLContext *ctx, Window win)
-{
- XWindowAttributes xw_attr;
- XVisualInfo vinfo_template;
- int tmp;
- XGetWindowAttributes(ctx->vo->x11->display, win, &xw_attr);
- vinfo_template.visualid = XVisualIDFromVisual(xw_attr.visual);
- return XGetVisualInfo(ctx->vo->x11->display, VisualIDMask, &vinfo_template, &tmp);
-}
-
-/**
- * \brief Changes the window in which video is displayed.
- * If possible only transfers the context to the new window, otherwise
- * creates a new one, which must be initialized by the caller.
- * \param vinfo Currently used visual.
- * \param context Currently used context.
- * \param win window that should be used for drawing.
- * \return one of SET_WINDOW_FAILED, SET_WINDOW_OK or SET_WINDOW_REINIT.
- * In case of SET_WINDOW_REINIT the context could not be transfered
- * and the caller must initialize it correctly.
- * \ingroup glcontext
- */
-static int setGlWindow_x11(MPGLContext *ctx)
-{
- struct glx_context *glx_context = ctx->priv;
- XVisualInfo **vinfo = &glx_context->vinfo;
- GLXContext *context = &glx_context->context;
- Display *display = ctx->vo->x11->display;
- Window win = ctx->vo->x11->window;
- XVisualInfo *new_vinfo;
- GLXContext new_context = NULL;
- int keep_context = 0;
- 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 = getWindowVisualInfo(ctx, win);
- if (*context && *vinfo && new_vinfo &&
- (*vinfo)->visualid == new_vinfo->visualid) {
- // we can keep the GLXContext
- new_context = *context;
+ XVisualInfo *new_vinfo = getWindowVisualInfo(ctx, ctx->vo->x11->window);
+ GLXContext new_context = glXCreateContext(display, new_vinfo, NULL, True);
+ if (!new_context) {
+ mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GLX context!\n");
XFree(new_vinfo);
- new_vinfo = *vinfo;
- keep_context = 1;
- } else {
- // create a context
- new_context = glXCreateContext(display, new_vinfo, NULL, True);
- if (!new_context) {
- mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GLX context!\n");
- XFree(new_vinfo);
- return SET_WINDOW_FAILED;
- }
+ return false;
}
- // set context
if (!glXMakeCurrent(display, ctx->vo->x11->window, new_context)) {
mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GLX context!\n");
- if (!keep_context) {
- glXDestroyContext(display, new_context);
- XFree(new_vinfo);
- }
- return SET_WINDOW_FAILED;
- }
-
- // set new values
- ctx->vo->x11->window = win;
- vo_x11_update_geometry(ctx->vo, 1);
- if (!keep_context) {
- void *(*getProcAddress)(const GLubyte *);
- if (*context)
- glXDestroyContext(display, *context);
- *context = new_context;
- if (*vinfo)
- XFree(*vinfo);
- *vinfo = new_vinfo;
- getProcAddress = getdladdr("glXGetProcAddress");
- if (!getProcAddress)
- getProcAddress = getdladdr("glXGetProcAddressARB");
-
- const char *glxstr = "";
- const char *(*glXExtStr)(Display *, int)
- = getdladdr("glXQueryExtensionsString");
- if (glXExtStr)
- glxstr = glXExtStr(display, ctx->vo->x11->screen);
-
- getFunctions(gl, getProcAddress, glxstr, false);
- if (!gl->GenPrograms && gl->GetString &&
- getProcAddress &&
- strstr(gl->GetString(GL_EXTENSIONS), "GL_ARB_vertex_program")) {
- mp_msg(MSGT_VO, MSGL_WARN,
- "Broken glXGetProcAddress detected, trying workaround\n");
- getFunctions(gl, NULL, glxstr, false);
- }
+ glXDestroyContext(display, new_context);
+ XFree(new_vinfo);
+ return false;
+ }
+
+ void *(*getProcAddress)(const GLubyte *);
+ getProcAddress = getdladdr("glXGetProcAddress");
+ if (!getProcAddress)
+ getProcAddress = getdladdr("glXGetProcAddressARB");
+
+ const char *glxstr = "";
+ const char *(*glXExtStr)(Display *, int)
+ = getdladdr("glXQueryExtensionsString");
+ if (glXExtStr)
+ glxstr = glXExtStr(display, ctx->vo->x11->screen);
- // and inform that reinit is neccessary
- return SET_WINDOW_REINIT;
+ getFunctions(gl, getProcAddress, glxstr, false);
+ if (!gl->GenPrograms && gl->GetString &&
+ gl->version < MPGL_VER(3, 0) &&
+ getProcAddress &&
+ strstr(gl->GetString(GL_EXTENSIONS), "GL_ARB_vertex_program"))
+ {
+ mp_msg(MSGT_VO, MSGL_WARN,
+ "Broken glXGetProcAddress detected, trying workaround\n");
+ getFunctions(gl, NULL, glxstr, false);
}
- return SET_WINDOW_OK;
+
+ glx_ctx->context = new_context;
+ glx_ctx->vinfo = new_vinfo;
+
+ if (!glXIsDirect(vo->x11->display, new_context))
+ ctx->gl->mpgl_caps &= ~MPGL_CAP_NO_SW;
+
+ return true;
}
// The GL3 initialization code roughly follows/copies from:
@@ -2161,9 +2315,8 @@ static GLXFBConfig select_fb_config(struct vo *vo, const int *attribs)
typedef GLXContext (*glXCreateContextAttribsARBProc)
(Display*, GLXFBConfig, GLXContext, Bool, const int*);
-static int create_window_x11_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_x11_gl3(struct MPGLContext *ctx, uint32_t d_width,
+ uint32_t d_height, uint32_t flags)
{
struct vo *vo = ctx->vo;
struct glx_context *glx_ctx = ctx->priv;
@@ -2176,7 +2329,7 @@ static int create_window_x11_gl3(struct MPGLContext *ctx, int gl_flags,
vo_x11_create_vo_window(vo, glx_ctx->vinfo, vo->dx, vo->dy, d_width,
d_height, flags, colormap, "gl");
XFreeColormap(vo->x11->display, colormap);
- return SET_WINDOW_OK;
+ return true;
}
int glx_major, glx_minor;
@@ -2186,7 +2339,7 @@ static int create_window_x11_gl3(struct MPGLContext *ctx, int gl_flags,
(MPGL_VER(glx_major, glx_minor) < MPGL_VER(1, 3)))
{
mp_msg(MSGT_VO, MSGL_ERR, "[gl] GLX version older than 1.3.\n");
- return SET_WINDOW_FAILED;
+ return false;
}
const int glx_attribs_stereo_value_idx = 1; // index of GLX_STEREO + 1
@@ -2213,7 +2366,7 @@ static int create_window_x11_gl3(struct MPGLContext *ctx, int gl_flags,
fbc = select_fb_config(vo, glx_attribs);
if (!fbc) {
mp_msg(MSGT_VO, MSGL_ERR, "[gl] no GLX support present\n");
- return SET_WINDOW_FAILED;
+ return false;
}
glXGetFBConfigAttrib(vo->x11->display, fbc, GLX_RED_SIZE, &ctx->depth_r);
@@ -2242,15 +2395,16 @@ static int create_window_x11_gl3(struct MPGLContext *ctx, int gl_flags,
if (!(have_ctx_ext && glXCreateContextAttribsARB)) {
XFree(vinfo);
- return SET_WINDOW_FAILED;
+ return false;
}
+ int gl_version = ctx->requested_gl_version;
int context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, MPGL_VER_GET_MAJOR(gl_version),
GLX_CONTEXT_MINOR_VERSION_ARB, MPGL_VER_GET_MINOR(gl_version),
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
- | (gl_flags & MPGLFLAG_DEBUG ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
+ | (flags & VOFLAG_GL_DEBUG ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
None
};
GLXContext context = glXCreateContextAttribsARB(vo->x11->display, fbc, 0,
@@ -2258,7 +2412,7 @@ static int create_window_x11_gl3(struct MPGLContext *ctx, int gl_flags,
if (!context) {
mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GLX context!\n");
XFree(vinfo);
- return SET_WINDOW_FAILED;
+ return false;
}
// set context
@@ -2266,7 +2420,7 @@ static int create_window_x11_gl3(struct MPGLContext *ctx, int gl_flags,
mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GLX context!\n");
glXDestroyContext(vo->x11->display, context);
XFree(vinfo);
- return SET_WINDOW_FAILED;
+ return false;
}
glx_ctx->vinfo = vinfo;
@@ -2274,7 +2428,10 @@ static int create_window_x11_gl3(struct MPGLContext *ctx, int gl_flags,
getFunctions(ctx->gl, (void *)glXGetProcAddress, glxstr, true);
- return SET_WINDOW_REINIT;
+ if (!glXIsDirect(vo->x11->display, context))
+ ctx->gl->mpgl_caps &= ~MPGL_CAP_NO_SW;
+
+ return true;
}
/**
@@ -2292,7 +2449,8 @@ static void releaseGlContext_x11(MPGLContext *ctx)
XFree(*vinfo);
*vinfo = NULL;
if (*context) {
- gl->Finish();
+ if (gl->Finish)
+ gl->Finish();
glXMakeCurrent(display, None, NULL);
glXDestroyContext(display, *context);
}
@@ -2334,45 +2492,46 @@ int mpgl_find_backend(const char *name)
return -1;
}
-MPGLContext *init_mpglcontext(enum MPGLType type, struct vo *vo)
+MPGLContext *mpgl_init(enum MPGLType type, struct vo *vo)
{
MPGLContext *ctx;
if (type == GLTYPE_AUTO) {
- ctx = init_mpglcontext(GLTYPE_COCOA, vo);
+ ctx = mpgl_init(GLTYPE_COCOA, vo);
if (ctx)
return ctx;
- ctx = init_mpglcontext(GLTYPE_W32, vo);
+ ctx = mpgl_init(GLTYPE_W32, vo);
if (ctx)
return ctx;
- return init_mpglcontext(GLTYPE_X11, vo);
+ return mpgl_init(GLTYPE_X11, vo);
}
ctx = talloc_zero(NULL, MPGLContext);
- ctx->gl = talloc_zero(ctx, GL);
- ctx->type = type;
- ctx->vo = vo;
+ *ctx = (MPGLContext) {
+ .gl = talloc_zero(ctx, GL),
+ .type = type,
+ .vo = vo,
+ .requested_gl_version = MPGL_VER(3, 0),
+ .vo_init_ok = true,
+ };
switch (ctx->type) {
#ifdef CONFIG_GL_COCOA
case GLTYPE_COCOA:
- ctx->create_window = create_window_cocoa;
+ ctx->create_window_old = create_window_cocoa_old;
ctx->create_window_gl3 = create_window_cocoa_gl3;
- ctx->setGlWindow = setGlWindow_cocoa;
ctx->releaseGlContext = releaseGlContext_cocoa;
ctx->swapGlBuffers = swapGlBuffers_cocoa;
ctx->check_events = cocoa_check_events;
ctx->update_xinerama_info = cocoa_update_xinerama_info;
ctx->fullscreen = cocoa_fullscreen;
ctx->ontop = vo_cocoa_ontop;
+ ctx->vo_init = vo_cocoa_init;
ctx->vo_uninit = vo_cocoa_uninit;
- if (vo_cocoa_init(vo))
- return ctx;
break;
#endif
#ifdef CONFIG_GL_WIN32
case GLTYPE_W32:
ctx->priv = talloc_zero(ctx, struct w32_context);
- ctx->create_window = create_window_w32;
+ ctx->create_window_old = create_window_w32_old;
ctx->create_window_gl3 = create_window_w32_gl3;
- ctx->setGlWindow = setGlWindow_w32;
ctx->releaseGlContext = releaseGlContext_w32;
ctx->swapGlBuffers = swapGlBuffers_w32;
ctx->update_xinerama_info = w32_update_xinerama_info;
@@ -2380,16 +2539,14 @@ MPGLContext *init_mpglcontext(enum MPGLType type, struct vo *vo)
ctx->check_events = vo_w32_check_events;
ctx->fullscreen = vo_w32_fullscreen;
ctx->ontop = vo_w32_ontop;
+ ctx->vo_init = vo_w32_init;
ctx->vo_uninit = vo_w32_uninit;
- if (vo_w32_init(vo))
- return ctx;
break;
#endif
#ifdef CONFIG_GL_X11
case GLTYPE_X11:
ctx->priv = talloc_zero(ctx, struct glx_context);
- ctx->create_window = create_window_x11;
- ctx->setGlWindow = setGlWindow_x11;
+ ctx->create_window_old = create_window_x11_old;
ctx->create_window_gl3 = create_window_x11_gl3;
ctx->releaseGlContext = releaseGlContext_x11;
ctx->swapGlBuffers = swapGlBuffers_x11;
@@ -2398,40 +2555,85 @@ MPGLContext *init_mpglcontext(enum MPGLType type, struct vo *vo)
ctx->check_events = vo_x11_check_events;
ctx->fullscreen = vo_x11_fullscreen;
ctx->ontop = vo_x11_ontop;
+ ctx->vo_init = vo_init;
ctx->vo_uninit = vo_x11_uninit;
- if (vo_init(vo))
- return ctx;
break;
#endif
}
+ if (ctx->vo_init && ctx->vo_init(vo))
+ return ctx;
talloc_free(ctx);
return NULL;
}
-int create_mpglcontext(struct MPGLContext *ctx, int gl_flags, int gl_version,
- uint32_t d_width, uint32_t d_height, uint32_t flags)
+bool mpgl_destroy_window(struct MPGLContext *ctx)
{
- if (gl_version < MPGL_VER(3, 0)) {
- if (ctx->create_window(ctx, d_width, d_height, flags) < 0)
- return SET_WINDOW_FAILED;
- return ctx->setGlWindow(ctx);
- } else {
- if (!ctx->create_window_gl3) {
- mp_msg(MSGT_VO, MSGL_ERR, "[gl] OpenGL 3.x context creation not "
- "implemented.\n");
- return SET_WINDOW_FAILED;
+ ctx->releaseGlContext(ctx);
+ *ctx->gl = (GL) {0};
+ // This is a caveat. At least on X11, this will recreate the X display
+ // connection. Also, if vo_init() fails, unspecified things will happen.
+ ctx->vo_uninit(ctx->vo);
+ ctx->vo_init_ok = ctx->vo_init(ctx->vo);
+ return ctx->vo_init_ok;
+}
+
+static bool create_window(struct MPGLContext *ctx, int gl_caps,
+ bool (*create)(struct MPGLContext *, uint32_t,
+ uint32_t, uint32_t),
+ uint32_t d_width, uint32_t d_height, uint32_t flags)
+{
+ if (!create || !ctx->vo_init_ok)
+ return false;
+ if (create(ctx, d_width, d_height, flags)) {
+ int missing = (ctx->gl->mpgl_caps & gl_caps) ^ gl_caps;
+ if (!missing) {
+ ctx->selected_create_window = create;
+ return true;
+ }
+ mp_msg(MSGT_VO, MSGL_WARN, "[gl] Missing OpenGL features:");
+ list_features(missing, MSGL_WARN, false);
+ if (missing & MPGL_CAP_NO_SW) {
+ mp_msg(MSGT_VO, MSGL_WARN, "[gl] Rejecting suspected software "
+ "OpenGL renderer.\n");
}
- return ctx->create_window_gl3(ctx, gl_flags, gl_version, d_width,
- d_height, flags);
}
+ // If we tried to create a GL 3 context, and we're going to create a legacy
+ // context after this, the window should be recreated at least on X11.
+ mpgl_destroy_window(ctx);
+ return false;
}
-void uninit_mpglcontext(MPGLContext *ctx)
+bool mpgl_create_window(struct MPGLContext *ctx, int gl_caps, uint32_t d_width,
+ uint32_t d_height, uint32_t flags)
+{
+ assert(ctx->vo_init_ok);
+ if (ctx->selected_create_window)
+ return ctx->selected_create_window(ctx, d_width, d_height, flags);
+
+ bool allow_gl3 = !(gl_caps & MPGL_CAP_GL_LEGACY);
+ bool allow_legacy = !(gl_caps & MPGL_CAP_GL3);
+ gl_caps |= MPGL_CAP_GL;
+
+ if (allow_gl3 && create_window(ctx, gl_caps, ctx->create_window_gl3,
+ d_width, d_height, flags))
+ return true;
+
+ if (allow_legacy && create_window(ctx, gl_caps, ctx->create_window_old,
+ d_width, d_height, flags))
+ return true;
+
+ mp_msg(MSGT_VO, MSGL_ERR, "[gl] OpenGL context creation failed!\n");
+ return false;
+}
+
+void mpgl_uninit(MPGLContext *ctx)
{
if (!ctx)
return;
- ctx->releaseGlContext(ctx);
- ctx->vo_uninit(ctx->vo);
+ if (ctx->vo_init_ok) {
+ ctx->releaseGlContext(ctx);
+ ctx->vo_uninit(ctx->vo);
+ }
talloc_free(ctx);
}
diff --git a/libvo/gl_common.h b/libvo/gl_common.h
index f42caa8fd1..d2592b2f4f 100644
--- a/libvo/gl_common.h
+++ b/libvo/gl_common.h
@@ -153,16 +153,6 @@ void glEnable3DLeft(GL *gl, int type);
void glEnable3DRight(GL *gl, int type);
void glDisable3D(GL *gl, int type);
-/** \addtogroup glcontext
- * \{ */
-//! could not set new window, will continue drawing into the old one.
-#define SET_WINDOW_FAILED -1
-//! new window is set, could even transfer the OpenGL context.
-#define SET_WINDOW_OK 0
-//! new window is set, but the OpenGL context needs to be reinitialized.
-#define SET_WINDOW_REINIT 1
-/** \} */
-
enum MPGLType {
GLTYPE_AUTO,
GLTYPE_COCOA,
@@ -171,49 +161,82 @@ enum MPGLType {
};
enum {
- MPGLFLAG_DEBUG = 1,
+ MPGL_CAP_GL = (1 << 0), // GL was successfully loaded
+ MPGL_CAP_GL_LEGACY = (1 << 1), // GL 1.1 (but not 3.x)
+ MPGL_CAP_GL2 = (1 << 2), // GL 2.0 (3.x core subset)
+ MPGL_CAP_GL21 = (1 << 3), // GL 2.1 (3.x core subset)
+ MPGL_CAP_GL3 = (1 << 4), // GL 3.x core
+ MPGL_CAP_FB = (1 << 5),
+ MPGL_CAP_VAO = (1 << 6),
+ MPGL_CAP_SRGB_TEX = (1 << 7),
+ MPGL_CAP_SRGB_FB = (1 << 8),
+ MPGL_CAP_FLOAT_TEX = (1 << 9),
+ MPGL_CAP_TEX_RG = (1 << 10), // GL_ARB_texture_rg / GL 3.x
+ MPGL_CAP_NO_SW = (1 << 30), // used to block sw. renderers
};
#define MPGL_VER(major, minor) (((major) << 16) | (minor))
#define MPGL_VER_GET_MAJOR(ver) ((ver) >> 16)
#define MPGL_VER_GET_MINOR(ver) ((ver) & ((1 << 16) - 1))
+#define MPGL_VER_P(ver) MPGL_VER_GET_MAJOR(ver), MPGL_VER_GET_MINOR(ver)
+
typedef struct MPGLContext {
GL *gl;
enum MPGLType type;
struct vo *vo;
- void *priv;
+
// Bit size of each component in the created framebuffer. 0 if unknown.
int depth_r, depth_g, depth_b;
- int (*create_window)(struct MPGLContext *ctx, uint32_t d_width,
- uint32_t d_height, uint32_t flags);
- int (*setGlWindow)(struct MPGLContext *);
- void (*releaseGlContext)(struct MPGLContext *);
+
+ // GL version requested from create_window_gl3 backend.
+ // (Might be different from the actual version in gl->version.)
+ int requested_gl_version;
+
void (*swapGlBuffers)(struct MPGLContext *);
int (*check_events)(struct vo *vo);
void (*fullscreen)(struct vo *vo);
+ int (*vo_init)(struct vo *vo);
void (*vo_uninit)(struct vo *vo);
- // only available if GL3 context creation is supported
- // gl_flags: bitfield of MPGLFLAG_* constants
- // gl_version: requested OpenGL version number (use MPGL_VER())
- // return value is one of the SET_WINDOW_* constants
- int (*create_window_gl3)(struct MPGLContext *ctx, int gl_flags,
- int gl_version, uint32_t d_width,
- uint32_t d_height, uint32_t flags);
+ void (*releaseGlContext)(struct MPGLContext *);
+
+ // Creates GL 1.x/2.x legacy context.
+ bool (*create_window_old)(struct MPGLContext *ctx, uint32_t d_width,
+ uint32_t d_height, uint32_t flags);
+
+ // Creates GL 3.x core context.
+ bool (*create_window_gl3)(struct MPGLContext *ctx, uint32_t d_width,
+ uint32_t d_height, uint32_t flags);
+
// optional
void (*ontop)(struct vo *vo);
void (*border)(struct vo *vo);
void (*update_xinerama_info)(struct vo *vo);
+
+ // For free use by the backend.
+ void *priv;
+ // Internal to gl_common.c.
+ bool (*selected_create_window)(struct MPGLContext *ctx, uint32_t d_width,
+ uint32_t d_height, uint32_t flags);
+ bool vo_init_ok;
} MPGLContext;
int mpgl_find_backend(const char *name);
-MPGLContext *init_mpglcontext(enum MPGLType type, struct vo *vo);
-void uninit_mpglcontext(MPGLContext *ctx);
+MPGLContext *mpgl_init(enum MPGLType type, struct vo *vo);
+void mpgl_uninit(MPGLContext *ctx);
-// calls create_window_gl3 or create_window+setGlWindow
-int create_mpglcontext(struct MPGLContext *ctx, int gl_flags, int gl_version,
- uint32_t d_width, uint32_t d_height, uint32_t flags);
+// Create a VO window and create a GL context on it.
+// (Calls create_window_gl3 or create_window+setGlWindow.)
+// gl_caps: bitfield of MPGL_CAP_* (required GL version and feature set)
+// flags: passed to the backend's create window function
+// Returns success.
+bool mpgl_create_window(struct MPGLContext *ctx, int gl_caps, uint32_t d_width,
+ uint32_t d_height, uint32_t flags);
+
+// Destroy the window, without resetting GL3 vs. GL2 context choice.
+// If this fails (false), mpgl_uninit(ctx) must be called.
+bool mpgl_destroy_window(struct MPGLContext *ctx);
// print a multi line string with line numbers (e.g. for shader sources)
// mod, lev: module and log level, as in mp_msg()
@@ -221,6 +244,11 @@ void mp_log_source(int mod, int lev, const char *src);
//function pointers loaded from the OpenGL library
struct GL {
+ int version; // MPGL_VER() mangled
+ int glsl_version; // e.g. 130 for GLSL 1.30
+ char *extensions; // Equivalent to GL_EXTENSIONS
+ int mpgl_caps; // Bitfield of MPGL_CAP_* constants
+
void (GLAPIENTRY *Begin)(GLenum);
void (GLAPIENTRY *End)(void);
void (GLAPIENTRY *Viewport)(GLint, GLint, GLsizei, GLsizei);
@@ -281,8 +309,6 @@ struct GL {
void (GLAPIENTRY *DisableClientState)(GLenum);
GLenum (GLAPIENTRY *GetError)(void);
-
- // OpenGL extension functions
void (GLAPIENTRY *GenBuffers)(GLsizei, GLuint *);
void (GLAPIENTRY *DeleteBuffers)(GLsizei, const GLuint *);
void (GLAPIENTRY *BindBuffer)(GLenum, GLuint);
@@ -304,7 +330,6 @@ struct GL {
GLsizei, GLint, GLenum, GLenum,
const GLvoid *);
- // ancient ATI extensions
void (GLAPIENTRY *BeginFragmentShader)(void);
void (GLAPIENTRY *EndFragmentShader)(void);
void (GLAPIENTRY *SampleMap)(GLuint, GLuint, GLenum);
@@ -315,8 +340,6 @@ struct GL {
GLuint, GLuint, GLuint);
void (GLAPIENTRY *SetFragmentShaderConstant)(GLuint, const GLfloat *);
-
- // GL 3, possibly in GL 2.x as well in form of extensions
void (GLAPIENTRY *GenVertexArrays)(GLsizei, GLuint *);
void (GLAPIENTRY *BindVertexArray)(GLuint);
GLint (GLAPIENTRY *GetAttribLocation)(GLuint, const GLchar *);
@@ -350,6 +373,7 @@ struct GL {
GLint);
void (GLAPIENTRY *Uniform1f)(GLint, GLfloat);
+ void (GLAPIENTRY *Uniform2f)(GLint, GLfloat, GLfloat);
void (GLAPIENTRY *Uniform3f)(GLint, GLfloat, GLfloat, GLfloat);
void (GLAPIENTRY *Uniform1i)(GLint, GLint);
void (GLAPIENTRY *UniformMatrix3fv)(GLint, GLsizei, GLboolean,
diff --git a/libvo/video_out.h b/libvo/video_out.h
index 2cd314f281..5ab5f96301 100644
--- a/libvo/video_out.h
+++ b/libvo/video_out.h
@@ -126,6 +126,7 @@ typedef struct {
#define VOFLAG_FLIPPING 0x08
#define VOFLAG_HIDDEN 0x10 //< Use to create a hidden window
#define VOFLAG_STEREO 0x20 //< Use to create a stereo-capable window
+#define VOFLAG_GL_DEBUG 0x40 // Hint to request debug OpenGL context
typedef struct vo_info_s
{
diff --git a/libvo/vo_corevideo.m b/libvo/vo_corevideo.m
index 1d10330bcb..d92e11ca1c 100644
--- a/libvo/vo_corevideo.m
+++ b/libvo/vo_corevideo.m
@@ -154,9 +154,8 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
p->image_width = width;
p->image_height = height;
- if (p->mpglctx->create_window(p->mpglctx, d_width, d_height, flags) < 0)
- return -1;
- if (p->mpglctx->setGlWindow(p->mpglctx) == SET_WINDOW_FAILED)
+ int mpgl_caps = MPGL_CAP_GL_LEGACY;
+ if (!mpgl_create_window(p->mpglctx, mpgl_caps, d_width, d_height, flags))
return -1;
init_gl(vo, vo->dwidth, vo->dheight);
@@ -367,7 +366,7 @@ static int query_format(struct vo *vo, uint32_t format)
static void uninit(struct vo *vo)
{
struct priv *p = vo->priv;
- uninit_mpglcontext(p->mpglctx);
+ mpgl_uninit(p->mpglctx);
release_cv_entities(vo);
}
@@ -377,7 +376,7 @@ static int preinit(struct vo *vo, const char *arg)
struct priv *p = vo->priv;
*p = (struct priv) {
- .mpglctx = init_mpglcontext(GLTYPE_COCOA, vo),
+ .mpglctx = mpgl_init(GLTYPE_COCOA, vo),
.colorspace = MP_CSP_DETAILS_DEFAULTS,
.quad = talloc_ptrtype(p, p->quad),
.osd = talloc_ptrtype(p, p->osd),
diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c
index 5453943fe9..f24448ac6c 100644
--- a/libvo/vo_gl.c
+++ b/libvo/vo_gl.c
@@ -62,6 +62,8 @@ struct gl_priv {
MPGLContext *glctx;
GL *gl;
+ int allow_sw;
+
int use_osd;
int scaled_osd;
//! Textures for OSD
@@ -388,6 +390,9 @@ static void uninitGl(struct vo *vo)
struct gl_priv *p = vo->priv;
GL *gl = p->gl;
+ if (!gl)
+ return;
+
int i = 0;
if (gl->DeletePrograms && p->fragprog)
gl->DeletePrograms(1, &p->fragprog);
@@ -415,16 +420,6 @@ static void uninitGl(struct vo *vo)
p->err_shown = 0;
}
-static int isSoftwareGl(struct vo *vo)
-{
- struct gl_priv *p = vo->priv;
- const char *renderer = p->gl->GetString(GL_RENDERER);
- const char *vendor = p->gl->GetString(GL_VENDOR);
- return !renderer || strcmp(renderer, "Software Rasterizer") == 0 ||
- strstr(renderer, "llvmpipe") ||
- strcmp(vendor, "Microsoft Corporation") == 0;
-}
-
static void autodetectGlExtensions(struct vo *vo)
{
struct gl_priv *p = vo->priv;
@@ -596,15 +591,18 @@ static int initGl(struct vo *vo, uint32_t d_width, uint32_t d_height)
return 1;
}
-static int create_window(struct vo *vo, uint32_t d_width, uint32_t d_height,
- uint32_t flags)
+static bool create_window(struct vo *vo, uint32_t d_width, uint32_t d_height,
+ uint32_t flags)
{
struct gl_priv *p = vo->priv;
if (p->stereo_mode == GL_3D_QUADBUFFER)
flags |= VOFLAG_STEREO;
- return p->glctx->create_window(p->glctx, d_width, d_height, flags);
+ int mpgl_caps = MPGL_CAP_GL_LEGACY;
+ if (!p->allow_sw)
+ mpgl_caps |= MPGL_CAP_NO_SW;
+ return mpgl_create_window(p->glctx, mpgl_caps, d_width, d_height, flags);
}
static int config(struct vo *vo, uint32_t width, uint32_t height,
@@ -626,13 +624,12 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
p->vo_flipped = !!(flags & VOFLAG_FLIPPING);
- if (create_window(vo, d_width, d_height, flags) < 0)
- return -1;
-
if (vo->config_count)
uninitGl(vo);
- if (p->glctx->setGlWindow(p->glctx) == SET_WINDOW_FAILED)
+
+ if (!create_window(vo, d_width, d_height, flags))
return -1;
+
initGl(vo, vo->dwidth, vo->dheight);
return 0;
@@ -1153,13 +1150,12 @@ static void uninit(struct vo *vo)
{
struct gl_priv *p = vo->priv;
- if (p->glctx)
- uninitGl(vo);
+ uninitGl(vo);
free(p->custom_prog);
p->custom_prog = NULL;
free(p->custom_tex);
p->custom_tex = NULL;
- uninit_mpglcontext(p->glctx);
+ mpgl_uninit(p->glctx);
p->glctx = NULL;
p->gl = NULL;
}
@@ -1192,7 +1188,6 @@ static int preinit(struct vo *vo, const char *arg)
p->eosd = eosd_packer_create(vo);
- int allow_sw = 0;
char *backend_arg = NULL;
//essentially unused; for legacy warnings only
@@ -1223,7 +1218,7 @@ static int preinit(struct vo *vo, const char *arg)
{"mipmapgen", OPT_ARG_BOOL, &p->mipmap_gen, NULL},
{"osdcolor", OPT_ARG_INT, &p->osd_color, NULL},
{"stereo", OPT_ARG_INT, &p->stereo_mode, NULL},
- {"sw", OPT_ARG_BOOL, &allow_sw, NULL},
+ {"sw", OPT_ARG_BOOL, &p->allow_sw, NULL},
{"backend", OPT_ARG_MSTRZ,&backend_arg, backend_valid},
// Removed options.
// They are only parsed to notify the user about the replacements.
@@ -1330,27 +1325,21 @@ static int preinit(struct vo *vo, const char *arg)
int backend = backend_arg ? mpgl_find_backend(backend_arg) : GLTYPE_AUTO;
free(backend_arg);
- p->glctx = init_mpglcontext(backend, vo);
+ p->glctx = mpgl_init(backend, vo);
if (!p->glctx)
goto err_out;
p->gl = p->glctx->gl;
- if (p->use_yuv == -1 || !allow_sw) {
- if (create_window(vo, 320, 200, VOFLAG_HIDDEN) < 0)
- goto err_out;
- if (p->glctx->setGlWindow(p->glctx) == SET_WINDOW_FAILED)
- goto err_out;
- if (!allow_sw && isSoftwareGl(vo))
+ if (p->use_yuv == -1) {
+ if (!create_window(vo, 320, 200, VOFLAG_HIDDEN))
goto err_out;
autodetectGlExtensions(vo);
// We created a window to test whether the GL context supports hardware
// acceleration and so on. Destroy that window to make sure all state
// associated with it is lost.
- uninit(vo);
- p->glctx = init_mpglcontext(backend, vo);
- if (!p->glctx)
+ uninitGl(vo);
+ if (!mpgl_destroy_window(p->glctx))
goto err_out;
- p->gl = p->glctx->gl;
}
if (p->many_fmts)
mp_msg(MSGT_VO, MSGL_INFO, "[gl] using extended formats. "
diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c
index dea0c6637a..329d19370f 100644
--- a/libvo/vo_gl3.c
+++ b/libvo/vo_gl3.c
@@ -148,7 +148,6 @@ struct gl_priv {
struct vo *vo;
MPGLContext *glctx;
GL *gl;
- const char *shader_version;
int use_indirect;
int use_gamma;
@@ -160,7 +159,7 @@ struct gl_priv {
int use_pbo;
int use_glFinish;
int use_gl_debug;
- int use_gl2;
+ int allow_sw;
int dither_depth;
int swap_interval;
@@ -194,6 +193,7 @@ struct gl_priv {
GLuint dither_texture;
float dither_quantization;
float dither_multiply;
+ int dither_size;
uint32_t image_width;
uint32_t image_height;
@@ -305,9 +305,13 @@ static void draw_triangles(struct gl_priv *p, struct vertex *vb, int vert_count)
GL_DYNAMIC_DRAW);
gl->BindBuffer(GL_ARRAY_BUFFER, 0);
- gl->BindVertexArray(p->vao);
+ if (gl->BindVertexArray)
+ gl->BindVertexArray(p->vao);
+
gl->DrawArrays(GL_TRIANGLES, 0, vert_count);
- gl->BindVertexArray(0);
+
+ if (gl->BindVertexArray)
+ gl->BindVertexArray(0);
debug_check_gl(p, "after rendering");
}
@@ -351,10 +355,12 @@ static void write_quad(struct vertex *va,
#undef COLOR_INIT
}
-static void fbotex_init(struct gl_priv *p, struct fbotex *fbo, int w, int h)
+static bool fbotex_init(struct gl_priv *p, struct fbotex *fbo, int w, int h)
{
GL *gl = p->gl;
+ bool res = true;
+ assert(gl->mpgl_caps & MPGL_CAP_FB);
assert(!fbo->fbo);
assert(!fbo->texture);
@@ -375,25 +381,28 @@ static void fbotex_init(struct gl_priv *p, struct fbotex *fbo, int w, int h)
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, fbo->texture, 0);
- if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER)
- != GL_FRAMEBUFFER_COMPLETE)
- {
+ if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
mp_msg(MSGT_VO, MSGL_ERR, "[gl] Error: framebuffer completeness "
"check failed!\n");
+ res = false;
}
gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
debug_check_gl(p, "after creating framebuffer & associated texture");
+
+ return res;
}
static void fbotex_uninit(struct gl_priv *p, struct fbotex *fbo)
{
GL *gl = p->gl;
- gl->DeleteFramebuffers(1, &fbo->fbo);
- gl->DeleteTextures(1, &fbo->texture);
- *fbo = (struct fbotex) {0};
+ if (gl->mpgl_caps & MPGL_CAP_FB) {
+ gl->DeleteFramebuffers(1, &fbo->fbo);
+ gl->DeleteTextures(1, &fbo->texture);
+ *fbo = (struct fbotex) {0};
+ }
}
static void matrix_ortho2d(float m[3][3], float x0, float x1,
@@ -444,9 +453,20 @@ static void update_uniforms(struct gl_priv *p, GLuint program)
1.0 / cparams.ggamma,
1.0 / cparams.bgamma);
- gl->Uniform1i(gl->GetUniformLocation(program, "texture1"), 0);
- gl->Uniform1i(gl->GetUniformLocation(program, "texture2"), 1);
- gl->Uniform1i(gl->GetUniformLocation(program, "texture3"), 2);
+ for (int n = 0; n < p->plane_count; n++) {
+ char textures_n[32];
+ char textures_size_n[32];
+ snprintf(textures_n, sizeof(textures_n), "textures[%d]", n);
+ snprintf(textures_size_n, sizeof(textures_size_n), "textures_size[%d]", n);
+
+ gl->Uniform1i(gl->GetUniformLocation(program, textures_n), n);
+ gl->Uniform2f(gl->GetUniformLocation(program, textures_size_n),
+ p->texture_width >> p->planes[n].shift_x,
+ p->texture_height >> p->planes[n].shift_y);
+ }
+
+ gl->Uniform2f(gl->GetUniformLocation(program, "dither_size"),
+ p->dither_size, p->dither_size);
gl->Uniform1i(gl->GetUniformLocation(program, "lut_3d"), TEXUNIT_3DLUT);
@@ -607,12 +627,12 @@ static void shader_setup_scaler(char **shader, struct scaler *scaler, int pass)
// The direction/pass assignment is rather arbitrary, but fixed in
// other parts of the code (like FBO setup).
const char *direction = pass == 0 ? "0, 1" : "1, 0";
- *shader = talloc_asprintf_append(*shader, "#define %s(p0, p1) "
- "sample_convolution_sep%d(vec2(%s), %s, p0, p1)\n",
+ *shader = talloc_asprintf_append(*shader, "#define %s(p0, p1, p2) "
+ "sample_convolution_sep%d(vec2(%s), %s, p0, p1, p2)\n",
target, size, direction, scaler->lut_name);
} else {
- *shader = talloc_asprintf_append(*shader, "#define %s(p0, p1) "
- "sample_convolution%d(%s, p0, p1)\n",
+ *shader = talloc_asprintf_append(*shader, "#define %s(p0, p1, p2) "
+ "sample_convolution%d(%s, p0, p1, p2)\n",
target, size, scaler->lut_name);
}
}
@@ -642,7 +662,7 @@ static void compile_shaders(struct gl_priv *p)
char *s_eosd = get_section(tmp, src, "frag_eosd");
char *s_osd = get_section(tmp, src, "frag_osd");
- char *header = talloc_asprintf(tmp, "#version %s\n%s", p->shader_version,
+ char *header = talloc_asprintf(tmp, "#version %d\n%s", gl->glsl_version,
shader_prelude);
char *header_eosd = talloc_strdup(tmp, header);
@@ -881,6 +901,8 @@ static void init_dither(struct gl_priv *p)
unsigned char dither[256];
make_dither_matrix(dither, size);
+ p->dither_size = size;
+
gl->ActiveTexture(GL_TEXTURE0 + TEXUNIT_DITHER);
gl->GenTextures(1, &p->dither_texture);
gl->BindTexture(GL_TEXTURE_2D, p->dither_texture);
@@ -1081,7 +1103,9 @@ static void do_render(struct gl_priv *p)
float final_texw = p->image_width * source->tex_w / (float)source->vp_w;
float final_texh = p->image_height * source->tex_h / (float)source->vp_h;
- if (p->use_srgb && !p->use_lut_3d)
+ bool use_srgb_fb = p->use_srgb && !p->use_lut_3d;
+
+ if (use_srgb_fb)
gl->Enable(GL_FRAMEBUFFER_SRGB);
if (p->stereo_mode) {
@@ -1122,7 +1146,8 @@ static void do_render(struct gl_priv *p)
draw_triangles(p, vb, VERTICES_PER_QUAD);
}
- gl->Disable(GL_FRAMEBUFFER_SRGB);
+ if (use_srgb_fb)
+ gl->Disable(GL_FRAMEBUFFER_SRGB);
gl->UseProgram(0);
@@ -1583,6 +1608,70 @@ static void draw_eosd(struct gl_priv *p, mp_eosd_images_t *imgs)
gl->Disable(GL_BLEND);
}
+// Disable features that are not supported with the current OpenGL version.
+static void check_gl_features(struct gl_priv *p)
+{
+ GL *gl = p->gl;
+ bool have_float_tex = gl->mpgl_caps & MPGL_CAP_FLOAT_TEX;
+ bool have_fbo = gl->mpgl_caps & MPGL_CAP_FB;
+ bool have_srgb = (gl->mpgl_caps & MPGL_CAP_SRGB_TEX) &&
+ (gl->mpgl_caps & MPGL_CAP_SRGB_FB);
+
+ char *disabled[10];
+ int n_disabled = 0;
+
+ if (have_fbo) {
+ struct fbotex fbo = {0};
+ have_fbo = fbotex_init(p, &fbo, 16, 16);
+ fbotex_uninit(p, &fbo);
+ }
+
+ // Disable these only if the user didn't disable scale-sep on the command
+ // line, so convolution filter can still be forced to be run.
+ // Normally, we want to disable them by default if FBOs are unavailable,
+ // because they will be slow (not critically slow, but still slower).
+ // Without FP textures, we must always disable them.
+ if (!have_float_tex || (!have_fbo && p->use_scale_sep)) {
+ for (int n = 0; n < 2; n++) {
+ struct scaler *scaler = &p->scalers[n];
+ if (mp_find_filter_kernel(scaler->name)) {
+ scaler->name = "bilinear";
+ disabled[n_disabled++]
+ = have_float_tex ? "scaler (FBO)" : "scaler (float tex.)";
+ }
+ }
+ }
+
+ if (!have_srgb && p->use_srgb) {
+ p->use_srgb = false;
+ disabled[n_disabled++] = "sRGB";
+ }
+ if (!have_fbo && p->use_lut_3d) {
+ p->use_lut_3d = false;
+ disabled[n_disabled++] = "color management (FBO)";
+ }
+ if (!have_srgb && p->use_lut_3d) {
+ p->use_lut_3d = false;
+ disabled[n_disabled++] = "color management (sRGB)";
+ }
+
+ if (!have_fbo) {
+ p->use_scale_sep = false;
+ p->use_indirect = false;
+ }
+
+ if (n_disabled) {
+ mp_msg(MSGT_VO, MSGL_ERR, "[gl] Some OpenGL extensions not detected, "
+ "disabling: ");
+ for (int n = 0; n < n_disabled; n++) {
+ if (n)
+ mp_msg(MSGT_VO, MSGL_ERR, ", ");
+ mp_msg(MSGT_VO, MSGL_ERR, "%s", disabled[n]);
+ }
+ mp_msg(MSGT_VO, MSGL_ERR, ".\n");
+ }
+}
+
static void setup_vertex_array(GL *gl)
{
size_t stride = sizeof(struct vertex);
@@ -1616,15 +1705,7 @@ static int init_gl(struct gl_priv *p)
mp_msg(MSGT_VO, MSGL_V, "[gl] Display depth: R=%d, G=%d, B=%d\n",
p->glctx->depth_r, p->glctx->depth_g, p->glctx->depth_b);
- GLint major, minor;
- gl->GetIntegerv(GL_MAJOR_VERSION, &major);
- gl->GetIntegerv(GL_MINOR_VERSION, &minor);
-
- p->shader_version = "130";
-
- // Hack for OSX: it only creates 3.2 contexts.
- if (MPGL_VER(major, minor) >= MPGL_VER(3, 2))
- p->shader_version = "150";
+ check_gl_features(p);
gl->Disable(GL_DITHER);
gl->Disable(GL_BLEND);
@@ -1634,13 +1715,18 @@ static int init_gl(struct gl_priv *p)
gl->DrawBuffer(GL_BACK);
gl->GenBuffers(1, &p->vertex_buffer);
- gl->GenVertexArrays(1, &p->vao);
-
gl->BindBuffer(GL_ARRAY_BUFFER, p->vertex_buffer);
- gl->BindVertexArray(p->vao);
- setup_vertex_array(gl);
+
+ if (gl->BindVertexArray) {
+ gl->GenVertexArrays(1, &p->vao);
+ gl->BindVertexArray(p->vao);
+ setup_vertex_array(gl);
+ gl->BindVertexArray(0);
+ } else {
+ setup_vertex_array(gl);
+ }
+
gl->BindBuffer(GL_ARRAY_BUFFER, 0);
- gl->BindVertexArray(0);
GLint max_texture_size;
gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
@@ -1664,7 +1750,8 @@ static void uninit_gl(struct gl_priv *p)
uninit_video(p);
- gl->DeleteVertexArrays(1, &p->vao);
+ if (gl->DeleteVertexArrays)
+ gl->DeleteVertexArrays(1, &p->vao);
p->vao = 0;
gl->DeleteBuffers(1, &p->vertex_buffer);
p->vertex_buffer = 0;
@@ -1762,26 +1849,19 @@ static int query_format(uint32_t format)
return caps;
}
-static bool config_window(struct gl_priv *p, uint32_t d_width,
+static bool create_window(struct gl_priv *p, uint32_t d_width,
uint32_t d_height, uint32_t flags)
{
if (p->stereo_mode == GL_3D_QUADBUFFER)
flags |= VOFLAG_STEREO;
- int mpgl_version = MPGL_VER(3, 0);
- int mpgl_flags = p->use_gl_debug ? MPGLFLAG_DEBUG : 0;
-
- if (p->use_gl2)
- mpgl_version = MPGL_VER(2, 1);
-
- if (create_mpglcontext(p->glctx, mpgl_flags, mpgl_version, d_width,
- d_height, flags) == SET_WINDOW_FAILED)
- return false;
-
- if (!p->vertex_buffer)
- init_gl(p);
+ if (p->use_gl_debug)
+ flags |= VOFLAG_GL_DEBUG;
- return true;
+ int mpgl_caps = MPGL_CAP_GL21 | MPGL_CAP_TEX_RG;
+ if (!p->allow_sw)
+ mpgl_caps |= MPGL_CAP_NO_SW;
+ return mpgl_create_window(p->glctx, mpgl_caps, d_width, d_height, flags);
}
static int config(struct vo *vo, uint32_t width, uint32_t height,
@@ -1790,9 +1870,12 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
{
struct gl_priv *p = vo->priv;
- if (!config_window(p, d_width, d_height, flags))
+ if (!create_window(p, d_width, d_height, flags))
return -1;
+ if (!p->vertex_buffer)
+ init_gl(p);
+
p->vo_flipped = !!(flags & VOFLAG_FLIPPING);
if (p->image_format != format || p->image_width != width
@@ -1918,6 +2001,7 @@ static int control(struct vo *vo, uint32_t request, void *data)
char *arg = data;
if (!reparse_cmdline(p, arg))
return false;
+ check_gl_features(p);
reinit_rendering(p);
resize(p);
vo->want_redraw = true;
@@ -1932,7 +2016,7 @@ static void uninit(struct vo *vo)
struct gl_priv *p = vo->priv;
uninit_gl(p);
- uninit_mpglcontext(p->glctx);
+ mpgl_uninit(p->glctx);
p->glctx = NULL;
p->gl = NULL;
}
@@ -2105,6 +2189,7 @@ const struct fbo_format fbo_formats[] = {
{"rgb", GL_RGB},
{"rgba", GL_RGBA},
{"rgb8", GL_RGB8},
+ {"rgb10", GL_RGB10},
{"rgb16", GL_RGB16},
{"rgb16f", GL_RGB16F},
{"rgb32f", GL_RGB32F},
@@ -2224,6 +2309,8 @@ static bool reparse_cmdline(struct gl_priv *p, char *arg)
p->use_scale_sep = opt->use_scale_sep;
p->dither_depth = opt->dither_depth;
+ check_gl_features(p);
+
return true;
}
@@ -2275,11 +2362,11 @@ static int preinit(struct vo *vo, const char *arg)
{"lparam2", OPT_ARG_FLOAT, &p->scaler_params[1]},
{"fancy-downscaling", OPT_ARG_BOOL, &p->use_fancy_downscaling},
{"debug", OPT_ARG_BOOL, &p->use_gl_debug},
- {"force-gl2", OPT_ARG_BOOL, &p->use_gl2},
{"indirect", OPT_ARG_BOOL, &p->use_indirect},
{"scale-sep", OPT_ARG_BOOL, &p->use_scale_sep},
{"fbo-format", OPT_ARG_MSTRZ, &fbo_format, fbo_format_valid},
{"backend", OPT_ARG_MSTRZ, &backend_arg, backend_valid},
+ {"sw", OPT_ARG_BOOL, &p->allow_sw},
{"icc-profile", OPT_ARG_MSTRZ, &icc_profile},
{"icc-cache", OPT_ARG_MSTRZ, &icc_cache},
{"icc-intent", OPT_ARG_INT, &icc_intent},
@@ -2328,23 +2415,20 @@ static int preinit(struct vo *vo, const char *arg)
p->eosd = eosd_packer_create(vo);
- p->glctx = init_mpglcontext(backend, vo);
+ p->glctx = mpgl_init(backend, vo);
if (!p->glctx)
goto err_out;
p->gl = p->glctx->gl;
- if (true) {
- if (!config_window(p, 320, 200, VOFLAG_HIDDEN))
- goto err_out;
- // We created a window to test whether the GL context could be
- // created and so on. Destroy that window to make sure all state
- // associated with it is lost.
- uninit(vo);
- p->glctx = init_mpglcontext(backend, vo);
- if (!p->glctx)
- goto err_out;
- p->gl = p->glctx->gl;
- }
+ if (!create_window(p, 320, 200, VOFLAG_HIDDEN))
+ goto err_out;
+ check_gl_features(p);
+ // We created a window to test whether the GL context could be
+ // created and so on. Destroy that window to make sure all state
+ // associated with it is lost.
+ uninit_gl(p);
+ if (!mpgl_destroy_window(p->glctx))
+ goto err_out;
return 0;
@@ -2464,13 +2548,10 @@ static const char help_text[] =
" This mechanism is disabled on RGB input.\n"
" fbo-format=<fmt>\n"
" Selects the internal format of any FBO textures used.\n"
-" fmt can be one of: rgb, rgba, rgb8, rgb16, rgb16f, rgb32f\n"
+" fmt can be one of: rgb, rgba, rgb8, rgb10, rgb16, rgb16f, rgb32f\n"
" Default: rgb16.\n"
" gamma\n"
" Always enable gamma control. (Disables delayed enabling.)\n"
-" force-gl2\n"
-" Create a legacy GL context. This will randomly malfunction\n"
-" if the proper extensions are not supported.\n"
"Color management:\n"
" icc-profile=<file>\n"
" Load an ICC profile and use it to transform linear RGB to\n"
diff --git a/libvo/vo_gl3_shaders.glsl b/libvo/vo_gl3_shaders.glsl
index f67e55e6f5..207b44b4ba 100644
--- a/libvo/vo_gl3_shaders.glsl
+++ b/libvo/vo_gl3_shaders.glsl
@@ -22,7 +22,29 @@
// inserted at the beginning of all shaders
#!section prelude
+
+// GLSL 1.20 compatibility layer
+// texture() should be assumed to always map to texture2D()
+#if __VERSION__ >= 130
+# define texture1D texture
+# define texture3D texture
+# define DECLARE_FRAGPARMS \
+ out vec4 out_color;
+#else
+# define texture texture2D
+# define DECLARE_FRAGPARMS
+# define out_color gl_FragColor
+# define in varying
+#endif
+
#!section vertex_all
+
+#if __VERSION__ < 130
+# undef in
+# define in attribute
+# define out varying
+#endif
+
uniform mat3 transform;
uniform sampler3D lut_3d;
@@ -40,37 +62,36 @@ void main() {
gl_Position = vec4(position, 1);
color = vertex_color;
#ifdef USE_3DLUT
- color = vec4(texture(lut_3d, color.rgb).rgb, color.a);
+ color = vec4(texture3D(lut_3d, color.rgb).rgb, color.a);
#endif
texcoord = vertex_texcoord;
}
#!section frag_eosd
-uniform sampler2D texture1;
+uniform sampler2D textures[3];
in vec2 texcoord;
in vec4 color;
-out vec4 out_color;
+DECLARE_FRAGPARMS
void main() {
- out_color = vec4(color.rgb, color.a * texture(texture1, texcoord).r);
+ out_color = vec4(color.rgb, color.a * texture(textures[0], texcoord).r);
}
#!section frag_osd
-uniform sampler2D texture1;
+uniform sampler2D textures[3];
in vec2 texcoord;
in vec4 color;
-out vec4 out_color;
+DECLARE_FRAGPARMS
void main() {
- out_color = texture(texture1, texcoord).rrrg * color;
+ out_color = texture(textures[0], texcoord).rrrg * color;
}
#!section frag_video
-uniform sampler2D texture1;
-uniform sampler2D texture2;
-uniform sampler2D texture3;
+uniform sampler2D textures[3];
+uniform vec2 textures_size[3];
uniform sampler1D lut_c_1d;
uniform sampler1D lut_l_1d;
uniform sampler2D lut_c_2d;
@@ -83,11 +104,12 @@ uniform float conv_gamma;
uniform float dither_quantization;
uniform float dither_multiply;
uniform float filter_param1;
+uniform vec2 dither_size;
in vec2 texcoord;
-out vec4 out_color;
+DECLARE_FRAGPARMS
-vec4 sample_bilinear(sampler2D tex, vec2 texcoord) {
+vec4 sample_bilinear(sampler2D tex, vec2 texsize, vec2 texcoord) {
return texture(tex, texcoord);
}
@@ -108,8 +130,7 @@ vec4 calcweights(float s) {
return t;
}
-vec4 sample_bicubic_fast(sampler2D tex, vec2 texcoord) {
- vec2 texsize = textureSize(tex, 0);
+vec4 sample_bicubic_fast(sampler2D tex, vec2 texsize, vec2 texcoord) {
vec2 pt = 1 / texsize;
vec2 fcoord = fract(texcoord * texsize + vec2(0.5, 0.5));
vec4 parmx = calcweights(fcoord.x);
@@ -130,12 +151,12 @@ vec4 sample_bicubic_fast(sampler2D tex, vec2 texcoord) {
}
float[2] weights2(sampler1D lookup, float f) {
- vec4 c = texture(lookup, f);
+ vec4 c = texture1D(lookup, f);
return float[2](c.r, c.g);
}
float[4] weights4(sampler1D lookup, float f) {
- vec4 c = texture(lookup, f);
+ vec4 c = texture1D(lookup, f);
return float[4](c.r, c.g, c.b, c.a);
}
@@ -169,13 +190,13 @@ float[16] weights16(sampler2D lookup, float f) {
c3.r, c3.g, c3.b, c3.a, c4.r, c4.g, c4.b, c4.a);
}
-#define CONVOLUTION_SEP_N(NAME, N) \
- vec4 NAME(sampler2D tex, vec2 texcoord, vec2 pt, float weights[N]) { \
- vec4 res = vec4(0); \
- for (int n = 0; n < N; n++) { \
- res += weights[n] * texture(tex, texcoord + pt * n); \
- } \
- return res; \
+#define CONVOLUTION_SEP_N(NAME, N) \
+ vec4 NAME(sampler2D tex, vec2 texcoord, vec2 pt, float weights[N]) { \
+ vec4 res = vec4(0); \
+ for (int n = 0; n < N; n++) { \
+ res += weights[n] * texture(tex, texcoord + pt * n); \
+ } \
+ return res; \
}
CONVOLUTION_SEP_N(convolution_sep2, 2)
@@ -188,8 +209,8 @@ CONVOLUTION_SEP_N(convolution_sep16, 16)
// The dir parameter is (0, 1) or (1, 0), and we expect the shader compiler to
// remove all the redundant multiplications and additions.
#define SAMPLE_CONVOLUTION_SEP_N(NAME, N, SAMPLERT, CONV_FUNC, WEIGHTS_FUNC)\
- vec4 NAME(vec2 dir, SAMPLERT lookup, sampler2D tex, vec2 texcoord) { \
- vec2 texsize = textureSize(tex, 0); \
+ vec4 NAME(vec2 dir, SAMPLERT lookup, sampler2D tex, vec2 texsize, \
+ vec2 texcoord) { \
vec2 pt = (1 / texsize) * dir; \
float fcoord = dot(fract(texcoord * texsize - 0.5), dir); \
vec2 base = texcoord - fcoord * pt; \
@@ -226,8 +247,7 @@ CONVOLUTION_N(convolution12, 12)
CONVOLUTION_N(convolution16, 16)
#define SAMPLE_CONVOLUTION_N(NAME, N, SAMPLERT, CONV_FUNC, WEIGHTS_FUNC) \
- vec4 NAME(SAMPLERT lookup, sampler2D tex, vec2 texcoord) { \
- vec2 texsize = textureSize(tex, 0); \
+ vec4 NAME(SAMPLERT lookup, sampler2D tex, vec2 texsize, vec2 texcoord) {\
vec2 pt = 1 / texsize; \
vec2 fcoord = fract(texcoord * texsize - 0.5); \
vec2 base = texcoord - fcoord * pt; \
@@ -245,8 +265,7 @@ SAMPLE_CONVOLUTION_N(sample_convolution16, 16, sampler2D, convolution16, weights
// Unsharp masking
-vec4 sample_sharpen3(sampler2D tex, vec2 texcoord) {
- vec2 texsize = textureSize(tex, 0);
+vec4 sample_sharpen3(sampler2D tex, vec2 texsize, vec2 texcoord) {
vec2 pt = 1 / texsize;
vec2 st = pt * 0.5;
vec4 p = texture(tex, texcoord);
@@ -257,8 +276,7 @@ vec4 sample_sharpen3(sampler2D tex, vec2 texcoord) {
return p + (p - 0.25 * sum) * filter_param1;
}
-vec4 sample_sharpen5(sampler2D tex, vec2 texcoord) {
- vec2 texsize = textureSize(tex, 0);
+vec4 sample_sharpen5(sampler2D tex, vec2 texsize, vec2 texcoord) {
vec2 pt = 1 / texsize;
vec2 st1 = pt * 1.2;
vec4 p = texture(tex, texcoord);
@@ -277,11 +295,11 @@ vec4 sample_sharpen5(sampler2D tex, vec2 texcoord) {
void main() {
#ifdef USE_PLANAR
- vec3 color = vec3(SAMPLE_L(texture1, texcoord).r,
- SAMPLE_C(texture2, texcoord).r,
- SAMPLE_C(texture3, texcoord).r);
+ vec3 color = vec3(SAMPLE_L(textures[0], textures_size[0], texcoord).r,
+ SAMPLE_C(textures[1], textures_size[1], texcoord).r,
+ SAMPLE_C(textures[2], textures_size[2], texcoord).r);
#else
- vec3 color = SAMPLE_L(texture1, texcoord).rgb;
+ vec3 color = SAMPLE_L(textures[0], textures_size[0], texcoord).rgb;
#endif
#ifdef USE_GBRP
color.gbr = color;
@@ -306,11 +324,11 @@ void main() {
color = pow(color, inv_gamma);
#endif
#ifdef USE_3DLUT
- color = texture(lut_3d, color).rgb;
+ color = texture3D(lut_3d, color).rgb;
#endif
#ifdef USE_DITHER
- float dither = texture(dither, gl_FragCoord.xy / textureSize(dither, 0)).r;
- color = floor(color * dither_multiply + dither ) / dither_quantization;
+ float dither_value = texture(dither, gl_FragCoord.xy / dither_size).r;
+ color = floor(color * dither_multiply + dither_value ) / dither_quantization;
#endif
out_color = vec4(color, 1);
}