Coverage Report

Created: 2026-10-17 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/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) 2019-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVenC Authors.
10
All rights reserved.
11
12
Redistribution and use in source and binary forms, with or without modification,
13
are permitted (subject to the limitations in the disclaimer below) provided that
14
the following conditions are met:
15
16
     * Redistributions of source code must retain the above copyright notice,
17
     this list of conditions and the following disclaimer.
18
19
     * Redistributions in binary form must reproduce the above copyright
20
     notice, this list of conditions and the following disclaimer in the
21
     documentation and/or other materials provided with the distribution.
22
23
     * Neither the name of the copyright holder nor the names of its
24
     contributors may be used to endorse or promote products derived from this
25
     software without specific prior written permission.
26
27
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
28
THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
29
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
31
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
32
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
36
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
POSSIBILITY OF SUCH DAMAGE.
39
40
41
------------------------------------------------------------------------------------------- */
42
43
44
/** \file     Prediction.cpp
45
    \brief    prediction class
46
*/
47
48
#include "InterPrediction.h"
49
#include "Unit.h"
50
#include "UnitTools.h"
51
#include "dtrace_next.h"
52
#include "dtrace_buffer.h"
53
#include "CommonLib/TimeProfiler.h"
54
55
#include <memory.h>
56
#include <algorithm>
57
58
//! \ingroup CommonLib
59
//! \{
60
61
namespace vvenc {
62
63
void addBDOFAvgCore(const Pel* src0, const ptrdiff_t  src0Stride, const Pel* src1, const ptrdiff_t  src1Stride, Pel* dst, const ptrdiff_t dstStride, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel*gradY1, const ptrdiff_t  gradStride, int width, int height, int tmpx, int tmpy, unsigned shift, int offset, const ClpRng& clpRng)
64
0
{
65
0
  int b = 0;
66
67
0
  for (int y = 0; y < height; y++)
68
0
  {
69
0
    for (int x = 0; x < width; x += 4)
70
0
    {
71
0
      b = tmpx * (gradX0[x] - gradX1[x]) + tmpy * (gradY0[x] - gradY1[x]);
72
0
      dst[x] = ClipPel((int16_t)rightShiftU((src0[x] + src1[x] + b + offset), shift), clpRng);
73
74
0
      b = tmpx * (gradX0[x + 1] - gradX1[x + 1]) + tmpy * (gradY0[x + 1] - gradY1[x + 1]);
75
0
      dst[x + 1] = ClipPel((int16_t)rightShiftU((src0[x + 1] + src1[x + 1] + b + offset), shift), clpRng);
76
77
0
      b = tmpx * (gradX0[x + 2] - gradX1[x + 2]) + tmpy * (gradY0[x + 2] - gradY1[x + 2]);
78
0
      dst[x + 2] = ClipPel((int16_t)rightShiftU((src0[x + 2] + src1[x + 2] + b + offset), shift), clpRng);
79
80
0
      b = tmpx * (gradX0[x + 3] - gradX1[x + 3]) + tmpy * (gradY0[x + 3] - gradY1[x + 3]);
81
0
      dst[x + 3] = ClipPel((int16_t)rightShiftU((src0[x + 3] + src1[x + 3] + b + offset), shift), clpRng);
82
0
    }
83
0
    dst += dstStride;       src0 += src0Stride;     src1 += src1Stride;
84
0
    gradX0 += gradStride; gradX1 += gradStride; gradY0 += gradStride; gradY1 += gradStride;
85
0
  }
86
0
}
87
88
void applyPROFCore(Pel* dst, int dstStride, const Pel* src, int srcStride, int width, int height, const Pel* gradX, const Pel* gradY, int gradStride, const int* dMvX, const int* dMvY, int dMvStride, const bool& bi, int shiftNum, Pel offset, const ClpRng& clpRng)
89
0
{
90
0
  int idx = 0;
91
0
  const int dILimit = 1 << std::max<int>(clpRng.bd + 1, 13);
92
0
  for (int h = 0; h < height; h++)
93
0
  {
94
0
    for (int w = 0; w < width; w++)
95
0
    {
96
0
      int32_t dI = dMvX[idx] * gradX[w] + dMvY[idx] * gradY[w];
97
0
      dI = Clip3(-dILimit, dILimit - 1, dI);
98
0
      dst[w] = src[w] + dI;
99
0
      if (!bi)
100
0
      {
101
0
        dst[w] = (dst[w] + offset) >> shiftNum;
102
0
        dst[w] = ClipPel(dst[w], clpRng);
103
0
      }
104
0
      idx++;
105
0
    }
106
0
    gradX += gradStride;
107
0
    gradY += gradStride;
108
0
    dst += dstStride;
109
0
    src += srcStride;
110
0
  }
111
0
}
112
113
template<bool PAD = true>
114
void gradFilterCore(const Pel* pSrc, int srcStride, int width, int height, int gradStride, Pel* gradX, Pel* gradY, const int bitDepth)
115
0
{
116
0
  const Pel* srcTmp = pSrc + srcStride + 1;
117
0
  Pel* gradXTmp = gradX + gradStride + 1;
118
0
  Pel* gradYTmp = gradY + gradStride + 1;
119
0
  int  shift1 = 6;
120
121
0
  for (int y = 0; y < (height - 2 * BDOF_EXTEND_SIZE); y++)
122
0
  {
123
0
    for (int x = 0; x < (width - 2 * BDOF_EXTEND_SIZE); x++)
124
0
    {
125
0
      gradYTmp[x] = ( srcTmp[x + srcStride] >> shift1 ) - ( srcTmp[x - srcStride] >> shift1 );
126
0
      gradXTmp[x] = ( srcTmp[x + 1] >> shift1 ) - ( srcTmp[x - 1] >> shift1 );
127
0
    }
128
0
    gradXTmp += gradStride;
129
0
    gradYTmp += gradStride;
130
0
    srcTmp += srcStride;
131
0
  }
132
133
0
  if (PAD)
134
0
  {
135
0
    gradXTmp = gradX + gradStride + 1;
136
0
    gradYTmp = gradY + gradStride + 1;
137
0
    for (int y = 0; y < (height - 2 * BDOF_EXTEND_SIZE); y++)
138
0
    {
139
0
      gradXTmp[-1] = gradXTmp[0];
140
0
      gradXTmp[width - 2 * BDOF_EXTEND_SIZE] = gradXTmp[width - 2 * BDOF_EXTEND_SIZE - 1];
141
0
      gradXTmp += gradStride;
142
143
0
      gradYTmp[-1] = gradYTmp[0];
144
0
      gradYTmp[width - 2 * BDOF_EXTEND_SIZE] = gradYTmp[width - 2 * BDOF_EXTEND_SIZE - 1];
145
0
      gradYTmp += gradStride;
146
0
    }
147
148
0
    gradXTmp = gradX + gradStride;
149
0
    gradYTmp = gradY + gradStride;
150
0
    ::memcpy(gradXTmp - gradStride, gradXTmp, sizeof(Pel)*(width));
151
0
    ::memcpy(gradXTmp + (height - 2 * BDOF_EXTEND_SIZE)*gradStride, gradXTmp + (height - 2 * BDOF_EXTEND_SIZE - 1)*gradStride, sizeof(Pel)*(width));
152
0
    ::memcpy(gradYTmp - gradStride, gradYTmp, sizeof(Pel)*(width));
153
0
    ::memcpy(gradYTmp + (height - 2 * BDOF_EXTEND_SIZE)*gradStride, gradYTmp + (height - 2 * BDOF_EXTEND_SIZE - 1)*gradStride, sizeof(Pel)*(width));
154
0
  }
155
0
}
Unexecuted instantiation: void vvenc::gradFilterCore<true>(short const*, int, int, int, int, short*, short*, int)
Unexecuted instantiation: void vvenc::gradFilterCore<false>(short const*, int, int, int, int, short*, short*, int)
156
157
void calcBDOFSumsCore( const Pel* srcY0Tmp, const Pel* srcY1Tmp, const Pel* gradX0, const Pel* gradX1,
158
                       const Pel* gradY0, const Pel* gradY1, int xu, int yu, const ptrdiff_t src0Stride, const ptrdiff_t src1Stride,
159
                       const ptrdiff_t widthG, const int bitDepth, int* sumAbsGX, int* sumAbsGY, int* sumDIX, int* sumDIY,
160
                       int* sumSignGY_GX )
161
0
{
162
0
  int shift4 = 4;
163
0
  int shift5 = 1;
164
165
0
  for (int y = 0; y < 6; y++)
166
0
  {
167
0
    for (int x = 0; x < 6; x++)
168
0
    {
169
0
      int tmpGX = (gradX0[x] + gradX1[x]) >> shift5;
170
0
      int tmpGY = (gradY0[x] + gradY1[x]) >> shift5;
171
0
      int tmpDI = (int)((srcY1Tmp[x] >> shift4) - (srcY0Tmp[x] >> shift4));
172
0
      *sumAbsGX += (tmpGX < 0 ? -tmpGX : tmpGX);
173
0
      *sumAbsGY += (tmpGY < 0 ? -tmpGY : tmpGY);
174
0
      *sumDIX += (tmpGX < 0 ? -tmpDI : (tmpGX == 0 ? 0 : tmpDI));
175
0
      *sumDIY += (tmpGY < 0 ? -tmpDI : (tmpGY == 0 ? 0 : tmpDI));
176
0
      *sumSignGY_GX += (tmpGY < 0 ? -tmpGX : (tmpGY == 0 ? 0 : tmpGX));
177
178
0
    }
179
0
    srcY1Tmp += src1Stride;
180
0
    srcY0Tmp += src0Stride;
181
0
    gradX0 += widthG;
182
0
    gradX1 += widthG;
183
0
    gradY0 += widthG;
184
0
    gradY1 += widthG;
185
0
  }
186
0
}
187
188
189
template<int padSize>
190
void paddingCore(Pel *ptr, int stride, int width, int height)
191
0
{
192
  /*left and right padding*/
193
0
  Pel *ptrTemp1 = ptr;
194
0
  Pel *ptrTemp2 = ptr + (width - 1);
195
0
  ptrdiff_t offset = 0;
196
0
  for (int i = 0; i < height; i++)
197
0
  {
198
0
    offset = stride * i;
199
0
    for (int j = 1; j <= padSize; j++)
200
0
    {
201
0
      *(ptrTemp1 - j + offset) = *(ptrTemp1 + offset);
202
0
      *(ptrTemp2 + j + offset) = *(ptrTemp2 + offset);
203
0
    }
204
0
  }
205
  /*Top and Bottom padding*/
206
0
  int numBytes = (width + padSize + padSize) * sizeof(Pel);
207
0
  ptrTemp1 = (ptr - padSize);
208
0
  ptrTemp2 = (ptr + (stride * (height - 1)) - padSize);
209
0
  for (int i = 1; i <= padSize; i++)
210
0
  {
211
0
    memcpy(ptrTemp1 - (i * stride), (ptrTemp1), numBytes);
212
0
    memcpy(ptrTemp2 + (i * stride), (ptrTemp2), numBytes);
213
0
  }
214
0
}
Unexecuted instantiation: void vvenc::paddingCore<1>(short*, int, int, int)
Unexecuted instantiation: void vvenc::paddingCore<2>(short*, int, int, int)
215
216
void padDmvrCore( const Pel* src, const int srcStride, Pel* dst, const int dstStride, int width, int height, int padSize )
217
0
{
218
0
  g_pelBufOP.copyBuffer( ( const char* ) src, srcStride * sizeof( Pel ), ( char* ) dst, dstStride * sizeof( Pel ), width * sizeof( Pel ), height );
219
0
  if( padSize == 1 )
220
0
    paddingCore<1>( dst, dstStride, width, height );
221
0
  else
222
0
    paddingCore<2>( dst, dstStride, width, height );
223
0
}
224
225
// ====================================================================================================================
226
// Constructor / destructor / initialize
227
// ====================================================================================================================
228
229
InterPrediction::InterPrediction()
230
4.62k
  : m_currChromaFormat( NUM_CHROMA_FORMAT )
231
4.62k
  , m_subPuMC(false)
232
4.62k
  , m_IBCBufferWidth(0)
233
4.62k
{
234
4.62k
}
235
236
InterPrediction::~InterPrediction()
237
4.62k
{
238
4.62k
  destroy();
239
4.62k
}
240
241
void InterPrediction::destroy()
242
4.62k
{
243
13.8k
  for( uint32_t i = 0; i < NUM_REF_PIC_LIST_01; i++ )
244
9.24k
  {
245
9.24k
    m_yuvPred[i].destroy();
246
9.24k
  }
247
4.62k
  m_geoPartBuf[0].destroy();
248
4.62k
  m_geoPartBuf[1].destroy();
249
4.62k
  m_IBCBuffer.destroy();
250
4.62k
}
251
252
void InterPrediction::init( RdCost* pcRdCost, ChromaFormat chFormat, const int ctuSize, const int ifpLines )
253
4.62k
{
254
  // if it has been initialised before, but the chroma format has changed, release the memory and start again.
255
4.62k
  if( m_yuvPred[L0].getOrigin( COMP_Y ) != nullptr && m_currChromaFormat != chFormat )
256
0
  {
257
0
    destroy();
258
0
    DMVR::destroy();
259
0
    InterPredInterpolation::destroy();
260
0
  }
261
262
4.62k
  m_currChromaFormat = chFormat;
263
264
4.62k
  if( m_yuvPred[L0].getOrigin( COMP_Y ) == nullptr )
265
4.62k
  {
266
13.8k
    for( uint32_t i = 0; i < NUM_REF_PIC_LIST_01; i++ )
267
9.24k
    {
268
9.24k
      m_yuvPred[i].create( chFormat, Area{ 0, 0, (int)MAX_CU_SIZE, (int)MAX_CU_SIZE }, 0, 0, 32 );
269
9.24k
    }
270
271
4.62k
    InterPredInterpolation::init();
272
4.62k
    DMVR::init( pcRdCost, chFormat );
273
4.62k
    m_geoPartBuf[0].create(UnitArea(chFormat, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
274
4.62k
    m_geoPartBuf[1].create(UnitArea(chFormat, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
275
4.62k
  }
276
4.62k
  if (m_IBCBufferWidth != g_IBCBufferSize / ctuSize)
277
4.62k
  {
278
4.62k
    m_IBCBuffer.destroy();
279
4.62k
  }
280
4.62k
  if (m_IBCBuffer.bufs.empty())
281
4.62k
  {
282
4.62k
    m_IBCBufferWidth = g_IBCBufferSize / ctuSize;
283
4.62k
    m_IBCBuffer.create(UnitArea(chFormat, Area(0, 0, m_IBCBufferWidth, ctuSize)));
284
4.62k
  }
285
4.62k
  InterPredInterpolation::m_ifpLines = ifpLines;
286
4.62k
}
287
288
// ====================================================================================================================
289
// Public member functions
290
// ====================================================================================================================
291
292
bool InterPrediction::xCheckIdenticalMotion( const CodingUnit& cu ) const
293
0
{
294
0
  const Slice &slice = *cu.cs->slice;
295
296
0
  if( slice.isInterB() && !cu.cs->pps->weightedBiPred )
297
0
  {
298
0
    if( cu.refIdx[0] >= 0 && cu.refIdx[1] >= 0 )
299
0
    {
300
0
      int RefPOCL0 = slice.getRefPic( REF_PIC_LIST_0, cu.refIdx[0] )->getPOC();
301
0
      int RefPOCL1 = slice.getRefPic( REF_PIC_LIST_1, cu.refIdx[1] )->getPOC();
302
303
0
      if( RefPOCL0 == RefPOCL1 )
304
0
      {
305
0
        if( !cu.affine )
306
0
        {
307
0
          if( cu.mv[0][0] == cu.mv[1][0] )
308
0
          {
309
0
            return true;
310
0
          }
311
0
        }
312
0
        else
313
0
        {
314
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] ) )
315
0
          {
316
0
            return true;
317
0
          }
318
0
        }
319
0
      }
320
0
    }
321
0
  }
322
323
0
  return false;
324
0
}
325
326
void InterPrediction::xSubPuBDOF( const CodingUnit& cu, PelUnitBuf& predBuf, const RefPicList& refPicList /*= REF_PIC_LIST_X*/)
327
0
{
328
0
  Position puPos = cu.lumaPos();
329
0
  Size puSize = cu.lumaSize();
330
331
0
  CodingUnit subCu = cu;  // th we do not need all that stuff 
332
0
  subCu.cs             = cu.cs;
333
0
  subCu.mergeType      = cu.mergeType;
334
0
  subCu.mmvdMergeFlag  = cu.mmvdMergeFlag;
335
0
  subCu.mcControl      = cu.mcControl;
336
0
  subCu.mergeFlag      = cu.mergeFlag;
337
0
  subCu.ciip           = cu.ciip;
338
0
  subCu.mvRefine       = cu.mvRefine;
339
0
  subCu.refIdx[0]      = cu.refIdx[0];
340
0
  subCu.refIdx[1]      = cu.refIdx[1];
341
342
0
  const int  yEnd      = puPos.y + puSize.height;
343
0
  const int  xEnd      = puPos.x + puSize.width;
344
0
  const int  dy        = std::min((int)MAX_BDOF_APPLICATION_REGION, (int)puSize.height);
345
0
  const int  dx        = std::min((int)MAX_BDOF_APPLICATION_REGION, (int)puSize.width);
346
347
  // BDOF is only applied to CUs with one motion for the whole block, so every sub-block uses the
348
  // motion of the CU. Taking it from the CU rather than from the motion buffer lets the merge search
349
  // skip writing the buffer for every candidate it evaluates.
350
0
  MotionInfo cuMotion;
351
0
  for( int i = 0; i < NUM_REF_PIC_LIST_01; i++ )
352
0
  {
353
0
    cuMotion.mv[i]       = cu.mv[i][0];
354
0
    cuMotion.miRefIdx[i] = cu.refIdx[i];
355
0
  }
356
357
0
  for (int y = puPos.y; y < yEnd; y += dy)
358
0
  {
359
0
    for (int x = puPos.x; x < xEnd; x += dx)
360
0
    {
361
0
      subCu.UnitArea::operator=(UnitArea(cu.chromaFormat, Area(x, y, dx, dy)));
362
0
      subCu = cuMotion;
363
0
      PelUnitBuf subPredBuf = predBuf.subBuf(UnitAreaRelative(cu, subCu));
364
365
0
      motionCompensation(subCu, subPredBuf, refPicList);
366
0
    }
367
0
  }
368
0
}
369
void InterPrediction::xPredInterUni( const CodingUnit &cu, const RefPicList &refPicList, PelUnitBuf &pcYuvPred, const bool bi, const bool bdofApplied )
370
21.1k
{
371
21.1k
  int iRefIdx = cu.refIdx[refPicList];
372
21.1k
  Mv mv[3];
373
21.1k
  bool isIBC = false;
374
21.1k
  CHECK(!CU::isIBC(cu) && cu.lwidth() == 4 && cu.lheight() == 4, "invalid 4x4 inter blocks");
375
21.1k
  if (CU::isIBC(cu))
376
21.1k
  {
377
21.1k
    isIBC = true;
378
21.1k
  }
379
21.1k
  if (cu.affine)
380
0
  {
381
0
    CHECK(iRefIdx < 0, "iRefIdx incorrect.");
382
383
0
    mv[0] = cu.mv[refPicList][0];
384
0
    mv[1] = cu.mv[refPicList][1];
385
0
    mv[2] = cu.mv[refPicList][2];
386
0
  }
387
21.1k
  else
388
21.1k
  {
389
21.1k
    mv[0] = cu.mv[refPicList][0];
390
21.1k
    if (!isIBC )
391
0
      clipMv(mv[0], cu.lumaPos(), cu.lumaSize(), *cu.cs->pcv);
392
21.1k
  }
393
394
84.5k
  for( uint32_t comp = COMP_Y; comp < pcYuvPred.bufs.size(); comp++ )
395
63.4k
  {
396
63.4k
    const ComponentID compID = ComponentID( comp );
397
398
63.4k
    bool luma   = !cu.mccNoLuma  ();
399
63.4k
    bool chroma = !cu.mccNoChroma();
400
401
63.4k
    if( compID == COMP_Y && !luma )
402
0
      continue;
403
63.4k
    if( compID != COMP_Y && !chroma )
404
42.2k
      continue;
405
406
21.1k
    if( cu.affine )
407
0
    {
408
0
      xPredAffineBlk( compID, cu, cu.slice->getRefPic( refPicList, iRefIdx ), mv, pcYuvPred, bi, cu.slice->clpRngs[ compID ], refPicList );
409
0
    }
410
21.1k
    else
411
21.1k
    {
412
21.1k
      if( isIBC )
413
21.1k
      {
414
21.1k
        xPredInterBlk( compID, cu, cu.slice->pic, mv[ 0 ], pcYuvPred, bi, cu.slice->clpRngs[ compID ], bdofApplied, isIBC );
415
21.1k
      }
416
0
      else
417
0
      {
418
0
        xPredInterBlk( compID, cu, cu.slice->getRefPic( refPicList, iRefIdx ), mv[ 0 ], pcYuvPred, bi, cu.slice->clpRngs[ compID ], bdofApplied, isIBC, refPicList );
419
0
      }
420
21.1k
    }
421
21.1k
  }
422
21.1k
}
423
424
void InterPrediction::xPredInterBi( const CodingUnit& cu, PelUnitBuf& yuvPred, const bool bdofApplied, PelUnitBuf *yuvPredTmp )
425
0
{
426
0
  CHECK( !cu.affine && cu.refIdx[0] >= 0 && cu.refIdx[1] >= 0 && ( cu.lwidth() + cu.lheight() == 12 ), "invalid 4x8/8x4 bi-predicted blocks" );
427
428
0
  PelUnitBuf puBuf[NUM_REF_PIC_LIST_01];
429
0
  for (uint32_t refList = 0; refList < NUM_REF_PIC_LIST_01; refList++)
430
0
  {
431
0
    if( cu.refIdx[refList] < 0)
432
0
    {
433
0
      continue;
434
0
    }
435
436
0
    RefPicList refPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
437
438
0
    CHECK(CU::isIBC(cu) && refPicList != REF_PIC_LIST_0, "Invalid interdir for ibc mode");
439
0
    CHECK(CU::isIBC(cu) && cu.refIdx[refList] != MAX_NUM_REF, "Invalid reference index for ibc mode");
440
0
    CHECK((CU::isInter(cu) && cu.refIdx[refList] >= cu.cs->slice->numRefIdx[ refPicList ]), "Invalid reference index");
441
442
0
    puBuf[refList] = m_yuvPred[refList].getCompactBuf( cu );
443
444
0
    if( cu.refIdx[0] >= 0 && cu.refIdx[1] >= 0 )
445
0
    {
446
0
      xPredInterUni ( cu, refPicList, puBuf[refList], true, bdofApplied );
447
0
    }
448
0
    else
449
0
    {
450
0
      xPredInterUni( cu, refPicList, puBuf[refList], cu.geo, bdofApplied );
451
0
    }
452
0
  }
453
454
0
  xWeightedAverage( cu, puBuf[0], puBuf[1], yuvPred, bdofApplied, yuvPredTmp );
455
0
}
456
457
void InterPrediction::motionCompensationIBC( CodingUnit& cu, PelUnitBuf& predBuf )
458
21.1k
{
459
  // dual tree handling for IBC as the only ref
460
21.1k
  xPredInterUni( cu, REF_PIC_LIST_0, predBuf, false, false );
461
21.1k
}
462
463
bool InterPrediction::motionCompensation( CodingUnit& cu, PelUnitBuf& predBuf, const RefPicList& refPicList, PelUnitBuf* predBufDfltWght )
464
0
{
465
0
  bool ret = false;
466
0
  if( refPicList != REF_PIC_LIST_X )
467
0
  {
468
0
    xPredInterUni( cu, refPicList, predBuf, false, false );
469
0
  }
470
0
  else
471
0
  {
472
0
    CHECK( !cu.affine && cu.refIdx[0] >= 0 && cu.refIdx[1] >= 0 && ( cu.lwidth() + cu.lheight() == 12 ), "Invalid 4x8/8x4 bi-predicted blocks" );
473
474
0
    bool bdofApplied = false;
475
0
    if( cu.cs->sps->BDOF && ( !cu.cs->picHeader->disBdofFlag ) )
476
0
    {
477
0
      if( cu.affine || m_subPuMC || cu.ciip )
478
0
      {
479
0
        bdofApplied = false;
480
0
      }
481
0
      else
482
0
      {
483
0
        if( CU::isBiPredFromDifferentDirEqDistPoc( cu )
484
0
            &&    cu.Y().minDim() >= 8
485
0
            &&    cu.Y().area() >= 128
486
0
            &&   !cu.smvdMode
487
0
            && !( cu.cs->sps->BCW && cu.BcwIdx != BCW_DEFAULT )
488
0
            && !( cu.mccNoBdof() && cu.mmvdMergeFlag ) )
489
0
        {
490
0
          bdofApplied = true;
491
0
        }
492
0
      }
493
0
    }
494
495
0
    bool dmvrApplied = cu.mvRefine && CU::checkDMVRCondition( cu );
496
0
    if( cu.lumaSize().maxDim() > MAX_BDOF_APPLICATION_REGION && cu.mergeType != MRG_TYPE_SUBPU_ATMVP && bdofApplied && !dmvrApplied )
497
0
    {
498
0
      xSubPuBDOF( cu, predBuf, refPicList );
499
0
    }
500
0
    else if (cu.mergeType != MRG_TYPE_DEFAULT_N && cu.mergeType != MRG_TYPE_IBC)
501
0
    {
502
0
      xSubPuMC(cu, predBuf, refPicList);
503
0
    }
504
0
    else if( xCheckIdenticalMotion( cu ) )
505
0
    {
506
0
      xPredInterUni( cu, REF_PIC_LIST_0, predBuf, false, false );
507
508
0
      if( predBufDfltWght )
509
0
      {
510
0
        predBufDfltWght->copyFrom( predBuf );
511
0
      }
512
0
    }
513
0
    else if( dmvrApplied )
514
0
    {
515
0
      xProcessDMVR( cu, predBuf, cu.slice->clpRngs, bdofApplied );
516
0
    }
517
0
    else
518
0
    {
519
0
      xPredInterBi( cu, predBuf, bdofApplied, predBufDfltWght );
520
0
    }
521
522
0
    DTRACE( g_trace_ctx, D_MOT_COMP, "BDOF=%d, DMVR=%d\n", bdofApplied, dmvrApplied );
523
0
    ret = bdofApplied || dmvrApplied;
524
0
  }
525
526
0
  DTRACE( g_trace_ctx, D_MOT_COMP, "MV=%d,%d\n", cu.mv[0][0].hor, cu.mv[0][0].ver );
527
0
  DTRACE( g_trace_ctx, D_MOT_COMP, "MV=%d,%d\n", cu.mv[1][0].hor, cu.mv[1][0].ver );
528
0
  DTRACE_PEL_BUF( D_MOT_COMP, predBuf.Y(), cu, cu.predMode, COMP_Y );
529
0
  if( cu.chromaFormat != VVENC_CHROMA_400 )
530
0
  {
531
0
    DTRACE_PEL_BUF( D_MOT_COMP, predBuf.Cb(), cu, cu.predMode, COMP_Cb );
532
0
    DTRACE_PEL_BUF( D_MOT_COMP, predBuf.Cr(), cu, cu.predMode, COMP_Cr );
533
0
  }
534
535
0
  return ret;
536
0
}
537
538
void InterPrediction::xSubPuMC(CodingUnit& cu, PelUnitBuf& predBuf, const RefPicList& eRefPicList /*= REF_PIC_LIST_X*/)
539
0
{
540
0
  Position puPos  = cu.lumaPos();
541
0
  Size     puSize = cu.lumaSize();
542
543
0
  int numPartLine = std::max( puSize.width  >> ATMVP_SUB_BLOCK_SIZE, 1u );
544
0
  int numPartCol  = std::max( puSize.height >> ATMVP_SUB_BLOCK_SIZE, 1u );
545
0
  int puHeight    = numPartCol == 1 ? puSize.height : 1 << ATMVP_SUB_BLOCK_SIZE;
546
0
  int puWidth     = numPartLine == 1 ? puSize.width : 1 << ATMVP_SUB_BLOCK_SIZE;
547
548
0
  CodingUnit subCu = cu;
549
0
  subCu.cs = cu.cs;
550
0
  subCu.mergeType = MRG_TYPE_DEFAULT_N;
551
552
0
  bool isAffine = cu.affine;
553
0
  subCu.affine = false;
554
555
  // join sub-pus containing the same motion
556
0
  bool verMC    = puSize.height > puSize.width;
557
0
  int  fstStart = (!verMC ? puPos.y : puPos.x);
558
0
  int  secStart = (!verMC ? puPos.x : puPos.y);
559
0
  int  fstEnd   = (!verMC ? puPos.y + puSize.height : puPos.x + puSize.width);
560
0
  int  secEnd   = (!verMC ? puPos.x + puSize.width : puPos.y + puSize.height);
561
0
  int  fstStep  = (!verMC ? puHeight : puWidth);
562
0
  int  secStep  = (!verMC ? puWidth : puHeight);
563
564
0
  cu.refIdx[0] = 0;
565
0
  cu.refIdx[1] = cu.cs->slice->sliceType == VVENC_B_SLICE ? 0 : -1;
566
0
  bool scaled = false;//!CU::isRefPicSameSize(cu);
567
568
0
  m_subPuMC = true;
569
570
0
  for (int fstDim = fstStart; fstDim < fstEnd; fstDim += fstStep)
571
0
  {
572
0
    for (int secDim = secStart; secDim < secEnd; secDim += secStep)
573
0
    {
574
0
      int x = !verMC ? secDim : fstDim;
575
0
      int y = !verMC ? fstDim : secDim;
576
0
      const MotionInfo &curMi = cu.getMotionInfo(Position{ x, y });
577
578
0
      int length = secStep;
579
0
      int later = secDim + secStep;
580
581
0
      while (later < secEnd)
582
0
      {
583
0
        const MotionInfo &laterMi = !verMC ? cu.getMotionInfo(Position{ later, fstDim }) : cu.getMotionInfo(Position{ fstDim, later });
584
0
        if (!scaled && laterMi == curMi)
585
0
        {
586
0
          length += secStep;
587
0
        }
588
0
        else
589
0
        {
590
0
          break;
591
0
        }
592
0
        later += secStep;
593
0
      }
594
0
      int dx = !verMC ? length : puWidth;
595
0
      int dy = !verMC ? puHeight : length;
596
597
0
      subCu.UnitArea::operator=(UnitArea(cu.chromaFormat, Area(x, y, dx, dy)));
598
0
      subCu = curMi;
599
0
      PelUnitBuf subPredBuf = predBuf.subBuf(UnitAreaRelative(cu, subCu));
600
0
      subCu.mcControl = (cu.mcControl >> 1) << 1;
601
0
      subCu.mvRefine = false;
602
0
      motionCompensation(subCu, subPredBuf, eRefPicList);
603
0
      secDim = later - secStep;
604
0
    }
605
0
  }
606
0
  m_subPuMC = false;
607
608
0
  cu.affine = isAffine;
609
0
}
610
611
static inline int xRightShiftMSB( int numer, int denom )
612
0
{
613
0
  return numer >> floorLog2( denom );
614
0
}
615
616
void xFpBiDirOptFlowCore( const Pel* srcY0, const Pel* srcY1, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0,
617
                          const Pel* gradY1, const int width, const int height, Pel* dstY, const ptrdiff_t dstStride,
618
                          const int shiftNum, const int offset, const int limit, const ClpRng& clpRng,
619
                          const int bitDepth )
620
0
{
621
0
  int xUnit = width >> 2;
622
0
  int yUnit = height >> 2;
623
0
  ptrdiff_t widthG = width + 2 * BDOF_EXTEND_SIZE;
624
625
0
  ptrdiff_t offsetPos = widthG * BDOF_EXTEND_SIZE + BDOF_EXTEND_SIZE;
626
0
  ptrdiff_t stridePredMC = widthG + 2;
627
628
0
  const ptrdiff_t  src0Stride = stridePredMC;
629
0
  const ptrdiff_t  src1Stride = stridePredMC;
630
631
0
  const Pel* srcY0Temp = srcY0;
632
0
  const Pel* srcY1Temp = srcY1;
633
634
0
  for( int yu = 0; yu < yUnit; yu++ )
635
0
  {
636
0
    for( int xu = 0; xu < xUnit; xu++ )
637
0
    {
638
0
      int tmpx = 0, tmpy = 0;
639
0
      int sumAbsGX = 0, sumAbsGY = 0, sumDIX = 0, sumDIY = 0;
640
0
      int sumSignGY_GX = 0;
641
642
0
      const Pel* pGradX0Tmp = gradX0 + ( xu << 2 ) + ( yu << 2 ) * widthG;
643
0
      const Pel* pGradX1Tmp = gradX1 + ( xu << 2 ) + ( yu << 2 ) * widthG;
644
0
      const Pel* pGradY0Tmp = gradY0 + ( xu << 2 ) + ( yu << 2 ) * widthG;
645
0
      const Pel* pGradY1Tmp = gradY1 + ( xu << 2 ) + ( yu << 2 ) * widthG;
646
0
      const Pel* SrcY1Tmp = srcY1 + ( xu << 2 ) + ( yu << 2 ) * src1Stride;
647
0
      const Pel* SrcY0Tmp = srcY0 + ( xu << 2 ) + ( yu << 2 ) * src0Stride;
648
649
0
      calcBDOFSumsCore( SrcY0Tmp, SrcY1Tmp, pGradX0Tmp, pGradX1Tmp, pGradY0Tmp, pGradY1Tmp, xu, yu, src0Stride,
650
0
                        src1Stride, widthG, bitDepth, &sumAbsGX, &sumAbsGY, &sumDIX, &sumDIY, &sumSignGY_GX );
651
0
      tmpx = ( sumAbsGX == 0 ? 0 : xRightShiftMSB( 4 * sumDIX, sumAbsGX ) );
652
0
      tmpx = Clip3( -limit, limit, tmpx );
653
654
0
      const int tmpData = sumSignGY_GX * tmpx >> 1;
655
0
      tmpy = ( sumAbsGY == 0 ? 0 : xRightShiftMSB( ( 4 * sumDIY - tmpData ), sumAbsGY ) );
656
0
      tmpy = Clip3( -limit, limit, tmpy );
657
658
0
      srcY0Temp = srcY0 + ( stridePredMC + 1 ) + ( ( yu * src0Stride + xu ) << 2 );
659
0
      srcY1Temp = srcY1 + ( stridePredMC + 1 ) + ( ( yu * src0Stride + xu ) << 2 );
660
0
      pGradX0Tmp = gradX0 + offsetPos + ( ( yu * widthG + xu ) << 2 );
661
0
      pGradX1Tmp = gradX1 + offsetPos + ( ( yu * widthG + xu ) << 2 );
662
0
      pGradY0Tmp = gradY0 + offsetPos + ( ( yu * widthG + xu ) << 2 );
663
0
      pGradY1Tmp = gradY1 + offsetPos + ( ( yu * widthG + xu ) << 2 );
664
665
0
      Pel* dstY0 = dstY + ( ( yu * dstStride + xu ) << 2 );
666
0
      addBDOFAvgCore( srcY0Temp, src0Stride, srcY1Temp, src1Stride, dstY0, dstStride, pGradX0Tmp, pGradX1Tmp,
667
0
                      pGradY0Tmp, pGradY1Tmp, widthG, ( 1 << 2 ), ( 1 << 2 ), tmpx, tmpy, shiftNum, offset, clpRng );
668
0
    } // xu
669
0
  } // yu
670
0
}
671
672
InterPredInterpolation::InterPredInterpolation()
673
4.62k
  : m_storedMv(nullptr)
674
4.62k
  , m_skipPROF(false)
675
4.62k
  , m_encOnly(false)
676
4.62k
  , m_isBi(false)
677
4.62k
  , m_ifpLines(0)
678
4.62k
{
679
680
4.62k
}
681
682
InterPredInterpolation::~InterPredInterpolation()
683
4.62k
{
684
4.62k
  destroy();
685
4.62k
}
686
687
void InterPredInterpolation::destroy()
688
4.62k
{
689
18.4k
  for( uint32_t c = 0; c < MAX_NUM_COMP; c++ )
690
13.8k
  {
691
69.3k
    for( uint32_t i = 0; i < LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS_SIGNAL; i++ )
692
55.4k
    {
693
277k
      for( uint32_t j = 0; j < LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS_SIGNAL; j++ )
694
221k
      {
695
221k
        xFree( m_filteredBlock[i][j][c] );
696
221k
        m_filteredBlock[i][j][c] = nullptr;
697
221k
      }
698
699
55.4k
      xFree( m_filteredBlockTmp[i][c] );
700
55.4k
      m_filteredBlockTmp[i][c] = nullptr;
701
55.4k
    }
702
13.8k
  }
703
4.62k
  xFree(m_gradX0);   m_gradX0 = nullptr;
704
4.62k
  xFree(m_gradY0);   m_gradY0 = nullptr;
705
4.62k
  xFree(m_gradX1);   m_gradX1 = nullptr;
706
4.62k
  xFree(m_gradY1);   m_gradY1 = nullptr;
707
708
4.62k
  if (m_storedMv != nullptr)
709
4.62k
  {
710
4.62k
    delete[] m_storedMv;
711
4.62k
    m_storedMv = nullptr;
712
4.62k
  }
713
4.62k
}
714
715
void InterPredInterpolation::init( bool enableOpt )
716
4.62k
{
717
18.4k
  for( uint32_t c = 0; c < MAX_NUM_COMP; c++ )
718
13.8k
  {
719
13.8k
    int extWidth = MAX_CU_SIZE + (2 * BDOF_EXTEND_SIZE + 2) + 16;
720
13.8k
    int extHeight = MAX_CU_SIZE + (2 * BDOF_EXTEND_SIZE + 2) + 1;
721
13.8k
    extWidth = extWidth > (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + 16) ? extWidth : MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + 16;
722
13.8k
    extHeight = extHeight > (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + 1) ? extHeight : MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + 1;
723
69.3k
    for( uint32_t i = 0; i < LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS_SIGNAL; i++ )
724
55.4k
    {
725
55.4k
      m_filteredBlockTmp[i][c] = ( Pel* ) xMalloc( Pel, ( extWidth + 4 ) * ( extHeight + 7 + 4 ) );
726
55.4k
      VALGRIND_MEMCLEAR( m_filteredBlockTmp[i][c], sizeof( Pel ) * (extWidth + 4) * (extHeight + 7 + 4) );
727
728
277k
      for( uint32_t j = 0; j < LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS_SIGNAL; j++ )
729
221k
      {
730
        // Only the fractional luma motion search reads the quarter-sample filtered blocks, so the
731
        // chroma ones are not allocated. That saves 32 blocks of about 39 KB per encoder thread.
732
221k
        if( c != COMP_Y )
733
147k
        {
734
147k
          m_filteredBlock[i][j][c] = nullptr;
735
147k
          continue;
736
147k
        }
737
73.9k
        m_filteredBlock[i][j][c] = ( Pel* ) xMalloc( Pel, extWidth * extHeight );
738
73.9k
        VALGRIND_MEMCLEAR( m_filteredBlock[i][j][c], sizeof( Pel ) * extWidth * extHeight );
739
73.9k
      }
740
55.4k
    }
741
13.8k
  }
742
743
4.62k
  m_gradX0 = (Pel*)xMalloc(Pel, BDOF_TEMP_BUFFER_SIZE);
744
4.62k
  m_gradY0 = (Pel*)xMalloc(Pel, BDOF_TEMP_BUFFER_SIZE);
745
4.62k
  m_gradX1 = (Pel*)xMalloc(Pel, BDOF_TEMP_BUFFER_SIZE);
746
4.62k
  m_gradY1 = (Pel*)xMalloc(Pel, BDOF_TEMP_BUFFER_SIZE);
747
748
4.62k
  VALGRIND_MEMCLEAR( m_gradX0, sizeof( Pel ) * BDOF_TEMP_BUFFER_SIZE );
749
4.62k
  VALGRIND_MEMCLEAR( m_gradY0, sizeof( Pel ) * BDOF_TEMP_BUFFER_SIZE );
750
4.62k
  VALGRIND_MEMCLEAR( m_gradX1, sizeof( Pel ) * BDOF_TEMP_BUFFER_SIZE );
751
4.62k
  VALGRIND_MEMCLEAR( m_gradY1, sizeof( Pel ) * BDOF_TEMP_BUFFER_SIZE );
752
753
4.62k
  m_if.initInterpolationFilter( true );
754
755
4.62k
  xFpBiDirOptFlow   = xFpBiDirOptFlowCore;
756
4.62k
  xFpBDOFGradFilter = gradFilterCore;
757
4.62k
  xFpProfGradFilter = gradFilterCore<false>;
758
4.62k
  xFpApplyPROF      = applyPROFCore;
759
4.62k
  xFpPadDmvr        = padDmvrCore;
760
761
4.62k
  if( enableOpt )
762
4.62k
  {
763
#if ENABLE_SIMD_OPT_BDOF && defined( TARGET_SIMD_X86 )
764
    initInterPredictionX86();
765
#endif
766
#if ENABLE_SIMD_OPT_BDOF && defined( TARGET_SIMD_ARM )
767
    initInterPredictionARM();
768
#endif
769
4.62k
  }
770
771
4.62k
  if (m_storedMv == nullptr)
772
4.62k
  {
773
4.62k
    const int MVBUFFER_SIZE = MAX_CU_SIZE / MIN_PU_SIZE;
774
4.62k
    m_storedMv = new Mv[MVBUFFER_SIZE*MVBUFFER_SIZE];
775
#if ENABLE_VALGRIND_CODE
776
    for( int i = 0; i < MVBUFFER_SIZE * MVBUFFER_SIZE; i++ )
777
    {
778
      m_storedMv[i].setZero();
779
    }
780
#endif
781
4.62k
  }
782
4.62k
}
783
784
void InterPredInterpolation::xPredInterBlk( const ComponentID compID, const CodingUnit &cu,
785
                                            const Picture *refPic, const Mv &_mv, PelUnitBuf &dstPic,
786
                                            const bool bi, const ClpRng &clpRng, const bool bdofApplied, const bool isIBC, const RefPicList refPicList,
787
                                            const SizeType dmvrWidth, const SizeType dmvrHeight,
788
                                            const bool bilinearMC, const Pel *srcPadBuf, const int32_t srcPadStride )
789
21.1k
{
790
21.1k
  const ChromaFormat  chFmt = cu.chromaFormat;
791
21.1k
  const bool          rndRes = !bi;
792
793
21.1k
  int shiftHor = MV_FRACTIONAL_BITS_INTERNAL + getComponentScaleX(compID, chFmt);
794
21.1k
  int shiftVer = MV_FRACTIONAL_BITS_INTERNAL + getComponentScaleY(compID, chFmt);
795
796
21.1k
  Mv    mv(_mv);
797
798
21.1k
  CHECKD( m_ifpLines && !srcPadBuf && cu.cs->picture != refPic && !CU::isMvInRangeFPP( cu[compID].y, cu[compID].height, mv.ver, m_ifpLines, *cu.cs->pcv, getComponentScaleY(compID, chFmt) ), "xPredInterBlk: CTU line-wise FPP MV restriction failed!\n" );
799
800
21.1k
  int xFrac = mv.hor & ((1 << shiftHor) - 1);
801
21.1k
  int yFrac = mv.ver & ((1 << shiftVer) - 1);
802
21.1k
  if (isIBC)
803
21.1k
  {
804
21.1k
    xFrac = yFrac = 0;
805
21.1k
  }
806
807
21.1k
  PelBuf& dstBuf  = dstPic.bufs[compID];
808
21.1k
  unsigned width  = dstBuf.width;
809
21.1k
  unsigned height = dstBuf.height;
810
811
21.1k
  const Pel* refBufPtr;
812
21.1k
  int        refBufStride;
813
814
21.1k
  if( srcPadBuf )
815
0
  {
816
0
    refBufPtr    = srcPadBuf;
817
0
    refBufStride = srcPadStride;
818
0
  }
819
21.1k
  else
820
21.1k
  {
821
21.1k
    Position offset = cu.blocks[compID].pos().offset( mv.hor >> shiftHor, mv.ver >> shiftVer );
822
21.1k
    refBufPtr       = refPic->getRecoBufPtr   ( compID );
823
21.1k
    refBufStride    = refPic->getRecoBufStride( compID );
824
21.1k
    refBufPtr      += offset.x;
825
21.1k
    refBufPtr      += offset.y * refBufStride;
826
21.1k
  }
827
828
21.1k
  if( dmvrWidth )
829
0
  {
830
0
    width  = dmvrWidth;
831
0
    height = dmvrHeight;
832
0
  }
833
  // backup data
834
21.1k
  const int backupWidth = width;
835
21.1k
  const int backupHeight = height;
836
21.1k
  Pel* backupDstBufPtr = dstBuf.buf;
837
21.1k
  int backupDstBufStride = dstBuf.stride;
838
21.1k
  if( bdofApplied && compID == COMP_Y )
839
0
  {
840
0
    width = width + 2 * BDOF_EXTEND_SIZE + 2;
841
0
    height = height + 2 * BDOF_EXTEND_SIZE + 2;
842
843
    // change MC output
844
0
    CHECK( refPicList >= NUM_REF_PIC_LIST_01, "Wrong refpiclist" );
845
0
    dstBuf.stride = width;
846
0
    dstBuf.buf = m_filteredBlockTmp[2 + refPicList][compID] + 2 * dstBuf.stride + 2;
847
0
  }
848
21.1k
  bool useAltHpelIf = cu.imv == IMV_HPEL;
849
850
21.1k
  if( bilinearMC )
851
0
  {
852
0
    m_if.filterN2_2D( compID, refBufPtr, refBufStride, dstBuf.buf, dstBuf.stride, width, height, xFrac, yFrac, clpRng );
853
0
  }
854
21.1k
  else if( yFrac == 0 )
855
21.1k
  {
856
21.1k
    m_if.filterHor(compID, refBufPtr, refBufStride, dstBuf.buf, dstBuf.stride, backupWidth, backupHeight, xFrac, rndRes, chFmt, clpRng, useAltHpelIf, 0);
857
21.1k
  }
858
0
  else if( xFrac == 0 )
859
0
  {
860
0
    m_if.filterVer(compID, refBufPtr, refBufStride, dstBuf.buf, dstBuf.stride, backupWidth, backupHeight, yFrac, true, rndRes, chFmt, clpRng, useAltHpelIf, 0);
861
0
  }
862
0
  else if( backupWidth == 4 && backupHeight == 4 )
863
0
  {
864
0
    m_if.filter4x4( compID, refBufPtr, refBufStride ,(Pel*)dstBuf.buf, dstBuf.stride, 4, 4, xFrac, yFrac, rndRes, chFmt, clpRng, useAltHpelIf );
865
0
  }
866
0
  else if( backupWidth == 16 )
867
0
  {
868
0
    m_if.filter16xH( compID, refBufPtr, refBufStride, dstBuf.buf, dstBuf.stride, 16, backupHeight, xFrac, yFrac, rndRes, chFmt, clpRng, useAltHpelIf );
869
0
  }
870
0
  else if( backupWidth == 8 )
871
0
  {
872
0
    m_if.filter8xH( compID, refBufPtr, refBufStride, dstBuf.buf, dstBuf.stride, 8, backupHeight, xFrac, yFrac, rndRes, chFmt, clpRng, useAltHpelIf );
873
0
  }
874
0
  else
875
0
  {
876
0
    const int vFilterSize = isLuma( compID ) ? NTAPS_LUMA : NTAPS_CHROMA;
877
878
0
    PelBuf tmpBuf( m_filteredBlockTmp[0][compID], dmvrWidth ? dmvrWidth : dstBuf.stride, dmvrWidth ? Size( dmvrWidth, dmvrHeight ) : cu.blocks[compID].size() );
879
880
0
    m_if.filterHor(compID, refBufPtr -  ((vFilterSize >> 1) - 1) * refBufStride,  refBufStride,  tmpBuf.buf, tmpBuf.stride, backupWidth, backupHeight + vFilterSize - 1, xFrac, false, chFmt, clpRng, useAltHpelIf, 0);
881
0
    m_if.filterVer(compID, tmpBuf.buf + ((vFilterSize >> 1) - 1) * tmpBuf.stride, tmpBuf.stride, dstBuf.buf, dstBuf.stride, backupWidth, backupHeight, yFrac, false, rndRes, chFmt, clpRng, useAltHpelIf, 0);
882
0
  }
883
884
21.1k
  if (bdofApplied && compID == COMP_Y)
885
0
  {
886
0
    const unsigned shift = std::max<int>(2, (IF_INTERNAL_PREC - clpRng.bd));
887
0
    int xOffset = (xFrac < 8) ? 1 : 0;
888
0
    int yOffset = (yFrac < 8) ? 1 : 0;
889
0
    const Pel* refPel = refBufPtr - yOffset * refBufStride - xOffset;
890
0
    Pel* dstPel = m_filteredBlockTmp[2 + refPicList][compID] + dstBuf.stride + 1;
891
0
    for (int w = 0; w < (width - 2 * BDOF_EXTEND_SIZE); w++)
892
0
    {
893
0
      Pel val = leftShiftU(refPel[w], shift);
894
0
      dstPel[w] = val - (Pel)IF_INTERNAL_OFFS;
895
0
    }
896
897
0
    refPel = refBufPtr + (1 - yOffset)*refBufStride - xOffset;
898
0
    dstPel = m_filteredBlockTmp[2 + refPicList][compID] + 2 * dstBuf.stride + 1;
899
0
    for (int h = 0; h < (height - 2 * BDOF_EXTEND_SIZE - 2); h++)
900
0
    {
901
0
      Pel val = leftShiftU(refPel[0], shift);
902
0
      dstPel[0] = val - (Pel)IF_INTERNAL_OFFS;
903
904
0
      val = leftShiftU(refPel[width - 3], shift);
905
0
      dstPel[width - 3] = val - (Pel)IF_INTERNAL_OFFS;
906
907
0
      refPel += refBufStride;
908
0
      dstPel += dstBuf.stride;
909
0
    }
910
911
0
    refPel = refBufPtr + (height - 2 * BDOF_EXTEND_SIZE - 2 + 1 - yOffset)*refBufStride - xOffset;
912
0
    dstPel = m_filteredBlockTmp[2 + refPicList][compID] + (height - 2 * BDOF_EXTEND_SIZE)*dstBuf.stride + 1;
913
0
    for (int w = 0; w < (width - 2 * BDOF_EXTEND_SIZE); w++)
914
0
    {
915
0
      Pel val = leftShiftU(refPel[w], shift);
916
0
      dstPel[w] = val - (Pel)IF_INTERNAL_OFFS;
917
0
    }
918
919
    // restore data
920
0
    width         = backupWidth;
921
0
    height        = backupHeight;
922
0
    dstBuf.buf    = backupDstBufPtr;
923
0
    dstBuf.stride = backupDstBufStride;
924
0
  }
925
21.1k
}
926
927
void InterPredInterpolation::xApplyBDOF( PelBuf& yuvDst, const ClpRng& clpRng )
928
0
{
929
0
  const int     bitDepth  = clpRng.bd;
930
931
0
  const int     height    = yuvDst.height;
932
0
  const int     width     = yuvDst.width;
933
0
  int           heightG   = height + 2 * BDOF_EXTEND_SIZE;
934
0
  int           widthG    = width + 2 * BDOF_EXTEND_SIZE;
935
936
0
  Pel*          gradX0 = m_gradX0;
937
0
  Pel*          gradX1 = m_gradX1;
938
0
  Pel*          gradY0 = m_gradY0;
939
0
  Pel*          gradY1 = m_gradY1;
940
941
0
  int           stridePredMC = widthG + 2;
942
0
  const Pel*    srcY0 = m_filteredBlockTmp[2][COMP_Y] + stridePredMC + 1;
943
0
  const Pel*    srcY1 = m_filteredBlockTmp[3][COMP_Y] + stridePredMC + 1;
944
945
0
  Pel*          dstY = yuvDst.buf;
946
0
  const int dstStride = yuvDst.stride;
947
948
0
  for (int refList = 0; refList < NUM_REF_PIC_LIST_01; refList++)
949
0
  {
950
0
    Pel* dstTempPtr = m_filteredBlockTmp[2 + refList][COMP_Y] + stridePredMC + 1;
951
0
    Pel* gradY = (refList == 0) ? m_gradY0 : m_gradY1;
952
0
    Pel* gradX = (refList == 0) ? m_gradX0 : m_gradX1;
953
954
0
    xFpBDOFGradFilter(dstTempPtr, stridePredMC, widthG, heightG, widthG, gradX, gradY, bitDepth );
955
0
    Pel* padStr = m_filteredBlockTmp[2 + refList][COMP_Y] + 2 * stridePredMC + 2;
956
0
    for (int y = 0; y< height; y++)
957
0
    {
958
0
      padStr[-1] = padStr[0];
959
0
      padStr[width] = padStr[width - 1];
960
0
      padStr += stridePredMC;
961
0
    }
962
963
0
    padStr = m_filteredBlockTmp[2 + refList][COMP_Y] + 2 * stridePredMC + 1;
964
0
    ::memcpy(padStr - stridePredMC, padStr, sizeof(Pel)*(widthG));
965
0
    ::memcpy(padStr + height*stridePredMC, padStr + (height - 1)*stridePredMC, sizeof(Pel)*(widthG));
966
0
  }
967
968
0
  const unsigned shiftNum = IF_INTERNAL_PREC + 1 - bitDepth;
969
0
  const int   offset = (1 << (shiftNum - 1)) + 2 * IF_INTERNAL_OFFS;
970
0
  const int   limit = (1 << 4) - 1;
971
972
0
  xFpBiDirOptFlow( srcY0, srcY1, gradX0, gradX1, gradY0, gradY1, width, height, dstY, dstStride, shiftNum, offset,
973
0
                   limit, clpRng, bitDepth );
974
0
}
975
976
void InterPredInterpolation::xWeightedAverage( const CodingUnit& cu, const CPelUnitBuf& pcYuvSrc0, const CPelUnitBuf& pcYuvSrc1, PelUnitBuf& pcYuvDst, const bool bdofApplied, PelUnitBuf *yuvPredTmp )
977
0
{
978
0
  const bool lumaOnly     = cu.mccNoChroma();
979
0
  const bool chromaOnly   = cu.mccNoLuma  ();
980
981
0
  CHECK( chromaOnly && lumaOnly, "should not happen" );
982
983
0
  const ClpRngs& clpRngs  = cu.slice->clpRngs;
984
0
  const int      iRefIdx0 = cu.refIdx[0];
985
0
  const int      iRefIdx1 = cu.refIdx[1];
986
987
0
  if( iRefIdx0 >= 0 && iRefIdx1 >= 0 )
988
0
  {
989
0
    if( cu.BcwIdx != BCW_DEFAULT && ( yuvPredTmp || !cu.ciip ) )
990
0
    {
991
0
      CHECK( bdofApplied, "BCW is disallowed with BIO" );
992
993
0
      pcYuvDst.addWeightedAvg( pcYuvSrc0, pcYuvSrc1, clpRngs, cu.BcwIdx, chromaOnly, lumaOnly );
994
995
0
      if( yuvPredTmp )
996
0
      {
997
0
        yuvPredTmp->addAvg( pcYuvSrc0, pcYuvSrc1, clpRngs, chromaOnly, lumaOnly );
998
0
      }
999
0
      return;
1000
0
    }
1001
    
1002
0
    if( bdofApplied && !chromaOnly )
1003
0
    {
1004
0
      xApplyBDOF( pcYuvDst.Y(), clpRngs[COMP_Y] );
1005
0
    }
1006
0
    if( !bdofApplied && ( lumaOnly || chromaOnly ) )
1007
0
    {
1008
0
      pcYuvDst.addAvg( pcYuvSrc0, pcYuvSrc1, clpRngs, chromaOnly, lumaOnly );
1009
0
    }
1010
0
    else
1011
0
    {
1012
0
      pcYuvDst.addAvg( pcYuvSrc0, pcYuvSrc1, clpRngs, bdofApplied );
1013
0
    }
1014
0
  }
1015
0
  else
1016
0
  {
1017
0
    if( cu.geo )
1018
0
    {
1019
0
      pcYuvDst.copyFrom( iRefIdx0 >= 0 ? pcYuvSrc0 : pcYuvSrc1 );
1020
0
    }
1021
0
    else
1022
0
    {
1023
0
      pcYuvDst.copyClip( iRefIdx0 >= 0 ? pcYuvSrc0 : pcYuvSrc1, clpRngs, lumaOnly, chromaOnly );
1024
0
    }
1025
0
  }
1026
0
}
1027
1028
void InterPrediction::motionCompensationGeo( CodingUnit &cu, PelUnitBuf &predBuf, const MergeCtx &geoMrgCtx )
1029
0
{
1030
0
  const ClpRngs &clpRngs      = cu.slice->clpRngs;
1031
0
  const UnitArea localUnitArea( cu.chromaFormat, Area( 0, 0, cu.lwidth(), cu.lheight() ) );
1032
1033
0
  PelUnitBuf     tmpGeoBuf0   = m_geoPartBuf[0].getBuf( localUnitArea );
1034
0
  PelUnitBuf     tmpGeoBuf1   = m_geoPartBuf[1].getBuf( localUnitArea );
1035
1036
0
  geoMrgCtx.setMergeInfo( cu, cu.geoMergeIdx[0] );
1037
0
  CU::spanMotionInfo    ( cu );
1038
0
  motionCompensation    ( cu, tmpGeoBuf0, REF_PIC_LIST_X );   // TODO: check 4:0:0 interaction with weighted prediction.
1039
1040
0
  geoMrgCtx.setMergeInfo( cu, cu.geoMergeIdx[1] );
1041
0
  CU::spanMotionInfo    ( cu );
1042
0
  motionCompensation    ( cu, tmpGeoBuf1, REF_PIC_LIST_X );   // TODO: check 4:0:0 interaction with weighted prediction.
1043
1044
0
  weightedGeoBlk( clpRngs, cu, cu.geoSplitDir, isChromaEnabled( cu.chromaFormat ) ? MAX_NUM_CH : CH_L, predBuf, tmpGeoBuf0, tmpGeoBuf1 );
1045
0
}
1046
1047
void InterPredInterpolation::weightedGeoBlk(const ClpRngs &clpRngs, CodingUnit& cu, const uint8_t splitDir,
1048
                                            int32_t channel, PelUnitBuf &predDst, PelUnitBuf &predSrc0, PelUnitBuf &predSrc1)
1049
0
{
1050
0
  if( channel != CH_C )
1051
0
  {
1052
0
    m_if.weightedGeoBlk( clpRngs, cu, cu.lumaSize().width, cu.lumaSize().height, COMP_Y, splitDir, predDst, predSrc0, predSrc1 );
1053
0
  }
1054
1055
0
  if( channel != CH_L && isChromaEnabled( cu.chromaFormat ) )
1056
0
  {
1057
0
    m_if.weightedGeoBlk( clpRngs, cu, cu.chromaSize().width, cu.chromaSize().height, COMP_Cb, splitDir, predDst, predSrc0, predSrc1 );
1058
0
    m_if.weightedGeoBlk( clpRngs, cu, cu.chromaSize().width, cu.chromaSize().height, COMP_Cr, splitDir, predDst, predSrc0, predSrc1 );
1059
0
  }
1060
0
}
1061
1062
4.62k
DMVR::DMVR() : m_pcRdCost( nullptr )
1063
4.62k
{
1064
4.62k
}
1065
1066
DMVR::~DMVR()
1067
4.62k
{
1068
4.62k
  destroy();
1069
4.62k
}
1070
1071
void DMVR::destroy()
1072
4.62k
{
1073
13.8k
  for( int i = 0; i < NUM_REF_PIC_LIST_01; i++ )
1074
9.24k
  {
1075
9.24k
    m_yuvPred[i].destroy();
1076
9.24k
    m_yuvPad[i].destroy();
1077
9.24k
    m_yuvTmp[i].destroy();
1078
9.24k
  }
1079
4.62k
  m_pcRdCost = nullptr;
1080
4.62k
}
1081
1082
void DMVR::init( RdCost* pcRdCost, const ChromaFormat chFormat )
1083
4.62k
{
1084
4.62k
  if( m_pcRdCost == nullptr )
1085
4.62k
  {
1086
4.62k
    m_pcRdCost = pcRdCost;
1087
1088
4.62k
    Area predArea = Area( 0, 0, DMVR_SUBCU_SIZE, DMVR_SUBCU_SIZE );
1089
4.62k
    Area refArea  = Area( 0, 0, MAX_CU_SIZE, MAX_CU_SIZE );
1090
13.8k
    for( int i = 0; i < NUM_REF_PIC_LIST_01; i++ )
1091
9.24k
    {
1092
9.24k
      m_yuvPred[i].create( chFormat, predArea );
1093
9.24k
      m_yuvTmp[i].create( CHROMA_400, refArea, 0, DMVR_NUM_ITERATION );
1094
9.24k
      m_yuvPad[i].create( chFormat, predArea, 0, DMVR_NUM_ITERATION + (NTAPS_LUMA>>1), 32 );
1095
      // the buffer m_yuvPad[i].bufs[0].buf is aligned to 32
1096
      // the actual begin of the written to buffer is m_yuvPad[i].bufs[0].buf - 3 * stride - 3 = m_yuvPad[i].bufs[0].buf - 99,
1097
      // which is not aligned with int. Since the margin on the left side is 1 sample too big, moving the buffer within the
1098
      // allocated memory 1 to the left doesn't cause problems
1099
9.24k
      m_yuvPad[i].bufs[0].buf--;
1100
9.24k
    }
1101
4.62k
  }
1102
4.62k
}
1103
1104
void DMVR::xCopyAndPad( const CodingUnit& cu, PelUnitBuf& pcPad, RefPicList refId, bool forLuma)
1105
0
{
1106
0
  int width, height;
1107
0
  Mv cMv;
1108
1109
0
  const Picture* refPic = cu.slice->getRefPic(refId, cu.refIdx[refId]);
1110
1111
0
  static constexpr int mvShift = MV_FRACTIONAL_BITS_INTERNAL;
1112
1113
0
  const int start = forLuma ? 0 : 1;
1114
0
  const int end   = forLuma ? 1 : MAX_NUM_COMP;
1115
1116
0
  for (int compID = start; compID < end; compID++)
1117
0
  {
1118
0
    int filtersize = compID == COMP_Y ? NTAPS_LUMA : NTAPS_CHROMA;
1119
0
    cMv            = cu.mv[refId][0];
1120
0
    width          = pcPad.bufs[compID].width;
1121
0
    height         = pcPad.bufs[compID].height;
1122
1123
0
    int mvshiftTemp = mvShift + getComponentScaleX((ComponentID)compID, cu.chromaFormat);
1124
1125
0
    width  += filtersize - 1;
1126
0
    height += filtersize - 1;
1127
0
    cMv    += Mv(-(((filtersize >> 1) - 1) << mvshiftTemp), -(((filtersize >> 1) - 1) << mvshiftTemp));
1128
1129
0
    clipMv(cMv, cu.lumaPos(), cu.lumaSize(), *cu.cs->pcv);
1130
1131
    /* Pre-fetch similar to HEVC*/
1132
0
    {
1133
0
      CPelBuf refBuf      = refPic->getRecoBuf(ComponentID(compID));
1134
0
      Position Rec_offset = cu.blocks[compID].pos().offset(cMv.hor >> mvshiftTemp, cMv.ver >> mvshiftTemp);
1135
0
      const Pel* refBufPtr = refBuf.bufAt(Rec_offset);
1136
1137
0
      PelBuf& dstBuf = pcPad.bufs[compID];
1138
1139
0
      const int leftTopFilterExt = ((filtersize >> 1) - 1);
1140
0
      const int padOffset        = leftTopFilterExt * dstBuf.stride + leftTopFilterExt;
1141
0
      const int padSize          = (DMVR_NUM_ITERATION) >> getComponentScaleX((ComponentID)compID, cu.chromaFormat);
1142
1143
0
      xFpPadDmvr( refBufPtr, refBuf.stride, dstBuf.buf - padOffset, dstBuf.stride, width, height, padSize );
1144
0
    }
1145
0
  }
1146
0
}
1147
1148
inline int32_t div_for_maxq7(int64_t N, int64_t D)
1149
0
{
1150
0
  int32_t sign, q;
1151
0
  sign = 0;
1152
0
  if (N < 0)
1153
0
  {
1154
0
    sign = 1;
1155
0
    N = -N;
1156
0
  }
1157
1158
0
  q = 0;
1159
0
  D = (D << 3);
1160
0
  if (N >= D)
1161
0
  {
1162
0
    N -= D;
1163
0
    q++;
1164
0
  }
1165
0
  q = (q << 1);
1166
1167
0
  D = (D >> 1);
1168
0
  if (N >= D)
1169
0
  {
1170
0
    N -= D;
1171
0
    q++;
1172
0
  }
1173
0
  q = (q << 1);
1174
1175
0
  if (N >= (D >> 1))
1176
0
    q++;
1177
1178
0
  if (sign)
1179
0
    return (-q);
1180
0
  return(q);
1181
0
}
1182
1183
void xSubPelErrorSrfc(uint64_t *sadBuffer, int32_t *deltaMv)
1184
0
{
1185
0
  for( int hv = 0; hv < 2; hv++)
1186
0
  {
1187
0
    const int32_t mvSubPelLvl = 4;/*1: half pel, 2: Qpel, 3:1/8, 4: 1/16*/
1188
0
    int64_t numerator   = (int64_t)((sadBuffer[hv+1] - sadBuffer[hv+3]) << mvSubPelLvl);
1189
0
    int64_t denominator = (int64_t)((sadBuffer[hv+1] + sadBuffer[hv+3] - (sadBuffer[0] << 1)));
1190
1191
0
    if (0 != denominator)
1192
0
    {
1193
0
      if ((sadBuffer[hv+1] != sadBuffer[0]) && (sadBuffer[hv+3] != sadBuffer[0]))
1194
0
      {
1195
0
        deltaMv[hv] = div_for_maxq7(numerator, denominator);
1196
0
      }
1197
0
      else
1198
0
      {
1199
0
        deltaMv[hv] = (sadBuffer[hv+1] == sadBuffer[0]) ? -8 : 8;
1200
0
      }
1201
0
    }
1202
0
  }
1203
0
}
1204
1205
void DMVR::xFinalPaddedMCForDMVR( const CodingUnit& cu, PelUnitBuf* dstBuf, const PelUnitBuf *refBuf, const bool bioApplied, const Mv mergeMv[NUM_REF_PIC_LIST_01], const Mv& refMv )
1206
0
{
1207
0
  int mvShift = MV_FRACTIONAL_BITS_INTERNAL;
1208
0
  Mv mv[2];
1209
0
  mv[L0] = mergeMv[L0] + refMv; mv[L0].clipToStorageBitDepth();
1210
0
  mv[L1] = mergeMv[L1] - refMv; mv[L1].clipToStorageBitDepth();
1211
1212
0
  for (int k = 0; k < NUM_REF_PIC_LIST_01; k++)
1213
0
  {
1214
0
    RefPicList refId = (RefPicList)k;
1215
0
    const Mv& cMv = mv[refId];
1216
0
    Mv cMvClipped( cMv );
1217
0
    clipMv(cMvClipped, cu.lumaPos(), cu.lumaSize(), *cu.cs->pcv);
1218
0
    const Picture* refPic = cu.slice->getRefPic(refId, cu.refIdx[refId]);
1219
0
    const Mv& startMv = mergeMv[refId];
1220
0
    for (int compID = 0; compID < getNumberValidComponents(cu.chromaFormat); compID++)
1221
0
    {
1222
0
      int mvshiftTemp = mvShift + getComponentScaleX((ComponentID)compID, cu.chromaFormat);
1223
0
      int deltaIntMvX = (cMv.hor >> mvshiftTemp) - (startMv.hor >> mvshiftTemp);
1224
0
      int deltaIntMvY = (cMv.ver >> mvshiftTemp) - (startMv.ver >> mvshiftTemp);
1225
1226
0
      CHECK((abs(deltaIntMvX) > DMVR_NUM_ITERATION) || (abs(deltaIntMvY) > DMVR_NUM_ITERATION), "not expected DMVR movement");
1227
1228
0
      if (deltaIntMvX || deltaIntMvY)
1229
0
      {
1230
0
        const PelBuf& srcBuf = refBuf[refId].bufs[compID];
1231
0
        int offset = (deltaIntMvY)*srcBuf.stride + (deltaIntMvX);
1232
1233
0
        xPredInterBlk( ( ComponentID ) compID, cu, nullptr, cMvClipped, dstBuf[refId], true, cu.cs->slice->clpRngs[compID], bioApplied, false, refId, 0, 0, 0, srcBuf.buf + offset, srcBuf.stride );
1234
0
      }
1235
0
      else
1236
0
      {
1237
0
        xPredInterBlk( ( ComponentID ) compID, cu, refPic,  cMvClipped, dstBuf[refId], true, cu.cs->slice->clpRngs[compID], bioApplied, false, refId );
1238
0
      }
1239
0
    }
1240
0
  }
1241
0
}
1242
1243
static void xDMVRSubPixelErrorSurface( int16_t *totalDeltaMV, int16_t *deltaMV, uint64_t *pSADsArray )
1244
0
{
1245
0
  int sadStride = (((2 * DMVR_NUM_ITERATION) + 1));
1246
0
  uint64_t sadbuffer[5];
1247
0
  if( ( abs( totalDeltaMV[ 0 ] ) != ( 2 << MV_FRACTIONAL_BITS_INTERNAL ) )
1248
0
   && ( abs( totalDeltaMV[ 1 ] ) != ( 2 << MV_FRACTIONAL_BITS_INTERNAL ) ) )
1249
0
  {
1250
0
    int32_t tempDeltaMv[2] = { 0,0 };
1251
0
    sadbuffer[0] = pSADsArray[0];
1252
0
    sadbuffer[1] = pSADsArray[-1];
1253
0
    sadbuffer[2] = pSADsArray[-sadStride];
1254
0
    sadbuffer[3] = pSADsArray[1];
1255
0
    sadbuffer[4] = pSADsArray[sadStride];
1256
0
    xSubPelErrorSrfc(sadbuffer, tempDeltaMv);
1257
0
    totalDeltaMV[0] += tempDeltaMv[0];
1258
0
    totalDeltaMV[1] += tempDeltaMv[1];
1259
0
  }
1260
0
}
1261
1262
void DMVR::xProcessDMVR( const CodingUnit& cu, PelUnitBuf& pcYuvDst, const ClpRngs &clpRngs, const bool bioApplied )
1263
0
{
1264
0
  PROFILER_SCOPE_AND_STAGE_EXT( 1, _TPROF, P_INTER_MRG_DMVR, cu.cs, CH_L );
1265
  /*Always High Precision*/
1266
0
  const int csx      = getChannelTypeScaleX( CH_C, cu.chromaFormat );
1267
0
  const int csy      = getChannelTypeScaleY( CH_C, cu.chromaFormat );
1268
0
  const int mvShift  = MV_FRACTIONAL_BITS_INTERNAL;
1269
0
  const int mvShiftC = mvShift + csx;
1270
1271
  /*use merge MV as starting MV*/
1272
0
  const Mv mergeMv[] = { cu.mv[REF_PIC_LIST_0][0], cu.mv[REF_PIC_LIST_1][0] };
1273
1274
1275
0
  const int dy = std::min<int>(cu.lumaSize().height, DMVR_SUBCU_SIZE);
1276
0
  const int dx = std::min<int>(cu.lumaSize().width,  DMVR_SUBCU_SIZE);
1277
1278
0
  const Position& puPos = cu.lumaPos();
1279
1280
0
  bool bioAppliedType[MAX_NUM_SUBCU_DMVR];
1281
1282
  // Do refinement search
1283
0
  {
1284
0
    const int bilinearBufStride = (cu.Y().width + (2 * DMVR_NUM_ITERATION));
1285
0
    const int padSize = DMVR_NUM_ITERATION << 1;
1286
0
    const int dstOffset = -( DMVR_NUM_ITERATION * bilinearBufStride + DMVR_NUM_ITERATION );
1287
1288
    /*use merge MV as starting MV*/
1289
0
    Mv mergeMVL0 = cu.mv[L0][0];
1290
0
    Mv mergeMVL1 = cu.mv[L1][0];
1291
1292
    /*Clip the starting MVs*/
1293
0
    clipMv(mergeMVL0, cu.lumaPos(), cu.lumaSize(), *cu.cs->pcv);
1294
0
    clipMv(mergeMVL1, cu.lumaPos(), cu.lumaSize(), *cu.cs->pcv);
1295
1296
    /*L0 MC for refinement*/
1297
0
    {
1298
0
      const Picture* refPic = cu.slice->getRefPic(L0, cu.refIdx[L0]);
1299
1300
0
      PelUnitBuf yuvTmp = PelUnitBuf(cu.chromaFormat, PelBuf(m_yuvTmp[L0].getBuf(COMP_Y).buf + dstOffset, bilinearBufStride, cu.lwidth() + padSize, cu.lheight() + padSize));
1301
1302
0
      mergeMVL0.hor -= (DMVR_NUM_ITERATION << MV_FRACTIONAL_BITS_INTERNAL);
1303
0
      mergeMVL0.ver -= (DMVR_NUM_ITERATION << MV_FRACTIONAL_BITS_INTERNAL);
1304
1305
0
      xPredInterBlk(COMP_Y, cu, refPic, mergeMVL0, yuvTmp, true, clpRngs[COMP_Y], false, false, L0, cu.lwidth() + padSize, cu.lheight() + padSize, true);
1306
0
    }
1307
1308
    /*L1 MC for refinement*/
1309
0
    {
1310
0
      const Picture* refPic = cu.slice->getRefPic(L1, cu.refIdx[L1]);
1311
1312
0
      PelUnitBuf yuvTmp = PelUnitBuf(cu.chromaFormat, PelBuf(m_yuvTmp[L1].getBuf(COMP_Y).buf + dstOffset, bilinearBufStride, cu.lwidth() + padSize, cu.lheight() + padSize));
1313
1314
0
      mergeMVL1.hor -= (DMVR_NUM_ITERATION << MV_FRACTIONAL_BITS_INTERNAL);
1315
0
      mergeMVL1.ver -= (DMVR_NUM_ITERATION << MV_FRACTIONAL_BITS_INTERNAL);
1316
1317
0
      xPredInterBlk(COMP_Y, cu, refPic, mergeMVL1, yuvTmp, true, clpRngs[COMP_Y], false, false, L1, cu.lwidth() + padSize, cu.lheight() + padSize, true);
1318
0
    }
1319
1320
    // point mc buffer to center point to avoid multiplication to reach each iteration to the beginning
1321
0
    const Pel* biLinearPredL0 = m_yuvTmp[0].getBuf( COMP_Y ).buf;
1322
0
    const Pel* biLinearPredL1 = m_yuvTmp[1].getBuf( COMP_Y ).buf;
1323
0
    const int bioEnabledThres = 2 * dy * dx;
1324
0
    const int bd = cu.cs->slice->clpRngs[COMP_Y].bd;
1325
1326
0
    DistParam distParam = m_pcRdCost->setDistParam( nullptr, nullptr, bilinearBufStride, bilinearBufStride, bd, COMP_Y, dx, dy, 1, true );
1327
1328
0
    int num = 0;
1329
0
    int yStart = 0;
1330
0
    uint64_t sadArray[((2 * DMVR_NUM_ITERATION) + 1) * ((2 * DMVR_NUM_ITERATION) + 1)];
1331
1332
0
    for( int y = puPos.y; y < ( puPos.y + cu.lumaSize().height ); y = y + dy, yStart = yStart + dy )
1333
0
    {
1334
0
      for( int x = puPos.x, xStart = 0; x < ( puPos.x + cu.lumaSize().width ); x = x + dx, xStart = xStart + dx )
1335
0
      {
1336
0
        uint64_t minCost        = MAX_UINT64;
1337
1338
        // set all entries to MAX_UNIT64
1339
0
        uint64_t *pSADsArray = &sadArray[( ( ( 2 * DMVR_NUM_ITERATION ) + 1 ) * ( ( 2 * DMVR_NUM_ITERATION ) + 1 ) ) >> 1];
1340
1341
0
        const Pel* addrL0Centre = biLinearPredL0 + yStart * bilinearBufStride + xStart;
1342
0
        const Pel* addrL1Centre = biLinearPredL1 + yStart * bilinearBufStride + xStart;
1343
1344
0
        const Pel* addrL0 = addrL0Centre;
1345
0
        const Pel* addrL1 = addrL1Centre;
1346
1347
0
        distParam.org.buf = addrL0;
1348
0
        distParam.cur.buf = addrL1;
1349
0
        minCost  = distParam.distFunc( distParam ) >> 1;
1350
0
        minCost -= ( minCost >> 2 );
1351
1352
0
        if( minCost < ( dx * dy ) )
1353
0
        {
1354
0
          cu.mvdL0SubPu[num] = Mv( 0, 0 );
1355
0
        }
1356
0
        else
1357
0
        {
1358
0
          int16_t totalDeltaMV[2] = { 0, 0 };
1359
0
          int16_t deltaMV[2]      = { 0, 0 };
1360
1361
0
          pSADsArray[0] = minCost;
1362
0
          pSADsArray    = sadArray;
1363
1364
0
          for( int ver = -2; ver <= 2; ver++ )
1365
0
          {
1366
0
            const int initHor = -2;
1367
0
            const ptrdiff_t offset = initHor + ver * bilinearBufStride;
1368
              
1369
0
            distParam.org.buf = addrL0 + offset;
1370
0
            distParam.cur.buf = addrL1 - offset;
1371
              
1372
0
            distParam.dmvrSadX5( distParam, pSADsArray, ver != 0 );
1373
1374
0
            for( int hor = -2; hor <= 2; hor++, pSADsArray++ )
1375
0
            {
1376
0
              Distortion cost = *pSADsArray;
1377
1378
0
              if( cost < minCost )
1379
0
              {
1380
0
                minCost    = cost;
1381
0
                deltaMV[0] = hor;
1382
0
                deltaMV[1] = ver;
1383
0
              }
1384
0
            }
1385
0
          }
1386
1387
0
          pSADsArray = &sadArray[( ( ( 2 * DMVR_NUM_ITERATION ) + 1 ) * ( ( 2 * DMVR_NUM_ITERATION ) + 1 ) ) >> 1];
1388
1389
0
          totalDeltaMV[0] += deltaMV[0];
1390
0
          totalDeltaMV[1] += deltaMV[1];
1391
0
          pSADsArray      += ( ( deltaMV[1] * ( ( ( 2 * DMVR_NUM_ITERATION ) + 1 ) ) ) + deltaMV[0] );
1392
0
          totalDeltaMV[0]  = totalDeltaMV[0] * ( 1 << mvShift );
1393
0
          totalDeltaMV[1]  = totalDeltaMV[1] * ( 1 << mvShift );
1394
1395
0
          xDMVRSubPixelErrorSurface( totalDeltaMV, deltaMV, pSADsArray );
1396
1397
0
          cu.mvdL0SubPu[num] = Mv( totalDeltaMV[0], totalDeltaMV[1] );
1398
0
        }
1399
1400
0
        bioAppliedType[num] = ( minCost < bioEnabledThres ) ? false : bioApplied;
1401
1402
0
        num++;
1403
0
      }
1404
0
    }
1405
0
  }
1406
1407
  // Final MC
1408
0
  CodingUnit subCu = cu;
1409
0
  subCu.UnitArea::operator=(UnitArea(cu.chromaFormat, Area(puPos.x, puPos.y, dx, dy)));
1410
0
  PelUnitBuf subPredBuf = pcYuvDst.subBuf(UnitAreaRelative(cu, subCu));
1411
1412
0
  PelUnitBuf predBuf[NUM_REF_PIC_LIST_01];
1413
0
  predBuf[L0] = m_yuvPred[L0].getCompactBuf( subCu );
1414
0
  predBuf[L1] = m_yuvPred[L1].getCompactBuf( subCu );
1415
  /* For padding */
1416
0
  PelUnitBuf padBuf[NUM_REF_PIC_LIST_01];
1417
0
  padBuf[L0] = m_yuvPad[L0].getBufPart(subCu);
1418
0
  padBuf[L1] = m_yuvPad[L1].getBufPart(subCu);
1419
1420
0
  int x = 0, y = 0;
1421
0
  int xStart = 0, yStart = 0;
1422
0
  int num = 0;
1423
0
  const int scaleX = getComponentScaleX(COMP_Cb, cu.chromaFormat);
1424
0
  const int scaleY = getComponentScaleY(COMP_Cb, cu.chromaFormat);
1425
1426
0
  const ptrdiff_t dstStride[MAX_NUM_COMP] = { pcYuvDst.bufs[COMP_Y].stride, cu.chromaFormat != CHROMA_400 ? pcYuvDst.bufs[COMP_Cb].stride : 0, cu.chromaFormat != CHROMA_400 ? pcYuvDst.bufs[COMP_Cr].stride : 0 };
1427
0
  for( y = puPos.y; y < ( puPos.y + cu.lumaSize().height ); y = y + dy, yStart = yStart + dy )
1428
0
  {
1429
0
    for( x = puPos.x, xStart = 0; x < ( puPos.x + cu.lumaSize().width ); x = x + dx, xStart = xStart + dx )
1430
0
    {
1431
0
      subCu.Y().x = x;
1432
0
      subCu.Y().y = y;
1433
1434
0
      if( cu.chromaFormat != CHROMA_400 )
1435
0
      {
1436
0
        subCu.Cb().x = subCu.Cr().x = x >> csx;
1437
0
        subCu.Cb().y = subCu.Cr().y = y >> csy;
1438
0
      }
1439
1440
0
      Mv mv0 = mergeMv[REF_PIC_LIST_0] + cu.mvdL0SubPu[num]; mv0.clipToStorageBitDepth();
1441
0
      Mv mv1 = mergeMv[REF_PIC_LIST_1] - cu.mvdL0SubPu[num]; mv1.clipToStorageBitDepth();
1442
1443
0
      bool padBufL0  = (mv0.hor >> mvShift)  != (mergeMv[0].hor >> mvShift)  || (mv0.ver >> mvShift)  != (mergeMv[0].ver >> mvShift);
1444
0
      bool padBufL0C = (mv0.hor >> mvShiftC) != (mergeMv[0].hor >> mvShiftC) || (mv0.ver >> mvShiftC) != (mergeMv[0].ver >> mvShiftC);
1445
        
1446
0
      bool padBufL1  = (mv1.hor >> mvShift)  != (mergeMv[1].hor >> mvShift)  || (mv1.ver >> mvShift)  != (mergeMv[1].ver >> mvShift);
1447
0
      bool padBufL1C = (mv1.hor >> mvShiftC) != (mergeMv[1].hor >> mvShiftC) || (mv1.ver >> mvShiftC) != (mergeMv[1].ver >> mvShiftC);
1448
1449
0
      padBufL0C &= cu.chromaFormat != CHROMA_400;
1450
0
      padBufL1C &= cu.chromaFormat != CHROMA_400;
1451
1452
0
      if (padBufL0)  xCopyAndPad(subCu, padBuf[L0], L0, true);
1453
0
      if (padBufL0C) xCopyAndPad(subCu, padBuf[L0], L0, false);
1454
0
      if (padBufL1)  xCopyAndPad(subCu, padBuf[L1], L1, true);
1455
0
      if (padBufL1C) xCopyAndPad(subCu, padBuf[L1], L1, false);
1456
1457
0
      xFinalPaddedMCForDMVR( subCu, predBuf, padBuf, bioAppliedType[num], mergeMv, cu.mvdL0SubPu[num] );
1458
1459
0
      subPredBuf.bufs[COMP_Y].buf  = pcYuvDst.bufs[COMP_Y].buf + xStart + yStart * dstStride[COMP_Y];
1460
0
      if( cu.chromaFormat != CHROMA_400 )
1461
0
      {
1462
0
        subPredBuf.bufs[COMP_Cb].buf = pcYuvDst.bufs[COMP_Cb].buf + (xStart >> scaleX) + ((yStart >> scaleY) * dstStride[COMP_Cb]);
1463
0
        subPredBuf.bufs[COMP_Cr].buf = pcYuvDst.bufs[COMP_Cr].buf + (xStart >> scaleX) + ((yStart >> scaleY) * dstStride[COMP_Cr]);
1464
0
      }
1465
1466
0
      xWeightedAverage( subCu, predBuf[L0], predBuf[L1], subPredBuf, bioAppliedType[num] );
1467
1468
0
      num++;
1469
0
    }
1470
0
  }
1471
0
}
1472
1473
bool InterPredInterpolation::isSubblockVectorSpreadOverLimit(int a, int b, int c, int d, int predType)
1474
0
{
1475
0
  int s4 = (4 << 11);
1476
0
  int filterTap = 6;
1477
1478
0
  if (predType == 3)
1479
0
  {
1480
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));
1481
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));
1482
0
    refBlkWidth = (refBlkWidth >> 11) + filterTap + 3;
