Metal:将 MTLRenderCommandEncoder 纹理加载限制为仅部分纹理 [英] Metal: limit MTLRenderCommandEncoder texture loading to only part of texture

查看:45
本文介绍了Metal:将 MTLRenderCommandEncoder 纹理加载限制为仅部分纹理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我确实有一个 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 loadActionstoreAction.

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:

  1. Blit (MTLBlitCommandEncoder) 从大纹理到较小(例如剪刀矩形的大小)中间纹理的感兴趣区域.

  1. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