summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Halachmi (:avih) <avihpit@yahoo.com>2015-03-17 01:15:28 +0200
committerwm4 <wm4@nowhere>2015-04-09 20:36:35 +0200
commit843bc822a8a7974c7fbeea62525cb56bbab23fde (patch)
tree0ce52c36cbae7804ce12d922c3bddc6bcb0dda25
parentc97f014576143c706e9d5189a89fa9959a651c71 (diff)
downloadmpv-843bc822a8a7974c7fbeea62525cb56bbab23fde.tar.bz2
mpv-843bc822a8a7974c7fbeea62525cb56bbab23fde.tar.xz
opengl: win32 - add option 'dwmflush' to sync in DWM
This could help in cases where the DWM (Windows desktop compositor) adds another layer of bufferring and therefore the SwapBuffers timing could get messed up. Signed-off-by: wm4 <wm4@nowhere>
-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),