1483
0
    refBlkHeight = (refBlkHeight >> 11) + filterTap + 3;
1484
1485
0
    if (refBlkWidth * refBlkHeight > (filterTap + 9) * (filterTap + 9))
1486
0
    {
1487
0
      return true;
1488
0
    }
1489
0
  }
1490
0
  else
1491
0
  {
1492
0
    int refBlkWidth = std::max(0, 4 * a + s4) - std::min(0, 4 * a + s4);
1493
0
    int refBlkHeight = std::max(0, 4 * b) - std::min(0, 4 * b);
1494
0
    refBlkWidth = (refBlkWidth >> 11) + filterTap + 3;
1495
0
    refBlkHeight = (refBlkHeight >> 11) + filterTap + 3;
1496
0
    if (refBlkWidth * refBlkHeight > (filterTap + 9) * (filterTap + 5))
1497
0
    {
1498
0
      return true;
1499
0
    }
1500
1501
0
    refBlkWidth = std::max(0, 4 * c) - std::min(0, 4 * c);
1502
0
    refBlkHeight = std::max(0, 4 * d + s4) - std::min(0, 4 * d + s4);
1503
0
    refBlkWidth = (refBlkWidth >> 11) + filterTap + 3;
1504
0
    refBlkHeight = (refBlkHeight >> 11) + filterTap + 3;
1505
0
    if (refBlkWidth * refBlkHeight > (filterTap + 5) * (filterTap + 9))
1506
0
    {
1507
0
      return true;
1508
0
    }
1509
0
  }
