Coverage Report

Created: 2026-04-01 07:49

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
0
: split               ( CU_DONT_SPLIT )
60
, parts               (               )
61
0
, idx                 ( 0u            )
62
0
, cuAbove             ( nullptr       )
63
0
, cuLeft              ( nullptr       )
64
0
, modeType            ( MODE_TYPE_ALL )
65
0
, qgEnable            ( true          )
66
0
, qgChromaEnable      ( true          )
67
0
{
68
0
}
69
70
void PartLevel::init()
71
0
{
72
0
  split           = CU_DONT_SPLIT;
73
0
  idx             = 0u;
74
0
  cuAbove         = nullptr;
75
0
  cuLeft          = nullptr;
76
0
  modeType        = MODE_TYPE_ALL;
77
0
  qgEnable        = true;
78
0
  qgChromaEnable  = true;
79
0
}
80
81
//////////////////////////////////////////////////////////////////////////
82
// Partitioner class
83
//////////////////////////////////////////////////////////////////////////
84
85
SplitSeries Partitioner::getSplitSeries() const
86
0
{
87
0
  SplitSeries splitSeries = 0;
88
0
  SplitSeries depth = 0;
89
90
0
  for( const auto &level : m_partStack )
91
0
  {
92
0
    if( level.split == CTU_LEVEL ) continue;
93
0
    else splitSeries += static_cast< SplitSeries >( level.split ) << ( depth * SPLIT_DMULT );
94
95
0
    depth++;
96
97
0
    if( depth >= 3 ) break;
98
0
  }
99
100
0
  return splitSeries;
101
0
}
102
103
bool Partitioner::isSepTree( const CodingStructure &cs ) const
104
0
{
105
0
  return treeType != TREE_D || isDualITree;
106
0
}
107
108
void Partitioner::setCUData( CodingUnit& cu )
109
0
{
110
0
  cu.depth       = currDepth;
111
0
  cu.qtDepth     = currQtDepth;
112
0
  cu.splitSeries = getSplitSeries();
113
0
}
114
115
static void setNeighborCu( PartLevel& level, Partitioner& p, const CodingStructure& cs )
116
0
{
117
0
  const ChannelType chType = p.treeType == TREE_C ? CH_C : p.chType;
118
0
  const Position   &pos    = p.currArea().blocks[chType].pos();
119
120
  // get above depth
121
0
  level.cuAbove  = cs.getCURestricted( pos.offset( 0, -1 ), pos, p.currSliceIdx, p.currTileIdx, chType );
122
123
  // get left depth
124
0
  level.cuLeft   = cs.getCURestricted( pos.offset( -1, 0 ), pos, p.currSliceIdx, p.currTileIdx, chType );
125
0
}
126
127
128
void Partitioner::initCtu( const UnitArea& ctuArea, const ChannelType _chType, const CodingStructure& cs, const Slice& slice )
129
0
{
130
0
  this->slice = &slice;
131
0
#if _DEBUG
132
0
  m_currArea = ctuArea;
133
0
#endif
134
0
  currDepth   = 0;
135
0
  currTrDepth = 0;
136
0
  currMtDepth = 0;
137
0
  currQtDepth = 0;
138
0
  currSubdiv  = 0;
139
0
  chType      = _chType;
140
0
  currQgPos   = ctuArea.lumaPos();
141
0
  currQgChromaPos = ctuArea.chromaFormat != CHROMA_400 ? ctuArea.chromaPos() : Position();
142
0
  currImplicitBtDepth = 0;
143
144
0
  currSliceIdx = slice.getIndependentSliceIdx();
145
0
  currTileIdx  = cs.pps->getTileIdx( ctuArea.lumaPos() );
146
147
0
  m_partBufIdx = 1;
148
0
  m_partStack.resize_noinit( 1 );
149
0
  m_partStack.back().split = CTU_LEVEL;
150
0
  m_partStack.back().parts = m_partBuf;
151
0
  m_partStack.back().parts[0] = ctuArea;
152
0
  m_partStack.back().numParts = 1;
153
0
  treeType = TREE_D;
154
0
  modeType = MODE_TYPE_ALL;
155
156
0
  setNeighborCu( m_partStack.back(), *this, cs );
157
158
0
  const SPS& sps = *cs.sps;
159
0
#if GDR_ADJ
160
0
  isDualITree = slice.isIntra() && slice.getSPS()->getUseDualITree();
161
0
  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
0
  const unsigned minBtSizeArr[] = { 1u << sps.getLog2MinCodingBlockSize(), 1u << sps.getLog2MinCodingBlockSize(), 1u << sps.getLog2MinCodingBlockSize() };
168
0
  const unsigned minTtSizeArr[] = { 1u << sps.getLog2MinCodingBlockSize(), 1u << sps.getLog2MinCodingBlockSize(), 1u << sps.getLog2MinCodingBlockSize() };
169
170
0
  minBtSize = minBtSizeArr[valIdx];
171
0
  minTtSize = minTtSizeArr[valIdx];
172
173
0
  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
0
  else
181
0
  {
182
0
    maxBTD    = sps.getMaxMTTHierarchyDepths()[valIdx];
183
0
    maxBtSize = sps.getMaxBTSizes()[valIdx];
184
0
    maxTtSize = sps.getMaxTTSizes()[valIdx];
185
0
    minQtSize = sps.getMinQTSizes()[valIdx];
186
0
  }
187
188
0
  maxTrSize = cs.sps->getMaxTbSize();
189
0
}
190
191
void Partitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs )
192
0
{
193
0
  const bool isImplicit = !cs.picture->Y().contains( currArea().Y().bottomRight() );
194
0
  const UnitArea& area  = currArea();
195
0
  bool qgEnable         = currQgEnable();
196
0
  bool qgChromaEnable   = currQgChromaEnable();
197
198
0
  PartLevel &last = m_partStack.back();
199
0
  m_partStack.resize_noinit( m_partStack.size() + 1 );
200
0
  PartLevel& back = m_partStack.back();
201
0
  back.init();
202
0
  back.parts = &m_partBuf[m_partBufIdx];
203
0
  int numParts;
204
205
0
  if     ( split <= CU_TRIV_SPLIT )
206
0
    numParts = PartitionerImpl::getCUSubPartitions     ( area, cs, split, back.parts );
207
0
  else if( split == TU_MAX_TR_SPLIT )
208
0
    numParts = PartitionerImpl::getMaxTuTiling         ( area, cs,        back.parts );
209
0
  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
0
  else /* if( split == TU_1D_HORZ_SPLIT || split == TU_1D_VERT_SPLIT ) */
212
0
    numParts = PartitionerImpl::getTUIntraSubPartitions( area, cs, isDualITree, split, back.parts, treeType );
213
214
0
  back.numParts = numParts;
215
0
  m_partBufIdx += numParts;
216
217
0
  CHECK( m_partBufIdx > partBufSize, "Partition buffer overflow" );
218
219
0
  switch( split )
220
0
  {
221
0
  case CU_QUAD_SPLIT:
222
0
    currTrDepth = 0;
223
0
    CHECKD( currMtDepth > 0, "Cannot split a non-square area other than with a binary split" );
224
0
    currMtDepth = 0;
225
0
    currQtDepth++;
226
0
    currSubdiv ++;
227
0
    break;
228
0
  case CU_HORZ_SPLIT:
229
0
  case CU_VERT_SPLIT:
230
0
    currTrDepth = 0;
231
0
    if( isImplicit ) currImplicitBtDepth++;
232
0
    currMtDepth++;
233
0
    break;
234
0
  case CU_TRIH_SPLIT:
235
0
  case CU_TRIV_SPLIT:
236
0
    currTrDepth = 0;
237
0
    currMtDepth++;
238
0
    currSubdiv ++;
239
0
    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
0
  case TU_1D_HORZ_SPLIT:
250
0
  case TU_1D_VERT_SPLIT:
251
0
    currTrDepth++;
252
0
    break;
253
0
  default:
254
0
    THROW_RECOVERABLE( "Unknown split mode" );
255
0
    break;
256
0
  }
257
258
0
  currDepth++;
259
0
  currSubdiv++;
260
  
261
0
  qgEnable       &= ( currSubdiv <= slice->getCuQpDeltaSubdiv() );
262
0
  qgChromaEnable &= ( currSubdiv <= slice->getCuChromaQpOffsetSubdiv() );
263
0
  if( qgEnable )
264
0
    currQgPos = currArea().lumaPos();
265
0
  if( qgChromaEnable )
266
0
    currQgChromaPos = currArea().chromaPos();
267
  
268
0
  back.qgEnable       = qgEnable;
269
0
  back.qgChromaEnable = qgChromaEnable;
270
0
  back.split          = split;
271
0
  back.modeType       = modeType;
272
0
  back.cuAbove        = last.cuAbove;
273
0
  back.cuLeft         = last.cuLeft;
274
275
0
#if _DEBUG
276
277
0
  m_currArea = m_partStack.back().parts[0];
278
0
#endif
279
0
}
280
281
void Partitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv ) const
282
0
{
283
0
  canNo = canQt = canBh = canTh = canBv = canTv = true;
284
0
  bool canBtt = currMtDepth < ( maxBTD + currImplicitBtDepth );
285
286
  // the minimal and maximal sizes are given in luma samples
287
0
  const CompArea&  area  = currArea().Y();
288
0
  const CompArea  *areaC = (chType == CHANNEL_TYPE_CHROMA) ? &(currArea().Cb()) : nullptr;
289
0
  const PartLevel& level = m_partStack.back();
290
291
0
  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
0
  if( treeType == TREE_C )
300
0
  {
301
0
    canQt = canBh = canTh = canBv = canTv = false;
302
0
    return;
303
0
  }
304
305
0
  const PartSplit lastSplit   = level.split;
306
0
  const bool      isTrInPic   = area.x + area.width  <= cs.picture->lwidth();
307
0
  const bool      isBlInPic   = area.y + area.height <= cs.picture->lheight();
308
0
  const bool      isImplicit  = !isBlInPic || !isTrInPic;
309
310
  // don't allow QT-splitting below a BT split
311
0
  if( lastSplit != CTU_LEVEL && lastSplit != CU_QUAD_SPLIT ) canQt = false;
312
  // minQtSize is in luma samples unit
313
0
  const unsigned minQTThreshold = minQtSize;
314
0
  if( area.width <= minQTThreshold )                         canQt = false;
315
316
0
  if( areaC && areaC->width <= MIN_DUALTREE_CHROMA_WIDTH ) canQt = false;
317
0
  if( isImplicit )
318
0
  {
319
0
    const bool isBtAllowed = area.width <= maxBtSize && area.height <= maxBtSize
320
0
                          && area.width <= MAX_TU_SIZE_FOR_PROFILE && area.height <= MAX_TU_SIZE_FOR_PROFILE
321
0
                          && canBtt;
322
0
    canNo  = canTh = canTv = false;
323
    
324
0
    canQt |= !isBtAllowed;
325
0
    canBh  =  isBtAllowed && !isBlInPic && ( isTrInPic || !canQt );
326
0
    canBv  =  isBtAllowed &&  isBlInPic &&  !isTrInPic;
327
0
    canBv &= ( !areaC || areaC->width > 4 );
328
0
    canQt |= !canBh && !canBv;
329
0
    return;
330
0
  }
331
332
0
  canBtt &=   area.width >  minBtSize || area.height >  minBtSize   ||   area.width >  minTtSize || area.height >  minTtSize;
333
0
  canBtt &= ( area.width <= maxBtSize && area.height <= maxBtSize ) || ( area.width <= maxTtSize && area.height <= maxTtSize );
334
335
0
  if( !canBtt )
336
0
  {
337
0
    canBh = canTh = canBv = canTv = false;
338
0
    return;
339
0
  }
340
341
0
  const bool allowModeBt = modeType != MODE_TYPE_INTER || area.area() != 32;
342
0
  const bool allowModeTt = modeType != MODE_TYPE_INTER || area.area() != 64;
343
344
0
  if( area.width > maxBtSize || area.height > maxBtSize || !allowModeBt )
345
0
  {
346
0
    canBh = canBv = false;
347
0
  }
348
0
  else
349
0
  {
350
0
    if( ( lastSplit == CU_TRIH_SPLIT || lastSplit == CU_TRIV_SPLIT ) && level.idx == 1 )
351
0
    {
352
0
      const PartSplit parlSplit = lastSplit == CU_TRIH_SPLIT ? CU_HORZ_SPLIT : CU_VERT_SPLIT;
353
354
0
      canBh = parlSplit != CU_HORZ_SPLIT;
355
0
      canBv = parlSplit != CU_VERT_SPLIT;
356
0
    }
357
358
    // specific check for BT splits
359
0
    canBh &= ( area.height > minBtSize && area.height <= maxBtSize );
360
0
    canBh &= ( area.width <= MAX_TU_SIZE_FOR_PROFILE || area.height > MAX_TU_SIZE_FOR_PROFILE );
361
362
0
    canBv &= ( area.width > minBtSize && area.width <= maxBtSize );
363
0
    canBv &= ( area.width > MAX_TU_SIZE_FOR_PROFILE || area.height <= MAX_TU_SIZE_FOR_PROFILE );
364
0
  }
365
366
0
  if( area.width > maxTtSize || area.height > maxTtSize || !allowModeTt || !( area.width <= MAX_TU_SIZE_FOR_PROFILE && area.height <= MAX_TU_SIZE_FOR_PROFILE ) )
367
0
  {
368
0
    canTh = canTv = false;
369
370
0
    if( !canBh && !canBv ) return;
371
0
  }
372
0
  else
373
0
  {
374
0
    canTh &= !( area.height <= 2 * minTtSize );
375
0
    canTv &= !( area.width  <= 2 * minTtSize );
376
0
  }
377
378
0
  if( areaC )
379
0
  {
380
0
    canBh &=  ( areaC->width * areaC->height > MIN_DUALTREE_CHROMA_SIZE );
381
0
    canTh &=  ( areaC->width * areaC->height > MIN_DUALTREE_CHROMA_SIZE*2 );
382
0
    canBv &=  ( areaC->width * areaC->height > MIN_DUALTREE_CHROMA_SIZE   && areaC->width > 4 );
383
0
    canTv &=  ( areaC->width * areaC->height > MIN_DUALTREE_CHROMA_SIZE*2 && areaC->width > 8 );
384
0
  }
385
0
}
386
387
bool Partitioner::canSplit( const PartSplit split, const CodingStructure &cs, bool isISP ) const
388
0
{
389
0
  CHECKD( split < TU_MAX_TR_SPLIT, "This function should only be used for transformation split handling!" );
390
391
0
  if( split == TU_MAX_TR_SPLIT )
392
0
  {
393
0
    const CompArea& area = currArea().Y();
394
395
0
    return area.width > maxTrSize || area.height > maxTrSize;
396
0
  }
397
0
  else
398
0
  {
399
0
    return currTrDepth == 0;
400
0
  }
401
  
402
0
  return false;
403
0
}
404
405
void Partitioner::exitCurrSplit( const CodingStructure& cs )
406
0
{
407
0
  const PartSplit currSplit = m_partStack.back().split;
408
0
  const int       currIndex = m_partStack.back().idx;
409
0
  const int       numParts  = m_partStack.back().numParts;
410
411
0
  m_partStack.pop_back();
412
0
  m_partBufIdx -= numParts;
413
414
0
  const bool isImplicit     = !cs.picture->Y().contains( currArea().Y().bottomRight() );
415
416
0
  CHECKD( currDepth == 0, "depth is '0', although a split was performed" );
417
418
0
  currDepth --;
419
0
  currSubdiv--;
420
421
0
  if( currQgEnable() )
422
0
    currQgPos = currArea().lumaPos();
423
0
  if( currArea().chromaFormat != CHROMA_400 && currQgChromaEnable() )
424
0
    currQgChromaPos = currArea().chromaPos();
425
426
0
#if _DEBUG
427
0
  m_currArea = m_partStack.back().parts[m_partStack.back().idx];
428
0
#endif
429
430
0
  if( currSplit == CU_HORZ_SPLIT || currSplit == CU_VERT_SPLIT || currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT )
431
0
  {
432
0
    CHECKD( currMtDepth == 0, "MT depth is '0', athough a BT split was performed" );
433
434
0
    currMtDepth--;
435
0
    if( isImplicit ) currImplicitBtDepth--;
436
    
437
0
    if( ( currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT ) && currIndex != 1 )
438
0
    {
439
0
      currSubdiv--;
440
0
    }
441
0
  }
442
0
  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
0
  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
0
  else if( currSplit == TU_1D_HORZ_SPLIT || currSplit == TU_1D_VERT_SPLIT )
455
0
  {
456
0
    currTrDepth--;
457
0
  }
458
0
  else
459
0
  {
460
0
    CHECKD( currTrDepth  > 0, "RQT found with QTBT partitioner" );
461
0
    CHECKD( currQtDepth == 0, "QT depth is '0', although a QT split was performed" );
462
463
0
    currQtDepth--;
464
0
    currSubdiv --;
465
0
  }
466
0
}
467
468
bool Partitioner::nextPart( const CodingStructure &cs, bool autoPop /*= false*/ )
469
0
{
470
0
        PartLevel& back   =   m_partStack.back();
471
0
  const unsigned currIdx  = ++back.idx;
472
0
  const PartSplit currSpl =   back.split;
473
474
0
  if( currIdx < back.numParts )
475
0
  {
476
0
#if _DEBUG
477
0
    m_currArea = back.parts[currIdx];
478
0
#endif
479
0
    if( currSpl <= CU_TRIV_SPLIT )
480
0
      setNeighborCu( back, *this, cs );
481
    
482
0
    if( currSpl == CU_TRIH_SPLIT || currSpl == CU_TRIV_SPLIT )
483
0
    {
484
0
      if( currIdx == 1 ) currSubdiv--;
485
0
      else               currSubdiv++;
486
0
    }
487
488
0
    if( currQgEnable() )
489
0
      currQgPos = currArea().lumaPos();
490
0
    if( currQgChromaEnable() )
491
0
      currQgChromaPos = currArea().chromaPos();
492
493
0
    return true;
494
0
  }
495
0
  else
496
0
  {
497
0
    if( autoPop ) exitCurrSplit( cs );
498
0
    return false;
499
0
  }
500
0
}
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
0
{
518
0
  const PartSplit splitType = _splitType;
519
520
0
  if( splitType == CU_QUAD_SPLIT )
521
0
  {
522
0
    Partitioning& sub = dst;
523
524
0
    for( uint32_t i = 0; i < 4; i++ )
525
0
    {
526
0
      sub[i] = cuArea;
527
528
0
      for( auto &blk : sub[i].blocks )
529
0
      {
530
0
        blk.height >>= 1;
531
0
        blk.width  >>= 1;
532
0
        if( i >= 2 ) blk.y += blk.height;
533
0
        if( i &  1 ) blk.x += blk.width;
534
0
      }
535
536
0
      CHECK( sub[i].lumaSize().height < MIN_TU_SIZE, "the split causes the block to be smaller than the minimal TU size" );
537
0
    }
538
539
0
    return 4;
540
0
  }
541
0
  else if( splitType == CU_HORZ_SPLIT )
542
0
  {
543
0
    Partitioning& sub = dst;
544
545
0
    for (uint32_t i = 0; i < 2; i++)
546
0
    {
547
0
      sub[i] = cuArea;
548
549
0
      for (auto &blk : sub[i].blocks)
550
0
      {
551
0
        blk.height >>= 1;
552
0
        if (i == 1) blk.y += blk.height;
553
0
      }
554
555
0
      CHECK(sub[i].lumaSize().height < MIN_TU_SIZE, "the cs split causes the block to be smaller than the minimal TU size");
556
0
    }
557
558
0
    return 2;
559
0
  }
560
0
  else if( splitType == CU_VERT_SPLIT )
561
0
  {
562
0
    Partitioning& sub = dst;
563
564
0
    for( uint32_t i = 0; i < 2; i++ )
565
0
    {
566
0
      sub[i] = cuArea;
567
568
0
      for( auto &blk : sub[i].blocks )
569
0
      {
570
0
        blk.width >>= 1;
571
0
        if( i == 1 ) blk.x += blk.width;
572
0
      }
573
574
0
      CHECK( sub[i].lumaSize().width < MIN_TU_SIZE, "the split causes the block to be smaller than the minimal TU size" );
575
0
    }
576
577
0
    return 2;
578
0
  }
579
0
  else if( splitType == CU_TRIH_SPLIT )
580
0
  {
581
0
    Partitioning& sub = dst;
582
583
0
    for( int i = 0; i < 3; i++ )
584
0
    {
585
0
      sub[i] = cuArea;
586
587
0
      for( auto &blk : sub[i].blocks )
588
0
      {
589
0
        blk.height >>= 1;
590
0
        if( ( i + 1 ) & 1 ) blk.height >>= 1;
591
0
        if( i == 1 )        blk.y       +=     blk.height / 2;
592
0
        if( i == 2 )        blk.y       += 3 * blk.height;
593
0
      }
594
595
0
      CHECK( sub[i].lumaSize().height < MIN_TU_SIZE, "the cs split causes the block to be smaller than the minimal TU size" );
596
0
    }
597
598
0
    return 3;
599
0
  }
600
0
  else if( splitType == CU_TRIV_SPLIT )
601
0
  {
602
0
    Partitioning& sub = dst;
603
604
0
    for( int i = 0; i < 3; i++ )
605
0
    {
606
0
      sub[i] = cuArea;
607
608
0
      for( auto &blk : sub[i].blocks )
609
0
      {
610
0
        blk.width >>= 1;
611
612
0
        if( ( i + 1 ) & 1 ) blk.width >>= 1;
613
0
        if( i == 1 )        blk.x      +=     blk.width / 2;
614
0
        if( i == 2 )        blk.x      += 3 * blk.width;
615
0
      }
616
617
0
      CHECK( sub[i].lumaSize().width < MIN_TU_SIZE, "the cs split causes the block to be smaller than the minimal TU size" );
618
0
    }
619
620
0
    return 3;
621
0
  }
622
0
  else
623
0
  {
624
0
    THROW_RECOVERABLE( "Unknown CU sub-partitioning" );
625
0
  }
626
0
}
627
628
int PartitionerImpl::getTUIntraSubPartitions( const UnitArea &tuArea, const CodingStructure &cs, const bool isDualTree, const PartSplit splitType, Partitioning &sub, const TreeType treeType )
629
0
{
630
0
  uint32_t nPartitions;
631
0
  uint32_t splitDimensionSize = CU::getISPSplitDim( tuArea.lumaSize().width, tuArea.lumaSize().height, splitType );
632
633
0
  if( splitType == TU_1D_HORZ_SPLIT )
634
0
  {
635
0
    nPartitions = tuArea.lumaSize().height >> getLog2(splitDimensionSize);
636
637
0
    for( uint32_t i = 0; i < nPartitions; i++ )
638
0
    {
639
0
      sub[i] = tuArea;
640
0
      CompArea& blkY = sub[i].blocks[COMPONENT_Y];
641
642
0
      blkY.height = splitDimensionSize;
643
0
      blkY.y = i > 0 ? sub[i - 1].blocks[COMPONENT_Y].y + splitDimensionSize : blkY.y;
644
645
0
      CHECK( sub[i].lumaSize().height < 1, "the cs split causes the block to be smaller than the minimal TU size" );
646
0
    }
647
0
  }
648
0
  else if( splitType == TU_1D_VERT_SPLIT )
649
0
  {
650
0
    nPartitions = tuArea.lumaSize().width >> getLog2(splitDimensionSize);
651
652
0
    for( uint32_t i = 0; i < nPartitions; i++ )
653
0
    {
654
0
      sub[i] = tuArea;
655
0
      CompArea& blkY = sub[i].blocks[COMPONENT_Y];
656
657
0
      blkY.width = splitDimensionSize;
658
0
      blkY.x = i > 0 ? sub[i - 1].blocks[COMPONENT_Y].x + splitDimensionSize : blkY.x;
659
0
      CHECK( sub[i].lumaSize().width < 1, "the split causes the block to be smaller than the minimal TU size" );
660
0
    }
661
0
  }
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
0
  uint32_t partitionsWithoutChroma = (cs.area.chromaFormat == CHROMA_400) ? 0 : (isDualTree ? nPartitions : nPartitions - 1);
668
0
  for( uint32_t i = 0; i < partitionsWithoutChroma; i++ )
669
0
  {
670
0
    CompArea& blkCb = sub[i].blocks[COMPONENT_Cb];
671
0
    CompArea& blkCr = sub[i].blocks[COMPONENT_Cr];
672
0
    blkCb = CompArea();
673
0
    blkCr = CompArea();
674
0
  }
675
676
0
  return nPartitions;
677
0
}
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
}