Merge remote-tracking branch 'aosp/upstream-master' into HEAD

Re-sync w/ upstream freedesktop.org tree

Change-Id: I1af2047bdf601cae19e29b6106c2b57a37b324a6
Signed-off-by: John Stultz <john.stultz@linaro.org>
diff --git a/.gitlab-ci-checkcommit.sh b/.gitlab-ci-checkcommit.sh
new file mode 100755
index 0000000..fc8963a
--- /dev/null
+++ b/.gitlab-ci-checkcommit.sh
@@ -0,0 +1,37 @@
+#! /usr/bin/env bash
+
+echoerr() {
+	printf "ERROR: %s\n" "$*" >&2
+}
+
+git fetch https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer.git
+
+git log --pretty='%h' FETCH_HEAD..HEAD | while read h; do
+	subject=$(git show -s --pretty='%s' "$h")
+	if [[ $subject != drm_hwcomposer:* ]]; then
+		echoerr "Invalid subject prefix: $subject"
+		exit 1
+	fi
+
+	commit_body=$(git show -s --pretty=%b "$h")
+
+	author=$(git show -s --format='%an <%ae>')
+	sob=$(echo "$commit_body" | grep "Signed-off-by: $author")
+	if [ -z "$sob" ] ; then
+		echoerr "Author SoB tag is missing from commit $h"
+		exit 1
+	fi
+
+	committer=$(git show -s --format='%cn <%ce>')
+	sob=$(echo "$commit_body" | grep "Signed-off-by: $committer")
+	if [ -z "$sob" ] ; then
+		echoerr "Committer SoB tag is missing from commit $h"
+		exit 1
+	fi
+
+	git show "$h" -- | clang-format-diff-5.0 -p 1 -style=file > format-fixup.patch
+	if [ -s  format-fixup.patch ]; then
+		cat format-fixup.patch >&2
+		exit 1
+	fi
+done
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 24c4a0a..c97f4ff 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -7,13 +7,9 @@
 stages:
   - style
 
-clang-format:
+checkstyle:
   stage: style
-  script:
-    - git fetch https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer.git
-    - git diff -U0 --no-color FETCH_HEAD...HEAD -- | clang-format-diff-5.0 -p 1 -style=file > format-fixup.patch
-    - if [ -s format-fixup.patch ]; then cat format-fixup.patch && exit 1; fi
+  script: "./.gitlab-ci-checkcommit.sh"
   artifacts:
     when: on_failure
-    paths:
-      - format-fixup.patch
+    untracked: true
diff --git a/README.md b/README.md
index 260ac9b..05f1364 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
 * drm_hwcomposer is Apache 2.0 Licensed and we require contributions to follow the developer's certificate of origin: http://developercertificate.org/
 * When submitting new code please follow the naming conventions documented in the generated documentation. Also please make full use of all the helpers and convenience macros provided by drm_hwcomposer. The below command can help you with formatting of your patches:
   
-      `git diff | clang-format-diff-3.5 -p 1 -style=file`
+      `git diff | clang-format-diff-5.0 -p 1 -style=file`
 * Hardware specific changes should be tested on relevant platforms before committing.
 
 If you need inspiration, please checkout our [TODO issues](https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/issues?label_name%5B%5D=TODO)
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index f479f10..a1ccdc7 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -316,6 +316,7 @@
     hwc_frect_t source_crop;
     uint64_t rotation = 0;
     uint64_t alpha = 0xFFFF;
