[v2,28/37] libcamera: shaders: Extend debayer shaders to apply RGB gain values on output
diff mbox series

Message ID 20250824-b4-v0-5-2-gpuisp-v2-a-v2-28-96f4576c814e@linaro.org
State Superseded
Headers show
Series
  • Add GLES 2.0 GPUISP to libcamera
Related show

Commit Message

Bryan O'Donoghue Aug. 24, 2025, 12:48 a.m. UTC
Extend out the bayer fragment shaders to take 3 x 256 byte inputs as
textures from the CPU.

We then use an index to the table to recover the colour-corrected values
provided by the SoftIPA thread.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 .../internal/shaders/bayer_1x_packed.frag          | 56 +++++++++++++++++++
 include/libcamera/internal/shaders/bayer_8.frag    | 62 +++++++++++++++++++++-
 2 files changed, 117 insertions(+), 1 deletion(-)

Comments

Barnabás Pőcze Sept. 25, 2025, 3:10 p.m. UTC | #1
Hi


2025. 08. 24. 2:48 keltezéssel, Bryan O'Donoghue írta:
> Extend out the bayer fragment shaders to take 3 x 256 byte inputs as
> textures from the CPU.
> 
> We then use an index to the table to recover the colour-corrected values
> provided by the SoftIPA thread.
> 
> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> ---
>   .../internal/shaders/bayer_1x_packed.frag          | 56 +++++++++++++++++++
>   include/libcamera/internal/shaders/bayer_8.frag    | 62 +++++++++++++++++++++-
>   2 files changed, 117 insertions(+), 1 deletion(-)
> 
> diff --git a/include/libcamera/internal/shaders/bayer_1x_packed.frag b/include/libcamera/internal/shaders/bayer_1x_packed.frag
> index 19b13ad08b3a71e408774dbb8e75ca4e22d9ba8e..90bd645709e02d8cf9bee112b25cbb26c681db0a 100644
> --- a/include/libcamera/internal/shaders/bayer_1x_packed.frag
> +++ b/include/libcamera/internal/shaders/bayer_1x_packed.frag
> @@ -65,6 +65,10 @@ uniform vec2 tex_step;
>   uniform vec2 tex_bayer_first_red;
>   
>   uniform sampler2D tex_y;
> +uniform sampler2D red_param;
> +uniform sampler2D green_param;
> +uniform sampler2D blue_param;
> +uniform mat3 ccm;
>   
>   void main(void)
>   {
> @@ -212,5 +216,57 @@ void main(void)
>   			vec3(patterns.y, C, patterns.x) :
>   			vec3(patterns.wz, C));
>   
> +#if defined(APPLY_CCM_PARAMETERS)
> +	/*
> +	 *   CCM is a 3x3 in the format
> +	 *
> +	 *   +--------------+----------------+---------------+
> +	 *   | RedRedGain   | RedGreenGain   | RedBlueGain   |
> +	 *   +--------------+----------------+---------------+
> +	 *   | GreenRedGain | GreenGreenGain | GreenBlueGain |
> +	 *   +--------------+----------------+---------------+
> +	 *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |
> +	 *   +--------------+----------------+---------------+
> +	 *
> +	 *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin
> +	 *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin
> +	 *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin
> +	 *
> +	 *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);
> +	 *
> +	 *   CPU
> +	 *   float ccm [] = {
> +	 *             RedRedGain,   RedGreenGain,   RedBlueGain,
> +	 *             GreenRedGain, GreenGreenGain, GreenBlueGain,
> +	 *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,
> +	 *   };
> +	 *
> +	 *   GPU
> +	 *   ccm = {
> +	 *             RedRedGain,   GreenRedGain,   BlueRedGain,
> +	 *             RedGreenGain, GreenGreenGain, BlueGreenGain,
> +	 *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,
> +	 *   }
> +	 *
> +	 *   However the indexing for the mat data-type is column major hence
> +	 *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain
> +	 *
> +	 */
> +	float rin, gin, bin;
> +	rin = rgb.r;
> +	gin = rgb.g;
> +	bin = rgb.b;
> +
> +	rgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);
> +	rgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);
> +	rgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);
> +
> +#elif defined(APPLY_RGB_PARAMETERS)
> +	/* Apply bayer params */
> +	rgb.r = texture2D(red_param, vec2(rgb.r, 0.5)).r;
> +	rgb.g = texture2D(green_param, vec2(rgb.g, 0.5)).g;
> +	rgb.b = texture2D(blue_param, vec2(rgb.b, 0.5)).b;
> +#endif
> +
>   	gl_FragColor = vec4(rgb, 1.0);
>   }
> diff --git a/include/libcamera/internal/shaders/bayer_8.frag b/include/libcamera/internal/shaders/bayer_8.frag
> index aa7a1b00436ae15d2ed6af7d666441d20db6bb0b..5955c2eafbe03678158b240740e18c7f00e58057 100644
> --- a/include/libcamera/internal/shaders/bayer_8.frag
> +++ b/include/libcamera/internal/shaders/bayer_8.frag
> @@ -21,11 +21,17 @@ precision highp float;
>   
>   /** Monochrome RGBA or GL_LUMINANCE Bayer encoded texture.*/
>   uniform sampler2D       tex_y;
> +uniform sampler2D	red_param;
> +uniform sampler2D	green_param;
> +uniform sampler2D	blue_param;
>   varying vec4            center;
>   varying vec4            yCoord;
>   varying vec4            xCoord;
> +uniform mat3		ccm;
>   
>   void main(void) {
> +    vec3 rgb;
> +
>       #define fetch(x, y) texture2D(tex_y, vec2(x, y)).r
>   
>       float C = texture2D(tex_y, center.xy).r; // ( 0, 0)
> @@ -97,11 +103,65 @@ void main(void) {
>       PATTERN.xw  += kB.xw * B;
>       PATTERN.xz  += kF.xz * F;
>   
> -    gl_FragColor.rgb = (alternate.y == 0.0) ?
> +    rgb =  (alternate.y == 0.0) ?
>           ((alternate.x == 0.0) ?
>               vec3(C, PATTERN.xy) :
>               vec3(PATTERN.z, C, PATTERN.w)) :
>           ((alternate.x == 0.0) ?
>               vec3(PATTERN.w, C, PATTERN.z) :
>               vec3(PATTERN.yx, C));
> +
> +#if defined(APPLY_CCM_PARAMETERS)
> +	/*
> +	 *   CCM is a 3x3 in the format
> +	 *
> +	 *   +--------------+----------------+---------------+
> +	 *   | RedRedGain   | RedGreenGain   | RedBlueGain   |
> +	 *   +--------------+----------------+---------------+
> +	 *   | GreenRedGain | GreenGreenGain | GreenBlueGain |
> +	 *   +--------------+----------------+---------------+
> +	 *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |
> +	 *   +--------------+----------------+---------------+
> +	 *
> +	 *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin
> +	 *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin
> +	 *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin
> +	 *
> +	 *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);
> +	 *
> +	 *   CPU
> +	 *   float ccm [] = {
> +	 *             RedRedGain,   RedGreenGain,   RedBlueGain,
> +	 *             GreenRedGain, GreenGreenGain, GreenBlueGain,
> +	 *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,
> +	 *   };
> +	 *
> +	 *   GPU
> +	 *   ccm = {
> +	 *             RedRedGain,   GreenRedGain,   BlueRedGain,
> +	 *             RedGreenGain, GreenGreenGain, BlueGreenGain,
> +	 *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,
> +	 *   }
> +	 *
> +	 *   However the indexing for the mat data-type is column major hence
> +	 *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain
> +	 *
> +	 */
> +	float rin, gin, bin;
> +	rin = rgb.r;
> +	gin = rgb.g;
> +	bin = rgb.b;
> +
> +	rgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);
> +	rgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);
> +	rgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);

