1 /*
2 * remap_backend.cpp - The backend hardware/software to do remap
3 *
4 * Copyright (c) 2021 Rockchip Electronics Co., Ltd.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Author: Cody Xie <cody.xie@rock-chips.com>
19 */
20 #include "remap_backend.h"
21
22 #include <algorithm>
23 #include <cassert>
24 #include <cstring>
25 #include <fstream>
26 #include <iostream>
27
28 #include "dvs_app.h"
29 #include "xcam_log.h"
30
31 namespace RkCam {
32
33 constexpr static const uint8_t fec_mesh_skipped = 3;
34 constexpr static const uint8_t fec_mesh_hold_by_algo = 2;
35 constexpr static const uint8_t fec_hw_mesh_used_by_hardware = 1;
36 constexpr static const uint8_t fec_mesh_available = 0;
37
ReadBinary(const std::string & path,void * buf,size_t size)38 static void ReadBinary(const std::string& path, void* buf, size_t size) {
39 std::ifstream ifs(path, std::ios::binary);
40 if (!ifs.is_open()) {
41 LOGE_AEIS("Failed to open file %s", path.c_str());
42 return;
43 } else {
44 ifs.read(reinterpret_cast<char*>(buf), size);
45 }
46 }
47
WriteBinary(const std::string & path,void * buf,size_t size)48 static void WriteBinary(const std::string& path, void* buf, size_t size) {
49 std::ofstream ofs(path, std::ios::binary);
50 if (!ofs.is_open()) {
51 LOGE_AEIS("Failed to open file %s", path.c_str());
52 return;
53 } else {
54 ofs.write(reinterpret_cast<char*>(buf), size);
55 }
56 }
57
FecRemapBackend(const FecMeshConfig & config,const isp_drv_share_mem_ops_t * mem_ops)58 FecRemapBackend::FecRemapBackend(const FecMeshConfig& config,
59 const isp_drv_share_mem_ops_t* mem_ops)
60 : config_(config),
61 mem_ops_(mem_ops),
62 user_buffer_index_(-1),
63 last_result_id_(-1) {
64 assert(mem_ops != nullptr);
65
66 ImportHwBuffers();
67 }
68
~FecRemapBackend()69 FecRemapBackend::~FecRemapBackend() { ReleaseHwBuffers(); }
70
AllocUserBuffer()71 FecMeshBuffer* FecRemapBackend::AllocUserBuffer() {
72 FecMeshBuffer* buf = new FecMeshBuffer();
73 assert(buf != nullptr);
74 buf->Fd = -1;
75 buf->Size = config_.MeshSize * (sizeof(*buf->MeshXi) + sizeof(*buf->MeshXf) +
76 sizeof(*buf->MeshYi) + sizeof(*buf->MeshYf));
77 buf->UserPtr = calloc(1, buf->Size + 1);
78 if (!buf->UserPtr) {
79 delete buf;
80 return nullptr;
81 }
82 buf->MeshXi = reinterpret_cast<unsigned short*>(buf->UserPtr);
83 buf->MeshYi = buf->MeshXi + config_.MeshSize;
84 buf->MeshXf = reinterpret_cast<unsigned char*>(buf->MeshYi + config_.MeshSize);
85 buf->MeshYf = buf->MeshXf + config_.MeshSize;
86 buf->State = reinterpret_cast<char*>(buf->UserPtr) + buf->Size;
87 buf->State[0] = fec_mesh_hold_by_algo;
88 buf->Index = ++user_buffer_index_;
89
90 std::unique_lock<std::mutex> lk(user_mtx_);
91 user_buffers_.emplace_back(buf);
92
93 return buf;
94 }
95
FreeUserBuffer(FecMeshBuffer * buf)96 void FecRemapBackend::FreeUserBuffer(FecMeshBuffer* buf) {
97 assert(buf != nullptr && buf->Fd == -1);
98 std::unique_lock<std::mutex> lk(user_mtx_);
99 auto it = std::remove_if(
100 user_buffers_.begin(), user_buffers_.end(),
101 [&buf](const std::unique_ptr<FecMeshBuffer>& p) { return (buf->Index == p->Index); });
102 user_buffers_.erase(it, user_buffers_.end());
103 }
104
GetAvailUserBuffer()105 FecMeshBuffer* FecRemapBackend::GetAvailUserBuffer() {
106 std::unique_lock<std::mutex> lk(user_mtx_);
107 for (auto it = user_buffers_.begin(); it != user_buffers_.end(); it++) {
108 if ((*it)->State[0] == fec_mesh_available) {
109 (*it)->State[0] = fec_mesh_hold_by_algo;
110 return (*it).get();
111 }
112 }
113 return nullptr;
114 }
115
ImportHwBuffers()116 void FecRemapBackend::ImportHwBuffers() {
117 assert(mem_ops_ != nullptr);
118 rk_aiq_share_mem_config_t hw_config_;
119 hw_config_.mem_type = MEM_TYPE_FEC;
120 hw_config_.alloc_param.width = config_.Width;
121 hw_config_.alloc_param.height = config_.Height;
122 hw_config_.alloc_param.reserved[0] = config_.MeshDensity;
123
124 mem_ops_->alloc_mem(0, (void*)mem_ops_, &hw_config_, &mem_ctx_);
125 }
126
ReleaseHwBuffers()127 void FecRemapBackend::ReleaseHwBuffers() {
128 if (mem_ctx_ && mem_ops_) mem_ops_->release_mem(0, mem_ctx_);
129 }
130
GetFreeHwBuffer()131 FecMeshBuffer* FecRemapBackend::GetFreeHwBuffer() {
132 if (mem_ops_ == nullptr || mem_ctx_ == nullptr) {
133 return nullptr;
134 }
135
136 const auto mem_info =
137 reinterpret_cast<rk_aiq_fec_share_mem_info_t*>(mem_ops_->get_free_item(0, mem_ctx_));
138 if (mem_info != nullptr) {
139 return new FecMeshBuffer(mem_info);
140 }
141 return nullptr;
142 }
143
GetMeshFromFile(MeshBuffer * info)144 void FecRemapBackend::GetMeshFromFile(MeshBuffer* info) {
145 FecMeshBuffer* buf = reinterpret_cast<FecMeshBuffer*>(info);
146 ReadBinary("/data/meshxi.bin", buf->MeshXi, sizeof(*buf->MeshXi) * config_.MeshSize);
147 ReadBinary("/data/meshxf.bin", buf->MeshXf, sizeof(*buf->MeshXf) * config_.MeshSize);
148 ReadBinary("/data/meshyi.bin", buf->MeshYi, sizeof(*buf->MeshYi) * config_.MeshSize);
149 ReadBinary("/data/meshyf.bin", buf->MeshYf, sizeof(*buf->MeshYf) * config_.MeshSize);
150 }
151
WriteMeshToFile(MeshBuffer * info)152 void FecRemapBackend::WriteMeshToFile(MeshBuffer* info) {
153 FecMeshBuffer* buf = reinterpret_cast<FecMeshBuffer*>(info);
154 std::string path = "/data/dvs_mesh_";
155 path.append(std::to_string(buf->Fd));
156 std::string pathxi = path;
157 pathxi.append("_xi.bin");
158 WriteBinary(pathxi, buf->MeshXi, sizeof(*buf->MeshXi) * config_.MeshSize);
159 std::string pathxf = path;
160 pathxf.append("_xf.bin");
161 WriteBinary(pathxf, buf->MeshXf, sizeof(*buf->MeshXf) * config_.MeshSize);
162 std::string pathyi = path;
163 pathyi.append("_yi.bin");
164 WriteBinary(pathyi, buf->MeshYi, sizeof(*buf->MeshYi) * config_.MeshSize);
165 std::string pathyf = path;
166 pathyf.append("_yf.bin");
167 WriteBinary(pathyf, buf->MeshYf, sizeof(*buf->MeshYf) * config_.MeshSize);
168 }
169
Remap(meshxyFEC * mesh)170 void FecRemapBackend::Remap(meshxyFEC* mesh) {
171 std::unique_lock<std::mutex> lk(user_mtx_);
172 auto it = std::find_if(user_buffers_.begin(), user_buffers_.end(),
173 [&mesh](const std::unique_ptr<FecMeshBuffer>& buf) {
174 return buf->Index == (size_t)mesh->mesh_buffer_index;
175 });
176 if (it != user_buffers_.end()) {
177 (*it)->ImageBufferIndex = mesh->image_buffer_index;
178 (*it)->FrameId = mesh->image_index;
179 if (mesh->is_skip) {
180 (*it)->State[0] = fec_mesh_skipped;
181 } else {
182 (*it)->State[0] = fec_hw_mesh_used_by_hardware;
183 }
184 }
185 }
186
187 // Does not do actual remap, but put result to hardware
Remap(MeshBuffer * info)188 void FecRemapBackend::Remap(MeshBuffer* info) {
189 std::unique_lock<std::mutex> lk(user_mtx_);
190 auto buf = reinterpret_cast<FecMeshBuffer*>(info);
191 buf->State[0] = fec_hw_mesh_used_by_hardware;
192 }
193
GetPendingHwResult()194 FecMeshBuffer* FecRemapBackend::GetPendingHwResult() {
195 FecMeshBuffer* buf = nullptr;
196 FecMeshBuffer* hw_buf = nullptr;
197 uint32_t min_id = (uint32_t)(-1);
198 {
199 std::unique_lock<std::mutex> lk(user_mtx_);
200 std::for_each(user_buffers_.begin(), user_buffers_.end(),
201 [&](const std::unique_ptr<FecMeshBuffer>& p) {
202 if (p->State[0] == fec_hw_mesh_used_by_hardware ||
203 p->State[0] == fec_mesh_skipped) {
204 if (p->FrameId != (uint32_t)(-1) && p->FrameId <= last_result_id_) {
205 LOGW_AEIS("Get pending result id %u PASSED !!!", p->FrameId);
206 p->State[0] = fec_mesh_available;
207 } else if (last_result_id_ != (uint32_t)(-1) && p->FrameId - last_result_id_ > 1) {
208 LOGV_AEIS("pending result id %u in FUTURE!!!", p->FrameId);
209 } else {
210 if (min_id >= p->FrameId) {
211 min_id = p->FrameId;
212 buf = p.get();
213 }
214 }
215 }
216 });
217 }
218 LOGV_AEIS("Get Pending result min id %u", min_id);
219
220 if (buf != nullptr) {
221 if (buf->State[0] == fec_mesh_skipped) {
222 LOGW_AEIS("Get pending result id %u SKIPPED ...", buf->FrameId);
223 auto* mesh = AllocUserBuffer();
224 if (mesh != nullptr) {
225 mesh->Fd = -1;
226 mesh->FrameId = buf->FrameId;
227 mesh->ImageBufferIndex = buf->ImageBufferIndex;
228 mesh->ImageBufferSize = buf->ImageBufferSize;
229 mesh->State[0] = fec_hw_mesh_used_by_hardware;
230 std::unique_lock<std::mutex> lk(user_mtx_);
231 buf->State[0] = fec_mesh_available;
232 last_result_id_ = buf->FrameId;
233 }
234 return mesh;
235 } else {
236 hw_buf = GetFreeHwBuffer();
237 if (hw_buf != nullptr) {
238 LOGD_AEIS("Get pending result id %u HW ", buf->FrameId);
239 memcpy(hw_buf->MeshXi, buf->MeshXi, (sizeof(*buf->MeshXi) * config_.MeshSize));
240 memcpy(hw_buf->MeshYi, buf->MeshYi, (sizeof(*buf->MeshYi) * config_.MeshSize));
241 memcpy(hw_buf->MeshXf, buf->MeshXf, (sizeof(*buf->MeshXf) * config_.MeshSize));
242 memcpy(hw_buf->MeshYf, buf->MeshYf, (sizeof(*buf->MeshYf) * config_.MeshSize));
243 hw_buf->FrameId = buf->FrameId;
244 hw_buf->ImageBufferIndex = buf->ImageBufferIndex;
245 hw_buf->ImageBufferSize = buf->ImageBufferSize;
246 hw_buf->State[0] = fec_hw_mesh_used_by_hardware;
247 std::unique_lock<std::mutex> lk(user_mtx_);
248 buf->State[0] = fec_mesh_available;
249 last_result_id_ = buf->FrameId;
250 } else {
251 LOGW_AEIS("Get pending result id %u HW no buffer", buf->FrameId);
252 }
253 return hw_buf;
254 }
255 }
256
257 return nullptr;
258 }
259
260 } // namespace RkCam
261