Metal(一)-简述 & 主要APIMetal(一)-简述 & 主要API

2021-08-09 11:20:22 浏览数 (1)

Metal简述

Metal是苹果公2014年推出的一套取代OpenGLES的渲染应用程序编程接口,支持到iOS8以上。Metal不单延续了OpenGLES中的渲染高级3D图形,还可以使用GPU高效完成数据并行计算。 Core Image, SpriteKit, 和 SceneKit已经在使用了。

Metal优化点
  1. 最大程度的降低了CPU的相关开销
  2. 最大程度的使用GPU的性能
  3. 最大限度的提高了CPU、GPU的并行能力
  4. 最大限度的进行系统资源的有效管理
graphics pipeline(图形管道)
  • 和OpenGL中的图形管道相比相似度非常高;
  • 顶点处理:物体矩阵、世界矩阵、观察者矩阵(相当于MVP),裁剪
  • 图元装配方式:点、线、线环、三角形、三角形带
  • 片段处理:纹理、模板、透明度、混合

Cpu:处理顶点数据->GPU: 顶点处理(顶点着色器)->图元装配(5种)->光栅化->片段处理(片元着色器)->帧缓存区

OpenGl

可以对照这幅图回忆一下自己的知识结构和OpenGLES中的知识点。

在使用Metal前,Apple有一些建议
  • Separate Your Rendering Loop分开渲染循环:不希望将渲染的处理逻辑放到ViewController | View中。建议单独创建一个类来完成各种Metal的渲染绘制工作。
  • Respond to View Events响应代理<MTKViewDelegate>的事件
  • Metal Command Objects创建一个命令对象,即创建执行命令的GPU
Metal中对象之间的关系

图一

图二

两张图可以对比来看

838133-8b76a2d6479f743b.jpg

  1. 命令缓存区(command buffer) 是从命令队列列(command queue) 创建的
  2. 命令编码器器(command encoders) 将命令编码到命令缓存区中
  3. 提交命令缓存区并将其发送到GPU
  4. GPU执⾏行行命令并将结果呈现为可绘制

Metal中常见Api

MTKView

MTKView理解上可以对标GLKView来理解。 相同点: 提供用于绘制layer的专属视图。

不同点:

  1. 没有MTKViewController。
  2. GLKView初始化时需要提供GLKContent,而MTKView需要确定MTLDevice
MTLDevice

Metal是直接操作GPU的,所以需要获取GPU的使用权限。在iOS中一般是通过默认的方式MTLCreateSystemDefaultDevice()获取GPU的使用权限。也可以使用MTLCopyAllDevices()来获取系统中所有Metal设备对象的引用数组。

MTLDevice协议表示可以执行命令的GPU,提供了如下功能

  • 创建新的命令队列
  • 从内存分配缓冲区
  • 创建纹理
  • 查询设备功能
MTLCommandQueue

在获取了GPU后,还需要一个渲染队列,即命令队列Command Queue类型是MTLCommandQueue,该队列是与GPU交互的第一个对象,队列中存储的是将要渲染的命令MTLCommandBuffer。正好对应上方图。

创建方式:

代码语言:javascript复制
_commandQueue = [_device newCommandQueue];
  • 该对象的创建需要消耗大量资源,加之这个命令队列生命周期很长,所以建议该对象作为全局,而不是反复创建和消耗。
MTLCommandBuffer

命令缓存区Command Buffer主要是用于存储编码的命令,其生命周期是指导缓存区被提交到GPU执行为止,单个的命令缓存区可以包含不同的编码命令,主要取决于用于构建它的编码器的类型和数量。

创建方式:

代码语言:javascript复制
commandBuffer = [_commandQueue commandBuffer]
  • buffer的创建需要通过Command Queue来创建的
  • buffer中生成的CommandEncoder都需要通过当前buffer来进行提交、渲染、绘制.

commandBuffer在未提交命令缓存区之前,是不会开始执行的。等待提交后命令缓存区将按其按照加入队的顺序进行执行。当然这是整个编码步骤中的最后一步。 commandBuffer的执行顺序有以下两种:

  • enqueue:顺序执行,enqueue方法在命令队列中为命令缓存区保留一个位置,此时并未提交命令缓存区,当最终提交命令缓存区后,按照命令队列的顺序依次执行
  • commit:插队尽快执行,如果前面有commit还是需要排队等着
MTLRenderCommandEncoder

MTLRenderCommandEncoder表示单个渲染过程中相关联的渲染状态和渲染命令(可以对标OpenGL中的上下文状态机来理解),有以下功能:

  1. 指定图形资源,例如缓存区和纹理对象,其中包含顶点、片元、纹理图片数据
  2. 指定MTLRenderPipelineState对象,其中包含编译的渲染状态、顶点着色器、片段着色器
  3. 指定固定功能状态,包括视口,三角形填充模式,剪刀矩形,深度和模板测试以及其他值
  4. 绘制3D图元
编码器执行流程
  1. 通过调用MTLCommandBuffer对象的makeRenderCommandEncoder(descriptor :)方法来创建MTLRenderCommandEncoder对象。
  2. 调用setRenderPipelineState(_ :)方法以指定MTLRenderPipelineState,该状态定义图形渲染管道的状态,包括顶点和片段函数。
  3. 指定用于顶点和片元函数输入和输出的资源,并在对应的参数中设置每个资源的位置(即索引),即将顶点数据等通过commandEncoder调用setVertexBytes:length:atIndex:函数传递到metal shader Language文件的顶点着色器和片元着色器函数
  4. 指定其他的固定功能状态,例如通过commandEncoder调用setViewport:函数设置视口大小等
  5. 绘制图形
  6. 调用endEncoding()方法以终止渲染命令编码器。
MTLRenderPipelineDescriptor

MTLRenderPipelineDescriptor管道状态描述符:在渲染过程中使用的渲染配置状态,包括光栅化(例如多重采样),可见性,混合,镶嵌和图形功能状态,主要是渲染管道描述符中指定顶点或片段函数。

举例:

代码语言:javascript复制
    MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
        //管道名称
    pipelineStateDescriptor.label = @"Simple Pipeline";
        //可编程函数,用于处理渲染过程中的各个顶点
    pipelineStateDescriptor.vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"];
        //可编程函数,用于处理渲染过程中各个片段/片元
    pipelineStateDescriptor.fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"];
        //一组存储颜色数据的组件
    pipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat;
        //同步创建并返回渲染管线状态对象
    _pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
MTLRenderPassDescriptor

官方文档定义为渲染命令编码器描述符:用于保存渲染过程中的一组结果 下图中红圈位置代表MTLRenderPassDescriptor在Metal整个渲染流程中的位置,也可以对标OpenGLES中的frameBuffer来理解

Metal渲染流程

0 人点赞