blob: 041174265348d5826459d312acf9b1942dc820c8 [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 Reckfe5e7b72014-05-23 17:42:28 -070021
Chris Craik2507c342015-05-04 14:36:49 -070022#define RETURN_IF_PROFILING_DISABLED() if (CC_LIKELY(mType == ProfileType::None)) return
23#define RETURN_IF_DISABLED() if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
John Reckfe5e7b72014-05-23 17:42:28 -070024
John Reckfe5e7b72014-05-23 17:42:28 -070025#define PROFILE_DRAW_WIDTH 3
26#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
27#define PROFILE_DRAW_DP_PER_MS 7
28
29// Number of floats we want to display from FrameTimingData
30// If this is changed make sure to update the indexes below
31#define NUM_ELEMENTS 4
32
33#define RECORD_INDEX 0
34#define PREPARE_INDEX 1
35#define PLAYBACK_INDEX 2
36#define SWAPBUFFERS_INDEX 3
37
38// Must be NUM_ELEMENTS in size
39static const SkColor ELEMENT_COLORS[] = { 0xcf3e66cc, 0xcf8f00ff, 0xcfdc3912, 0xcfe69800 };
40static const SkColor CURRENT_FRAME_COLOR = 0xcf5faa4d;
41static const SkColor THRESHOLD_COLOR = 0xff5faa4d;
42
43// We could get this from TimeLord and use the actual frame interval, but
44// this is good enough
45#define FRAME_THRESHOLD 16
46
47namespace android {
48namespace uirenderer {
49
50static int dpToPx(int dp, float density) {
51 return (int) (dp * density + 0.5f);
52}
53
John Reck4c9e59d2015-05-12 07:17:50 -070054FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source)
55 : mFrameSource(source) {
John Reckfe5e7b72014-05-23 17:42:28 -070056 setDensity(1);
57}
58
John Reck4c9e59d2015-05-12 07:17:50 -070059FrameInfoVisualizer::~FrameInfoVisualizer() {
John Reckfe5e7b72014-05-23 17:42:28 -070060 destroyData();
61}
62
John Reck4c9e59d2015-05-12 07:17:50 -070063void FrameInfoVisualizer::setDensity(float density) {
John Reckfe5e7b72014-05-23 17:42:28 -070064 if (CC_UNLIKELY(mDensity != density)) {
65 mDensity = density;
66 mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
67 mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
68 mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
69 }
70}
71
John Reck4c9e59d2015-05-12 07:17:50 -070072void FrameInfoVisualizer::unionDirty(SkRect* dirty) {
John Reckfe5e7b72014-05-23 17:42:28 -070073 RETURN_IF_DISABLED();
74 // Not worth worrying about minimizing the dirty region for debugging, so just
75 // dirty the entire viewport.
76 if (dirty) {
John Reck23d307c2014-10-27 12:38:48 -070077 mDirtyRegion = *dirty;
John Reckfe5e7b72014-05-23 17:42:28 -070078 dirty->setEmpty();
79 }
80}
81
John Reck4c9e59d2015-05-12 07:17:50 -070082void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) {
John Reck23d307c2014-10-27 12:38:48 -070083 RETURN_IF_DISABLED();
84
85 if (mShowDirtyRegions) {
86 mFlashToggle = !mFlashToggle;
87 if (mFlashToggle) {
88 SkPaint paint;
89 paint.setColor(0x7fff0000);
90 canvas->drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
91 mDirtyRegion.fRight, mDirtyRegion.fBottom, &paint);
92 }
John Reckfe5e7b72014-05-23 17:42:28 -070093 }
94
Chris Craik2507c342015-05-04 14:36:49 -070095 if (mType == ProfileType::Bars) {
John Reck23d307c2014-10-27 12:38:48 -070096 prepareShapes(canvas->getViewportHeight());
97 drawGraph(canvas);
98 drawCurrentFrame(canvas);
99 drawThreshold(canvas);
100 }
John Reckfe5e7b72014-05-23 17:42:28 -0700101}
102
John Reck4c9e59d2015-05-12 07:17:50 -0700103void FrameInfoVisualizer::createData() {
104 if (mRects.get()) return;
John Reckfe5e7b72014-05-23 17:42:28 -0700105
John Reck4c9e59d2015-05-12 07:17:50 -0700106 mRects.reset(new float*[mFrameSource.capacity()]);
John Reckfe5e7b72014-05-23 17:42:28 -0700107 for (int i = 0; i < NUM_ELEMENTS; i++) {
108 // 4 floats per rect
John Reck4c9e59d2015-05-12 07:17:50 -0700109 mRects.get()[i] = (float*) calloc(mFrameSource.capacity(), 4 * sizeof(float));
John Reckfe5e7b72014-05-23 17:42:28 -0700110 }
John Reckfe5e7b72014-05-23 17:42:28 -0700111}
112
John Reck4c9e59d2015-05-12 07:17:50 -0700113void FrameInfoVisualizer::destroyData() {
114 mRects.reset(nullptr);
John Reckfe5e7b72014-05-23 17:42:28 -0700115}
116
John Reck4c9e59d2015-05-12 07:17:50 -0700117void FrameInfoVisualizer::addRect(Rect& r, float data, float* shapeOutput) {
John Reckfe5e7b72014-05-23 17:42:28 -0700118 r.top = r.bottom - (data * mVerticalUnit);
119 shapeOutput[0] = r.left;
120 shapeOutput[1] = r.top;
121 shapeOutput[2] = r.right;
122 shapeOutput[3] = r.bottom;
123 r.bottom = r.top;
124}
125
John Reck4c9e59d2015-05-12 07:17:50 -0700126void FrameInfoVisualizer::prepareShapes(const int baseline) {
John Reckfe5e7b72014-05-23 17:42:28 -0700127 Rect r;
128 r.right = mHorizontalUnit;
John Reck4c9e59d2015-05-12 07:17:50 -0700129 for (size_t i = 0; i < mFrameSource.size(); i++) {
John Reckfe5e7b72014-05-23 17:42:28 -0700130 const int shapeIndex = i * 4;
131 r.bottom = baseline;
John Reck4c9e59d2015-05-12 07:17:50 -0700132 addRect(r, recordDuration(i), mRects.get()[RECORD_INDEX] + shapeIndex);
133 addRect(r, prepareDuration(i), mRects.get()[PREPARE_INDEX] + shapeIndex);
134 addRect(r, issueDrawDuration(i), mRects.get()[PLAYBACK_INDEX] + shapeIndex);
135 addRect(r, swapBuffersDuration(i), mRects.get()[SWAPBUFFERS_INDEX] + shapeIndex);
John Reckfe5e7b72014-05-23 17:42:28 -0700136 r.translate(mHorizontalUnit, 0);
137 }
138}
139
John Reck4c9e59d2015-05-12 07:17:50 -0700140void FrameInfoVisualizer::drawGraph(OpenGLRenderer* canvas) {
John Reckfe5e7b72014-05-23 17:42:28 -0700141 SkPaint paint;
142 for (int i = 0; i < NUM_ELEMENTS; i++) {
143 paint.setColor(ELEMENT_COLORS[i]);
John Reck4c9e59d2015-05-12 07:17:50 -0700144 canvas->drawRects(mRects.get()[i], mFrameSource.capacity() * 4, &paint);
John Reckfe5e7b72014-05-23 17:42:28 -0700145 }
146}
147
John Reck4c9e59d2015-05-12 07:17:50 -0700148void FrameInfoVisualizer::drawCurrentFrame(OpenGLRenderer* canvas) {
John Reckfe5e7b72014-05-23 17:42:28 -0700149 // This draws a solid rect over the entirety of the current frame's shape
150 // To do so we use the bottom of mRects[0] and the top of mRects[NUM_ELEMENTS-1]
151 // which will therefore fully overlap the previously drawn rects
152 SkPaint paint;
153 paint.setColor(CURRENT_FRAME_COLOR);
John Reck4c9e59d2015-05-12 07:17:50 -0700154 const int i = (mFrameSource.size() - 1) * 4;
155 canvas->drawRect(mRects.get()[0][i], mRects.get()[NUM_ELEMENTS-1][i+1],
156 mRects.get()[0][i+2], mRects.get()[0][i+3], &paint);
John Reckfe5e7b72014-05-23 17:42:28 -0700157}
158
John Reck4c9e59d2015-05-12 07:17:50 -0700159void FrameInfoVisualizer::drawThreshold(OpenGLRenderer* canvas) {
John Reckfe5e7b72014-05-23 17:42:28 -0700160 SkPaint paint;
161 paint.setColor(THRESHOLD_COLOR);
162 paint.setStrokeWidth(mThresholdStroke);
163
164 float pts[4];
165 pts[0] = 0.0f;
166 pts[1] = pts[3] = canvas->getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
167 pts[2] = canvas->getViewportWidth();
168 canvas->drawLines(pts, 4, &paint);
169}
170
John Reck4c9e59d2015-05-12 07:17:50 -0700171bool FrameInfoVisualizer::consumeProperties() {
John Reck23d307c2014-10-27 12:38:48 -0700172 bool changed = false;
Chris Craik2507c342015-05-04 14:36:49 -0700173 ProfileType newType = Properties::getProfileType();
John Reckfe5e7b72014-05-23 17:42:28 -0700174 if (newType != mType) {
175 mType = newType;
Chris Craik2507c342015-05-04 14:36:49 -0700176 if (mType == ProfileType::None) {
John Reckfe5e7b72014-05-23 17:42:28 -0700177 destroyData();
178 } else {
179 createData();
180 }
John Reck23d307c2014-10-27 12:38:48 -0700181 changed = true;
John Reckfe5e7b72014-05-23 17:42:28 -0700182 }
Chris Craik2507c342015-05-04 14:36:49 -0700183
184 bool showDirty = Properties::showDirtyRegions;
John Reck23d307c2014-10-27 12:38:48 -0700185 if (showDirty != mShowDirtyRegions) {
186 mShowDirtyRegions = showDirty;
187 changed = true;
188 }
189 return changed;
John Reckfe5e7b72014-05-23 17:42:28 -0700190}
191
John Reck4c9e59d2015-05-12 07:17:50 -0700192void FrameInfoVisualizer::dumpData(int fd) {
John Reck23d307c2014-10-27 12:38:48 -0700193 RETURN_IF_PROFILING_DISABLED();
John Reckfe5e7b72014-05-23 17:42:28 -0700194
195 // This method logs the last N frames (where N is <= mDataSize) since the
196 // last call to dumpData(). In other words if there's a dumpData(), draw frame,
197 // dumpData(), the last dumpData() should only log 1 frame.
198
John Reckfe5e7b72014-05-23 17:42:28 -0700199 FILE *file = fdopen(fd, "a");
200 fprintf(file, "\n\tDraw\tPrepare\tProcess\tExecute\n");
201
John Reck4c9e59d2015-05-12 07:17:50 -0700202 for (size_t i = 0; i < mFrameSource.size(); i++) {
203 if (mFrameSource[i][FrameInfoIndex::kIntendedVsync] <= mLastFrameLogged) {
John Reckfe5e7b72014-05-23 17:42:28 -0700204 continue;
205 }
John Reck4c9e59d2015-05-12 07:17:50 -0700206 mLastFrameLogged = mFrameSource[i][FrameInfoIndex::kIntendedVsync];
John Reckfe5e7b72014-05-23 17:42:28 -0700207 fprintf(file, "\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n",
John Reck4c9e59d2015-05-12 07:17:50 -0700208 recordDuration(i), prepareDuration(i),
209 issueDrawDuration(i), swapBuffersDuration(i));
John Reckfe5e7b72014-05-23 17:42:28 -0700210 }
John Reckfe5e7b72014-05-23 17:42:28 -0700211
212 fflush(file);
213}
214
215} /* namespace uirenderer */
216} /* namespace android */