summaryrefslogtreecommitdiff
path: root/libs/hwui/renderthread/DrawFrameTask.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/renderthread/DrawFrameTask.cpp')
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp145
1 files changed, 139 insertions, 6 deletions
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 1e593388d063..e7081df2b558 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -16,19 +16,74 @@
#include "DrawFrameTask.h"
+#include <dlfcn.h>
+#include <gui/TraceUtils.h>
#include <utils/Log.h>
-#include <utils/Trace.h>
+#include <algorithm>
#include "../DeferredLayerUpdater.h"
#include "../DisplayList.h"
+#include "../Properties.h"
#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)
@@ -37,11 +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;
+ mUiThreadId = uiThreadId;
+ mRenderThreadId = renderThreadId;
}
void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
@@ -82,7 +139,9 @@ void DrawFrameTask::postAndWait() {
}
void DrawFrameTask::run() {
- ATRACE_NAME("DrawFrame");
+ const int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)];
+ ATRACE_FORMAT("DrawFrames %" PRId64, vsyncId);
+ nsecs_t syncDelayDuration = systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued;
bool canUnblockUiThread;
bool canDrawThisFrame;
@@ -101,6 +160,9 @@ void DrawFrameTask::run() {
CanvasContext* context = mContext;
std::function<void(int64_t)> callback = std::move(mFrameCallback);
mFrameCallback = nullptr;
+ int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)];
+ int64_t frameDeadline = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameDeadline)];
+ int64_t frameStartTime = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameStartTime)];
// From this point on anything in "this" is *UNSAFE TO ACCESS*
if (canUnblockUiThread) {
@@ -113,9 +175,16 @@ void DrawFrameTask::run() {
[callback, frameNr = context->getFrameNumber()]() { callback(frameNr); });
}
+ nsecs_t dequeueBufferDuration = 0;
if (CC_LIKELY(canDrawThisFrame)) {
- context->draw();
+ 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();
}
@@ -123,12 +192,38 @@ void DrawFrameTask::run() {
if (!canUnblockUiThread) {
unblockUiThread();
}
+
+ 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;
}
bool DrawFrameTask::syncFrameState(TreeInfo& info) {
ATRACE_CALL();
int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
- mRenderThread->timeLord().vsyncReceived(vsync);
+ int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)];
+ int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)];
+ int64_t frameDeadline = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameDeadline)];
+ int64_t frameInterval = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameInterval)];
+ mRenderThread->timeLord().vsyncReceived(vsync, intendedVsync, vsyncId, frameDeadline,
+ frameInterval);
bool canDraw = mContext->makeCurrent();
mContext->unpinImages();
@@ -168,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 */