Metal框架详细解析(四十一) —— Metal编程指南之图形渲染:渲染命令编码器之Part 1(六)

版本记录

版本号 时间
V1.0 2018.11.10 星期六

前言

很多做视频和图像的,相信对这个框架都不是很陌生,它渲染高级3D图形,并使用GPU执行数据并行计算。接下来的几篇我们就详细的解析这个框架。感兴趣的看下面几篇文章。
1. Metal框架详细解析(一)—— 基本概览
2. Metal框架详细解析(二) —— 器件和命令(一)
3. Metal框架详细解析(三) —— 渲染简单的2D三角形(一)
4. Metal框架详细解析(四) —— 关于GPU Family 4(一)
5. Metal框架详细解析(五) —— 关于GPU Family 4之关于Imageblocks(二)
6. Metal框架详细解析(六) —— 关于GPU Family 4之关于Tile Shading(三)
7. Metal框架详细解析(七) —— 关于GPU Family 4之关于光栅顺序组(四)
8. Metal框架详细解析(八) —— 关于GPU Family 4之关于增强的MSAA和Imageblock采样覆盖控制(五)
9. Metal框架详细解析(九) —— 关于GPU Family 4之关于线程组共享(六)
10. Metal框架详细解析(十) —— 基本组件(一)
11. Metal框架详细解析(十一) —— 基本组件之器件选择 - 图形渲染的器件选择(二)
12. Metal框架详细解析(十二) —— 基本组件之器件选择 - 计算处理的设备选择(三)
13. Metal框架详细解析(十三) —— 计算处理(一)
14. Metal框架详细解析(十四) —— 计算处理之你好,计算(二)
15. Metal框架详细解析(十五) —— 计算处理之关于线程和线程组(三)
16. Metal框架详细解析(十六) —— 计算处理之计算线程组和网格大小(四)
17. Metal框架详细解析(十七) —— 工具、分析和调试(一)
18. Metal框架详细解析(十八) —— 工具、分析和调试之Metal GPU Capture(二)
19. Metal框架详细解析(十九) —— 工具、分析和调试之GPU活动监视器(三)
20. Metal框架详细解析(二十) —— 工具、分析和调试之关于Metal着色语言文件名扩展名、使用Metal的命令行工具构建库和标记Metal对象和命令(四)
21. Metal框架详细解析(二十一) —— 基本课程之基本缓冲区(一)
22. Metal框架详细解析(二十二) —— 基本课程之基本纹理(二)
23. Metal框架详细解析(二十三) —— 基本课程之CPU和GPU同步(三)
24. Metal框架详细解析(二十四) —— 基本课程之参数缓冲 - 基本参数缓冲(四)
25. Metal框架详细解析(二十五) —— 基本课程之参数缓冲 - 带有数组和资源堆的参数缓冲区(五)
26. Metal框架详细解析(二十六) —— 基本课程之参数缓冲 - 具有GPU编码的参数缓冲区(六)
27. Metal框架详细解析(二十七) —— 高级技术之图层选择的反射(一)
28. Metal框架详细解析(二十八) —— 高级技术之使用专用函数的LOD(一)
29. Metal框架详细解析(二十九) —— 高级技术之具有参数缓冲区的动态地形(一)
30. Metal框架详细解析(三十) —— 延迟照明(一)
31. Metal框架详细解析(三十一) —— 在视图中混合Metal和OpenGL渲染(一)
32. Metal框架详细解析(三十二) —— Metal渲染管道教程(一)
33. Metal框架详细解析(三十三) —— Metal渲染管道教程(二)
34. Metal框架详细解析(三十四) —— Hello Metal! 一个简单的三角形的实现(一)
35. Metal框架详细解析(三十五) —— Hello Metal! 一个简单的三角形的实现(二)
36. Metal框架详细解析(三十六) —— Metal编程指南之概览(一)
37. Metal框架详细解析(三十七) —— Metal编程指南之基本Metal概念(二)
38. Metal框架详细解析(三十八) —— Metal编程指南之命令组织和执行模型(三)
39. Metal框架详细解析(三十九) —— Metal编程指南之资源对象:缓冲区和纹理(四)
40. Metal框架详细解析(四十) —— Metal编程指南之函数和库(五)

