6

我对此有点疯狂,因为我真的不明白什么是错的,什么不是。一定是我严重误解了某些东西,或者代码或驱动程序中存在某种错误。截至上周,我正在使用最新的催化剂 beta 驱动程序在 AMD Radeon 5850 上运行它。

好的,我开始执行 OIT 渲染实现,并希望使用保存在着色器存储缓冲区对象中的结构数组。好吧,那个索引在内存中反映/向前移动是错误的,我几乎认为这是一个驱动程序错误 - 因为他们最近才开始支持这样的事情+是的,它是一个测试版驱动程序。因此,我向后移动了一个档次,并改用了纹理缓冲区对象中的 glsl 图像,我猜至少从前一段时间就已经支持了。

仍然表现不正确。所以我创建了一个简单的测试项目并摸索了一下,现在我想我只是捏了一下东西在哪里。

好的!首先我初始化缓冲区和纹理。

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

我只是设置了一些内存障碍以更加确定,不应该比性能更有害吗?好吧,不管有没有障碍,结果都是一样的,所以...... :)

着色器程序是一个简单的直通顶点着色器和进行测试的片段着色器。

顶点着色器

#version 430

in vec3 in_vertex;

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

片段着色器(我猜这里并不需要连贯和 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;
}

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

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

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

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

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

我可以得出的结论是我的更新有问题。它是从纹理参考中解开缓冲区还是什么?那样的话,第一帧没问题是不是很奇怪?只有在第一个 imageStore-command(嗯,第一帧)之后,纹理才会全黑——“bind()-map()-unmap()-bind(0)”第一次起作用,但之后就不行了。我对 glMapBuffer 的看法是,它将缓冲区数据从 GPU 复制到 CPU 内存,让您更改它,然后 Unmap 将其复制回来。好吧,刚才我想也许它不会将缓冲区从GPU复制到CPU然后再复制回来,但只有一种方式?可能是应该更改为 GL_READ_WRITE 的 GL_WRITE_ONLY 吗?嗯,我都试过了。据说其中一个是正确的,我的屏幕在使用那个时不会总是在“

啊,我做错了什么?

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

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

4

1 回答 1

3

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

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

于 2014-02-27T18:27:22.010 回答