buffer - 为什么在 Metal 中不允许从片段着色器中写入缓冲区?

标签 buffer fragment-shader metal

Metal Shading Language Guide 中所述:

Writes to a buffer or a texture are disallowed from a fragment function.


我知道情况确实如此,但我很好奇为什么。能够从片段着色器中写入缓冲区非常有用;我知道在硬件端可能更复杂,不提前知道特定线程的内存写入的结束位置,您并不总是知道原始缓冲区写入,但这是 Metal 计算中公开的功能着色器,那么为什么不在片段着色器中呢?
附录
我应该澄清为什么我认为来自片段函数的缓冲区写入很有用。在光栅化管道的最常见使用情况下,三角形被光栅化和着色(根据片段着色器)并写入预定义的内存位置,在每次片段着色器调用之前已知,并由标准化设备坐标和帧的预定义映射确定缓冲。这适合大多数用例,因为大多数时候您只想将三角形​​直接渲染到缓冲区或屏幕。
在其他情况下,您可能希望在片段着色器中进行延迟写入,其结束位置基于片段属性而不是片段的确切位置;有效地,具有副作用的光栅化。例如,大多数基于 GPU 的体素化的工作方式是从某个理想的角度使用正交投影渲染场景,然后写入 3D 纹理,将片段的 XY 坐标及其关联的深度值映射到 3D 纹理中的某个位置。这是描述 here .
其他用途包括某些形式的与顺序无关的透明度(透明,其中绘制顺序不重要,允许重叠透明对象)。一种解决方案是使用多层帧缓冲区,然后在单独的 channel 中根据它们的深度值对片段进行排序和混合。由于没有硬件支持这样做(在大多数 GPU 上,我相信英特尔有硬件加速),您必须维护原子计数器和每个像素的手动纹理/缓冲区写入,以协调写入分层帧缓冲区。
另一个例子可能是通过光栅化为 GI 提取虚拟点光源(即在光栅化时为相关片段写出点光源)。在所有这些用例中,都需要从片段着色器写入缓冲区,因为 ROP 只为每个像素存储一个结果片段。在没有此功能的情况下获得等效结果的唯一方法是通过某种方式的深度剥离,这对于高度复杂的场景来说非常慢。
现在我意识到我给出的例子并不是特别关于缓冲区写入,而是更普遍地关于从片段着色器写入动态内存的想法,最好是支持原子性。缓冲区写入似乎是一个简单的问题,它们的包含将对改善这种情况大有帮助。
由于我在这里没有得到任何答案,所以我结束了 posting the question on Apple's developer forums .我在那里得到了更多反馈,但仍然没有真正的答案。除非我遗漏了什么,似乎几乎所有正式支持 Metal 的 OS X 设备都有对此功能的硬件支持。据我了解,这个功能在 2009 年左右首次出现在 GPU 中。它是当前 DirectX 和 OpenGL 的共同功能(甚至不考虑 DX12 或 Vulkan),因此 Metal 将是唯一缺少它的“尖端”API .
我意识到 PowerVR 硬件可能不支持此功能,但 Apple 通过功能集区分 Metal Shading Language 没有问题。例如,iOS 上的 Metal 允许在片段着色器中进行“免费”帧缓冲区获取,这在硬件中由高速缓存的 PowerVR 架构直接支持。此功能直接在 Metal Shading Language 中体现出来,因为它允许您使用 [[color(m)]] 声明片段函数输入。 iOS 着色器的属性限定符。可以说允许使用 device 声明缓冲区存储空间限定符,或带有 access::write 的纹理,作为片段着色器的输入,对语言的语义变化不会比苹果为 iOS 优化所做的更大。因此,就我而言,PowerVR 缺乏支持并不能解释我在 OS X 上寻找的功能的缺失。

最佳答案

现在支持从片段着色器写入缓冲区,如中所述
What’s New in iOS 10, tvOS 10, and macOS 10.12

Function Buffer Read-Writes Available in: iOS_GPUFamily3_v2, OSX_GPUFamily1_v2

Fragment functions can now write to buffers. Writable buffers must be declared in the device address space and must not be const. Use dynamic indexing to write to a buffer.



此外,指定限制的行(来自原始问题)不在 Metal Shading Language Specification 2.0

关于buffer - 为什么在 Metal 中不允许从片段着色器中写入缓冲区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34459972/

相关文章:

node.js - 将流写入缓冲区对象

opengl-es - GLSL OpenGL ES 2.0 (iOS) 中有噪声函数吗?

android - Metal 和所有其他 c++ 平台共有哪些 c++ 数据类型

swift - 如何从 MTKView 无缝切换到 UIView 显示

vim - 用粘贴缓冲区的内容替换单词?

c - 为什么 C 中没有检测到分隔符\n?

c - 字 rune 件和 block 文件的区别

opengl-es - 使用片段着色器在二维多边形上绘制边框

opengl-es - 警告 X3550 : array reference cannot be used as an l-value

swift - Abysmal Metal 渲染速度