GPU技术总结(二):Metal渲染基本流程
作为GPU应用程序接口,Metal和OpenGL ES一样,主要功能便是3D图形渲染。3D图形渲染最基本的就是渲染一个三角形,下面是Metal渲染基本流程。
(1) 获取系统设备对象 MTLDevice。
这里的MTLDevice对象就是指GPU,可以执行Metal命令,后续的大部分对象都是由该设备对象引出来的。API函数MTLCreateSystemDefaultDevice()可以用来获取系统默认的MTLDevice对象。
(2) 创建命令队列对象 MTLCommandQueue。
命令队列可以接收多个命令缓冲区,然后按照各个命令缓冲区的提交顺序依次执行。一般情况下,所有命令缓冲区应该提交到一个命令队列以保证执行次序,同时命令队列也有线程安全机制保证可以多个线程同时操作。
(3) 创建命令缓冲区对象 MTLCommandBuffer。
命令缓冲区中存放各种不同的Metal命令,在实际使用时常被用来完成一帧图像的渲染。命令缓冲区的使用是一次性的,遵循"创建->提交->执行->销毁"的用法,不适合复用。
(4) 创建渲染通道描述符对象 MTLRenderPassDescriptor。
渲染通道描述符主要是指定渲染的输出目标,包括多个颜色挂载点(color attachment),一个深度挂载点(depth attachment)和一个模版挂载点(stencil attachment)。其作用类似于OpenGL ES 中的FBO对象。
(5) 创建渲染命令编码器对象 MTLRenderCommandEncoder。
一个命令编码器是一个执行单元,存储命令的输入(缓冲区对象,纹理对象,采样器对象等),处理过程(顶点着色器,像素着色器,深度测试,裁减测试等),输出(渲染通道描述符)等信息。命令编码器对象主要包括三类:渲染命令编码器对象。
MTLRenderCommandEncoder,计算命令编码器对象
MTLComputeCommandEncoder,拷贝命令编码器对象MTLBlitCommandEncoder
其中,渲染命令编码器对象主要用于编码渲染命令。
(6) 创建渲染管线状态对象 MTLRenderPipelineState。
渲染管线状态主要是用来指定顶点数据布局格式,顶点着色器处理函数,像素着色器处理函数以及各挂载点的格式等信息。渲染管线状态对象是可以复用的,多个渲染命令编码器可以共用一个渲染管线状态对象以提高性能。
(7) 指定渲染输入资源,包括纹理,缓冲区和采样器。
在Metal中,顶点着色器和像素着色器有一些相同的输入参数列表,包括:31个缓冲区参数列表,31个纹理参数列表和16个采样器参数列表。指定的这些参数可以在着色器处理函数中直接访问。
(8) 设置固定功能状态。
包括视口,裁减状态,深度测试,模版测试等。其中视口viewpart是3D的,包含深度,这一点和OpenGL ES不同。
(9) 绘制图元。
设置好各种状态后就可以开始绘制图元了,绘制图元需要指定图元类型,顶点起始位置,顶点个数等信息。另外,metal也支持索引顶点渲染和多实例渲染。
(10) 启动渲染。
结束命令编码,提交命令缓冲区,即可启动渲染了。
Metal采用的是面向对象的编程语言,其软件框架是以诸多的对象(object)来组织的。渲染过程最难理解的莫过于各种各样的对象object,下图说明了Metal中多线程与各个对象之间的关系:
下面是渲染的示例代码:
//获取系统设备对象
id
//创建命令队列对象
id
//创建命令缓冲区对象
id
//创建渲染通道描述符对象
MTLRenderPassDescriptor *renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture = currentTexture;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0,1.0,1.0,1.0);
//创建渲染命令编码器对象
id
//指定渲染输入资源
static const float posData[] = {
0.0f, 0.33f, 0.0f, 1.f,
-0.33f, -0.33f, 0.0f, 1.f,
0.33f, -0.33f, 0.0f, 1.f,
};
static const float colData[] = {
1.f, 0.f, 0.f, 1.f,
0.f, 1.f, 0.f, 1.f,
0.f, 0.f, 1.f, 1.f,
};
id
id
[renderEncoder setVertexBuffer:posBuf offset:0 atIndex:0];
[renderEncoder setVertexBuffer:colBuf offset:0 atIndex:1];
//创建渲染管线状态对象
NSError *errors;
id
id
id
MTLRenderPipelineDescriptor *renderPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.vertexFunction = vertFunc;
renderPipelineDesc.fragmentFunction = fragFunc;
renderPipelineDesc.colorAttachments[0].pixelFormat = currentTexture.pixelFormat;
id
[renderEncoder setRenderPipelineState:pipeline];
//绘制图元
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
//启动渲染
[renderEncoder endEncoding];
[commandBuffer commit];
- 点赞
- 收藏
- 关注作者
评论(0)