Files
2023-10-13 14:01:41 +00:00

403 lines
15 KiB
C++

/*
* cac_algo_adaptor.h
*
* Copyright (c) 2021 Rockchip Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Cody Xie <cody.xie@rock-chips.com>
*/
#include "cac_adaptor.h"
#include <fstream>
#include <iostream>
#include "rk_aiq_types_priv.h"
#include "xcam_log.h"
#include <fcntl.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
using namespace XCam;
namespace RkCam {
#define BITS_PER_BYTE 8
#define BYTES_PER_WORD 4
#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD)
#define INTERP_CAC(x0, x1, ratio) ((ratio) * ((x1) - (x0)) + (x0))
#define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d))
enum class LutBufferState {
kInitial = MESH_BUF_INIT,
kWait2Chip = MESH_BUF_WAIT2CHIP,
kChipInUse = MESH_BUF_CHIPINUSE,
};
struct LutBufferConfig {
bool IsBigMode;
uint32_t Width;
uint32_t Height;
uint32_t LutHCount;
uint32_t LutVCount;
uint8_t ScaleFactor;
uint16_t PsfCfgCount;
};
static const uint32_t IspBigModeWidthLimit = 2688;
static const uint32_t IspBigModeSizeLimit = IspBigModeWidthLimit * 1536;
static const uint8_t CacScaleFactorDefault = 64;
static const uint8_t CacScaleFactorBigMode = 128;
static const uint8_t CacStrengthDistance = 128;
static const uint8_t CacPsfKernelSize = 7 * 5;
static const uint8_t CacPsfKernelWordSizeInMemory =
DIV_ROUND_UP((CacPsfKernelSize - 1) * BITS_PER_BYTE, BITS_PER_WORD);
static const uint8_t CacChannelCount = 2;
static const uint32_t CacPsfCountLimit = 1632;
static const uint8_t CacPsfBufferCount = ISP2X_MESH_BUF_NUM;
static inline bool IsIspBigMode(uint32_t width, uint32_t height, bool is_multi_sensor) {
if (is_multi_sensor || width > IspBigModeWidthLimit || width * height > IspBigModeSizeLimit)
return true;
else
return false;
};
/**
* cac_wsize=bigmode_en ? (pic_width+126)>>7 : (pic_width+62)>>6;
* cac_hsize=bigmode_en ? (pic_height+126)>>7 : (pic_height+62)>>6;
* lut_h_wsize = cac_wsize*9
* lut_v_size = cac_hsize*2
*/
static inline void CalcCacLutConfig(uint32_t width, uint32_t height, bool is_big_mode,
LutBufferConfig& config) {
config.Width = width;
config.Height = height;
config.IsBigMode = is_big_mode;
if (config.IsBigMode) {
config.ScaleFactor = CacScaleFactorBigMode;
} else {
config.ScaleFactor = CacScaleFactorDefault;
}
/**
* CAC only processes R & B channels, that means for R or R channels,
* which have only half size of full picture, only need to div round up by 32(scale==64) or
* 64(scale==128). For calculate convinient, use full picture size to calculate
*/
config.LutHCount = is_big_mode ? (width + 126) >> 7 : (width + 62) >> 6;
config.LutVCount = is_big_mode ? (height + 126) >> 7 : (height + 62) >> 6;
config.PsfCfgCount = config.LutHCount * config.LutVCount;
XCAM_ASSERT(config.PsfCfgCount <= CacPsfCountLimit);
/**
* CAC stores one PSF point's kernel in 9 words, one kernel size is 8 bytes.
* (8bytes*8bits/byte + 32 - 1) / 32bits/word = 9 words.
*/
}
struct LutBuffer {
LutBuffer() = delete;
LutBuffer(const LutBufferConfig& config)
: State(LutBufferState::kInitial), Config(config), Fd(-1), Size(0), Addr(0) {}
LutBuffer(const LutBufferConfig& config, const rk_aiq_cac_share_mem_info_t* mem_info)
: Config(config) {
State = static_cast<LutBufferState>(*mem_info->state);
Fd = mem_info->fd;
Addr = mem_info->addr;
Size = mem_info->size;
}
LutBuffer(const LutBuffer&) = delete;
LutBuffer& operator=(const LutBuffer&) = delete;
LutBufferState State;
LutBufferConfig Config;
int Fd;
int Size;
void* Addr;
};
class LutBufferManager {
public:
LutBufferManager() = delete;
LutBufferManager(const LutBufferConfig& config, const isp_drv_share_mem_ops_t* mem_ops)
: config_(config), mem_ops_(mem_ops) {}
LutBufferManager(const LutBufferManager&) = delete;
LutBufferManager& operator=(const LutBufferManager&) = delete;
~LutBufferManager() {
// TODO(Cody)
ReleaseHwBuffers(0);
ReleaseHwBuffers(1);
}
void ImportHwBuffers(uint8_t isp_id) {
assert(mem_ops_ != nullptr);
rk_aiq_share_mem_config_t hw_config_;
hw_config_.mem_type = MEM_TYPE_CAC;
hw_config_.alloc_param.width = config_.Width;
hw_config_.alloc_param.height = config_.Height;
mem_ops_->alloc_mem(isp_id, (void*)mem_ops_, &hw_config_, &mem_ctx_);
}
void ReleaseHwBuffers(uint8_t isp_id) {
if (mem_ctx_ && mem_ops_) mem_ops_->release_mem(isp_id, mem_ctx_);
}
LutBuffer* GetFreeHwBuffer(uint8_t isp_id) {
if (mem_ops_ == nullptr || mem_ctx_ == nullptr) {
return nullptr;
}
const auto* mem_info = reinterpret_cast<rk_aiq_cac_share_mem_info_t*>(
mem_ops_->get_free_item(isp_id, mem_ctx_));
if (mem_info != nullptr) {
return new LutBuffer(config_, mem_info);
}
return nullptr;
}
private:
const isp_drv_share_mem_ops_t* mem_ops_;
void* mem_ctx_;
LutBufferConfig config_;
};
CacAlgoAdaptor::~CacAlgoAdaptor() {
if (current_lut_[0]) delete current_lut_[0];
if (current_lut_[1]) delete current_lut_[1];
if (lut_manger_ != nullptr) delete lut_manger_;
}
XCamReturn CacAlgoAdaptor::Config(const AlgoCtxInstanceCfg* config,
const CalibDbV2_Cac_t* calib) {
LOGD_ACAC("%s : Enter", __func__);
enable_ = calib ? calib->SettingPara.enable : false;
calib_ = calib;
if (!enable_) {
return XCAM_RETURN_BYPASS;
}
if (access(calib->SettingPara.psf_path, O_RDONLY)) {
LOGE_ACAC("The PSF file path %s cannot be accessed", calib->SettingPara.psf_path);
valid_ = false;
return XCAM_RETURN_ERROR_FILE;
}
valid_ = true;
return XCAM_RETURN_NO_ERROR;
}
XCamReturn CacAlgoAdaptor::Prepare(const RkAiqAlgoConfigAcac* config) {
LutBufferConfig lut_config;
LutBufferConfig full_lut_config;
uint32_t width = config->width;
uint32_t height = config->height;
bool is_big_mode = IsIspBigMode(width, height, config->is_multi_sensor);
LOGD_ACAC("%s : Enter", __func__);
if (!enable_ || !valid_) {
return XCAM_RETURN_BYPASS;
}
config_ = config;
if (config->is_multi_isp) {
CalcCacLutConfig(width, height, is_big_mode, full_lut_config);
width = width / 2 + config->multi_isp_extended_pixel;
CalcCacLutConfig(width, height, is_big_mode, lut_config);
} else {
CalcCacLutConfig(width, height, is_big_mode, lut_config);
}
lut_manger_ = new LutBufferManager(lut_config, config->mem_ops);
lut_manger_->ImportHwBuffers(0);
current_lut_[0] = lut_manger_->GetFreeHwBuffer(0);
XCAM_ASSERT(current_lut_[0] != nullptr);
if (config->is_multi_isp) {
lut_manger_->ImportHwBuffers(1);
current_lut_[1] = lut_manger_->GetFreeHwBuffer(1);
XCAM_ASSERT(current_lut_[1] != nullptr);
}
std::ifstream ifs(calib_->SettingPara.psf_path, std::ios::binary);
if (!ifs.is_open()) {
LOGE_ACAC("Failed to open PSF file %s", calib_->SettingPara.psf_path);
valid_ = false;
return XCAM_RETURN_ERROR_FILE;
} else {
if (!config->is_multi_isp) {
uint32_t line_offset = lut_config.LutHCount * CacPsfKernelWordSizeInMemory * BYTES_PER_WORD;
uint32_t size = lut_config.LutHCount * lut_config.LutVCount * CacPsfKernelWordSizeInMemory * BYTES_PER_WORD;
for (int ch = 0; ch < CacChannelCount; ch++) {
char* addr0 = reinterpret_cast<char*>(current_lut_[0]->Addr) +
ch * size;
ifs.read(addr0, size);
}
} else {
// Read and Split Memory
// a == line_size - line_offset
// b == line_offset
// c == line_offset - a = 2 * line_offset - line_size
// For each line:
// read b size to left
// copy c from left to right
// read a' to right
// - +---------------------------+
// | |<---a---->| | |<---a'--->|
// | | |<-c->| |
// v |<---b---------->| |
// | | | | | |
// - +---------------------------+
// |<---------line_size------->|
//
uint32_t line_offset = lut_config.LutHCount * CacPsfKernelWordSizeInMemory * BYTES_PER_WORD;
uint32_t line_size = full_lut_config.LutHCount * CacPsfKernelWordSizeInMemory * BYTES_PER_WORD;
for (int ch = 0; ch < CacChannelCount; ch++) {
char* addr0 = reinterpret_cast<char*>(current_lut_[0]->Addr) +
ch * line_offset * lut_config.LutVCount;
char* addr1 = reinterpret_cast<char*>(current_lut_[1]->Addr) +
ch * line_offset * lut_config.LutVCount;
for (uint32_t i = 0; i < full_lut_config.LutVCount; i++) {
ifs.read(addr0 + (i * line_offset), line_offset);
memcpy(addr1 + (i * line_offset),
addr0 + (i * line_offset) + line_size - line_offset,
2 * line_offset - line_size);
ifs.read(addr1 + (i * line_size) + line_offset, line_size - line_offset);
}
}
}
}
return XCAM_RETURN_NO_ERROR;
}
void CacAlgoAdaptor::OnFrameEvent(const RkAiqAlgoProcAcac* input,
RkAiqAlgoProcResAcac* output) {
int i;
int iso_low = 50;
int iso_high = 50;
int gain_high, gain_low;
float ratio;
int iso_div = 50;
int max_iso_step = RKCAC_MAX_ISO_LEVEL;
int iso = input->iso;
LOGD_ACAC("%s : Enter", __func__);
if (!enable_ || !valid_) {
output->config[0].bypass_en = 1;
output->config[1].bypass_en = 1;
return;
}
for (i = max_iso_step - 1; i >= 0; i--) {
if (iso < iso_div * (2 << i)) {
iso_low = iso_div * (2 << (i)) / 2;
iso_high = iso_div * (2 << i);
}
}
ratio = (float)(iso - iso_low) / (iso_high - iso_low);
if (iso_low == iso) {
iso_high = iso;
ratio = 0;
}
if (iso_high == iso) {
iso_low = iso;
ratio = 1;
}
gain_high = (int)(log((float)iso_high / 50) / log((float)2));
gain_low = (int)(log((float)iso_low / 50) / log((float)2));
gain_low = MIN(MAX(gain_low, 0), max_iso_step - 1);
gain_high = MIN(MAX(gain_high, 0), max_iso_step - 1);
XCAM_ASSERT(gain_low >= 0 && gain_low < max_iso_step);
XCAM_ASSERT(gain_high >= 0 && gain_high < max_iso_step);
#if 0
output->config[0].strength[0] = 128;
output->config[0].strength[1] = 256;
output->config[0].strength[2] = 384;
output->config[0].strength[3] = 512;
output->config[0].strength[4] = 640;
output->config[0].strength[5] = 768;
output->config[0].strength[6] = 896;
output->config[0].strength[7] = 1024;
output->config[0].strength[8] = 1152;
output->config[0].strength[9] = 1280;
output->config[0].strength[10] = 1408;
output->config[0].strength[11] = 1536;
output->config[0].strength[12] = 1568;
output->config[0].strength[13] = 1600;
output->config[0].strength[14] = 1632;
output->config[0].strength[15] = 1664;
output->config[0].strength[16] = 1696;
output->config[0].strength[17] = 1728;
output->config[0].strength[18] = 1760;
output->config[0].strength[19] = 1792;
output->config[0].strength[20] = 1824;
output->config[0].strength[21] = 2047;
#endif
float strength[RKCAC_STRENGTH_TABLE_LEN] = {1.0f};
for (i = 0; i < RKCAC_STRENGTH_TABLE_LEN; i++) {
strength[i] =
INTERP_CAC(calib_->TuningPara.SettingByIso[gain_low].strength_table[i],
calib_->TuningPara.SettingByIso[gain_high].strength_table[i], ratio);
output->config[0].strength[i] = ROUND_F(strength[i] * (1 << RKCAC_STRENGTH_FIX_BITS));
output->config[0].strength[i] =
output->config[0].strength[i] > 2047 ? 2047 : output->config[0].strength[i];
}
output->config[0].bypass_en =
INTERP_CAC(calib_->TuningPara.SettingByIso[gain_low].bypass,
calib_->TuningPara.SettingByIso[gain_high].bypass, ratio);
output->config[0].center_en = calib_->SettingPara.center_en;
output->config[0].center_width = calib_->SettingPara.center_x;
output->config[0].center_height = calib_->SettingPara.center_y;
output->config[0].psf_sft_bit = calib_->SettingPara.psf_shift_bits;
output->config[0].cfg_num = current_lut_[0]->Config.PsfCfgCount;
output->config[0].buf_fd = current_lut_[0]->Fd;
output->config[0].hsize = current_lut_[0]->Config.LutHCount * CacPsfKernelWordSizeInMemory;
output->config[0].vsize = current_lut_[0]->Config.LutVCount * CacChannelCount;
if (current_lut_[1]) {
memcpy(&output->config[1], &output->config[0], sizeof(output->config[0]));
output->config[1].buf_fd = current_lut_[1]->Fd;
if (output->config[0].center_en) {
uint16_t w = config_->width / 4;
uint16_t e = config_->multi_isp_extended_pixel / 4;
uint16_t x = calib_->SettingPara.center_x;
output->config[1].center_width = x - (w / 2 - e);
}
}
LOGD_ACAC("global en : %d", calib_->SettingPara.enable);
LOGD_ACAC("current bypass: %d", output->config[0].bypass_en);
LOGD_ACAC("center en: %d", output->config[0].center_en);
LOGD_ACAC("center x: %u", output->config[0].center_width);
LOGD_ACAC("center y: %u", output->config[0].center_height);
LOGD_ACAC("psf shift bits: %u", output->config[0].psf_sft_bit);
LOGD_ACAC("psf cfg num: %u", output->config[0].cfg_num);
LOGD_ACAC("psf buf fd: %d", output->config[0].buf_fd);
if (current_lut_[1]) {
LOGD_ACAC("psf buf fd right: %d", output->config[1].buf_fd);
LOGD_ACAC("center x right: %d", output->config[1].center_width);
LOGD_ACAC("center y right: %d", output->config[1].center_height);
}
LOGD_ACAC("psf hwsize: %u", output->config[0].hsize);
LOGD_ACAC("psf size: %u", output->config[0].vsize);
for (i = 0; i < RKCAC_STRENGTH_TABLE_LEN; i++) {
LOGD_ACAC("strength %d: %u", i, output->config[0].strength[i]);
}
}
} // namespace RkCam