OpenGL错误和性能Tips
1. 接口使用不当
1)GLES中的glAAx 形式的接口使用,glTranslatex,glRotatex,glScalex等函数。
float posx = 100.0f, posy = 100.0f, posz = 100.0f;
glTranslatef(posx, posy, posz);
//等价于
int fpX = (int)(posx * 65536), fpY = (int)(posy * 65536), fpZ = (int)(posz * 65536);
glTranslatex(fpX, fpY, fpZ);
2. GLEnum使用不当
错误做法:为深度缓冲区创建一个GL_DEPTH_COMPONENT24格式的RenderBuffer;为模板缓冲区创建一个GL_STENCIL_INDEX格式的RenderBuffer。
正确做法:模板、深度 共用一个RenderBuffer,而且格式是GL_DEPTH24_STENCIL8。具体参见:http://www.linuxidc.com/Linux/2014-03/98792.htm
2)获取模型视图矩阵用GL_MODELVIEW_MATRIX而不是GL_MODELVIEW,获取投影视图矩阵用GL_PROJECTION_MATRIX而不是GL_PROJECTION;
3. 隐晦的逻辑问题
解决方法:glFrontFace( GL_CW / GL_CCW )修改默认配置。
2)关闭深度测试,导致混合失效??
public void setRenderer(Renderer renderer) {
checkRenderThreadState();
if (mEGLConfigChooser == null) { // here
mEGLConfigChooser = new SimpleEGLConfigChooser(true);
}
if (mEGLContextFactory == null) {
mEGLContextFactory = new DefaultContextFactory();
}
if (mEGLWindowSurfaceFactory == null) {
mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
}
mGLThread = new GLThread(renderer);
mGLThread.start();
}
/**
* This class will choose a RGB_565 surface with
* or without a depth buffer.
*
*/
private class SimpleEGLConfigChooser extends ComponentSizeChooser {
public SimpleEGLConfigChooser(boolean withDepthBuffer) {
super(5, 6, 5, 0, withDepthBuffer ? 16 : 0, 0);
}
}
4. gl状态
1)上次适配AntTweakBar GLES时,它库中EndDraw函数结束绘制时将当前矩阵堆栈设为TEXTURE_MATRIX,下次进入渲染函数时在BeginDraw中各种尝试修改模型视图失效实际修改的都是纹理矩阵,glGetError返回也为0。
调试:glVertexPointer上传顶点,禁掉VertexArray,ColorArray,TextureArray后调用glDrawElements不会crash,说明问题出在上面这三个状态设置,进一步检查发现上传顶点中只有位置和颜色,但是GL_TEXTURE_ARRAY没有禁掉。所以才会出现随机性crash。
5. 性能Tips
TextureAtlas思想,一系列Icon静态打包到一个资源中,通过纹理坐标索引不同的资源。纹理烘焙思想。
2)避免纹理动态申请、释放,地图渲染中涉及大量的瓦片,而且他们的格式和尺寸都一致。旧做法:glTexImage2D创建纹理,淘汰瓦片时glDeleteTextures删除瓦片纹理。改进后的做法:淘汰瓦片时glTexSubImage2D用新的瓦片内容替换就瓦片显存内容。
// 所有item同步做动画
glScale(scalex, scaley, scalez);
batch_draw_100_itmes();
// 不同步动画
// V1 通过opengl做动画
for (int cursor = 0; cursor < 100; cursor++)
{
glScale3fv(items[cursor].scaleVar);
items[cursor].single_draw_item();
}
// V2 CPU对顶点进行计算,然后批量绘制
for (int cursor = 0; cursor < 100; cursor++)
{
cpu_scale_vertices(items[cursor].scaleVar);
}
batch_draw_100_items();
当每个item动画个异步执行时,V1的实现item缩放过度依赖于opengl,而且没法实现批处理! V2牺牲点CPU计算性能换来GPU的批量绘制。
通过glReadPixels获取帧缓存区内容,导致GPU中断,效率非常低。网上有一种PBO异步方式获取帧缓存的做法效率不错,适合PC。
通过glCopyTexImage2D将帧缓区内容拷内到纹理,会导致渲染中断,如下图十分耗时。替代做法:将纹理与FBO绑定,直接渲染到纹理,RTT。
大纹理切换开销也十分大,手机端一般别超过1024*1024,不同手机支持纹理最大尺寸可以通过接口查询。
相关阅读: