surfaceflinger: skip composition for empty frames

By not committing the results of composition for empty frames, we
avoid spitting out series of black frames for virtual displays that
don't have visible layers. We still draw one black frame when going
from having layers to not having any. In particular, this avoids
having a series of empty frames due to re-compositing the primary
display in the period between creating the virtual display and adding
layers to it.

Bug: 16786752
Change-Id: I7e9b2ed2e407d8d49c7af736b447d4c6181b0ad8
This commit is contained in:
Jesse Hall 2014-08-14 15:45:06 -07:00
parent e3d37a7b55
commit b7a0549c98
3 changed files with 28 additions and 3 deletions

View File

@ -59,7 +59,8 @@ DisplayDevice::DisplayDevice(
const sp<DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer,
EGLConfig config)
: mFlinger(flinger),
: lastCompositionHadVisibleLayers(false),
mFlinger(flinger),
mType(type), mHwcDisplayId(hwcId),
mDisplayToken(displayToken),
mDisplaySurface(displaySurface),

View File

@ -53,6 +53,7 @@ public:
mutable Region swapRegion;
// region in screen space
Region undefinedRegion;
bool lastCompositionHadVisibleLayers;
enum DisplayType {
DISPLAY_ID_INVALID = -1,

View File

@ -881,9 +881,32 @@ void SurfaceFlinger::rebuildLayerStacks() {
void SurfaceFlinger::setUpHWComposer() {
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
bool mustRecompose =
!(mDisplays[dpy]->getDirtyRegion(false).isEmpty());
bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
// If nothing has changed (!dirty), don't recompose.
// If something changed, but we don't currently have any visible layers,
// and didn't when we last did a composition, then skip it this time.
// The second rule does two things:
// - When all layers are removed from a display, we'll emit one black
// frame, then nothing more until we get new layers.
// - When a display is created with a private layer stack, we won't
// emit any black frames until a layer is added to the layer stack.
bool mustRecompose = dirty && !(empty && wasEmpty);
ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
"dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy,
mustRecompose ? "doing" : "skipping",
dirty ? "+" : "-",
empty ? "+" : "-",
wasEmpty ? "+" : "-");
mDisplays[dpy]->beginFrame(mustRecompose);
if (mustRecompose) {
mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
}
}
HWComposer& hwc(getHwComposer());