众所周知,OpenGL的鲁棒性很强,ES也同样,一般不会crash,例如某些接口传的参数不是OpenGL预期的类型,也很少会发生crash。可是,一旦发生了crash或渲染异常,由于其本质上是一个状态机,就导致了错误会累计,发生crash的现场并非问题的源头,十分难定位。好比OpenGL会经常挂在drawcall上,然而很有可能是在前面的glBindTexture、glTexImage2D或glUniformMatrix等方法中出现了问题。故此,本文根据笔者遇到的OpenGL ES问题,包括crash或渲染异常,整理出一份OpenGL ES在iOS系统中的问题快速定位表单。
问题现象 | 根本原因及解决方法 |
---|---|
界面图片出现花屏 | 对于jpg图片解码后,以RGBA格式传入GPU纹理,需要添加alpha通道 |
glReadPixels crash,堆栈栈顶包含gldReadFramebufferData特征 | glReadPixels宽高参数大于实际宽高 |
使用OES_texture_half_float扩展时,发生渲染异常 | OES_texture_half_float使用时,需要在texImage2D改变internalFormat为GL_RGBA16F |
Fbo上有时有画面,有时黑屏 | 使用的纹理没有设置wrap_s和wrap_t参数 |
游戏画面背景闪烁 | 由于背景只画了一次,前景局部刷新,而2d游戏EAGLLayer的kEAGLDrawablePropertyRetainedBacking属性设置为false,导致没保留上一帧内容,而闪烁怀疑是iOS的双缓冲甚至三缓冲机制导致的 |
iOS9系统手机画面部分黑屏 | iOS 9使用glStencilFunc函数有问题,导致部分纹理没通过模板测试而黑屏,需要在调用该方法前调用glClearStencil(0xff)和glClear(GL_STENCIL_BUFFER_BIT) |
iOS9系统图片花屏 | iOS 9上使用CGContextDrawImage解码图片时会带上上一次解码的残影,即使是一个新的CGContext也会,需要在draw前clearRect |
glTexImage2D crash可能情况1 | 传入参数中宽高参数与pixels不对应,宽高大于pixels实际宽高时crash,小于时花屏 |
glTexImage2D crash可能情况2 | 之前调用glPixelStorei修改过GL_UNPACK_ALIGNMENT参数,假如GL_UNPACK_ALIGNMENT大小与glTexImage2D中pixels参数的单位像素字节数不符就会crash,这是很明显的累积错误引发的crash |
两个context交互时发生闪屏 | 两个context渲染时机不同步,需要使用glSync方法进行同步 |
两个context交互时发生部分纹理黑屏 | 两个context创建时没有共享shareGroup,导致纹理不共享,只能先传到CPU,再传给另一个context |
gldReadFramebufferData crash | 除了上面提到glReadPixels出问题的可能外,在内存不足情况下也会发生该crash,注意纹理等资源的及时释放 |
以上便是笔者到目前为止积累的OpenGL ES在iOS系统中常见问题的整理,后面假如遇到奇葩问题也会继续更新,而Android系统由于同样可以用OpenGL ES,问题可能也会有所类似,希望对大家定位OpenGL问题有所帮助。