surfaceflinger: cache HWC client targets and buffers

Remember HWC client targets and buffers, and make sure we send each
unique slot/handle pair only once.  This allows the composer to
clone/register/retain each buffer only once.

Test: builds and boots
Change-Id: Ib485189043a9c132031e82d4d7380ace3bf9453d
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e57c19a..3a9bca6 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -270,6 +270,16 @@
     }
 }
 
+void Layer::onBuffersReleased() {
+#ifdef USE_HWC2
+    Mutex::Autolock lock(mHwcBufferCacheMutex);
+
+    for (auto info : mHwcBufferCaches) {
+        info.second.clear();
+    }
+#endif
+}
+
 void Layer::onSidebandStreamChanged() {
     if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
         // mSidebandStreamChanged was false
@@ -836,8 +846,22 @@
               static_cast<int32_t>(error));
     }
 
+    uint32_t hwcSlot = 0;
+    buffer_handle_t hwcHandle = nullptr;
+    {
+        Mutex::Autolock lock(mHwcBufferCacheMutex);
+
+        auto& hwcBufferCache = mHwcBufferCaches[hwcId];
+        sp<GraphicBuffer> hwcBuffer;
+        hwcBufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer,
+                &hwcSlot, &hwcBuffer);
+        if (hwcBuffer != nullptr) {
+            hwcHandle = hwcBuffer->handle;
+        }
+    }
+
     auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence();
-    error = hwcLayer->setBuffer(mActiveBuffer->handle, acquireFence);
+    error = hwcLayer->setBuffer(hwcSlot, hwcHandle, acquireFence);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
                 mActiveBuffer->handle, to_string(error).c_str(),
@@ -2087,7 +2111,8 @@
     }
 
     // update the active buffer
-    mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
+    mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer(
+            &mActiveBufferSlot);
     if (mActiveBuffer == NULL) {
         // this can only happen if the very first buffer was rejected.
         return outDirtyRegion;