[libcamera-devel,v2,2/2] android: Introduce PlatformFrameBufferAllocator
diff mbox series

Message ID 20211101071652.107912-3-hiroh@chromium.org
State Superseded
Headers show
Series
  • Introduce PlatformFrameBufferAllocator
Related show

Commit Message

Hirokazu Honda Nov. 1, 2021, 7:16 a.m. UTC
After we unify identical streams to one stream configuration, the
capture requested by a HAL client can have been resolved as
CameraStream::Mapped. That is, a buffer to be written by a camera
is not provided by a client. We would handle this case by
dynamically allocating FrameBuffer.

The existing FrameBufferAllocator cannot used because it 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 <hiroh@chromium.org>
---
 src/android/frame_buffer_allocator.h          |  54 +++++++
 .../mm/cros_frame_buffer_allocator.cpp        |  90 +++++++++++
 .../mm/generic_frame_buffer_allocator.cpp     | 144 ++++++++++++++++++
 src/android/mm/meson.build                    |   6 +-
 4 files changed, 292 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

Comments

Kieran Bingham Nov. 8, 2021, 11:26 p.m. UTC | #1
Quoting Hirokazu Honda (2021-11-01 07:16:52)
> After we unify identical streams to one stream configuration, the
> capture requested by a HAL client can have been resolved as
> CameraStream::Mapped. That is, a buffer to be written by a camera
> is not provided by a client. We would handle this case by
> dynamically allocating FrameBuffer.
> 
> The existing FrameBufferAllocator cannot used because it 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 <hiroh@chromium.org>

I'm finding this one harder to grasp. It's late so I think I might have
to continue tomorrow.

I wish we had better infrastructure for unit tests on the Android layer,
as I'm sure some of this would benefit from more tests, but even then
we'd have to have an environment to run the unit tests against the
allocators...


