When calling `Debayer::process()` from `SoftwareIsp::process()`, the
`DebayerParams` object is copied multiple times:
(1) call of `BoundMethodMember<...>::activate()`
inside `Object::invokeMethod()`
(2) constructor of `BoundMethodArgs<...>`
inside `BoundMethodMember<...>::activate()`
(3) call of `BoundMethodMember<...>::invoke()`
inside `BoundMethodArgs::invokePack()`
(4) call of the actual pointer to member function
inside `BoundMethodMember::invoke()`
While compilers might avoid one or two of the above copies, this is still
not ideal. By making `Debayer::process()` take the parameter object by
const lvalue reference, only the copy in the `BoundMethodArgs` constructor
remains. So do that.
Before:
[0:12:51.133836595] [12424] DEBUG SoftwareIsp software_isp.cpp:399 params=0x7d0a691f57d0
copy from 0x7d0a691f57d0 into 0x7baa65f2bf30
copy from 0x7baa65f2bf30 into 0x7c6a69209758
copy from 0x7c6a69209758 into 0x7baa63223930
copy from 0x7baa63223930 into 0x7baa63223a70
[0:12:51.134559602] [12426] DEBUG eGL debayer_egl.cpp:538 params=0x7baa63223a70
771.099877 (30.06 fps) cam0-stream0 seq: 000031 bytesused: 8666112
After:
[0:13:42.861691943] [12543] DEBUG SoftwareIsp software_isp.cpp:399 params=0x7cfaad5f57d0
copy from 0x7cfaad5f57d0 into 0x7c5aad609758
[0:13:42.862453917] [12545] DEBUG eGL debayer_egl.cpp:538 params=0x7c5aad609758
822.827388 (30.02 fps) cam0-stream0 seq: 000031 bytesused: 8666112
Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
154 lines
5.9 KiB
C++
154 lines
5.9 KiB
C++
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
/*
|
|
* Copyright (C) 2023, Linaro Ltd
|
|
* Copyright (C) 2023-2026 Red Hat Inc.
|
|
*
|
|
* Authors:
|
|
* Hans de Goede <hdegoede@redhat.com>
|
|
*
|
|
* CPU based debayering header
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
#include <stdint.h>
|
|
#include <vector>
|
|
|
|
#include <libcamera/base/object.h>
|
|
|
|
#include "libcamera/internal/bayer_format.h"
|
|
#include "libcamera/internal/global_configuration.h"
|
|
#include "libcamera/internal/software_isp/debayer_params.h"
|
|
#include "libcamera/internal/software_isp/swstats_cpu.h"
|
|
|
|
#include "debayer.h"
|
|
|
|
namespace libcamera {
|
|
|
|
class DebayerCpu : public Debayer
|
|
{
|
|
public:
|
|
DebayerCpu(std::unique_ptr<SwStatsCpu> stats, const GlobalConfiguration &configuration);
|
|
~DebayerCpu();
|
|
|
|
int configure(const StreamConfiguration &inputCfg,
|
|
const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs,
|
|
bool ccmEnabled);
|
|
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(uint32_t frame, FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms);
|
|
SizeRange sizes(PixelFormat inputFormat, const Size &inputSize);
|
|
const SharedFD &getStatsFD() { return stats_->getStatsFD(); }
|
|
|
|
private:
|
|
/**
|
|
* \brief Called to debayer 1 line of Bayer input data to output format
|
|
* \param[out] dst Pointer to the start of the output line to write
|
|
* \param[in] src The input data
|
|
*
|
|
* Input data is an array of (patternSize_.height + 1) src
|
|
* pointers each pointing to a line in the Bayer source. The middle
|
|
* element of the array will point to the actual line being processed.
|
|
* Earlier element(s) will point to the previous line(s) and later
|
|
* element(s) to the next line(s).
|
|
*
|
|
* These functions take an array of src pointers, rather than
|
|
* a single src pointer + a stride for the source, so that when the src
|
|
* is slow uncached memory it can be copied to faster memory before
|
|
* debayering. Debayering a standard 2x2 Bayer pattern requires access
|
|
* to the previous and next src lines for interpolating the missing
|
|
* colors. To allow copying the src lines only once 3 temporary buffers
|
|
* each holding a single line are used, re-using the oldest buffer for
|
|
* the next line and the pointers are swizzled so that:
|
|
* src[0] = previous-line, src[1] = currrent-line, src[2] = next-line.
|
|
* This way the 3 pointers passed to the debayer functions form
|
|
* a sliding window over the src avoiding the need to copy each
|
|
* line more than once.
|
|
*
|
|
* Similarly for bayer patterns which repeat every 4 lines, 5 src
|
|
* pointers are passed holding: src[0] = 2-lines-up, src[1] = 1-line-up
|
|
* src[2] = current-line, src[3] = 1-line-down, src[4] = 2-lines-down.
|
|
*/
|
|
using debayerFn = void (DebayerCpu::*)(uint8_t *dst, const uint8_t *src[]);
|
|
|
|
/* 8-bit raw bayer format */
|
|
template<bool addAlphaByte, bool ccmEnabled>
|
|
void debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);
|
|
template<bool addAlphaByte, bool ccmEnabled>
|
|
void debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);
|
|
/* unpacked 10-bit raw bayer format */
|
|
template<bool addAlphaByte, bool ccmEnabled>
|
|
void debayer10_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);
|
|
template<bool addAlphaByte, bool ccmEnabled>
|
|
void debayer10_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);
|
|
/* unpacked 12-bit raw bayer format */
|
|
template<bool addAlphaByte, bool ccmEnabled>
|
|
void debayer12_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);
|
|
template<bool addAlphaByte, bool ccmEnabled>
|
|
void debayer12_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);
|
|
/* CSI-2 packed 10-bit raw bayer format (all the 4 orders) */
|
|
template<bool addAlphaByte, bool ccmEnabled>
|
|
void debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);
|
|
template<bool addAlphaByte, bool ccmEnabled>
|
|
void debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);
|
|
template<bool addAlphaByte, bool ccmEnabled>
|
|
void debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[]);
|
|
template<bool addAlphaByte, bool ccmEnabled>
|
|
void debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[]);
|
|
|
|
static int getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config);
|
|
static int getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config);
|
|
int setupStandardBayerOrder(BayerFormat::Order order);
|
|
int setDebayerFunctions(PixelFormat inputFormat,
|
|
PixelFormat outputFormat,
|
|
bool ccmEnabled);
|
|
void setupInputMemcpy(const uint8_t *linePointers[]);
|
|
void shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src);
|
|
void memcpyNextLine(const uint8_t *linePointers[]);
|
|
void process2(uint32_t frame, const uint8_t *src, uint8_t *dst);
|
|
void process4(uint32_t frame, const uint8_t *src, uint8_t *dst);
|
|
void updateGammaTable(const DebayerParams ¶ms);
|
|
void updateLookupTables(const DebayerParams ¶ms);
|
|
|
|
/* Max. supported Bayer pattern height is 4, debayering this requires 5 lines */
|
|
static constexpr unsigned int kMaxLineBuffers = 5;
|
|
|
|
static constexpr unsigned int kRGBLookupSize = 256;
|
|
static constexpr unsigned int kGammaLookupSize = 1024;
|
|
struct CcmColumn {
|
|
int16_t r;
|
|
int16_t g;
|
|
int16_t b;
|
|
};
|
|
using LookupTable = std::array<uint8_t, kRGBLookupSize>;
|
|
using CcmLookupTable = std::array<CcmColumn, kRGBLookupSize>;
|
|
LookupTable red_;
|
|
LookupTable green_;
|
|
LookupTable blue_;
|
|
CcmLookupTable redCcm_;
|
|
CcmLookupTable greenCcm_;
|
|
CcmLookupTable blueCcm_;
|
|
std::array<double, kGammaLookupSize> gammaTable_;
|
|
LookupTable gammaLut_;
|
|
bool ccmEnabled_;
|
|
DebayerParams params_;
|
|
|
|
debayerFn debayer0_;
|
|
debayerFn debayer1_;
|
|
debayerFn debayer2_;
|
|
debayerFn debayer3_;
|
|
Rectangle window_;
|
|
std::unique_ptr<SwStatsCpu> stats_;
|
|
std::vector<uint8_t> lineBuffers_[kMaxLineBuffers];
|
|
unsigned int lineBufferLength_;
|
|
unsigned int lineBufferPadding_;
|
|
unsigned int lineBufferIndex_;
|
|
unsigned int xShift_; /* Offset of 0/1 applied to window_.x */
|
|
bool enableInputMemcpy_;
|
|
};
|
|
|
|
} /* namespace libcamera */
|