2

我是 macOS 开发的新手。

目前我正在NSOpenGLView使用第三方库实现一个。

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

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

演示截图: 截屏

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.inLiveResizevideoView.drawRect()如果为真则停止调用。调整大小时,会自动调用 draw() 函数。这种方法可以很好地调整大小,但是当暂停拖动时,由于 LiveResize 事件未完成,视图将冻结。
func update() {
  if !(videoView.window!.inLiveResize) {
    videoView.glQueue.async {
      videoView.drawRect()
    }
  }
}

我终于设法找到了一个解决方法,但它仍然不完美,我确信这不是正确的方向。

请建议我是否以正确的方式执行此操作,或者在不阻塞 UI 的情况下进行绘图的更好解决方案/最佳实践。谢谢!

4

0 回答 0