Fix virtual display nesting

This fixes the cycling rendering loop caused by nesting virtual
displays by preventing them from recomposing if their contents
haven't changed.

(cherry-pick from master I600365c0fd5d3ad93e04295d26cf9de177ffc79b)

Bug: 12101046
Change-Id: I6182993d53537781aedb522f97a50f06eed8b80f
This commit is contained in:
Dan Stoza 2014-02-04 16:22:36 -08:00 committed by Andy McFadden
parent cf818ebbf0
commit f3c07d4f70
8 changed files with 48 additions and 20 deletions

View File

@ -199,8 +199,8 @@ void DisplayDevice::flip(const Region& dirty) const
mPageFlipCount++; mPageFlipCount++;
} }
status_t DisplayDevice::beginFrame() const { status_t DisplayDevice::beginFrame(bool mustRecompose) const {
return mDisplaySurface->beginFrame(); return mDisplaySurface->beginFrame(mustRecompose);
} }
status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const { status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const {

View File

@ -124,7 +124,9 @@ public:
int32_t getHwcDisplayId() const { return mHwcDisplayId; } int32_t getHwcDisplayId() const { return mHwcDisplayId; }
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; } const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
status_t beginFrame() const; // We pass in mustRecompose so we can keep VirtualDisplaySurface's state
// machine happy without actually queueing a buffer if nothing has changed
status_t beginFrame(bool mustRecompose) const;
status_t prepareFrame(const HWComposer& hwc) const; status_t prepareFrame(const HWComposer& hwc) const;
void swapBuffers(HWComposer& hwc) const; void swapBuffers(HWComposer& hwc) const;

View File

@ -33,7 +33,9 @@ public:
// beginFrame is called at the beginning of the composition loop, before // beginFrame is called at the beginning of the composition loop, before
// the configuration is known. The DisplaySurface should do anything it // the configuration is known. The DisplaySurface should do anything it
// needs to do to enable HWComposer to decide how to compose the frame. // needs to do to enable HWComposer to decide how to compose the frame.
virtual status_t beginFrame() = 0; // We pass in mustRecompose so we can keep VirtualDisplaySurface's state
// machine happy without actually queueing a buffer if nothing has changed.
virtual status_t beginFrame(bool mustRecompose) = 0;
// prepareFrame is called after the composition configuration is known but // prepareFrame is called after the composition configuration is known but
// before composition takes place. The DisplaySurface can use the // before composition takes place. The DisplaySurface can use the

View File

@ -68,7 +68,7 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp,
mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
} }
status_t FramebufferSurface::beginFrame() { status_t FramebufferSurface::beginFrame(bool mustRecompose) {
return NO_ERROR; return NO_ERROR;
} }

View File

@ -39,7 +39,7 @@ class FramebufferSurface : public ConsumerBase,
public: public:
FramebufferSurface(HWComposer& hwc, int disp, const sp<IGraphicBufferConsumer>& consumer); FramebufferSurface(HWComposer& hwc, int disp, const sp<IGraphicBufferConsumer>& consumer);
virtual status_t beginFrame(); virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType compositionType); virtual status_t prepareFrame(CompositionType compositionType);
virtual status_t compositionComplete(); virtual status_t compositionComplete();
virtual status_t advanceFrame(); virtual status_t advanceFrame();

View File

@ -56,7 +56,8 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
mOutputUsage(GRALLOC_USAGE_HW_COMPOSER), mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
mProducerSlotSource(0), mProducerSlotSource(0),
mDbgState(DBG_STATE_IDLE), mDbgState(DBG_STATE_IDLE),
mDbgLastCompositionType(COMPOSITION_UNKNOWN) mDbgLastCompositionType(COMPOSITION_UNKNOWN),
mMustRecompose(false)
{ {
mSource[SOURCE_SINK] = sink; mSource[SOURCE_SINK] = sink;
mSource[SOURCE_SCRATCH] = bq; mSource[SOURCE_SCRATCH] = bq;
@ -92,10 +93,12 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
VirtualDisplaySurface::~VirtualDisplaySurface() { VirtualDisplaySurface::~VirtualDisplaySurface() {
} }
status_t VirtualDisplaySurface::beginFrame() { status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) {
if (mDisplayId < 0) if (mDisplayId < 0)
return NO_ERROR; return NO_ERROR;
mMustRecompose = mustRecompose;
VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE, VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
"Unexpected beginFrame() in %s state", dbgStateStr()); "Unexpected beginFrame() in %s state", dbgStateStr());
mDbgState = DBG_STATE_BEGUN; mDbgState = DBG_STATE_BEGUN;
@ -228,16 +231,24 @@ void VirtualDisplaySurface::onFrameCommitted() {
QueueBufferOutput qbo; QueueBufferOutput qbo;
sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId); sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId);
VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot); VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot);
status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, if (mMustRecompose) {
QueueBufferInput( status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
systemTime(), false /* isAutoTimestamp */, QueueBufferInput(
Rect(mSinkBufferWidth, mSinkBufferHeight), systemTime(), false /* isAutoTimestamp */,
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */, Rect(mSinkBufferWidth, mSinkBufferHeight),
true /* async*/, NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */,
outFence), true /* async*/,
&qbo); outFence),
if (result == NO_ERROR) { &qbo);
updateQueueBufferOutput(qbo); if (result == NO_ERROR) {
updateQueueBufferOutput(qbo);
}
} else {
// If the surface hadn't actually been updated, then we only went
// through the motions of updating the display to keep our state
// machine happy. We cancel the buffer to avoid triggering another
// re-composition and causing an infinite loop.
mSource[SOURCE_SINK]->cancelBuffer(sslot, outFence);
} }
} }

View File

@ -79,7 +79,7 @@ public:
// //
// DisplaySurface interface // DisplaySurface interface
// //
virtual status_t beginFrame(); virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType compositionType); virtual status_t prepareFrame(CompositionType compositionType);
virtual status_t compositionComplete(); virtual status_t compositionComplete();
virtual status_t advanceFrame(); virtual status_t advanceFrame();
@ -222,6 +222,8 @@ private:
const char* dbgStateStr() const; const char* dbgStateStr() const;
static const char* dbgSourceStr(Source s); static const char* dbgSourceStr(Source s);
bool mMustRecompose;
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -881,7 +881,9 @@ void SurfaceFlinger::rebuildLayerStacks() {
void SurfaceFlinger::setUpHWComposer() { void SurfaceFlinger::setUpHWComposer() {
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
mDisplays[dpy]->beginFrame(); bool mustRecompose =
!(mDisplays[dpy]->getDirtyRegion(false).isEmpty());
mDisplays[dpy]->beginFrame(mustRecompose);
} }
HWComposer& hwc(getHwComposer()); HWComposer& hwc(getHwComposer());
@ -1499,6 +1501,15 @@ void SurfaceFlinger::invalidateHwcGeometry()
void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
const Region& inDirtyRegion) const Region& inDirtyRegion)
{ {
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
// 2) There is work to be done (the dirty region isn't empty)
bool isHwcDisplay = hw->getHwcDisplayId() >= 0;
if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
return;
}
Region dirtyRegion(inDirtyRegion); Region dirtyRegion(inDirtyRegion);
// compute the invalid region // compute the invalid region