blob: b416615c20e16095eeec07e1be352a72eb4dd417 [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"
John Reckfe5e7b72014-05-23 17:42:28 -070019
John Reck4c9e59d2015-05-12 07:17:50 -070020#include <cutils/compiler.h>
John Reckbf3c6022015-06-02 15:55:00 -070021#include <array>
John Reckfe5e7b72014-05-23 17:42:28 -070022
Chris Craik2507c342015-05-04 14:36:49 -070023#define RETURN_IF_PROFILING_DISABLED() if (CC_LIKELY(mType == ProfileType::None)) return
24#define RETURN_IF_DISABLED() if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
John Reckfe5e7b72014-05-23 17:42:28 -070025
John Reckfe5e7b72014-05-23 17:42:28 -070026#define PROFILE_DRAW_WIDTH 3
27#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
28#define PROFILE_DRAW_DP_PER_MS 7
29
John Reckfe5e7b72014-05-23 17:42:28 -070030// Must be NUM_ELEMENTS in size
John Reckfe5e7b72014-05-23 17:42:28 -070031static const SkColor THRESHOLD_COLOR = 0xff5faa4d;
John Reck41300272015-06-03 14:42:34 -070032static const SkColor BAR_FAST_ALPHA = 0x8F000000;
33static const SkColor BAR_JANKY_ALPHA = 0xDF000000;
John Reckfe5e7b72014-05-23 17:42:28 -070034
35// We could get this from TimeLord and use the actual frame interval, but
36// this is good enough
37#define FRAME_THRESHOLD 16
John Reck41300272015-06-03 14:42:34 -070038#define FRAME_THRESHOLD_NS 16000000
John Reckfe5e7b72014-05-23 17:42:28 -070039
40namespace android {
41namespace uirenderer {
42
John Reckbf3c6022015-06-02 15:55:00 -070043struct BarSegment {
44 FrameInfoIndex start;
45 FrameInfoIndex end;
46 SkColor color;
47};
48
John Reck41300272015-06-03 14:42:34 -070049static const std::array<BarSegment,7> Bar {{
50 { FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, 0x00796B },
51 { FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart, 0x388E3C },
52 { FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, 0x689F38},
Chris Craik1b54fb22015-06-02 17:40:58 -070053 { FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, 0x2196F3},
54 { FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, 0x4FC3F7},
55 { FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, 0xF44336},
56 { FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, 0xFF9800},
John Reckbf3c6022015-06-02 15:55:00 -070057}};
58
John Reckfe5e7b72014-05-23 17:42:28 -070059static int dpToPx(int dp, float density) {
60 return (int) (dp * density + 0.5f);
61}
62
John Reck4c9e59d2015-05-12 07:17:50 -070063FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source)
64 : mFrameSource(source) {
John Reckfe5e7b72014-05-23 17:42:28 -070065 setDensity(1);
66}
67
John Reck4c9e59d2015-05-12 07:17:50 -070068FrameInfoVisualizer::~FrameInfoVisualizer() {
John Reckfe5e7b72014-05-23 17:42:28 -070069 destroyData();
70}
71
John Reck4c9e59d2015-05-12 07:17:50 -070072void FrameInfoVisualizer::setDensity(float density) {
John Reckfe5e7b72014-05-23 17:42:28 -070073 if (CC_UNLIKELY(mDensity != density)) {
74 mDensity = density;
75 mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
John Reckfe5e7b72014-05-23 17:42:28 -070076 mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
77 }
78}
79
John Reck4c9e59d2015-05-12 07:17:50 -070080void FrameInfoVisualizer::unionDirty(SkRect* dirty) {
John Reckfe5e7b72014-05-23 17:42:28 -070081 RETURN_IF_DISABLED();
82 // Not worth worrying about minimizing the dirty region for debugging, so just
83 // dirty the entire viewport.
84 if (dirty) {
John Reck23d307c2014-10-27 12:38:48 -070085 mDirtyRegion = *dirty;
John Reckfe5e7b72014-05-23 17:42:28 -070086 dirty->setEmpty();
87 }
88}
89
John Reck4c9e59d2015-05-12 07:17:50 -070090void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) {
John Reck23d307c2014-10-27 12:38:48 -070091 RETURN_IF_DISABLED();
92
93 if (mShowDirtyRegions) {
94 mFlashToggle = !mFlashToggle;
95 if (mFlashToggle) {
96 SkPaint paint;
97 paint.setColor(0x7fff0000);
98 canvas->drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
99 mDirtyRegion.fRight, mDirtyRegion.fBottom, &paint);
100 }
John Reckfe5e7b72014-05-23 17:42:28 -0700101 }
102
Chris Craik2507c342015-05-04 14:36:49 -0700103 if (mType == ProfileType::Bars) {
John Reck41300272015-06-03 14:42:34 -0700104 // Patch up the current frame to pretend we ended here. CanvasContext
105 // will overwrite these values with the real ones after we return.
106 // This is a bit nicer looking than the vague green bar, as we have
107 // valid data for almost all the stages and a very good idea of what
108 // the issue stage will look like, too
109 FrameInfo& info = mFrameSource.back();
110 info.markSwapBuffers();
111 info.markFrameCompleted();
112
113 initializeRects(canvas->getViewportHeight(), canvas->getViewportWidth());
John Reck23d307c2014-10-27 12:38:48 -0700114 drawGraph(canvas);
John Reck23d307c2014-10-27 12:38:48 -0700115 drawThreshold(canvas);
116 }
John Reckfe5e7b72014-05-23 17:42:28 -0700117}
118
John Reck4c9e59d2015-05-12 07:17:50 -0700119void FrameInfoVisualizer::createData() {
John Reck41300272015-06-03 14:42:34 -0700120 if (mFastRects.get()) return;
John Reckfe5e7b72014-05-23 17:42:28 -0700121
John Reck41300272015-06-03 14:42:34 -0700122 mFastRects.reset(new float[mFrameSource.capacity() * 4]);
123 mJankyRects.reset(new float[mFrameSource.capacity() * 4]);
John Reckfe5e7b72014-05-23 17:42:28 -0700124}
125
John Reck4c9e59d2015-05-12 07:17:50 -0700126void FrameInfoVisualizer::destroyData() {
John Reck41300272015-06-03 14:42:34 -0700127 mFastRects.reset(nullptr);
128 mJankyRects.reset(nullptr);
John Reckfe5e7b72014-05-23 17:42:28 -0700129}
130
John Reck41300272015-06-03 14:42:34 -0700131void FrameInfoVisualizer::initializeRects(const int baseline, const int width) {
132 // Target the 95% mark for the current frame
133 float right = width * .95;
134 float baseLineWidth = right / mFrameSource.capacity();
135 mNumFastRects = 0;
136 mNumJankyRects = 0;
137 int fast_i = 0, janky_i = 0;
John Reckbf3c6022015-06-02 15:55:00 -0700138 // Set the bottom of all the shapes to the baseline
John Reck41300272015-06-03 14:42:34 -0700139 for (int fi = mFrameSource.size() - 1; fi >= 0; fi--) {
140 if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) {
141 continue;
142 }
143 float lineWidth = baseLineWidth;
144 float* rect;
145 int ri;
John Reckbf3c6022015-06-02 15:55:00 -0700146 // Rects are LTRB
John Reck41300272015-06-03 14:42:34 -0700147 if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) {
148 rect = mFastRects.get();
149 ri = fast_i;
150 fast_i += 4;
151 mNumFastRects++;
152 } else {
153 rect = mJankyRects.get();
154 ri = janky_i;
155 janky_i += 4;
156 mNumJankyRects++;
157 lineWidth *= 2;
158 }
159
160 rect[ri + 0] = right - lineWidth;
161 rect[ri + 1] = baseline;
162 rect[ri + 2] = right;
163 rect[ri + 3] = baseline;
164 right -= lineWidth;
John Reckbf3c6022015-06-02 15:55:00 -0700165 }
John Reckfe5e7b72014-05-23 17:42:28 -0700166}
167
John Reckbf3c6022015-06-02 15:55:00 -0700168void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex end) {
John Reck41300272015-06-03 14:42:34 -0700169 int fast_i = (mNumFastRects - 1) * 4;
170 int janky_i = (mNumJankyRects - 1) * 4;;
171 for (size_t fi = 0; fi < mFrameSource.size(); fi++) {
Chris Craik1b54fb22015-06-02 17:40:58 -0700172 if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) {
John Reckbf3c6022015-06-02 15:55:00 -0700173 continue;
174 }
175
John Reck41300272015-06-03 14:42:34 -0700176 float* rect;
177 int ri;
178 // Rects are LTRB
179 if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) {
180 rect = mFastRects.get();
181 ri = fast_i;
182 fast_i -= 4;
183 } else {
184 rect = mJankyRects.get();
185 ri = janky_i;
186 janky_i -= 4;
187 }
188
John Reckbf3c6022015-06-02 15:55:00 -0700189 // Set the bottom to the old top (build upwards)
John Reck41300272015-06-03 14:42:34 -0700190 rect[ri + 3] = rect[ri + 1];
John Reckbf3c6022015-06-02 15:55:00 -0700191 // Move the top up by the duration
John Reckbe3fba02015-07-06 13:49:58 -0700192 rect[ri + 1] -= mVerticalUnit * durationMS(fi, start, end);
John Reckfe5e7b72014-05-23 17:42:28 -0700193 }
194}
195
John Reck4c9e59d2015-05-12 07:17:50 -0700196void FrameInfoVisualizer::drawGraph(OpenGLRenderer* canvas) {
John Reckfe5e7b72014-05-23 17:42:28 -0700197 SkPaint paint;
John Reckbf3c6022015-06-02 15:55:00 -0700198 for (size_t i = 0; i < Bar.size(); i++) {
John Reckbf3c6022015-06-02 15:55:00 -0700199 nextBarSegment(Bar[i].start, Bar[i].end);
John Reck41300272015-06-03 14:42:34 -0700200 paint.setColor(Bar[i].color | BAR_FAST_ALPHA);
201 canvas->drawRects(mFastRects.get(), mNumFastRects * 4, &paint);
202 paint.setColor(Bar[i].color | BAR_JANKY_ALPHA);
203 canvas->drawRects(mJankyRects.get(), mNumJankyRects * 4, &paint);
John Reckfe5e7b72014-05-23 17:42:28 -0700204 }
205}
206
John Reck4c9e59d2015-05-12 07:17:50 -0700207void FrameInfoVisualizer::drawThreshold(OpenGLRenderer* canvas) {
John Reckfe5e7b72014-05-23 17:42:28 -0700208 SkPaint paint;
209 paint.setColor(THRESHOLD_COLOR);
210 paint.setStrokeWidth(mThresholdStroke);
211
212 float pts[4];
213 pts[0] = 0.0f;
214 pts[1] = pts[3] = canvas->getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
215 pts[2] = canvas->getViewportWidth();
216 canvas->drawLines(pts, 4, &paint);
217}
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 Reckfe5e7b72014-05-23 17:42:28 -0700247 FILE *file = fdopen(fd, "a");
248 fprintf(file, "\n\tDraw\tPrepare\tProcess\tExecute\n");
249
John Reck4c9e59d2015-05-12 07:17:50 -0700250 for (size_t i = 0; i < mFrameSource.size(); i++) {
Chris Craik1b54fb22015-06-02 17:40:58 -0700251 if (mFrameSource[i][FrameInfoIndex::IntendedVsync] <= mLastFrameLogged) {
John Reckfe5e7b72014-05-23 17:42:28 -0700252 continue;
253 }
Chris Craik1b54fb22015-06-02 17:40:58 -0700254 mLastFrameLogged = mFrameSource[i][FrameInfoIndex::IntendedVsync];
John Reckfe5e7b72014-05-23 17:42:28 -0700255 fprintf(file, "\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n",
John Reckbe3fba02015-07-06 13:49:58 -0700256 durationMS(i, FrameInfoIndex::IntendedVsync, FrameInfoIndex::SyncStart),
257 durationMS(i, FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart),
258 durationMS(i, FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers),
259 durationMS(i, FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted));
John Reckfe5e7b72014-05-23 17:42:28 -0700260 }
John Reckfe5e7b72014-05-23 17:42:28 -0700261
262 fflush(file);
263}
264
265} /* namespace uirenderer */
266} /* namespace android */