Support SurfaceView synchronization.
Add API for fetching the next frame number to be produced by
a given buffer producer. Add an API to SurfaceComposer to
defer execution of the current transaction until a given frame number.
Together these may be used to synchronize app drawing and surface
control updates.
Change-Id: I8e0f4993332ac0199c768c88581a453fefbaff1d
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 6e16a60..322f2ec 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -170,6 +170,9 @@
// See IGraphicBufferProducer::getConsumerName
virtual String8 getConsumerName() const override;
+ // See IGraphicBufferProducer::getNextFrameNumber
+ virtual uint64_t getNextFrameNumber() const override;
+
private:
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index b8cba2f..4586839 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -508,6 +508,9 @@
// Returns the name of the connected consumer.
virtual String8 getConsumerName() const = 0;
+
+ // Returns the number of the next frame which will be dequeued.
+ virtual uint64_t getNextFrameNumber() const = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index ed2331b..3f46460 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -109,6 +109,9 @@
// See IGraphicBufferProducer::getConsumerName
String8 getConsumerName() const;
+ // See IGraphicBufferProducer::getNextFrameNumber
+ uint64_t getNextFrameNumber() const;
+
protected:
virtual ~Surface();
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 37d953e..aa48718 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -134,6 +134,8 @@
status_t setSize(const sp<IBinder>& id, uint32_t w, uint32_t h);
status_t setCrop(const sp<IBinder>& id, const Rect& crop);
status_t setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
+ status_t deferTransactionUntil(const sp<IBinder>& id,
+ const sp<IBinder>& handle, uint64_t frameNumber);
status_t destroySurface(const sp<IBinder>& id);
status_t clearLayerFrameStats(const sp<IBinder>& token) const;
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 9f62f7c..993a92f 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -69,10 +69,15 @@
status_t setMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
status_t setCrop(const Rect& crop);
+ // Defers applying any changes made in this transaction until the Layer
+ // identified by handle reaches the given frameNumber
+ status_t deferTransactionUntil(sp<IBinder> handle, uint64_t frameNumber);
+
static status_t writeSurfaceToParcel(
const sp<SurfaceControl>& control, Parcel* parcel);
sp<Surface> getSurface() const;
+ sp<IBinder> getHandle() const;
status_t clearLayerFrameStats() const;
status_t getLayerFrameStats(FrameStats* outStats) const;
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index b2574d0..1711071 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -52,6 +52,7 @@
eFlagsChanged = 0x00000040,
eLayerStackChanged = 0x00000080,
eCropChanged = 0x00000100,
+ eDeferTransaction = 0x00000200
};
layer_state_t()
@@ -87,6 +88,8 @@
uint8_t reserved;
matrix22_t matrix;
Rect crop;
+ sp<IBinder> handle;
+ uint64_t frameNumber;
// non POD must be last. see write/read
Region transparentRegion;
};
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 0cb018c..9ef8ff7 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1151,6 +1151,14 @@
return mConsumerName;
}
+uint64_t BufferQueueProducer::getNextFrameNumber() const {
+ ATRACE_CALL();
+
+ Mutex::Autolock lock(mCore->mMutex);
+ uint64_t nextFrameNumber = mCore->mFrameCounter + 1;
+ return nextFrameNumber;
+}
+
void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
// If we're here, it means that a producer we were connected to died.
// We're guaranteed that we are still connected to it because we remove
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 8ab963d..640a9f2 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -49,7 +49,8 @@
SET_GENERATION_NUMBER,
GET_CONSUMER_NAME,
SET_MAX_DEQUEUED_BUFFER_COUNT,
- SET_ASYNC_MODE
+ SET_ASYNC_MODE,
+ GET_NEXT_FRAME_NUMBER
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -326,6 +327,18 @@
}
return reply.readString8();
}
+
+ virtual uint64_t getNextFrameNumber() const {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ status_t result = remote()->transact(GET_NEXT_FRAME_NUMBER, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getNextFrameNumber failed to transact: %d", result);
+ return 0;
+ }
+ uint64_t frameNumber = reply.readUint64();
+ return frameNumber;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -508,6 +521,12 @@
reply->writeString8(getConsumerName());
return NO_ERROR;
}
+ case GET_NEXT_FRAME_NUMBER: {
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ uint64_t frameNumber = getNextFrameNumber();
+ reply->writeUint64(frameNumber);
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index eafda86..06f13e8 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -38,6 +38,8 @@
*reinterpret_cast<layer_state_t::matrix22_t *>(
output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix;
output.write(crop);
+ output.writeStrongBinder(handle);
+ output.writeUint64(frameNumber);
output.write(transparentRegion);
return NO_ERROR;
}
@@ -62,6 +64,8 @@
return BAD_VALUE;
}
input.read(crop);
+ handle = input.readStrongBinder();
+ frameNumber = input.readUint64();
input.read(transparentRegion);
return NO_ERROR;
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index a31876b..9191b2a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -111,6 +111,10 @@
return result;
}
+uint64_t Surface::getNextFrameNumber() const {
+ return mGraphicBufferProducer->getNextFrameNumber();
+}
+
String8 Surface::getConsumerName() const {
return mGraphicBufferProducer->getConsumerName();
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 9167a0c..3242f55 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -158,6 +158,9 @@
const Rect& crop);
status_t setLayerStack(const sp<SurfaceComposerClient>& client,
const sp<IBinder>& id, uint32_t layerStack);
+ status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
+ const sp<IBinder>& id, const sp<IBinder>& handle,
+ uint64_t frameNumber);
void setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
@@ -383,6 +386,20 @@
return NO_ERROR;
}
+status_t Composer::deferTransactionUntil(
+ const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+ const sp<IBinder>& handle, uint64_t frameNumber) {
+ Mutex::Autolock lock(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s) {
+ return BAD_INDEX;
+ }
+ s->what |= layer_state_t::eDeferTransaction;
+ s->handle = handle;
+ s->frameNumber = frameNumber;
+ return NO_ERROR;
+}
+
// ---------------------------------------------------------------------------
DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
@@ -609,6 +626,11 @@
return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy);
}
+status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id,
+ const sp<IBinder>& handle, uint64_t frameNumber) {
+ return getComposer().deferTransactionUntil(this, id, handle, frameNumber);
+}
+
// ----------------------------------------------------------------------------
void SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 1983027..a945358 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -145,6 +145,13 @@
return mClient->setCrop(mHandle, crop);
}
+status_t SurfaceControl::deferTransactionUntil(sp<IBinder> handle,
+ uint64_t frameNumber) {
+ status_t err = validate();
+ if (err < 0) return err;
+ return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
+}
+
status_t SurfaceControl::clearLayerFrameStats() const {
status_t err = validate();
if (err < 0) return err;
@@ -190,5 +197,11 @@
return mSurfaceData;
}
+sp<IBinder> SurfaceControl::getHandle() const
+{
+ Mutex::Autolock lock(mLock);
+ return mHandle;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 48971bc..392b1cc 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -539,6 +539,10 @@
return String8("VirtualDisplaySurface");
}
+uint64_t VirtualDisplaySurface::getNextFrameNumber() const {
+ return 0;
+}
+
void VirtualDisplaySurface::updateQueueBufferOutput(
const QueueBufferOutput& qbo) {
uint32_t w, h, transformHint, numPendingBuffers;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index d53d43c..fb37373 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -119,6 +119,7 @@
virtual status_t allowAllocation(bool allow);
virtual status_t setGenerationNumber(uint32_t generationNumber);
virtual String8 getConsumerName() const override;
+ virtual uint64_t getNextFrameNumber() const override;
//
// Utility methods
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 33af4a5..a7b167f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -66,6 +66,8 @@
mName("unnamed"),
mFormat(PIXEL_FORMAT_NONE),
mTransactionFlags(0),
+ mPendingStateMutex(),
+ mPendingStates(),
mQueuedFrames(0),
mSidebandStreamChanged(false),
mCurrentTransform(0),
@@ -164,6 +166,20 @@
}
}
+void Layer::markSyncPointsAvailable(const BufferItem& item) {
+ auto pointIter = mLocalSyncPoints.begin();
+ while (pointIter != mLocalSyncPoints.end()) {
+ if ((*pointIter)->getFrameNumber() == item.mFrameNumber) {
+ auto syncPoint = *pointIter;
+ pointIter = mLocalSyncPoints.erase(pointIter);
+ Mutex::Autolock lock(mAvailableFrameMutex);
+ mAvailableFrames.push_back(std::move(syncPoint));
+ } else {
+ ++pointIter;
+ }
+ }
+}
+
void Layer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
@@ -192,30 +208,36 @@
mQueueItemCondition.broadcast();
}
+ markSyncPointsAvailable(item);
+
mFlinger->signalLayerUpdate();
}
void Layer::onFrameReplaced(const BufferItem& item) {
- Mutex::Autolock lock(mQueueItemLock);
+ { // Autolock scope
+ Mutex::Autolock lock(mQueueItemLock);
- // Ensure that callbacks are handled in order
- while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
- status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
- ms2ns(500));
- if (result != NO_ERROR) {
- ALOGE("[%s] Timed out waiting on callback", mName.string());
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+ ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
}
+
+ if (mQueueItems.empty()) {
+ ALOGE("Can't replace a frame on an empty queue");
+ return;
+ }
+ mQueueItems.editItemAt(0) = item;
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
}
- if (mQueueItems.empty()) {
- ALOGE("Can't replace a frame on an empty queue");
- return;
- }
- mQueueItems.editItemAt(0) = item;
-
- // Wake up any pending callbacks
- mLastFrameNumberReceived = item.mFrameNumber;
- mQueueItemCondition.broadcast();
+ markSyncPointsAvailable(item);
}
void Layer::onSidebandStreamChanged() {
@@ -266,6 +288,22 @@
return NO_ERROR;
}
+/*
+ * The layer handle is just a BBinder object passed to the client
+ * (remote process) -- we don't keep any reference on our side such that
+ * the dtor is called when the remote side let go of its reference.
+ *
+ * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for
+ * this layer when the handle is destroyed.
+ */
+class Layer::Handle : public BBinder, public LayerCleaner {
+ public:
+ Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
+ : LayerCleaner(flinger, layer), owner(layer) {}
+
+ wp<Layer> owner;
+};
+
sp<IBinder> Layer::getHandle() {
Mutex::Autolock _l(mLock);
@@ -274,23 +312,6 @@
mHasSurface = true;
- /*
- * The layer handle is just a BBinder object passed to the client
- * (remote process) -- we don't keep any reference on our side such that
- * the dtor is called when the remote side let go of its reference.
- *
- * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for
- * this layer when the handle is destroyed.
- */
-
- class Handle : public BBinder, public LayerCleaner {
- wp<const Layer> mOwner;
- public:
- Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
- : LayerCleaner(flinger, layer), mOwner(layer) {
- }
- };
-
return new Handle(mFlinger, this);
}
@@ -781,6 +802,24 @@
return static_cast<uint32_t>(producerStickyTransform);
}
+void Layer::addSyncPoint(std::shared_ptr<SyncPoint> point) {
+ uint64_t headFrameNumber = 0;
+ {
+ Mutex::Autolock lock(mQueueItemLock);
+ if (!mQueueItems.empty()) {
+ headFrameNumber = mQueueItems[0].mFrameNumber;
+ } else {
+ headFrameNumber = mLastFrameNumberReceived;
+ }
+ }
+
+ if (point->getFrameNumber() <= headFrameNumber) {
+ point->setFrameAvailable();
+ } else {
+ mLocalSyncPoints.push_back(std::move(point));
+ }
+}
+
void Layer::setFiltering(bool filtering) {
mFiltering = filtering;
}
@@ -895,9 +934,103 @@
// transaction
// ----------------------------------------------------------------------------
+void Layer::pushPendingState() {
+ if (!mCurrentState.modified) {
+ return;
+ }
+
+ Mutex::Autolock lock(mPendingStateMutex);
+
+ // If this transaction is waiting on the receipt of a frame, generate a sync
+ // point and send it to the remote layer.
+ if (mCurrentState.handle != nullptr) {
+ sp<Handle> handle = static_cast<Handle*>(mCurrentState.handle.get());
+ sp<Layer> handleLayer = handle->owner.promote();
+ if (handleLayer == nullptr) {
+ ALOGE("[%s] Unable to promote Layer handle", mName.string());
+ // If we can't promote the layer we are intended to wait on,
+ // then it is expired or otherwise invalid. Allow this transaction
+ // to be applied as per normal (no synchronization).
+ mCurrentState.handle = nullptr;
+ }
+
+ auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber);
+ handleLayer->addSyncPoint(syncPoint);
+ mRemoteSyncPoints.push_back(std::move(syncPoint));
+
+ // Wake us up to check if the frame has been received
+ setTransactionFlags(eTransactionNeeded);
+ }
+ mPendingStates.push_back(mCurrentState);
+}
+
+void Layer::popPendingState() {
+ auto oldFlags = mCurrentState.flags;
+ mCurrentState = mPendingStates[0];
+ mCurrentState.flags = (oldFlags & ~mCurrentState.mask) |
+ (mCurrentState.flags & mCurrentState.mask);
+
+ mPendingStates.removeAt(0);
+}
+
+bool Layer::applyPendingStates() {
+ Mutex::Autolock lock(mPendingStateMutex);
+
+ bool stateUpdateAvailable = false;
+ while (!mPendingStates.empty()) {
+ if (mPendingStates[0].handle != nullptr) {
+ if (mRemoteSyncPoints.empty()) {
+ // If we don't have a sync point for this, apply it anyway. It
+ // will be visually wrong, but it should keep us from getting
+ // into too much trouble.
+ ALOGE("[%s] No local sync point found", mName.string());
+ popPendingState();
+ stateUpdateAvailable = true;
+ continue;
+ }
+
+ if (mRemoteSyncPoints.front()->frameIsAvailable()) {
+ // Apply the state update
+ popPendingState();
+ stateUpdateAvailable = true;
+
+ // Signal our end of the sync point and then dispose of it
+ mRemoteSyncPoints.front()->setTransactionApplied();
+ mRemoteSyncPoints.pop_front();
+ }
+ break;
+ } else {
+ popPendingState();
+ stateUpdateAvailable = true;
+ }
+ }
+
+ // If we still have pending updates, wake SurfaceFlinger back up and point
+ // it at this layer so we can process them
+ if (!mPendingStates.empty()) {
+ setTransactionFlags(eTransactionNeeded);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
+ }
+
+ mCurrentState.modified = false;
+ return stateUpdateAvailable;
+}
+
+void Layer::notifyAvailableFrames() {
+ Mutex::Autolock lock(mAvailableFrameMutex);
+ for (auto frame : mAvailableFrames) {
+ frame->setFrameAvailable();
+ }
+}
+
uint32_t Layer::doTransaction(uint32_t flags) {
ATRACE_CALL();
+ pushPendingState();
+ if (!applyPendingStates()) {
+ return 0;
+ }
+
const Layer::State& s(getDrawingState());
const Layer::State& c(getCurrentState());
@@ -1017,6 +1150,7 @@
return false;
mCurrentState.sequence++;
mCurrentState.transform.set(x, y);
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1025,6 +1159,7 @@
return false;
mCurrentState.sequence++;
mCurrentState.z = z;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1033,6 +1168,7 @@
return false;
mCurrentState.requested.w = w;
mCurrentState.requested.h = h;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1041,6 +1177,7 @@
return false;
mCurrentState.sequence++;
mCurrentState.alpha = alpha;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1048,11 +1185,13 @@
mCurrentState.sequence++;
mCurrentState.transform.set(
matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setTransparentRegionHint(const Region& transparent) {
mCurrentState.requestedTransparentRegion = transparent;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1062,6 +1201,8 @@
return false;
mCurrentState.sequence++;
mCurrentState.flags = newFlags;
+ mCurrentState.mask = mask;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1070,6 +1211,7 @@
return false;
mCurrentState.sequence++;
mCurrentState.requested.crop = crop;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1079,10 +1221,22 @@
return false;
mCurrentState.sequence++;
mCurrentState.layerStack = layerStack;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
+void Layer::deferTransactionUntil(const sp<IBinder>& handle,
+ uint64_t frameNumber) {
+ mCurrentState.handle = handle;
+ mCurrentState.frameNumber = frameNumber;
+ // We don't set eTransactionNeeded, because just receiving a deferral
+ // request without any other state updates shouldn't actually induce a delay
+ mCurrentState.modified = true;
+ pushPendingState();
+ mCurrentState.modified = false;
+}
+
void Layer::useSurfaceDamage() {
if (mFlinger->mForceFullDamage) {
surfaceDamageRegion = Region::INVALID_REGION;
@@ -1307,9 +1461,35 @@
getProducerStickyTransform() != 0);
uint64_t maxFrameNumber = 0;
+ uint64_t headFrameNumber = 0;
{
Mutex::Autolock lock(mQueueItemLock);
maxFrameNumber = mLastFrameNumberReceived;
+ if (!mQueueItems.empty()) {
+ headFrameNumber = mQueueItems[0].mFrameNumber;
+ }
+ }
+
+ bool availableFramesEmpty = true;
+ {
+ Mutex::Autolock lock(mAvailableFrameMutex);
+ availableFramesEmpty = mAvailableFrames.empty();
+ }
+ if (!availableFramesEmpty) {
+ Mutex::Autolock lock(mAvailableFrameMutex);
+ bool matchingFramesFound = false;
+ bool allTransactionsApplied = true;
+ for (auto& frame : mAvailableFrames) {
+ if (headFrameNumber != frame->getFrameNumber()) {
+ break;
+ }
+ matchingFramesFound = true;
+ allTransactionsApplied &= frame->transactionIsApplied();
+ }
+ if (matchingFramesFound && !allTransactionsApplied) {
+ mFlinger->signalLayerUpdate();
+ return outDirtyRegion;
+ }
}
status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
@@ -1368,6 +1548,15 @@
mFlinger->signalLayerUpdate();
}
+ if (!availableFramesEmpty) {
+ Mutex::Autolock lock(mAvailableFrameMutex);
+ auto frameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+ while (!mAvailableFrames.empty() &&
+ frameNumber == mAvailableFrames.front()->getFrameNumber()) {
+ mAvailableFrames.pop_front();
+ }
+ }
+
if (updateResult != NO_ERROR) {
// something happened!
recomputeVisibleRegions = true;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c1e5e9f..4ff9006 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -36,6 +36,8 @@
#include <private/gui/LayerState.h>
+#include <list>
+
#include "FrameTracker.h"
#include "Client.h"
#include "MonitoredProducer.h"
@@ -107,9 +109,17 @@
uint32_t layerStack;
uint8_t alpha;
uint8_t flags;
+ uint8_t mask;
uint8_t reserved[2];
int32_t sequence; // changes when visible regions can change
Transform transform;
+ bool modified;
+
+ // If set, defers this state update until the Layer identified by handle
+ // receives a frame with the given frameNumber
+ sp<IBinder> handle;
+ uint64_t frameNumber;
+
// the transparentRegion hint is a bit special, it's latched only
// when we receive a buffer -- this is because it's "content"
// dependent.
@@ -137,6 +147,7 @@
bool setFlags(uint8_t flags, uint8_t mask);
bool setCrop(const Rect& crop);
bool setLayerStack(uint32_t layerStack);
+ void deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber);
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
@@ -152,6 +163,7 @@
Rect computeBounds(const Region& activeTransparentRegion) const;
Rect computeBounds() const;
+ class Handle;
sp<IBinder> getHandle();
sp<IGraphicBufferProducer> getProducer() const;
const String8& getName() const;
@@ -343,6 +355,10 @@
virtual void onFrameReplaced(const BufferItem& item) override;
virtual void onSidebandStreamChanged() override;
+ // Move frames made available by item in to a list which will
+ // be signalled at the beginning of the next transaction
+ virtual void markSyncPointsAvailable(const BufferItem& item);
+
void commitTransaction();
// needsLinearFiltering - true if this surface's state requires filtering
@@ -362,6 +378,56 @@
// Temporary - Used only for LEGACY camera mode.
uint32_t getProducerStickyTransform() const;
+ // -----------------------------------------------------------------------
+
+ class SyncPoint
+ {
+ public:
+ SyncPoint(uint64_t frameNumber) : mFrameNumber(frameNumber),
+ mFrameIsAvailable(false), mTransactionIsApplied(false) {}
+
+ uint64_t getFrameNumber() const {
+ return mFrameNumber;
+ }
+
+ bool frameIsAvailable() const {
+ return mFrameIsAvailable;
+ }
+
+ void setFrameAvailable() {
+ mFrameIsAvailable = true;
+ }
+
+ bool transactionIsApplied() const {
+ return mTransactionIsApplied;
+ }
+
+ void setTransactionApplied() {
+ mTransactionIsApplied = true;
+ }
+
+ private:
+ const uint64_t mFrameNumber;
+ std::atomic<bool> mFrameIsAvailable;
+ std::atomic<bool> mTransactionIsApplied;
+ };
+
+ std::list<std::shared_ptr<SyncPoint>> mLocalSyncPoints;
+
+ // Guarded by mPendingStateMutex
+ std::list<std::shared_ptr<SyncPoint>> mRemoteSyncPoints;
+
+ void addSyncPoint(std::shared_ptr<SyncPoint> point);
+
+ void pushPendingState();
+ void popPendingState();
+ bool applyPendingStates();
+
+ Mutex mAvailableFrameMutex;
+ std::list<std::shared_ptr<SyncPoint>> mAvailableFrames;
+public:
+ void notifyAvailableFrames();
+private:
// -----------------------------------------------------------------------
@@ -378,6 +444,10 @@
State mDrawingState;
volatile int32_t mTransactionFlags;
+ // Accessed from main thread and binder threads
+ Mutex mPendingStateMutex;
+ Vector<State> mPendingStates;
+
// thread-safe
volatile int32_t mQueuedFrames;
volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 79ef92f..68b6b86 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -127,6 +127,10 @@
return mProducer->getConsumerName();
}
+uint64_t MonitoredProducer::getNextFrameNumber() const {
+ return mProducer->getNextFrameNumber();
+}
+
IBinder* MonitoredProducer::onAsBinder() {
return IInterface::asBinder(mProducer).get();
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index 3df6f0f..4d2ed6e 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -57,6 +57,7 @@
virtual status_t allowAllocation(bool allow);
virtual status_t setGenerationNumber(uint32_t generationNumber);
virtual String8 getConsumerName() const override;
+ virtual uint64_t getNextFrameNumber() const override;
virtual IBinder* onAsBinder();
private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 285b829..093ca12 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1326,6 +1326,11 @@
const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
const size_t count = currentLayers.size();
+ // Notify all layers of available frames
+ for (size_t i = 0; i < count; ++i) {
+ currentLayers[i]->notifyAvailableFrames();
+ }
+
/*
* Traversal of the children
* (perform the transaction for each of them if needed)
@@ -2280,6 +2285,11 @@
flags |= eTransactionNeeded|eTraversalNeeded;
}
}
+ if (what & layer_state_t::eDeferTransaction) {
+ layer->deferTransactionUntil(s.handle, s.frameNumber);
+ // We don't trigger a traversal here because if no other state is
+ // changed, we don't want this to cause any more work
+ }
}
return flags;
}