1510
0
  return false;
1511
0
}
1512
1513
void InterPredInterpolation::xPredAffineBlk(const ComponentID compID, const CodingUnit& cu, const Picture* refPic, const Mv* _mv, PelUnitBuf& dstPic, const bool bi, const ClpRng& clpRng, const RefPicList refPicList)
1514
0
{
1515
0
  const ChromaFormat chFmt = cu.chromaFormat;
1516
0
  int iScaleX = getComponentScaleX(compID, chFmt);
1517
0
  int iScaleY = getComponentScaleY(compID, chFmt);
1518
1519
0
  Mv mvLT = _mv[0];
1520
0
  Mv mvRT = _mv[1];
1521
0
  Mv mvLB = _mv[2];
1522
1523
  // get affine sub-block width and height
1524
0
  const int width = cu.Y().width;
1525
0
  const int height = cu.Y().height;
1526
0
  int blockWidth = AFFINE_MIN_BLOCK_SIZE;
1527
0
  int blockHeight = AFFINE_MIN_BLOCK_SIZE;
1528
1529
0
  CHECK(blockWidth  > (width >> iScaleX), "Sub Block width  > Block width");
1530
0
  CHECK(blockHeight > (height >> iScaleY), "Sub Block height > Block height");
1531
0
  const int MVBUFFER_SIZE = MAX_CU_SIZE / MIN_PU_SIZE;
1532
1533
0
  const int cxWidth = width >> iScaleX;
1534
0
  const int cxHeight = height >> iScaleY;
1535
0
  const int iHalfBW = blockWidth >> 1;
1536
0
  const int iHalfBH = blockHeight >> 1;
1537
1538
0
  const int iBit = MAX_CU_DEPTH;
1539
0
  int iDMvHorX = 0;
1540
0
  int iDMvHorY = 0;
1541
0
  int iDMvVerX = 0;
1542
0
  int iDMvVerY = 0;
1543
1544
0
  iDMvHorX = (mvRT - mvLT).hor * (1 <<(iBit - Log2(cxWidth)));
1545
0
  iDMvHorY = (mvRT - mvLT).ver * (1 <<(iBit - Log2(cxWidth)));
1546
0
  if (cu.affineType == AFFINEMODEL_6PARAM)
1547
0
  {
1548
0
    iDMvVerX = (mvLB - mvLT).hor * (1 <<(iBit - Log2(cxHeight)));
1549
0
    iDMvVerY = (mvLB - mvLT).ver * (1 <<(iBit - Log2(cxHeight)));
1550
0
  }
1551
0
  else
1552
0
  {
1553
0
    iDMvVerX = -iDMvHorY;
1554
0
    iDMvVerY = iDMvHorX;
1555
0
  }
1556
1557
0
  int iMvScaleHor = mvLT.hor * (1 << iBit);
1558
0
  int iMvScaleVer = mvLT.ver * (1 << iBit);
1559
0
  const PPS &pps = *cu.cs->pps;
1560
0
  const SPS &sps = *cu.cs->sps;
1561
0
  const int iMvShift = 4;
1562
0
  const int iOffset = 8;
1563
0
  const int iHorMax = (pps.picWidthInLumaSamples + iOffset - cu.Y().x - 1) << iMvShift;
1564
0
  const int iHorMin = (-(int)cu.cs->pcv->maxCUSize - iOffset - (int)cu.Y().x + 1) * (1 << iMvShift);
1565
0
  const int iVerMax = (pps.picHeightInLumaSamples + iOffset - cu.Y().y - 1) << iMvShift;
1566
0
  const int iVerMin = (-(int)cu.cs->pcv->maxCUSize - iOffset - (int)cu.Y().y + 1) * (1 << iMvShift);
1567
  
1568
0
  const int shift = iBit - 4 + MV_FRACTIONAL_BITS_INTERNAL;
1569
0
  const bool subblkMVSpreadOverLimit = isSubblockVectorSpreadOverLimit(iDMvHorX, iDMvHorY, iDMvVerX, iDMvVerY, cu.interDir);
1570
1571
0
  bool enablePROF = sps.PROF && (!m_skipPROF) && (compID == COMP_Y);
1572
0
  enablePROF &= (!cu.cs->picHeader->disProfFlag);
1573
0
  enablePROF &= !((cu.affineType == AFFINEMODEL_6PARAM && _mv[0] == _mv[1] && _mv[0] == _mv[2]) || (cu.affineType == AFFINEMODEL_4PARAM && _mv[0] == _mv[1]));
1574
0
  enablePROF &= !subblkMVSpreadOverLimit;
1575
0
  const int profThres = 1 << (iBit + (m_isBi ? 1 : 0));
1576
0
  enablePROF &= !m_encOnly || cu.slice->checkLDC || iDMvHorX > profThres || iDMvHorY > profThres || iDMvVerX > profThres || iDMvVerY > profThres || iDMvHorX < -profThres || iDMvHorY < -profThres || iDMvVerX < -profThres || iDMvVerY < -profThres;
1577
0
  enablePROF &= pps.picWidthInLumaSamples == refPic->cs->pps->picWidthInLumaSamples && pps.picHeightInLumaSamples == refPic->cs->pps->picHeightInLumaSamples;
1578
1579
0
  bool isLast = enablePROF ? false : !bi;
1580
1581
0
  const int cuExtW = AFFINE_MIN_BLOCK_SIZE + PROF_BORDER_EXT_W * 2;
1582
0
  const int cuExtH = AFFINE_MIN_BLOCK_SIZE + PROF_BORDER_EXT_H * 2;
1583
1584
0
  PelBuf gradXExt(m_gradBuf[0], cuExtW, cuExtH);
1585
0
  PelBuf gradYExt(m_gradBuf[1], cuExtW, cuExtH);
1586
1587
0
  int dstExtW = (((blockWidth + PROF_BORDER_EXT_W * 2 + 7) >> 3) << 3);
1588
0
  int dstExtH = (blockHeight + PROF_BORDER_EXT_H * 2);
1589
1590
0
  PelBuf dstExtBuf(m_filteredBlockTmp[1][compID], dstExtW, dstExtH);
1591
1592
0
  PelBuf& dstBuf = dstPic.bufs[compID];
1593
1594
0
  int *dMvScaleHor = m_dMvBuf[refPicList];
1595
0
  int *dMvScaleVer = m_dMvBuf[refPicList] + 16;
1596
1597
0
  if (enablePROF)
1598
0
  {
1599
0
    int* dMvH = dMvScaleHor;
1600
0
    int* dMvV = dMvScaleVer;
1601
0
    int quadHorX = 4 * iDMvHorX ;
1602
0
    int quadHorY = 4 * iDMvHorY ;
1603
0
    int quadVerX = 4 * iDMvVerX ;
1604
0
    int quadVerY = 4 * iDMvVerY ;
1605
1606
0
    dMvH[0] = ((iDMvHorX + iDMvVerX) * 2) - ((quadHorX + quadVerX)  * 2);
1607
0
    dMvV[0] = ((iDMvHorY + iDMvVerY) * 2) - ((quadHorY + quadVerY)  * 2);
1608
1609
0
    for (int w = 1; w < blockWidth; w++)
1610
0
    {
1611
0
      dMvH[w] = dMvH[w - 1] + quadHorX;
1612
0
      dMvV[w] = dMvV[w - 1] + quadHorY;
1613
0
    }
1614
1615
0
    dMvH += blockWidth;
1616
0
    dMvV += blockWidth;
1617
0
    for (int h = 1; h < blockHeight; h++)
1618
0
    {
1619
0
      for (int w = 0; w < blockWidth; w++)
1620
0
      {
1621
0
        dMvH[w] = dMvH[w - blockWidth] + quadVerX;
1622
0
        dMvV[w] = dMvV[w - blockWidth] + quadVerY;
1623
0
      }
1624
0
      dMvH += blockWidth;
1625
0
      dMvV += blockWidth;
1626
0
    }
1627
1628
0
    const int mvShift  = 8;
1629
0
    const int dmvLimit = ( 1 << 5 ) - 1;
1630
1631
0
    if (!g_pelBufOP.roundIntVector)
1632
0
    {
1633
0
      for (int idx = 0; idx < blockWidth * blockHeight; idx++)
1634
0
      {
1635
0
        roundAffineMv(dMvScaleHor[idx], dMvScaleVer[idx], mvShift);
1636
0
        dMvScaleHor[idx] = Clip3(-dmvLimit, dmvLimit, dMvScaleHor[idx]);
1637
0
        dMvScaleVer[idx] = Clip3(-dmvLimit, dmvLimit, dMvScaleVer[idx]);
1638
0
      }
1639
0
    }
1640
0
    else
1641
0
    {
1642
0
      int sz = blockWidth * blockHeight;
1643
0
      g_pelBufOP.roundIntVector(dMvScaleHor, sz, mvShift, dmvLimit);
1644
0
      g_pelBufOP.roundIntVector(dMvScaleVer, sz, mvShift, dmvLimit);
1645
0
    }
1646
0
  }
1647
1648
0
  int scaleXLuma = getComponentScaleX(COMP_Y, chFmt);
1649
0
  int scaleYLuma = getComponentScaleY(COMP_Y, chFmt);
1650
0
  if( cu.mccNoLuma() && ( compID == COMP_Cb ) && cu.chromaFormat != CHROMA_444 )
1651
0
  {
1652
0
    CHECK(compID == COMP_Y, "Chroma only subblock MV calculation should not apply to Luma");
1653
0
    int lumaBlockWidth = AFFINE_MIN_BLOCK_SIZE;
1654
0
    int lumaBlockHeight = AFFINE_MIN_BLOCK_SIZE;
1655
1656
0
    CHECK(lumaBlockWidth > (width >> scaleXLuma), "Sub Block width  > Block width");
1657
0
    CHECK(lumaBlockHeight > (height >> scaleYLuma), "Sub Block height > Block height");
1658
1659
0
    const int cxWidthLuma = width >> scaleXLuma;
1660
0
    const int cxHeightLuma = height >> scaleYLuma;
1661
0
    const int halfBWLuma = lumaBlockWidth >> 1;
1662
0
    const int halfBHLuma = lumaBlockHeight >> 1;
1663
1664
0
    int dMvHorXLuma, dMvHorYLuma, dMvVerXLuma, dMvVerYLuma;
1665
0
    dMvHorXLuma = (mvRT - mvLT).hor * (1 << (iBit - floorLog2(cxWidthLuma)));
1666
0
    dMvHorYLuma = (mvRT - mvLT).ver * (1 <<  (iBit - floorLog2(cxWidthLuma)));
1667
0
    if (cu.affineType == AFFINEMODEL_6PARAM)
1668
0
    {
1669
0
      dMvVerXLuma = (mvLB - mvLT).hor * (1 << (iBit - floorLog2(cxHeightLuma)));
1670
0
      dMvVerYLuma = (mvLB - mvLT).ver * (1 << (iBit - floorLog2(cxHeightLuma)));
1671
0
    }
1672
0
    else
1673
0
    {
1674
0
      dMvVerXLuma = -dMvHorYLuma;
1675
0
      dMvVerYLuma = dMvHorXLuma;
1676
0
    }
1677
1678
0
    const bool subblkMVSpreadOverLimitLuma = isSubblockVectorSpreadOverLimit(dMvHorXLuma, dMvHorYLuma, dMvVerXLuma, dMvVerYLuma, cu.interDir);
1679
1680
    // get luma MV block by block
1681
0
    for (int h = 0; h < cxHeightLuma; h += lumaBlockHeight)
1682
0
    {
1683
0
      for (int w = 0; w < cxWidthLuma; w += lumaBlockWidth)
1684
0
      {
1685
0
        int mvScaleTmpHor, mvScaleTmpVer;
1686
0
        if (!subblkMVSpreadOverLimitLuma)
1687
0
        {
1688
0
          mvScaleTmpHor = iMvScaleHor + dMvHorXLuma * (halfBWLuma + w) + dMvVerXLuma * (halfBHLuma + h);
1689
0
          mvScaleTmpVer = iMvScaleVer + dMvHorYLuma * (halfBWLuma + w) + dMvVerYLuma * (halfBHLuma + h);
1690
0
        }
1691
0
        else
1692
0
        {
1693
0
          mvScaleTmpHor = iMvScaleHor + dMvHorXLuma * (cxWidthLuma >> 1) + dMvVerXLuma * (cxHeightLuma >> 1);
1694
0
          mvScaleTmpVer = iMvScaleVer + dMvHorYLuma * (cxWidthLuma >> 1) + dMvVerYLuma * (cxHeightLuma >> 1);
1695
0
        }
1696
1697
0
        roundAffineMv(mvScaleTmpHor, mvScaleTmpVer, shift);
1698
0
        Mv tmpMv(mvScaleTmpHor, mvScaleTmpVer);
1699
0
        tmpMv.clipToStorageBitDepth();
1700
0
        mvScaleTmpHor = tmpMv.hor;
1701
0
        mvScaleTmpVer = tmpMv.ver;
1702
1703
0
        m_storedMv[h / AFFINE_MIN_BLOCK_SIZE * MVBUFFER_SIZE + w / AFFINE_MIN_BLOCK_SIZE].set(mvScaleTmpHor, mvScaleTmpVer);
1704
0
      }
1705
0
    }
1706
0
  }
1707
  // get prediction block by block
1708
0
  const CPelBuf refBuf     = refPic->getRecoBuf(compID);
1709
1710
0
  const int puX = cu.blocks[compID].x;
1711
0
  const int puY = cu.blocks[compID].y;
1712
1713
0
  for (int h = 0; h < cxHeight; h += blockHeight)
1714
0
  {
1715
0
    for (int w = 0; w < cxWidth; w += blockWidth)
1716
0
    {
1717
0
      int iMvScaleTmpHor, iMvScaleTmpVer;
1718
0
      if (compID == COMP_Y || cu.chromaFormat == CHROMA_444)
1719
0
      {
1720
0
        if (!subblkMVSpreadOverLimit)
1721
0
        {
1722
0
          iMvScaleTmpHor = iMvScaleHor + iDMvHorX * (iHalfBW + w) + iDMvVerX * (iHalfBH + h);
1723
0
          iMvScaleTmpVer = iMvScaleVer + iDMvHorY * (iHalfBW + w) + iDMvVerY * (iHalfBH + h);
1724
0
        }
1725
0
        else
1726
0
        {
1727
0
          iMvScaleTmpHor = iMvScaleHor + iDMvHorX * (cxWidth >> 1) + iDMvVerX * (cxHeight >> 1);
1728
0
          iMvScaleTmpVer = iMvScaleVer + iDMvHorY * (cxWidth >> 1) + iDMvVerY * (cxHeight >> 1);
1729
0
        }
1730
1731
0
        roundAffineMv(iMvScaleTmpHor, iMvScaleTmpVer, shift);
1732
0
        Mv tmpMv(iMvScaleTmpHor, iMvScaleTmpVer);
1733
0
        tmpMv.clipToStorageBitDepth();
1734
0
        iMvScaleTmpHor = tmpMv.hor;
1735
0
        iMvScaleTmpVer = tmpMv.ver;
1736
1737
        // clip and scale
1738
0
        m_storedMv[h / AFFINE_MIN_BLOCK_SIZE * MVBUFFER_SIZE + w / AFFINE_MIN_BLOCK_SIZE].set(iMvScaleTmpHor, iMvScaleTmpVer);
1739
        //   if( scalingRatio == SCALE_1X ) 
1740
0
        {
1741
0
          iMvScaleTmpHor = std::min<int>(iHorMax, std::max<int>(iHorMin, iMvScaleTmpHor));
1742
0
          iMvScaleTmpVer = std::min<int>(iVerMax, std::max<int>(iVerMin, iMvScaleTmpVer));
1743
0
        }
1744
0
      }
1745
0
      else
1746
0
      {
1747
0
        Mv curMv = m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE) * MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE)] +
1748
0
          m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE + iScaleY)* MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE + iScaleX)];
