Shared timeline plumbing
Add plumbing to get shared timeline data from Surface Flinger to HWUI
and back.
Bug: 162890382
Bug: 162888881
Bug: 162890407
Test: manual using ALOG messages in SF
Change-Id: I85c5eb56d2fa933889518854e7b79b1e65e29af3
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index 0698775..30ce537 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -22,6 +22,7 @@
const std::string FrameInfoNames[] = {
"Flags",
+ "FrameTimelineVsyncId",
"IntendedVsync",
"Vsync",
"OldestInputEvent",
@@ -44,7 +45,7 @@
static_cast<int>(FrameInfoIndex::NumIndexes),
"size mismatch: FrameInfoNames doesn't match the enum!");
-static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 17,
+static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 18,
"Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
void FrameInfo::importUiThreadInfo(int64_t* info) {
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index dc30617..f5bfedd 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -27,10 +27,11 @@
namespace android {
namespace uirenderer {
-#define UI_THREAD_FRAME_INFO_SIZE 9
+#define UI_THREAD_FRAME_INFO_SIZE 10
enum class FrameInfoIndex {
Flags = 0,
+ FrameTimelineVsyncId,
IntendedVsync,
Vsync,
OldestInputEvent,
@@ -71,11 +72,15 @@
class UiFrameInfoBuilder {
public:
+ static constexpr int64_t INVALID_VSYNC_ID = -1;
+
explicit UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) {
memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
+ set(FrameInfoIndex::FrameTimelineVsyncId) = INVALID_VSYNC_ID;
}
- UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync) {
+ UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync, int64_t vsyncId) {
+ set(FrameInfoIndex::FrameTimelineVsyncId) = vsyncId;
set(FrameInfoIndex::Vsync) = vsyncTime;
set(FrameInfoIndex::IntendedVsync) = intendedVsync;
// Pretend the other fields are all at vsync, too, so that naive
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index e817ca7..c89463b 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -514,7 +514,7 @@
proxy.setLightGeometry((Vector3){0, 0, 0}, 0);
nsecs_t vsync = systemTime(SYSTEM_TIME_MONOTONIC);
UiFrameInfoBuilder(proxy.frameInfo())
- .setVsync(vsync, vsync)
+ .setVsync(vsync, vsync, UiFrameInfoBuilder::INVALID_VSYNC_ID)
.addFlag(FrameInfoFlags::SurfaceCanvas);
proxy.syncAndDrawFrame();
}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 13d544c..c7560b2 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -484,6 +484,14 @@
waitOnFences();
+ if (mNativeSurface) {
+ // TODO(b/165985262): measure performance impact
+ if (const auto vsyncId = mCurrentFrameInfo->get(FrameInfoIndex::FrameTimelineVsyncId);
+ vsyncId != UiFrameInfoBuilder::INVALID_VSYNC_ID) {
+ native_window_set_frame_timeline_vsync(mNativeSurface->getNativeWindow(), vsyncId);
+ }
+ }
+
bool requireSwap = false;
int error = OK;
bool didSwap =
@@ -617,8 +625,11 @@
ATRACE_CALL();
nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
+ int64_t vsyncId = mRenderThread.timeLord().lastVsyncId();
int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
- UiFrameInfoBuilder(frameInfo).addFlag(FrameInfoFlags::RTAnimation).setVsync(vsync, vsync);
+ UiFrameInfoBuilder(frameInfo)
+ .addFlag(FrameInfoFlags::RTAnimation)
+ .setVsync(vsync, vsync, vsyncId);
TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
prepareTree(info, frameInfo, systemTime(SYSTEM_TIME_MONOTONIC), node);
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 1e59338..1ea595d 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -128,7 +128,9 @@
bool DrawFrameTask::syncFrameState(TreeInfo& info) {
ATRACE_CALL();
int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
- mRenderThread->timeLord().vsyncReceived(vsync);
+ int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)];
+ int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)];
+ mRenderThread->timeLord().vsyncReceived(vsync, intendedVsync, vsyncId);
bool canDraw = mContext->makeCurrent();
mContext->unpinImages();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 4dcbc44..9371656 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -51,8 +51,10 @@
void RenderThread::frameCallback(int64_t frameTimeNanos, void* data) {
RenderThread* rt = reinterpret_cast<RenderThread*>(data);
+ int64_t vsyncId = AChoreographer_getVsyncId(rt->mChoreographer);
rt->mVsyncRequested = false;
- if (rt->timeLord().vsyncReceived(frameTimeNanos) && !rt->mFrameCallbackTaskPending) {
+ if (rt->timeLord().vsyncReceived(frameTimeNanos, frameTimeNanos, vsyncId) &&
+ !rt->mFrameCallbackTaskPending) {
ATRACE_NAME("queue mFrameCallbackTask");
rt->mFrameCallbackTaskPending = true;
nsecs_t runAt = (frameTimeNanos + rt->mDispatchFrameDelay);
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index d7dc00b..4fbb0716 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -19,8 +19,8 @@
#include <GrDirectContext.h>
#include <SkBitmap.h>
-#include <apex/choreographer.h>
#include <cutils/compiler.h>
+#include <private/android/choreographer.h>
#include <thread/ThreadBase.h>
#include <utils/Looper.h>
#include <utils/Thread.h>
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
index 784068f..7dc36c4 100644
--- a/libs/hwui/renderthread/TimeLord.cpp
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -19,9 +19,17 @@
namespace uirenderer {
namespace renderthread {
-TimeLord::TimeLord() : mFrameIntervalNanos(milliseconds_to_nanoseconds(16)), mFrameTimeNanos(0) {}
+TimeLord::TimeLord() : mFrameIntervalNanos(milliseconds_to_nanoseconds(16)),
+ mFrameTimeNanos(0),
+ mFrameIntendedTimeNanos(0),
+ mFrameVsyncId(-1) {}
-bool TimeLord::vsyncReceived(nsecs_t vsync) {
+bool TimeLord::vsyncReceived(nsecs_t vsync, nsecs_t intendedVsync, int64_t vsyncId) {
+ if (intendedVsync > mFrameIntendedTimeNanos) {
+ mFrameIntendedTimeNanos = intendedVsync;
+ mFrameVsyncId = vsyncId;
+ }
+
if (vsync > mFrameTimeNanos) {
mFrameTimeNanos = vsync;
return true;
@@ -36,6 +44,8 @@
if (jitterNanos >= mFrameIntervalNanos) {
nsecs_t lastFrameOffset = jitterNanos % mFrameIntervalNanos;
mFrameTimeNanos = now - lastFrameOffset;
+ // mFrameVsyncId is not adjusted here as we still want to send
+ // the vsync id that started this frame to the Surface Composer
}
return mFrameTimeNanos;
}
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
index 68a0f7f..23c1e51 100644
--- a/libs/hwui/renderthread/TimeLord.h
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -32,9 +32,10 @@
nsecs_t frameIntervalNanos() const { return mFrameIntervalNanos; }
// returns true if the vsync is newer, false if it was rejected for staleness
- bool vsyncReceived(nsecs_t vsync);
+ bool vsyncReceived(nsecs_t vsync, nsecs_t indendedVsync, int64_t vsyncId);
nsecs_t latestVsync() { return mFrameTimeNanos; }
nsecs_t computeFrameTimeNanos();
+ int64_t lastVsyncId() const { return mFrameVsyncId; }
private:
friend class RenderThread;
@@ -44,6 +45,8 @@
nsecs_t mFrameIntervalNanos;
nsecs_t mFrameTimeNanos;
+ nsecs_t mFrameIntendedTimeNanos;
+ int64_t mFrameVsyncId;
};
} /* namespace renderthread */
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 801cb7d..ed89c59 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -145,7 +145,8 @@
for (int i = 0; i < warmupFrameCount; i++) {
testContext.waitForVsync();
nsecs_t vsync = systemTime(SYSTEM_TIME_MONOTONIC);
- UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
+ UiFrameInfoBuilder(proxy->frameInfo())
+ .setVsync(vsync, vsync, UiFrameInfoBuilder::INVALID_VSYNC_ID);
proxy->syncAndDrawFrame();
}
@@ -165,7 +166,8 @@
nsecs_t vsync = systemTime(SYSTEM_TIME_MONOTONIC);
{
ATRACE_NAME("UI-Draw Frame");
- UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
+ UiFrameInfoBuilder(proxy->frameInfo())
+ .setVsync(vsync, vsync, UiFrameInfoBuilder::INVALID_VSYNC_ID);
scene->doFrame(i);
proxy->syncAndDrawFrame();
}