summaryrefslogtreecommitdiff
path: root/libs/hwui/renderthread/CanvasContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/renderthread/CanvasContext.cpp')
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp86
1 files changed, 58 insertions, 28 deletions
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 9898a1c30856..b5ef8f43dfb6 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
@@ -150,6 +147,7 @@ void CanvasContext::setSurface(sp<Surface>&& surface) {
mNativeSurface = new ReliableSurface{std::move(surface)};
// TODO: Fix error handling & re-shorten timeout
mNativeSurface->setDequeueTimeout(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)