[RFC,v4,7/7] libcamera: software_isp: debayer_egl: Add LSC support
diff mbox series

Message ID 20260504182658.590233-8-mzamazal@redhat.com
State New
Headers show
Series
  • LSC for SoftISP simple pipeline
Related show

Commit Message

Milan Zamazal May 4, 2026, 6:26 p.m. UTC
From: Xander Pronk <xander.c.pronk@gmail.com>

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

The LSC table values are floats, we must add `type' parameter to
createTexture2D to support this.  Moreover, we use 16-bit internal
format for the values, primarily because this works for me, unlike
32-bit floats.

Co-developed-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>
Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
---
 include/libcamera/internal/egl.h              | 10 +++++--
 .../internal/software_isp/debayer_params.h    |  2 ++
 src/libcamera/egl.cpp                         | 16 ++++++++---
 src/libcamera/software_isp/debayer.cpp        |  5 ++++
 src/libcamera/software_isp/debayer_egl.cpp    | 28 +++++++++++++++++--
 src/libcamera/software_isp/debayer_egl.h      |  5 ++++
 6 files changed, 58 insertions(+), 8 deletions(-)

Patch
diff mbox series

diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h
index 6402dd5c7..3de47d970 100644
--- a/include/libcamera/internal/egl.h
+++ b/include/libcamera/internal/egl.h
@@ -103,8 +103,14 @@  public:
 
 	int createInputDMABufTexture2D(eGLImage &eglImage, int fd);
 	int createOutputDMABufTexture2D(eGLImage &eglImage, int fd);
-	void createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height,
-			     const void *data, GLint filter);
+	void createTexture2D(eGLImage &eglImage,
+			     GLint internalFormat,
+			     GLint format,
+			     GLenum type,
+			     uint32_t width,
+			     uint32_t height,
+			     const void *data,
+			     GLint filter);
 
 	void pushEnv(std::vector<std::string> &shaderEnv, const char *str);
 	void makeCurrent();
diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h
index 47f2c3ac2..5b1c8b508 100644
--- a/include/libcamera/internal/software_isp/debayer_params.h
+++ b/include/libcamera/internal/software_isp/debayer_params.h
@@ -30,6 +30,8 @@  struct DebayerParams {
 	static constexpr unsigned int kLscGridSize = 16;
 	static constexpr unsigned int kLscValuesPerCell = 3;
 	using LscValueType = float;
+	static constexpr unsigned int kLscBytesPerCell =
+		kLscValuesPerCell * sizeof(LscValueType);
 	using LscLookupTable =
 		std::array<LscValueType, kLscGridSize * kLscGridSize * kLscValuesPerCell>;
 	LscLookupTable lscLut{};
diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
index 93778acb8..fb716429d 100644
--- a/src/libcamera/egl.cpp
+++ b/src/libcamera/egl.cpp
@@ -208,7 +208,9 @@  int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd)
 /**
  * \brief Create a 2D texture from a memory buffer
  * \param[in,out] eglImage EGL image to associate with the texture
- * \param[in] format OpenGL internal format (e.g., GL_RGB, GL_RGBA)
+ * \param[in] internalFormat OpenGL internal storage format (e.g., GL_RGB8, GL_RGBA8)
+ * \param[in] format OpenGL pixel data format (e.g., GL_RGB, GL_RGBA)
+ * \param[in] type OpenGL pixel data type (e.g., GL_UNSIGNED_BYTE, GL_FLOAT)
  * \param[in] width Texture width in pixels
  * \param[in] height Texture height in pixels
  * \param[in] data Pointer to pixel data, or nullptr for uninitialised texture
@@ -219,8 +221,14 @@  int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd)
  * is useful for uploading static data like lookup tables or uniform color
  * matrices to the GPU.
  */
-void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height,
-			  const void *data, GLint filter)
+void eGL::createTexture2D(eGLImage &eglImage,
+			  GLint internalFormat,
+			  GLint format,
+			  GLenum type,
+			  uint32_t width,
+			  uint32_t height,
+			  const void *data,
+			  GLint filter)
 {
 	ASSERT(tid_ == Thread::currentId());
 
@@ -228,7 +236,7 @@  void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint
 	glBindTexture(GL_TEXTURE_2D, eglImage.texture_);
 
 	// Generate texture, bind, associate image to texture, configure, unbind
-	glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
+	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, data);
 
 	// Nearest filtering
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp
index 76c66e55b..cc1dbb2d0 100644
--- a/src/libcamera/software_isp/debayer.cpp
+++ b/src/libcamera/software_isp/debayer.cpp
@@ -58,6 +58,11 @@  namespace libcamera {
  * \brief Type of LSC grid values
  */
 
+/**
+ * \var DebayerParams::kLscBytesPerCell
+ * \brief Number of bytes per each of the lens shading grid areas
+ */
+
 /**
  * \typedef DebayerParams::LscLookupTable
  * \brief Lookup table for lens shading correction
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 82c511976..0a77a0b41 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -110,6 +110,8 @@  int DebayerEGL::getShaderVariableLocations(void)
 	textureUniformBayerFirstRed_ = glGetUniformLocation(programId_, "tex_bayer_first_red");
 	textureUniformProjMatrix_ = glGetUniformLocation(programId_, "proj_matrix");
 
+	textureUniformLsc_ = glGetUniformLocation(programId_, "lsc_tex");
+
 	LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_
 			    << " tex_y " << textureUniformBayerDataIn_
 			    << " ccm " << ccmUniformDataIn_
@@ -120,7 +122,8 @@  int DebayerEGL::getShaderVariableLocations(void)
 			    << " tex_size " << textureUniformSize_
 			    << " stride_factor " << textureUniformStrideFactor_
 			    << " tex_bayer_first_red " << textureUniformBayerFirstRed_
-			    << " proj_matrix " << textureUniformProjMatrix_;
+			    << " proj_matrix " << textureUniformProjMatrix_
+			    << " lsc " << textureUniformLsc_;
 	return 0;
 }
 
@@ -139,6 +142,9 @@  int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm
 	/* Specify GL_OES_EGL_image_external */
 	egl_.pushEnv(shaderEnv, "#extension GL_OES_EGL_image_external: enable");
 
+	if (lscEnabled_)
+		egl_.pushEnv(shaderEnv, "#define APPLY_LSC");
+
 	/*
 	 * Tell shaders how to re-order output taking account of how the pixels
 	 * are actually stored by EGL.
@@ -338,6 +344,17 @@  int DebayerEGL::configure(const StreamConfiguration &inputCfg,
 	 */
 	stats_->setWindow(Rectangle(window_.size()));
 
+	if (lscEnabled_) {
+		constexpr unsigned int gridSize = DebayerParams::kLscGridSize;
+		const unsigned int stride = gridSize * DebayerParams::kLscBytesPerCell;
+		eglImageLscLookup_ =
+			std::make_unique<eGLImage>(gridSize,
+						   gridSize,
+						   stride,
+						   GL_TEXTURE2,
+						   2);
+	}
+
 	return 0;
 }
 
@@ -477,6 +494,13 @@  void DebayerEGL::setShaderVariableValues(const DebayerParams &params)
 	glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);
 	LOG(Debayer, Debug) << " ccmUniformDataIn_ " << ccmUniformDataIn_ << " data " << params.combinedMatrix;
 
+	if (lscEnabled_) {
+		egl_.createTexture2D(*eglImageLscLookup_, GL_RGB16F, GL_RGB, GL_FLOAT,
+				     DebayerParams::kLscGridSize, DebayerParams::kLscGridSize,
+				     params.lscLut.data(), GL_LINEAR);
+		glUniform1i(textureUniformLsc_, eglImageLscLookup_->texture_unit_uniform_id_);
+	}
+
 	/*
 	 * 0 = Red, 1 = Green, 2 = Blue
 	 */
@@ -504,7 +528,7 @@  int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParam
 	egl_.makeCurrent();
 
 	/* Create a standard texture input */
-	egl_.createTexture2D(*eglImageBayerIn_, glFormat_,
+	egl_.createTexture2D(*eglImageBayerIn_, glFormat_, glFormat_, GL_UNSIGNED_BYTE,
 			     inputConfig_.stride / bytesPerPixel_, height_,
 			     in.planes()[0].data(), GL_NEAREST);
 
diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
index 4d895b55d..744efba61 100644
--- a/src/libcamera/software_isp/debayer_egl.h
+++ b/src/libcamera/software_isp/debayer_egl.h
@@ -78,7 +78,10 @@  private:
 	std::unique_ptr<eGLImage> eglImageBayerIn_;
 	std::unique_ptr<eGLImage> eglImageBayerOut_;
 
+	/* LSC lookup table */
+	std::unique_ptr<eGLImage> eglImageLscLookup_;
 	bool lscEnabled_;
+
 	/* Shader parameters */
 	float firstRed_x_;
 	float firstRed_y_;
@@ -92,6 +95,8 @@  private:
 
 	GLint textureUniformBayerDataIn_;
 
+	GLint textureUniformLsc_;
+
 	/* Represent per-frame CCM as a uniform vector of floats 3 x 3 */
 	GLint ccmUniformDataIn_;