Add GPU completion to FrameMetrics (2/3)
- Add SurfaceStatsCallback to TransactionCompletedListener
- Register a callback in RenderProxy to be called when we have
surface stats from SF via the BLAST callback.
- Instead of finishing a frame for frame metrics reporting
immediately, wait until BLAST callback fires, note GPU completion
time and finish frame.
- Expose GPU_COMPLETION in FrameMetrics
- Modify TOTAL_DURATION to also include GPU_COMPLETION
Test: FrameMetricsListenerTest
Fixes: 171046219
Change-Id: If4b63c6a4c49c9ce2f31410d7f33541b0e6bf594
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 27fb2a8..d41da9b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -194,6 +194,25 @@
}
}
+void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie,
+ sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mSurfaceStatsListeners.insert({surfaceControl->getHandle(),
+ SurfaceStatsCallbackEntry(context, cookie, listener)});
+}
+
+void TransactionCompletedListener::removeSurfaceStatsListener(void* context, void* cookie) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ for (auto it = mSurfaceStatsListeners.begin(); it != mSurfaceStatsListeners.end();) {
+ auto [itContext, itCookie, itListener] = it->second;
+ if (itContext == context && itCookie == cookie) {
+ it = mSurfaceStatsListeners.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
void TransactionCompletedListener::addSurfaceControlToCallbacks(
const sp<SurfaceControl>& surfaceControl,
const std::unordered_set<CallbackId>& callbackIds) {
@@ -210,6 +229,7 @@
void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
+ std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry> surfaceListeners;
{
std::lock_guard<std::mutex> lock(mMutex);
@@ -226,6 +246,7 @@
*/
callbacksMap = mCallbacks;
jankListenersMap = mJankListeners;
+ surfaceListeners = mSurfaceStatsListeners;
for (const auto& transactionStats : listenerStats.transactionStats) {
for (auto& callbackId : transactionStats.callbackIds) {
mCallbacks.erase(callbackId);
@@ -259,9 +280,16 @@
surfaceControlStats);
}
for (const auto& surfaceStats : transactionStats.surfaceStats) {
+ auto listenerRange = surfaceListeners.equal_range(surfaceStats.surfaceControl);
+ for (auto it = listenerRange.first; it != listenerRange.second; it++) {
+ auto entry = it->second;
+ entry.callback(entry.context, transactionStats.latchTime,
+ transactionStats.presentFence, surfaceStats);
+ }
+
if (surfaceStats.jankData.empty()) continue;
- for (auto it = jankListenersMap.find(surfaceStats.surfaceControl);
- it != jankListenersMap.end(); it++) {
+ auto jankRange = jankListenersMap.equal_range(surfaceStats.surfaceControl);
+ for (auto it = jankRange.first; it != jankRange.second; it++) {
it->second->onJankDataAvailable(surfaceStats.jankData);
}
}