简体   繁体   English

CALayer drawinContext称为@ 60fps,但以1fps查看更新图形

[英]CALayer drawinContext called @ 60fps but view update graphics @ 1fps

I am trying to implement a graph drawing view in OSX using Cocoa and Quartz framework using NSBezierPath and add/delete data points as I go. 我正在尝试使用NSBezierPath使用Cocoa和Quartz框架在OSX中实现图形绘图视图,并在添加数据时添加/删除数据点。

Doing so in drawRect worked fine as the graph was updating frequently but then I encountered performance problem when I need to increase total datapoints/sampling rate. 当图形频繁更新时,在drawRect中这样做很好,但是当我需要增加总数据点/采样率时遇到了性能问题。

I decided to move to drawLayer: inContext: but as the function is called at 60fps, the view isn't updating the graph when the function is call and instead update at 1fps. 我决定移动到drawLayer:inContext:但由于该函数以60fps的速度调用,因此在调用函数时视图不会更新图形,而是以1fps的速度更新。

What am I doing wrong here? 我在这里做错了什么?

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
        }


    }

If your path needs to be drawn that frequently, check out CAShapeLayer, where you can just change the path property. 如果需要经常绘制路径,请查看CAShapeLayer,您可以在其中更改path属性。 That will be hardware accelerated and much faster than drawRect or drawLayer. 这将通过硬件加速,并且比drawRect或drawLayer快得多。

It is incredibly rare that you should ever call a function at 60 Hz. 非常罕见的是,您永远都不能以60 Hz的频率调用函数。 In no case should you ever try to call a drawing function at 60 Hz; 在任何情况下都不应该尝试以60 Hz的频率调用绘图函数。 that never makes sense in Cocoa. 在可可粉中从来没有任何意义。 If you really mean "at the screen refresh interval," see CADisplayLink , which is specifically built to allow you to draw at the screen refresh interval. 如果您的意思是“以屏幕刷新间隔”,请参阅CADisplayLink ,它专门用于允许您以屏幕刷新间隔进行绘制。 This may be slower than 60 Hz. 这可能比60 Hz慢。 If you try to draw exactly at 60 Hz, you can get out of sync and cause beats in your animation. 如果尝试以60 Hz的频率精确绘制,则可能会失去同步并在动画中引起节拍。 But this really only intended for things like real-time video. 但这实际上仅适用于实时视频之类的东西。 If that what you have, then this is the tool, but it doesn't really sound like it. 如果您拥有的话,那么这就是工具,但听起来并不是真的。

It's a bit difficult to understand your code. 理解您的代码有点困难。 It's not clear where your 60fps comes in. But I'm assuming what you're trying to do is animate drawing the graph. 目前尚不清楚60fps的输入位置。但是我假设您要尝试制作的动画是绘制图形。 If so, as Mark F notes, see CAShapeLayer. 如果是这样,如Mark F所述,请参阅CAShapeLayer。 It has automatic path animations built-in, and is definitely what you want. 它内置了自动路径动画,绝对是您想要的。 It automatically handles timings and syncing with the screen refresh and GPU optimizations, and lots of other things that you shouldn't try to work around. 它会自动处理时间并与屏幕刷新和GPU优化同步,以及许多其他您不应尝试解决的问题。

Even if CAShapeLayer isn't what you want, you should be looking at Core Animation, which is designed to work with you to animate values and redraw as necessary. 即使CAShapeLayer不是您想要的,您也应该查看Core Animation,该动画旨在与您一起制作值的动画并根据需要重新绘制。 It automatically will handle rendering your layer on multiple cores for instance, which will dramatically improve performance. 例如,它将自动处理在多个核心上渲染图层的操作,这将大大提高性能。 For more on that, see Animating Custom Layer Properties . 有关更多信息,请参见动画自定义图层属性

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM