Shopify / Shopify/react-native-skia
Atlas Api performs worse than Picture Api
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 8.6k
- Forks
- 647
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 35
Description
Description
Hi, first of all thanks for the great library!!
The issue is that Atlas is said to be more efficient at rendering the same instance multiple times but unfortunately that is not the case for me.
For example I tried creating 1000 circles that are falling down, so it is the same image but different transformations and the Picture API while sill has poor performance, was better than Atlas.
Note that I testing on an Android, Samsung Galaxy A34.
So here is an example using Picture:
function App() {
const size = useSharedValue({width: 0, height: 0});
const circles = useSharedValue<Array<{x: number; y: number}>>([]);
useAnimatedReaction(
() => size.value,
currentSize => {
circles.value = Array.from({length: 1000}).map(
(): SkPoint => ({
x: getRandomNumber(CIRCLE_RADIUS, currentSize.width - CIRCLE_RADIUS),
y: getRandomNumber(CIRCLE_RADIUS, currentSize.height - CIRCLE_RADIUS),
}),
);
},
);
useFrameCallback(info => {
if (!info.timeSincePreviousFrame) return;
const timeSincePreviousFrame = info.timeSincePreviousFrame;
circles.modify(circles => {
circles.forEach(circle => {
circle.y += CIRCLE_SPEED * timeSincePreviousFrame;
if (circle.y > size.value.height - CIRCLE_RADIUS) {
circle.y = -CIRCLE_RADIUS;
circle.x = getRandomNumber(
CIRCLE_RADIUS,
size.value.width - CIRCLE_RADIUS,
);
}
});
return circles;
});
});
const picture = useDerivedValue(() => {
return createPicture(canvas => {
const paint = Skia.Paint();
paint.setColor(Skia.Color('white'));
circles.value.forEach(circle => {
canvas.drawCircle(circle.x, circle.y, CIRCLE_RADIUS, paint);
});
});
}, []);
return (
<View style={styles.screen}>
<Canvas onSize={size} style={styles.canvas}>
<Picture picture={picture} />
</Canvas>
</View>
);
}
And here is the Atlas version:
const image = drawAsImage(
<Circle cx={0} cy={0} r={CIRCLE_RADIUS} color={'white'} />,
{
width: 2 * CIRCLE_RADIUS,
height: 2 * CIRCLE_RADIUS,
},
);
const sprites = Array.from({length: CIRCLE_COUNT}).map(
(): SkRect => rect(0, 0, CIRCLE_RADIUS * 2, CIRCLE_RADIUS * 2),
);
function getRandomNumber(min: number, max: number) {
'worklet';
return Math.random() * (max - min) + min;
}
function App() {
const size = useSharedValue({width: 0, height: 0});
const circles = useSharedValue<Array<{x: number; y: number}>>([]);
useAnimatedReaction(
() => size.value,
currentSize => {
circles.value = Array.from({length: 1000}).map(
(): SkPoint => ({
x: getRandomNumber(CIRCLE_RADIUS, currentSize.width - CIRCLE_RADIUS),
y: getRandomNumber(CIRCLE_RADIUS, currentSize.height - CIRCLE_RADIUS),
}),
);
},
);
useFrameCallback(info => {
if (!info.timeSincePreviousFrame) return;
const timeSincePreviousFrame = info.timeSincePreviousFrame;
circles.modify(circles => {
circles.forEach(circle => {
circle.y += CIRCLE_SPEED * timeSincePreviousFrame;
if (circle.y > size.value.height - CIRCLE_RADIUS) {
circle.y = -CIRCLE_RADIUS;
circle.x = getRandomNumber(
CIRCLE_RADIUS,
size.value.width - CIRCLE_RADIUS,
);
}
});
return circles;
});
});
const transforms = useDerivedValue(() => {
return circles.value.map(circle => Skia.RSXform(1, 0, circle.x, circle.y));
}, []);
return (
<View style={styles.screen}>
<Canvas onSize={size} style={styles.canvas}>
<Atlas image={image} sprites={sprites} transforms={transforms} />
</Canvas>
</View>
);
}
| Atlas | Picture |
|---|---|
Not sure also why the output looks different, Atlas circles are smaller? But anyways perf is the bug at the moment
Version
1.4.2
Steps to reproduce
Clone the repo provided and checkout the main branch which uses the picture api and the atlas branch which uses the Atlas Api on an Android device? Perhaps a low end if possible eg: Samsung A34
Snack, code example, screenshot, or link to a repository
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked PictureVsAtlas repository, checking the main branch's Picture API example against the atlas branch's Atlas API example on an Android device such as a Samsung Galaxy A34. Measure the 1,000-circle rendering performance and compare the apparent circle sizes; done means the Atlas result no longer performs worse than Picture and the size discrepancy is explained or corrected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, react-native, typescript
- Domain
- frontend, mobile-dev, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100