Coverage Report

Created: 2025-06-12 06:52

/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__