Graphics Rendering: Render Command Encoder - 图形渲染:渲染命令编码器

本章介绍如何创建和使用MTLRenderCommandEncoder和MTLParallelRenderCommandEncoder对象,这些对象用于将图形渲染命令编码到命令缓冲区中。 MTLRenderCommandEncoder命令描述图形渲染管道,如图5-1所示。

Metal框架详细解析(四十一) —— Metal编程指南之图形渲染:渲染命令编码器之Part 1(六)_第1张图片
Figure 5-1 Metal Graphics Rendering Pipeline

MTLRenderCommandEncoder对象表示单个渲染命令编码器。 MTLParallelRenderCommandEncoder对象允许将单个呈现过程分解为多个单独的MTLRenderCommandEncoder对象,每个对象可以分配给不同的线程。 然后将来自不同渲染命令编码器的命令链接在一起并以一致,可预测的顺序执行,如 Multiple Threads for a Rendering Pass中所述。


Creating and Using a Render Command Encoder - 创建和使用渲染命令编码器

要创建,初始化和使用单个渲染命令编码器:

  • 1) 创建一个MTLRenderPassDescriptor对象,以定义一组附件,这些附件用作该呈现过程的命令缓冲区中图形命令的渲染目标。通常,您创建一次MTLRenderPassDescriptor对象,并在每次应用渲染帧时重复使用它。请参阅Creating a Render Pass Descriptor。
  • 2) 通过使用指定的渲染过程描述符调用MTLCommandBuffer的renderCommandEncoderWithDescriptor:方法来创建MTLRenderCommandEncoder对象。请参阅Using the Render Pass Descriptor to Create a Render Command Encoder。
  • 3) 创建一个MTLRenderPipelineState对象,以定义一个或多个绘制调用的图形渲染管道的状态(包括着色器,混合,多重采样和可见性测试)。要使用此渲染管道状态来绘制基元,请调用MTLRenderCommandEncoder的setRenderPipelineState:方法。有关详细信息,请参阅Creating a Render Pipeline State。
  • 4) 设置渲染命令编码器使用的纹理,缓冲区和采样器,如为Specifying Resources for a Render Command Encoder中所述。
  • 5) 调用MTLRenderCommandEncoder方法以指定其他固定函数状态,包括深度和模板状态,如Fixed-Function State Operations中所述。
  • 6) 最后,调用MTLRenderCommandEncoder方法绘制图形基元,如Drawing Geometric Primitives中所述。

1. Creating a Render Pass Descriptor - 创建渲染管道描述符

MTLRenderPassDescriptor对象表示编码的渲染命令的目标,该命令是附件(attachments)的集合。渲染通道描述符的属性可以包括用于颜色像素数据的多达四个附件的阵列,一个附件用于深度像素数据,以及一个附件用于模板像素数据。 renderPassDescriptor便捷方法使用默认附件状态创建具有颜色,深度和模板附件属性的MTLRenderPassDescriptor对象。 visibilityResultBuffer属性指定设备可以更新的缓冲区,以指示是否有任何样本通过深度和模板测试 - 有关详细信息,请参阅Fixed-Function State Operations。

每个单独的附件,包括将要写入的纹理,由附件描述符表示。对于附件描述符,必须适当地选择相关纹理的像素格式以存储颜色,深度或模板数据。对于颜色附件描述符MTLRenderPassColorAttachmentDescriptor,使用颜色可渲染像素格式。对于深度附加描述符MTLRenderPassDepthAttachmentDescriptor,使用深度可渲染像素格式,例如MTLPixelFormatDepth32Float。对于模板附件描述符MTLRenderPassStencilAttachmentDescriptor,使用模板可渲染像素格式,例如MTLPixelFormatStencil8。

纹理实际上在设备上每个像素使用的内存量并不总是与Metal框架代码中纹理的像素格式的大小相匹配,因为设备添加了填充以用于对齐或其他目的。有关每种像素格式实际使用的内存量以及附件大小和数量的限制,请参阅Metal Feature Set Tables一章。

Load and Store Actions - 加载和存储操作

附件描述符的loadAction和storeAction属性指定在呈现过程的开始或结束时执行的操作。 (对于MTLParallelRenderCommandEncoder,加载和存储操作发生在整个命令的边界,而不是每个MTLRenderCommandEncoder对象。有关详细信息,请参阅Multiple Threads for a Rendering Pass。)

