1.背景介绍
这是我参加8月更文挑战的第二天.GLSurfaceView是Android端使用OpenGL es绘图的重要组件,如果我们理解了它的源码,我们就能更加深入的理解OpenGL es.
2.代码分析
2.1.入口
我们平时在使用GLSurfaceView时,最主要用到的两个方法就是setEGLContextClientVersion和setRenderer,前者是设置OpenGL es的版本,主要的绘制工作都是在第二个方法里实现的,所以我们主要看一下setRenderer方法.
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.
mEGLConfigChooser是用于在EGLHelper中的start方法(下文会提到)生成EGLConfig对象以及指定OpenGL颜色和深度.
mEGLContextFactory也是用在EGLHelper的start方法中生成EGLContext,提供EGLContext的创建和销毁的方法.
mEGLWindowSurfaceFactory用于在EGLHelper的createSurface方法中生成EGLSurface,同样提供了EGLSurface的创建和销毁方法.
EGLDisplay是代表实际显示设备的类,EGLSurface是用于存储图像信息的类.基于这两个类GLSurfaceView才能实现双缓冲机制.
2.2.GLThread的分析
setRenderer方法最后生成了一个GLThread对象并且启动了该对象,我们进入这个类可以看见这是它集成了Thread,所以我们就着重看它的run方法.
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()方法,这个方法比较长,就关注一些主要的代码就好.
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的代码
2.3.EGLHelper
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的数据.
3.总结
经过以上分析,我们就能指定GLSurface创建渲染的大部分流程,通过模仿这些代码我们就可以使用自定义载体来进行OpenGL的渲染,比如说TextureView等等.下面这张图就是GLSurface创建渲染过程中涉及到的主要的类和方法:



















![[02/27][官改] Simplicity@MIX2 ROM更新-一一网](https://www.proyy.com/wp-content/uploads/2020/02/3168457341.jpg)


![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)