[5/7] libcamera: software_isp: debayer_egl: Add LSC support
diff mbox series

Message ID 20260126104256.119697-6-rick.w.ten.wolde@gmail.com
State New
Headers show
Series
  • LSC for SoftISP simple pipeline
Related show

Commit Message

Rick ten Wolde Jan. 26, 2026, 10:42 a.m. UTC
From: Xander Pronk <xander.c.pronk@gmail.com>

Add support for passing the LSC tables from debayerParams to
the shaders.

Co-authored-by: Rick ten Wolde <rick_libcamera@wolde.info>
Signed-off-by: Rick ten Wolde <rick_libcamera@wolde.info>
Signed-off-by: Xander Pronk <xander.c.pronk@gmail.com>
---
 src/libcamera/software_isp/debayer_egl.cpp | 21 +++++++++++++++++++++
 src/libcamera/software_isp/debayer_egl.h   |  9 +++++++++
 2 files changed, 30 insertions(+)

Comments

Barnabás Pőcze Jan. 26, 2026, 11:30 a.m. UTC | #1
Hi

2026. 01. 26. 11:42 keltezéssel, Rick ten Wolde írta:
> From: Xander Pronk <xander.c.pronk@gmail.com>
> 
> Add support for passing the LSC tables from debayerParams to
> the shaders.
> 
> Co-authored-by: Rick ten Wolde <rick_libcamera@wolde.info>
> Signed-off-by: Rick ten Wolde <rick_libcamera@wolde.info>
> Signed-off-by: Xander Pronk <xander.c.pronk@gmail.com>
> ---
>   src/libcamera/software_isp/debayer_egl.cpp | 21 +++++++++++++++++++++
>   src/libcamera/software_isp/debayer_egl.h   |  9 +++++++++
>   2 files changed, 30 insertions(+)
> 
> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
> index 8e089032..0f36b149 100644
> --- a/src/libcamera/software_isp/debayer_egl.cpp
> +++ b/src/libcamera/software_isp/debayer_egl.cpp
> @@ -111,6 +111,10 @@ int DebayerEGL::getShaderVariableLocations(void)
>   	textureUniformBayerFirstRed_ = glGetUniformLocation(programId_, "tex_bayer_first_red");
>   	textureUniformProjMatrix_ = glGetUniformLocation(programId_, "proj_matrix");
>   
> +	textureUniformLSCRed_ = glGetUniformLocation(programId_, "lsc_tex_red");
> +	textureUniformLSCGreen_ = glGetUniformLocation(programId_, "lsc_tex_green");
> +	textureUniformLSCBlue_ = glGetUniformLocation(programId_, "lsc_tex_blue");
> +
>   	LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_
>   			    << " tex_y " << textureUniformBayerDataIn_
>   			    << " ccm " << ccmUniformDataIn_
> @@ -140,6 +144,9 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm
>   	/* Specify GL_OES_EGL_image_external */
>   	egl_.pushEnv(shaderEnv, "#extension GL_OES_EGL_image_external: enable");
>   
> +	/* Always use LSC */
> +	egl_.pushEnv(shaderEnv, "#define DO_LSC");
> +
>   	/*
>   	 * Tell shaders how to re-order output taking account of how the
>   	 * pixels are actually stored by GBM
> @@ -349,6 +356,12 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg,
>   	 */
>   	stats_->setWindow(Rectangle(window_.size()));
>   
> +	eglImageLSCLookupRed_ = new eGLImage(20, 20, sizeof(GLubyte), GL_TEXTURE5, 5);
> +	eglImageLSCLookupGreen_ = new eGLImage(20, 20, sizeof(GLubyte), GL_TEXTURE5, 5);
> +	eglImageLSCLookupBlue_ = new eGLImage(20, 20, sizeof(GLubyte), GL_TEXTURE5, 5);
> +	if (!eglImageLSCLookupRed_ || !eglImageLSCLookupGreen_ || !eglImageLSCLookupBlue_)

These operator new calls never return nullptr. But see below.


> +		return -ENOMEM;
> +
>   	return 0;
>   }
>   
> @@ -488,6 +501,14 @@ void DebayerEGL::setShaderVariableValues(DebayerParams &params)
>   	glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);
>   	LOG(Debayer, Debug) << " ccmUniformDataIn_ " << ccmUniformDataIn_ << " data " << params.ccm;
>   
> +	egl_.createTexture2D(*eglImageLSCLookupRed_, GL_LUMINANCE, 16, 16, &params.LSC_red, GL_LINEAR);
> +	egl_.createTexture2D(*eglImageLSCLookupBlue_, GL_LUMINANCE, 16, 16, &params.LSC_green, GL_LINEAR);
> +	egl_.createTexture2D(*eglImageLSCLookupGreen_, GL_LUMINANCE, 16, 16, &params.LSC_blue, GL_LINEAR);
> +
> +	glUniform1i(textureUniformLSCRed_, eglImageLSCLookupRed_->texture_unit_uniform_id_);
> +	glUniform1i(textureUniformLSCGreen_, eglImageLSCLookupGreen_->texture_unit_uniform_id_);
> +	glUniform1i(textureUniformLSCBlue_, eglImageLSCLookupBlue_->texture_unit_uniform_id_);
> +
>   	/*
>   	 * 0 = Red, 1 = Green, 2 = Blue
>   	 */
> diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
> index a5033bc6..61feadab 100644
> --- a/src/libcamera/software_isp/debayer_egl.h
> +++ b/src/libcamera/software_isp/debayer_egl.h
> @@ -85,6 +85,11 @@ private:
>   	std::unique_ptr<eGLImage> eglImageBayerIn_;
>   	std::unique_ptr<eGLImage> eglImageBayerOut_;
>   
> +	/* Pointer to object representing input texture */
> +	eGLImage *eglImageLSCLookupRed_;
> +	eGLImage *eglImageLSCLookupBlue_;
> +	eGLImage *eglImageLSCLookupGreen_;

These need to become `std::optional<eGLImage>` or `std::unique_ptr<>` at least.
Please no raw owning raw pointers.


Regards,
Barnabás Pőcze


> +
>   	/* Shader parameters */
>   	float firstRed_x_;
>   	float firstRed_y_;
> @@ -98,6 +103,10 @@ private:
>   
>   	GLint textureUniformBayerDataIn_;
>   
> +	GLint textureUniformLSCRed_;
> +	GLint textureUniformLSCGreen_;
> +	GLint textureUniformLSCBlue_;
> +
>   	/* Represent per-frame CCM as a uniform vector of floats 3 x 3 */
>   	GLint ccmUniformDataIn_;
>
Milan Zamazal Jan. 26, 2026, 3:28 p.m. UTC | #2
Hi,

thank you for the patches.

Rick ten Wolde <rick.w.ten.wolde@gmail.com> writes:

> From: Xander Pronk <xander.c.pronk@gmail.com>
>
> Add support for passing the LSC tables from debayerParams to
> the shaders.
>
> Co-authored-by: Rick ten Wolde <rick_libcamera@wolde.info>
> Signed-off-by: Rick ten Wolde <rick_libcamera@wolde.info>
> Signed-off-by: Xander Pronk <xander.c.pronk@gmail.com>
> ---
>  src/libcamera/software_isp/debayer_egl.cpp | 21 +++++++++++++++++++++
>  src/libcamera/software_isp/debayer_egl.h   |  9 +++++++++
>  2 files changed, 30 insertions(+)
>
> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
> index 8e089032..0f36b149 100644
> --- a/src/libcamera/software_isp/debayer_egl.cpp
> +++ b/src/libcamera/software_isp/debayer_egl.cpp
> @@ -111,6 +111,10 @@ int DebayerEGL::getShaderVariableLocations(void)
>  	textureUniformBayerFirstRed_ = glGetUniformLocation(programId_, "tex_bayer_first_red");
>  	textureUniformProjMatrix_ = glGetUniformLocation(programId_, "proj_matrix");
>  
> +	textureUniformLSCRed_ = glGetUniformLocation(programId_, "lsc_tex_red");
> +	textureUniformLSCGreen_ = glGetUniformLocation(programId_, "lsc_tex_green");
> +	textureUniformLSCBlue_ = glGetUniformLocation(programId_, "lsc_tex_blue");
> +
>  	LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_
>  			    << " tex_y " << textureUniformBayerDataIn_
>  			    << " ccm " << ccmUniformDataIn_
> @@ -140,6 +144,9 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm
>  	/* Specify GL_OES_EGL_image_external */
>  	egl_.pushEnv(shaderEnv, "#extension GL_OES_EGL_image_external: enable");
>  
> +	/* Always use LSC */
> +	egl_.pushEnv(shaderEnv, "#define DO_LSC");

I think this should be conditional.  For example, what if LSC algorithm
is disabled?  Or LSC parameters are not available in the tuning file?

> +
>  	/*
>  	 * Tell shaders how to re-order output taking account of how the
>  	 * pixels are actually stored by GBM
> @@ -349,6 +356,12 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg,
>  	 */
>  	stats_->setWindow(Rectangle(window_.size()));
>  
> +	eglImageLSCLookupRed_ = new eGLImage(20, 20, sizeof(GLubyte), GL_TEXTURE5, 5);
> +	eglImageLSCLookupGreen_ = new eGLImage(20, 20, sizeof(GLubyte), GL_TEXTURE5, 5);
> +	eglImageLSCLookupBlue_ = new eGLImage(20, 20, sizeof(GLubyte), GL_TEXTURE5, 5);
> +	if (!eglImageLSCLookupRed_ || !eglImageLSCLookupGreen_ || !eglImageLSCLookupBlue_)
> +		return -ENOMEM;
> +
>  	return 0;
>  }
>  
> @@ -488,6 +501,14 @@ void DebayerEGL::setShaderVariableValues(DebayerParams &params)
>  	glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);
>  	LOG(Debayer, Debug) << " ccmUniformDataIn_ " << ccmUniformDataIn_ << " data " << params.ccm;
>  
> +	egl_.createTexture2D(*eglImageLSCLookupRed_, GL_LUMINANCE, 16, 16, &params.LSC_red, GL_LINEAR);
> +	egl_.createTexture2D(*eglImageLSCLookupBlue_, GL_LUMINANCE, 16, 16, &params.LSC_green, GL_LINEAR);
> +	egl_.createTexture2D(*eglImageLSCLookupGreen_, GL_LUMINANCE, 16, 16, &params.LSC_blue, GL_LINEAR);
> +
> +	glUniform1i(textureUniformLSCRed_, eglImageLSCLookupRed_->texture_unit_uniform_id_);
> +	glUniform1i(textureUniformLSCGreen_, eglImageLSCLookupGreen_->texture_unit_uniform_id_);
> +	glUniform1i(textureUniformLSCBlue_, eglImageLSCLookupBlue_->texture_unit_uniform_id_);
> +
>  	/*
>  	 * 0 = Red, 1 = Green, 2 = Blue
>  	 */
> diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
> index a5033bc6..61feadab 100644
> --- a/src/libcamera/software_isp/debayer_egl.h
> +++ b/src/libcamera/software_isp/debayer_egl.h
> @@ -85,6 +85,11 @@ private:
>  	std::unique_ptr<eGLImage> eglImageBayerIn_;
>  	std::unique_ptr<eGLImage> eglImageBayerOut_;
>  
> +	/* Pointer to object representing input texture */
> +	eGLImage *eglImageLSCLookupRed_;
> +	eGLImage *eglImageLSCLookupBlue_;
> +	eGLImage *eglImageLSCLookupGreen_;
> +
>  	/* Shader parameters */
>  	float firstRed_x_;
>  	float firstRed_y_;
> @@ -98,6 +103,10 @@ private:
>  
>  	GLint textureUniformBayerDataIn_;
>  
> +	GLint textureUniformLSCRed_;
> +	GLint textureUniformLSCGreen_;
> +	GLint textureUniformLSCBlue_;
> +
>  	/* Represent per-frame CCM as a uniform vector of floats 3 x 3 */
>  	GLint ccmUniformDataIn_;
Bryan O'Donoghue Feb. 4, 2026, 3:23 p.m. UTC | #3
On 26/01/2026 10:42, Rick ten Wolde wrote:
> From: Xander Pronk <xander.c.pronk@gmail.com>
> 
> Add support for passing the LSC tables from debayerParams to
> the shaders.
> 
> Co-authored-by: Rick ten Wolde <rick_libcamera@wolde.info>
> Signed-off-by: Rick ten Wolde <rick_libcamera@wolde.info>
> Signed-off-by: Xander Pronk <xander.c.pronk@gmail.com>
> ---
>   src/libcamera/software_isp/debayer_egl.cpp | 21 +++++++++++++++++++++
>   src/libcamera/software_isp/debayer_egl.h   |  9 +++++++++
>   2 files changed, 30 insertions(+)
> 
> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
> index 8e089032..0f36b149 100644
> --- a/src/libcamera/software_isp/debayer_egl.cpp
> +++ b/src/libcamera/software_isp/debayer_egl.cpp
> @@ -111,6 +111,10 @@ int DebayerEGL::getShaderVariableLocations(void)
>   	textureUniformBayerFirstRed_ = glGetUniformLocation(programId_, "tex_bayer_first_red");
>   	textureUniformProjMatrix_ = glGetUniformLocation(programId_, "proj_matrix");
> 
> +	textureUniformLSCRed_ = glGetUniformLocation(programId_, "lsc_tex_red");
> +	textureUniformLSCGreen_ = glGetUniformLocation(programId_, "lsc_tex_green");
> +	textureUniformLSCBlue_ = glGetUniformLocation(programId_, "lsc_tex_blue");
> +
>   	LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_
>   			    << " tex_y " << textureUniformBayerDataIn_
>   			    << " ccm " << ccmUniformDataIn_
> @@ -140,6 +144,9 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm
>   	/* Specify GL_OES_EGL_image_external */
>   	egl_.pushEnv(shaderEnv, "#extension GL_OES_EGL_image_external: enable");
> 
> +	/* Always use LSC */
> +	egl_.pushEnv(shaderEnv, "#define DO_LSC");
> +

If you are always doing LSC there's not much point in having it 
controlled by define.

You also need to update qcam -> src/apps/qcam/viewfinder_gl.cpp

What happens if I don't have LSC data though ?

>   	/*
>   	 * Tell shaders how to re-order output taking account of how the
>   	 * pixels are actually stored by GBM
> @@ -349,6 +356,12 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg,
>   	 */
>   	stats_->setWindow(Rectangle(window_.size()));
> 
> +	eglImageLSCLookupRed_ = new eGLImage(20, 20, sizeof(GLubyte), GL_TEXTURE5, 5);
> +	eglImageLSCLookupGreen_ = new eGLImage(20, 20, sizeof(GLubyte), GL_TEXTURE5, 5);
> +	eglImageLSCLookupBlue_ = new eGLImage(20, 20, sizeof(GLubyte), GL_TEXTURE5, 5);

I think this should be be GL_TEXTURE2, 2) GL_TEXTURE3, 3) and 
GL_TEXTURE4, 4) respectively.

In the sampler only one texture can be active with one texture unit at 
any one time.

So the only texture you are really using in the fragment shader is the 
last bound shader.

That's why for these tables, we use a different texture unit for each R, 
G and B channel.

https://gitlab.freedesktop.org/camera/libcamera-softisp/-/blob/v0.5.2-gpuisp-v5a/src/libcamera/software_isp/debayer_egl.cpp?ref_type=heads#L394

