Closed micbay closed 3 months ago
I'm getting the same issue on my app.
Environment: Safari, iPad 7th Gen iOS v17.1
Here is a link to some more info and some comparable test codesandboxes, from discussion of this issue I'd posted on the three.js forum. discourse.threejs post. And a post on the apple forum: apple forum issue post
This issue appears to be related to recent iOS used on older ipads and with R3F in general. I no longer believe it's tied to use of a texture, but it is related to, or at minimum, exacerbated by using R3F, as using straight three.js seems to not have the same issue.
this remains an issue even with the most recent iOS 17.6.1 update
You should try lowering DPR as a first step, but continue with three.js or Apple support forums. R3F only deals with reconciliation and has nothing do to here.
I know it seems hard for folks to accept that R3F is affecting code to cause problems, but as best as I can, the occurrence of the problem has been isolated to usage of R3F. Something about how R3F operates is affecting code execution, timing, order of events, something, it is doing is exposing this issue.
Reposted here are multiple codesanboxes that prove this. Using react for all components, one component is built using vanilla three.js, and one using R3F. The R3F component causes a failure on older ipads and iOS 17.5 or 17.6. Probably a change to three.js, R3F, or iOS could fix this issue, but it is without a doubt an error that is encouraged by the use of R3F.
In the following sandboxes, on my ipad i can see the vanilla cube rotating fine and i can see the both ways app if i comment out the fiber cube component. I get the described null error if I try to view the fiber only or the both ways with fiber cube enabled. Basic-ThreeJS-Cubes-Bothways Basic-ThreeJS-Cube-Fiber Basic-ThreeJS-Cube-Vanilla
As the maintainer of R3F and three's WebGLRenderer, I am probably the most qualified to tell you that R3F does not impose memory limits or alter GPU memory, and you should heed my comment as a consequence if you expect any resolve. The error TypeError: null is not an object (evaluating 'gl.getShaderPrecisionFormat(gl.VERTEX_SHADER
tells me that the browser is revoking the context and any resource creation, so this is an OS level error from the GPU device being lost or OOM generally as a safety measure. It is possible there is a memory leak in R3F we haven't seen despite scaling to massive games and software, but such is definitely not intentional and should be considered a bug.
Looks like the component had a memory leak where it would create a new texture every render without memoization. Here is the same thing with the 2D canvas memoized, and a CanvasTexture
bound in JSX so R3F will dispose on unmount and memoize through JSX.
https://codesandbox.io/p/sandbox/basic-threejs-cube-fiber-forked-5rn4rs
I would agree this appears to be ultimately rooted in iOS, and I'm certainly not intending to present any rejection of expertise. I appreciate all help in this matter.
I still have the same issue with this forked memoized version as well. In fact the issue exhibits itself on any of the R3F examples from the R3F example page. Occasionally a render will work, I'm guessing based on the timing of renders and cache. But inevitably refreshing for clean loads results in an error and failure to render.
Were you detecting a memory leak, or predicting one based on code? I'm relatively new with three.js and react so I don't know the best practices for when to use memoization.
Regardless for this particular problem, if there is a memory leak, it doesn't appear to be the issue, if the forked sandbox you made is leak free, as the error still presents itself.
Have you been able to re-create the error on a device, did memoization resolve it for you?
I glanced over the code and saw it held an unstable resource to a texture.
Seeing this is not endemic to minor user error (you're creating a very small texture (256p = 64 KB), this looks to not be a memory leak at all and a device/OS issue since you can't even create a WebGL program and aren't allocating GPU memory as a result.
I would take this upstream to three or especially Apple, note the OS and device, and try updating it if possible.
Unfortunately I don't expect much attention from Apple, though I've tried, and will continue to push, making them aware of the issue. Apple iOS has already had at least 1 update without fixing this issue.
I was hoping, since R3F is such an un-obtrusive construct that it might be straight forward to see why the vanilla three.js and R3F implementations behave differently, and what could be done to make an R3F implementation, as robust against this iOS issue, as the vanilla three.js seems to be. Perhaps it's as simple as adding a null check somewhere. Though i realize this would be in three.js code, not R3F, I hoped whatever the impact that R3F is having, that vanilla doesn't, could isolate where maintainers should look.
My only notice to three.js is the forum post I linked above, if there is another place I should use to run this up the flag pole for three.js maintainers, that you know of please point me that way.
The only thing different in your vanilla demo is it doesn't set dpr like R3F does renderer.setPixelRatio(Math.min(2, Math.max(1, window.devicePixelRatio)))
which increases the framebuffer resolution. I'd see if that creates the problem. Everything else is related to color management or pure reconciliation, so they can be ignored.
Same problem. both my app and R3F example page. device: iPad Pro 10.5 os: ipadOS 17.6.1 any browser(safari, chrome, edge)
Other Apple OS(m1 mac, iPhone 15 pro) are OK.
See https://github.com/pmndrs/react-three-fiber/issues/3309#issuecomment-2276420872 and try decreasing DPR to lower the memory impact of the canvas framebuffer and/or antialias
which may supersample on some hardware. I'm afraid we can't do anything more to help as R3F does not impact runtime behavior whatsoever, and I don't think three.js is the right place either if it's something other than memory limits you're hitting (again see my prior comments). If that is not enough, please take this to Apple who I'd strongly urge you to reach to first.
For reference, this is the configuration R3F produces. I'd whittle away at it until it matches your expectations with vanilla and apply that change to your app with R3F.
const renderer = new THREE.WebGLRenderer({
powerPreference: 'high-performance',
antialias: true,
alpha: true,
})
renderer.setPixelRatio(Math.min(2, Math.max(1, devicePixelRatio)))
renderer.setSize(innerWidth, innerHeight)
const camera = new THREE.PerspectiveCamera(75, innerWidth / innerHeight, 0.1, 1000)
camera.position.z = 5
//
texture.colorSpace = THREE.SRGBColorSpace
Spent a moment debugging it on discord, since iPad Pros are a huge chunk of the market for CAD / drawing apps with R3F - keeping the device support list inline with vanilla three.js can be important.
By default <Canvas />
uses powerPreference: "high-performance"
and antialias: true
which causes iPad Pro 10.5 and iPad 8th gen to instantly lose context due to lack of memory, use the following as a work-around:
<Canvas gl={{ powerPreference: 'default', antialias: false }} />
Since dpr
is set to native iPads resolution by default, there should be pretty much no visual difference. Verified on iPad Pro 10.5 with 17.5.1:
@hotelcostes @micbay could you verify it fixes the issue? I'll add it to a related thread on discourse of vanilla three.js then.
That would be antialias: false
. It's quite strange powerPreference
has any effect here due to the lack of discrete hardware on Mx hardware. I'd still take this up with Apple so they don't regress their iPad line which can be quite different than iOS for iPhone. We've seen regressions in support for WebGL on iOS which used to be exclusive to iPad (e.g. float textures).
<Canvas gl={{ powerPreference: 'default', antialiasing: false }} />
@hotelcostes @micbay could you verify it fixes the issue? I'll add it to a related thread on discourse of vanilla three.js then.
<Canvas gl={{ powerPreference: 'default', antialias: false }} />
@mjurczyk antialiasing: false
probably a typo. Works fine. thx.
<Canvas gl={{ powerPreference: 'default', antialias: false }} />
Hi, @mjurczyk , yes, changing the powerPreference to 'default', and antialias to 'false' corrects the problem in my app, on my older iPad. Thanks so much for digging in deeper, isolating the root cause, and sharing a solution, it's much appreciated.
I recently updated my ipad pro from, I think 16, maybe even 15, to the latest ios17.5.1.
Before the update my three js project was rendering just fine. After the update I now get an error:
I believe this is from the following function in the three.cjs build file.
My app is a lot to try and post, but the following linked example from some react-three-fiber, doc site that deals a lot with textures, as does my app, also exhibits the same problem. React Three Fiber Tutorials - Material Picker working example page of example with code
on an ipad with iOS 17.5.1(21F90) will produce a black screen when trying to render the linked example.