blob: 049b1c7e5b3c0454cb5d9f2369c44c05003674ff [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
* framebuffer.cpp - Frame buffer handling
*/
#include <libcamera/framebuffer.h>
#include "libcamera/internal/framebuffer.h"
#include <sys/stat.h>
#include <libcamera/base/log.h>
#include <libcamera/base/shared_fd.h>
/**
* \file libcamera/framebuffer.h
* \brief Frame buffer handling
*
* \file libcamera/internal/framebuffer.h
* \brief Internal frame buffer handling support
*/
namespace libcamera {
LOG_DEFINE_CATEGORY(Buffer)
/**
* \struct FrameMetadata
* \brief Metadata related to a captured frame
*
* The FrameMetadata structure stores all metadata related to a captured frame,
* as stored in a FrameBuffer, such as capture status, timestamp and bytesused.
*/
/**
* \enum FrameMetadata::Status
* \brief Define the frame completion status
* \var FrameMetadata::FrameSuccess
* The frame has been captured with success and contains valid data. All fields
* of the FrameMetadata structure are valid.
* \var FrameMetadata::FrameError
* An error occurred during capture of the frame. The frame data may be partly
* or fully invalid. The sequence and timestamp fields of the FrameMetadata
* structure is valid, the other fields may be invalid.
* \var FrameMetadata::FrameCancelled
* Capture stopped before the frame completed. The frame data is not valid. All
* fields of the FrameMetadata structure but the status field are invalid.
*/
/**
* \struct FrameMetadata::Plane
* \brief Per-plane frame metadata
*
* Frames are stored in memory in one or multiple planes. The
* FrameMetadata::Plane structure stores per-plane metadata.
*/
/**
* \var FrameMetadata::Plane::bytesused
* \brief Number of bytes occupied by the data in the plane, including line
* padding
*
* This value may vary per frame for compressed formats. For uncompressed
* formats it will be constant for all frames, but may be smaller than the
* FrameBuffer size.
*/
/**
* \var FrameMetadata::status
* \brief Status of the frame
*
* The validity of other fields of the FrameMetadata structure depends on the
* status value.
*/
/**
* \var FrameMetadata::sequence
* \brief Frame sequence number
*
* The sequence number is a monotonically increasing number assigned to the
* frames captured by the stream. The value is increased by one for each frame.
* Gaps in the sequence numbers indicate dropped frames.
*/
/**
* \var FrameMetadata::timestamp
* \brief Time when the frame was captured
*
* The timestamp is expressed as a number of nanoseconds relative to the system
* clock since an unspecified time point.
*
* \todo Be more precise on what timestamps refer to.
*/
/**
* \fn FrameMetadata::planes()
* \copydoc FrameMetadata::planes() const
*/
/**
* \fn FrameMetadata::planes() const
* \brief Retrieve the array of per-plane metadata
* \return The array of per-plane metadata
*/
/**
* \class FrameBuffer::Private
* \brief Base class for FrameBuffer private data
*
* The FrameBuffer::Private class stores all private data associated with a
* framebuffer. It implements the d-pointer design pattern to hide core
* FrameBuffer data from the public API, and exposes utility functions to
* pipeline handlers.
*/
FrameBuffer::Private::Private()
: request_(nullptr), isContiguous_(true)
{
}
/**
* \brief FrameBuffer::Private destructor
*/
FrameBuffer::Private::~Private()
{
}
/**
* \fn FrameBuffer::Private::setRequest()
* \brief Set the request this buffer belongs to
* \param[in] request Request to set
*
* For buffers added to requests by applications, this function is called by
* Request::addBuffer() or Request::reuse(). For buffers internal to pipeline
* handlers, it is called by the pipeline handlers themselves.
*/
/**
* \fn FrameBuffer::Private::isContiguous()
* \brief Check if the frame buffer stores planes contiguously in memory
*
* Multi-planar frame buffers can store their planes contiguously in memory, or
* split them into discontiguous memory areas. This function checks in which of
* these two categories the frame buffer belongs.
*
* \return True if the planes are stored contiguously in memory, false otherwise
*/
/**
* \fn FrameBuffer::Private::fence()
* \brief Retrieve a const pointer to the Fence
*
* This function does only return a reference to the the fence and does not
* change its ownership. The fence is stored in the FrameBuffer and can only be
* reset with FrameBuffer::releaseFence() in case the buffer has completed with
* error due to a Fence wait failure.
*
* If buffer with a Fence completes with errors due to a failure in handling
* the fence, applications are responsible for releasing the Fence before
* calling Request::addBuffer() again.
*
* \sa Request::addBuffer()
*
* \return A const pointer to the Fence if any, nullptr otherwise
*/
/**
* \fn FrameBuffer::Private::setFence()
* \brief Move a \a fence in this buffer
* \param[in] fence The Fence
*
* This function associates a Fence with this Framebuffer. The intended caller
* is the Request::addBuffer() function.
*
* Once a FrameBuffer is associated with a Fence, the FrameBuffer will only be
* made available to the hardware device once the Fence has been correctly
* signalled.
*
* \sa Request::prepare()
*
* If the FrameBuffer completes successfully the core releases the Fence and the
* Buffer can be reused immediately. If handling of the Fence fails during the
* request preparation, the Fence is not released and is left in the
* FrameBuffer. It is applications responsibility to correctly release the
* fence and handle it opportunely before using the buffer again.
*/
/**
* \class FrameBuffer
* \brief Frame buffer data and its associated dynamic metadata
*
* The FrameBuffer class is the primary interface for applications, IPAs and
* pipeline handlers to interact with frame memory. It contains all the static
* and dynamic information to manage the whole life cycle of a frame capture,
* from buffer creation to consumption.
*
* The static information describes the memory planes that make a frame. The
* planes are specified when creating the FrameBuffer and are expressed as a set
* of dmabuf file descriptors, offset and length.
*
* The dynamic information is grouped in a FrameMetadata instance. It is updated
* during the processing of a queued capture request, and is valid from the
* completion of the buffer as signaled by Camera::bufferComplete() until the
* FrameBuffer is either reused in a new request or deleted.
*
* The creator of a FrameBuffer (application, IPA or pipeline handler) may
* associate to it an integer cookie for any private purpose. The cookie may be
* set when creating the FrameBuffer, and updated at any time with setCookie().
* The cookie is transparent to the libcamera core and shall only be set by the
* creator of the FrameBuffer. This mechanism supplements the Request cookie.
*/
/**
* \struct FrameBuffer::Plane
* \brief A memory region to store a single plane of a frame
*
* Planar pixel formats use multiple memory regions to store the different
* colour components of a frame. The Plane structure describes such a memory
* region by a dmabuf file descriptor, an offset within the dmabuf and a length.
* A FrameBuffer then contains one or multiple planes, depending on the pixel
* format of the frames it is meant to store.
*
* The offset identifies the location of the plane data from the start of the
* memory referenced by the dmabuf file descriptor. Multiple planes may be
* stored in the same dmabuf, in which case they will reference the same dmabuf
* and different offsets. No two planes may overlap, as specified by their
* offset and length.
*
* To support DMA access, planes are associated with dmabuf objects represented
* by SharedFD handles. The Plane class doesn't handle mapping of the memory to
* the CPU, but applications and IPAs may use the dmabuf file descriptors to map
* the plane memory with mmap() and access its contents.
*
* \todo Specify how an application shall decide whether to use a single or
* multiple dmabufs, based on the camera requirements.
*/
/**
* \var FrameBuffer::Plane::kInvalidOffset
* \brief Invalid offset value, to identify uninitialized planes
*/
/**
* \var FrameBuffer::Plane::fd
* \brief The dmabuf file descriptor
*/
/**
* \var FrameBuffer::Plane::offset
* \brief The plane offset in bytes
*/
/**
* \var FrameBuffer::Plane::length
* \brief The plane length in bytes
*/
namespace {
ino_t fileDescriptorInode(const SharedFD &fd)
{
if (!fd.isValid())
return 0;
struct stat st;
int ret = fstat(fd.get(), &st);
if (ret < 0) {
ret = -errno;
LOG(Buffer, Fatal)
<< "Failed to fstat() fd: " << strerror(-ret);
return 0;
}
return st.st_ino;
}
} /* namespace */
/**
* \brief Construct a FrameBuffer with an array of planes
* \param[in] planes The frame memory planes
* \param[in] cookie Cookie
*/
FrameBuffer::FrameBuffer(const std::vector<Plane> &planes, unsigned int cookie)
: FrameBuffer(std::make_unique<Private>(), planes, cookie)
{
}
/**
* \brief Construct a FrameBuffer with an extensible private class and an array
* of planes
* \param[in] d The extensible private class
* \param[in] planes The frame memory planes
* \param[in] cookie Cookie
*/
FrameBuffer::FrameBuffer(std::unique_ptr<Private> d,
const std::vector<Plane> &planes,
unsigned int cookie)
: Extensible(std::move(d)), planes_(planes), cookie_(cookie)
{
metadata_.planes_.resize(planes_.size());
unsigned int offset = 0;
bool isContiguous = true;
ino_t inode = 0;
for (const auto &plane : planes_) {
ASSERT(plane.offset != Plane::kInvalidOffset);
if (plane.offset != offset) {
isContiguous = false;
break;
}
/*
* Two different dmabuf file descriptors may still refer to the
* same dmabuf instance. Check this using inodes.
*/
if (plane.fd != planes_[0].fd) {
if (!inode)
inode = fileDescriptorInode(planes_[0].fd);
if (fileDescriptorInode(plane.fd) != inode) {
isContiguous = false;
break;
}
}
offset += plane.length;
}
LOG(Buffer, Debug)
<< "Buffer is " << (isContiguous ? "" : "not ") << "contiguous";
_d()->isContiguous_ = isContiguous;
}
/**
* \fn FrameBuffer::planes()
* \brief Retrieve the static plane descriptors
* \return Array of plane descriptors
*/
/**
* \brief Retrieve the request this buffer belongs to
*
* The intended callers of this function are buffer completion handlers that
* need to associate a buffer to the request it belongs to.
*
* A FrameBuffer is associated to a request by Request::addBuffer() and the
* association is valid until the buffer completes. The returned request
* pointer is valid only during that interval.
*
* \return The Request the FrameBuffer belongs to, or nullptr if the buffer is
* not associated with a request
*/
Request *FrameBuffer::request() const
{
return _d()->request_;
}
/**
* \fn FrameBuffer::metadata()
* \brief Retrieve the dynamic metadata
* \return Dynamic metadata for the frame contained in the buffer
*/
/**
* \fn FrameBuffer::cookie()
* \brief Retrieve the cookie
*
* The cookie belongs to the creator of the FrameBuffer, which controls its
* lifetime and value.
*
* \sa setCookie()
*
* \return The cookie
*/
/**
* \fn FrameBuffer::setCookie()
* \brief Set the cookie
* \param[in] cookie Cookie to set
*
* The cookie belongs to the creator of the FrameBuffer. Its value may be
* modified at any time with this function. Applications and IPAs shall not
* modify the cookie value of buffers they haven't created themselves. The
* libcamera core never modifies the buffer cookie.
*/
/**
* \brief Extract the Fence associated with this Framebuffer
*
* This function moves the buffer's fence ownership to the caller.
* After the fence has been released, calling this function always return
* nullptr.
*
* If buffer with a Fence completes with errors due to a failure in handling
* the fence, applications are responsible for releasing the Fence before
* calling Request::addBuffer() again.
*
* \return A unique pointer to the Fence if set, or nullptr if the fence has
* been released already
*/
std::unique_ptr<Fence> FrameBuffer::releaseFence()
{
return std::move(_d()->fence_);
}
/**
* \fn FrameBuffer::cancel()
* \brief Marks the buffer as cancelled
*
* If a buffer is not used by a request, it shall be marked as cancelled to
* indicate that the metadata is invalid.
*/
} /* namespace libcamera */