I'm looking for a SceneKit expert to suggest some way to work around the bad performance bug in SceneKit's built-in Metal shader compilation in iOS 14.x and macOS Catalyst 11.x. Since I've tried everything I can think of to get Apple to fix the problem (TSI, Feedback, Twitter, Developer Forums, Apple Evangelist), we need a workaround.
Using the Xcode Instruments app with SceneKit tracing, it appears that SceneKit shader compilation can about 100x slower in iOS 14.0, 14.1 and 14.2 Beta (including Beta 4) vs. iOS 13.7. For example, it typically takes SceneKit 1-2ms to compile a shader in iOS 13.7 whereas it can take as much as 200ms in iOS 14.
SceneKit appears to automatically compile a shader each time we add a new model node tree to a parent node in a visible scene.
Loading a typical SceneKit scene of dozens of model nodes in our app can go from taking less than 2 seconds to well over 30 seconds. And since SceneKit shader compilation occurs on the render thread which which appears to be invoked by a CADisplayLink handler, the entire app UI can be completely frozen for many seconds (30+ in testing). This drastically affects the usability of our SceneKit-based app.
And if you consider that to get anything like 60-30 fps scene updating, you need to spend no more than 16-33 msec per frame to avoid frame drops, spending 200 msec each for many frames is really bad. (And if you're trying to get 120 fps on an iPad Pro...)
One issue with this is bug is that it's very inconsistent: I can do one run of the app with Instruments and the compile times will be fine (1-2 msec) and I'll do another few runs and it will be bad for each shader compile (100-200 msec). I think there is some Metal shader caching going on, but I don't know how it works and what causes it to be invalidated.
I've tried dozens of ways to work around this: multiple queues/threads/operations, transactions, deferring node adds to add multiple nodes at once, using perform (avoid: fatal crash bugs), etc. I've tried adding nodes with lights before all other nodes or after all other nodes.
We use PBR materials throughout our models and we have multiple lights with shadows enabled in most scenes (e.g. sun or moon outdoors, lamps indoors) along with environment lighting. Reflections are not enabled in SCNView non-AR mode, though apparently ARSceneView does enable them. We don't typically use any of our own shaders, though a few scenes use custom shader modifiers, which don't appear to have any effect when removed.
Any and all suggestions are greatly appreciated. Thanks!
Here is a sample scene screenshot and the shader compile times from Instruments 12.1 running the app on a iPad Pro 11 (2018) with iOS 14:
00:01.347.989 667.58 µs Compile shader
00:01.349.275 579.62 µs Compile shader
00:01.350.529 779.17 µs Compile shader
00:01.353.772 809.92 µs Compile shader
00:01.358.928 909.54 µs Compile shader
00:01.361.232 831.96 µs Compile shader
00:01.363.443 779.17 µs Compile shader
00:01.371.931 1.09 ms Compile shader
00:02.336.543 786.88 µs Compile shader
00:02.338.079 594.67 µs Compile shader
00:02.344.969 805.38 µs Compile shader
00:02.349.393 845.71 µs Compile shader
00:02.351.679 775.33 µs Compile shader
00:02.353.969 714.75 µs Compile shader
00:02.355.389 578.96 µs Compile shader
00:02.374.813 243.54 ms Compile shader
00:02.619.090 204.87 ms Compile shader
00:02.824.654 203.34 ms Compile shader
00:03.033.721 203.22 ms Compile shader
00:03.245.523 199.92 ms Compile shader
00:03.446.541 641.67 µs Compile shader
00:03.458.231 200.25 ms Compile shader
00:03.670.527 202.03 ms Compile shader
00:03.875.402 200.12 ms Compile shader
00:04.089.184 725.21 µs Compile shader
00:04.091.070 201.98 ms Compile shader
00:04.297.075 212.00 ms Compile shader
00:04.509.799 200.11 ms Compile shader
00:04.710.886 203.88 ms Compile shader
00:04.915.507 199.86 ms Compile shader
00:05.116.368 199.27 ms Compile shader
00:05.316.424 200.51 ms Compile shader
00:05.517.957 203.45 ms Compile shader
00:05.722.065 646.38 µs Compile shader
00:05.723.205 582.29 µs Compile shader
00:05.802.072 831.96 µs Compile shader
00:05.808.265 203.29 ms Compile shader
I've seen similar performance regressions in iOS 14. There are even complete freezes occurring on a SceneKit based ARKit project running in an App Clip. Have you heard about any improvements or workarounds recently?