Coverage Report

Created: 2026-10-28 06:18

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