renderthread: add EGL_EXT_buffer_age support

EGL_EXT_buffer_age is better than EGL_BUFFER_PRESERVED
because it can save memory bandwidth used to blit
back buffer into front buffer.

Change-Id: I2fea0ee08dc7dd66e348b04dd694d075d509d01b
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 6dfb6e8..ea73387 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -98,6 +98,9 @@
         setSurface(nullptr);
     }
     mHaveNewSurface = false;
+    if (mEglManager.useBufferAgeExt()) {
+        mDirtyHistory.prepend(Rect(dirty));
+    }
 }
 
 void CanvasContext::requireSurface() {
@@ -227,6 +230,8 @@
             "drawRenderNode called on a context with no canvas or surface!");
 
     SkRect dirty;
+    bool useBufferAgeExt = mEglManager.useBufferAgeExt();
+    Rect patchedDirty;
     mDamageAccumulator.finish(&dirty);
 
     // TODO: Re-enable after figuring out cause of b/22592975
@@ -237,12 +242,18 @@
 
     mCurrentFrameInfo->markIssueDrawCommandsStart();
 
-    EGLint width, height;
-    mEglManager.beginFrame(mEglSurface, &width, &height);
+    EGLint width, height, framebufferAge;
+    mEglManager.beginFrame(mEglSurface, &width, &height, &framebufferAge);
+
+    if (useBufferAgeExt && mHaveNewSurface) {
+        mDirtyHistory.clear();
+    }
+
     if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
         mCanvas->setViewport(width, height);
         dirty.setEmpty();
     } else if (!mBufferPreserved || mHaveNewSurface) {
+        mDirtyHistory.clear();
         dirty.setEmpty();
     } else {
         if (!dirty.isEmpty() && !dirty.intersect(0, 0, width, height)) {
@@ -253,9 +264,14 @@
         profiler().unionDirty(&dirty);
     }
 
-    if (!dirty.isEmpty()) {
-        mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,
-                dirty.fRight, dirty.fBottom, mOpaque);
+    patchedDirty = dirty;
+    if (useBufferAgeExt && !dirty.isEmpty()) {
+        patchedDirty = mDirtyHistory.unionWith(Rect(dirty), framebufferAge-1);
+    }
+
+    if (!patchedDirty.isEmpty()) {
+        mCanvas->prepareDirty(patchedDirty.left, patchedDirty.top,
+                patchedDirty.right, patchedDirty.bottom, mOpaque);
     } else {
         mCanvas->prepare(mOpaque);
     }