您好,欢迎访问代码之道!登录后台查看权限
  • 欢迎大神光临
  • 有朋自远方来 不亦悦乎

Metal中文文档:设备和命令

Objective-C 老刘 2018-09-14 2284 次浏览 0个评论

演示如何访问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事件

对象实现了MTKViewDelegatemtkView: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

Metal命令对象关系

准备一帧

每一帧都通过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

已有 2284 位网友参与,快来吐槽:

发表评论