+    uint64_t blend;
 
     if (comp_plane.type() != DrmCompositionPlane::Type::kDisable) {
       if (source_layers.size() > 1) {
@@ -338,8 +339,36 @@
       fence_fd = layer.acquire_fence.get();
       display_frame = layer.display_frame;
       source_crop = layer.source_crop;
-      if (layer.blending == DrmHwcBlending::kPreMult)
-        alpha = layer.alpha;
+      alpha = layer.alpha;
+
+      if (plane->blend_property().id()) {
+        switch (layer.blending) {
+          case DrmHwcBlending::kPreMult:
+            std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName(
+                "Pre-multiplied");
+            break;
+          case DrmHwcBlending::kCoverage:
+            std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName(
+                "Coverage");
+            break;
+          case DrmHwcBlending::kNone:
+          default:
+            std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName(
+                "None");
+            break;
+        }
+      }
+
+      if (plane->zpos_property().id() && !plane->zpos_property().immutable()) {
+        ret = drmModeAtomicAddProperty(pset, plane->id(),
+                                       plane->zpos_property().id(),
+                                       source_layers.front()) < 0;
+        if (ret) {
+          ALOGE("Failed to add zpos property %d to plane %d",
+                plane->zpos_property().id(), plane->id());
+          break;
+        }
+      }
 
       rotation = 0;
       if (layer.transform & DrmHwcTransform::kFlipH)
@@ -382,20 +411,6 @@
       continue;
     }
 
-    // TODO: Once we have atomic test, this should fall back to GL
-    if (rotation != DRM_MODE_ROTATE_0 && plane->rotation_property().id() == 0) {
-      ALOGV("Rotation is not supported on plane %d", plane->id());
-      ret = -EINVAL;
-      break;
-    }
-
-    // TODO: Once we have atomic test, this should fall back to GL
-    if (alpha != 0xFFFF && plane->alpha_property().id() == 0) {
-      ALOGV("Alpha is not supported on plane %d", plane->id());
-      ret = -EINVAL;
-      break;
-    }
-
     ret = drmModeAtomicAddProperty(pset, plane->id(),
                                    plane->crtc_property().id(), crtc->id()) < 0;
     ret |= drmModeAtomicAddProperty(pset, plane->id(),
@@ -453,6 +468,16 @@
         break;
       }
     }
+
+    if (plane->blend_property().id()) {
+      ret = drmModeAtomicAddProperty(pset, plane->id(),
+                                     plane->blend_property().id(), blend) < 0;
+      if (ret) {
+        ALOGE("Failed to add pixel blend mode property %d to plane %d",
+              plane->blend_property().id(), plane->id());
+        break;
+      }
+    }
   }
 
   if (!ret) {
diff --git a/drmhwctwo.cpp b/drmhwctwo.cpp
index c801f2e..cd79e7b 100644
--- a/drmhwctwo.cpp
+++ b/drmhwctwo.cpp
@@ -491,9 +491,13 @@
   std::map<uint32_t, DrmHwcTwo::HwcLayer *> z_map;
   for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) {
     HWC2::Composition comp_type;
-    if (test)
+    if (test) {
       comp_type = l.second.sf_type();
-    else
+      if (comp_type == HWC2::Composition::Device) {
+        if (!importer_->CanImportBuffer(l.second.buffer()))
+          comp_type = HWC2::Composition::Client;
+      }
+    } else
       comp_type = l.second.validated_type();
 
     switch (comp_type) {
@@ -735,7 +739,8 @@
   for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) {
     if (comp_failed || !avail_planes--)
       break;
-    l.second->set_validated_type(HWC2::Composition::Device);
+    if (importer_->CanImportBuffer(l.second->buffer()))
+      l.second->set_validated_type(HWC2::Composition::Device);
   }
 
   for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) {
diff --git a/drmplane.cpp b/drmplane.cpp
index 2603e16..35f91b4 100644
--- a/drmplane.cpp
+++ b/drmplane.cpp
@@ -118,6 +118,10 @@
     return ret;
   }
 
+  ret = drm_->GetPlaneProperty(*this, "zpos", &zpos_property_);
+  if (ret)
+    ALOGE("Could not get zpos property for plane %u", id());
+
   ret = drm_->GetPlaneProperty(*this, "rotation", &rotation_property_);
   if (ret)
     ALOGE("Could not get rotation property");
@@ -126,6 +130,10 @@
   if (ret)
     ALOGI("Could not get alpha property");
 
