sdm: Avoid fb_id creation and removal in each frame

- Cache the <handle_id, fb_id> map in SDM layer.
- Registry finds the handle_id in layer map. If it is found, then
  mapped fb_id is programmed to DRM driver. Else fb_id is created
  and it is added in map for the given handle_id key. This map is
  cleared and fb_ids are removed, when the SDM layer gets deleted.
- "vendor.display.disable_fbid_cache" system prop needs to be set
  to disable the fb_id caching in SDM. So, fb_id will be removed
  and created for each SDM layer in every draw cycle.

CRs-Fixed: 2235202
Change-Id: I1d6c7fbc1fc5c1f9afad36cf49f17bc8c5322fe5
diff --git a/include/display_properties.h b/include/display_properties.h
index 505235f..799eade 100644
--- a/include/display_properties.h
+++ b/include/display_properties.h
@@ -94,6 +94,7 @@
 #define DISABLE_EXCL_RECT_PROP               DISPLAY_PROP("disable_excl_rect")
 #define ENABLE_PIPE_PRIORITY_PROP            DISPLAY_PROP("enable_pipe_priority")
 #define DISABLE_EXCl_RECT_PARTIAL_FB         DISPLAY_PROP("disable_excl_rect_partial_fb")
+#define DISABLE_FBID_CACHE                   DISPLAY_PROP("disable_fbid_cache")
 
 #define DISABLE_HDR_LUT_GEN                  DISPLAY_PROP("disable_hdr_lut_gen")
 #define ENABLE_DEFAULT_COLOR_MODE            DISPLAY_PROP("enable_default_color_mode")
diff --git a/sdm/include/core/buffer_allocator.h b/sdm/include/core/buffer_allocator.h
index e0c7136..a6a3cac 100644
--- a/sdm/include/core/buffer_allocator.h
+++ b/sdm/include/core/buffer_allocator.h
@@ -70,6 +70,7 @@
   uint32_t aligned_height = 0;   //!< Specifies aligned allocated buffer height in pixels.
   LayerBufferFormat format = kFormatInvalid;  // Specifies buffer format for allocated buffer.
   uint32_t size = 0;             //!< Specifies the size of the allocated buffer.
+  uint64_t id = 0;               //!< Specifies the Id of the allocated buffer.
 };
 
 /*! @brief Holds the information about the input/output configuration of an output buffer.
diff --git a/sdm/include/core/layer_buffer.h b/sdm/include/core/layer_buffer.h
index 8f7f6fe..b5f1701 100644
--- a/sdm/include/core/layer_buffer.h
+++ b/sdm/include/core/layer_buffer.h
@@ -286,6 +286,8 @@
     color_metadata.colorPrimaries = ColorPrimaries_BT709_5;
     color_metadata.transfer = Transfer_sRGB;
   }
+
+  uint64_t handle_id = 0;
 };
 
 // This enum represents buffer layout types.
@@ -295,6 +297,11 @@
   kTPTiled    //!< Tightly Packed data
 };
 
+class LayerBufferObject {
+ public:
+  virtual ~LayerBufferObject() {}
+};
+
 }  // namespace sdm
 
 #endif  // __LAYER_BUFFER_H__
diff --git a/sdm/include/core/layer_stack.h b/sdm/include/core/layer_stack.h
index f85a337..699cb8b 100644
--- a/sdm/include/core/layer_stack.h
+++ b/sdm/include/core/layer_stack.h
@@ -36,6 +36,8 @@
 
 #include <vector>
 #include <utility>
+#include <unordered_map>
+#include <memory>
 
 #include "layer_buffer.h"
 #include "sdm_types.h"
@@ -310,6 +312,10 @@
   uint32_t alpha = 0;      //!< Alpha value
 };
 
+struct LayerBufferMap {
+  std::unordered_map<uint64_t, std::shared_ptr<LayerBufferObject>> buffer_map;
+};
+
 /*! @brief This structure defines display layer object which contains layer properties and a drawing
   buffer.
 
@@ -382,6 +388,7 @@
   Lut3d lut_3d = {};                               //!< o/p - Populated by SDM when tone mapping is
                                                    //!< needed on this layer.
   LayerSolidFill solid_fill_info = {};             //!< solid fill info along with depth.
+  std::shared_ptr<LayerBufferMap> buffer_map = nullptr;  //!< Map of handle_id and fb_id.
 };
 
 /*! @brief This structure defines the color space + transfer of a given layer.
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 0554b4f..5b61523 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -177,6 +177,9 @@
   hw_layers_info.stack = layer_stack;
 
   for (auto &layer : layers) {
+    if (layer->buffer_map == nullptr) {
+      layer->buffer_map = std::make_shared<LayerBufferMap>();
+    }
     if (layer->composition == kCompositionGPUTarget) {
       hw_layers_info.gpu_target_index = hw_layers_info.app_layer_count;
       break;
@@ -1403,6 +1406,7 @@
     hw_layer.input_buffer.planes[0].stride = sdm_layer->input_buffer.planes[0].stride;
     hw_layer.input_buffer.size = sdm_layer->input_buffer.size;
     hw_layer.input_buffer.acquire_fence_fd = sdm_layer->input_buffer.acquire_fence_fd;
+    hw_layer.input_buffer.handle_id = sdm_layer->input_buffer.handle_id;
   }
 
   return;
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index c094681..3be82e1 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -258,25 +258,31 @@
   }
 }
 
-HWDeviceDRM::Registry::Registry(BufferAllocator *buffer_allocator) :
-  buffer_allocator_(buffer_allocator) {
-  DRMMaster *master = nullptr;
-  DRMMaster::GetInstance(&master);
-
-  if (!master) {
-    DLOGE("Failed to acquire DRM Master instance");
-    return;
+class FrameBufferObject : public LayerBufferObject {
+ public:
+  explicit FrameBufferObject(uint32_t fb_id) : fb_id_(fb_id) {
   }
 
-  // If RMFB is ref-counted, we should immediately make a call to clean up fb_id after commit.
-  // Driver will release fb_id after its usage. Otherwise speculatively free up fb_id after 3
-  // cycles assuming driver is done with it.
-  rmfb_delay_ = master->IsRmFbRefCounted() ? 1 : 3;
-  hashmap_ = new std::unordered_map<int, uint32_t>[rmfb_delay_];
-}
+  ~FrameBufferObject() {
+    DRMMaster *master;
+    DRMMaster::GetInstance(&master);
+    int ret = master->RemoveFbId(fb_id_);
+    if (ret < 0) {
+      DLOGE("Removing fb_id %d failed with error %d", fb_id_, errno);
+    }
+  }
+  uint32_t GetFbId() { return fb_id_; }
 
-HWDeviceDRM::Registry::~Registry() {
-  delete [] hashmap_;
+ private:
+  uint32_t fb_id_;
+};
+
+HWDeviceDRM::Registry::Registry(BufferAllocator *buffer_allocator) :
+  buffer_allocator_(buffer_allocator) {
+  int value = 0;
+  if (Debug::GetProperty(DISABLE_FBID_CACHE, &value) == kErrorNone) {
+    disable_fbid_cache_ = (value == 1);
+  }
 }
 
 void HWDeviceDRM::Registry::Register(HWLayers *hw_layers) {
@@ -293,84 +299,111 @@
       input_buffer = &hw_rotator_session->output_buffer;
     }
 
-    MapBufferToFbId(input_buffer);
+    // layer input buffer map to fb id also applies for inline rot
+    MapBufferToFbId(&layer, input_buffer);
 
     if (hw_rotator_session->mode == kRotatorInline && hw_rotate_info->valid &&
         hw_rotator_session->output_buffer.planes[0].fd >= 0) {
-      MapBufferToFbId(&hw_rotator_session->output_buffer);
+      MapBufferToFbId(&layer, &hw_rotator_session->output_buffer);
     }
   }
 }
 
-void HWDeviceDRM::Registry::MapBufferToFbId(LayerBuffer* buffer) {
-  int fd = buffer->planes[0].fd;
+int HWDeviceDRM::Registry::CreateFbId(LayerBuffer *buffer, uint32_t *fb_id) {
   DRMMaster *master = nullptr;
   DRMMaster::GetInstance(&master);
+  int ret = -1;
 
   if (!master) {
     DLOGE("Failed to acquire DRM Master instance");
+    return ret;
+  }
+
+  DRMBuffer layout{};
+  AllocatedBufferInfo buf_info{};
+  buf_info.fd = layout.fd = buffer->planes[0].fd;
+  buf_info.aligned_width = layout.width = buffer->width;
+  buf_info.aligned_height = layout.height = buffer->height;
+  buf_info.format = buffer->format;
+  GetDRMFormat(buf_info.format, &layout.drm_format, &layout.drm_format_modifier);
+  buffer_allocator_->GetBufferLayout(buf_info, layout.stride, layout.offset, &layout.num_planes);
+  ret = master->CreateFbId(layout, fb_id);
+  if (ret < 0) {
+    DLOGE("CreateFbId failed. width %d, height %d, format: %s, stride %u, error %d",
+        layout.width, layout.height, GetFormatString(buf_info.format), layout.stride[0], errno);
+  }
+
+  return ret;
+}
+
+void HWDeviceDRM::Registry::MapBufferToFbId(Layer* layer, LayerBuffer* buffer) {
+  if (buffer->planes[0].fd < 0) {
     return;
   }
 
-  if (fd >= 0 && hashmap_[current_index_].find(fd) == hashmap_[current_index_].end()) {
-    AllocatedBufferInfo buf_info{};
-    DRMBuffer layout{};
-    buf_info.fd = layout.fd = fd;
-    buf_info.aligned_width = layout.width = buffer->width;
-    buf_info.aligned_height = layout.height = buffer->height;
-    buf_info.format = buffer->format;
-    GetDRMFormat(buf_info.format, &layout.drm_format, &layout.drm_format_modifier);
-    buffer_allocator_->GetBufferLayout(buf_info, layout.stride, layout.offset,
-        &layout.num_planes);
-    uint32_t fb_id = 0;
-    int ret = master->CreateFbId(layout, &fb_id);
-    if (ret < 0) {
-      DLOGE("CreateFbId failed. width %d, height %d, format: %s, stride %u, error %d",
-          layout.width, layout.height, GetFormatString(buf_info.format), layout.stride[0],
-          errno);
-    } else {
-      hashmap_[current_index_][fd] = fb_id;
-    }
+  uint64_t handle_id = buffer->handle_id;
+
+  if (!handle_id || disable_fbid_cache_) {
+    // Legacy: Remove & Create fb_id in each frame
+    layer->buffer_map->buffer_map.clear();
   }
-  return;
-}
 
-void HWDeviceDRM::Registry::Next() {
-  current_index_ = (current_index_ + 1) % rmfb_delay_;
-}
-
-void HWDeviceDRM::Registry::Unregister() {
-  DRMMaster *master = nullptr;
-  DRMMaster::GetInstance(&master);
-
-  if (!master) {
-    DLOGE("Failed to acquire DRM Master instance");
+  if (layer->buffer_map->buffer_map.find(handle_id) != layer->buffer_map->buffer_map.end()) {
+    // Found fb_id for given handle_id key
     return;
   }
 
-  auto &curr_map = hashmap_[current_index_];
-  for (auto &pair : curr_map) {
-    uint32_t fb_id = pair.second;
-    int ret = master->RemoveFbId(fb_id);
-    if (ret < 0) {
-      DLOGE("Removing fb_id %d failed with error %d", fb_id, errno);
-    }
+  uint32_t fb_id = 0;
+  if (CreateFbId(buffer, &fb_id) >= 0) {
+    // Create and cache the fb_id in map
+    layer->buffer_map->buffer_map[handle_id] = std::make_shared<FrameBufferObject>(fb_id);
+  }
+}
+
+void HWDeviceDRM::Registry::MapOutputBufferToFbId(LayerBuffer *output_buffer) {
+  if (output_buffer->planes[0].fd < 0) {
+    return;
   }
 
-  curr_map.clear();
+  uint64_t handle_id = output_buffer->handle_id;
+
+  if (!handle_id || disable_fbid_cache_) {
+    // Legacy: Remove & Create fb_id in each frame
+    output_buffer_map_.clear();
+  }
+
+  if (output_buffer_map_.find(handle_id) != output_buffer_map_.end()) {
+    return;
+  }
+
+  uint32_t fb_id = 0;
+  if (CreateFbId(output_buffer, &fb_id) >= 0) {
+    output_buffer_map_[handle_id] = std::make_shared<FrameBufferObject>(fb_id);
+  }
 }
 
 void HWDeviceDRM::Registry::Clear() {
-  for (int i = 0; i < rmfb_delay_; i++) {
-    Unregister();
-    Next();
-  }
-  current_index_ = 0;
+  output_buffer_map_.clear();
 }
 
-uint32_t HWDeviceDRM::Registry::GetFbId(int fd) {
-  auto it = hashmap_[current_index_].find(fd);
-  return (it == hashmap_[current_index_].end()) ? 0 : it->second;
+uint32_t HWDeviceDRM::Registry::GetFbId(Layer *layer, uint64_t handle_id) {
+  auto it = layer->buffer_map->buffer_map.find(handle_id);
+  if (it != layer->buffer_map->buffer_map.end()) {
+    FrameBufferObject *fb_obj = static_cast<FrameBufferObject*>(it->second.get());
+    return fb_obj->GetFbId();
+  }
+
+  return 0;
+}
+
+uint32_t HWDeviceDRM::Registry::GetOutputFbId(uint64_t handle_id) {
+  auto it = output_buffer_map_.find(handle_id);
+  if (it != output_buffer_map_.end()) {
+    FrameBufferObject *fb_obj = static_cast<FrameBufferObject*>(it->second.get());
+    return fb_obj->GetFbId();
+  }
+
+  return 0;
 }
 
 HWDeviceDRM::HWDeviceDRM(BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator,
@@ -938,7 +971,8 @@
         input_buffer = &hw_rotator_session->output_buffer;
       }
 
-      uint32_t fb_id = registry_.GetFbId(input_buffer->planes[0].fd);
+      uint32_t fb_id = registry_.GetFbId(&layer, input_buffer->handle_id);
+
       if (pipe_info->valid && fb_id) {
         uint32_t pipe_id = pipe_info->pipe_id;
         drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ALPHA, pipe_id, layer.plane_alpha);
@@ -955,7 +989,8 @@
           SetRect(hw_rotate_info->dst_roi, &rot_dst);
           drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ROTATION_DST_RECT, pipe_id, rot_dst);
           if (hw_rotator_session->output_buffer.planes[0].fd >= 0) {
-            uint32_t rot_fb_id = registry_.GetFbId(hw_rotator_session->output_buffer.planes[0].fd);
+            uint32_t rot_fb_id = registry_.GetFbId(&layer,
+                                                   hw_rotator_session->output_buffer.handle_id);
             if (rot_fb_id) {
               drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ROT_FB_ID, pipe_id, rot_fb_id);
             }
@@ -1125,7 +1160,6 @@
     err = kErrorHardware;
   }
 
-  registry_.Unregister();
   return err;
 }
 
@@ -1141,9 +1175,6 @@
     err = AtomicCommit(hw_layers);
   }
 
-  registry_.Next();
-  registry_.Unregister();
-
   return err;
 }
 
@@ -1184,7 +1215,8 @@
   drmModeModeInfo mode;
   res_mgr->GetMode(&mode);
 
-  uint32_t fb_id = registry_.GetFbId(hw_layer_info.hw_layers.at(0).input_buffer.planes[0].fd);
+  uint64_t handle_id = hw_layer_info.hw_layers.at(0).input_buffer.handle_id;
+  uint32_t fb_id = registry_.GetFbId(&hw_layer_info.hw_layers.at(0), handle_id);
   ret = drmModeSetCrtc(dev_fd, crtc_id, fb_id, 0 /* x */, 0 /* y */, &connector_id,
                        1 /* num_connectors */, &mode);
   if (ret < 0) {
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index 718cc15..fe7b669 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -154,27 +154,24 @@
   class Registry {
    public:
     explicit Registry(BufferAllocator *buffer_allocator);
-    ~Registry();
-    // Called on each Validate and Commit to register layer buffers fds to the slot pointed to by
-    // current_index_
+    // Called on each Validate and Commit to map the handle_id to fb_id of each layer buffer.
     void Register(HWLayers *hw_layers);
-    // Clears the slot pointed to by current_index_
-    void Unregister();
-    // Moves current_index_ to the next position
-    void Next();
-    // Called on display disconnect to release all gem handles and fb_ids
+    // Called on display disconnect to clear output buffer map and remove fb_ids.
     void Clear();
-    // Maps given fd to FB ID
-    void MapBufferToFbId(LayerBuffer* buffer);
-    // Finds an fb_id corresponding to an fd in current map
-    uint32_t GetFbId(int fd);
+    // Create the fd_id for the given buffer.
+    int CreateFbId(LayerBuffer *buffer, uint32_t *fb_id);
+    // Find handle_id in the layer map. Else create fb_id and add <handle_id,fb_id> in map.
+    void MapBufferToFbId(Layer* layer, LayerBuffer* buffer);
+    // Find handle_id in output buffer map. Else create fb_id and add <handle_id,fb_id> in map.
+    void MapOutputBufferToFbId(LayerBuffer* buffer);
+    // Find fb_id for given handle_id in the layer map.
+    uint32_t GetFbId(Layer *layer, uint64_t handle_id);
+    // Find fb_id for given handle_id in output buffer map.
+    uint32_t GetOutputFbId(uint64_t handle_id);
 
    private:
-    uint8_t rmfb_delay_ = 1;  // N cycle delay before destroy
-    // fd to fb_id map. fd is used as key only for a single draw cycle between
-    // prepare and commit. It should not be used for caching in future due to fd recycling
-    std::unordered_map<int, uint32_t> *hashmap_ {};
-    int current_index_ = 0;
+    bool disable_fbid_cache_ = false;
+    std::unordered_map<uint64_t, std::shared_ptr<LayerBufferObject>> output_buffer_map_ {};
     BufferAllocator *buffer_allocator_ = {};
   };
 
diff --git a/sdm/libs/core/drm/hw_peripheral_drm.cpp b/sdm/libs/core/drm/hw_peripheral_drm.cpp
index 340dc05..bac56ba 100644
--- a/sdm/libs/core/drm/hw_peripheral_drm.cpp
+++ b/sdm/libs/core/drm/hw_peripheral_drm.cpp
@@ -270,7 +270,7 @@
 
 void HWPeripheralDRM::ConfigureConcurrentWriteback(LayerStack *layer_stack) {
   LayerBuffer *output_buffer = layer_stack->output_buffer;
-  registry_.MapBufferToFbId(output_buffer);
+  registry_.MapOutputBufferToFbId(output_buffer);
 
   // Set the topology for Concurrent Writeback: [CRTC_PRIMARY_DISPLAY - CONNECTOR_VIRTUAL_DISPLAY].
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_CRTC, cwb_config_.token.conn_id, token_.crtc_id);
@@ -281,7 +281,7 @@
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_CAPTURE_MODE, token_.crtc_id, capture_mode);
 
   // Set Connector Output FB
-  uint32_t fb_id = registry_.GetFbId(output_buffer->planes[0].fd);
+  uint32_t fb_id = registry_.GetOutputFbId(output_buffer->handle_id);
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_OUTPUT_FB_ID, cwb_config_.token.conn_id, fb_id);
 
   // Set Connector Secure Mode
diff --git a/sdm/libs/core/drm/hw_virtual_drm.cpp b/sdm/libs/core/drm/hw_virtual_drm.cpp
index 20d27f9..a9c1c29 100644
--- a/sdm/libs/core/drm/hw_virtual_drm.cpp
+++ b/sdm/libs/core/drm/hw_virtual_drm.cpp
@@ -126,8 +126,8 @@
   DisplayError err = kErrorNone;
 
   registry_.Register(hw_layers);
-  registry_.MapBufferToFbId(output_buffer);
-  uint32_t fb_id = registry_.GetFbId(output_buffer->planes[0].fd);
+  registry_.MapOutputBufferToFbId(output_buffer);
+  uint32_t fb_id = registry_.GetOutputFbId(output_buffer->handle_id);
 
   ConfigureWbConnectorFbId(fb_id);
   ConfigureWbConnectorDestRect();
@@ -138,17 +138,14 @@
     DLOGE("Atomic commit failed for crtc_id %d conn_id %d", token_.crtc_id, token_.conn_id);
   }
 
-  registry_.Next();
-  registry_.Unregister();
-
   return(err);
 }
 
 DisplayError HWVirtualDRM::Validate(HWLayers *hw_layers) {
   LayerBuffer *output_buffer = hw_layers->info.stack->output_buffer;
 
-  registry_.MapBufferToFbId(output_buffer);
-  uint32_t fb_id = registry_.GetFbId(output_buffer->planes[0].fd);
+  registry_.MapOutputBufferToFbId(output_buffer);
+  uint32_t fb_id = registry_.GetOutputFbId(output_buffer->handle_id);
 
   ConfigureWbConnectorFbId(fb_id);
   ConfigureWbConnectorDestRect();
diff --git a/sdm/libs/hwc2/hwc_buffer_allocator.cpp b/sdm/libs/hwc2/hwc_buffer_allocator.cpp
index c879e94..34db732 100644
--- a/sdm/libs/hwc2/hwc_buffer_allocator.cpp
+++ b/sdm/libs/hwc2/hwc_buffer_allocator.cpp
@@ -144,6 +144,7 @@
   alloc_buffer_info->aligned_width = UINT32(hnd->width);
   alloc_buffer_info->aligned_height = UINT32(hnd->height);
   alloc_buffer_info->size = hnd->size;
+  alloc_buffer_info->id = hnd->id;
 
   buffer_info->private_data = reinterpret_cast<void *>(hnd);
   return kErrorNone;
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index a645169..7aac16f 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -299,6 +299,7 @@
   layer_buffer->planes[0].stride = UINT32(handle->width);
   layer_buffer->size = handle->size;
   layer_buffer->buffer_id = reinterpret_cast<uint64_t>(handle);
+  layer_buffer->handle_id = handle->id;
 
   return HWC2::Error::None;
 }