Merge changes from topic "tm-qpr-fix-drm_virgl" into tm-qpr-dev

* changes:
  Fix flickering with client frame composer
  Add display finder DRM flow
  Add client composition mode to RanchuHWC
diff --git a/system/hwc2/Android.mk b/system/hwc2/Android.mk
index b53456c..f2c4f25 100644
--- a/system/hwc2/Android.mk
+++ b/system/hwc2/Android.mk
@@ -58,6 +58,7 @@
 emulator_hwcomposer_relative_path := hw
 
 emulator_hwcomposer2_src_files := \
+    ClientComposer.cpp \
     Common.cpp \
     Device.cpp \
     Display.cpp \
diff --git a/system/hwc2/ClientComposer.cpp b/system/hwc2/ClientComposer.cpp
new file mode 100644
index 0000000..211667b
--- /dev/null
+++ b/system/hwc2/ClientComposer.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ClientComposer.h"
+
+#include "Device.h"
+#include "Display.h"
+#include "Drm.h"
+#include "Layer.h"
+
+namespace android {
+
+ClientComposer::ClientComposer(DrmPresenter* drmPresenter)
+    : mDrmPresenter(drmPresenter) {}
+
+HWC2::Error ClientComposer::init() {
+  DEBUG_LOG("%s", __FUNCTION__);
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error ClientComposer::onDisplayCreate(Display* display) {
+  const auto displayId = display->getId();
+  DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+  // Ensure created.
+  mDisplayInfos.emplace(displayId, DisplayInfo{});
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error ClientComposer::onDisplayDestroy(Display* display) {
+  const auto displayId = display->getId();
+  DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+  auto it = mDisplayInfos.find(displayId);
+  if (it == mDisplayInfos.end()) {
+    ALOGE("%s: display:%" PRIu64 " missing display buffers?", __FUNCTION__,
+          displayId);
+    return HWC2::Error::BadDisplay;
+  }
+
+  mDisplayInfos.erase(it);
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error ClientComposer::onDisplayClientTargetSet(Display* display) {
+  const auto displayId = display->getId();
+  DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+  auto it = mDisplayInfos.find(displayId);
+  if (it == mDisplayInfos.end()) {
+    ALOGE("%s: display:%" PRIu64 " missing display buffers?", __FUNCTION__,
+          displayId);
+    return HWC2::Error::BadDisplay;
+  }
+
+  DisplayInfo& displayInfo = it->second;
+
+  auto clientTargetNativeBuffer = display->getClientTarget().getBuffer();
+  auto clientTargetDrmBuffer =
+    std::make_unique<DrmBuffer>(clientTargetNativeBuffer, mDrmPresenter);
+  if (!clientTargetDrmBuffer) {
+    ALOGE("%s: display:%" PRIu64 " failed to create client target drm buffer",
+          __FUNCTION__, displayId);
+    return HWC2::Error::NoResources;
+  }
+
+  displayInfo.clientTargetDrmBuffer = std::move(clientTargetDrmBuffer);
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error ClientComposer::onActiveConfigChange(Display*) {
+  DEBUG_LOG("%s", __FUNCTION__);
+
+  return HWC2::Error::None;
+};
+
+HWC2::Error ClientComposer::validateDisplay(
+    Display* display, std::unordered_map<hwc2_layer_t, HWC2::Composition>* changes) {
+  const auto displayId = display->getId();
+  DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+  (void)displayId;
+
+  const std::vector<Layer*>& layers = display->getOrderedLayers();
+
+  for (Layer* layer : layers) {
+    const auto layerId = layer->getId();
+    const auto layerCompositionType = layer->getCompositionType();
+
+    if (layerCompositionType != HWC2::Composition::Client) {
+      (*changes)[layerId] = HWC2::Composition::Client;
+    }
+  }
+
+  return HWC2::Error::None;
+}
+
+std::tuple<HWC2::Error, base::unique_fd> ClientComposer::presentDisplay(
+    Display* display) {
+  ATRACE_CALL();
+
+  const auto displayId = display->getId();
+  DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+  auto displayInfoIt = mDisplayInfos.find(displayId);
+  if (displayInfoIt == mDisplayInfos.end()) {
+    ALOGE("%s: failed to find display buffers for display:%" PRIu64,
+          __FUNCTION__, displayId);
+    return std::make_tuple(HWC2::Error::BadDisplay, base::unique_fd());
+  }
+
+  DisplayInfo& displayInfo = displayInfoIt->second;
+
+  auto clientTargetFence = display->getClientTarget().getFence();
+
+  auto [error, presentFence] =
+      displayInfo.clientTargetDrmBuffer->flushToDisplay(
+          static_cast<int>(displayId), clientTargetFence);
+  if (error != HWC2::Error::None) {
+    ALOGE("%s: display:%" PRIu64 " failed to flush drm buffer" PRIu64,
+          __FUNCTION__, displayId);
+    return std::make_tuple(error, base::unique_fd());
+  }
+
+  return std::make_tuple(HWC2::Error::None, std::move(presentFence));
+}
+
+}  // namespace android
\ No newline at end of file
diff --git a/system/hwc2/ClientComposer.h b/system/hwc2/ClientComposer.h
new file mode 100644
index 0000000..58d4cce
--- /dev/null
+++ b/system/hwc2/ClientComposer.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWC_CLIENTCOMPOSER_H
+#define ANDROID_HWC_CLIENTCOMPOSER_H
+
+#include <unordered_map>
+
+#include "Common.h"
+#include "Composer.h"
+#include "Display.h"
+#include "DrmPresenter.h"
+#include "Layer.h"
+
+namespace android {
+
+class ClientComposer : public Composer {
+ public:
+  ClientComposer(DrmPresenter* drmPresenter);
+
+  ClientComposer(const ClientComposer&) = delete;
+  ClientComposer& operator=(const ClientComposer&) = delete;
+
+  ClientComposer(ClientComposer&&) = delete;
+  ClientComposer& operator=(ClientComposer&&) = delete;
+
+  HWC2::Error init() override;
+
+  HWC2::Error onDisplayCreate(Display*) override;
+
+  HWC2::Error onDisplayDestroy(Display*) override;
+
+  HWC2::Error onDisplayClientTargetSet(Display*) override;
+
+  HWC2::Error onActiveConfigChange(Display*) override;
+
+  // Determines if this composer can compose the given layers on the given
+  // display and requests changes for layers that can't not be composed.
+  HWC2::Error validateDisplay(
+      Display* display, std::unordered_map<hwc2_layer_t, HWC2::Composition>*
+                            outLayerCompositionChanges) override;
+
+  // Performs the actual composition of layers and presents the composed result
+  // to the display.
+  std::tuple<HWC2::Error, base::unique_fd> presentDisplay(
+      Display* display) override;
+
+ private:
+  struct DisplayInfo {
+    std::unique_ptr<DrmBuffer> clientTargetDrmBuffer;
+  };
+
+  std::unordered_map<int64_t, DisplayInfo> mDisplayInfos;
+
+  DrmPresenter* mDrmPresenter = nullptr;
+};
+
+}  // namespace android
+
+#endif
\ No newline at end of file
diff --git a/system/hwc2/Common.cpp b/system/hwc2/Common.cpp
index 3e465c2..021d032 100644
--- a/system/hwc2/Common.cpp
+++ b/system/hwc2/Common.cpp
@@ -31,3 +31,7 @@
 bool IsNoOpMode() {
   return android::base::GetProperty("ro.vendor.hwcomposer.mode", "") == "noop";
 }
+
+bool IsClientCompositionMode() {
+  return android::base::GetProperty("ro.vendor.hwcomposer.mode", "") == "client";
+}
diff --git a/system/hwc2/Common.h b/system/hwc2/Common.h
index b0e0770..f13553b 100644
--- a/system/hwc2/Common.h
+++ b/system/hwc2/Common.h
@@ -45,5 +45,6 @@
 bool IsCuttlefish();
 bool IsCuttlefishFoldable();
 bool IsNoOpMode();
+bool IsClientCompositionMode();
 
 #endif
diff --git a/system/hwc2/Device.cpp b/system/hwc2/Device.cpp
index 1be15b3..f49905d 100644
--- a/system/hwc2/Device.cpp
+++ b/system/hwc2/Device.cpp
@@ -18,6 +18,7 @@
 
 #include <android-base/properties.h>
 
+#include "ClientComposer.h"
 #include "DisplayFinder.h"
 #include "GuestComposer.h"
 #include "HostComposer.h"
@@ -78,6 +79,9 @@
   if (IsNoOpMode()) {
     DEBUG_LOG("%s: using NoOpComposer", __FUNCTION__);
     mComposer = std::make_unique<NoOpComposer>();
+  } else if (IsClientCompositionMode()) {
+    DEBUG_LOG("%s: using ClientComposer", __FUNCTION__);
+    mComposer = std::make_unique<ClientComposer>(mDrmPresenter.get());
   } else if (ShouldUseGuestComposer()) {
     DEBUG_LOG("%s: using GuestComposer", __FUNCTION__);
     mComposer = std::make_unique<GuestComposer>(mDrmPresenter.get());
diff --git a/system/hwc3/ClientFrameComposer.cpp b/system/hwc3/ClientFrameComposer.cpp
index d7f8b55..284a46f 100644
--- a/system/hwc3/ClientFrameComposer.cpp
+++ b/system/hwc3/ClientFrameComposer.cpp
@@ -146,6 +146,11 @@
   }
 
   DisplayInfo& displayInfo = displayInfoIt->second;
+  if (!displayInfo.clientTargetDrmBuffer) {
+    ALOGW("%s: display:%" PRIu64 " no client target set, nothing to present.",
+          __FUNCTION__, displayId);
+    return HWC3::Error::None;
+  }
 
   ::android::base::unique_fd fence = display->getClientTarget().getFence();
 
diff --git a/system/hwc3/ClientFrameComposer.h b/system/hwc3/ClientFrameComposer.h
index 3fb0ba8..28199b3 100644
--- a/system/hwc3/ClientFrameComposer.h
+++ b/system/hwc3/ClientFrameComposer.h
@@ -64,9 +64,13 @@
       std::unordered_map<int64_t, ::android::base::unique_fd>* outLayerFences)
       override;
 
+  const DrmPresenter* getDrmPresenter() const override {
+    return &mDrmPresenter;
+  }
+
  private:
   struct DisplayInfo {
-    std::unique_ptr<DrmBuffer> clientTargetDrmBuffer;;
+    std::shared_ptr<DrmBuffer> clientTargetDrmBuffer;
   };
 
   std::unordered_map<int64_t, DisplayInfo> mDisplayInfos;
diff --git a/system/hwc3/Common.cpp b/system/hwc3/Common.cpp
index 497f764..e9ac507 100644
--- a/system/hwc3/Common.cpp
+++ b/system/hwc3/Common.cpp
@@ -30,18 +30,34 @@
              std::string::npos;
 }
 
-bool IsNoOpMode() {
+bool IsInNoOpCompositionMode() {
   const std::string mode = ::android::base::GetProperty("ro.vendor.hwcomposer.mode", "");
   DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.mode is %s", __FUNCTION__, mode.c_str());
   return mode == "noop";
 }
 
-bool IsClientCompositionMode() {
+bool IsInClientCompositionMode() {
   const std::string mode = ::android::base::GetProperty("ro.vendor.hwcomposer.mode", "");
   DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.mode is %s", __FUNCTION__, mode.c_str());
   return mode == "client";
 }
 
+bool IsInNoOpDisplayFinderMode() {
+  const std::string mode =
+    ::android::base::GetProperty("ro.vendor.hwcomposer.display_finder_mode", "");
+  DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.display_finder_mode is %s",
+            __FUNCTION__, mode.c_str());
+  return mode == "noop";
+}
+
+bool IsInDrmDisplayFinderMode() {
+  const std::string mode =
+    ::android::base::GetProperty("ro.vendor.hwcomposer.display_finder_mode", "");
+  DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.display_finder_mode is %s",
+            __FUNCTION__, mode.c_str());
+  return mode == "drm";
+}
+
 std::string toString(HWC3::Error error) {
   switch (error) {
     case HWC3::Error::None:
diff --git a/system/hwc3/Common.h b/system/hwc3/Common.h
index 5b6587e..493e5d0 100644
--- a/system/hwc3/Common.h
+++ b/system/hwc3/Common.h
@@ -44,8 +44,12 @@
 
 bool IsCuttlefish();
 bool IsCuttlefishFoldable();
-bool IsNoOpMode();
-bool IsClientCompositionMode();
+
+bool IsInNoOpCompositionMode();
+bool IsInClientCompositionMode();
+
+bool IsInNoOpDisplayFinderMode();
+bool IsInDrmDisplayFinderMode();
 
 namespace HWC3 {
 enum class Error : int32_t {
diff --git a/system/hwc3/ComposerClient.cpp b/system/hwc3/ComposerClient.cpp
index db05383..2098435 100644
--- a/system/hwc3/ComposerClient.cpp
+++ b/system/hwc3/ComposerClient.cpp
@@ -1237,7 +1237,7 @@
 
   std::vector<DisplayMultiConfigs> displays;
 
-  HWC3::Error error = findDisplays(displays);
+  HWC3::Error error = findDisplays(mComposer->getDrmPresenter(), &displays);
   if (error != HWC3::Error::None) {
     ALOGE("%s failed to find display configs", __FUNCTION__);
     return error;
diff --git a/system/hwc3/Device.cpp b/system/hwc3/Device.cpp
index cf4be42..894d48b 100644
--- a/system/hwc3/Device.cpp
+++ b/system/hwc3/Device.cpp
@@ -94,10 +94,10 @@
   std::unique_lock<std::mutex> lock(mMutex);
 
   if (mComposer == nullptr) {
-    if (IsNoOpMode()) {
+    if (IsInNoOpCompositionMode()) {
       DEBUG_LOG("%s: using NoOpFrameComposer", __FUNCTION__);
       mComposer = std::make_unique<NoOpFrameComposer>();
-    } else if (IsClientCompositionMode()) {
+    } else if (IsInClientCompositionMode()) {
       DEBUG_LOG("%s: using ClientFrameComposer", __FUNCTION__);
       mComposer = std::make_unique<ClientFrameComposer>();
     } else if (shouldUseGuestComposer()) {
diff --git a/system/hwc3/DisplayFinder.cpp b/system/hwc3/DisplayFinder.cpp
index 8e252cb..10bd5fd 100644
--- a/system/hwc3/DisplayFinder.cpp
+++ b/system/hwc3/DisplayFinder.cpp
@@ -31,7 +31,7 @@
   return 1000 * 1000 * 1000 / hertz;
 }
 
-HWC3::Error findCuttlefishDisplays(std::vector<DisplayMultiConfigs>& displays) {
+HWC3::Error findCuttlefishDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
   DEBUG_LOG("%s", __FUNCTION__);
 
   // TODO: replace with initializing directly from DRM info.
@@ -55,7 +55,7 @@
                               vsyncPeriodNanos),
             },
     };
-    displays.push_back(display);
+    outDisplays->push_back(display);
     ++displayId;
   }
 
@@ -79,7 +79,7 @@
 }
 
 HWC3::Error findGoldfishPrimaryDisplay(
-    std::vector<DisplayMultiConfigs>& displays) {
+    std::vector<DisplayMultiConfigs>* outDisplays) {
   DEBUG_LOG("%s", __FUNCTION__);
 
   DEFINE_AND_VALIDATE_HOST_CONNECTION
@@ -118,13 +118,13 @@
   }
   hostCon->unlock();
 
-  displays.push_back(display);
+  outDisplays->push_back(display);
 
   return HWC3::Error::None;
 }
 
 HWC3::Error findGoldfishSecondaryDisplays(
-    std::vector<DisplayMultiConfigs>& displays) {
+    std::vector<DisplayMultiConfigs>* outDisplays) {
   DEBUG_LOG("%s", __FUNCTION__);
 
   static constexpr const char kExternalDisplayProp[] =
@@ -170,7 +170,7 @@
         /*dpiYh=*/propIntParts[3],               //
         /*vsyncPeriod=*/HertzToPeriodNanos(160)  //
         ));
-    displays.push_back(display);
+    outDisplays->push_back(display);
 
     ++secondaryDisplayId;
 
@@ -180,14 +180,14 @@
   return HWC3::Error::None;
 }
 
-HWC3::Error findGoldfishDisplays(std::vector<DisplayMultiConfigs>& displays) {
-  HWC3::Error error = findGoldfishPrimaryDisplay(displays);
+HWC3::Error findGoldfishDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
+  HWC3::Error error = findGoldfishPrimaryDisplay(outDisplays);
   if (error != HWC3::Error::None) {
     ALOGE("%s failed to find Goldfish primary display", __FUNCTION__);
     return error;
   }
 
-  error = findGoldfishSecondaryDisplays(displays);
+  error = findGoldfishSecondaryDisplays(outDisplays);
   if (error != HWC3::Error::None) {
     ALOGE("%s failed to find Goldfish secondary displays", __FUNCTION__);
   }
@@ -197,8 +197,8 @@
 
 // This is currently only used for Gem5 bring-up where virtio-gpu and drm
 // are not currently available. For now, just return a placeholder display.
-HWC3::Error findNoOpDisplays(std::vector<DisplayMultiConfigs>& displays) {
-  displays.push_back(DisplayMultiConfigs{
+HWC3::Error findNoOpDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
+  outDisplays->push_back(DisplayMultiConfigs{
       .displayId = 0,
       .activeConfigId = 0,
       .configs = {DisplayConfig(0,
@@ -213,16 +213,54 @@
   return HWC3::Error::None;
 }
 
+HWC3::Error findDrmDisplays(const DrmPresenter& drm,
+                            std::vector<DisplayMultiConfigs>* outDisplays) {
+  outDisplays->clear();
+
+  std::vector<DrmPresenter::DisplayConfig> drmDisplayConfigs;
+
+  HWC3::Error error = drm.getDisplayConfigs(&drmDisplayConfigs);
+  if (error != HWC3::Error::None) {
+    ALOGE("%s failed to find displays from DRM.", __FUNCTION__);
+    return error;
+  }
+
+  for (const DrmPresenter::DisplayConfig drmDisplayConfig : drmDisplayConfigs) {
+    outDisplays->push_back(DisplayMultiConfigs{
+      .displayId = drmDisplayConfig.id,
+      .activeConfigId = static_cast<int32_t>(drmDisplayConfig.id),
+      .configs = {
+        DisplayConfig(static_cast<int32_t>(drmDisplayConfig.id),
+                      drmDisplayConfig.width,
+                      drmDisplayConfig.height,
+                      drmDisplayConfig.dpiX,
+                      drmDisplayConfig.dpiY,
+                      HertzToPeriodNanos(drmDisplayConfig.refreshRateHz)),
+      },
+    });
+  }
+
+  return HWC3::Error::None;
+}
+
 }  // namespace
 
-HWC3::Error findDisplays(std::vector<DisplayMultiConfigs>& displays) {
+HWC3::Error findDisplays(const DrmPresenter* drm,
+                         std::vector<DisplayMultiConfigs>* outDisplays) {
   HWC3::Error error = HWC3::Error::None;
-  if (IsNoOpMode()) {
-    error = findNoOpDisplays(displays);
+  if (IsInNoOpCompositionMode()) {
+    error = findNoOpDisplays(outDisplays);
+  } else if (IsInDrmDisplayFinderMode()) {
+    if (drm == nullptr) {
+      ALOGE("%s asked to find displays from DRM, but DRM not available.",
+            __FUNCTION__);
+      return HWC3::Error::NoResources;
+    }
+    error = findDrmDisplays(*drm, outDisplays);
   } else if (IsCuttlefish()) {
-    error = findCuttlefishDisplays(displays);
+    error = findCuttlefishDisplays(outDisplays);
   } else {
-    error = findGoldfishDisplays(displays);
+    error = findGoldfishDisplays(outDisplays);
   }
 
   if (error != HWC3::Error::None) {
@@ -230,7 +268,7 @@
     return error;
   }
 
-  for (auto& display : displays) {
+  for (auto& display : *outDisplays) {
     DisplayConfig::addConfigGroups(&display.configs);
   }
 
diff --git a/system/hwc3/DisplayFinder.h b/system/hwc3/DisplayFinder.h
index 8197a82..171d204 100644
--- a/system/hwc3/DisplayFinder.h
+++ b/system/hwc3/DisplayFinder.h
@@ -17,10 +17,12 @@
 #ifndef ANDROID_HWC_DISPLAYFINDER_H
 #define ANDROID_HWC_DISPLAYFINDER_H
 
+#include <optional>
 #include <vector>
 
 #include "Common.h"
 #include "DisplayConfig.h"
+#include "DrmPresenter.h"
 
 namespace aidl::android::hardware::graphics::composer3::impl {
 
@@ -31,7 +33,8 @@
   std::vector<DisplayConfig> configs;
 };
 
-HWC3::Error findDisplays(std::vector<DisplayMultiConfigs>& displays);
+HWC3::Error findDisplays(const DrmPresenter* drm,
+                         std::vector<DisplayMultiConfigs>* outDisplays);
 
 }  // namespace aidl::android::hardware::graphics::composer3::impl
 
diff --git a/system/hwc3/DrmPresenter.cpp b/system/hwc3/DrmPresenter.cpp
index 6e13209..b512277 100644
--- a/system/hwc3/DrmPresenter.cpp
+++ b/system/hwc3/DrmPresenter.cpp
@@ -80,6 +80,18 @@
       ALOGE("%s: Failed to initialize DRM backend", __FUNCTION__);
       return HWC3::Error::NoResources;
     }
+
+    constexpr const std::size_t kCachedBuffersPerDisplay = 3;
+    std::size_t numDisplays = 0;
+    for (const DrmConnector& connector : mConnectors) {
+      if (connector.connection == DRM_MODE_CONNECTED) {
+        ++numDisplays;
+      }
+    }
+    const std::size_t bufferCacheSize = kCachedBuffersPerDisplay * numDisplays;
+    DEBUG_LOG("%s: initializing DRM buffer cache to size %zu",
+              __FUNCTION__, bufferCacheSize);
+    mBufferCache = std::make_unique<DrmBufferCache>(bufferCacheSize);
   }
 
   mDrmEventListener = ::android::sp<DrmEventListener>::make(*this);
@@ -93,6 +105,31 @@
   return HWC3::Error::None;
 }
 
+HWC3::Error DrmPresenter::getDisplayConfigs(std::vector<DisplayConfig>* configs) const {
+  AutoReadLock lock(mStateMutex);
+
+  configs->clear();
+
+  for (uint32_t i = 0; i < mConnectors.size(); i++) {
+    const auto& connector = mConnectors[i];
+
+    if (connector.connection != DRM_MODE_CONNECTED) {
+      continue;
+    }
+
+    configs->emplace_back(DisplayConfig{
+        .id = i,
+        .width = connector.mMode.hdisplay,
+        .height = connector.mMode.vdisplay,
+        .dpiX = 160, //static_cast<uint32_t>(connector.dpiX),
+        .dpiY = 160, //static_cast<uint32_t>(connector.dpiY),
+        .refreshRateHz = connector.mRefreshRateAsInteger,
+    });
+  }
+
+  return HWC3::Error::None;
+}
+
 HWC3::Error DrmPresenter::registerOnHotplugCallback(const HotplugCallback& cb) {
   mHotplugCallback = cb;
   return HWC3::Error::None;
@@ -322,54 +359,59 @@
   mPlanes.clear();
 }
 
-std::tuple<HWC3::Error, std::unique_ptr<DrmBuffer>> DrmPresenter::create(
+std::tuple<HWC3::Error, std::shared_ptr<DrmBuffer>> DrmPresenter::create(
     const native_handle_t* handle) {
-  auto buffer = std::unique_ptr<DrmBuffer>(new DrmBuffer(*this));
-
   cros_gralloc_handle* crosHandle = (cros_gralloc_handle*)handle;
   if (crosHandle == nullptr) {
     ALOGE("%s: invalid cros_gralloc_handle", __FUNCTION__);
-    return std::make_tuple(HWC3::Error::NoResources,
-                           std::unique_ptr<DrmBuffer>());
+    return std::make_tuple(HWC3::Error::NoResources, nullptr);
   }
 
+  DrmPrimeBufferHandle primeHandle = 0;
+  int ret = drmPrimeFDToHandle(mFd.get(), crosHandle->fds[0], &primeHandle);
+  if (ret) {
+    ALOGE("%s: drmPrimeFDToHandle failed: %s (errno %d)", __FUNCTION__,
+          strerror(errno), errno);
+    return std::make_tuple(HWC3::Error::NoResources, nullptr);
+  }
+
+  auto drmBufferPtr = mBufferCache->get(primeHandle);
+  if (drmBufferPtr != nullptr) {
+    return std::make_tuple(HWC3::Error::None,
+                           std::shared_ptr<DrmBuffer>(*drmBufferPtr));
+  }
+
+  auto buffer = std::shared_ptr<DrmBuffer>(new DrmBuffer(*this));
   buffer->mWidth = crosHandle->width;
   buffer->mHeight = crosHandle->height;
   buffer->mDrmFormat = crosHandle->format;
   buffer->mPlaneFds[0] = crosHandle->fds[0];
+  buffer->mPlaneHandles[0] = primeHandle;
   buffer->mPlanePitches[0] = crosHandle->strides[0];
   buffer->mPlaneOffsets[0] = crosHandle->offsets[0];
 
-  HWC3::Error error = createDrmFramebuffer(buffer.get());
-  return std::make_tuple(error, std::move(buffer));
-}
-
-HWC3::Error DrmPresenter::createDrmFramebuffer(DrmBuffer* buffer) {
-  int ret;
-
-  ret = drmPrimeFDToHandle(mFd.get(), buffer->mPlaneFds[0],
-                           &buffer->mPlaneHandles[0]);
-  if (ret) {
-    ALOGE("%s: drmPrimeFDToHandle failed: %s (errno %d)", __FUNCTION__,
-          strerror(errno), errno);
-    return HWC3::Error::NoResources;
-  }
-
   uint32_t framebuffer = 0;
-  ret = drmModeAddFB2(mFd.get(), buffer->mWidth, buffer->mHeight,
-                      buffer->mDrmFormat, buffer->mPlaneHandles,
-                      buffer->mPlanePitches, buffer->mPlaneOffsets,
-                      &framebuffer, 0);
+  ret = drmModeAddFB2(mFd.get(),
+                      buffer->mWidth,
+                      buffer->mHeight,
+                      buffer->mDrmFormat,
+                      buffer->mPlaneHandles,
+                      buffer->mPlanePitches,
+                      buffer->mPlaneOffsets,
+                      &framebuffer,
+                      0);
   if (ret) {
     ALOGE("%s: drmModeAddFB2 failed: %s (errno %d)", __FUNCTION__,
           strerror(errno), errno);
-    return HWC3::Error::NoResources;
+    return std::make_tuple(HWC3::Error::NoResources, nullptr);
   }
-
   DEBUG_LOG("%s: created framebuffer:%" PRIu32, __FUNCTION__, framebuffer);
+  buffer->mDrmFramebuffer = framebuffer;
 
-  buffer->mDrmFramebuffer.emplace(framebuffer);
-  return HWC3::Error::None;
+  mBufferCache->set(primeHandle, std::shared_ptr<DrmBuffer>(buffer));
+
+  return std::make_tuple(HWC3::Error::None,
+                         std::shared_ptr<DrmBuffer>(buffer));
 }
 
 HWC3::Error DrmPresenter::destroyDrmFramebuffer(DrmBuffer* buffer) {
@@ -391,6 +433,8 @@
             strerror(errno), errno);
       return HWC3::Error::NoResources;
     }
+
+    mBufferCache->remove(buffer->mPlaneHandles[0]);
   }
 
   return HWC3::Error::None;
diff --git a/system/hwc3/DrmPresenter.h b/system/hwc3/DrmPresenter.h
index 61e546a..72e3f5a 100644
--- a/system/hwc3/DrmPresenter.h
+++ b/system/hwc3/DrmPresenter.h
@@ -29,6 +29,7 @@
 #include <vector>
 
 #include "Common.h"
+#include "LruCache.h"
 #include "android/base/synchronization/AndroidLock.h"
 
 namespace aidl::android::hardware::graphics::composer3::impl {
@@ -60,7 +61,6 @@
   uint32_t mPlaneHandles[4] = {0, 0, 0, 0};
   uint32_t mPlanePitches[4] = {0, 0, 0, 0};
   uint32_t mPlaneOffsets[4] = {0, 0, 0, 0};
-
   std::optional<uint32_t> mDrmFramebuffer;
 };
 
@@ -77,6 +77,17 @@
 
   HWC3::Error init();
 
+  struct DisplayConfig {
+    uint32_t id;
+    uint32_t width;
+    uint32_t height;
+    uint32_t dpiX;
+    uint32_t dpiY;
+    uint32_t refreshRateHz;
+  };
+
+  HWC3::Error getDisplayConfigs(std::vector<DisplayConfig>* configs) const;
+
   using HotplugCallback = std::function<void(bool /*connected*/,   //
                                              uint32_t /*id*/,      //
                                              uint32_t /*width*/,   //
@@ -90,7 +101,7 @@
 
   uint32_t refreshRate() const { return mConnectors[0].mRefreshRateAsInteger; }
 
-  std::tuple<HWC3::Error, std::unique_ptr<DrmBuffer>> create(
+  std::tuple<HWC3::Error, std::shared_ptr<DrmBuffer>> create(
       const native_handle_t* handle);
 
   std::tuple<HWC3::Error, ::android::base::unique_fd> flushToDisplay(
@@ -100,9 +111,13 @@
   std::optional<std::vector<uint8_t>> getEdid(uint32_t id);
 
  private:
-  // Grant visibility for createDrmFramebuffer and clearDrmFB to DrmBuffer.
+  // TODO: make this cache per display when enabling hotplug support.
+  using DrmPrimeBufferHandle = uint32_t;
+  using DrmBufferCache = LruCache<DrmPrimeBufferHandle, std::shared_ptr<DrmBuffer>>;
+  std::unique_ptr<DrmBufferCache> mBufferCache;
+
+  // Grant visibility to destroyDrmFramebuffer to DrmBuffer.
   friend class DrmBuffer;
-  HWC3::Error createDrmFramebuffer(DrmBuffer* buffer);
   HWC3::Error destroyDrmFramebuffer(DrmBuffer* buffer);
 
   // Grant visibility for handleHotplug to DrmEventListener.
@@ -117,7 +132,7 @@
   std::optional<HotplugCallback> mHotplugCallback;
 
   // Protects access to the below drm structs.
-  ::android::base::guest::ReadWriteLock mStateMutex;
+  mutable ::android::base::guest::ReadWriteLock mStateMutex;
 
   struct DrmPlane {
     uint32_t mId = -1;
diff --git a/system/hwc3/FrameComposer.h b/system/hwc3/FrameComposer.h
index fdb6db3..794855b 100644
--- a/system/hwc3/FrameComposer.h
+++ b/system/hwc3/FrameComposer.h
@@ -26,6 +26,7 @@
 
 #include "Common.h"
 #include "DisplayChanges.h"
+#include "DrmPresenter.h"
 
 namespace aidl::android::hardware::graphics::composer3::impl {
 
@@ -68,6 +69,10 @@
           outLayerFences) = 0;
 
   virtual HWC3::Error onActiveConfigChange(Display* display) = 0;
+
+  virtual const DrmPresenter* getDrmPresenter() const {
+    return nullptr;
+  }
 };
 
 }  // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/GuestFrameComposer.h b/system/hwc3/GuestFrameComposer.h
index af46b3d..e37ff87 100644
--- a/system/hwc3/GuestFrameComposer.h
+++ b/system/hwc3/GuestFrameComposer.h
@@ -62,6 +62,10 @@
 
   HWC3::Error onActiveConfigChange(Display* /*display*/) override;
 
+  const DrmPresenter* getDrmPresenter() const override {
+    return &mDrmPresenter;
+  }
+
  private:
   struct DisplayConfig {
     int width;
@@ -91,7 +95,7 @@
     // Additional per display buffer for the composition result.
     buffer_handle_t compositionResultBuffer = nullptr;
 
-    std::unique_ptr<DrmBuffer> compositionResultDrmBuffer;
+    std::shared_ptr<DrmBuffer> compositionResultDrmBuffer;
   };
 
   std::unordered_map<int64_t, DisplayInfo> mDisplayInfos;
diff --git a/system/hwc3/HostFrameComposer.h b/system/hwc3/HostFrameComposer.h
index e99e6f2..42eb43a 100644
--- a/system/hwc3/HostFrameComposer.h
+++ b/system/hwc3/HostFrameComposer.h
@@ -65,6 +65,13 @@
 
   HWC3::Error onActiveConfigChange(Display* display) override;
 
+  const DrmPresenter* getDrmPresenter() const override {
+    if (mDrmPresenter) {
+      return &*mDrmPresenter;
+    }
+    return nullptr;
+  }
+
  private:
   HWC3::Error createHostComposerDisplayInfo(Display* display,
                                             uint32_t hostDisplayId);
@@ -85,10 +92,10 @@
     const native_handle_t* compositionResultBuffer = nullptr;
 
     // Drm info for the additional composition result buffer.
-    std::unique_ptr<DrmBuffer> compositionResultDrmBuffer;
+    std::shared_ptr<DrmBuffer> compositionResultDrmBuffer;
 
     // Drm info for the displays client target buffer.
-    std::unique_ptr<DrmBuffer> clientTargetDrmBuffer;
+    std::shared_ptr<DrmBuffer> clientTargetDrmBuffer;
   };
 
   std::unordered_map<int64_t, HostComposerDisplayInfo> mDisplayInfos;
diff --git a/system/hwc3/LruCache.h b/system/hwc3/LruCache.h
new file mode 100644
index 0000000..9ffca46
--- /dev/null
+++ b/system/hwc3/LruCache.h
@@ -0,0 +1,83 @@
+// Copyright 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <list>
+#include <unordered_map>
+
+template <typename Key, typename Value>
+class LruCache {
+  public:
+    LruCache(std::size_t maxSize) : m_maxSize(maxSize) {
+        m_table.reserve(maxSize);
+    }
+
+    Value* get(const Key& key) {
+        auto tableIt = m_table.find(key);
+        if (tableIt == m_table.end()) {
+            return nullptr;
+        }
+
+        // Move to front.
+        auto elementsIt = tableIt->second;
+        m_elements.splice(elementsIt, m_elements, m_elements.begin());
+        return &elementsIt->value;
+    }
+
+    void set(const Key& key, Value&& value) {
+        auto tableIt = m_table.find(key);
+        if (tableIt == m_table.end()) {
+            if (m_table.size() >= m_maxSize) {
+                auto& kv = m_elements.back();
+                m_table.erase(kv.key);
+                m_elements.pop_back();
+            }
+        } else {
+            auto elementsIt = tableIt->second;
+            m_elements.erase(elementsIt);
+        }
+        m_elements.emplace_front(KeyValue{
+            key,
+            std::forward<Value>(value),
+        });
+        m_table[key] = m_elements.begin();
+    }
+
+    void remove(const Key& key) {
+        auto tableIt = m_table.find(key);
+        if (tableIt == m_table.end()) {
+            return;
+        }
+        auto elementsIt = tableIt->second;
+        m_elements.erase(elementsIt);
+        m_table.erase(tableIt);
+    }
+
+    void clear() {
+        m_elements.clear();
+        m_table.clear();
+    }
+
+  private:
+    struct KeyValue {
+        Key key;
+        Value value;
+    };
+
+    const std::size_t m_maxSize;
+    // Front is the most recently used and back is the least recently used.
+    std::list<KeyValue> m_elements;
+    std::unordered_map<Key, typename std::list<KeyValue>::iterator> m_table;
+};