可能的loadAction值包括:

  • MTLLoadActionClear,它将相同的值写入指定附件描述符中的每个像素。有关此操作的更多详细信息,请参阅 Specifying the Clear Load Action。
  • MTLLoadActionLoad,它保留纹理的现有内容。
  • MTLLoadActionDontCare,允许附件中的每个像素在渲染过程开始时采用任何值。

如果您的应用程序将呈现给定帧的附件的所有像​​素,请使用默认加载操作MTLLoadActionDontCare。 MTLLoadActionDontCare操作允许GPU避免加载纹理的现有内容,从而确保最佳性能。否则,您可以使用MTLLoadActionClear操作清除附件的先前内容,或使用MTLLoadActionLoad操作来保留它们。 MTLLoadActionClear操作还可以避免加载现有纹理内容,但是会产生使用纯色填充目标的成本。

可能的storeAction值包括:

  • MTLStoreActionStore,它将渲染过程的最终结果保存到附件中。
  • MTLStoreActionMultisampleResolve将渲染目标中的多重采样数据解析为单个样本值,将它们存储在附件属性resolveTexture指定的纹理中,并使附件的内容保持未定义状态。有关详细信息,请参阅示例Example: Creating a Render Pass Descriptor for Multisampled Rendering。
  • MTLStoreActionDontCare,在渲染过程完成后将附件保留为未定义状态。这可以提高性能,因为它使实现能够避免保留渲染结果所需的任何工作。

对于颜色附件,MTLStoreActionStore操作是默认的存储操作,因为应用程序几乎总是在渲染过程结束时保留附件中的最终颜色值。对于深度和模板附件,MTLStoreActionDontCare是默认的存储操作,因为在渲染传递完成后通常不需要保留这些附件。

Specifying the Clear Load Action - 指定Clear Load Action

如果附件描述符的loadAction属性设置为MTLLoadActionClear,则在渲染过程开始时将清除值写入指定附件描述符中的每个像素。清除值属性取决于附件的类型。

  • 对于MTLRenderPassColorAttachmentDescriptor,clearColor包含一个MTLClearColor值,该值由四个双精度浮点RGBA组件组成,用于清除颜色附件。 MTLClearColorMake函数从红色,绿色,蓝色和alpha分量创建清晰的颜色值。默认的清晰颜色为(0.0,0.0,0.0,1.0)或不透明的黑色。
  • 对于MTLRenderPassDepthAttachmentDescriptor,clearDepth包含一个双精度浮点清除值,范围为[0.0,1.0],用于清除深度附件。默认值为1.0。
  • 对于MTLRenderPassStencilAttachmentDescriptor,clearStencil包含一个32位无符号整数,用于清除模板附件。默认值为0。

Example: Creating a Render Pass Descriptor with Load and Store Actions - 示例:使用Load and Store Actions创建渲染通道描述符

Listing 5-1创建了一个带有颜色和深度附件的简单渲染过程描述符。 首先,创建两个纹理对象,一个具有可颜色渲染的像素格式,另一个具有深度像素格式。 接下来,MTLRenderPassDescriptor的renderPassDescriptor便捷方法创建默认的渲染通道描述符。 然后通过MTLRenderPassDescriptor的属性访问颜色和深度附件。 纹理和动作在colorAttachments [0]中设置,它表示第一个颜色附件(在数组中的索引0处)和深度附件。

Listing 5-1  Creating a Render Pass Descriptor with Color and Depth Attachments

MTLTextureDescriptor *colorTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
id  colorTex = [device newTextureWithDescriptor:colorTexDesc];
 
MTLTextureDescriptor *depthTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatDepth32Float
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
id  depthTex = [device newTextureWithDescriptor:depthTexDesc];
 
MTLRenderPassDescriptor *renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture = colorTex;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0,1.0,0.0,1.0);
 
renderPassDesc.depthAttachment.texture = depthTex;
renderPassDesc.depthAttachment.loadAction = MTLLoadActionClear;
renderPassDesc.depthAttachment.storeAction = MTLStoreActionStore;
renderPassDesc.depthAttachment.clearDepth = 1.0;

