Fix an issue is SF that caused drawing artifacts when hwc changed mode

we were not redrawing and/or clearing the FB properly when
hwc moved a layer from/to FB to/from OVERLAY.

In these cases we needed to expand the dirty region to include
the layer that changed mode.

Also split composeSurfaces() which was becoming quite large.

Change-Id: Id6fa1acfc4ff694037fddf7efd037a4405732073
This commit is contained in:
Mathias Agopian 2011-09-08 18:31:55 -07:00
parent 93ec1147c4
commit f384cc3008
4 changed files with 88 additions and 63 deletions

View File

@ -344,6 +344,14 @@ void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
hwcl->handle = NULL;
}
void LayerBase::setOverlay(bool inOverlay) {
mInOverlay = inOverlay;
}
bool LayerBase::isOverlay() const {
return mInOverlay;
}
void LayerBase::setFiltering(bool filtering)
{
mFiltering = filtering;

View File

@ -109,8 +109,10 @@ public:
virtual const char* getTypeId() const { return "LayerBase"; }
virtual void setGeometry(hwc_layer_t* hwcl);
virtual void setPerFrameData(hwc_layer_t* hwcl);
void setOverlay(bool inOverlay);
bool isOverlay() const;
/**
* draw - performs some global clipping optimizations
@ -242,6 +244,11 @@ private:
// Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering;
// this layer is currently handled by the hwc. this is
// updated at composition time, always frmo the composition
// thread.
bool mInOverlay;
protected:
// cached during validateVisibility()
int32_t mOrientation;

View File

@ -817,20 +817,6 @@ void SurfaceFlinger::handleWorkList()
mHwWorkListDirty = false;
HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
if (hwc.initCheck() == NO_ERROR) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
uint32_t flags = hw.getFlags();
if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
(flags & DisplayHardware::BUFFER_PRESERVED))
{
// we need to redraw everything (the whole screen)
// NOTE: we could be more subtle here and redraw only
// the area which will end-up in an overlay. But since this
// shouldn't happen often, we invalidate everything.
mDirtyRegion.set(hw.bounds());
mInvalidRegion = mDirtyRegion;
}
const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ);
const size_t count = currentLayers.size();
hwc.createWorkList(count);
@ -891,29 +877,26 @@ void SurfaceFlinger::handleRepaint()
}
// compose all surfaces
setupHardwareComposer(&mDirtyRegion);
composeSurfaces(mDirtyRegion);
// clear the dirty regions
mDirtyRegion.clear();
}
void SurfaceFlinger::composeSurfaces(const Region& dirty)
void SurfaceFlinger::setupHardwareComposer(Region* dirtyInOut)
{
if (UNLIKELY(!mWormholeRegion.isEmpty())) {
// should never happen unless the window manager has a bug
// draw something...
drawWormhole();
}
status_t err = NO_ERROR;
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
size_t count = layers.size();
const DisplayHardware& hw(graphicPlane(0).displayHardware());
HWComposer& hwc(hw.getHwComposer());
hwc_layer_t* const cur(hwc.getLayers());
if (!cur) {
return;
}
LOGE_IF(cur && hwc.getNumLayers() != count,
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
size_t count = layers.size();
LOGE_IF(hwc.getNumLayers() != count,
"HAL number of layers (%d) doesn't match surfaceflinger (%d)",
hwc.getNumLayers(), count);
@ -927,56 +910,82 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty)
* and build the transparent region of the FB
*/
Region transparent;
if (cur) {
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(layers[i]);
layer->setPerFrameData(&cur[i]);
}
err = hwc.prepare();
LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(layers[i]);
layer->setPerFrameData(&cur[i]);
}
status_t err = hwc.prepare();
LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
if (err == NO_ERROR) {
for (size_t i=0 ; i<count ; i++) {
if (cur[i].hints & HWC_HINT_CLEAR_FB) {
const sp<LayerBase>& layer(layers[i]);
if (layer->isOpaque()) {
transparent.orSelf(layer->visibleRegionScreen);
}
}
if (err == NO_ERROR) {
Region transparentDirty(*dirtyInOut);
for (size_t i=0 ; i<count ; i++) {
// Calculate the new transparent region and dirty region
// - the transparent region needs to always include the layers
// that moved from FB to OVERLAY, regardless of the dirty region
// - the dirty region needs to be expanded to include layers
// that moved from OVERLAY to FB.
const sp<LayerBase>& layer(layers[i]);
if ((cur[i].hints & HWC_HINT_CLEAR_FB) && layer->isOpaque()) {
transparent.orSelf(layer->visibleRegionScreen);
}
/*
* clear the area of the FB that need to be transparent
*/
transparent.andSelf(dirty);
if (!transparent.isEmpty()) {
glClearColor(0,0,0,0);
Region::const_iterator it = transparent.begin();
Region::const_iterator const end = transparent.end();
const int32_t height = hw.getHeight();
while (it != end) {
const Rect& r(*it++);
const GLint sy = height - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glClear(GL_COLOR_BUFFER_BIT);
}
bool isOverlay = (cur[i].compositionType != HWC_FRAMEBUFFER) &&
!(cur[i].flags & HWC_SKIP_LAYER);
if (!isOverlay && layer->isOverlay()) {
dirtyInOut->orSelf(layer->visibleRegionScreen);
}
if (isOverlay && !layer->isOverlay()) {
transparentDirty.orSelf(layer->visibleRegionScreen);
}
layer->setOverlay(isOverlay);
}
/*
* clear the area of the FB that need to be transparent
*/
transparent.andSelf(transparentDirty);
if (!transparent.isEmpty()) {
glClearColor(0,0,0,0);
Region::const_iterator it = transparent.begin();
Region::const_iterator const end = transparent.end();
const int32_t height = hw.getHeight();
while (it != end) {
const Rect& r(*it++);
const GLint sy = height - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glClear(GL_COLOR_BUFFER_BIT);
}
}
}
}
void SurfaceFlinger::composeSurfaces(const Region& dirty)
{
if (UNLIKELY(!mWormholeRegion.isEmpty())) {
// should never happen unless the window manager has a bug
// draw something...
drawWormhole();
}
const DisplayHardware& hw(graphicPlane(0).displayHardware());
HWComposer& hwc(hw.getHwComposer());
hwc_layer_t* const cur(hwc.getLayers());
/*
* and then, render the layers targeted at the framebuffer
*/
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
if (cur) {
if ((cur[i].compositionType != HWC_FRAMEBUFFER) &&
if (cur && (cur[i].compositionType != HWC_FRAMEBUFFER) &&
!(cur[i].flags & HWC_SKIP_LAYER)) {
// skip layers handled by the HAL
continue;
}
continue;
}
const sp<LayerBase>& layer(layers[i]);
const Region clip(dirty.intersect(layer->visibleRegionScreen));
if (!clip.isEmpty()) {

View File

@ -277,6 +277,7 @@ private:
void handleWorkList();
void handleRepaint();
void postFramebuffer();
void setupHardwareComposer(Region* dirtyInOut);
void composeSurfaces(const Region& dirty);
void repaintEverything();