GLSurfaceView 源码分析 & EGL 创建过程

本文详细分析了GLSurfaceView的源码,包括基本用法、SurfaceHolder.Callback、EGL创建过程,重点讲解了EGL10和EGL14的创建步骤,并介绍了GLThread及其核心函数。此外,还探讨了渲染接口和GLSurfaceView的生命周期管理。
摘要由CSDN通过智能技术生成

GLSurfaceView 源码分析

基本用法

mGLView.setEGLContextClientVersion(2);
//在setRenderer之前,可以调用以下方法来进行EGL设置
//mGLView.setEGLConfigChooser();    //颜色、深度、模板等等设置
//mGLView.setEGLWindowSurfaceFactory(); //窗口设置
//mGLView.setEGLContextFactory();   //EGLContext设置
//设置渲染器,渲染主要就是由渲染器来决定
mGLView.setRenderer(new GLSurfaceView.Renderer(){
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // surface被创建后需要做的处理
    }
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        // 渲染窗口大小发生改变的处理
    }
    @Override
    public void onDrawFrame(GL10 gl) {
        // 执行渲染工作
    }
});

// RENDERMODE_WHEN_DIRTY表示被动渲染
// RENDERMODE_CONTINUOUSLY表示持续渲染*/
mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

GLSurfaceView 继承自 SurfaceView,实现了SurfaceHolder.Callback2 接口。

SurfaceHolder.Callback

使用 SurfaceView 的时候都会用到这个 Callback 回调。
一共有三个函数

  • surfaceCreated
  • surfaceChanged
  • surfaceDestroyed
    public interface Callback {
        /**
         * 当 surface 首次创建的时候回调
         */
        public void surfaceCreated(SurfaceHolder holder);

        /**
         * 当 surface 的 format 或者 size 发生改变时回调此函数。
         * 在回调surfaceCreated()之后,该函数至少被回调一次
         */
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height);

        /**
         * 在 surface 被销毁之前回调。此函数回调之后就不能在访问 surface 了。
         */
        public void surfaceDestroyed(SurfaceHolder holder);
    }

SurfaceHolder.Callback2

  • surfaceRedrawNeeded
  • surfaceRedrawNeededAsync

这两个函数并不常用。

    /**
     * SurfaceHolder.Callback的扩展接口
     */
    public interface Callback2 extends Callback {
        /**
         * Called when the application needs to redraw the content of its
         * surface, after it is resized or for some other reason.  By not
         * returning from here until the redraw is complete, you can ensure that
         * the user will not see your surface in a bad state (at its new
         * size before it has been correctly drawn that way).  This will
         * typically be preceeded by a call to {@link #surfaceChanged}.
         *
         * As of O, {@link #surfaceRedrawNeededAsync} may be implemented
         * to provide a non-blocking implementation. If {@link #surfaceRedrawNeededAsync}
         * is not implemented, then this will be called instead.
         *
         * @param holder The SurfaceHolder whose surface has changed.
         */
        void surfaceRedrawNeeded(SurfaceHolder holder);

        /**
         * An alternative to surfaceRedrawNeeded where it is not required to block
         * until the redraw is complete. You should initiate the redraw, and return,
         * later invoking drawingFinished when your redraw is complete.
         *
         * This can be useful to avoid blocking your main application thread on rendering.
         *
         * As of O, if this is implemented {@link #surfaceRedrawNeeded} will not be called.
         * However it is still recommended to implement {@link #surfaceRedrawNeeded} for
         * compatibility with older versions of the platform.
         *
         * @param holder The SurfaceHolder which needs redrawing.
         * @param drawingFinished A runnable to signal completion. This may be invoked
         * from any thread.
         *
         */
        default void surfaceRedrawNeededAsync(SurfaceHolder holder, Runnable drawingFinished) {
            surfaceRedrawNeeded(holder);
            drawingFinished.run();
        }
    }

继续查看 GLSurfaceView的关键代码:

public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback2 {

	  private static final GLThreadManager sGLThreadManager = new GLThreadManager(); // 线程管理类

    private final WeakReference<GLSurfaceView> mThisWeakRef =
            new WeakReference<GLSurfaceView>(this);
    private GLThread mGLThread; // GL 线程
    private Renderer mRenderer; // GLSurfaceView 的回调接口
    private boolean mDetached;
    private EGLConfigChooser mEGLConfigChooser;
    private EGLContextFactory mEGLContextFactory;
    private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
    private GLWrapper mGLWrapper;
    private int mDebugFlags;
    private int mEGLContextClientVersion;
    private boolean mPreserveEGLContextOnPause;


    public GLSurfaceView(Context context) {
        super(context);
        init();
    }

    /**
     * Standard View constructor. In order to render something, you
     * must call {@link #setRenderer} to register a renderer.
     */
    public GLSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
    }

	  // 设置渲染接口
	  public void setRenderer(Renderer renderer) {
        checkRenderThreadState();
        if (mEGLConfigChooser == null) {
            mEGLConfigChooser = new SimpleEGLConfigChooser(true);
        }
        if (mEGLContextFactory == null) {
            mEGLContextFactory = new DefaultContextFactory();
        }
        if (mEGLWindowSurfaceFactory == null) {
            mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
        }
        mRenderer = renderer;
        mGLThread = new GLThread(mThisWeakRef);
        mGLThread.start();
    }

	  // 检查渲染线程状态
	  private void checkRenderThreadState() {
        if (mGLThread != null) {
            throw new IllegalStateException(
                    "setRenderer has already been called for this instance.");
        }
    }

	/**
     * 设置渲染模式
     * @see #RENDERMODE_CONTINUOUSLY
     * @see #RENDERMODE_WHEN_DIRTY
     */
    public void setRenderMode(int renderMode) {
        mGLThread.setRenderMode(renderMode);
    }

    /**
     * Override SurfaceHolder.Callback interface
     */
    public void surfaceCreated(SurfaceHolder holder) {
        mGLThread.surfaceCreated();
    }

    /**
     * Override SurfaceHolder.Callback interface
     */
    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return
        mGLThread.surfaceDestroyed();
    }

    /**
     * Override SurfaceHolder.Callback interface
     */
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        mGLThread.onWindowResize(w, h);
    }		

}

通过 checkRenderThreadState() 函数可以看出,setRender() 函数调用多次会导致 ::IllegalStateException:: 。

有几个关键的类:

  • GLThreadManager
  • GLThread
  • Renderer
  • EGLConfigChooser
  • EGLContextFactory
  • EGLWindowSurfaceFactory
  • GLWrapper
  • EglHelper

要了解这几个类的用途,先来说下 EGL 的创建过程。

GLSurfaceView内部管理一个 surface,用来负责 OpenGL 的渲染工作,


EGL

EGL 环境的创建过程如下图:

  • 获取默认的显示设备
  • 初始化显示设备
  • 从系统中获取对应属性的配置
  • 创建 EglContext
  • 创建渲染的 Surface
  • 绑定 EglContext 和 Surface 到显示设备中
  • 刷新数据,显示渲染场景

初始化 EGL 环境通常使用 EGL10或者 EGL14。SDK版本大于17,优先使用 EGL14。

EGL10

创建EGL10环境的大概过程如下:

        // 1. 获取 EGL 实例
        val egl = EGLContext.getEGL() as EGL10
        // 2. 获取默认的显示设备
        val eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)
        if (eglDisplay == EGL10.EGL_NO_DISPLAY) {
            // todo error
        }
        // 3. 初始化显示设备
        val version = IntArray(2)
        val initializeResult = egl.eglInitialize(eglDisplay, version)
        if (!initializeResult) {
            // todo error
        }
        // 4. 设置显示设备的属性
        val attributes = intArrayOf(
                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)
        val configNum = IntArray(1)
        var chooseResult = egl.eglChooseConfig(eglDisplay, attributes, null, 1, configNum)
        if (!chooseResult) {
            // todo error
        }
        // 5. 从系统中获取对应属性的配置
        val configs = arrayOfNulls<EGLConfig>(configNum[0])
        chooseResult = egl.eglChooseConfig(eglDisplay, attributes, configs, configNum[0], configNum)
        if (!chooseResult) {
            // todo error
        }
        // 6. 创建 EGLContext
        val eglContext = egl.eglCreateContext(eglDisplay, configs[0], EGL10.EGL_NO_CONTEXT, null)
        if (eglContext == EGL10.EGL_NO_CONTEXT) {
            // todo error
        }
        // 7. 创建渲染的 Surface
        val eglSurface = egl.eglCreateWindowSurface(eglDisplay, configs[0], EGL10.EGL_NO_SURFACE, null)
        if (eglSurface == EGL10.EGL_NO_SURFACE) {
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值