前期文章:
OpenGL ES是是一个开源图形库,那么与之相关的需要一个东西去显示画面,在android里,opengl包里提供了一个View叫GLSurfaceView,它的定义如下:
An implementation of SurfaceView that uses the dedicated surface for
displaying OpenGL rendering.
可见系统已封装好一个View用于渲染画面并能进行相应设置。
1.创建定义一个GLSurfaceView
2.调用GLSurfaceView的setEGLContextClientVersion设置版本号,可设为2
3.onResume 和 onPause分别调用GLSurfaceView相应的生命周期方法
4.调用GLSurfaceView的setRender设置自己实现GLSurfaceView.Render接口的类
5.Render接口有3个方法,分别是SurfaceCreated时候进行相应的初始化工作,SurfaceChange时候高宽的适配以及具体的DrawFrame方法
1.GLSurfaceView在构造函数中调用init()设置如上3个回掉函数
private void init() {
SurfaceHolder holder = getHolder();
holder.addCallback(this);
}
2.setRender会进行一些默认的设置,并生成一个GLThread的线程进行渲染绘制相关操作,绘制的内容默认情况下依旧是绘制到SurfaceView所提供的Surface上
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();
}
3.GLThread的run()方法里调用了guardedRun()方法,在guardedRun方法里new 了一个EglHelper类,并在一段逻辑判断后调用了EglHelper的start方法。
4.EglHelper.start()方法里
public void start() {
mEgl = (EGL10) EGLContext.getEGL();
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 {
mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
}
...
}
这里有如下几个重要方法,最终会调用到C++层去初始化相关的渲染界面
5.在guardedRun() start()调用后会调用EglHelper.createSurface()方法,最终也会调用到C++层。
public boolean createSurface() {
//Check preconditions.
//window size has changed, create a new surface.
destroySurfaceImp();
//Create an EGL surface we can render into.
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
mEglDisplay, mEglConfig, view.getHolder());
} else {mEglSurface = null;}
...
int error = mEgl.eglGetError();
...
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
return false;
}
return true;
}
EGL用于管理绘图表面,有如下机制
EGLDisplay:由于每个窗口系统都有不同的语义,所以EGL提供基本的不透明类型EGLDisplay,封装了所有系统相关性,用于和原生窗口系统接口
EGL有如下一些方法:
EGLDisplay eglGetDisplay(Object native_display);
1.打开与EGL显示服务器的链接打开与EGL显示服务器的链接
2.native_display是一个displayId,指定显示链接,默认链接为EGL_DEFAULT_DISPLAY
boolean eglInitialize(EGLDisplay display, int[] major_minor)
1.打开链接后,需要初始化EGL
2.display:getDisplay返回的值
3.主次版本号
boolean eglChooseConfig(EGLDisplay display, int[] attrib_list, EGLConfig[] configs, int config_size, int[] num_config);
1.让EGL选择匹配的EGLConfig
2.具体就是调用选择配置,配置细节暂不叙述
EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list);
1.创建渲染上下文
2.display:指定的显示链接
3.config:指定的配置
4.share_context:允许多个EGL上下文共享特定类型的数据;使用EGL_NO_CONTEXT表示没有共享
5.attrib_list:指定创建上下文使用的属性列表;只有一个可接受的属性:EGL_CONTEXT_CLIENT_VERSION表示指定与你所使用的OpenGL ES版本
6.eglCreateContext成功时,它返回一个指向新创建上下文的句柄。
EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
1.有了符合渲染要求的EGLConfig,就可调用此函数创建一个窗口
2.属性同上
int eglGetError();
1.EGL函数成功时返回EGL_TRUE,否则返回EGL_FALSE。如果需要查询故障原因,调用eglGetError()得到返回错误码。
boolean eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
1.因一个应用程序可能创建多个EGLContext用于不同的用途,所以需要关联特定的EGLContext和渲染表面即:指定当前上下文
整个大概流程就如上所述调用下来。