libcamera: egl: Fix DRM format for GL_RG dmabuf import
diff mbox series

Message ID 20261021065624.153207-1-faizel.kb@gmail.com
State Superseded
Headers show
Series
  • libcamera: egl: Fix DRM format for GL_RG dmabuf import
Related show

Commit Message

Faizel K B Oct. 21, 2026, 6:56 a.m. UTC
Importing unpacked 10/12-bit Bayer input buffers (e.g. SGBRG10) as
dmabufs always fails with Mesa, and DebayerEGL silently falls back to
mapping each input buffer and uploading it with glTexImage2D() on every
frame:

  INFO Debayer debayer_egl.cpp:523 Importing input DMABuf failed, falling back to upload

The cause is the DRM format used for GL_RG textures. Unpacked Bayer
pixels are 16-bit little-endian words, loaded into a GL_RG texture with
the low byte in .r and the high byte in .g, which the shaders recombine
into a single sample. R and G here are texture channels, not colours.
GL names formats in memory byte order, while DRM fourccs describe the
components of a little-endian word from MSB to LSB:

  DRM_FORMAT_RG88  [15:0] R:G 8:8 little endian  -> byte 0 = G, byte 1 = R
  DRM_FORMAT_GR88  [15:0] G:R 8:8 little endian  -> byte 0 = R, byte 1 = G

The import path maps GL_RG to DRM_FORMAT_RG88, which has the opposite
byte order. Mesa has no RG88 entry in its DRI image format table, so
eglCreateImageKHR() fails.

Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
output path (GL_RGBA) are not affected.

Fixes: 6e23162ddcae ("egl: Add GL format parameter to eGLImage constructor")
Signed-off-by: Faizel K B <faizel.kb@gmail.com>
---

Notes:
    Tested on RK3588 (Mali-G610, Panfrost, Mesa 24.3.4) with an IMX415
    sensor (SGBRG10 unpacked, 3864x2192).
    
    Panfrost requires the row stride of linear dmabuf imports to be
    64-byte aligned. The SGBRG10 stride at 3864 pixels is 7728 bytes, so
    the import also needed a local rkcif change to honour the 256-byte
    aligned stride (7936) that DebayerEGL::preferredInputStride() requests.

 src/libcamera/egl.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Robert Mader Oct. 21, 2026, 9:13 a.m. UTC | #1
Hi, thanks for the patch!

On 21.10.26 08:56, Faizel K B wrote:
> Importing unpacked 10/12-bit Bayer input buffers (e.g. SGBRG10) as
> dmabufs always fails with Mesa, and DebayerEGL silently falls back to
> mapping each input buffer and uploading it with glTexImage2D() on every
> frame:
>
>    INFO Debayer debayer_egl.cpp:523 Importing input DMABuf failed, falling back to upload
>
> The cause is the DRM format used for GL_RG textures. Unpacked Bayer
> pixels are 16-bit little-endian words, loaded into a GL_RG texture with
> the low byte in .r and the high byte in .g, which the shaders recombine
> into a single sample. R and G here are texture channels, not colours.
> GL names formats in memory byte order, while DRM fourccs describe the
> components of a little-endian word from MSB to LSB:
>
>    DRM_FORMAT_RG88  [15:0] R:G 8:8 little endian  -> byte 0 = G, byte 1 = R
>    DRM_FORMAT_GR88  [15:0] G:R 8:8 little endian  -> byte 0 = R, byte 1 = G
>
> The import path maps GL_RG to DRM_FORMAT_RG88, which has the opposite
> byte order. Mesa has no RG88 entry in its DRI image format table, so
> eglCreateImageKHR() fails.
>
> Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
> supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
> output path (GL_RGBA) are not affected.
>
> Fixes: 6e23162ddcae ("egl: Add GL format parameter to eGLImage constructor")
> Signed-off-by: Faizel K B <faizel.kb@gmail.com>
> ---
>
> Notes:
>      Tested on RK3588 (Mali-G610, Panfrost, Mesa 24.3.4) with an IMX415
>      sensor (SGBRG10 unpacked, 3864x2192).
>      
>      Panfrost requires the row stride of linear dmabuf imports to be
>      64-byte aligned. The SGBRG10 stride at 3864 pixels is 7728 bytes, so
>      the import also needed a local rkcif change to honour the 256-byte
>      aligned stride (7936) that DebayerEGL::preferredInputStride() requests.
Note that V4L2 drivers don't need to honor the bytesperline request - 
you could also just align things to 64 bytes (7744) if that's enough for 
Panfrost. But optimally the upstream driver would honor the request and 
not hardcode any values - any chance you're looking into working on 
that? :)
>
>   src/libcamera/egl.cpp | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
> index 3cde9040a..59a7d8cf9 100644
> --- a/src/libcamera/egl.cpp
> +++ b/src/libcamera/egl.cpp
> @@ -184,7 +184,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
>   		drm_format = DRM_FORMAT_R8;
>   		break;
>   	case GL_RG:
> -		drm_format = DRM_FORMAT_RG88;
> +		drm_format = DRM_FORMAT_GR88;

Good catch!

Reviewed-by: Robert Mader <robert.mader@collabora.com>

>   		break;
>   	case GL_RGBA:
>   		drm_format = DRM_FORMAT_ARGB8888;
Barnabás Pőcze Oct. 21, 2026, 10:30 a.m. UTC | #2
Hi

2026. 10. 21. 8:56 keltezéssel, Faizel K B írta:
> Importing unpacked 10/12-bit Bayer input buffers (e.g. SGBRG10) as
> dmabufs always fails with Mesa, and DebayerEGL silently falls back to
> mapping each input buffer and uploading it with glTexImage2D() on every
> frame:
> 
>    INFO Debayer debayer_egl.cpp:523 Importing input DMABuf failed, falling back to upload
> 
> The cause is the DRM format used for GL_RG textures. Unpacked Bayer
> pixels are 16-bit little-endian words, loaded into a GL_RG texture with
> the low byte in .r and the high byte in .g, which the shaders recombine
> into a single sample. R and G here are texture channels, not colours.
> GL names formats in memory byte order, while DRM fourccs describe the
> components of a little-endian word from MSB to LSB:
> 
>    DRM_FORMAT_RG88  [15:0] R:G 8:8 little endian  -> byte 0 = G, byte 1 = R
>    DRM_FORMAT_GR88  [15:0] G:R 8:8 little endian  -> byte 0 = R, byte 1 = G
> 
> The import path maps GL_RG to DRM_FORMAT_RG88, which has the opposite
> byte order. Mesa has no RG88 entry in its DRI image format table, so
> eglCreateImageKHR() fails.
> 
> Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
> supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
> output path (GL_RGBA) are not affected.

The only thing that's not entirely clear to me is why GL_RGBA is not affected.

Tested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> # ipu6 + ov2740


> 
> Fixes: 6e23162ddcae ("egl: Add GL format parameter to eGLImage constructor")
> Signed-off-by: Faizel K B <faizel.kb@gmail.com>
> ---
> 
> Notes:
>      Tested on RK3588 (Mali-G610, Panfrost, Mesa 24.3.4) with an IMX415
>      sensor (SGBRG10 unpacked, 3864x2192).
>      
>      Panfrost requires the row stride of linear dmabuf imports to be
>      64-byte aligned. The SGBRG10 stride at 3864 pixels is 7728 bytes, so
>      the import also needed a local rkcif change to honour the 256-byte
>      aligned stride (7936) that DebayerEGL::preferredInputStride() requests.
> 
>   src/libcamera/egl.cpp | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
> index 3cde9040a..59a7d8cf9 100644
> --- a/src/libcamera/egl.cpp
> +++ b/src/libcamera/egl.cpp
> @@ -184,7 +184,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
>   		drm_format = DRM_FORMAT_R8;
>   		break;
>   	case GL_RG:
> -		drm_format = DRM_FORMAT_RG88;
> +		drm_format = DRM_FORMAT_GR88;
>   		break;
>   	case GL_RGBA:
>   		drm_format = DRM_FORMAT_ARGB8888;
Robert Mader Oct. 21, 2026, 11:29 a.m. UTC | #3
Hi,

On 21.10.26 12:30, Barnabás Pőcze wrote:
> Hi
>
> 2026. 10. 21. 8:56 keltezéssel, Faizel K B írta:
>> Importing unpacked 10/12-bit Bayer input buffers (e.g. SGBRG10) as
>> dmabufs always fails with Mesa, and DebayerEGL silently falls back to
>> mapping each input buffer and uploading it with glTexImage2D() on every
>> frame:
>>
>>    INFO Debayer debayer_egl.cpp:523 Importing input DMABuf failed, 
>> falling back to upload
>>
>> The cause is the DRM format used for GL_RG textures. Unpacked Bayer
>> pixels are 16-bit little-endian words, loaded into a GL_RG texture with
>> the low byte in .r and the high byte in .g, which the shaders recombine
>> into a single sample. R and G here are texture channels, not colours.
>> GL names formats in memory byte order, while DRM fourccs describe the
>> components of a little-endian word from MSB to LSB:
>>
>>    DRM_FORMAT_RG88  [15:0] R:G 8:8 little endian  -> byte 0 = G, byte 
>> 1 = R
>>    DRM_FORMAT_GR88  [15:0] G:R 8:8 little endian  -> byte 0 = R, byte 
>> 1 = G
>>
>> The import path maps GL_RG to DRM_FORMAT_RG88, which has the opposite
>> byte order. Mesa has no RG88 entry in its DRI image format table, so
>> eglCreateImageKHR() fails.
>>
>> Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
>> supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
>> output path (GL_RGBA) are not affected.
>
> The only thing that's not entirely clear to me is why GL_RGBA is not 
> affected.

The mapping from GL_RGBA <-> DRM_FORMAT_ARGB8888 already uses the 
inverted order, so that makes sense, no?


>
> Tested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> # ipu6 + 
> ov2740
>
>
>>
>> Fixes: 6e23162ddcae ("egl: Add GL format parameter to eGLImage 
>> constructor")
>> Signed-off-by: Faizel K B <faizel.kb@gmail.com>
>> ---
>>
>> Notes:
>>      Tested on RK3588 (Mali-G610, Panfrost, Mesa 24.3.4) with an IMX415
>>      sensor (SGBRG10 unpacked, 3864x2192).
>>           Panfrost requires the row stride of linear dmabuf imports 
>> to be
>>      64-byte aligned. The SGBRG10 stride at 3864 pixels is 7728 
>> bytes, so
>>      the import also needed a local rkcif change to honour the 256-byte
>>      aligned stride (7936) that DebayerEGL::preferredInputStride() 
>> requests.
>>
>>   src/libcamera/egl.cpp | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
>> index 3cde9040a..59a7d8cf9 100644
>> --- a/src/libcamera/egl.cpp
>> +++ b/src/libcamera/egl.cpp
>> @@ -184,7 +184,7 @@ int eGL::createDMABufTexture2D(eGLImage 
>> &eglImage, int fd, bool output)
>>           drm_format = DRM_FORMAT_R8;
>>           break;
>>       case GL_RG:
>> -        drm_format = DRM_FORMAT_RG88;
>> +        drm_format = DRM_FORMAT_GR88;
>>           break;
>>       case GL_RGBA:
>>           drm_format = DRM_FORMAT_ARGB8888;
Barnabás Pőcze Oct. 21, 2026, 11:35 a.m. UTC | #4
2026. 10. 21. 13:29 keltezéssel, Robert Mader írta:
> Hi,
> 
> On 21.10.26 12:30, Barnabás Pőcze wrote:
>> Hi
>>
>> 2026. 10. 21. 8:56 keltezéssel, Faizel K B írta:
>>> Importing unpacked 10/12-bit Bayer input buffers (e.g. SGBRG10) as
>>> dmabufs always fails with Mesa, and DebayerEGL silently falls back to
>>> mapping each input buffer and uploading it with glTexImage2D() on every
>>> frame:
>>>
>>>    INFO Debayer debayer_egl.cpp:523 Importing input DMABuf failed, falling back to upload
>>>
>>> The cause is the DRM format used for GL_RG textures. Unpacked Bayer
>>> pixels are 16-bit little-endian words, loaded into a GL_RG texture with
>>> the low byte in .r and the high byte in .g, which the shaders recombine
>>> into a single sample. R and G here are texture channels, not colours.
>>> GL names formats in memory byte order, while DRM fourccs describe the
>>> components of a little-endian word from MSB to LSB:
>>>
>>>    DRM_FORMAT_RG88  [15:0] R:G 8:8 little endian  -> byte 0 = G, byte 1 = R
>>>    DRM_FORMAT_GR88  [15:0] G:R 8:8 little endian  -> byte 0 = R, byte 1 = G
>>>
>>> The import path maps GL_RG to DRM_FORMAT_RG88, which has the opposite
>>> byte order. Mesa has no RG88 entry in its DRI image format table, so
>>> eglCreateImageKHR() fails.
>>>
>>> Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
>>> supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
>>> output path (GL_RGBA) are not affected.
>>
>> The only thing that's not entirely clear to me is why GL_RGBA is not affected.
> 
> The mapping from GL_RGBA <-> DRM_FORMAT_ARGB8888 already uses the inverted order, so that makes sense, no?

I'd have expected DRM_FORMAT_ABGR8888, since

   /* [31:0] A:B:G:R 8:8:8:8 little endian */

so the memory order is RGBA. But I must be missing something.


> 
> 
>>
>> Tested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> # ipu6 + ov2740
>>
>>
>>>
>>> Fixes: 6e23162ddcae ("egl: Add GL format parameter to eGLImage constructor")
>>> Signed-off-by: Faizel K B <faizel.kb@gmail.com>
>>> ---
>>>
>>> Notes:
>>>      Tested on RK3588 (Mali-G610, Panfrost, Mesa 24.3.4) with an IMX415
>>>      sensor (SGBRG10 unpacked, 3864x2192).
>>>           Panfrost requires the row stride of linear dmabuf imports to be
>>>      64-byte aligned. The SGBRG10 stride at 3864 pixels is 7728 bytes, so
>>>      the import also needed a local rkcif change to honour the 256-byte
>>>      aligned stride (7936) that DebayerEGL::preferredInputStride() requests.
>>>
>>>   src/libcamera/egl.cpp | 2 +-
>>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
>>> index 3cde9040a..59a7d8cf9 100644
>>> --- a/src/libcamera/egl.cpp
>>> +++ b/src/libcamera/egl.cpp
>>> @@ -184,7 +184,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
>>>           drm_format = DRM_FORMAT_R8;
>>>           break;
>>>       case GL_RG:
>>> -        drm_format = DRM_FORMAT_RG88;
>>> +        drm_format = DRM_FORMAT_GR88;
>>>           break;
>>>       case GL_RGBA:
>>>           drm_format = DRM_FORMAT_ARGB8888;
Robert Mader Oct. 21, 2026, 11:44 a.m. UTC | #5
On 21.10.26 13:35, Barnabás Pőcze wrote:
> 2026. 10. 21. 13:29 keltezéssel, Robert Mader írta:
>> Hi,
>>
>> On 21.10.26 12:30, Barnabás Pőcze wrote:
>>> Hi
>>>
>>> 2026. 10. 21. 8:56 keltezéssel, Faizel K B írta:
>>>> Importing unpacked 10/12-bit Bayer input buffers (e.g. SGBRG10) as
>>>> dmabufs always fails with Mesa, and DebayerEGL silently falls back to
>>>> mapping each input buffer and uploading it with glTexImage2D() on 
>>>> every
>>>> frame:
>>>>
>>>>    INFO Debayer debayer_egl.cpp:523 Importing input DMABuf failed, 
>>>> falling back to upload
>>>>
>>>> The cause is the DRM format used for GL_RG textures. Unpacked Bayer
>>>> pixels are 16-bit little-endian words, loaded into a GL_RG texture 
>>>> with
>>>> the low byte in .r and the high byte in .g, which the shaders 
>>>> recombine
>>>> into a single sample. R and G here are texture channels, not colours.
>>>> GL names formats in memory byte order, while DRM fourccs describe the
>>>> components of a little-endian word from MSB to LSB:
>>>>
>>>>    DRM_FORMAT_RG88  [15:0] R:G 8:8 little endian  -> byte 0 = G, 
>>>> byte 1 = R
>>>>    DRM_FORMAT_GR88  [15:0] G:R 8:8 little endian  -> byte 0 = R, 
>>>> byte 1 = G
>>>>
>>>> The import path maps GL_RG to DRM_FORMAT_RG88, which has the opposite
>>>> byte order. Mesa has no RG88 entry in its DRI image format table, so
>>>> eglCreateImageKHR() fails.
>>>>
>>>> Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
>>>> supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
>>>> output path (GL_RGBA) are not affected.
>>>
>>> The only thing that's not entirely clear to me is why GL_RGBA is not 
>>> affected.
>>
>> The mapping from GL_RGBA <-> DRM_FORMAT_ARGB8888 already uses the 
>> inverted order, so that makes sense, no?
>
> I'd have expected DRM_FORMAT_ABGR8888, since
>
>   /* [31:0] A:B:G:R 8:8:8:8 little endian */
>
> so the memory order is RGBA. But I must be missing something.

Urgh. I think you're right. This format is only used for the output 
buffer, not the input ones - and we require the dmabuf import to succeed 
in that case, so there's no fallback path.

If we have a R-B swap here - then we most likely also have one in the 
shaders, compensating for it.

>
>
>>
>>
>>>
>>> Tested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> # ipu6 + 
>>> ov2740
>>>
>>>
>>>>
>>>> Fixes: 6e23162ddcae ("egl: Add GL format parameter to eGLImage 
>>>> constructor")
>>>> Signed-off-by: Faizel K B <faizel.kb@gmail.com>
>>>> ---
>>>>
>>>> Notes:
>>>>      Tested on RK3588 (Mali-G610, Panfrost, Mesa 24.3.4) with an 
>>>> IMX415
>>>>      sensor (SGBRG10 unpacked, 3864x2192).
>>>>           Panfrost requires the row stride of linear dmabuf imports 
>>>> to be
>>>>      64-byte aligned. The SGBRG10 stride at 3864 pixels is 7728 
>>>> bytes, so
>>>>      the import also needed a local rkcif change to honour the 
>>>> 256-byte
>>>>      aligned stride (7936) that DebayerEGL::preferredInputStride() 
>>>> requests.
>>>>
>>>>   src/libcamera/egl.cpp | 2 +-
>>>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>>>
>>>> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
>>>> index 3cde9040a..59a7d8cf9 100644
>>>> --- a/src/libcamera/egl.cpp
>>>> +++ b/src/libcamera/egl.cpp
>>>> @@ -184,7 +184,7 @@ int eGL::createDMABufTexture2D(eGLImage 
>>>> &eglImage, int fd, bool output)
>>>>           drm_format = DRM_FORMAT_R8;
>>>>           break;
>>>>       case GL_RG:
>>>> -        drm_format = DRM_FORMAT_RG88;
>>>> +        drm_format = DRM_FORMAT_GR88;
>>>>           break;
>>>>       case GL_RGBA:
>>>>           drm_format = DRM_FORMAT_ARGB8888;
>
Laurent Pinchart Oct. 21, 2026, 12:11 p.m. UTC | #6
On Tue, Oct 20, 2026 at 11:56:24PM -0700, Faizel K B wrote:
> Importing unpacked 10/12-bit Bayer input buffers (e.g. SGBRG10) as
> dmabufs always fails with Mesa, and DebayerEGL silently falls back to
> mapping each input buffer and uploading it with glTexImage2D() on every
> frame:
> 
>   INFO Debayer debayer_egl.cpp:523 Importing input DMABuf failed, falling back to upload

That's not very silent, is it ?

> The cause is the DRM format used for GL_RG textures. Unpacked Bayer
> pixels are 16-bit little-endian words, loaded into a GL_RG texture with
> the low byte in .r and the high byte in .g, which the shaders recombine
> into a single sample. R and G here are texture channels, not colours.
> GL names formats in memory byte order, while DRM fourccs describe the
> components of a little-endian word from MSB to LSB:
> 
>   DRM_FORMAT_RG88  [15:0] R:G 8:8 little endian  -> byte 0 = G, byte 1 = R
>   DRM_FORMAT_GR88  [15:0] G:R 8:8 little endian  -> byte 0 = R, byte 1 = G
> 
> The import path maps GL_RG to DRM_FORMAT_RG88, which has the opposite
> byte order. Mesa has no RG88 entry in its DRI image format table, so
> eglCreateImageKHR() fails.

I've checked mesa and can confirm that.

> Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
> supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
> output path (GL_RGBA) are not affected.
> 
> Fixes: 6e23162ddcae ("egl: Add GL format parameter to eGLImage constructor")
> Signed-off-by: Faizel K B <faizel.kb@gmail.com>
> ---
> 
> Notes:
>     Tested on RK3588 (Mali-G610, Panfrost, Mesa 24.3.4) with an IMX415
>     sensor (SGBRG10 unpacked, 3864x2192).
>     
>     Panfrost requires the row stride of linear dmabuf imports to be
>     64-byte aligned. The SGBRG10 stride at 3864 pixels is 7728 bytes, so
>     the import also needed a local rkcif change to honour the 256-byte
>     aligned stride (7936) that DebayerEGL::preferredInputStride() requests.

Do you plan to upstream that ?

With s/silently // in the commit message (which we can handle when
applying, no need for a v2),

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

>  src/libcamera/egl.cpp | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
> index 3cde9040a..59a7d8cf9 100644
> --- a/src/libcamera/egl.cpp
> +++ b/src/libcamera/egl.cpp
> @@ -184,7 +184,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
>  		drm_format = DRM_FORMAT_R8;
>  		break;
>  	case GL_RG:
> -		drm_format = DRM_FORMAT_RG88;
> +		drm_format = DRM_FORMAT_GR88;
>  		break;
>  	case GL_RGBA:
>  		drm_format = DRM_FORMAT_ARGB8888;
Barnabás Pőcze Oct. 21, 2026, 12:48 p.m. UTC | #7
2026. 10. 21. 13:44 keltezéssel, Robert Mader írta:
> On 21.10.26 13:35, Barnabás Pőcze wrote:
>> 2026. 10. 21. 13:29 keltezéssel, Robert Mader írta:
>>> Hi,
>>>
>>> On 21.10.26 12:30, Barnabás Pőcze wrote:
>>>> Hi
>>>>
>>>> 2026. 10. 21. 8:56 keltezéssel, Faizel K B írta:
>>>>> Importing unpacked 10/12-bit Bayer input buffers (e.g. SGBRG10) as
>>>>> dmabufs always fails with Mesa, and DebayerEGL silently falls back to
>>>>> mapping each input buffer and uploading it with glTexImage2D() on every
>>>>> frame:
>>>>>
>>>>>    INFO Debayer debayer_egl.cpp:523 Importing input DMABuf failed, falling back to upload
>>>>>
>>>>> The cause is the DRM format used for GL_RG textures. Unpacked Bayer
>>>>> pixels are 16-bit little-endian words, loaded into a GL_RG texture with
>>>>> the low byte in .r and the high byte in .g, which the shaders recombine
>>>>> into a single sample. R and G here are texture channels, not colours.
>>>>> GL names formats in memory byte order, while DRM fourccs describe the
>>>>> components of a little-endian word from MSB to LSB:
>>>>>
>>>>>    DRM_FORMAT_RG88  [15:0] R:G 8:8 little endian  -> byte 0 = G, byte 1 = R
>>>>>    DRM_FORMAT_GR88  [15:0] G:R 8:8 little endian  -> byte 0 = R, byte 1 = G
>>>>>
>>>>> The import path maps GL_RG to DRM_FORMAT_RG88, which has the opposite
>>>>> byte order. Mesa has no RG88 entry in its DRI image format table, so
>>>>> eglCreateImageKHR() fails.
>>>>>
>>>>> Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
>>>>> supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
>>>>> output path (GL_RGBA) are not affected.
>>>>
>>>> The only thing that's not entirely clear to me is why GL_RGBA is not affected.
>>>
>>> The mapping from GL_RGBA <-> DRM_FORMAT_ARGB8888 already uses the inverted order, so that makes sense, no?
>>
>> I'd have expected DRM_FORMAT_ABGR8888, since
>>
>>   /* [31:0] A:B:G:R 8:8:8:8 little endian */
>>
>> so the memory order is RGBA. But I must be missing something.
> 
> Urgh. I think you're right. This format is only used for the output buffer, not the input ones - and we require the dmabuf import to succeed in that case, so there's no fallback path.
> 
> If we have a R-B swap here - then we most likely also have one in the shaders, compensating for it.
> 

After some testing, I think "... output path (GL_RGBA) are not affected" is not entirely correct.
It is affected, it's just not visible.


```
diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag
index 0b641a5f3..e5a4f4b10 100644
--- a/src/libcamera/shaders/bayer_1x_packed.frag
+++ b/src/libcamera/shaders/bayer_1x_packed.frag
@@ -255,4 +255,6 @@ void main(void)
  #else
         gl_FragColor = vec4(rgb, 1.0);
  #endif
+
+       gl_FragColor = vec4(1, 0.5, 0.25, 1);
  }
diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag
index 10c5e941b..e52164703 100644
--- a/src/libcamera/shaders/bayer_unpacked.frag
+++ b/src/libcamera/shaders/bayer_unpacked.frag
@@ -157,4 +157,6 @@ void main(void) {
  #else
      gl_FragColor = vec4(rgb, 1.0);
  #endif
+
+       gl_FragColor = vec4(1, 0.5, 0.25, 1);
  }
```

$ cam -c1 -C1 --file=/tmp/asd.bin
$ hexdump -n4 -C /tmp/asd.bin
00000000  40 80 ff ff                                       |@...|
00000004

which corresponds to the BGRA memory order. The reason why it apparently works
in the first place, well, that eludes me for now, but I think we might want to
extend this patch with the following:

```
diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
index 3cde9040a..aeedc5de3 100644
--- a/src/libcamera/egl.cpp
+++ b/src/libcamera/egl.cpp
@@ -187,7 +187,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
                 drm_format = DRM_FORMAT_RG88;
                 break;
         case GL_RGBA:
-               drm_format = DRM_FORMAT_ARGB8888;
+               drm_format = DRM_FORMAT_ABGR8888;
                 break;
         default:
                 LOG(eGL, Error) << "unhandled GL format";
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 300822f9d..cb9908e1d 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -150,10 +150,10 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm
         switch (outputFormat) {
         case formats::ARGB8888:
         case formats::XRGB8888:
+               egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
                 break;
         case formats::ABGR8888:
         case formats::XBGR8888:
-               egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
                 break;
         default:
                 LOG(Debayer, Error) << "Unsupported output format";
```

because that will remove the inconsistency.


>>
>>
>>>
>>>
>>>>
>>>> Tested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> # ipu6 + ov2740
>>>>
>>>>
>>>>>
>>>>> Fixes: 6e23162ddcae ("egl: Add GL format parameter to eGLImage constructor")
>>>>> Signed-off-by: Faizel K B <faizel.kb@gmail.com>
>>>>> ---
>>>>>
>>>>> Notes:
>>>>>      Tested on RK3588 (Mali-G610, Panfrost, Mesa 24.3.4) with an IMX415
>>>>>      sensor (SGBRG10 unpacked, 3864x2192).
>>>>>           Panfrost requires the row stride of linear dmabuf imports to be
>>>>>      64-byte aligned. The SGBRG10 stride at 3864 pixels is 7728 bytes, so
>>>>>      the import also needed a local rkcif change to honour the 256-byte
>>>>>      aligned stride (7936) that DebayerEGL::preferredInputStride() requests.
>>>>>
>>>>>   src/libcamera/egl.cpp | 2 +-
>>>>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
>>>>> index 3cde9040a..59a7d8cf9 100644
>>>>> --- a/src/libcamera/egl.cpp
>>>>> +++ b/src/libcamera/egl.cpp
>>>>> @@ -184,7 +184,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
>>>>>           drm_format = DRM_FORMAT_R8;
>>>>>           break;
>>>>>       case GL_RG:
>>>>> -        drm_format = DRM_FORMAT_RG88;
>>>>> +        drm_format = DRM_FORMAT_GR88;
>>>>>           break;
>>>>>       case GL_RGBA:
>>>>>           drm_format = DRM_FORMAT_ARGB8888;
>>
Laurent Pinchart Oct. 21, 2026, 12:48 p.m. UTC | #8
On Wed, Oct 21, 2026 at 01:44:03PM +0200, Robert Mader wrote:
> On 21.10.26 13:35, Barnabás Pőcze wrote:
> > 2026. 10. 21. 13:29 keltezéssel, Robert Mader írta:
> >> Hi,
> >>
> >> On 21.10.26 12:30, Barnabás Pőcze wrote:
> >>> Hi
> >>>
> >>> 2026. 10. 21. 8:56 keltezéssel, Faizel K B írta:
> >>>> Importing unpacked 10/12-bit Bayer input buffers (e.g. SGBRG10) as
> >>>> dmabufs always fails with Mesa, and DebayerEGL silently falls back to
> >>>> mapping each input buffer and uploading it with glTexImage2D() on 
> >>>> every
> >>>> frame:
> >>>>
> >>>>    INFO Debayer debayer_egl.cpp:523 Importing input DMABuf failed, 
> >>>> falling back to upload
> >>>>
> >>>> The cause is the DRM format used for GL_RG textures. Unpacked Bayer
> >>>> pixels are 16-bit little-endian words, loaded into a GL_RG texture 
> >>>> with
> >>>> the low byte in .r and the high byte in .g, which the shaders 
> >>>> recombine
> >>>> into a single sample. R and G here are texture channels, not colours.
> >>>> GL names formats in memory byte order, while DRM fourccs describe the
> >>>> components of a little-endian word from MSB to LSB:
> >>>>
> >>>>    DRM_FORMAT_RG88  [15:0] R:G 8:8 little endian  -> byte 0 = G, 
> >>>> byte 1 = R
> >>>>    DRM_FORMAT_GR88  [15:0] G:R 8:8 little endian  -> byte 0 = R, 
> >>>> byte 1 = G
> >>>>
> >>>> The import path maps GL_RG to DRM_FORMAT_RG88, which has the opposite
> >>>> byte order. Mesa has no RG88 entry in its DRI image format table, so
> >>>> eglCreateImageKHR() fails.
> >>>>
> >>>> Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
> >>>> supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
> >>>> output path (GL_RGBA) are not affected.
> >>>
> >>> The only thing that's not entirely clear to me is why GL_RGBA is not 
> >>> affected.
> >>
> >> The mapping from GL_RGBA <-> DRM_FORMAT_ARGB8888 already uses the 
> >> inverted order, so that makes sense, no?
> >
> > I'd have expected DRM_FORMAT_ABGR8888, since
> >
> >   /* [31:0] A:B:G:R 8:8:8:8 little endian */
> >
> > so the memory order is RGBA. But I must be missing something.

Here are the three relevant entries in dri2_format_table[]
(src/gallium/frontends/dri/dri_helpers.c) in Mesa:

      { DRM_FORMAT_ARGB8888,      __DRI_IMAGE_FORMAT_ARGB8888,
        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_BGRA8888_UNORM, 1,
        { { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB8888 } } },
      { DRM_FORMAT_ABGR8888,      __DRI_IMAGE_FORMAT_ABGR8888,
        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_RGBA8888_UNORM, 1,
        { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR8888 } } },
      { DRM_FORMAT_GR88,          __DRI_IMAGE_FORMAT_GR88,
        __DRI_IMAGE_COMPONENTS_RG,        PIPE_FORMAT_RG88_UNORM, 1,
        { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 } } },

