二、OpenGL ES 2.0之配置选择源码分析

648 阅读3分钟

本文是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

总结: 其实这一步做的挺少,如果设置了就初始化一些数据,没有设置配置选择就给一个默认的,至于配置选择的作用,我们会在使用的时候继续深入理解。