drm_hwcomposer: Rework HWC frontends buffer management

Change summary:

- Use BufferInfo instead of native_buffer to configure the HwcLayer.
- Extend buffer properties with slot info.
- Provide fence and active slot ID separate from the buffer.
- Move swapchain tracking into HWC2. HWC3 doesn't need that.

Why:

- Support more flexible resource management control from the frontend
  side,  which is required by HWC3 API.
- Move more Android-specific data types to the frontend module.

Change-Id: Idaa4c552f600f78d6f0ad21997cfa7f3a6c6cbd8
Signed-off-by: Roman Stratiienko <r.stratiienko@gmail.com>
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index da40416..252276f 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -262,7 +262,19 @@
     if (modeset_buffer != nullptr) {
       auto modeset_layer = std::make_unique<HwcLayer>(this);
       HwcLayer::LayerProperties properties;
-      properties.buffer = {.buffer_handle = modeset_buffer};
+      auto bi = BufferInfoGetter::GetInstance()->GetBoInfo(modeset_buffer);
+      if (!bi) {
+        ALOGE("Failed to get buffer info for modeset buffer.");
+        return ConfigError::kBadConfig;
+      }
+      properties.slot_buffer = {
+          .slot_id = 0,
+          .bi = bi,
+      };
+      properties.active_slot = {
+          .slot_id = 0,
+          .fence = {},
+      };
       properties.blend_mode = BufferBlendMode::kNone;
       modeset_layer->SetLayerProperties(properties);
       modeset_layer->PopulateLayerData();
@@ -422,7 +434,7 @@
     vsync_worker_ = {};
   }
 
