一双絮、簡介
??EGL 是渲染 API(如 OpenGL ES)和原生窗口系統(tǒng)之間的接口。
通常來說,OpenGL 是一個操作 GPU 的 API,它通過驅(qū)動向 GPU 發(fā)送相關(guān)指令剩檀,控制圖形渲染管線狀態(tài)機的運行狀態(tài),但是當涉及到與本地窗口系統(tǒng)進行交互時旺芽,就需要這么一個中間層沪猴,且它最好是與平臺無關(guān)的。
因此 EGL 被設(shè)計出來甥绿,作為 OpenGL 和原生窗口系統(tǒng)之間的橋梁
二字币、功能
??EGL API 是獨立于 OpenGL ES 各版本標準的獨立的一套 API,其主要作用是為 OpenGL 指令 創(chuàng)建 Context 共缕、繪制目標 Surface 洗出、配置 FrameBuffer 屬性、Swap 提交繪制結(jié)果 等图谷。
??EGL 提供如下機制:
與設(shè)備原生窗口通信
查詢繪制 surface 的可用類型和配置
創(chuàng)建繪制 surface
在 OpenGL ES 或其他渲染 API 之間同步渲染
管理紋理貼圖等渲染資源
??那么在安卓中翩活,已經(jīng)提供了GLSurfaceView,當我們需要把同一個場景渲染到不同的Surface上時便贵,此時系統(tǒng)GLSurfaceView
就不能滿足需求了菠镇,所以我們需要自己創(chuàng)建EGL環(huán)境來實現(xiàn)渲染操作。
??注意:OpenGL整體是一個狀態(tài)機承璃,通過改變狀態(tài)就能改變后續(xù)的渲染方式利耍,而
EGLContext(EgL上下文)就保存有所有狀態(tài),因此可以通過共享EGLContext
來實現(xiàn)同一場景渲染到不同的Surface上盔粹。
??看下在安卓設(shè)備中創(chuàng)建Egl環(huán)境的流程
- 1隘梨、得到Egl實例:
- 2、得到默認的顯示設(shè)備(就是窗口)
- 3舷嗡、初始化默認顯示設(shè)備
- 4轴猎、設(shè)置顯示設(shè)備的屬性
- 5、從系統(tǒng)中獲取對應屬性的配置
- 6进萄、創(chuàng)建EglContext
- 7捻脖、創(chuàng)建渲染的Surface
- 8、綁定EglContext和Surface到顯示設(shè)備中
- 9中鼠、刷新數(shù)據(jù)可婶,顯示渲染場景
??看下具體的執(zhí)行代碼
public class 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兜蠕、得到默認的顯示設(shè)備(就是窗口)
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay failed");
}
//3扰肌、初始化默認顯示設(shè)備
int[] version = new int[2];
if (!mEgl.eglInitialize(mEglDisplay, version)) {
throw new RuntimeException("eglInitialize failed");
}
//4、設(shè)置顯示設(shè)備的屬性
int[] attributes = 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_config = new int[1];
if (!mEgl.eglChooseConfig(mEglDisplay, attributes, 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熊杨、從系統(tǒng)中獲取對應屬性的配置
EGLConfig[] configs = new EGLConfig[numConfigs];
if (!mEgl.eglChooseConfig(mEglDisplay, attributes, configs, numConfigs,
num_config)) {
throw new IllegalArgumentException("eglChooseConfig#2 failed");
}
//6曙旭、創(chuàng)建EglContext
if (eglContext != null) {
mEglContext = mEgl.eglCreateContext(mEglDisplay, configs[0], eglContext, null);
} else {
mEglContext = mEgl.eglCreateContext(mEglDisplay, configs[0], EGL10.EGL_NO_CONTEXT, null);
}
//7盗舰、創(chuàng)建渲染的Surface
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, configs[0], surface, null);
//8、綁定EglContext和Surface到顯示設(shè)備中
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
throw new RuntimeException("eglMakeCurrent fail");
}
}
/**
* 9桂躏、刷新數(shù)據(jù)钻趋,顯示渲染場景
**/
public boolean swapBuffers() {
if (mEgl != null) {
return mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
} else {
throw new RuntimeException("egl is null");
}
}
public EGLContext getEglContext() {
return mEglContext;
}
public void destroyEgl() {
if (mEgl != null) {
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
mEglSurface = null;
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
mEglContext = null;
mEgl.eglTerminate(mEglDisplay);
mEglDisplay = null;
mEgl = null;
}
}
}
??使用起來也比較簡單
public class MainActivity extends Activity {
private SurfaceView surfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = findViewById(R.id.surface_view);
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(final SurfaceHolder holder, int format, final int width, final int height) {
new Thread() {
@Override
public void run() {
super.run();
EglHelper eglHelper = new EglHelper();
eglHelper.initEgl(holder.getSurface(), null);
while (true) {
GLES20.glViewport(0, 0, width, height);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
eglHelper.swapBuffers();
try {
Thread.sleep(16);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
}
}
??布局就一個SurfaceView即可
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
??看下最終的渲染效果
??嗯,很黃很有效剂习。