大家好,接下來將為大家介紹EGL 作用及其使用,。
1,、什么是EGL
EGL 是 OpenGL ES 渲染 API 和本地窗口系統(tǒng)(native platform window system)之間的一個(gè)中間接口層,EGL作為OpenGL ES與顯示設(shè)備的橋梁,,讓OpenGL ES繪制的內(nèi)容能夠在呈現(xiàn)當(dāng)前設(shè)備上,。它主要由系統(tǒng)制造商實(shí)現(xiàn),。
EGL具有如下作用:
a:與設(shè)備的原生窗口系統(tǒng)通信。
b:查詢繪圖表面的可用類型和配置,。
c:創(chuàng)建繪圖表面,。
d:在OpenGL ES 和其他圖形渲染API之間同步渲染。
e:管理紋理貼圖等渲染資源,。
2,、EGL和OpenGL?ES的關(guān)系
從上面的講解我們基本上可以知道,EGL為OpenGL提供繪制表面,?;蛘哒fEGL是OpenGl ES的渲染畫布。EGL作為OpenGL ES與顯示設(shè)備的橋梁,,讓OpenGL ES繪制的內(nèi)容能夠在呈現(xiàn)當(dāng)前設(shè)備上,。
?
3、EGL繪圖的基本步驟
簡(jiǎn)單講解下各部分的作用:
a:Display(EGLDisplay) 是對(duì)實(shí)際顯示設(shè)備的抽象,。
b:Surface(EGLSurface)是對(duì)用來存儲(chǔ)圖像的內(nèi)存區(qū)域FrameBuffer 的抽象,,包括 Color Buffer, Stencil Buffer ,,Depth Buffer,。
c:Context (EGLContext) 存儲(chǔ) OpenGL ES繪圖的一些狀態(tài)信息。
?
4.1,、EGL的基本使用步驟:
a:獲取 EGL Display 對(duì)象:通過eglGetDisplay()方法來返回EGLDisplay作為OpenGL?ES的渲染目標(biāo),。
if ( (mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY)) == EGL14.EGL_NO_DISPLAY) {
throw new RuntimeException("unable to get EGL14 display"); }
b:初始化與 EGLDisplay 之間的連接:eglInitialize()。第一參數(shù)代表Major版本,,第二個(gè)代表Minor版本,。如果不關(guān)心版本號(hào),傳0或者null就可以了,。
if (!EGL14.eglInitialize(mEGLDisplay, 0, 0)) {
throw new RuntimeException("unable to initialize EGL14"); }
c:獲取 EGLConfig 對(duì)象:eglChooseConfig(),。
int[] attribList = {
EGL14.EGL_RED_SIZE, 8,
EGL14.EGL_GREEN_SIZE, 8,
EGL14.EGL_BLUE_SIZE, 8,
EGL14.EGL_ALPHA_SIZE, 8,
EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES3_BIT,
EGL_RECORDABLE_ANDROID, 1,
EGL14.EGL_NONE
};
EGLConfig[] configs = new EGLConfig[1];
int[] numConfigs = new int[1];
EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length,
numConfigs, 0);
d:創(chuàng)建 EGLContext 實(shí)例:接下來我們需要?jiǎng)?chuàng)建OpenGL的上下文環(huán)境 EGLContext 實(shí)例,這里值得留意的是,,OpenGL的任何一條指令都是必須在自己的OpenGL上下文環(huán)境中運(yùn)行,,我們可以通過eglCreateContext()方法來構(gòu)建上下文環(huán)境:
int[] attrib_list = {
EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
EGL14.EGL_NONE
};
mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
attrib_list, 0);
e:創(chuàng)建 EGLSurface 實(shí)例:通過eglCreateWindowSurface()方法創(chuàng)建一個(gè)實(shí)際可以顯示的EGLSurface。
private EGLSurface mEGLSurface = EGL14.EGL_NO_SURFACE;
int[] surfaceAttribs = {
EGL14.EGL_NONE
};
mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, configs[0], mSurface,
surfaceAttribs, 0);
f:連接 EGLContext 和 EGLSurface:通過上面的步驟,,EGL的準(zhǔn)備工作做好了,,一方面我們?yōu)镺penGL?ES渲染提供了目標(biāo)及上下文環(huán)境EGLContext,可以接收到OpenGl ES渲染出來的紋理,;另一方面我們連接好了設(shè)備顯示屏EGLSurface(這里指SurfaceView或者TextureView),,接下來我們講解如何在創(chuàng)建好的EGL環(huán)境下工作的。首先我們有一點(diǎn)必須要明確,,OpenGL?ES 的渲染必須新開一個(gè)線程,,并為該線程綁定顯示設(shè)備及上下文環(huán)境(EGLContext),。前面有說過OpenGL指令必須要在其上下文環(huán)境中才能執(zhí)行。所以我們首先要通過 eglMakeCurrent()方法來綁定該線程的顯示設(shè)備及上下文,。
EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
g:當(dāng)我們綁定完成之后,,我們就可以進(jìn)行RenderLoop循環(huán)了,使用 OpenGL ES API 繪制圖形:gl_*() ,。
h:繪制好之后,,切換 front buffer 和 back buffer 送顯:eglSwapBuffer()。EGL的工作模式是雙緩沖模式,,其內(nèi)部有兩個(gè)FrameBuffer(幀緩沖區(qū),,可以理解為一個(gè)圖像存儲(chǔ)區(qū)域),當(dāng)EGL將一個(gè)FrameBuffer顯示到屏幕上的時(shí)候,,另一個(gè)FrameBuffer就在后臺(tái)等待OpenGl ES進(jìn)行渲染輸出,。直到調(diào)用了eglSwapBuffer()這條指令的時(shí)候,才會(huì)把前臺(tái)的FrameBuffers和后臺(tái)的FrameBuffer進(jìn)行交換,,這時(shí)界面呈現(xiàn)的就是OpenGL?ES剛剛渲染的內(nèi)容了,。
EGL14.eglSwapBuffer();
i:斷開并釋放與 EGLSurface 關(guān)聯(lián)的 EGLContext 對(duì)象:eglRelease()。
j:刪除 EGLSurface 對(duì)象,,eglDestroySurface(),。
EGL14.eglDestroySurface(display, surface);
k:刪除 EGLContext 對(duì)象,
EGL14.eglDestroyContext(display, context);
l:終止與 EGLDisplay 之間的連接,,
EGL14.eglTerminate(display);
?
5,、EGL 環(huán)境搭建示例
import android.icu.text.UFormat;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceView;
import javax.microedition.khronos.egl.EGL;
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;
import static javax.microedition.khronos.egl.EGL10.EGL_NO_CONTEXT;
public class EGLHelper {
private EGL10 mEgl;
private EGLDisplay mEglDisplay;
private EGLContext mEglContext;
private EGLSurface eglSurface;
public void init(Surface surface, EGLContext eglContext){
//1.得到Egl實(shí)例
mEgl = (EGL10) EGLContext.getEGL();
//2.得到默認(rèn)的顯示設(shè)備(就是窗口)
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
//判斷獲取默認(rèn)顯示設(shè)備是否成功
if (mEglDisplay==EGL10.EGL_NO_DISPLAY){
throw new RuntimeException("eglGetDisplay failed");
}
//3.初始化默認(rèn)顯示設(shè)備(初始化EGL)
//主版本號(hào)和次版本號(hào)
int[] version=new int[2];
boolean initialize = mEgl.eglInitialize(mEglDisplay, version);
if (!initialize){
throw new RuntimeException("eglInitialize failed");
}
Log.e("ike","version:" version[0]);
Log.e("ike","version:" version[1]);
//4.設(shè)置顯示設(shè)備的屬性
int[] attribute=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, 4,
EGL10.EGL_NONE};
//根據(jù)屬性信息從系統(tǒng)的所有的配置信息中,,獲取支持該屬性列表的配置信息的個(gè)數(shù),。一般來說就選取一個(gè)就好了
int[] num_config = new int[1];
boolean chooseConfig = mEgl.eglChooseConfig(mEglDisplay, attribute, null, 1, num_config);
if (!chooseConfig){
throw new RuntimeException("eglChooseConfig failed");
}
//判斷是否選擇到符合傳入?yún)?shù)的配置信息
if (num_config[0]<=0){
throw new IllegalArgumentException(
"No configs match configSpec");
}
//5.從系統(tǒng)中獲取對(duì)應(yīng)屬性的配置
EGLConfig[] eglConfigs=new EGLConfig[num_config[0]];
boolean eglChooseConfig = mEgl.eglChooseConfig(mEglDisplay, attribute, eglConfigs, num_config[0], num_config);
if (!eglChooseConfig){
throw new RuntimeException("eglChooseConfig$2 failed");
}
//6. 創(chuàng)建EglContext
//如果eglContext==null則創(chuàng)建新的egl上下文
int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 3,
EGL10.EGL_NONE };
if (eglContext==null){
mEglContext = mEgl.eglCreateContext(mEglDisplay, eglConfigs[0], EGL_NO_CONTEXT, null);
}else {
//根據(jù)傳入eglContext創(chuàng)建可以共享的egl上下文
mEglContext = mEgl.eglCreateContext(mEglDisplay, eglConfigs[0], eglContext, null);
}
if (mEglContext==null||mEglContext== EGL_NO_CONTEXT){
mEglContext=null;
throw new RuntimeException("eglCreateContext failed");
}
//7.創(chuàng)建surface
eglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, eglConfigs[0], surface, null);
if (eglSurface==null||eglSurface==EGL10.EGL_NO_SURFACE){
eglSurface=null;
throw new RuntimeException("eglCreateWindowSurface failed");
}
//8.綁定EGLContext和surface到顯示設(shè)備
boolean makeCurrent = mEgl.eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext);
if (!makeCurrent){
Log.e("ike","eglMakeCurrent failed");
}
}
/**
* 刷新數(shù)據(jù)
*/
public void swapBuffers(){
if (mEgl!=null){
boolean eglSwapBuffers = mEgl.eglSwapBuffers(mEglDisplay, eglSurface);
if (!eglSwapBuffers){
Log.e("ike","eglSwapBuffers failed");
}
}
}
/**
* 獲取EGL上下文
* @return
*/
public EGLContext getEGLCOntext(){
return mEglContext;
}
public void destoryEgl(){
if (mEgl!=null){
//與顯示設(shè)備解綁,銷毀eglsurface
mEgl.eglMakeCurrent(mEglDisplay,EGL10.EGL_NO_SURFACE,EGL10.EGL_NO_SURFACE,EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay,eglSurface);
eglSurface=null;
//銷毀上下文
mEgl.eglDestroyContext(mEglDisplay,mEglContext);
mEglContext=null;
//銷毀顯示設(shè)備
mEgl.eglTerminate(mEglDisplay);
mEglDisplay=null;
mEgl=null;
}
}
}
?
最后,,歡迎大家一起交流學(xué)習(xí):微信:liaosy666 ,; QQ:2209115372?。
來源:https://www./content-4-672601.html
|