Skip to content

Commit 30c248f

Browse files
authored
Min suport for manual rendering (#138)
1 parent 91cdda2 commit 30c248f

File tree

2 files changed

+54
-12
lines changed

2 files changed

+54
-12
lines changed

Modules/@babylonjs/react-native/shared/BabylonNative.cpp

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,18 @@ namespace Babylon
1414
{
1515
using namespace facebook;
1616

17+
namespace
18+
{
19+
Dispatcher g_inlineDispatcher{[](const std::function<void()>& func) { func(); }};
20+
}
21+
1722
class ReactNativeModule : public jsi::HostObject
1823
{
1924
public:
20-
ReactNativeModule(jsi::Runtime& jsiRuntime, Dispatcher jsDispatcher)
25+
ReactNativeModule(jsi::Runtime& jsiRuntime, Dispatcher jsDispatcher, bool autoRender)
2126
: m_env{ Napi::Attach<facebook::jsi::Runtime&>(jsiRuntime) }
2227
, m_jsDispatcher{ std::move(jsDispatcher) }
28+
, m_autoRender{ autoRender }
2329
, m_isRunning{ std::make_shared<bool>(true) }
2430
{
2531
// Initialize a JS promise that will be returned by whenInitialized, and completed when NativeEngine is initialized.
@@ -71,18 +77,28 @@ namespace Babylon
7177

7278
void UpdateView(void* windowPtr, size_t width, size_t height)
7379
{
74-
// TODO: We shouldn't have to dispatch to the JS thread most of this, but not doing so results in a crash.
75-
// I don't understand the issue yet, but for now just retain the pre-refactor logic. We'll need to
76-
// resolve this to enable manual non-JS thread rendering. Note this only repros in release builds
77-
// where we actually call ResetView.
78-
m_jsDispatcher([this, windowPtr, width, height]()
80+
// TODO: We shouldn't have to dispatch to the JS thread for CreateGraphics/UpdateWindow/UpdateSize, but not doing so results in a crash.
81+
// I don't understand the issue yet, but for now just retain the pre-refactor logic. We'll need to resolve this to enable manual
82+
// non-JS thread rendering. Note this only repros in release builds where we actually call ResetView.
83+
84+
// When auto rendering is enabled, we render from the JS thread. In this case, we dispatch to the JS thread to initialize/update graphics,
85+
// and stay on this thread (with an inline dispatcher) to interact with the JS runtime.
86+
// When auto rendering is disabled, we render from a different thread. In this case, we assume this function was called from the render thread
87+
// and do an inline dispatch (e.g. execute synchronously on the calling thread), and switch to the JS thread to interact with the JS runtime.
88+
auto renderDispatcher = m_autoRender ? m_jsDispatcher : g_inlineDispatcher;
89+
auto jsDispatcher = m_autoRender ? g_inlineDispatcher : m_jsDispatcher;
90+
91+
renderDispatcher([this, windowPtr, width, height, jsDispatcher{ std::move(jsDispatcher) }]()
7992
{
8093
if (!m_graphics)
8194
{
8295
m_graphics = Graphics::CreateGraphics(windowPtr, width, height);
83-
m_graphics->AddToJavaScript(m_env);
84-
Plugins::NativeEngine::Initialize(m_env, true);
85-
m_resolveInitPromise();
96+
jsDispatcher([this]()
97+
{
98+
m_graphics->AddToJavaScript(m_env);
99+
Plugins::NativeEngine::Initialize(m_env, m_autoRender);
100+
m_resolveInitPromise();
101+
});
86102
}
87103
else
88104
{
@@ -93,12 +109,24 @@ namespace Babylon
93109
});
94110
}
95111

112+
void RenderView()
113+
{
114+
if (m_autoRender)
115+
{
116+
throw std::runtime_error{ "RenderView can only be called when automatic rendering is disabled." };
117+
}
118+
119+
m_graphics->RenderCurrentFrame();
120+
}
121+
96122
void ResetView()
97123
{
98124
// TODO: We shouldn't have to dispatch to the JS thread for this since we are already on the JS thread,
99125
// but there is an issue in NativeEngine where it will Dispatch a call to RenderCurrentFrame, then
100126
// get disposed, then try to actually render the frame. This results in immediately re-enabling
101127
// graphics after disabling it here. For now, retain the pre-refactor logic (queueing on the JS thread).
128+
// TODO: This is called from JS code (and therefore the JS thread), so we need to figure out a good way
129+
// to get on the proper (render) thread to make this call.
102130
m_jsDispatcher([this]()
103131
{
104132
if (m_graphics)
@@ -170,6 +198,7 @@ namespace Babylon
170198

171199
Napi::Env m_env;
172200
Dispatcher m_jsDispatcher{};
201+
bool m_autoRender{};
173202

174203
std::shared_ptr<bool> m_isRunning{};
175204
std::unique_ptr<Graphics> m_graphics{};
@@ -184,11 +213,11 @@ namespace Babylon
184213
std::weak_ptr<ReactNativeModule> g_nativeModule{};
185214
}
186215

187-
void Initialize(facebook::jsi::Runtime& jsiRuntime, Dispatcher jsDispatcher)
216+
void Initialize(facebook::jsi::Runtime& jsiRuntime, Dispatcher jsDispatcher, bool autoRender)
188217
{
189218
if (!jsiRuntime.global().hasProperty(jsiRuntime, JS_INSTANCE_NAME))
190219
{
191-
auto nativeModule{ std::make_shared<ReactNativeModule>(jsiRuntime, jsDispatcher) };
220+
auto nativeModule{ std::make_shared<ReactNativeModule>(jsiRuntime, jsDispatcher, autoRender) };
192221
jsiRuntime.global().setProperty(jsiRuntime, JS_INSTANCE_NAME, jsi::Object::createFromHostObject(jsiRuntime, nativeModule));
193222
g_nativeModule = nativeModule;
194223
}
@@ -214,6 +243,18 @@ namespace Babylon
214243
}
215244
}
216245

246+
void RenderView()
247+
{
248+
if (auto nativeModule{ g_nativeModule.lock() })
249+
{
250+
nativeModule->RenderView();
251+
}
252+
else
253+
{
254+
throw std::runtime_error{ "RenderView must not be called before Initialize." };
255+
}
256+
}
257+
217258
void SetPointerButtonState(uint32_t pointerId, uint32_t buttonId, bool isDown, uint32_t x, uint32_t y)
218259
{
219260
if (auto nativeModule{ g_nativeModule.lock() })

Modules/@babylonjs/react-native/shared/BabylonNative.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ namespace Babylon
66
{
77
using Dispatcher = std::function<void(std::function<void()>)>;
88

9-
void Initialize(facebook::jsi::Runtime& jsiRuntime, Dispatcher jsDispatcher);
9+
void Initialize(facebook::jsi::Runtime& jsiRuntime, Dispatcher jsDispatcher, bool autoRender = true);
1010
void Deinitialize();
1111
void UpdateView(void* windowPtr, size_t width, size_t height);
12+
void RenderView();
1213
void SetPointerButtonState(uint32_t pointerId, uint32_t buttonId, bool isDown, uint32_t x, uint32_t y);
1314
void SetPointerPosition(uint32_t pointerId, uint32_t x, uint32_t y);
1415
}

0 commit comments

Comments
 (0)