Metal简介

Metal 框架支持 GPU 加速高级 3D 图像渲染,以及数据并行计算工作。Metal 提供了先进合理的 API,它不仅为图形的组织、处理和呈现,也为计算命令以及为这些命令相关的数据和资源的管理,提供了细粒度和底层的控制。Metal 的主要目的是最小化 GPU 工作时 CPU 所要的消耗。

Metal的特点

Metal特点.png
  • 低CPU开销
  • 最大程度发挥GPU性能
  • 最大限度的提高CPU/GPU 的并发性
  • 有效的资源管理

图形管道 graphics pipelines

Metal图形管道.png
  • 通过CPU将顶点数据传入定点着色器
  • 进行图元装配
  • 进行光栅化
  • 将颜色值传入片元着色器
  • 将数据传入帧缓冲区,显示到屏幕上

Metal的使用建议

Apple对于Metal的使用提出了几点建议

  • Separate Your Rendering Loop 分开渲染循环。Apple建议开发者将渲染循环单独封装在一个类中。
  • Respond to View Events 响应视图的事件,即MTKViewDelegate协议,也需要放在自定义的渲染循环中。
  • Metal Command Objects 创建一个命令对象,即创建执行命令的GPU、与GPU交互的MTLCommandQueue对象以及MTCommandBuffer渲染缓存区湘。

Metal命令对象之间的关系

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

Metal API

顶点函数声明

vertex RasterizerData
vertexShader(uint vertexID [[vertex_id]],
 constant CCVertex *vertices [[buffer(CCVertexInputIndexVertices)]],
 constant vector_uint2 *viewportSizePointer [[buffer(CCVertexInputIndexViewportSize)]]) 
//vertexID : 顶点索引 [[vertex_id]] 属性修饰符
//vertices : 顶点数组 [[buffer(CCVertexInputIndexVertices)]] 属性修饰符
//viewportSizePointer : 视⼝⼤⼩ [[buffer(CCVertexInputIndexViewportSize)]] 属性修饰符

顶点函数实现

1. 执⾏坐标系转换,将⽣成的顶点剪辑空间位置写⼊`out.clipSpacePosition`返回值。 
2. 将顶点颜⾊传递给`out.color`返回值。
RasterizerData out; 
 out.clipSpacePosition = vector_float4(0.0, 0.0, 0.0, 1.0); 
 float2 pixelSpacePosition = vertices[vertexID].position.xy; 
 vector_float2 viewportSize = vector_float2(*viewportSizePointer);
 out.clipSpacePosition.xy = pixelSpacePosition / (viewportSize / 2.0); 
 out.color = vertices[vertexID].color;  
return out;

⽚元函数实现

主要任务是处理传⼊的⽚段数据并计算可绘制像素的颜⾊值。

fragment float4 fragmentShader(RasterizerData in [[stage_in]])
{
 return in.color;
}

获取函数库并创建管道

//在项目中加载所有的(.metal)着色器文件,从bundle中获取.metal文件
id<MTLLibrary> defaultLibrary = [_device newDefaultLibrary];
//从库中加载顶点函数
id<MTLFunction> vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"];
//从库中加载片元函数
id<MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"];
//配置用于创建管道状态的管道
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
//管道名称
pipelineStateDescriptor.label = @"Simple Pipeline";
//可编程函数,用于处理渲染过程中的各个顶点
pipelineStateDescriptor.vertexFunction = vertexFunction;
//可编程函数,用于处理渲染过程中各个片段/片元
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
//一组存储颜色数据的组件
pipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat;

//同步创建并返回渲染管线状态对象
_pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
//判断是否返回了管线状态对象
if (!_pipelineState)
{
           
     //如果我们没有正确设置管道描述符,则管道状态创建可能失败
     NSLog(@"Failed to created pipeline state, error %@", error);
     return nil;
}

//创建命令队列
_commandQueue = [_device newCommandQueue];
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。