我正在尝试实现自动曝光的HDR色调映射,我正在尝试降低成本,以找到我的场景的平均亮度,我似乎遇到了glReadPixels
的瓶颈。下面是我的设置:
1:我创建了一个下采样的FBO,以降低在仅使用GL_RED
值的GL_BYTE
格式使用glReadPixels
时的读取成本。
private void CreateDownSampleExposure() {
DownFrameBuffer = glGenFramebuffers();
DownTexture = GL11.glGenTextures();
glBindFramebuffer(GL_FRAMEBUFFER, DownFrameBuffer);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, DownTexture);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RED, 1600/8, 1200/8,
0, GL11.GL_RED, GL11.GL_BYTE, (ByteBuffer) null);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL11.GL_TEXTURE_2D, DownTexture, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
System.err.println("error");
} else {
System.err.println("success");
}
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
2:设置ByteBuffers并读取上面FBO纹理的纹理。
Setup(){
byte[] testByte = new byte[1600/8*1000/8];
ByteBuffer testByteBuffer = BufferUtils.createByteBuffer(testByte.length);
testByteBuffer.put(testByte);
testByteBuffer.flip();
}
MainLoop(){
//Render scene and store result into downSampledFBO texture
GL11.glBindTexture(GL11.GL_TEXTURE_2D, DeferredFBO.getDownTexture());
//GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RED, GL11.GL_BYTE,
//testByteBuffer); <- This is slower than readPixels.
GL11.glReadPixels(0, 0, DisplayManager.Width/8, DisplayManager.Height/8,
GL11.GL_RED, GL11.GL_BYTE, testByteBuffer);
int x = 0;
for(int i = 0; i <testByteBuffer.capacity(); i++){
x+= testByteBuffer.get(i);
}
System.out.println(x); <-Print out accumulated value of brightness.
}
//Adjust exposure depending on brightness.
问题是,我可以对我的FBO纹理进行100倍的下采样,所以我的glReadPixels
只读取16x10像素,并且几乎没有性能提升。没有下采样会有很大的性能提升,但是一旦我将宽度和高度除以8,它似乎就会下降。看起来仅仅调用这个函数就有很大的开销。在调用glReadPixels
时,我是否做错了什么或没有考虑到什么?
发布于 2015-09-30 15:32:19
glReadPixels速度很慢,因为它必须等到图形处理器完成所有渲染后才能给出结果。可怕的同步点。
让glReadPixels变得更快的一种方法是使用某种双/三重缓冲方案,这样你只需要在你期望图形处理器已经完成的渲染到纹理上调用glReadPixels。只有在您的应用程序中可以接受在接收glReadPixels结果之前等待几个帧的情况下,这才是可行的。例如,在视频游戏中,这种延迟可以被解释为对瞳孔对光照条件变化的反应时间的模拟。
但是,对于特定的色调映射示例,您可能只想计算平均亮度,以便将该信息反馈到GPU中以进行另一个渲染过程。不是glReadPixels,而是计算平均值,方法是将图像复制到使用线性过滤(框过滤器)连续半个大小的渲染目标,直到目标降到1x1。
1x1目标现在是包含平均亮度的纹理,并且可以在色调映射渲染过程中使用该纹理。没有同步点。
https://stackoverflow.com/questions/32857554
复制相似问题