/* * remap_backend.cpp - The backend hardware/software to do remap * * 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 */ #include "remap_backend.h" #include #include #include #include #include #include "dvs_app.h" #include "xcam_log.h" namespace RkCam { constexpr static const uint8_t fec_mesh_skipped = 3; constexpr static const uint8_t fec_mesh_hold_by_algo = 2; constexpr static const uint8_t fec_hw_mesh_used_by_hardware = 1; constexpr static const uint8_t fec_mesh_available = 0; static void ReadBinary(const std::string& path, void* buf, size_t size) { std::ifstream ifs(path, std::ios::binary); if (!ifs.is_open()) { LOGE_AEIS("Failed to open file %s", path.c_str()); return; } else { ifs.read(reinterpret_cast(buf), size); } } static void WriteBinary(const std::string& path, void* buf, size_t size) { std::ofstream ofs(path, std::ios::binary); if (!ofs.is_open()) { LOGE_AEIS("Failed to open file %s", path.c_str()); return; } else { ofs.write(reinterpret_cast(buf), size); } } FecRemapBackend::FecRemapBackend(const FecMeshConfig& config, const isp_drv_share_mem_ops_t* mem_ops) : config_(config), mem_ops_(mem_ops), user_buffer_index_(-1), hw_buffer_index_(-1), last_result_id_(-1) { assert(mem_ops != nullptr); ImportHwBuffers(); } FecRemapBackend::~FecRemapBackend() { ReleaseHwBuffers(); } FecMeshBuffer* FecRemapBackend::AllocUserBuffer() { FecMeshBuffer* buf = new FecMeshBuffer(); assert(buf != nullptr); buf->Fd = -1; buf->Size = config_.MeshSize * (sizeof(*buf->MeshXi) + sizeof(*buf->MeshXf) + sizeof(*buf->MeshYi) + sizeof(*buf->MeshYf)); buf->UserPtr = calloc(1, buf->Size + 1); if (!buf->UserPtr) { delete buf; return nullptr; } buf->MeshXi = reinterpret_cast(buf->UserPtr); buf->MeshYi = buf->MeshXi + config_.MeshSize; buf->MeshXf = reinterpret_cast(buf->MeshYi + config_.MeshSize); buf->MeshYf = buf->MeshXf + config_.MeshSize; buf->State = reinterpret_cast(buf->UserPtr) + buf->Size; buf->State[0] = fec_mesh_hold_by_algo; buf->Index = ++user_buffer_index_; std::unique_lock lk(user_mtx_); user_buffers_.emplace_back(buf); return buf; } void FecRemapBackend::FreeUserBuffer(FecMeshBuffer* buf) { assert(buf != nullptr && buf->Fd == -1); std::unique_lock lk(user_mtx_); auto it = std::remove_if( user_buffers_.begin(), user_buffers_.end(), [&buf](const std::unique_ptr& p) { return (buf->Index == p->Index); }); user_buffers_.erase(it, user_buffers_.end()); } FecMeshBuffer* FecRemapBackend::GetAvailUserBuffer() { std::unique_lock lk(user_mtx_); for (auto it = user_buffers_.begin(); it != user_buffers_.end(); it++) { if ((*it)->State[0] == fec_mesh_available) { (*it)->State[0] = fec_mesh_hold_by_algo; return (*it).get(); } } return nullptr; } void FecRemapBackend::ImportHwBuffers() { assert(mem_ops_ != nullptr); rk_aiq_share_mem_config_t hw_config_; hw_config_.mem_type = MEM_TYPE_FEC; hw_config_.alloc_param.width = config_.Width; hw_config_.alloc_param.height = config_.Height; hw_config_.alloc_param.reserved[0] = config_.MeshDensity; mem_ops_->alloc_mem(0, (void*)mem_ops_, &hw_config_, &mem_ctx_); } void FecRemapBackend::ReleaseHwBuffers() { if (mem_ctx_ && mem_ops_) mem_ops_->release_mem(0, mem_ctx_); } FecMeshBuffer* FecRemapBackend::GetFreeHwBuffer() { if (mem_ops_ == nullptr || mem_ctx_ == nullptr) { return nullptr; } const auto mem_info = reinterpret_cast(mem_ops_->get_free_item(0, mem_ctx_)); if (mem_info != nullptr) { return new FecMeshBuffer(mem_info); } return nullptr; } void FecRemapBackend::GetMeshFromFile(MeshBuffer* info) { FecMeshBuffer* buf = reinterpret_cast(info); ReadBinary("/data/meshxi.bin", buf->MeshXi, sizeof(*buf->MeshXi) * config_.MeshSize); ReadBinary("/data/meshxf.bin", buf->MeshXf, sizeof(*buf->MeshXf) * config_.MeshSize); ReadBinary("/data/meshyi.bin", buf->MeshYi, sizeof(*buf->MeshYi) * config_.MeshSize); ReadBinary("/data/meshyf.bin", buf->MeshYf, sizeof(*buf->MeshYf) * config_.MeshSize); } void FecRemapBackend::WriteMeshToFile(MeshBuffer* info) { FecMeshBuffer* buf = reinterpret_cast(info); std::string path = "/data/dvs_mesh_"; path.append(std::to_string(buf->Fd)); std::string pathxi = path; pathxi.append("_xi.bin"); WriteBinary(pathxi, buf->MeshXi, sizeof(*buf->MeshXi) * config_.MeshSize); std::string pathxf = path; pathxf.append("_xf.bin"); WriteBinary(pathxf, buf->MeshXf, sizeof(*buf->MeshXf) * config_.MeshSize); std::string pathyi = path; pathyi.append("_yi.bin"); WriteBinary(pathyi, buf->MeshYi, sizeof(*buf->MeshYi) * config_.MeshSize); std::string pathyf = path; pathyf.append("_yf.bin"); WriteBinary(pathyf, buf->MeshYf, sizeof(*buf->MeshYf) * config_.MeshSize); } void FecRemapBackend::Remap(meshxyFEC* mesh) { std::unique_lock lk(user_mtx_); auto it = std::find_if(user_buffers_.begin(), user_buffers_.end(), [&mesh](const std::unique_ptr& buf) { return buf->Index == (size_t)mesh->mesh_buffer_index; }); if (it != user_buffers_.end()) { (*it)->ImageBufferIndex = mesh->image_buffer_index; (*it)->FrameId = mesh->image_index; if (mesh->is_skip) { (*it)->State[0] = fec_mesh_skipped; } else { (*it)->State[0] = fec_hw_mesh_used_by_hardware; } } } // Does not do actual remap, but put result to hardware void FecRemapBackend::Remap(MeshBuffer* info) { std::unique_lock lk(user_mtx_); auto buf = reinterpret_cast(info); buf->State[0] = fec_hw_mesh_used_by_hardware; } FecMeshBuffer* FecRemapBackend::GetPendingHwResult() { FecMeshBuffer* buf = nullptr; FecMeshBuffer* hw_buf = nullptr; uint32_t min_id = (uint32_t)(-1); { std::unique_lock lk(user_mtx_); std::for_each(user_buffers_.begin(), user_buffers_.end(), [&](const std::unique_ptr& p) { if (p->State[0] == fec_hw_mesh_used_by_hardware || p->State[0] == fec_mesh_skipped) { if (p->FrameId != (uint32_t)(-1) && p->FrameId <= last_result_id_) { LOGW_AEIS("Get pending result id %u PASSED !!!", p->FrameId); p->State[0] = fec_mesh_available; } else if (last_result_id_ != (uint32_t)(-1) && p->FrameId - last_result_id_ > 1) { LOGV_AEIS("pending result id %u in FUTURE!!!", p->FrameId); } else { if (min_id >= p->FrameId) { min_id = p->FrameId; buf = p.get(); } } } }); } LOGV_AEIS("Get Pending result min id %u", min_id); if (buf != nullptr) { if (buf->State[0] == fec_mesh_skipped) { LOGW_AEIS("Get pending result id %u SKIPPED ...", buf->FrameId); auto* mesh = AllocUserBuffer(); if (mesh != nullptr) { mesh->Fd = -1; mesh->FrameId = buf->FrameId; mesh->ImageBufferIndex = buf->ImageBufferIndex; mesh->ImageBufferSize = buf->ImageBufferSize; mesh->State[0] = fec_hw_mesh_used_by_hardware; std::unique_lock lk(user_mtx_); buf->State[0] = fec_mesh_available; last_result_id_ = buf->FrameId; } return mesh; } else { hw_buf = GetFreeHwBuffer(); if (hw_buf != nullptr) { LOGD_AEIS("Get pending result id %u HW ", buf->FrameId); memcpy(hw_buf->MeshXi, buf->MeshXi, (sizeof(*buf->MeshXi) * config_.MeshSize)); memcpy(hw_buf->MeshYi, buf->MeshYi, (sizeof(*buf->MeshYi) * config_.MeshSize)); memcpy(hw_buf->MeshXf, buf->MeshXf, (sizeof(*buf->MeshXf) * config_.MeshSize)); memcpy(hw_buf->MeshYf, buf->MeshYf, (sizeof(*buf->MeshYf) * config_.MeshSize)); hw_buf->FrameId = buf->FrameId; hw_buf->ImageBufferIndex = buf->ImageBufferIndex; hw_buf->ImageBufferSize = buf->ImageBufferSize; hw_buf->State[0] = fec_hw_mesh_used_by_hardware; std::unique_lock lk(user_mtx_); buf->State[0] = fec_mesh_available; last_result_id_ = buf->FrameId; } else { LOGW_AEIS("Get pending result id %u HW no buffer", buf->FrameId); } return hw_buf; } } return nullptr; } } // namespace RkCam