@@ -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();
@@ -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{};
@@ -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);
@@ -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
@@ -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 ¶ms)
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);
@@ -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_;