Metal 框架之 MTKView

「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

概述

MTKView 封装了 Metal 的基本功能,隐藏了配置 Metal 的一些操作,省去了开发者配置的麻烦,开发者只需要将精力花费在图形渲染即数据准备上就可以。

在 iOS, iPadOS, Mac Catalyst, tvOS中,代码定义如下:


class MTKView : UIView 

复制代码

在 macOS 中定义如下:


class MTKView : NSView

复制代码

MTKView 使用 CAMetalLayer 来管理 Metal 可绘制对象,通过 MTLRenderPassDescriptor 对象可以将内容渲染到一个纹理中。

此外,通过 MTKView 可以创建深度和模板纹理以及抗锯齿所需的任何中间纹理。该视图使用 CAMetalLayer 来管理 Metal 可绘制对象。

指定绘制模式

MTKView 支持三种绘制模式:

  • 定时更新:视图根据内部计时器重绘其内容。默认情况下使用这个绘制方式,初始化时需要将 isPaused 和 enableSetNeedsDisplay 都设置为 false。游戏和更新的动画内容常用这种模式。

  • 绘制通知:当调用 setNeedsDisplay() 或者 当某些内容使其内容无效时,视图会重绘自身。在这种情况下,将 isPaused 和 enableSetNeedsDisplay 设置为 true。这种模式适用于具有更传统工作流程的应用程序,更新只会在数据更改时发生,而不会定期更新。

  • 显式绘制:当显式调用 draw() 方法时,视图才会重绘其内容。这种模式下,需要将 isPaused 设置为 true 并将 enableSetNeedsDisplay 设置为 false。一般使用此模式来创建自定义工作流程。

绘制

无论使用哪一种绘图模式,当视图需要更新其内容时,在子类重写 draw(:) 方法时,它会调用 draw(:) 方法,否则在视图的委托上调用 draw(in:) 方法。

在绘图方法中,从视图中获取渲染通道描述符,此后的渲染结果都会存在渲染通道描述符中,最后渲染结果呈现在其关联的可绘制对象上。

从 MetalKit 视图中获取可绘制对

CAMetalLayer 提供 MTKView 视图的绘图能力。在渲染器过程中,需要实现 MTKViewDelegate 协议来实现与 MetalKit 视图交互。调用 MetalKit 视图的 currentRenderPassDescriptor 属性可以获取当前帧的渲染通道描述符:


// BEGIN encoding your onscreen render pass.

// Obtain a render pass descriptor generated from the drawable's texture.

// (`currentRenderPassDescriptor` implicitly obtains the current drawable.)

// If there's a valid render pass descriptor, use it to render to the current drawable.

if let onscreenDescriptor = view.currentRenderPassDescriptor

复制代码

当读取currentRenderPassDescriptor属性时,Core Animation 会隐式获取当前帧的可绘制对象并将其存储在 currentDrawable 属性中。后续深度、模板和抗锯齿纹理会被绘制到 currentDrawable 对象中。视图使用默认的存储和加载操作配置此渲染通道,在创建 MTLRenderCommandEncoder 之前,可以调整描述符。为了提升渲染性能,应该尽可能晚地获取可绘制对象,最好是在编码屏幕渲染通道之前。

关联可绘制对象

在渲染内容后,需要将可绘制对象的结果更新到视图中来显示。展示内容最方便的方法是调用命令缓冲区上的 present(:) 方法将视图与命令缓冲区关联起来,然后调用 commit() 方法将命令缓冲区提交给 GPU:*

if let onscreenDescriptor = view.currentRenderPassDescriptor,

let onscreenCommandEncoder = onscreenCommandBuffer.makeRenderCommandEncoder(descriptor: onscreenDescriptor) {

    /* Set render state and resources.

       ...

     */

    /* Issue draw calls.

       ...

     */

    onscreenCommandEncoder.endEncoding()

    // END encoding your onscreen render pass.

    

    // Register the drawable's presentation.

    if let currentDrawable = view.currentDrawable {

        onscreenCommandBuffer.present(currentDrawable)

    }

}


// Finalize your onscreen CPU work and commit the command buffer to a GPU.

onscreenCommandBuffer.commit()

复制代码

当命令队列调度可执行的命令缓冲区时,可绘制对象会在该命令缓冲区中遍历其自身的所有渲染或写入请求。在命令完成执行之前,操作系统不会在屏幕上显示可绘制对象。通过这种调度方式,保证了命令队列调度此命令缓冲区之后才显示渲染结果。

总结

本文介绍了如何使用 MTKView 来创建、配置和展示 Metal 对象。讲解了 MTKView 使用的每个步骤,阅读完本文可以对 MTKView 绘制流程有个基本了解。

猜你喜欢

转载自juejin.im/post/7030741059999121439