通过在同一着色器中多次绑定SSBO通过将其绑定

发布于 2025-01-28 18:29:29 字数 1752 浏览 2 评论 0原文

播放无绑定渲染,我有一个大静态SSBO,可以容纳我的顶点数据。这些顶点作为连续数组包装在内存中,其中每个顶点具有以下布局:

|               Position (floats)               | Normal (snorm shorts) |  Pad  |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|      P.x      |      P.y      |      P.z      |  N.x  |  N.y  |  N.z  |       |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|     float     |     float     |     float     |     uint      |     uint      |

请注意,每个顶点如何为20个字节 / 5“单词” / 1.25 vec4 < / code> s。 GPU并不是一个圆形的数字。因此,我选择“手动”解开数据包装数据。

顶点着色器:

...

layout(std430, set = 0, binding = 1)
readonly buffer FloatStaticBuffer
{
    float staticBufferFloats[];
};

layout(std430, set = 0, binding = 1) // Using the same binding?!
readonly buffer UintStaticBuffer
{
    uint staticBufferUInts[];
};

...

void main()
{
    const uint vertexBaseDataI = gl_VertexIndex * 5u;

    // Unpack position
    const vec3 position = vec3(
        staticBufferFloats[vertexBaseDataI + 0u],
        staticBufferFloats[vertexBaseDataI + 1u],
        staticBufferFloats[vertexBaseDataI + 2u]);

    // Unpack normal
    const vec3 normal = vec3(
        unpackSnorm2x16(staticBufferUInts[vertexBaseDataI + 3u]),
        unpackSnorm2x16(staticBufferUInts[vertexBaseDataI + 4u]).x);

    ...
}

能够将缓冲区“别名”作为floatuint数据非常方便。

问题:是这样一个可怕的想法“使” ssbo“混音”,我只是很幸运,还是这实际上是一个有效的选择,可以跨平台使用?

替代方法:

  • 仅使用一个缓冲区,例如staticBufferuints,然后使用uintbitStofloat提取位置。没什么大不了的,但性能费用很小?
  • 在CPU上两次将相同的缓冲液结合到两个不同的结合。再说一次,没什么大不了的,只是有点烦人。

Playing around with bindless rendering, I have one big static SSBO that holds my vertex data. The vertices are packed in memory as a contiguous array where each vertex has the following layout:

|               Position (floats)               | Normal (snorm shorts) |  Pad  |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|      P.x      |      P.y      |      P.z      |  N.x  |  N.y  |  N.z  |       |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|     float     |     float     |     float     |     uint      |     uint      |

Note how each vertex is 20 bytes / 5 "words" / 1.25 vec4s. Not exactly a round number for a GPU. So instead of doing a bunch of padding and using uneccessary memory, I have opted to unpack the data "manually".

Vertex shader:

...

layout(std430, set = 0, binding = 1)
readonly buffer FloatStaticBuffer
{
    float staticBufferFloats[];
};

layout(std430, set = 0, binding = 1) // Using the same binding?!
readonly buffer UintStaticBuffer
{
    uint staticBufferUInts[];
};

...

void main()
{
    const uint vertexBaseDataI = gl_VertexIndex * 5u;

    // Unpack position
    const vec3 position = vec3(
        staticBufferFloats[vertexBaseDataI + 0u],
        staticBufferFloats[vertexBaseDataI + 1u],
        staticBufferFloats[vertexBaseDataI + 2u]);

    // Unpack normal
    const vec3 normal = vec3(
        unpackSnorm2x16(staticBufferUInts[vertexBaseDataI + 3u]),
        unpackSnorm2x16(staticBufferUInts[vertexBaseDataI + 4u]).x);

    ...
}

It is awfully convenient to be able to "alias" the buffer as both float and uint data.

The question: is "aliasing" a SSBO this way a terrible idea, and I'm just getting lucky, or is this actually a valid option that would work across platforms?

Alternatives:

  • Use just one buffer, say staticBufferUInts, and then use uintBitsToFloat to extract the positions. Not a big deal, but might have a small performance cost?
  • Bind the same buffer twice on the CPU to two different bindings. Again, not a big deal, just slightly annoying.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夢归不見 2025-02-04 18:29:29

只要没有从中读取错误的值,Vulkan就可以使不兼容的资源在内存中别名。 读到也允许它 - 您应该只得到垃圾。但是,我现在找不到标准的部分。

(实际上,我认为即使您从无效的部分中 标准,“内存混叠”部分:

否则,别名解释了内存的内容
换句话说,并通过一个别名写入记忆的内容
部分或完全不确定其他别名。 如果第一个别名是宿主访问的子资源,那么受影响的字节是根据其寻址方案编写的字节。如果第一个别名不可访问,则字节,则字节
受影响的是由图像子资源重叠的
书面。如果第二个别名是宿主访问的子资源,则
受影响的字节变得不确定。如果第二个别名不是
可访问的主机,所有稀疏图像块(用于稀疏
部分驻留图像)或所有图像子资源(对于非SPARSE
图像和完全驻留的稀疏图像)与受影响的影响重叠
字节变得不确定。

请注意,该标准讨论字节被编写并在混乱资源中变得不确定。这不是整个资源变得无效。

让我们这样看看:您有两个混叠的SSBO(实际上只是一个绑定了两次),具有不同的类型(float,short int)。您写入浮标的任何字节都在您写入缓冲区的那一刻的“ float View”中有效,而在“ int视图”中无效。 INT也是如此:它们所占据的字节在INT视图中已变得有效,但在浮点视图中无效。根据标准,这意味着两种观点都有无效的部分。但是,他们俩都没有完全无效。特别是,您关心的部分仍然有效,并且可以从中读取。

简而言之:允许。

Vulkan allows incompatible resources to alias in memory as long as no malformed values are read from it. (Actually, I think it's allowed even when you read from the invalid sections - you should just get garbage. But I can't find the section of the standard right now that spells this out. The Vulkan standard is way too complicated.)

From the standard, section "Memory Aliasing":

Otherwise, the aliases interpret the contents of the memory
differently, and writes via one alias make the contents of memory
partially or completely undefined to the other alias. If the first alias is a host-accessible subresource, then the bytes affected are those written by the memory operations according to its addressing scheme. If the first alias is not host-accessible, then the bytes
affected are those overlapped by the image subresources that were
written. If the second alias is a host-accessible subresource, the
affected bytes become undefined. If the second alias is not
host-accessible, all sparse image blocks (for sparse
partially-resident images) or all image subresources (for non-sparse
image and fully resident sparse images) that overlap the affected
bytes become undefined.

Note that the standard talks about bytes being written and becoming undefined in aliasing resources. It's not the entire resource that becomes invalid.

Let's see it this way: You have two aliasing SSBOs (in reality just one that's bound twice) with different types (float, short int). Any bytes that you wrote floats into became valid in the "float view" and invalid in the "int view" the moment you wrote into the buffer. The same goes for the ints: The bytes occupied by them have become valid in the int view but invalid in the float view. According to the standard, this means that both views have invalid sections in them; however, neither of them is fully invalid. In particular, the sections you care about are still valid and may be read from.

In short: It's allowed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文