262 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			262 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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 <cody.xie@rock-chips.com>
 | |
|  */
 | |
| #include "remap_backend.h"
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <cassert>
 | |
| #include <cstring>
 | |
| #include <fstream>
 | |
| #include <iostream>
 | |
| 
 | |
| #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<char*>(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<char*>(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<unsigned short*>(buf->UserPtr);
 | |
|     buf->MeshYi   = buf->MeshXi + config_.MeshSize;
 | |
|     buf->MeshXf   = reinterpret_cast<unsigned char*>(buf->MeshYi + config_.MeshSize);
 | |
|     buf->MeshYf   = buf->MeshXf + config_.MeshSize;
 | |
|     buf->State    = reinterpret_cast<char*>(buf->UserPtr) + buf->Size;
 | |
|     buf->State[0] = fec_mesh_hold_by_algo;
 | |
|     buf->Index    = ++user_buffer_index_;
 | |
| 
 | |
|     std::unique_lock<std::mutex> lk(user_mtx_);
 | |
|     user_buffers_.emplace_back(buf);
 | |
| 
 | |
|     return buf;
 | |
| }
 | |
| 
 | |
| void FecRemapBackend::FreeUserBuffer(FecMeshBuffer* buf) {
 | |
|     assert(buf != nullptr && buf->Fd == -1);
 | |
|     std::unique_lock<std::mutex> lk(user_mtx_);
 | |
|     auto it = std::remove_if(
 | |
|         user_buffers_.begin(), user_buffers_.end(),
 | |
|         [&buf](const std::unique_ptr<FecMeshBuffer>& p) { return (buf->Index == p->Index); });
 | |
|     user_buffers_.erase(it, user_buffers_.end());
 | |
| }
 | |
| 
 | |
| FecMeshBuffer* FecRemapBackend::GetAvailUserBuffer() {
 | |
|     std::unique_lock<std::mutex> 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<rk_aiq_fec_share_mem_info_t*>(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<FecMeshBuffer*>(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<FecMeshBuffer*>(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<std::mutex> lk(user_mtx_);
 | |
|     auto it = std::find_if(user_buffers_.begin(), user_buffers_.end(),
 | |
|                            [&mesh](const std::unique_ptr<FecMeshBuffer>& 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<std::mutex> lk(user_mtx_);
 | |
|     auto buf      = reinterpret_cast<FecMeshBuffer*>(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<std::mutex> lk(user_mtx_);
 | |
|         std::for_each(user_buffers_.begin(), user_buffers_.end(),
 | |
|                       [&](const std::unique_ptr<FecMeshBuffer>& 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<std::mutex> 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<std::mutex> 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
 |