drm_hwcomposer: Extract DrmHwc abstract base class

DrmHwc holds implementation details that can be shared between hwc2 and
hwc3. It exposes abstract functions for implementing callbacks to hwc
clients.

Leave the HWC2 specific implementation details in the DrmHwcTwo class, such
as the client callback implementation, and implement the DrmHwc abstract
functions in terms of hwc2.

DrmHwc is based on the DrmHwcInterface extracted in
(drm_hwcomposer: Connect ComposerClient with HwcDisplay) from !238

Co-authored-by: Dennis Tsiang <dennis.tsiang@arm.com>
Co-authored-by: Normunds Rieksts <normunds.rieksts@arm.com>
Signed-off-by: Drew Davenport <ddavenport@chromium.org>
diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp
index 2ea6c77..c120b63 100644
--- a/hwc2_device/DrmHwcTwo.cpp
+++ b/hwc2_device/DrmHwcTwo.cpp
@@ -25,174 +25,6 @@
 
 namespace android {
 
-DrmHwcTwo::DrmHwcTwo() : resource_manager_(this){};
-
-/* Must be called after every display attach/detach cycle */
-void DrmHwcTwo::FinalizeDisplayBinding() {
-  if (displays_.count(kPrimaryDisplay) == 0) {
-    /* Primary display MUST always exist */
-    ALOGI("No pipelines available. Creating null-display for headless mode");
-    displays_[kPrimaryDisplay] = std::make_unique<
-        HwcDisplay>(kPrimaryDisplay, HWC2::DisplayType::Physical, this);
-    /* Initializes null-display */
-    displays_[kPrimaryDisplay]->SetPipeline({});
-  }
-
-  if (displays_[kPrimaryDisplay]->IsInHeadlessMode() &&
-      !display_handles_.empty()) {
-    /* Reattach first secondary display to take place of the primary */
-    auto pipe = display_handles_.begin()->first;
-    ALOGI("Primary display was disconnected, reattaching '%s' as new primary",
-          pipe->connector->Get()->GetName().c_str());
-    UnbindDisplay(pipe);
-    BindDisplay(pipe);
-  }
-
-  // Finally, send hotplug events to the client
-  for (auto &dhe : deferred_hotplug_events_) {
-    SendHotplugEventToClient(dhe.first, dhe.second);
-  }
-  deferred_hotplug_events_.clear();
-
-  /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
-   */
-  auto &mutex = GetResMan().GetMainLock();
-  mutex.unlock();
-  const int kTimeForSFToDisposeDisplayUs = 200000;
-  usleep(kTimeForSFToDisposeDisplayUs);
-  mutex.lock();
-  for (auto handle : displays_for_removal_list_) {
-    displays_.erase(handle);
-  }
-}
-
-bool DrmHwcTwo::BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
-  if (display_handles_.count(pipeline) != 0) {
-    ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
-          __func__, pipeline.get());
-    return false;
-  }
-
-  uint32_t disp_handle = kPrimaryDisplay;
-
-  if (displays_.count(kPrimaryDisplay) != 0 &&
-      !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
-    disp_handle = ++last_display_handle_;
-  }
-
-  if (displays_.count(disp_handle) == 0) {
-    auto disp = std::make_unique<HwcDisplay>(disp_handle,
-                                             HWC2::DisplayType::Physical, this);
-    displays_[disp_handle] = std::move(disp);
-  }
-
-  ALOGI("Attaching pipeline '%s' to the display #%d%s",
-        pipeline->connector->Get()->GetName().c_str(), (int)disp_handle,
-        disp_handle == kPrimaryDisplay ? " (Primary)" : "");
-
-  displays_[disp_handle]->SetPipeline(pipeline);
-  display_handles_[pipeline] = disp_handle;
-
-  return true;
-}
-
-bool DrmHwcTwo::UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
-  if (display_handles_.count(pipeline) == 0) {
-    ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline.get());
-    return false;
-  }
-  auto handle = display_handles_[pipeline];
-  display_handles_.erase(pipeline);
-
-  ALOGI("Detaching the pipeline '%s' from the display #%i%s",
-        pipeline->connector->Get()->GetName().c_str(), (int)handle,
-        handle == kPrimaryDisplay ? " (Primary)" : "");
-
-  if (displays_.count(handle) == 0) {
-    ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
-    return false;
-  }
-  displays_[handle]->SetPipeline({});
-
-  /* We must defer display disposal and removal, since it may still have pending
-   * HWC_API calls scheduled and waiting until ueventlistener thread releases
-   * main lock, otherwise transaction may fail and SF may crash
-   */
-  if (handle != kPrimaryDisplay) {
-    displays_for_removal_list_.emplace_back(handle);
-  }
-  return true;
-}
-
-HWC2::Error DrmHwcTwo::CreateVirtualDisplay(
-    uint32_t width, uint32_t height,
-    int32_t *format,  // NOLINT(readability-non-const-parameter)
-    hwc2_display_t *display) {
-  ALOGI("Creating virtual display %dx%d format %d", width, height, *format);
-
-  auto virtual_pipeline = resource_manager_.GetVirtualDisplayPipeline();
-  if (!virtual_pipeline)
-    return HWC2::Error::Unsupported;
-
-  *display = ++last_display_handle_;
-  auto disp = std::make_unique<HwcDisplay>(*display, HWC2::DisplayType::Virtual,
-                                           this);
-
-  disp->SetVirtualDisplayResolution(width, height);
-  disp->SetPipeline(virtual_pipeline);
-  displays_[*display] = std::move(disp);
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t display) {
-  ALOGI("Destroying virtual display %" PRIu64, display);
-
-  if (displays_.count(display) == 0) {
-    ALOGE("Trying to destroy non-existent display %" PRIu64, display);
-    return HWC2::Error::BadDisplay;
-  }
-
-  displays_[display]->SetPipeline({});
-
-  /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
-   */
-  auto &mutex = GetResMan().GetMainLock();
-  mutex.unlock();
-  const int kTimeForSFToDisposeDisplayUs = 200000;
-  usleep(kTimeForSFToDisposeDisplayUs);
-  mutex.lock();
-
-  displays_.erase(display);
-
-  return HWC2::Error::None;
-}
-
-void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) {
-  if (outBuffer != nullptr) {
-    auto copied_bytes = mDumpString.copy(outBuffer, *outSize);
-    *outSize = static_cast<uint32_t>(copied_bytes);
-    return;
-  }
-
-  std::stringstream output;
-
-  output << "-- drm_hwcomposer --\n\n";
-
-  for (auto &disp : displays_)
-    output << disp.second->Dump();
-
-  mDumpString = output.str();
-  *outSize = static_cast<uint32_t>(mDumpString.size());
-}
-
-uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
-  auto writeback_count = resource_manager_.GetWritebackConnectorsCount();
-  writeback_count = std::min(writeback_count, 1U);
-  /* Currently, only 1 virtual display is supported. Other cases need testing */
-  ALOGI("Max virtual display count: %d", writeback_count);
-  return writeback_count;
-}
-
 HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
                                         hwc2_callback_data_t data,
                                         hwc2_function_pointer_t function) {
@@ -200,13 +32,13 @@
     case HWC2::Callback::Hotplug: {
       hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
       if (function != nullptr) {
-        resource_manager_.Init();
+        GetResMan().Init();
       } else {
-        resource_manager_.DeInit();
+        GetResMan().DeInit();
         /* Headless display may still be here. Remove it! */
-        if (displays_.count(kPrimaryDisplay) != 0) {
-          displays_[kPrimaryDisplay]->Deinit();
-          displays_.erase(kPrimaryDisplay);
+        if (Displays().count(kPrimaryDisplay) != 0) {
+          Displays()[kPrimaryDisplay]->Deinit();
+          Displays().erase(kPrimaryDisplay);
         }
       }
       break;
@@ -237,7 +69,7 @@
 }
 
 void DrmHwcTwo::SendHotplugEventToClient(hwc2_display_t displayid,
-                                         bool connected) const {
+                                         bool connected) {
   auto hc = hotplug_callback_;
   if (hc.first != nullptr && hc.second != nullptr) {
     /* For some reason HWC Service will call HWC2 API in hotplug callback
@@ -283,4 +115,11 @@
 #endif
 }
 
+void DrmHwcTwo::SendRefreshEventToClient(hwc2_display_t displayid) {
+  if (refresh_callback_.first != nullptr &&
+      refresh_callback_.second != nullptr) {
+    refresh_callback_.first(refresh_callback_.second, displayid);
+  }
+}
+
 }  // namespace android
diff --git a/hwc2_device/DrmHwcTwo.h b/hwc2_device/DrmHwcTwo.h
index 8701feb..b3ca0f8 100644
--- a/hwc2_device/DrmHwcTwo.h
+++ b/hwc2_device/DrmHwcTwo.h
@@ -18,16 +18,28 @@
 
 #include <hardware/hwcomposer2.h>
 
-#include "drm/ResourceManager.h"
-#include "hwc2_device/HwcDisplay.h"
+#include "drm/DrmHwc.h"
 
 namespace android {
 
-class DrmHwcTwo : public PipelineToFrontendBindingInterface {
+class DrmHwcTwo : public DrmHwc {
  public:
-  DrmHwcTwo();
+  DrmHwcTwo() = default;
   ~DrmHwcTwo() override = default;
 
+  HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
+                               hwc2_function_pointer_t function);
+
+  // DrmHwc
+  void SendVsyncEventToClient(hwc2_display_t displayid, int64_t timestamp,
+                              uint32_t vsync_period) const override;
+  void SendVsyncPeriodTimingChangedEventToClient(
+      hwc2_display_t displayid, int64_t timestamp) const override;
+  void SendRefreshEventToClient(uint64_t displayid) override;
+  void SendHotplugEventToClient(hwc2_display_t displayid,
+                                bool connected) override;
+
+ private:
   std::pair<HWC2_PFN_HOTPLUG, hwc2_callback_data_t> hotplug_callback_{};
   std::pair<HWC2_PFN_VSYNC, hwc2_callback_data_t> vsync_callback_{};
 #if __ANDROID_API__ > 29
@@ -36,53 +48,5 @@
       period_timing_changed_callback_{};
 #endif
   std::pair<HWC2_PFN_REFRESH, hwc2_callback_data_t> refresh_callback_{};
-
-  // Device functions
-  HWC2::Error CreateVirtualDisplay(uint32_t width, uint32_t height,
-                                   int32_t *format, hwc2_display_t *display);
-  HWC2::Error DestroyVirtualDisplay(hwc2_display_t display);
-  void Dump(uint32_t *outSize, char *outBuffer);
-  uint32_t GetMaxVirtualDisplayCount();
-  HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
-                               hwc2_function_pointer_t function);
-
-  auto GetDisplay(hwc2_display_t display_handle) {
-    return displays_.count(display_handle) != 0
-               ? displays_[display_handle].get()
-               : nullptr;
-  }
-
-  auto &GetResMan() {
-    return resource_manager_;
-  }
-
-  void ScheduleHotplugEvent(hwc2_display_t displayid, bool connected) {
-    deferred_hotplug_events_[displayid] = connected;
-  }
-
-  // PipelineToFrontendBindingInterface
-  bool BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) override;
-  bool UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) override;
-  void FinalizeDisplayBinding() override;
-
-  void SendVsyncEventToClient(hwc2_display_t displayid, int64_t timestamp,
-                              uint32_t vsync_period) const;
-  void SendVsyncPeriodTimingChangedEventToClient(hwc2_display_t displayid,
-                                                 int64_t timestamp) const;
-
- private:
-  void SendHotplugEventToClient(hwc2_display_t displayid, bool connected) const;
-
-  ResourceManager resource_manager_;
-  std::map<hwc2_display_t, std::unique_ptr<HwcDisplay>> displays_;
-  std::map<std::shared_ptr<DrmDisplayPipeline>, hwc2_display_t>
-      display_handles_;
-
-  std::string mDumpString;
-
-  std::map<hwc2_display_t, bool> deferred_hotplug_events_;
-  std::vector<hwc2_display_t> displays_for_removal_list_;
-
-  uint32_t last_display_handle_ = kPrimaryDisplay;
 };
 }  // namespace android
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 89a8c3f..dad568c 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -19,10 +19,10 @@
 
 #include "HwcDisplay.h"
 
-#include "DrmHwcTwo.h"
 #include "backend/Backend.h"
 #include "backend/BackendManager.h"
 #include "bufferinfo/BufferInfoGetter.h"
+#include "drm/DrmHwc.h"
 #include "utils/log.h"
 #include "utils/properties.h"
 
@@ -66,8 +66,8 @@
 }
 
 HwcDisplay::HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type,
-                       DrmHwcTwo *hwc2)
-    : hwc2_(hwc2), handle_(handle), type_(type), client_layer_(this) {
+                       DrmHwc *hwc)
+    : hwc_(hwc), handle_(handle), type_(type), client_layer_(this) {
   if (type_ == HWC2::DisplayType::Virtual) {
     writeback_layer_ = std::make_unique<HwcLayer>(this);
   }
@@ -94,9 +94,9 @@
 
   if (pipeline_ != nullptr || handle_ == kPrimaryDisplay) {
     Init();
-    hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ true);
+    hwc_->ScheduleHotplugEvent(handle_, /*connected = */ true);
   } else {
-    hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ false);
+    hwc_->ScheduleHotplugEvent(handle_, /*connected = */ false);
   }
 }
 
