diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index c91f0affe..009baea88 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include "clz.h" @@ -158,11 +159,26 @@ void Layer::onLayerDisplayed(const sp& /* hw */, } } -void Layer::onFrameAvailable(const BufferItem& /* item */) { +void Layer::onFrameAvailable(const BufferItem& item) { + // Add this buffer from our internal queue tracker + { // Autolock scope + Mutex::Autolock lock(mQueueItemLock); + mQueueItems.push_back(item); + } + android_atomic_inc(&mQueuedFrames); mFlinger->signalLayerUpdate(); } +void Layer::onFrameReplaced(const BufferItem& item) { + Mutex::Autolock lock(mQueueItemLock); + if (mQueueItems.empty()) { + ALOGE("Can't replace a frame on an empty queue"); + return; + } + mQueueItems.editItemAt(0) = item; +} + void Layer::onSidebandStreamChanged() { if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) { // mSidebandStreamChanged was false @@ -1012,6 +1028,14 @@ bool Layer::setLayerStack(uint32_t layerStack) { // pageflip handling... // ---------------------------------------------------------------------------- +bool Layer::shouldPresentNow(const DispSync& dispSync) const { + Mutex::Autolock lock(mQueueItemLock); + nsecs_t expectedPresent = + mSurfaceFlingerConsumer->computeExpectedPresent(dispSync); + return mQueueItems.empty() ? + false : mQueueItems[0].mTimestamp < expectedPresent; +} + bool Layer::onPreComposition() { mRefreshPending = false; return mQueuedFrames > 0 || mSidebandStreamChanged; @@ -1201,6 +1225,12 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) return outDirtyRegion; } + // Remove this buffer from our internal queue tracker + { // Autolock scope + Mutex::Autolock lock(mQueueItemLock); + mQueueItems.removeAt(0); + } + // Decrement the queued-frames count. Signal another event if we // have more frames pending. if (android_atomic_dec(&mQueuedFrames) > 1) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index b705bc273..424c03ed3 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -210,6 +210,8 @@ public: void onLayerDisplayed(const sp& hw, HWComposer::HWCLayerInterface* layer); + bool shouldPresentNow(const DispSync& dispSync) const; + /* * called before composition. * returns true if the layer has pending updates. @@ -331,6 +333,7 @@ protected: private: // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener virtual void onFrameAvailable(const BufferItem& item); + virtual void onFrameReplaced(const BufferItem& item); virtual void onSidebandStreamChanged(); void commitTransaction(); @@ -403,6 +406,10 @@ private: // This layer can be a cursor on some displays. bool mPotentialCursor; + + // Local copy of the queued contents of the incoming BufferQueue + mutable Mutex mQueueItemLock; + Vector mQueueItems; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1060b096a..e8c90254e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -828,30 +828,39 @@ void SurfaceFlinger::eventControl(int disp, int event, int enabled) { void SurfaceFlinger::onMessageReceived(int32_t what) { ATRACE_CALL(); switch (what) { - case MessageQueue::TRANSACTION: - handleMessageTransaction(); - break; - case MessageQueue::INVALIDATE: - handleMessageTransaction(); - handleMessageInvalidate(); - signalRefresh(); - break; - case MessageQueue::REFRESH: - handleMessageRefresh(); - break; + case MessageQueue::TRANSACTION: { + handleMessageTransaction(); + break; + } + case MessageQueue::INVALIDATE: { + bool refreshNeeded = handleMessageTransaction(); + refreshNeeded |= handleMessageInvalidate(); + if (refreshNeeded) { + // Signal a refresh if a transaction modified the window state or if + // a new buffer was latched + signalRefresh(); + } + break; + } + case MessageQueue::REFRESH: { + handleMessageRefresh(); + break; + } } } -void SurfaceFlinger::handleMessageTransaction() { +bool SurfaceFlinger::handleMessageTransaction() { uint32_t transactionFlags = peekTransactionFlags(eTransactionMask); if (transactionFlags) { handleTransaction(transactionFlags); + return true; } + return false; } -void SurfaceFlinger::handleMessageInvalidate() { +bool SurfaceFlinger::handleMessageInvalidate() { ATRACE_CALL(); - handlePageFlip(); + return handlePageFlip(); } void SurfaceFlinger::handleMessageRefresh() { @@ -1686,12 +1695,13 @@ void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack, } } -void SurfaceFlinger::handlePageFlip() +bool SurfaceFlinger::handlePageFlip() { Region dirtyRegion; bool visibleRegions = false; const LayerVector& layers(mDrawingState.layersSortedByZ); + bool frameQueued = false; // Store the set of layers that need updates. This set must not change as // buffers are being latched, as this could result in a deadlock. @@ -1705,8 +1715,12 @@ void SurfaceFlinger::handlePageFlip() Vector layersWithQueuedFrames; for (size_t i = 0, count = layers.size(); i& layer(layers[i]); - if (layer->hasQueuedFrame()) - layersWithQueuedFrames.push_back(layer.get()); + if (layer->hasQueuedFrame()) { + frameQueued = true; + if (layer->shouldPresentNow(mPrimaryDispSync)) { + layersWithQueuedFrames.push_back(layer.get()); + } + } } for (size_t i = 0, count = layersWithQueuedFrames.size() ; i& hw, int mode); - void handleMessageTransaction(); - void handleMessageInvalidate(); + // Returns whether the transaction actually modified any state + bool handleMessageTransaction(); + + // Returns whether a new buffer has been latched (see handlePageFlip()) + bool handleMessageInvalidate(); + void handleMessageRefresh(); void handleTransaction(uint32_t transactionFlags); @@ -256,10 +260,11 @@ private: void updateCursorAsync(); - /* handlePageFilp: this is were we latch a new buffer - * if available and compute the dirty region. + /* handlePageFlip - latch a new buffer if available and compute the dirty + * region. Returns whether a new buffer has been latched, i.e., whether it + * is necessary to perform a refresh during this vsync. */ - void handlePageFlip(); + bool handlePageFlip(); /* ------------------------------------------------------------------------ * Transactions diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h index 5633980ee..28f2f6aeb 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.h +++ b/services/surfaceflinger/SurfaceFlingerConsumer.h @@ -67,9 +67,9 @@ public: sp getSidebandStream() const; -private: nsecs_t computeExpectedPresent(const DispSync& dispSync); +private: virtual void onSidebandStreamChanged(); wp mContentsChangedListener;