drm_hwcomposer: fix pre comp regions during protected playback

During protected video playback an issue could happen when there are layers
below the protected video surface. The current logic in protected plane
provisioning logic includes all layers below the protected layer in precomp
plane in order to draw holes in these. However, when there are other layers in
place, in particular one that has blending (ex. PREMULT). For example:

Layers: count=3
  [0] blending[a=255]=NONE display_frame[x/y/w/h]=0/125/2560/1438
  [1] protected blending[a=255]=NONE display_frame[x/y/w/h]=0/181/2560/1438
  [2] blending[a=255]=PREMULT display_frame[x/y/w/h]=0/0/2560/1800
Planes: count=3
  [0] plane=17 type=LAYER source_layer=1
  [1] plane=22 type=LAYER source_layer=2
  [2] plane=23 type=PRECOMP source_layer=0
Squash Regions: count=0
Pre-Comp Regions: count=0

In this case, layer[0] is below protected surface (layer[1]). This causes
issues because precomp plane is setup to be on the highest z-order all the
time, and any time it isn't it expects any layers with higher z-order will
obscure some contents of the precomp layer. But in this case the layer on top
(layer[2]) has blending enabled (PREMULT) and is transparent so expectation is
that layer[0] is also rendered and blended with layer[2].

By merging any layer that is of higher z-order (layer[2] in example) to precomp
plane, all these layers can be handled during pre composition.

Bug: 36879178
Change-Id: I9b63b37fef0ae828c4a781e0d1da264d8a3d7a76
diff --git a/platform.cpp b/platform.cpp
index 105d8f7..e920872 100644
--- a/platform.cpp
+++ b/platform.cpp
@@ -140,6 +140,34 @@
   return 0;
 }
 
+int PlanStagePrecomp::ProvisionPlanes(
+    std::vector<DrmCompositionPlane> *composition,
+    std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
+    std::vector<DrmPlane *> *planes) {
+  DrmCompositionPlane *precomp = GetPrecomp(composition);
+  if (!precomp || precomp->source_layers().empty())
+    return 0;
+
+  // Find lowest zorder out of precomp layers
+  size_t precomp_zorder = *std::min_element(
+      precomp->source_layers().begin(), precomp->source_layers().end(),
+      [](size_t a, size_t b) { return a < b; });
+
+  // if there are any remaining layers on top of any of the precomp layers,
+  // add them to precomp to avoid blending issues since precomp is always at
+  // highest zorder
+  for (auto i = layers.begin(); i != layers.end();) {
+    if (i->first < precomp_zorder) {
+      i++;
+      continue;
+    }
+    precomp->source_layers().emplace_back(i->first);
+    i = layers.erase(i);
+  }
+
+  return 0;
+}
+
 int PlanStageGreedy::ProvisionPlanes(
     std::vector<DrmCompositionPlane> *composition,
     std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
diff --git a/platform.h b/platform.h
index da6b7cb..70e5e81 100644
--- a/platform.h
+++ b/platform.h
@@ -152,6 +152,18 @@
                       std::vector<DrmPlane *> *planes);
 };
 
+// This plan stage provisions the precomp plane with any remaining layers that
+// are on top of the current precomp layers. This stage should be included in
+// all platforms before loosely allocating layers (i.e. PlanStageGreedy) if
+// any previous plan could have modified the precomp plane layers
+// (ex. PlanStageProtected).
+class PlanStagePrecomp : public Planner::PlanStage {
+ public:
+  int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition,
+                      std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
+                      std::vector<DrmPlane *> *planes);
+};
+
 // This plan stage places as many layers on dedicated planes as possible (first
 // come first serve), and then sticks the rest in a precomposition plane (if
 // needed).
diff --git a/platformnv.cpp b/platformnv.cpp
index db7ee36..084d4f0 100644
--- a/platformnv.cpp
+++ b/platformnv.cpp
@@ -190,6 +190,7 @@
   std::unique_ptr<Planner> planner(new Planner);
   planner->AddStage<PlanStageProtectedRotated>();
   planner->AddStage<PlanStageProtected>();
+  planner->AddStage<PlanStagePrecomp>();
   planner->AddStage<PlanStageGreedy>();
   return planner;
 }