[v4,3/7] libcamera: software_isp: Pass correct y-coordinate to stats
diff mbox series

Message ID 20250925192856.77881-4-mzamazal@redhat.com
State Superseded
Headers show
Series
  • Fix stats related problems in software ISP
Related show

Commit Message

Milan Zamazal Sept. 25, 2025, 7:28 p.m. UTC
The window set by SwStatsCpu::setWindow is relative to the processed
image area.  But debayering passes the processed line y-coordinate to
the stats relative to the whole image area.  This can result in
gathering stats from a wrong image area or in not gathering stats at
all.

Let's pass the correct y-coordinate to the stats processing methods.

Bug: https://bugs.libcamera.org/show_bug.cgi?id=280
Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
---
 src/libcamera/software_isp/debayer_cpu.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

Comments

Hans de Goede Sept. 29, 2025, 11:16 a.m. UTC | #1
Hi Milan,

Thank you for these fixes.

On 25-Sep-25 21:28, Milan Zamazal wrote:
> The window set by SwStatsCpu::setWindow is relative to the processed
> image area.  But debayering passes the processed line y-coordinate to
> the stats relative to the whole image area.  This can result in
> gathering stats from a wrong image area or in not gathering stats at
> all.
> 
> Let's pass the correct y-coordinate to the stats processing methods.
> 
> Bug: https://bugs.libcamera.org/show_bug.cgi?id=280
> Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
> ---
>  src/libcamera/software_isp/debayer_cpu.cpp | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
> index bcaaa5dee..5f3f22f07 100644
> --- a/src/libcamera/software_isp/debayer_cpu.cpp
> +++ b/src/libcamera/software_isp/debayer_cpu.cpp
> @@ -661,7 +661,7 @@ void DebayerCpu::memcpyNextLine(const uint8_t *linePointers[])
>  
>  void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
>  {
> -	unsigned int yEnd = window_.y + window_.height;
> +	unsigned int yEnd = window_.height;
>  	/* Holds [0] previous- [1] current- [2] next-line */
>  	const uint8_t *linePointers[3];
>  
> @@ -677,12 +677,12 @@ void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
>  		linePointers[1] = src + inputConfig_.stride;
>  		linePointers[2] = src;
>  		/* Last 2 lines also need special handling */
> -		yEnd -= 2;
> +		yEnd = (yEnd > 2 ? yEnd - 2 : 0);
>  	}
>  

Before the substraction yEnd = window_.heigh, which can never be less then 2.

See sizes() method in debayer_cpu.cpp, this sets a min-outputsize of
patternSize-width x patternSize-height which is a minimum of 2x2, this is
enforced by DebayerCpu::configure().

So this part of the patch is not necessary.

