• <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>

            大龍的博客

            常用鏈接

            統(tǒng)計

            最新評論

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

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

             

            了解顯示系統(tǒng)需要從三方面入手:

            (1)圖像引擎skia

            (2)OpenGL ES

            (3)surface

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

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

             android <wbr />顯示系統(tǒng)詳解

             

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

            libskiagl.so   包含/skia/src/gl里面的內(nèi)容,主要用來調(diào)用opengl實現(xiàn)部分效果。

            。skia結(jié)構(gòu)如圖:

                 
            android <wbr />顯示系統(tǒng)詳解

             

                                       (圖片來自于網(wǎng)絡(luò))

             

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

            (1)輸入輸出明確

            (2)接口封裝功能完善

             

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

            如圖:

             android <wbr />顯示系統(tǒng)詳解

              

             

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

             

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

             

            Android 3D 引擎采用的是OpenGL ESOpenGL ES是一套為手持和嵌入式系統(tǒng)設(shè)計的3D引擎API,由Khronos公司維護,EGL 是 OpenGL ES 和底層 Native 平臺視窗系統(tǒng)之間的接口EGL 主要構(gòu)成( 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對應(yīng)的是顯示的硬件

                    

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

                    mEglDisplay = eglDisplay;

             

                   

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

                    

                    int[] version = new int[2];

                    egl.eglInitialize(eglDisplay, version);

             

                   

                  // 選擇Config,其實就是設(shè)置一些FrameBuffer相關(guān)參數(shù)

                    

                    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就代表這個狀態(tài)機,程序的主要工作就是向Context提供狀態(tài),也從Context里獲取一些信息。一般狀態(tài)機的操作是通過命令的方式,類似的例子如opencore

                    

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

                            EGL10.EGL_NO_CONTEXT, null);

                    mEglContext = context;

             

                    

                       // 獲取EGLSurface,這里的EGLSurface顯示的硬件對應(yīng)的FrameBuffer

                    

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

                    mEglSurface = surface;

             

                   

                          // 將狀態(tài)機和EGLSurface綁定

                     

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

             

                   

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

                    

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

                    mGL = gl;

                    mGlCanvas = new Canvas(gl);

                    mUseGL = true;

                }

            在應(yīng)用層由三種顯示相關(guān)的view:

            (1)        普通的view類

            (2)        SurfaceView

            (3)        GLSurfaceView 

             

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

             

            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,將數(shù)據(jù)送給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);

             

                     。。。。。。

             

                 // 從應(yīng)用層傳入的view都放在ViewGroup里面,mView為視圖組,當調(diào)用mView是會調(diào)用dispatchDraw函數(shù)遍歷的調(diào)用視圖組中每個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關(guān)系如圖:

             

            android <wbr />顯示系統(tǒng)詳解

            剩下的任務(wù)主要是分析surface:

             

            原理 分析

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

             android <wbr />顯示系統(tǒng)詳解

             

             

            每一個應(yīng)用程序?qū)?yīng)一個或者多個activity,每個activity對應(yīng)一個或者多個圖形界面,每個圖形界面我們稱為surface

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

             

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

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

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

             

            Surface類創(chuàng)建過程分析:

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

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

            構(gòu)造函數(shù)代碼如下:

            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中實現(xiàn)

             

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

             

            Surface java層函數(shù)和JNI層函數(shù)調(diào)用的映射表如下:

            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);

            //創(chuàng)建一個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層當我們調(diào)用surface的構(gòu)造函數(shù)時候

              public Surface(SurfaceSession s,

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

            ,需要傳遞一個SurfaceSession類的引用SurfaceSession類調(diào)用如下:

            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;

            }

            //函數(shù)映射表

            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 />顯示系統(tǒng)詳解

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

            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 />顯示系統(tǒng)詳解

            當上圖關(guān)心建立完成后如下的函數(shù)會被調(diào)用:

            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 對應(yīng)一種類型的窗口,并對應(yīng)這種窗口相應(yīng)的操作: Layer , LayerBlur , LayerBuffer , LayerDim 。

            Norm Layer 是 Android 種使用最多的一種 Layer ,一般的應(yīng)用程序在創(chuàng)建 surface 的時候都是采用的這樣的 layer ,

             Normal Layer 為每個 Surface 分配兩個 buffer : front buffer 和 back buffer ,這個前后是相對的概念,他們是可以進行替換的。 Front buffer 用于 SurfaceFlinger 進行顯示,而 Back buffer 用于應(yīng)用程序進行畫圖,當 Back buffer 填滿數(shù)據(jù) (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); //創(chuàng)建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 />顯示系統(tǒng)詳解

            待續(xù)。。。。。。

             

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

            久久久免费精品re6| 久久亚洲国产成人影院网站 | 少妇被又大又粗又爽毛片久久黑人 | 精品永久久福利一区二区| 99久久综合国产精品免费| 久久影视综合亚洲| 欧洲国产伦久久久久久久| 合区精品久久久中文字幕一区 | 久久亚洲春色中文字幕久久久 | 无码AV中文字幕久久专区| 无遮挡粉嫩小泬久久久久久久| 精品国产乱码久久久久软件| 久久国产劲爆AV内射—百度| 亚洲精品乱码久久久久久久久久久久 | 色综合久久88色综合天天| 精品九九久久国内精品| 国产精品99久久久久久宅男| 久久噜噜久久久精品66| 2021国产精品久久精品| 亚洲αv久久久噜噜噜噜噜| 99久久无码一区人妻a黑| 国产精品va久久久久久久| 欧洲国产伦久久久久久久 | 亚洲成色WWW久久网站| 日本福利片国产午夜久久| 久久久久亚洲AV成人网| 久久无码中文字幕东京热| 久久精品九九亚洲精品| 精品国产婷婷久久久| 伊人久久五月天| 久久国产免费观看精品3| 久久国产精品二国产精品| 久久久一本精品99久久精品88| 婷婷综合久久狠狠色99h| 四虎影视久久久免费观看| 久久精品中文騷妇女内射| 久久国产成人精品国产成人亚洲| 亚洲αv久久久噜噜噜噜噜| 久久精品国产WWW456C0M| 久久精品国产亚洲AV嫖农村妇女 | 久久se这里只有精品|