EGL
是
OpenGL ES
和本地窗口系统的接口,不同平台上EGL
配置是不一样的,而OpenGL
的调用方式是一致的,就是说:OpenGL
跨平台就是依赖于EGL
接口。 我的得理解是:在一个平台上搭建OpenGL
的环境。
为什么要自己创建EGL环境?
有的人会想,在android里面系统已经提供了
GLSurfaceView
,已经有了EGL
环境,我们为什么还要自己搭建这个环境呢? 当我们需要把同一个场景渲染到不同的Surface
上时,此时系统GLSurfaceView
就不能满足需求了,所以我们需要自己创建EGL
环境来实现渲染操作。 注意:OpenGL
整体是一个状态机,通过改变状态就能改变后续的渲染方式,而EGLContext(EgL上下文)
就保存有所有状态,因此可以通过共享EGLContext
来实现同一场景渲染到不同的Surface
上。
Android
配置egl
环境我们根据GLSurfaceView
源码来实现。在GLSurfaceView
源码里面,当调用setRenderer
的时候会开启一个线程GLThread
,GLThread
调用start
的时候会初始化EglHelper
来配置egl
环境,然后一个while(true)
执行,根据不同的标识判断执行egl
的环境配置,Renderer
的onSurfaceCreated
,onSurfaceChanged
,onDrawFrame
等函数。
从源码得知我们配置egl
环境主要根据GLSurfaceView.EglHelper
来写,主要分为已下几步:
1、得到Egl实例 2、得到默认的显示设备(就是窗口) 3、初始化默认显示设备 4、设置显示设备的属性 5、从系统中获取对应属性的配置 6、创建EglContext 7、创建渲染的Surface 8、绑定EglContext和Surface到显示设备中 9、刷新数据,显示渲染场景
最终代码如下: EglHelper.java
package com.zzw.glsurfaceviewdemo;
import android.view.Surface;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
public class EglHelper {
private static final String TAG = "EglHelper";
private EGL10 mEgl;
private EGLDisplay mEglDisplay;
private EGLContext mEglContext;
private EGLSurface mEglSurface;
public void initEgl(Surface surface, EGLContext eglContext) {
//1. 得到Egl实例
mEgl = (EGL10) EGLContext.getEGL();
//2. 得到默认的显示设备(就是窗口)
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay failed");
}
//3. 初始化默认显示设备
int[] version = new int[2];
if (!mEgl.eglInitialize(mEglDisplay, version)) {
throw new RuntimeException("eglInitialize failed");
}
//4. 设置显示设备的属性
int[] attrib_list = new int[]{
EGL10.EGL_RED_SIZE, mRedSize,
EGL10.EGL_GREEN_SIZE, mGreenSize,
EGL10.EGL_BLUE_SIZE, mBlueSize,
EGL10.EGL_ALPHA_SIZE, mAlphaSize,
EGL10.EGL_DEPTH_SIZE, mDepthSize,
EGL10.EGL_STENCIL_SIZE, mStencilSize,
EGL10.EGL_RENDERABLE_TYPE, mRenderType,//egl版本 2.0
EGL10.EGL_NONE};
int[] num_config = new int[1];
if (!mEgl.eglChooseConfig(mEglDisplay, attrib_list, null, 1,
num_config)) {
throw new IllegalArgumentException("eglChooseConfig failed");
}
int numConfigs = num_config[0];
if (numConfigs <= 0) {
throw new IllegalArgumentException(
"No configs match configSpec");
}
//5. 从系统中获取对应属性的配置
EGLConfig[] configs = new EGLConfig[numConfigs];
if (!mEgl.eglChooseConfig(mEglDisplay, attrib_list, configs, numConfigs,
num_config)) {
throw new IllegalArgumentException("eglChooseConfig#2 failed");
}
EGLConfig eglConfig = chooseConfig(mEgl, mEglDisplay, configs);
if (eglConfig == null) {
eglConfig = configs[0];
}
//6. 创建EglContext
int[] contextAttr = new int[]{
EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
EGL10.EGL_NONE
};
if (eglContext == null) {
mEglContext = mEgl.eglCreateContext(mEglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, contextAttr);
} else {
mEglContext = mEgl.eglCreateContext(mEglDisplay, eglConfig, eglContext, contextAttr);
}
//7. 创建渲染的Surface
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, eglConfig, surface, null);
//8. 绑定EglContext和Surface到显示设备中
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
throw new RuntimeException("eglMakeCurrent fail");
}
}
//9. 刷新数据,显示渲染场景
public boolean swapBuffers() {
if (mEgl != null) {
return mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
} else {
throw new RuntimeException("egl is null");
}
}
public void destoryEgl() {
if (mEgl != null) {
if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
mEglSurface = null;
}
if (mEglContext != null) {
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
mEglContext = null;
}
if (mEglDisplay != null) {
mEgl.eglTerminate(mEglDisplay);
mEglDisplay = null;
}
mEgl = null;
}
}
public EGLContext getEglContext() {
return mEglContext;
}
private final int mRedSize = 8;
private final int mGreenSize = 8;
private final int mBlueSize = 8;
private final int mAlphaSize = 8;
private final int mDepthSize = 8;
private final int mStencilSize = 8;
private final int mRenderType = 4;
private EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
EGLConfig[] configs) {
for (EGLConfig config : configs) {
int d = findConfigAttrib(egl, display, config,
EGL10.EGL_DEPTH_SIZE, 0);
int s = findConfigAttrib(egl, display, config,
EGL10.EGL_STENCIL_SIZE, 0);
if ((d >= mDepthSize) && (s >= mStencilSize)) {
int r = findConfigAttrib(egl, display, config,
EGL10.EGL_RED_SIZE, 0);
int g = findConfigAttrib(egl, display, config,
EGL10.EGL_GREEN_SIZE, 0);
int b = findConfigAttrib(egl, display, config,
EGL10.EGL_BLUE_SIZE, 0);
int a = findConfigAttrib(egl, display, config,
EGL10.EGL_ALPHA_SIZE, 0);
if ((r == mRedSize) && (g == mGreenSize)
&& (b == mBlueSize) && (a == mAlphaSize)) {
return config;
}
}
}
return null;
}
private int findConfigAttrib(EGL10 egl, EGLDisplay display,
EGLConfig config, int attribute, int defaultValue) {
int[] value = new int[1];
if (egl.eglGetConfigAttrib(display, config, attribute, value)) {
return value[0];
}
return defaultValue;
}
}