Swift 如何从背景线程向CametLayer渲染CIImage
应该可以从背景线程渲染到CametLayer,如下所示。注意,我已经注释掉了Swift 如何从背景线程向CametLayer渲染CIImage,swift,macos,core-image,cametallayer,Swift,Macos,Core Image,Cametallayer,应该可以从背景线程渲染到CametLayer,如下所示。注意,我已经注释掉了DispatchQueue.global.async{},因为它生成了一个SwiftUI错误,因为更新必须来自主线程 如果没有,那么什么是正确/最好的方法来避免阻塞UI线程?如果可能的话。我想在用户拖动调整滑块时进行渲染,但如果图像大小太大,UI会变得不稳定,这似乎会影响性能 不知何故,Pixelmator Pro似乎实现了一种方法,允许对图像进行调整,而不会出现明显的UI延迟或结巴。如有任何建议,将不胜感激 func
DispatchQueue.global.async{}
,因为它生成了一个SwiftUI错误,因为更新必须来自主线程
如果没有,那么什么是正确/最好的方法来避免阻塞UI线程?如果可能的话。我想在用户拖动调整滑块时进行渲染,但如果图像大小太大,UI会变得不稳定,这似乎会影响性能
不知何故,Pixelmator Pro似乎实现了一种方法,允许对图像进行调整,而不会出现明显的UI延迟或结巴。如有任何建议,将不胜感激
func display(_ layer: CALayer) {
// DispatchQueue.global(qos: .userInitiated).async {
if let drawable = self.metalLayer.nextDrawable(),
let commandBuffer = self.commandQueue.makeCommandBuffer() {
let colorAttachment = self.passDescriptor.colorAttachments[0]!
colorAttachment.texture = drawable.texture
colorAttachment.loadAction = .clear
colorAttachment.storeAction = .dontCare
colorAttachment.clearColor = MTLClearColor(red: 0, green: 0, blue: 0, alpha: 0)
if let rawFilter = self.rawFilter {
// Required in order to clear the screen if no selection
let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: self.passDescriptor)!
renderEncoder.endEncoding()
if let processed = self.process(rawFilter) {
let x = self.size.width/2 - processed.extent.width/2
let y = self.size.height/2 - processed.extent.height/2
self.context.render(processed,
to: drawable.texture,
commandBuffer: commandBuffer,
bounds: CGRect(x:-x, y:-y, width: self.size.width, height: self.size.height),
colorSpace: self.colorSpace)
}
}
else {
// Required in order to clear the screen if no selection
let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: self.passDescriptor)!
renderEncoder.endEncoding()
}
commandBuffer.commit()
commandBuffer.waitUntilScheduled()
drawable.present()
// }
}
}
好的,我刚刚找到了解决方案不起作用的原因——我在process()函数中创建了一个图像直方图,并设置了一个UI控件图像——这只需要包装在DispatchQueue.main.async{}调用中 为了防止响应滑块移动的调用过多,除非渲染周期已完成,否则不要调用此选项
var isBusy = false
func display(_ layer: CALayer) {
guard !self.isBusy else {
return
}
self.isBusy = true
DispatchQueue.global(qos: .userInitiated).async {
if let drawable = self.metalLayer.nextDrawable(),
let commandBuffer = self.commandQueue.makeCommandBuffer() {
let colorAttachment = self.passDescriptor.colorAttachments[0]!
colorAttachment.texture = drawable.texture
colorAttachment.loadAction = .clear
colorAttachment.storeAction = .dontCare
colorAttachment.clearColor = MTLClearColor(red: 0, green: 0, blue: 0, alpha: 0)
if let rawFilter = self.rawFilter {
// Required in order to clear the screen if no selection
let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: self.passDescriptor)!
renderEncoder.endEncoding()
if let processed = self.process(rawFilter) {
let x = self.size.width/2 - processed.extent.width/2
let y = self.size.height/2 - processed.extent.height/2
self.context.render(processed,
to: drawable.texture,
commandBuffer: commandBuffer,
bounds: CGRect(x:-x, y:-y, width: self.size.width, height: self.size.height),
colorSpace: self.colorSpace)
}
}
else {
// Required in order to clear the screen if no selection
let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: self.passDescriptor)!
renderEncoder.endEncoding()
}
commandBuffer.commit()
commandBuffer.waitUntilScheduled()
// Present on the main thread - not sure if this is necessary but it seems like it to get the UI to update
DispatchQueue.main.async {
drawable.present()
}
self.isBusy = false
}
}
}