Coverage Report

Created: 2026-09-02 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/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) 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     UnitPartitioner.h
45
 *  \brief    Provides a class for partitioning management
46
 */
47
48
#include "UnitPartitioner.h"
49
#include "CodingStructure.h"
50
#include "Unit.h"
51
#include "Slice.h"
52
#include "UnitTools.h"
53
#include "Picture.h"
54
55
//! \ingroup CommonLib
56
//! \{
57
58
namespace vvenc {
59
60
PartLevel::PartLevel()
61
2.09M
: split               ( CU_DONT_SPLIT )
62
, parts               (               )
63
2.09M
, idx                 ( 0u            )
64
2.09M
, checkdIfImplicit    ( false         )
65
2.09M
, isImplicit          ( false         )
66
2.09M
, implicitSplit       ( CU_DONT_SPLIT )
67
2.09M
, firstSubPartSplit   ( CU_DONT_SPLIT )
68
2.09M
, canQtSplit          ( true          )
69
2.09M
, qgEnable            ( true          )
70
2.09M
, qgChromaEnable      ( true          )
71
2.09M
, modeType            ( MODE_TYPE_ALL )
72
2.09M
{
73
2.09M
}
74
75
void PartLevel::init()
76
192k
{
77
192k
  split               = CU_DONT_SPLIT;
78
192k
  idx                 = 0u;
79
192k
  checkdIfImplicit    = false;
80
192k
  isImplicit          = false;
81
192k
  implicitSplit       = CU_DONT_SPLIT;
82
192k
  firstSubPartSplit   = CU_DONT_SPLIT;
83
192k
  canQtSplit          = true;
84
192k
  qgEnable            = true;
85
192k
  qgChromaEnable      = true;
86
192k
  modeType            = MODE_TYPE_ALL;
87
192k
  numParts            = 0;
88
192k
}
89
90
//////////////////////////////////////////////////////////////////////////
91
// Partitioner class
92
//////////////////////////////////////////////////////////////////////////
93
94
SplitSeries Partitioner::getSplitSeries() const
95
125k
{
96
125k
  SplitSeries splitSeries = 0;
97
125k
  SplitSeries depth = 0;
98
99
125k
  for( const auto &level : m_partStack )
100
507k
  {
101
507k
    if( level.split == CTU_LEVEL ) continue;
102
381k
    else splitSeries += static_cast< SplitSeries >( level.split ) << ( depth * SPLIT_DMULT );
103
104
381k
    depth++;
105
381k
  }
106
107
125k
  return splitSeries;
108
125k
}
109
110
ModeTypeSeries Partitioner::getModeTypeSeries() const
111
125k
{
112
125k
  ModeTypeSeries modeTypeSeries = 0;
113
125k
  int depth = 0;
114
115
125k
  for( const auto &level : m_partStack )
116
507k
  {
117
507k
    if( level.split == CTU_LEVEL ) continue;
118
381k
    else modeTypeSeries += static_cast<int>(level.modeType) << (depth * 3);
119
120
381k
    depth++;
121
381k
  }
122
123
125k
  return modeTypeSeries;
124
125k
}
125
126
bool Partitioner::isSepTree( const CodingStructure &cs )
127
694k
{
128
694k
  return treeType != TREE_D || CS::isDualITree( cs );
129
694k
}
130
131
void Partitioner::setCUData( CodingUnit& cu )
132
125k
{
133
125k
  cu.depth       = currDepth;
134
125k
  cu.btDepth     = currBtDepth;
135
125k
  cu.mtDepth     = currMtDepth;
136
125k
  cu.qtDepth     = currQtDepth;
137
125k
  cu.splitSeries = getSplitSeries();
138
125k
  cu.modeTypeSeries = getModeTypeSeries();
139
125k
  cu.treeType    = treeType; 
140
125k
  cu.modeType    = modeType; 
141
142
125k
}
143
144
void Partitioner::copyState( const Partitioner& other )
145
0
{
146
0
  m_partStack = other.m_partStack;
147
0
  currBtDepth = other.currBtDepth;
148
0
  currQtDepth = other.currQtDepth;
149
0
  currDepth   = other.currDepth;
150
0
  currMtDepth = other.currMtDepth;
151
0
  currTrDepth = other.currTrDepth;
152
0
  currSubdiv  = other.currSubdiv;
153
0
  currQgPos   = other.currQgPos;
154
0
  currQgChromaPos = other.currQgChromaPos;
155
0
  currImplicitBtDepth
156
0
              = other.currImplicitBtDepth;
157
0
  chType      = other.chType;
158
0
#ifdef _DEBUG
159
0
  m_currArea  = other.m_currArea;
160
0
#endif
161
0
}
162
163
void Partitioner::setMaxMinDepth( unsigned& minDepth, unsigned& maxDepth, const CodingStructure& cs, int QtbttSpeedUp, bool MergeFlag) const
164
123k
{
165
123k
  unsigned          stdMinDepth = 0;
166
123k
  unsigned          stdMaxDepth = cs.pcv->getMaxDepth( cs.slice->sliceType, chType );
167
123k
  const Position    pos         = currArea().blocks[chType].pos();
168
123k
  const unsigned    curSliceIdx = cs.slice->independentSliceIdx;
169
123k
  const unsigned    curTileIdx  = cs.pps->getTileIdx( currArea().lumaPos() );
170
171
123k
  const CodingUnit* cuLeft        = cs.getCURestricted( pos.offset( -1,                               0 ), pos, curSliceIdx, curTileIdx, chType, treeType );
172
123k
  const CodingUnit* cuBelowLeft   = cs.getCURestricted( pos.offset( -1, currArea().blocks[chType].height), pos, curSliceIdx, curTileIdx, chType, treeType );
173
123k
  const CodingUnit* cuAbove       = cs.getCURestricted( pos.offset(  0,                              -1 ), pos, curSliceIdx, curTileIdx, chType, treeType );
174
123k
  const CodingUnit* cuAboveRight  = cs.getCURestricted( pos.offset( currArea().blocks[chType].width, -1 ), pos, curSliceIdx, curTileIdx, chType, treeType );
175
176
123k
  minDepth = stdMaxDepth;
177
123k
  maxDepth = stdMinDepth;
178
179
123k
  if( cuLeft )
180
72.6k
  {
181
72.6k
    minDepth = std::min<unsigned>( minDepth, cuLeft->qtDepth );
182
72.6k
    maxDepth = std::max<unsigned>( maxDepth, cuLeft->qtDepth );
183
72.6k
  }
184
50.8k
  else
185
50.8k
  {
186
50.8k
    minDepth = stdMinDepth;
187
50.8k
    maxDepth = stdMaxDepth;
188
50.8k
  }
189
190
123k
  if( cuBelowLeft )
191
10.8k
  {
192
10.8k
    minDepth = std::min<unsigned>( minDepth, cuBelowLeft->qtDepth );
193
10.8k
    maxDepth = std::max<unsigned>( maxDepth, cuBelowLeft->qtDepth );
194
10.8k
  }
195
112k
  else
196
112k
  {
197
112k
    minDepth = stdMinDepth;
198
112k
    maxDepth = stdMaxDepth;
199
112k
  }
200
201
123k
  if( cuAbove )
202
75.1k
  {
203
75.1k
    minDepth = std::min<unsigned>( minDepth, cuAbove->qtDepth );
204
75.1k
    maxDepth = std::max<unsigned>( maxDepth, cuAbove->qtDepth );
205
75.1k
  }
206
48.3k
  else
207
48.3k
  {
208
48.3k
    minDepth = stdMinDepth;
209
48.3k
    maxDepth = stdMaxDepth;
210
48.3k
  }
211
212
123k
  if( cuAboveRight )
213
25.8k
  {
214
25.8k
    minDepth = std::min<unsigned>( minDepth, cuAboveRight->qtDepth );
215
25.8k
    maxDepth = std::max<unsigned>( maxDepth, cuAboveRight->qtDepth );
216
25.8k
  }
217
97.6k
  else
218
97.6k
  {
219
97.6k
    minDepth = stdMinDepth;
220
97.6k
    maxDepth = stdMaxDepth;
221
97.6k
  }
222
223
123k
  minDepth = ( minDepth >= 1 ? minDepth - 1 : 0 );
224
123k
  maxDepth = std::min<unsigned>( stdMaxDepth, maxDepth + 1 );
225
123k
  if((QtbttSpeedUp >> 2) && (cs.slice->TLayer > 0) && ((cs.area.Y().width >= 8) || (cs.area.Y().height >= 8)))
226
0
  {
227
0
    int minDepthCur = stdMaxDepth;
228
0
    int maxDepthCur = stdMinDepth;
229
0
    int amountN = 0;
230
0
    for (int n = 0; n < 3; n++)
231
0
    {
232
0
      const CodingUnit* cuNeigh = (n==0)?cs.getCURestricted(pos.offset(-1, -1), pos, curSliceIdx, curTileIdx, chType, treeType): (n==1)? cuAbove : cuLeft;
233
0
      if (cuNeigh)
234
0
      {
235
0
        amountN++;
236
0
        minDepthCur = std::min<unsigned>(minDepthCur, cuNeigh->qtDepth);
237
0
        maxDepthCur = std::max<unsigned>(maxDepthCur, cuNeigh->qtDepth);
238
0
      }
239
0
    }
240
0
    if (amountN)
241
0
    {
242
0
      minDepthCur = (minDepthCur >= 1 ? minDepthCur - 1 : 0);
243
0
      maxDepthCur = std::min<unsigned>(stdMaxDepth, maxDepthCur + 1);
244
0
      maxDepth = std::min<unsigned>(maxDepthCur, maxDepth);
245
0
      minDepth = std::max<unsigned>(minDepthCur, minDepth);
246
0
    }
247
0
  }
248
249
123k
  if (!cs.slice->isIntra() && (QtbttSpeedUp & 3))
250
0
  {
251
0
    bool doMin_SCC = !(((QtbttSpeedUp & 3) == 2) && (cs.area.Y().width < cs.pcv->maxCUSize));
252
0
    bool LimitDepths = (QtbttSpeedUp & 2) ? (MergeFlag == 0) : (cs.area.Y().width >= cs.pcv->maxCUSize);
253
0
    if (LimitDepths && cuAbove && cuLeft && (cuLeft->qtDepth == cuAbove->qtDepth))
254
0
    {
255
0
      int minDepthCur = cuAbove->qtDepth;
256
0
      int maxDepthCur = cuAbove->qtDepth;
257
0
      minDepthCur = (minDepthCur > 0) ? (minDepthCur - 1) : 0;
258
0
      maxDepthCur = (maxDepthCur < stdMaxDepth) ? (maxDepthCur + 1) : maxDepthCur;
259
0
      maxDepth = std::min<unsigned>(maxDepthCur, maxDepth);
260
0
      minDepth = std::max<unsigned>(minDepthCur, minDepth);
261
0
    }
262
0
    else if (doMin_SCC && LimitDepths && cuAbove && cuLeft)
263
0
    {
264
0
      int minDepthCur = cuAbove->qtDepth;
265
0
      int maxDepthCur = cuAbove->qtDepth;
266
0
      minDepthCur = (minDepthCur > 0) ? (minDepthCur - 1) : 0;
267
0
      maxDepthCur = (maxDepthCur < stdMaxDepth) ? (maxDepthCur + 1) : maxDepthCur;
268
0
      if ((cuLeft->qtDepth > maxDepthCur) && ((cuLeft->qtDepth - 1) >= maxDepthCur))
269
0
      {
270
0
        minDepthCur += 1;
271
0
        maxDepthCur += 1;
272
0
      }
273
0
      else if ((cuLeft->qtDepth < minDepthCur) && ((cuLeft->qtDepth + 1) <= minDepthCur))
274
0
      {
275
0
        maxDepthCur -= 1;
276
0
        minDepthCur -= 1;
277
0
      }
278
0
      maxDepth = std::min<unsigned>(maxDepthCur, maxDepth);
279
0
      minDepth = std::max<unsigned>(minDepthCur, minDepth);
280
0
    }
281
0
    if ((QtbttSpeedUp & 2) && MergeFlag && (maxDepth == 4) && (cs.area.Y().width <= 16))
282
0
    {
283
0
      maxDepth = 3;
284
0
      minDepth = (minDepth == 3)? 2: minDepth;
285
0
    }
286
0
  }
287
123k
}
288
289
void Partitioner::initCtu( const UnitArea& ctuArea, const ChannelType _chType, const Slice& slice )
290
21.5k
{
291
21.5k
#if _DEBUG
292
21.5k
  m_currArea = ctuArea;
293
21.5k
#endif
294
21.5k
  currDepth   = 0;
295
21.5k
  currTrDepth = 0;
296
21.5k
  currBtDepth = 0;
297
21.5k
  currMtDepth = 0;
298
21.5k
  currQtDepth = 0;
299
21.5k
  currSubdiv  = 0;
300
21.5k
  currQgPos   = ctuArea.lumaPos();
301
21.5k
  currQgChromaPos = ctuArea.chromaFormat != CHROMA_400 ? ctuArea.chromaPos() : Position();
302
21.5k
  currImplicitBtDepth = 0;
303
21.5k
  chType      = _chType;
304
305
21.5k
  const PreCalcValues& pcv = *slice.pps->pcv;
306
  
307
21.5k
  maxBTD      = pcv.getMaxMTTDepth( slice, chType );
308
21.5k
  maxBtSize   = pcv.getMaxBtSize  ( slice, chType );
309
21.5k
  minTSize    = pcv.getMinTSize   ( slice, chType );
310
21.5k
  maxTtSize   = pcv.getMaxTtSize  ( slice, chType );
311
21.5k
  minQtSize   = pcv.getMinQtSize  ( slice, chType );
312
  
313
21.5k
  m_partBufIdx = 1;
314
21.5k
  m_partStack.resize_noinit( 1 );
315
21.5k
  m_partStack.back().init();
316
21.5k
  m_partStack.back().split = CTU_LEVEL;
317
21.5k
  m_partStack.back().parts = m_partBuf;
318
21.5k
  m_partStack.back().parts[0] = ctuArea;
319
21.5k
  m_partStack.back().numParts = 1;
320
321
21.5k
  treeType = TREE_D;
322
21.5k
  modeType = MODE_TYPE_ALL;
323
21.5k
}
324
325
void Partitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs )
326
170k
{
327
170k
  if ((split != TU_1D_HORZ_SPLIT) && (split != TU_1D_VERT_SPLIT))
328
150k
  {
329
150k
    CHECKD(!canSplit(split, cs), "Trying to apply a prohibited split!");
330
150k
  }
331
332
170k
  bool isImplicit = isSplitImplicit( split, cs );
333
170k
  bool canQtSplit = canSplit( CU_QUAD_SPLIT, cs );
334
170k
  bool qgEnable = currQgEnable();
335
170k
  bool qgChromaEnable = currQgChromaEnable();
336
337
170k
  const UnitArea& area = currArea();
338
170k
  m_partStack.resize_noinit( m_partStack.size() + 1 );
339
170k
  PartLevel& back = m_partStack.back();
340
170k
  back.init();
341
170k
  back.split = split;
342
170k
  back.parts = &m_partBuf[m_partBufIdx];
343
170k
  int numParts;
344
345
170k
  CHECK( m_partBufIdx > partBufSize, "Partition buffer overflow" );
346
347
170k
  switch( split )
348
170k
  {
349
49.4k
  case CU_QUAD_SPLIT:
350
49.4k
    numParts = PartitionerImpl::getCUSubPartitions( back.parts, area, cs, split );
351
49.4k
    back.modeType = modeType;
352
49.4k
    break;
353
49.0k
  case CU_HORZ_SPLIT:
354
101k
  case CU_VERT_SPLIT:
355
101k
    numParts = PartitionerImpl::getCUSubPartitions( back.parts, area, cs, split );
356
101k
    back.modeType = modeType;
357
101k
    break;
358
337
  case CU_TRIH_SPLIT:
359
394
  case CU_TRIV_SPLIT:
360
394
    numParts = PartitionerImpl::getCUSubPartitions( back.parts, area, cs, split );
361
394
    back.modeType = modeType;
362
394
    break;
363
0
  case TU_MAX_TR_SPLIT:
364
0
    numParts = PartitionerImpl::getMaxTuTiling( back.parts, area, cs );
365
0
    break;
366
0
  case SBT_VER_HALF_POS0_SPLIT:
367
0
  case SBT_VER_HALF_POS1_SPLIT:
368
0
  case SBT_HOR_HALF_POS0_SPLIT:
369
0
  case SBT_HOR_HALF_POS1_SPLIT:
370
0
  case SBT_VER_QUAD_POS0_SPLIT:
371
0
  case SBT_VER_QUAD_POS1_SPLIT:
372
0
  case SBT_HOR_QUAD_POS0_SPLIT:
373
0
  case SBT_HOR_QUAD_POS1_SPLIT:
374
0
    numParts = PartitionerImpl::getSbtTuTiling( back.parts, area, cs, split );
375
0
    break;
376
9.37k
  case TU_1D_HORZ_SPLIT:
377
19.5k
  case TU_1D_VERT_SPLIT:
378
19.5k
  {
379
19.5k
    numParts = PartitionerImpl::getTUIntraSubPartitions(back.parts, area, cs, split, TREE_D);
380
19.5k
    break;
381
9.37k
  }
382
0
  default:
383
0
    THROW( "Unknown split mode" );
384
0
    break;
385
170k
  }
386
387
170k
  back.numParts = numParts;
388
170k
  m_partBufIdx += numParts;
389
390
170k
  CHECK( m_partBufIdx > partBufSize, "Partition buffer overflow" );
391
392
170k
  currDepth++;
393
170k
  currSubdiv++;
394
170k
#if _DEBUG
395
170k
  m_currArea = m_partStack.back().parts[0];
396
170k
#endif
397
398
170k
  if ((split == TU_MAX_TR_SPLIT) || (split == TU_1D_HORZ_SPLIT) || (split == TU_1D_VERT_SPLIT))
399
19.5k
  {
400
19.5k
    currTrDepth++;
401
19.5k
  }
402
150k
  else if( split >= SBT_VER_HALF_POS0_SPLIT && split <= SBT_HOR_QUAD_POS1_SPLIT )
403
0
  {
404
0
    currTrDepth++;
405
0
  }
406
150k
  else
407
150k
  {
408
150k
    currTrDepth = 0;
409
150k
  }
410
411
170k
  if( split == CU_HORZ_SPLIT || split == CU_VERT_SPLIT || split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT )
412
101k
  {
413
101k
    currBtDepth++;
414
101k
    if( isImplicit ) currImplicitBtDepth++;
415
101k
    currMtDepth++;
416
417
101k
    if( split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT )
418
394
    {
419
      // first and last part of triple split are equivalent to double bt split
420
394
      currBtDepth++;
421
394
      currSubdiv++;
422
394
    }
423
101k
    m_partStack.back().canQtSplit = canQtSplit;
424
101k
  }
425
69.0k
  else if( split == CU_QUAD_SPLIT )
426
49.4k
  {
427
49.4k
    CHECK( currBtDepth > 0, "Cannot split a non-square area other than with a binary split" );
428
49.4k
    CHECK( currMtDepth > 0, "Cannot split a non-square area other than with a binary split" );
429
49.4k
    currMtDepth = 0;
430
49.4k
    currBtDepth = 0;
431
49.4k
    currQtDepth++;
432
49.4k
    currSubdiv++;
433
49.4k
  }
434
435
170k
  qgEnable       &= (currSubdiv <= (cs.slice->isIntra() ? cs.slice->picHeader->cuQpDeltaSubdivIntra : cs.slice->picHeader->cuQpDeltaSubdivInter ));
436
170k
  qgChromaEnable &= (currSubdiv <= (cs.slice->isIntra() ? cs.slice->picHeader->cuChromaQpOffsetSubdivIntra : cs.slice->picHeader->cuChromaQpOffsetSubdivInter ));
437
170k
  m_partStack.back().qgEnable       = qgEnable;
438
170k
  m_partStack.back().qgChromaEnable = qgChromaEnable;
439
170k
  if (qgEnable)
440
7.31k
    currQgPos = currArea().lumaPos();
441
170k
  if (qgChromaEnable)
442
0
    currQgChromaPos = currArea().chromaPos();
443
170k
}
444
445
void Partitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv )
446
2.16M
{
447
2.16M
  const PartSplit implicitSplit = m_partStack.back().checkdIfImplicit ? m_partStack.back().implicitSplit : getImplicitSplit( cs );
448
449
2.16M
  canNo = canQt = canBh = canTh = canBv = canTv = true;
450
2.16M
  bool canBtt = currMtDepth < (maxBTD + currImplicitBtDepth);
451
452
  // the minimal and maximal sizes are given in luma samples
453
2.16M
  const CompArea&  area  = currArea().Y();
454
2.16M
  const CompArea  *areaC = (chType == CH_C) ? &(currArea().Cb()) : nullptr;
455
2.16M
        PartLevel& level = m_partStack.back();
456
457
2.16M
  const PartSplit lastSplit = level.split;
458
2.16M
  const PartSplit parlSplit = lastSplit == CU_TRIH_SPLIT ? CU_HORZ_SPLIT : CU_VERT_SPLIT;
459
460
  // don't allow QT-splitting below a BT split
461
2.16M
  if( lastSplit != CTU_LEVEL && lastSplit != CU_QUAD_SPLIT ) canQt = false;
462
  // minQtSize is in luma samples unit
463
2.16M
  const unsigned minQTThreshold = minQtSize >> ((area.chromaFormat == CHROMA_400) ? 0 : ((int) getChannelTypeScaleX(CH_C, area.chromaFormat) - (int) getChannelTypeScaleY(CH_C, area.chromaFormat)));
464
2.16M
  if( area.width <= minQTThreshold )                         canQt = false;
465
2.16M
  if( areaC && areaC->width <= MIN_DUALTREE_CHROMA_WIDTH ) canQt = false;
466
2.16M
  if( treeType == TREE_C )
467
0
  {
468
0
    canQt = canBh = canTh = canBv = canTv = false;
469
0
    return;
470
0
  }
471
2.16M
  if( implicitSplit != CU_DONT_SPLIT )
472
807k
  {
473
807k
    canNo = canTh = canTv = false;
474
475
807k
    canBh = implicitSplit == CU_HORZ_SPLIT;
476
807k
    canBv = implicitSplit == CU_VERT_SPLIT;
477
807k
    if (areaC && areaC->width == 4) canBv = false;
478
807k
    if( !canBh && !canBv && !canQt ) canQt = true;
479
807k
    return;
480
807k
  }
481
482
1.35M
  if( ( lastSplit == CU_TRIH_SPLIT || lastSplit == CU_TRIV_SPLIT ) && currPartIdx() == 1 )
483
4.36k
  {
484
4.36k
    canBh = parlSplit != CU_HORZ_SPLIT;
485
4.36k
    canBv = parlSplit != CU_VERT_SPLIT;
486
4.36k
  }
487
488
1.35M
  if( canBtt && ( area.width <= minTSize && area.height <= minTSize ) )
489
0
  {
490
0
    canBtt = false;
491
0
  }
492
1.35M
  if( canBtt && ( area.width > maxBtSize || area.height > maxBtSize )
493
89.5k
      && ( ( area.width > maxTtSize || area.height > maxTtSize ) ) )
494
89.5k
  {
495
89.5k
    canBtt = false;
496
89.5k
  }
497
498
1.35M
  if( !canBtt )
499
303k
  {
500
303k
    canBh = canTh = canBv = canTv = false;
501
502
303k
    return;
503
303k
  }
504
505
1.05M
  if( area.width > maxBtSize || area.height > maxBtSize )
506
0
  {
507
0
    canBh = canBv = false;
508
0
  }
509
510
  // specific check for BT splits
511
1.05M
  if( area.height <= minTSize )                            canBh = false;
512
1.05M
  if( area.width > MAX_TB_SIZEY && area.height <= MAX_TB_SIZEY ) canBh = false;
513
1.05M
  if( areaC && areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE )     canBh = false;
514
1.05M
  if( area.width <= minTSize )                              canBv = false;
515
1.05M
  if( area.width <= MAX_TB_SIZEY && area.height > MAX_TB_SIZEY ) canBv = false;
516
1.05M
  if (areaC && (areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE || areaC->width == 4))     canBv = false;
517
1.05M
  if( modeType == MODE_TYPE_INTER && area.width * area.height == 32 )  canBv = canBh = false;
518
1.05M
  if( area.height <= 2 * minTSize || area.height > maxTtSize || area.width > maxTtSize )
519
435k
                                                                                       canTh = false;
520
1.05M
  if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY )  canTh = false;
