blob: ef1d279e7bd6f8e51c05156c2f187b5d76c2e719 [file] [log] [blame]
/*
* Copyright (C) 2019-2020 Intel Corporation.
*
* 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.
*/
#define LOG_TAG "PGCommon"
#include "PGCommon.h"
#include <stdint.h>
#include <math.h>
#include <utility>
#include "iutils/Utils.h"
#include "iutils/CameraLog.h"
#include "iutils/CameraDump.h"
namespace icamera {
#define IS_VALID_TERMINAL(terminal) (terminal >=0 && terminal < mTerminalCount)
int PGCommon::getFrameSize(int format, int width, int height,
bool needAlignedHeight, bool needExtraSize, bool needCompression)
{
int size = 0;
int cssFormat = PGUtils::getCssFmt(format);
int stride = PGUtils::getCssStride(format, width);
switch (cssFormat) {
case IA_CSS_DATA_FORMAT_BAYER_LINE_INTERLEAVED: // CSL6
if (needAlignedHeight) {
height = ALIGN_64(height);
}
size = stride * height * 3 / 2;
break;
default:
break;
}
if (!size) {
size = CameraUtils::getFrameSize(format, width, height,
needAlignedHeight, needExtraSize, needCompression);
}
return size;
}
PGCommon::PGCommon(int pgId, const std::string& pgName, ia_uid terminalBaseUid):
mCtx(nullptr),
mManifestBuffer(nullptr),
mPGParamsBuffer(nullptr),
mPGParamAdapt(nullptr),
mPGId(pgId),
mName(pgName),
mTerminalBaseUid(terminalBaseUid),
mStreamId(-1),
mPGCount(0),
mPlatform(IA_P2P_PLATFORM_BXT_B0),
mProgramCount(0),
mTerminalCount(0),
mManifestSize(0),
mKernelBitmap(ia_css_kernel_bitmap_clear()),
mRoutingBitmap(nullptr),
mFragmentCount(1),
mPGBuffer(nullptr),
mProcessGroup(nullptr),
mCmdExtBuffer(nullptr),
mPPG(false),
mPPGStarted(false),
mPPGBuffer(nullptr),
mPPGProcessGroup(nullptr),
mToken(0),
mEvent(nullptr),
mTerminalBuffers(nullptr),
mInputMainTerminal(-1),
mOutputMainTerminal(-1),
mShareReferPool(nullptr)
{
mTnrTerminalPair.inId = -1;
mTnrTerminalPair.outId = -1;
CLEAR(mParamPayload);
CLEAR(mShareReferIds);
}
PGCommon::~PGCommon()
{
}
int PGCommon::init()
{
mDisableDataTermials.clear();
mPGParamAdapt = std::unique_ptr<IntelPGParam>(new IntelPGParam(mPGId));
mCtx = new CIPR::Context();
int ret = getCapability();
if (ret != OK) return ret;
// create mManifestBuffer
ret = getManifest(mPGId);
if (ret != OK) return ret;
mTerminalBuffers = (CIPR::Buffer**)CIPR::callocMemory(mTerminalCount, sizeof(CIPR::Buffer*));
CheckError(!mTerminalBuffers, NO_MEMORY, "Allocate terminal buffers fail");
memset(mTerminalBuffers, 0, (mTerminalCount * sizeof(CIPR::Buffer*)));
mFrameFormatType = std::unique_ptr<ia_css_frame_format_type[]>(new ia_css_frame_format_type[mTerminalCount]);
for (int i = 0; i < mTerminalCount; i++) {
mFrameFormatType[i] = IA_CSS_N_FRAME_FORMAT_TYPES;
}
mPgTerminals = std::unique_ptr<uint8_t[]>(new uint8_t[mTerminalCount]);
for (int i = 0; i < mTerminalCount; i++) {
mPgTerminals[i] = IPU_MAX_TERMINAL_COUNT;
}
std::vector<TerminalPair> tnrTerminalPairs;
if (PGUtils::getTerminalPairs(mPGId, PGUtils::TERMINAL_PAIR_TNR, &tnrTerminalPairs)) {
mTnrTerminalPair = tnrTerminalPairs[0];
}
PGUtils::getTerminalPairs(mPGId, PGUtils::TERMINAL_PAIR_DVS, &mDvsTerminalPairs);
PGUtils::getTerminalPairs(mPGId, PGUtils::TERMINAL_PAIR_TNR_SIM, &mTnrSimTerminalPairs);
return ret;
}
void PGCommon::deInit()
{
if (mPPGStarted) {
stopPPG();
mPPGStarted = false;
}
destoryCommands();
while (!mTnrDataBuffers.empty()) {
uint8_t* ptr = mTnrDataBuffers.back();
mTnrDataBuffers.pop_back();
free(ptr);
}
mDvsTerminalPairs.clear();
mTnrSimTerminalPairs.clear();
mDisableDataTermials.clear();
if (mTerminalBuffers) {
CIPR::freeMemory(mTerminalBuffers);
}
delete mManifestBuffer;
delete mPGParamsBuffer;
delete mPGBuffer;
if (mPPGBuffer) {
delete mPPGBuffer;
}
for (auto& item : mBuffers) {
delete item.ciprBuf;
}
delete mCtx;
mPGParamAdapt->deinit();
mRoutingBitmap.reset();
}
void PGCommon::setInputInfo(const TerminalFrameInfoMap& inputInfos)
{
mInputMainTerminal = -1;
int maxFrameSize = 0;
for (const auto& item : inputInfos) {
int terminal = item.first - mTerminalBaseUid;
CheckError(!IS_VALID_TERMINAL(terminal), VOID_VALUE, "error input terminal %d", item.first);
FrameInfo frameInfo;
frameInfo.mWidth = item.second.mWidth;
frameInfo.mHeight = item.second.mHeight;
frameInfo.mFormat = item.second.mFormat;
frameInfo.mBpp = CameraUtils::getBpp(frameInfo.mFormat);
frameInfo.mStride = CameraUtils::getStride(frameInfo.mFormat, frameInfo.mWidth);
mTerminalFrameInfos[terminal] = frameInfo;
int size = frameInfo.mWidth * frameInfo.mHeight;
if (maxFrameSize < size) {
maxFrameSize = size;
mInputMainTerminal = terminal;
}
}
// Create frame info for tnr terminals (i.e. data terminals)
FrameInfo config = mTerminalFrameInfos[mInputMainTerminal];
if (config.mHeight % 32) {
LOG1("%s: height %d not multiple of 32, rounding up!", __func__, config.mHeight);
config.mHeight = ((config.mHeight / 32) + 1) * 32;
}
for (int i = PAIR_BUFFER_IN_INDEX; i <= PAIR_BUFFER_OUT_INDEX; i++) {
int tnrId = (i == PAIR_BUFFER_IN_INDEX) ? mTnrTerminalPair.inId : mTnrTerminalPair.outId;
if (tnrId < 0) continue;
mFrameFormatType[tnrId] = IA_CSS_DATA_FORMAT_NV12; // for IPU6
mTerminalFrameInfos[tnrId] = config;
}
LOG1("%s:%d use input terminal %d as main", __func__, mPGId, mInputMainTerminal);
}
void PGCommon::setOutputInfo(const TerminalFrameInfoMap& outputInfos)
{
mOutputMainTerminal = -1;
int maxFrameSize = 0;
for (const auto& item : outputInfos) {
int terminal = item.first - mTerminalBaseUid;
CheckError(!IS_VALID_TERMINAL(terminal), VOID_VALUE, "error output terminal %d", item.first);
FrameInfo frameInfo;
frameInfo.mWidth = item.second.mWidth;
frameInfo.mHeight = item.second.mHeight;
frameInfo.mFormat = item.second.mFormat;
frameInfo.mBpp = CameraUtils::getBpp(frameInfo.mFormat);
frameInfo.mStride = CameraUtils::getStride(frameInfo.mFormat, frameInfo.mWidth);
mTerminalFrameInfos[terminal] = frameInfo;
int size = frameInfo.mWidth * frameInfo.mHeight;
if (maxFrameSize < size) {
maxFrameSize = size;
mOutputMainTerminal = terminal;
}
}
}
void PGCommon::setDisabledTerminals(const std::vector<ia_uid>& disabledTerminals)
{
for (auto const terminalUid : disabledTerminals) {
int terminal = terminalUid - mTerminalBaseUid;
CheckError(!IS_VALID_TERMINAL(terminal), VOID_VALUE, "error disabled terminal %d", terminalUid);
mDisableDataTermials.push_back(terminal);
}
}
void PGCommon::setRoutingBitmap(const void* rbm, uint32_t bytes)
{
if (!rbm || !bytes) {
return;
}
const unsigned char* rbmData = (const unsigned char*)rbm;
if (mRoutingBitmap.get() == nullptr) {
mRoutingBitmap = std::unique_ptr<ia_css_rbm_t>(new ia_css_rbm_t);
}
ia_css_rbm_t* rbmPtr = mRoutingBitmap.get();
*rbmPtr = ia_css_rbm_clear();
for (uint32_t bit = 0; bit < bytes * 8; bit++) {
if (rbmData[bit / 8] & (1 << (bit %8))) {
*rbmPtr = ia_css_rbm_set(*rbmPtr, bit);
}
}
}
int PGCommon::prepare(IspParamAdaptor* adaptor, int streamId)
{
mStreamId = streamId;
// Set the data terminal frame format
int ret = configTerminalFormat();
CheckError((ret != OK), ret, "%s, call configTerminal fail", __func__);
// Init and config p2p handle
ret = initParamAdapt();
CheckError((ret != OK), ret, "%s, init p2p fail", __func__);
// Query and save the requirement for each terminal, get the final kernel bitmap
ret = mPGParamAdapt->prepare(adaptor->getIpuParameter(-1, streamId), mRoutingBitmap.get(), &mKernelBitmap);
CheckError((ret != OK), ret, "%s, prepare p2p fail", __func__);
// Init PG parameters
ret = handlePGParams(mFrameFormatType.get());
CheckError((ret != OK), ret, "%s, call handlePGParams fail", __func__);
ret = setKernelBitMap();
CheckError((ret != OK), ret, "%s, call setKernelBitMap fail", __func__);
ret = setTerminalParams(mFrameFormatType.get());
CheckError((ret != OK), ret, "%s, call setTerminalParams fail", __func__);
// Create process group
mProcessGroup = createPG(&mPGBuffer);
CheckError(!mProcessGroup, UNKNOWN_ERROR, "%s, create pg fail", __func__);
uint8_t pgTerminalCount = ia_css_process_group_get_terminal_count(mProcessGroup);
for (uint8_t termNum = 0 ; termNum < pgTerminalCount; termNum++) {
ia_css_terminal_t* terminal = ia_css_process_group_get_terminal(mProcessGroup, termNum);
CheckError(!terminal, UNKNOWN_ERROR, "failed to get terminal");
uint16_t termIdx = ia_css_terminal_get_terminal_manifest_index(terminal);
CheckError((termIdx >= IPU_MAX_TERMINAL_COUNT), UNKNOWN_ERROR, "wrong term index for terminal num %d", termNum);
mPgTerminals[termIdx] = termNum;
}
mPGParamAdapt->setPGAndPrepareProgram(mProcessGroup);
ret = configureFragmentDesc();
CheckError((ret != OK), ret, "%s, call configureFragmentDesc fail", __func__);
ret = allocateTnrDataBuffers();
CheckError((ret != OK), ret, "%s, call allocateTnrDataBuffers fail", __func__);
ret = preparePayloadBuffers();
CheckError((ret != OK), NO_MEMORY, "%s, preparePayloadBuffers fails", __func__);
return OK;
}
ia_css_process_group_t* PGCommon::createPG(CIPR::Buffer** pgBuffer)
{
CheckError(*pgBuffer, nullptr, "pg has already created");
// Create process group
ia_css_program_group_param_t* pgParamsBuf =
(ia_css_program_group_param_t*)getCiprBufferPtr(mPGParamsBuffer);
ia_css_program_group_manifest_t* manifestBuf =
(ia_css_program_group_manifest_t*)getCiprBufferPtr(mManifestBuffer);
size_t pgSize = ia_css_sizeof_process_group(manifestBuf, pgParamsBuf);
LOG1("%s process group size is %zu", __func__, pgSize);
void* pgMemory = mPGParamAdapt->allocatePGBuffer(pgSize);
CheckError(!pgMemory, nullptr, "allocate PG error");
*pgBuffer = createUserPtrCiprBuffer(pgSize, pgMemory);
CheckError(!*pgBuffer, nullptr, "%s, call createUserPtrCiprBuffer fail", __func__);
ia_css_process_group_t* pg = ia_css_process_group_create(getCiprBufferPtr(*pgBuffer),
(ia_css_program_group_manifest_t*)getCiprBufferPtr(mManifestBuffer),
(ia_css_program_group_param_t*)getCiprBufferPtr(mPGParamsBuffer));
CheckError(!pg, nullptr, "Create process group failed.");
if (mPPG) {
ia_css_process_group_set_num_queues(pg, 1);
}
if (mRoutingBitmap.get()) {
ia_css_process_group_set_routing_bitmap(pg, *mRoutingBitmap.get());
}
return pg;
}
int PGCommon::createCommands()
{
int bufCount = ia_css_process_group_get_terminal_count(mProcessGroup);
int ret = createCommand(mPGBuffer, &mCmd, &mCmdExtBuffer, bufCount);
CheckError(ret, NO_MEMORY, "create cmd fail!");
if (mPPG) {
ret = createCommand(mPPGBuffer, &mPPGCmd[PPG_CMD_TYPE_START], &mPPGCmdExtBuffer[PPG_CMD_TYPE_START], bufCount);
CheckError(ret, NO_MEMORY, "create ppg start buffer %d fail");
ret = createCommand(mPPGBuffer, &mPPGCmd[PPG_CMD_TYPE_STOP], &mPPGCmdExtBuffer[PPG_CMD_TYPE_STOP], 0);
CheckError(ret, NO_MEMORY, "create ppg stop %d fail");
}
CIPR::PSysEventConfig eventCfg = {};
eventCfg.timeout = kEventTimeout;
mEvent = new CIPR::Event(eventCfg);
return OK;
}
int PGCommon::createCommand(CIPR::Buffer* pg, CIPR::Command** cmd, CIPR::Buffer** extBuffer, int bufCount)
{
CIPR::PSysCommandConfig cmdCfg;
CIPR::ProcessGroupCommand *pgCommand;
CIPR::Result ret;
// Create command with basic setting
cmdCfg.buffers.resize(bufCount);
std::fill(cmdCfg.buffers.begin(), cmdCfg.buffers.end(), nullptr);
*cmd = new CIPR::Command(cmdCfg);
ret = (*cmd)->getConfig(&cmdCfg);
CheckError(ret != CIPR::Result::OK, UNKNOWN_ERROR, "%s, call get_command_config fail", __func__);
// Create ext buffer
*extBuffer = new CIPR::Buffer(sizeof(CIPR::ProcessGroupCommand),
CIPR::MemoryFlag::AllocateCpuPtr
| CIPR::MemoryFlag::PSysAPI,
nullptr);
ret = (*extBuffer)->attatchDevice(mCtx);
CheckError(ret != CIPR::Result::OK, NO_MEMORY, "unable to access extBuffer");
void* p = nullptr;
ret = (*extBuffer)->getMemoryCpuPtr(&p);
CheckError(ret != CIPR::Result::OK, NO_MEMORY, "unable to access extBuffer memory");
pgCommand = reinterpret_cast<CIPR::ProcessGroupCommand*>(p);
CheckError(!pgCommand, NO_MEMORY, "unable to access memory.cpu_ptr");
pgCommand->header.size = sizeof(CIPR::ProcessGroupCommand);
pgCommand->header.offset = sizeof(pgCommand->header);
pgCommand->header.version = psys_command_ext_ppg_1; // for ipu6
if (pgCommand->header.version == psys_command_ext_ppg_1) {
CIPR::memoryCopy(pgCommand->dynamicKernelBitmap, sizeof(ia_css_kernel_bitmap_t),
&mKernelBitmap, sizeof(ia_css_kernel_bitmap_t));
}
// Update setting and set back to command
cmdCfg.id = mPGId;
cmdCfg.priority = 1;
cmdCfg.pgParamsBuf = mPPG ? nullptr : mPGParamsBuffer;
cmdCfg.pgManifestBuf = mManifestBuffer;
cmdCfg.pg = pg;
cmdCfg.extBuf = *extBuffer;
ret = (*cmd)->setConfig(cmdCfg);
CheckError(ret != CIPR::Result::OK, UNKNOWN_ERROR, "%s, call set_command_config fail", __func__);
return OK;
}
void PGCommon::destoryCommands()
{
delete mCmd;
delete mCmdExtBuffer;
for (int i = 0; i < PPG_CMD_TYPE_COUNT; i++) {
delete mPPGCmd[i];
delete mPPGCmdExtBuffer[i];
}
if (mEvent) {
delete mEvent;
}
}
int PGCommon::configTerminalFormat()
{
for (int i = 0; i < mTerminalCount; i++) {
if (mTerminalFrameInfos.find(i) != mTerminalFrameInfos.end()) {
mFrameFormatType[i] = PGUtils::getCssFmt(mTerminalFrameInfos[i].mFormat);
}
}
return OK;
}
int PGCommon::initParamAdapt()
{
mFragmentCount = calcFragmentCount();
ia_css_program_group_manifest_t* manifestBuf =
(ia_css_program_group_manifest_t*)getCiprBufferPtr(mManifestBuffer);
PgConfiguration config;
config.pgManifest = manifestBuf;
config.pgManifestSize = getCiprBufferSize(mManifestBuffer);
config.disableDataTermials = mDisableDataTermials;
config.fragmentCount = mFragmentCount;
FrameInfo* pgInFrame = nullptr;
FrameInfo* pgOutFrame = nullptr;
if (mInputMainTerminal >= 0) {
pgInFrame = &mTerminalFrameInfos[mInputMainTerminal];
}
if (mOutputMainTerminal >= 0) {
pgOutFrame = &mTerminalFrameInfos[mOutputMainTerminal];
}
if (pgInFrame) {
config.inputMainFrame.width = pgInFrame->mWidth;
config.inputMainFrame.height = pgInFrame->mHeight;
config.inputMainFrame.bpe = pgInFrame->mBpp; //TODO: use bpe
}
if (pgOutFrame) {
config.outputMainFrame.width = pgOutFrame->mWidth;
config.outputMainFrame.height = pgOutFrame->mHeight;
config.outputMainFrame.bpe = pgOutFrame->mBpp; //TODO: use bpe
}
// init and config p2p handle
int ret = mPGParamAdapt->init(mPlatform, config);
return ret;
}
// Support horizontal fragment only now
int PGCommon::calcFragmentCount(int overlap)
{
int finalFragmentCount = 0;
ia_css_data_terminal_manifest_t * data_terminal_manifest = nullptr;
const ia_css_program_group_manifest_t *manifest =
(const ia_css_program_group_manifest_t*)getCiprBufferPtr(mManifestBuffer);
CheckError(!manifest, 1, "%s, can't get manifest ptr", __func__);
for (int termIdx = 0; termIdx < mTerminalCount; termIdx++) {
// Get max fragement size from manifest (align with 64)
ia_css_terminal_manifest_t *terminal_manifest = ia_css_program_group_manifest_get_term_mnfst(manifest, termIdx);
ia_css_terminal_type_t terminal_type = ia_css_terminal_manifest_get_type(terminal_manifest);
if (!((terminal_type == IA_CSS_TERMINAL_TYPE_DATA_OUT) || (terminal_type == IA_CSS_TERMINAL_TYPE_DATA_IN))) {
continue;
}
data_terminal_manifest = ia_css_program_group_manifest_get_data_terminal_manifest(manifest, termIdx);
CheckError(!data_terminal_manifest, -1, "%s, can't get data terminal manifest for term %d", __func__, termIdx);
uint16_t size[IA_CSS_N_DATA_DIMENSION] = {0};
int ret = ia_css_data_terminal_manifest_get_max_size(data_terminal_manifest, size);
CheckError(ret < 0, 1, "%s: get max fragment size error for term %d", __func__, termIdx);
size[IA_CSS_COL_DIMENSION] = ALIGN_64(size[IA_CSS_COL_DIMENSION]);
// Overwrite the max value if need
// Calc fragment count for terminal (only for horizontal direction)
int maxFragmentWidth = size[IA_CSS_COL_DIMENSION];
FrameInfo config;
if (mTerminalFrameInfos.find(termIdx) != mTerminalFrameInfos.end()) {
config = mTerminalFrameInfos[termIdx];
}
int fragmentCovered = maxFragmentWidth;
int fragmentCount = 1;
/*
* Calculate how many fragment frames can cover the whole frame.
* Consider overlap between two fragment frames.
* Example: frame width = 300, max fragment width = 100, overlap = 10
* 0|------------------------------|300
* f1 0|----------|100
* f2 90|----------|190
* f3 180|----------|280
* f4 270|---|300
*/
while (fragmentCovered < config.mWidth) {
fragmentCovered += (maxFragmentWidth - overlap);
fragmentCount++;
}
if (finalFragmentCount < fragmentCount) {
finalFragmentCount = fragmentCount;
}
}
LOG2("%s: final fragment count %d for pg %d", __func__, finalFragmentCount, mPGId);
return finalFragmentCount;
}
int PGCommon::handlePGParams(const ia_css_frame_format_type* frameFormatTypes)
{
int pgParamsSize = ia_css_sizeof_program_group_param(mProgramCount, mTerminalCount, mFragmentCount);
mPGParamsBuffer = createUserPtrCiprBuffer(pgParamsSize);
CheckError(!mPGParamsBuffer, NO_MEMORY, "%s, call createUserPtrCiprBuffer fail", __func__);
ia_css_program_group_param_t* pgParamsBuf = (ia_css_program_group_param_t*)getCiprBufferPtr(mPGParamsBuffer);
int ret = ia_css_program_group_param_init(pgParamsBuf, mProgramCount, mTerminalCount, mFragmentCount, frameFormatTypes);
CheckError((ret != OK), ret, "%s, call ia_css_program_group_param_init fail", __func__);
if (mPPG) {
ret = ia_css_program_group_param_set_protocol_version(
pgParamsBuf,
IA_CSS_PROCESS_GROUP_PROTOCOL_PPG);
CheckError((ret != OK), ret, "%s, call ia_css_program_group_param_set_protocol_version fail", __func__);
}
return ret;
}
int PGCommon::setKernelBitMap()
{
ia_css_program_group_param_t* pgParamsBuf = (ia_css_program_group_param_t*)getCiprBufferPtr(mPGParamsBuffer);
LOG1("%s: mKernelBitmap: %#018lx", __func__, mKernelBitmap);
int ret = ia_css_program_group_param_set_kernel_enable_bitmap(pgParamsBuf, mKernelBitmap);
CheckError((ret != OK), ret, "%s, call ia_css_program_group_param_set_kernel_enable_bitmap fail", __func__);
return ret;
}
int PGCommon::setTerminalParams(const ia_css_frame_format_type* frameFormatTypes)
{
ia_css_program_group_param_t* pgParamsBuf =
(ia_css_program_group_param_t*)getCiprBufferPtr(mPGParamsBuffer);
ia_css_program_group_manifest_t* pg_manifest =
(ia_css_program_group_manifest_t*)getCiprBufferPtr(mManifestBuffer);
for (int i = 0; i < mTerminalCount; i++) {
ia_css_terminal_param_t *terminalParam =
ia_css_program_group_param_get_terminal_param(pgParamsBuf, i);
CheckError(!terminalParam, UNKNOWN_ERROR, "%s, call ia_css_program_group_param_get_terminal_param fail", __func__);
ia_css_terminal_manifest_t *terminal_manifest = ia_css_program_group_manifest_get_term_mnfst(pg_manifest, i);
ia_css_terminal_type_t terminal_type = ia_css_terminal_manifest_get_type(terminal_manifest);
if (!((terminal_type == IA_CSS_TERMINAL_TYPE_DATA_OUT) || (terminal_type == IA_CSS_TERMINAL_TYPE_DATA_IN))) {
continue;
}
FrameInfo config = mTerminalFrameInfos[i];
terminalParam->frame_format_type = frameFormatTypes[i];
terminalParam->dimensions[IA_CSS_COL_DIMENSION] = config.mWidth;
terminalParam->dimensions[IA_CSS_ROW_DIMENSION] = config.mHeight;
terminalParam->fragment_dimensions[IA_CSS_COL_DIMENSION] = config.mWidth;
terminalParam->fragment_dimensions[IA_CSS_ROW_DIMENSION] = config.mHeight;
terminalParam->bpp = PGUtils::getCssBpp(config.mFormat);
terminalParam->bpe = terminalParam->bpp;
terminalParam->stride = PGUtils::getCssStride(config.mFormat, config.mWidth);
terminalParam->offset = 0;
terminalParam->index[IA_CSS_COL_DIMENSION] = 0;
terminalParam->index[IA_CSS_ROW_DIMENSION] = 0;
LOG2("%s: setTerminalParams: index=%d, format=%d, w=%d, h=%d, fw=%d, fh=%d, bpp=%d, bpe=%d, stride=%d, offset=%d, col=%d, row=%d",
getName(), i,
terminalParam->frame_format_type,
terminalParam->dimensions[IA_CSS_COL_DIMENSION],
terminalParam->dimensions[IA_CSS_ROW_DIMENSION],
terminalParam->fragment_dimensions[IA_CSS_COL_DIMENSION],
terminalParam->fragment_dimensions[IA_CSS_ROW_DIMENSION],
terminalParam->bpp,
terminalParam->bpe,
terminalParam->stride,
terminalParam->offset,
terminalParam->index[IA_CSS_COL_DIMENSION],
terminalParam->index[IA_CSS_ROW_DIMENSION]);
}
return OK;
}
int PGCommon::configureFragmentDesc()
{
int num = mTerminalCount * mFragmentCount;
std::unique_ptr<ia_p2p_fragment_desc[]> srcFragDesc =
std::unique_ptr<ia_p2p_fragment_desc[]>(new ia_p2p_fragment_desc[num]);
int count = mPGParamAdapt->getFragmentDescriptors(num, srcFragDesc.get());
CheckError(!count, UNKNOWN_ERROR, "getFragmentDescriptors fails");
for (int termIdx = 0; termIdx < mTerminalCount; termIdx++) {
if (mPgTerminals[termIdx] >= IPU_MAX_TERMINAL_COUNT) {
continue;
}
ia_css_terminal_t* terminal = ia_css_process_group_get_terminal(mProcessGroup, mPgTerminals[termIdx]);
ia_css_terminal_type_t terminalType = ia_css_terminal_get_type(terminal);
if (!((terminalType == IA_CSS_TERMINAL_TYPE_DATA_OUT) || (terminalType == IA_CSS_TERMINAL_TYPE_DATA_IN))) {
continue;
}
configureTerminalFragmentDesc(termIdx, &srcFragDesc[termIdx]);
}
return OK;
}
int PGCommon::configureTerminalFragmentDesc(int termIdx, const ia_p2p_fragment_desc* srcDesc)
{
#define DDR_WORD_BYTES 64
ia_css_terminal_t* terminal = ia_css_process_group_get_terminal(mProcessGroup, mPgTerminals[termIdx]);
ia_css_terminal_type_t terminalType = ia_css_terminal_get_type(terminal);
if (!((terminalType == IA_CSS_TERMINAL_TYPE_DATA_OUT) || (terminalType == IA_CSS_TERMINAL_TYPE_DATA_IN))) {
return OK;
}
bool vectorized = false;
int packed_multiplier = 1;
int packed_divider = 1;
int dimension_bpp = PGUtils::getCssBpp(mTerminalFrameInfos[termIdx].mFormat);
switch(mFrameFormatType[termIdx]) {
case IA_CSS_DATA_FORMAT_BAYER_VECTORIZED:
case IA_CSS_DATA_FORMAT_BAYER_LINE_INTERLEAVED:
vectorized = true;
dimension_bpp = (uint8_t) ALIGN_8(PGUtils::getCssBpp(mTerminalFrameInfos[termIdx].mFormat));
break;
case IA_CSS_DATA_FORMAT_RAW:
dimension_bpp = (uint8_t) ALIGN_8(PGUtils::getCssBpp(mTerminalFrameInfos[termIdx].mFormat));
break;
case IA_CSS_DATA_FORMAT_BAYER_GRBG:
case IA_CSS_DATA_FORMAT_BAYER_RGGB:
case IA_CSS_DATA_FORMAT_BAYER_BGGR:
case IA_CSS_DATA_FORMAT_BAYER_GBRG:
dimension_bpp = (uint8_t) ALIGN_8(PGUtils::getCssBpp(mTerminalFrameInfos[termIdx].mFormat));
break;
case IA_CSS_DATA_FORMAT_YYUVYY_VECTORIZED:
dimension_bpp = (uint8_t) (PGUtils::getCssBpp(mTerminalFrameInfos[termIdx].mFormat) * 3 / 2);
packed_multiplier = 3;
packed_divider = 2;
vectorized = true;
break;
default:
break;
}
for (int fragIdx = 0; fragIdx < mFragmentCount; fragIdx++) {
ia_css_fragment_descriptor_t* dstFragDesc =
ia_css_data_terminal_get_fragment_descriptor((ia_css_data_terminal_t*)terminal, fragIdx);
CheckError(!dstFragDesc, -1, "%s: Can't get frag desc from terminal", __func__);
dstFragDesc->dimension[IA_CSS_COL_DIMENSION] = srcDesc[fragIdx].fragment_width;
dstFragDesc->dimension[IA_CSS_ROW_DIMENSION] = srcDesc[fragIdx].fragment_height;
dstFragDesc->index[IA_CSS_COL_DIMENSION] = (uint16_t)
(((srcDesc[fragIdx].fragment_start_x * packed_multiplier)
/ packed_divider) * (vectorized ? 2 : 1));
dstFragDesc->index[IA_CSS_ROW_DIMENSION] = (uint16_t)
(srcDesc[fragIdx].fragment_start_y / (vectorized ? 2 : 1));
int colOffset = 0;
int pixels_per_word = 0;
switch (mFrameFormatType[termIdx]) {
case IA_CSS_DATA_FORMAT_YUV420:
case IA_CSS_DATA_FORMAT_YYUVYY_VECTORIZED:
case IA_CSS_DATA_FORMAT_BAYER_VECTORIZED:
/** \todo Fragmentation with DMA packed formats is still open, need to
* check this again when it is more clear (see #H1804344344).
*/
pixels_per_word = (uint16_t) floor(DDR_WORD_BYTES * 8 / dimension_bpp);
colOffset = (uint16_t) (floor(dstFragDesc->index[IA_CSS_COL_DIMENSION] / pixels_per_word) * DDR_WORD_BYTES);
colOffset = (uint16_t) (colOffset + (((dstFragDesc->index[IA_CSS_COL_DIMENSION] % pixels_per_word) * dimension_bpp) / 8));
break;
default:
colOffset = (uint16_t) (dstFragDesc->index[IA_CSS_COL_DIMENSION] * dimension_bpp / 8);
break;
}
dstFragDesc->offset[IA_CSS_COL_DIMENSION] = (uint16_t)colOffset;
dstFragDesc->offset[IA_CSS_ROW_DIMENSION] = dstFragDesc->index[IA_CSS_ROW_DIMENSION];
LOG2("%s: %d:%d: get frag desc %d (%d, %d, %d, %d)", __func__, mPGId, termIdx, fragIdx,
srcDesc[fragIdx].fragment_width, srcDesc[fragIdx].fragment_height,
srcDesc[fragIdx].fragment_start_x, srcDesc[fragIdx].fragment_start_y);
LOG2("%s: %d:%d: frag %d: size(%d, %d) index(%d, %d), offset(%d, %d)", __func__, mPGId, termIdx,fragIdx,
dstFragDesc->dimension[IA_CSS_COL_DIMENSION],
dstFragDesc->dimension[IA_CSS_ROW_DIMENSION],
dstFragDesc->index[IA_CSS_COL_DIMENSION],
dstFragDesc->index[IA_CSS_ROW_DIMENSION],
dstFragDesc->offset[IA_CSS_COL_DIMENSION],
dstFragDesc->offset[IA_CSS_ROW_DIMENSION]);
}
return OK;
}
int PGCommon::iterate(CameraBufferMap &inBufs, CameraBufferMap &outBufs,
ia_binary_data *statistics, const ia_binary_data *ipuParameters)
{
LOG2("%s:%s ++", getName(), __func__);
long sequence = 0;
if (!inBufs.empty()) {
sequence = inBufs.begin()->second->getSequence();
}
int ret = prepareTerminalBuffers(ipuParameters, inBufs, outBufs, sequence);
CheckError((ret != OK), ret, "%s, prepareTerminalBuffers fail with %d", getName(), ret);
// Create PPG & PPG start/stop commands at the beginning
if (mPPG && !mPPGBuffer) {
ia_css_program_group_param_t* pgParamsBuf =
(ia_css_program_group_param_t*)getCiprBufferPtr(mPGParamsBuffer);
ia_css_program_group_manifest_t* manifestBuf =
(ia_css_program_group_manifest_t*)getCiprBufferPtr(mManifestBuffer);
size_t pgSize = ia_css_sizeof_process_group(manifestBuf, pgParamsBuf);
mPPGBuffer = createUserPtrCiprBuffer(pgSize);
CheckError(!mPPGBuffer, NO_MEMORY, "%s, call createUserPtrCiprBuffer fail", __func__);
mPPGProcessGroup = (ia_css_process_group_t*)getCiprBufferPtr(mPPGBuffer);
MEMCPY_S(mPPGProcessGroup, pgSize, mProcessGroup, ia_css_process_group_get_size(mProcessGroup));
}
if (!mCmd) {
ret = createCommands();
CheckError((ret != OK), ret, "%s, call createCommands fail", __func__);
}
if (mPPG && !mPPGStarted) {
ret = startPPG();
CheckError((ret != OK), ret, "%s, startPPG fail", getName());
mPPGStarted = true;
}
ret = executePG();
CheckError((ret != OK), ret, "%s, executePG fail", getName());
if (statistics) {
ret = mPGParamAdapt->decode(mTerminalCount, mParamPayload, statistics);
CheckError((ret != OK), ret, "%s, decode fail", getName());
}
postTerminalBuffersDone(sequence);
LOG2("%s:%s -- ", getName(), __func__);
return ret;
}
int PGCommon::preparePayloadBuffers() {
int count = mPGParamAdapt->getPayloadSizes(mTerminalCount, mParamPayload);
CheckError((count != mTerminalCount), NO_MEMORY, "%s, getPayloadSize fails", __func__);
// For TNR parameter refer terminals
int ret = allocateTnrSimBuffers();
CheckError((ret != OK), NO_MEMORY, "%s, allocateTnrSimBuffers fails", __func__);
// For other normal terminals
std::vector<ia_binary_data> payloads;
ia_binary_data payload = {nullptr, 0};
for (int termIdx = 0; termIdx < mTerminalCount; termIdx++) {
if (mParamPayload[termIdx].data) {
payload.size = 0; // allocated
} else {
payload.size = mParamPayload[termIdx].size;
}
payloads.push_back(payload);
}
ret = mPGParamAdapt->allocatePayloads(payloads.size(), payloads.data());
CheckError(ret != OK, NO_MEMORY, "%s, allocate payloads fail", __func__);
for (int i = 0; i < mTerminalCount; i++) {
if (payloads[i].data) {
CIPR::Buffer* ciprBuf = registerUserBuffer(payloads[i].size, payloads[i].data);
CheckError(!ciprBuf, NO_MEMORY, "%s, register payload buffer %p for term %d fail",
__func__, payloads[i].data, i);
memset(payloads[i].data, 0, PAGE_ALIGN(payloads[i].size));
mParamPayload[i].data = payloads[i].data;
mTerminalBuffers[i] = ciprBuf;
}
}
return OK;
}
int PGCommon::allocateTnrDataBuffers() {
if (mTnrTerminalPair.inId < 0 || !mTnrDataBuffers.empty()) return OK;
// port = term index + 1
int32_t termIndex = mTnrTerminalPair.inId;
int64_t referId = ShareReferBufferPool::constructReferId(mStreamId, mPGId, termIndex + 1);
int32_t bufferCount = PAIR_BUFFER_COUNT;
if (mShareReferPool.get()) {
bufferCount = mShareReferPool->getMinBufferNum(referId);
if (bufferCount) {
mShareReferIds[termIndex] = referId; // mShareReferPool supports for the refer buffers
}
}
if (bufferCount < PAIR_BUFFER_COUNT) {
bufferCount = PAIR_BUFFER_COUNT;
}
int size = CameraUtils::getFrameSize(mTerminalFrameInfos[mInputMainTerminal].mFormat,
mTerminalFrameInfos[mInputMainTerminal].mWidth,
mTerminalFrameInfos[mInputMainTerminal].mHeight);
for (int32_t i = 0; i < bufferCount; i++) {
uint8_t* buffer = nullptr;
int ret = posix_memalign((void**)&buffer, PAGE_SIZE_U, PAGE_ALIGN(size));
CheckError(ret, NO_MEMORY, "%s, alloc %d tnr data buf fails", __func__, i);
mTnrDataBuffers.push_back(buffer);
CIPR::Buffer* ciprBuf = registerUserBuffer(size, buffer);
CheckError(!ciprBuf, NO_MEMORY, "%s, register %d tnr buf %p fails", __func__, i, buffer);
if (i == PAIR_BUFFER_IN_INDEX) mTerminalBuffers[mTnrTerminalPair.inId] = ciprBuf;
else if (i == PAIR_BUFFER_OUT_INDEX) mTerminalBuffers[mTnrTerminalPair.outId] = ciprBuf;
if (mShareReferIds[termIndex])
mShareReferPool->registerReferBuffers(referId, ciprBuf);
}
return OK;
}
int PGCommon::allocateTnrSimBuffers() {
for (auto pair : mTnrSimTerminalPairs) {
int32_t inId = pair.inId;
// port = term index + 1
int64_t referId = ShareReferBufferPool::constructReferId(mStreamId, mPGId, inId + 1);
int32_t bufferCount = PAIR_BUFFER_COUNT;
if (mShareReferPool.get()) {
bufferCount = mShareReferPool->getMinBufferNum(referId);
if (bufferCount) {
mShareReferIds[inId] = referId; // flag it: get payload via mShareReferPool
}
}
if (bufferCount < PAIR_BUFFER_COUNT) {
bufferCount = PAIR_BUFFER_COUNT;
}
std::vector<ia_binary_data> payloads;
ia_binary_data payload = {nullptr, mParamPayload[inId].size};
for (int32_t i = 0; i < bufferCount; i++) {
payloads.push_back(payload);
}
int ret = mPGParamAdapt->allocatePayloads(payloads.size(), payloads.data());
CheckError(ret != OK, NO_MEMORY, "%s, allocate for term pair %d fail", __func__, inId);
// Register all buffers and clear
for (int32_t i = 0; i < bufferCount; i++) {
CIPR::Buffer* ciprBuf = registerUserBuffer(payloads[i].size, payloads[i].data);
CheckError(!ciprBuf, NO_MEMORY, "%s, register %d:%p for term pair %d fails",
__func__, i, payloads[i].data, inId);
memset(payloads[i].data, 0, PAGE_ALIGN(payloads[i].size));
if (mShareReferIds[inId])
mShareReferPool->registerReferBuffers(referId, ciprBuf);
// Set default payload for terminal pair to mark they are allocated.
if (i == PAIR_BUFFER_IN_INDEX) {
mParamPayload[pair.inId].data = payloads[PAIR_BUFFER_IN_INDEX].data;
mTerminalBuffers[pair.inId] = ciprBuf;
} else if (i == PAIR_BUFFER_OUT_INDEX) {
mParamPayload[pair.outId].data = payloads[PAIR_BUFFER_OUT_INDEX].data;
mTerminalBuffers[pair.outId] = ciprBuf;
}
}
}
return OK;
}
int PGCommon::prepareTerminalBuffers(const ia_binary_data *ipuParameters,
const CameraBufferMap& inBufs, const CameraBufferMap& outBufs,
long sequence) {
CIPR::Buffer* ciprBuf = nullptr;
// Prepare payload
for (int termIdx = 0; termIdx < mTerminalCount; termIdx++) {
// Payload for data terminals
std::shared_ptr<CameraBuffer> buffer;
ia_uid terminalUid = mTerminalBaseUid + termIdx;
if (inBufs.find(terminalUid) != inBufs.end()) {
buffer = inBufs.at(terminalUid);
} else if (outBufs.find(terminalUid) != outBufs.end()) {
buffer = outBufs.at(terminalUid);
}
if (buffer) {
bool flush = buffer->getUsage() == BUFFER_USAGE_GENERAL ? true : false;
ciprBuf = (buffer->getMemory() == V4L2_MEMORY_DMABUF) \
? registerUserBuffer(buffer->getBufferSize(), buffer->getFd(), flush) \
: registerUserBuffer(buffer->getBufferSize(), buffer->getBufferAddr(), flush);
CheckError(!ciprBuf, NO_MEMORY, "%s, register buffer size %d for terminal %d fail",
__func__, buffer->getBufferSize(), termIdx);
mTerminalBuffers[termIdx] = ciprBuf;
}
}
if (!mTnrDataBuffers.empty()) {
if (mShareReferIds[mTnrTerminalPair.inId]) {
mShareReferPool->acquireBuffer(mShareReferIds[mTnrTerminalPair.inId],
&mTerminalBuffers[mTnrTerminalPair.inId],
&mTerminalBuffers[mTnrTerminalPair.outId],
sequence);
} else {
std::swap(mTerminalBuffers[mTnrTerminalPair.inId],
mTerminalBuffers[mTnrTerminalPair.outId]);
}
}
for (auto& pair : mDvsTerminalPairs) {
std::swap(mTerminalBuffers[pair.inId], mTerminalBuffers[pair.outId]);
}
for (auto& pair : mTnrSimTerminalPairs) {
if (mShareReferIds[pair.inId]) {
mShareReferPool->acquireBuffer(mShareReferIds[pair.inId],
&mTerminalBuffers[pair.inId],
&mTerminalBuffers[pair.outId],
sequence);
} else {
std::swap(mTerminalBuffers[pair.inId], mTerminalBuffers[pair.outId]);
}
// Update palyload buffers
mTerminalBuffers[pair.inId]->getMemoryCpuPtr(&mParamPayload[pair.inId].data);
mTerminalBuffers[pair.outId]->getMemoryCpuPtr(&mParamPayload[pair.outId].data);
}
return mPGParamAdapt->updatePALAndEncode(ipuParameters, mTerminalCount, mParamPayload);
}
void PGCommon::postTerminalBuffersDone(long sequence) {
if (!mTnrDataBuffers.empty() && mShareReferIds[mTnrTerminalPair.inId]) {
mShareReferPool->releaseBuffer(mShareReferIds[mTnrTerminalPair.inId],
mTerminalBuffers[mTnrTerminalPair.inId],
mTerminalBuffers[mTnrTerminalPair.outId],
sequence);
}
for (auto pair : mTnrSimTerminalPairs) {
if (mShareReferIds[pair.inId]) {
mShareReferPool->releaseBuffer(mShareReferIds[pair.inId],
mTerminalBuffers[pair.inId],
mTerminalBuffers[pair.outId],
sequence);
}
}
}
int PGCommon::executePG()
{
TRACE_LOG_PROCESS(mName.c_str(), __func__);
CheckError((!mCmd), INVALID_OPERATION, "%s, Command is invalid.", __func__);
CheckError((!mProcessGroup), INVALID_OPERATION, "%s, process group is invalid.", __func__);
mCmd->getConfig(&mCmdCfg);
int bufferCount = ia_css_process_group_get_terminal_count(mProcessGroup);
mCmdCfg.id = mPGId;
mCmdCfg.priority = 1;
mCmdCfg.pgParamsBuf = mPPG ? nullptr : mPGParamsBuffer;
mCmdCfg.pgManifestBuf = mManifestBuffer;
mCmdCfg.pg = mPGBuffer;
mCmdCfg.extBuf = mCmdExtBuffer;
mCmdCfg.buffers.resize(bufferCount);
for (int i = 0; i < bufferCount; i++) {
ia_css_terminal_t *terminal = ia_css_process_group_get_terminal(mProcessGroup, i);
CheckError(!terminal, UNKNOWN_ERROR, "failed to get terminal");
mCmdCfg.buffers[i] = mTerminalBuffers[terminal->tm_index];
}
if (mPPG) {
ia_css_process_group_set_token(mProcessGroup, mToken);
}
for (int fragIdx = 0; fragIdx < mFragmentCount; fragIdx++) {
int ret = ia_css_process_group_set_fragment_state(mProcessGroup, (uint16_t)fragIdx);
CheckError((ret != OK), ret, "%s, set fragment count %d fail %p", getName(), fragIdx, mProcessGroup);
ret = ia_css_process_group_set_fragment_limit(mProcessGroup, (uint16_t)(fragIdx + 1));
CheckError((ret != OK), ret, "%s, set fragment limit %d fail", getName(), fragIdx);
ret = handleCmd(&mCmd, &mCmdCfg);
CheckError((ret != OK), ret, "%s, call handleCmd fail", getName());
}
return OK;
}
int PGCommon::startPPG()
{
// Get basic command config
CIPR::PSysCommandConfig cmdCfg;
mPPGCmd[PPG_CMD_TYPE_START]->getConfig(&cmdCfg);
// Update config
cmdCfg.id = mPGId;
cmdCfg.priority = 1;
cmdCfg.pgParamsBuf = mPPG ? nullptr : mPGParamsBuffer;
cmdCfg.pgManifestBuf = mManifestBuffer;
cmdCfg.pg = mPPGBuffer;
cmdCfg.extBuf = mPPGCmdExtBuffer[PPG_CMD_TYPE_START];
const int terminalCount = ia_css_process_group_get_terminal_count(mProcessGroup);
cmdCfg.buffers.resize(terminalCount);
std::fill(cmdCfg.buffers.begin(), cmdCfg.buffers.end(), nullptr);
ia_css_process_group_set_fragment_state(mPPGProcessGroup, 0);
ia_css_process_group_set_fragment_limit(mPPGProcessGroup, 1);
int ret = handleCmd(&mPPGCmd[PPG_CMD_TYPE_START], &cmdCfg);
mToken = ia_css_process_group_get_token(mPPGProcessGroup);
return ret;
}
int PGCommon::stopPPG()
{
CIPR::PSysCommandConfig cmdCfg;
mPPGCmd[PPG_CMD_TYPE_STOP]->getConfig(&cmdCfg);
cmdCfg.id = mCmdCfg.id;
cmdCfg.priority = mCmdCfg.priority;
cmdCfg.pgParamsBuf = mCmdCfg.pgParamsBuf;
cmdCfg.pgManifestBuf = mCmdCfg.pgManifestBuf;
cmdCfg.pg = mPPGBuffer;
cmdCfg.extBuf = mPPGCmdExtBuffer[PPG_CMD_TYPE_STOP];
cmdCfg.buffers.resize(0);
int ret = handleCmd(&mPPGCmd[PPG_CMD_TYPE_STOP], &cmdCfg);
return ret;
}
int PGCommon::handleCmd(CIPR::Command** cmd, CIPR::PSysCommandConfig* cmdCfg)
{
CIPR::PSysEventConfig eventCfg = {};
mEvent->getConfig(&eventCfg);
cmdCfg->issueID = reinterpret_cast<uint64_t>(cmd);
eventCfg.commandIssueID = cmdCfg->issueID;
CIPR::Result ret = (*cmd)->setConfig(*cmdCfg);
CheckError((ret != CIPR::Result::OK), UNKNOWN_ERROR, "%s, call CIPR::Command::setConfig fail", __func__);
ret = (*cmd)->getConfig(cmdCfg);
CheckError((ret != CIPR::Result::OK), UNKNOWN_ERROR, "%s, call CIPR::Command::getConfig fail", __func__);
ret = (*cmd)->enqueue(mCtx);
CheckError((ret != CIPR::Result::OK), UNKNOWN_ERROR, "%s, call Context::enqueueCommand() fail %d", __func__, ret);
// Wait event
ret = mEvent->wait(mCtx);
CheckError((ret != CIPR::Result::OK), UNKNOWN_ERROR, "%s, call Context::waitForEvent fail, ret: %d", __func__, ret);
ret = mEvent->getConfig(&eventCfg);
CheckError((ret != CIPR::Result::OK), UNKNOWN_ERROR, "%s, call Event::getConfig() fail, ret: %d", __func__, ret);
// Ignore the error in event config since it's not a fatal error.
if (eventCfg.error) {
LOGW("%s, event config error: %d", __func__, eventCfg.error);
}
return (eventCfg.error == 0) ? OK : UNKNOWN_ERROR;
}
int PGCommon::getCapability()
{
CIPR::PSYSCapability cap;
int ret = OK;
CIPR::Result err = mCtx->getCapabilities(&cap);
CheckError((err != CIPR::Result::OK), UNKNOWN_ERROR, "Call Context::getCapabilities() fail, ret:%d", ret);
LOG1("%s: capability.version:%d", __func__, cap.version);
LOG1("%s: capability.driver:%s", __func__, cap.driver);
LOG1("%s: capability.devModel:%s", __func__, cap.devModel);
LOG1("%s: capability.programGroupCount:%d", __func__, cap.programGroupCount);
mPGCount = cap.programGroupCount;
if (strncmp((char *)cap.devModel, "ipu4p", 5) == 0) {
mPlatform = IA_P2P_PLATFORM_CNL_B0;
LOG1("%s: cnl/icl/ksl shared the same p2p platform id", __func__);
} else if (strncmp((char *)cap.devModel, "ipu4", 4) == 0) {
switch (cap.devModel[13]) {
case 'B':
mPlatform = IA_P2P_PLATFORM_BXT_B0;
break;
default:
LOGE("%s: unsupported psys device model :%s", __func__, cap.devModel);
ret = BAD_VALUE;
break;
}
} else if (strncmp((char *)cap.devModel, "ipu6", 4) == 0) {
mPlatform = IA_P2P_PLATFORM_IPU6;
mPPG = true;
} else {
LOGE("%s: unsupported psys device model : %s", __func__, cap.devModel);
ret = BAD_VALUE;
}
return ret;
}
int PGCommon::getManifest(int pgId)
{
int i = 0;
for (; i < mPGCount; i++) {
CIPR::Buffer* manifestBuffer = nullptr;
int programCount = 0;
int terminalCount = 0;
int programGroupId = 0;
int manifestSize = 0;
ia_css_kernel_bitmap_t kernelBitmap = ia_css_kernel_bitmap_clear();
uint32_t size = 0;
CIPR::Result ret = mCtx->getManifest(i, &size, nullptr);
if (ret != CIPR::Result::OK) continue;
CheckError((size == 0), UNKNOWN_ERROR, "%s, the manifest size is 0", __func__);
manifestBuffer = createUserPtrCiprBuffer(size);
CheckError(!manifestBuffer, NO_MEMORY, "%s, call createUserPtrCiprBuffer fail", __func__);
void* manifest = getCiprBufferPtr(manifestBuffer);
ret = mCtx->getManifest(i, &size, manifest);
if (ret != CIPR::Result::OK) {
LOGE("%s, call Context::getManifest() fail", __func__);
delete manifestBuffer;
return UNKNOWN_ERROR;
}
LOG1("%s: pg index: %d, manifest size: %u", __func__, i, size);
const ia_css_program_group_manifest_t *mf = (const ia_css_program_group_manifest_t*)manifest;
programCount = ia_css_program_group_manifest_get_program_count(mf);
terminalCount = ia_css_program_group_manifest_get_terminal_count(mf);
programGroupId = ia_css_program_group_manifest_get_program_group_ID(mf);
manifestSize = ia_css_program_group_manifest_get_size(mf);
kernelBitmap = ia_css_program_group_manifest_get_kernel_bitmap(mf);
LOG1("%s: pgIndex: %d, programGroupId: %d, manifestSize: %d, programCount: %d, terminalCount: %d",
__func__, i, programGroupId, manifestSize, programCount, terminalCount);
if (pgId == programGroupId) {
mProgramCount = programCount;
mTerminalCount = terminalCount;
mManifestSize = manifestSize;
mKernelBitmap = kernelBitmap;
mManifestBuffer = manifestBuffer;
break;
}
delete manifestBuffer;
}
CheckError((i == mPGCount), BAD_VALUE, "%s, Can't found available pg: %d", __func__, pgId);
return OK;
}
CIPR::Buffer* PGCommon::createDMACiprBuffer(int size, int fd, bool flush)
{
CIPR::MemoryFlag deviceFlags = CIPR::MemoryFlag::MemoryHandle;
if (!flush) deviceFlags |= CIPR::MemoryFlag::NoFlush;
CIPR::MemoryDesc mem;
mem.size = size;
mem.flags = CIPR::MemoryFlag::MemoryHandle | CIPR::MemoryFlag::HardwareOnly;
mem.handle = fd;
mem.cpuPtr = nullptr;
mem.anchor = nullptr;
CIPR::Buffer* buf = new CIPR::Buffer(size, mem.flags | deviceFlags, &mem);
CIPR::Result ret = buf->attatchDevice(mCtx);
if (ret != CIPR::Result::OK) {
LOGE("%s, call Buffer::attatchDevice() fail", __func__);
delete buf;
return nullptr;
}
return buf;
}
CIPR::Buffer* PGCommon::createUserPtrCiprBuffer(int size, void* ptr, bool flush)
{
CIPR::Buffer* buf = nullptr;
if (ptr == nullptr) {
buf = new CIPR::Buffer(size, CIPR::MemoryFlag::AllocateCpuPtr | CIPR::MemoryFlag::NoFlush,
nullptr);
} else {
CIPR::MemoryDesc mem;
mem.size = size;
mem.flags = CIPR::MemoryFlag::CpuPtr;
if (!flush) mem.flags |= CIPR::MemoryFlag::NoFlush;
mem.handle = 0;
mem.cpuPtr = ptr;
mem.anchor = nullptr;
buf = new CIPR::Buffer(size, CIPR::MemoryFlag::CpuPtr, &mem);
}
CIPR::Result ret = buf->attatchDevice(mCtx);
if (ret != CIPR::Result::OK) {
LOGE("%s, call Buffer::attatchDevice() fail", __func__);
delete buf;
return nullptr;
}
return buf;
}
void* PGCommon::getCiprBufferPtr(CIPR::Buffer* buffer)
{
CheckError(!buffer, nullptr, "%s, invalid cipr buffer", __func__);
void* ptr = nullptr;
CIPR::Result ret = buffer->getMemoryCpuPtr(&ptr);
CheckError((ret != CIPR::Result::OK), nullptr, "%s, call Buffer::getMemoryCpuPtr() fail", __func__);
return ptr;
}
int PGCommon::getCiprBufferSize(CIPR::Buffer* buffer)
{
CheckError(!buffer, BAD_VALUE, "%s, invalid cipr buffer", __func__);
int size = 0;
CIPR::Result ret = buffer->getMemorySize(&size);
CheckError((ret != CIPR::Result::OK), NO_MEMORY, "%s, call Buffer::getMemorySize() fail", __func__);
return size;
}
CIPR::Buffer* PGCommon::registerUserBuffer(int size, void* ptr, bool flush)
{
CheckError((size <= 0 || ptr == nullptr), nullptr, "Invalid parameter: size=%d, ptr=%p", size, ptr);
for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
if (ptr == it->userPtr) {
if (size == getCiprBufferSize(it->ciprBuf)) {
return it->ciprBuf;
}
LOG2("%s, the buffer size is changed: old(%d), new(%d) addr(%p)",
__func__, getCiprBufferSize(it->ciprBuf), size, it->userPtr);
delete it->ciprBuf;
it->ciprBuf = nullptr;
it->userPtr = nullptr;
mBuffers.erase(it);
break;
}
}
CIPR::Buffer* ciprBuf = createUserPtrCiprBuffer(size, ptr, flush);
CheckError(!ciprBuf, nullptr, "Create cipr buffer for %p failed", ptr);
CiprBufferMapping bufMap;
bufMap.userPtr = ptr;
bufMap.ciprBuf = ciprBuf;
mBuffers.push_back(bufMap);
return ciprBuf;
}
CIPR::Buffer* PGCommon::registerUserBuffer(int size, int fd, bool flush)
{
CheckError((size <= 0 || fd < 0), nullptr, "Invalid parameter: size: %d, fd: %d", size, fd);
for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
if (fd == it->userFd) {
if (size == getCiprBufferSize(it->ciprBuf)) {
return it->ciprBuf;
}
LOG2("%s, the buffer size is changed: old(%d), new(%d) fd(%d)",
__func__, getCiprBufferSize(it->ciprBuf), size, it->userFd);
delete it->ciprBuf;
it->ciprBuf = nullptr;
it->userFd = -1;
mBuffers.erase(it);
break;
}
}
CIPR::Buffer* ciprBuf = createDMACiprBuffer(size, fd, flush);
CheckError(!ciprBuf, nullptr, "Create cipr buffer for fd %d failed", fd);
CiprBufferMapping bufMap;
bufMap.userFd = fd;
bufMap.ciprBuf = ciprBuf;
mBuffers.push_back(bufMap);
return ciprBuf;
}
void PGCommon::dumpTerminalPyldAndDesc(int pgId, long sequence, ia_css_process_group_t* pgGroup)
{
if (!CameraDump::isDumpTypeEnable(DUMP_PSYS_PG)) return;
char fileName[MAX_NAME_LEN] = {'\0'};
uint32_t pgSize = ia_css_process_group_get_size(pgGroup);
snprintf(fileName, (MAX_NAME_LEN - 1), "hal_pg_%d_%ld.bin", pgId, sequence);
FILE *fp = fopen (fileName, "w+");
CheckError(fp == nullptr, VOID_VALUE, "open dump file %s failed", fileName);
const unsigned int* printPtr = (const unsigned int*)pgGroup;
fprintf(fp, "::pg dump size %d(0x%x)\n", pgSize, pgSize);
for (unsigned int i = 0; i < pgSize / sizeof(*printPtr); i++) {
fprintf(fp, "%08x\n", printPtr[i]);
}
int terminalCount = ia_css_process_group_get_terminal_count(pgGroup);
for (int i = 0; i < terminalCount; i++) {
ia_css_terminal_t *terminal = ia_css_process_group_get_terminal(pgGroup, i);
if (!terminal) {
LOGE("failed to get terminal");
fclose(fp);
return;
}
if (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_DATA_IN
|| terminal->terminal_type == IA_CSS_TERMINAL_TYPE_DATA_OUT) {
continue;
}
void* ptr = getCiprBufferPtr(mTerminalBuffers[terminal->tm_index]);
int size = getCiprBufferSize(mTerminalBuffers[terminal->tm_index]);
const char* typeStr = (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_DATA_IN) ? "DATA_IN"
: (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_DATA_OUT) ? "DATA_OUT"
: (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_PARAM_STREAM) ? "PARAM_STREAM"
: (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_PARAM_CACHED_IN) ? "CACHED_IN"
: (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_PARAM_CACHED_OUT) ? "CACHED_OUT"
: (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_PARAM_SPATIAL_IN) ? "SPATIAL_IN"
: (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_PARAM_SPATIAL_OUT) ? "SPATIAL_OUT"
: (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_PARAM_SLICED_IN) ? "SLICED_IN"
: (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_PARAM_SLICED_OUT) ? "SLICED_OU"
: (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_STATE_IN) ? "STATE_IN"
: (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_STATE_OUT) ? "STATE_OUT"
: (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_PROGRAM) ? "PROGRAM"
: (terminal->terminal_type == IA_CSS_TERMINAL_TYPE_PROGRAM_CONTROL_INIT) ? "PROGRAM_CONTROL_INIT"
: "UNKNOWN";
printPtr = (const unsigned int*)ptr;
fprintf(fp, "::terminal %d dump size %d(0x%x), line %d, type %s\n", terminal->tm_index, size, size, PAGE_ALIGN(size)/4, typeStr);
for (unsigned int i = 0; i < PAGE_ALIGN(size) / sizeof(*printPtr); i++) {
fprintf(fp, "%08x\n", printPtr[i]);
}
}
fclose (fp);
}
} // namespace icamera