NSOpenGLView:在不同的线程中绘制,在实时调整大小时出现毛刺/闪烁

时间:2016-07-11 18:34:20

标签: swift macos cocoa opengl nsopenglview

我是macOS开发的新手。

目前,我正在使用第三方库实施NSOpenGLView

  • update函数是来自库的回调函数,将在新帧到达时调用。由于预计会立即返回,因此应该异步调用绘图。
  • 我试图在这里使用DispatchQueue.main.async()但是我发现它会阻止主线程,例如调整容器窗口大小时不会有动画。所以我创建了一个用于绘图的调度队列。
  • 现在调整大小非常顺利,但在调整大小时,视图会出现毛刺。我认为原因应该是从不同的线程中提取(当调整大小时,视图也从主线程重新绘制),但是我不确定具体的原因。
  • 仅在窗口限制正在改变时发生毛刺。调整大小期间,如果停止拖动一段时间,则不会出现毛刺。

(更新:仅在启用双缓冲时才会出现问题)

演示截图: screenshot

func update() {
  videoView.glQueue.async {
    videoView.drawRect()
  }
}

class VideoView: NSOpenGLView {

  lazy var glQueue: DispatchQueue = DispatchQueue(label: "gl", attributes: .serial)

  override func draw(_ dirtyRect: NSRect) {
    self.drawRect()
  }

  func drawRect() {
    openGLContext?.lock()
    openGLContext?.makeCurrentContext()
    doDrawing()
    openGLContext?.flushBuffer()
    openGLContext?.unlock()
  }
} 

我尝试了几种解决方案。

  • 主队列中的videoView.drawRect()调用将完全阻止调整大小。
  • 添加锁定到update()draw()将消除故障,但UI线程仍然非常慢,并且调整大小不稳定。
class VideoView: NSOpenGLView {
  override func update() {
    // lock with NSLock / lock the context
    super.update()
    // unlock
  }
}
  • 检查window.inLiveResize,如果为真则停止呼叫videoView.drawRect()。调整大小时,会自动调用draw()函数。这种方法适用于非常平滑的调整大小,但是当暂停拖动时,视图将冻结,因为LiveResize事件未完成。
func update() {
  if !(videoView.window!.inLiveResize) {
    videoView.glQueue.async {
      videoView.drawRect()
    }
  }
}

我终于找到了解决方法,但它仍然不完善,我确定它不是正确的方向。

请建议我是否以正确的方式执行此操作,或者更好地解决绘制而不阻止UI 的解决方案/最佳做法。谢谢!

0 个答案:

没有答案