1
0
mirror of https://github.com/FunkyFr3sh/cnc-ddraw.git synced 2025-03-14 22:03:27 +01:00

improve fps limiter for vsync and maxfps=-1

This commit is contained in:
FunkyFr3sh 2021-02-02 18:15:25 +01:00
parent d2903413a0
commit a6f85fbd73
11 changed files with 223 additions and 217 deletions

View File

@ -33,6 +33,7 @@ FILES = src/IDirect3D/IDirect3D.c \
src/dllmain.c \
src/wndproc.c \
src/utils.c \
src/fps_limiter.c \
src/opengl_utils.c
all:

View File

@ -32,6 +32,7 @@
</ClCompile>
<ClCompile Include="src\directinput.c" />
<ClCompile Include="src\dllmain.c" />
<ClCompile Include="src\fps_limiter.c" />
<ClCompile Include="src\IDirect3D\IDirect3D.c" />
<ClCompile Include="src\IDirect3D\IDirect3D2.c" />
<ClCompile Include="src\IDirect3D\IDirect3D3.c" />
@ -63,6 +64,7 @@
<ClInclude Include="inc\ddclipper.h" />
<ClInclude Include="inc\directinput.h" />
<ClInclude Include="inc\dllmain.h" />
<ClInclude Include="inc\fps_limiter.h" />
<ClInclude Include="inc\glcorearb.h" />
<ClInclude Include="inc\IDirect3D.h" />
<ClInclude Include="inc\IAMMediaStream.h" />

View File

@ -147,6 +147,9 @@
<ClCompile Include="src\IDirectDraw\IDirectDrawGammaControl.c">
<Filter>Source Files\IDirectDraw</Filter>
</ClCompile>
<ClCompile Include="src\fps_limiter.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="inc\ddraw.h">
@ -248,6 +251,9 @@
<ClInclude Include="inc\IDirectDrawGammaControl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="inc\fps_limiter.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ddraw.rc">

View File

@ -118,7 +118,6 @@ typedef struct cnc_ddraw
BOOL show_driver_warning;
speed_limiter ticks_limiter;
speed_limiter flip_limiter;
speed_limiter fps_limiter;
} cnc_ddraw;

52
inc/fps_limiter.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef FPS_LIMITER_H
#define FPS_LIMITER_H
#include <windows.h>
#include <dwmapi.h>
typedef struct _D3DKMT_WAITFORVERTICALBLANKEVENT {
UINT hAdapter;
UINT hDevice;
UINT VidPnSourceId;
} D3DKMT_WAITFORVERTICALBLANKEVENT;
typedef struct _D3DKMT_OPENADAPTERFROMHDC {
HDC hDc;
UINT hAdapter;
LUID AdapterLuid;
UINT VidPnSourceId;
} D3DKMT_OPENADAPTERFROMHDC;
typedef struct _D3DKMT_CLOSEADAPTER {
UINT hAdapter;
} D3DKMT_CLOSEADAPTER;
typedef struct fps_limiter
{
DWORD tick_start;
DWORD tick_end;
DWORD tick_length;
LONGLONG tick_length_ns;
HANDLE htimer;
LARGE_INTEGER due_time;
D3DKMT_WAITFORVERTICALBLANKEVENT vblank_event;
D3DKMT_OPENADAPTERFROMHDC adapter;
D3DKMT_CLOSEADAPTER close_adapter;
HRESULT(WINAPI* DwmFlush)(VOID);
HRESULT(WINAPI* DwmIsCompositionEnabled)(BOOL*);
NTSTATUS(WINAPI* D3DKMTWaitForVerticalBlankEvent)(const D3DKMT_WAITFORVERTICALBLANKEVENT* Arg1);
NTSTATUS(WINAPI* D3DKMTOpenAdapterFromHdc)(D3DKMT_OPENADAPTERFROMHDC* Arg1);
NTSTATUS(WINAPI* D3DKMTCloseAdapter)(D3DKMT_CLOSEADAPTER* Arg1);
BOOL got_adapter;
} fps_limiter;
extern fps_limiter g_fpsl;
void fpsl_init();
BOOL fpsl_wait_for_vblank();
BOOL fpsl_dwn_is_enabled();
void fpsl_frame_start();
void fpsl_frame_end();
#endif

