diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h index 40a6f1e8c..f02c95414 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h @@ -84,9 +84,10 @@ public: status_t compositionComplete() const; - Rect bounds() const { + Rect getBounds() const { return Rect(mWidth, mHeight); } + inline Rect bounds() const { return getBounds(); } // only for debugging int getCurrentBufferIndex() const; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index daefd5e32..e707bdce7 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -40,6 +40,7 @@ namespace android { HWComposer::HWComposer(const sp& flinger) : mFlinger(flinger), mModule(0), mHwc(0), mList(0), mCapacity(0), + mNumOVLayers(0), mNumFBLayers(0), mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE) { int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule); @@ -98,9 +99,40 @@ status_t HWComposer::createWorkList(size_t numLayers) { status_t HWComposer::prepare() const { int err = mHwc->prepare(mHwc, mList); + if (err == NO_ERROR) { + size_t numOVLayers = 0; + size_t numFBLayers = 0; + size_t count = mList->numHwLayers; + for (size_t i=0 ; ihwLayers[i]); + if (l.flags & HWC_SKIP_LAYER) { + l.compositionType = HWC_FRAMEBUFFER; + } + switch (l.compositionType) { + case HWC_OVERLAY: + numOVLayers++; + break; + case HWC_FRAMEBUFFER: + numFBLayers++; + break; + } + } + mNumOVLayers = numOVLayers; + mNumFBLayers = numFBLayers; + } return (status_t)err; } +size_t HWComposer::getLayerCount(int type) const { + switch (type) { + case HWC_OVERLAY: + return mNumOVLayers; + case HWC_FRAMEBUFFER: + return mNumFBLayers; + } + return 0; +} + status_t HWComposer::commit() const { int err = mHwc->set(mHwc, mDpy, mSur, mList); if (mList) { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 8758a801b..aa8ebe1fd 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -64,6 +64,9 @@ public: size_t getNumLayers() const; hwc_layer_t* getLayers() const; + // updated in preapre() + size_t getLayerCount(int type) const; + // for debugging void dump(String8& out, char* scratch, size_t SIZE, const Vector< sp >& visibleLayersSortedByZ) const; @@ -81,6 +84,8 @@ private: hwc_composer_device_t* mHwc; hwc_layer_list_t* mList; size_t mCapacity; + mutable size_t mNumOVLayers; + mutable size_t mNumFBLayers; hwc_display_t mDpy; hwc_surface_t mSur; cb_context mCBContext; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1703448cf..0ef03bb7d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -876,24 +876,21 @@ void SurfaceFlinger::handleRepaint() } } - Region expandDirty = setupHardwareComposer(mDirtyRegion); - mDirtyRegion.orSelf(expandDirty); - mSwapRegion.orSelf(mDirtyRegion); + setupHardwareComposer(mDirtyRegion); composeSurfaces(mDirtyRegion); - // clear the dirty regions + // update the swap region and clear the dirty region + mSwapRegion.orSelf(mDirtyRegion); mDirtyRegion.clear(); } -Region SurfaceFlinger::setupHardwareComposer(const Region& dirty) +void SurfaceFlinger::setupHardwareComposer(Region& dirtyInOut) { - Region dirtyOut(dirty); - const DisplayHardware& hw(graphicPlane(0).displayHardware()); HWComposer& hwc(hw.getHwComposer()); hwc_layer_t* const cur(hwc.getLayers()); if (!cur) { - return dirtyOut; + return; } const Vector< sp >& layers(mVisibleLayersSortedByZ); @@ -916,53 +913,62 @@ Region SurfaceFlinger::setupHardwareComposer(const Region& dirty) const sp& layer(layers[i]); layer->setPerFrameData(&cur[i]); } + const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER); status_t err = hwc.prepare(); LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); if (err == NO_ERROR) { + // what's happening here is tricky. + // we want to clear all the layers with the CLEAR_FB flags + // that are opaque. + // however, since some GPU are efficient at preserving + // the backbuffer, we want to take advantage of that so we do the + // clear only in the dirty region (other areas will be preserved + // on those GPUs). + // NOTE: on non backbuffer preserving GPU, the dirty region + // has already been expanded as needed, so the code is correct + // there too. + // + // However, the content of the framebuffer cannot be trusted when + // we switch to/from FB/OVERLAY, in which case we need to + // expand the dirty region to those areas too. + // + // Note also that there is a special case when switching from + // "no layers in FB" to "some layers in FB", where we need to redraw + // the entire FB, since some areas might contain uninitialized + // data. + // + // Also we want to make sure to not clear areas that belong to + // layers above that won't redraw (we would just erasing them), + // that is, we can't erase anything outside the dirty region. + Region transparent; - for (size_t i=0 ; i& layer(layers[i]); - if ((cur[i].hints & HWC_HINT_CLEAR_FB) && layer->isOpaque()) { - transparent.orSelf(layer->visibleRegionScreen); + if (!fbLayerCount && hwc.getLayerCount(HWC_FRAMEBUFFER)) { + transparent.set(hw.getBounds()); + dirtyInOut = transparent; + } else { + for (size_t i=0 ; i& layer(layers[i]); + if ((cur[i].hints & HWC_HINT_CLEAR_FB) && layer->isOpaque()) { + transparent.orSelf(layer->visibleRegionScreen); + } + bool isOverlay = (cur[i].compositionType != HWC_FRAMEBUFFER); + if (isOverlay != layer->isOverlay()) { + // we transitioned to/from overlay, so add this layer + // to the dirty region so the framebuffer can be either + // cleared or redrawn. + dirtyInOut.orSelf(layer->visibleRegionScreen); + } + layer->setOverlay(isOverlay); } - - bool isOverlay = (cur[i].compositionType != HWC_FRAMEBUFFER) && - !(cur[i].flags & HWC_SKIP_LAYER); - - if (isOverlay != layer->isOverlay()) { - // we transitioned to/from overlay, so add this layer - // to the dirty region so the framebuffer can be either - // cleared or redrawn. - dirtyOut.orSelf(layer->visibleRegionScreen); - } - layer->setOverlay(isOverlay); + // don't erase stuff outside the dirty region + transparent.andSelf(dirtyInOut); } - /* * clear the area of the FB that need to be transparent */ - // don't erase stuff outside the dirty region - transparent.andSelf(dirtyOut); if (!transparent.isEmpty()) { glClearColor(0,0,0,0); Region::const_iterator it = transparent.begin(); @@ -976,7 +982,6 @@ Region SurfaceFlinger::setupHardwareComposer(const Region& dirty) } } } - return dirtyOut; } void SurfaceFlinger::composeSurfaces(const Region& dirty) @@ -997,8 +1002,7 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty) const Vector< sp >& layers(mVisibleLayersSortedByZ); size_t count = layers.size(); for (size_t i=0 ; i& layer(layers[i]); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a8036a68f..d7f005f7c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -277,7 +277,7 @@ private: void handleWorkList(); void handleRepaint(); void postFramebuffer(); - Region setupHardwareComposer(const Region& dirty); + void setupHardwareComposer(Region& dirtyInOut); void composeSurfaces(const Region& dirty); void repaintEverything();