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)
}
@available(iOS 13.0, *)
func processAnimationFolderParallel(basePath: String, path: String, stopOnFailure: Bool, process: @escaping (String, String, Bool) async -> Bool) async -> Bool {
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 {

View File

@ -79,7 +79,7 @@ private final class ReferenceCompareTest {
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 continueFromNameValue == name {
continueFromName = nil

View File

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

View File

@ -101,6 +101,34 @@ public:
}
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()) {
return nullptr;
}
@ -121,7 +149,17 @@ public:
}
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->position(),
_contentsLayer->transform(),
@ -132,7 +170,7 @@ public:
renderTreeValue,
nullptr,
false
));
));*/
assert(opacity() == 1.0);
assert(!isHidden());
@ -140,18 +178,17 @@ public:
assert(transform().isIdentity());
assert(position() == Vector2D::Zero());
return std::make_shared<RenderTreeNode>(
bounds(),
position(),
transform(),
opacity(),
masksToBounds(),
isHidden(),
nullptr,
subnodes,
maskNode,
invertMask
);
_renderTreeNode->_bounds = bounds();
_renderTreeNode->_position = position();
_renderTreeNode->_transform = transform();
_renderTreeNode->_alpha = opacity();
_renderTreeNode->_masksToBounds = masksToBounds();
_renderTreeNode->_isHidden = isHidden();
_renderTreeNode->_subnodes = subnodes;
_renderTreeNode->_mask = maskNode;
_renderTreeNode->_invertMask = invertMask;
return _renderTreeNode;
}
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:
double _frameRate = 0.0;
std::shared_ptr<NodeProperty<Vector1D>> _remappingNode;
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) {
_frameTime = frame;
_frameTimeInitialized = true;
_contentTree->itemTree->renderChildren(_frameTime, std::nullopt);
}
std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() {
if (_contentsLayer->isHidden()) {
return nullptr;
if (!_frameTimeInitialized) {
_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;
bool invertMask = false;
@ -1304,45 +1334,39 @@ std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() {
}
}
std::vector<std::shared_ptr<RenderTreeNode>> renderTreeValue;
renderTreeValue.push_back(_contentTree->itemTree->renderTree());
_contentsTreeNode->_bounds = _contentsLayer->bounds();
_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;
subnodes.push_back(std::make_shared<RenderTreeNode>(
_contentsLayer->bounds(),
_contentsLayer->position(),
_contentsLayer->transform(),
_contentsLayer->opacity(),
_contentsLayer->masksToBounds(),
_contentsLayer->isHidden(),
nullptr,
renderTreeValue,
nullptr,
false
));
subnodes.push_back(_contentsTreeNode);
assert(position() == Vector2D::Zero());
assert(transform().isIdentity());
assert(opacity() == 1.0);
assert(!masksToBounds());
assert(!isHidden());
assert(_contentsLayer->bounds() == CGRect(0.0, 0.0, 0.0, 0.0));
assert(_contentsLayer->position() == Vector2D::Zero());
assert(!_contentsLayer->masksToBounds());
return std::make_shared<RenderTreeNode>(
bounds(),
position(),
transform(),
opacity(),
masksToBounds(),
isHidden(),
nullptr,
subnodes,
maskNode,
invertMask
);
_renderTreeNode->_bounds = bounds();
_renderTreeNode->_position = position();
_renderTreeNode->_transform = transform();
_renderTreeNode->_alpha = opacity();
_renderTreeNode->_masksToBounds = masksToBounds();
_renderTreeNode->_isHidden = isHidden();
_renderTreeNode->_subnodes = subnodes;
_renderTreeNode->_mask = maskNode;
_renderTreeNode->_invertMask = invertMask;
return _renderTreeNode;
}
void ShapeCompositionLayer::updateRenderTree() {
}
}

View File

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

View File

@ -23,12 +23,6 @@ public:
_textProvider = textProvider;
_fontProvider = fontProvider;
//_contentsLayer->addSublayer(_textLayer);
assert(false);
//self.textLayer.masksToBounds = false
//self.textLayer.isGeometryFlipped = true
if (_rootNode) {
_childKeypaths.push_back(rootNode);
}
@ -67,42 +61,6 @@ public:
if (_rootNode) {
_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:
@ -114,7 +72,6 @@ private:
std::shared_ptr<TextAnimatorNode> _rootNode;
std::shared_ptr<KeyframeInterpolator<TextDocument>> _textDocument;
//std::shared_ptr<CoreTextRenderLayer> _textLayer;
std::shared_ptr<AnimationTextProvider> _textProvider;
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:
// MARK: Internal