Coverage Report

Created: 2026-06-16 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vvdec/source/Lib/CommonLib/UnitPartitioner.cpp
Line
Count
Source
1
/* -----------------------------------------------------------------------------
2
The copyright in this software is being made available under the Clear BSD
3
License, included below. No patent rights, trademark rights and/or 
4
other Intellectual Property Rights other than the copyrights concerning 
5
the Software are granted under this license.
6
7
The Clear BSD License
8
9
Copyright (c) 2018-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVdeC Authors.
10
All rights reserved.
11
12
Redistribution and use in source and binary forms, with or without modification,
13
are permitted (subject to the limitations in the disclaimer below) provided that
14
the following conditions are met:
15
16
     * Redistributions of source code must retain the above copyright notice,
17
     this list of conditions and the following disclaimer.
18
19
     * Redistributions in binary form must reproduce the above copyright
20
     notice, this list of conditions and the following disclaimer in the
21
     documentation and/or other materials provided with the distribution.
22
23
     * Neither the name of the copyright holder nor the names of its
24
     contributors may be used to endorse or promote products derived from this
25
     software without specific prior written permission.
26
27
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
28
THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
29
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
31
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
32
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
36
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
POSSIBILITY OF SUCH DAMAGE.
39
40
41
------------------------------------------------------------------------------------------- */
42
43
/** \file     UnitPartitioner.h
44
 *  \brief    Provides a class for partitioning management
45
 */
