• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            大龍的博客

            常用鏈接

            統計

            最新評論

            android 顯示系統詳解(http://blog.sina.com.cn/s/blog_6b653d110100xhgw.html)

            通過上一篇博客我們了解了,window和Viewroot的創建過程和作用,此時我們是否考慮過我們的布局文件中的view類是如何顯示的,我們 現在可知的是布局文件中的view類已經存放在Viewroot里面了,隨后的工作系統應該完成所有view類繪制,如何繪制和顯示是我們本篇博客討論的 重點

             

            了解顯示系統需要從三方面入手:

            (1)圖像引擎skia

            (2)OpenGL ES

            (3)surface

            Android使用圖像引擎skia 作為其核心圖形引擎。Skia 圖形渲染引擎最初由 Skia 公司開

            發,該公司于2005 年被 Google 收購。skia是作為一個第三方組件放在external目錄下面

             android <wbr />顯示系統詳解

             

                 其實主要涉及到的3個庫:
                 libcorecg.so  包含/skia/src/core的部分內容,比如其中的Region,Rect是在SurfaceFlinger里面計算可是區域的操作基本單位;
                 libsgl.so        包含/skia/src/core|effects|images|ports|utils的部分和全部內容,這個實現了skia大部分的圖形效果,以及圖形格式的編輯

            libskiagl.so   包含/skia/src/gl里面的內容,主要用來調用opengl實現部分效果。

            。skia結構如圖:

                 
            android <wbr />顯示系統詳解

             

                                       (圖片來自于網絡)

             

            Skia作為android圖像引擎在處理部分,只要是C++代碼實現,作為第三方組件提供給android使用,作為組件提供的框架代碼最好提供一個很好的設計方式給編程者調用,從編程角度來考慮Skia

            (1)輸入輸出明確

            (2)接口封裝功能完善

             

            Skia組件可以想象成圖像加工工廠,把原料加入進去,出來的是想要的產品,想要什么樣的產品可以通過接口調用來完成

            如圖:

             android <wbr />顯示系統詳解

              

             

            從圖可知我們給Skia傳遞一個bitmap或者device,我們傳遞的是bitmap或者device的地址,就像我們C語言的指針傳遞一樣,給定了bitmap或者device最后通過接口的加工完成圖像的繪制工作

             

            Skia的功能只是完成圖像的繪制加工,至于完成后的bitmap如何放在LCD上顯示,是surface的工作。

             

            Android 3D 引擎采用的是OpenGL ESOpenGL ES是一套為手持和嵌入式系統設計的3D引擎API,由Khronos公司維護,EGL 是 OpenGL ES 和底層 Native 平臺視窗系統之間的接口EGL 主要構成( Display , Context , Configuration )
                
            EGL 相當作用是將OpenGL ES封裝,外部使用OpenGL ES,只要初始化EGL,通過EGL來使用OpenGL ES

            Android中初始化EGL代碼:

             

            ViewRoot.java (frameworks\base\core\java\android\view)   

            private void initializeGLInner() {

                    final EGL10 egl = (EGL10) EGLContext.getEGL();

                    mEgl = egl;

             

                    

                   // 獲取Display,這里的Display對應的是顯示的硬件

                    

                    final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

                    mEglDisplay = eglDisplay;

             

                   

                     //  初始化egl,完成一些初始化工作

                    

                    int[] version = new int[2];

                    egl.eglInitialize(eglDisplay, version);

             

                   

                  // 選擇Config,其實就是設置一些FrameBuffer相關參數

                    

                    final int[] configSpec = {

                            EGL10.EGL_RED_SIZE,      5,

                            EGL10.EGL_GREEN_SIZE,    6,

                            EGL10.EGL_BLUE_SIZE,     5,

                            EGL10.EGL_DEPTH_SIZE,    0,

                            EGL10.EGL_NONE

                    };

                    final EGLConfig[] configs = new EGLConfig[1];

                    final int[] num_config = new int[1];

                    egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, num_config);

                    final EGLConfig config = configs[0];

             

                   

              // Context就代表這個狀態機,程序的主要工作就是向Context提供狀態,也從Context里獲取一些信息。一般狀態機的操作是通過命令的方式,類似的例子如opencore

                    

                    final EGLContext context = egl.eglCreateContext(eglDisplay, config,

                            EGL10.EGL_NO_CONTEXT, null);

                    mEglContext = context;

             

                    

                       // 獲取EGLSurface,這里的EGLSurface顯示的硬件對應的FrameBuffer

                    

                    final EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, mHolder, null);

                    mEglSurface = surface;

             

                   

                          // 將狀態機和EGLSurface綁定

                     

                    egl.eglMakeCurrent(eglDisplay, surface, surface, context);

             

                   

                       // 獲取GL11,也就是3D引擎接口,通過接口操作3D

                    

                    final GL11 gl = (GL11) context.getGL();

                    mGL = gl;

                    mGlCanvas = new Canvas(gl);

                    mUseGL = true;

                }

            在應用層由三種顯示相關的view:

            (1)        普通的view類

            (2)        SurfaceView

            (3)        GLSurfaceView 

             

            通過上一篇博客了解到,這三種view類的都會通過setContentView加入到ViewRoot,由ViewRoot統一管理顯示,ViewRoot如何區分顯示的看如下代碼:

             

            ViewRoot.java (frameworks\base\core\java\android\view) 

            private void draw(boolean fullRedrawNeeded) {

                  。。。。。。

             

                   

                   // 如果是  GLSurfaceView使用3D繪圖接口繪制 

                  

             

                    if (mUseGL) {

                        if (!dirty.isEmpty()) {

                            Canvas canvas = mGlCanvas;

                            if (mGL != null && canvas != null) {

                                mGL.glDisable(GL_SCISSOR_TEST);

                                mGL.glClearColor(0, 0, 0, 0);

                                mGL.glClear(GL_COLOR_BUFFER_BIT);

                                mGL.glEnable(GL_SCISSOR_TEST);

             

                                mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();

                                mAttachInfo.mIgnoreDirtyState = true;

                                mView.mPrivateFlags |= View.DRAWN;

             

                                int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);

                                try {

                                    canvas.translate(0, -yoff);

                                    if (mTranslator != null) {

                                        mTranslator.translateCanvas(canvas);

                                    }

                                    canvas.setScreenDensity(scalingRequired

                                            ? DisplayMetrics.DENSITY_DEVICE : 0);

                                    mView.draw(canvas);

                                    if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {

                                        mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);

                                    }

                                } finally {

                                    canvas.restoreToCount(saveCount);

                                }

             

                                mAttachInfo.mIgnoreDirtyState = false;

             

                         

                                    // eglSwapBuffers,將數據送給FrameBuffer顯示

                        

             

             

                                mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);

                                checkEglErrors();

            。。。。。。

             

                 

             // 如果是  普通的view類或者SurfaceView都是有2D接口顯示

             

                  

             

             

                                Canvas canvas;

                    try {

                        int left = dirty.left;

                        int top = dirty.top;

                        int right = dirty.right;

                        int bottom = dirty.bottom;

                   

                  // 通過surface獲取canvas

             

                   

             

                        canvas = surface.lockCanvas(dirty);

             

                     。。。。。。

             

                 // 從應用層傳入的view都放在ViewGroup里面,mView為視圖組,當調用mView是會調用dispatchDraw函數遍歷的調用視圖組中每個view的draw()

             

                  

             

                                mView.draw(canvas);

                            } finally {

                                mAttachInfo.mIgnoreDirtyState = false;

                                canvas.restoreToCount(saveCount);

                            }

             

                            if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {

                                mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);

                            }

             

                            if (Config.DEBUG && ViewDebug.showFps) {

                                int now = (int)SystemClock.elapsedRealtime();

                                if (sDrawTime != 0) {

                                    nativeShowFPS(canvas, now - sDrawTime);

                                }

                                sDrawTime = now;

                            }

             

                            if (Config.DEBUG && ViewDebug.profileDrawing) {

                                EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);

                            }

                        }

             

                  // 用完以后釋放CanvasCanvas供多個surface使用

             

                  

             

                    } finally {

                        surface.unlockCanvasAndPost(canvas);

                    }

             

               。。。。。。

            }

            2D引擎,3D引擎和surface關系如圖:

             

            android <wbr />顯示系統詳解

            剩下的任務主要是分析surface:

             

            原理 分析

            讓我們首先看一android屏幕示意圖:

             android <wbr />顯示系統詳解

             

             

            每一個應用程序對應一個或者多個activity,每個activity對應一個或者多個圖形界面,每個圖形界面我們稱為surface

            在上面的圖中我們能看到3個surface ,一個是home 界面,還有就是紅、藍、,而兩個控件實際是home surface 里面的內容,3個surface相互重疊在一起,系統是如何解決圖層的重合,是surface系統的關鍵

             

            (1)surface在android中解釋為一個顯示模塊的封裝,一個顯示模塊在android中需要一個合理的類來描述其信息,這里面和顯示相關的信 息有如下內容:在屏幕上有它要顯示的內容,大小,位置這些元素,surface類就是封裝了一個顯示模塊的這些信息,其中需要一個結構來記錄應用程序界面 的位置,大小,以及一個buffer 來記錄需要顯示的內容,所以這就是我們surface 的概念,

            (2)多個surface顯示會出現重疊的作用,這里需要一個管理者來管理這些surface的重疊顯示,通過上面的博客的閱讀,我們大致可以想到 android會使用一種服務的方式去管理這些surface的顯示,并且各個surface和管理者通過binder通信的方式進行通信,在 android中起到管理者作用的是SurfaceFlinger,它把各個surface 組合(compose/merge) 成一個main Surface ,最后將Main Surface 的內容發送給FB/V4l2 Output ,這樣屏幕上就能看到我們想要的效果。

            在實際中對這些Surface 進行merge 可以采用兩種方式,一種就是采用軟件的形式來merge ,還一種就是采用硬件的方式,軟件的方式就是我們的SurfaceFlinger ,而硬件的方式就是Overlay 。(Overlay的具體實現的內容將在下一篇的博客中詳細講解)

             

            Surface類創建過程分析:

            Surface.java (frameworks\base\core\java\android\view)  

            這個文件為Surface類的實現代碼,也是我們在java層可以直接使用的代碼

            構造函數代碼如下:

            public Surface(SurfaceSession s,

                        int pid, int display, int w, int h, int format, int flags)

                    throws OutOfResourcesException {

                    mCanvas = new CompatibleCanvas();

                    init(s,pid,display,w,h,format,flags);

                }

              init(s,pid,display,w,h,format,flags);//為JNI層代碼在android_view_Surface.cpp中實現

             

            android_view_Surface.cpp (frameworks\base\core\jni)

             

            Surface java層函數和JNI層函數調用的映射表如下:

            static JNINativeMethod gSurfaceMethods[] = {

                {"nativeClassInit",     "()V",  (void*)nativeClassInit },

                {"init",                "(Landroid/view/SurfaceSession;IIIIII)V",  (void*)Surface_init },

            {"init",                "(Landroid/os/Parcel;)V",  (void*)Surface_initParcel },

            。。。。。。

            };

            static void Surface_init(

                    JNIEnv* env, jobject clazz,

                    jobject session, jint pid, jint dpy, jint w, jint h, jint format, jint flags)

            {

                if (session == NULL) {

                    doThrow(env, "java/lang/NullPointerException");

                    return;

                }

            //獲取java層SurfaceSession變量  mClient域   

                SurfaceComposerClient* client =

                        (SurfaceComposerClient*)env->GetIntField(session, sso.client);

            //創建一個surface

                sp<SurfaceControl> surface(client->createSurface(pid, dpy, w, h, format, flags));

                if (surface == 0) {

                    doThrow(env, OutOfResourcesException);

                    return;

                }

                setSurfaceControl(env, clazz, surface);

            }end

            *******

            SurfaceComposerClient* client =

                        (SurfaceComposerClient*)env->GetIntField(session, sso.client);

            這段代碼如何取得SurfaceComposerClient實例的引用,這里解釋一下首先在java層當我們調用surface的構造函數時候

              public Surface(SurfaceSession s,

                        int pid, int display, int w, int h, int format, int flags)

            ,需要傳遞一個SurfaceSession類的引用SurfaceSession類調用如下:

            SurfaceSession.java (frameworks\base\core\java\android\view)

            public class SurfaceSession {

               

                public SurfaceSession() {

                    init();

                }

                protected void finalize() throws Throwable {

                    destroy();

                }

                private native void init();

                private native void destroy()

                private int mClient;

            }

            //函數映射表

            static JNINativeMethod gSurfaceSessionMethods[] = {

                 {"init",     "()V",  (void*)SurfaceSession_init },

                 {"destroy",  "()V",  (void*)SurfaceSession_destroy },

                {"kill",     "()V",  (void*)SurfaceSession_kill },

            };

            static void SurfaceSession_init(JNIEnv* env, jobject clazz)

            {

                sp<SurfaceComposerClient> client = new SurfaceComposerClient;

                client->incStrong(clazz);

                env->SetIntField(clazz, sso.client, (int)client.get());//將SurfaceComposerClient的C++層引用賦值給java層

            }

             android <wbr />顯示系統詳解

            說明:當創建一個surface時,同時創建一個SurfaceComposerClient,SurfaceComposerClient可以看做封裝 surface類,對于一個surface來說需要和服務器SurfaceFlinger通信,通信在android中需要使用proxy/stub機 制,SurfaceComposerClient類本身沒有這種機制,但是在它的內部有封裝了一些可以和服務器通信的類。

            class SurfaceComposerClient : virtual public RefBase

            {

            。。。。。。

                sp<SurfaceControl> createSurface(

                        int pid,            // pid of the process the surface is for

                        DisplayID display,  // Display to create this surface on

                        uint32_t w,         // width in pixel

                        uint32_t h,         // height in pixel

                        PixelFormat format, // pixel-format desired

             。。。。。

                            // after assignment

                            status_t                    mStatus;

                            SharedClient*               mControl;

                            sp<IMemoryHeap>             mControlMemory;

                            sp<ISurfaceFlingerClient>   mClient; //客戶端class BClient : public BnSurfaceFlingerClient的 proxy

                            sp<ISurfaceComposer>        mSignalServer; //客戶端class SurfaceFlinger : public BnSurfaceComposer 的proxy

             

            };

             

            }; // namespace android

             

             

             android <wbr />顯示系統詳解

            當上圖關心建立完成后如下的函數會被調用:

            sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,

                    ISurfaceFlingerClient::surface_data_t* params,

                    DisplayID d, uint32_t w, uint32_t h, PixelFormat format,

                    uint32_t flags)

            {

              。。。。。。

             

                switch (flags & eFXSurfaceMask) {

                    case eFXSurfaceNormal:

                        if (UNLIKELY(flags & ePushBuffers)) {

                            layer = createPushBuffersSurfaceLocked(client, d, id,

                                    w, h, flags);

                        } else {

                            layer = createNormalSurfaceLocked(client, d, id,

                                    w, h, flags, format);

                        }

                        break;

                    case eFXSurfaceBlur:

                        layer = createBlurSurfaceLocked(client, d, id, w, h, flags);

                        break;

                    case eFXSurfaceDim:

                        layer = createDimSurfaceLocked(client, d, id, w, h, flags);

                        break;

                }

             

               。。。。。。

                }

             

                return surfaceHandle;

            }

            Android 提供了 4 種類型的 layer 供選擇,每個 layer 對應一種類型的窗口,并對應這種窗口相應的操作: Layer , LayerBlur , LayerBuffer , LayerDim 。

            Norm Layer 是 Android 種使用最多的一種 Layer ,一般的應用程序在創建 surface 的時候都是采用的這樣的 layer ,

             Normal Layer 為每個 Surface 分配兩個 buffer : front buffer 和 back buffer ,這個前后是相對的概念,他們是可以進行替換的。 Front buffer 用于 SurfaceFlinger 進行顯示,而 Back buffer 用于應用程序進行畫圖,當 Back buffer 填滿數據 (dirty) 以后,就會 替換, back buffer 就變成了 front buffer 用于顯示,而 front buffer 就變成了 back buffer 用來畫圖,(這段話引用其他博客文章

             

            sp<LayerBaseClient> SurfaceFlinger::createNormalSurfaceLocked(

                    const sp<Client>& client, DisplayID display,

                    int32_t id, uint32_t w, uint32_t h, uint32_t flags,

                    PixelFormat& format)

            {

                // initialize the surfaces

                switch (format) { // TODO: take h/w into account

                case PIXEL_FORMAT_TRANSPARENT:

                case PIXEL_FORMAT_TRANSLUCENT:

                    format = PIXEL_FORMAT_RGBA_8888;

                    break;

                case PIXEL_FORMAT_OPAQUE:

                    format = PIXEL_FORMAT_RGB_565;

                    break;

                }

             

                sp<Layer> layer = new Layer(this, display, client, id); //創建Layer

                status_t err = layer->setBuffers(w, h, format, flags);

                if (LIKELY(err == NO_ERROR)) {

                    layer->initStates(w, h, flags);

                    addLayer_l(layer);

                } else {

                    LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));

                    layer.clear();

                }

                return layer;

            }

            Layer類描述如下:

             

             

             

             





            android <wbr />顯示系統詳解

            待續。。。。。。

             

            posted on 2013-01-14 22:37 大龍 閱讀(3080) 評論(0)  編輯 收藏 引用

            久久夜色精品国产噜噜亚洲a | 国产精品99久久免费观看| 2021国产精品午夜久久| 久久国产精品无码HDAV| 97久久精品人人做人人爽| 久久伊人亚洲AV无码网站| 色婷婷久久综合中文久久蜜桃av| 91精品国产综合久久久久久| 美女久久久久久| 久久er99热精品一区二区| 久久青青草原精品国产软件 | 精品久久久久久久无码| 久久久无码精品午夜| 久久夜色精品国产噜噜亚洲AV| 91超碰碰碰碰久久久久久综合| 77777亚洲午夜久久多人| 久久99国产精品成人欧美| 人妻少妇久久中文字幕一区二区| 久久人人爽人人爽AV片| 国产精品99久久精品| 7777久久久国产精品消防器材| 久久av免费天堂小草播放| 精品国际久久久久999波多野| 思思久久好好热精品国产| 久久久久久一区国产精品| 国产精品视频久久久| 亚洲AV成人无码久久精品老人 | 久久久久人妻一区精品性色av| 要久久爱在线免费观看| 国产精品成人久久久久久久| 久久综合久久综合久久综合| 久久精品国产亚洲精品2020| 亚洲色大成网站WWW久久九九| 久久经典免费视频| 久久综合视频网| 亚洲欧美伊人久久综合一区二区 | 久久人人爽人人爽人人片AV不| 久久精品国产99国产精品| 99久久成人18免费网站| 精品久久人人妻人人做精品 | 91秦先生久久久久久久|