drm_hwcomposer: Use DUMB buffer for modeset

Now, as the LayerProperties struct accepts BufferInfo and BufferInfo can
carry the RAII-wrapped dmabuf FD, it has become elementary to use dumb
buffer for a modeset.

There are two benefits compared to using the gralloc:

1. We aim to make the DRM composer backend Android-agnostic.
2. Not every gralloc may support mapping the HWFB buffer.

Change-Id: I661c88be276de8f068d3af1e44da2740b1bec60d
Signed-off-by: Roman Stratiienko <r.stratiienko@gmail.com>
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index 4534104..787d77c 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -18,6 +18,7 @@
 
 #include "DrmDevice.h"
 
+#include <sys/mman.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
@@ -260,4 +261,93 @@
   return encoders_;
 }
 
+class DumbBufferFd : public PrimeFdsSharedBase {
+ public:
+  SharedFd fd;
+};
+
+// NOLINTBEGIN(cppcoreguidelines-avoid-goto)
+auto DrmDevice::CreateBufferForModeset(uint32_t width, uint32_t height)
+    -> std::optional<BufferInfo> {
+  constexpr uint32_t kDumbBufferFormat = DRM_FORMAT_XRGB8888;
+  constexpr uint32_t kDumbBufferBpp = 32;
+
+  std::optional<BufferInfo> result;
+  void *ptr = MAP_FAILED;
+  struct drm_mode_create_dumb create = {
+      .height = height,
+      .width = width,
+      .bpp = kDumbBufferBpp,
+      .flags = 0,
+  };
+
+  int ret = drmIoctl(*fd_, DRM_IOCTL_MODE_CREATE_DUMB, &create);
+  if (ret != 0) {
+    ALOGE("Failed to DRM_IOCTL_MODE_CREATE_DUMB %d", errno);
+    return {};
+  }
+
+  struct drm_mode_map_dumb map = {
+      .handle = create.handle,
+  };
+
+  auto dumb_buffer_fd = std::make_shared<DumbBufferFd>();
+
+  BufferInfo buffer_info = {
+      .width = width,
+      .height = height,
+
+      .format = kDumbBufferFormat,
+      .pitches = {create.pitch},
+      .prime_fds = {-1, -1, -1, -1},
+      .modifiers = {DRM_FORMAT_MOD_NONE},
+
+      .color_space = BufferColorSpace::kUndefined,
+      .sample_range = BufferSampleRange::kUndefined,
+      .blend_mode = BufferBlendMode::kNone,
+
+      .fds_shared = dumb_buffer_fd,
+  };
+
+  ret = drmIoctl(*fd_, DRM_IOCTL_MODE_MAP_DUMB, &map);
+  if (ret != 0) {
+    ALOGE("Failed to DRM_IOCTL_MODE_MAP_DUMB %d", errno);
+    goto done;
+  }
+
+  ptr = mmap(nullptr, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd_,
+             (off_t)map.offset);
+  if (ptr == MAP_FAILED) {
+    ALOGE("Failed to mmap dumb buffer %d", errno);
+    goto done;
+  }
+
+  memset(ptr, 0, create.size);
+
+  if (munmap(ptr, create.size) != 0) {
+    ALOGE("Failed to unmap dumb buffer: %d", errno);
+  }
+
+  ret = drmPrimeHandleToFD(*fd_, create.handle, 0, &buffer_info.prime_fds[0]);
+  if (ret != 0) {
+    ALOGE("Failed to export dumb buffer as FD: %d", errno);
+    goto done;
+  }
+
+  dumb_buffer_fd->fd = MakeSharedFd(buffer_info.prime_fds[0]);
+
+  result = buffer_info;
+
+done:
+  if (create.handle > 0) {
+    struct drm_mode_destroy_dumb destroy = {
+        .handle = create.handle,
+    };
+    drmIoctl(*fd_, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
+  }
+
+  return result;
+}
+// NOLINTEND(cppcoreguidelines-avoid-goto)
+
 }  // namespace android
diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h
index cbaa536..7ee7d10 100644
--- a/drm/DrmDevice.h
+++ b/drm/DrmDevice.h
@@ -18,11 +18,13 @@
 
 #include <cstdint>
 #include <map>
