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:
parent
bebc323c6d
commit
88982f2855
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user