如何在 MTKView 中使用多重采样?

Posted

技术标签:

【中文标题】如何在 MTKView 中使用多重采样?【英文标题】:How to use multisampling with an MTKView? 【发布时间】:2019-03-21 15:05:57 【问题描述】:

我正在尝试使用MTKView 进行多重采样。我有一个MTKView 和一个代表。我将视图的 sampleCount 属性设置为 4。我创建了一个管道状态描述符,并将 rasterSampleCount 设置为 4,并使用它来创建渲染时使用的渲染管道状态。

在委托的draw(in:) 方法中,我通过获取视图的当前渲染通道描述符并将storeAction 设置为multisampleResolve 来创建渲染通道描述符。我也设置了尝试storeAndMultisampleResolve 无济于事。

我已经为渲染通道描述符创建了一个解析纹理,它与视图具有相同的宽度和高度以及相同的像素格式。

鉴于上述情况,我在渲染过程中得到一个完整的红框。我已经使用金属调试器来查看纹理,并且视图的纹理和解析纹理都具有正确的渲染。我在 AMD 机器上,其中完全红色的纹理通常表示未初始化的纹理。

我需要做些什么才能让渲染显示到屏幕上吗?

以下是我设置视图、管道状态和解析纹理的方式:

    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)!

我是这样画的:

    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!);

然后我进行绘制调用,然后调用结束:

    renderEncoder?.endEncoding()
    commandBuffer?.present(metalView.currentDrawable!)
    commandBuffer?.commit()

这是调试器在我的纹理中显示的内容:

奇怪的是,在进行调试时,我不小心隐藏了 Xcode,并且在 1 帧内,视图显示了正确的纹理。

【问题讨论】:

【参考方案1】:

renderPassDescriptor 的初始配置是什么(从metalView.currentRenderPassDescriptor 返回?

我相信您希望将颜色附件的texture 设置为metalView.multisampleColorTexture,并将其resolveTexture 设置为metalView.currentDrawable.texture。也就是说,它应该对多采样纹理进行主要的多采样渲染,然后将其解析为可绘制纹理以在视图中实际绘制它。

我不知道当sampleCount > 1 时,MTKView 是否会自动设置它的currentRenderPassDescriptor。理想情况下会这样。

【讨论】:

做到了!太感谢了!它没有自动设置这些东西似乎很奇怪。可能值得一个错误报告。我目前无法发放赏金,但会在几个小时后发放。 谢谢肯!您配置 renderPassDescriptor 的方式修复了我在 MetalView 中遇到的错误 [失败的断言 `MTLRenderPassDescriptor MTLStoreActionMultisampleResolve 存储操作需要解析纹理']。

以上是关于如何在 MTKView 中使用多重采样?的主要内容,如果未能解决你的问题,请参考以下文章

Python常用的几种去重方法

在具有多重采样的 QGLFramebufferObject 中使用 sRGB 颜色

ImGui 多重采样

如何使用音频重采样器对 IF 信号进行重采样

激活多重采样(Windows)时如何防止空的OpenGL窗口?

Metal(iOS)中的多重采样/锯齿状边缘