@@ -33,6 +33,8 @@ struct DebayerParams {
**/
static constexpr unsigned int kLscGridSize = 17;
static constexpr unsigned int kLscValuesPerCell = 4;
+ static constexpr unsigned int kLscBytesPerCell =
+ kLscValuesPerCell * sizeof(uint8_t);
using LscLookupTable =
std::array<uint8_t, kLscGridSize * kLscGridSize * kLscValuesPerCell>;
static constexpr auto identityLscLut = [] {
@@ -53,6 +53,11 @@ namespace libcamera {
* \brief Number of pixel values per each of the lens shading grid areas
*/
+/**
+ * \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
@@ -115,6 +115,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_
<< " awb " << awbUniformDataIn_
@@ -126,7 +128,8 @@ int DebayerEGL::getShaderVariableLocations(void)
<< " tex_size " << textureUniformSize_
<< " stride_factor " << textureUniformStrideFactor_
<< " tex_bayer_first_red " << textureUniformBayerFirstRed_
- << " proj_matrix " << textureUniformProjMatrix_;
+ << " proj_matrix " << textureUniformProjMatrix_
+ << " tex_lsc " << textureUniformLsc_;
return 0;
}
@@ -143,6 +146,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.
@@ -467,6 +473,31 @@ void DebayerEGL::setShaderVariableValues(eGLImage &eglImageIn, const DebayerPara
glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_TRUE, params.combinedMatrix.data().data());
LOG(Debayer, Debug) << " ccmUniformDataIn_ " << ccmUniformDataIn_ << " data " << params.combinedMatrix;
+ if (lscEnabled_) {
+ bool create = !eglImageLscLookup_;
+ if (create) {
+ constexpr unsigned int gridSize = DebayerParams::kLscGridSize;
+ const unsigned int stride = gridSize * DebayerParams::kLscBytesPerCell;
+ eglImageLscLookup_ =
+ std::make_unique<eGLImage>(GL_RGBA,
+ gridSize,
+ gridSize,
+ stride,
+ GL_TEXTURE2,
+ 2);
+ }
+ glUniform1i(textureUniformLsc_, eglImageLscLookup_->texture_unit_uniform_id_);
+ if (params.lscLutVersion != lscLutVersion_) {
+ if (create)
+ egl_.createTexture2D(*eglImageLscLookup_, eglImageLscLookup_->format_, GL_UNSIGNED_BYTE,
+ params.lscLut.data(), GL_LINEAR);
+ else
+ egl_.updateTexture2D(*eglImageLscLookup_, params.lscLut.data());
+
+ lscLutVersion_ = params.lscLutVersion;
+ }
+ }
+
/*
* 0 = Red, 1 = Green, 2 = Blue
*/
@@ -687,6 +718,9 @@ void DebayerEGL::stop()
eglImageOutCache_.clear();
eglImageInCache_.clear();
+ eglImageLscLookup_.reset();
+ lscLutVersion_.reset();
+
if (programId_)
glDeleteProgram(programId_);
}
@@ -83,7 +83,11 @@ private:
unsigned int inputBufferCount_;
unsigned int outputBufferCount_;
+ /* LSC lookup table */
+ std::unique_ptr<eGLImage> eglImageLscLookup_;
bool lscEnabled_;
+ std::optional<uint64_t> lscLutVersion_;
+
/* Shader parameters */
float firstRed_x_;
float firstRed_y_;
@@ -100,6 +104,9 @@ private:
/* Per-frame AWB gains */
GLint awbUniformDataIn_;
+ /* Lens shading correction */
+ GLint textureUniformLsc_;
+
/* Represent per-frame CCM as a uniform vector of floats 3 x 3 */
GLint ccmUniformDataIn_;