Note that the table doesn't contain any entry for the DRM_FORMAT_RG88,
DRM_FORMAT_BGRA8888 or DRM_FORMAT_RGBA8888 formats (even though
PIPE_FORMAT_GR88_UNORM, PIPE_FORMAT_ABGR8888_UNORM and
PIPE_FORMAT_ARGB8888_UNORM exist in Mesa).

It's also worth noting that the format_mapping[] table in
src/gallium/frontends/dri/dri_util.c contains the following entries:

   {
      .image_format    = __DRI_IMAGE_FORMAT_ARGB8888,
      .mesa_format     =        MESA_FORMAT_B8G8R8A8_UNORM,
      .internal_format =        GL_RGBA8,
   },
   {
      .image_format    = __DRI_IMAGE_FORMAT_ABGR8888,
      .mesa_format     =        MESA_FORMAT_R8G8B8A8_UNORM,
      .internal_format =        GL_RGBA8,
   },
   {
      .image_format    = __DRI_IMAGE_FORMAT_GR88,
      .mesa_format     =        MESA_FORMAT_RG_UNORM8,
      .internal_format =        GL_RG8,
   },
   {
      .image_format    = __DRI_IMAGE_FORMAT_GR88,
      .mesa_format     =        MESA_FORMAT_LA_UNORM8,
      .internal_format =        GL_RG8,
   },

> Urgh. I think you're right. This format is only used for the output 
> buffer, not the input ones - and we require the dmabuf import to succeed 
> in that case, so there's no fallback path.
> 
> If we have a R-B swap here - then we most likely also have one in the 
> shaders, compensating for it.

We have

	switch (outputFormat) {
	case formats::ARGB8888:
	case formats::XRGB8888:
		break;  
	case formats::ABGR8888:
	case formats::XBGR8888:
		egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
		break;							
	default:
		LOG(Debayer, Error) << "Unsupported output format";
		return -EINVAL;
	}

in DebayerEGL::initBayerShaders(), and

#if defined (SWAP_BLUE)
    gl_FragColor = vec4(rgb.bgr, 1.0);
#else
    gl_FragColor = vec4(rgb, 1.0);
#endif

in the shaders.

Unless I'm mistaken, while GL_RG and GL_RGBA may map by default to R, G,
B and A stored in bytes 0, 1, 2 and 3 respectively, the actual byte
order in memory can be overridden with EGL_LINUX_DRM_FOURCC_EXT when
calling eglCreateImageKHR(). This is documented in
https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt:

    The ordering of samples within a plane is taken from the drm_fourcc
    pixel_format specified for EGL_LINUX_DRM_FOURCC_EXT.

It therefore doesn't matter much if we map GL_RGBA to
DRM_FORMAT_ARGB8888 or DRM_FORMAT_ABGR8888, as long as both are
supported by the GPU. Similarly, mapping GL_RG to DRM_FORMAT_RG88 would
be absolutely fine if it wasn't for the fact that Mesa doesn't support
that mapping (likely because no GPU supports it).

If GL_RGBA would indeed map natively to DRM_FORMAT_ABGR8888 unless
specified otherwise, it's probably safe to consider DRM_FORMAT_ABGR8888
as more widely supported by GPUs than DRM_FORMAT_ARGB8888. It would then
be better to use DRM_FORMAT_ABGR8888 to ensure compatibility with a
wider range of GPUs.

Could someone test mapping GL_RGBA to GL_ABGR, and setting SWAP_BLUE for
formats::[AX]RGB8888 instead of formats::[AX]BGR8888 ?

The commit message of this patch should probably be updated to reflect
the above (if my explanation is correct).

