blob: acb2fa2b699d1da980862b2b1b874d591f6f4e5f [file] [log] [blame]
/* 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