mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Improve caching of Text per shadow Node
Summary: This diff optimizes text measurement by adding a layer of caching per shadow node. When ReactFeatureFlags.enableTextMeasureCachePerShadowNode is enabled, we will cache and reused measurements per shadow node. This optimization showed a 2x improvement on text rendearing when a screen contains a big amount of text components. Changelog: [Internal] Internal Reviewed By: sammy-SC Differential Revision: D44221170 fbshipit-source-id: c3e7ba1ad216929826a99585874981717c90e13b
This commit is contained in:
committed by
Lorenzo Sciandra
parent
05ba16aa3d
commit
f5fbda5e46
+3
@@ -75,6 +75,9 @@ public class ReactFeatureFlags {
|
||||
/** Feature Flag to enable the pending event queue in fabric before mounting views */
|
||||
public static boolean enableFabricPendingEventQueue = false;
|
||||
|
||||
/** Feature Flag to enable caching mechanism of text measurement at shadow node level */
|
||||
public static boolean enableTextMeasureCachePerShadowNode = false;
|
||||
|
||||
/**
|
||||
* Feature flag that controls how turbo modules are exposed to JS
|
||||
*
|
||||
|
||||
@@ -429,6 +429,9 @@ void Binding::installFabricUIManager(
|
||||
"CalculateTransformedFramesEnabled",
|
||||
getFeatureFlagValue("calculateTransformedFramesEnabled"));
|
||||
|
||||
CoreFeatures::cacheLastTextMeasurement =
|
||||
getFeatureFlagValue("enableTextMeasureCachePerShadowNode");
|
||||
|
||||
// Props setter pattern feature
|
||||
CoreFeatures::enablePropIteratorSetter =
|
||||
getFeatureFlagValue("enableCppPropsIteratorSetter");
|
||||
|
||||
+30
-5
@@ -15,6 +15,19 @@ TextMeasurement ParagraphLayoutManager::measure(
|
||||
AttributedString const &attributedString,
|
||||
ParagraphAttributes const ¶graphAttributes,
|
||||
LayoutConstraints layoutConstraints) const {
|
||||
bool cacheLastTextMeasurement = CoreFeatures::cacheLastTextMeasurement;
|
||||
if (cacheLastTextMeasurement &&
|
||||
(layoutConstraints.maximumSize.width == availableWidth_ ||
|
||||
layoutConstraints.maximumSize.width ==
|
||||
cachedTextMeasurement_.size.width)) {
|
||||
/* Yoga has requested measurement for this size before. Let's use cached
|
||||
* value. `TextLayoutManager` might not have cached this because it could be
|
||||
* using different width to generate cache key. This happens because Yoga
|
||||
* switches between available width and exact width but since we already
|
||||
* know exact width, it is wasteful to calculate it again.
|
||||
*/
|
||||
return cachedTextMeasurement_;
|
||||
}
|
||||
if (CoreFeatures::cacheNSTextStorage) {
|
||||
size_t newHash = folly::hash::hash_combine(
|
||||
0,
|
||||
@@ -28,11 +41,23 @@ TextMeasurement ParagraphLayoutManager::measure(
|
||||
}
|
||||
}
|
||||
|
||||
return textLayoutManager_->measure(
|
||||
AttributedStringBox(attributedString),
|
||||
paragraphAttributes,
|
||||
layoutConstraints,
|
||||
hostTextStorage_);
|
||||
if (cacheLastTextMeasurement) {
|
||||
cachedTextMeasurement_ = textLayoutManager_->measure(
|
||||
AttributedStringBox(attributedString),
|
||||
paragraphAttributes,
|
||||
layoutConstraints,
|
||||
hostTextStorage_);
|
||||
|
||||
availableWidth_ = layoutConstraints.maximumSize.width;
|
||||
|
||||
return cachedTextMeasurement_;
|
||||
} else {
|
||||
return textLayoutManager_->measure(
|
||||
AttributedStringBox(attributedString),
|
||||
paragraphAttributes,
|
||||
layoutConstraints,
|
||||
hostTextStorage_);
|
||||
}
|
||||
}
|
||||
|
||||
LinesMeasurements ParagraphLayoutManager::measureLines(
|
||||
|
||||
+12
@@ -54,6 +54,18 @@ class ParagraphLayoutManager {
|
||||
std::shared_ptr<TextLayoutManager const> mutable textLayoutManager_{};
|
||||
std::shared_ptr<void> mutable hostTextStorage_{};
|
||||
|
||||
/* The width Yoga set as maximum width.
|
||||
* Yoga sometimes calls measure twice with two
|
||||
* different maximum width. One if available space.
|
||||
* The other one is exact space needed for the string.
|
||||
* This happens when node is dirtied but its size is not affected.
|
||||
* To deal with this inefficiency, we cache `TextMeasurement` for each
|
||||
* `ParagraphShadowNode`. If Yoga tries to re-measure with available width
|
||||
* or exact width, we provide it with the cached value.
|
||||
*/
|
||||
Float mutable availableWidth_{};
|
||||
TextMeasurement mutable cachedTextMeasurement_{};
|
||||
|
||||
size_t mutable hash_{};
|
||||
};
|
||||
} // namespace facebook::react
|
||||
|
||||
@@ -15,6 +15,7 @@ bool CoreFeatures::enableMapBuffer = false;
|
||||
bool CoreFeatures::blockPaintForUseLayoutEffect = false;
|
||||
bool CoreFeatures::useNativeState = false;
|
||||
bool CoreFeatures::cacheNSTextStorage = false;
|
||||
bool CoreFeatures::cacheLastTextMeasurement = false;
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
||||
@@ -39,6 +39,11 @@ class CoreFeatures {
|
||||
// creating it twice. Once when measuring text and once when rendering it.
|
||||
// This flag caches it inside ParagraphState.
|
||||
static bool cacheNSTextStorage;
|
||||
|
||||
// Yoga might measure multiple times the same Text with the same constraints
|
||||
// This flag enables a caching mechanism to avoid subsequents measurements
|
||||
// of the same Text with the same constrainst.
|
||||
static bool cacheLastTextMeasurement;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
|
||||
+5
-1
@@ -12,6 +12,7 @@
|
||||
#include <react/common/mapbuffer/JReadableMapBuffer.h>
|
||||
#include <react/jni/ReadableNativeMap.h>
|
||||
#include <react/renderer/attributedstring/conversions.h>
|
||||
#include <react/renderer/core/CoreFeatures.h>
|
||||
#include <react/renderer/core/conversions.h>
|
||||
#include <react/renderer/mapbuffer/MapBuffer.h>
|
||||
#include <react/renderer/mapbuffer/MapBufferBuilder.h>
|
||||
@@ -146,7 +147,10 @@ Size measureAndroidComponentMapBuffer(
|
||||
TextLayoutManager::TextLayoutManager(
|
||||
const ContextContainer::Shared &contextContainer)
|
||||
: contextContainer_(contextContainer),
|
||||
measureCache_(kSimpleThreadSafeCacheSizeCap) {}
|
||||
measureCache_(
|
||||
CoreFeatures::cacheLastTextMeasurement
|
||||
? 8096
|
||||
: kSimpleThreadSafeCacheSizeCap) {}
|
||||
|
||||
void *TextLayoutManager::getNativeTextLayoutManager() const {
|
||||
return self_;
|
||||
|
||||
Reference in New Issue
Block a user