react-native-skia: [Android] Performance regression on JS thread when applying transformation on UI

Description

Hello,

I’m doing a migration from Skia values to reanimated shared values, with the goal of freeing up the JS thread and performing all computations in UI. So far so good in terms of API, but I found a strange behaviour when trying to apply a transformation to a group using a derived value.

See the code example below, where I calculate the derived value in the first one, but I’m not applying it to the group, and the only difference with the second one is that I’m actually applying it. As far as I understood, this should only affect the UI thread, but I see a significant regression in fps in both threads, especially on the JS one. See also two screenshots of the performance monitor before and after the change.

Am I doing something wrong in the implementation? Or can this be an internal bug? I can provide code for reproducing it if necessary. Keep in mind that the component where this code is from is rendered 10 times in 10 different canvas.

Thanks a lot for your work in this amazing library!

Version

0.1.210

Steps to reproduce

Apply transformation to a group using a derived value. I can provide code examples to reproduce.

Snack, code example, screenshot, or link to a repository

[... other code]

  const transform = useDerivedValue(
    () => [{translateX: progress.value}],
    [progress],
  );

  return (
    <Group> // -> Without applying transformation
      <Path path={gradientPath} style="fill">
        <CornerPathEffect r={16} />
        <LinearGradient
          start={vec(size.width, 0)}
          end={vec(size.width, height * 1.1)}
          colors={colors}
        />
      </Path>
      <Path
        path={linePathData}
        style="stroke"
        strokeWidth={height * STROKE_WIDTH_RATIO}
        color={Color(tintColor).alpha(0.6).toString()}
      >
        <CornerPathEffect r={16} />
      </Path>
    </Group>
  );
[... other code]

  const transform = useDerivedValue(
    () => [{translateX: progress.value}],
    [progress],
  );

  return (
    <Group transform={transform}> // -> Applying transformation
      <Path path={gradientPath} style="fill">
        <CornerPathEffect r={16} />
        <LinearGradient
          start={vec(size.width, 0)}
          end={vec(size.width, height * 1.1)}
          colors={colors}
        />
      </Path>
      <Path
        path={linePathData}
        style="stroke"
        strokeWidth={height * STROKE_WIDTH_RATIO}
        color={Color(tintColor).alpha(0.6).toString()}
      >
        <CornerPathEffect r={16} />
      </Path>
    </Group>
  );

About this issue

  • Original URL
  • State: closed
  • Created 9 months ago
  • Comments: 15

Most upvoted comments

This great to hear 😃 We wrote a little note about performance when animating with Reanimated: https://shopify.github.io/react-native-skia/docs/animations/animations#performance The main idea is not do any JSI allocation when animating. And we think/hope that we provides the means to do that.

We also mentioned textures which can help with repeating paths/patterns: https://shopify.github.io/react-native-skia/docs/animations/textures (these should be extremely fast).

We are working on some substantial performance improvements, one of which should come out within a few weeks. Thank you for your trust and support and stay tuned 😃