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:
parent
cf818ebbf0
commit
f3c07d4f70
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue