Display設(shè)備管理

DisplayDevice介紹

DisplayDevice描述了一個(gè)顯示設(shè)備,是Android顯示設(shè)備的抽象類(lèi)。Android系統(tǒng)中定義了三種Device

        DISPLAY_PRIMARY     = HWC_DISPLAY_PRIMARY,
        DISPLAY_EXTERNAL    = HWC_DISPLAY_EXTERNAL,
        DISPLAY_VIRTUAL     = HWC_DISPLAY_VIRTUAL,

1:DISPLAY_PRIMARY Android 手機(jī)主顯示屏
2:DISPLAY_EXTERNAL 一般為外接顯示設(shè)備
3:DISPLAY_VIRTUAL 虛擬顯示設(shè)備,用于WiFi投屏

第一種類(lèi)型是基本的設(shè)備,基本所有設(shè)備都有自帶顯示屏, 其他兩種則需要其他硬件來(lái)支持

SurfaceFlinger中需要顯示的圖層(layer)將通過(guò)DisplayDevice對(duì)象傳遞到OpenGLES中進(jìn)行合成,因?yàn)槿绻瑫r(shí)有多個(gè)顯示屏的情況下,不同的Layer可能會(huì)顯示在不同的屏幕上。合成之后的圖像再通過(guò)HWComposer對(duì)象傳遞到Framebuffer中顯示。DisplayDevice對(duì)象中的成員變量mVisibleLayersSortedByZ保存了所有需要顯示在本顯示設(shè)備中顯示的Layer對(duì)象,同時(shí)DisplayDevice對(duì)象也保存了和顯示設(shè)備相關(guān)的顯示方向、顯示區(qū)域坐標(biāo)等信息。
SurfaceFlinger的init函數(shù)中會(huì)初始化Display設(shè)備,代碼如下:

  //先檢查硬件設(shè)備是否連接,或者是否是主顯示屏
  if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
            // All non-virtual displays are currently considered secure.
            bool isSecure = true;
            //給顯示設(shè)備分配一個(gè)Token,并且創(chuàng)建一個(gè)DisplayDeviceState對(duì)象,保存在SurfaceFlinger的mCurrentState.display列表中
            createBuiltinDisplayLocked(type);
            wp<IBinder> token = mBuiltinDisplays[i];
            
            //為當(dāng)前設(shè)備創(chuàng)建一個(gè)Buffer隊(duì)列,初始化一個(gè)生產(chǎn)者和一個(gè)消費(fèi)者,消費(fèi)者有FrameBufferSurface封裝,生產(chǎn)者交由DisplayDevice持有
            sp<IGraphicBufferProducer> producer;
            sp<IGraphicBufferConsumer> consumer;
            BufferQueue::createBufferQueue(&producer, &consumer,
                    new GraphicBufferAlloc());
            //
            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
                    consumer);
            //為甚分配一個(gè)ID
            int32_t hwcId = allocateHwcDisplayId(type);
            //根據(jù)相關(guān)信息,創(chuàng)建DisplayDevice對(duì)象
            sp<DisplayDevice> hw = new DisplayDevice(this,
                    type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
                    fbs, producer,
                    mRenderEngine->getEGLConfig());
            if (i > DisplayDevice::DISPLAY_PRIMARY) {
                // FIXME: currently we don't get blank/unblank requests
                // for displays other than the main display, so we always
                // assume a connected display is unblanked.
                ALOGD("marking display %zu as acquired/unblanked", i);
                hw->setPowerMode(HWC_POWER_MODE_NORMAL);
            }
            //將DiplayDevice保存到SurfaceFlinger的mDisplays中。
            mDisplays.add(token, hw);
        }
    }

     getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);

1:調(diào)用了HWComposer的isConnected來(lái)檢查顯示設(shè)備是否已連接,只有連接的硬件設(shè)備才會(huì)創(chuàng)建對(duì)應(yīng)的DisplayDevice。主設(shè)備除外,無(wú)論是否連接都會(huì)創(chuàng)建一個(gè)DisplayDevice。
2:為當(dāng)前顯示設(shè)備創(chuàng)建一個(gè)BBinder類(lèi)型的Token,并且創(chuàng)建一個(gè)DisplayDeviceState對(duì)象,保存在SurfaceFlinger的mCurrentState.display列表中
3:為當(dāng)前顯示設(shè)備創(chuàng)建一個(gè)Buffer隊(duì)列,初始化一個(gè)生產(chǎn)者和一個(gè)消費(fèi)者,消費(fèi)者有FrameBufferSurface封裝,生產(chǎn)者交由DisplayDevice持有
4:創(chuàng)建DisplayDevice對(duì)象,傳入Buffer隊(duì)列的producer,DisplayDevice的構(gòu)造函數(shù)中,會(huì)創(chuàng)建一個(gè)Surface對(duì)象傳遞給底層的OpenGL ES使用,而這個(gè)Surface是一個(gè)生產(chǎn)者。在OpenGl ES中合成好了圖像之后會(huì)將圖像數(shù)據(jù)寫(xiě)到Surface對(duì)象中,這將觸發(fā)consumer對(duì)象的onFrameAvailable函數(shù)被調(diào)用,然后FramebufferSurface調(diào)用HWComposer對(duì)象mHwc的fbPost函數(shù)輸出到FB中。
5:將DiplayDevice保存到SurfaceFlinger的mDisplays中。
6:調(diào)用主顯示屏的makeCurrent,綁定DisplayDevice的上下文

DisplayDevice構(gòu)造方法如下:

    mNativeWindow = new Surface(producer, false);
    ANativeWindow* const window = mNativeWindow.get();

    /*
     * Create our display's surface
     */

    EGLSurface surface;
    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (config == EGL_NO_CONFIG) {
        config = RenderEngine::chooseEglConfig(display, format);
    }
    surface = eglCreateWindowSurface(display, config, window, NULL);
    eglQuerySurface(display, surface, EGL_WIDTH,  &mDisplayWidth);
    eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight);

    if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
        window->setSwapInterval(window, 0);

    mConfig = config;
    mDisplay = display;
    mSurface = surface;
    mFormat  = format;
    mPageFlipCount = 0;
    mViewport.makeInvalid();
    mFrame.makeInvalid();

    setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);

創(chuàng)建OpenGL的EGL環(huán)境,我們?cè)谇懊嬉呀?jīng)解釋過(guò),初始化過(guò)后,openGL就可以想Surface中繪制了,繪制完成調(diào)用eglswapBuffer來(lái)將繪制完成的Buffer發(fā)送到Buffer隊(duì)列,這樣FrameBufferSurface就可收到onFrameAvaliable通知了。

接著看下DisplayDevice的swapBuffer函數(shù)

void DisplayDevice::swapBuffers(HWComposer& hwc) const {
    // 調(diào)用eglSwapBuffers()函數(shù)的條件:
    //  (1) 沒(méi)有HWComposer硬件
    //  (2) 這一幀我們需要使用GLES來(lái)合成(包括兩種情況)
    //    (a) we have framebuffer target support (not present on legacy
    //        devices, where HWComposer::commit() handles things); or
    //    (b) 虛擬顯示設(shè)備
    if (hwc.initCheck() != NO_ERROR ||
            (hwc.hasGlesComposition(mHwcDisplayId) &&
             (hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) {
        //調(diào)用eglSwapBuffers更新隊(duì)列
        EGLBoolean success = eglSwapBuffers(mDisplay, mSurface);
        ......
    }
}

swapBuffers用于將Display合成的圖像渲染到FB設(shè)備的圖像緩沖區(qū),一般只有在不支持HWComposer情況下才會(huì)調(diào)用。
當(dāng)DisplayDevice調(diào)用swapBuffer函數(shù)后,消費(fèi)者收到onFrameAvailable通知。再來(lái)看下FrameBufferSurface的onFrameAvailale函數(shù)。

// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl.
void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {
    sp<GraphicBuffer> buf;
    sp<Fence> acquireFence;
    //調(diào)用NextBuffer從Buffer隊(duì)列中獲取新的Buffer
    status_t err = nextBuffer(buf, acquireFence);
    if (err != NO_ERROR) {
        ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)",
                strerror(-err), err);
        return;
    }
    //調(diào)用gralloc模塊的FB設(shè)備的函數(shù)fbPost將graphicBuffer圖像緩沖區(qū)渲染到FB顯示緩沖區(qū)中.
    err = mHwc.fbPost(mDisplayType, acquireFence, buf);
    if (err != NO_ERROR) {
        ALOGE("error posting framebuffer: %d", err);
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容