new file mode 100644
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Red Hat Inc.
+ *
+ * Geometry for scaling and cropping debayered images
+ */
+
+#pragma once
+
+
+#include <libcamera/geometry.h>
+
+namespace libcamera {
+
+/* Return the visible sensor rectangle, before statistics Bayer alignment. */
+inline Rectangle debayerCrop(const Size &inputSize, const Size &nativeSize,
+ const Size &outputSize)
+{
+ const Size visibleSize = nativeSize.boundedToAspectRatio(outputSize);
+ return visibleSize.centeredTo(Rectangle(inputSize).center());
+}
+
+} /* namespace libcamera */
@@ -1,9 +1,10 @@
# SPDX-License-Identifier: CC0-1.0
libcamera_internal_headers += files([
'benchmark.h',
+ 'debayer_geometry.h',
'debayer_params.h',
'software_isp.h',
'swisp_stats.h',
'swstats_cpu.h',
])
@@ -1,56 +1,57 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2024, Linaro Ltd.
*
* Authors:
* Bryan O'Donoghue <bryan.odonoghue@linaro.org>
*
*/
#include "debayer_egl.h"
#include <algorithm>
#include <assert.h>
#include <memory>
#include <span>
#include <stdlib.h>
#include <string>
#include <tuple>
#include <vector>
#include <libcamera/base/utils.h>
#include <libcamera/formats.h>
#include "libcamera/internal/formats.h"
#include "libcamera/internal/framebuffer.h"
+#include "libcamera/internal/software_isp/debayer_geometry.h"
#include "../shaders/glsl_shaders.h"
namespace libcamera {
/**
* \class DebayerEGL
* \brief Class for debayering using an EGL Shader
*
* Implements an EGL shader based debayering solution.
*/
/**
* \brief Construct a DebayerEGL object
* \param[in] stats Statistics processing object
* \param[in] cm The camera manager
* \param[in] display The EGL display to use
*/
DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm, EGLDisplay display)
: Debayer(cm), stats_(std::move(stats)), egl_(display)
{
}
DebayerEGL::~DebayerEGL()
{
}
int DebayerEGL::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config)
{
BayerFormat bayerFormat =
@@ -304,72 +305,65 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg,
inputConfig_.stride = inputCfg.stride;
inputPixelFormat_ = inputCfg.pixelFormat;
width_ = inputCfg.size.width;
height_ = inputCfg.size.height;
if (outputCfgs.size() != 1) {
LOG(Debayer, Error)
<< "Unsupported number of output streams: "
<< outputCfgs.size();
return -EINVAL;
}
const StreamConfiguration &outputCfg = outputCfgs[0];
SizeRange outSizeRange = sizes(inputCfg.pixelFormat, inputCfg.size);
std::tie(outputConfig_.stride, outputConfig_.frameSize) =
strideAndFrameSize(outputCfg.pixelFormat, outputCfg.size);
if (!outSizeRange.contains(outputCfg.size) || outputConfig_.stride != outputCfg.stride) {
LOG(Debayer, Error)
<< "Invalid output size/stride: "
<< "\n " << outputCfg.size << " (" << outSizeRange << ")"
<< "\n " << outputCfg.stride << " (" << outputConfig_.stride << ")";
return -EINVAL;
}
outputPixelFormat_ = outputCfg.pixelFormat;
outputSize_ = outputCfg.size;
nativeOutputSize_ = outSizeRange.max;
- window_.x = ((inputCfg.size.width - outputCfg.size.width) / 2) &
- ~(inputConfig_.patternSize.width - 1);
- window_.y = ((inputCfg.size.height - outputCfg.size.height) / 2) &
- ~(inputConfig_.patternSize.height - 1);
- window_.width = outputCfg.size.width;
- window_.height = outputCfg.size.height;
-
/*
- * Don't pass x,y from window_ since process() already adjusts for it.
- * But crop the window to 2/3 of its width and height for speedup.
+ * The GPU scales the visible sensor crop to outputSize_. Statistics
+ * consume the original input buffer, so use sensor coordinates here.
*/
- stats_->setWindow(Rectangle(window_.size()));
+ stats_->setWindow(debayerCrop(inputCfg.size, nativeOutputSize_, outputSize_));
inputBufferCount_ = inputCfg.bufferCount;
outputBufferCount_ = outputCfg.bufferCount;
return 0;
}
Size DebayerEGL::patternSize(PixelFormat inputFormat)
{
DebayerEGL::DebayerInputConfig config;
if (getInputConfig(inputFormat, config) != 0)
return {};
return config.patternSize;
}
std::vector<PixelFormat> DebayerEGL::formats(PixelFormat inputFormat)
{
DebayerEGL::DebayerInputConfig config;
if (getInputConfig(inputFormat, config) != 0)
return std::vector<PixelFormat>();
return config.outputFormats;
}
std::tuple<unsigned int, unsigned int>
DebayerEGL::strideAndFrameSize(const PixelFormat &outputFormat, const Size &size)
{
@@ -93,41 +93,40 @@ private:
float firstRed_y_;
GLint attributeVertex_;
GLint attributeTexture_;
GLint textureUniformStep_;
GLint textureUniformSize_;
GLint textureUniformStrideFactor_;
GLint textureUniformBayerFirstRed_;
GLint textureUniformProjMatrix_;
GLint textureUniformBayerDataIn_;
/* 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_;
/* Black Level compensation */
GLint blackLevelUniformDataIn_;
/* Gamma */
GLint gammaUniformDataIn_;
/* Contrast */
GLint contrastExpUniformDataIn_;
Size nativeOutputSize_;
- Rectangle window_;
std::unique_ptr<SwStatsCpu> stats_;
eGL egl_;
uint32_t width_;
uint32_t height_;
GLint glFormat_;
unsigned int bytesPerPixel_;
uint32_t shaderStridePixels_;
};
} /* namespace libcamera */