View File

@ -1,7 +1,7 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <d3d9.h>
#include "fps_limiter.h"
#include "config.h"
#include "dd.h"
#include "render_d3d9.h"
@ -78,7 +78,7 @@ void cfg_load()
}
if (g_ddraw->accurate_timers || g_ddraw->vsync)
g_ddraw->fps_limiter.htimer = CreateWaitableTimer(NULL, TRUE, NULL);
g_fpsl.htimer = CreateWaitableTimer(NULL, TRUE, NULL);
//can't fully set it up here due to missing g_ddraw->mode.dmDisplayFrequency
int max_ticks = cfg_get_int("maxgameticks", 0);

View File

@ -9,6 +9,7 @@
#include "render_d3d9.h"
#include "render_gdi.h"
#include "render_ogl.h"
#include "fps_limiter.h"
#include "debug.h"
#include "utils.h"
@ -817,11 +818,11 @@ ULONG dd_Release()
g_ddraw->flip_limiter.htimer = NULL;
}
if (g_ddraw->fps_limiter.htimer)
if (g_fpsl.htimer)
{
CancelWaitableTimer(g_ddraw->fps_limiter.htimer);
CloseHandle(g_ddraw->fps_limiter.htimer);
g_ddraw->fps_limiter.htimer = NULL;
CancelWaitableTimer(g_fpsl.htimer);
CloseHandle(g_fpsl.htimer);
g_fpsl.htimer = NULL;
}
DeleteCriticalSection(&g_ddraw->cs);

140
src/fps_limiter.c Normal file
View File

@ -0,0 +1,140 @@
#include <windows.h>
#include "fps_limiter.h"
#include "dd.h"
#include "debug.h"
fps_limiter g_fpsl;
void fpsl_init()
{
int max_fps = g_ddraw->render.maxfps;
g_fpsl.tick_length_ns = 0;
g_fpsl.tick_length = 0;
if (max_fps < 0 || g_ddraw->vsync)
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 = len * 10000;
g_fpsl.tick_length = len;// + 0.5f;
}
if (g_fpsl.got_adapter && g_fpsl.D3DKMTCloseAdapter)
{
g_fpsl.got_adapter = FALSE;
g_fpsl.close_adapter.hAdapter = g_fpsl.adapter.hAdapter;
g_fpsl.D3DKMTCloseAdapter(&g_fpsl.close_adapter);
}
g_fpsl.DwmFlush =
(HRESULT(WINAPI*)(VOID))GetProcAddress(GetModuleHandleA("Dwmapi.dll"), "DwmFlush");
g_fpsl.DwmIsCompositionEnabled =
(HRESULT(WINAPI*)(BOOL*))GetProcAddress(GetModuleHandleA("Dwmapi.dll"), "DwmIsCompositionEnabled");
g_fpsl.D3DKMTWaitForVerticalBlankEvent =
(NTSTATUS(WINAPI*)(const D3DKMT_WAITFORVERTICALBLANKEVENT * Arg1))
GetProcAddress(GetModuleHandleA("gdi32.dll"), "D3DKMTWaitForVerticalBlankEvent");
g_fpsl.D3DKMTOpenAdapterFromHdc =
(NTSTATUS(WINAPI*)(D3DKMT_OPENADAPTERFROMHDC * Arg1))
GetProcAddress(GetModuleHandleA("gdi32.dll"), "D3DKMTOpenAdapterFromHdc");
g_fpsl.D3DKMTCloseAdapter =
(NTSTATUS(WINAPI*)(D3DKMT_CLOSEADAPTER * Arg1))
GetProcAddress(GetModuleHandleA("gdi32.dll"), "D3DKMTCloseAdapter");
}
BOOL fpsl_wait_for_vblank()
{
if (g_fpsl.D3DKMTOpenAdapterFromHdc && !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;
}
}
if (g_fpsl.got_adapter && g_fpsl.D3DKMTWaitForVerticalBlankEvent)
{
return g_fpsl.D3DKMTWaitForVerticalBlankEvent(&g_fpsl.vblank_event) == 0;
}
return FALSE;
}
BOOL fpsl_dwn_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_ddraw->render.maxfps < 0 || g_ddraw->vsync)
{
if (fpsl_dwn_is_enabled() && g_fpsl.DwmFlush && SUCCEEDED(g_fpsl.DwmFlush()))
return;
if (fpsl_wait_for_vblank())
return;
}
if (g_fpsl.tick_length > 0)
{
if (g_fpsl.htimer)
{
if (g_ddraw->vsync)
{
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));
}
}
}
}

