AndroidWay

GUI:GLSurfaceView

2016-11-15  本文已影响599人  81bad73e9053

1.java层使用EGL和OpengLES的两种方式

第一种:使用GLES类,这些类会通过jni 的方式调用到c/c++层的EGL和OpenGLES(这种方式程序编写方式复杂)
第二种:GLSurfaceView

GLSurfaceView继承自SurfaceView,也就意味着它有所有view类的功能和属性,特别是处理事件的能力,同时GLSurfaceView也拥有OpenGlES所提供的图形处理能力

GLSurfaceView的功能

2.GLSurfaceView的使用步骤

第一步:创建GLSurfaceView

GLSurfaceView也是View,可以通过布局文件的方式将它加入整棵view树中

第二步:初始化OpenGLES环境

GLSurfaceView默认情况下已经为开发人员搭建好了OpenGLES的运行环境,因而如果没有特别的要求,并不需要做额外的工作。开发人员可以更改一些默认的设置

setEGLConfigChooser(boolean);
setGLWrraper(GLWrapper);

第三步:设置Renderer

渲染是OpenGLES的核心工作,setRenderer可以将用户自定义的一个Renderer加入实际的渲染流程中。

第四步:设置RenderingMode

GLSurfaceView默认采用的是连续渲染的方式,如有需要可以通过这个方法更改渲染方式

第五步:状态处理

使用GLSurfaceView需要注意程序的声明周期,Activity会有暂停和恢复等状态,为了达到最优效果,GLSurfaceView也需根据这些状态来做相应的处理,比如Activity暂停时需要GLSurfaceView的onPause,恢复时需要GLSurfaceView的onResume等,这样能使OpenGLES的内部线程做出正确的判断,从而保证应用程序的稳定性

开发基于GLSurfaceView的程序,主要的工作就是设置Renderer,其他过程,例如EGL的创建,Surface的分配以及OpenGLES的调用都被隐藏起来了。

3.GLSurfaceView的创建过程

public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {

    public GLSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    
     private void init() {
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed
        SurfaceHolder holder = getHolder();
        holder.addCallback(this); //添加回调,这样surface有变化的时候就能收到通知了
    }
    //..........    
}   

3.1 Callback

    public interface Callback {
        /**当成功申请到一个Surface的时候被调用,一般情况下只会发生一次
         * This is called immediately after the surface is first created.
         * Implementations of this should start up whatever rendering code
         * they desire.  Note that only one thread can ever draw into
         * a Surface, so you should not draw into the Surface here
         * if your normal rendering will be in another thread.
         */
        public void surfaceCreated(SurfaceHolder holder);

        /**当Surface改变时调用,如format和size的更动
         * This is called immediately after any structural changes (format or
         * size) have been made to the surface.  You should at this point update
         * the imagery in the surface.  This method is always called at least
         * once, after surfaceCreated
         */
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height);

        /**当Surface销毁时调用
         * This is called immediately before a surface is being destroyed. After
         * returning from this call, you should no longer try to access this
         * surface.  If you have a rendering thread that directly accesses
         * the surface, you must ensure that thread is no longer touching the 
         * Surface before returning from this function
         */
        public void surfaceDestroyed(SurfaceHolder holder);
    }

3.2SurfaceHolder的创建

     private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
        //....
        public void addCallback(Callback callback) {
            synchronized (mCallbacks) { 
                if (mCallbacks.contains(callback) == false) {      
                    mCallbacks.add(callback);
                }
            }
        }
     //....
     }

SurfaceView中,mSurfaceHolder 是一个全局变量,addCallback用于将接受回调通知的类加入到mCallbacks队列中,如GLSurfaceView在构造方法中调用addCallback方法,这样当SurfaceHolder有变化的时候就能通知到GLSurfaceView。

3.3 SurfaceView中surface的申请(与一般的View不同)

TU 17-11SurfaceView中Surface的申请过程

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mParent.requestTransparentRegion(this);
        //mSession是ViewRoot与WMS的通信中介
        mSession = getWindowSession();
        mLayout.token = getWindowToken();
        mLayout.setTitle("SurfaceView");
        //...
    }

    
    private void updateWindow(boolean force, boolean redrawNeeded) {  
        ViewRootImpl viewRoot = (ViewRootImpl) getRootView().getParent();
        relayoutResult = mSession.relayout(
                        mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
                            visible ? VISIBLE : GONE,
                            WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY,
                            mWinFrame, mContentInsets,
                            mVisibleInsets, mConfiguration, mNewSurface);        
    mSurface.transferFrom(mNewSurface);
    }   

1.一般情况下,SurfaceView是布局在某个ViewGroup中的,当ViewRoot成功AttachToWindow之后,它需要将这一事件告诉View树中的所有成员
2.SurfaceView收到AttachToWindow成功的消息后,会通过getWindowSession方法获取一个IWindowSession,IWindowSession是ViewRoot与WMS的通信中介。
3.SurfaceView在updateWindow的时候,利用IWindowSession.relayout()来重新申请一个Surface,其中最后一个参数就是WMS新生成的Surface。
4.SurfaceView获取到新的Surface之后,会Transfer到mSurface变量中,然后再通知所有注册了Callback的对象,如GLSurfaceView。这样SurfaceView的Surface就创建成功了。

3.4Surface申请成功之后,GLSurfaceView的操作

    public void surfaceCreated(SurfaceHolder holder) {
        mGLThread.surfaceCreated();
    }

public void surfaceCreated() {
    synchronized(sGLThreadManager) {
         
        mHasSurface = true;
        mFinishedCreatingEglSurface = false;
        sGLThreadManager.notifyAll();
        while (mWaitingForSurface
               && !mFinishedCreatingEglSurface
               && !mExited) { 
                sGLThreadManager.wait();                    
        }
    }
}

GLSurfaceView会启动一个工作线程来完成渲染,避免阻塞UI主线程,这个工作线程就是mGLThread,这个线程在应用程序setRederer的时候启动,然后不停地等待和处理事件,同时还负责开展Render工作。

public void setRenderer(Renderer renderer) {
    checkRenderThreadState(); 
    mRenderer = renderer;
    //mGLThread在setRenderer时初始化并启动
    mGLThread = new GLThread(mThisWeakRef);
    mGLThread.start();
}

static class GLThread extends Thread {
    @Override
    public void run() { 
        guardedRun();
    }
}

3.5 guardedRun

private void guardedRun() throws InterruptedException {
        while (true) {//死循环,除非主动跳出
            synchronized (sGLThreadManager) {
                while (true) {
                    if (mShouldExit) {//是否需要结束循环
                        return;
                    }
                    //从EventQueue中取出消息
                    if (! mEventQueue.isEmpty()) {
                        event = mEventQueue.remove(0);
                        break;
                    }


                    // When pausing, release the EGL surface:
                    if (pausing && mHaveEglSurface) {
                        //如果acitivity已经暂停,释放surface
                        stopEglSurfaceLocked();
                    }

                    // When pausing, optionally release the EGL Context:

                    // Have we lost the SurfaceView surface?
                    //判断Surface是否丢失
                    if ((! mHasSurface) && (! mWaitingForSurface)) {
                        //如果当前没有Surface,而且也不再等待Surface的创建,说明已经失去了Surface
                        if (mHaveEglSurface) {
                            stopEglSurfaceLocked();
                        }
                        mWaitingForSurface = true;
                        mSurfaceIsBad = false;
                        sGLThreadManager.notifyAll();
                    }

                    // Have we acquired the surface view surface?
                    if (mHasSurface && mWaitingForSurface) {
                        //如果已经成功获取到Surface,那就重新设置相应的全局变量
                        mWaitingForSurface = false;
                        //通知任何在等待的线程
                        sGLThreadManager.notifyAll();
                    }

                    // Ready to draw?
                    if (readyToDraw()) {
                    //这里是最核心的工作,根据应用程序设置的Renderer来进行图形渲染
                    } 
                    sGLThreadManager.wait();
                }
            } // end of synchronized(sGLThreadManager)

            if (event != null) {
                event.run();
                event = null;
                continue;
            }

            if (createEglSurface) {//EglSurface需要被创建
                //.....创建
                //创建成功之后设置标志位
                createEglSurface = false;
            }
            
            if (sizeChanged) { 
                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                if (view != null) {//通知应用程序发生了变化
                    view.mRenderer.onSurfaceChanged(gl, w, h);
                }
                sizeChanged = false;
            } 
            
            {
                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                if (view != null) {//调用应用程序的Renderer
                    view.mRenderer.onDrawFrame(gl);
                }
            }
            //通过swap把渲染结果显示到屏幕上
            int swapError = mEglHelper.swap();
             
        }           
}

