I'm trying to get multisampling working with MTKView
. I have an MTKView
with a delegate. I set the view's sampleCount
property to 4. I create a pipeline state descriptor with the rasterSampleCount
set to 4, and use that to make a render pipeline state that I use when rendering.
In the delegate's draw(in:)
method, I create a render pass descriptor by getting the view's current render pass descriptor and setting the storeAction
to multisampleResolve
. I've also set tried storeAndMultisampleResolve
to no avail.
I have created a resolve texture for the render pass descriptor, and it is the same width and height as the view and the same pixel format.
Given the above, I get a full red frame during rendering. I have used the metal debugger to look at the textures, and both the view's texture and the resolve texture have the correct rendering in them. I'm on an AMD machine where a fully red texture often indicates an uninitialized texture.
Is there anything I need to do to get the rendering to go to the screen?
Here's how I'm setting up the view, pipeline state, and resolve texture:
metalView = newMetalView
metalView.sampleCount = 4
metalView.clearColor = MTLClearColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
device = newMetalView.device!
let metalLibrary = device.makeDefaultLibrary()!
let vertexFunction = metalLibrary.makeFunction(name: "vertexShader")
let fragmentFunction = metalLibrary.makeFunction(name: "fragmentShader")
let pipelineStateDescriptor = MTLRenderPipelineDescriptor.init()
pipelineStateDescriptor.label = "Particle Renderer"
pipelineStateDescriptor.vertexFunction = vertexFunction
pipelineStateDescriptor.fragmentFunction = fragmentFunction
pipelineStateDescriptor.colorAttachments [ 0 ].pixelFormat = metalView.colorPixelFormat
pipelineStateDescriptor.rasterSampleCount = 4
do {
try pipelineState = device.makeRenderPipelineState(descriptor: pipelineStateDescriptor)
} catch {
NSLog("Unable to create pipeline state")
pipelineState = nil
}
let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: metalView.colorPixelFormat, width: Int(metalView.bounds.width), height: Int(metalView.bounds.height), mipmapped: false)
resolveTexture = device.makeTexture(descriptor: textureDescriptor)!
And here's how I'm drawing:
let commandBuffer = commandQueue.makeCommandBuffer()
commandBuffer?.label = "Partcle Command Buffer"
let renderPassDescriptor = metalView.currentRenderPassDescriptor
renderPassDescriptor?.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0)
renderPassDescriptor?.colorAttachments[0].loadAction = MTLLoadAction.clear
renderPassDescriptor?.colorAttachments[0].storeAction = MTLStoreAction.multisampleResolve
renderPassDescriptor?.colorAttachments[0].resolveTexture = resolveTexture
let renderEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: renderPassDescriptor!)
renderEncoder?.label = "Particle Render Encoder"
renderEncoder?.setViewport(MTLViewport(originX: 0.0, originY: 0.0, width: Double(viewportSize.x), height: Double(viewportSize.y), znear: -1.0, zfar: 1.0))
renderEncoder?.setRenderPipelineState(pipelineState!);
Then I make my draw calls, and then finish up by calling:
renderEncoder?.endEncoding()
commandBuffer?.present(metalView.currentDrawable!)
commandBuffer?.commit()
Here's what the debugger shows is in my textures:
Oddly, while doing that debugging, I accidentally hid Xcode, and for 1 frame, the view showed the correct texture.
What's the initial configuration of renderPassDescriptor
(as returned from metalView.currentRenderPassDescriptor
?
I believe you want the color attachment's texture
set to metalView.multisampleColorTexture
and its resolveTexture
set to metalView.currentDrawable.texture
. That is, it should do the primary, multi-sampled rendering to the multi-sample texture and then that gets resolved to the drawable texture to actually draw it in the view.
I don't know if MTKView
sets up its currentRenderPassDescriptor
like that automatically when there's a sampleCount
> 1. Ideally, it would.