From 843bc822a8a7974c7fbeea62525cb56bbab23fde Mon Sep 17 00:00:00 2001 From: "Avi Halachmi (:avih)" Date: Tue, 17 Mar 2015 01:15:28 +0200 Subject: 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 --- video/out/gl_common.h | 6 ++++++ video/out/gl_w32.c | 42 ++++++++++++++++++++++++++++++++++++++++++ video/out/vo_opengl.c | 11 +++++++++++ 3 files changed, 59 insertions(+) (limited to 'video') 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), -- cgit v1.2.3