Loading libs/hwui/FrameInfo.h +14 −2 Original line number Diff line number Diff line Loading @@ -116,16 +116,28 @@ public: set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag); } int64_t operator[](FrameInfoIndex index) const { inline int64_t operator[](FrameInfoIndex index) const { if (index == FrameInfoIndex::NumIndexes) return 0; return mFrameInfo[static_cast<int>(index)]; } int64_t operator[](int index) const { inline int64_t operator[](int index) const { if (index < 0 || index >= static_cast<int>(FrameInfoIndex::NumIndexes)) return 0; return mFrameInfo[index]; } inline int64_t duration(FrameInfoIndex start, FrameInfoIndex end) const { int64_t endtime = mFrameInfo[static_cast<int>(end)]; int64_t starttime = mFrameInfo[static_cast<int>(start)]; int64_t gap = endtime - starttime; gap = starttime > 0 ? gap : 0; return gap > 0 ? gap : 0; } inline int64_t totalDuration() const { return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted); } private: inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; Loading libs/hwui/FrameInfoVisualizer.cpp +76 −41 Original line number Diff line number Diff line Loading @@ -30,11 +30,13 @@ // Must be NUM_ELEMENTS in size static const SkColor CURRENT_FRAME_COLOR = 0xcf5faa4d; static const SkColor THRESHOLD_COLOR = 0xff5faa4d; static const SkColor BAR_ALPHA = 0xCF000000; static const SkColor BAR_FAST_ALPHA = 0x8F000000; static const SkColor BAR_JANKY_ALPHA = 0xDF000000; // 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 namespace android { namespace uirenderer { Loading @@ -45,12 +47,10 @@ struct BarSegment { SkColor color; }; static const std::array<BarSegment,9> Bar {{ { FrameInfoIndex::IntendedVsync, FrameInfoIndex::Vsync, 0x00695C }, { FrameInfoIndex::Vsync, FrameInfoIndex::HandleInputStart, 0x00796B }, { FrameInfoIndex::HandleInputStart, FrameInfoIndex::AnimationStart, 0x00897B }, { FrameInfoIndex::AnimationStart, FrameInfoIndex::PerformTraversalsStart, 0x009688 }, { FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, 0x26A69A}, static const std::array<BarSegment,7> Bar {{ { FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, 0x00796B }, { FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart, 0x388E3C }, { FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, 0x689F38}, { FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, 0x2196F3}, { FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, 0x4FC3F7}, { FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, 0xF44336}, Loading @@ -74,7 +74,6 @@ void FrameInfoVisualizer::setDensity(float density) { if (CC_UNLIKELY(mDensity != density)) { mDensity = density; mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density); mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density); mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density); } } Loading Loading @@ -103,73 +102,109 @@ void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) { } if (mType == ProfileType::Bars) { initializeRects(canvas->getViewportHeight()); // Patch up the current frame to pretend we ended here. CanvasContext // will overwrite these values with the real ones after we return. // This is a bit nicer looking than the vague green bar, as we have // valid data for almost all the stages and a very good idea of what // the issue stage will look like, too FrameInfo& info = mFrameSource.back(); info.markSwapBuffers(); info.markFrameCompleted(); initializeRects(canvas->getViewportHeight(), canvas->getViewportWidth()); drawGraph(canvas); drawCurrentFrame(canvas->getViewportHeight(), canvas); drawThreshold(canvas); } } void FrameInfoVisualizer::createData() { if (mRects.get()) return; if (mFastRects.get()) return; mRects.reset(new float[mFrameSource.capacity() * 4]); mFastRects.reset(new float[mFrameSource.capacity() * 4]); mJankyRects.reset(new float[mFrameSource.capacity() * 4]); } void FrameInfoVisualizer::destroyData() { mRects.reset(nullptr); mFastRects.reset(nullptr); mJankyRects.reset(nullptr); } void FrameInfoVisualizer::initializeRects(const int baseline) { float left = 0; void FrameInfoVisualizer::initializeRects(const int baseline, const int width) { // Target the 95% mark for the current frame float right = width * .95; float baseLineWidth = right / mFrameSource.capacity(); mNumFastRects = 0; mNumJankyRects = 0; int fast_i = 0, janky_i = 0; // Set the bottom of all the shapes to the baseline for (size_t i = 0; i < (mFrameSource.capacity() * 4); i += 4) { for (int fi = mFrameSource.size() - 1; fi >= 0; fi--) { if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) { continue; } float lineWidth = baseLineWidth; float* rect; int ri; // Rects are LTRB mRects[i + 0] = left; mRects[i + 1] = baseline; left += mHorizontalUnit; mRects[i + 2] = left; mRects[i + 3] = baseline; if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) { rect = mFastRects.get(); ri = fast_i; fast_i += 4; mNumFastRects++; } else { rect = mJankyRects.get(); ri = janky_i; janky_i += 4; mNumJankyRects++; lineWidth *= 2; } rect[ri + 0] = right - lineWidth; rect[ri + 1] = baseline; rect[ri + 2] = right; rect[ri + 3] = baseline; right -= lineWidth; } } void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex end) { for (size_t fi = 0, ri = 0; fi < mFrameSource.size(); fi++, ri += 4) { // TODO: Skipped frames will leave little holes in the graph, but this // is better than bogus and freaky lines, so... int fast_i = (mNumFastRects - 1) * 4; int janky_i = (mNumJankyRects - 1) * 4;; for (size_t fi = 0; fi < mFrameSource.size(); fi++) { if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) { continue; } float* rect; int ri; // Rects are LTRB if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) { rect = mFastRects.get(); ri = fast_i; fast_i -= 4; } else { rect = mJankyRects.get(); ri = janky_i; janky_i -= 4; } // Set the bottom to the old top (build upwards) mRects[ri + 3] = mRects[ri + 1]; rect[ri + 3] = rect[ri + 1]; // Move the top up by the duration mRects[ri + 1] -= mVerticalUnit * duration(fi, start, end); rect[ri + 1] -= mVerticalUnit * duration(fi, start, end); } } void FrameInfoVisualizer::drawGraph(OpenGLRenderer* canvas) { SkPaint paint; for (size_t i = 0; i < Bar.size(); i++) { paint.setColor(Bar[i].color | BAR_ALPHA); nextBarSegment(Bar[i].start, Bar[i].end); canvas->drawRects(mRects.get(), (mFrameSource.size() - 1) * 4, &paint); paint.setColor(Bar[i].color | BAR_FAST_ALPHA); canvas->drawRects(mFastRects.get(), mNumFastRects * 4, &paint); paint.setColor(Bar[i].color | BAR_JANKY_ALPHA); canvas->drawRects(mJankyRects.get(), mNumJankyRects * 4, &paint); } } void FrameInfoVisualizer::drawCurrentFrame(const int baseline, OpenGLRenderer* canvas) { // This draws a solid rect over the entirety of the current frame's shape // To do so we use the bottom of mRects[0] and the top of mRects[NUM_ELEMENTS-1] // which will therefore fully overlap the previously drawn rects SkPaint paint; paint.setColor(CURRENT_FRAME_COLOR); size_t fi = mFrameSource.size() - 1; size_t ri = fi * 4; float top = baseline - (mVerticalUnit * duration(fi, FrameInfoIndex::IntendedVsync, FrameInfoIndex::IssueDrawCommandsStart)); canvas->drawRect(mRects[ri], top, mRects[ri + 2], baseline, &paint); } void FrameInfoVisualizer::drawThreshold(OpenGLRenderer* canvas) { SkPaint paint; paint.setColor(THRESHOLD_COLOR); Loading libs/hwui/FrameInfoVisualizer.h +5 −11 Original line number Diff line number Diff line Loading @@ -54,10 +54,9 @@ private: void createData(); void destroyData(); void initializeRects(const int baseline); void initializeRects(const int baseline, const int width); void nextBarSegment(FrameInfoIndex start, FrameInfoIndex end); void drawGraph(OpenGLRenderer* canvas); void drawCurrentFrame(const int baseline, OpenGLRenderer* canvas); void drawThreshold(OpenGLRenderer* canvas); inline float duration(size_t index, FrameInfoIndex start, FrameInfoIndex end) { Loading @@ -75,17 +74,12 @@ private: FrameInfoSource& mFrameSource; int mVerticalUnit = 0; int mHorizontalUnit = 0; int mThresholdStroke = 0; /* * mRects represents an array of rect shapes, divided into NUM_ELEMENTS * groups such that each group is drawn with the same paint. * For example mRects[0] is the array of rect floats suitable for * OpenGLRenderer:drawRects() that makes up all the FrameTimingData:record * information. */ std::unique_ptr<float[]> mRects; int mNumFastRects; std::unique_ptr<float[]> mFastRects; int mNumJankyRects; std::unique_ptr<float[]> mJankyRects; bool mShowDirtyRegions = false; SkRect mDirtyRegion; Loading libs/hwui/utils/RingBuffer.h +2 −2 Original line number Diff line number Diff line Loading @@ -43,11 +43,11 @@ public: } T& front() { return this[0]; return (*this)[0]; } T& back() { return this[size() - 1]; return (*this)[size() - 1]; } T& operator[](size_t index) { Loading Loading
libs/hwui/FrameInfo.h +14 −2 Original line number Diff line number Diff line Loading @@ -116,16 +116,28 @@ public: set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag); } int64_t operator[](FrameInfoIndex index) const { inline int64_t operator[](FrameInfoIndex index) const { if (index == FrameInfoIndex::NumIndexes) return 0; return mFrameInfo[static_cast<int>(index)]; } int64_t operator[](int index) const { inline int64_t operator[](int index) const { if (index < 0 || index >= static_cast<int>(FrameInfoIndex::NumIndexes)) return 0; return mFrameInfo[index]; } inline int64_t duration(FrameInfoIndex start, FrameInfoIndex end) const { int64_t endtime = mFrameInfo[static_cast<int>(end)]; int64_t starttime = mFrameInfo[static_cast<int>(start)]; int64_t gap = endtime - starttime; gap = starttime > 0 ? gap : 0; return gap > 0 ? gap : 0; } inline int64_t totalDuration() const { return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted); } private: inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; Loading
libs/hwui/FrameInfoVisualizer.cpp +76 −41 Original line number Diff line number Diff line Loading @@ -30,11 +30,13 @@ // Must be NUM_ELEMENTS in size static const SkColor CURRENT_FRAME_COLOR = 0xcf5faa4d; static const SkColor THRESHOLD_COLOR = 0xff5faa4d; static const SkColor BAR_ALPHA = 0xCF000000; static const SkColor BAR_FAST_ALPHA = 0x8F000000; static const SkColor BAR_JANKY_ALPHA = 0xDF000000; // 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 namespace android { namespace uirenderer { Loading @@ -45,12 +47,10 @@ struct BarSegment { SkColor color; }; static const std::array<BarSegment,9> Bar {{ { FrameInfoIndex::IntendedVsync, FrameInfoIndex::Vsync, 0x00695C }, { FrameInfoIndex::Vsync, FrameInfoIndex::HandleInputStart, 0x00796B }, { FrameInfoIndex::HandleInputStart, FrameInfoIndex::AnimationStart, 0x00897B }, { FrameInfoIndex::AnimationStart, FrameInfoIndex::PerformTraversalsStart, 0x009688 }, { FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, 0x26A69A}, static const std::array<BarSegment,7> Bar {{ { FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, 0x00796B }, { FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart, 0x388E3C }, { FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, 0x689F38}, { FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, 0x2196F3}, { FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, 0x4FC3F7}, { FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, 0xF44336}, Loading @@ -74,7 +74,6 @@ void FrameInfoVisualizer::setDensity(float density) { if (CC_UNLIKELY(mDensity != density)) { mDensity = density; mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density); mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density); mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density); } } Loading Loading @@ -103,73 +102,109 @@ void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) { } if (mType == ProfileType::Bars) { initializeRects(canvas->getViewportHeight()); // Patch up the current frame to pretend we ended here. CanvasContext // will overwrite these values with the real ones after we return. // This is a bit nicer looking than the vague green bar, as we have // valid data for almost all the stages and a very good idea of what // the issue stage will look like, too FrameInfo& info = mFrameSource.back(); info.markSwapBuffers(); info.markFrameCompleted(); initializeRects(canvas->getViewportHeight(), canvas->getViewportWidth()); drawGraph(canvas); drawCurrentFrame(canvas->getViewportHeight(), canvas); drawThreshold(canvas); } } void FrameInfoVisualizer::createData() { if (mRects.get()) return; if (mFastRects.get()) return; mRects.reset(new float[mFrameSource.capacity() * 4]); mFastRects.reset(new float[mFrameSource.capacity() * 4]); mJankyRects.reset(new float[mFrameSource.capacity() * 4]); } void FrameInfoVisualizer::destroyData() { mRects.reset(nullptr); mFastRects.reset(nullptr); mJankyRects.reset(nullptr); } void FrameInfoVisualizer::initializeRects(const int baseline) { float left = 0; void FrameInfoVisualizer::initializeRects(const int baseline, const int width) { // Target the 95% mark for the current frame float right = width * .95; float baseLineWidth = right / mFrameSource.capacity(); mNumFastRects = 0; mNumJankyRects = 0; int fast_i = 0, janky_i = 0; // Set the bottom of all the shapes to the baseline for (size_t i = 0; i < (mFrameSource.capacity() * 4); i += 4) { for (int fi = mFrameSource.size() - 1; fi >= 0; fi--) { if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) { continue; } float lineWidth = baseLineWidth; float* rect; int ri; // Rects are LTRB mRects[i + 0] = left; mRects[i + 1] = baseline; left += mHorizontalUnit; mRects[i + 2] = left; mRects[i + 3] = baseline; if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) { rect = mFastRects.get(); ri = fast_i; fast_i += 4; mNumFastRects++; } else { rect = mJankyRects.get(); ri = janky_i; janky_i += 4; mNumJankyRects++; lineWidth *= 2; } rect[ri + 0] = right - lineWidth; rect[ri + 1] = baseline; rect[ri + 2] = right; rect[ri + 3] = baseline; right -= lineWidth; } } void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex end) { for (size_t fi = 0, ri = 0; fi < mFrameSource.size(); fi++, ri += 4) { // TODO: Skipped frames will leave little holes in the graph, but this // is better than bogus and freaky lines, so... int fast_i = (mNumFastRects - 1) * 4; int janky_i = (mNumJankyRects - 1) * 4;; for (size_t fi = 0; fi < mFrameSource.size(); fi++) { if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) { continue; } float* rect; int ri; // Rects are LTRB if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) { rect = mFastRects.get(); ri = fast_i; fast_i -= 4; } else { rect = mJankyRects.get(); ri = janky_i; janky_i -= 4; } // Set the bottom to the old top (build upwards) mRects[ri + 3] = mRects[ri + 1]; rect[ri + 3] = rect[ri + 1]; // Move the top up by the duration mRects[ri + 1] -= mVerticalUnit * duration(fi, start, end); rect[ri + 1] -= mVerticalUnit * duration(fi, start, end); } } void FrameInfoVisualizer::drawGraph(OpenGLRenderer* canvas) { SkPaint paint; for (size_t i = 0; i < Bar.size(); i++) { paint.setColor(Bar[i].color | BAR_ALPHA); nextBarSegment(Bar[i].start, Bar[i].end); canvas->drawRects(mRects.get(), (mFrameSource.size() - 1) * 4, &paint); paint.setColor(Bar[i].color | BAR_FAST_ALPHA); canvas->drawRects(mFastRects.get(), mNumFastRects * 4, &paint); paint.setColor(Bar[i].color | BAR_JANKY_ALPHA); canvas->drawRects(mJankyRects.get(), mNumJankyRects * 4, &paint); } } void FrameInfoVisualizer::drawCurrentFrame(const int baseline, OpenGLRenderer* canvas) { // This draws a solid rect over the entirety of the current frame's shape // To do so we use the bottom of mRects[0] and the top of mRects[NUM_ELEMENTS-1] // which will therefore fully overlap the previously drawn rects SkPaint paint; paint.setColor(CURRENT_FRAME_COLOR); size_t fi = mFrameSource.size() - 1; size_t ri = fi * 4; float top = baseline - (mVerticalUnit * duration(fi, FrameInfoIndex::IntendedVsync, FrameInfoIndex::IssueDrawCommandsStart)); canvas->drawRect(mRects[ri], top, mRects[ri + 2], baseline, &paint); } void FrameInfoVisualizer::drawThreshold(OpenGLRenderer* canvas) { SkPaint paint; paint.setColor(THRESHOLD_COLOR); Loading
libs/hwui/FrameInfoVisualizer.h +5 −11 Original line number Diff line number Diff line Loading @@ -54,10 +54,9 @@ private: void createData(); void destroyData(); void initializeRects(const int baseline); void initializeRects(const int baseline, const int width); void nextBarSegment(FrameInfoIndex start, FrameInfoIndex end); void drawGraph(OpenGLRenderer* canvas); void drawCurrentFrame(const int baseline, OpenGLRenderer* canvas); void drawThreshold(OpenGLRenderer* canvas); inline float duration(size_t index, FrameInfoIndex start, FrameInfoIndex end) { Loading @@ -75,17 +74,12 @@ private: FrameInfoSource& mFrameSource; int mVerticalUnit = 0; int mHorizontalUnit = 0; int mThresholdStroke = 0; /* * mRects represents an array of rect shapes, divided into NUM_ELEMENTS * groups such that each group is drawn with the same paint. * For example mRects[0] is the array of rect floats suitable for * OpenGLRenderer:drawRects() that makes up all the FrameTimingData:record * information. */ std::unique_ptr<float[]> mRects; int mNumFastRects; std::unique_ptr<float[]> mFastRects; int mNumJankyRects; std::unique_ptr<float[]> mJankyRects; bool mShowDirtyRegions = false; SkRect mDirtyRegion; Loading
libs/hwui/utils/RingBuffer.h +2 −2 Original line number Diff line number Diff line Loading @@ -43,11 +43,11 @@ public: } T& front() { return this[0]; return (*this)[0]; } T& back() { return this[size() - 1]; return (*this)[size() - 1]; } T& operator[](size_t index) { Loading