drm_hwcomposer: Don't composite over protected layers

This patch changes two things with respect to protected layers:

1- It provisions the HW plane in the correct position. ie: if
   the background layer is slated for a HW plane, it will be
   placed on the primary layer and the protected layer will be
   placed on top of it.
2- It punches a hole through the precomposite and squash layers
   such that when they are placed on top of the protected layer,
   they do not obstruct it.

BUG=b/27502957
TEST=Tested on smaug with multi-window with a variety of different
     layouts and visible layers

Change-Id: Ie30939f2bb750dbe3faa558ddb094b677f41f45e
Signed-off-by: Sean Paul <seanpaul@chromium.org>
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index 300414d..d5e97b4 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -180,6 +180,8 @@
 
 static void SeparateLayers(DrmHwcLayer *layers, size_t *used_layers,
                            size_t num_used_layers,
+                           size_t *protected_layers,
+                           size_t num_protected_layers,
                            DrmHwcRect<int> *exclude_rects,
                            size_t num_exclude_rects,
                            std::vector<DrmCompositionRegion> &regions) {
@@ -188,33 +190,62 @@
     return;
   }
 
-  if (num_used_layers + num_exclude_rects > 64) {
+  // Index at which the actual layers begin
+  size_t layer_offset = num_exclude_rects + num_protected_layers;
+
+  if (num_used_layers + layer_offset > 64) {
     ALOGW(
         "Exclusion rectangles are being truncated to make the rectangle count "
         "fit into 64");
-    num_exclude_rects = 64 - num_used_layers;
+    num_exclude_rects = 64 - num_used_layers - num_protected_layers;
   }
 
   // We inject all the exclude rects into the rects list. Any resulting rect
-  // that includes ANY of the first num_exclude_rects is rejected.
-  std::vector<DrmHwcRect<int>> layer_rects(num_used_layers + num_exclude_rects);
+  // that includes ANY of the first num_exclude_rects is rejected. After the
+  // exclude rects, we add the protected layers. The rects that intersect with
+  // the protected layer will be inspected and only those which are above the
+  // protected layer will be included in the composition regions.
+  std::vector<DrmHwcRect<int>> layer_rects(num_used_layers + layer_offset);
   std::copy(exclude_rects, exclude_rects + num_exclude_rects,
             layer_rects.begin());
   std::transform(
-      used_layers, used_layers + num_used_layers,
+      protected_layers, protected_layers + num_protected_layers,
       layer_rects.begin() + num_exclude_rects,
       [=](size_t layer_index) { return layers[layer_index].display_frame; });
+  std::transform(
+      used_layers, used_layers + num_used_layers,
+      layer_rects.begin() + layer_offset,
+      [=](size_t layer_index) { return layers[layer_index].display_frame; });
 
   std::vector<separate_rects::RectSet<uint64_t, int>> separate_regions;
   separate_rects::separate_rects_64(layer_rects, &separate_regions);
   uint64_t exclude_mask = ((uint64_t)1 << num_exclude_rects) - 1;
+  uint64_t protected_mask = (((uint64_t)1 << num_protected_layers) - 1) <<
+                            num_exclude_rects;
 
   for (separate_rects::RectSet<uint64_t, int> &region : separate_regions) {
     if (region.id_set.getBits() & exclude_mask)
       continue;
+
+    // If a rect intersects a protected layer, we need to remove the layers
+    // from the composition region which appear *below* the protected layer.
+    // This effectively punches a hole through the composition layer such
+    // that the protected layer can be placed below the composition and not
+    // be occluded by things like the background.
+    uint64_t protected_intersect = region.id_set.getBits() & protected_mask;
+    for (size_t i = 0; protected_intersect && i < num_protected_layers; ++i) {
+      // Only exclude layers if they intersect this particular protected layer
+      if (!(protected_intersect & (1 << (i + num_exclude_rects))))
+        continue;
+
+      region.id_set.subtract(layer_offset, layer_offset + protected_layers[i]);
+    }
+    if (region.id_set.isEmpty())
+      continue;
+
     regions.emplace_back(DrmCompositionRegion{
         region.rect,
-        SetBitsToVector(region.id_set.getBits() >> num_exclude_rects,
+        SetBitsToVector(region.id_set.getBits() >> layer_offset,
                         used_layers)});
   }
 }
@@ -346,16 +377,20 @@
 
   // All protected layers get first usage of planes
   std::vector<size_t> layers_remaining;
+  std::vector<size_t> protected_layers;
   for (size_t layer_index = 0; layer_index < layers_.size(); layer_index++) {
     if (!layers_[layer_index].protected_usage() || planes_can_use == 0) {
       layers_remaining.push_back(layer_index);
       continue;
     }
-    EmplaceCompositionPlane(layer_index, primary_planes, overlay_planes);
+    protected_layers.push_back(layer_index);
     planes_can_use--;
   }
 
   if (planes_can_use == 0 && layers_remaining.size() > 0) {
+    for(auto i : protected_layers)
+      EmplaceCompositionPlane(i, primary_planes, overlay_planes);
+
     ALOGE("Protected layers consumed all hardware planes");
     return CreateAndAssignReleaseFences();
   }
@@ -380,22 +415,43 @@
     planes_can_use--;  // Reserve one for pre-compositing
 
   // Whatever planes that are not reserved get assigned a layer
-  size_t last_composition_layer = 0;
-  for (last_composition_layer = 0;
-       last_composition_layer < layers_remaining.size() && planes_can_use > 0;
-       last_composition_layer++, planes_can_use--) {
-    EmplaceCompositionPlane(layers_remaining[last_composition_layer],
+  size_t last_hw_comp_layer = 0;
+  size_t protected_idx = 0;
+  while(last_hw_comp_layer < layers_remaining.size() && planes_can_use > 0) {
+    size_t idx = layers_remaining[last_hw_comp_layer];
+
+    // Put the protected layers into the composition at the right place. We've
+    // already reserved them by decrementing planes_can_use, so no need to do
+    // that again.
+    if (protected_idx < protected_layers.size() &&
+        idx > protected_layers[protected_idx]) {
+        EmplaceCompositionPlane(protected_layers[protected_idx], primary_planes,
+                                overlay_planes);
+        protected_idx++;
+        continue;
+    }
+
+    EmplaceCompositionPlane(layers_remaining[last_hw_comp_layer],
                             primary_planes, overlay_planes);
+    last_hw_comp_layer++;
+    planes_can_use--;
   }
 
   layers_remaining.erase(layers_remaining.begin(),
-                         layers_remaining.begin() + last_composition_layer);
+                         layers_remaining.begin() + last_hw_comp_layer);
+
+  // Enqueue the rest of the protected layers (if any) between the hw composited
+  // overlay layers and the squash/precomp layers.
+  for(int i = protected_idx; i < protected_layers.size(); ++i)
+    EmplaceCompositionPlane(protected_layers[i], primary_planes,
+                            overlay_planes);
 
   if (layers_remaining.size() > 0) {
     EmplaceCompositionPlane(DrmCompositionPlane::kSourcePreComp, primary_planes,
                             overlay_planes);
     SeparateLayers(layers_.data(), layers_remaining.data(),
-                   layers_remaining.size(), exclude_rects.data(),
+                   layers_remaining.size(), protected_layers.data(),
+                   protected_layers.size(), exclude_rects.data(),
                    exclude_rects.size(), pre_comp_regions_);
   }
 
diff --git a/separate_rects.h b/separate_rects.h
index de8b660..cb46ecb 100644
--- a/separate_rects.h
+++ b/separate_rects.h
@@ -105,6 +105,14 @@
     bitset &= ~(((TUInt)1) << id);
   }
 
+  void subtract(TId start, TId end) {
+    if (start > end)
+      return;
+    TId start_mask = (1 << start) - 1;
+    TId end_mask = (1 << end) - 1;
+    bitset &= ~(start_mask ^ end_mask);
+  }
+
   bool isEmpty() const {
     return bitset == 0;
   }