Command Organization and Execution Model
在Metal 架构中,MTLDevice协议定义了代表单独GPU的接口。MTLDevice协议支持为了创建其他特定设备对象,如buffers 、textures,或者为了编码和排列(encoding and queueing)那些要被提交到GPU运行的渲染和计算命令,而去查询设备属性的接口.
一个command queue包含一队列的command buffers,而且还组织管理那些command buffers的执行顺序。
一个command buffer包含那些准备运行在特定设备上的压缩过的commands。
一个command encoder将那些渲染、计算、以及块传输命令追加到一个command buffer中,最终这些command buffers都会被提交到到设备上去以便执行。
MTLCommandQueue 协议定义了一个关于command queues的接口,主要支持创建command buffer对象的方法。MTLCommandBuffer协议定义了一个command buffers的接口而且提供创建command encoders、将command buffers 入队排序以便运行、检查状态、以及其他的一些操作等的方法。
MTLCommandBuffer协议支持下列命令编码类型,编码不同GPU 工作负荷格式到一个command buffer中去的接口
一个MTLDevice 对象代表了一个可以执行commands 的GPU 。MTLDevice 协议有以下操作的方法,如创建新command queues、从内存中初始化buffers(allocate buffers from memory,分配空间)、创建textures、查询该设备的能力(capabilities)。为了获取首选系统设备,可以调用MTLCreateSystemDefaultDevice方法。
Transient(短暂的,临时的) and Non-transient Objects in Metal
Metal中的一些对象被设计为临时的和极轻体量的,与此同时,也有一些对象被设计为更占内存并且可以持续一段时间,甚至有可能充斥整个app生命周期。
Command buffer 和command encoder对象是临时的,而且为一次性使用。他们在创建和销毁过程中几乎不耗费什么资源,所以他们的创建方法也是返回的autoreleased objects.
下列的对象都是非临时的,需要在性能敏感的代码里复用这些对象,禁止重复创建
一个command queue接受一列GPU将会执行的而且已经排好序的command buffers .所有被送到一个单独queue之中的command buffers默认会按照其入队的顺序来执行。一般情况下,command queues 是线程安全的,而且允许同时有多个激活的command buffer去执行被encode操作。
可以用一个MTLDevice对象调用newCommandQueue方法或者newCommandQueueWithMaxCommandBufferCount方法。一般来讲,希望command queues 可以长期存活的,所以不要反复的创建和销毁。
一个command buffer 一直存储那些已经编码过的commands直到该buffer 被提交给GPU运算。一个单独command buffer可以包含许多不同种类的encoded commands,这取决于用于创建它的encoder的数目和种类。在一个典型的app中,一个完整的渲染(rendering )帧会被编码进一个单独的command buffer中,即使渲染该帧包含了多个渲染过程、计算处理函数、或者blit操作。
Command buffers 是临时而且只能单次使用的对象,不支持复用。一旦一个command buffer已经被提交运行,唯一有效的操作是等待该command buffer被重新安排或者结束,通过同步请求(calls)或者在 Registering Handler Blocks for Command Buffer Execution中讨论的回调blocks,去检查该command buffer 运行的状态。
Command buffers也代表了可以被该app仅能独立跟踪的工作单元,而且它们定义了由Metal memory model 建立的一致性/相干性/内聚耦合(*注:该处的coherency应该是一致性)边界,详细内容可在Resource Objects: Buffers and Textures中查看。
去创建一个MTLCommandBuffer对象,调用MTLCommandQueue重的commandBuffer方法。一个MTLCommandBuffer对象只能被提交到创建它的MTLCommandQueue中。
被commandBuffer方法创建的Command buffers持有将被运行的数据。对于某些情况(For certain scenarios),当你想在一个MTLCommandBuffer对象执行期间在其他地方持有该对象,你可以通过调用MTLCommandQueue的commandBufferWithUnretainedReferences方法另行创建一个command buffer来instead.
只在性能要求极其严格的apps中使用commandBufferWithUnretainedReferences方法,这样可以确保关键对象在app的其他地方一直保有引用,直到该command buffer操作完成。
另外,一个不再保有引用的对象可能会被提前释放,这时该command buffer运行的结果还没有被定义。
MTLCommandBuffer协议利用下面的方法来建立在command queue中的command buffers 的执行顺序。一个command buffer 直到被提交才会执行。一旦提交,command buffers 会按照它们排序的顺序来执行。
下面列出的 MTLCommandBuffer 方法监控命令的执行。已收进和完成的handlers被放在一个未定义的线程上按照顺序执行。被放进这些handlers的代码应该是能快速执行的,如果该handler需要耗费较大,可以单独将其安排到另一个线程推迟执行。
有status 和error两个属性,当命令执行成功时,error为nil.
一个command encoder 对象是一个临时对象,可以用它来在一个单独command buffer中以一种GPU可以执行的格式一次性写入命令和状态。许多command encoder 对象方法在command buffer上添加commands。只要一个command encoder 是活跃的状态(active),它便具有绝对的能力来为它的command buffer添加命令。一旦想结束encoding commands,调用endEncoding方法。如果想要写更多的commands,可以重新创建一个encoder。
Creating a Command Encoder Object
command encoder 都要给command buffer添加命令,所以需要用MTLCommandBuffer对象的方法来创建合适类型的command encoder .
图形渲染可以以一个渲染过程来描述。一个MTLRenderCommandEncoder对象代表了渲染状态和一个单独渲染过程相应的drawing commands. 一个MTLRenderCommandEncoder对象需要有相应的 MTLRenderPassDescriptor对象,其包含了color,depth ,stencil attachment 作为rendering commands 的目标属性。
MTLRenderCommandEncoder对象有以下能力:
为了数据并行计算,MTLComputeCommandEncoder协议提供了一系列方法来encode commands到command buffer中,指定计算方法和它的参数(如,texture ,buffer, sampler state),而且分派计算方法的执行。
MTLBlitCommandEncoder 协议拥有添加命令到buffers (MTLBuffer) 和 textures(MTLTexture)之间的内存拷贝操作中。而且该协议也提供了用单色填充纹理以及生成位图的方法。
绝大多数app都会用一个单独线程来encode渲染命令,但是如果想要并行处理command buffer 编码,可以同时创建多个command buffer,然后用各自不同的线程来分别进行编码处理。
如果知道了command buffer的执行时间,便可以enqueue方法来声明它在command queue中的执行顺序,而不用等相应命令的编码和提交。
一个例子: