From patchwork Thu Dec 14 12:13:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 19318 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 786A3C3292 for ; Thu, 14 Dec 2023 12:14:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1C92062B4A; Thu, 14 Dec 2023 13:14:04 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1702556044; bh=HGoZ/2miZ0DnzfXtEPZ5obtr5/e2y45lUGzw4o3mEBk=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=ctTbEcH9gBzCIx1tNsHEigeVS5r93uJBoNQN8Dakyv7+6fhwmfq6ad6/3wze6ECBY w8Uk870ODinN6hA/jIEIK5js5r+2WQY+sWwuipBSXe5kYemdPPkEhhx+C5OzlmY1Nm Bc17u1f/O4sJhzhgyC/tTXYTPNZ+ctlRAitJ7vIEPruYTvdfOmJeqvu6C8QsmjQssI 3zCCJhAkM5fgjuP+r98W1KXYw9uyhfORD7xxcR78msePnNc1Y56L9RzgBzAgVvbYHk KIxZtkgc6IYt5lWffIAog4a6G98E01d+1ZtLXw7sWf0v0cYNTpQZuzD/wyulrpbpZ7 uEny4TsftO0vg== Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 15CB161D97 for ; Thu, 14 Dec 2023 13:14:02 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="h8LRWqQ1"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1702556041; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=jb1x2doyAt9CwBVHIyjwa9LcY/h0jg/Vb4MkHLGfX6I=; b=h8LRWqQ1Wbt20VBMgvT4oopmd6ZyRs9/sNfIlMKVQPa4Cuwtn0MG96Yb/IZnrldzM/SnNf R5M9pmgWU2zKlTwrJ9FUiMmpj5eVJLT13HcOwlb9BF15jWaGtqsbAyFLVG+c+ER6+pUimZ YCh8DiLdU8D0yjfvmdEziDnx1+kNOSQ= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-637-rWsdU6djMhW3DP-oEIcReQ-1; Thu, 14 Dec 2023 07:13:57 -0500 X-MC-Unique: rWsdU6djMhW3DP-oEIcReQ-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id BBA538630C5; Thu, 14 Dec 2023 12:13:56 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.194.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id 481B31121306; Thu, 14 Dec 2023 12:13:55 +0000 (UTC) To: libcamera-devel@lists.libcamera.org, Andrey Konovalov Date: Thu, 14 Dec 2023 13:13:41 +0100 Message-ID: <20231214121350.206015-4-hdegoede@redhat.com> In-Reply-To: <20231214121350.206015-1-hdegoede@redhat.com> References: <20231214121350.206015-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [libcamera-devel] [PATCH 03/11] libcamera: software_isp: Add SwStats base class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Hans de Goede via libcamera-devel From: Hans de Goede Reply-To: Hans de Goede Cc: Maxime Ripard , g.martti@gmail.com, t.langendam@gmail.com, srinivas.kandagatla@linaro.org, Bryan O'Donoghue , admin@dennisbonke.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a virtual base class for CPU based software statistics gathering implementations. The idea is for the implementations to offer a configure function + functions to gather statistics on a line by line basis. This allows CPU based software debayering to call into interlace debayering and statistics gathering on a line by line bases while the input data is still hot in the cache. This base class also allows the user of an implementation to specify a window over which to gather statistics instead of processing the whole frame; and it allows the implementation to choose to only process 1/2, 1/4th, etc. of the lines instead of processing all lines (in the window) by setting y_skip_mask_ from configure(). Skipping columns is left up the line-processing functions provided by the implementation. The base class also provides a processFrame() convenience function which collects statistics for an entire frame at once for use cases where CPU based software debayering is not used. Co-authored-by: Andrey Konovalov Signed-off-by: Andrey Konovalov Signed-off-by: Hans de Goede --- .../internal/software_isp/meson.build | 6 + .../internal/software_isp/swisp_stats.h | 21 +++ .../libcamera/internal/software_isp/swstats.h | 150 ++++++++++++++++++ src/libcamera/software_isp/meson.build | 5 + src/libcamera/software_isp/swstats.cpp | 65 ++++++++ 5 files changed, 247 insertions(+) create mode 100644 include/libcamera/internal/software_isp/meson.build create mode 100644 include/libcamera/internal/software_isp/swisp_stats.h create mode 100644 include/libcamera/internal/software_isp/swstats.h create mode 100644 src/libcamera/software_isp/meson.build create mode 100644 src/libcamera/software_isp/swstats.cpp diff --git a/include/libcamera/internal/software_isp/meson.build b/include/libcamera/internal/software_isp/meson.build new file mode 100644 index 00000000..1c43acc4 --- /dev/null +++ b/include/libcamera/internal/software_isp/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: CC0-1.0 + +libcamera_internal_headers += files([ + 'swisp_stats.h', + 'swstats.h', +]) diff --git a/include/libcamera/internal/software_isp/swisp_stats.h b/include/libcamera/internal/software_isp/swisp_stats.h new file mode 100644 index 00000000..f7afbaa4 --- /dev/null +++ b/include/libcamera/internal/software_isp/swisp_stats.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * + * swisp_stats.h - Statistics data format used by the software ISP and software IPA + */ + +#pragma once + +namespace libcamera { + +struct SwIspStats { + unsigned long sumR_; + unsigned long sumB_; + unsigned long sumG_; + + float bright_ratio; + float too_bright_ratio; +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/software_isp/swstats.h b/include/libcamera/internal/software_isp/swstats.h new file mode 100644 index 00000000..0e7407f6 --- /dev/null +++ b/include/libcamera/internal/software_isp/swstats.h @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * Copyright (C) 2023, Red Hat Inc. + * + * Authors: + * Hans de Goede + * + * swstats.h - software statistics base class + */ + +#pragma once + +#include + +#include +#include + +#include + +namespace libcamera { + +class PixelFormat; +struct SharedFD; +struct StreamConfiguration; + +LOG_DECLARE_CATEGORY(SwStats) + +class SwStats +{ +public: + virtual ~SwStats() = 0; + + virtual bool isValid() const = 0; + + /* + * Setup the SwStats object for the passed in input format. + * Return 0 on success, a negative errno value on failure + * (unsupported format or failed to create the SharedMemObject). + */ + virtual int configure(const StreamConfiguration &inputCfg) = 0; + + /* Get the FD for the SharedMemObject for the stats. */ + virtual const SharedFD &getStatsFD() = 0; + +protected: + typedef void (SwStats::*statsProcessFn)(const uint8_t *src, unsigned int stride); + typedef void (SwStats::*statsVoidFn)(); + + /* Variables set by configure(), used every line */ + statsProcessFn stats0_; + statsProcessFn stats2_; + + unsigned int bpp_; /* Memory used per pixel, not precision */ + unsigned int y_skip_mask_; /* Skip lines where this bitmask is set in y */ + + /* Statistics windows, set by setWindow(), used every line */ + Rectangle window_; + + /* Variables set by configure(), used once per frame */ + statsVoidFn startFrame_; + statsVoidFn finishFrame_; + Size patternSize_; + unsigned int x_shift_; /* Offset of 0/1 applied to window_.x for bayer variants */ + +public: + /* + * For some input-formats, e.g. Bayer data, processing is done multiple lines + * and/or columns at a time. Get width and height at which the (bayer) pattern + * repeats. Window values are rounded down to a multiple of this and the height + * also indicates if processLine2() should be called or not. + * This may only be called after a successful configure() call. + */ + const Size &patternSize() { return patternSize_; } + + /* + * Specify window coordinates over which to gather statistics. + */ + void setWindow(Rectangle window) + { + window_ = window; + + window_.x &= ~(patternSize_.width - 1); + window_.x += x_shift_; + window_.y &= ~(patternSize_.height - 1); + + /* width_ - x_shift_ to make sure the window fits */ + window_.width -= x_shift_; + window_.width &= ~(patternSize_.width - 1); + window_.height &= ~(patternSize_.height - 1); + } + + /* + * Reset state to start statistic gathering for a new frame. + * This may only be called after a successful setWindow() call. + */ + void startFrame() + { + (this->*startFrame_)(); + } + + /* + * Process line 0 of input formats with patternSize height == 1. + * Process line 0 + 1 of input formats with patternSize height >= 2. + * This may only be called after a successful setWindow() call. + */ + void processLine0(unsigned int y, const uint8_t *src, unsigned int stride) + { + if ((y & y_skip_mask_) || y < (unsigned int)window_.y || + y >= (window_.y + window_.height)) + return; + + (this->*stats0_)(src + window_.x * bpp_ / 8, stride); + } + + /* + * Process lines 2 + 3 of input formats with patternSize height == 4. + * This may only be called after a successful setWindow() call. + */ + void processLine2(unsigned int y, const uint8_t *src, unsigned int stride) + { + if ((y & y_skip_mask_) || y < (unsigned int)window_.y || + y >= (window_.y + window_.height)) + return; + + (this->*stats2_)(src + window_.x * bpp_ / 8, stride); + } + + /* + * Finish statistics calculation for current frame and + * store the results in the SharedMemObject. + * This may only be called after a successful setWindow() call. + */ + void finishFrame() + { + (this->*finishFrame_)(); + } + + /* + * Process a whole frame at once, replacing manually calling + * startFrame() + processLine0() + finishFrame(). + * This may only be called after a successful setWindow() call. + */ + void processFrame(const uint8_t *src, unsigned int stride); + + /* The int parameter isn't actually used */ + Signal statsReady; +}; + +} /* namespace libcamera */ diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build new file mode 100644 index 00000000..9359075d --- /dev/null +++ b/src/libcamera/software_isp/meson.build @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: CC0-1.0 + +libcamera_sources += files([ + 'swstats.cpp', +]) diff --git a/src/libcamera/software_isp/swstats.cpp b/src/libcamera/software_isp/swstats.cpp new file mode 100644 index 00000000..9a5e1a10 --- /dev/null +++ b/src/libcamera/software_isp/swstats.cpp @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * Copyright (C) 2023, Red Hat Inc. + * + * Authors: + * Hans de Goede + * + * swstats.cpp - software statistics base class + */ + +#include "libcamera/internal/software_isp/swstats.h" + +namespace libcamera { + +LOG_DEFINE_CATEGORY(SwStats) + +void SwStats::processFrame(const uint8_t *src, unsigned int stride) +{ + unsigned int y_end = window_.y + window_.height; + + startFrame(); + + /* Adjust src to point to starting corner of the statistics window */ + src += window_.y * stride; + src += window_.x * bpp_ / 8; + + switch (patternSize_.height) { + case 1: + for (unsigned int y = window_.y ; y < y_end; y++) { + if (!(y & y_skip_mask_)) + (this->*stats0_)(src, stride); + src += stride; + } + break; + case 2: + for (unsigned int y = window_.y ; y < y_end; y += 2) { + if (!(y & y_skip_mask_)) + (this->*stats0_)(src, stride); + src += 2 * stride; + } + break; + case 4: + for (unsigned int y = window_.y ; y < y_end; y += 4) { + if (y & y_skip_mask_) { + src += 4 * stride; + continue; + } + + (this->*stats0_)(src, stride); + src += 2 * stride; + (this->*stats2_)(src, stride); + src += 2 * stride; + } + break; + } + + finishFrame(); +} + +SwStats::~SwStats() +{ +} + +} /* namespace libcamera */