Prompt Gemini: "can i create multiple textures on the same texture unit"

Ans: "In OpenGL, you can technically bind multiple textures to the same
       texture unit, but only one can be active and usable by a sampler
       at any given time. To use multiple textures in a single shader
       pass, you must bind each texture to a different texture unit
       (e.g., GL_TEXTURE0, GL_TEXTURE1)"

https://www.google.com/search?client=firefox-b-d&q=can+i+create+multiple+textures+on+the+same+texture+unit&zx=1770218257332&no_sw_cr=1#fpstate=ive&vld=cid:763327a7,vid:9cP1w2ykaYc,st:351

> +	if (!eglImageLSCLookupRed_ || !eglImageLSCLookupGreen_ || !eglImageLSCLookupBlue_)
> +		return -ENOMEM;
> +
>   	return 0;
>   }
> 
> @@ -488,6 +501,14 @@ void DebayerEGL::setShaderVariableValues(DebayerParams &params)
>   	glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);
>   	LOG(Debayer, Debug) << " ccmUniformDataIn_ " << ccmUniformDataIn_ << " data " << params.ccm;
> 
> +	egl_.createTexture2D(*eglImageLSCLookupRed_, GL_LUMINANCE, 16, 16, &params.LSC_red, GL_LINEAR);
> +	egl_.createTexture2D(*eglImageLSCLookupBlue_, GL_LUMINANCE, 16, 16, &params.LSC_green, GL_LINEAR);
> +	egl_.createTexture2D(*eglImageLSCLookupGreen_, GL_LUMINANCE, 16, 16, &params.LSC_blue, GL_LINEAR);
> +
> +	glUniform1i(textureUniformLSCRed_, eglImageLSCLookupRed_->texture_unit_uniform_id_);
> +	glUniform1i(textureUniformLSCGreen_, eglImageLSCLookupGreen_->texture_unit_uniform_id_);
> +	glUniform1i(textureUniformLSCBlue_, eglImageLSCLookupBlue_->texture_unit_uniform_id_);
> +
>   	/*
>   	 * 0 = Red, 1 = Green, 2 = Blue
>   	 */
> diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
> index a5033bc6..61feadab 100644
> --- a/src/libcamera/software_isp/debayer_egl.h
> +++ b/src/libcamera/software_isp/debayer_egl.h
> @@ -85,6 +85,11 @@ private:
>   	std::unique_ptr<eGLImage> eglImageBayerIn_;
>   	std::unique_ptr<eGLImage> eglImageBayerOut_;
> 
> +	/* Pointer to object representing input texture */
> +	eGLImage *eglImageLSCLookupRed_;
> +	eGLImage *eglImageLSCLookupBlue_;
> +	eGLImage *eglImageLSCLookupGreen_;
> +
>   	/* Shader parameters */
>   	float firstRed_x_;
>   	float firstRed_y_;
> @@ -98,6 +103,10 @@ private:
> 
>   	GLint textureUniformBayerDataIn_;
> 
> +	GLint textureUniformLSCRed_;
> +	GLint textureUniformLSCGreen_;
> +	GLint textureUniformLSCBlue_;
> +
>   	/* Represent per-frame CCM as a uniform vector of floats 3 x 3 */
>   	GLint ccmUniformDataIn_;
> 
> --
> 2.51.0
>

Patch
diff mbox series

diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 8e089032..0f36b149 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -111,6 +111,10 @@  int DebayerEGL::getShaderVariableLocations(void)
 	textureUniformBayerFirstRed_ = glGetUniformLocation(programId_, "tex_bayer_first_red");
 	textureUniformProjMatrix_ = glGetUniformLocation(programId_, "proj_matrix");
 