Is there any downside to making `rgb = rgb * ccm` or similar work instead
of manual multiplication?


> +
> +#elif defined(APPLY_RGB_PARAMETERS)
> +	/* Apply bayer params */
> +	rgb.r = texture2D(red_param, vec2(rgb.r, 0.5)).r;
> +	rgb.g = texture2D(red_param, vec2(rgb.g, 0.5)).g;

green_param ?

> +	rgb.b = texture2D(red_param, vec2(rgb.b, 0.5)).b;

blue_param ?


Regards,
Barnabás Pőcze


> +#endif
> +
> +    gl_FragColor.rgb = rgb;
>   }
>
Bryan O'Donoghue Sept. 25, 2025, 3:14 p.m. UTC | #2
On 25/09/2025 16:10, Barnabás Pőcze wrote:
> Hi
> 
> 
> 2025. 08. 24. 2:48 keltezéssel, Bryan O'Donoghue írta:
>> Extend out the bayer fragment shaders to take 3 x 256 byte inputs as
>> textures from the CPU.
>>
>> We then use an index to the table to recover the colour-corrected values
>> provided by the SoftIPA thread.
>>
>> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
>> ---
>>    .../internal/shaders/bayer_1x_packed.frag          | 56 +++++++++++++++++++
>>    include/libcamera/internal/shaders/bayer_8.frag    | 62 +++++++++++++++++++++-
>>    2 files changed, 117 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/libcamera/internal/shaders/bayer_1x_packed.frag b/include/libcamera/internal/shaders/bayer_1x_packed.frag
>> index 19b13ad08b3a71e408774dbb8e75ca4e22d9ba8e..90bd645709e02d8cf9bee112b25cbb26c681db0a 100644
>> --- a/include/libcamera/internal/shaders/bayer_1x_packed.frag
>> +++ b/include/libcamera/internal/shaders/bayer_1x_packed.frag
>> @@ -65,6 +65,10 @@ uniform vec2 tex_step;
>>    uniform vec2 tex_bayer_first_red;
>>
>>    uniform sampler2D tex_y;
>> +uniform sampler2D red_param;
>> +uniform sampler2D green_param;
>> +uniform sampler2D blue_param;
>> +uniform mat3 ccm;
>>
>>    void main(void)
>>    {
>> @@ -212,5 +216,57 @@ void main(void)
>>    			vec3(patterns.y, C, patterns.x) :
>>    			vec3(patterns.wz, C));
>>
>> +#if defined(APPLY_CCM_PARAMETERS)
>> +	/*
>> +	 *   CCM is a 3x3 in the format
>> +	 *
>> +	 *   +--------------+----------------+---------------+
>> +	 *   | RedRedGain   | RedGreenGain   | RedBlueGain   |
>> +	 *   +--------------+----------------+---------------+
>> +	 *   | GreenRedGain | GreenGreenGain | GreenBlueGain |
>> +	 *   +--------------+----------------+---------------+
>> +	 *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |
>> +	 *   +--------------+----------------+---------------+
>> +	 *
>> +	 *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin
>> +	 *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin
>> +	 *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin
>> +	 *
>> +	 *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);
>> +	 *
>> +	 *   CPU
>> +	 *   float ccm [] = {
>> +	 *             RedRedGain,   RedGreenGain,   RedBlueGain,
>> +	 *             GreenRedGain, GreenGreenGain, GreenBlueGain,
>> +	 *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,
>> +	 *   };
>> +	 *
>> +	 *   GPU
>> +	 *   ccm = {
>> +	 *             RedRedGain,   GreenRedGain,   BlueRedGain,
>> +	 *             RedGreenGain, GreenGreenGain, BlueGreenGain,
>> +	 *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,
>> +	 *   }
>> +	 *
>> +	 *   However the indexing for the mat data-type is column major hence
>> +	 *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain
>> +	 *
>> +	 */
>> +	float rin, gin, bin;
>> +	rin = rgb.r;
>> +	gin = rgb.g;
>> +	bin = rgb.b;
>> +
>> +	rgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);
>> +	rgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);
>> +	rgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);
>> +
>> +#elif defined(APPLY_RGB_PARAMETERS)
>> +	/* Apply bayer params */
>> +	rgb.r = texture2D(red_param, vec2(rgb.r, 0.5)).r;
>> +	rgb.g = texture2D(green_param, vec2(rgb.g, 0.5)).g;
>> +	rgb.b = texture2D(blue_param, vec2(rgb.b, 0.5)).b;
>> +#endif
>> +
>>    	gl_FragColor = vec4(rgb, 1.0);
>>    }
>> diff --git a/include/libcamera/internal/shaders/bayer_8.frag b/include/libcamera/internal/shaders/bayer_8.frag
>> index aa7a1b00436ae15d2ed6af7d666441d20db6bb0b..5955c2eafbe03678158b240740e18c7f00e58057 100644
>> --- a/include/libcamera/internal/shaders/bayer_8.frag
>> +++ b/include/libcamera/internal/shaders/bayer_8.frag
>> @@ -21,11 +21,17 @@ precision highp float;
>>
>>    /** Monochrome RGBA or GL_LUMINANCE Bayer encoded texture.*/
>>    uniform sampler2D       tex_y;
>> +uniform sampler2D	red_param;
>> +uniform sampler2D	green_param;
>> +uniform sampler2D	blue_param;
>>    varying vec4            center;
>>    varying vec4            yCoord;
>>    varying vec4            xCoord;
>> +uniform mat3		ccm;
>>
>>    void main(void) {
>> +    vec3 rgb;
>> +
>>        #define fetch(x, y) texture2D(tex_y, vec2(x, y)).r
>>
>>        float C = texture2D(tex_y, center.xy).r; // ( 0, 0)
>> @@ -97,11 +103,65 @@ void main(void) {
>>        PATTERN.xw  += kB.xw * B;
>>        PATTERN.xz  += kF.xz * F;
>>
>> -    gl_FragColor.rgb = (alternate.y == 0.0) ?
>> +    rgb =  (alternate.y == 0.0) ?
>>            ((alternate.x == 0.0) ?
>>                vec3(C, PATTERN.xy) :
>>                vec3(PATTERN.z, C, PATTERN.w)) :
>>            ((alternate.x == 0.0) ?
>>                vec3(PATTERN.w, C, PATTERN.z) :
>>                vec3(PATTERN.yx, C));
>> +
>> +#if defined(APPLY_CCM_PARAMETERS)
>> +	/*
>> +	 *   CCM is a 3x3 in the format
>> +	 *
>> +	 *   +--------------+----------------+---------------+
>> +	 *   | RedRedGain   | RedGreenGain   | RedBlueGain   |
>> +	 *   +--------------+----------------+---------------+
>> +	 *   | GreenRedGain | GreenGreenGain | GreenBlueGain |
>> +	 *   +--------------+----------------+---------------+
>> +	 *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |
>> +	 *   +--------------+----------------+---------------+
>> +	 *
>> +	 *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin
>> +	 *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin
>> +	 *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin
>> +	 *
>> +	 *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);
>> +	 *
>> +	 *   CPU
>> +	 *   float ccm [] = {
>> +	 *             RedRedGain,   RedGreenGain,   RedBlueGain,
>> +	 *             GreenRedGain, GreenGreenGain, GreenBlueGain,
>> +	 *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,
>> +	 *   };
>> +	 *
>> +	 *   GPU
>> +	 *   ccm = {
>> +	 *             RedRedGain,   GreenRedGain,   BlueRedGain,
>> +	 *             RedGreenGain, GreenGreenGain, BlueGreenGain,
>> +	 *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,
>> +	 *   }
>> +	 *
>> +	 *   However the indexing for the mat data-type is column major hence
>> +	 *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain
>> +	 *
>> +	 */
>> +	float rin, gin, bin;
>> +	rin = rgb.r;
>> +	gin = rgb.g;
>> +	bin = rgb.b;
>> +
>> +	rgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);
>> +	rgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);
>> +	rgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);
> 
> Is there any downside to making `rgb = rgb * ccm` or similar work instead
> of manual multiplication?

... No I think that will work just as well.

> 
> 
>> +
>> +#elif defined(APPLY_RGB_PARAMETERS)
>> +	/* Apply bayer params */
>> +	rgb.r = texture2D(red_param, vec2(rgb.r, 0.5)).r;
>> +	rgb.g = texture2D(red_param, vec2(rgb.g, 0.5)).g;
> 
> green_param ?
> 
>> +	rgb.b = texture2D(red_param, vec2(rgb.b, 0.5)).b;
> 
> blue_param ?

Yep already noticed this thx:

https://gitlab.freedesktop.org/camera/libcamera-softisp/-/blob/v0.5.2-gpuisp-v2-a+kbingham-agc/include/libcamera/internal/shaders/bayer_1x_packed.frag?ref_type=heads#L264> 

> 
> Regards,
> Barnabás Pőcze
> 

---
bod
Bryan O'Donoghue Oct. 6, 2025, 9:13 p.m. UTC | #3
On 25/09/2025 16:10, Barnabás Pőcze wrote:
> Hi
> 
> 
> 2025. 08. 24. 2:48 keltezéssel, Bryan O'Donoghue írta:
>> Extend out the bayer fragment shaders to take 3 x 256 byte inputs as
>> textures from the CPU.
>>
>> We then use an index to the table to recover the colour-corrected values
>> provided by the SoftIPA thread.
>>
>> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
>> ---
>>    .../internal/shaders/bayer_1x_packed.frag          | 56 +++++++++++++++++++
>>    include/libcamera/internal/shaders/bayer_8.frag    | 62 +++++++++++++++++++++-
>>    2 files changed, 117 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/libcamera/internal/shaders/bayer_1x_packed.frag b/include/libcamera/internal/shaders/bayer_1x_packed.frag
>> index 19b13ad08b3a71e408774dbb8e75ca4e22d9ba8e..90bd645709e02d8cf9bee112b25cbb26c681db0a 100644
>> --- a/include/libcamera/internal/shaders/bayer_1x_packed.frag
>> +++ b/include/libcamera/internal/shaders/bayer_1x_packed.frag
>> @@ -65,6 +65,10 @@ uniform vec2 tex_step;
>>    uniform vec2 tex_bayer_first_red;
>>
>>    uniform sampler2D tex_y;
>> +uniform sampler2D red_param;
>> +uniform sampler2D green_param;
>> +uniform sampler2D blue_param;
>> +uniform mat3 ccm;
>>
>>    void main(void)
>>    {
>> @@ -212,5 +216,57 @@ void main(void)
>>    			vec3(patterns.y, C, patterns.x) :
>>    			vec3(patterns.wz, C));
>>
>> +#if defined(APPLY_CCM_PARAMETERS)
>> +	/*
>> +	 *   CCM is a 3x3 in the format
>> +	 *
>> +	 *   +--------------+----------------+---------------+
>> +	 *   | RedRedGain   | RedGreenGain   | RedBlueGain   |
>> +	 *   +--------------+----------------+---------------+
>> +	 *   | GreenRedGain | GreenGreenGain | GreenBlueGain |
>> +	 *   +--------------+----------------+---------------+
>> +	 *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |
>> +	 *   +--------------+----------------+---------------+
>> +	 *
>> +	 *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin
>> +	 *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin
>> +	 *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin
>> +	 *
>> +	 *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);
>> +	 *
>> +	 *   CPU
>> +	 *   float ccm [] = {
>> +	 *             RedRedGain,   RedGreenGain,   RedBlueGain,
>> +	 *             GreenRedGain, GreenGreenGain, GreenBlueGain,
>> +	 *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,
>> +	 *   };
>> +	 *
>> +	 *   GPU
>> +	 *   ccm = {
>> +	 *             RedRedGain,   GreenRedGain,   BlueRedGain,
>> +	 *             RedGreenGain, GreenGreenGain, BlueGreenGain,
>> +	 *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,
>> +	 *   }
>> +	 *
>> +	 *   However the indexing for the mat data-type is column major hence
>> +	 *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain
>> +	 *
>> +	 */
>> +	float rin, gin, bin;
>> +	rin = rgb.r;
>> +	gin = rgb.g;
>> +	bin = rgb.b;
>> +
>> +	rgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);
>> +	rgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);
>> +	rgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);
>> +
>> +#elif defined(APPLY_RGB_PARAMETERS)
>> +	/* Apply bayer params */
>> +	rgb.r = texture2D(red_param, vec2(rgb.r, 0.5)).r;
>> +	rgb.g = texture2D(green_param, vec2(rgb.g, 0.5)).g;
>> +	rgb.b = texture2D(blue_param, vec2(rgb.b, 0.5)).b;
>> +#endif
>> +
>>    	gl_FragColor = vec4(rgb, 1.0);
>>    }
>> diff --git a/include/libcamera/internal/shaders/bayer_8.frag b/include/libcamera/internal/shaders/bayer_8.frag
>> index aa7a1b00436ae15d2ed6af7d666441d20db6bb0b..5955c2eafbe03678158b240740e18c7f00e58057 100644
>> --- a/include/libcamera/internal/shaders/bayer_8.frag
>> +++ b/include/libcamera/internal/shaders/bayer_8.frag
>> @@ -21,11 +21,17 @@ precision highp float;
>>
>>    /** Monochrome RGBA or GL_LUMINANCE Bayer encoded texture.*/
>>    uniform sampler2D       tex_y;
>> +uniform sampler2D	red_param;
>> +uniform sampler2D	green_param;
>> +uniform sampler2D	blue_param;
>>    varying vec4            center;
>>    varying vec4            yCoord;
>>    varying vec4            xCoord;
>> +uniform mat3		ccm;
>>
>>    void main(void) {
>> +    vec3 rgb;
>> +
>>        #define fetch(x, y) texture2D(tex_y, vec2(x, y)).r
>>
>>        float C = texture2D(tex_y, center.xy).r; // ( 0, 0)
>> @@ -97,11 +103,65 @@ void main(void) {
>>        PATTERN.xw  += kB.xw * B;
>>        PATTERN.xz  += kF.xz * F;
>>
>> -    gl_FragColor.rgb = (alternate.y == 0.0) ?
>> +    rgb =  (alternate.y == 0.0) ?
>>            ((alternate.x == 0.0) ?
>>                vec3(C, PATTERN.xy) :
>>                vec3(PATTERN.z, C, PATTERN.w)) :
>>            ((alternate.x == 0.0) ?
>>                vec3(PATTERN.w, C, PATTERN.z) :
>>                vec3(PATTERN.yx, C));
>> +
>> +#if defined(APPLY_CCM_PARAMETERS)
>> +	/*
>> +	 *   CCM is a 3x3 in the format
>> +	 *
>> +	 *   +--------------+----------------+---------------+
>> +	 *   | RedRedGain   | RedGreenGain   | RedBlueGain   |
>> +	 *   +--------------+----------------+---------------+
>> +	 *   | GreenRedGain | GreenGreenGain | GreenBlueGain |
>> +	 *   +--------------+----------------+---------------+
>> +	 *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |
>> +	 *   +--------------+----------------+---------------+
>> +	 *
>> +	 *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin
>> +	 *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin
>> +	 *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin
>> +	 *
>> +	 *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);
>> +	 *
>> +	 *   CPU
>> +	 *   float ccm [] = {
>> +	 *             RedRedGain,   RedGreenGain,   RedBlueGain,
>> +	 *             GreenRedGain, GreenGreenGain, GreenBlueGain,
>> +	 *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,
>> +	 *   };
>> +	 *
>> +	 *   GPU
>> +	 *   ccm = {
>> +	 *             RedRedGain,   GreenRedGain,   BlueRedGain,
>> +	 *             RedGreenGain, GreenGreenGain, BlueGreenGain,
>> +	 *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,
>> +	 *   }
>> +	 *
>> +	 *   However the indexing for the mat data-type is column major hence
>> +	 *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain
>> +	 *
>> +	 */
>> +	float rin, gin, bin;
>> +	rin = rgb.r;
>> +	gin = rgb.g;
>> +	bin = rgb.b;
>> +
>> +	rgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);
>> +	rgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);
>> +	rgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);
> 
> Is there any downside to making `rgb = rgb * ccm` or similar work instead
> of manual multiplication?

