這是我參加8月更文挑戰的次日.GLSurfaceView是Android端使用OpenGL es繪圖的重要組件,若是咱們理解了它的源碼,咱們就能更加深刻的理解OpenGL es.git
咱們平時在使用GLSurfaceView時,最主要用到的兩個方法就是setEGLContextClientVersion和setRenderer,前者是設置OpenGL es的版本,主要的繪製工做都是在第二個方法裏實現的,因此咱們主要看一下setRenderer方法.github
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();
}
複製代碼
這個方法比較簡短,主要涉及到了三個對象,分別是:mEGLConfigChooser,mEGLContextFactory,mEGLWindowSurfaceFactory.markdown
mEGLConfigChooser是用於在EGLHelper中的start方法(下文會提到)生成EGLConfig對象以及指定OpenGL顏色和深度.app
mEGLContextFactory也是用在EGLHelper的start方法中生成EGLContext,提供EGLContext的建立和銷燬的方法.oop
mEGLWindowSurfaceFactory用於在EGLHelper的createSurface方法中生成EGLSurface,一樣提供了EGLSurface的建立和銷燬方法.this
EGLDisplay是表明實際顯示設備的類,EGLSurface是用於存儲圖像信息的類.基於這兩個類GLSurfaceView才能實現雙緩衝機制.spa
setRenderer方法最後生成了一個GLThread對象而且啓動了該對象,咱們進入這個類能夠看見這是它集成了Thread,因此咱們就着重看它的run方法.3d
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()方法,這個方法比較長,就關注一些主要的代碼就好.code
private void guardedRun() throws InterruptedException{
mEGLHlper = new EglHelper(mGLSurfaceViewWeakRef);
//...省略一堆變量的定義
while(true) {
//...省略一堆條件判斷
if (readyToDraw()){ //準備好開始渲染
mEglHelper.start();
}
if (createGLInterface) {
gl = (GL10) mEglHelper.createGL();
}
if (createEglContext) {
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
}
if (sizeChanged) {
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
view.mRenderer.onSurfaceChanged(gl, w, h);
}
{
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
view.mRenderer.onDrawFrame(gl);
}
int swapError = mEglHelper.swap();
}
}
複製代碼
能夠看見咱們平時在自定義Renderer的時候實現的三個方法都是在這裏調用的,除了這一點咱們還須要關注的是mEGLHelper這個對象,從上面這些代碼咱們能夠看見mEGLHelper的使用是貫穿整個GLSurfaceView的,因此咱們還須要看看mEGLHelper的代碼orm
public void start(){
mEgl = (EGL10) EGLContext.getEGL();
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
mEgl.eglInitialize(mEglDisplay, version)
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig)
}
複製代碼
在start的方法中進行了一些初始化操做,實例化了EGL,EGLConfig和EGLContext,初始化了EGL,還生成了EGLDisplay.
public boolean createSurface() {
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
mEglDisplay, mEglConfig, view.getHolder());
}
複製代碼
createSurface方法用於建立EGLSurface對象.
GL createGL() {
GL gl = mEglContext.getGL();
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
if (view.mGLWrapper != null) {
gl = view.mGLWrapper.wrap(gl);
}
}
return gl;
}
複製代碼
createGL主要用於建立GL對象,GL對象在自定義Render實現的三個方法的參數裏都有用到.
public int swap() {
if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
return mEgl.eglGetError();
}
return EGL10.EGL_SUCCESS;
}
複製代碼
swap方法調用了native方法來交換EGLDisplay和EGLSurface的數據.
通過以上分析,咱們就能指定GLSurface建立渲染的大部分流程,經過模仿這些代碼咱們就能夠使用自定義載體來進行OpenGL的渲染,好比說TextureView等等.下面這張圖就是GLSurface建立渲染過程當中涉及到的主要的類和方法: