floooh / sokol

minimal cross-platform standalone C headers
https://floooh.github.io/sokol-html5
zlib License
6.93k stars 487 forks source link

Fullscreen FPS on MacMook Pro M1 (Metal backend) is unstable and much lower than a large window #926

Closed tmikov closed 11 months ago

tmikov commented 11 months ago

I have a small simplistic game as a test app (rendering around ten textured rectangles and less than 100 color filled). In windowed mode, when I manually resize the window to cover the entire desktop, the FPS is steady 120FPS. When I maximize it to full screen, it immediately falls to about 90FPS and is generally unstable, rarely if ever reaching 120FPS.

What could be causing this difference? Is this just MacOS weirdness?

Although I doubt anyone would bother looking at the source, it is available. It is a very quick and (very) dirty hack to port a JS game (written by ChatGPT) to C/C++, just to experiment with the APIs. But it is not very complex. There are two versions with similar performance:

floooh commented 11 months ago

It doesn't really explain the difference between windowed and fullscreen, but doing all this stuff for every sprite will be very expensive:

https://github.com/tmikov/gpt-scroller/blob/9de88f40999a06b351031d7eefc6c5b9b7f71bd4/src/demo.cpp#L182-L211

Ideally you'd want to batch many sprites into a single draw call.

Not sure why there's a framerate difference between windowed and fullscreen. The swapchain is completely handled by MTKView so not much I can do there (assuming this is the Metal backend). Maybe it's simply because it's a lot more pixels? Do you have a lot of overdraw?

If you are using the GL backend, then things get murkier, since GL is deprecated all bets are off...

tmikov commented 11 months ago

Not sure why there's a framerate difference between windowed and fullscreen. The swapchain is completely handled by MTKView so not much I can do there (assuming this is the Metal backend). Maybe it's simply because it's a lot more pixels? Do you have a lot of overdraw?

Two possibly important data point:

Is it possible that ProMotion is making stupid decisions about refresh rate based on screen contents with Metal?

There are less than 10 textured quads on screen, alpha blended. Typically less than 100 quad fills (for bullets and explosion particles), again alpha blended. The JS version is exactly the same visually, so it gives a very good idea https://tmikov.github.io/gpt-scroller/ .

I feel that without vsync this should theoretically run at +Infinity FPS 😅 . To be clear I am not criticizing Sokol, I suspect that this is Mac weirdness. I will test this on Windows and Linux as well.

It doesn't really explain the difference between windowed and fullscreen, but doing all this stuff for every sprite will be very expensive:

https://github.com/tmikov/gpt-scroller/blob/9de88f40999a06b351031d7eefc6c5b9b7f71bd4/src/demo.cpp#L182-L211

Sorry for my ignorance, which part is expensive? Am I using the APIs incorrectly? My intuition is that a setting uniforms and issuing literally less than a hundred draw calls per frame should not be expensive (we are not talking millions of triangles here). FWIW, the second version of the app uses a single draw call for all fills and the perf is exactly the same.

tmikov commented 11 months ago

Closing, because I believe the answer is ProMotion is controlling the FPS.