我是 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.inLiveResize
,videoView.drawRect()
如果为真则停止调用。调整大小时,会自动调用 draw() 函数。这种方法可以很好地调整大小,但是当暂停拖动时,由于 LiveResize 事件未完成,视图将冻结。
func update() {
if !(videoView.window!.inLiveResize) {
videoView.glQueue.async {
videoView.drawRect()
}
}
}
我终于设法找到了一个解决方法,但它仍然不完美,我确信这不是正确的方向。
请建议我是否以正确的方式执行此操作,或者在不阻塞 UI 的情况下进行绘图的更好解决方案/最佳实践。谢谢!