Lottie: optimization

This commit is contained in:
Isaac 2024-05-09 00:22:07 +04:00
parent 9fcef12d55
commit 58a1caf9df
8 changed files with 159 additions and 95 deletions

View File

@ -256,9 +256,10 @@ func processAnimationFolderAsync(basePath: String, path: String, stopOnFailure:
return await processAnimationFolderItems(items: items, countPerBucket: 1, stopOnFailure: stopOnFailure, process: process) return await processAnimationFolderItems(items: items, countPerBucket: 1, stopOnFailure: stopOnFailure, process: process)
} }
@available(iOS 13.0, *)
func processAnimationFolderParallel(basePath: String, path: String, stopOnFailure: Bool, process: @escaping (String, String, Bool) async -> Bool) async -> Bool { func processAnimationFolderParallel(basePath: String, path: String, stopOnFailure: Bool, process: @escaping (String, String, Bool) async -> Bool) async -> Bool {
let items = buildAnimationFolderItems(basePath: basePath, path: path) let items = buildAnimationFolderItems(basePath: basePath, path: path)
return await processAnimationFolderItems(items: items, countPerBucket: 16, stopOnFailure: stopOnFailure, process: process) return await processAnimationFolderItemsParallel(items: items, stopOnFailure: stopOnFailure, process: process)
} }
func cacheReferenceFolderPath(baseCachePath: String, width: Int, name: String) -> String { func cacheReferenceFolderPath(baseCachePath: String, width: Int, name: String) -> String {

View File

@ -79,7 +79,7 @@ private final class ReferenceCompareTest {
var continueFromName: String? = "5138957708585599529.json" var continueFromName: String? = "5138957708585599529.json"
let _ = await processAnimationFolderParallel(basePath: bundlePath, path: "", stopOnFailure: true, process: { path, name, alwaysDraw in let _ = await processAnimationFolderAsync(basePath: bundlePath, path: "", stopOnFailure: true, process: { path, name, alwaysDraw in
if let continueFromNameValue = continueFromName { if let continueFromNameValue = continueFromName {
if continueFromNameValue == name { if continueFromNameValue == name {
continueFromName = nil continueFromName = nil

View File

@ -89,7 +89,13 @@ public:
void displayWithFrame(double frame, bool forceUpdates) { void displayWithFrame(double frame, bool forceUpdates) {
_transformNode->updateTree(frame, forceUpdates); _transformNode->updateTree(frame, forceUpdates);
bool layerVisible = isInRangeOrEqual(frame, _inFrame, _outFrame); bool layerVisible = isInRangeOrEqual(frame, _inFrame, _outFrame);
_contentsLayer->setTransform(_transformNode->globalTransform());
_contentsLayer->setOpacity(_transformNode->opacity());
_contentsLayer->setIsHidden(!layerVisible);
/// Only update contents if current time is within the layers time bounds. /// Only update contents if current time is within the layers time bounds.
if (layerVisible) { if (layerVisible) {
displayContentsWithFrame(frame, forceUpdates); displayContentsWithFrame(frame, forceUpdates);
@ -97,9 +103,6 @@ public:
_maskLayer->updateWithFrame(frame, forceUpdates); _maskLayer->updateWithFrame(frame, forceUpdates);
} }
} }
_contentsLayer->setTransform(_transformNode->globalTransform());
_contentsLayer->setOpacity(_transformNode->opacity());
_contentsLayer->setIsHidden(!layerVisible);
if (const auto delegate = _layerDelegate.lock()) { if (const auto delegate = _layerDelegate.lock()) {
delegate->frameUpdated(frame); delegate->frameUpdated(frame);
@ -168,6 +171,9 @@ public:
return nullptr; return nullptr;
} }
virtual void updateRenderTree() {
}
public: public:
std::shared_ptr<LayerTransformNode> const transformNode() const { std::shared_ptr<LayerTransformNode> const transformNode() const {
return _transformNode; return _transformNode;
@ -193,8 +199,6 @@ private:
std::string _keypathName; std::string _keypathName;
//std::shared_ptr<RenderTreeNode> _renderTree;
public: public:
virtual bool isImageCompositionLayer() const { virtual bool isImageCompositionLayer() const {
return false; return false;

View File

@ -101,6 +101,34 @@ public:
} }
virtual std::shared_ptr<RenderTreeNode> renderTreeNode() override { virtual std::shared_ptr<RenderTreeNode> renderTreeNode() override {
if (!_renderTreeNode) {
_renderTreeNode = std::make_shared<RenderTreeNode>(
CGRect(0.0, 0.0, 0.0, 0.0),
Vector2D(0.0, 0.0),
CATransform3D::identity(),
1.0,
false,
false,
nullptr,
std::vector<std::shared_ptr<RenderTreeNode>>(),
nullptr,
false
);
_contentsTreeNode = std::make_shared<RenderTreeNode>(
CGRect(0.0, 0.0, 0.0, 0.0),
Vector2D(0.0, 0.0),
CATransform3D::identity(),
1.0,
false,
false,
nullptr,
std::vector<std::shared_ptr<RenderTreeNode>>(),
nullptr,
false
);
}
if (_contentsLayer->isHidden()) { if (_contentsLayer->isHidden()) {
return nullptr; return nullptr;
} }
@ -121,7 +149,17 @@ public:
} }
std::vector<std::shared_ptr<RenderTreeNode>> subnodes; std::vector<std::shared_ptr<RenderTreeNode>> subnodes;
subnodes.push_back(std::make_shared<RenderTreeNode>(
_contentsTreeNode->_bounds = _contentsLayer->bounds();
_contentsTreeNode->_position = _contentsLayer->position();
_contentsTreeNode->_transform = _contentsLayer->transform();
_contentsTreeNode->_alpha = _contentsLayer->opacity();
_contentsTreeNode->_masksToBounds = _contentsLayer->masksToBounds();
_contentsTreeNode->_isHidden = _contentsLayer->isHidden();
_contentsTreeNode->_subnodes = renderTreeValue;
subnodes.push_back(_contentsTreeNode);
/*subnodes.push_back(std::make_shared<RenderTreeNode>(
_contentsLayer->bounds(), _contentsLayer->bounds(),
_contentsLayer->position(), _contentsLayer->position(),
_contentsLayer->transform(), _contentsLayer->transform(),
@ -132,7 +170,7 @@ public:
renderTreeValue, renderTreeValue,
nullptr, nullptr,
false false
)); ));*/
assert(opacity() == 1.0); assert(opacity() == 1.0);
assert(!isHidden()); assert(!isHidden());
@ -140,18 +178,17 @@ public:
assert(transform().isIdentity()); assert(transform().isIdentity());
assert(position() == Vector2D::Zero()); assert(position() == Vector2D::Zero());
return std::make_shared<RenderTreeNode>( _renderTreeNode->_bounds = bounds();
bounds(), _renderTreeNode->_position = position();
position(), _renderTreeNode->_transform = transform();
transform(), _renderTreeNode->_alpha = opacity();
opacity(), _renderTreeNode->_masksToBounds = masksToBounds();
masksToBounds(), _renderTreeNode->_isHidden = isHidden();
isHidden(), _renderTreeNode->_subnodes = subnodes;
nullptr, _renderTreeNode->_mask = maskNode;
subnodes, _renderTreeNode->_invertMask = invertMask;
maskNode,
invertMask return _renderTreeNode;
);
} }
std::shared_ptr<RenderTreeNode> renderTree() { std::shared_ptr<RenderTreeNode> renderTree() {
@ -188,11 +225,33 @@ public:
); );
} }
virtual void updateRenderTree() override {
if (_matteLayer) {
_matteLayer->updateRenderTree();
}
for (const auto &animationLayer : _animationLayers) {
bool found = false;
for (const auto &sublayer : contentsLayer()->sublayers()) {
if (animationLayer == sublayer) {
found = true;
break;
}
}
if (found) {
animationLayer->updateRenderTree();
}
}
}
private: private:
double _frameRate = 0.0; double _frameRate = 0.0;
std::shared_ptr<NodeProperty<Vector1D>> _remappingNode; std::shared_ptr<NodeProperty<Vector1D>> _remappingNode;
std::vector<std::shared_ptr<CompositionLayer>> _animationLayers; std::vector<std::shared_ptr<CompositionLayer>> _animationLayers;
std::shared_ptr<RenderTreeNode> _renderTreeNode;
std::shared_ptr<RenderTreeNode> _contentsTreeNode;
}; };
} }

View File

@ -1284,16 +1284,46 @@ CompositionLayer(solidLayer, Vector2D::Zero()) {
void ShapeCompositionLayer::displayContentsWithFrame(double frame, bool forceUpdates) { void ShapeCompositionLayer::displayContentsWithFrame(double frame, bool forceUpdates) {
_frameTime = frame; _frameTime = frame;
_frameTimeInitialized = true; _frameTimeInitialized = true;
_contentTree->itemTree->renderChildren(_frameTime, std::nullopt); _contentTree->itemTree->renderChildren(_frameTime, std::nullopt);
} }
std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() { std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() {
if (_contentsLayer->isHidden()) { if (!_frameTimeInitialized) {
return nullptr; _frameTime = 0.0;
_frameTimeInitialized = true;
_contentTree->itemTree->renderChildren(_frameTime, std::nullopt);
} }
assert(_frameTimeInitialized); if (!_renderTreeNode) {
_renderTreeNode = std::make_shared<RenderTreeNode>(
CGRect(0.0, 0.0, 0.0, 0.0),
Vector2D(0.0, 0.0),
CATransform3D::identity(),
1.0,
false,
false,
nullptr,
std::vector<std::shared_ptr<RenderTreeNode>>(),
nullptr,
false
);
std::vector<std::shared_ptr<RenderTreeNode>> renderTreeValue;
renderTreeValue.push_back(_contentTree->itemTree->renderTree());
_contentsTreeNode = std::make_shared<RenderTreeNode>(
CGRect(0.0, 0.0, 0.0, 0.0),
Vector2D(0.0, 0.0),
CATransform3D::identity(),
1.0,
false,
false,
nullptr,
renderTreeValue,
nullptr,
false
);
}
std::shared_ptr<RenderTreeNode> maskNode; std::shared_ptr<RenderTreeNode> maskNode;
bool invertMask = false; bool invertMask = false;
@ -1304,45 +1334,39 @@ std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() {
} }
} }
std::vector<std::shared_ptr<RenderTreeNode>> renderTreeValue; _contentsTreeNode->_bounds = _contentsLayer->bounds();
renderTreeValue.push_back(_contentTree->itemTree->renderTree()); _contentsTreeNode->_position = _contentsLayer->position();
_contentsTreeNode->_transform = _contentsLayer->transform();
_contentsTreeNode->_alpha = _contentsLayer->opacity();
_contentsTreeNode->_masksToBounds = _contentsLayer->masksToBounds();
_contentsTreeNode->_isHidden = _contentsLayer->isHidden();
std::vector<std::shared_ptr<RenderTreeNode>> subnodes; std::vector<std::shared_ptr<RenderTreeNode>> subnodes;
subnodes.push_back(std::make_shared<RenderTreeNode>( subnodes.push_back(_contentsTreeNode);
_contentsLayer->bounds(),
_contentsLayer->position(),
_contentsLayer->transform(),
_contentsLayer->opacity(),
_contentsLayer->masksToBounds(),
_contentsLayer->isHidden(),
nullptr,
renderTreeValue,
nullptr,
false
));
assert(position() == Vector2D::Zero()); assert(position() == Vector2D::Zero());
assert(transform().isIdentity()); assert(transform().isIdentity());
assert(opacity() == 1.0); assert(opacity() == 1.0);
assert(!masksToBounds()); assert(!masksToBounds());
assert(!isHidden()); assert(!isHidden());
assert(_contentsLayer->bounds() == CGRect(0.0, 0.0, 0.0, 0.0)); assert(_contentsLayer->bounds() == CGRect(0.0, 0.0, 0.0, 0.0));
assert(_contentsLayer->position() == Vector2D::Zero()); assert(_contentsLayer->position() == Vector2D::Zero());
assert(!_contentsLayer->masksToBounds()); assert(!_contentsLayer->masksToBounds());
return std::make_shared<RenderTreeNode>( _renderTreeNode->_bounds = bounds();
bounds(), _renderTreeNode->_position = position();
position(), _renderTreeNode->_transform = transform();
transform(), _renderTreeNode->_alpha = opacity();
opacity(), _renderTreeNode->_masksToBounds = masksToBounds();
masksToBounds(), _renderTreeNode->_isHidden = isHidden();
isHidden(), _renderTreeNode->_subnodes = subnodes;
nullptr, _renderTreeNode->_mask = maskNode;
subnodes, _renderTreeNode->_invertMask = invertMask;
maskNode,
invertMask return _renderTreeNode;
); }
void ShapeCompositionLayer::updateRenderTree() {
} }
} }

View File

@ -18,12 +18,16 @@ public:
virtual void displayContentsWithFrame(double frame, bool forceUpdates) override; virtual void displayContentsWithFrame(double frame, bool forceUpdates) override;
virtual std::shared_ptr<RenderTreeNode> renderTreeNode() override; virtual std::shared_ptr<RenderTreeNode> renderTreeNode() override;
virtual void updateRenderTree() override;
private: private:
std::shared_ptr<ShapeLayerPresentationTree> _contentTree; std::shared_ptr<ShapeLayerPresentationTree> _contentTree;
AnimationFrameTime _frameTime = 0.0; AnimationFrameTime _frameTime = 0.0;
bool _frameTimeInitialized = false; bool _frameTimeInitialized = false;
std::shared_ptr<RenderTreeNode> _renderTreeNode;
std::shared_ptr<RenderTreeNode> _contentsTreeNode;
}; };
} }