+	textureUniformLSCRed_ = glGetUniformLocation(programId_, "lsc_tex_red");
+	textureUniformLSCGreen_ = glGetUniformLocation(programId_, "lsc_tex_green");
+	textureUniformLSCBlue_ = glGetUniformLocation(programId_, "lsc_tex_blue");
+
 	LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_
 			    << " tex_y " << textureUniformBayerDataIn_
 			    << " ccm " << ccmUniformDataIn_
@@ -140,6 +144,9 @@  int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm
 	/* Specify GL_OES_EGL_image_external */
 	egl_.pushEnv(shaderEnv, "#extension GL_OES_EGL_image_external: enable");
 
+	/* Always use LSC */
+	egl_.pushEnv(shaderEnv, "#define DO_LSC");
+
 	/*
 	 * Tell shaders how to re-order output taking account of how the
 	 * pixels are actually stored by GBM
@@ -349,6 +356,12 @@  int DebayerEGL::configure(const StreamConfiguration &inputCfg,
 	 */
 	stats_->setWindow(Rectangle(window_.size()));
 
+	eglImageLSCLookupRed_ = new eGLImage(20, 20, sizeof(GLubyte), GL_TEXTURE5, 5);
+	eglImageLSCLookupGreen_ = new eGLImage(20, 20, sizeof(GLubyte), GL_TEXTURE5, 5);
+	eglImageLSCLookupBlue_ = new eGLImage(20, 20, sizeof(GLubyte), GL_TEXTURE5, 5);
+	if (!eglImageLSCLookupRed_ || !eglImageLSCLookupGreen_ || !eglImageLSCLookupBlue_)
+		return -ENOMEM;
+
 	return 0;
 }
 
@@ -488,6 +501,14 @@  void DebayerEGL::setShaderVariableValues(DebayerParams &params)
 	glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);
 	LOG(Debayer, Debug) << " ccmUniformDataIn_ " << ccmUniformDataIn_ << " data " << params.ccm;
 
+	egl_.createTexture2D(*eglImageLSCLookupRed_, GL_LUMINANCE, 16, 16, &params.LSC_red, GL_LINEAR);
+	egl_.createTexture2D(*eglImageLSCLookupBlue_, GL_LUMINANCE, 16, 16, &params.LSC_green, GL_LINEAR);
+	egl_.createTexture2D(*eglImageLSCLookupGreen_, GL_LUMINANCE, 16, 16, &params.LSC_blue, GL_LINEAR);
+
+	glUniform1i(textureUniformLSCRed_, eglImageLSCLookupRed_->texture_unit_uniform_id_);
+	glUniform1i(textureUniformLSCGreen_, eglImageLSCLookupGreen_->texture_unit_uniform_id_);
+	glUniform1i(textureUniformLSCBlue_, eglImageLSCLookupBlue_->texture_unit_uniform_id_);
+
 	/*
 	 * 0 = Red, 1 = Green, 2 = Blue
 	 */
diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
index a5033bc6..61feadab 100644
--- a/src/libcamera/software_isp/debayer_egl.h
+++ b/src/libcamera/software_isp/debayer_egl.h
@@ -85,6 +85,11 @@  private:
 	std::unique_ptr<eGLImage> eglImageBayerIn_;
 	std::unique_ptr<eGLImage> eglImageBayerOut_;
 
+	/* Pointer to object representing input texture */
+	eGLImage *eglImageLSCLookupRed_;
+	eGLImage *eglImageLSCLookupBlue_;
+	eGLImage *eglImageLSCLookupGreen_;
+
 	/* Shader parameters */
 	float firstRed_x_;
 	float firstRed_y_;
@@ -98,6 +103,10 @@  private:
 
 	GLint textureUniformBayerDataIn_;
 
+	GLint textureUniformLSCRed_;
+	GLint textureUniformLSCGreen_;
+	GLint textureUniformLSCBlue_;
+
 	/* Represent per-frame CCM as a uniform vector of floats 3 x 3 */
 	GLint ccmUniformDataIn_;