Shopify / react-native-skia

High-performance React Native Graphics using Skia
https://shopify.github.io/react-native-skia
MIT License
6.95k stars 447 forks source link

Pefromance issue on makeImageSnapshot #429

Closed mahmoud2802 closed 2 years ago

mahmoud2802 commented 2 years ago

hello

I want to scroll Text and makeImageSnapshot on every 40ms but when snapshot start screen getting lock and flickering. how can I do something like that?

const ref = useCanvasRef();

  useEffect(() => {  
      setInterval(async () => {
       const image = ref.current?.makeImageSnapshot();
        if (image) {
          // you can use image in an <Image> component
          // Or save to file using encodeToBytes -> Uint8Array
          //const bytes = image.encodeToBytes();
        }

      }, 40);    

  }, []);

  const x = useValue(0);
  const progress = useSharedValue(0);

  useEffect(() => {
    progress.value = withRepeat(withTiming(2, { duration: 1000 }), -1, true);
  }, [progress]);

  useSharedValueEffect(() => {
    x.current = mix(progress.value, 0, 100);
  }, progress); // you can pass other shared values as extra parameters

  return (
    <>
      <Canvas ref={ref} style={{height:200,width:400 }}>
        <Text
          x={x}
          y={100}
          text="Hello world"
          familyName="tahoma"
          size={70}
        />

      </Canvas>

    </>
  );
wcandillon commented 2 years ago

It may not be appropriate to take a snapshot every 40ms, what are you trying to achieve? Did you try something like react-native-view-shot?

NikitaDudin commented 2 years ago

@wcandillon It will be excellent to add readPixels with similar on WebGL2 readPixels behaviour. I think, just updating of Uint8Array should be work more faster. That will be helpful for creating textures as pixels array in real time with next applying that texture into WebGL context scene.

wcandillon commented 2 years ago

We can expose this function. Before we do, can you tell us a bit more about your use case?

NikitaDudin commented 2 years ago

I am planning to use Skia to compose images with filters, shaders and masks, geometric primitives on a canvas, then read as pixels and apply as webgl data texture to the model in real time. Current taking snapshot function slow for that(~20ms(taking snapshot)+~20ms(encode to base64) for canvas real resolution 1024x1024 and 20 elements on the canvas on iPhone 12). Maybe read pixels will be more faster.

mahmoud2802 commented 2 years ago

@wcandillon I want built something like that .so i need to get array pixel of canvas every 40ms (25fps) and convert it to to my led scroller. I did it in native side android by moving text by animation and take a take snap shot of my view every 40ms and its work without any problem .but in react native i can't do it and performance doesn't allow me to do that.

99b1393a7b9906a43e50d4ff3a33e768

wcandillon commented 2 years ago

Thanks for providing us with these use cases. This is very helpful. There are two things that currently make this operation slow for a real-time use case:

We will investigate if we can provide makeImageSnapshot directly the gpu-backed surface. If we can, providing the necessary API to get the bitmap directly without encoding should be fairly easy.

wcandillon commented 2 years ago

@NikitaDudin @mahmoud2802 we're currently investigating this issue but it may take us a while to offer a good solution for this. In the meantime, I would like to explore workarounds that may fit your use cases. Here are two ideas on top of my head:

wcandillon commented 2 years ago

closing this issue as a duplicate of #700