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

时间:2013-10-08 16:11:42

标签: c++ opengl glsl

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

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

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

OK!首先,我初始化缓冲区和纹理。

//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);

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

更新就是这样......

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);

抽奖就是这样......

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);

我只是放了一些内存障碍来确定,不应该伤害超过性能吗?好吧,无论如何,无论有没有障碍,结果都是一样的,所以......:)

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

顶点着色器

#version 430

in vec3 in_vertex;

void main(void)
{
    gl_Position = vec4(in_vertex, 1.0);
}

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

#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;
}

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

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

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

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

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

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

ARGH,我做错了什么?

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

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

1 个答案:

答案 0 :(得分:3)

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

也许还有其他错误,但这很突出。 https://www.opengl.org/wiki/Buffer_Texture