521
1.05M
  if( areaC && areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE*2 )     canTh = false;
522
1.05M
  if( area.width <= 2 * minTSize || area.width > maxTtSize || area.height > maxTtSize )
523
429k
                                                                                       canTv = false;
524
1.05M
  if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY )  canTv = false;
525
1.05M
  if (areaC && (areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE * 2 || areaC->width == 8))     canTv = false;
526
1.05M
  if( modeType == MODE_TYPE_INTER && area.width * area.height == 64 )  canTv = canTh = false;
527
1.05M
}
528
529
bool Partitioner::canSplit( const PartSplit split, const CodingStructure &cs )
530
1.73M
{
531
1.73M
  const CompArea area       = currArea().Y();
532
1.73M
  const unsigned maxTrSize  = cs.sps->getMaxTbSize();
533
534
1.73M
  bool canNo, canQt, canBh, canTh, canBv, canTv;
535
536
1.73M
  canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv );
537
538
1.73M
  switch( split )
539
1.73M
  {
540
0
  case CTU_LEVEL:
541
0
    THROW( "Checking if top level split is possible" );
542
0
    return true;
543
0
    break;
544
250k
  case TU_MAX_TR_SPLIT:
545
250k
    return area.width > maxTrSize || area.height > maxTrSize;
546
0
    break;
547
0
  case SBT_VER_HALF_POS0_SPLIT:
548
0
  case SBT_VER_HALF_POS1_SPLIT:
549
0
  case SBT_HOR_HALF_POS0_SPLIT:
550
0
  case SBT_HOR_HALF_POS1_SPLIT:
551
0
  case SBT_VER_QUAD_POS0_SPLIT:
552
0
  case SBT_VER_QUAD_POS1_SPLIT:
553
0
  case SBT_HOR_QUAD_POS0_SPLIT:
554
0
  case SBT_HOR_QUAD_POS1_SPLIT:
555
0
    return currTrDepth == 0;
556
0
    break;
557
366k
  case CU_QUAD_SPLIT:
558
366k
    return canQt;
559
75.2k
  case CU_DONT_SPLIT:
560
75.2k
    return canNo;
561
373k
  case CU_HORZ_SPLIT:
562
373k
    return canBh;
563
374k
  case CU_VERT_SPLIT:
564
374k
    return canBv;
565
151k
  case CU_TRIH_SPLIT:
566
151k
    return canTh;
567
145k
  case CU_TRIV_SPLIT:
568
145k
    return canTv;
569
0
  case CU_MT_SPLIT:
570
0
    return ( canBh || canTh || canBv || canTv );
571
0
  case CU_BT_SPLIT:
572
0
    return ( canBh || canBv );
573
0
  break;
574
0
  default:
575
0
    THROW( "Unknown split mode" );
576
0
    return false;
577
0
    break;
578
1.73M
  }
579
580
0
  return true;
581
1.73M
}
582
583
bool Partitioner::canSplitISP(const PartSplit split, const CodingStructure& cs, CodingUnit& cu)
584
0
{
585
  // const PartSplit implicitSplit = getImplicitSplit(cs);
586
0
  const UnitArea& area = currArea();
587
588
0
  switch (split)
589
0
  {
590
0
  case TU_1D_HORZ_SPLIT:
591
0
  {
592
0
    return area.lheight() == cu.lheight();
593
0
  }
594
0
  case TU_1D_VERT_SPLIT:
595
0
  {
596
0
    return area.lwidth() == cu.lwidth();
597
0
  }
598
0
  case TU_MAX_TR_SPLIT:
599
0
  {
600
    // this split is performed implicitly with the other splits
601
0
    return false;
602
0
  }
603
0
  default: THROW("Unknown 1-D split mode"); break;
604
0
  }
605
0
}
606
607
bool Partitioner::isSplitImplicit( const PartSplit split, const CodingStructure &cs )
608
170k
{
609
170k
  return split == getImplicitSplit( cs );
610
170k
}
611
612
PartSplit Partitioner::getImplicitSplit( const CodingStructure &cs )
613
880k
{
614
880k
  if( m_partStack.back().checkdIfImplicit )
615
594k
  {
616
594k
    return m_partStack.back().implicitSplit;
617
594k
  }
618
619
285k
  PartSplit split = CU_DONT_SPLIT;
620
621
285k
  if( split == CU_DONT_SPLIT )
622
285k
  {
623
285k
    const bool isBlInPic = cs.picture->Y().contains( currArea().Y().bottomLeft() );
624
285k
    const bool isTrInPic = cs.picture->Y().contains( currArea().Y().topRight() );
625
626
285k
    const CompArea& area      = currArea().Y();
627
285k
    const bool isBtAllowed    = area.width <= maxBtSize && area.height <= maxBtSize && currMtDepth < (maxBTD + currImplicitBtDepth);
628
    // minQtSize is in luma samples unit
629
285k
    const unsigned minQTThreshold = minQtSize >> ((area.chromaFormat == CHROMA_400) ? 0 : ((int) getChannelTypeScaleX(CH_C, area.chromaFormat) - (int) getChannelTypeScaleY(CH_C, area.chromaFormat)));
630
285k
    const bool isQtAllowed    = area.width > minQTThreshold && currBtDepth == 0;
631
632
285k
    if( !isBlInPic && !isTrInPic && isQtAllowed )
633
19.6k
    {
634
19.6k
      split = CU_QUAD_SPLIT;
635
19.6k
    }
636
266k
    else if( !isBlInPic && isBtAllowed && area.width <= MAX_TB_SIZEY )
637
40.7k
    {
638
40.7k
      split = CU_HORZ_SPLIT;
639
40.7k
    }
640
225k
    else if( !isTrInPic && isBtAllowed && area.height <= MAX_TB_SIZEY )
641
44.6k
    {
642
44.6k
      split = CU_VERT_SPLIT;
643
44.6k
    }
644
181k
    else if( !isBlInPic || !isTrInPic )
645
22.5k
    {
646
22.5k
      split = CU_QUAD_SPLIT;
647
22.5k
    }
648
285k
    if (CS::isDualITree(cs) && (currArea().Y().width > 64 || currArea().Y().height > 64))
649
21.5k
    {
650
21.5k
      split = CU_QUAD_SPLIT;
651
21.5k
    }
652
285k
    if( (!isBlInPic || !isTrInPic) && split == CU_DONT_SPLIT )
653
0
    {
654
0
      split = CU_QUAD_SPLIT;
655
0
    }
656
285k
  }
657
658
285k
  m_partStack.back().checkdIfImplicit = true;
659
285k
  m_partStack.back().isImplicit = split != CU_DONT_SPLIT;
660
285k
  m_partStack.back().implicitSplit = split;
661
662
285k
  return split;
663
880k
}
664
665
void Partitioner::exitCurrSplit()
666
170k
{
667
170k
  const PartSplit currSplit = m_partStack.back().split;
668
170k
  const int       currIndex = m_partStack.back().idx;
669
170k
  const int       numParts  = m_partStack.back().numParts;
670
671
170k
  m_partStack.pop_back();
672
170k
  m_partBufIdx -= numParts;
673
674
170k
  CHECK( currDepth == 0, "depth is '0', although a split was performed" );
675
170k
  currDepth--;
676
170k
  currSubdiv--;
677
170k
  if( currQgEnable() )
678
34.3k
    currQgPos = currArea().lumaPos();
679
170k
  if( currArea().chromaFormat != CHROMA_400 && currQgChromaEnable() )
680
21.5k
    currQgChromaPos = currArea().chromaPos();
681
170k
#if _DEBUG
682
170k
  m_currArea = m_partStack.back().parts[m_partStack.back().idx];
683
170k
#endif
684
685
170k
  if( currSplit == CU_HORZ_SPLIT || currSplit == CU_VERT_SPLIT || currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT )
686
101k
  {
687
101k
    CHECK( !m_partStack.back().checkdIfImplicit, "Didn't check if the current split is implicit" );
688
101k
    CHECK( currBtDepth == 0, "BT depth is '0', athough a BT split was performed" );
689
101k
    CHECK( currMtDepth == 0, "MT depth is '0', athough a BT split was performed" );
690
101k
    currMtDepth--;
691
101k
    if( m_partStack.back().isImplicit ) currImplicitBtDepth--;
692
101k
    currBtDepth--;
693
101k
    if( ( currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT ) && currIndex != 1 )
694
394
    {
695
394
      CHECK( currBtDepth == 0, "BT depth is '0', athough a TT split was performed" );
696
394
      currBtDepth--;
697
394
      currSubdiv--;
698
394
    }
699
101k
  }
700
69.0k
  else if( currSplit == TU_MAX_TR_SPLIT )
701
0
  {
702
0
    CHECK( currTrDepth == 0, "TR depth is '0', although a TU split was performed" );
703
0
    currTrDepth--;
704
0
  }
705
69.0k
  else if( currSplit >= SBT_VER_HALF_POS0_SPLIT && currSplit <= SBT_HOR_QUAD_POS1_SPLIT )
706
0
  {
707
0
    CHECK( currTrDepth == 0, "TR depth is '0', although a TU split was performed" );
708
0
    currTrDepth--;
709
0
  }
710
69.0k
  else if ((currSplit == TU_1D_HORZ_SPLIT) || (currSplit == TU_1D_VERT_SPLIT))
711
19.5k
  {
712
19.5k
    CHECK(currTrDepth == 0, "TR depth is '0', although a TU split was performed");
713
19.5k
    currTrDepth--;
714
19.5k
  }
715
49.4k
  else
716
49.4k
  {
717
49.4k
    CHECK( currTrDepth > 0, "RQT found with QTBT partitioner" );
718
719
49.4k
    CHECK( currQtDepth == 0, "QT depth is '0', although a QT split was performed" );
720
49.4k
    currQtDepth--;
721
49.4k
    currSubdiv--;
722
49.4k
  }
723
170k
}
724
725
bool Partitioner::nextPart( const CodingStructure &cs, bool autoPop /*= false*/ )
726
426k
{
727
426k
  const Position& prevPos = currArea().blocks[chType].pos();
728
729
426k
  unsigned currIdx = ++m_partStack.back().idx;
730
731
426k
  m_partStack.back().checkdIfImplicit = false;
732
426k
  m_partStack.back().isImplicit = false;
733
734
426k
  if( currIdx == 1 )
735
157k
  {
736
157k
    const CodingUnit* prevCU = cs.getCU( prevPos, chType, treeType );
737
157k
    m_partStack.back().firstSubPartSplit = prevCU ? CU::getSplitAtDepth( *prevCU, currDepth ) : CU_DONT_SPLIT;
738
157k
  }
739
740
426k
  if( currIdx < m_partStack.back().numParts )
741
268k
  {
742
268k
    if( m_partStack.back().split == CU_TRIH_SPLIT || m_partStack.back().split == CU_TRIV_SPLIT )
743
788
    {
744
      // adapt the current bt depth
745
788
      if( currIdx == 1 ) currBtDepth--;
746
394
      else               currBtDepth++;
747
788
      if( currIdx == 1 ) currSubdiv--;
748
394
      else               currSubdiv++;
749
788
    }
750
268k
  if( currQgEnable() )
751
21.9k
    currQgPos = currArea().lumaPos();
752
268k
  if( currQgChromaEnable() )
753
0
    currQgChromaPos = currArea().chromaPos();
754
268k
#if _DEBUG
755
268k
    m_currArea = m_partStack.back().parts[currIdx];
756
268k
#endif
757
268k
    return true;
758
268k
  }
759
157k
  else
760
157k
  {
761
157k
    if( autoPop ) exitCurrSplit();
762
157k
    return false;
763
157k
  }
764
426k
}
765
766
bool Partitioner::hasNextPart()
767
116k
{
768
116k
  return ( ( m_partStack.back().idx + 1 ) < m_partStack.back().numParts );
769
116k
}
770
771
//////////////////////////////////////////////////////////////////////////
772
// Partitioner methods describing the actual partitioning logic
773
//////////////////////////////////////////////////////////////////////////
774
775
int PartitionerImpl::getCUSubPartitions( Partitioning& dst, const UnitArea &cuArea, const CodingStructure &cs, const PartSplit _splitType )
776
150k
{
777
150k
  const PartSplit splitType = _splitType;
778
779
150k
  if( splitType == CU_QUAD_SPLIT )
780
49.4k
  {
781
49.4k
    Partitioning& sub = dst;
782
783
247k
    for( uint32_t i = 0; i < 4; i++ )
784
197k
    {
785
197k
      sub[i] = cuArea;
786
787
197k
      for( auto &blk : sub[i].blocks )
788
593k
      {
789
593k
        blk.height >>= 1;
790
593k
        blk.width  >>= 1;
791
593k
        if( i >= 2 ) blk.y += blk.height;
792
593k
        if( i &  1 ) blk.x += blk.width;
793
593k
      }
794
197k
    }
795
796
49.4k
    return 4;
797
49.4k
  }
798
101k
  else if( splitType == CU_HORZ_SPLIT )
799
49.0k
  {
800
49.0k
    Partitioning& sub = dst;
801
802
147k
    for (uint32_t i = 0; i < 2; i++)
803
98.1k
    {
804
98.1k
      sub[i] = cuArea;
805
806
98.1k
      for (auto &blk : sub[i].blocks)
807
294k
      {
808
294k
        blk.height >>= 1;
809
294k
        if (i == 1) blk.y += blk.height;
810
294k
      }
811
98.1k
    }
812
813
49.0k
    return 2;
814
49.0k
  }
815
52.3k
  else if( splitType == CU_VERT_SPLIT )
816
51.9k
  {
817
51.9k
    Partitioning& sub = dst;
818
819
155k
    for( uint32_t i = 0; i < 2; i++ )
820
103k
    {
821
103k
      sub[i] = cuArea;
822
823
103k
      for( auto &blk : sub[i].blocks )
824
311k
      {
825
311k
        blk.width >>= 1;
826
311k
        if( i == 1 ) blk.x += blk.width;
827
311k
      }
828
103k
    }
829
830
51.9k
    return 2;
831
51.9k
  }
832
391
  else if( splitType == CU_TRIH_SPLIT )
833
337
  {
834
337
    Partitioning& sub = dst;
835
836
1.34k
    for( int i = 0; i < 3; i++ )
837
1.01k
    {
838
1.01k
      sub[i] = cuArea;
839
840
1.01k
      for( auto &blk : sub[i].blocks )
841
3.03k
      {
842
3.03k
        blk.height >>= 1;
843
3.03k
        if( ( i + 1 ) & 1 ) blk.height >>= 1;
844
3.03k
        if( i == 1 )        blk.y       +=     blk.height / 2;
845
3.03k
        if( i == 2 )        blk.y       += 3 * blk.height;
846
3.03k
      }
847
1.01k
    }
848
849
337
    return 3;
850
337
  }
851
54
  else if( splitType == CU_TRIV_SPLIT )
852
57
  {
853
57
    Partitioning& sub = dst;
854
855
228
    for( int i = 0; i < 3; i++ )
856
171
    {
857
171
      sub[i] = cuArea;
858
859
171
      for( auto &blk : sub[i].blocks )
860
513
      {
861
513
        blk.width >>= 1;
862
863
513
        if( ( i + 1 ) & 1 ) blk.width >>= 1;
864
513
        if( i == 1 )        blk.x      +=     blk.width / 2;
865
513
        if( i == 2 )        blk.x      += 3 * blk.width;
866
513
      }
867
171
    }
868
869
57
    return 3;
870
57
  }
871
18.4E
  else
872
18.4E
  {
873
18.4E
    THROW( "Unknown CU sub-partitioning" );
874
18.4E
  }
875
150k
}
876
877
int PartitionerImpl::getTUIntraSubPartitions( Partitioning& sub, const UnitArea &tuArea, const CodingStructure &cs, const PartSplit splitType, const TreeType treeType )
878
19.5k
{
879
19.5k
  uint32_t nPartitions;
880
19.5k
  uint32_t splitDimensionSize = CU::getISPSplitDim( tuArea.lumaSize().width, tuArea.lumaSize().height, splitType );
881
882
19.5k
  bool isDualTree = CS::isDualITree( cs ) || treeType != TREE_D;
883
884
19.5k
  if( splitType == TU_1D_HORZ_SPLIT )
885
9.37k
  {
886
9.37k
    nPartitions = tuArea.lumaSize().height >> Log2(splitDimensionSize);
887
888
46.8k
    for( uint32_t i = 0; i < nPartitions; i++ )
889
37.4k
    {
890
37.4k
      sub[i] = tuArea;
891
37.4k
      CompArea& blkY = sub[i].blocks[COMP_Y];
892
893
37.4k
      blkY.height = splitDimensionSize;
894
37.4k
      blkY.y = i > 0 ? sub[i - 1].blocks[COMP_Y].y + splitDimensionSize : blkY.y;
895
896
37.4k
      CHECK( sub[i].lumaSize().height < 1, "the cs split causes the block to be smaller than the minimal TU size" );
897
37.4k
    }
898
9.37k
  }
899
10.1k
  else if( splitType == TU_1D_VERT_SPLIT )
900
10.1k
  {
901
10.1k
    nPartitions = tuArea.lumaSize().width >> Log2(splitDimensionSize);
902
903
50.7k
    for( uint32_t i = 0; i < nPartitions; i++ )
904
40.6k
    {
905
40.6k
      sub[i] = tuArea;
906
40.6k
      CompArea& blkY = sub[i].blocks[COMP_Y];
907
908
40.6k
      blkY.width = splitDimensionSize;
909
40.6k
      blkY.x = i > 0 ? sub[i - 1].blocks[COMP_Y].x + splitDimensionSize : blkY.x;
910
40.6k
      CHECK( sub[i].lumaSize().width < 1, "the split causes the block to be smaller than the minimal TU size" );
911
40.6k
    }
912
10.1k
  }
913
0
  else
914
0
  {
915
0
    THROW( "Unknown TU sub-partitioning" );
916
0
  }
917
  //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)
918
19.5k
  uint32_t partitionsWithoutChroma = (cs.area.chromaFormat == CHROMA_400) ? 0 : (isDualTree ? nPartitions : nPartitions - 1);
919
97.6k
  for( uint32_t i = 0; i < partitionsWithoutChroma; i++ )
920
78.1k
  {
921
78.1k
    CompArea& blkCb = sub[i].blocks[COMP_Cb];
922
78.1k
    CompArea& blkCr = sub[i].blocks[COMP_Cr];
923
78.1k
    blkCb = CompArea();
924
78.1k
    blkCr = CompArea();
925
78.1k
  }
926
927
19.5k
  return nPartitions;
928
19.5k
}
929
930
931
static const int g_rsScanToZ_w4[16] =
932
{
933
   0,  1,  4,  5, // wouldn't work for 128x32 blocks, but those are forbidden bcs of VPDU constraints
934
   2,  3,  6,  7, // correct ordering for 128x64 (TU32)
935
   8,  9, 12, 13,
936
  10, 11, 14, 15, // correct ordering for 128x128 (TU32)
937
};
938
939
static const int g_rsScanToZ_w2[8] =
940
{
941
   0,  1, // correct ordering for 64x32 (TU32) and 128x64 (TU64)
942
   2,  3, // correct ordering for 64x64 (TU32) and 128x128 (TU64)
943
   4,  5,
944
   6,  7, // correct ordering for 32x64 (TU32) and 64x128 (TU64)
945
};
946
947
static const int g_rsScanToZ_w1[4] =
948
{
949
   0, // no tiling, never used
950
   1, // correct ordering for 64x32 (TU32) and 128x64 (TU64)
951
   2,
952
   3, // correct ordering for 128x32 (TU32)
953
};
954
955
static const int* g_rsScanToZ[3] = { g_rsScanToZ_w1, g_rsScanToZ_w2, g_rsScanToZ_w4 };
956
957
int PartitionerImpl::getMaxTuTiling( Partitioning& dst, const UnitArea& cuArea, const CodingStructure& cs )
958
0
{
959
0
  const Size area = cuArea.lumaSize();
960
0
  const int maxTrSize = cs.sps->getMaxTbSize();
961
0
  const int numTilesH = std::max<int>( 1, area.width / maxTrSize );
962
0
  const int numTilesV = std::max<int>( 1, area.height / maxTrSize );
963
0
  const int numTiles  = numTilesH * numTilesV;
964
0
  const int numLog2H  = Log2( numTilesH );
965
0
  const int* rsScanToZ = g_rsScanToZ[numLog2H];
966
967
0
  Partitioning& ret = dst;
968
969
0
  for( int i = 0; i < numTiles; i++ )
970
0
  {
971
0
    ret[i] = cuArea;
972
973
0
    const int zid = rsScanToZ[i];
974
975
0
    const int y = zid >> numLog2H;
976
0
    const int x = zid & ( ( 1 << numLog2H ) - 1 );
977
978
0
    UnitArea& tile = ret[i];
979
980
0
    for( CompArea& comp : tile.blocks )
981
0
    {
982
0
      if( !comp.valid() ) continue;
983
984
0
      comp.width  /= numTilesH;
985
0
      comp.height /= numTilesV;
986
987
0
      comp.x += comp.width  * x;
988
0
      comp.y += comp.height * y;
989
0
    }
990
0
  }
991
992
0
  return numTiles;
993
0
}
994
995
int PartitionerImpl::getSbtTuTiling( Partitioning& dst, const UnitArea& cuArea, const CodingStructure &cs, const PartSplit splitType )
996
0
{
997
0
  Partitioning& ret = dst;
998
0
  int numTiles      = 2;
999
0
  int widthFactor, heightFactor, xOffsetFactor, yOffsetFactor;
1000
1001
0
  CHECK( !(splitType >= SBT_VER_HALF_POS0_SPLIT && splitType <= SBT_HOR_QUAD_POS1_SPLIT), "wrong" );
1002
1003
0
  for( int i = 0; i < numTiles; i++ )
1004
0
  {
1005
0
    ret[i] = cuArea;
1006
1007
0
    if( splitType >= SBT_VER_QUAD_POS0_SPLIT )
1008
0
    {
1009
0
      if( splitType == SBT_HOR_QUAD_POS0_SPLIT || splitType == SBT_HOR_QUAD_POS1_SPLIT )
1010
0
      {
1011
0
        widthFactor   = 4;
1012
0
        xOffsetFactor = 0;
1013
0
        heightFactor  = ( ( i == 0 &&        splitType == SBT_HOR_QUAD_POS0_SPLIT ) || ( i == 1 && splitType == SBT_HOR_QUAD_POS1_SPLIT ) ) ? 1 : 3;
1014
0
        yOffsetFactor =   ( i == 0 ) ? 0 : ( splitType == SBT_HOR_QUAD_POS0_SPLIT ? 1 : 3 );
1015
0
      }
1016
0
      else
1017
0
      {
1018
0
        widthFactor   = ( ( i == 0 &&        splitType == SBT_VER_QUAD_POS0_SPLIT ) || ( i == 1 && splitType == SBT_VER_QUAD_POS1_SPLIT ) ) ? 1 : 3;
1019
0
        xOffsetFactor =   ( i == 0 ) ? 0 : ( splitType == SBT_VER_QUAD_POS0_SPLIT ? 1 : 3 );
1020
0
        heightFactor  = 4;
1021
0
        yOffsetFactor = 0;
1022
0
      }
1023
0
    }
1024
0
    else
1025
0
    {
1026
0
      if( splitType == SBT_HOR_HALF_POS0_SPLIT || splitType == SBT_HOR_HALF_POS1_SPLIT )
1027
0
      {
1028
0
        widthFactor   = 4;
1029
0
        xOffsetFactor = 0;
1030
0
        heightFactor  = 2;
1031
0
        yOffsetFactor = ( i == 0 ) ? 0 : 2;
1032
0
      }
1033
0
      else
1034
0
      {
1035
0
        widthFactor   = 2;
1036
0
        xOffsetFactor = ( i == 0 ) ? 0 : 2;
1037
0
        heightFactor  = 4;
1038
0
        yOffsetFactor = 0;
1039
0
      }
1040
0
    }
1041
1042
0
    UnitArea& tile = ret[i];
1043
1044
0
    for( CompArea &comp : tile.blocks )
1045
0
    {
1046
0
      if( !comp.valid() ) continue;
1047
1048
0
      comp.x     += ( comp.width  * xOffsetFactor ) >> 2;
1049
0
      comp.y     += ( comp.height * yOffsetFactor ) >> 2;
1050
0
      comp.width  = ( comp.width  * widthFactor   ) >> 2;
1051
0
      comp.height = ( comp.height * heightFactor  ) >> 2;
1052
0
    }
1053
0
  }
1054
1055
0
  return numTiles;
1056
0
}
1057
1058
1059
} // namespace vvenc
1060
1061
//! \}
1062