From testing Needle sites on mobile, I am noticing on iOS Safari quite often even a small 3d website can crash on load. I suspect this is Safari keeping the memory of the last tab but I am making some minimal repro sites to test this. It is happening with Safari the app and also with Webviews from safari inside Flutter using Inappwebview plugin
Testing this test site on iPhone 13 mini the main page crashes every time I click back to it after I click a hotspot to go to a product page then the red return button at the top left to go back to the main page. I made this as a test as the main scene with the product in it is 3.2mb and uses Draco + KTX2 compression so I made it as small as possible
It sounds like you’re dealing with a challenging issue related to memory management on iOS Safari. This is not uncommon, as iOS can sometimes struggle with handling large web-based 3D content, especially when switching between tabs or pages.
Here are a few suggestions that might help you:
Memory Management: Since you suspect the issue is related to Safari retaining tabs in memory, try unloading any unnecessary resources when leaving and then reloading them when returning. This might be accomplished by using component lifecycle methods in Needle Engine to clean up and reload resources.
Optimize Resource Management: Ensure that the assets are as optimized as possible:
Make use of LOD (Level of Detail) to reduce poly counts where high detail is not needed.
Ensure textures are appropriately compressed (which you’re already doing with KTX2).
Consider breaking larger scenes into smaller chunks or sections that load dynamically as needed.
Debugging in Needle Engine: Use Needle Engine’s debugging tools to monitor memory usage and identify potential leaks or issues. You might also look at the developer tools in Safari to inspect resource loading.
Test and Profile: Create a simpler version of the scene as a control to compare against your current setup. Gradually increase complexity to pinpoint when issues start. Profiling tools can be helpful in diagnosing where bottlenecks occur.
Webview Settings: Since you’re using InAppWebView from Flutter, ensure that you have set the webview to utilize resources efficiently, possibly limiting the number of simultaneous resources.
If you want more targeted help, providing logs from the Safari developer tools or Needle Engine could offer further insights into what might be causing these crashes.
For reference, check the Needle Engine and three.js documentation for more best practices and tips on managing resources.
Let me know if you need a deeper dive into any of these areas!
24 replies left thread_mmjVv3maBgNbgdwfbNcxQxuO Reply to this message to continue the conversation
From further inspection, this crashing in Safari is more common when moving between two pages with an instance of Needle Engine, suggesting that the new 3d context initializing is the reason for Safari occasionally killing the webpage. If I insert a blank html webpage inbetween the two Needle webpages with a button to load the respective pages, the crash doesn’t happen which suggests Safari is caching the last page for a quick back navigation and the cache for it is cleared when we move 2 pages ahead.
It sounds like you’ve identified a potential workaround for the issue by inserting a blank HTML page between your Needle Engine instances. This approach may help mitigate the crashing by allowing Safari to refresh its context, which can alleviate memory pressure.
Here are a few additional recommendations to further manage the situation:
Optimize Scene Management: Consider implementing scene transitions that unload the current scene before loading the next one. This can help reduce memory usage as the existing context can be cleaned up properly.
Use a Loading Screen: Implement a loading screen that shows while transitioning between scenes. This can give the user feedback while the engine prepares the new context.
Disable Caching: For your Needle pages, you can try disabling caching in the HTTP headers. This could force Safari to reload a fresh instance rather than using a potentially problematic cached version.
Monitor Performance: Utilize performance monitoring tools in Safari to analyze memory usage when switching between pages. It will help you pinpoint if there are specific memory-intensive resources causing the crash.
Incremental Loading: If possible, implement incremental or lazy loading of resources in your Needle scenes to improve load performance and reduce the likelihood of spikes in memory usage during transitions.
If you’ve noticed that specific assets or scenes contribute more to the issue, optimizing or simplifying those may also help alleviate crashes.
Your approach with the blank HTML page seems like a practical interim solution. Continue testing this method while applying the optimizations suggested, and it should improve the overall stability of your Needle Engine applications on iOS Safari.
Let me know how it goes or if you need further assistance!
24 replies left thread_mmjVv3maBgNbgdwfbNcxQxuO Reply to this message to continue the conversation
Maybe you could try disposing the context yourself before page navigation, but I’m not sure if it will help. Or, you override the navigation between your pages so that it’s a history replace, not a history navigate.
Is there any way to dispose the scene via a Needle Engine callback? I’m putting together a repro with pure Three.js and Needle to see if the behaviour is the same while I investigate this
I have made a reproducible I will share the links for in our private chat but I will discuss the results publicly here - I made a repro site where there is a subfolder for threejs and needle respectively, each subfolder has a main Index page with 2 buttons linking to two sub pages in subfolders called Main and Sub. Both the sub pages have a Needle Engine instance in them. Both the Threejs and Needle examples have the same 3d content in them for the most part and identical scene settings where I could match them up.
With Needle Engine:
If you navigate from the Index > Main > Sub page you get a crash, if you keep navigating between Main and Sub, you also can get the Safari web browser to crash
With Three.js:
You can Navigate from Index > Main > Sub then back/forth between main and sub as many times as you want and the browser does not crash or hit any issue
I suspect this to be some issue with disposing the instance of three.js or anything else Needle is using when navigating to another page or closing the page?
For now I consider this fixed by disposing the Needle Engine before any page navigations happen, here is the code I am using to do this on a html button currently -
if (Needle.Context.Current != null) {
console.log("disposing")
let disposed = await Needle.Context.Current.dispose();
console.log("disposed: ", disposed);
}
At the moment this is partly due to iOS, MacOS and Webview not supporting the page navigate events
If there is an in-engine workaround to listen for a similar page change in Safari, this will be resolved fully as Needle currently uses the navigate events in other browsers to dispose itself on page change.
To clarify: <needle-engine> does dispose itself by default during the onDisconnectedCallback which is the callback invoked by the browser when the web componnet is removed from the DOM.
Sharing this to help others if they encounter this:
Now I made a sample using Needle Engine version 4.3.2-beta 5 This has the buttons without calling the needle engine context dispose, it can crash safari on iOS, iOS Webview and MacOS when loading 3 Needle pages in a row - tested on iPad Pro and Mac Mini M1
Video showing the crash:
This has the dispose method in the html buttons, it doesn’t crash safari no-matter how many pages I change between
Video showing no crashes:
This leads me to suspect that by default, the onDisconnectedCallback is not firing in Safari or not firing fast enough and the engine is not disposed? My HTML buttons call this
if (Needle.Context.Current != null) {
console.log("disposing")
let disposed = await Needle.Context.Current.dispose();
console.log("disposed: ", disposed);
}
I think there need to be some clarifications here, a bit too much fearmongering
What’s true is that Safari’s memory handling on iOS is different from other browsers – it seems to keep visited pages in memory for longer.
What’s not true is that this issue is specific to Needle – any app that creates a WebGL context will have the same behaviour, so we’re still determining if this is actually an issue we can work around on Needle side or a bug in Safari that needs to be fixed by Apple.
The bug report we received from @robyer1 so far compares apples and oranges – a three.js scene without any postprocessing, without any compression workers, and with a 16x smaller skybox, compared to a fully-flegded Needle scene with pretty much everything.
So we’re still working on getting a bug report that compares similar things, to determine what the issue actually is.
This issue is reproducible with just pure threejs and needle so it seems to be an underlying issue with Safari and ThreeJS rather than anything Needle specific. Apologies for any concerns caused, I have been investigating this as this issue is affecting some builds I have made that are viewed in iOS Safari webview as the webviews can get killed and it also kills the webpage when navigating between 3d pages on Safari on MacOS, iOS and iOS webview. Non safari based browsers such as android and windows Chrome/Firefox/Edge don’t have this issue.