Makes Yoga threadsafed:

- Uses <atomic> for gNodeInstanceCount & gConfigInstanceCount because of counting instance only.
- Store gCurrentGenerationCount & gDepth in root node for multithreading.
This commit is contained in:
Trung Bui Thanh
2018-06-19 11:13:55 +07:00
parent 2ce219ef42
commit fb7031cd04
3 changed files with 43 additions and 21 deletions

View File

@@ -255,14 +255,17 @@ void YGNode::setNextChild(YGNodeRef nextChild) {
void YGNode::replaceChild(YGNodeRef child, uint32_t index) { void YGNode::replaceChild(YGNodeRef child, uint32_t index) {
children_[index] = child; children_[index] = child;
setChildRoot(child);
} }
void YGNode::replaceChild(YGNodeRef oldChild, YGNodeRef newChild) { void YGNode::replaceChild(YGNodeRef oldChild, YGNodeRef newChild) {
std::replace(children_.begin(), children_.end(), oldChild, newChild); std::replace(children_.begin(), children_.end(), oldChild, newChild);
setChildRoot(newChild);
} }
void YGNode::insertChild(YGNodeRef child, uint32_t index) { void YGNode::insertChild(YGNodeRef child, uint32_t index) {
children_.insert(children_.begin() + index, child); children_.insert(children_.begin() + index, child);
setChildRoot(child);
} }
void YGNode::setConfig(YGConfigRef config) { void YGNode::setConfig(YGConfigRef config) {
@@ -770,3 +773,15 @@ bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const {
} }
return isLayoutTreeEqual; return isLayoutTreeEqual;
} }
YGNodeRef YGNode::getRoot() {
if (pRoot == nullptr) pRoot = this;
return pRoot;
}
void YGNode::setChildRoot(YGNodeRef node) {
node->pRoot = getRoot();
for (auto child: node->children_) {
setChildRoot(child);
}
}

View File

@@ -183,4 +183,13 @@ struct YGNode {
bool isNodeFlexible(); bool isNodeFlexible();
bool didUseLegacyFlag(); bool didUseLegacyFlag();
bool isLayoutTreeEqualToNode(const YGNode& node) const; bool isLayoutTreeEqualToNode(const YGNode& node) const;
private:
YGNodeRef pRoot = nullptr;
public:
uint32_t gCurrentGenerationCount = 0;
uint32_t gDepth = 0;
YGNodeRef getRoot();
void setChildRoot(YGNodeRef node);
}; };

View File

