[v2] libcamera: debayer_cpu: Sync DMABUFs
diff mbox series

Message ID 20240913120416.96828-1-robert.mader@collabora.com
State Accepted
Headers show
Series
  • [v2] libcamera: debayer_cpu: Sync DMABUFs
Related show

Commit Message

Robert Mader Sept. 13, 2024, 12:04 p.m. UTC
Using `DMA_BUF_IOCTL_SYNC` is required for DMABUFs in order to ensure
correct output. Not doing so currently results in occasional tearing
and/or backlashes in GL/VK clients that use the buffers directly for
rendering.

An alternative approach to have the sync code in `MappedFrameBuffer` was
considered but rejected for now, in order to allow clients more
flexibility.

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

---

Changes in v2:
 - sync input buffer as well
 - update commit title accordingly
 - small changes to the commit message
 - linting fixes, should pass now
---
 src/libcamera/software_isp/debayer_cpu.cpp | 35 ++++++++++++++++++++++
 1 file changed, 35 insertions(+)

Comments

Kieran Bingham Sept. 13, 2024, 12:31 p.m. UTC | #1
Hi Robert,

Quoting Robert Mader (2024-09-13 13:04:16)
> Using `DMA_BUF_IOCTL_SYNC` is required for DMABUFs in order to ensure
> correct output. Not doing so currently results in occasional tearing
> and/or backlashes in GL/VK clients that use the buffers directly for
> rendering.
> 
> An alternative approach to have the sync code in `MappedFrameBuffer` was
> considered but rejected for now, in order to allow clients more
> flexibility.
> 
> Signed-off-by: Robert Mader <robert.mader@collabora.com>
> 
> ---
> 
> Changes in v2:
>  - sync input buffer as well
>  - update commit title accordingly
>  - small changes to the commit message
>  - linting fixes, should pass now
> ---
>  src/libcamera/software_isp/debayer_cpu.cpp | 35 ++++++++++++++++++++++
>  1 file changed, 35 insertions(+)
> 
> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
> index 077f7f4b..a3b4851c 100644
> --- a/src/libcamera/software_isp/debayer_cpu.cpp
> +++ b/src/libcamera/software_isp/debayer_cpu.cpp
> @@ -12,8 +12,11 @@
>  #include "debayer_cpu.h"
>  
>  #include <stdlib.h>
> +#include <sys/ioctl.h>
>  #include <time.h>
>  
> +#include <linux/dma-buf.h>
> +
>  #include <libcamera/formats.h>
>  
>  #include "libcamera/internal/bayer_format.h"
> @@ -733,6 +736,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
>                 clock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime);
>         }
>  
> +       for (const FrameBuffer::Plane &plane : input->planes()) {
> +               const int fd = plane.fd.get();
> +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ };
> +
> +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;

We can't use 'errno' directly on our error messages because the LOG()
implementations or other processing of the log statement (not in this
case, but in others it could be possible) could affect errno.

So we use the style 

src/libcamera/dma_buf_allocator.cpp-    if (ret < 0) {
src/libcamera/dma_buf_allocator.cpp:            ret = errno;
src/libcamera/dma_buf_allocator.cpp-            LOG(DmaBufAllocator, Error)
src/libcamera/dma_buf_allocator.cpp-                    << "Failed to create dma buf for " << name
src/libcamera/dma_buf_allocator.cpp-                    << ": " << strerror(ret);
src/libcamera/dma_buf_allocator.cpp-            return {};
src/libcamera/dma_buf_allocator.cpp-    }

Where we store the errno immediately and then use it in the log. It's
also helpful to use strerror too.

> +       }
> +
> +       for (const FrameBuffer::Plane &plane : output->planes()) {
> +               const int fd = plane.fd.get();
> +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE };
> +
> +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> +       }

(jumping back up from below) And this likewise could then be:

	intput->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ);
 	output->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE);

> +
>         green_ = params.green;
>         red_ = swapRedBlueGains_ ? params.blue : params.red;
>         blue_ = swapRedBlueGains_ ? params.red : params.blue;
> @@ -760,6 +779,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
>  
>         metadata.planes()[0].bytesused = out.planes()[0].size();
>  
> +       for (const FrameBuffer::Plane &plane : output->planes()) {
> +               const int fd = plane.fd.get();
> +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE };
> +
> +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> +       }
> +
> +       for (const FrameBuffer::Plane &plane : input->planes()) {
> +               const int fd = plane.fd.get();
> +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ };
> +
> +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;

That's four iterations of very similar code. I think we could add a
helper directly into FrameBuffer directly as a preceeding patch, that
would allow something more like:

	output->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
	input->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ);


We could probably do that using our Flags class too ... but the above
would be a good start.



> +       }
> +
>         /* Measure before emitting signals */
>         if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure &&
>             ++measuredFrames_ > DebayerCpu::kFramesToSkip) {
> -- 
> 2.46.0
>
Laurent Pinchart Sept. 13, 2024, 12:38 p.m. UTC | #2
On Fri, Sep 13, 2024 at 01:31:11PM +0100, Kieran Bingham wrote:
> Quoting Robert Mader (2024-09-13 13:04:16)
> > Using `DMA_BUF_IOCTL_SYNC` is required for DMABUFs in order to ensure
> > correct output. Not doing so currently results in occasional tearing
> > and/or backlashes in GL/VK clients that use the buffers directly for
> > rendering.
> > 
> > An alternative approach to have the sync code in `MappedFrameBuffer` was
> > considered but rejected for now, in order to allow clients more
> > flexibility.
> > 
> > Signed-off-by: Robert Mader <robert.mader@collabora.com>
> > 
> > ---
> > 
> > Changes in v2:
> >  - sync input buffer as well
> >  - update commit title accordingly
> >  - small changes to the commit message
> >  - linting fixes, should pass now
> > ---
> >  src/libcamera/software_isp/debayer_cpu.cpp | 35 ++++++++++++++++++++++
> >  1 file changed, 35 insertions(+)
> > 
> > diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
> > index 077f7f4b..a3b4851c 100644
> > --- a/src/libcamera/software_isp/debayer_cpu.cpp
> > +++ b/src/libcamera/software_isp/debayer_cpu.cpp
> > @@ -12,8 +12,11 @@
> >  #include "debayer_cpu.h"
> >  
> >  #include <stdlib.h>
> > +#include <sys/ioctl.h>
> >  #include <time.h>
> >  
> > +#include <linux/dma-buf.h>
> > +
> >  #include <libcamera/formats.h>
> >  
> >  #include "libcamera/internal/bayer_format.h"
> > @@ -733,6 +736,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
> >                 clock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime);
> >         }
> >  
> > +       for (const FrameBuffer::Plane &plane : input->planes()) {
> > +               const int fd = plane.fd.get();
> > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ };
> > +
> > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> 
> We can't use 'errno' directly on our error messages because the LOG()
> implementations or other processing of the log statement (not in this
> case, but in others it could be possible) could affect errno.
> 
> So we use the style 
> 
> src/libcamera/dma_buf_allocator.cpp-    if (ret < 0) {
> src/libcamera/dma_buf_allocator.cpp:            ret = errno;
> src/libcamera/dma_buf_allocator.cpp-            LOG(DmaBufAllocator, Error)
> src/libcamera/dma_buf_allocator.cpp-                    << "Failed to create dma buf for " << name
> src/libcamera/dma_buf_allocator.cpp-                    << ": " << strerror(ret);
> src/libcamera/dma_buf_allocator.cpp-            return {};
> src/libcamera/dma_buf_allocator.cpp-    }
> 
> Where we store the errno immediately and then use it in the log. It's
> also helpful to use strerror too.
> 
> > +       }
> > +
> > +       for (const FrameBuffer::Plane &plane : output->planes()) {
> > +               const int fd = plane.fd.get();
> > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE };
> > +
> > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > +       }
> 
> (jumping back up from below) And this likewise could then be:
> 
> 	intput->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ);
>  	output->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE);
> 
> > +
> >         green_ = params.green;
> >         red_ = swapRedBlueGains_ ? params.blue : params.red;
> >         blue_ = swapRedBlueGains_ ? params.red : params.blue;
> > @@ -760,6 +779,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
> >  
> >         metadata.planes()[0].bytesused = out.planes()[0].size();
> >  
> > +       for (const FrameBuffer::Plane &plane : output->planes()) {
> > +               const int fd = plane.fd.get();
> > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE };
> > +
> > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > +       }
> > +
> > +       for (const FrameBuffer::Plane &plane : input->planes()) {
> > +               const int fd = plane.fd.get();
> > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ };
> > +
> > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> 
> That's four iterations of very similar code. I think we could add a
> helper directly into FrameBuffer directly as a preceeding patch, that
> would allow something more like:
> 
> 	output->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
> 	input->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ);
> 
> We could probably do that using our Flags class too ... but the above
> would be a good start.

I'd like a helper too, but I don't think it should be part of the public
API, so the FrameBuffer class isn't the right place.

> > +       }
> > +
> >         /* Measure before emitting signals */
> >         if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure &&
> >             ++measuredFrames_ > DebayerCpu::kFramesToSkip) {
Kieran Bingham Sept. 13, 2024, 1:06 p.m. UTC | #3
Quoting Laurent Pinchart (2024-09-13 13:38:44)
> On Fri, Sep 13, 2024 at 01:31:11PM +0100, Kieran Bingham wrote:
> > Quoting Robert Mader (2024-09-13 13:04:16)
> > > Using `DMA_BUF_IOCTL_SYNC` is required for DMABUFs in order to ensure
> > > correct output. Not doing so currently results in occasional tearing
> > > and/or backlashes in GL/VK clients that use the buffers directly for
> > > rendering.
> > > 
> > > An alternative approach to have the sync code in `MappedFrameBuffer` was
> > > considered but rejected for now, in order to allow clients more
> > > flexibility.
> > > 
> > > Signed-off-by: Robert Mader <robert.mader@collabora.com>
> > > 
> > > ---
> > > 
> > > Changes in v2:
> > >  - sync input buffer as well
> > >  - update commit title accordingly
> > >  - small changes to the commit message
> > >  - linting fixes, should pass now
> > > ---
> > >  src/libcamera/software_isp/debayer_cpu.cpp | 35 ++++++++++++++++++++++
> > >  1 file changed, 35 insertions(+)
> > > 
> > > diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
> > > index 077f7f4b..a3b4851c 100644
> > > --- a/src/libcamera/software_isp/debayer_cpu.cpp
> > > +++ b/src/libcamera/software_isp/debayer_cpu.cpp
> > > @@ -12,8 +12,11 @@
> > >  #include "debayer_cpu.h"
> > >  
> > >  #include <stdlib.h>
> > > +#include <sys/ioctl.h>
> > >  #include <time.h>
> > >  
> > > +#include <linux/dma-buf.h>
> > > +
> > >  #include <libcamera/formats.h>
> > >  
> > >  #include "libcamera/internal/bayer_format.h"
> > > @@ -733,6 +736,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
> > >                 clock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime);
> > >         }
> > >  
> > > +       for (const FrameBuffer::Plane &plane : input->planes()) {
> > > +               const int fd = plane.fd.get();
> > > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ };
> > > +
> > > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > 
> > We can't use 'errno' directly on our error messages because the LOG()
> > implementations or other processing of the log statement (not in this
> > case, but in others it could be possible) could affect errno.
> > 
> > So we use the style 
> > 
> > src/libcamera/dma_buf_allocator.cpp-    if (ret < 0) {
> > src/libcamera/dma_buf_allocator.cpp:            ret = errno;
> > src/libcamera/dma_buf_allocator.cpp-            LOG(DmaBufAllocator, Error)
> > src/libcamera/dma_buf_allocator.cpp-                    << "Failed to create dma buf for " << name
> > src/libcamera/dma_buf_allocator.cpp-                    << ": " << strerror(ret);
> > src/libcamera/dma_buf_allocator.cpp-            return {};
> > src/libcamera/dma_buf_allocator.cpp-    }
> > 
> > Where we store the errno immediately and then use it in the log. It's
> > also helpful to use strerror too.
> > 
> > > +       }
> > > +
> > > +       for (const FrameBuffer::Plane &plane : output->planes()) {
> > > +               const int fd = plane.fd.get();
> > > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE };
> > > +
> > > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > > +       }
> > 
> > (jumping back up from below) And this likewise could then be:
> > 
> >       intput->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ);
> >       output->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE);
> > 
> > > +
> > >         green_ = params.green;
> > >         red_ = swapRedBlueGains_ ? params.blue : params.red;
> > >         blue_ = swapRedBlueGains_ ? params.red : params.blue;
> > > @@ -760,6 +779,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
> > >  
> > >         metadata.planes()[0].bytesused = out.planes()[0].size();
> > >  
> > > +       for (const FrameBuffer::Plane &plane : output->planes()) {
> > > +               const int fd = plane.fd.get();
> > > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE };
> > > +
> > > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > > +       }
> > > +
> > > +       for (const FrameBuffer::Plane &plane : input->planes()) {
> > > +               const int fd = plane.fd.get();
> > > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ };
> > > +
> > > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > 
> > That's four iterations of very similar code. I think we could add a
> > helper directly into FrameBuffer directly as a preceeding patch, that
> > would allow something more like:
> > 
> >       output->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
> >       input->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ);
> > 
> > We could probably do that using our Flags class too ... but the above
> > would be a good start.
> 
> I'd like a helper too, but I don't think it should be part of the public
> API, so the FrameBuffer class isn't the right place.

How about in FrameBuffer::Private::sync() then ?

Or worst case - and to progress here, at the very least - just a private
DebayerCpu::syncBuffer() for

	syncBuffer(output, DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);

which would at least bump any documentation requirements until there are
more users.

--
Kieran

> 
> > > +       }
> > > +
> > >         /* Measure before emitting signals */
> > >         if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure &&
> > >             ++measuredFrames_ > DebayerCpu::kFramesToSkip) {
> 
> -- 
> Regards,
> 
> Laurent Pinchart
Laurent Pinchart Sept. 13, 2024, 2:34 p.m. UTC | #4
On Fri, Sep 13, 2024 at 02:06:37PM +0100, Kieran Bingham wrote:
> Quoting Laurent Pinchart (2024-09-13 13:38:44)
> > On Fri, Sep 13, 2024 at 01:31:11PM +0100, Kieran Bingham wrote:
> > > Quoting Robert Mader (2024-09-13 13:04:16)
> > > > Using `DMA_BUF_IOCTL_SYNC` is required for DMABUFs in order to ensure
> > > > correct output. Not doing so currently results in occasional tearing
> > > > and/or backlashes in GL/VK clients that use the buffers directly for
> > > > rendering.
> > > > 
> > > > An alternative approach to have the sync code in `MappedFrameBuffer` was
> > > > considered but rejected for now, in order to allow clients more
> > > > flexibility.
> > > > 
> > > > Signed-off-by: Robert Mader <robert.mader@collabora.com>
> > > > 
> > > > ---
> > > > 
> > > > Changes in v2:
> > > >  - sync input buffer as well
> > > >  - update commit title accordingly
> > > >  - small changes to the commit message
> > > >  - linting fixes, should pass now
> > > > ---
> > > >  src/libcamera/software_isp/debayer_cpu.cpp | 35 ++++++++++++++++++++++
> > > >  1 file changed, 35 insertions(+)
> > > > 
> > > > diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
> > > > index 077f7f4b..a3b4851c 100644
> > > > --- a/src/libcamera/software_isp/debayer_cpu.cpp
> > > > +++ b/src/libcamera/software_isp/debayer_cpu.cpp
> > > > @@ -12,8 +12,11 @@
> > > >  #include "debayer_cpu.h"
> > > >  
> > > >  #include <stdlib.h>
> > > > +#include <sys/ioctl.h>
> > > >  #include <time.h>
> > > >  
> > > > +#include <linux/dma-buf.h>
> > > > +
> > > >  #include <libcamera/formats.h>
> > > >  
> > > >  #include "libcamera/internal/bayer_format.h"
> > > > @@ -733,6 +736,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
> > > >                 clock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime);
> > > >         }
> > > >  
> > > > +       for (const FrameBuffer::Plane &plane : input->planes()) {
> > > > +               const int fd = plane.fd.get();
> > > > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ };
> > > > +
> > > > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > > > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > > 
> > > We can't use 'errno' directly on our error messages because the LOG()
> > > implementations or other processing of the log statement (not in this
> > > case, but in others it could be possible) could affect errno.
> > > 
> > > So we use the style 
> > > 
> > > src/libcamera/dma_buf_allocator.cpp-    if (ret < 0) {
> > > src/libcamera/dma_buf_allocator.cpp:            ret = errno;
> > > src/libcamera/dma_buf_allocator.cpp-            LOG(DmaBufAllocator, Error)
> > > src/libcamera/dma_buf_allocator.cpp-                    << "Failed to create dma buf for " << name
> > > src/libcamera/dma_buf_allocator.cpp-                    << ": " << strerror(ret);
> > > src/libcamera/dma_buf_allocator.cpp-            return {};
> > > src/libcamera/dma_buf_allocator.cpp-    }
> > > 
> > > Where we store the errno immediately and then use it in the log. It's
> > > also helpful to use strerror too.
> > > 
> > > > +       }
> > > > +
> > > > +       for (const FrameBuffer::Plane &plane : output->planes()) {
> > > > +               const int fd = plane.fd.get();
> > > > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE };
> > > > +
> > > > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > > > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > > > +       }
> > > 
> > > (jumping back up from below) And this likewise could then be:
> > > 
> > >       intput->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ);
> > >       output->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE);
> > > 
> > > > +
> > > >         green_ = params.green;
> > > >         red_ = swapRedBlueGains_ ? params.blue : params.red;
> > > >         blue_ = swapRedBlueGains_ ? params.red : params.blue;
> > > > @@ -760,6 +779,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
> > > >  
> > > >         metadata.planes()[0].bytesused = out.planes()[0].size();
> > > >  
> > > > +       for (const FrameBuffer::Plane &plane : output->planes()) {
> > > > +               const int fd = plane.fd.get();
> > > > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE };
> > > > +
> > > > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > > > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > > > +       }
> > > > +
> > > > +       for (const FrameBuffer::Plane &plane : input->planes()) {
> > > > +               const int fd = plane.fd.get();
> > > > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ };
> > > > +
> > > > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > > > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > > 
> > > That's four iterations of very similar code. I think we could add a
> > > helper directly into FrameBuffer directly as a preceeding patch, that
> > > would allow something more like:
> > > 
> > >       output->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
> > >       input->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ);
> > > 
> > > We could probably do that using our Flags class too ... but the above
> > > would be a good start.
> > 
> > I'd like a helper too, but I don't think it should be part of the public
> > API, so the FrameBuffer class isn't the right place.
> 
> How about in FrameBuffer::Private::sync() then ?

I was thinking about the same, I think

	input->_d()->sync()

would work.

> Or worst case - and to progress here, at the very least - just a private
> DebayerCpu::syncBuffer() for
> 
> 	syncBuffer(output, DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
> 
> which would at least bump any documentation requirements until there are
> more users.
> 
> > > > +       }
> > > > +
> > > >         /* Measure before emitting signals */
> > > >         if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure &&
> > > >             ++measuredFrames_ > DebayerCpu::kFramesToSkip) {
Nicolas Dufresne Sept. 13, 2024, 2:50 p.m. UTC | #5
Hi,

Le vendredi 13 septembre 2024 à 17:34 +0300, Laurent Pinchart a écrit :
> On Fri, Sep 13, 2024 at 02:06:37PM +0100, Kieran Bingham wrote:
> > Quoting Laurent Pinchart (2024-09-13 13:38:44)
> > > On Fri, Sep 13, 2024 at 01:31:11PM +0100, Kieran Bingham wrote:
> > > > Quoting Robert Mader (2024-09-13 13:04:16)
> > > > > Using `DMA_BUF_IOCTL_SYNC` is required for DMABUFs in order to ensure
> > > > > correct output. Not doing so currently results in occasional tearing
> > > > > and/or backlashes in GL/VK clients that use the buffers directly for
> > > > > rendering.
> > > > > 
> > > > > An alternative approach to have the sync code in `MappedFrameBuffer` was
> > > > > considered but rejected for now, in order to allow clients more
> > > > > flexibility.
> > > > > 
> > > > > Signed-off-by: Robert Mader <robert.mader@collabora.com>
> > > > > 
> > > > > ---
> > > > > 
> > > > > Changes in v2:
> > > > >  - sync input buffer as well
> > > > >  - update commit title accordingly
> > > > >  - small changes to the commit message
> > > > >  - linting fixes, should pass now
> > > > > ---
> > > > >  src/libcamera/software_isp/debayer_cpu.cpp | 35 ++++++++++++++++++++++
> > > > >  1 file changed, 35 insertions(+)
> > > > > 
> > > > > diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
> > > > > index 077f7f4b..a3b4851c 100644
> > > > > --- a/src/libcamera/software_isp/debayer_cpu.cpp
> > > > > +++ b/src/libcamera/software_isp/debayer_cpu.cpp
> > > > > @@ -12,8 +12,11 @@
> > > > >  #include "debayer_cpu.h"
> > > > >  
> > > > >  #include <stdlib.h>
> > > > > +#include <sys/ioctl.h>
> > > > >  #include <time.h>
> > > > >  
> > > > > +#include <linux/dma-buf.h>
> > > > > +
> > > > >  #include <libcamera/formats.h>
> > > > >  
> > > > >  #include "libcamera/internal/bayer_format.h"
> > > > > @@ -733,6 +736,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
> > > > >                 clock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime);
> > > > >         }
> > > > >  
> > > > > +       for (const FrameBuffer::Plane &plane : input->planes()) {
> > > > > +               const int fd = plane.fd.get();
> > > > > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ };
> > > > > +
> > > > > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > > > > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > > > 
> > > > We can't use 'errno' directly on our error messages because the LOG()
> > > > implementations or other processing of the log statement (not in this
> > > > case, but in others it could be possible) could affect errno.
> > > > 
> > > > So we use the style 
> > > > 
> > > > src/libcamera/dma_buf_allocator.cpp-    if (ret < 0) {
> > > > src/libcamera/dma_buf_allocator.cpp:            ret = errno;
> > > > src/libcamera/dma_buf_allocator.cpp-            LOG(DmaBufAllocator, Error)
> > > > src/libcamera/dma_buf_allocator.cpp-                    << "Failed to create dma buf for " << name
> > > > src/libcamera/dma_buf_allocator.cpp-                    << ": " << strerror(ret);
> > > > src/libcamera/dma_buf_allocator.cpp-            return {};
> > > > src/libcamera/dma_buf_allocator.cpp-    }
> > > > 
> > > > Where we store the errno immediately and then use it in the log. It's
> > > > also helpful to use strerror too.
> > > > 
> > > > > +       }
> > > > > +
> > > > > +       for (const FrameBuffer::Plane &plane : output->planes()) {
> > > > > +               const int fd = plane.fd.get();
> > > > > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE };
> > > > > +
> > > > > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > > > > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > > > > +       }
> > > > 
> > > > (jumping back up from below) And this likewise could then be:
> > > > 
> > > >       intput->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ);
> > > >       output->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE);
> > > > 
> > > > > +
> > > > >         green_ = params.green;
> > > > >         red_ = swapRedBlueGains_ ? params.blue : params.red;
> > > > >         blue_ = swapRedBlueGains_ ? params.red : params.blue;
> > > > > @@ -760,6 +779,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
> > > > >  
> > > > >         metadata.planes()[0].bytesused = out.planes()[0].size();
> > > > >  
> > > > > +       for (const FrameBuffer::Plane &plane : output->planes()) {
> > > > > +               const int fd = plane.fd.get();
> > > > > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE };
> > > > > +
> > > > > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > > > > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > > > > +       }
> > > > > +
> > > > > +       for (const FrameBuffer::Plane &plane : input->planes()) {
> > > > > +               const int fd = plane.fd.get();
> > > > > +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ };
> > > > > +
> > > > > +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> > > > > +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> > > > 
> > > > That's four iterations of very similar code. I think we could add a
> > > > helper directly into FrameBuffer directly as a preceeding patch, that
> > > > would allow something more like:
> > > > 
> > > >       output->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
> > > >       input->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ);
> > > > 
> > > > We could probably do that using our Flags class too ... but the above
> > > > would be a good start.
> > > 
> > > I'd like a helper too, but I don't think it should be part of the public
> > > API, so the FrameBuffer class isn't the right place.
> > 
> > How about in FrameBuffer::Private::sync() then ?
> 
> I was thinking about the same, I think
> 
> 	input->_d()->sync()
> 
> would work.

For our future sanity, I may suggest to call this sync_for_cpu() or something
like this. Just being a little more precise make its clear what this is doing.

