一、什么是EGL
EGL用于管理繪圖表面, 提供了如下機(jī)制:
- 與設(shè)備的原生窗口系統(tǒng)通信;
- 查詢繪制表面的可用類型和配置;
- 創(chuàng)建繪圖表面;
- 在OpenGL ES3.0 和其他圖形渲染API直接同步渲染;
- 管理紋理貼圖等渲染資源;
總之:EGL提供了OpenGL ES3.0和運(yùn)行于計(jì)算機(jī)上的原生窗口系統(tǒng)之間的一個(gè)“結(jié)合”層次。使用過(guò)程可分如下幾個(gè)步驟:
- 初始化EGL
- 確定可用表面配置
- 創(chuàng)建渲染窗口
- 創(chuàng)建一個(gè)渲染上下文
- 設(shè)置為當(dāng)前的渲染環(huán)境
二、初始化EGL
EGL10 egl10 = (EGL10) EGLContext.getEGL();
EGLDisplay eglDisplay = egl10.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (EGL10.EGL_NO_DISPLAY == eglDisplay){
//error msg
return;
}
int version[] = new int[2];
if(!egl10.eglInitialize(eglDisplay, version)){
//error msg
return;
}
eglGetDisplay方法用于獲得EGLDisplay, EGLDisplay為顯示設(shè)備。獲取成功后即可調(diào)用eglInitialize初始化EGL, 其中version[0]為主版本號(hào),version[1]為子版本號(hào)。
另外也可以調(diào)用eglQueryString來(lái)查詢EGL的相關(guān)信息,如版本號(hào)、實(shí)現(xiàn)廠家等。
例如:
String vendor = egl10.eglQueryString(eglDisplay, EGL10.EGL_VENDOR);
System.out.println("egl vendor: " + vendor); // 打印此版本EGL的實(shí)現(xiàn)廠商
三、確定可用表面配置
初始化EGL之后,就可以確定可用的渲染表面的類型和配置,有兩種方法:
- 查詢每個(gè)表面配置, 找出最好的選擇;
- 指定一組需求, 讓EGL推薦最佳匹配;
1、 查詢所有配置
EGLConfig包含EGL相關(guān)的各種屬性,如何獲取EGL支持的所有配置呢?需要用到的函數(shù)為:
boolean eglGetConfigs(EGLDisplay display, EGLConfig[] configs, int config_size, int[] num_config);
其中:
config_size為獲取EGLConfig的數(shù)量,num_config為系統(tǒng)支持的所有EGLConfig數(shù)量。函數(shù)有兩種使用方式:第一種是configs設(shè)為null,則num_config可返回可用配置的數(shù)量;第二種方式是將config_size設(shè)置為configs數(shù)組的大小,函數(shù)將返回config_size個(gè)可用配置。為了謹(jǐn)慎起見(jiàn)使用如下:
int configsNum[] = new int[1];
egl10.eglGetConfigs(eglDisplay, null, 0, configsNum);
EGLConfig eglConfig[] = new EGLConfig[configsNum[0]];
egl10.eglGetConfigs(eglDisplay, eglConfig, configsNum[0], configsNum);
獲取EGLConfig后可用eglGetConfigAttrib查詢所支持的配置信息,如查詢第i個(gè)EGLConfig中顏色緩沖區(qū)中所有顏色分量的位數(shù):
int colorBufferSize[] = new int[1];
egl10.eglGetConfigAttrib(eglDisplay, eglConfig[i], EGL10.EGL_BUFFER_SIZE, colorBufferSize);
System.out.println("EGL_BUFFER_SIZE:" + colorBufferSize[0]);
2、讓EGL選擇配置
使用函數(shù):
boolean eglChooseConfig(EGLDisplay display, int[] attrib_list, EGLConfig[] configs, int config_size, int[] num_config);
可匹配符合需要的EGLConfig。
其中:attrib_list為匹配的熟悉列表。
如果匹配成功則返回true。使用方式如下:
int[] attributes = new int[] {
EGL10.EGL_RED_SIZE, 5, //指定RGB中的R大?。╞its)
EGL10.EGL_GREEN_SIZE, 6, //指定G大小
EGL10.EGL_BLUE_SIZE, 5, //指定B大小
EGL10.EGL_DEPTH_SIZE, 1, //指定深度緩存(Z Buffer)大小
EGL10.EGL_NONE };
int chooseNum = 10;
EGLConfig chooseConfigs[] = new EGLConfig[chooseNum];
int chooseMaxNum[] = new int[1];
egl10.eglChooseConfig(eglDisplay, attributes, chooseConfigs, chooseNum, chooseMaxNum);
熟悉列表最后以EGL10.EGL_NONE結(jié)尾。
四、創(chuàng)建渲染窗口
當(dāng)找到符合渲染需求的EGLConfig后,就可以創(chuàng)建顯然窗口, 調(diào)用函數(shù)如下:
EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
五、創(chuàng)建一個(gè)渲染上下文
EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list);
其中share_context表示是否有context共享,共享的contxt之間亦共享所有數(shù)據(jù),EGL_NO_CONTEXT代表不共享;attrib_list表示可用屬性,當(dāng)前只有EGL_CONTEXT_CLIENT_VERSION, 1代表OpenGL ES 1.x, 2代表2.0。
六、設(shè)置為當(dāng)前的渲染環(huán)境
boolean eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
其中:draw為繪圖表面, read為讀取表面。
七、demo
在Android中使用OpenGL ES一般都是直接利用GLSurfaceView控件, 其封裝了EGL相關(guān)的操作,方便使用。那如何在SurfaceView中使用OpenGL ES呢? 例子如下:
- MainActivity:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback{
private EGLUtils eglUtils;
private SurfaceView view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view = new SurfaceView(this);
view.getHolder().addCallback(this);
setContentView(view);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
eglUtils = new EGLUtils();
if(eglUtils.CreateEGLEnv(holder)){
Triangle triangle = new Triangle();
triangle.draw();
eglUtils.swapBuffer();
eglUtils.destroy();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
將EGL相關(guān)操作封裝如下:
- EGLUtils:
import android.view.SurfaceHolder;
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 android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION;
import static javax.microedition.khronos.egl.EGL10.EGL_NO_CONTEXT;
import static javax.microedition.khronos.egl.EGL10.EGL_NO_SURFACE;
public class EGLUtils {
private EGLDisplay eglDisplay;
private EGL10 egl10;
private EGLSurface eglSurface;
private EGLContext eglContext;
public boolean CreateEGLEnv(SurfaceHolder holder){
egl10 = (EGL10) EGLContext.getEGL();
eglDisplay = egl10.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (EGL10.EGL_NO_DISPLAY == eglDisplay){
System.out.println("egl 不可用:err:" + egl10.eglGetError());
return false;
}
int version[] = new int[2];
if(!egl10.eglInitialize(eglDisplay, version)){
//error msg
return false;
}
int[] attributes = new int[] {
EGL10.EGL_RED_SIZE, 5, //指定RGB中的R大?。╞its)
EGL10.EGL_GREEN_SIZE, 6, //指定G大小
EGL10.EGL_BLUE_SIZE, 5, //指定B大小
EGL10.EGL_DEPTH_SIZE, 1, //指定深度緩存(Z Buffer)大小
EGL10.EGL_NONE };
int chooseNum = 10;
EGLConfig chooseConfigs[] = new EGLConfig[chooseNum];
int chooseMaxNum[] = new int[1];
egl10.eglChooseConfig(eglDisplay, attributes, chooseConfigs, chooseNum, chooseMaxNum);
System.out.println("chooseMaxNum:" + chooseMaxNum[0]);
eglSurface = egl10.eglCreateWindowSurface(eglDisplay, chooseConfigs[0], holder, null);
if(eglSurface == EGL_NO_SURFACE){
System.out.println("create surface failed,msg:" + egl10.eglGetError());
return false;
}
int[] contextAttr = new int[]{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL10.EGL_NONE
};
eglContext = egl10.eglCreateContext(eglDisplay, chooseConfigs[0], egl10.EGL_NO_CONTEXT, contextAttr);
if(eglContext == EGL_NO_CONTEXT){
System.out.println("create context failed,msg:" + egl10.eglGetError());
return false;
}
if(!egl10.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)){
System.out.println("eglMakeCurrent ailed, msg:" + egl10.eglGetError());
return false;
}
return true;
}
public void destroy(){
egl10.eglMakeCurrent(eglDisplay, EGL_NO_SURFACE,
EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
egl10.eglDestroySurface(eglDisplay, eglSurface);
egl10.eglDestroyContext(eglDisplay, eglContext);
egl10.eglTerminate(eglDisplay);
}
public void swapBuffer(){
egl10.eglSwapBuffers(eglDisplay, eglSurface);
}
}
demo以繪制一個(gè)三角形為目的,三角形如下:
- Triangle.java
import android.opengl.GLES20;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
public class Triangle {
private FloatBuffer vertexBuffer;
private static final float VERTEXS[] = {
-0.5f, 0.0f,
0.5f, 0.0f,
0.0f, 0.5f
};
private static final String vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
"gl_Position = vPosition;" +
"gl_PointSize = 10.0;" +
"}";
private static final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
"gl_FragColor = vColor;" +
"}";
private int programId;
private int vertexPositionId;
private int colorPositionId;
public Triangle(){
ByteBuffer vertexBytes = ByteBuffer.allocateDirect(
VERTEXS.length * 4);
vertexBytes.order(ByteOrder.nativeOrder());
vertexBuffer = vertexBytes.asFloatBuffer();
vertexBuffer.put(VERTEXS);
vertexBuffer.position(0);
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
programId = OpenGlUtils.loadProgram(vertexShaderCode, fragmentShaderCode);
}
public void draw(){
GLES20.glClear(GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(programId);
vertexPositionId = GLES20.glGetAttribLocation(programId, "vPosition");
colorPositionId = GLES20.glGetUniformLocation(programId, "vColor");
GLES20.glVertexAttribPointer(vertexPositionId, 2,
GLES20.GL_FLOAT, false,
0, vertexBuffer);
GLES20.glEnableVertexAttribArray(vertexPositionId);
GLES20.glUniform4f(colorPositionId, 1.0f, 0.0f, 0.0f, 0.0f);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
GLES20.glDisableVertexAttribArray(vertexPositionId);
}
}
其中OpenGlUtils在文章2. 第一個(gè)三角形。
說(shuō)明:本demo只是為了演示如果在SurfaceView中使用OpenGL ES,實(shí)際中如何使用可參考:Android example source code file (GLView.java)。
參考: