summaryrefslogtreecommitdiffstats
path: root/libs/hwui/FrameInfoVisualizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/FrameInfoVisualizer.cpp')
-rw-r--r--libs/hwui/FrameInfoVisualizer.cpp163
1 files changed, 107 insertions, 56 deletions
diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp
index 0411742..5b81ac9 100644
--- a/libs/hwui/FrameInfoVisualizer.cpp
+++ b/libs/hwui/FrameInfoVisualizer.cpp
@@ -18,6 +18,7 @@
#include "OpenGLRenderer.h"
#include <cutils/compiler.h>
+#include <array>
#define RETURN_IF_PROFILING_DISABLED() if (CC_LIKELY(mType == ProfileType::None)) return
#define RETURN_IF_DISABLED() if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
@@ -26,27 +27,36 @@
#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
#define PROFILE_DRAW_DP_PER_MS 7
-// Number of floats we want to display from FrameTimingData
-// If this is changed make sure to update the indexes below
-#define NUM_ELEMENTS 4
-
-#define RECORD_INDEX 0
-#define PREPARE_INDEX 1
-#define PLAYBACK_INDEX 2
-#define SWAPBUFFERS_INDEX 3
-
// Must be NUM_ELEMENTS in size
-static const SkColor ELEMENT_COLORS[] = { 0xcf3e66cc, 0xcf8f00ff, 0xcfdc3912, 0xcfe69800 };
static const SkColor CURRENT_FRAME_COLOR = 0xcf5faa4d;
static const SkColor THRESHOLD_COLOR = 0xff5faa4d;
+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 {
+struct BarSegment {
+ FrameInfoIndex start;
+ FrameInfoIndex end;
+ SkColor color;
+};
+
+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},
+ { FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, 0xFF9800},
+}};
+
static int dpToPx(int dp, float density) {
return (int) (dp * density + 0.5f);
}
@@ -64,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);
}
}
@@ -93,67 +102,107 @@ void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) {
}
if (mType == ProfileType::Bars) {
- prepareShapes(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);
drawThreshold(canvas);
}
}
void FrameInfoVisualizer::createData() {
- if (mRects.get()) return;
+ if (mFastRects.get()) return;
- mRects.reset(new float*[mFrameSource.capacity()]);
- for (int i = 0; i < NUM_ELEMENTS; i++) {
- // 4 floats per rect
- mRects.get()[i] = (float*) calloc(mFrameSource.capacity(), 4 * sizeof(float));
- }
+ 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::addRect(Rect& r, float data, float* shapeOutput) {
- r.top = r.bottom - (data * mVerticalUnit);
- shapeOutput[0] = r.left;
- shapeOutput[1] = r.top;
- shapeOutput[2] = r.right;
- shapeOutput[3] = r.bottom;
- r.bottom = r.top;
-}
+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 (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
+ 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;
+ }
-void FrameInfoVisualizer::prepareShapes(const int baseline) {
- Rect r;
- r.right = mHorizontalUnit;
- for (size_t i = 0; i < mFrameSource.size(); i++) {
- const int shapeIndex = i * 4;
- r.bottom = baseline;
- addRect(r, recordDuration(i), mRects.get()[RECORD_INDEX] + shapeIndex);
- addRect(r, prepareDuration(i), mRects.get()[PREPARE_INDEX] + shapeIndex);
- addRect(r, issueDrawDuration(i), mRects.get()[PLAYBACK_INDEX] + shapeIndex);
- addRect(r, swapBuffersDuration(i), mRects.get()[SWAPBUFFERS_INDEX] + shapeIndex);
- r.translate(mHorizontalUnit, 0);
+ rect[ri + 0] = right - lineWidth;
+ rect[ri + 1] = baseline;
+ rect[ri + 2] = right;
+ rect[ri + 3] = baseline;
+ right -= lineWidth;
}
}
-void FrameInfoVisualizer::drawGraph(OpenGLRenderer* canvas) {
- SkPaint paint;
- for (int i = 0; i < NUM_ELEMENTS; i++) {
- paint.setColor(ELEMENT_COLORS[i]);
- canvas->drawRects(mRects.get()[i], mFrameSource.capacity() * 4, &paint);
+void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex end) {
+ 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)
+ rect[ri + 3] = rect[ri + 1];
+ // Move the top up by the duration
+ rect[ri + 1] -= mVerticalUnit * duration(fi, start, end);
}
}
-void FrameInfoVisualizer::drawCurrentFrame(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
+void FrameInfoVisualizer::drawGraph(OpenGLRenderer* canvas) {
SkPaint paint;
- paint.setColor(CURRENT_FRAME_COLOR);
- const int i = (mFrameSource.size() - 1) * 4;
- canvas->drawRect(mRects.get()[0][i], mRects.get()[NUM_ELEMENTS-1][i+1],
- mRects.get()[0][i+2], mRects.get()[0][i+3], &paint);
+ for (size_t i = 0; i < Bar.size(); i++) {
+ nextBarSegment(Bar[i].start, Bar[i].end);
+ 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::drawThreshold(OpenGLRenderer* canvas) {
@@ -200,13 +249,15 @@ void FrameInfoVisualizer::dumpData(int fd) {
fprintf(file, "\n\tDraw\tPrepare\tProcess\tExecute\n");
for (size_t i = 0; i < mFrameSource.size(); i++) {
- if (mFrameSource[i][FrameInfoIndex::kIntendedVsync] <= mLastFrameLogged) {
+ if (mFrameSource[i][FrameInfoIndex::IntendedVsync] <= mLastFrameLogged) {
continue;
}
- mLastFrameLogged = mFrameSource[i][FrameInfoIndex::kIntendedVsync];
+ mLastFrameLogged = mFrameSource[i][FrameInfoIndex::IntendedVsync];
fprintf(file, "\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n",
- recordDuration(i), prepareDuration(i),
- issueDrawDuration(i), swapBuffersDuration(i));
+ duration(i, FrameInfoIndex::IntendedVsync, FrameInfoIndex::SyncStart),
+ duration(i, FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart),
+ duration(i, FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers),
+ duration(i, FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted));
}
fflush(file);