Day 18 done. FPS enforcing.
This commit is contained in:
+53
-20
@@ -19,6 +19,14 @@
|
|||||||
|
|
||||||
global bool GlobalRunning;
|
global bool GlobalRunning;
|
||||||
|
|
||||||
|
global U64 GlobalPerfCountFrequency;
|
||||||
|
|
||||||
|
#define CONTROLLER_LEFT_THUMB_DEADZONE 8000
|
||||||
|
#define MAX_CONTROLLERS 4
|
||||||
|
SDL_GameController *ControllerHandles[MAX_CONTROLLERS];
|
||||||
|
|
||||||
|
global offscreen_buffer GlobalBackbuffer;
|
||||||
|
|
||||||
internal U32 SafeTruncateUInt64(U64 Value)
|
internal U32 SafeTruncateUInt64(U64 Value)
|
||||||
{
|
{
|
||||||
Assert(Value <= 0xFFFFFFFF);
|
Assert(Value <= 0xFFFFFFFF);
|
||||||
@@ -105,12 +113,6 @@ sdl_window_dimension SDLGetWindowDimension(SDL_Window *Window)
|
|||||||
return Dimension;
|
return Dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CONTROLLER_LEFT_THUMB_DEADZONE 8000
|
|
||||||
#define MAX_CONTROLLERS 4
|
|
||||||
SDL_GameController *ControllerHandles[MAX_CONTROLLERS];
|
|
||||||
|
|
||||||
global offscreen_buffer GlobalBackbuffer;
|
|
||||||
|
|
||||||
internal void SDLResizeTexture(offscreen_buffer *Buffer, SDL_Renderer *Renderer, int Width, int Height)
|
internal void SDLResizeTexture(offscreen_buffer *Buffer, SDL_Renderer *Renderer, int Width, int Height)
|
||||||
{
|
{
|
||||||
if(Buffer->Texture)
|
if(Buffer->Texture)
|
||||||
@@ -295,21 +297,30 @@ internal F32 SDLProcessInputStickValue(F32 Value, S32 DeadZoneThreshold)
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DEFAULT_REFRESH_RATE 60
|
||||||
internal S32 SDLGetWindowRefreshRate(SDL_Window *Window)
|
internal S32 SDLGetWindowRefreshRate(SDL_Window *Window)
|
||||||
{
|
{
|
||||||
SDL_DisplayMode Mode;
|
|
||||||
int DisplayIndex = SDL_GetWindowDisplayIndex(Window);
|
int DisplayIndex = SDL_GetWindowDisplayIndex(Window);
|
||||||
// If we can't find the refresh rate, we'll return this:
|
SDL_DisplayMode Mode;
|
||||||
int DefaultRefreshRate = 60;
|
|
||||||
if(SDL_GetDesktopDisplayMode(DisplayIndex, &Mode) != 0)
|
if(SDL_GetDesktopDisplayMode(DisplayIndex, &Mode) != 0)
|
||||||
return DefaultRefreshRate;
|
return DEFAULT_REFRESH_RATE;
|
||||||
if(Mode.refresh_rate == 0)
|
if(Mode.refresh_rate == 0)
|
||||||
return DefaultRefreshRate;
|
return DEFAULT_REFRESH_RATE;
|
||||||
return Mode.refresh_rate;
|
return Mode.refresh_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal U64 SDLGetWallClock()
|
||||||
|
{
|
||||||
|
return SDL_GetPerformanceCounter();
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
internal F32 SDLGetSecondsElapsed(U64 Start, U64 End)
|
||||||
|
{
|
||||||
|
return (F32)(End - Start) / (F32)GlobalPerfCountFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
S32 main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_GAMECONTROLLER|SDL_INIT_AUDIO)) {
|
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_GAMECONTROLLER|SDL_INIT_AUDIO)) {
|
||||||
/* TODO: This didn't work . . . */
|
/* TODO: This didn't work . . . */
|
||||||
@@ -320,7 +331,8 @@ int main(int argc, char *argv[])
|
|||||||
SDL_Window *Window = SDL_CreateWindow("Handmade Hero", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 700, 500, SDL_WINDOW_RESIZABLE);
|
SDL_Window *Window = SDL_CreateWindow("Handmade Hero", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 700, 500, SDL_WINDOW_RESIZABLE);
|
||||||
|
|
||||||
if(Window) {
|
if(Window) {
|
||||||
SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, 0);
|
//SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, 0);
|
||||||
|
SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, SDL_RENDERER_PRESENTVSYNC);
|
||||||
// "Wayland needs an event loop and rendering or it won't function." https://github.com/libsdl-org/SDL/issues/7699#issuecomment-1545684792
|
// "Wayland needs an event loop and rendering or it won't function." https://github.com/libsdl-org/SDL/issues/7699#issuecomment-1545684792
|
||||||
// NOTE: This means that we need to readraw to even resize the window, otherwise the window frame will appear outdated to its actual size.
|
// NOTE: This means that we need to readraw to even resize the window, otherwise the window frame will appear outdated to its actual size.
|
||||||
// SDL_RenderPresent(Renderer) is enough to display the window.
|
// SDL_RenderPresent(Renderer) is enough to display the window.
|
||||||
@@ -368,18 +380,24 @@ int main(int argc, char *argv[])
|
|||||||
game_input *OldInput = &Input[1];
|
game_input *OldInput = &Input[1];
|
||||||
memset(&Input, 0, sizeof(Input));
|
memset(&Input, 0, sizeof(Input));
|
||||||
|
|
||||||
U64 PerfCountFrequency = SDL_GetPerformanceFrequency();
|
GlobalPerfCountFrequency = SDL_GetPerformanceFrequency();
|
||||||
|
|
||||||
U64 LastCounter;
|
U64 LastCounter;
|
||||||
#if ARCH_X64 || ARCH_X86
|
#if ARCH_X64 || ARCH_X86
|
||||||
U64 LastCycleCount;
|
U64 LastCycleCount;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while(GlobalRunning) {
|
while(GlobalRunning) {
|
||||||
LastCounter = SDL_GetPerformanceCounter();
|
LastCounter = SDLGetWallClock();
|
||||||
|
|
||||||
#if ARCH_X64 || ARCH_X86
|
#if ARCH_X64 || ARCH_X86
|
||||||
LastCycleCount = __rdtsc(); // NOTE: rdtsc reports clock cylces, however it is not meant for really precise profiler work as the value returned is varied.
|
LastCycleCount = __rdtsc(); // NOTE: rdtsc reports clock cylces, however it is not meant for really precise profiler work as the value returned is varied.
|
||||||
#endif // Also, __rdtsc is not available on MacOS ARM; I have not checked MacOS x64.
|
#endif // Also, __rdtsc is not available on MacOS ARM; I have not checked MacOS x64.
|
||||||
|
|
||||||
|
S32 MonitorRefreshHz = SDLGetWindowRefreshRate(Window);
|
||||||
|
S32 GameUpdateHz = MonitorRefreshHz;
|
||||||
|
F32 TargetSecondsPerFrame = 1.0f / (F32)GameUpdateHz;
|
||||||
|
|
||||||
game_controller_input *OldKeyboardController = GetController(OldInput, 0);
|
game_controller_input *OldKeyboardController = GetController(OldInput, 0);
|
||||||
game_controller_input *NewKeyboardController = GetController(NewInput, 0);
|
game_controller_input *NewKeyboardController = GetController(NewInput, 0);
|
||||||
game_controller_input ZeroController = {0};
|
game_controller_input ZeroController = {0};
|
||||||
@@ -466,12 +484,28 @@ int main(int argc, char *argv[])
|
|||||||
GameUpdateAndRender(&GameMemory, NewInput, &Buffer, &SoundBuffer);
|
GameUpdateAndRender(&GameMemory, NewInput, &Buffer, &SoundBuffer);
|
||||||
SDLFillSoundBuffer(&SoundOutput, BytesToWrite);
|
SDLFillSoundBuffer(&SoundOutput, BytesToWrite);
|
||||||
|
|
||||||
|
U64 WorkCounter = SDLGetWallClock();
|
||||||
|
F32 WorkSecondsElapsed = SDLGetSecondsElapsed(LastCounter, WorkCounter);
|
||||||
|
|
||||||
|
F32 SecondsElapsedForFrame = WorkSecondsElapsed;
|
||||||
|
if(SecondsElapsedForFrame < TargetSecondsPerFrame) {
|
||||||
|
while(SecondsElapsedForFrame < TargetSecondsPerFrame) {
|
||||||
|
SecondsElapsedForFrame = SDLGetSecondsElapsed(LastCounter, SDLGetWallClock());
|
||||||
|
SDL_Delay((U32)((TargetSecondsPerFrame - SecondsElapsedForFrame) * 1000.0f));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: Missed frame rate!
|
||||||
|
// TODO: Logging.
|
||||||
|
}
|
||||||
|
|
||||||
|
U64 EndCounter = SDLGetWallClock();
|
||||||
|
|
||||||
SDLDisplayBufferInWindow(GlobalBackbuffer, Window, Renderer);
|
SDLDisplayBufferInWindow(GlobalBackbuffer, Window, Renderer);
|
||||||
|
|
||||||
U64 EndCounter = SDL_GetPerformanceCounter();
|
F64 MSPerFrame = 1000.0f * SDLGetSecondsElapsed(LastCounter, EndCounter);
|
||||||
U64 CounterElapsed = EndCounter - LastCounter;
|
F64 FPS = 0.0f;
|
||||||
F64 MSPerFrame = (((1000.0f * (F64)CounterElapsed) / (F64)PerfCountFrequency));
|
|
||||||
F64 FPS = (F64)PerfCountFrequency / (F64)CounterElapsed;
|
LastCounter = EndCounter;
|
||||||
|
|
||||||
#if ARCH_X64 || ARCH_X86
|
#if ARCH_X64 || ARCH_X86
|
||||||
U64 EndCycleCount = __rdtsc();
|
U64 EndCycleCount = __rdtsc();
|
||||||
@@ -482,7 +516,6 @@ int main(int argc, char *argv[])
|
|||||||
#else
|
#else
|
||||||
fprintf(stderr, "%.02f ms/f, %.02f/s\n", MSPerFrame, FPS);
|
fprintf(stderr, "%.02f ms/f, %.02f/s\n", MSPerFrame, FPS);
|
||||||
#endif
|
#endif
|
||||||
LastCounter = EndCounter;
|
|
||||||
|
|
||||||
Swap(game_input *, NewInput, OldInput);
|
Swap(game_input *, NewInput, OldInput);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user