Severe performance decrease after 1.10.2 updateΒ #2904
Open
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;