diff --git a/sdl_handmade.cpp b/sdl_handmade.cpp index ea34ea3..bd9ad00 100644 --- a/sdl_handmade.cpp +++ b/sdl_handmade.cpp @@ -19,6 +19,14 @@ 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) { Assert(Value <= 0xFFFFFFFF); @@ -105,12 +113,6 @@ sdl_window_dimension SDLGetWindowDimension(SDL_Window *Window) 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) { if(Buffer->Texture) @@ -295,21 +297,30 @@ internal F32 SDLProcessInputStickValue(F32 Value, S32 DeadZoneThreshold) return Result; } +#define DEFAULT_REFRESH_RATE 60 internal S32 SDLGetWindowRefreshRate(SDL_Window *Window) { - SDL_DisplayMode Mode; int DisplayIndex = SDL_GetWindowDisplayIndex(Window); - // If we can't find the refresh rate, we'll return this: - int DefaultRefreshRate = 60; + SDL_DisplayMode Mode; + if(SDL_GetDesktopDisplayMode(DisplayIndex, &Mode) != 0) - return DefaultRefreshRate; + return DEFAULT_REFRESH_RATE; if(Mode.refresh_rate == 0) - return DefaultRefreshRate; + return DEFAULT_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)) { /* 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); 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 // 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. @@ -368,18 +380,24 @@ int main(int argc, char *argv[]) game_input *OldInput = &Input[1]; memset(&Input, 0, sizeof(Input)); - U64 PerfCountFrequency = SDL_GetPerformanceFrequency(); + GlobalPerfCountFrequency = SDL_GetPerformanceFrequency(); + U64 LastCounter; #if ARCH_X64 || ARCH_X86 U64 LastCycleCount; #endif while(GlobalRunning) { - LastCounter = SDL_GetPerformanceCounter(); + LastCounter = SDLGetWallClock(); + #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. #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 *NewKeyboardController = GetController(NewInput, 0); game_controller_input ZeroController = {0}; @@ -466,12 +484,28 @@ int main(int argc, char *argv[]) GameUpdateAndRender(&GameMemory, NewInput, &Buffer, &SoundBuffer); 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); - U64 EndCounter = SDL_GetPerformanceCounter(); - U64 CounterElapsed = EndCounter - LastCounter; - F64 MSPerFrame = (((1000.0f * (F64)CounterElapsed) / (F64)PerfCountFrequency)); - F64 FPS = (F64)PerfCountFrequency / (F64)CounterElapsed; + F64 MSPerFrame = 1000.0f * SDLGetSecondsElapsed(LastCounter, EndCounter); + F64 FPS = 0.0f; + + LastCounter = EndCounter; #if ARCH_X64 || ARCH_X86 U64 EndCycleCount = __rdtsc(); @@ -482,7 +516,6 @@ int main(int argc, char *argv[]) #else fprintf(stderr, "%.02f ms/f, %.02f/s\n", MSPerFrame, FPS); #endif - LastCounter = EndCounter; Swap(game_input *, NewInput, OldInput); }