diff --git a/code/actionline.cpp b/code/actionline.cpp index 6f4b55a34..9ba9cb511 100644 --- a/code/actionline.cpp +++ b/code/actionline.cpp @@ -7,6 +7,7 @@ * See LICENSE.md for applicable additional terms and warranty disclaimers. ******************************************************************************/ +#include "mstimer.h" #include "always.h" #include "actionline.h" @@ -74,7 +75,7 @@ void Draw_Action_Line_Segment(Surface & surface, Coord const & start, Coord cons for (int index = 0; index < PATTERN_LENGTH; index++) { pattern[index] = ((index / dash_length) & 1) == 0; } - int offset = (dash_rate > 0) ? ((-(int)timeGetTime() / dash_rate) & (PATTERN_LENGTH - 1)) : (7 * Frame % PATTERN_LENGTH); + int offset = (dash_rate > 0) ? ((-(int)System_Milliseconds() / dash_rate) & (PATTERN_LENGTH - 1)) : (7 * Frame % PATTERN_LENGTH); // A thick line is two rows; its shadow sits below both. int rows = style.IsThick ? 2 : 1; diff --git a/code/dbgprint.cpp b/code/dbgprint.cpp index 97ef4f21b..02c3e7b19 100644 --- a/code/dbgprint.cpp +++ b/code/dbgprint.cpp @@ -18,8 +18,6 @@ #include "opents_build.h" #include "win.h" -#include - #include #include #include @@ -55,41 +53,7 @@ static char DebugDirectory[MAX_PATH]; static char DebugFileName[MAX_PATH]; static unsigned __int64 DebugBytesWritten = 0; -/// -/// Reports whether the command line asks for the debug console. The game's own parser runs -/// too late to catch the messages written during early startup, so the raw command line is -/// read here instead. -/// -static bool Command_Line_Requests_Console(void) -{ - int argc = 0; - LPWSTR * argv = CommandLineToArgvW(GetCommandLineW(), &argc); - - if (argv == NULL) { - return(false); - } - - bool requested = false; - - // Index zero is the executable path, which may itself look like an option. - for (int index = 1; index < argc && !requested; index++) { - wchar_t const * token = argv[index]; - - if (token[0] != L'-' || (token[1] != L'X' && token[1] != L'x')) { - continue; - } - - for (wchar_t const * code = token + 2; *code != L'\0'; code++) { - if (*code == L'C' || *code == L'c') { - requested = true; - break; - } - } - } - - LocalFree(argv); - return(requested); -} +static bool ConsoleRequested = false; /// @@ -225,7 +189,20 @@ static void Init_Console_Locked(void) } -static void Write_Banner_Locked(SYSTEMTIME const & started); +static void Write_Banner_Locked(SYSTEMTIME const & started, int argc, char const * const * argv); +static void Write_Text_Locked(char const * text, size_t length); +static void Write_Message_Locked(char const * buffer, bool with_prefix); + + +static bool Requests_Debug_Console(int argc, char const * const * argv) +{ + for (int index = 1; index < argc; index++) { + char const * const token = argv[index]; + if (token[0] != '-' || (token[1] != 'X' && token[1] != 'x')) continue; + if (strchr(token + 2, 'C') != nullptr || strchr(token + 2, 'c') != nullptr) return(true); + } + return(false); +} /// @@ -233,7 +210,7 @@ static void Write_Banner_Locked(SYSTEMTIME const & started); /// or the command line asks for it. The caller holds the logging lock. A log that cannot be /// opened leaves the debugger and console sinks working. /// -static void Init_Locked(void) +static void Init_Locked(int argc, char const * const * argv) { if (DebugInitDone) { return; @@ -279,16 +256,19 @@ static void Init_Locked(void) } } + ConsoleRequested = ConsoleRequested || Requests_Debug_Console(argc, argv); + #ifdef _DEBUG Init_Console_Locked(); #else - if (Command_Line_Requests_Console()) { + if (ConsoleRequested) { Init_Console_Locked(); } #endif // Last, so that the banner heads the log and also reaches a console that has just opened. - Write_Banner_Locked(now); + AtLineStart = true; + Write_Banner_Locked(now, argc, argv); } @@ -297,6 +277,8 @@ static void Init_Locked(void) /// static void Write_Text_Locked(char const * text, size_t length) { + if (length == 0) return; + DWORD actual; if (DebugFile != INVALID_HANDLE_VALUE) { @@ -365,7 +347,7 @@ static void Write_Message_Locked(char const * buffer, bool with_prefix) /// DebugStringNoPrefix would meet the re-entrancy guard and reach the debugger only. /// /// The time this run's log was opened. -static void Write_Banner_Locked(SYSTEMTIME const & started) +static void Write_Banner_Locked(SYSTEMTIME const & started, int argc, char const * const * argv) { // A raw literal keeps the lettering readable, and keeps its backslashes out of the reach of // escape processing. It opens on its own line so the rows line up here, which costs a @@ -428,25 +410,16 @@ R"ART( // The arguments only. The executable path usually carries the account name, and re-joining // the arguments loses the shell's original quoting, which a diagnostic can live without. - char options[256] = "(none)"; - int argc = 0; - LPWSTR * argv = CommandLineToArgvW(GetCommandLineW(), &argc); - - if (argv != NULL) { - size_t used = 0; + Write_Message_Locked("Options : ", false); + if (argv != nullptr && argc > 1) { for (int index = 1; index < argc; index++) { - int const written = snprintf(options + used, sizeof(options) - used, "%s%ls", - used == 0 ? "" : " ", argv[index]); - if (written <= 0 || size_t(written) >= sizeof(options) - used) { - break; - } - used += size_t(written); + if (index > 1) Write_Message_Locked(" ", false); + Write_Message_Locked(argv[index], false); } - LocalFree(argv); + } else { + Write_Message_Locked("(none)", false); } - - snprintf(line, sizeof(line), "Options : %s\n", options); - Write_Message_Locked(line, false); + Write_Message_Locked("\n", false); Write_Message_Locked("--------------------------------------------------------------------------------\n", false); } @@ -471,7 +444,6 @@ static void Emit(char const * buffer, bool with_prefix) AcquireSRWLockExclusive(&DebugLock); DebugLockOwner = self; - Init_Locked(); Write_Message_Locked(buffer, with_prefix); DebugLockOwner = 0; @@ -480,40 +452,31 @@ static void Emit(char const * buffer, bool with_prefix) /// -/// Runs first time initialisation under the logging lock. +/// Opens this run's log beside the executable and writes the banner. Messages reported +/// before this call reach the debugger and the console but no file. Repeated initialization +/// keeps the first setup, including a failed file open. /// -static void Init_Once(bool with_console) +void Debug_Init(int argc, char const * const * argv) { AcquireSRWLockExclusive(&DebugLock); DebugLockOwner = GetCurrentThreadId(); - - Init_Locked(); - if (with_console) { - Init_Console_Locked(); - } - + Init_Locked(argc, argv); DebugLockOwner = 0; ReleaseSRWLockExclusive(&DebugLock); } /// -/// Prepares the debug log and, when the build or the command line asks for it, the debug -/// console. Logging works without this call, but calling it early fixes the log's timestamp -/// at process start and puts the console up before the first message. -/// -void Debug_Init(void) -{ - Init_Once(false); -} - - -/// -/// Opens the debug console if it is not open already. +/// Opens the console after logging is initialized, or requests it for Debug_Init. /// void Debug_Init_Console(void) { - Init_Once(true); + AcquireSRWLockExclusive(&DebugLock); + DebugLockOwner = GetCurrentThreadId(); + ConsoleRequested = true; + if (DebugInitDone) Init_Console_Locked(); + DebugLockOwner = 0; + ReleaseSRWLockExclusive(&DebugLock); } @@ -534,23 +497,20 @@ void Debug_Console_Hold(void) /// /// Returns the full path of this run's debug log, or an empty string when no log could be -/// opened. Intended for startup code and user interface text; never call it from a crash -/// handler, because it takes the logging lock. +/// opened or initialization has not run. Call after Debug_Init on the startup thread. /// char const * Debug_Log_File_Name(void) { - Init_Once(false); return(DebugFileName); } /// /// Returns the folder where per-run diagnostic files belong, or an empty string when it could -/// not be created. Shared by callers that write their own files beside the debug log. +/// not be selected. Call after Debug_Init on the startup thread. /// char const * Debug_Directory(void) { - Init_Once(false); return(DebugDirectory); } diff --git a/code/dbgprint.h b/code/dbgprint.h index e24a002d2..058cea8d8 100644 --- a/code/dbgprint.h +++ b/code/dbgprint.h @@ -26,7 +26,8 @@ #endif -void Debug_Init(void); +// Borrows the arguments for this call; repeated initialization leaves the first setup intact. +void Debug_Init(int argc, char const * const * argv); void Debug_Init_Console(void); void Debug_Console_Hold(void); char const * Debug_Log_File_Name(void); diff --git a/code/dropship.cpp b/code/dropship.cpp index 960b13d19..aefcb1cb0 100644 --- a/code/dropship.cpp +++ b/code/dropship.cpp @@ -7,6 +7,7 @@ * See LICENSE.md for applicable additional terms and warranty disclaimers. ******************************************************************************/ +#include "mstimer.h" #include "always.h" #include "dropship.h" @@ -247,7 +248,7 @@ struct CrossDissolveEffect FromSurface(from_surface), ToSurface(to_surface), Alpha(0), - StartTime(::timeGetTime()), + StartTime(System_Milliseconds()), FromBlitter(from_blitter), ToBlitter(to_blitter), WasDrawn(false) @@ -557,7 +558,7 @@ void Dropship_Screen(void) DynamicVectorClass button_fades; - unsigned int money_display_time = ::timeGetTime(); + unsigned int money_display_time = System_Milliseconds(); unsigned int screen_start_time = money_display_time; int loadout_anim_frame = 0; unsigned int last_input_time = 0; @@ -613,7 +614,7 @@ void Dropship_Screen(void) KeyNumType input = button_list->Input(); if (!recent_click && (input & KN_BUTTON) != 0) { input = (KeyNumType)(input & ~KN_BUTTON); - last_input_time = ::timeGetTime(); + last_input_time = System_Milliseconds(); if (input <= _cameo_count && selected_count < dropship_count * SLOT_PER_DROPSHIP) { int candidate_index = cameo_top + input - 1; @@ -650,13 +651,13 @@ void Dropship_Screen(void) int light_row = (input - 1) / 2; if (light_frame[light_row] == (unsigned int)-1) { light_frame[light_row] = 0; - light_start[light_row] = ::timeGetTime(); + light_start[light_row] = System_Milliseconds(); } force_light_redraw = true; for (j = 0; ; ++j) { if (j >= button_fades.Count()) { - ButtonFadeEffect *fade = new ButtonFadeEffect(::timeGetTime(), candidate_index, 127.0f, -1.0f, false); + ButtonFadeEffect *fade = new ButtonFadeEffect(System_Milliseconds(), candidate_index, 127.0f, -1.0f, false); if (usage_index != -1 && Scen->AllowableUnitCounts[usage_index] >= Scen->AllowableUnitMaximums[usage_index]) { force_info_redraw = true; fade->StopAtLow = true; @@ -709,7 +710,7 @@ void Dropship_Screen(void) if (Scen->AllowableUnitCounts[usage_index] >= Scen->AllowableUnitMaximums[usage_index]) { for (j = 0; j < candidates.Count(); ++j) { if (candidates[j] == selections[remove_index]) { - ButtonFadeEffect *fade = new ButtonFadeEffect(::timeGetTime(), j, 127.0f, -1.0f, false); + ButtonFadeEffect *fade = new ButtonFadeEffect(System_Milliseconds(), j, 127.0f, -1.0f, false); fade->Direction = 1.0f; fade->Alpha = 63.0f; button_fades.Add(fade); @@ -780,7 +781,7 @@ void Dropship_Screen(void) for (i = 0; i < ARRAY_SIZE(_green_light_ys); ++i) { if (light_frame[i] != (unsigned int)-1) { int frame = light_frame[i]; - int next_frame = (timeGetTime() - light_start[i]) / _light_rate; + int next_frame = (System_Milliseconds() - light_start[i]) / _light_rate; if (next_frame != frame || force_light_redraw) { int light_y = y + _green_light_ys[i]; int light_x = x + _light_x; @@ -816,14 +817,14 @@ void Dropship_Screen(void) ButtonFadeEffect *effect = button_fades[i]; int alpha; if (effect->Direction < 0.0f) { - alpha = 127 - (_fade_rate * timeGetTime() - _fade_rate * effect->StartTime) / _fade_scale; + alpha = 127 - (_fade_rate * System_Milliseconds() - _fade_rate * effect->StartTime) / _fade_scale; if (alpha < _fade_low) { alpha = _fade_low; effect->Direction = 1.0f; - effect->StartTime = timeGetTime(); + effect->StartTime = System_Milliseconds(); } } else { - alpha = (_fade_rate * timeGetTime() - _fade_rate * effect->StartTime) / _fade_scale + _fade_low; + alpha = (_fade_rate * System_Milliseconds() - _fade_rate * effect->StartTime) / _fade_scale + _fade_low; if (alpha > 127) { alpha = 127; } @@ -867,7 +868,7 @@ void Dropship_Screen(void) --j; } - int alpha = std::min(255ul, (_dissolve_rate * timeGetTime() - _dissolve_rate * effect->StartTime) / _dissolve_scale); + int alpha = std::min(255, (_dissolve_rate * System_Milliseconds() - _dissolve_rate * effect->StartTime) / _dissolve_scale); if (alpha != effect->Alpha || overlap_drawn) { effect->Alpha = alpha; @@ -899,17 +900,17 @@ void Dropship_Screen(void) } } - recent_click = (::timeGetTime() - last_input_time) < _click_delay; + recent_click = (System_Milliseconds() - last_input_time) < _click_delay; int loadout_count = loadout_shape->Get_Count(); - int next_loadout_frame = ((::timeGetTime() - screen_start_time) / _loadout_rate) % loadout_count; + int next_loadout_frame = ((System_Milliseconds() - screen_start_time) / _loadout_rate) % loadout_count; if (next_loadout_frame != loadout_anim_frame) { loadout_anim_frame = next_loadout_frame; Draw_Shape(*HiddenSurface, *drawer_dropship, loadout_shape, loadout_anim_frame, Point2D(0, 0), Rect(Point2D(x, y) + Point2D(_loadout_x, _loadout_y), loadout_shape->Get_Width(), loadout_shape->Get_Height()), SHAPE_NORMAL); redraw = true; } - unsigned int now = ::timeGetTime(); + unsigned int now = System_Milliseconds(); if ((unsigned int)money != money_display) { unsigned int elapsed = now - money_display_time; if (elapsed >= _money_rate) { @@ -933,7 +934,7 @@ void Dropship_Screen(void) } if (pilot_frame >= 0) { - int next_pilot_frame = (::timeGetTime() - pilot_start_time) / _pilot_rate; + int next_pilot_frame = (System_Milliseconds() - pilot_start_time) / _pilot_rate; if (next_pilot_frame != pilot_frame) { if (next_pilot_frame < pilotlight_shape->Get_Count()) { pilot_frame = next_pilot_frame; @@ -950,7 +951,7 @@ void Dropship_Screen(void) if (pilot_timer == 0) { if (Scen->RandomNumber(0, INT_MAX - 1) / (double)(INT_MAX - 1) < _pilot_chance) { pilot_frame = 0; - pilot_start_time = ::timeGetTime(); + pilot_start_time = System_Milliseconds(); Draw_Shape(*HiddenSurface, *drawer_dropship, pilotlight_shape, 0, Point2D(0, 0), Rect(x + _pilot_x, y + _pilot_y, pilotlight_shape->Get_Width(), pilotlight_shape->Get_Height()), SHAPE_NORMAL); redraw = true; } diff --git a/code/gametime.cpp b/code/gametime.cpp index a4ff06d15..acd05d055 100644 --- a/code/gametime.cpp +++ b/code/gametime.cpp @@ -33,6 +33,7 @@ // INCLUDES //========================================================================== +#include "mstimer.h" #include "always.h" #include "gametime.h" @@ -59,7 +60,7 @@ GameTimeClass Game_Time; *=========================================================================*/ GameTimeClass::GameTimeClass( void ) { - game_start_time = timeGetTime(); + game_start_time = System_Milliseconds(); } @@ -81,7 +82,7 @@ unsigned int GameTimeClass::Get_Time( void ) unsigned int curr_windows_time; unsigned int game_time; - curr_windows_time = timeGetTime(); + curr_windows_time = System_Milliseconds(); if ( curr_windows_time <= game_start_time ) { // Handles the case if the windows time wraps while playing the game. game_time = MAX_ULONG - game_start_time + curr_windows_time; diff --git a/code/init.cpp b/code/init.cpp index a6994a892..54452907d 100644 --- a/code/init.cpp +++ b/code/init.cpp @@ -54,6 +54,7 @@ * Load_Prolog_Page -- Loads the special pre-prolog "please wait" page. * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +#include "mstimer.h" #include "always.h" #include "init.h" @@ -1960,7 +1961,7 @@ void Init_Random(void) Seed = CustomSeed; } else { CryptRandom.Get(&Seed, sizeof(Seed)); - Seed = GetTickCount(); + Seed = System_Milliseconds(); //srand(time(NULL)); //Seed = rand(); } diff --git a/code/mainloop.cpp b/code/mainloop.cpp index c3e70e9f3..aaf21b413 100644 --- a/code/mainloop.cpp +++ b/code/mainloop.cpp @@ -228,7 +228,7 @@ bool Main_Loop(void) // // Initialize our AI processing timer // - Session.ProcessTimer = timeGetTime();/// TickCount; + Session.ProcessTimer = System_Milliseconds();/// TickCount; if (Session.TrapCheckHeap) { Debug_Trap_Check_Heap = true; @@ -347,7 +347,7 @@ bool Main_Loop(void) // // Measure how long it took to process the AI // - Session.ProcessTicks += std::min(1000, (timeGetTime() - Session.ProcessTimer)); // (TickCount - Session.ProcessTimer) + Session.ProcessTicks += std::min(1000, (System_Milliseconds() - Session.ProcessTimer)); // (TickCount - Session.ProcessTimer) Session.ProcessFrames++; /* diff --git a/code/milsectmr.cpp b/code/milsectmr.cpp index f77953f99..265f9aada 100644 --- a/code/milsectmr.cpp +++ b/code/milsectmr.cpp @@ -11,87 +11,17 @@ #include "milsectmr.h" -#include "dbgprint.h" -#include "getcpu.h" -#include "mpu.h" -#include "win.h" - -#define PERIOD_RESOLUTION 1 /// Use 1-millisecond target resolution. - -/// Microsoft's macros for widening a large integer into a double. -#define ULi2Double(x) ((double)((x).u.HighPart) * 4.294967296E9 + (double)((x).u.LowPart)) -#define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 + (double)((x).LowPart)) - -/// The same conversion, but taking the two halves of the value separately. -#define LI_TO_DBL(dh, dl) ((double)((double)dh * 4.294967296E9 + (double)dl)) +#include /// -/// Creates the millisecond timer and works out how to drive it. -/// This routine will ask the processor for its clock rate so that the cycle counter can be -/// scaled into milliseconds. Machines that will not report a rate fall back to the Windows -/// multimedia timer, whose resolution is raised to one millisecond for the life of the timer. +/// Fetches the current time in milliseconds, with whatever resolution the steady clock +/// offers. The origin is this process, so readings are only meaningful against one another. /// -MillisecondTimerClass::MillisecondTimerClass(void) -{ - unsigned int high = 0; - Frequency = 1.0; - unsigned int low = Get_CPU_Rate(high); - - if (low == 0 && high == 0) { - timeBeginPeriod(PERIOD_RESOLUTION); - - } else { - double dl = low; - double dh = high; - - DebugString("MillisecondTimerClass low = %u, high = %u\n", low, high); - - Frequency = LI_TO_DBL(dh, dl) / 1000; // 1000 = rate. - - } -} - - -/// -/// Releases the millisecond timer. -/// If this timer had to raise the system timer resolution in order to work, the resolution -/// is dropped back here so that the rest of the system is not left paying for it. -/// -MillisecondTimerClass::~MillisecondTimerClass(void) -{ - if (Frequency != 1.0) { - timeEndPeriod(PERIOD_RESOLUTION); - } -} - - -/// -/// Fetches the current time, expressed in milliseconds. -/// This routine is used every time the timer is read. The processor's own cycle counter -/// supplies the value when the machine is new enough to have one, since it is both cheaper -/// and finer grained than the system timer. Otherwise the Windows multimedia timer is -/// consulted instead. -/// -/// Returns with the current time in milliseconds. MillisecondTimerClass::operator double () const { - static int cpu_type = -1; - - if (cpu_type == -1) { - Get_CPU_Type(cpu_type, NULL, 0); - } - /// On extremely old CPUs (80486 and older) the TSC and rdtsc instruction don't exist. - if (Frequency != 1.0 && cpu_type > 4) { - unsigned int high; - unsigned int low; - - low = Get_CPU_Clock(high); - double dl = low; - double dh = high; - - return(LI_TO_DBL(dh, dl) / Frequency); - } + using namespace std::chrono; - return(timeGetTime()); + static steady_clock::time_point const started = steady_clock::now(); + return(duration(steady_clock::now() - started).count()); } diff --git a/code/milsectmr.h b/code/milsectmr.h index 3228f85d2..98fb59cb9 100644 --- a/code/milsectmr.h +++ b/code/milsectmr.h @@ -13,16 +13,5 @@ class MillisecondTimerClass { public: - MillisecondTimerClass(void); - ~MillisecondTimerClass(void); - operator double () const; - - private: - /* - * This is the number of processor clock cycles that pass in one millisecond, and - * the raw cycle count is divided by it to yield a time. If it is 1.0, then the - * processor would not report its rate and the multimedia timer is read instead. - */ - double Frequency; }; diff --git a/code/mstimer.cpp b/code/mstimer.cpp index fceb0fc3a..64c4ff79e 100644 --- a/code/mstimer.cpp +++ b/code/mstimer.cpp @@ -11,49 +11,37 @@ #include "mstimer.h" -#include "win.h" +#include /// -/// Asks Windows for one millisecond timer resolution. -/// This routine is called when the timer is created so that the readings it hands out -/// are fine grained enough for the game to pace itself by. +/// Returns the milliseconds elapsed since the first call. The origin is this process, not +/// the machine, so readings are only meaningful against one another. /// -MillisecondSystemTimerClass::MillisecondSystemTimerClass(void) +unsigned int System_Milliseconds(void) { - timeBeginPeriod(1); -} - + using namespace std::chrono; -/// -/// Returns the system timer to its normal resolution. -/// This routine undoes the resolution request made when the timer was created, so that -/// the rest of the system is not left paying for the finer granularity. -/// -MillisecondSystemTimerClass::~MillisecondSystemTimerClass(void) -{ - timeEndPeriod(1); + static steady_clock::time_point const started = steady_clock::now(); + return((unsigned int)duration_cast(steady_clock::now() - started).count()); } /// -/// Fetches the current millisecond reading of the system clock. -/// This is the sampling routine that the timer templates call whenever they need to -/// know how much time has passed. +/// Fetches the current millisecond reading. This is the sampling routine that the timer +/// templates call whenever they need to know how much time has passed. /// -/// Returns with the number of milliseconds elapsed since Windows started. int MillisecondSystemTimerClass::operator () (void) const { - return(timeGetTime()); + return((int)System_Milliseconds()); } /// -/// Converts the timer into its current millisecond reading. -/// This routine lets the timer object be used wherever a plain time value is expected. +/// Converts the timer into its current millisecond reading, so that it can be used wherever +/// a plain time value is expected. /// -/// Returns with the number of milliseconds elapsed since Windows started. MillisecondSystemTimerClass::operator int (void) const { - return(timeGetTime()); + return((int)System_Milliseconds()); } diff --git a/code/mstimer.h b/code/mstimer.h index 169353c27..c18a5b4af 100644 --- a/code/mstimer.h +++ b/code/mstimer.h @@ -9,12 +9,12 @@ #pragma once +// Milliseconds since the first reading, which is all any caller compares. +unsigned int System_Milliseconds(void); + class MillisecondSystemTimerClass { public: - MillisecondSystemTimerClass(void); - ~MillisecondSystemTimerClass(void); - int operator () (void) const; operator int (void) const; }; diff --git a/code/session.cpp b/code/session.cpp index c3e10e3e9..2182cfb2c 100644 --- a/code/session.cpp +++ b/code/session.cpp @@ -44,6 +44,7 @@ * SessionClass::Compute_Unique_ID -- computes unique local ID number * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +#include "mstimer.h" #include "always.h" #include "session.h" @@ -1003,7 +1004,7 @@ unsigned int SessionClass::Compute_Unique_ID(void) //------------------------------------------------------------------------ // time(&tm); // id = (unsigned long)tm; - id = timeGetTime(); + id = System_Milliseconds(); //------------------------------------------------------------------------ // Now add in the free space on the hard drive diff --git a/code/startup.cpp b/code/startup.cpp index ee17b98dc..b22157350 100644 --- a/code/startup.cpp +++ b/code/startup.cpp @@ -296,6 +296,10 @@ static void RegisterClasses(void) REGISTER_CLASS(AlphaShapeClass, ClassID_AlphaShapeClass); } + +static bool TimerResolutionRaised = false; + + /// /// Builds the argument list the game parses from the command line the shell handed over. /// The shell's own quoting decides where one argument ends and the next begins, so a @@ -361,7 +365,7 @@ int CALLBACK WinMain ( HINSTANCE instance , HINSTANCE , char * , int command_sho { int argc; //Command line argument count char ** argv; //Pointers to command line arguments - char path_to_exe[MAX_PATH]; + char path_to_exe[MAX_PATH] = ""; char buffer[512]; // First, so that everything after it is covered, including the rest of this function. @@ -369,7 +373,14 @@ int CALLBACK WinMain ( HINSTANCE instance , HINSTANCE , char * , int command_sho ProgramInstance = instance; - Debug_Init(); + GetModuleFileName(instance, path_to_exe, sizeof(path_to_exe)); + argc = Build_Arguments(path_to_exe, argv); + + Debug_Init(argc, argv); + + // The scheduler tick rather than the clock: without this every Sleep below waits a whole + // tick, about 15ms, however little it asked for. Prog_End drops it again. + TimerResolutionRaised = timeBeginPeriod(1) == TIMERR_NOERROR; // Handed over now because the exception path may not ask the logger for anything: the // thread that crashed may be the one holding the logger's lock. @@ -463,17 +474,6 @@ int CALLBACK WinMain ( HINSTANCE instance , HINSTANCE , char * , int command_sho RegisterClasses(); - /* - ** Get the full path to the .EXE - */ - GetModuleFileName (instance, &path_to_exe[0], sizeof(path_to_exe)); - - /* - ** Get pointers to command line arguments just like if we were in DOS - ** - */ - argc = Build_Arguments(path_to_exe, argv); - /* ** Change directory to the where the executable is located. Handle the ** case where there is no path attached to argv[0]. @@ -688,6 +688,11 @@ void __cdecl Prog_End(void) { int i; + if (TimerResolutionRaised) { + timeEndPeriod(1); + TimerResolutionRaised = false; + } + GameActive = false; Session.Free_Scenario_Descriptions(); diff --git a/code/stimer.cpp b/code/stimer.cpp index 9574ee3db..f3cc68dd6 100644 --- a/code/stimer.cpp +++ b/code/stimer.cpp @@ -29,6 +29,7 @@ * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +#include "mstimer.h" #include "always.h" #include "stimer.h" @@ -54,7 +55,7 @@ /// Returns with the current system time, expressed in timer ticks. int SystemTimerClass::operator () (void) const { - return(timeGetTime()/16); + return(System_Milliseconds()/16); } @@ -66,5 +67,5 @@ int SystemTimerClass::operator () (void) const /// Returns with the current system time, expressed in timer ticks. SystemTimerClass::operator int (void) const { - return(timeGetTime()/16); + return(System_Milliseconds()/16); } diff --git a/code/timer.h b/code/timer.h index ad1d48c41..f2d83929a 100644 --- a/code/timer.h +++ b/code/timer.h @@ -80,13 +80,20 @@ class BasicTimerClass { int operator () (void) const; /* - * Carries the timer to or from a save game. Only the start reading travels; the - * regulator reads a clock the whole game shares and holds nothing of its own. + * Carries the timer to or from a save game. Started reads a clock whose origin is + * this process, so what travels is how long ago the timer started rather than when, + * and the load rebases it onto the clock it finds. -1 marks a stopped timer and has + * to survive the trip as itself. */ template void Serialize(S & stream) { - stream.Serialize(Started); + int const now = Timer(); + int elapsed = (Started == -1) ? -1 : now - Started; + + stream.Serialize(elapsed); + + Started = (elapsed == -1) ? -1 : now - elapsed; } protected: diff --git a/code/video.cpp b/code/video.cpp index f262d5b5d..f4098ff8f 100644 --- a/code/video.cpp +++ b/code/video.cpp @@ -11,6 +11,7 @@ // as it always has; this decides when that frame reaches the screen and where in the // window it lands, and hands it to the renderer behind video.h. +#include "mstimer.h" #include "always.h" #include "video.h" @@ -278,7 +279,7 @@ void Video_Present(void) _Presenting = false; _FrameIsDirty = false; - _LastPresentTime = timeGetTime(); + _LastPresentTime = System_Milliseconds(); } @@ -294,7 +295,7 @@ void Video_Present_If_Dirty(void) return; } - unsigned int now = timeGetTime(); + unsigned int now = System_Milliseconds(); if ((now - _LastPresentTime) < _PresentInterval) { return; } diff --git a/manual/content/using/debug-logging.md b/manual/content/using/debug-logging.md index ea059bc30..32b1f9393 100644 --- a/manual/content/using/debug-logging.md +++ b/manual/content/using/debug-logging.md @@ -16,7 +16,7 @@ related: ## Where the log is written Every run writes a log to a `Debug` folder beside the executable, named for the moment the -process started: +logger initialized: ``` Debug/DEBUG_17-08-2026_06-00-35.LOG @@ -44,7 +44,7 @@ named commit. `Options` lists the launch options the game was started with. ## Reading the rest -Each line after the banner is stamped with the time it was written: +Each line after the banner is stamped with the time it was reported: ``` [06:00:35.412] Video: renderer is Direct3D 11 diff --git a/tests/ini/inicontract.cpp b/tests/ini/inicontract.cpp index b21db3e95..aa8bbbca0 100644 --- a/tests/ini/inicontract.cpp +++ b/tests/ini/inicontract.cpp @@ -248,7 +248,7 @@ int main(void) { std::printf("OpenTS INI contract\n\n"); - Debug_Init(); + Debug_Init(0, nullptr); { INIClass ini; diff --git a/tests/logstress/logstress.cpp b/tests/logstress/logstress.cpp index d12ed2d80..66f4904a8 100644 --- a/tests/logstress/logstress.cpp +++ b/tests/logstress/logstress.cpp @@ -99,7 +99,7 @@ bool Line_Is_Intact(std::string const & raw) } // namespace -int main(void) +int main(int argc, char ** argv) { std::string const directory = Log_Directory(); std::string const report_path = directory + "\\logstress-report.txt"; @@ -109,7 +109,7 @@ int main(void) // The timings below describe the sinks a released game actually runs with, so the console // stays shut until they are done. - Debug_Init(); + Debug_Init(argc, argv); std::string const log = Debug_Log_File_Name(); Check(!log.empty(), "log file opened");