OpenGl 第一站——創建自己的EglHelper

EGL

是OpenGL ES本地窗口系統的接口,不同平臺上EGL配置是不一樣的,而OpenGL的調用方式是一致的,就是說:OpenGL跨平臺就是依賴於EGL接口

爲什麼要自己創建EGL環境?

當我們需要把同一個場景渲染到不同的Surface上時,此時系統GLSurfaceView就不能滿足需求了,所以我們需要自己創建EGL環境來實現渲染操作。

注意:OpenGL整體是一個狀態機,通過改變狀態就能改變後續的渲染方式,而EGLContext(EgL上下文)就保存有所有狀態,因此可以通過共享EGLContext來實現同一場景渲染到不同的Surface上。

實現步驟參考GLSurfaceView類中的EglHelper內部類

1、得到Egl實例:

EGL10 mEgl = (EGL10) EGLContext.getEGL();

2、得到默認的顯示設備(就是窗口)

EGLDisplay mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

3、初始化默認顯示設備

int[] version = new int[2];
if (!mEgl.eglInitialize(mEglDisplay, version)) {
    throw new RuntimeException("eglInitialize failed");
}

4、設置顯示設備的屬性

int[] attrbutes = new int[]{
        //紅
        EGL10.EGL_RED_SIZE, 8,
        //綠
        EGL10.EGL_GREEN_SIZE, 8,
        //藍
        EGL10.EGL_BLUE_SIZE, 8,
        //透明度
        EGL10.EGL_ALPHA_SIZE, 8,
        //深度
        EGL10.EGL_DEPTH_SIZE, 8,
        //場景
        EGL10.EGL_STENCIL_SIZE, 8,
        //必寫
        EGL10.EGL_RENDERABLE_TYPE, 4,
        //結尾
        EGL10.EGL_NONE
};
int[] num_configs = new int[1];
if (!mEgl.eglChooseConfig(mEglDisplay, attrbutes, null, 1, num_configs)) {
    throw new IllegalArgumentException("eglChooseConfig failed");
}
int num_config = num_configs[0];

5、從系統中獲取對應屬性的配置

EGLConfig[] eglConfigs = new EGLConfig[num_config];
if (!mEgl.eglChooseConfig(mEglDisplay, attrbutes, eglConfigs, num_config, num_configs)) {
    throw new IllegalArgumentException("eglChooseConfig#2 failed");
}

6、創建EglContext

private EGLContext mEglContext;
int[] attrib_list = {
        EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
        EGL10.EGL_NONE
};
//判斷一下eglContext是否已經創建,已創建了共享
if (null != eglContext) {
    mEglContext = mEgl.eglCreateContext(mEglDisplay, eglConfigs[0], eglContext, attrib_list);
} else
    mEglContext = mEgl.eglCreateContext(mEglDisplay, eglConfigs[0], EGL10.EGL_NO_CONTEXT, attrib_list);

7、創建渲染的Surface

EGLSurface mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, eglConfigs[0], surface, null);

8、綁定EglContextSurface到顯示設備中

if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
    throw new RuntimeException("eglMakeCurrent fail");
}

9、刷新數據,顯示渲染場景

public boolean swapBuffers() {
    if (null != mEgl) {
        return mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
    } else {
        throw new RuntimeException("egl is null");
    }
}

完整代碼

public class EglHelper {
    private EGL10 mEgl;
    private EGLDisplay mEglDisplay;
    private EGLContext mEglContext;
    private EGLSurface mEglSurface;

    public void init(Surface surface, EGLContext eglContext) {
        //得到EGL實例
        mEgl = (EGL10) EGLContext.getEGL();
        //得到默認的顯示設備(就是窗口)
        mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
        if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
            throw new RuntimeException("eglGetDisplay failed");
        }
        //初始化默認顯示設備
        int[] version = new int[2];
        if (!mEgl.eglInitialize(mEglDisplay, version)) {
            throw new RuntimeException("eglInitialize failed");
        }
        //設置顯示設備的屬性
        int[] attrbutes = new int[]{
                //紅
                EGL10.EGL_RED_SIZE, 8,
                //綠
                EGL10.EGL_GREEN_SIZE, 8,
                //藍
                EGL10.EGL_BLUE_SIZE, 8,
                //透明度
                EGL10.EGL_ALPHA_SIZE, 8,
                //深度
                EGL10.EGL_DEPTH_SIZE, 8,
                //場景
                EGL10.EGL_STENCIL_SIZE, 8,
                //必寫
                EGL10.EGL_RENDERABLE_TYPE, 4,
                //結束
                EGL10.EGL_NONE
        };
        int[] num_configs = new int[1];
        if (!mEgl.eglChooseConfig(mEglDisplay, attrbutes, null, 1, num_configs)) {
            throw new IllegalArgumentException("eglChooseConfig failed");
        }
        int num_config = num_configs[0];
        if (num_config <= 0) {
            throw new IllegalArgumentException(
                    "No configs match configSpec");
        }
        //從系統中獲取對應的屬性的配置
        EGLConfig[] eglConfigs = new EGLConfig[num_config];
        if (!mEgl.eglChooseConfig(mEglDisplay, attrbutes, eglConfigs, num_config, num_configs)) {
            throw new IllegalArgumentException("eglChooseConfig#2 failed");
        }
        //創建EGLContext
        int[] attrib_list = {
                EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
                EGL10.EGL_NONE
        };
        if (null != eglContext) {
            mEglContext = mEgl.eglCreateContext(mEglDisplay, eglConfigs[0], eglContext, attrib_list);
        } else
            mEglContext = mEgl.eglCreateContext(mEglDisplay, eglConfigs[0], EGL10.EGL_NO_CONTEXT, attrib_list);
        //創建渲染的Surface
        mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, eglConfigs[0], surface, null);
        //綁定EGLContext和Surface到顯示設備中
        if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
            throw new RuntimeException("eglMakeCurrent fail");
        }

    }

    //刷新數據,顯示渲染場景
    public boolean swapBuffers() {
        if (null != mEgl) {
            return mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
        } else {
            throw new RuntimeException("egl is null");
        }
    }

    public EGLContext getEglContext() {
        return mEglContext;
    }

    //銷燬
    public void destroyEgl() {
        if (null != mEgl) {
            //銷燬Surface
            mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
            mEglSurface = null;
            //銷燬EGLContext
            mEgl.eglDestroyContext(mEglDisplay, mEglContext);
            mEglContext = null;
            //銷燬顯示設備
            mEgl.eglTerminate(mEglDisplay);
            mEglDisplay = null;

            mEgl = null;
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章