Skip to content

Commit

Permalink
Reanimated 120 fps (#2636)
Browse files Browse the repository at this point in the history
## Description

This PR adds support for 120 fps on iOS devices. On Android, 120 fps is already supported without any changes.

## How to enable 120 fps mode in your app

### Android

There's nothing to do. Just make sure that your device has 120 fps mode enabled in the general system settings.

### iOS

Add the following lines to `Info.plist` of your app:

```diff
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	...
+	<key>CADisableMinimumFrameDurationOnPhone</key>
+	<true/>
</dict>
</plist>
```

Once added, it should be visible Project Settings > Info > Custom iOS Target Properties:

![](https://user-images.githubusercontent.com/20516055/142171272-71cdb548-5b0a-405a-ad92-7dfc2ee9f6ff.png)

If it's not, then restart Xcode. Finally, build and run your app as usual.

<!--
Description and motivation for this PR.

Inlude Fixes #<number> if this is fixing some issue.

Fixes # .
-->

## Example

<details>
<summary>FpsCounter.tsx</summary>

```tsx
import Animated, {
  runOnUI,
  useAnimatedStyle,
  useSharedValue,
  withSpring,
} from 'react-native-reanimated';

import React from 'react';
import { View } from 'react-native';

export default function FpsCounter() {
  const [state, setState] = React.useState(false);

  const x = useSharedValue(0);

  React.useEffect(() => {
    runOnUI(() => {
      'worklet';
      global.frameTimestamps = [];
    })();
    x.value = withSpring(state ? 360 : 0);
  }, [state]);

  const handlePress = () => {
    setState((state) => !state);
  };

  const styles = useAnimatedStyle(() => {
    if (_WORKLET) {
      const now = _frameTimestamp;
      global.frameTimestamps.push(now);
      if (global.frameTimestamps.length >= 20) {
        const first = global.frameTimestamps.shift();
        const fps = (1000 / (now - first)) * global.frameTimestamps.length;
        console.log(`${fps.toFixed(3)} fps`);
      }
    }

    return {
      transform: [{ rotate: `${x.value}deg` }],
    };
  });

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Animated.View
        style={[{ width: 200, height: 200, backgroundColor: 'red' }, styles]}
        onTouchStart={handlePress}
      />
    </View>
  );
}
```

</details>



## Changes

<!--
Please describe things you've changed here, make a **high level** overview, if change is simple you can omit this section.

For example:

- Added `foo` method which add bouncing animation
- Updated `about.md` docs
- Added caching in CI builds

-->

- Set preferred frames per second for display link to 120

<!--

## Screenshots / GIFs

Here you can add screenshots / GIFs documenting your change.

You can add before / after section if you're changing some behavior.

### Before

### After

-->

## Test code and steps to reproduce

<!--
Please include code that can be used to test this change and short description how this example should work.
This snippet should be as minimal as possible and ready to be pasted into editor (don't exclude exports or remove "not important" parts of reproduction example)
-->

1. Copy `FpsCounter.tsx` to your app
2. Modify `Info.plist` of your app (iOS only)
3. Build and run your app
5. Click on the red square to start animation
6. Check FPS count in the console output

![console](https://user-images.githubusercontent.com/20516055/142170731-18b3f90d-15e8-4bb0-9098-1bc594cdfe1b.png)

## Checklist

- [x] Included code example that can be used to test this change
- [ ] Updated TS types
- [ ] Added TS types tests
- [ ] Added unit / integration tests
- [ ] Updated documentation
- [ ] Ensured that CI passes

## References

* https://developer.apple.com/documentation/quartzcore/optimizing_promotion_refresh_rates_for_iphone_13_pro_and_ipad_pro?language=objc
* https://developer.apple.com/documentation/quartzcore/cadisplaylink
* https://developer.apple.com/documentation/quartzcore/cadisplaylink/1648421-preferredframespersecond?language=objc
  • Loading branch information
tomekzaw committed Nov 23, 2021
1 parent bbf78f7 commit 1036d81
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Example/ios/ReanimatedExample/Info.plist
Expand Up @@ -51,5 +51,7 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
</dict>
</plist>
1 change: 1 addition & 0 deletions ios/REANodesManager.m
Expand Up @@ -116,6 +116,7 @@ - (instancetype)initWithModule:(REAModule *)reanimatedModule uiManager:(RCTUIMan
}

_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onAnimationFrame:)];
_displayLink.preferredFramesPerSecond = 120; // will fallback to 60 fps for devices without Pro Motion display
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[_displayLink setPaused:true];
return self;
Expand Down

0 comments on commit 1036d81

Please sign in to comment.