Android SurfaceFlinger服務(八) ----- 映像的輸出

來源:互聯網
上載者:User

標籤:沒有   format   efault   phi   connected   RoCE   bre   com   comm   

SurfaceFlinger合成後就進行映像的輸出的工作。在映像輸出時,存在硬體合成器與不存在的情況有些差別。軟體合成時用到映像緩衝區生產者與消費者模型。首先來看看映像緩衝區的初始化。

void SurfaceFlinger::init() {    ALOGI(  "SurfaceFlinger‘s main thread ready to run. "            "Initializing graphics H/W...");    ......    // initialize our non-virtual displays    for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {        DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);        // set-up the displays that are already connected        if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {            // All non-virtual displays are currently considered secure.            bool isSecure = true;            createBuiltinDisplayLocked(type);            wp<IBinder> token = mBuiltinDisplays[i];            sp<IGraphicBufferProducer> producer;            sp<IGraphicBufferConsumer> consumer;            BufferQueue::createBufferQueue(&producer, &consumer,                    new GraphicBufferAlloc());            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,                    consumer);            int32_t hwcId = allocateHwcDisplayId(type);            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);            }            mDisplays.add(token, hw);        }    }   ......}
  • 調用BufferQueue::createBufferQueue建立映像緩衝區,並得到其生產者和消費者介面
  • 利用上面得到的consumer消費者介面建立FramebufferSurface
  • 利用上面得到的producer生產者介面建立DisplayDevice
  • DisplayDevice軟體合成的映像在FramebufferSurface中得以消費處理
DisplayDevice::DisplayDevice(        const sp<SurfaceFlinger>& flinger,        DisplayType type,        int32_t hwcId,        int format,        bool isSecure,        const wp<IBinder>& displayToken,        const sp<DisplaySurface>& displaySurface,        const sp<IGraphicBufferProducer>& producer,        EGLConfig config)    : lastCompositionHadVisibleLayers(false),      mFlinger(flinger),      mType(type), mHwcDisplayId(hwcId),      mDisplayToken(displayToken),      mDisplaySurface(displaySurface),      mDisplay(EGL_NO_DISPLAY),      mSurface(EGL_NO_SURFACE),      mDisplayWidth(), mDisplayHeight(), mFormat(),      mFlags(),      mPageFlipCount(),      mIsSecure(isSecure),      mSecureLayerVisible(false),      mLayerStack(NO_LAYER_STACK),      mOrientation(),      mPowerMode(HWC_POWER_MODE_OFF),      mActiveConfig(0){    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);    // Make sure that composition can never be stalled by a virtual display    // consumer that isn‘t processing buffers fast enough. We have to do this    // in two places:    // * Here, in case the display is composed entirely by HWC.    // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the    //   window‘s swap interval in eglMakeCurrent, so they‘ll override the    //   interval we set here.    if (mType >= DisplayDevice::DISPLAY_VIRTUAL)        window->setSwapInterval(window, 0);    mConfig = config;    mDisplay = display;    mSurface = surface;    mFormat  = format;    mPageFlipCount = 0;    mViewport.makeInvalid();    mFrame.makeInvalid();    // virtual displays are always considered enabled    mPowerMode = (mType >= DisplayDevice::DISPLAY_VIRTUAL) ?                  HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;    // Name the display.  The name will be replaced shortly if the display    // was created with createDisplay().    switch (mType) {        case DISPLAY_PRIMARY:            mDisplayName = "Built-in Screen";            break;        case DISPLAY_EXTERNAL:            mDisplayName = "HDMI Screen";            break;        default:            mDisplayName = "Virtual Screen";    // e.g. Overlay #n            break;    }    // initialize the display orientation transform.    setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);}
  • 使用生產者介面初始化egl圖形庫
  • 軟體繪製圖層時就會調用EGL圖形庫,間接調用生產者介面

在SurfaceFlinger::doDisplayComposition函數中調用doComposeSurfaces函數合成圖層,然後調用hw->swapBuffers。對於沒有HWComper存在時,直接提交顯示。若存在HWComper時,將軟體合成的圖層交由HWComper處理。

void DisplayDevice::swapBuffers(HWComposer& hwc) const {        // We need to call eglSwapBuffers() if:                     //  (1) we don‘t have a hardware composer, or               //  (2) we did GLES composition this frame, and either      //    (a) we have framebuffer target support (not present on legacy    //        devices, where HWComposer::commit() handles things); or    //    (b) this is a virtual display    if (hwc.initCheck() != NO_ERROR ||                                  (hwc.hasGlesComposition(mHwcDisplayId) &&                    (hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) {        EGLBoolean success = eglSwapBuffers(mDisplay, mSurface);             if (!success) {            EGLint error = eglGetError();                               if (error == EGL_CONTEXT_LOST ||                                    mType == DisplayDevice::DISPLAY_PRIMARY) {                               LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x",                                mDisplay, mSurface, error);                     } else {                ALOGE("eglSwapBuffers(%p, %p) failed with 0x%08x",                                           mDisplay, mSurface, error);                     }        }    }      status_t result = mDisplaySurface->advanceFrame();          if (result != NO_ERROR) {        ALOGE("[%s] failed pushing new frame to HWC: %d",                   mDisplayName.string(), result);                 }  }
  • 在不存在HWComposer或存在HWComposer但使用gles合成時調用eglSwapBuffers提交gles合成的緩衝區
  • 其它情況對圖層合層不作處理

eglSwapBuffers提交gles合成的緩衝區後交由圖層消費者去處理,前文中提到消費者是FramebufferSurface。看看其處理函數:

void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {    sp<GraphicBuffer> buf;    sp<Fence> acquireFence;    status_t err = nextBuffer(buf, acquireFence);    if (err != NO_ERROR) {        ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)",                strerror(-err), err);        return;    }    err = mHwc.fbPost(mDisplayType, acquireFence, buf);    if (err != NO_ERROR) {        ALOGE("error posting framebuffer: %d", err);    }}
  • 調用mHwc.fbPost提交buffer到HWComposer函數
int HWComposer::fbPost(int32_t id,        const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {    if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {        return setFramebufferTarget(id, acquireFence, buffer);    } else {        acquireFence->waitForever("HWComposer::fbPost");        return mFbDev->post(mFbDev, buffer->handle);    }}
  • 存在硬體合成器時,調用setFramebufferTarget函數將軟體合成的結果提交給硬體合成器去混合圖層輸出
  • 不存在硬體合成器時,直接調用mFbDev->post將軟體合成的結果提交到framebuffer進去輸出

在SurfaceFlinger中執行完doDisplayComposition進行圖層處理後會調用postFramebuffer提交圖層到HWComposer中。

void SurfaceFlinger::postFramebuffer(){    ATRACE_CALL();    ......    HWComposer& hwc(getHwComposer());    if (hwc.initCheck() == NO_ERROR) {        if (!hwc.supportsFramebufferTarget()) {            // EGL spec says:            //   "surface must be bound to the calling thread‘s current context,            //    for the current rendering API."            getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);                                                                                                                        }        hwc.commit();    }      ......}
  • 存在HWComposer時調用hwc.commit()提交圖層。
status_t HWComposer::commit() {    int err = NO_ERROR;    if (mHwc) {        if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {                   // On version 1.0, the OpenGL ES target surface is communicated            // by the (dpy, sur) fields and we are guaranteed to have only            // a single display.            mLists[0]->dpy = eglGetCurrentDisplay();                    mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW);        }        for (size_t i=VIRTUAL_DISPLAY_ID_BASE; i<mNumDisplays; i++) {                DisplayData& disp(mDisplayData[i]);            if (disp.outbufHandle) {                                        mLists[i]->outbuf = disp.outbufHandle;                      mLists[i]->outbufAcquireFenceFd =                                   disp.outbufAcquireFence->dup();                 }        }        err = mHwc->set(mHwc, mNumDisplays, mLists);        for (size_t i=0 ; i<mNumDisplays ; i++) {            DisplayData& disp(mDisplayData[i]);            disp.lastDisplayFence = disp.lastRetireFence;            disp.lastRetireFence = Fence::NO_FENCE;                     if (disp.list) {                if (disp.list->retireFenceFd != -1) {                           disp.lastRetireFence = new Fence(disp.list->retireFenceFd);                      disp.list->retireFenceFd = -1;                          }                disp.list->flags &= ~HWC_GEOMETRY_CHANGED;              }        }    }      return (status_t)err;}
  • 調用mHwc->set使用硬體對層圖進行合成並輸出到顯示裝置

Android SurfaceFlinger服務(八) ----- 映像的輸出

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.