请注意,我在 ES 方面没有太多经验,因此在这种情况下可能有更好的方法来做这件事。不过,一般要点适用于普通 OpenGL 或 ES。
首先,最重要的性能考虑应该是在阅读时。如果您在渲染时从显卡请求数据,您的程序(CPU 端)将不得不暂停,直到显卡返回数据,由于您无法发出进一步的渲染命令,这将减慢渲染速度。作为一般规则,您应该始终上传、渲染、下载 - 不要混合使用这些过程中的任何一个,这会极大地影响速度,而且很大程度上取决于驱动程序/硬件/操作系统。
我建议在渲染周期结束时使用glReadPixels( )。我怀疑该功能的格式限制与帧缓冲区格式的限制有关。此外,你真的应该使用 8 位无符号或浮点,both of which are supported。如果您遇到不允许任何这些支持格式的特殊情况,您应该解释这是什么,因为可能有专门处理它的方法。
如果您在渲染的特定点(而不是结束)需要帧缓冲区的内容,请创建第二个纹理 + 帧缓冲区(同样格式相同)作为有效的“后缓冲区”,然后从目标复制该纹理的帧缓冲区。这发生在视频卡上,因此它不会直接读取总线延迟。这是我写的执行此操作的内容:
glActiveTexture( GL_TEXTURE0 + unit );
glBindTexture( GL_TEXTURE_2D, backbufferTextureHandle );
glBindFramebuffer( GL_READ_FRAMEBUFFER, framebufferHandle );
glCopyTexSubImage2D(
GL_TEXTURE_2D,
0, // level
0, 0, // offset
0, 0, // x, y
screenX, screenY );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, framebufferHandle );
然后,当您需要数据时,将后台缓冲区绑定到 GL_READ_FRAMEBUFFER 并在其上使用glReadPixels( )。
最后,您应该记住,下载数据仍然会停止 CPU 端。如果您在显示帧缓冲区之前下载,您将推迟显示图像,直到您可以再次执行命令,这可能会导致可见的延迟。因此,我建议您仍然使用非默认帧缓冲区,即使您只关心最终缓冲区状态,并结束渲染周期以达到以下效果:
(1.) Blit 到默认帧缓冲区:
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); // Default framebuffer
glBindFramebuffer( GL_READ_FRAMEBUFFER, framebufferHandle );
glBlitFramebuffer(
0, 0, screenX, screenY,
0, 0, screenX, screenY,
GL_COLOR_BUFFER_BIT,
GL_NEAREST );
(2.) 在您给定的情况下调用任何您的交换缓冲区命令。
(3.) 来自帧缓冲区的下载调用(可能是 glReadPixels( ) 或其他)。
至于 blit/texcopy 操作对速度的影响,它在大多数现代硬件上都相当不错,即使每帧执行 10 次以上,我也没有发现它有明显的影响,但如果您正在处理过时的硬件,这可能值得三思。