本文是OpenGL ES 2.0源码分析的第二篇,关于设置OpenGL ES配置选择,从源码角度去追溯设置配置选择到底做了哪些事情。
还是先列出我们使用OpenGL ES 2.0的过程:
mGLSurfaceView.setEGLContextClientVersion(2);
mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
mGLSurfaceView.setRenderer(new TexRenderer(this));
mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
今天我们的主角是:mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);,跟踪源码,我们可以看到:
public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
int alphaSize, int depthSize, int stencilSize) {
// 调用了另一个设置EGL配置选择的方法
setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize,
blueSize, alphaSize, depthSize, stencilSize));
}
继续跟踪
public void setEGLConfigChooser(EGLConfigChooser configChooser) {
// 还是检测GL线程是否被初始化,如果被初始化直接抛异常
checkRenderThreadState();
// 设置本地字段
mEGLConfigChooser = configChooser;
}
代码的内容很简单,不过我们既然来了,就好好看下EGLConfigChooser是个什么。
public interface EGLConfigChooser {
EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
}
其实可以发现就是一个接口,那么ComponentSizeChooser跟它又有什么关系呢?追踪代码,最后我们可以知道,他们的关系如下:
- ComponentSizeChooser extends BaseConfigChooser
- BaseConfigChooser implements EGLConfigChooser
通过观看源代码,其实可以发现ComponentSizeChooser主要是调用父类BaseConfigChooser去初始化数据:
public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
int alphaSize, int depthSize, int stencilSize) {
// 调用父类构造函数
super(new int[] {
EGL10.EGL_RED_SIZE, redSize,
EGL10.EGL_GREEN_SIZE, greenSize,
EGL10.EGL_BLUE_SIZE, blueSize,
EGL10.EGL_ALPHA_SIZE, alphaSize,
EGL10.EGL_DEPTH_SIZE, depthSize,
EGL10.EGL_STENCIL_SIZE, stencilSize,
EGL10.EGL_NONE});
// 本类中也保存一份数据
mValue = new int[1];
mRedSize = redSize;
mGreenSize = greenSize;
mBlueSize = blueSize;
mAlphaSize = alphaSize;
mDepthSize = depthSize;
mStencilSize = stencilSize;
}
那么父类到底做了什么呢?
public BaseConfigChooser(int[] configSpec) {
mConfigSpec = filterConfigSpec(configSpec);
}
是不是很简单,主要看filterConfigSpec这个方法做了什么。
private int[] filterConfigSpec(int[] configSpec) {
// 如果设置的不是es2或者es3就直接返回,所以这个设置不能在设置版本之前设置
if (mEGLContextClientVersion != 2 && mEGLContextClientVersion != 3) {
return configSpec;
}
/* 我们知道没有任何子类定义EGL_RENDERABLE_TYPE.
* 我们也知道 configSpec 被很好的格式化.
*/
int len = configSpec.length;
// 新创建一个 len + 2 长度的数组
int[] newConfigSpec = new int[len + 2];
// 将老数据拷贝到新数组中
System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1);
// 设置倒数第三位为EGL10.EGL_RENDERABLE_TYPE
newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE;
// 根据不同版本设置新数组的倒数第二位的值
if (mEGLContextClientVersion == 2) {
newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT; /* EGL_OPENGL_ES2_BIT */
} else {
newConfigSpec[len] = EGLExt.EGL_OPENGL_ES3_BIT_KHR; /* EGL_OPENGL_ES3_BIT_KHR */
}
// 设置倒数第一位的值为EGL10.EGL_NONE
newConfigSpec[len+1] = EGL10.EGL_NONE;
return newConfigSpec;
}
到此关于ComponentSizeChooser的分析就结束了,至于里面其他的函数目前暂不分析。
通过上面的源码分析,我们其实对这个配置选择的设置有了一个认识,那么我们来看看到底哪里使用到了mEGLConfigChooser,唯一使用到的地方就是在setRenderer里面,里面有一段:
if (mEGLConfigChooser == null) {
mEGLConfigChooser = new SimpleEGLConfigChooser(true);
}
其实就是如果我们没有设置配置选择,给一个默认的:
private class SimpleEGLConfigChooser extends ComponentSizeChooser {
public SimpleEGLConfigChooser(boolean withDepthBuffer) {
super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0);
}
}
所以在android-26源码中默认是8, 8, 8, 0, 16, 0。
总结: 其实这一步做的挺少,如果设置了就初始化一些数据,没有设置配置选择就给一个默认的,至于配置选择的作用,我们会在使用的时候继续深入理解。