多媒体技术图形编程框架之Metal介绍与基本概念

所属分类:ios | 发布于 2024-12-18

你敢不敢相信,就想搞一个相机App,居然研究到了Metal,也终于接触了苹果发布会上次次都要说的GPU。

背景

图形编程是多媒体技术中最重要的一块。

图标边框框架用于解决什么问题:

1、在游戏开发中,对游戏场景/游戏任务的渲染

2、在音视频开发中,对于视频解码后的数据渲染

3、在地图引擎中,对于地图数据的渲染

4、在动画中,实现动画的绘制

5、在视频处理中,视频添加滤镜效果

6、...

目前几个主流的图形处理框架:

1、DirectX:由很多API组成,是Windows上的一个多媒体处理框架,只支持Windows系统。

2、OpenGL(Open Graphics Library):一种跨平台的图像处理框架,用于开发2D和3D图形应用程序。

3、OpenGL ES(OpenGL for Embedded Systems):是OpenGL三维图形API的子集,针对手机、PDA和游戏主机等嵌入式设备而设计的,去除了许多不必要和性能较低的API接口。

4、Metal:Apple推出的新的平台技术,该技术能为3D图像提高10倍的渲染性能。在Metal之前,苹果使用OpenGL ES,在iOS12以后,弃用了OpenGL ES,转为对Metal的支持。

Metal介绍

Metal是苹果平台上图形和计算机编程的一个强大而低级的框架。它允许您充分利用GPU(图形处理单元)的性能来执行复杂的计算和渲染任务。

官方文档:https://developer.apple.com/cn/metal/

Metal的主要用例之一是图像处理,因为它允许您以高性能和低开销实时对图像和视频执行操作。

我们将介绍Metal编程的基础知识,包括主要概念和术语,以及设置开发环境的步骤。

Metal Shader(着色器)的使用

在Metal中,Shader(着色器)是一个在GPU上运行的小程序,负责执行特定任务,例如渲染3D模型或应用图像过滤器。

Metal中有三种主要类型的着色器:Vertex shaders(顶点着色器)Feagment shaders(片段着色器)Compute shaders(计算着色器)

1、Vertex shaders

Vertex shaders负责将模型的3D坐标转换为2D屏幕空间坐标。它们将一组顶点数据(如位置、法线和纹理坐标)作为输入,并将一组变换后的顶点数据作为输出。

2、Fragment shaders

Fragment shaders负责确定屏幕上每个像素的最终颜色。它们从顶点着色器中获取插值顶点数据作为输入,并为每个像素返回最终颜色作为输出。

3、Compute shaders

Compute shaders是一种更通用的着色器类型,可以在GPU上执行任何类型的计算。它们通常用于图像处理和模拟等任务。

 

利用GPU进行计算

进行GPU计算是每个Metal应用都要使用的基本任务,整个流程大致如下:

1、编写MSL函数

2、找到一个可用的GPU

3、创建pipeline

4、创建GPU可访问的数据对象

5、创建命令缓冲区,向其写入命令

6、将缓冲区提交到命令队列

1、编写一个GPU函数

如果需要在GPU上执行计算,需要使用MSL(Metal Shading Language)编写的函数。MSL是C++的一个变体,专为GPU编程而设计。在Metal中,运行在GPU上的代码被称为shader着色器。

新建一个add.metal文件,并写入如下代码:

kernel void add_arrays(device const float* inA,
                       device const float* inB,
                       device float* result,
                       uint index [[thread_position_in_grid]])
{
    // the for-loop is replaced with a collection of threads, each of which
    // calls this function.
    result[index] = inA[index] + inB[index];
}

Xcode在应用程序目标中构建所有的 .Metal 文件,并创建一个默认的Metal库,并打包到应用程序中。

为了更好的解释代码含义,写一个C语言版本的来做对比:

void add_arrays(const float* inA,
                const float* inB,
                float* result,
                int length)
{
    for (int index = 0; index < length ; index++)
    {
        result[index] = inA[index] + inB[index];
    }
}

代码解释:

1、函数添加kernel关键字,kernel关键字将声明函数为公开GPU函数。公开函数只有你自己的应用能访问到。公开函数也不能被其他shader函数调用。同时也表明这是一个计算函数(也称为计算内核),它使用线程网格执行并行计算。

2、add_arrays函数用device关键字声明了它的三个参数,表示这些指针位于设备地址空间中。MSL为内存定义了几个不相交的地址空间。在MSL中声明指针时,必须提供一个关键字来声明其地址空间。本例使用设备地址空间来声明只有内存,以保证GPU可以读取和写入。

3、MSL版相对于C版本,删除了for循环,因为该函数现在将有计算网格中的多个线程调用。这个示例创建一个与数组尺寸完全匹配的一堆线程网格,这样数组中的每个元素都由不同的线程计算。

为了替换先前由for循环提供的索引,该函数接受一个新的索引参数,该参数使用另一个MSL关键字thread_position_in_grid,该关键字使用C++属性语法指定。这个关键字声明Metal应该为每个线程计算一个唯一的索引,并在这个参数中传递该索引。因为add_arrays使用一维网格,所以索引被定义为一个标量整数。

2、找到一个可用的GPU

在Metal中,MTLDevice对象是GPU的一个抽象,你可以使用它来和GPU通信,Metal为每个GPU创建一个MTLDevice。通过调用MTLCreateSystemDefaultDevice()来获取默认对象。在 macOS中,Mac可以有多个GPU,Metal旋转其中一个GPU作为默认值并返回该GPU的设备对象。

let device: MTLDevice = MTLCreateSystemDefaultDevice();

 

3、获取Metal函数引用

4、创建Metal Pipeline

5、创建命令队列

6、创建数据缓冲区和加载数据

7、创建命令缓冲区

8、创建命令编码器

9、设置Pipeline State和参数数据

10、指定线程组数量

11、执行线程组大小

12、编码计算命令提交到执行线程

13、结束计算编码

14、提交到命令缓冲区并执行

15、等待计算完成

16、从缓冲区读取结果

 

文哥博客(https://wenge365.com)属于文野个人博客,欢迎浏览使用

联系方式:qq:52292959 邮箱:52292959@qq.com

备案号:粤ICP备18108585号 友情链接