diff options
author | John Reck <jreck@google.com> | 2014-05-23 17:42:28 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2014-05-29 15:00:29 -0700 |
commit | fe5e7b7346a54537b980796ceeca66bfdbd05561 (patch) | |
tree | 4036571ea103cd41fbd5fe3a805191c1bef9898c /libs | |
parent | 45d01929291eba56e1bce582192941446b86bf5a (diff) | |
download | frameworks_base-fe5e7b7346a54537b980796ceeca66bfdbd05561.zip frameworks_base-fe5e7b7346a54537b980796ceeca66bfdbd05561.tar.gz frameworks_base-fe5e7b7346a54537b980796ceeca66bfdbd05561.tar.bz2 |
Enable debug stuffs
Bug: 14596762
* dumpsys gfxinfo implemented
* profile GPU visual_bars implemented
Change-Id: Icb948a9d5af5989b5615504d0d76ade64b93ef5b
Diffstat (limited to 'libs')
-rw-r--r-- | libs/hwui/Android.mk | 1 | ||||
-rw-r--r-- | libs/hwui/DrawProfiler.cpp | 261 | ||||
-rw-r--r-- | libs/hwui/DrawProfiler.h | 96 | ||||
-rw-r--r-- | libs/hwui/Properties.h | 30 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 11 | ||||
-rw-r--r-- | libs/hwui/RenderNode.h | 1 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 13 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 5 | ||||
-rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.cpp | 9 | ||||
-rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.h | 5 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 25 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.h | 6 |
12 files changed, 453 insertions, 10 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 2cadf09..442f327 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -23,6 +23,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) DisplayListLogBuffer.cpp \ DisplayListRenderer.cpp \ Dither.cpp \ + DrawProfiler.cpp \ Extensions.cpp \ FboCache.cpp \ GradientCache.cpp \ diff --git a/libs/hwui/DrawProfiler.cpp b/libs/hwui/DrawProfiler.cpp new file mode 100644 index 0000000..971a66e --- /dev/null +++ b/libs/hwui/DrawProfiler.cpp @@ -0,0 +1,261 @@ +/* + * 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_DISABLED() if (CC_LIKELY(mType == kNone)) 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(NULL) + , mDataSize(0) + , mCurrentFrame(-1) + , mPreviousTime(0) + , mVerticalUnit(0) + , mHorizontalUnit(0) + , mThresholdStroke(0) { + 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_DISABLED(); + mData[mCurrentFrame].record = NANOS_TO_MILLIS_FLOAT(recordDurationNanos); + mPreviousTime = systemTime(CLOCK_MONOTONIC); +} + +void DrawProfiler::markPlaybackStart() { + RETURN_IF_DISABLED(); + nsecs_t now = systemTime(CLOCK_MONOTONIC); + mData[mCurrentFrame].prepare = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime); + mPreviousTime = now; +} + +void DrawProfiler::markPlaybackEnd() { + RETURN_IF_DISABLED(); + nsecs_t now = systemTime(CLOCK_MONOTONIC); + mData[mCurrentFrame].playback = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime); + mPreviousTime = now; +} + +void DrawProfiler::finishFrame() { + RETURN_IF_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(Rect* dirty) { + RETURN_IF_DISABLED(); + // Not worth worrying about minimizing the dirty region for debugging, so just + // dirty the entire viewport. + if (dirty) { + dirty->setEmpty(); + } +} + +void DrawProfiler::draw(OpenGLRenderer* canvas) { + if (CC_LIKELY(mType != kBars)) { + return; + } + + 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 = NULL; +} + +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() { + ProfileType newType = loadRequestedProfileType(); + if (newType != mType) { + mType = newType; + if (mType == kNone) { + destroyData(); + } else { + createData(); + } + return true; + } + return false; +} + +void DrawProfiler::dumpData(int fd) { + RETURN_IF_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 */ diff --git a/libs/hwui/DrawProfiler.h b/libs/hwui/DrawProfiler.h new file mode 100644 index 0000000..c1aa1c6 --- /dev/null +++ b/libs/hwui/DrawProfiler.h @@ -0,0 +1,96 @@ +/* + * 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. + */ +#ifndef DRAWPROFILER_H +#define DRAWPROFILER_H + +#include <utils/Timers.h> +#include "Rect.h" + +namespace android { +namespace uirenderer { + +class OpenGLRenderer; + +class DrawProfiler { +public: + DrawProfiler(); + ~DrawProfiler(); + + bool loadSystemProperties(); + void setDensity(float density); + + void startFrame(nsecs_t recordDurationNanos = 0); + void markPlaybackStart(); + void markPlaybackEnd(); + void finishFrame(); + + void unionDirty(Rect* dirty); + void draw(OpenGLRenderer* canvas); + + void dumpData(int fd); + +private: + enum ProfileType { + kNone, + kConsole, + kBars, + }; + + typedef struct { + float record; + float prepare; + float playback; + float swapBuffers; + } FrameTimingData; + + void createData(); + void destroyData(); + + void addRect(Rect& r, float data, float* shapeOutput); + void prepareShapes(const int baseline); + void drawGraph(OpenGLRenderer* canvas); + void drawCurrentFrame(OpenGLRenderer* canvas); + void drawThreshold(OpenGLRenderer* canvas); + + ProfileType loadRequestedProfileType(); + + ProfileType mType; + float mDensity; + + FrameTimingData* mData; + int mDataSize; + + int mCurrentFrame; + nsecs_t mPreviousTime; + + int mVerticalUnit; + int mHorizontalUnit; + int mThresholdStroke; + + /* + * mRects represents an array of rect shapes, divided into NUM_ELEMENTS + * groups such that each group is drawn with the same paint. + * For example mRects[0] is the array of rect floats suitable for + * OpenGLRenderer:drawRects() that makes up all the FrameTimingData:record + * information. + */ + float** mRects; +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* DRAWPROFILER_H */ diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 20b8f2f..12241b8 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -89,6 +89,36 @@ enum DebugLevel { #define PROPERTY_DEBUG_NV_PROFILING "debug.hwui.nv_profiling" /** + * System property used to enable or disable hardware rendering profiling. + * The default value of this property is assumed to be false. + * + * When profiling is enabled, the adb shell dumpsys gfxinfo command will + * output extra information about the time taken to execute by the last + * frames. + * + * Possible values: + * "true", to enable profiling + * "visual_bars", to enable profiling and visualize the results on screen + * "false", to disable profiling + */ +#define PROPERTY_PROFILE "debug.hwui.profile" +#define PROPERTY_PROFILE_VISUALIZE_BARS "visual_bars" + +/** + * System property used to specify the number of frames to be used + * when doing hardware rendering profiling. + * The default value of this property is #PROFILE_MAX_FRAMES. + * + * When profiling is enabled, the adb shell dumpsys gfxinfo command will + * output extra information about the time taken to execute by the last + * frames. + * + * Possible values: + * "60", to set the limit of frames to 60 + */ +#define PROPERTY_PROFILE_MAXFRAMES "debug.hwui.profile.maxframes" + +/** * Used to enable/disable non-rectangular clipping debugging. * * The accepted values are: diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index df74f31..d964efc 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -93,6 +93,17 @@ void RenderNode::output(uint32_t level) { ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName()); } +int RenderNode::getDebugSize() { + int size = sizeof(RenderNode); + if (mStagingDisplayListData) { + size += mStagingDisplayListData->allocator.usedSize(); + } + if (mDisplayListData && mDisplayListData != mStagingDisplayListData) { + size += mDisplayListData->allocator.usedSize(); + } + return size; +} + void RenderNode::prepareTree(TreeInfo& info) { ATRACE_CALL(); diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 1811a7b..1a5377b 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -119,6 +119,7 @@ public: void replayNodeInParent(ReplayStateStruct& replayStruct, const int level); ANDROID_API void output(uint32_t level = 1); + ANDROID_API int getDebugSize(); bool isRenderable() const { return mDisplayListData && mDisplayListData->hasDrawOps; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 160fbea..f849273 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -486,6 +486,8 @@ void CanvasContext::draw(Rect* dirty) { LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE, "drawDisplayList called on a context with no canvas or surface!"); + profiler().markPlaybackStart(); + EGLint width, height; mGlobalContext->beginFrame(mEglSurface, &width, &height); if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) { @@ -493,6 +495,8 @@ void CanvasContext::draw(Rect* dirty) { dirty = NULL; } else if (!mDirtyRegionsEnabled || mHaveNewSurface) { dirty = NULL; + } else { + profiler().unionDirty(dirty); } status_t status; @@ -506,14 +510,17 @@ void CanvasContext::draw(Rect* dirty) { Rect outBounds; status |= mCanvas->drawDisplayList(mRootRenderNode.get(), outBounds); - // TODO: Draw debug info - // TODO: Performance tracking + profiler().draw(mCanvas); mCanvas->finish(); + profiler().markPlaybackEnd(); + if (status & DrawGlInfo::kStatusDrew) { swapBuffers(); } + + profiler().finishFrame(); } // Called by choreographer to do an RT-driven animation @@ -524,6 +531,8 @@ void CanvasContext::doFrame() { ATRACE_CALL(); + profiler().startFrame(); + TreeInfo info; info.evaluateAnimations = true; info.performStagingPush = false; diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index da85d44..a04269b 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -23,6 +23,7 @@ #include <utils/Functor.h> #include <utils/Vector.h> +#include "../DrawProfiler.h" #include "../RenderNode.h" #include "RenderTask.h" #include "RenderThread.h" @@ -77,6 +78,8 @@ public: void notifyFramePending(); + DrawProfiler& profiler() { return mProfiler; } + private: friend class RegisterFrameCallbackTask; @@ -100,6 +103,8 @@ private: bool mHaveNewSurface; const sp<RenderNode> mRootRenderNode; + + DrawProfiler mProfiler; }; } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index ee3e059..7ea358f 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -34,6 +34,8 @@ DrawFrameTask::DrawFrameTask() : mRenderThread(NULL) , mContext(NULL) , mFrameTimeNanos(0) + , mRecordDurationNanos(0) + , mDensity(1.0f) // safe enough default , mSyncResult(kSync_OK) { } @@ -64,15 +66,17 @@ void DrawFrameTask::setDirty(int left, int top, int right, int bottom) { mDirty.set(left, top, right, bottom); } -int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos) { +int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos) { LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!"); mSyncResult = kSync_OK; mFrameTimeNanos = frameTimeNanos; + mRecordDurationNanos = recordDurationNanos; postAndWait(); // Reset the single-frame data mFrameTimeNanos = 0; + mRecordDurationNanos = 0; mDirty.setEmpty(); return mSyncResult; @@ -87,6 +91,9 @@ void DrawFrameTask::postAndWait() { void DrawFrameTask::run() { ATRACE_NAME("DrawFrame"); + mContext->profiler().setDensity(mDensity); + mContext->profiler().startFrame(mRecordDurationNanos); + bool canUnblockUiThread; bool canDrawThisFrame; { diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index acbc02a..30c8880 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -60,7 +60,8 @@ public: void removeLayer(DeferredLayerUpdater* layer); void setDirty(int left, int top, int right, int bottom); - int drawFrame(nsecs_t frameTimeNanos); + void setDensity(float density) { mDensity = density; } + int drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos); virtual void run(); @@ -80,6 +81,8 @@ private: *********************************************/ Rect mDirty; nsecs_t mFrameTimeNanos; + nsecs_t mRecordDurationNanos; + float mDensity; int mSyncResult; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 8e772f2..77c0aa7 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -99,16 +99,20 @@ void RenderProxy::setFrameInterval(nsecs_t frameIntervalNanos) { post(task); } -CREATE_BRIDGE0(loadSystemProperties) { +CREATE_BRIDGE1(loadSystemProperties, CanvasContext* context) { bool needsRedraw = false; if (Caches::hasInstance()) { needsRedraw = Caches::getInstance().initProperties(); } + if (args->context->profiler().loadSystemProperties()) { + needsRedraw = true; + } return (void*) needsRedraw; } bool RenderProxy::loadSystemProperties() { SETUP_TASK(loadSystemProperties); + args->context = mContext; return (bool) postAndWait(task); } @@ -175,10 +179,11 @@ void RenderProxy::setOpaque(bool opaque) { post(task); } -int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, - int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) { +int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos, + float density, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) { mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom); - return mDrawFrameTask.drawFrame(frameTimeNanos); + mDrawFrameTask.setDensity(density); + return mDrawFrameTask.drawFrame(frameTimeNanos, recordDurationNanos); } CREATE_BRIDGE1(destroyCanvasAndSurface, CanvasContext* context) { @@ -315,6 +320,18 @@ void RenderProxy::notifyFramePending() { mRenderThread.queueAtFront(task); } +CREATE_BRIDGE2(dumpProfileInfo, CanvasContext* context, int fd) { + args->context->profiler().dumpData(args->fd); + return NULL; +} + +void RenderProxy::dumpProfileInfo(int fd) { + SETUP_TASK(dumpProfileInfo); + args->context = mContext; + args->fd = fd; + postAndWait(task); +} + void RenderProxy::post(RenderTask* task) { mRenderThread.queue(task); } diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 22d4e22..c8d42ec 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -69,8 +69,8 @@ public: ANDROID_API void pauseSurface(const sp<ANativeWindow>& window); ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius); ANDROID_API void setOpaque(bool opaque); - ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos, - int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom); + ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos, + float density, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom); ANDROID_API void destroyCanvasAndSurface(); ANDROID_API void invokeFunctor(Functor* functor, bool waitForCompletion); @@ -87,6 +87,8 @@ public: ANDROID_API void fence(); ANDROID_API void notifyFramePending(); + ANDROID_API void dumpProfileInfo(int fd); + private: RenderThread& mRenderThread; CanvasContext* mContext; |