/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2021, Google Inc. * * generic_camera_buffer.cpp - Allocate FrameBuffer using gralloc API */ #include <memory> #include <vector> #include <libcamera/base/log.h> #include <libcamera/base/shared_fd.h> #include "libcamera/internal/formats.h" #include "libcamera/internal/framebuffer.h" #include <hardware/camera3.h> #include <hardware/gralloc.h> #include <hardware/hardware.h> #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<libcamera::FrameBuffer> 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<libcamera::FrameBuffer> 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<FrameBuffer::Plane> 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<FrameBuffer>( std::make_unique<GenericFrameBufferData>(allocDevice_, handle), planes); } PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION