drm_hwcomposer: Rework KMS composition planner + plane sharing support

Rewrite Layer-to-Plane planner. Get rid of ~200 redundant lines of code
+ added plane sharing functionality.

Closes: https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/-/issues/11
Signed-off-by: Roman Stratiienko <roman.o.stratiienko@globallogic.com>
diff --git a/compositor/DrmDisplayComposition.cpp b/compositor/DrmDisplayComposition.cpp
deleted file mode 100644
index e571b26..0000000
--- a/compositor/DrmDisplayComposition.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#define LOG_TAG "hwc-drm-display-composition"
-
-#include "DrmDisplayComposition.h"
-
-#include <sync/sync.h>
-#include <xf86drmMode.h>
-
-#include <algorithm>
-#include <cstdlib>
-#include <unordered_set>
-
-#include "DrmDisplayCompositor.h"
-#include "Planner.h"
-#include "drm/DrmDevice.h"
-#include "utils/log.h"
-
-namespace android {
-
-DrmDisplayComposition::DrmDisplayComposition(DrmCrtc *crtc)
-    : crtc_(crtc)  // Can be NULL if we haven't modeset yet
-{
-}
-
-int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers) {
-  for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
-    layers_.emplace_back(std::move(layers[layer_index]));
-  }
-
-  return 0;
-}
-
-int DrmDisplayComposition::AddPlaneComposition(DrmCompositionPlane plane) {
-  composition_planes_.emplace_back(std::move(plane));
-  return 0;
-}
-
-int DrmDisplayComposition::Plan(std::vector<DrmPlane *> *primary_planes,
-                                std::vector<DrmPlane *> *overlay_planes) {
-  std::map<size_t, DrmHwcLayer *> to_composite;
-
-  for (size_t i = 0; i < layers_.size(); ++i)
-    to_composite.emplace(std::make_pair(i, &layers_[i]));
-
-  int ret = 0;
-  std::tie(ret, composition_planes_) = Planner::ProvisionPlanes(to_composite,
-                                                                crtc_,
-                                                                primary_planes,
-                                                                overlay_planes);
-  if (ret) {
-    ALOGV("Planner failed provisioning planes ret=%d", ret);
-    return ret;
-  }
-
-  // Remove the planes we used from the pool before returning. This ensures they
-  // won't be reused by another display in the composition.
-  for (auto &i : composition_planes_) {
-    if (!i.plane())
-      continue;
-
-    std::vector<DrmPlane *> *container = nullptr;
-    if (i.plane()->GetType() == DRM_PLANE_TYPE_PRIMARY)
-      container = primary_planes;
-    else
-      container = overlay_planes;
-    for (auto j = container->begin(); j != container->end(); ++j) {
-      if (*j == i.plane()) {
-        container->erase(j);
-        break;
-      }
-    }
-  }
-
-  return 0;
-}
-
-}  // namespace android
diff --git a/compositor/DrmDisplayComposition.h b/compositor/DrmDisplayComposition.h
deleted file mode 100644
index dcfd96e..0000000
--- a/compositor/DrmDisplayComposition.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2015 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_DRM_DISPLAY_COMPOSITION_H_
-#define ANDROID_DRM_DISPLAY_COMPOSITION_H_
-
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-
-#include <sstream>
-#include <vector>
-
-#include "drm/DrmCrtc.h"
-#include "drm/DrmPlane.h"
-#include "drmhwcomposer.h"
-
-namespace android {
-
-class Importer;
-
-constexpr size_t kUndefinedSourceLayer = UINT16_MAX;
-
-class DrmCompositionPlane {
- public:
-  DrmCompositionPlane() = default;
-  DrmCompositionPlane(DrmCompositionPlane &&rhs) = default;
-  DrmCompositionPlane &operator=(DrmCompositionPlane &&other) = default;
-  DrmCompositionPlane(DrmPlane *plane, size_t source_layer)
-      : plane_(plane), source_layer_(source_layer) {
-  }
-
-  DrmPlane *plane() const {
-    return plane_;
-  }
-
-  size_t source_layer() const {
-    return source_layer_;
-  }
-
- private:
-  DrmPlane *plane_ = nullptr;
-  size_t source_layer_ = kUndefinedSourceLayer;
-};
-
-class DrmDisplayComposition {
- public:
-  DrmDisplayComposition(const DrmDisplayComposition &) = delete;
-  explicit DrmDisplayComposition(DrmCrtc *crtc);
-  ~DrmDisplayComposition() = default;
-
-  int SetLayers(DrmHwcLayer *layers, size_t num_layers);
-  int AddPlaneComposition(DrmCompositionPlane plane);
-
-  int Plan(std::vector<DrmPlane *> *primary_planes,
-           std::vector<DrmPlane *> *overlay_planes);
-
-  std::vector<DrmHwcLayer> &layers() {
-    return layers_;
-  }
-
-  std::vector<DrmCompositionPlane> &composition_planes() {
-    return composition_planes_;
-  }
-
-  DrmCrtc *crtc() const {
-    return crtc_;
-  }
-
- private:
-  DrmCrtc *crtc_ = nullptr;
-
-  std::vector<DrmHwcLayer> layers_;
-  std::vector<DrmCompositionPlane> composition_planes_;
-};
-}  // namespace android
-
-#endif  // ANDROID_DRM_DISPLAY_COMPOSITION_H_
diff --git a/compositor/DrmDisplayCompositor.cpp b/compositor/DrmDisplayCompositor.cpp
index bd0247d..5be2941 100644
--- a/compositor/DrmDisplayCompositor.cpp
+++ b/compositor/DrmDisplayCompositor.cpp
@@ -108,29 +108,18 @@
     new_frame_state.used_framebuffers.clear();
     new_frame_state.used_planes.clear();
 
-    std::vector<DrmHwcLayer> &layers = args.composition->layers();
-    std::vector<DrmCompositionPlane> &comp_planes = args.composition
-                                                        ->composition_planes();
-
-    for (DrmCompositionPlane &comp_plane : comp_planes) {
-      DrmPlane *plane = comp_plane.plane();
-      size_t source_layer = comp_plane.source_layer();
-
-      if (source_layer >= layers.size()) {
-        ALOGE("Source layer index %zu out of bounds %zu", source_layer,
-              layers.size());
-        return -EINVAL;
-      }
-      DrmHwcLayer &layer = layers[source_layer];
+    for (auto &joining : args.composition->plan) {
+      DrmPlane *plane = joining.plane->Get();
+      DrmHwcLayer &layer = joining.layer;
 
       new_frame_state.used_framebuffers.emplace_back(layer.fb_id_handle);
-      new_frame_state.used_planes.emplace_back(plane);
+      new_frame_state.used_planes.emplace_back(joining.plane);
 
       /* Remove from 'unused' list, since plane is re-used */
       auto &v = unused_planes;
-      v.erase(std::remove(v.begin(), v.end(), plane), v.end());
+      v.erase(std::remove(v.begin(), v.end(), joining.plane), v.end());
 
-      if (plane->AtomicSetState(*pset, layer, source_layer, crtc->GetId()) !=
+      if (plane->AtomicSetState(*pset, layer, joining.z_pos, crtc->GetId()) !=
           0) {
         return -EINVAL;
       }
@@ -143,8 +132,8 @@
   }
 
   if (args.clear_active_composition || args.composition) {
-    for (auto *plane : unused_planes) {
-      if (plane->AtomicDisablePlane(*pset) != 0) {
+    for (auto &plane : unused_planes) {
+      if (plane->Get()->AtomicDisablePlane(*pset) != 0) {
         return -EINVAL;
       }
     }
diff --git a/compositor/DrmDisplayCompositor.h b/compositor/DrmDisplayCompositor.h
index bff3de7..b556268 100644
--- a/compositor/DrmDisplayCompositor.h
+++ b/compositor/DrmDisplayCompositor.h
@@ -17,8 +17,6 @@
 #ifndef ANDROID_DRM_DISPLAY_COMPOSITOR_H_
 #define ANDROID_DRM_DISPLAY_COMPOSITOR_H_
 
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
 #include <pthread.h>
 
 #include <functional>
@@ -27,7 +25,8 @@
 #include <sstream>
 #include <tuple>
 
-#include "DrmDisplayComposition.h"
+#include "DrmKmsPlan.h"
+#include "drm/DrmPlane.h"
 #include "drm/ResourceManager.h"
 #include "drm/VSyncWorker.h"
 #include "drmhwcomposer.h"
@@ -39,7 +38,7 @@
   bool test_only = false;
   std::optional<DrmMode> display_mode;
   std::optional<bool> active;
-  std::shared_ptr<DrmDisplayComposition> composition;
+  std::shared_ptr<DrmKmsPlan> composition;
   /* 'clear' should never be used together with 'composition' */
   bool clear_active_composition = false;
 
@@ -68,7 +67,7 @@
 
   struct KmsState {
     /* Required to cleanup unused planes */
-    std::vector<DrmPlane *> used_planes;
+    std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> used_planes;
     /* We have to hold a reference to framebuffer while displaying it ,
      * otherwise picture will blink */
     std::vector<std::shared_ptr<DrmFbIdHandle>> used_framebuffers;
diff --git a/compositor/DrmKmsPlan.cpp b/compositor/DrmKmsPlan.cpp
new file mode 100644
index 0000000..966bd4e
--- /dev/null
+++ b/compositor/DrmKmsPlan.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "hwc-composition-drm-kms-plan"
+
+#include "DrmKmsPlan.h"
+
+#include "drm/DrmDevice.h"
+#include "drm/DrmPlane.h"
+#include "utils/log.h"
+
+namespace android {
+auto DrmKmsPlan::CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
+                                  std::vector<DrmHwcLayer> composition)
+    -> std::unique_ptr<DrmKmsPlan> {
+  auto plan = std::make_unique<DrmKmsPlan>();
+
+  auto avail_planes = pipe.GetUsablePlanes();
+
+  int z_pos = 0;
+  for (auto &dhl : composition) {
+    std::shared_ptr<BindingOwner<DrmPlane>> plane;
+
+    /* Skip unsupported planes */
+    do {
+      if (avail_planes.empty()) {
+        return {};
+      }
+
+      plane = *avail_planes.begin();
+      avail_planes.erase(avail_planes.begin());
+    } while (!plane->Get()->IsValidForLayer(&dhl));
+
+    LayerToPlaneJoining joining = {
+        .layer = std::move(dhl),
+        .plane = plane,
+        .z_pos = z_pos++,
+    };
+
+    plan->plan.emplace_back(std::move(joining));
+  }
+
+  return plan;
+}
+
+}  // namespace android
diff --git a/compositor/DrmKmsPlan.h b/compositor/DrmKmsPlan.h
new file mode 100644
index 0000000..35e66e9
--- /dev/null
+++ b/compositor/DrmKmsPlan.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 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_DRM_KMS_PLAN_H_
+#define ANDROID_DRM_KMS_PLAN_H_
+
+#include <memory>
+#include <vector>
+
+#include "drmhwcomposer.h"
+
+namespace android {
+
+class DrmDevice;
+
+struct DrmKmsPlan {
+  struct LayerToPlaneJoining {
+    DrmHwcLayer layer;
+    std::shared_ptr<BindingOwner<DrmPlane>> plane;
+    int z_pos;
+  };
+
+  std::vector<LayerToPlaneJoining> plan;
+
+  static auto CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
+                               std::vector<DrmHwcLayer> composition)
+      -> std::unique_ptr<DrmKmsPlan>;
+};
+
+}  // namespace android
+#endif
diff --git a/compositor/Planner.cpp b/compositor/Planner.cpp
deleted file mode 100644
index d875b4b..0000000
--- a/compositor/Planner.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#define LOG_TAG "hwc-platform"
-
-#include "Planner.h"
-
-#include <algorithm>
-
-#include "drm/DrmDevice.h"
-#include "utils/log.h"
-
-namespace android {
-
-std::vector<DrmPlane *> Planner::GetUsablePlanes(
-    DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes,
-    std::vector<DrmPlane *> *overlay_planes) {
-  std::vector<DrmPlane *> usable_planes;
-  std::copy_if(primary_planes->begin(), primary_planes->end(),
-               std::back_inserter(usable_planes),
-               [=](DrmPlane *plane) { return plane->IsCrtcSupported(*crtc); });
-  std::copy_if(overlay_planes->begin(), overlay_planes->end(),
-               std::back_inserter(usable_planes),
-               [=](DrmPlane *plane) { return plane->IsCrtcSupported(*crtc); });
-  return usable_planes;
-}
-
-std::tuple<int, std::vector<DrmCompositionPlane>> Planner::ProvisionPlanes(
-    std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
-    std::vector<DrmPlane *> *primary_planes,
-    std::vector<DrmPlane *> *overlay_planes) {
-  std::vector<DrmCompositionPlane> composition;
-  std::vector<DrmPlane *> planes = GetUsablePlanes(crtc, primary_planes,
-                                                   overlay_planes);
-  if (planes.empty()) {
-    ALOGE("Crtc %d has no usable planes", crtc->GetId());
-    return std::make_tuple(-ENODEV, std::vector<DrmCompositionPlane>());
-  }
-
-  // Go through the provisioning stages and provision planes
-  int ret = ProvisionPlanesInternal(&composition, layers, &planes);
-  if (ret != 0) {
-    ALOGV("Failed provision stage with ret %d", ret);
-    return std::make_tuple(ret, std::vector<DrmCompositionPlane>());
-  }
-
-  return std::make_tuple(0, std::move(composition));
-}
-
-int Planner::ProvisionPlanesInternal(
-    std::vector<DrmCompositionPlane> *composition,
-    std::map<size_t, DrmHwcLayer *> &layers, std::vector<DrmPlane *> *planes) {
-  // Fill up the remaining planes
-  for (auto i = layers.begin(); i != layers.end(); i = layers.erase(i)) {
-    int ret = Emplace(composition, planes, std::make_pair(i->first, i->second));
-    // We don't have any planes left
-    if (ret == -ENOENT)
-      break;
-
-    if (ret != 0) {
-      ALOGV("Failed to emplace layer %zu, dropping it", i->first);
-      return ret;
-    }
-  }
-
-  return 0;
-}
-}  // namespace android
diff --git a/compositor/Planner.h b/compositor/Planner.h
deleted file mode 100644
index 7802d0c..0000000
--- a/compositor/Planner.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2015 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_DRM_PLATFORM_H_
-#define ANDROID_DRM_PLATFORM_H_
-
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "compositor/DrmDisplayComposition.h"
-#include "drmhwcomposer.h"
-
-namespace android {
-
-class DrmDevice;
-
-class Planner {
- private:
-  // Removes and returns the next available plane from planes
-  static DrmPlane *PopPlane(std::vector<DrmPlane *> *planes) {
-    if (planes->empty())
-      return nullptr;
-    DrmPlane *plane = planes->front();
-    planes->erase(planes->begin());
-    return plane;
-  }
-
-  // Inserts the given layer:plane in the composition at the back
-  static int Emplace(std::vector<DrmCompositionPlane> *composition,
-                     std::vector<DrmPlane *> *planes,
-                     std::pair<size_t, DrmHwcLayer *> layer) {
-    DrmPlane *plane = PopPlane(planes);
-    std::vector<DrmPlane *> unused_planes;
-    int ret = -ENOENT;
-    while (plane != nullptr) {
-      ret = plane->IsValidForLayer(layer.second) ? 0 : -EINVAL;
-      if (ret == 0)
-        break;
-      if (!plane->GetZPosProperty().is_immutable())
-        unused_planes.push_back(plane);
-      plane = PopPlane(planes);
-    }
-
-    if (ret == 0) {
-      composition->emplace_back(plane, layer.first);
-      planes->insert(planes->begin(), unused_planes.begin(),
-                     unused_planes.end());
-    }
-
-    return ret;
-  }
-
-  static int ProvisionPlanesInternal(
-      std::vector<DrmCompositionPlane> *composition,
-      std::map<size_t, DrmHwcLayer *> &layers, std::vector<DrmPlane *> *planes);
-
- public:
-  // Takes a stack of layers and provisions hardware planes for them. If the
-  // entire stack can't fit in hardware, FIXME
-  //
-  // @layers: a map of index:layer of layers to composite
-  // @primary_planes: a vector of primary planes available for this frame
-  // @overlay_planes: a vector of overlay planes available for this frame
-  //
-  // Returns: A tuple with the status of the operation (0 for success) and
-  //          a vector of the resulting plan (ie: layer->plane mapping).
-  static std::tuple<int, std::vector<DrmCompositionPlane>> ProvisionPlanes(
-      std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
-      std::vector<DrmPlane *> *primary_planes,
-      std::vector<DrmPlane *> *overlay_planes);
-
- private:
-  static std::vector<DrmPlane *> GetUsablePlanes(
-      DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes,
-      std::vector<DrmPlane *> *overlay_planes);
-};
-}  // namespace android
-#endif