Skip to content
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

wip: nitrogen #256

Closed
wants to merge 14 commits into from
Closed
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
13 changes: 8 additions & 5 deletions package/android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ find_package(ReactAndroid REQUIRED CONFIG)
find_package(fbjni REQUIRED CONFIG)
find_library(LOG_LIB log)

include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/RNF+autolinking.cmake)

# Add react-native-filament sources
add_library(
${PACKAGE_NAME}
Expand Down Expand Up @@ -127,7 +129,7 @@ target_link_libraries(
)

# Link with RNWC:
if (IS_OLD_ARCHITECTURE_ENABLED)
if(IS_OLD_ARCHITECTURE_ENABLED)
# On the old arch RNWC publishes a prefab that we need to find (and it has a different name):
find_package(react-native-worklets-core REQUIRED CONFIG)
message("RN Filament: react-native-worklets core found! Enabling Worklets support...")
Expand All @@ -136,13 +138,14 @@ if (IS_OLD_ARCHITECTURE_ENABLED)
${PACKAGE_NAME}
react-native-worklets-core::rnworklets
)
else ()
else()
target_link_libraries(
${PACKAGE_NAME}
react_codegen_rnfilament # link against the codegen generated library of rnf (needed so this module is compiled correctly)
react-native-worklets-core
${PACKAGE_NAME}
react_codegen_rnfilament # link against the codegen generated library of rnf (needed so this module is compiled correctly)
react-native-worklets-core
)
endif()

add_definitions(-DHAS_WORKLETS=1)

# Filament (local CMake project as a git submodule)
Expand Down
2 changes: 1 addition & 1 deletion package/cpp/RNFChoreographer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void Choreographer::onFrame(double timestamp) {
}

void Choreographer::removeAllListeners() {
Logger::log(TAG, "Removing all listeners");
margelo::Logger::log(TAG, "Removing all listeners");
// Simply create a new ListenerManager, so the memory of the old one gets freed.
_listeners = ListenerManager<OnFrameCallback>::create();
}
Expand Down
5 changes: 3 additions & 2 deletions package/cpp/RNFChoreographer.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

#pragma once

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