View File

@ -1,6 +1,7 @@
#include <windows.h>
#include <stdio.h>
#include <d3d9.h>
#include "fps_limiter.h"
#include "dd.h"
#include "ddsurface.h"
#include "d3d9shader.h"
@ -13,7 +14,6 @@
static BOOL d3d9_create_resouces();
static BOOL d3d9_set_states();
static BOOL d3d9_update_vertices(BOOL in_cutscene, BOOL stretch);
static void d3d9_set_max_fps();
static d3d9_renderer g_d3d9;
@ -305,35 +305,12 @@ static BOOL d3d9_update_vertices(BOOL in_cutscene, BOOL stretch)
return FALSE;
}
static void d3d9_set_max_fps()
{
int max_fps = g_ddraw->render.maxfps;
g_ddraw->fps_limiter.tick_length_ns = 0;
g_ddraw->fps_limiter.tick_length = 0;
if (max_fps < 0 || g_ddraw->vsync)
max_fps = g_ddraw->mode.dmDisplayFrequency;
if (max_fps > 1000)
max_fps = 0;
if (max_fps > 0)
{
float len = 1000.0f / max_fps;
g_ddraw->fps_limiter.tick_length_ns = len * 10000;
g_ddraw->fps_limiter.tick_length = len;// + 0.5f;
}
}
DWORD WINAPI d3d9_render_main(void)
{
Sleep(500);
d3d9_set_max_fps();
fpsl_init();
DWORD tick_start = 0;
DWORD tick_end = 0;
BOOL needs_update = FALSE;
DWORD timeout = g_ddraw->render.minfps > 0 ? g_ddraw->render.minfps_tick_len : 200;
@ -347,8 +324,7 @@ DWORD WINAPI d3d9_render_main(void)
static int tex_index = 0, palIndex = 0;
if (g_ddraw->fps_limiter.tick_length > 0)
tick_start = timeGetTime();
fpsl_frame_start();
EnterCriticalSection(&g_ddraw->cs);
@ -456,44 +432,7 @@ DWORD WINAPI d3d9_render_main(void)
dbg_draw_frame_info_end();
#endif
if (g_ddraw->fps_limiter.tick_length > 0)
{
if (g_ddraw->fps_limiter.htimer)
{
if (g_ddraw->vsync)
{
WaitForSingleObject(g_ddraw->fps_limiter.htimer, g_ddraw->fps_limiter.tick_length * 2);
LARGE_INTEGER due_time = { .QuadPart = -g_ddraw->fps_limiter.tick_length_ns };
SetWaitableTimer(g_ddraw->fps_limiter.htimer, &due_time, 0, NULL, NULL, FALSE);
}
else
{
FILETIME ft = { 0 };
GetSystemTimeAsFileTime(&ft);
if (CompareFileTime((FILETIME *)&g_ddraw->fps_limiter.due_time, &ft) == -1)
{
memcpy(&g_ddraw->fps_limiter.due_time, &ft, sizeof(LARGE_INTEGER));
}
else
{
WaitForSingleObject(g_ddraw->fps_limiter.htimer, g_ddraw->fps_limiter.tick_length * 2);
}
g_ddraw->fps_limiter.due_time.QuadPart += g_ddraw->fps_limiter.tick_length_ns;
SetWaitableTimer(g_ddraw->fps_limiter.htimer, &g_ddraw->fps_limiter.due_time, 0, NULL, NULL, FALSE);
}
}
else
{
tick_end = timeGetTime();
if (tick_end - tick_start < g_ddraw->fps_limiter.tick_length)
{
Sleep(g_ddraw->fps_limiter.tick_length - (tick_end - tick_start));
}
}
}
fpsl_frame_end();
}
return 0;
}

