Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/110.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios MTKView绘图性能 我想做什么_Ios_Swift_Xcode_Metal_Metal Performance Shaders - Fatal编程技术网

Ios MTKView绘图性能 我想做什么

Ios MTKView绘图性能 我想做什么,ios,swift,xcode,metal,metal-performance-shaders,Ios,Swift,Xcode,Metal,Metal Performance Shaders,我正在尝试使用金属视图在摄影机提要上显示过滤器:MTKView。我正在密切关注苹果公司的示例代码——利用TrueDepth摄像头数据增强实时视频() 到目前为止我所拥有的 以下代码非常有用(主要从上述示例代码中解释): 注释 之所以使用MTKViewDelegate而不是子类化MTKView是因为当它被子类化时,在主线程上调用了draw调用。对于上面所示的委托方法,似乎每个循环都有一个不同的金属相关线程调用。上述方法似乎提供了更好的性能 关于上述更新方法的CIFilter用法的详细信息必须进行

我正在尝试使用金属视图在摄影机提要上显示过滤器:
MTKView
。我正在密切关注苹果公司的示例代码——利用TrueDepth摄像头数据增强实时视频()

到目前为止我所拥有的 以下代码非常有用(主要从上述示例代码中解释):

注释

  • 之所以使用
    MTKViewDelegate
    而不是子类化
    MTKView
    是因为当它被子类化时,在主线程上调用了draw调用。对于上面所示的委托方法,似乎每个循环都有一个不同的金属相关线程调用。上述方法似乎提供了更好的性能
  • 关于上述更新方法的
    CIFilter
    用法的详细信息必须进行编辑。所有这一切都是一条沉重的过滤链。不幸的是,这些过滤器没有任何调整的余地
问题 上面的代码似乎大大降低了主线程的速度,导致应用程序UI的其余部分变得不稳定。例如,滚动
UIScrollview
gets看起来很慢,而且不稳定

目标 调整Metal视图以减轻CPU的负担,并在主线程上轻松处理,为UI的其余部分留下足够的资源

根据上面的图形,命令缓冲区的准备都是在CPU中完成的,直到出现并提交(?)。有没有办法把它从CPU上卸下来

任何提示,反馈,提示等,以提高绘图效率将不胜感激

您可以做以下几件事来提高性能:

  • 直接渲染到视图的可绘制视图中,而不是渲染到纹理中,然后再次渲染以将该纹理渲染到视图中
  • 使用最新的
    CIRenderDestination
    API将实际纹理检索延迟到视图实际渲染到的时刻(即核心图像完成时)
这是我在核心图像项目中使用的
绘图(视图:MTKView)
,针对您的情况进行了修改:

public func draw(in view: MTKView) {
    if let currentDrawable = view.currentDrawable,
        let commandBuffer = self.commandQueue.makeCommandBuffer() {
        let drawableSize = view.drawableSize

        // optional: scale the image to fit the view
        let scaleX = drawableSize.width / image.extent.width
        let scaleY = drawableSize.height / image.extent.height
        let scale = min(scaleX, scaleY)
        let scaledImage = previewImage.transformed(by: CGAffineTransform(scaleX: scale, y: scale))

        // optional: center in the view
        let originX = max(drawableSize.width - scaledImage.extent.size.width, 0) / 2
        let originY = max(drawableSize.height - scaledImage.extent.size.height, 0) / 2
        let centeredImage = scaledImage.transformed(by: CGAffineTransform(translationX: originX, y: originY))

        // create a render destination that allows to lazily fetch the target texture
        // which allows the encoder to process all CI commands _before_ the texture is actually available;
        // this gives a nice speed boost because the CPU doesn’t need to wait for the GPU to finish
        // before starting to encode the next frame
        let destination = CIRenderDestination(width: Int(drawableSize.width),
                                              height: Int(drawableSize.height),
                                              pixelFormat: view.colorPixelFormat,
                                              commandBuffer: commandBuffer,
                                              mtlTextureProvider: { () -> MTLTexture in
                                                return currentDrawable.texture
        })

        let task = try! self.context.startTask(toRender: centeredImage, to: destination)
        // bonus: you can Quick Look the task to see what’s actually scheduled for the GPU

        commandBuffer.present(currentDrawable)
        commandBuffer.commit()

        // optional: you can wait for the task execution and Quick Look the info object to get insights and metrics
        DispatchQueue.global(qos: .background).async {
            let info = try! task.waitUntilCompleted()
        }
    }
}

