Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/gapi/src/backends/fluid/gfluidbuffer.cpp
16354 views
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
// Copyright (C) 2018 Intel Corporation
6
7
8
#include "precomp.hpp"
9
10
#include <iomanip> // hex, dec (debug)
11
12
#include "opencv2/gapi/own/convert.hpp"
13
#include "opencv2/gapi/own/types.hpp"
14
15
#include "opencv2/gapi/fluid/gfluidbuffer.hpp"
16
#include "backends/fluid/gfluidbuffer_priv.hpp"
17
#include "opencv2/gapi/opencv_includes.hpp"
18
19
#include "backends/fluid/gfluidutils.hpp" // saturate
20
21
namespace cv {
22
namespace gapi {
23
namespace fluid {
24
bool operator == (const fluid::Border& b1, const fluid::Border& b2)
25
{
26
return b1.type == b2.type && b1.value == b2.value;
27
}
28
} // namespace fluid
29
30
// Fluid BorderHandler implementation /////////////////////////////////////////////////
31
32
namespace {
33
template<typename T>
34
// Expected inputs:
35
// row - row buffer allocated with border in mind (have memory for both image and border pixels)
36
// length - size of the buffer with left and right borders included
37
void fillBorderReplicateRow(uint8_t* row, int length, int chan, int borderSize)
38
{
39
auto leftBorder = reinterpret_cast<T*>(row);
40
auto rightBorder = leftBorder + (length - borderSize) * chan;
41
for (int b = 0; b < borderSize; b++)
42
{
43
for (int c = 0; c < chan; c++)
44
{
45
leftBorder [b*chan + c] = leftBorder [borderSize*chan + c];
46
rightBorder[b*chan + c] = rightBorder[-chan + c];
47
}
48
}
49
}
50
51
template<typename T>
52
void fillBorderReflectRow(uint8_t* row, int length, int chan, int borderSize)
53
{
54
auto leftBorder = reinterpret_cast<T*>(row);
55
auto rightBorder = leftBorder + (length - borderSize) * chan;
56
for (int b = 0; b < borderSize; b++)
57
{
58
for (int c = 0; c < chan; c++)
59
{
60
leftBorder [b*chan + c] = leftBorder [(2*borderSize - b)*chan + c];
61
rightBorder[b*chan + c] = rightBorder[(-b - 2)*chan + c];
62
}
63
}
64
}
65
66
template<typename T>
67
void fillConstBorderRow(uint8_t* row, int length, int chan, int borderSize, cv::gapi::own::Scalar borderValue)
68
{
69
GAPI_DbgAssert(chan > 0 && chan <= 4);
70
71
auto leftBorder = reinterpret_cast<T*>(row);
72
auto rightBorder = leftBorder + (length - borderSize) * chan;
73
for (int b = 0; b < borderSize; b++)
74
{
75
for (int c = 0; c < chan; c++)
76
{
77
leftBorder [b*chan + c] = fluid::saturate<T>(borderValue[c], fluid::roundd);
78
rightBorder[b*chan + c] = fluid::saturate<T>(borderValue[c], fluid::roundd);
79
}
80
}
81
}
82
83
// Fills const border pixels in the whole mat
84
void fillBorderConstant(int borderSize, cv::gapi::own::Scalar borderValue, cv::gapi::own::Mat& mat)
85
{
86
// cv::Scalar can contain maximum 4 chan
87
GAPI_Assert(mat.channels() > 0 && mat.channels() <= 4);
88
89
auto getFillBorderRowFunc = [&](int type) {
90
switch(type)
91
{
92
case CV_8U: return &fillConstBorderRow< uint8_t>; break;
93
case CV_16S: return &fillConstBorderRow< int16_t>; break;
94
case CV_16U: return &fillConstBorderRow<uint16_t>; break;
95
case CV_32F: return &fillConstBorderRow< float >; break;
96
default: GAPI_Assert(false); return &fillConstBorderRow<uint8_t>;
97
}
98
};
99
100
auto fillBorderRow = getFillBorderRowFunc(mat.depth());
101
for (int y = 0; y < mat.rows; y++)
102
{
103
fillBorderRow(mat.ptr(y), mat.cols, mat.channels(), borderSize, borderValue);
104
}
105
}
106
} // anonymous namespace
107
108
fluid::BorderHandler::BorderHandler(int border_size)
109
{
110
GAPI_Assert(border_size > 0);
111
m_border_size = border_size;
112
}
113
114
template <int BorderType>
115
fluid::BorderHandlerT<BorderType>::BorderHandlerT(int border_size, int data_type)
116
: BorderHandler(border_size)
117
{
118
auto getFillBorderRowFunc = [&](int border, int dataType) {
119
if (border == cv::BORDER_REPLICATE)
120
{
121
switch(dataType)
122
{
123
case CV_8U: return &fillBorderReplicateRow< uint8_t>; break;
124
case CV_16S: return &fillBorderReplicateRow< int16_t>; break;
125
case CV_16U: return &fillBorderReplicateRow<uint16_t>; break;
126
case CV_32F: return &fillBorderReplicateRow< float >; break;
127
default: GAPI_Assert(!"Unsupported data type"); return &fillBorderReplicateRow<uint8_t>;
128
}
129
}
130
else if (border == cv::BORDER_REFLECT_101)
131
{
132
switch(dataType)
133
{
134
case CV_8U: return &fillBorderReflectRow< uint8_t>; break;
135
case CV_16S: return &fillBorderReflectRow< int16_t>; break;
136
case CV_16U: return &fillBorderReflectRow<uint16_t>; break;
137
case CV_32F: return &fillBorderReflectRow< float >; break;
138
default: GAPI_Assert(!"Unsupported data type"); return &fillBorderReflectRow<uint8_t>;
139
}
140
}
141
else
142
{
143
GAPI_Assert(!"Unsupported border type");
144
return &fillBorderReflectRow<uint8_t>;
145
}
146
};
147
148
m_fill_border_row = getFillBorderRowFunc(BorderType, data_type);
149
}
150
151
namespace {
152
template <int BorderType> int getBorderIdx(int log_idx, int desc_height);
153
154
template<> int getBorderIdx<cv::BORDER_REPLICATE>(int log_idx, int desc_height)
155
{
156
return log_idx < 0 ? 0 : desc_height - 1;
157
}
158
159
template<> int getBorderIdx<cv::BORDER_REFLECT_101>(int log_idx, int desc_height)
160
{
161
return log_idx < 0 ? -log_idx : 2*(desc_height - 1) - log_idx;
162
}
163
} // namespace
164
165
template <int BorderType>
166
const uint8_t* fluid::BorderHandlerT<BorderType>::inLineB(int log_idx, const BufferStorageWithBorder& data, int desc_height) const
167
{
168
auto idx = getBorderIdx<BorderType>(log_idx, desc_height);
169
return data.ptr(idx);
170
}
171
172
fluid::BorderHandlerT<cv::BORDER_CONSTANT>::BorderHandlerT(int border_size, cv::gapi::own::Scalar border_value, int data_type, int desc_width)
173
: BorderHandler(border_size), m_border_value(border_value)
174
{
175
m_const_border.create(1, desc_width + 2*m_border_size, data_type);
176
m_const_border = border_value;
177
}
178
179
const uint8_t* fluid::BorderHandlerT<cv::BORDER_CONSTANT>::inLineB(int /*log_idx*/, const BufferStorageWithBorder& /*data*/, int /*desc_height*/) const
180
{
181
return m_const_border.ptr(0, m_border_size);
182
}
183
184
void fluid::BorderHandlerT<cv::BORDER_CONSTANT>::fillCompileTimeBorder(BufferStorageWithBorder& data) const
185
{
186
cv::gapi::fillBorderConstant(m_border_size, m_border_value, data.data());
187
}
188
189
template <int BorderType>
190
void fluid::BorderHandlerT<BorderType>::updateBorderPixels(BufferStorageWithBorder &data, int startLine, int nLines) const
191
{
192
auto& mat = data.data();
193
auto length = mat.cols;
194
auto chan = mat.channels();
195
196
for (int l = startLine; l < startLine + nLines; l++)
197
{
198
auto row = mat.ptr(data.physIdx(l));
199
m_fill_border_row(row, length, chan, m_border_size);
200
}
201
}
202
203
std::size_t fluid::BorderHandlerT<cv::BORDER_CONSTANT>::size() const
204
{
205
return m_const_border.total() * m_const_border.elemSize();
206
}
207
208
// Fluid BufferStorage implementation //////////////////////////////////////////
209
void fluid::BufferStorageWithBorder::create(int capacity, int desc_width, int dtype, int border_size, Border border)
210
{
211
auto width = (desc_width + 2*border_size);
212
m_data.create(capacity, width, dtype);
213
214
switch(border.type)
215
{
216
case cv::BORDER_CONSTANT:
217
m_borderHandler.reset(new BorderHandlerT<cv::BORDER_CONSTANT>(border_size, border.value, dtype, desc_width)); break;
218
case cv::BORDER_REPLICATE:
219
m_borderHandler.reset(new BorderHandlerT<cv::BORDER_REPLICATE>(border_size, dtype)); break;
220
case cv::BORDER_REFLECT_101:
221
m_borderHandler.reset(new BorderHandlerT<cv::BORDER_REFLECT_101>(border_size, dtype)); break;
222
default:
223
GAPI_Assert(false);
224
}
225
226
m_borderHandler->fillCompileTimeBorder(*this);
227
}
228
229
void fluid::BufferStorageWithoutBorder::create(int capacity, int desc_width, int dtype)
230
{
231
auto width = desc_width;
232
m_data.create(capacity, width, dtype);
233
234
m_is_virtual = true;
235
}
236
237
const uint8_t* fluid::BufferStorageWithBorder::inLineB(int log_idx, int desc_height) const
238
{
239
if (log_idx < 0 || log_idx >= desc_height)
240
{
241
return m_borderHandler->inLineB(log_idx, *this, desc_height);
242
}
243
else
244
{
245
return ptr(log_idx);
246
}
247
}
248
249
const uint8_t* fluid::BufferStorageWithoutBorder::inLineB(int log_idx, int /*desc_height*/) const
250
{
251
return ptr(log_idx);
252
}
253
254
static void copyWithoutBorder(const cv::gapi::own::Mat& src, int src_border_size, cv::gapi::own::Mat& dst, int dst_border_size, int startSrcLine, int startDstLine, int lpi)
255
{
256
auto subSrc = src(cv::gapi::own::Rect{src_border_size, startSrcLine, src.cols - 2*src_border_size, lpi});
257
auto subDst = dst(cv::gapi::own::Rect{dst_border_size, startDstLine, dst.cols - 2*dst_border_size, lpi});
258
259
subSrc.copyTo(subDst);
260
}
261
262
void fluid::BufferStorageWithoutBorder::copyTo(BufferStorageWithBorder &dst, int startLine, int nLines) const
263
{
264
for (int l = startLine; l < startLine + nLines; l++)
265
{
266
copyWithoutBorder(m_data, 0, dst.data(), dst.borderSize(), physIdx(l), dst.physIdx(l), 1);
267
}
268
}
269
270
void fluid::BufferStorageWithBorder::copyTo(BufferStorageWithBorder &dst, int startLine, int nLines) const
271
{
272
// Copy required lpi lines line by line (to avoid wrap if invoked for multiple lines)
273
for (int l = startLine; l < startLine + nLines; l++)
274
{
275
copyWithoutBorder(m_data, borderSize(), dst.data(), dst.borderSize(), physIdx(l), dst.physIdx(l), 1);
276
}
277
}
278
279
// FIXME? remember parent and remove src parameter?
280
void fluid::BufferStorageWithBorder::updateBeforeRead(int startLine, int nLines, const BufferStorage& src)
281
{
282
// TODO:
283
// Cover with tests!!
284
// (Ensure that there are no redundant copies done
285
// and only required (not fetched before) lines are copied)
286
287
GAPI_DbgAssert(startLine >= 0);
288
289
src.copyTo(*this, startLine, nLines);
290
m_borderHandler->updateBorderPixels(*this, startLine, nLines);
291
}
292
293
void fluid::BufferStorageWithoutBorder::updateBeforeRead(int /*startLine*/, int /*lpi*/, const BufferStorage& /*src*/)
294
{
295
/* nothing */
296
}
297
298
void fluid::BufferStorageWithBorder::updateAfterWrite(int startLine, int nLines)
299
{
300
// FIXME?
301
// Actually startLine + nLines can be > logical height so
302
// redundant end lines which will never be read
303
// can be filled in the ring buffer
304
m_borderHandler->updateBorderPixels(*this, startLine, nLines);
305
}
306
307
void fluid::BufferStorageWithoutBorder::updateAfterWrite(int /*startLine*/, int /*lpi*/)
308
{
309
/* nothing */
310
}
311
312
size_t fluid::BufferStorageWithBorder::size() const
313
{
314
return m_data.total()*m_data.elemSize() + m_borderHandler->size();
315
}
316
317
size_t fluid::BufferStorageWithoutBorder::size() const
318
{
319
return m_data.total()*m_data.elemSize();
320
}
321
322
namespace fluid {
323
namespace {
324
std::unique_ptr<fluid::BufferStorage> createStorage(int capacity, int desc_width, int type,
325
int border_size, fluid::BorderOpt border);
326
std::unique_ptr<fluid::BufferStorage> createStorage(int capacity, int desc_width, int type,
327
int border_size, fluid::BorderOpt border)
328
{
329
if (border)
330
{
331
std::unique_ptr<fluid::BufferStorageWithBorder> storage(new BufferStorageWithBorder);
332
storage->create(capacity, desc_width, type, border_size, border.value());
333
return std::move(storage);
334
}
335
336
std::unique_ptr<BufferStorageWithoutBorder> storage(new BufferStorageWithoutBorder);
337
storage->create(capacity, desc_width, type);
338
return std::move(storage);
339
}
340
341
std::unique_ptr<BufferStorage> createStorage(const cv::gapi::own::Mat& data, cv::gapi::own::Rect roi);
342
std::unique_ptr<BufferStorage> createStorage(const cv::gapi::own::Mat& data, cv::gapi::own::Rect roi)
343
{
344
std::unique_ptr<BufferStorageWithoutBorder> storage(new BufferStorageWithoutBorder);
345
storage->attach(data, roi);
346
return std::move(storage);
347
}
348
} // namespace
349
} // namespace fluid
350
351
// Fluid View implementation ///////////////////////////////////////////////////
352
353
void fluid::View::Priv::reset(int linesForFirstIteration)
354
{
355
GAPI_DbgAssert(m_p);
356
357
m_lines_next_iter = linesForFirstIteration;
358
m_read_caret = m_p->priv().readStart();
359
}
360
361
void fluid::View::Priv::readDone(int linesRead, int linesForNextIteration)
362
{
363
GAPI_DbgAssert(m_p);
364
m_read_caret += linesRead;
365
m_read_caret %= m_p->meta().size.height;
366
m_lines_next_iter = linesForNextIteration;
367
}
368
369
bool fluid::View::Priv::ready() const
370
{
371
auto lastWrittenLine = m_p->priv().writeStart() + m_p->linesReady();
372
// + bottom border
373
if (lastWrittenLine == m_p->meta().size.height) lastWrittenLine += m_border_size;
374
// + top border
375
lastWrittenLine += m_border_size;
376
377
auto lastRequiredLine = m_read_caret + m_lines_next_iter;
378
379
return lastWrittenLine >= lastRequiredLine;
380
}
381
382
fluid::ViewPrivWithoutOwnBorder::ViewPrivWithoutOwnBorder(const Buffer *parent, int borderSize)
383
{
384
GAPI_Assert(parent);
385
m_p = parent;
386
m_border_size = borderSize;
387
}
388
389
const uint8_t* fluid::ViewPrivWithoutOwnBorder::InLineB(int index) const
390
{
391
GAPI_DbgAssert(m_p);
392
393
const auto &p_priv = m_p->priv();
394
395
GAPI_DbgAssert(index >= -m_border_size
396
&& index < -m_border_size + m_lines_next_iter);
397
398
const int log_idx = m_read_caret + index;
399
400
return p_priv.storage().inLineB(log_idx, m_p->meta().size.height);
401
}
402
403
fluid::ViewPrivWithOwnBorder::ViewPrivWithOwnBorder(const Buffer *parent, int lineConsumption, int borderSize, Border border)
404
{
405
GAPI_Assert(parent);
406
m_p = parent;
407
m_border_size = borderSize;
408
409
auto desc = m_p->meta();
410
int type = CV_MAKETYPE(desc.depth, desc.chan);
411
m_own_storage.create(lineConsumption, desc.size.width, type, borderSize, border);
412
}
413
414
void fluid::ViewPrivWithOwnBorder::prepareToRead()
415
{
416
int startLine = 0;
417
int nLines = 0;
418
419
if (m_read_caret == m_p->priv().readStart())
420
{
421
// Need to fetch full window on the first iteration
422
startLine = (m_read_caret > m_border_size) ? m_read_caret - m_border_size : 0;
423
nLines = m_lines_next_iter;
424
}
425
else
426
{
427
startLine = m_read_caret + m_border_size;
428
nLines = m_lines_next_iter - 2*m_border_size;
429
}
430
431
m_own_storage.updateBeforeRead(startLine, nLines, m_p->priv().storage());
432
}
433
434
std::size_t fluid::ViewPrivWithOwnBorder::size() const
435
{
436
GAPI_DbgAssert(m_p);
437
return m_own_storage.size();
438
}
439
440
const uint8_t* fluid::ViewPrivWithOwnBorder::InLineB(int index) const
441
{
442
GAPI_DbgAssert(m_p);
443
GAPI_DbgAssert(index >= -m_border_size
444
&& index < -m_border_size + m_lines_next_iter);
445
446
const int log_idx = m_read_caret + index;
447
448
return m_own_storage.inLineB(log_idx, m_p->meta().size.height);
449
}
450
451
const uint8_t* fluid::View::InLineB(int index) const
452
{
453
return m_priv->InLineB(index);
454
}
455
456
fluid::View::operator bool() const
457
{
458
return m_priv != nullptr && m_priv->m_p != nullptr;
459
}
460
461
int fluid::View::length() const
462
{
463
return m_priv->m_p->length();
464
}
465
466
bool fluid::View::ready() const
467
{
468
return m_priv->ready();
469
}
470
471
int fluid::View::y() const
472
{
473
return m_priv->m_read_caret - m_priv->m_border_size;
474
}
475
476
const GMatDesc& fluid::View::meta() const
477
{
478
// FIXME: cover with test!
479
return m_priv->m_p->meta();
480
}
481
482
fluid::View::Priv& fluid::View::priv()
483
{
484
return *m_priv;
485
}
486
487
const fluid::View::Priv& fluid::View::priv() const
488
{
489
return *m_priv;
490
}
491
492
// Fluid Buffer implementation /////////////////////////////////////////////////
493
494
fluid::Buffer::Priv::Priv(int read_start, cv::gapi::own::Rect roi)
495
: m_readStart(read_start)
496
, m_roi(roi)
497
{}
498
499
void fluid::Buffer::Priv::init(const cv::GMatDesc &desc,
500
int wlpi,
501
int readStartPos,
502
cv::gapi::own::Rect roi)
503
{
504
m_writer_lpi = wlpi;
505
m_desc = desc;
506
m_readStart = readStartPos;
507
m_roi = roi == cv::Rect{} ? cv::Rect{0, 0, desc.size.width, desc.size.height}
508
: roi;
509
}
510
511
void fluid::Buffer::Priv::allocate(BorderOpt border,
512
int border_size,
513
int line_consumption,
514
int skew)
515
{
516
GAPI_Assert(!m_storage);
517
GAPI_Assert(line_consumption > 0);
518
519
// Init physical buffer
520
521
// FIXME? combine line_consumption with skew?
522
auto data_height = std::max(line_consumption, skew) + m_writer_lpi - 1;
523
524
m_storage = createStorage(data_height,
525
m_desc.size.width,
526
CV_MAKETYPE(m_desc.depth, m_desc.chan),
527
border_size,
528
border);
529
530
// Finally, initialize carets
531
m_write_caret = 0;
532
}
533
534
void fluid::Buffer::Priv::bindTo(const cv::gapi::own::Mat &data, bool is_input)
535
{
536
// FIXME: move all these fields into a separate structure
537
GAPI_Assert(m_desc == descr_of(data));
538
539
// Currently m_writer_lpi is obtained from metadata which is shared between islands
540
// and this assert can trigger for slot which connects two fluid islands.
541
// m_writer_lpi is used only in write-related functions and doesn't affect
542
// buffer which is island's input so it's safe to skip this check.
543
// FIXME:
544
// Bring back this check when we move to 1 buffer <-> 1 metadata model
545
// if (is_input) GAPI_Assert(m_writer_lpi == 1);
546
547
m_storage = createStorage(data, m_roi);
548
549
m_is_input = is_input;
550
m_write_caret = is_input ? writeEnd(): writeStart();
551
// NB: views remain the same!
552
}
553
554
bool fluid::Buffer::Priv::full() const
555
{
556
int slowest_y = writeEnd();
557
if (!m_views.empty())
558
{
559
// reset with maximum possible value and then find minimum
560
slowest_y = m_desc.size.height;
561
for (const auto &v : m_views) slowest_y = std::min(slowest_y, v.y());
562
}
563
564
return m_write_caret + lpi() - slowest_y > m_storage->rows();
565
}
566
567
void fluid::Buffer::Priv::writeDone()
568
{
569
// There are possible optimizations which can be done to fill a border values
570
// in compile time of the graph (for example border is const),
571
// so there is no need to update border values after each write.
572
// If such optimizations weren't applied, fill border for lines
573
// which have been just written
574
m_storage->updateAfterWrite(m_write_caret, m_writer_lpi);
575
576
// Final write may produce less LPI, so
577
// write caret may exceed logical buffer size
578
m_write_caret += m_writer_lpi;
579
// FIXME: add consistency check!
580
}
581
582
void fluid::Buffer::Priv::reset()
583
{
584
m_write_caret = m_is_input ? writeEnd() : writeStart();
585
}
586
587
int fluid::Buffer::Priv::size() const
588
{
589
std::size_t view_sz = 0;
590
for (const auto &v : m_views) view_sz += v.priv().size();
591
592
auto total = view_sz;
593
if (m_storage) total += m_storage->size();
594
595
// FIXME: Change API to return size_t!!!
596
return static_cast<int>(total);
597
}
598
599
int fluid::Buffer::Priv::linesReady() const
600
{
601
if (m_is_input)
602
{
603
return m_storage->rows();
604
}
605
else
606
{
607
const int writes = std::min(m_write_caret - writeStart(), outputLines());
608
return writes;
609
}
610
}
611
612
uint8_t* fluid::Buffer::Priv::OutLineB(int index)
613
{
614
GAPI_DbgAssert(index >= 0 && index < m_writer_lpi);
615
616
return m_storage->ptr(m_write_caret + index);
617
}
618
619
int fluid::Buffer::Priv::lpi() const
620
{
621
// FIXME:
622
// m_write_caret can be greater than m_writeRoi.y + m_writeRoi.height, so return value can be negative !!!
623
return std::min(writeEnd() - m_write_caret, m_writer_lpi);
624
}
625
626
fluid::Buffer::Buffer()
627
: m_priv(new Priv())
628
{
629
}
630
631
fluid::Buffer::Buffer(const cv::GMatDesc &desc)
632
: m_priv(new Priv())
633
{
634
int lineConsumption = 1;
635
int border = 0, skew = 0, wlpi = 1, readStart = 0;
636
cv::gapi::own::Rect roi = {0, 0, desc.size.width, desc.size.height};
637
m_priv->init(desc, wlpi, readStart, roi);
638
m_priv->allocate({}, border, lineConsumption, skew);
639
}
640
641
fluid::Buffer::Buffer(const cv::GMatDesc &desc,
642
int max_line_consumption,
643
int border_size,
644
int skew,
645
int wlpi,
646
BorderOpt border)
647
: m_priv(new Priv())
648
{
649
int readStart = 0;
650
cv::gapi::own::Rect roi = {0, 0, desc.size.width, desc.size.height};
651
m_priv->init(desc, wlpi, readStart, roi);
652
m_priv->allocate(border, border_size, max_line_consumption, skew);
653
}
654
655
fluid::Buffer::Buffer(const cv::gapi::own::Mat &data, bool is_input)
656
: m_priv(new Priv())
657
{
658
int wlpi = 1, readStart = 0;
659
cv::gapi::own::Rect roi{0, 0, data.cols, data.rows};
660
m_priv->init(descr_of(data), wlpi, readStart, roi);
661
m_priv->bindTo(data, is_input);
662
}
663
664
uint8_t* fluid::Buffer::Buffer::OutLineB(int index)
665
{
666
return m_priv->OutLineB(index);
667
}
668
669
int fluid::Buffer::linesReady() const
670
{
671
return m_priv->linesReady();
672
}
673
674
int fluid::Buffer::length() const
675
{
676
return meta().size.width;
677
}
678
679
int fluid::Buffer::lpi() const
680
{
681
return m_priv->lpi();
682
}
683
684
const GMatDesc& fluid::Buffer::meta() const
685
{
686
return m_priv->meta();
687
}
688
689
fluid::View::View(Priv* p)
690
: m_priv(p)
691
{ /* nothing */ }
692
693
fluid::View fluid::Buffer::mkView(int lineConsumption, int borderSize, BorderOpt border, bool ownStorage)
694
{
695
// FIXME: logic outside of Priv (because View takes pointer to Buffer)
696
auto view = ownStorage ? View(new ViewPrivWithOwnBorder(this, lineConsumption, borderSize, border.value()))
697
: View(new ViewPrivWithoutOwnBorder(this, borderSize));
698
m_priv->addView(view);
699
return view;
700
}
701
702
void fluid::debugBufferPriv(const fluid::Buffer& buffer, std::ostream &os)
703
{
704
// FIXME Use cv::gapi::own Size and Rect with operator<<, when merged ADE-285
705
const auto& p = buffer.priv();
706
os << "Fluid buffer " << std::hex << &buffer << std::dec
707
<< " " << p.m_desc.size.width << " x " << p.m_desc.size.height << "]"
708
<< " readStart:" << p.m_readStart
709
<< " roi:" << "[" << p.m_roi.width << " x " << p.m_roi.height << " from (" << p.m_roi.x << ", " << p.m_roi.y << ")]"
710
<<" (phys " << "[" << p.storage().cols() << " x " << p.storage().rows() << "]" << ") :"
711
<< " w: " << p.m_write_caret
712
<< ", r: [";
713
for (const auto &v : p.m_views) { os << &v.priv() << ":" << v.y() << " "; }
714
os << "], avail: " << buffer.linesReady()
715
<< std::endl;
716
}
717
718
void fluid::Buffer::debug(std::ostream &os) const
719
{
720
debugBufferPriv(*this, os);
721
}
722
723
fluid::Buffer::Priv& fluid::Buffer::priv()
724
{
725
return *m_priv;
726
}
727
728
const fluid::Buffer::Priv& fluid::Buffer::priv() const
729
{
730
return *m_priv;
731
}
732
733
int fluid::Buffer::y() const
734
{
735
return m_priv->y();
736
}
737
738
} // namespace cv::gapi
739
} // namespace cv
740
741