Files
FC1/CrySystem/Timer.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

365 lines
8.7 KiB
C++

//////////////////////////////////////////////////////////////////////
//
// Crytek CryENGINE Source code
//
// File:Timer.cpp
// Description: Implementation of the timer class: timing functions
//
// History:
// -Jan 31,2001:Created by Marco Corbetta
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Timer.h"
#include <ISystem.h>
#include <IConsole.h>
#include <ILog.h>
/////////////////////////////////////////////////////
#ifndef _XBOX
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#include "Mmsystem.h"
#endif
#else
#include <xtl.h>
#endif
//this should not be included here
#include <IRenderer.h> // needed for m_pSystem->GetIRenderer()->EF_Query(EFQ_RecurseLevel)
//#define PROFILING 1
#ifdef PROFILING
static int64 g_lCurrentTime = 0;
#endif
/////////////////////////////////////////////////////
CTimer::CTimer()
{
m_pfnUpdate=NULL;
m_lBaseTime=0;
m_lLastTime=0;
m_lTicksPerSec=0;
m_lCurrentTime=0;
m_fFrameTime=0;
m_fCurrTime=0;
m_fixed_time_step = 0;
m_e_time_profiling = 0;
m_e_time_smoothing = 0;
// smoothing
m_timecount=0;
for (int k=0;k<FPS_FRAMES;k++)
m_previousTimes[k]=0;
m_nCurProfLine=0;
m_fProfStartTime = -1;
memset(m_TimeInfoTable,0,sizeof(m_TimeInfoTable));
m_nCurProfLinesNum = 0;
m_fStatsLogic = m_fStatsRender = m_fStatsSumm = 0;
m_bEnabled=true;
}
//init the timer
/////////////////////////////////////////////////////
bool CTimer::Init(ISystem *pSystem)
{
m_pSystem=pSystem;
m_pSystem->GetIConsole()->Register("e_time_profiling",&m_e_time_profiling,0,0,"0=off, 1=??, 2=peak profiling, 3=??");
m_pSystem->GetIConsole()->Register("e_time_smoothing",&m_e_time_smoothing,0,0,"[0..15] 0=no smoothing, x=x additional steps"); // FPS_FRAMES-1=15
m_pSystem->GetIConsole()->Register( "fixed_time_step",&m_fixed_time_step,0,0,"Game updated with this fixed time step" );
#if !defined (PS2) && !defined (GC)
LARGE_INTEGER TTicksPerSec;
if (QueryPerformanceFrequency(&TTicksPerSec))
{
// performance counter is available, use it instead of multimedia timer
LARGE_INTEGER t;
QueryPerformanceCounter( &t );
m_lTicksPerSec=TTicksPerSec.QuadPart;
m_pfnUpdate = &CTimer::GetPerformanceCounterTime;
}
else
{
//Use MM timer if unable to use the High Frequency timer
m_lTicksPerSec=1000;
m_pfnUpdate = &CTimer::GetMMTime;
}
Reset();
return (true);
#else
return (false);
#endif
}
//get frame rate
/////////////////////////////////////////////////////
float CTimer::GetFrameRate()
{
float diff=GetFrameTime();
if (diff) return (1.0f/diff);
return (0);
}
void CTimer::RefreshCurrTime()
{
double dVal=(double)m_lCurrentTime;
m_fCurrTime=(float)(dVal/(double)(m_lTicksPerSec));
assert(m_fCurrTime>=0);
}
//update the timer
/////////////////////////////////////////////////////
void CTimer::Update()
{
if(!m_bEnabled)
return;
#ifdef PROFILING
m_fFrameTime = 20; //20ms = 50fps
g_lCurrentTime += (int)(m_fFrameTime*(float)(TIMEVALUE_PRECISION));
m_lCurrentTime = g_lCurrentTime;
m_lLastTime = m_lCurrentTime;
RefreshCurrTime();
return;
#endif
if (m_fixed_time_step != 0)
{
m_fFrameTime = m_fixed_time_step;
m_lCurrentTime += (int64)(m_fixed_time_step*(float)(m_lTicksPerSec));
m_lLastTime = m_lCurrentTime;
RefreshCurrTime();
return;
}
m_lCurrentTime = (*m_pfnUpdate)() - m_lBaseTime;
RefreshCurrTime();
m_fFrameTime=(float)(m_lCurrentTime-m_lLastTime) / (float)(m_lTicksPerSec);
if (m_fFrameTime < 0)
m_fFrameTime = 0;
if(m_e_time_smoothing>0)
{
if(m_e_time_smoothing>FPS_FRAMES-1)
m_e_time_smoothing=FPS_FRAMES-2;
if(m_fFrameTime < 0.0000001f)
m_fFrameTime = 0.0000001f;
m_previousTimes[m_timecount] = m_fFrameTime;
m_timecount++;
if(m_timecount>=m_e_time_smoothing)
m_timecount=0;
// average multiple frames together to smooth changes out a bit
float total = 0;
for (int i = 0 ; i < m_e_time_smoothing+1; i++ )
total += m_previousTimes[i];
if (!total)
total = 1;
m_fFrameTime=total/(float)(m_e_time_smoothing+1);
}
m_lLastTime = m_lCurrentTime;
}
//reset the timer
/////////////////////////////////////////////////////
void CTimer::Reset()
{
m_lBaseTime = (*m_pfnUpdate)();
m_lLastTime = m_lCurrentTime = 0;
m_fFrameTime = 0;
RefreshCurrTime();
}
void CTimer::Enable(bool bEnable)
{
if(!bEnable)
m_fFrameTime=0.0001f;
m_bEnabled = bEnable;
};
//get time from performance counter
/////////////////////////////////////////////////////
int64 CTimer::GetPerformanceCounterTime()
{
#ifdef PROFILING
return g_lCurrentTime;
#endif
LARGE_INTEGER lNow;
QueryPerformanceCounter(&lNow);
// for the following calculation even 64bit integer isn't enough
// int64 lCurTime=(lNow.QuadPart*TIMEVALUE_PRECISION) / m_lTicksPerSec;
// int64 lCurTime = (int64)((double)lNow.QuadPart / m_lTicksPerMicroSec);
return lNow.QuadPart;
}
//get time from multimedia timer
/////////////////////////////////////////////////////
int64 CTimer::GetMMTime()
{
int64 lNow=timeGetTime();
return lNow;
}
float CTimer::MeasureTime(LPCSTR szComment)
{
if(m_e_time_profiling==0)
{
m_nCurProfLinesNum = m_nCurProfLine;
m_nCurProfLine = 0;
return (0);
}
if(!szComment)
return 0;
if (!m_pSystem || !m_pSystem->GetIRenderer())
return 0;
if(szComment==(LPCSTR)-1)
szComment=0;
int nRecursionLevel = (int)m_pSystem->GetIRenderer()->EF_Query(EFQ_RecurseLevel) - 1;
if(nRecursionLevel>0)
return 0;
if(m_fProfStartTime == -1) // this var should be initialized only now
m_fProfStartTime = (float)(GetAsyncCurTime()*1000);
float fEnd = (float)(GetAsyncCurTime()*1000);
float fTime = (fEnd - m_fProfStartTime);
m_fProfStartTime = fEnd;
float fMinShowTime = -100.0f;
if (m_e_time_profiling == 3)
fMinShowTime = 0.02f;
if(m_nCurProfLine>=TIME_PROFILE_PARAMS)
return 0;
if( szComment && m_nCurProfLine>=0 && m_nCurProfLine<TIME_PROFILE_PARAMS && strlen(szComment)>0 )
{
assert( (int)strlen(szComment) < sizeof(m_TimeInfoTable[m_nCurProfLine].param_name) );
strcpy(m_TimeInfoTable[m_nCurProfLine].param_name, szComment);
m_TimeInfoTable[m_nCurProfLine].param_name[10]=0; // bad
if(fTime<0)
fTime=0;
if((m_e_time_profiling==2 && fTime>m_TimeInfoTable[m_nCurProfLine].value) || (GetFrameTime()>1))
m_TimeInfoTable[m_nCurProfLine].value = (fTime); // peak profiling
else
m_TimeInfoTable[m_nCurProfLine].value = (fTime+m_TimeInfoTable[m_nCurProfLine].value*50)/51.f;
m_nCurProfLine++;
}
else if(m_e_time_profiling)
{ // detail stats
// m_pSystem->GetIRenderer()->EnableFog(false);
int nLine=0;
float fSumm=0;
#ifndef _XBOX
float fOffs = 78;
#else
float fOffs = 60;
#endif
int nLinesInCollumn=36;
int nCollumns = m_nCurProfLine/nLinesInCollumn;
//if(GetFrameTime()>1)
// m_pSystem->GetILog()->Log("-- Slow frame rate profiling --");
int nColumn = 0;
for(int i=0; i<m_nCurProfLine; i++)
{
if (m_TimeInfoTable[i].value < fMinShowTime)
continue;
if(m_TimeInfoTable[i].param_name[0])
{
float fColorK = (m_TimeInfoTable[i].value>0.1f) ? 1.f : 0.5f;
m_pSystem->GetIRenderer()->TextToScreenColor(
(int)(fOffs-(nCollumns-nColumn/nLinesInCollumn)*20),
(int)(25+((((nLine++)%nLinesInCollumn)*2))),
(m_TimeInfoTable[i].param_name[0]=='3')*fColorK,fColorK,fColorK,1,
"%12s %.02f",
m_TimeInfoTable[i].param_name + (m_TimeInfoTable[i].param_name[0]=='3'),
m_TimeInfoTable[i].value);
//if(GetFrameTime()>1)
// m_pSystem->GetILog()->Log(" %12s %.02f", m_TimeInfoTable[i].param_name, m_TimeInfoTable[i].value);
}
fSumm += m_TimeInfoTable[i].value;
nColumn++;
}
m_pSystem->GetIRenderer()->TextToScreen(
fOffs-(nCollumns-nColumn/nLinesInCollumn)*16,
(float)(25+((((nLine++)%nLinesInCollumn)*2))),
"%12s %.02f", "* Summ *", fSumm);
m_nCurProfLinesNum = m_nCurProfLine;
m_nCurProfLine = 0;
}
/*
if( szComment==0 || szComment[0] == 0 ) // update basic stats
{
float fStatsLogic=0;
float fStatsRender=0;
float fStatsSumm=0;
for(int i=0; i<m_nCurProfLinesNum; i++)
{
if(m_TimeInfoTable[i].param_name[0])
{
if(m_TimeInfoTable[i].param_name[0]=='3')
fStatsRender += m_TimeInfoTable[i].value;
else
fStatsLogic += m_TimeInfoTable[i].value;
}
fStatsSumm += m_TimeInfoTable[i].value;
}
m_fStatsLogic = (m_fStatsLogic +fStatsLogic)*0.5f;
m_fStatsRender = (m_fStatsRender+fStatsRender)*0.5f;
m_fStatsSumm = (m_fStatsSumm +fStatsSumm)*0.5f;
}
*/
return fTime;
}
bool CTimer::GetBasicStats( float & fStatsLogic, float & fStatsRender, float & fStatsSumm )
{
fStatsLogic = m_fStatsLogic;
fStatsRender= m_fStatsRender;
fStatsSumm = m_fStatsSumm;
return fStatsSumm!=0;
}