I didn't do this because the code is I think easier to understand this 
way without loosing any performance.

>> +
>> +#elif defined(APPLY_RGB_PARAMETERS)
>> +	/* Apply bayer params */
>> +	rgb.r = texture2D(red_param, vec2(rgb.r, 0.5)).r;
>> +	rgb.g = texture2D(red_param, vec2(rgb.g, 0.5)).g;
> 
> green_param ?
> 
>> +	rgb.b = texture2D(red_param, vec2(rgb.b, 0.5)).b;
> 
> blue_param ?

I very much did this though :)

---
bod
Barnabás Pőcze Oct. 7, 2025, 11:23 a.m. UTC | #4
2025. 10. 06. 23:13 keltezéssel, Bryan O'Donoghue írta:
> On 25/09/2025 16:10, Barnabás Pőcze wrote:
>> Hi
>>
>>
>> 2025. 08. 24. 2:48 keltezéssel, Bryan O'Donoghue írta:
>>> Extend out the bayer fragment shaders to take 3 x 256 byte inputs as
>>> textures from the CPU.
>>>
>>> We then use an index to the table to recover the colour-corrected values
>>> provided by the SoftIPA thread.
>>>
>>> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
>>> ---
>>>     .../internal/shaders/bayer_1x_packed.frag          | 56 +++++++++++++++++++
>>>     include/libcamera/internal/shaders/bayer_8.frag    | 62 +++++++++++++++++++++-
>>>     2 files changed, 117 insertions(+), 1 deletion(-)
>>>
> [...]
>>> diff --git a/include/libcamera/internal/shaders/bayer_8.frag b/include/libcamera/internal/shaders/bayer_8.frag
>>> index aa7a1b00436ae15d2ed6af7d666441d20db6bb0b..5955c2eafbe03678158b240740e18c7f00e58057 100644
>>> --- a/include/libcamera/internal/shaders/bayer_8.frag
>>> +++ b/include/libcamera/internal/shaders/bayer_8.frag
>>> @@ -21,11 +21,17 @@ precision highp float;
>>>
>>>     /** Monochrome RGBA or GL_LUMINANCE Bayer encoded texture.*/
>>>     uniform sampler2D       tex_y;
>>> +uniform sampler2D	red_param;
>>> +uniform sampler2D	green_param;
>>> +uniform sampler2D	blue_param;
>>>     varying vec4            center;
>>>     varying vec4            yCoord;
>>>     varying vec4            xCoord;
>>> +uniform mat3		ccm;
>>>
>>>     void main(void) {
>>> +    vec3 rgb;
>>> +
>>>         #define fetch(x, y) texture2D(tex_y, vec2(x, y)).r
>>>
>>>         float C = texture2D(tex_y, center.xy).r; // ( 0, 0)
>>> @@ -97,11 +103,65 @@ void main(void) {
>>>         PATTERN.xw  += kB.xw * B;
>>>         PATTERN.xz  += kF.xz * F;
>>>
>>> -    gl_FragColor.rgb = (alternate.y == 0.0) ?
>>> +    rgb =  (alternate.y == 0.0) ?
>>>             ((alternate.x == 0.0) ?
>>>                 vec3(C, PATTERN.xy) :
>>>                 vec3(PATTERN.z, C, PATTERN.w)) :
>>>             ((alternate.x == 0.0) ?
>>>                 vec3(PATTERN.w, C, PATTERN.z) :
>>>                 vec3(PATTERN.yx, C));
>>> +
>>> +#if defined(APPLY_CCM_PARAMETERS)
>>> +	/*
>>> +	 *   CCM is a 3x3 in the format
>>> +	 *
>>> +	 *   +--------------+----------------+---------------+
>>> +	 *   | RedRedGain   | RedGreenGain   | RedBlueGain   |
>>> +	 *   +--------------+----------------+---------------+
>>> +	 *   | GreenRedGain | GreenGreenGain | GreenBlueGain |
>>> +	 *   +--------------+----------------+---------------+
>>> +	 *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |
>>> +	 *   +--------------+----------------+---------------+
>>> +	 *
>>> +	 *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin
>>> +	 *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin
>>> +	 *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin
>>> +	 *
>>> +	 *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);
>>> +	 *
>>> +	 *   CPU
>>> +	 *   float ccm [] = {
>>> +	 *             RedRedGain,   RedGreenGain,   RedBlueGain,
>>> +	 *             GreenRedGain, GreenGreenGain, GreenBlueGain,
>>> +	 *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,
>>> +	 *   };
>>> +	 *
>>> +	 *   GPU
>>> +	 *   ccm = {
>>> +	 *             RedRedGain,   GreenRedGain,   BlueRedGain,
>>> +	 *             RedGreenGain, GreenGreenGain, BlueGreenGain,
>>> +	 *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,
>>> +	 *   }
>>> +	 *
>>> +	 *   However the indexing for the mat data-type is column major hence
>>> +	 *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain
>>> +	 *
>>> +	 */
>>> +	float rin, gin, bin;
>>> +	rin = rgb.r;
>>> +	gin = rgb.g;
>>> +	bin = rgb.b;
>>> +
>>> +	rgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);
>>> +	rgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);
>>> +	rgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);
>>
>> Is there any downside to making `rgb = rgb * ccm` or similar work instead
>> of manual multiplication?
> 
> I didn't do this because the code is I think easier to understand this
> way without loosing any performance.

