Bag of scheduling tweaks
Bug: 15118640
* Prevent over-stuffing the queue by dropping frames
* Prevent double-drawing in one pulse by RT by deferring
vsync registration until post-draw so that it catches
the next vsync pulse instead of the current one
* Bias vsync race condition towards the UI thread
* Fix queueDelay to actually work
Change-Id: Ibf584258bd93ebcbba058bd976dc8b307f1c6155
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 839ef91..b6b3428 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -360,7 +360,9 @@
setSurface(NULL);
}
-void CanvasContext::setSurface(EGLNativeWindowType window) {
+void CanvasContext::setSurface(ANativeWindow* window) {
+ mNativeWindow = window;
+
if (mEglSurface != EGL_NO_SURFACE) {
mGlobalContext->destroySurface(mEglSurface);
mEglSurface = EGL_NO_SURFACE;
@@ -393,7 +395,7 @@
makeCurrent();
}
-bool CanvasContext::initialize(EGLNativeWindowType window) {
+bool CanvasContext::initialize(ANativeWindow* window) {
if (mCanvas) return false;
setSurface(window);
mCanvas = new OpenGLRenderer();
@@ -401,11 +403,11 @@
return true;
}
-void CanvasContext::updateSurface(EGLNativeWindowType window) {
+void CanvasContext::updateSurface(ANativeWindow* window) {
setSurface(window);
}
-void CanvasContext::pauseSurface(EGLNativeWindowType window) {
+void CanvasContext::pauseSurface(ANativeWindow* window) {
// TODO: For now we just need a fence, in the future suspend any animations
// and such to prevent from trying to render into this surface
}
@@ -456,7 +458,15 @@
info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
mRootRenderNode->prepareTree(info);
- if (info.out.hasAnimations) {
+ int runningBehind = 0;
+ // TODO: This query is moderately expensive, investigate adding some sort
+ // of fast-path based off when we last called eglSwapBuffers() as well as
+ // last vsync time. Or something.
+ mNativeWindow->query(mNativeWindow.get(),
+ NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind);
+ info.out.canDrawThisFrame = !runningBehind;
+
+ if (info.out.hasAnimations || !info.out.canDrawThisFrame) {
if (info.out.hasFunctors) {
info.out.requiresUiRedraw = true;
} else if (!info.out.requiresUiRedraw) {
@@ -467,6 +477,11 @@
}
}
+void CanvasContext::notifyFramePending() {
+ ATRACE_CALL();
+ mRenderThread.pushBackFrameCallback(this);
+}
+
void CanvasContext::draw(Rect* dirty) {
LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
"drawDisplayList called on a context with no canvas or surface!");
@@ -515,7 +530,9 @@
info.prepareTextures = false;
prepareTree(info);
- draw(NULL);
+ if (info.out.canDrawThisFrame) {
+ draw(NULL);
+ }
}
void CanvasContext::invokeFunctor(Functor* functor) {