如果这仍然太慢,您可以尝试在创建
CIContext
时设置
priorityRequestLow
cicontextext
以告知核心图像以低优先级渲染。

正确的做法是使用仪器进行测量。也就是说,有两个明显的问题:在每次绘制时都创建纹理。相反,您应该在开始时创建一个小的纹理池,为每个绘制抓取一个,并在命令缓冲区完成后将其返回到该池。同样,不应在每次绘制时创建队列。您通常应该在应用程序设置中创建一个队列,并在整个过程中使用它。由于要手动(从后台线程)调用
draw()
,因此不要设置
enableSetNeedsDisplay
。似乎不需要清除
framebufferOnly
。对于队列,我创建
self.metalCommandQueue=self.metalDevice!。初始化时生成命令队列()
。那是不对的?哦,你是对的。对不起,我看错了。我被你使用
guard
的行为愚弄了,可能会报告你无法在draw方法中创建队列。因此对于最简单的设置:framebufferOnly=true和enableSetNeedsDisplay=false?是的,但纹理创建可能是一个更大的因素。这提高了FPS!但是,它似乎仍然会降低主线程/CPU的速度,从而导致UI其余部分的运行缓慢。在绘图调用之前,是否可以在update()中完成这些工作?请注意,您的UI绘图也在GPU上进行。因此,当GPU太忙时,UI将挂起。在
update()
draw()
中执行实际的核心图像渲染并不重要。您可以降低捕获设备的FPS,这样系统就不会被无法处理的帧淹没。还可以使用
self.metalBufferView?.setNeedsDisplay()
而不是
.draw()
来允许UIKit在适当的时候绘制视图。如果过滤器在draw()之外运行,它们是否应该运行?或者内部会提供更好的性能?这无关紧要,因为在实际调用
CIContext
的一个相关绘图函数之前,
CIFilter
永远不会运行(
startTask(本例中为toRender:to:)
),这需要在
draw()内部进行
@Gizmodo您是否尝试过在上下文中设置
priorityRequestLow
public func draw(in view: MTKView) {
    if let currentDrawable = view.currentDrawable,
        let commandBuffer = self.commandQueue.makeCommandBuffer() {
        let drawableSize = view.drawableSize

        // optional: scale the image to fit the view
        let scaleX = drawableSize.width / image.extent.width
        let scaleY = drawableSize.height / image.extent.height
        let scale = min(scaleX, scaleY)
        let scaledImage = previewImage.transformed(by: CGAffineTransform(scaleX: scale, y: scale))

        // optional: center in the view
        let originX = max(drawableSize.width - scaledImage.extent.size.width, 0) / 2
        let originY = max(drawableSize.height - scaledImage.extent.size.height, 0) / 2
        let centeredImage = scaledImage.transformed(by: CGAffineTransform(translationX: originX, y: originY))

        // create a render destination that allows to lazily fetch the target texture
        // which allows the encoder to process all CI commands _before_ the texture is actually available;
        // this gives a nice speed boost because the CPU doesn’t need to wait for the GPU to finish
        // before starting to encode the next frame
        let destination = CIRenderDestination(width: Int(drawableSize.width),
                                              height: Int(drawableSize.height),
                                              pixelFormat: view.colorPixelFormat,
                                              commandBuffer: commandBuffer,
                                              mtlTextureProvider: { () -> MTLTexture in
                                                return currentDrawable.texture
        })

        let task = try! self.context.startTask(toRender: centeredImage, to: destination)
        // bonus: you can Quick Look the task to see what’s actually scheduled for the GPU

        commandBuffer.present(currentDrawable)
        commandBuffer.commit()

        // optional: you can wait for the task execution and Quick Look the info object to get insights and metrics
        DispatchQueue.global(qos: .background).async {
            let info = try! task.waitUntilCompleted()
        }
    }
}