View File

@ -1,5 +1,6 @@
#include <windows.h>
#include <stdio.h>
#include "fps_limiter.h"
#include "dd.h"
#include "ddsurface.h"
#include "opengl_utils.h"
@ -30,26 +31,7 @@ DWORD WINAPI gdi_render_main(void)
Sleep(500);
DWORD tick_start = 0;
DWORD tick_end = 0;
int max_fps = g_ddraw->render.maxfps;
g_ddraw->fps_limiter.tick_length_ns = 0;
g_ddraw->fps_limiter.tick_length = 0;
if (max_fps < 0)
max_fps = g_ddraw->mode.dmDisplayFrequency;
if (max_fps > 1000)
max_fps = 0;
if (max_fps > 0)
{
float len = 1000.0f / max_fps;
g_ddraw->fps_limiter.tick_length_ns = len * 10000;
g_ddraw->fps_limiter.tick_length = len + (g_ddraw->accurate_timers ? 0.5f : 0.0f);
}
fpsl_init();
DWORD timeout = g_ddraw->render.minfps > 0 ? g_ddraw->render.minfps_tick_len : INFINITE;
@ -60,8 +42,7 @@ DWORD WINAPI gdi_render_main(void)
dbg_draw_frame_info_start();
#endif
if (g_ddraw->fps_limiter.tick_length > 0)
tick_start = timeGetTime();
fpsl_frame_start();
EnterCriticalSection(&g_ddraw->cs);
@ -155,35 +136,7 @@ DWORD WINAPI gdi_render_main(void)
dbg_draw_frame_info_end();
#endif
if (g_ddraw->fps_limiter.tick_length > 0)
{
if (g_ddraw->fps_limiter.htimer)
{
FILETIME ft = { 0 };
GetSystemTimeAsFileTime(&ft);
if (CompareFileTime((FILETIME*)&g_ddraw->fps_limiter.due_time, &ft) == -1)
{
memcpy(&g_ddraw->fps_limiter.due_time, &ft, sizeof(LARGE_INTEGER));
}
else
{
WaitForSingleObject(g_ddraw->fps_limiter.htimer, g_ddraw->fps_limiter.tick_length * 2);
}
g_ddraw->fps_limiter.due_time.QuadPart += g_ddraw->fps_limiter.tick_length_ns;
SetWaitableTimer(g_ddraw->fps_limiter.htimer, &g_ddraw->fps_limiter.due_time, 0, NULL, NULL, FALSE);
}
else
{
tick_end = timeGetTime();
if (tick_end - tick_start < g_ddraw->fps_limiter.tick_length)
{
Sleep(g_ddraw->fps_limiter.tick_length - (tick_end - tick_start));
}
}
}
fpsl_frame_end();
}
return TRUE;

View File