I see, in my mind there wasn't any doubt that `rgb * ccm` is easier
to read, well, at least to me.


Regards,
Barnabás Pőcze

> 
>>> +
>>> +#elif defined(APPLY_RGB_PARAMETERS)
>>> +	/* Apply bayer params */
>>> +	rgb.r = texture2D(red_param, vec2(rgb.r, 0.5)).r;
>>> +	rgb.g = texture2D(red_param, vec2(rgb.g, 0.5)).g;
>>
>> green_param ?
>>
>>> +	rgb.b = texture2D(red_param, vec2(rgb.b, 0.5)).b;
>>
>> blue_param ?
> 
> I very much did this though :)
> 
> ---
> bod
>

Patch
diff mbox series

diff --git a/include/libcamera/internal/shaders/bayer_1x_packed.frag b/include/libcamera/internal/shaders/bayer_1x_packed.frag
index 19b13ad08b3a71e408774dbb8e75ca4e22d9ba8e..90bd645709e02d8cf9bee112b25cbb26c681db0a 100644
--- a/include/libcamera/internal/shaders/bayer_1x_packed.frag
+++ b/include/libcamera/internal/shaders/bayer_1x_packed.frag
@@ -65,6 +65,10 @@  uniform vec2 tex_step;
 uniform vec2 tex_bayer_first_red;
 
 uniform sampler2D tex_y;
