OSDN Git Service

drm_hwcomposer: Added hotplug support of the external display
authorAndrii Chepurnyi <andrii_chepurnyi@epam.com>
Wed, 1 Aug 2018 14:42:56 +0000 (17:42 +0300)
committerAndrii Chepurnyi <andrii_chepurnyi@epam.com>
Wed, 6 Mar 2019 17:21:49 +0000 (19:21 +0200)
Unplug of the main display will not work because of
Activity Manager code(ActivityStackSupervisor.java:handleDisplayRemoved).
Only one display can be connected as an external
display (see SurfaceFlinger::determineDisplayType).

Tested-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Andrii Chepurnyi <andrii_chepurnyi@epam.com>
drmdevice.h
drmdisplaycompositor.h
drmeventlistener.cpp
drmeventlistener.h
drmhwctwo.cpp
drmhwctwo.h
resourcemanager.h

index da1b961..91dd38b 100644 (file)
@@ -76,6 +76,9 @@ class DrmDevice {
   int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id);
   int DestroyPropertyBlob(uint32_t blob_id);
   bool HandlesDisplay(int display) const;
+  void RegisterHotplugHandler(DrmEventHandler *handler) {
+    event_listener_.RegisterHotplugHandler(handler);
+  }
 
  private:
   int TryEncoderForDisplay(int display, DrmEncoder *enc);
index 67f6334..1005598 100644 (file)
@@ -55,6 +55,7 @@ class DrmDisplayCompositor {
   int Composite();
   void Dump(std::ostringstream *out) const;
   void Vsync(int display, int64_t timestamp);
+  void ClearDisplay();
 
   std::tuple<uint32_t, uint32_t, int> GetActiveModeResolution();
 
@@ -82,7 +83,6 @@ class DrmDisplayCompositor {
   int ApplyDpms(DrmDisplayComposition *display_comp);
   int DisablePlanes(DrmDisplayComposition *display_comp);
 
-  void ClearDisplay();
   void ApplyFrame(std::unique_ptr<DrmDisplayComposition> composition,
                   int status, bool writeback = false);
   int FlattenActiveComposition();
index 6aab6fb..8f655a7 100644 (file)
@@ -64,7 +64,7 @@ int DrmEventListener::Init() {
 
 void DrmEventListener::RegisterHotplugHandler(DrmEventHandler *handler) {
   assert(!hotplug_handler_);
-  hotplug_handler_ = handler;
+  hotplug_handler_.reset(handler);
 }
 
 void DrmEventListener::FlipHandler(int /* fd */, unsigned int /* sequence */,
index d8a61a5..95672ee 100644 (file)
@@ -58,7 +58,7 @@ class DrmEventListener : public Worker {
   int max_fd_ = -1;
 
   DrmDevice *drm_;
-  DrmEventHandler *hotplug_handler_ = NULL;
+  std::unique_ptr<DrmEventHandler> hotplug_handler_;
 };
 }  // namespace android
 
index 7bd8d64..f506bfc 100644 (file)
@@ -57,43 +57,55 @@ DrmHwcTwo::DrmHwcTwo() {
   getFunction = HookDevGetFunction;
 }
 
-HWC2::Error DrmHwcTwo::Init() {
-  int ret = resource_manager_.Init();
-  if (ret) {
-    ALOGE("Can't initialize the resource manager %d", ret);
-    return HWC2::Error::NoResources;
-  }
-
-  DrmDevice *drm = resource_manager_.GetDrmDevice(HWC_DISPLAY_PRIMARY);
-  std::shared_ptr<Importer> importer = resource_manager_.GetImporter(
-      HWC_DISPLAY_PRIMARY);
+HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ,
+                                     HWC2::DisplayType type) {
+  DrmDevice *drm = resource_manager_.GetDrmDevice(displ);
+  std::shared_ptr<Importer> importer = resource_manager_.GetImporter(displ);
   if (!drm || !importer) {
     ALOGE("Failed to get a valid drmresource and importer");
     return HWC2::Error::NoResources;
   }
-
-  displays_.emplace(std::piecewise_construct,
-                    std::forward_as_tuple(HWC_DISPLAY_PRIMARY),
+  displays_.emplace(std::piecewise_construct, std::forward_as_tuple(displ),
                     std::forward_as_tuple(&resource_manager_, drm, importer,
-                                          HWC_DISPLAY_PRIMARY,
-                                          HWC2::DisplayType::Physical));
+                                          displ, type));
 
-  DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(HWC_DISPLAY_PRIMARY));
+  DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(displ));
   if (!crtc) {
-    ALOGE("Failed to get crtc for display %d",
-          static_cast<int>(HWC_DISPLAY_PRIMARY));
+    ALOGE("Failed to get crtc for display %d", static_cast<int>(displ));
     return HWC2::Error::BadDisplay;
   }
-
   std::vector<DrmPlane *> display_planes;
   for (auto &plane : drm->planes()) {
     if (plane->GetCrtcSupported(*crtc))
       display_planes.push_back(plane.get());
   }
-  displays_.at(HWC_DISPLAY_PRIMARY).Init(&display_planes);
+  displays_.at(displ).Init(&display_planes);
   return HWC2::Error::None;
 }
 
