Upgrade drm_hwcomposer to f638348b22e96e208badb71de52a860d201ee2fb

This project was upgraded with external_updater.
Usage: tools/external_updater/updater.sh update external/drm_hwcomposer
For more info, check https://cs.android.com/android/platform/superproject/main/+/main:tools/external_updater/README.md

Bug: 383346402
Test: TreeHugger
Change-Id: If01d83a02be030c21e820b05782d6c19059668c2
diff --git a/METADATA b/METADATA
index 2d137a9..24845b6 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@
   last_upgrade_date {
     year: 2025
     month: 3
-    day: 13
+    day: 14
   }
   identifier {
     type: "Git"
     value: "https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer"
-    version: "7009cc1909804ef707376441b5b3f986b492d66a"
+    version: "f638348b22e96e208badb71de52a860d201ee2fb"
   }
 }
diff --git a/backend/Backend.cpp b/backend/Backend.cpp
index 650e29e..12a5fea 100644
--- a/backend/Backend.cpp
+++ b/backend/Backend.cpp
@@ -20,9 +20,20 @@
 
 #include "BackendManager.h"
 #include "bufferinfo/BufferInfoGetter.h"
+#include "hardware/hwcomposer2.h"
 
 namespace android {
 
+namespace {
+
+bool HasCursorLayer(const std::vector<HwcLayer *> &layers) {
+  return std::find_if(layers.begin(), layers.end(), [&](auto *layer) -> bool {
+           return layer->GetSfType() == HWC2::Composition::Cursor;
+         }) != layers.end();
+}
+
+}  // namespace
+
 HWC2::Error Backend::ValidateDisplay(HwcDisplay *display, uint32_t *num_types,
                                      uint32_t *num_requests) {
   *num_types = 0;
@@ -62,7 +73,27 @@
     ++display->total_stats().failed_kms_validate_;
     client_start = 0;
     client_size = layers.size();
-    MarkValidated(layers, 0, client_size);
+
+    // Expand the client range to include all layers except the cursor layer (if
+    // there is one) and retry.
+    auto [_, cursor_plane] = display->GetPipe().GetUsablePlanes();
+    if (cursor_plane && HasCursorLayer(layers)) {
+      --client_size;
+      MarkValidated(layers, 0, client_size);
+
+      testing_needed = display->CreateComposition(a_args) != HWC2::Error::None;
+
+      // If testing is still needed, expand the client range to include the
+      // cursor layer for the next retry.
+      if (testing_needed) {
+        ++client_size;
+        ++display->total_stats().failed_kms_validate_;
+      }
+    }
+
+    if (testing_needed) {
+      MarkValidated(layers, 0, client_size);
+    }
   }
 
   *num_types = client_size;
@@ -120,10 +151,13 @@
 void Backend::MarkValidated(std::vector<HwcLayer *> &layers,
                             size_t client_first_z, size_t client_size) {
   for (size_t z_order = 0; z_order < layers.size(); ++z_order) {
-    if (z_order >= client_first_z && z_order < client_first_z + client_size)
+    if (z_order >= client_first_z && z_order < client_first_z + client_size) {
       layers[z_order]->SetValidatedType(HWC2::Composition::Client);
-    else
+    } else if (layers[z_order]->GetSfType() == HWC2::Composition::Cursor) {
+      layers[z_order]->SetValidatedType(HWC2::Composition::Cursor);
+    } else {
       layers[z_order]->SetValidatedType(HWC2::Composition::Device);
+    }
   }
 }
 
@@ -132,31 +166,39 @@
     int client_start, size_t client_size) {
   auto [planes, cursor_plane] = display->GetPipe().GetUsablePlanes();
   size_t avail_planes = planes.size();
+  size_t layers_size = layers.size();
+
+  // |cursor_plane| is not counted among |avail_planes|, so the cursor layer
+  // shouldn't be counted in |layers_size|.
+  if (cursor_plane && HasCursorLayer(layers)) {
+    --layers_size;
+  }
 
   /*
-   * If more layers then planes, save one plane
+   * If more layers than planes, save one plane
    * for client composited layers
    */
-  if (avail_planes < display->layers().size())
+  if (avail_planes < layers_size) {
     avail_planes--;
+  }
 
-  const int extra_client = int(layers.size() - client_size) - int(avail_planes);
+  const int extra_client = int(layers_size - client_size) - int(avail_planes);
 
   if (extra_client > 0) {
     int start = 0;
     size_t steps = 0;
     if (client_size != 0) {
       const int prepend = std::min(client_start, extra_client);
-      const int append = std::min(int(layers.size()) -
+      const int append = std::min(int(layers_size) -
                                       int(client_start + client_size),
                                   extra_client);
       start = client_start - (int)prepend;
       client_size += extra_client;
       steps = 1 + std::min(std::min(append, prepend),
-                           int(layers.size()) - int(start + client_size));
+                           int(layers_size) - int(start + client_size));
     } else {
       client_size = extra_client;
-      steps = 1 + layers.size() - extra_client;
+      steps = 1 + layers_size - extra_client;
     }
 
     uint32_t gpu_pixops = UINT32_MAX;
diff --git a/bufferinfo/BufferInfoMapperMetadata.cpp b/bufferinfo/BufferInfoMapperMetadata.cpp
index dc1b906..125c5c8 100644
--- a/bufferinfo/BufferInfoMapperMetadata.cpp
+++ b/bufferinfo/BufferInfoMapperMetadata.cpp
@@ -31,6 +31,23 @@
 
 namespace android {
 
+namespace {
+
+std::optional<std::pair<uint32_t, uint32_t>> GetAlignedDimensions(
+    const ui::PlaneLayout &layout) {
+  if (layout.sampleIncrementInBits == 0 || layout.strideInBytes == 0) {
+    ALOGW("Invalid plane layout");
+    return std::nullopt;
+  }
+
+  constexpr uint32_t kBitsPerByte = 8;
+  return std::pair{layout.strideInBytes * kBitsPerByte /
+                       layout.sampleIncrementInBits,
+                   layout.totalSizeInBytes / layout.strideInBytes};
+}
+
+}  // namespace
+
 BufferInfoGetter *BufferInfoMapperMetadata::CreateInstance() {
   if (GraphicBufferMapper::getInstance().getMapperVersion() <
       GraphicBufferMapper::GRALLOC_4)
@@ -136,6 +153,25 @@
     bi.sizes[i] = layouts[i].totalSizeInBytes;
   }
 
+  uint64_t usage = 0;
+  err = mapper.getUsage(handle, &usage);
+  if (err != 0) {
+    ALOGE("Failed to get Usage err=%d", err);
+    return {};
+  }
+
+  if ((usage & GRALLOC_USAGE_CURSOR) != 0) {
+    if (layouts.size() > 1) {
+      ALOGW("Multiplanar format buffer alignment not supported");
+    } else {
+      auto aligned = GetAlignedDimensions(layouts[0]);
+      if (aligned.has_value()) {
+        bi.width = aligned->first;
+        bi.height = aligned->second;
+      }
+    }
+  }
+
   err = GetFds(handle, &bi);
   if (err != 0) {
     ALOGE("Failed to get fds (err=%d)", err);
diff --git a/compositor/DrmKmsPlan.cpp b/compositor/DrmKmsPlan.cpp
index 443b515..1155697 100644
--- a/compositor/DrmKmsPlan.cpp
+++ b/compositor/DrmKmsPlan.cpp
@@ -23,17 +23,30 @@
 #include "utils/log.h"
 
 namespace android {
-auto DrmKmsPlan::CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
-                                  std::vector<LayerData> composition)
-    -> std::unique_ptr<DrmKmsPlan> {
+auto DrmKmsPlan::CreateDrmKmsPlan(
+    DrmDisplayPipeline &pipe, std::vector<LayerData> composition,
+    std::optional<LayerData> cursor_layer) -> std::unique_ptr<DrmKmsPlan> {
   auto plan = std::make_unique<DrmKmsPlan>();
 
   auto [avail_planes, cursor_plane] = pipe.GetUsablePlanes();
 
   int z_pos = 0;
+  if (cursor_layer.has_value()) {
+    if (cursor_plane &&
+        cursor_plane->Get()->IsValidForLayer(&cursor_layer.value())) {
+      plan->plan.emplace_back(
+          LayerToPlaneJoining{.layer = std::move(cursor_layer.value()),
+                              .plane = cursor_plane,
+                              .z_pos = z_pos++});
+    } else {
+      // Cursor layer can't use cursor plane, so let it match normally with
+      // others.
+      composition.push_back(std::move(cursor_layer.value()));
+    }
+  }
+
   for (auto &dhl : composition) {
     std::shared_ptr<BindingOwner<DrmPlane>> plane;
-
     /* Skip unsupported planes */
     do {
       if (avail_planes.empty()) {
diff --git a/compositor/DrmKmsPlan.h b/compositor/DrmKmsPlan.h
index 054cd93..d0b271a 100644
--- a/compositor/DrmKmsPlan.h
+++ b/compositor/DrmKmsPlan.h
@@ -35,8 +35,9 @@
   std::vector<LayerToPlaneJoining> plan;
 
   static auto CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
-                               std::vector<LayerData> composition)
-      -> std::unique_ptr<DrmKmsPlan>;
+                               std::vector<LayerData> composition,
+                               std::optional<LayerData> cursor_layer =
+                                   std::nullopt) -> std::unique_ptr<DrmKmsPlan>;
 };
 
 }  // namespace android
diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp
index 0fe060d..2251a78 100644
--- a/drm/DrmPlane.cpp
+++ b/drm/DrmPlane.cpp
@@ -284,6 +284,13 @@
   auto disp = opt_disp.value();
   auto src = opt_src.value();
 
+  if (type_ == DRM_PLANE_TYPE_CURSOR) {
+    disp.right = disp.left + static_cast<int>(layer.bi->width);
+    disp.bottom = disp.top + static_cast<int>(layer.bi->height);
+    src = {0, 0, static_cast<float>(layer.bi->width),
+           static_cast<float>(layer.bi->height)};
+  }
+
   if (!crtc_property_.AtomicSet(pset, crtc_id) ||
       !fb_property_.AtomicSet(pset, layer.fb->GetFbId()) ||
       !crtc_x_property_.AtomicSet(pset, disp.left) ||
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index 7ec1c28..4b08515 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -84,6 +84,11 @@
   return last_timestamp_is_fresh_ ? last_timestamp_.value_or(0) : 0;
 }
 
+int64_t VSyncWorker::GetNextVsyncTimestamp(int64_t time) {
+  const std::lock_guard<std::mutex> lock(mutex_);
+  return GetPhasedVSync(vsync_period_ns_, time);
+}
+
 void VSyncWorker::SetTimestampCallback(
     std::optional<VsyncTimestampCallback> &&callback) {
   {
diff --git a/drm/VSyncWorker.h b/drm/VSyncWorker.h
index 8e410f4..e8ed24b 100644
--- a/drm/VSyncWorker.h
+++ b/drm/VSyncWorker.h
@@ -50,6 +50,10 @@
   void SetVsyncTimestampTracking(bool enabled);
   uint32_t GetLastVsyncTimestamp();
 
+  // Get the next predicted vsync timestamp after |time|, based on the last
+  // recorded vsync timestamp and the current vsync period.
+  int64_t GetNextVsyncTimestamp(int64_t time);
+
   void StopThread();
 
  private:
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 15a4c6e..c97c640 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -375,8 +375,8 @@
 }
 
 auto HwcDisplay::PresentStagedComposition(
-    SharedFd &out_present_fence, std::vector<ReleaseFence> &out_release_fences)
-    -> bool {
+    std::optional<int64_t> desired_present_time, SharedFd &out_present_fence,
+    std::vector<ReleaseFence> &out_release_fences) -> bool {
   if (IsInHeadlessMode()) {
     return true;
   }
@@ -384,6 +384,17 @@
 
   ++total_stats_.total_frames_;
 
+  uint32_t vperiod_ns = 0;
+  GetDisplayVsyncPeriod(&vperiod_ns);
+
+  if (desired_present_time && vperiod_ns != 0) {
+    // DRM atomic uAPI does not support specifying that a commit should be
+    // applied to some future vsync. Until such uAPI is available, sleep in
+    // userspace until the next expected vsync time is consistent with the
+    // desired present time.
+    WaitForPresentTime(desired_present_time.value(), vperiod_ns);
+  }
+
   AtomicCommitArgs a_args{};
   ret = CreateComposition(a_args);
 
@@ -745,6 +756,39 @@
   return args;
 }
 
+void HwcDisplay::WaitForPresentTime(int64_t present_time,
+                                    uint32_t vsync_period_ns) {
+  const int64_t current_time = ResourceManager::GetTimeMonotonicNs();
+  int64_t next_vsync_time = vsync_worker_->GetNextVsyncTimestamp(current_time);
+
+  int64_t vsync_after_present_time = vsync_worker_->GetNextVsyncTimestamp(
+      present_time);
+  int64_t vsync_before_present_time = vsync_after_present_time -
+                                      vsync_period_ns;
+
+  // Check if |present_time| is closer to the expected vsync before or after.
+  int64_t desired_vsync = (vsync_after_present_time - present_time) <
+                                  (present_time - vsync_before_present_time)
+                              ? vsync_after_present_time
+                              : vsync_before_present_time;
+
+  // Don't sleep if desired_vsync is before or nearly equal to vsync_period of
+  // the next expected vsync.
+  const int64_t quarter_vsync_period = vsync_period_ns / 4;
+  if ((desired_vsync - next_vsync_time) < quarter_vsync_period) {
+    return;
+  }
+
+  // Sleep until 75% vsync_period before the desired_vsync.
+  int64_t sleep_until = desired_vsync - (quarter_vsync_period * 3);
+  struct timespec sleep_until_ts{};
+  constexpr int64_t kOneSecondNs = 1LL * 1000 * 1000 * 1000;
+  sleep_until_ts.tv_sec = int(sleep_until / kOneSecondNs);
+  sleep_until_ts.tv_nsec = int(sleep_until -
+                               (sleep_until_ts.tv_sec * kOneSecondNs));
+  clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &sleep_until_ts, nullptr);
+}
+
 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
 HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
   if (IsInHeadlessMode()) {
@@ -781,11 +825,21 @@
   bool use_client_layer = false;
   uint32_t client_z_order = UINT32_MAX;
   std::map<uint32_t, HwcLayer *> z_map;
+  std::optional<LayerData> cursor_layer = std::nullopt;
   for (auto &[_, layer] : layers_) {
     switch (layer.GetValidatedType()) {
       case HWC2::Composition::Device:
         z_map.emplace(layer.GetZOrder(), &layer);
         break;
+      case HWC2::Composition::Cursor:
+        if (!cursor_layer.has_value()) {
+          layer.PopulateLayerData();
+          cursor_layer = layer.GetLayerData();
+        } else {
+          ALOGW("Detected multiple cursor layers");
+          z_map.emplace(layer.GetZOrder(), &layer);
+        }
+        break;
       case HWC2::Composition::Client:
         // Place it at the z_order of the lowest client layer
         use_client_layer = true;
@@ -835,7 +889,8 @@
    * in between of ValidateDisplay() and PresentDisplay() calls
    */
   current_plan_ = DrmKmsPlan::CreateDrmKmsPlan(GetPipe(),
-                                               std::move(composition_layers));
+                                               std::move(composition_layers),
+                                               cursor_layer);
 
   if (type_ == HWC2::DisplayType::Virtual) {
     writeback_layer_->PopulateLayerData();
@@ -1064,6 +1119,12 @@
 
   std::sort(std::begin(ordered_layers), std::end(ordered_layers),
             [](const HwcLayer *lhs, const HwcLayer *rhs) {
+              // Cursor layers should always have highest zpos.
+              if ((lhs->GetSfType() == HWC2::Composition::Cursor) !=
+                  (rhs->GetSfType() == HWC2::Composition::Cursor)) {
+                return rhs->GetSfType() == HWC2::Composition::Cursor;
+              }
+
               return lhs->GetZOrder() < rhs->GetZOrder();
             });
 
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index b8c52fe..c645400 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -98,7 +98,7 @@
   auto GetConfig(hwc2_config_t config_id) const -> const HwcDisplayConfig *;
 
   auto GetDisplayBoundsMm() -> std::pair<int32_t, int32_t>;
-  
+
   // To be called after SetDisplayProperties. Returns an empty vector if the
   // requested layers have been validated, otherwise the vector describes
   // the requested composition type changes.
@@ -108,11 +108,14 @@
   // Mark previously validated properties as ready to present.
   auto AcceptValidatedComposition() -> void;
 
+  using ReleaseFence = std::pair<ILayerId, SharedFd>;
   // Present previously staged properties, and return fences to indicate when
   // the new content has been presented, and when the previous buffers have
-  // been released.
-  using ReleaseFence = std::pair<ILayerId, SharedFd>;
-  auto PresentStagedComposition(SharedFd &out_present_fence,
+  // been released. If |desired_present_time| is set, ensure that the
+  // composition is presented at the closest vsync to that requested time.
+  // Otherwise, present immediately.
+  auto PresentStagedComposition(std::optional<int64_t> desired_present_time,
+                                SharedFd &out_present_fence,
                                 std::vector<ReleaseFence> &out_release_fences)
       -> bool;
 
@@ -255,6 +258,10 @@
       const HwcDisplayConfig *config,
       const std::optional<LayerData> &modeset_layer);
 
+  // Sleep the current thread until |present_time| is closest to the next
+  // expected vsync time.
+  void WaitForPresentTime(int64_t present_time, uint32_t vsync_period_ns);
+
   HwcDisplayConfigs configs_;
 
   DrmHwc *const hwc_;
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
index c1c5157..7c9d806 100644
--- a/hwc2_device/hwc2_device.cpp
+++ b/hwc2_device/hwc2_device.cpp
@@ -501,7 +501,7 @@
 
   hwc2display->release_fences.clear();
 
-  if (!idisplay->PresentStagedComposition(out_fence,
+  if (!idisplay->PresentStagedComposition(std::nullopt, out_fence,
                                           hwc2display->release_fences)) {
     ALOGE("Failed to present display");
     return static_cast<int32_t>(HWC2::Error::BadDisplay);
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
index c7ec522..ecb2dca 100644
--- a/hwc3/ComposerClient.cpp
+++ b/hwc3/ComposerClient.cpp
@@ -154,6 +154,14 @@
   return AidlToSampleRange(dataspace->dataspace);
 }
 
+std::optional<int64_t> AidlToPresentTimeNs(
+    const std::optional<ClockMonotonicTimestamp>& expected_present_time) {
+  if (!expected_present_time || expected_present_time->timestampNanos == 0) {
+    return std::nullopt;
+  }
+  return expected_present_time->timestampNanos;
+}
+
 bool IsSupportedCompositionType(
     const std::optional<ParcelableComposition> composition) {
   if (!composition) {
@@ -731,6 +739,8 @@
     cmd_result_writer_->AddChanges(changes);
     auto hwc3_display = DrmHwcThree::GetHwc3Display(*display);
     hwc3_display->must_validate = false;
+    hwc3_display->desired_present_time = AidlToPresentTimeNs(
+        command.expectedPresentTime);
 
     // TODO: DisplayRequests are not implemented.
   }
@@ -755,9 +765,12 @@
       cmd_result_writer_->AddError(hwc3::Error::kNotValidated);
       return;
     }
+
     ::android::SharedFd present_fence;
     std::vector<HwcDisplay::ReleaseFence> release_fences;
-    bool ret = display->PresentStagedComposition(present_fence, release_fences);
+    bool ret = display->PresentStagedComposition(hwc3_display
+                                                     ->desired_present_time,
+                                                 present_fence, release_fences);
 
     if (!ret) {
       cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
diff --git a/hwc3/DrmHwcThree.h b/hwc3/DrmHwcThree.h
index 10470ea..89bcf46 100644
--- a/hwc3/DrmHwcThree.h
+++ b/hwc3/DrmHwcThree.h
@@ -26,6 +26,9 @@
 class Hwc3Display : public ::android::FrontendDisplayBase {
  public:
   bool must_validate = false;
+  // Desired present time for a composition that has been validated but not
+  // yet presented. nullopt means it should be presented at the next vsync.
+  std::optional<int64_t> desired_present_time = std::nullopt;
 
   int64_t next_layer_id = 1;
 };