+uniform sampler2D red_param;
+uniform sampler2D green_param;
+uniform sampler2D blue_param;
+uniform mat3 ccm;
 
 void main(void)
 {
@@ -212,5 +216,57 @@  void main(void)
 			vec3(patterns.y, C, patterns.x) :
 			vec3(patterns.wz, C));
 
+#if defined(APPLY_CCM_PARAMETERS)
+	/*
+	 *   CCM is a 3x3 in the format
+	 *
+	 *   +--------------+----------------+---------------+
+	 *   | RedRedGain   | RedGreenGain   | RedBlueGain   |
+	 *   +--------------+----------------+---------------+
+	 *   | GreenRedGain | GreenGreenGain | GreenBlueGain |
+	 *   +--------------+----------------+---------------+
+	 *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |
+	 *   +--------------+----------------+---------------+
+	 *
+	 *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin
+	 *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin
+	 *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin
+	 *
+	 *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);
+	 *
+	 *   CPU
+	 *   float ccm [] = {
+	 *             RedRedGain,   RedGreenGain,   RedBlueGain,
+	 *             GreenRedGain, GreenGreenGain, GreenBlueGain,
+	 *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,
+	 *   };
+	 *
+	 *   GPU
+	 *   ccm = {
+	 *             RedRedGain,   GreenRedGain,   BlueRedGain,
+	 *             RedGreenGain, GreenGreenGain, BlueGreenGain,
+	 *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,
+	 *   }
+	 *
+	 *   However the indexing for the mat data-type is column major hence
+	 *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain
+	 *
+	 */
+	float rin, gin, bin;
+	rin = rgb.r;
+	gin = rgb.g;
+	bin = rgb.b;
+
+	rgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);
+	rgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);
+	rgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);
+
+#elif defined(APPLY_RGB_PARAMETERS)
+	/* Apply bayer params */
+	rgb.r = texture2D(red_param, vec2(rgb.r, 0.5)).r;
+	rgb.g = texture2D(green_param, vec2(rgb.g, 0.5)).g;
+	rgb.b = texture2D(blue_param, vec2(rgb.b, 0.5)).b;
+#endif
+
 	gl_FragColor = vec4(rgb, 1.0);
 }
