[v8,01/26] libcamera: software_isp: gbm: Add a GBM helper class for GPU surface access
diff mbox series

Message ID 20251212002937.3118-2-bryan.odonoghue@linaro.org
State Superseded
Headers show
Series
  • Add GLES 2.0 GPUISP to libcamera
Related show

Commit Message

Bryan O'Donoghue Dec. 12, 2025, 12:29 a.m. UTC
A helper class to interact with GBM. This will allow us to specify the
internal storage format of the GPU when making a texture for the Debayer
vertex/fragment shaders and thus ensure we receive an uncompressed and
untiled output buffer.

Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 include/libcamera/internal/gbm.h       |  39 ++++++++
 include/libcamera/internal/meson.build |   1 +
 src/libcamera/gbm.cpp                  | 130 +++++++++++++++++++++++++
 src/libcamera/meson.build              |  10 ++
 4 files changed, 180 insertions(+)
 create mode 100644 include/libcamera/internal/gbm.h
 create mode 100644 src/libcamera/gbm.cpp

Comments

Robert Mader Dec. 12, 2025, 12:13 p.m. UTC | #1
Hi,

On 12.12.25 01:29, Bryan O'Donoghue wrote:
> A helper class to interact with GBM. This will allow us to specify the
> internal storage format of the GPU when making a texture for the Debayer
> vertex/fragment shaders and thus ensure we receive an uncompressed and
> untiled output buffer.

I'm pretty sure we should be able to use the device EGL platform instead 
here (1), which is generally more robust and simpler than GBM - and 
meant for usecases like this.

Compression/tiling should not be an issue any more as we import the 
buffers with linear modifiers in the next patch (see 
"EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT") and a major advantage is that we 
don't have to deal with hardcoded paths like "/dev/dri/renderD128". 
Instead we can just use the default/preferred device or enumerate our 
options with EXT_device_enumeration.

Thus we should be able to drop this patch and adopt the EGL 
initialization, which should make things simpler overall.

1. EGL_EXT_platform_device, equivalent to EGL_MESA_platform_surfaceless 
together with EGL_EXT_explicit_device.

