Loading services/surfaceflinger/BufferLayer.h +1 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ #include "BufferLayerConsumer.h" #include "Client.h" #include "DisplayHardware/HWComposer.h" #include "FrameTimeline.h" #include "FrameTracker.h" #include "Layer.h" #include "LayerVector.h" Loading services/surfaceflinger/BufferQueueLayer.cpp +52 −22 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ #include "TimeStats/TimeStats.h" namespace android { using PresentState = frametimeline::SurfaceFrame::PresentState; BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {} Loading Loading @@ -109,7 +110,7 @@ bool BufferQueueLayer::shouldPresentNow(nsecs_t expectedPresentTime) const { Mutex::Autolock lock(mQueueItemLock); const int64_t addedTime = mQueueItems[0].mTimestamp; const int64_t addedTime = mQueueItems[0].item.mTimestamp; // Ignore timestamps more than a second in the future const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1)); Loading @@ -136,7 +137,7 @@ bool BufferQueueLayer::fenceHasSignaled() const { } Mutex::Autolock lock(mQueueItemLock); if (mQueueItems[0].mIsDroppable) { if (mQueueItems[0].item.mIsDroppable) { // Even though this buffer's fence may not have signaled yet, it could // be replaced by another buffer before it has a chance to, which means // that it's possible to get into a situation where a buffer is never Loading @@ -144,7 +145,7 @@ bool BufferQueueLayer::fenceHasSignaled() const { return true; } const bool fenceSignaled = mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; mQueueItems[0].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; if (!fenceSignaled) { mFlinger->mTimeStats->incrementLatchSkipped(getSequence(), TimeStats::LatchSkipReason::LateAcquire); Loading @@ -159,12 +160,12 @@ bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) co } Mutex::Autolock lock(mQueueItemLock); return mQueueItems[0].mTimestamp <= expectedPresentTime; return mQueueItems[0].item.mTimestamp <= expectedPresentTime; } uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const { Mutex::Autolock lock(mQueueItemLock); uint64_t frameNumber = mQueueItems[0].mFrameNumber; uint64_t frameNumber = mQueueItems[0].item.mFrameNumber; // The head of the queue will be dropped if there are signaled and timely frames behind it if (isRemovedFromCurrentState()) { Loading @@ -173,23 +174,23 @@ uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const { for (int i = 1; i < mQueueItems.size(); i++) { const bool fenceSignaled = mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; if (!fenceSignaled) { break; } // We don't drop frames without explicit timestamps if (mQueueItems[i].mIsAutoTimestamp) { if (mQueueItems[i].item.mIsAutoTimestamp) { break; } const nsecs_t desiredPresent = mQueueItems[i].mTimestamp; const nsecs_t desiredPresent = mQueueItems[i].item.mTimestamp; if (desiredPresent < expectedPresentTime - BufferQueueConsumer::MAX_REASONABLE_NSEC || desiredPresent > expectedPresentTime) { break; } frameNumber = mQueueItems[i].mFrameNumber; frameNumber = mQueueItems[i].item.mFrameNumber; } return frameNumber; Loading Loading @@ -254,11 +255,11 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t Mutex::Autolock lock(mQueueItemLock); for (int i = 0; i < mQueueItems.size(); i++) { bool fenceSignaled = mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; if (!fenceSignaled) { break; } lastSignaledFrameNumber = mQueueItems[i].mFrameNumber; lastSignaledFrameNumber = mQueueItems[i].item.mFrameNumber; } } const uint64_t maxFrameNumberToAcquire = Loading @@ -276,9 +277,13 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // and return early if (queuedBuffer) { Mutex::Autolock lock(mQueueItemLock); mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].mFrameNumber); mQueueItems.removeAt(0); mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); if (mQueueItems[0].surfaceFrame) { mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame), PresentState::Dropped); } mQueueItems.erase(mQueueItems.begin()); mQueuedFrames--; } return BAD_VALUE; Loading @@ -289,6 +294,12 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // early. if (queuedBuffer) { Mutex::Autolock lock(mQueueItemLock); for (auto& [item, surfaceFrame] : mQueueItems) { if (surfaceFrame) { mFlinger->mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame), PresentState::Dropped); } } mQueueItems.clear(); mQueuedFrames = 0; mFlinger->mTimeStats->onDestroy(layerId); Loading @@ -312,19 +323,29 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // Remove any stale buffers that have been dropped during // updateTexImage while (mQueueItems[0].mFrameNumber != currentFrameNumber) { mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].mFrameNumber); mQueueItems.removeAt(0); while (mQueueItems[0].item.mFrameNumber != currentFrameNumber) { mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); if (mQueueItems[0].surfaceFrame) { mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame), PresentState::Dropped); } mQueueItems.erase(mQueueItems.begin()); mQueuedFrames--; } uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId(); uint64_t bufferID = mQueueItems[0].item.mGraphicBuffer->getId(); mFlinger->mTimeStats->setLatchTime(layerId, currentFrameNumber, latchTime); mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, currentFrameNumber, latchTime, FrameTracer::FrameEvent::LATCH); mQueueItems.removeAt(0); if (mQueueItems[0].surfaceFrame) { mQueueItems[0].surfaceFrame->setActualEndTime( mQueueItems[0].item.mFenceTime->getSignalTime()); mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame), PresentState::Presented); } mQueueItems.erase(mQueueItems.begin()); } // Decrement the queued-frames count. Signal another event if we Loading Loading @@ -416,7 +437,11 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { } } mQueueItems.push_back(item); auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems.push_back({item, std::move(surfaceFrame)}); mQueuedFrames++; // Wake up any pending callbacks Loading Loading @@ -449,7 +474,12 @@ void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { ALOGE("Can't replace a frame on an empty queue"); return; } mQueueItems.editItemAt(mQueueItems.size() - 1) = item; auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems[mQueueItems.size() - 1].item = item; mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame); // Wake up any pending callbacks mLastFrameNumberReceived = item.mFrameNumber; Loading services/surfaceflinger/BufferQueueLayer.h +12 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,10 @@ namespace android { namespace frametimeline { class SurfaceFrame; } /* * A new BufferQueue and a new BufferLayerConsumer are created when the * BufferLayer is first referenced. Loading Loading @@ -125,7 +129,14 @@ private: // Local copy of the queued contents of the incoming BufferQueue mutable Mutex mQueueItemLock; Condition mQueueItemCondition; Vector<BufferItem> mQueueItems; struct BufferData { BufferData(BufferItem item, std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame) : item(item), surfaceFrame(std::move(surfaceFrame)) {} BufferItem item; std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame; }; std::vector<BufferData> mQueueItems; std::atomic<uint64_t> mLastFrameNumberReceived{0}; bool mAutoRefresh{false}; Loading services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +29 −4 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "FrameTimeline.h" #include <android-base/stringprintf.h> #include <utils/Trace.h> #include <cinttypes> namespace android::frametimeline::impl { Loading @@ -27,6 +28,7 @@ namespace android::frametimeline::impl { using base::StringAppendF; int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); const int64_t assignedToken = mCurrentToken++; mPredictions[assignedToken] = predictions; Loading Loading @@ -88,18 +90,34 @@ TimelineItem SurfaceFrame::getActuals() { return mActuals; } void SurfaceFrame::setActuals(frametimeline::TimelineItem&& actuals) { nsecs_t SurfaceFrame::getActualQueueTime() { std::lock_guard<std::mutex> lock(mMutex); mActuals = actuals; return mActualQueueTime; } void SurfaceFrame::setPresentTime(nsecs_t presentTime) { void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) { std::lock_guard<std::mutex> lock(mMutex); mActuals.startTime = actualStartTime; } void SurfaceFrame::setActualQueueTime(nsecs_t actualQueueTime) { std::lock_guard<std::mutex> lock(mMutex); mActualQueueTime = actualQueueTime; } void SurfaceFrame::setActualEndTime(nsecs_t actualEndTime) { std::lock_guard<std::mutex> lock(mMutex); mActuals.endTime = actualEndTime; } void SurfaceFrame::setActualPresentTime(nsecs_t presentTime) { std::lock_guard<std::mutex> lock(mMutex); mActuals.presentTime = presentTime; } void SurfaceFrame::dump(std::string& result) { std::lock_guard<std::mutex> lock(mMutex); StringAppendF(&result, "Present State : %d\n", static_cast<int>(mPresentState)); StringAppendF(&result, "Prediction State : %d\n", static_cast<int>(mPredictionState)); StringAppendF(&result, "Predicted Start Time : %" PRId64 "\n", mPredictions.startTime); StringAppendF(&result, "Actual Start Time : %" PRId64 "\n", mActuals.startTime); StringAppendF(&result, "Actual Queue Time : %" PRId64 "\n", mActualQueueTime); Loading @@ -120,6 +138,7 @@ FrameTimeline::DisplayFrame::DisplayFrame() std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken( const std::string& layerName, std::optional<int64_t> token) { ATRACE_CALL(); if (!token) { return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::None, TimelineItem()); Loading @@ -136,6 +155,7 @@ std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfa void FrameTimeline::addSurfaceFrame( std::unique_ptr<android::frametimeline::SurfaceFrame> surfaceFrame, SurfaceFrame::PresentState state) { ATRACE_CALL(); surfaceFrame->setPresentState(state); std::unique_ptr<impl::SurfaceFrame> implSurfaceFrame( static_cast<impl::SurfaceFrame*>(surfaceFrame.release())); Loading @@ -144,18 +164,21 @@ void FrameTimeline::addSurfaceFrame( } void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) { ATRACE_CALL(); const std::optional<TimelineItem> prediction = mTokenManager.getPredictionsForToken(token); std::lock_guard<std::mutex> lock(mMutex); if (!prediction) { mCurrentDisplayFrame->predictionState = PredictionState::Expired; } else { mCurrentDisplayFrame->surfaceFlingerPredictions = *prediction; mCurrentDisplayFrame->predictionState = PredictionState::Valid; } mCurrentDisplayFrame->surfaceFlingerActuals.startTime = wakeUpTime; } void FrameTimeline::setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence) { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); mCurrentDisplayFrame->surfaceFlingerActuals.endTime = sfPresentTime; mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame)); Loading @@ -179,7 +202,7 @@ void FrameTimeline::flushPendingPresentFences() { for (auto& surfaceFrame : displayFrame->surfaceFrames) { if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) { // Only presented SurfaceFrames need to be updated surfaceFrame->setPresentTime(signalTime); surfaceFrame->setActualPresentTime(signalTime); } } } Loading @@ -204,6 +227,8 @@ void FrameTimeline::dump(std::string& result) { StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size()); for (const auto& displayFrame : mDisplayFrames) { StringAppendF(&result, "---Display Frame---\n"); StringAppendF(&result, "Prediction State : %d\n", static_cast<int>(displayFrame->predictionState)); StringAppendF(&result, "Predicted SF wake time : %" PRId64 "\n", displayFrame->surfaceFlingerPredictions.startTime); StringAppendF(&result, "Actual SF wake time : %" PRId64 "\n", Loading services/surfaceflinger/FrameTimeline/FrameTimeline.h +18 −12 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ public: // Generates a token for the given set of predictions. Stores the predictions for 120ms and // destroys it later. virtual int64_t generateTokenForPredictions(TimelineItem&& prediction); virtual int64_t generateTokenForPredictions(TimelineItem&& prediction) = 0; }; enum class PredictionState { Loading @@ -76,15 +76,18 @@ public: virtual TimelineItem getPredictions() = 0; virtual TimelineItem getActuals() = 0; virtual nsecs_t getActualQueueTime() = 0; virtual PresentState getPresentState() = 0; virtual PredictionState getPredictionState() = 0; virtual void setPresentState(PresentState state) = 0; virtual void setActuals(TimelineItem&& actuals) = 0; // There is no prediction for Queue time and it is not a part of TimelineItem. Set it // separately. // Actual timestamps of the app are set individually at different functions. // Start time (if the app provides) and Queue time are accessible after queueing the frame, // whereas End time is available only during latch. virtual void setActualStartTime(nsecs_t actualStartTime) = 0; virtual void setActualQueueTime(nsecs_t actualQueueTime) = 0; virtual void setActualEndTime(nsecs_t actualEndTime) = 0; }; /* Loading @@ -94,7 +97,7 @@ public: class FrameTimeline { public: virtual ~FrameTimeline() = default; virtual TokenManager& getTokenManager() = 0; virtual TokenManager* getTokenManager() = 0; // Create a new surface frame, set the predictions based on a token and return it to the caller. // Sets the PredictionState of SurfaceFrame. Loading @@ -115,6 +118,8 @@ public: // that vsync. virtual void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence) = 0; virtual void dump(std::string& result) = 0; }; namespace impl { Loading Loading @@ -151,14 +156,15 @@ public: TimelineItem getPredictions() override { return mPredictions; }; TimelineItem getActuals() override; nsecs_t getActualQueueTime() override; PresentState getPresentState() override; PredictionState getPredictionState() override; void setActuals(TimelineItem&& actuals) override; void setActualQueueTime(nsecs_t actualQueueTime) override { mActualQueueTime = actualQueueTime; }; void setActualStartTime(nsecs_t actualStartTime) override; void setActualQueueTime(nsecs_t actualQueueTime) override; void setActualEndTime(nsecs_t actualEndTime) override; void setPresentState(PresentState state) override; void setPresentTime(nsecs_t presentTime); void setActualPresentTime(nsecs_t presentTime); void dump(std::string& result); private: Loading @@ -176,7 +182,7 @@ public: FrameTimeline(); ~FrameTimeline() = default; frametimeline::TokenManager& getTokenManager() override { return mTokenManager; } frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } std::unique_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken( const std::string& layerName, std::optional<int64_t> token) override; void addSurfaceFrame(std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame, Loading @@ -184,7 +190,7 @@ public: void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override; void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence) override; void dump(std::string& result); void dump(std::string& result) override; private: // Friend class for testing Loading Loading
services/surfaceflinger/BufferLayer.h +1 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ #include "BufferLayerConsumer.h" #include "Client.h" #include "DisplayHardware/HWComposer.h" #include "FrameTimeline.h" #include "FrameTracker.h" #include "Layer.h" #include "LayerVector.h" Loading
services/surfaceflinger/BufferQueueLayer.cpp +52 −22 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ #include "TimeStats/TimeStats.h" namespace android { using PresentState = frametimeline::SurfaceFrame::PresentState; BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {} Loading Loading @@ -109,7 +110,7 @@ bool BufferQueueLayer::shouldPresentNow(nsecs_t expectedPresentTime) const { Mutex::Autolock lock(mQueueItemLock); const int64_t addedTime = mQueueItems[0].mTimestamp; const int64_t addedTime = mQueueItems[0].item.mTimestamp; // Ignore timestamps more than a second in the future const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1)); Loading @@ -136,7 +137,7 @@ bool BufferQueueLayer::fenceHasSignaled() const { } Mutex::Autolock lock(mQueueItemLock); if (mQueueItems[0].mIsDroppable) { if (mQueueItems[0].item.mIsDroppable) { // Even though this buffer's fence may not have signaled yet, it could // be replaced by another buffer before it has a chance to, which means // that it's possible to get into a situation where a buffer is never Loading @@ -144,7 +145,7 @@ bool BufferQueueLayer::fenceHasSignaled() const { return true; } const bool fenceSignaled = mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; mQueueItems[0].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; if (!fenceSignaled) { mFlinger->mTimeStats->incrementLatchSkipped(getSequence(), TimeStats::LatchSkipReason::LateAcquire); Loading @@ -159,12 +160,12 @@ bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) co } Mutex::Autolock lock(mQueueItemLock); return mQueueItems[0].mTimestamp <= expectedPresentTime; return mQueueItems[0].item.mTimestamp <= expectedPresentTime; } uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const { Mutex::Autolock lock(mQueueItemLock); uint64_t frameNumber = mQueueItems[0].mFrameNumber; uint64_t frameNumber = mQueueItems[0].item.mFrameNumber; // The head of the queue will be dropped if there are signaled and timely frames behind it if (isRemovedFromCurrentState()) { Loading @@ -173,23 +174,23 @@ uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const { for (int i = 1; i < mQueueItems.size(); i++) { const bool fenceSignaled = mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; if (!fenceSignaled) { break; } // We don't drop frames without explicit timestamps if (mQueueItems[i].mIsAutoTimestamp) { if (mQueueItems[i].item.mIsAutoTimestamp) { break; } const nsecs_t desiredPresent = mQueueItems[i].mTimestamp; const nsecs_t desiredPresent = mQueueItems[i].item.mTimestamp; if (desiredPresent < expectedPresentTime - BufferQueueConsumer::MAX_REASONABLE_NSEC || desiredPresent > expectedPresentTime) { break; } frameNumber = mQueueItems[i].mFrameNumber; frameNumber = mQueueItems[i].item.mFrameNumber; } return frameNumber; Loading Loading @@ -254,11 +255,11 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t Mutex::Autolock lock(mQueueItemLock); for (int i = 0; i < mQueueItems.size(); i++) { bool fenceSignaled = mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; if (!fenceSignaled) { break; } lastSignaledFrameNumber = mQueueItems[i].mFrameNumber; lastSignaledFrameNumber = mQueueItems[i].item.mFrameNumber; } } const uint64_t maxFrameNumberToAcquire = Loading @@ -276,9 +277,13 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // and return early if (queuedBuffer) { Mutex::Autolock lock(mQueueItemLock); mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].mFrameNumber); mQueueItems.removeAt(0); mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); if (mQueueItems[0].surfaceFrame) { mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame), PresentState::Dropped); } mQueueItems.erase(mQueueItems.begin()); mQueuedFrames--; } return BAD_VALUE; Loading @@ -289,6 +294,12 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // early. if (queuedBuffer) { Mutex::Autolock lock(mQueueItemLock); for (auto& [item, surfaceFrame] : mQueueItems) { if (surfaceFrame) { mFlinger->mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame), PresentState::Dropped); } } mQueueItems.clear(); mQueuedFrames = 0; mFlinger->mTimeStats->onDestroy(layerId); Loading @@ -312,19 +323,29 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // Remove any stale buffers that have been dropped during // updateTexImage while (mQueueItems[0].mFrameNumber != currentFrameNumber) { mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].mFrameNumber); mQueueItems.removeAt(0); while (mQueueItems[0].item.mFrameNumber != currentFrameNumber) { mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); if (mQueueItems[0].surfaceFrame) { mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame), PresentState::Dropped); } mQueueItems.erase(mQueueItems.begin()); mQueuedFrames--; } uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId(); uint64_t bufferID = mQueueItems[0].item.mGraphicBuffer->getId(); mFlinger->mTimeStats->setLatchTime(layerId, currentFrameNumber, latchTime); mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, currentFrameNumber, latchTime, FrameTracer::FrameEvent::LATCH); mQueueItems.removeAt(0); if (mQueueItems[0].surfaceFrame) { mQueueItems[0].surfaceFrame->setActualEndTime( mQueueItems[0].item.mFenceTime->getSignalTime()); mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame), PresentState::Presented); } mQueueItems.erase(mQueueItems.begin()); } // Decrement the queued-frames count. Signal another event if we Loading Loading @@ -416,7 +437,11 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { } } mQueueItems.push_back(item); auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems.push_back({item, std::move(surfaceFrame)}); mQueuedFrames++; // Wake up any pending callbacks Loading Loading @@ -449,7 +474,12 @@ void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { ALOGE("Can't replace a frame on an empty queue"); return; } mQueueItems.editItemAt(mQueueItems.size() - 1) = item; auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems[mQueueItems.size() - 1].item = item; mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame); // Wake up any pending callbacks mLastFrameNumberReceived = item.mFrameNumber; Loading
services/surfaceflinger/BufferQueueLayer.h +12 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,10 @@ namespace android { namespace frametimeline { class SurfaceFrame; } /* * A new BufferQueue and a new BufferLayerConsumer are created when the * BufferLayer is first referenced. Loading Loading @@ -125,7 +129,14 @@ private: // Local copy of the queued contents of the incoming BufferQueue mutable Mutex mQueueItemLock; Condition mQueueItemCondition; Vector<BufferItem> mQueueItems; struct BufferData { BufferData(BufferItem item, std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame) : item(item), surfaceFrame(std::move(surfaceFrame)) {} BufferItem item; std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame; }; std::vector<BufferData> mQueueItems; std::atomic<uint64_t> mLastFrameNumberReceived{0}; bool mAutoRefresh{false}; Loading
services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +29 −4 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "FrameTimeline.h" #include <android-base/stringprintf.h> #include <utils/Trace.h> #include <cinttypes> namespace android::frametimeline::impl { Loading @@ -27,6 +28,7 @@ namespace android::frametimeline::impl { using base::StringAppendF; int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); const int64_t assignedToken = mCurrentToken++; mPredictions[assignedToken] = predictions; Loading Loading @@ -88,18 +90,34 @@ TimelineItem SurfaceFrame::getActuals() { return mActuals; } void SurfaceFrame::setActuals(frametimeline::TimelineItem&& actuals) { nsecs_t SurfaceFrame::getActualQueueTime() { std::lock_guard<std::mutex> lock(mMutex); mActuals = actuals; return mActualQueueTime; } void SurfaceFrame::setPresentTime(nsecs_t presentTime) { void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) { std::lock_guard<std::mutex> lock(mMutex); mActuals.startTime = actualStartTime; } void SurfaceFrame::setActualQueueTime(nsecs_t actualQueueTime) { std::lock_guard<std::mutex> lock(mMutex); mActualQueueTime = actualQueueTime; } void SurfaceFrame::setActualEndTime(nsecs_t actualEndTime) { std::lock_guard<std::mutex> lock(mMutex); mActuals.endTime = actualEndTime; } void SurfaceFrame::setActualPresentTime(nsecs_t presentTime) { std::lock_guard<std::mutex> lock(mMutex); mActuals.presentTime = presentTime; } void SurfaceFrame::dump(std::string& result) { std::lock_guard<std::mutex> lock(mMutex); StringAppendF(&result, "Present State : %d\n", static_cast<int>(mPresentState)); StringAppendF(&result, "Prediction State : %d\n", static_cast<int>(mPredictionState)); StringAppendF(&result, "Predicted Start Time : %" PRId64 "\n", mPredictions.startTime); StringAppendF(&result, "Actual Start Time : %" PRId64 "\n", mActuals.startTime); StringAppendF(&result, "Actual Queue Time : %" PRId64 "\n", mActualQueueTime); Loading @@ -120,6 +138,7 @@ FrameTimeline::DisplayFrame::DisplayFrame() std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken( const std::string& layerName, std::optional<int64_t> token) { ATRACE_CALL(); if (!token) { return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::None, TimelineItem()); Loading @@ -136,6 +155,7 @@ std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfa void FrameTimeline::addSurfaceFrame( std::unique_ptr<android::frametimeline::SurfaceFrame> surfaceFrame, SurfaceFrame::PresentState state) { ATRACE_CALL(); surfaceFrame->setPresentState(state); std::unique_ptr<impl::SurfaceFrame> implSurfaceFrame( static_cast<impl::SurfaceFrame*>(surfaceFrame.release())); Loading @@ -144,18 +164,21 @@ void FrameTimeline::addSurfaceFrame( } void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) { ATRACE_CALL(); const std::optional<TimelineItem> prediction = mTokenManager.getPredictionsForToken(token); std::lock_guard<std::mutex> lock(mMutex); if (!prediction) { mCurrentDisplayFrame->predictionState = PredictionState::Expired; } else { mCurrentDisplayFrame->surfaceFlingerPredictions = *prediction; mCurrentDisplayFrame->predictionState = PredictionState::Valid; } mCurrentDisplayFrame->surfaceFlingerActuals.startTime = wakeUpTime; } void FrameTimeline::setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence) { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); mCurrentDisplayFrame->surfaceFlingerActuals.endTime = sfPresentTime; mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame)); Loading @@ -179,7 +202,7 @@ void FrameTimeline::flushPendingPresentFences() { for (auto& surfaceFrame : displayFrame->surfaceFrames) { if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) { // Only presented SurfaceFrames need to be updated surfaceFrame->setPresentTime(signalTime); surfaceFrame->setActualPresentTime(signalTime); } } } Loading @@ -204,6 +227,8 @@ void FrameTimeline::dump(std::string& result) { StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size()); for (const auto& displayFrame : mDisplayFrames) { StringAppendF(&result, "---Display Frame---\n"); StringAppendF(&result, "Prediction State : %d\n", static_cast<int>(displayFrame->predictionState)); StringAppendF(&result, "Predicted SF wake time : %" PRId64 "\n", displayFrame->surfaceFlingerPredictions.startTime); StringAppendF(&result, "Actual SF wake time : %" PRId64 "\n", Loading
services/surfaceflinger/FrameTimeline/FrameTimeline.h +18 −12 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ public: // Generates a token for the given set of predictions. Stores the predictions for 120ms and // destroys it later. virtual int64_t generateTokenForPredictions(TimelineItem&& prediction); virtual int64_t generateTokenForPredictions(TimelineItem&& prediction) = 0; }; enum class PredictionState { Loading @@ -76,15 +76,18 @@ public: virtual TimelineItem getPredictions() = 0; virtual TimelineItem getActuals() = 0; virtual nsecs_t getActualQueueTime() = 0; virtual PresentState getPresentState() = 0; virtual PredictionState getPredictionState() = 0; virtual void setPresentState(PresentState state) = 0; virtual void setActuals(TimelineItem&& actuals) = 0; // There is no prediction for Queue time and it is not a part of TimelineItem. Set it // separately. // Actual timestamps of the app are set individually at different functions. // Start time (if the app provides) and Queue time are accessible after queueing the frame, // whereas End time is available only during latch. virtual void setActualStartTime(nsecs_t actualStartTime) = 0; virtual void setActualQueueTime(nsecs_t actualQueueTime) = 0; virtual void setActualEndTime(nsecs_t actualEndTime) = 0; }; /* Loading @@ -94,7 +97,7 @@ public: class FrameTimeline { public: virtual ~FrameTimeline() = default; virtual TokenManager& getTokenManager() = 0; virtual TokenManager* getTokenManager() = 0; // Create a new surface frame, set the predictions based on a token and return it to the caller. // Sets the PredictionState of SurfaceFrame. Loading @@ -115,6 +118,8 @@ public: // that vsync. virtual void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence) = 0; virtual void dump(std::string& result) = 0; }; namespace impl { Loading Loading @@ -151,14 +156,15 @@ public: TimelineItem getPredictions() override { return mPredictions; }; TimelineItem getActuals() override; nsecs_t getActualQueueTime() override; PresentState getPresentState() override; PredictionState getPredictionState() override; void setActuals(TimelineItem&& actuals) override; void setActualQueueTime(nsecs_t actualQueueTime) override { mActualQueueTime = actualQueueTime; }; void setActualStartTime(nsecs_t actualStartTime) override; void setActualQueueTime(nsecs_t actualQueueTime) override; void setActualEndTime(nsecs_t actualEndTime) override; void setPresentState(PresentState state) override; void setPresentTime(nsecs_t presentTime); void setActualPresentTime(nsecs_t presentTime); void dump(std::string& result); private: Loading @@ -176,7 +182,7 @@ public: FrameTimeline(); ~FrameTimeline() = default; frametimeline::TokenManager& getTokenManager() override { return mTokenManager; } frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } std::unique_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken( const std::string& layerName, std::optional<int64_t> token) override; void addSurfaceFrame(std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame, Loading @@ -184,7 +190,7 @@ public: void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override; void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence) override; void dump(std::string& result); void dump(std::string& result) override; private: // Friend class for testing Loading