Coverage Report

Created: 2026-10-17 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/EncoderLib/EncModeCtrl.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     EncModeCtrl.cpp
45
    \brief    Encoder controller for trying out specific modes
46
*/
47
48
#include "EncCu.h"
49
50
#include "EncModeCtrl.h"
51
#include "CommonLib/RdCost.h"
52
#include "CommonLib/CodingStructure.h"
53
#include "CommonLib/Picture.h"
54
#include "CommonLib/UnitTools.h"
55
#include "CommonLib/dtrace_next.h"
56
57
#include <cmath>
58
59
//! \ingroup EncoderLib
60
//! \{
61
62
namespace vvenc {
63
64
void CacheBlkInfoCtrl::create(int ctuSize)
65
4.62k
{
66
4.62k
  const unsigned numPos = MAX_CU_SIZE >> MIN_CU_LOG2;
67
4.62k
  const int maxSizeIdx  = MAX_CU_SIZE_IDX - MIN_CU_LOG2;
68
69
  //static constexpr size_t numCu = 7921;
70
71
4.62k
  size_t numCu = 0;
72
  
73
32.3k
  for( int wIdx = 0; wIdx < maxSizeIdx; wIdx++ )
74
27.7k
  {
75
194k
    for( int hIdx = 0; hIdx < maxSizeIdx; hIdx++ )
76
166k
    {
77
5.49M
      for( unsigned y = 0; y < numPos; y++ )
78
5.32M
      {
79
175M
        for( unsigned x = 0; x < numPos; x++ )
80
170M
        {
81
          // a block of width W might be offset of N * W + 1/2 W (bcs of TT), same for H
82
          // W = 1 << ( wIdx + 2 )
83
          // 1/2 W = 1 << ( wIdx + 1 )
84
          // remainder of (N+1/2)*W -> x & ( ( 1 << ( wIdx + 1 ) ) - 1 )
85
  
86
170M
          if( (x + (1 << (wIdx)) <= (ctuSize >> MIN_CU_LOG2))
87
119M
              && (y + (1 << (hIdx)) <= (ctuSize >> MIN_CU_LOG2))
88
84.2M
              && (((x << MIN_CU_LOG2) & ((1 << (wIdx + MIN_CU_LOG2 - 1)) - 1)) == 0)
89
55.5M
              && (((y << MIN_CU_LOG2) & ((1 << (hIdx + MIN_CU_LOG2 - 1)) - 1)) == 0) )
90
36.6M
          {
91
36.6M
            numCu++;
92
36.6M
          }
93
170M
        }
94
5.32M
      }
95
166k
    }
96
27.7k
  }
97
98
4.62k
  m_codedCUInfoBuf = new CodedCUInfo[numCu];
99
4.62k
  CodedCUInfo* cuInfo = m_codedCUInfoBuf;
100
101
32.3k
  for( int wIdx = 0; wIdx < maxSizeIdx; wIdx++ )
102
27.7k
  {
103
194k
    for( int hIdx = 0; hIdx < maxSizeIdx; hIdx++ )
104
166k
    {
105
5.49M
      for( unsigned y = 0; y < numPos; y++ )
106
5.32M
      {
107
175M
        for( unsigned x = 0; x < numPos; x++ )
108
170M
        {
109
          // a block of width W might be offset of N * W + 1/2 W (bcs of TT), same for H
110
          // W = 1 << ( wIdx + 2 )
111
          // 1/2 W = 1 << ( wIdx + 1 )
112
          // remainder of (N+1/2)*W -> x & ( ( 1 << ( wIdx + 1 ) ) - 1 )
113
114
170M
          if(( x + (1<<(wIdx)) <= ( ctuSize >> MIN_CU_LOG2 ) )
115
119M
            && ( y + (1<<(hIdx)) <= ( ctuSize >> MIN_CU_LOG2 ) )
116
84.2M
            && ( ( ( x << MIN_CU_LOG2 ) & ((1 << (wIdx + MIN_CU_LOG2 - 1)) - 1) ) == 0 )
117
55.5M
            && ( ( ( y << MIN_CU_LOG2 ) & ((1 << (hIdx + MIN_CU_LOG2 - 1)) - 1) ) == 0 ) )
118
36.6M
          {
119
36.6M
            m_codedCUInfo[wIdx][hIdx][x][y] = cuInfo++;
120
36.6M
            m_codedCUInfo[wIdx][hIdx][x][y]->poc       = -1;
121
36.6M
            m_codedCUInfo[wIdx][hIdx][x][y]->ctuRsAddr = -1;
122
36.6M
          }
123
133M
          else
124
133M
          {
125
133M
            m_codedCUInfo[wIdx][hIdx][x][y] = nullptr;
126
133M
          }
127
170M
        }
128
5.32M
      }
129
166k
    }
130
27.7k
  }
131
4.62k
}
132
133
void CacheBlkInfoCtrl::destroy()
134
4.62k
{
135
4.62k
  delete[] m_codedCUInfoBuf;
136
4.62k
  m_codedCUInfoBuf = nullptr;
137
4.62k
}
138
139
void CacheBlkInfoCtrl::init( const Slice &slice )
140
3.50k
{
141
3.50k
  m_pcv = slice.pps->pcv;
142
3.50k
}
143
144
void CacheBlkInfoCtrl::initBlk( const UnitArea& area, int poc )
145
123k
{
146
123k
  unsigned idx1, idx2, idx3, idx4;
147
123k
  getAreaIdxNew( area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
148
149
123k
  const int ctuRsAddr = getCtuAddr( area.lumaPos(), *m_pcv );
150
123k
  CodedCUInfo* cuInfo = m_codedCUInfo[idx1][idx2][idx3][idx4];
151
152
123k
  if( cuInfo->poc != poc || cuInfo->ctuRsAddr != ctuRsAddr )
153
87.7k
  {
154
87.7k
    GCC_WARNING_DISABLE_class_memaccess
155
87.7k
    memset( cuInfo, 0, sizeof( CodedCUInfo ) );
156
87.7k
    GCC_WARNING_RESET
157
158
87.7k
    cuInfo->poc       = poc;
159
87.7k
    cuInfo->ctuRsAddr = ctuRsAddr;
160
87.7k
  }
161
123k
}
162
163
CodedCUInfo& CacheBlkInfoCtrl::getBlkInfo( const UnitArea& area )
164
203k
{
165
203k
  unsigned idx1, idx2, idx3, idx4;
166
203k
  getAreaIdxNew( area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
167
//  DTRACE( g_trace_ctx, D_TMP, "%d loc %d %d %d %d\n", g_trace_ctx->getChannelCounter(D_TMP), idx1, idx2, idx3, idx4);
168
203k
  return *m_codedCUInfo[idx1][idx2][idx3][idx4];
169
203k
}
170
171
void CodedCUInfo::setMv( const RefPicList refPicList, const int iRefIdx, const Mv& rMv )
172
0
{
173
0
  if( iRefIdx >= MAX_STORED_CU_INFO_REFS ) return;
174
175
0
  saveMv [refPicList][iRefIdx] = rMv;
176
0
  validMv[refPicList][iRefIdx] = true;
177
0
}
178
179
bool CodedCUInfo::getMv( const RefPicList refPicList, const int iRefIdx, Mv& rMv ) const
180
0
{
181
0
  if( iRefIdx >= MAX_STORED_CU_INFO_REFS )
182
0
  {
183
0
    rMv = saveMv[refPicList][0];
184
0
    return false;
185
0
  }
186
187
0
  rMv = saveMv[refPicList][iRefIdx];
188
0
  return validMv[refPicList][iRefIdx];
189
0
}
190
191
uint8_t CacheBlkInfoCtrl::findBestSbt( const UnitArea& area, const uint32_t curPuSse )
192
0
{
193
0
  unsigned idx1, idx2, idx3, idx4;
194
0
  getAreaIdxNew( area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
195
0
  CodedCUInfo* pSbtSave = m_codedCUInfo[idx1][idx2][idx3][idx4];
196
197
0
  for( int i = 0; i < pSbtSave->numPuInfoStored; i++ )
198
0
  {
199
0
    if( curPuSse == pSbtSave->puSse[i] )
200
0
    {
201
0
      return pSbtSave->puSbt[i];
202
0
    }
203
0
  }
204
205
0
  return MAX_UCHAR;
206
0
}
207
208
bool CacheBlkInfoCtrl::saveBestSbt( const UnitArea& area, const uint32_t curPuSse, const uint8_t curPuSbt )
209
0
{
210
0
  unsigned idx1, idx2, idx3, idx4;
211
0
  getAreaIdxNew( area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
212
0
  CodedCUInfo* pSbtSave = m_codedCUInfo[idx1][idx2][idx3][idx4];
213
214
0
  if( pSbtSave->numPuInfoStored == SBT_NUM_SL )
215
0
  {
216
0
    return false;
217
0
  }
218
219
0
  pSbtSave->puSse[pSbtSave->numPuInfoStored] = curPuSse;
220
0
  pSbtSave->puSbt[pSbtSave->numPuInfoStored] = curPuSbt;
221
0
  pSbtSave->numPuInfoStored++;
222
223
0
  return true;
224
0
}
225
226
static bool isTheSameNbHood( const CodingUnit &cu, const CodingStructure& cs, const Partitioner &partitioner, int picW, int picH )
227
0
{
228
0
  if( cu.chType != partitioner.chType )
229
0
  {
230
0
    return false;
231
0
  }
232
233
0
  const PartitioningStack &ps = partitioner.getPartStack();
234
235
0
  int i = 1;
236
237
0
  for( ; i < ps.size(); i++ )
238
0
  {
239
0
    if( ps[i].split != CU::getSplitAtDepth( cu, i - 1 ) )
240
0
    {
241
0
      break;
242
0
    }
243
0
  }
244
245
0
  const UnitArea& cmnAnc = ps[i - 1].parts[ps[i - 1].idx];
246
0
  const UnitArea cuArea  = CS::getArea( cs, cu, partitioner.chType, partitioner.treeType );
247
248
0
  for( int i = 0; i < cmnAnc.blocks.size(); i++ )
249
0
  {
250
0
    if( i < cuArea.blocks.size() && cuArea.blocks[i].valid() && cuArea.blocks[i].pos() != cmnAnc.blocks[i].pos() )
251
0
    {
252
0
      return false;
253
0
    }
254
0
  }
255
256
0
  return true;
257
0
}
258
259
void BestEncInfoCache::create( const bool reuseCuResults, const ChromaFormat chFmt, const int ctuSize )
260
4.62k
{
261
4.62k
  m_reuseCuResults = reuseCuResults;
262
263
4.62k
  if( !m_reuseCuResults ) return;
264
265
0
  m_chFmt = chFmt;
266
0
  std::fill_n( &m_bestEncInfo[0][0][0][0], sizeof( m_bestEncInfo ) / sizeof( m_bestEncInfo[0][0][0][0] ), nullptr );
267
0
}
268
269
void BestEncInfoCache::destroy()
270
4.62k
{
271
4.62k
  if( !m_reuseCuResults ) return;
272
273
0
  std::fill_n( &m_bestEncInfo[0][0][0][0], sizeof( m_bestEncInfo ) / sizeof( m_bestEncInfo[0][0][0][0] ), nullptr );
274
0
  m_filledSlots.clear();
275
0
  m_entryArena.release();
276
0
  m_coeffArena.release();
277
0
  m_dmvrMvArena.release();
278
279
0
  m_pcv = nullptr;
280
0
}
281
282
void BestEncInfoCache::init( const Slice &slice )
283
3.50k
{
284
3.50k
  if( !m_reuseCuResults ) return;
285
286
  // A new CTU starts, and no result of the previous one can match its CUs.
287
0
  for( BestEncodingInfo** slot : m_filledSlots )
288
0
  {
289
0
    *slot = nullptr;
290
0
  }
291
0
  m_filledSlots.clear();
292
0
  m_entryArena.reset();
293
0
  m_coeffArena.reset();
294
0
  m_dmvrMvArena.reset();
295
296
0
  bool isInitialized = m_pcv;
297
298
0
  m_pcv = slice.pps->pcv;
299
300
0
  if( isInitialized ) return;
301
302
0
  m_dummyCS.pcv = m_pcv;
303
0
}
304
305
// Takes storage for the result of a CU with size indices wIdx and hIdx, set up the way the earlier
306
// fixed table of results was set up when it was created.
307
BestEncodingInfo* BestEncInfoCache::xNewEntry( const int wIdx, const int hIdx )
308
0
{
309
0
  BestEncodingInfo* encInfo = m_entryArena.take( 1 );
310
0
  encInfo->~BestEncodingInfo();
311
0
  new( encInfo ) BestEncodingInfo();
312
313
0
  const UnitArea area( m_chFmt, Area( 0, 0, 1 << ( wIdx + MIN_CU_LOG2 ), 1 << ( hIdx + MIN_CU_LOG2 ) ) );
314
315
0
  encInfo->cu.UnitArea::operator=( area );
316
0
  encInfo->tu.UnitArea::operator=( area );
317
318
0
  encInfo->cu.chType   = CH_L;
319
0
  encInfo->cu.treeType = TREE_D;
320
0
  encInfo->cu.modeType = MODE_TYPE_ALL;
321
0
  encInfo->cu.qp       = MAX_SCHAR;
322
0
  encInfo->tu.chType   = CH_L;
323
324
0
  if( hIdx >= 1 && wIdx >= 1 && ( wIdx + hIdx ) >= 3 )
325
0
  {
326
0
    const int dmvrSize = ( 1 << std::max( 0, ( wIdx + MIN_CU_LOG2 - DMVR_SUBCU_SIZE_LOG2 ) ) ) * ( 1 << std::max( 0, ( hIdx + MIN_CU_LOG2 - DMVR_SUBCU_SIZE_LOG2 ) ) );
327
0
    encInfo->cu.mvdL0SubPu = m_dmvrMvArena.take( dmvrSize );
328
0
  }
329
330
0
  TCoeffSig* coeff[MAX_NUM_TBLOCKS] = { 0, };
331
0
  for( int i = 0; i < area.blocks.size(); i++ )
332
0
  {
333
0
    coeff[i] = m_coeffArena.take( area.blocks[i].area() );
334
0
  }
335
336
0
  encInfo->tu.cs = &m_dummyCS;
337
0
  encInfo->tu.init( coeff );
338
339
0
  encInfo->poc      = -1;
340
0
  encInfo->testMode = EncTestMode();
341
0
  return encInfo;
342
0
}
343
344
bool BestEncInfoCache::setFromCs( const CodingStructure& cs, const EncTestMode& testMode, const Partitioner& partitioner )
345
77.7k
{
346
77.7k
  if( !m_reuseCuResults ) return false;
347
348
0
  if( cs.cus.size() != 1 || cs.tus.size() != 1 || partitioner.maxBTD <= 1 )
349
0
  {
350
0
    return false;
351
0
  }
352
353
0
  unsigned idx1, idx2, idx3, idx4;
354
0
  getAreaIdxNew( cs.area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
355
356
0
  BestEncodingInfo*& slot = m_bestEncInfo[idx1][idx2][idx3][idx4];
357
0
  if( !slot )
358
0
  {
359
0
    slot = xNewEntry( idx1, idx2 );
360
0
    m_filledSlots.push_back( &slot );
361
0
  }
362
0
  BestEncodingInfo& encInfo = *slot;
363
364
0
  encInfo.poc            =  cs.picture->poc;
365
0
  encInfo.cu.UnitArea::operator= ( *cs.cus.front() );
366
0
  encInfo.tu.UnitArea::operator= ( *cs.tus.front() );
367
0
  encInfo.cu             = *cs.cus.front();
368
0
  for( auto &blk : cs.tus.front()->blocks )
369
0
  {
370
0
    if( blk.valid() ) encInfo.tu.copyComponentFrom( *cs.tus.front(), blk.compID );
371
0
  }
372
0
  encInfo.testMode       = testMode;
373
0
  encInfo.dist           = cs.dist;
374
0
  encInfo.costEDO        = cs.costDbOffset;
375
376
0
  return true;
377
0
}
378
379
bool BestEncInfoCache::isReusingCuValid( const CodingStructure& cs, const Partitioner& partitioner, int qp )
380
200k
{
381
200k
  if( !m_reuseCuResults || partitioner.treeType == TREE_C || partitioner.maxBTD <= 1 )
382
200k
  {
383
200k
    return false; //if save & load is allowed for chroma CUs, we should check whether luma info (pred, recon, etc) is the same, which is quite complex
384
200k
  }
385
386
0
  unsigned idx1, idx2, idx3, idx4;
387
0
  getAreaIdxNew( cs.area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
388
389
0
  const BestEncodingInfo* stored = m_bestEncInfo[idx1][idx2][idx3][idx4];
390
0
  if( !stored )
391
0
  {
392
0
    return false;
393
0
  }
394
0
  const BestEncodingInfo& encInfo = *stored;
395
396
0
  if( encInfo.cu.treeType != partitioner.treeType || encInfo.cu.modeType != partitioner.modeType )
397
0
  {
398
0
    return false;
399
0
  }
400
0
  if( encInfo.cu.qp != qp )
401
0
    return false;
402
0
  if( cs.picture->poc != encInfo.poc 
403
0
    || CS::getArea( cs, cs.area, partitioner.chType, partitioner.treeType ) != CS::getArea( cs, encInfo.cu, partitioner.chType, partitioner.treeType ) 
404
0
    || !isTheSameNbHood( encInfo.cu, cs, partitioner, (cs.picture->Y().width), (cs.picture->Y().height))
405
0
    || CU::isIBC(encInfo.cu)
406
0
    || partitioner.currQgEnable() || cs.currQP[partitioner.chType] != encInfo.cu.qp
407
0
    )
408
0
  {
409
0
    return false;
410
0
  }
411
0
  else
412
0
  {
413
0
    return true;
414
0
  }
415
0
}
416
417
bool BestEncInfoCache::setCsFrom( CodingStructure& cs, EncTestMode& testMode, const Partitioner& partitioner ) const
418
0
{
419
0
  if( !m_reuseCuResults ) return false;
420
421
0
  unsigned idx1, idx2, idx3, idx4;
422
0
  getAreaIdxNew( cs.area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
423
424
0
  const BestEncodingInfo* stored = m_bestEncInfo[idx1][idx2][idx3][idx4];
425
0
  if( !stored )
426
0
  {
427
0
    return false;
428
0
  }
429
0
  const BestEncodingInfo& encInfo = *stored;
430
431
0
  if( cs.picture->poc != encInfo.poc 
432
0
    || CS::getArea( cs, cs.area, partitioner.chType, partitioner.treeType ) != CS::getArea( cs, encInfo.cu, partitioner.chType, partitioner.treeType ) 
433
0
    || !isTheSameNbHood( encInfo.cu, cs, partitioner, (cs.picture->Y().width), (cs.picture->Y().height))
434
0
    || partitioner.currQgEnable() || cs.currQP[partitioner.chType] != encInfo.cu.qp
435
0
    )
436
0
  {
437
0
    return false;
438
0
  }
439
440
0
  const UnitArea ua = CS::getArea( cs, cs.area, partitioner.chType, partitioner.treeType );
441
0
  CodingUnit     &cu = cs.addCU( ua, partitioner.chType );
442
0
  cu.treeType = partitioner.treeType;
443
0
  cu.modeType = partitioner.modeType;
444
0
  cu.initPuData();
445
0
  TransformUnit  &tu = cs.addTU( ua, partitioner.chType, &cu );
446
447
0
  cu          .repositionTo( encInfo.cu );
448
0
  cu          .repositionTo( encInfo.cu );
449
0
  tu          .repositionTo( encInfo.tu );
450
451
0
  cu          = encInfo.cu;
452
0
  cu          = encInfo.cu;
453
0
  for( auto &blk : tu.blocks )
454
0
  {
455
0
    if( blk.valid() ) tu.copyComponentFrom( encInfo.tu, blk.compID );
456
0
  }
457
458
0
  testMode    = encInfo.testMode;
459
0
  cs.dist     = encInfo.dist;
460
0
  cs.costDbOffset = encInfo.costEDO;
461
0
  return true;
462
0
}
463
464
465
//////////////////////////////////////////////////////////////////////////
466
// EncModeCtrl
467
//////////////////////////////////////////////////////////////////////////
468
void EncModeCtrl::init( const VVEncCfg& encCfg, RdCost* pRdCost )
469
4.62k
{
470
4.62k
  m_pcEncCfg = &encCfg;
471
4.62k
  m_pcRdCost = pRdCost;
472
4.62k
  comprCUCtx = nullptr;
473
474
4.62k
  CacheBlkInfoCtrl::create( encCfg.m_CTUSize );
475
4.62k
  BestEncInfoCache::create( encCfg.m_reuseCuResults, encCfg.m_internChromaFormat, encCfg.m_CTUSize );
476
4.62k
}
477
478
void EncModeCtrl::destroy()
479
4.62k
{
480
4.62k
  CacheBlkInfoCtrl::destroy();
481
4.62k
  BestEncInfoCache::destroy();
482
4.62k
}
483
484
void EncModeCtrl::initCTUEncoding( const Slice &slice, int tileIdx )
485
3.50k
{
486
3.50k
  CacheBlkInfoCtrl::init( slice );
487
3.50k
  BestEncInfoCache::init( slice );
488
489
3.50k
  CHECK( !m_ComprCUCtxList.empty(), "Mode list is not empty at the beginning of a CTU" );
490
491
3.50k
  if( m_pcEncCfg->m_fastQtBtEnc )
492
3.50k
  {
493
3.50k
    m_skipThresholdE0023FastEnc = ((slice.getMinPictureDistance() <= PICTURE_DISTANCE_TH) ? FAST_SKIP_DEPTH : SKIP_DEPTH);
494
3.50k
  }
495
0
  else
496
0
  {
497
0
    m_skipThresholdE0023FastEnc = SKIP_DEPTH;
498
0
  }
499
500
3.50k
  m_tileIdx = tileIdx;
501
3.50k
}
502
503
void EncModeCtrl::initCULevel( Partitioner &partitioner, const CodingStructure& cs, int  MergeSimpleFlag)
504
123k
{
505
  // Min/max depth
506
123k
  unsigned minDepth = 0;
507
123k
  unsigned maxDepth = cs.pcv->getMaxDepth( cs.slice->sliceType, partitioner.chType );
508
123k
  if( m_pcEncCfg->m_useFastLCTU )
509
123k
  {
510
123k
    partitioner.setMaxMinDepth(minDepth, maxDepth, cs, cs.picture->useQtbttSpeedUpMode, MergeSimpleFlag);
511
123k
  }
512
513
123k
  minDepth = std::max<unsigned>( minDepth, cs.pcv->getMinDepth( cs.slice->sliceType, partitioner.chType ) );
514
123k
  maxDepth = std::min<unsigned>( maxDepth, cs.pcv->getMaxDepth( cs.slice->sliceType, partitioner.chType ) );
515
516
123k
  m_ComprCUCtxList.push_back( ComprCUCtx( cs, minDepth, maxDepth ) );
517
123k
  comprCUCtx = &m_ComprCUCtxList.back();
518
519
123k
  const CodingUnit* cuLeft  = cs.getCURestricted( cs.area.blocks[partitioner.chType].pos().offset( -1, 0 ), cs.area.blocks[partitioner.chType].pos(), cs.slice->independentSliceIdx, m_tileIdx, partitioner.chType, partitioner.treeType );
520
123k
  const CodingUnit* cuAbove = cs.getCURestricted( cs.area.blocks[partitioner.chType].pos().offset( 0, -1 ), cs.area.blocks[partitioner.chType].pos(), cs.slice->independentSliceIdx, m_tileIdx, partitioner.chType, partitioner.treeType );
521
522
123k
  const bool qtBeforeBt = ( (  cuLeft  &&  cuAbove  && cuLeft ->qtDepth > partitioner.currQtDepth && cuAbove->qtDepth > partitioner.currQtDepth )
523
121k
                         || (  cuLeft  && !cuAbove  && cuLeft ->qtDepth > partitioner.currQtDepth )
524
119k
                         || ( !cuLeft  &&  cuAbove  && cuAbove->qtDepth > partitioner.currQtDepth )
525
116k
                         || ( !cuAbove && !cuLeft   && cs.area.lwidth() >= ( 32 << cs.slice->TLayer ) )
526
103k
                         || ( m_pcEncCfg->m_qtbttSpeedUp > 1 && partitioner.maxBTD < ( ( cs.slice->isIntra() && !cs.sps->IBC ) ? 3 : 2 ) ) )
527
19.6k
                         && ( cs.area.lwidth() > ( cs.pcv->getMinQtSize( *cs.slice, partitioner.chType ) << 1 ) );
528
529
  // set features
530
123k
  ComprCUCtx &cuECtx    = *comprCUCtx;
531
123k
  cuECtx.qtBeforeBt     = qtBeforeBt;
532
123k
  cuECtx.doTriHorzSplit = true;
533
123k
  cuECtx.doTriVertSplit = true;
534
123k
  cuECtx.doMoreSplits   = 3;
535
123k
  cuECtx.isReusingCu    = isReusingCuValid( cs, partitioner, cs.baseQP );
536
123k
  cuECtx.didHorzSplit   = partitioner.canSplit( CU_HORZ_SPLIT, cs );
537
123k
  cuECtx.didVertSplit   = partitioner.canSplit( CU_VERT_SPLIT, cs );
538
123k
  cuECtx.doHorChromaSplit = true;
539
123k
  cuECtx.doVerChromaSplit = true;
540
123k
  cuECtx.doQtChromaSplit  = true;
541
542
123k
  if( m_pcEncCfg->m_contentBasedFastQtbt && cs.pcv->getMaxMTTDepth(*cs.slice, partitioner.chType))
543
123k
  {
544
123k
    const CompArea& currArea = partitioner.currArea().Y();
545
123k
    int cuHeight  = currArea.height;
546
123k
    int cuWidth   = currArea.width;
547
548
123k
    const bool condIntraInter = m_pcEncCfg->m_IntraPeriod == 1 ? ( partitioner.currBtDepth == 0 ) : ( cuHeight > 32 && cuWidth > 32 );
549
550
123k
    if( cuWidth == cuHeight && condIntraInter )
551
25.5k
    {
552
25.5k
      const CPelBuf bufCurrArea = cs.getOrgBuf( partitioner.currArea().block( COMP_Y ) );
553
554
25.5k
      Intermediate_Int horVal = 0;
555
25.5k
      Intermediate_Int verVal = 0;
556
25.5k
      Intermediate_Int dupVal = 0;
557
25.5k
      Intermediate_Int dowVal = 0;
558
559
25.5k
      unsigned j, k;
560
561
2.05M
      for( k = 0; k < cuHeight - 1; k++ )
562
2.03M
      {
563
185M
        for( j = 0; j < cuWidth - 1; j++ )
564
183M
        {
565
183M
          horVal += abs( bufCurrArea.at( j + 1, k     ) - bufCurrArea.at( j, k ) );
566
183M
          verVal += abs( bufCurrArea.at( j    , k + 1 ) - bufCurrArea.at( j, k ) );
567
183M
          dowVal += abs( bufCurrArea.at( j + 1, k )     - bufCurrArea.at( j, k + 1 ) );
568
183M
          dupVal += abs( bufCurrArea.at( j + 1, k + 1 ) - bufCurrArea.at( j, k ) );
569
183M
        }
570
2.03M
      }
571
572
25.5k
      cuECtx.grad_horVal = (double)horVal;
573
25.5k
      cuECtx.grad_verVal = (double)verVal;
574
25.5k
      cuECtx.grad_dowVal = (double)dowVal;
575
25.5k
      cuECtx.grad_dupVal = (double)dupVal;
576
25.5k
    }
577
123k
  }
578
123k
}
579
580
void EncModeCtrl::finishCULevel( Partitioner &partitioner )
581
123k
{
582
123k
  m_ComprCUCtxList.pop_back();
583
123k
  comprCUCtx = m_ComprCUCtxList.size() ? &m_ComprCUCtxList.back() : nullptr;
584
123k
}
585
586
bool EncModeCtrl::trySplit( const EncTestMode& encTestmode, const CodingStructure &cs, Partitioner& partitioner, const EncTestMode& lastTestmode )
587
299k
{
588
299k
  ComprCUCtx& cuECtx = *comprCUCtx;
589
590
299k
  const PartSplit implicitSplit = partitioner.getImplicitSplit( cs );
591
299k
  const bool isBoundary         = implicitSplit != CU_DONT_SPLIT;
592
593
299k
  if( ( m_pcEncCfg->m_IntraPeriod == 1 ) && ( partitioner.chType == CH_C ) && ( !cuECtx.doQtChromaSplit ) )
594
0
  {
595
0
    cuECtx.maxDepth         = partitioner.currDepth;
596
0
  }
597
598
299k
  if( isBoundary )
599
74.9k
  {
600
74.9k
    if( encTestmode.type != ETM_SPLIT_QT )
601
29.7k
    {
602
29.7k
      return getPartSplit( encTestmode ) == implicitSplit;
603
29.7k
    }
604
45.2k
    else
605
45.2k
    {
606
45.2k
      return partitioner.canSplit( CU_QUAD_SPLIT, cs );
607
45.2k
    }
608
74.9k
  }
609
610
224k
  const Slice&           slice       = *cs.slice;
611
224k
  const uint32_t         width       = partitioner.currArea().lumaSize().width;
612
224k
  const CodingStructure *bestCS      = cuECtx.bestCS;
613
224k
  const CodingUnit      *bestCU      = cuECtx.bestCU;
614
615
224k
  if( cuECtx.minDepth > partitioner.currQtDepth && partitioner.canSplit( CU_QUAD_SPLIT, cs ) )
616
0
  {
617
    // enforce QT
618
0
    return encTestmode.type == ETM_SPLIT_QT;
619
0
  }
620
224k
  else if( encTestmode.type == ETM_SPLIT_QT && cuECtx.maxDepth <= partitioner.currQtDepth )
621
1.29k
  {
622
    // don't check this QT depth
623
1.29k
    return false;
624
1.29k
  }
625
626
223k
  CHECK( ! isModeSplit( encTestmode ), "wrong method" );
627
628
  //////////////////////////////////////////////////////////////////////////
629
  // skip-history rule - don't split further if at least for three past levels
630
  //                     in the split tree it was found that skip is the best mode
631
  //////////////////////////////////////////////////////////////////////////
632
223k
  int skipScore = 0;
633
634
223k
  if ((!slice.isIntra() || slice.sps->IBC) && cuECtx.isBestNoSplitSkip )
635
0
  {
636
0
    for( int i = 2; i <= m_ComprCUCtxList.size(); i++ )
637
0
    {
638
0
      if( ( m_ComprCUCtxList.end() - i )->isBestNoSplitSkip )
639
0
      {
640
0
        skipScore += 1;
641
0
      }
642
0
      else
643
0
      {
644
0
        break;
645
0
      }
646
0
    }
647
0
  }
648
649
223k
  const PartSplit split = getPartSplit( encTestmode );
650
223k
  if( !partitioner.canSplit( split, cs ) || skipScore >= 2 || ( skipScore == 1 && m_ComprCUCtxList.size() == 2 ) )
651
57.4k
  {
652
57.4k
    if( split == CU_HORZ_SPLIT ) cuECtx.didHorzSplit = false;
653
57.4k
    if( split == CU_VERT_SPLIT ) cuECtx.didVertSplit = false;
654
57.4k
    if( split == CU_QUAD_SPLIT ) cuECtx.didQuadSplit = false;
655
57.4k
    return false;
656
57.4k
  }
657
658
166k
  if( isChroma( partitioner.chType ) && !cuECtx.doHorChromaSplit && ( split == CU_HORZ_SPLIT || split == CU_TRIH_SPLIT ) )
659
0
  {
660
0
    if( split == CU_HORZ_SPLIT )
661
0
    {
662
0
      cuECtx.didHorzSplit = false;
663
0
    }
664
665
0
    return false;
666
0
  }
667
668
166k
  if( isChroma( partitioner.chType ) && !cuECtx.doVerChromaSplit && ( split == CU_VERT_SPLIT || split == CU_TRIV_SPLIT ) )
669
0
  {
670
0
    if( split == CU_VERT_SPLIT )
671
0
    {
672
0
      cuECtx.didVertSplit = false;
673
0
    }
674
675
0
    return false;
676
0
  }
677
678
166k
  if( m_pcEncCfg->m_contentBasedFastQtbt )
679
166k
  {
680
166k
    const CompArea& currArea = partitioner.currArea().Y();
681
166k
    int cuHeight  = currArea.height;
682
166k
    int cuWidth   = currArea.width;
683
684
166k
    const bool condIntraInter = m_pcEncCfg->m_IntraPeriod == 1 ? ( partitioner.currBtDepth == 0 ) : ( cuHeight > 32 && cuWidth > 32 );
685
686
166k
    if( cuWidth == cuHeight && condIntraInter && split != CU_QUAD_SPLIT )
687
8.55k
    {
688
8.55k
      const double th1 = m_pcEncCfg->m_IntraPeriod == 1 ?  1.2              :  1.0;
689
8.55k
      const double th2 = m_pcEncCfg->m_IntraPeriod == 1 ? (1.2 / sqrt( 2 )) : (1.0 / sqrt( 2 ));
690
691
8.55k
      if( cuECtx.grad_horVal > th1 * cuECtx.grad_verVal && cuECtx.grad_horVal > th2 * cuECtx.grad_dowVal && cuECtx.grad_horVal > th2 * cuECtx.grad_dupVal && ( split == CU_HORZ_SPLIT || split == CU_TRIH_SPLIT ) )
692
0
      {
693
0
        return false;
694
0
      }
695
8.55k
      if( th2 * cuECtx.grad_dupVal < cuECtx.grad_verVal && th2 * cuECtx.grad_dowVal < cuECtx.grad_verVal && th1 * cuECtx.grad_horVal < cuECtx.grad_verVal && ( split == CU_VERT_SPLIT || split == CU_TRIV_SPLIT ) )
696
0
      {
697
0
        return false;
698
0
      }
699
8.55k
    }
700
701
166k
    if( m_pcEncCfg->m_IntraPeriod == 1 && cuWidth <= 32 && cuHeight <= 32 && bestCS && bestCS->tus.size() == 1 && bestCU && bestCU->depth == partitioner.currDepth && partitioner.currBtDepth > 1 && isLuma( partitioner.chType ) )
702
0
    {
703
0
      if( !bestCU->rootCbf )
704
0
      {
705
0
        return false;
706
0
      }
707
0
    }
708
166k
  }
709
710
166k
  if( m_pcEncCfg->m_qtbttSpeedUp > 1 )
711
166k
  {
712
166k
    const int availDepth = cs.pcv->getMaxMTTDepth( slice, partitioner.chType ) - partitioner.currMtDepth;
713
166k
    if( bestCU && bestCU->skip && availDepth <= ( 3 - m_skipThresholdE0023FastEnc ) && !isModeSplit( lastTestmode ) && split != CU_QUAD_SPLIT )
714
0
    {
715
0
      return false;
716
0
    }
717
166k
  }
718
166k
  if( bestCU && bestCU->skip && bestCU->mtDepth >= m_skipThresholdE0023FastEnc && !isModeSplit( lastTestmode ) )
719
0
  {
720
0
    return false;
721
0
  }
722
723
166k
  bool resetFeature = false;
724
725
166k
  switch( split )
726
166k
  {
727
19.0k
    case CU_QUAD_SPLIT:
728
19.0k
      {
729
19.0k
        if( !cuECtx.qtBeforeBt && bestCU )
730
16.9k
        {
731
16.9k
          unsigned maxBTD        = cs.pcv->getMaxMTTDepth( slice, partitioner.chType );
732
16.9k
          const CodingUnit *cuBR = bestCS->cus.back();
733
16.9k
          unsigned height        = partitioner.currArea().lumaSize().height;
734
735
16.9k
          if(((bestCU->btDepth == 0 && maxBTD >= ((slice.isIntra() && !slice.sps->IBC) ? 3 : 2))
736
93
            || (bestCU->btDepth == 1 && cuBR && cuBR->btDepth == 1 && maxBTD >= ((slice.isIntra() && !slice.sps->IBC) ? 4 : 3)))
737
16.9k
            && (width <= MAX_TB_SIZEY && height <= MAX_TB_SIZEY)
738
16.9k
            && cuECtx.didHorzSplit && cuECtx.didVertSplit )
739
13.1k
          {
740
13.1k
            return false;
741
13.1k
          }
742
16.9k
        }
743
5.88k
        if( bestCS )
744
5.88k
        {
745
5.88k
          if( m_pcEncCfg->m_useEarlyCU == 2 && bestCS->cost != MAX_DOUBLE && bestCU && bestCU->skip && cuECtx.nonSkipWasTested && bestCS->cus.size() == 1 )
746
0
          {
747
0
            return false;
748
0
          }
749
750
5.88k
          int stopSplit = (m_pcEncCfg->m_FastInferMerge >> 4) && (bestCS->slice->TLayer > 4);
751
5.88k
          int limitBLsize = stopSplit ? 2048 : 1024;
752
5.88k
          if((m_pcEncCfg->m_useEarlyCU == 1 || stopSplit) && bestCS->cost != MAX_DOUBLE && bestCU && bestCU->skip && partitioner.currArea().lumaSize().area() < limitBLsize )
753
0
          {
754
0
            return false;
755
0
          }
756
5.88k
        }
757
5.88k
      }
758
5.88k
      break;
759
51.1k
    case CU_HORZ_SPLIT:
760
97.8k
    case CU_VERT_SPLIT:
761
97.8k
      resetFeature = true;
762
97.8k
      break;
763
27.6k
    case CU_TRIH_SPLIT:
764
27.6k
      if( cuECtx.didHorzSplit && bestCU && bestCU->btDepth == partitioner.currBtDepth && !bestCU->rootCbf )
765
22.2k
      {
766
22.2k
        return false;
767
22.2k
      }
768
769
5.34k
      if( m_pcEncCfg->m_qtbttSpeedUp > 1 )
770
5.34k
      {
771
        //unsigned maxBTD = cs.pcv->getMaxMTTDepth( slice, partitioner.chType );
772
5.34k
        if( /*maxBTD == 1 && */cuECtx.didHorzSplit && cuECtx.didVertSplit && cuECtx.bestCostHorzSplit > cuECtx.bestCostVertSplit )
773
1.51k
        {
774
1.51k
          return false;
775
1.51k
        }
776
5.34k
      }
777
778
3.83k
      if( !cuECtx.doTriHorzSplit )
779
16
      {
780
16
        return false;
781
16
      }
782
783
3.81k
      if (m_pcEncCfg->m_fastTTSplit && cuECtx.bestCostHorzSplit < MAX_DOUBLE)
784
2.79k
      {
785
2.79k
        if (cuECtx.bestCostBeforeSplit < MAX_DOUBLE && (cuECtx.bestCostHorzSplit > m_pcEncCfg->m_fastTT_th * cuECtx.bestCostBeforeSplit))
786
2.32k
        {
787
2.32k
          return false;
788
2.32k
        }
789
466
        if (cuECtx.bestCostVertSplit < MAX_DOUBLE && (cuECtx.bestCostHorzSplit > m_pcEncCfg->m_fastTT_th * cuECtx.bestCostVertSplit))
790
0
        {
791
0
          return false;
792
0
        }
793
466
      }
794
1.48k
      break;
795
21.6k
    case CU_TRIV_SPLIT:
796
21.6k
      if( cuECtx.didVertSplit && bestCU && bestCU->btDepth == partitioner.currBtDepth && !bestCU->rootCbf )
797
18.3k
      {
798
18.3k
        return false;
799
18.3k
      }
800
801
3.30k
      if( m_pcEncCfg->m_qtbttSpeedUp > 1 )
802
3.30k
      {
803
        //unsigned maxBTD = cs.pcv->getMaxMTTDepth( slice, partitioner.chType );
804
3.30k
        if( /*maxBTD == 1 && */cuECtx.didHorzSplit && cuECtx.didVertSplit && cuECtx.bestCostHorzSplit < cuECtx.bestCostVertSplit )
805
1.77k
        {
806
1.77k
          return false;
807
1.77k
        }
808
3.30k
      }
809
810
1.52k
      if( !cuECtx.doTriVertSplit )
811
34
      {
812
34
        return false;
813
34
      }
814
815
1.49k
      if (m_pcEncCfg->m_fastTTSplit && cuECtx.bestCostVertSplit < MAX_DOUBLE)
816
515
      {
817
515
        if (cuECtx.bestCostBeforeSplit < MAX_DOUBLE && (cuECtx.bestCostVertSplit > m_pcEncCfg->m_fastTT_th * cuECtx.bestCostBeforeSplit))
818
341
        {
819
341
          return false;
820
341
        }
821
174
        if (cuECtx.bestCostHorzSplit < MAX_DOUBLE && (cuECtx.bestCostVertSplit > m_pcEncCfg->m_fastTT_th * cuECtx.bestCostHorzSplit))
822
0
        {
823
0
          return false;
824
0
        }
825
174
      }
826
1.15k
      break;
827
1.15k
    default:
828
0
      THROW( "Only CU split modes are governed by the EncModeCtrl" );
829
0
      return false;
830
0
      break;
831
166k
  }
832
833
106k
  switch( split )
834
106k
  {
835
51.1k
    case CU_HORZ_SPLIT:
836
52.6k
    case CU_TRIH_SPLIT:
837
52.6k
      if( cuECtx.qtBeforeBt && cuECtx.didQuadSplit )
838
1.75k
      {
839
1.75k
        if( cuECtx.maxQtSubDepth > partitioner.currQtDepth + 1 )
840
0
        {
841
0
          if( resetFeature ) cuECtx.didHorzSplit = false;
842
0
          return false;
843
0
        }
844
1.75k
      }
845
52.6k
      break;
846
52.6k
    case CU_VERT_SPLIT:
847
47.8k
    case CU_TRIV_SPLIT:
848
47.8k
      if( cuECtx.qtBeforeBt && cuECtx.didQuadSplit )
849
1.81k
      {
850
1.81k
        if( cuECtx.maxQtSubDepth > partitioner.currQtDepth + 1 )
851
0
        {
852
0
          if( resetFeature ) cuECtx.didVertSplit = false;
853
0
          return false;
854
0
        }
855
1.81k
      }
856
47.8k
      break;
857
47.8k
    default:
858
5.88k
      break;
859
106k
  }
860
861
106k
  if( split == CU_QUAD_SPLIT )
862
5.88k
  {
863
5.88k
    cuECtx.didQuadSplit = m_pcEncCfg->m_qtbttSpeedUp <= 1 || !!cuECtx.doMoreSplits;
864
5.88k
  }
865
866
106k
  return m_pcEncCfg->m_qtbttSpeedUp <= 1 || !!cuECtx.doMoreSplits;
867
106k
}
868
869
bool EncModeCtrl::tryMode( const EncTestMode& encTestmode, const CodingStructure &cs, Partitioner& partitioner )
870
125k
{
871
125k
  CHECK( isModeSplit( encTestmode ), "wrong method");
872
873
125k
  ComprCUCtx& cuECtx = m_ComprCUCtxList.back();
874
875
125k
  if( cuECtx.minDepth > partitioner.currQtDepth && partitioner.canSplit( CU_QUAD_SPLIT, cs ) )
876
0
  {
877
    // enforce QT
878
0
    return false;
879
0
  }
880
881
125k
  const Slice&           slice        = *cs.slice;
882
125k
  const uint32_t         numComp      = getNumberValidComponents( slice.sps->chromaFormatIdc );
883
125k
  const CodedCUInfo      &relatedCU   = getBlkInfo( partitioner.currArea() );
884
125k
  const Area             &lumaArea    = partitioner.currArea().Y();
885
125k
  const CodingStructure* bestCS       = cuECtx.bestCS;
886
125k
  const EncTestMode      bestMode     = bestCS ?cuECtx.bestMode : EncTestMode();
887
888
125k
  if( encTestmode.type == ETM_INTRA )
889
77.7k
  {
890
    // if this is removed, the IntraSearch::xIntraCodingLumaQT needs to be adapted to support Intra TU split
891
    // also isXXAvailable in IntraPrediction.cpp need to be fixed to check availability within the same CU without isDecomp
892
77.7k
    if (m_pcEncCfg->m_FastInferMerge && !slice.isIntra() && !slice.isIRAP() && !(cs.area.lwidth() == 4 && cs.area.lheight() == 4) && !partitioner.isConsIntra())
893
0
    {
894
0
      if (bestCS && (bestCS->slice->TLayer > (m_pcEncCfg->m_maxTLayer - (m_pcEncCfg->m_FastInferMerge & 7)))
895
0
        && (bestCS->bestParent != nullptr) && bestCS->bestParent->cus.size() && (bestCS->bestParent->cus[0]->skip))
896
0
      {
897
0
        return false;
898
0
      }
899
0
    }
900
901
77.7k
    if( lumaArea.width > cs.sps->getMaxTbSize() || lumaArea.height > cs.sps->getMaxTbSize() )
902
0
    {
903
0
      return false;
904
0
    }
905
906
77.7k
    if (m_pcEncCfg->m_usePbIntraFast && (!cs.slice->isIntra() || cs.slice->sps->IBC) && cuECtx.interHad == 0 && cuECtx.bestCU && !CU::isIntra(*cuECtx.bestCU))
907
0
    {
908
0
      return false;
909
0
    }
910
911
    // INTRA MODES
912
77.7k
    if (cs.sps->IBC && !cuECtx.bestTU)
913
56.6k
    {
914
     // return true;
915
56.6k
    }
916
21.1k
    else
917
21.1k
    if( partitioner.isConsIntra() && !cuECtx.bestTU )
918
0
    {
919
      //return true;
920
0
    }
921
21.1k
    else
922
21.1k
    if ( lumaArea.width == 4 && lumaArea.height == 4 && !slice.isIntra() && !cuECtx.bestTU )
923
0
    {
924
      //return true;
925
0
    }
926
21.1k
    else
927
21.1k
    if (!(slice.isIRAP() || bestMode.type == ETM_INTRA || !cuECtx.bestTU ||
928
0
      ((!m_pcEncCfg->m_bDisableIntraCUsInInterSlices) && (!relatedCU.isInter || !relatedCU.isIBC) && (
929
0
                                    ( cuECtx.bestTU->cbf[0] != 0 ) ||
930
0
           ( ( numComp > COMP_Cb ) && cuECtx.bestTU->cbf[1] != 0 ) ||
931
0
           ( ( numComp > COMP_Cr ) && cuECtx.bestTU->cbf[2] != 0 )  // avoid very complex intra if it is unlikely
932
0
         ) ) ) )
933
0
    {
934
0
      return false;
935
0
    }
936
21.1k
    else
937
21.1k
    if( cuECtx.bestCS && cuECtx.bestCU && cuECtx.interHad )
938
21.1k
    {
939
      // Get SATD threshold from best Inter-CU
940
21.1k
      if( !cs.slice->isIRAP() && m_pcEncCfg->m_usePbIntraFast )
941
0
      {
942
0
        const DFunc dfunc = DF_HAD;
943
0
        DistParam distParam = m_pcRdCost->setDistParam( cs.getOrgBuf( COMP_Y ), cuECtx.bestCS->getPredBuf( COMP_Y ), cs.sps->bitDepths[ CH_L ], dfunc );
944
0
        cuECtx.interHad = distParam.distFunc( distParam );
945
0
      }
946
21.1k
    }
947
77.7k
    if ((m_pcEncCfg->m_IBCFastMethod > 1) && !cs.slice->isIntra()//IBC_FAST_METHOD_NOINTRA_IBCCBF0
948
0
      && (bestMode.type == ETM_IBC || bestMode.type == ETM_IBC_MERGE)
949
0
      && (!cuECtx.bestCU->Y().valid() || cuECtx.bestTU->cbf[0] == 0)
950
0
      && (!cuECtx.bestCU->Cb().valid() || cuECtx.bestTU->cbf[1] == 0)
951
0
      && (!cuECtx.bestCU->Cr().valid() || cuECtx.bestTU->cbf[2] == 0))
952
0
    {
953
0
      return false;
954
0
    }
955
77.7k
    if (m_pcEncCfg->m_FastIntraTools)
956
77.7k
    {
957
77.7k
      if (relatedCU.relatedCuIsValid)
958
12.9k
      {
959
12.9k
        cuECtx.relatedCuIsValid = relatedCU.relatedCuIsValid;
960
12.9k
      }
961
77.7k
      if (relatedCU.isIntra)
962
21.4k
      {
963
21.4k
        cuECtx.isIntra = relatedCU.isIntra;
964
21.4k
      }
965
77.7k
    }
966
77.7k
  }
967
47.4k
  else if( isModeInter( encTestmode ) )
968
0
  {
969
    // INTER MODES (ME + MERGE/SKIP)
970
0
    CHECK( slice.isIntra(), "Inter-mode should not be in the I-Slice mode list!" );
971
972
    // --- Check if we can quit current mode using SAVE/LOAD coding history
973
974
0
    if( encTestmode.type == ETM_INTER_ME )
975
0
    {
976
0
      if( encTestmode.opts == ETO_STANDARD )
977
0
      {
978
0
        if (m_pcEncCfg->m_FastInferMerge)
979
0
        {
980
0
          if (bestCS && (bestCS->slice->TLayer > (m_pcEncCfg->m_maxTLayer - (m_pcEncCfg->m_FastInferMerge & 7)))
981
0
            && (bestCS->bestParent != nullptr) && bestCS->bestParent->cus.size() && (bestCS->bestParent->cus[0]->skip))
982
0
          {
983
0
            return false;
984
0
          }
985
0
        }
986
0
        if( relatedCU.isSkip || relatedCU.isIntra )
987
0
        {
988
0
          return false;
989
0
        }
990
0
      }
991
0
    }
992
0
  }
993
47.4k
  else if (encTestmode.type == ETM_IBC || encTestmode.type == ETM_IBC_MERGE)
994
47.4k
  {
995
47.4k
    if ((m_pcEncCfg->m_IBCFastMethod > 1) && !(slice.isIRAP() || bestMode.type == ETM_INTRA || !cuECtx.bestTU ||
996
0
      ((!m_pcEncCfg->m_bDisableIntraCUsInInterSlices) && (!relatedCU.isInter || !relatedCU.isIBC) && (
997
0
        (cuECtx.bestTU->cbf[0] != 0) ||
998
0
        ((numComp > COMP_Cb) && cuECtx.bestTU->cbf[1] != 0) ||
999
0
        ((numComp > COMP_Cr) && cuECtx.bestTU->cbf[2] != 0)  // avoid very complex intra if it is unlikely
1000
0
        ))))
1001
0
    {
1002
0
      return false;
1003
0
    }
1004
47.4k
    if ((m_pcEncCfg->m_IBCFastMethod > 3) &&(lumaArea.width == 4 && lumaArea.height == 4 && !slice.isIntra()))
1005
0
    {
1006
0
      return false;
1007
0
    }
1008
    // IBC MODES
1009
47.4k
    return slice.sps->IBC && (partitioner.currArea().lumaSize().width < 128 && partitioner.currArea().lumaSize().height < 128);
1010
47.4k
  }
1011
1
  else
1012
1
  {
1013
1
    THROW("problem");
1014
0
    return false;
1015
1
  }
1016
1017
77.7k
  STAT_COUNT_CU_MODES( partitioner.chType == CH_L, g_cuCounters1D[CU_MODES_TRIED][0][!cs.slice->isIntra() + cs.slice->depth] );
1018
77.7k
  STAT_COUNT_CU_MODES( partitioner.chType == CH_L && !cs.slice->isIntra(), g_cuCounters2D[CU_MODES_TRIED][Log2( cs.area.lheight() )][Log2( cs.area.lwidth() )] );
1019
77.7k
  return true;
1020
125k
}
1021
1022
1023
void EncModeCtrl::beforeSplit( Partitioner& partitioner )
1024
77.7k
{
1025
77.7k
  ComprCUCtx&           cuECtx  = m_ComprCUCtxList.back();
1026
1027
77.7k
  if( ! cuECtx.bestCS )
1028
0
    return;
1029
1030
77.7k
  CodedCUInfo    &relatedCU   = getBlkInfo( partitioner.currArea() );
1031
77.7k
  const CodingUnit&  bestCU   = *cuECtx.bestCU;
1032
1033
77.7k
  cuECtx.bestNsPredMode       = cuECtx.bestMode;
1034
77.7k
  cuECtx.bestCostBeforeSplit  = cuECtx.bestCS->cost;
1035
1036
77.7k
  setFromCs( *cuECtx.bestCS, cuECtx.bestMode, partitioner );
1037
1038
77.7k
  if( bestCU.skip )
1039
0
  {
1040
0
    cuECtx.doMoreSplits--;
1041
0
  }
1042
1043
77.7k
  if( partitioner.modeType == MODE_TYPE_INTRA && partitioner.chType == CH_L )
1044
0
  {
1045
0
    return; //not set best coding mode for intra coding pass
1046
0
  }
1047
1048
  // assume the non-split modes are done and set the marks for the best found mode
1049
77.7k
  if( CU::isInter( bestCU ) )
1050
0
  {
1051
0
    relatedCU.isInter     = true;
1052
0
    relatedCU.isSkip     |= bestCU.skip;
1053
0
    relatedCU.isMMVDSkip |= bestCU.mmvdSkip;
1054
0
    relatedCU.BcwIdx      = bestCU.BcwIdx;
1055
0
  }
1056
77.7k
  else if (CU::isIBC(bestCU))
1057
0
  {
1058
0
    relatedCU.isIBC = true;
1059
0
    relatedCU.isSkip |= bestCU.skip;
1060
0
  }
1061
77.7k
  else if( CU::isIntra( bestCU ) )
1062
77.7k
  {
1063
77.7k
    relatedCU.isIntra     = true;
1064
77.7k
    if (m_pcEncCfg->m_FastIntraTools)
1065
77.7k
    {
1066
77.7k
      if ( cuECtx.intraWasTested && (!relatedCU.relatedCuIsValid || cuECtx.bestCS->cost < relatedCU.bestCost))
1067
23.7k
      {
1068
23.7k
        relatedCU.bestCost = cuECtx.bestCS->cost;
1069
23.7k
        relatedCU.relatedCuIsValid = true;
1070
23.7k
      }
1071
77.7k
    }
1072
77.7k
  }
1073
77.7k
  cuECtx.isBestNoSplitSkip = bestCU.skip;
1074
77.7k
}
1075
1076
1077
bool EncModeCtrl::useModeResult( const EncTestMode& encTestmode, CodingStructure*& tempCS, Partitioner& partitioner, const bool useEDO )
1078
162k
{
1079
162k
  ComprCUCtx& cuECtx = m_ComprCUCtxList.back();
1080
1081
1082
162k
  if(      encTestmode.type == ETM_SPLIT_BT_H )
1083
22.7k
  {
1084
22.7k
    cuECtx.bestCostHorzSplit = tempCS->cost;
1085
22.7k
  }
1086
139k
  else if( encTestmode.type == ETM_SPLIT_BT_V )
1087
22.9k
  {
1088
22.9k
    cuECtx.bestCostVertSplit = tempCS->cost;
1089
22.9k
  }
1090
117k
  else if( !isModeSplit( encTestmode ) && isModeInter( encTestmode ) && tempCS->cus.size() == 1 )
1091
0
  {
1092
0
    cuECtx.nonSkipWasTested |= !tempCS->cus.front()->skip;
1093
0
  }
1094
162k
  if (m_pcEncCfg->m_AMVRspeed && encTestmode.type == ETM_INTER_ME)
1095
0
  {
1096
0
    int imvMode = (encTestmode.opts & ETO_IMV) >> ETO_IMV_SHIFT;
1097
1098
0
    if (imvMode == 0)
1099
0
    {
1100
0
      if (tempCS->cost < cuECtx.bestCostNoImv )
1101
0
      {
1102
0
        cuECtx.bestCostNoImv = tempCS->cost;
1103
0
      }
1104
0
    }
1105
0
  }
1106
1107
162k
  if( encTestmode.type == ETM_SPLIT_QT )
1108
17.7k
  {
1109
17.7k
    int maxQtD = 0;
1110
17.7k
    for( const auto& cu : tempCS->cus )
1111
70.9k
    {
1112
70.9k
      maxQtD = std::max<int>( maxQtD, cu->qtDepth );
1113
70.9k
    }
1114
17.7k
    cuECtx.maxQtSubDepth = maxQtD;
1115
17.7k
  }
1116
1117
162k
  int maxMtD = tempCS->pcv->getMaxMTTDepth( *tempCS->slice, partitioner.chType ) + partitioner.currImplicitBtDepth;
1118
1119
162k
  if( encTestmode.type == ETM_SPLIT_BT_H )
1120
22.7k
  {
1121
22.7k
    if( tempCS->cus.size() > 2 )
1122
857
    {
1123
857
      int h_2   = tempCS->area.blocks[partitioner.chType].height / 2;
1124
857
      int cu1_h = tempCS->cus.front()->blocks[partitioner.chType].height;
1125
857
      int cu2_h = tempCS->cus.back() ->blocks[partitioner.chType].height;
1126
1127
857
      cuECtx.doTriHorzSplit = cu1_h < h_2 || cu2_h < h_2 || partitioner.currMtDepth + 1 == maxMtD;
1128
857
    }
1129
22.7k
  }
1130
139k
  else if( encTestmode.type == ETM_SPLIT_BT_V )
1131
22.9k
  {
1132
22.9k
    if( tempCS->cus.size() > 2 )
1133
993
    {
1134
993
      int w_2   = tempCS->area.blocks[partitioner.chType].width / 2;
1135
993
      int cu1_w = tempCS->cus.front()->blocks[partitioner.chType].width;
1136
993
      int cu2_w = tempCS->cus.back() ->blocks[partitioner.chType].width;
1137
1138
993
      cuECtx.doTriVertSplit = cu1_w < w_2 || cu2_w < w_2 || partitioner.currMtDepth + 1 == maxMtD;
1139
993
    }
1140
22.9k
  }
1141
1142
162k
  if( encTestmode.type == ETM_SPLIT_BT_V || encTestmode.type == ETM_SPLIT_BT_H || encTestmode.type == ETM_SPLIT_QT )
1143
63.3k
  {
1144
63.3k
    bool isAllSkip = true;
1145
1146
63.3k
    for( const auto& cu : tempCS->cus )
1147
142k
    {
1148
142k
      isAllSkip &= cu->skip;
1149
142k
    }
1150
1151
63.3k
    if( isAllSkip ) cuECtx.doMoreSplits--;
1152
63.3k
    if( isAllSkip && encTestmode.type == ETM_SPLIT_QT )
1153
0
                    cuECtx.doMoreSplits--;
1154
63.3k
  }
1155
1156
  // for now just a simple decision based on RD-cost or choose tempCS if bestCS is not yet coded
1157
162k
  if( tempCS->cost != MAX_DOUBLE && ( !cuECtx.bestCS || ( ( tempCS->cost + ( useEDO ? tempCS->costDbOffset : 0 ) ) < ( cuECtx.bestCS->cost + ( useEDO ? cuECtx.bestCS->costDbOffset : 0 ) ) ) ) )
1158
146k
  {
1159
146k
    cuECtx.bestCS   = tempCS;
1160
146k
    cuECtx.bestCU   = tempCS->cus[0];
1161
146k
    cuECtx.bestTU   = cuECtx.bestCU->firstTU;
1162
146k
    cuECtx.bestMode = encTestmode;
1163
1164
146k
    return true;
1165
146k
  }
1166
15.7k
  else
1167
15.7k
  {
1168
15.7k
    return false;
1169
15.7k
  }
1170
162k
}
1171
1172
} // namespace vvenc
1173
1174
//! \}
1175