我目前正在开发一个程序,该程序支持与深度无关(也称为与顺序无关)的alpha混合。为此,我实现了一个按像素的链接列表,使用标题的纹理(每个像素指向链接列表中第一个条目的点)和纹理缓冲区对象作为链接列表本身。虽然这可以正常工作,但我还是想与着色器存储缓冲区交换纹理缓冲区对象。
我想我差不多了,但是花了大约一个星期的时间,我才能真正使用着色器存储缓冲区。我的问题是:
为什么我不能映射着色器存储缓冲区?
为什么再次绑定着色器存储缓冲区是一个问题?
为了进行调试,我只显示着色器存储缓冲区的内容(尚不包含链接列表)。我通过以下方式创建了着色器存储缓冲区:
glm::vec4* bufferData = new glm::vec4[windowOptions.width * windowOptions.height];
glm::vec4* readBufferData = new glm::vec4[windowOptions.width * windowOptions.height];
for(unsigned int y = 0; y < windowOptions.height; ++y)
{
for(unsigned int x = 0; x < windowOptions.width; ++x)
{
// Set the whole buffer to red
bufferData[x + y * windowOptions.width] = glm::vec4(1,0,0,1);
}
}
GLuint ssb;
// Get a handle
glGenBuffers(1, &ssb);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssb);
// Create buffer
glBufferData(GL_SHADER_STORAGE_BUFFER, windowOptions.width * windowOptions.height * sizeof(glm::vec4), bufferData, GL_DYNAMIC_COPY);
// Now bind the buffer to the shader
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssb);
在着色器中,着色器存储缓冲区定义为:
layout (std430, binding = 0) buffer BufferObject
{
vec4 points[];
};
在渲染循环中,我执行以下操作:
glUseProgram(defaultProgram);
for(unsigned int y = 0; y < windowOptions.height; ++y)
{
for(unsigned int x = 0; x < windowOptions.width; ++x)
{
// Create a green/red color gradient
bufferData[x + y * windowOptions.width] =
glm::vec4((float)x / (float)windowOptions.width,
(float)y / (float)windowOptions.height, 0.0f, 1.0f);
}
}
glMemoryBarrier(GL_ALL_BARRIER_BITS); // Don't know if this is necessary, just a precaution
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, windowOptions.width * windowOptions.height * sizeof(glm::vec4), bufferData);
// Retrieving the buffer also works fine
// glMemoryBarrier(GL_ALL_BARRIER_BITS);
// glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, windowOptions.width * windowOptions.height * sizeof(glm::vec4), readBufferData);
glMemoryBarrier(GL_ALL_BARRIER_BITS); // Don't know if this is necessary, just a precaution
// Draw a quad which fills the screen
// ...
这段代码有效,但是当我用以下代码替换glBufferSubData时,
glm::vec4* p = (glm::vec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, windowOptions.width * windowOptions.height, GL_WRITE_ONLY);
for(unsigned int x = 0; x < windowOptions.width; ++x)
{
for(unsigned int y = 0; y < windowOptions.height; ++y)
{
p[x + y * windowOptions.width] = glm::vec4(0,1,0,1);
}
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
映射失败,返回GL_INVALID_OPERATION。似乎着色器存储缓冲区仍绑定到某些对象,因此无法进行映射。我读了一些有关glGetProgramResourceIndex(http://www.opengl.org/wiki/GlGetProgramResourceIndex)和glShaderStorageBlockBinding(http://www.opengl.org/wiki/GlShaderStorageBlockBinding)的书,但我确实不了解。
我的第二个问题是,为什么我既不能打电话
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssb);
,也不
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssb);
在glBufferSubData和glMemoryBarrier之后的渲染循环中。此代码不应更改任何事情,因为这些调用与创建着色器存储缓冲区的过程相同。如果无法绑定不同的着色器存储缓冲区,则只能使用一个。但是我知道支持多个着色器存储缓冲区,所以我认为我还缺少其他内容(例如“释放”缓冲区)。
首先,glMapBufferRange
失败是因为GL_WRITE_ONLY
它不是有效的参数。那是旧的glMapBuffer
,但是glMapBufferRange
使用标志的集合来进行更细粒度的控制。在您的情况下,您需要GL_MAP_WRITE_BIT
。而且,由于您似乎完全覆盖了整个缓冲区,而无需关心先前的值,因此可能需要进行其他优化GL_MAP_INVALIDATE_BUFFER_BIT
。因此,将该调用替换为:
glm::vec4* p = (glm::vec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0,
windowOptions.width * windowOptions.height,
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
问题中没有很好地描述另一个错误。但是先解决此问题,也许它会帮助解决以下错误。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句