Loading libs/hwui/FrameInfoVisualizer.cpp +30 −20 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include "IProfileRenderer.h" #include "utils/Color.h" #include "utils/TimeUtils.h" #include <cutils/compiler.h> #include <array> Loading @@ -26,22 +27,24 @@ #define RETURN_IF_DISABLED() \ if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return #define PROFILE_DRAW_WIDTH 3 #define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2 #define PROFILE_DRAW_DP_PER_MS 7 namespace android { namespace uirenderer { // Must be NUM_ELEMENTS in size static const SkColor THRESHOLD_COLOR = Color::Green_500; static const SkColor BAR_FAST_MASK = 0x8FFFFFFF; static const SkColor BAR_JANKY_MASK = 0xDFFFFFFF; static constexpr auto PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2; static constexpr auto PROFILE_DRAW_DP_PER_MS = 7; struct Threshold { SkColor color; float percentFrametime; }; // We could get this from TimeLord and use the actual frame interval, but // this is good enough #define FRAME_THRESHOLD 16 #define FRAME_THRESHOLD_NS 16000000 static constexpr std::array<Threshold, 3> THRESHOLDS{ Threshold{.color = Color::Green_500, .percentFrametime = 0.8f}, Threshold{.color = Color::Lime_500, .percentFrametime = 1.0f}, Threshold{.color = Color::Red_500, .percentFrametime = 1.5f}, }; static constexpr SkColor BAR_FAST_MASK = 0x8FFFFFFF; static constexpr SkColor BAR_JANKY_MASK = 0xDFFFFFFF; struct BarSegment { FrameInfoIndex start; Loading @@ -64,7 +67,8 @@ static int dpToPx(int dp, float density) { return (int)(dp * density + 0.5f); } FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source) : mFrameSource(source) { FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source, nsecs_t frameInterval) : mFrameSource(source), mFrameInterval(frameInterval) { setDensity(1); consumeProperties(); } Loading @@ -76,7 +80,10 @@ FrameInfoVisualizer::~FrameInfoVisualizer() { void FrameInfoVisualizer::setDensity(float density) { if (CC_UNLIKELY(mDensity != density)) { mDensity = density; mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density); // We want the vertical units to scale height relative to a baseline 16ms. // This keeps the threshold lines consistent across varying refresh rates mVerticalUnit = static_cast<int>(dpToPx(PROFILE_DRAW_DP_PER_MS, density) * (float)16_ms / (float)mFrameInterval); mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density); } } Loading Loading @@ -148,7 +155,7 @@ void FrameInfoVisualizer::initializeRects(const int baseline, const int width) { float* rect; int ri; // Rects are LTRB if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) { if (mFrameSource[fi].totalDuration() <= mFrameInterval) { rect = mFastRects.get(); ri = fast_i; fast_i += 4; Loading Loading @@ -181,7 +188,7 @@ void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex en float* rect; int ri; // Rects are LTRB if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) { if (mFrameSource[fi].totalDuration() <= mFrameInterval) { rect = mFastRects.get(); ri = fast_i; fast_i -= 4; Loading Loading @@ -211,11 +218,14 @@ void FrameInfoVisualizer::drawGraph(IProfileRenderer& renderer) { void FrameInfoVisualizer::drawThreshold(IProfileRenderer& renderer) { SkPaint paint; paint.setColor(THRESHOLD_COLOR); float yLocation = renderer.getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit); for (auto& t : THRESHOLDS) { paint.setColor(t.color); float yLocation = renderer.getViewportHeight() - (ns2ms(mFrameInterval) * t.percentFrametime * mVerticalUnit); renderer.drawRect(0.0f, yLocation - mThresholdStroke / 2, renderer.getViewportWidth(), yLocation + mThresholdStroke / 2, paint); } } bool FrameInfoVisualizer::consumeProperties() { bool changed = false; Loading libs/hwui/FrameInfoVisualizer.h +2 −1 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ typedef RingBuffer<FrameInfo, 120> FrameInfoSource; class FrameInfoVisualizer { public: explicit FrameInfoVisualizer(FrameInfoSource& source); explicit FrameInfoVisualizer(FrameInfoSource& source, nsecs_t frameInterval); ~FrameInfoVisualizer(); bool consumeProperties(); Loading Loading @@ -71,6 +71,7 @@ private: FrameInfoSource& mFrameSource; nsecs_t mFrameInterval; int mVerticalUnit = 0; int mThresholdStroke = 0; Loading libs/hwui/renderthread/CanvasContext.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -103,7 +103,7 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* , mOpaque(!translucent) , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord())) , mJankTracker(&thread.globalProfileData(), thread.mainDisplayInfo()) , mProfiler(mJankTracker.frames()) , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos()) , mContentDrawBounds(0, 0, 0, 0) , mRenderPipeline(std::move(renderPipeline)) { rootRenderNode->makeRoot(); Loading libs/hwui/renderthread/RenderThread.cpp +2 −4 Original line number Diff line number Diff line Loading @@ -52,9 +52,6 @@ namespace renderthread { // using just a few large reads. static const size_t EVENT_BUFFER_SIZE = 100; // Slight delay to give the UI time to push us a new frame before we replay static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4); static bool gHasRenderThreadInstance = false; static JVMAttachHook gOnStartHook = nullptr; Loading Loading @@ -171,6 +168,7 @@ void RenderThread::initThreadLocals() { mDisplayInfo = DeviceInfo::get()->displayInfo(); nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps); mTimeLord.setFrameInterval(frameIntervalNanos); mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f); initializeDisplayEventReceiver(); mEglManager = new EglManager(); mRenderState = new RenderState(*this); Loading Loading @@ -311,7 +309,7 @@ void RenderThread::drainDisplayEventQueue() { if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) { ATRACE_NAME("queue mFrameCallbackTask"); mFrameCallbackTaskPending = true; nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY); nsecs_t runAt = (vsyncEvent + mDispatchFrameDelay); queue().postAt(runAt, [this]() { dispatchFrameCallbacks(); }); } } Loading libs/hwui/renderthread/RenderThread.h +2 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include "TimeLord.h" #include "thread/ThreadBase.h" #include "WebViewFunctorManager.h" #include "utils/TimeUtils.h" #include <GrContext.h> #include <SkBitmap.h> Loading Loading @@ -164,6 +165,7 @@ private: bool mFrameCallbackTaskPending; TimeLord mTimeLord; nsecs_t mDispatchFrameDelay = 4_ms; RenderState* mRenderState; EglManager* mEglManager; WebViewFunctorManager& mFunctorManager; Loading Loading
libs/hwui/FrameInfoVisualizer.cpp +30 −20 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include "IProfileRenderer.h" #include "utils/Color.h" #include "utils/TimeUtils.h" #include <cutils/compiler.h> #include <array> Loading @@ -26,22 +27,24 @@ #define RETURN_IF_DISABLED() \ if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return #define PROFILE_DRAW_WIDTH 3 #define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2 #define PROFILE_DRAW_DP_PER_MS 7 namespace android { namespace uirenderer { // Must be NUM_ELEMENTS in size static const SkColor THRESHOLD_COLOR = Color::Green_500; static const SkColor BAR_FAST_MASK = 0x8FFFFFFF; static const SkColor BAR_JANKY_MASK = 0xDFFFFFFF; static constexpr auto PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2; static constexpr auto PROFILE_DRAW_DP_PER_MS = 7; struct Threshold { SkColor color; float percentFrametime; }; // We could get this from TimeLord and use the actual frame interval, but // this is good enough #define FRAME_THRESHOLD 16 #define FRAME_THRESHOLD_NS 16000000 static constexpr std::array<Threshold, 3> THRESHOLDS{ Threshold{.color = Color::Green_500, .percentFrametime = 0.8f}, Threshold{.color = Color::Lime_500, .percentFrametime = 1.0f}, Threshold{.color = Color::Red_500, .percentFrametime = 1.5f}, }; static constexpr SkColor BAR_FAST_MASK = 0x8FFFFFFF; static constexpr SkColor BAR_JANKY_MASK = 0xDFFFFFFF; struct BarSegment { FrameInfoIndex start; Loading @@ -64,7 +67,8 @@ static int dpToPx(int dp, float density) { return (int)(dp * density + 0.5f); } FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source) : mFrameSource(source) { FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source, nsecs_t frameInterval) : mFrameSource(source), mFrameInterval(frameInterval) { setDensity(1); consumeProperties(); } Loading @@ -76,7 +80,10 @@ FrameInfoVisualizer::~FrameInfoVisualizer() { void FrameInfoVisualizer::setDensity(float density) { if (CC_UNLIKELY(mDensity != density)) { mDensity = density; mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density); // We want the vertical units to scale height relative to a baseline 16ms. // This keeps the threshold lines consistent across varying refresh rates mVerticalUnit = static_cast<int>(dpToPx(PROFILE_DRAW_DP_PER_MS, density) * (float)16_ms / (float)mFrameInterval); mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density); } } Loading Loading @@ -148,7 +155,7 @@ void FrameInfoVisualizer::initializeRects(const int baseline, const int width) { float* rect; int ri; // Rects are LTRB if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) { if (mFrameSource[fi].totalDuration() <= mFrameInterval) { rect = mFastRects.get(); ri = fast_i; fast_i += 4; Loading Loading @@ -181,7 +188,7 @@ void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex en float* rect; int ri; // Rects are LTRB if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) { if (mFrameSource[fi].totalDuration() <= mFrameInterval) { rect = mFastRects.get(); ri = fast_i; fast_i -= 4; Loading Loading @@ -211,11 +218,14 @@ void FrameInfoVisualizer::drawGraph(IProfileRenderer& renderer) { void FrameInfoVisualizer::drawThreshold(IProfileRenderer& renderer) { SkPaint paint; paint.setColor(THRESHOLD_COLOR); float yLocation = renderer.getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit); for (auto& t : THRESHOLDS) { paint.setColor(t.color); float yLocation = renderer.getViewportHeight() - (ns2ms(mFrameInterval) * t.percentFrametime * mVerticalUnit); renderer.drawRect(0.0f, yLocation - mThresholdStroke / 2, renderer.getViewportWidth(), yLocation + mThresholdStroke / 2, paint); } } bool FrameInfoVisualizer::consumeProperties() { bool changed = false; Loading
libs/hwui/FrameInfoVisualizer.h +2 −1 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ typedef RingBuffer<FrameInfo, 120> FrameInfoSource; class FrameInfoVisualizer { public: explicit FrameInfoVisualizer(FrameInfoSource& source); explicit FrameInfoVisualizer(FrameInfoSource& source, nsecs_t frameInterval); ~FrameInfoVisualizer(); bool consumeProperties(); Loading Loading @@ -71,6 +71,7 @@ private: FrameInfoSource& mFrameSource; nsecs_t mFrameInterval; int mVerticalUnit = 0; int mThresholdStroke = 0; Loading
libs/hwui/renderthread/CanvasContext.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -103,7 +103,7 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* , mOpaque(!translucent) , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord())) , mJankTracker(&thread.globalProfileData(), thread.mainDisplayInfo()) , mProfiler(mJankTracker.frames()) , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos()) , mContentDrawBounds(0, 0, 0, 0) , mRenderPipeline(std::move(renderPipeline)) { rootRenderNode->makeRoot(); Loading
libs/hwui/renderthread/RenderThread.cpp +2 −4 Original line number Diff line number Diff line Loading @@ -52,9 +52,6 @@ namespace renderthread { // using just a few large reads. static const size_t EVENT_BUFFER_SIZE = 100; // Slight delay to give the UI time to push us a new frame before we replay static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4); static bool gHasRenderThreadInstance = false; static JVMAttachHook gOnStartHook = nullptr; Loading Loading @@ -171,6 +168,7 @@ void RenderThread::initThreadLocals() { mDisplayInfo = DeviceInfo::get()->displayInfo(); nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps); mTimeLord.setFrameInterval(frameIntervalNanos); mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f); initializeDisplayEventReceiver(); mEglManager = new EglManager(); mRenderState = new RenderState(*this); Loading Loading @@ -311,7 +309,7 @@ void RenderThread::drainDisplayEventQueue() { if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) { ATRACE_NAME("queue mFrameCallbackTask"); mFrameCallbackTaskPending = true; nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY); nsecs_t runAt = (vsyncEvent + mDispatchFrameDelay); queue().postAt(runAt, [this]() { dispatchFrameCallbacks(); }); } } Loading
libs/hwui/renderthread/RenderThread.h +2 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include "TimeLord.h" #include "thread/ThreadBase.h" #include "WebViewFunctorManager.h" #include "utils/TimeUtils.h" #include <GrContext.h> #include <SkBitmap.h> Loading Loading @@ -164,6 +165,7 @@ private: bool mFrameCallbackTaskPending; TimeLord mTimeLord; nsecs_t mDispatchFrameDelay = 4_ms; RenderState* mRenderState; EglManager* mEglManager; WebViewFunctorManager& mFunctorManager; Loading