Day 18 done. FPS enforcing.

This commit is contained in:
2026-03-09 22:01:35 -07:00
parent 0717d54f63
commit 46b6f69e33
+53 -20
View File
@@ -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);
} }