@ -1,5 +1,6 @@
#include <windows.h>
#include <stdio.h>
#include "fps_limiter.h"
#include "opengl_utils.h"
#include "dd.h"
#include "ddsurface.h"
@ -12,7 +13,6 @@
static HGLRC ogl_create_core_context(HDC hdc);
static HGLRC ogl_create_context(HDC hdc);
static void ogl_set_max_fps();
static void ogl_build_programs();
static void ogl_create_textures(int width, int height);
static void ogl_init_main_program();
@ -36,7 +36,10 @@ DWORD WINAPI ogl_render_main(void)
g_ogl.context = ogl_create_core_context(g_ddraw->render.hdc);
ogl_set_max_fps();
if (oglu_ext_exists("WGL_EXT_swap_control", g_ddraw->render.hdc) && wglSwapIntervalEXT)
wglSwapIntervalEXT(g_ddraw->vsync ? 1 : 0);
fpsl_init();
ogl_build_programs();
ogl_create_textures(g_ddraw->width, g_ddraw->height);
ogl_init_main_program();
@ -110,56 +113,6 @@ static HGLRC ogl_create_context(HDC hdc)
return context;
}
static void ogl_set_max_fps()
{
int max_fps = g_ddraw->render.maxfps;
g_ddraw->fps_limiter.tick_length_ns = 0;
g_ddraw->fps_limiter.tick_length = 0;
/*
if (oglu_ext_exists("WGL_EXT_swap_control_tear", g_ddraw->render.hDC))
{
if (wglSwapIntervalEXT)
{
if (g_ddraw->vsync)
{
wglSwapIntervalEXT(-1);
max_fps = g_ddraw->mode.dmDisplayFrequency;
}
else
wglSwapIntervalEXT(0);
}
}
else */
if (oglu_ext_exists("WGL_EXT_swap_control", g_ddraw->render.hdc))
{
if (wglSwapIntervalEXT)
{
if (g_ddraw->vsync)
{
wglSwapIntervalEXT(1);
max_fps = g_ddraw->mode.dmDisplayFrequency;
}
else
wglSwapIntervalEXT(0);
}
}
if (max_fps < 0)
max_fps = g_ddraw->mode.dmDisplayFrequency;
if (max_fps > 1000)
max_fps = 0;
if (max_fps > 0)
{
float len = 1000.0f / max_fps;
g_ddraw->fps_limiter.tick_length_ns = len * 10000;
g_ddraw->fps_limiter.tick_length = len;// + 0.5f;
}
}
static void ogl_build_programs()
{
g_ogl.main_program = g_ogl.scale_program = 0;
@ -573,8 +526,6 @@ static void ogl_init_scale_program()
static void ogl_render()
{
DWORD tick_start = 0;
DWORD tick_end = 0;
BOOL needs_update = FALSE;
glViewport(
@ -606,8 +557,7 @@ static void ogl_render()
BOOL scale_changed = FALSE;
if (g_ddraw->fps_limiter.tick_length > 0)
tick_start = timeGetTime();
fpsl_frame_start();
EnterCriticalSection(&g_ddraw->cs);
@ -836,44 +786,7 @@ static void ogl_render()
dbg_draw_frame_info_end();
#endif
if (g_ddraw->fps_limiter.tick_length > 0)
{
if (g_ddraw->fps_limiter.htimer)
{
if (g_ddraw->vsync)
{
WaitForSingleObject(g_ddraw->fps_limiter.htimer, g_ddraw->fps_limiter.tick_length * 2);
LARGE_INTEGER due_time = { .QuadPart = -g_ddraw->fps_limiter.tick_length_ns };
SetWaitableTimer(g_ddraw->fps_limiter.htimer, &due_time, 0, NULL, NULL, FALSE);
}
else
{
FILETIME ft = { 0 };
GetSystemTimeAsFileTime(&ft);
if (CompareFileTime((FILETIME *)&g_ddraw->fps_limiter.due_time, &ft) == -1)
{
memcpy(&g_ddraw->fps_limiter.due_time, &ft, sizeof(LARGE_INTEGER));
}
else
{
WaitForSingleObject(g_ddraw->fps_limiter.htimer, g_ddraw->fps_limiter.tick_length * 2);
}
g_ddraw->fps_limiter.due_time.QuadPart += g_ddraw->fps_limiter.tick_length_ns;
SetWaitableTimer(g_ddraw->fps_limiter.htimer, &g_ddraw->fps_limiter.due_time, 0, NULL, NULL, FALSE);
}
}
else
{
tick_end = timeGetTime();
if (tick_end - tick_start < g_ddraw->fps_limiter.tick_length)
{
Sleep(g_ddraw->fps_limiter.tick_length - (tick_end - tick_start));
}
}
}
fpsl_frame_end();
}
}