EGL:
是OpenGL ES和本地窗口系統的接口,不同平臺上EGL配置是不一樣的,而OpenGL的調用方式是一致的,就是說:OpenGL跨平臺就是依賴於EGL接口。
爲什麼要自己創建EGL環境?
當我們需要把同一個場景渲染到不同的Surface上時,此時系統GLSurfaceView就不能滿足需求了,所以我們需要自己創建EGL環境來實現渲染操作。
注意:OpenGL整體是一個狀態機,通過改變狀態就能改變後續的渲染方式,而EGLContext(EgL上下文)就保存有所有狀態,因此可以通過共享EGLContext來實現同一場景渲染到不同的Surface上。
實現步驟(參考GLSurfaceView類中的EglHelper內部類)
1、得到Egl實例:
EGL10 mEgl = (EGL10) EGLContext.getEGL();
2、得到默認的顯示設備(就是窗口)
EGLDisplay mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
3、初始化默認顯示設備
int[] version = new int[2];
if (!mEgl.eglInitialize(mEglDisplay, version)) {
throw new RuntimeException("eglInitialize failed");
}
4、設置顯示設備的屬性
int[] attrbutes = new int[]{
//紅
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
};
int[] num_configs = new int[1];
if (!mEgl.eglChooseConfig(mEglDisplay, attrbutes, null, 1, num_configs)) {
throw new IllegalArgumentException("eglChooseConfig failed");
}
int num_config = num_configs[0];
5、從系統中獲取對應屬性的配置
EGLConfig[] eglConfigs = new EGLConfig[num_config];
if (!mEgl.eglChooseConfig(mEglDisplay, attrbutes, eglConfigs, num_config, num_configs)) {
throw new IllegalArgumentException("eglChooseConfig#2 failed");
}
6、創建EglContext
private EGLContext mEglContext;
int[] attrib_list = {
EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
EGL10.EGL_NONE
};
//判斷一下eglContext是否已經創建,已創建了共享
if (null != eglContext) {
mEglContext = mEgl.eglCreateContext(mEglDisplay, eglConfigs[0], eglContext, attrib_list);
} else
mEglContext = mEgl.eglCreateContext(mEglDisplay, eglConfigs[0], EGL10.EGL_NO_CONTEXT, attrib_list);
7、創建渲染的Surface
EGLSurface mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, eglConfigs[0], surface, null);
8、綁定EglContext和Surface到顯示設備中
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
throw new RuntimeException("eglMakeCurrent fail");
}
9、刷新數據,顯示渲染場景
public boolean swapBuffers() {
if (null != mEgl) {
return mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
} else {
throw new RuntimeException("egl is null");
}
}
完整代碼
public class EglHelper {
private EGL10 mEgl;
private EGLDisplay mEglDisplay;
private EGLContext mEglContext;
private EGLSurface mEglSurface;
public void init(Surface surface, EGLContext eglContext) {
//得到EGL實例
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");
}
//設置顯示設備的屬性
int[] attrbutes = new int[]{
//紅
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
};
int[] num_configs = new int[1];
if (!mEgl.eglChooseConfig(mEglDisplay, attrbutes, null, 1, num_configs)) {
throw new IllegalArgumentException("eglChooseConfig failed");
}
int num_config = num_configs[0];
if (num_config <= 0) {
throw new IllegalArgumentException(
"No configs match configSpec");
}
//從系統中獲取對應的屬性的配置
EGLConfig[] eglConfigs = new EGLConfig[num_config];
if (!mEgl.eglChooseConfig(mEglDisplay, attrbutes, eglConfigs, num_config, num_configs)) {
throw new IllegalArgumentException("eglChooseConfig#2 failed");
}
//創建EGLContext
int[] attrib_list = {
EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
EGL10.EGL_NONE
};
if (null != eglContext) {
mEglContext = mEgl.eglCreateContext(mEglDisplay, eglConfigs[0], eglContext, attrib_list);
} else
mEglContext = mEgl.eglCreateContext(mEglDisplay, eglConfigs[0], EGL10.EGL_NO_CONTEXT, attrib_list);
//創建渲染的Surface
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, eglConfigs[0], surface, null);
//綁定EGLContext和Surface到顯示設備中
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
throw new RuntimeException("eglMakeCurrent fail");
}
}
//刷新數據,顯示渲染場景
public boolean swapBuffers() {
if (null != mEgl) {
return mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
} else {
throw new RuntimeException("egl is null");
}
}
public EGLContext getEglContext() {
return mEglContext;
}
//銷燬
public void destroyEgl() {
if (null != mEgl) {
//銷燬Surface
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
mEglSurface = null;
//銷燬EGLContext
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
mEglContext = null;
//銷燬顯示設備
mEgl.eglTerminate(mEglDisplay);
mEglDisplay = null;
mEgl = null;
}
}
}