Search code examples
iosswiftmetalmetalkit

Off screen Rendering With Multisampling


I am drawing a quad and adding texture to it and drawing small quad and adding textures. When the sample count is 4 I got following error when small quad is added. when the sample count is one is it is working fine.

Execution of the command buffer was aborted due to an error during execution. Ignored (for causing prior/excessive GPU errors) (IOAF code 4)

How can i use sample count 4

guard let drawable = view.currentDrawable else { return }

let textureDescriptor = MTLTextureDescriptor()

textureDescriptor.textureType = MTLTextureType.type2DMultisample
textureDescriptor.width = drawable.texture.width
textureDescriptor.height = drawable.texture.height
textureDescriptor.pixelFormat = .bgra8Unorm
textureDescriptor.storageMode = .shared
 textureDescriptor.sampleCount = 4

textureDescriptor.usage = [.renderTarget, .shaderRead]
let sampleTexture = device.makeTexture(descriptor: textureDescriptor)


let renderPass = MTLRenderPassDescriptor()
renderPass.colorAttachments[0].texture = sampleTexture
renderPass.colorAttachments[0].resolveTexture = outTexture
renderPass.colorAttachments[0].loadAction = .clear
renderPass.colorAttachments[0].clearColor =
    MTLClearColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
 renderPass.colorAttachments[0].storeAction = .multisampleResolve

let commandBuffer = commandQueue.makeCommandBuffer()

let semaphore = inFlightSemaphore

commandBuffer?.addCompletedHandler { (_ commandBuffer)-> Swift.Void in
        semaphore.signal()
}

var commandEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: renderPass)

for scene in scenes {
    scene.render(commandEncoder: commandEncoder!)
}

commandEncoder?.endEncoding()


let descriptor = view.currentRenderPassDescriptor
commandEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: descriptor!)



for x in canvasScenes{
    x.updateCanvas(texture: sampleTexture!)
    x.render(commandEncoder: commandEncoder!)
}

commandEncoder?.endEncoding()


commandBuffer?.present(drawable)
commandBuffer?.commit()
commandBuffer?.waitUntilCompleted()

Solution

  • That's my setup for offscreen rendering with multisampling. I use also depth texture. Here is written small description about multisampling https://developer.apple.com/documentation/metal/mtlrenderpassattachmentdescriptor?language=objc

        let offscreenTextureDescriptor = MTLTextureDescriptor()
        offscreenTextureDescriptor.width = size.width
        offscreenTextureDescriptor.height = size.height
        offscreenTextureDescriptor.depth = size.depth
        offscreenTextureDescriptor.pixelFormat = RenderPixelFormat.offscreen.rawValue.mtlPixelFormat()
        offscreenTextureDescriptor.textureType = .type2DMultisample
        offscreenTextureDescriptor.storageMode = .shared
        offscreenTextureDescriptor.usage = [.renderTarget, .shaderRead, .shaderWrite, .pixelFormatView]
        offscreenTextureDescriptor.sampleCount = 4
    
        self.offScreenTexture = device.makeTexture(descriptor: offscreenTextureDescriptor)
    
        offscreenTextureDescriptor.textureType = .type2D
        offscreenTextureDescriptor.sampleCount = 1
        offscreenTextureDescriptor.usage = [.shaderWrite]
    
        self.resolveOffScreenTexture = device.makeTexture(descriptor: offscreenTextureDescriptor)
    
        let depthTextureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .depth32Float, width: self.offScreenTexture.width, height: self.offScreenTexture.height, mipmapped: false)
        depthTextureDescriptor.usage = [.renderTarget, .shaderRead, .shaderWrite, .pixelFormatView]
        depthTextureDescriptor.textureType = .type2DMultisample
        depthTextureDescriptor.storageMode = .private
        depthTextureDescriptor.resourceOptions = [.storageModePrivate]
        depthTextureDescriptor.sampleCount = 4
    
        let depthAttachementTexureDescriptor = MTLRenderPassDepthAttachmentDescriptor()
        depthAttachementTexureDescriptor.clearDepth = 1.0
        depthAttachementTexureDescriptor.loadAction = .clear
        depthAttachementTexureDescriptor.storeAction = .store
        depthAttachementTexureDescriptor.texture = device.makeTexture(descriptor: depthTextureDescriptor)
    
        let renderPassDescriptor = MTLRenderPassDescriptor()
        renderPassDescriptor.colorAttachments[0].texture = self.offScreenTexture
        renderPassDescriptor.colorAttachments[0].resolveTexture = self.resolveOffScreenTexture
        renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 1)
        renderPassDescriptor.colorAttachments[0].loadAction = .clear
        renderPassDescriptor.colorAttachments[0].storeAction = .multisampleResolve
        renderPassDescriptor.depthAttachment = depthAttachementTexureDescriptor
        self.renderPassDescriptor = renderPassDescriptor