+HWC2::Error DrmHwcTwo::Init() {
+  int rv = resource_manager_.Init();
+  if (rv) {
+    ALOGE("Can't initialize the resource manager %d", rv);
+    return HWC2::Error::NoResources;
+  }
+
+  HWC2::Error ret = HWC2::Error::None;
+  for (int i = 0; i < resource_manager_.getDisplayCount(); i++) {
+    ret = CreateDisplay(i, HWC2::DisplayType::Physical);
+    if (ret != HWC2::Error::None) {
+      ALOGE("Failed to create display %d with error %d", i, ret);
+      return ret;
+    }
+  }
+
+  auto &drmDevices = resource_manager_.getDrmDevices();
+  for (auto &device : drmDevices) {
+    device->RegisterHotplugHandler(new DrmHotplugHandler(this, device.get()));
+  }
+  return ret;
+}
+
 template <typename... Args>
 static inline HWC2::Error unsupported(char const *func, Args... /*args*/) {
   ALOGV("Unsupported function: %s", func);
@@ -132,6 +144,12 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
                                         hwc2_function_pointer_t function) {
   supported(__func__);
   auto callback = static_cast<HWC2::Callback>(descriptor);
+
+  if (!function) {
+    callbacks_.erase(callback);
+    return HWC2::Error::None;
+  }
+
   callbacks_.emplace(callback, HwcCallback(data, function));
 
   switch (callback) {
@@ -139,6 +157,9 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
       auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(function);
       hotplug(data, HWC_DISPLAY_PRIMARY,
               static_cast<int32_t>(HWC2::Connection::Connected));
+      auto &drmDevices = resource_manager_.getDrmDevices();
+      for (auto &device : drmDevices)
+        HandleInitialHotplugState(device.get());
       break;
     }
     case HWC2::Callback::Vsync: {
@@ -165,6 +186,10 @@ DrmHwcTwo::HwcDisplay::HwcDisplay(ResourceManager *resource_manager,
   supported(__func__);
 }
 
+void DrmHwcTwo::HwcDisplay::ClearDisplay() {
+  compositor_.ClearDisplay();
+}
+
 HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
   supported(__func__);
   planner_ = Planner::CreateInstance(drm_);
@@ -204,6 +229,16 @@ HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
     return HWC2::Error::BadDisplay;
   }
 
+  ret = vsync_worker_.Init(drm_, display);
+  if (ret) {
+    ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
+    return HWC2::Error::BadDisplay;
+  }
+
+  return ChosePreferredConfig();
+}
+
+HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() {
   // Fetch the number of modes from the display
   uint32_t num_configs;
   HWC2::Error err = GetDisplayConfigs(&num_configs, NULL);
@@ -217,13 +252,6 @@ HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
   err = GetDisplayConfigs(&num_configs, &default_config);
   if (err != HWC2::Error::None)
     return err;
-
-  ret = vsync_worker_.Init(drm_, display);
-  if (ret) {
-    ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
-    return HWC2::Error::BadDisplay;
-  }
-
   return SetActiveConfig(default_config);
 }
 
@@ -617,8 +645,8 @@ HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfig(hwc2_config_t config) {
     ALOGE("Failed to queue dpms composition on %d", ret);
     return HWC2::Error::BadConfig;
   }