-  client_layer_.SwChainClearCache();
+  client_layer_.ClearSlots();
 }
 
 HWC2::Error HwcDisplay::Init() {
diff --git a/hwc2_device/HwcLayer.cpp b/hwc2_device/HwcLayer.cpp
index 6940c12..d0ff216 100644
--- a/hwc2_device/HwcLayer.cpp
+++ b/hwc2_device/HwcLayer.cpp
@@ -25,10 +25,21 @@
 namespace android {
 
 void HwcLayer::SetLayerProperties(const LayerProperties& layer_properties) {
-  if (layer_properties.buffer) {
-    layer_data_.acquire_fence = layer_properties.buffer->acquire_fence;
-    buffer_handle_ = layer_properties.buffer->buffer_handle;
-    buffer_handle_updated_ = true;
+  if (layer_properties.slot_buffer) {
+    auto slot_id = layer_properties.slot_buffer->slot_id;
+    if (!layer_properties.slot_buffer->bi) {
+      slots_.erase(slot_id);
+    } else {
+      slots_[slot_id] = {
+          .bi = layer_properties.slot_buffer->bi.value(),
+          .fb = {},
+      };
+    }
+  }
+  if (layer_properties.active_slot) {
+    active_slot_id_ = layer_properties.active_slot->slot_id;
+    layer_data_.acquire_fence = layer_properties.active_slot->fence;
+    buffer_updated_ = true;
   }
   if (layer_properties.blend_mode) {
     blend_mode_ = layer_properties.blend_mode.value();
@@ -60,49 +71,39 @@
 }
 
 void HwcLayer::ImportFb() {
-  if (!IsLayerUsableAsDevice() || !buffer_handle_updated_) {
+  if (!IsLayerUsableAsDevice() || !buffer_updated_ ||
+      !active_slot_id_.has_value()) {
     return;
   }
-  buffer_handle_updated_ = false;
+  buffer_updated_ = false;
 
-  layer_data_.fb = {};
-
-  auto unique_id = BufferInfoGetter::GetInstance()->GetUniqueId(buffer_handle_);
-  if (unique_id && SwChainGetBufferFromCache(*unique_id)) {
+  if (slots_[*active_slot_id_].fb) {
     return;
   }
 
-  layer_data_.bi = BufferInfoGetter::GetInstance()->GetBoInfo(buffer_handle_);
-  if (!layer_data_.bi) {
-    ALOGW("Unable to get buffer information (0x%p)", buffer_handle_);
-    bi_get_failed_ = true;
-    return;
-  }
+  auto& fb_importer = parent_->GetPipe().device->GetDrmFbImporter();
+  auto fb = fb_importer.GetOrCreateFbId(&slots_[*active_slot_id_].bi);
 
-  layer_data_
-      .fb = parent_->GetPipe().device->GetDrmFbImporter().GetOrCreateFbId(
-      &layer_data_.bi.value());
-
-  if (!layer_data_.fb) {
-    ALOGV("Unable to create framebuffer object for buffer 0x%p",
-          buffer_handle_);
+  if (!fb) {
+    ALOGE("Unable to create framebuffer object for layer %p", this);
     fb_import_failed_ = true;
     return;
   }
 
-  if (unique_id) {
-    SwChainAddCurrentBuffer(*unique_id);
-  }
+  slots_[*active_slot_id_].fb = fb;
 }
 
 void HwcLayer::PopulateLayerData() {
   ImportFb();
 
-  if (!layer_data_.bi) {
-    ALOGE("%s: Invalid state", __func__);
+  if (!active_slot_id_.has_value()) {
+    ALOGE("Internal error: populate layer data called without active slot");
     return;
   }
 
+  layer_data_.bi = slots_[*active_slot_id_].bi;
+  layer_data_.fb = slots_[*active_slot_id_].fb;
+
   if (blend_mode_ != BufferBlendMode::kUndefined) {
     layer_data_.bi->blend_mode = blend_mode_;
   }
@@ -114,75 +115,9 @@
   }
 }
 
-/* SwapChain Cache */
-
-bool HwcLayer::SwChainGetBufferFromCache(BufferUniqueId unique_id) {
-  if (swchain_lookup_table_.count(unique_id) == 0) {
-    return false;
-  }
-
-  auto seq = swchain_lookup_table_[unique_id];
-
-  if (swchain_cache_.count(seq) == 0) {
-    return false;
-  }
-
-  auto& el = swchain_cache_[seq];
-  if (!el.bi) {
-    return false;
-  }
-
-  layer_data_.bi = el.bi;
-  layer_data_.fb = el.fb;
-
-  return true;
-}
-
-void HwcLayer::SwChainReassemble(BufferUniqueId unique_id) {
-  if (swchain_lookup_table_.count(unique_id) != 0) {
-    if (swchain_lookup_table_[unique_id] ==
-        int(swchain_lookup_table_.size()) - 1) {
-      /* Skip same buffer */
-      return;
-    }
-    if (swchain_lookup_table_[unique_id] == 0) {
-      swchain_reassembled_ = true;
-      return;
-    }
-    /* Tracking error */
-    SwChainClearCache();
-    return;
-  }
-
-  swchain_lookup_table_[unique_id] = int(swchain_lookup_table_.size());
-}
-
-void HwcLayer::SwChainAddCurrentBuffer(BufferUniqueId unique_id) {
-  if (!swchain_reassembled_) {
-    SwChainReassemble(unique_id);
-  }
-
-  if (swchain_reassembled_) {
-    if (swchain_lookup_table_.count(unique_id) == 0) {
-      SwChainClearCache();
-      return;
-    }
-
-    auto seq = swchain_lookup_table_[unique_id];
-
-    if (swchain_cache_.count(seq) == 0) {
-      swchain_cache_[seq] = {};
-    }
-
-    swchain_cache_[seq].bi = layer_data_.bi;
-    swchain_cache_[seq].fb = layer_data_.fb;
-  }
-}
-
-void HwcLayer::SwChainClearCache() {
-  swchain_cache_.clear();
-  swchain_lookup_table_.clear();
-  swchain_reassembled_ = false;
+void HwcLayer::ClearSlots() {
+  slots_.clear();
+  active_slot_id_.reset();
 }
 
 }  // namespace android
\ No newline at end of file
diff --git a/hwc2_device/HwcLayer.h b/hwc2_device/HwcLayer.h
index d597977..c335d88 100644
--- a/hwc2_device/HwcLayer.h
+++ b/hwc2_device/HwcLayer.h
@@ -18,23 +18,36 @@
 
 #include <aidl/android/hardware/graphics/common/Transform.h>
 #include <hardware/hwcomposer2.h>
+#include <memory>
 
+#include "bufferinfo/BufferInfo.h"
 #include "bufferinfo/BufferInfoGetter.h"
 #include "compositor/LayerData.h"
+#include "utils/fd.h"
 
 namespace android {
 
 class HwcDisplay;
 
+class FrontendLayerBase {
+ public:
+  virtual ~FrontendLayerBase() = default;
+};
+
 class HwcLayer {
  public:
   struct Buffer {
-    buffer_handle_t buffer_handle;
-    SharedFd acquire_fence;
+    int32_t slot_id;
+    std::optional<BufferInfo> bi;
+  };
+  struct Slot {
+    int32_t slot_id;
+    SharedFd fence;
   };
   // A set of properties to be validated.
   struct LayerProperties {
-    std::optional<Buffer> buffer;
+    std::optional<Buffer> slot_buffer;
+    std::optional<Slot> active_slot;
     std::optional<BufferBlendMode> blend_mode;
     std::optional<BufferColorSpace> color_space;
     std::optional<BufferSampleRange> sample_range;
@@ -82,6 +95,14 @@
 
   void SetLayerProperties(const LayerProperties &layer_properties);
 
+  auto GetFrontendPrivateData() -> std::shared_ptr<FrontendLayerBase> {
+    return frontend_private_data_;
+  }
+
+  auto SetFrontendPrivateData(std::shared_ptr<FrontendLayerBase> data) {
+    frontend_private_data_ = std::move(data);
+  }
+
  private:
   // sf_type_ stores the initial type given to us by surfaceflinger,
   // validated_type_ stores the type after running ValidateDisplay
@@ -101,43 +122,32 @@
   BufferColorSpace color_space_{};
   BufferSampleRange sample_range_{};
   BufferBlendMode blend_mode_{};
-  buffer_handle_t buffer_handle_{};
-  bool buffer_handle_updated_{};
+  bool buffer_updated_{};
 
   bool prior_buffer_scanout_flag_{};
 
   HwcDisplay *const parent_;
 
-  /* Layer state */
- public:
-  void PopulateLayerData();
+  std::shared_ptr<FrontendLayerBase> frontend_private_data_;
 
-  bool IsLayerUsableAsDevice() const {
-    return !bi_get_failed_ && !fb_import_failed_ && buffer_handle_ != nullptr;
-  }
-
- private:
-  void ImportFb();
-  bool bi_get_failed_{};
-  bool fb_import_failed_{};
-
-  /* SwapChain Cache */
- public:
-  void SwChainClearCache();
-
- private:
-  struct SwapChainElement {
-    std::optional<BufferInfo> bi;
+  std::optional<int32_t> active_slot_id_;
+  struct BufferSlot {
+    BufferInfo bi;
     std::shared_ptr<DrmFbIdHandle> fb;
   };
+  std::map<int32_t /*slot*/, BufferSlot> slots_;
 
-  bool SwChainGetBufferFromCache(BufferUniqueId unique_id);
-  void SwChainReassemble(BufferUniqueId unique_id);
-  void SwChainAddCurrentBuffer(BufferUniqueId unique_id);
+  void ImportFb();
+  bool fb_import_failed_{};
 
-  std::map<int /*seq_no*/, SwapChainElement> swchain_cache_;
-  std::map<BufferUniqueId, int /*seq_no*/> swchain_lookup_table_;
-  bool swchain_reassembled_{};
+ public:
+  void PopulateLayerData();
+  void ClearSlots();
+
+  bool IsLayerUsableAsDevice() const {
+    return !fb_import_failed_ && active_slot_id_.has_value() &&
+           slots_.count(*active_slot_id_) > 0;
+  }
 };
 
 }  // namespace android
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
index ac25cf6..10e1608 100644
--- a/hwc2_device/hwc2_device.cpp
+++ b/hwc2_device/hwc2_device.cpp
@@ -19,10 +19,16 @@
 
 #define LOG_TAG "drmhwc"
 
+#include <cassert>
 #include <cinttypes>
+#include <memory>
+#include <optional>
+
+#include <cutils/native_handle.h>
 
 #include "DrmHwcTwo.h"
 #include "backend/Backend.h"
+#include "hwc2_device/HwcLayer.h"
 #include "utils/log.h"
 
 namespace android {
@@ -43,6 +49,110 @@
   return str.substr(p1, p2 - p1);
 }
 
+class Hwc2DeviceLayer : public FrontendLayerBase {
+ public:
+  auto HandleNextBuffer(buffer_handle_t buffer_handle, int32_t fence_fd)
+      -> std::pair<std::optional<HwcLayer::LayerProperties>,
+                   bool /* not a swapchain */> {
+    auto slot = GetSlotNumber(buffer_handle);
+
+    if (invalid_) {
+      return std::make_pair(std::nullopt, true);
+    }
+
+    bool buffer_provided = false;
+    bool not_a_swapchain = true;
+    int32_t slot_id = 0;
+
+    if (slot.has_value()) {
+      buffer_provided = swchain_slots_[slot.value()];
+      slot_id = slot.value();
+      not_a_swapchain = true;
+    }
+
+    HwcLayer::LayerProperties lp;
+    if (!buffer_provided) {
+      auto bo_info = BufferInfoGetter::GetInstance()->GetBoInfo(buffer_handle);
+      if (!bo_info) {
+        invalid_ = true;
+        return std::make_pair(std::nullopt, true);
+      }
+
+      lp.slot_buffer = {
+          .slot_id = slot_id,
+          .bi = bo_info,
+      };
+    }
+    lp.active_slot = {
+        .slot_id = slot_id,
+        .fence = MakeSharedFd(fence_fd),
+    };
+
+    return std::make_pair(lp, not_a_swapchain);
+  }
+
+  void SwChainClearCache() {
+    swchain_lookup_table_.clear();
+    swchain_slots_.clear();
+    swchain_reassembled_ = false;
+  }
+
+ private:
+  auto GetSlotNumber(buffer_handle_t buffer_handle) -> std::optional<int32_t> {
+    auto unique_id = BufferInfoGetter::GetInstance()->GetUniqueId(
+        buffer_handle);
+    if (!unique_id) {
+      ALOGE("Failed to get unique id for buffer handle %p", buffer_handle);
+      return std::nullopt;
+    }
+
+    if (swchain_lookup_table_.count(*unique_id) == 0) {
+      SwChainReassemble(*unique_id);
+      return std::nullopt;
+    }
+
+    if (!swchain_reassembled_) {
+      return std::nullopt;
+    }
+
+    return swchain_lookup_table_[*unique_id];
+  }
+
+  void SwChainReassemble(BufferUniqueId unique_id) {
+    if (swchain_lookup_table_.count(unique_id) != 0) {
+      if (swchain_lookup_table_[unique_id] ==
+          int(swchain_lookup_table_.size()) - 1) {
+        /* Skip same buffer */
+        return;
+      }
+      if (swchain_lookup_table_[unique_id] == 0) {
+        swchain_reassembled_ = true;
+        return;
+      }
+      /* Tracking error */
+      SwChainClearCache();
+      return;
+    }
+
+    swchain_lookup_table_[unique_id] = int(swchain_lookup_table_.size());
+  }
+
+  bool invalid_{}; /* Layer is invalid and should be skipped */
+  std::map<BufferUniqueId, int /*slot*/> swchain_lookup_table_;
+  std::map<int /*slot*/, bool /*buffer_provided*/> swchain_slots_;
+  bool swchain_reassembled_{};
+};
+
+static auto GetHwc2DeviceLayer(HwcLayer &layer)
+    -> std::shared_ptr<Hwc2DeviceLayer> {
+  auto frontend_private_data = layer.GetFrontendPrivateData();
+  if (!frontend_private_data) {
+    frontend_private_data = std::make_shared<Hwc2DeviceLayer>();
+    layer.SetFrontendPrivateData(frontend_private_data);
+  }
+  return std::static_pointer_cast<Hwc2DeviceLayer>(frontend_private_data);
+}
+
 struct Drmhwc2Device : hwc2_device {
   DrmHwcTwo drmhwctwo;
 };
@@ -149,20 +259,33 @@
   LOCK_COMPOSER(device);
   GET_DISPLAY(display);
 
+  auto &client_layer = idisplay->GetClientLayer();
+  auto h2l = GetHwc2DeviceLayer(client_layer);
+  if (!h2l) {
+    client_layer.SetFrontendPrivateData(std::make_shared<Hwc2DeviceLayer>());
+  }
+
   if (target == nullptr) {
-    idisplay->GetClientLayer().SwChainClearCache();
+    client_layer.ClearSlots();
+    h2l->SwChainClearCache();
+
     return 0;
   }
 
-  HwcLayer::LayerProperties lp;
-  lp.buffer = {
-      .buffer_handle = target,
-      .acquire_fence = MakeSharedFd(acquire_fence),
-  };
-  lp.color_space = Hwc2ToColorSpace(dataspace);
-  lp.sample_range = Hwc2ToSampleRange(dataspace);
+  auto [lp, not_a_swapchain] = h2l->HandleNextBuffer(target, acquire_fence);
+  if (!lp) {
+    ALOGE("Failed to process client target");
+    return static_cast<int32_t>(HWC2::Error::BadLayer);
+  }
 
-  idisplay->GetClientLayer().SetLayerProperties(lp);
+  if (not_a_swapchain) {
+    client_layer.ClearSlots();
+  }
+
+  lp->color_space = Hwc2ToColorSpace(dataspace);
+  lp->sample_range = Hwc2ToSampleRange(dataspace);
+
+  idisplay->GetClientLayer().SetLayerProperties(lp.value());
 
   return 0;
 }
@@ -179,12 +302,23 @@
     return static_cast<int32_t>(HWC2::Error::BadLayer);
   }
 
-  HwcLayer::LayerProperties lp;
-  lp.buffer = {
-      .buffer_handle = buffer,
-      .acquire_fence = MakeSharedFd(release_fence),
-  };
-  writeback_layer->SetLayerProperties(lp);
+  auto h2l = GetHwc2DeviceLayer(*writeback_layer);
+  if (!h2l) {
+    writeback_layer->SetFrontendPrivateData(
+        std::make_shared<Hwc2DeviceLayer>());
+  }
+
+  auto [lp, not_a_swapchain] = h2l->HandleNextBuffer(buffer, release_fence);
+  if (!lp) {
+    ALOGE("Failed to process output buffer");
+    return static_cast<int32_t>(HWC2::Error::BadLayer);
+  }
+
+  if (not_a_swapchain) {
+    writeback_layer->ClearSlots();
+  }
+
+  writeback_layer->SetLayerProperties(lp.value());
 
   return 0;
 }
@@ -232,10 +366,19 @@
   GET_DISPLAY(display);
   GET_LAYER(layer);
 
-  HwcLayer::LayerProperties layer_properties;
-  layer_properties.buffer = {.buffer_handle = buffer,
-                             .acquire_fence = MakeSharedFd(acquire_fence)};
-  ilayer->SetLayerProperties(layer_properties);
+  auto h2l = GetHwc2DeviceLayer(*ilayer);
+
+  auto [lp, not_a_swapchain] = h2l->HandleNextBuffer(buffer, acquire_fence);
+  if (!lp) {
+    ALOGV("Failed to process layer buffer");
+    return static_cast<int32_t>(HWC2::Error::BadLayer);
+  }
+
+  if (not_a_swapchain) {
+    ilayer->ClearSlots();
+  }
+
+  ilayer->SetLayerProperties(lp.value());
 
   return 0;
 }