GLSurfaceView 源码分析 & EGL 创建过程
Posted 月盡天明
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GLSurfaceView 源码分析 & EGL 创建过程相关的知识,希望对你有一定的参考价值。
文章目录
- GLSurfaceView 源码分析
GLSurfaceView 源码分析
基本用法
mGLView.setEGLContextClientVersion(2);
//在setRenderer之前,可以调用以下方法来进行EGL设置
//mGLView.setEGLConfigChooser(); //颜色、深度、模板等等设置
//mGLView.setEGLWindowSurfaceFactory(); //窗口设置
//mGLView.setEGLContextFactory(); //EGLContext设置
//设置渲染器,渲染主要就是由渲染器来决定
mGLView.setRenderer(new GLSurfaceView.Renderer()
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
// surface被创建后需要做的处理
@Override
public void onSurfaceChanged(GL10 gl, int width, int height)
// 渲染窗口大小发生改变的处理
@Override
public void onDrawFrame(GL10 gl)
// 执行渲染工作
);
// RENDERMODE_WHEN_DIRTY表示被动渲染
// RENDERMODE_CONTINUOUSLY表示持续渲染*/
mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
GLSurfaceView 继承自 SurfaceView,实现了SurfaceHolder.Callback2 接口。
SurfaceHolder.Callback
使用 SurfaceView 的时候都会用到这个 Callback 回调。
一共有三个函数
- surfaceCreated
- surfaceChanged
- surfaceDestroyed
public interface Callback
/**
* 当 surface 首次创建的时候回调
*/
public void surfaceCreated(SurfaceHolder holder);
/**
* 当 surface 的 format 或者 size 发生改变时回调此函数。
* 在回调surfaceCreated()之后,该函数至少被回调一次
*/
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height);
/**
* 在 surface 被销毁之前回调。此函数回调之后就不能在访问 surface 了。
*/
public void surfaceDestroyed(SurfaceHolder holder);
SurfaceHolder.Callback2
- surfaceRedrawNeeded
- surfaceRedrawNeededAsync
这两个函数并不常用。
/**
* SurfaceHolder.Callback的扩展接口
*/
public interface Callback2 extends Callback
/**
* Called when the application needs to redraw the content of its
* surface, after it is resized or for some other reason. By not
* returning from here until the redraw is complete, you can ensure that
* the user will not see your surface in a bad state (at its new
* size before it has been correctly drawn that way). This will
* typically be preceeded by a call to @link #surfaceChanged.
*
* As of O, @link #surfaceRedrawNeededAsync may be implemented
* to provide a non-blocking implementation. If @link #surfaceRedrawNeededAsync
* is not implemented, then this will be called instead.
*
* @param holder The SurfaceHolder whose surface has changed.
*/
void surfaceRedrawNeeded(SurfaceHolder holder);
/**
* An alternative to surfaceRedrawNeeded where it is not required to block
* until the redraw is complete. You should initiate the redraw, and return,
* later invoking drawingFinished when your redraw is complete.
*
* This can be useful to avoid blocking your main application thread on rendering.
*
* As of O, if this is implemented @link #surfaceRedrawNeeded will not be called.
* However it is still recommended to implement @link #surfaceRedrawNeeded for
* compatibility with older versions of the platform.
*
* @param holder The SurfaceHolder which needs redrawing.
* @param drawingFinished A runnable to signal completion. This may be invoked
* from any thread.
*
*/
default void surfaceRedrawNeededAsync(SurfaceHolder holder, Runnable drawingFinished)
surfaceRedrawNeeded(holder);
drawingFinished.run();
继续查看 GLSurfaceView的关键代码:
public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback2
private static final GLThreadManager sGLThreadManager = new GLThreadManager(); // 线程管理类
private final WeakReference<GLSurfaceView> mThisWeakRef =
new WeakReference<GLSurfaceView>(this);
private GLThread mGLThread; // GL 线程
private Renderer mRenderer; // GLSurfaceView 的回调接口
private boolean mDetached;
private EGLConfigChooser mEGLConfigChooser;
private EGLContextFactory mEGLContextFactory;
private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
private GLWrapper mGLWrapper;
private int mDebugFlags;
private int mEGLContextClientVersion;
private boolean mPreserveEGLContextOnPause;
public GLSurfaceView(Context context)
super(context);
init();
/**
* Standard View constructor. In order to render something, you
* must call @link #setRenderer to register a renderer.
*/
public GLSurfaceView(Context context, AttributeSet attrs)
super(context, attrs);
init();
private void init()
SurfaceHolder holder = getHolder();
holder.addCallback(this);
// 设置渲染接口
public void setRenderer(Renderer renderer)
checkRenderThreadState();
if (mEGLConfigChooser == null)
mEGLConfigChooser = new SimpleEGLConfigChooser(true);
if (mEGLContextFactory == null)
mEGLContextFactory = new DefaultContextFactory();
if (mEGLWindowSurfaceFactory == null)
mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
mRenderer = renderer;
mGLThread = new GLThread(mThisWeakRef);
mGLThread.start();
// 检查渲染线程状态
private void checkRenderThreadState()
if (mGLThread != null)
throw new IllegalStateException(
"setRenderer has already been called for this instance.");
/**
* 设置渲染模式
* @see #RENDERMODE_CONTINUOUSLY
* @see #RENDERMODE_WHEN_DIRTY
*/
public void setRenderMode(int renderMode)
mGLThread.setRenderMode(renderMode);
/**
* Override SurfaceHolder.Callback interface
*/
public void surfaceCreated(SurfaceHolder holder)
mGLThread.surfaceCreated();
/**
* Override SurfaceHolder.Callback interface
*/
public void surfaceDestroyed(SurfaceHolder holder)
// Surface will be destroyed when we return
mGLThread.surfaceDestroyed();
/**
* Override SurfaceHolder.Callback interface
*/
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
mGLThread.onWindowResize(w, h);
通过 checkRenderThreadState() 函数可以看出,setRender() 函数调用多次会导致 ::IllegalStateException:: 。
有几个关键的类:
- GLThreadManager
- GLThread
- Renderer
- EGLConfigChooser
- EGLContextFactory
- EGLWindowSurfaceFactory
- GLWrapper
- EglHelper
要了解这几个类的用途,先来说下 EGL 的创建过程。
GLSurfaceView内部管理一个 surface,用来负责 OpenGL 的渲染工作,
EGL
EGL 环境的创建过程如下图:
- 获取默认的显示设备
- 初始化显示设备
- 从系统中获取对应属性的配置
- 创建 EglContext
- 创建渲染的 Surface
- 绑定 EglContext 和 Surface 到显示设备中
- 刷新数据,显示渲染场景
初始化 EGL 环境通常使用 EGL10或者 EGL14。SDK版本大于17,优先使用 EGL14。
EGL10
创建EGL10环境的大概过程如下:
// 1. 获取 EGL 实例
val egl = EGLContext.getEGL() as EGL10
// 2. 获取默认的显示设备
val eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)
if (eglDisplay == EGL10.EGL_NO_DISPLAY)
// todo error
// 3. 初始化显示设备
val version = IntArray(2)
val initializeResult = egl.eglInitialize(eglDisplay, version)
if (!initializeResult)
// todo error
// 4. 设置显示设备的属性
val attributes = intArrayOf(
EGL10.EGL_RED_SIZE, 8,
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_ALPHA_SIZE, 8,
EGL10.EGL_DEPTH_SIZE, 8,
EGL10.EGL_STENCIL_SIZE, 8,
EGL10.EGL_RENDERABLE_TYPE, 4,
EGL10.EGL_NONE)
val configNum = IntArray(1)
var chooseResult = egl.eglChooseConfig(eglDisplay, attributes, null, 1, configNum)
if (!chooseResult)
// todo error
// 5. 从系统中获取对应属性的配置
val configs = arrayOfNulls<EGLConfig>(configNum[0])
chooseResult = egl.eglChooseConfig(eglDisplay, attributes, configs, configNum[0], configNum)
if (!chooseResult)
// todo error
// 6. 创建 EGLContext
val eglContext = egl.eglCreateContext(eglDisplay, configs[0], EGL10.EGL_NO_CONTEXT, null)
if (eglContext == EGL10.EGL_NO_CONTEXT)
// todo error
// 7. 创建渲染的 Surface
val eglSurface = egl.eglCreateWindowSurface(eglDisplay, configs[0], EGL10.EGL_NO_SURFACE, null)
if (eglSurface == EGL10.EGL_NO_SURFACE)
//todo error
// 8. 绑定 EGLContext 和 Surface 到显示设备上
val makeCurrentResult = egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)
if (makeCurrentResult)
// todo error
// do sth.
// 9. 刷新数据,显示渲染结果
val result = egl.eglSwapBuffers(eglDisplay, eglSurface)
if (!result)
// todo error
相关的类有
- EGLContext
- EGL
- EGL10
而 EGL10继承自 EGL,同时也是一个接口。通过 EGlContext获取到的 EGL 实例为什么是 EGL10呢?
通过 EGLContext 的源码可以看出,getEGL() 是一个com.google.android.gles_jni.EGLImpl 对象。
通过 http://androidxref.com 这个网址可以查看 Android 源码
对应接口的实现类的位置:
/frameworks/base/opengl/java/com/google/android/gles_jni/
Jni接口的位置: /frameworks/base/core/jni/com_google_android_gles_jni_EGLImpl.cpp
继续看 EGLImpl 的源码:
package com.google.android.gles_jni;
import javax.microedition.khronos.egl.*;
import android.graphics.SurfaceTexture;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
public class EGLImpl implements EGL10
private EGLContextImpl mContext = new EGLContextImpl(-1);
private EGLDisplayImpl mDisplay = new EGLDisplayImpl(-1);
private EGLSurfaceImpl mSurface = new EGLSurfaceImpl(-1);
public native boolean eglInitialize(EGLDisplay display, int[] major_minor);
public native boolean eglQueryContext(EGLDisplay display, EGLContext context, int attribute, int[] value);
public native boolean eglQuerySurface(EGLDisplay display, EGLSurface surface, int attribute, int[] value);
/** @hide **/
public native boolean eglReleaseThread();
public native boolean eglChooseConfig(EGLDisplay display, int[] attrib_list, EGLConfig[] configs, int config_size, int[] num_config);
public native boolean eglGetConfigAttrib(EGLDisplay display, EGLConfig config, int attribute, int[] value);
public native boolean eglGetConfigs(EGLDisplay display, EGLConfig[] configs, int config_size, int[] num_config);
public native int eglGetError();
public native boolean eglDestroyContext(EGLDisplay display, EGLContext context);
public native boolean eglDestroySurface(EGLDisplay display, EGLSurface surface);
public native boolean eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
public native String eglQueryString(EGLDisplay display, int name);
public native boolean eglSwapBuffers(EGLDisplay display, EGLSurface surface);
public native boolean eglTerminate(EGLDisplay display);
public native boolean eglCopyBuffers(EGLDisplay display, EGLSurface surface, Object native_pixmap);
public native boolean eglWaitGL();
public native boolean eglWaitNative(int engine, Object bindTarget);
/** @hide **/
public static native int getInitCount(EGLDisplay display);
public EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list)
long eglContextId = _eglCreateContext(display, config, share_context, attrib_list);
if (eglContextId == 0)
return EGL10.EGL_NO_CONTEXT;
return new EGLContextImpl( eglContextId );
public EGLSurface eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list)
long eglSurfaceId = _eglCreatePbufferSurface(display, config, attrib_list);
if (eglSurfaceId == 0)
return EGL10.EGL_NO_SURFACE;
return new EGLSurfaceImpl( eglSurfaceId );
public EGLSurface eglCreatePixmapSurface(EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list)
EGLSurfaceImpl sur = new EGLSurfaceImpl();
_eglCreatePixmapSurface(sur, display, config, native_pixmap, attrib_list);
if (sur.mEGLSurface == 0)
return EGL10.EGL_NO_SURFACE;
return sur;
public EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list)
Surface sur = null;
if (native_window instanceof SurfaceView)
SurfaceView surfaceView = (SurfaceView)native_window;
sur = surfaceView.getHolder().getSurface();
else if (native_window instanceof SurfaceHolder)
SurfaceHolder holder = (SurfaceHolder)native_window;
sur = holder.getSurface();
else if (native_window instanceof Surface)
sur = (Surface) native_window;
long eglSurfaceId;
if (sur != null)
eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
else if (native_window instanceof SurfaceTexture)
eglSurfaceId = _eglCreateWindowSurfaceTexture(display, config,
native_window, attrib_list);
else
throw new java.lang.UnsupportedOperationException(
"eglCreateWindowSurface() can only be called with an instance of " +
"Surface, SurfaceView, SurfaceHolder or SurfaceTexture at the moment.");
if (eglSurfaceId == 0)
return EGL10.EGL_NO_SURFACE;
return new EGLSurfaceImpl( eglSurfaceId );
public synchronized EGLDisplay eglGetDisplay(Object native_display)
long value = _eglGetDisplay(native_display);
if (value == 0)
return EGL10.EGL_NO_DISPLAY;
if (mDisplay.mEGLDisplay != value)
mDisplay = new EGLDisplayImpl(value);
return mDisplay;
public synchronized EGLContext eglGetCurrentContext()
long value = _eglGetCurrentContext();
if (value == 0)
return EGL10.EGL_NO_CONTEXT;
if (mContext.mEGLContext != value)
mContext = new EGLContextImpl(value);
return mContext;
public synchronized EGLDisplay eglGetCurrentDisplay()
long value = _eglGetCurrentDisplay();
if (value == 0)
return EGL10.EGL_NO_DISPLAY;
if (mDisplay.mEGLDisplay != value)
mDisplay = new EGLDisplayImpl(value);
return mDisplay;
public synchronized EGLSurface eglGetCurrentSurface(int readdraw)
long value = _eglGetCurrentSurface(readdraw);
if (value == 0)
return EGL10.EGL_NO_SURFACE;
if (mSurface.mEGLSurface != value)
mSurface = new EGLSurfaceImpl(value);
return mSurface;
private native long _eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list);
private native long _eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list);
private native void _eglCreatePixmapSurface(EGLSurface sur, EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list);
private native long _eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
private native long _eglCreateWindowSurfaceTexture(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
private native long _eglGetDisplay(Object native_display);
private native long _eglGetCurrentContext();
private native long _eglGetCurrentDisplay();
private native long _eglGetCurrentSurface(int readdraw);
native private static void _nativeClassInit();
static _nativeClassInit();
通过该类的继承关系可以看出,EGLContext.getEGL() 返回的对象就是 EGL10类型。
- EGLContextImpl
- EGLDisplayImpl
- EGLSurfaceImpl
EGLDisplayImpl
/frameworks/base/opengl/java/com/google/android/gles_jni/EGLDisplayImpl.java
package com.google.android.gles_jni;
import javax.microedition.khronos.egl.*;
public class EGLDisplayImpl extends EGLDisplay
long mEGLDisplay;
public EGLDisplayImpl(long dpy)
mEGLDisplay = dpy;
@Override
public boolean equals(Object o)
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EGLDisplayImpl that = (EGLDisplayImpl) o;
return mEGLDisplay == that.mEGLDisplay;
@Override
public int hashCode()
/*
* Based on the algorithm suggested in
* http://developer.android.com/reference/java/lang/Object.html
*/
int result = 17;
result = 31 * result + (int) (mEGLDisplay ^ (mEGLDisplay >>> 32));
return result;
EGLDisplayImpl 这个类本身没有什么特别的东西,直接继承了 EGLDisplay 。
public abstract class EGLDisplay
EGLSurfaceImpl
/frameworks/base/opengl/java/com/google/android/gles_jni/EGLSurfaceImpl.java
package com.google.android.gles_jni;
import javax.microedition.khronos.egl.*;
public class EGLSurfaceImpl extends EGLSurface
long mEGLSurface;
public EGLSurfaceImpl()
mEGLSurface = 0;
public EGLSurfaceImpl(long surface)
mEGLSurface = surface;
@Override
public boolean equals(Object o)
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EGLSurfaceImpl that = (EGLSurfaceImpl) o;
return mEGLSurface == that.mEGLSurface;
@Override
public int hashCode()
/*
* Based on the algorithm suggested in
* http://developer.android.com/reference/java/lang/Object.html
*/
int result = 17;
result = 31 * result + (int) (mEGLSurface ^ (mEGLSurface >>> 32));
return result;
EGLContextImpl
/frameworks/base/opengl/java/com/google/android/gles_jni/EGLContextImpl.java
package com.google.android.gles_jni;
import javax.microedition.khronos.egl.*;
import javax.microedition.khronos.opengles.GL;
public class EGLContextImpl extends EGLContext
private GLImpl mGLContext;
long mEGLContext;
public EGLContextImpl(long ctx)
mEGLContext = ctx;
mGLContext = new GLImpl();
@Override
public GL getGL()
return mGLContext;
@Override
public boolean equals(Object o)
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EGLContextImpl that = (EGLContextImpl) o;
return mEGLContext == that.mEGLContext;
@Override
public int hashCode()
/*
* Based on the algorithm suggested in
* http://developer.android.com/reference/java/lang/Object.html
*/
int result = 17;
result = 31 * result + (int) (mEGLContext ^ (mEGLContext >>> 32));
return result;
com_google_android_gles_jni_EGLImpl.cpp
/frameworks/base/core/jni/com_google_android_gles_jni_EGLImpl.cpp
eglGetDisplay()
static jlong jni_eglGetDisplay(JNIEnv *_env, jobject _this, jobject native_display)
return reinterpret_cast<jlong>(eglGetDisplay(EGL_DEFAULT_DISPLAY));
EGL14
EGL14创建 egl 环境的大概过程如下:
private val attributes = intArrayOf(
EGL14.EGL_RED_SIZE, 8, //指定RGB中的R大小(bits)
EGL14.EGL_GREEN_SIZE, 8, //指定G大小
EGL14.EGL_BLUE_SIZE, 8, //指定B大小
EGL14.EGL_ALPHA_SIZE, 8, //指定Alpha大小,以上四项实际上指定了像素格式
EGL14.EGL_DEPTH_SIZE, 16, //指定深度缓存(Z Buffer)大小
EGL14.EGL_RENDERABLE_TYPE, 4, //指定渲染api类别, 如上一小节描述,这里或者是硬编码的4(EGL14.EGL_OPENGL_ES2_BIT)
EGL14.EGL_NONE) //总是以EGL14.EGL_NONE结尾
// 1. 创建与本地窗口系统的连接
eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY)
if (eglDisplay == EGL14.EGL_NO_DISPLAY)
// TODO error
// 2. 初始化 EGl
val version = IntArray(2)
val initializeResult = EGL14.eglInitialize(eglDisplay, version, 0, version, 1)
if (!initializeResult)
// TODO error
// 3. 确定可用的渲染表面配置
val configs = arrayOfNulls<EGLConfig>(1)
val numConfig = IntArray(1)
val result = EGL14.eglChooseConfig(eglDisplay, attributes, 0, configs, 0, configs.size, numConfig, 0)
if (!result)
// TODO error
eglConfig = configs[0]!!
// 4. 创建 EGLContext
val contextAttributes = intArrayOf(EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE)
eglContext = EGL14.eglCreateContext(eglDisplay, eglConfig, EGL14.EGL_NO_CONTEXT, contextAttributes, 0)
// 5. 创建渲染表面
val eglSurfaceAttributes = intArrayOf(EGL14.EGL_NONE)
eglSurface = EGL14.eglCreateWindowSurface(eglDisplay, eglConfig, surface, eglSurfaceAttributes, 0)
// 6. 绑定上下文
val makeCurrentResult = EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, eglSurface, eglContext)
if (!makeCurrentResult)
// TODO error
基本过程与EGL10的方式一致。
同时也可以参考系统类 【 ** android.hardware.camera2.legacy*
*.SurfaceTextureRenderer.java ** 】 里面的写法。
GLThread
了解了 EGL的创建过程,继续接着 GLSurfaceView 的代码看。
注意到 setRender() 函数中初始化的及各类。
- SimpleEGLConfigChooser 对应 eglChooseConfig() 的过程
- DefaultContextFactory 对应 eglCreateContext() 的过程
- DefaultWindowSurfaceFactory 对应 eglCreateWindowSurface() 的过程
创建 EGL环境的对象有了,那么开始创建的这一些过程在哪呢? 答案是::GLThread::
private final WeakReference<GLSurfaceView> mThisWeakRef =
new WeakReference<GLSurfaceView>(this);
mGLThread = new GLThread(mThisWeakRef);
mGLThread.start();
GLThread的构造传入了一个引用当前 GLSurfaceView 的对象,是一个弱引用。
static class GLThread extends Thread
private boolean mShouldExit;
private boolean mExited;
private boolean mRequestPaused;
private boolean mPaused;
private boolean mHasSurface;
private boolean mSurfaceIsBad;
private boolean mWaitingForSurface;
private boolean mHaveEglContext;
private boolean mHaveEglSurface;
private boolean mFinishedCreatingEglSurface;
private boolean mShouldReleaseEglContext;
private int mWidth;
private int mHeight;
private int mRenderMode;
private boolean mRequestRender;
private boolean mWantRenderNotification;
private boolean mRenderComplete;
private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>(); // 待执行的任务队列
private boolean mSizeChanged = true;
private Runnable mFinishDrawingRunnable = null;
private EglHelper mEglHelper; // EGL环境的帮助类
private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
// 构造函数
GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef)
super();
mWidth = 0;
mHeight = 0;
mRequestRender = true;
mRenderMode = RENDERMODE_CONTINUOUSLY;
mWantRenderNotification = false;
mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
可以看出 GLThread 就是一个线程,也就是所谓的 ”GL 线程“。
public void run()
setName("GLThread " + getId());
if (LOG_THREADS)
Log.i("GLThread", "starting tid=" + getId());
try
guardedRun();
catch (InterruptedException e)
// fall thru and exit normally
finally
sGLThreadManager.threadExiting(this);
最重要的 guardedRun() 函数登场了。
// 判断是否准备好开始 draw
private boolean readyToDraw()
return (!mPaused) && mHasSurface && (!mSurfaceIsBad)
&& (mWidth > 0) && (mHeight > 0)
// 如果是 RENDERMODE_CONTINUOUSLY 渲染模式,则不需要调用 requestRender() 也会一直调用onDrawFrame() 进行渲染
&& (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
private void guardedRun() throws InterruptedException
mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);
mHaveEglContext = false;
mHaveEglSurface = false;
mWantRenderNotification = false;
try
GL10 gl = null;
boolean createEglContext = false;
boolean createEglSurface = false;
boolean createGlInterface = false;
boolean lostEglContext = false;
boolean sizeChanged = false;
boolean wantRenderNotification = false;
boolean doRenderNotification = false;
boolean askedToReleaseEglContext = false;
int w = 0;
int h = 0;
Runnable event = null;
Runnable finishDrawingRunnable = null;
while (true)
synchronized (sGLThreadManager)
while (true)
// ...
// Ready to draw?
if (readyToDraw())
// 如果还没有 EGL环境,先创建一个
if (! mHaveEglContext)
try
// 创建EGL环境
mEglHelper.start();
catch (RuntimeException t)
sGLThreadManager.releaseEglContextLocked(this);
throw t;
mHaveEglContext = true;
createEglContext = true;
sGLThreadManager.notifyAll();
if (mHaveEglContext && !mHaveEglSurface)
mHaveEglSurface = true;
createEglSurface = true;
createGlInterface = true;
sizeChanged = true;
if (mHaveEglSurface)
// mSizeChanged 默认值为 true
if (mSizeChanged)
sizeChanged = true;
w = mWidth;
h = mHeight;
// Destroy and recreate the EGL surface.
createEglSurface = true;
mSizeChanged = false;
mRequestRender = false;
sGLThreadManager.notifyAll();
break;
else
// ...
sGLThreadManager.wait();
// end of synchronized(sGLThreadManager)
if (event != null)
event.run();
event = null;
continue;
if (createEglSurface)
// 创建 eglSurface 并绑定 context
if (mEglHelper.createSurface())
// ...
else
// ...
continue;
createEglSurface = false;
// 获取 gl 对象
if (createGlInterface)
gl = (GL10) mEglHelper.createGL();
createGlInterface = false;
if (createEglContext)
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null)
try
// 回调 onSurfaceCreated() 函数
view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
finally
createEglContext = false;
if (sizeChanged)
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null)
try
// 回调 onSurfaceChanged() 函数
view.mRenderer.onSurfaceChanged(gl, w, h);
finally
sizeChanged = false;
// 回调 onDrawFrame() 函数,一般在此函数中做绘制工作。
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null)
try
view.mRenderer.onDrawFrame(gl);
if (finishDrawingRunnable != null)
finishDrawingRunnable.run();
finishDrawingRunnable = null;
finally
// 交换缓冲区显示渲染的数据
int swapError = mEglHelper.swap();
// ...
finally
// clean-up
run() 函数内部有两层 while 循环。内层 while 循环首先调用 readyToDraw() 来判断是否可以往下走。首次 mHasSurface = false。
public void surfaceCreated()
synchronized(sGLThreadManager)
mHasSurface = true;
mFinishedCreatingEglSurface = false;
sGLThreadManager.notifyAll();
while (mWaitingForSurface
&& !mFinishedCreatingEglSurface
&& !mExited)
try
sGLThreadManager.wait();
catch (InterruptedException e)
Thread.currentThread().interrupt();
public void surfaceCreated(SurfaceHolder holder)
mGLThread.surfaceCreated();
GLSurfaceView 实现了 SurfaceHolder.Callback接口,在 surfaceCreated() 回调中调用了 GLThead.surfaceCreated(),在此函数中将 mHasSurface 置为 true。
然后 run() 函数内部 if (readyToDraw()) 函数就可以执行进去了。
内部主要调用了EglHelper 的几个关键函数。
EGLHelper
- start()
- createSurface()
- createGL()
- swap()
- destroySurfaceImp()
- finish()
EGLHelper.start()
public void start()
// 创建 egl 实例
mEgl = (EGL10) EGLContext.getEGL();
// 获取默认 display
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (mEglDisplay == EGL10.EGL_NO_DISPLAY)
throw new RuntimeException("eglGetDisplay failed");
// 初始化
int[] version = new int[2];
if(!mEgl.eglInitialize(mEglDisplay, version))
throw new RuntimeException("eglInitialize failed");
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view == null)
mEglConfig = null;
mEglContext = null;
else
// 创建 EGLConfig
mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
// 创建 EGLContext
mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT)
mEglContext = null;
throwEglException("createContext");
mEglSurface = null;
EGLHelper.createSurface()
public boolean createSurface()
// 检查前置条件
if (mEgl == null)
throw new RuntimeException("egl not initialized");
if (mEglDisplay == null)
throw new RuntimeException("eglDisplay not initialized");
if (mEglConfig == null)
throw new RuntimeException("mEglConfig not initialized");
// 销毁旧的 surface
destroySurfaceImp();
// 创建 EglSurface
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null)
mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
mEglDisplay, mEglConfig, view.getHolder());
else
mEglSurface = null;
if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE)
int error = mEgl.eglGetError();
if (error == EGL10.EGL_BAD_NATIVE_WINDOW)
Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
return false;
// 绑定上下文
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext))
logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
return false;
return true;
从 start() 和 createSurface() 这两个函数可以看出,自己创建 egl 环境时,也是参考 EGLHelper 的方式来的。可以看到本篇文章上面介绍 【EGL 环境】时,创建 egl 环境的大体步骤也是如此。
EGLHelper.swap()
// 交换缓冲,显示数据
public int swap()
if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface))
return mEgl.eglGetError();
return EGL10.EGL_SUCCESS;
EGLHelper. destroySurfaceImp()
// 销毁 surface
private void destroySurfaceImp()
if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE)
//
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_CONTEXT);
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null)
view.mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
mEglSurface = null;
在创建 egl 绑定上下文的时候,mEgl.eglMakeCurrent() 传入的都是有效surface 和 context,销毁 surface 传入 EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT 即可。
EGLHelper. finish()
public void finish()
if (mEglContext != null)
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null)
view.mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
mEglContext = null;
if (mEglDisplay != null)
mEgl.eglTerminate(mEglDisplay);
mEglDisplay = null;
mGLContextFactory = DefaultContextFactory()
public void destroyContext(EGL10 egl, EGLDisplay display,
EGLContext context)
if (!egl.eglDestroyContext(display, context))
EglHelper.throwEglException("eglDestroyContex", egl.eglGetError());
最终调用的是 EGLImpl 类的 eglDestroyContext() 函数。
Render 接口
在if (readyToDraw()) 函数体内部的准备工作进行完之后,break guardedRun() 的内存 while 循环。
调用EGLHelper 的 createSurface() 之后,回调了 Render 的 onSurfaceCreated(GL10 gl, EGLConfig config) 函数, onSurfaceChanged(GL10 gl, intwidth, intheight) 函数,onDrawFrame(GL10 gl) 函数。
我们一般在onDrawFrame() 函数中做一些自己的绘制操作。
最后调用了 EGLHelper的 swap() 来切换缓冲区,显示渲染的结果。
queueEvent
由于操作 OpenGL 环境只能通过 GL线程,所以GLSurfaceView 提供了 queueEvent() 函数,将待执行的 runnable 添加到 GLThread 中的队列中。
public void queueEvent(Runnable r)
mGLThread.queueEvent(r);
public void queueEvent(Runnable r)
if (r == null)
throw new IllegalArgumentException("r must not be null");
synchronized(sGLThreadManager)
mEventQueue.add(r);
sGLThreadManager.notifyAll();
GLThread 的 run() 内部循环执行时,就会从队列中取出 event 来执行。
while (true)
synchronized (sGLThreadManager)
while (true)
if (mShouldExit)
return;
// 取出Runnable
if (! mEventQueue.isEmpty())
event = mEventQueue.remove(0);
break;
// 省略
// end of synchronized(sGLThreadManager)
// 执行Runnable
if (event != null)
event.run();
event = null;
continue;
// 省略
生命周期管理
- onAttachedToWindow()
- onDetachedFromWindow()
- onResume()
- onPause()
onAttachedToWindow()
@Override
protected void onAttachedToWindow()
super.onAttachedToWindow();
// 如果已经 detach 并且 renderer 为空时
if (mDetached && (mRenderer != null))
int renderMode = RENDERMODE_CONTINUOUSLY;
if (mGLThread != null)
renderMode = mGLThread.getRenderMode();
// 创建 GLThread,并设置渲染模式
mGLThread = new GLThread(mThisWeakRef);
if (renderMode != RENDERMODE_CONTINUOUSLY)
mGLThread.setRenderMode(renderMode);
mGLThread.start();
mDetached = false;
onDetachedFromWindow()
@Override
protected void onDetachedFromWindow()
if (mGLThread != null)
mGLThread.requestExitAndWait();
// 设置变量的值
mDetached = true;
super.onDetachedFromWindow();
public void requestExitAndWait()
synchronized(sGLThreadManager)
// 设置变量的值
mShouldExit = true;
sGLThreadManager.notifyAll();
while (! mExited)
try
sGLThreadManager.wait();
catch (InterruptedException ex)
Thread.currentThread().interrupt();
mShouldExit 被设置为 true 之后, 在guardedRun() 函数中,则会直接 return,不会再往下回调 onDrawFrame() 来绘制。
while (true)
synchronized (sGLThreadManager)
while (true)
if (mShouldExit)
return;
// ...
reference
- EGL接口解析与理解-腾讯游戏学院
- 在英特尔® 凌动™ 处理器上将 OpenGL* 游戏移植到 Android* (第一部分) | 英特尔® 软件
- 在英特尔® 凌动™ 处理器上将 OpenGL* 游戏移植到 Android* (第二部分) | 英特尔® 软件
以上是关于GLSurfaceView 源码分析 & EGL 创建过程的主要内容,如果未能解决你的问题,请参考以下文章
Android GLSurfaceView EGL_BAD_CONFIG 源码分析定位
Android GLSurfaceView EGL_BAD_CONFIG 源码分析定位
Android GLSurfaceView EGL_BAD_CONFIG 源码分析定位