-  if (connector_->active_mode().id() == 0)
-    connector_->set_active_mode(*mode);
+
+  connector_->set_active_mode(*mode);
 
   // Setup the client layer's dimensions
   hwc_rect_t display_frame = {.left = 0,
@@ -880,6 +908,52 @@ void DrmHwcTwo::HwcLayer::PopulateDrmLayer(DrmHwcLayer *layer) {
   layer->SetTransform(static_cast<int32_t>(transform_));
 }
 
+void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
+  auto cb = callbacks_.find(HWC2::Callback::Hotplug);
+  if (cb == callbacks_.end())
+    return;
+
+  auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(cb->second.func);
+  hotplug(cb->second.data, displayid,
+          (state == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
+                                       : HWC2_CONNECTION_DISCONNECTED));
+}
+
+void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) {
+  for (auto &conn : drmDevice->connectors()) {
+    if (conn->state() != DRM_MODE_CONNECTED)
+      continue;
+    HandleDisplayHotplug(conn->display(), conn->state());
+  }
+}
+
+void DrmHwcTwo::DrmHotplugHandler::HandleEvent(uint64_t timestamp_us) {
+  for (auto &conn : drm_->connectors()) {
+    drmModeConnection old_state = conn->state();
+    drmModeConnection cur_state = conn->UpdateModes()
+                                      ? DRM_MODE_UNKNOWNCONNECTION
+                                      : conn->state();
+
+    if (cur_state == old_state)
+      continue;
+
+    ALOGI("%s event @%" PRIu64 " for connector %u on display %d",
+          cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us,
+          conn->id(), conn->display());
+
+    int display_id = conn->display();
+    if (cur_state == DRM_MODE_CONNECTED) {
+      auto &display = hwc2_->displays_.at(display_id);
+      display.ChosePreferredConfig();
+    } else {
+      auto &display = hwc2_->displays_.at(display_id);
+      display.ClearDisplay();
+    }
+
+    hwc2_->HandleDisplayHotplug(display_id, cur_state);
+  }
+}
+
 // static
 int DrmHwcTwo::HookDevClose(hw_device_t * /*dev*/) {
   unsupported(__func__);
index d9ced9b..a71d7cc 100644 (file)
@@ -143,6 +143,7 @@ class DrmHwcTwo : public hwc2_device_t {
 
     HWC2::Error RegisterVsyncCallback(hwc2_callback_data_t data,
                                       hwc2_function_pointer_t func);
+    void ClearDisplay();
 
     // HWC Hooks
     HWC2::Error AcceptDisplayChanges();
@@ -173,6 +174,7 @@ class DrmHwcTwo : public hwc2_device_t {
                                  int32_t *fences);
     HWC2::Error PresentDisplay(int32_t *retire_fence);
     HWC2::Error SetActiveConfig(hwc2_config_t config);
+    HWC2::Error ChosePreferredConfig();
     HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence,
                                 int32_t dataspace, hwc_region_t damage);
     HWC2::Error SetColorMode(int32_t mode);
@@ -213,6 +215,18 @@ class DrmHwcTwo : public hwc2_device_t {
     uint32_t frame_no_ = 0;
   };
 
+  class DrmHotplugHandler : public DrmEventHandler {
+   public:
+    DrmHotplugHandler(DrmHwcTwo *hwc2, DrmDevice *drm)
+        : hwc2_(hwc2), drm_(drm) {
+    }
+    void HandleEvent(uint64_t timestamp_us);
+
+   private:
+    DrmHwcTwo *hwc2_;
+    DrmDevice *drm_;
+  };
+
   static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) {
     return static_cast<DrmHwcTwo *>(dev);
   }
@@ -261,6 +275,9 @@ class DrmHwcTwo : public hwc2_device_t {
   uint32_t GetMaxVirtualDisplayCount();
   HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
                                hwc2_function_pointer_t function);
+  HWC2::Error CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type);
+  void HandleDisplayHotplug(hwc2_display_t displayid, int state);
+  void HandleInitialHotplugState(DrmDevice *drmDevice);
 
   ResourceManager resource_manager_;
   std::map<hwc2_display_t, HwcDisplay> displays_;
index 463739b..f10af45 100644 (file)
@@ -34,6 +34,12 @@ class ResourceManager {
   std::shared_ptr<Importer> GetImporter(int display);
   const gralloc_module_t *gralloc();
   DrmConnector *AvailableWritebackConnector(int display);
+  const std::vector<std::unique_ptr<DrmDevice>> &getDrmDevices() const {
+    return drms_;
+  }
+  int getDisplayCount() const {
+    return num_displays_;
+  }
 
  private:
   int AddDrmDevice(std::string path);