【问题标题】:Why does glGetTexImage transfer all mipmap textures even if only the 1x1 mipmap level is requested?为什么即使只请求 1x1 mipmap 级别,glGetTexImage 也会传输所有 mipmap 纹理?
【发布时间】:2012-09-16 22:40:50
【问题描述】:

我在 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 吗?

【问题讨论】:

  • 如何生成mipmap? glGenerateMipmap,我猜?
  • "完成该行代码所需的时间取决于纹理的 0 级 mipmap 的大小。"您如何测量它?
  • @ChristianRau:是的,我在 glGetTexImage 之前使用 glGenerateMipmap。
  • @NicolBolas:我使用 boost::timer 类来测量线路何时完成。这并不完全准确,每次测试的时间略有不同,但因为它慢了 12 倍,所以我并不真正关心精度。 glGenerateMipmap( GL_TEXTURE_2D ); float *fPixel = new float[4]; Timer.resume(); glGetTexImage(GL_TEXTURE_2D, highestMipMapLevel, GL_RGBA, GL_FLOAT, fPixel); Timer.stop();
  • @lenn 由于 GPU 操作的异步性,您的时间测量很可能完全是垃圾。您可能正在测量glGenerateMipmaps(或一系列其他先前的操作),一旦CPU 调用glGenerateMipmaps 返回,就不必完成这些操作。尝试在glGetTexImage(或简单的glFinish)之前插入一个栅栏事件点,以等待任何先前GPU操作完成以实际测量glGetTexImage(当然仅用于测量目的,请勿在生产代码)。

标签: opengl gpu gpgpu render-to-texture


【解决方案1】:
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 与大多数渲染命令一样,在它返回时实际上还没有完成。事实上,它甚至没有开始的可能性很大。这很好,因为它allows OpenGL to run independently of the CPU. You issue a rendering command, and it completes sometime later.

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

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

更重要的是,如果你想异步读取像素数据,你需要do the read into a buffer object. 这可以让 OpenGL 避免 CPU 停顿,但只有在你有其他工作可以在同时。

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

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

【讨论】:

  • 在所有计时器调用之前使用 glFinish 测量现在完全有意义,我实际上正在测量 3 次渲染调用到 FBO,我总是发现它的速度非常快;)非常感谢!现在我只需要测试它是否更快地将大纹理带到 CPU 并在渲染下一个纹理时计算那里的平均像素值,或者 mipmap 计算是否是更快的方法:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-06
  • 2019-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多