6383b064a356541834dbe519a8257b83
Metal【1】—— 概述

前言:

本文主要是概念阐述,将会介绍:

  • 什么是 Metal,Metal 的发展史
  • Metal 能做什么,目前现状,Apple 重视力度,社区活跃状态
  • 为什么要用 Metal,对比其他更上层框架以及 OpenGL ES

Metal,介绍

关于什么是什么这样的描述,我觉得没什么比官方的定义更权威了。

The Metal framework supports GPU-accelerated advanced 3D graphics rendering and data-parallel computation workloads. Metal provides a modern and streamlined API for fine-grained, low-level control of the organization, processing, and submission of graphics and computation commands, as well as the management of the associated data and resources for these commands. A primary goal of Metal is to minimize the CPU overhead incurred by executing GPU workloads.

概况来说,Metal 提供了一组简明的 API,使得我们开发者拥有了直接和 GPU 对话的能力。

在图像渲染,通用计算方面,通过发挥 GPU 的特性,极大提升性能。

这也正是,为什么取名叫 Metal,因为它非常非常非常接近底层芯片(金属材质)。

在 Metal 整体的设计上,按 Apple 官方的话说,那就是要多厉害有多厉害。

  • 完美适配现代 GPU
  • API 清晰明了,使用简单,可控性强
  • 极大降低 CPU 负载
  • 甩 OpenGL 几条街
  • ...

再具体的,我们下文接着吹。

那么,如此牛逼的 Metal,能用来做什么呢?

概括来说, 跟显示,数据计算相关的,基本都能和 Metal 搭上关系,因为 Metal 本身只是一个发挥 GPU 能力的媒介。GPU 能做的,基本就是 Metal 能做的

再展开,比如图像处理,相机预览,游戏,甚至机器学习等,都可以借助 Metal。


Metal,现状

那么,这样的一门牛逼的技术,从 2014 年推出至今,它的发展如何呢?

我们先看下 Metal 的主要发展史:

  • WWDC 2014,发布了 Metal,仅支持 iOS 8 以及 A7 以上的设备。
  • WWDC 2015,Metal 支持在 OS X 上运行,2012 之后生产的,系统版本在 El Capitan(10.11)之上的 Mac 设备。
  • WWDC 2016,Metal 性能优化,一些新技术,比如Tessellation(曲面细分)可用于实现细节层次,高效调整以适应不同材质等。最重要的应该是引入了 Metal Performance Shaders,内置了一系列常用的图像处理 kernel,方便进行图像效果处理。
  • WWDC 2017,发布了 Metal 2。名字上是图形 API 更新,实际上更多是内部实现的优化,以及加入一系列调试工具,API 层面并没有多大改变。硬件方面要求一致,系统版本支持 iOS 11,macOS High Sierra,tvOS 11。
  • WWDC 2018,iOS 12 之后弃用 OpenGL ES,系统的一些框架全面改成默认 Metal 支持。

年年 WWDC,Metal 都有新内容输出,这样的维护力度,可见 Apple 对其的重视。
如果这还不够震撼,那下面这个列表,可以随意感受下。

WWDC Session 2014

603: Working with Metal: Overview

604: Working with Metal: Fundamentals

605: Working with Metal: Advanced

WWDC Session 2015

603: What's New in Metal, Part 1

607: What's New in Metal, Part 2

610: Metal Performance Optimization Techniques

WWDC Session 2016

602: Adopting Metal, Part 1

603: Adopting Metal, Part 2

604: What's New in Metal, Part 1

605: What's New in Metal, Part 2

606: Advanced Metal Shader Optimization

WWDC Fall 2017

Metal 2 on A11

WWDC Session 2017

601: Introducing Metal 2

607: Metal 2 Optimization and Debugging

608: Using Metal 2 for Compute

WWDC Session 2018

604: Metal for OpenGL Developers

606: Metal for Ray Tracing Acceleration

607: Metal for Game Developers

608: Metal Shader Debugging and Profiling

609: Metal for Accelerating Machine Learning

611: Metal for VR

612: Metal Game Performance Optimization

纵观近几年的发展,可能也就 Swift 能和 Metal 对比吧。
所以可以很负责任的说,Metal 绝对是未来。