> >>> Tested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> # ipu6 + 
> >>> ov2740
> >>>
> >>>> Fixes: 6e23162ddcae ("egl: Add GL format parameter to eGLImage 
> >>>> constructor")
> >>>> Signed-off-by: Faizel K B <faizel.kb@gmail.com>
> >>>> ---
> >>>>
> >>>> Notes:
> >>>>      Tested on RK3588 (Mali-G610, Panfrost, Mesa 24.3.4) with an 
> >>>> IMX415
> >>>>      sensor (SGBRG10 unpacked, 3864x2192).
> >>>>           Panfrost requires the row stride of linear dmabuf imports 
> >>>> to be
> >>>>      64-byte aligned. The SGBRG10 stride at 3864 pixels is 7728 
> >>>> bytes, so
> >>>>      the import also needed a local rkcif change to honour the 
> >>>> 256-byte
> >>>>      aligned stride (7936) that DebayerEGL::preferredInputStride() 
> >>>> requests.
> >>>>
> >>>>   src/libcamera/egl.cpp | 2 +-
> >>>>   1 file changed, 1 insertion(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
> >>>> index 3cde9040a..59a7d8cf9 100644
> >>>> --- a/src/libcamera/egl.cpp
> >>>> +++ b/src/libcamera/egl.cpp
> >>>> @@ -184,7 +184,7 @@ int eGL::createDMABufTexture2D(eGLImage 
> >>>> &eglImage, int fd, bool output)
> >>>>           drm_format = DRM_FORMAT_R8;
> >>>>           break;
> >>>>       case GL_RG:
> >>>> -        drm_format = DRM_FORMAT_RG88;
> >>>> +        drm_format = DRM_FORMAT_GR88;
> >>>>           break;
> >>>>       case GL_RGBA:
> >>>>           drm_format = DRM_FORMAT_ARGB8888;
Faizel K B Oct. 22, 2026, 12:12 a.m. UTC | #9
On Wed, Oct 21, 2026 at 11:13:01AM +0200, Robert Mader wrote:
>Hi, thanks for the patch!
>

>>
>>Notes:
>>     Tested on RK3588 (Mali-G610, Panfrost, Mesa 24.3.4) with an IMX415
>>     sensor (SGBRG10 unpacked, 3864x2192).
>>     Panfrost requires the row stride of linear dmabuf imports to be
>>     64-byte aligned. The SGBRG10 stride at 3864 pixels is 7728 bytes, so
>>     the import also needed a local rkcif change to honour the 256-byte
>>     aligned stride (7936) that DebayerEGL::preferredInputStride() requests.
>Note that V4L2 drivers don't need to honor the bytesperline request - 
>you could also just align things to 64 bytes (7744) if that's enough 
>for Panfrost. But optimally the upstream driver would honor the 
>request and not hardcode any values - any chance you're looking into 
>working on that? :)

Yes. I am planning to work on it.

>>
>>  src/libcamera/egl.cpp | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>>diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
>>index 3cde9040a..59a7d8cf9 100644
>>--- a/src/libcamera/egl.cpp
>>+++ b/src/libcamera/egl.cpp
>>@@ -184,7 +184,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
>>  		drm_format = DRM_FORMAT_R8;
>>  		break;
>>  	case GL_RG:
>>-		drm_format = DRM_FORMAT_RG88;
>>+		drm_format = DRM_FORMAT_GR88;
>
>Good catch!
>
>Reviewed-by: Robert Mader <robert.mader@collabora.com>

Thanks for the review. I am planning to send a two set patch for addressing the
comments on this and output path (GL_RGBA).
Faizel K B Oct. 22, 2026, 12:33 a.m. UTC | #10
Hi,

Thank you all for the reviews and the testing.


>> >>>>
>> >>>> Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
>> >>>> supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
>> >>>> output path (GL_RGBA) are not affected.
>> >>>
>> >>> The only thing that's not entirely clear to me is why GL_RGBA is not
>> >>> affected.
>> >>
>> >> The mapping from GL_RGBA <-> DRM_FORMAT_ARGB8888 already uses the
>> >> inverted order, so that makes sense, no?
>> >
>> > I'd have expected DRM_FORMAT_ABGR8888, since
>> >
>> >   /* [31:0] A:B:G:R 8:8:8:8 little endian */
>> >
>> > so the memory order is RGBA. But I must be missing something.
>
>Here are the three relevant entries in dri2_format_table[]
>(src/gallium/frontends/dri/dri_helpers.c) in Mesa:
>
>      { DRM_FORMAT_ARGB8888,      __DRI_IMAGE_FORMAT_ARGB8888,
>        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_BGRA8888_UNORM, 1,
>        { { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB8888 } } },
>      { DRM_FORMAT_ABGR8888,      __DRI_IMAGE_FORMAT_ABGR8888,
>        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_RGBA8888_UNORM, 1,
>        { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR8888 } } },
>      { DRM_FORMAT_GR88,          __DRI_IMAGE_FORMAT_GR88,
>        __DRI_IMAGE_COMPONENTS_RG,        PIPE_FORMAT_RG88_UNORM, 1,
>        { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 } } },
>
>Note that the table doesn't contain any entry for the DRM_FORMAT_RG88,
>DRM_FORMAT_BGRA8888 or DRM_FORMAT_RGBA8888 formats (even though
>PIPE_FORMAT_GR88_UNORM, PIPE_FORMAT_ABGR8888_UNORM and
>PIPE_FORMAT_ARGB8888_UNORM exist in Mesa).
>
>It's also worth noting that the format_mapping[] table in
>src/gallium/frontends/dri/dri_util.c contains the following entries:
>
>   {
>      .image_format    = __DRI_IMAGE_FORMAT_ARGB8888,
>      .mesa_format     =        MESA_FORMAT_B8G8R8A8_UNORM,
>      .internal_format =        GL_RGBA8,
>   },
>   {
>      .image_format    = __DRI_IMAGE_FORMAT_ABGR8888,
>      .mesa_format     =        MESA_FORMAT_R8G8B8A8_UNORM,
>      .internal_format =        GL_RGBA8,
>   },
>   {
>      .image_format    = __DRI_IMAGE_FORMAT_GR88,
>      .mesa_format     =        MESA_FORMAT_RG_UNORM8,
>      .internal_format =        GL_RG8,
>   },
>   {
>      .image_format    = __DRI_IMAGE_FORMAT_GR88,
>      .mesa_format     =        MESA_FORMAT_LA_UNORM8,
>      .internal_format =        GL_RG8,
>   },
>
>> Urgh. I think you're right. This format is only used for the output
>> buffer, not the input ones - and we require the dmabuf import to succeed
>> in that case, so there's no fallback path.
>>
>> If we have a R-B swap here - then we most likely also have one in the
>> shaders, compensating for it.
>
>We have
>
>	switch (outputFormat) {
>	case formats::ARGB8888:
>	case formats::XRGB8888:
>		break;
>	case formats::ABGR8888:
>	case formats::XBGR8888:
>		egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
>		break;							
>	default:
>		LOG(Debayer, Error) << "Unsupported output format";
>		return -EINVAL;
>	}
>
>in DebayerEGL::initBayerShaders(), and
>
>#if defined (SWAP_BLUE)
>    gl_FragColor = vec4(rgb.bgr, 1.0);
>#else
>    gl_FragColor = vec4(rgb, 1.0);
>#endif
>
>in the shaders.
>
>Unless I'm mistaken, while GL_RG and GL_RGBA may map by default to R, G,
>B and A stored in bytes 0, 1, 2 and 3 respectively, the actual byte
>order in memory can be overridden with EGL_LINUX_DRM_FOURCC_EXT when
>calling eglCreateImageKHR(). This is documented in
>https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt:
>
>    The ordering of samples within a plane is taken from the drm_fourcc
>    pixel_format specified for EGL_LINUX_DRM_FOURCC_EXT.
>
>It therefore doesn't matter much if we map GL_RGBA to
>DRM_FORMAT_ARGB8888 or DRM_FORMAT_ABGR8888, as long as both are
>supported by the GPU. Similarly, mapping GL_RG to DRM_FORMAT_RG88 would
>be absolutely fine if it wasn't for the fact that Mesa doesn't support
>that mapping (likely because no GPU supports it).
>
>If GL_RGBA would indeed map natively to DRM_FORMAT_ABGR8888 unless
>specified otherwise, it's probably safe to consider DRM_FORMAT_ABGR8888
>as more widely supported by GPUs than DRM_FORMAT_ARGB8888. It would then
>be better to use DRM_FORMAT_ABGR8888 to ensure compatibility with a
>wider range of GPUs.
>
>Could someone test mapping GL_RGBA to GL_ABGR, and setting SWAP_BLUE for
>formats::[AX]RGB8888 instead of formats::[AX]BGR8888 ?
>
>The commit message of this patch should probably be updated to reflect
>the above (if my explanation is correct).
>

Yes I have tested the swap changes Barnabás Pőcze suggested and it is working.
(making the drm format as DRM_FORMAT_ABGR8888 and swap changes)


diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
index 59a7d8cf9..d7a36f232 100644
--- a/src/libcamera/egl.cpp
+++ b/src/libcamera/egl.cpp
@@ -187,7 +187,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
                 drm_format = DRM_FORMAT_GR88;
                 break;
         case GL_RGBA:
