Metal:将 MTLRenderCommandEncoder 纹理加载限制为仅部分纹理 [英] Metal: limit MTLRenderCommandEncoder texture loading to only part of texture
问题描述
我确实有一个 Metal 渲染管道设置,它对渲染命令进行编码并对 texture: MTLTexture
对象进行操作以加载和存储输出.这个纹理
相当大,并且每个渲染命令只对整个纹理的一小部分进行操作.基本设置大致如下:
I do have a Metal rendering pipeline setup which encodes render commands and operates on a texture: MTLTexture
object to load and store the output. This texture
is rather large and and each render command just operates on a small fraction of the whole texture. The basic setup is roughly the following:
// 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 loadAction
和 storeAction
.
In practice many renderCommandEncoder
objects are created, each time just operating on a small fraction of the texture. Unfortunately, each time a renderCommandEncoder
is commited the whole texture is loaded and stored at the end, which is specified by the renderPassDescriptor
due to the corresponding setting of its colorAttachment loadAction
and storeAction
.
我的问题是:
是否可以将加载和存储过程限制在 texture
的一个区域内?(为了避免在加载和存储大量纹理时浪费计算时间,当只有一个需要一小部分)
My Question is:
Is it possible to limit the load and store process to a region of texture
? (in order to avoid wasting computation time for loading and storing huge parts of the texture when only a small part is needed)
推荐答案
一种避免将整个纹理加载和存储到渲染管道中的方法,可以是以下方法,假设您的剪刀矩形在绘制调用之间保持不变:
One approach, to avoid loading and storing the entire texture into the render pipeline, could be the following, assuming your scissor rectangle is constant between drawcalls:
Blit (MTLBlitCommandEncoder) 从大纹理到较小(例如剪刀矩形的大小)中间纹理的感兴趣区域.
Blit (MTLBlitCommandEncoder) the region of interest from the large texture to a smaller(e.g. the size of your scissor rectangle) intermediate texture.
仅在较小的中间纹理上加载和存储以及绘制/操作.
Load and store, and draw/operate only on the smaller intermediate texture.
完成编码后,将结果返回到较大纹理的原始源区域.
When done encoding, blit back the result to the original source region of the larger texture.
通过这种方式,您只加载和存储管道中的感兴趣区域,只会增加维持较小中间纹理的恒定内存成本(假设感兴趣区域在两次绘制调用之间保持不变).
This way you load and store only the region of interest in your pipeline, with only the added constant memory cost of maintaining a smaller intermediate texture(assuming region of interest is constant between drawcalls).
Blitting 是一种快速操作,因此上述方法应该可以优化您当前的管道.
这篇关于Metal:将 MTLRenderCommandEncoder 纹理加载限制为仅部分纹理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!