Android配置EGL环境

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的环境配置,RendereronSurfaceCreated,onSurfaceChanged,onDrawFrame等函数。

从源码得知我们配置egl环境主要根据GLSurfaceView.EglHelper来写,主要分为已下几步:

1、得到Egl实例
2、得到默认的显示设备(就是窗口)
3、初始化默认显示设备
4、设置显示设备的属性
5、从系统中获取对应属性的配置
6、创建EglContext
7、创建渲染的Surface
8、绑定EglContext和Surface到显示设备中
9、刷新数据,显示渲染场景

最终代码如下:
EglHelper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175

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