blob: b7dd3b7e2f9514c90e8ac65b12f86b962556637e [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
18#include "OpenGLRenderer.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
Chris Craik2507c342015-05-04 14:36:49 -070024#define RETURN_IF_PROFILING_DISABLED() if (CC_LIKELY(mType == ProfileType::None)) return
25#define RETURN_IF_DISABLED() if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
John Reckfe5e7b72014-05-23 17:42:28 -070026
John Reckfe5e7b72014-05-23 17:42:28 -070027#define PROFILE_DRAW_WIDTH 3
28#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
29#define PROFILE_DRAW_DP_PER_MS 7
30
Chris Craik54fa17f2015-11-25 14:14:53 -080031namespace android {
32namespace uirenderer {
33
John Reckfe5e7b72014-05-23 17:42:28 -070034// Must be NUM_ELEMENTS in size
Chris Craik54fa17f2015-11-25 14:14:53 -080035static const SkColor THRESHOLD_COLOR = Color::Green_500;
36static const SkColor BAR_FAST_MASK = 0x8FFFFFFF;
37static const SkColor BAR_JANKY_MASK = 0xDFFFFFFF;
John Reckfe5e7b72014-05-23 17:42:28 -070038
39// We could get this from TimeLord and use the actual frame interval, but
40// this is good enough
41#define FRAME_THRESHOLD 16
John Reck41300272015-06-03 14:42:34 -070042#define FRAME_THRESHOLD_NS 16000000
John Reckfe5e7b72014-05-23 17:42:28 -070043
John Reckbf3c6022015-06-02 15:55:00 -070044struct BarSegment {
45 FrameInfoIndex start;
46 FrameInfoIndex end;
47 SkColor color;
48};
49
John Reck41300272015-06-03 14:42:34 -070050static const std::array<BarSegment,7> Bar {{
Chris Craik54fa17f2015-11-25 14:14:53 -080051 { FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, Color::Teal_700 },
52 { FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart, Color::Green_700 },
53 { FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, Color::LightGreen_700 },
54 { FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, Color::Blue_500 },
55 { FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, Color::LightBlue_300 },
56 { FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, Color::Red_500},
57 { FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, Color::Orange_500},
John Reckbf3c6022015-06-02 15:55:00 -070058}};
59
John Reckfe5e7b72014-05-23 17:42:28 -070060static int dpToPx(int dp, float density) {
61 return (int) (dp * density + 0.5f);
62}
63
John Reck4c9e59d2015-05-12 07:17:50 -070064FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source)
65 : mFrameSource(source) {
John Reckfe5e7b72014-05-23 17:42:28 -070066 setDensity(1);
67}
68
John Reck4c9e59d2015-05-12 07:17:50 -070069FrameInfoVisualizer::~FrameInfoVisualizer() {
John Reckfe5e7b72014-05-23 17:42:28 -070070 destroyData();
71}
72
John Reck4c9e59d2015-05-12 07:17:50 -070073void FrameInfoVisualizer::setDensity(float density) {
John Reckfe5e7b72014-05-23 17:42:28 -070074 if (CC_UNLIKELY(mDensity != density)) {
75 mDensity = density;
76 mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
John Reckfe5e7b72014-05-23 17:42:28 -070077 mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
78 }
79}
80
John Reck4c9e59d2015-05-12 07:17:50 -070081void FrameInfoVisualizer::unionDirty(SkRect* dirty) {
John Reckfe5e7b72014-05-23 17:42:28 -070082 RETURN_IF_DISABLED();
83 // Not worth worrying about minimizing the dirty region for debugging, so just
84 // dirty the entire viewport.
85 if (dirty) {
John Reck23d307c2014-10-27 12:38:48 -070086 mDirtyRegion = *dirty;
John Reckfe5e7b72014-05-23 17:42:28 -070087 dirty->setEmpty();
88 }
89}
90
John Reck4c9e59d2015-05-12 07:17:50 -070091void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) {
John Reck23d307c2014-10-27 12:38:48 -070092 RETURN_IF_DISABLED();
93
94 if (mShowDirtyRegions) {
95 mFlashToggle = !mFlashToggle;
96 if (mFlashToggle) {
97 SkPaint paint;
98 paint.setColor(0x7fff0000);
99 canvas->drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
100 mDirtyRegion.fRight, mDirtyRegion.fBottom, &paint);
101 }
John Reckfe5e7b72014-05-23 17:42:28 -0700102 }
103
Chris Craik2507c342015-05-04 14:36:49 -0700104 if (mType == ProfileType::Bars) {
John Reck41300272015-06-03 14:42:34 -0700105 // Patch up the current frame to pretend we ended here. CanvasContext
106 // will overwrite these values with the real ones after we return.
107 // This is a bit nicer looking than the vague green bar, as we have
108 // valid data for almost all the stages and a very good idea of what
109 // the issue stage will look like, too
110 FrameInfo& info = mFrameSource.back();
111 info.markSwapBuffers();
112 info.markFrameCompleted();
113
114 initializeRects(canvas->getViewportHeight(), canvas->getViewportWidth());
John Reck23d307c2014-10-27 12:38:48 -0700115 drawGraph(canvas);
John Reck23d307c2014-10-27 12:38:48 -0700116 drawThreshold(canvas);
117 }
John Reckfe5e7b72014-05-23 17:42:28 -0700118}
119
John Reck4c9e59d2015-05-12 07:17:50 -0700120void FrameInfoVisualizer::createData() {
John Reck41300272015-06-03 14:42:34 -0700121 if (mFastRects.get()) return;
John Reckfe5e7b72014-05-23 17:42:28 -0700122
John Reck41300272015-06-03 14:42:34 -0700123 mFastRects.reset(new float[mFrameSource.capacity() * 4]);
124 mJankyRects.reset(new float[mFrameSource.capacity() * 4]);
John Reckfe5e7b72014-05-23 17:42:28 -0700125}
126
John Reck4c9e59d2015-05-12 07:17:50 -0700127void FrameInfoVisualizer::destroyData() {
John Reck41300272015-06-03 14:42:34 -0700128 mFastRects.reset(nullptr);
129 mJankyRects.reset(nullptr);
John Reckfe5e7b72014-05-23 17:42:28 -0700130}
131
John Reck41300272015-06-03 14:42:34 -0700132void FrameInfoVisualizer::initializeRects(const int baseline, const int width) {
133 // Target the 95% mark for the current frame
134 float right = width * .95;
135 float baseLineWidth = right / mFrameSource.capacity();
136 mNumFastRects = 0;
137 mNumJankyRects = 0;
138 int fast_i = 0, janky_i = 0;
John Reckbf3c6022015-06-02 15:55:00 -0700139 // Set the bottom of all the shapes to the baseline
John Reck41300272015-06-03 14:42:34 -0700140 for (int fi = mFrameSource.size() - 1; fi >= 0; fi--) {
141 if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) {
142 continue;
143 }
144 float lineWidth = baseLineWidth;
145 float* rect;
146 int ri;
John Reckbf3c6022015-06-02 15:55:00 -0700147 // Rects are LTRB
John Reck41300272015-06-03 14:42:34 -0700148 if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) {
149 rect = mFastRects.get();
150 ri = fast_i;
151 fast_i += 4;
152 mNumFastRects++;
153 } else {
154 rect = mJankyRects.get();
155 ri = janky_i;
156 janky_i += 4;
157 mNumJankyRects++;
158 lineWidth *= 2;
159 }
160
161 rect[ri + 0] = right - lineWidth;
162 rect[ri + 1] = baseline;
163 rect[ri + 2] = right;
164 rect[ri + 3] = baseline;
165 right -= lineWidth;
John Reckbf3c6022015-06-02 15:55:00 -0700166 }
John Reckfe5e7b72014-05-23 17:42:28 -0700167}
168
John Reckbf3c6022015-06-02 15:55:00 -0700169void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex end) {
John Reck41300272015-06-03 14:42:34 -0700170 int fast_i = (mNumFastRects - 1) * 4;
171 int janky_i = (mNumJankyRects - 1) * 4;;
172 for (size_t fi = 0; fi < mFrameSource.size(); fi++) {
Chris Craik1b54fb22015-06-02 17:40:58 -0700173 if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) {
John Reckbf3c6022015-06-02 15:55:00 -0700174 continue;
175 }
176
John Reck41300272015-06-03 14:42:34 -0700177 float* rect;
178 int ri;
179 // Rects are LTRB
180 if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) {
181 rect = mFastRects.get();
182 ri = fast_i;
183 fast_i -= 4;
184 } else {
185 rect = mJankyRects.get();
186 ri = janky_i;
187 janky_i -= 4;
188 }
189
John Reckbf3c6022015-06-02 15:55:00 -0700190 // Set the bottom to the old top (build upwards)
John Reck41300272015-06-03 14:42:34 -0700191 rect[ri + 3] = rect[ri + 1];
John Reckbf3c6022015-06-02 15:55:00 -0700192 // Move the top up by the duration
John Reckbe3fba02015-07-06 13:49:58 -0700193 rect[ri + 1] -= mVerticalUnit * durationMS(fi, start, end);
John Reckfe5e7b72014-05-23 17:42:28 -0700194 }
195}
196
John Reck4c9e59d2015-05-12 07:17:50 -0700197void FrameInfoVisualizer::drawGraph(OpenGLRenderer* canvas) {
John Reckfe5e7b72014-05-23 17:42:28 -0700198 SkPaint paint;
John Reckbf3c6022015-06-02 15:55:00 -0700199 for (size_t i = 0; i < Bar.size(); i++) {
John Reckbf3c6022015-06-02 15:55:00 -0700200 nextBarSegment(Bar[i].start, Bar[i].end);
Chris Craik54fa17f2015-11-25 14:14:53 -0800201 paint.setColor(Bar[i].color & BAR_FAST_MASK);
John Reck41300272015-06-03 14:42:34 -0700202 canvas->drawRects(mFastRects.get(), mNumFastRects * 4, &paint);
Chris Craik54fa17f2015-11-25 14:14:53 -0800203 paint.setColor(Bar[i].color & BAR_JANKY_MASK);
John Reck41300272015-06-03 14:42:34 -0700204 canvas->drawRects(mJankyRects.get(), mNumJankyRects * 4, &paint);
John Reckfe5e7b72014-05-23 17:42:28 -0700205 }
206}
207
John Reck4c9e59d2015-05-12 07:17:50 -0700208void FrameInfoVisualizer::drawThreshold(OpenGLRenderer* canvas) {
John Reckfe5e7b72014-05-23 17:42:28 -0700209 SkPaint paint;
210 paint.setColor(THRESHOLD_COLOR);
211 paint.setStrokeWidth(mThresholdStroke);
212
213 float pts[4];
214 pts[0] = 0.0f;
215 pts[1] = pts[3] = canvas->getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
216 pts[2] = canvas->getViewportWidth();
217 canvas->drawLines(pts, 4, &paint);
218}
219
John Reck4c9e59d2015-05-12 07:17:50 -0700220bool FrameInfoVisualizer::consumeProperties() {
John Reck23d307c2014-10-27 12:38:48 -0700221 bool changed = false;
Chris Craik2507c342015-05-04 14:36:49 -0700222 ProfileType newType = Properties::getProfileType();
John Reckfe5e7b72014-05-23 17:42:28 -0700223 if (newType != mType) {
224 mType = newType;
Chris Craik2507c342015-05-04 14:36:49 -0700225 if (mType == ProfileType::None) {
John Reckfe5e7b72014-05-23 17:42:28 -0700226 destroyData();
227 } else {
228 createData();
229 }
John Reck23d307c2014-10-27 12:38:48 -0700230 changed = true;
John Reckfe5e7b72014-05-23 17:42:28 -0700231 }
Chris Craik2507c342015-05-04 14:36:49 -0700232
233 bool showDirty = Properties::showDirtyRegions;
John Reck23d307c2014-10-27 12:38:48 -0700234 if (showDirty != mShowDirtyRegions) {
235 mShowDirtyRegions = showDirty;
236 changed = true;
237 }
238 return changed;
John Reckfe5e7b72014-05-23 17:42:28 -0700239}
240
John Reck4c9e59d2015-05-12 07:17:50 -0700241void FrameInfoVisualizer::dumpData(int fd) {
John Reck23d307c2014-10-27 12:38:48 -0700242 RETURN_IF_PROFILING_DISABLED();
John Reckfe5e7b72014-05-23 17:42:28 -0700243
244 // This method logs the last N frames (where N is <= mDataSize) since the
245 // last call to dumpData(). In other words if there's a dumpData(), draw frame,
246 // dumpData(), the last dumpData() should only log 1 frame.
247
John Reckfe5e7b72014-05-23 17:42:28 -0700248 FILE *file = fdopen(fd, "a");
249 fprintf(file, "\n\tDraw\tPrepare\tProcess\tExecute\n");
250
John Reck4c9e59d2015-05-12 07:17:50 -0700251 for (size_t i = 0; i < mFrameSource.size(); i++) {
Chris Craik1b54fb22015-06-02 17:40:58 -0700252 if (mFrameSource[i][FrameInfoIndex::IntendedVsync] <= mLastFrameLogged) {
John Reckfe5e7b72014-05-23 17:42:28 -0700253 continue;
254 }
Chris Craik1b54fb22015-06-02 17:40:58 -0700255 mLastFrameLogged = mFrameSource[i][FrameInfoIndex::IntendedVsync];
John Reckfe5e7b72014-05-23 17:42:28 -0700256 fprintf(file, "\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n",
John Reckbe3fba02015-07-06 13:49:58 -0700257 durationMS(i, FrameInfoIndex::IntendedVsync, FrameInfoIndex::SyncStart),
258 durationMS(i, FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart),
259 durationMS(i, FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers),
260 durationMS(i, FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted));
John Reckfe5e7b72014-05-23 17:42:28 -0700261 }
John Reckfe5e7b72014-05-23 17:42:28 -0700262
263 fflush(file);
264}
265
266} /* namespace uirenderer */
267} /* namespace android */