summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/vo.rst10
-rw-r--r--video/out/gl_common.h6
-rw-r--r--video/out/gl_w32.c42
-rw-r--r--video/out/vo_opengl.c11
4 files changed, 69 insertions, 0 deletions
diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst
index 5d4bbe1c61..1696b51a53 100644
--- a/DOCS/man/vo.rst
+++ b/DOCS/man/vo.rst
@@ -548,6 +548,16 @@ Available video output drivers are:
X11/GLX only.
+ ``dwmflush``
+ Calls ``DwmFlush`` after swapping buffers on Windows (default: 0).
+ It also sets ``SwapInterval(0)`` to ignore the OpenGL timing. Values
+ are: 0 (disabled), 1 (only in windowed mode), 2 (also in full screen).
+ This may help getting more consistent frame intervals, especially with
+ high-fps clips - which might also reduce dropped frames. Typically a
+ value of 1 should be enough since full screen may bypass the DWM.
+
+ Windows only.
+
``sw``
Continue even if a software renderer is detected.
diff --git a/video/out/gl_common.h b/video/out/gl_common.h
index 2e25d331c7..06960f75ea 100644
--- a/video/out/gl_common.h
+++ b/video/out/gl_common.h
@@ -93,6 +93,12 @@ typedef struct MPGLContext {
void (*releaseGlContext)(struct MPGLContext *);
void (*set_current)(struct MPGLContext *, bool current);
+ // Used on windows only, tries to vsync with the DWM, and modifies SwapInterval
+ // when it does so. Returns the possibly modified swapinterval value.
+ int (*DwmFlush)(struct MPGLContext *, int opt_dwmflush,
+ int opt_swapinterval, int current_swapinterval);
+
+
// Resize the window, or create a new window if there isn't one yet.
// On the first call, it creates a GL context according to what's specified
// in MPGLContext.requested_gl_version. This is just a hint, and if the
diff --git a/video/out/gl_w32.c b/video/out/gl_w32.c
index f2b7cf63d3..b1985e5e1f 100644
--- a/video/out/gl_w32.c
+++ b/video/out/gl_w32.c
@@ -24,10 +24,15 @@
#include "w32_common.h"
#include "gl_common.h"
+typedef HRESULT (WINAPI *DwmFlush_t)(void);
+
struct w32_context {
HGLRC context;
HDC hdc;
int flags;
+
+ HINSTANCE dwmapi_dll;
+ DwmFlush_t dwmflush;
};
static bool create_dc(struct MPGLContext *ctx, int flags)
@@ -202,6 +207,11 @@ static void create_ctx(void *ptr)
create_context_w32_gl3(ctx);
if (!w32_ctx->context)
create_context_w32_old(ctx);
+
+ w32_ctx->dwmapi_dll = LoadLibrary(L"Dwmapi.dll");
+ if (w32_ctx->dwmapi_dll)
+ w32_ctx->dwmflush = (DwmFlush_t)GetProcAddress(w32_ctx->dwmapi_dll, "DwmFlush");
+
wglMakeCurrent(w32_ctx->hdc, NULL);
}
@@ -240,6 +250,11 @@ static void releaseGlContext_w32(MPGLContext *ctx)
if (w32_ctx->context)
wglMakeCurrent(w32_ctx->hdc, 0);
vo_w32_run_on_thread(ctx->vo, destroy_gl, ctx);
+
+ w32_ctx->dwmflush = NULL;
+ if (w32_ctx->dwmapi_dll)
+ FreeLibrary(w32_ctx->dwmapi_dll);
+ w32_ctx->dwmapi_dll = NULL;
}
static void swapGlBuffers_w32(MPGLContext *ctx)
@@ -248,6 +263,32 @@ static void swapGlBuffers_w32(MPGLContext *ctx)
SwapBuffers(w32_ctx->hdc);
}
+// opt_dwmflush: 0 - never DwmFlush, 1 - only in windowed mode, 2 - always
+// return: the current (applied if modified) SwapInterval value.
+// DwmFlush waits on DWM vsync similar to SwapBuffers but a bit more noisy.
+// SwapBuffers still needs to be called, but we SwapInterval(0) when DwmFLush is
+// used (will get applied for the following SwapBuffers calls)
+static int DwmFlush_w32(MPGLContext *ctx, int opt_dwmflush,
+ int opt_swapinterval, int current_swapinterval)
+{
+ struct w32_context *w32_ctx = ctx->priv;
+ int new_swapinterval = opt_swapinterval; // default if we don't DwmFLush
+
+ if (w32_ctx->dwmflush &&
+ (opt_dwmflush == 2 || (opt_dwmflush == 1 && !ctx->vo->opts->fullscreen)) &&
+ S_OK == w32_ctx->dwmflush())
+ {
+ new_swapinterval = 0;
+ }
+
+ if ((new_swapinterval != current_swapinterval) && ctx->gl->SwapInterval) {
+ ctx->gl->SwapInterval(new_swapinterval);
+ MP_VERBOSE(ctx->vo, "DwmFlush: set SwapInterval(%d)\n", new_swapinterval);
+ }
+
+ return new_swapinterval;
+}
+
void mpgl_set_backend_w32(MPGLContext *ctx)
{
ctx->priv = talloc_zero(ctx, struct w32_context);
@@ -257,4 +298,5 @@ void mpgl_set_backend_w32(MPGLContext *ctx)
ctx->vo_init = vo_w32_init;
ctx->vo_uninit = vo_w32_uninit;
ctx->vo_control = vo_w32_control;
+ ctx->DwmFlush = DwmFlush_w32;
}
diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c
index 589ae7b0db..fb47464e9a 100644
--- a/video/out/vo_opengl.c
+++ b/video/out/vo_opengl.c
@@ -72,6 +72,9 @@ struct gl_priv {
int use_gl_debug;
int allow_sw;
int swap_interval;
+ int current_swap_interval;
+ int dwm_flush;
+
char *backend;
int vo_flipped;
@@ -154,6 +157,12 @@ static void flip_page(struct vo *vo)
}
}
+ if (p->glctx->DwmFlush) {
+ p->current_swap_interval = p->glctx->DwmFlush(p->glctx, p->dwm_flush,
+ p->swap_interval,
+ p->current_swap_interval);
+ }
+
mpgl_unlock(p->glctx);
}
@@ -463,6 +472,7 @@ static int preinit(struct vo *vo)
} else {
MP_VERBOSE(vo, "swap_control extension missing.\n");
}
+ p->current_swap_interval = p->swap_interval;
p->renderer = gl_video_init(p->gl, vo->log);
if (!p->renderer)
@@ -498,6 +508,7 @@ static const struct m_option options[] = {
OPT_FLAG("glfinish", use_glFinish, 0),
OPT_FLAG("waitvsync", waitvsync, 0),
OPT_INT("swapinterval", swap_interval, 0, OPTDEF_INT(1)),
+ OPT_INT("dwmflush", dwm_flush, 0, OPTDEF_INT(0)),
OPT_FLAG("debug", use_gl_debug, 0),
OPT_STRING_VALIDATE("backend", backend, 0, mpgl_validate_backend_opt),
OPT_FLAG("sw", allow_sw, 0),