diff options
author | 2021-02-03 23:19:29 +0100 | |
---|---|---|
committer | 2021-02-17 14:55:22 +0100 | |
commit | 71db8892acc0c80c343141139bde8cfd3f037c4a (patch) | |
tree | 9f40ac7b2cf2d535d24d9e6eacf8c353e8dcabc8 /libs/hwui | |
parent | 5fdf7b8d26f3cd1a2f2fb8a441d40d33270d3b77 (diff) |
Add GPU completion to FrameMetrics (1/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: I16fa1d80cfc4e7a5527c18fec7e885409f17ee4d
Diffstat (limited to 'libs/hwui')
-rw-r--r-- | libs/hwui/Android.bp | 4 | ||||
-rw-r--r-- | libs/hwui/FrameInfo.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/FrameInfo.h | 5 | ||||
-rw-r--r-- | libs/hwui/FrameMetricsReporter.h | 30 | ||||
-rw-r--r-- | libs/hwui/JankTracker.cpp | 15 | ||||
-rw-r--r-- | libs/hwui/JankTracker.h | 7 | ||||
-rw-r--r-- | libs/hwui/ProfileDataContainer.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/ProfileDataContainer.h | 11 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 90 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 16 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderThread.cpp | 23 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderThread.h | 16 |
13 files changed, 187 insertions, 41 deletions
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index f48122858267..42c6d7ce1570 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -480,6 +480,8 @@ cc_defaults { target: { android: { + header_libs: ["libandroid_headers_private" ], + srcs: [ "hwui/AnimatedImageThread.cpp", "pipeline/skia/ATraceMemoryDump.cpp", @@ -567,6 +569,7 @@ cc_defaults { name: "hwui_test_defaults", defaults: ["hwui_defaults"], test_suites: ["device-tests"], + header_libs: ["libandroid_headers_private"], target: { android: { shared_libs: [ @@ -604,7 +607,6 @@ cc_test { shared_libs: [ "libmemunreachable", ], - srcs: [ "tests/unit/main.cpp", "tests/unit/ABitmapTests.cpp", diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp index 8b20492543f7..ce9b2889cd9e 100644 --- a/libs/hwui/FrameInfo.cpp +++ b/libs/hwui/FrameInfo.cpp @@ -42,7 +42,7 @@ const std::array<std::string, static_cast<int>(FrameInfoIndex::NumIndexes)> Fram "GpuCompleted", }; -static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 19, +static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 20, "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 ee7d15a2fbce..45a367f525da 100644 --- a/libs/hwui/FrameInfo.h +++ b/libs/hwui/FrameInfo.h @@ -55,6 +55,7 @@ enum class FrameInfoIndex { QueueBufferDuration, GpuCompleted, + SwapBuffersCompleted, // Must be the last value! // Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT @@ -120,6 +121,10 @@ public: void markSwapBuffers() { set(FrameInfoIndex::SwapBuffers) = systemTime(SYSTEM_TIME_MONOTONIC); } + void markSwapBuffersCompleted() { + set(FrameInfoIndex::SwapBuffersCompleted) = systemTime(SYSTEM_TIME_MONOTONIC); + } + void markFrameCompleted() { set(FrameInfoIndex::FrameCompleted) = systemTime(SYSTEM_TIME_MONOTONIC); } void addFlag(int frameInfoFlag) { diff --git a/libs/hwui/FrameMetricsReporter.h b/libs/hwui/FrameMetricsReporter.h index 75b8038c5040..0643e790d00b 100644 --- a/libs/hwui/FrameMetricsReporter.h +++ b/libs/hwui/FrameMetricsReporter.h @@ -16,14 +16,16 @@ #pragma once +#include <utils/Mutex.h> #include <utils/Log.h> #include <utils/RefBase.h> +#include <ui/FatVector.h> + #include "FrameInfo.h" #include "FrameMetricsObserver.h" #include <string.h> -#include <vector> namespace android { namespace uirenderer { @@ -32,9 +34,13 @@ class FrameMetricsReporter { public: FrameMetricsReporter() {} - void addObserver(FrameMetricsObserver* observer) { mObservers.push_back(observer); } + void addObserver(FrameMetricsObserver* observer) { + std::lock_guard lock(mObserversLock); + mObservers.push_back(observer); + } bool removeObserver(FrameMetricsObserver* observer) { + std::lock_guard lock(mObserversLock); for (size_t i = 0; i < mObservers.size(); i++) { if (mObservers[i].get() == observer) { mObservers.erase(mObservers.begin() + i); @@ -44,16 +50,28 @@ public: return false; } - bool hasObservers() { return mObservers.size() > 0; } + bool hasObservers() { + std::lock_guard lock(mObserversLock); + return mObservers.size() > 0; + } void reportFrameMetrics(const int64_t* stats) { - for (size_t i = 0; i < mObservers.size(); i++) { - mObservers[i]->notify(stats); + FatVector<sp<FrameMetricsObserver>, 10> copy; + { + std::lock_guard lock(mObserversLock); + copy.reserve(mObservers.size()); + for (size_t i = 0; i < mObservers.size(); i++) { + copy.push_back(mObservers[i]); + } + } + for (size_t i = 0; i < copy.size(); i++) { + copy[i]->notify(stats); } } private: - std::vector<sp<FrameMetricsObserver> > mObservers; + FatVector<sp<FrameMetricsObserver>, 10> mObservers GUARDED_BY(mObserversLock); + std::mutex mObserversLock; }; } // namespace uirenderer diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp index ccce403ecfac..4a2e30dd38f2 100644 --- a/libs/hwui/JankTracker.cpp +++ b/libs/hwui/JankTracker.cpp @@ -79,7 +79,9 @@ static const int64_t EXEMPT_FRAMES_FLAGS = FrameInfoFlags::SurfaceCanvas; // and filter it out of the frame profile data static FrameInfoIndex sFrameStart = FrameInfoIndex::IntendedVsync; -JankTracker::JankTracker(ProfileDataContainer* globalData) { +JankTracker::JankTracker(ProfileDataContainer* globalData) + : mData(globalData->getDataMutex()) + , mDataMutex(globalData->getDataMutex()) { mGlobalData = globalData; nsecs_t frameIntervalNanos = DeviceInfo::getVsyncPeriod(); nsecs_t sfOffset = DeviceInfo::getCompositorOffset(); @@ -107,6 +109,8 @@ void JankTracker::setFrameInterval(nsecs_t frameInterval) { } void JankTracker::finishFrame(const FrameInfo& frame) { + std::lock_guard lock(mDataMutex); + // Fast-path for jank-free frames int64_t totalDuration = frame.duration(sFrameStart, FrameInfoIndex::FrameCompleted); if (mDequeueTimeForgiveness && frame[FrameInfoIndex::DequeueBufferDuration] > 500_us) { @@ -125,7 +129,11 @@ void JankTracker::finishFrame(const FrameInfo& frame) { } } - LOG_ALWAYS_FATAL_IF(totalDuration <= 0, "Impossible totalDuration %" PRId64, totalDuration); + LOG_ALWAYS_FATAL_IF(totalDuration <= 0, "Impossible totalDuration %" PRId64 " start=%" PRIi64 + " gpuComplete=%" PRIi64, totalDuration, + frame[FrameInfoIndex::IntendedVsync], + frame[FrameInfoIndex::GpuCompleted]); + mData->reportFrame(totalDuration); (*mGlobalData)->reportFrame(totalDuration); @@ -188,6 +196,7 @@ void JankTracker::finishFrame(const FrameInfo& frame) { void JankTracker::dumpData(int fd, const ProfileDataDescription* description, const ProfileData* data) { + if (description) { switch (description->type) { case JankTrackerType::Generic: @@ -227,6 +236,7 @@ void JankTracker::dumpFrames(int fd) { } void JankTracker::reset() { + std::lock_guard lock(mDataMutex); mFrames.clear(); mData->reset(); (*mGlobalData)->reset(); @@ -235,6 +245,7 @@ void JankTracker::reset() { } void JankTracker::finishGpuDraw(const FrameInfo& frame) { + std::lock_guard lock(mDataMutex); int64_t totalGPUDrawTime = frame.gpuDrawTime(); if (totalGPUDrawTime >= 0) { mData->reportGPUFrame(totalGPUDrawTime); diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h index b3fbbfe98669..096455372923 100644 --- a/libs/hwui/JankTracker.h +++ b/libs/hwui/JankTracker.h @@ -84,12 +84,15 @@ private: // This is only used if we are in pipelined mode and are using HWC2, // otherwise it's 0. nsecs_t mDequeueTimeForgiveness = 0; - ProfileDataContainer mData; - ProfileDataContainer* mGlobalData; + ProfileDataContainer mData GUARDED_BY(mDataMutex); + ProfileDataContainer* mGlobalData GUARDED_BY(mDataMutex); ProfileDataDescription mDescription; // Ring buffer large enough for 2 seconds worth of frames RingBuffer<FrameInfo, 120> mFrames; + + // Mutex to protect acccess to mData and mGlobalData obtained from mGlobalData->getDataMutex + std::mutex& mDataMutex; }; } /* namespace uirenderer */ diff --git a/libs/hwui/ProfileDataContainer.cpp b/libs/hwui/ProfileDataContainer.cpp index 38e0f0aa8d83..41afc0e04c8b 100644 --- a/libs/hwui/ProfileDataContainer.cpp +++ b/libs/hwui/ProfileDataContainer.cpp @@ -38,6 +38,8 @@ void ProfileDataContainer::freeData() { } void ProfileDataContainer::rotateStorage() { + std::lock_guard lock(mJankDataMutex); + // If we are mapped we want to stop using the ashmem backend and switch to malloc // We are expecting a switchStorageToAshmem call to follow this, but it's not guaranteed // If we aren't sitting on top of ashmem then just do a reset() as it's functionally @@ -50,6 +52,7 @@ void ProfileDataContainer::rotateStorage() { } void ProfileDataContainer::switchStorageToAshmem(int ashmemfd) { + std::lock_guard lock(mJankDataMutex); int regionSize = ashmem_get_size_region(ashmemfd); if (regionSize < 0) { int err = errno; @@ -70,7 +73,9 @@ void ProfileDataContainer::switchStorageToAshmem(int ashmemfd) { return; } - newData->mergeWith(*mData); + if (mData != nullptr) { + newData->mergeWith(*mData); + } freeData(); mData = newData; mIsMapped = true; diff --git a/libs/hwui/ProfileDataContainer.h b/libs/hwui/ProfileDataContainer.h index a39869491ede..a61b8dcf390e 100644 --- a/libs/hwui/ProfileDataContainer.h +++ b/libs/hwui/ProfileDataContainer.h @@ -19,6 +19,9 @@ #include "ProfileData.h" #include "utils/Macros.h" +#include <mutex> +#include <utils/Mutex.h> + namespace android { namespace uirenderer { @@ -26,7 +29,8 @@ class ProfileDataContainer { PREVENT_COPY_AND_ASSIGN(ProfileDataContainer); public: - explicit ProfileDataContainer() {} + explicit ProfileDataContainer(std::mutex& jankDataMutex) + : mData(new ProfileData()), mJankDataMutex(jankDataMutex) {} ~ProfileDataContainer() { freeData(); } @@ -36,13 +40,16 @@ public: ProfileData* get() { return mData; } ProfileData* operator->() { return mData; } + std::mutex& getDataMutex() { return mJankDataMutex; } + private: void freeData(); // By default this will use malloc memory. It may be moved later to ashmem // if there is shared space for it and a request comes in to do that. - ProfileData* mData = new ProfileData; + ProfileData* mData GUARDED_BY(mJankDataMutex); bool mIsMapped = false; + std::mutex& mJankDataMutex; }; } /* namespace uirenderer */ diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 9543d47640e6..b760db287bcb 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -178,12 +178,16 @@ void CanvasContext::setSurfaceControl(ASurfaceControl* surfaceControl) { if (surfaceControl == mSurfaceControl) return; auto funcs = mRenderThread.getASurfaceControlFunctions(); + if (mSurfaceControl != nullptr) { + funcs.unregisterListenerFunc(this, &onSurfaceStatsAvailable); funcs.releaseFunc(mSurfaceControl); } mSurfaceControl = surfaceControl; + mExpectSurfaceStats = surfaceControl != nullptr; if (mSurfaceControl != nullptr) { funcs.acquireFunc(mSurfaceControl); + funcs.registerListenerFunc(surfaceControl, this, &onSurfaceStatsAvailable); } } @@ -332,8 +336,8 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy // just keep using the previous frame's structure instead if (!wasSkipped(mCurrentFrameInfo)) { mCurrentFrameInfo = mJankTracker.startFrame(); - mLast4FrameInfos.next().first = mCurrentFrameInfo; } + mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo); mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued; mCurrentFrameInfo->markSyncStart(); @@ -538,17 +542,14 @@ void CanvasContext::draw() { } mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = swap.dequeueDuration; mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = swap.queueDuration; - mLast4FrameInfos[-1].second = frameCompleteNr; mHaveNewSurface = false; mFrameNumber = -1; } else { mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0; mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0; - mLast4FrameInfos[-1].second = -1; } - // TODO: Use a fence for real completion? - mCurrentFrameInfo->markFrameCompleted(); + mCurrentFrameInfo->markSwapBuffersCompleted(); #if LOG_FRAMETIME_MMA float thisFrame = mCurrentFrameInfo->duration(FrameInfoIndex::IssueDrawCommandsStart, @@ -572,30 +573,73 @@ void CanvasContext::draw() { mFrameCompleteCallbacks.clear(); } - mJankTracker.finishFrame(*mCurrentFrameInfo); - if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) { - mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data()); - } - - if (mLast4FrameInfos.size() == mLast4FrameInfos.capacity()) { - // By looking 4 frames back, we guarantee all SF stats are available. There are at - // most 3 buffers in BufferQueue. Surface object keeps stats for the last 8 frames. - FrameInfo* forthBehind = mLast4FrameInfos.front().first; - int64_t composedFrameId = mLast4FrameInfos.front().second; - nsecs_t acquireTime = -1; - if (mNativeSurface) { - native_window_get_frame_timestamps(mNativeSurface->getNativeWindow(), composedFrameId, - nullptr, &acquireTime, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr); + if (requireSwap) { + if (mExpectSurfaceStats) { + std::lock_guard lock(mLast4FrameInfosMutex); + std::pair<FrameInfo*, int64_t>& next = mLast4FrameInfos.next(); + next.first = mCurrentFrameInfo; + next.second = frameCompleteNr; + } else { + mCurrentFrameInfo->markFrameCompleted(); + mCurrentFrameInfo->set(FrameInfoIndex::GpuCompleted) + = mCurrentFrameInfo->get(FrameInfoIndex::FrameCompleted); + finishFrame(mCurrentFrameInfo); } - // Ignore default -1, NATIVE_WINDOW_TIMESTAMP_INVALID and NATIVE_WINDOW_TIMESTAMP_PENDING - forthBehind->set(FrameInfoIndex::GpuCompleted) = acquireTime > 0 ? acquireTime : -1; - mJankTracker.finishGpuDraw(*forthBehind); } mRenderThread.cacheManager().onFrameCompleted(); } +void CanvasContext::finishFrame(FrameInfo* frameInfo) { + + // TODO (b/169858044): Consolidate this into a single call. + mJankTracker.finishFrame(*frameInfo); + mJankTracker.finishGpuDraw(*frameInfo); + + // TODO (b/169858044): Move this into JankTracker to adjust deadline when queue is + // double-stuffed. + if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) { + mFrameMetricsReporter->reportFrameMetrics(frameInfo->data()); + } +} + +void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* control, + ASurfaceControlStats* stats) { + + CanvasContext* instance = static_cast<CanvasContext*>(context); + + const ASurfaceControlFunctions& functions = + instance->mRenderThread.getASurfaceControlFunctions(); + + nsecs_t gpuCompleteTime = functions.getAcquireTimeFunc(stats); + uint64_t frameNumber = functions.getFrameNumberFunc(stats); + + FrameInfo* frameInfo = nullptr; + { + std::lock_guard(instance->mLast4FrameInfosMutex); + for (size_t i = 0; i < instance->mLast4FrameInfos.size(); i++) { + if (instance->mLast4FrameInfos[i].second == frameNumber) { + frameInfo = instance->mLast4FrameInfos[i].first; + break; + } + } + } + if (frameInfo != nullptr) { + if (gpuCompleteTime == -1) { + gpuCompleteTime = frameInfo->get(FrameInfoIndex::SwapBuffersCompleted); + } + if (gpuCompleteTime < frameInfo->get(FrameInfoIndex::SwapBuffers)) { + // TODO (b/180488606): Investigate why this can happen for first frames. + ALOGW("Impossible GPU complete time swapBuffers=%" PRIi64 " gpuComplete=%" PRIi64, + frameInfo->get(FrameInfoIndex::SwapBuffers), gpuCompleteTime); + gpuCompleteTime = frameInfo->get(FrameInfoIndex::SwapBuffersCompleted); + } + frameInfo->set(FrameInfoIndex::FrameCompleted) = gpuCompleteTime; + frameInfo->set(FrameInfoIndex::GpuCompleted) = gpuCompleteTime; + instance->finishFrame(frameInfo); + } +} + // Called by choreographer to do an RT-driven animation void CanvasContext::doFrame() { if (!mRenderPipeline->isSurfaceReady()) return; diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 917b00cb6591..2e7b2f618a8a 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -37,6 +37,7 @@ #include <SkSize.h> #include <cutils/compiler.h> #include <utils/Functor.h> +#include <utils/Mutex.h> #include <functional> #include <future> @@ -196,6 +197,10 @@ public: SkISize getNextFrameSize() const; + // Called when SurfaceStats are available. + static void onSurfaceStatsAvailable(void* context, ASurfaceControl* control, + ASurfaceControlStats* stats); + private: CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline); @@ -212,6 +217,7 @@ private: void setupPipelineSurface(); SkRect computeDirtyRect(const Frame& frame, SkRect* dirty); + void finishFrame(FrameInfo* frameInfo); // The same type as Frame.mWidth and Frame.mHeight int32_t mLastFrameWidth = 0; @@ -261,7 +267,12 @@ private: std::vector<sp<RenderNode>> mRenderNodes; FrameInfo* mCurrentFrameInfo = nullptr; - RingBuffer<std::pair<FrameInfo*, int64_t>, 4> mLast4FrameInfos; + + // List of frames that are awaiting GPU completion reporting + RingBuffer<std::pair<FrameInfo*, int64_t>, 4> mLast4FrameInfos + GUARDED_BY(mLast4FrameInfosMutex); + std::mutex mLast4FrameInfosMutex; + std::string mName; JankTracker mJankTracker; FrameInfoVisualizer mProfiler; @@ -276,6 +287,9 @@ private: std::unique_ptr<IRenderPipeline> mRenderPipeline; std::vector<std::function<void(int64_t)>> mFrameCompleteCallbacks; + + // If set to true, we expect that callbacks into onSurfaceStatsAvailable + bool mExpectSurfaceStats = false; }; } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index e14842f89b61..b9568fcf8e66 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -215,6 +215,7 @@ void RenderProxy::notifyFramePending() { void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) { mRenderThread.queue().runSync([&]() { + std::lock_guard lock(mRenderThread.getJankDataMutex()); mContext->profiler().dumpData(fd); if (dumpFlags & DumpFlags::FrameStats) { mContext->dumpFrames(fd); @@ -234,6 +235,7 @@ void RenderProxy::resetProfileInfo() { uint32_t RenderProxy::frameTimePercentile(int percentile) { return mRenderThread.queue().runSync([&]() -> auto { + std::lock_guard lock(mRenderThread.globalProfileData().getDataMutex()); return mRenderThread.globalProfileData()->findPercentile(percentile); }); } diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 26101867c43f..5dc02e8454ac 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -59,6 +59,26 @@ ASurfaceControlFunctions::ASurfaceControlFunctions() { releaseFunc = (ASC_release) dlsym(handle_, "ASurfaceControl_release"); LOG_ALWAYS_FATAL_IF(releaseFunc == nullptr, "Failed to find required symbol ASurfaceControl_release!"); + + registerListenerFunc = (ASC_registerSurfaceStatsListener) dlsym(handle_, + "ASurfaceControl_registerSurfaceStatsListener"); + LOG_ALWAYS_FATAL_IF(registerListenerFunc == nullptr, + "Failed to find required symbol ASurfaceControl_registerSurfaceStatsListener!"); + + unregisterListenerFunc = (ASC_unregisterSurfaceStatsListener) dlsym(handle_, + "ASurfaceControl_unregisterSurfaceStatsListener"); + LOG_ALWAYS_FATAL_IF(unregisterListenerFunc == nullptr, + "Failed to find required symbol ASurfaceControl_unregisterSurfaceStatsListener!"); + + getAcquireTimeFunc = (ASCStats_getAcquireTime) dlsym(handle_, + "ASurfaceControlStats_getAcquireTime"); + LOG_ALWAYS_FATAL_IF(getAcquireTimeFunc == nullptr, + "Failed to find required symbol ASurfaceControlStats_getAcquireTime!"); + + getFrameNumberFunc = (ASCStats_getFrameNumber) dlsym(handle_, + "ASurfaceControlStats_getFrameNumber"); + LOG_ALWAYS_FATAL_IF(getFrameNumberFunc == nullptr, + "Failed to find required symbol ASurfaceControlStats_getFrameNumber!"); } void RenderThread::frameCallback(int64_t frameTimeNanos, void* data) { @@ -146,7 +166,8 @@ RenderThread::RenderThread() , mFrameCallbackTaskPending(false) , mRenderState(nullptr) , mEglManager(nullptr) - , mFunctorManager(WebViewFunctorManager::instance()) { + , mFunctorManager(WebViewFunctorManager::instance()) + , mGlobalProfileData(mJankDataMutex) { Properties::load(); start("RenderThread"); } diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index bb7c5181e112..a7d1ba8dafd7 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -17,6 +17,7 @@ #ifndef RENDERTHREAD_H_ #define RENDERTHREAD_H_ +#include <surface_control_private.h> #include <GrDirectContext.h> #include <SkBitmap.h> #include <cutils/compiler.h> @@ -81,11 +82,22 @@ struct VsyncSource { typedef void (*ASC_acquire)(ASurfaceControl* control); typedef void (*ASC_release)(ASurfaceControl* control); +typedef void (*ASC_registerSurfaceStatsListener)(ASurfaceControl* control, void* context, + ASurfaceControl_SurfaceStatsListener func); +typedef void (*ASC_unregisterSurfaceStatsListener)(void* context, + ASurfaceControl_SurfaceStatsListener func); + +typedef int64_t (*ASCStats_getAcquireTime)(ASurfaceControlStats* stats); +typedef uint64_t (*ASCStats_getFrameNumber)(ASurfaceControlStats* stats); + struct ASurfaceControlFunctions { ASurfaceControlFunctions(); - ASC_acquire acquireFunc; ASC_release releaseFunc; + ASC_registerSurfaceStatsListener registerListenerFunc; + ASC_unregisterSurfaceStatsListener unregisterListenerFunc; + ASCStats_getAcquireTime getAcquireTimeFunc; + ASCStats_getFrameNumber getFrameNumberFunc; }; class ChoreographerSource; @@ -114,6 +126,7 @@ public: RenderState& renderState() const { return *mRenderState; } EglManager& eglManager() const { return *mEglManager; } ProfileDataContainer& globalProfileData() { return mGlobalProfileData; } + std::mutex& getJankDataMutex() { return mJankDataMutex; } Readback& readback(); GrDirectContext* getGrContext() const { return mGrContext.get(); } @@ -205,6 +218,7 @@ private: sp<VulkanManager> mVkManager; ASurfaceControlFunctions mASurfaceControlFunctions; + std::mutex mJankDataMutex; }; } /* namespace renderthread */ |