/* 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 #include "libcamera/internal/formats.h" #include "libcamera/internal/framebuffer.h" #include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wextra-semi" #include #pragma GCC diagnostic pop #include #include "../camera_device.h" #include "../frame_buffer_allocator.h" #include "../hal_framebuffer.h" using namespace libcamera; LOG_DECLARE_CATEGORY(HAL) namespace { class GenericFrameBufferData : public FrameBuffer::Private { LIBCAMERA_DECLARE_PUBLIC(FrameBuffer) public: GenericFrameBufferData(buffer_handle_t handle, const std::vector &planes) : FrameBuffer::Private(planes), handle_(handle) { ASSERT(handle_); } ~GenericFrameBufferData() override { /* * \todo Thread safety against alloc_device_t is not documented. * Is it no problem to call alloc/free in parallel? */ auto &allocator = android::GraphicBufferAllocator::get(); android::status_t status = allocator.free(handle_); if (status != android::NO_ERROR) LOG(HAL, Error) << "Error freeing framebuffer: " << status; } private: const buffer_handle_t handle_; }; } /* namespace */ class PlatformFrameBufferAllocator::Private : public Extensible::Private { LIBCAMERA_DECLARE_PUBLIC(PlatformFrameBufferAllocator) public: Private(CameraDevice *const cameraDevice) : cameraDevice_(cameraDevice) { } ~Private() = default; std::unique_ptr allocate(int halPixelFormat, const libcamera::Size &size, uint32_t usage); private: const CameraDevice *const cameraDevice_; }; std::unique_ptr PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, const libcamera::Size &size, uint32_t usage) { uint32_t stride = 0; buffer_handle_t handle = nullptr; auto &allocator = android::GraphicBufferAllocator::get(); android::status_t status = allocator.allocate(size.width, size.height, halPixelFormat, 1 /*layerCount*/, usage, &handle, &stride, "libcameraHAL"); if (status != android::NO_ERROR) { LOG(HAL, Error) << "failed buffer allocation: " << status; 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( handle, planes), handle); } PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION