大多数浏览器和
Developer App 均支持流媒体播放。
-
利用 Metal 3 实现无绑定
了解如何利用 Metal 3 实现无绑定,让渲染技术 (如光线追踪) 发挥其强大功能。我们将向您介绍如何通过简化参数缓冲区、分配来自堆的加速架构,以及运用 Metal 验证层和调试器工具的改进,使您 App 的无绑定旅程轻松愉快。我们还将探索如何利用长期资源结构,帮助您增强对 CPU 和 GPU 性能的控制。
资源
相关视频
WWDC23
WWDC22
WWDC21
-
下载
Alè: 大家好 欢迎 我是 Alè Segovia Azapian 来自 Apple GPU Software 团队 Mayur: 我是 Mayur 也是来自 GPU Software 团队 Alè: 在本次讲座中 我们将与 大家一起探究下无绑定渲染 无绑定渲染模型是 为着色器提供资源 解锁高级渲染技巧 如光线追踪的 全新方法 今天 我首先与大家回顾下 无绑定渲染模型的运作 您用 Metal 3 可以如何在 游戏和 App 中应用无绑定
无绑定渲染通过汇总数据 为提高 CPU 和 GPU 的性能 提供了新机会 我今天会给您两个具体的 改善 CPU 和 GPU 时间的方法 然后将会由 Mayur 为大家展示这些工具 是如何帮您应用无绑定模型的 在无绑定模型中 资源是通过参数缓冲区 聚合连接到一起的 从概念上讲 看起来是这样的 在这个示例中 一个数组 聚合了场景中所有网格 在传统绑定模型下 每个资源独立绑定 到管线的具体位置中 而无绑定模型则不同 资源首先在内存中连接在一起 让您的着色器可以通过 自由遍历单个缓冲区 来访问所需的资源 以计算复杂的表面和光照 App 采用无绑定后 光线追踪着色器可访问 它们需要的所有数据 绘制漂亮的反射 这个 App 可以将 3D 模型和纹理 包括地面 卡车 它们的材料 甚至天空 全部放置在参数缓冲区 让光线追踪着色器获取 更好的是 无绑定渲染 与其它 Metal 例如堆的功能配对时 减少了 CPU 压力 让 App 和游戏获得更好的性能 我给大家解释下 Metal 3 中 对无绑定渲染来说比较有用的 四个具体的增强功能 参数缓冲区作为 基础 Metal 构造 允许您将资源连接在一起 它们引用了资源 如纹理和其它缓冲区 有了 Metal 3 写入参数缓冲区比之前更简单 因为现在您不再需要 参数编码器对象 对非固定数组也一样 您现在可以从 Metal 堆中 分配加速结构 如果资源没有驻留在 GPU 内存中 着色器验证层会 发出警告 这四个功能让无绑定 变得更为简单
特别是在 Metal 3 中写入 参数缓冲区轻松愉快 要将场景编码到参数缓冲区中 您可以将场景数据写入 这些缓冲区 如实例 网格 材料和纹理 在 Metal 2 中 这些是用参数编码器来完成的 所以 我先带大家回顾下 这些对象是如何工作的 然后我给大家演示 Metal 3 可以如何简化您的代码 用参数编码器 第一步是 创建编码器实例 您可通过着色器函数映射 或通过向 Metal 描述结构体成员来创建 有了编码器实例后 设置其记录目标和 到目标参数缓冲的偏移 然后使用其方法将数据 写入缓冲区 您可查看去年的无绑定讲座 回顾更多关于参数缓冲区 和参数编码器的信息 现在这个机制非常好 但是编码器对象有时候 不好管理 Metal 提供了两种创建 参数编码器的机制 哪种适合您的 App 可能不太明确 此外 在多线程中使用 参数编码器需要格外小心 开发者们都很直观地了解 如何写一个 C 结构体 有了 Metal 3 您可以用同样的方法 使用参数缓冲区 Metal 3 可让您 方便地写入参数缓冲区 就象其他任何 CPU 端的结构一样 直接写入 现在您可以访问 虚拟 GPU 地址 和您资源的资源 ID 了 当您直接将这些写入 参数缓冲区时 Metal 现在理解您要引用的 是哪种资源 和之前用参数编码器 来编码引用的方式相比 两者在功能上是一样的 只是不再需要编码器了 这种功能支持所有支持 二级参数缓冲区的设备 也就是说 所有高于 2016 版本的 Mac 和所有搭载 A13 仿生芯片 或更高版本的 iOS 设备
如果您不确定设备是否支持 二级参数缓冲区 可使用 MTLDevice 对象中的 功能咨询 非常方便 该过程在 Metal 3 中 是这样的 首先 定义 CPU 可见的结构 缓冲区的地址和纹理的 MTLResourceID 需要使用 64 位类型 然后 分配参数缓冲区 您可直接从 MTLDevice 或从 MTLHeap 分配缓冲区 您获得缓冲区内容 并将它转换为 参数缓冲区结构类型 最后 将地址和资源 ID 写入结构体成员 看下这在混合渲染示范程序中 是如何操作的 这是代码 是不是很简单 宿主结构直接存储 法线缓冲区的 GPU 地址 这是 64 位 无符号整数 所以我使用了 uint64_t 现在没有编码器对象了 对于参数缓冲区 您只需使用结构体大小 Metal 可确保 GPU 和 CPU 结构的尺寸和对齐 与 clang 和 Metal 着色器编译器 相匹配
接下来 如往常一样分配缓冲区 如果缓冲区的存储模式是 Managed 或 Shared 可将缓冲区的指针 强制转换为结构类型 最后 将法线成员 设置为 gpuAddress 如果需要, 再加上对齐 GPU 内存所需的地址偏移
有一点要强调的是 结构声明 如何在 Metal 着色语言 和 C 语言声明之间改变 在这个例子中 这些是独立的 但如果您愿意 可以在 共享头文件上只做一次结构声明 使用条件编译来区分 着色器编译器类型 和 C 语言类型 这是 C 语言中的统一声明 __METAL_VERSION__ 宏只在 编译着色器代码时定义 用它在头文件声明中 区分 GPU 和 CPU 代码 如果您的 App 以 C++ 为目标 可将其更进一步 用模板来统一声明
看下参数缓冲区 示例代码的最佳实践方法 你可以这样写一个结构 但您也可以用无限数组 来写入多个结构 您可能在 Metal 中已经通过参数编码器 实现了无限数组 但 Metal 3 进一步简化了流程 使其可以仅填写一个结构数组
这就是与写入 一个结构之间的区别 您现在需要为您想要存储的 所有结构分配足够的存储空间 然后 循环访问数组 为每个结构写入数据
回到代码示例 首先 扩展缓冲区大小 以便存储场景中 所有网格的结构 这与您在 CPU 缓冲区的所做的 是完全一样的 用网格数量乘以结构大小 我想要花点时间 看下这有多强大 这一个变量完全控制了 数组的大小 着色器完全不需要 向 Metal 着色器编译器 声明该大小 而且可随意索引任何位置 这就是 Metal 中无绑定模型 如此灵活的部分原因 因为您可以编写着色器 毫无约束地访问任何大小的数组 真的很好用
接下来 分配这个大小的缓冲区 将指向内容的指针强制转换为 正确的结构类型
现在缓冲区已经足够大了 可以通过简单的循环 按照网格结构的大小递进 最后 直接设置数组中 每个结构的 GPUAddress 以及根据需要添加对齐偏移
从 GPU 端的着色器来说 这是代表无限数组的 一种方法 这里 我将其声明为网格指针参数 传送到着色器
这样它可以 如所有 C 语言数组一样 直接自由访问内容
另一个选项是将所有无限数组 放入一个结构 这可以通过在单一位置聚合数据 保持着色器整洁 在这个例子中 所有网格和材料 都统一在一个场景结构中
使用该场景结构 场景可通过绑定一个缓冲区 直接传递到着色器 而不是独立传送 每个无限数组
访问也如往常一样 现在 可以通过场景结构 获取网格数组了 这就是在 Metal 3 中写入 参数缓冲区和无限数组的方法 完整修订的 API 现在 让其更直观 与您在 CPU 结构或结构数组中 的做法相匹配 通过今年的光线追踪更新 光线追踪加速结构可 与您的缓冲区和纹理一起 通过 Metal 堆分配
这意味着它们可以彼此聚合在一起 也可以与其它资源类型聚合 这就很好 因为如果您将 所有加速结构聚合到堆 就可以用 useHeap 在单次调用中 将它们全部标记为常驻 这在您 App 的渲染线程中 可极大地节约 CPU
这是一些在堆中 使用加速结构的技巧 首先 从堆中配置时 加速结构在对齐和大小方面 有一定的要求 且因设备而异 这是一项新的查询 查看堆分配的加速结构的 大小和对齐 使用 MTLDevice 的 heapAccelerationStructureSize andAlignWithDescriptor 方法 为结构描述符 确定 SizeAndAlignment 要记住 这和 MTLDevice 设备中的 accelerationStructureSizes WithDescriptor 方法 是不同的
现在加速结构 在 MTLHeap 对象中了 调用 useHeap: 通过一次调用 让它们都成为常驻 这比为每个独立资源 调用 useResource 更快 记住 除非您选择堆为 风险跟踪 Metal 不会防止 资源的竞态条件 所以您需要同步彼此之间的 加速结构构建 且与光线追踪运行同步 不过不用担心 我稍后会再详细阐述这部分
记得要查看今年的 “Maximize your Metal ray tracing performance” 讲座 以获得更多关于 这个话题和 Metal 3 其它 光线追踪性能改进的信息 使用堆分配的加速结构 在必要的时候 让你有机会减少 App 的 CPU 使用率 最后 这是我今年最喜欢的 功能之一 即着色器验证增强功能
在 useResource 和 useHeap 的话题中 非常重要的一点是 App 为 Metal 对所有间接访问资源标注驻留 如果忘了这一操作意味着 支持这些资源的存储页面 不一定会在渲染时间出现 这可能会导致指令缓冲失败 GPU 重启或甚至图像损坏 不幸的是 这些问题在开启了 无绑定流程期间很常遇到 因为在无绑定中 场景资源的大部分 是间接访问的 着色器在运行期间 做出指针遍历决策 今年 Metal 3 推出了全新的 着色器验证层功能 可帮助您追踪 指令缓冲执行过程中 未驻留的资源 我给大家看一个具体的例子 在混合渲染 App 的 更新过程中 我们有时会遇到反射错误的 现实问题 我给大家演示下验证层 是如何帮助诊断和修正问题的
要向 Metal 标记驻留 App 在加载期间将所有独立的 不是分配在堆上的 资源存入一个可变集合 App 添加缓冲区 添加纹理 在渲染期间 在 App 发送 光线追踪核心程序前 它向 Metal 示意使用 集内的所有资源 这是一个简单的流程 App 在遍历集合 在每个元素上 调用 useResource 随后 Metal 在开始 光线追踪工作前 将所有资源设为驻留 这是 App 将资源 加入集合的部分代码 App 将其作为参数缓冲区 写入流程的一部分 App 的加载函数 遍历每个子网格 它抓取所需要的数据 写入参数缓冲区 即索引数据 材料的纹理数据 然后将索引缓冲区地址 存入参数缓冲区 而在材料方面 它查看纹理数组 将纹理 GPU 资源 ID 写入参数缓冲区 最后 它将子网格材料中 所有独立纹理 添加到 sceneResources 集 从而在发送的时候 将它们标记为驻留
不幸的是 这里有一个 小 bug App 运行指令缓冲区 在某些情况下 反射会丢失 之前 这很难追踪 现在 在 Metal 3 中 着色器验证层可以帮上大忙 这种问题现在会在 指令缓冲执行期间生成错误 示意错误的内容 错误信息会指示 触发问题的着色器名称 通道名称 metal 文件和检测到访问的 代码行 甚至是缓冲区标签和大小 以及它未驻留的事实 作为一个专业建议 标记 Metal 对象 总是最佳实践 工具使用标签 在尝试识别 调试您 App 的对象时很有用 手上有了这些细节信息 现在就很容易在着色器代码中 找到丢失的资源了 更好的是 当调试断点启用后 Xcode 很方便地展示了 着色器验证检测到问题的 具体着色器代码行 在 demo App 中 索引缓冲区没有驻留 修正方法就很直接了 回到代码 App 现在将丢失的索引缓冲区 存储到了驻留资源集中 有了这些调整 在稍后的光线追踪时间内 Metal 知道要让索引缓冲区 对于 GPU 可用 从而解决问题 这是一个很必要的工具 也是一个游戏改变者 这能在您无绑定旅程中 大大节约了潜在的调试时间 所以这些就是 Metal 3 带来的 管理和引用 无绑定资源的增强功能 现在我要换个话题 跟大家分享下在无绑定过程中 如何最大化游戏性能 在这一部分 我会讲两个话题 非持有资源及 未追踪资源 这些技巧可以帮助您 在有长期和聚合的资源时 可获得更好的 CPU 和 GPU 性能 现在我们来看下如何通过 长期资源提高 CPU 性能 我先与大家回顾下 Metal 资源的生命周期 Objective-C 和 Swift 通过 引用计数处理对象生命周期 Metal 资源沿袭了这一模型 资源的 retainCount 始于 1 在所有强引用消失后 运行时会释放它们 因为 CPU 和 GPU 是并行操作的 如果 CPU 在 GPU 还在使用时 就允许 retainCount 达到 0 并释放这个资源 将会导致问题
为了避免这一问题 Metal 指令缓冲区为其使用的 所有资源创建了强引用 确保 retainCount 最少为 1 Metal 为您直接绑定至管线的 资源创建了强引用 如通过 setVertexBuffer 或 setFragmentTexture 这些函数 也还包括渲染附件 您通过 useHeap API 标记为 驻留的 Metal 堆对象 以及您通过 useResource API 设为驻留的间接资源 即使它们是堆的一部分 您可查看今年的 “Program Metal in C++ with metal-cpp” 讲座 以了解更多关于 Mental 对象 生命周期的信息 现在 Metal 创建这些引用 是非常有用的 因为作为程序设计员来说 您无需担心 可能释放了 GPU 正在使用的对象 Metal 为您提供的这种安全保证 可以很快执行 但也还是会带来一个小小的 CPU 成本 在无绑定模型中 Apps 将资源聚合为堆 这些应该是长期的 与应用范围相匹配 例如 在游戏中 资源 在整个关卡的持续时间都是活跃的 在这种情况下 针对资源的 生命周期 Metal 无需提供额外的保证 那您可以通过让 Metal 指令缓冲器不要保持 它们到资源的引用 来收回 CPU 成本
要关闭 Metal 的自动保持 资源引用计数的功能 只要创建一个非持有引用的 指令缓冲区 您可以直接从 MTLCommandQueue 来完成 如同您创建常规指令缓冲区一样 您不需要对 App 做出任何改变 只要您已确保了资源生命周期 要记住这个设置的粒度级别 是整个指令缓冲区 它要么持有所有引用资源 或要么完全不持有
在小规模基准测试中 仅仅通过转换为非持有引用的 指令缓冲区 CPU 使用率在指令缓冲区的 生命周期就减少了 2% 但这些时间完全用在了 创建和摧毁不必要的强引用上
总的来说 非持有资源 在您已经确保了资源生命周期时 提供了节约额外 CPU 的机会 与非持有资源相似 非跟踪资源 提供了一个禁用安全功能 获取更多性能的机会 有许多视觉技巧都需要 先渲染到中间纹理和写入缓存区 并在后续的通道中使用 阴影映射 蒙皮和后期处理 都是很好的例子 现在 生成并立即消费资源 会带来写完后再读的风险 此外 如多个通道 写到同一个资源中 如两条渲染通道 相继绘制到同一个附件中 或两个位块传输编码器 写入同一个资源中 由于 Metal 在 GPU 上 调度工作的方式 会产生写完后再写的风险 当您使用被跟踪资源时 Metal 自动使用 同步原语以避免 GPU 时间线上的风险 比如 Metal 让 GPU 等到 写入缓冲区的 计算蒙皮通道结束后 再启动读取同样缓冲区的 场景渲染通道
这非常好 正因为如此 Metal 被认为是 易于接受的图形 API 但对于聚合资源到堆的 App 来说 还是有一些性能考虑的
思考下这个示例 这个 GPU 正在运行中 相继绘制两帧 包含顶点蒙皮 渲染场景 应用色调映射 GPU 在 App 的指示下持续运行 Metal 基于资源依赖关系 发现渲染和计算工作 可重叠的机会 如没有对应的依赖关系 条件也合适 Metal 会重叠调度工作 并行运行 这能让 GPU 的工作饱和 在同样的时间内 能完成更多工作
现在 App 将资源聚合到堆时 所有子资源都以一个整体 出现在 Metal 前 因此堆的协作更高效 但这意味着 Metal 看到读写工作是在同一资源上 且必须谨慎计划 以避免竞态条件 哪怕并没有实际风险存在时
如您所料 这个情况称为“伪共享” 它增加了 GPU 工作 执行的持续时间 所以有一个性能方面的小技巧 如果您知道堆中的资源 没有依赖关系 那您可以避免这一行为
要避免伪共享 您可将资源 排除在风险追踪之外 直接向 Metal 示意 细粒度依赖关系 您通过将资源描述符的 hazardTracking 设置为 Untracked 从而将资源追踪排除 因为这太重要了 所以这是堆的默认设置 它允许您解锁更多 GPU 得以立刻 并行运行工作的机会 一旦您开始使用非追踪资源 您要使用以下原语 传达依赖关系 基于不同的情况 使用 Fences Events Shared Events 或 Memory Barriers Metal Fences 可以为 同一指令队列内 不同的渲染和计算通道间 访问一个或更多资源做同步 这是一种分离屏障式的原语 因此消费者通道会等到 生产者发出 Fence 信号
您唯一需要记住的要求是 当使用 Fences 时 就是先提交或入队 生产者指令缓冲区 再到消费者指令缓冲区 当您无法保证顺序 或是为同一设备上 多个队列来同步时 可以使用 MTL Events 使用 Events 消费者者指令缓冲区 等待生产者的指令缓冲区 发出指定数值的 Event 信号 在其发出数值信号后 就可安全读取资源 使用 Events 来提示 GPU 暂停工作 直至指令发出 Event 信号 MTLSharedEvents 与常规 Events 行为非常相似 但工作范围更大 可以超越单独 GPU 工作 使用这些来同步不同 Metal 设备之间的 资源访问 甚至包括 CPU 例如 使用 Shared Events 来 处理 GPU 取自 CPU 的 计算结果 以下是示例 这个例子中的 GPU 用计算通道为网格蒙皮 CPU 存储姿态到磁盘 因为有两个独立的设备 使用 Shared Event 让 CPU 等待 直到 GPU 生成资源 起初 CPU 无条件地开始等待 GPU 发出 Shared Event 信号 当 GPU 生成资源 将其放置于统一内存中时 它发出 Shared Event 信号 在这时 CPU 的等待线程唤醒 安全使用资源
最后一种原语类型 是 Memory Barriers Memory Barriers 强迫所有 单一渲染或计算通道中的 后续指令等待 直到之前的所有指令完成 在大部分情况下 barrier 的成本 与 Fence 的成本接近 然而 只有一个例外
这个例外就是渲染通道中 片元阶段后的 barriers 这些 barriers 成本非常高 相当于打断了渲染通道 Metal 在 Apple GPUs 上 禁用片元阶段后的 barriers 从而帮助您的 Apps 保持在最快的驱动路径 如果您在 Apple GPUs 上 在片元阶段后添加 barrier Metal 调试层甚至会生成 验证错误 推荐使用 Fence 来 同步片元阶段后资源访问
以下是同步原语的简短总结 以及该何时使用它们 最好使用 Fences 以确保成本最低 它适合提交和入队的工作 在同一指令队列 以先生成再消费的顺序情况下 Fences 对大多数常用情况来说 是很好的 当提交指令无法确定顺序时 或当有多个指令队列时 使用 Metal Events Shared Events 允许 多 GPUs 相互之间 或与 CPU 同步 只在这些特定的 多设备情况下来使用它们 在通道内的同步场景 最好使用 Memory Barriers Barriers 是大部分案例下的 快速原语 如并发的计算通道 及 draw call 之间的顶点阶段 但温馨提示下 在通道间的 片元阶段后同步 使用 Fence 而不是 barrier 因为这些 barriers 成本很高 Apple GPUs 并不允许
使用非跟踪资源及 手动细粒度追踪 您现在可以在最大化 GPU 并行时 拥有数据聚合的所有优势 这些是通过无绑定 充分利用 CPU 和 GPU 提升性能的技巧 对于 Metal 3 如何解锁简化 和高效的无绑定工作流 我今天说了很多 但写代码只是等式的一半 另一半是这些可用的工具 如何帮助您验证 GPU 是如何看待 和执行工作的 现在我们有请 Mayur 来为大家分享下 Metal 3 的 无绑定工具有哪些更新 Mayur: 谢谢 Alè 今天 很高兴能为大家演示 Metal Debugger 的一些 强大的新功能 帮助您调试 和优化无绑定 Apps 我用 Alè 刚刚给您看的 混合渲染 App 中 抓取的一帧为例 当您在 Metal Debugger 中 抓到一帧 您会先看到 Summary 页面 给您提供帧概览 以及如何提升 App 性能的 帮助建议 但今天 我很高兴地问您展示 一个全新的依赖关系图 要打开它 您只需点击 左边的 Dependencies 这是新的依赖关系图 其特点在于全新功能带来的 全新的设计 依赖关系图将您的 工作负荷 用基于图形的方式来展示 图形中的每个节点 都代表一个通道 由一个指令编码器编码 和它的输出资源 边缘展现了通道之间的 资源依赖 通过今年新推出的功能 您可以根据两种依赖关系 来分析您的工作负荷 数据流和同步 实线代表数据流 它们为您展示了 数据在您 App 上是如何流动的 虚线代表同步 它们展示了通道之间 进行 GPU 同步的依赖关系 您可以点击任意编码器 资源或边缘来了解更多信息 调试器会在新的侧边栏为您展示 许多详细信息 例如 这一边缘添加了同步 且在这些通道间有数据流 默认情况下依赖关系图 同时展示数据流 和同步依赖关系 但您可以最底部的菜单 来查看一个依赖类型 这里 我只查看同步 如 Alè 刚才所说 伪共享是在追踪堆里 读写不同资源的常见问题 依赖关系图让捕捉这些问题 变得更简单 我抓取的这一示例 来自早期的开发版本 正是出现了该问题 如果我点击这个堆 依赖关系图会显示 该堆已被追踪 因此在两条通道之间添加同步 依赖关系图也强调了 在堆内部分配的资源 如这个渲染编码器存储的 渲染目标纹理 以及计算编码器读取和写入的 缓冲区 问题在于 两条通道之间的同步 并不必要 因为计算编码器没有使用 之前编码器中的任何资源 要移除该依赖关系 我可以调整 App 以使用非跟踪堆 在同步需要的地方插入 Fences 通过这一调整 这两条通道 现在可并行运行了 Xcode 14 中另一个改进 帮助调试您的无绑定 App 是最新的资源清单 我可以导航到想要调试的 draw call 并打开它 当使用无绑定时 数百个甚至数千个资源 在 GPU 任意时间都是可用的 今年 Metal 调试器为您提供了 检查 draw call 访问的是 哪个资源的能力 只要点击顶上的 “Accessed” 模式即可 现在调试器只展示了 draw call 访问的 少数资源 以及每个访问的类型 这对于理解您的着色器 从参数缓冲区访问了 哪些资源非常有用 知道您的 draw call 使用了 哪些资源 这样太好了 但如果它只展示了 非您预期的资源 您可以使用着色器调试器 来看下是什么情况 要启动着色器调试器 只要点击底部工具栏的 调试按钮 选择您要调试的像素 点击调试按钮 现在您已进入着色器调试器 着色器调试器展示了 您的代码是如何逐行执行的 包括访问了哪个资源 在这些行中 着色器从参数缓冲区读取纹理 我可将详细视图扩展到右侧栏 查看读取的是哪个资源 这可帮助识别您的着色器访问了 哪个错误的参数缓冲区元素 在这个 demo 中 我问大家展示了 如何使用新的依赖关系视图 来分析和验证资源依赖关系 如何使用新的资源清单 来理解 draw call 访问了 哪个资源 以及如何使用着色器调试器 来逐行分析 着色器是如何执行的 我已经迫不及待看看大家 是如何使用这些新功能 来创建强大的 Metal 无绑定 Apps 了 交回给您 Alè Alè: 谢谢 Mayur 非常了不起的 demo 总结一下 Metal 3 为无绑定带来了许多改进 通过简化参数缓冲区编码 分配在堆上的加速结构 提升验证层和工具 Metal 3 是一个优秀的 API 能为您的游戏和 App 带来有效和高性能的无绑定 通过今年的增强功能 混合渲染 App 比之前更好了 我们将它公布在了 Metal 示例代码库中 有更新版本 App 的 全部源码 您可以下载 学习和修改 作为练习 我给大家一个考验 将其更进一步 为镜像表面增加递归 我等不及看看您能用这个功能 来做什么了 Metal 3 迎来了前所未有的 无绑定时代 感谢大家的观看
-
-
5:38 - Write argument buffers in Metal 3
// Write argument buffers in Metal 3 struct Mesh { uint64_t normals; // 64-bit uint for constant packed_float3* }; NSUInteger meshArgumentSize = sizeof(struct Mesh); id<MTLBuffer> meshArgumentBuffer = [device newBufferWithLength:meshArgumentSize options:storageMode]; struct Mesh* meshes = (struct Mesh *)(meshArgumentBuffer.contents); meshes->normals = normalBuffer.gpuAddress + normalBufferOffset;
-
6:31 - // Shader struct:
// Shader struct: struct Mesh { constant packed_float3* normals; }; // Host-side struct: struct Mesh { uint64_t normals; };
-
6:53 - Shared struct:
// Shared struct: #if __METAL_VERSION__ #define CONSTANT_PTR(x) constant x* #else #define CONSTANT_PTR(x) uint64_t #endif struct Mesh { CONSTANT_PTR(packed_float3) normals; };
-
7:53 - Write unbounded arrays of resources in Metal 3
// Write unbounded arrays of resources in Metal 3 struct Mesh { uint64_t normals; // 64-bit uint for constant packed_float3* }; NSUInteger meshArgumentSize = sizeof(struct Mesh) * meshes.count; id<MTLBuffer> meshArgumentBuffer = [device newBufferWithLength:meshArgumentSize options:storageMode]; struct Mesh* meshes = (struct Mesh *)(meshArgumentBuffer.contents); for ( NSUInteger i = 0; i < meshes.count; ++i ) { meshes[i].normals = normalBuffers[i].gpuAddress + normalBufferOffsets[i]; }
-
9:03 - Metal shading language: unbounded arrays option 1
// Metal shading language: struct Mesh { constant packed_float3* normals; }; fragment half4 fragmentShader(ColorInOut v [[stage_in]], constant Mesh* meshes [[buffer(0)]] ) { /* determine mesh to read, e.g. geometry_id */ packed_float3 n0 = meshes[ geometry_id ].normals[0]; packed_float3 n1 = meshes[ geometry_id ].normals[1]; packed_float3 n2 = meshes[ geometry_id ].normals[2]; /* interpolate normals and calculate shading */ }
-
9:25 - Metal shading language: unbounded arrays option 2
// Metal shading language: struct Mesh { constant packed_float3* normals; }; struct Scene { constant Mesh* meshes; // mesh array constant Material* materials; // material array }; fragment half4 fragmentShader(ColorInOut v [[stage_in]], constant Scene& scene [[buffer(0)]] ) { /* determine mesh to read, e.g. geometry_id */ packed_float3 n0 = scene.meshes[ geometry_id ].normals[0]; packed_float3 n1 = scene.meshes[ geometry_id ].normals[1]; packed_float3 n2 = scene.meshes[ geometry_id ].normals[2]; /* interpolate normals and calculate shading */ }
-
11:00 - Size and alignment for MTLAccelerationStructure in a MTLHeap
heapAccelerationStructureSizeAndAlignWithDescriptor:
-
13:49 - Store individual indirect resources in NSMutableSet
// Argument buffer loading for (NSUInteger i = 0; i < mesh.submeshes.count; ++i) { Submesh* submesh = mesh.submeshes[i]; id<MTLBuffer> indexBuffer = submesh.indexBuffer; NSArray* textures = submesh.textures; // Copy index buffer into argument buffer submeshAB[i].indices = indexBuffer.gpuAddress; // Copy material textures into argument buffer for (NSUInteger m = 0; m < textures.count; ++m) { submeshAB[i].textures[m] = textures[m].gpuResourceID; } // Remember indirect resources [sceneResources addObject:indexBuffer]; [sceneResources addObjectsFromArray:textures]; }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。