我正在尝试在 OpenGL 中执行 SSBO 数据的读回。为此,我坚持映射 SSBO,但以下代码实际上并未从示例计算着色器中读回写入的数据:
std::int32_t value = 12u;
GLuint ssbo = 0u;
glCreateBuffers(1u, &ssbo);
glNamedBufferStorage(ssbo, sizeof(value), &value, GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT);
const auto* ptr = reinterpret_cast<const std::int32_t*>(glMapNamedBuffer(ssbo, GL_READ_WRITE));
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
glDispatchCompute(1, 1, 1);
glFinish();
glMemoryBarrier(GL_ALL_BARRIER_BITS);
std::memcpy(&value, ptr, sizeof(value));
printf("Value: %d\n", value);
计算着色器如下所示:
#version 460
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout (std430, binding = 0) writeonly buffer resBuf { int res[]; };
void main()
{
res[0] = 25;
}
值的预期结果应该是 25,但是我仍然得到初始值 12。
glFinish
和 GL_ALL_BARRIER_BITS
只是为了确保同步不是问题。
现在,当我切换
glMapNamedBuffer
和 glBindBufferBase
的顺序时,我确实得到了正确的读回结果 - 也就是说,在 AMD GPU 上。在这两种情况下,回读都可以在 Nvidia GPU 上运行。
我注意到
glBindBuffer
的文档指出“缓冲区对象在第一次绑定后立即的状态是未映射的零大小内存缓冲区[...]”。但是,我使用的是 DSA,大多数操作几乎不需要显式绑定缓冲区,并且 glCreateBuffers
还指出它创建了一个新的缓冲区对象“[...],就好像它已绑定到未指定的目标一样。”
这是 AMD GL 实现的错误还是我遗漏了什么?存在一个简单的解决方法(只需将缓冲区绑定到虚假目标),但我仍然需要澄清。
持久映射缓冲区时,必须持久映射缓冲区。使用持久标志分配缓冲区只会告诉系统您“可以”持久地映射它。持久映射要求映射调用本身声明缓冲区正在被持久映射。
所以glMapNamedBufferRange