/src/opencv/modules/dnn/src/legacy_backend.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | // This file is part of OpenCV project. |
2 | | // It is subject to the license terms in the LICENSE file found in the top-level directory |
3 | | // of this distribution and at http://opencv.org/license.html. |
4 | | |
5 | | #ifndef __OPENCV_DNN_SRC_LEGACY_BACKEND_HPP__ |
6 | | #define __OPENCV_DNN_SRC_LEGACY_BACKEND_HPP__ |
7 | | |
8 | | #include "layer_internals.hpp" // LayerPin LayerData DataLayer |
9 | | |
10 | | namespace cv { namespace dnn { |
11 | | CV__DNN_INLINE_NS_BEGIN |
12 | | inline namespace detail { |
13 | | |
14 | | |
15 | | #ifdef HAVE_OPENCL |
16 | | class OpenCLBackendWrapper : public BackendWrapper |
17 | | { |
18 | | public: |
19 | | OpenCLBackendWrapper(Mat& m) |
20 | 0 | : BackendWrapper(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL) |
21 | 0 | { |
22 | 0 | m.copyTo(umat); |
23 | 0 | host = &m; |
24 | 0 | hostDirty = false; |
25 | 0 | } |
26 | | |
27 | | OpenCLBackendWrapper(const Ptr<BackendWrapper>& baseBuffer, Mat& m) |
28 | 0 | : BackendWrapper(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL) |
29 | 0 | { |
30 | 0 | Ptr<OpenCLBackendWrapper> base = baseBuffer.dynamicCast<OpenCLBackendWrapper>(); |
31 | 0 | CV_Assert(!base.empty()); |
32 | | |
33 | 0 | host = &m; |
34 | |
|
35 | 0 | int shape[] = { 1, (int)base->umat.total() }; |
36 | 0 | umat = base->umat.reshape(1, 2, &shape[0]) |
37 | 0 | .colRange(0, host->total()) |
38 | 0 | .reshape(1, host->dims, &host->size[0]); |
39 | 0 | hostDirty = false; |
40 | 0 | } |
41 | | |
42 | | static Ptr<BackendWrapper> create(Mat& m) |
43 | 0 | { |
44 | 0 | return Ptr<BackendWrapper>(new OpenCLBackendWrapper(m)); |
45 | 0 | } |
46 | | |
47 | | static Ptr<BackendWrapper> create(const Ptr<BackendWrapper>& baseBuffer, Mat& m) |
48 | 0 | { |
49 | 0 | return Ptr<BackendWrapper>(new OpenCLBackendWrapper(baseBuffer, m)); |
50 | 0 | } |
51 | | |
52 | | static std::vector<UMat> getUMatVector(const std::vector<Ptr<BackendWrapper>>& wrappers) |
53 | 0 | { |
54 | 0 | const int numWrappers = wrappers.size(); |
55 | 0 | std::vector<UMat> mats(wrappers.size()); |
56 | 0 | for (int i = 0; i < numWrappers; ++i) |
57 | 0 | { |
58 | 0 | Ptr<OpenCLBackendWrapper> umatWrapper = wrappers[i].dynamicCast<OpenCLBackendWrapper>(); |
59 | 0 | CV_Assert(!umatWrapper.empty()); |
60 | 0 | umatWrapper->copyToDevice(); |
61 | 0 | mats[i] = umatWrapper->umat; |
62 | 0 | } |
63 | 0 | return mats; |
64 | 0 | } |
65 | | |
66 | | // Replaces all umats in wrappers to specific ones. |
67 | | static void update(const std::vector<Ptr<BackendWrapper>>& wrappers, |
68 | | const std::vector<UMat>& umats) |
69 | 0 | { |
70 | 0 | CV_Assert(wrappers.size() == umats.size()); |
71 | 0 | for (int i = 0, n = umats.size(); i < n; ++i) |
72 | 0 | { |
73 | 0 | Ptr<OpenCLBackendWrapper> umatWrapper = wrappers[i].dynamicCast<OpenCLBackendWrapper>(); |
74 | 0 | CV_Assert(!umatWrapper.empty()); |
75 | 0 | umatWrapper->umat = umats[i]; |
76 | 0 | } |
77 | 0 | } |
78 | | |
79 | 0 | ~OpenCLBackendWrapper() {} |
80 | | |
81 | | // Copies data from device to a host memory. |
82 | | virtual void copyToHost() CV_OVERRIDE |
83 | 0 | { |
84 | 0 | umat.copyTo(*host); |
85 | 0 | } |
86 | | |
87 | | virtual void setHostDirty() CV_OVERRIDE |
88 | 0 | { |
89 | 0 | hostDirty = true; |
90 | 0 | }; |
91 | | |
92 | | void copyToDevice() |
93 | 0 | { |
94 | 0 | if (hostDirty) |
95 | 0 | { |
96 | 0 | host->copyTo(umat); |
97 | 0 | hostDirty = false; |
98 | 0 | } |
99 | 0 | } |
100 | | |
101 | | private: |
102 | | UMat umat; |
103 | | Mat* host; |
104 | | bool hostDirty; |
105 | | }; // OpenCLBackendWrapper |
106 | | #endif // HAVE_OPENCL |
107 | | |
108 | | |
109 | | struct BlobManager |
110 | | { |
111 | | public: |
112 | | // Increase references counter to layer output. |
113 | | void addReference(const LayerPin& lp) |
114 | 0 | { |
115 | 0 | std::map<LayerPin, int>::iterator it = refCounter.find(lp); |
116 | 0 | if (it == refCounter.end()) |
117 | 0 | refCounter[lp] = 1; |
118 | 0 | else |
119 | 0 | it->second += 1; |
120 | 0 | } |
121 | | |
122 | | void addReferences(const std::vector<LayerPin>& pins) |
123 | 0 | { |
124 | 0 | for (int i = 0; i < pins.size(); i++) |
125 | 0 | { |
126 | 0 | addReference(pins[i]); |
127 | 0 | } |
128 | 0 | } |
129 | | |
130 | | // Returns number of references to allocated memory that used in specific |
131 | | // layer blob. |
132 | | int numReferences(const LayerPin& lp) |
133 | 0 | { |
134 | 0 | std::map<LayerPin, LayerPin>::const_iterator mapIt = reuseMap.find(lp); |
135 | 0 | CV_Assert(mapIt != reuseMap.end()); |
136 | 0 | LayerPin memHost = mapIt->second; |
137 | |
|
138 | 0 | std::map<LayerPin, int>::const_iterator refIt = refCounter.find(memHost); |
139 | 0 | CV_Assert(refIt != refCounter.end()); |
140 | 0 | return refIt->second; |
141 | 0 | } |
142 | | |
143 | | // Reuse data allocated in <host> inside the <user> blob. |
144 | | void reuse(const LayerPin& host, const LayerPin& user) |
145 | 0 | { |
146 | 0 | CV_Assert(reuseMap.find(user) == reuseMap.end()); |
147 | 0 | CV_Assert(reuseMap.find(host) != reuseMap.end()); |
148 | 0 | LayerPin memHost = reuseMap[host]; |
149 | 0 | reuseMap[user] = memHost; |
150 | 0 | if (refCounter.find(memHost) != refCounter.end()) |
151 | 0 | { |
152 | 0 | std::map<LayerPin, int>::iterator userRefIt = refCounter.find(user); |
153 | 0 | if (userRefIt != refCounter.end()) |
154 | 0 | { |
155 | 0 | refCounter[memHost] += userRefIt->second; |
156 | 0 | refCounter.erase(userRefIt); |
157 | 0 | } |
158 | 0 | else |
159 | 0 | refCounter[memHost] += 1; |
160 | 0 | } |
161 | 0 | } |
162 | | |
163 | | // Decrease references counter to allocated memory inside specific blob. |
164 | | void releaseReference(const LayerPin& lp) |
165 | 0 | { |
166 | 0 | std::map<LayerPin, LayerPin>::const_iterator mapIt = reuseMap.find(lp); |
167 | 0 | CV_Assert(mapIt != reuseMap.end()); |
168 | | |
169 | 0 | std::map<LayerPin, int>::iterator refIt = refCounter.find(mapIt->second); |
170 | 0 | CV_Assert(refIt != refCounter.end()); |
171 | 0 | CV_Assert(refIt->second > 0); |
172 | 0 | refIt->second -= 1; |
173 | 0 | } |
174 | | |
175 | | void releaseReferences(const std::vector<LayerPin>& pins) |
176 | 0 | { |
177 | 0 | for (int i = 0; i < pins.size(); i++) |
178 | 0 | { |
179 | 0 | releaseReference(pins[i]); |
180 | 0 | } |
181 | 0 | } |
182 | | |
183 | | void reuseOrCreate(const MatShape& shape, const LayerPin& lp, Mat& dst, const int& dtype) |
184 | 0 | { |
185 | 0 | if (!getParam_DNN_DISABLE_MEMORY_OPTIMIZATIONS()) |
186 | 0 | { |
187 | 0 | Mat bestBlob; |
188 | 0 | LayerPin bestBlobPin; |
189 | |
|
190 | 0 | std::map<LayerPin, Mat>::const_iterator hostIt; |
191 | 0 | std::map<LayerPin, int>::const_iterator refIt; |
192 | |
|
193 | 0 | const int targetTotal = total(shape); |
194 | 0 | int bestBlobTotal = INT_MAX; |
195 | |
|
196 | 0 | for (hostIt = memHosts.begin(); hostIt != memHosts.end(); ++hostIt) |
197 | 0 | { |
198 | 0 | refIt = refCounter.find(hostIt->first); |
199 | | // Use only blobs that had references before because if not, |
200 | | // it might be used as output. |
201 | 0 | if (refIt != refCounter.end() && refIt->second == 0) |
202 | 0 | { |
203 | 0 | const Mat& unusedBlob = hostIt->second; |
204 | 0 | if (unusedBlob.total() >= targetTotal && unusedBlob.total() < bestBlobTotal && unusedBlob.type() == dtype) |
205 | 0 | { |
206 | 0 | bestBlobPin = hostIt->first; |
207 | 0 | bestBlob = unusedBlob; |
208 | 0 | bestBlobTotal = unusedBlob.total(); |
209 | 0 | } |
210 | 0 | } |
211 | 0 | } |
212 | 0 | if (!bestBlob.empty()) |
213 | 0 | { |
214 | 0 | reuse(bestBlobPin, lp); |
215 | 0 | dst = bestBlob.reshape(1, 1).colRange(0, targetTotal).reshape(1, shape); |
216 | 0 | dst.dims = shape.size(); |
217 | 0 | return; |
218 | 0 | } |
219 | 0 | } |
220 | | |
221 | 0 | { |
222 | | // if dst already has been allocated with total(shape) elements, |
223 | | // it won't be recreated and pointer of dst.data remains the same. |
224 | 0 | dst.create(shape, dtype); |
225 | 0 | addHost(lp, dst); |
226 | 0 | } |
227 | 0 | } |
228 | | |
229 | | void allocateBlobsForLayer(LayerData& ld, const LayerShapes& layerShapes, |
230 | | std::vector<LayerPin>& pinsForInternalBlobs) |
231 | 0 | { |
232 | 0 | CV_TRACE_FUNCTION(); |
233 | |
|
234 | 0 | pinsForInternalBlobs.clear(); |
235 | |
|
236 | 0 | std::vector<Mat>&outputBlobs = ld.outputBlobs, |
237 | 0 | &internalBlobs = ld.internals; |
238 | |
|
239 | 0 | const ShapesVec &outShapes = layerShapes.out, |
240 | 0 | internalShapes = layerShapes.internal; |
241 | |
|
242 | 0 | outputBlobs.resize(std::max((size_t)1, outShapes.size())); // layer produce at least one output blob |
243 | 0 | internalBlobs.resize(internalShapes.size()); |
244 | |
|
245 | 0 | CV_Assert(ld.requiredOutputs.size() <= outShapes.size()); |
246 | | |
247 | | // Check that layer could work in-place. |
248 | 0 | bool inPlace = false; |
249 | 0 | if (layerShapes.supportInPlace) |
250 | 0 | { |
251 | 0 | if (ld.inputBlobs.size() == 1) |
252 | 0 | { |
253 | | // Get number of references to the input memory. |
254 | 0 | int numRef = numReferences(ld.inputBlobsId[0]); |
255 | | // If current layer is one and only customer of this blob. |
256 | 0 | inPlace = numRef == 1; |
257 | 0 | } |
258 | 0 | } |
259 | |
|
260 | 0 | ShapesVec shapes(outShapes); |
261 | 0 | shapes.insert(shapes.end(), internalShapes.begin(), internalShapes.end()); |
262 | 0 | std::vector<Mat*> blobs; |
263 | 0 | for (int i = 0; i < outputBlobs.size(); i++) |
264 | 0 | { |
265 | 0 | blobs.push_back(&outputBlobs[i]); |
266 | 0 | } |
267 | |
|
268 | 0 | for (int i = 0; i < internalBlobs.size(); i++) |
269 | 0 | { |
270 | 0 | blobs.push_back(&internalBlobs[i]); |
271 | 0 | if (total(internalShapes[i])) |
272 | 0 | { |
273 | 0 | pinsForInternalBlobs.push_back(LayerPin(ld.id, ld.outputBlobs.size() + i)); |
274 | 0 | } |
275 | 0 | } |
276 | |
|
277 | 0 | addReferences(pinsForInternalBlobs); |
278 | |
|
279 | 0 | std::map<int, std::vector<int>> idxSizes; |
280 | 0 | for (int i = 0; i < shapes.size(); i++) |
281 | 0 | { |
282 | 0 | idxSizes[total(shapes[i])].push_back(i); |
283 | 0 | } |
284 | |
|
285 | 0 | std::map<int, std::vector<int>>::reverse_iterator it; |
286 | 0 | for (it = idxSizes.rbegin(); it != idxSizes.rend(); it++) |
287 | 0 | { |
288 | 0 | for (int j = 0; j < it->second.size(); j++) |
289 | 0 | { |
290 | 0 | int index = it->second[j]; |
291 | 0 | if (total(shapes[index])) |
292 | 0 | { |
293 | 0 | LayerPin blobPin(ld.id, index); |
294 | 0 | if (index < outShapes.size() && inPlace) |
295 | 0 | { |
296 | 0 | CV_Assert(ld.inputBlobs[0]->total() == total(shapes[index])); |
297 | 0 | ld.outputBlobs[index] = ld.inputBlobs[0]->reshape(1, shapes[index]); |
298 | 0 | reuse(ld.inputBlobsId[0], blobPin); |
299 | 0 | } |
300 | 0 | else |
301 | 0 | reuseOrCreate(shapes[index], blobPin, *blobs[index], ld.dtype); |
302 | 0 | } |
303 | 0 | } |
304 | 0 | } |
305 | 0 | } |
306 | | |
307 | | // Clear internal state. Calls before an every reallocation. |
308 | | void reset() |
309 | 0 | { |
310 | 0 | CV_TRACE_FUNCTION(); |
311 | |
|
312 | 0 | refCounter.clear(); |
313 | 0 | reuseMap.clear(); |
314 | 0 | memHosts.clear(); |
315 | 0 | } |
316 | | |
317 | | private: |
318 | | // Register allocated memory. |
319 | | void addHost(const LayerPin& lp, const Mat& mat) |
320 | 0 | { |
321 | 0 | CV_Assert(memHosts.find(lp) == memHosts.end()); |
322 | 0 | reuseMap[lp] = lp; |
323 | 0 | memHosts[lp] = mat; |
324 | 0 | } |
325 | | |
326 | | std::map<LayerPin, int> refCounter; |
327 | | // Maps pin to origin blob (for whom memory was allocated firstly). |
328 | | // For origin blobs key == value. |
329 | | std::map<LayerPin, LayerPin> reuseMap; |
330 | | std::map<LayerPin, Mat> memHosts; |
331 | | }; // BlobManager |
332 | | |
333 | | |
334 | | Ptr<BackendWrapper> wrapMat(int backendId, int targetId, cv::Mat& m); |
335 | | |
336 | | |
337 | | } // namespace detail |
338 | | CV__DNN_INLINE_NS_END |
339 | | }} // namespace cv::dnn |
340 | | #endif // __OPENCV_DNN_SRC_LEGACY_BACKEND_HPP__ |