0

我在 FBO 中渲染到浮点纹理,并且需要 CPU 上该纹理的所有像素的平均值。所以我认为使用 mipmapping 来计算 1x1 mipmap 的平均值非常方便,因为我节省了 CPU 计算时间,我只需要将 1 个像素传输到 CPU,而不是 1024x1024 像素。

所以我使用这条线:

glGetTexImage(GL_TEXTURE_2D, variableHighestMipMapLevel, GL_RGBA, GL_FLOAT, fPixel);

但尽管我只特别要求最高的 mipmap 级别,它的大小始终为 1x1 像素,但完成该行代码所需的时间取决于纹理的级别 0 mipmap 的大小。这对我来说毫无意义。例如,在我的测试中,1024x1024 基础纹理的这条线比 32x32 基础纹理花费的时间大约长 12 倍。

fPixel 中的结果是正确的,只包含想要的像素,但时间清楚地表明整个纹理集被转移,这对我来说是主要的原因,因为转移到 CPU 显然是我的瓶颈。

我使用 Win7 和 opengl 并在 ATI Radeon HD 4800 和 GeForce 8800 GTS 上进行了测试。

有谁知道这个问题,或者有一种聪明的方法只将最高 mipmap 的一个像素传输到 CPU?

4

1 回答 1

3
glGenerateMipmap( GL_TEXTURE_2D );
float *fPixel = new float[4];
Timer.resume();
glGetTexImage(GL_TEXTURE_2D, highestMipMapLevel, GL_RGBA, GL_FLOAT, fPixel);
Timer.stop();

让这成为您的一个教训:始终提供完整的信息。

它花费 12 倍的时间是因为您正在测量生成mipmap 所需的时间,而不是将 mipmap 传输到 CPU 所需的时间。glGenerateMipmap,像大多数渲染命令一样,在它返回时实际上并没有完成。事实上,它甚至还没有开始的可能性很大。这很好,因为它允许 OpenGL 独立于 CPU 运行。您发出一个渲染命令,它会在稍后的某个时间完成。

但是,当您开始从该纹理读取时,OpenGL 必须停止 CPU 并等待所有将接触该纹理的内容完成。因此,您的时间是测量对纹理执行所有操作所需的时间以及将数据传回的时间。

如果您想要更准确的测量,请在启动计时器glFinish 之前发出 a。

更重要的是,如果要执行像素数据的异步读取,则需要读取缓冲区对象。这允许 OpenGL 避免 CPU 停顿,但它仅在您有其他工作可以同时进行时才有用。

例如,如果您这样做是为了计算 HDR 色调映射的场景的整体照明,您应该对前一帧的场景数据执行此操作,而不是当前的。没有人会注意到。所以你渲染一个场景,生成mipmaps,读入一个缓冲区对象,然后渲染下一帧的场景,生成mipmaps,读入一个不同的缓冲区对象,然后开始从前一个场景的缓冲区中读取。

这样,当您开始读取前一次读取的结果时,它们实际上会在那里,并且不会发生 CPU 停顿。

于 2012-09-25T16:51:32.010 回答