> 
> > Or worst case - and to progress here, at the very least - just a private
> > DebayerCpu::syncBuffer() for
> > 
> > 	syncBuffer(output, DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
> > 
> > which would at least bump any documentation requirements until there are
> > more users.
> > 
> > > > > +       }
> > > > > +
> > > > >         /* Measure before emitting signals */
> > > > >         if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure &&
> > > > >             ++measuredFrames_ > DebayerCpu::kFramesToSkip) {
>
Robert Mader Sept. 16, 2024, 10:45 a.m. UTC | #6
Any resistance against a local

syncBufferForCPU(output, DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);

then?

On 13.09.24 16:50, Nicolas Dufresne wrote:
> Hi,
>
> Le vendredi 13 septembre 2024 à 17:34 +0300, Laurent Pinchart a écrit :
>> On Fri, Sep 13, 2024 at 02:06:37PM +0100, Kieran Bingham wrote:
>>> Quoting Laurent Pinchart (2024-09-13 13:38:44)
>>>> On Fri, Sep 13, 2024 at 01:31:11PM +0100, Kieran Bingham wrote:
>>>>> Quoting Robert Mader (2024-09-13 13:04:16)
>>>>>> Using `DMA_BUF_IOCTL_SYNC` is required for DMABUFs in order to ensure
>>>>>> correct output. Not doing so currently results in occasional tearing
>>>>>> and/or backlashes in GL/VK clients that use the buffers directly for
>>>>>> rendering.
>>>>>>
>>>>>> An alternative approach to have the sync code in `MappedFrameBuffer` was
>>>>>> considered but rejected for now, in order to allow clients more
>>>>>> flexibility.
>>>>>>
>>>>>> Signed-off-by: Robert Mader <robert.mader@collabora.com>
>>>>>>
>>>>>> ---
>>>>>>
>>>>>> Changes in v2:
>>>>>>   - sync input buffer as well
>>>>>>   - update commit title accordingly
>>>>>>   - small changes to the commit message
>>>>>>   - linting fixes, should pass now
>>>>>> ---
>>>>>>   src/libcamera/software_isp/debayer_cpu.cpp | 35 ++++++++++++++++++++++
>>>>>>   1 file changed, 35 insertions(+)
>>>>>>
>>>>>> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
>>>>>> index 077f7f4b..a3b4851c 100644
>>>>>> --- a/src/libcamera/software_isp/debayer_cpu.cpp
>>>>>> +++ b/src/libcamera/software_isp/debayer_cpu.cpp
>>>>>> @@ -12,8 +12,11 @@
>>>>>>   #include "debayer_cpu.h"
>>>>>>   
>>>>>>   #include <stdlib.h>
>>>>>> +#include <sys/ioctl.h>
>>>>>>   #include <time.h>
>>>>>>   
>>>>>> +#include <linux/dma-buf.h>
>>>>>> +
>>>>>>   #include <libcamera/formats.h>
>>>>>>   
>>>>>>   #include "libcamera/internal/bayer_format.h"
>>>>>> @@ -733,6 +736,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
>>>>>>                  clock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime);
>>>>>>          }
>>>>>>   
>>>>>> +       for (const FrameBuffer::Plane &plane : input->planes()) {
>>>>>> +               const int fd = plane.fd.get();
>>>>>> +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ };
>>>>>> +
>>>>>> +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
>>>>>> +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
>>>>> We can't use 'errno' directly on our error messages because the LOG()
>>>>> implementations or other processing of the log statement (not in this
>>>>> case, but in others it could be possible) could affect errno.
>>>>>
>>>>> So we use the style
>>>>>
>>>>> src/libcamera/dma_buf_allocator.cpp-    if (ret < 0) {
>>>>> src/libcamera/dma_buf_allocator.cpp:            ret = errno;
>>>>> src/libcamera/dma_buf_allocator.cpp-            LOG(DmaBufAllocator, Error)
>>>>> src/libcamera/dma_buf_allocator.cpp-                    << "Failed to create dma buf for " << name
>>>>> src/libcamera/dma_buf_allocator.cpp-                    << ": " << strerror(ret);
>>>>> src/libcamera/dma_buf_allocator.cpp-            return {};
>>>>> src/libcamera/dma_buf_allocator.cpp-    }
>>>>>
>>>>> Where we store the errno immediately and then use it in the log. It's
>>>>> also helpful to use strerror too.
>>>>>
>>>>>> +       }
>>>>>> +
>>>>>> +       for (const FrameBuffer::Plane &plane : output->planes()) {
>>>>>> +               const int fd = plane.fd.get();
>>>>>> +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE };
>>>>>> +
>>>>>> +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
>>>>>> +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
>>>>>> +       }
>>>>> (jumping back up from below) And this likewise could then be:
>>>>>
>>>>>        intput->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ);
>>>>>        output->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE);
>>>>>
>>>>>> +
>>>>>>          green_ = params.green;
>>>>>>          red_ = swapRedBlueGains_ ? params.blue : params.red;
>>>>>>          blue_ = swapRedBlueGains_ ? params.red : params.blue;
>>>>>> @@ -760,6 +779,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
>>>>>>   
>>>>>>          metadata.planes()[0].bytesused = out.planes()[0].size();
>>>>>>   
>>>>>> +       for (const FrameBuffer::Plane &plane : output->planes()) {
>>>>>> +               const int fd = plane.fd.get();
>>>>>> +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE };
>>>>>> +
>>>>>> +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
>>>>>> +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
>>>>>> +       }
>>>>>> +
>>>>>> +       for (const FrameBuffer::Plane &plane : input->planes()) {
>>>>>> +               const int fd = plane.fd.get();
>>>>>> +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ };
>>>>>> +
>>>>>> +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
>>>>>> +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
>>>>> That's four iterations of very similar code. I think we could add a
>>>>> helper directly into FrameBuffer directly as a preceeding patch, that
>>>>> would allow something more like:
>>>>>
>>>>>        output->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
>>>>>        input->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ);
>>>>>
>>>>> We could probably do that using our Flags class too ... but the above
>>>>> would be a good start.
>>>> I'd like a helper too, but I don't think it should be part of the public
>>>> API, so the FrameBuffer class isn't the right place.
>>> How about in FrameBuffer::Private::sync() then ?
>> I was thinking about the same, I think
>>
>> 	input->_d()->sync()
>>
>> would work.
> For our future sanity, I may suggest to call this sync_for_cpu() or something
> like this. Just being a little more precise make its clear what this is doing.
>
>>> Or worst case - and to progress here, at the very least - just a private
>>> DebayerCpu::syncBuffer() for
>>>
>>> 	syncBuffer(output, DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
>>>
>>> which would at least bump any documentation requirements until there are
>>> more users.
>>>
>>>>>> +       }
>>>>>> +
>>>>>>          /* Measure before emitting signals */
>>>>>>          if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure &&
>>>>>>              ++measuredFrames_ > DebayerCpu::kFramesToSkip) {
Kieran Bingham Sept. 16, 2024, 12:41 p.m. UTC | #7
Quoting Robert Mader (2024-09-16 11:45:30)
> Any resistance against a local
> 
> syncBufferForCPU(output, DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
> 
> then?

If this is the first/only place to add these so far then I think that's
fine, as long as the duplication below is wrapped into a simple helper.

It can be local, and then if/when we determine a second place to make
use of it we can move to the FrameBuffer::Private::syncForCpu() and
handle documentation and flags conversions that might be more desireable
if this is used more widely.

--
Kieran


> 
> On 13.09.24 16:50, Nicolas Dufresne wrote:
> > Hi,
> >
> > Le vendredi 13 septembre 2024 à 17:34 +0300, Laurent Pinchart a écrit :
> >> On Fri, Sep 13, 2024 at 02:06:37PM +0100, Kieran Bingham wrote:
> >>> Quoting Laurent Pinchart (2024-09-13 13:38:44)
> >>>> On Fri, Sep 13, 2024 at 01:31:11PM +0100, Kieran Bingham wrote:
> >>>>> Quoting Robert Mader (2024-09-13 13:04:16)
> >>>>>> Using `DMA_BUF_IOCTL_SYNC` is required for DMABUFs in order to ensure
> >>>>>> correct output. Not doing so currently results in occasional tearing
> >>>>>> and/or backlashes in GL/VK clients that use the buffers directly for
> >>>>>> rendering.
> >>>>>>
> >>>>>> An alternative approach to have the sync code in `MappedFrameBuffer` was
> >>>>>> considered but rejected for now, in order to allow clients more
> >>>>>> flexibility.
> >>>>>>
> >>>>>> Signed-off-by: Robert Mader <robert.mader@collabora.com>
> >>>>>>
> >>>>>> ---
> >>>>>>
> >>>>>> Changes in v2:
> >>>>>>   - sync input buffer as well
> >>>>>>   - update commit title accordingly
> >>>>>>   - small changes to the commit message
> >>>>>>   - linting fixes, should pass now
> >>>>>> ---
> >>>>>>   src/libcamera/software_isp/debayer_cpu.cpp | 35 ++++++++++++++++++++++
> >>>>>>   1 file changed, 35 insertions(+)
> >>>>>>
> >>>>>> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
> >>>>>> index 077f7f4b..a3b4851c 100644
> >>>>>> --- a/src/libcamera/software_isp/debayer_cpu.cpp
> >>>>>> +++ b/src/libcamera/software_isp/debayer_cpu.cpp
> >>>>>> @@ -12,8 +12,11 @@
> >>>>>>   #include "debayer_cpu.h"
> >>>>>>   
> >>>>>>   #include <stdlib.h>
> >>>>>> +#include <sys/ioctl.h>
> >>>>>>   #include <time.h>
> >>>>>>   
> >>>>>> +#include <linux/dma-buf.h>
> >>>>>> +
> >>>>>>   #include <libcamera/formats.h>
> >>>>>>   
> >>>>>>   #include "libcamera/internal/bayer_format.h"
> >>>>>> @@ -733,6 +736,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
> >>>>>>                  clock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime);
> >>>>>>          }
> >>>>>>   
> >>>>>> +       for (const FrameBuffer::Plane &plane : input->planes()) {
> >>>>>> +               const int fd = plane.fd.get();
> >>>>>> +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ };
> >>>>>> +
> >>>>>> +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> >>>>>> +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> >>>>> We can't use 'errno' directly on our error messages because the LOG()
> >>>>> implementations or other processing of the log statement (not in this
> >>>>> case, but in others it could be possible) could affect errno.
> >>>>>
> >>>>> So we use the style
> >>>>>
> >>>>> src/libcamera/dma_buf_allocator.cpp-    if (ret < 0) {
> >>>>> src/libcamera/dma_buf_allocator.cpp:            ret = errno;
> >>>>> src/libcamera/dma_buf_allocator.cpp-            LOG(DmaBufAllocator, Error)
> >>>>> src/libcamera/dma_buf_allocator.cpp-                    << "Failed to create dma buf for " << name
> >>>>> src/libcamera/dma_buf_allocator.cpp-                    << ": " << strerror(ret);
> >>>>> src/libcamera/dma_buf_allocator.cpp-            return {};
> >>>>> src/libcamera/dma_buf_allocator.cpp-    }
> >>>>>
> >>>>> Where we store the errno immediately and then use it in the log. It's
> >>>>> also helpful to use strerror too.
> >>>>>
> >>>>>> +       }
> >>>>>> +
> >>>>>> +       for (const FrameBuffer::Plane &plane : output->planes()) {
> >>>>>> +               const int fd = plane.fd.get();
> >>>>>> +               struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE };
> >>>>>> +
> >>>>>> +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> >>>>>> +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> >>>>>> +       }
> >>>>> (jumping back up from below) And this likewise could then be:
> >>>>>
> >>>>>        intput->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ);
> >>>>>        output->sync(DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE);
> >>>>>
> >>>>>> +
> >>>>>>          green_ = params.green;
> >>>>>>          red_ = swapRedBlueGains_ ? params.blue : params.red;
> >>>>>>          blue_ = swapRedBlueGains_ ? params.red : params.blue;
> >>>>>> @@ -760,6 +779,22 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
> >>>>>>   
> >>>>>>          metadata.planes()[0].bytesused = out.planes()[0].size();
> >>>>>>   
> >>>>>> +       for (const FrameBuffer::Plane &plane : output->planes()) {
> >>>>>> +               const int fd = plane.fd.get();
> >>>>>> +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE };
> >>>>>> +
> >>>>>> +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> >>>>>> +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> >>>>>> +       }
> >>>>>> +
> >>>>>> +       for (const FrameBuffer::Plane &plane : input->planes()) {
> >>>>>> +               const int fd = plane.fd.get();
> >>>>>> +               struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ };
> >>>>>> +
> >>>>>> +               if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
> >>>>>> +                       LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
> >>>>> That's four iterations of very similar code. I think we could add a
> >>>>> helper directly into FrameBuffer directly as a preceeding patch, that
> >>>>> would allow something more like:
> >>>>>
> >>>>>        output->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
> >>>>>        input->sync(DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ);
> >>>>>
> >>>>> We could probably do that using our Flags class too ... but the above
> >>>>> would be a good start.
> >>>> I'd like a helper too, but I don't think it should be part of the public
> >>>> API, so the FrameBuffer class isn't the right place.
> >>> How about in FrameBuffer::Private::sync() then ?
> >> I was thinking about the same, I think
> >>
> >>      input->_d()->sync()
> >>
> >> would work.
> > For our future sanity, I may suggest to call this sync_for_cpu() or something
> > like this. Just being a little more precise make its clear what this is doing.
> >
> >>> Or worst case - and to progress here, at the very least - just a private
> >>> DebayerCpu::syncBuffer() for
> >>>
> >>>     syncBuffer(output, DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
> >>>
> >>> which would at least bump any documentation requirements until there are
> >>> more users.
> >>>
> >>>>>> +       }
> >>>>>> +
> >>>>>>          /* Measure before emitting signals */
> >>>>>>          if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure &&
> >>>>>>              ++measuredFrames_ > DebayerCpu::kFramesToSkip) {
> 
> -- 
> Robert Mader
> Consultant Software Developer
> 
> Collabora Ltd.
> Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, UK
> Registered in England & Wales, no. 5513718
>

Patch
diff mbox series

diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
index 077f7f4b..a3b4851c 100644
--- a/src/libcamera/software_isp/debayer_cpu.cpp
+++ b/src/libcamera/software_isp/debayer_cpu.cpp
@@ -12,8 +12,11 @@ 
 #include "debayer_cpu.h"
 
 #include <stdlib.h>
+#include <sys/ioctl.h>
 #include <time.h>
 
+#include <linux/dma-buf.h>
+
 #include <libcamera/formats.h>
 
 #include "libcamera/internal/bayer_format.h"
@@ -733,6 +736,22 @@  void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
 		clock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime);
 	}
 
