1
0
mirror of https://github.com/mpv-player/mpv synced 2025-01-13 18:45:25 +00:00

vo_opengl: better probe handling

Involve detection of software renderers in the probing properly. Other
VOs could handle probing also more gracefully, and e.g. produce less
noise if an API is unavailable. (Although other than the OpenGL VOs,
only vo_wayland will.)

Now the "sw" suboption for vo_opengl[_old] is strictly speaking not
needed anymore. Doing "--vo=opengl" disables the probing logic, and will
always force it, if possible.

Includes some simplifications as well.
This commit is contained in:
wm4 2014-12-19 18:37:16 +01:00
parent bebc323c6d
commit 88982f2855
6 changed files with 53 additions and 61 deletions

View File

@ -98,27 +98,17 @@ struct feature {
static const struct feature features[] = {
{MPGL_CAP_GL_LEGACY, "Legacy OpenGL"},
{MPGL_CAP_GL21, "OpenGL 2.1+"},
{MPGL_CAP_GL21, "OpenGL 2.1+ (or subset)"},
{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"},
{MPGL_CAP_SW, "suspected software renderer"},
{0},
};
static void list_features(int set, struct mp_log *log, int msgl, bool invert)
{
char b[1024] = {0};
for (const struct feature *f = &features[0]; f->id; f++) {
if (invert == !(f->id & set))
mp_snprintf_cat(b, sizeof(b), " [%s]", f->name);
}
mp_msg(log, msgl, "%s\n", b);
}
// This guesses if the current GL context is a suspected software renderer.
static bool is_software_gl(GL *gl)
{
@ -649,11 +639,16 @@ void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n),
gl->glsl_version = 150;
}
if (!is_software_gl(gl))
gl->mpgl_caps |= MPGL_CAP_NO_SW;
if (is_software_gl(gl))
gl->mpgl_caps |= MPGL_CAP_SW;
mp_verbose(log, "Detected OpenGL features:");
list_features(gl->mpgl_caps, log, MSGL_V, false);
if (gl->mpgl_caps) {
mp_verbose(log, "Detected OpenGL features:\n");
for (const struct feature *f = &features[0]; f->id; f++) {
if ((f->id & gl->mpgl_caps))
mp_verbose(log, " - %s\n", f->name);
}
}
// Provided for simpler handling if no framebuffer support is available.
if (!gl->BindFramebuffer)
@ -906,13 +901,14 @@ static MPGLContext *init_backend(struct vo *vo, MPGLSetBackendFn set_backend,
.gl = talloc_zero(ctx, GL),
.vo = vo,
};
vo->probing = probing;
bool old_probing = vo->probing;
vo->probing = probing; // hack; kill it once backends are separate
set_backend(ctx);
if (!ctx->vo_init(vo)) {
talloc_free(ctx);
ctx = NULL;
}
vo->probing = false;
vo->probing = old_probing;
return ctx;
}
@ -933,32 +929,37 @@ static MPGLContext *mpgl_create(struct vo *vo, const char *backend_name)
}
MPGLContext *mpgl_init(struct vo *vo, const char *backend_name,
int gl_caps, int vo_flags)
int gl_flavor, int vo_flags)
{
MPGLContext *ctx = mpgl_create(vo, backend_name);
if (!ctx)
return NULL;
goto cleanup;
ctx->requested_gl_version = (gl_caps & MPGL_CAP_GL_LEGACY)
? MPGL_VER(2, 1) : MPGL_VER(3, 0);
// A bit strange; but <300 triggers legacy context creation in mpv code.
ctx->requested_gl_version = gl_flavor < 210 ? 210 : 300;
if (ctx->config_window(ctx, vo_flags | VOFLAG_HIDDEN)) {
int missing = (ctx->gl->mpgl_caps & gl_caps) ^ gl_caps;
if (!missing)
return ctx;
if (!ctx->config_window(ctx, vo_flags | VOFLAG_HIDDEN))
goto cleanup;
MP_WARN(ctx->vo, "Missing OpenGL features:");
list_features(missing, ctx->vo->log, MSGL_WARN, false);
if (missing == MPGL_CAP_NO_SW) {
MP_WARN(ctx->vo, "Rejecting suspected software OpenGL renderer.\n");
} else if ((missing & MPGL_CAP_GL21) &&
(ctx->gl->mpgl_caps & MPGL_CAP_GL_LEGACY))
{
MP_WARN(ctx->vo, "OpenGL version too old. Try: --vo=opengl-old\n");
}
if (gl_flavor >= 210 && !(ctx->gl->mpgl_caps & MPGL_CAP_GL21)) {
MP_WARN(ctx->vo, "At least OpenGL 2.1 required.\n");
if (!vo->probing && (ctx->gl->mpgl_caps & MPGL_CAP_GL_LEGACY))
MP_WARN(ctx->vo, "Try with: --vo=opengl-old\n");
goto cleanup;
} else if (gl_flavor < 210 && !(ctx->gl->mpgl_caps & MPGL_CAP_GL_LEGACY)) {
MP_WARN(ctx->vo, "OpenGL context creation failed!\n");
goto cleanup;
}
MP_ERR(ctx->vo, "OpenGL context creation failed!\n");
if (ctx->gl->mpgl_caps & MPGL_CAP_SW) {
MP_WARN(ctx->vo, "Suspected software renderer or indirect context.\n");
if (vo->probing)
goto cleanup;
}
return ctx;
cleanup:
mpgl_uninit(ctx);
return NULL;
}

View File

@ -79,7 +79,7 @@ enum {
MPGL_CAP_TEX_RG = (1 << 10), // GL_ARB_texture_rg / GL 3.x
MPGL_CAP_VDPAU = (1 << 11), // GL_NV_vdpau_interop
MPGL_CAP_APPLE_RGB_422 = (1 << 12), // GL_APPLE_rgb_422
MPGL_CAP_NO_SW = (1 << 30), // used to block sw. renderers
MPGL_CAP_SW = (1 << 30), // indirect or sw renderer
};
// E.g. 310 means 3.1
@ -136,11 +136,11 @@ bool mpgl_is_thread_safe(MPGLContext *ctx);
// Create a VO window and create a GL context on it.
// (Calls config_window_gl3 or config_window+setGlWindow.)
// gl_caps: bitfield of MPGL_CAP_* (required GL version and feature set)
// gl_flavor: 110 for legacy GL, 210 for GL 2.1 or 3.x core
// flags: passed to the backend's create window function
// Returns success.
MPGLContext *mpgl_init(struct vo *vo, const char *backend_name,
int gl_caps, int vo_flags);
int gl_flavor, int vo_flags);
void mpgl_uninit(MPGLContext *ctx);
// flags: passed to the backend function

