summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Stoza <stoza@google.com>2014-11-07 16:00:59 -0800
committerDan Stoza <stoza@google.com>2014-11-17 21:32:13 +0000
commit6b9454d1fee0347711af1746642aa7820b1ea04d (patch)
treeebf569047268bfce45e46fa63ae84d1e6d00fa9a
parent7d9fdd1e0d980fb9e67fbb96b4c499b1895109f1 (diff)
downloadnative-6b9454d1fee0347711af1746642aa7820b1ea04d.tar.gz
SurfaceFlinger: Do less work when using PTS
Currently, SurfaceFlinger is very dumb about how it handles buffer updates at less than 60fps. If there is a new frame pending, but its timestamp says not to present it until later SurfaceFlinger will wake up every vsync until it is time to present it. Even worse, if SurfaceFlinger has woken up but nothing has changed, it still goes through the entire composition process. This change (mostly) fixes that inefficiency. SurfaceFlinger will still wake up every refresh period while there is a new frame pending, but if there is no work to do, it will almost immediately go back to sleep. Bug: 18111837 Change-Id: I7825bacd37f40bf26edcc6a5e0f051dce45291fb
-rw-r--r--services/surfaceflinger/Layer.cpp32
-rw-r--r--services/surfaceflinger/Layer.h7
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp58
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h15
-rw-r--r--services/surfaceflinger/SurfaceFlingerConsumer.h2
5 files changed, 90 insertions, 24 deletions
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index acc277531d..c3e1a768e3 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -34,6 +34,7 @@
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
+#include <gui/BufferItem.h>
#include <gui/Surface.h>
#include "clz.h"
@@ -159,11 +160,26 @@ void Layer::onLayerDisplayed(const sp<const DisplayDevice>& /* 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
@@ -1014,6 +1030,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;
@@ -1203,6 +1227,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 e2100fcd1c..1d4eee7789 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -210,6 +210,8 @@ public:
void onLayerDisplayed(const sp<const DisplayDevice>& 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();
@@ -404,6 +407,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<BufferItem> mQueueItems;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c46962768c..b8b6472663 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -829,30 +829,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() {
@@ -1685,12 +1694,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.
@@ -1704,8 +1714,12 @@ void SurfaceFlinger::handlePageFlip()
Vector<Layer*> layersWithQueuedFrames;
for (size_t i = 0, count = layers.size(); i<count ; i++) {
const sp<Layer>& 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<count ; i++) {
Layer* layer = layersWithQueuedFrames[i];
@@ -1715,6 +1729,16 @@ void SurfaceFlinger::handlePageFlip()
}
mVisibleRegionsDirty |= visibleRegions;
+
+ // If we will need to wake up at some time in the future to deal with a
+ // queued frame that shouldn't be displayed during this vsync period, wake
+ // up during the next vsync period to check again.
+ if (frameQueued && layersWithQueuedFrames.empty()) {
+ signalLayerUpdate();
+ }
+
+ // Only continue with the refresh if there is actually new work to do
+ return !layersWithQueuedFrames.empty();
}
void SurfaceFlinger::invalidateHwcGeometry()
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 710dac7126..4deb815521 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -247,8 +247,12 @@ private:
// called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& 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 5633980ee1..28f2f6aeb5 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -67,9 +67,9 @@ public:
sp<NativeHandle> getSidebandStream() const;
-private:
nsecs_t computeExpectedPresent(const DispSync& dispSync);
+private:
virtual void onSidebandStreamChanged();
wp<ContentsChangedListener> mContentsChangedListener;