文章目录
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) {