drm_hwcomposer: Introduce DrmDisplayPipeline class

Create systematic way of binding DRM objects (Crtc,Encoder,Planes...)
to the pipeline using RAII. Use it to create the pipeline.

+ Allow pipeline creation to fail.

Closes: https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/-/issues/14
Signed-off-by: Roman Stratiienko <roman.o.stratiienko@globallogic.com>
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index 29dd95f..ece9437 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -66,7 +66,6 @@
   ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
   if (ret != 0) {
     ALOGI("Failed to set writeback cap %d", ret);
-    ret = 0;
   }
 #endif
 
@@ -125,30 +124,6 @@
     }
   }
 
-  auto add_displays = [this, &num_displays](bool internal, bool connected) {
-    for (auto &conn : connectors_) {
-      bool is_connected = conn->IsConnected();
-      if ((internal ? conn->IsInternal() : conn->IsExternal()) &&
-          (connected ? is_connected : !is_connected)) {
-        bound_connectors_[num_displays] = conn.get();
-        connectors_to_display_id_[conn.get()] = num_displays;
-        ++num_displays;
-      }
-    }
-  };
-
-  /* Put internal first to ensure Primary display will be internal
-   * in case at least 1 internal is available
-   */
-  add_displays(/*internal = */ true, /*connected = */ true);
-  add_displays(/*internal = */ false, /*connected = */ true);
-  add_displays(/*internal = */ true, /*connected = */ false);
-  add_displays(/*internal = */ false, /*connected = */ false);
-
-  // Catch-all for the above loops
-  if (ret != 0)
-    return std::make_tuple(ret, 0);
-
   auto plane_res = MakeDrmModePlaneResUnique(GetFd());
   if (!plane_res) {
     ALOGE("Failed to get plane resources");
@@ -164,91 +139,50 @@
     }
   }
 
-  for (auto &conn : connectors_) {
-    ret = CreateDisplayPipe(conn.get());
-    if (ret != 0) {
-      ALOGE("Failed CreateDisplayPipe %d with %d", conn->GetId(), ret);
-      return std::make_tuple(ret, 0);
+  auto add_displays = [this, &num_displays](bool internal, bool connected) {
+    for (auto &conn : connectors_) {
+      bool is_connected = conn->IsConnected();
+      if ((internal ? conn->IsInternal() : conn->IsExternal()) &&
+          (connected ? is_connected : !is_connected)) {
+        auto pipe = DrmDisplayPipeline::CreatePipeline(*conn);
+        if (pipe) {
+          pipelines_[num_displays] = std::move(pipe);
+          ++num_displays;
+        }
+      }
     }
-  }
-  return std::make_tuple(ret, bound_connectors_.size());
+  };
+
+  /* Put internal first to ensure Primary display will be internal
+   * in case at least 1 internal is available
+   */
+  add_displays(/*internal = */ true, /*connected = */ true);
+  add_displays(/*internal = */ false, /*connected = */ true);
+  add_displays(/*internal = */ true, /*connected = */ false);
+  add_displays(/*internal = */ false, /*connected = */ false);
+
+  return std::make_tuple(0, pipelines_.size());
 }
 
 bool DrmDevice::HandlesDisplay(int display) const {
-  return bound_connectors_.count(display) != 0;
+  return pipelines_.count(display) != 0;
 }
 
 DrmConnector *DrmDevice::GetConnectorForDisplay(int display) const {
-  return bound_connectors_.at(display);
+  return pipelines_.at(display)->connector->Get();
 }
 
 DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const {
-  return bound_crtcs_.at(display);
+  return pipelines_.at(display)->crtc->Get();
 }
 
-int DrmDevice::TryEncoderForDisplay(int display, DrmEncoder *enc) {
-  /* First try to use the currently-bound crtc */
-  auto *crtc = FindCrtcById(enc->GetCurrentCrtcId());
-  if (crtc != nullptr && bound_crtcs_.count(display) == 0) {
-    bound_crtcs_[display] = crtc;
-    bound_encoders_[crtc] = enc;
-    return 0;
-  }
-
-  /* Try to find a possible crtc which will work */
-  for (auto &crtc : crtcs_) {
-    /* Crtc not supported or we've already tried this earlier */
-    if (!enc->SupportsCrtc(*crtc) || crtc->GetId() == enc->GetCurrentCrtcId()) {
-      continue;
-    }
-
-    if (bound_crtcs_.count(display) == 0) {
-      bound_crtcs_[display] = crtc.get();
-      bound_encoders_[crtc.get()] = enc;
-      return 0;
+auto DrmDevice::GetDisplayId(DrmConnector *conn) -> int {
+  for (auto &dpipe : pipelines_) {
+    if (dpipe.second->connector->Get() == conn) {
+      return dpipe.first;
     }
   }
-
-  /* We can't use the encoder, but nothing went wrong, try another one */
-  return -EAGAIN;
-}
-
-int DrmDevice::CreateDisplayPipe(DrmConnector *connector) {
-  int display = connectors_to_display_id_.at(connector);
-  /* Try to use current setup first */
-  auto *enc0 = FindEncoderById(connector->GetCurrentEncoderId());
-  if (enc0 != nullptr && encoders_to_display_id_.count(enc0) == 0) {
-    int ret = TryEncoderForDisplay(display, enc0);
-    if (ret == 0) {
-      encoders_to_display_id_[enc0] = display;
-      return 0;
-    }
-
-    if (ret != -EAGAIN) {
-      ALOGE("Could not set mode %d/%d", display, ret);
-      return ret;
-    }
-  }
-
-  for (auto &enc : encoders_) {
-    if (!connector->SupportsEncoder(*enc) ||
-        encoders_to_display_id_.count(enc.get()) != 0) {
-      continue;
-    }
-
-    int ret = TryEncoderForDisplay(display, enc.get());
-    if (ret == 0) {
-      encoders_to_display_id_[enc.get()] = display;
-      return 0;
-    }
-
-    if (ret != -EAGAIN) {
-      ALOGE("Could not set mode %d/%d", display, ret);
-      return ret;
-    }
-  }
-  ALOGE("Could not find a suitable encoder/crtc for display %d", display);
-  return -ENODEV;
+  return -1;
 }
 
 auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const