drm_hwcomposer: Make single atomic function for all atomic commit ops.

... to allow precise control on atomic commit operations.

This should also help to implement dynamic modechange, readback and
other useful features.

Signed-off-by: Roman Stratiienko <roman.o.stratiienko@globallogic.com>
diff --git a/compositor/DrmDisplayCompositor.cpp b/compositor/DrmDisplayCompositor.cpp
index bb6a33b..447d75e 100644
--- a/compositor/DrmDisplayCompositor.cpp
+++ b/compositor/DrmDisplayCompositor.cpp
@@ -40,20 +40,6 @@
 
 namespace android {
 
-DrmDisplayCompositor::DrmDisplayCompositor()
-    : resource_manager_(nullptr),
-      display_(-1),
-      initialized_(false),
-      active_(false) {
-}
-
-DrmDisplayCompositor::~DrmDisplayCompositor() {
-  if (!initialized_)
-    return;
-
-  active_composition_.reset();
-}
-
 auto DrmDisplayCompositor::Init(ResourceManager *resource_manager, int display)
     -> int {
   resource_manager_ = resource_manager;
@@ -81,42 +67,30 @@
   return std::make_unique<DrmDisplayComposition>(crtc, planner_.get());
 }
 
-int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) {
-  auto pset = MakeDrmModeAtomicReqUnique();
-  if (!pset) {
-    ALOGE("Failed to allocate property set");
-    return -ENOMEM;
-  }
-
-  int ret = 0;
-  std::vector<DrmCompositionPlane> &comp_planes = display_comp
-                                                      ->composition_planes();
-  for (DrmCompositionPlane &comp_plane : comp_planes) {
-    if (comp_plane.plane()->AtomicDisablePlane(*pset) != 0) {
-      return -EINVAL;
-    }
-  }
-  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  ret = drmModeAtomicCommit(drm->fd(), pset.get(), 0, drm);
-  if (ret) {
-    ALOGE("Failed to commit pset ret=%d\n", ret);
-    return ret;
-  }
-
-  return 0;
-}
-
-int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
-                                      bool test_only) {
+auto DrmDisplayCompositor::CommitFrame(AtomicCommitArgs &args) -> int {
   ATRACE_CALL();
 
-  int ret = 0;
+  if (args.active && *args.active == active_kms_data.active_state) {
+    /* Don't set the same state twice */
+    args.active.reset();
+  }
 
-  std::vector<DrmHwcLayer> &layers = display_comp->layers();
-  std::vector<DrmCompositionPlane> &comp_planes = display_comp
-                                                      ->composition_planes();
+  if (!args.HasInputs()) {
+    /* nothing to do */
+    return 0;
+  }
+
+  if (!active_kms_data.active_state) {
+    /* Force activate display */
+    args.active = true;
+  }
+
+  if (args.clear_active_composition && args.composition) {
+    ALOGE("%s: Invalid arguments", __func__);
+    return -EINVAL;
+  }
+
   DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  uint64_t out_fences[drm->crtcs().size()];
 
   DrmConnector *connector = drm->GetConnectorForDisplay(display_);
   if (!connector) {
@@ -135,113 +109,133 @@
     return -ENOMEM;
   }
 
+  int64_t out_fence = -1;
   if (crtc->out_fence_ptr_property() &&
-      !crtc->out_fence_ptr_property()
-           .AtomicSet(*pset, (uint64_t)&out_fences[crtc->pipe()])) {
+      !crtc->out_fence_ptr_property().AtomicSet(*pset, (uint64_t)&out_fence)) {
     return -EINVAL;
   }
 
-  if (mode_.blob &&
-      (!crtc->active_property().AtomicSet(*pset, 1) ||
-       !crtc->mode_property().AtomicSet(*pset, *mode_.blob) ||
-       !connector->crtc_id_property().AtomicSet(*pset, crtc->id()))) {
-    return -EINVAL;
+  DrmModeUserPropertyBlobUnique mode_blob;
+
+  if (args.active) {
+    if (!crtc->active_property().AtomicSet(*pset, *args.active) ||
+        !connector->crtc_id_property().AtomicSet(*pset, crtc->id())) {
+      return -EINVAL;
+    }
   }
 
-  for (DrmCompositionPlane &comp_plane : comp_planes) {
-    DrmPlane *plane = comp_plane.plane();
-    std::vector<size_t> &source_layers = comp_plane.source_layers();
+  if (args.display_mode) {
+    mode_blob = args.display_mode.value().CreateModeBlob(
+        *resource_manager_->GetDrmDevice(display_));
 
-    if (comp_plane.type() != DrmCompositionPlane::Type::kDisable) {
-      if (source_layers.size() > 1) {
-        ALOGE("Can't handle more than one source layer sz=%zu type=%d",
-              source_layers.size(), comp_plane.type());
-        continue;
-      }
+    if (!mode_blob) {
+      ALOGE("Failed to create mode_blob");
+      return -EINVAL;
+    }
 
-      if (source_layers.empty() || source_layers.front() >= layers.size()) {
-        ALOGE("Source layer index %zu out of bounds %zu type=%d",
-              source_layers.front(), layers.size(), comp_plane.type());
-        return -EINVAL;
-      }
-      DrmHwcLayer &layer = layers[source_layers.front()];
+    if (!crtc->mode_property().AtomicSet(*pset, *mode_blob)) {
+      return -EINVAL;
+    }
+  }
 
-      if (plane->AtomicSetState(*pset, layer, source_layers.front(),
-                                crtc->id()) != 0) {
-        return -EINVAL;
+  if (args.composition) {
+    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();
+      std::vector<size_t> &source_layers = comp_plane.source_layers();
+
+      if (comp_plane.type() != DrmCompositionPlane::Type::kDisable) {
+        if (source_layers.size() > 1) {
+          ALOGE("Can't handle more than one source layer sz=%zu type=%d",
+                source_layers.size(), comp_plane.type());
+          continue;
+        }
+
+        if (source_layers.empty() || source_layers.front() >= layers.size()) {
+          ALOGE("Source layer index %zu out of bounds %zu type=%d",
+                source_layers.front(), layers.size(), comp_plane.type());
+          return -EINVAL;
+        }
+        DrmHwcLayer &layer = layers[source_layers.front()];
+
+        if (plane->AtomicSetState(*pset, layer, source_layers.front(),
+                                  crtc->id()) != 0) {
+          return -EINVAL;
+        }
+      } else {
+        if (plane->AtomicDisablePlane(*pset) != 0) {
+          return -EINVAL;
+        }
       }
-    } else {
-      if (plane->AtomicDisablePlane(*pset) != 0) {
+    }
+  }
+
+  if (args.clear_active_composition && active_kms_data.composition) {
+    auto &comp_planes = active_kms_data.composition->composition_planes();
+    for (auto &comp_plane : comp_planes) {
+      if (comp_plane.plane()->AtomicDisablePlane(*pset) != 0) {
         return -EINVAL;
       }
     }
   }
 
-  if (!ret) {
-    uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
-    if (test_only)
-      flags |= DRM_MODE_ATOMIC_TEST_ONLY;
+  uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+  if (args.test_only)
+    flags |= DRM_MODE_ATOMIC_TEST_ONLY;
 
-    ret = drmModeAtomicCommit(drm->fd(), pset.get(), flags, drm);
-    if (ret) {
-      if (!test_only)
-        ALOGE("Failed to commit pset ret=%d\n", ret);
-      return ret;
-    }
+  int err = drmModeAtomicCommit(drm->fd(), pset.get(), flags, drm);
+  if (err) {
+    if (!args.test_only)
+      ALOGE("Failed to commit pset ret=%d\n", err);
+    return err;
   }
 
-  if (!test_only) {
-    if (mode_.blob) {
-      connector->set_active_mode(mode_.mode);
-      mode_.old_blob = std::move(mode_.blob);
+  if (!args.test_only) {
+    if (args.display_mode) {
+      connector->set_active_mode(*args.display_mode);
+      active_kms_data.mode_blob = std::move(mode_blob);
     }
-    active_changed_ = false;
+
+    if (args.clear_active_composition) {
+      active_kms_data.composition.reset();
+    }
+
+    if (args.composition) {
+      active_kms_data.composition = args.composition;
+    }
+
+    if (args.active) {
+      active_kms_data.active_state = *args.active;
+    }
 
     if (crtc->out_fence_ptr_property()) {
-      display_comp->out_fence_ = UniqueFd((int)out_fences[crtc->pipe()]);
+      args.out_fence = UniqueFd((int)out_fence);
     }
   }
 
-  return ret;
+  return 0;
 }
 
-void DrmDisplayCompositor::ClearDisplay() {
-  if (!active_composition_)
-    return;
+auto DrmDisplayCompositor::ExecuteAtomicCommit(AtomicCommitArgs &args) -> int {
+  int err = CommitFrame(args);
 
-  if (DisablePlanes(active_composition_.get()))
-    return;
-
-  active_composition_.reset(nullptr);
-}
-
-int DrmDisplayCompositor::ApplyComposition(
-    std::unique_ptr<DrmDisplayComposition> composition) {
-  int ret = CommitFrame(composition.get(), false);
-
-  if (ret) {
-    ALOGE("Composite failed for display %d", display_);
-    // Disable the hw used by the last active composition. This allows us to
-    // signal the release fences from that composition to avoid hanging.
-    ClearDisplay();
-    return ret;
+  if (!args.test_only) {
+    if (err) {
+      ALOGE("Composite failed for display %d", display_);
+      // Disable the hw used by the last active composition. This allows us to
+      // signal the release fences from that composition to avoid hanging.
+      AtomicCommitArgs cl_args = {.clear_active_composition = true};
+      if (CommitFrame(cl_args)) {
+        ALOGE("Failed to clean-up active composition for display %d", display_);
+      }
+      return err;
+    }
   }
 
-  if (composition) {
-    active_composition_.swap(composition);
-  }
-
-  return ret;
-}
-
-int DrmDisplayCompositor::TestComposition(DrmDisplayComposition *composition) {
-  return CommitFrame(composition, true);
-}
-
-auto DrmDisplayCompositor::SetDisplayMode(const DrmMode &display_mode) -> bool {
-  mode_.mode = display_mode;
-  mode_.blob = mode_.mode.CreateModeBlob(*resource_manager_->GetDrmDevice(display_));
-  return !!mode_.blob;
-}
+  return err;
+}  // namespace android
 
 }  // namespace android