diff --git a/submodules/TelegramUI/Components/AnimationCache/Sources/AnimationCache.swift b/submodules/TelegramUI/Components/AnimationCache/Sources/AnimationCache.swift index f92e1ef1f4..96920e9871 100644 --- a/submodules/TelegramUI/Components/AnimationCache/Sources/AnimationCache.swift +++ b/submodules/TelegramUI/Components/AnimationCache/Sources/AnimationCache.swift @@ -6,18 +6,34 @@ import ManagedFile import Compression public final class AnimationCacheItemFrame { - public enum Format { - case rgba(width: Int, height: Int, bytesPerRow: Int) + public enum RequestedFormat { + case rgba + case yuva + } + + public final class Plane { + public let data: Data + public let width: Int + public let height: Int + public let bytesPerRow: Int + + public init(data: Data, width: Int, height: Int, bytesPerRow: Int) { + self.data = data + self.width = width + self.height = height + self.bytesPerRow = bytesPerRow + } + } + + public enum Format { + case rgba(data: Data, width: Int, height: Int, bytesPerRow: Int) + case yuva(y: Plane, u: Plane, v: Plane, a: Plane) } - public let data: Data - public let range: Range public let format: Format public let duration: Double - public init(data: Data, range: Range, format: Format, duration: Double) { - self.data = data - self.range = range + public init(format: Format, duration: Double) { self.format = format self.duration = duration } @@ -25,22 +41,22 @@ public final class AnimationCacheItemFrame { public final class AnimationCacheItem { public let numFrames: Int - private let getFrameImpl: (Int) -> AnimationCacheItemFrame? + private let getFrameImpl: (Int, AnimationCacheItemFrame.RequestedFormat) -> AnimationCacheItemFrame? private let getFrameIndexImpl: (Double) -> Int - public init(numFrames: Int, getFrame: @escaping (Int) -> AnimationCacheItemFrame?, getFrameIndexImpl: @escaping (Double) -> Int) { + public init(numFrames: Int, getFrame: @escaping (Int, AnimationCacheItemFrame.RequestedFormat) -> AnimationCacheItemFrame?, getFrameIndexImpl: @escaping (Double) -> Int) { self.numFrames = numFrames self.getFrameImpl = getFrame self.getFrameIndexImpl = getFrameIndexImpl } - public func getFrame(index: Int) -> AnimationCacheItemFrame? { - return self.getFrameImpl(index) + public func getFrame(index: Int, requestedFormat: AnimationCacheItemFrame.RequestedFormat) -> AnimationCacheItemFrame? { + return self.getFrameImpl(index, requestedFormat) } - public func getFrame(at duration: Double) -> AnimationCacheItemFrame? { + public func getFrame(at duration: Double, requestedFormat: AnimationCacheItemFrame.RequestedFormat) -> AnimationCacheItemFrame? { let index = self.getFrameIndexImpl(duration) - return self.getFrameImpl(index) + return self.getFrameImpl(index, requestedFormat) } } @@ -495,13 +511,11 @@ private final class AnimationCacheItemAccessor { self.currentDctCoefficients = DctCoefficientsYUVA420(width: width, height: height) } - func getFrame(index: Int) -> AnimationCacheItemFrame? { + func getFrame(index: Int, requestedFormat: AnimationCacheItemFrame.RequestedFormat) -> AnimationCacheItemFrame? { guard let frameInfo = self.frameMapping[index] else { return nil } - let currentSurface = ImageARGB(width: self.currentYUVASurface.yPlane.width, height: self.currentYUVASurface.yPlane.height) - var frameDataOffset = 0 let frameLength = frameInfo.range.upperBound - frameInfo.range.lowerBound for i in 0 ..< 4 { @@ -531,9 +545,47 @@ private final class AnimationCacheItemAccessor { } self.currentDctCoefficients.idct(dctData: self.currentDctData, target: self.currentYUVASurface) - self.currentYUVASurface.toARGB(target: currentSurface) - return AnimationCacheItemFrame(data: currentSurface.argbPlane.data, range: 0 ..< currentSurface.argbPlane.data.count, format: .rgba(width: currentSurface.argbPlane.width, height: currentSurface.argbPlane.height, bytesPerRow: currentSurface.argbPlane.bytesPerRow), duration: frameInfo.duration) + switch requestedFormat { + case .rgba: + let currentSurface = ImageARGB(width: self.currentYUVASurface.yPlane.width, height: self.currentYUVASurface.yPlane.height) + self.currentYUVASurface.toARGB(target: currentSurface) + + return AnimationCacheItemFrame(format: .rgba(data: currentSurface.argbPlane.data, width: currentSurface.argbPlane.width, height: currentSurface.argbPlane.height, bytesPerRow: currentSurface.argbPlane.bytesPerRow), duration: frameInfo.duration) + case .yuva: + let currentYUVASurface = self.currentYUVASurface + self.currentYUVASurface = ImageYUVA420(width: currentYUVASurface.yPlane.width, height: currentYUVASurface.yPlane.height) + + return AnimationCacheItemFrame( + format: .yuva( + y: AnimationCacheItemFrame.Plane( + data: currentYUVASurface.yPlane.data, + width: currentYUVASurface.yPlane.width, + height: currentYUVASurface.yPlane.height, + bytesPerRow: currentYUVASurface.yPlane.bytesPerRow + ), + u: AnimationCacheItemFrame.Plane( + data: currentYUVASurface.uPlane.data, + width: currentYUVASurface.uPlane.width, + height: currentYUVASurface.uPlane.height, + bytesPerRow: currentYUVASurface.uPlane.bytesPerRow + ), + v: AnimationCacheItemFrame.Plane( + data: currentYUVASurface.vPlane.data, + width: currentYUVASurface.vPlane.width, + height: currentYUVASurface.vPlane.height, + bytesPerRow: currentYUVASurface.vPlane.bytesPerRow + ), + a: AnimationCacheItemFrame.Plane( + data: currentYUVASurface.aPlane.data, + width: currentYUVASurface.aPlane.width, + height: currentYUVASurface.aPlane.height, + bytesPerRow: currentYUVASurface.aPlane.bytesPerRow + ) + ), + duration: frameInfo.duration + ) + } } func getFrameIndex(duration: Double) -> Int { @@ -675,8 +727,8 @@ private func loadItem(path: String) -> AnimationCacheItem? { let itemAccessor = AnimationCacheItemAccessor(data: data, frameMapping: frameMapping, width: Int(width), height: Int(height), dctQuality: Int(dctQuality)) - return AnimationCacheItem(numFrames: Int(numFrames), getFrame: { index in - return itemAccessor.getFrame(index: index) + return AnimationCacheItem(numFrames: Int(numFrames), getFrame: { index, requestedFormat in + return itemAccessor.getFrame(index: index, requestedFormat: requestedFormat) }, getFrameIndexImpl: { duration in return itemAccessor.getFrameIndex(duration: duration) }) diff --git a/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift b/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift index f0b417afcf..90f7314679 100644 --- a/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift +++ b/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift @@ -101,10 +101,11 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget { override public func action(forKey event: String) -> CAAction? { if event == kCAOnOrderIn { self.isInHierarchyValue = true + self.updatePlayback() } else if event == kCAOnOrderOut { self.isInHierarchyValue = false + self.updatePlayback() } - self.updatePlayback() return nullAction } diff --git a/submodules/TelegramUI/Components/MultiAnimationRenderer/Resources/MultiAnimationRendererShaders.metal b/submodules/TelegramUI/Components/MultiAnimationRenderer/Resources/MultiAnimationRendererShaders.metal index 35a1806d35..c8a7c8c2f7 100644 --- a/submodules/TelegramUI/Components/MultiAnimationRenderer/Resources/MultiAnimationRendererShaders.metal +++ b/submodules/TelegramUI/Components/MultiAnimationRenderer/Resources/MultiAnimationRendererShaders.metal @@ -31,7 +31,10 @@ vertex Varyings multiAnimationVertex( fragment half4 multiAnimationFragment( Varyings in[[stage_in]], - texture2d texture[[texture(0)]] + texture2d textureY[[texture(0)]], + texture2d textureU[[texture(1)]], + texture2d textureV[[texture(2)]], + texture2d textureA[[texture(3)]] ) { constexpr sampler s(address::clamp_to_edge, filter::linear); return half4(texture.sample(s, in.texCoord)); diff --git a/submodules/TelegramUI/Components/MultiAnimationRenderer/Sources/MultiAnimationMetalRenderer.swift b/submodules/TelegramUI/Components/MultiAnimationRenderer/Sources/MultiAnimationMetalRenderer.swift index 2a3646512d..0f9e39af6d 100644 --- a/submodules/TelegramUI/Components/MultiAnimationRenderer/Sources/MultiAnimationMetalRenderer.swift +++ b/submodules/TelegramUI/Components/MultiAnimationRenderer/Sources/MultiAnimationMetalRenderer.swift @@ -64,12 +64,14 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { private final class TextureStoragePool { let width: Int let height: Int + let format: TextureStorage.Content.Format private var items: [TextureStorage.Content] = [] - init(width: Int, height: Int) { + init(width: Int, height: Int, format: TextureStorage.Content.Format) { self.width = width self.height = height + self.format = format } func recycle(content: TextureStorage.Content) { @@ -82,7 +84,7 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { func take(device: MTLDevice) -> TextureStorage.Content? { if self.items.isEmpty { - guard let content = TextureStorage.Content(device: device, width: self.width, height: self.height) else { + guard let content = TextureStorage.Content(device: device, width: self.width, height: self.height, format: format) else { return nil } return content @@ -93,6 +95,11 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { private final class TextureStorage { final class Content { + enum Format { + case bgra + case r + } + let buffer: MTLBuffer? let width: Int @@ -100,9 +107,18 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { let bytesPerRow: Int let texture: MTLTexture - init?(device: MTLDevice, width: Int, height: Int) { - let bytesPerPixel = 4 - let pixelRowAlignment = device.minimumLinearTextureAlignment(for: .bgra8Unorm) + init?(device: MTLDevice, width: Int, height: Int, format: Format) { + let bytesPerPixel: Int + let pixelFormat: MTLPixelFormat + switch format { + case .bgra: + bytesPerPixel = 4 + pixelFormat = .bgra8Unorm + case .r: + bytesPerPixel = 1 + pixelFormat = .r8Unorm + } + let pixelRowAlignment = device.minimumLinearTextureAlignment(for: pixelFormat) let bytesPerRow = alignUp(size: width * bytesPerPixel, align: pixelRowAlignment) self.width = width @@ -112,7 +128,7 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { #if targetEnvironment(simulator) let textureDescriptor = MTLTextureDescriptor() textureDescriptor.textureType = .type2D - textureDescriptor.pixelFormat = .bgra8Unorm + textureDescriptor.pixelFormat = pixelFormat textureDescriptor.width = width textureDescriptor.height = height textureDescriptor.usage = [.renderTarget] @@ -130,7 +146,7 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { let textureDescriptor = MTLTextureDescriptor() textureDescriptor.textureType = .type2D - textureDescriptor.pixelFormat = .bgra8Unorm + textureDescriptor.pixelFormat = pixelFormat textureDescriptor.width = width textureDescriptor.height = height textureDescriptor.usage = [.renderTarget] @@ -144,7 +160,7 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { self.texture = texture } - func replace(rgbaData: Data, range: Range, width: Int, height: Int, bytesPerRow: Int) { + func replace(rgbaData: Data, width: Int, height: Int, bytesPerRow: Int) { if width != self.width || height != self.height { assert(false, "Image size does not match") return @@ -153,11 +169,11 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { if let buffer = self.buffer, self.bytesPerRow == bytesPerRow { rgbaData.withUnsafeBytes { bytes in - let _ = memcpy(buffer.contents(), bytes.baseAddress!.advanced(by: range.lowerBound), bytesPerRow * height) + let _ = memcpy(buffer.contents(), bytes.baseAddress!, bytesPerRow * height) } } else { rgbaData.withUnsafeBytes { bytes in - self.texture.replace(region: region, mipmapLevel: 0, withBytes: bytes.baseAddress!.advanced(by: range.lowerBound), bytesPerRow: bytesPerRow) + self.texture.replace(region: region, mipmapLevel: 0, withBytes: bytes.baseAddress!, bytesPerRow: bytesPerRow) } } } @@ -229,15 +245,26 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { private final class Frame { let timestamp: Double - let texture: TextureStorage.Content + let textureY: TextureStorage.Content + let textureU: TextureStorage.Content + let textureV: TextureStorage.Content + let textureA: TextureStorage.Content - init(device: MTLDevice, texture: TextureStorage.Content, data: AnimationCacheItemFrame, timestamp: Double) { + init?(device: MTLDevice, textureY: TextureStorage.Content, textureU: TextureStorage.Content, textureV: TextureStorage.Content, textureA: TextureStorage.Content, data: AnimationCacheItemFrame, timestamp: Double) { self.timestamp = timestamp - self.texture = texture + self.textureY = textureY + self.textureU = textureU + self.textureV = textureV + self.textureA = textureA switch data.format { - case let .rgba(width, height, bytesPerRow): - texture.replace(rgbaData: data.data, range: data.range, width: width, height: height, bytesPerRow: bytesPerRow) + case .rgba: + return nil + case let .yuva(y, u, v, a): + self.textureY.replace(rgbaData: y.data, width: y.width, height: y.height, bytesPerRow: y.bytesPerRow) + self.textureU.replace(rgbaData: u.data, width: u.width, height: u.height, bytesPerRow: u.bytesPerRow) + self.textureV.replace(rgbaData: v.data, width: v.width, height: v.height, bytesPerRow: v.bytesPerRow) + self.textureA.replace(rgbaData: a.data, width: a.width, height: a.height, bytesPerRow: a.bytesPerRow) } } } @@ -316,11 +343,11 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { self.isPlaying = isPlaying } - func animationTick(device: MTLDevice, texturePool: TextureStoragePool, advanceTimestamp: Double) -> LoadFrameTask? { - return self.update(device: device, texturePool: texturePool, advanceTimestamp: advanceTimestamp) + func animationTick(device: MTLDevice, texturePoolFullPlane: TextureStoragePool, texturePoolHalfPlane: TextureStoragePool, advanceTimestamp: Double) -> LoadFrameTask? { + return self.update(device: device, texturePoolFullPlane: texturePoolFullPlane, texturePoolHalfPlane: texturePoolHalfPlane, advanceTimestamp: advanceTimestamp) } - private func update(device: MTLDevice, texturePool: TextureStoragePool, advanceTimestamp: Double?) -> LoadFrameTask? { + private func update(device: MTLDevice, texturePoolFullPlane: TextureStoragePool, texturePoolHalfPlane: TextureStoragePool, advanceTimestamp: Double?) -> LoadFrameTask? { guard let item = self.item else { return nil } @@ -335,7 +362,7 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { self.isLoadingFrame = true return LoadFrameTask(task: { [weak self] in - let frame = item.getFrame(at: timestamp) + let frame = item.getFrame(at: timestamp, requestedFormat: .rgba) return { guard let strongSelf = self else { @@ -343,9 +370,12 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { } var currentFrame: Frame? - let texture = texturePool.take(device: device) - if let frame = frame, let texture = texture { - currentFrame = Frame(device: device, texture: texture, data: frame, timestamp: timestamp) + let textureY = texturePoolFullPlane.take(device: device) + let textureU = texturePoolHalfPlane.take(device: device) + let textureV = texturePoolHalfPlane.take(device: device) + let textureA = texturePoolFullPlane.take(device: device) + if let frame = frame, let textureY = textureY, let textureU = textureU, let textureV = textureV, let textureA = textureA { + currentFrame = Frame(device: device, textureY: textureY, textureU: textureU, textureV: textureV, textureA: textureA, data: frame, timestamp: timestamp) } strongSelf.isLoadingFrame = false @@ -369,7 +399,8 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { private let commandQueue: MTLCommandQueue private let renderPipelineState: MTLRenderPipelineState - private let texturePool: TextureStoragePool + private let texturePoolFullPlane: TextureStoragePool + private let texturePoolHalfPlane: TextureStoragePool private let slotCount: Int private let slotsX: Int @@ -389,8 +420,10 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { self.cellSize = cellSize self.stateUpdated = stateUpdated - self.slotsX = 16 - self.slotsY = 16 + let resolutionX = max(1, (1024 / Int(cellSize.width))) * Int(cellSize.width) + let resolutionY = max(1, (1024 / Int(cellSize.height))) * Int(cellSize.height) + self.slotsX = resolutionX / Int(cellSize.width) + self.slotsY = resolutionY / Int(cellSize.height) let drawableSize = CGSize(width: cellSize.width * CGFloat(self.slotsX), height: cellSize.height * CGFloat(self.slotsY)) self.slotCount = (Int(drawableSize.width) / Int(cellSize.width)) * (Int(drawableSize.height) / Int(cellSize.height)) @@ -413,7 +446,8 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { self.renderPipelineState = makePipelineState(device: self.metalDevice, library: defaultLibrary, vertexProgram: "multiAnimationVertex", fragmentProgram: "multiAnimationFragment")! - self.texturePool = TextureStoragePool(width: Int(self.cellSize.width), height: Int(self.cellSize.height)) + self.texturePoolFullPlane = TextureStoragePool(width: Int(self.cellSize.width), height: Int(self.cellSize.height), format: .r) + self.texturePoolHalfPlane = TextureStoragePool(width: Int(self.cellSize.width) / 2, height: Int(self.cellSize.height) / 2, format: .r) super.init() @@ -427,6 +461,7 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { self.pixelFormat = .bgra8Unorm self.framebufferOnly = true self.allowsNextDrawableTimeout = true + self.isOpaque = false } override public init(layer: Any) { @@ -465,6 +500,23 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { if let itemContext = self.itemContexts[itemId] { itemContext.targets.append(TargetReference(target)) + + let deinitIndex = target.deinitCallbacks.add { [weak self, weak itemContext] in + Queue.mainQueue().async { + guard let strongSelf = self, let currentItemContext = strongSelf.itemContexts[itemId], currentItemContext === itemContext else { + return + } + strongSelf.removeTargetFromItemContext(itemId: itemId, itemContext: currentItemContext, targetId: targetId) + } + } + + let updateStateIndex = target.updateStateCallbacks.add { [weak itemContext] in + guard let itemContext = itemContext else { + return + } + itemContext.updateIsPlaying() + } + target.contents = self.contents let slotX = itemContext.slotIndex % self.slotsX @@ -476,22 +528,18 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { self.isPlaying = true - return ActionDisposable { [weak self, weak itemContext] in + return ActionDisposable { [weak self, weak target, weak itemContext] in Queue.mainQueue().async { guard let strongSelf = self, let currentItemContext = strongSelf.itemContexts[itemId], currentItemContext === itemContext else { return } - if let index = currentItemContext.targets.firstIndex(where: { $0.id == targetId }) { - currentItemContext.targets.remove(at: index) - if currentItemContext.targets.isEmpty { - strongSelf.slotToItemId[currentItemContext.slotIndex] = nil - strongSelf.itemContexts.removeValue(forKey: itemId) - - if strongSelf.itemContexts.isEmpty { - strongSelf.isPlaying = false - } - } + + if let target = target { + target.deinitCallbacks.remove(deinitIndex) + target.updateStateCallbacks.remove(updateStateIndex) } + + strongSelf.removeTargetFromItemContext(itemId: itemId, itemContext: currentItemContext, targetId: targetId) } } } else { @@ -499,6 +547,21 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { } } + private func removeTargetFromItemContext(itemId: String, itemContext: ItemContext, targetId: Int64) { + if let index = itemContext.targets.firstIndex(where: { $0.id == targetId }) { + itemContext.targets.remove(at: index) + + if itemContext.targets.isEmpty { + self.slotToItemId[itemContext.slotIndex] = nil + self.itemContexts.removeValue(forKey: itemId) + + if self.itemContexts.isEmpty { + self.isPlaying = false + } + } + } + } + private func updateIsPlaying() { var isPlaying = false for (_, itemContext) in self.itemContexts { @@ -515,7 +578,7 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { var tasks: [LoadFrameTask] = [] for (_, itemContext) in self.itemContexts { if itemContext.isPlaying { - if let task = itemContext.animationTick(device: self.metalDevice, texturePool: self.texturePool, advanceTimestamp: advanceTimestamp) { + if let task = itemContext.animationTick(device: self.metalDevice, texturePoolFullPlane: self.texturePoolFullPlane, texturePoolHalfPlane: self.texturePoolHalfPlane, advanceTimestamp: advanceTimestamp) { tasks.append(task) } } @@ -580,25 +643,31 @@ public final class MultiAnimationMetalRendererImpl: MultiAnimationRenderer { let contentsRect = CGRect(origin: CGPoint(x: (CGFloat(slotX) * self.cellSize.width) / totalX, y: (CGFloat(slotY) * self.cellSize.height) / totalY), size: CGSize(width: self.cellSize.width / totalX, height: self.cellSize.height / totalY)) - vertices[4 * 0 + 0] = Float(contentsRect.minX).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) - vertices[4 * 0 + 1] = Float(contentsRect.minY).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) - - vertices[4 * 1 + 0] = Float(contentsRect.maxX).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) - vertices[4 * 1 + 1] = Float(contentsRect.minY).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) - vertices[4 * 2 + 0] = Float(contentsRect.minX).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) - vertices[4 * 2 + 1] = Float(contentsRect.maxY).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) + vertices[4 * 2 + 1] = Float(contentsRect.minY).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) vertices[4 * 3 + 0] = Float(contentsRect.maxX).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) - vertices[4 * 3 + 1] = Float(contentsRect.maxY).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) + vertices[4 * 3 + 1] = Float(contentsRect.minY).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) + + vertices[4 * 0 + 0] = Float(contentsRect.minX).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) + vertices[4 * 0 + 1] = Float(contentsRect.maxY).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) + + vertices[4 * 1 + 0] = Float(contentsRect.maxX).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) + vertices[4 * 1 + 1] = Float(contentsRect.maxY).remap(fromLow: 0.0, fromHigh: 1.0, toLow: -1.0, toHigh: 1.0) renderEncoder.setVertexBytes(&vertices, length: 4 * vertices.count, index: 0) var slotPosition = simd_uint2(UInt32(itemContext.slotIndex % self.slotsX), UInt32(itemContext.slotIndex % self.slotsY)) renderEncoder.setVertexBytes(&slotPosition, length: MemoryLayout.size * 2, index: 3) - usedTextures.append(frame.texture) - renderEncoder.setFragmentTexture(frame.texture.texture, index: 0) + usedTextures.append(frame.textureY) + usedTextures.append(frame.textureU) + usedTextures.append(frame.textureV) + usedTextures.append(frame.textureA) + renderEncoder.setFragmentTexture(frame.textureY.texture, index: 0) + renderEncoder.setFragmentTexture(frame.textureU.texture, index: 1) + renderEncoder.setFragmentTexture(frame.textureV.texture, index: 2) + renderEncoder.setFragmentTexture(frame.textureA.texture, index: 3) renderEncoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4, instanceCount: 1) } diff --git a/submodules/TelegramUI/Components/MultiAnimationRenderer/Sources/MultiAnimationRenderer.swift b/submodules/TelegramUI/Components/MultiAnimationRenderer/Sources/MultiAnimationRenderer.swift index 6b354caa28..c30fa0affe 100644 --- a/submodules/TelegramUI/Components/MultiAnimationRenderer/Sources/MultiAnimationRenderer.swift +++ b/submodules/TelegramUI/Components/MultiAnimationRenderer/Sources/MultiAnimationRenderer.swift @@ -16,8 +16,8 @@ private var nextRenderTargetId: Int64 = 1 open class MultiAnimationRenderTarget: SimpleLayer { public let id: Int64 - fileprivate let deinitCallbacks = Bag<() -> Void>() - fileprivate let updateStateCallbacks = Bag<() -> Void>() + let deinitCallbacks = Bag<() -> Void>() + let updateStateCallbacks = Bag<() -> Void>() public final var shouldBeAnimating: Bool = false { didSet { @@ -69,16 +69,16 @@ private final class FrameGroup { let timestamp: Double init?(item: AnimationCacheItem, timestamp: Double) { - guard let firstFrame = item.getFrame(at: timestamp) else { + guard let firstFrame = item.getFrame(at: timestamp, requestedFormat: .rgba) else { return nil } switch firstFrame.format { - case let .rgba(width, height, bytesPerRow): + case let .rgba(data, width, height, bytesPerRow): let context = DrawingContext(size: CGSize(width: CGFloat(width), height: CGFloat(height)), scale: 1.0, opaque: false, bytesPerRow: bytesPerRow) - firstFrame.data.withUnsafeBytes { bytes -> Void in - memcpy(context.bytes, bytes.baseAddress!.advanced(by: firstFrame.range.lowerBound), height * bytesPerRow) + data.withUnsafeBytes { bytes -> Void in + memcpy(context.bytes, bytes.baseAddress!, height * bytesPerRow) /*var sourceBuffer = vImage_Buffer() sourceBuffer.width = UInt(width) @@ -110,6 +110,8 @@ private final class FrameGroup { self.size = CGSize(width: CGFloat(width), height: CGFloat(height)) self.timestamp = timestamp self.badgeImage = nil + default: + return nil } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 7f7efef8c2..7b4bbe4d44 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -303,11 +303,11 @@ class ChatPresentationContext { }) let animationRenderer: MultiAnimationRenderer - /*if #available(iOS 13.0, *) { + if #available(iOS 13.0, *) { animationRenderer = MultiAnimationMetalRendererImpl() - } else {*/ + } else { animationRenderer = MultiAnimationRendererImpl() - //} + } self.animationRenderer = animationRenderer }