Skia mount startup time
See original GitHub issueHello guys,
first of all thank you for this amazing library. I playing with this library and I am trying to use it to render SVG icons instead of react-native-svg
. Briefly discussed in #462 and solution you suggested works very well, but recently I noticed there is noticeable delay between component mount and when it actually renders anything. I tried to replace SVG with just some Circle
component, to verify this is not related just some SVG loading and it seems it is not.
I tried both iOS and Android, development and production. It’s little bit better in production and on iOS, but still noticeable especially on Android .
Do you think this is some Skia limitation or it’s something that can be possibly improved? If it’s something that could be improved I will try to figure it out.
Video (video is actually slowed down to 0.25x, but you can notice this as user even at normal speed):
https://user-images.githubusercontent.com/5837757/174345913-1a09c8c6-f782-4eaa-a181-b14f0d174df9.mov
And code of my Icon component:
const icons = {
close: require('close.svg');
...etc
}
export const Icon = ({ name, size = 'large', color = 'black' }: IconProps) => {
const svg = useSVG(icons[name]);
const {
utils: { colors },
} = useNativeStyles();
const sizeNumber = iconSizes[size];
const paint = usePaintRef();
return (
<Canvas style={{ height: sizeNumber, width: sizeNumber }}>
<Paint ref={paint}>
<BlendColor color={colors[color]} mode="srcIn" />
</Paint>
<Group layer={paint}>
{svg && <ImageSVG svg={svg} x={0} y={0} width={sizeNumber} height={sizeNumber} />}
</Group>
</Canvas>
);
};
Thanks!
Issue Analytics
- State:
- Created a year ago
- Reactions:3
- Comments:18 (7 by maintainers)
No no, @nodonski 😃 I didn’t take your message as pressure to do more work 😃 (and thanks for those kind words!)
What’s going on internally is not that complicated, and it hopefully explains the time to mount delay as well.
All components in the Canvas element is converted to Javascript drawing declarations and operations, like for a rect the JS operation would be
drawRect
for a Paint element the JS operation would be to create and update a paint object etc.This means that when we draw the Canvas we call all these operations in the SkiaView’s
onDraw
callback. This callback is called on the Javascript thread (which might be a bit busy when you load new screens in React Native) - this is the root cause of why we’re seeing a small delay: The view is displayed on screen from the main thread, the Skia drawing operations are executed on the Javascript thread - and this could cause a few frames to drop when there are many things going on at the same time on the JS thread.(In fact the Skia View uses a faster method to render from the JS thread - the drawing operations are stored in an SkPicture (which is the binary format for Skia drawing operations) and then transferred to the GPU to be rendered on a separate thread).
The only way to fix this 100% is to do the rendering on the main thread so that the Skia View can render immediately and at the same time as the screen is rendered.
Hope this could clarify 😃
@Nodonisko this Icon component is fun 😉
I’ve rebuilt a similar example but the only delay I can experience seems to be a “warmup” issue where some shaders need to be initialized. Once we draw the icon once, redrawing seems instantaneous even on a very low-end Android device (I’m testing on a Nokia 6.2).
@chrfalch I feel like it could be fun to have useSVG (or useImage) to return an SkPicture, then we can use it to warmup. Where would we draw these picture to warmup? 🤔 a Surface not visible on screen? (either below an opaque view or translated to not be visible? 🤔)
As a side note, you can use the Group for the icon size. For instance here, all my icons are of size 24x24: