diff options
Diffstat (limited to 'libs/hwui/renderthread')
| -rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 93 | ||||
| -rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 35 | ||||
| -rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.cpp | 23 | ||||
| -rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.h | 13 | ||||
| -rw-r--r-- | libs/hwui/renderthread/EglManager.cpp | 34 | ||||
| -rw-r--r-- | libs/hwui/renderthread/EglManager.h | 2 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 142 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderProxy.h | 10 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderTask.cpp | 7 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderTask.h | 8 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderThread.cpp | 39 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderThread.h | 17 | ||||
| -rw-r--r-- | libs/hwui/renderthread/TimeLord.cpp | 8 | ||||
| -rw-r--r-- | libs/hwui/renderthread/TimeLord.h | 4 |
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; |
