diff --git a/src/pc/gfx/gfx_dxgi.cpp b/src/pc/gfx/gfx_dxgi.cpp index 5bdb73401..6358a48e4 100644 --- a/src/pc/gfx/gfx_dxgi.cpp +++ b/src/pc/gfx/gfx_dxgi.cpp @@ -42,6 +42,17 @@ #define FRAME_INTERVAL_US_DENOMINATOR 6 #endif +// TODO: figure out if this shit even works +#ifdef VERSION_EU +# define FRAMERATE 25 +#else +# define FRAMERATE 30 +#endif +// time between consequtive game frames +static const f64 sFrameTime = 1.0 / (2.0 * FRAMERATE); +static f64 sFrameTargetTime = 0; +extern "C" f64 clock_elapsed_f64(void); + using namespace Microsoft::WRL; // For ComPtr static bool inTextInput = false; @@ -395,7 +406,8 @@ static uint64_t qpc_to_us(uint64_t qpc) { } static bool gfx_dxgi_start_frame(void) { - DXGI_FRAME_STATISTICS stats; + // HACK: all of this is too confusing to bother with right now + /*DXGI_FRAME_STATISTICS stats; if (dxgi.swap_chain->GetFrameStatistics(&stats) == S_OK && (stats.SyncRefreshCount != 0 || stats.SyncQPCTime.QuadPart != 0ULL)) { { LARGE_INTEGER t0; @@ -507,13 +519,36 @@ static bool gfx_dxgi_start_frame(void) { dxgi.length_in_vsync_frames = vsyncs_to_wait; } else { dxgi.length_in_vsync_frames = 2; + }*/ + + dxgi.length_in_vsync_frames = configWindow.vsync; + f64 curTime = clock_elapsed_f64(); + if (curTime > sFrameTargetTime) { + sFrameTargetTime += sFrameTime; + if (curTime > sFrameTargetTime + sFrameTime * 3) { + sFrameTargetTime = curTime; + } + dxgi.dropped_frame = true; + return false; } + dxgi.dropped_frame = false; return true; } +static inline void sync_framerate_with_timer(void) { + f64 curTime = clock_elapsed_f64(); + if (curTime < sFrameTargetTime) { + u32 delayMs = (sFrameTargetTime - curTime) * 1000.0; + if (delayMs > 0) { + Sleep(delayMs); + } + } + sFrameTargetTime += sFrameTime; +} + static void gfx_dxgi_swap_buffers_begin(void) { - //dxgi.length_in_vsync_frames = 1; + sync_framerate_with_timer(); ThrowIfFailed(dxgi.swap_chain->Present(dxgi.length_in_vsync_frames, 0)); UINT this_present_id; if (dxgi.swap_chain->GetLastPresentCount(&this_present_id) == S_OK) { @@ -527,12 +562,12 @@ static void gfx_dxgi_swap_buffers_end(void) { QueryPerformanceCounter(&t0); QueryPerformanceCounter(&t1); - if (!dxgi.dropped_frame) { + /*if (!dxgi.dropped_frame) { if (dxgi.waitable_object != nullptr) { WaitForSingleObject(dxgi.waitable_object, INFINITE); } // else TODO: maybe sleep until some estimated time the frame will be shown to reduce lag - } + }*/ DXGI_FRAME_STATISTICS stats; dxgi.swap_chain->GetFrameStatistics(&stats); diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c index 7208bb2d1..dd5759826 100644 --- a/src/pc/gfx/gfx_sdl2.c +++ b/src/pc/gfx/gfx_sdl2.c @@ -35,12 +35,17 @@ #include "src/pc/controller/controller_keyboard.h" +#include "pc/utils/misc.h" + // TODO: figure out if this shit even works #ifdef VERSION_EU # define FRAMERATE 25 #else # define FRAMERATE 30 #endif +// time between consequtive game frames +static const f64 sFrameTime = 1.0 / (2.0 * FRAMERATE); +static f64 sFrameTargetTime = 0; static SDL_Window *wnd; static SDL_GLContext ctx = NULL; @@ -51,11 +56,6 @@ static kb_callback_t kb_key_up = NULL; static void (*kb_all_keys_up)(void) = NULL; static void (*kb_text_input)(char*) = NULL; -// whether to use timer for frame control -static bool use_timer = true; -// time between consequtive game frames -static const int frame_time = 1000 / (2 * FRAMERATE); - const SDL_Scancode windows_scancode_table[] = { /* 0 1 2 3 4 5 6 7 */ /* 8 9 A B C D E F */ @@ -140,26 +140,7 @@ int test_vsync(void) { } static inline void gfx_sdl_set_vsync(const bool enabled) { - if (enabled) { - // try to detect refresh rate - SDL_GL_SetSwapInterval(1); - int vblanks = test_vsync(); - if (vblanks & 1) - vblanks = 0; // not divisible by 60, fuck that - else - vblanks /= 2; - if (vblanks) { - printf("determined swap interval: %d\n", vblanks); - SDL_GL_SetSwapInterval(vblanks); - use_timer = false; - return; - } else { - printf("could not determine swap interval, falling back to timer sync\n"); - } - } - - use_timer = true; - SDL_GL_SetSwapInterval(0); + SDL_GL_SetSwapInterval(enabled); } static void gfx_sdl_set_fullscreen(void) { @@ -334,21 +315,30 @@ static void gfx_sdl_set_keyboard_callbacks(kb_callback_t on_key_down, kb_callbac } static bool gfx_sdl_start_frame(void) { + f64 curTime = clock_elapsed_f64(); + if (curTime > sFrameTargetTime) { + sFrameTargetTime += sFrameTime; + if (curTime > sFrameTargetTime + sFrameTime * 3) { + sFrameTargetTime = curTime; + } + return false; + } return true; } static inline void sync_framerate_with_timer(void) { - static Uint32 last_time = 0; - // get base timestamp on the first frame (might be different from 0) - if (last_time == 0) last_time = SDL_GetTicks(); - const int elapsed = SDL_GetTicks() - last_time; - if (elapsed < frame_time) - SDL_Delay(frame_time - elapsed); - last_time += frame_time; + f64 curTime = clock_elapsed_f64(); + if (curTime < sFrameTargetTime) { + u32 delayMs = (sFrameTargetTime - curTime) * 1000.0; + if (delayMs > 0) { + SDL_Delay(delayMs); + } + } + sFrameTargetTime += sFrameTime; } static void gfx_sdl_swap_buffers_begin(void) { - if (use_timer) sync_framerate_with_timer(); + sync_framerate_with_timer(); SDL_GL_SwapWindow(wnd); } diff --git a/src/pc/utils/misc.c b/src/pc/utils/misc.c index d89d0f1b2..1163848cb 100644 --- a/src/pc/utils/misc.c +++ b/src/pc/utils/misc.c @@ -71,6 +71,10 @@ f32 clock_elapsed(void) { return (clock_elapsed_ns() / 1000000000.0f); } +f64 clock_elapsed_f64(void) { + return (clock_elapsed_ns() / 1000000000.0); +} + u32 clock_elapsed_ticks(void) { return (clock_elapsed_ns() * 3 / 100000000); } \ No newline at end of file diff --git a/src/pc/utils/misc.h b/src/pc/utils/misc.h index 765e03052..ff86e699b 100644 --- a/src/pc/utils/misc.h +++ b/src/pc/utils/misc.h @@ -4,6 +4,7 @@ float smoothstep(float edge0, float edge1, float x); void update_all_mario_stars(void); f32 clock_elapsed(void); +f64 clock_elapsed_f64(void); u32 clock_elapsed_ticks(void); #endif \ No newline at end of file