Example: Creating a Render Pass Descriptor for Multisampled Rendering - 示例:为多重采样渲染创建渲染通道描述符

要使用MTLStoreActionMultisampleResolve操作,必须将texture属性设置为多重采样类型纹理,resolveTexture属性将包含多重采样解析操作的结果。 (如果texture不支持多重采样,则多重采样解析操作的结果未定义。)resolveLevel,resolveSlice和resolveDepthPlane属性也可用于多重采样解析操作,以指定多重采样纹理的mipmap级别,立方体切片和深度平面。在大多数情况下,resolveLevelresolveSliceresolveDepthPlane的默认值都是可用的。 在Listing 5-2中,最初创建了一个附件,然后将其loadActionstoreActiontextureresolveTexture属性设置为支持多重采样解析。

Listing 5-2  Setting Properties for an Attachment with Multisample Resolve

MTLTextureDescriptor *colorTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
id  colorTex = [device newTextureWithDescriptor:colorTexDesc];
 
MTLTextureDescriptor *msaaTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
msaaTexDesc.textureType = MTLTextureType2DMultisample;
msaaTexDesc.sampleCount = sampleCount;  //  must be > 1
id  msaaTex = [device newTextureWithDescriptor:msaaTexDesc];
 
MTLRenderPassDescriptor *renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture = msaaTex;
renderPassDesc.colorAttachments[0].resolveTexture = colorTex;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0,1.0,0.0,1.0);

2. Using the Render Pass Descriptor to Create a Render Command Encoder - 使用渲染通道描述符创建渲染命令编码器

在创建渲染过程描述符并指定其属性后,使用MTLCommandBuffer对象的renderCommandEncoderWithDescriptor:方法创建渲染命令编码器,如Listing 5-3所示。

Listing 5-3  Creating a Render Command Encoder with the Render Pass Descriptor

id  renderCE = [commandBuffer
                    renderCommandEncoderWithDescriptor:renderPassDesc];

Displaying Rendered Content with Core Animation - 使用Core Animation显示渲染内容

Core Animation定义了CAMetalLayer类,该类专为使用Metal渲染内容的图层支持视图的特殊行为而设计。 CAMetalLayer对象表示有关内容几何(位置和大小),其可视属性(背景颜色,边框和阴影)的信息,以及Metal用于在颜色附件中显示内容的资源。它还封装了内容呈现的时间,以便内容可以在可用时或在指定时间显示。有关Core Animation的更多信息,请参阅Core Animation Programming Guide

Core Animation还为可显示资源的对象定义了CAMetalDrawable协议。 CAMetalDrawable协议扩展了MTLDrawable并提供了符合MTLTexture协议的对象,因此它可以用作渲染命令的目标。要渲染到CAMetalLayer对象中,您应该为每个渲染过程获取一个新的CAMetalDrawable对象,获取它提供的MTLTexture对象,并使用该纹理创建颜色附件。与颜色附件(attachment)不同,深度或模板附件的创建和破坏是昂贵的。如果需要深度或模板附件,请创建一次,然后在每次渲染帧时重复使用它们。

通常,您使用layerClass方法将CAMetalLayer指定为您自己的自定义UIView子类的支持层类型,如Listing 5-4所示。否则,您可以使用其init方法创建CAMetalLayer,并将该图层包含在现有视图中

Listing 5-4  Using CAMetalLayer as the backing layer for a UIView subclass

+ (id) layerClass {
    return [CAMetalLayer class];
}

要显示图层中Metal渲染的内容,您必须从CAMetalLayer对象获取可显示资源(CAMetalDrawable对象),然后通过将其附加到MTLRenderPassDescriptor对象来渲染到此资源中的纹理。为此,首先设置描述其提供的可绘制资源的CAMetalLayer对象的属性,然后在每次开始渲染新帧时调用其nextDrawable方法。如果未设置CAMetalLayer属性,则nextDrawable方法调用将失败。以下CAMetalLayer属性描述了可绘制对象:

  • device属性声明从中创建资源的MTLDevice对象。
  • pixelFormat属性声明纹理的像素格式。支持的值是MTLPixelFormatBGRA8Unorm(默认值)和MTLPixelFormatBGRA8Unorm_sRGB。
  • drawableSize属性声明设备像素中纹理的尺寸。要确保您的应用以显示的精确尺寸呈现内容(在某些设备上无需额外的采样阶段),请在计算图层所需的大小时考虑目标屏幕的nativeScale或nativeBounds属性。
  • framebufferOnly属性声明纹理是仅可用作附件(YES)还是也可用于纹理采样和像素读/写操作(NO)。如果是YES,则图层对象可以优化纹理以供显示。对于大多数应用,建议值为YES。
  • presentsWithTransaction属性声明是否使用标准Core Animation事务机制(YES)更新图层渲染资源的更改,或者是否异步更新为常规图层更新(NO,默认值)。

