Metal框架详细解析(二十四) —— 基本课程之参数缓冲 - 基本参数缓冲(四)

版本记录

版本号 时间
V1.0 2018.10.09 星期二

前言

很多做视频和图像的,相信对这个框架都不是很陌生,它渲染高级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同步(三)

Argument Buffers - 参数缓冲

学习如何使用参数缓冲区。


Basic Argument Buffers - 基本参数缓冲区

演示如何使用参数缓冲区管理资源组。

参数缓冲区表示一组资源,可以将这些资源共同指定为图形或计算功能的参数。 您可以使用参数缓冲区来降低CPU开销,简化资源管理并实现GPU驱动的管道。

在此示例中,您将学习如何在参数缓冲区中指定,编码,设置和访问资源。 特别是,您将了解在参数缓冲区中管理资源组而不是单个资源的优势。 该示例使用纹理,采样器,缓冲区和常量编码到参数缓冲区中呈现静态四边形。


CPU Overhead and Argument Buffers - CPU开销和参数缓冲区

Metal命令是高效的,当应用程序访问GPU时,会产生最小的CPU开销。 但是,每个命令都会产生一些开销;要进一步减少金额,请使用以下策略:

  • 使用更少的CPU命令执行更多GPU工作。
  • 避免重复昂贵的CPU命令。

Metal的参数缓冲区功能可以减少应用程序关键路径中CPU命令的数量和性能成本(例如,在应用程序的渲染循环中)。 参数缓冲区允许您在单个缓冲区内对多个资源进行分组和编码,而不是单独编码每个资源。 通过使用参数缓冲区,您可以将大量的CPU开销从应用程序的关键路径转移到其初始设置。


Individual Resources versus Argument Buffers - 个人资源与参数缓冲区

Metal应用程序,尤其是游戏,通常包含多个3D对象,每个对象都与一组资源相关联,如纹理,采样器,缓冲区和常量。 为了渲染每个对象,apps编码Metal命令,在发出绘制调用之前将这些资源设置为图形函数的参数。

您可以通过为每个资源调用MTLRenderCommandEncoder方法(如setVertexBuffer:offset:atIndex:setFragmentTexture:atIndex:)将各个资源设置为参数。

设置单个资源的命令可能变得繁多且昂贵,尤其是对于大型应用程序或游戏。 相反,您可以将相关资源分组到参数缓冲区中,然后将整个缓冲区设置为图形函数的单个参数。 这种方法大大降低了CPU开销,并且仍然提供对您资源的单独GPU访问。

参数缓冲区表示为MTLBuffer对象。 因此,您可以通过为每个参数缓冲区调用MTLRenderCommandEncoder方法(如setVertexBuffer:offset:atIndex:setFragmentBuffer:offset:atIndex:)将它们设置为参数。

注意:要访问参数缓冲区中的各个资源,必须为要使用的每个资源调用useResource:usage:方法。 有关更多信息,请参阅Enable the GPU Memory of Resources in the Argument Buffer部分。


Define Argument Buffers - 定义参数缓冲区

参数缓冲区在Metal Shading Language中定义为自定义结构。 每个结构元素表示一个单独的资源,声明为纹理,采样器,缓冲区或常量数据类型。 结构元素还与使用[[id(n)]]属性限定符声明的整数相关联,该整数指定单个资源的索引。

此示例中的参数缓冲区被声明为FragmentShaderArguments结构,这是它的定义:

typedef struct FragmentShaderArguments {
    texture2d<half> exampleTexture  [[ id(AAPLArgumentBufferIDExampleTexture)  ]];
    sampler         exampleSampler  [[ id(AAPLArgumentBufferIDExampleSampler)  ]];
    device float   *exampleBuffer   [[ id(AAPLArgumentBufferIDExampleBuffer)   ]];
    uint32_t        exampleConstant [[ id(AAPLArgumentBufferIDExampleConstant) ]];
} FragmentShaderArguments;

此参数缓冲区包含以下资源:

  • exampleTexture,索引为0的2D纹理。
  • exampleSampler,索引为1的采样器。
  • exampleBuffer,索引为2的浮点缓冲区。
  • exampleConstant,一个索引为3的uint32_t常量。

此示例的片段函数fragmentShader使用参数缓冲区作为单个参数。

fragment float4
fragmentShader(       RasterizerData            in                 [[ stage_in ]],
               device FragmentShaderArguments & fragmentShaderArgs [[ buffer(AAPLFragmentBufferIndexArguments) ]])

fragmentShaderArgs参数是FragmentShaderArguments类型的缓冲区。 当样本将MTLBuffer设置为片段函数的参数时,该函数将fragmentShaderArgs参数中的数据解释为具有纹理,采样器,缓冲区和常量的参数缓冲区(由FragmentShaderArguments结构定义)。


Encode Resources into an Argument Buffer - 将资源编码到参数缓冲区中

在函数访问缓冲区之前,必须将各个资源编码到参数缓冲区中。 这是通过从使用参数缓冲区的MTLFunction创建MTLArgumentBufferEncoder来实现的。

此示例从fragmentShader函数创建MTLArgumentBufferEncoder,该函数包含fragmentShaderArgs参数。

id <MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"];

