1
0
mirror of https://github.com/mpv-player/mpv synced 2025-01-02 04:42:10 +00:00

vo_gl3: make it work on OpenGL 2.1

Now vo_gl3 should work with standard OpenGL 2.1, as long as the
GL_ARB_texture_rg extension is available. Optional features, which
require features that are always in OpenGL 3.0, but are available
as extensions only in OpenGL 2.1, are automatically disabled.

The force-gl2 suboption, which was an unreliable hack to run vo_gl3
in an OpenGL 2.1 context, is removed.

Significant changes are done to the extension loader to make it easier
to identify optional OpenGL features.

Context creation is a bit changed to simplify the code and to handle
the fallback better if OpenGL 3 context creation fails, and creating
an OpenGL legacy context is attempted.

Based on the initial work by Rudolf Polzer <divverent@xonotic.org>,
which included making the shader GLSL 1.20 compatible, and more.
This commit is contained in:
wm4 2012-10-03 01:54:13 +02:00
parent db565ca4f8
commit a0b43a11e4
8 changed files with 969 additions and 653 deletions

View File

@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -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,

View File

@ -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
{

View File

@ -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),

View File

@ -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. "

View File

@ -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_gl_debug)
flags |= VOFLAG_GL_DEBUG;
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);
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"

View File

@ -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);
}