1749
0
        roundAffineMv(curMv.hor, curMv.ver, 1);
1750
1751
0
        curMv.hor = std::min<int>(iHorMax, std::max<int>(iHorMin, curMv.hor));
1752
0
        curMv.ver = std::min<int>(iVerMax, std::max<int>(iVerMin, curMv.ver));
1753
1754
0
        iMvScaleTmpHor = curMv.hor;
1755
0
        iMvScaleTmpVer = curMv.ver;
1756
0
      }
1757
1758
0
      CHECKD( m_ifpLines && !CU::isMvInRangeFPP( puY + h, blockHeight, iMvScaleTmpVer, m_ifpLines, *pps.pcv, iScaleY ), "xPredAffineBlk: FPP MV restriction failed!\n" );
1759
      // get the MV in high precision
1760
0
      int xFrac, yFrac, xInt, yInt;
1761
1762
0
      if (!iScaleX)
1763
0
      {
1764
0
        xInt = iMvScaleTmpHor >> 4;
1765
0
        xFrac = iMvScaleTmpHor & 15;
1766
0
      }
1767
0
      else
1768
0
      {
1769
0
        xInt = iMvScaleTmpHor >> 5;
1770
0
        xFrac = iMvScaleTmpHor & 31;
1771
0
      }
1772
0
      if (!iScaleY)
1773
0
      {
1774
0
        yInt = iMvScaleTmpVer >> 4;
1775
0
        yFrac = iMvScaleTmpVer & 15;
1776
0
      }
1777
0
      else
1778
0
      {
1779
0
        yInt = iMvScaleTmpVer >> 5;
1780
0
        yFrac = iMvScaleTmpVer & 31;
1781
0
      }
1782
1783
0
      const Pel* ref = refBuf.buf;
1784
0
      ref           +=   puX + xInt + w;
1785
0
      ref           += ( puY + yInt + h ) * refBuf.stride;
1786
0
      Pel* dst       = dstBuf.buf + w + h * dstBuf.stride;
1787
1788
0
      int refStride = refBuf.stride;
1789
0
      int dstStride = dstBuf.stride;
1790
1791
0
      int bw = blockWidth;
1792
0
      int bh = blockHeight;
1793
1794
0
      if( enablePROF )
1795
0
      {
1796
0
        dst = dstExtBuf.bufAt(PROF_BORDER_EXT_W, PROF_BORDER_EXT_H);
1797
0
        dstStride = dstExtBuf.stride;
1798
0
      }
1799
1800
0
      if( xFrac && yFrac )
1801
0
      {
1802
0
        m_if.filter4x4( compID, ref, refStride, dst, dstStride, 4, 4, xFrac, yFrac, isLast, chFmt, clpRng );
1803
0
      }
