Skip to content

Add UIBatchingQueue to bridgeless mode #12812

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

Merged
merged 11 commits into from
Mar 11, 2024
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Add UIBatchingQueue to bridgeless mode",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -6325,7 +6325,7 @@ exports[`View Tests Views can have layout conformance 1`] = `
],
"Opacity": 1,
"Size": [
60,
0,
30,
],
"Visual Type": "SpriteVisual",
Expand All @@ -6351,7 +6351,7 @@ exports[`View Tests Views can have layout conformance 1`] = `
],
"Opacity": 1,
"Size": [
60,
0,
30,
],
"Visual Type": "SpriteVisual",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,11 @@ void CompositionReactViewInstance::UpdateRootView() noexcept {
}

void CompositionReactViewInstance::UninitRootView() noexcept {
assert(m_uiDispatcher.HasThreadAccess());
if (auto rootControl = m_weakRootControl.get()) {
rootControl->UninitRootView();
if (m_uiDispatcher) {
assert(m_uiDispatcher.HasThreadAccess());
if (auto rootControl = m_weakRootControl.get()) {
rootControl->UninitRootView();
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ void CompositionUIService::SetCompositionContext(
ICompositionContext const &compositionContext) noexcept {
ReactPropertyBag(properties).Set(CompositionContextPropertyId(), compositionContext);
// Default to using Bridgeless mode when using fabric
/*
winrt::Microsoft::ReactNative::implementation::QuirkSettings::SetIsBridgeless(
ReactPropertyBag(properties), !!compositionContext);
*/
}

ICompositionContext CompositionUIService::GetCompositionContext(const IReactPropertyBag &properties) noexcept {
Expand Down
10 changes: 8 additions & 2 deletions vnext/Microsoft.ReactNative/Modules/Timing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,20 @@ TimerRegistry::~TimerRegistry() {
m_timingModule->DetachBridgeless();
}

double SchedulingTimeNow() {
const int64_t msFrom1601to1970 = 11644473600000;
return std::chrono::duration<double, std::milli>(TDateTime::clock::now().time_since_epoch()).count() -
msFrom1601to1970;
}

void TimerRegistry::createTimer(uint32_t timerID, double delayMS) {
m_timingModule->createTimer(timerID, delayMS / 1000.0, 0.0f, false);
m_timingModule->createTimer(timerID, delayMS, SchedulingTimeNow(), false);
}
void TimerRegistry::deleteTimer(uint32_t timerID) {
m_timingModule->deleteTimer(timerID);
}
void TimerRegistry::createRecurringTimer(uint32_t timerID, double delayMS) {
m_timingModule->createTimer(timerID, delayMS / 1000.0, 0.0f, true);
m_timingModule->createTimer(timerID, delayMS, SchedulingTimeNow(), true);
}

void TimerRegistry::callTimers(const vector<uint32_t> &ids) noexcept {
Expand Down
91 changes: 58 additions & 33 deletions vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,20 @@ Mso::DispatchQueueSettings CreateDispatchQueueSettings(
#ifdef USE_FABRIC
void ReactInstanceWin::InitializeBridgeless() noexcept {
InitUIQueue();

m_uiMessageThread.Exchange(std::make_shared<MessageDispatchQueue2>(
*m_uiQueue, Mso::MakeWeakMemberFunctor(this, &ReactInstanceWin::OnError)));

ReactPropertyBag(m_reactContext->Properties())
.Set(
winrt::Microsoft::ReactNative::implementation::ReactCoreInjection::PostToUIBatchingQueueProperty(),
[wkBatchingUIThread = std::weak_ptr<facebook::react::MessageQueueThread>(m_uiMessageThread.Load())](
winrt::Microsoft::ReactNative::ReactDispatcherCallback const &callback) {
if (auto batchingUIThread = wkBatchingUIThread.lock()) {
batchingUIThread->runOnQueue(callback);
}
});

InitDevMenu();

m_uiQueue->Post([this, weakThis = Mso::WeakPtr{this}]() noexcept {
Expand Down Expand Up @@ -583,31 +597,33 @@ void ReactInstanceWin::InitializeBridgeless() noexcept {
Mso::MakeWeakMemberFunctor(this, &ReactInstanceWin::OnError),
Mso::Copy(m_whenDestroyed)));

auto timerRegistry = ::Microsoft::ReactNative::TimerRegistry::CreateTimerRegistry(
m_options.Properties.Get(ReactDispatcherHelper::UIDispatcherProperty()).try_as<IReactDispatcher>());
auto timerRegistryRaw = timerRegistry.get();
m_jsMessageThread.Load()->runOnQueueSync([&]() {
::SetThreadDescription(GetCurrentThread(), L"React-Native JavaScript Thread");
auto timerRegistry = ::Microsoft::ReactNative::TimerRegistry::CreateTimerRegistry(
m_options.Properties.Get(ReactDispatcherHelper::UIDispatcherProperty()).try_as<IReactDispatcher>());
auto timerRegistryRaw = timerRegistry.get();

auto timerManager = std::make_shared<facebook::react::TimerManager>(std::move(timerRegistry));
timerRegistryRaw->setTimerManager(timerManager);
auto timerManager = std::make_shared<facebook::react::TimerManager>(std::move(timerRegistry));
timerRegistryRaw->setTimerManager(timerManager);

auto jsErrorHandlingFunc = [this](facebook::react::MapBuffer errorMap) noexcept {
OnJSError(std::move(errorMap));
};
auto jsErrorHandlingFunc = [this](facebook::react::MapBuffer errorMap) noexcept {
OnJSError(std::move(errorMap));
};

m_jsiRuntimeHolder = std::make_shared<Microsoft::ReactNative::HermesRuntimeHolder>(
devSettings, m_jsMessageThread.Load(), CreateHermesPreparedScriptStore());
m_bridgelessReactInstance = std::make_unique<facebook::react::ReactInstance>(
std::make_unique<Microsoft::ReactNative::HermesJSRuntime>(m_jsiRuntimeHolder),
m_jsMessageThread.Load(),
timerManager,
jsErrorHandlingFunc);
m_jsiRuntimeHolder = std::make_shared<Microsoft::ReactNative::HermesRuntimeHolder>(
devSettings, m_jsMessageThread.Load(), CreateHermesPreparedScriptStore());
auto jsRuntime = std::make_unique<Microsoft::ReactNative::HermesJSRuntime>(m_jsiRuntimeHolder);
jsRuntime->getRuntime();
m_bridgelessReactInstance = std::make_unique<facebook::react::ReactInstance>(
std::move(jsRuntime), m_jsMessageThread.Load(), timerManager, jsErrorHandlingFunc);

auto bufferedRuntimeExecutor = m_bridgelessReactInstance->getBufferedRuntimeExecutor();
timerManager->setRuntimeExecutor(bufferedRuntimeExecutor);
auto bufferedRuntimeExecutor = m_bridgelessReactInstance->getBufferedRuntimeExecutor();
timerManager->setRuntimeExecutor(bufferedRuntimeExecutor);

Microsoft::ReactNative::SchedulerSettings::SetRuntimeScheduler(
winrt::Microsoft::ReactNative::ReactPropertyBag(m_options.Properties),
m_bridgelessReactInstance->getRuntimeScheduler());
Microsoft::ReactNative::SchedulerSettings::SetRuntimeScheduler(
winrt::Microsoft::ReactNative::ReactPropertyBag(m_options.Properties),
m_bridgelessReactInstance->getRuntimeScheduler());
});

facebook::react::ReactInstance::JSRuntimeFlags options;
m_bridgelessReactInstance->initializeRuntime(options, [=](facebook::jsi::Runtime &runtime) {
Expand Down Expand Up @@ -650,6 +666,7 @@ void ReactInstanceWin::InitializeBridgeless() noexcept {
FireInstanceCreatedCallback();

LoadJSBundlesBridgeless(devSettings);
SetupHMRClient();

} catch (std::exception &e) {
OnErrorWithMessage(e.what());
Expand Down Expand Up @@ -830,18 +847,7 @@ void ReactInstanceWin::InitializeWithBridge() noexcept {

FireInstanceCreatedCallback();
LoadJSBundles();

if (UseDeveloperSupport() && State() != ReactInstanceState::HasError) {
folly::dynamic params = folly::dynamic::array(
winrt::Microsoft::ReactNative::implementation::ReactCoreInjection::GetPlatformName(
m_reactContext->Properties()),
DebugBundlePath(),
SourceBundleHost(),
SourceBundlePort(),
m_isFastReloadEnabled,
"ws");
m_instance.Load()->callJSFunction("HMRClient", "setup", std::move(params));
}
SetupHMRClient();

} catch (std::exception &e) {
OnErrorWithMessage(e.what());
Expand All @@ -858,6 +864,20 @@ void ReactInstanceWin::InitializeWithBridge() noexcept {
});
}

void ReactInstanceWin::SetupHMRClient() noexcept {
if (UseDeveloperSupport() && State() != ReactInstanceState::HasError) {
folly::dynamic params = folly::dynamic::array(
winrt::Microsoft::ReactNative::implementation::ReactCoreInjection::GetPlatformName(
m_reactContext->Properties()),
DebugBundlePath(),
SourceBundleHost(),
SourceBundlePort(),
m_isFastReloadEnabled,
"ws");
CallJsFunction("HMRClient", "setup", std::move(params));
}
}

void ReactInstanceWin::LoadJSBundles() noexcept {
//
// We use m_jsMessageThread to load JS bundles synchronously. In that case we only load
Expand Down Expand Up @@ -1292,7 +1312,12 @@ void ReactInstanceWin::DrainJSCallQueue() noexcept {
}
}

if (auto instance = m_instance.LoadWithLock()) {
#ifdef USE_FABRIC
if (m_bridgelessReactInstance) {
m_bridgelessReactInstance->callFunctionOnModule(entry.ModuleName, entry.MethodName, entry.Args);
} else
#endif
if (auto instance = m_instance.LoadWithLock()) {
instance->callJSFunction(std::move(entry.ModuleName), std::move(entry.MethodName), std::move(entry.Args));
}
}
Expand Down
1 change: 1 addition & 0 deletions vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class ReactInstanceWin final : public Mso::ActiveObject<IReactInstanceInternal>
void InitJSMessageThread() noexcept;
void InitNativeMessageThread() noexcept;
void InitUIMessageThread() noexcept;
void SetupHMRClient() noexcept;
#ifndef CORE_ABI
void InitUIManager() noexcept;
#endif
Expand Down