From c58662c5770e4c2b4446318295055fcbc04c1824 Mon Sep 17 00:00:00 2001 From: Hirokazu Honda Date: Wed, 24 Nov 2021 03:39:47 +0900 Subject: android: Introduce PlatformFrameBufferAllocator The existing FrameBufferAllocator is not allowed to allocate a new buffer while Camera is running. This introduces PlatformFrameBufferAllocator. It allocates FrameBuffer using cros::CameraBufferManager on ChromeOS and gralloc on non ChromeOS platform. The allocated FrameBuffer owns the underlying buffer but must be destroyed before PlatformFrameBufferAllocator is destroyed. Signed-off-by: Hirokazu Honda Reviewed-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Signed-off-by: Jacopo Mondi --- src/android/frame_buffer_allocator.h | 55 +++++++++ src/android/mm/cros_frame_buffer_allocator.cpp | 88 +++++++++++++ src/android/mm/generic_frame_buffer_allocator.cpp | 143 ++++++++++++++++++++++ src/android/mm/meson.build | 6 +- 4 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 src/android/frame_buffer_allocator.h create mode 100644 src/android/mm/cros_frame_buffer_allocator.cpp create mode 100644 src/android/mm/generic_frame_buffer_allocator.cpp (limited to 'src') diff --git a/src/android/frame_buffer_allocator.h b/src/android/frame_buffer_allocator.h new file mode 100644 index 00000000..5d2eeda1 --- /dev/null +++ b/src/android/frame_buffer_allocator.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * frame_buffer_allocator.h - Interface definition to allocate Frame buffer in + * platform dependent way. + */ +#ifndef __ANDROID_FRAME_BUFFER_ALLOCATOR_H__ +#define __ANDROID_FRAME_BUFFER_ALLOCATOR_H__ + +#include + +#include + +#include +#include +#include + +class CameraDevice; + +class PlatformFrameBufferAllocator : libcamera::Extensible +{ + LIBCAMERA_DECLARE_PRIVATE() + +public: + explicit PlatformFrameBufferAllocator(CameraDevice *const cameraDevice); + ~PlatformFrameBufferAllocator(); + + /* + * FrameBuffer owns the underlying buffer. Returns nullptr on failure. + * Note: The returned FrameBuffer needs to be destroyed before + * PlatformFrameBufferAllocator is destroyed. + */ + std::unique_ptr allocate( + int halPixelFormat, const libcamera::Size &size, uint32_t usage); +}; + +#define PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION \ +PlatformFrameBufferAllocator::PlatformFrameBufferAllocator( \ + CameraDevice *const cameraDevice) \ + : Extensible(std::make_unique(cameraDevice)) \ +{ \ +} \ +PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator() \ +{ \ +} \ +std::unique_ptr \ +PlatformFrameBufferAllocator::allocate(int halPixelFormat, \ + const libcamera::Size &size, \ + uint32_t usage) \ +{ \ + return _d()->allocate(halPixelFormat, size, usage); \ +} + +#endif /* __ANDROID_FRAME_BUFFER_ALLOCATOR_H__ */ diff --git a/src/android/mm/cros_frame_buffer_allocator.cpp b/src/android/mm/cros_frame_buffer_allocator.cpp new file mode 100644 index 00000000..52e8c180 --- /dev/null +++ b/src/android/mm/cros_frame_buffer_allocator.cpp @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * cros_frame_buffer.cpp - Allocate FrameBuffer for Chromium OS using + * CameraBufferManager + */ + +#include +#include + +#include +#include + +#include "libcamera/internal/framebuffer.h" + +#include "../camera_device.h" +#include "../frame_buffer_allocator.h" +#include "cros-camera/camera_buffer_manager.h" + +using namespace libcamera; + +LOG_DECLARE_CATEGORY(HAL) + +namespace { +class CrosFrameBufferData : public FrameBuffer::Private +{ + LIBCAMERA_DECLARE_PUBLIC(FrameBuffer) + +public: + CrosFrameBufferData(cros::ScopedBufferHandle scopedHandle) + : FrameBuffer::Private(), scopedHandle_(std::move(scopedHandle)) + { + } + +private: + cros::ScopedBufferHandle scopedHandle_; +}; +} /* namespace */ + +class PlatformFrameBufferAllocator::Private : public Extensible::Private +{ + LIBCAMERA_DECLARE_PUBLIC(PlatformFrameBufferAllocator) + +public: + Private([[maybe_unused]] CameraDevice *const cameraDevice) + { + } + + std::unique_ptr + allocate(int halPixelFormat, const libcamera::Size &size, uint32_t usage); +}; + +std::unique_ptr +PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, + const libcamera::Size &size, + uint32_t usage) +{ + cros::ScopedBufferHandle scopedHandle = + cros::CameraBufferManager::AllocateScopedBuffer( + size.width, size.height, halPixelFormat, usage); + if (!scopedHandle) { + LOG(HAL, Error) << "Failed to allocate buffer handle"; + return nullptr; + } + + buffer_handle_t handle = *scopedHandle; + SharedFD fd{ handle->data[0] }; + if (!fd.isValid()) { + LOG(HAL, Fatal) << "Invalid fd"; + return nullptr; + } + + /* This code assumes all the planes are located in the same buffer. */ + const size_t numPlanes = cros::CameraBufferManager::GetNumPlanes(handle); + std::vector planes(numPlanes); + for (auto [i, plane] : utils::enumerate(planes)) { + plane.fd = fd; + plane.offset = cros::CameraBufferManager::GetPlaneOffset(handle, i); + plane.length = cros::CameraBufferManager::GetPlaneSize(handle, i); + } + + return std::make_unique( + std::make_unique(std::move(scopedHandle)), + planes); +} + +PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION diff --git a/src/android/mm/generic_frame_buffer_allocator.cpp b/src/android/mm/generic_frame_buffer_allocator.cpp new file mode 100644 index 00000000..acb2fa2b --- /dev/null +++ b/src/android/mm/generic_frame_buffer_allocator.cpp @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * generic_camera_buffer.cpp - Allocate FrameBuffer using gralloc API + */ + +#include +#include + +#include +#include + +#include "libcamera/internal/formats.h" +#include "libcamera/internal/framebuffer.h" + +#include +#include +#include + +#include "../camera_device.h" +#include "../frame_buffer_allocator.h" + +using namespace libcamera; + +LOG_DECLARE_CATEGORY(HAL) + +namespace { +class GenericFrameBufferData : public FrameBuffer::Private +{ + LIBCAMERA_DECLARE_PUBLIC(FrameBuffer) + +public: + GenericFrameBufferData(struct alloc_device_t *allocDevice, + buffer_handle_t handle) + : allocDevice_(allocDevice), handle_(handle) + { + ASSERT(allocDevice_); + ASSERT(handle_); + } + + ~GenericFrameBufferData() override + { + /* + * allocDevice_ is used to destroy handle_. allocDevice_ is + * owned by PlatformFrameBufferAllocator::Private. + * GenericFrameBufferData must be destroyed before it is + * destroyed. + * + * \todo Consider managing alloc_device_t with std::shared_ptr + * if this is difficult to maintain. + * + * \todo Thread safety against alloc_device_t is not documented. + * Is it no problem to call alloc/free in parallel? + */ + allocDevice_->free(allocDevice_, handle_); + } + +private: + struct alloc_device_t *allocDevice_; + const buffer_handle_t handle_; +}; +} /* namespace */ + +class PlatformFrameBufferAllocator::Private : public Extensible::Private +{ + LIBCAMERA_DECLARE_PUBLIC(PlatformFrameBufferAllocator) + +public: + Private(CameraDevice *const cameraDevice) + : cameraDevice_(cameraDevice), + hardwareModule_(cameraDevice->camera3Device()->common.module), + allocDevice_(nullptr) + { + ASSERT(hardwareModule_); + } + + ~Private() override; + + std::unique_ptr + allocate(int halPixelFormat, const libcamera::Size &size, uint32_t usage); + +private: + const CameraDevice *const cameraDevice_; + struct hw_module_t *const hardwareModule_; + struct alloc_device_t *allocDevice_; +}; + +PlatformFrameBufferAllocator::Private::~Private() +{ + if (allocDevice_) + gralloc_close(allocDevice_); +} + +std::unique_ptr +PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, + const libcamera::Size &size, + uint32_t usage) +{ + if (!allocDevice_) { + int ret = gralloc_open(hardwareModule_, &allocDevice_); + if (ret) { + LOG(HAL, Fatal) << "gralloc_open() failed: " << ret; + return nullptr; + } + } + + int stride = 0; + buffer_handle_t handle = nullptr; + int ret = allocDevice_->alloc(allocDevice_, size.width, size.height, + halPixelFormat, usage, &handle, &stride); + if (ret) { + LOG(HAL, Error) << "failed buffer allocation: " << ret; + return nullptr; + } + if (!handle) { + LOG(HAL, Fatal) << "invalid buffer_handle_t"; + return nullptr; + } + + /* This code assumes the planes are mapped consecutively. */ + const libcamera::PixelFormat pixelFormat = + cameraDevice_->capabilities()->toPixelFormat(halPixelFormat); + const auto &info = PixelFormatInfo::info(pixelFormat); + std::vector planes(info.numPlanes()); + + SharedFD fd{ handle->data[0] }; + size_t offset = 0; + for (auto [i, plane] : utils::enumerate(planes)) { + const size_t planeSize = info.planeSize(size.height, i, stride); + + plane.fd = fd; + plane.offset = offset; + plane.length = planeSize; + offset += planeSize; + } + + return std::make_unique( + std::make_unique(allocDevice_, handle), + planes); +} + +PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION diff --git a/src/android/mm/meson.build b/src/android/mm/meson.build index eeb5cc2e..d40a3b0b 100644 --- a/src/android/mm/meson.build +++ b/src/android/mm/meson.build @@ -2,8 +2,10 @@ platform = get_option('android_platform') if platform == 'generic' - android_hal_sources += files(['generic_camera_buffer.cpp']) + android_hal_sources += files(['generic_camera_buffer.cpp', + 'generic_frame_buffer_allocator.cpp']) elif platform == 'cros' - android_hal_sources += files(['cros_camera_buffer.cpp']) + android_hal_sources += files(['cros_camera_buffer.cpp', + 'cros_frame_buffer_allocator.cpp']) android_deps += [dependency('libcros_camera')] endif -- cgit v1.2.1