Skip to content

Severe performance decrease after 1.10.2 updateΒ #2904

Open
@flowtyone

Description

Description

I'm seeing severe performance decrease, 10 to 20 fps drop when using the newest version of react-native-skia. I saw that a new reconciler was introduced and thought I might try to upgrade, but will roll back for now. Still wanted to report it.
I also upgraded react-native-reanimated and react-native-gesture-handler. These are on versions 3.16.7 and 2.22.0.
My canvas is very simple, a full screen gesture handler with around 100 rectangles in a group. The group can be panned and scaled. I was getting 60+ fps on version 1.8.1.

React Native Skia Version

1.10.2

React Native Version

0.76.5

Using New Architecture

  • Enabled

Steps to Reproduce

Run the following code.

Snack, Code Example, Screenshot, or Link to Repository

import React from "react";
import {Dimensions, Platform, View} from "react-native";
import {
    Canvas,
    Fill,
    Group,
    matchFont,
    Rect,
    rect,
    rrect,
    Skia,
    SkMatrix,
    vec,
    Vector,
    Text
} from "@shopify/react-native-skia";
import {useDerivedValue, useSharedValue} from "react-native-reanimated";
import {Gesture, GestureDetector} from "react-native-gesture-handler";

const translateMatrix = (matrix: SkMatrix, x: number, y: number) => {
    "worklet";
    const m = Skia.Matrix();
    m.translate(x, y);
    m.concat(matrix);
    return m;
};


const scaleMatrix = (matrix: SkMatrix, s: number, origin: Vector) => {
    "worklet";
    const source = Skia.Matrix(matrix.get());
    source.translate(origin.x, origin.y);
    source.scale(s, s);
    source.translate(-origin.x, -origin.y);
    return source;
};

const tileProperties = {
    size: {
        width: 100,
        height: 160
    },
    cornerRadius: 16,
    color: "#202020",
    padding: 10
}

const getTilePositions = () => {
    const positions: { x: number, y: number }[] = [];
    const {width, height} = Dimensions.get('window');

    const minX = 0;
    const minY = 0;
    const maxX = width * 3;
    const maxY = height * 3;

    let x = minX, y = minY;

    while (y < maxY) {
        while (x < maxX) {
            positions.push({x, y})

            x += tileProperties.size.width + tileProperties.padding;
        }

        y += tileProperties.size.height + tileProperties.padding
        x = minX;
    }

    return positions;
}

const tilePositions = getTilePositions();

const debugFont = matchFont({
    fontFamily: Platform.select({ios: "Helvetica", default: "serif"}),
    fontSize: 14
});

const Tile: React.FC<{ position: { x: number, y: number } }> = ({position}) => {

    const clipRect = React.useMemo(() => rrect(
        rect(position.x, position.y, tileProperties.size.width, tileProperties.size.height),
        tileProperties.cornerRadius,
        tileProperties.cornerRadius
    ), [position])

    return (
        <Group clip={clipRect}>
            <Rect
                style="fill"
                color={tileProperties.color}
                width={tileProperties.size.width}
                height={tileProperties.size.height}
                {...position}
            />
            <Text
                text="1"
                x={position.x + 30}
                y={position.y + 60}
                font={debugFont}
                color="white"
            />
        </Group>
    )
}
const Tiles = () => {

    const pivot = useSharedValue(Skia.Point(0, 0));
    const position = useSharedValue(Skia.Point(0, 0));

    const matrix = useSharedValue<SkMatrix>(Skia.Matrix());
    const prevMatrix = useSharedValue(Skia.Matrix());

    const pan = Gesture.Pan()
        .onChange((e) => {
            matrix.value = translateMatrix(
                matrix.value,
                e.changeX,
                e.changeY
            );
        });

    const pinch = Gesture.Pinch()
        .onStart((e) => {
            prevMatrix.value = matrix.value;

            pivot.value = vec(
                e.focalX - position.value.x,
                e.focalY - position.value.y
            );
        })
        .onChange((e) => {
            matrix.value = scaleMatrix(
                prevMatrix.value,
                e.scale,
                pivot.value
            );
        });

    const gesture = Gesture.Race(pinch, pan);

    return (
        <GestureDetector gesture={gesture}>
            <View style={{flex: 1}}>
                <Canvas style={{flex: 1}}>
                    <Fill color="black"/>
                    <Group matrix={matrix}>
                        {tilePositions.map((point) => (
                            <Tile
                                key={`${point.x},${point.y}`}
                                position={point}
                            />
                        ))}
                    </Group>
                </Canvas>
            </View>
        </GestureDetector>
    )
}

export default Tiles;

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions