BlastBufferQueue: Add support for auto refresh
When BQ is in shared bufer mode, the client can request
the consumer to aquire frames as fast as possible before
waiting for a frame to be available. To support this for
BLAST, pass the state via a transaction.
Fixes: 168506187
Test: atest SurfaceViewBufferTests
Change-Id: I25ddd98671a08e56798612b7e5dc72095b2c4b7b
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 6db6112..e6aa02a 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -289,6 +289,11 @@
t->setDesiredPresentTime(bufferItem.mTimestamp);
t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber);
+ if (mAutoRefresh != bufferItem.mAutoRefresh) {
+ t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh);
+ mAutoRefresh = bufferItem.mAutoRefresh;
+ }
+
if (applyTransaction) {
t->apply();
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 90999fa..7d2c7b8 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -61,7 +61,9 @@
frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT),
shouldBeSeamless(true),
fixedTransformHint(ui::Transform::ROT_INVALID),
- frameNumber(0) {
+ frameNumber(0),
+ frameTimelineVsyncId(ISurfaceComposer::INVALID_VSYNC_ID),
+ autoRefresh(false) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
hdrMetadata.validTypes = 0;
@@ -149,6 +151,7 @@
SAFE_PARCEL(output.writeUint32, fixedTransformHint);
SAFE_PARCEL(output.writeUint64, frameNumber);
SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId);
+ SAFE_PARCEL(output.writeBool, autoRefresh);
SAFE_PARCEL(output.writeUint32, blurRegions.size());
for (auto region : blurRegions) {
@@ -269,6 +272,7 @@
fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
SAFE_PARCEL(input.readUint64, &frameNumber);
SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId);
+ SAFE_PARCEL(input.readBool, &autoRefresh);
uint32_t numRegions = 0;
SAFE_PARCEL(input.readUint32, &numRegions);
@@ -534,6 +538,20 @@
what |= eFrameNumberChanged;
frameNumber = other.frameNumber;
}
+ if (other.what & eFrameTimelineVsyncChanged) {
+ // When merging vsync Ids we take the oldest valid one
+ if (frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID &&
+ other.frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) {
+ frameTimelineVsyncId = std::max(frameTimelineVsyncId, other.frameTimelineVsyncId);
+ } else if (frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) {
+ frameTimelineVsyncId = other.frameTimelineVsyncId;
+ }
+ what |= eFrameTimelineVsyncChanged;
+ }
+ if (other.what & eAutoRefreshChanged) {
+ what |= eAutoRefreshChanged;
+ autoRefresh = other.autoRefresh;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIu64 " what=0x%" PRIu64,
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index a822598..47a08ab 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1527,6 +1527,19 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAutoRefresh(
+ const sp<SurfaceControl>& sc, bool autoRefresh) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eAutoRefreshChanged;
+ s->autoRefresh = autoRefresh;
+ return *this;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 42427c0..9fb7d6f 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -139,6 +139,10 @@
// If set to true, the next queue buffer will wait until the shadow queue has been processed by
// the adapter.
bool mFlushShadowQueue = false;
+ // Last requested auto refresh state set by the producer. The state indicates that the consumer
+ // should acquire the next frame as soon as it can and not wait for a frame to become available.
+ // This is only relevant for shared buffer mode.
+ bool mAutoRefresh GUARDED_BY(mMutex) = false;
};
} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index d9f2806..f1c5d67 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -130,6 +130,7 @@
eFrameNumberChanged = 0x400'00000000,
eFrameTimelineVsyncChanged = 0x800'00000000,
eBlurRegionsChanged = 0x1000'00000000,
+ eAutoRefreshChanged = 0x2000'00000000,
};
layer_state_t();
@@ -234,6 +235,11 @@
uint64_t frameNumber;
int64_t frameTimelineVsyncId;
+
+ // Indicates that the consumer should acquire the next frame as soon as it
+ // can and not wait for a frame to become available. This is only relevant
+ // in shared buffer mode.
+ bool autoRefresh;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 6289c6a..2eb97f2 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -541,6 +541,11 @@
Transaction& setFrameTimelineVsync(const sp<SurfaceControl>& sc,
int64_t frameTimelineVsyncId);
+ // Indicates that the consumer should acquire the next frame as soon as it
+ // can and not wait for a frame to become available. This is only relevant
+ // in shared buffer mode.
+ Transaction& setAutoRefresh(const sp<SurfaceControl>& sc, bool autoRefresh);
+
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index deaf846..63dfe5f 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -178,13 +178,17 @@
/// the mStateLock.
ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
+ bool getAutoRefresh() const { return mAutoRefresh; }
+ bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
+
+ std::atomic<bool> mAutoRefresh{false};
+ std::atomic<bool> mSidebandStreamChanged{false};
+
private:
virtual bool fenceHasSignaled() const = 0;
virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0;
virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0;
- virtual bool getAutoRefresh() const = 0;
- virtual bool getSidebandStreamChanged() const = 0;
// Latch sideband stream and returns true if the dirty region should be updated.
virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 71b05fd..dc99986 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -196,14 +196,6 @@
return frameNumber;
}
-bool BufferQueueLayer::getAutoRefresh() const {
- return mAutoRefresh;
-}
-
-bool BufferQueueLayer::getSidebandStreamChanged() const {
- return mSidebandStreamChanged;
-}
-
bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
// We need to update the sideband stream if the layer has both a buffer and a sideband stream.
const bool updateSidebandStream = hasFrameUpdate() && mSidebandStream.get();
@@ -265,8 +257,10 @@
const uint64_t maxFrameNumberToAcquire =
std::min(mLastFrameNumberReceived.load(), lastSignaledFrameNumber);
- status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh,
+ bool autoRefresh;
+ status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &autoRefresh,
&queuedBuffer, maxFrameNumberToAcquire);
+ mAutoRefresh = autoRefresh;
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index fb8a0c2..b45900e 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -90,9 +90,6 @@
private:
uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
- bool getAutoRefresh() const override;
- bool getSidebandStreamChanged() const override;
-
bool latchSidebandStream(bool& recomputeVisibleRegions) override;
void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
@@ -140,11 +137,8 @@
std::vector<BufferData> mQueueItems;
std::atomic<uint64_t> mLastFrameNumberReceived{0};
- bool mAutoRefresh{false};
-
// thread-safe
std::atomic<int32_t> mQueuedFrames{0};
- std::atomic<bool> mSidebandStreamChanged{false};
sp<ContentsChangedListener> mContentsChangedListener;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 234b6e2..963e541 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -482,13 +482,10 @@
return mCurrentState.frameNumber;
}
-bool BufferStateLayer::getAutoRefresh() const {
- // TODO(marissaw): support shared buffer mode
- return false;
-}
-
-bool BufferStateLayer::getSidebandStreamChanged() const {
- return mSidebandStreamChanged.load();
+void BufferStateLayer::setAutoRefresh(bool autoRefresh) {
+ if (!mAutoRefresh.exchange(autoRefresh)) {
+ mFlinger->signalLayerUpdate();
+ }
}
bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 104a13b..42be62a 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -100,6 +100,7 @@
Rect getBufferSize(const State& s) const override;
FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
Layer::RoundedCornerState getRoundedCornerState() const override;
+ void setAutoRefresh(bool autoRefresh) override;
// -----------------------------------------------------------------------
@@ -123,9 +124,6 @@
uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
- bool getAutoRefresh() const override;
- bool getSidebandStreamChanged() const override;
-
bool latchSidebandStream(bool& recomputeVisibleRegions) override;
bool hasFrameUpdate() const override;
@@ -149,8 +147,6 @@
std::unique_ptr<renderengine::Image> mTextureImage;
- std::atomic<bool> mSidebandStreamChanged{false};
-
mutable uint64_t mFrameNumber{0};
uint64_t mFrameCounter{0};
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 1a784aa..8d67ce5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -444,6 +444,7 @@
virtual bool setColorSpaceAgnostic(const bool agnostic);
virtual bool setFrameRateSelectionPriority(int32_t priority);
virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
+ virtual void setAutoRefresh(bool /* autoRefresh */) {}
// If the variable is not set on the layer, it traverses up the tree to inherit the frame
// rate priority from its parent.
virtual int32_t getFrameRateSelectionPriority() const;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 91f050c..4e398d3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3796,6 +3796,9 @@
flags |= eTraversalNeeded | eTransformHintUpdateNeeded;
}
}
+ if (what & layer_state_t::eAutoRefreshChanged) {
+ layer->setAutoRefresh(s.autoRefresh);
+ }
// This has to happen after we reparent children because when we reparent to null we remove
// child layers from current state and remove its relative z. If the children are reparented in
// the same transaction, then we have to make sure we reparent the children first so we do not