[v6,10/24] libcamera: shaders: Add support for contrast
diff mbox series

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

Commit Message

Bryan O'Donoghue Dec. 2, 2025, 1:45 p.m. UTC
Apply contrast after black-level and CCM operations.

Suggested-by: Milan Zamazal <mzamazal@redhat.com>
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 src/libcamera/shaders/bayer_1x_packed.frag | 19 +++++++++++++++++++
 src/libcamera/shaders/bayer_unpacked.frag  | 19 +++++++++++++++++++
 2 files changed, 38 insertions(+)

Comments

Milan Zamazal Dec. 3, 2025, 7:07 p.m. UTC | #1
Bryan O'Donoghue <bryan.odonoghue@linaro.org> writes:

> Apply contrast after black-level and CCM operations.
>
> Suggested-by: Milan Zamazal <mzamazal@redhat.com>
> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> ---
>  src/libcamera/shaders/bayer_1x_packed.frag | 19 +++++++++++++++++++
>  src/libcamera/shaders/bayer_unpacked.frag  | 19 +++++++++++++++++++
>  2 files changed, 38 insertions(+)
>
> diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag
> index 77d9fbfa7..2fc9952e2 100644
> --- a/src/libcamera/shaders/bayer_1x_packed.frag
> +++ b/src/libcamera/shaders/bayer_1x_packed.frag
> @@ -68,6 +68,19 @@ uniform sampler2D tex_y;
>  uniform mat3 ccm;
>  uniform vec3 blacklevel;
>  uniform float gamma;
> +uniform float contrast;
> +
> +float apply_contrast(float normalise, float contrast_in)

The argument names look somewhat confusing.  How about simply

  float apply_contrast(float value, float contrast)

?

(The same for the unpacked shader.)

> +{
> +	// Convert 0..2 contrast to 0..infinity; avoid actual infinity at tan(pi/2)
> +	float contrastExp = tan(clamp(contrast_in * 0.78539816339744830962, 0.0, 1.5707963267948966 - 0.00001));

This is computed 3 times per each pixel, while the value can be computed
just once per the whole image.  It doesn't seem to have an obvious
impact on performance, but still...

(The same for the unpacked shader.)

> +
> +	// Apply simple S-curve
> +	if (normalise < 0.5)
> +		return 0.5 * pow(normalise / 0.5, contrastExp);
> +	else
> +		return 1.0 - 0.5 * pow((1.0 - normalise) / 0.5, contrastExp);
> +}
>  
>  void main(void)
>  {
> @@ -261,6 +274,12 @@ void main(void)
>  	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]);
>  
> +	/* Contrast */

It would be nice to use either "/* ... */" or "// ..." single line
comments consistently.

> +	rgb = clamp(rgb, 0.0, 1.0);
> +	rgb.r = apply_contrast(rgb.r, contrast);
> +	rgb.g = apply_contrast(rgb.g, contrast);
> +	rgb.b = apply_contrast(rgb.b, contrast);
> +
>  	/* Apply gamma after colour correction */
>  	rgb = pow(rgb, vec3(gamma));
>  
> diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag
> index aba11a87f..caa0ba15d 100644
> --- a/src/libcamera/shaders/bayer_unpacked.frag
> +++ b/src/libcamera/shaders/bayer_unpacked.frag
> @@ -27,6 +27,19 @@ varying vec4            xCoord;
>  uniform mat3            ccm;
>  uniform vec3            blacklevel;
>  uniform float           gamma;
> +uniform float           contrast;
> +
> +float apply_contrast(float normalise, float contrast_in)
> +{
> +    // Convert 0..2 contrast to 0..infinity; avoid actual infinity at tan(pi/2)
> +    float contrastExp = tan(clamp(contrast_in * 0.78539816339744830962, 0.0, 1.5707963267948966 - 0.00001));
> +
> +    // Apply simple S-curve
> +    if (normalise < 0.5)
> +        return 0.5 * pow(normalise / 0.5, contrastExp);
> +    else
> +        return 1.0 - 0.5 * pow((1.0 - normalise) / 0.5, contrastExp);
> +}
>  
>  void main(void) {
>      vec3 rgb;
> @@ -156,6 +169,12 @@ void main(void) {
>      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]);
>  
> +    /* Contrast */
> +    rgb = clamp(rgb, 0.0, 1.0);
> +    rgb.r = apply_contrast(rgb.r, contrast);
> +    rgb.g = apply_contrast(rgb.g, contrast);
> +    rgb.b = apply_contrast(rgb.b, contrast);
> +
>      /* Apply gamma after colour correction */
>      rgb = pow(rgb, vec3(gamma));

Patch
diff mbox series

diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag
index 77d9fbfa7..2fc9952e2 100644
--- a/src/libcamera/shaders/bayer_1x_packed.frag
+++ b/src/libcamera/shaders/bayer_1x_packed.frag
@@ -68,6 +68,19 @@  uniform sampler2D tex_y;
 uniform mat3 ccm;
 uniform vec3 blacklevel;
 uniform float gamma;
+uniform float contrast;
+
+float apply_contrast(float normalise, float contrast_in)
+{
+	// Convert 0..2 contrast to 0..infinity; avoid actual infinity at tan(pi/2)
+	float contrastExp = tan(clamp(contrast_in * 0.78539816339744830962, 0.0, 1.5707963267948966 - 0.00001));
+
+	// Apply simple S-curve
+	if (normalise < 0.5)
+		return 0.5 * pow(normalise / 0.5, contrastExp);
+	else
+		return 1.0 - 0.5 * pow((1.0 - normalise) / 0.5, contrastExp);
+}
 
 void main(void)
 {
@@ -261,6 +274,12 @@  void main(void)
 	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]);
 
+	/* Contrast */
+	rgb = clamp(rgb, 0.0, 1.0);
+	rgb.r = apply_contrast(rgb.r, contrast);
+	rgb.g = apply_contrast(rgb.g, contrast);
+	rgb.b = apply_contrast(rgb.b, contrast);
+
 	/* Apply gamma after colour correction */
 	rgb = pow(rgb, vec3(gamma));
 
diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag
index aba11a87f..caa0ba15d 100644
--- a/src/libcamera/shaders/bayer_unpacked.frag
+++ b/src/libcamera/shaders/bayer_unpacked.frag
@@ -27,6 +27,19 @@  varying vec4            xCoord;
 uniform mat3            ccm;
 uniform vec3            blacklevel;
 uniform float           gamma;
+uniform float           contrast;
+
+float apply_contrast(float normalise, float contrast_in)
+{
+    // Convert 0..2 contrast to 0..infinity; avoid actual infinity at tan(pi/2)
+    float contrastExp = tan(clamp(contrast_in * 0.78539816339744830962, 0.0, 1.5707963267948966 - 0.00001));
+
+    // Apply simple S-curve
+    if (normalise < 0.5)
+        return 0.5 * pow(normalise / 0.5, contrastExp);
+    else
+        return 1.0 - 0.5 * pow((1.0 - normalise) / 0.5, contrastExp);
+}
 
 void main(void) {
     vec3 rgb;
@@ -156,6 +169,12 @@  void main(void) {
     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]);
 
+    /* Contrast */
+    rgb = clamp(rgb, 0.0, 1.0);
+    rgb.r = apply_contrast(rgb.r, contrast);
+    rgb.g = apply_contrast(rgb.g, contrast);
+    rgb.b = apply_contrast(rgb.b, contrast);
+
     /* Apply gamma after colour correction */
     rgb = pow(rgb, vec3(gamma));