在OpenGL/GLSL 4.3中读取和更新纹理缓冲区

Gou*_*fhg 6 c++ opengl glsl

我对此有点坚定,因为我没有真正弄错了什么不是.必须有一些我极度误解的东西,或者在代码或驱动程序中都存在某种错误.我上周在AMD Radeon 5850上运行了最新的催化剂beta驱动程序.

好的,我开始做一个OIT渲染实现,并希望使用保存在着色器存储缓冲区对象中的struct-array.好吧,那个中的索引在内存中反映/向前移动是错误的,我几乎认为这是一个驱动程序错误 - 因为他们刚刚开始支持这样的事情+是的,它是一个beta驱动程序.因此,我向后退了一个档位并使用了来自纹理缓冲区对象的glsl-images,我想至少有一段时间以来一直支持它们.

仍然表现不正常.所以我创建了一个简单的测试项目并且稍微摸了一下,现在我觉得我只是捏了一下这个东西.

好!首先,我初始化缓冲区和纹理.

//Clearcolor and Cleardepth setup, disabling of depth test, compile and link shaderprogram etc.
...
//
GLint tbo, tex;
datasize = resolution.x * resolution.y * 4 * sizeof(GLfloat);
glGenBuffers(1, &tbo);
glBindBuffer(GL_TEXTURE_BUFFER, tbo);
glBufferData(GL_TEXTURE_BUFFER, datasize, NULL, GL_DYNAMIC_COPY);
glBindBuffer(GL_TEXTURE_BUFFER, 0);

glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_BUFFER, tex);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, tex);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glBindImageTexture(2, tex, 0, GL_TRUE, 0, GL_READ_WRITE, GL_RGBA32F);
Run Code Online (Sandbox Code Playgroud)

然后渲染循环 - 更新并绘制,更新和绘制......两者之间有延迟,以便我有时间查看更新的作用.

更新是这样的...

ivec2 resolution; //Using GLM
resolution.x = (GLuint)(iResolution.x + .5f);
resolution.y = (GLuint)(iResolution.y + .5f);

glBindBuffer(GL_TEXTURE_BUFFER, tbo);
void *ptr = glMapBuffer(GL_TEXTURE_BUFFER, GL_WRITE_ONLY);
color *c = (color*)ptr; //color is a simple struct containing 4 GLfloats.
for (int i = 0; i < resolution.x*resolution.y; ++i)
{
  c[i].r = c[i].g = c[i].b = c[i].a = 1.0f;
}
glUnmapBuffer(GL_TEXTURE_BUFFER); c = (color*)(ptr = NULL);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
Run Code Online (Sandbox Code Playgroud)

平局是这样的...

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMemoryBarrier(GL_ALL_BARRIER_BITS);
ShaderProgram->Use(); //Simple shader program class
quad->Draw(GL_TRIANGLES); //Simple mesh class containing triangles (vertices) and colors
glFinish();
glMemoryBarrier(GL_ALL_BARRIER_BITS);
Run Code Online (Sandbox Code Playgroud)

我只是把一些记忆障碍放在一边更加确定,不应该伤害超过表现吗?好吧,无论如何,无论有没有障碍,结果都是一样的,所以...... :)

Shader程序是一个简单的传递顶点着色器和正在进行测试的片段着色器.

顶点着色器

#version 430

in vec3 in_vertex;

void main(void)
{
    gl_Position = vec4(in_vertex, 1.0);
}
Run Code Online (Sandbox Code Playgroud)

片段着色器(我猜这里并不需要连贯&memoryBarrier()因为我在CPU上执行绘制/片段着色器执行...但是它有害吗?)

#version 430

uniform vec2 iResolution;
layout(binding = 2, rgba32f) coherent uniform imageBuffer colorMap;

out vec4 FragColor;

void main(void)
{
    ivec2 res = ivec2(int(iResolution.x + 0.5), int(iResolution.y + 0.5));
    ivec2 pos = ivec2(int(gl_FragCoord.x + 0.5), int(gl_FragCoord.y + 0.5));
    int pixelpos = pos.y * res.x + pos.x;

    memoryBarrier();
    vec4 prevPixel = imageLoad(colorMap, pixelpos);

    vec4 green = vec4(0.0, 1.0, 0.0, 0.0);
    imageStore(colorMap, pixelpos, green);
    FragColor = prevPixel;
}
Run Code Online (Sandbox Code Playgroud)

期待:白屏!因为我在每次绘制之间写入"白色"到整个缓冲区,即使我在实际着色器中加载后向图像写入绿色.

结果:第一帧为绿色,其余为黑色.我的某些部分认为有一个白色的框架太快而无法看到,或者有一些vsync-thing的东西让它变得渺茫,但这是一个逻辑的地方?:P

好吧,然后我尝试了一个新的东西,并将更新块(我正在写"白色"到整个缓冲区)移动到init.

期望:白色的第一帧,然后是绿色屏幕.

结果:哦,是的它绿色好吧!即使第一帧有一些白色/绿色的文物,有时只有绿色.这可能是由于某些东西的(缺乏)vsync,没有检查出来.不过,我想我得到了我想要的结果.

我可以得出的结论是,我的更新中出现了问题.它是否从纹理参考中取消了缓冲区或其他东西?在那种情况下,第一帧是否正常并不奇怪?只有在第一个imageStore命令(嗯,第一帧)之后,纹理全部变黑 - "bind() - map() - unmap() - bind(0)"第一次工作,但之后不工作.我的glMapBuffer图片是它将缓冲区数据从GPU复制到CPU内存,让你改变它,Unmap将它复制回来.好吧,刚才我想也许它不会将缓冲区从GPU复制到CPU再返回,但只有一种方式?可能是GL_WRITE_ONLY应该更改为GL_READ_WRITE吗?好吧,我试过了两个.据说其中一个是正确的,使用那个时我的屏幕不会总是白色的"

ARGH,我做错了什么?

编辑:嗯,我仍然不知道......显然glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, tex);应该是glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, tbo);,但我认为tbo并且tex具有相同的价值,因为它们是以相同的顺序生成的.因此它在这个实现中起作用.我已经解决了这个问题,因为我认为上述内容应该有效,所以我对此并不满意.另一方面,新解决方案可能在性能方面更好一些.glMapBuffer()我没有使用,而是通过使用glBufferSubData()glgetBufferSubData()在CPU/GPU之间发送数据来切换到在CPU上保留tbo内存的副本.这很有用,所以我将继续使用该解决方案.

但是,是的,问题仍然存在 - 为什么不能glMapBuffer()使用我的纹理缓冲区对象?

小智 4

glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, tex); 应该是 glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, tbo);

也许还有其他问题,但这一点很突出。 https://www.opengl.org/wiki/Buffer_Texture