編輯:關於Android編程
上篇博客分析到setUpHWComposer函數,這裡我們繼續分析圖像合成的過程從doComposition函數開始,以及在這過程中解答一些上篇博客提出的疑問。
doComposition這個函數就是合成所有層的圖像
void SurfaceFlinger::doComposition() { ATRACE_CALL(); const bool repaintEverything = android_atomic_and(0, &mRepaintEverything); for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); if (hw->isDisplayOn()) { // transform the dirty region into this screen's coordinate space const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); // repaint the framebuffer (if needed) doDisplayComposition(hw, dirtyRegion); hw->dirtyRegion.clear(); hw->flip(hw->swapRegion); hw->swapRegion.clear(); } // inform the h/w that we're done compositing hw->compositionComplete(); } postFramebuffer(); }
上面函數遍歷所有的DisplayDevice然後調用doDisplayComposition函數。然後我們再看看doDisplayComposition函數
void SurfaceFlinger::doDisplayComposition(const sp& hw, const Region& inDirtyRegion) { bool isHwcDisplay = hw->getHwcDisplayId() >= 0; if (!isHwcDisplay && inDirtyRegion.isEmpty()) { return; } Region dirtyRegion(inDirtyRegion); //swapRegion設置為需要更新的區域 hw->swapRegion.orSelf(dirtyRegion); uint32_t flags = hw->getFlags();//獲得顯示設備支持的更新方式標志 if (flags & DisplayDevice::SWAP_RECTANGLE) {//支持矩陣更新 dirtyRegion.set(hw->swapRegion.bounds()); } else { if (flags & DisplayDevice::PARTIAL_UPDATES) {//支持部分更新 dirtyRegion.set(hw->swapRegion.bounds()); } else { //將更新區域調整為整個窗口大小 dirtyRegion.set(hw->bounds()); hw->swapRegion = dirtyRegion; } } if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) { if (!doComposeSurfaces(hw, dirtyRegion)) return;//合成 } else { RenderEngine& engine(getRenderEngine()); mat4 colorMatrix = mColorMatrix; if (mDaltonize) { colorMatrix = colorMatrix * mDaltonizer(); } mat4 oldMatrix = engine.setupColorTransform(colorMatrix); doComposeSurfaces(hw, dirtyRegion);//合成 engine.setupColorTransform(oldMatrix); } // update the swap region and clear the dirty region hw->swapRegion.orSelf(dirtyRegion); // swap buffers (presentation) hw->swapBuffers(getHwComposer());//使用egl將egl中的合成好的圖像,輸出到DisplayDevice的mSurface中 }
這個函數設置下需要更新的區域,後面調用doComposeSurfaces函數來合成圖層,調用完doComposeSurfaces函數後,如果需要egl合成圖像話,在這個函數中合成好。而最後調用swapBuffers只是將egl合成好的圖像輸出到DisplayDevice的mSurface中。
我們再來看看doComposeSurfaces函數,我們先來看一開始的代碼,先判斷是否有egl合成,然後再看是否有hwc合成(硬件合成)
bool SurfaceFlinger::doComposeSurfaces(const sp& hw, const Region& dirty) { RenderEngine& engine(getRenderEngine()); const int32_t id = hw->getHwcDisplayId(); HWComposer& hwc(getHwComposer()); HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); bool hasGlesComposition = hwc.hasGlesComposition(id); if (hasGlesComposition) {//是否有egl合成 if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) { ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s", hw->getDisplayName().string()); eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) { ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting."); } return false; } // Never touch the framebuffer if we don't have any framebuffer layers const bool hasHwcComposition = hwc.hasHwcComposition(id); if (hasHwcComposition) {//是否有hwc合成 // when using overlays, we assume a fully transparent framebuffer // NOTE: we could reduce how much we need to clear, for instance // remove where there are opaque FB layers. however, on some // GPUs doing a "clean slate" clear might be more efficient. // We'll revisit later if needed. engine.clearWithColor(0, 0, 0, 0); } else { // we start with the whole screen area const Region bounds(hw->getBounds()); // we remove the scissor part // we're left with the letterbox region // (common case is that letterbox ends-up being empty) const Region letterbox(bounds.subtract(hw->getScissor())); // compute the area to clear Region region(hw->undefinedRegion.merge(letterbox)); // but limit it to the dirty region region.andSelf(dirty); // screen is already cleared here if (!region.isEmpty()) { // can happen with SurfaceView drawWormhole(hw, region); } } if (hw->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) { // just to be on the safe side, we don't set the // scissor on the main display. It should never be needed // anyways (though in theory it could since the API allows it). const Rect& bounds(hw->getBounds()); const Rect& scissor(hw->getScissor()); if (scissor != bounds) { // scissor doesn't match the screen's dimensions, so we // need to clear everything outside of it and enable // the GL scissor so we don't draw anything where we shouldn't // enable scissor for this frame const uint32_t height = hw->getHeight(); engine.setScissor(scissor.left, height - scissor.bottom, scissor.getWidth(), scissor.getHeight()); } } } ......
我們來看hasGlesComposition函數和hasHwcComposition函數,就是看其對應的DisplayData中是否有hasFbComp和hasOvComp。
bool HWComposer::hasGlesComposition(int32_t id) const { if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) return true; return mDisplayData[id].hasFbComp; }
bool HWComposer::hasHwcComposition(int32_t id) const { if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) return false; return mDisplayData[id].hasOvComp; }而這兩個值是在prepare中調用Hwc的prepare函數之後賦值的
status_t HWComposer::prepare() { ...... int err = mHwc->prepare(mHwc, mNumDisplays, mLists); ALOGE_IF(err, "HWComposer: prepare failed (%s)", strerror(-err)); if (err == NO_ERROR) { // here we're just making sure that "skip" layers are set // to HWC_FRAMEBUFFER and we're also counting how many layers // we have of each type. // // If there are no window layers, we treat the display has having FB // composition, because SurfaceFlinger will use GLES to draw the // wormhole region. for (size_t i=0 ; inumHwLayers ; i++) { hwc_layer_1_t& l = disp.list->hwLayers[i]; //ALOGD("prepare: %d, type=%d, handle=%p", // i, l.compositionType, l.handle); if (l.flags & HWC_SKIP_LAYER) { l.compositionType = HWC_FRAMEBUFFER; } if (l.compositionType == HWC_FRAMEBUFFER) { disp.hasFbComp = true;//只要有一個layer是HWC_FRAMEBUFFER } if (l.compositionType == HWC_OVERLAY) { disp.hasOvComp = true;//有一個layer是HWC_OVERLAY } if (l.compositionType == HWC_CURSOR_OVERLAY) { disp.hasOvComp = true;//有一個layer是HWC_CURSOR_OVERLAY } } if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) {//layer的數量 有framebufferTarget為1 沒有為0 disp.hasFbComp = true; } } else { disp.hasFbComp = true;//沒有list } } } return (status_t)err; }
我們繼續看doComposeSurfaces函數,下面這個函數當cur!=end代表起碼有兩個以上圖層,然後遍歷圖層,當layer是HWC_FRAMEBUFFER代表是需要egl合成的,而HWC_FRAMEBUFFER_TARGET是egl合成後使用的直接就跳了,HWC_CURSOR_OVERLAY和HWC_OVERLAY是用HWC模塊(硬件合成)的,也就不用調用Layer的draw方法。而如果圖層只要1個或者沒有,那麼直接使用egl合成。
HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); ...... const Vector< sp>& layers(hw->getVisibleLayersSortedByZ()); const size_t count = layers.size(); const Transform& tr = hw->getTransform(); if (cur != end) { //代表起碼有兩個以上圖層 // we're using h/w composer for (size_t i=0 ; i & layer(layers[i]); const Region clip(dirty.intersect(tr.transform(layer->visibleRegion))); if (!clip.isEmpty()) { switch (cur->getCompositionType()) { case HWC_CURSOR_OVERLAY: case HWC_OVERLAY: { const Layer::State& state(layer->getDrawingState()); if ((cur->getHints() & HWC_HINT_CLEAR_FB) && i && layer->isOpaque(state) && (state.alpha == 0xFF) && hasGlesComposition) { // never clear the very first layer since we're // guaranteed the FB is already cleared layer->clearWithOpenGL(hw, clip); } break; } case HWC_FRAMEBUFFER: { layer->draw(hw, clip);//只有是HWC_FRAMEBUFFER才會調用Layer的draw合成 break; } case HWC_FRAMEBUFFER_TARGET: { // this should not happen as the iterator shouldn't // let us get there. ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu)", i); break; } } } layer->setAcquireFence(hw, *cur); } } else { // we're not using h/w composer for (size_t i=0 ; i & layer(layers[i]); const Region clip(dirty.intersect( tr.transform(layer->visibleRegion))); if (!clip.isEmpty()) { layer->draw(hw, clip); } } } // disable scissor at the end of the frame engine.disableScissor(); return true; }
Layer的draw我們就不看了主要是使用egl合成紋理,但是有一點疑問,我們從來沒有把layer中的mActiveBuffer放到egl中去,那麼egl又是怎麼合成各個layer的呢,我想肯定客戶進程在繪制各個layer的時候,也是用egl繪制的,所有後面合成的時候egl有各個layer的buffer。
後面我們再來看下DisplayDevice::swapBuffers函數,是使用eglSwapBuffers來把egl合成的數據放到mSurface中去。
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); } } } else if(hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL) { EGLBoolean success = eglSwapBuffersVIV(mDisplay, mSurface); if (!success) { EGLint error = eglGetError(); ALOGE("eglSwapBuffersVIV(%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); } }
之前分析DisplayDevice時候,還分析了FramebufferSurface,我們這裡再來看下。
在SurfaceFlinger.cpp中的init函數,在創建DisplayDevice之前,我們先調用createBufferQueue來創建了一個buffer的生產者和消費者,然後把消費者放入了FramebufferSurface,生產者放入了DisplayDevice中。
spproducer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer, new GraphicBufferAlloc()); sp<framebuffersurface> fbs = new FramebufferSurface(*mHwc, i, consumer); int32_t hwcId = allocateHwcDisplayId(type); sp hw = new DisplayDevice(this, type, hwcId, mHwc->getFormat(hwcId), isSecure, token, fbs, producer, mRenderEngine->getEGLConfig()); </framebuffersurface>
我們先來看生產者,下面是DisplayDevice的構造函數,生產者作為參數直接新建了一個Surface,然後把這個Surface作為參數調用eglCreateWindowSurface返回的就是mSurface,之前我們分析最後egl合成的數據時調用eglSwapBuffers並且把數據放到mSurface,這樣最後肯定就到消費者(FramebufferSurface)去了。
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);
最後到消費者那端的onFrameAvailable,也就是FramebufferSurface的onFrameAvailable中,我們現在來分析下這個過程,也就解答了一個onFrameAvailable的疑惑。
FramebufferSurface的父類是ConsumerBase類,我們來看其構造函數。先是構造了mConsumer,這裡其實就是BufferQueueConsumer類,後面調用了其consumerConnect方法。
ConsumerBase::ConsumerBase(const sp& bufferQueue, bool controlledByApp) : mAbandoned(false), mConsumer(bufferQueue) { mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); wp listener = static_cast (this); sp proxy = new BufferQueue::ProxyConsumerListener(listener); status_t err = mConsumer->consumerConnect(proxy, controlledByApp); if (err != NO_ERROR) { CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)", strerror(-err), err); } else { mConsumer->setConsumerName(mName); } }
我們來看下BufferQueueConsumer類的consumerConnect方法,就是調用了connect方法。
virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) { return connect(consumer, controlledByApp); }
這個方法中將mCore->mConsumerListener = consumerListener,這個mCore就是BufferQueueCore類。我們再從ConsumerBase的構造函數看這個consumerListener參數其實就是FrameBufferSurface對象本身。
status_t BufferQueueConsumer::connect( const sp& consumerListener, bool controlledByApp) { ATRACE_CALL(); if (consumerListener == NULL) { BQ_LOGE("connect(C): consumerListener may not be NULL"); return BAD_VALUE; } BQ_LOGV("connect(C): controlledByApp=%s", controlledByApp ? "true" : "false"); Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("connect(C): BufferQueue has been abandoned"); return NO_INIT; } mCore->mConsumerListener = consumerListener;//設置回調 mCore->mConsumerControlledByApp = controlledByApp; return NO_ERROR; }
我們再看BufferQueueProducer::queueBuffer函數,這個函數應該是生產者已經使用好buffer了,這個使用會調用如下代碼這個listener就是BufferQueueCore的mConsumerListener,傳輸的數據時BufferItem。再傳之前把BufferItem的mGraphicBuffer清了,因為消費者可以自己獲取buffer,不用通過BufferItem傳。
item.mGraphicBuffer.clear(); item.mSlot = BufferItem::INVALID_BUFFER_SLOT; // Call back without the main BufferQueue lock held, but with the callback // lock held so we can ensure that callbacks occur in order { Mutex::Autolock lock(mCallbackMutex); while (callbackTicket != mCurrentCallbackTicket) { mCallbackCondition.wait(mCallbackMutex); } if (frameAvailableListener != NULL) { frameAvailableListener->onFrameAvailable(item); } else if (frameReplacedListener != NULL) { frameReplacedListener->onFrameReplaced(item); } ++mCurrentCallbackTicket; mCallbackCondition.broadcast(); }
這樣就要FramebufferSurface的onFrameAvailable函數中去了,我們來看下這個函數。
void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) { sp這個函數先用nextBuffer獲取數據,然後調用了HWComposer的fbPost函數。我們先來看下nextBuffer函數,這個函數主要通過acquireBufferLocked獲取BufferItem,其中的mBuf就是buffer了。buf; sp 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); } }
status_t FramebufferSurface::nextBuffer(sp而這個acquireBufferLocked還是用mConsumer的acquireBuffer來獲取BufferItem。mConsumer就是BufferQueueConsumer類。& outBuffer, sp & outFence) { Mutex::Autolock lock(mMutex); BufferItem item; status_t err = acquireBufferLocked(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { outBuffer = mCurrentBuffer; return NO_ERROR; } else if (err != NO_ERROR) { ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err); return err; } if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && item.mBuf != mCurrentBufferSlot) { // Release the previous buffer. err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err < NO_ERROR) { ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); return err; } } mCurrentBufferSlot = item.mBuf; mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer; outFence = item.mFence; outBuffer = mCurrentBuffer; return NO_ERROR; }
status_t ConsumerBase::acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, uint64_t maxFrameNumber) { status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber); if (err != NO_ERROR) { return err; } if (item->mGraphicBuffer != NULL) { mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; } mSlots[item->mBuf].mFrameNumber = item->mFrameNumber; mSlots[item->mBuf].mFence = item->mFence; CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64, item->mBuf, item->mFrameNumber); return OK; }
繼上面調用fbPost方法,我們來看下,這裡是調用了setFramebufferTarget方法。
int HWComposer::fbPost(int32_t id, const sp& acquireFence, const sp & 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方法,這裡就是把該設備的DisplayData數據中的framebufferTarget填充,主要是其handle數據,這裡就是egl合成好的數據buffer。
也就是最終egl合成好的數據放在DisplayData的framebufferTarget變量的handle中。
status_t HWComposer::setFramebufferTarget(int32_t id, const sp& acquireFence, const sp & buf) { if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { return BAD_INDEX; } DisplayData& disp(mDisplayData[id]); if (!disp.framebufferTarget) { // this should never happen, but apparently eglCreateWindowSurface() // triggers a Surface::queueBuffer() on some // devices (!?) -- log and ignore. ALOGE("HWComposer: framebufferTarget is null"); return NO_ERROR; } int acquireFenceFd = -1; if (acquireFence->isValid()) { acquireFenceFd = acquireFence->dup(); } // ALOGD("fbPost: handle=%p, fence=%d", buf->handle, acquireFenceFd); disp.fbTargetHandle = buf->handle;//egl合成好的數據 disp.framebufferTarget->handle = disp.fbTargetHandle;//egl合成好的數據,最終是放在這裡 disp.framebufferTarget->acquireFenceFd = acquireFenceFd; return NO_ERROR; }
這樣就剩最後一步了,把不管是普通layer的數據,還是egl合成好的數據發送到硬件模塊合成了,最後就到顯示設備了。
繼第一節分析的doComposition函數最後會調用postFramebuffer函數,我們再來分析下這個函數,這個函數主要是調用了HWComposer的commit函數。
void SurfaceFlinger::postFramebuffer() { ATRACE_CALL(); const nsecs_t now = systemTime(); mDebugInSwapBuffers = now; 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的commit函數,這個函數就是先設置了egl的那個設備的surface和display,然後處理虛擬設備的outbuf等,最後調用了硬件模塊合成到顯示設備上。
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();//設置下egl相關變量 mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW); } for (size_t i=VIRTUAL_DISPLAY_ID_BASE; ioutbuf = disp.outbufHandle; mLists[i]->outbufAcquireFenceFd = disp.outbufAcquireFence->dup(); } } err = mHwc->set(mHwc, mNumDisplays, mLists);//調用硬件模塊合成 ......
轉載請注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/26810303),請尊重他人的
設計過一款基於開源的XMPP即時通信協議的軟件,采用C/S協議,通過GPRS無線網絡用TCP協議到服務器,以架設開源的Openfire 服務器作為即時通訊平台 系統主要由
Android圖表庫MPAndroidChart(十二)——正負堆疊條形圖。接上篇,今天要說的,和上篇的類似,只是方向是有相反的兩面,我們先看下效
前面我寫了兩篇文章說明了zc301的實現 具體請看 http://blog.csdn.net/hclydao/article/details/21235919 下面順