diff --git a/src/sdl/hardware.cpp b/src/sdl/hardware.cpp index ef78b4c310..49730802bf 100644 --- a/src/sdl/hardware.cpp +++ b/src/sdl/hardware.cpp @@ -33,6 +33,8 @@ */ #include +#include +#include #include "hardware.h" #include "i_video.h" @@ -175,10 +177,89 @@ void I_ClosestResolution (int *width, int *height, int bits) return; } } -} +} + +//========================================================================== +// +// SetFPSLimit +// +// Initializes an event timer to fire at a rate of /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) { + 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; diff --git a/src/sdl/hardware.h b/src/sdl/hardware.h index 651d3ee2b4..86f3bd2426 100644 --- a/src/sdl/hardware.h +++ b/src/sdl/hardware.h @@ -37,6 +37,29 @@ #include "i_video.h" #include "v_video.h" +// Semaphores +#ifdef __APPLE__ +#include +#include +#include +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 +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 { public: @@ -59,6 +82,7 @@ void I_InitGraphics (); void I_ShutdownGraphics (); void I_CreateRenderer(); +extern Semaphore FPSLimitSemaphore; void I_SetFPSLimit(int limit); extern IVideo *Video; diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index f7ca515d3b..df15ce774c 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -38,14 +38,6 @@ #include #endif -#ifdef __APPLE__ -#include -#include -#include -#else -#include -#endif - #include "doomerrors.h" #include @@ -144,11 +136,7 @@ static DWORD BaseTime; static int TicFrozen; // Signal based timer. -#ifdef __APPLE__ -static semaphore_t timerWait; -#else -static sem_t timerWait; -#endif +static Semaphore timerWait; static int tics; static DWORD sig_start, sig_next; @@ -221,12 +209,7 @@ int I_WaitForTicSignaled (int prevtic) while(tics <= prevtic) { -#ifdef __APPLE__ - while(semaphore_wait(timerWait) != KERN_SUCCESS) - ; -#else - while(sem_wait(&timerWait) != 0); -#endif + SEMAPHORE_WAIT(timerWait) } return tics; @@ -276,11 +259,7 @@ void I_HandleAlarm (int sig) tics++; sig_start = SDL_GetTicks(); sig_next = Scale((Scale (sig_start, TICRATE, 1000) + 1), 1000, TICRATE); -#ifdef __APPLE__ - semaphore_signal(timerWait); -#else - sem_post(&timerWait); -#endif + SEMAPHORE_SIGNAL(timerWait) } // @@ -290,11 +269,7 @@ void I_HandleAlarm (int sig) // void I_SelectTimer() { -#ifdef __APPLE__ - semaphore_create(mach_task_self(), &timerWait, 0, 0); -#else - sem_init(&timerWait, 0, 0); -#endif + SEMAPHORE_INIT(timerWait, 0, 0) signal(SIGALRM, I_HandleAlarm); struct itimerval itv; diff --git a/src/sdl/sdlvideo.cpp b/src/sdl/sdlvideo.cpp index 26723c583e..f0a3245658 100644 --- a/src/sdl/sdlvideo.cpp +++ b/src/sdl/sdlvideo.cpp @@ -80,6 +80,7 @@ extern SDL_Rect cursorBlit; extern bool GUICapture; EXTERN_CVAR (Float, Gamma) +EXTERN_CVAR (Int, vid_maxfps) // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -374,6 +375,11 @@ void SDLFB::Update () DrawRateStuff (); + if(vid_maxfps) + { + SEMAPHORE_WAIT(FPSLimitSemaphore) + } + Buffer = NULL; LockCount = 0; UpdatePending = false;