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;
}
}