diff options
Diffstat (limited to 'libs/hwui/renderthread')
-rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.cpp | 147 | ||||
-rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.h | 24 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 13 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.h | 2 | ||||
-rw-r--r-- | libs/hwui/renderthread/VulkanManager.cpp | 4 |
5 files changed, 146 insertions, 44 deletions
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 5c4b9019b0ad..e7081df2b558 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -16,6 +16,7 @@ #include "DrawFrameTask.h" +#include <dlfcn.h> #include <gui/TraceUtils.h> #include <utils/Log.h> #include <algorithm> @@ -26,11 +27,63 @@ #include "../RenderNode.h" #include "CanvasContext.h" #include "RenderThread.h" +#include "thread/CommonPool.h" namespace android { namespace uirenderer { namespace renderthread { +namespace { + +typedef APerformanceHintManager* (*APH_getManager)(); +typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*, + size_t, int64_t); +typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t); +typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t); +typedef void (*APH_closeSession)(APerformanceHintSession* session); + +bool gAPerformanceHintBindingInitialized = false; +APH_getManager gAPH_getManagerFn = nullptr; +APH_createSession gAPH_createSessionFn = nullptr; +APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr; +APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr; +APH_closeSession gAPH_closeSessionFn = nullptr; + +void ensureAPerformanceHintBindingInitialized() { + if (gAPerformanceHintBindingInitialized) return; + + void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE); + LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!"); + + gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager"); + LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr, + "Failed to find required symbol APerformanceHint_getManager!"); + + gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession"); + LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr, + "Failed to find required symbol APerformanceHint_createSession!"); + + gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym( + handle_, "APerformanceHint_updateTargetWorkDuration"); + LOG_ALWAYS_FATAL_IF( + gAPH_updateTargetWorkDurationFn == nullptr, + "Failed to find required symbol APerformanceHint_updateTargetWorkDuration!"); + + gAPH_reportActualWorkDurationFn = (APH_reportActualWorkDuration)dlsym( + handle_, "APerformanceHint_reportActualWorkDuration"); + LOG_ALWAYS_FATAL_IF( + gAPH_reportActualWorkDurationFn == nullptr, + "Failed to find required symbol APerformanceHint_reportActualWorkDuration!"); + + gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession"); + LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr, + "Failed to find required symbol APerformanceHint_closeSession!"); + + gAPerformanceHintBindingInitialized = true; +} + +} // namespace + DrawFrameTask::DrawFrameTask() : mRenderThread(nullptr) , mContext(nullptr) @@ -39,17 +92,13 @@ DrawFrameTask::DrawFrameTask() DrawFrameTask::~DrawFrameTask() {} -void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, - RenderNode* targetNode) { +void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode, + int32_t uiThreadId, int32_t renderThreadId) { mRenderThread = thread; mContext = context; mTargetNode = targetNode; -} - -void DrawFrameTask::setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration, - std::function<void(int64_t)> reportActualWorkDuration) { - mUpdateTargetWorkDuration = std::move(updateTargetWorkDuration); - mReportActualWorkDuration = std::move(reportActualWorkDuration); + mUiThreadId = uiThreadId; + mRenderThreadId = renderThreadId; } void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) { @@ -130,6 +179,12 @@ void DrawFrameTask::run() { if (CC_LIKELY(canDrawThisFrame)) { dequeueBufferDuration = context->draw(); } else { + // Do a flush in case syncFrameState performed any texture uploads. Since we skipped + // the draw() call, those uploads (or deletes) will end up sitting in the queue. + // Do them now + if (GrDirectContext* grContext = mRenderThread->getGrContext()) { + grContext->flushAndSubmit(); + } // wait on fences so tasks don't overlap next frame context->waitOnFences(); } @@ -138,27 +193,25 @@ void DrawFrameTask::run() { unblockUiThread(); } - // These member callbacks are effectively const as they are set once during init, so it's safe - // to use these directly instead of making local copies. - if (mUpdateTargetWorkDuration && mReportActualWorkDuration) { - constexpr int64_t kSanityCheckLowerBound = 100000; // 0.1ms - constexpr int64_t kSanityCheckUpperBound = 10000000000; // 10s - int64_t targetWorkDuration = frameDeadline - intendedVsync; - targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100; - if (targetWorkDuration > kSanityCheckLowerBound && - targetWorkDuration < kSanityCheckUpperBound && - targetWorkDuration != mLastTargetWorkDuration) { - mLastTargetWorkDuration = targetWorkDuration; - mUpdateTargetWorkDuration(targetWorkDuration); - } - int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime; - int64_t actualDuration = frameDuration - - (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - - dequeueBufferDuration; - if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) { - mReportActualWorkDuration(actualDuration); - } + if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId); + constexpr int64_t kSanityCheckLowerBound = 100000; // 0.1ms + constexpr int64_t kSanityCheckUpperBound = 10000000000; // 10s + int64_t targetWorkDuration = frameDeadline - intendedVsync; + targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100; + if (targetWorkDuration > kSanityCheckLowerBound && + targetWorkDuration < kSanityCheckUpperBound && + targetWorkDuration != mLastTargetWorkDuration) { + mLastTargetWorkDuration = targetWorkDuration; + mHintSessionWrapper->updateTargetWorkDuration(targetWorkDuration); } + int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime; + int64_t actualDuration = frameDuration - + (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - + dequeueBufferDuration; + if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) { + mHintSessionWrapper->reportActualWorkDuration(actualDuration); + } + mLastDequeueBufferDuration = dequeueBufferDuration; } @@ -210,6 +263,44 @@ void DrawFrameTask::unblockUiThread() { mSignal.signal(); } +DrawFrameTask::HintSessionWrapper::HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId) { + if (!Properties::useHintManager) return; + if (uiThreadId < 0 || renderThreadId < 0) return; + + ensureAPerformanceHintBindingInitialized(); + + APerformanceHintManager* manager = gAPH_getManagerFn(); + if (!manager) return; + + std::vector<int32_t> tids = CommonPool::getThreadIds(); + tids.push_back(uiThreadId); + tids.push_back(renderThreadId); + + // DrawFrameTask code will always set a target duration before reporting actual durations. + // So this is just a placeholder value that's never used. + int64_t dummyTargetDurationNanos = 16666667; + mHintSession = + gAPH_createSessionFn(manager, tids.data(), tids.size(), dummyTargetDurationNanos); +} + +DrawFrameTask::HintSessionWrapper::~HintSessionWrapper() { + if (mHintSession) { + gAPH_closeSessionFn(mHintSession); + } +} + +void DrawFrameTask::HintSessionWrapper::updateTargetWorkDuration(long targetDurationNanos) { + if (mHintSession) { + gAPH_updateTargetWorkDurationFn(mHintSession, targetDurationNanos); + } +} + +void DrawFrameTask::HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) { + if (mHintSession) { + gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos); + } +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index 2455ea84c94e..6a61a2bb645f 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -16,8 +16,10 @@ #ifndef DRAWFRAMETASK_H #define DRAWFRAMETASK_H +#include <optional> #include <vector> +#include <performance_hint_private.h> #include <utils/Condition.h> #include <utils/Mutex.h> #include <utils/StrongPointer.h> @@ -60,9 +62,8 @@ public: DrawFrameTask(); virtual ~DrawFrameTask(); - void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode); - void setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration, - std::function<void(int64_t)> reportActualWorkDuration); + void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode, + int32_t uiThreadId, int32_t renderThreadId); void setContentDrawBounds(int left, int top, int right, int bottom) { mContentDrawBounds.set(left, top, right, bottom); } @@ -85,6 +86,18 @@ public: } private: + class HintSessionWrapper { + public: + HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId); + ~HintSessionWrapper(); + + void updateTargetWorkDuration(long targetDurationNanos); + void reportActualWorkDuration(long actualDurationNanos); + + private: + APerformanceHintSession* mHintSession = nullptr; + }; + void postAndWait(); bool syncFrameState(TreeInfo& info); void unblockUiThread(); @@ -95,6 +108,8 @@ private: RenderThread* mRenderThread; CanvasContext* mContext; RenderNode* mTargetNode = nullptr; + int32_t mUiThreadId = -1; + int32_t mRenderThreadId = -1; Rect mContentDrawBounds; /********************************************* @@ -112,8 +127,7 @@ private: nsecs_t mLastDequeueBufferDuration = 0; nsecs_t mLastTargetWorkDuration = 0; - std::function<void(int64_t)> mUpdateTargetWorkDuration; - std::function<void(int64_t)> mReportActualWorkDuration; + std::optional<HintSessionWrapper> mHintSessionWrapper; }; } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index a77b5b569907..c485ce2781e5 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -29,6 +29,8 @@ #include "utils/Macros.h" #include "utils/TimeUtils.h" +#include <pthread.h> + namespace android { namespace uirenderer { namespace renderthread { @@ -39,7 +41,8 @@ RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* { return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory); }); - mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode); + mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode, + pthread_gettid_np(pthread_self()), getRenderThreadTid()); } RenderProxy::~RenderProxy() { @@ -48,7 +51,7 @@ RenderProxy::~RenderProxy() { void RenderProxy::destroyContext() { if (mContext) { - mDrawFrameTask.setContext(nullptr, nullptr, nullptr); + mDrawFrameTask.setContext(nullptr, nullptr, nullptr, -1, -1); // This is also a fence as we need to be certain that there are no // outstanding mDrawFrame tasks posted before it is destroyed mRenderThread.queue().runSync([this]() { delete mContext; }); @@ -76,12 +79,6 @@ void RenderProxy::setName(const char* name) { mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); }); } -void RenderProxy::setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration, - std::function<void(int64_t)> reportActualWorkDuration) { - mDrawFrameTask.setHintSessionCallbacks(std::move(updateTargetWorkDuration), - std::move(reportActualWorkDuration)); -} - void RenderProxy::setSurface(ANativeWindow* window, bool enableTimeout) { if (window) { ANativeWindow_acquire(window); } mRenderThread.queue().post([this, win = window, enableTimeout]() mutable { diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 1b0f22e75a2d..2b5405c82563 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -71,8 +71,6 @@ public: void setSwapBehavior(SwapBehavior swapBehavior); bool loadSystemProperties(); void setName(const char* name); - void setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration, - std::function<void(int64_t)> reportActualWorkDuration); void setSurface(ANativeWindow* window, bool enableTimeout = true); void setSurfaceControl(ASurfaceControl* surfaceControl); diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index f70149111116..9e8a1e141fe1 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -579,7 +579,9 @@ void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) std::lock_guard<std::mutex> lock(mGraphicsQueueMutex); mQueueWaitIdle(mGraphicsQueue); } - destroy_semaphore(mDestroySemaphoreContext); + if (mDestroySemaphoreContext) { + destroy_semaphore(mDestroySemaphoreContext); + } surface->presentCurrentBuffer(dirtyRect, fenceFd); mSwapSemaphore = VK_NULL_HANDLE; |