summaryrefslogtreecommitdiffstats
path: root/libs/hwui/renderthread
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/renderthread')
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp93
-rw-r--r--libs/hwui/renderthread/CanvasContext.h35
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp23
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.h13
-rw-r--r--libs/hwui/renderthread/EglManager.cpp34
-rw-r--r--libs/hwui/renderthread/EglManager.h2
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp142
-rw-r--r--libs/hwui/renderthread/RenderProxy.h10
-rw-r--r--libs/hwui/renderthread/RenderTask.cpp7
-rw-r--r--libs/hwui/renderthread/RenderTask.h8
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp39
-rw-r--r--libs/hwui/renderthread/RenderThread.h17
-rw-r--r--libs/hwui/renderthread/TimeLord.cpp8
-rw-r--r--libs/hwui/renderthread/TimeLord.h4
14 files changed, 269 insertions, 166 deletions
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b7e1752..9456073 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -16,19 +16,19 @@
#include "CanvasContext.h"
-#include <algorithm>
-#include <private/hwui/DrawGlInfo.h>
-#include <strings.h>
-
#include "EglManager.h"
#include "RenderThread.h"
#include "../AnimationContext.h"
#include "../Caches.h"
#include "../DeferredLayerUpdater.h"
-#include "../RenderState.h"
+#include "../renderstate/RenderState.h"
+#include "../renderstate/Stencil.h"
#include "../LayerRenderer.h"
#include "../OpenGLRenderer.h"
-#include "../Stencil.h"
+
+#include <algorithm>
+#include <private/hwui/DrawGlInfo.h>
+#include <strings.h>
#define TRIM_MEMORY_COMPLETE 80
#define TRIM_MEMORY_UI_HIDDEN 20
@@ -45,28 +45,29 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
, mBufferPreserved(false)
, mSwapBehavior(kSwap_default)
, mOpaque(!translucent)
- , mCanvas(NULL)
+ , mCanvas(nullptr)
, mHaveNewSurface(false)
- , mRootRenderNode(rootRenderNode) {
- mAnimationContext = contextFactory->createAnimationContext(mRenderThread.timeLord());
+ , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
+ , mRootRenderNode(rootRenderNode)
+ , mCurrentFrameInfo(nullptr) {
mRenderThread.renderState().registerCanvasContext(this);
+ mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
}
CanvasContext::~CanvasContext() {
destroy();
- delete mAnimationContext;
mRenderThread.renderState().unregisterCanvasContext(this);
}
void CanvasContext::destroy() {
stopDrawing();
- setSurface(NULL);
+ setSurface(nullptr);
freePrefetechedLayers();
destroyHardwareResources();
mAnimationContext->destroy();
if (mCanvas) {
delete mCanvas;
- mCanvas = 0;
+ mCanvas = nullptr;
}
}
@@ -96,7 +97,7 @@ void CanvasContext::setSurface(ANativeWindow* window) {
void CanvasContext::swapBuffers() {
if (CC_UNLIKELY(!mEglManager.swapBuffers(mEglSurface))) {
- setSurface(NULL);
+ setSurface(nullptr);
}
mHaveNewSurface = false;
}
@@ -128,8 +129,8 @@ bool CanvasContext::pauseSurface(ANativeWindow* window) {
}
// TODO: don't pass viewport size, it's automatic via EGL
-void CanvasContext::setup(int width, int height, const Vector3& lightCenter,
- float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
+void CanvasContext::setup(int width, int height, const Vector3& lightCenter, float lightRadius,
+ uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
if (!mCanvas) return;
mCanvas->initLight(lightCenter, lightRadius, ambientShadowAlpha, spotShadowAlpha);
}
@@ -152,9 +153,13 @@ void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) {
}
}
-void CanvasContext::prepareTree(TreeInfo& info) {
+void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo) {
mRenderThread.removeFrameCallback(this);
+ mCurrentFrameInfo = &mFrames.next();
+ mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
+ mCurrentFrameInfo->markSyncStart();
+
info.damageAccumulator = &mDamageAccumulator;
info.renderer = mCanvas;
if (mPrefetechedLayers.size() && info.mode == TreeInfo::MODE_FULL) {
@@ -204,6 +209,7 @@ void CanvasContext::draw() {
"drawRenderNode called on a context with no canvas or surface!");
profiler().markPlaybackStart();
+ mCurrentFrameInfo->markIssueDrawCommandsStart();
SkRect dirty;
mDamageAccumulator.finish(&dirty);
@@ -224,29 +230,35 @@ void CanvasContext::draw() {
profiler().unionDirty(&dirty);
}
- status_t status;
if (!dirty.isEmpty()) {
- status = mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,
+ mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,
dirty.fRight, dirty.fBottom, mOpaque);
} else {
- status = mCanvas->prepare(mOpaque);
+ mCanvas->prepare(mOpaque);
}
Rect outBounds;
- status |= mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);
+ mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);
profiler().draw(mCanvas);
- mCanvas->finish();
+ bool drew = mCanvas->finish();
profiler().markPlaybackEnd();
- if (status & DrawGlInfo::kStatusDrew) {
+ // Even if we decided to cancel the frame, from the perspective of jank
+ // metrics the frame was swapped at this point
+ mCurrentFrameInfo->markSwapBuffers();
+
+ if (drew) {
swapBuffers();
} else {
mEglManager.cancelFrame();
}
+ // TODO: Use a fence for real completion?
+ mCurrentFrameInfo->markFrameCompleted();
+ mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo);
profiler().finishFrame();
}
@@ -259,9 +271,14 @@ void CanvasContext::doFrame() {
ATRACE_CALL();
profiler().startFrame();
+ int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
+ UiFrameInfoBuilder(frameInfo)
+ .addFlag(FrameInfoFlags::kRTAnimation)
+ .setVsync(mRenderThread.timeLord().computeFrameTimeNanos(),
+ mRenderThread.timeLord().latestVsync());
TreeInfo info(TreeInfo::MODE_RT_ONLY, mRenderThread.renderState());
- prepareTree(info);
+ prepareTree(info, frameInfo);
if (info.out.canDrawThisFrame) {
draw();
}
@@ -275,19 +292,19 @@ void CanvasContext::invokeFunctor(RenderThread& thread, Functor* functor) {
mode = DrawGlInfo::kModeProcess;
}
- thread.renderState().invokeFunctor(functor, mode, NULL);
+ thread.renderState().invokeFunctor(functor, mode, nullptr);
}
void CanvasContext::markLayerInUse(RenderNode* node) {
if (mPrefetechedLayers.erase(node)) {
- node->decStrong(0);
+ node->decStrong(nullptr);
}
}
static void destroyPrefetechedNode(RenderNode* node) {
ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...", node->getName());
node->destroyHardwareResources();
- node->decStrong(0);
+ node->decStrong(nullptr);
}
void CanvasContext::freePrefetechedLayers() {
@@ -321,7 +338,7 @@ void CanvasContext::buildLayer(RenderNode* node) {
mCanvas->markLayersAsBuildLayers();
mCanvas->flushLayerUpdates();
- node->incStrong(0);
+ node->incStrong(nullptr);
mPrefetechedLayers.insert(node);
}
@@ -374,6 +391,28 @@ void CanvasContext::setTextureAtlas(RenderThread& thread,
thread.eglManager().setTextureAtlas(buffer, map, mapSize);
}
+void CanvasContext::dumpFrames(int fd) {
+ FILE* file = fdopen(fd, "a");
+ fprintf(file, "\n\n---PROFILEDATA---");
+ for (size_t i = 0; i < mFrames.size(); i++) {
+ FrameInfo& frame = mFrames[i];
+ if (frame[FrameInfoIndex::kSyncStart] == 0) {
+ continue;
+ }
+ fprintf(file, "\n");
+ for (int i = 0; i < static_cast<int>(FrameInfoIndex::kNumIndexes); i++) {
+ fprintf(file, "%" PRId64 ",", frame[i]);
+ }
+ }
+ fprintf(file, "\n---PROFILEDATA---\n\n");
+ fflush(file);
+}
+
+void CanvasContext::resetFrameStats() {
+ mFrames.clear();
+ mRenderThread.jankTracker().reset();
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0cc2c7c..c3904c2 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -17,7 +17,14 @@
#ifndef CANVASCONTEXT_H_
#define CANVASCONTEXT_H_
-#include <set>
+#include "DamageAccumulator.h"
+#include "DrawProfiler.h"
+#include "IContextFactory.h"
+#include "FrameInfo.h"
+#include "RenderNode.h"
+#include "utils/RingBuffer.h"
+#include "renderthread/RenderTask.h"
+#include "renderthread/RenderThread.h"
#include <cutils/compiler.h>
#include <EGL/egl.h>
@@ -25,14 +32,8 @@
#include <utils/Functor.h>
#include <utils/Vector.h>
-#include "../DamageAccumulator.h"
-#include "../DrawProfiler.h"
-#include "../IContextFactory.h"
-#include "../RenderNode.h"
-#include "RenderTask.h"
-#include "RenderThread.h"
-
-#define FUNCTOR_PROCESS_DELAY 4
+#include <set>
+#include <string>
namespace android {
namespace uirenderer {
@@ -75,12 +76,12 @@ public:
void setOpaque(bool opaque);
void makeCurrent();
void processLayerUpdate(DeferredLayerUpdater* layerUpdater);
- void prepareTree(TreeInfo& info);
+ void prepareTree(TreeInfo& info, int64_t* uiFrameInfo);
void draw();
void destroy();
// IFrameCallback, Chroreographer-driven frame callback entry point
- virtual void doFrame();
+ virtual void doFrame() override;
void buildLayer(RenderNode* node);
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
@@ -103,6 +104,12 @@ public:
DrawProfiler& profiler() { return mProfiler; }
+ void dumpFrames(int fd);
+ void resetFrameStats();
+
+ void setName(const std::string&& name) { mName = name; }
+ const std::string& name() { return mName; }
+
private:
friend class RegisterFrameCallbackTask;
// TODO: Replace with something better for layer & other GL object
@@ -128,11 +135,15 @@ private:
OpenGLRenderer* mCanvas;
bool mHaveNewSurface;
DamageAccumulator mDamageAccumulator;
- AnimationContext* mAnimationContext;
+ std::unique_ptr<AnimationContext> mAnimationContext;
const sp<RenderNode> mRootRenderNode;
DrawProfiler mProfiler;
+ FrameInfo* mCurrentFrameInfo;
+ // Ring buffer large enough for 1 second worth of frames
+ RingBuffer<FrameInfo, 60> mFrames;
+ std::string mName;
std::set<RenderNode*> mPrefetechedLayers;
};
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 97b31a9..35391b2 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -32,11 +32,8 @@ namespace uirenderer {
namespace renderthread {
DrawFrameTask::DrawFrameTask()
- : mRenderThread(NULL)
- , mContext(NULL)
- , mFrameTimeNanos(0)
- , mRecordDurationNanos(0)
- , mDensity(1.0f) // safe enough default
+ : mRenderThread(nullptr)
+ , mContext(nullptr)
, mSyncResult(kSync_OK) {
}
@@ -68,18 +65,12 @@ void DrawFrameTask::removeLayerUpdate(DeferredLayerUpdater* layer) {
}
}
-int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos) {
+int DrawFrameTask::drawFrame() {
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;
-
return mSyncResult;
}
@@ -92,8 +83,7 @@ void DrawFrameTask::postAndWait() {
void DrawFrameTask::run() {
ATRACE_NAME("DrawFrame");
- mContext->profiler().setDensity(mDensity);
- mContext->profiler().startFrame(mRecordDurationNanos);
+ mContext->profiler().startFrame();
bool canUnblockUiThread;
bool canDrawThisFrame;
@@ -122,7 +112,8 @@ void DrawFrameTask::run() {
bool DrawFrameTask::syncFrameState(TreeInfo& info) {
ATRACE_CALL();
- mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos);
+ int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::kVsync)];
+ mRenderThread->timeLord().vsyncReceived(vsync);
mContext->makeCurrent();
Caches::getInstance().textureCache.resetMarkInUse();
@@ -130,7 +121,7 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) {
mContext->processLayerUpdate(mLayers[i].get());
}
mLayers.clear();
- mContext->prepareTree(info);
+ mContext->prepareTree(info, mFrameInfo);
// This is after the prepareTree so that any pending operations
// (RenderNode tree state, prefetched layers, etc...) will be flushed.
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 28f6cb2..8039643 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -25,6 +25,7 @@
#include "RenderTask.h"
#include "../Rect.h"
+#include "../FrameInfo.h"
#include "../TreeInfo.h"
namespace android {
@@ -61,10 +62,11 @@ public:
void pushLayerUpdate(DeferredLayerUpdater* layer);
void removeLayerUpdate(DeferredLayerUpdater* layer);
- void setDensity(float density) { mDensity = density; }
- int drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos);
+ int drawFrame();
- virtual void run();
+ int64_t* frameInfo() { return mFrameInfo; }
+
+ virtual void run() override;
private:
void postAndWait();
@@ -80,12 +82,11 @@ private:
/*********************************************
* Single frame data
*********************************************/
- nsecs_t mFrameTimeNanos;
- nsecs_t mRecordDurationNanos;
- float mDensity;
std::vector< sp<DeferredLayerUpdater> > mLayers;
int mSyncResult;
+
+ int64_t mFrameInfo[UI_THREAD_FRAME_INFO_SIZE];
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 8fb1b10..3afca2f 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -16,15 +16,19 @@
#include "EglManager.h"
+#include "../Caches.h"
+#include "../renderstate/RenderState.h"
+#include "RenderThread.h"
+
#include <cutils/log.h>
#include <cutils/properties.h>
-
-#include "../RenderState.h"
-#include "RenderThread.h"
+#include <EGL/eglext.h>
#define PROPERTY_RENDER_DIRTY_REGIONS "debug.hwui.render_dirty_regions"
#define GLES_VERSION 2
+#define WAIT_FOR_GPU_COMPLETION 0
+
// Android-specific addition that is used to show when frames began in systrace
EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
@@ -67,12 +71,12 @@ static bool load_dirty_regions_property() {
EglManager::EglManager(RenderThread& thread)
: mRenderThread(thread)
, mEglDisplay(EGL_NO_DISPLAY)
- , mEglConfig(0)
+ , mEglConfig(nullptr)
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
, mAllowPreserveBuffer(load_dirty_regions_property())
, mCurrentSurface(EGL_NO_SURFACE)
- , mAtlasMap(NULL)
+ , mAtlasMap(nullptr)
, mAtlasMapSize(0)
, mInFrame(false) {
mCanSetPreserveBuffer = mAllowPreserveBuffer;
@@ -193,7 +197,7 @@ void EglManager::usePBufferSurface() {
EGLSurface EglManager::createSurface(EGLNativeWindowType window) {
initialize();
- EGLSurface surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, NULL);
+ EGLSurface surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, nullptr);
LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
"Failed to create EGLSurface for window %p, eglErr = %s",
(void*) window, egl_error_str());
@@ -213,9 +217,6 @@ void EglManager::destroy() {
if (mEglDisplay == EGL_NO_DISPLAY) return;
usePBufferSurface();
- if (Caches::hasInstance()) {
- Caches::getInstance().terminate();
- }
mRenderThread.renderState().onGLContextDestroyed();
eglDestroyContext(mEglDisplay, mEglContext);
@@ -262,6 +263,14 @@ void EglManager::beginFrame(EGLSurface surface, EGLint* width, EGLint* height) {
bool EglManager::swapBuffers(EGLSurface surface) {
mInFrame = false;
+
+#if WAIT_FOR_GPU_COMPLETION
+ {
+ ATRACE_NAME("Finishing GPU work");
+ fence();
+ }
+#endif
+
eglSwapBuffers(mEglDisplay, surface);
EGLint err = eglGetError();
if (CC_LIKELY(err == EGL_SUCCESS)) {
@@ -280,6 +289,13 @@ bool EglManager::swapBuffers(EGLSurface surface) {
return false;
}
+void EglManager::fence() {
+ EGLSyncKHR fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL);
+ eglClientWaitSyncKHR(mEglDisplay, fence,
+ EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
+ eglDestroySyncKHR(mEglDisplay, fence);
+}
+
void EglManager::cancelFrame() {
mInFrame = false;
}
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index e12db3a..b1a18a9 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -55,6 +55,8 @@ public:
void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
+ void fence();
+
private:
friend class RenderThread;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 36ba3a9..ea4216c 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -16,14 +16,14 @@
#include "RenderProxy.h"
-#include "CanvasContext.h"
-#include "RenderTask.h"
-#include "RenderThread.h"
-
-#include "../DeferredLayerUpdater.h"
-#include "../DisplayList.h"
-#include "../LayerRenderer.h"
-#include "../Rect.h"
+#include "DeferredLayerUpdater.h"
+#include "DisplayList.h"
+#include "LayerRenderer.h"
+#include "Rect.h"
+#include "renderthread/CanvasContext.h"
+#include "renderthread/RenderTask.h"
+#include "renderthread/RenderThread.h"
+#include "utils/Macros.h"
namespace android {
namespace uirenderer {
@@ -52,6 +52,12 @@ namespace renderthread {
MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
ARGS(method) *args = (ARGS(method) *) task->payload()
+enum class DumpFlags {
+ kFrameStats = 1 << 0,
+ kReset = 1 << 1,
+};
+MAKE_FLAGS_ENUM(DumpFlags)
+
CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent,
RenderNode* rootRenderNode, IContextFactory* contextFactory) {
return new CanvasContext(*args->thread, args->translucent,
@@ -60,7 +66,7 @@ CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent,
RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory)
: mRenderThread(RenderThread::getInstance())
- , mContext(0) {
+ , mContext(nullptr) {
SETUP_TASK(createContext);
args->translucent = translucent;
args->rootRenderNode = rootRenderNode;
@@ -76,36 +82,24 @@ RenderProxy::~RenderProxy() {
CREATE_BRIDGE1(destroyContext, CanvasContext* context) {
delete args->context;
- return NULL;
+ return nullptr;
}
void RenderProxy::destroyContext() {
if (mContext) {
SETUP_TASK(destroyContext);
args->context = mContext;
- mContext = 0;
- mDrawFrameTask.setContext(NULL, NULL);
+ mContext = nullptr;
+ mDrawFrameTask.setContext(nullptr, nullptr);
// This is also a fence as we need to be certain that there are no
// outstanding mDrawFrame tasks posted before it is destroyed
postAndWait(task);
}
}
-CREATE_BRIDGE2(setFrameInterval, RenderThread* thread, nsecs_t frameIntervalNanos) {
- args->thread->timeLord().setFrameInterval(args->frameIntervalNanos);
- return NULL;
-}
-
-void RenderProxy::setFrameInterval(nsecs_t frameIntervalNanos) {
- SETUP_TASK(setFrameInterval);
- args->thread = &mRenderThread;
- args->frameIntervalNanos = frameIntervalNanos;
- post(task);
-}
-
CREATE_BRIDGE2(setSwapBehavior, CanvasContext* context, SwapBehavior swapBehavior) {
args->context->setSwapBehavior(args->swapBehavior);
- return NULL;
+ return nullptr;
}
void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) {
@@ -132,6 +126,18 @@ bool RenderProxy::loadSystemProperties() {
return (bool) postAndWait(task);
}
+CREATE_BRIDGE2(setName, CanvasContext* context, const char* name) {
+ args->context->setName(std::string(args->name));
+ return nullptr;
+}
+
+void RenderProxy::setName(const char* name) {
+ SETUP_TASK(setName);
+ args->context = mContext;
+ args->name = name;
+ post(task);
+}
+
CREATE_BRIDGE2(initialize, CanvasContext* context, ANativeWindow* window) {
return (void*) args->context->initialize(args->window);
}
@@ -145,7 +151,7 @@ bool RenderProxy::initialize(const sp<ANativeWindow>& window) {
CREATE_BRIDGE2(updateSurface, CanvasContext* context, ANativeWindow* window) {
args->context->updateSurface(args->window);
- return NULL;
+ return nullptr;
}
void RenderProxy::updateSurface(const sp<ANativeWindow>& window) {
@@ -171,7 +177,7 @@ CREATE_BRIDGE7(setup, CanvasContext* context, int width, int height,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
args->context->setup(args->width, args->height, args->lightCenter, args->lightRadius,
args->ambientShadowAlpha, args->spotShadowAlpha);
- return NULL;
+ return nullptr;
}
void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float lightRadius,
@@ -189,7 +195,7 @@ void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float
CREATE_BRIDGE2(setOpaque, CanvasContext* context, bool opaque) {
args->context->setOpaque(args->opaque);
- return NULL;
+ return nullptr;
}
void RenderProxy::setOpaque(bool opaque) {
@@ -199,15 +205,17 @@ void RenderProxy::setOpaque(bool opaque) {
post(task);
}
-int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
- float density) {
- mDrawFrameTask.setDensity(density);
- return mDrawFrameTask.drawFrame(frameTimeNanos, recordDurationNanos);
+int64_t* RenderProxy::frameInfo() {
+ return mDrawFrameTask.frameInfo();
+}
+
+int RenderProxy::syncAndDrawFrame() {
+ return mDrawFrameTask.drawFrame();
}
CREATE_BRIDGE1(destroy, CanvasContext* context) {
args->context->destroy();
- return NULL;
+ return nullptr;
}
void RenderProxy::destroy() {
@@ -221,7 +229,7 @@ void RenderProxy::destroy() {
CREATE_BRIDGE2(invokeFunctor, RenderThread* thread, Functor* functor) {
CanvasContext::invokeFunctor(*args->thread, args->functor);
- return NULL;
+ return nullptr;
}
void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
@@ -242,7 +250,7 @@ void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
CREATE_BRIDGE2(runWithGlContext, CanvasContext* context, RenderTask* task) {
args->context->runWithGlContext(args->task);
- return NULL;
+ return nullptr;
}
void RenderProxy::runWithGlContext(RenderTask* gltask) {
@@ -254,7 +262,7 @@ void RenderProxy::runWithGlContext(RenderTask* gltask) {
CREATE_BRIDGE2(createTextureLayer, RenderThread* thread, CanvasContext* context) {
Layer* layer = args->context->createTextureLayer();
- if (!layer) return 0;
+ if (!layer) return nullptr;
return new DeferredLayerUpdater(*args->thread, layer);
}
@@ -269,7 +277,7 @@ DeferredLayerUpdater* RenderProxy::createTextureLayer() {
CREATE_BRIDGE2(buildLayer, CanvasContext* context, RenderNode* node) {
args->context->buildLayer(args->node);
- return NULL;
+ return nullptr;
}
void RenderProxy::buildLayer(RenderNode* node) {
@@ -303,7 +311,7 @@ void RenderProxy::cancelLayerUpdate(DeferredLayerUpdater* layer) {
CREATE_BRIDGE1(detachSurfaceTexture, DeferredLayerUpdater* layer) {
args->layer->detachSurfaceTexture();
- return NULL;
+ return nullptr;
}
void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) {
@@ -314,7 +322,7 @@ void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) {
CREATE_BRIDGE1(destroyHardwareResources, CanvasContext* context) {
args->context->destroyHardwareResources();
- return NULL;
+ return nullptr;
}
void RenderProxy::destroyHardwareResources() {
@@ -325,7 +333,7 @@ void RenderProxy::destroyHardwareResources() {
CREATE_BRIDGE2(timMemory, RenderThread* thread, int level) {
CanvasContext::trimMemory(*args->thread, args->level);
- return NULL;
+ return nullptr;
}
void RenderProxy::trimMemory(int level) {
@@ -339,16 +347,14 @@ void RenderProxy::trimMemory(int level) {
}
}
-template <typename T>
-void UNUSED(T) {}
-
-
CREATE_BRIDGE0(fence) {
// Intentionally empty
- UNUSED(args);
- return NULL;
+ return nullptr;
}
+template <typename T>
+void UNUSED(T t) {}
+
void RenderProxy::fence() {
SETUP_TASK(fence);
UNUSED(args);
@@ -357,7 +363,7 @@ void RenderProxy::fence() {
CREATE_BRIDGE1(stopDrawing, CanvasContext* context) {
args->context->stopDrawing();
- return NULL;
+ return nullptr;
}
void RenderProxy::stopDrawing() {
@@ -368,7 +374,7 @@ void RenderProxy::stopDrawing() {
CREATE_BRIDGE1(notifyFramePending, CanvasContext* context) {
args->context->notifyFramePending();
- return NULL;
+ return nullptr;
}
void RenderProxy::notifyFramePending() {
@@ -377,40 +383,58 @@ void RenderProxy::notifyFramePending() {
mRenderThread.queueAtFront(task);
}
-CREATE_BRIDGE2(dumpProfileInfo, CanvasContext* context, int fd) {
+CREATE_BRIDGE3(dumpProfileInfo, CanvasContext* context, int fd, int dumpFlags) {
args->context->profiler().dumpData(args->fd);
- return NULL;
+ if (args->dumpFlags & DumpFlags::kFrameStats) {
+ args->context->dumpFrames(args->fd);
+ }
+ if (args->dumpFlags & DumpFlags::kReset) {
+ args->context->resetFrameStats();
+ }
+ return nullptr;
}
-void RenderProxy::dumpProfileInfo(int fd) {
+void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) {
SETUP_TASK(dumpProfileInfo);
args->context = mContext;
args->fd = fd;
+ args->dumpFlags = dumpFlags;
postAndWait(task);
}
-CREATE_BRIDGE1(outputLogBuffer, int fd) {
- RenderNode::outputLogBuffer(args->fd);
- return NULL;
+CREATE_BRIDGE2(dumpGraphicsMemory, int fd, RenderThread* thread) {
+ args->thread->jankTracker().dump(args->fd);
+
+ FILE *file = fdopen(args->fd, "a");
+ if (Caches::hasInstance()) {
+ String8 cachesLog;
+ Caches::getInstance().dumpMemoryUsage(cachesLog);
+ fprintf(file, "\nCaches:\n%s\n", cachesLog.string());
+ } else {
+ fprintf(file, "\nNo caches instance.\n");
+ }
+ fflush(file);
+ return nullptr;
}
-void RenderProxy::outputLogBuffer(int fd) {
- SETUP_TASK(outputLogBuffer);
+void RenderProxy::dumpGraphicsMemory(int fd) {
+ SETUP_TASK(dumpGraphicsMemory);
args->fd = fd;
+ args->thread = &RenderThread::getInstance();
staticPostAndWait(task);
}
CREATE_BRIDGE4(setTextureAtlas, RenderThread* thread, GraphicBuffer* buffer, int64_t* map, size_t size) {
CanvasContext::setTextureAtlas(*args->thread, args->buffer, args->map, args->size);
- args->buffer->decStrong(0);
- return NULL;
+ args->buffer->decStrong(nullptr);
+ return nullptr;
}
void RenderProxy::setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size) {
SETUP_TASK(setTextureAtlas);
args->thread = &mRenderThread;
args->buffer = buffer.get();
- args->buffer->incStrong(0);
+ args->buffer->incStrong(nullptr);
args->map = map;
args->size = size;
post(task);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index fd1fe05..43cbe07 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -62,10 +62,10 @@ public:
ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode, IContextFactory* contextFactory);
ANDROID_API virtual ~RenderProxy();
- ANDROID_API void setFrameInterval(nsecs_t frameIntervalNanos);
// Won't take effect until next EGLSurface creation
ANDROID_API void setSwapBehavior(SwapBehavior swapBehavior);
ANDROID_API bool loadSystemProperties();
+ ANDROID_API void setName(const char* name);
ANDROID_API bool initialize(const sp<ANativeWindow>& window);
ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
@@ -73,8 +73,8 @@ public:
ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
ANDROID_API void setOpaque(bool opaque);
- ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
- float density);
+ ANDROID_API int64_t* frameInfo();
+ ANDROID_API int syncAndDrawFrame();
ANDROID_API void destroy();
ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion);
@@ -95,8 +95,8 @@ public:
ANDROID_API void stopDrawing();
ANDROID_API void notifyFramePending();
- ANDROID_API void dumpProfileInfo(int fd);
- ANDROID_API static void outputLogBuffer(int fd);
+ ANDROID_API void dumpProfileInfo(int fd, int dumpFlags);
+ ANDROID_API static void dumpGraphicsMemory(int fd);
ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size);
diff --git a/libs/hwui/renderthread/RenderTask.cpp b/libs/hwui/renderthread/RenderTask.cpp
index 13970ba..b14f580 100644
--- a/libs/hwui/renderthread/RenderTask.cpp
+++ b/libs/hwui/renderthread/RenderTask.cpp
@@ -14,15 +14,8 @@
* limitations under the License.
*/
-// LOG_TAG is being provided by the Makefile, reset.
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-#define LOG_TAG "RenderTask"
-
#include "RenderTask.h"
-#include <utils/Log.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
diff --git a/libs/hwui/renderthread/RenderTask.h b/libs/hwui/renderthread/RenderTask.h
index 1554a16..89c3a7d 100644
--- a/libs/hwui/renderthread/RenderTask.h
+++ b/libs/hwui/renderthread/RenderTask.h
@@ -47,7 +47,7 @@ namespace renderthread {
class ANDROID_API RenderTask {
public:
- ANDROID_API RenderTask() : mNext(0), mRunAt(0) {}
+ ANDROID_API RenderTask() : mNext(nullptr), mRunAt(0) {}
ANDROID_API virtual ~RenderTask() {}
ANDROID_API virtual void run() = 0;
@@ -61,7 +61,7 @@ public:
// Takes ownership of task, caller owns lock and signal
SignalingRenderTask(RenderTask* task, Mutex* lock, Condition* signal)
: mTask(task), mLock(lock), mSignal(signal) {}
- virtual void run();
+ virtual void run() override;
private:
RenderTask* mTask;
@@ -74,12 +74,12 @@ typedef void* (*RunnableMethod)(void* data);
class MethodInvokeRenderTask : public RenderTask {
public:
MethodInvokeRenderTask(RunnableMethod method)
- : mMethod(method), mReturnPtr(0) {}
+ : mMethod(method), mReturnPtr(nullptr) {}
void* payload() { return mData; }
void setReturnPtr(void** retptr) { mReturnPtr = retptr; }
- virtual void run() {
+ virtual void run() override {
void* retval = mMethod(mData);
if (mReturnPtr) {
*mReturnPtr = retval;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 37e11d8..3ac2976 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -16,15 +16,17 @@
#include "RenderThread.h"
-#include <gui/DisplayEventReceiver.h>
-#include <sys/resource.h>
-#include <utils/Log.h>
-
-#include "../RenderState.h"
+#include "../renderstate/RenderState.h"
#include "CanvasContext.h"
#include "EglManager.h"
#include "RenderProxy.h"
+#include <gui/DisplayEventReceiver.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <sys/resource.h>
+#include <utils/Log.h>
+
namespace android {
using namespace uirenderer::renderthread;
ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread);
@@ -40,16 +42,16 @@ static const size_t EVENT_BUFFER_SIZE = 100;
// Slight delay to give the UI time to push us a new frame before we replay
static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4);
-TaskQueue::TaskQueue() : mHead(0), mTail(0) {}
+TaskQueue::TaskQueue() : mHead(nullptr), mTail(nullptr) {}
RenderTask* TaskQueue::next() {
RenderTask* ret = mHead;
if (ret) {
mHead = ret->mNext;
if (!mHead) {
- mTail = 0;
+ mTail = nullptr;
}
- ret->mNext = 0;
+ ret->mNext = nullptr;
}
return ret;
}
@@ -69,7 +71,7 @@ void TaskQueue::queue(RenderTask* task) {
mTail = task;
} else {
// Need to find the proper insertion point
- RenderTask* previous = 0;
+ RenderTask* previous = nullptr;
RenderTask* next = mHead;
while (next && next->mRunAt <= task->mRunAt) {
previous = next;
@@ -129,19 +131,19 @@ private:
public:
DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {}
- virtual void run() {
+ virtual void run() override {
mRenderThread->dispatchFrameCallbacks();
}
};
RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>()
, mNextWakeup(LLONG_MAX)
- , mDisplayEventReceiver(0)
+ , mDisplayEventReceiver(nullptr)
, mVsyncRequested(false)
, mFrameCallbackTaskPending(false)
- , mFrameCallbackTask(0)
- , mRenderState(NULL)
- , mEglManager(NULL) {
+ , mFrameCallbackTask(nullptr)
+ , mRenderState(nullptr)
+ , mEglManager(nullptr) {
mFrameCallbackTask = new DispatchFrameCallbacks(this);
mLooper = new Looper(false);
run("RenderThread");
@@ -164,9 +166,16 @@ void RenderThread::initializeDisplayEventReceiver() {
}
void RenderThread::initThreadLocals() {
+ sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
+ ISurfaceComposer::eDisplayIdMain));
+ status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
+ LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
+ nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
+ mTimeLord.setFrameInterval(frameIntervalNanos);
initializeDisplayEventReceiver();
mEglManager = new EglManager(*this);
mRenderState = new RenderState(*this);
+ mJankTracker = new JankTracker(frameIntervalNanos);
}
int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
@@ -346,7 +355,7 @@ RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
next = mQueue.next();
} else {
- next = 0;
+ next = nullptr;
}
}
if (nextWakeup) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 99c2e15..8096099 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -19,16 +19,18 @@
#include "RenderTask.h"
-#include <memory>
-#include <set>
+#include "../JankTracker.h"
+#include "TimeLord.h"
#include <cutils/compiler.h>
+#include <ui/DisplayInfo.h>
#include <utils/Looper.h>
#include <utils/Mutex.h>
#include <utils/Singleton.h>
#include <utils/Thread.h>
-#include "TimeLord.h"
+#include <memory>
+#include <set>
namespace android {
@@ -88,9 +90,12 @@ public:
TimeLord& timeLord() { return mTimeLord; }
RenderState& renderState() { return *mRenderState; }
EglManager& eglManager() { return *mEglManager; }
+ JankTracker& jankTracker() { return *mJankTracker; }
+
+ const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; }
protected:
- virtual bool threadLoop();
+ virtual bool threadLoop() override;
private:
friend class Singleton<RenderThread>;
@@ -118,6 +123,8 @@ private:
nsecs_t mNextWakeup;
TaskQueue mQueue;
+ DisplayInfo mDisplayInfo;
+
DisplayEventReceiver* mDisplayEventReceiver;
bool mVsyncRequested;
std::set<IFrameCallback*> mFrameCallbacks;
@@ -132,6 +139,8 @@ private:
TimeLord mTimeLord;
RenderState* mRenderState;
EglManager* mEglManager;
+
+ JankTracker* mJankTracker = nullptr;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
index f187493..f846d6a 100644
--- a/libs/hwui/renderthread/TimeLord.cpp
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -32,7 +32,7 @@ bool TimeLord::vsyncReceived(nsecs_t vsync) {
return false;
}
-nsecs_t TimeLord::computeFrameTimeMs() {
+nsecs_t TimeLord::computeFrameTimeNanos() {
// Logic copied from Choreographer.java
nsecs_t now = systemTime(CLOCK_MONOTONIC);
nsecs_t jitterNanos = now - mFrameTimeNanos;
@@ -40,7 +40,11 @@ nsecs_t TimeLord::computeFrameTimeMs() {
nsecs_t lastFrameOffset = jitterNanos % mFrameIntervalNanos;
mFrameTimeNanos = now - lastFrameOffset;
}
- return nanoseconds_to_milliseconds(mFrameTimeNanos);
+ return mFrameTimeNanos;
+}
+
+nsecs_t TimeLord::computeFrameTimeMs() {
+ return nanoseconds_to_milliseconds(computeFrameTimeNanos());
}
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
index 7c155d2..5464399 100644
--- a/libs/hwui/renderthread/TimeLord.h
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -29,9 +29,13 @@ class RenderThread;
class TimeLord {
public:
void setFrameInterval(nsecs_t intervalNanos) { mFrameIntervalNanos = intervalNanos; }
+ nsecs_t frameIntervalNanos() const { return mFrameIntervalNanos; }
+
// returns true if the vsync is newer, false if it was rejected for staleness
bool vsyncReceived(nsecs_t vsync);
+ nsecs_t latestVsync() { return mFrameTimeNanos; }
nsecs_t computeFrameTimeMs();
+ nsecs_t computeFrameTimeNanos();
private:
friend class RenderThread;