From e60b0687c8d49871d0c8786cabe6851f7a7783b5 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 21 Aug 2012 23:34:09 -0700 Subject: [PATCH] HWComposer now has its own concept of display IDs HWComposer can now create IDs representing a display it can deal with. IDs MAIN and HDMI are reserved. SurfaceFlinger associate HWComposer IDs with a DisplayDevice and uses that when it talks to HWComposer. A DisplayDevice doesn't have to have a HWComposer ID, in that case it just can't use h/w composer composition. Change-Id: Iec3d7ac92e0c22bf975052ae2847402f58bade71 --- services/surfaceflinger/DisplayDevice.cpp | 4 +- services/surfaceflinger/DisplayDevice.h | 4 +- .../DisplayHardware/HWComposer.cpp | 162 ++++++++++-------- .../DisplayHardware/HWComposer.h | 45 +++-- services/surfaceflinger/SurfaceFlinger.cpp | 71 ++++---- 5 files changed, 171 insertions(+), 115 deletions(-) diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 228944422..821a3295c 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -68,12 +68,12 @@ void checkGLErrors() DisplayDevice::DisplayDevice( const sp& flinger, - int display, + int32_t display, int32_t hwcDisplayId, const sp& nativeWindow, const sp& framebufferSurface, EGLConfig config) : mFlinger(flinger), - mId(display), + mId(display), mHwcDisplayId(hwcDisplayId), mNativeWindow(nativeWindow), mFramebufferSurface(framebufferSurface), mDisplay(EGL_NO_DISPLAY), diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 979069954..14b194fb1 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -62,7 +62,7 @@ public: DisplayDevice( const sp& flinger, - int dpy, + int32_t dpy, int32_t hwcDisplayId, const sp& nativeWindow, const sp& framebufferSurface, EGLConfig config); @@ -96,6 +96,7 @@ public: const Transform& getTransform() const { return mGlobalTransform; } uint32_t getLayerStack() const { return mLayerStack; } int32_t getDisplayId() const { return mId; } + int32_t getHwcDisplayId() const { return mHwcDisplayId; } status_t compositionComplete() const; @@ -132,6 +133,7 @@ private: */ sp mFlinger; int32_t mId; + int32_t mHwcDisplayId; // ANativeWindow this display is rendering into sp mNativeWindow; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 403b9799b..dd7023289 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -194,13 +194,13 @@ HWComposer::HWComposer( framebuffer_device_t const* fbDev) : mFlinger(flinger), mModule(0), mHwc(0), mNumDisplays(1), mCapacity(0), - mNumOVLayers(0), mNumFBLayers(0), mCBContext(new cb_context), - mEventHandler(handler), mRefreshPeriod(0), + mEventHandler(handler), mVSyncCount(0), mDebugForceFakeVSync(false) { - for (size_t i = 0; i < MAX_DISPLAYS; i++) - mLists[i] = NULL; + for (size_t i =0 ; iregisterProcs(mHwc, &mCBContext->procs); } + // these IDs are always reserved + mTokens.markBit(HWC_DISPLAY_PRIMARY); + mTokens.markBit(HWC_DISPLAY_EXTERNAL); + // always turn vsync off when we start needVSyncThread = false; if (hwcHasVsyncEvent(mHwc)) { @@ -239,7 +243,7 @@ HWComposer::HWComposer( int period; if (mHwc->query(mHwc, HWC_VSYNC_PERIOD, &period) == NO_ERROR) { - mRefreshPeriod = nsecs_t(period); + mDisplayData[0].refresh = nsecs_t(period); } } else { needVSyncThread = true; @@ -255,17 +259,17 @@ HWComposer::HWComposer( if (fbDev) { - if (mRefreshPeriod == 0) { - mRefreshPeriod = nsecs_t(1e9 / fbDev->fps); - ALOGW("getting VSYNC period from fb HAL: %lld", mRefreshPeriod); + if (mDisplayData[HWC_DISPLAY_PRIMARY].refresh == 0) { + mDisplayData[HWC_DISPLAY_PRIMARY].refresh = nsecs_t(1e9 / fbDev->fps); + ALOGW("getting VSYNC period from fb HAL: %lld", mDisplayData[0].refresh); } - mDpiX = fbDev->xdpi; - mDpiY = fbDev->ydpi; + mDisplayData[HWC_DISPLAY_PRIMARY].xdpi = fbDev->xdpi; + mDisplayData[HWC_DISPLAY_PRIMARY].ydpi = fbDev->ydpi; } - if (mRefreshPeriod == 0) { - mRefreshPeriod = nsecs_t(1e9 / 60.0); - ALOGW("getting VSYNC period thin air: %lld", mRefreshPeriod); + if (mDisplayData[HWC_DISPLAY_PRIMARY].refresh == 0) { + mDisplayData[HWC_DISPLAY_PRIMARY].refresh = nsecs_t(1e9 / 60.0); + ALOGW("getting VSYNC period thin air: %lld", mDisplayData[0].refresh); } if (needVSyncThread) { @@ -276,8 +280,9 @@ HWComposer::HWComposer( HWComposer::~HWComposer() { hwcEventControl(mHwc, 0, EVENT_VSYNC, 0); - for (size_t i = 0; i < MAX_DISPLAYS; i++) + for (size_t i = 0; i < MAX_DISPLAYS; i++) { free(mLists[i]); + } if (mVSyncThread != NULL) { mVSyncThread->requestExitAndWait(); } @@ -315,8 +320,32 @@ void HWComposer::vsync(int dpy, int64_t timestamp) { mLastHwVSync = timestamp; } +int32_t HWComposer::allocateDisplayId() { + if (mTokens.isFull()) { + return NO_MEMORY; + } + + // FIXME: for now we don't support h/w composition wifi displays + return -1; + + int32_t id = mTokens.firstUnmarkedBit(); + mTokens.markBit(id); + return id; +} + +status_t HWComposer::freeDisplayId(int32_t id) { + if (id < MAX_DISPLAYS) { + return BAD_VALUE; + } + if (!mTokens.hasBit(id)) { + return BAD_INDEX; + } + mTokens.clearBit(id); + return NO_ERROR; +} + nsecs_t HWComposer::getRefreshPeriod() const { - return mRefreshPeriod; + return mDisplayData[0].refresh; } nsecs_t HWComposer::getRefreshTimestamp() const { @@ -325,15 +354,15 @@ nsecs_t HWComposer::getRefreshTimestamp() const { // the refresh period and whatever closest timestamp we have. Mutex::Autolock _l(mLock); nsecs_t now = systemTime(CLOCK_MONOTONIC); - return now - ((now - mLastHwVSync) % mRefreshPeriod); + return now - ((now - mLastHwVSync) % mDisplayData[0].refresh); } float HWComposer::getDpiX() const { - return mDpiX; + return mDisplayData[HWC_DISPLAY_PRIMARY].xdpi; } float HWComposer::getDpiY() const { - return mDpiY; + return mDisplayData[HWC_DISPLAY_PRIMARY].ydpi; } void HWComposer::eventControl(int event, int enabled) { @@ -354,10 +383,11 @@ void HWComposer::eventControl(int event, int enabled) { } status_t HWComposer::createWorkList(int32_t id, size_t numLayers) { - // FIXME: handle multiple displays - if (uint32_t(id) >= MAX_DISPLAYS) + if (!mTokens.hasBit(id)) { return BAD_INDEX; + } + // FIXME: handle multiple displays if (mHwc) { // TODO: must handle multiple displays here // mLists[0] is NULL only when this is called from the constructor @@ -376,9 +406,10 @@ status_t HWComposer::createWorkList(int32_t id, size_t numLayers) { return NO_ERROR; } -status_t HWComposer::prepare() const { +status_t HWComposer::prepare() { int err = hwcPrepare(mHwc, mNumDisplays, const_cast(mLists)); + if (err == NO_ERROR) { // here we're just making sure that "skip" layers are set @@ -388,65 +419,58 @@ status_t HWComposer::prepare() const { // think is almost possible. // TODO: must handle multiple displays here - - size_t numOVLayers = 0; - size_t numFBLayers = 0; - size_t count = getNumLayers(0); - - for (size_t i=0 ; ihwLayers[i]; + if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) { + size_t count = getNumLayers(0); + struct hwc_display_contents_1* disp = mLists[0]; + mDisplayData[0].hasFbComp = false; + mDisplayData[0].hasOvComp = false; + for (size_t i=0 ; ihwLayers[i]; if (l->flags & HWC_SKIP_LAYER) { l->compositionType = HWC_FRAMEBUFFER; } - compositionType = l->compositionType; - } else { - // mList really has hwc_layer_list_t memory layout - hwc_layer_list_t* list0 = reinterpret_cast(mLists[0]); - hwc_layer_t* l = &list0->hwLayers[i]; - if (l->flags & HWC_SKIP_LAYER) { - l->compositionType = HWC_FRAMEBUFFER; - } - compositionType = l->compositionType; + if (l->compositionType == HWC_FRAMEBUFFER) + mDisplayData[HWC_DISPLAY_PRIMARY].hasFbComp = true; + if (l->compositionType == HWC_OVERLAY) + mDisplayData[HWC_DISPLAY_PRIMARY].hasOvComp = true; } - - switch (compositionType) { - case HWC_OVERLAY: - numOVLayers++; - break; - case HWC_FRAMEBUFFER: - numFBLayers++; - break; + } else { + size_t count = getNumLayers(0); + hwc_layer_list_t* disp = reinterpret_cast(mLists[0]); + mDisplayData[0].hasFbComp = false; + mDisplayData[0].hasOvComp = false; + for (size_t i=0 ; ihwLayers[i]; + if (l->flags & HWC_SKIP_LAYER) { + l->compositionType = HWC_FRAMEBUFFER; + } + if (l->compositionType == HWC_FRAMEBUFFER) + mDisplayData[HWC_DISPLAY_PRIMARY].hasFbComp = true; + if (l->compositionType == HWC_OVERLAY) + mDisplayData[HWC_DISPLAY_PRIMARY].hasOvComp = true; } } - mNumOVLayers = numOVLayers; - mNumFBLayers = numFBLayers; } return (status_t)err; } -size_t HWComposer::getLayerCount(int32_t id, int type) const { - // FIXME: handle multiple displays - if (uint32_t(id) >= MAX_DISPLAYS) { - // FIXME: in practice this is only use to know - // if we have at least one layer of type. - return (type == HWC_FRAMEBUFFER) ? 1 : 0; - } - - - switch (type) { - case HWC_OVERLAY: - return mNumOVLayers; - case HWC_FRAMEBUFFER: - return mNumFBLayers; - } - return 0; +bool HWComposer::hasHwcComposition(int32_t id) const { + if (!mTokens.hasBit(id)) + return false; + return mDisplayData[id].hasOvComp; } -status_t HWComposer::commit(void* fbDisplay, void* fbSurface) const { +bool HWComposer::hasGlesComposition(int32_t id) const { + if (!mTokens.hasBit(id)) + return false; + return mDisplayData[id].hasFbComp; +} + +status_t HWComposer::commit() const { int err = NO_ERROR; if (mHwc) { + void* fbDisplay = eglGetCurrentDisplay(); + void* fbSurface = eglGetCurrentSurface(EGL_DRAW); err = hwcSet(mHwc, fbDisplay, fbSurface, mNumDisplays, const_cast(mLists)); if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) { @@ -661,10 +685,10 @@ public: * returns an iterator initialized at a given index in the layer list */ HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) { - // FIXME: handle multiple displays - if (uint32_t(id) >= MAX_DISPLAYS) + if (!mTokens.hasBit(id)) return LayerListIterator(); + // FIXME: handle multiple displays if (!mHwc || index > hwcNumHwLayers(mHwc, mLists[0])) return LayerListIterator(); if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) { @@ -741,7 +765,7 @@ void HWComposer::dump(String8& result, char* buffer, size_t SIZE, HWComposer::VSyncThread::VSyncThread(HWComposer& hwc) : mHwc(hwc), mEnabled(false), mNextFakeVSync(0), - mRefreshPeriod(hwc.mRefreshPeriod) + mRefreshPeriod(hwc.getRefreshPeriod()) { } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index d15c6f4cb..7bb3f81ea 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -28,6 +28,7 @@ #include #include #include +#include extern "C" int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, @@ -70,14 +71,26 @@ public: status_t initCheck() const; + // returns a display ID starting at MAX_DISPLAYS, this ID + // is to be used with createWorkList (and all other + // methods requiring an ID below). + // IDs below MAX_DISPLAY are pre-defined and therefore are always valid. + // returns a negative error code if an ID cannot be allocated + int32_t allocateDisplayId(); + + // recycles the given ID and frees the associated worklist. + // IDs below MAX_DISPLAYS are not recycled + status_t freeDisplayId(int32_t id); + + // Asks the HAL what it can do - status_t prepare() const; + status_t prepare(); // disable hwc until next createWorkList status_t disable(); // commits the list - status_t commit(void* fbDisplay, void* fbSurface) const; + status_t commit() const; // release hardware resources and blank screen status_t release() const; @@ -88,9 +101,11 @@ public: // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED. status_t createWorkList(int32_t id, size_t numLayers); - // get number of layers of the given type as updated in prepare(). - // type is HWC_OVERLAY or HWC_FRAMEBUFFER - size_t getLayerCount(int32_t id, int type) const; + // does this display have layers handled by HWC + bool hasHwcComposition(int32_t id) const; + + // does this display have layers handled by GLES + bool hasGlesComposition(int32_t id) const; // needed forward declarations class LayerListIterator; @@ -237,26 +252,32 @@ private: inline void vsync(int dpy, int64_t timestamp); + struct DisplayData { + DisplayData() : xdpi(0), ydpi(0), refresh(0), + hasFbComp(false), hasOvComp(false) { } + float xdpi; + float ydpi; + nsecs_t refresh; + bool hasFbComp; + bool hasOvComp; + }; + sp mFlinger; hw_module_t const* mModule; struct hwc_composer_device_1* mHwc; // invariant: mLists[0] != NULL iff mHwc != NULL - // TODO: decide whether mLists[i>0] should be non-NULL when display i is - // not attached/enabled. + // mLists[i>0] can be NULL. that display is to be ignored struct hwc_display_contents_1* mLists[MAX_DISPLAYS]; + DisplayData mDisplayData[MAX_DISPLAYS]; size_t mNumDisplays; size_t mCapacity; - mutable size_t mNumOVLayers; - mutable size_t mNumFBLayers; cb_context* mCBContext; EventHandler& mEventHandler; - nsecs_t mRefreshPeriod; - float mDpiX; - float mDpiY; size_t mVSyncCount; sp mVSyncThread; bool mDebugForceFakeVSync; + BitSet32 mTokens; // protected by mLock mutable Mutex mLock; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c63d0cf14..e6e258f4e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -409,7 +409,8 @@ status_t SurfaceFlinger::readyToRun() mCurrentState.displays.add(mDefaultDisplays[i], DisplayDeviceState(i)); } sp hw = new DisplayDevice(this, - DisplayDevice::DISPLAY_ID_MAIN, anw, fbs, mEGLConfig); + DisplayDevice::DISPLAY_ID_MAIN, HWC_DISPLAY_PRIMARY, + anw, fbs, mEGLConfig); mDisplays.add(hw->getDisplayId(), hw); // initialize OpenGL ES @@ -779,29 +780,30 @@ void SurfaceFlinger::setUpHWComposer() { mHwWorkListDirty = false; for (size_t dpy=0 ; dpy hw(mDisplays[dpy]); - const Vector< sp >& currentLayers( + const int32_t id = hw->getHwcDisplayId(); + if (id >= 0) { + const Vector< sp >& currentLayers( hw->getVisibleLayersSortedByZ()); - const size_t count = currentLayers.size(); + const size_t count = currentLayers.size(); + if (hwc.createWorkList(id, count) >= 0) { + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); + for (size_t i=0 ; cur!=end && i& layer(currentLayers[i]); - const int32_t id = hw->getDisplayId(); - if (hwc.createWorkList(id, count) >= 0) { - HWComposer::LayerListIterator cur = hwc.begin(id); - const HWComposer::LayerListIterator end = hwc.end(id); - for (size_t i=0 ; cur!=end && i& layer(currentLayers[i]); - - if (CC_UNLIKELY(workListsDirty)) { - layer->setGeometry(hw, *cur); - if (mDebugDisableHWC || mDebugRegion) { - cur->setSkip(true); + if (CC_UNLIKELY(workListsDirty)) { + layer->setGeometry(hw, *cur); + if (mDebugDisableHWC || mDebugRegion) { + cur->setSkip(true); + } } - } - /* - * update the per-frame h/w composer data for each layer - * and build the transparent region of the FB - */ - layer->setPerFrameData(hw, *cur); + /* + * update the per-frame h/w composer data for each layer + * and build the transparent region of the FB + */ + layer->setPerFrameData(hw, *cur); + } } } } @@ -841,21 +843,20 @@ void SurfaceFlinger::postFramebuffer() HWComposer& hwc(getHwComposer()); if (hwc.initCheck() == NO_ERROR) { - // FIXME: eventually commit() won't take arguments // FIXME: EGL spec says: // "surface must be bound to the calling thread's current context, // for the current rendering API." DisplayDevice::makeCurrent( getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN), mEGLContext); - hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface()); + hwc.commit(); } for (size_t dpy=0 ; dpy hw(mDisplays[dpy]); const Vector< sp >& currentLayers(hw->getVisibleLayersSortedByZ()); const size_t count = currentLayers.size(); - if (hwc.initCheck() == NO_ERROR) { - int32_t id = hw->getDisplayId(); + int32_t id = hw->getHwcDisplayId(); + if (id >=0 && hwc.initCheck() == NO_ERROR) { HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); for (size_t i = 0; cur != end && i < count; ++i, ++cur) { @@ -951,12 +952,15 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (state.surface->asBinder() != draw[i].surface->asBinder()) { // changing the surface is like destroying and // recreating the DisplayDevice + const int32_t hwcDisplayId = + (uint32_t(state.id) < DisplayDevice::DISPLAY_ID_COUNT) ? + state.id : getHwComposer().allocateDisplayId(); sp stc( new SurfaceTextureClient(state.surface)); sp disp = new DisplayDevice(this, - state.id, stc, 0, mEGLConfig); + state.id, hwcDisplayId, stc, 0, mEGLConfig); disp->setLayerStack(state.layerStack); disp->setOrientation(state.orientation); @@ -982,10 +986,14 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) for (size_t i=0 ; i stc( new SurfaceTextureClient(state.surface)); - sp disp = new DisplayDevice(this, state.id, - stc, 0, mEGLConfig); + sp disp = new DisplayDevice(this, + state.id, hwcDisplayId, stc, 0, mEGLConfig); mDisplays.add(state.id, disp); } } @@ -1251,12 +1259,13 @@ void SurfaceFlinger::doDisplayComposition(const sp& hw, void SurfaceFlinger::doComposeSurfaces(const sp& hw, const Region& dirty) { HWComposer& hwc(getHwComposer()); - int32_t id = hw->getDisplayId(); + int32_t id = hw->getHwcDisplayId(); HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); - const size_t fbLayerCount = hwc.getLayerCount(id, HWC_FRAMEBUFFER); - if (cur==end || fbLayerCount) { + const bool hasGlesComposition = hwc.hasGlesComposition(id); + const bool hasHwcComposition = hwc.hasHwcComposition(id); + if (cur==end || hasGlesComposition) { DisplayDevice::makeCurrent(hw, mEGLContext); @@ -1265,7 +1274,7 @@ void SurfaceFlinger::doComposeSurfaces(const sp& hw, const glLoadIdentity(); // Never touch the framebuffer if we don't have any framebuffer layers - if (hwc.getLayerCount(id, HWC_OVERLAY)) { + if (hasHwcComposition) { // 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