diff options
author | Florian Klink <flokli@flokli.de> | 2024-03-17T14·11+0200 |
---|---|---|
committer | clbot <clbot@tvl.fyi> | 2024-03-19T06·59+0000 |
commit | 9948eb64d1d0a96c175114cfb2069cd301df740d (patch) | |
tree | 565a6ef12826eaeb0725c113a0442d4793a59129 /users/flokli/ipu6-softisp/libcamera/0010-libcamera-software_isp-Add-DebayerCpu-class.patch | |
parent | 622efa86fa28f6357f65fc8e37efb8120734af39 (diff) |
chore(users/flokli/ipu6-softisp): refresh libcamera patches r/7738
Refresh them with the patches from https://patchwork.libcamera.org/cover/19663/. This is still based off v0.2.0. Change-Id: I875fd64e3bb71a95c92af1108a23d27c0f3494e0 Reviewed-on: https://cl.tvl.fyi/c/depot/+/11179 Tested-by: BuildkiteCI Reviewed-by: flokli <flokli@flokli.de> Autosubmit: flokli <flokli@flokli.de>
Diffstat (limited to 'users/flokli/ipu6-softisp/libcamera/0010-libcamera-software_isp-Add-DebayerCpu-class.patch')
-rw-r--r-- | users/flokli/ipu6-softisp/libcamera/0010-libcamera-software_isp-Add-DebayerCpu-class.patch | 727 |
1 files changed, 0 insertions, 727 deletions
diff --git a/users/flokli/ipu6-softisp/libcamera/0010-libcamera-software_isp-Add-DebayerCpu-class.patch b/users/flokli/ipu6-softisp/libcamera/0010-libcamera-software_isp-Add-DebayerCpu-class.patch deleted file mode 100644 index 56bc87336c2e..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0010-libcamera-software_isp-Add-DebayerCpu-class.patch +++ /dev/null @@ -1,727 +0,0 @@ -From 7eb7164ed7d90ea4cf9ec7e4f35fa8efa25f35e9 Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Mon, 11 Dec 2023 17:00:17 +0100 -Subject: [PATCH 10/25] libcamera: software_isp: Add DebayerCpu class - -Add CPU based debayering implementation. This initial implementation -only supports debayering packed 10 bits per pixel bayer data in -the 4 standard bayer orders. - -Doxygen documentation by Dennis Bonke. - -Co-authored-by: Dennis Bonke <admin@dennisbonke.com> -Signed-off-by: Dennis Bonke <admin@dennisbonke.com> -Co-authored-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Co-authored-by: Pavel Machek <pavel@ucw.cz> -Signed-off-by: Pavel Machek <pavel@ucw.cz> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> ---- - .../internal/software_isp/debayer_cpu.h | 131 +++++ - .../internal/software_isp/meson.build | 1 + - src/libcamera/software_isp/debayer_cpu.cpp | 528 ++++++++++++++++++ - src/libcamera/software_isp/meson.build | 1 + - 4 files changed, 661 insertions(+) - create mode 100644 include/libcamera/internal/software_isp/debayer_cpu.h - create mode 100644 src/libcamera/software_isp/debayer_cpu.cpp - -diff --git a/include/libcamera/internal/software_isp/debayer_cpu.h b/include/libcamera/internal/software_isp/debayer_cpu.h -new file mode 100644 -index 00000000..78573f44 ---- /dev/null -+++ b/include/libcamera/internal/software_isp/debayer_cpu.h -@@ -0,0 +1,131 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Linaro Ltd -+ * Copyright (C) 2023, Red Hat Inc. -+ * -+ * Authors: -+ * Hans de Goede <hdegoede@redhat.com> -+ * -+ * debayer_cpu.h - CPU based debayering header -+ */ -+ -+#pragma once -+ -+#include <memory> -+#include <stdint.h> -+#include <vector> -+ -+#include <libcamera/base/object.h> -+ -+#include "libcamera/internal/software_isp/swstats_cpu.h" -+#include "libcamera/internal/software_isp/debayer.h" -+ -+namespace libcamera { -+ -+/** -+ * \class DebayerCpu -+ * \brief Class for debayering on the CPU -+ * -+ * Implementation for CPU based debayering -+ */ -+class DebayerCpu : public Debayer, public Object -+{ -+public: -+ /* -+ * FIXME this should be a plain (implementation independent) SwStats -+ * this can be fixed once getStats() is dropped. -+ */ -+ /** -+ * \brief Constructs a DebayerCpu object. -+ * \param[in] stats Pointer to the stats object to use. -+ */ -+ DebayerCpu(std::unique_ptr<SwStatsCpu> stats); -+ ~DebayerCpu(); -+ -+ /* -+ * Setup the Debayer object according to the passed in parameters. -+ * Return 0 on success, a negative errno value on failure -+ * (unsupported parameters). -+ */ -+ int configure(const StreamConfiguration &inputCfg, -+ const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs); -+ -+ /* -+ * Get width and height at which the bayer-pattern repeats. -+ * Return pattern-size or an empty Size for an unsupported inputFormat. -+ */ -+ Size patternSize(PixelFormat inputFormat); -+ -+ std::vector<PixelFormat> formats(PixelFormat input); -+ std::tuple<unsigned int, unsigned int> -+ strideAndFrameSize(const PixelFormat &outputFormat, const Size &size); -+ -+ void process(FrameBuffer *input, FrameBuffer *output, DebayerParams params); -+ -+ /** -+ * \brief Get the file descriptor for the statistics. -+ * -+ * \return the file descriptor pointing to the statistics. -+ */ -+ const SharedFD &getStatsFD() { return stats_->getStatsFD(); } -+ -+ /** -+ * \brief Get the output frame size. -+ * -+ * \return The output frame size. -+ */ -+ unsigned int frameSize() { return outputConfig_.frameSize; } -+private: -+ void initLinePointers(const uint8_t *linePointers[], const uint8_t *src); -+ void shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src); -+ void process2(const uint8_t *src, uint8_t *dst); -+ void process4(const uint8_t *src, uint8_t *dst); -+ /* CSI-2 packed 10-bit raw bayer format (all the 4 orders) */ -+ void debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]); -+ void debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]); -+ void debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[]); -+ void debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[]); -+ -+ typedef void (DebayerCpu::*debayerFn)(uint8_t *dst, const uint8_t *src[]); -+ -+ struct DebayerInputConfig { -+ Size patternSize; -+ unsigned int bpp; /* Memory used per pixel, not precision */ -+ unsigned int stride; -+ std::vector<PixelFormat> outputFormats; -+ }; -+ -+ struct DebayerOutputConfig { -+ unsigned int bpp; /* Memory used per pixel, not precision */ -+ unsigned int stride; -+ unsigned int frameSize; -+ }; -+ -+ int getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config); -+ int getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config); -+ int setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputFormat); -+ -+ uint8_t gamma_[1024]; -+ uint8_t red_[256]; -+ uint8_t green_[256]; -+ uint8_t blue_[256]; -+ debayerFn debayer0_; -+ debayerFn debayer1_; -+ debayerFn debayer2_; -+ debayerFn debayer3_; -+ Rectangle window_; -+ DebayerInputConfig inputConfig_; -+ DebayerOutputConfig outputConfig_; -+ std::unique_ptr<SwStatsCpu> stats_; -+ uint8_t *lineBuffers_[5]; -+ unsigned int lineBufferIndex_; -+ bool enableInputMemcpy_; -+ float gamma_correction_; -+ int measuredFrames_; -+ int64_t frameProcessTime_; -+ /* Skip 30 frames for things to stabilize then measure 30 frames */ -+ static const int framesToSkip = 30; -+ static const int framesToMeasure = 60; -+}; -+ -+} /* namespace libcamera */ -diff --git a/include/libcamera/internal/software_isp/meson.build b/include/libcamera/internal/software_isp/meson.build -index 7e40925e..b5a0d737 100644 ---- a/include/libcamera/internal/software_isp/meson.build -+++ b/include/libcamera/internal/software_isp/meson.build -@@ -2,6 +2,7 @@ - - libcamera_internal_headers += files([ - 'debayer.h', -+ 'debayer_cpu.h', - 'debayer_params.h', - 'swisp_stats.h', - 'swstats.h', -diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp -new file mode 100644 -index 00000000..e0c3c658 ---- /dev/null -+++ b/src/libcamera/software_isp/debayer_cpu.cpp -@@ -0,0 +1,528 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Linaro Ltd -+ * Copyright (C) 2023, Red Hat Inc. -+ * -+ * Authors: -+ * Hans de Goede <hdegoede@redhat.com> -+ * -+ * debayer_cpu.cpp - CPU based debayering class -+ */ -+ -+#include "libcamera/internal/software_isp/debayer_cpu.h" -+ -+#include <math.h> -+#include <stdlib.h> -+#include <time.h> -+ -+#include <libcamera/formats.h> -+ -+#include "libcamera/internal/bayer_format.h" -+#include "libcamera/internal/framebuffer.h" -+#include "libcamera/internal/mapped_framebuffer.h" -+ -+namespace libcamera { -+ -+DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats) -+ : stats_(std::move(stats)), gamma_correction_(1.0) -+{ -+#ifdef __x86_64__ -+ enableInputMemcpy_ = false; -+#else -+ enableInputMemcpy_ = true; -+#endif -+ /* Initialize gamma to 1.0 curve */ -+ for (int i = 0; i < 1024; i++) -+ gamma_[i] = i / 4; -+ -+ for (int i = 0; i < 5; i++) -+ lineBuffers_[i] = NULL; -+} -+ -+DebayerCpu::~DebayerCpu() -+{ -+ for (int i = 0; i < 5; i++) -+ free(lineBuffers_[i]); -+} -+ -+// RGR -+// GBG -+// RGR -+#define BGGR_BGR888(p, n, div) \ -+ *dst++ = blue_[curr[x] / (div)]; \ -+ *dst++ = green_[(prev[x] + curr[x - p] + curr[x + n] + next[x]) / (4 * (div))]; \ -+ *dst++ = red_[(prev[x - p] + prev[x + n] + next[x - p] + next[x + n]) / (4 * (div))]; \ -+ x++; -+ -+// GBG -+// RGR -+// GBG -+#define GRBG_BGR888(p, n, div) \ -+ *dst++ = blue_[(prev[x] + next[x]) / (2 * (div))]; \ -+ *dst++ = green_[curr[x] / (div)]; \ -+ *dst++ = red_[(curr[x - p] + curr[x + n]) / (2 * (div))]; \ -+ x++; -+ -+// GRG -+// BGB -+// GRG -+#define GBRG_BGR888(p, n, div) \ -+ *dst++ = blue_[(curr[x - p] + curr[x + n]) / (2 * (div))]; \ -+ *dst++ = green_[curr[x] / (div)]; \ -+ *dst++ = red_[(prev[x] + next[x]) / (2 * (div))]; \ -+ x++; -+ -+// BGB -+// GRG -+// BGB -+#define RGGB_BGR888(p, n, div) \ -+ *dst++ = blue_[(prev[x - p] + prev[x + n] + next[x - p] + next[x + n]) / (4 * (div))]; \ -+ *dst++ = green_[(prev[x] + curr[x - p] + curr[x + n] + next[x]) / (4 * (div))]; \ -+ *dst++ = red_[curr[x] / (div)]; \ -+ x++; -+ -+void DebayerCpu::debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ const int width_in_bytes = window_.width * 5 / 4; -+ const uint8_t *prev = (const uint8_t *)src[0]; -+ const uint8_t *curr = (const uint8_t *)src[1]; -+ const uint8_t *next = (const uint8_t *)src[2]; -+ -+ /* -+ * For the first pixel getting a pixel from the previous column uses -+ * x - 2 to skip the 5th byte with least-significant bits for 4 pixels. -+ * Same for last pixel (uses x + 2) and looking at the next column. -+ * x++ in the for-loop skips the 5th byte with 4 x 2 lsb-s for 10bit packed. -+ */ -+ for (int x = 0; x < width_in_bytes; x++) { -+ /* Even pixel */ -+ BGGR_BGR888(2, 1, 1) -+ /* Odd pixel BGGR -> GBRG */ -+ GBRG_BGR888(1, 1, 1) -+ /* Same thing for next 2 pixels */ -+ BGGR_BGR888(1, 1, 1) -+ GBRG_BGR888(1, 2, 1) -+ } -+} -+ -+void DebayerCpu::debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ const int width_in_bytes = window_.width * 5 / 4; -+ const uint8_t *prev = (const uint8_t *)src[0]; -+ const uint8_t *curr = (const uint8_t *)src[1]; -+ const uint8_t *next = (const uint8_t *)src[2]; -+ -+ for (int x = 0; x < width_in_bytes; x++) { -+ /* Even pixel */ -+ GRBG_BGR888(2, 1, 1) -+ /* Odd pixel GRBG -> RGGB */ -+ RGGB_BGR888(1, 1, 1) -+ /* Same thing for next 2 pixels */ -+ GRBG_BGR888(1, 1, 1) -+ RGGB_BGR888(1, 2, 1) -+ } -+} -+ -+void DebayerCpu::debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ const int width_in_bytes = window_.width * 5 / 4; -+ const uint8_t *prev = (const uint8_t *)src[0]; -+ const uint8_t *curr = (const uint8_t *)src[1]; -+ const uint8_t *next = (const uint8_t *)src[2]; -+ -+ for (int x = 0; x < width_in_bytes; x++) { -+ /* Even pixel */ -+ GBRG_BGR888(2, 1, 1) -+ /* Odd pixel GBGR -> BGGR */ -+ BGGR_BGR888(1, 1, 1) -+ /* Same thing for next 2 pixels */ -+ GBRG_BGR888(1, 1, 1) -+ BGGR_BGR888(1, 2, 1) -+ } -+} -+ -+void DebayerCpu::debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ const int width_in_bytes = window_.width * 5 / 4; -+ const uint8_t *prev = (const uint8_t *)src[0]; -+ const uint8_t *curr = (const uint8_t *)src[1]; -+ const uint8_t *next = (const uint8_t *)src[2]; -+ -+ for (int x = 0; x < width_in_bytes; x++) { -+ /* Even pixel */ -+ RGGB_BGR888(2, 1, 1) -+ /* Odd pixel RGGB -> GRBG*/ -+ GRBG_BGR888(1, 1, 1) -+ /* Same thing for next 2 pixels */ -+ RGGB_BGR888(1, 1, 1) -+ GRBG_BGR888(1, 2, 1) -+ } -+} -+ -+static bool isStandardBayerOrder(BayerFormat::Order order) -+{ -+ return order == BayerFormat::BGGR || order == BayerFormat::GBRG || -+ order == BayerFormat::GRBG || order == BayerFormat::RGGB; -+} -+ -+int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config) -+{ -+ BayerFormat bayerFormat = -+ BayerFormat::fromPixelFormat(inputFormat); -+ -+ if (bayerFormat.bitDepth == 10 && -+ bayerFormat.packing == BayerFormat::Packing::CSI2 && -+ isStandardBayerOrder(bayerFormat.order)) { -+ config.bpp = 10; -+ config.patternSize.width = 4; /* 5 bytes per *4* pixels */ -+ config.patternSize.height = 2; -+ config.outputFormats = std::vector<PixelFormat>({ formats::RGB888 }); -+ return 0; -+ } -+ -+ LOG(Debayer, Info) -+ << "Unsupported input format " << inputFormat.toString(); -+ return -EINVAL; -+} -+ -+int DebayerCpu::getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config) -+{ -+ if (outputFormat == formats::RGB888) { -+ config.bpp = 24; -+ return 0; -+ } -+ -+ LOG(Debayer, Info) -+ << "Unsupported output format " << outputFormat.toString(); -+ return -EINVAL; -+} -+ -+/* TODO: this ignores outputFormat since there is only 1 supported outputFormat for now */ -+int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, [[maybe_unused]] PixelFormat outputFormat) -+{ -+ BayerFormat bayerFormat = -+ BayerFormat::fromPixelFormat(inputFormat); -+ -+ if (bayerFormat.bitDepth == 10 && -+ bayerFormat.packing == BayerFormat::Packing::CSI2) { -+ switch (bayerFormat.order) { -+ case BayerFormat::BGGR: -+ debayer0_ = &DebayerCpu::debayer10P_BGBG_BGR888; -+ debayer1_ = &DebayerCpu::debayer10P_GRGR_BGR888; -+ return 0; -+ case BayerFormat::GBRG: -+ debayer0_ = &DebayerCpu::debayer10P_GBGB_BGR888; -+ debayer1_ = &DebayerCpu::debayer10P_RGRG_BGR888; -+ return 0; -+ case BayerFormat::GRBG: -+ debayer0_ = &DebayerCpu::debayer10P_GRGR_BGR888; -+ debayer1_ = &DebayerCpu::debayer10P_BGBG_BGR888; -+ return 0; -+ case BayerFormat::RGGB: -+ debayer0_ = &DebayerCpu::debayer10P_RGRG_BGR888; -+ debayer1_ = &DebayerCpu::debayer10P_GBGB_BGR888; -+ return 0; -+ default: -+ break; -+ } -+ } -+ -+ LOG(Debayer, Error) << "Unsupported input output format combination"; -+ return -EINVAL; -+} -+ -+int DebayerCpu::configure(const StreamConfiguration &inputCfg, -+ const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs) -+{ -+ if (getInputConfig(inputCfg.pixelFormat, inputConfig_) != 0) -+ return -EINVAL; -+ -+ if (stats_->configure(inputCfg) != 0) -+ return -EINVAL; -+ -+ const Size &stats_pattern_size = stats_->patternSize(); -+ if (inputConfig_.patternSize.width != stats_pattern_size.width || -+ inputConfig_.patternSize.height != stats_pattern_size.height) { -+ LOG(Debayer, Error) -+ << "mismatching stats and debayer pattern sizes for " -+ << inputCfg.pixelFormat.toString(); -+ return -EINVAL; -+ } -+ -+ inputConfig_.stride = inputCfg.stride; -+ -+ 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; -+ } -+ -+ if (setDebayerFunctions(inputCfg.pixelFormat, outputCfg.pixelFormat) != 0) -+ return -EINVAL; -+ -+ 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 since process() already adjusts src before passing it */ -+ stats_->setWindow(Rectangle(window_.size())); -+ -+ for (unsigned int i = 0; -+ i < (inputConfig_.patternSize.height + 1) && enableInputMemcpy_; -+ i++) { -+ /* pad with patternSize.Width on both left and right side */ -+ size_t lineLength = (window_.width + 2 * inputConfig_.patternSize.width) * -+ inputConfig_.bpp / 8; -+ -+ free(lineBuffers_[i]); -+ lineBuffers_[i] = (uint8_t *)malloc(lineLength); -+ if (!lineBuffers_[i]) -+ return -ENOMEM; -+ } -+ -+ measuredFrames_ = 0; -+ frameProcessTime_ = 0; -+ -+ return 0; -+} -+ -+Size DebayerCpu::patternSize(PixelFormat inputFormat) -+{ -+ DebayerCpu::DebayerInputConfig config; -+ -+ if (getInputConfig(inputFormat, config) != 0) -+ return {}; -+ -+ return config.patternSize; -+} -+ -+std::vector<PixelFormat> DebayerCpu::formats(PixelFormat inputFormat) -+{ -+ DebayerCpu::DebayerInputConfig config; -+ -+ if (getInputConfig(inputFormat, config) != 0) -+ return std::vector<PixelFormat>(); -+ -+ return config.outputFormats; -+} -+ -+std::tuple<unsigned int, unsigned int> -+DebayerCpu::strideAndFrameSize(const PixelFormat &outputFormat, const Size &size) -+{ -+ DebayerCpu::DebayerOutputConfig config; -+ -+ if (getOutputConfig(outputFormat, config) != 0) -+ return std::make_tuple(0, 0); -+ -+ /* round up to multiple of 8 for 64 bits alignment */ -+ unsigned int stride = (size.width * config.bpp / 8 + 7) & ~7; -+ -+ return std::make_tuple(stride, stride * size.height); -+} -+ -+void DebayerCpu::initLinePointers(const uint8_t *linePointers[], const uint8_t *src) -+{ -+ const int patternHeight = inputConfig_.patternSize.height; -+ -+ for (int i = 0; i < patternHeight; i++) -+ linePointers[i + 1] = src + -+ (-patternHeight / 2 + i) * (int)inputConfig_.stride; -+ -+ if (!enableInputMemcpy_) -+ return; -+ -+ for (int i = 0; i < patternHeight; i++) { -+ /* pad with patternSize.Width on both left and right side */ -+ size_t lineLength = (window_.width + 2 * inputConfig_.patternSize.width) * -+ inputConfig_.bpp / 8; -+ int padding = inputConfig_.patternSize.width * inputConfig_.bpp / 8; -+ -+ memcpy(lineBuffers_[i], linePointers[i + 1] - padding, lineLength); -+ linePointers[i + 1] = lineBuffers_[i] + padding; -+ } -+ -+ /* Point lineBufferIndex_ to first unused lineBuffer */ -+ lineBufferIndex_ = patternHeight; -+} -+ -+void DebayerCpu::shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src) -+{ -+ const int patternHeight = inputConfig_.patternSize.height; -+ -+ for (int i = 0; i < patternHeight; i++) -+ linePointers[i] = linePointers[i + 1]; -+ -+ linePointers[patternHeight] = src + -+ (patternHeight / 2) * (int)inputConfig_.stride; -+ -+ if (!enableInputMemcpy_) -+ return; -+ -+ size_t lineLength = (window_.width + 2 * inputConfig_.patternSize.width) * -+ inputConfig_.bpp / 8; -+ int padding = inputConfig_.patternSize.width * inputConfig_.bpp / 8; -+ memcpy(lineBuffers_[lineBufferIndex_], linePointers[patternHeight] - padding, lineLength); -+ linePointers[patternHeight] = lineBuffers_[lineBufferIndex_] + padding; -+ -+ lineBufferIndex_ = (lineBufferIndex_ + 1) % (patternHeight + 1); -+} -+ -+void DebayerCpu::process2(const uint8_t *src, uint8_t *dst) -+{ -+ const unsigned int y_end = window_.y + window_.height; -+ const uint8_t *linePointers[3]; -+ -+ /* Adjust src to top left corner of the window */ -+ src += window_.y * inputConfig_.stride + window_.x * inputConfig_.bpp / 8; -+ -+ initLinePointers(linePointers, src); -+ -+ for (unsigned int y = window_.y; y < y_end; y += 2) { -+ shiftLinePointers(linePointers, src); -+ stats_->processLine0(y, linePointers); -+ (this->*debayer0_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ -+ shiftLinePointers(linePointers, src); -+ (this->*debayer1_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ } -+} -+ -+void DebayerCpu::process4(const uint8_t *src, uint8_t *dst) -+{ -+ const unsigned int y_end = window_.y + window_.height; -+ const uint8_t *linePointers[5]; -+ -+ /* Adjust src to top left corner of the window */ -+ src += window_.y * inputConfig_.stride + window_.x * inputConfig_.bpp / 8; -+ -+ initLinePointers(linePointers, src); -+ -+ for (unsigned int y = window_.y; y < y_end; y += 4) { -+ shiftLinePointers(linePointers, src); -+ stats_->processLine0(y, linePointers); -+ (this->*debayer0_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ -+ shiftLinePointers(linePointers, src); -+ (this->*debayer1_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ -+ shiftLinePointers(linePointers, src); -+ stats_->processLine2(y, linePointers); -+ (this->*debayer2_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ -+ shiftLinePointers(linePointers, src); -+ (this->*debayer3_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ } -+} -+ -+static inline int64_t timeDiff(timespec &after, timespec &before) -+{ -+ return (after.tv_sec - before.tv_sec) * 1000000000LL + -+ (int64_t)after.tv_nsec - (int64_t)before.tv_nsec; -+} -+ -+void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams params) -+{ -+ timespec frameStartTime; -+ -+ if (measuredFrames_ < DebayerCpu::framesToMeasure) { -+ frameStartTime = {}; -+ clock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime); -+ } -+ -+ /* Apply DebayerParams */ -+ if (params.gamma != gamma_correction_) { -+ for (int i = 0; i < 1024; i++) -+ gamma_[i] = 255 * powf(i / 1023.0, params.gamma); -+ -+ gamma_correction_ = params.gamma; -+ } -+ -+ for (int i = 0; i < 256; i++) { -+ int idx; -+ -+ /* Apply gamma after gain! */ -+ idx = std::min({ i * params.gainR / 64U, 1023U }); -+ red_[i] = gamma_[idx]; -+ -+ idx = std::min({ i * params.gainG / 64U, 1023U }); -+ green_[i] = gamma_[idx]; -+ -+ idx = std::min({ i * params.gainB / 64U, 1023U }); -+ blue_[i] = gamma_[idx]; -+ } -+ -+ /* Copy metadata from the input buffer */ -+ FrameMetadata &metadata = output->_d()->metadata(); -+ metadata.status = input->metadata().status; -+ metadata.sequence = input->metadata().sequence; -+ metadata.timestamp = input->metadata().timestamp; -+ -+ MappedFrameBuffer in(input, MappedFrameBuffer::MapFlag::Read); -+ MappedFrameBuffer out(output, MappedFrameBuffer::MapFlag::Write); -+ if (!in.isValid() || !out.isValid()) { -+ LOG(Debayer, Error) << "mmap-ing buffer(s) failed"; -+ metadata.status = FrameMetadata::FrameError; -+ return; -+ } -+ -+ stats_->startFrame(); -+ -+ if (inputConfig_.patternSize.height == 2) -+ process2(in.planes()[0].data(), out.planes()[0].data()); -+ else -+ process4(in.planes()[0].data(), out.planes()[0].data()); -+ -+ metadata.planes()[0].bytesused = out.planes()[0].size(); -+ -+ /* Measure before emitting signals */ -+ if (measuredFrames_ < DebayerCpu::framesToMeasure && -+ ++measuredFrames_ > DebayerCpu::framesToSkip) { -+ timespec frameEndTime = {}; -+ clock_gettime(CLOCK_MONOTONIC_RAW, &frameEndTime); -+ frameProcessTime_ += timeDiff(frameEndTime, frameStartTime); -+ if (measuredFrames_ == DebayerCpu::framesToMeasure) { -+ const int measuredFrames = DebayerCpu::framesToMeasure - -+ DebayerCpu::framesToSkip; -+ LOG(Debayer, Info) -+ << "Processed " << measuredFrames -+ << " frames in " << frameProcessTime_ / 1000 << "us, " -+ << frameProcessTime_ / (1000 * measuredFrames) -+ << " us/frame"; -+ } -+ } -+ -+ stats_->finishFrame(); -+ outputBufferReady.emit(output); -+ inputBufferReady.emit(input); -+} -+ -+} /* namespace libcamera */ -diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build -index d4ae5ac7..6d7a44d7 100644 ---- a/src/libcamera/software_isp/meson.build -+++ b/src/libcamera/software_isp/meson.build -@@ -2,6 +2,7 @@ - - libcamera_sources += files([ - 'debayer.cpp', -+ 'debayer_cpu.cpp', - 'swstats.cpp', - 'swstats_cpu.cpp', - ]) --- -2.43.0 - |