+  ret = drm_->GetPlaneProperty(*this, "pixel blend mode", &blend_property_);
+  if (ret)
+    ALOGI("Could not get pixel blend mode property");
+
   ret = drm_->GetPlaneProperty(*this, "IN_FENCE_FD", &in_fence_fd_property_);
   if (ret)
     ALOGI("Could not get IN_FENCE_FD property");
@@ -185,6 +193,10 @@
   return src_h_property_;
 }
 
+const DrmProperty &DrmPlane::zpos_property() const {
+  return zpos_property_;
+}
+
 const DrmProperty &DrmPlane::rotation_property() const {
   return rotation_property_;
 }
@@ -193,6 +205,10 @@
   return alpha_property_;
 }
 
+const DrmProperty &DrmPlane::blend_property() const {
+  return blend_property_;
+}
+
 const DrmProperty &DrmPlane::in_fence_fd_property() const {
   return in_fence_fd_property_;
 }
diff --git a/drmplane.h b/drmplane.h
index 46dbc94..43e0e8a 100644
--- a/drmplane.h
+++ b/drmplane.h
@@ -52,8 +52,10 @@
   const DrmProperty &src_y_property() const;
   const DrmProperty &src_w_property() const;
   const DrmProperty &src_h_property() const;
+  const DrmProperty &zpos_property() const;
   const DrmProperty &rotation_property() const;
   const DrmProperty &alpha_property() const;
+  const DrmProperty &blend_property() const;
   const DrmProperty &in_fence_fd_property() const;
 
  private:
@@ -74,8 +76,10 @@
   DrmProperty src_y_property_;
   DrmProperty src_w_property_;
   DrmProperty src_h_property_;
+  DrmProperty zpos_property_;
   DrmProperty rotation_property_;
   DrmProperty alpha_property_;
+  DrmProperty blend_property_;
   DrmProperty in_fence_fd_property_;
 };
 }  // namespace android
diff --git a/drmproperty.cpp b/drmproperty.cpp
index e71c159..9faa37e 100644
--- a/drmproperty.cpp
+++ b/drmproperty.cpp
@@ -99,4 +99,19 @@
       return -EINVAL;
   }
 }
+
+bool DrmProperty::immutable() const {
+  return id_ && (flags_ & DRM_MODE_PROP_IMMUTABLE);
+}
+
+std::tuple<uint64_t, int> DrmProperty::GetEnumValueWithName(
+    std::string name) const {
+  for (auto it : enums_) {
+    if (it.name_.compare(name) == 0) {
+      return std::make_tuple(it.value_, 0);
+    }
+  }
+
+  return std::make_tuple(UINT64_MAX, -EINVAL);
+}
 }  // namespace android
diff --git a/drmproperty.h b/drmproperty.h
index dc01c88..f1328fe 100644
--- a/drmproperty.h
+++ b/drmproperty.h
@@ -40,11 +40,13 @@
   DrmProperty &operator=(const DrmProperty &) = delete;
 
   void Init(drmModePropertyPtr p, uint64_t value);
+  std::tuple<uint64_t, int> GetEnumValueWithName(std::string name) const;
 
   uint32_t id() const;
   std::string name() const;
 
   int value(uint64_t *value) const;
+  bool immutable() const;
 
  private:
   class DrmPropertyEnum {
diff --git a/platform.cpp b/platform.cpp
index af18124..b7a47c7 100644
--- a/platform.cpp
+++ b/platform.cpp
@@ -36,6 +36,50 @@
   return usable_planes;
 }
 
