Posts

Post not yet marked as solved
0 Replies
519 Views
The past few days I've been attempting to solve a bewildering bug: sometimes, for no apparent reason, my Metal-based game will suffer severe performance problems as soon as the app opens, and that sluggishness persists throughout the lifetime of the app. But the biggest problem is that this is not at all consistent -- if I close the app and reopen it, sometimes it will run at a buttery-smooth 60fps. Every time I open the app, I never know whether it will run fast or slow. It's almost like the performance of my app is determined by a coin flip. This is not good.I haven't had any luck reproducing this behavior in a small test case (quite possibly because of its inconsistent nature), so unfortunately I can't share any code, but here's the pertinent info:The window (created with SDL2) has a subview with a CAMetalLayer (framebufferOnly=true, magnificationFilter=nearest, displaySyncEnabled=true, maximumDrawableCount = 3)In the worst-performing cases, the Xcode GPU claims ~4ms are being spent on GPU and the remaining >20ms are on the CPU.My CPU profiler claims the vast majority of the time spent in the app is spent waiting on "nextDrawable". (Which seems to imply that the GPU is actually taking too long, not the CPU? Or maybe it's the driver?)The app is written in C#, so Objective-C block handlers are cumbersome to deal with. Instead, my app just waits on the nextDrawable call at the end of each frame for triple-buffer synchronization, which (at least in my testing) seems to have an equivalent effect.The app uses multisampled textures. Disabling multisampling significantly helps the framerate in the worst-performing case, but of course this isn't a real solution.If I disable vsync, the game tears like crazy but as far as I can tell it always performs well.These tests were performed on a MacBook Pro 13" 2016 (non-touchbar / Intel Iris Graphics 540) running macOS 10.15.1.Here's what I've tried in order to solve this:Reducing the number of render passes and resolve operations. This helped performance when the app was running well, but made no impact on sluggish runs.Using double-buffering instead of triple-buffering. No noticable difference.Moving the nextDrawable call to a background thread, and sleeping the main thread if it wasn't ready by the end of the next frame. No difference.Implementing actual Objective-C block callbacks in C# and using proper semaphores instead of waiting on nextDrawable. No difference.I'm out of ideas at this point. Has anyone else run into something like this? I am 100% open to any suggestions. Thanks!
Posted
by TheSpydog.
Last updated
.