drm_hwcomposer: Introduce Planner interface

This patch introduces a new Planner interface to the platform specific
code. This new interface will allow for platform-specific plane provisioning
decisions to cover various hardware quirks.

Each platform must provide a Planner with one or more PlanStage steps. These
stages are run in order and are used to move the given layers onto composition
planes.

There are two generic stages provided by the platform:
- Protected: Places layers on dedicated planes
- Greedy: Provisions as many layers to planes and sticks the rest in precomp

There is also one platform-specific stage included:
- ProtectedRotated: Places any protected & rotated layer on the primary plane

BUG=b/28117135
TEST=Tested on ryu with a variety of window layouts

Signed-off-by: Sean Paul <seanpaul@chromium.org>
Change-Id: Ib6062ab4779166753afaf122450bb63126bf9161
diff --git a/platformnv.cpp b/platformnv.cpp
index 5b79826..db7ee36 100644
--- a/platformnv.cpp
+++ b/platformnv.cpp
@@ -183,4 +183,92 @@
                            GRALLOC_MODULE_PERFORM_SET_IMPORTER_PRIVATE, handle,
                            NvGrallocRelease, buf);
 }
+
+#ifdef USE_NVIDIA_IMPORTER
+// static
+std::unique_ptr<Planner> Planner::CreateInstance(DrmResources *) {
+  std::unique_ptr<Planner> planner(new Planner);
+  planner->AddStage<PlanStageProtectedRotated>();
+  planner->AddStage<PlanStageProtected>();
+  planner->AddStage<PlanStageGreedy>();
+  return planner;
+}
+#endif
+
+static DrmPlane *GetCrtcPrimaryPlane(DrmCrtc *crtc,
+                                     std::vector<DrmPlane *> *planes) {
+  for (auto i = planes->begin(); i != planes->end(); ++i) {
+    if ((*i)->GetCrtcSupported(*crtc)) {
+      DrmPlane *plane = *i;
+      planes->erase(i);
+      return plane;
+    }
+  }
+  return NULL;
+}
+
+int PlanStageProtectedRotated::ProvisionPlanes(
+    std::vector<DrmCompositionPlane> *composition,
+    std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
+    std::vector<DrmPlane *> *planes) {
+  int ret;
+  int protected_zorder = -1;
+  for (auto i = layers.begin(); i != layers.end();) {
+    if (!i->second->protected_usage() || !i->second->transform) {
+      ++i;
+      continue;
+    }
+
+    auto primary_iter = planes->begin();
+    for (; primary_iter != planes->end(); ++primary_iter) {
+      if ((*primary_iter)->type() == DRM_PLANE_TYPE_PRIMARY)
+        break;
+    }
+
+    // We cheat a little here. Since there can only be one primary plane per
+    // crtc, we know we'll only hit this case once. So we blindly insert the
+    // protected content at the beginning of the composition, knowing this path
+    // won't be taken a second time during the loop.
+    if (primary_iter != planes->end()) {
+      composition->emplace(composition->begin(),
+                           DrmCompositionPlane::Type::kLayer, *primary_iter,
+                           crtc, i->first);
+      planes->erase(primary_iter);
+      protected_zorder = i->first;
+    } else {
+      ALOGE("Could not provision primary plane for protected/rotated layer");
+    }
+    i = layers.erase(i);
+  }
+
+  if (protected_zorder == -1)
+    return 0;
+
+  // Add any layers below the protected content to the precomposition since we
+  // need to punch a hole through them.
+  for (auto i = layers.begin(); i != layers.end();) {
+    // Skip layers above the z-order of the protected content
+    if (i->first > static_cast<size_t>(protected_zorder)) {
+      ++i;
+      continue;
+    }
+
+    // If there's no precomp layer already queued, queue one now.
+    DrmCompositionPlane *precomp = GetPrecomp(composition);
+    if (precomp) {
+      precomp->source_layers().emplace_back(i->first);
+    } else {
+      if (planes->size()) {
+        DrmPlane *precomp_plane = planes->back();
+        planes->pop_back();
+        composition->emplace_back(DrmCompositionPlane::Type::kPrecomp,
+                                  precomp_plane, crtc, i->first);
+      } else {
+        ALOGE("Not enough planes to reserve for precomp fb");
+      }
+    }
+    i = layers.erase(i);
+  }
+  return 0;
+}
 }