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);
}
}