如果nextDrawable方法成功,则返回具有以下只读属性的CAMetalDrawable对象:

  • texture属性保存纹理对象。 在创建渲染管道(MTLRenderPipelineColorAttachmentDescriptor对象)时,可以将其用作附件。
  • layer属性指向负责显示drawableCAMetalLayer对象。

重要说明:只有一小部分可绘制资源,因此长帧渲染时间可能暂时耗尽这些资源并导致nextDrawable方法调用阻塞其CPU线程,直到方法完成。为了避免昂贵的CPU停顿,在调用CAMetalLayer对象的nextDrawable方法之前,执行所有不需要可绘制资源的每帧操作。

要在渲染完成后显示可绘制对象的内容,必须通过调用drawable对象的present方法将其提交给Core Animation。要同步drawable的表示和完成负责其呈现的命令缓冲区,可以在MTLCommandBuffer对象上调用presentDrawable:或presentDrawable:atTime:便利方法。这些方法使用调度处理程序(请参阅Registering Handler Blocks for Command Buffer Execution)来调用drawablepresent方法,该方法涵盖大多数方案。 presentDrawable:atTime:方法提供了对drawable何时呈现的进一步控制。


Creating a Render Pipeline State - 创建渲染管道状态

要使用MTLRenderCommandEncoder对象对渲染命令进行编码,必须首先指定MTLRenderPipelineState对象以定义任何绘制调用的图形状态。 渲染管道状态对象是一个长期存在的持久对象,可以在渲染命令编码器之外创建,预先缓存,并在多个渲染命令编码器中重用。 在描述相同的图形状态集时,重用先前创建的渲染管线状态对象可以避免重新评估并将指定状态转换为GPU命令的昂贵操作。

渲染管道状态是不可变对象。 要创建渲染管道状态,首先要创建并配置一个可变MTLRenderPipelineDescriptor对象,该对象描述渲染管道状态的属性。 然后,使用描述符创建MTLRenderPipelineState对象。

1. Creating and Configuring a Render Pipeline Descriptor - 创建和配置渲染管道描述符

要创建渲染管道状态,首先要创建一个MTLRenderPipelineDescriptor对象,该对象具有描述在渲染过程中要使用的图形渲染管道状态的属性,如图5-2所示。 新MTLRenderPipelineDescriptor对象的colorAttachments属性包含一个MTLRenderPipelineColorAttachmentDescriptor对象数组,每个描述符表示一个颜色附加状态,指定该附件的混合操作和因子,详见Configuring Blending in a Render Pipeline Attachment Descriptor。 附件描述符还指定附件的像素格式,该格式必须与渲染管道描述符的纹理的像素格式与相应的附件索引匹配,否则会发生错误。

Metal框架详细解析(四十一) —— Metal编程指南之图形渲染:渲染命令编码器之Part 1(六)_第2张图片
Figure 5-2 Creating a Render Pipeline State from a Descriptor