diff --git a/include/libcamera/internal/shaders/bayer_8.frag b/include/libcamera/internal/shaders/bayer_8.frag
index aa7a1b00436ae15d2ed6af7d666441d20db6bb0b..5955c2eafbe03678158b240740e18c7f00e58057 100644
--- a/include/libcamera/internal/shaders/bayer_8.frag
+++ b/include/libcamera/internal/shaders/bayer_8.frag
@@ -21,11 +21,17 @@  precision highp float;
 
 /** Monochrome RGBA or GL_LUMINANCE Bayer encoded texture.*/
 uniform sampler2D       tex_y;
+uniform sampler2D	red_param;
+uniform sampler2D	green_param;
+uniform sampler2D	blue_param;
 varying vec4            center;
 varying vec4            yCoord;
 varying vec4            xCoord;
+uniform mat3		ccm;
 
 void main(void) {
+    vec3 rgb;
+
     #define fetch(x, y) texture2D(tex_y, vec2(x, y)).r
 
     float C = texture2D(tex_y, center.xy).r; // ( 0, 0)
@@ -97,11 +103,65 @@  void main(void) {
     PATTERN.xw  += kB.xw * B;
     PATTERN.xz  += kF.xz * F;
 
-    gl_FragColor.rgb = (alternate.y == 0.0) ?
+    rgb =  (alternate.y == 0.0) ?
         ((alternate.x == 0.0) ?
             vec3(C, PATTERN.xy) :
             vec3(PATTERN.z, C, PATTERN.w)) :
         ((alternate.x == 0.0) ?
             vec3(PATTERN.w, C, PATTERN.z) :
             vec3(PATTERN.yx, C));
+
+#if defined(APPLY_CCM_PARAMETERS)
+	/*
+	 *   CCM is a 3x3 in the format
+	 *
+	 *   +--------------+----------------+---------------+
+	 *   | RedRedGain   | RedGreenGain   | RedBlueGain   |
+	 *   +--------------+----------------+---------------+
+	 *   | GreenRedGain | GreenGreenGain | GreenBlueGain |
+	 *   +--------------+----------------+---------------+
+	 *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |
+	 *   +--------------+----------------+---------------+
+	 *
+	 *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin
+	 *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin
+	 *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin
+	 *
+	 *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);
+	 *
+	 *   CPU
+	 *   float ccm [] = {
+	 *             RedRedGain,   RedGreenGain,   RedBlueGain,
+	 *             GreenRedGain, GreenGreenGain, GreenBlueGain,
+	 *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,
+	 *   };
+	 *
+	 *   GPU
+	 *   ccm = {
+	 *             RedRedGain,   GreenRedGain,   BlueRedGain,
+	 *             RedGreenGain, GreenGreenGain, BlueGreenGain,
+	 *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,
+	 *   }
+	 *
+	 *   However the indexing for the mat data-type is column major hence
+	 *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain
+	 *
+	 */
+	float rin, gin, bin;
+	rin = rgb.r;
+	gin = rgb.g;
+	bin = rgb.b;
+
+	rgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);
+	rgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);
+	rgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);
+
+#elif defined(APPLY_RGB_PARAMETERS)
+	/* Apply bayer params */
+	rgb.r = texture2D(red_param, vec2(rgb.r, 0.5)).r;
+	rgb.g = texture2D(red_param, vec2(rgb.g, 0.5)).g;
+	rgb.b = texture2D(red_param, vec2(rgb.b, 0.5)).b;
+#endif
+
+    gl_FragColor.rgb = rgb;
 }