46
47
#include "UnitPartitioner.h"
48
49
#include "CodingStructure.h"
50
#include "Unit.h"
51
#include "Slice.h"
52
#include "UnitTools.h"
53
#include "Picture.h"
54
55
namespace vvdec
56
{
57
58
PartLevel::PartLevel()
59
21.3k
: split               ( CU_DONT_SPLIT )
60
, parts               (               )
61
21.3k
, idx                 ( 0u            )
62
21.3k
, cuAbove             ( nullptr       )
63
21.3k
, cuLeft              ( nullptr       )
64
21.3k
, modeType            ( MODE_TYPE_ALL )
65
21.3k
, qgEnable            ( true          )
66
21.3k
, qgChromaEnable      ( true          )
67
21.3k
{
68
21.3k
}
69
70
void PartLevel::init()
71
112k
{
72
112k
  split           = CU_DONT_SPLIT;
73
112k
  idx             = 0u;
74
112k
  cuAbove         = nullptr;
75
112k
  cuLeft          = nullptr;
76
112k
  modeType        = MODE_TYPE_ALL;
77
112k
  qgEnable        = true;
78
112k
  qgChromaEnable  = true;
79
112k
}
80
81
//////////////////////////////////////////////////////////////////////////
82
// Partitioner class
83
//////////////////////////////////////////////////////////////////////////
84
85
SplitSeries Partitioner::getSplitSeries() const
86
182k
{
87
182k
  SplitSeries splitSeries = 0;
88
182k
  SplitSeries depth = 0;
89
90
182k
  for( const auto &level : m_partStack )
91
660k
  {
92
660k
    if( level.split == CTU_LEVEL ) continue;
93
477k
    else splitSeries += static_cast< SplitSeries >( level.split ) << ( depth * SPLIT_DMULT );
94
95
477k
    depth++;
96
97
477k
    if( depth >= 3 ) break;
98
477k
  }
99
100
182k
  return splitSeries;
101
182k
}
102
103
bool Partitioner::isSepTree( const CodingStructure &cs ) const
104
364k
{
105
364k
  return treeType != TREE_D || isDualITree;
106
364k
}
107
108
void Partitioner::setCUData( CodingUnit& cu )
109
182k
{
110
182k
  cu.depth       = currDepth;
111
182k
  cu.qtDepth     = currQtDepth;
112
182k
  cu.splitSeries = getSplitSeries();
113
182k
}
114
115
static void setNeighborCu( PartLevel& level, Partitioner& p, const CodingStructure& cs )
116
184k
{
117
184k
  const ChannelType chType = p.treeType == TREE_C ? CH_C : p.chType;
118
184k
  const Position   &pos    = p.currArea().blocks[chType].pos();
119
120
  // get above depth
121
184k
  level.cuAbove  = cs.getCURestricted( pos.offset( 0, -1 ), pos, p.currSliceIdx, p.currTileIdx, chType );
122
123
  // get left depth
124
184k
  level.cuLeft   = cs.getCURestricted( pos.offset( -1, 0 ), pos, p.currSliceIdx, p.currTileIdx, chType );
125
184k
}
126
127
128
void Partitioner::initCtu( const UnitArea& ctuArea, const ChannelType _chType, const CodingStructure& cs, const Slice& slice )
129
10.8k
{
130
10.8k
  this->slice = &slice;
131
10.8k
#if _DEBUG
132
10.8k
  m_currArea = ctuArea;
133
10.8k
#endif
134
10.8k
  currDepth   = 0;
135
10.8k
  currTrDepth = 0;
136
10.8k
  currMtDepth = 0;
137
10.8k
  currQtDepth = 0;
138
10.8k
  currSubdiv  = 0;
139
10.8k
  chType      = _chType;
140
10.8k
  currQgPos   = ctuArea.lumaPos();
141
10.8k
  currQgChromaPos = ctuArea.chromaFormat != CHROMA_400 ? ctuArea.chromaPos() : Position();
142
10.8k
  currImplicitBtDepth = 0;
143
144
10.8k
  currSliceIdx = slice.getIndependentSliceIdx();
145
10.8k
  currTileIdx  = cs.pps->getTileIdx( ctuArea.lumaPos() );
146
147
10.8k
  m_partBufIdx = 1;
148
10.8k
  m_partStack.resize_noinit( 1 );
149
10.8k
  m_partStack.back().split = CTU_LEVEL;
150
10.8k
  m_partStack.back().parts = m_partBuf;
151
10.8k
  m_partStack.back().parts[0] = ctuArea;
152
10.8k
  m_partStack.back().numParts = 1;
153
10.8k
  treeType = TREE_D;
154
10.8k
  modeType = MODE_TYPE_ALL;
155
156
10.8k
  setNeighborCu( m_partStack.back(), *this, cs );
157
158
10.8k
  const SPS& sps = *cs.sps;
159
10.8k
#if GDR_ADJ
160
10.8k
  isDualITree = slice.isIntra() && slice.getSPS()->getUseDualITree();
161
10.8k
  const int valIdx = slice.isIntra() ? ( !isDualITree? 0 : ( _chType << 1 ) ) : 1;
162
#else
163
  isDualITree = slice.isIRAP() && slice.getSPS()->getUseDualITree();
164
  const int valIdx = slice.isIRAP() ? ( _chType << 1 ) : 1;
165
#endif
166
167
10.8k
  const unsigned minBtSizeArr[] = { 1u << sps.getLog2MinCodingBlockSize(), 1u << sps.getLog2MinCodingBlockSize(), 1u << sps.getLog2MinCodingBlockSize() };
168
10.8k
  const unsigned minTtSizeArr[] = { 1u << sps.getLog2MinCodingBlockSize(), 1u << sps.getLog2MinCodingBlockSize(), 1u << sps.getLog2MinCodingBlockSize() };
169
170
10.8k
  minBtSize = minBtSizeArr[valIdx];
171
10.8k
  minTtSize = minTtSizeArr[valIdx];
172
173
10.8k
  if( cs.picHeader->getSplitConsOverrideFlag() )
174
0
  {
175
0
    maxBTD    = slice.getPicHeader()->getMaxMTTHierarchyDepth( slice.getSliceType(), _chType );
176
0
    maxBtSize = slice.getPicHeader()->getMaxBTSize( slice.getSliceType(), _chType );
177
0
    maxTtSize = slice.getPicHeader()->getMaxTTSize( slice.getSliceType(), _chType );
178
0
    minQtSize = slice.getPicHeader()->getMinQTSize( slice.getSliceType(), _chType );
179
0
  }
180
10.8k
  else
181
10.8k
  {
182
10.8k
    maxBTD    = sps.getMaxMTTHierarchyDepths()[valIdx];
183
10.8k
    maxBtSize = sps.getMaxBTSizes()[valIdx];
184
10.8k
    maxTtSize = sps.getMaxTTSizes()[valIdx];
185
10.8k
    minQtSize = sps.getMinQTSizes()[valIdx];
186
10.8k
  }
187
188
10.8k
  maxTrSize = cs.sps->getMaxTbSize();
189
10.8k
}
190
191
void Partitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs )
192
112k
{
193
112k
  const bool isImplicit = !cs.picture->Y().contains( currArea().Y().bottomRight() );
194
112k
  const UnitArea& area  = currArea();
195
112k
  bool qgEnable         = currQgEnable();
196
112k
  bool qgChromaEnable   = currQgChromaEnable();
197
198
112k
  PartLevel &last = m_partStack.back();
199
112k
  m_partStack.resize_noinit( m_partStack.size() + 1 );
200
112k
  PartLevel& back = m_partStack.back();
201
112k
  back.init();
202
112k
  back.parts = &m_partBuf[m_partBufIdx];
203
112k
  int numParts;
204
205
112k
  if     ( split <= CU_TRIV_SPLIT )
206
105k
    numParts = PartitionerImpl::getCUSubPartitions     ( area, cs, split, back.parts );
207
6.97k
  else if( split == TU_MAX_TR_SPLIT )
208
0
    numParts = PartitionerImpl::getMaxTuTiling         ( area, cs,        back.parts );
209
6.97k
  else if( split >= SBT_VER_HALF_POS0_SPLIT && split <= SBT_HOR_QUAD_POS1_SPLIT )
210
0
    numParts = PartitionerImpl::getSbtTuTiling         ( area, cs, split, back.parts );
211
6.97k
  else /* if( split == TU_1D_HORZ_SPLIT || split == TU_1D_VERT_SPLIT ) */
212
6.97k
    numParts = PartitionerImpl::getTUIntraSubPartitions( area, cs, isDualITree, split, back.parts, treeType );
213
214
112k
  back.numParts = numParts;
215
112k
  m_partBufIdx += numParts;
216
217
112k
  CHECK( m_partBufIdx > partBufSize, "Partition buffer overflow" );
218
219
112k
  switch( split )
220
112k
  {
221
29.2k
  case CU_QUAD_SPLIT:
222
29.2k
    currTrDepth = 0;
223
29.2k
    CHECKD( currMtDepth > 0, "Cannot split a non-square area other than with a binary split" );
224
29.2k
    currMtDepth = 0;
225
29.2k
    currQtDepth++;
226
29.2k
    currSubdiv ++;
227
29.2k
    break;
228
34.2k
  case CU_HORZ_SPLIT:
229
62.8k
  case CU_VERT_SPLIT:
230
62.8k
    currTrDepth = 0;
231
62.8k
    if( isImplicit ) currImplicitBtDepth++;
232
62.8k
    currMtDepth++;
233
62.8k
    break;
234
7.16k
  case CU_TRIH_SPLIT:
235
13.2k
  case CU_TRIV_SPLIT:
236
13.2k
    currTrDepth = 0;
237
13.2k
    currMtDepth++;
238
13.2k
    currSubdiv ++;
239
13.2k
    break;
240
0
  case TU_MAX_TR_SPLIT:
241
0
  case SBT_VER_HALF_POS0_SPLIT:
242
0
  case SBT_VER_HALF_POS1_SPLIT:
243
0
  case SBT_HOR_HALF_POS0_SPLIT:
244
0
  case SBT_HOR_HALF_POS1_SPLIT:
245
0
  case SBT_VER_QUAD_POS0_SPLIT:
246
0
  case SBT_VER_QUAD_POS1_SPLIT:
247
0
  case SBT_HOR_QUAD_POS0_SPLIT:
248
0
  case SBT_HOR_QUAD_POS1_SPLIT:
249
3.57k
  case TU_1D_HORZ_SPLIT:
250
6.97k
  case TU_1D_VERT_SPLIT:
251
6.97k
    currTrDepth++;
252
6.97k
    break;
253
0
  default:
254
0
    THROW_RECOVERABLE( "Unknown split mode" );
255
0
    break;
256
112k
  }
257
258
112k
  currDepth++;
259
112k
  currSubdiv++;
260
  
261
112k
  qgEnable       &= ( currSubdiv <= slice->getCuQpDeltaSubdiv() );
262
112k
  qgChromaEnable &= ( currSubdiv <= slice->getCuChromaQpOffsetSubdiv() );
263
112k
  if( qgEnable )
264
10.9k
    currQgPos = currArea().lumaPos();
265
112k
  if( qgChromaEnable )
266
0
    currQgChromaPos = currArea().chromaPos();
267
  
268
112k
  back.qgEnable       = qgEnable;
269
112k
  back.qgChromaEnable = qgChromaEnable;
270
112k
  back.split          = split;
271
112k
  back.modeType       = modeType;
272
112k
  back.cuAbove        = last.cuAbove;
273
112k
  back.cuLeft         = last.cuLeft;
274
275
112k
#if _DEBUG
276
277
112k
  m_currArea = m_partStack.back().parts[0];
278
112k
#endif
279
112k
}
280
281
void Partitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv ) const
282
277k
{
283
277k
  canNo = canQt = canBh = canTh = canBv = canTv = true;
284
277k
  bool canBtt = currMtDepth < ( maxBTD + currImplicitBtDepth );
285
286
  // the minimal and maximal sizes are given in luma samples
287
277k
  const CompArea&  area  = currArea().Y();
288
277k
  const CompArea  *areaC = (chType == CHANNEL_TYPE_CHROMA) ? &(currArea().Cb()) : nullptr;
289
277k
  const PartLevel& level = m_partStack.back();
290
291
277k
  if( isDualITree && ( area.width > 64 || area.height > 64 ) )
292
0
  {
293
0
    canQt                                 = true;
294
0
    canNo = canBh = canTh = canBv = canTv = false;
295
296
0
    return;
297
0
  }
298
299
277k
  if( treeType == TREE_C )
300
0
  {
301
0
    canQt = canBh = canTh = canBv = canTv = false;
302
0
    return;
303
0
  }
304
305
277k
  const PartSplit lastSplit   = level.split;
306
277k
  const bool      isTrInPic   = area.x + area.width  <= cs.picture->lwidth();
307
277k
  const bool      isBlInPic   = area.y + area.height <= cs.picture->lheight();
308
277k
  const bool      isImplicit  = !isBlInPic || !isTrInPic;
309
310
  // don't allow QT-splitting below a BT split
311
277k
  if( lastSplit != CTU_LEVEL && lastSplit != CU_QUAD_SPLIT ) canQt = false;
312
  // minQtSize is in luma samples unit
313
277k
  const unsigned minQTThreshold = minQtSize;
314
277k
  if( area.width <= minQTThreshold )                         canQt = false;
315
316
277k
  if( areaC && areaC->width <= MIN_DUALTREE_CHROMA_WIDTH ) canQt = false;
317
277k
  if( isImplicit )
318
233
  {
319
233
    const bool isBtAllowed = area.width <= maxBtSize && area.height <= maxBtSize
320
90
                          && area.width <= MAX_TU_SIZE_FOR_PROFILE && area.height <= MAX_TU_SIZE_FOR_PROFILE
321
90
                          && canBtt;
322
233
    canNo  = canTh = canTv = false;
323
    
324
233
    canQt |= !isBtAllowed;
325
233
    canBh  =  isBtAllowed && !isBlInPic && ( isTrInPic || !canQt );
326
233
    canBv  =  isBtAllowed &&  isBlInPic &&  !isTrInPic;
327
233
    canBv &= ( !areaC || areaC->width > 4 );
328
233
    canQt |= !canBh && !canBv;
329
233
    return;
330
233
  }
331
332
277k
  canBtt &=   area.width >  minBtSize || area.height >  minBtSize   ||   area.width >  minTtSize || area.height >  minTtSize;
333
277k
  canBtt &= ( area.width <= maxBtSize && area.height <= maxBtSize ) || ( area.width <= maxTtSize && area.height <= maxTtSize );
334
335
277k
  if( !canBtt )
336
97.6k
  {
337
97.6k
    canBh = canTh = canBv = canTv = false;
338
97.6k
    return;
339
97.6k
  }
340
341
179k
  const bool allowModeBt = modeType != MODE_TYPE_INTER || area.area() != 32;
342
179k
  const bool allowModeTt = modeType != MODE_TYPE_INTER || area.area() != 64;
343
344
179k
  if( area.width > maxBtSize || area.height > maxBtSize || !allowModeBt )
345
11
  {
346
11
    canBh = canBv = false;
347
11
  }
348
179k
  else
349
179k
  {
350
179k
    if( ( lastSplit == CU_TRIH_SPLIT || lastSplit == CU_TRIV_SPLIT ) && level.idx == 1 )
351
7.01k
    {
352
7.01k
      const PartSplit parlSplit = lastSplit == CU_TRIH_SPLIT ? CU_HORZ_SPLIT : CU_VERT_SPLIT;
353
354
7.01k
      canBh = parlSplit != CU_HORZ_SPLIT;
355
7.01k
      canBv = parlSplit != CU_VERT_SPLIT;
356
7.01k
    }
357
358
    // specific check for BT splits
359
179k
    canBh &= ( area.height > minBtSize && area.height <= maxBtSize );
360
179k
    canBh &= ( area.width <= MAX_TU_SIZE_FOR_PROFILE || area.height > MAX_TU_SIZE_FOR_PROFILE );
361
362
179k
    canBv &= ( area.width > minBtSize && area.width <= maxBtSize );
363
179k
    canBv &= ( area.width > MAX_TU_SIZE_FOR_PROFILE || area.height <= MAX_TU_SIZE_FOR_PROFILE );
364
179k
  }
365
366
179k
  if( area.width > maxTtSize || area.height > maxTtSize || !allowModeTt || !( area.width <= MAX_TU_SIZE_FOR_PROFILE && area.height <= MAX_TU_SIZE_FOR_PROFILE ) )
367
28.0k
  {
368
28.0k
    canTh = canTv = false;
369
370
28.0k
    if( !canBh && !canBv ) return;
371
28.0k
  }
372
151k
  else
373
151k
  {
374
151k
    canTh &= !( area.height <= 2 * minTtSize );
375
151k
    canTv &= !( area.width  <= 2 * minTtSize );
376
151k
  }
377
378
179k
  if( areaC )
379
76.5k
  {
380
76.5k
    canBh &=  ( areaC->width * areaC->height > MIN_DUALTREE_CHROMA_SIZE );
381
76.5k
    canTh &=  ( areaC->width * areaC->height > MIN_DUALTREE_CHROMA_SIZE*2 );
382
76.5k
    canBv &=  ( areaC->width * areaC->height > MIN_DUALTREE_CHROMA_SIZE   && areaC->width > 4 );
383
76.5k
    canTv &=  ( areaC->width * areaC->height > MIN_DUALTREE_CHROMA_SIZE*2 && areaC->width > 8 );
384
76.5k
  }
385
179k
}
386
387
bool Partitioner::canSplit( const PartSplit split, const CodingStructure &cs, bool isISP ) const
388
13.0k
{
389
13.0k
  CHECKD( split < TU_MAX_TR_SPLIT, "This function should only be used for transformation split handling!" );
390
391
13.0k
  if( split == TU_MAX_TR_SPLIT )
392
13.0k
  {
393
13.0k
    const CompArea& area = currArea().Y();
394
395
13.0k
    return area.width > maxTrSize || area.height > maxTrSize;
396
13.0k
  }
397
0
  else
398
0
  {
399
0
    return currTrDepth == 0;
400
0
  }
401
  
402
0
  return false;
403
13.0k
}
404
405
void Partitioner::exitCurrSplit( const CodingStructure& cs )
406
100k
{
407
100k
  const PartSplit currSplit = m_partStack.back().split;
408
100k
  const int       currIndex = m_partStack.back().idx;
409
100k
  const int       numParts  = m_partStack.back().numParts;
410
411
100k
  m_partStack.pop_back();
412
100k
  m_partBufIdx -= numParts;
413
414
100k
  const bool isImplicit     = !cs.picture->Y().contains( currArea().Y().bottomRight() );
415
416
100k
  CHECKD( currDepth == 0, "depth is '0', although a split was performed" );
417
418
100k
  currDepth --;
419
100k
  currSubdiv--;
420
421
100k
  if( currQgEnable() )
422
16.4k
    currQgPos = currArea().lumaPos();
423
100k
  if( currArea().chromaFormat != CHROMA_400 && currQgChromaEnable() )
424
0
    currQgChromaPos = currArea().chromaPos();
425
426
100k
#if _DEBUG
427
100k
  m_currArea = m_partStack.back().parts[m_partStack.back().idx];
428
100k
#endif
429
430
100k
  if( currSplit == CU_HORZ_SPLIT || currSplit == CU_VERT_SPLIT || currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT )
431
75.4k
  {
432
75.4k
    CHECKD( currMtDepth == 0, "MT depth is '0', athough a BT split was performed" );
433
434
75.4k
    currMtDepth--;
435
75.4k
    if( isImplicit ) currImplicitBtDepth--;
436
    
437
75.4k
    if( ( currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT ) && currIndex != 1 )
438
13.0k
    {
439
13.0k
      currSubdiv--;
440
13.0k
    }
441
75.4k
  }
442
24.5k
  else if( currSplit == TU_MAX_TR_SPLIT )
443
0
  {
444
0
    CHECKD( currTrDepth == 0, "TR depth is '0', although a TU split was performed" );
445
446
0
    currTrDepth--;
447
0
  }
448
24.5k
  else if( currSplit >= SBT_VER_HALF_POS0_SPLIT && currSplit <= SBT_HOR_QUAD_POS1_SPLIT )
449
0
  {
450
0
    CHECKD( currTrDepth == 0, "TR depth is '0', although a TU split was performed" );
451
452
0
    currTrDepth--;
453
0
  }
454
24.5k
  else if( currSplit == TU_1D_HORZ_SPLIT || currSplit == TU_1D_VERT_SPLIT )
455
6.91k
  {
456
6.91k
    currTrDepth--;
457
6.91k
  }
458
17.6k
  else
459
17.6k
  {
460
17.6k
    CHECKD( currTrDepth  > 0, "RQT found with QTBT partitioner" );
461
17.6k
    CHECKD( currQtDepth == 0, "QT depth is '0', although a QT split was performed" );
462
463
17.6k
    currQtDepth--;
464
17.6k
    currSubdiv --;
465
17.6k
  }
466
100k
}
467
468
bool Partitioner::nextPart( const CodingStructure &cs, bool autoPop /*= false*/ )
469
298k
{
470
298k
        PartLevel& back   =   m_partStack.back();
471
298k
  const unsigned currIdx  = ++back.idx;
472
298k
  const PartSplit currSpl =   back.split;
473
474
298k
  if( currIdx < back.numParts )
475
193k
  {
476
193k
#if _DEBUG
477
193k
    m_currArea = back.parts[currIdx];
478
193k
#endif
479
193k
    if( currSpl <= CU_TRIV_SPLIT )
480
173k
      setNeighborCu( back, *this, cs );
481
    
482
193k
    if( currSpl == CU_TRIH_SPLIT || currSpl == CU_TRIV_SPLIT )
483
26.3k
    {
484
26.3k
      if( currIdx == 1 ) currSubdiv--;
485
13.1k
      else               currSubdiv++;
486
26.3k
    }
487
488
193k
    if( currQgEnable() )
489
30.3k
      currQgPos = currArea().lumaPos();
490
193k
    if( currQgChromaEnable() )
491
0
      currQgChromaPos = currArea().chromaPos();
492
493
193k
    return true;
494
193k
  }
495
104k
  else
496
104k
  {
497
104k
    if( autoPop ) exitCurrSplit( cs );
498
104k
    return false;
499
104k
  }
500
298k
}
501
502
void Partitioner::updateNeighbors( const CodingStructure& cs )
503
0
{
504
0
  setNeighborCu( m_partStack.back(), *this, cs );
505
0
}
506
507
bool Partitioner::hasNextPart() const
508
0
{
509
0
  return ( ( m_partStack.back().idx + 1 ) < m_partStack.back().numParts );
510
0
}
511
512
//////////////////////////////////////////////////////////////////////////
513
// Partitioner methods describing the actual partitioning logic
514
//////////////////////////////////////////////////////////////////////////
515
516
int PartitionerImpl::getCUSubPartitions( const UnitArea &cuArea, const CodingStructure &cs, const PartSplit _splitType, Partitioning& dst )
517
105k
{
518
105k
  const PartSplit splitType = _splitType;
519
520
105k
  if( splitType == CU_QUAD_SPLIT )
521
29.2k
  {
522
29.2k
    Partitioning& sub = dst;
523
524
146k
    for( uint32_t i = 0; i < 4; i++ )
525
117k
    {
526
117k
      sub[i] = cuArea;
527
528
117k
      for( auto &blk : sub[i].blocks )
529
351k
      {
530
351k
        blk.height >>= 1;
531
351k
        blk.width  >>= 1;
532
351k
        if( i >= 2 ) blk.y += blk.height;
533
351k
        if( i &  1 ) blk.x += blk.width;
534
351k
      }
535
536
117k
      CHECK( sub[i].lumaSize().height < MIN_TU_SIZE, "the split causes the block to be smaller than the minimal TU size" );
537
117k
    }
538
539
29.2k
    return 4;
540
29.2k
  }
541
76.1k
  else if( splitType == CU_HORZ_SPLIT )
542
34.2k
  {
543
34.2k
    Partitioning& sub = dst;
544
545
102k
    for (uint32_t i = 0; i < 2; i++)
546
68.4k
    {
547
68.4k
      sub[i] = cuArea;
548
549
68.4k
      for (auto &blk : sub[i].blocks)
550
205k
      {
551
205k
        blk.height >>= 1;
552
205k
        if (i == 1) blk.y += blk.height;
553
205k
      }
554
555
68.4k
      CHECK(sub[i].lumaSize().height < MIN_TU_SIZE, "the cs split causes the block to be smaller than the minimal TU size");
556
68.4k
    }
557
558
34.2k
    return 2;
559
34.2k
  }
560
41.9k
  else if( splitType == CU_VERT_SPLIT )
561
28.6k
  {
562
28.6k
    Partitioning& sub = dst;
563
564
86.0k
    for( uint32_t i = 0; i < 2; i++ )
565
57.3k
    {
566
57.3k
      sub[i] = cuArea;
567
568
57.3k
      for( auto &blk : sub[i].blocks )
569
172k
      {
570
172k
        blk.width >>= 1;
571
172k
        if( i == 1 ) blk.x += blk.width;
572
172k
      }
573
574
57.3k
      CHECK( sub[i].lumaSize().width < MIN_TU_SIZE, "the split causes the block to be smaller than the minimal TU size" );
575
57.3k
    }
576
577
28.6k
    return 2;
578
28.6k
  }
579
13.2k
  else if( splitType == CU_TRIH_SPLIT )
580
7.16k
  {
581
7.16k
    Partitioning& sub = dst;
582
583
28.6k
    for( int i = 0; i < 3; i++ )
584
21.4k
    {
585
21.4k
      sub[i] = cuArea;
586
587
21.4k
      for( auto &blk : sub[i].blocks )
588
64.4k
      {
589
64.4k
        blk.height >>= 1;
590
64.4k
        if( ( i + 1 ) & 1 ) blk.height >>= 1;
591
64.4k
        if( i == 1 )        blk.y       +=     blk.height / 2;
592
64.4k
        if( i == 2 )        blk.y       += 3 * blk.height;
593
64.4k
      }
594
595
21.4k
      CHECK( sub[i].lumaSize().height < MIN_TU_SIZE, "the cs split causes the block to be smaller than the minimal TU size" );
596
21.4k
    }
597
598
7.16k
    return 3;
599
7.16k
  }
600
6.07k
  else if( splitType == CU_TRIV_SPLIT )
601
6.07k
  {
602
6.07k
    Partitioning& sub = dst;
603
604
24.2k
    for( int i = 0; i < 3; i++ )
605
18.2k
    {
606
18.2k
      sub[i] = cuArea;
607
608
18.2k
      for( auto &blk : sub[i].blocks )
609
54.6k
      {
610
54.6k
        blk.width >>= 1;
611
612
54.6k
        if( ( i + 1 ) & 1 ) blk.width >>= 1;
613
54.6k
        if( i == 1 )        blk.x      +=     blk.width / 2;
614
54.6k
        if( i == 2 )        blk.x      += 3 * blk.width;
615
54.6k
      }
616
617
18.2k
      CHECK( sub[i].lumaSize().width < MIN_TU_SIZE, "the cs split causes the block to be smaller than the minimal TU size" );
618
18.2k
    }
619
620
6.07k
    return 3;
621
6.07k
  }
622
0
  else
623
0
  {
624
0
    THROW_RECOVERABLE( "Unknown CU sub-partitioning" );
625
0
  }
626
105k
}
627
628
int PartitionerImpl::getTUIntraSubPartitions( const UnitArea &tuArea, const CodingStructure &cs, const bool isDualTree, const PartSplit splitType, Partitioning &sub, const TreeType treeType )
629
6.97k
{
630
6.97k
  uint32_t nPartitions;
631
6.97k
  uint32_t splitDimensionSize = CU::getISPSplitDim( tuArea.lumaSize().width, tuArea.lumaSize().height, splitType );
632
633
6.97k
  if( splitType == TU_1D_HORZ_SPLIT )
634
3.57k
  {
635
3.57k
    nPartitions = tuArea.lumaSize().height >> getLog2(splitDimensionSize);
636
637
17.5k
    for( uint32_t i = 0; i < nPartitions; i++ )
638
13.9k
    {
639
13.9k
      sub[i] = tuArea;
640
13.9k
      CompArea& blkY = sub[i].blocks[COMPONENT_Y];
641
642
13.9k
      blkY.height = splitDimensionSize;
643
13.9k
      blkY.y = i > 0 ? sub[i - 1].blocks[COMPONENT_Y].y + splitDimensionSize : blkY.y;
644
645
13.9k
      CHECK( sub[i].lumaSize().height < 1, "the cs split causes the block to be smaller than the minimal TU size" );
646
13.9k
    }
647
3.57k
  }
648
3.40k
  else if( splitType == TU_1D_VERT_SPLIT )
649
3.40k
  {
650
3.40k
    nPartitions = tuArea.lumaSize().width >> getLog2(splitDimensionSize);
651
652
16.6k
    for( uint32_t i = 0; i < nPartitions; i++ )
653
13.2k
    {
654
13.2k
      sub[i] = tuArea;
655
13.2k
      CompArea& blkY = sub[i].blocks[COMPONENT_Y];
656
657
13.2k
      blkY.width = splitDimensionSize;
658
13.2k
      blkY.x = i > 0 ? sub[i - 1].blocks[COMPONENT_Y].x + splitDimensionSize : blkY.x;
659
13.2k
      CHECK( sub[i].lumaSize().width < 1, "the split causes the block to be smaller than the minimal TU size" );
660
13.2k
    }
661
3.40k
  }
662
0
  else
663
0
  {
664
0
    THROW_RECOVERABLE( "Unknown TU sub-partitioning" );
665
0
  }
666
  //we only partition luma, so there is going to be only one chroma tu at the end (unless it is dual tree, in which case there won't be any chroma components)
667
6.97k
  uint32_t partitionsWithoutChroma = (cs.area.chromaFormat == CHROMA_400) ? 0 : (isDualTree ? nPartitions : nPartitions - 1);
668
34.2k
  for( uint32_t i = 0; i < partitionsWithoutChroma; i++ )
669
27.2k
  {
670
27.2k
    CompArea& blkCb = sub[i].blocks[COMPONENT_Cb];
671
27.2k
    CompArea& blkCr = sub[i].blocks[COMPONENT_Cr];
672
27.2k
    blkCb = CompArea();
673
27.2k
    blkCr = CompArea();
674
27.2k
  }
675
676
6.97k
  return nPartitions;
677
6.97k
}
678
679
680
static const int g_rsScanToZ_w4[16] =
681
{
682
   0,  1,  4,  5, // wouldn't work for 128x32 blocks, but those are forbidden bcs of VPDU constraints
683
   2,  3,  6,  7, // correct ordering for 128x64 (TU32)
684
   8,  9, 12, 13,
685
  10, 11, 14, 15, // correct ordering for 128x128 (TU32)
686
};
687
688
static const int g_rsScanToZ_w2[8] =
689
{
690
   0,  1, // correct ordering for 64x32 (TU32) and 128x64 (TU64)
691
   2,  3, // correct ordering for 64x64 (TU32) and 128x128 (TU64)
692
   4,  5,
693
   6,  7, // correct ordering for 32x64 (TU32) and 64x128 (TU64)
694
};
695
696
static const int g_rsScanToZ_w1[4] =
697
{
698
   0, // no tiling, never used
699
   1, // correct ordering for 64x32 (TU32) and 128x64 (TU64)
700
   2,
701
   3, // correct ordering for 128x32 (TU32)
702
};
703
704
static const int* g_rsScanToZ[3] = { g_rsScanToZ_w1, g_rsScanToZ_w2, g_rsScanToZ_w4 };
705
706
int PartitionerImpl::getMaxTuTiling( const UnitArea &cuArea, const CodingStructure &cs, Partitioning& dst )
707
0
{
708
0
  const Size area     = cuArea.lumaSize();
709
0
  const int maxTrSize = cs.sps->getMaxTbSize();
710
0
  const int numTilesH = std::max<int>( 1, area.width  / maxTrSize );
711
0
  const int numTilesV = std::max<int>( 1, area.height / maxTrSize );
712
0
  const int numTiles  = numTilesH * numTilesV;
713
0
  const int numLog2H  = getLog2( numTilesH );
714
0
  const int* rsScanToZ = g_rsScanToZ[numLog2H];
715
716
0
  CHECK( numTiles > MAX_CU_TILING_PARTITIONS, "CU partitioning requires more partitions than available" );
717
718
0
  Partitioning& ret = dst;
719
720
0
  for( int i = 0; i < numTiles; i++ )
721
0
  {
722
0
    ret[i] = cuArea;
723
724
0
    const int zid = rsScanToZ[i];
725
726
0
    const int y = zid >>         numLog2H;
727
0
    const int x = zid & ( ( 1 << numLog2H) - 1 );
728
729
0
    UnitArea& tile = ret[i];
730
731
0
    for( CompArea &comp : tile.blocks )
732
0
    {
733
0
      if( !comp.valid() ) continue;
734
735
0
      comp.width  /= numTilesH;
736
0
      comp.height /= numTilesV;
737
738
0
      comp.x += comp.width  * x;
739
0
      comp.y += comp.height * y;
740
0
    }
741
0
  }
742
743
0
  return numTiles;
744
0
}
745
746
int PartitionerImpl::getSbtTuTiling( const UnitArea& cuArea, const CodingStructure &cs, const PartSplit splitType, Partitioning& dst )
747
0
{
748
0
  Partitioning& ret = dst;
749
0
  int numTiles      = 2;
750
0
  int widthFactor, heightFactor, xOffsetFactor, yOffsetFactor;
751
752
0
  CHECK( !(splitType >= SBT_VER_HALF_POS0_SPLIT && splitType <= SBT_HOR_QUAD_POS1_SPLIT), "wrong" );
753
754
0
  for( int i = 0; i < numTiles; i++ )
755
0
  {
756
0
    ret[i] = cuArea;
757
758
0
    if( splitType >= SBT_VER_QUAD_POS0_SPLIT )
759
0
    {
760
0
      if( splitType == SBT_HOR_QUAD_POS0_SPLIT || splitType == SBT_HOR_QUAD_POS1_SPLIT )
761
0
      {
762
0
        widthFactor   = 4;
763
0
        xOffsetFactor = 0;
764
0
        heightFactor  = ( ( i == 0 &&        splitType == SBT_HOR_QUAD_POS0_SPLIT ) || ( i == 1 && splitType == SBT_HOR_QUAD_POS1_SPLIT ) ) ? 1 : 3;
765
0
        yOffsetFactor =   ( i == 0 ) ? 0 : ( splitType == SBT_HOR_QUAD_POS0_SPLIT ? 1 : 3 );
766
0
      }
767
0
      else
768
0
      {
769
0
        widthFactor   = ( ( i == 0 &&        splitType == SBT_VER_QUAD_POS0_SPLIT ) || ( i == 1 && splitType == SBT_VER_QUAD_POS1_SPLIT ) ) ? 1 : 3;
770
0
        xOffsetFactor =   ( i == 0 ) ? 0 : ( splitType == SBT_VER_QUAD_POS0_SPLIT ? 1 : 3 );
771
0
        heightFactor  = 4;
772
0
        yOffsetFactor = 0;
773
0
      }
774
0
    }
775
0
    else
776
0
    {
777
0
      if( splitType == SBT_HOR_HALF_POS0_SPLIT || splitType == SBT_HOR_HALF_POS1_SPLIT )
778
0
      {
779
0
        widthFactor   = 4;
780
0
        xOffsetFactor = 0;
781
0
        heightFactor  = 2;
782
0
        yOffsetFactor = ( i == 0 ) ? 0 : 2;
783
0
      }
784
0
      else
785
0
      {
786
0
        widthFactor   = 2;
787
0
        xOffsetFactor = ( i == 0 ) ? 0 : 2;
788
0
        heightFactor  = 4;
789
0
        yOffsetFactor = 0;
790
0
      }
791
0
    }
792
793
0
    UnitArea& tile = ret[i];
794
795
0
    for( CompArea &comp : tile.blocks )
796
0
    {
797
0
      if( !comp.valid() ) continue;
798
799
0
      comp.x     += ( comp.width  * xOffsetFactor ) >> 2;
800
0
      comp.y     += ( comp.height * yOffsetFactor ) >> 2;
801
0
      comp.width  = ( comp.width  * widthFactor   ) >> 2;
802
0
      comp.height = ( comp.height * heightFactor  ) >> 2;
803
0
    }
804
0
  }
805
806
0
  return numTiles;
807
0
}
808
809
}