> ---
>  src/android/frame_buffer_allocator.h          |  54 +++++++
>  .../mm/cros_frame_buffer_allocator.cpp        |  90 +++++++++++
>  .../mm/generic_frame_buffer_allocator.cpp     | 144 ++++++++++++++++++
>  src/android/mm/meson.build                    |   6 +-
>  4 files changed, 292 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
> 
> diff --git a/src/android/frame_buffer_allocator.h b/src/android/frame_buffer_allocator.h
> new file mode 100644
> index 00000000..41ed4ae1
> --- /dev/null
> +++ b/src/android/frame_buffer_allocator.h
> @@ -0,0 +1,54 @@
> +/* 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 <memory>
> +
> +#include <libcamera/base/class.h>
> +#include <libcamera/camera.h>
> +#include <libcamera/framebuffer.h>
> +#include <libcamera/geometry.h>
> +
> +class CameraDevice;
> +
> +class PlatformFrameBufferAllocator : libcamera::Extensible

Does the 'PlatformFrameBufferAllocater' benefit from using Extensible?
Is it required somehow? Can't it just be a normal class that the CrOS
and Android variants inherit from?


> +{
> +       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<libcamera::FrameBuffer> 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<Private>(this, cameraDevice))     \
> +{                                                                      \
> +}                                                                      \
> +PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator()          \
> +{                                                                      \
> +}                                                                      \
> +std::unique_ptr<libcamera::FrameBuffer>                                        \
> +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..9c7e4ea4
> --- /dev/null
> +++ b/src/android/mm/cros_frame_buffer_allocator.cpp
> @@ -0,0 +1,90 @@
> +/* 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 <memory>
> +#include <vector>
> +
> +#include <libcamera/base/log.h>
> +
> +#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))
> +       {
> +       }
> +
> +       ~CrosFrameBufferData() override = default;
> +
> +private:
> +       cros::ScopedBufferHandle scopedHandle_;
> +};
> +} /* namespace */
> +
> +class PlatformFrameBufferAllocator::Private : public Extensible::Private
> +{
> +       LIBCAMERA_DECLARE_PUBLIC(PlatformFrameBufferAllocator)
> +
> +public:
> +       Private([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> +               [[maybe_unused]] CameraDevice *const cameraDevice)
> +       {
> +       }
> +
> +       ~Private() override = default;
> +
> +       std::unique_ptr<libcamera::FrameBuffer> allocate(
> +               int halPixelFormat, const libcamera::Size &size, uint32_t usage);
> +};
> +
> +std::unique_ptr<libcamera::FrameBuffer>
> +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;
> +       const size_t numPlanes = cros::CameraBufferManager::GetNumPlanes(handle);
> +       std::vector<FrameBuffer::Plane> planes(numPlanes);
> +       FileDescriptor 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. */
> +       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<FrameBuffer>(
> +               std::make_unique<CrosFrameBufferData>(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..167cc1a5
> --- /dev/null
> +++ b/src/android/mm/generic_frame_buffer_allocator.cpp
> @@ -0,0 +1,144 @@
> +/* 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/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.
> +                *
> +                * Q: Thread safety against alloc_device_t is not documented.
> +                * Is it no problem to call alloc/free in parallel?
> +                */
> +               ASSERT(allocDevice_);
> +               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([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> +               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 allocating: " << ret;
> +               return nullptr;
> +       }
> +       if (!handle) {
> +               LOG(HAL, Fatal) << "buffer_handle_t is empty on success";
> +               return nullptr;
> +       }
> +
> +       const libcamera::PixelFormat pixelFormat =
> +               cameraDevice_->capabilities()->toPixelFormat(halPixelFormat);
> +       const auto &info = PixelFormatInfo::info(pixelFormat);
> +       const unsigned int numPlanes = info.numPlanes();
> +       std::vector<FrameBuffer::Plane> planes(numPlanes);
> +
> +       /* This code assumes the planes are mapped consecutively. */
> +       FileDescriptor 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);
> +
> +               planes[i].fd = fd;
> +               planes[i].offset = offset;
> +               planes[i].length = planeSize;
> +               offset += planeSize;
> +       }
> +
> +       return std::make_unique<FrameBuffer>(
> +               std::make_unique<GenericFrameBufferData>(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
> -- 
> 2.33.1.1089.g2158813163f-goog
>
Hirokazu Honda Nov. 9, 2021, 5:46 a.m. UTC | #2
Hi Kieran,

On Tue, Nov 9, 2021 at 8:26 AM Kieran Bingham
<kieran.bingham@ideasonboard.com> wrote:
>
> Quoting Hirokazu Honda (2021-11-01 07:16:52)
> > After we unify identical streams to one stream configuration, the
> > capture requested by a HAL client can have been resolved as
> > CameraStream::Mapped. That is, a buffer to be written by a camera
> > is not provided by a client. We would handle this case by
> > dynamically allocating FrameBuffer.
> >
> > The existing FrameBufferAllocator cannot used because it 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 <hiroh@chromium.org>
>
> I'm finding this one harder to grasp. It's late so I think I might have
> to continue tomorrow.
>
> I wish we had better infrastructure for unit tests on the Android layer,
> as I'm sure some of this would benefit from more tests, but even then
> we'd have to have an environment to run the unit tests against the
> allocators...
>
>
> > ---
> >  src/android/frame_buffer_allocator.h          |  54 +++++++
> >  .../mm/cros_frame_buffer_allocator.cpp        |  90 +++++++++++
> >  .../mm/generic_frame_buffer_allocator.cpp     | 144 ++++++++++++++++++
> >  src/android/mm/meson.build                    |   6 +-
> >  4 files changed, 292 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
> >
> > diff --git a/src/android/frame_buffer_allocator.h b/src/android/frame_buffer_allocator.h
> > new file mode 100644
> > index 00000000..41ed4ae1
> > --- /dev/null
> > +++ b/src/android/frame_buffer_allocator.h
> > @@ -0,0 +1,54 @@
> > +/* 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 <memory>
> > +
> > +#include <libcamera/base/class.h>
> > +#include <libcamera/camera.h>
> > +#include <libcamera/framebuffer.h>
> > +#include <libcamera/geometry.h>
> > +
> > +class CameraDevice;
> > +
> > +class PlatformFrameBufferAllocator : libcamera::Extensible
>
> Does the 'PlatformFrameBufferAllocater' benefit from using Extensible?
> Is it required somehow? Can't it just be a normal class that the CrOS
> and Android variants inherit from?
>

I followed CameraBuffer design pattern here.
I am fine to make them normal classes.
How shall I decide which to be used in run time?

-Hiro
>
> > +{
> > +       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<libcamera::FrameBuffer> 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<Private>(this, cameraDevice))     \
> > +{                                                                      \
> > +}                                                                      \
> > +PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator()          \
> > +{                                                                      \
> > +}                                                                      \
> > +std::unique_ptr<libcamera::FrameBuffer>                                        \
> > +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..9c7e4ea4
> > --- /dev/null
> > +++ b/src/android/mm/cros_frame_buffer_allocator.cpp
> > @@ -0,0 +1,90 @@
> > +/* 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 <memory>
> > +#include <vector>
> > +
> > +#include <libcamera/base/log.h>
> > +
> > +#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))
> > +       {
> > +       }
> > +
> > +       ~CrosFrameBufferData() override = default;
> > +
> > +private:
> > +       cros::ScopedBufferHandle scopedHandle_;
> > +};
> > +} /* namespace */
> > +
> > +class PlatformFrameBufferAllocator::Private : public Extensible::Private
> > +{
> > +       LIBCAMERA_DECLARE_PUBLIC(PlatformFrameBufferAllocator)
> > +
> > +public:
> > +       Private([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> > +               [[maybe_unused]] CameraDevice *const cameraDevice)
> > +       {
> > +       }
> > +
> > +       ~Private() override = default;
> > +
> > +       std::unique_ptr<libcamera::FrameBuffer> allocate(
> > +               int halPixelFormat, const libcamera::Size &size, uint32_t usage);
> > +};
> > +
> > +std::unique_ptr<libcamera::FrameBuffer>
> > +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;
> > +       const size_t numPlanes = cros::CameraBufferManager::GetNumPlanes(handle);
> > +       std::vector<FrameBuffer::Plane> planes(numPlanes);
> > +       FileDescriptor 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. */
> > +       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<FrameBuffer>(
> > +               std::make_unique<CrosFrameBufferData>(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..167cc1a5
> > --- /dev/null
> > +++ b/src/android/mm/generic_frame_buffer_allocator.cpp
> > @@ -0,0 +1,144 @@
> > +/* 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/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.
> > +                *
> > +                * Q: Thread safety against alloc_device_t is not documented.
> > +                * Is it no problem to call alloc/free in parallel?
> > +                */
> > +               ASSERT(allocDevice_);
> > +               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([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> > +               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 allocating: " << ret;
> > +               return nullptr;
> > +       }
> > +       if (!handle) {
> > +               LOG(HAL, Fatal) << "buffer_handle_t is empty on success";
> > +               return nullptr;
> > +       }
> > +
> > +       const libcamera::PixelFormat pixelFormat =
> > +               cameraDevice_->capabilities()->toPixelFormat(halPixelFormat);
> > +       const auto &info = PixelFormatInfo::info(pixelFormat);
> > +       const unsigned int numPlanes = info.numPlanes();
> > +       std::vector<FrameBuffer::Plane> planes(numPlanes);
> > +
> > +       /* This code assumes the planes are mapped consecutively. */
> > +       FileDescriptor 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);
> > +
> > +               planes[i].fd = fd;
> > +               planes[i].offset = offset;
> > +               planes[i].length = planeSize;
> > +               offset += planeSize;
> > +       }
> > +
> > +       return std::make_unique<FrameBuffer>(
> > +               std::make_unique<GenericFrameBufferData>(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
> > --
> > 2.33.1.1089.g2158813163f-goog
> >
Jacopo Mondi Nov. 9, 2021, 8:57 a.m. UTC | #3
Hello

On Tue, Nov 09, 2021 at 02:46:14PM +0900, Hirokazu Honda wrote:
> Hi Kieran,
>
> On Tue, Nov 9, 2021 at 8:26 AM Kieran Bingham
> <kieran.bingham@ideasonboard.com> wrote:
> >
> > Quoting Hirokazu Honda (2021-11-01 07:16:52)
> > > After we unify identical streams to one stream configuration, the
> > > capture requested by a HAL client can have been resolved as
> > > CameraStream::Mapped. That is, a buffer to be written by a camera
> > > is not provided by a client. We would handle this case by
> > > dynamically allocating FrameBuffer.
> > >
> > > The existing FrameBufferAllocator cannot used because it 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 <hiroh@chromium.org>
> >
> > I'm finding this one harder to grasp. It's late so I think I might have
> > to continue tomorrow.
> >
> > I wish we had better infrastructure for unit tests on the Android layer,
> > as I'm sure some of this would benefit from more tests, but even then
> > we'd have to have an environment to run the unit tests against the
> > allocators...
> >
> >
> > > ---
> > >  src/android/frame_buffer_allocator.h          |  54 +++++++
> > >  .../mm/cros_frame_buffer_allocator.cpp        |  90 +++++++++++
> > >  .../mm/generic_frame_buffer_allocator.cpp     | 144 ++++++++++++++++++
> > >  src/android/mm/meson.build                    |   6 +-
> > >  4 files changed, 292 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
> > >
> > > diff --git a/src/android/frame_buffer_allocator.h b/src/android/frame_buffer_allocator.h
> > > new file mode 100644
> > > index 00000000..41ed4ae1
> > > --- /dev/null
> > > +++ b/src/android/frame_buffer_allocator.h
> > > @@ -0,0 +1,54 @@
> > > +/* 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 <memory>
> > > +
> > > +#include <libcamera/base/class.h>
> > > +#include <libcamera/camera.h>
> > > +#include <libcamera/framebuffer.h>
> > > +#include <libcamera/geometry.h>
> > > +
> > > +class CameraDevice;
> > > +
> > > +class PlatformFrameBufferAllocator : libcamera::Extensible
> >
> > Does the 'PlatformFrameBufferAllocater' benefit from using Extensible?
> > Is it required somehow? Can't it just be a normal class that the CrOS
> > and Android variants inherit from?
> >
>
> I followed CameraBuffer design pattern here.
> I am fine to make them normal classes.
> How shall I decide which to be used in run time?
>

I think compile time selection like it's done for CameraBuffer is
better and I don't see what benefit would bring removing the Extensible
pattern.

Thanks
   j

> -Hiro
> >
> > > +{
> > > +       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<libcamera::FrameBuffer> 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<Private>(this, cameraDevice))     \
> > > +{                                                                      \
> > > +}                                                                      \
> > > +PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator()          \
> > > +{                                                                      \
> > > +}                                                                      \
> > > +std::unique_ptr<libcamera::FrameBuffer>                                        \
> > > +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..9c7e4ea4
> > > --- /dev/null
> > > +++ b/src/android/mm/cros_frame_buffer_allocator.cpp
> > > @@ -0,0 +1,90 @@
> > > +/* 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 <memory>
> > > +#include <vector>
> > > +
> > > +#include <libcamera/base/log.h>
> > > +
> > > +#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))
> > > +       {
> > > +       }
> > > +
> > > +       ~CrosFrameBufferData() override = default;
> > > +
> > > +private:
> > > +       cros::ScopedBufferHandle scopedHandle_;
> > > +};
> > > +} /* namespace */
> > > +
> > > +class PlatformFrameBufferAllocator::Private : public Extensible::Private
> > > +{
> > > +       LIBCAMERA_DECLARE_PUBLIC(PlatformFrameBufferAllocator)
> > > +
> > > +public:
> > > +       Private([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> > > +               [[maybe_unused]] CameraDevice *const cameraDevice)
> > > +       {
> > > +       }
> > > +
> > > +       ~Private() override = default;
> > > +
> > > +       std::unique_ptr<libcamera::FrameBuffer> allocate(
> > > +               int halPixelFormat, const libcamera::Size &size, uint32_t usage);
> > > +};
> > > +
> > > +std::unique_ptr<libcamera::FrameBuffer>
> > > +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;
> > > +       const size_t numPlanes = cros::CameraBufferManager::GetNumPlanes(handle);
> > > +       std::vector<FrameBuffer::Plane> planes(numPlanes);
> > > +       FileDescriptor 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. */
> > > +       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<FrameBuffer>(
> > > +               std::make_unique<CrosFrameBufferData>(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..167cc1a5
> > > --- /dev/null
> > > +++ b/src/android/mm/generic_frame_buffer_allocator.cpp
> > > @@ -0,0 +1,144 @@
> > > +/* 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/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.
> > > +                *
> > > +                * Q: Thread safety against alloc_device_t is not documented.
> > > +                * Is it no problem to call alloc/free in parallel?
> > > +                */
> > > +               ASSERT(allocDevice_);
> > > +               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([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> > > +               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 allocating: " << ret;
> > > +               return nullptr;
> > > +       }
> > > +       if (!handle) {
> > > +               LOG(HAL, Fatal) << "buffer_handle_t is empty on success";
> > > +               return nullptr;
> > > +       }
> > > +
> > > +       const libcamera::PixelFormat pixelFormat =
> > > +               cameraDevice_->capabilities()->toPixelFormat(halPixelFormat);
> > > +       const auto &info = PixelFormatInfo::info(pixelFormat);
> > > +       const unsigned int numPlanes = info.numPlanes();
> > > +       std::vector<FrameBuffer::Plane> planes(numPlanes);
> > > +
> > > +       /* This code assumes the planes are mapped consecutively. */
> > > +       FileDescriptor 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);
> > > +
> > > +               planes[i].fd = fd;
> > > +               planes[i].offset = offset;
> > > +               planes[i].length = planeSize;
> > > +               offset += planeSize;
> > > +       }
> > > +
> > > +       return std::make_unique<FrameBuffer>(
> > > +               std::make_unique<GenericFrameBufferData>(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
> > > --
> > > 2.33.1.1089.g2158813163f-goog
> > >
Kieran Bingham Nov. 9, 2021, 10:14 a.m. UTC | #4
Quoting Jacopo Mondi (2021-11-09 08:57:26)
> Hello
> 
> On Tue, Nov 09, 2021 at 02:46:14PM +0900, Hirokazu Honda wrote:
> > Hi Kieran,
> >
> > On Tue, Nov 9, 2021 at 8:26 AM Kieran Bingham
> > <kieran.bingham@ideasonboard.com> wrote:
> > >
> > > Quoting Hirokazu Honda (2021-11-01 07:16:52)
> > > > After we unify identical streams to one stream configuration, the
> > > > capture requested by a HAL client can have been resolved as
> > > > CameraStream::Mapped. That is, a buffer to be written by a camera
> > > > is not provided by a client. We would handle this case by
> > > > dynamically allocating FrameBuffer.
> > > >
> > > > The existing FrameBufferAllocator cannot used because it 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 <hiroh@chromium.org>
> > >
> > > I'm finding this one harder to grasp. It's late so I think I might have
> > > to continue tomorrow.
> > >
> > > I wish we had better infrastructure for unit tests on the Android layer,
> > > as I'm sure some of this would benefit from more tests, but even then
> > > we'd have to have an environment to run the unit tests against the
> > > allocators...
> > >
> > >
> > > > ---
> > > >  src/android/frame_buffer_allocator.h          |  54 +++++++
> > > >  .../mm/cros_frame_buffer_allocator.cpp        |  90 +++++++++++
> > > >  .../mm/generic_frame_buffer_allocator.cpp     | 144 ++++++++++++++++++
> > > >  src/android/mm/meson.build                    |   6 +-
> > > >  4 files changed, 292 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
> > > >
> > > > diff --git a/src/android/frame_buffer_allocator.h b/src/android/frame_buffer_allocator.h
> > > > new file mode 100644
> > > > index 00000000..41ed4ae1
> > > > --- /dev/null
> > > > +++ b/src/android/frame_buffer_allocator.h
> > > > @@ -0,0 +1,54 @@
> > > > +/* 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 <memory>
> > > > +
> > > > +#include <libcamera/base/class.h>
> > > > +#include <libcamera/camera.h>
> > > > +#include <libcamera/framebuffer.h>
> > > > +#include <libcamera/geometry.h>
> > > > +
> > > > +class CameraDevice;
> > > > +
> > > > +class PlatformFrameBufferAllocator : libcamera::Extensible
> > >
> > > Does the 'PlatformFrameBufferAllocater' benefit from using Extensible?
> > > Is it required somehow? Can't it just be a normal class that the CrOS
> > > and Android variants inherit from?
> > >
> >
> > I followed CameraBuffer design pattern here.
> > I am fine to make them normal classes.
> > How shall I decide which to be used in run time?
> >
> 
> I think compile time selection like it's done for CameraBuffer is
> better and I don't see what benefit would bring removing the Extensible
> pattern.

Aha, that's the part I'd missed last night. Yes this is fine for
Extensible I think.

 
> Thanks
>    j
> 
> > -Hiro
> > >
> > > > +{
> > > > +       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<libcamera::FrameBuffer> 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<Private>(this, cameraDevice))     \
> > > > +{                                                                      \
> > > > +}                                                                      \
> > > > +PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator()          \
> > > > +{                                                                      \
> > > > +}                                                                      \
> > > > +std::unique_ptr<libcamera::FrameBuffer>                                        \
> > > > +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..9c7e4ea4
> > > > --- /dev/null
> > > > +++ b/src/android/mm/cros_frame_buffer_allocator.cpp
> > > > @@ -0,0 +1,90 @@
> > > > +/* 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 <memory>
> > > > +#include <vector>
> > > > +
> > > > +#include <libcamera/base/log.h>
> > > > +
> > > > +#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))
> > > > +       {
> > > > +       }
> > > > +
> > > > +       ~CrosFrameBufferData() override = default;
> > > > +
> > > > +private:
> > > > +       cros::ScopedBufferHandle scopedHandle_;
> > > > +};
> > > > +} /* namespace */
> > > > +
> > > > +class PlatformFrameBufferAllocator::Private : public Extensible::Private
> > > > +{
> > > > +       LIBCAMERA_DECLARE_PUBLIC(PlatformFrameBufferAllocator)
> > > > +
> > > > +public:
> > > > +       Private([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> > > > +               [[maybe_unused]] CameraDevice *const cameraDevice)
> > > > +       {
> > > > +       }
> > > > +
> > > > +       ~Private() override = default;
> > > > +
> > > > +       std::unique_ptr<libcamera::FrameBuffer> allocate(
> > > > +               int halPixelFormat, const libcamera::Size &size, uint32_t usage);
> > > > +};
> > > > +
> > > > +std::unique_ptr<libcamera::FrameBuffer>
> > > > +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;
> > > > +       const size_t numPlanes = cros::CameraBufferManager::GetNumPlanes(handle);
> > > > +       std::vector<FrameBuffer::Plane> planes(numPlanes);
> > > > +       FileDescriptor 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. */
> > > > +       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<FrameBuffer>(
> > > > +               std::make_unique<CrosFrameBufferData>(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..167cc1a5
> > > > --- /dev/null
> > > > +++ b/src/android/mm/generic_frame_buffer_allocator.cpp
> > > > @@ -0,0 +1,144 @@
> > > > +/* 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/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.
> > > > +                *
> > > > +                * Q: Thread safety against alloc_device_t is not documented.
> > > > +                * Is it no problem to call alloc/free in parallel?
> > > > +                */
> > > > +               ASSERT(allocDevice_);
> > > > +               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([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> > > > +               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 allocating: " << ret;
> > > > +               return nullptr;
> > > > +       }
> > > > +       if (!handle) {
> > > > +               LOG(HAL, Fatal) << "buffer_handle_t is empty on success";
> > > > +               return nullptr;
> > > > +       }
> > > > +
> > > > +       const libcamera::PixelFormat pixelFormat =
> > > > +               cameraDevice_->capabilities()->toPixelFormat(halPixelFormat);
> > > > +       const auto &info = PixelFormatInfo::info(pixelFormat);
> > > > +       const unsigned int numPlanes = info.numPlanes();
> > > > +       std::vector<FrameBuffer::Plane> planes(numPlanes);
> > > > +
> > > > +       /* This code assumes the planes are mapped consecutively. */
> > > > +       FileDescriptor 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);
> > > > +
> > > > +               planes[i].fd = fd;
> > > > +               planes[i].offset = offset;
> > > > +               planes[i].length = planeSize;
> > > > +               offset += planeSize;
> > > > +       }
> > > > +
> > > > +       return std::make_unique<FrameBuffer>(
> > > > +               std::make_unique<GenericFrameBufferData>(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
> > > > --
> > > > 2.33.1.1089.g2158813163f-goog
> > > >
Kieran Bingham Nov. 9, 2021, 8:31 p.m. UTC | #5
Quoting Kieran Bingham (2021-11-09 10:14:19)
> Quoting Jacopo Mondi (2021-11-09 08:57:26)
> > Hello
> > 
> > On Tue, Nov 09, 2021 at 02:46:14PM +0900, Hirokazu Honda wrote:
> > > Hi Kieran,
> > >
> > > On Tue, Nov 9, 2021 at 8:26 AM Kieran Bingham
> > > <kieran.bingham@ideasonboard.com> wrote:
> > > >
> > > > Quoting Hirokazu Honda (2021-11-01 07:16:52)
> > > > > After we unify identical streams to one stream configuration, the
> > > > > capture requested by a HAL client can have been resolved as
> > > > > CameraStream::Mapped. That is, a buffer to be written by a camera
> > > > > is not provided by a client. We would handle this case by
> > > > > dynamically allocating FrameBuffer.
> > > > >
> > > > > The existing FrameBufferAllocator cannot used because it 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 <hiroh@chromium.org>
> > > >
> > > > I'm finding this one harder to grasp. It's late so I think I might have
> > > > to continue tomorrow.
> > > >
> > > > I wish we had better infrastructure for unit tests on the Android layer,
> > > > as I'm sure some of this would benefit from more tests, but even then
> > > > we'd have to have an environment to run the unit tests against the
> > > > allocators...
> > > >
> > > >
> > > > > ---
> > > > >  src/android/frame_buffer_allocator.h          |  54 +++++++
> > > > >  .../mm/cros_frame_buffer_allocator.cpp        |  90 +++++++++++
> > > > >  .../mm/generic_frame_buffer_allocator.cpp     | 144 ++++++++++++++++++
> > > > >  src/android/mm/meson.build                    |   6 +-
> > > > >  4 files changed, 292 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
> > > > >
> > > > > diff --git a/src/android/frame_buffer_allocator.h b/src/android/frame_buffer_allocator.h
> > > > > new file mode 100644
> > > > > index 00000000..41ed4ae1
> > > > > --- /dev/null
> > > > > +++ b/src/android/frame_buffer_allocator.h
> > > > > @@ -0,0 +1,54 @@
> > > > > +/* 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 <memory>
> > > > > +
> > > > > +#include <libcamera/base/class.h>
> > > > > +#include <libcamera/camera.h>
> > > > > +#include <libcamera/framebuffer.h>
> > > > > +#include <libcamera/geometry.h>
> > > > > +
> > > > > +class CameraDevice;
> > > > > +
> > > > > +class PlatformFrameBufferAllocator : libcamera::Extensible
> > > >
> > > > Does the 'PlatformFrameBufferAllocater' benefit from using Extensible?
> > > > Is it required somehow? Can't it just be a normal class that the CrOS
> > > > and Android variants inherit from?
> > > >
> > >
> > > I followed CameraBuffer design pattern here.
> > > I am fine to make them normal classes.
> > > How shall I decide which to be used in run time?
> > >
> > 
> > I think compile time selection like it's done for CameraBuffer is
> > better and I don't see what benefit would bring removing the Extensible
> > pattern.
> 
> Aha, that's the part I'd missed last night. Yes this is fine for
> Extensible I think.

In fact, it doesn't matter too much - but I still don't see why this
needs to be Extensible.

The implementation for PlatformFrameBufferAllocator can have an
identically named class in both 
	src/android/mm/cros_frame_buffer_allocator.cpp
	src/android/mm/generic_frame_buffer_allocator.cpp

And the one that gets used will be the one that is compiled in...?


> > Thanks
> >    j
> > 
> > > -Hiro
> > > >
> > > > > +{
> > > > > +       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<libcamera::FrameBuffer> 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<Private>(this, cameraDevice))     \
> > > > > +{                                                                      \
> > > > > +}                                                                      \
> > > > > +PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator()          \
> > > > > +{                                                                      \
> > > > > +}                                                                      \
> > > > > +std::unique_ptr<libcamera::FrameBuffer>                                        \
> > > > > +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..9c7e4ea4
> > > > > --- /dev/null
> > > > > +++ b/src/android/mm/cros_frame_buffer_allocator.cpp
> > > > > @@ -0,0 +1,90 @@
> > > > > +/* 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 <memory>
> > > > > +#include <vector>
> > > > > +
> > > > > +#include <libcamera/base/log.h>
> > > > > +
> > > > > +#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))
> > > > > +       {
> > > > > +       }
> > > > > +
> > > > > +       ~CrosFrameBufferData() override = default;
> > > > > +
> > > > > +private:
> > > > > +       cros::ScopedBufferHandle scopedHandle_;
> > > > > +};
> > > > > +} /* namespace */
> > > > > +
> > > > > +class PlatformFrameBufferAllocator::Private : public Extensible::Private
> > > > > +{
> > > > > +       LIBCAMERA_DECLARE_PUBLIC(PlatformFrameBufferAllocator)
> > > > > +
> > > > > +public:
> > > > > +       Private([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> > > > > +               [[maybe_unused]] CameraDevice *const cameraDevice)
> > > > > +       {
> > > > > +       }
> > > > > +
> > > > > +       ~Private() override = default;
> > > > > +
> > > > > +       std::unique_ptr<libcamera::FrameBuffer> allocate(
> > > > > +               int halPixelFormat, const libcamera::Size &size, uint32_t usage);
> > > > > +};
> > > > > +
> > > > > +std::unique_ptr<libcamera::FrameBuffer>
> > > > > +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;
> > > > > +       const size_t numPlanes = cros::CameraBufferManager::GetNumPlanes(handle);
> > > > > +       std::vector<FrameBuffer::Plane> planes(numPlanes);
> > > > > +       FileDescriptor 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. */
> > > > > +       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<FrameBuffer>(
> > > > > +               std::make_unique<CrosFrameBufferData>(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..167cc1a5
> > > > > --- /dev/null
> > > > > +++ b/src/android/mm/generic_frame_buffer_allocator.cpp
> > > > > @@ -0,0 +1,144 @@
> > > > > +/* 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/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.
> > > > > +                *
> > > > > +                * Q: Thread safety against alloc_device_t is not documented.
> > > > > +                * Is it no problem to call alloc/free in parallel?
> > > > > +                */
> > > > > +               ASSERT(allocDevice_);
> > > > > +               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([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> > > > > +               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 allocating: " << ret;
> > > > > +               return nullptr;
> > > > > +       }
> > > > > +       if (!handle) {
> > > > > +               LOG(HAL, Fatal) << "buffer_handle_t is empty on success";
> > > > > +               return nullptr;
> > > > > +       }
> > > > > +
> > > > > +       const libcamera::PixelFormat pixelFormat =
> > > > > +               cameraDevice_->capabilities()->toPixelFormat(halPixelFormat);
> > > > > +       const auto &info = PixelFormatInfo::info(pixelFormat);
> > > > > +       const unsigned int numPlanes = info.numPlanes();
> > > > > +       std::vector<FrameBuffer::Plane> planes(numPlanes);
> > > > > +
> > > > > +       /* This code assumes the planes are mapped consecutively. */
> > > > > +       FileDescriptor 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);
> > > > > +
> > > > > +               planes[i].fd = fd;
> > > > > +               planes[i].offset = offset;
> > > > > +               planes[i].length = planeSize;
> > > > > +               offset += planeSize;
> > > > > +       }
> > > > > +
> > > > > +       return std::make_unique<FrameBuffer>(
> > > > > +               std::make_unique<GenericFrameBufferData>(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
> > > > > --
> > > > > 2.33.1.1089.g2158813163f-goog
> > > > >
Hirokazu Honda Nov. 10, 2021, 3:09 a.m. UTC | #6
Hi Kieran,


On Wed, Nov 10, 2021 at 5:31 AM Kieran Bingham
<kieran.bingham@ideasonboard.com> wrote:
>
> Quoting Kieran Bingham (2021-11-09 10:14:19)
> > Quoting Jacopo Mondi (2021-11-09 08:57:26)
> > > Hello
> > >
> > > On Tue, Nov 09, 2021 at 02:46:14PM +0900, Hirokazu Honda wrote:
> > > > Hi Kieran,
> > > >
> > > > On Tue, Nov 9, 2021 at 8:26 AM Kieran Bingham
> > > > <kieran.bingham@ideasonboard.com> wrote:
> > > > >
> > > > > Quoting Hirokazu Honda (2021-11-01 07:16:52)
> > > > > > After we unify identical streams to one stream configuration, the
> > > > > > capture requested by a HAL client can have been resolved as
> > > > > > CameraStream::Mapped. That is, a buffer to be written by a camera
> > > > > > is not provided by a client. We would handle this case by
> > > > > > dynamically allocating FrameBuffer.
> > > > > >
> > > > > > The existing FrameBufferAllocator cannot used because it 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 <hiroh@chromium.org>
> > > > >
> > > > > I'm finding this one harder to grasp. It's late so I think I might have
> > > > > to continue tomorrow.
> > > > >
> > > > > I wish we had better infrastructure for unit tests on the Android layer,
> > > > > as I'm sure some of this would benefit from more tests, but even then
> > > > > we'd have to have an environment to run the unit tests against the
> > > > > allocators...
> > > > >
> > > > >
> > > > > > ---
> > > > > >  src/android/frame_buffer_allocator.h          |  54 +++++++
> > > > > >  .../mm/cros_frame_buffer_allocator.cpp        |  90 +++++++++++
> > > > > >  .../mm/generic_frame_buffer_allocator.cpp     | 144 ++++++++++++++++++
> > > > > >  src/android/mm/meson.build                    |   6 +-
> > > > > >  4 files changed, 292 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
> > > > > >
> > > > > > diff --git a/src/android/frame_buffer_allocator.h b/src/android/frame_buffer_allocator.h
> > > > > > new file mode 100644
> > > > > > index 00000000..41ed4ae1
> > > > > > --- /dev/null
> > > > > > +++ b/src/android/frame_buffer_allocator.h
> > > > > > @@ -0,0 +1,54 @@
> > > > > > +/* 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 <memory>
> > > > > > +
> > > > > > +#include <libcamera/base/class.h>
> > > > > > +#include <libcamera/camera.h>
> > > > > > +#include <libcamera/framebuffer.h>
> > > > > > +#include <libcamera/geometry.h>
> > > > > > +
> > > > > > +class CameraDevice;
> > > > > > +
> > > > > > +class PlatformFrameBufferAllocator : libcamera::Extensible
> > > > >
> > > > > Does the 'PlatformFrameBufferAllocater' benefit from using Extensible?
> > > > > Is it required somehow? Can't it just be a normal class that the CrOS
> > > > > and Android variants inherit from?
> > > > >
> > > >
> > > > I followed CameraBuffer design pattern here.
> > > > I am fine to make them normal classes.
> > > > How shall I decide which to be used in run time?
> > > >
> > >
> > > I think compile time selection like it's done for CameraBuffer is
> > > better and I don't see what benefit would bring removing the Extensible
> > > pattern.
> >
> > Aha, that's the part I'd missed last night. Yes this is fine for
> > Extensible I think.
>
> In fact, it doesn't matter too much - but I still don't see why this
> needs to be Extensible.
>
> The implementation for PlatformFrameBufferAllocator can have an
> identically named class in both
>         src/android/mm/cros_frame_buffer_allocator.cpp
>         src/android/mm/generic_frame_buffer_allocator.cpp
>
> And the one that gets used will be the one that is compiled in...?
>

That's a good point. I couldn't find a reason for this.
If this is applicable for PlatformFrameBufferAllocator, I think we can
change CameraBuffer too.

-Hiro
>
> > > Thanks
> > >    j
> > >
> > > > -Hiro
> > > > >
> > > > > > +{
> > > > > > +       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<libcamera::FrameBuffer> 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<Private>(this, cameraDevice))     \
> > > > > > +{                                                                      \
> > > > > > +}                                                                      \
> > > > > > +PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator()          \
> > > > > > +{                                                                      \
> > > > > > +}                                                                      \
> > > > > > +std::unique_ptr<libcamera::FrameBuffer>                                        \
> > > > > > +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..9c7e4ea4
> > > > > > --- /dev/null
> > > > > > +++ b/src/android/mm/cros_frame_buffer_allocator.cpp
> > > > > > @@ -0,0 +1,90 @@
> > > > > > +/* 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 <memory>
> > > > > > +#include <vector>
> > > > > > +
> > > > > > +#include <libcamera/base/log.h>
> > > > > > +
> > > > > > +#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))
> > > > > > +       {
> > > > > > +       }
> > > > > > +
> > > > > > +       ~CrosFrameBufferData() override = default;
> > > > > > +
> > > > > > +private:
> > > > > > +       cros::ScopedBufferHandle scopedHandle_;
> > > > > > +};
> > > > > > +} /* namespace */
> > > > > > +
> > > > > > +class PlatformFrameBufferAllocator::Private : public Extensible::Private
> > > > > > +{
> > > > > > +       LIBCAMERA_DECLARE_PUBLIC(PlatformFrameBufferAllocator)
> > > > > > +
> > > > > > +public:
> > > > > > +       Private([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> > > > > > +               [[maybe_unused]] CameraDevice *const cameraDevice)
> > > > > > +       {
> > > > > > +       }
> > > > > > +
> > > > > > +       ~Private() override = default;
> > > > > > +
> > > > > > +       std::unique_ptr<libcamera::FrameBuffer> allocate(
> > > > > > +               int halPixelFormat, const libcamera::Size &size, uint32_t usage);
> > > > > > +};
> > > > > > +
> > > > > > +std::unique_ptr<libcamera::FrameBuffer>
> > > > > > +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;
> > > > > > +       const size_t numPlanes = cros::CameraBufferManager::GetNumPlanes(handle);
> > > > > > +       std::vector<FrameBuffer::Plane> planes(numPlanes);
> > > > > > +       FileDescriptor 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. */
> > > > > > +       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<FrameBuffer>(
> > > > > > +               std::make_unique<CrosFrameBufferData>(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..167cc1a5
> > > > > > --- /dev/null
> > > > > > +++ b/src/android/mm/generic_frame_buffer_allocator.cpp
> > > > > > @@ -0,0 +1,144 @@
> > > > > > +/* 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/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.
> > > > > > +                *
> > > > > > +                * Q: Thread safety against alloc_device_t is not documented.
> > > > > > +                * Is it no problem to call alloc/free in parallel?
> > > > > > +                */
> > > > > > +               ASSERT(allocDevice_);
> > > > > > +               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([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> > > > > > +               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 allocating: " << ret;
> > > > > > +               return nullptr;
> > > > > > +       }
> > > > > > +       if (!handle) {
> > > > > > +               LOG(HAL, Fatal) << "buffer_handle_t is empty on success";
> > > > > > +               return nullptr;
> > > > > > +       }
> > > > > > +
> > > > > > +       const libcamera::PixelFormat pixelFormat =
> > > > > > +               cameraDevice_->capabilities()->toPixelFormat(halPixelFormat);
> > > > > > +       const auto &info = PixelFormatInfo::info(pixelFormat);
> > > > > > +       const unsigned int numPlanes = info.numPlanes();
> > > > > > +       std::vector<FrameBuffer::Plane> planes(numPlanes);
> > > > > > +
> > > > > > +       /* This code assumes the planes are mapped consecutively. */
> > > > > > +       FileDescriptor 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);
> > > > > > +
> > > > > > +               planes[i].fd = fd;
> > > > > > +               planes[i].offset = offset;
> > > > > > +               planes[i].length = planeSize;
> > > > > > +               offset += planeSize;
> > > > > > +       }
> > > > > > +
> > > > > > +       return std::make_unique<FrameBuffer>(
> > > > > > +               std::make_unique<GenericFrameBufferData>(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
> > > > > > --
> > > > > > 2.33.1.1089.g2158813163f-goog
> > > > > >
Kieran Bingham Nov. 17, 2021, 6:02 p.m. UTC | #7
Quoting Hirokazu Honda (2021-11-10 03:09:34)
> Hi Kieran,
> 
> > In fact, it doesn't matter too much - but I still don't see why this
> > needs to be Extensible.
> >
> > The implementation for PlatformFrameBufferAllocator can have an
> > identically named class in both
> >         src/android/mm/cros_frame_buffer_allocator.cpp
> >         src/android/mm/generic_frame_buffer_allocator.cpp
> >
> > And the one that gets used will be the one that is compiled in...?
> >
> 
> That's a good point. I couldn't find a reason for this.
> If this is applicable for PlatformFrameBufferAllocator, I think we can
> change CameraBuffer too.

Sure, if it simplifies things. The class is not a public API, and
doesn't need to be 'extensible' with a private implementation as far as
I am aware. In this case, it's just that there are two possible
implementations which are selected at compile time anyway.

--
Kieran
Hirokazu Honda Nov. 18, 2021, 8:13 a.m. UTC | #8
On Thu, Nov 18, 2021 at 3:02 AM Kieran Bingham
<kieran.bingham@ideasonboard.com> wrote:
>
> Quoting Hirokazu Honda (2021-11-10 03:09:34)
> > Hi Kieran,
> >
> > > In fact, it doesn't matter too much - but I still don't see why this
> > > needs to be Extensible.
> > >
> > > The implementation for PlatformFrameBufferAllocator can have an
> > > identically named class in both
> > >         src/android/mm/cros_frame_buffer_allocator.cpp
> > >         src/android/mm/generic_frame_buffer_allocator.cpp
> > >
> > > And the one that gets used will be the one that is compiled in...?
> > >
> >
> > That's a good point. I couldn't find a reason for this.
> > If this is applicable for PlatformFrameBufferAllocator, I think we can
> > change CameraBuffer too.
>
> Sure, if it simplifies things. The class is not a public API, and
> doesn't need to be 'extensible' with a private implementation as far as
> I am aware. In this case, it's just that there are two possible
> implementations which are selected at compile time anyway.
>

+Laurent Pinchart , can I implement so?
Why is CameraBuffer designed so?

-Hiro
> --
> Kieran
Jacopo Mondi Nov. 18, 2021, 8:44 a.m. UTC | #9
Hi Hiro,

On Thu, Nov 18, 2021 at 05:13:29PM +0900, Hirokazu Honda wrote:
> On Thu, Nov 18, 2021 at 3:02 AM Kieran Bingham
> <kieran.bingham@ideasonboard.com> wrote:
> >
> > Quoting Hirokazu Honda (2021-11-10 03:09:34)
> > > Hi Kieran,
> > >
> > > > In fact, it doesn't matter too much - but I still don't see why this
> > > > needs to be Extensible.
> > > >
> > > > The implementation for PlatformFrameBufferAllocator can have an
> > > > identically named class in both
> > > >         src/android/mm/cros_frame_buffer_allocator.cpp
> > > >         src/android/mm/generic_frame_buffer_allocator.cpp
> > > >
> > > > And the one that gets used will be the one that is compiled in...?
> > > >
> > >
> > > That's a good point. I couldn't find a reason for this.
> > > If this is applicable for PlatformFrameBufferAllocator, I think we can
> > > change CameraBuffer too.
> >
> > Sure, if it simplifies things. The class is not a public API, and
> > doesn't need to be 'extensible' with a private implementation as far as
> > I am aware. In this case, it's just that there are two possible
> > implementations which are selected at compile time anyway.
> >
>
> +Laurent Pinchart , can I implement so?
> Why is CameraBuffer designed so?
>

At the time I designed CameraBuffer using Extensible seemed like a
good idea. I had probably been lazy as there might be more opportune
patterns.

What I was looking for was a mechanism that

- Allows to define a standard and unique interface for the
  CameraManager to interface with
- Had a compile-time selectable implementation
- Allowed to not pollute the shared interface with details of the
  implementation

I evaluated making use of a more canonical class hierarchy, and I
considered:

a) A single .h file that defines the interface, multiple .cpp that
  implement it selected at compile time.

  I considered that Extensible would have left more room for
  implementation-specificities in the Private class interface,
  allowing more flexibility and wouldn't have requried
  implementation-specific details to surface in the interface. This
  mostly apply to the implementation-specific data, which Extensible
  allows to easy model in the Private subclass.

  Different .h is not an option and keeping them in sync with the
  common user would be painful

b) A canonical class hierarchy where the 'right' sub-class would be
  instantiated at run time, but I ditched that as it would have
  required #ifdefs in the code which I would prefer not to.

There surely are better solution, as your implementation shows
details and requirement of a specific implementation are surfacing to
the interface as well, so this can be surely improved with some more
opportune design pattern.

That said, I won't be too much concerned. The pattern is there and is
in use, simply replacing it with a) won't bring much value, so I would
say do whatever is faster for you and if we find a more elegant
solution we'll change both BufferAllocator and CameraBuffer in one
go.

-

> -Hiro
> > --
> > Kieran
Hirokazu Honda Nov. 18, 2021, 8:50 a.m. UTC | #10
Hi Jacopo,

On Thu, Nov 18, 2021 at 5:43 PM Jacopo Mondi <jacopo@jmondi.org> wrote:
>
> Hi Hiro,
>
> On Thu, Nov 18, 2021 at 05:13:29PM +0900, Hirokazu Honda wrote:
> > On Thu, Nov 18, 2021 at 3:02 AM Kieran Bingham
> > <kieran.bingham@ideasonboard.com> wrote:
> > >
> > > Quoting Hirokazu Honda (2021-11-10 03:09:34)
> > > > Hi Kieran,
> > > >
> > > > > In fact, it doesn't matter too much - but I still don't see why this
> > > > > needs to be Extensible.
> > > > >
> > > > > The implementation for PlatformFrameBufferAllocator can have an
> > > > > identically named class in both
> > > > >         src/android/mm/cros_frame_buffer_allocator.cpp
> > > > >         src/android/mm/generic_frame_buffer_allocator.cpp
> > > > >
> > > > > And the one that gets used will be the one that is compiled in...?
> > > > >
> > > >
> > > > That's a good point. I couldn't find a reason for this.
> > > > If this is applicable for PlatformFrameBufferAllocator, I think we can
> > > > change CameraBuffer too.
> > >
> > > Sure, if it simplifies things. The class is not a public API, and
> > > doesn't need to be 'extensible' with a private implementation as far as
> > > I am aware. In this case, it's just that there are two possible
> > > implementations which are selected at compile time anyway.
> > >
> >
> > +Laurent Pinchart , can I implement so?
> > Why is CameraBuffer designed so?
> >
>
> At the time I designed CameraBuffer using Extensible seemed like a
> good idea. I had probably been lazy as there might be more opportune
> patterns.
>
> What I was looking for was a mechanism that
>
> - Allows to define a standard and unique interface for the
>   CameraManager to interface with
> - Had a compile-time selectable implementation
> - Allowed to not pollute the shared interface with details of the
>   implementation
>
> I evaluated making use of a more canonical class hierarchy, and I
> considered:
>
> a) A single .h file that defines the interface, multiple .cpp that
>   implement it selected at compile time.
>
>   I considered that Extensible would have left more room for
>   implementation-specificities in the Private class interface,
>   allowing more flexibility and wouldn't have requried
>   implementation-specific details to surface in the interface. This
>   mostly apply to the implementation-specific data, which Extensible
>   allows to easy model in the Private subclass.
>
>   Different .h is not an option and keeping them in sync with the
>   common user would be painful
>
> b) A canonical class hierarchy where the 'right' sub-class would be
>   instantiated at run time, but I ditched that as it would have
>   required #ifdefs in the code which I would prefer not to.
>
> There surely are better solution, as your implementation shows
> details and requirement of a specific implementation are surfacing to
> the interface as well, so this can be surely improved with some more
> opportune design pattern.
>
> That said, I won't be too much concerned. The pattern is there and is
> in use, simply replacing it with a) won't bring much value, so I would
> say do whatever is faster for you and if we find a more elegant
> solution we'll change both BufferAllocator and CameraBuffer in one
> go.
>

Ah, it is a good point that with Extensible we can have the platform
dependent class like allocDevice_ in the Extensible class.
So I would go along with Extensible.

-Hiro
> -
>
> > -Hiro
> > > --
> > > Kieran
Laurent Pinchart Nov. 22, 2021, 1:07 a.m. UTC | #11
Hello,

On Thu, Nov 18, 2021 at 05:50:15PM +0900, Hirokazu Honda wrote:
> On Thu, Nov 18, 2021 at 5:43 PM Jacopo Mondi wrote:
> > On Thu, Nov 18, 2021 at 05:13:29PM +0900, Hirokazu Honda wrote:
> > > On Thu, Nov 18, 2021 at 3:02 AM Kieran Bingham wrote:
> > > > Quoting Hirokazu Honda (2021-11-10 03:09:34)
> > > > > Hi Kieran,
> > > > >
> > > > > > In fact, it doesn't matter too much - but I still don't see why this
> > > > > > needs to be Extensible.
> > > > > >
> > > > > > The implementation for PlatformFrameBufferAllocator can have an
> > > > > > identically named class in both
> > > > > >         src/android/mm/cros_frame_buffer_allocator.cpp
> > > > > >         src/android/mm/generic_frame_buffer_allocator.cpp
> > > > > >
> > > > > > And the one that gets used will be the one that is compiled in...?
> > > > >
> > > > > That's a good point. I couldn't find a reason for this.
> > > > > If this is applicable for PlatformFrameBufferAllocator, I think we can
> > > > > change CameraBuffer too.
> > > >
> > > > Sure, if it simplifies things. The class is not a public API, and
> > > > doesn't need to be 'extensible' with a private implementation as far as
> > > > I am aware. In this case, it's just that there are two possible
> > > > implementations which are selected at compile time anyway.
> > >
> > > +Laurent Pinchart , can I implement so?
> > > Why is CameraBuffer designed so?
> >
> > At the time I designed CameraBuffer using Extensible seemed like a
> > good idea. I had probably been lazy as there might be more opportune
> > patterns.

Usage of the Extensible class for CameraBuffer was a bit of a hack I
think. In particular, I'm not fond of the
PUBLIC_CAMERA_BUFFER_IMPLEMENTATION macro. I haven't taken the time to
try and find a better solution.

> > What I was looking for was a mechanism that
> >
> > - Allows to define a standard and unique interface for the
> >   CameraManager to interface with
> > - Had a compile-time selectable implementation
> > - Allowed to not pollute the shared interface with details of the
> >   implementation
> >
> > I evaluated making use of a more canonical class hierarchy, and I
> > considered:
> >
> > a) A single .h file that defines the interface, multiple .cpp that
> >   implement it selected at compile time.
> >
> >   I considered that Extensible would have left more room for
> >   implementation-specificities in the Private class interface,
> >   allowing more flexibility and wouldn't have requried
> >   implementation-specific details to surface in the interface. This
> >   mostly apply to the implementation-specific data, which Extensible
> >   allows to easy model in the Private subclass.
> >
> >   Different .h is not an option and keeping them in sync with the
> >   common user would be painful
> >
> > b) A canonical class hierarchy where the 'right' sub-class would be
> >   instantiated at run time, but I ditched that as it would have
> >   required #ifdefs in the code which I would prefer not to.
> >
> > There surely are better solution, as your implementation shows
> > details and requirement of a specific implementation are surfacing to
> > the interface as well, so this can be surely improved with some more
> > opportune design pattern.
> >
> > That said, I won't be too much concerned. The pattern is there and is
> > in use, simply replacing it with a) won't bring much value, so I would
> > say do whatever is faster for you and if we find a more elegant
> > solution we'll change both BufferAllocator and CameraBuffer in one
> > go.
> 
> Ah, it is a good point that with Extensible we can have the platform
> dependent class like allocDevice_ in the Extensible class.
> So I would go along with Extensible.
Laurent Pinchart Nov. 22, 2021, 2:01 a.m. UTC | #12
Hi Hiro,

Thank you for the patch.

On Mon, Nov 01, 2021 at 04:16:52PM +0900, Hirokazu Honda wrote:
> After we unify identical streams to one stream configuration, the
> capture requested by a HAL client can have been resolved as
> CameraStream::Mapped. That is, a buffer to be written by a camera
> is not provided by a client. We would handle this case by
> dynamically allocating FrameBuffer.

This sounds quite confusing.

> The existing FrameBufferAllocator cannot used because it 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 <hiroh@chromium.org>
> ---
>  src/android/frame_buffer_allocator.h          |  54 +++++++
>  .../mm/cros_frame_buffer_allocator.cpp        |  90 +++++++++++
>  .../mm/generic_frame_buffer_allocator.cpp     | 144 ++++++++++++++++++
>  src/android/mm/meson.build                    |   6 +-
>  4 files changed, 292 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
> 
> diff --git a/src/android/frame_buffer_allocator.h b/src/android/frame_buffer_allocator.h
> new file mode 100644
> index 00000000..41ed4ae1
> --- /dev/null
> +++ b/src/android/frame_buffer_allocator.h
> @@ -0,0 +1,54 @@
> +/* 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 <memory>
> +
> +#include <libcamera/base/class.h>
> +#include <libcamera/camera.h>
> +#include <libcamera/framebuffer.h>
> +#include <libcamera/geometry.h>
> +
> +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<libcamera::FrameBuffer> 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<Private>(this, cameraDevice))	\
> +{									\
> +}									\
> +PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator()		\
> +{									\
> +}									\
> +std::unique_ptr<libcamera::FrameBuffer>					\
> +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..9c7e4ea4
> --- /dev/null
> +++ b/src/android/mm/cros_frame_buffer_allocator.cpp
> @@ -0,0 +1,90 @@
> +/* 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 <memory>
> +#include <vector>
> +
> +#include <libcamera/base/log.h>
> +
> +#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))
> +	{
> +	}
> +
> +	~CrosFrameBufferData() override = default;

Do you need this ?

> +
> +private:
> +	cros::ScopedBufferHandle scopedHandle_;
> +};
> +} /* namespace */
> +
> +class PlatformFrameBufferAllocator::Private : public Extensible::Private
> +{
> +	LIBCAMERA_DECLARE_PUBLIC(PlatformFrameBufferAllocator)
> +
> +public:
> +	Private([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> +		[[maybe_unused]] CameraDevice *const cameraDevice)
> +	{
> +	}
> +
> +	~Private() override = default;

And this ?

> +
> +	std::unique_ptr<libcamera::FrameBuffer> allocate(
> +		int halPixelFormat, const libcamera::Size &size, uint32_t usage);
> +};
> +
> +std::unique_ptr<libcamera::FrameBuffer>
> +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;
> +	const size_t numPlanes = cros::CameraBufferManager::GetNumPlanes(handle);
> +	std::vector<FrameBuffer::Plane> planes(numPlanes);
> +	FileDescriptor 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. */
> +	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<FrameBuffer>(
> +		std::make_unique<CrosFrameBufferData>(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..167cc1a5
> --- /dev/null
> +++ b/src/android/mm/generic_frame_buffer_allocator.cpp
> @@ -0,0 +1,144 @@
> +/* 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/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

Extra space before allocDevice_.

> +		 * owned by PlatformFrameBufferAllocator::Private.
> +		 * GenericFrameBufferData must be destroyed before it is
> +		 * destroyed.
> +		 *
> +		 * \todo: Consider managing alloc_device_t with std::shared_ptr

s/todo:/todo/

> +		 * if this is difficult to maintain.
> +		 *
> +		 * Q: Thread safety against alloc_device_t is not documented.

s/Q:/\todo/

> +		 * Is it no problem to call alloc/free in parallel?
> +		 */
> +		ASSERT(allocDevice_);

You can drop this, it's tested in the constructor.

> +		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([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
> +		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 allocating: " << ret;
> +		return nullptr;
> +	}
> +	if (!handle) {
> +		LOG(HAL, Fatal) << "buffer_handle_t is empty on success";
> +		return nullptr;
> +	}
> +
> +	const libcamera::PixelFormat pixelFormat =
> +		cameraDevice_->capabilities()->toPixelFormat(halPixelFormat);
> +	const auto &info = PixelFormatInfo::info(pixelFormat);
> +	const unsigned int numPlanes = info.numPlanes();
> +	std::vector<FrameBuffer::Plane> planes(numPlanes);

	std::vector<FrameBuffer::Plane> planes(info.numPlanes());

I wonder how all this will interact with a generic way to map
FrameBuffer objects, in the libcamera core. We'll see when we get there,
it will be interesting.

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> +
> +	/* This code assumes the planes are mapped consecutively. */
> +	FileDescriptor 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);
> +
> +		planes[i].fd = fd;
> +		planes[i].offset = offset;
> +		planes[i].length = planeSize;
> +		offset += planeSize;
> +	}
> +
> +	return std::make_unique<FrameBuffer>(
> +		std::make_unique<GenericFrameBufferData>(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

Patch
diff mbox series

diff --git a/src/android/frame_buffer_allocator.h b/src/android/frame_buffer_allocator.h
new file mode 100644
index 00000000..41ed4ae1
--- /dev/null
+++ b/src/android/frame_buffer_allocator.h
@@ -0,0 +1,54 @@ 
+/* 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 <memory>
+
+#include <libcamera/base/class.h>
+#include <libcamera/camera.h>
+#include <libcamera/framebuffer.h>
+#include <libcamera/geometry.h>
+
+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<libcamera::FrameBuffer> 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<Private>(this, cameraDevice))	\
+{									\
+}									\
+PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator()		\
+{									\
+}									\
+std::unique_ptr<libcamera::FrameBuffer>					\
+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..9c7e4ea4
--- /dev/null
+++ b/src/android/mm/cros_frame_buffer_allocator.cpp
@@ -0,0 +1,90 @@ 
+/* 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 <memory>
+#include <vector>
+
+#include <libcamera/base/log.h>
+
+#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))
+	{
+	}
+
+	~CrosFrameBufferData() override = default;
+
+private:
+	cros::ScopedBufferHandle scopedHandle_;
+};
+} /* namespace */
+
+class PlatformFrameBufferAllocator::Private : public Extensible::Private
+{
+	LIBCAMERA_DECLARE_PUBLIC(PlatformFrameBufferAllocator)
+
+public:
+	Private([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
+		[[maybe_unused]] CameraDevice *const cameraDevice)
+	{
+	}
+
+	~Private() override = default;
+
+	std::unique_ptr<libcamera::FrameBuffer> allocate(
+		int halPixelFormat, const libcamera::Size &size, uint32_t usage);
+};
+
+std::unique_ptr<libcamera::FrameBuffer>
+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;
+	const size_t numPlanes = cros::CameraBufferManager::GetNumPlanes(handle);
+	std::vector<FrameBuffer::Plane> planes(numPlanes);
+	FileDescriptor 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. */
+	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<FrameBuffer>(
+		std::make_unique<CrosFrameBufferData>(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..167cc1a5
--- /dev/null
+++ b/src/android/mm/generic_frame_buffer_allocator.cpp
@@ -0,0 +1,144 @@ 
+/* 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/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.
+		 *
+		 * Q: Thread safety against alloc_device_t is not documented.
+		 * Is it no problem to call alloc/free in parallel?
+		 */
+		ASSERT(allocDevice_);
+		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([[maybe_unused]] PlatformFrameBufferAllocator *allocator,
+		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 allocating: " << ret;
+		return nullptr;
+	}
+	if (!handle) {
+		LOG(HAL, Fatal) << "buffer_handle_t is empty on success";
+		return nullptr;
+	}
+
+	const libcamera::PixelFormat pixelFormat =
+		cameraDevice_->capabilities()->toPixelFormat(halPixelFormat);
+	const auto &info = PixelFormatInfo::info(pixelFormat);
+	const unsigned int numPlanes = info.numPlanes();
+	std::vector<FrameBuffer::Plane> planes(numPlanes);
+
+	/* This code assumes the planes are mapped consecutively. */
+	FileDescriptor 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);
+
+		planes[i].fd = fd;
+		planes[i].offset = offset;
+		planes[i].length = planeSize;
+		offset += planeSize;
+	}
+
+	return std::make_unique<FrameBuffer>(
+		std::make_unique<GenericFrameBufferData>(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