summaryrefslogtreecommitdiff
path: root/libs/hwui/renderthread
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/renderthread')
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp147
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.h24
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp13
-rw-r--r--libs/hwui/renderthread/RenderProxy.h2
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp4
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;