| Message ID | 20260810201957.19623-8-mzamazal@redhat.com |
|---|---|
| State | Superseded |
| Headers | show |
| Series |
|
| Related | show |
2026. 08. 10. 22:19 keltezéssel, Milan Zamazal írta: > From: Xander Pronk <xander.c.pronk@gmail.com> > > Add support for passing the LSC table from debayerParams to the shaders. > > We use 8-bit texture with the original UQ<2, 6> values to avoid trouble > with floats. 32-bit floats don't work in my environment and 16-bit > floats may not be supported in all OpenGL environments. > > When LSC is disabled by the runtime control, we provide a constant 1.0 > correction table, i.e. a no-op table. This is preferred to having a > runtime flag, to not disturb GPU computation with runtime switches, > assuming that disabling LSC in runtime is not a common use case. > > The LSC texture is created once and then updated. The texture creation > cannot be done in `configure', because of a different thread. > > 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> > --- > .../internal/software_isp/debayer_params.h | 2 ++ > src/libcamera/software_isp/debayer.cpp | 5 +++ > src/libcamera/software_isp/debayer_egl.cpp | 36 ++++++++++++++++++- > src/libcamera/software_isp/debayer_egl.h | 7 ++++ > 4 files changed, 49 insertions(+), 1 deletion(-) > > diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h > index b7860c9dd..1e0b5b553 100644 > --- a/include/libcamera/internal/software_isp/debayer_params.h > +++ b/include/libcamera/internal/software_isp/debayer_params.h > @@ -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 = [] { > diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp > index 8295b8fc2..4f6659000 100644 > --- a/src/libcamera/software_isp/debayer.cpp > +++ b/src/libcamera/software_isp/debayer.cpp > @@ -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 > diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp > index 5227d2bbd..941fdc914 100644 > --- a/src/libcamera/software_isp/debayer_egl.cpp > +++ b/src/libcamera/software_isp/debayer_egl.cpp > @@ -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; > + } I think I'm going to contradict my earlier review comments, so sorry about that. But after looking some more at this code, I think the following would be a worthy change. The main change here is that `setShaderVariableValues()` only ever updates the texture, and the creation is only done at the start. I feel like that makes things easier to understand, roughly something like this: diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 077c6ddda8..5645b52a80 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -473,29 +473,11 @@ 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); - } + if (lscEnabled_ && params.lscLutVersion != lscLutVersion_) { + egl_.updateTexture2D(*eglImageLscLookup_, params.lscLut.data()); + lscLutVersion_ = params.lscLutVersion; + 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; - } } /* @@ -708,6 +690,14 @@ int DebayerEGL::start() if (initBayerShaders(inputPixelFormat_, outputPixelFormat_)) return -EINVAL; + if (lscEnabled_) { + constexpr unsigned int gridSize = DebayerParams::kLscGridSize; + constexpr unsigned int stride = gridSize * DebayerParams::kLscBytesPerCell; + + eglImageLscLookup_.emplace(GL_RGBA, gridSize, gridSize, stride, GL_TEXTURE2, 2); + egl_.createTexture2D(*eglImageLscLookup_, eglImageLscLookup_->format_, GL_UNSIGNED_BYTE, nullptr, GL_LINEAR); + } + return 0; } diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index c2a08fb064..9dbf6f71d7 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -84,7 +84,7 @@ private: unsigned int outputBufferCount_; /* LSC lookup table */ - std::unique_ptr<eGLImage> eglImageLscLookup_; + std::optional<eGLImage> eglImageLscLookup_; bool lscEnabled_; std::optional<uint64_t> 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_); > } > diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h > index a64dc925a..c2a08fb06 100644 > --- a/src/libcamera/software_isp/debayer_egl.h > +++ b/src/libcamera/software_isp/debayer_egl.h > @@ -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_; >
Barnabás Pőcze <barnabas.pocze@ideasonboard.com> writes: > 2026. 08. 10. 22:19 keltezéssel, Milan Zamazal írta: >> From: Xander Pronk <xander.c.pronk@gmail.com> >> Add support for passing the LSC table from debayerParams to the shaders. >> We use 8-bit texture with the original UQ<2, 6> values to avoid trouble >> with floats. 32-bit floats don't work in my environment and 16-bit >> floats may not be supported in all OpenGL environments. >> When LSC is disabled by the runtime control, we provide a constant 1.0 >> correction table, i.e. a no-op table. This is preferred to having a >> runtime flag, to not disturb GPU computation with runtime switches, >> assuming that disabling LSC in runtime is not a common use case. >> The LSC texture is created once and then updated. The texture creation >> cannot be done in `configure', because of a different thread. >> 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> >> --- >> .../internal/software_isp/debayer_params.h | 2 ++ >> src/libcamera/software_isp/debayer.cpp | 5 +++ >> src/libcamera/software_isp/debayer_egl.cpp | 36 ++++++++++++++++++- >> src/libcamera/software_isp/debayer_egl.h | 7 ++++ >> 4 files changed, 49 insertions(+), 1 deletion(-) >> diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h >> index b7860c9dd..1e0b5b553 100644 >> --- a/include/libcamera/internal/software_isp/debayer_params.h >> +++ b/include/libcamera/internal/software_isp/debayer_params.h >> @@ -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 = [] { >> diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp >> index 8295b8fc2..4f6659000 100644 >> --- a/src/libcamera/software_isp/debayer.cpp >> +++ b/src/libcamera/software_isp/debayer.cpp >> @@ -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 >> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp >> index 5227d2bbd..941fdc914 100644 >> --- a/src/libcamera/software_isp/debayer_egl.cpp >> +++ b/src/libcamera/software_isp/debayer_egl.cpp >> @@ -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; >> + } > > I think I'm going to contradict my earlier review comments, so sorry about that. But after > looking some more at this code, I think the following would be a worthy change. > The main change here is that `setShaderVariableValues()` only ever updates the > texture, and the creation is only done at the start. I feel like that makes things > easier to understand, roughly something like this: > > diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp > index 077c6ddda8..5645b52a80 100644 > --- a/src/libcamera/software_isp/debayer_egl.cpp > +++ b/src/libcamera/software_isp/debayer_egl.cpp > @@ -473,29 +473,11 @@ 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); > - } > + if (lscEnabled_ && params.lscLutVersion != lscLutVersion_) { > + egl_.updateTexture2D(*eglImageLscLookup_, params.lscLut.data()); > + lscLutVersion_ = params.lscLutVersion; > + > 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; > - } > } > /* > @@ -708,6 +690,14 @@ int DebayerEGL::start() > if (initBayerShaders(inputPixelFormat_, outputPixelFormat_)) > return -EINVAL; > + if (lscEnabled_) { > + constexpr unsigned int gridSize = DebayerParams::kLscGridSize; > + constexpr unsigned int stride = gridSize * DebayerParams::kLscBytesPerCell; > + > + eglImageLscLookup_.emplace(GL_RGBA, gridSize, gridSize, stride, GL_TEXTURE2, 2); > + egl_.createTexture2D(*eglImageLscLookup_, eglImageLscLookup_->format_, GL_UNSIGNED_BYTE, nullptr, GL_LINEAR); > + } > + > return 0; > } > diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h > index c2a08fb064..9dbf6f71d7 100644 > --- a/src/libcamera/software_isp/debayer_egl.h > +++ b/src/libcamera/software_isp/debayer_egl.h > @@ -84,7 +84,7 @@ private: > unsigned int outputBufferCount_; > /* LSC lookup table */ > - std::unique_ptr<eGLImage> eglImageLscLookup_; > + std::optional<eGLImage> eglImageLscLookup_; > bool lscEnabled_; > std::optional<uint64_t> lscLutVersion_; Yes, seems to look better. I'll try to do something along these lines in v14. > > + } >> + >> /* >> * 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_); >> } >> diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h >> index a64dc925a..c2a08fb06 100644 >> --- a/src/libcamera/software_isp/debayer_egl.h >> +++ b/src/libcamera/software_isp/debayer_egl.h >> @@ -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_; >>
diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h index b7860c9dd..1e0b5b553 100644 --- a/include/libcamera/internal/software_isp/debayer_params.h +++ b/include/libcamera/internal/software_isp/debayer_params.h @@ -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 = [] { diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index 8295b8fc2..4f6659000 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -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 diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 5227d2bbd..941fdc914 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -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_); } diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index a64dc925a..c2a08fb06 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -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_;