Coverage Report

Created: 2026-08-31 06:22

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.20M
: split               ( CU_DONT_SPLIT )
62
, parts               (               )
63
2.20M
, idx                 ( 0u            )
64
2.20M
, checkdIfImplicit    ( false         )
65
2.20M
, isImplicit          ( false         )
66
2.20M
, implicitSplit       ( CU_DONT_SPLIT )
67
2.20M
, firstSubPartSplit   ( CU_DONT_SPLIT )
68
2.20M
, canQtSplit          ( true          )
69
2.20M
, qgEnable            ( true          )
70
2.20M
, qgChromaEnable      ( true          )
71
2.20M
, modeType            ( MODE_TYPE_ALL )
72
2.20M
{
73
2.20M
}
74
75
void PartLevel::init()
76
202k
{
77
202k
  split               = CU_DONT_SPLIT;
78
202k
  idx                 = 0u;
79
202k
  checkdIfImplicit    = false;
80
202k
  isImplicit          = false;
81
202k
  implicitSplit       = CU_DONT_SPLIT;
82
202k
  firstSubPartSplit   = CU_DONT_SPLIT;
83
202k
  canQtSplit          = true;
84
202k
  qgEnable            = true;
85
202k
  qgChromaEnable      = true;
86
202k
  modeType            = MODE_TYPE_ALL;
87
202k
  numParts            = 0;
88
202k
}
89
90
//////////////////////////////////////////////////////////////////////////
91
// Partitioner class
92
//////////////////////////////////////////////////////////////////////////
93
94
SplitSeries Partitioner::getSplitSeries() const
95
132k
{
96
132k
  SplitSeries splitSeries = 0;
97
132k
  SplitSeries depth = 0;
98
99
132k
  for( const auto &level : m_partStack )
100
537k
  {
101
537k
    if( level.split == CTU_LEVEL ) continue;
102
404k
    else splitSeries += static_cast< SplitSeries >( level.split ) << ( depth * SPLIT_DMULT );
103
104
404k
    depth++;
105
404k
  }
106
107
132k
  return splitSeries;
108
132k
}
109
110
ModeTypeSeries Partitioner::getModeTypeSeries() const
111
132k
{
112
132k
  ModeTypeSeries modeTypeSeries = 0;
113
132k
  int depth = 0;
114
115
132k
  for( const auto &level : m_partStack )
116
537k
  {
117
537k
    if( level.split == CTU_LEVEL ) continue;
118
404k
    else modeTypeSeries += static_cast<int>(level.modeType) << (depth * 3);
119
120
404k
    depth++;
121
404k
  }
122
123
132k
  return modeTypeSeries;
124
132k
}
125
126
bool Partitioner::isSepTree( const CodingStructure &cs )
127
734k
{
128
734k
  return treeType != TREE_D || CS::isDualITree( cs );
129
734k
}
130
131
void Partitioner::setCUData( CodingUnit& cu )
132
132k
{
133
132k
  cu.depth       = currDepth;
134
132k
  cu.btDepth     = currBtDepth;
135
132k
  cu.mtDepth     = currMtDepth;
136
132k
  cu.qtDepth     = currQtDepth;
137
132k
  cu.splitSeries = getSplitSeries();
138
132k
  cu.modeTypeSeries = getModeTypeSeries();
139
132k
  cu.treeType    = treeType; 
140
132k
  cu.modeType    = modeType; 
141
142
132k
}
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
130k
{
165
130k
  unsigned          stdMinDepth = 0;
166
130k
  unsigned          stdMaxDepth = cs.pcv->getMaxDepth( cs.slice->sliceType, chType );
167
130k
  const Position    pos         = currArea().blocks[chType].pos();
168
130k
  const unsigned    curSliceIdx = cs.slice->independentSliceIdx;
169
130k
  const unsigned    curTileIdx  = cs.pps->getTileIdx( currArea().lumaPos() );
170
171
130k
  const CodingUnit* cuLeft        = cs.getCURestricted( pos.offset( -1,                               0 ), pos, curSliceIdx, curTileIdx, chType, treeType );
172
130k
  const CodingUnit* cuBelowLeft   = cs.getCURestricted( pos.offset( -1, currArea().blocks[chType].height), pos, curSliceIdx, curTileIdx, chType, treeType );
173
130k
  const CodingUnit* cuAbove       = cs.getCURestricted( pos.offset(  0,                              -1 ), pos, curSliceIdx, curTileIdx, chType, treeType );
174
130k
  const CodingUnit* cuAboveRight  = cs.getCURestricted( pos.offset( currArea().blocks[chType].width, -1 ), pos, curSliceIdx, curTileIdx, chType, treeType );
175
176
130k
  minDepth = stdMaxDepth;
177
130k
  maxDepth = stdMinDepth;
178
179
130k
  if( cuLeft )
180
76.4k
  {
181
76.4k
    minDepth = std::min<unsigned>( minDepth, cuLeft->qtDepth );
182
76.4k
    maxDepth = std::max<unsigned>( maxDepth, cuLeft->qtDepth );
183
76.4k
  }
184
54.0k
  else
185
54.0k
  {
186
54.0k
    minDepth = stdMinDepth;
187
54.0k
    maxDepth = stdMaxDepth;
188
54.0k
  }
189
190
130k
  if( cuBelowLeft )
191
11.2k
  {
192
11.2k
    minDepth = std::min<unsigned>( minDepth, cuBelowLeft->qtDepth );
193
11.2k
    maxDepth = std::max<unsigned>( maxDepth, cuBelowLeft->qtDepth );
194
11.2k
  }
195
119k
  else
196
119k
  {
197
119k
    minDepth = stdMinDepth;
198
119k
    maxDepth = stdMaxDepth;
199
119k
  }
200
201
130k
  if( cuAbove )
202
79.4k
  {
203
79.4k
    minDepth = std::min<unsigned>( minDepth, cuAbove->qtDepth );
204
79.4k
    maxDepth = std::max<unsigned>( maxDepth, cuAbove->qtDepth );
205
79.4k
  }
206
51.0k
  else
207
51.0k
  {
208
51.0k
    minDepth = stdMinDepth;
209
51.0k
    maxDepth = stdMaxDepth;
210
51.0k
  }
211
212
130k
  if( cuAboveRight )
213
27.4k
  {
214
27.4k
    minDepth = std::min<unsigned>( minDepth, cuAboveRight->qtDepth );
215
27.4k
    maxDepth = std::max<unsigned>( maxDepth, cuAboveRight->qtDepth );
216
27.4k
  }
217
103k
  else
218
103k
  {
219
103k
    minDepth = stdMinDepth;
220
103k
    maxDepth = stdMaxDepth;
221
103k
  }
222
223
130k
  minDepth = ( minDepth >= 1 ? minDepth - 1 : 0 );
224
130k
  maxDepth = std::min<unsigned>( stdMaxDepth, maxDepth + 1 );
225
130k
  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
130k
  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
130k
}
288
289
void Partitioner::initCtu( const UnitArea& ctuArea, const ChannelType _chType, const Slice& slice )
290
22.6k
{
291
22.6k
#if _DEBUG
292
22.6k
  m_currArea = ctuArea;
293
22.6k
#endif
294
22.6k
  currDepth   = 0;
295
22.6k
  currTrDepth = 0;
296
22.6k
  currBtDepth = 0;
297
22.6k
  currMtDepth = 0;
298
22.6k
  currQtDepth = 0;
299
22.6k
  currSubdiv  = 0;
300
22.6k
  currQgPos   = ctuArea.lumaPos();
301
22.6k
  currQgChromaPos = ctuArea.chromaFormat != CHROMA_400 ? ctuArea.chromaPos() : Position();
302
22.6k
  currImplicitBtDepth = 0;
303
22.6k
  chType      = _chType;
304
305
22.6k
  const PreCalcValues& pcv = *slice.pps->pcv;
306
  
307
22.6k
  maxBTD      = pcv.getMaxMTTDepth( slice, chType );
308
22.6k
  maxBtSize   = pcv.getMaxBtSize  ( slice, chType );
309
22.6k
  minTSize    = pcv.getMinTSize   ( slice, chType );
310
22.6k
  maxTtSize   = pcv.getMaxTtSize  ( slice, chType );
311
22.6k
  minQtSize   = pcv.getMinQtSize  ( slice, chType );
312
  
313
22.6k
  m_partBufIdx = 1;
314
22.6k
  m_partStack.resize_noinit( 1 );
315
22.6k
  m_partStack.back().init();
316
22.6k
  m_partStack.back().split = CTU_LEVEL;
317
22.6k
  m_partStack.back().parts = m_partBuf;
318
22.6k
  m_partStack.back().parts[0] = ctuArea;
319
22.6k
  m_partStack.back().numParts = 1;
320
321
22.6k
  treeType = TREE_D;
322
22.6k
  modeType = MODE_TYPE_ALL;
323
22.6k
}
324
325
void Partitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs )
326
179k
{
327
179k
  if ((split != TU_1D_HORZ_SPLIT) && (split != TU_1D_VERT_SPLIT))
328
159k
  {
329
159k
    CHECKD(!canSplit(split, cs), "Trying to apply a prohibited split!");
330
159k
  }
331
332
179k
  bool isImplicit = isSplitImplicit( split, cs );
333
179k
  bool canQtSplit = canSplit( CU_QUAD_SPLIT, cs );
334
179k
  bool qgEnable = currQgEnable();
335
179k
  bool qgChromaEnable = currQgChromaEnable();
336
337
179k
  const UnitArea& area = currArea();
338
179k
  m_partStack.resize_noinit( m_partStack.size() + 1 );
339
179k
  PartLevel& back = m_partStack.back();
340
179k
  back.init();
341
179k
  back.split = split;
342
179k
  back.parts = &m_partBuf[m_partBufIdx];
343
179k
  int numParts;
344
345
179k
  CHECK( m_partBufIdx > partBufSize, "Partition buffer overflow" );
346
347
179k
  switch( split )
348
179k
  {
349
52.0k
  case CU_QUAD_SPLIT:
350
52.0k
    numParts = PartitionerImpl::getCUSubPartitions( back.parts, area, cs, split );
351
52.0k
    back.modeType = modeType;
352
52.0k
    break;
353
51.9k
  case CU_HORZ_SPLIT:
354
106k
  case CU_VERT_SPLIT:
355
106k
    numParts = PartitionerImpl::getCUSubPartitions( back.parts, area, cs, split );
356
106k
    back.modeType = modeType;
357
106k
    break;
358
369
  case CU_TRIH_SPLIT:
359
426
  case CU_TRIV_SPLIT:
360
426
    numParts = PartitionerImpl::getCUSubPartitions( back.parts, area, cs, split );
361
426
    back.modeType = modeType;
362
426
    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.91k
  case TU_1D_HORZ_SPLIT:
377
20.7k
  case TU_1D_VERT_SPLIT:
378
20.7k
  {
379
20.7k
    numParts = PartitionerImpl::getTUIntraSubPartitions(back.parts, area, cs, split, TREE_D);
380
20.7k
    break;
381
9.91k
  }
382
0
  default:
383
0
    THROW( "Unknown split mode" );
384
0
    break;
385
179k
  }
386
387
179k
  back.numParts = numParts;
388
179k
  m_partBufIdx += numParts;
389
390
179k
  CHECK( m_partBufIdx > partBufSize, "Partition buffer overflow" );
391
392
179k
  currDepth++;
393
179k
  currSubdiv++;
394
179k
#if _DEBUG
395
179k
  m_currArea = m_partStack.back().parts[0];
396
179k
#endif
397
398
179k
  if ((split == TU_MAX_TR_SPLIT) || (split == TU_1D_HORZ_SPLIT) || (split == TU_1D_VERT_SPLIT))
399
20.7k
  {
400
20.7k
    currTrDepth++;
401
20.7k
  }
402
159k
  else if( split >= SBT_VER_HALF_POS0_SPLIT && split <= SBT_HOR_QUAD_POS1_SPLIT )
403
0
  {
404
0
    currTrDepth++;
405
0
  }
406
159k
  else
407
159k
  {
408
159k
    currTrDepth = 0;
409
159k
  }
410
411
179k
  if( split == CU_HORZ_SPLIT || split == CU_VERT_SPLIT || split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT )
412
107k
  {
413
107k
    currBtDepth++;
414
107k
    if( isImplicit ) currImplicitBtDepth++;
415
107k
    currMtDepth++;
416
417
107k
    if( split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT )
418
426
    {
419
      // first and last part of triple split are equivalent to double bt split
420
426
      currBtDepth++;
421
426
      currSubdiv++;
422
426
    }
423
107k
    m_partStack.back().canQtSplit = canQtSplit;
424
107k
  }
425
72.8k
  else if( split == CU_QUAD_SPLIT )
426
52.0k
  {
427
52.0k
    CHECK( currBtDepth > 0, "Cannot split a non-square area other than with a binary split" );
428
52.0k
    CHECK( currMtDepth > 0, "Cannot split a non-square area other than with a binary split" );
429
52.0k
    currMtDepth = 0;
430
52.0k
    currBtDepth = 0;
431
52.0k
    currQtDepth++;
432
52.0k
    currSubdiv++;
433
52.0k
  }
434
435
18.4E
  qgEnable       &= (currSubdiv <= (cs.slice->isIntra() ? cs.slice->picHeader->cuQpDeltaSubdivIntra : cs.slice->picHeader->cuQpDeltaSubdivInter ));
436
18.4E
  qgChromaEnable &= (currSubdiv <= (cs.slice->isIntra() ? cs.slice->picHeader->cuChromaQpOffsetSubdivIntra : cs.slice->picHeader->cuChromaQpOffsetSubdivInter ));
437
179k
  m_partStack.back().qgEnable       = qgEnable;
438
179k
  m_partStack.back().qgChromaEnable = qgChromaEnable;
439
179k
  if (qgEnable)
440
7.92k
    currQgPos = currArea().lumaPos();
441
179k
  if (qgChromaEnable)
442
0
    currQgChromaPos = currArea().chromaPos();
443
179k
}
444
445
void Partitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv )
446
2.28M
{
447
2.28M
  const PartSplit implicitSplit = m_partStack.back().checkdIfImplicit ? m_partStack.back().implicitSplit : getImplicitSplit( cs );
448
449
2.28M
  canNo = canQt = canBh = canTh = canBv = canTv = true;
450
2.28M
  bool canBtt = currMtDepth < (maxBTD + currImplicitBtDepth);
451
452
  // the minimal and maximal sizes are given in luma samples
453
2.28M
  const CompArea&  area  = currArea().Y();
454
2.28M
  const CompArea  *areaC = (chType == CH_C) ? &(currArea().Cb()) : nullptr;
455
2.28M
        PartLevel& level = m_partStack.back();
456
457
2.28M
  const PartSplit lastSplit = level.split;
458
2.28M
  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.28M
  if( lastSplit != CTU_LEVEL && lastSplit != CU_QUAD_SPLIT ) canQt = false;
462
  // minQtSize is in luma samples unit
463
2.28M
  const unsigned minQTThreshold = minQtSize >> ((area.chromaFormat == CHROMA_400) ? 0 : ((int) getChannelTypeScaleX(CH_C, area.chromaFormat) - (int) getChannelTypeScaleY(CH_C, area.chromaFormat)));
464
2.28M
  if( area.width <= minQTThreshold )                         canQt = false;
465
2.28M
  if( areaC && areaC->width <= MIN_DUALTREE_CHROMA_WIDTH ) canQt = false;
466
2.28M
  if( treeType == TREE_C )
467
0
  {
468
0
    canQt = canBh = canTh = canBv = canTv = false;
469
0
    return;
470
0
  }
471
2.28M
  if( implicitSplit != CU_DONT_SPLIT )
472
850k
  {
473
850k
    canNo = canTh = canTv = false;
474
475
850k
    canBh = implicitSplit == CU_HORZ_SPLIT;
476
850k
    canBv = implicitSplit == CU_VERT_SPLIT;
477
850k
    if (areaC && areaC->width == 4) canBv = false;
478
850k
    if( !canBh && !canBv && !canQt ) canQt = true;
479
850k
    return;
480
850k
  }
481
482
1.43M
  if( ( lastSplit == CU_TRIH_SPLIT || lastSplit == CU_TRIV_SPLIT ) && currPartIdx() == 1 )
483
4.76k
  {
484
4.76k
    canBh = parlSplit != CU_HORZ_SPLIT;
485
4.76k
    canBv = parlSplit != CU_VERT_SPLIT;
486
4.76k
  }
487
488
1.43M
  if( canBtt && ( area.width <= minTSize && area.height <= minTSize ) )
489
0
  {
490
0
    canBtt = false;
491
0
  }
492
1.43M
  if( canBtt && ( area.width > maxBtSize || area.height > maxBtSize )
493
94.6k
      && ( ( area.width > maxTtSize || area.height > maxTtSize ) ) )
494
94.6k
  {
495
94.6k
    canBtt = false;
496
94.6k
  }
497
498
1.43M
  if( !canBtt )
499
321k
  {
500
321k
    canBh = canTh = canBv = canTv = false;
501
502
321k
    return;
503
321k
  }
504
505
1.10M
  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.10M
  if( area.height <= minTSize )                            canBh = false;
512
1.10M
  if( area.width > MAX_TB_SIZEY && area.height <= MAX_TB_SIZEY ) canBh = false;
513
1.10M
  if( areaC && areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE )     canBh = false;
514
1.10M
  if( area.width <= minTSize )                              canBv = false;
515
1.10M
  if( area.width <= MAX_TB_SIZEY && area.height > MAX_TB_SIZEY ) canBv = false;
516
1.10M
  if (areaC && (areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE || areaC->width == 4))     canBv = false;
517
1.10M
  if( modeType == MODE_TYPE_INTER && area.width * area.height == 32 )  canBv = canBh = false;
518
1.10M
  if( area.height <= 2 * minTSize || area.height > maxTtSize || area.width > maxTtSize )
519
462k
                                                                                       canTh = false;
520
1.10M
  if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY )  canTh = false;
521
1.10M
  if( areaC && areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE*2 )     canTh = false;
522
1.10M
  if( area.width <= 2 * minTSize || area.width > maxTtSize || area.height > maxTtSize )
523
455k
                                                                                       canTv = false;
524
1.10M
  if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY )  canTv = false;
525
1.10M
  if (areaC && (areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE * 2 || areaC->width == 8))     canTv = false;
526
1.10M
  if( modeType == MODE_TYPE_INTER && area.width * area.height == 64 )  canTv = canTh = false;
527
1.10M
}
528
529
bool Partitioner::canSplit( const PartSplit split, const CodingStructure &cs )
530
1.83M
{
531
1.83M
  const CompArea area       = currArea().Y();
532
1.83M
  const unsigned maxTrSize  = cs.sps->getMaxTbSize();
533
534
1.83M
  bool canNo, canQt, canBh, canTh, canBv, canTv;
535
536
1.83M
  canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv );
537
538
1.83M
  switch( split )
539
1.83M
  {
540
0
  case CTU_LEVEL:
541
0
    THROW( "Checking if top level split is possible" );
542
0
    return true;
543
0
    break;
544
264k
  case TU_MAX_TR_SPLIT:
545
264k
    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
386k
  case CU_QUAD_SPLIT:
558
386k
    return canQt;
559
79.1k
  case CU_DONT_SPLIT:
560
79.1k
    return canNo;
561
395k
  case CU_HORZ_SPLIT:
562
395k
    return canBh;
563
395k
  case CU_VERT_SPLIT:
564
395k
    return canBv;
565
160k
  case CU_TRIH_SPLIT:
566
160k
    return canTh;
567
153k
  case CU_TRIV_SPLIT:
568
153k
    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.83M
  }
