From 66ef9f32e67a96655d10ba38f7a830b3bbfe50f2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 14 Dec 2023 19:09:44 +0100 Subject: [PATCH 16/25] libcamera: swstats_cpu: Add support for 8, 10 and 12 bpp unpacked bayer input Add support for 8, 10 and 12 bpp unpacked bayer input for all 4 standard bayer orders. Tested-by: Bryan O'Donoghue # sc8280xp Lenovo x13s Tested-by: Pavel Machek Signed-off-by: Kieran Bingham Signed-off-by: Hans de Goede --- .../internal/software_isp/swstats_cpu.h | 9 ++ src/libcamera/software_isp/swstats_cpu.cpp | 126 ++++++++++++++++++ 2 files changed, 135 insertions(+) diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h index 8bb86e98..e7abc6bb 100644 --- a/include/libcamera/internal/software_isp/swstats_cpu.h +++ b/include/libcamera/internal/software_isp/swstats_cpu.h @@ -11,6 +11,7 @@ #pragma once +#include "libcamera/internal/bayer_format.h" #include "libcamera/internal/shared_mem_object.h" #include "libcamera/internal/software_isp/swisp_stats.h" #include "libcamera/internal/software_isp/swstats.h" @@ -31,6 +32,14 @@ public: const SharedFD &getStatsFD() { return sharedStats_.fd(); } int configure(const StreamConfiguration &inputCfg); private: + int setupStandardBayerOrder(BayerFormat::Order order); + /* Bayer 8 bpp unpacked */ + void statsBGGR8Line0(const uint8_t *src[]); + /* Bayer 10 bpp unpacked */ + void statsBGGR10Line0(const uint8_t *src[]); + /* Bayer 12 bpp unpacked */ + void statsBGGR12Line0(const uint8_t *src[]); + /* Bayer 10 bpp packed */ void statsBGGR10PLine0(const uint8_t *src[]); void statsGBRG10PLine0(const uint8_t *src[]); void resetStats(void); diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp index 59453d07..87550371 100644 --- a/src/libcamera/software_isp/swstats_cpu.cpp +++ b/src/libcamera/software_isp/swstats_cpu.cpp @@ -59,6 +59,83 @@ static const unsigned int BLUE_Y_MUL = 29; /* 0.11 * 256 */ stats_.sumG_ += sumG; \ stats_.sumB_ += sumB; +void SwStatsCpu::statsBGGR8Line0(const uint8_t *src[]) +{ + const uint8_t *src0 = src[1] + window_.x; + const uint8_t *src1 = src[2] + window_.x; + + SWISP_LINARO_START_LINE_STATS(uint8_t) + + if (swap_lines_) + std::swap(src0, src1); + + /* x += 4 sample every other 2x2 block */ + for (int x = 0; x < (int)window_.width; x += 4) { + b = src0[x]; + g = src0[x + 1]; + g2 = src1[x]; + r = src1[x + 1]; + + g = (g + g2) / 2; + + SWISP_LINARO_ACCUMULATE_LINE_STATS(1) + } + + SWISP_LINARO_FINISH_LINE_STATS() +} + +void SwStatsCpu::statsBGGR10Line0(const uint8_t *src[]) +{ + const uint16_t *src0 = (const uint16_t *)src[1] + window_.x; + const uint16_t *src1 = (const uint16_t *)src[2] + window_.x; + + SWISP_LINARO_START_LINE_STATS(uint16_t) + + if (swap_lines_) + std::swap(src0, src1); + + /* x += 4 sample every other 2x2 block */ + for (int x = 0; x < (int)window_.width; x += 4) { + b = src0[x]; + g = src0[x + 1]; + g2 = src1[x]; + r = src1[x + 1]; + + g = (g + g2) / 2; + + /* divide Y by 4 for 10 -> 8 bpp value */ + SWISP_LINARO_ACCUMULATE_LINE_STATS(4) + } + + SWISP_LINARO_FINISH_LINE_STATS() +} + +void SwStatsCpu::statsBGGR12Line0(const uint8_t *src[]) +{ + const uint16_t *src0 = (const uint16_t *)src[1] + window_.x; + const uint16_t *src1 = (const uint16_t *)src[2] + window_.x; + + SWISP_LINARO_START_LINE_STATS(uint16_t) + + if (swap_lines_) + std::swap(src0, src1); + + /* x += 4 sample every other 2x2 block */ + for (int x = 0; x < (int)window_.width; x += 4) { + b = src0[x]; + g = src0[x + 1]; + g2 = src1[x]; + r = src1[x + 1]; + + g = (g + g2) / 2; + + /* divide Y by 16 for 12 -> 8 bpp value */ + SWISP_LINARO_ACCUMULATE_LINE_STATS(16) + } + + SWISP_LINARO_FINISH_LINE_STATS() +} + static inline __attribute__((always_inline)) void statsBayer10P(const int width, const uint8_t *src0, const uint8_t *src1, bool bggr, SwIspStats &stats_) { @@ -124,6 +201,39 @@ void SwStatsCpu::finishStats(void) statsReady.emit(0); } +/* + * Check if order is a standard Bayer order and setup x_shift_ and swap_lines_ + * so that a single BGGR stats function can be used for all 4 standard orders. + */ +int SwStatsCpu::setupStandardBayerOrder(BayerFormat::Order order) +{ + switch (order) { + case BayerFormat::BGGR: + x_shift_ = 0; + swap_lines_ = false; + break; + case BayerFormat::GBRG: + x_shift_ = 1; /* BGGR -> GBRG */ + swap_lines_ = false; + break; + case BayerFormat::GRBG: + x_shift_ = 0; + swap_lines_ = true; /* BGGR -> GRBG */ + break; + case BayerFormat::RGGB: + x_shift_ = 1; /* BGGR -> GBRG */ + swap_lines_ = true; /* GBRG -> RGGB */ + break; + default: + return -EINVAL; + } + + patternSize_.height = 2; + patternSize_.width = 2; + y_skip_mask_ = 0x02; /* Skip every 3th and 4th line */ + return 0; +} + int SwStatsCpu::configure(const StreamConfiguration &inputCfg) { BayerFormat bayerFormat = @@ -132,6 +242,22 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg) startFrame_ = (SwStats::statsVoidFn)&SwStatsCpu::resetStats; finishFrame_ = (SwStats::statsVoidFn)&SwStatsCpu::finishStats; + if (bayerFormat.packing == BayerFormat::Packing::None && + setupStandardBayerOrder(bayerFormat.order) == 0) { + bpp_ = (bayerFormat.bitDepth + 7) & ~7; + switch (bayerFormat.bitDepth) { + case 8: + stats0_ = (SwStats::statsProcessFn)&SwStatsCpu::statsBGGR8Line0; + return 0; + case 10: + stats0_ = (SwStats::statsProcessFn)&SwStatsCpu::statsBGGR10Line0; + return 0; + case 12: + stats0_ = (SwStats::statsProcessFn)&SwStatsCpu::statsBGGR12Line0; + return 0; + } + } + if (bayerFormat.bitDepth == 10 && bayerFormat.packing == BayerFormat::Packing::CSI2) { bpp_ = 10; -- 2.43.0