-
Notifications
You must be signed in to change notification settings - Fork 647
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSI: Add no-copy ArrayBuffer constructor #564
Comments
cc @savv @tmikov @sercand @mhorowitz @wkozyra95 @ryantrem because you guys were part of the discussions in the previous issues/PRs - would love to get your opinion on this. |
+@bghgary, and thanks for the ping @mrousavy. It would be great to have this feature, and there are scenarios in Babylon React Native where we would use it, such as when we download files and expose them to JS (we have a JSI-based implementation of For the scenarios described above though, it's not 100% clear to me how much this will help. I would expect that for something like VisionCamera the following would be true:
The above basically outlines the constraints we have in Babylon React Native for a similar scenario, where we have a frame capture feature that can get what is being rendered on screen by Babylon each frame and expose it as an RGB buffer to JS. We don't attempt to consume this ArrayBuffer in JS code though, we just pass it off to other JSI native modules (for things like encoding the captured frames into an mp4 in real time). In this case, there are three threads, and each one needs one copy of the buffer (plus one temp buffer, described below):
So we end up basically with three persistent buffers and one temp buffer, and three |
Hi @ryantrem thanks for the detailed answer! To answer those questions;
Right
Wrong, I am running a separate workletized JS-Runtime on the same Thread where I get those buffers. That's why I need to be able to re-use a single buffer, because I exactly know when it's no longer being used, everything's synchronous. I don't want to create a new
It might be, yes. But I'm mostly doing this for an experiment anyways, so I wanted to see how that would work out. Maybe some basic tasks work fine. Also I'm not doing this at 240 Hz, in a real world use case this will happen at 1 FPS up to 30 FPS. Also the user can then pass the |
Added in e6d887a. |
@neildhar Thank you for this feature, it's super useful 🙏 |
Problem
I'm trying to efficiently use
ArrayBuffer
s to avoid expensive copy operations. To expose buffers to JS I use thisTypedArray
implementation by Expo, which unfortunately copies the entire buffer (see code here). Because the entire buffer is copied, this causes two separate issues:TypedArray
(e.g.Uint8Array
) is very slow because those huge buffers (~ 10 MB) have to be copiedUse-case 1
I'm the maintainer of VisionCamera which provides an API to run any sort of frame processing code for each frame the camera "sees". For example, you might use this to run some AI to detect faces, objects, barcodes or whatever.
Since the frame objects are so big, I tried to directly expose the native pixel buffer (~ 10 MB per frame) to JS by using
ArrayBuffer
s. Those callbacks are called 30, 60 and sometimes even 240 times per second, so copying all of the pixels every time will not be fast enough - instead I want to directly use the buffer I already have in memory. Also I am experiencing out of memory errors since the JSIArrayBuffer
implementation maintains a custom buffer which is only cleaned when the JS VM runs a garbage collection - instead I either want to manually free the buffer, or re-use my custom buffer.Working on this here: mrousavy/react-native-vision-camera#308
Use-case 2
I'm working on a feature to stream Audio Sample Buffers from a audio/music player in realtime where you can read those values in JS. Currently I use normal Arrays for this, but I want to improve the performance by avoiding copy operations and instead directly expose the native audio sample buffer array to JS using an
ArrayBuffer
. The problem here is as well that theArrayBuffer
implementation copies the entire buffer.Working on this here: expo/expo#13516
So TL;DR: Currently the
ArrayBuffer
API does not provide a way to initialize a newArrayBuffer
from an already existing memory buffer without copying the entire thing.Solution
Update the JSI API to provide an initializer for
ArrayBuffer
with the following signature:I am not aware of any workarounds that do not copy the entire buffer at the moment.
Additional Context
Here's the API from JSC to create an ArrayBuffer using an existing memory buffer: JSTypedArray.h:
JSObjectMakeTypedArrayWithBytesNoCopy
afaik, Hermes does not provide this constructor yet.
There have been numerous feature requests and discussions for this:
The text was updated successfully, but these errors were encountered: