blob: 236a6b667f3b95af44cce5128a18b0daee7b517b [file] [log] [blame]
John Reckfe5e7b72014-05-23 17:42:28 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
John Reck4c9e59d2015-05-12 07:17:50 -070016#include "FrameInfoVisualizer.h"
John Reckfe5e7b72014-05-23 17:42:28 -070017
Matt Sarettde973072016-10-25 11:07:40 -040018#include "IProfileRenderer.h"
Chris Craik54fa17f2015-11-25 14:14:53 -080019#include "utils/Color.h"
John Reckfe5e7b72014-05-23 17:42:28 -070020
John Reck4c9e59d2015-05-12 07:17:50 -070021#include <cutils/compiler.h>
John Reckbf3c6022015-06-02 15:55:00 -070022#include <array>
John Reckfe5e7b72014-05-23 17:42:28 -070023
John Reck1bcacfd2017-11-03 10:12:19 -070024#define RETURN_IF_PROFILING_DISABLED() \
25 if (CC_LIKELY(mType == ProfileType::None)) return
26#define RETURN_IF_DISABLED() \
27 if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
John Reckfe5e7b72014-05-23 17:42:28 -070028
John Reckfe5e7b72014-05-23 17:42:28 -070029#define PROFILE_DRAW_WIDTH 3
30#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
31#define PROFILE_DRAW_DP_PER_MS 7
32
Chris Craik54fa17f2015-11-25 14:14:53 -080033namespace android {
34namespace uirenderer {
35
John Reckfe5e7b72014-05-23 17:42:28 -070036// Must be NUM_ELEMENTS in size
Chris Craik54fa17f2015-11-25 14:14:53 -080037static const SkColor THRESHOLD_COLOR = Color::Green_500;
38static const SkColor BAR_FAST_MASK = 0x8FFFFFFF;
39static const SkColor BAR_JANKY_MASK = 0xDFFFFFFF;
John Reckfe5e7b72014-05-23 17:42:28 -070040
41// We could get this from TimeLord and use the actual frame interval, but
42// this is good enough
43#define FRAME_THRESHOLD 16
John Reck41300272015-06-03 14:42:34 -070044#define FRAME_THRESHOLD_NS 16000000
John Reckfe5e7b72014-05-23 17:42:28 -070045
John Reckbf3c6022015-06-02 15:55:00 -070046struct BarSegment {
47 FrameInfoIndex start;
48 FrameInfoIndex end;
49 SkColor color;
50};
51
John Reck1bcacfd2017-11-03 10:12:19 -070052static const std::array<BarSegment, 7> Bar{{
53 {FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, Color::Teal_700},
54 {FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart,
55 Color::Green_700},
56 {FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, Color::LightGreen_700},
57 {FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, Color::Blue_500},
58 {FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, Color::LightBlue_300},
59 {FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, Color::Red_500},
60 {FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, Color::Orange_500},
John Reckbf3c6022015-06-02 15:55:00 -070061}};
62
John Reckfe5e7b72014-05-23 17:42:28 -070063static int dpToPx(int dp, float density) {
John Reck1bcacfd2017-11-03 10:12:19 -070064 return (int)(dp * density + 0.5f);
John Reckfe5e7b72014-05-23 17:42:28 -070065}
66
John Reck1bcacfd2017-11-03 10:12:19 -070067FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source) : mFrameSource(source) {
John Reckfe5e7b72014-05-23 17:42:28 -070068 setDensity(1);
69}
70
John Reck4c9e59d2015-05-12 07:17:50 -070071FrameInfoVisualizer::~FrameInfoVisualizer() {
John Reckfe5e7b72014-05-23 17:42:28 -070072 destroyData();
73}
74
John Reck4c9e59d2015-05-12 07:17:50 -070075void FrameInfoVisualizer::setDensity(float density) {
John Reckfe5e7b72014-05-23 17:42:28 -070076 if (CC_UNLIKELY(mDensity != density)) {
77 mDensity = density;
78 mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
John Reckfe5e7b72014-05-23 17:42:28 -070079 mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
80 }
81}
82
John Reck4c9e59d2015-05-12 07:17:50 -070083void FrameInfoVisualizer::unionDirty(SkRect* dirty) {
John Reckfe5e7b72014-05-23 17:42:28 -070084 RETURN_IF_DISABLED();
85 // Not worth worrying about minimizing the dirty region for debugging, so just
86 // dirty the entire viewport.
87 if (dirty) {
John Reck23d307c2014-10-27 12:38:48 -070088 mDirtyRegion = *dirty;
John Reckfe5e7b72014-05-23 17:42:28 -070089 dirty->setEmpty();
90 }
91}
92
Matt Sarettde973072016-10-25 11:07:40 -040093void FrameInfoVisualizer::draw(IProfileRenderer& renderer) {
John Reck23d307c2014-10-27 12:38:48 -070094 RETURN_IF_DISABLED();
95
96 if (mShowDirtyRegions) {
97 mFlashToggle = !mFlashToggle;
98 if (mFlashToggle) {
99 SkPaint paint;
100 paint.setColor(0x7fff0000);
John Reck1bcacfd2017-11-03 10:12:19 -0700101 renderer.drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop, mDirtyRegion.fRight,
102 mDirtyRegion.fBottom, paint);
John Reck23d307c2014-10-27 12:38:48 -0700103 }
John Reckfe5e7b72014-05-23 17:42:28 -0700104 }
105
Chris Craik2507c342015-05-04 14:36:49 -0700106 if (mType == ProfileType::Bars) {
John Reck41300272015-06-03 14:42:34 -0700107 // Patch up the current frame to pretend we ended here. CanvasContext
108 // will overwrite these values with the real ones after we return.
109 // This is a bit nicer looking than the vague green bar, as we have
110 // valid data for almost all the stages and a very good idea of what
111 // the issue stage will look like, too
112 FrameInfo& info = mFrameSource.back();
113 info.markSwapBuffers();
114 info.markFrameCompleted();
115
Matt Sarettde973072016-10-25 11:07:40 -0400116 initializeRects(renderer.getViewportHeight(), renderer.getViewportWidth());
Chris Craik1dfa0702016-03-04 15:59:24 -0800117 drawGraph(renderer);
118 drawThreshold(renderer);
John Reck23d307c2014-10-27 12:38:48 -0700119 }
John Reckfe5e7b72014-05-23 17:42:28 -0700120}
121
John Reck4c9e59d2015-05-12 07:17:50 -0700122void FrameInfoVisualizer::createData() {
John Reck41300272015-06-03 14:42:34 -0700123 if (mFastRects.get()) return;
John Reckfe5e7b72014-05-23 17:42:28 -0700124
John Reck41300272015-06-03 14:42:34 -0700125 mFastRects.reset(new float[mFrameSource.capacity() * 4]);
126 mJankyRects.reset(new float[mFrameSource.capacity() * 4]);
John Reckfe5e7b72014-05-23 17:42:28 -0700127}
128
John Reck4c9e59d2015-05-12 07:17:50 -0700129void FrameInfoVisualizer::destroyData() {
John Reck41300272015-06-03 14:42:34 -0700130 mFastRects.reset(nullptr);
131 mJankyRects.reset(nullptr);
John Reckfe5e7b72014-05-23 17:42:28 -0700132}
133
John Reck41300272015-06-03 14:42:34 -0700134void FrameInfoVisualizer::initializeRects(const int baseline, const int width) {
135 // Target the 95% mark for the current frame
136 float right = width * .95;
137 float baseLineWidth = right / mFrameSource.capacity();
138 mNumFastRects = 0;
139 mNumJankyRects = 0;
140 int fast_i = 0, janky_i = 0;
John Reckbf3c6022015-06-02 15:55:00 -0700141 // Set the bottom of all the shapes to the baseline
John Reck41300272015-06-03 14:42:34 -0700142 for (int fi = mFrameSource.size() - 1; fi >= 0; fi--) {
143 if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) {
144 continue;
145 }
146 float lineWidth = baseLineWidth;
147 float* rect;
148 int ri;
John Reckbf3c6022015-06-02 15:55:00 -0700149 // Rects are LTRB
John Reck41300272015-06-03 14:42:34 -0700150 if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) {
151 rect = mFastRects.get();
152 ri = fast_i;
153 fast_i += 4;
154 mNumFastRects++;
155 } else {
156 rect = mJankyRects.get();
157 ri = janky_i;
158 janky_i += 4;
159 mNumJankyRects++;
160 lineWidth *= 2;
161 }
162
163 rect[ri + 0] = right - lineWidth;
164 rect[ri + 1] = baseline;
165 rect[ri + 2] = right;
166 rect[ri + 3] = baseline;
167 right -= lineWidth;
John Reckbf3c6022015-06-02 15:55:00 -0700168 }
John Reckfe5e7b72014-05-23 17:42:28 -0700169}
170
John Reckbf3c6022015-06-02 15:55:00 -0700171void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex end) {
John Reck41300272015-06-03 14:42:34 -0700172 int fast_i = (mNumFastRects - 1) * 4;
John Reck1bcacfd2017-11-03 10:12:19 -0700173 int janky_i = (mNumJankyRects - 1) * 4;
174 ;
John Reck41300272015-06-03 14:42:34 -0700175 for (size_t fi = 0; fi < mFrameSource.size(); fi++) {
Chris Craik1b54fb22015-06-02 17:40:58 -0700176 if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) {
John Reckbf3c6022015-06-02 15:55:00 -0700177 continue;
178 }
179
John Reck41300272015-06-03 14:42:34 -0700180 float* rect;
181 int ri;
182 // Rects are LTRB
183 if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) {
184 rect = mFastRects.get();
185 ri = fast_i;
186 fast_i -= 4;
187 } else {
188 rect = mJankyRects.get();
189 ri = janky_i;
190 janky_i -= 4;
191 }
192
John Reckbf3c6022015-06-02 15:55:00 -0700193 // Set the bottom to the old top (build upwards)
John Reck41300272015-06-03 14:42:34 -0700194 rect[ri + 3] = rect[ri + 1];
John Reckbf3c6022015-06-02 15:55:00 -0700195 // Move the top up by the duration
John Reckbe3fba02015-07-06 13:49:58 -0700196 rect[ri + 1] -= mVerticalUnit * durationMS(fi, start, end);
John Reckfe5e7b72014-05-23 17:42:28 -0700197 }
198}
199
Matt Sarettde973072016-10-25 11:07:40 -0400200void FrameInfoVisualizer::drawGraph(IProfileRenderer& renderer) {
John Reckfe5e7b72014-05-23 17:42:28 -0700201 SkPaint paint;
John Reckbf3c6022015-06-02 15:55:00 -0700202 for (size_t i = 0; i < Bar.size(); i++) {
John Reckbf3c6022015-06-02 15:55:00 -0700203 nextBarSegment(Bar[i].start, Bar[i].end);
Chris Craik54fa17f2015-11-25 14:14:53 -0800204 paint.setColor(Bar[i].color & BAR_FAST_MASK);
Matt Sarettde973072016-10-25 11:07:40 -0400205 renderer.drawRects(mFastRects.get(), mNumFastRects * 4, paint);
Chris Craik54fa17f2015-11-25 14:14:53 -0800206 paint.setColor(Bar[i].color & BAR_JANKY_MASK);
Matt Sarettde973072016-10-25 11:07:40 -0400207 renderer.drawRects(mJankyRects.get(), mNumJankyRects * 4, paint);
John Reckfe5e7b72014-05-23 17:42:28 -0700208 }
209}
210
Matt Sarettde973072016-10-25 11:07:40 -0400211void FrameInfoVisualizer::drawThreshold(IProfileRenderer& renderer) {
John Reckfe5e7b72014-05-23 17:42:28 -0700212 SkPaint paint;
213 paint.setColor(THRESHOLD_COLOR);
Matt Sarettde973072016-10-25 11:07:40 -0400214 float yLocation = renderer.getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
John Reck1bcacfd2017-11-03 10:12:19 -0700215 renderer.drawRect(0.0f, yLocation - mThresholdStroke / 2, renderer.getViewportWidth(),
216 yLocation + mThresholdStroke / 2, paint);
John Reckfe5e7b72014-05-23 17:42:28 -0700217}
218
John Reck4c9e59d2015-05-12 07:17:50 -0700219bool FrameInfoVisualizer::consumeProperties() {
John Reck23d307c2014-10-27 12:38:48 -0700220 bool changed = false;
Chris Craik2507c342015-05-04 14:36:49 -0700221 ProfileType newType = Properties::getProfileType();
John Reckfe5e7b72014-05-23 17:42:28 -0700222 if (newType != mType) {
223 mType = newType;
Chris Craik2507c342015-05-04 14:36:49 -0700224 if (mType == ProfileType::None) {
John Reckfe5e7b72014-05-23 17:42:28 -0700225 destroyData();
226 } else {
227 createData();
228 }
John Reck23d307c2014-10-27 12:38:48 -0700229 changed = true;
John Reckfe5e7b72014-05-23 17:42:28 -0700230 }
Chris Craik2507c342015-05-04 14:36:49 -0700231
232 bool showDirty = Properties::showDirtyRegions;
John Reck23d307c2014-10-27 12:38:48 -0700233 if (showDirty != mShowDirtyRegions) {
234 mShowDirtyRegions = showDirty;
235 changed = true;
236 }
237 return changed;
John Reckfe5e7b72014-05-23 17:42:28 -0700238}
239
John Reck4c9e59d2015-05-12 07:17:50 -0700240void FrameInfoVisualizer::dumpData(int fd) {
John Reck23d307c2014-10-27 12:38:48 -0700241 RETURN_IF_PROFILING_DISABLED();
John Reckfe5e7b72014-05-23 17:42:28 -0700242
243 // This method logs the last N frames (where N is <= mDataSize) since the
244 // last call to dumpData(). In other words if there's a dumpData(), draw frame,
245 // dumpData(), the last dumpData() should only log 1 frame.
246
John Reck47f5c3a2017-11-13 11:32:39 -0800247 dprintf(fd, "\n\tDraw\tPrepare\tProcess\tExecute\n");
John Reckfe5e7b72014-05-23 17:42:28 -0700248
John Reck4c9e59d2015-05-12 07:17:50 -0700249 for (size_t i = 0; i < mFrameSource.size(); i++) {
Chris Craik1b54fb22015-06-02 17:40:58 -0700250 if (mFrameSource[i][FrameInfoIndex::IntendedVsync] <= mLastFrameLogged) {
John Reckfe5e7b72014-05-23 17:42:28 -0700251 continue;
252 }
Chris Craik1b54fb22015-06-02 17:40:58 -0700253 mLastFrameLogged = mFrameSource[i][FrameInfoIndex::IntendedVsync];
John Reck47f5c3a2017-11-13 11:32:39 -0800254 dprintf(fd, "\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n",
John Reckbe3fba02015-07-06 13:49:58 -0700255 durationMS(i, FrameInfoIndex::IntendedVsync, FrameInfoIndex::SyncStart),
256 durationMS(i, FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart),
257 durationMS(i, FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers),
258 durationMS(i, FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted));
John Reckfe5e7b72014-05-23 17:42:28 -0700259 }
John Reckfe5e7b72014-05-23 17:42:28 -0700260}
261
262} /* namespace uirenderer */
263} /* namespace android */