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