id <MTLArgumentEncoder> argumentEncoder
    = [fragmentFunction newArgumentEncoderWithBufferIndex:AAPLFragmentBufferIndexArguments];

argumentEncoderencodedLength属性确定包含参数缓冲区中所有资源所需的大小(以字节为单位)。 此示例使用该值创建一个新缓冲区_fragmentShaderArgumentBuffer,其长度参数与参数缓冲区所需的大小相匹配。

NSUInteger argumentBufferLength = argumentEncoder.encodedLength;

_fragmentShaderArgumentBuffer = [_device newBufferWithLength:argumentBufferLength options:0];

然后,此示例调用setArgumentBuffer:offset:方法以指定_fragmentShaderArgumentBuffer是可以编码资源的参数缓冲区。

[argumentEncoder setArgumentBuffer:_fragmentShaderArgumentBuffer offset:0];

此示例通过以下方式将各个资源编码到参数缓冲区中:

  • 为每种资源类型调用特定方法,例如setTexture:atIndex:,setSamplerState:atIndex:setBuffer:offset:atIndex
  • index参数的值与为FragmentShaderArguments结构的每个元素声明的[[id(n)]]属性限定符的值匹配。
[argumentEncoder setTexture:_texture atIndex:AAPLArgumentBufferIDExampleTexture];
[argumentEncoder setSamplerState:_sampler atIndex:AAPLArgumentBufferIDExampleSampler];
[argumentEncoder setBuffer:_indirectBuffer offset:0 atIndex:AAPLArgumentBufferIDExampleBuffer];

常量编码有点不同;常量数据直接嵌入到参数缓冲区中,而不是驻留在参数缓冲区指向的另一个对象中。 此示例调用constantDataAtIndex:方法以检索常量所在的参数缓冲区中的地址。 然后,该示例在检索到的地址处设置常量bufferElements的实际值。

uint32_t *numElementsAddress = [argumentEncoder constantDataAtIndex:AAPLArgumentBufferIDExampleConstant];

*numElementsAddress = bufferElements;

Enable the GPU Memory of Resources in the Argument Buffer - 在参数缓冲区中启用资源的GPU内存

Metal有效地管理GPU访问的内存;在GPU使用任何资源之前,Metal确保GPU可以访问资源的内存。 通过调用MTLRenderCommandEncoder方法(例如setVertexBuffer:offset:atIndex:setFragmentTexture:atIndex:)来单独设置资源可确保GPU可以访问资源的内存。

但是,当资源编码到参数缓冲区中时,设置参数缓冲区不会单独设置其每个资源。 Metal不检查参数缓冲区以确定在其中编码哪些资源(这种昂贵的操作会否定参数缓冲区的性能优势)。 因此,Metal无法确定GPU可以访问哪些资源的内存。 相反,您调用useResource:usage:方法来显式指示MTLRenderCommandEncoder使GPU可访问特定资源的内存。

注意:您只需要在MTLRenderCommandEncoder的生命周期内为每个资源调用一次useResource:usage:方法,即使您在多个绘制调用中使用该资源也是如此。useResource:usage:方法特定于参数缓冲区,但调用它比单独设置每个资源要便宜得多。


Set Argument Buffers - 设置参数缓冲区

此示例调用useResource:usage:方法,用于编入参数缓冲区的_texture_indirectBuffer资源。 这些调用指定MTLResourceUsage值,进一步指示对每个资源执行哪些GPU操作(对纹理进行采样并在GPU中读取缓冲区)。

[renderEncoder useResource:_texture usage:MTLResourceUsageSample];
[renderEncoder useResource:_indirectBuffer usage:MTLResourceUsageRead];

注意:useResource:usage:方法不适用于采样器或常量,因为它们不是MTLResource对象。

此示例仅将_fragmentShaderArgumentBuffer设置为片段函数的参数;它不单独设置_texture_indirectBuffer_samplerbufferElements资源。 此命令允许片段函数访问参数缓冲区及其编码资源。

[renderEncoder setFragmentBuffer:_fragmentShaderArgumentBuffer
                          offset:0
                         atIndex:AAPLFragmentBufferIndexArguments];

Access the Resources in an Argument Buffer - 访问参数缓冲区中的资源

在函数内,访问参数缓冲区中编码的资源类似于直接访问各个资源。 主要区别在于资源是作为参数缓冲区结构的元素访问的。

在此示例中,通过fragmentShader函数的fragmentShaderArgs参数访问参数缓冲区资源。

// Get the sampler encoded in the argument buffer
sampler exampleSampler = fragmentShaderArgs.exampleSampler;

// Sample the texture encoded in the argument buffer
half4 textureSample = fragmentShaderArgs.exampleTexture.sample(exampleSampler, in.texCoord);

// Use the fragment position and the constant encoded in the argument buffer to calculate an array index
uint32_t index = (uint32_t)in.position.x % fragmentShaderArgs.exampleConstant;

// Index into the buffer encoded in the argument buffer
float colorScale = fragmentShaderArgs.exampleBuffer[index];

该示例使用参数缓冲区中的所有四个资源来生成每个片段的最终颜色。

在此示例中,您学习了如何在参数缓冲区中指定,编码,设置和访问资源。

后记

本篇主要讲述了基本参数缓冲,感兴趣的给个赞或者关注~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容