diff --git a/src/CxbxKrnl/CxbxKrnl.cpp b/src/CxbxKrnl/CxbxKrnl.cpp index ec54ba8a9..827f40fa0 100644 --- a/src/CxbxKrnl/CxbxKrnl.cpp +++ b/src/CxbxKrnl/CxbxKrnl.cpp @@ -366,6 +366,8 @@ extern "C" CXBXKRNL_API void CxbxKrnlInit g_CurrentProcessHandle = GetCurrentProcess(); + CxbxInitPerformanceCounters(); + #ifdef _DEBUG // MessageBoxA(NULL, "Attach a Debugger", "DEBUG", 0); // Debug child processes using https://marketplace.visualstudio.com/items?itemName=GreggMiskelly.MicrosoftChildProcessDebuggingPowerTool diff --git a/src/CxbxKrnl/CxbxKrnl.h b/src/CxbxKrnl/CxbxKrnl.h index cedf156e7..8c502d90c 100644 --- a/src/CxbxKrnl/CxbxKrnl.h +++ b/src/CxbxKrnl/CxbxKrnl.h @@ -82,6 +82,8 @@ CXBXKRNL_API void CxbxKrnlPanic(); /*! empty function */ CXBXKRNL_API void CxbxKrnlNoFunc(); +CXBXKRNL_API void CxbxInitPerformanceCounters(); // Implemented in EmuKrnlKe.cpp + /*! kernel thunk table */ extern CXBXKRNL_API uint32 CxbxKrnl_KernelThunkTable[379]; diff --git a/src/CxbxKrnl/EmuKrnlKe.cpp b/src/CxbxKrnl/EmuKrnlKe.cpp index d693c5c9f..e3792129d 100644 --- a/src/CxbxKrnl/EmuKrnlKe.cpp +++ b/src/CxbxKrnl/EmuKrnlKe.cpp @@ -424,6 +424,27 @@ XBSYSAPI EXPORTNUM(125) xboxkrnl::ULONGLONG NTAPI xboxkrnl::KeQueryInterruptTime RETURN(InterruptTime); } +// Xbox Performance Counter Frequency = 337F98 = ACPI timer frequency (3.375000 Mhz) +#define XBOX_PERFORMANCE_FREQUENCY 3375000 + +LARGE_INTEGER NativePerformanceCounter = { 0 }; +LARGE_INTEGER NativePerformanceFrequency = { 0 }; +double NativeToXbox_FactorForPerformanceFrequency; + +CXBXKRNL_API void CxbxInitPerformanceCounters() +{ + //BootTickCount = GetTickCount(); + + // Measure current host performance counter and frequency + QueryPerformanceCounter(&NativePerformanceCounter); + QueryPerformanceFrequency(&NativePerformanceFrequency); + // TODO : If anything like speed-stepping influences this, prevent or fix it here + + // Calculate the host-to-xbox performance frequency factor, + // used the return Xbox-like results in KeQueryPerformanceCounter: + NativeToXbox_FactorForPerformanceFrequency = (double)XBOX_PERFORMANCE_FREQUENCY / NativePerformanceFrequency.QuadPart; +} + // ****************************************************************** // * 0x007E - KeQueryPerformanceCounter() // ****************************************************************** @@ -431,11 +452,19 @@ XBSYSAPI EXPORTNUM(126) xboxkrnl::ULONGLONG NTAPI xboxkrnl::KeQueryPerformanceCo { LOG_FUNC(); - ::LARGE_INTEGER Counter; + ::LARGE_INTEGER PerformanceCounter; - QueryPerformanceCounter(&Counter); + // Dxbx note : Xbox actually uses the RDTSC machine code instruction for this, + // and we we're bound to a single core, so we could do that too, but on Windows + // rdtsc is not a very stable counter, so instead, we'll use the native PeformanceCounter : + QueryPerformanceCounter(&PerformanceCounter); - RETURN(Counter.QuadPart); + // Re-base the performance counter to increase accuracy of the following conversion : + PerformanceCounter.QuadPart -= NativePerformanceCounter.QuadPart; + // We appy a conversion factor here, to fake Xbox1-like increment-speed behaviour : + PerformanceCounter.QuadPart = (ULONGLONG)(NativeToXbox_FactorForPerformanceFrequency * PerformanceCounter.QuadPart); + + RETURN(PerformanceCounter.QuadPart); } // ****************************************************************** @@ -445,12 +474,11 @@ XBSYSAPI EXPORTNUM(127) xboxkrnl::ULONGLONG NTAPI xboxkrnl::KeQueryPerformanceFr { LOG_FUNC(); - // Xbox Performance Counter Frequency := 337F98h - ::LARGE_INTEGER Frequency; + // Dxbx note : We return the real Xbox1 frequency here, + // to make subsequent calculations behave the same as on the real Xbox1 : + ULONGLONG ret = XBOX_PERFORMANCE_FREQUENCY; - QueryPerformanceFrequency(&Frequency); - - RETURN(Frequency.QuadPart); + RETURN(ret); } // ******************************************************************