我怎样才能加速这个进行许多椭圆填充的Quartz 2D绘制循环?

时间:2015-03-24 23:23:56

标签: ios objective-c performance swift quartz-2d

我有一个应用程序可以完成数千个循环填充,每个循环填充可以在每个帧中独立变化。 Quartz在这方面非常快,我可以在iPhone 6上获得大约30fps,下面的示例使用-Ofast,-Ounchecked。但是我想尽可能地优化它。

我尝试或考虑的事情:

1)绘制缓存的图像而不是填充椭圆:我尝试使用此技术的代码在示例中被注释掉,因为我希望它可以更快。我发现的是,对于示例中的填充尺寸大致相同,但随着填充变大,它比简单绘制要慢得多。 (这与我在尝试此操作时在Java中发现的内容相矛盾。)

2)填充图像后面的矩形蒙版:填充矩形比填充椭圆要快得多,但是当我向蒙版添加剪裁时,它的速度会慢一些。如果有人要我发布它(试图保持这一点),我有一些代码。

3)Metal API:根据我的阅读,我可以使用几何着色器在GPU上渲染缩放适当的圆形几何体。我担心这是GPU的最坏情况,因为所有顶点数据都可以在每个帧上独立变化。我对这有多快没有任何直觉,除非我确定这将是一个巨大的改进,否则它需要学习很多。

这是一个代表问题的测试UIView(我省略了颜色以使图像比特更简单)。它是用Swift编写的,但如果它有帮助我很乐意将部件移动到objc(我不认为Swift是这里的问题)。请注意,技术的相对性能因maxPartSize而异。我正在寻找任何可以加快速度的方法。感谢。

class TestView: UIView
{
    var parts: [Part]!
    var start:NSDate!
    var drawCount = 0 // for fps counter
    var image: UIImage! // for the image approach
    let maxPartSize: CGFloat = 10.0

    override func drawRect(screenRect: CGRect)
    {
        if ( self.start == nil) { self.start = NSDate() }
        if ( self.parts == nil ) { setupParts(screenRect) }

        var context = UIGraphicsGetCurrentContext()
        for (var i=0; i<parts.count; i++) {
            let part = parts[i]
            var drawRect: CGRect = CGRectMake(CGFloat(part.x), CGFloat(part.y), CGFloat(part.size), CGFloat(part.size))

            // Draw 2D
            CGContextSetFillColorWithColor(context, UIColor.blueColor().CGColor)
            CGContextSetAlpha(context, CGFloat(part.trans))
            CGContextFillEllipseInRect(context, drawRect)

            // Draw with image. (This is faster for small values of maxPartSize, much slower otherwise)
            // CGContextSetAlpha(context, CGFloat(part.trans))
            // CGContextDrawImage(context, drawRect, getImage().CGImage)
       }

        drawCount++
        if ( drawCount%100 == 0 ) {
            let fps: Double = Double(drawCount) / NSDate().timeIntervalSinceDate(start)
            println("\(fps) fps")
        }
    }

    func setupParts( rect: CGRect ) {
        self.parts = []
        let numParts = 2000
        for(var i=0; i<numParts; i++ ) {
            let x=randomFloat()*Float(rect.width)
            let y=randomFloat()*Float(rect.height)
            let size = randomFloat() * Float(maxPartSize)
            let trans=randomFloat()
            parts.append( Part( x:x, y:y, size:size, trans:trans) )
        }
    }

    func getImage() -> UIImage
    {
        if ( self.image != nil ) { return self.image }
        var size = CGSizeMake(maxPartSize, maxPartSize)
        UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.mainScreen().scale)
        var context = UIGraphicsGetCurrentContext()
        CGContextSetFillColorWithColor(context, UIColor.blueColor().CGColor)
        CGContextFillEllipseInRect(context, CGRectMake( 0, 0, maxPartSize, maxPartSize) )
        var image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.image = image;
        return image
    }

    required init(coder: NSCoder) {
        super.init(coder: coder)
        startAnimating()
    }

    func refreshView() { self.setNeedsDisplay(); }

    func startAnimating() {
        var updater = CADisplayLink(target: self, selector: Selector("refreshView"))
        updater.frameInterval = 1
        updater.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSRunLoopCommonModes )
    }

}

final class Part {
    var x:Float, y:Float, size: Float, trans: Float 
    init( x:Float, y:Float, size:Float, trans:Float ) {
        self.x = x; self.y = y; self.size = size; self.trans = trans
    }
}

func randomFloat() -> Float {  return Float( arc4random() ) /  Float(UInt32.max) }

0 个答案:

没有答案