blob: adadd32a2fc0219675cb979b2687ca2a977b5fb5 [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
Chris Craik1dfa0702016-03-04 15:59:24 -080018#if HWUI_NEW_OPS
19#include "BakedOpRenderer.h"
20#else
John Reckfe5e7b72014-05-23 17:42:28 -070021#include "OpenGLRenderer.h"
Chris Craik1dfa0702016-03-04 15:59:24 -080022#endif
Chris Craik54fa17f2015-11-25 14:14:53 -080023#include "utils/Color.h"
John Reckfe5e7b72014-05-23 17:42:28 -070024
John Reck4c9e59d2015-05-12 07:17:50 -070025#include <cutils/compiler.h>
John Reckbf3c6022015-06-02 15:55:00 -070026#include <array>
John Reckfe5e7b72014-05-23 17:42:28 -070027
Chris Craik2507c342015-05-04 14:36:49 -070028#define RETURN_IF_PROFILING_DISABLED() if (CC_LIKELY(mType == ProfileType::None)) return
29#define RETURN_IF_DISABLED() if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
John Reckfe5e7b72014-05-23 17:42:28 -070030
John Reckfe5e7b72014-05-23 17:42:28 -070031#define PROFILE_DRAW_WIDTH 3
32#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
33#define PROFILE_DRAW_DP_PER_MS 7
34
Chris Craik54fa17f2015-11-25 14:14:53 -080035namespace android {
36namespace uirenderer {
37
John Reckfe5e7b72014-05-23 17:42:28 -070038// Must be NUM_ELEMENTS in size
Chris Craik54fa17f2015-11-25 14:14:53 -080039static const SkColor THRESHOLD_COLOR = Color::Green_500;
40static const SkColor BAR_FAST_MASK = 0x8FFFFFFF;
41static const SkColor BAR_JANKY_MASK = 0xDFFFFFFF;
John Reckfe5e7b72014-05-23 17:42:28 -070042
43// We could get this from TimeLord and use the actual frame interval, but
44// this is good enough
45#define FRAME_THRESHOLD 16
John Reck41300272015-06-03 14:42:34 -070046#define FRAME_THRESHOLD_NS 16000000
John Reckfe5e7b72014-05-23 17:42:28 -070047
John Reckbf3c6022015-06-02 15:55:00 -070048struct BarSegment {
49 FrameInfoIndex start;
50 FrameInfoIndex end;
51 SkColor color;
52};
53
John Reck41300272015-06-03 14:42:34 -070054static const std::array<BarSegment,7> Bar {{
Chris Craik54fa17f2015-11-25 14:14:53 -080055 { FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, Color::Teal_700 },
56 { FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart, Color::Green_700 },
57 { FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, Color::LightGreen_700 },
58 { FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, Color::Blue_500 },
59 { FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, Color::LightBlue_300 },
60 { FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, Color::Red_500},
61 { FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, Color::Orange_500},
John Reckbf3c6022015-06-02 15:55:00 -070062}};
63
John Reckfe5e7b72014-05-23 17:42:28 -070064static int dpToPx(int dp, float density) {
65 return (int) (dp * density + 0.5f);
66}
67
John Reck4c9e59d2015-05-12 07:17:50 -070068FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source)
69 : mFrameSource(source) {
John Reckfe5e7b72014-05-23 17:42:28 -070070 setDensity(1);
71}
72
John Reck4c9e59d2015-05-12 07:17:50 -070073FrameInfoVisualizer::~FrameInfoVisualizer() {
John Reckfe5e7b72014-05-23 17:42:28 -070074 destroyData();
75}
76
John Reck4c9e59d2015-05-12 07:17:50 -070077void FrameInfoVisualizer::setDensity(float density) {
John Reckfe5e7b72014-05-23 17:42:28 -070078 if (CC_UNLIKELY(mDensity != density)) {
79 mDensity = density;
80 mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
John Reckfe5e7b72014-05-23 17:42:28 -070081 mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
82 }
83}
84
John Reck4c9e59d2015-05-12 07:17:50 -070085void FrameInfoVisualizer::unionDirty(SkRect* dirty) {
John Reckfe5e7b72014-05-23 17:42:28 -070086 RETURN_IF_DISABLED();
87 // Not worth worrying about minimizing the dirty region for debugging, so just
88 // dirty the entire viewport.
89 if (dirty) {
John Reck23d307c2014-10-27 12:38:48 -070090 mDirtyRegion = *dirty;
John Reckfe5e7b72014-05-23 17:42:28 -070091 dirty->setEmpty();
92 }
93}
94
Chris Craik1dfa0702016-03-04 15:59:24 -080095void FrameInfoVisualizer::draw(ContentRenderer* renderer) {
John Reck23d307c2014-10-27 12:38:48 -070096 RETURN_IF_DISABLED();
97
98 if (mShowDirtyRegions) {
99 mFlashToggle = !mFlashToggle;
100 if (mFlashToggle) {
101 SkPaint paint;
102 paint.setColor(0x7fff0000);
Chris Craik1dfa0702016-03-04 15:59:24 -0800103 renderer->drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
John Reck23d307c2014-10-27 12:38:48 -0700104 mDirtyRegion.fRight, mDirtyRegion.fBottom, &paint);
105 }
John Reckfe5e7b72014-05-23 17:42:28 -0700106 }
107
Chris Craik2507c342015-05-04 14:36:49 -0700108 if (mType == ProfileType::Bars) {
John Reck41300272015-06-03 14:42:34 -0700109 // Patch up the current frame to pretend we ended here. CanvasContext
110 // will overwrite these values with the real ones after we return.
111 // This is a bit nicer looking than the vague green bar, as we have
112 // valid data for almost all the stages and a very good idea of what
113 // the issue stage will look like, too
114 FrameInfo& info = mFrameSource.back();
115 info.markSwapBuffers();
116 info.markFrameCompleted();
117
Chris Craik1dfa0702016-03-04 15:59:24 -0800118 initializeRects(renderer->getViewportHeight(), renderer->getViewportWidth());
119 drawGraph(renderer);
120 drawThreshold(renderer);
John Reck23d307c2014-10-27 12:38:48 -0700121 }
John Reckfe5e7b72014-05-23 17:42:28 -0700122}
123
John Reck4c9e59d2015-05-12 07:17:50 -0700124void FrameInfoVisualizer::createData() {
John Reck41300272015-06-03 14:42:34 -0700125 if (mFastRects.get()) return;
John Reckfe5e7b72014-05-23 17:42:28 -0700126
John Reck41300272015-06-03 14:42:34 -0700127 mFastRects.reset(new float[mFrameSource.capacity() * 4]);
128 mJankyRects.reset(new float[mFrameSource.capacity() * 4]);
John Reckfe5e7b72014-05-23 17:42:28 -0700129}
130
John Reck4c9e59d2015-05-12 07:17:50 -0700131void FrameInfoVisualizer::destroyData() {
John Reck41300272015-06-03 14:42:34 -0700132 mFastRects.reset(nullptr);
133 mJankyRects.reset(nullptr);
John Reckfe5e7b72014-05-23 17:42:28 -0700134}
135
John Reck41300272015-06-03 14:42:34 -0700136void FrameInfoVisualizer::initializeRects(const int baseline, const int width) {
137 // Target the 95% mark for the current frame
138 float right = width * .95;
139 float baseLineWidth = right / mFrameSource.capacity();
140 mNumFastRects = 0;
141 mNumJankyRects = 0;
142 int fast_i = 0, janky_i = 0;
John Reckbf3c6022015-06-02 15:55:00 -0700143 // Set the bottom of all the shapes to the baseline
John Reck41300272015-06-03 14:42:34 -0700144 for (int fi = mFrameSource.size() - 1; fi >= 0; fi--) {
145 if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) {
146 continue;
147 }
148 float lineWidth = baseLineWidth;
149 float* rect;
150 int ri;
John Reckbf3c6022015-06-02 15:55:00 -0700151 // Rects are LTRB
John Reck41300272015-06-03 14:42:34 -0700152 if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) {
153 rect = mFastRects.get();
154 ri = fast_i;
155 fast_i += 4;
156 mNumFastRects++;
157 } else {
158 rect = mJankyRects.get();
159 ri = janky_i;
160 janky_i += 4;
161 mNumJankyRects++;
162 lineWidth *= 2;
163 }
164
165 rect[ri + 0] = right - lineWidth;
166 rect[ri + 1] = baseline;
167 rect[ri + 2] = right;
168 rect[ri + 3] = baseline;
169 right -= lineWidth;
John Reckbf3c6022015-06-02 15:55:00 -0700170 }
John Reckfe5e7b72014-05-23 17:42:28 -0700171}
172
John Reckbf3c6022015-06-02 15:55:00 -0700173void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex end) {
John Reck41300272015-06-03 14:42:34 -0700174 int fast_i = (mNumFastRects - 1) * 4;
175 int janky_i = (mNumJankyRects - 1) * 4;;
176 for (size_t fi = 0; fi < mFrameSource.size(); fi++) {
Chris Craik1b54fb22015-06-02 17:40:58 -0700177 if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) {
John Reckbf3c6022015-06-02 15:55:00 -0700178 continue;
179 }
180
John Reck41300272015-06-03 14:42:34 -0700181 float* rect;
182 int ri;
183 // Rects are LTRB
184 if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) {
185 rect = mFastRects.get();
186 ri = fast_i;
187 fast_i -= 4;
188 } else {
189 rect = mJankyRects.get();
190 ri = janky_i;
191 janky_i -= 4;
192 }
193
John Reckbf3c6022015-06-02 15:55:00 -0700194 // Set the bottom to the old top (build upwards)
John Reck41300272015-06-03 14:42:34 -0700195 rect[ri + 3] = rect[ri + 1];
John Reckbf3c6022015-06-02 15:55:00 -0700196 // Move the top up by the duration
John Reckbe3fba02015-07-06 13:49:58 -0700197 rect[ri + 1] -= mVerticalUnit * durationMS(fi, start, end);
John Reckfe5e7b72014-05-23 17:42:28 -0700198 }
199}
200
Chris Craik1dfa0702016-03-04 15:59:24 -0800201void FrameInfoVisualizer::drawGraph(ContentRenderer* renderer) {
John Reckfe5e7b72014-05-23 17:42:28 -0700202 SkPaint paint;
John Reckbf3c6022015-06-02 15:55:00 -0700203 for (size_t i = 0; i < Bar.size(); i++) {
John Reckbf3c6022015-06-02 15:55:00 -0700204 nextBarSegment(Bar[i].start, Bar[i].end);
Chris Craik54fa17f2015-11-25 14:14:53 -0800205 paint.setColor(Bar[i].color & BAR_FAST_MASK);
Chris Craik1dfa0702016-03-04 15:59:24 -0800206 renderer->drawRects(mFastRects.get(), mNumFastRects * 4, &paint);
Chris Craik54fa17f2015-11-25 14:14:53 -0800207 paint.setColor(Bar[i].color & BAR_JANKY_MASK);
Chris Craik1dfa0702016-03-04 15:59:24 -0800208 renderer->drawRects(mJankyRects.get(), mNumJankyRects * 4, &paint);
John Reckfe5e7b72014-05-23 17:42:28 -0700209 }
210}
211
Chris Craik1dfa0702016-03-04 15:59:24 -0800212void FrameInfoVisualizer::drawThreshold(ContentRenderer* renderer) {
John Reckfe5e7b72014-05-23 17:42:28 -0700213 SkPaint paint;
214 paint.setColor(THRESHOLD_COLOR);
Chris Craik1dfa0702016-03-04 15:59:24 -0800215 float yLocation = renderer->getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
216 renderer->drawRect(0.0f,
217 yLocation - mThresholdStroke/2,
218 renderer->getViewportWidth(),
219 yLocation + mThresholdStroke/2,
220 &paint);
John Reckfe5e7b72014-05-23 17:42:28 -0700221}
222
John Reck4c9e59d2015-05-12 07:17:50 -0700223bool FrameInfoVisualizer::consumeProperties() {
John Reck23d307c2014-10-27 12:38:48 -0700224 bool changed = false;
Chris Craik2507c342015-05-04 14:36:49 -0700225 ProfileType newType = Properties::getProfileType();
John Reckfe5e7b72014-05-23 17:42:28 -0700226 if (newType != mType) {
227 mType = newType;
Chris Craik2507c342015-05-04 14:36:49 -0700228 if (mType == ProfileType::None) {
John Reckfe5e7b72014-05-23 17:42:28 -0700229 destroyData();
230 } else {
231 createData();
232 }
John Reck23d307c2014-10-27 12:38:48 -0700233 changed = true;
John Reckfe5e7b72014-05-23 17:42:28 -0700234 }
Chris Craik2507c342015-05-04 14:36:49 -0700235
236 bool showDirty = Properties::showDirtyRegions;
John Reck23d307c2014-10-27 12:38:48 -0700237 if (showDirty != mShowDirtyRegions) {
238 mShowDirtyRegions = showDirty;
239 changed = true;
240 }
241 return changed;
John Reckfe5e7b72014-05-23 17:42:28 -0700242}
243
John Reck4c9e59d2015-05-12 07:17:50 -0700244void FrameInfoVisualizer::dumpData(int fd) {
John Reck23d307c2014-10-27 12:38:48 -0700245 RETURN_IF_PROFILING_DISABLED();
John Reckfe5e7b72014-05-23 17:42:28 -0700246
247 // This method logs the last N frames (where N is <= mDataSize) since the
248 // last call to dumpData(). In other words if there's a dumpData(), draw frame,
249 // dumpData(), the last dumpData() should only log 1 frame.
250
John Reckfe5e7b72014-05-23 17:42:28 -0700251 FILE *file = fdopen(fd, "a");
252 fprintf(file, "\n\tDraw\tPrepare\tProcess\tExecute\n");
253
John Reck4c9e59d2015-05-12 07:17:50 -0700254 for (size_t i = 0; i < mFrameSource.size(); i++) {
Chris Craik1b54fb22015-06-02 17:40:58 -0700255 if (mFrameSource[i][FrameInfoIndex::IntendedVsync] <= mLastFrameLogged) {
John Reckfe5e7b72014-05-23 17:42:28 -0700256 continue;
257 }
Chris Craik1b54fb22015-06-02 17:40:58 -0700258 mLastFrameLogged = mFrameSource[i][FrameInfoIndex::IntendedVsync];
John Reckfe5e7b72014-05-23 17:42:28 -0700259 fprintf(file, "\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n",
John Reckbe3fba02015-07-06 13:49:58 -0700260 durationMS(i, FrameInfoIndex::IntendedVsync, FrameInfoIndex::SyncStart),
261 durationMS(i, FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart),
262 durationMS(i, FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers),
263 durationMS(i, FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted));
John Reckfe5e7b72014-05-23 17:42:28 -0700264 }
John Reckfe5e7b72014-05-23 17:42:28 -0700265
266 fflush(file);
267}
268
269} /* namespace uirenderer */
270} /* namespace android */