-
Notifications
You must be signed in to change notification settings - Fork 47
Expand file tree
/
Copy pathRNFFilamentProxy.cpp
More file actions
173 lines (140 loc) · 7.08 KB
/
RNFFilamentProxy.cpp
File metadata and controls
173 lines (140 loc) · 7.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//
// Created by Marc Rousavy on 20.02.24.
//
#include "RNFFilamentProxy.h"
#include <jsi/jsi.h>
#include "RNFReferences.h"
#include "core/RNFEngineBackendEnum.h"
#include "core/RNFEngineConfigHelper.h"
#include "jsi/RNFPromise.h"
#include "threading/RNFDispatcher.h"
#include "threading/RNFAsyncQueueImpl.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
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);
#if HAS_WORKLETS
// Newly added APIs:
registerHybridMethod("createWorkletAsyncQueue", &FilamentProxy::createWorkletAsyncQueue, this);
registerHybridMethod("installDispatcher", &FilamentProxy::installDispatcher, this);
registerHybridMethod("box", &FilamentProxy::box, this);
#endif
}
bool FilamentProxy::getHasWorklets() {
#if HAS_WORKLETS
return true;
#else
return false;
#endif
}
#if HAS_WORKLETS
std::shared_ptr<worklets::AsyncQueue> FilamentProxy::createWorkletAsyncQueue() {
Logger::log(TAG, "Creating Worklet AsyncQueue...");
auto renderThreadDispatcher = getRenderThreadDispatcher();
// auto runOnWorklet = [=](std::function<void()>&& function) { renderThreadDispatcher->runAsync(std::move(function)); };
// TODO: i am pretty sure i should hold this dispatcher somewhere? or will the JS engine keep it alive as its NativeState?
auto asyncQueue = std::make_shared<RNFAsyncQueueImpl>(renderThreadDispatcher);
return asyncQueue;
}
jsi::Value FilamentProxy::installDispatcher(jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*, size_t) {
auto renderThreadDispatcher = getRenderThreadDispatcher(); // todo: return dispatcher, and pass it here is cleaner i guess
// Note: one thing that is odd, is that this is called with the correct runtime, but on the "wrong" thread.
// this will still be called from the JS thread, but the runtime is the worklet runtime.
Dispatcher::installRuntimeGlobalDispatcher(runtime, renderThreadDispatcher);
return jsi::Value::undefined();
}
std::shared_ptr<RNFBoxedHybridObject> FilamentProxy::box(const std::shared_ptr<HybridObject>& hybridObject) {
return std::make_shared<RNFBoxedHybridObject>(hybridObject);
}
#endif
jsi::Value FilamentProxy::getCurrentDispatcher(jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*, size_t) {
return Dispatcher::getRuntimeGlobalDispatcherHolder(runtime);
}
std::future<std::shared_ptr<FilamentBuffer>> FilamentProxy::loadAssetAsync(const std::string& path) {
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]() {
auto sharedThis = weakThis.lock();
if (sharedThis != nullptr) {
return sharedThis->loadAsset(path);
} else {
throw std::runtime_error("Failed to load asset, FilamentProxy has already been destroyed!");
}
});
}
std::future<std::shared_ptr<FilamentView>> FilamentProxy::findFilamentViewAsync(int id) {
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]() {
auto sharedThis = weakThis.lock();
if (sharedThis != nullptr) {
return sharedThis->findFilamentView(id);
} else {
throw std::runtime_error("Failed to find Filament View, FilamentProxy has already been destroyed!");
}
});
}
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();
Engine::Config config = EngineConfigHelper::makeConfigFromUserParams(arguments);
Engine::Backend backendEnum = Engine::Backend::DEFAULT;
if (backend.has_value()) {
EnumMapper::convertJSUnionToEnum(backend.value(), &backendEnum);
}
// Create the actual filament engine:
std::shared_ptr<Engine> engine =
References<Engine>::adoptRef(Engine::Builder().backend(backendEnum).config(&config).build(), [renderThread](Engine* engine) {
// 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...");
Engine::destroy(engine);
});
});
// Get screen refresh rate
float refreshRate = getDisplayRefreshRate();
Logger::log(TAG, "Display refresh rate: %f Hz", refreshRate);
float densityPixelRatio = getDensityPixelRatio();
// Create the EngineImpl...
std::shared_ptr<EngineImpl> engineImpl = std::make_shared<EngineImpl>(renderThread, engine, refreshRate, densityPixelRatio);
return std::make_shared<EngineWrapper>(engineImpl);
}
std::shared_ptr<BulletWrapper> FilamentProxy::createBullet() {
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...");
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;
});
return JSIConverter<std::shared_ptr<ChoreographerWrapper>>::toJSI(runtime, choreographerWrapper);
}
} // namespace margelo