GPU技术总结(二):Metal渲染基本流程

举报
大数据小粉 发表于 2017/04/10 15:22:02 2017/04/10
【摘要】 作为GPU应用程序接口,Metal和OpenGL ES一样,主要功能便是3D图形渲染。3D图形渲染最基本的就是渲染一个三角形,下面是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 device = MTLCreateSystemDefaultDevice();

//创建命令队列对象
id commandQueue = [device newCommandQueue];

//创建命令缓冲区对象
id commandBuffer = [commandQueue commandBuffer];

//创建渲染通道描述符对象
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 renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDesc];

//指定渲染输入资源
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 posBuf = [device newBufferWithBytes:posData length:sizeof(posData) options:nil];
id colBuf = [device newBufferWithBytes:colorData length:sizeof(colData) options:nil];
[renderEncoder setVertexBuffer:posBuf offset:0 atIndex:0];
[renderEncoder setVertexBuffer:colBuf offset:0 atIndex:1];

//创建渲染管线状态对象
NSError *errors;
id library = [device newLibraryWithSource:progSrc options:nil error:&errors];
id vertFunc = [library newFunctionWithName:@"hello_vertex" options:nil error:&errors];
id fragFunc = [library newFunctionWithName:@"hello_fragment" options:nil error:&errors];
MTLRenderPipelineDescriptor *renderPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.vertexFunction = vertFunc;
renderPipelineDesc.fragmentFunction = fragFunc;
renderPipelineDesc.colorAttachments[0].pixelFormat = currentTexture.pixelFormat;
id pipeline = [device newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&errors];
[renderEncoder setRenderPipelineState:pipeline];

//绘制图元
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];

//启动渲染
[renderEncoder endEncoding];
[commandBuffer commit];

转载请注明出处:华为云博客 https://portal.hwclouds.com/blogs

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

举报
请填写举报理由
0/200