summaryrefslogtreecommitdiffstats
path: root/services/surfaceflinger
diff options
context:
space:
mode:
authorMathias Agopian <mathias@google.com>2011-09-20 17:21:56 -0700
committerMathias Agopian <mathias@google.com>2011-09-20 17:57:55 -0700
commit661a1bf0332240a2e677a07af5f96cb4534196be (patch)
tree6e9edcd6eb4cb6e4ade69809ffa7b43051e4f8e2 /services/surfaceflinger
parent97911723a3169cd6735d2305d504cf1ec4358b57 (diff)
downloadframeworks_base-661a1bf0332240a2e677a07af5f96cb4534196be.zip
frameworks_base-661a1bf0332240a2e677a07af5f96cb4534196be.tar.gz
frameworks_base-661a1bf0332240a2e677a07af5f96cb4534196be.tar.bz2
fix transition from full overlays to fb
we need to clear the whole framebuffer in that situation because we can't trust the content of the FB when partial (fb preserving) updates are used. Bug: 5318492 Change-Id: I3f0e01b0fb665a34e44d88ad9f0f54a5d990060b
Diffstat (limited to 'services/surfaceflinger')
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayHardware.h3
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp32
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.h5
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp96
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h2
5 files changed, 90 insertions, 48 deletions
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 40a6f1e..f02c954 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 daefd5e..e707bdc 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -40,6 +40,7 @@ namespace android {
HWComposer::HWComposer(const sp<SurfaceFlinger>& 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 ; i<count ; i++) {
+ hwc_layer& l(mList->hwLayers[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 8758a80..aa8ebe1 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<LayerBase> >& 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 1703448..0ef03bb 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<LayerBase> >& layers(mVisibleLayersSortedByZ);
@@ -916,53 +913,62 @@ Region SurfaceFlinger::setupHardwareComposer(const Region& dirty)
const sp<LayerBase>& 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) {
- Region transparent;
- for (size_t i=0 ; i<count ; i++) {
- // 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.
- //
- // 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.
+ // 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.
- const sp<LayerBase>& layer(layers[i]);
- if ((cur[i].hints & HWC_HINT_CLEAR_FB) && layer->isOpaque()) {
- transparent.orSelf(layer->visibleRegionScreen);
- }
-
- bool isOverlay = (cur[i].compositionType != HWC_FRAMEBUFFER) &&
- !(cur[i].flags & HWC_SKIP_LAYER);
+ Region transparent;
- 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);
+ if (!fbLayerCount && hwc.getLayerCount(HWC_FRAMEBUFFER)) {
+ transparent.set(hw.getBounds());
+ dirtyInOut = transparent;
+ } else {
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& 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);
}
- 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<LayerBase> >& layers(mVisibleLayersSortedByZ);
size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
- if (cur && (cur[i].compositionType != HWC_FRAMEBUFFER) &&
- !(cur[i].flags & HWC_SKIP_LAYER)) {
+ if (cur && (cur[i].compositionType != HWC_FRAMEBUFFER)) {
continue;
}
const sp<LayerBase>& layer(layers[i]);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a8036a6..d7f005f 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();