View File

@ -23,12 +23,6 @@ public:
_textProvider = textProvider; _textProvider = textProvider;
_fontProvider = fontProvider; _fontProvider = fontProvider;
//_contentsLayer->addSublayer(_textLayer);
assert(false);
//self.textLayer.masksToBounds = false
//self.textLayer.isGeometryFlipped = true
if (_rootNode) { if (_rootNode) {
_childKeypaths.push_back(rootNode); _childKeypaths.push_back(rootNode);
} }
@ -67,42 +61,6 @@ public:
if (_rootNode) { if (_rootNode) {
_rootNode->rebuildOutputs(frame); _rootNode->rebuildOutputs(frame);
} }
assert(false);
/*// Get Text Attributes
let text = textDocument.value(frame: frame) as! TextDocument
let strokeColor = rootNode?.textOutputNode.strokeColor ?? text.strokeColorData?.cgColorValue
let strokeWidth = rootNode?.textOutputNode.strokeWidth ?? CGFloat(text.strokeWidth ?? 0)
let tracking = (CGFloat(text.fontSize) * (rootNode?.textOutputNode.tracking ?? CGFloat(text.tracking))) / 1000.0
let matrix = rootNode?.textOutputNode.xform ?? CATransform3DIdentity
let textString = textProvider.textFor(keypathName: keypathName, sourceText: text.text)
let ctFont = fontProvider.fontFor(family: text.fontFamily, size: CGFloat(text.fontSize))
// Set all of the text layer options
textLayer.text = textString
textLayer.font = ctFont
textLayer.alignment = text.justification.textAlignment
textLayer.lineHeight = CGFloat(text.lineHeight)
textLayer.tracking = tracking
if let fillColor = rootNode?.textOutputNode.fillColor {
textLayer.fillColor = fillColor
} else if let fillColor = text.fillColorData?.cgColorValue {
textLayer.fillColor = fillColor
} else {
textLayer.fillColor = nil
}
textLayer.preferredSize = text.textFrameSize?.sizeValue
textLayer.strokeOnTop = text.strokeOverFill ?? false
textLayer.strokeWidth = strokeWidth
textLayer.strokeColor = strokeColor
textLayer.sizeToFit()
textLayer.opacity = Float(rootNode?.textOutputNode.opacity ?? 1)
textLayer.transform = CATransform3DIdentity
textLayer.position = text.textFramePosition?.pointValue ?? CGPoint.zero
textLayer.transform = matrix*/
} }
public: public:
@ -114,7 +72,6 @@ private:
std::shared_ptr<TextAnimatorNode> _rootNode; std::shared_ptr<TextAnimatorNode> _rootNode;
std::shared_ptr<KeyframeInterpolator<TextDocument>> _textDocument; std::shared_ptr<KeyframeInterpolator<TextDocument>> _textDocument;
//std::shared_ptr<CoreTextRenderLayer> _textLayer;
std::shared_ptr<AnimationTextProvider> _textProvider; std::shared_ptr<AnimationTextProvider> _textProvider;
std::shared_ptr<AnimationFontProvider> _fontProvider; std::shared_ptr<AnimationFontProvider> _fontProvider;
}; };

View File

@ -250,6 +250,21 @@ public:
); );
} }
virtual void updateRenderTree() {
for (const auto &animationLayer : _animationLayers) {
bool found = false;
for (const auto &sublayer : sublayers()) {
if (animationLayer == sublayer) {
found = true;
break;
}
}
if (found) {
animationLayer->updateRenderTree();
}
}
}
private: private:
// MARK: Internal // MARK: Internal