SurfaceFlinger: Shared timeline plumbing
Add plumbing to get shared timeline data from Surface Flinger to HWUI
and back.
Bug: 162890382
Bug: 162888881
Test: SF unit tests
Change-Id: Ifb76e6bf28d43c051e6c8ff568437ec9a106b865
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 2cc7c34..7e894b4 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -73,7 +73,8 @@
nsecs_t vsyncTimestamp;
PhysicalDisplayId vsyncDisplayId;
uint32_t vsyncCount;
- if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
+ int64_t vsyncId;
+ if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncId)) {
ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
}
@@ -116,11 +117,13 @@
nsecs_t vsyncTimestamp;
PhysicalDisplayId vsyncDisplayId;
uint32_t vsyncCount;
- if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
- ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", displayId=%s, count=%d", this,
- ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount);
+ int64_t vsyncId;
+ if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncId)) {
+ ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
+ ", displayId=%s, count=%d, vsyncId=%" PRId64,
+ this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount, vsyncId);
mWaitingForVsync = false;
- dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
+ dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncId);
}
return 1; // keep the callback
@@ -128,10 +131,11 @@
bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
PhysicalDisplayId* outDisplayId,
- uint32_t* outCount) {
+ uint32_t* outCount, int64_t* outVsyncId) {
bool gotVsync = false;
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
ssize_t n;
+ *outVsyncId = 0;
while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
ALOGV("dispatcher %p ~ Read %d events.", this, int(n));
for (ssize_t i = 0; i < n; i++) {
@@ -144,6 +148,7 @@
*outTimestamp = ev.header.timestamp;
*outDisplayId = ev.header.displayId;
*outCount = ev.vsync.count;
+ *outVsyncId = ev.vsync.vsyncId;
break;
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 0ac493d..8b65ea1 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1150,6 +1150,38 @@
return NO_ERROR;
}
+
+ virtual status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
+ int64_t frameTimelineVsyncId) {
+ Parcel data, reply;
+ status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (err != NO_ERROR) {
+ ALOGE("setFrameTimelineVsync: failed writing interface token: %s (%d)", strerror(-err),
+ -err);
+ return err;
+ }
+
+ err = data.writeStrongBinder(IInterface::asBinder(surface));
+ if (err != NO_ERROR) {
+ ALOGE("setFrameTimelineVsync: failed writing strong binder: %s (%d)", strerror(-err),
+ -err);
+ return err;
+ }
+
+ err = data.writeInt64(frameTimelineVsyncId);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameTimelineVsync: failed writing int64_t: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_VSYNC, data, &reply);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameTimelineVsync: failed to transact: %s (%d)", strerror(-err), err);
+ return err;
+ }
+
+ return reply.readInt32();
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -1950,6 +1982,33 @@
}
return NO_ERROR;
}
+ case SET_FRAME_TIMELINE_VSYNC: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> binder;
+ status_t err = data.readStrongBinder(&binder);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameTimelineVsync: failed to read strong binder: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+ sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder);
+ if (!surface) {
+ ALOGE("setFrameTimelineVsync: failed to cast to IGraphicBufferProducer: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+ int64_t frameTimelineVsyncId;
+ err = data.readInt64(&frameTimelineVsyncId);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameTimelineVsync: failed to read int64_t: %s (%d)", strerror(-err),
+ -err);
+ return err;
+ }
+
+ status_t result = setFrameTimelineVsync(surface, frameTimelineVsyncId);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index e45b3d1..9ce8442 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1207,6 +1207,9 @@
case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER:
res = dispatchGetLastQueuedBuffer(args);
break;
+ case NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC:
+ res = dispatchSetFrameTimelineVsync(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -1513,6 +1516,14 @@
return result;
}
+int Surface::dispatchSetFrameTimelineVsync(va_list args) {
+ ATRACE_CALL();
+ auto frameTimelineVsyncId = static_cast<int64_t>(va_arg(args, int64_t));
+
+ ALOGV("Surface::dispatchSetFrameTimelineVsync");
+ return composerService()->setFrameTimelineVsync(mGraphicBufferProducer, frameTimelineVsyncId);
+}
+
bool Surface::transformToDisplayInverse() {
return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index eb5b004..cf598ea 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -43,7 +43,8 @@
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
- virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
+ virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
+ int64_t vsyncId) = 0;
virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
bool connected) = 0;
virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
@@ -53,6 +54,6 @@
virtual void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) = 0;
bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
- uint32_t* outCount);
+ uint32_t* outCount, int64_t* outVsyncId);
};
} // namespace android
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 0d0d102..df3118f 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -73,6 +73,7 @@
uint32_t count;
nsecs_t expectedVSyncTimestamp __attribute__((aligned(8)));
nsecs_t deadlineTimestamp __attribute__((aligned(8)));
+ int64_t vsyncId;
};
struct Hotplug {
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e057b68..7c25b97 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -479,6 +479,13 @@
* for tests. Release the token by releasing the returned IBinder reference.
*/
virtual status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) = 0;
+
+ /*
+ * Sets the frame timeline vsync id received from choreographer that corresponds to next
+ * buffer submitted on that surface.
+ */
+ virtual status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
+ int64_t frameTimelineVsyncId) = 0;
};
// ----------------------------------------------------------------------------
@@ -538,6 +545,7 @@
SET_GAME_CONTENT_TYPE,
SET_FRAME_RATE,
ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
+ SET_FRAME_TIMELINE_VSYNC,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 55b4101..a68f2e7 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -265,6 +265,7 @@
int dispatchAddQueueInterceptor(va_list args);
int dispatchAddQueryInterceptor(va_list args);
int dispatchGetLastQueuedBuffer(va_list args);
+ int dispatchSetFrameTimelineVsync(va_list args);
bool transformToDisplayInverse();
protected:
diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp
index 4bcb795..7210910 100644
--- a/libs/gui/tests/DisplayEventStructLayout_test.cpp
+++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp
@@ -33,6 +33,8 @@
CHECK_OFFSET(DisplayEventReceiver::Event::VSync, count, 0);
CHECK_OFFSET(DisplayEventReceiver::Event::VSync, expectedVSyncTimestamp, 8);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, deadlineTimestamp, 16);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncId, 24);
CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index aedba2a..8d69997 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -868,7 +868,14 @@
return NO_ERROR;
}
- status_t acquireFrameRateFlexibilityToken(sp<IBinder>* /*outToken*/) { return NO_ERROR; }
+ status_t acquireFrameRateFlexibilityToken(sp<IBinder>* /*outToken*/) override {
+ return NO_ERROR;
+ }
+
+ status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& /*surface*/,
+ int64_t /*frameTimelineVsyncId*/) override {
+ return NO_ERROR;
+ }
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index ff1b5e6..b7c5b2a 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -128,11 +128,14 @@
static Choreographer* getForThread();
virtual ~Choreographer() override EXCLUDES(gChoreographers.lock);
+ int64_t getVsyncId() const;
+
private:
Choreographer(const Choreographer&) = delete;
- void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
+ void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
+ int64_t vsyncId) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId,
nsecs_t vsyncPeriod) override;
@@ -146,6 +149,7 @@
std::vector<RefreshRateCallback> mRefreshRateCallbacks;
nsecs_t mLatestVsyncPeriod = -1;
+ int64_t mLastVsyncId = -1;
const sp<Looper> mLooper;
const std::thread::id mThreadId;
@@ -350,7 +354,7 @@
// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
// the internal display implicitly.
-void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) {
+void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t, int64_t vsyncId) {
std::vector<FrameCallback> callbacks{};
{
std::lock_guard<std::mutex> _l{mLock};
@@ -360,6 +364,7 @@
mFrameCallbacks.pop();
}
}
+ mLastVsyncId = vsyncId;
for (const auto& cb : callbacks) {
if (cb.callback64 != nullptr) {
cb.callback64(timestamp, cb.data);
@@ -404,6 +409,10 @@
}
}
+int64_t Choreographer::getVsyncId() const {
+ return mLastVsyncId;
+}
+
} // namespace android
using namespace android;
@@ -411,6 +420,11 @@
return reinterpret_cast<Choreographer*>(choreographer);
}
+static inline const Choreographer* AChoreographer_to_Choreographer(
+ const AChoreographer* choreographer) {
+ return reinterpret_cast<const Choreographer*>(choreographer);
+}
+
// Glue for private C api
namespace android {
void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) {
@@ -468,15 +482,14 @@
return AChoreographer_unregisterRefreshRateCallback(choreographer, callback, data);
}
+int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer) {
+ return AChoreographer_to_Choreographer(choreographer)->getVsyncId();
+}
+
} // namespace android
/* Glue for the NDK interface */
-static inline const Choreographer* AChoreographer_to_Choreographer(
- const AChoreographer* choreographer) {
- return reinterpret_cast<const Choreographer*>(choreographer);
-}
-
static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) {
return reinterpret_cast<AChoreographer*>(choreographer);
}
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
index 2164930..1d57c15 100644
--- a/libs/nativedisplay/include-private/private/android/choreographer.h
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -29,6 +29,12 @@
// for consumption by callbacks.
void AChoreographer_signalRefreshRateCallbacks(int64_t vsyncPeriod);
+// Returns the vsync id of the last frame callback. Client are expected to call
+// this function from their frame callback function to get the vsyncId and pass
+// it together with a buffer or transaction to the Surface Composer. Calling
+// this function from anywhere else will return an undefined value.
+int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer);
+
// Trampoline functions allowing libandroid.so to define the NDK symbols without including
// the entirety of libnativedisplay as a whole static lib. As libnativedisplay
// maintains global state, libnativedisplay can never be directly statically
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index fc59431..5ed2e49 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -29,6 +29,7 @@
android::AChoreographer_routeRegisterRefreshRateCallback*;
android::AChoreographer_routeUnregisterRefreshRateCallback*;
android::AChoreographer_signalRefreshRateCallbacks*;
+ android::AChoreographer_getVsyncId*;
android::ADisplay_acquirePhysicalDisplays*;
android::ADisplay_release*;
android::ADisplay_getMaxSupportedFps*;
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index b78fc5d..138e08f 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -255,6 +255,7 @@
NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */
NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */
NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */
+ NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC = 48, /* private */
// clang-format on
};
@@ -1022,6 +1023,12 @@
(int)compatibility);
}
+static inline int native_window_set_frame_timeline_vsync(struct ANativeWindow* window,
+ int64_t frameTimelineVsyncId) {
+ return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC,
+ frameTimelineVsyncId);
+}
+
// ------------------------------------------------------------------------------------------------
// Candidates for APEX visibility
// These functions are planned to be made stable for APEX modules, but have not