444 lines
13 KiB
C
444 lines
13 KiB
C
/****************************************************************************
|
|
Description: CPA Timer.lib. Window specific part.
|
|
|
|
Author: F. Jentey.
|
|
Last Update : 03/03/97
|
|
***************************************************************************/
|
|
|
|
|
|
#include "TimerPrv.h"
|
|
#include "Detect.h"
|
|
|
|
#include <ddraw.h>
|
|
|
|
|
|
extern tdstTimer a_stTimerTab[];
|
|
short g_wTimerPeriodOk = 0;
|
|
u_long g_ulPeriodMin;
|
|
|
|
|
|
#ifndef WATCOM
|
|
/******** VISUAL 5 ************/
|
|
|
|
#define RDTSC __asm _emit 0x0F __asm _emit 0x31
|
|
|
|
void fn_vTimerPentiumCounter(stTimerCount *p_stTimerCount)
|
|
{
|
|
__asm
|
|
{
|
|
RDTSC
|
|
mov ebx,dword ptr p_stTimerCount
|
|
mov [ebx],eax
|
|
mov [ebx+4],edx
|
|
}
|
|
}
|
|
|
|
void fn_vTimerWaitVBL(void)
|
|
{
|
|
__asm
|
|
{
|
|
push eax
|
|
push edx
|
|
mov dx,03dah
|
|
Wait_VBLStart:
|
|
in al,dx
|
|
and ax,08h
|
|
jz Wait_VBLStart
|
|
|
|
Wait_VBLEnd:
|
|
in al,dx
|
|
and ax,08h
|
|
jnz Wait_VBLEnd
|
|
|
|
pop edx
|
|
pop eax
|
|
}
|
|
}
|
|
|
|
#else
|
|
/******** WATCOM ************/
|
|
|
|
void fn_vTimerPentiumCounter(stTimerCount *p_stTimerCount);
|
|
#pragma aux fn_vTimerPentiumCounter = \
|
|
"db 0x0F,0x31" \
|
|
"mov [ebx],eax" \
|
|
"mov 4[ebx],edx" \
|
|
parm [ebx] \
|
|
modify [eax edx]
|
|
|
|
void fn_vTimerWaitVBL(void);
|
|
#pragma aux fn_vWaitVBL = \
|
|
"mov dx,03dah" \
|
|
"Wait_VBLStart:" \
|
|
"in al,dx" \
|
|
"and al,08h" \
|
|
"jz Wait_VBLStart" \
|
|
"Wait_VBLEnd:" \
|
|
"in al,dx" \
|
|
"and al,08h" \
|
|
"jnz Wait_VBLEnd" \
|
|
modify [eax edx]
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/****************************************/
|
|
/* Get the clock frequency of the CPU. */
|
|
/****************************************/
|
|
u_long fn_ulTimerCpuClock()
|
|
{
|
|
stTimerCount count1, count2;
|
|
u_long t, ulresult;
|
|
|
|
t = timeGetTime();
|
|
fn_vTimerPentiumCounter(&count1);
|
|
while (timeGetTime()-t < 1000);
|
|
fn_vTimerPentiumCounter(&count2);
|
|
if (count2.m_ulLowPart > count1.m_ulLowPart)
|
|
ulresult = count2.m_ulLowPart - count1.m_ulLowPart;
|
|
else
|
|
ulresult = count2.m_ulLowPart + 4294967295 - count1.m_ulLowPart;
|
|
|
|
if ( ulresult < 63000000 ) return 60000000;
|
|
if ( ulresult < 68000000 ) return 66600000;
|
|
if ( ulresult < 80000000 ) return 75000000;
|
|
if ( ulresult < 94000000 ) return 90000000;
|
|
if ( ulresult < 106000000 ) return 100000000;
|
|
if ( ulresult < 125000000 ) return 120000000;
|
|
if ( ulresult < 138000000 ) return 133300000;
|
|
if ( ulresult < 155000000 ) return 150000000;
|
|
if ( ulresult < 170000000 ) return 166600000;
|
|
if ( ulresult < 185000000 ) return 180000000;
|
|
if ( ulresult < 205000000 ) return 200000000;
|
|
if ( ulresult < 240000000 ) return 233300000;
|
|
if ( ulresult < 272000000 ) return 266600000;
|
|
if ( ulresult < 310000000 ) return 300000000;
|
|
if ( ulresult < 340000000 ) return 333300000;
|
|
if ( ulresult < 356000000 ) return 350000000;
|
|
if ( ulresult < 380000000 ) return 366600000;
|
|
/* ANNECY AV*/
|
|
if ( ulresult < 425000000 ) return 400000000;
|
|
if ( ulresult < 475000000 ) return 450000000;
|
|
if ( ulresult < 525000000 ) return 500000000;
|
|
if ( ulresult < 575000000 ) return 550000000;
|
|
if ( ulresult < 625000000 ) return 600000000;
|
|
return ulresult;
|
|
/* END ANNECY AV*/
|
|
}
|
|
|
|
|
|
/***************************************************************/
|
|
/* This function return the number of CPU cycle of a frame. */
|
|
/***************************************************************/
|
|
u_long fn_ulTimerFrameLength()
|
|
{
|
|
LPDIRECTDRAW lpDD;
|
|
HRESULT ddrval;
|
|
stTimerCount stBefore, stAfter;
|
|
u_long ulTime,ulSomme = 0;
|
|
long i;
|
|
|
|
if (!fn_lIsRdtscAvailable()) return (0);
|
|
|
|
ddrval = DirectDrawCreate(NULL, &lpDD, NULL);
|
|
if (ddrval != DD_OK) lpDD = NULL;
|
|
|
|
ulTime = 0;
|
|
fn_vTimerPentiumCounter(&stBefore); /* La fonction Direct Draw WaitForVerticalBlank */
|
|
for (i=0; i<64; i++) /* ne fonctionne pas correctement sous 95 !? */
|
|
{
|
|
unsigned long ulNewTime;
|
|
ddrval = IDirectDraw_WaitForVerticalBlank(lpDD,DDWAITVB_BLOCKBEGIN, NULL);
|
|
if (ddrval != DD_OK) return (0);
|
|
ulNewTime = timeGetTime();
|
|
if (ulNewTime-ulTime < 5) return (0);
|
|
ulTime = ulNewTime;
|
|
}
|
|
fn_vTimerPentiumCounter(&stAfter);
|
|
if (stAfter.m_ulLowPart > stBefore.m_ulLowPart )
|
|
ulSomme = stAfter.m_ulLowPart - stBefore.m_ulLowPart;
|
|
else
|
|
ulSomme = stAfter.m_ulLowPart + 4294967295 - stBefore.m_ulLowPart;
|
|
stBefore.m_ulLowPart = stAfter.m_ulLowPart;
|
|
|
|
if (lpDD) IDirectDraw_Release(lpDD);
|
|
|
|
return (ulSomme >> 6);
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
/* Set the precision (in millisecond) of the timeGetTime and */
|
|
/* setEvent function */
|
|
/******************************************************************/
|
|
void fn_vSetTimePeriod()
|
|
{
|
|
TIMECAPS tc;
|
|
MMRESULT err;
|
|
|
|
if (!g_wTimerPeriodOk)
|
|
{
|
|
err = timeGetDevCaps(&tc, sizeof(TIMECAPS));
|
|
if (err != TIMERR_NOERROR)
|
|
g_ulPeriodMin = 0;
|
|
else
|
|
{
|
|
g_ulPeriodMin = min( max( tc.wPeriodMin, 1 ), tc.wPeriodMax);
|
|
/* TO DO: Test the result */
|
|
timeBeginPeriod(g_ulPeriodMin);
|
|
}
|
|
g_wTimerPeriodOk = 1;
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/* Return the frequency of the specified timer type in tick per second */
|
|
/**************************************************************************/
|
|
u_long fn_ulTimerTickPerSecond(short wTimerType)
|
|
{
|
|
LARGE_INTEGER perf;
|
|
u_long ulTicksPerSecond;
|
|
|
|
switch (wTimerType)
|
|
{
|
|
case C_wTimerFrequencyLow:
|
|
fn_vSetTimePeriod();
|
|
ulTicksPerSecond = 1000;
|
|
break;
|
|
|
|
case C_wTimerFrequencyMedium:
|
|
if ( QueryPerformanceFrequency(&perf) == TRUE )
|
|
ulTicksPerSecond = perf.LowPart;
|
|
else
|
|
ulTicksPerSecond = 0;
|
|
break;
|
|
|
|
case C_wTimerFrequencyHigh:
|
|
if (fn_lIsRdtscAvailable())
|
|
ulTicksPerSecond = fn_ulTimerCpuClock();
|
|
else
|
|
ulTicksPerSecond = 0;
|
|
break;
|
|
|
|
default:
|
|
ulTicksPerSecond = 0;
|
|
}
|
|
|
|
return (ulTicksPerSecond);
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* Return the frequency of the specified event type in tick per second */
|
|
/*************************************************************************/
|
|
u_long fn_ulTimerEventTickPerSecond(short wTimerType)
|
|
{
|
|
/* TIMECAPS tc;
|
|
MMRESULT err;*/
|
|
u_long ulTicksPerSecond;
|
|
|
|
switch (wTimerType)
|
|
{
|
|
case C_wTimerFrequencyLow:
|
|
/*err = timeGetDevCaps(&tc, sizeof(TIMECAPS));
|
|
if ( err != TIMERR_NOERROR )
|
|
ulTicksPerSecond = 0;
|
|
else
|
|
{ UINT
|
|
ulTicksPerSecond = min( max( tc.wPeriodMin, 1 ), tc.wPeriodMax);
|
|
TO DO Test the result*/
|
|
/* timeBeginPeriod(ulTicksPerSecond);*/
|
|
fn_vSetTimePeriod();
|
|
ulTicksPerSecond = 1000;
|
|
break;
|
|
|
|
case C_wTimerFrequencyMedium: /* Not Available */
|
|
ulTicksPerSecond = 0;
|
|
break;
|
|
|
|
case C_wTimerFrequencyHigh: /* Not Available */
|
|
ulTicksPerSecond = 0;
|
|
break;
|
|
|
|
default:
|
|
ulTicksPerSecond = 0;
|
|
}
|
|
|
|
return ulTicksPerSecond;
|
|
}
|
|
|
|
|
|
/*********************************************************/
|
|
/* Some operation to release event */
|
|
/*********************************************************/
|
|
short fn_wTimerReleaseEvents(/*u_long* p_EventFreqTab*/)
|
|
{
|
|
/* short wTimerNum;*/
|
|
/* First, kill all events */
|
|
/* for (wTimerNum=0 ; wTimerNum < C_uwTimerMaxCount ; wTimerNum++ )
|
|
{
|
|
if ( (a_stTimerTab[wTimerNum].m_wTimerType >= C_wTimerEvent)
|
|
&& (a_stTimerTab[wTimerNum].m_wTimerState != C_wTimerUnused) )
|
|
{
|
|
timeKillEvent( a_stTimerTab[wTimerNum].m_ulEventId );
|
|
}
|
|
}
|
|
*/
|
|
/* TO DO */
|
|
/* Test if timeBeginPeriod succed before */
|
|
timeEndPeriod(g_ulPeriodMin);
|
|
return (0);
|
|
}
|
|
|
|
/*******************************/
|
|
/* Destroy an event */
|
|
/*******************************/
|
|
short fn_wTimerDestroyEvent(u_long ulEventId)
|
|
{
|
|
/* TO DO */
|
|
/* Test if timeBeginPeriod succed before */
|
|
if (timeKillEvent(ulEventId) != TIMERR_NOERROR)
|
|
return (0);
|
|
else
|
|
return (1);
|
|
}
|
|
|
|
/***************************************************/
|
|
/* Get the current value of the specified counter */
|
|
/***************************************************/
|
|
void fn_vTimerGetCounter(short wTimerType, stTimerCount* p_stValue)
|
|
{
|
|
u_long ulTemp;
|
|
|
|
switch ( wTimerType )
|
|
{
|
|
case C_wTimerFrequencyLow:
|
|
ulTemp = timeGetTime();
|
|
p_stValue->m_ulLowPart = ulTemp;
|
|
p_stValue->m_ulHighPart = 0;
|
|
break;
|
|
|
|
case C_wTimerFrequencyMedium:
|
|
QueryPerformanceCounter((LARGE_INTEGER*)p_stValue);
|
|
break;
|
|
|
|
case C_wTimerFrequencyHigh:
|
|
fn_vTimerPentiumCounter(p_stValue);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/********************************/
|
|
/* Wait during ulTicksToWait */
|
|
/********************************/
|
|
void fn_vTimerWait(u_long ulTicksToWait)
|
|
{
|
|
u_long ulTick;
|
|
|
|
ulTick = timeGetTime();
|
|
while ( timeGetTime() - ulTick < ulTicksToWait );
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/* Return the number of ticks per second for the fn_wTimerDelay function */
|
|
/***************************************************************************/
|
|
u_long fn_ulTimerWaitTicksPerSecond()
|
|
{
|
|
return (1000);
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/* This is the event server */
|
|
/* This function call the callback function associated with the event */
|
|
/* corresponding to the parameter uTimerID */
|
|
/***************************************************************************/
|
|
void PASCAL fn_vTimerEventsCallback(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
|
|
{
|
|
short wTimerNum;
|
|
|
|
/* First, finf the timer corrsponding to uTimerID */
|
|
for (wTimerNum=0 ; wTimerNum < C_uwTimerMaxCount ; wTimerNum++ )
|
|
{
|
|
if ( a_stTimerTab[wTimerNum].m_wTimerType >= C_wTimerEvent )
|
|
{
|
|
if ( (a_stTimerTab[wTimerNum].m_ulEventId == uTimerID) &&
|
|
(a_stTimerTab[wTimerNum].m_p_fn_vEventCallback) )
|
|
{
|
|
a_stTimerTab[wTimerNum].m_p_fn_vEventCallback();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************/
|
|
/* Create an event */
|
|
/* ulPeriod is the period of the event in ticks */
|
|
/* p_fn_vEventCallback is a pointer to the callback function of the event */
|
|
/* ulEventType must be set with C_ulTimerEventOneTime or C_ulTimerEventPeriodic */
|
|
/***********************************************************************************/
|
|
short fn_wTimerNewEvent(
|
|
u_long ulPeriod,
|
|
u_long ulResolution,
|
|
td_p_fn_vTimerEventCallback p_fn_vEventCallback,
|
|
u_long ulTimerEventType,
|
|
u_long* p_ulEventId
|
|
)
|
|
{
|
|
MMRESULT Id;
|
|
Id = timeSetEvent(
|
|
ulPeriod,
|
|
ulResolution,
|
|
(LPTIMECALLBACK)fn_vTimerEventsCallback,
|
|
0,
|
|
ulTimerEventType
|
|
);
|
|
if (Id == 0L) return (C_wTimerError);
|
|
|
|
*p_ulEventId = Id;
|
|
return (0);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************/
|
|
/* This function return vertical refresh rate. The result is multiple by 100. */
|
|
/* Actualy return 0 if not Intel Pentium */
|
|
/*******************************************************************************/
|
|
u_long fn_ulTimerVerticalRefreshRate(u_long ulCpuClock)
|
|
{
|
|
LPDIRECTDRAW lpDD = NULL;
|
|
HRESULT ddrval;
|
|
u_long ulFrequency;
|
|
float fTempFreq;
|
|
|
|
ddrval = DirectDrawCreate(NULL, &lpDD, NULL);
|
|
if(ddrval == DD_OK)
|
|
{
|
|
ddrval = IDirectDraw_GetMonitorFrequency(lpDD,&ulFrequency);
|
|
IDirectDraw_Release(lpDD);
|
|
if (ddrval == DD_OK)
|
|
{ /* DDraw do not return in Hz*100 */
|
|
if (ulFrequency < 1000) ulFrequency *= 100;
|
|
return (ulFrequency);
|
|
}
|
|
}
|
|
|
|
ulFrequency = fn_ulTimerFrameLength();
|
|
if (ulFrequency==0) return (0);
|
|
|
|
/* Use a float to avoid overflow */
|
|
fTempFreq = (float)ulFrequency;
|
|
fTempFreq = (float)ulCpuClock * (float)100.0 / fTempFreq;
|
|
ulFrequency = (u_long)fTempFreq;
|
|
|
|
return (ulFrequency);
|
|
}
|
|
|