除了配置颜色附件外,还要为MTLRenderPipelineDescriptor对象设置以下属性:

  • 设置depthAttachmentPixelFormat属性以匹配MTLRenderPassDescriptor中depthAttachment纹理的像素格式。
  • 设置stencilAttachmentPixelFormat属性以匹配MTLRenderPassDescriptor中stencilAttachment纹理的像素格式。
  • 要在渲染管道状态中指定顶点或片段着色器,请分别设置vertexFunction或fragmentFunction属性。将fragmentFunction设置为nil会禁用像素光栅化到指定的颜色附件,该附件通常用于仅深度渲染或用于从顶点着色器将数据输出到缓冲区对象。
  • 如果顶点着色器具有带有每顶点输入属性的参数,请设置vertexDescriptor属性以描述该参数中顶点数据的组织,如Vertex Descriptor for Data Organization中所述。
  • 对于大多数典型的渲染任务,rasterizationEnabled属性的默认值YES是足够的。要仅使用图形管道的顶点阶段(例如,要收集在顶点着色器中转换的数据),请将此属性设置为NO
  • 如果附件支持多重采样(即附件是MTLTextureType2DMultisample类型纹理),则可以为每个像素创建多个样本。要确定片段如何组合以提供像素覆盖,请使用以下MTLRenderPipelineDescriptor属性。
    • sampleCount属性确定每个像素的样本数。创建MTLRenderCommandEncoder时,所有附件的纹理的sampleCount必须与此sampleCount属性匹配。如果附件不支持多重采样,则sampleCount为1,这也是默认值。
    • 如果alphaToCoverageEnabled设置为YES,则读取colorAttachments [0]alpha通道片段输出并用于确定coverage掩码。
    • 如果alphaToOneEnabled设置为YES,则colorAttachments [0]的alpha通道片段值将强制为1.0,这是最大的可表示值。 (其他附件不受影响。)

2. Creating a Render Pipeline State from a Descriptor - 从描述符创建渲染管道状态

在创建渲染管道描述符并指定其属性后,使用它来创建MTLRenderPipelineState对象。因为创建渲染管道状态需要对图形状态进行昂贵的评估以及可能编译指定的图形着色器,所以您可以使用阻塞或异步方法以最适合您的应用程序设计的方式调度此类工作。

  • 要同步创建渲染管道状态对象,请调用MTLDevice对象newRenderPipelineStateWithDescriptor:error:或newRenderPipelineStateWithDescriptor:options:reflection:error:的方法。这些方法阻塞当前线程,而Metal评估描述符的图形状态信息,并编译着色器代码以创建管道状态对象。
  • 要异步创建渲染管道状态对象,请调用MTLDevice对象的newRenderPipelineStateWithDescriptor:completionHandler:或newRenderPipelineStateWithDescriptor:options:completionHandler:方法。这些方法立即返回 - Metal异步评估描述符的图形状态信息,并编译着色器代码以创建管道状态对象,然后调用完成处理程序以提供新的MTLRenderPipelineState对象。

创建MTLRenderPipelineState对象时,您还可以选择创建反射数据,以显示管道着色器函数及其参数的详细信息。newRenderPipelineStateWithDescriptor:options:reflection:error:和newRenderPipelineStateWithDescriptor:options:completionHandler:提供此数据。 如果不使用反射数据,请避免获取反射数据。 有关如何分析反射数据的更多信息,请参阅Determining Function Details at Runtime。

创建MTLRenderPipelineState
对象后,调用MTLRenderCommandEncoder的setRenderPipelineState:方法将渲染管道状态与命令编码器关联以用于渲染。

Listing 5-5演示了如何创建一个名为pipeline的渲染管道状态对象。

Listing 5-5  Creating a Simple Pipeline State

