diff options
Diffstat (limited to 'libs/hwui/renderthread/CanvasContext.cpp')
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 88 |
1 files changed, 59 insertions, 29 deletions
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 9898a1c30856..684dc22ee4d1 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -15,11 +15,20 @@ */ #include "CanvasContext.h" + #include <GpuMemoryTracker.h> +#include <apex/window.h> +#include <fcntl.h> +#include <strings.h> +#include <sys/stat.h> + +#include <algorithm> +#include <cstdint> +#include <cstdlib> +#include <functional> #include "../Properties.h" #include "AnimationContext.h" -#include "EglManager.h" #include "Frame.h" #include "LayerUpdateQueue.h" #include "Properties.h" @@ -33,18 +42,6 @@ #include "utils/TimeUtils.h" #include "utils/TraceUtils.h" -#include <cutils/properties.h> -#include <private/hwui/DrawGlInfo.h> -#include <strings.h> - -#include <fcntl.h> -#include <sys/stat.h> -#include <algorithm> - -#include <cstdint> -#include <cstdlib> -#include <functional> - #define TRIM_MEMORY_COMPLETE 80 #define TRIM_MEMORY_UI_HIDDEN 20 @@ -149,7 +146,8 @@ void CanvasContext::setSurface(sp<Surface>&& surface) { if (surface) { mNativeSurface = new ReliableSurface{std::move(surface)}; // TODO: Fix error handling & re-shorten timeout - mNativeSurface->setDequeueTimeout(4000_ms); + ANativeWindow_setDequeueTimeout(mNativeSurface.get(), 4000_ms); + mNativeSurface->enableFrameTimestamps(true); } else { mNativeSurface = nullptr; } @@ -297,6 +295,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy // just keep using the previous frame's structure instead if (!wasSkipped(mCurrentFrameInfo)) { mCurrentFrameInfo = mJankTracker.startFrame(); + mLast4FrameInfos.next().first = mCurrentFrameInfo; } mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo); mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued; @@ -448,48 +447,66 @@ void CanvasContext::draw() { mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes, &(profiler())); - int64_t frameCompleteNr = mFrameCompleteCallbacks.size() ? getFrameNumber() : -1; + int64_t frameCompleteNr = getFrameNumber(); waitOnFences(); bool requireSwap = false; + int error = OK; bool didSwap = mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap); mIsDirty = false; if (requireSwap) { - if (!didSwap) { // some error happened + bool didDraw = true; + // Handle any swapchain errors + error = mNativeSurface->getAndClearError(); + if (error == TIMED_OUT) { + // Try again + mRenderThread.postFrameCallback(this); + // But since this frame didn't happen, we need to mark full damage in the swap + // history + didDraw = false; + + } else if (error != OK || !didSwap) { + // Unknown error, abandon the surface setSurface(nullptr); + didDraw = false; } + SwapHistory& swap = mSwapHistory.next(); - swap.damage = windowDirty; - swap.swapCompletedTime = systemTime(CLOCK_MONOTONIC); + if (didDraw) { + swap.damage = windowDirty; + } else { + swap.damage = SkRect::MakeWH(INT_MAX, INT_MAX); + } + swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC); swap.vsyncTime = mRenderThread.timeLord().latestVsync(); - if (mNativeSurface.get()) { - int durationUs; - nsecs_t dequeueStart = mNativeSurface->getLastDequeueStartTime(); + if (didDraw) { + nsecs_t dequeueStart = ANativeWindow_getLastDequeueStartTime(mNativeSurface.get()); if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) { // Ignoring dequeue duration as it happened prior to frame render start // and thus is not part of the frame. swap.dequeueDuration = 0; } else { - mNativeSurface->query(NATIVE_WINDOW_LAST_DEQUEUE_DURATION, &durationUs); - swap.dequeueDuration = us2ns(durationUs); + swap.dequeueDuration = + us2ns(ANativeWindow_getLastDequeueDuration(mNativeSurface.get())); } - mNativeSurface->query(NATIVE_WINDOW_LAST_QUEUE_DURATION, &durationUs); - swap.queueDuration = us2ns(durationUs); + swap.queueDuration = us2ns(ANativeWindow_getLastQueueDuration(mNativeSurface.get())); } else { swap.dequeueDuration = 0; swap.queueDuration = 0; } mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = swap.dequeueDuration; mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = swap.queueDuration; + mLast4FrameInfos[-1].second = frameCompleteNr; mHaveNewSurface = false; mFrameNumber = -1; } else { mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0; mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0; + mLast4FrameInfos[-1].second = -1; } // TODO: Use a fence for real completion? @@ -522,6 +539,19 @@ void CanvasContext::draw() { mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data()); } + if (mLast4FrameInfos.size() == mLast4FrameInfos.capacity()) { + // By looking 4 frames back, we guarantee all SF stats are available. There are at + // most 3 buffers in BufferQueue. Surface object keeps stats for the last 8 frames. + FrameInfo* forthBehind = mLast4FrameInfos.front().first; + int64_t composedFrameId = mLast4FrameInfos.front().second; + nsecs_t acquireTime = -1; + mNativeSurface->getFrameTimestamps(composedFrameId, nullptr, &acquireTime, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr); + // Ignore default -1, NATIVE_WINDOW_TIMESTAMP_INVALID and NATIVE_WINDOW_TIMESTAMP_PENDING + forthBehind->set(FrameInfoIndex::GpuCompleted) = acquireTime > 0 ? acquireTime : -1; + mJankTracker.finishGpuDraw(*forthBehind); + } + GpuMemoryTracker::onFrameCompleted(); } @@ -550,7 +580,7 @@ void CanvasContext::prepareAndDraw(RenderNode* node) { UiFrameInfoBuilder(frameInfo).addFlag(FrameInfoFlags::RTAnimation).setVsync(vsync, vsync); TreeInfo info(TreeInfo::MODE_RT_ONLY, *this); - prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node); + prepareTree(info, frameInfo, systemTime(SYSTEM_TIME_MONOTONIC), node); if (info.out.canDrawThisFrame) { draw(); } else { @@ -694,7 +724,7 @@ SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) { // New surface needs a full draw dirty->setEmpty(); } else { - if (!dirty->isEmpty() && !dirty->intersect(0, 0, frame.width(), frame.height())) { + if (!dirty->isEmpty() && !dirty->intersect(SkRect::MakeIWH(frame.width(), frame.height()))) { ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", SK_RECT_ARGS(*dirty), frame.width(), frame.height()); dirty->setEmpty(); @@ -703,7 +733,7 @@ SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) { } if (dirty->isEmpty()) { - dirty->set(0, 0, frame.width(), frame.height()); + dirty->setIWH(frame.width(), frame.height()); } // At this point dirty is the area of the window to update. However, @@ -719,7 +749,7 @@ SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) { if (frame.bufferAge() > (int)mSwapHistory.size()) { // We don't have enough history to handle this old of a buffer // Just do a full-draw - dirty->set(0, 0, frame.width(), frame.height()); + dirty->setIWH(frame.width(), frame.height()); } else { // At this point we haven't yet added the latest frame // to the damage history (happens below) |