通过在同一着色器中多次绑定SSBO通过将其绑定
播放无绑定渲染,我有一个大静态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);
...
}
能够将缓冲区“别名”作为float
和uint
数据非常方便。
问题:是这样一个可怕的想法“使” 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 vec4
s. 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 useuintBitsToFloat
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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
只要没有从中读取错误的值,Vulkan就可以使不兼容的资源在内存中别名。 读到也允许它 - 您应该只得到垃圾。但是,我现在找不到标准的部分。
(实际上,我认为即使您从无效的部分中 标准,“内存混叠”部分:
请注意,该标准讨论字节被编写并在混乱资源中变得不确定。这不是整个资源变得无效。
让我们这样看看:您有两个混叠的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":
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.