Animation rendering updates

This commit is contained in:
Ali 2022-02-11 23:49:58 +04:00
parent c8bc4b7f12
commit 05a0d399dd
6 changed files with 228 additions and 217 deletions

View file

@ -172,7 +172,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
private var cachedData: (Data, Bool, EmojiFitzModifier?)?
private let useMetalCache: Bool
private var renderer: (AnimationRenderer & ASDisplayNode)?
private var renderer: AnimationRendererPool.Holder?
public var isPlaying: Bool = false
private var currentLoopCount: Int = 0
@ -232,30 +232,42 @@ public final class AnimatedStickerNode: ASDisplayNode {
self.timer.swap(nil)?.invalidate()
}
private static let hardwareRendererPool = AnimationRendererPool(generate: {
if #available(iOS 10.0, *) {
return CompressedAnimationRenderer()
} else {
return SoftwareAnimationRenderer()
}
})
private static let softwareRendererPool = AnimationRendererPool(generate: {
return SoftwareAnimationRenderer()
})
private weak var nodeToCopyFrameFrom: AnimatedStickerNode?
override public func didLoad() {
super.didLoad()
if #available(iOS 10.0, *), self.useMetalCache {
self.renderer = CompressedAnimationRenderer()
self.renderer = AnimatedStickerNode.hardwareRendererPool.take()
} else {
self.renderer = SoftwareAnimationRenderer()
self.renderer = AnimatedStickerNode.softwareRendererPool.take()
if let contents = self.nodeToCopyFrameFrom?.renderer?.renderer.contents {
self.renderer?.renderer.contents = contents
}
}
self.renderer?.frame = CGRect(origin: CGPoint(), size: self.size ?? self.bounds.size)
if let contents = self.nodeToCopyFrameFrom?.renderer?.contents {
self.renderer?.contents = contents
}
self.renderer?.renderer.frame = CGRect(origin: CGPoint(), size: self.size ?? self.bounds.size)
if let (overlayColor, replace) = self.overlayColor {
self.renderer?.setOverlayColor(overlayColor, replace: replace, animated: false)
self.renderer?.renderer.setOverlayColor(overlayColor, replace: replace, animated: false)
}
self.nodeToCopyFrameFrom = nil
self.addSubnode(self.renderer!)
self.addSubnode(self.renderer!.renderer)
}
public func cloneCurrentFrame(from otherNode: AnimatedStickerNode?) {
if let renderer = self.renderer {
if let contents = otherNode?.renderer?.contents {
if let renderer = self.renderer?.renderer as? SoftwareAnimationRenderer, let otherRenderer = otherNode?.renderer?.renderer as? SoftwareAnimationRenderer {
if let contents = otherRenderer.contents {
renderer.contents = contents
}
} else {
@ -428,7 +440,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
return
}
strongSelf.renderer?.render(queue: strongSelf.queue, width: frame.width, height: frame.height, bytesPerRow: frame.bytesPerRow, data: frame.data, type: frame.type, mulAlpha: frame.multiplyAlpha, completion: {
strongSelf.renderer?.renderer.render(queue: strongSelf.queue, width: frame.width, height: frame.height, bytesPerRow: frame.bytesPerRow, data: frame.data, type: frame.type, mulAlpha: frame.multiplyAlpha, completion: {
guard let strongSelf = self else {
return
}
@ -532,7 +544,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
return
}
strongSelf.renderer?.render(queue: strongSelf.queue, width: frame.width, height: frame.height, bytesPerRow: frame.bytesPerRow, data: frame.data, type: frame.type, mulAlpha: frame.multiplyAlpha, completion: {
strongSelf.renderer?.renderer.render(queue: strongSelf.queue, width: frame.width, height: frame.height, bytesPerRow: frame.bytesPerRow, data: frame.data, type: frame.type, mulAlpha: frame.multiplyAlpha, completion: {
guard let strongSelf = self else {
return
}
@ -685,7 +697,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
return
}
strongSelf.renderer?.render(queue: strongSelf.queue, width: frame.width, height: frame.height, bytesPerRow: frame.bytesPerRow, data: frame.data, type: frame.type, mulAlpha: frame.multiplyAlpha, completion: {
strongSelf.renderer?.renderer.render(queue: strongSelf.queue, width: frame.width, height: frame.height, bytesPerRow: frame.bytesPerRow, data: frame.data, type: frame.type, mulAlpha: frame.multiplyAlpha, completion: {
guard let strongSelf = self else {
return
}
@ -715,11 +727,11 @@ public final class AnimatedStickerNode: ASDisplayNode {
public func updateLayout(size: CGSize) {
self.size = size
self.renderer?.frame = CGRect(origin: CGPoint(), size: size)
self.renderer?.renderer.frame = CGRect(origin: CGPoint(), size: size)
}
public func setOverlayColor(_ color: UIColor?, replace: Bool, animated: Bool) {
self.overlayColor = (color, replace)
self.renderer?.setOverlayColor(color, replace: replace, animated: animated)
self.renderer?.renderer.setOverlayColor(color, replace: replace, animated: animated)
}
}

View file

@ -8,7 +8,47 @@ public enum AnimationRendererFrameType {
case dct
}
protocol AnimationRenderer {
final class AnimationRendererPool {
final class Holder {
let pool: AnimationRendererPool
let renderer: AnimationRenderer
init(pool: AnimationRendererPool, renderer: AnimationRenderer) {
self.pool = pool
self.renderer = renderer
}
deinit {
self.renderer.removeFromSupernode()
self.pool.putBack(renderer: self.renderer)
}
}
private let generate: () -> AnimationRenderer
private var items: [AnimationRenderer] = []
init(generate: @escaping () -> AnimationRenderer) {
self.generate = generate
}
func take() -> Holder {
if !self.items.isEmpty {
let item = self.items.removeLast()
return Holder(pool: self, renderer: item)
} else {
return Holder(pool: self, renderer: self.generate())
}
}
private func putBack(renderer: AnimationRenderer) {
#if DEBUG
self.items.append(renderer)
#endif
}
}
protocol AnimationRenderer: ASDisplayNode {
func render(queue: Queue, width: Int, height: Int, bytesPerRow: Int, data: Data, type: AnimationRendererFrameType, mulAlpha: Bool, completion: @escaping () -> Void)
func setOverlayColor(_ color: UIColor?, replace: Bool, animated: Bool)

View file

@ -88,66 +88,6 @@ final class CompressedAnimationRenderer: ASDisplayNode, AnimationRenderer {
case .yuva:
self.renderer.renderYuva(metalLayer: self.layer, width: width, height: height, data: data, completion: completion)
}
/*assert(bytesPerRow > 0)
queue.async { [weak self] in
switch type {
case .dct:
break
default:
return
}
var image: UIImage?
autoreleasepool {
image = generateImagePixel(CGSize(width: CGFloat(width), height: CGFloat(height)), scale: 1.0, pixelGenerator: { _, pixelData, contextBytesPerRow in
switch type {
case .yuva:
data.withUnsafeBytes { bytes -> Void in
guard let baseAddress = bytes.baseAddress else {
return
}
if bytesPerRow <= 0 || height <= 0 || width <= 0 || bytesPerRow * height > bytes.count {
assert(false)
return
}
decodeYUVAToRGBA(baseAddress.assumingMemoryBound(to: UInt8.self), pixelData, Int32(width), Int32(height), Int32(contextBytesPerRow))
}
case .argb:
var data = data
data.withUnsafeMutableBytes { bytes -> Void in
guard let baseAddress = bytes.baseAddress else {
return
}
if mulAlpha {
var srcData = vImage_Buffer(data: baseAddress.assumingMemoryBound(to: UInt8.self), height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow)
var destData = vImage_Buffer(data: pixelData, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow)
let permuteMap: [UInt8] = [3, 2, 1, 0]
vImagePermuteChannels_ARGB8888(&srcData, &destData, permuteMap, vImage_Flags(kvImageDoNotTile))
vImagePremultiplyData_ARGB8888(&destData, &destData, vImage_Flags(kvImageDoNotTile))
vImagePermuteChannels_ARGB8888(&destData, &destData, permuteMap, vImage_Flags(kvImageDoNotTile))
} else {
memcpy(pixelData, baseAddress.assumingMemoryBound(to: UInt8.self), bytes.count)
}
}
}
})
}
Queue.mainQueue().async {
guard let strongSelf = self else {
return
}
strongSelf.contents = image?.cgImage
strongSelf.updateHighlightedContentNode()
if strongSelf.highlightedContentNode?.frame != strongSelf.bounds {
strongSelf.highlightedContentNode?.frame = strongSelf.bounds
}
completion()
}
}*/
}
private func updateHighlightedContentNode() {