使用glReadPixels(...)在三星S9设备上出现黑屏问题
碰到这种特定设备的OpenGL问题确实头疼,我给你整理几个针对性的排查方向,你可以一个个试:
确认帧缓冲区绑定状态:有时候在渲染流程中可能切换到了自定义的FBO,调用
glReadPixels前别忘了切回默认帧缓冲区,执行glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)。另外也可以显式指定读取的缓冲区:glReadBuffer(GL_BACK),确保读的是后台渲染缓冲区。核对读取参数的正确性:OpenGL的坐标原点是左下角,而安卓屏幕是左上角,你有没有把y坐标搞反?比如应该用
screenHeight - y - height来计算读取的起始y位置?还有检查glReadPixels的格式和类型是否和当前帧缓冲区匹配,比如如果当前缓冲区是GL_RGBA8,那用GL_RGBA和GL_UNSIGNED_BYTE才对,别用了不兼容的格式。把握调用时机:一定要在渲染命令全部执行完、还没调用
eglSwapBuffers之前调用glReadPixels!有些设备(包括三星的)在交换缓冲区后,后台缓冲区的内容会被清空,这时候读就只能得到黑色。另外可以在调用前加个glFinish(),强制等待所有OpenGL命令执行完毕,避免异步渲染导致的读取时机过早。适配三星设备的特殊优化:三星的GPU可能默认开启了一些帧压缩或者延迟渲染的优化,导致
glReadPixels拿不到正确数据。你可以试试在EGL配置的时候,选择不带压缩的颜色格式,或者设置EGL的交换行为为EGL_BUFFER_PRESERVED,这样交换后后台缓冲区内容会保留。另外也可以尝试在AndroidManifest里给对应的Activity加上android:hardwareAccelerated="false"(如果你的OpenGL上下文是和Activity绑定的话),看看是不是硬件加速的锅。检查像素存储对齐:默认的
GL_PACK_ALIGNMENT是4,如果你的屏幕宽度不是4的倍数,可能会导致读取的像素数据偏移,看起来全黑。可以在调用glReadPixels前执行glPixelStorei(GL_PACK_ALIGNMENT, 1),强制按字节对齐,避免这个问题。尝试替代读取方案:如果上面的都不行,可以换个思路,比如创建一个离屏FBO,把渲染内容先画到FBO的纹理上,然后读取这个纹理的像素(用
glGetTexImage),这种方式有时候能绕过设备的底层限制。或者用EGL的eglCopyBuffers函数,把帧缓冲区内容复制到一个Surface,再从Surface提取像素数据。
内容的提问来源于stack exchange,提问作者user1254938

