Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/3rdparty/carotene/src/sum.cpp
16337 views
1
/*
2
* By downloading, copying, installing or using the software you agree to this license.
3
* If you do not agree to this license, do not download, install,
4
* copy or use the software.
5
*
6
*
7
* License Agreement
8
* For Open Source Computer Vision Library
9
* (3-clause BSD License)
10
*
11
* Copyright (C) 2012-2015, NVIDIA Corporation, all rights reserved.
12
* Third party copyrights are property of their respective owners.
13
*
14
* Redistribution and use in source and binary forms, with or without modification,
15
* are permitted provided that the following conditions are met:
16
*
17
* * Redistributions of source code must retain the above copyright notice,
18
* this list of conditions and the following disclaimer.
19
*
20
* * Redistributions in binary form must reproduce the above copyright notice,
21
* this list of conditions and the following disclaimer in the documentation
22
* and/or other materials provided with the distribution.
23
*
24
* * Neither the names of the copyright holders nor the names of the contributors
25
* may be used to endorse or promote products derived from this software
26
* without specific prior written permission.
27
*
28
* This software is provided by the copyright holders and contributors "as is" and
29
* any express or implied warranties, including, but not limited to, the implied
30
* warranties of merchantability and fitness for a particular purpose are disclaimed.
31
* In no event shall copyright holders or contributors be liable for any direct,
32
* indirect, incidental, special, exemplary, or consequential damages
33
* (including, but not limited to, procurement of substitute goods or services;
34
* loss of use, data, or profits; or business interruption) however caused
35
* and on any theory of liability, whether in contract, strict liability,
36
* or tort (including negligence or otherwise) arising in any way out of
37
* the use of this software, even if advised of the possibility of such damage.
38
*/
39
40
#include "common.hpp"
41
42
#include "vtransform.hpp"
43
44
namespace CAROTENE_NS {
45
46
bool isSumSupported(u32 channels)
47
{
48
return (channels && channels < 5);
49
}
50
51
void sum(const Size2D &_size,
52
const u8 * srcBase, ptrdiff_t srcStride,
53
u32 * sumdst, u32 channels)
54
{
55
internal::assertSupportedConfiguration(isSumSupported(channels));
56
#ifdef CAROTENE_NEON
57
Size2D size(_size);
58
if (srcStride == (ptrdiff_t)(size.width))
59
{
60
size.width *= size.height;
61
size.height = 1;
62
}
63
const ptrdiff_t width = size.width * channels;
64
65
for(size_t k = 0; k < size.height; ++k)
66
{
67
const u8* src = internal::getRowPtr( srcBase, srcStride, k);
68
ptrdiff_t i = 0;
69
70
if (channels == 3)
71
{
72
uint32x4_t vs1231 = vdupq_n_u32(0);
73
uint32x4_t vs3123 = vdupq_n_u32(0);
74
uint32x4_t vs2312 = vdupq_n_u32(0);
75
for (; i <= width - 257*8*3; i += 257*8*3, src += 257*8*3)
76
{
77
uint16x8_t s1 = vmovl_u8(vld1_u8(src + 0));
78
uint16x8_t s2 = vmovl_u8(vld1_u8(src + 8));
79
uint16x8_t s3 = vmovl_u8(vld1_u8(src + 16));
80
81
for (ptrdiff_t j = 8*3; j < 257*8*3; j+= 8*3)
82
{
83
internal::prefetch(src + j + 24);
84
s1 = vaddw_u8(s1, vld1_u8(src + j + 0));
85
s2 = vaddw_u8(s2, vld1_u8(src + j + 8));
86
s3 = vaddw_u8(s3, vld1_u8(src + j + 16));
87
}
88
89
vs1231 = vqaddq_u32(vs1231, vaddl_u16(vget_low_u16(s1), vget_high_u16(s2)));
90
vs3123 = vqaddq_u32(vs3123, vaddl_u16(vget_low_u16(s2), vget_high_u16(s3)));
91
vs2312 = vqaddq_u32(vs2312, vaddl_u16(vget_low_u16(s3), vget_high_u16(s1)));
92
}
93
if (i <= width - 8*3)
94
{
95
uint16x8_t s1 = vmovl_u8(vld1_u8(src + 0));
96
uint16x8_t s2 = vmovl_u8(vld1_u8(src + 8));
97
uint16x8_t s3 = vmovl_u8(vld1_u8(src + 16));
98
99
for (i += 8*3, src += 8*3; i <= width - 8*3; i += 8*3, src += 8*3)
100
{
101
internal::prefetch(src + 24);
102
s1 = vaddw_u8(s1, vld1_u8(src + 0));
103
s2 = vaddw_u8(s2, vld1_u8(src + 8));
104
s3 = vaddw_u8(s3, vld1_u8(src + 16));
105
}
106
107
vs1231 = vqaddq_u32(vs1231, vaddl_u16(vget_low_u16(s1), vget_high_u16(s2)));
108
vs3123 = vqaddq_u32(vs3123, vaddl_u16(vget_low_u16(s2), vget_high_u16(s3)));
109
vs2312 = vqaddq_u32(vs2312, vaddl_u16(vget_low_u16(s3), vget_high_u16(s1)));
110
}
111
112
u32 sum[12];
113
vst1q_u32(sum+0, vs1231);
114
vst1q_u32(sum+4, vs2312);
115
vst1q_u32(sum+8, vs3123);
116
117
for (; i < width; i += 3, src += 3)
118
{
119
sumdst[0] += src[0];
120
sumdst[1] += src[1];
121
sumdst[2] += src[2];
122
}
123
124
sumdst[0] += sum[0] + sum[3] + sum[6] + sum[9];
125
sumdst[1] += sum[1] + sum[4] + sum[7] + sum[10];
126
sumdst[2] += sum[2] + sum[5] + sum[8] + sum[11];
127
}
128
else
129
{
130
uint32x4_t vs = vdupq_n_u32(0);
131
for (; i <= width - 257*8; i += 257*8, src += 257 * 8)
132
{
133
uint16x8_t s1 = vmovl_u8(vld1_u8(src));
134
135
for (int j = 8; j < 257 * 8; j += 8)
136
{
137
internal::prefetch(src + j);
138
s1 = vaddw_u8(s1, vld1_u8(src + j));
139
}
140
141
vs = vqaddq_u32(vs, vaddl_u16(vget_low_u16(s1), vget_high_u16(s1)));
142
}
143
if (i < width - 7)
144
{
145
uint16x8_t s1 = vmovl_u8(vld1_u8(src));
146
147
for(i+=8,src+=8; i < width-7; i+=8,src+=8)
148
{
149
internal::prefetch(src);
150
s1 = vaddw_u8(s1, vld1_u8(src));
151
}
152
vs = vqaddq_u32(vs, vaddl_u16(vget_low_u16(s1), vget_high_u16(s1)));
153
}
154
155
if (channels == 1)
156
{
157
uint32x2_t vs2 = vqadd_u32(vget_low_u32(vs), vget_high_u32(vs));
158
uint32x2_t vs1 = vreinterpret_u32_u64(vpaddl_u32(vs2));
159
160
u32 s0 = vget_lane_u32(vs1, 0);
161
for(; i < width; ++i,++src)
162
s0 += src[0];
163
sumdst[0] += s0;
164
}
165
else if (channels == 4)
166
{
167
vst1q_u32(sumdst, vqaddq_u32(vs, vld1q_u32(sumdst)));
168
169
for(; i < width; i+=4,src+=4)
170
{
171
sumdst[0] += src[0];
172
sumdst[1] += src[1];
173
sumdst[2] += src[2];
174
sumdst[3] += src[3];
175
}
176
}
177
else//if (channels == 2)
178
{
179
uint32x2_t vs2 = vqadd_u32(vget_low_u32(vs), vget_high_u32(vs));
180
vst1_u32(sumdst, vqadd_u32(vs2, vld1_u32(sumdst)));
181
182
for(; i < width; i+=2,src+=2)
183
{
184
sumdst[0] += src[0];
185
sumdst[1] += src[1];
186
}
187
}
188
}//channels != 3
189
}
190
#else
191
(void)_size;
192
(void)srcBase;
193
(void)srcStride;
194
(void)sumdst;
195
(void)channels;
196
#endif
197
}
198
199
void sum(const Size2D &_size,
200
const f32 * srcBase, ptrdiff_t srcStride,
201
f64 * sumdst, u32 channels)
202
{
203
internal::assertSupportedConfiguration(isSumSupported(channels));
204
#ifdef CAROTENE_NEON
205
Size2D size(_size);
206
if (srcStride == (ptrdiff_t)(size.width))
207
{
208
size.width *= size.height;
209
size.height = 1;
210
}
211
const ptrdiff_t width = size.width * channels;
212
213
for(size_t k = 0; k < size.height; ++k)
214
{
215
const f32* src = internal::getRowPtr( srcBase, srcStride, k);
216
ptrdiff_t i = 0;
217
218
if (channels == 3)
219
{
220
float32x4_t vs1231 = vdupq_n_f32(0);
221
float32x4_t vs2312 = vdupq_n_f32(0);
222
float32x4_t vs3123 = vdupq_n_f32(0);
223
for(; i <= width-12; i += 12)
224
{
225
internal::prefetch(src + i + 12);
226
vs1231 = vaddq_f32(vs1231, vld1q_f32(src + i + 0));
227
vs2312 = vaddq_f32(vs2312, vld1q_f32(src + i + 4));
228
vs3123 = vaddq_f32(vs3123, vld1q_f32(src + i + 8));
229
}
230
231
f32 s[12];
232
vst1q_f32(s + 0, vs1231);
233
vst1q_f32(s + 4, vs2312);
234
vst1q_f32(s + 8, vs3123);
235
236
sumdst[0] += s[0] + s[3] + s[6] + s[9];
237
sumdst[1] += s[1] + s[4] + s[7] + s[10];
238
sumdst[2] += s[2] + s[5] + s[8] + s[11];
239
for( ; i < width; i+=3)
240
{
241
sumdst[0] += src[i];
242
sumdst[1] += src[i+1];
243
sumdst[2] += src[i+2];
244
}
245
}
246
else
247
{
248
float32x4_t vs = vdupq_n_f32(0);
249
for(; i <= width-4; i += 4)
250
{
251
internal::prefetch(src + i);
252
vs = vaddq_f32(vs, vld1q_f32(src+i));
253
}
254
255
if (channels == 1)
256
{
257
float32x2_t vs2 = vpadd_f32(vget_low_f32(vs), vget_high_f32(vs));
258
f32 s[2];
259
vst1_f32(s, vs2);
260
261
sumdst[0] += s[0] + s[1];
262
for( ; i < width; i++)
263
sumdst[0] += src[i];
264
}
265
else if (channels == 4)
266
{
267
f32 s[4];
268
vst1q_f32(s, vs);
269
270
sumdst[0] += s[0];
271
sumdst[1] += s[1];
272
sumdst[2] += s[2];
273
sumdst[3] += s[3];
274
}
275
else//if (channels == 2)
276
{
277
float32x2_t vs2 = vadd_f32(vget_low_f32(vs), vget_high_f32(vs));
278
f32 s[2];
279
vst1_f32(s, vs2);
280
281
sumdst[0] += s[0];
282
sumdst[1] += s[1];
283
284
if(i < width)
285
{
286
sumdst[0] += src[i];
287
sumdst[1] += src[i+1];
288
}
289
}
290
}//channels != 3
291
}
292
#else
293
(void)_size;
294
(void)srcBase;
295
(void)srcStride;
296
(void)sumdst;
297
(void)channels;
298
#endif
299
}
300
301
bool isSqsumSupported(u32 channels)
302
{
303
return (channels && ((4/channels)*channels == 4));
304
}
305
306
void sqsum(const Size2D &_size,
307
const u8 * srcBase, ptrdiff_t srcStride,
308
f64 * sumdst, f64 * sqsumdst, u32 channels)
309
{
310
internal::assertSupportedConfiguration(isSqsumSupported(channels));
311
#ifdef CAROTENE_NEON
312
Size2D size(_size);
313
if (srcStride == (ptrdiff_t)(size.width*channels))
314
{
315
size.width *= size.height;
316
size.height = 1;
317
}
318
const size_t width = size.width * channels;
319
320
size_t blockSize0 = 1 << 23;
321
size_t roiw8 = width & ~7;
322
323
uint32x4_t v_zero = vdupq_n_u32(0u);
324
325
for (size_t i = 0; i < size.height; ++i)
326
{
327
const u8 * src = internal::getRowPtr(srcBase, srcStride, i);
328
size_t j = 0u;
329
330
while (j < roiw8)
331
{
332
size_t blockSize = std::min(roiw8 - j, blockSize0) + j;
333
uint32x4_t v_sum = v_zero;
334
uint32x4_t v_sqsum = v_zero;
335
336
for ( ; j < blockSize ; j += 8, src += 8)
337
{
338
internal::prefetch(src);
339
uint8x8_t v_src0 = vld1_u8(src);
340
341
uint16x8_t v_src = vmovl_u8(v_src0);
342
uint16x4_t v_srclo = vget_low_u16(v_src), v_srchi = vget_high_u16(v_src);
343
v_sum = vaddq_u32(v_sum, vaddl_u16(v_srclo, v_srchi));
344
v_sqsum = vmlal_u16(v_sqsum, v_srclo, v_srclo);
345
v_sqsum = vmlal_u16(v_sqsum, v_srchi, v_srchi);
346
}
347
348
u32 arsum[8];
349
vst1q_u32(arsum, v_sum);
350
vst1q_u32(arsum + 4, v_sqsum);
351
352
sumdst[0] += (f64)arsum[0];
353
sumdst[1 % channels] += (f64)arsum[1];
354
sumdst[2 % channels] += (f64)arsum[2];
355
sumdst[3 % channels] += (f64)arsum[3];
356
sqsumdst[0] += (f64)arsum[4];
357
sqsumdst[1 % channels] += (f64)arsum[5];
358
sqsumdst[2 % channels] += (f64)arsum[6];
359
sqsumdst[3 % channels] += (f64)arsum[7];
360
}
361
// collect a few last elements in the current row
362
// it's ok to process channels elements per step
363
// since we could handle 1,2 or 4 channels
364
// we always have channels-fold amount of elements remaining
365
for ( ; j < width; j+=channels, src+=channels)
366
{
367
for (u32 kk = 0; kk < channels; kk++)
368
{
369
u32 srcval = src[kk];
370
sumdst[kk] += srcval;
371
sqsumdst[kk] += srcval * srcval;
372
}
373
}
374
}
375
#else
376
(void)_size;
377
(void)srcBase;
378
(void)srcStride;
379
(void)sumdst;
380
(void)sqsumdst;
381
(void)channels;
382
#endif
383
}
384
385
} // namespace CAROTENE_NS
386
387