-               drm_format = DRM_FORMAT_ARGB8888;
+               drm_format = DRM_FORMAT_ABGR8888;
                 break;
         default:
                 LOG(eGL, Error) << "unhandled GL format";
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 300822f9d..cb9908e1d 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -150,10 +150,10 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm
         switch (outputFormat) {
         case formats::ARGB8888:
         case formats::XRGB8888:
+               egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
                 break;
         case formats::ABGR8888:
         case formats::XBGR8888:
-               egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
                 break;
         default:
                 LOG(Debayer, Error) << "Unsupported output format";




Planning to send as second set of a two set patch. The first set to modify the 
comments to remove the 'silent' word for the initial patch. 

Regards
Faizel
Barnabás Pőcze Oct. 22, 2026, 7:56 a.m. UTC | #11
2026. 10. 22. 2:33 keltezéssel, Faizel K B írta:
> Hi,
> 
> Thank you all for the reviews and the testing.
> 
> 
>>> >>>>
>>> >>>> Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
>>> >>>> supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
>>> >>>> output path (GL_RGBA) are not affected.
>>> >>>
>>> >>> The only thing that's not entirely clear to me is why GL_RGBA is not
>>> >>> affected.
>>> >>
>>> >> The mapping from GL_RGBA <-> DRM_FORMAT_ARGB8888 already uses the
>>> >> inverted order, so that makes sense, no?
>>> >
>>> > I'd have expected DRM_FORMAT_ABGR8888, since
>>> >
>>> >   /* [31:0] A:B:G:R 8:8:8:8 little endian */
>>> >
>>> > so the memory order is RGBA. But I must be missing something.
>>
>> Here are the three relevant entries in dri2_format_table[]
>> (src/gallium/frontends/dri/dri_helpers.c) in Mesa:
>>
>>      { DRM_FORMAT_ARGB8888,      __DRI_IMAGE_FORMAT_ARGB8888,
>>        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_BGRA8888_UNORM, 1,
>>        { { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB8888 } } },
>>      { DRM_FORMAT_ABGR8888,      __DRI_IMAGE_FORMAT_ABGR8888,
>>        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_RGBA8888_UNORM, 1,
>>        { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR8888 } } },
>>      { DRM_FORMAT_GR88,          __DRI_IMAGE_FORMAT_GR88,
>>        __DRI_IMAGE_COMPONENTS_RG,        PIPE_FORMAT_RG88_UNORM, 1,
>>        { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 } } },
>>
>> Note that the table doesn't contain any entry for the DRM_FORMAT_RG88,
>> DRM_FORMAT_BGRA8888 or DRM_FORMAT_RGBA8888 formats (even though
>> PIPE_FORMAT_GR88_UNORM, PIPE_FORMAT_ABGR8888_UNORM and
>> PIPE_FORMAT_ARGB8888_UNORM exist in Mesa).
>>
>> It's also worth noting that the format_mapping[] table in
>> src/gallium/frontends/dri/dri_util.c contains the following entries:
>>
>>   {
>>      .image_format    = __DRI_IMAGE_FORMAT_ARGB8888,
>>      .mesa_format     =        MESA_FORMAT_B8G8R8A8_UNORM,
>>      .internal_format =        GL_RGBA8,
>>   },
>>   {
>>      .image_format    = __DRI_IMAGE_FORMAT_ABGR8888,
>>      .mesa_format     =        MESA_FORMAT_R8G8B8A8_UNORM,
>>      .internal_format =        GL_RGBA8,
>>   },
>>   {
>>      .image_format    = __DRI_IMAGE_FORMAT_GR88,
>>      .mesa_format     =        MESA_FORMAT_RG_UNORM8,
>>      .internal_format =        GL_RG8,
>>   },
>>   {
>>      .image_format    = __DRI_IMAGE_FORMAT_GR88,
>>      .mesa_format     =        MESA_FORMAT_LA_UNORM8,
>>      .internal_format =        GL_RG8,
>>   },
>>
>>> Urgh. I think you're right. This format is only used for the output
>>> buffer, not the input ones - and we require the dmabuf import to succeed
>>> in that case, so there's no fallback path.
>>>
>>> If we have a R-B swap here - then we most likely also have one in the
>>> shaders, compensating for it.
>>
>> We have
>>
>>     switch (outputFormat) {
>>     case formats::ARGB8888:
>>     case formats::XRGB8888:
>>         break;
>>     case formats::ABGR8888:
>>     case formats::XBGR8888:
>>         egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
>>         break;
>>     default:
>>         LOG(Debayer, Error) << "Unsupported output format";
>>         return -EINVAL;
>>     }
>>
>> in DebayerEGL::initBayerShaders(), and
>>
>> #if defined (SWAP_BLUE)
>>    gl_FragColor = vec4(rgb.bgr, 1.0);
>> #else
>>    gl_FragColor = vec4(rgb, 1.0);
>> #endif
>>
>> in the shaders.
>>
>> Unless I'm mistaken, while GL_RG and GL_RGBA may map by default to R, G,
>> B and A stored in bytes 0, 1, 2 and 3 respectively, the actual byte
>> order in memory can be overridden with EGL_LINUX_DRM_FOURCC_EXT when
>> calling eglCreateImageKHR(). This is documented in
>> https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt:
>>
>>    The ordering of samples within a plane is taken from the drm_fourcc
>>    pixel_format specified for EGL_LINUX_DRM_FOURCC_EXT.
>>
>> It therefore doesn't matter much if we map GL_RGBA to
>> DRM_FORMAT_ARGB8888 or DRM_FORMAT_ABGR8888, as long as both are
>> supported by the GPU. Similarly, mapping GL_RG to DRM_FORMAT_RG88 would
>> be absolutely fine if it wasn't for the fact that Mesa doesn't support
>> that mapping (likely because no GPU supports it).

I'm not sure it would be fine because this is used on the input side, so using the other
format "swaps" the meaning of components in the shaders. With `DRM_FORMAT_RG88`, green is
byte 0, while with `DRM_FORMAT_GR88` green is byte 1.

For the fallback path GL_RG + GL_UNSIGNED_BYTE is used, so green is byte 1,
so I think actually only `DRM_FORMAT_GR88` is correct in this case.


>>
>> If GL_RGBA would indeed map natively to DRM_FORMAT_ABGR8888 unless
>> specified otherwise, it's probably safe to consider DRM_FORMAT_ABGR8888
>> as more widely supported by GPUs than DRM_FORMAT_ARGB8888. It would then
>> be better to use DRM_FORMAT_ABGR8888 to ensure compatibility with a
>> wider range of GPUs.
>>
>> Could someone test mapping GL_RGBA to GL_ABGR, and setting SWAP_BLUE for
>> formats::[AX]RGB8888 instead of formats::[AX]BGR8888 ?
>>
>> The commit message of this patch should probably be updated to reflect
>> the above (if my explanation is correct).
>>
> 
> Yes I have tested the swap changes Barnabás Pőcze suggested and it is working.
> (making the drm format as DRM_FORMAT_ABGR8888 and swap changes)
> 
> 
> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
> index 59a7d8cf9..d7a36f232 100644
> --- a/src/libcamera/egl.cpp
> +++ b/src/libcamera/egl.cpp
> @@ -187,7 +187,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
>                  drm_format = DRM_FORMAT_GR88;
>                  break;
>          case GL_RGBA:
> -               drm_format = DRM_FORMAT_ARGB8888;
> +               drm_format = DRM_FORMAT_ABGR8888;
>                  break;
>          default:
>                  LOG(eGL, Error) << "unhandled GL format";
> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
> index 300822f9d..cb9908e1d 100644
> --- a/src/libcamera/software_isp/debayer_egl.cpp
> +++ b/src/libcamera/software_isp/debayer_egl.cpp
> @@ -150,10 +150,10 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm
>          switch (outputFormat) {
>          case formats::ARGB8888:
>          case formats::XRGB8888:
> +               egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
>                  break;
>          case formats::ABGR8888:
>          case formats::XBGR8888:
> -               egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
>                  break;
>          default:
>                  LOG(Debayer, Error) << "Unsupported output format";
> 
> 
> 
> 
> Planning to send as second set of a two set patch. The first set to modify the comments to remove the 'silent' word for the initial patch.
> Regards
> Faizel

I think what I suggested is actually not needed. As it turns out above, it's
effectively the fourcc code that determines things, and the color components
are apparently remapped appropriately.

Now we might still want to make this switch to always use the reverse ordering
between GL_* and DRM_FORMAT_* values, but I now think it's not strictly needed.
Laurent Pinchart Oct. 22, 2026, 10:07 a.m. UTC | #12
On Thu, Oct 22, 2026 at 09:56:07AM +0200, Barnabás Pőcze wrote:
> 2026. 10. 22. 2:33 keltezéssel, Faizel K B írta:
> > Hi,
> > 
> > Thank you all for the reviews and the testing.
> > 
> >>> >>>> Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
> >>> >>>> supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
> >>> >>>> output path (GL_RGBA) are not affected.
> >>> >>>
> >>> >>> The only thing that's not entirely clear to me is why GL_RGBA is not
> >>> >>> affected.
> >>> >>
> >>> >> The mapping from GL_RGBA <-> DRM_FORMAT_ARGB8888 already uses the
> >>> >> inverted order, so that makes sense, no?
> >>> >
> >>> > I'd have expected DRM_FORMAT_ABGR8888, since
> >>> >
> >>> >   /* [31:0] A:B:G:R 8:8:8:8 little endian */
> >>> >
> >>> > so the memory order is RGBA. But I must be missing something.
> >>
> >> Here are the three relevant entries in dri2_format_table[]
> >> (src/gallium/frontends/dri/dri_helpers.c) in Mesa:
> >>
> >>      { DRM_FORMAT_ARGB8888,      __DRI_IMAGE_FORMAT_ARGB8888,
> >>        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_BGRA8888_UNORM, 1,
> >>        { { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB8888 } } },
> >>      { DRM_FORMAT_ABGR8888,      __DRI_IMAGE_FORMAT_ABGR8888,
> >>        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_RGBA8888_UNORM, 1,
> >>        { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR8888 } } },
> >>      { DRM_FORMAT_GR88,          __DRI_IMAGE_FORMAT_GR88,
> >>        __DRI_IMAGE_COMPONENTS_RG,        PIPE_FORMAT_RG88_UNORM, 1,
> >>        { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 } } },
> >>
> >> Note that the table doesn't contain any entry for the DRM_FORMAT_RG88,
> >> DRM_FORMAT_BGRA8888 or DRM_FORMAT_RGBA8888 formats (even though
> >> PIPE_FORMAT_GR88_UNORM, PIPE_FORMAT_ABGR8888_UNORM and
> >> PIPE_FORMAT_ARGB8888_UNORM exist in Mesa).
> >>
> >> It's also worth noting that the format_mapping[] table in
> >> src/gallium/frontends/dri/dri_util.c contains the following entries:
> >>
> >>   {
> >>      .image_format    = __DRI_IMAGE_FORMAT_ARGB8888,
> >>      .mesa_format     =        MESA_FORMAT_B8G8R8A8_UNORM,
> >>      .internal_format =        GL_RGBA8,
> >>   },
> >>   {
> >>      .image_format    = __DRI_IMAGE_FORMAT_ABGR8888,
> >>      .mesa_format     =        MESA_FORMAT_R8G8B8A8_UNORM,
> >>      .internal_format =        GL_RGBA8,
> >>   },
> >>   {
> >>      .image_format    = __DRI_IMAGE_FORMAT_GR88,
> >>      .mesa_format     =        MESA_FORMAT_RG_UNORM8,
> >>      .internal_format =        GL_RG8,
> >>   },
> >>   {
> >>      .image_format    = __DRI_IMAGE_FORMAT_GR88,
> >>      .mesa_format     =        MESA_FORMAT_LA_UNORM8,
> >>      .internal_format =        GL_RG8,
> >>   },
> >>
> >>> Urgh. I think you're right. This format is only used for the output
> >>> buffer, not the input ones - and we require the dmabuf import to succeed
> >>> in that case, so there's no fallback path.
> >>>
> >>> If we have a R-B swap here - then we most likely also have one in the
> >>> shaders, compensating for it.
> >>
> >> We have
> >>
> >>     switch (outputFormat) {
> >>     case formats::ARGB8888:
> >>     case formats::XRGB8888:
> >>         break;
> >>     case formats::ABGR8888:
> >>     case formats::XBGR8888:
> >>         egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
> >>         break;
> >>     default:
> >>         LOG(Debayer, Error) << "Unsupported output format";
> >>         return -EINVAL;
> >>     }
> >>
> >> in DebayerEGL::initBayerShaders(), and
> >>
> >> #if defined (SWAP_BLUE)
> >>    gl_FragColor = vec4(rgb.bgr, 1.0);
> >> #else
> >>    gl_FragColor = vec4(rgb, 1.0);
> >> #endif
> >>
> >> in the shaders.
> >>
> >> Unless I'm mistaken, while GL_RG and GL_RGBA may map by default to R, G,
> >> B and A stored in bytes 0, 1, 2 and 3 respectively, the actual byte
> >> order in memory can be overridden with EGL_LINUX_DRM_FOURCC_EXT when
> >> calling eglCreateImageKHR(). This is documented in
> >> https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt:
> >>
> >>    The ordering of samples within a plane is taken from the drm_fourcc
> >>    pixel_format specified for EGL_LINUX_DRM_FOURCC_EXT.
> >>
> >> It therefore doesn't matter much if we map GL_RGBA to
> >> DRM_FORMAT_ARGB8888 or DRM_FORMAT_ABGR8888, as long as both are
> >> supported by the GPU. Similarly, mapping GL_RG to DRM_FORMAT_RG88 would
> >> be absolutely fine if it wasn't for the fact that Mesa doesn't support
> >> that mapping (likely because no GPU supports it).
> 
> I'm not sure it would be fine because this is used on the input side, so using the other
> format "swaps" the meaning of components in the shaders. With `DRM_FORMAT_RG88`, green is
> byte 0, while with `DRM_FORMAT_GR88` green is byte 1.
> 
> For the fallback path GL_RG + GL_UNSIGNED_BYTE is used, so green is byte 1,
> so I think actually only `DRM_FORMAT_GR88` is correct in this case.