@@ -144,11 +144,11 @@
   auto vsw_callbacks = (VSyncWorkerCallbacks){
       .out_event =
           [this](int64_t timestamp) {
-            const std::unique_lock lock(hwc2_->GetResMan().GetMainLock());
+            const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
             if (vsync_event_en_) {
               uint32_t period_ns{};
               GetDisplayVsyncPeriod(&period_ns);
-              hwc2_->SendVsyncEventToClient(handle_, timestamp, period_ns);
+              hwc_->SendVsyncEventToClient(handle_, timestamp, period_ns);
             }
             if (vsync_tracking_en_) {
               last_vsync_ts_ = timestamp;
@@ -178,12 +178,8 @@
       ALOGE("Failed to set backend for d=%d %d\n", int(handle_), ret);
       return HWC2::Error::BadDisplay;
     }
-    auto flatcbk = (struct FlatConCallbacks){.trigger = [this]() {
-      if (hwc2_->refresh_callback_.first != nullptr &&
-          hwc2_->refresh_callback_.second != nullptr)
-        hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second,
-                                       handle_);
-    }};
+    auto flatcbk = (struct FlatConCallbacks){
+        .trigger = [this]() { hwc_->SendRefreshEventToClient(handle_); }};
     flatcon_ = FlatteningController::CreateInstance(flatcbk);
   }
 