第一步:判断事件队列是否为空,如果有事件需要处理,则直接跳出内循环,否则依然在内循环运行
第二步:1.判断是否需要释放EGLSurface,2.判断是否丢失了Surface,mHasSurface表示当前有没有可用的Surface,mWaitingForSurface表示是否在申请Surface的过程中,3.是否需要放弃EGLContext
第三步:经过以上的判断之后,程序进入图形渲染前的准备工作,也就是readyToDraw之间的代码
第四步:一旦程序执行到这里也就是跳出了内循环,有两种可能,第一是EventQueue中有需要处理的事件,第二是需要执行渲染工作

3.6 readyToDraw

// Ready to draw?
if (readyToDraw()) { 
    // If we don't have an EGL context, try to acquire one.
    if (! mHaveEglContext) {//没有EGLContext的情况下
        //判断是否要建立EGLContext
        if (askedToReleaseEglContext) {
            askedToReleaseEglContext = false;
        } else if (sGLThreadManager.tryAcquireEglContextLocked(this)) {
            try {
                mEglHelper.start();
            } catch (RuntimeException t) {
                sGLThreadManager.releaseEglContextLocked(this);
                throw t;
            }
            mHaveEglContext = true;
            createEglContext = true;

            sGLThreadManager.notifyAll();
        }
    }
    if (mHaveEglSurface) {//有EGLSurface      
        mRequestRender = false;
        sGLThreadManager.notifyAll();
        break;
    }
}

判断两个关键因素:EGLContext和EGLSurface是否存在并有效,如果没有EGLContext,就需要获取一个,如果当前有EGLSurface但尺寸发生了变化,那么就需要销毁他并重新申请Surface

可以渲染图形的条件是:1.程序当前不处于pause状态2.已经成功获得Surface3.有合适的尺寸4.处于自动持续渲染状态,或者用户发起了渲染请求

3.7 执行渲染工作的处理流程

3.8 EGLHelper

readyToDraw中调用了start方法,然后跳出readyToDraw后调用了createSurface方法

第一步:

public void start() {
    mEgl = (EGL10) EGLContext.getEGL();//获取一个EGL实例
        //获取一个EGLDisplay
    mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

       //初始化EGL并返回版本号
    if(!mEgl.eglInitialize(mEglDisplay, version)) {
 
    }
    GLSurfaceView view = mGLSurfaceViewWeakRef.get();
        //选取一个配置
    mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
        //创建EGLContext
    mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
    mEglSurface = null;
}

第二步:mEglHelper.createSurface()


public boolean createSurface() {
    if (LOG_EGL) {
        Log.w("EglHelper", "createSurface()  tid=" + Thread.currentThread().getId());
    }
    /*
     * Check preconditions.
     */
    if (mEgl == null) {
        throw new RuntimeException("egl not initialized");
    }
    if (mEglDisplay == null) {
        throw new RuntimeException("eglDisplay not initialized");
    }
    if (mEglConfig == null) {
        throw new RuntimeException("mEglConfig not initialized");
    } 
    GLSurfaceView view = mGLSurfaceViewWeakRef.get();
    
    mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
                mEglDisplay, mEglConfig, view.getHolder()); 

    return true;
}



private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {

    public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
            EGLConfig config, Object nativeWindow) {
        EGLSurface result = null;
        result = egl.eglCreateWindowSurface(display, config, nativeWindow, null); 
        return result;
}

}

第三步:

public int swap() {
            if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
                return mEgl.eglGetError();
            }
            return EGL10.EGL_SUCCESS;
        }

4.总结

GLSurfaceView使用EGL的流程

1.生成一个EGL实例
mEgl = (EGL10) EGLContext.getEGL();
2.获取一个EGL Display   
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

 3.初始化EGL并返回版本号
if(!mEgl.eglInitialize(mEglDisplay, version)) {
 
    }

 4.选取一个配置
mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
5.创建一个EGLContext
mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
6.创建EGLSurface
egl.eglCreateWindowSurface(display, config, nativeWindow, null);
7.通过swap将渲染内容显示到屏幕
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)
        

wms2
http://blog.csdn.net/xuesen_lin/article/details/8954748

上一篇下一篇

猜你喜欢

热点阅读