OSDN Git Service

drm_hwcomposer: Modify source_layers_ to be integer instead of array
[android-x86/external-drm_hwcomposer.git] / compositor / DrmDisplayCompositor.cpp
index 5b16cad..6b8a92b 100644 (file)
 
 namespace android {
 
-DrmDisplayCompositor::DrmDisplayCompositor()
-    : resource_manager_(nullptr),
-      display_(-1),
-      initialized_(false),
-      active_(false),
-      use_hw_overlays_(true),
-      dump_frames_composited_(0),
-      dump_last_timestamp_ns_(0) {
-  struct timespec ts {};
-  if (clock_gettime(CLOCK_MONOTONIC, &ts))
-    return;
-  dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
-}
-
-DrmDisplayCompositor::~DrmDisplayCompositor() {
-  if (!initialized_)
-    return;
-  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  if (mode_.blob_id)
-    drm->DestroyPropertyBlob(mode_.blob_id);
-  if (mode_.old_blob_id)
-    drm->DestroyPropertyBlob(mode_.old_blob_id);
-
-  active_composition_.reset();
-}
-
 auto DrmDisplayCompositor::Init(ResourceManager *resource_manager, int display)
     -> int {
   resource_manager_ = resource_manager;
@@ -93,56 +67,33 @@ DrmDisplayCompositor::CreateInitializedComposition() const {
   return std::make_unique<DrmDisplayComposition>(crtc, planner_.get());
 }
 
-std::tuple<uint32_t, uint32_t, int>
-DrmDisplayCompositor::GetActiveModeResolution() {
-  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  DrmConnector *connector = drm->GetConnectorForDisplay(display_);
-  if (connector == nullptr) {
-    ALOGE("Failed to determine display mode: no connector for display %d",
-          display_);
-    return std::make_tuple(0, 0, -ENODEV);
-  }
-
-  const DrmMode &mode = connector->active_mode();
-  return std::make_tuple(mode.h_display(), mode.v_display(), 0);
-}
+// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
+auto DrmDisplayCompositor::CommitFrame(AtomicCommitArgs &args) -> int {
+  ATRACE_CALL();
 
-int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) {
-  auto pset = MakeDrmModeAtomicReqUnique();
-  if (!pset) {
-    ALOGE("Failed to allocate property set");
-    return -ENOMEM;
+  if (args.active && *args.active == active_frame_state.crtc_active_state) {
+    /* Don't set the same state twice */
+    args.active.reset();
   }
 
-  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;
+  if (!args.HasInputs()) {
+    /* nothing to do */
+    return 0;
   }
 
-  return 0;
-}
+  if (!active_frame_state.crtc_active_state) {
+    /* Force activate display */
+    args.active = true;
+  }
 
-int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
-                                      bool test_only) {
-  ATRACE_CALL();
+  if (args.clear_active_composition && args.composition) {
+    ALOGE("%s: Invalid arguments", __func__);
+    return -EINVAL;
+  }
 
-  int ret = 0;
+  auto new_frame_state = NewFrameState();
 
-  std::vector<DrmHwcLayer> &layers = display_comp->layers();
-  std::vector<DrmCompositionPlane> &comp_planes = display_comp
-                                                      ->composition_planes();
   DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  uint64_t out_fences[drm->crtcs().size()];
 
   DrmConnector *connector = drm->GetConnectorForDisplay(display_);
   if (!connector) {
@@ -161,221 +112,126 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
     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_.needs_modeset &&
-      (!crtc->active_property().AtomicSet(*pset, 1) ||
-       !crtc->mode_property().AtomicSet(*pset, mode_.blob_id) ||
-       !connector->crtc_id_property().AtomicSet(*pset, crtc->id()))) {
-    return -EINVAL;
+  if (args.active) {
+    new_frame_state.crtc_active_state = *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 (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 (args.display_mode) {
+    new_frame_state.mode_blob = args.display_mode.value().CreateModeBlob(
+        *resource_manager_->GetDrmDevice(display_));
 
-      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 (!new_frame_state.mode_blob) {
+      ALOGE("Failed to create mode_blob");
+      return -EINVAL;
+    }
 
-      if (plane->AtomicSetState(*pset, layer, source_layers.front(),
-                                crtc->id()) != 0) {
-        return -EINVAL;
-      }
-    } else {
-      if (plane->AtomicDisablePlane(*pset) != 0) {
-        return -EINVAL;
-      }
+    if (!crtc->mode_property().AtomicSet(*pset, *new_frame_state.mode_blob)) {
+      return -EINVAL;
     }
   }
 
-  if (!ret) {
-    uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
-    if (test_only)
-      flags |= DRM_MODE_ATOMIC_TEST_ONLY;
+  auto unused_planes = new_frame_state.used_planes;
 
-    ret = drmModeAtomicCommit(drm->fd(), pset.get(), flags, drm);
-    if (ret) {
-      if (!test_only)
-        ALOGE("Failed to commit pset ret=%d\n", ret);
-      return ret;
-    }
-  }
+  if (args.composition) {
+    new_frame_state.used_framebuffers.clear();
+    new_frame_state.used_planes.clear();
 
-  if (!test_only && mode_.needs_modeset) {
-    ret = drm->DestroyPropertyBlob(mode_.old_blob_id);
-    if (ret) {
-      ALOGE("Failed to destroy old mode property blob %" PRIu32 "/%d",
-            mode_.old_blob_id, ret);
-      return ret;
-    }
+    std::vector<DrmHwcLayer> &layers = args.composition->layers();
+    std::vector<DrmCompositionPlane> &comp_planes = args.composition
+                                                        ->composition_planes();
 
-    /* TODO: Add dpms to the pset when the kernel supports it */
-    ret = ApplyDpms(display_comp);
-    if (ret) {
-      ALOGE("Failed to apply DPMS after modeset %d\n", ret);
-      return ret;
-    }
+    for (DrmCompositionPlane &comp_plane : comp_planes) {
+      DrmPlane *plane = comp_plane.plane();
+      size_t source_layer = comp_plane.source_layer();
 
-    connector->set_active_mode(mode_.mode);
-    mode_.old_blob_id = mode_.blob_id;
-    mode_.blob_id = 0;
-    mode_.needs_modeset = false;
-  }
+      if (source_layer >= layers.size()) {
+        ALOGE("Source layer index %zu out of bounds %zu", source_layer,
+              layers.size());
+        return -EINVAL;
+      }
+      DrmHwcLayer &layer = layers[source_layer];
 
-  if (crtc->out_fence_ptr_property()) {
-    display_comp->out_fence_ = UniqueFd((int)out_fences[crtc->pipe()]);
-  }
+      new_frame_state.used_framebuffers.emplace_back(layer.FbIdHandle);
+      new_frame_state.used_planes.emplace_back(plane);
 
-  return ret;
-}
+      /* Remove from 'unused' list, since plane is re-used */
+      auto &v = unused_planes;
+      v.erase(std::remove(v.begin(), v.end(), plane), v.end());
 
-int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
-  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  DrmConnector *conn = drm->GetConnectorForDisplay(display_);
-  if (!conn) {
-    ALOGE("Failed to get DrmConnector for display %d", display_);
-    return -ENODEV;
+      if (plane->AtomicSetState(*pset, layer, source_layer, crtc->id()) != 0) {
+        return -EINVAL;
+      }
+    }
   }
 
-  const DrmProperty &prop = conn->dpms_property();
-  int ret = drmModeConnectorSetProperty(drm->fd(), conn->id(), prop.id(),
-                                        display_comp->dpms_mode());
-  if (ret) {
-    ALOGE("Failed to set DPMS property for connector %d", conn->id());
-    return ret;
+  if (args.clear_active_composition) {
+    new_frame_state.used_framebuffers.clear();
+    new_frame_state.used_planes.clear();
   }
-  return 0;
-}
 
-std::tuple<int, uint32_t> DrmDisplayCompositor::CreateModeBlob(
-    const DrmMode &mode) {
-  struct drm_mode_modeinfo drm_mode {};
-  mode.ToDrmModeModeInfo(&drm_mode);
-
-  uint32_t id = 0;
-  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  int ret = drm->CreatePropertyBlob(&drm_mode, sizeof(struct drm_mode_modeinfo),
-                                    &id);
-  if (ret) {
-    ALOGE("Failed to create mode property blob %d", ret);
-    return std::make_tuple(ret, 0);
+  if (args.clear_active_composition || args.composition) {
+    for (auto *plane : unused_planes) {
+      if (plane->AtomicDisablePlane(*pset) != 0) {
+        return -EINVAL;
+      }
+    }
   }
-  ALOGE("Create blob_id %" PRIu32 "\n", id);
-  return std::make_tuple(ret, id);
-}
 
-void DrmDisplayCompositor::ClearDisplay() {
-  if (!active_composition_)
-    return;
+  uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+  if (args.test_only)
+    flags |= DRM_MODE_ATOMIC_TEST_ONLY;
 
-  if (DisablePlanes(active_composition_.get()))
-    return;
-
-  active_composition_.reset(nullptr);
-}
-
-void DrmDisplayCompositor::ApplyFrame(
-    std::unique_ptr<DrmDisplayComposition> composition, int status) {
-  int ret = status;
-
-  if (!ret) {
-    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;
+  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;
   }
-  ++dump_frames_composited_;
 
-  active_composition_.swap(composition);
-}
+  if (!args.test_only) {
+    if (args.display_mode) {
+      /* TODO(nobody): we still need this for synthetic vsync, remove after
+       * vsync reworked */
+      connector->set_active_mode(*args.display_mode);
+    }
 
-int DrmDisplayCompositor::ApplyComposition(
-    std::unique_ptr<DrmDisplayComposition> composition) {
-  int ret = 0;
-  switch (composition->type()) {
-    case DRM_COMPOSITION_TYPE_FRAME:
-      if (composition->geometry_changed()) {
-        // Send the composition to the kernel to ensure we can commit it. This
-        // is just a test, it won't actually commit the frame.
-        ret = CommitFrame(composition.get(), true);
-        if (ret) {
-          ALOGE("Commit test failed for display %d, FIXME", display_);
-          return ret;
-        }
-      }
+    active_frame_state = std::move(new_frame_state);
 
-      ApplyFrame(std::move(composition), ret);
-      break;
-    case DRM_COMPOSITION_TYPE_DPMS:
-      active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
-      ret = ApplyDpms(composition.get());
-      if (ret)
-        ALOGE("Failed to apply dpms for display %d", display_);
-      return ret;
-    case DRM_COMPOSITION_TYPE_MODESET:
-      mode_.mode = composition->display_mode();
-      if (mode_.blob_id)
-        resource_manager_->GetDrmDevice(display_)->DestroyPropertyBlob(
-            mode_.blob_id);
-      std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode);
-      if (ret) {
-        ALOGE("Failed to create mode blob for display %d", display_);
-        return ret;
-      }
-      mode_.needs_modeset = true;
-      return 0;
-    default:
-      ALOGE("Unknown composition type %d", composition->type());
-      return -EINVAL;
+    if (crtc->out_fence_ptr_property()) {
+      args.out_fence = UniqueFd((int)out_fence);
+    }
   }
 
-  return ret;
-}
-
-int DrmDisplayCompositor::TestComposition(DrmDisplayComposition *composition) {
-  return CommitFrame(composition, true);
+  return 0;
 }
 
-void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
-  uint64_t num_frames = dump_frames_composited_;
-  dump_frames_composited_ = 0;
-
-  struct timespec ts {};
-  int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
-  if (ret) {
-    return;
+auto DrmDisplayCompositor::ExecuteAtomicCommit(AtomicCommitArgs &args) -> int {
+  int err = CommitFrame(args);
+
+  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;
+    }
   }
 
-  uint64_t cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
-  uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
-  float fps = num_ms ? static_cast<float>(num_frames) * 1000.0F /
-                           static_cast<float>(num_ms)
-                     : 0.0F;
-
-  *out << "--DrmDisplayCompositor[" << display_
-       << "]: num_frames=" << num_frames << " num_ms=" << num_ms
-       << " fps=" << fps << "\n";
+  return err;
+}  // namespace android
 
-  dump_last_timestamp_ns_ = cur_ts;
-}
 }  // namespace android