1804
0
      else if( !yFrac )
1805
0
      {
1806
0
        m_if.filterHor( compID, ref, refStride, dst, dstStride, bw, bh, xFrac, isLast, chFmt, clpRng );
1807
0
      }
1808
0
      else if( xFrac == 0 )
1809
0
      {
1810
0
        m_if.filterVer( compID, ref, refStride, dst, dstStride, bw, bh, yFrac, true, isLast, chFmt, clpRng );
1811
0
      }
1812
      
1813
0
      if (enablePROF)
1814
0
      {
1815
0
        const unsigned shift = std::max<int>(2, (IF_INTERNAL_PREC - clpRng.bd));
1816
0
        const int xOffset = xFrac >> 3;
1817
0
        const int yOffset = yFrac >> 3;
1818
1819
0
        const int refOffset = (blockHeight + 1) * refStride;
1820
0
        const int dstOffset = (blockHeight + 1)* dstStride;
1821
1822
0
        const Pel* refPel = ref - (1 - yOffset) * refStride + xOffset - 1;
1823
0
        Pel* dstPel = dst - dstStride - 1;
1824
0
        for (int pw = 0; pw < blockWidth + 2; pw++)
1825
0
        {
1826
0
          dstPel[pw] = leftShiftU(refPel[pw], shift) - (Pel)IF_INTERNAL_OFFS;
1827
0
          dstPel[pw + dstOffset] = leftShiftU(refPel[pw + refOffset], shift) - (Pel)IF_INTERNAL_OFFS;
1828
0
        }
1829
1830
0
        refPel = ref + yOffset * refBuf.stride + xOffset;
1831
0
        dstPel = dst;
1832
0
        for (int ph = 0; ph < blockHeight; ph++, refPel += refStride, dstPel += dstStride)
1833
0
        {
1834
0
          dstPel[-1] = leftShiftU(refPel[-1], shift) - (Pel)IF_INTERNAL_OFFS;
1835
0
          dstPel[blockWidth] = leftShiftU(refPel[blockWidth], shift) - (Pel)IF_INTERNAL_OFFS;
1836
0
        }
1837
1838
0
        PelBuf gradXBuf = gradXExt.subBuf(0, 0, blockWidth + 2, blockHeight + 2);
1839
0
        PelBuf gradYBuf = gradYExt.subBuf(0, 0, blockWidth + 2, blockHeight + 2);
1840
1841
0
        xFpProfGradFilter(dstExtBuf.buf, dstExtBuf.stride, blockWidth + 2, blockHeight + 2, gradXBuf.stride, gradXBuf.buf, gradYBuf.buf, clpRng.bd);
1842
1843
0
        const int shiftNum = std::max<int>(2, (IF_INTERNAL_PREC - clpRng.bd));
1844
0
        const Pel offset = (1 << (shiftNum - 1)) + IF_INTERNAL_OFFS;
1845
0
        Pel* src = dstExtBuf.bufAt(PROF_BORDER_EXT_W, PROF_BORDER_EXT_H);
1846
0
        Pel* gX = gradXBuf.bufAt(PROF_BORDER_EXT_W, PROF_BORDER_EXT_H);
1847
0
        Pel* gY = gradYBuf.bufAt(PROF_BORDER_EXT_W, PROF_BORDER_EXT_H);
1848
1849
0
        Pel*  dstY = dstBuf.bufAt(w, h);
1850
1851
0
        xFpApplyPROF(dstY, dstBuf.stride, src, dstExtBuf.stride, blockWidth, blockHeight, gX, gY, gradXBuf.stride, dMvScaleHor, dMvScaleVer, blockWidth, bi, shiftNum, offset, clpRng);
1852
0
      }
