android_frameworks_base/libs/hwui/DrawProfiler.cpp
Chris Craik d41c4d8c73 Add overrides and switch to nullptr keyword for all files
Adds remaining missing overrides and nullptr usages, missed due to
an extreme failure in tool usage.

Change-Id: I56abd72975a3999ad13330003c348db40f59aebf
2015-01-05 16:49:13 -08:00

282 lines
8.7 KiB
C++

/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "DrawProfiler.h"
#include <cutils/compiler.h>
#include "OpenGLRenderer.h"
#include "Properties.h"
#define DEFAULT_MAX_FRAMES 128
#define RETURN_IF_PROFILING_DISABLED() if (CC_LIKELY(mType == kNone)) return
#define RETURN_IF_DISABLED() if (CC_LIKELY(mType == kNone && !mShowDirtyRegions)) return
#define NANOS_TO_MILLIS_FLOAT(nanos) ((nanos) * 0.000001f)
#define PROFILE_DRAW_WIDTH 3
#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
#define PROFILE_DRAW_DP_PER_MS 7
// Number of floats we want to display from FrameTimingData
// If this is changed make sure to update the indexes below
#define NUM_ELEMENTS 4
#define RECORD_INDEX 0
#define PREPARE_INDEX 1
#define PLAYBACK_INDEX 2
#define SWAPBUFFERS_INDEX 3
// Must be NUM_ELEMENTS in size
static const SkColor ELEMENT_COLORS[] = { 0xcf3e66cc, 0xcf8f00ff, 0xcfdc3912, 0xcfe69800 };
static const SkColor CURRENT_FRAME_COLOR = 0xcf5faa4d;
static const SkColor THRESHOLD_COLOR = 0xff5faa4d;
// We could get this from TimeLord and use the actual frame interval, but
// this is good enough
#define FRAME_THRESHOLD 16
namespace android {
namespace uirenderer {
static int dpToPx(int dp, float density) {
return (int) (dp * density + 0.5f);
}
DrawProfiler::DrawProfiler()
: mType(kNone)
, mDensity(0)
, mData(nullptr)
, mDataSize(0)
, mCurrentFrame(-1)
, mPreviousTime(0)
, mVerticalUnit(0)
, mHorizontalUnit(0)
, mThresholdStroke(0)
, mShowDirtyRegions(false)
, mFlashToggle(false) {
setDensity(1);
}
DrawProfiler::~DrawProfiler() {
destroyData();
}
void DrawProfiler::setDensity(float density) {
if (CC_UNLIKELY(mDensity != density)) {
mDensity = density;
mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
}
}
void DrawProfiler::startFrame(nsecs_t recordDurationNanos) {
RETURN_IF_PROFILING_DISABLED();
mData[mCurrentFrame].record = NANOS_TO_MILLIS_FLOAT(recordDurationNanos);
mPreviousTime = systemTime(CLOCK_MONOTONIC);
}
void DrawProfiler::markPlaybackStart() {
RETURN_IF_PROFILING_DISABLED();
nsecs_t now = systemTime(CLOCK_MONOTONIC);
mData[mCurrentFrame].prepare = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime);
mPreviousTime = now;
}
void DrawProfiler::markPlaybackEnd() {
RETURN_IF_PROFILING_DISABLED();
nsecs_t now = systemTime(CLOCK_MONOTONIC);
mData[mCurrentFrame].playback = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime);
mPreviousTime = now;
}
void DrawProfiler::finishFrame() {
RETURN_IF_PROFILING_DISABLED();
nsecs_t now = systemTime(CLOCK_MONOTONIC);
mData[mCurrentFrame].swapBuffers = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime);
mPreviousTime = now;
mCurrentFrame = (mCurrentFrame + 1) % mDataSize;
}
void DrawProfiler::unionDirty(SkRect* dirty) {
RETURN_IF_DISABLED();
// Not worth worrying about minimizing the dirty region for debugging, so just
// dirty the entire viewport.
if (dirty) {
mDirtyRegion = *dirty;
dirty->setEmpty();
}
}
void DrawProfiler::draw(OpenGLRenderer* canvas) {
RETURN_IF_DISABLED();
if (mShowDirtyRegions) {
mFlashToggle = !mFlashToggle;
if (mFlashToggle) {
SkPaint paint;
paint.setColor(0x7fff0000);
canvas->drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
mDirtyRegion.fRight, mDirtyRegion.fBottom, &paint);
}
}
if (mType == kBars) {
prepareShapes(canvas->getViewportHeight());
drawGraph(canvas);
drawCurrentFrame(canvas);
drawThreshold(canvas);
}
}
void DrawProfiler::createData() {
if (mData) return;
mDataSize = property_get_int32(PROPERTY_PROFILE_MAXFRAMES, DEFAULT_MAX_FRAMES);
if (mDataSize <= 0) mDataSize = 1;
if (mDataSize > 4096) mDataSize = 4096; // Reasonable maximum
mData = (FrameTimingData*) calloc(mDataSize, sizeof(FrameTimingData));
mRects = new float*[NUM_ELEMENTS];
for (int i = 0; i < NUM_ELEMENTS; i++) {
// 4 floats per rect
mRects[i] = (float*) calloc(mDataSize, 4 * sizeof(float));
}
mCurrentFrame = 0;
}
void DrawProfiler::destroyData() {
delete mData;
mData = nullptr;
}
void DrawProfiler::addRect(Rect& r, float data, float* shapeOutput) {
r.top = r.bottom - (data * mVerticalUnit);
shapeOutput[0] = r.left;
shapeOutput[1] = r.top;
shapeOutput[2] = r.right;
shapeOutput[3] = r.bottom;
r.bottom = r.top;
}
void DrawProfiler::prepareShapes(const int baseline) {
Rect r;
r.right = mHorizontalUnit;
for (int i = 0; i < mDataSize; i++) {
const int shapeIndex = i * 4;
r.bottom = baseline;
addRect(r, mData[i].record, mRects[RECORD_INDEX] + shapeIndex);
addRect(r, mData[i].prepare, mRects[PREPARE_INDEX] + shapeIndex);
addRect(r, mData[i].playback, mRects[PLAYBACK_INDEX] + shapeIndex);
addRect(r, mData[i].swapBuffers, mRects[SWAPBUFFERS_INDEX] + shapeIndex);
r.translate(mHorizontalUnit, 0);
}
}
void DrawProfiler::drawGraph(OpenGLRenderer* canvas) {
SkPaint paint;
for (int i = 0; i < NUM_ELEMENTS; i++) {
paint.setColor(ELEMENT_COLORS[i]);
canvas->drawRects(mRects[i], mDataSize * 4, &paint);
}
}
void DrawProfiler::drawCurrentFrame(OpenGLRenderer* canvas) {
// This draws a solid rect over the entirety of the current frame's shape
// To do so we use the bottom of mRects[0] and the top of mRects[NUM_ELEMENTS-1]
// which will therefore fully overlap the previously drawn rects
SkPaint paint;
paint.setColor(CURRENT_FRAME_COLOR);
const int i = mCurrentFrame * 4;
canvas->drawRect(mRects[0][i], mRects[NUM_ELEMENTS-1][i+1], mRects[0][i+2],
mRects[0][i+3], &paint);
}
void DrawProfiler::drawThreshold(OpenGLRenderer* canvas) {
SkPaint paint;
paint.setColor(THRESHOLD_COLOR);
paint.setStrokeWidth(mThresholdStroke);
float pts[4];
pts[0] = 0.0f;
pts[1] = pts[3] = canvas->getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
pts[2] = canvas->getViewportWidth();
canvas->drawLines(pts, 4, &paint);
}
DrawProfiler::ProfileType DrawProfiler::loadRequestedProfileType() {
ProfileType type = kNone;
char buf[PROPERTY_VALUE_MAX] = {'\0',};
if (property_get(PROPERTY_PROFILE, buf, "") > 0) {
if (!strcmp(buf, PROPERTY_PROFILE_VISUALIZE_BARS)) {
type = kBars;
} else if (!strcmp(buf, "true")) {
type = kConsole;
}
}
return type;
}
bool DrawProfiler::loadSystemProperties() {
bool changed = false;
ProfileType newType = loadRequestedProfileType();
if (newType != mType) {
mType = newType;
if (mType == kNone) {
destroyData();
} else {
createData();
}
changed = true;
}
bool showDirty = property_get_bool(PROPERTY_DEBUG_SHOW_DIRTY_REGIONS, false);
if (showDirty != mShowDirtyRegions) {
mShowDirtyRegions = showDirty;
changed = true;
}
return changed;
}
void DrawProfiler::dumpData(int fd) {
RETURN_IF_PROFILING_DISABLED();
// This method logs the last N frames (where N is <= mDataSize) since the
// last call to dumpData(). In other words if there's a dumpData(), draw frame,
// dumpData(), the last dumpData() should only log 1 frame.
const FrameTimingData emptyData = {0, 0, 0, 0};
FILE *file = fdopen(fd, "a");
fprintf(file, "\n\tDraw\tPrepare\tProcess\tExecute\n");
for (int frameOffset = 1; frameOffset <= mDataSize; frameOffset++) {
int i = (mCurrentFrame + frameOffset) % mDataSize;
if (!memcmp(mData + i, &emptyData, sizeof(FrameTimingData))) {
continue;
}
fprintf(file, "\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n",
mData[i].record, mData[i].prepare, mData[i].playback, mData[i].swapBuffers);
}
// reset the buffer
memset(mData, 0, sizeof(FrameTimingData) * mDataSize);
mCurrentFrame = 0;
fflush(file);
}
} /* namespace uirenderer */
} /* namespace android */