@@ -107,8 +107,12 @@ public:
int createInputDMABufTexture2D(eGLImage &eglImage, int fd);
int createOutputDMABufTexture2D(eGLImage &eglImage, int fd);
- void createTexture2D(eGLImage &eglImage, void *data, GLint filter);
- void updateTexture2D(eGLImage &eglImage, void *data);
+ void createTexture2D(eGLImage &eglImage,
+ GLint internalFormat,
+ GLenum type,
+ const void *data,
+ GLint filter);
+ void updateTexture2D(eGLImage &eglImage, const void *data);
void createOutputTexture2D(eGLImage &eglImage);
int attachTextureToFBO(eGLImage &eglImage);
@@ -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>;
LscLookupTable lscLut{};
@@ -274,6 +274,8 @@ 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] internalFormat OpenGL internal storage format (e.g., GL_RGB8, GL_RGBA8)
+ * \param[in] type OpenGL pixel data type (e.g., GL_UNSIGNED_BYTE, GL_FLOAT)
* \param[in] data Pointer to pixel data, or nullptr for uninitialised texture
* \param[in] filter GL texture filter setting
*
@@ -282,14 +284,18 @@ 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, void *data, GLint filter)
+void eGL::createTexture2D(eGLImage &eglImage,
+ GLint internalFormat,
+ GLenum type,
+ const void *data,
+ GLint filter)
{
ASSERT(tid_ == Thread::currentId());
activateBindTexture(eglImage);
// Generate texture, bind, associate image to texture, configure, unbind
- glTexImage2D(GL_TEXTURE_2D, 0, eglImage.format_, eglImage.width_, eglImage.height_, 0, eglImage.format_, GL_UNSIGNED_BYTE, data);
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, eglImage.width_, eglImage.height_, 0, eglImage.format_, type, data);
// Nearest filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
@@ -351,7 +357,7 @@ bool eGL::isAvailable()
*
* Updates a 2D texture in VRAM.
*/
-void eGL::updateTexture2D(eGLImage &eglImage, void *data)
+void eGL::updateTexture2D(eGLImage &eglImage, const void *data)
{
ASSERT(tid_ == Thread::currentId());
@@ -370,7 +376,7 @@ void eGL::updateTexture2D(eGLImage &eglImage, void *data)
*/
void eGL::createOutputTexture2D(eGLImage &eglImage)
{
- createTexture2D(eglImage, NULL, GL_NEAREST);
+ createTexture2D(eglImage, eglImage.format_, GL_UNSIGNED_BYTE, NULL, GL_NEAREST);
attachTextureToFBO(eglImage);
}
@@ -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
@@ -128,6 +128,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_
@@ -139,7 +141,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;
}
@@ -156,6 +159,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.
@@ -351,6 +357,18 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg,
inputBufferCount_ = inputCfg.bufferCount;
outputBufferCount_ = outputCfg.bufferCount;
+ if (lscEnabled_) {
+ 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);
+ }
+
return 0;
}
@@ -486,6 +504,21 @@ 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_) {
+ glUniform1i(textureUniformLsc_, eglImageLscLookup_->texture_unit_uniform_id_);
+ if (params.lscLutVersion != lscLutVersion_) {
+ if (lscTextureCreated_) {
+ egl_.updateTexture2D(*eglImageLscLookup_, params.lscLut.data());
+ } else {
+ egl_.createTexture2D(*eglImageLscLookup_, eglImageLscLookup_->format_, GL_UNSIGNED_BYTE,
+ params.lscLut.data(), GL_LINEAR);
+ lscTextureCreated_ = true;
+ }
+
+ lscLutVersion_ = params.lscLutVersion;
+ }
+ }
+
/*
* 0 = Red, 1 = Green, 2 = Blue
*/
@@ -552,7 +585,11 @@ eGLImage *DebayerEGL::getCachedInputFrameBuffer(FrameBuffer *input, std::optiona
return nullptr;
}
if (cache_miss)
- egl_.createTexture2D(*eglImageIn, inMapped->value().planes()[0].data(), GL_NEAREST);
+ egl_.createTexture2D(*eglImageIn,
+ eglImageIn->format_,
+ GL_UNSIGNED_BYTE,
+ inMapped->value().planes()[0].data(),
+ GL_NEAREST);
else
egl_.updateTexture2D(*eglImageIn, inMapped->value().planes()[0].data());
@@ -698,6 +735,7 @@ void DebayerEGL::stop()
{
eglImageOutCache_.clear();
eglImageInCache_.clear();
+ lscTextureCreated_ = false;
if (programId_)
glDeleteProgram(programId_);
@@ -84,7 +84,12 @@ private:
unsigned int inputBufferCount_;
unsigned int outputBufferCount_;
+ /* LSC lookup table */
+ std::unique_ptr<eGLImage> eglImageLscLookup_;
bool lscEnabled_;
+ bool lscTextureCreated_ = false;
+ uint64_t lscLutVersion_ = 0;
+
/* Shader parameters */
float firstRed_x_;
float firstRed_y_;
@@ -101,6 +106,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_;