Coverage Report

Created: 2026-07-16 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvdec/source/Lib/CommonLib/InterPrediction.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) 2018-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVdeC 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
/** \file     Prediction.cpp
44
    \brief    prediction class
45
*/
46
47
#include "InterPrediction.h"
48
49
#include "Buffer.h"
50
#include "UnitTools.h"
51
#include "CommonLib/TimeProfiler.h"
52
53
#include <memory.h>
54
#include <algorithm>
55
#include <cmath>
56
57
namespace vvdec
58
{
59
60
template<bool bi>
61
void applyPROFCore( Pel* dst, ptrdiff_t dstStride, const Pel* src, const Pel* gradX, const Pel* gradY, const int* dMvX, const int* dMvY, int shiftNum, Pel offset, const ClpRng& clpRng )
62
0
{
63
0
  static constexpr ptrdiff_t srcStride = 6;
64
0
  static constexpr int width = 4;
65
0
  static constexpr int height = 4;
66
67
0
  int idx = 0;
68
0
  const int dILimit = 1 << std::max<int>(clpRng.bd + 1, 13);
69
70
0
  for (int h = 0; h < height; h++)
71
0
  {
72
0
    for (int w = 0; w < width; w++)
73
0
    {
74
0
      int32_t dI = dMvX[idx] * gradX[w] + dMvY[idx] * gradY[w];
75
0
      dI = Clip3(-dILimit, dILimit - 1, dI);
76
0
      dst[w] = src[w] + dI;
77
0
      if (!bi)
78
0
      {
79
0
        dst[w] = (dst[w] + offset) >> shiftNum;
80
0
        dst[w] = ClipPel(dst[w], clpRng);
81
0
      }
82
0
      idx++;
83
0
    }
84
0
    gradX += 4;
85
0
    gradY += 4;
86
0
    dst += dstStride;
87
0
    src += srcStride;
88
0
  }
89
0
}
Unexecuted instantiation: void vvdec::applyPROFCore<false>(short*, long, short const*, short const*, short const*, int const*, int const*, int, short, vvdec::ClpRngTemplate<short> const&)
Unexecuted instantiation: void vvdec::applyPROFCore<true>(short*, long, short const*, short const*, short const*, int const*, int const*, int, short, vvdec::ClpRngTemplate<short> const&)
90
91
92
static inline int rightShiftMSB(int numer, int denom)
93
0
{
94
0
  int     d;
95
0
  int msbIdx = 0;
96
0
  for (msbIdx = 0; msbIdx<32; msbIdx++)
97
0
  {
98
0
    if (denom < ((int)1 << msbIdx))
99
0
    {
100
0
      break;
101
0
    }
102
0
  }
103
0
  int shiftIdx = msbIdx - 1;
104
0
  d = (numer >> shiftIdx);
105
106
0
  return d;
107
0
}
108
109
static inline void addBIOAvg4(const Pel* src0, ptrdiff_t src0Stride, const Pel* src1, ptrdiff_t src1Stride, Pel *dst, ptrdiff_t dstStride, const Pel *gradX0, const Pel *gradX1, const Pel *gradY0, const Pel*gradY1, ptrdiff_t gradStride, int width, int height, int tmpx, int tmpy, int shift, int offset, const ClpRng& clpRng)
110
0
{
111
0
  int b = 0;
112
113
0
  for (int y = 0; y < height; y++)
114
0
  {
115
0
    for (int x = 0; x < width; x += 4)
116
0
    {
117
0
      b = tmpx * (gradX0[x] - gradX1[x]) + tmpy * (gradY0[x] - gradY1[x]);
118
0
      dst[x] = ClipPel((int16_t)rightShift((src0[x] + src1[x] + b + offset), shift), clpRng);
119
120
0
      b = tmpx * (gradX0[x + 1] - gradX1[x + 1]) + tmpy * (gradY0[x + 1] - gradY1[x + 1]);
121
0
      dst[x + 1] = ClipPel((int16_t)rightShift((src0[x + 1] + src1[x + 1] + b + offset), shift), clpRng);
122
123
0
      b = tmpx * (gradX0[x + 2] - gradX1[x + 2]) + tmpy * (gradY0[x + 2] - gradY1[x + 2]);
124
0
      dst[x + 2] = ClipPel((int16_t)rightShift((src0[x + 2] + src1[x + 2] + b + offset), shift), clpRng);
125
126
0
      b = tmpx * (gradX0[x + 3] - gradX1[x + 3]) + tmpy * (gradY0[x + 3] - gradY1[x + 3]);
127
0
      dst[x + 3] = ClipPel((int16_t)rightShift((src0[x + 3] + src1[x + 3] + b + offset), shift), clpRng);
128
0
    }
129
0
    dst += dstStride;       src0 += src0Stride;     src1 += src1Stride;
130
0
    gradX0 += gradStride; gradX1 += gradStride; gradY0 += gradStride; gradY1 += gradStride;
131
0
  }
132
0
}
133
134
void calcBIOSums(const Pel* srcY0Tmp, const Pel* srcY1Tmp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int xu, int yu, const int src0Stride, const int src1Stride, const int widthG, const int bitDepth, int* sumAbsGX, int* sumAbsGY, int* sumDIX, int* sumDIY, int* sumSignGY_GX)
135
0
{
136
0
  int shift4 = 4;
137
0
  int shift5 = 1;
138
139
0
  for (int y = 0; y < 6; y++)
140
0
  {
141
0
    for (int x = 0; x < 6; x++)
142
0
    {
143
0
      int tmpGX = (gradX0[x] + gradX1[x]) >> shift5;
144
0
      int tmpGY = (gradY0[x] + gradY1[x]) >> shift5;
145
0
      int tmpDI = (int)((srcY1Tmp[x] >> shift4) - (srcY0Tmp[x] >> shift4));
146
0
      *sumAbsGX += (tmpGX < 0 ? -tmpGX : tmpGX);
147
0
      *sumAbsGY += (tmpGY < 0 ? -tmpGY : tmpGY);
148
0
      *sumDIX += (tmpGX < 0 ? -tmpDI : (tmpGX == 0 ? 0 : tmpDI));
149
0
      *sumDIY += (tmpGY < 0 ? -tmpDI : (tmpGY == 0 ? 0 : tmpDI));
150
0
      *sumSignGY_GX += (tmpGY < 0 ? -tmpGX : (tmpGY == 0 ? 0 : tmpGX));
151
152
0
    }
153
0
    srcY1Tmp += src1Stride;
154
0
    srcY0Tmp += src0Stride;
155
0
    gradX0 += widthG;
156
0
    gradX1 += widthG;
157
0
    gradY0 += widthG;
158
0
    gradY1 += widthG;
159
0
  }
160
0
}
161
162
static void BiOptFlowCore(const Pel* srcY0,const Pel* srcY1,const Pel* gradX0,const Pel* gradX1,const Pel* gradY0,const Pel* gradY1,const int width,const int height,Pel* dstY,const ptrdiff_t dstStride,const int shiftNum,const int  offset,const int  limit, const ClpRng& clpRng, const int bitDepth)
163
0
{
164
0
  int           widthG  = width      + BIO_ALIGN_SIZE;
165
0
  int           stridePredMC = width + BIO_ALIGN_SIZE;
166
0
  int           offsetPos = widthG*BIO_EXTEND_SIZE + BIO_EXTEND_SIZE;
167
0
  int xUnit = (width >> 2);
168
0
  int yUnit = (height >> 2);
169
170
0
  const Pel*    srcY0Temp;
171
0
  const Pel*    srcY1Temp;
172
0
  int OffPos;
173
0
  Pel *dstY0;
174
0
  for (int yu = 0; yu < yUnit; yu++)
175
0
  {
176
0
    for (int xu = 0; xu < xUnit; xu++)
177
0
    {
178
0
      OffPos=offsetPos + ((yu*widthG + xu) << 2);
179
180
0
      {
181
0
        int tmpx = 0, tmpy = 0;
182
0
        int sumAbsGX = 0, sumAbsGY = 0, sumDIX = 0, sumDIY = 0;
183
0
        int sumSignGY_GX = 0;
184
185
0
        const Pel* pGradX0Tmp = gradX0 + (xu << 2) + (yu << 2) * widthG;
186
0
        const Pel* pGradX1Tmp = gradX1 + (xu << 2) + (yu << 2) * widthG;
187
0
        const Pel* pGradY0Tmp = gradY0 + (xu << 2) + (yu << 2) * widthG;
188
0
        const Pel* pGradY1Tmp = gradY1 + (xu << 2) + (yu << 2) * widthG;
189
0
        const Pel* SrcY1Tmp = srcY1 + (xu << 2) + (yu << 2) * stridePredMC;
190
0
        const Pel* SrcY0Tmp = srcY0 + (xu << 2) + (yu << 2) * stridePredMC;
191
192
0
        calcBIOSums(SrcY0Tmp, SrcY1Tmp, pGradX0Tmp, pGradX1Tmp, pGradY0Tmp, pGradY1Tmp, xu, yu, stridePredMC, stridePredMC, widthG, bitDepth, &sumAbsGX, &sumAbsGY, &sumDIX, &sumDIY, &sumSignGY_GX);
193
0
        tmpx = (sumAbsGX == 0 ? 0 : rightShiftMSB(sumDIX *4, sumAbsGX));
194
0
        tmpx = Clip3(-limit, limit, tmpx);
195
0
        int     mainsGxGy = sumSignGY_GX >> 12;
196
0
        int     secsGxGy = sumSignGY_GX & ((1 << 12) - 1);
197
0
        int     tmpData = tmpx * mainsGxGy;
198
0
        tmpData = ((tmpData *(1<< 12)) + tmpx*secsGxGy) >> 1;
199
0
        tmpy = (sumAbsGY == 0 ? 0 : rightShiftMSB(((sumDIY *4) - tmpData), sumAbsGY));
200
0
        tmpy = Clip3(-limit, limit, tmpy);
201
0
        srcY0Temp = srcY0 + (stridePredMC + 1) + ((yu*stridePredMC + xu) << 2);
202
0
        srcY1Temp = srcY1 + (stridePredMC + 1) + ((yu*stridePredMC + xu) << 2);
203
0
        dstY0 = dstY + ((yu*dstStride + xu) << 2);
204
0
        addBIOAvg4(srcY0Temp, stridePredMC, srcY1Temp, stridePredMC, dstY0, dstStride, gradX0 + OffPos, gradX1 + OffPos, gradY0 + OffPos, gradY1 + OffPos, widthG, (1 << 2), (1 << 2), (int)tmpx, (int)tmpy, shiftNum, offset, clpRng);
205
0
      }
206
0
    }  // xu
207
0
  }  // yu
208
209
210
0
}
211
212
template<bool PAD = true>
213
void gradFilterCore(Pel* pSrc, ptrdiff_t srcStride, int width, int height, ptrdiff_t gradStride, Pel* gradX, Pel* gradY, const int bitDepth)
214
0
{
215
0
  Pel* srcTmp   = PAD ? pSrc  + srcStride  + 1 : pSrc;
216
0
  Pel* gradXTmp = PAD ? gradX + gradStride + 1 : gradX;
217
0
  Pel* gradYTmp = PAD ? gradY + gradStride + 1 : gradY;
218
0
  int  shift1 = 6;
219
  
220
0
  const int widthInside  = PAD ? width  - 2 * BIO_EXTEND_SIZE : width;
221
0
  const int heightInside = PAD ? height - 2 * BIO_EXTEND_SIZE : height;
222
223
0
  for (int y = 0; y < heightInside; y++)
224
0
  {
225
0
    for (int x = 0; x < widthInside; x++)
226
0
    {
227
0
      gradYTmp[x] = ( srcTmp[x + srcStride] >> shift1 ) - ( srcTmp[x - srcStride] >> shift1 );
228
0
      gradXTmp[x] = ( srcTmp[x + 1] >> shift1 ) - ( srcTmp[x - 1] >> shift1 );
229
0
    }
230
0
    gradXTmp += gradStride;
231
0
    gradYTmp += gradStride;
232
0
    srcTmp += srcStride;
233
0
  }
234
235
0
  if (PAD)
236
0
  {
237
0
    gradXTmp = gradX + gradStride + 1;
238
0
    gradYTmp = gradY + gradStride + 1;
239
0
    srcTmp   = pSrc  + srcStride  + 1;
240
241
0
    for (int y = 0; y < heightInside; y++)
242
0
    {
243
0
      gradXTmp[-1] = gradXTmp[0];
244
0
      gradXTmp[width - 2 * BIO_EXTEND_SIZE] = gradXTmp[width - 2 * BIO_EXTEND_SIZE - 1];
245
0
      gradXTmp += gradStride;
246
247
0
      gradYTmp[-1] = gradYTmp[0];
248
0
      gradYTmp[width - 2 * BIO_EXTEND_SIZE] = gradYTmp[width - 2 * BIO_EXTEND_SIZE - 1];
249
0
      gradYTmp += gradStride;
250
      
251
0
      srcTmp[-1] = srcTmp[0];
252
0
      srcTmp[width - 2 * BIO_EXTEND_SIZE] = srcTmp[width - 2 * BIO_EXTEND_SIZE - 1];
253
0
      srcTmp += srcStride;
254
0
    }
255
256
0
    gradXTmp = gradX + gradStride;
257
0
    gradYTmp = gradY + gradStride;
258
0
    srcTmp   = pSrc  + srcStride;
259
260
0
    ::memcpy(gradXTmp - gradStride, gradXTmp, sizeof(Pel)*(width));
261
0
    ::memcpy(gradXTmp + (height - 2 * BIO_EXTEND_SIZE)*gradStride, gradXTmp + (height - 2 * BIO_EXTEND_SIZE - 1)*gradStride, sizeof(Pel)*(width));
262
0
    ::memcpy(gradYTmp - gradStride, gradYTmp, sizeof(Pel)*(width));
263
0
    ::memcpy(gradYTmp + (height - 2 * BIO_EXTEND_SIZE)*gradStride, gradYTmp + (height - 2 * BIO_EXTEND_SIZE - 1)*gradStride, sizeof(Pel)*(width));
264
0
    ::memcpy(srcTmp   - srcStride , srcTmp, sizeof(Pel)*(width));
265
0
    ::memcpy(srcTmp   + (height - 2 * BIO_EXTEND_SIZE)*srcStride , srcTmp   + (height - 2 * BIO_EXTEND_SIZE - 1)*srcStride , sizeof(Pel)*(width));
266
0
  }
267
0
}
Unexecuted instantiation: void vvdec::gradFilterCore<true>(short*, long, int, int, long, short*, short*, int)
Unexecuted instantiation: void vvdec::gradFilterCore<false>(short*, long, int, int, long, short*, short*, int)
268
269
void PaddBIOCore(const Pel* refPel,Pel* dstPel,unsigned width,const int shift)
270
0
{
271
0
#define LFTSHFT( y, shift ) y * ( 1 << shift )   // simplification because shift is never < 0
272
273
0
  for( int w = 0; w < width + 2 * BIO_EXTEND_SIZE; w++ )
274
0
  {
275
0
    Pel val   = LFTSHFT( refPel[w], shift );
276
0
    dstPel[w] = val - (Pel)IF_INTERNAL_OFFS;
277
0
  }
278
279
280
0
}
281
282
template<int padSize>
283
void paddingCore(Pel *ptr, ptrdiff_t stride, int width, int height)
284
0
{
285
  /*left and right padding*/
286
0
  Pel *ptrTemp1 = ptr;
287
0
  Pel *ptrTemp2 = ptr + (width - 1);
288
0
  ptrdiff_t offset = 0;
289
0
  for (int i = 0; i < height; i++)
290
0
  {
291
0
    offset = stride * i;
292
0
    for (int j = 1; j <= padSize; j++)
293
0
    {
294
0
      *(ptrTemp1 - j + offset) = *(ptrTemp1 + offset);
295
0
      *(ptrTemp2 + j + offset) = *(ptrTemp2 + offset);
296
0
    }
297
0
  }
298
  /*Top and Bottom padding*/
299
0
  int numBytes = (width + padSize + padSize) * sizeof(Pel);
300
0
  ptrTemp1 = (ptr - padSize);
301
0
  ptrTemp2 = (ptr + (stride * (height - 1)) - padSize);
302
0
  for (int i = 1; i <= padSize; i++)
303
0
  {
304
0
    memcpy(ptrTemp1 - (i * stride), (ptrTemp1), numBytes);
305
0
    memcpy(ptrTemp2 + (i * stride), (ptrTemp2), numBytes);
306
0
  }
307
0
}
Unexecuted instantiation: void vvdec::paddingCore<2>(short*, long, int, int)
Unexecuted instantiation: void vvdec::paddingCore<1>(short*, long, int, int)
308
309
template<int padSize>
310
void prefetchPadCore( const Pel* src, const ptrdiff_t srcStride, Pel* dst, const ptrdiff_t dstStride, int width, int height )
311
0
{
312
0
  g_pelBufOP.copyBuffer( ( const char* ) src, srcStride * sizeof( Pel ), ( char* ) dst, dstStride * sizeof( Pel ), width * sizeof( Pel ), height );
313
314
0
  paddingCore<padSize>( dst, dstStride, width, height );
315
0
}
Unexecuted instantiation: void vvdec::prefetchPadCore<2>(short const*, long, short*, long, int, int)
Unexecuted instantiation: void vvdec::prefetchPadCore<1>(short const*, long, short*, long, int, int)
316
317
// ====================================================================================================================
318
// Constructor / destructor / initialize
319
// ====================================================================================================================
320
321
322
InterPrediction::InterPrediction()
323
22.7k
  : BioGradFilter ( gradFilterCore )
324
22.7k
  , profGradFilter( gradFilterCore<false> )
325
22.7k
  , BiOptFlow     ( BiOptFlowCore )
326
22.7k
  , roundIntVector( nullptr )
327
22.7k
{
328
22.7k
  clipMv = clipMvInPic;
329
330
22.7k
  m_currChromaFormat = NUM_CHROMA_FORMAT;
331
332
22.7k
  memset( m_gradX0,               0x00, sizeof( m_gradX0             ) );
333
22.7k
  memset( m_gradY0,               0x00, sizeof( m_gradY0             ) );
334
22.7k
  memset( m_gradX1,               0x00, sizeof( m_gradX1             ) );
335
22.7k
  memset( m_gradY1,               0x00, sizeof( m_gradY1             ) );
336
22.7k
  memset( m_bdofBlock,            0x00, sizeof( m_bdofBlock          ) );
337
22.7k
  memset( m_acYuvPred,            0x00, sizeof( m_acYuvPred          ) );
338
22.7k
  memset( m_tmpBlock,             0x00, sizeof( m_tmpBlock           ) );
339
22.7k
  memset( m_cRefSamplesDMVRL0,    0x00, sizeof( m_cRefSamplesDMVRL0  ) );
340
22.7k
  memset( m_cRefSamplesDMVRL1,    0x00, sizeof( m_cRefSamplesDMVRL1  ) );
341
22.7k
  memset( m_cYuvPredTempDMVRL0,   0x00, sizeof( m_cYuvPredTempDMVRL0 ) );
342
22.7k
  memset( m_cYuvPredTempDMVRL1,   0x00, sizeof( m_cYuvPredTempDMVRL1 ) );
343
22.7k
  memset( m_SADsArray,            0x00, sizeof( m_SADsArray          ) );
344
22.7k
}
345
346
InterPrediction::~InterPrediction()
347
22.7k
{
348
22.7k
  destroy();
349
22.7k
}
350
351
void InterPrediction::destroy()
352
22.7k
{
353
22.7k
}
354
355
void InterPrediction::init( RdCost* pcRdCost, ChromaFormat chromaFormatIDC, const int ctuSize, bool enableOpt )
356
0
{
357
0
  m_pcRdCost = pcRdCost;
358
359
  // if it has been initialised before, but the chroma format has changed, release the memory and start again.
360
0
  if( m_currChromaFormat != chromaFormatIDC )
361
0
  {
362
0
    destroy();
363
0
    m_currChromaFormat = NUM_CHROMA_FORMAT;
364
0
  }
365
366
0
  if( m_currChromaFormat == NUM_CHROMA_FORMAT ) // check if first is null (in which case, nothing initialised yet)
367
0
  {
368
0
    VALGRIND_MEMCLEAR( m_bdofBlock );
369
0
    VALGRIND_MEMCLEAR( m_tmpBlock  );
370
371
0
    m_iRefListIdx = -1;
372
373
0
    VALGRIND_MEMCLEAR( m_gradX0 );
374
0
    VALGRIND_MEMCLEAR( m_gradY0 );
375
0
    VALGRIND_MEMCLEAR( m_gradX1 );
376
0
    VALGRIND_MEMCLEAR( m_gradY1 );
377
378
0
    m_if.initInterpolationFilter( true );
379
380
0
    applyPROF[0] = applyPROFCore<0>;
381
0
    applyPROF[1] = applyPROFCore<1>;
382
0
    PaddBIO      = PaddBIOCore;
383
0
    prefetchPad[0] = prefetchPadCore<2>; // luma
384
0
    prefetchPad[1] = prefetchPadCore<2>; // chroma for 444 and 422
385
0
    prefetchPad[2] = prefetchPadCore<1>; // chroma for 420
386
0
    if( enableOpt )
387
0
    {
388
#if ENABLE_SIMD_OPT_INTER && defined( TARGET_SIMD_X86 )
389
      initInterPredictionX86();
390
#endif
391
#if ENABLE_SIMD_OPT_INTER && defined( TARGET_SIMD_ARM )
392
      initInterPredictionARM();
393
#endif
394
0
    }
395
0
  }
396
397
0
  m_currChromaFormat = chromaFormatIDC;
398
0
}
399
400
// ====================================================================================================================
401
// Public member functions
402
// ====================================================================================================================
403
404
bool InterPrediction::xCheckIdenticalMotion( const CodingUnit &cu )
405
0
{
406
0
  const Slice &slice = *cu.slice;
407
408
0
  if( slice.isInterB() && !cu.pps->getWPBiPred() )
409
0
  {
410
0
    if( cu.refIdx[0] >= 0 && cu.refIdx[1] >= 0 )
411
0
    {
412
0
      int RefPOCL0 = slice.getRefPOC( REF_PIC_LIST_0, cu.refIdx[0] );
413
0
      int RefPOCL1 = slice.getRefPOC( REF_PIC_LIST_1, cu.refIdx[1] );
414
415
0
      if( RefPOCL0 == RefPOCL1 )
416
0
      {
417
0
        if( !cu.affineFlag() )
418
0
        {
419
0
          if( cu.mv[0][0] == cu.mv[1][0] )
420
0
          {
421
0
            return true;
422
0
          }
423
0
        }
424
0
        else
425
0
        {
426
0
          if( cu.mv[0][0] == cu.mv[1][0] && cu.mv[0][1] == cu.mv[1][1] && ( cu.affineType() == AFFINEMODEL_4PARAM || cu.mv[0][2] == cu.mv[1][2] ) )
427
0
          {
428
0
            return true;
429
0
          }
430
0
        }
431
0
      }
432
0
    }
433
0
  }
434
435
0
  return false;
436
0
}
437
438
void InterPrediction::xSubPuMC( CodingUnit& cu, PelUnitBuf& predBuf )
439
0
{
440
  // compute the location of the current PU
441
0
  const Position puPos    = cu.lumaPos();
442
0
  const Size puSize       = cu.lumaSize();
443
444
0
  const int numPartLine   = std::max<SizeType>( puSize.width  >> ATMVP_SUB_BLOCK_SIZE, 1u );
445
0
  const int numPartCol    = std::max<SizeType>( puSize.height >> ATMVP_SUB_BLOCK_SIZE, 1u );
446
0
  const int puHeight      = numPartCol  == 1 ? puSize.height : 1 << ATMVP_SUB_BLOCK_SIZE;
447
0
  const int puWidth       = numPartLine == 1 ? puSize.width  : 1 << ATMVP_SUB_BLOCK_SIZE;
448
449
0
  CodingUnit      subCu;
450
0
  CodingUnit& subPu = subCu;
451
452
0
  subCu.cs           = cu.cs;
453
0
  subCu.slice        = cu.slice;
454
0
  subCu.pps          = cu.pps;
455
0
  subCu.sps          = cu.sps;
456
0
  subCu.setChType    ( cu.chType() );
457
0
  subCu.setPredMode  ( cu.predMode() );
458
0
  subCu.UnitArea::operator=( cu );
459
460
0
  subPu.setMergeType ( MRG_TYPE_DEFAULT_N );
461
0
  subPu.setAffineFlag( false );
462
0
  subPu.setGeoFlag   ( false );
463
0
  subPu.setBcwIdx    ( cu.BcwIdx() );
464
0
  subPu.setImv       ( cu.imv() );
465
0
  subPu.setSmvdMode  ( cu.smvdMode() );
466
467
  // join sub-pus containing the same motion
468
0
  bool verMC    = puSize.height > puSize.width;
469
0
  int  fstStart = ( !verMC ? puPos.y : puPos.x );
470
0
  int  secStart = ( !verMC ? puPos.x : puPos.y );
471
0
  int  fstEnd   = ( !verMC ? puPos.y + puSize.height : puPos.x + puSize.width  );
472
0
  int  secEnd   = ( !verMC ? puPos.x + puSize.width  : puPos.y + puSize.height );
473
0
  int  fstStep  = ( !verMC ? puHeight : puWidth  );
474
0
  int  secStep  = ( !verMC ? puWidth  : puHeight );
475
476
0
#if RPR_FIX
477
0
  bool scaled = cu.slice->getRefPic( REF_PIC_LIST_0, 0 )->isRefScaled( cu.pps ) || ( cu.slice->getSliceType() == B_SLICE ? cu.slice->getRefPic( REF_PIC_LIST_1, 0 )->isRefScaled( cu.pps ) : false );
478
0
#endif
479
  
480
0
  m_subPuMC = true;
481
482
0
  for( int fstDim = fstStart; fstDim < fstEnd; fstDim += fstStep )
483
0
  {
484
0
    for( int secDim = secStart; secDim < secEnd; secDim += secStep )
485
0
    {
486
0
      int x = !verMC ? secDim : fstDim;
487
0
      int y = !verMC ? fstDim : secDim;
488
0
      const MotionInfo &curMi = cu.getMotionInfo( Position{ x, y } );
489
490
0
      int length = secStep;
491
0
      int later   = secDim + secStep;
492
493
0
      while( later < secEnd )
494
0
      {
495
0
        const MotionInfo &laterMi = !verMC ? cu.getMotionInfo( Position{ later, fstDim } ) : cu.getMotionInfo( Position{ fstDim, later } );
496
0
#if RPR_FIX
497
0
        if( !scaled && laterMi == curMi )
498
#else
499
        if( laterMi == curMi )
500
#endif
501
0
        {
502
0
          length += secStep;
503
0
        }
504
0
        else
505
0
        {
506
0
          break;
507
0
        }
508
0
        later += secStep;
509
0
      }
510
511
0
      int dx = !verMC ? length : puWidth;
512
0
      int dy = !verMC ? puHeight : length;
513
514
0
      subPu = curMi;
515
516
0
      if( !verMC && ( dx & 15 ) && dx > 16 )
517
0
      {
518
0
        int dxPart = dx & ~15;
519
520
0
        new ( &static_cast< UnitArea& >( subPu ) ) UnitArea( cu.chromaFormat, Area( x, y, dxPart, dy ) );
521
0
        PelUnitBuf subPredBuf = predBuf.subBuf( UnitAreaRelative( cu, subPu ) );
522
523
0
        motionCompensation( subPu, subPredBuf );
524
0
        x  += dxPart;
525
0
        dx -= dxPart;
526
0
      }
527
0
      else if( verMC && ( dy & 15 ) && dy > 16 )
528
0
      {
529
0
        int dyPart = dy & ~15;
530
531
0
        new ( &static_cast< UnitArea& >( subPu ) ) UnitArea( cu.chromaFormat, Area( x, y, dx, dyPart ) );
532
0
        PelUnitBuf subPredBuf = predBuf.subBuf( UnitAreaRelative( cu, subPu ) );
533
534
0
        motionCompensation( subPu, subPredBuf );
535
536
0
        y  += dyPart;
537
0
        dy -= dyPart;
538
0
      }
539
540
0
      new ( &static_cast< UnitArea& >( subPu ) ) UnitArea( cu.chromaFormat, Area( x, y, dx, dy ) );
541
0
      PelUnitBuf subPredBuf = predBuf.subBuf( UnitAreaRelative( cu, subPu ) );
542
543
0
      motionCompensation( subPu, subPredBuf );
544
545
0
      secDim = later - secStep;
546
0
    }
547
0
  }
548
0
  m_subPuMC = false;
549
0
}
550
551
void InterPrediction::xSubPuBio(CodingUnit& cu, PelUnitBuf& predBuf )
552
0
{
553
  // compute the location of the current PU
554
0
  const Position puPos = cu.lumaPos();
555
0
  const Size puSize    = cu.lumaSize();
556
  
557
0
  CodingUnit      subCu;
558
0
  CodingUnit& subPu = subCu;
559
560
0
  subCu.cs           = cu.cs;
561
0
  subCu.slice        = cu.slice;
562
0
  subCu.pps          = cu.pps;
563
0
  subCu.sps          = cu.sps;
564
0
  subCu.setChType    ( cu.chType() );
565
0
  subCu.setPredMode  ( cu.predMode() );
566
567
0
  subPu.setMergeType ( cu.mergeType() );
568
0
  subPu.setMmvdFlag  ( cu.mmvdFlag() );
569
0
  subPu.setMergeFlag ( cu.mergeFlag() );
570
0
  subPu.setCiipFlag  ( cu.ciipFlag() );
571
0
  subPu.setGeoFlag   ( cu.geoFlag() );
572
//  subPu.mvRefine = cu.mvRefine;
573
0
  subPu.setAffineFlag( cu.affineFlag() );
574
0
  subPu.refIdx[0]    = cu.refIdx[0];
575
0
  subPu.refIdx[1]    = cu.refIdx[1];
576
0
  subPu.setBcwIdx    ( cu.BcwIdx() );
577
0
  subPu.setImv       ( cu.imv() );
578
0
  subPu.setSmvdMode  ( cu.smvdMode() );
579
580
0
  const int  subPuHeight = std::min<int>( MAX_BDOF_APPLICATION_REGION, puSize.height );
581
0
  const int  subPuWidth  = std::min<int>( MAX_BDOF_APPLICATION_REGION, puSize.width );
582
583
0
  const int  csy = getChannelTypeScaleY( CH_C, cu.chromaFormat );
584
0
  const int  csx = getChannelTypeScaleX( CH_C, cu.chromaFormat );
585
586
0
  const int  subPuHeightC = subPuHeight >> csy;
587
0
  const int  subPuWidthC  = subPuWidth  >> csx;
588
  
589
0
  PelUnitBuf pcMbBuf1( cu.chromaFormat, PelBuf( m_acYuvPred[0], subPuWidth, subPuHeight ), PelBuf( m_acYuvPred[1], subPuWidthC, subPuHeightC ), PelBuf( m_acYuvPred[2], subPuWidthC, subPuHeightC ) );
590
  
591
0
  PelUnitBuf subPredBuf = predBuf.subBuf( UnitAreaRelative( cu, UnitArea( cu.chromaFormat, Area( 0, 0, subPuWidth, subPuHeight ) ) ) );
592
                                                                   
593
0
  for( int y = puPos.y, dy = 0; y < puPos.y + puSize.height; y += subPuHeight, dy += subPuHeight )
594
0
  {
595
0
    for( int x = puPos.x, dx = 0; x < puPos.x + puSize.width; x += subPuWidth, dx += subPuWidth )
596
0
    {
597
0
      const MotionInfo &curMi = cu.getMotionInfo( Position{ x, y } );
598
599
0
      new ( &static_cast< UnitArea& >( subPu ) ) UnitArea( cu.chromaFormat, Area( x, y, subPuWidth, subPuHeight ) );
600
0
      subPu = curMi;
601
602
0
      subPredBuf  .bufs[0].buf = GET_OFFSET( predBuf.bufs[0].buf, predBuf.bufs[0].stride, dx,        dy );
603
0
      if( isChromaEnabled( cu.chromaFormat ) )
604
0
      {
605
0
        subPredBuf.bufs[1].buf = GET_OFFSET( predBuf.bufs[1].buf, predBuf.bufs[1].stride, dx >> csx, dy >> csy );
606
0
        subPredBuf.bufs[2].buf = GET_OFFSET( predBuf.bufs[2].buf, predBuf.bufs[2].stride, dx >> csx, dy >> csy );
607
0
      }
608
609
0
      CHECKD( cu.refIdx[0] < 0 || cu.refIdx[1] < 0, "Bi-prediction required for BDOF!" );
610
611
0
      PelUnitBuf& pcMbBuf0 = subPredBuf;
612
613
0
      m_iRefListIdx = REF_PIC_LIST_0;
614
0
      xPredInterUni( subPu, REF_PIC_LIST_0, pcMbBuf0, true, true, true, true );
615
0
      m_iRefListIdx = REF_PIC_LIST_1;
616
0
      xPredInterUni( subPu, REF_PIC_LIST_1, pcMbBuf1, true, true, true, true );
617
618
0
      xWeightedAverage( subPu, pcMbBuf0, pcMbBuf1, subPredBuf, cu.sps->getBitDepths(), cu.slice->clpRngs(), true );
619
0
    }
620
0
  }
621
0
}
622
623
void InterPrediction::xPredInterUni( const CodingUnit &cu, const RefPicList &eRefPicList, PelUnitBuf &pcYuvPred, const bool &bi, const bool &bioApplied, const bool luma, const bool chroma )
624
0
{
625
0
  const SPS &    sps     = *cu.sps;
626
0
  const int      iRefIdx = cu.refIdx[eRefPicList];
627
0
  const bool     isIBC   = CU::isIBC( cu );
628
0
  const Picture *refPic  = isIBC ? cu.slice->getPic() : cu.slice->getRefPic( eRefPicList, iRefIdx );
629
0
        bool     affine  = cu.affineFlag();
630
0
  Mv             mv[3];
631
0
  const bool scaled       = refPic ? refPic->isRefScaled( cu.pps ) : false;
632
0
  const auto scalingRatio = cu.slice->getScalingRatio( eRefPicList, iRefIdx );
633
634
0
  CHECKD( !CU::isIBC( cu ) && cu.lwidth() == 4 && cu.lheight() == 4, "invalid 4x4 inter blocks" );
635
636
0
  if( affine )
637
0
  {
638
0
    CHECK( iRefIdx < 0, "iRefIdx incorrect." );
639
640
0
    mv[0] = cu.mv[eRefPicList][0];
641
0
    mv[1] = cu.mv[eRefPicList][1];
642
0
    mv[2] = cu.mv[eRefPicList][2];
643
0
  }
644
0
  else
645
0
  {
646
0
    mv[0] = cu.mv[eRefPicList][0];
647
648
0
    CHECK( !refPic, "xPredInterUni missing ref pic" );
649
650
0
    if( !isIBC && !scaled )
651
0
    {
652
0
      clipMv( mv[0], m_currCuArea.lumaPos(), m_currCuArea.lumaSize(), sps, *cu.pps );
653
0
    }
654
0
  }
655
656
0
  const bool wrapRef = !isIBC && cu.sps->getUseWrapAround() && wrapClipMv( mv[0], cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
657
658
0
  for( uint32_t comp = COMPONENT_Y; comp < pcYuvPred.bufs.size(); comp++ )
659
0
  {
660
0
    const ComponentID compID = ComponentID( comp );
661
662
0
    if( compID == COMPONENT_Y && !luma   ) continue;
663
0
    if( compID != COMPONENT_Y && !chroma ) continue;
664
665
0
    if( affine )
666
0
    {
667
0
      CHECK( bioApplied, "BIO is not allowed with affine" );
668
0
      m_iRefListIdx = eRefPicList;
669
0
      xPredAffineBlk( compID, cu, refPic, eRefPicList, pcYuvPred, bi, cu.slice->clpRng( compID ), cu.slice->getScalingRatio( eRefPicList, iRefIdx ) );
670
0
    }
671
0
    else
672
0
    {
673
0
      if( !isIBC && scaled )
674
0
      {
675
0
        xPredInterBlkRPR( scalingRatio, *cu.pps, compID, cu.chromaFormat, refPic, mv[0], cu.blocks[compID], pcYuvPred.bufs[compID].width, pcYuvPred.bufs[compID].height, pcYuvPred.bufs[compID].buf, pcYuvPred.bufs[compID].stride, bi, wrapRef, cu.slice->clpRng( compID ), 0, cu.imv() == IMV_HPEL );
676
0
        CHECKD( bioApplied, "BDOF should be disabled with RPR" );
677
0
      }
678
0
      else
679
0
      {
680
0
        xPredInterBlk<false, false>( compID, cu, refPic, mv[0], pcYuvPred.bufs[compID], bi, cu.slice->clpRng( compID ), bioApplied, isIBC, wrapRef );
681
0
      }
682
0
    }
683
0
  }
684
0
}
685
686
void InterPrediction::xPredInterBi( CodingUnit& cu, PelUnitBuf &pcYuvPred )
687
0
{
688
0
  const Slice &slice = *cu.slice;
689
0
  const PPS   &pps   = *cu.pps;
690
691
0
  PelUnitBuf& pcMbBuf0 = pcYuvPred;
692
0
  PelUnitBuf  pcMbBuf1 = isChromaEnabled( cu.chromaFormat ) ? PelUnitBuf( cu.chromaFormat, PelBuf( m_acYuvPred[0], pcYuvPred.Y() ), PelBuf( m_acYuvPred[1], pcYuvPred.Cb() ), PelBuf( m_acYuvPred[2], pcYuvPred.Cr() ) ) : PelUnitBuf( cu.chromaFormat, PelBuf( m_acYuvPred[0], pcYuvPred.Y() ) );
693
694
0
  const bool isBiPred = cu.refIdx[0] >= 0 && cu.refIdx[1] >= 0;
695
696
0
  if( isBiPred )
697
0
  {
698
0
    m_iRefListIdx = REF_PIC_LIST_0;
699
0
    xPredInterUni( cu, REF_PIC_LIST_0, pcMbBuf0, true, false, true, true );
700
0
    m_iRefListIdx = REF_PIC_LIST_1;
701
0
    xPredInterUni( cu, REF_PIC_LIST_1, pcMbBuf1, true, false, true, true );
702
0
  }
703
0
  else
704
0
  {
705
0
    m_iRefListIdx = cu.refIdx[0] >= 0 ? REF_PIC_LIST_0 : REF_PIC_LIST_1;
706
707
0
    if( !cu.geoFlag() && ( ( pps.getUseWP() && slice.getSliceType() == P_SLICE ) || ( pps.getWPBiPred() && slice.getSliceType() == B_SLICE ) ) )
708
0
    {
709
0
      xPredInterUni( cu, RefPicList( m_iRefListIdx ), pcMbBuf0, true, false, true, true );
710
0
    }
711
0
    else
712
0
    {
713
0
      xPredInterUni( cu, RefPicList( m_iRefListIdx ), pcYuvPred, cu.geoFlag(), false, true, true );
714
0
    }
715
0
  }
716
717
0
#ifndef NDEBUG
718
0
  for( uint32_t refList = 0; refList < NUM_REF_PIC_LIST_01; refList++ )
719
0
  {
720
0
    if( cu.refIdx[refList] < 0 )
721
0
    {
722
0
      continue;
723
0
    }
724
725
0
    RefPicList eRefPicList = refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
726
727
0
    CHECKD( CU::isIBC( cu ) && eRefPicList != REF_PIC_LIST_0, "Invalid interdir for ibc mode" );
728
0
    CHECKD( CU::isIBC( cu ) && cu.refIdx[refList] != MAX_NUM_REF, "Invalid reference index for ibc mode" );
729
0
    CHECKD( CU::isInter( cu ) && cu.refIdx[refList] >= slice.getNumRefIdx( eRefPicList ), "Invalid reference index" );
730
0
  }
731
732
0
#endif
733
0
  if( !cu.geoFlag() )
734
0
  {
735
0
    if( pps.getWPBiPred() && slice.getSliceType() == B_SLICE && cu.BcwIdx() == BCW_DEFAULT )
736
0
    {
737
0
      xWeightedPredictionBi( cu, pcMbBuf0, isBiPred ? pcMbBuf1 : pcMbBuf0, pcYuvPred );
738
0
    }
739
0
    else if( pps.getUseWP() && slice.getSliceType() == P_SLICE )
740
0
    {
741
0
      xWeightedPredictionUni( cu, pcMbBuf0, REF_PIC_LIST_0, pcYuvPred, -1 );
742
0
    }
743
0
    else if( isBiPred )
744
0
    {
745
0
      xWeightedAverage( cu, pcMbBuf0, pcMbBuf1, pcYuvPred, slice.getSPS()->getBitDepths(), slice.clpRngs(), false );
746
0
    }
747
0
  }
748
0
}
749
750
template<bool altSrc, bool altSize>
751
void InterPrediction::xPredInterBlk( const ComponentID&    compID,
752
                                     const CodingUnit& cu,
753
                                     const Picture*        refPic,
754
                                     Mv                    mv,
755
                                     PelBuf&               dstPic,
756
                                     bool                  bi,
757
                                     const ClpRng&         clpRng,
758
                                     bool                  bioApplied,
759
                                     bool                  isIBC,
760
                                     bool                  wrapRef,
761
                                     SizeType              dmvrWidth,
762
                                     SizeType              dmvrHeight,
763
                                     bool                  bilinearMC,
764
                                     Pel*                  srcPadBuf,
765
                                     ptrdiff_t             srcPadStride )
766
0
{
767
0
  CHECK( srcPadBuf == NULL && altSrc, "wrong" );
768
  
769
0
  const ChromaFormat  chFmt = cu.chromaFormat;
770
0
  const bool          rndRes = !bi;
771
772
0
  const int shiftHor = MV_FRACTIONAL_BITS_INTERNAL + getComponentScaleX(compID, chFmt);
773
0
  const int shiftVer = MV_FRACTIONAL_BITS_INTERNAL + getComponentScaleY(compID, chFmt);
774
  
775
0
  const bool useAltHpelIf = cu.imv() == IMV_HPEL;
776
777
0
  const int xFrac     = !isIBC ? mv.hor & ( ( 1 << shiftHor ) - 1 ) : 0;
778
0
  const int yFrac     = !isIBC ? mv.ver & ( ( 1 << shiftVer ) - 1 ) : 0;
779
780
0
  const Pel* refPtr    = nullptr;
781
0
  ptrdiff_t  refStride = 0;
782
0
  if( cu.pps->getNumSubPics() > 1 && cu.pps->getSubPicFromCU( cu ).getTreatedAsPicFlag() )
783
0
  {
784
0
    const int subPicIdx = cu.pps->getSubPicFromCU( cu ).getSubPicIdx();
785
0
    refPtr              = altSrc ? srcPadBuf    : refPic->getSubPicBufPtr   ( subPicIdx, compID, wrapRef );
786
0
    refStride           = altSrc ? srcPadStride : refPic->getSubPicBufStride( subPicIdx, compID, wrapRef );
787
0
  }
788
0
  else
789
0
  {
790
0
    refPtr    = altSrc ? srcPadBuf    : refPic->getRecoBufPtr   ( compID, wrapRef );
791
0
    refStride = altSrc ? srcPadStride : refPic->getRecoBufStride( compID, wrapRef );
792
0
  }
793
794
0
  if( !altSrc )
795
0
  {
796
0
    OFFSET( refPtr, refStride, cu.blocks[compID].x + ( mv.hor >> shiftHor ), cu.blocks[compID].y + ( mv.ver >> shiftVer ) );
797
0
  }
798
799
0
  unsigned width, height;
800
801
0
  if( altSize )
802
0
  {
803
0
    width  = dmvrWidth;
804
0
    height = dmvrHeight;
805
0
  }
806
0
  else
807
0
  {
808
0
    width  = dstPic.width;
809
0
    height = dstPic.height;
810
0
  }
811
812
0
  Pel* dstBuf;
813
0
  ptrdiff_t dstStride;
814
815
0
  if( bioApplied && compID == COMPONENT_Y )
816
0
  {
817
    // change MC output
818
0
    dstStride = width + BIO_ALIGN_SIZE;
819
0
    dstBuf    = m_bdofBlock[m_iRefListIdx] + 2 * dstStride + 1;
820
0
  }
821
0
  else
822
0
  {
823
0
    dstBuf    = dstPic.buf;
824
0
    dstStride = dstPic.stride;
825
0
  }
826
827
    
828
0
  if( yFrac == 0 )
829
0
  {
830
0
    m_if.filterHor( compID, refPtr, refStride, dstBuf, dstStride, width, height, xFrac, rndRes, chFmt, clpRng, bilinearMC ? 1 : 0, useAltHpelIf );
831
0
  }
832
0
  else if( xFrac == 0 )
833
0
  {
834
0
    m_if.filterVer( compID, refPtr, refStride, dstBuf, dstStride, width, height, yFrac, true, rndRes, chFmt, clpRng, bilinearMC ? 1 : 0, useAltHpelIf );
835
0
  }
836
0
  else if( bilinearMC )
837
0
  {
838
0
    m_if.filterN2_2D( compID, refPtr, refStride, dstBuf, dstStride, width, height, xFrac, yFrac, chFmt, clpRng );
839
0
  }
840
0
  else if( width == 4 && height == 4 )
841
0
  {
842
0
    m_if.filter4x4( compID, refPtr, refStride, dstBuf, dstStride, 4, 4, xFrac, yFrac, rndRes, chFmt, clpRng );
843
0
  }
844
0
  else if( width == 16 )
845
0
  {
846
0
    m_if.filter16xH( compID, refPtr, refStride, dstBuf, dstStride, 16, height, xFrac, yFrac, rndRes, chFmt, clpRng, useAltHpelIf );
847
0
  }
848
0
  else if( width == 8 )
849
0
  {
850
0
    m_if.filter8xH( compID, refPtr, refStride, dstBuf, dstStride, 8, height, xFrac, yFrac, rndRes, chFmt, clpRng, useAltHpelIf );
851
0
  }
852
0
  else
853
0
  {
854
0
    Pel *tmpBuf = m_tmpBlock;
855
0
    ptrdiff_t tmpStride = dmvrWidth ? dmvrWidth : width;
856
857
0
    int vFilterSize = bilinearMC ? NTAPS_BILINEAR : isLuma( compID ) ? NTAPS_LUMA : NTAPS_CHROMA;
858
859
0
    m_if.filterHor( compID, GET_OFFSETY( refPtr, refStride, -( ( vFilterSize >> 1 ) - 1 ) ), refStride, tmpBuf, tmpStride, width, height + vFilterSize - 1, xFrac, false,         chFmt, clpRng, bilinearMC ? 1 : 0, useAltHpelIf );
860
0
    m_if.filterVer( compID, GET_OFFSETY( tmpBuf, tmpStride,    ( vFilterSize >> 1 ) - 1 ),   tmpStride, dstBuf, dstStride, width, height,                   yFrac, false, rndRes, chFmt, clpRng, bilinearMC ? 1 : 0, useAltHpelIf );
861
0
  }
862
863
0
  if( bioApplied && compID == COMPONENT_Y )
864
0
  {
865
0
    const int   shift   = std::max<int>( 2, ( IF_INTERNAL_PREC - clpRng.bd ) );
866
0
    const int   xOffset = ( xFrac < 8 ) ? 1 : 0;
867
0
    const int   yOffset = ( yFrac < 8 ) ? 1 : 0;
868
0
    const Pel*  refPel  = refPtr + ( 1 - yOffset ) * refStride - xOffset;
869
0
    Pel*        dstPel  = m_bdofBlock[m_iRefListIdx] + 2 * dstStride;
870
871
0
    for( int h = 0; h < height; h++ )
872
0
    {
873
0
      dstPel[0]         = refPel[0        ] * ( 1 << shift ) - ( Pel ) IF_INTERNAL_OFFS;
874
0
      dstPel[width + 1] = refPel[width + 1] * ( 1 << shift ) - ( Pel ) IF_INTERNAL_OFFS;
875
876
0
      refPel += refStride;
877
0
      dstPel += dstStride;
878
0
    }
879
880
0
    refPel = refPtr - yOffset * refStride - xOffset;
881
0
    dstPel = m_bdofBlock[m_iRefListIdx] + dstStride;
882
883
0
    PaddBIO( refPel, dstPel, width, shift );
884
    
885
0
    refPel = refPtr + ( height + 1 - yOffset ) * refStride - xOffset;
886
0
    dstPel = m_bdofBlock[m_iRefListIdx] + ( height + 2 * BIO_EXTEND_SIZE ) * dstStride;
887
888
0
    PaddBIO( refPel, dstPel, width, shift );
889
0
  }
890
0
}
Unexecuted instantiation: void vvdec::InterPrediction::xPredInterBlk<false, false>(vvdec::ComponentID const&, vvdec::CodingUnit const&, vvdec::Picture const*, vvdec::Mv, vvdec::AreaBuf<short>&, bool, vvdec::ClpRngTemplate<short> const&, bool, bool, bool, unsigned int, unsigned int, bool, short*, long)
Unexecuted instantiation: void vvdec::InterPrediction::xPredInterBlk<true, false>(vvdec::ComponentID const&, vvdec::CodingUnit const&, vvdec::Picture const*, vvdec::Mv, vvdec::AreaBuf<short>&, bool, vvdec::ClpRngTemplate<short> const&, bool, bool, bool, unsigned int, unsigned int, bool, short*, long)
Unexecuted instantiation: void vvdec::InterPrediction::xPredInterBlk<false, true>(vvdec::ComponentID const&, vvdec::CodingUnit const&, vvdec::Picture const*, vvdec::Mv, vvdec::AreaBuf<short>&, bool, vvdec::ClpRngTemplate<short> const&, bool, bool, bool, unsigned int, unsigned int, bool, short*, long)
891
892
bool InterPrediction::isSubblockVectorSpreadOverLimit( int a, int b, int c, int d, int predType )
893
0
{
894
0
  int s4 = ( 4 << 11 );
895
0
  int filterTap = 6;
896
897
0
  if ( predType == 3 )
898
0
  {
899
0
    int refBlkWidth  = std::max( std::max( 0, 4 * a + s4 ), std::max( 4 * c, 4 * a + 4 * c + s4 ) ) - std::min( std::min( 0, 4 * a + s4 ), std::min( 4 * c, 4 * a + 4 * c + s4 ) );
900
0
    int refBlkHeight = std::max( std::max( 0, 4 * b ), std::max( 4 * d + s4, 4 * b + 4 * d + s4 ) ) - std::min( std::min( 0, 4 * b ), std::min( 4 * d + s4, 4 * b + 4 * d + s4 ) );
901
0
    refBlkWidth  = ( refBlkWidth >> 11 ) + filterTap + 3;
902
0
    refBlkHeight = ( refBlkHeight >> 11 ) + filterTap + 3;
903
904
0
    if ( refBlkWidth * refBlkHeight > ( filterTap + 9 ) * ( filterTap + 9 ) )
905
0
    {
906
0
      return true;
907
0
    }
908
0
  }
909
0
  else
910
0
  {
911
0
    int refBlkWidth  = std::max( 0, 4 * a + s4 ) - std::min( 0, 4 * a + s4 );
912
0
    int refBlkHeight = std::max( 0, 4 * b ) - std::min( 0, 4 * b );
913
0
    refBlkWidth  = ( refBlkWidth >> 11 ) + filterTap + 3;
914
0
    refBlkHeight = ( refBlkHeight >> 11 ) + filterTap + 3;
915
0
    if ( refBlkWidth * refBlkHeight > ( filterTap + 9 ) * ( filterTap + 5 ) )
916
0
    {
917
0
      return true;
918
0
    }
919
920
0
    refBlkWidth  = std::max( 0, 4 * c ) - std::min( 0, 4 * c );
921
0
    refBlkHeight = std::max( 0, 4 * d + s4 ) - std::min( 0, 4 * d + s4 );
922
0
    refBlkWidth  = ( refBlkWidth >> 11 ) + filterTap + 3;
923
0
    refBlkHeight = ( refBlkHeight >> 11 ) + filterTap + 3;
924
0
    if ( refBlkWidth * refBlkHeight > ( filterTap + 5 ) * ( filterTap + 9 ) )
925
0
    {
926
0
      return true;
927
0
    }
928
0
  }
929
0
  return false;
930
0
}
931
932
#define CALC_AFFINE_MV_ON_THE_FLY 0
933
934
void InterPrediction::xPredAffineBlk( const ComponentID&        compID,
935
                                      const CodingUnit&     cu,
936
                                      const Picture*            refPic,
937
                                      const RefPicList          refPicList,
938
                                      PelUnitBuf&               dstPic,
939
                                      bool                      bi,
940
                                      const ClpRng&             clpRng,
941
                                      const std::pair<int, int> scalingRatio
942
                                      )
943
0
{
944
0
  const ChromaFormat chFmt = cu.chromaFormat;
945
0
  const int iScaleX = getComponentScaleX( compID, chFmt );
946
0
  const int iScaleY = getComponentScaleY( compID, chFmt );
947
948
0
  const int chromaScaleX = getChannelTypeScaleX( CH_C, chFmt );
949
0
  const int chromaScaleY = getChannelTypeScaleY( CH_C, chFmt );
950
951
0
  const int shiftX = 4 + iScaleX;
952
0
  const int shiftY = 4 + iScaleY;
953
0
  const int maskX  = ( 1 << shiftX ) - 1;
954
0
  const int maskY  = ( 1 << shiftY ) - 1;
955
956
  // get affine sub-block width and height
957
0
  const int width  = cu.lwidth();
958
0
  const int height = cu.lheight();
959
960
0
  static constexpr int blockWidth  = AFFINE_MIN_BLOCK_SIZE;
961
0
  static constexpr int blockHeight = AFFINE_MIN_BLOCK_SIZE;
962
963
0
  const int MVBUFFER_SIZE = ( width / AFFINE_MIN_BLOCK_SIZE ) >> chromaScaleX;
964
965
0
  const int cxWidth  = width  >> iScaleX;
966
0
  const int cxHeight = height >> iScaleY;
967
0
  const SPS &sps    = *cu.sps;
968
0
  const int iMvShift = 4;
969
0
  const int iOffset  = 8;
970
0
  const int iHorMax = ( cu.pps->getPicWidthInLumaSamples()  + iOffset -       cu.lx() - 1 ) *(1<< iMvShift);
971
0
  const int iHorMin = (  -(int)cu.cs->pcv->maxCUWidth       - iOffset -  (int)cu.lx() + 1 ) *(1<< iMvShift);
972
0
  const int iVerMax = ( cu.pps->getPicHeightInLumaSamples() + iOffset -       cu.ly() - 1 ) *(1<< iMvShift);
973
0
  const int iVerMin = (  -(int)cu.cs->pcv->maxCUHeight      - iOffset -  (int)cu.ly() + 1 ) *(1<< iMvShift);
974
0
  const bool clipSubPic = clipMv == clipMvInSubpic;
975
976
0
  const int shift = MAX_CU_DEPTH;
977
978
0
  const Mv &affLT = cu.mv[refPicList][0];
979
0
  const Mv &affRT = cu.mv[refPicList][1];
980
0
  const Mv &affLB = cu.mv[refPicList][2];
981
982
0
  int deltaMvHorX, deltaMvHorY, deltaMvVerX, deltaMvVerY;
983
984
0
  deltaMvHorX = ( affRT - affLT ).getHor() *(1<< ( shift - getLog2( width )));
985
0
  deltaMvHorY = ( affRT - affLT ).getVer() *(1<< ( shift - getLog2( width )));
986
987
0
  if( cu.affineType() == AFFINEMODEL_6PARAM )
988
0
  {
989
0
    deltaMvVerX = ( affLB - affLT ).getHor() *(1<< ( shift - getLog2( height )));
990
0
    deltaMvVerY = ( affLB - affLT ).getVer() *(1<< ( shift - getLog2( height )));
991
0
  }
992
0
  else
993
0
  {
994
0
    deltaMvVerX = -deltaMvHorY;
995
0
    deltaMvVerY =  deltaMvHorX;
996
0
  }
997
998
#if CALC_AFFINE_MV_ON_THE_FLY
999
  const int mvScaleHor = affLT.getHor() << shift;
1000
  const int mvScaleVer = affLT.getVer() << shift;
1001
1002
  static const int halfBW = AFFINE_MIN_BLOCK_SIZE >> 1;
1003
  static const int halfBH = AFFINE_MIN_BLOCK_SIZE >> 1;
1004
1005
#endif
1006
0
  const bool subblkMVSpreadOverLimit = InterPrediction::isSubblockVectorSpreadOverLimit( deltaMvHorX, deltaMvHorY, deltaMvVerX, deltaMvVerY, cu.interDir() );
1007
1008
0
  const bool refPicScaled = refPic->isRefScaled( cu.pps );
1009
1010
0
  PelBuf &dstBuf = dstPic.bufs[compID];
1011
1012
0
#if !CALC_AFFINE_MV_ON_THE_FLY
1013
0
  const CMotionBuf mb       = cu.getMotionBuf();
1014
0
  const MotionInfo* curMi   = mb.buf;
1015
0
  const ptrdiff_t miStride  = mb.stride;
1016
0
#endif
1017
0
  Mv* chromaMvFld = m_storedMv;
1018
1019
0
  if( isLuma( compID ) )
1020
0
  {
1021
0
    memset( NO_WARNING_class_memaccess( m_storedMv ), 0, MVBUFFER_SIZE * ( g_miScaling.scaleVer( height ) >> chromaScaleY ) * sizeof( Mv ) );
1022
0
  }
1023
1024
0
  bool enablePROF = ( sps.getUsePROF() ) && ( compID == COMPONENT_Y );
1025
0
  enablePROF &= (! cu.cs->picHeader->getDisProfFlag() );
1026
0
  enablePROF &= !( ( cu.affineType() == AFFINEMODEL_6PARAM && affLT == affRT && affLT == affLB ) || ( cu.affineType() == AFFINEMODEL_4PARAM && affLT == affRT ) );
1027
0
  enablePROF &= !subblkMVSpreadOverLimit;
1028
0
  enablePROF &= !refPicScaled;
1029
1030
0
  bool isLast = enablePROF ? false : !bi;
1031
1032
0
  Pel gradX[36];
1033
0
  Pel gradY[36];
1034
1035
0
  static constexpr int dstExtW = blockWidth  + PROF_BORDER_EXT_W * 2;
1036
0
  static constexpr int dstExtH = blockHeight + PROF_BORDER_EXT_H * 2;
1037
0
  PelBuf dstExtBuf( m_bdofBlock[0], dstExtW, dstExtH );
1038
1039
0
  int dMvScaleHor[16];
1040
0
  int dMvScaleVer[16];
1041
1042
0
  if (enablePROF)
1043
0
  {
1044
0
    int* dMvH = dMvScaleHor;
1045
0
    int* dMvV = dMvScaleVer;
1046
0
    int quadHorX = deltaMvHorX *(1<< 2);
1047
0
    int quadHorY = deltaMvHorY *(1<< 2);
1048
0
    int quadVerX = deltaMvVerX *(1<< 2);
1049
0
    int quadVerY = deltaMvVerY *(1<< 2);
1050
1051
0
    dMvH[0] = ((deltaMvHorX + deltaMvVerX) *2) - ((quadHorX + quadVerX) *2);
1052
0
    dMvV[0] = ((deltaMvHorY + deltaMvVerY) *2) - ((quadHorY + quadVerY) *2);
1053
1054
0
    for (int w = 1; w < blockWidth; w++)
1055
0
    {
1056
0
      dMvH[w] = dMvH[w - 1] + quadHorX;
1057
0
      dMvV[w] = dMvV[w - 1] + quadHorY;
1058
0
    }
1059
1060
0
    dMvH += blockWidth;
1061
0
    dMvV += blockWidth;
1062
0
    for (int h = 1; h < blockHeight; h++)
1063
0
    {
1064
0
      for (int w = 0; w < blockWidth; w++)
1065
0
      {
1066
0
        dMvH[w] = dMvH[w - blockWidth] + quadVerX;
1067
0
        dMvV[w] = dMvV[w - blockWidth] + quadVerY;
1068
0
      }
1069
0
      dMvH += blockWidth;
1070
0
      dMvV += blockWidth;
1071
0
    }
1072
1073
0
    const int mvShift  = 8;
1074
0
    const int dmvLimit = ( 1 << 5 ) - 1;
1075
1076
0
    if (!roundIntVector)
1077
0
    {
1078
0
      for (int idx = 0; idx < blockWidth * blockHeight; idx++)
1079
0
      {
1080
0
        roundAffineMv(dMvScaleHor[idx], dMvScaleVer[idx], mvShift);
1081
0
        dMvScaleHor[idx] = Clip3( -dmvLimit, dmvLimit, dMvScaleHor[idx] );
1082
0
        dMvScaleVer[idx] = Clip3( -dmvLimit, dmvLimit, dMvScaleVer[idx] );
1083
0
      }
1084
0
    }
1085
0
    else
1086
0
    {
1087
0
      int sz = blockWidth * blockHeight;
1088
0
      roundIntVector(dMvScaleHor, sz, mvShift, dmvLimit);
1089
0
      roundIntVector(dMvScaleVer, sz, mvShift, dmvLimit);
1090
0
    }
1091
0
  }
1092
  
1093
#if CALC_AFFINE_MV_ON_THE_FLY
1094
  int mvhor, mvver;
1095
1096
  if( subblkMVSpreadOverLimit )
1097
  {
1098
    mvhor = mvScaleHor + deltaMvHorX * ( width >> 1 ) + deltaMvVerX * ( height >> 1 );
1099
    mvver = mvScaleVer + deltaMvHorY * ( width >> 1 ) + deltaMvVerY * ( height >> 1 );
1100
    roundAffineMv( mvhor, mvver, shift );
1101
    mv.hor = mvhor; mv.ver = mvver;
1102
    mv.clipToStorageBitDepth();
1103
  }
1104
#endif
1105
1106
0
  std::array<const Pel*, 2> refBuf{ nullptr, nullptr };
1107
0
  std::array<ptrdiff_t, 2>  refBufStride{ 0, 0 };
1108
0
  if( cu.pps->getNumSubPics() > 1 && cu.pps->getSubPicFromCU( cu ).getTreatedAsPicFlag() )
1109
0
  {
1110
0
    const int subPicIdx = cu.pps->getSubPicFromCU( cu ).getSubPicIdx();
1111
0
    refBuf              = { refPic->getSubPicBufPtr   ( subPicIdx, compID, false ), 0 /*refPic->getSubPicBufPtr   ( subPicIdx, compID, true )*/ };
1112
0
    refBufStride        = { refPic->getSubPicBufStride( subPicIdx, compID, false ), 0 /*refPic->getSubPicBufStride( subPicIdx, compID, true )*/ };
1113
0
  }
1114
0
  else
1115
0
  {
1116
0
    if( cu.sps->getUseWrapAround() )
1117
0
    {
1118
0
      refBuf       = { refPic->getRecoBufPtr   ( compID, false ), refPic->getRecoBufPtr   ( compID, true ) };
1119
0
      refBufStride = { refPic->getRecoBufStride( compID, false ), refPic->getRecoBufStride( compID, true ) };
1120
0
    }
1121
0
    else
1122
0
    {
1123
0
      refBuf      [0] = refBuf      [1] = refPic->getRecoBufPtr   ( compID, false );
1124
0
      refBufStride[0] = refBufStride[1] = refPic->getRecoBufStride( compID, false );
1125
0
    }
1126
0
  }
1127
1128
0
  const int puPosX = cu.blocks[compID].x, puPosY = cu.blocks[compID].y;
1129
1130
  // get prediction block by block
1131
0
  for ( int h = 0; h < cxHeight; h += blockHeight )
1132
0
  {
1133
0
#if !CALC_AFFINE_MV_ON_THE_FLY
1134
0
    const MotionInfo* lineMi = curMi;
1135
1136
0
#endif
1137
0
    for ( int w = 0; w < cxWidth; w += blockWidth )
1138
0
    {
1139
0
      Position mvPos{ w >> 2, h >> 2 };
1140
      
1141
0
      int iMvScaleTmpHor;
1142
0
      int iMvScaleTmpVer;
1143
1144
0
      if( isLuma( compID ) || chFmt == CHROMA_444 )
1145
0
      {
1146
#if CALC_AFFINE_MV_ON_THE_FLY
1147
        if( !subblkMVSpreadOverLimit )
1148
        {
1149
          mvhor = mvScaleHor + deltaMvHorX * ( halfBW + w ) + deltaMvVerX * ( halfBH + h );
1150
          mvver = mvScaleVer + deltaMvHorY * ( halfBW + w ) + deltaMvVerY * ( halfBH + h );
1151
          roundAffineMv( mvhor, mvver, shift );
1152
          mv.hor = mvhor; mv.ver = mvver;
1153
          mv.clipToStorageBitDepth();
1154
        }
1155
#else   
1156
0
        const Mv& mv = lineMi->mv[refPicList];
1157
1158
0
        iMvScaleTmpHor = mv.hor;
1159
0
        iMvScaleTmpVer = mv.ver;
1160
0
#endif
1161
1162
0
        if( chFmt != CHROMA_400 && chFmt != CHROMA_444 && ( ( ( mvPos.x ^ mvPos.y ) & 1 ) == 0 || chFmt != CHROMA_420 ) )
1163
0
        {
1164
0
          Mv &chromaMv = *GET_OFFSET( chromaMvFld, MVBUFFER_SIZE, mvPos.x >> chromaScaleX, mvPos.y >> chromaScaleY );
1165
0
          chromaMv.hor += iMvScaleTmpHor;
1166
0
          chromaMv.ver += iMvScaleTmpVer;
1167
0
        }
1168
0
      }
1169
0
      else
1170
0
      {
1171
0
        Mv& mv = *GET_OFFSET( chromaMvFld, MVBUFFER_SIZE, mvPos.x, mvPos.y );
1172
0
        iMvScaleTmpHor = mv.hor *(1<< ( 1 - ( chromaScaleX | chromaScaleY ) ));
1173
0
        iMvScaleTmpVer = mv.ver *(1<< ( 1 - ( chromaScaleX | chromaScaleY ) ));
1174
0
        roundAffineMv( iMvScaleTmpHor, iMvScaleTmpVer, 1 );
1175
0
      }
1176
1177
0
      bool wrapRef = false;
1178
1179
0
      if ( refPic->isWrapAroundEnabled( cu.pps ) )
1180
0
      {
1181
0
        Mv tmpMv(iMvScaleTmpHor, iMvScaleTmpVer);
1182
0
        wrapRef = wrapClipMv( tmpMv, Position( cu.Y().x + ( w << iScaleX ), cu.Y().y + ( h << iScaleY ) ), Size( blockWidth << iScaleX, blockHeight << iScaleY ), sps, *cu.pps );
1183
0
        iMvScaleTmpHor = tmpMv.getHor();
1184
0
        iMvScaleTmpVer = tmpMv.getVer();
1185
0
      }
1186
0
      else if( !refPicScaled && clipSubPic )
1187
0
      {
1188
0
        Mv mv{ iMvScaleTmpHor, iMvScaleTmpVer };
1189
0
        clipMv( mv, cu.lumaPos(), cu.lumaSize(), sps, *cu.pps );
1190
0
        iMvScaleTmpHor = mv.hor;
1191
0
        iMvScaleTmpVer = mv.ver;
1192
0
      }
1193
0
      else
1194
0
      {
1195
0
        iMvScaleTmpHor = std::min<int>( iHorMax, std::max<int>( iHorMin, iMvScaleTmpHor ) );
1196
0
        iMvScaleTmpVer = std::min<int>( iVerMax, std::max<int>( iVerMin, iMvScaleTmpVer ) );
1197
0
      }
1198
1199
0
      CHECKD( !refPic, "Should not be null" );
1200
0
      if( refPicScaled )
1201
0
      {
1202
0
        xPredInterBlkRPR( scalingRatio, *cu.pps, compID, cu.chromaFormat, refPic, Mv( iMvScaleTmpHor, iMvScaleTmpVer ), cu.blocks[compID].offset( w, h ), blockWidth, blockHeight, dstPic.bufs[compID].buf + w + h * dstPic.bufs[compID].stride, dstPic.bufs[compID].stride, bi, wrapRef, clpRng, 2 );
1203
0
        CHECKD( enablePROF, "PROF should be disabled with RPR" );
1204
0
      }
1205
0
      else
1206
0
      {
1207
0
        const int xInt  = iMvScaleTmpHor >> shiftX;
1208
0
        const int xFrac = iMvScaleTmpHor &  maskX;
1209
0
        const int yInt  = iMvScaleTmpVer >> shiftY;
1210
0
        const int yFrac = iMvScaleTmpVer &  maskY;
1211
1212
0
        const Pel*      refBufPtr = refBuf      [wrapRef];
1213
0
        const ptrdiff_t refStride = refBufStride[wrapRef];
1214
0
        OFFSET( refBufPtr, refStride, puPosX + xInt + w, puPosY + yInt + h );
1215
1216
0
        Pel* dst;
1217
1218
0
        ptrdiff_t dstStride;
1219
1220
0
        if( enablePROF )
1221
0
        {
1222
0
          dst       = dstExtBuf.buf + 1 + dstExtBuf.stride;
1223
0
          dstStride = dstExtBuf.stride;
1224
0
        }
1225
0
        else
1226
0
        {
1227
0
          dst       = dstBuf.bufAt( w, h );
1228
0
          dstStride = dstBuf.stride;
1229
0
        }
1230
1231
0
        if( xFrac && yFrac )
1232
0
        {
1233
0
          m_if.filter4x4( compID, refBufPtr, refStride, dst, dstStride, 4, 4, xFrac, yFrac, isLast, chFmt, clpRng );
1234
0
        }
1235
0
        else if( yFrac == 0 )
1236
0
        {
1237
0
          m_if.filterHor( compID, refBufPtr, refStride, dst, dstStride, blockWidth, blockHeight, xFrac, isLast, chFmt, clpRng );
1238
0
        }
1239
0
        else// if( xFrac == 0 )
1240
0
        {
1241
0
          m_if.filterVer( compID, refBufPtr, refStride, dst, dstStride, blockWidth, blockHeight, yFrac, true, isLast, chFmt, clpRng );
1242
0
        }
1243
1244
0
        if( enablePROF )
1245
0
        {
1246
0
          const Pel shift   = std::max<int>( 2, ( IF_INTERNAL_PREC - clpRng.bd ) );
1247
0
          const int xOffset = xFrac >> 3;
1248
0
          const int yOffset = yFrac >> 3;
1249
1250
0
          CHECKD( shift < 0, "Shift need to be positive!" );
1251
0
          static_assert( PROF_BORDER_EXT_H == BIO_EXTEND_SIZE, "PROF and BIO extension need to be equal!" );
1252
0
          static_assert( PROF_BORDER_EXT_W == BIO_EXTEND_SIZE, "PROF and BIO extension need to be equal!" );
1253
1254
0
          const ptrdiff_t refOffset = ( blockHeight + 1 ) * refStride;
1255
0
          const ptrdiff_t dstOffset = ( blockHeight + 1 ) * dstStride;
1256
1257
0
          const Pel* refPel = refBufPtr - ( 1 - yOffset ) * refStride + xOffset - 1;
1258
0
                Pel* dstPel = dst - 1 - dstStride;
1259
1260
0
          PaddBIO( refPel,             dstPel,             blockWidth, shift );
1261
0
          PaddBIO( refPel + refOffset, dstPel + dstOffset, blockWidth, shift );
1262
1263
0
          refPel = refBufPtr + yOffset * refStride + xOffset;
1264
0
          dstPel = dst;
1265
0
          for( int ph = 0; ph < 4; ph++, refPel += refStride, dstPel += dstStride )
1266
0
          {
1267
0
            dstPel[        -1] = refPel[        -1] * ( 1 << shift ) - Pel( IF_INTERNAL_OFFS );
1268
0
            dstPel[blockWidth] = refPel[blockWidth] * ( 1 << shift ) - Pel( IF_INTERNAL_OFFS );
1269
0
          }
1270
1271
0
          profGradFilter( dst, dstStride, blockWidth, blockHeight, AFFINE_MIN_BLOCK_SIZE, gradX, gradY, clpRng.bd );
1272
1273
0
          Pel *dstY = dstBuf.buf + w + dstBuf.stride * h;
1274
0
          const Pel offset   = ( 1 << ( shift- 1 ) ) + IF_INTERNAL_OFFS;
1275
0
          applyPROF[bi]( dstY, dstBuf.stride, dst, gradX, gradY, dMvScaleHor, dMvScaleVer, shift, offset, clpRng );
1276
0
        }
1277
0
      }
1278
0
#if !CALC_AFFINE_MV_ON_THE_FLY
1279
1280
0
      INCX( lineMi, miStride );
1281
0
#endif
1282
0
    }
1283
0
#if !CALC_AFFINE_MV_ON_THE_FLY
1284
1285
0
    INCY( curMi, miStride );
1286
0
#endif
1287
0
  }
1288
0
}
1289
1290
void InterPrediction::applyBiOptFlow( const CodingUnit &cu,
1291
                                      const PelUnitBuf &    yuvSrc0,
1292
                                      const PelUnitBuf &    yuvSrc1,
1293
                                      const int &           refIdx0,
1294
                                      const int &           refIdx1,
1295
                                      PelUnitBuf &          yuvDst,
1296
                                      const BitDepths &     clipBitDepths )
1297
0
{
1298
0
  const int height  = yuvDst.Y().height;
1299
0
  const int width   = yuvDst.Y().width;
1300
0
  int       heightG = height + 2 * BIO_EXTEND_SIZE;
1301
0
  int       widthG  = width  + 2 * BIO_EXTEND_SIZE;
1302
1303
0
  Pel *gradX0 = m_gradX0;
1304
0
  Pel *gradX1 = m_gradX1;
1305
0
  Pel *gradY0 = m_gradY0;
1306
0
  Pel *gradY1 = m_gradY1;
1307
1308
0
  int        stridePredMC = width + BIO_ALIGN_SIZE;
1309
0
  const Pel *srcY0        = m_bdofBlock[0] + stridePredMC;
1310
0
  const Pel *srcY1        = m_bdofBlock[1] + stridePredMC;
1311
1312
0
  Pel *           dstY      = yuvDst.Y().buf;
1313
0
  const ptrdiff_t dstStride = yuvDst.Y().stride;
1314
1315
0
  const int       bitDepth  = clipBitDepths.recon;
1316
1317
0
  for( int refList = 0; refList < NUM_REF_PIC_LIST_01; refList++ )
1318
0
  {
1319
0
    Pel *dstTempPtr = m_bdofBlock[refList] + stridePredMC;
1320
0
    Pel *gradY      = ( refList == 0 ) ? m_gradY0 : m_gradY1;
1321
0
    Pel *gradX      = ( refList == 0 ) ? m_gradX0 : m_gradX1;
1322
0
    BioGradFilter( dstTempPtr, stridePredMC, widthG, heightG, width + BIO_ALIGN_SIZE, gradX, gradY, bitDepth );
1323
0
  }
1324
1325
0
  const ClpRng &clpRng   = cu.slice->clpRng( COMPONENT_Y );
1326
0
  const int     shiftNum = IF_INTERNAL_PREC + 1 - bitDepth;
1327
0
  const int     offset   = ( 1 << ( shiftNum - 1 ) ) + 2 * IF_INTERNAL_OFFS;
1328
0
  const int     limit    = ( 1 << 4 ) - 1;
1329
1330
1331
0
  BiOptFlow( srcY0,
1332
0
             srcY1,
1333
0
             gradX0,
1334
0
             gradX1,
1335
0
             gradY0,
1336
0
             gradY1,
1337
0
             width,
1338
0
             height,
1339
0
             dstY,
1340
0
             dstStride,
1341
0
             shiftNum,
1342
0
             offset,
1343
0
             limit,
1344
0
             clpRng,
1345
0
             bitDepth
1346
0
            );
1347
0
}
1348
1349
void InterPrediction::xWeightedAverage(const CodingUnit& cu, const PelUnitBuf& pcYuvSrc0, const PelUnitBuf& pcYuvSrc1, PelUnitBuf& pcYuvDst, const BitDepths& clipBitDepths, const ClpRngs& clpRngs, const bool& bioApplied )
1350
0
{
1351
0
  const int iRefIdx0 = cu.refIdx[0];
1352
0
  const int iRefIdx1 = cu.refIdx[1];
1353
1354
0
  CHECKD( !( iRefIdx0 >= 0 && iRefIdx1 >= 0 ), "xWeightedAverage should only be called for BI-predicted blocks!" );
1355
1356
0
  if( cu.BcwIdx() != BCW_DEFAULT && !cu.ciipFlag() )
1357
0
  {
1358
0
    CHECK( bioApplied, "Bcw is disallowed with BIO" );
1359
0
    pcYuvDst.addWeightedAvg( pcYuvSrc0, pcYuvSrc1, clpRngs, g_BcwInternBcw[cu.BcwIdx()] );
1360
0
    return;
1361
0
  }
1362
1363
0
  if( bioApplied )
1364
0
  {
1365
0
    applyBiOptFlow( cu, pcYuvSrc0, pcYuvSrc1, iRefIdx0, iRefIdx1, pcYuvDst, clipBitDepths );
1366
0
  }
1367
1368
0
  pcYuvDst.addAvg( pcYuvSrc0, pcYuvSrc1, clpRngs, bioApplied );
1369
0
}
1370
1371
1372
void InterPrediction::motionCompensation( CodingUnit &cu, PelUnitBuf &predBuf, const bool luma, const bool chroma )
1373
0
{
1374
0
  PROFILER_SCOPE_AND_STAGE_EXT( 1, g_timeProfiler, P_MOTCOMP, *cu.cs, luma ? CH_L: CH_C );
1375
0
  m_currCuArea = cu;
1376
1377
0
  if( cu.slice->getSliceType() != I_SLICE && cu.slice->getRefPic( REF_PIC_LIST_0, 0 )->subPictures.size() > 1 )
1378
0
  {
1379
0
    clipMv = clipMvInSubpic;
1380
0
  }
1381
0
  else
1382
0
  {
1383
0
    clipMv = clipMvInPic;
1384
0
  }
1385
1386
0
  if( CU::isIBC( cu ) )
1387
0
  {
1388
0
    CHECK( !luma, "IBC only for Chroma is not allowed." );
1389
0
    xIntraBlockCopy( cu, predBuf, COMPONENT_Y );
1390
0
    if( chroma )
1391
0
    {
1392
0
      xIntraBlockCopy( cu, predBuf, COMPONENT_Cb );
1393
0
      xIntraBlockCopy( cu, predBuf, COMPONENT_Cr );
1394
0
    }
1395
0
    return;
1396
0
  }
1397
1398
  // else, go with regular MC below
1399
0
  const PPS &pps            = *cu.pps;
1400
1401
0
  CHECKD( !cu.affineFlag() && cu.refIdx[0] >= 0 && cu.refIdx[1] >= 0 && ( cu.lwidth() + cu.lheight() == 12 ), "invalid 4x8/8x4 bi-predicted blocks" );
1402
0
  const WPScalingParam* wp0 = nullptr;
1403
0
  const WPScalingParam* wp1 = nullptr;
1404
0
  int refIdx0 = cu.refIdx[REF_PIC_LIST_0];
1405
0
  int refIdx1 = cu.refIdx[REF_PIC_LIST_1];
1406
0
  cu.slice->getWpScaling( REF_PIC_LIST_0, refIdx0, wp0 );
1407
0
  cu.slice->getWpScaling( REF_PIC_LIST_1, refIdx1, wp1 );
1408
0
  bool bioApplied    = false;
1409
0
  const Slice &slice = *cu.slice;
1410
1411
0
  if( cu.sps->getUseBIO() && ( !cu.cs->picHeader->getDisBdofFlag() ) )
1412
0
  {
1413
1414
0
    if( cu.affineFlag() || m_subPuMC || cu.ciipFlag() || cu.smvdMode() || ( cu.sps->getUseBcw() && cu.BcwIdx() != BCW_DEFAULT ) )
1415
0
    {
1416
0
      bioApplied = false;
1417
0
    }
1418
0
    else
1419
0
    {
1420
0
      const bool biocheck0 = !((wp0[COMPONENT_Y].bPresentFlag || wp0[COMPONENT_Cb].bPresentFlag || wp0[COMPONENT_Cr].bPresentFlag || wp1[COMPONENT_Y].bPresentFlag || wp1[COMPONENT_Cb].bPresentFlag || wp1[COMPONENT_Cr].bPresentFlag) && slice.getSliceType() == B_SLICE);
1421
0
      const bool biocheck1 = !( pps.getUseWP() && slice.getSliceType() == P_SLICE );
1422
1423
0
      if( biocheck0 && biocheck1 && PU::isBiPredFromDifferentDirEqDistPoc( cu ) && cu.Y().height >= 8 && cu.Y().width >= 8 && cu.Y().area() >= 128 )
1424
0
      {
1425
0
        bioApplied = true;
1426
0
      }
1427
0
    }
1428
0
  }
1429
    
1430
0
  bool dmvrApplied = !m_subPuMC && PU::checkDMVRCondition( cu );
1431
0
  bool refIsScaled = ( refIdx0 < 0 ? false : cu.slice->getRefPic( REF_PIC_LIST_0, refIdx0 )->isRefScaled( cu.pps ) ) ||
1432
0
                     ( refIdx1 < 0 ? false : cu.slice->getRefPic( REF_PIC_LIST_1, refIdx1 )->isRefScaled( cu.pps ) );
1433
1434
0
  dmvrApplied = dmvrApplied && !refIsScaled;
1435
0
  bioApplied  = bioApplied  && !refIsScaled;
1436
1437
0
  if( cu.mergeType() != MRG_TYPE_SUBPU_ATMVP && bioApplied && !dmvrApplied )
1438
0
  {
1439
0
    xSubPuBio( cu, predBuf );
1440
0
  }
1441
0
  else if( dmvrApplied )
1442
0
  {
1443
0
    cu.setDmvrCondition( true );
1444
0
    xProcessDMVR( cu, predBuf, slice.clpRngs(), bioApplied );
1445
0
  }
1446
0
  else if( cu.mergeType() == MRG_TYPE_SUBPU_ATMVP )
1447
0
  {
1448
0
    xSubPuMC( cu, predBuf );
1449
0
  }
1450
0
  else if( xCheckIdenticalMotion( cu ) )
1451
0
  {
1452
0
    xPredInterUni( cu, REF_PIC_LIST_0, predBuf, false, false , true, true );
1453
0
  }
1454
0
  else
1455
0
  {
1456
0
    CHECKD( bioApplied, "BIO should not be applied here!" );
1457
0
    xPredInterBi( cu, predBuf );
1458
0
  }
1459
0
}
1460
1461
void InterPrediction::motionCompensationGeo( CodingUnit &cu, PelUnitBuf &predBuf )
1462
0
{
1463
0
  PROFILER_SCOPE_AND_STAGE_EXT( 1, g_timeProfiler, P_MOTCOMP, *cu.cs, CH_L );
1464
1465
0
  if( cu.slice->getSliceType() != I_SLICE && cu.slice->getRefPic( REF_PIC_LIST_0, 0 )->subPictures.size() > 1 )
1466
0
  {
1467
0
    clipMv = clipMvInSubpic;
1468
0
  }
1469
0
  else
1470
0
  {
1471
0
    clipMv = clipMvInPic;
1472
0
  }
1473
1474
0
  const UnitArea localUnitArea( cu.cs->area.chromaFormat, Area( 0, 0, cu.lwidth(), cu.lheight() ) );
1475
1476
0
  PelUnitBuf tmpGeoBuf0 = isChromaEnabled( cu.chromaFormat ) ? PelUnitBuf( cu.chromaFormat, PelBuf( m_acYuvPred[0], localUnitArea.Y() ), PelBuf( m_acYuvPred[1], localUnitArea.Cb() ), PelBuf( m_acYuvPred[2], localUnitArea.Cr() ) ) : PelUnitBuf( cu.chromaFormat, PelBuf( m_acYuvPred[0], localUnitArea.Y() ) );
1477
1478
0
  uint8_t locInterDir = cu.interDirrefIdxGeo0() >> 4;
1479
0
  CHECKD( !( locInterDir == 1 || locInterDir == 2 ), "Should not happen" );
1480
0
  cu.mv  [REF_PIC_LIST_0][0] = locInterDir == 1 ? cu.mv[0][1] : Mv();
1481
0
  cu.mv  [REF_PIC_LIST_1][0] = locInterDir == 1 ? Mv() : cu.mv[0][1];
1482
0
  cu.refIdx [REF_PIC_LIST_0] = locInterDir == 1 ? cu.interDirrefIdxGeo0() & 15 : -1;
1483
0
  cu.refIdx [REF_PIC_LIST_1] = locInterDir == 1 ? -1 : cu.interDirrefIdxGeo0() & 15;
1484
0
  cu.mvpIdx [REF_PIC_LIST_0] = NOT_VALID;
1485
0
  cu.mvpIdx [REF_PIC_LIST_1] = NOT_VALID;
1486
0
  motionCompensation( cu, tmpGeoBuf0, true, isChromaEnabled( cu.chromaFormat ) );
1487
1488
0
  locInterDir = cu.interDirrefIdxGeo1() >> 4;
1489
0
  CHECKD( !( locInterDir == 1 || locInterDir == 2 ), "Should not happen" );
1490
0
  cu.mv  [REF_PIC_LIST_0][0] = locInterDir == 1 ? cu.mv[1][1] : Mv();
1491
0
  cu.mv  [REF_PIC_LIST_1][0] = locInterDir == 1 ? Mv() : cu.mv[1][1];
1492
0
  cu.refIdx [REF_PIC_LIST_0] = locInterDir == 1 ? cu.interDirrefIdxGeo1() & 15 : -1;
1493
0
  cu.refIdx [REF_PIC_LIST_1] = locInterDir == 1 ? -1 : cu.interDirrefIdxGeo1() & 15;
1494
0
  cu.mvpIdx [REF_PIC_LIST_0] = NOT_VALID;
1495
0
  cu.mvpIdx [REF_PIC_LIST_1] = NOT_VALID;
1496
0
  motionCompensation( cu, predBuf, true, isChromaEnabled( cu.chromaFormat ) );
1497
1498
0
  const uint8_t splitDir = cu.geoSplitDir;
1499
0
  weightedGeoBlk( cu, splitDir, isChromaEnabled( cu.chromaFormat ) ? MAX_NUM_CHANNEL_TYPE : CHANNEL_TYPE_LUMA, predBuf, tmpGeoBuf0, predBuf );
1500
0
}
1501
1502
void InterPrediction::weightedGeoBlk( CodingUnit &cu, const uint8_t splitDir, int32_t channel, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1)
1503
0
{
1504
0
  if( channel == CHANNEL_TYPE_LUMA )
1505
0
  {
1506
0
    m_if.weightedGeoBlk( cu, cu.lumaSize().width, cu.lumaSize().height, COMPONENT_Y, splitDir, predDst, predSrc0, predSrc1, cu.slice->clpRngs() );
1507
0
  }
1508
0
  else if( channel == CHANNEL_TYPE_CHROMA )
1509
0
  {
1510
0
    m_if.weightedGeoBlk( cu, cu.chromaSize().width, cu.chromaSize().height, COMPONENT_Cb, splitDir, predDst, predSrc0, predSrc1, cu.slice->clpRngs() );
1511
0
    m_if.weightedGeoBlk( cu, cu.chromaSize().width, cu.chromaSize().height, COMPONENT_Cr, splitDir, predDst, predSrc0, predSrc1, cu.slice->clpRngs() );
1512
0
  }
1513
0
  else
1514
0
  {
1515
0
    m_if.weightedGeoBlk( cu, cu.lumaSize().width,   cu.lumaSize().height,   COMPONENT_Y,  splitDir, predDst, predSrc0, predSrc1, cu.slice->clpRngs() );
1516
0
    if( isChromaEnabled( cu.chromaFormat ) )
1517
0
    {
1518
0
      m_if.weightedGeoBlk( cu, cu.chromaSize().width, cu.chromaSize().height, COMPONENT_Cb, splitDir, predDst, predSrc0, predSrc1, cu.slice->clpRngs() );
1519
0
      m_if.weightedGeoBlk( cu, cu.chromaSize().width, cu.chromaSize().height, COMPONENT_Cr, splitDir, predDst, predSrc0, predSrc1, cu.slice->clpRngs() );
1520
0
    }
1521
0
  }
1522
0
}
1523
1524
1525
void InterPrediction::xPrefetchPad( CodingUnit& cu, PelUnitBuf &pcPad, RefPicList refId, bool forLuma )
1526
0
{
1527
0
  int width, height;
1528
0
  Mv cMv;
1529
1530
0
  const Picture* refPic = cu.slice->getRefPic( refId, cu.refIdx[refId] );
1531
1532
0
  static constexpr int mvShift = MV_FRACTIONAL_BITS_INTERNAL;
1533
1534
0
  const bool wrapRefEnbld = refPic->isWrapAroundEnabled( cu.pps );
1535
0
  const bool subPicAsPic  = cu.pps->getNumSubPics() > 1 && cu.pps->getSubPicFromCU( cu ).getTreatedAsPicFlag();
1536
1537
0
  const ChannelType chType = forLuma ? CHANNEL_TYPE_LUMA : CHANNEL_TYPE_CHROMA;
1538
1539
0
  int filtersize = isLuma( chType ) ? NTAPS_LUMA : NTAPS_CHROMA;
1540
0
  cMv = cu.mv[refId][0];
1541
  
1542
0
  const int mvshiftTempHor        = mvShift + getChannelTypeScaleX( chType, cu.chromaFormat );
1543
0
  const int mvshiftTempVer        = mvShift + getChannelTypeScaleY( chType, cu.chromaFormat );
1544
0
  cMv                      += Mv( -( ( ( filtersize >> 1 ) - 1 ) << mvshiftTempHor ),
1545
0
                                  -( ( ( filtersize >> 1 ) - 1 ) << mvshiftTempVer ) );
1546
0
  bool wrapRef = false;
1547
1548
0
  if( wrapRefEnbld )
1549
0
  {
1550
0
    wrapRef = wrapClipMv( cMv, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1551
0
  }
1552
0
  else
1553
0
  {
1554
0
    clipMv( cMv, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1555
0
  }
1556
1557
0
  cMv.hor >>= mvshiftTempHor;
1558
0
  cMv.ver >>= mvshiftTempVer;
1559
1560
0
  if( isLuma( chType ) )
1561
0
  {
1562
0
    pcPad.bufs[COMPONENT_Y]
1563
0
      .stride  = pcPad.bufs[COMPONENT_Y].width + ( 2 * DMVR_NUM_ITERATION ) + filtersize;
1564
0
    width      = pcPad.bufs[COMPONENT_Y].width;
1565
0
    height     = pcPad.bufs[COMPONENT_Y].height;
1566
0
    ptrdiff_t
1567
0
      offset   = DMVR_NUM_ITERATION * ( pcPad.bufs[COMPONENT_Y].stride + 1 );
1568
1569
0
    width      += filtersize - 1;
1570
0
    height     += filtersize - 1;
1571
1572
0
    CPelBuf refBuf = subPicAsPic ? refPic->getSubPicBuf( cu.pps->getSubPicFromCU( cu ).getSubPicIdx(), COMPONENT_Y, wrapRef ) : refPic->getRecoBuf( COMPONENT_Y, wrapRef );
1573
1574
0
    Position   Rec_offset = cu.lumaPos().offset( cMv.hor, cMv.ver );
1575
0
    const Pel* refBufPtr  = refBuf.bufAt( Rec_offset );
1576
1577
0
    PelBuf& dstBuf = pcPad.Y();
1578
0
    prefetchPad[0]( refBufPtr, refBuf.stride, dstBuf.buf + offset, dstBuf.stride, width, height );
1579
0
  }
1580
0
  else
1581
0
  {
1582
0
    pcPad.bufs[COMPONENT_Cb]
1583
0
      .stride  = pcPad.bufs[COMPONENT_Cb].width + ( 2 * DMVR_NUM_ITERATION ) + filtersize;
1584
0
    pcPad.bufs[COMPONENT_Cr]
1585
0
      .stride  = pcPad.bufs[COMPONENT_Cb].stride;
1586
0
    width      = pcPad.bufs[COMPONENT_Cb].width;
1587
0
    height     = pcPad.bufs[COMPONENT_Cb].height;
1588
0
    ptrdiff_t
1589
0
      offsetCb = DMVR_NUM_ITERATION * ( pcPad.bufs[COMPONENT_Cb].stride + 1 );
1590
0
    ptrdiff_t
1591
0
      offsetCr = DMVR_NUM_ITERATION * ( pcPad.bufs[COMPONENT_Cr].stride + 1 );
1592
1593
0
    width      += filtersize - 1;
1594
0
    height     += filtersize - 1;
1595
1596
0
    CPelBuf refBufCb = subPicAsPic ? refPic->getSubPicBuf( cu.pps->getSubPicFromCU( cu ).getSubPicIdx(), COMPONENT_Cb, wrapRef ) : refPic->getRecoBuf( COMPONENT_Cb, wrapRef );
1597
0
    CPelBuf refBufCr = subPicAsPic ? refPic->getSubPicBuf( cu.pps->getSubPicFromCU( cu ).getSubPicIdx(), COMPONENT_Cr, wrapRef ) : refPic->getRecoBuf( COMPONENT_Cr, wrapRef );
1598
1599
0
    Position   Rec_offset     = cu.blocks[COMPONENT_Cb].pos().offset( cMv.hor, cMv.ver );
1600
0
    const Pel* refBufPtr  [2] = { refBufCb.bufAt( Rec_offset ), refBufCr.bufAt( Rec_offset ) };
1601
0
    const ptrdiff_t stride[2] = { refBufCb.stride, refBufCr.stride };
1602
0
          Pel* dstBufPtr  [2] = { pcPad.Cb().buf + offsetCb, pcPad.Cr().buf + offsetCr };
1603
0
    const ptrdiff_t dstStr[2] = { pcPad.Cb().stride, pcPad.Cr().stride };
1604
1605
0
    const int idx = getChannelTypeScaleY( CH_C, cu.chromaFormat );
1606
1607
0
    prefetchPad[1+idx]( refBufPtr[0], stride[0], dstBufPtr[0], dstStr[0], width, height );
1608
0
    prefetchPad[1+idx]( refBufPtr[1], stride[1], dstBufPtr[1], dstStr[1], width, height );
1609
0
  }
1610
0
}
1611
1612
inline int32_t div_for_maxq7(int64_t N, int64_t D)
1613
0
{
1614
0
  int32_t sign, q;
1615
0
  sign = 0;
1616
0
  if (N < 0)
1617
0
  {
1618
0
    sign = 1;
1619
0
    N = -N;
1620
0
  }
1621
1622
0
  q = 0;
1623
0
  D = (D << 3);
1624
0
  if (N >= D)
1625
0
  {
1626
0
    N -= D;
1627
0
    q++;
1628
0
  }
1629
0
  q = (q << 1);
1630
1631
0
  D = (D >> 1);
1632
0
  if (N >= D)
1633
0
  {
1634
0
    N -= D;
1635
0
    q++;
1636
0
  }
1637
0
  q = (q << 1);
1638
1639
0
  if (N >= (D >> 1))
1640
0
    q++;
1641
1642
0
  if (sign)
1643
0
    return (-q);
1644
0
  return(q);
1645
0
}
1646
1647
void xSubPelErrorSrfc(uint64_t *sadBuffer, int32_t *deltaMv)
1648
0
{
1649
0
  int64_t numerator, denominator;
1650
0
  int32_t mvDeltaSubPel;
1651
0
  int32_t mvSubPelLvl = 4;/*1: half pel, 2: Qpel, 3:1/8, 4: 1/16*/
1652
                                                        /*horizontal*/
1653
0
    numerator = (int64_t)(sadBuffer[1] - sadBuffer[3]) * (int64_t(1) << mvSubPelLvl);
1654
0
    denominator = (int64_t)((sadBuffer[1] + sadBuffer[3] - (sadBuffer[0] << 1)));
1655
1656
0
    if (0 != denominator)
1657
0
    {
1658
0
      if ((sadBuffer[1] != sadBuffer[0]) && (sadBuffer[3] != sadBuffer[0]))
1659
0
      {
1660
0
        mvDeltaSubPel = div_for_maxq7(numerator, denominator);
1661
0
        deltaMv[0] = (mvDeltaSubPel);
1662
0
      }
1663
0
      else
1664
0
      {
1665
0
        if (sadBuffer[1] == sadBuffer[0])
1666
0
        {
1667
0
          deltaMv[0] = -8;// half pel
1668
0
        }
1669
0
        else
1670
0
        {
1671
0
          deltaMv[0] = 8;// half pel
1672
0
        }
1673
0
      }
1674
0
    }
1675
1676
    /*vertical*/
1677
0
    numerator = (int64_t)((sadBuffer[2] - sadBuffer[4]) << mvSubPelLvl);
1678
0
    denominator = (int64_t)((sadBuffer[2] + sadBuffer[4] - (sadBuffer[0] << 1)));
1679
0
    if (0 != denominator)
1680
0
    {
1681
0
      if ((sadBuffer[2] != sadBuffer[0]) && (sadBuffer[4] != sadBuffer[0]))
1682
0
      {
1683
0
        mvDeltaSubPel = div_for_maxq7(numerator, denominator);
1684
0
        deltaMv[1] = (mvDeltaSubPel);
1685
0
      }
1686
0
      else
1687
0
      {
1688
0
        if (sadBuffer[2] == sadBuffer[0])
1689
0
        {
1690
0
          deltaMv[1] = -8;// half pel
1691
0
        }
1692
0
        else
1693
0
        {
1694
0
          deltaMv[1] = 8;// half pel
1695
0
        }
1696
0
      }
1697
0
    }
1698
1699
0
  return;
1700
0
}
1701
1702
void InterPrediction::xBIPMVRefine( DistParam &cDistParam, const Pel *pRefL0, const Pel *pRefL1, Distortion& minCost, int16_t *deltaMV, Distortion *pSADsArray)
1703
0
{
1704
0
  const ptrdiff_t refStride = m_biLinearBufStride;
1705
1706
0
  const Pel *pRefL0Orig = pRefL0;
1707
0
  const Pel *pRefL1Orig = pRefL1;
1708
1709
0
  for (int ver = -2; ver <= 2; ver++) {
1710
0
    const int initHor = -2;
1711
0
    const ptrdiff_t offset = initHor + ver * refStride;
1712
0
    pRefL0 = pRefL0Orig + offset;
1713
0
    pRefL1 = pRefL1Orig - offset;
1714
0
    cDistParam.org.buf = pRefL0;
1715
0
    cDistParam.cur.buf = pRefL1;
1716
1717
0
    cDistParam.distFuncX5(cDistParam, pSADsArray, ver != 0);
1718
1719
0
    for (int hor = -2; hor <= 2; hor++, pSADsArray++) {
1720
0
      Distortion cost = *pSADsArray;
1721
1722
0
      if (cost < minCost) {
1723
0
        minCost = cost;
1724
0
        deltaMV[0] = hor;
1725
0
        deltaMV[1] = ver;
1726
0
      }
1727
0
    }
1728
0
  }
1729
0
}
1730
1731
void InterPrediction::xFinalPaddedMCForDMVR(CodingUnit& cu, PelUnitBuf &pcYuvSrc0, PelUnitBuf &pcYuvSrc1, PelUnitBuf &pcPad0, PelUnitBuf &pcPad1, const bool bioApplied, const Mv mergeMV[NUM_REF_PIC_LIST_01] )
1732
0
{
1733
0
  ptrdiff_t offset;
1734
0
  int deltaIntMvX, deltaIntMvY;
1735
1736
  /*always high precision MVs are used*/
1737
0
  const int mvShift      = MV_FRACTIONAL_BITS_INTERNAL;
1738
0
  const ClpRngs clp      = cu.slice->clpRngs();
1739
0
  const int numValidComp = getNumberValidComponents( cu.chromaFormat );
1740
1741
0
  for (int k = 0; k < NUM_REF_PIC_LIST_01; k++)
1742
0
  {
1743
0
    PelUnitBuf &pcYUVTemp = k == 0 ? pcYuvSrc0 : pcYuvSrc1;
1744
0
    PelUnitBuf &pcPadTemp = k == 0 ? pcPad0    : pcPad1;
1745
1746
0
    RefPicList refId = (RefPicList)k;
1747
0
    Mv cMv = cu.mv[refId][0];
1748
0
    m_iRefListIdx = refId;
1749
0
    const Picture* refPic = cu.slice->getRefPic( refId, cu.refIdx[refId] );
1750
0
    Mv cMvClipped( cMv );
1751
0
    clipMv( cMvClipped, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1752
0
    const bool wrapRef = cu.pps->getUseWrapAround() && wrapClipMv( cMvClipped, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1753
1754
0
    Mv startMv = mergeMV[refId];
1755
1756
0
    for( int compID = 0; compID < numValidComp; compID++ )
1757
0
    {
1758
0
      const int mvshiftTempHor = mvShift + getComponentScaleX( (ComponentID)compID, cu.chromaFormat );
1759
0
      const int mvshiftTempVer = mvShift + getComponentScaleY( (ComponentID)compID, cu.chromaFormat );
1760
0
      deltaIntMvX = ( cMv.getHor() >> mvshiftTempHor ) - ( startMv.getHor() >> mvshiftTempHor );
1761
0
      deltaIntMvY = ( cMv.getVer() >> mvshiftTempVer ) - ( startMv.getVer() >> mvshiftTempVer );
1762
1763
0
      if( deltaIntMvX || deltaIntMvY )
1764
0
      {
1765
0
        ptrdiff_t pcPadstride       = pcPadTemp.bufs[compID].stride;
1766
0
        const int leftPixelExtra    = compID == COMPONENT_Y ? ( NTAPS_LUMA >> 1 ) - 1 : ( NTAPS_CHROMA >> 1 ) - 1;
1767
1768
0
        CHECKD( ( abs( deltaIntMvX ) > DMVR_NUM_ITERATION ) || ( abs( deltaIntMvY ) > DMVR_NUM_ITERATION ), "not expected DMVR movement" );
1769
1770
0
        offset  = ( DMVR_NUM_ITERATION + leftPixelExtra ) * ( pcPadstride + 1 );
1771
0
        offset += ( deltaIntMvY ) * pcPadstride;
1772
0
        offset += ( deltaIntMvX );
1773
0
        Pel *srcBufPelPtr = pcPadTemp.bufs[compID].buf + offset;
1774
1775
0
        xPredInterBlk<true , false>( ComponentID( compID ), cu, refPic, cMvClipped, pcYUVTemp.bufs[compID], true, clp, bioApplied, false, wrapRef, 0, 0, 0, srcBufPelPtr, pcPadstride );
1776
0
      }
1777
0
      else
1778
0
      {
1779
0
        xPredInterBlk<false, false>( ComponentID( compID ), cu, refPic, cMvClipped, pcYUVTemp.bufs[compID], true, clp, bioApplied, false, wrapRef, 0, 0, 0 );
1780
0
      }
1781
0
    }
1782
0
  }
1783
0
}
1784
1785
void xDMVRSubPixelErrorSurface( int16_t *totalDeltaMV, int16_t *deltaMV, Distortion*pSADsArray )
1786
0
{
1787
0
  static constexpr int sadStride = ( ( ( 2 * DMVR_NUM_ITERATION ) + 1 ) );
1788
0
  uint64_t sadbuffer[5];
1789
1790
0
  if( abs( totalDeltaMV[0] ) != ( 2 << MV_FRACTIONAL_BITS_INTERNAL ) && abs( totalDeltaMV[1] ) != ( 2 << MV_FRACTIONAL_BITS_INTERNAL ) )
1791
0
  {
1792
0
    int32_t tempDeltaMv[2] = { 0,0 };
1793
0
    sadbuffer[0] = pSADsArray[0];
1794
0
    sadbuffer[1] = pSADsArray[-1];
1795
0
    sadbuffer[2] = pSADsArray[-sadStride];
1796
0
    sadbuffer[3] = pSADsArray[1];
1797
0
    sadbuffer[4] = pSADsArray[sadStride];
1798
0
    xSubPelErrorSrfc(sadbuffer, tempDeltaMv);
1799
0
    totalDeltaMV[0] += tempDeltaMv[0];
1800
0
    totalDeltaMV[1] += tempDeltaMv[1];
1801
0
  }
1802
0
}
1803
1804
void InterPrediction::xinitMC( CodingUnit& cu, const ClpRngs &clpRngs )
1805
0
{
1806
  /*use merge MV as starting MV*/
1807
0
  Mv mergeMVL0(cu.mv[REF_PIC_LIST_0][0]);
1808
0
  Mv mergeMVL1(cu.mv[REF_PIC_LIST_1][0]);
1809
1810
  /*Clip the starting MVs*/
1811
0
  clipMv( mergeMVL0, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1812
0
  clipMv( mergeMVL1, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1813
1814
0
  const bool wrapRefL0 = cu.pps->getUseWrapAround() && wrapClipMv( mergeMVL0, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1815
0
  const bool wrapRefL1 = cu.pps->getUseWrapAround() && wrapClipMv( mergeMVL1, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1816
1817
0
  static constexpr int sizeExt = DMVR_NUM_ITERATION << 1;
1818
1819
0
  const int extWidth  = cu.lwidth()  + sizeExt;
1820
0
  const int extHeight = cu.lheight() + sizeExt;
1821
1822
  /*L0 MC for refinement*/
1823
0
  {
1824
0
    const Picture* refPic = cu.slice->getRefPic( L0, cu.refIdx[L0] );
1825
1826
0
    PelBuf yuvPredTempL0( m_cYuvPredTempDMVRL0, m_biLinearBufStride, extWidth, extHeight );
1827
1828
0
    mergeMVL0.hor -= ( DMVR_NUM_ITERATION << MV_FRACTIONAL_BITS_INTERNAL );
1829
0
    mergeMVL0.ver -= ( DMVR_NUM_ITERATION << MV_FRACTIONAL_BITS_INTERNAL );
1830
1831
0
    xPredInterBlk<false, true>( COMPONENT_Y, cu, refPic, mergeMVL0, yuvPredTempL0, true, clpRngs, false, false, wrapRefL0, extWidth, extHeight, true );
1832
0
  }
1833
1834
  /*L1 MC for refinement*/
1835
0
  {
1836
0
    const Picture* refPic = cu.slice->getRefPic( L1, cu.refIdx[L1] );
1837
1838
0
    PelBuf yuvPredTempL1( m_cYuvPredTempDMVRL1, m_biLinearBufStride, extWidth, extHeight );
1839
1840
0
    mergeMVL1.hor -= ( DMVR_NUM_ITERATION << MV_FRACTIONAL_BITS_INTERNAL );
1841
0
    mergeMVL1.ver -= ( DMVR_NUM_ITERATION << MV_FRACTIONAL_BITS_INTERNAL );
1842
1843
0
    xPredInterBlk<false, true>( COMPONENT_Y, cu, refPic, mergeMVL1, yuvPredTempL1, true, clpRngs, false, false, wrapRefL1, extWidth, extHeight, true );
1844
0
  }
1845
0
}
1846
1847
void InterPrediction::xProcessDMVR( CodingUnit& cu, PelUnitBuf &pcYuvDst, const ClpRngs &clpRngs, const bool bioApplied )
1848
0
{
1849
  /*Always High Precision*/
1850
0
  static constexpr int mvShift  = MV_FRACTIONAL_BITS_INTERNAL;
1851
0
         const     int mvShiftX = mvShift + getChannelTypeScaleX( CH_C, cu.chromaFormat );
1852
0
         const     int mvShiftY = mvShift + getChannelTypeScaleY( CH_C, cu.chromaFormat );
1853
1854
  /*use merge MV as starting MV*/
1855
0
  Mv mergeMv[] = { cu.mv[REF_PIC_LIST_0][0] , cu.mv[REF_PIC_LIST_1][0] };
1856
1857
0
  m_biLinearBufStride = ( cu.lwidth() + ( 2 * DMVR_NUM_ITERATION ) );
1858
1859
0
  xinitMC( cu, clpRngs );
1860
1861
0
  int dy = std::min<int>( cu.lumaSize().height, DMVR_SUBCU_HEIGHT );
1862
0
  int dx = std::min<int>( cu.lumaSize().width,  DMVR_SUBCU_WIDTH );
1863
1864
0
  Position puPos = cu.lumaPos();
1865
0
  BitDepths bds  = cu.sps->getBitDepths();
1866
1867
0
  int  bioEnabledThres = ( 2 * dy * dx );
1868
0
  bool bioAppliedSubblk;
1869
0
  {
1870
0
    int num = 0;
1871
    
1872
0
    int scaleX = getComponentScaleX( COMPONENT_Cb, cu.chromaFormat );
1873
0
    int scaleY = getComponentScaleY( COMPONENT_Cb, cu.chromaFormat );
1874
    // point mc buffer to cetre point to avoid multiplication to reach each iteration to the begining
1875
0
    Pel *biLinearPredL0 = m_cYuvPredTempDMVRL0 + ( DMVR_NUM_ITERATION * m_biLinearBufStride ) + DMVR_NUM_ITERATION;
1876
0
    Pel *biLinearPredL1 = m_cYuvPredTempDMVRL1 + ( DMVR_NUM_ITERATION * m_biLinearBufStride ) + DMVR_NUM_ITERATION;
1877
    
1878
0
    CodingUnit      subCu;
1879
0
    CodingUnit& subPu = subCu;
1880
1881
0
    subPu                   = cu;
1882
0
    subPu.UnitArea::operator=( UnitArea( cu.chromaFormat, Area( puPos.x, puPos.y, dx, dy ) ) );
1883
1884
0
    PelUnitBuf cYuvRefBuffDMVRL0 = isChromaEnabled( cu.chromaFormat ) ? PelUnitBuf( cu.chromaFormat, PelBuf( m_cRefSamplesDMVRL0[0], subPu.Y() ), PelBuf( m_cRefSamplesDMVRL0[1], subPu.Cb() ), PelBuf( m_cRefSamplesDMVRL0[2], subPu.Cr() ) ) : PelUnitBuf( cu.chromaFormat, PelBuf( m_cRefSamplesDMVRL0[0], subPu.Y() ) );
1885
0
    PelUnitBuf cYuvRefBuffDMVRL1 = isChromaEnabled( cu.chromaFormat ) ? PelUnitBuf( cu.chromaFormat, PelBuf( m_cRefSamplesDMVRL1[0], subPu.Y() ), PelBuf( m_cRefSamplesDMVRL1[1], subPu.Cb() ), PelBuf( m_cRefSamplesDMVRL1[2], subPu.Cr() ) ) : PelUnitBuf( cu.chromaFormat, PelBuf( m_cRefSamplesDMVRL1[0], subPu.Y() ) );
1886
1887
0
    PelUnitBuf srcPred1 = isChromaEnabled( cu.chromaFormat ) ? PelUnitBuf( cu.chromaFormat, PelBuf( m_acYuvPred[0], subPu.Y() ), PelBuf( m_acYuvPred[1], subPu.Cb() ), PelBuf( m_acYuvPred[2], subPu.Cr() ) ) : PelUnitBuf( cu.chromaFormat, PelBuf( m_acYuvPred[0], subPu.Y() ) );
1888
1889
0
    DistParam cDistParam;
1890
0
    m_pcRdCost->setDistParam( cDistParam, nullptr, nullptr, m_biLinearBufStride, m_biLinearBufStride, clpRngs.bd, dx, dy, 1 );
1891
    
1892
0
    PelUnitBuf subPredBuf = pcYuvDst.subBuf( UnitAreaRelative( cu, subPu ) );
1893
0
    const ptrdiff_t dstStride[MAX_NUM_COMPONENT] = { pcYuvDst.bufs[COMPONENT_Y].stride,
1894
0
                                                     isChromaEnabled(cu.chromaFormat) ? pcYuvDst.bufs[COMPONENT_Cb].stride : 0,
1895
0
                                                     isChromaEnabled(cu.chromaFormat) ? pcYuvDst.bufs[COMPONENT_Cr].stride : 0};
1896
0
    for( int y = puPos.y, yStart = 0; y < ( puPos.y + cu.lumaSize().height ); y = y + dy, yStart = yStart + dy )
1897
0
    {
1898
0
      for( int x = puPos.x, xStart = 0; x < ( puPos.x + cu.lumaSize().width ); x = x + dx, xStart = xStart + dx )
1899
0
      {
1900
0
        subPu.mv[0][0]    = cu.mv[0][0]; subPu.mv[1][0]    = cu.mv[1][0];
1901
0
        subPu.blocks[0].x = x;           subPu.blocks[0].y = y;
1902
0
        if( isChromaEnabled( subPu.chromaFormat ) )
1903
0
        {
1904
0
          subPu.blocks[1].x = x >> scaleX; subPu.blocks[1].y = y >> scaleY;
1905
0
          subPu.blocks[2].x = x >> scaleX; subPu.blocks[2].y = y >> scaleY;
1906
0
        }
1907
1908
0
        subPredBuf.bufs[COMPONENT_Y].buf    = pcYuvDst.bufs[COMPONENT_Y].buf  +   xStart +                 yStart             * dstStride[COMPONENT_Y];
1909
1910
0
        if( isChromaEnabled( cu.chromaFormat ) )
1911
0
        {
1912
0
          subPredBuf.bufs[COMPONENT_Cb].buf = pcYuvDst.bufs[COMPONENT_Cb].buf + ( xStart >> scaleX ) + ( ( yStart >> scaleY ) * dstStride[COMPONENT_Cb] );
1913
0
          subPredBuf.bufs[COMPONENT_Cr].buf = pcYuvDst.bufs[COMPONENT_Cr].buf + ( xStart >> scaleX ) + ( ( yStart >> scaleY ) * dstStride[COMPONENT_Cr] );
1914
0
        }
1915
1916
0
        Distortion *pSADsArray = &m_SADsArray[( ( ( 2 * DMVR_NUM_ITERATION ) + 1 ) * ( ( 2 * DMVR_NUM_ITERATION ) + 1 ) ) >> 1];
1917
1918
0
        Pel *biPredSubPuL0 = biLinearPredL0 + xStart + yStart * m_biLinearBufStride;
1919
0
        Pel *biPredSubPuL1 = biLinearPredL1 + xStart + yStart * m_biLinearBufStride;
1920
1921
0
        cDistParam.cur.buf = biPredSubPuL0;
1922
0
        cDistParam.org.buf = biPredSubPuL1;
1923
1924
0
        Distortion minCost = cDistParam.distFunc( cDistParam );
1925
1926
0
        minCost >>= 1;
1927
0
        minCost  -= ( minCost >> 2 );
1928
1929
0
        if( minCost < ( dx * dy ) )
1930
0
        {
1931
0
          Mv &curDMv = cu.cs->m_dmvrMvCache[cu.mvdL0SubPuOff + num];
1932
0
          curDMv = Mv( 0, 0 );
1933
0
        }
1934
0
        else
1935
0
        {
1936
0
          int16_t totalDeltaMV[2] = { 0, 0 };
1937
0
          int16_t deltaMV[2]      = { 0, 0 };
1938
1939
0
          pSADsArray[0] = minCost;
1940
1941
0
          xBIPMVRefine( cDistParam, biPredSubPuL0, biPredSubPuL1, minCost, deltaMV, m_SADsArray );
1942
1943
0
          if( deltaMV[0] != 0 || deltaMV[1] != 0 )
1944
0
          {
1945
0
            pSADsArray += deltaMV[1] * ( 2 * DMVR_NUM_ITERATION + 1 ) + deltaMV[0];
1946
0
          }
1947
1948
0
          totalDeltaMV[0] = deltaMV[0] * ( 1 << mvShift );
1949
0
          totalDeltaMV[1] = deltaMV[1] * ( 1 << mvShift );
1950
1951
0
          xDMVRSubPixelErrorSurface( totalDeltaMV, deltaMV, pSADsArray );
1952
1953
0
          Mv &curDMv = cu.cs->m_dmvrMvCache[cu.mvdL0SubPuOff + num];
1954
0
          curDMv = Mv( totalDeltaMV[0], totalDeltaMV[1] );
1955
1956
0
          Mv mv0 = mergeMv[REF_PIC_LIST_0] + curDMv; mv0.clipToStorageBitDepth();
1957
0
          Mv mv1 = mergeMv[REF_PIC_LIST_1] - curDMv; mv1.clipToStorageBitDepth();
1958
1959
0
          if( ( mv0.hor >> mvShift ) != ( mergeMv[0].hor >> mvShift ) || ( mv0.ver >> mvShift ) != ( mergeMv[0].ver >> mvShift ) )
1960
0
          {
1961
0
            xPrefetchPad( subPu, cYuvRefBuffDMVRL0, REF_PIC_LIST_0, true );
1962
0
          }
1963
1964
0
          if( isChromaEnabled( cu.chromaFormat ) && ( ( mv0.hor >> mvShiftX ) != ( mergeMv[0].hor >> mvShiftX ) || ( mv0.ver >> mvShiftY ) != ( mergeMv[0].ver >> mvShiftY ) ) )
1965
0
          {
1966
0
            xPrefetchPad( subPu, cYuvRefBuffDMVRL0, REF_PIC_LIST_0, false );
1967
0
          }
1968
1969
0
          if( ( mv1.hor >> mvShift ) != ( mergeMv[1].hor >> mvShift ) || ( mv1.ver >> mvShift ) != ( mergeMv[1].ver >> mvShift ) )
1970
0
          {
1971
0
            xPrefetchPad( subPu, cYuvRefBuffDMVRL1, REF_PIC_LIST_1, true );
1972
0
          }
1973
0
          if( isChromaEnabled( cu.chromaFormat ) && ( ( mv1.hor >> mvShiftX ) != ( mergeMv[1].hor >> mvShiftX ) || ( mv1.ver >> mvShiftY ) != ( mergeMv[1].ver >> mvShiftY ) ) )
1974
0
          {
1975
0
            xPrefetchPad( subPu, cYuvRefBuffDMVRL1, REF_PIC_LIST_1, false );
1976
0
          }
1977
1978
0
          subPu.mv[0][0] = mv0;
1979
0
          subPu.mv[1][0] = mv1;
1980
0
        }
1981
1982
0
        PelUnitBuf& srcPred0 = subPredBuf;
1983
1984
0
        bioAppliedSubblk = minCost < bioEnabledThres ? false : bioApplied;
1985
1986
0
        xFinalPaddedMCForDMVR( subPu, srcPred0, srcPred1, cYuvRefBuffDMVRL0, cYuvRefBuffDMVRL1, bioAppliedSubblk, mergeMv );
1987
0
        xWeightedAverage     ( subPu, srcPred0, srcPred1, subPredBuf, bds, clpRngs, bioAppliedSubblk );
1988
1989
0
        num++;
1990
0
      }
1991
0
    }
1992
0
  }
1993
0
}
1994
1995
void InterPrediction::xIntraBlockCopy( CodingUnit &cu, PelUnitBuf &predBuf, const ComponentID compID )
1996
0
{
1997
0
  const unsigned int lcuWidth = cu.sps->getMaxCUWidth();
1998
0
  const int shiftSampleHor = getComponentScaleX( compID, cu.chromaFormat );
1999
0
  const int shiftSampleVer = getComponentScaleY( compID, cu.chromaFormat );
2000
0
  const int ctuSizeVerLog2 = getLog2(lcuWidth) - shiftSampleVer;
2001
0
  Mv bv = cu.mv[REF_PIC_LIST_0][0];
2002
0
  bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT);
2003
0
  int refx, refy;
2004
0
  if (compID == COMPONENT_Y)
2005
0
  {
2006
0
    refx = cu.Y().x + bv.hor;
2007
0
    refy = cu.Y().y + bv.ver;
2008
0
  }
2009
0
  else
2010
0
  {//Cb or Cr
2011
0
    refx = cu.Cb().x + (bv.hor >> shiftSampleHor);
2012
0
    refy = cu.Cb().y + (bv.ver >> shiftSampleVer);
2013
0
  }
2014
0
  const int ibcBufferWidth = cu.cs->m_IBCBufferWidth >> shiftSampleHor;
2015
0
  refx &= ( ibcBufferWidth - 1 );
2016
0
  refy &= ((1 << ctuSizeVerLog2) - 1);
2017
2018
0
  const int lineIdx = cu.lumaPos().y / cu.slice->getSPS()->getMaxCUHeight();
2019
2020
0
  CHECK( refy + predBuf.bufs[compID].height > ( 1 << ctuSizeVerLog2 ), "IBC access out of bounds." );
2021
0
  if (refx + (int)predBuf.bufs[compID].width <= ibcBufferWidth)
2022
0
  {
2023
0
    const CompArea srcArea = CompArea( compID, Position( refx, refy ), Size( predBuf.bufs[compID] ) );
2024
0
    const CPelBuf refBuf = cu.cs->m_virtualIBCbuf[lineIdx].getBuf( srcArea );
2025
0
    predBuf.bufs[compID].copyFrom( refBuf );
2026
0
  }
2027
0
  else
2028
0
  {   // wrap around
2029
0
    CHECK( (int) predBuf.bufs[compID].width > ibcBufferWidth, "IBC access out of bounds." );
2030
2031
0
    const int width   = ibcBufferWidth - refx;
2032
0
    CompArea  srcArea = CompArea( compID, Position( refx, refy ), Size( width, predBuf.bufs[compID].height ) );
2033
0
    CPelBuf   srcBuf  = cu.cs->m_virtualIBCbuf[lineIdx].getBuf( srcArea );
2034
0
    PelBuf    dstBuf  = predBuf.bufs[compID].subBuf( 0, 0, width, predBuf.bufs[compID].height );
2035
0
    dstBuf.copyFrom( srcBuf );
2036
2037
0
    const int remWidth = predBuf.bufs[compID].width - width;
2038
0
    srcArea            = CompArea( compID, Position( 0, refy ), Size( remWidth, predBuf.bufs[compID].height ) );
2039
0
    srcBuf             = cu.cs->m_virtualIBCbuf[lineIdx].getBuf( srcArea );
2040
0
    dstBuf             = predBuf.bufs[compID].subBuf( width, 0, remWidth, predBuf.bufs[compID].height );
2041
0
    dstBuf.copyFrom( srcBuf );
2042
0
  }
2043
0
}
2044
2045
#if JVET_O1170_CHECK_BV_AT_DECODER
2046
void InterPrediction::resetIBCBuffer(const ChromaFormat chromaFormatIDC, const int ctuSize)
2047
{
2048
  const UnitArea area = UnitArea(chromaFormatIDC, Area(0, 0, m_IBCBufferWidth, ctuSize));
2049
  m_IBCBuffer.getBuf(area).fill(-1);
2050
}
2051
2052
void InterPrediction::resetVPDUforIBC(const ChromaFormat chromaFormatIDC, const int ctuSize, const int vSize, const int xPos, const int yPos)
2053
{
2054
  const UnitArea area = UnitArea(chromaFormatIDC, Area(xPos & (m_IBCBufferWidth - 1), yPos & (ctuSize - 1), vSize, vSize));
2055
  m_IBCBuffer.getBuf(area).fill(-1);
2056
}
2057
2058
bool InterPrediction::isLumaBvValid(const int ctuSize, const int xCb, const int yCb, const int width, const int height, const int xBv, const int yBv)
2059
{
2060
  if(((yCb + yBv) & (ctuSize - 1)) + height > ctuSize)
2061
  {
2062
    return false;
2063
  }
2064
  int refTLx = xCb + xBv;
2065
  int refTLy = (yCb + yBv) & (ctuSize - 1);
2066
  PelBuf buf = m_IBCBuffer.Y();
2067
  for(int x = 0; x < width; x += 4)
2068
  {
2069
    for(int y = 0; y < height; y += 4)
2070
    {
2071
      if(buf.at((x + refTLx) & (m_IBCBufferWidth - 1), y + refTLy) == -1) return false;
2072
      if(buf.at((x + 3 + refTLx) & (m_IBCBufferWidth - 1), y + refTLy) == -1) return false;
2073
      if(buf.at((x + refTLx) & (m_IBCBufferWidth - 1), y + 3 + refTLy) == -1) return false;
2074
      if(buf.at((x + 3 + refTLx) & (m_IBCBufferWidth - 1), y + 3 + refTLy) == -1) return false;
2075
    }
2076
  }
2077
  return true;
2078
}
2079
#endif
2080
2081
void InterPrediction::xPredInterBlkRPR( const std::pair<int, int>& scalingRatio, const PPS& pps, const ComponentID& compID, const ChromaFormat chFmt, const Picture* refPic, const Mv& mv, const Position blkPos, const int dstWidth, const int dstHeight, Pel* dst, const ptrdiff_t dstStride, const bool bi, const bool wrapRef, const ClpRng& clpRng, const int filterIndex, const bool useAltHpelIf )
2082
0
{
2083
0
  const bool rndRes = !bi;
2084
2085
0
  const int csx = getComponentScaleX( compID, chFmt );
2086
0
  const int csy = getComponentScaleY( compID, chFmt );
2087
2088
0
  const int shiftHor  = MV_FRACTIONAL_BITS_INTERNAL + csx;
2089
0
  const int shiftVer  = MV_FRACTIONAL_BITS_INTERNAL + csy;
2090
2091
0
  const int width     = dstWidth;
2092
0
  const int height    = dstHeight;
2093
2094
0
  const int refPicWidth  = refPic->lwidth();
2095
0
  const int refPicHeight = refPic->lheight();
2096
2097
0
  const PPS* refPPS = refPic->slices[ 0 ]->getPPS();
2098
0
  const auto refBuf = refPic->getRecoBuf( compID, wrapRef );
2099
2100
0
  static constexpr int rprThreshold1 = ( 1 << SCALE_RATIO_BITS ) * 5 / 4;
2101
0
  static constexpr int rprThreshold2 = ( 1 << SCALE_RATIO_BITS ) * 7 / 4;
2102
2103
0
  int xFilter = filterIndex;
2104
0
  if     ( scalingRatio.first > rprThreshold2 ) xFilter = 4;
2105
0
  else if( scalingRatio.first > rprThreshold1 ) xFilter = 3;
2106
2107
0
  int yFilter = filterIndex;
2108
0
  if     ( scalingRatio.second > rprThreshold2 ) yFilter = 4;
2109
0
  else if( scalingRatio.second > rprThreshold1 ) yFilter = 3;
2110
2111
0
  if( isLuma( compID ) && filterIndex == 2 )
2112
0
  {
2113
0
    if( scalingRatio.first  > rprThreshold1 ) xFilter += 2;
2114
0
    if( scalingRatio.second > rprThreshold1 ) yFilter += 2;
2115
0
  }
2116
2117
0
  const int posShift = SCALE_RATIO_BITS - 4;
2118
0
  const int stepX    = ( scalingRatio.first  + 8 ) >> 4;
2119
0
  const int stepY    = ( scalingRatio.second + 8 ) >> 4;
2120
0
  const int offX     = 1 << ( posShift - shiftHor - 1 );
2121
0
  const int offY     = 1 << ( posShift - shiftVer - 1 );
2122
2123
0
  const int64_t posX = ( ( blkPos.x << csx ) - ( pps.getScalingWindow().getWindowLeftOffset() * SPS::getWinUnitX( chFmt ) ) ) >> csx;
2124
0
  const int64_t posY = ( ( blkPos.y << csy ) - ( pps.getScalingWindow().getWindowTopOffset()  * SPS::getWinUnitY( chFmt ) ) ) >> csy;
2125
2126
0
  const int     addX = isLuma( compID ) ? 0 : int( 1 - refPic->cs->sps->getHorCollocatedChromaFlag() ) * 8 * ( scalingRatio.first  - SCALE_1X.first  );
2127
0
  const int     addY = isLuma( compID ) ? 0 : int( 1 - refPic->cs->sps->getVerCollocatedChromaFlag() ) * 8 * ( scalingRatio.second - SCALE_1X.second );
2128
2129
0
  int64_t x0Int = ( ( posX << ( 4 + csx ) ) + mv.getHor() ) * (int64_t) scalingRatio.first + addX;
2130
0
          x0Int = SIGN( x0Int ) * ( ( std::abs( x0Int ) + ( (int64_t) 1 << ( 7 + csx ) ) ) >> ( 8 + csx ) )
2131
0
                + ( ( refPPS->getScalingWindow().getWindowLeftOffset() * SPS::getWinUnitX( chFmt ) ) << ( ( posShift - csx ) ) );
2132
2133
0
  int64_t y0Int = ( ( posY << ( 4 + csy ) ) + mv.getVer() ) * (int64_t) scalingRatio.second + addY;
2134
0
          y0Int = SIGN( y0Int ) * ( ( std::abs( y0Int ) + ( (int64_t) 1 << ( 7 + csy ) ) ) >> ( 8 + csy ) )
2135
0
                  + ( ( refPPS->getScalingWindow().getWindowTopOffset() * SPS::getWinUnitY( chFmt ) ) << ( ( posShift - csy ) ) );
2136
2137
0
  const int extSize = isLuma( compID ) ? 1 : 2;
2138
2139
0
  const int vFilterSize = isLuma( compID ) ? NTAPS_LUMA : NTAPS_CHROMA;
2140
2141
0
  int yInt0 = ( (int32_t) y0Int + offY ) >> posShift;
2142
0
      yInt0 = Clip3( -( NTAPS_LUMA / 2 ), ( refPicHeight >> csy ) + ( NTAPS_LUMA / 2 ), yInt0 );
2143
2144
0
  int xInt0 = ( (int32_t) x0Int + offX ) >> posShift;
2145
0
      xInt0 = Clip3( -( NTAPS_LUMA / 2 ), ( refPicWidth >> csx ) + ( NTAPS_LUMA / 2 ), xInt0 );
2146
2147
0
  int refHeight = ( ( ( (int32_t) y0Int + ( height - 1 ) * stepY ) + offY ) >> posShift )
2148
0
                - ( ( ( (int32_t) y0Int +              0 * stepY ) + offY ) >> posShift ) + 1;
2149
0
  refHeight = std::max<int>( 1, refHeight );
2150
2151
0
  CHECK( MAX_CU_SIZE * MAX_SCALING_RATIO + 16 < refHeight + vFilterSize - 1 + extSize,
2152
0
                     "Buffer size is not enough, scaling more than MAX_SCALING_RATIO" );
2153
2154
0
  Pel buffer[ ( MAX_CU_SIZE + 16 ) * ( MAX_CU_SIZE * MAX_SCALING_RATIO + 16 ) ];
2155
0
  int tmpStride = width;
2156
2157
0
  const int filtHeight = refHeight + vFilterSize - 1 + extSize;
2158
  // only need special case for bottom margin, because all other directions are clamped to -4/+4, which should always fit within the margin
2159
0
  const int maxFiltHeight = std::min( filtHeight, ( (int) ( refPicHeight + refPic->margin ) >> csy ) - yInt0 );
2160
2161
0
  int col;
2162
0
  for( col = 0; col < width; col++ )
2163
0
  {
2164
0
    int posX = (int32_t) x0Int + col * stepX;
2165
0
    int xInt = ( posX + offX ) >> posShift;
2166
0
        xInt = Clip3( -( NTAPS_LUMA / 2 ), ( refPicWidth >> csx ) + ( NTAPS_LUMA / 2 ), xInt );
2167
0
    int xFrac = ( ( posX + offX ) >> ( posShift - shiftHor ) ) & ( ( 1 << shiftHor ) - 1 );
2168
2169
0
    CHECK( xInt0 > xInt, "Wrong horizontal starting point" );
2170
2171
0
    const Pel* refPtr    = refBuf.bufAt( xInt, yInt0 );
2172
0
    ptrdiff_t  refStride = refBuf.stride;
2173
2174
0
    m_if.filterHor( compID,
2175
0
                    GET_OFFSETY( refPtr, refStride, -( vFilterSize / 2 - 1 ) ), refStride,
2176
0
                    GET_OFFSETX( buffer, tmpStride, col ),                      tmpStride,
2177
0
                    1, maxFiltHeight,
2178
0
                    xFrac,
2179
0
                    false,
2180
0
                    chFmt,
2181
0
                    clpRng,
2182
0
                    xFilter,
2183
0
                    useAltHpelIf && scalingRatio.first == SCALE_1X.first );
2184
0
  }
2185
2186
  // fill buffer area where source block reaches out of the source image + bottom margin using pixel values from last filtered column
2187
0
  if( filtHeight > maxFiltHeight )
2188
0
  {
2189
0
    CHECK( maxFiltHeight <= 0, "nothing filtered yet. Reference block completely outside?" );
2190
0
    for( int row = maxFiltHeight; row < filtHeight; ++row )
2191
0
    {
2192
0
      memcpy( &buffer[ tmpStride * row ], &buffer[ tmpStride * ( maxFiltHeight - 1 ) ], width * sizeof( buffer[ 0 ] ) );
2193
0
    }
2194
0
  }
2195
2196
0
  for( int row = 0; row < height; row++ )
2197
0
  {
2198
0
    int posY = (int32_t) y0Int + row * stepY;
2199
0
    int yInt = ( posY + offY ) >> posShift;
2200
0
        yInt = Clip3( -( NTAPS_LUMA / 2 ), ( refPicHeight >> csy ) + ( NTAPS_LUMA / 2 ), yInt );
2201
0
    int yFrac = ( ( posY + offY ) >> ( posShift - shiftVer ) ) & ( ( 1 << shiftVer ) - 1 );
2202
2203
0
    CHECK( yInt0 > yInt, "Wrong vertical starting point" );
2204
2205
0
    m_if.filterVer( compID,
2206
0
                    GET_OFFSETY( buffer, tmpStride, ( yInt - yInt0 ) + ( ( vFilterSize >> 1 ) - 1 ) ), tmpStride,
2207
0
                    GET_OFFSETY( dst, dstStride, row ),                                                dstStride,
2208
0
                    width, 1,
2209
0
                    yFrac,
2210
0
                    false,
2211
0
                    rndRes,
2212
0
                    chFmt,
2213
0
                    clpRng,
2214
0
                    yFilter,
2215
0
                    useAltHpelIf && scalingRatio.second == SCALE_1X.second );
2216
0
  }
2217
0
}
2218
2219
}   // namespace vvdec