579
580
0
  return true;
581
1.83M
}
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
179k
{
609
179k
  return split == getImplicitSplit( cs );
610
179k
}
611
612
PartSplit Partitioner::getImplicitSplit( const CodingStructure &cs )
613
929k
{
614
929k
  if( m_partStack.back().checkdIfImplicit )
615
628k
  {
616
628k
    return m_partStack.back().implicitSplit;
617
628k
  }
618
619
301k
  PartSplit split = CU_DONT_SPLIT;
620
621
301k
  if( split == CU_DONT_SPLIT )
622
301k
  {
623
301k
    const bool isBlInPic = cs.picture->Y().contains( currArea().Y().bottomLeft() );
624
301k
    const bool isTrInPic = cs.picture->Y().contains( currArea().Y().topRight() );
625
626
301k
    const CompArea& area      = currArea().Y();
627
301k
    const bool isBtAllowed    = area.width <= maxBtSize && area.height <= maxBtSize && currMtDepth < (maxBTD + currImplicitBtDepth);
628
    // minQtSize is in luma samples unit
629
301k
    const unsigned minQTThreshold = minQtSize >> ((area.chromaFormat == CHROMA_400) ? 0 : ((int) getChannelTypeScaleX(CH_C, area.chromaFormat) - (int) getChannelTypeScaleY(CH_C, area.chromaFormat)));
630
301k
    const bool isQtAllowed    = area.width > minQTThreshold && currBtDepth == 0;
631
632
301k
    if( !isBlInPic && !isTrInPic && isQtAllowed )
633
20.7k
    {
634
20.7k
      split = CU_QUAD_SPLIT;
635
20.7k
    }
636
280k
    else if( !isBlInPic && isBtAllowed && area.width <= MAX_TB_SIZEY )
637
42.9k
    {
638
42.9k
      split = CU_HORZ_SPLIT;
639
42.9k
    }
640
237k
    else if( !isTrInPic && isBtAllowed && area.height <= MAX_TB_SIZEY )
641
47.0k
    {
642
47.0k
      split = CU_VERT_SPLIT;
643
47.0k
    }
644
190k
    else if( !isBlInPic || !isTrInPic )
645
23.6k
    {
646
23.6k
      split = CU_QUAD_SPLIT;
647
23.6k
    }
648
301k
    if (CS::isDualITree(cs) && (currArea().Y().width > 64 || currArea().Y().height > 64))
649
22.6k
    {
650
22.6k
      split = CU_QUAD_SPLIT;
651
22.6k
    }
652
301k
    if( (!isBlInPic || !isTrInPic) && split == CU_DONT_SPLIT )
653
0
    {
654
0
      split = CU_QUAD_SPLIT;
655
0
    }
656
301k
  }
657
658
301k
  m_partStack.back().checkdIfImplicit = true;
659
301k
  m_partStack.back().isImplicit = split != CU_DONT_SPLIT;
660
301k
  m_partStack.back().implicitSplit = split;
661
662
301k
  return split;
663
929k
}
664
665
void Partitioner::exitCurrSplit()
666
179k
{
667
179k
  const PartSplit currSplit = m_partStack.back().split;
668
179k
  const int       currIndex = m_partStack.back().idx;
669
179k
  const int       numParts  = m_partStack.back().numParts;
670
671
179k
  m_partStack.pop_back();
672
179k
  m_partBufIdx -= numParts;
673
674
179k
  CHECK( currDepth == 0, "depth is '0', although a split was performed" );
675
179k
  currDepth--;
676
179k
  currSubdiv--;
677
179k
  if( currQgEnable() )
678
36.5k
    currQgPos = currArea().lumaPos();
679
179k
  if( currArea().chromaFormat != CHROMA_400 && currQgChromaEnable() )
680
22.6k
    currQgChromaPos = currArea().chromaPos();
681
179k
#if _DEBUG
682
179k
  m_currArea = m_partStack.back().parts[m_partStack.back().idx];
683
179k
#endif
684
685
179k
  if( currSplit == CU_HORZ_SPLIT || currSplit == CU_VERT_SPLIT || currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT )
686
107k
  {
687
107k
    CHECK( !m_partStack.back().checkdIfImplicit, "Didn't check if the current split is implicit" );
688
107k
    CHECK( currBtDepth == 0, "BT depth is '0', athough a BT split was performed" );
689
107k
    CHECK( currMtDepth == 0, "MT depth is '0', athough a BT split was performed" );
690
107k
    currMtDepth--;
691
107k
    if( m_partStack.back().isImplicit ) currImplicitBtDepth--;
692
107k
    currBtDepth--;
693
107k
    if( ( currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT ) && currIndex != 1 )
694
426
    {
695
426
      CHECK( currBtDepth == 0, "BT depth is '0', athough a TT split was performed" );
696
426
      currBtDepth--;
697
426
      currSubdiv--;
698
426
    }
699
107k
  }
700
72.8k
  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
72.8k
  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
72.8k
  else if ((currSplit == TU_1D_HORZ_SPLIT) || (currSplit == TU_1D_VERT_SPLIT))
711
20.7k
  {
712
20.7k
    CHECK(currTrDepth == 0, "TR depth is '0', although a TU split was performed");
713
20.7k
    currTrDepth--;
714
20.7k
  }
715
52.0k
  else
716
52.0k
  {
717
52.0k
    CHECK( currTrDepth > 0, "RQT found with QTBT partitioner" );
718
719
52.0k
    CHECK( currQtDepth == 0, "QT depth is '0', although a QT split was performed" );
720
52.0k
    currQtDepth--;
721
52.0k
    currSubdiv--;
722
52.0k
  }
723
179k
}
724
725
bool Partitioner::nextPart( const CodingStructure &cs, bool autoPop /*= false*/ )
726
449k
{
727
449k
  const Position& prevPos = currArea().blocks[chType].pos();
728
729
449k
  unsigned currIdx = ++m_partStack.back().idx;
730
731
449k
  m_partStack.back().checkdIfImplicit = false;
732
449k
  m_partStack.back().isImplicit = false;
733
734
449k
  if( currIdx == 1 )
735
165k
  {
736
165k
    const CodingUnit* prevCU = cs.getCU( prevPos, chType, treeType );
737
18.4E
    m_partStack.back().firstSubPartSplit = prevCU ? CU::getSplitAtDepth( *prevCU, currDepth ) : CU_DONT_SPLIT;
738
165k
  }
739
740
449k
  if( currIdx < m_partStack.back().numParts )
741
283k
  {
742
283k
    if( m_partStack.back().split == CU_TRIH_SPLIT || m_partStack.back().split == CU_TRIV_SPLIT )
743
852
    {
744
      // adapt the current bt depth
745
852
      if( currIdx == 1 ) currBtDepth--;
746
426
      else               currBtDepth++;
747
852
      if( currIdx == 1 ) currSubdiv--;
748
426
      else               currSubdiv++;
749
852
    }
750
283k
  if( currQgEnable() )
751
23.7k
    currQgPos = currArea().lumaPos();
752
283k
  if( currQgChromaEnable() )
753
0
    currQgChromaPos = currArea().chromaPos();
754
283k
#if _DEBUG
755
283k
    m_currArea = m_partStack.back().parts[currIdx];
756
283k
#endif
757
283k
    return true;
758
283k
  }
759
165k
  else
760
165k
  {
761
165k
    if( autoPop ) exitCurrSplit();
762
165k
    return false;
763
165k
  }
764
449k
}
765
766
bool Partitioner::hasNextPart()
767
122k
{
768
122k
  return ( ( m_partStack.back().idx + 1 ) < m_partStack.back().numParts );
769
122k
}
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
159k
{
777
159k
  const PartSplit splitType = _splitType;
778
779
159k
  if( splitType == CU_QUAD_SPLIT )
780
52.0k
  {
781
52.0k
    Partitioning& sub = dst;
782
783
260k
    for( uint32_t i = 0; i < 4; i++ )
784
208k
    {
785
208k
      sub[i] = cuArea;
786
787
208k
      for( auto &blk : sub[i].blocks )
788
624k
      {
789
624k
        blk.height >>= 1;
790
624k
        blk.width  >>= 1;
791
624k
        if( i >= 2 ) blk.y += blk.height;
792
624k
        if( i &  1 ) blk.x += blk.width;
793
624k
      }
794
208k
    }
795
796
52.0k
    return 4;
797
52.0k
  }
798
107k
  else if( splitType == CU_HORZ_SPLIT )
799
51.9k
  {
800
51.9k
    Partitioning& sub = dst;
801
802
155k
    for (uint32_t i = 0; i < 2; i++)
803
103k
    {
804
103k
      sub[i] = cuArea;
805
806
103k
      for (auto &blk : sub[i].blocks)
807
311k
      {
808
311k
        blk.height >>= 1;
809
311k
        if (i == 1) blk.y += blk.height;
810
311k
      }
811
103k
    }
812
813
51.9k
    return 2;
814
51.9k
  }
815
55.2k
  else if( splitType == CU_VERT_SPLIT )
816
54.7k
  {
817
54.7k
    Partitioning& sub = dst;
818
819
164k
    for( uint32_t i = 0; i < 2; i++ )
820
109k
    {
821
109k
      sub[i] = cuArea;
822
823
109k
      for( auto &blk : sub[i].blocks )
824
328k
      {
825
328k
        blk.width >>= 1;
826
328k
        if( i == 1 ) blk.x += blk.width;
827
328k
      }
828
109k
    }
829
830
54.7k
    return 2;
831
54.7k
  }
832
421
  else if( splitType == CU_TRIH_SPLIT )
833
369
  {
834
369
    Partitioning& sub = dst;
835
836
1.47k
    for( int i = 0; i < 3; i++ )
837
1.10k
    {
838
1.10k
      sub[i] = cuArea;
839
840
1.10k
      for( auto &blk : sub[i].blocks )
841
3.32k
      {
842
3.32k
        blk.height >>= 1;
843
3.32k
        if( ( i + 1 ) & 1 ) blk.height >>= 1;
844
3.32k
        if( i == 1 )        blk.y       +=     blk.height / 2;
845
3.32k
        if( i == 2 )        blk.y       += 3 * blk.height;
846
3.32k
      }
847
1.10k
    }
848
849
369
    return 3;
850
369
  }
851
52
  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
159k
}
876
877
int PartitionerImpl::getTUIntraSubPartitions( Partitioning& sub, const UnitArea &tuArea, const CodingStructure &cs, const PartSplit splitType, const TreeType treeType )
878
20.7k
{
879
20.7k
  uint32_t nPartitions;
880
20.7k
  uint32_t splitDimensionSize = CU::getISPSplitDim( tuArea.lumaSize().width, tuArea.lumaSize().height, splitType );
881
882
20.7k
  bool isDualTree = CS::isDualITree( cs ) || treeType != TREE_D;
883
884
20.7k
  if( splitType == TU_1D_HORZ_SPLIT )
885
9.91k
  {
886
9.91k
    nPartitions = tuArea.lumaSize().height >> Log2(splitDimensionSize);
887
888
49.5k
    for( uint32_t i = 0; i < nPartitions; i++ )
889
39.6k
    {
890
39.6k
      sub[i] = tuArea;
891
39.6k
      CompArea& blkY = sub[i].blocks[COMP_Y];
892
893
39.6k
      blkY.height = splitDimensionSize;
894
39.6k
      blkY.y = i > 0 ? sub[i - 1].blocks[COMP_Y].y + splitDimensionSize : blkY.y;
895
896
39.6k
      CHECK( sub[i].lumaSize().height < 1, "the cs split causes the block to be smaller than the minimal TU size" );
897
39.6k
    }
898
9.91k
  }
899
10.8k
  else if( splitType == TU_1D_VERT_SPLIT )
900
10.8k
  {
901
10.8k
    nPartitions = tuArea.lumaSize().width >> Log2(splitDimensionSize);
902
903
54.1k
    for( uint32_t i = 0; i < nPartitions; i++ )
904
43.3k
    {
905
43.3k
      sub[i] = tuArea;
906
43.3k
      CompArea& blkY = sub[i].blocks[COMP_Y];
907
908
43.3k
      blkY.width = splitDimensionSize;
909
43.3k
      blkY.x = i > 0 ? sub[i - 1].blocks[COMP_Y].x + splitDimensionSize : blkY.x;
910
43.3k
      CHECK( sub[i].lumaSize().width < 1, "the split causes the block to be smaller than the minimal TU size" );
911
43.3k
    }
912
10.8k
  }
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
20.7k
  uint32_t partitionsWithoutChroma = (cs.area.chromaFormat == CHROMA_400) ? 0 : (isDualTree ? nPartitions : nPartitions - 1);
919
103k
  for( uint32_t i = 0; i < partitionsWithoutChroma; i++ )
920
82.9k
  {
921
82.9k
    CompArea& blkCb = sub[i].blocks[COMP_Cb];
922
82.9k
    CompArea& blkCr = sub[i].blocks[COMP_Cr];
923
82.9k
    blkCb = CompArea();
924
82.9k
    blkCr = CompArea();
925
82.9k
  }
926
927
20.7k
  return nPartitions;
928
20.7k
}
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