1853
0
    }
1854
0
  }
1855
0
}
1856
1857
bool InterPredInterpolation::xIsAffineMvInRangeFPP( const CodingUnit &cu, const Mv* _mv, const int ifpLines, const int mvPrecShift )
1858
0
{
1859
0
  const PreCalcValues& pcv = *cu.cs->pcv;
1860
0
  if( cu.ly() >= ( ( pcv.heightInCtus - 1 - ifpLines ) << pcv.maxCUSizeLog2 ) )
1861
0
    return true;
1862
1863
0
  const ChromaFormat chFmt = cu.chromaFormat;
1864
0
  const int width       = cu.Y().width;
1865
0
  const int height      = cu.Y().height;
1866
0
  const int nBW  = AFFINE_MIN_BLOCK_SIZE;
1867
0
  const int nBH = AFFINE_MIN_BLOCK_SIZE;
1868
0
  const int iHalfBW     = nBW >> 1;
1869
0
  const int iHalfBH     = nBH >> 1;
1870
0
  const int iBit        = MAX_CU_DEPTH;
1871
0
  const int shift       = iBit - 4 + MV_FRACTIONAL_BITS_INTERNAL;
1872
0
  Mv mvLT = _mv[0];
1873
0
  Mv mvRT = _mv[1];
1874
0
  Mv mvLB = _mv[2];
1875
1876
0
  int iDMvHorX = 0;
1877
0
  int iDMvHorY = 0;
1878
0
  int iDMvVerX = 0;
1879
0
  int iDMvVerY = 0;
1880
1881
0
  const int iMvScaleVer = mvLT.ver * (1 << iBit);
1882
1883
0
  int iScaleX = getChannelTypeScaleX(CH_C, chFmt);
1884
0
  int iScaleY = getChannelTypeScaleY(CH_C, chFmt);
1885
0
  const int cxWidth  = width;
1886
0
  const int cxHeight = height;
1887
1888
0
  iDMvHorX = (mvRT - mvLT).hor * (1 << (iBit - Log2(cxWidth)));
1889
0
  iDMvHorY = (mvRT - mvLT).ver * (1 <<(iBit - Log2(cxWidth)));
1890
0
  if (cu.affineType == AFFINEMODEL_6PARAM)
1891
0
  {
1892
0
    iDMvVerX = (mvLB - mvLT).hor * (1 <<(iBit - Log2(cxHeight)));
1893
0
    iDMvVerY = (mvLB - mvLT).ver * (1 <<(iBit - Log2(cxHeight)));
1894
0
  }
1895
0
  else
1896
0
  {
1897
0
    iDMvVerX = -iDMvHorY;
1898
0
    iDMvVerY = iDMvHorX;
1899
0
  }
1900
0
  const bool subblkMVSpreadOverLimit = InterPrediction::isSubblockVectorSpreadOverLimit(iDMvHorX, iDMvHorY, iDMvVerX, iDMvVerY, cu.interDir);
1901
1902
0
  const int yRefMax     = ( ( ( cu.ly() >> pcv.maxCUSizeLog2 ) + ifpLines + 1 ) << pcv.maxCUSizeLog2 ) - 1;
1903
0
  const int dctifMarginVerBot = 4;
1904
1905
0
  auto roundMvVal = [&](int mvVal, int shift)
1906
0
  {
1907
0
    const int nOffset = 1 << (shift - 1);
1908
0
    mvVal = (mvVal + nOffset - (mvVal >= 0)) >> shift;
1909
0
    return mvVal;
1910
0
  };
1911
0
  auto calcAffineMv = [&](int w, int h)
1912
0
  {
1913
0
    int iMvScaleTmpVer;
1914
0
    if(!subblkMVSpreadOverLimit)
1915
0
    {
1916
0
      iMvScaleTmpVer = iMvScaleVer + iDMvHorY * (iHalfBW + w) + iDMvVerY * (iHalfBH + h);
1917
0
    }
1918
0
    else
1919
0
    {
1920
0
      iMvScaleTmpVer = iMvScaleVer + iDMvHorY * (cxWidth >> 1) + iDMvVerY * (cxHeight >> 1);
1921
0
    }
1922
0
    iMvScaleTmpVer = roundMvVal(iMvScaleTmpVer, shift);
1923
0
    return iMvScaleTmpVer;
1924
0
  };
1925
1926
0
  auto checkMvLineSync = [&](int yMv, int blkBot, const int scaleVer = 0 )
1927
0
  {
1928
0
    if( ( ( blkBot ) + (yMv >> ( mvPrecShift + scaleVer) ) > ( yRefMax >> scaleVer ) ) )
1929
0
      return false;
1930
0
    return true;
1931
0
  };
1932
1933
0
  const int filterMargin = dctifMarginVerBot - 1;
1934
0
  int x = cu.lx();
1935
0
  int y = cu.ly();
1936
1937
  // luma
1938
0
  Position off00 (0, 0);
1939
0
  Position blk00 (x + off00.x, y + off00.y);
1940
0
  int mvVer00 = calcAffineMv(off00.x, off00.y);
1941
0
  if( !checkMvLineSync( mvVer00, blk00.y + filterMargin + nBH ) ) 
1942
0
    return false;
1943
1944
0
  Position off01 (width - nBW, 0);
1945
0
  Position blk01 (x + off01.x, y + off01.y);
1946
0
  int mvVer01 = calcAffineMv(off01.x, off01.y);
1947
0
  if( !checkMvLineSync( mvVer01, blk00.y + filterMargin + nBH ) ) 
1948
0
    return false;
1949
1950
0
  Position off10 (0, height - nBH);
1951
0
  Position blk10 (x + off10.x, y + off10.y);
1952
0
  int mvVer10 = calcAffineMv(off10.x, off10.y);
1953
0
  if( !checkMvLineSync( mvVer10, blk10.y + filterMargin + nBH  ) ) 
1954
0
    return false;
1955
1956
0
  Position off11 (width - nBW, height - nBH);
1957
0
  Position blk11 (x + off11.x, y + off11.y);
1958
0
  int mvVer11 = calcAffineMv(off11.x, off11.y);
1959
0
  if( !checkMvLineSync( mvVer11, blk10.y + filterMargin + nBH  ) ) 
1960
0
    return false;
1961
1962
  // chroma
1963
0
  if( cu.lwidth() == 8 && cu.lheight() == 8 )
1964
0
  {
1965
0
    if(iScaleX || iScaleY)
1966
0
    {
1967
0
      if(iScaleY)
1968
0
      {
1969
0
        const int blkBot = ((blk00.y + filterMargin) >> iScaleY) + nBH;
1970
0
        if(!checkMvLineSync( roundMvVal( mvVer00 + mvVer11, 1 ), blkBot, iScaleY ))
1971
0
          return false;
1972
0
      }
1973
0
      else
1974
0
      {
1975
0
        if(!checkMvLineSync( roundMvVal( mvVer00 + mvVer01, 1 ), blk00.y + filterMargin + nBH, iScaleY ))
1976
0
          return false;
1977
0
        if(!checkMvLineSync( roundMvVal( mvVer10 + mvVer11, 1 ), blk10.y + filterMargin + nBH, iScaleY ))
1978
0
          return false;
1979
0
      }
1980
0
    }
1981
0
  }
1982
0
  else
1983
0
  {
1984
0
    if(iScaleX || iScaleY)
1985
0
    {
1986
0
      int blkBot = ((blk00.y + filterMargin) >> iScaleY) + nBH;
1987
0
      int mvVer00_ = calcAffineMv(off00.x + nBW, off00.y + (iScaleY ? nBH: 0) );
1988
0
      if(!checkMvLineSync( roundMvVal( mvVer00 + mvVer00_, 1 ), blkBot, iScaleY ))
1989
0
        return false;
1990
1991
0
      int _mvVer01 =           calcAffineMv( off01.x - nBW, off01.y       );
1992
0
      int mvVer01_ = iScaleY ? calcAffineMv( off01.x      , off01.y + nBH ): mvVer01;
1993
0
      if(!checkMvLineSync( roundMvVal( _mvVer01 + mvVer01_, 1 ), blkBot, iScaleY ))
1994
0
        return false;
1995
1996
0
      blkBot = ((blk10.y - (iScaleY ? nBH: 0) + filterMargin) >> iScaleY) + nBH;
1997
0
      int _mvVer10 = iScaleY ? calcAffineMv( off10.x      , off10.y - nBH ): mvVer10;
1998
0
      int mvVer10_ =           calcAffineMv( off10.x + nBW, off10.y       );
1999
0
      if(!checkMvLineSync( roundMvVal( _mvVer10 + mvVer10_, 1 ), blkBot, iScaleY ))
2000
0
        return false;
2001
2002
0
      int _mvVer11 = calcAffineMv( off11.x - nBW, off11.y - (iScaleY ? nBH: 0) );
2003
0
      if(!checkMvLineSync( roundMvVal( _mvVer11 + mvVer11, 1 ), blkBot, iScaleY ))
2004
0
        return false;
2005
0
    }
2006
0
  }
2007
2008
0
  return true;
2009
0
}
2010
2011
void InterPrediction::xFillIBCBuffer(CodingUnit& cu)
2012
0
{
2013
0
  for (auto& currPU : CU::traverseTUs(cu))
2014
0
  {
2015
0
    for (const CompArea& area : currPU.blocks)
2016
0
    {
2017
0
      if (!area.valid())
2018
0
      {
2019
0
        continue;
2020
0
      }
2021
0
      const unsigned int lcuWidth = cu.cs->slice->sps->CTUSize;
2022
0
      const int shiftSampleHor = getComponentScaleX(area.compID, cu.chromaFormat);
2023
0
      const int shiftSampleVer = getComponentScaleY(area.compID, cu.chromaFormat);
2024
0
      const int ctuSizeLog2Ver = floorLog2(lcuWidth) - shiftSampleVer;
2025
0
      const int pux = area.x & ((m_IBCBufferWidth >> shiftSampleHor) - 1);
2026
0
      const int puy = area.y & ((1 << ctuSizeLog2Ver) - 1);
2027
0
      const CompArea dstArea = CompArea(area.compID, cu.chromaFormat, Position(pux, puy), Size(area.width, area.height));
2028
0
      CPelBuf srcBuf = cu.cs->getRecoBuf(area);
2029
0
      PelBuf dstBuf = m_IBCBuffer.getBuf(dstArea);
2030
2031
0
      dstBuf.copyFrom(srcBuf);
2032
0
    }
2033
0
  }
2034
0
}
2035
2036
void InterPrediction::xIntraBlockCopyIBC(CodingUnit& cu, PelUnitBuf& predBuf, const ComponentID compID)
2037
0
{
2038
0
  const unsigned int lcuWidth = cu.cs->slice->sps->CTUSize;
2039
0
  const int shiftSampleHor = getComponentScaleX(compID, cu.chromaFormat);
2040
0
  const int shiftSampleVer = getComponentScaleY(compID, cu.chromaFormat);
2041
0
  const int ctuSizeLog2Ver = floorLog2(lcuWidth) - shiftSampleVer;
2042
0
  Mv bv = cu.mv[REF_PIC_LIST_0][0];
2043
0
  bv.changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT );
2044
0
  int refx, refy;
2045
0
  if (compID == COMP_Y)
2046
0
  {
2047
0
    refx = cu.Y().x + bv.hor;
2048
0
    refy = cu.Y().y + bv.ver;
2049
0
  }
2050
0
  else
2051
0
  {//Cb or Cr
2052
0
    refx = cu.Cb().x + (bv.hor >> shiftSampleHor);
2053
0
    refy = cu.Cb().y + (bv.ver >> shiftSampleVer);
2054
0
  }
2055
0
  refx &= ((m_IBCBufferWidth >> shiftSampleHor) - 1);
2056
0
  refy &= ((1 << ctuSizeLog2Ver) - 1);
2057
2058
0
  if (refx + predBuf.bufs[compID].width <= (m_IBCBufferWidth >> shiftSampleHor))
2059
0
  {
2060
0
    const CompArea srcArea = CompArea(compID, cu.chromaFormat, Position(refx, refy), Size(predBuf.bufs[compID].width, predBuf.bufs[compID].height));
2061
0
    const CPelBuf refBuf = m_IBCBuffer.getBuf(srcArea);
2062
0
    predBuf.bufs[compID].copyFrom(refBuf);
2063
0
  }
2064
0
  else
2065
0
  {//wrap around
2066
0
    int width = (m_IBCBufferWidth >> shiftSampleHor) - refx;
2067
0
    CompArea srcArea = CompArea(compID, cu.chromaFormat, Position(refx, refy), Size(width, predBuf.bufs[compID].height));
2068
0
    CPelBuf srcBuf = m_IBCBuffer.getBuf(srcArea);
2069
0
    PelBuf dstBuf = PelBuf(predBuf.bufs[compID].bufAt(Position(0, 0)), predBuf.bufs[compID].stride, Size(width, predBuf.bufs[compID].height));
2070
0
    dstBuf.copyFrom(srcBuf);
2071
2072
0
    width = refx + predBuf.bufs[compID].width - (m_IBCBufferWidth >> shiftSampleHor);
2073
0
    srcArea = CompArea(compID, cu.chromaFormat, Position(0, refy), Size(width, predBuf.bufs[compID].height));
2074
0
    srcBuf = m_IBCBuffer.getBuf(srcArea);
2075
0
    dstBuf = PelBuf(predBuf.bufs[compID].bufAt(Position((m_IBCBufferWidth >> shiftSampleHor) - refx, 0)), predBuf.bufs[compID].stride, Size(width, predBuf.bufs[compID].height));
2076
0
    dstBuf.copyFrom(srcBuf);
2077
0
  }
2078
0
}
2079
2080
void InterPrediction::resetIBCBuffer(const ChromaFormat chromaFormatIDC, const int ctuSize)
2081
0
{
2082
0
  const UnitArea area = UnitArea(chromaFormatIDC, Area(0, 0, m_IBCBufferWidth, ctuSize));
2083
0
  m_IBCBuffer.getBuf(area).fill(-1);
2084
0
}
2085
2086
void InterPrediction::resetVPDUforIBC(const ChromaFormat chromaFormatIDC, const int ctuSize, const int vSize, const int xPos, const int yPos)
2087
0
{
2088
0
  const UnitArea area = UnitArea(chromaFormatIDC, Area(xPos & (m_IBCBufferWidth - 1), yPos & (ctuSize - 1), vSize, vSize));
2089
0
  m_IBCBuffer.getBuf(area).fill(-1);
2090
0
}
2091
bool InterPrediction::isLumaBvValidIBC(const int ctuSize, const int xCb, const int yCb, const int width, const int height, const int xBv, const int yBv)
2092
0
{
2093
0
  if (((yCb + yBv) & (ctuSize - 1)) + height > ctuSize)
2094
0
  {
2095
0
    return false;
2096
0
  }
2097
0
  int refTLx = xCb + xBv;
2098
0
  int refTLy = (yCb + yBv) & (ctuSize - 1);
2099
0
  PelBuf buf = m_IBCBuffer.Y();
2100
0
  for (int x = 0; x < width; x += 4)
2101
0
  {
2102
0
    for (int y = 0; y < height; y += 4)
2103
0
    {
2104
0
      if (buf.at((x + refTLx) & (m_IBCBufferWidth - 1), y + refTLy) == -1) return false;
2105
0
      if (buf.at((x + 3 + refTLx) & (m_IBCBufferWidth - 1), y + refTLy) == -1) return false;
2106
0
      if (buf.at((x + refTLx) & (m_IBCBufferWidth - 1), y + 3 + refTLy) == -1) return false;
2107
0
      if (buf.at((x + 3 + refTLx) & (m_IBCBufferWidth - 1), y + 3 + refTLy) == -1) return false;
2108
0
    }
2109
0
  }
2110
0
  return true;
2111
0
}
2112
2113
} // namespace vvenc
2114
2115
//! \}
2116