相关文章推荐

EGL全称:Embedded-System Graphics Library。

显示设备的参数设置有十多种,不同硬件系统之间差异很大,比如有的不支持RGB_565,所以维护OpenGLES的khronos组织专门抽出一层,以适配各平台的差异,这个抽象层即EGL。

OpenGLES定义了平台无关的GL绘图指令,EGL则定义了控制 displays、contexts 以及 surfaces 的统一的平台接口。

java是跨平台的,是因为java虚拟机打平了各平台的差异。同理,EGL打平了各平台底层图形硬件的差异,所以openGL ES才能跨平台。类似的功能库有SDL、GLFW、GLUT等。

下文中GL指的OpenGL ES,不再说明。

为什么要用到EGL

基于GLSurfaceView,就可以很简单的继成GL,Android平台替开发者屏蔽了复杂的EGL,懂一点GL就可以渲染酷炫的效果,在图像、视频处理中有广泛的应用。

弊端是,如果有比较复杂的定制,GLSurfaceView就不够用了。比如应用中有多个GL环境,需要动态切换,或多个GL环境需要共享GLContext(context保存了GL的状态、资源),而GLSurfaceView中EGL的实现是默认写死的。

GLSurfaceView源码中,有一个EglHelper类处理了EGL初始化配置的逻辑,后面还会讲到。

Java层配置EGL,自定义GLSurfaceView,参考

继成SurfaceView,完整实现一个GLSurfaceView,就很清楚的了解GLSurfaceView替我们干了啥。

把最核心的逻辑抠出来,画了张流程图:

GLSurfaceView的工作流程:

  • 设置Renderer
  • addCallback(SurfaceView方法)
  • 实现EGLThread(常说的渲染线程)
  • 初始化EGL
  • while(true)中循环调用onSurfaceCreated()、onSurfaceChanged()、onDrawFrame()
  • 从实现EglHelper.java开始,仿照GLSurfaceView自己实现一遍

    实现EglHelper,封装EGL初始化逻辑

    EGL像个中介,把Display、Surface、Context绑到一起,让这三者结合到一起,紧密配合,碰撞出爱的火花。初始化及绑定的工作封装在EglHelper中。

    上图用代码实现,流程如下:

    EGL实例

  • 得到Egl实例
  • Display

  • 得到默认的显示设备(就是窗口)
  • 初始化默认显示设备
  • 设置显示设备的属性
  • 从系统中获取对应属性的配置
  • Context

  • 创建EglContext
  • Surface

  • 创建渲染的Surface
  • 绑定EglContext和Surface到显示设备中
  • 渲染到屏幕

  • 刷新数据,显示渲染场景
  • EGL设置略繁琐,但是逻辑并不复杂,详细参考github代码

    GLSurfaceView实现

    GLSurfaceView最核心的逻辑是实现了GLThread,该线程中处理了EGL初始化,以及drawFrame等重要回调

    GLThread run()函数实现比较重要单独拿出来看看,完整代码参考

    重点关注:

  • EGLHelper初始化
  • 不同的RenderMode,如何处理
  • onCreate() onChange(width, height) onDraw()回调时机
  •  @Override
    public void run() {
        super.run();
        try {
            guardedRun();
        } catch (InterruptedException e) {
            e.printStackTrace();
    private void guardedRun() throws InterruptedException {
        isExit = false;
        isStart = false;
        object = new Object();
        mEglHelper = new EglHelper();
        mEglHelper.initEgl(mEGLSurfaceViewWeakRef.get().mSurface, mEGLSurfaceViewWeakRef.get().mEglContext);
        while (true) {
            if (isExit) {
                // 释放资源
                release();
                break;
            if (isStart) {
                if (mEGLSurfaceViewWeakRef.get().mRenderMode == RENDERMODE_WHEN_DIRTY) {
                    synchronized(object) {
              // 自动绘制模式下,等待数据更新通知
                        object.wait();
                } else if (mEGLSurfaceViewWeakRef.get().mRenderMode == RENDERMODE_CONTINUOUSLY) {
              // 近似1秒绘制60次
                    Thread.sleep(1000 / 60);
                } else {
                    throw new IllegalArgumentException("renderMode");
            // 三个重要的回调,回调里有判断是否需要执行
            onCreate();
            onChange(width, height);
            onDraw();
            isStart = true;
    

    Activity中使用自定义的GLSurfaceView

    demo很简单,点击GLSurfaceView,触发更改颜色。重要的是把整个流程串起来,弄明白了,可以使用OpenGL定义更有意思的效果。

    实现效果:

    完成Demo:

    public class EglMainActivity extends AppCompatActivity implements EglSurfaceView.Renderer{ public static final String TAG = "EglMainActivity"; private EglSurfaceView eglSurfaceView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); eglSurfaceView = new EglSurfaceView(this); setContentView(eglSurfaceView); eglSurfaceView.setRenderer(this); eglSurfaceView.setRendererMode(EglSurfaceView.RENDERMODE_WHEN_DIRTY); eglSurfaceView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { eglSurfaceView.requestRender(); @Override public void onSurfaceCreated() { Log.e(TAG, "onSurfaceCreated"); @Override public void onSurfaceChanged(int width, int height) { Log.e(TAG, "onSurfaceChanged"); GLES20.glViewport(0, 0, width, height); @Override public void onDrawFrame() { Log.e(TAG, "onDrawFrame"); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); float r = (float) Math.random(); float g = (float) Math.random(); float b = (float) Math.random(); GLES20.glClearColor(r, g, b, 1.0f);

    GL线程分析,这篇文章讲的非常好,建议认真阅读

    EGL OpenGLES版本选择说明参考

    Native层配置EGL

    开发复杂的渲染功能时,opengl egl相关的代码放到C++层更方便,比如搭建一个渲染引擎,大多数库都是c++版本的。另一方面,C++层执行逻辑效率会高一些。

    需要对NDK、C++开发有一定的了解。

    接下来,我们讲讲Native方式配置EGL,逻辑和Java层的差不多。

    完整工程:

    github.com/summer-go/A…

    重点讲不一样的地方:

    Android Studio 新建C++工程

    工程目录:

    代码逻辑:

    CMakeLists.txt配置

    # cmake最小版本
    cmake_minimum_required(VERSION 3.4.1)
    add_library( # Sets the name of the library.
            native-lib
            SHARED
            native-lib.cpp
            egl/EglHelper.cpp
            egl/EglThread.cpp
    find_library( # Sets the name of the path variable.
            log-lib
            # Specifies the name of the NDK library that
            # you want CMake to locate.
            log)
    target_link_libraries( # Specifies the target library.
            native-lib
            # Links the target library to the log library
            # included in the NDK.
            ${log-lib}
            GLESv2
            android
    

    实现EglHelper.cpp EglThread.cpp

    逻辑与java层差不多,换成c++实现而已,详细参考工程代码

    封装jni

    jni逻辑放在native-lib.cpp,是C++工程自动创建的文件,名字我也懒得改,就在里面造了。比较简单:

    EglThread *eglThread = NULL; // surfaceCreate回调 void callBackOnCreate(){ LOGE("callBackOnCreate"); // surface size change回调 void callBackOnChange(int width, int height){ LOGE("callBackOnChange"); // 最重要的draw回调 void callBackOnDraw(){ glClearColor(0.0, 1.0, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); LOGE("callBackOnDraw"); // native接口,surfaceCreate // 设置好三个重要的回调指针,设置渲染模式 // 从SurfaceView中获取ANativeWindow extern "C" JNIEXPORT void JNICALL Java_com_android_samples_nativeegl_opengl_NativeOpenGL_nativeSurfaceCreate(JNIEnv *env,jobject thiz,jobject surface) { eglThread = new EglThread(); eglThread->callBackOnCreate(callBackOnCreate); eglThread->callBackOnChange(callBackOnChange); eglThread->callBackOnDraw(callBackOnDraw); eglThread->setRenderModule(RENDER_MODULE_MANUAL); ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env, surface); eglThread->onSurfaceCreate(nativeWindow); // 调用surfaceChange extern "C" JNIEXPORT void JNICALL Java_com_android_samples_nativeegl_opengl_NativeOpenGL_nativeSurfaceChanged(JNIEnv *env, jobject thiz,jint width,jint height) { if(eglThread){ eglThread->onSurfaceChange(width, height); // 调用SurfaceDestroyed extern "C" JNIEXPORT void JNICALL Java_com_android_samples_nativeegl_opengl_NativeOpenGL_nativeSurfaceDestroyed(JNIEnv *env,jobject thiz) { if(eglThread){ eglThread->isExit = true; //等待线程结束 pthread_join(eglThread->mEglThread, NULL); delete eglThread; eglThread = NULL;

    NativeGLSurfaceView实现

    NativeGLSurfaceView继承SurfaceView,几乎是个壳子,关键方法里调到Native方法

    class NativeGLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
        private NativeOpenGL mNativeOpenGL;
        public NativeGLSurfaceView(Context context) {
            this(context, null);
        public NativeGLSurfaceView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        public NativeGLSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mNativeOpenGL = new NativeOpenGL();
            getHolder().addCallback(this);
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            mNativeOpenGL.nativeSurfaceCreate(holder.getSurface());
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            mNativeOpenGL.nativeSurfaceChanged(width, height);
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            mNativeOpenGL.nativeSurfaceDestroyed();
    

    NativeOpenGL封装Native方法 java层接口 so easy

    class NativeOpenGL {
        static {
            System.loadLibrary("native-lib");
        public native void nativeSurfaceCreate(Surface surface);
        public native void nativeSurfaceChanged(int width, int height);
        public native void nativeSurfaceDestroyed();
    

    最后在Activity中调用NativeGLSurfaceView

    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    

    SurfaceView写在布局中

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity">
        <com.android.samples.nativeegl.opengl.NativeGLSurfaceView
                android:id="@+id/sample_text"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    实现效果很简单,随便画个颜色

    你也可以改成自己喜欢的颜色 修改native-lib.cpp callBackOnDraw方法

    void callBackOnDraw(){
        glClearColor(0.0, 1.0, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        LOGE("callBackOnDraw");
    

    开发一个完整的demo,涉及到不少细节,无法在一篇文章中详细阐述,读者朋友们有时间,可以读读文末附录的参考

    欢迎关注公众号:sumsmile /专注图像处理的移动开发老兵~~

    Android配置EGL环境: www.jianshu.com/p/ce3496ab9…

    Android自定义GLSurfaceView: www.jianshu.com/p/08f9338ae…

    EglHelper实现: github.com/summer-go/A…

    EglSurfaceView实现: github.com/summer-go/A…

    剖析EGL及GL线程源码: cloud.tencent.com/developer/a…

    EGL OpenGLES版本选择: www.cnblogs.com/kiffa/archi…

    eglmakeCurrent api: www.khronos.org/registry/EG…;

    makeCurrent、eglSwapBuffers: www.zybuluo.com/SR1s/note/6…

    非常棒的EGL opengl示意图: www.icode9.com/content-4-6…

    c++ lock使用: blog.csdn.net/u012109245/…

    android c++ EGL环境实现: www.jianshu.com/p/cb34f965a…

    分类:
    Android
    标签:
     
    推荐文章