3.GLSurfaceView源码解析
我感觉还是先看一下源码,了解一下内部的流程,再接着学习其他的OpenGL部分会更合适。
从上一篇文章中GLSurfaceView的使用中可以看到入口是setRenderer()方法,这里就看一下setRenderder(Renderer renderer)方法的实现:
- Renderer接口
public interface Renderer {
// surface创建的回调
void onSurfaceCreated(GL10 gl, EGLConfig config);
// surface大小改变的回调
void onSurfaceChanged(GL10 gl, int width, int height);
// 开始绘制每一帧的回调
void onDrawFrame(GL10 gl);
}
- setRenderer()方法
public void setRenderer(Renderer renderer) {
// 保证setRenderer方法只能被调用一次
checkRenderThreadState();
if (mEGLConfigChooser == null) {
// 设置EGLConfgi,如果不设置就用默认的一个RGB_888的Surface选择器
mEGLConfigChooser = new SimpleEGLConfigChooser(true);
}
if (mEGLContextFactory == null) {
// 设置EGLContext工厂,如果不设置就用默认的EGLContext的工厂类,用他来创建EGLContext
mEGLContextFactory = new DefaultContextFactory();
}
if (mEGLWindowSurfaceFactory == null) {
// 设置EGLSurface工厂,如果不设置就用默认的EGLSurface的工厂类,我们可以通过这个方法来设置让图像渲染到其他地方的surface上,例如textureview上
mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
}
mRenderer = renderer;
// 创建并开启GLThread,GL线程
mGLThread = new GLThread(mThisWeakRef);
mGLThread.start();
}
接下来看一下GLThread的线程的实现,GLThread是GLSurfaceView自带的一个渲染线程,同步的,不会阻塞线程,主要用来执行OpenGL的绘制工作:
static class GLThread extends Thread { GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) { super(); mWidth = 0; mHeight = 0; // 连续渲染模式下是true,如果是按需渲染模式就为false,然后通过requesetRender()方法来修改它的值 mRequestRender = true; // 默认的渲染模式 mRenderMode = RENDERMODE_CONTINUOUSLY; mWantRenderNotification = false; mGLSurfaceViewWeakRef = glSurfaceViewWeakRef; } @Override public void run() { setName("GLThread " + getId()); if (LOG_THREADS) { Log.i("GLThread", "starting tid=" + getId()); } try { // 具体的run方法,内部实现在下面,所有的核心都在里面,把这个方法单独放到下面说 guardedRun(); } catch (InterruptedException e) { // fall thru and exit normally } finally { sGLThreadManager.threadExiting(this); } } // GLSurfaceView的onPause方法会调用到这里 public void onPause() { synchronized (sGLThreadManager) { if (LOG_PAUSE_RESUME) { Log.i("GLThread", "onPause tid=" + getId()); } mRequestPaused = true; // 这里使用了GLThreadManager这个类,这个类是提供线程同步控制功能的,最后会说这个类,通知EGL线程解除堵塞 sGLThreadManager.notifyAll(); // 保证onPause方法执行后GLThread也是pause的状态 while ((! mExited) && (! mPaused)) { if (LOG_PAUSE_RESUME) { Log.i("Main thread", "onPause waiting for mPaused."); } try { sGLThreadManager.wait(); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } } } // GLSurfaceView的onResume方法会调用到这里 public void onResume() { synchronized (sGLThreadManager) { if (LOG_PAUSE_RESUME) { Log.i("GLThread", "onResume tid=" + getId()); } // 修改状态变量 mRequestPaused = false; // 重绘一次 mRequestRender = true; mRenderComplete = false; sGLThreadManager.notifyAll(); // 保证onResume执行后,GLThread也是resume的状态 while ((! mExited) && mPaused && (!mRenderComplete)) { if (LOG_PAUSE_RESUME) { Log.i("Main thread", "onResume waiting for !mPaused."); } try { sGLThreadManager.wait(); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } } } }
guardeRun()方法:
核心就是用一个while true循环,内部加了各种场景的判断,最后会调用renderer.onDrawFrame()方法进行绘制。
private void guardedRun() throws InterruptedException {
//GL帮助类,内部建立GL环境
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) {
// 外部请求退出
if (mShouldExit) {
return;
// 如果还有GL线程中要处理的事件没处理完,就先处理事件
if (! mEventQueue.isEmpty()) {
event = mEventQueue.remove(0);
break;
}
// 更新onResume和onPause时的状态变化
// Update the pause state.
boolean pausing = false;
if (mPaused != mRequestPaused) {
pausing = mRequestPaused;
mPaused = mRequestPaused;
// onPause和onResume的时候都会用wait方法等待GL线程的响应,这时候主线程堵塞。需要调用notifyAll
sGLThreadManager.notifyAll();
if (LOG_PAUSE_RESUME) {
Log.i("GLThread", "mPaused is now " + mPaused + " tid=" + getId());
}
}
// 需要释放EGLContext
// Do we need to give up the EGL context?
if (mShouldReleaseEglContext) {
if (LOG_SURFACE) {
Log.i("GLThread", "releasing EGL context because asked to tid=" + getId());
}
stopEglSurfaceLocked();
stopEglContextLocked();
mShouldReleaseEglContext = false;
askedToReleaseEglContext = true;
}
// 如果EGLContext丢失,需要销毁EGLSurface和EGLContext
// Have we lost the EGL context?
if (lostEglContext) {
stopEglSurfaceLocked();
stopEglContextLocked();
lostEglContext = false;
}
// 如果onPause了并且当前GLSurface已经存在了,就销毁EGLSurface
// When pausing, release the EGL surface:
if (pausing && mHaveEglSurface) {
if (LOG_SURFACE) {
Log.i("GLThread", "releasing EGL surface because paused tid=" + getId());
}
stopEglSurfaceLocked();
}
// 接受了onPuase信号,并且当前EGLContext存在时,需要根据用户的设置来决定是否销毁EGLContext
// When pausing, optionally release the EGL Context:
if (pausing && mHaveEglContext) {
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
boolean preserveEglContextOnPause = view == null ?
false : view.mPreserveEGLContextOnPause;
if (!preserveEglContextOnPause) {
stopEglContextLocked();
if (LOG_SURFACE) {
Log.i("GLThread", "releasing EGL context because paused tid=" + getId());
}
}
}
// Have we lost the SurfaceView surface?
if ((! mHasSurface) && (! mWaitingForSurface)) {
if (LOG_SURFACE) {
Log.i("GLThread", "noticed surfaceView surface lost tid=" + getId());
}
if (mHaveEglSurface) {
stopEglSurfaceLocked();
}
mWaitingForSurface = true;
mSurfaceIsBad = false;
sGLThreadManager.notifyAll();
}
// Have we acquired the surface view surface?
if (mHasSurface && mWaitingForSurface) {
if (LOG_SURFACE) {
Log.i("GLThread", "noticed surfaceView surface acquired tid=" + getId());
}
mWaitingForSurface = false;
sGLThreadManager.notifyAll();
}
if (doRenderNotification) {
if (LOG_SURFACE) {
Log.i("GLThread", "sending render notification tid=" + getId());
}
mWantRenderNotification = false;
doRenderNotification = false;
mRenderComplete = true;
sGLThreadManager.notifyAll();
}
if (mFinishDrawingRunnable != null) {
finishDrawingRunnable = mFinishDrawingRunnable;
mFinishDrawingRunnable = null;
}
// readyToDraw()方法内部会判断是否已经pause或者mRequestRender是否是true以及是否是主动渲染模式。如果是被动渲染的模式mRequestRender就会是false,只有调用requestRender()方法后才会是true,如果是主动渲染模式readyToDraw()就不用根据mRequestRender来判断。
// Ready to draw?
if (readyToDraw()) {
// 没有EGLContext就去调用EGLHelper来创建,第一次会走到这里先创建EGLContext
// If we don't have an EGL context, try to acquire one.
if (! mHaveEglContext) {
if (askedToReleaseEglContext) {
askedToReleaseEglContext = false;
} else {
try {
// 后面会看这个EglHelper.start()方法,初始化EGL环境,内部会去创建各种GL EGL EGLContext EGLDisplay等环境
mEglHelper.start();
} catch (RuntimeException t) {
sGLThreadManager.releaseEglContextLocked(this);
throw t;
}
// 创建完后把该变量变成true
mHaveEglContext = true;
createEglContext = true;
sGLThreadManager.notifyAll();
}
}
if (mHaveEglContext && !mHaveEglSurface) {
mHaveEglSurface = true;
createEglSurface = true;
createGlInterface = true;
sizeChanged = true;
}
if (mHaveEglSurface) {
if (mSizeChanged) {
sizeChanged = true;
w = mWidth;
h = mHeight;
mWantRenderNotification = true;
if (LOG_SURFACE) {
Log.i("GLThread",
"noticing that we want render notification tid="
+ getId());
}
// Destroy and recreate the EGL surface.
createEglSurface = true;
mSizeChanged = false;
}
mRequestRender = false;
sGLThreadManager.notifyAll();
if (mWantRenderNotification) {
wantRenderNotification = true;
}
break;
}
} else {
if (finishDrawingRunnable != null) {
Log.w(TAG, "Warning, !readyToDraw() but waiting for " +
"draw finished! Early reporting draw finished.");
finishDrawingRunnable.run();
finishDrawingRunnable = null;
}
}
// By design, this is the only place in a GLThread thread where we wait().
sGLThreadManager.wait();
}
} // end of synchronized(sGLThreadManager)
if (event != null) {
// 执行event的run方法,这个event是GLSurfaceView中提供的queueEvent(runnable run)实现的,该方法会把runnable添加到EventQueue中,然后再在这里去执行该runnable
event.run();
event = null;
continue;
}
if (createEglSurface) {
// EglHelper创建EglSurface
if (mEglHelper.createSurface()) {
synchronized(sGLThreadManager) {
mFinishedCreatingEglSurface = true;
sGLThreadManager.notifyAll();
}
} else {
synchronized(sGLThreadManager) {
mFinishedCreatingEglSurface = true;
mSurfaceIsBad = true;
sGLThreadManager.notifyAll();
}
continue;
}
createEglSurface = false;
}
if (createGlInterface) {
gl = (GL10) mEglHelper.createGL();
createGlInterface = false;
}
if (createEglContext) {
if (LOG_RENDERER) {
Log.w("GLThread", "onSurfaceCreated");
}
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceCreated");
// 回调onSurfaceCreated
view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
createEglContext = false;
}
if (sizeChanged) {
if (LOG_RENDERER) {
Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")");
}
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceChanged");
// 回调onSurfaceChangeed
view.mRenderer.onSurfaceChanged(gl, w, h);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
sizeChanged = false;
}
if (LOG_RENDERER_DRAW_FRAME) {
Log.w("GLThread", "onDrawFrame tid=" + getId());
}
{
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
// 调用renderder.onDrawFrame方法开始绘制
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onDrawFrame");
view.mRenderer.onDrawFrame(gl);
if (finishDrawingRunnable != null) {
finishDrawingRunnable.run();
finishDrawingRunnable = null;
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
}
int swapError = mEglHelper.swap();
switch (swapError) {
case EGL10.EGL_SUCCESS:
break;
case EGL11.EGL_CONTEXT_LOST:
if (LOG_SURFACE) {
Log.i("GLThread", "egl context lost tid=" + getId());
}
lostEglContext = true;
break;
default:
// Other errors typically mean that the current surface is bad,
// probably because the SurfaceView surface has been destroyed,
// but we haven't been notified yet.
// Log the error to help developers understand why rendering stopped.
EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers", swapError);
synchronized(sGLThreadManager) {
mSurfaceIsBad = true;
sGLThreadManager.notifyAll();
}
break;
}
if (wantRenderNotification) {
doRenderNotification = true;
wantRenderNotification = false;
}
}
} finally {
/*
* clean-up everything...
*/
synchronized (sGLThreadManager) {
stopEglSurfaceLocked();
stopEglContextLocked();
}
}
}
接着看一下上面提到的几个类:
- EGLHelper
/**
* An EGL helper class.
*/
private static class EglHelper {
public EglHelper(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
}
/**
* 初始化EGL环境,创建EGL EGLContext EGLDisplay
* Initialize EGL for a given configuration spec.
* @param configSpec
*/
public void start() {
if (LOG_EGL) {
Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId());
}
/*
* Get an EGL instance
*/
mEgl = (EGL10) EGLContext.getEGL();
/*
* Get to the default display.
*/
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay failed");
}
/*
* We can now initialize EGL for that display
*/
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 {
// 使用setRender方法中setEGLConfigChooser和setEGLContextFactory中设置的部分来创建
mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
/*
* Create an EGL context. We want to do this as rarely as we can, because an
* EGL context is a somewhat heavy object.
*/
mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
}
if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
mEglContext = null;
throwEglException("createContext");
}
if (LOG_EGL) {
Log.w("EglHelper", "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
}
mEglSurface = null;
}
/**
* 创建EGLSurface
* Create an egl surface for the current SurfaceHolder surface. If a surface
* already exists, destroy it before creating the new surface.
*
* @return true if the surface was created successfully.
*/
public boolean createSurface() {
if (LOG_EGL) {
Log.w("EglHelper", "createSurface() tid=" + Thread.currentThread().getId());
}
/*
* Check preconditions.
*/
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");
}
/*
* The window size has changed, so we need to create a new
* surface.
*/
destroySurfaceImp();
/*
* Create an EGL surface we can render into.
*/
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
// 也是通过EGLWindowSurfaceFactory来创建EGLSurface,如果没有设置就会调用默认的DefaultWindowSurfaceFactory。后面说一下这里
mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
mEglDisplay, mEglConfig, view.getHolder());
} else {
mEglSurface = null;
}
/*
将EGLContext上下文加载到当前线程环境
* Before we can issue GL commands, we need to make sure
* the context is current and bound to a surface.
*/
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
/*
* Could not make the context current, probably because the underlying
* SurfaceView surface has been destroyed.
*/
logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
return false;
}
return true;
}
/**
获取OpenGL ES的编程接口
* Create a GL object for the current EGL context.
* @return
*/
GL createGL() {
GL gl = mEglContext.getGL();
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
if (view.mGLWrapper != null) {
gl = view.mGLWrapper.wrap(gl);
}
if ((view.mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS)) != 0) {
int configFlags = 0;
Writer log = null;
if ((view.mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) {
configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR;
}
if ((view.mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) {
log = new LogWriter();
}
gl = GLDebugHelper.wrap(gl, configFlags, log);
}
}
return gl;
}
public void destroySurface() {
if (LOG_EGL) {
Log.w("EglHelper", "destroySurface() tid=" + Thread.currentThread().getId());
}
destroySurfaceImp();
}
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) {
// EGLWindowSurfaceFactory除了创建EGLSurface还有销毁的功能
view.mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
}
mEglSurface = null;
}
}
private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
EGL10 mEgl;
EGLDisplay mEglDisplay;
EGLSurface mEglSurface;
EGLConfig mEglConfig;
EGLContext mEglContext;
}
- EGLWindowSurfaceFactory
/**
* An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls.
* <p>
* This interface must be implemented by clients wishing to call
* {@link GLSurfaceView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
*/
public interface EGLWindowSurfaceFactory {
/**
* @return null if the surface cannot be constructed.
*/
EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config,
Object nativeWindow);
void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
}
private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {
public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
EGLConfig config, Object nativeWindow) {
EGLSurface result = null;
try {
result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
} catch (IllegalArgumentException e) {
// This exception indicates that the surface flinger surface
// is not valid. This can happen if the surface flinger surface has
// been torn down, but the application has not yet been
// notified via SurfaceHolder.Callback.surfaceDestroyed.
// In theory the application should be notified first,
// but in practice sometimes it is not. See b/4588890
Log.e(TAG, "eglCreateWindowSurface", e);
}
return result;
}
public void destroySurface(EGL10 egl, EGLDisplay display,
EGLSurface surface) {
egl.eglDestroySurface(display, surface);
}
}
看到这里我们知道可以自定义WindowSurfaceFactory然后使用其他SurfaceView或者TextureView的Surface来创建EGLSurface,让其把渲染后的内容输出到SurfaceView或者TextureView上显示。
GLThreadManager类
上面看到wait和notifyall的时候sGLThreadManager.notifyAll();都用到了GLThreadManager类。它就是线程同步的锁。
这个类主要提供的是线程同步控制的功能,因为在GLSurfaceView里面有两个线程: GL线程和调用线程。所以对一些变量必须要进行同步。
- 邮箱 :[email protected]
- Good Luck!