mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Metal rendering improvements
This commit is contained in:
parent
b90e1bcef6
commit
1cda4437cc
@ -245,6 +245,12 @@ public final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func alignUp(size: Int, align: Int) -> Int {
|
||||||
|
precondition(((align - 1) & align) == 0, "Align must be a power of two")
|
||||||
|
|
||||||
|
let alignmentMask = align - 1
|
||||||
|
return (size + alignmentMask) & ~alignmentMask
|
||||||
|
}
|
||||||
|
|
||||||
private final class AnimatedStickerDirectFrameSourceCache {
|
private final class AnimatedStickerDirectFrameSourceCache {
|
||||||
private enum FrameRangeResult {
|
private enum FrameRangeResult {
|
||||||
@ -274,8 +280,8 @@ private final class AnimatedStickerDirectFrameSourceCache {
|
|||||||
self.storeQueue = sharedStoreQueue
|
self.storeQueue = sharedStoreQueue
|
||||||
|
|
||||||
self.frameCount = frameCount
|
self.frameCount = frameCount
|
||||||
self.width = width
|
self.width = alignUp(size: width, align: 8)
|
||||||
self.height = height
|
self.height = alignUp(size: width, align: 8)
|
||||||
self.useHardware = useHardware
|
self.useHardware = useHardware
|
||||||
|
|
||||||
let suffix : String
|
let suffix : String
|
||||||
|
@ -248,7 +248,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
|
|||||||
override public func didLoad() {
|
override public func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
if #available(iOS 10.0, *), self.useMetalCache {
|
if #available(iOS 10.0, *), (self.useMetalCache/* || "".isEmpty*/) {
|
||||||
self.renderer = AnimatedStickerNode.hardwareRendererPool.take()
|
self.renderer = AnimatedStickerNode.hardwareRendererPool.take()
|
||||||
} else {
|
} else {
|
||||||
self.renderer = AnimatedStickerNode.softwareRendererPool.take()
|
self.renderer = AnimatedStickerNode.softwareRendererPool.take()
|
||||||
|
@ -42,9 +42,9 @@ final class AnimationRendererPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func putBack(renderer: AnimationRenderer) {
|
private func putBack(renderer: AnimationRenderer) {
|
||||||
#if DEBUG
|
/*#if DEBUG
|
||||||
self.items.append(renderer)
|
self.items.append(renderer)
|
||||||
#endif
|
#endif*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,44 +8,19 @@ import Accelerate
|
|||||||
import AnimationCompression
|
import AnimationCompression
|
||||||
import Metal
|
import Metal
|
||||||
import MetalKit
|
import MetalKit
|
||||||
|
import MetalImageView
|
||||||
|
|
||||||
@available(iOS 10.0, *)
|
@available(iOS 10.0, *)
|
||||||
final class CompressedAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
final class CompressedAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
||||||
private final class View: UIView {
|
private final class View: UIView {
|
||||||
static override var layerClass: AnyClass {
|
static override var layerClass: AnyClass {
|
||||||
#if targetEnvironment(simulator)
|
return MetalImageLayer.self
|
||||||
if #available(iOS 13.0, *) {
|
|
||||||
return CAMetalLayer.self
|
|
||||||
} else {
|
|
||||||
preconditionFailure()
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return CAMetalLayer.self
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init(device: MTLDevice) {
|
init(device: MTLDevice) {
|
||||||
super.init(frame: CGRect())
|
super.init(frame: CGRect())
|
||||||
|
|
||||||
#if targetEnvironment(simulator)
|
(self.layer as! MetalImageLayer).renderer.device = device
|
||||||
if #available(iOS 13.0, *) {
|
|
||||||
let metalLayer = self.layer as! CAMetalLayer
|
|
||||||
|
|
||||||
metalLayer.device = MTLCreateSystemDefaultDevice()
|
|
||||||
metalLayer.pixelFormat = .bgra8Unorm
|
|
||||||
metalLayer.framebufferOnly = true
|
|
||||||
metalLayer.allowsNextDrawableTimeout = true
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
let metalLayer = self.layer as! CAMetalLayer
|
|
||||||
|
|
||||||
metalLayer.device = MTLCreateSystemDefaultDevice()
|
|
||||||
metalLayer.pixelFormat = .bgra8Unorm
|
|
||||||
metalLayer.framebufferOnly = true
|
|
||||||
if #available(iOS 11.0, *) {
|
|
||||||
metalLayer.allowsNextDrawableTimeout = true
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
@ -82,16 +57,25 @@ final class CompressedAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
|||||||
func render(queue: Queue, width: Int, height: Int, bytesPerRow: Int, data: Data, type: AnimationRendererFrameType, mulAlpha: Bool, completion: @escaping () -> Void) {
|
func render(queue: Queue, width: Int, height: Int, bytesPerRow: Int, data: Data, type: AnimationRendererFrameType, mulAlpha: Bool, completion: @escaping () -> Void) {
|
||||||
switch type {
|
switch type {
|
||||||
case .dct:
|
case .dct:
|
||||||
self.renderer.renderIdct(metalLayer: self.layer, compressedImage: AnimationCompressor.CompressedImageData(data: data), completion: completion)
|
self.renderer.renderIdct(layer: self.layer as! MetalImageLayer, compressedImage: AnimationCompressor.CompressedImageData(data: data), completion: { [weak self] in
|
||||||
|
self?.updateHighlightedContentNode()
|
||||||
|
completion()
|
||||||
|
})
|
||||||
case .argb:
|
case .argb:
|
||||||
self.renderer.renderRgb(metalLayer: self.layer, width: width, height: height, bytesPerRow: bytesPerRow, data: data, completion: completion)
|
self.renderer.renderRgb(layer: self.layer as! MetalImageLayer, width: width, height: height, bytesPerRow: bytesPerRow, data: data, completion: { [weak self] in
|
||||||
|
self?.updateHighlightedContentNode()
|
||||||
|
completion()
|
||||||
|
})
|
||||||
case .yuva:
|
case .yuva:
|
||||||
self.renderer.renderYuva(metalLayer: self.layer, width: width, height: height, data: data, completion: completion)
|
self.renderer.renderYuva(layer: self.layer as! MetalImageLayer, width: width, height: height, data: data, completion: { [weak self] in
|
||||||
|
self?.updateHighlightedContentNode()
|
||||||
|
completion()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateHighlightedContentNode() {
|
private func updateHighlightedContentNode() {
|
||||||
/*guard let highlightedContentNode = self.highlightedContentNode, let highlightedColor = self.highlightedColor else {
|
guard let highlightedContentNode = self.highlightedContentNode, let highlightedColor = self.highlightedColor else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let contents = self.contents, CFGetTypeID(contents as CFTypeRef) == CGImage.typeID {
|
if let contents = self.contents, CFGetTypeID(contents as CFTypeRef) == CGImage.typeID {
|
||||||
@ -100,11 +84,11 @@ final class CompressedAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
|||||||
highlightedContentNode.tintColor = highlightedColor
|
highlightedContentNode.tintColor = highlightedColor
|
||||||
if self.highlightReplacesContent {
|
if self.highlightReplacesContent {
|
||||||
self.contents = nil
|
self.contents = nil
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setOverlayColor(_ color: UIColor?, replace: Bool, animated: Bool) {
|
func setOverlayColor(_ color: UIColor?, replace: Bool, animated: Bool) {
|
||||||
/*self.highlightReplacesContent = replace
|
self.highlightReplacesContent = replace
|
||||||
var updated = false
|
var updated = false
|
||||||
if let current = self.highlightedColor, let color = color {
|
if let current = self.highlightedColor, let color = color {
|
||||||
updated = !current.isEqual(color)
|
updated = !current.isEqual(color)
|
||||||
@ -141,6 +125,6 @@ final class CompressedAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
|||||||
strongSelf.highlightedContentNode?.removeFromSupernode()
|
strongSelf.highlightedContentNode?.removeFromSupernode()
|
||||||
strongSelf.highlightedContentNode = nil
|
strongSelf.highlightedContentNode = nil
|
||||||
})
|
})
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import Metal
|
|||||||
import MetalKit
|
import MetalKit
|
||||||
import simd
|
import simd
|
||||||
import DctHuffman
|
import DctHuffman
|
||||||
|
import MetalImageView
|
||||||
|
|
||||||
private struct Vertex {
|
private struct Vertex {
|
||||||
var position: vector_float2
|
var position: vector_float2
|
||||||
@ -109,62 +110,9 @@ public final class CompressedImageRenderer {
|
|||||||
|
|
||||||
private var drawableRequestTimestamp: Double?
|
private var drawableRequestTimestamp: Double?
|
||||||
|
|
||||||
private func getNextDrawable(metalLayer: CALayer, drawableSize: CGSize) -> CAMetalDrawable? {
|
private func getNextDrawable(layer: MetalImageLayer, drawableSize: CGSize) -> MetalImageLayer.Drawable? {
|
||||||
#if targetEnvironment(simulator)
|
layer.renderer.drawableSize = drawableSize
|
||||||
if #available(iOS 13.0, *) {
|
return layer.renderer.nextDrawable()
|
||||||
if let metalLayer = metalLayer as? CAMetalLayer {
|
|
||||||
if metalLayer.drawableSize != drawableSize {
|
|
||||||
metalLayer.drawableSize = drawableSize
|
|
||||||
}
|
|
||||||
let beginTime = CFAbsoluteTimeGetCurrent()
|
|
||||||
let drawableRequestDuration: Double
|
|
||||||
if let drawableRequestTimestamp = self.drawableRequestTimestamp {
|
|
||||||
drawableRequestDuration = beginTime - drawableRequestTimestamp
|
|
||||||
if drawableRequestDuration < 1.0 / 60.0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
drawableRequestDuration = 0.0
|
|
||||||
}
|
|
||||||
self.drawableRequestTimestamp = beginTime
|
|
||||||
let result = metalLayer.nextDrawable()
|
|
||||||
let duration = CFAbsoluteTimeGetCurrent() - beginTime
|
|
||||||
if duration > 1.0 / 60.0 {
|
|
||||||
print("lag \(duration * 1000.0) ms (\(drawableRequestDuration * 1000.0) ms)")
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if let metalLayer = metalLayer as? CAMetalLayer {
|
|
||||||
if metalLayer.drawableSize != drawableSize {
|
|
||||||
metalLayer.drawableSize = drawableSize
|
|
||||||
}
|
|
||||||
let beginTime = CFAbsoluteTimeGetCurrent()
|
|
||||||
let drawableRequestDuration: Double
|
|
||||||
if let drawableRequestTimestamp = self.drawableRequestTimestamp {
|
|
||||||
drawableRequestDuration = beginTime - drawableRequestTimestamp
|
|
||||||
if drawableRequestDuration < 1.0 / 60.0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
drawableRequestDuration = 0.0
|
|
||||||
}
|
|
||||||
self.drawableRequestTimestamp = beginTime
|
|
||||||
let result = metalLayer.nextDrawable()
|
|
||||||
let duration = CFAbsoluteTimeGetCurrent() - beginTime
|
|
||||||
if duration > 1.0 / 200.0 {
|
|
||||||
print("lag \(duration * 1000.0) ms (\(drawableRequestDuration * 1000.0) ms)")
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateIdctTextures(compressedImage: AnimationCompressor.CompressedImageData) {
|
private func updateIdctTextures(compressedImage: AnimationCompressor.CompressedImageData) {
|
||||||
@ -241,7 +189,7 @@ public final class CompressedImageRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func renderIdct(metalLayer: CALayer, compressedImage: AnimationCompressor.CompressedImageData, completion: @escaping () -> Void) {
|
public func renderIdct(layer: MetalImageLayer, compressedImage: AnimationCompressor.CompressedImageData, completion: @escaping () -> Void) {
|
||||||
DispatchQueue.global().async {
|
DispatchQueue.global().async {
|
||||||
self.updateIdctTextures(compressedImage: compressedImage)
|
self.updateIdctTextures(compressedImage: compressedImage)
|
||||||
|
|
||||||
@ -313,7 +261,7 @@ public final class CompressedImageRenderer {
|
|||||||
|
|
||||||
let drawableSize = CGSize(width: CGFloat(outputTextures.textures[0].width), height: CGFloat(outputTextures.textures[0].height))
|
let drawableSize = CGSize(width: CGFloat(outputTextures.textures[0].width), height: CGFloat(outputTextures.textures[0].height))
|
||||||
|
|
||||||
guard let drawable = self.getNextDrawable(metalLayer: metalLayer, drawableSize: drawableSize) else {
|
guard let drawable = self.getNextDrawable(layer: layer, drawableSize: drawableSize) else {
|
||||||
commandBuffer.commit()
|
commandBuffer.commit()
|
||||||
completion()
|
completion()
|
||||||
return
|
return
|
||||||
@ -339,35 +287,15 @@ public final class CompressedImageRenderer {
|
|||||||
|
|
||||||
renderEncoder.endEncoding()
|
renderEncoder.endEncoding()
|
||||||
|
|
||||||
var storedDrawable: MTLDrawable? = drawable
|
var storedDrawable: MetalImageLayer.Drawable? = drawable
|
||||||
commandBuffer.addScheduledHandler { _ in
|
|
||||||
autoreleasepool {
|
|
||||||
storedDrawable?.present()
|
|
||||||
storedDrawable = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if targetEnvironment(simulator)
|
|
||||||
commandBuffer.addCompletedHandler { _ in
|
commandBuffer.addCompletedHandler { _ in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion()
|
autoreleasepool {
|
||||||
}
|
storedDrawable?.present(completion: completion)
|
||||||
}
|
storedDrawable = nil
|
||||||
#else
|
|
||||||
if #available(iOS 10.3, *) {
|
|
||||||
drawable.addPresentedHandler { _ in
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
completion()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
commandBuffer.addCompletedHandler { _ in
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
completion()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
commandBuffer.commit()
|
commandBuffer.commit()
|
||||||
}
|
}
|
||||||
@ -402,14 +330,7 @@ public final class CompressedImageRenderer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func renderRgb(metalLayer: CALayer, width: Int, height: Int, bytesPerRow: Int, data: Data, completion: @escaping () -> Void) {
|
public func renderRgb(layer: MetalImageLayer, width: Int, height: Int, bytesPerRow: Int, data: Data, completion: @escaping () -> Void) {
|
||||||
if "".isEmpty {
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.0 / 60.0, execute: {
|
|
||||||
completion()
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
self.updateRgbTexture(width: width, height: height, bytesPerRow: bytesPerRow, data: data)
|
self.updateRgbTexture(width: width, height: height, bytesPerRow: bytesPerRow, data: data)
|
||||||
|
|
||||||
guard let rgbTexture = self.rgbTexture else {
|
guard let rgbTexture = self.rgbTexture else {
|
||||||
@ -423,7 +344,7 @@ public final class CompressedImageRenderer {
|
|||||||
|
|
||||||
let drawableSize = CGSize(width: CGFloat(rgbTexture.width), height: CGFloat(rgbTexture.height))
|
let drawableSize = CGSize(width: CGFloat(rgbTexture.width), height: CGFloat(rgbTexture.height))
|
||||||
|
|
||||||
guard let drawable = self.getNextDrawable(metalLayer: metalLayer, drawableSize: drawableSize) else {
|
guard let drawable = self.getNextDrawable(layer: layer, drawableSize: drawableSize) else {
|
||||||
commandBuffer.commit()
|
commandBuffer.commit()
|
||||||
completion()
|
completion()
|
||||||
return
|
return
|
||||||
@ -446,35 +367,15 @@ public final class CompressedImageRenderer {
|
|||||||
|
|
||||||
renderEncoder.endEncoding()
|
renderEncoder.endEncoding()
|
||||||
|
|
||||||
var storedDrawable: MTLDrawable? = drawable
|
var storedDrawable: MetalImageLayer.Drawable? = drawable
|
||||||
commandBuffer.addScheduledHandler { _ in
|
|
||||||
autoreleasepool {
|
|
||||||
storedDrawable?.present()
|
|
||||||
storedDrawable = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if targetEnvironment(simulator)
|
|
||||||
commandBuffer.addCompletedHandler { _ in
|
commandBuffer.addCompletedHandler { _ in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion()
|
autoreleasepool {
|
||||||
}
|
storedDrawable?.present(completion: completion)
|
||||||
}
|
storedDrawable = nil
|
||||||
#else
|
|
||||||
if #available(iOS 10.3, *) {
|
|
||||||
drawable.addPresentedHandler { _ in
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
completion()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
commandBuffer.addCompletedHandler { _ in
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
completion()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
commandBuffer.commit()
|
commandBuffer.commit()
|
||||||
}
|
}
|
||||||
@ -553,17 +454,10 @@ public final class CompressedImageRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func renderYuva(metalLayer: CALayer, width: Int, height: Int, data: Data, completion: @escaping () -> Void) {
|
public func renderYuva(layer: MetalImageLayer, width: Int, height: Int, data: Data, completion: @escaping () -> Void) {
|
||||||
if self.isRendering {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
completion()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.isRendering = true
|
|
||||||
DispatchQueue.global().async {
|
DispatchQueue.global().async {
|
||||||
autoreleasepool {
|
autoreleasepool {
|
||||||
let renderStartTime = CFAbsoluteTimeGetCurrent()
|
//let renderStartTime = CFAbsoluteTimeGetCurrent()
|
||||||
|
|
||||||
var beginTime: Double = 0.0
|
var beginTime: Double = 0.0
|
||||||
var duration: Double = 0.0
|
var duration: Double = 0.0
|
||||||
@ -578,7 +472,6 @@ public final class CompressedImageRenderer {
|
|||||||
|
|
||||||
guard let yuvaTextures = self.yuvaTextures else {
|
guard let yuvaTextures = self.yuvaTextures else {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.isRendering = false
|
|
||||||
completion()
|
completion()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -588,7 +481,6 @@ public final class CompressedImageRenderer {
|
|||||||
|
|
||||||
guard let commandBuffer = self.commandQueue.makeCommandBuffer() else {
|
guard let commandBuffer = self.commandQueue.makeCommandBuffer() else {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.isRendering = false
|
|
||||||
completion()
|
completion()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -598,10 +490,9 @@ public final class CompressedImageRenderer {
|
|||||||
|
|
||||||
let drawableSize = CGSize(width: CGFloat(yuvaTextures.width), height: CGFloat(yuvaTextures.height))
|
let drawableSize = CGSize(width: CGFloat(yuvaTextures.width), height: CGFloat(yuvaTextures.height))
|
||||||
|
|
||||||
guard let drawable = self.getNextDrawable(metalLayer: metalLayer, drawableSize: drawableSize) else {
|
guard let drawable = self.getNextDrawable(layer: layer, drawableSize: drawableSize) else {
|
||||||
commandBuffer.commit()
|
commandBuffer.commit()
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.isRendering = false
|
|
||||||
completion()
|
completion()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -614,7 +505,6 @@ public final class CompressedImageRenderer {
|
|||||||
|
|
||||||
guard let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) else {
|
guard let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) else {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.isRendering = false
|
|
||||||
completion()
|
completion()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -633,44 +523,15 @@ public final class CompressedImageRenderer {
|
|||||||
|
|
||||||
renderEncoder.endEncoding()
|
renderEncoder.endEncoding()
|
||||||
|
|
||||||
var storedDrawable: MTLDrawable? = drawable
|
var storedDrawable: MetalImageLayer.Drawable? = drawable
|
||||||
commandBuffer.addScheduledHandler { _ in
|
|
||||||
autoreleasepool {
|
|
||||||
storedDrawable?.present()
|
|
||||||
storedDrawable = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if targetEnvironment(simulator)
|
|
||||||
commandBuffer.addCompletedHandler { _ in
|
commandBuffer.addCompletedHandler { _ in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.isRendering = false
|
autoreleasepool {
|
||||||
completion()
|
storedDrawable?.present(completion: completion)
|
||||||
}
|
storedDrawable = nil
|
||||||
}
|
|
||||||
#else
|
|
||||||
if #available(iOS 10.3, *) {
|
|
||||||
commandBuffer.addCompletedHandler { _ in
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self.isRendering = false
|
|
||||||
}
|
|
||||||
let renderDuration = CFAbsoluteTimeGetCurrent() - renderStartTime
|
|
||||||
print("render duration \(renderDuration * 1000.0) ms")
|
|
||||||
}
|
|
||||||
drawable.addPresentedHandler { _ in
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
completion()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
commandBuffer.addCompletedHandler { _ in
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self.isRendering = false
|
|
||||||
completion()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
commandBuffer.commit()
|
commandBuffer.commit()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user