> Acked-by: Kieran Bingham<kieran.bingham@ideasonboard.com>
> Signed-off-by: Bryan O'Donoghue<bryan.odonoghue@linaro.org>
> ---
>   include/libcamera/internal/gbm.h       |  39 ++++++++
>   include/libcamera/internal/meson.build |   1 +
>   src/libcamera/gbm.cpp                  | 130 +++++++++++++++++++++++++
>   src/libcamera/meson.build              |  10 ++
>   4 files changed, 180 insertions(+)
>   create mode 100644 include/libcamera/internal/gbm.h
>   create mode 100644 src/libcamera/gbm.cpp
>
> diff --git a/include/libcamera/internal/gbm.h b/include/libcamera/internal/gbm.h
> new file mode 100644
> index 000000000..09811d1ef
> --- /dev/null
> +++ b/include/libcamera/internal/gbm.h
> @@ -0,0 +1,39 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2024, Linaro Ltd.
> + *
> + * Authors:
> + * Bryan O'Donoghue<bryan.odonoghue@linaro.org>
> + *
> + * 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 createDevice();
> +	struct gbm_device *getDevice();
> +	PixelFormat getPixelFormat();
> +
> +private:
> +	int fd_;
> +	struct gbm_device *gbmDevice_;
> +	PixelFormat format_;
> +};
> +
> +} /* namespace libcamera */
> diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build
> index e9540a2f7..b8324996b 100644
> --- a/include/libcamera/internal/meson.build
> +++ b/include/libcamera/internal/meson.build
> @@ -23,6 +23,7 @@ libcamera_internal_headers = files([
>       'dma_buf_allocator.h',
>       'formats.h',
>       'framebuffer.h',
> +    'gbm.h',
>       'global_configuration.h',
>       'ipa_data_serializer.h',
>       'ipa_manager.h',
> diff --git a/src/libcamera/gbm.cpp b/src/libcamera/gbm.cpp
> new file mode 100644
> index 000000000..a2e4c7076
> --- /dev/null
> +++ b/src/libcamera/gbm.cpp
> @@ -0,0 +1,130 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2024, Linaro Ltd.
> + *
> + * Authors:
> + * Bryan O'Donoghue<bryan.odonoghue@linaro.org>
> + *
> + * Helper class for managing GBM interactions
> + */
> +
> +#include "libcamera/internal/gbm.h"
> +
> +#include <errno.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)
> +
> +/**
> + * \class GBM
> + * \brief Helper class for managing GBM interactions
> + *
> + * The GBM class provides a simplified interface for creating and managing
> + * GBM devices. It handles the initialization and teardown of GBM devices
> + * used for buffer allocation in graphics and camera pipelines.
> + *
> + * This class is responsible for opening a DRI render node, creating a GBM
> + * device, and providing access to the device and its associated pixel format.
> + */
> +
> +/**
> + *\var GBM::fd_
> + *\brief file descriptor to DRI device
> + */
> +
> +/**
> + *\var GBM::gbmDevice_
> + *\brief Pointer to GBM device structure derived from fd_
> + */
> +
> +/**
> + *\var GBM::format_
> + *\brief Pixel format the GBM surface was created in
> + */
> +
> +/**
> + *\brief GBM constructor.
> + *
> + * Creates a GBM instance with unitialised state.
> + */
> +GBM::GBM()
> +{
> +	fd_ = 0;
> +	gbmDevice_ = nullptr;
> +}
> +
> +/**
> + *\brief GBM destructor
> + *
> + * Cleans up the GBM device if it was successfully created, and closes
> + * the associated file descriptor.
> + */
> +GBM::~GBM()
> +{
> +	if (gbmDevice_)
> +		gbm_device_destroy(gbmDevice_);
> +}
> +
> +/**
> + * \brief Create and initialize a GBM device
> + *
> + * \todo Get dri device name from envOption setting
> + *
> + * Opens the DRI render node (/dev/dri/renderD128) and creates a GBM
> + * device using the libgbm library. Sets the default pixel format to
> + * ARGB8888.
> + *
> + * \return 0 on success, or a negative error code on failure
> + */
> +int GBM::createDevice()
> +{
> +	const char *dri_node = "/dev/dri/renderD128";
> +
> +	fd_ = open(dri_node, O_RDWR | O_CLOEXEC);
> +	if (fd_ < 0) {
> +		LOG(GBM, Error) << "Open " << dri_node << " fail " << fd_;
> +		return fd_;
> +	}
> +
> +	gbmDevice_ = gbm_create_device(fd_);
> +	if (!gbmDevice_) {
> +		LOG(GBM, Error) << "gbm_create_device fail";
> +		close(fd_);
> +		return -errno;
> +	}
> +
> +	format_ = libcamera::formats::ARGB8888;
> +
> +	return 0;
> +}
> +
> +/**
> + * \brief Retrieve the GBM device handle
> + *
> + * \return Pointer to the gbm_device structure, or nullptr if the device
> + * has not been created
> + */
> +struct gbm_device * GBM::getDevice()
> +{
> +	return gbmDevice_;
> +}
> +
> +/**
> + * \brief Retrieve the pixel format
> + *
> + * \return The PixelFormat used by this GBM instance (ARGB8888)
> + */
> +
> +PixelFormat GBM::getPixelFormat()
> +{
> +	return format_;
> +}
> +} /* namespace libcamera */
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index 90d434a5a..685213c78 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -70,6 +70,15 @@ 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
> +    libcamera_internal_sources += files([
> +        'gbm.cpp',
> +    ])
> +endif
> +
>   subdir('base')
>   subdir('converter')
>   subdir('ipa')
> @@ -178,6 +187,7 @@ libcamera_deps += [
>       libcamera_base_private,
>       libcrypto,
>       libdl,
> +    libgbm,
>       liblttng,
>       libudev,
>       libyaml,
Robert Mader Dec. 12, 2025, 2:21 p.m. UTC | #2
FTR., I gave this a quick try and it seems to work just fine on my test 
devices. Pushed a commit here: 
https://gitlab.freedesktop.org/rmader/libcamera/-/commits/v0.6.0-gpuisp-v8-fixes

On 12.12.25 13:13, Robert Mader wrote:
> Hi,
>
> On 12.12.25 01:29, Bryan O'Donoghue wrote:
>> A helper class to interact with GBM. This will allow us to specify the
>> internal storage format of the GPU when making a texture for the Debayer
>> vertex/fragment shaders and thus ensure we receive an uncompressed and
>> untiled output buffer.
>
> I'm pretty sure we should be able to use the device EGL platform 
> instead here (1), which is generally more robust and simpler than GBM 
> - and meant for usecases like this.
>
> Compression/tiling should not be an issue any more as we import the 
> buffers with linear modifiers in the next patch (see 
> "EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT") and a major advantage is that we 
> don't have to deal with hardcoded paths like "/dev/dri/renderD128". 
> Instead we can just use the default/preferred device or enumerate our 
> options with EXT_device_enumeration.
>
> Thus we should be able to drop this patch and adopt the EGL 
> initialization, which should make things simpler overall.
>
> 1. EGL_EXT_platform_device, equivalent to 
> EGL_MESA_platform_surfaceless together with EGL_EXT_explicit_device.
>
>> Acked-by: Kieran Bingham<kieran.bingham@ideasonboard.com>
>> Signed-off-by: Bryan O'Donoghue<bryan.odonoghue@linaro.org>
>> ---
>>   include/libcamera/internal/gbm.h       |  39 ++++++++
>>   include/libcamera/internal/meson.build |   1 +
>>   src/libcamera/gbm.cpp                  | 130 +++++++++++++++++++++++++
>>   src/libcamera/meson.build              |  10 ++
>>   4 files changed, 180 insertions(+)
>>   create mode 100644 include/libcamera/internal/gbm.h
>>   create mode 100644 src/libcamera/gbm.cpp
>>
>> diff --git a/include/libcamera/internal/gbm.h 
>> b/include/libcamera/internal/gbm.h
>> new file mode 100644
>> index 000000000..09811d1ef
>> --- /dev/null
>> +++ b/include/libcamera/internal/gbm.h
>> @@ -0,0 +1,39 @@
>> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
>> +/*
>> + * Copyright (C) 2024, Linaro Ltd.
>> + *
>> + * Authors:
>> + * Bryan O'Donoghue<bryan.odonoghue@linaro.org>
>> + *
>> + * 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 createDevice();
>> +    struct gbm_device *getDevice();
>> +    PixelFormat getPixelFormat();
>> +
>> +private:
>> +    int fd_;
>> +    struct gbm_device *gbmDevice_;
>> +    PixelFormat format_;
>> +};
>> +
>> +} /* namespace libcamera */
>> diff --git a/include/libcamera/internal/meson.build 
>> b/include/libcamera/internal/meson.build
>> index e9540a2f7..b8324996b 100644
>> --- a/include/libcamera/internal/meson.build
>> +++ b/include/libcamera/internal/meson.build
>> @@ -23,6 +23,7 @@ libcamera_internal_headers = files([
>>       'dma_buf_allocator.h',
>>       'formats.h',
>>       'framebuffer.h',
>> +    'gbm.h',
>>       'global_configuration.h',
>>       'ipa_data_serializer.h',
>>       'ipa_manager.h',
>> diff --git a/src/libcamera/gbm.cpp b/src/libcamera/gbm.cpp
>> new file mode 100644
>> index 000000000..a2e4c7076
>> --- /dev/null
>> +++ b/src/libcamera/gbm.cpp
>> @@ -0,0 +1,130 @@
>> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
>> +/*
>> + * Copyright (C) 2024, Linaro Ltd.
>> + *
>> + * Authors:
>> + * Bryan O'Donoghue<bryan.odonoghue@linaro.org>
>> + *
>> + * Helper class for managing GBM interactions
>> + */
>> +
>> +#include "libcamera/internal/gbm.h"
>> +
>> +#include <errno.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)
>> +
>> +/**
>> + * \class GBM
>> + * \brief Helper class for managing GBM interactions
>> + *
>> + * The GBM class provides a simplified interface for creating and 
>> managing
>> + * GBM devices. It handles the initialization and teardown of GBM 
>> devices
>> + * used for buffer allocation in graphics and camera pipelines.
>> + *
>> + * This class is responsible for opening a DRI render node, creating 
>> a GBM
>> + * device, and providing access to the device and its associated 
>> pixel format.
>> + */
>> +
>> +/**
>> + *\var GBM::fd_
>> + *\brief file descriptor to DRI device
>> + */
>> +
>> +/**
>> + *\var GBM::gbmDevice_
>> + *\brief Pointer to GBM device structure derived from fd_
>> + */
>> +
>> +/**
>> + *\var GBM::format_
>> + *\brief Pixel format the GBM surface was created in
>> + */
>> +
>> +/**
>> + *\brief GBM constructor.
>> + *
>> + * Creates a GBM instance with unitialised state.
>> + */
>> +GBM::GBM()
>> +{
>> +    fd_ = 0;
>> +    gbmDevice_ = nullptr;
>> +}
>> +
>> +/**
>> + *\brief GBM destructor
>> + *
>> + * Cleans up the GBM device if it was successfully created, and closes
>> + * the associated file descriptor.
>> + */
>> +GBM::~GBM()
>> +{
>> +    if (gbmDevice_)
>> +        gbm_device_destroy(gbmDevice_);
>> +}
>> +
>> +/**
>> + * \brief Create and initialize a GBM device
>> + *
>> + * \todo Get dri device name from envOption setting
>> + *
>> + * Opens the DRI render node (/dev/dri/renderD128) and creates a GBM
>> + * device using the libgbm library. Sets the default pixel format to
>> + * ARGB8888.
>> + *
>> + * \return 0 on success, or a negative error code on failure
>> + */
>> +int GBM::createDevice()
>> +{
>> +    const char *dri_node = "/dev/dri/renderD128";
>> +
>> +    fd_ = open(dri_node, O_RDWR | O_CLOEXEC);
>> +    if (fd_ < 0) {
>> +        LOG(GBM, Error) << "Open " << dri_node << " fail " << fd_;
>> +        return fd_;
>> +    }
>> +
>> +    gbmDevice_ = gbm_create_device(fd_);
>> +    if (!gbmDevice_) {
>> +        LOG(GBM, Error) << "gbm_create_device fail";
>> +        close(fd_);
>> +        return -errno;
>> +    }
>> +
>> +    format_ = libcamera::formats::ARGB8888;
>> +
>> +    return 0;
>> +}
>> +
>> +/**
>> + * \brief Retrieve the GBM device handle
>> + *
>> + * \return Pointer to the gbm_device structure, or nullptr if the 
>> device
>> + * has not been created
>> + */
>> +struct gbm_device * GBM::getDevice()
>> +{
>> +    return gbmDevice_;
>> +}
>> +
>> +/**
>> + * \brief Retrieve the pixel format
>> + *
>> + * \return The PixelFormat used by this GBM instance (ARGB8888)
>> + */
>> +
>> +PixelFormat GBM::getPixelFormat()
>> +{
>> +    return format_;
>> +}
>> +} /* namespace libcamera */
>> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
>> index 90d434a5a..685213c78 100644
>> --- a/src/libcamera/meson.build
>> +++ b/src/libcamera/meson.build
>> @@ -70,6 +70,15 @@ 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
>> +    libcamera_internal_sources += files([
>> +        'gbm.cpp',
>> +    ])
>> +endif
>> +
>>   subdir('base')
>>   subdir('converter')
>>   subdir('ipa')
>> @@ -178,6 +187,7 @@ libcamera_deps += [
>>       libcamera_base_private,
>>       libcrypto,
>>       libdl,
>> +    libgbm,
>>       liblttng,
>>       libudev,
>>       libyaml,
Robert Mader Dec. 12, 2025, 2:36 p.m. UTC | #3
P.S. (sorry for the noise): another advantage of not using GBM is that 
that `LIBGL_ALWAYS_SOFTWARE=1` gets respected - making it easy to use 
llvmpipe - and that we can test things more easily on CI / on platforms 
without DRI device.

On 12.12.25 15:21, Robert Mader wrote:
> FTR., I gave this a quick try and it seems to work just fine on my 
> test devices. Pushed a commit here: 
> https://gitlab.freedesktop.org/rmader/libcamera/-/commits/v0.6.0-gpuisp-v8-fixes
>
> On 12.12.25 13:13, Robert Mader wrote:
>> Hi,
>>
>> On 12.12.25 01:29, Bryan O'Donoghue wrote:
>>> A helper class to interact with GBM. This will allow us to specify the
>>> internal storage format of the GPU when making a texture for the 
>>> Debayer
>>> vertex/fragment shaders and thus ensure we receive an uncompressed and
>>> untiled output buffer.
>>
>> I'm pretty sure we should be able to use the device EGL platform 
>> instead here (1), which is generally more robust and simpler than GBM 
>> - and meant for usecases like this.
>>
>> Compression/tiling should not be an issue any more as we import the 
>> buffers with linear modifiers in the next patch (see 
>> "EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT") and a major advantage is that 
>> we don't have to deal with hardcoded paths like 
>> "/dev/dri/renderD128". Instead we can just use the default/preferred 
>> device or enumerate our options with EXT_device_enumeration.
>>
>> Thus we should be able to drop this patch and adopt the EGL 
>> initialization, which should make things simpler overall.
>>
>> 1. EGL_EXT_platform_device, equivalent to 
>> EGL_MESA_platform_surfaceless together with EGL_EXT_explicit_device.
>>
>>> Acked-by: Kieran Bingham<kieran.bingham@ideasonboard.com>
>>> Signed-off-by: Bryan O'Donoghue<bryan.odonoghue@linaro.org>
>>> ---
>>>   include/libcamera/internal/gbm.h       |  39 ++++++++
>>>   include/libcamera/internal/meson.build |   1 +
>>>   src/libcamera/gbm.cpp                  | 130 
>>> +++++++++++++++++++++++++
>>>   src/libcamera/meson.build              |  10 ++
>>>   4 files changed, 180 insertions(+)
>>>   create mode 100644 include/libcamera/internal/gbm.h
>>>   create mode 100644 src/libcamera/gbm.cpp
>>>
>>> diff --git a/include/libcamera/internal/gbm.h 
>>> b/include/libcamera/internal/gbm.h
>>> new file mode 100644
>>> index 000000000..09811d1ef
>>> --- /dev/null
>>> +++ b/include/libcamera/internal/gbm.h
>>> @@ -0,0 +1,39 @@
>>> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
>>> +/*
>>> + * Copyright (C) 2024, Linaro Ltd.
>>> + *
>>> + * Authors:
>>> + * Bryan O'Donoghue<bryan.odonoghue@linaro.org>
>>> + *
>>> + * 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 createDevice();
>>> +    struct gbm_device *getDevice();
>>> +    PixelFormat getPixelFormat();
>>> +
>>> +private:
>>> +    int fd_;
>>> +    struct gbm_device *gbmDevice_;
>>> +    PixelFormat format_;
>>> +};
>>> +
>>> +} /* namespace libcamera */
>>> diff --git a/include/libcamera/internal/meson.build 
>>> b/include/libcamera/internal/meson.build
>>> index e9540a2f7..b8324996b 100644
>>> --- a/include/libcamera/internal/meson.build
>>> +++ b/include/libcamera/internal/meson.build
>>> @@ -23,6 +23,7 @@ libcamera_internal_headers = files([
>>>       'dma_buf_allocator.h',
>>>       'formats.h',
>>>       'framebuffer.h',
>>> +    'gbm.h',
>>>       'global_configuration.h',
>>>       'ipa_data_serializer.h',
>>>       'ipa_manager.h',
>>> diff --git a/src/libcamera/gbm.cpp b/src/libcamera/gbm.cpp
>>> new file mode 100644
>>> index 000000000..a2e4c7076
>>> --- /dev/null
>>> +++ b/src/libcamera/gbm.cpp
>>> @@ -0,0 +1,130 @@
>>> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
>>> +/*
>>> + * Copyright (C) 2024, Linaro Ltd.
>>> + *
>>> + * Authors:
>>> + * Bryan O'Donoghue<bryan.odonoghue@linaro.org>
>>> + *
>>> + * Helper class for managing GBM interactions
>>> + */
>>> +
>>> +#include "libcamera/internal/gbm.h"
>>> +
>>> +#include <errno.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)
>>> +
>>> +/**
>>> + * \class GBM
>>> + * \brief Helper class for managing GBM interactions
>>> + *
>>> + * The GBM class provides a simplified interface for creating and 
>>> managing
>>> + * GBM devices. It handles the initialization and teardown of GBM 
>>> devices
>>> + * used for buffer allocation in graphics and camera pipelines.
>>> + *
>>> + * This class is responsible for opening a DRI render node, 
>>> creating a GBM
>>> + * device, and providing access to the device and its associated 
>>> pixel format.
>>> + */
>>> +
>>> +/**
>>> + *\var GBM::fd_
>>> + *\brief file descriptor to DRI device
>>> + */
>>> +
>>> +/**
>>> + *\var GBM::gbmDevice_
>>> + *\brief Pointer to GBM device structure derived from fd_
>>> + */
>>> +
>>> +/**
>>> + *\var GBM::format_
>>> + *\brief Pixel format the GBM surface was created in
>>> + */
>>> +
>>> +/**
>>> + *\brief GBM constructor.
>>> + *
>>> + * Creates a GBM instance with unitialised state.
>>> + */
>>> +GBM::GBM()
>>> +{
>>> +    fd_ = 0;
>>> +    gbmDevice_ = nullptr;
>>> +}
>>> +
>>> +/**
>>> + *\brief GBM destructor
>>> + *
>>> + * Cleans up the GBM device if it was successfully created, and closes
>>> + * the associated file descriptor.
>>> + */
>>> +GBM::~GBM()
>>> +{
>>> +    if (gbmDevice_)
>>> +        gbm_device_destroy(gbmDevice_);
>>> +}
>>> +
>>> +/**
>>> + * \brief Create and initialize a GBM device
>>> + *
>>> + * \todo Get dri device name from envOption setting
>>> + *
>>> + * Opens the DRI render node (/dev/dri/renderD128) and creates a GBM
>>> + * device using the libgbm library. Sets the default pixel format to
>>> + * ARGB8888.
>>> + *
>>> + * \return 0 on success, or a negative error code on failure
>>> + */
>>> +int GBM::createDevice()
>>> +{
>>> +    const char *dri_node = "/dev/dri/renderD128";
>>> +
>>> +    fd_ = open(dri_node, O_RDWR | O_CLOEXEC);
>>> +    if (fd_ < 0) {
>>> +        LOG(GBM, Error) << "Open " << dri_node << " fail " << fd_;
>>> +        return fd_;
>>> +    }
>>> +
>>> +    gbmDevice_ = gbm_create_device(fd_);
>>> +    if (!gbmDevice_) {
>>> +        LOG(GBM, Error) << "gbm_create_device fail";
>>> +        close(fd_);
>>> +        return -errno;
>>> +    }
>>> +
>>> +    format_ = libcamera::formats::ARGB8888;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +/**
>>> + * \brief Retrieve the GBM device handle
>>> + *
>>> + * \return Pointer to the gbm_device structure, or nullptr if the 
>>> device
>>> + * has not been created
>>> + */
>>> +struct gbm_device * GBM::getDevice()
>>> +{
>>> +    return gbmDevice_;
>>> +}
>>> +
>>> +/**
>>> + * \brief Retrieve the pixel format
>>> + *
>>> + * \return The PixelFormat used by this GBM instance (ARGB8888)
>>> + */
>>> +
>>> +PixelFormat GBM::getPixelFormat()
>>> +{
>>> +    return format_;
>>> +}
>>> +} /* namespace libcamera */
>>> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
>>> index 90d434a5a..685213c78 100644
>>> --- a/src/libcamera/meson.build
>>> +++ b/src/libcamera/meson.build
>>> @@ -70,6 +70,15 @@ 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
>>> +    libcamera_internal_sources += files([
>>> +        'gbm.cpp',
>>> +    ])
>>> +endif
>>> +
>>>   subdir('base')
>>>   subdir('converter')
>>>   subdir('ipa')
>>> @@ -178,6 +187,7 @@ libcamera_deps += [
>>>       libcamera_base_private,
>>>       libcrypto,
>>>       libdl,
>>> +    libgbm,
>>>       liblttng,
>>>       libudev,
>>>       libyaml,
>
Milan Zamazal Dec. 12, 2025, 7:37 p.m. UTC | #4
Robert Mader <robert.mader@collabora.com> writes:

> FTR., I gave this a quick try and it seems to work just fine on my test
> devices. Pushed a commit here:
> https://gitlab.freedesktop.org/rmader/libcamera/-/commits/v0.6.0-gpuisp-v8-fixes

It fails in my environment with:

  ERROR eGL egl.cpp:309 eglInitialize fail

> On 12.12.25 13:13, Robert Mader wrote:
>> Hi,
>>
>> On 12.12.25 01:29, Bryan O'Donoghue wrote:
>>> A helper class to interact with GBM. This will allow us to specify the
>>> internal storage format of the GPU when making a texture for the Debayer
>>> vertex/fragment shaders and thus ensure we receive an uncompressed and
>>> untiled output buffer.
>>
>> I'm pretty sure we should be able to use the device EGL platform instead here (1),
>> which is generally more robust and simpler than GBM - and meant for usecases like
>> this.
>>
>> Compression/tiling should not be an issue any more as we import the buffers with
>> linear modifiers in the next patch (see "EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT") and a
>> major advantage is that we don't have to deal with hardcoded paths like
>> "/dev/dri/renderD128". Instead we can just use the default/preferred device or
>> enumerate our options with EXT_device_enumeration.
>>
>> Thus we should be able to drop this patch and adopt the EGL initialization, which
>> should make things simpler overall.
>>
>> 1. EGL_EXT_platform_device, equivalent to EGL_MESA_platform_surfaceless together
>> with EGL_EXT_explicit_device.
>>
>>> Acked-by: Kieran Bingham<kieran.bingham@ideasonboard.com>
>>> Signed-off-by: Bryan O'Donoghue<bryan.odonoghue@linaro.org>
>>> ---
>>>   include/libcamera/internal/gbm.h       |  39 ++++++++
>>>   include/libcamera/internal/meson.build |   1 +
>>>   src/libcamera/gbm.cpp                  | 130 +++++++++++++++++++++++++
>>>   src/libcamera/meson.build              |  10 ++
>>>   4 files changed, 180 insertions(+)
>>>   create mode 100644 include/libcamera/internal/gbm.h
>>>   create mode 100644 src/libcamera/gbm.cpp
>>>
>>> diff --git a/include/libcamera/internal/gbm.h b/include/libcamera/internal/gbm.h
>>> new file mode 100644
>>> index 000000000..09811d1ef
>>> --- /dev/null
>>> +++ b/include/libcamera/internal/gbm.h
>>> @@ -0,0 +1,39 @@
>>> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
>>> +/*
>>> + * Copyright (C) 2024, Linaro Ltd.
>>> + *
>>> + * Authors:
>>> + * Bryan O'Donoghue<bryan.odonoghue@linaro.org>
>>> + *
>>> + * 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 createDevice();
>>> +    struct gbm_device *getDevice();
>>> +    PixelFormat getPixelFormat();
>>> +
>>> +private:
>>> +    int fd_;
>>> +    struct gbm_device *gbmDevice_;
>>> +    PixelFormat format_;
>>> +};
>>> +
>>> +} /* namespace libcamera */
>>> diff --git a/include/libcamera/internal/meson.build
>>> b/include/libcamera/internal/meson.build
>>> index e9540a2f7..b8324996b 100644
>>> --- a/include/libcamera/internal/meson.build
>>> +++ b/include/libcamera/internal/meson.build
>>> @@ -23,6 +23,7 @@ libcamera_internal_headers = files([
>>>       'dma_buf_allocator.h',
>>>       'formats.h',
>>>       'framebuffer.h',
>>> +    'gbm.h',
>>>       'global_configuration.h',
>>>       'ipa_data_serializer.h',
>>>       'ipa_manager.h',
>>> diff --git a/src/libcamera/gbm.cpp b/src/libcamera/gbm.cpp
>>> new file mode 100644
>>> index 000000000..a2e4c7076
>>> --- /dev/null
>>> +++ b/src/libcamera/gbm.cpp
>>> @@ -0,0 +1,130 @@
>>> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
>>> +/*
>>> + * Copyright (C) 2024, Linaro Ltd.
>>> + *
>>> + * Authors:
>>> + * Bryan O'Donoghue<bryan.odonoghue@linaro.org>
>>> + *
>>> + * Helper class for managing GBM interactions
>>> + */
>>> +
>>> +#include "libcamera/internal/gbm.h"
>>> +
>>> +#include <errno.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)
>>> +
>>> +/**
>>> + * \class GBM
>>> + * \brief Helper class for managing GBM interactions
>>> + *
>>> + * The GBM class provides a simplified interface for creating and managing
>>> + * GBM devices. It handles the initialization and teardown of GBM devices
>>> + * used for buffer allocation in graphics and camera pipelines.
>>> + *
>>> + * This class is responsible for opening a DRI render node, creating a GBM
>>> + * device, and providing access to the device and its associated pixel format.
>>> + */
>>> +
>>> +/**
>>> + *\var GBM::fd_
>>> + *\brief file descriptor to DRI device
>>> + */
>>> +
>>> +/**
>>> + *\var GBM::gbmDevice_
>>> + *\brief Pointer to GBM device structure derived from fd_
>>> + */
>>> +
>>> +/**
>>> + *\var GBM::format_
>>> + *\brief Pixel format the GBM surface was created in
>>> + */
>>> +
>>> +/**
>>> + *\brief GBM constructor.
>>> + *
>>> + * Creates a GBM instance with unitialised state.
>>> + */
>>> +GBM::GBM()
>>> +{
>>> +    fd_ = 0;
>>> +    gbmDevice_ = nullptr;
>>> +}
>>> +
>>> +/**
>>> + *\brief GBM destructor
>>> + *
>>> + * Cleans up the GBM device if it was successfully created, and closes
>>> + * the associated file descriptor.
>>> + */
>>> +GBM::~GBM()
>>> +{
>>> +    if (gbmDevice_)
>>> +        gbm_device_destroy(gbmDevice_);
>>> +}
>>> +
>>> +/**
>>> + * \brief Create and initialize a GBM device
>>> + *
>>> + * \todo Get dri device name from envOption setting
>>> + *
>>> + * Opens the DRI render node (/dev/dri/renderD128) and creates a GBM
>>> + * device using the libgbm library. Sets the default pixel format to
>>> + * ARGB8888.
>>> + *
>>> + * \return 0 on success, or a negative error code on failure
>>> + */
>>> +int GBM::createDevice()
>>> +{
>>> +    const char *dri_node = "/dev/dri/renderD128";
>>> +
>>> +    fd_ = open(dri_node, O_RDWR | O_CLOEXEC);
>>> +    if (fd_ < 0) {
>>> +        LOG(GBM, Error) << "Open " << dri_node << " fail " << fd_;
>>> +        return fd_;
>>> +    }
>>> +
>>> +    gbmDevice_ = gbm_create_device(fd_);
>>> +    if (!gbmDevice_) {
>>> +        LOG(GBM, Error) << "gbm_create_device fail";
>>> +        close(fd_);
>>> +        return -errno;
>>> +    }
>>> +
>>> +    format_ = libcamera::formats::ARGB8888;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +/**
>>> + * \brief Retrieve the GBM device handle
>>> + *
>>> + * \return Pointer to the gbm_device structure, or nullptr if the device
>>> + * has not been created
>>> + */
>>> +struct gbm_device * GBM::getDevice()
>>> +{
>>> +    return gbmDevice_;
>>> +}
>>> +
>>> +/**
>>> + * \brief Retrieve the pixel format
>>> + *
>>> + * \return The PixelFormat used by this GBM instance (ARGB8888)
>>> + */
>>> +
>>> +PixelFormat GBM::getPixelFormat()
>>> +{
>>> +    return format_;
>>> +}
>>> +} /* namespace libcamera */
>>> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
>>> index 90d434a5a..685213c78 100644
>>> --- a/src/libcamera/meson.build
>>> +++ b/src/libcamera/meson.build
>>> @@ -70,6 +70,15 @@ 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
>>> +    libcamera_internal_sources += files([
>>> +        'gbm.cpp',
>>> +    ])
>>> +endif
>>> +
>>>   subdir('base')
>>>   subdir('converter')
>>>   subdir('ipa')
>>> @@ -178,6 +187,7 @@ libcamera_deps += [
>>>       libcamera_base_private,
>>>       libcrypto,
>>>       libdl,
>>> +    libgbm,
>>>       liblttng,
>>>       libudev,
>>>       libyaml,
Milan Zamazal Dec. 12, 2025, 7:40 p.m. UTC | #5
Bryan O'Donoghue <bryan.odonoghue@linaro.org> writes:

> A helper class to interact with GBM. This will allow us to specify the
> internal storage format of the GPU when making a texture for the Debayer
> vertex/fragment shaders and thus ensure we receive an uncompressed and
> untiled output buffer.
>
> Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Robert has some interesting points but if we decide to keep the current
version for now:

Reviewed-by: Milan Zamazal <mzamazal@redhat.com>

> ---
>  include/libcamera/internal/gbm.h       |  39 ++++++++
>  include/libcamera/internal/meson.build |   1 +
>  src/libcamera/gbm.cpp                  | 130 +++++++++++++++++++++++++
>  src/libcamera/meson.build              |  10 ++
>  4 files changed, 180 insertions(+)
>  create mode 100644 include/libcamera/internal/gbm.h
>  create mode 100644 src/libcamera/gbm.cpp
>
> diff --git a/include/libcamera/internal/gbm.h b/include/libcamera/internal/gbm.h
> new file mode 100644
> index 000000000..09811d1ef
> --- /dev/null
> +++ b/include/libcamera/internal/gbm.h
> @@ -0,0 +1,39 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2024, Linaro Ltd.
> + *
> + * Authors:
> + * Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> + *
> + * 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 createDevice();
> +	struct gbm_device *getDevice();
> +	PixelFormat getPixelFormat();
> +
> +private:
> +	int fd_;
> +	struct gbm_device *gbmDevice_;
> +	PixelFormat format_;
> +};
> +
> +} /* namespace libcamera */
> diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build
> index e9540a2f7..b8324996b 100644
> --- a/include/libcamera/internal/meson.build
> +++ b/include/libcamera/internal/meson.build
> @@ -23,6 +23,7 @@ libcamera_internal_headers = files([
>      'dma_buf_allocator.h',
>      'formats.h',
>      'framebuffer.h',
> +    'gbm.h',
>      'global_configuration.h',
>      'ipa_data_serializer.h',
>      'ipa_manager.h',
> diff --git a/src/libcamera/gbm.cpp b/src/libcamera/gbm.cpp
> new file mode 100644
> index 000000000..a2e4c7076
> --- /dev/null
> +++ b/src/libcamera/gbm.cpp
> @@ -0,0 +1,130 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2024, Linaro Ltd.
> + *
> + * Authors:
> + * Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> + *
> + * Helper class for managing GBM interactions
> + */
> +
> +#include "libcamera/internal/gbm.h"
> +
> +#include <errno.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)
> +
> +/**
> + * \class GBM
> + * \brief Helper class for managing GBM interactions
> + *
> + * The GBM class provides a simplified interface for creating and managing
> + * GBM devices. It handles the initialization and teardown of GBM devices
> + * used for buffer allocation in graphics and camera pipelines.
> + *
> + * This class is responsible for opening a DRI render node, creating a GBM
> + * device, and providing access to the device and its associated pixel format.
> + */
> +
> +/**
> + *\var GBM::fd_
> + *\brief file descriptor to DRI device
> + */
> +
> +/**
> + *\var GBM::gbmDevice_
> + *\brief Pointer to GBM device structure derived from fd_
> + */
> +
> +/**
> + *\var GBM::format_
> + *\brief Pixel format the GBM surface was created in
> + */
> +
> +/**
> + *\brief GBM constructor.
> + *
> + * Creates a GBM instance with unitialised state.
> + */
> +GBM::GBM()
> +{
> +	fd_ = 0;
> +	gbmDevice_ = nullptr;
> +}
> +
> +/**
> + *\brief GBM destructor
> + *
> + * Cleans up the GBM device if it was successfully created, and closes
> + * the associated file descriptor.
> + */
> +GBM::~GBM()
> +{
> +	if (gbmDevice_)
> +		gbm_device_destroy(gbmDevice_);
> +}
> +
> +/**
> + * \brief Create and initialize a GBM device
> + *
> + * \todo Get dri device name from envOption setting
> + *
> + * Opens the DRI render node (/dev/dri/renderD128) and creates a GBM
> + * device using the libgbm library. Sets the default pixel format to
> + * ARGB8888.
> + *
> + * \return 0 on success, or a negative error code on failure
> + */
> +int GBM::createDevice()
> +{
> +	const char *dri_node = "/dev/dri/renderD128";
> +
> +	fd_ = open(dri_node, O_RDWR | O_CLOEXEC);
> +	if (fd_ < 0) {
> +		LOG(GBM, Error) << "Open " << dri_node << " fail " << fd_;
> +		return fd_;
> +	}
> +
> +	gbmDevice_ = gbm_create_device(fd_);
> +	if (!gbmDevice_) {
> +		LOG(GBM, Error) << "gbm_create_device fail";
> +		close(fd_);
> +		return -errno;
> +	}
> +
> +	format_ = libcamera::formats::ARGB8888;
> +
> +	return 0;
> +}
> +
> +/**
> + * \brief Retrieve the GBM device handle
> + *
> + * \return Pointer to the gbm_device structure, or nullptr if the device
> + * has not been created
> + */
> +struct gbm_device * GBM::getDevice()
> +{
> +	return gbmDevice_;
> +}
> +
> +/**
> + * \brief Retrieve the pixel format
> + *
> + * \return The PixelFormat used by this GBM instance (ARGB8888)
> + */
> +
> +PixelFormat GBM::getPixelFormat()
> +{
> +	return format_;
> +}
> +} /* namespace libcamera */
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index 90d434a5a..685213c78 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -70,6 +70,15 @@ 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
> +    libcamera_internal_sources += files([
> +        'gbm.cpp',
> +    ])
> +endif
> +
>  subdir('base')
>  subdir('converter')
>  subdir('ipa')
> @@ -178,6 +187,7 @@ libcamera_deps += [
>      libcamera_base_private,
>      libcrypto,
>      libdl,
> +    libgbm,
>      liblttng,
>      libudev,
>      libyaml,
Robert Mader Dec. 12, 2025, 7:44 p.m. UTC | #6
On 12.12.25 20:37, Milan Zamazal wrote:
> Robert Mader <robert.mader@collabora.com> writes:
>
>> FTR., I gave this a quick try and it seems to work just fine on my test
>> devices. Pushed a commit here:
>> https://gitlab.freedesktop.org/rmader/libcamera/-/commits/v0.6.0-gpuisp-v8-fixes
> It fails in my environment with:
>
>    ERROR eGL egl.cpp:309 eglInitialize fail

What's the scenario here? Any chance that's because you start e.g. qcam 
via ssh, i.e. qt wants to initializes EGL with the Wayland or X11 
platform and the gpu-isp without? Because that'd be a somewhat special 
case (single-process app with multiple different EGL contexts) that'd 
need to get worked out.

It *should* work if you start the app directly on the device (via some 
launcher or terminal) or by forcing a display, e.g. 
`WAYLAND_DISPLAY=wayland-0 qcam`
Milan Zamazal Dec. 12, 2025, 7:56 p.m. UTC | #7
Robert Mader <robert.mader@collabora.com> writes:

> On 12.12.25 20:37, Milan Zamazal wrote:
>> Robert Mader <robert.mader@collabora.com> writes:
>>
>>> FTR., I gave this a quick try and it seems to work just fine on my test
>>> devices. Pushed a commit here:
>>> https://gitlab.freedesktop.org/rmader/libcamera/-/commits/v0.6.0-gpuisp-v8-fixes
>> It fails in my environment with:
>>
>>    ERROR eGL egl.cpp:309 eglInitialize fail
>
> What's the scenario here? Any chance that's because you start e.g. qcam via ssh, i.e. qt wants to
> initializes EGL with the Wayland or X11 platform and the gpu-isp without? Because that'd be a somewhat
> special case (single-process app with multiple different EGL contexts) that'd need to get worked out.
>
> It *should* work if you start the app directly on the device (via some launcher or terminal) or by forcing
> a display, e.g. `WAYLAND_DISPLAY=wayland-0 qcam`

This is with KMS, I connect via ssh and run

  cam -c1 -C -D

in the terminal.  No graphical environment is running on the board.
Robert Mader Dec. 12, 2025, 11:13 p.m. UTC | #8
On 12.12.25 20:56, Milan Zamazal wrote:
> Robert Mader<robert.mader@collabora.com> writes:
>
>> On 12.12.25 20:37, Milan Zamazal wrote:
>>> Robert Mader<robert.mader@collabora.com> writes:
>>>
>>>> FTR., I gave this a quick try and it seems to work just fine on my test
>>>> devices. Pushed a commit here:
>>>> https://gitlab.freedesktop.org/rmader/libcamera/-/commits/v0.6.0-gpuisp-v8-fixes
>>> It fails in my environment with:
>>>
>>>     ERROR eGL egl.cpp:309 eglInitialize fail
>> What's the scenario here? Any chance that's because you start e.g. qcam via ssh, i.e. qt wants to
>> initializes EGL with the Wayland or X11 platform and the gpu-isp without? Because that'd be a somewhat
>> special case (single-process app with multiple different EGL contexts) that'd need to get worked out.
>>
>> It *should* work if you start the app directly on the device (via some launcher or terminal) or by forcing
>> a display, e.g. `WAYLAND_DISPLAY=wayland-0 qcam`
> This is with KMS, I connect via ssh and run
>
>    cam -c1 -C -D
>
> in the terminal.  No graphical environment is running on the board.

I see, thanks. I pushed an additional commit that fixes the ssh case for 
me - could you give that a try?
Milan Zamazal Dec. 15, 2025, 1:30 p.m. UTC | #9
Robert Mader <robert.mader@collabora.com> writes:

> On 12.12.25 20:56, Milan Zamazal wrote:
>> Robert Mader<robert.mader@collabora.com> writes:
>>
>
>>> On 12.12.25 20:37, Milan Zamazal wrote:
>>>> Robert Mader<robert.mader@collabora.com> writes:
>>>>
>>>>> FTR., I gave this a quick try and it seems to work just fine on my test
>>>>> devices. Pushed a commit here:
>>>>> https://gitlab.freedesktop.org/rmader/libcamera/-/commits/v0.6.0-gpuisp-v8-fixes
>>>> It fails in my environment with:
>>>>
>>>>     ERROR eGL egl.cpp:309 eglInitialize fail
>>> What's the scenario here? Any chance that's because you start e.g. qcam via ssh, i.e. qt wants to
>>> initializes EGL with the Wayland or X11 platform and the gpu-isp without? Because that'd be a somewhat
>>> special case (single-process app with multiple different EGL contexts) that'd need to get worked out.
>>>
>>> It *should* work if you start the app directly on the device (via some launcher or terminal) or by
>>> forcing
>>> a display, e.g. `WAYLAND_DISPLAY=wayland-0 qcam`
>> This is with KMS, I connect via ssh and run
>>
>>    cam -c1 -C -D
>>
>> in the terminal.  No graphical environment is running on the board.
>
> I see, thanks. I pushed an additional commit that fixes the ssh case for me - could you give that a try?

0.6.0-gpuisp-v9-fixes works for me, thanks.

Patch
diff mbox series

diff --git a/include/libcamera/internal/gbm.h b/include/libcamera/internal/gbm.h
new file mode 100644
index 000000000..09811d1ef
--- /dev/null
+++ b/include/libcamera/internal/gbm.h
@@ -0,0 +1,39 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Linaro Ltd.
+ *
+ * Authors:
+ * Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+ *
+ * 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 createDevice();
+	struct gbm_device *getDevice();
+	PixelFormat getPixelFormat();
+
+private:
+	int fd_;
+	struct gbm_device *gbmDevice_;
+	PixelFormat format_;
+};
+
+} /* namespace libcamera */
diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build
index e9540a2f7..b8324996b 100644
--- a/include/libcamera/internal/meson.build
+++ b/include/libcamera/internal/meson.build
@@ -23,6 +23,7 @@  libcamera_internal_headers = files([
     'dma_buf_allocator.h',
     'formats.h',
     'framebuffer.h',
+    'gbm.h',
     'global_configuration.h',
     'ipa_data_serializer.h',
     'ipa_manager.h',
diff --git a/src/libcamera/gbm.cpp b/src/libcamera/gbm.cpp
new file mode 100644
index 000000000..a2e4c7076
--- /dev/null
+++ b/src/libcamera/gbm.cpp
@@ -0,0 +1,130 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Linaro Ltd.
+ *
+ * Authors:
+ * Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+ *
+ * Helper class for managing GBM interactions
+ */
+
+#include "libcamera/internal/gbm.h"
+
+#include <errno.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)
+
+/**
+ * \class GBM
+ * \brief Helper class for managing GBM interactions
+ *
+ * The GBM class provides a simplified interface for creating and managing
+ * GBM devices. It handles the initialization and teardown of GBM devices
+ * used for buffer allocation in graphics and camera pipelines.
+ *
+ * This class is responsible for opening a DRI render node, creating a GBM
+ * device, and providing access to the device and its associated pixel format.
+ */
+
+/**
+ *\var GBM::fd_
+ *\brief file descriptor to DRI device
+ */
+
+/**
+ *\var GBM::gbmDevice_
+ *\brief Pointer to GBM device structure derived from fd_
+ */
+
+/**
+ *\var GBM::format_
+ *\brief Pixel format the GBM surface was created in
+ */
+
+/**
+ *\brief GBM constructor.
+ *
+ * Creates a GBM instance with unitialised state.
+ */
+GBM::GBM()
+{
+	fd_ = 0;
+	gbmDevice_ = nullptr;
+}
+
+/**
+ *\brief GBM destructor
+ *
+ * Cleans up the GBM device if it was successfully created, and closes
+ * the associated file descriptor.
+ */
+GBM::~GBM()
+{
+	if (gbmDevice_)
+		gbm_device_destroy(gbmDevice_);
+}
+
+/**
+ * \brief Create and initialize a GBM device
+ *
+ * \todo Get dri device name from envOption setting
+ *
+ * Opens the DRI render node (/dev/dri/renderD128) and creates a GBM
+ * device using the libgbm library. Sets the default pixel format to
+ * ARGB8888.
+ *
+ * \return 0 on success, or a negative error code on failure
+ */
+int GBM::createDevice()
+{
+	const char *dri_node = "/dev/dri/renderD128";
+
+	fd_ = open(dri_node, O_RDWR | O_CLOEXEC);
+	if (fd_ < 0) {
+		LOG(GBM, Error) << "Open " << dri_node << " fail " << fd_;
+		return fd_;
+	}
+
+	gbmDevice_ = gbm_create_device(fd_);
+	if (!gbmDevice_) {
+		LOG(GBM, Error) << "gbm_create_device fail";
+		close(fd_);
+		return -errno;
+	}
+
+	format_ = libcamera::formats::ARGB8888;
+
+	return 0;
+}
+
+/**
+ * \brief Retrieve the GBM device handle
+ *
+ * \return Pointer to the gbm_device structure, or nullptr if the device
+ * has not been created
+ */
+struct gbm_device * GBM::getDevice()
+{
+	return gbmDevice_;
+}
+
+/**
+ * \brief Retrieve the pixel format
+ *
+ * \return The PixelFormat used by this GBM instance (ARGB8888)
+ */
+
+PixelFormat GBM::getPixelFormat()
+{
+	return format_;
+}
+} /* namespace libcamera */
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index 90d434a5a..685213c78 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -70,6 +70,15 @@  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
+    libcamera_internal_sources += files([
+        'gbm.cpp',
+    ])
+endif
+
 subdir('base')
 subdir('converter')
 subdir('ipa')
@@ -178,6 +187,7 @@  libcamera_deps += [
     libcamera_base_private,
     libcrypto,
     libdl,
+    libgbm,
     liblttng,
     libudev,
     libyaml,