我确实有一个Metal渲染管道设置,该设置对渲染命令进行编码,并在texture: MTLTexture
对象上进行操作以加载和存储输出。这个texture
很大,并且每个渲染命令只对整个纹理的一小部分起作用。基本设置大致如下:
// texture: MTLTexture, pipelineState: MTLRenderPipelineState, commandBuffer: MTLCommandBuffer
// create and setup MTLRenderPassDescriptor with loadAction = .load
let renderPassDescriptor = MTLRenderPassDescriptor()
if let attachment = self.renderPassDescriptor?.colorAttachments[0] {
attachment.clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0)
attachment.texture = texture // texture size is rather large
attachment.loadAction = .load
attachment.storeAction = .store
}
// create MTLRenderCommandEncoder
guard let renderCommandEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) else { return }
// limit rendering to small fraction of texture
let scissorRect = CGRect(origin: CGPoint.zero, size: 0.1 * CGSize(width: CGFloat(texture.width), height: CGFloat(texture.height))) // create rect begin small fraction of texture rect
let metalScissorRect = MTLScissorRect(x: Int(scissorRect.origin.x), y: Int(scissorRect.origin.y), width: Int(scissorRect.width), height: Int(scissorRect.height))
renderCommandEncoder.setScissorRect(metalScissorRect)
renderCommandEncoder.setRenderPipelineState(pipelineState)
renderCommandEncoder.setScissorRect(metalScissorRect)
// encode some commands here
renderCommandEncoder.endEncoding()
在实践中,会创建许多renderCommandEncoder
对象,每次仅对纹理的一小部分进行操作。 不幸的是,每次提交renderCommandEncoder
时,整个纹理都会被加载并存储在末尾,renderPassDescriptor
由于其colorAttachment {{ 1}}和loadAction
。
我的问题是:
是否可以将加载和存储过程限制在storeAction
的区域?(为了避免浪费计算时间,当仅存储一小部分纹理时,加载和存储大部分纹理需要)
答案 0 :(得分:0)
以下一种避免将整个纹理加载和存储到渲染管线中的方法,假设您的剪刀矩形在两次绘制调用之间是恒定的:
将(MLBlitCommandEncoder)感兴趣的区域从大纹理扩展到较小的(例如,剪刀矩形的大小)中间纹理。
仅在较小的中间纹理上加载和存储以及绘制/操作。
完成编码后,将结果反白到较大纹理的原始源区域。
通过这种方式,您仅在管道中加载和存储感兴趣的区域,而仅增加了保持较小中间纹理的恒定内存成本(假设感兴趣区域在两次调用之间是恒定的)。
Blitting是一种快速操作,因此上述方法应该可以优化您当前的管道。