@@ -13,6 +13,7 @@
#include "YGNode.h" #include "YGNode.h"
#include "YGNodePrint.h" #include "YGNodePrint.h"
#include "Yoga-internal.h" #include "Yoga-internal.h"
#include <atomic>
#ifdef _MSC_VER #ifdef _MSC_VER
#include <float.h> #include <float.h>
@@ -211,8 +212,8 @@ void YGNodeMarkDirtyAndPropogateToDescendants(const YGNodeRef node) {
return node->markDirtyAndPropogateDownwards(); return node->markDirtyAndPropogateDownwards();
} }
int32_t gNodeInstanceCount = 0; std::atomic<int32_t> gNodeInstanceCount(0);
int32_t gConfigInstanceCount = 0; std::atomic<int32_t> gConfigInstanceCount(0);
WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) { WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) {
const YGNodeRef node = new YGNode(); const YGNodeRef node = new YGNode();
@@ -243,6 +244,7 @@ YGNodeRef YGNodeClone(YGNodeRef oldNode) {
oldNode->getConfig(), oldNode->getConfig(),
node != nullptr, node != nullptr,
"Could not allocate memory for node"); "Could not allocate memory for node");
oldNode->setChildRoot(node);
gNodeInstanceCount++; gNodeInstanceCount++;
node->setOwner(nullptr); node->setOwner(nullptr);
return node; return node;
@@ -300,8 +302,8 @@ void YGNodeFree(const YGNodeRef node) {
static void YGConfigFreeRecursive(const YGNodeRef root) { static void YGConfigFreeRecursive(const YGNodeRef root) {
if (root->getConfig() != nullptr) { if (root->getConfig() != nullptr) {
gConfigInstanceCount--;
delete root->getConfig(); delete root->getConfig();
gConfigInstanceCount--;
} }
// Delete configs recursively for childrens // Delete configs recursively for childrens
for (uint32_t i = 0; i < root->getChildrenCount(); ++i) { for (uint32_t i = 0; i < root->getChildrenCount(); ++i) {
@@ -959,8 +961,6 @@ bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node) {
return node->getLayout().doesLegacyStretchFlagAffectsLayout; return node->getLayout().doesLegacyStretchFlagAffectsLayout;
} }
uint32_t gCurrentGenerationCount = 0;
bool YGLayoutNodeInternal(const YGNodeRef node, bool YGLayoutNodeInternal(const YGNodeRef node,
const float availableWidth, const float availableWidth,
const float availableHeight, const float availableHeight,
@@ -1219,8 +1219,7 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
if (child->getLayout().computedFlexBasis.isUndefined() || if (child->getLayout().computedFlexBasis.isUndefined() ||
(YGConfigIsExperimentalFeatureEnabled( (YGConfigIsExperimentalFeatureEnabled(
child->getConfig(), YGExperimentalFeatureWebFlexBasis) && child->getConfig(), YGExperimentalFeatureWebFlexBasis) &&
child->getLayout().computedFlexBasisGeneration != child->getLayout().computedFlexBasisGeneration != node->getRoot()->gCurrentGenerationCount)) {
gCurrentGenerationCount)) {
const YGFloatOptional& paddingAndBorder = YGFloatOptional( const YGFloatOptional& paddingAndBorder = YGFloatOptional(
YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth)); YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth));
child->setLayoutComputedFlexBasis( child->setLayoutComputedFlexBasis(
@@ -1360,7 +1359,7 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
child->getLayout().measuredDimensions[dim[mainAxis]], child->getLayout().measuredDimensions[dim[mainAxis]],
YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth)))); YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth))));
} }
child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount); child->setLayoutComputedFlexBasisGeneration(node->getRoot()->gCurrentGenerationCount);
} }
static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, static void YGNodeAbsoluteLayoutChild(const YGNodeRef node,
@@ -1826,7 +1825,7 @@ static void YGNodeComputeFlexBasisForChildren(
continue; continue;
} }
if (child == singleFlexChild) { if (child == singleFlexChild) {
child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount); child->setLayoutComputedFlexBasisGeneration(node->getRoot()->gCurrentGenerationCount);
child->setLayoutComputedFlexBasis(YGFloatOptional(0)); child->setLayoutComputedFlexBasis(YGFloatOptional(0));
} else { } else {
YGNodeComputeFlexBasisForChild( YGNodeComputeFlexBasisForChild(
@@ -3343,7 +3342,6 @@ static void YGNodelayoutImpl(const YGNodeRef node,
} }
} }
uint32_t gDepth = 0;
bool gPrintTree = false; bool gPrintTree = false;
bool gPrintChanges = false; bool gPrintChanges = false;
bool gPrintSkips = false; bool gPrintSkips = false;
@@ -3514,10 +3512,10 @@ bool YGLayoutNodeInternal(const YGNodeRef node,
const YGConfigRef config) { const YGConfigRef config) {
YGLayout* layout = &node->getLayout(); YGLayout* layout = &node->getLayout();
gDepth++; node->getRoot()->gDepth++;
const bool needToVisitNode = const bool needToVisitNode =
(node->isDirty() && layout->generationCount != gCurrentGenerationCount) || (node->isDirty() && layout->generationCount != node->getRoot()->gCurrentGenerationCount) ||
layout->lastOwnerDirection != ownerDirection; layout->lastOwnerDirection != ownerDirection;
if (needToVisitNode) { if (needToVisitNode) {
@@ -3609,7 +3607,7 @@ bool YGLayoutNodeInternal(const YGNodeRef node,
layout->measuredDimensions[YGDimensionHeight] = cachedResults->computedHeight; layout->measuredDimensions[YGDimensionHeight] = cachedResults->computedHeight;
if (gPrintChanges && gPrintSkips) { if (gPrintChanges && gPrintSkips) {
YGLog(node, YGLogLevelVerbose, "%s%d.{[skipped] ", YGSpacer(gDepth), gDepth); YGLog(node, YGLogLevelVerbose, "%s%d.{[skipped] ", YGSpacer(node->getRoot()->gDepth), node->getRoot()->gDepth);
if (node->getPrintFunc() != nullptr) { if (node->getPrintFunc() != nullptr) {
node->getPrintFunc()(node); node->getPrintFunc()(node);
} }
@@ -3631,8 +3629,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node,
node, node,
YGLogLevelVerbose, YGLogLevelVerbose,
"%s%d.{%s", "%s%d.{%s",
YGSpacer(gDepth), YGSpacer(node->getRoot()->gDepth),
gDepth, node->getRoot()->gDepth,
needToVisitNode ? "*" : ""); needToVisitNode ? "*" : "");
if (node->getPrintFunc() != nullptr) { if (node->getPrintFunc() != nullptr) {
node->getPrintFunc()(node); node->getPrintFunc()(node);
@@ -3664,8 +3662,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node,
node, node,
YGLogLevelVerbose, YGLogLevelVerbose,
"%s%d.}%s", "%s%d.}%s",
YGSpacer(gDepth), YGSpacer(node->getRoot()->gDepth),
gDepth, node->getRoot()->gDepth,
needToVisitNode ? "*" : ""); needToVisitNode ? "*" : "");
if (node->getPrintFunc() != nullptr) { if (node->getPrintFunc() != nullptr) {
node->getPrintFunc()(node); node->getPrintFunc()(node);
@@ -3722,8 +3720,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node,
node->setDirty(false); node->setDirty(false);
} }
gDepth--; node->getRoot()->gDepth--;
layout->generationCount = gCurrentGenerationCount; layout->generationCount = node->getRoot()->gCurrentGenerationCount;
return (needToVisitNode || cachedResults == nullptr); return (needToVisitNode || cachedResults == nullptr);
} }
@@ -3819,7 +3817,7 @@ void YGNodeCalculateLayout(
// all dirty nodes at least once. Subsequent visits will be skipped if the // all dirty nodes at least once. Subsequent visits will be skipped if the
// input // input
// parameters don't change. // parameters don't change.
gCurrentGenerationCount++; node->getRoot()->gCurrentGenerationCount++;
node->resolveDimension(); node->resolveDimension();
float width = YGUndefined; float width = YGUndefined;
YGMeasureMode widthMeasureMode = YGMeasureModeUndefined; YGMeasureMode widthMeasureMode = YGMeasureModeUndefined;
@@ -3899,7 +3897,7 @@ void YGNodeCalculateLayout(
originalNode->resolveDimension(); originalNode->resolveDimension();
// Recursively mark nodes as dirty // Recursively mark nodes as dirty
originalNode->markDirtyAndPropogateDownwards(); originalNode->markDirtyAndPropogateDownwards();
gCurrentGenerationCount++; node->getRoot()->gCurrentGenerationCount++;
// Rerun the layout, and calculate the diff // Rerun the layout, and calculate the diff
originalNode->setAndPropogateUseLegacyFlag(false); originalNode->setAndPropogateUseLegacyFlag(false);
if (YGLayoutNodeInternal( if (YGLayoutNodeInternal(