Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Still seeing decreased performance, please keep CanvasOld #2930

Closed
1 task done
flowtyone opened this issue Jan 29, 2025 · 14 comments
Closed
1 task done

Still seeing decreased performance, please keep CanvasOld #2930

flowtyone opened this issue Jan 29, 2025 · 14 comments
Labels
bug Something isn't working

Comments

@flowtyone
Copy link

Description

@wcandillon Thank you for all the hard work on trying to fix #2904 but I'm still seeing up to 200% decrease in performance from the old canvas. If this issue isn't fixable for now it's ok, just please keep the CanvasOld implementation around until it is. Feel free to close this issue, I only opened it to ask that.

React Native Skia Version

1.11.1

React Native Version

0.76.5

Using New Architecture

  • Enabled

Steps to Reproduce

Continuation of #2904

Snack, Code Example, Screenshot, or Link to Repository

Continuation of #2904

@flowtyone flowtyone added the bug Something isn't working label Jan 29, 2025
@wcandillon
Copy link
Contributor

wcandillon commented Jan 29, 2025

In our tests, we don't have an example where CanvasOld is faster, if you have one please share it with us and we will reopen it immediately (we did act somewhat fast on #2904 right?)

In the current architecture we are running the drawing at virtually native speed, anything else from the frame budget is either Reanimated shared value or hermes performance (reconciler, reanimated worklets).
We will not keep CanvasOld since it is quite buggy and has some stability issues on Android. Also architecturally speaking, we don't think it makes sense.

But it sounds like we might be missing something just let us know.

@wcandillon
Copy link
Contributor

wcandillon commented Jan 29, 2025 via email

@flowtyone
Copy link
Author

@wcandillon I'm currently going through updating all of our dependencies including react native itself from version 0.76.5 to 0.77. I'll let you know if that improves anything

@flowtyone
Copy link
Author

@wcandillon after updating all dependencies, performance on the OldCanvas still far supercedes the new Canvas. I can provide you all the details you need as I believe more people will be experiencing this, our use case is not so unique. But I will only be able to share the details with you privately.

@wcandillon
Copy link
Contributor

wcandillon commented Jan 31, 2025 via email

@wcandillon
Copy link
Contributor

wcandillon commented Feb 1, 2025 via email

@flowtyone
Copy link
Author

flowtyone commented Feb 1, 2025

@wcandillon I'd appreciate if you don't put it there, I was not intending to even post it publicly. I only did that so you can try to help us out here. I will remove the code snippet once you have a local copy

@wcandillon
Copy link
Contributor

wcandillon commented Feb 1, 2025

of course, sending you an update you will like in a few minutes :)

@wcandillon
Copy link
Contributor

Ok so this is a very cool and interesting example. And it gives me a lot of food for thoughts on the next improvements to work on.
I rewrote it in a way that is much faster than with CanvasOld but for the images things get a bit tricky. Let me provide a bit of context on that.

First things first, we had to remove CanvasOld because it contained many bugs and had some stability issues. Its "fatal" design flow is that it treated updates from the JS thread and animation updates equally. That made animations slow. And this is why we find it to be much faster because we only looked at animations. In your case, you only run updates on the JS thread and so indeed in your case things are slower (I didn't do an actual benchmark vs CanvasOld but just by looking at the code, it's very safe to assume).

We do want JS updates to be very fast as well, but here the bottleneck really on Hermes speed, we architectured everything to optimize for animation speed where here we virtually run at native speed.
I know it probably sounds crazy you have the exact use-case for which CanvasOld was optimizing for but on our side it was a complete no go to continue this approach.

Now what do we do from there?
We do still want to make JS-side updates faster. We have ideas there it's also very dependent on Hermes performance.

I rewrote the example to use only animation values (no JS updates) and then it's crazy fast. For dealing with the images, things get tricky.
With useImage, you cannot cancel the request if you got out of the bound of the viewport and you would need to use .dispose when the component gets unmounted but there also a lot of things on our side we can do to improve the situation there.

If you where to rewrite the example without the reconciller, to just draw the scene like a video game loop, you would have the same issue with the image handling where you wouldn't get anything for free. In fact if we can figure out a good image management for this demo, we can definitely rewrite it faster than with CanvasOld (with our without reconciler). I want to give it some more thoughts but let's keep the discussion going on this.

@wcandillon
Copy link
Contributor

I should mention also that this example did make me find a "quirk" in the new reconciler where a loading image goes from null, to SkImage and is considered a tree/JS update even thought the tree didn't really change, we just need to rerender with the new value.

@wcandillon
Copy link
Contributor

Can you send the original example privately as well? I think we can really make the example better, I have some ideas, in the end there is no reason that an example like this one would require a full re-render of the JS thread for each animation frame. And that's a bit counter intuitive to what Reanimated does right?

@flowtyone
Copy link
Author

@wcandillon Thank you for the quick reply and as always, great in depth explanation. I can continue the conversation with you privately and even share more details regarding what we're building which would help to make sense of everything. I just haven't figured out how to contact you privately yet.

@wcandillon
Copy link
Contributor

So my thinking is to figure out the image loading (maybe we need to have a workletRuntime pool to pull/decode images in parallel for instance) and then the images are all available via a shared value anyways and so we can just run it as an animation And you have also figured out the "cleaning out" in your code but I lost that part because I modified the original example too much.

@flowtyone
Copy link
Author

flowtyone commented Feb 1, 2025

@wcandillon That's a good direction. I messaged you, hopefully we can take it from there

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants