1
0
mirror of https://github.com/FunkyFr3sh/cnc-ddraw.git synced 2025-03-23 00:52:18 +01:00
cnc-ddraw/src/fps_limiter.c
2024-05-06 02:00:58 +02:00

211 lines
5.5 KiB
C

#include <windows.h>
#include "fps_limiter.h"
#include "dd.h"
#include "debug.h"
#include "hook.h"
#include "config.h"
#include "render_ogl.h"
#include "versionhelpers.h"
FPSLIMITER g_fpsl;
void fpsl_init()
{
int max_fps = g_config.maxfps;
g_fpsl.tick_length_ns = 0;
g_fpsl.tick_length = 0;
if (max_fps < 0 || (g_config.vsync && (!g_config.maxfps || g_config.maxfps >= g_ddraw.mode.dmDisplayFrequency)))
max_fps = g_ddraw.mode.dmDisplayFrequency;
if (max_fps > 1000)
max_fps = 0;
if (max_fps > 0)
{
float len = 1000.0f / max_fps;
g_fpsl.tick_length_ns = (LONGLONG)(len * 10000);
g_fpsl.tick_length = (DWORD)len;// + 0.5f;
}
if (g_fpsl.got_adapter && g_fpsl.D3DKMTCloseAdapter)
{
g_fpsl.initialized = FALSE;
g_fpsl.got_adapter = FALSE;
g_fpsl.close_adapter.hAdapter = g_fpsl.adapter.hAdapter;
g_fpsl.D3DKMTCloseAdapter(&g_fpsl.close_adapter);
}
if (!g_fpsl.cs_initialized)
{
g_fpsl.cs_initialized = TRUE;
InitializeCriticalSection(&g_fpsl.cs);
}
if (!g_fpsl.gdi32_dll)
{
g_fpsl.gdi32_dll = real_LoadLibraryA("gdi32.dll");
}
if (!g_fpsl.dwmapi_dll)
{
g_fpsl.dwmapi_dll = real_LoadLibraryA("dwmapi.dll");
}
if (!g_fpsl.DwmFlush)
{
g_fpsl.DwmFlush =
(DWMFLUSHPROC)real_GetProcAddress(g_fpsl.dwmapi_dll, "DwmFlush");
}
if (!g_fpsl.DwmIsCompositionEnabled)
{
g_fpsl.DwmIsCompositionEnabled =
(DWMISCOMPOSITIONENABLEDPROC)real_GetProcAddress(g_fpsl.dwmapi_dll, "DwmIsCompositionEnabled");
}
if (!g_fpsl.D3DKMTWaitForVerticalBlankEvent)
{
g_fpsl.D3DKMTWaitForVerticalBlankEvent =
(D3DKMTWAITFORVERTICALBLANKEVENTPROC)real_GetProcAddress(g_fpsl.gdi32_dll, "D3DKMTWaitForVerticalBlankEvent");
}
if (!g_fpsl.D3DKMTOpenAdapterFromHdc)
{
g_fpsl.D3DKMTOpenAdapterFromHdc =
(D3DKMTOPENADAPTERFROMHDCPROC)real_GetProcAddress(g_fpsl.gdi32_dll, "D3DKMTOpenAdapterFromHdc");
}
if (!g_fpsl.D3DKMTCloseAdapter)
{
g_fpsl.D3DKMTCloseAdapter =
(D3DKMTCLOSEADAPTERPROC)real_GetProcAddress(g_fpsl.gdi32_dll, "D3DKMTCloseAdapter");
}
g_fpsl.initialized = TRUE;
}
BOOL fpsl_wait_for_vblank()
{
if (g_fpsl.initialized)
{
if (!g_fpsl.got_adapter && g_fpsl.D3DKMTOpenAdapterFromHdc && g_ddraw.render.hdc)
{
EnterCriticalSection(&g_fpsl.cs);
if (!g_fpsl.got_adapter)
{
g_fpsl.adapter.hDc = g_ddraw.render.hdc;
if (g_fpsl.D3DKMTOpenAdapterFromHdc(&g_fpsl.adapter) == 0)
{
g_fpsl.vblank_event.hAdapter = g_fpsl.adapter.hAdapter;
g_fpsl.got_adapter = TRUE;
}
}
LeaveCriticalSection(&g_fpsl.cs);
}
if (g_fpsl.got_adapter && g_fpsl.D3DKMTWaitForVerticalBlankEvent)
{
return g_fpsl.D3DKMTWaitForVerticalBlankEvent(&g_fpsl.vblank_event) == 0;
}
}
return FALSE;
}
BOOL fpsl_dwm_flush()
{
if (g_fpsl.initialized && fpsl_dwm_is_enabled() && g_fpsl.DwmFlush)
{
HRESULT x = g_fpsl.DwmFlush();
if (!SUCCEEDED(x))
{
//TRACE(" ERROR %s(result=%08X)\n", __FUNCTION__, x);
}
return SUCCEEDED(x);
}
return FALSE;
}
BOOL fpsl_dwm_is_enabled()
{
BOOL dwm_enabled = FALSE;
if (g_fpsl.DwmIsCompositionEnabled)
g_fpsl.DwmIsCompositionEnabled(&dwm_enabled);
return dwm_enabled;
}
void fpsl_frame_start()
{
if (g_fpsl.tick_length > 0)
g_fpsl.tick_start = timeGetTime();
}
void fpsl_frame_end()
{
if (g_config.maxfps < 0 ||
(g_config.vsync && (!g_config.maxfps || g_config.maxfps >= g_ddraw.mode.dmDisplayFrequency)))
{
/* Workaround for DwmFlush() freeze (e.g. slow alt+tab) issue on windows 7 SP1 */
if (g_ddraw.renderer == ogl_render_main && !IsWine() && !IsWindows8OrGreater())
{
if (fpsl_wait_for_vblank())
return;
}
else
{
if (fpsl_dwm_flush() || fpsl_wait_for_vblank())
return;
}
}
if (g_fpsl.tick_length > 0)
{
if (g_fpsl.htimer)
{
if (g_config.vsync && (!g_config.maxfps || g_config.maxfps >= g_ddraw.mode.dmDisplayFrequency))
{
WaitForSingleObject(g_fpsl.htimer, g_fpsl.tick_length * 2);
LARGE_INTEGER due_time = { .QuadPart = -g_fpsl.tick_length_ns };
SetWaitableTimer(g_fpsl.htimer, &due_time, 0, NULL, NULL, FALSE);
}
else
{
FILETIME ft = { 0 };
GetSystemTimeAsFileTime(&ft);
if (CompareFileTime((FILETIME*)&g_fpsl.due_time, &ft) == -1)
{
memcpy(&g_fpsl.due_time, &ft, sizeof(LARGE_INTEGER));
}
else
{
WaitForSingleObject(g_fpsl.htimer, g_fpsl.tick_length * 2);
}
g_fpsl.due_time.QuadPart += g_fpsl.tick_length_ns;
SetWaitableTimer(g_fpsl.htimer, &g_fpsl.due_time, 0, NULL, NULL, FALSE);
}
}
else
{
g_fpsl.tick_end = timeGetTime();
if (g_fpsl.tick_end - g_fpsl.tick_start < g_fpsl.tick_length)
{
Sleep(g_fpsl.tick_length - (g_fpsl.tick_end - g_fpsl.tick_start));
}
}
}
}