Android使用OpenGL ES需要搭配GLSurfaceView、Renderer,当然也可以使用TextureView,不过TextureView没有GLSurfaceView的OpenGL ES初始化操作,所以使用起来有些麻烦,需要自定义OpenGL初始化,本文使用GLSurfaceView初始化OpenGL ES。
首先讲一下Android中View,GLSurfaceView和TextureView等的区别吧
##初始化OpenGL##
一般步骤如下:
前三步的代码可参考如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//实例化一个GLSurfaceView
mGLSurfaceView = new GLSurfaceView(this);
//检查设备是否支持OpenGL ES 2.0
final ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
final boolean supportES2 = configurationInfo.reqGlEsVersion >= 0x00020000;
//配置OpenGL ES,主要是版本设置和设置Renderer,Renderer用于执行OpenGL的绘制
if (supportES2) {
mGLSurfaceView.setEGLContextClientVersion(2);
mGLSurfaceView.setRenderer(new MyRenderer());
renderSet = true;
} else {
Toast.makeText(getApplicationContext(),"不支持OpenGL ES 2.0版本",Toast.LENGTH_SHORT).show();
return;
}
//在屏幕上显示GLSurfaceView
setContentView(mGLSurfaceView);
}
创建Renderer渲染器的代码如下:
public class MyRenderer implements GLSurfaceView.Renderer {
//当Surface创建后会调用此方法
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
glClearColor(1.0f,0.0f,0.0f,0.0f);//清空屏幕的颜色,本例为红色
}
//当Surface创建成功或尺寸改变时都调用此方法
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
glViewport(0,0,width,height);
}
//每绘制一帧都会调用此方法
@Override
public void onDrawFrame(GL10 gl) {
//清空颜色缓冲区,然后使用glClearColor()方法设置填充屏幕的颜色
glClear(GL_COLOR_BUFFER_BIT);
}
}
GL10 gl这个参数是OpenGL ES 1.0遗留下来的,如果使用OpenGL ES 2.0以上版本可以忽略它
现在运行起来屏幕会显示空白的红色窗口,初始化OpenGL就是这么简单
##Renderer子线程原理
之前讲了GLSurfaceView是在新的线程更新画面,也就是执行Renderer,现在通过源码来分析一下是如何做到的。
首先我们给GLSurfaceView设置Renderer渲染器是通过下面这个方法。
mGLSurfaceView.setRenderer(new MyRenderer());
我们进到此方法中,发现它会创建一个GLThread线程并启动
public void setRenderer(Renderer renderer) {
......
//将renderer赋值给GLSurfaceView的实例变量mRenderer
mRenderer = renderer;
mGLThread = new GLThread(mThisWeakRef);
mGLThread.start();
}
mThisWeakRef是此GLSurfaceView的一个虚引用,防止内存泄露,它是GLSurfaceView的一个实例变量
private final WeakReference mThisWeakRef =
new WeakReference(this);
GLThread线程的run方法会执行guardedRun()方法
@Override
public void run() {
......
try {
guardedRun();
} catch (InterruptedException e) {
// fall thru and exit normally
} finally {
sGLThreadManager.threadExiting(this);
}
}
guardedRun方法里面首先会创建一个EglHelper实例,它是用来初始化EGL环境配置的,然后启动一个无限循环
private void guardedRun() throws InterruptedException {
mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);
while (true) {
......
}
}
这个无限循环里面东西很多,核心为一下几块:
mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);
......
try {
mEglHelper.start();//
} catch (RuntimeException t) {
sGLThreadManager.releaseEglContextLocked(this);
throw t;
}
mHaveEglContext = true;
createEglContext = true;
//如果EGL环境配置好了,会执行onSurfaceCreated()方法,这个方法实际使用时可能会被多次调用,比如设备被唤醒或从别的Activity切换到此Activity时
if (createEglContext) {
//mGLSurfaceViewWeakRef就是前面的mThisWeakRef,它是GLThread构造函数里面设置的,通过mGLSurfaceViewWeakRef获取到所指的GLSurfaceView
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
try {
view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
createEglContext = false;
}
当Surface的尺寸改变时就会调用onSurfaceChanged()方法
if (sizeChanged) {
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
try {
view.mRenderer.onSurfaceChanged(gl, w, h);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
sizeChanged = false;
}
它是在代码块中执行的,也就是说每绘制一帧时都会执行onDrawFrame()方法
{
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
try {
view.mRenderer.onDrawFrame(gl);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
}
onDrawFrame()执行之后会交换前后缓冲区。
int swapError = mEglHelper.swap();
public int swap() {
if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
return mEgl.eglGetError();
}
return EGL10.EGL_SUCCESS;
}