Expand All @@ -14,7 +15,7 @@ class Choreographer {
public:
explicit Choreographer() {}
~Choreographer() {
Logger::log("Choreographer", "(MEMORY) Deleting Choreographer... ❌");
margelo::Logger::log("Choreographer", "(MEMORY) Deleting Choreographer... ❌");
}
using OnFrameCallback = std::function<void(double timestamp)>;

Expand Down
43 changes: 16 additions & 27 deletions package/cpp/RNFChoreographerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,6 @@ ChoreographerWrapper::~ChoreographerWrapper() {
stopAndRemoveListeners();
}

void ChoreographerWrapper::loadHybridMethods() {
registerHybridMethod("start", &ChoreographerWrapper::start, this);
registerHybridMethod("stop", &ChoreographerWrapper::stop, this);
registerHybridMethod("addFrameCallbackListener", &ChoreographerWrapper::addFrameCallbackListener, this);
registerHybridMethod("release", &ChoreographerWrapper::release, this, true);
}

void ChoreographerWrapper::start() {
std::unique_lock lock(_mutex);

Expand All @@ -31,17 +24,17 @@ void ChoreographerWrapper::stop() {
pointee()->stop();
}

std::shared_ptr<Listener> ChoreographerWrapper::addFrameCallbackListener(RenderCallback onFrameCallback) {
std::shared_ptr<HybridListenerSpec> ChoreographerWrapper::addFrameCallbackListener(const std::function<void(const FrameInfo& /* frameInfo */)>& callback) {
std::unique_lock lock(_mutex);

Logger::log(TAG, "Adding frame callback listener");
margelo::Logger::log(HybridChoreographerSpec::TAG, "Adding frame callback listener");

std::weak_ptr<ChoreographerWrapper> weakThis = shared<ChoreographerWrapper>();
return pointee()->addOnFrameListener([weakThis, onFrameCallback](double timestamp) {
return pointee()->addOnFrameListener([weakThis, callback](double timestamp) {
auto sharedThis = weakThis.lock();
if (sharedThis) {
FrameInfo frameInfo = sharedThis->createFrameInfo(timestamp);
onFrameCallback(frameInfo);
callback(frameInfo);
}
});
}
Expand All @@ -57,42 +50,38 @@ FrameInfo ChoreographerWrapper::createFrameInfo(double timestamp) {
double passedSeconds = (timestamp - _startTime) / 1e9;
double timeSinceLastFrame = (timestamp - _lastFrameTime) / 1e9;
_lastFrameTime = timestamp;
return {
{"timestamp", timestamp},
{"passedSeconds", passedSeconds},
{"startTime", _startTime},
{"timeSinceLastFrame", timeSinceLastFrame},
};
return FrameInfo(timestamp, _startTime, passedSeconds, timeSinceLastFrame);
}

void ChoreographerWrapper::stopAndRemoveListeners() {
// Its possible that the pointer was already released manually by the user
if (!getIsValid()) {
Logger::log(TAG, "stopAndRemoveListeners() called but Choreographer is invalid already!");
if (!HybridPointerHolder::getIsValid()) {
margelo::Logger::log(HybridChoreographerSpec::TAG, "stopAndRemoveListeners() called but Choreographer is invalid already!");
return;
}

Logger::log(TAG, "Stopping choreographer and removing listeners...");
margelo::Logger::log(HybridChoreographerSpec::TAG, "Stopping choreographer and removing listeners...");
pointee()->stop();
// Clear all listeners now - that will cause the listeners function destructors to be called
// When onRuntimeDestroyed gets called we still have time to stopAndRemoveListeners our jsi functions (RenderCallback):
pointee()->removeAllListeners();
}

void ChoreographerWrapper::release() {
std::unique_lock lock(_mutex);
stopAndRemoveListeners();
PointerHolder::release();
}
// TODO: tries to overwrite release from PointerHolder
//void ChoreographerWrapper::release() {
// std::unique_lock lock(_mutex);
// stopAndRemoveListeners();
// PointerHolder::release();
//}

void ChoreographerWrapper::onRuntimeDestroyed(jsi::Runtime*) {
std::unique_lock lock(_mutex);
Logger::log(TAG, "Runtime destroyed...");
margelo::Logger::log(HybridChoreographerSpec::TAG, "Runtime destroyed...");
stopAndRemoveListeners();
}

std::shared_ptr<Choreographer> ChoreographerWrapper::getChoreographer() {
if (getIsValid()) {
if (HybridPointerHolder::getIsValid()) {
return pointee();
}
return nullptr;
Expand Down
19 changes: 8 additions & 11 deletions package/cpp/RNFChoreographerWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@

#pragma once

#include "HybridChoreographerSpec.hpp"
#include "RNFChoreographer.h"
#include "jsi/RNFPointerHolder.h"
#include "jsi/RNFHybridPointerHolder.h"
#include "jsi/RNFRuntimeCache.h"

namespace margelo {

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

class ChoreographerWrapper : public PointerHolder<Choreographer>, public RuntimeLifecycleListener {
class ChoreographerWrapper : public HybridChoreographerSpec, public HybridPointerHolder<Choreographer>, public RuntimeLifecycleListener {
public:
explicit ChoreographerWrapper(std::shared_ptr<Choreographer> choreographer) : PointerHolder(TAG, choreographer) {}
explicit ChoreographerWrapper(std::shared_ptr<Choreographer> choreographer) : HybridChoreographerSpec(), HybridPointerHolder(HybridChoreographerSpec::TAG, choreographer) {}
~ChoreographerWrapper() override;

void loadHybridMethods() override;
Expand All @@ -25,9 +25,9 @@ class ChoreographerWrapper : public PointerHolder<Choreographer>, public Runtime
friend class FilamentView; // Allow filament view to access protected method

private: // Exposed JS API
void start();
void stop();
std::shared_ptr<Listener> addFrameCallbackListener(RenderCallback onFrameCallback);
void start() override;
void stop() override;
std::shared_ptr<HybridListenerSpec> addFrameCallbackListener(const std::function<void(const FrameInfo& /* frameInfo */)>& callback) override;
void release() override;

private: // Internal
Expand All @@ -39,8 +39,5 @@ class ChoreographerWrapper : public PointerHolder<Choreographer>, public Runtime
std::mutex _mutex;
double _startTime = 0;
double _lastFrameTime = 0;

private:
static constexpr auto TAG = "ChoreographerWrapper";
};
} // namespace margelo
7 changes: 3 additions & 4 deletions package/cpp/RNFFilamentBuffer.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
#pragma once

#include "RNFManagedBuffer.h"
#include "jsi/RNFPointerHolder.h"
#include "jsi/RNFHybridPointerHolder.h"

namespace margelo {

class FilamentBuffer : public PointerHolder<ManagedBuffer> {
class FilamentBuffer : public HybridPointerHolder<ManagedBuffer> {
public:
explicit FilamentBuffer(std::shared_ptr<ManagedBuffer> buffer) : PointerHolder("FilamentBuffer", buffer) {}
void loadHybridMethods() override {}
explicit FilamentBuffer(std::shared_ptr<ManagedBuffer> buffer) : HybridPointerHolder("FilamentBuffer", buffer) {}

std::shared_ptr<ManagedBuffer> getBuffer() {
return pointee();
Expand Down
30 changes: 15 additions & 15 deletions package/cpp/RNFFilamentProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,30 +45,30 @@ bool FilamentProxy::getHasWorklets() {

#if HAS_WORKLETS
std::shared_ptr<RNWorklet::JsiWorkletContext> FilamentProxy::createWorkletContext() {
Logger::log(TAG, "Creating Worklet Context...");
margelo::Logger::log(TAG, "Creating Worklet Context...");
auto jsDispatcher = getJSDispatcher();
auto runOnJS = [=](std::function<void()>&& function) { jsDispatcher->runAsync(std::move(function)); };
auto renderThreadDispatcher = getRenderThreadDispatcher();
auto runOnWorklet = [=](std::function<void()>&& function) { renderThreadDispatcher->runAsync(std::move(function)); };
auto& runtime = getMainJSRuntime();
auto workletContext = std::make_shared<RNWorklet::JsiWorkletContext>("FilamentRenderer", &runtime, runOnJS, runOnWorklet);
Logger::log(TAG, "Successfully created WorkletContext! Installing global Dispatcher...");
margelo::Logger::log(TAG, "Successfully created WorkletContext! Installing global Dispatcher...");

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

return workletContext;
}
#endif

jsi::Value FilamentProxy::getCurrentDispatcher(jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*, size_t) {
return Dispatcher::getRuntimeGlobalDispatcherHolder(runtime);
return margelo::Dispatcher::getRuntimeGlobalDispatcherHolder(runtime);
}

std::future<std::shared_ptr<FilamentBuffer>> FilamentProxy::loadAssetAsync(const std::string& path) {
Logger::log(TAG, "Loading asset %s...", path.c_str());
margelo::Logger::log(TAG, "Loading asset %s...", path.c_str());
auto weakThis = std::weak_ptr<FilamentProxy>(shared<FilamentProxy>());
auto dispatcher = getBackgroundDispatcher();
return dispatcher->runAsyncAwaitable<std::shared_ptr<FilamentBuffer>>([weakThis, path]() {
Expand All @@ -82,7 +82,7 @@ std::future<std::shared_ptr<FilamentBuffer>> FilamentProxy::loadAssetAsync(const
}

std::future<std::shared_ptr<FilamentView>> FilamentProxy::findFilamentViewAsync(int id) {
Logger::log(TAG, "Finding FilamentView #%i...", id);
margelo::Logger::log(TAG, "Finding FilamentView #%i...", id);
auto weakThis = std::weak_ptr<FilamentProxy>(shared<FilamentProxy>());
auto dispatcher = getUIDispatcher();
return dispatcher->runAsyncAwaitable<std::shared_ptr<FilamentView>>([weakThis, id]() {
Expand All @@ -96,15 +96,15 @@ std::future<std::shared_ptr<FilamentView>> FilamentProxy::findFilamentViewAsync(
}

std::shared_ptr<TestHybridObject> FilamentProxy::createTestObject() {
Logger::log(TAG, "Creating TestObject...");
margelo::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...");
margelo::Logger::log(TAG, "Creating Engine...");

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

Engine::Config config = EngineConfigHelper::makeConfigFromUserParams(arguments);
Engine::Backend backendEnum = Engine::Backend::DEFAULT;
Expand All @@ -118,14 +118,14 @@ std::shared_ptr<EngineWrapper> FilamentProxy::createEngine(std::optional<std::st
// Make sure that the engine gets destroyed on the thread that it was created on.
// It can happen that the engine gets cleaned up by Hades (hermes GC) on a different thread.
renderThread->runAsync([engine]() {
Logger::log(TAG, "Destroying engine...");
margelo::Logger::log(TAG, "Destroying engine...");
Engine::destroy(engine);
});
});

// Get screen refresh rate
float refreshRate = getDisplayRefreshRate();
Logger::log(TAG, "Display refresh rate: %f Hz", refreshRate);
margelo::Logger::log(TAG, "Display refresh rate: %f Hz", refreshRate);

float densityPixelRatio = getDensityPixelRatio();

Expand All @@ -136,13 +136,13 @@ std::shared_ptr<EngineWrapper> FilamentProxy::createEngine(std::optional<std::st
}

std::shared_ptr<BulletWrapper> FilamentProxy::createBullet() {
Logger::log(TAG, "Creating Bullet...");
margelo::Logger::log(TAG, "Creating Bullet...");
return std::make_shared<BulletWrapper>();
}

jsi::Value FilamentProxy::createChoreographerWrapper(jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*, size_t) {

Logger::log(TAG, "Creating Choreographer...");
margelo::Logger::log(TAG, "Creating Choreographer...");
std::shared_ptr<Choreographer> choreographer = createChoreographer();

ChoreographerWrapper* choreographerWrapperPtr = new ChoreographerWrapper(choreographer);
Expand All @@ -157,7 +157,7 @@ jsi::Value FilamentProxy::createChoreographerWrapper(jsi::Runtime& runtime, cons
delete ptr;
});

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

} // namespace margelo
12 changes: 7 additions & 5 deletions package/cpp/RNFFilamentProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <string>
#include <vector>

#include "HybridFilamentProxy.hpp"
#include "RNFChoreographer.h"
#include "RNFChoreographerWrapper.h"
#include "RNFFilamentBuffer.h"
Expand All @@ -36,8 +37,9 @@
namespace margelo {

using namespace facebook;
using namespace margelo::RNF;

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

Expand All @@ -51,22 +53,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<margelo::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<margelo::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<margelo::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<margelo::Dispatcher> getBackgroundDispatcher() = 0;
/**
* Get the refresh rate of the display in Hz.
* Needed for correct frame pacing and dynamic resolution calculations.
Expand Down
6 changes: 3 additions & 3 deletions package/cpp/RNFFilamentRecorder.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ namespace margelo {

using namespace facebook;

class FilamentRecorder : public HybridObject {
class FilamentRecorder : public margelo::HybridObject {
public:
using ReadyForMoreDataCallback = std::function<bool()>;

public:
explicit FilamentRecorder(std::shared_ptr<Dispatcher> renderThreadDispatcher, int width, int height, int fps, double bitRate);
explicit FilamentRecorder(std::shared_ptr<margelo::Dispatcher> renderThreadDispatcher, int width, int height, int fps, double bitRate);
~FilamentRecorder();

public:
Expand Down Expand Up @@ -77,7 +77,7 @@ class FilamentRecorder : public HybridObject {
static constexpr auto TAG = "FilamentRecorder";

protected:
std::shared_ptr<Dispatcher> _renderThreadDispatcher;
std::shared_ptr<margelo::Dispatcher> _renderThreadDispatcher;
int _width;
int _height;
int _fps;
Expand Down
Loading