From 24e0c315e1cc762927b4f4b319296e3bc2857992 Mon Sep 17 00:00:00 2001 From: "Azamat H. Hackimov" Date: Sat, 25 May 2024 03:01:59 +0300 Subject: [PATCH 1/2] Use chrono steady_clock for time measurement Implementing static ChronoTimer class based on C++11 chrono library that replaces platform dependent time measurement implementation. --- ddio/CMakeLists.txt | 3 +- ddio/chrono_timer.cpp | 36 +++++ ddio/chrono_timer.h | 44 ++++++ ddio/ddio.cpp | 2 +- ddio/ddio.h | 20 +-- ddio/lnxtimer.cpp | 158 --------------------- ddio/wintimer.cpp | 313 ------------------------------------------ 7 files changed, 87 insertions(+), 489 deletions(-) create mode 100644 ddio/chrono_timer.cpp create mode 100644 ddio/chrono_timer.h delete mode 100644 ddio/lnxtimer.cpp delete mode 100644 ddio/wintimer.cpp diff --git a/ddio/CMakeLists.txt b/ddio/CMakeLists.txt index 065214756..629540f48 100644 --- a/ddio/CMakeLists.txt +++ b/ddio/CMakeLists.txt @@ -1,4 +1,5 @@ set(CPPS + chrono_timer.cpp ddio.cpp key.cpp $<$: @@ -9,7 +10,6 @@ set(CPPS lnxkey.cpp lnxkey_null.cpp lnxmouse.cpp - lnxtimer.cpp lnxcdrom.cpp lnxkey_sdl.cpp > @@ -20,7 +20,6 @@ set(CPPS winjoy.cpp winkey.cpp winmouse.cpp - wintimer.cpp > ) add_library(ddio STATIC ${CPPS}) diff --git a/ddio/chrono_timer.cpp b/ddio/chrono_timer.cpp new file mode 100644 index 000000000..edef90775 --- /dev/null +++ b/ddio/chrono_timer.cpp @@ -0,0 +1,36 @@ +/* + * Descent 3 + * Copyright (C) 2024 Descent Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "chrono_timer.h" + +namespace D3 { + +void ChronoTimer::Initialize() { m_start_tstamp = std::chrono::steady_clock::now(); } + +float ChronoTimer::GetTime() { + return std::chrono::duration_cast>(std::chrono::steady_clock::now() - m_start_tstamp) + .count(); +} + +int64_t ChronoTimer::GetTimeMS() { + return std::chrono::duration_cast(std::chrono::steady_clock::now() - m_start_tstamp) + .count(); +} + +} // namespace D3 diff --git a/ddio/chrono_timer.h b/ddio/chrono_timer.h new file mode 100644 index 000000000..1c51aae1e --- /dev/null +++ b/ddio/chrono_timer.h @@ -0,0 +1,44 @@ +/* + * Descent 3 + * Copyright (C) 2024 Descent Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +namespace D3 { + +static std::chrono::time_point m_start_tstamp; + +/** + * Static class for handling timers and time durations + */ +class ChronoTimer { +public: + + /// Initialize internal timestamp + static void Initialize(); + + /// Get time in seconds after class initialization (i.e. application start) + static float GetTime(); + + /// Get time in milliseconds after class initialization (i.e. application start) + static int64_t GetTimeMS(); + +}; + +} diff --git a/ddio/ddio.cpp b/ddio/ddio.cpp index eaeb16ead..50dd76257 100644 --- a/ddio/ddio.cpp +++ b/ddio/ddio.cpp @@ -107,7 +107,7 @@ bool ddio_Init(ddio_init_info *init_info) { res = ddio_InternalInit(init_info); if (res) { if (first_time) { // initialize once and only once. - timer_Init(0, init_info->use_lo_res_time); + timer_Init(); } if (!ddio_KeyInit(init_info)) Error("Failed to initialize keyboard system."); diff --git a/ddio/ddio.h b/ddio/ddio.h index b86b00dcb..91e10226c 100644 --- a/ddio/ddio.h +++ b/ddio/ddio.h @@ -193,8 +193,9 @@ #include #include -#include "pstypes.h" +#include "chrono_timer.h" #include "ddio_common.h" +#include "pstypes.h" // ---------------------------------------------------------------------------- // Initialization and destruction functions @@ -230,20 +231,9 @@ void ddio_InternalResetKey(uint8_t key); // Device Dependent Timer Interface // ---------------------------------------------------------------------------- -bool timer_Init(int preemptive, bool force_lores); -void timer_Close(); - -// returns time in seconds -float timer_GetTime(); - -// returns time in milliseconds -int64_t timer_GetMSTime(); - -// hook in timer function at certain period. returns a handle to this function -//@@int timer_HookFunction(void (*fncptr)(), int period); - -// clears function from hook list specified by a handle returned from HookFunction -//@@void timer_ReleaseFunction(int func); +#define timer_Init D3::ChronoTimer::Initialize +#define timer_GetTime D3::ChronoTimer::GetTime +#define timer_GetMSTime D3::ChronoTimer::GetTimeMS // ---------------------------------------------------------------------------- // Device Dependent Mouse Interface diff --git a/ddio/lnxtimer.cpp b/ddio/lnxtimer.cpp deleted file mode 100644 index 5f8e23d95..000000000 --- a/ddio/lnxtimer.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* -* Descent 3 -* Copyright (C) 2024 Parallax Software -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . - ---- HISTORICAL COMMENTS FOLLOW --- - - * $Logfile: /DescentIII/Main/ddio_lnx/lnxtimer.cpp $ - * $Revision: 1.2 $ - * $Date: 2000/06/29 08:50:17 $ - * $Author: icculus $ - * - * Linux timer routines - * - * $Log: lnxtimer.cpp,v $ - * Revision 1.2 2000/06/29 08:50:17 icculus - * Fixed to be more sane. Probably fixes lockup bug, too. - * - * Revision 1.1.1.1 2000/04/18 00:00:33 icculus - * initial checkin - * - * - * 7 8/20/99 7:19p Jeff - * rewrote timer code...trying to get rid of mysterious bug - * - * 6 8/19/99 3:40p Jeff - * possibly fix any holes with signed/unsigned issues - * - * 5 7/14/99 9:06p Jeff - * added comment header - * - * $NoKeywords: $ - */ - -#include - -#include "ddio.h" -#include "pserror.h" - -// --------------------------------------------------------------------------- -// Variables -// --------------------------------------------------------------------------- - -static bool Timer_initialized = 0; -// rcg06292000 not used with SDL. -// static uint64_t Timer_sys_start_time = 0; -// static uint64_t Timer_accum = 0,Timer_high_mark = 0; -// void timer_Normalize(); -// uint64_t timer_GetTickCount(); - -// --------------------------------------------------------------------------- - -bool timer_Init(int preemptive, bool force_lores) { - // struct timeval t; - // gettimeofday(&t,NULL); - // Timer_sys_start_time = t.tv_sec*1000000.0 + t.tv_usec; - // Timer_sys_start_time = 0; - - Timer_initialized = 1; - - // Timer_accum = 0; - // Timer_high_mark = 0; - return true; -} - -void timer_Close() { - ASSERT(Timer_initialized); - Timer_initialized = 0; -} - -float ddio_TickToSeconds(uint32_t ticks) { - // rcg06292000 not used with SDL. - // uint32_t time_ms; - // uint64_t new_ticks = ticks; - - // timer_Normalize(); - // time_ms = new_ticks;// - Timer_sys_start_time; - - // return (float)((double)time_ms/((double)1000000.0)); - - return (ticks / 1000.0); -} - -float timer_GetTime() { - // rcg06292000 ain't working. - // uint32_t time_ms; - // timer_Normalize(); - // time_ms = timer_GetTickCount() - Timer_sys_start_time; - // return (float)((double)time_ms/((double)1000000.0)); - - // rcg06292000 'dis sucka's MINE! - return ((float)SDL_GetTicks() / 1000.0); -} - -int64_t timer_GetMSTime() { - // rcg06292000 not used with SDL. - // uint32_t time_ms; - // timer_Normalize(); - // time_ms = timer_GetTickCount() - Timer_sys_start_time; - // return (int64_t)((double)time_ms/((double)1000.0)); - - return (SDL_GetTicks()); -} - -// --------------------------------------------------------------------------- -// Internal functions -// --------------------------------------------------------------------------- - -// rcg06292000 not used with SDL. -/* -void timer_Normalize() -{ - uint64_t new_time; - new_time = timer_GetTickCount(); - - if (new_time < Timer_sys_start_time) { - Timer_sys_start_time = new_time; - return; - } -} - -uint64_t timer_GetTickCount(void) -{ - uint64_t ret; - struct timeval t; - gettimeofday(&t,NULL); - - ret = t.tv_sec*1000000.0 + t.tv_usec; - - if(ret > Timer_high_mark) - { - Timer_high_mark = ret; - }else - { - // timer roll over - mprintf(0,"TIMER: ROLL OVER\n"); - if(Timer_high_mark>0) - Timer_accum += (Timer_high_mark - Timer_sys_start_time); - Timer_high_mark = ret; - Timer_sys_start_time = ret; - ret = 100;//give some time - } - - return Timer_accum + ret; -} -*/ diff --git a/ddio/wintimer.cpp b/ddio/wintimer.cpp deleted file mode 100644 index 28985924d..000000000 --- a/ddio/wintimer.cpp +++ /dev/null @@ -1,313 +0,0 @@ -/* -* Descent 3 -* Copyright (C) 2024 Parallax Software -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - - -#include "ddio_win.h" -#include "ddio.h" - -#include - -#include "pserror.h" -#include "mono.h" - -#include -#include - -#define MAX_TIMER_HOOKS 4 -#define TIMER_CLOCK_RATE 100 // ms - -// --------------------------------------------------------------------------- -// Variables -// --------------------------------------------------------------------------- - -static bool Timer_initialized = 0; -static bool Timer_use_highres_timer = 0; -static bool Timer_firstinit = false; -static bool Timer_preemptive = 0; -static int Timer_resolution = 0; -static DWORD Timer_sys_start_time = 0; - -bool timerhi_Init(void); -void timerhi_Close(void); -float ddio_TickToSeconds(LARGE_INTEGER ticks); -float timerhi_GetTime(); -int64_t timerhi_GetMSTime(); -void timerhi_Normalize(); -LARGE_INTEGER Timer_hi_sys_start_time; -LARGE_INTEGER Timer_hi_resolution; - -void timer_Normalize(); - -//@@static void (*Timer_function_hook[MAX_TIMER_HOOKS])(); -//@@static int Timer_function_period[MAX_TIMER_HOOKS]; - -//@@void CALLBACK timer_Proc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); - -// --------------------------------------------------------------------------- - -bool timer_Init(int preemptive, bool force_lores) { - TIMECAPS tc; - MMRESULT mmresult; - - ASSERT(!Timer_initialized); - - if (force_lores) { - Timer_use_highres_timer = false; - mprintf(0, "Timer: Forcing to Lo-Res Timer\n"); - } else { - if (timerhi_Init()) - mprintf(0, "Timer: Hi-Resolution Timer available\n"); - else - mprintf(0, "Timer: Hi-Resolution Timer NOT available\n"); - } - - if (!Timer_firstinit) { - Timer_sys_start_time = GetTickCount(); - Timer_firstinit = true; - atexit(timer_Close); - } - - if (preemptive) { - // Initialize Win32 Timer system - //@@ timeGetDevCaps(&tc, sizeof(tc)); - //@@ if (tc.wPeriodMin < 50) tc.wPeriodMin = 50; - //@@ - //@@ Timer_resolution = tc.wPeriodMin; - //@@ - //@@ mmresult = timeBeginPeriod(tc.wPeriodMin); - //@@ if (mmresult != TIMERR_NOERROR) { - //@@ Error("Unable to initialize Win32 timer (err:%x).\n", mmresult); - //@@ } - //@@ - //@@ Timer_preemptive = 1; - //@@ - //@@ // clear out timer function hook list - //@@ for (int i = 0; i < MAX_TIMER_HOOKS;i++) - //@@ Timer_function_hook[i] = NULL; - //@@ - //@@ Timer_event_id = timeSetEvent(TIMER_CLOCK_RATE, Timer_resolution, timer_Proc, 0, TIME_PERIODIC); - //@@ if (Timer_event_id == 0) Error("Unable to instantiate the timer procedure.\n"); - //@@ - //@@ mprintf(0, "Preemptive timer system initialized.\n"); - mprintf(0, "No preemptive timer, default to non-preemptive!"); - Int3(); - Timer_preemptive = 0; - } else { - mprintf(0, "Timer system initialized.\n"); - Timer_preemptive = 0; - } - - // Initialize Win32 Timer system - timeGetDevCaps(&tc, sizeof(tc)); - if (tc.wPeriodMin < 50) - tc.wPeriodMin = 50; - - Timer_resolution = tc.wPeriodMin; - - mmresult = timeBeginPeriod(tc.wPeriodMin); - if (mmresult != TIMERR_NOERROR) { - // Error("Unable to initialize Win32 timer (err:%x).\n", mmresult); - } - - Timer_initialized = 1; - - return 1; -} - -void timer_Close() { - ASSERT(Timer_initialized); - - // mprintf(0, "Timer system closed.\n"); - - if (Timer_use_highres_timer) { - timerhi_Close(); - } else { - if (Timer_resolution) { - timeEndPeriod(Timer_resolution); - Timer_resolution = 0; - } - } - - Timer_initialized = 0; -} - -float ddio_TickToSeconds(uint32_t ticks) { - if (Timer_use_highres_timer) { - LARGE_INTEGER t; - t.QuadPart = ticks; - return ddio_TickToSeconds(t); - } else { - timer_Normalize(); - - DWORD time_ms; - - time_ms = ticks - Timer_sys_start_time; - - return ((float)time_ms / ((float)1000.0)); - } - - Int3(); // ack!! - return 0; -} - -float timer_GetTime() { - if (Timer_use_highres_timer) { - return timerhi_GetTime(); - } else { - DWORD time_ms; - - timer_Normalize(); - time_ms = GetTickCount() - Timer_sys_start_time; - - return ((float)time_ms / ((float)1000.0)); - } - - Int3(); // ack!! - return 0; -} - -int64_t timer_GetMSTime() { - if (Timer_use_highres_timer) { - return timerhi_GetMSTime(); - } else { - DWORD time_ms; - - timer_Normalize(); - time_ms = GetTickCount() - Timer_sys_start_time; - - return time_ms; - } - - Int3(); // ack!! - return 0; -} - -// --------------------------------------------------------------------------- -// Internal functions -// --------------------------------------------------------------------------- -// hook in timer function at certain period. returns a handle to this function -DWORD timer_HookFunction(void(CALLBACK *fncptr)(UINT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR), UINT delay) { - DWORD time_event_id; - - time_event_id = timeSetEvent(delay, Timer_resolution, fncptr, 0, TIME_PERIODIC); - - return time_event_id; -} - -// clears function from hook list specified by a handle returned from HookFunction -void timer_ReleaseFunction(DWORD func) { timeKillEvent(func); } - -void timer_Normalize() { - DWORD new_time; - - new_time = GetTickCount(); - - if (new_time < Timer_sys_start_time) { - Timer_sys_start_time = new_time; - return; - } -} - -// --------------------------------------------------------------------------- -// Support for Win32 timer functions -// We support a timer callback function which we can hook functions to. -// Call function hooks at specified period -// --------------------------------------------------------------------------- - -//@@void CALLBACK timer_Proc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) -//@@{ -//@@ static int ticks = 0; -//@@ static BOOL in_func = FALSE; -//@@ int i; -//@@ -//@@/* Hopefully this will prevent some reentrance, but the timer functions should be very minimal -//@@ and follow Win32 conventions -//@@*/ -//@@ if (!in_func) { -//@@ in_func = TRUE; -//@@ -//@@ for (i = 0; i < MAX_TIMER_HOOKS; i++) -//@@ { -//@@ if (Timer_function_hook[i] && !(ticks % Timer_function_period[i])) -//@@ (*Timer_function_hook[i])(); -//@@ } -//@@ -//@@ in_func = FALSE; -//@@ } -//@@ -//@@ ticks++; -//@@ if (ticks == 256) ticks = 0; -//@@} - -bool timerhi_Init(void) { - // See if we can get the Windows hi res time - Timer_use_highres_timer = (bool)(QueryPerformanceFrequency(&Timer_hi_resolution) != FALSE); - - if (!Timer_use_highres_timer) - return false; - - // determine the start tick - QueryPerformanceCounter(&Timer_hi_sys_start_time); - return true; -} - -void timerhi_Close(void) { - // do any shutdown here!? -} - -float ddio_TickToSeconds(LARGE_INTEGER ticks) { - timerhi_Normalize(); - - LARGE_INTEGER time_ms; - - time_ms.QuadPart = ticks.QuadPart - Timer_hi_sys_start_time.QuadPart; - - return (float)((double)time_ms.QuadPart / ((double)Timer_hi_resolution.QuadPart)); -} - -float timerhi_GetTime() { - LARGE_INTEGER time_tick; - - timerhi_Normalize(); - - QueryPerformanceCounter(&time_tick); - - return (float)(((double)time_tick.QuadPart - Timer_hi_sys_start_time.QuadPart) / - ((double)Timer_hi_resolution.QuadPart)); -} - -// This should return a timer in milliseconds -int64_t timerhi_GetMSTime() { - LARGE_INTEGER time_tick; - - timerhi_Normalize(); - - QueryPerformanceCounter(&time_tick); - - return ((time_tick.QuadPart - Timer_hi_sys_start_time.QuadPart) / (Timer_hi_resolution.QuadPart / 1000)); -} - -void timerhi_Normalize() { - LARGE_INTEGER new_time; - - QueryPerformanceCounter(&new_time); - - if (new_time.QuadPart < Timer_hi_sys_start_time.QuadPart) { - Timer_hi_sys_start_time = new_time; - } -} From 683cac5ea54e9fc7080872e6e8bdb7bbac2643ad Mon Sep 17 00:00:00 2001 From: "Azamat H. Hackimov" Date: Sat, 25 May 2024 03:31:43 +0300 Subject: [PATCH 2/2] Remove unused lorestimer arg option lorestimer was required only for Windows (9x, I guess?), and now with chrono library, that can provide any resolution, it's redundant. Removing related field of ddio_init_info struct. --- Descent3/init.cpp | 2 -- ddio/ddio_common.h | 1 - 2 files changed, 3 deletions(-) diff --git a/Descent3/init.cpp b/Descent3/init.cpp index e1dd61393..9d59daf00 100644 --- a/Descent3/init.cpp +++ b/Descent3/init.cpp @@ -1461,7 +1461,6 @@ void InitIOSystems(bool editor) { // do io init stuff io_info.obj = Descent; - io_info.use_lo_res_time = (bool)(FindArg("-lorestimer") != 0); io_info.joy_emulation = (bool)((FindArg("-alternatejoy") == 0) && (FindArg("-directinput") == 0)); io_info.key_emulation = true; //(bool)(FindArg("-slowkey")!=0); WIN95: DirectInput is flaky for some keys. INIT_MESSAGE(("Initializing DDIO systems.")); @@ -2229,7 +2228,6 @@ void RestartD3() { // startup io io_info.obj = Descent; - io_info.use_lo_res_time = (bool)(FindArg("-lorestimer") != 0); io_info.key_emulation = true; //(bool)(FindArg("-slowkey")!=0); io_info.joy_emulation = (bool)((FindArg("-alternatejoy") == 0) && (FindArg("-directinput") == 0)); if (!ddio_Init(&io_info)) { diff --git a/ddio/ddio_common.h b/ddio/ddio_common.h index f97e96b4a..313d2dd13 100644 --- a/ddio/ddio_common.h +++ b/ddio/ddio_common.h @@ -124,7 +124,6 @@ typedef struct ddio_init_info { oeApplication *obj; // App object used to initialize to IO system - bool use_lo_res_time; bool key_emulation; // keyboard emulation bool joy_emulation; // joystick emulation } ddio_init_info;