- Ported frame rate limiting code to SDL.

SVN r3891 (trunk)
This commit is contained in:
Braden Obrzut 2012-10-17 19:45:04 +00:00
parent 441f633983
commit 1907983ab7
4 changed files with 116 additions and 30 deletions

View File

@ -33,6 +33,8 @@
*/ */
#include <SDL.h> #include <SDL.h>
#include <signal.h>
#include <time.h>
#include "hardware.h" #include "hardware.h"
#include "i_video.h" #include "i_video.h"
@ -175,10 +177,89 @@ void I_ClosestResolution (int *width, int *height, int bits)
return; return;
} }
} }
} }
//==========================================================================
//
// SetFPSLimit
//
// Initializes an event timer to fire at a rate of <limit>/sec. The video
// update will wait for this timer to trigger before updating.
//
// Pass 0 as the limit for unlimited.
// Pass a negative value for the limit to use the value of vid_maxfps.
//
//==========================================================================
EXTERN_CVAR(Int, vid_maxfps);
EXTERN_CVAR(Bool, cl_capfps);
Semaphore FPSLimitSemaphore;
static void FPSLimitNotify(sigval val)
{
SEMAPHORE_SIGNAL(FPSLimitSemaphore)
}
void I_SetFPSLimit(int limit) void I_SetFPSLimit(int limit)
{ {
static sigevent FPSLimitEvent;
static timer_t FPSLimitTimer;
static bool FPSLimitTimerEnabled = false;
static bool EventSetup = false;
if(!EventSetup)
{
EventSetup = true;
FPSLimitEvent.sigev_notify = SIGEV_THREAD;
FPSLimitEvent.sigev_signo = 0;
FPSLimitEvent.sigev_value.sival_int = 0;
FPSLimitEvent.sigev_notify_function = FPSLimitNotify;
FPSLimitEvent.sigev_notify_attributes = NULL;
SEMAPHORE_INIT(FPSLimitSemaphore, 0, 0)
}
if (limit < 0)
{
limit = vid_maxfps;
}
// Kill any leftover timer.
if (FPSLimitTimerEnabled)
{
timer_delete(FPSLimitTimer);
FPSLimitTimerEnabled = false;
}
if (limit == 0)
{ // no limit
DPrintf("FPS timer disabled\n");
}
else
{
FPSLimitTimerEnabled = true;
if(timer_create(CLOCK_REALTIME, &FPSLimitEvent, &FPSLimitTimer) == -1)
Printf("Failed to create FPS limitter event\n");
itimerspec period = { {0, 0}, {0, 0} };
period.it_value.tv_nsec = period.it_interval.tv_nsec = 1000000000 / limit;
if(timer_settime(FPSLimitTimer, 0, &period, NULL) == -1)
Printf("Failed to set FPS limitter timer\n");
DPrintf("FPS timer set to %u ms\n", (unsigned int) period.it_interval.tv_nsec / 1000000);
}
}
CUSTOM_CVAR (Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (vid_maxfps < TICRATE && vid_maxfps != 0)
{
vid_maxfps = TICRATE;
}
else if (vid_maxfps > 1000)
{
vid_maxfps = 1000;
}
else if (cl_capfps == 0)
{
I_SetFPSLimit(vid_maxfps);
}
} }
extern int NewWidth, NewHeight, NewBits, DisplayBits; extern int NewWidth, NewHeight, NewBits, DisplayBits;

View File