+	for (const FrameBuffer::Plane &plane : input->planes()) {
+		const int fd = plane.fd.get();
+		struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ };
+
+		if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
+			LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
+	}
+
+	for (const FrameBuffer::Plane &plane : output->planes()) {
+		const int fd = plane.fd.get();
+		struct dma_buf_sync sync = { DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE };
+
+		if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
+			LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
+	}
+
 	green_ = params.green;
 	red_ = swapRedBlueGains_ ? params.blue : params.red;
 	blue_ = swapRedBlueGains_ ? params.red : params.blue;
@@ -760,6 +779,22 @@  void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams
 
 	metadata.planes()[0].bytesused = out.planes()[0].size();
 
+	for (const FrameBuffer::Plane &plane : output->planes()) {
+		const int fd = plane.fd.get();
+		struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE };
+
+		if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
+			LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
+	}
+
+	for (const FrameBuffer::Plane &plane : input->planes()) {
+		const int fd = plane.fd.get();
+		struct dma_buf_sync sync = { DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ };
+
+		if (ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync) < 0)
+			LOG(Debayer, Error) << "Syncing buffer FD " << fd << "failed: " << errno;
+	}
+
 	/* Measure before emitting signals */
 	if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure &&
 	    ++measuredFrames_ > DebayerCpu::kFramesToSkip) {