Coverage Report

Created: 2026-10-28 06:18

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
30.5k
  : BioGradFilter ( gradFilterCore )
324
30.5k
  , profGradFilter( gradFilterCore<false> )
325
30.5k
  , BiOptFlow     ( BiOptFlowCore )
326
30.5k
  , roundIntVector( nullptr )
327
30.5k
{
328
30.5k
  clipMv = clipMvInPic;
329
330
30.5k
  m_currChromaFormat = NUM_CHROMA_FORMAT;
331
332
30.5k
  memset( m_gradX0,               0x00, sizeof( m_gradX0             ) );
333
30.5k
  memset( m_gradY0,               0x00, sizeof( m_gradY0             ) );
334
30.5k
  memset( m_gradX1,               0x00, sizeof( m_gradX1             ) );
335
30.5k
  memset( m_gradY1,               0x00, sizeof( m_gradY1             ) );
336
30.5k
  memset( m_bdofBlock,            0x00, sizeof( m_bdofBlock          ) );
337
30.5k
  memset( m_acYuvPred,            0x00, sizeof( m_acYuvPred          ) );
338
30.5k
  memset( m_tmpBlock,             0x00, sizeof( m_tmpBlock           ) );
339
30.5k
  memset( m_cRefSamplesDMVRL0,    0x00, sizeof( m_cRefSamplesDMVRL0  ) );
340
30.5k
  memset( m_cRefSamplesDMVRL1,    0x00, sizeof( m_cRefSamplesDMVRL1  ) );
341
30.5k
  memset( m_cYuvPredTempDMVRL0,   0x00, sizeof( m_cYuvPredTempDMVRL0 ) );
342
30.5k
  memset( m_cYuvPredTempDMVRL1,   0x00, sizeof( m_cYuvPredTempDMVRL1 ) );
343
30.5k
  memset( m_SADsArray,            0x00, sizeof( m_SADsArray          ) );
344
30.5k
}
345
346
InterPrediction::~InterPrediction()
347
30.5k
{
348
30.5k
  destroy();
349
30.5k
}
350
351
void InterPrediction::destroy()
352
30.5k
{
353
30.5k
}
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 if( isLuma( compID ) && ( width % 16 ) == 0 && ( height % 4 ) == 0 )
853
0
  {
854
    // Fused single-temp-pass MC for wide luma blocks (width = 32/48/64/96/128).
855
    // Apply the verified sliding-window 16xH N8 kernel in independent 16-wide column
856
    // strips, eliminating the separate filterHor->m_tmpBlock->filterVer second memory
857
    // pass. 2D separable MC is column-independent, so per-strip results are bit-exact
858
    // to the two-pass path (the width==16 branch above uses the same kernel).
859
0
    for( unsigned x = 0; x < width; x += 16 )
860
0
    {
861
0
      m_if.filter16xH( compID, refPtr + x, refStride, dstBuf + x, dstStride, 16, height, xFrac, yFrac, rndRes, chFmt, clpRng, useAltHpelIf );
862
0
    }
863
0
  }
864
0
  else
865
0
  {
866
0
    Pel *tmpBuf = m_tmpBlock;
867
0
    ptrdiff_t tmpStride = dmvrWidth ? dmvrWidth : width;
868
869
0
    int vFilterSize = bilinearMC ? NTAPS_BILINEAR : isLuma( compID ) ? NTAPS_LUMA : NTAPS_CHROMA;
870
871
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 );
872
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 );
873
0
  }
874
875
0
  if( bioApplied && compID == COMPONENT_Y )
876
0
  {
877
0
    const int   shift   = std::max<int>( 2, ( IF_INTERNAL_PREC - clpRng.bd ) );
878
0
    const int   xOffset = ( xFrac < 8 ) ? 1 : 0;
879
0
    const int   yOffset = ( yFrac < 8 ) ? 1 : 0;
880
0
    const Pel*  refPel  = refPtr + ( 1 - yOffset ) * refStride - xOffset;
881
0
    Pel*        dstPel  = m_bdofBlock[m_iRefListIdx] + 2 * dstStride;
882
883
0
    for( int h = 0; h < height; h++ )
884
0
    {
885
0
      dstPel[0]         = refPel[0        ] * ( 1 << shift ) - ( Pel ) IF_INTERNAL_OFFS;
886
0
      dstPel[width + 1] = refPel[width + 1] * ( 1 << shift ) - ( Pel ) IF_INTERNAL_OFFS;
887
888
0
      refPel += refStride;
889
0
      dstPel += dstStride;
890
0
    }
891
892
0
    refPel = refPtr - yOffset * refStride - xOffset;
893
0
    dstPel = m_bdofBlock[m_iRefListIdx] + dstStride;
894
895
0
    PaddBIO( refPel, dstPel, width, shift );
896
    
897
0
    refPel = refPtr + ( height + 1 - yOffset ) * refStride - xOffset;
898
0
    dstPel = m_bdofBlock[m_iRefListIdx] + ( height + 2 * BIO_EXTEND_SIZE ) * dstStride;
899
900
0
    PaddBIO( refPel, dstPel, width, shift );
901
0
  }
902
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)
903
904
bool InterPrediction::isSubblockVectorSpreadOverLimit( int a, int b, int c, int d, int predType )
905
0
{
906
0
  int s4 = ( 4 << 11 );
907
0
  int filterTap = 6;
908
909
0
  if ( predType == 3 )
910
0
  {
911
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 ) );
912
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 ) );
913
0
    refBlkWidth  = ( refBlkWidth >> 11 ) + filterTap + 3;
914
0
    refBlkHeight = ( refBlkHeight >> 11 ) + filterTap + 3;
915
916
0
    if ( refBlkWidth * refBlkHeight > ( filterTap + 9 ) * ( filterTap + 9 ) )
917
0
    {
918
0
      return true;
919
0
    }
920
0
  }
921
0
  else
922
0
  {
923
0
    int refBlkWidth  = std::max( 0, 4 * a + s4 ) - std::min( 0, 4 * a + s4 );
924
0
    int refBlkHeight = std::max( 0, 4 * b ) - std::min( 0, 4 * b );
925
0
    refBlkWidth  = ( refBlkWidth >> 11 ) + filterTap + 3;
926
0
    refBlkHeight = ( refBlkHeight >> 11 ) + filterTap + 3;
927
0
    if ( refBlkWidth * refBlkHeight > ( filterTap + 9 ) * ( filterTap + 5 ) )
928
0
    {
929
0
      return true;
930
0
    }
931
932
0
    refBlkWidth  = std::max( 0, 4 * c ) - std::min( 0, 4 * c );
933
0
    refBlkHeight = std::max( 0, 4 * d + s4 ) - std::min( 0, 4 * d + s4 );
934
0
    refBlkWidth  = ( refBlkWidth >> 11 ) + filterTap + 3;
935
0
    refBlkHeight = ( refBlkHeight >> 11 ) + filterTap + 3;
936
0
    if ( refBlkWidth * refBlkHeight > ( filterTap + 5 ) * ( filterTap + 9 ) )
937
0
    {
938
0
      return true;
939
0
    }
940
0
  }
941
0
  return false;
942
0
}
943
944
#define CALC_AFFINE_MV_ON_THE_FLY 0
945
946
void InterPrediction::xPredAffineBlk( const ComponentID&        compID,
947
                                      const CodingUnit&     cu,
948
                                      const Picture*            refPic,
949
                                      const RefPicList          refPicList,
950
                                      PelUnitBuf&               dstPic,
951
                                      bool                      bi,
952
                                      const ClpRng&             clpRng,
953
                                      const std::pair<int, int> scalingRatio
954
                                      )
955
0
{
956
0
  const ChromaFormat chFmt = cu.chromaFormat;
957
0
  const int iScaleX = getComponentScaleX( compID, chFmt );
958
0
  const int iScaleY = getComponentScaleY( compID, chFmt );
959
960
0
  const int chromaScaleX = getChannelTypeScaleX( CH_C, chFmt );
961
0
  const int chromaScaleY = getChannelTypeScaleY( CH_C, chFmt );
962
963
0
  const int shiftX = 4 + iScaleX;
964
0
  const int shiftY = 4 + iScaleY;
965
0
  const int maskX  = ( 1 << shiftX ) - 1;
966
0
  const int maskY  = ( 1 << shiftY ) - 1;
967
968
  // get affine sub-block width and height
969
0
  const int width  = cu.lwidth();
970
0
  const int height = cu.lheight();
971
972
0
  static constexpr int blockWidth  = AFFINE_MIN_BLOCK_SIZE;
973
0
  static constexpr int blockHeight = AFFINE_MIN_BLOCK_SIZE;
974
975
0
  const int MVBUFFER_SIZE = ( width / AFFINE_MIN_BLOCK_SIZE ) >> chromaScaleX;
976
977
0
  const int cxWidth  = width  >> iScaleX;
978
0
  const int cxHeight = height >> iScaleY;
979
0
  const SPS &sps    = *cu.sps;
980
0
  const int iMvShift = 4;
981
0
  const int iOffset  = 8;
982
0
  const int iHorMax = ( cu.pps->getPicWidthInLumaSamples()  + iOffset -       cu.lx() - 1 ) *(1<< iMvShift);
983
0
  const int iHorMin = (  -(int)cu.cs->pcv->maxCUWidth       - iOffset -  (int)cu.lx() + 1 ) *(1<< iMvShift);
984
0
  const int iVerMax = ( cu.pps->getPicHeightInLumaSamples() + iOffset -       cu.ly() - 1 ) *(1<< iMvShift);
985
0
  const int iVerMin = (  -(int)cu.cs->pcv->maxCUHeight      - iOffset -  (int)cu.ly() + 1 ) *(1<< iMvShift);
986
0
  const bool clipSubPic = clipMv == clipMvInSubpic;
987
988
0
  const int shift = MAX_CU_DEPTH;
989
990
0
  const Mv &affLT = cu.mv[refPicList][0];
991
0
  const Mv &affRT = cu.mv[refPicList][1];
992
0
  const Mv &affLB = cu.mv[refPicList][2];
993
994
0
  int deltaMvHorX, deltaMvHorY, deltaMvVerX, deltaMvVerY;
995
996
0
  deltaMvHorX = ( affRT - affLT ).getHor() *(1<< ( shift - getLog2( width )));
997
0
  deltaMvHorY = ( affRT - affLT ).getVer() *(1<< ( shift - getLog2( width )));
998
999
0
  if( cu.affineType() == AFFINEMODEL_6PARAM )
1000
0
  {
1001
0
    deltaMvVerX = ( affLB - affLT ).getHor() *(1<< ( shift - getLog2( height )));
1002
0
    deltaMvVerY = ( affLB - affLT ).getVer() *(1<< ( shift - getLog2( height )));
1003
0
  }
1004
0
  else
1005
0
  {
1006
0
    deltaMvVerX = -deltaMvHorY;
1007
0
    deltaMvVerY =  deltaMvHorX;
1008
0
  }
1009
1010
#if CALC_AFFINE_MV_ON_THE_FLY
1011
  const int mvScaleHor = affLT.getHor() << shift;
1012
  const int mvScaleVer = affLT.getVer() << shift;
1013
1014
  static const int halfBW = AFFINE_MIN_BLOCK_SIZE >> 1;
1015
  static const int halfBH = AFFINE_MIN_BLOCK_SIZE >> 1;
1016
1017
#endif
1018
0
  const bool subblkMVSpreadOverLimit = InterPrediction::isSubblockVectorSpreadOverLimit( deltaMvHorX, deltaMvHorY, deltaMvVerX, deltaMvVerY, cu.interDir() );
1019
1020
0
  const bool refPicScaled = refPic->isRefScaled( cu.pps );
1021
1022
0
  PelBuf &dstBuf = dstPic.bufs[compID];
1023
1024
0
#if !CALC_AFFINE_MV_ON_THE_FLY
1025
0
  const CMotionBuf mb       = cu.getMotionBuf();
1026
0
  const MotionInfo* curMi   = mb.buf;
1027
0
  const ptrdiff_t miStride  = mb.stride;
1028
0
#endif
1029
0
  Mv* chromaMvFld = m_storedMv;
1030
1031
0
  if( isLuma( compID ) )
1032
0
  {
1033
0
    memset( NO_WARNING_class_memaccess( m_storedMv ), 0, MVBUFFER_SIZE * ( g_miScaling.scaleVer( height ) >> chromaScaleY ) * sizeof( Mv ) );
1034
0
  }
1035
1036
0
  bool enablePROF = ( sps.getUsePROF() ) && ( compID == COMPONENT_Y );
1037
0
  enablePROF &= (! cu.cs->picHeader->getDisProfFlag() );
1038
0
  enablePROF &= !( ( cu.affineType() == AFFINEMODEL_6PARAM && affLT == affRT && affLT == affLB ) || ( cu.affineType() == AFFINEMODEL_4PARAM && affLT == affRT ) );
1039
0
  enablePROF &= !subblkMVSpreadOverLimit;
1040
0
  enablePROF &= !refPicScaled;
1041
1042
0
  bool isLast = enablePROF ? false : !bi;
1043
1044
0
  Pel gradX[36];
1045
0
  Pel gradY[36];
1046
1047
0
  static constexpr int dstExtW = blockWidth  + PROF_BORDER_EXT_W * 2;
1048
0
  static constexpr int dstExtH = blockHeight + PROF_BORDER_EXT_H * 2;
1049
0
  PelBuf dstExtBuf( m_bdofBlock[0], dstExtW, dstExtH );
1050
1051
0
  int dMvScaleHor[16];
1052
0
  int dMvScaleVer[16];
1053
1054
0
  if (enablePROF)
1055
0
  {
1056
0
    int* dMvH = dMvScaleHor;
1057
0
    int* dMvV = dMvScaleVer;
1058
0
    int quadHorX = deltaMvHorX *(1<< 2);
1059
0
    int quadHorY = deltaMvHorY *(1<< 2);
1060
0
    int quadVerX = deltaMvVerX *(1<< 2);
1061
0
    int quadVerY = deltaMvVerY *(1<< 2);
1062
1063
0
    dMvH[0] = ((deltaMvHorX + deltaMvVerX) *2) - ((quadHorX + quadVerX) *2);
1064
0
    dMvV[0] = ((deltaMvHorY + deltaMvVerY) *2) - ((quadHorY + quadVerY) *2);
1065
1066
0
    for (int w = 1; w < blockWidth; w++)
1067
0
    {
1068
0
      dMvH[w] = dMvH[w - 1] + quadHorX;
1069
0
      dMvV[w] = dMvV[w - 1] + quadHorY;
1070
0
    }
1071
1072
0
    dMvH += blockWidth;
1073
0
    dMvV += blockWidth;
1074
0
    for (int h = 1; h < blockHeight; h++)
1075
0
    {
1076
0
      for (int w = 0; w < blockWidth; w++)
1077
0
      {
1078
0
        dMvH[w] = dMvH[w - blockWidth] + quadVerX;
1079
0
        dMvV[w] = dMvV[w - blockWidth] + quadVerY;
1080
0
      }
1081
0
      dMvH += blockWidth;
1082
0
      dMvV += blockWidth;
1083
0
    }
1084
1085
0
    const int mvShift  = 8;
1086
0
    const int dmvLimit = ( 1 << 5 ) - 1;
1087
1088
0
    if (!roundIntVector)
1089
0
    {
1090
0
      for (int idx = 0; idx < blockWidth * blockHeight; idx++)
1091
0
      {
1092
0
        roundAffineMv(dMvScaleHor[idx], dMvScaleVer[idx], mvShift);
1093
0
        dMvScaleHor[idx] = Clip3( -dmvLimit, dmvLimit, dMvScaleHor[idx] );
1094
0
        dMvScaleVer[idx] = Clip3( -dmvLimit, dmvLimit, dMvScaleVer[idx] );
1095
0
      }
1096
0
    }
1097
0
    else
1098
0
    {
1099
0
      int sz = blockWidth * blockHeight;
1100
0
      roundIntVector(dMvScaleHor, sz, mvShift, dmvLimit);
1101
0
      roundIntVector(dMvScaleVer, sz, mvShift, dmvLimit);
1102
0
    }
1103
0
  }
1104
  
1105
#if CALC_AFFINE_MV_ON_THE_FLY
1106
  int mvhor, mvver;
1107
1108
  if( subblkMVSpreadOverLimit )
1109
  {
1110
    mvhor = mvScaleHor + deltaMvHorX * ( width >> 1 ) + deltaMvVerX * ( height >> 1 );
1111
    mvver = mvScaleVer + deltaMvHorY * ( width >> 1 ) + deltaMvVerY * ( height >> 1 );
1112
    roundAffineMv( mvhor, mvver, shift );
1113
    mv.hor = mvhor; mv.ver = mvver;
1114
    mv.clipToStorageBitDepth();
1115
  }
1116
#endif
1117
1118
0
  std::array<const Pel*, 2> refBuf{ nullptr, nullptr };
1119
0
  std::array<ptrdiff_t, 2>  refBufStride{ 0, 0 };
1120
0
  if( cu.pps->getNumSubPics() > 1 && cu.pps->getSubPicFromCU( cu ).getTreatedAsPicFlag() )
1121
0
  {
1122
0
    const int subPicIdx = cu.pps->getSubPicFromCU( cu ).getSubPicIdx();
1123
0
    refBuf              = { refPic->getSubPicBufPtr   ( subPicIdx, compID, false ), 0 /*refPic->getSubPicBufPtr   ( subPicIdx, compID, true )*/ };
1124
0
    refBufStride        = { refPic->getSubPicBufStride( subPicIdx, compID, false ), 0 /*refPic->getSubPicBufStride( subPicIdx, compID, true )*/ };
1125
0
  }
1126
0
  else
1127
0
  {
1128
0
    if( cu.sps->getUseWrapAround() )
1129
0
    {
1130
0
      refBuf       = { refPic->getRecoBufPtr   ( compID, false ), refPic->getRecoBufPtr   ( compID, true ) };
1131
0
      refBufStride = { refPic->getRecoBufStride( compID, false ), refPic->getRecoBufStride( compID, true ) };
1132
0
    }
1133
0
    else
1134
0
    {
1135
0
      refBuf      [0] = refBuf      [1] = refPic->getRecoBufPtr   ( compID, false );
1136
0
      refBufStride[0] = refBufStride[1] = refPic->getRecoBufStride( compID, false );
1137
0
    }
1138
0
  }
1139
1140
0
  const int puPosX = cu.blocks[compID].x, puPosY = cu.blocks[compID].y;
1141
1142
  // get prediction block by block
1143
0
  for ( int h = 0; h < cxHeight; h += blockHeight )
1144
0
  {
1145
0
#if !CALC_AFFINE_MV_ON_THE_FLY
1146
0
    const MotionInfo* lineMi = curMi;
1147
1148
0
#endif
1149
0
    for ( int w = 0; w < cxWidth; w += blockWidth )
1150
0
    {
1151
0
      Position mvPos{ w >> 2, h >> 2 };
1152
      
1153
0
      int iMvScaleTmpHor;
1154
0
      int iMvScaleTmpVer;
1155
1156
0
      if( isLuma( compID ) || chFmt == CHROMA_444 )
1157
0
      {
1158
#if CALC_AFFINE_MV_ON_THE_FLY
1159
        if( !subblkMVSpreadOverLimit )
1160
        {
1161
          mvhor = mvScaleHor + deltaMvHorX * ( halfBW + w ) + deltaMvVerX * ( halfBH + h );
1162
          mvver = mvScaleVer + deltaMvHorY * ( halfBW + w ) + deltaMvVerY * ( halfBH + h );
1163
          roundAffineMv( mvhor, mvver, shift );
1164
          mv.hor = mvhor; mv.ver = mvver;
1165
          mv.clipToStorageBitDepth();
1166
        }
1167
#else   
1168
0
        const Mv& mv = lineMi->mv[refPicList];
1169
1170
0
        iMvScaleTmpHor = mv.hor;
1171
0
        iMvScaleTmpVer = mv.ver;
1172
0
#endif
1173
1174
0
        if( chFmt != CHROMA_400 && chFmt != CHROMA_444 && ( ( ( mvPos.x ^ mvPos.y ) & 1 ) == 0 || chFmt != CHROMA_420 ) )
1175
0
        {
1176
0
          Mv &chromaMv = *GET_OFFSET( chromaMvFld, MVBUFFER_SIZE, mvPos.x >> chromaScaleX, mvPos.y >> chromaScaleY );
1177
0
          chromaMv.hor += iMvScaleTmpHor;
1178
0
          chromaMv.ver += iMvScaleTmpVer;
1179
0
        }
1180
0
      }
1181
0
      else
1182
0
      {
1183
0
        Mv& mv = *GET_OFFSET( chromaMvFld, MVBUFFER_SIZE, mvPos.x, mvPos.y );
1184
0
        iMvScaleTmpHor = mv.hor *(1<< ( 1 - ( chromaScaleX | chromaScaleY ) ));
1185
0
        iMvScaleTmpVer = mv.ver *(1<< ( 1 - ( chromaScaleX | chromaScaleY ) ));
1186
0
        roundAffineMv( iMvScaleTmpHor, iMvScaleTmpVer, 1 );
1187
0
      }
1188
1189
0
      bool wrapRef = false;
1190
1191
0
      if ( refPic->isWrapAroundEnabled( cu.pps ) )
1192
0
      {
1193
0
        Mv tmpMv(iMvScaleTmpHor, iMvScaleTmpVer);
1194
0
        wrapRef = wrapClipMv( tmpMv, Position( cu.Y().x + ( w << iScaleX ), cu.Y().y + ( h << iScaleY ) ), Size( blockWidth << iScaleX, blockHeight << iScaleY ), sps, *cu.pps );
1195
0
        iMvScaleTmpHor = tmpMv.getHor();
1196
0
        iMvScaleTmpVer = tmpMv.getVer();
1197
0
      }
1198
0
      else if( !refPicScaled && clipSubPic )
1199
0
      {
1200
0
        Mv mv{ iMvScaleTmpHor, iMvScaleTmpVer };
1201
0
        clipMv( mv, cu.lumaPos(), cu.lumaSize(), sps, *cu.pps );
1202
0
        iMvScaleTmpHor = mv.hor;
1203
0
        iMvScaleTmpVer = mv.ver;
1204
0
      }
1205
0
      else
1206
0
      {
1207
0
        iMvScaleTmpHor = std::min<int>( iHorMax, std::max<int>( iHorMin, iMvScaleTmpHor ) );
1208
0
        iMvScaleTmpVer = std::min<int>( iVerMax, std::max<int>( iVerMin, iMvScaleTmpVer ) );
1209
0
      }
1210
1211
0
      CHECKD( !refPic, "Should not be null" );
1212
0
      if( refPicScaled )
1213
0
      {
1214
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 );
1215
0
        CHECKD( enablePROF, "PROF should be disabled with RPR" );
1216
0
      }
1217
0
      else
1218
0
      {
1219
0
        const int xInt  = iMvScaleTmpHor >> shiftX;
1220
0
        const int xFrac = iMvScaleTmpHor &  maskX;
1221
0
        const int yInt  = iMvScaleTmpVer >> shiftY;
1222
0
        const int yFrac = iMvScaleTmpVer &  maskY;
1223
1224
0
        const Pel*      refBufPtr = refBuf      [wrapRef];
1225
0
        const ptrdiff_t refStride = refBufStride[wrapRef];
1226
0
        OFFSET( refBufPtr, refStride, puPosX + xInt + w, puPosY + yInt + h );
1227
1228
0
        Pel* dst;
1229
1230
0
        ptrdiff_t dstStride;
1231
1232
0
        if( enablePROF )
1233
0
        {
1234
0
          dst       = dstExtBuf.buf + 1 + dstExtBuf.stride;
1235
0
          dstStride = dstExtBuf.stride;
1236
0
        }
1237
0
        else
1238
0
        {
1239
0
          dst       = dstBuf.bufAt( w, h );
1240
0
          dstStride = dstBuf.stride;
1241
0
        }
1242
1243
0
        if( xFrac && yFrac )
1244
0
        {
1245
0
          m_if.filter4x4( compID, refBufPtr, refStride, dst, dstStride, 4, 4, xFrac, yFrac, isLast, chFmt, clpRng );
1246
0
        }
1247
0
        else if( yFrac == 0 )
1248
0
        {
1249
0
          m_if.filterHor( compID, refBufPtr, refStride, dst, dstStride, blockWidth, blockHeight, xFrac, isLast, chFmt, clpRng );
1250
0
        }
1251
0
        else// if( xFrac == 0 )
1252
0
        {
1253
0
          m_if.filterVer( compID, refBufPtr, refStride, dst, dstStride, blockWidth, blockHeight, yFrac, true, isLast, chFmt, clpRng );
1254
0
        }
1255
1256
0
        if( enablePROF )
1257
0
        {
1258
0
          const Pel shift   = std::max<int>( 2, ( IF_INTERNAL_PREC - clpRng.bd ) );
1259
0
          const int xOffset = xFrac >> 3;
1260
0
          const int yOffset = yFrac >> 3;
1261
1262
0
          CHECKD( shift < 0, "Shift need to be positive!" );
1263
0
          static_assert( PROF_BORDER_EXT_H == BIO_EXTEND_SIZE, "PROF and BIO extension need to be equal!" );
1264
0
          static_assert( PROF_BORDER_EXT_W == BIO_EXTEND_SIZE, "PROF and BIO extension need to be equal!" );
1265
1266
0
          const ptrdiff_t refOffset = ( blockHeight + 1 ) * refStride;
1267
0
          const ptrdiff_t dstOffset = ( blockHeight + 1 ) * dstStride;
1268
1269
0
          const Pel* refPel = refBufPtr - ( 1 - yOffset ) * refStride + xOffset - 1;
1270
0
                Pel* dstPel = dst - 1 - dstStride;
1271
1272
0
          PaddBIO( refPel,             dstPel,             blockWidth, shift );
1273
0
          PaddBIO( refPel + refOffset, dstPel + dstOffset, blockWidth, shift );
1274
1275
0
          refPel = refBufPtr + yOffset * refStride + xOffset;
1276
0
          dstPel = dst;
1277
0
          for( int ph = 0; ph < 4; ph++, refPel += refStride, dstPel += dstStride )
1278
0
          {
1279
0
            dstPel[        -1] = refPel[        -1] * ( 1 << shift ) - Pel( IF_INTERNAL_OFFS );
1280
0
            dstPel[blockWidth] = refPel[blockWidth] * ( 1 << shift ) - Pel( IF_INTERNAL_OFFS );
1281
0
          }
1282
1283
0
          profGradFilter( dst, dstStride, blockWidth, blockHeight, AFFINE_MIN_BLOCK_SIZE, gradX, gradY, clpRng.bd );
1284
1285
0
          Pel *dstY = dstBuf.buf + w + dstBuf.stride * h;
1286
0
          const Pel offset   = ( 1 << ( shift- 1 ) ) + IF_INTERNAL_OFFS;
1287
0
          applyPROF[bi]( dstY, dstBuf.stride, dst, gradX, gradY, dMvScaleHor, dMvScaleVer, shift, offset, clpRng );
1288
0
        }
1289
0
      }
1290
0
#if !CALC_AFFINE_MV_ON_THE_FLY
1291
1292
0
      INCX( lineMi, miStride );
1293
0
#endif
1294
0
    }
1295
0
#if !CALC_AFFINE_MV_ON_THE_FLY
1296
1297
0
    INCY( curMi, miStride );
1298
0
#endif
1299
0
  }
1300
0
}
1301
1302
void InterPrediction::applyBiOptFlow( const CodingUnit &cu,
1303
                                      const PelUnitBuf &    yuvSrc0,
1304
                                      const PelUnitBuf &    yuvSrc1,
1305
                                      const int &           refIdx0,
1306
                                      const int &           refIdx1,
1307
                                      PelUnitBuf &          yuvDst,
1308
                                      const BitDepths &     clipBitDepths )
1309
0
{
1310
0
  const int height  = yuvDst.Y().height;
1311
0
  const int width   = yuvDst.Y().width;
1312
0
  int       heightG = height + 2 * BIO_EXTEND_SIZE;
1313
0
  int       widthG  = width  + 2 * BIO_EXTEND_SIZE;
1314
1315
0
  Pel *gradX0 = m_gradX0;
1316
0
  Pel *gradX1 = m_gradX1;
1317
0
  Pel *gradY0 = m_gradY0;
1318
0
  Pel *gradY1 = m_gradY1;
1319
1320
0
  int        stridePredMC = width + BIO_ALIGN_SIZE;
1321
0
  const Pel *srcY0        = m_bdofBlock[0] + stridePredMC;
1322
0
  const Pel *srcY1        = m_bdofBlock[1] + stridePredMC;
1323
1324
0
  Pel *           dstY      = yuvDst.Y().buf;
1325
0
  const ptrdiff_t dstStride = yuvDst.Y().stride;
1326
1327
0
  const int       bitDepth  = clipBitDepths.recon;
1328
1329
0
  for( int refList = 0; refList < NUM_REF_PIC_LIST_01; refList++ )
1330
0
  {
1331
0
    Pel *dstTempPtr = m_bdofBlock[refList] + stridePredMC;
1332
0
    Pel *gradY      = ( refList == 0 ) ? m_gradY0 : m_gradY1;
1333
0
    Pel *gradX      = ( refList == 0 ) ? m_gradX0 : m_gradX1;
1334
0
    BioGradFilter( dstTempPtr, stridePredMC, widthG, heightG, width + BIO_ALIGN_SIZE, gradX, gradY, bitDepth );
1335
0
  }
1336
1337
0
  const ClpRng &clpRng   = cu.slice->clpRng( COMPONENT_Y );
1338
0
  const int     shiftNum = IF_INTERNAL_PREC + 1 - bitDepth;
1339
0
  const int     offset   = ( 1 << ( shiftNum - 1 ) ) + 2 * IF_INTERNAL_OFFS;
1340
0
  const int     limit    = ( 1 << 4 ) - 1;
1341
1342
1343
0
  BiOptFlow( srcY0,
1344
0
             srcY1,
1345
0
             gradX0,
1346
0
             gradX1,
1347
0
             gradY0,
1348
0
             gradY1,
1349
0
             width,
1350
0
             height,
1351
0
             dstY,
1352
0
             dstStride,
1353
0
             shiftNum,
1354
0
             offset,
1355
0
             limit,
1356
0
             clpRng,
1357
0
             bitDepth
1358
0
            );
1359
0
}
1360
1361
void InterPrediction::xWeightedAverage(const CodingUnit& cu, const PelUnitBuf& pcYuvSrc0, const PelUnitBuf& pcYuvSrc1, PelUnitBuf& pcYuvDst, const BitDepths& clipBitDepths, const ClpRngs& clpRngs, const bool& bioApplied )
1362
0
{
1363
0
  const int iRefIdx0 = cu.refIdx[0];
1364
0
  const int iRefIdx1 = cu.refIdx[1];
1365
1366
0
  CHECKD( !( iRefIdx0 >= 0 && iRefIdx1 >= 0 ), "xWeightedAverage should only be called for BI-predicted blocks!" );
1367
1368
0
  if( cu.BcwIdx() != BCW_DEFAULT && !cu.ciipFlag() )
1369
0
  {
1370
0
    CHECK( bioApplied, "Bcw is disallowed with BIO" );
1371
0
    pcYuvDst.addWeightedAvg( pcYuvSrc0, pcYuvSrc1, clpRngs, g_BcwInternBcw[cu.BcwIdx()] );
1372
0
    return;
1373
0
  }
1374
1375
0
  if( bioApplied )
1376
0
  {
1377
0
    applyBiOptFlow( cu, pcYuvSrc0, pcYuvSrc1, iRefIdx0, iRefIdx1, pcYuvDst, clipBitDepths );
1378
0
  }
1379
1380
0
  pcYuvDst.addAvg( pcYuvSrc0, pcYuvSrc1, clpRngs, bioApplied );
1381
0
}
1382
1383
1384
void InterPrediction::motionCompensation( CodingUnit &cu, PelUnitBuf &predBuf, const bool luma, const bool chroma )
1385
0
{
1386
0
  PROFILER_SCOPE_AND_STAGE_EXT( 1, g_timeProfiler, P_MOTCOMP, *cu.cs, luma ? CH_L: CH_C );
1387
0
  m_currCuArea = cu;
1388
1389
0
  if( cu.slice->getSliceType() != I_SLICE && cu.slice->getRefPic( REF_PIC_LIST_0, 0 )->subPictures.size() > 1 )
1390
0
  {
1391
0
    clipMv = clipMvInSubpic;
1392
0
  }
1393
0
  else
1394
0
  {
1395
0
    clipMv = clipMvInPic;
1396
0
  }
1397
1398
0
  if( CU::isIBC( cu ) )
1399
0
  {
1400
0
    CHECK( !luma, "IBC only for Chroma is not allowed." );
1401
0
    xIntraBlockCopy( cu, predBuf, COMPONENT_Y );
1402
0
    if( chroma )
1403
0
    {
1404
0
      xIntraBlockCopy( cu, predBuf, COMPONENT_Cb );
1405
0
      xIntraBlockCopy( cu, predBuf, COMPONENT_Cr );
1406
0
    }
1407
0
    return;
1408
0
  }
1409
1410
  // else, go with regular MC below
1411
0
  const PPS &pps            = *cu.pps;
1412
1413
0
  CHECKD( !cu.affineFlag() && cu.refIdx[0] >= 0 && cu.refIdx[1] >= 0 && ( cu.lwidth() + cu.lheight() == 12 ), "invalid 4x8/8x4 bi-predicted blocks" );
1414
0
  const WPScalingParam* wp0 = nullptr;
1415
0
  const WPScalingParam* wp1 = nullptr;
1416
0
  int refIdx0 = cu.refIdx[REF_PIC_LIST_0];
1417
0
  int refIdx1 = cu.refIdx[REF_PIC_LIST_1];
1418
0
  cu.slice->getWpScaling( REF_PIC_LIST_0, refIdx0, wp0 );
1419
0
  cu.slice->getWpScaling( REF_PIC_LIST_1, refIdx1, wp1 );
1420
0
  bool bioApplied    = false;
1421
0
  const Slice &slice = *cu.slice;
1422
1423
0
  if( cu.sps->getUseBIO() && ( !cu.cs->picHeader->getDisBdofFlag() ) )
1424
0
  {
1425
1426
0
    if( cu.affineFlag() || m_subPuMC || cu.ciipFlag() || cu.smvdMode() || ( cu.sps->getUseBcw() && cu.BcwIdx() != BCW_DEFAULT ) )
1427
0
    {
1428
0
      bioApplied = false;
1429
0
    }
1430
0
    else
1431
0
    {
1432
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);
1433
0
      const bool biocheck1 = !( pps.getUseWP() && slice.getSliceType() == P_SLICE );
1434
1435
0
      if( biocheck0 && biocheck1 && PU::isBiPredFromDifferentDirEqDistPoc( cu ) && cu.Y().height >= 8 && cu.Y().width >= 8 && cu.Y().area() >= 128 )
1436
0
      {
1437
0
        bioApplied = true;
1438
0
      }
1439
0
    }
1440
0
  }
1441
    
1442
0
  bool dmvrApplied = !m_subPuMC && PU::checkDMVRCondition( cu );
1443
0
  bool refIsScaled = ( refIdx0 < 0 ? false : cu.slice->getRefPic( REF_PIC_LIST_0, refIdx0 )->isRefScaled( cu.pps ) ) ||
1444
0
                     ( refIdx1 < 0 ? false : cu.slice->getRefPic( REF_PIC_LIST_1, refIdx1 )->isRefScaled( cu.pps ) );
1445
1446
0
  dmvrApplied = dmvrApplied && !refIsScaled;
1447
0
  bioApplied  = bioApplied  && !refIsScaled;
1448
1449
0
  if( cu.mergeType() != MRG_TYPE_SUBPU_ATMVP && bioApplied && !dmvrApplied )
1450
0
  {
1451
0
    xSubPuBio( cu, predBuf );
1452
0
  }
1453
0
  else if( dmvrApplied )
1454
0
  {
1455
0
    cu.setDmvrCondition( true );
1456
0
    xProcessDMVR( cu, predBuf, slice.clpRngs(), bioApplied );
1457
0
  }
1458
0
  else if( cu.mergeType() == MRG_TYPE_SUBPU_ATMVP )
1459
0
  {
1460
0
    xSubPuMC( cu, predBuf );
1461
0
  }
1462
0
  else if( xCheckIdenticalMotion( cu ) )
1463
0
  {
1464
0
    xPredInterUni( cu, REF_PIC_LIST_0, predBuf, false, false , true, true );
1465
0
  }
1466
0
  else
1467
0
  {
1468
0
    CHECKD( bioApplied, "BIO should not be applied here!" );
1469
0
    xPredInterBi( cu, predBuf );
1470
0
  }
1471
0
}
1472
1473
void InterPrediction::motionCompensationGeo( CodingUnit &cu, PelUnitBuf &predBuf )
1474
0
{
1475
0
  PROFILER_SCOPE_AND_STAGE_EXT( 1, g_timeProfiler, P_MOTCOMP, *cu.cs, CH_L );
1476
1477
0
  if( cu.slice->getSliceType() != I_SLICE && cu.slice->getRefPic( REF_PIC_LIST_0, 0 )->subPictures.size() > 1 )
1478
0
  {
1479
0
    clipMv = clipMvInSubpic;
1480
0
  }
1481
0
  else
1482
0
  {
1483
0
    clipMv = clipMvInPic;
1484
0
  }
1485
1486
0
  const UnitArea localUnitArea( cu.cs->area.chromaFormat, Area( 0, 0, cu.lwidth(), cu.lheight() ) );
1487
1488
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() ) );
1489
1490
0
  uint8_t locInterDir = cu.interDirrefIdxGeo0() >> 4;
1491
0
  CHECKD( !( locInterDir == 1 || locInterDir == 2 ), "Should not happen" );
1492
0
  cu.mv  [REF_PIC_LIST_0][0] = locInterDir == 1 ? cu.mv[0][1] : Mv();
1493
0
  cu.mv  [REF_PIC_LIST_1][0] = locInterDir == 1 ? Mv() : cu.mv[0][1];
1494
0
  cu.refIdx [REF_PIC_LIST_0] = locInterDir == 1 ? cu.interDirrefIdxGeo0() & 15 : -1;
1495
0
  cu.refIdx [REF_PIC_LIST_1] = locInterDir == 1 ? -1 : cu.interDirrefIdxGeo0() & 15;
1496
0
  cu.mvpIdx [REF_PIC_LIST_0] = NOT_VALID;
1497
0
  cu.mvpIdx [REF_PIC_LIST_1] = NOT_VALID;
1498
0
  motionCompensation( cu, tmpGeoBuf0, true, isChromaEnabled( cu.chromaFormat ) );
1499
1500
0
  locInterDir = cu.interDirrefIdxGeo1() >> 4;
1501
0
  CHECKD( !( locInterDir == 1 || locInterDir == 2 ), "Should not happen" );
1502
0
  cu.mv  [REF_PIC_LIST_0][0] = locInterDir == 1 ? cu.mv[1][1] : Mv();
1503
0
  cu.mv  [REF_PIC_LIST_1][0] = locInterDir == 1 ? Mv() : cu.mv[1][1];
1504
0
  cu.refIdx [REF_PIC_LIST_0] = locInterDir == 1 ? cu.interDirrefIdxGeo1() & 15 : -1;
1505
0
  cu.refIdx [REF_PIC_LIST_1] = locInterDir == 1 ? -1 : cu.interDirrefIdxGeo1() & 15;
1506
0
  cu.mvpIdx [REF_PIC_LIST_0] = NOT_VALID;
1507
0
  cu.mvpIdx [REF_PIC_LIST_1] = NOT_VALID;
1508
0
  motionCompensation( cu, predBuf, true, isChromaEnabled( cu.chromaFormat ) );
1509
1510
0
  const uint8_t splitDir = cu.geoSplitDir;
1511
0
  weightedGeoBlk( cu, splitDir, isChromaEnabled( cu.chromaFormat ) ? MAX_NUM_CHANNEL_TYPE : CHANNEL_TYPE_LUMA, predBuf, tmpGeoBuf0, predBuf );
1512
0
}
1513
1514
void InterPrediction::weightedGeoBlk( CodingUnit &cu, const uint8_t splitDir, int32_t channel, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1)
1515
0
{
1516
0
  if( channel == CHANNEL_TYPE_LUMA )
1517
0
  {
1518
0
    m_if.weightedGeoBlk( cu, cu.lumaSize().width, cu.lumaSize().height, COMPONENT_Y, splitDir, predDst, predSrc0, predSrc1, cu.slice->clpRngs() );
1519
0
  }
1520
0
  else if( channel == CHANNEL_TYPE_CHROMA )
1521
0
  {
1522
0
    m_if.weightedGeoBlk( cu, cu.chromaSize().width, cu.chromaSize().height, COMPONENT_Cb, splitDir, predDst, predSrc0, predSrc1, cu.slice->clpRngs() );
1523
0
    m_if.weightedGeoBlk( cu, cu.chromaSize().width, cu.chromaSize().height, COMPONENT_Cr, splitDir, predDst, predSrc0, predSrc1, cu.slice->clpRngs() );
1524
0
  }
1525
0
  else
1526
0
  {
1527
0
    m_if.weightedGeoBlk( cu, cu.lumaSize().width,   cu.lumaSize().height,   COMPONENT_Y,  splitDir, predDst, predSrc0, predSrc1, cu.slice->clpRngs() );
1528
0
    if( isChromaEnabled( cu.chromaFormat ) )
1529
0
    {
1530
0
      m_if.weightedGeoBlk( cu, cu.chromaSize().width, cu.chromaSize().height, COMPONENT_Cb, splitDir, predDst, predSrc0, predSrc1, cu.slice->clpRngs() );
1531
0
      m_if.weightedGeoBlk( cu, cu.chromaSize().width, cu.chromaSize().height, COMPONENT_Cr, splitDir, predDst, predSrc0, predSrc1, cu.slice->clpRngs() );
1532
0
    }
1533
0
  }
1534
0
}
1535
1536
1537
void InterPrediction::xPrefetchPad( CodingUnit& cu, PelUnitBuf &pcPad, RefPicList refId, bool forLuma )
1538
0
{
1539
0
  int width, height;
1540
0
  Mv cMv;
1541
1542
0
  const Picture* refPic = cu.slice->getRefPic( refId, cu.refIdx[refId] );
1543
1544
0
  static constexpr int mvShift = MV_FRACTIONAL_BITS_INTERNAL;
1545
1546
0
  const bool wrapRefEnbld = refPic->isWrapAroundEnabled( cu.pps );
1547
0
  const bool subPicAsPic  = cu.pps->getNumSubPics() > 1 && cu.pps->getSubPicFromCU( cu ).getTreatedAsPicFlag();
1548
1549
0
  const ChannelType chType = forLuma ? CHANNEL_TYPE_LUMA : CHANNEL_TYPE_CHROMA;
1550
1551
0
  int filtersize = isLuma( chType ) ? NTAPS_LUMA : NTAPS_CHROMA;
1552
0
  cMv = cu.mv[refId][0];
1553
  
1554
0
  const int mvshiftTempHor        = mvShift + getChannelTypeScaleX( chType, cu.chromaFormat );
1555
0
  const int mvshiftTempVer        = mvShift + getChannelTypeScaleY( chType, cu.chromaFormat );
1556
0
  cMv                      += Mv( -( ( ( filtersize >> 1 ) - 1 ) << mvshiftTempHor ),
1557
0
                                  -( ( ( filtersize >> 1 ) - 1 ) << mvshiftTempVer ) );
1558
0
  bool wrapRef = false;
1559
1560
0
  if( wrapRefEnbld )
1561
0
  {
1562
0
    wrapRef = wrapClipMv( cMv, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1563
0
  }
1564
0
  else
1565
0
  {
1566
0
    clipMv( cMv, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1567
0
  }
1568
1569
0
  cMv.hor >>= mvshiftTempHor;
1570
0
  cMv.ver >>= mvshiftTempVer;
1571
1572
0
  if( isLuma( chType ) )
1573
0
  {
1574
0
    pcPad.bufs[COMPONENT_Y]
1575
0
      .stride  = pcPad.bufs[COMPONENT_Y].width + ( 2 * DMVR_NUM_ITERATION ) + filtersize;
1576
0
    width      = pcPad.bufs[COMPONENT_Y].width;
1577
0
    height     = pcPad.bufs[COMPONENT_Y].height;
1578
0
    ptrdiff_t
1579
0
      offset   = DMVR_NUM_ITERATION * ( pcPad.bufs[COMPONENT_Y].stride + 1 );
1580
1581
0
    width      += filtersize - 1;
1582
0
    height     += filtersize - 1;
1583
1584
0
    CPelBuf refBuf = subPicAsPic ? refPic->getSubPicBuf( cu.pps->getSubPicFromCU( cu ).getSubPicIdx(), COMPONENT_Y, wrapRef ) : refPic->getRecoBuf( COMPONENT_Y, wrapRef );
1585
1586
0
    Position   Rec_offset = cu.lumaPos().offset( cMv.hor, cMv.ver );
1587
0
    const Pel* refBufPtr  = refBuf.bufAt( Rec_offset );
1588
1589
0
    PelBuf& dstBuf = pcPad.Y();
1590
0
    prefetchPad[0]( refBufPtr, refBuf.stride, dstBuf.buf + offset, dstBuf.stride, width, height );
1591
0
  }
1592
0
  else
1593
0
  {
1594
0
    pcPad.bufs[COMPONENT_Cb]
1595
0
      .stride  = pcPad.bufs[COMPONENT_Cb].width + ( 2 * DMVR_NUM_ITERATION ) + filtersize;
1596
0
    pcPad.bufs[COMPONENT_Cr]
1597
0
      .stride  = pcPad.bufs[COMPONENT_Cb].stride;
1598
0
    width      = pcPad.bufs[COMPONENT_Cb].width;
1599
0
    height     = pcPad.bufs[COMPONENT_Cb].height;
1600
0
    ptrdiff_t
1601
0
      offsetCb = DMVR_NUM_ITERATION * ( pcPad.bufs[COMPONENT_Cb].stride + 1 );
1602
0
    ptrdiff_t
1603
0
      offsetCr = DMVR_NUM_ITERATION * ( pcPad.bufs[COMPONENT_Cr].stride + 1 );
1604
1605
0
    width      += filtersize - 1;
1606
0
    height     += filtersize - 1;
1607
1608
0
    CPelBuf refBufCb = subPicAsPic ? refPic->getSubPicBuf( cu.pps->getSubPicFromCU( cu ).getSubPicIdx(), COMPONENT_Cb, wrapRef ) : refPic->getRecoBuf( COMPONENT_Cb, wrapRef );
1609
0
    CPelBuf refBufCr = subPicAsPic ? refPic->getSubPicBuf( cu.pps->getSubPicFromCU( cu ).getSubPicIdx(), COMPONENT_Cr, wrapRef ) : refPic->getRecoBuf( COMPONENT_Cr, wrapRef );
1610
1611
0
    Position   Rec_offset     = cu.blocks[COMPONENT_Cb].pos().offset( cMv.hor, cMv.ver );
1612
0
    const Pel* refBufPtr  [2] = { refBufCb.bufAt( Rec_offset ), refBufCr.bufAt( Rec_offset ) };
1613
0
    const ptrdiff_t stride[2] = { refBufCb.stride, refBufCr.stride };
1614
0
          Pel* dstBufPtr  [2] = { pcPad.Cb().buf + offsetCb, pcPad.Cr().buf + offsetCr };
1615
0
    const ptrdiff_t dstStr[2] = { pcPad.Cb().stride, pcPad.Cr().stride };
1616
1617
0
    const int idx = getChannelTypeScaleY( CH_C, cu.chromaFormat );
1618
1619
0
    prefetchPad[1+idx]( refBufPtr[0], stride[0], dstBufPtr[0], dstStr[0], width, height );
1620
0
    prefetchPad[1+idx]( refBufPtr[1], stride[1], dstBufPtr[1], dstStr[1], width, height );
1621
0
  }
1622
0
}
1623
1624
inline int32_t div_for_maxq7(int64_t N, int64_t D)
1625
0
{
1626
0
  int32_t sign, q;
1627
0
  sign = 0;
1628
0
  if (N < 0)
1629
0
  {
1630
0
    sign = 1;
1631
0
    N = -N;
1632
0
  }
1633
1634
0
  q = 0;
1635
0
  D = (D << 3);
1636
0
  if (N >= D)
1637
0
  {
1638
0
    N -= D;
1639
0
    q++;
1640
0
  }
1641
0
  q = (q << 1);
1642
1643
0
  D = (D >> 1);
1644
0
  if (N >= D)
1645
0
  {
1646
0
    N -= D;
1647
0
    q++;
1648
0
  }
1649
0
  q = (q << 1);
1650
1651
0
  if (N >= (D >> 1))
1652
0
    q++;
1653
1654
0
  if (sign)
1655
0
    return (-q);
1656
0
  return(q);
1657
0
}
1658
1659
void xSubPelErrorSrfc(uint64_t *sadBuffer, int32_t *deltaMv)
1660
0
{
1661
0
  int64_t numerator, denominator;
1662
0
  int32_t mvDeltaSubPel;
1663
0
  int32_t mvSubPelLvl = 4;/*1: half pel, 2: Qpel, 3:1/8, 4: 1/16*/
1664
                                                        /*horizontal*/
1665
0
    numerator = (int64_t)(sadBuffer[1] - sadBuffer[3]) * (int64_t(1) << mvSubPelLvl);
1666
0
    denominator = (int64_t)((sadBuffer[1] + sadBuffer[3] - (sadBuffer[0] << 1)));
1667
1668
0
    if (0 != denominator)
1669
0
    {
1670
0
      if ((sadBuffer[1] != sadBuffer[0]) && (sadBuffer[3] != sadBuffer[0]))
1671
0
      {
1672
0
        mvDeltaSubPel = div_for_maxq7(numerator, denominator);
1673
0
        deltaMv[0] = (mvDeltaSubPel);
1674
0
      }
1675
0
      else
1676
0
      {
1677
0
        if (sadBuffer[1] == sadBuffer[0])
1678
0
        {
1679
0
          deltaMv[0] = -8;// half pel
1680
0
        }
1681
0
        else
1682
0
        {
1683
0
          deltaMv[0] = 8;// half pel
1684
0
        }
1685
0
      }
1686
0
    }
1687
1688
    /*vertical*/
1689
0
    numerator = (int64_t)((sadBuffer[2] - sadBuffer[4]) << mvSubPelLvl);
1690
0
    denominator = (int64_t)((sadBuffer[2] + sadBuffer[4] - (sadBuffer[0] << 1)));
1691
0
    if (0 != denominator)
1692
0
    {
1693
0
      if ((sadBuffer[2] != sadBuffer[0]) && (sadBuffer[4] != sadBuffer[0]))
1694
0
      {
1695
0
        mvDeltaSubPel = div_for_maxq7(numerator, denominator);
1696
0
        deltaMv[1] = (mvDeltaSubPel);
1697
0
      }
1698
0
      else
1699
0
      {
1700
0
        if (sadBuffer[2] == sadBuffer[0])
1701
0
        {
1702
0
          deltaMv[1] = -8;// half pel
1703
0
        }
1704
0
        else
1705
0
        {
1706
0
          deltaMv[1] = 8;// half pel
1707
0
        }
1708
0
      }
1709
0
    }
1710
1711
0
  return;
1712
0
}
1713
1714
void InterPrediction::xBIPMVRefine( DistParam &cDistParam, const Pel *pRefL0, const Pel *pRefL1, Distortion& minCost, int16_t *deltaMV, Distortion *pSADsArray)
1715
0
{
1716
0
  const ptrdiff_t refStride = m_biLinearBufStride;
1717
1718
0
  const Pel *pRefL0Orig = pRefL0;
1719
0
  const Pel *pRefL1Orig = pRefL1;
1720
1721
0
  for (int ver = -2; ver <= 2; ver++) {
1722
0
    const int initHor = -2;
1723
0
    const ptrdiff_t offset = initHor + ver * refStride;
1724
0
    pRefL0 = pRefL0Orig + offset;
1725
0
    pRefL1 = pRefL1Orig - offset;
1726
0
    cDistParam.org.buf = pRefL0;
1727
0
    cDistParam.cur.buf = pRefL1;
1728
1729
0
    cDistParam.distFuncX5(cDistParam, pSADsArray, ver != 0);
1730
1731
0
    for (int hor = -2; hor <= 2; hor++, pSADsArray++) {
1732
0
      Distortion cost = *pSADsArray;
1733
1734
0
      if (cost < minCost) {
1735
0
        minCost = cost;
1736
0
        deltaMV[0] = hor;
1737
0
        deltaMV[1] = ver;
1738
0
      }
1739
0
    }
1740
0
  }
1741
0
}
1742
1743
void InterPrediction::xFinalPaddedMCForDMVR(CodingUnit& cu, PelUnitBuf &pcYuvSrc0, PelUnitBuf &pcYuvSrc1, PelUnitBuf &pcPad0, PelUnitBuf &pcPad1, const bool bioApplied, const Mv mergeMV[NUM_REF_PIC_LIST_01] )
1744
0
{
1745
0
  ptrdiff_t offset;
1746
0
  int deltaIntMvX, deltaIntMvY;
1747
1748
  /*always high precision MVs are used*/
1749
0
  const int mvShift      = MV_FRACTIONAL_BITS_INTERNAL;
1750
0
  const ClpRngs clp      = cu.slice->clpRngs();
1751
0
  const int numValidComp = getNumberValidComponents( cu.chromaFormat );
1752
1753
0
  for (int k = 0; k < NUM_REF_PIC_LIST_01; k++)
1754
0
  {
1755
0
    PelUnitBuf &pcYUVTemp = k == 0 ? pcYuvSrc0 : pcYuvSrc1;
1756
0
    PelUnitBuf &pcPadTemp = k == 0 ? pcPad0    : pcPad1;
1757
1758
0
    RefPicList refId = (RefPicList)k;
1759
0
    Mv cMv = cu.mv[refId][0];
1760
0
    m_iRefListIdx = refId;
1761
0
    const Picture* refPic = cu.slice->getRefPic( refId, cu.refIdx[refId] );
1762
0
    Mv cMvClipped( cMv );
1763
0
    clipMv( cMvClipped, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1764
0
    const bool wrapRef = cu.pps->getUseWrapAround() && wrapClipMv( cMvClipped, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1765
1766
0
    Mv startMv = mergeMV[refId];
1767
1768
0
    for( int compID = 0; compID < numValidComp; compID++ )
1769
0
    {
1770
0
      const int mvshiftTempHor = mvShift + getComponentScaleX( (ComponentID)compID, cu.chromaFormat );
1771
0
      const int mvshiftTempVer = mvShift + getComponentScaleY( (ComponentID)compID, cu.chromaFormat );
1772
0
      deltaIntMvX = ( cMv.getHor() >> mvshiftTempHor ) - ( startMv.getHor() >> mvshiftTempHor );
1773
0
      deltaIntMvY = ( cMv.getVer() >> mvshiftTempVer ) - ( startMv.getVer() >> mvshiftTempVer );
1774
1775
0
      if( deltaIntMvX || deltaIntMvY )
1776
0
      {
1777
0
        ptrdiff_t pcPadstride       = pcPadTemp.bufs[compID].stride;
1778
0
        const int leftPixelExtra    = compID == COMPONENT_Y ? ( NTAPS_LUMA >> 1 ) - 1 : ( NTAPS_CHROMA >> 1 ) - 1;
1779
1780
0
        CHECKD( ( abs( deltaIntMvX ) > DMVR_NUM_ITERATION ) || ( abs( deltaIntMvY ) > DMVR_NUM_ITERATION ), "not expected DMVR movement" );
1781
1782
0
        offset  = ( DMVR_NUM_ITERATION + leftPixelExtra ) * ( pcPadstride + 1 );
1783
0
        offset += ( deltaIntMvY ) * pcPadstride;
1784
0
        offset += ( deltaIntMvX );
1785
0
        Pel *srcBufPelPtr = pcPadTemp.bufs[compID].buf + offset;
1786
1787
0
        xPredInterBlk<true , false>( ComponentID( compID ), cu, refPic, cMvClipped, pcYUVTemp.bufs[compID], true, clp, bioApplied, false, wrapRef, 0, 0, 0, srcBufPelPtr, pcPadstride );
1788
0
      }
1789
0
      else
1790
0
      {
1791
0
        xPredInterBlk<false, false>( ComponentID( compID ), cu, refPic, cMvClipped, pcYUVTemp.bufs[compID], true, clp, bioApplied, false, wrapRef, 0, 0, 0 );
1792
0
      }
1793
0
    }
1794
0
  }
1795
0
}
1796
1797
void xDMVRSubPixelErrorSurface( int16_t *totalDeltaMV, int16_t *deltaMV, Distortion*pSADsArray )
1798
0
{
1799
0
  static constexpr int sadStride = ( ( ( 2 * DMVR_NUM_ITERATION ) + 1 ) );
1800
0
  uint64_t sadbuffer[5];
1801
1802
0
  if( abs( totalDeltaMV[0] ) != ( 2 << MV_FRACTIONAL_BITS_INTERNAL ) && abs( totalDeltaMV[1] ) != ( 2 << MV_FRACTIONAL_BITS_INTERNAL ) )
1803
0
  {
1804
0
    int32_t tempDeltaMv[2] = { 0,0 };
1805
0
    sadbuffer[0] = pSADsArray[0];
1806
0
    sadbuffer[1] = pSADsArray[-1];
1807
0
    sadbuffer[2] = pSADsArray[-sadStride];
1808
0
    sadbuffer[3] = pSADsArray[1];
1809
0
    sadbuffer[4] = pSADsArray[sadStride];
1810
0
    xSubPelErrorSrfc(sadbuffer, tempDeltaMv);
1811
0
    totalDeltaMV[0] += tempDeltaMv[0];
1812
0
    totalDeltaMV[1] += tempDeltaMv[1];
1813
0
  }
1814
0
}
1815
1816
void InterPrediction::xinitMC( CodingUnit& cu, const ClpRngs &clpRngs )
1817
0
{
1818
  /*use merge MV as starting MV*/
1819
0
  Mv mergeMVL0(cu.mv[REF_PIC_LIST_0][0]);
1820
0
  Mv mergeMVL1(cu.mv[REF_PIC_LIST_1][0]);
1821
1822
  /*Clip the starting MVs*/
1823
0
  clipMv( mergeMVL0, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1824
0
  clipMv( mergeMVL1, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1825
1826
0
  const bool wrapRefL0 = cu.pps->getUseWrapAround() && wrapClipMv( mergeMVL0, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1827
0
  const bool wrapRefL1 = cu.pps->getUseWrapAround() && wrapClipMv( mergeMVL1, cu.lumaPos(), cu.lumaSize(), *cu.sps, *cu.pps );
1828
1829
0
  static constexpr int sizeExt = DMVR_NUM_ITERATION << 1;
1830
1831
0
  const int extWidth  = cu.lwidth()  + sizeExt;
1832
0
  const int extHeight = cu.lheight() + sizeExt;
1833
1834
  /*L0 MC for refinement*/
1835
0
  {
1836
0
    const Picture* refPic = cu.slice->getRefPic( L0, cu.refIdx[L0] );
1837
1838
0
    PelBuf yuvPredTempL0( m_cYuvPredTempDMVRL0, m_biLinearBufStride, extWidth, extHeight );
1839
1840
0
    mergeMVL0.hor -= ( DMVR_NUM_ITERATION << MV_FRACTIONAL_BITS_INTERNAL );
1841
0
    mergeMVL0.ver -= ( DMVR_NUM_ITERATION << MV_FRACTIONAL_BITS_INTERNAL );
1842
1843
0
    xPredInterBlk<false, true>( COMPONENT_Y, cu, refPic, mergeMVL0, yuvPredTempL0, true, clpRngs, false, false, wrapRefL0, extWidth, extHeight, true );
1844
0
  }
1845
1846
  /*L1 MC for refinement*/
1847
0
  {
1848
0
    const Picture* refPic = cu.slice->getRefPic( L1, cu.refIdx[L1] );
1849
1850
0
    PelBuf yuvPredTempL1( m_cYuvPredTempDMVRL1, m_biLinearBufStride, extWidth, extHeight );
1851
1852
0
    mergeMVL1.hor -= ( DMVR_NUM_ITERATION << MV_FRACTIONAL_BITS_INTERNAL );
1853
0
    mergeMVL1.ver -= ( DMVR_NUM_ITERATION << MV_FRACTIONAL_BITS_INTERNAL );
1854
1855
0
    xPredInterBlk<false, true>( COMPONENT_Y, cu, refPic, mergeMVL1, yuvPredTempL1, true, clpRngs, false, false, wrapRefL1, extWidth, extHeight, true );
1856
0
  }
1857
0
}
1858
1859
void InterPrediction::xProcessDMVR( CodingUnit& cu, PelUnitBuf &pcYuvDst, const ClpRngs &clpRngs, const bool bioApplied )
1860
0
{
1861
  /*Always High Precision*/
1862
0
  static constexpr int mvShift  = MV_FRACTIONAL_BITS_INTERNAL;
1863
0
         const     int mvShiftX = mvShift + getChannelTypeScaleX( CH_C, cu.chromaFormat );
1864
0
         const     int mvShiftY = mvShift + getChannelTypeScaleY( CH_C, cu.chromaFormat );
1865
1866
  /*use merge MV as starting MV*/
1867
0
  Mv mergeMv[] = { cu.mv[REF_PIC_LIST_0][0] , cu.mv[REF_PIC_LIST_1][0] };
1868
1869
0
  m_biLinearBufStride = ( cu.lwidth() + ( 2 * DMVR_NUM_ITERATION ) );
1870
1871
0
  xinitMC( cu, clpRngs );
1872
1873
0
  int dy = std::min<int>( cu.lumaSize().height, DMVR_SUBCU_HEIGHT );
1874
0
  int dx = std::min<int>( cu.lumaSize().width,  DMVR_SUBCU_WIDTH );
1875
1876
0
  Position puPos = cu.lumaPos();
1877
0
  BitDepths bds  = cu.sps->getBitDepths();
1878
1879
0
  int  bioEnabledThres = ( 2 * dy * dx );
1880
0
  bool bioAppliedSubblk;
1881
0
  {
1882
0
    int num = 0;
1883
    
1884
0
    int scaleX = getComponentScaleX( COMPONENT_Cb, cu.chromaFormat );
1885
0
    int scaleY = getComponentScaleY( COMPONENT_Cb, cu.chromaFormat );
1886
    // point mc buffer to cetre point to avoid multiplication to reach each iteration to the begining
1887
0
    Pel *biLinearPredL0 = m_cYuvPredTempDMVRL0 + ( DMVR_NUM_ITERATION * m_biLinearBufStride ) + DMVR_NUM_ITERATION;
1888
0
    Pel *biLinearPredL1 = m_cYuvPredTempDMVRL1 + ( DMVR_NUM_ITERATION * m_biLinearBufStride ) + DMVR_NUM_ITERATION;
1889
    
1890
0
    CodingUnit      subCu;
1891
0
    CodingUnit& subPu = subCu;
1892
1893
0
    subPu                   = cu;
1894
0
    subPu.UnitArea::operator=( UnitArea( cu.chromaFormat, Area( puPos.x, puPos.y, dx, dy ) ) );
1895
1896
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() ) );
1897
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() ) );
1898
1899
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() ) );
1900
1901
0
    DistParam cDistParam;
1902
0
    m_pcRdCost->setDistParam( cDistParam, nullptr, nullptr, m_biLinearBufStride, m_biLinearBufStride, clpRngs.bd, dx, dy, 1 );
1903
    
1904
0
    PelUnitBuf subPredBuf = pcYuvDst.subBuf( UnitAreaRelative( cu, subPu ) );
1905
0
    const ptrdiff_t dstStride[MAX_NUM_COMPONENT] = { pcYuvDst.bufs[COMPONENT_Y].stride,
1906
0
                                                     isChromaEnabled(cu.chromaFormat) ? pcYuvDst.bufs[COMPONENT_Cb].stride : 0,
1907
0
                                                     isChromaEnabled(cu.chromaFormat) ? pcYuvDst.bufs[COMPONENT_Cr].stride : 0};
1908
0
    for( int y = puPos.y, yStart = 0; y < ( puPos.y + cu.lumaSize().height ); y = y + dy, yStart = yStart + dy )
1909
0
    {
1910
0
      for( int x = puPos.x, xStart = 0; x < ( puPos.x + cu.lumaSize().width ); x = x + dx, xStart = xStart + dx )
1911
0
      {
1912
0
        subPu.mv[0][0]    = cu.mv[0][0]; subPu.mv[1][0]    = cu.mv[1][0];
1913
0
        subPu.blocks[0].x = x;           subPu.blocks[0].y = y;
1914
0
        if( isChromaEnabled( subPu.chromaFormat ) )
1915
0
        {
1916
0
          subPu.blocks[1].x = x >> scaleX; subPu.blocks[1].y = y >> scaleY;
1917
0
          subPu.blocks[2].x = x >> scaleX; subPu.blocks[2].y = y >> scaleY;
1918
0
        }
1919
1920
0
        subPredBuf.bufs[COMPONENT_Y].buf    = pcYuvDst.bufs[COMPONENT_Y].buf  +   xStart +                 yStart             * dstStride[COMPONENT_Y];
1921
1922
0
        if( isChromaEnabled( cu.chromaFormat ) )
1923
0
        {
1924
0
          subPredBuf.bufs[COMPONENT_Cb].buf = pcYuvDst.bufs[COMPONENT_Cb].buf + ( xStart >> scaleX ) + ( ( yStart >> scaleY ) * dstStride[COMPONENT_Cb] );
1925
0
          subPredBuf.bufs[COMPONENT_Cr].buf = pcYuvDst.bufs[COMPONENT_Cr].buf + ( xStart >> scaleX ) + ( ( yStart >> scaleY ) * dstStride[COMPONENT_Cr] );
1926
0
        }
1927
1928
0
        Distortion *pSADsArray = &m_SADsArray[( ( ( 2 * DMVR_NUM_ITERATION ) + 1 ) * ( ( 2 * DMVR_NUM_ITERATION ) + 1 ) ) >> 1];
1929
1930
0
        Pel *biPredSubPuL0 = biLinearPredL0 + xStart + yStart * m_biLinearBufStride;
1931
0
        Pel *biPredSubPuL1 = biLinearPredL1 + xStart + yStart * m_biLinearBufStride;
1932
1933
0
        cDistParam.cur.buf = biPredSubPuL0;
1934
0
        cDistParam.org.buf = biPredSubPuL1;
1935
1936
0
        Distortion minCost = cDistParam.distFunc( cDistParam );
1937
1938
0
        minCost >>= 1;
1939
0
        minCost  -= ( minCost >> 2 );
1940
1941
0
        if( minCost < ( dx * dy ) )
1942
0
        {
1943
0
          Mv &curDMv = cu.cs->m_dmvrMvCache[cu.mvdL0SubPuOff + num];
1944
0
          curDMv = Mv( 0, 0 );
1945
0
        }
1946
0
        else
1947
0
        {
1948
0
          int16_t totalDeltaMV[2] = { 0, 0 };
1949
0
          int16_t deltaMV[2]      = { 0, 0 };
1950
1951
0
          pSADsArray[0] = minCost;
1952
1953
0
          xBIPMVRefine( cDistParam, biPredSubPuL0, biPredSubPuL1, minCost, deltaMV, m_SADsArray );
1954
1955
0
          if( deltaMV[0] != 0 || deltaMV[1] != 0 )
1956
0
          {
1957
0
            pSADsArray += deltaMV[1] * ( 2 * DMVR_NUM_ITERATION + 1 ) + deltaMV[0];
1958
0
          }
1959
1960
0
          totalDeltaMV[0] = deltaMV[0] * ( 1 << mvShift );
1961
0
          totalDeltaMV[1] = deltaMV[1] * ( 1 << mvShift );
1962
1963
0
          xDMVRSubPixelErrorSurface( totalDeltaMV, deltaMV, pSADsArray );
1964
1965
0
          Mv &curDMv = cu.cs->m_dmvrMvCache[cu.mvdL0SubPuOff + num];
1966
0
          curDMv = Mv( totalDeltaMV[0], totalDeltaMV[1] );
1967
1968
0
          Mv mv0 = mergeMv[REF_PIC_LIST_0] + curDMv; mv0.clipToStorageBitDepth();
1969
0
          Mv mv1 = mergeMv[REF_PIC_LIST_1] - curDMv; mv1.clipToStorageBitDepth();
1970
1971
0
          if( ( mv0.hor >> mvShift ) != ( mergeMv[0].hor >> mvShift ) || ( mv0.ver >> mvShift ) != ( mergeMv[0].ver >> mvShift ) )
1972
0
          {
1973
0
            xPrefetchPad( subPu, cYuvRefBuffDMVRL0, REF_PIC_LIST_0, true );
1974
0
          }
1975
1976
0
          if( isChromaEnabled( cu.chromaFormat ) && ( ( mv0.hor >> mvShiftX ) != ( mergeMv[0].hor >> mvShiftX ) || ( mv0.ver >> mvShiftY ) != ( mergeMv[0].ver >> mvShiftY ) ) )
1977
0
          {
1978
0
            xPrefetchPad( subPu, cYuvRefBuffDMVRL0, REF_PIC_LIST_0, false );
1979
0
          }
1980
1981
0
          if( ( mv1.hor >> mvShift ) != ( mergeMv[1].hor >> mvShift ) || ( mv1.ver >> mvShift ) != ( mergeMv[1].ver >> mvShift ) )
1982
0
          {
1983
0
            xPrefetchPad( subPu, cYuvRefBuffDMVRL1, REF_PIC_LIST_1, true );
1984
0
          }
1985
0
          if( isChromaEnabled( cu.chromaFormat ) && ( ( mv1.hor >> mvShiftX ) != ( mergeMv[1].hor >> mvShiftX ) || ( mv1.ver >> mvShiftY ) != ( mergeMv[1].ver >> mvShiftY ) ) )
1986
0
          {
1987
0
            xPrefetchPad( subPu, cYuvRefBuffDMVRL1, REF_PIC_LIST_1, false );
1988
0
          }
1989
1990
0
          subPu.mv[0][0] = mv0;
1991
0
          subPu.mv[1][0] = mv1;
1992
0
        }
1993
1994
0
        PelUnitBuf& srcPred0 = subPredBuf;
1995
1996
0
        bioAppliedSubblk = minCost < bioEnabledThres ? false : bioApplied;
1997
1998
0
        xFinalPaddedMCForDMVR( subPu, srcPred0, srcPred1, cYuvRefBuffDMVRL0, cYuvRefBuffDMVRL1, bioAppliedSubblk, mergeMv );
1999
0
        xWeightedAverage     ( subPu, srcPred0, srcPred1, subPredBuf, bds, clpRngs, bioAppliedSubblk );
2000
2001
0
        num++;
2002
0
      }
2003
0
    }
2004
0
  }
2005
0
}
2006
2007
void InterPrediction::xIntraBlockCopy( CodingUnit &cu, PelUnitBuf &predBuf, const ComponentID compID )
2008
0
{
2009
0
  const unsigned int lcuWidth = cu.sps->getMaxCUWidth();
2010
0
  const int shiftSampleHor = getComponentScaleX( compID, cu.chromaFormat );
2011
0
  const int shiftSampleVer = getComponentScaleY( compID, cu.chromaFormat );
2012
0
  const int ctuSizeVerLog2 = getLog2(lcuWidth) - shiftSampleVer;
2013
0
  Mv bv = cu.mv[REF_PIC_LIST_0][0];
2014
0
  bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT);
2015
0
  int refx, refy;
2016
0
  if (compID == COMPONENT_Y)
2017
0
  {
2018
0
    refx = cu.Y().x + bv.hor;
2019
0
    refy = cu.Y().y + bv.ver;
2020
0
  }
2021
0
  else
2022
0
  {//Cb or Cr
2023
0
    refx = cu.Cb().x + (bv.hor >> shiftSampleHor);
2024
0
    refy = cu.Cb().y + (bv.ver >> shiftSampleVer);
2025
0
  }
2026
0
  const int ibcBufferWidth = cu.cs->m_IBCBufferWidth >> shiftSampleHor;
2027
0
  refx &= ( ibcBufferWidth - 1 );
2028
0
  refy &= ((1 << ctuSizeVerLog2) - 1);
2029
2030
0
  const int lineIdx = cu.lumaPos().y / cu.slice->getSPS()->getMaxCUHeight();
2031
2032
0
  CHECK( refy + predBuf.bufs[compID].height > ( 1 << ctuSizeVerLog2 ), "IBC access out of bounds." );
2033
0
  if (refx + (int)predBuf.bufs[compID].width <= ibcBufferWidth)
2034
0
  {
2035
0
    const CompArea srcArea = CompArea( compID, Position( refx, refy ), Size( predBuf.bufs[compID] ) );
2036
0
    const CPelBuf refBuf = cu.cs->m_virtualIBCbuf[lineIdx].getBuf( srcArea );
2037
0
    predBuf.bufs[compID].copyFrom( refBuf );
2038
0
  }
2039
0
  else
2040
0
  {   // wrap around
2041
0
    CHECK( (int) predBuf.bufs[compID].width > ibcBufferWidth, "IBC access out of bounds." );
2042
2043
0
    const int width   = ibcBufferWidth - refx;
2044
0
    CompArea  srcArea = CompArea( compID, Position( refx, refy ), Size( width, predBuf.bufs[compID].height ) );
2045
0
    CPelBuf   srcBuf  = cu.cs->m_virtualIBCbuf[lineIdx].getBuf( srcArea );
2046
0
    PelBuf    dstBuf  = predBuf.bufs[compID].subBuf( 0, 0, width, predBuf.bufs[compID].height );
2047
0
    dstBuf.copyFrom( srcBuf );
2048
2049
0
    const int remWidth = predBuf.bufs[compID].width - width;
2050
0
    srcArea            = CompArea( compID, Position( 0, refy ), Size( remWidth, predBuf.bufs[compID].height ) );
2051
0
    srcBuf             = cu.cs->m_virtualIBCbuf[lineIdx].getBuf( srcArea );
2052
0
    dstBuf             = predBuf.bufs[compID].subBuf( width, 0, remWidth, predBuf.bufs[compID].height );
2053
0
    dstBuf.copyFrom( srcBuf );
2054
0
  }
2055
0
}
2056
2057
#if JVET_O1170_CHECK_BV_AT_DECODER
2058
void InterPrediction::resetIBCBuffer(const ChromaFormat chromaFormatIDC, const int ctuSize)
2059
{
2060
  const UnitArea area = UnitArea(chromaFormatIDC, Area(0, 0, m_IBCBufferWidth, ctuSize));
2061
  m_IBCBuffer.getBuf(area).fill(-1);
2062
}
2063
2064
void InterPrediction::resetVPDUforIBC(const ChromaFormat chromaFormatIDC, const int ctuSize, const int vSize, const int xPos, const int yPos)
2065
{
2066
  const UnitArea area = UnitArea(chromaFormatIDC, Area(xPos & (m_IBCBufferWidth - 1), yPos & (ctuSize - 1), vSize, vSize));
2067
  m_IBCBuffer.getBuf(area).fill(-1);
2068
}
2069
2070
bool InterPrediction::isLumaBvValid(const int ctuSize, const int xCb, const int yCb, const int width, const int height, const int xBv, const int yBv)
2071
{
2072
  if(((yCb + yBv) & (ctuSize - 1)) + height > ctuSize)
2073
  {
2074
    return false;
2075
  }
2076
  int refTLx = xCb + xBv;
2077
  int refTLy = (yCb + yBv) & (ctuSize - 1);
2078
  PelBuf buf = m_IBCBuffer.Y();
2079
  for(int x = 0; x < width; x += 4)
2080
  {
2081
    for(int y = 0; y < height; y += 4)
2082
    {
2083
      if(buf.at((x + refTLx) & (m_IBCBufferWidth - 1), y + refTLy) == -1) return false;
2084
      if(buf.at((x + 3 + refTLx) & (m_IBCBufferWidth - 1), y + refTLy) == -1) return false;
2085
      if(buf.at((x + refTLx) & (m_IBCBufferWidth - 1), y + 3 + refTLy) == -1) return false;
2086
      if(buf.at((x + 3 + refTLx) & (m_IBCBufferWidth - 1), y + 3 + refTLy) == -1) return false;
2087
    }
2088
  }
2089
  return true;
2090
}
2091
#endif
2092
2093
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 )
2094
0
{
2095
0
  const bool rndRes = !bi;
2096
2097
0
  const int csx = getComponentScaleX( compID, chFmt );
2098
0
  const int csy = getComponentScaleY( compID, chFmt );
2099
2100
0
  const int shiftHor  = MV_FRACTIONAL_BITS_INTERNAL + csx;
2101
0
  const int shiftVer  = MV_FRACTIONAL_BITS_INTERNAL + csy;
2102
2103
0
  const int width     = dstWidth;
2104
0
  const int height    = dstHeight;
2105
2106
0
  const int refPicWidth  = refPic->lwidth();
2107
0
  const int refPicHeight = refPic->lheight();
2108
2109
0
  const PPS* refPPS = refPic->slices[ 0 ]->getPPS();
2110
0
  const auto refBuf = refPic->getRecoBuf( compID, wrapRef );
2111
2112
0
  static constexpr int rprThreshold1 = ( 1 << SCALE_RATIO_BITS ) * 5 / 4;
2113
0
  static constexpr int rprThreshold2 = ( 1 << SCALE_RATIO_BITS ) * 7 / 4;
2114
2115
0
  int xFilter = filterIndex;
2116
0
  if     ( scalingRatio.first > rprThreshold2 ) xFilter = 4;
2117
0
  else if( scalingRatio.first > rprThreshold1 ) xFilter = 3;
2118
2119
0
  int yFilter = filterIndex;
2120
0
  if     ( scalingRatio.second > rprThreshold2 ) yFilter = 4;
2121
0
  else if( scalingRatio.second > rprThreshold1 ) yFilter = 3;
2122
2123
0
  if( isLuma( compID ) && filterIndex == 2 )
2124
0
  {
2125
0
    if( scalingRatio.first  > rprThreshold1 ) xFilter += 2;
2126
0
    if( scalingRatio.second > rprThreshold1 ) yFilter += 2;
2127
0
  }
2128
2129
0
  const int posShift = SCALE_RATIO_BITS - 4;
2130
0
  const int stepX    = ( scalingRatio.first  + 8 ) >> 4;
2131
0
  const int stepY    = ( scalingRatio.second + 8 ) >> 4;
2132
0
  const int offX     = 1 << ( posShift - shiftHor - 1 );
2133
0
  const int offY     = 1 << ( posShift - shiftVer - 1 );
2134
2135
0
  const int64_t posX = ( ( blkPos.x << csx ) - ( pps.getScalingWindow().getWindowLeftOffset() * SPS::getWinUnitX( chFmt ) ) ) >> csx;
2136
0
  const int64_t posY = ( ( blkPos.y << csy ) - ( pps.getScalingWindow().getWindowTopOffset()  * SPS::getWinUnitY( chFmt ) ) ) >> csy;
2137
2138
0
  const int     addX = isLuma( compID ) ? 0 : int( 1 - refPic->cs->sps->getHorCollocatedChromaFlag() ) * 8 * ( scalingRatio.first  - SCALE_1X.first  );
2139
0
  const int     addY = isLuma( compID ) ? 0 : int( 1 - refPic->cs->sps->getVerCollocatedChromaFlag() ) * 8 * ( scalingRatio.second - SCALE_1X.second );
2140
2141
0
  int64_t x0Int = ( ( posX << ( 4 + csx ) ) + mv.getHor() ) * (int64_t) scalingRatio.first + addX;
2142
0
          x0Int = SIGN( x0Int ) * ( ( std::abs( x0Int ) + ( (int64_t) 1 << ( 7 + csx ) ) ) >> ( 8 + csx ) )
2143
0
                + ( ( refPPS->getScalingWindow().getWindowLeftOffset() * SPS::getWinUnitX( chFmt ) ) << ( ( posShift - csx ) ) );
2144
2145
0
  int64_t y0Int = ( ( posY << ( 4 + csy ) ) + mv.getVer() ) * (int64_t) scalingRatio.second + addY;
2146
0
          y0Int = SIGN( y0Int ) * ( ( std::abs( y0Int ) + ( (int64_t) 1 << ( 7 + csy ) ) ) >> ( 8 + csy ) )
2147
0
                  + ( ( refPPS->getScalingWindow().getWindowTopOffset() * SPS::getWinUnitY( chFmt ) ) << ( ( posShift - csy ) ) );
2148
2149
0
  const int extSize = isLuma( compID ) ? 1 : 2;
2150
2151
0
  const int vFilterSize = isLuma( compID ) ? NTAPS_LUMA : NTAPS_CHROMA;
2152
2153
0
  int yInt0 = ( (int32_t) y0Int + offY ) >> posShift;
2154
0
      yInt0 = Clip3( -( NTAPS_LUMA / 2 ), ( refPicHeight >> csy ) + ( NTAPS_LUMA / 2 ), yInt0 );
2155
2156
0
  int xInt0 = ( (int32_t) x0Int + offX ) >> posShift;
2157
0
      xInt0 = Clip3( -( NTAPS_LUMA / 2 ), ( refPicWidth >> csx ) + ( NTAPS_LUMA / 2 ), xInt0 );
2158
2159
0
  int refHeight = ( ( ( (int32_t) y0Int + ( height - 1 ) * stepY ) + offY ) >> posShift )
2160
0
                - ( ( ( (int32_t) y0Int +              0 * stepY ) + offY ) >> posShift ) + 1;
2161
0
  refHeight = std::max<int>( 1, refHeight );
2162
2163
0
  CHECK( MAX_CU_SIZE * MAX_SCALING_RATIO + 16 < refHeight + vFilterSize - 1 + extSize,
2164
0
                     "Buffer size is not enough, scaling more than MAX_SCALING_RATIO" );
2165
2166
0
  Pel buffer[ ( MAX_CU_SIZE + 16 ) * ( MAX_CU_SIZE * MAX_SCALING_RATIO + 16 ) ];
2167
0
  int tmpStride = width;
2168
2169
0
  const int filtHeight = refHeight + vFilterSize - 1 + extSize;
2170
  // only need special case for bottom margin, because all other directions are clamped to -4/+4, which should always fit within the margin
2171
0
  const int maxFiltHeight = std::min( filtHeight, ( (int) ( refPicHeight + refPic->margin ) >> csy ) - yInt0 );
2172
2173
0
  int col;
2174
0
  for( col = 0; col < width; col++ )
2175
0
  {
2176
0
    int posX = (int32_t) x0Int + col * stepX;
2177
0
    int xInt = ( posX + offX ) >> posShift;
2178
0
        xInt = Clip3( -( NTAPS_LUMA / 2 ), ( refPicWidth >> csx ) + ( NTAPS_LUMA / 2 ), xInt );
2179
0
    int xFrac = ( ( posX + offX ) >> ( posShift - shiftHor ) ) & ( ( 1 << shiftHor ) - 1 );
2180
2181
0
    CHECK( xInt0 > xInt, "Wrong horizontal starting point" );
2182
2183
0
    const Pel* refPtr    = refBuf.bufAt( xInt, yInt0 );
2184
0
    ptrdiff_t  refStride = refBuf.stride;
2185
2186
0
    m_if.filterHor( compID,
2187
0
                    GET_OFFSETY( refPtr, refStride, -( vFilterSize / 2 - 1 ) ), refStride,
2188
0
                    GET_OFFSETX( buffer, tmpStride, col ),                      tmpStride,
2189
0
                    1, maxFiltHeight,
2190
0
                    xFrac,
2191
0
                    false,
2192
0
                    chFmt,
2193
0
                    clpRng,
2194
0
                    xFilter,
2195
0
                    useAltHpelIf && scalingRatio.first == SCALE_1X.first );
2196
0
  }
2197
2198
  // fill buffer area where source block reaches out of the source image + bottom margin using pixel values from last filtered column
2199
0
  if( filtHeight > maxFiltHeight )
2200
0
  {
2201
0
    CHECK( maxFiltHeight <= 0, "nothing filtered yet. Reference block completely outside?" );
2202
0
    for( int row = maxFiltHeight; row < filtHeight; ++row )
2203
0
    {
2204
0
      memcpy( &buffer[ tmpStride * row ], &buffer[ tmpStride * ( maxFiltHeight - 1 ) ], width * sizeof( buffer[ 0 ] ) );
2205
0
    }
2206
0
  }
2207
2208
0
  for( int row = 0; row < height; row++ )
2209
0
  {
2210
0
    int posY = (int32_t) y0Int + row * stepY;
2211
0
    int yInt = ( posY + offY ) >> posShift;
2212
0
        yInt = Clip3( -( NTAPS_LUMA / 2 ), ( refPicHeight >> csy ) + ( NTAPS_LUMA / 2 ), yInt );
2213
0
    int yFrac = ( ( posY + offY ) >> ( posShift - shiftVer ) ) & ( ( 1 << shiftVer ) - 1 );
2214
2215
0
    CHECK( yInt0 > yInt, "Wrong vertical starting point" );
2216
2217
0
    m_if.filterVer( compID,
2218
0
                    GET_OFFSETY( buffer, tmpStride, ( yInt - yInt0 ) + ( ( vFilterSize >> 1 ) - 1 ) ), tmpStride,
2219
0
                    GET_OFFSETY( dst, dstStride, row ),                                                dstStride,
2220
0
                    width, 1,
2221
0
                    yFrac,
2222
0
                    false,
2223
0
                    rndRes,
2224
0
                    chFmt,
2225
0
                    clpRng,
2226
0
                    yFilter,
2227
0
                    useAltHpelIf && scalingRatio.second == SCALE_1X.second );
2228
0
  }
2229
0
}
2230
2231
}   // namespace vvdec