+int Planner::PlanStage::ValidatePlane(DrmPlane *plane, DrmHwcLayer *layer) {
+  int ret = 0;
+  uint64_t blend;
+
+  if ((plane->rotation_property().id() == 0) &&
+      layer->transform != DrmHwcTransform::kIdentity) {
+    ALOGE("Rotation is not supported on plane %d", plane->id());
+    return -EINVAL;
+  }
+
+  if (plane->alpha_property().id() == 0 && layer->alpha != 0xffff) {
+    ALOGE("Alpha is not supported on plane %d", plane->id());
+    return -EINVAL;
+  }
+
+  if (plane->blend_property().id() == 0) {
+    if ((layer->blending != DrmHwcBlending::kNone) &&
+        (layer->blending != DrmHwcBlending::kPreMult)) {
+      ALOGE("Blending is not supported on plane %d", plane->id());
+      return -EINVAL;
+    }
+  } else {
+    switch (layer->blending) {
+      case DrmHwcBlending::kPreMult:
+        std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName(
+            "Pre-multiplied");
+        break;
+      case DrmHwcBlending::kCoverage:
+        std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName(
+            "Coverage");
+        break;
+      case DrmHwcBlending::kNone:
+      default:
+        std::tie(blend,
+                 ret) = plane->blend_property().GetEnumValueWithName("None");
+        break;
+    }
+    if (ret)
+      ALOGE("Expected a valid blend mode on plane %d", plane->id());
+  }
+
+  return ret;
+}
+
 std::tuple<int, std::vector<DrmCompositionPlane>> Planner::ProvisionPlanes(
     std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
     std::vector<DrmPlane *> *primary_planes,
@@ -73,9 +117,11 @@
     }
 
     ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer, crtc,
-                  i->first);
-    if (ret)
+                  std::make_pair(i->first, i->second));
+    if (ret) {
       ALOGE("Failed to dedicate protected layer! Dropping it.");
+      return ret;
+    }
 
     protected_zorder = i->first;
     i = layers.erase(i);
@@ -91,12 +137,14 @@
   // Fill up the remaining planes
   for (auto i = layers.begin(); i != layers.end(); i = layers.erase(i)) {
     int ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer,
-                      crtc, i->first);
+                      crtc, std::make_pair(i->first, i->second));
     // We don't have any planes left
     if (ret == -ENOENT)
       break;
-    else if (ret)
+    else if (ret) {
       ALOGE("Failed to emplace layer %zu, dropping it", i->first);
+      return ret;
+    }
   }
 
   return 0;
diff --git a/platform.h b/platform.h
index 37c4647..a58d62e 100644
--- a/platform.h
+++ b/platform.h
@@ -49,6 +49,9 @@
   // Note: This can be called from a different thread than ImportBuffer. The
   //       implementation is responsible for ensuring thread safety.
   virtual int ReleaseBuffer(hwc_drm_bo_t *bo) = 0;
+
+  // Checks if importer can import the buffer.
+  virtual bool CanImportBuffer(buffer_handle_t handle) = 0;
 };
 
 class Planner {
@@ -73,17 +76,32 @@
       return plane;
     }
 
+    static int ValidatePlane(DrmPlane *plane, DrmHwcLayer *layer);
+
     // Inserts the given layer:plane in the composition at the back
     static int Emplace(std::vector<DrmCompositionPlane> *composition,
                        std::vector<DrmPlane *> *planes,
                        DrmCompositionPlane::Type type, DrmCrtc *crtc,
-                       size_t source_layer) {
+                       std::pair<size_t, DrmHwcLayer *> layer) {
       DrmPlane *plane = PopPlane(planes);
-      if (!plane)
-        return -ENOENT;
+      std::vector<DrmPlane *> unused_planes;
+      int ret = -ENOENT;
+      while (plane) {
+        ret = ValidatePlane(plane, layer.second);
+        if (!ret)
+          break;
+        if (!plane->zpos_property().immutable())
+          unused_planes.push_back(plane);
+        plane = PopPlane(planes);
+      }
 
-      composition->emplace_back(type, plane, crtc, source_layer);
-      return 0;
+      if (!ret) {
+        composition->emplace_back(type, plane, crtc, layer.first);
+        planes->insert(planes->begin(), unused_planes.begin(),
+                       unused_planes.end());
+      }
+
+      return ret;
     }
   };
 
diff --git a/platformdrmgeneric.cpp b/platformdrmgeneric.cpp
index 24d0650..503c04a 100644
--- a/platformdrmgeneric.cpp
+++ b/platformdrmgeneric.cpp
@@ -161,6 +161,12 @@
   return 0;
 }
 
+bool DrmGenericImporter::CanImportBuffer(buffer_handle_t handle) {
+  if (handle == NULL)
+    return false;
+  return true;
+}
+
 #ifdef USE_DRM_GENERIC_IMPORTER
 std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice *) {
   std::unique_ptr<Planner> planner(new Planner);
diff --git a/platformdrmgeneric.h b/platformdrmgeneric.h
index d46e8b0..233ba55 100644
--- a/platformdrmgeneric.h
+++ b/platformdrmgeneric.h
@@ -33,6 +33,7 @@
 
   int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
   int ReleaseBuffer(hwc_drm_bo_t *bo) override;
+  bool CanImportBuffer(buffer_handle_t handle) override;
 
   uint32_t ConvertHalFormatToDrm(uint32_t hal_format);
   uint32_t DrmFormatToBitsPerPixel(uint32_t drm_format);
diff --git a/platformhisi.cpp b/platformhisi.cpp
index 68bb5a7..76fe1e7 100644
--- a/platformhisi.cpp
+++ b/platformhisi.cpp
@@ -78,10 +78,10 @@
   if (!hnd)
     return -EINVAL;
 
-  // We can't import these types of buffers, so pretend we did and rely on the
-  // planner to skip them when choosing layers for planes
+  // We can't import these types of buffers.
+  // These buffers should have been filtered out with CanImportBuffer()
   if (!(hnd->usage & GRALLOC_USAGE_HW_FB))
-    return 0;
+    return -EINVAL;
 
   uint32_t gem_handle;
   int ret = drmPrimeFDToHandle(drm_->fd(), hnd->share_fd, &gem_handle);
@@ -139,36 +139,39 @@
   return ret;
 }
 
+bool HisiImporter::CanImportBuffer(buffer_handle_t handle) {
+  private_handle_t const *hnd = reinterpret_cast<private_handle_t const *>(
+      handle);
+  return hnd && (hnd->usage & GRALLOC_USAGE_HW_FB);
+}
+
 class PlanStageHiSi : public Planner::PlanStage {
  public:
   int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition,
                       std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
                       std::vector<DrmPlane *> *planes) {
     int layers_added = 0;
-    int initial_layers = layers.size();
-    // Fill up as many planes as we can with buffers that do not have HW_FB
-    // usage
+    // Fill up as many DRM planes as we can with buffers that have HW_FB usage.
+    // Buffers without HW_FB should have been filtered out with
+    // CanImportBuffer(), if we meet one here, just skip it.
     for (auto i = layers.begin(); i != layers.end(); i = layers.erase(i)) {
       if (!(i->second->gralloc_buffer_usage & GRALLOC_USAGE_HW_FB))
         continue;
 
       int ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer,
-                        crtc, i->first);
+                        crtc, std::make_pair(i->first, i->second));
       layers_added++;
       // We don't have any planes left
       if (ret == -ENOENT)
         break;
-      else if (ret)
+      else if (ret) {
         ALOGE("Failed to emplace layer %zu, dropping it", i->first);
+        return ret;
+      }
     }
-    /*
-     * If we only have one layer, but we didn't emplace anything, we
-     * can run into trouble, as we might try to device composite a
-     * buffer we fake-imported, which can cause things to jamb up.
-     * So return an error in this case to ensure we force client
-     * compositing.
-     */
-    if (!layers_added && (initial_layers <= 1))
+    // If we didn't emplace anything, return an error to ensure we force client
+    // compositing.
+    if (!layers_added)
       return -EINVAL;
 
     return 0;
diff --git a/platformhisi.h b/platformhisi.h
index 2b2d439..927da17 100644
--- a/platformhisi.h
+++ b/platformhisi.h
@@ -36,6 +36,8 @@
 
   int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
 
+  bool CanImportBuffer(buffer_handle_t handle) override;
+
  private:
   DrmDevice *drm_;