Coverage Report

Created: 2026-09-14 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/CommonLib/Buffer.cpp
Line
Count
Source
1
/* -----------------------------------------------------------------------------
2
The copyright in this software is being made available under the Clear BSD
3
License, included below. No patent rights, trademark rights and/or 
4
other Intellectual Property Rights other than the copyrights concerning 
5
the Software are granted under this license.
6
7
The Clear BSD License
8
9
Copyright (c) 2019-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVenC Authors.
10
All rights reserved.
11
12
Redistribution and use in source and binary forms, with or without modification,
13
are permitted (subject to the limitations in the disclaimer below) provided that
14
the following conditions are met:
15
16
     * Redistributions of source code must retain the above copyright notice,
17
     this list of conditions and the following disclaimer.
18
19
     * Redistributions in binary form must reproduce the above copyright
20
     notice, this list of conditions and the following disclaimer in the
21
     documentation and/or other materials provided with the distribution.
22
23
     * Neither the name of the copyright holder nor the names of its
24
     contributors may be used to endorse or promote products derived from this
25
     software without specific prior written permission.
26
27
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
28
THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
29
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
31
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
32
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
36
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
POSSIBILITY OF SUCH DAMAGE.
39
40
41
------------------------------------------------------------------------------------------- */
42
43
44
/** \file     Buffer.cpp
45
 *  \brief    Low-overhead class describing 2D memory layout
46
 */
47
48
#define DONT_UNDEF_SIZE_AWARE_PER_EL_OP
49
50
// unit needs to come first due to a forward declaration
51
#include "Unit.h"
52
#include "Slice.h"
53
#include "InterpolationFilter.h"
54
55
//! \ingroup CommonLib
56
//! \{
57
58
namespace vvenc {
59
60
void weightCiipCore( Pel* res, const Pel* src, const int numSamples, int numIntra )
61
0
{
62
0
  if( numIntra == 1 )
63
0
  {
64
0
    for (int n = 0; n < numSamples; n+=2)
65
0
    {
66
0
      res[n  ] = (res[n  ] + src[n  ] + 1) >> 1;
67
0
      res[n+1] = (res[n+1] + src[n+1] + 1) >> 1;
68
0
    }
69
0
  }
70
0
  else
71
0
  {
72
0
    const Pel* scale   = numIntra ? src : res;
73
0
    const Pel* unscale = numIntra ? res : src;
74
75
0
    for (int n = 0; n < numSamples; n+=2)
76
0
    {
77
0
      res[n  ] = (unscale[n  ] + 3*scale[n  ] + 2) >> 2;
78
0
      res[n+1] = (unscale[n+1] + 3*scale[n+1] + 2) >> 2;
79
0
    }
80
0
  }
81
0
}
82
83
template< unsigned inputSize, unsigned outputSize >
84
void mipMatrixMulCore( Pel* res, const Pel* input, const uint8_t* weight, const int maxVal, const int inputOffset, bool transpose )
85
256k
{
86
256k
  Pel buffer[ outputSize*outputSize];
87
88
256k
  int sum = 0;
89
2.30M
  for( int i = 0; i < inputSize; i++ )
90
2.04M
  {
91
2.04M
    sum += input[i];
92
2.04M
  }
93
256k
  const int offset = (1 << (MIP_SHIFT_MATRIX - 1)) - MIP_OFFSET_MATRIX * sum + (inputOffset << MIP_SHIFT_MATRIX);
94
256k
  CHECK( inputSize != 4 * (inputSize >> 2), "Error, input size not divisible by four" );
95
96
256k
  Pel* mat = transpose ? buffer : res;
97
256k
  unsigned posRes = 0;
98
16.3M
  for( unsigned n = 0; n < outputSize*outputSize; n++ )
99
16.1M
  {
100
16.1M
    int tmp0 = input[0] * weight[0];
101
16.1M
    int tmp1 = input[1] * weight[1];
102
16.1M
    int tmp2 = input[2] * weight[2];
103
16.1M
    int tmp3 = input[3] * weight[3];
104
16.1M
    if( 8 == inputSize )
105
16.1M
    {
106
16.1M
      tmp0 += input[4] * weight[4];
107
16.1M
      tmp1 += input[5] * weight[5];
108
16.1M
      tmp2 += input[6] * weight[6];
109
16.1M
      tmp3 += input[7] * weight[7];
110
16.1M
    }
111
16.1M
    mat[posRes++] = Clip3<int>( 0, maxVal, ((tmp0 + tmp1 + tmp2 + tmp3 + offset) >> MIP_SHIFT_MATRIX) );
112
113
16.1M
    weight += inputSize;
114
16.1M
  }
115
116
256k
  if( transpose )
117
116k
  {
118
1.03M
    for( int j = 0; j < outputSize; j++ )
119
919k
    {
120
8.22M
      for( int i = 0; i < outputSize; i++ )
121
7.30M
      {
122
7.30M
        res[j * outputSize + i] = buffer[i * outputSize + j];
123
7.30M
      }
124
919k
    }
125
116k
  }
126
256k
}
Unexecuted instantiation: void vvenc::mipMatrixMulCore<4u, 4u>(short*, short const*, unsigned char const*, int, int, bool)
void vvenc::mipMatrixMulCore<8u, 4u>(short*, short const*, unsigned char const*, int, int, bool)
Line
Count
Source
85
5.98k
{
86
5.98k
  Pel buffer[ outputSize*outputSize];
87
88
5.98k
  int sum = 0;
89
53.8k
  for( int i = 0; i < inputSize; i++ )
90
47.8k
  {
91
47.8k
    sum += input[i];
92
47.8k
  }
93
5.98k
  const int offset = (1 << (MIP_SHIFT_MATRIX - 1)) - MIP_OFFSET_MATRIX * sum + (inputOffset << MIP_SHIFT_MATRIX);
94
5.98k
  CHECK( inputSize != 4 * (inputSize >> 2), "Error, input size not divisible by four" );
95
96
5.98k
  Pel* mat = transpose ? buffer : res;
97
5.98k
  unsigned posRes = 0;
98
101k
  for( unsigned n = 0; n < outputSize*outputSize; n++ )
99
95.7k
  {
100
95.7k
    int tmp0 = input[0] * weight[0];
101
95.7k
    int tmp1 = input[1] * weight[1];
102
95.7k
    int tmp2 = input[2] * weight[2];
103
95.7k
    int tmp3 = input[3] * weight[3];
104
95.7k
    if( 8 == inputSize )
105
95.7k
    {
106
95.7k
      tmp0 += input[4] * weight[4];
107
95.7k
      tmp1 += input[5] * weight[5];
108
95.7k
      tmp2 += input[6] * weight[6];
109
95.7k
      tmp3 += input[7] * weight[7];
110
95.7k
    }
111
95.7k
    mat[posRes++] = Clip3<int>( 0, maxVal, ((tmp0 + tmp1 + tmp2 + tmp3 + offset) >> MIP_SHIFT_MATRIX) );
112
113
95.7k
    weight += inputSize;
114
95.7k
  }
115
116
5.98k
  if( transpose )
117
2.99k
  {
118
14.9k
    for( int j = 0; j < outputSize; j++ )
119
11.9k
    {
120
59.8k
      for( int i = 0; i < outputSize; i++ )
121
47.8k
      {
122
47.8k
        res[j * outputSize + i] = buffer[i * outputSize + j];
123
47.8k
      }
124
11.9k
    }
125
2.99k
  }
126
5.98k
}
void vvenc::mipMatrixMulCore<8u, 8u>(short*, short const*, unsigned char const*, int, int, bool)
Line
Count
Source
85
250k
{
86
250k
  Pel buffer[ outputSize*outputSize];
87
88
250k
  int sum = 0;
89
2.25M
  for( int i = 0; i < inputSize; i++ )
90
2.00M
  {
91
2.00M
    sum += input[i];
92
2.00M
  }
93
250k
  const int offset = (1 << (MIP_SHIFT_MATRIX - 1)) - MIP_OFFSET_MATRIX * sum + (inputOffset << MIP_SHIFT_MATRIX);
94
250k
  CHECK( inputSize != 4 * (inputSize >> 2), "Error, input size not divisible by four" );
95
96
250k
  Pel* mat = transpose ? buffer : res;
97
250k
  unsigned posRes = 0;
98
16.2M
  for( unsigned n = 0; n < outputSize*outputSize; n++ )
99
16.0M
  {
100
16.0M
    int tmp0 = input[0] * weight[0];
101
16.0M
    int tmp1 = input[1] * weight[1];
102
16.0M
    int tmp2 = input[2] * weight[2];
103
16.0M
    int tmp3 = input[3] * weight[3];
104
16.0M
    if( 8 == inputSize )
105
16.0M
    {
106
16.0M
      tmp0 += input[4] * weight[4];
107
16.0M
      tmp1 += input[5] * weight[5];
108
16.0M
      tmp2 += input[6] * weight[6];
109
16.0M
      tmp3 += input[7] * weight[7];
110
16.0M
    }
111
16.0M
    mat[posRes++] = Clip3<int>( 0, maxVal, ((tmp0 + tmp1 + tmp2 + tmp3 + offset) >> MIP_SHIFT_MATRIX) );
112
113
16.0M
    weight += inputSize;
114
16.0M
  }
115
116
250k
  if( transpose )
117
113k
  {
118
1.02M
    for( int j = 0; j < outputSize; j++ )
119
907k
    {
120
8.16M
      for( int i = 0; i < outputSize; i++ )
121
7.25M
      {
122
7.25M
        res[j * outputSize + i] = buffer[i * outputSize + j];
123
7.25M
      }
124
907k
    }
125
113k
  }
126
250k
}
127
128
template< typename T >
129
void addAvgCore( const T* src1, int src1Stride, const T* src2, int src2Stride, T* dest, int dstStride, int width, int height, unsigned rshift, int offset, const ClpRng& clpRng )
130
0
{
131
0
#define ADD_AVG_CORE_OP( ADDR ) dest[ADDR] = ClipPel( rightShiftU( ( src1[ADDR] + src2[ADDR] + offset ), rshift ), clpRng )
132
0
#define ADD_AVG_CORE_INC    \
133
0
  src1 += src1Stride;       \
134
0
  src2 += src2Stride;       \
135
0
  dest +=  dstStride;       \
136
0
137
0
  SIZE_AWARE_PER_EL_OP( ADD_AVG_CORE_OP, ADD_AVG_CORE_INC );
138
139
0
#undef ADD_AVG_CORE_OP
140
0
#undef ADD_AVG_CORE_INC
141
0
}
142
143
template<typename T>
144
void addWeightedAvgCore( const T* src1, int src1Stride, const T* src2, int src2Stride, T* dest, int destStride, int width, int height, unsigned rshift, int offset, int w0, int w1, const ClpRng& clpRng )
145
0
{
146
0
#define ADD_WGHT_AVG_OP( ADDR ) dest[ADDR] = ClipPel( rightShiftU( ( src1[ADDR]*w0 + src2[ADDR]*w1 + offset ), rshift ), clpRng )
147
0
#define ADD_WGHT_AVG_INC     \
148
0
    src1 += src1Stride; \
149
0
    src2 += src2Stride; \
150
0
    dest += destStride; \
151
0
152
0
  SIZE_AWARE_PER_EL_OP( ADD_WGHT_AVG_OP, ADD_WGHT_AVG_INC );
153
154
0
#undef ADD_WGHT_AVG_OP
155
0
#undef ADD_WGHT_AVG_INC
156
0
}
157
158
template<typename T>
159
void subsCore( const T* src0, int src0Stride, const T* src1, int src1Stride, T* dest, int destStride, int width, int height )
160
789k
{
161
789k
#define SUBS_INC                \
162
789k
  dest += destStride;  \
163
789k
  src0 += src0Stride;  \
164
789k
  src1 += src1Stride;  \
165
789k
166
372M
#define SUBS_OP( ADDR ) dest[ADDR] = src0[ADDR] - src1[ADDR]
167
168
372M
  SIZE_AWARE_PER_EL_OP( SUBS_OP, SUBS_INC );
169
170
789k
#undef SUBS_OP
171
789k
#undef SUBS_INC
172
789k
}
173
174
void removeHighFreq(int16_t* dst, int dstStride, const int16_t* src, int srcStride, int width, int height)
175
0
{
176
0
#define REM_HF_INC  \
177
0
 src += srcStride; \
178
0
 dst += dstStride; \
179
0
180
0
#define REM_HF_OP( ADDR )      dst[ADDR] =             2 * dst[ADDR] - src[ADDR]
181
182
0
 SIZE_AWARE_PER_EL_OP(REM_HF_OP, REM_HF_INC);
183
184
0
#undef REM_HF_INC
185
0
#undef REM_HF_OP
186
0
#undef REM_HF_OP_CLIP
187
0
}
188
189
template<typename T>
190
void reconstructCore( const T* src1, int src1Stride, const T* src2, int src2Stride, T* dest, int dstStride, int width, int height, const ClpRng& clpRng )
191
9.01k
{
192
3.83M
#define RECO_CORE_OP( ADDR ) dest[ADDR] = ClipPel( src1[ADDR] + src2[ADDR], clpRng )
193
9.01k
#define RECO_CORE_INC     \
194
9.01k
  src1 += src1Stride;     \
195
9.01k
  src2 += src2Stride;     \
196
9.01k
  dest +=  dstStride;     \
197
9.01k
198
3.83M
  SIZE_AWARE_PER_EL_OP( RECO_CORE_OP, RECO_CORE_INC );
199
200
9.01k
#undef RECO_CORE_OP
201
9.01k
#undef RECO_CORE_INC
202
9.01k
}
203
204
template<typename T>
205
void recoCore( const T* src1, const T* src2, T* dest, int numSamples, const ClpRng& clpRng )
206
2.21M
{
207
337M
  for( int n = 0; n < numSamples; n+=2)
208
335M
  {
209
335M
    dest[n]   = ClipPel( src1[n]   + src2[n], clpRng );
210
335M
    dest[n+1] = ClipPel( src1[n+1] + src2[n+1], clpRng );
211
335M
  }
212
2.21M
}
213
214
template<typename T>
215
void copyClipCore( const T* src, Pel* dst, int numSamples, const ClpRng& clpRng )
216
0
{
217
0
  for( int n = 0; n < numSamples; n+=2)
218
0
  {
219
0
    dst[n]   = ClipPel( src[n]   , clpRng );
220
0
    dst[n+1] = ClipPel( src[n+1] , clpRng );
221
0
  }
222
0
}
223
224
template< typename T >
225
void addAvgCore( const T* src1, const T* src2, T* dest, int numSamples, unsigned rshift, int offset, const ClpRng& clpRng )
226
0
{
227
0
  for( int n = 0; n < numSamples; n+=2)
228
0
  {
229
0
    dest[n]   = ClipPel( rightShiftU( ( src1[n]   + src2[n]   + offset ), rshift ), clpRng );
230
0
    dest[n+1] = ClipPel( rightShiftU( ( src1[n+1] + src2[n+1] + offset ), rshift ), clpRng );
231
0
  }
232
0
}
233
234
template< typename T >
235
void roundGeoCore( const T* src, T* dest, const int numSamples, unsigned rshift, int offset, const ClpRng &clpRng)
236
0
{
237
0
  for( int i = 0; i < numSamples; i+=2)
238
0
  {
239
0
    dest[i]   = ClipPel(rightShiftU(src[i  ] + offset, rshift), clpRng);
240
0
    dest[i+1] = ClipPel(rightShiftU(src[i+1] + offset, rshift), clpRng);
241
0
  }
242
0
}
243
244
template<typename T>
245
void linTfCore( const T* src, int srcStride, Pel* dst, int dstStride, int width, int height, int scale, unsigned shift, int offset, const ClpRng& clpRng, bool bClip )
246
202k
{
247
202k
#define LINTF_CORE_INC  \
248
202k
  src += srcStride;     \
249
202k
  dst += dstStride;     \
250
202k
251
202k
  if( bClip )
252
202k
  {
253
41.0M
#define LINTF_CORE_OP( ADDR ) dst[ADDR] = ( Pel ) ClipPel( rightShiftU( scale * src[ADDR], shift ) + offset, clpRng )
254
255
41.0M
  SIZE_AWARE_PER_EL_OP( LINTF_CORE_OP, LINTF_CORE_INC );
256
257
202k
#undef LINTF_CORE_OP
258
202k
  }
259
0
  else
260
0
  {
261
0
#define LINTF_CORE_OP( ADDR ) dst[ADDR] = ( Pel ) ( rightShiftU( scale * src[ADDR], shift ) + offset )
262
263
0
  SIZE_AWARE_PER_EL_OP( LINTF_CORE_OP, LINTF_CORE_INC );
264
265
0
#undef LINTF_CORE_OP
266
0
  }
267
202k
#undef LINTF_CORE_INC
268
202k
}
269
270
template<typename T, int N>
271
void transposeNxNCore( const Pel* src, int srcStride, Pel* dst, int dstStride )
272
7.19M
{
273
63.2M
  for( int i = 0; i < N; i++ )
274
56.0M
  {
275
498M
    for( int j = 0; j < N; j++ )
276
442M
    {
277
442M
      dst[j * dstStride] = src[j];
278
442M
    }
279
280
56.0M
    dst++;
281
56.0M
    src += srcStride;
282
56.0M
  }
283
7.19M
}
void vvenc::transposeNxNCore<short, 4>(short const*, int, short*, int)
Line
Count
Source
272
388k
{
273
1.94M
  for( int i = 0; i < N; i++ )
274
1.55M
  {
275
7.76M
    for( int j = 0; j < N; j++ )
276
6.21M
    {
277
6.21M
      dst[j * dstStride] = src[j];
278
6.21M
    }
279
280
1.55M
    dst++;
281
1.55M
    src += srcStride;
282
1.55M
  }
283
388k
}
void vvenc::transposeNxNCore<short, 8>(short const*, int, short*, int)
Line
Count
Source
272
6.81M
{
273
61.2M
  for( int i = 0; i < N; i++ )
274
54.4M
  {
275
490M
    for( int j = 0; j < N; j++ )
276
435M
    {
277
435M
      dst[j * dstStride] = src[j];
278
435M
    }
279
280
54.4M
    dst++;
281
54.4M
    src += srcStride;
282
54.4M
  }
283
6.81M
}
284
285
template<typename T>
286
void copyClipCore( const T* src, int srcStride, Pel* dst, int dstStride, int width, int height, const ClpRng& clpRng )
287
0
{
288
0
#define RECO_OP( ADDR ) dst[ADDR] = ClipPel( src[ADDR], clpRng )
289
0
#define RECO_INC      \
290
0
    src += srcStride; \
291
0
    dst += dstStride; \
292
0
293
0
  SIZE_AWARE_PER_EL_OP( RECO_OP, RECO_INC );
294
295
0
#undef RECO_OP
296
0
#undef RECO_INC
297
0
}
298
299
void copyBufferCore( const char* src, int srcStride, char* dst, int dstStride, int numBytes, int height)
300
8.44M
{
301
142M
  for( int i = 0; i < height; i++, src += srcStride, dst += dstStride )
302
133M
  {
303
133M
    memcpy( dst, src, numBytes );
304
133M
  }
305
8.44M
}
306
307
void fillMapPtr_Core( void** ptrMap, const ptrdiff_t mapStride, int width, int height, void* val )
308
437k
{
309
437k
  if( width == mapStride )
310
287k
  {
311
287k
    std::fill_n( ptrMap, width * height, val );
312
287k
  }
313
150k
  else
314
150k
  {
315
1.40M
    while( height-- )
316
1.25M
    {
317
1.25M
      std::fill_n( ptrMap, width, val );
318
1.25M
      ptrMap += mapStride;
319
1.25M
    }
320
150k
  }
321
437k
}
322
323
uint64_t AvgHighPassCore( const int width, const int height, const Pel* pSrc, const int iSrcStride)
324
10.8k
{
325
10.8k
  uint64_t saAct = 0;
326
893k
  for (int y = 1; y < height - 1; y++)
327
882k
  {
328
82.4M
    for (int x = 1; x < width - 1; x++) // center cols
329
81.5M
    {
330
81.5M
      const int s = 12 * (int) pSrc[x  ] - 2 * ((int) pSrc[x-1] + (int) pSrc[x+1] + (int) pSrc[x  -iSrcStride] + (int) pSrc[x  +iSrcStride])
331
81.5M
                             - ((int) pSrc[x-1-iSrcStride] + (int) pSrc[x+1-iSrcStride] + (int) pSrc[x-1+iSrcStride] + (int) pSrc[x+1+iSrcStride]);
332
81.5M
      saAct += abs (s);
333
81.5M
    }
334
882k
    pSrc += iSrcStride;
335
882k
  }
336
10.8k
  return saAct;
337
10.8k
}
338
339
uint64_t HDHighPassCore  (const int width, const int height,const Pel*  pSrc,const Pel* pSM1,const int iSrcStride,const int iSM1Stride)
340
0
{
341
0
  uint64_t taAct = 0;
342
0
  for (int y = 1; y < height - 1; y++)
343
0
  {
344
0
    for (int x = 1; x < width - 1; x++)  // cnt cols
345
0
    {
346
0
      const int t = (int) pSrc[x] - (int) pSM1[x];
347
0
      taAct += (1 + 3 * abs (t)) >> 1;
348
0
    }
349
0
    pSrc += iSrcStride;
350
0
    pSM1 += iSM1Stride;
351
0
  }
352
0
  return taAct;
353
0
}
354
355
uint64_t  HDHighPass2Core  (const int width, const int height,const Pel*  pSrc,const Pel* pSM1,const Pel* pSM2,const int iSrcStride,const int iSM1Stride,const int iSM2Stride)
356
0
{
357
0
  uint64_t taAct = 0;
358
0
  for (int y = 1; y < height - 1; y++)
359
0
  {
360
0
    for (int x = 1; x < width - 1; x++)  // cnt cols
361
0
    {
362
0
      const int t = (int) pSrc[x] - 2 * (int) pSM1[x] + (int) pSM2[x];
363
0
      taAct += abs (t);
364
0
    }
365
0
    pSrc += iSrcStride;
366
0
    pSM1 += iSM1Stride;
367
0
    pSM2 += iSM2Stride;
368
0
  }
369
0
  return taAct;
370
0
}
371
uint64_t AvgHighPassWithDownsamplingCore( const int width, const int height, const Pel* pSrc, const int iSrcStride)
372
0
{
373
0
  uint64_t saAct = 0;
374
0
  pSrc -= iSrcStride;
375
0
  pSrc -= iSrcStride;
376
0
 for (int y = 2; y < height - 2; y += 2)
377
0
 {
378
0
   for (int x = 2; x < width - 2; x += 2)
379
0
   {
380
0
     const int f = 12 * ((int)pSrc[ y   *iSrcStride + x  ] + (int)pSrc[ y   *iSrcStride + x+1] + (int)pSrc[(y+1)*iSrcStride + x  ] + (int)pSrc[(y+1)*iSrcStride + x+1])
381
0
                  - 3 * ((int)pSrc[(y-1)*iSrcStride + x  ] + (int)pSrc[(y-1)*iSrcStride + x+1] + (int)pSrc[(y+2)*iSrcStride + x  ] + (int)pSrc[(y+2)*iSrcStride + x+1])
382
0
                  - 3 * ((int)pSrc[ y   *iSrcStride + x-1] + (int)pSrc[ y   *iSrcStride + x+2] + (int)pSrc[(y+1)*iSrcStride + x-1] + (int)pSrc[(y+1)*iSrcStride + x+2])
383
0
                  - 2 * ((int)pSrc[(y-1)*iSrcStride + x-1] + (int)pSrc[(y-1)*iSrcStride + x+2] + (int)pSrc[(y+2)*iSrcStride + x-1] + (int)pSrc[(y+2)*iSrcStride + x+2])
384
0
                      - ((int)pSrc[(y-2)*iSrcStride + x-1] + (int)pSrc[(y-2)*iSrcStride + x  ] + (int)pSrc[(y-2)*iSrcStride + x+1] + (int)pSrc[(y-2)*iSrcStride + x+2]
385
0
                       + (int)pSrc[(y+3)*iSrcStride + x-1] + (int)pSrc[(y+3)*iSrcStride + x  ] + (int)pSrc[(y+3)*iSrcStride + x+1] + (int)pSrc[(y+3)*iSrcStride + x+2]
386
0
                       + (int)pSrc[(y-1)*iSrcStride + x-2] + (int)pSrc[ y   *iSrcStride + x-2] + (int)pSrc[(y+1)*iSrcStride + x-2] + (int)pSrc[(y+2)*iSrcStride + x-2]
387
0
                       + (int)pSrc[(y-1)*iSrcStride + x+3] + (int)pSrc[ y   *iSrcStride + x+3] + (int)pSrc[(y+1)*iSrcStride + x+3] + (int)pSrc[(y+2)*iSrcStride + x+3]);
388
0
     saAct += (uint64_t) abs(f);
389
0
   }
390
0
 }
391
0
 return saAct;
392
0
}
393
uint64_t AvgHighPassWithDownsamplingDiff1stCore (const int width, const int  height, const Pel* pSrc,const Pel* pSrcM1, const int iSrcStride, const int iSrcM1Stride)
394
0
{
395
0
  uint64_t taAct = 0;
396
0
  pSrc -= iSrcStride;
397
0
  pSrc -= iSrcStride;
398
0
  pSrcM1-=iSrcM1Stride;
399
0
  pSrcM1-=iSrcM1Stride;
400
401
0
  for (uint32_t y = 2; y < height-2; y += 2)
402
0
  {
403
0
    for (uint32_t x = 2; x < width-2; x += 2)
404
0
    {
405
0
      const int t = (int)pSrc  [y*iSrcStride + x] + (int)pSrc  [y*iSrcStride + x+1] + (int)pSrc  [(y+1)*iSrcStride + x] + (int)pSrc  [(y+1)*iSrcStride + x+1]
406
0
                 - ((int)pSrcM1[y*iSrcM1Stride + x] + (int)pSrcM1[y*iSrcM1Stride + x+1] + (int)pSrcM1[(y+1)*iSrcM1Stride + x] + (int)pSrcM1[(y+1)*iSrcM1Stride + x+1]);
407
0
      taAct += (1 + 3 * abs (t)) >> 1;
408
0
    }
409
0
  }
410
0
  return (taAct );
411
0
}
412
413
uint64_t AvgHighPassWithDownsamplingDiff2ndCore (const int width,const int height,const Pel* pSrc,const Pel* pSrcM1,const Pel* pSrcM2,const int iSrcStride,const int iSM1Stride,const int iSM2Stride)
414
0
{
415
0
  uint64_t taAct = 0;
416
417
0
  pSrc -= iSrcStride;
418
0
  pSrc -= iSrcStride;
419
0
  pSrcM1-=iSM1Stride;
420
0
  pSrcM1-=iSM1Stride;
421
0
  pSrcM2-=iSM2Stride;
422
0
  pSrcM2-=iSM2Stride;
423
424
0
  for (uint32_t y = 2; y < height-2; y += 2)
425
0
  {
426
0
    for (uint32_t x = 2; x < width-2; x += 2)
427
0
    {
428
0
      const int t = (int)pSrc  [y*iSrcStride + x] + (int)pSrc  [y*iSrcStride + x+1] + (int)pSrc  [(y+1)*iSrcStride + x] + (int)pSrc  [(y+1)*iSrcStride + x+1]
429
0
                            - 2 * ((int)pSrcM1[y*iSM1Stride + x] + (int)pSrcM1[y*iSM1Stride + x+1] + (int)pSrcM1[(y+1)*iSM1Stride + x] + (int)pSrcM1[(y+1)*iSM1Stride + x+1])
430
0
                            + (int)pSrcM2[y*iSM2Stride + x] + (int)pSrcM2[y*iSM2Stride + x+1] + (int)pSrcM2[(y+1)*iSM2Stride + x] + (int)pSrcM2[(y+1)*iSM2Stride + x+1];
431
0
      taAct += (uint64_t) abs(t);
432
0
    }
433
0
  }
434
0
  return (taAct);
435
0
}
436
437
PelBufferOps::PelBufferOps()
438
14
{
439
14
  addAvg            = addAvgCore<Pel>;
440
14
  reco              = recoCore<Pel>;
441
14
  copyClip          = copyClipCore<Pel>;
442
14
  roundGeo          = roundGeoCore<Pel>;
443
444
14
  addAvg4           = addAvgCore<Pel>;
445
14
  addAvg8           = addAvgCore<Pel>;
446
14
  addAvg16          = addAvgCore<Pel>;
447
448
14
  sub4              = subsCore<Pel>;
449
14
  sub8              = subsCore<Pel>;
450
451
14
  wghtAvg4          = addWeightedAvgCore<Pel>;
452
14
  wghtAvg8          = addWeightedAvgCore<Pel>;
453
454
14
  copyClip4         = copyClipCore<Pel>;
455
14
  copyClip8         = copyClipCore<Pel>;
456
457
14
  reco4             = reconstructCore<Pel>;
458
14
  reco8             = reconstructCore<Pel>;
459
460
14
  linTf4            = linTfCore<Pel>;
461
14
  linTf8            = linTfCore<Pel>;
462
463
14
  copyBuffer        = copyBufferCore;
464
465
14
  removeHighFreq8   = removeHighFreq;
466
14
  removeHighFreq4   = removeHighFreq;
467
468
14
  transpose4x4      = transposeNxNCore<Pel,4>;
469
14
  transpose8x8      = transposeNxNCore<Pel,8>;
470
14
  mipMatrixMul_4_4  = mipMatrixMulCore<4,4>;
471
14
  mipMatrixMul_8_4  = mipMatrixMulCore<8,4>;
472
14
  mipMatrixMul_8_8  = mipMatrixMulCore<8,8>;
473
14
  weightCiip        = weightCiipCore;
474
14
  roundIntVector    = nullptr;
475
476
14
  fillPtrMap        = fillMapPtr_Core;
477
14
  AvgHighPassWithDownsampling = AvgHighPassWithDownsamplingCore;
478
14
  AvgHighPass = AvgHighPassCore;
479
14
  AvgHighPassWithDownsamplingDiff1st = AvgHighPassWithDownsamplingDiff1stCore;
480
14
  AvgHighPassWithDownsamplingDiff2nd = AvgHighPassWithDownsamplingDiff2ndCore;
481
14
  HDHighPass = HDHighPassCore;
482
14
  HDHighPass2 = HDHighPass2Core;
483
14
}
484
485
void PelBufferOps::initPelBufOps( bool enableOpt )
486
0
{
487
0
  if( isInitSIMDDone )
488
0
  {
489
0
    return;
490
0
  }
491
0
  isInitSIMDDone = true;
492
493
0
  if( enableOpt )
494
0
  {
495
0
#if ENABLE_SIMD_OPT_BUFFER
496
#  if defined( TARGET_SIMD_X86 )
497
    g_pelBufOP.initPelBufOpsX86();
498
#  endif
499
#  if defined( TARGET_SIMD_ARM )
500
    g_pelBufOP.initPelBufOpsARM();
501
#  endif
502
0
#endif   // ENABLE_SIMD_OPT_BUFFER
503
0
  }
504
0
}
505
506
PelBufferOps g_pelBufOP = PelBufferOps();
507
508
template<>
509
void AreaBuf<Pel>::addWeightedAvg(const AreaBuf<const Pel>& other1, const AreaBuf<const Pel>& other2, const ClpRng& clpRng, const int8_t BcwIdx)
510
0
{
511
0
  const int8_t w0 = getBcwWeight( BcwIdx, REF_PIC_LIST_0 );
512
0
  const int8_t w1 = getBcwWeight( BcwIdx, REF_PIC_LIST_1 );
513
0
  const int8_t log2WeightBase = g_BcwLog2WeightBase;
514
0
  const Pel* src0 = other1.buf;
515
0
  const Pel* src2 = other2.buf;
516
0
        Pel* dest =        buf;
517
518
0
  const int src1Stride = other1.stride;
519
0
  const int src2Stride = other2.stride;
520
0
  const int destStride =        stride;
521
0
  const int clipbd     = clpRng.bd;
522
0
  const int shiftNum   = std::max<int>( 2, ( IF_INTERNAL_PREC - clipbd ) ) + log2WeightBase;
523
0
  const int offset     = ( 1 << ( shiftNum - 1 ) ) + ( IF_INTERNAL_OFFS << log2WeightBase );
524
525
0
  if( ( width & 7 ) == 0 )
526
0
  {
527
0
    g_pelBufOP.wghtAvg8( src0, src1Stride, src2, src2Stride, dest, destStride, width, height, shiftNum, offset, w0, w1, clpRng );
528
0
  }
529
0
  else if( ( width & 3 ) == 0 )
530
0
  {
531
0
    g_pelBufOP.wghtAvg4( src0, src1Stride, src2, src2Stride, dest, destStride, width, height, shiftNum, offset, w0, w1, clpRng );
532
0
  }
533
0
  else
534
0
  {
535
0
#define WGHT_AVG_OP( ADDR ) dest[ADDR] = ClipPel( rightShiftU( ( src0[ADDR]*w0 + src2[ADDR]*w1 + offset ), shiftNum ), clpRng )
536
0
#define WGHT_AVG_INC    \
537
0
    src0 += src1Stride; \
538
0
    src2 += src2Stride; \
539
0
    dest += destStride; \
540
0
541
0
    SIZE_AWARE_PER_EL_OP( WGHT_AVG_OP, WGHT_AVG_INC );
542
543
0
#undef WGHT_AVG_OP
544
0
#undef WGHT_AVG_INC
545
0
  }
546
0
}
547
548
template<>
549
void AreaBuf<Pel>::addAvg( const AreaBuf<const Pel>& other1, const AreaBuf<const Pel>& other2, const ClpRng& clpRng)
550
0
{
551
0
  const Pel* src0 = other1.buf;
552
0
  const Pel* src2 = other2.buf;
553
0
        Pel* dest =        buf;
554
555
0
  const unsigned src1Stride = other1.stride;
556
0
  const unsigned src2Stride = other2.stride;
557
0
  const unsigned destStride =        stride;
558
0
  const int      clipbd     = clpRng.bd;
559
0
  const unsigned shiftNum   = std::max<int>(2, (IF_INTERNAL_PREC - clipbd)) + 1;
560
0
  const int      offset     = (1 << (shiftNum - 1)) + 2 * IF_INTERNAL_OFFS;
561
562
0
#if ENABLE_SIMD_OPT_BUFFER
563
0
  if( destStride == width )
564
0
  {
565
0
    g_pelBufOP.addAvg(src0, src2, dest, width * height, shiftNum, offset, clpRng);
566
0
  }
567
0
  else if ((width & 15) == 0)
568
0
  {
569
0
    g_pelBufOP.addAvg16(src0, src1Stride, src2, src2Stride, dest, destStride, width, height, shiftNum, offset, clpRng);
570
0
  }
571
0
  else if( ( width & 7 ) == 0 )
572
0
  {
573
0
    g_pelBufOP.addAvg8( src0, src1Stride, src2, src2Stride, dest, destStride, width, height, shiftNum, offset, clpRng );
574
0
  }
575
0
  else if( ( width & 3 ) == 0 )
576
0
  {
577
0
    g_pelBufOP.addAvg4( src0, src1Stride, src2, src2Stride, dest, destStride, width, height, shiftNum, offset, clpRng );
578
0
  }
579
0
  else
580
0
#endif
581
0
  {
582
0
#define ADD_AVG_OP( ADDR ) dest[ADDR] = ClipPel( rightShiftU( ( src0[ADDR] + src2[ADDR] + offset ), shiftNum ), clpRng )
583
0
#define ADD_AVG_INC     \
584
0
    src0 += src1Stride; \
585
0
    src2 += src2Stride; \
586
0
    dest += destStride; \
587
0
588
0
    SIZE_AWARE_PER_EL_OP( ADD_AVG_OP, ADD_AVG_INC );
589
590
0
#undef ADD_AVG_OP
591
0
#undef ADD_AVG_INC
592
0
  }
593
0
}
594
595
template<>
596
void AreaBuf<Pel>::subtract( const AreaBuf<const Pel>& minuend, const AreaBuf<const Pel>& subtrahend )
597
789k
{
598
789k
  CHECKD( width  != minuend.width,     "Incompatible size" );
599
789k
  CHECKD( height != minuend.height,    "Incompatible size" );
600
789k
  CHECKD( width  != subtrahend.width,  "Incompatible size");
601
789k
  CHECKD( height != subtrahend.height, "Incompatible size");
602
  
603
789k
        Pel* dest =            buf;
604
789k
  const Pel* mins = minuend   .buf;
605
789k
  const Pel* subs = subtrahend.buf;
606
607
608
789k
#if ENABLE_SIMD_OPT_BUFFER
609
789k
  const unsigned destStride =            stride;
610
789k
  const unsigned minsStride = minuend.   stride;
611
789k
  const unsigned subsStride = subtrahend.stride;
612
613
789k
  if( ( width & 7 ) == 0 )
614
667k
  {
615
667k
    g_pelBufOP.sub8( mins, minsStride, subs, subsStride, dest, destStride, width, height );
616
667k
  }
617
121k
  else if( ( width & 3 ) == 0 )
618
121k
  {
619
121k
    g_pelBufOP.sub4( mins, minsStride, subs, subsStride, dest, destStride, width, height );
620
121k
  }
621
18.4E
  else
622
18.4E
#endif
623
18.4E
  {
624
18.4E
#define SUBS_INC                \
625
18.4E
    dest +=            stride;  \
626
18.4E
    mins += minuend   .stride;  \
627
18.4E
    subs += subtrahend.stride;  \
628
18.4E
629
18.4E
#define SUBS_OP( ADDR ) dest[ADDR] = mins[ADDR] - subs[ADDR]
630
631
18.4E
    SIZE_AWARE_PER_EL_OP( SUBS_OP, SUBS_INC );
632
633
18.4E
#undef SUBS_OP
634
18.4E
#undef SUBS_INC
635
18.4E
  }
636
789k
}
637
638
template<>
639
void AreaBuf<const Pel>::calcVarianceSplit( const AreaBuf<const Pel>& Org, const uint32_t  size, int& varh,int& varv) const
640
0
{
641
0
  CHECK( Org.width != Org.height, "Incompatible size!" );
642
0
  int stride = Org.stride;
643
0
  const Pel* src;
644
0
  Pel data;
645
0
  double variance=0;
646
0
  double mean=0;
647
0
  int64_t sum[4]={0,0,0,0};
648
0
  int64_t sum_sqr[4]={0,0,0,0};
649
0
  uint32_t halfsize =size>>1;
650
0
  uint32_t off[4]={0,halfsize,size*halfsize,size*halfsize+halfsize};
651
0
  int n,x,y;
652
653
0
  for( n = 0; n < 4; n++)
654
0
  {
655
0
    src = Org.buf+off[n];
656
0
    for( y = 0; y < halfsize; y++)
657
0
    {
658
0
      for(x = 0; x < halfsize; x++)
659
0
      {
660
0
        data=src[y*stride+x];
661
0
        sum[n]+=data;
662
0
        sum_sqr[n]+= data*data;
663
0
      }
664
0
    }
665
0
  }
666
0
  int num=size*(size>>1);
667
  // varhu
668
0
  mean=(double)(sum[0]+sum[1])/(num);
669
0
  variance =  (double)(sum_sqr[0]+sum_sqr[1])/(num) - (mean*mean);
670
0
  varh =(int)(variance+0.5);
671
  // varhl
672
0
  mean=(double)(sum[2]+sum[3])/(num);
673
0
  variance =  (double)(sum_sqr[2]+sum_sqr[3])/(num) - (mean*mean);
674
0
  varh +=(int)(variance+0.5);
675
  // varvl
676
0
  mean=(double)(sum[0]+sum[2])/(num);
677
0
  variance =  (double)(sum_sqr[0]+sum_sqr[2])/(num) - (mean*mean);
678
0
  varv =(int)(variance+0.5);
679
  // varvr
680
0
  mean=(double)(sum[1]+sum[3])/(num);
681
0
  variance =  (double)(sum_sqr[1]+sum_sqr[3])/(num) - (mean*mean);
682
0
  varv +=(int)(variance+0.5);
683
0
}
684
685
template<>
686
void AreaBuf<Pel>::copyClip( const AreaBuf<const Pel>& src, const ClpRng& clpRng )
687
0
{
688
0
  const Pel* srcp = src.buf;
689
0
        Pel* dest =     buf;
690
691
0
  const unsigned srcStride  = src.stride;
692
0
  const unsigned destStride = stride;
693
694
0
  if( destStride == width)
695
0
  {
696
0
    g_pelBufOP.copyClip(srcp, dest, width * height, clpRng);
697
0
  }
698
0
  else if ((width & 7) == 0)
699
0
  {
700
0
    g_pelBufOP.copyClip8(srcp, srcStride, dest, destStride, width, height, clpRng);
701
0
  }
702
0
  else if ((width & 3) == 0)
703
0
  {
704
0
    g_pelBufOP.copyClip4(srcp, srcStride, dest, destStride, width, height, clpRng);
705
0
  }
706
0
  else
707
0
  {
708
0
    for( int y = 0; y < height; y++ )
709
0
    {
710
0
      dest[0] = ClipPel( srcp[0], clpRng);
711
0
      dest[1] = ClipPel( srcp[1], clpRng);
712
0
      srcp += srcStride;
713
0
      dest += destStride;
714
0
    }                                                         \
715
0
  }
716
0
}
717
718
template<>
719
void AreaBuf<Pel>::reconstruct( const AreaBuf<const Pel>& pred, const AreaBuf<const Pel>& resi, const ClpRng& clpRng )
720
2.22M
{
721
2.22M
  const Pel* src1 = pred.buf;
722
2.22M
  const Pel* src2 = resi.buf;
723
2.22M
        Pel* dest =      buf;
724
725
2.22M
  const unsigned src1Stride = pred.stride;
726
2.22M
  const unsigned src2Stride = resi.stride;
727
2.22M
  const unsigned destStride =      stride;
728
2.22M
  if( src2Stride == width )
729
2.21M
  {
730
2.21M
    g_pelBufOP.reco( pred.buf, resi.buf, buf, width * height, clpRng );
731
2.21M
  }
732
9.01k
  else if( ( width & 7 ) == 0 )
733
5.61k
  {
734
5.61k
    g_pelBufOP.reco8( src1, src1Stride, src2, src2Stride, dest, destStride, width, height, clpRng );
735
5.61k
  }
736
3.39k
  else if( ( width & 3 ) == 0 )
737
3.39k
  {
738
3.39k
    g_pelBufOP.reco4( src1, src1Stride, src2, src2Stride, dest, destStride, width, height, clpRng );
739
3.39k
  }
740
18.4E
  else if( ( width & 1 ) == 0 )
741
0
  {
742
0
    for( int y = 0; y < height; y++ )
743
0
    {
744
0
      dest[0] = ClipPel( src1[0] + src2[0], clpRng);
745
0
      dest[1] = ClipPel( src1[1] + src2[1], clpRng);
746
0
      src1 += src1Stride;
747
0
      src2 += src2Stride;
748
0
      dest += destStride;
749
0
    }                        
750
0
  }
751
18.4E
  else
752
18.4E
  {
753
18.4E
    CHECKD( width != 1, "Expecting width to be '1'!" );
754
755
18.4E
    for( int y = 0; y < height; y++ )
756
0
    {
757
0
      dest[0] = ClipPel( src1[0] + src2[0], clpRng );
758
759
0
      src1 += src1Stride;
760
0
      src2 += src2Stride;
761
0
      dest += destStride;
762
0
    }
763
18.4E
  }
764
2.22M
}
765
766
template<>
767
void AreaBuf<Pel>::linearTransform( const int scale, const unsigned shift, const int offset, bool bClip, const ClpRng& clpRng )
768
202k
{
769
202k
  const Pel* src = buf;
770
202k
        Pel* dst = buf;
771
772
202k
  if( stride == width)
773
202k
  {
774
202k
    if( width > 2 && height > 2 )
775
190k
    {
776
190k
      g_pelBufOP.linTf8( src, stride<<2, dst, stride<<2, width<<2, height>>2, scale, shift, offset, clpRng, bClip );
777
190k
    }
778
12.0k
    else
779
12.0k
    {
780
12.0k
      g_pelBufOP.linTf4( src, stride<<1, dst, stride<<1, width<<1, height>>1, scale, shift, offset, clpRng, bClip );
781
12.0k
    }
782
202k
  }
783
0
  else if( ( width & 7 ) == 0 )
784
0
  {
785
0
    g_pelBufOP.linTf8( src, stride, dst, stride, width, height, scale, shift, offset, clpRng, bClip );
786
0
  }
787
0
  else if( ( width & 3 ) == 0 )
788
0
  {
789
0
    g_pelBufOP.linTf4( src, stride, dst, stride, width, height, scale, shift, offset, clpRng, bClip );
790
0
  }
791
0
  else
792
0
  {
793
0
    if( bClip )
794
0
    {
795
0
      for( int y = 0; y < height; y++ )
796
0
      {
797
0
        dst[0] = ( Pel ) ClipPel( rightShiftU( scale * src[0], shift ) + offset, clpRng );
798
0
        dst[1] = ( Pel ) ClipPel( rightShiftU( scale * src[1], shift ) + offset, clpRng );
799
0
        src += stride;
800
0
        dst += stride;
801
0
      }
802
0
    }
803
0
    else
804
0
    {
805
0
      for( int y = 0; y < height; y++ )
806
0
      {
807
0
        dst[0] = ( Pel ) ( rightShiftU( scale * src[0], shift ) + offset );
808
0
        dst[1] = ( Pel ) ( rightShiftU( scale * src[1], shift ) + offset );
809
0
        src += stride;
810
0
        dst += stride;
811
0
      }
812
0
    }
813
0
  }
814
202k
}
815
816
#if ENABLE_SIMD_OPT_BUFFER
817
818
template<>
819
void AreaBuf<Pel>::transposedFrom( const AreaBuf<const Pel>& other )
820
592k
{
821
592k
  CHECK( width != other.height || height != other.width, "Incompatible size" );
822
823
592k
  if( ( ( width | height ) & 7 ) == 0 )
824
478k
  {
825
478k
    const Pel* src = other.buf;
826
827
1.96M
    for( unsigned y = 0; y < other.height; y += 8 )
828
1.48M
    {
829
1.48M
      Pel* dst = buf + y;
830
831
8.29M
      for( unsigned x = 0; x < other.width; x += 8 )
832
6.81M
      {
833
6.81M
        g_pelBufOP.transpose8x8( &src[x], other.stride, dst, stride );
834
835
6.81M
        dst += 8 * stride;
836
6.81M
      }
837
838
1.48M
      src += 8 * other.stride;
839
1.48M
    }
840
478k
  }
841
113k
  else if( ( ( width | height ) & 3 ) == 0 )
842
103k
  {
843
103k
    const Pel* src = other.buf;
844
845
306k
    for( unsigned y = 0; y < other.height; y += 4 )
846
203k
    {
847
203k
      Pel* dst = buf + y;
848
849
591k
      for( unsigned x = 0; x < other.width; x += 4 )
850
388k
      {
851
388k
        g_pelBufOP.transpose4x4( &src[x], other.stride, dst, stride );
852
853
388k
        dst += 4 * stride;
854
388k
      }
855
856
203k
      src += 4 * other.stride;
857
203k
    }
858
103k
  }
859
9.76k
  else
860
9.76k
  {
861
9.76k
          Pel* dst =       buf;
862
9.76k
    const Pel* src = other.buf;
863
9.76k
    width          = other.height;
864
9.76k
    height         = other.width;
865
9.76k
    stride         = stride < width ? width : stride;
866
867
122k
    for( unsigned y = 0; y < other.height; y++ )
868
112k
    {
869
337k
      for( unsigned x = 0; x < other.width; x++ )
870
225k
      {
871
225k
        dst[y + x*stride] = src[x + y * other.stride];
872
225k
      }
873
112k
    }
874
9.76k
  }
875
592k
}
876
#endif
877
878
template<>
879
void AreaBuf<Pel>::weightCiip( const AreaBuf<const Pel>& intra, const int numIntra )
880
0
{
881
0
  CHECK(width == 2, "Width of 2 is not supported");
882
0
  g_pelBufOP.weightCiip( buf, intra.buf, width * height, numIntra );
883
0
}
884
885
template<>
886
void AreaBuf<MotionInfo>::fill( const MotionInfo& val )
887
22.4k
{
888
22.4k
  if( width == stride )
889
22.4k
  {
890
22.4k
    std::fill_n( buf, width * height, val );
891
22.4k
  }
892
0
  else
893
0
  {
894
0
    MotionInfo* dst = buf;
895
896
0
    for( int y = 0; y < height; y++, dst += stride )
897
0
    {
898
0
      std::fill_n( dst, width, val );
899
0
    }
900
0
  }
901
22.4k
}
902
903
PelStorage::PelStorage()
904
4.08M
{
905
16.3M
  for( uint32_t i = 0; i < MAX_NUM_COMP; i++ )
906
12.2M
  {
907
12.2M
    m_origin[i] = nullptr;
908
12.2M
  }
909
4.08M
}
910
911
PelStorage::~PelStorage()
912
4.08M
{
913
4.08M
  destroy();
914
4.08M
}
915
916
void PelStorage::create( const UnitArea& _UnitArea )
917
1.80M
{
918
1.80M
  create( _UnitArea.chromaFormat, _UnitArea.blocks[0] );
919
1.80M
  m_maxArea = _UnitArea;
920
1.80M
}
921
922
void PelStorage::create( const ChromaFormat &_chromaFormat, const Area& _area )
923
3.58M
{
924
3.58M
  CHECK( !bufs.empty(), "Trying to re-create an already initialized buffer" );
925
926
3.58M
  chromaFormat = _chromaFormat;
927
928
3.58M
  const uint32_t numComp = getNumberValidComponents( _chromaFormat );
929
930
3.58M
  uint32_t bufSize = 0;
931
12.8M
  for( uint32_t i = 0; i < numComp; i++ )
932
9.22M
  {
933
9.22M
    const ComponentID compID = ComponentID( i );
934
9.22M
    const unsigned totalWidth  = _area.width  >> getComponentScaleX( compID, _chromaFormat );
935
9.22M
    const unsigned totalHeight = _area.height >> getComponentScaleY( compID, _chromaFormat );
936
937
9.22M
    const uint32_t area = totalWidth * totalHeight;
938
9.22M
    CHECK( !area, "Trying to create a buffer with zero area" );
939
9.22M
    bufSize += area;
940
9.22M
  }
941
942
3.58M
  bufSize += 1; // for SIMD DMVR on the bottom right corner, which overreads the lines by 1 sample
943
944
  //allocate one buffer
945
3.58M
  m_origin[0] = ( Pel* ) xMalloc( Pel, bufSize );
946
947
3.58M
  Pel* topLeft = m_origin[0];
948
12.8M
  for( uint32_t i = 0; i < numComp; i++ )
949
9.22M
  {
950
9.22M
    const ComponentID compID = ComponentID( i );
951
9.22M
    const unsigned totalWidth  = _area.width  >> getComponentScaleX( compID, _chromaFormat );
952
9.22M
    const unsigned totalHeight = _area.height >> getComponentScaleY( compID, _chromaFormat );
953
9.22M
    const uint32_t area = totalWidth * totalHeight;
954
955
9.22M
    bufs.push_back( PelBuf( topLeft, totalWidth, totalWidth, totalHeight ) );
956
9.22M
    topLeft += area;
957
9.22M
  }
958
959
3.58M
  m_maxArea = UnitArea( _chromaFormat, _area );
960
3.58M
}
961
962
void PelStorage::create( const ChromaFormat &_chromaFormat, const Area& _area, const unsigned _maxCUSize, const unsigned _margin, const unsigned _alignment, const bool _scaleChromaMargin )
963
166k
{
964
166k
  CHECK( !bufs.empty(), "Trying to re-create an already initialized buffer" );
965
966
166k
  chromaFormat = _chromaFormat;
967
968
166k
  const uint32_t numComp = getNumberValidComponents( _chromaFormat );
969
970
166k
  unsigned extHeight = _area.height;
971
166k
  unsigned extWidth  = _area.width;
972
973
166k
  if( _maxCUSize )
974
31.1k
  {
975
31.1k
    extHeight = ( ( _area.height + _maxCUSize - 1 ) / _maxCUSize ) * _maxCUSize;
976
31.1k
    extWidth  = ( ( _area.width  + _maxCUSize - 1 ) / _maxCUSize ) * _maxCUSize;
977
31.1k
  }
978
979
589k
  for( uint32_t i = 0; i < numComp; i++ )
980
423k
  {
981
423k
    const ComponentID compID = ComponentID( i );
982
423k
    const unsigned scaleX = getComponentScaleX( compID, _chromaFormat );
983
423k
    const unsigned scaleY = getComponentScaleY( compID, _chromaFormat );
984
985
423k
    unsigned scaledHeight = extHeight >> scaleY;
986
423k
    unsigned scaledWidth  = extWidth  >> scaleX;
987
423k
    unsigned ymargin      = _margin >> (_scaleChromaMargin?scaleY:0);
988
423k
    unsigned xmargin      = _margin >> (_scaleChromaMargin?scaleX:0);
989
423k
    unsigned totalWidth   = scaledWidth + 2*xmargin;
990
423k
    unsigned totalHeight  = scaledHeight +2*ymargin;
991
992
423k
    if( _alignment )
993
237k
    {
994
      // make sure buffer lines are align
995
237k
      CHECK( _alignment != MEMORY_ALIGN_DEF_SIZE, "Unsupported alignment" );
996
237k
      totalWidth = ( ( totalWidth + _alignment - 1 ) / _alignment ) * _alignment;
997
237k
    }
998
423k
    uint32_t area = totalWidth * totalHeight;
999
423k
    CHECK( !area, "Trying to create a buffer with zero area" );
1000
1001
423k
    m_origin[i] = ( Pel* ) xMalloc( Pel, area );
1002
423k
    Pel* topLeft = m_origin[i] + totalWidth * ymargin + xmargin;
1003
423k
    bufs.push_back( PelBuf( topLeft, totalWidth, _area.width >> scaleX, _area.height >> scaleY ) );
1004
423k
  }
1005
1006
166k
  m_maxArea = UnitArea( _chromaFormat, _area );
1007
166k
}
1008
1009
void PelStorage::createFromBuf( PelUnitBuf buf )
1010
2.39k
{
1011
2.39k
  chromaFormat = buf.chromaFormat;
1012
1013
2.39k
  const uint32_t numCh = getNumberValidComponents( chromaFormat );
1014
1015
2.39k
  bufs.resize(numCh);
1016
1017
9.59k
  for( uint32_t i = 0; i < numCh; i++ )
1018
7.19k
  {
1019
7.19k
    PelBuf cPelBuf = buf.get( ComponentID( i ) );
1020
7.19k
    bufs[i] = PelBuf( cPelBuf.bufAt( 0, 0 ), cPelBuf.stride, cPelBuf.width, cPelBuf.height );
1021
7.19k
  }
1022
2.39k
}
1023
1024
void PelStorage::compactResize( const UnitArea& area )
1025
2.21M
{
1026
2.21M
  CHECK( bufs.size() < area.blocks.size(), "Cannot increase buffer size when compacting!" );
1027
1028
7.50M
  for( uint32_t i = 0; i < area.blocks.size(); i++ )
1029
5.28M
  {
1030
5.28M
    CHECK( m_maxArea.blocks[i].area() < area.blocks[i].area(), "Cannot increase buffer size when compacting!" );
1031
1032
5.28M
    bufs[i].Size::operator=( area.blocks[i].size() );
1033
5.28M
    bufs[i].stride = bufs[i].width;
1034
5.28M
  }
1035
2.21M
}
1036
1037
void PelStorage::takeOwnership( PelStorage& other )
1038
0
{
1039
0
  chromaFormat = other.chromaFormat;
1040
1041
0
  const uint32_t numCh = getNumberValidComponents( chromaFormat );
1042
1043
0
  bufs.resize(numCh);
1044
1045
0
  for( uint32_t i = 0; i < numCh; i++ )
1046
0
  {
1047
0
    PelBuf cPelBuf = other.get( ComponentID( i ) );
1048
0
    bufs[i] = PelBuf( cPelBuf.bufAt( 0, 0 ), cPelBuf.stride, cPelBuf.width, cPelBuf.height );
1049
0
    std::swap( m_origin[i], other.m_origin[i]);
1050
0
  }
1051
1052
0
  m_maxArea = other.m_maxArea;
1053
1054
0
  other.destroy();
1055
0
}
1056
1057
1058
void PelStorage::swap( PelStorage& other )
1059
0
{
1060
0
  const uint32_t numCh = getNumberValidComponents( chromaFormat );
1061
1062
0
  for( uint32_t i = 0; i < numCh; i++ )
1063
0
  {
1064
    // check this otherwise it would turn out to get very weird
1065
0
    CHECK( chromaFormat                   != other.chromaFormat                  , "Incompatible formats" );
1066
0
    CHECK( get( ComponentID( i ) )        != other.get( ComponentID( i ) )       , "Incompatible formats" );
1067
0
    CHECK( get( ComponentID( i ) ).stride != other.get( ComponentID( i ) ).stride, "Incompatible formats" );
1068
1069
0
    std::swap( bufs[i].buf,    other.bufs[i].buf );
1070
0
    std::swap( bufs[i].stride, other.bufs[i].stride );
1071
0
    std::swap( m_origin[i],    other.m_origin[i] );
1072
0
  }
1073
0
}
1074
1075
void PelStorage::destroy()
1076
7.82M
{
1077
7.82M
  chromaFormat = NUM_CHROMA_FORMAT;
1078
31.2M
  for( uint32_t i = 0; i < MAX_NUM_COMP; i++ )
1079
23.4M
  {
1080
23.4M
    if( m_origin[i] )
1081
4.01M
    {
1082
4.01M
      xFree( m_origin[i] );
1083
4.01M
      m_origin[i] = nullptr;
1084
4.01M
    }
1085
23.4M
  }
1086
7.82M
  bufs.clear();
1087
7.82M
}
1088
1089
PelBuf PelStorage::getBuf( const ComponentID CompID )
1090
15.9k
{
1091
15.9k
  return bufs[CompID];
1092
15.9k
}
1093
1094
const CPelBuf PelStorage::getBuf( const ComponentID CompID ) const
1095
0
{
1096
0
  return bufs[CompID];
1097
0
}
1098
1099
PelBuf PelStorage::getBuf( const CompArea& blk )
1100
20.8M
{
1101
20.8M
  const PelBuf& r = bufs[blk.compID];
1102
20.8M
  return PelBuf( r.buf + rsAddr( blk, r.stride ), r.stride, blk );
1103
20.8M
}
1104
1105
const CPelBuf PelStorage::getBuf( const CompArea& blk ) const
1106
28.2k
{
1107
28.2k
  const PelBuf& r = bufs[blk.compID];
1108
28.2k
  return CPelBuf( r.buf + rsAddr( blk, r.stride ), r.stride, blk );
1109
28.2k
}
1110
1111
PelUnitBuf PelStorage::getBuf( const UnitArea& unit )
1112
3.84k
{
1113
3.84k
  return ( chromaFormat == CHROMA_400 ) ? PelUnitBuf( chromaFormat, getBuf( unit.Y() ) ) : PelUnitBuf( chromaFormat, getBuf( unit.Y() ), getBuf( unit.Cb() ), getBuf( unit.Cr() ) );
1114
3.84k
}
1115
1116
const CPelUnitBuf PelStorage::getBuf( const UnitArea& unit ) const
1117
0
{
1118
0
  return ( chromaFormat == CHROMA_400 ) ? CPelUnitBuf( chromaFormat, getBuf( unit.Y() ) ) : CPelUnitBuf( chromaFormat, getBuf( unit.Y() ), getBuf( unit.Cb() ), getBuf( unit.Cr() ) );
1119
0
}
1120
1121
PelUnitBuf PelStorage::getBuf(const int strY, const int strCb, const int strCr, const UnitArea& unit)
1122
0
{
1123
0
  CHECKD( unit.Y().width > bufs[COMP_Y].width && unit.Y().height > bufs[COMP_Y].height, "unsuported request" );
1124
0
  CHECKD( strY > bufs[COMP_Y].stride, "unsuported request" );
1125
0
  CHECKD( strCb > bufs[COMP_Cb].stride, "unsuported request" );
1126
0
  CHECKD( strCr > bufs[COMP_Cr].stride, "unsuported request" );
1127
0
  return (chromaFormat == CHROMA_400) ? PelUnitBuf(chromaFormat, PelBuf( bufs[COMP_Y].buf, strY, unit.Y())) : PelUnitBuf(chromaFormat, PelBuf( bufs[COMP_Y].buf, strY, unit.Y()), PelBuf( bufs[COMP_Cb].buf, strCb, unit.Cb()), PelBuf( bufs[COMP_Cr].buf, strCr, unit.Cr()));
1128
0
}
1129
1130
const CPelUnitBuf PelStorage::getBuf(const int strY, const int strCb, const int strCr, const UnitArea& unit) const
1131
0
{
1132
0
  CHECKD( unit.Y().width > bufs[COMP_Y].width && unit.Y().height > bufs[COMP_Y].height, "unsuported request" );
1133
0
  CHECKD( strY > bufs[COMP_Y].stride, "unsuported request" );
1134
0
  CHECKD( strCb > bufs[COMP_Cb].stride, "unsuported request" );
1135
0
  CHECKD( strCr > bufs[COMP_Cr].stride, "unsuported request" );
1136
0
  return (chromaFormat == CHROMA_400) ? CPelUnitBuf(chromaFormat, CPelBuf( bufs[COMP_Y].buf, strY, unit.Y())) : CPelUnitBuf(chromaFormat, CPelBuf( bufs[COMP_Y].buf, strY, unit.Y()), CPelBuf( bufs[COMP_Cb].buf, strCb, unit.Cb()), CPelBuf( bufs[COMP_Cr].buf, strCr, unit.Cr()));
1137
0
}
1138
1139
PelUnitBuf PelStorage::getBufPart(const UnitArea& unit)
1140
0
{
1141
0
  CHECKD( unit.Y().width > bufs[COMP_Y].width && unit.Y().height > bufs[COMP_Y].height, "unsuported request" );
1142
0
  return (chromaFormat == CHROMA_400) ? PelUnitBuf(chromaFormat, PelBuf( bufs[COMP_Y].buf, bufs[COMP_Y].stride, unit.Y())) : PelUnitBuf(chromaFormat, PelBuf( bufs[COMP_Y].buf, bufs[COMP_Y].stride, unit.Y()), PelBuf( bufs[COMP_Cb].buf, bufs[COMP_Cb].stride, unit.Cb()), PelBuf( bufs[COMP_Cr].buf, bufs[COMP_Cr].stride, unit.Cr()));
1143
0
}
1144
1145
const CPelUnitBuf PelStorage::getBufPart(const UnitArea& unit) const
1146
0
{
1147
0
  CHECKD(unit.Y().width > bufs[COMP_Y].width && unit.Y().height > bufs[COMP_Y].height, "unsuported request");
1148
0
  return (chromaFormat == CHROMA_400) ? CPelUnitBuf(chromaFormat, CPelBuf(bufs[COMP_Y].buf, unit.Y().width, unit.Y())) : CPelUnitBuf(chromaFormat, CPelBuf(bufs[COMP_Y].buf, unit.Y().width, unit.Y()), CPelBuf(bufs[COMP_Cb].buf, unit.Cb().width, unit.Cb()), CPelBuf(bufs[COMP_Cr].buf, unit.Cr().width, unit.Cr()));
1149
0
}
1150
1151
const CPelUnitBuf PelStorage::getCompactBuf(const UnitArea& unit) const
1152
0
{
1153
0
  CHECKD( unit.Y().width > bufs[COMP_Y].width && unit.Y().height > bufs[COMP_Y].height, "unsuported request" );
1154
1155
0
  PelUnitBuf ret;
1156
0
  ret.chromaFormat = chromaFormat;
1157
0
  ret.bufs.resize_noinit( chromaFormat == CHROMA_400 ? 1 : 3 );
1158
  
1159
0
  ret.Y   ().buf = bufs[COMP_Y ].buf; ret.Y ().width = ret.Y ().stride = unit.Y ().width; ret.Y ().height = unit.Y ().height;
1160
0
  if( chromaFormat != CHROMA_400 )
1161
0
  {
1162
0
    ret.Cb().buf = bufs[COMP_Cb].buf; ret.Cb().width = ret.Cb().stride = unit.Cb().width; ret.Cb().height = unit.Cb().height;
1163
0
    ret.Cr().buf = bufs[COMP_Cr].buf; ret.Cr().width = ret.Cr().stride = unit.Cr().width; ret.Cr().height = unit.Cr().height;
1164
0
  }
1165
1166
0
  return ret;
1167
0
}
1168
1169
PelUnitBuf PelStorage::getCompactBuf(const UnitArea& unit)
1170
142k
{
1171
142k
  CHECKD( unit.Y().width > bufs[COMP_Y].width && unit.Y().height > bufs[COMP_Y].height, "unsuported request" );
1172
1173
142k
  PelUnitBuf ret;
1174
142k
  ret.chromaFormat = chromaFormat;
1175
142k
  ret.bufs.resize_noinit( chromaFormat == CHROMA_400 ? 1 : 3 );
1176
1177
142k
  ret.Y   ().buf = bufs[COMP_Y ].buf; ret.Y ().width = ret.Y ().stride = unit.Y ().width; ret.Y ().height = unit.Y ().height;
1178
142k
  if( chromaFormat != CHROMA_400 )
1179
142k
  {
1180
142k
    ret.Cb().buf = bufs[COMP_Cb].buf; ret.Cb().width = ret.Cb().stride = unit.Cb().width; ret.Cb().height = unit.Cb().height;
1181
142k
    ret.Cr().buf = bufs[COMP_Cr].buf; ret.Cr().width = ret.Cr().stride = unit.Cr().width; ret.Cr().height = unit.Cr().height;
1182
142k
  }
1183
1184
142k
  return ret;
1185
142k
}
1186
1187
const CPelBuf PelStorage::getCompactBuf(const CompArea& carea) const
1188
0
{
1189
0
  return CPelBuf( bufs[carea.compID].buf, carea.width, carea);
1190
0
}
1191
1192
PelBuf PelStorage::getCompactBuf(const CompArea& carea)
1193
0
{
1194
0
  return PelBuf( bufs[carea.compID].buf, carea.width, carea);
1195
0
}
1196
1197
void downsampleYuv(PelBuf& dest, const vvencYUVPlane& yuvPlaneIn, int downsampleStep)
1198
0
{
1199
0
  const int widthd = dest.width;
1200
0
  const int heightd = dest.height;
1201
0
  int difStride = dest.stride - dest.width;
1202
1203
0
  const int16_t* src = yuvPlaneIn.ptr;
1204
0
  const int instride = yuvPlaneIn.stride;
1205
0
  const int width = yuvPlaneIn.width;
1206
0
  int n = 0;
1207
0
  for (int j = 0; j < heightd; j++)
1208
0
  {
1209
0
    int i = 0;
1210
0
    for (i = 0; i < widthd; i++)
1211
0
    {
1212
0
      long int b = 0;
1213
0
      for (int r = 0; r < downsampleStep; r++)
1214
0
      {
1215
0
        int posr = width * r;
1216
0
        for (int n = 0; n < downsampleStep; n++)
1217
0
        {
1218
0
          b += src[posr + n];
1219
0
        }
1220
0
      }
1221
0
      src += downsampleStep;
1222
0
      dest.buf[n] = (int16_t)((b + 2) / (downsampleStep << 1));
1223
0
      n++;
1224
0
    }
1225
0
    n += difStride;
1226
0
    src = src - downsampleStep * i + width;
1227
1228
0
    src += (instride * (downsampleStep - 1));
1229
0
  }
1230
0
}
1231
1232
void copyPadToPelUnitBuf( PelUnitBuf pelUnitBuf, const vvencYUVBuffer& yuvBuffer, const ChromaFormat& chFmt )
1233
1.19k
{
1234
1.19k
  CHECK( pelUnitBuf.bufs.size() == 0, "pelUnitBuf not initialized" );
1235
1.19k
  pelUnitBuf.chromaFormat = chFmt;
1236
1.19k
  const int numComp = getNumberValidComponents( chFmt );
1237
4.79k
  for ( int i = 0; i < numComp; i++ )
1238
3.59k
  {
1239
3.59k
    const vvencYUVPlane& src = yuvBuffer.planes[ i ];
1240
3.59k
    CHECK( src.ptr == nullptr, "yuvBuffer not setup" );
1241
3.59k
    PelBuf& dest = pelUnitBuf.bufs[i];
1242
3.59k
    CHECK( dest.buf == nullptr, "yuvBuffer not setup" );
1243
1244
3.59k
    if (dest.width < src.width)
1245
0
    {
1246
0
      downsampleYuv(dest, src, 2);
1247
0
    }
1248
3.59k
    else
1249
3.59k
    {
1250
376k
      for (int y = 0; y < src.height; y++)
1251
373k
      {
1252
373k
        ::memcpy(dest.buf + y * dest.stride, src.ptr + y * src.stride, src.width * sizeof(int16_t));
1253
1254
        // pad right if required
1255
373k
        for (int x = src.width; x < dest.width; x++)
1256
0
        {
1257
0
          dest.buf[x + y * dest.stride] = dest.buf[src.width - 1 + y * dest.stride];
1258
0
        }
1259
373k
      }
1260
1261
      // pad bottom if required
1262
3.59k
      for (int y = src.height; y < dest.height; y++)
1263
0
      {
1264
0
        ::memcpy(dest.buf + y * dest.stride, dest.buf + (src.height - 1) * dest.stride, dest.width * sizeof(int16_t));
1265
0
      }
1266
3.59k
    }
1267
3.59k
  }
1268
1.19k
}
1269
1270
/*
1271
void setupPelUnitBuf( const YUVBuffer& yuvBuffer, PelUnitBuf& pelUnitBuf, const ChromaFormat& chFmt )
1272
{
1273
  CHECK( pelUnitBuf.bufs.size() != 0, "pelUnitBuf already in use" );
1274
  pelUnitBuf.chromaFormat = chFmt;
1275
  const int numComp = getNumberValidComponents( chFmt );
1276
  for ( int i = 0; i < numComp; i++ )
1277
  {
1278
    const YUVBuffer::Plane& yuvPlane = yuvBuffer.planes[ i ];
1279
    CHECK( yuvPlane.ptr == nullptr, "yuvBuffer not setup" );
1280
    PelBuf area( yuvPlane.ptr, yuvPlane.stride, yuvPlane.width, yuvPlane.height );
1281
    pelUnitBuf.bufs.push_back( area );
1282
  }
1283
}
1284
*/
1285
void setupYuvBuffer ( const PelUnitBuf& pelUnitBuf, vvencYUVBuffer& yuvBuffer, const Window* confWindow )
1286
0
{
1287
0
  const ChromaFormat chFmt = pelUnitBuf.chromaFormat;
1288
0
  const int numComp        = getNumberValidComponents( chFmt );
1289
0
  for ( int i = 0; i < numComp; i++ )
1290
0
  {
1291
0
    const ComponentID compId = ComponentID( i );
1292
0
          PelBuf area        = pelUnitBuf.get( compId );
1293
0
    const int sx             = getComponentScaleX( compId, chFmt );
1294
0
    const int sy             = getComponentScaleY( compId, chFmt );
1295
0
    vvencYUVPlane& yuvPlane = yuvBuffer.planes[ i ];
1296
0
    CHECK( yuvPlane.ptr != nullptr, "yuvBuffer already in use" );
1297
0
    yuvPlane.ptr             = area.bufAt( confWindow->winLeftOffset >> sx, confWindow->winTopOffset >> sy );
1298
0
    yuvPlane.width           = ( ( area.width  << sx ) - ( confWindow->winLeftOffset + confWindow->winRightOffset  ) ) >> sx;
1299
0
    yuvPlane.height          = ( ( area.height << sy ) - ( confWindow->winTopOffset  + confWindow->winBottomOffset ) ) >> sy;
1300
0
    yuvPlane.stride          = area.stride;
1301
0
  }
1302
0
}
1303
1304
} // namespace vvenc
1305
1306
//! \}
1307