【问题标题】:CALayer drawinContext called @ 60fps but view update graphics @ 1fpsCALayer drawinContext 调用 @ 60fps 但查看更新图形 @ 1fps
【发布时间】:2015-10-14 06:43:11
【问题描述】:

我正在尝试使用 NSBezierPath 的 Cocoa 和 Quartz 框架在 OSX 中实现图形绘制视图,并随时添加/删除数据点。

在 drawRect 中这样做可以正常工作,因为图形经常更新,但是当我需要增加总数据点/采样率时遇到了性能问题。

我决定改用 drawLayer:inContext: 但由于函数以 60fps 调用,因此视图不会在调用函数时更新图形,而是以 1fps 更新。

我在这里做错了什么?

class CustomDrawLayer: CALayer {


convenience init(view: NSView, drawsAsynchronously : Bool = false) {
    self.init()
    self.bounds = view.bounds
    self.anchorPoint = CGPointZero
    self.opaque = false
    self.frame = view.frame
    self.drawsAsynchronously = drawsAsynchronously

    //        for multiple draws in hosting view
    //        self.delegate = self

}

override func actionForLayer(layer: CALayer, forKey event: String) -> CAAction? {
    return nil
}}

override func drawLayer(layer: CALayer, inContext ctx: CGContext) {

    if layer == self.layer {
        Swift.print("axes drawing")
        graphBounds.origin = self.frame.origin
        graphAxes.drawAxesInRect(graphBounds, axeOrigin: plotOrigin, xPointsToShow: CGFloat(totalSecondsToDisplay), yPointsToShow: CGFloat(totalChannelsToDisplay))
    }

    if layer == self.board {
        Swift.print(1/NSDate().timeIntervalSinceDate(fpsTimer))
        fpsTimer = NSDate()
        drawPointsInGraph(graphAxes, context: ctx)

    }
}

    func drawPointsInGraph(axes: AxesDrawer, context:  CGContext)
    {
            color.set()

            var x : CGFloat = 0
            var y : CGFloat = 0

            for var channel = 0; channel < Int(totalChannelsToDisplay); channel++ {

                path.removeAllPoints()

                var visibleIndex = (dirtyRect.origin.x - axes.position.x) / (axes.pointsPerUnit.x / samplingRate)
                if visibleIndex < 2 {
                    visibleIndex = 2
                }
                for var counter = Int(visibleIndex); counter < dataStream![channel].count; counter++ {

                    if dataStream![channel][counter] == 0  {
                        if path.elementCount > 0 {
                            path.stroke()
                        }

                        break
                    }


                    let position = axes.position
                    let ppY = axes.pointsPerUnit.y
                    let ppX = axes.pointsPerUnit.x

                    let channelYLocation = CGFloat(channel)

                    x = position.x + CGFloat(counter-1) * (ppX / samplingRate)
                    y = ((channelYLocation * ppY) + position.y) + (dataStream![channel][counter-1] * (ppY))
                    path.moveToPoint(CGPoint(x: align(x), y: align(y)))

                    x = position.x + CGFloat(counter) * (ppX / samplingRate)
                    y = ((channelYLocation * ppY) + position.y) + (dataStream![channel][counter] * (ppY) )


                    path.lineToPoint(CGPoint(x: align(x), y: align(y)))




                    if x > (axes.position.x + axes.bounds.width) * 0.9 {

                        graphAxes.forwardStep = 5
                        dirtyRect = graphBounds

                        for var c = 0; c < Int(totalChannelsToDisplay); c++ {
                            for var i = 0; i < Int(samplingRate) * graphAxes.forwardStep; i++
                            {
                                dataStream![c][i] = 0
                            }

                        }

                        return
                    }


                }



                path.stroke()

        }

        if inLiveResize {
            dirtyRect = graphBounds
        } else {
            dirtyRect.origin.x = x
            dirtyRect.origin.y = bounds.minY
            dirtyRect.size.width = 10
            dirtyRect.size.height = bounds.height
        }


    }

【问题讨论】:

    标签: ios macos cocoa core-animation quartz-graphics


    【解决方案1】:

    您很少会以 60 Hz 的频率调用函数。在任何情况下,您都不应该尝试以 60 Hz 的频率调用绘图函数;这在 Cocoa 中毫无意义。如果您的意思是“在屏幕刷新间隔”,请参阅CADisplayLink,它是专门为允许您在屏幕刷新间隔进行绘制而构建的。这可能低于 60 Hz。如果您尝试以 60 Hz 精确绘制,您可能会失去同步并导致动画中出现节拍。但这实际上只适用于实时视频之类的东西。如果这就是你所拥有的,那么这就是工具,但听起来并不像它。

    理解您的代码有点困难。目前尚不清楚您的 60fps 来自何处。但我假设您正在尝试做的是动画绘制图表。如果是这样,正如 Mark F 所说,请参阅 CAShapeLayer。它内置了自动路径动画,绝对是您想要的。它会自动处理时间并与屏幕刷新和 GPU 优化同步,以及许多您不应该尝试解决的其他事情。

    即使CAShapeLayer 不是您想要的,您也应该查看Core Animation,它旨在与您一起为值设置动画并在必要时重绘。例如,它会自动处理在多个核心上渲染您的层,这将显着提高性能。有关更多信息,请参阅Animating Custom Layer Properties

    【讨论】:

      【解决方案2】:

      如果您的路径需要如此频繁地绘制,请查看 CAShapeLayer,您可以在其中更改路径属性。这将是硬件加速的,并且比 drawRect 或 drawLayer 快得多。

      【讨论】:

        猜你喜欢
        • 2012-02-17
        • 1970-01-01
        • 2012-07-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多