libcamera: software_isp: gbm: Add in a GBM helper class for GPU surface access

A helper class to interact with GBM. This will allow us to specify the
internal storage format of the CPU when making a texture for the Debayer
vertext/fragment shaders and thus ensure we receive an uncompressed and
untiled output buffer.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
This commit is contained in:
Bryan O'Donoghue 2024-09-23 16:11:28 +01:00
parent 59284f4f27
commit 234849b2b9
4 changed files with 204 additions and 0 deletions

View file

@ -0,0 +1,55 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2024, Linaro Ltd.
*
* Authors:
* Bryan O'Donoghue <bryan.odonoghue@linaro.org>
*
* gbm.h - Helper class for managing GBM interactions.
*/
#pragma once
#include <gbm.h>
#include <libcamera/base/log.h>
#include <libcamera/formats.h>
namespace libcamera {
LOG_DECLARE_CATEGORY(GBM)
class GBM
{
public:
GBM();
~GBM();
int initSurface(uint32_t width, uint32_t height);
int mapSurface();
int getFrameBufferData(uint8_t *data_out, size_t data_len);
struct gbm_device *getDevice() { return gbm_device_; }
struct gbm_surface *getSurface() { return gbm_surface_; }
uint32_t getFrameSize() { return framesize_; }
uint32_t getStride() { return stride_; }
PixelFormat getPixelFormat() { return format_; }
private:
int fd_;
struct gbm_device *gbm_device_;
struct gbm_surface *gbm_surface_;
struct gbm_bo *gbm_bo_;
uint32_t width_;
uint32_t height_;
uint32_t stride_;
uint32_t offset_;
uint32_t framesize_;
void *map_;
int bo_fd_;
PixelFormat format_;
};
} // namespace libcamera

View file

@ -23,6 +23,7 @@ libcamera_internal_headers = files([
'dma_buf_allocator.h',
'formats.h',
'framebuffer.h',
'gbm.h',
'ipa_data_serializer.h',
'ipa_manager.h',
'ipa_module.h',

137
src/libcamera/gbm.cpp Normal file
View file

@ -0,0 +1,137 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2024, Linaro Ltd.
*
* Authors:
* Bryan O'Donoghue <bryan.odonoghue@linaro.org>
*
* egl.cpp - Helper class for managing GBM interactions.
*/
#include "libcamera/internal/gbm.h"
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <linux/dma-buf.h>
#include <linux/dma-heap.h>
namespace libcamera {
LOG_DEFINE_CATEGORY(GBM)
GBM::GBM()
{
fd_ = 0;
}
GBM::~GBM()
{
if (gbm_surface_)
gbm_surface_destroy(gbm_surface_);
if (gbm_device_)
gbm_device_destroy(gbm_device_);
if (fd_ >= 0)
close(fd_);
}
// this should probably go into its own class to deal with the
// allocation and deletion of frambuffers attached to GBM devices/objects
int GBM::initSurface(uint32_t width, uint32_t height)
{
const char *dri_node = "/dev/dri/renderD128"; //TODO: get from an env or config setting
fd_ = open(dri_node, O_RDWR | O_CLOEXEC); //TODO: CLOEXEC ?
if (fd_ < 0) {
LOG(GBM, Error) << "Open " << dri_node << " fail " << fd_;
return fd_;
}
gbm_device_ = gbm_create_device(fd_);
if (!gbm_device_) {
LOG(GBM, Error) << "gbm_crate_device fail";
goto fail;
}
// GBM_FORMAT_RGBA8888 is not supported mesa::src/gbm/dri/gbm_dri.c::gbm_dri_visuals_table[]
// This means we need to choose XRGB8888 or ARGB8888 as the raw buffer format
gbm_surface_ = gbm_surface_create(gbm_device_, width, height, GBM_FORMAT_ARGB8888,
GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR);
if (!gbm_surface_) {
LOG(GBM, Error) << "Unable to create linear gbm surface";
goto fail;
}
format_ = libcamera::formats::ARGB8888;
return 0;
fail:
return -ENODEV;
}
int GBM::mapSurface()
{
gbm_bo_ = gbm_surface_lock_front_buffer(gbm_surface_);
if (!gbm_bo_) {
LOG(GBM, Error) << "GBM input buffer object create fail";
return -ENODEV;
}
gbm_surface_release_buffer(gbm_surface_, gbm_bo_);
bo_fd_ = gbm_bo_get_fd(gbm_bo_);
if (!bo_fd_) {
gbm_surface_release_buffer(gbm_surface_, gbm_bo_);
LOG(GBM, Error) << "Unable to get fd for bo: " << bo_fd_;
return -ENODEV;
}
stride_ = gbm_bo_get_stride(gbm_bo_);
width_ = gbm_bo_get_width(gbm_bo_);
height_ = gbm_bo_get_height(gbm_bo_);
offset_ = gbm_bo_get_offset(gbm_bo_, 0);
framesize_ = height_ * stride_;
map_ = mmap(NULL, height_ * stride_, PROT_READ, MAP_SHARED, bo_fd_, 0);
if (map_ == MAP_FAILED) {
LOG(GBM, Error) << "mmap gbm_bo_ fail";
return -ENODEV;
}
LOG(GBM, Debug) << " stride " << stride_
<< " width " << width_
<< " height " << height_
<< " offset " << offset_
<< " framesize " << framesize_;
return 0;
}
int GBM::getFrameBufferData(uint8_t *data, size_t data_len)
{
struct dma_buf_sync sync;
gbm_surface_lock_front_buffer(gbm_surface_);
sync.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ;
ioctl(bo_fd_, DMA_BUF_IOCTL_SYNC, &sync);
if (data_len > framesize_) {
LOG(GBM, Error) << "Invalid read size " << data_len << " max is " << framesize_;
return -EINVAL;
}
memcpy(data, map_, data_len);
sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ;
ioctl(bo_fd_, DMA_BUF_IOCTL_SYNC, &sync);
gbm_surface_release_buffer(gbm_surface_, gbm_bo_);
return 0;
}
} //namespace libcamera

View file

@ -67,6 +67,16 @@ libcamera_deps = []
libatomic = cc.find_library('atomic', required : false)
libthreads = dependency('threads')
libgbm = cc.find_library('gbm', required: false)
gbm_works = cc.check_header('gbm.h', required: false)
if libgbm.found() and gbm_works
config_h.set('HAVE_GBM', 1)
libcamera_internal_sources += files([
'gbm.cpp',
])
endif
subdir('base')
subdir('converter')
subdir('ipa')
@ -188,6 +198,7 @@ libcamera_deps += [
libcamera_base_private,
libcrypto,
libdl,
libgbm,
liblttng,
libudev,
libyaml,