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()
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
.
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) 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 is a fast operation and the above method should thus optimize your current pipeline.