Skip to content

Commit c0a2841

Browse files
Fix fast refresh for PG (#454)
* Fix fast refresh for PG * kick the build * build * Windows SDK 10+ * CppWinRT version bump * reworking reset * removed unnecessary changes * cleanup tsx * init promise Android * typo in yml * ios create init promise * no reset on view unmount * removed unused import * comment * revert 1 change * promise reset is done multiplatform * boolean for updateView with fastrefresh * pending reset + comment
1 parent 42b7058 commit c0a2841

File tree

2 files changed

+42
-23
lines changed

2 files changed

+42
-23
lines changed

Modules/@babylonjs/react-native/ReactNativeEngine.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { NativeEngine } from '@babylonjs/core';
66
declare const BabylonNative: {
77
readonly initializationPromise: Promise<void>;
88
reset: () => void;
9+
resetInitializationPromise: () => void;
910
};
1011

1112
export class ReactNativeEngine extends NativeEngine {
@@ -35,12 +36,8 @@ export class ReactNativeEngine extends NativeEngine {
3536
if (!this.isDisposed) {
3637
super.dispose();
3738

38-
// Ideally we would always do a reset here as we don't want different behavior between debug and release. Unfortunately, fast refresh has some strange behavior that
39-
// makes it quite difficult to get this to work correctly (e.g. it re-runs previous useEffect instances, which means it can try to use Babylon Native in a de-initialized state).
40-
// TODO: https://github.com/BabylonJS/BabylonReactNative/issues/125
41-
if (!__DEV__) {
42-
reset();
43-
}
39+
BabylonNative.resetInitializationPromise();
40+
reset();
4441

4542
this._isDisposed = true;
4643
}

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

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -75,26 +75,28 @@ namespace BabylonNative
7575

7676
void UpdateView(WindowType window, size_t width, size_t height)
7777
{
78-
Babylon::Graphics::WindowConfiguration windowConfig{};
79-
windowConfig.Window = window;
80-
windowConfig.Width = width;
81-
windowConfig.Height = height;
78+
m_windowConfig.Window = window;
79+
m_windowConfig.Width = width;
80+
m_windowConfig.Height = height;
81+
UpdateGraphicsConfiguration();
82+
}
8283

84+
void UpdateGraphicsConfiguration()
85+
{
8386
if (!g_graphics)
8487
{
85-
g_graphics = Babylon::Graphics::Device::Create(windowConfig);
88+
g_graphics = Babylon::Graphics::Device::Create(m_windowConfig);
8689
g_update = std::make_unique<Babylon::Graphics::DeviceUpdate>(g_graphics->GetUpdate("update"));
8790
}
8891
else
8992
{
90-
g_graphics->UpdateWindow(windowConfig);
91-
g_graphics->UpdateSize(width, height);
93+
g_graphics->UpdateWindow(m_windowConfig);
94+
g_graphics->UpdateSize(m_windowConfig.Width, m_windowConfig.Height);
9295
}
9396
g_graphics->UpdateMSAA(mMSAAValue);
9497
g_graphics->UpdateAlphaPremultiplied(mAlphaPremultiplied);
9598

9699
g_graphics->EnableRendering();
97-
m_isRenderingEnabled = true;
98100

99101
std::call_once(m_isGraphicsInitialized, [this]()
100102
{
@@ -105,10 +107,15 @@ namespace BabylonNative
105107
});
106108
});
107109

108-
m_jsDispatcher([this]()
110+
if (!m_isRenderingEnabled)
109111
{
110-
m_resolveInitPromise();
111-
});
112+
m_jsDispatcher([this]()
113+
{
114+
m_resolveInitPromise();
115+
});
116+
}
117+
m_isRenderingEnabled = true;
118+
m_pendingReset = false;
112119
}
113120

114121
void UpdateMSAA(uint8_t value)
@@ -131,6 +138,15 @@ namespace BabylonNative
131138

132139
void RenderView()
133140
{
141+
// m_pendingReset becomes true when a resetView call has been performed and no UpdateView has been performed.
142+
// This happens with a fast refresh when the view is not unmounted and it's still available for rendering.
143+
// UpdateView will set back m_pendingReset to false in case the view is unmounted/mounted with Engine.Dispose for example.
144+
// With fast refresh, we have to do that work on the UI/render thread, and UpdateView is not called in that case,
145+
// so RenderView is pretty much the only option. Specifically, it must be done on the UI/render thread and so RenderView is the only hook we have.
146+
if (m_pendingReset)
147+
{
148+
UpdateGraphicsConfiguration();
149+
}
134150
// If rendering has not been explicitly enabled, or has been explicitly disabled, then don't try to render.
135151
// Otherwise rendering can be implicitly enabled, which may not be desirable (e.g. after the engine is disposed).
136152
if (g_graphics && m_isRenderingEnabled)
@@ -148,11 +164,7 @@ namespace BabylonNative
148164
{
149165
g_nativeCanvas->FlushGraphicResources();
150166
g_graphics->DisableRendering();
151-
152-
m_jsDispatcher([this]()
153-
{
154-
CreateInitPromise();
155-
});
167+
m_pendingReset = true;
156168
}
157169

158170
m_isRenderingEnabled = false;
@@ -212,10 +224,17 @@ namespace BabylonNative
212224
{
213225
return { runtime, m_initPromise };
214226
}
227+
else if (propName == "resetInitializationPromise")
228+
{
229+
return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forAscii(runtime, "executor"), 0, [this](jsi::Runtime& rt, const jsi::Value&, const jsi::Value* args, size_t) -> jsi::Value
230+
{
231+
CreateInitPromise();
232+
return {};
233+
});
234+
}
215235

216236
return {};
217237
}
218-
219238
private:
220239
void CreateInitPromise()
221240
{
@@ -246,6 +265,9 @@ namespace BabylonNative
246265
Babylon::Plugins::NativeInput* m_nativeInput{};
247266
std::optional<Babylon::Plugins::NativeXr> m_nativeXr{};
248267

268+
Babylon::Graphics::WindowConfiguration m_windowConfig{};
269+
bool m_pendingReset{};
270+
249271
std::shared_ptr<bool> m_isXRActive{};
250272
uint8_t mMSAAValue{};
251273
bool mAlphaPremultiplied{};

0 commit comments

Comments
 (0)