Yes, the shaders would of course need to be updated. My point was that
it could work if Mesa (and GPUs) supported that. As they don't, it's a
moot point anyway.

> >> If GL_RGBA would indeed map natively to DRM_FORMAT_ABGR8888 unless
> >> specified otherwise, it's probably safe to consider DRM_FORMAT_ABGR8888
> >> as more widely supported by GPUs than DRM_FORMAT_ARGB8888. It would then
> >> be better to use DRM_FORMAT_ABGR8888 to ensure compatibility with a
> >> wider range of GPUs.
> >>
> >> Could someone test mapping GL_RGBA to GL_ABGR, and setting SWAP_BLUE for
> >> formats::[AX]RGB8888 instead of formats::[AX]BGR8888 ?
> >>
> >> The commit message of this patch should probably be updated to reflect
> >> the above (if my explanation is correct).
> >>
> > 
> > Yes I have tested the swap changes Barnabás Pőcze suggested and it is working.
> > (making the drm format as DRM_FORMAT_ABGR8888 and swap changes)
> > 
> > 
> > diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
> > index 59a7d8cf9..d7a36f232 100644
> > --- a/src/libcamera/egl.cpp
> > +++ b/src/libcamera/egl.cpp
> > @@ -187,7 +187,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
> >                  drm_format = DRM_FORMAT_GR88;
> >                  break;
> >          case GL_RGBA:
> > -               drm_format = DRM_FORMAT_ARGB8888;
> > +               drm_format = DRM_FORMAT_ABGR8888;
> >                  break;
> >          default:
> >                  LOG(eGL, Error) << "unhandled GL format";
> > diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
> > index 300822f9d..cb9908e1d 100644
> > --- a/src/libcamera/software_isp/debayer_egl.cpp
> > +++ b/src/libcamera/software_isp/debayer_egl.cpp
> > @@ -150,10 +150,10 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm
> >          switch (outputFormat) {
> >          case formats::ARGB8888:
> >          case formats::XRGB8888:
> > +               egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
> >                  break;
> >          case formats::ABGR8888:
> >          case formats::XBGR8888:
> > -               egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
> >                  break;
> >          default:
> >                  LOG(Debayer, Error) << "Unsupported output format";
> > 
> > 
> > Planning to send as second set of a two set patch. The first set to modify the comments to remove the 'silent' word for the initial patch.
> > Regards
> > Faizel
> 
> I think what I suggested is actually not needed. As it turns out above, it's
> effectively the fourcc code that determines things, and the color components
> are apparently remapped appropriately.
> 
> Now we might still want to make this switch to always use the reverse ordering
> between GL_* and DRM_FORMAT_* values, but I now think it's not strictly needed.

It's not strictly needed, but I think it can provide better
compatibility with a wider range of GPUs. As there's no downside (that I
can see), I'd prefer using ABGR8888.
Bryan O'Donoghue Oct. 22, 2026, 10:13 a.m. UTC | #13
On 22/10/2026 01:33, Faizel K B wrote:
> @@ -150,10 +150,10 @@ int DebayerEGL::initBayerShaders(PixelFormat 
> inputFormat, PixelFormat outputForm
>          switch (outputFormat) {
>          case formats::ARGB8888:
>          case formats::XRGB8888:
> +               egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");

This feels wrong.

---
bod
Laurent Pinchart Oct. 22, 2026, 10:19 a.m. UTC | #14
On Thu, Oct 22, 2026 at 11:13:36AM +0100, Bryan O'Donoghue wrote:
> On 22/10/2026 01:33, Faizel K B wrote:
> > @@ -150,10 +150,10 @@ int DebayerEGL::initBayerShaders(PixelFormat 
> > inputFormat, PixelFormat outputForm
> >          switch (outputFormat) {
> >          case formats::ARGB8888:
> >          case formats::XRGB8888:
> > +               egl_.pushEnv(shaderEnv, "#define SWAP_BLUE");
> 
> This feels wrong.

How so ? It moves the SWAP_BLUE from ABGR to ARGB to match the switch
from DRM_FORMAT_ARGB8888 to DRM_FORMAT_ABGR8888. That is, the GPU will
now expect DRM_FORMAT_ABGR8888, and if it gets DRM_FORMAT_ARGB8888 we
swap R and G in the shader.

Note that we could also select DRM_FORMAT_ARGB8888 or
DRM_FORMAT_ABGR8888 to match the output format and drop SWAP_BLUE.
Bryan O'Donoghue Oct. 22, 2026, 12:16 p.m. UTC | #15
On 22/10/2026 11:19, Laurent Pinchart wrote:
> Note that we could also select DRM_FORMAT_ARGB8888 or
> DRM_FORMAT_ABGR8888 to match the output format and drop SWAP_BLUE.

I prefer this.

My original understanding of the intent of swap-blue was well, to swap 
the blue because it was in a different position not to compensate for 
how pixels are packed by the GPU.

Also - I think we look into how qcam's RAW path works ... its probably 
fine come to think of it because we aren't doing eglCreateImageKHR on a 
dma-buf handle ..

---
bod
Milan Zamazal Oct. 22, 2026, 3:34 p.m. UTC | #16
Faizel K B <faizel.kb@gmail.com> writes:

> Importing unpacked 10/12-bit Bayer input buffers (e.g. SGBRG10) as
> dmabufs always fails with Mesa, and DebayerEGL silently falls back to
> mapping each input buffer and uploading it with glTexImage2D() on every
> frame:
>
>   INFO Debayer debayer_egl.cpp:523 Importing input DMABuf failed, falling back to upload
>
> The cause is the DRM format used for GL_RG textures. Unpacked Bayer
> pixels are 16-bit little-endian words, loaded into a GL_RG texture with
> the low byte in .r and the high byte in .g, which the shaders recombine
> into a single sample. R and G here are texture channels, not colours.
> GL names formats in memory byte order, while DRM fourccs describe the
> components of a little-endian word from MSB to LSB:
>
>   DRM_FORMAT_RG88  [15:0] R:G 8:8 little endian  -> byte 0 = G, byte 1 = R
>   DRM_FORMAT_GR88  [15:0] G:R 8:8 little endian  -> byte 0 = R, byte 1 = G
>
> The import path maps GL_RG to DRM_FORMAT_RG88, which has the opposite
> byte order. Mesa has no RG88 entry in its DRI image format table, so
> eglCreateImageKHR() fails.
>
> Map GL_RG to DRM_FORMAT_GR88, which matches the upload path and is
> supported by Mesa. 8-bit and CSI-2 packed input (GL_LUMINANCE) and the
> output path (GL_RGBA) are not affected.
>
> Fixes: 6e23162ddcae ("egl: Add GL format parameter to eGLImage constructor")
> Signed-off-by: Faizel K B <faizel.kb@gmail.com>

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

With:

  INFO Camera camera.cpp:1216 configuring streams: (0) 1920x1080-ABGR8888/sRGB
  INFO SoftwareIsp software_isp.cpp:300 Input 2304x1296-BGGR-10 stride 4608

> ---
>
> Notes:
>     Tested on RK3588 (Mali-G610, Panfrost, Mesa 24.3.4) with an IMX415
>     sensor (SGBRG10 unpacked, 3864x2192).
>     
>     Panfrost requires the row stride of linear dmabuf imports to be
>     64-byte aligned. The SGBRG10 stride at 3864 pixels is 7728 bytes, so
>     the import also needed a local rkcif change to honour the 256-byte
>     aligned stride (7936) that DebayerEGL::preferredInputStride() requests.
>
>  src/libcamera/egl.cpp | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
> index 3cde9040a..59a7d8cf9 100644
> --- a/src/libcamera/egl.cpp
> +++ b/src/libcamera/egl.cpp
> @@ -184,7 +184,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
>  		drm_format = DRM_FORMAT_R8;
>  		break;
>  	case GL_RG:
> -		drm_format = DRM_FORMAT_RG88;
> +		drm_format = DRM_FORMAT_GR88;
>  		break;
>  	case GL_RGBA:
>  		drm_format = DRM_FORMAT_ARGB8888;
Laurent Pinchart Oct. 22, 2026, 4:08 p.m. UTC | #17
On Thu, Oct 22, 2026 at 01:16:34PM +0100, Bryan O'Donoghue wrote:
> On 22/10/2026 11:19, Laurent Pinchart wrote:
> > Note that we could also select DRM_FORMAT_ARGB8888 or
> > DRM_FORMAT_ABGR8888 to match the output format and drop SWAP_BLUE.
> 
> I prefer this.

My only concern is that I don't know if all GPUs we may encounter
support both DRM_FORMAT_ARGB8888 and DRM_FORMAT_ABGR8888. It feels that
DRM_FORMAT_ABGR8888 would always be supported (because it maps to the
native order of GL_RGBA), while DRM_FORMAT_ARGB8888 may not be
universally implemented. I don't know if that's true or not.

> My original understanding of the intent of swap-blue was well, to swap 
> the blue because it was in a different position not to compensate for 
> how pixels are packed by the GPU.
> 
> Also - I think we look into how qcam's RAW path works ... its probably 
> fine come to think of it because we aren't doing eglCreateImageKHR on a 
> dma-buf handle ..
Robert Mader Oct. 22, 2026, 6:27 p.m. UTC | #18
On 22.10.26 18:08, Laurent Pinchart wrote:
> On Thu, Oct 22, 2026 at 01:16:34PM +0100, Bryan O'Donoghue wrote:
>> On 22/10/2026 11:19, Laurent Pinchart wrote:
>>> Note that we could also select DRM_FORMAT_ARGB8888 or
>>> DRM_FORMAT_ABGR8888 to match the output format and drop SWAP_BLUE.
>> I prefer this.
> My only concern is that I don't know if all GPUs we may encounter
> support both DRM_FORMAT_ARGB8888 and DRM_FORMAT_ABGR8888. It feels that
> DRM_FORMAT_ABGR8888 would always be supported (because it maps to the
> native order of GL_RGBA), while DRM_FORMAT_ARGB8888 may not be
> universally implemented. I don't know if that's true or not.

AFAIK both are universally supported. In theory there could be GLES 2.0 
drivers not supporting GL_EXT_texture_format_BGRA8888 - i.e. 
DRM_FORMAT_ARGB8888 - which would then only support DRM_FORMAT_ABGR8888, 
which is mandatory. However DRM_FORMAT_ARGB8888 - together with its 
opaque version - happens to be the only format essentially required for 
Wayland compositors (WL_SHM_FORMAT_ARGB8888). So all Linux GL drivers 
that are not unmaintained and ancient are pretty much guaranteed to 
support both if I'm not totally mistaken.

If we need a bit more time to discuss this, though - should we already 
land the original patch with the commit message fixed during applying?

>
>> My original understanding of the intent of swap-blue was well, to swap
>> the blue because it was in a different position not to compensate for
>> how pixels are packed by the GPU.
>>
>> Also - I think we look into how qcam's RAW path works ... its probably
>> fine come to think of it because we aren't doing eglCreateImageKHR on a
>> dma-buf handle ..
Laurent Pinchart Oct. 22, 2026, 6:37 p.m. UTC | #19
On Thu, Oct 22, 2026 at 08:27:47PM +0200, Robert Mader wrote:
> On 22.10.26 18:08, Laurent Pinchart wrote:
> > On Thu, Oct 22, 2026 at 01:16:34PM +0100, Bryan O'Donoghue wrote:
> >> On 22/10/2026 11:19, Laurent Pinchart wrote:
> >>> Note that we could also select DRM_FORMAT_ARGB8888 or
> >>> DRM_FORMAT_ABGR8888 to match the output format and drop SWAP_BLUE.
> >> 
> >> I prefer this.
> > 
> > My only concern is that I don't know if all GPUs we may encounter
> > support both DRM_FORMAT_ARGB8888 and DRM_FORMAT_ABGR8888. It feels that
> > DRM_FORMAT_ABGR8888 would always be supported (because it maps to the
> > native order of GL_RGBA), while DRM_FORMAT_ARGB8888 may not be
> > universally implemented. I don't know if that's true or not.
> 
> AFAIK both are universally supported. In theory there could be GLES 2.0 
> drivers not supporting GL_EXT_texture_format_BGRA8888 - i.e. 
> DRM_FORMAT_ARGB8888 - which would then only support DRM_FORMAT_ABGR8888, 
> which is mandatory. However DRM_FORMAT_ARGB8888 - together with its 
> opaque version - happens to be the only format essentially required for 
> Wayland compositors (WL_SHM_FORMAT_ARGB8888). So all Linux GL drivers 
> that are not unmaintained and ancient are pretty much guaranteed to 
> support both if I'm not totally mistaken.

Thank you for the information.

> If we need a bit more time to discuss this, though - should we already 
> land the original patch with the commit message fixed during applying?

Fine with me. It fixes an issue, we can address GL_RGBA in a second
step.

> >> My original understanding of the intent of swap-blue was well, to swap
> >> the blue because it was in a different position not to compensate for
> >> how pixels are packed by the GPU.
> >>
> >> Also - I think we look into how qcam's RAW path works ... its probably
> >> fine come to think of it because we aren't doing eglCreateImageKHR on a
> >> dma-buf handle ..
Faizel K B Oct. 22, 2026, 11:38 p.m. UTC | #20
On Thu, Oct 22, 2026 at 09:37:46PM +0300, Laurent Pinchart wrote:
>On Thu, Oct 22, 2026 at 08:27:47PM +0200, Robert Mader wrote:
>> On 22.10.26 18:08, Laurent Pinchart wrote:
>> > On Thu, Oct 22, 2026 at 01:16:34PM +0100, Bryan O'Donoghue wrote:
>> >> On 22/10/2026 11:19, Laurent Pinchart wrote:
>> >>> Note that we could also select DRM_FORMAT_ARGB8888 or
>> >>> DRM_FORMAT_ABGR8888 to match the output format and drop SWAP_BLUE.
>> >>
>> >> I prefer this.
>> >
>> > My only concern is that I don't know if all GPUs we may encounter
>> > support both DRM_FORMAT_ARGB8888 and DRM_FORMAT_ABGR8888. It feels that
>> > DRM_FORMAT_ABGR8888 would always be supported (because it maps to the
>> > native order of GL_RGBA), while DRM_FORMAT_ARGB8888 may not be
>> > universally implemented. I don't know if that's true or not.
>>
>> AFAIK both are universally supported. In theory there could be GLES 2.0
>> drivers not supporting GL_EXT_texture_format_BGRA8888 - i.e.
>> DRM_FORMAT_ARGB8888 - which would then only support DRM_FORMAT_ABGR8888,
>> which is mandatory. However DRM_FORMAT_ARGB8888 - together with its
>> opaque version - happens to be the only format essentially required for
>> Wayland compositors (WL_SHM_FORMAT_ARGB8888). So all Linux GL drivers
>> that are not unmaintained and ancient are pretty much guaranteed to
>> support both if I'm not totally mistaken.
>
>Thank you for the information.
>
>> If we need a bit more time to discuss this, though - should we already
>> land the original patch with the commit message fixed during applying?
>
>Fine with me. It fixes an issue, we can address GL_RGBA in a second
>step.
>

Thanks all. I have sent v2 with the commit message updated and the
tags collected

  https://patchwork.libcamera.org/patch/28567/

Regards
Faizel

Patch
diff mbox series

diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
index 3cde9040a..59a7d8cf9 100644
--- a/src/libcamera/egl.cpp
+++ b/src/libcamera/egl.cpp
@@ -184,7 +184,7 @@  int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
 		drm_format = DRM_FORMAT_R8;
 		break;
 	case GL_RG:
-		drm_format = DRM_FORMAT_RG88;
+		drm_format = DRM_FORMAT_GR88;
 		break;
 	case GL_RGBA:
 		drm_format = DRM_FORMAT_ARGB8888;