@@ -564,9 +560,9 @@
     staged_mode_.reset();
     vsync_tracking_en_ = false;
     if (last_vsync_ts_ != 0) {
-      hwc2_->SendVsyncPeriodTimingChangedEventToClient(handle_,
-                                                       last_vsync_ts_ +
-                                                           prev_vperiod_ns);
+      hwc_->SendVsyncPeriodTimingChangedEventToClient(handle_,
+                                                      last_vsync_ts_ +
+                                                          prev_vperiod_ns);
     }
   }
 
@@ -731,7 +727,7 @@
   if (GetPipe().crtc->Get()->GetCtmProperty())
     return false;
 
-  if (GetHwc2()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
+  if (GetHwc()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
     return false;
 
   return true;
@@ -963,7 +959,7 @@
   bool skip_ctm = false;
 
   // Skip client CTM if user requested DRM_OR_IGNORE
-  if (GetHwc2()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
+  if (GetHwc()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
     skip_ctm = true;
 
   // Skip client CTM if DRM can handle it
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index 13d4328..9fe555d 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -33,14 +33,14 @@
 namespace android {
 
 class Backend;
-class DrmHwcTwo;
+class DrmHwc;
 
 inline constexpr uint32_t kPrimaryDisplay = 0;
 
 // NOLINTNEXTLINE
 class HwcDisplay {
  public:
-  HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwcTwo *hwc2);
+  HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwc *hwc);
   HwcDisplay(const HwcDisplay &) = delete;
   ~HwcDisplay();
 
@@ -149,8 +149,8 @@
   const Backend *backend() const;
   void set_backend(std::unique_ptr<Backend> backend);
 
-  auto GetHwc2() {
-    return hwc2_;
+  auto GetHwc() {
+    return hwc_;
   }
 
   std::map<hwc2_layer_t, HwcLayer> &layers() {
@@ -195,7 +195,7 @@
  private:
   HwcDisplayConfigs configs_;
 
-  DrmHwcTwo *const hwc2_;
+  DrmHwc *const hwc_;
 
   SharedFd present_fence_;
 
diff --git a/hwc2_device/meson.build b/hwc2_device/meson.build
index 7e6b8f4..6a9a93a 100644
--- a/hwc2_device/meson.build
+++ b/hwc2_device/meson.build
@@ -6,14 +6,23 @@
     'HwcLayer.cpp',
 )
 
+drmhwc_hwc2_common = static_library(
+    'drm_hwc2',
+    src_hwc2_device,
+# TODO remove hwc2 flags from common code (backends needs rework)
+    cpp_args : common_cpp_flags + hwc2_cpp_flags,
+    dependencies : deps,
+    link_with: drmhwc_common,
+    include_directories: inc_include,
+)
+
 shared_library(
     'hwcomposer.drm',
-    src_hwc2_device,
     name_prefix : '',
     cpp_args : common_cpp_flags + hwc2_cpp_flags,
     dependencies : deps,
     install : true,
-    link_whole: drmhwc_common,
+    link_whole: [drmhwc_common, drmhwc_hwc2_common],
     install_dir : get_option('libdir') / 'hw',
     include_directories: inc_include,
-)
+)
\ No newline at end of file