+#include <optional>
 #include <tuple>
 
 #include "DrmConnector.h"
 #include "DrmCrtc.h"
 #include "DrmEncoder.h"
+#include "bufferinfo/BufferInfo.h"
 #include "utils/fd.h"
 
 namespace android {
@@ -70,6 +72,9 @@
     return HasAddFb2ModifiersSupport_;
   }
 
+  auto CreateBufferForModeset(uint32_t width, uint32_t height)
+      -> std::optional<BufferInfo>;
+
   auto &GetDrmFbImporter() {
     return *drm_fb_importer_;
   }
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index e569c71..016998f 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -21,13 +21,7 @@
 
 #include <cinttypes>
 
-#include <xf86drmMode.h>
-
-#include <hardware/gralloc.h>
 #include <ui/ColorSpace.h>
-#include <ui/GraphicBufferAllocator.h>
-#include <ui/GraphicBufferMapper.h>
-#include <ui/PixelFormat.h>
 
 #include "backend/Backend.h"
 #include "backend/BackendManager.h"
@@ -95,49 +89,6 @@
   return color_matrix;
 }
 
-// Allocate a black buffer that can be used for an initial modeset when there.
-// is no appropriate client buffer available to be used.
-// Caller must free the returned buffer with GraphicBufferAllocator::free.
-auto GetModesetBuffer(uint32_t width, uint32_t height) -> buffer_handle_t {
-  constexpr PixelFormat format = PIXEL_FORMAT_RGBA_8888;
-  constexpr uint64_t usage = GRALLOC_USAGE_SW_READ_OFTEN |
-                             GRALLOC_USAGE_SW_WRITE_OFTEN |
-                             GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
-
-  constexpr uint32_t layer_count = 1;
-  const std::string name = "drm-hwcomposer";
-
-  buffer_handle_t handle = nullptr;
-  uint32_t stride = 0;
-  status_t status = GraphicBufferAllocator::get().allocate(width, height,
-                                                           format, layer_count,
-                                                           usage, &handle,
-                                                           &stride, name);
-  if (status != OK) {
-    ALOGE("Failed to allocate modeset buffer.");
-    return nullptr;
-  }
-
-  void *data = nullptr;
-  Rect bounds = {0, 0, static_cast<int32_t>(width),
-                 static_cast<int32_t>(height)};
-  status = GraphicBufferMapper::get().lock(handle, usage, bounds, &data);
-  if (status != OK) {
-    ALOGE("Failed to map modeset buffer.");
-    GraphicBufferAllocator::get().free(handle);
-    return nullptr;
-  }
-
-  // Cast one of the multiplicands to ensure that the multiplication happens
-  // in a wider type (size_t).
-  const size_t buffer_size = static_cast<size_t>(height) * stride *
-                             bytesPerPixel(format);
-  memset(data, 0, buffer_size);
-  status = GraphicBufferMapper::get().unlock(handle);
-  ALOGW_IF(status != OK, "Failed to unmap buffer.");
-  return handle;
-}
-
 }  // namespace
 
 std::string HwcDisplay::DumpDelta(HwcDisplay::Stats delta) {
@@ -258,18 +209,14 @@
     modeset_layer_data = client_layer_.GetLayerData();
   } else {
     ALOGV("Allocate modeset buffer.");
-    buffer_handle_t modeset_buffer = GetModesetBuffer(width, height);
-    if (modeset_buffer != nullptr) {
+    auto modeset_buffer =  //
+        GetPipe().device->CreateBufferForModeset(width, height);
+    if (modeset_buffer) {
       auto modeset_layer = std::make_unique<HwcLayer>(this);
       HwcLayer::LayerProperties properties;
-      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,
+          .bi = modeset_buffer,
       };
       properties.active_slot = {
           .slot_id = 0,
@@ -279,7 +226,6 @@
       modeset_layer->SetLayerProperties(properties);
       modeset_layer->PopulateLayerData();
       modeset_layer_data = modeset_layer->GetLayerData();
-      GraphicBufferAllocator::get().free(modeset_buffer);
     }
   }