
GLThread核心:guardedRun函数
在Android OpenGL ES渲染体系中,GLThread是承载OpenGL渲染逻辑的核心线程,而guardedRun()则是GLThread的“心脏”——它掌控着EGL上下文/表面的生命周期、渲染回调的触发时机、线程状态的流转,甚至决定了整个OpenGL渲染流程的稳定性。
本文将从核心定位、设计思想、流程拆解到实际应用,全方位解析guardedRun()函数。
核心定位与作用
guardedRun()是GLThread类的私有核心方法,声明为:
private void guardedRun() throws InterruptedException
它的核心使命是管理OpenGL渲染的全生命周期,具体职责可归纳为4点:
简单来说,所有与OpenGL渲染相关的“调度”和“资源管理”逻辑,几乎都集中在这个函数中。
核心设计思想
guardedRun()的设计遵循两个关键原则,也是理解它的核心:
1. 事件驱动 + 状态机
函数内部通过“双层循环 + 标记位”实现状态机逻辑:
- 外层无限循环:作为渲染线程的主循环,直到mShouldExit标记为true时退出;
- 内层循环:优先处理事件队列(mEventQueue)、更新线程状态(暂停/恢复、Surface变化等),直到满足“可绘制”条件(readyToDraw()返回true);
- 标记位驱动:通过mHaveEglContext/mHaveEglSurface/lostEglContext等布尔标记,跟踪EGL资源和线程状态,避免重复操作或状态混乱。
2. 线程安全:全局锁同步
整个核心逻辑包裹在sGLThreadManager的同步块中:
synchronized (sGLThreadManager) { ... }
sGLThreadManager是GLThread的全局管理器锁,保证多线程(如主线程、渲染线程)对EGL资源、状态标记的操作互斥,避免竞态条件。
核心流程拆解
我们将guardedRun()的执行流程拆解为6个核心阶段,结合关键代码逻辑逐一解析:
阶段1:初始化与变量声明
函数开头会初始化EGL辅助类,并声明一系列状态标记变量,这些变量是“状态机”的核心:
// 初始化EGL辅助类(封装eglCreateContext/eglCreateSurface等底层操作)
mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);
// EGL资源状态标记
mHaveEglContext = false; // 是否拥有EGL上下文
mHaveEglSurface = false; // 是否拥有EGL表面
// 渲染通知标记
mWantRenderNotification = false;
// 其他核心标记(略)
boolean createEglContext = false; // 是否需要创建EGL上下文
boolean lostEglContext = false; // EGL上下文是否丢失
关键细节:mGLSurfaceViewWeakRef是GLSurfaceView的弱引用——避免渲染线程持有View强引用导致内存泄漏,这是Android线程设计的经典实践。
阶段2:内层循环:状态更新与事件处理
内层循环是“状态预处理”阶段,核心做4件事:
1. 处理退出与事件队列
优先检查退出标记,再处理外部提交的事件(如主线程触发的“请求渲染”指令):
if (mShouldExit) { return; } // 退出线程
if (! mEventQueue.isEmpty()) {
event = mEventQueue.remove(0);
break; // 取出事件,跳出内层循环执行
}
2. 处理暂停/恢复逻辑
同步“请求暂停状态”(mRequestPaused)与“当前暂停状态”(mPaused),暂停时释放EGL表面/上下文(可选):
if (mPaused != mRequestPaused) {
pausing = mRequestPaused;
mPaused = mRequestPaused;
// 暂停时释放EGL表面
if (pausing && mHaveEglSurface) { stopEglSurfaceLocked(); }
// 暂停时可选释放EGL上下文(由mPreserveEGLContextOnPause控制)
if (pausing && mHaveEglContext && !preserveEglContextOnPause) {
stopEglContextLocked();
}
}
3. 处理Surface丢失/重建
SurfaceView的Surface可能因系统回收、Activity生命周期变化丢失,函数会及时检测并释放EGL资源:
// Surface丢失:释放EGL表面,标记“等待Surface重建”
if ((! mHasSurface) && (! mWaitingForSurface)) {
if (mHaveEglSurface) { stopEglSurfaceLocked(); }
mWaitingForSurface = true;
}
// Surface重建:重置等待标记
if (mHasSurface && mWaitingForSurface) {
mWaitingForSurface = false;
}
4. 线程等待:无操作时进入休眠
若没有事件、不满足可绘制条件,线程会释放锁并进入等待状态,避免空轮询消耗CPU:
sGLThreadManager.wait();
只有当外部调用notifyAll()(如Surface重建、收到渲染请求)时,线程才会被唤醒。
阶段3:判断可绘制条件(readyToDraw())
内层循环的核心出口是readyToDraw()返回true,该方法的判断逻辑(简化):
private boolean readyToDraw() {
return !mPaused // 未暂停
&& mHasSurface // Surface已存在
&& !mSurfaceIsBad // Surface未失效
&& mRequestRender; // 有渲染请求
}
满足条件后,函数会触发EGL资源创建(上下文/表面),并跳出内层循环执行渲染。
阶段4:EGL资源创建
这是渲染前的“准备工作”,分两步:
1. 创建EGL上下文
if (! mHaveEglContext) {
mEglHelper.start(); // 内部调用eglCreateContext/eglMakeCurrent
mHaveEglContext = true;
createEglContext = true; // 标记需要触发onSurfaceCreated
}
2. 创建EGL表面
if (mHaveEglContext && !mHaveEglSurface) {
mHaveEglSurface = true;
createEglSurface = true; // 标记需要创建EGL表面
createGlInterface = true;// 标记需要创建GL10接口对象
}
EGL表面创建完成后,会通过mFinishedCreatingEglSurface标记通知其他线程。
阶段5:触发渲染回调(核心渲染逻辑)
EGL资源准备完成后,函数会按顺序触发Renderer的三大回调:
1. onSurfaceCreated:初始化OpenGL资源
if (createEglContext) {
view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
createEglContext = false;
}
仅在EGL上下文首次创建时触发,适合初始化纹理、着色器、投影矩阵等全局资源。
2. onSurfaceChanged:适配Surface尺寸
if (sizeChanged) {
view.mRenderer.onSurfaceChanged(gl, w, h);
sizeChanged = false;
}
Surface尺寸变化(如屏幕旋转、View大小调整)时触发,适合设置视口(glViewport)、调整投影矩阵。
3. onDrawFrame:逐帧渲染
view.mRenderer.onDrawFrame(gl);
这是最核心的渲染逻辑入口,每帧都会执行——开发者的绘制代码(如绘制三角形、纹理贴图)都写在这里。
阶段6:缓冲区交换与错误处理
渲染完成后,需要将后台缓冲区的内容交换到前台显示(即“刷屏”):
int swapError = mEglHelper.swap(); // 内部调用eglSwapBuffers
switch (swapError) {
case EGL10.EGL_SUCCESS:
break; // 交换成功
case EGL11.EGL_CONTEXT_LOST:
lostEglContext = true; // 上下文丢失,后续重建
break;
default:
// Surface失效,标记后触发重建
mSurfaceIsBad = true;
break;
}
关键细节:EGL上下文丢失(EGL_CONTEXT_LOST)是高频异常(如系统内存不足),函数会标记lostEglContext,后续自动重建上下文和表面,保证渲染不中断。
阶段7:资源清理(finally块)
无论函数因何退出(正常退出/异常),finally块都会释放EGL资源,避免内存泄漏:
finally {
synchronized (sGLThreadManager) {
stopEglSurfaceLocked(); // 释放EGL表面
stopEglContextLocked(); // 释放EGL上下文
}
}
实际开发中的关键应用与问题排查
理解guardedRun()的逻辑,能快速定位OpenGL渲染的常见问题:
1. 渲染卡顿:检查线程等待与事件队列
若渲染卡顿,可排查:
- 事件队列(mEventQueue)是否堆积大量耗时操作;
- readyToDraw()是否频繁返回false(如Surface频繁丢失、暂停状态异常);
- onDrawFrame是否执行耗时操作(如复杂计算),阻塞渲染线程。
2. EGL上下文丢失:定位资源重建逻辑
若日志中出现egl context lost,说明guardedRun()检测到上下文丢失并触发重建,需检查:
- 是否开启mPreserveEGLContextOnPause(暂停时保留上下文);
- 设备内存是否充足(系统会回收后台App的EGL上下文);
- onSurfaceCreated是否正确重新初始化OpenGL资源(上下文丢失后需重新加载纹理/着色器)。
3. Surface创建失败:检查createSurface逻辑
若mEglHelper.createSurface()返回false,会标记mSurfaceIsBad,需排查:
- SurfaceView的Surface是否已销毁;
- EGL配置(mEglConfig)是否与Surface匹配;
- 权限是否缺失(如android.permission.WAKE_LOCK)。
总结
guardedRun()是Android OpenGL渲染的“总调度器”,其核心价值在于:





