Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions docs/docs/guides/GETTING_STARTED.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,27 @@ import TabItem from '@theme/TabItem'

1. Install [react-native-filament](https://www.npmjs.com/package/react-native-filament):

```sh
npm i react-native-filament
```
<Tabs
groupId="rnfInstallation"
defaultValue="RN075"
values={[
{label: 'React Native >= 0.75.x', value: 'RN075'},
{label: 'React Native < 0.75.x', value: 'RN074'}
]}>
<TabItem value="RN075">
We highly recommend that you use react-native >= v0.75.x, as it has a lot of improvements and fixes. You'll get the fastest performance as react-native-filament uses [react-native-nitro-modules](https://nitro.margelo.com/docs/for-users):

```sh
npm i react-native-nitro-modules
npm i react-native-filament
```
</TabItem>
<TabItem value="RN074">
```sh
npm i react-native-filament@^1.0.0
```
</TabItem>
</Tabs>

2. `react-native-filament` depends on [`react-native-worklets-core`](https://github.com/margelo/react-native-worklets-core):

Expand Down Expand Up @@ -65,7 +83,7 @@ For react-native-worklets-core its necessary to add a plugin to your `babel.conf
</TabItem>

<TabItem value="w_rea">
You should already use the reaniamted babel pluginVersions, make sure to add the `processNestedWorklets` option to it:
You should already use the reanimated babel pluginVersions, make sure to add the `processNestedWorklets` option to it:

```js
module.exports = {
Expand Down
4 changes: 2 additions & 2 deletions package/android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ endif()
find_package(ReactAndroid REQUIRED CONFIG)
find_package(fbjni REQUIRED CONFIG)
find_library(LOG_LIB log)
find_package(react-native-nitro-modules REQUIRED) # <-- Used to create all HybridObjects and use the Nitro core library

# Add react-native-filament sources
add_library(
Expand All @@ -38,13 +39,11 @@ add_library(
../cpp/RNFChoreographer.cpp
../cpp/RNFChoreographerWrapper.cpp
../cpp/RNFListener.cpp
../cpp/jsi/RNFHybridObject.cpp
../cpp/jsi/RNFPromise.cpp
../cpp/jsi/RNFPromiseFactory.cpp
../cpp/jsi/RNFRuntimeCache.cpp
../cpp/jsi/RNFWorkletRuntimeRegistry.cpp
../cpp/threading/RNFDispatcher.cpp
../cpp/test/RNFTestHybridObject.cpp

# Filament Core
../cpp/core/RNFEngineImpl.cpp
Expand Down Expand Up @@ -124,6 +123,7 @@ target_link_libraries(
fbjni::fbjni # <-- fbjni
GLESv3 # <-- OpenGL (Core)
EGL # <-- OpenGL (EGL)
react-native-nitro-modules::NitroModules # <-- NitroModules Core :)
)

# Link with RNWC:
Expand Down
1 change: 1 addition & 0 deletions package/cpp/RNFChoreographer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "RNFChoreographer.h"
#include "RNFListenerManager.h"
#include "RNFLogger.h"

namespace margelo {

Expand Down
1 change: 1 addition & 0 deletions package/cpp/RNFChoreographer.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "RNFListener.h"
#include "RNFListenerManager.h"
#include "RNFLogger.h"
#include <functional>

namespace margelo {
Expand Down
23 changes: 14 additions & 9 deletions package/cpp/RNFChoreographerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ ChoreographerWrapper::~ChoreographerWrapper() {
}

void ChoreographerWrapper::loadHybridMethods() {
registerHybridMethod("start", &ChoreographerWrapper::start, this);
registerHybridMethod("stop", &ChoreographerWrapper::stop, this);
registerHybridMethod("addFrameCallbackListener", &ChoreographerWrapper::addFrameCallbackListener, this);
registerHybridMethod("release", &ChoreographerWrapper::release, this, true);
PointerHolder::loadHybridMethods();
registerHybrids(this, [](nitro::Prototype& proto) {
proto.registerHybridMethod("start", &ChoreographerWrapper::start);
proto.registerHybridMethod("stop", &ChoreographerWrapper::stop);
proto.registerHybridMethod("addFrameCallbackListener", &ChoreographerWrapper::addFrameCallbackListener);
// TODO: overwrite mechanism doens't exist yet i believe
proto.registerHybridMethod("release", &ChoreographerWrapper::release);
});
}

void ChoreographerWrapper::start() {
Expand Down Expand Up @@ -85,11 +89,12 @@ void ChoreographerWrapper::release() {
PointerHolder::release();
}

void ChoreographerWrapper::onRuntimeDestroyed(jsi::Runtime*) {
std::unique_lock lock(_mutex);
Logger::log(TAG, "Runtime destroyed...");
stopAndRemoveListeners();
}
// TODO: nitro is this still needed? I don't think so
// void ChoreographerWrapper::onRuntimeDestroyed(jsi::Runtime*) {
// std::unique_lock lock(_mutex);
// Logger::log(TAG, "Runtime destroyed...");
// stopAndRemoveListeners();
//}

std::shared_ptr<Choreographer> ChoreographerWrapper::getChoreographer() {
if (getIsValid()) {
Expand Down
4 changes: 1 addition & 3 deletions package/cpp/RNFChoreographerWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@

#include "RNFChoreographer.h"
#include "jsi/RNFPointerHolder.h"
#include "jsi/RNFRuntimeCache.h"

namespace margelo {

using FrameInfo = std::unordered_map<std::string, double>;
using RenderCallback = std::function<void(FrameInfo)>;

class ChoreographerWrapper : public PointerHolder<Choreographer>, public RuntimeLifecycleListener {
class ChoreographerWrapper : public PointerHolder<Choreographer> {
public:
explicit ChoreographerWrapper(std::shared_ptr<Choreographer> choreographer) : PointerHolder(TAG, choreographer) {}
~ChoreographerWrapper() override;
Expand All @@ -32,7 +31,6 @@ class ChoreographerWrapper : public PointerHolder<Choreographer>, public Runtime

private: // Internal
void stopAndRemoveListeners();
void onRuntimeDestroyed(jsi::Runtime*) override;
FrameInfo createFrameInfo(double timestamp);

private:
Expand Down
4 changes: 3 additions & 1 deletion package/cpp/RNFFilamentBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ namespace margelo {
class FilamentBuffer : public PointerHolder<ManagedBuffer> {
public:
explicit FilamentBuffer(std::shared_ptr<ManagedBuffer> buffer) : PointerHolder("FilamentBuffer", buffer) {}
void loadHybridMethods() override {}
void loadHybridMethods() override {
PointerHolder::loadHybridMethods();
}

std::shared_ptr<ManagedBuffer> getBuffer() {
return pointee();
Expand Down
58 changes: 26 additions & 32 deletions package/cpp/RNFFilamentProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
#include "RNFReferences.h"
#include "core/RNFEngineBackendEnum.h"
#include "core/RNFEngineConfigHelper.h"
#include "jsi/RNFPromise.h"
#include "threading/RNFDispatcher.h"

#include <memory>
#include <string>
Expand All @@ -21,18 +19,20 @@ namespace margelo {
using namespace facebook;

void FilamentProxy::loadHybridMethods() {
registerHybridMethod("loadAsset", &FilamentProxy::loadAssetAsync, this);
registerHybridMethod("findFilamentView", &FilamentProxy::findFilamentViewAsync, this);
registerHybridMethod("createTestObject", &FilamentProxy::createTestObject, this);
registerHybridMethod("createEngine", &FilamentProxy::createEngine, this);
registerHybridMethod("createBullet", &FilamentProxy::createBullet, this);
registerHybridMethod("createChoreographer", &FilamentProxy::createChoreographerWrapper, this);
registerHybridMethod("createRecorder", &FilamentProxy::createRecorder, this);
registerHybridMethod("getCurrentDispatcher", &FilamentProxy::getCurrentDispatcher, this);
registerHybridGetter("hasWorklets", &FilamentProxy::getHasWorklets, this);
HybridObject::loadHybridMethods();
registerHybrids(this, [](nitro::Prototype& proto) {
proto.registerHybridMethod("loadAsset", &FilamentProxy::loadAssetAsync);
proto.registerHybridMethod("findFilamentView", &FilamentProxy::findFilamentViewAsync);
proto.registerHybridMethod("createEngine", &FilamentProxy::createEngine);
proto.registerHybridMethod("createBullet", &FilamentProxy::createBullet);
proto.registerRawHybridMethod("createChoreographer", 0, &FilamentProxy::createChoreographerWrapper);
proto.registerHybridMethod("createRecorder", &FilamentProxy::createRecorder);
proto.registerRawHybridMethod("getCurrentDispatcher", 0, &FilamentProxy::getCurrentDispatcher);
proto.registerHybridGetter("hasWorklets", &FilamentProxy::getHasWorklets);
#if HAS_WORKLETS
registerHybridMethod("createWorkletContext", &FilamentProxy::createWorkletContext, this);
proto.registerHybridMethod("createWorkletContext", &FilamentProxy::createWorkletContext);
#endif
});
}

bool FilamentProxy::getHasWorklets() {
Expand All @@ -55,16 +55,25 @@ std::shared_ptr<RNWorklet::JsiWorkletContext> FilamentProxy::createWorkletContex
Logger::log(TAG, "Successfully created WorkletContext! Installing global Dispatcher...");

workletContext->invokeOnWorkletThread([=](RNWorklet::JsiWorkletContext*, jsi::Runtime& runtime) {
Dispatcher::installRuntimeGlobalDispatcher(runtime, renderThreadDispatcher);
nitro::Dispatcher::installRuntimeGlobalDispatcher(runtime, renderThreadDispatcher);
Logger::log(TAG, "Successfully installed global Dispatcher in WorkletContext!");
});

return workletContext;
}
#endif

// TODO: nitro is this still needed?!
jsi::Value FilamentProxy::getCurrentDispatcher(jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*, size_t) {
return Dispatcher::getRuntimeGlobalDispatcherHolder(runtime);
#ifdef NITRO_DEBUG
if (!runtime.global().hasProperty(runtime, "__nitroDispatcher")) [[unlikely]] {
throw std::runtime_error("Failed to get current Dispatcher - the global Dispatcher "
"holder (global.__nitroDispatcher) "
"does not exist! Was Dispatcher::installDispatcherIntoRuntime() called "
"for this jsi::Runtime?");
}
#endif
return runtime.global().getProperty(runtime, "__nitroDispatcher");
}

std::future<std::shared_ptr<FilamentBuffer>> FilamentProxy::loadAssetAsync(const std::string& path) {
Expand Down Expand Up @@ -95,16 +104,11 @@ std::future<std::shared_ptr<FilamentView>> FilamentProxy::findFilamentViewAsync(
});
}

std::shared_ptr<TestHybridObject> FilamentProxy::createTestObject() {
Logger::log(TAG, "Creating TestObject...");
return std::make_shared<TestHybridObject>();
}

std::shared_ptr<EngineWrapper> FilamentProxy::createEngine(std::optional<std::string> backend,
std::optional<std::unordered_map<std::string, int>> arguments) {
Logger::log(TAG, "Creating Engine...");

std::shared_ptr<Dispatcher> renderThread = getRenderThreadDispatcher();
std::shared_ptr<nitro::Dispatcher> renderThread = getRenderThreadDispatcher();

Engine::Config config = EngineConfigHelper::makeConfigFromUserParams(arguments);
Engine::Backend backendEnum = Engine::Backend::DEFAULT;
Expand Down Expand Up @@ -145,19 +149,9 @@ jsi::Value FilamentProxy::createChoreographerWrapper(jsi::Runtime& runtime, cons
Logger::log(TAG, "Creating Choreographer...");
std::shared_ptr<Choreographer> choreographer = createChoreographer();

ChoreographerWrapper* choreographerWrapperPtr = new ChoreographerWrapper(choreographer);

RuntimeLifecycleMonitor::addListener(runtime, choreographerWrapperPtr);

// Wrap the ChoreographerWrapper in a shared_ptr with a custom deleter that removes the listener from the RuntimeLifecycleMonitor:
std::shared_ptr<ChoreographerWrapper> choreographerWrapper =
std::shared_ptr<ChoreographerWrapper>(choreographerWrapperPtr, [&runtime](ChoreographerWrapper* ptr) {
// Remove the ChoreographerWrapper from the RuntimeLifecycleMonitor when it gets destroyed.
RuntimeLifecycleMonitor::removeListener(runtime, ptr);
delete ptr;
});
std::shared_ptr<ChoreographerWrapper> choreographerWrapper = std::make_shared<ChoreographerWrapper>(choreographer);

return JSIConverter<std::shared_ptr<ChoreographerWrapper>>::toJSI(runtime, choreographerWrapper);
return nitro::JSIConverter<std::shared_ptr<ChoreographerWrapper>>::toJSI(runtime, choreographerWrapper);
}

} // namespace margelo
23 changes: 12 additions & 11 deletions package/cpp/RNFFilamentProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@

#pragma once

#if __has_include(<NitroModules/HybridObject.hpp>)
#include <NitroModules/Dispatcher.hpp>
#include <NitroModules/HybridObject.hpp>
#else
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
#endif

#include <jsi/jsi.h>

#include <future>
Expand All @@ -17,9 +24,6 @@
#include "RNFFilamentView.h"
#include "bullet/RNFBulletWrapper.h"
#include "core/RNFEngineWrapper.h"
#include "jsi/RNFHybridObject.h"
#include "test/RNFTestHybridObject.h"
#include "threading/RNFDispatcher.h"

#include <ReactCommon/CallInvoker.h>

Expand All @@ -37,7 +41,7 @@ namespace margelo {

using namespace facebook;

class FilamentProxy : public HybridObject {
class FilamentProxy : public nitro::HybridObject {
public:
explicit FilamentProxy() : HybridObject(TAG) {}

Expand All @@ -51,22 +55,22 @@ class FilamentProxy : public HybridObject {
/**
* Get the Dispatcher for the main react JS thread.
*/
virtual std::shared_ptr<Dispatcher> getJSDispatcher() = 0;
virtual std::shared_ptr<nitro::Dispatcher> getJSDispatcher() = 0;
/**
* Get the Dispatcher that is responsible for rendering to Filament.
* This is guaranteed to only use a single Thread, as opposed to a Thread-pool.
*/
virtual std::shared_ptr<Dispatcher> getRenderThreadDispatcher() = 0;
virtual std::shared_ptr<nitro::Dispatcher> getRenderThreadDispatcher() = 0;
/**
* Get the Dispatcher for the platform-default UI Thread.
* This is guaranteed to only use a single Thread, as opposed to a Thread-pool.
*/
virtual std::shared_ptr<Dispatcher> getUIDispatcher() = 0;
virtual std::shared_ptr<nitro::Dispatcher> getUIDispatcher() = 0;
/**
* Get a Dispatcher that uses a Thread-pool for background operations such as File I/O.
* This Dispatcher may use multiple Threads to run code.
*/
virtual std::shared_ptr<Dispatcher> getBackgroundDispatcher() = 0;
virtual std::shared_ptr<nitro::Dispatcher> getBackgroundDispatcher() = 0;
/**
* Get the refresh rate of the display in Hz.
* Needed for correct frame pacing and dynamic resolution calculations.
Expand All @@ -79,9 +83,6 @@ class FilamentProxy : public HybridObject {

jsi::Value getCurrentDispatcher(jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* args, size_t count);

// For testing
std::shared_ptr<TestHybridObject> createTestObject();

// Public API
std::future<std::shared_ptr<FilamentBuffer>> loadAssetAsync(const std::string& path);
std::future<std::shared_ptr<FilamentView>> findFilamentViewAsync(int id);
Expand Down
30 changes: 18 additions & 12 deletions package/cpp/RNFFilamentRecorder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
//

#include "RNFFilamentRecorder.h"
#include "RNFLogger.h"
#include <jsi/jsi.h>

namespace margelo {

using namespace facebook;

FilamentRecorder::FilamentRecorder(std::shared_ptr<Dispatcher> renderThreadDispatcher, int width, int height, int fps, double bitRate)
FilamentRecorder::FilamentRecorder(std::shared_ptr<nitro::Dispatcher> renderThreadDispatcher, int width, int height, int fps,
double bitRate)
: HybridObject("FilamentRecorder"), _renderThreadDispatcher(renderThreadDispatcher), _width(width), _height(height), _fps(fps),
_bitRate(bitRate), _listenerManager(ListenerManager<ReadyForMoreDataCallback>::create()) {
Logger::log(TAG, "Creating %zu x %zu @ %zu FPS (%f bps) FilamentRecorder...", width, height, fps, bitRate);
Expand All @@ -20,19 +22,23 @@ FilamentRecorder::~FilamentRecorder() {
}

void FilamentRecorder::loadHybridMethods() {
registerHybridGetter("width", &FilamentRecorder::getWidth, this);
registerHybridGetter("height", &FilamentRecorder::getHeight, this);
registerHybridGetter("fps", &FilamentRecorder::getFps, this);
registerHybridGetter("bitRate", &FilamentRecorder::getBitRate, this);
registerHybridGetter("outputFile", &FilamentRecorder::getOutputFile, this);
registerHybridGetter("isRecording", &FilamentRecorder::getIsRecording, this);
registerHybridMethod("startRecording", &FilamentRecorder::startRecording, this);
registerHybridMethod("stopRecording", &FilamentRecorder::stopRecording, this);
registerHybridMethod("renderFrame", &FilamentRecorder::renderFrame, this);
registerHybridMethod("addOnReadyForMoreDataListener", &FilamentRecorder::addOnReadyForMoreDataListener, this);
HybridObject::loadHybridMethods();
registerHybrids(this, [](nitro::Prototype& proto) {
proto.registerHybridGetter("width", &FilamentRecorder::getWidth);
proto.registerHybridGetter("height", &FilamentRecorder::getHeight);
proto.registerHybridGetter("fps", &FilamentRecorder::getFps);
proto.registerHybridGetter("bitRate", &FilamentRecorder::getBitRate);
proto.registerHybridGetter("outputFile", &FilamentRecorder::getOutputFile);
proto.registerHybridGetter("isRecording", &FilamentRecorder::getIsRecording);
proto.registerHybridMethod("startRecording", &FilamentRecorder::startRecording);
proto.registerHybridMethod("stopRecording", &FilamentRecorder::stopRecording);
proto.registerHybridMethod("renderFrame", &FilamentRecorder::renderFrame);
// TODO: nitro
// proto.registerHybridMethod("addOnReadyForMoreDataListener", &FilamentRecorder::addOnReadyForMoreDataListener);
});
}

std::shared_ptr<Listener> FilamentRecorder::addOnReadyForMoreDataListener(ReadyForMoreDataCallback callback) {
std::shared_ptr<Listener> FilamentRecorder::addOnReadyForMoreDataListener(const ReadyForMoreDataCallback& callback) {
return _listenerManager->add(callback);
}

Expand Down
Loading
Loading