@ -37,6 +37,29 @@
#include "i_video.h" #include "i_video.h"
#include "v_video.h" #include "v_video.h"
// Semaphores
#ifdef __APPLE__
#include <mach/mach_init.h>
#include <mach/semaphore.h>
#include <mach/task.h>
typedef semaphore_t Semaphore;
#define SEMAPHORE_WAIT(sem) \
while(semaphore_wait(sem) != KERN_SUCCESS){}
#define SEMAPHORE_SIGNAL(sem) \
semaphore_signal(sem)
#define SEMAPHORE_INIT(sem, shared, value) \
semaphore_create(mach_task_self(), &sem, shared, value);
#else
#include <semaphore.h>
typedef sem_t Semaphore;
#define SEMAPHORE_WAIT(sem) \
while(sem_wait(&sem) != 0);
#define SEMAPHORE_SIGNAL(sem) \
sem_post(&sem);
#define SEMAPHORE_INIT(sem, shared, value) \
sem_init(&sem, shared, value);
#endif
class IVideo class IVideo
{ {
public: public:
@ -59,6 +82,7 @@ void I_InitGraphics ();
void I_ShutdownGraphics (); void I_ShutdownGraphics ();
void I_CreateRenderer(); void I_CreateRenderer();
extern Semaphore FPSLimitSemaphore;
void I_SetFPSLimit(int limit); void I_SetFPSLimit(int limit);
extern IVideo *Video; extern IVideo *Video;

View File

@ -38,14 +38,6 @@
#include <gdk/gdkkeysyms.h> #include <gdk/gdkkeysyms.h>
#endif #endif
#ifdef __APPLE__
#include <mach/mach_init.h>
#include <mach/semaphore.h>
#include <mach/task.h>
#else
#include <semaphore.h>
#endif
#include "doomerrors.h" #include "doomerrors.h"
#include <math.h> #include <math.h>
@ -144,11 +136,7 @@ static DWORD BaseTime;
static int TicFrozen; static int TicFrozen;
// Signal based timer. // Signal based timer.
#ifdef __APPLE__ static Semaphore timerWait;
static semaphore_t timerWait;
#else
static sem_t timerWait;
#endif
static int tics; static int tics;
static DWORD sig_start, sig_next; static DWORD sig_start, sig_next;
@ -221,12 +209,7 @@ int I_WaitForTicSignaled (int prevtic)
while(tics <= prevtic) while(tics <= prevtic)
{ {
#ifdef __APPLE__ SEMAPHORE_WAIT(timerWait)
while(semaphore_wait(timerWait) != KERN_SUCCESS)
;
#else
while(sem_wait(&timerWait) != 0);
#endif
} }
return tics; return tics;
@ -276,11 +259,7 @@ void I_HandleAlarm (int sig)
tics++; tics++;
sig_start = SDL_GetTicks(); sig_start = SDL_GetTicks();
sig_next = Scale((Scale (sig_start, TICRATE, 1000) + 1), 1000, TICRATE); sig_next = Scale((Scale (sig_start, TICRATE, 1000) + 1), 1000, TICRATE);
#ifdef __APPLE__ SEMAPHORE_SIGNAL(timerWait)
semaphore_signal(timerWait);
#else
sem_post(&timerWait);
#endif
} }
// //
@ -290,11 +269,7 @@ void I_HandleAlarm (int sig)
// //
void I_SelectTimer() void I_SelectTimer()
{ {
#ifdef __APPLE__ SEMAPHORE_INIT(timerWait, 0, 0)
semaphore_create(mach_task_self(), &timerWait, 0, 0);
#else
sem_init(&timerWait, 0, 0);
#endif
signal(SIGALRM, I_HandleAlarm); signal(SIGALRM, I_HandleAlarm);
struct itimerval itv; struct itimerval itv;

View File

@ -80,6 +80,7 @@ extern SDL_Rect cursorBlit;
extern bool GUICapture; extern bool GUICapture;
EXTERN_CVAR (Float, Gamma) EXTERN_CVAR (Float, Gamma)
EXTERN_CVAR (Int, vid_maxfps)
// PUBLIC DATA DEFINITIONS ------------------------------------------------- // PUBLIC DATA DEFINITIONS -------------------------------------------------
@ -374,6 +375,11 @@ void SDLFB::Update ()
DrawRateStuff (); DrawRateStuff ();
if(vid_maxfps)
{
SEMAPHORE_WAIT(FPSLimitSemaphore)
}
Buffer = NULL; Buffer = NULL;
LockCount = 0; LockCount = 0;
UpdatePending = false; UpdatePending = false;