MTLRenderPipelineDescriptor *renderPipelineDesc =
                             [[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.vertexFunction = vertFunc;
renderPipelineDesc.fragmentFunction = fragFunc;
renderPipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm;
 
// Create MTLRenderPipelineState from MTLRenderPipelineDescriptor
NSError *errors = nil;
id  pipeline = [device
         newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&errors];
assert(pipeline && !errors);
 
// Set the pipeline state for MTLRenderCommandEncoder
[renderCE setRenderPipelineState:pipeline];

变量vertFuncfragFunc是着色器函数,它们被指定为渲染管道状态描述符的属性,称为renderPipelineDesc。 调用MTLDevice对象的newRenderPipelineStateWithDescriptor:error:的方法同步使用管道状态描述符来创建渲染管道状态对象。 调用MTLRenderCommandEncoder的setRenderPipelineState:方法指定要与渲染命令编码器一起使用的MTLRenderPipelineState对象。

注意:因为MTLRenderPipelineState对象的创建成本很高,所以只要您想使用相同的图形状态,就应该重复使用它。

3. Configuring Blending in a Render Pipeline Attachment Descriptor - 在渲染管道附件描述符中配置混合

Blending使用高度可配置的混合操作将片段函数(源)返回的输出与附件(目标)中的像素值混合。混合操作确定源和目标值如何与混合因子组合。

要配置颜色附件的混合,请设置以下MTLRenderPipelineColorAttachmentDescriptor属性:

  • 要启用混合,请将blendingEnabled设置为YES。默认情况下,禁用混合。
  • writeMask标识混合了哪些颜色通道。默认值MTLColorWriteMaskAll允许混合所有颜色通道。
  • rgbBlendOperation和alphaBlendOperation分别使用MTLBlendOperation值为RGB和Alpha片段数据分配混合操作。两个属性的默认值是MTLBlendOperationAdd。
  • sourceRGBBlendFactor, sourceAlphaBlendFactor, destinationRGBBlendFactor
    和destinationAlphaBlendFactor分配源和目标混合因子。

Understanding Blending Factors and Operations - 了解混合因子和操作

四个混合因子指的是恒定的混合颜色值:MTLBlendFactorBlendColorMTLBlendFactorOneMinusBlendColorMTLBlendFactorBlendAlphaMTLBlendFactorOneMinusBlendAlpha。 调用MTLRenderCommandEncoder的setBlendColorRed:green:blue:alpha:方法,以指定与这些混合因子一起使用的常量颜色和alpha值,如Fixed-Function State Operations中所述。

某些混合操作通过将源值乘以源MTLBlendFactor值(缩写为SBF),将目标值乘以目标混合因子(DBF),并使用MTLBlendOperation值指示的算法组合结果来组合片段值。 (如果混合操作是MTLBlendOperationMinMTLBlendOperationMax,则忽略SBFDBF混合因子。)例如,rgbBlendOperationalphaBlendOperation属性的MTLBlendOperationAdd为RGB和Alpha值定义以下额外的混合操作:

RGB = (Source.rgb * sourceRGBBlendFactor) + (Dest.rgb * destinationRGBBlendFactor)
Alpha = (Source.a * sourceAlphaBlendFactor) + (Dest.a * destinationAlphaBlendFactor)

在默认的混合行为中,源完全覆盖目标。 此行为相当于将sourceRGBBlendFactorsourceAlphaBlendFactor都设置为MTLBlendFactorOne,将destinationRGBBlendFactordestinationAlphaBlendFactor设置为MTLBlendFactorZero。 此行为在数学上表示为:

RGB = (Source.rgb * 1.0) + (Dest.rgb * 0.0)
A = (Source.a * 1.0) + (Dest.a * 0.0)

另一种常用的混合操作,其中源alpha定义目标颜色的剩余量,可以用数学方式表示为:

RGB = (Source.rgb * 1.0) + (Dest.rgb * (1 - Source.a))
A = (Source.a * 1.0) + (Dest.a * (1 - Source.a))

Using a Custom Blending Configuration - 使用自定义混合配置

Listing 5-6显示了自定义混合配置的代码,使用混合操作MTLBlendOperationAdd,源混合因子MTLBlendFactorOne和目标混合因子MTLBlendFactorOneMinusSourceAlphacolorAttachments [0]是一个MTLRenderPipelineColorAttachmentDescriptor对象,其属性指定混合配置

Listing 5-6  Specifying a Custom Blending Configuration

MTLRenderPipelineDescriptor *renderPipelineDesc = 
                             [[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.colorAttachments[0].blendingEnabled = YES; 
renderPipelineDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
renderPipelineDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
renderPipelineDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOne;
renderPipelineDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
renderPipelineDesc.colorAttachments[0].destinationRGBBlendFactor = 
       MTLBlendFactorOneMinusSourceAlpha;
renderPipelineDesc.colorAttachments[0].destinationAlphaBlendFactor = 
       MTLBlendFactorOneMinusSourceAlpha;

NSError *errors = nil;
id  pipeline = [device 
         newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&errors];

后记

本篇主要讲述了图形渲染:渲染命令编码器,感兴趣的给个赞或者关注~~~

Metal框架详细解析(四十一) —— Metal编程指南之图形渲染:渲染命令编码器之Part 1(六)_第3张图片

你可能感兴趣的:(Metal框架详细解析(四十一) —— Metal编程指南之图形渲染:渲染命令编码器之Part 1(六))