>  	setupInputMemcpy(linePointers);
>  
> -	for (unsigned int y = window_.y; y < yEnd; y += 2) {
> +	for (unsigned int y = 0; y < yEnd; y += 2) {
>  		shiftLinePointers(linePointers, src);
>  		memcpyNextLine(linePointers);
>  		stats_->processLine0(y, linePointers);
> @@ -716,7 +716,7 @@ void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
>  
>  void DebayerCpu::process4(const uint8_t *src, uint8_t *dst)
>  {
> -	const unsigned int yEnd = window_.y + window_.height;
> +	const unsigned int yEnd = window_.height;

Unlike in process2(), where it can be modified, my suggestion would be to
just completely drop the yEnd variable here.

>  	/*
>  	 * This holds pointers to [0] 2-lines-up [1] 1-line-up [2] current-line
>  	 * [3] 1-line-down [4] 2-lines-down.
> @@ -734,7 +734,7 @@ void DebayerCpu::process4(const uint8_t *src, uint8_t *dst)
>  
>  	setupInputMemcpy(linePointers);
>  
> -	for (unsigned int y = window_.y; y < yEnd; y += 4) {
> +	for (unsigned int y = 0; y < yEnd; y += 4) {

And then just use 'y < window_.height' here.

With those changes this looks good to me:

Reviewed-by: Hans de Goede <hansg@kernel.org>

Regards,

Hans




>  		shiftLinePointers(linePointers, src);
>  		memcpyNextLine(linePointers);
>  		stats_->processLine0(y, linePointers);
Barnabás Pőcze Sept. 29, 2025, 11:17 a.m. UTC | #2
Hi

2025. 09. 25. 21:28 keltezéssel, Milan Zamazal írta:
> The window set by SwStatsCpu::setWindow is relative to the processed
> image area.  But debayering passes the processed line y-coordinate to
> the stats relative to the whole image area.  This can result in
> gathering stats from a wrong image area or in not gathering stats at
> all.
> 
> Let's pass the correct y-coordinate to the stats processing methods.
> 
> Bug: https://bugs.libcamera.org/show_bug.cgi?id=280
> Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
> ---

Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>


>   src/libcamera/software_isp/debayer_cpu.cpp | 10 +++++-----
>   1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
> index bcaaa5dee..5f3f22f07 100644
> --- a/src/libcamera/software_isp/debayer_cpu.cpp
> +++ b/src/libcamera/software_isp/debayer_cpu.cpp
> @@ -661,7 +661,7 @@ void DebayerCpu::memcpyNextLine(const uint8_t *linePointers[])
>   
>   void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
>   {
> -	unsigned int yEnd = window_.y + window_.height;
> +	unsigned int yEnd = window_.height;
>   	/* Holds [0] previous- [1] current- [2] next-line */
>   	const uint8_t *linePointers[3];
>   
> @@ -677,12 +677,12 @@ void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
>   		linePointers[1] = src + inputConfig_.stride;
>   		linePointers[2] = src;
>   		/* Last 2 lines also need special handling */
> -		yEnd -= 2;
> +		yEnd = (yEnd > 2 ? yEnd - 2 : 0);
>   	}
>   
>   	setupInputMemcpy(linePointers);
>   
> -	for (unsigned int y = window_.y; y < yEnd; y += 2) {
> +	for (unsigned int y = 0; y < yEnd; y += 2) {
>   		shiftLinePointers(linePointers, src);
>   		memcpyNextLine(linePointers);
>   		stats_->processLine0(y, linePointers);
> @@ -716,7 +716,7 @@ void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
>   
>   void DebayerCpu::process4(const uint8_t *src, uint8_t *dst)
>   {
> -	const unsigned int yEnd = window_.y + window_.height;
> +	const unsigned int yEnd = window_.height;
>   	/*
>   	 * This holds pointers to [0] 2-lines-up [1] 1-line-up [2] current-line
>   	 * [3] 1-line-down [4] 2-lines-down.
> @@ -734,7 +734,7 @@ void DebayerCpu::process4(const uint8_t *src, uint8_t *dst)
>   
>   	setupInputMemcpy(linePointers);
>   
> -	for (unsigned int y = window_.y; y < yEnd; y += 4) {
> +	for (unsigned int y = 0; y < yEnd; y += 4) {
>   		shiftLinePointers(linePointers, src);
>   		memcpyNextLine(linePointers);
>   		stats_->processLine0(y, linePointers);
Maciej S. Szmigiero Sept. 29, 2025, 11:18 a.m. UTC | #3
On 29.09.2025 13:16, Hans de Goede wrote:
> Hi Milan,
> 
> Thank you for these fixes.
> 
> On 25-Sep-25 21:28, Milan Zamazal wrote:
>> The window set by SwStatsCpu::setWindow is relative to the processed
>> image area.  But debayering passes the processed line y-coordinate to
>> the stats relative to the whole image area.  This can result in
>> gathering stats from a wrong image area or in not gathering stats at
>> all.
>>
>> Let's pass the correct y-coordinate to the stats processing methods.
>>
>> Bug: https://bugs.libcamera.org/show_bug.cgi?id=280
>> Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
>> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
>> ---
>>   src/libcamera/software_isp/debayer_cpu.cpp | 10 +++++-----
>>   1 file changed, 5 insertions(+), 5 deletions(-)
>>
>> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
>> index bcaaa5dee..5f3f22f07 100644
>> --- a/src/libcamera/software_isp/debayer_cpu.cpp
>> +++ b/src/libcamera/software_isp/debayer_cpu.cpp
>> @@ -661,7 +661,7 @@ void DebayerCpu::memcpyNextLine(const uint8_t *linePointers[])
>>   
>>   void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
>>   {
>> -	unsigned int yEnd = window_.y + window_.height;
>> +	unsigned int yEnd = window_.height;
>>   	/* Holds [0] previous- [1] current- [2] next-line */
>>   	const uint8_t *linePointers[3];
>>   
>> @@ -677,12 +677,12 @@ void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
>>   		linePointers[1] = src + inputConfig_.stride;
>>   		linePointers[2] = src;
>>   		/* Last 2 lines also need special handling */
>> -		yEnd -= 2;
>> +		yEnd = (yEnd > 2 ? yEnd - 2 : 0);
>>   	}
>>   
> 
> Before the substraction yEnd = window_.heigh, which can never be less then 2.
> 
> See sizes() method in debayer_cpu.cpp, this sets a min-outputsize of
> patternSize-width x patternSize-height which is a minimum of 2x2, this is
> enforced by DebayerCpu::configure().
> 
> So this part of the patch is not necessary.

Maybe replace it with an ASSERT() then just to be sure?

Thanks,
Maciej
Hans de Goede Sept. 29, 2025, 11:20 a.m. UTC | #4
Hi,

On 29-Sep-25 13:18, Maciej S. Szmigiero wrote:
> On 29.09.2025 13:16, Hans de Goede wrote:
>> Hi Milan,
>>
>> Thank you for these fixes.
>>
>> On 25-Sep-25 21:28, Milan Zamazal wrote:
>>> The window set by SwStatsCpu::setWindow is relative to the processed
>>> image area.  But debayering passes the processed line y-coordinate to
>>> the stats relative to the whole image area.  This can result in
>>> gathering stats from a wrong image area or in not gathering stats at
>>> all.
>>>
>>> Let's pass the correct y-coordinate to the stats processing methods.
>>>
>>> Bug: https://bugs.libcamera.org/show_bug.cgi?id=280
>>> Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
>>> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
>>> ---
>>>   src/libcamera/software_isp/debayer_cpu.cpp | 10 +++++-----
>>>   1 file changed, 5 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
>>> index bcaaa5dee..5f3f22f07 100644
>>> --- a/src/libcamera/software_isp/debayer_cpu.cpp
>>> +++ b/src/libcamera/software_isp/debayer_cpu.cpp
>>> @@ -661,7 +661,7 @@ void DebayerCpu::memcpyNextLine(const uint8_t *linePointers[])
>>>     void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
>>>   {
>>> -    unsigned int yEnd = window_.y + window_.height;
>>> +    unsigned int yEnd = window_.height;
>>>       /* Holds [0] previous- [1] current- [2] next-line */
>>>       const uint8_t *linePointers[3];
>>>   @@ -677,12 +677,12 @@ void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
>>>           linePointers[1] = src + inputConfig_.stride;
>>>           linePointers[2] = src;
>>>           /* Last 2 lines also need special handling */
>>> -        yEnd -= 2;
>>> +        yEnd = (yEnd > 2 ? yEnd - 2 : 0);
>>>       }
>>>   
>>
>> Before the substraction yEnd = window_.heigh, which can never be less then 2.
>>
>> See sizes() method in debayer_cpu.cpp, this sets a min-outputsize of
>> patternSize-width x patternSize-height which is a minimum of 2x2, this is
>> enforced by DebayerCpu::configure().
>>
>> So this part of the patch is not necessary.
> 
> Maybe replace it with an ASSERT() then just to be sure?

Adding an assert is probably a good idea, but IMHO that should be done
in a separate patch, since yEnd underflowing can already happen with
the current code.

Regards,

Hans

Patch
diff mbox series

diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
index bcaaa5dee..5f3f22f07 100644
--- a/src/libcamera/software_isp/debayer_cpu.cpp
+++ b/src/libcamera/software_isp/debayer_cpu.cpp
@@ -661,7 +661,7 @@  void DebayerCpu::memcpyNextLine(const uint8_t *linePointers[])
 
 void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
 {
-	unsigned int yEnd = window_.y + window_.height;
+	unsigned int yEnd = window_.height;
 	/* Holds [0] previous- [1] current- [2] next-line */
 	const uint8_t *linePointers[3];
 
@@ -677,12 +677,12 @@  void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
 		linePointers[1] = src + inputConfig_.stride;
 		linePointers[2] = src;
 		/* Last 2 lines also need special handling */
-		yEnd -= 2;
+		yEnd = (yEnd > 2 ? yEnd - 2 : 0);
 	}
 
 	setupInputMemcpy(linePointers);
 
-	for (unsigned int y = window_.y; y < yEnd; y += 2) {
+	for (unsigned int y = 0; y < yEnd; y += 2) {
 		shiftLinePointers(linePointers, src);
 		memcpyNextLine(linePointers);
 		stats_->processLine0(y, linePointers);
@@ -716,7 +716,7 @@  void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)
 
 void DebayerCpu::process4(const uint8_t *src, uint8_t *dst)
 {
-	const unsigned int yEnd = window_.y + window_.height;
+	const unsigned int yEnd = window_.height;
 	/*
 	 * This holds pointers to [0] 2-lines-up [1] 1-line-up [2] current-line
 	 * [3] 1-line-down [4] 2-lines-down.
@@ -734,7 +734,7 @@  void DebayerCpu::process4(const uint8_t *src, uint8_t *dst)
 
 	setupInputMemcpy(linePointers);
 
-	for (unsigned int y = window_.y; y < yEnd; y += 4) {
+	for (unsigned int y = 0; y < yEnd; y += 4) {
 		shiftLinePointers(linePointers, src);
 		memcpyNextLine(linePointers);
 		stats_->processLine0(y, linePointers);