View File

@ -68,9 +68,6 @@ static bool create_context_x11_old(struct MPGLContext *ctx)
glx_ctx->context = new_context;
if (!glXIsDirect(vo->x11->display, new_context))
ctx->gl->mpgl_caps &= ~MPGL_CAP_NO_SW;
return true;
}
@ -124,9 +121,6 @@ static bool create_context_x11_gl3(struct MPGLContext *ctx, bool debug)
mpgl_load_functions(ctx->gl, (void *)glXGetProcAddress, glxstr, vo->log);
if (!glXIsDirect(vo->x11->display, context))
ctx->gl->mpgl_caps &= ~MPGL_CAP_NO_SW;
return true;
}
@ -260,14 +254,11 @@ static bool config_window_x11(struct MPGLContext *ctx, int flags)
success = create_context_x11_gl3(ctx, flags & VOFLAG_GL_DEBUG);
if (!success)
success = create_context_x11_old(ctx);
if (success && !glXIsDirect(vo->x11->display, glx_ctx->context))
ctx->gl->mpgl_caps |= MPGL_CAP_SW;
return success;
}
/**
* \brief free the VisualInfo and GLXContext of an OpenGL context.
* \ingroup glcontext
*/
static void releaseGlContext_x11(MPGLContext *ctx)
{
struct glx_context *glx_ctx = ctx->priv;

View File

@ -202,7 +202,7 @@ static void dealloc_vo(struct vo *vo)
talloc_free(vo);
}
static struct vo *vo_create(struct mpv_global *global,
static struct vo *vo_create(bool probing, struct mpv_global *global,
struct input_ctx *input_ctx, struct osd_state *osd,
struct encode_lavc_context *encode_lavc_ctx,
char *name, char **args)
@ -225,6 +225,7 @@ static struct vo *vo_create(struct mpv_global *global,
.osd = osd,
.event_fd = -1,
.monitor_par = 1,
.probing = probing,
.in = talloc(vo, struct vo_internal),
};
talloc_steal(vo, log);
@ -271,7 +272,8 @@ struct vo *init_best_video_out(struct mpv_global *global,
// Something like "-vo name," allows fallback to autoprobing.
if (strlen(vo_list[n].name) == 0)
goto autoprobe;
struct vo *vo = vo_create(global, input_ctx, osd, encode_lavc_ctx,
bool p = !!vo_list[n + 1].name;
struct vo *vo = vo_create(p, global, input_ctx, osd, encode_lavc_ctx,
vo_list[n].name, vo_list[n].attribs);
if (vo)
return vo;
@ -281,7 +283,7 @@ struct vo *init_best_video_out(struct mpv_global *global,
autoprobe:
// now try the rest...
for (int i = 0; video_out_drivers[i]; i++) {
struct vo *vo = vo_create(global, input_ctx, osd, encode_lavc_ctx,
struct vo *vo = vo_create(true, global, input_ctx, osd, encode_lavc_ctx,
(char *)video_out_drivers[i]->name, NULL);
if (vo)
return vo;

View File

@ -408,11 +408,10 @@ static int preinit(struct vo *vo)
if (p->use_gl_debug)
vo_flags |= VOFLAG_GL_DEBUG;
int mpgl_caps = MPGL_CAP_GL21;
if (!p->allow_sw)
mpgl_caps |= MPGL_CAP_NO_SW;
if (p->allow_sw)
vo->probing = false;
p->glctx = mpgl_init(vo, p->backend, mpgl_caps, vo_flags);
p->glctx = mpgl_init(vo, p->backend, 210, vo_flags);
if (!p->glctx)
goto err_out;
p->gl = p->glctx->gl;

View File

@ -2168,11 +2168,10 @@ static int preinit(struct vo *vo)
if (p->stereo_mode == GL_3D_QUADBUFFER)
vo_flags |= VOFLAG_STEREO;
int mpgl_caps = MPGL_CAP_GL_LEGACY;
if (!p->allow_sw)
mpgl_caps |= MPGL_CAP_NO_SW;
if (p->allow_sw)
vo->probing = false;
p->glctx = mpgl_init(vo, p->backend_arg, mpgl_caps, vo_flags);
p->glctx = mpgl_init(vo, p->backend_arg, MPGL_CAP_GL_LEGACY, vo_flags);
if (!p->glctx)
goto err_out;
p->gl = p->glctx->gl;