演示如何访问GPU并和GPU交互
概述
Metal提供对用户设备上的图像处理单元(graphics processing unit,GPU)底层低开销的访问, 有效地使用GPU获得优秀的应用程序。开发一个如此这搬优秀的Metal应用的关键是理解底层的软硬件交互。
在这个例子中,你将学会如何用Metal写一个应用程序,并学会发送简单的渲染指令到GPU。
重点是,你将学会如何获得一个Metal设备(MTLDevice
),如何配置一个MetalKit view(MTKView
),
创建并执行GPU命令,显示渲染内容。
Metal和MetalKit框架
这个例子使用了两个框架去实现内容渲染:Metal和MetalKit。 Metal提供了访问GPU的接口,而MetalKit提供常用的Metal工具,这些工具使得开发一个Metal应用变得更加简单。 系统和框架无缝地结合在一起,让你可以集中精力于GPU程序(Metal code)。
MetaKit提供一个最有用的组件之一就是类MTKView
,它是对类UIView
或者类NSView
的封装
(注:UIView
/NSView
是不能直接用于Metal/OpenGLES的显示输出的,必须进行一些特殊配置),
并且配置好了专用于Metal的Core Animation功能。MetalKit view自动配置并管理了一个持续
的渲染循环(Rendering Loop),它在每一帧为你提供了一个2D的可显示的资源,也就是drawable(
注:drawable是指view.currentDrawable
,用于呈现Metal的输出,你才可以从屏幕
看到渲染结果)。
你可以直接用Core Animation开发Metal app,它更容易、更快并且更加方便使用MetalKit。
分离(Separate)渲染循环
在开发一个Metal应用的时候分离你的渲染循环,把渲染循环放入一个独立的类中,这常常是很有用的。
使用一个分离的类,你可以更好地管理你初始化Metal的配置代码和每一帧的Metal命令。
这种架构是通过类AAPLRenderer
实现的,用一个MetaKit view初始化AAPLRenderer
对象,
并把这个AAPLRenderer
对象赋值为view的委托。
_renderer = [[AAPLRenderer alloc] initWithMetalKitView:_view]; if(!_renderer) { NSLog(@"Renderer failed initialization"); return; } _view.delegate = _renderer;
响应MTKView事件
对象实现了MTKViewDelegate
的mtkView:drawableSizeWillChange:
和drawInMTKView:
方法,
这些方法会通知你MetalKit view重置尺寸和绘制事件。
当窗口大小改变(macOS)或者重新布局,比如一个设备的方向改变了(iOS和tvOS),
MetalKit view会调用mtkView:drawableSizeWillChange:
方法。
如果需要,你可以响应view的新尺寸并且改变你的渲染分辨率(ViewPort)。
每当绘制新一帧的时候,drawInMTKView: method
就会被调用,可以通过view的preferredFramesPerSecond
属性指定帧率(比如,60FPS)。这个回调通常作为开始执行你的渲染循环的主要事件(注:也就是一般就在这个回调函数里面
编写每帧的渲染命令)。
Metal命令对象
一个MTLDevice
对象代表一个GPU。通常,你调用MTLCreateSystemDefaultDevice()
方法获得一个
单一的MTLDevice
对象,这个对象代表着设备上默认的GPU。一个设备对象提供关于GPU的信息,但是他的主要职能
是创建其他和GPU交互的对象。
所有的应用要和GPU交互,第一个对象就是一个MTLCommandQueue
对象。
_commandQueue = [_device newCommandQueue];
你使用一个MTLCommandQueue对象去创建和组织MTLCommandBuffer
对象,确保他们以正确的序列发送到GPU。
在每一帧,创建一个新的MTLCommandBuffer
对象,并且填充被GPU执行的命令。
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
GPU的类型是很多的,每种类型GPU接收和解释命令的方式都不尽相同。
一个MTLCommandBuffer
对象用于合并所有的命令,一起提交,但是在这之前,命令必须首先通过一个
MTLCommandEncoder
对象以设备无关的方式编码。MTLCommandEncoder以及她的那些子类型之间是有少许不同的,
每种类型都是用于在GPU上执行不同类型的任务。这个例子展示了MTLCommandEncoder
的子类MTLRenderCommandEncoder
的用法,她将编码渲染命令到一个命令缓冲(创建她的命令缓冲)
这个例子使用了一个MTLRenderCommandEncoder
对象去编码命令,渲染像素数据到MetalKit view的
drawable上。为了显示到MetalKit view,这个命令编码器必须明确关联到drawable。
要创建一个MTLRenderCommandEncoder
对象,你必须首先创建一个MTLRenderPassDescriptor
对象。MTLRenderPassDescriptor
是轻量级的,临时的,包含各种属性配置,使用MTLCommandBuffer
创建一个新的MTLRenderCommandEncoder
对象。之后就不需要MTLRenderPassDescriptor
对象了。
接着用图解法阐明Metal各个命令对象间的关系。概括如下: + 从命令队列创建命令缓冲 + 从命令缓冲创建命令编码器 + 提交并发送命令缓冲到GPU
准备一帧
每一帧都通过view的属性currentRenderPassDescriptor
获取一个MTLRenderPassDescriptor对象。
这个MTLRenderPassDescriptor对象已经预先配置好了各种属性,这些属性和view相关,
有些属性则派生于view的drawable,她使得创建一个新的MTLRenderCommandEncoder对象变得容易和便利。
// Obtain a render pass descriptor, generated from the view's drawable MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor; // If you've successfully obtained a render pass descriptor, you can render to // the drawable; otherwise you skip any rendering this frame because you have no // drawable to draw to if(renderPassDescriptor != nil) { id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
命令编码进MTLRenderCommandEncoder
对象,渲染到view的drawable。默认,创建一个
MTLRenderCommandEncoder对象时,会隐式编码进一个清理命令,GPU会在任何其他渲染命令之前执行她。
在渲染循环的的一开始,就将drawable的像素更新为一个固定颜色。
Color color = [self makeFancyColor]; view.clearColor = MTLClearColorMake(color.red, color.green, color.blue, color.alpha);
完成一帧
中间,Metal应用多次调用MTLRenderCommandEncoder的方法,将渲染命令明确地编码进一个命令缓冲。
当编码器完成的时候,命令缓冲还需要做最后两步:present和commit。
因为GPU不直接绘制到屏幕,在完成执行渲染命令之前,她会阻止绘制像素到屏幕。你可以调用方法
presentDrawable:
,去避免因为不完整的绘制造成一个糟糕的用户体验(注:看到绘制过程,闪屏),
这个方法告诉Metal,在呈现到屏幕之前,先等待GPU完整渲染到drawable。
[commandBuffer presentDrawable:view.currentDrawable];
GPU不会马上执行命令。MTLRenderCommandEncoder
或者MTLCommandBuffer
的命令,都会在commit
方法被调用之后执行。当GPU开始执行的时候,这个drawable被清理为一个新的颜色。
当GPU执行完毕的时候,渲染好的drawable被呈现到屏幕。
[commandBuffer commit];
下一步
在这个例子中,你学会了如何用Metal写一个应用,发送简单的渲染的命令到GPU。 在你好,三角形这个例子中,你将学会如何在metal中渲染一个简单几何图形。
英文原文:Devices and Commands
已有 2718 位网友参与,快来吐槽:
发表评论