那么,Metal 对现有的生态圈,有什么影响呢?

自从 Metal 发布后,Crytek、PopCap、EPIC、Unity 等引擎公司就陆续跟进了,并且现在已经是主要的渲染器了。

另外,WWDC 2017,苹果公布了一组数据,
截止 2017 年 6 月,已经有 148000 个应用,直接使用了 Metal。更有 170w 的应用,通过更高层次的框架(比如 Core Image,SpriteKit,SceneKit 等),间接使用了 Metal。

当然,我相信现在,以及未来,这个数据肯定是直线上升。

更不用说,OpenGL ES 在 iOS 12 后被弃用,Metal 的时代,正式来临。


Metal,选择

那么,问题来了。什么时候应该选择 Metal ?

在架构设计上,Metal 和 OpenGL ES,Core Graphics 属于同一级,最接近 Graphics Hardware

PS:

  • Metal / OpenGL ES 是使用 GPU 处理,而 Core Graphics 是 CPU。
  • OpenGL ES 在 iOS 12 后被弃用。

在整个基础上,我们分别对比三种情况,考虑是否需要选择 Metal

  • Metal vs high-level frameworks
  • CPU vs GPU
  • Metal vs OpenGL ES

Metal vs high-level frameworks

对于开发者来说,Apple 提供给我们的更高层次框架,比如 UIKit、SpriteKit、SceneKit、Core Image 等,已经足够应付日常的需求了。如果在功能都能满足,无需扩展自定义,并且对性能没那么敏感的时候,那么,我建议尽可能使用上层框架,专注于业务开发,而不需要关心具体是如何与图形硬件交互。

当然,我们知道越高层次的封装,就意味着越多的性能损耗,功能支持越少。

Of course, as with high-level programming languages, this level of abstraction comes at the expense of efficiency

比如,通过 [UIImageView setImage:] 去显示图片,整个流程是这样的:

  1. Core Animation 提交会话,包括自己和子树(view hierarchy)的 layout 状态等;
  2. RenderServer 解析提交的子树状态,生成绘制指令;
  3. GPU 执行绘制指令;
  4. 显示渲染后的数据;

对应到具体的各个层级的框架,如下:

我们可以看到,UIKit 的相关操作,最后都会交由 Core Animation 去转发处理。
Core Animation 依赖于 Metal 做 GPU 渲染,Core Graphics 做 CPU 渲染;

所以,调用更上层的框架,本质上是 Apple 为我们再封装了一层,间接调用 Metal

而上层会屏蔽了更多的实现细节,导致我们对性能,对具体的实现方式,都是不可控的。也导致了可扩展性差,比如无法自定义脚本实现各式各样的效果等。

所以,如果我们能直接使用 Metal,与 GPU 打交道,那么能做的事情肯定是更多的。

CPU vs GPU

对比 CPU 和 GPU 之前,我们先看下为什么会产生卡顿

通常来说,计算机系统中 CPU、GPU、显示器是以上面这种方式协同工作的。

CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区。

随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示。

iOS 设备会始终使用双缓存,并开启垂直同步。
由于垂直同步的机制,如果在一个 VSync 时间内,CPU 或者 GPU 没有完成内容提交,则那一帧就会被丢弃,等待下一次机会再显示,而这时显示屏会保留之前的内容不变。这就是界面卡顿的原因。

所以,让 CPU 和 GPU 均衡负载,二者各司其职,做自己擅长的事,是解决卡顿的首要方案。

那么,如果图像数据处理这块,也交由 CPU 去处理,比如我们使用 Core Graphics,来对图片进行二值化处理,大致这么一个流程:

```objective-c

  • (UIImage *)covertToGray {
    CGSize size = [self size];
    int width = size.width;
    int height = size.height;

    // 像素将画在这个数组
    uint32_t *pixels = (uint32_t *)malloc(width *height *sizeof(uint32_t));
    // 清空像素数组
    memset(pixels, 0, widthheightsizeof(uint32_t));

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width*sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), [self CGImage]);

    // 逐像素处理
    int tt = 1;

top Created with Sketch.