Coverage Report

Created: 2026-09-02 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/EncoderLib/EncSlice.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     EncSlice.cpp
45
    \brief    slice encoder class
46
*/
47
48
#include "EncSlice.h"
49
#include "EncStage.h"
50
#include "EncLib.h"
51
#include "EncPicture.h"
52
#include "BitAllocation.h"
53
#include "CommonLib/UnitTools.h"
54
#include "CommonLib/Picture.h"
55
#include "CommonLib/TimeProfiler.h"
56
#include "CommonLib/dtrace_codingstruct.h"
57
#include "Utilities/NoMallocThreadPool.h"
58
59
#include <math.h>
60
#include "vvenc/vvencCfg.h"
61
62
//! \ingroup EncoderLib
63
//! \{
64
65
namespace vvenc {
66
67
#ifdef TRACE_ENABLE_ITT
68
static const __itt_domain* itt_domain_encode              = __itt_domain_create( "Encode" );
69
static const __itt_string_handle* itt_handle_ctuEncode    = __itt_string_handle_create( "Encode_CTU" );
70
static const __itt_string_handle* itt_handle_rspLfVer     = __itt_string_handle_create( "RspLfVer_CTU" );
71
static const __itt_string_handle* itt_handle_lfHor        = __itt_string_handle_create( "LfHor_CTU" );
72
static const __itt_string_handle* itt_handle_sao          = __itt_string_handle_create( "SAO_CTU" );
73
static const __itt_string_handle* itt_handle_alf_stat     = __itt_string_handle_create( "ALF_CTU_STAT" );
74
static const __itt_string_handle* itt_handle_alf_derive   = __itt_string_handle_create( "ALF_DERIVE" );
75
static const __itt_string_handle* itt_handle_alf_recon    = __itt_string_handle_create( "ALF_RECONSTRUCT" );
76
static const __itt_string_handle* itt_handle_ccalf_stat   = __itt_string_handle_create( "CCALF_CTU_STAT" );
77
static const __itt_string_handle* itt_handle_ccalf_derive = __itt_string_handle_create( "CCALF_DERIVE" );
78
static const __itt_string_handle* itt_handle_ccalf_recon  = __itt_string_handle_create( "CCALF_RECONSTRUCT" );
79
#endif
80
81
void setArbitraryWppPattern( const PreCalcValues& pcv, std::vector<int>& ctuAddrMap, int stepX = 1 )
82
4.58k
{
83
4.58k
  ctuAddrMap.resize( pcv.sizeInCtus, 0 );
84
4.58k
  std::vector<int> x_in_line( pcv.heightInCtus, 0 );
85
4.58k
  int x = 0, y = 0, addr = 0;
86
4.58k
  int y_top = 0;
87
4.58k
  const int step = stepX; // number of CTUs in x-direction to scan 
88
4.58k
  ctuAddrMap[addr++] = x++; // first entry (can be omitted)
89
10.8k
  while( addr < pcv.sizeInCtus )
90
7.08k
  {
91
    // fill entries in x-direction
92
7.08k
    int x1 = x;
93
16.8k
    while( x < std::min(x1 + step, (int)pcv.widthInCtus) )
94
9.77k
    {
95
      // general WPP condition (top-right CTU availability)
96
9.77k
      if( y > 0 && !( x_in_line[y - 1] - x >= 2 ) && x != pcv.widthInCtus - 1 )
97
0
        break;
98
9.77k
      ctuAddrMap[addr++] = y*pcv.widthInCtus + x;
99
9.77k
      x++;
100
9.77k
    }
101
7.08k
    x_in_line[y] = x;
102
        
103
7.08k
    y += 1;
104
105
7.08k
    if( y >= pcv.heightInCtus )
106
3.55k
    {
107
      // go up
108
3.55k
      if( x_in_line[y_top] >= pcv.widthInCtus )
109
3.55k
      {
110
3.55k
        y_top++;
111
3.55k
        if( y_top >= pcv.heightInCtus )
112
796
        {
113
          // done
114
796
          break;
115
796
        }
116
3.55k
      }
117
2.75k
      y = y_top;
118
2.75k
    }
119
6.29k
    x = x_in_line[y];
120
121
6.29k
    CHECK( y >= pcv.heightInCtus, "Height in CTUs is exceeded" );
122
6.29k
  }
123
4.58k
}
124
125
struct TileLineEncRsrc
126
{
127
  BitEstimator            m_BitEstimator;
128
  CABACWriter             m_CABACEstimator;
129
  BitEstimator            m_SaoBitEstimator;
130
  CABACWriter             m_SaoCABACEstimator;
131
  BitEstimator            m_AlfBitEstimator;
132
  CABACWriter             m_AlfCABACEstimator;
133
  ReuseUniMv              m_ReuseUniMv;
134
  BlkUniMvInfoBuffer      m_BlkUniMvInfoBuffer;
135
  AffineProfList          m_AffineProfList;
136
  IbcBvCand               m_CachedBvs;
137
  EncSampleAdaptiveOffset m_encSao;
138
  int                     m_prevQp[ MAX_NUM_CH ];
139
8.12k
  TileLineEncRsrc( const VVEncCfg& encCfg ) : m_CABACEstimator( m_BitEstimator ), m_SaoCABACEstimator( m_SaoBitEstimator ), m_AlfCABACEstimator( m_AlfBitEstimator ) { m_AffineProfList.init( ! encCfg.m_picReordering ); }
140
};
141
142
struct PerThreadRsrc
143
{
144
  CtxCache  m_CtxCache;
145
  EncCu     m_encCu;
146
  PelStorage m_alfTempCtuBuf;
147
};
148
149
struct CtuEncParam
150
{
151
  Picture*  pic;
152
  EncSlice* encSlice;
153
  int       ctuRsAddr;
154
  int       ctuPosX;
155
  int       ctuPosY;
156
  UnitArea  ctuArea;
157
  int       tileLineResIdx;
158
159
14.3k
  CtuEncParam() : pic( nullptr ), encSlice( nullptr ), ctuRsAddr( 0 ), ctuPosX( 0 ), ctuPosY( 0 ), ctuArea(), tileLineResIdx( 0 ) {}
160
  CtuEncParam( Picture* _p, EncSlice* _s, const int _r, const int _x, const int _y, const int _tileLineResIdx )
161
    : pic( _p )
162
    , encSlice( _s )
163
    , ctuRsAddr( _r )
164
    , ctuPosX( _x )
165
    , ctuPosY( _y )
166
    , ctuArea( pic->chromaFormat, pic->slices[0]->pps->pcv->getCtuArea( _x, _y ) )
167
0
    , tileLineResIdx( _tileLineResIdx ) {}
168
};
169
170
// ====================================================================================================================
171
// Constructor / destructor / create / destroy
172
// ====================================================================================================================
173
174
EncSlice::EncSlice()
175
4.58k
  : m_pcEncCfg           ( nullptr)
176
4.58k
  , m_threadPool         ( nullptr )
177
4.58k
  , m_ctuTasksDoneCounter( nullptr )
178
4.58k
  , m_ctuEncDelay        ( 1 )
179
4.58k
  , m_pLoopFilter        ( nullptr )
180
4.58k
  , m_pALF               ( nullptr )
181
4.58k
  , m_pcRateCtrl         ( nullptr )
182
4.58k
  , m_CABACWriter        ( m_BinEncoder )
183
4.58k
  , m_encCABACTableIdx   ( VVENC_I_SLICE )
184
4.58k
{
185
4.58k
}
186
187
188
EncSlice::~EncSlice()
189
4.58k
{
190
4.58k
  for( auto* lnRsc : m_TileLineEncRsrc )
191
8.12k
  {
192
8.12k
    delete lnRsc;
193
8.12k
  }
194
4.58k
  m_TileLineEncRsrc.clear();
195
196
4.58k
  for( auto* taskRsc: m_ThreadRsrc )
197
18.3k
  {
198
18.3k
    taskRsc->m_alfTempCtuBuf.destroy();
199
18.3k
    delete taskRsc;
200
18.3k
  }
201
4.58k
  m_ThreadRsrc.clear();
202
203
4.58k
  m_saoReconParams.clear();
204
205
18.9k
  for( int i = 0; i < m_saoStatData.size(); i++ )
206
14.3k
  {
207
57.4k
    for( int compIdx = 0; compIdx < MAX_NUM_COMP; compIdx++ )
208
43.0k
    {
209
43.0k
      delete[] m_saoStatData[ i ][ compIdx ];
210
43.0k
    }
211
14.3k
    delete[] m_saoStatData[ i ];
212
14.3k
  }
213
4.58k
  m_saoStatData.clear();
214
4.58k
}
215
216
void EncSlice::init( const VVEncCfg& encCfg,
217
                     const SPS& sps,
218
                     const PPS& pps,
219
                     std::vector<int>* const globalCtuQpVector,
220
                     LoopFilter& loopFilter,
221
                     EncAdaptiveLoopFilter& alf,
222
                     RateCtrl& rateCtrl,
223
                     NoMallocThreadPool* threadPool,
224
                     WaitCounter* ctuTasksDoneCounter )
225
4.58k
{
226
4.58k
  m_pcEncCfg            = &encCfg;
227
4.58k
  m_pLoopFilter         = &loopFilter;
228
4.58k
  m_pALF                = &alf;
229
4.58k
  m_pcRateCtrl          = &rateCtrl;
230
4.58k
  m_threadPool          = threadPool;
231
4.58k
  m_ctuTasksDoneCounter = ctuTasksDoneCounter;
232
4.58k
  m_syncPicCtx.resize( encCfg.m_entropyCodingSyncEnabled ? pps.getNumTileLineIds() : 0 );
233
234
  
235
4.58k
  const int maxCntRscr = ( encCfg.m_numThreads > 0 ) ? pps.getNumTileLineIds() : 1;
236
4.58k
  const int maxCtuEnc  = ( encCfg.m_numThreads > 0 && threadPool ) ? threadPool->numThreads() : 1;
237
238
4.58k
  m_ThreadRsrc.resize( maxCtuEnc,  nullptr );
239
4.58k
  m_TileLineEncRsrc.resize( maxCntRscr, nullptr );
240
241
4.58k
  for( PerThreadRsrc*& taskRsc : m_ThreadRsrc )
242
18.3k
  {
243
18.3k
    taskRsc = new PerThreadRsrc();
244
18.3k
    taskRsc->m_encCu.init( encCfg,
245
18.3k
                           sps,
246
18.3k
                           globalCtuQpVector,
247
18.3k
                           m_syncPicCtx.data(),
248
18.3k
                           &rateCtrl );
249
18.3k
    taskRsc->m_alfTempCtuBuf.create( pps.pcv->chrFormat, Area( 0, 0, pps.pcv->maxCUSize + (MAX_ALF_PADDING_SIZE << 1), pps.pcv->maxCUSize + (MAX_ALF_PADDING_SIZE << 1) ), pps.pcv->maxCUSize, MAX_ALF_PADDING_SIZE, 0, false );
250
18.3k
  }
251
252
4.58k
  for( TileLineEncRsrc*& lnRsc : m_TileLineEncRsrc )
253
8.12k
  {
254
8.12k
    lnRsc = new TileLineEncRsrc( encCfg );
255
8.12k
    if( sps.saoEnabled )
256
8.12k
    {
257
8.12k
      lnRsc->m_encSao.init( encCfg );
258
8.12k
    }
259
8.12k
  }
260
261
4.58k
  const int sizeInCtus = pps.pcv->sizeInCtus;
262
4.58k
  m_processStates = std::vector<ProcessCtuState>( sizeInCtus );
263
4.58k
  m_saoReconParams.resize( sizeInCtus );
264
265
4.58k
  ::memset( m_saoDisabledRate, 0, sizeof( m_saoDisabledRate ) );
266
267
  // sao statistics
268
4.58k
  if( encCfg.m_bUseSAO )
269
4.58k
  {
270
4.58k
    m_saoStatData.resize( sizeInCtus );
271
18.9k
    for( int i = 0; i < sizeInCtus; i++ )
272
14.3k
    {
273
14.3k
      m_saoStatData[ i ] = new SAOStatData*[ MAX_NUM_COMP ];
274
57.4k
      for( int compIdx = 0; compIdx < MAX_NUM_COMP; compIdx++ )
275
43.0k
      {
276
43.0k
        m_saoStatData[ i ][ compIdx ] = new SAOStatData[ NUM_SAO_NEW_TYPES ];
277
43.0k
      }
278
14.3k
    }
279
4.58k
  }
280
4.58k
  ctuEncParams.resize( sizeInCtus );
281
4.58k
  setArbitraryWppPattern( *pps.pcv, m_ctuAddrMap, 3 );
282
283
4.58k
  const unsigned asuHeightInCtus = m_pALF->getAsuHeightInCtus();
284
4.58k
  const unsigned numDeriveLines  = encCfg.m_ifpLines ? 
285
4.58k
    std::min( ((encCfg.m_ifpLines & (~(asuHeightInCtus - 1))) + asuHeightInCtus), pps.pcv->heightInCtus ) : pps.pcv->heightInCtus;
286
4.58k
  m_alfDeriveCtu  = numDeriveLines * pps.pcv->widthInCtus - 1;
287
4.58k
  m_ccalfDeriveCtu = encCfg.m_ifpLines ? pps.pcv->widthInCtus * std::min((unsigned)encCfg.m_ifpLines + 1, pps.pcv->heightInCtus) - 1: pps.pcv->sizeInCtus - 1;
288
4.58k
}
289
290
291
void EncSlice::initPic( Picture* pic )
292
1.14k
{
293
1.14k
  Slice* slice = pic->cs->slice;
294
295
1.14k
  if( slice->pps->numTileCols * slice->pps->numTileRows > 1 )
296
0
  {
297
0
    slice->sliceMap = slice->pps->sliceMap[0];
298
0
  }
299
1.14k
  else
300
1.14k
  {
301
1.14k
    slice->sliceMap.addCtusToSlice( 0, pic->cs->pcv->widthInCtus, 0, pic->cs->pcv->heightInCtus, pic->cs->pcv->widthInCtus);
302
1.14k
  }
303
304
  // this ensures that independently encoded bitstream chunks can be combined to bit-equal
305
1.14k
  const SliceType cabacTableIdx = ! slice->pps->cabacInitPresent || slice->pendingRasInit ? slice->sliceType : m_encCABACTableIdx;
306
1.14k
  slice->encCABACTableIdx = cabacTableIdx;
307
308
  // set QP and lambda values
309
1.14k
  xInitSliceLambdaQP( slice );
310
311
1.14k
  for( auto* thrRsc : m_ThreadRsrc )
312
4.58k
  {
313
4.58k
    thrRsc->m_encCu.initPic( pic );
314
4.58k
  }
315
316
1.14k
  for( auto* lnRsc : m_TileLineEncRsrc )
317
2.03k
  {
318
2.03k
    lnRsc->m_ReuseUniMv.resetReusedUniMvs();
319
2.03k
  }
320
321
1.14k
  m_ctuEncDelay = 1;
322
1.14k
  if( pic->useIBC )
323
1.14k
  {
324
    // IBC needs unfiltered samples up to max IBC search range
325
    // therefore ensure that numCtuDelayLUT CTU's have been enocded first
326
    // assuming IBC localSearchRangeX / Y = 128
327
1.14k
    const int numCtuDelayLUT[ 3 ] = { 15, 3, 1 };
328
1.14k
    CHECK( pic->cs->pcv->maxCUSizeLog2 < 5 || pic->cs->pcv->maxCUSizeLog2 > 7, "invalid max CTUSize" );
329
1.14k
    m_ctuEncDelay = numCtuDelayLUT[ pic->cs->pcv->maxCUSizeLog2 - 5 ];
330
1.14k
  }
331
1.14k
}
332
333
334
335
void EncSlice::xInitSliceLambdaQP( Slice* slice )
336
1.14k
{
337
  // pre-compute lambda and QP
338
1.14k
  const bool rcp = (m_pcEncCfg->m_RCTargetBitrate > 0 && slice->pic->picInitialQP >= 0); // 2nd pass
339
1.14k
  int  iQP = Clip3 (-slice->sps->qpBDOffset[CH_L], MAX_QP, slice->pic->picInitialQP); // RC start QP
340
1.14k
  double dQP     = (rcp ? (double) slice->pic->picInitialQP : xGetQPForPicture (slice));
341
1.14k
  double dLambda = (rcp ? slice->pic->picInitialLambda : xCalculateLambda (slice, slice->TLayer, dQP, dQP, iQP));
342
1.14k
  int sliceChromaQpOffsetIntraOrPeriodic[2] = { m_pcEncCfg->m_sliceChromaQpOffsetIntraOrPeriodic[0], m_pcEncCfg->m_sliceChromaQpOffsetIntraOrPeriodic[1] };
343
1.14k
  const int lookAheadRCCQpOffset = 0;   // was (m_pcEncCfg->m_RCTargetBitrate > 0 && m_pcEncCfg->m_LookAhead && CS::isDualITree (*slice->pic->cs) ? 1 : 0);
344
1.14k
  int cbQP = 0, crQP = 0, cbCrQP = 0;
345
346
1.14k
  if (m_pcEncCfg->m_usePerceptQPA) // adapt sliceChromaQpOffsetIntraOrPeriodic and pic->ctuAdaptedQP
347
1.14k
  {
348
1.14k
    const bool cqp = (slice->isIntra() && !slice->sps->IBC) || (m_pcEncCfg->m_sliceChromaQpOffsetPeriodicity > 0 && (slice->poc % m_pcEncCfg->m_sliceChromaQpOffsetPeriodicity) == 0);
349
1.14k
    const uint32_t startCtuTsAddr    = slice->sliceMap.ctuAddrInSlice[0];
350
1.14k
    const uint32_t boundingCtuTsAddr = slice->pic->cs->pcv->sizeInCtus;
351
352
1.14k
    if ((iQP = BitAllocation::applyQPAdaptationSlice (slice, m_pcEncCfg, iQP, dLambda, &slice->pic->picVA.visAct, // updates pic->picInitialQP
353
1.14k
                                                      *m_ThreadRsrc[0]->m_encCu.getQpPtr(), m_pcRateCtrl->getIntraPQPAStats(),
354
1.14k
                                                      (slice->pps->sliceChromaQpFlag && cqp ? sliceChromaQpOffsetIntraOrPeriodic : nullptr),
355
1.14k
                                                      m_pcRateCtrl->getMinNoiseLevels(), startCtuTsAddr, boundingCtuTsAddr)) >= 0) // QP OK?
356
1.14k
    {
357
1.14k
      dLambda *= pow (2.0, ((double) iQP - dQP) / 3.0); // adjust lambda based on change of slice QP
358
1.14k
    }
359
0
    else iQP = (int) dQP; // revert to unadapted slice QP
360
1.14k
  }
361
0
  else if (rcp)
362
0
  {
363
0
    slice->pic->picInitialQP = -1; // no QPA - unused now
364
0
  }
365
366
1.14k
  if (slice->pps->sliceChromaQpFlag && CS::isDualITree (*slice->pic->cs) && !m_pcEncCfg->m_usePerceptQPA && (m_pcEncCfg->m_sliceChromaQpOffsetPeriodicity == 0))
367
0
  {
368
0
    cbQP = m_pcEncCfg->m_chromaCbQpOffsetDualTree + lookAheadRCCQpOffset; // QP offset for dual-tree
369
0
    crQP = m_pcEncCfg->m_chromaCrQpOffsetDualTree + lookAheadRCCQpOffset;
370
0
    cbCrQP = m_pcEncCfg->m_chromaCbCrQpOffsetDualTree + lookAheadRCCQpOffset;
371
0
  }
372
1.14k
  else if (slice->pps->sliceChromaQpFlag)
373
1.14k
  {
374
1.14k
    const GOPEntry &gopEntry             = *(slice->pic->gopEntry);
375
1.14k
    const bool bUseIntraOrPeriodicOffset = (slice->isIntra() && !slice->sps->IBC) || (m_pcEncCfg->m_sliceChromaQpOffsetPeriodicity > 0 && (slice->poc % m_pcEncCfg->m_sliceChromaQpOffsetPeriodicity) == 0);
376
377
1.14k
    cbQP = (bUseIntraOrPeriodicOffset ? sliceChromaQpOffsetIntraOrPeriodic[0] : gopEntry.m_CbQPoffset) + lookAheadRCCQpOffset;
378
1.14k
    crQP = (bUseIntraOrPeriodicOffset ? sliceChromaQpOffsetIntraOrPeriodic[1] : gopEntry.m_CrQPoffset) + lookAheadRCCQpOffset;
379
1.14k
    cbCrQP = (cbQP + crQP) >> 1; // use floor of average CbCr chroma QP offset for joint-CbCr coding
380
381
1.14k
    cbQP = Clip3 (-12, 12, cbQP + slice->pps->chromaQpOffset[COMP_Cb]) - slice->pps->chromaQpOffset[COMP_Cb];
382
1.14k
    crQP = Clip3 (-12, 12, crQP + slice->pps->chromaQpOffset[COMP_Cr]) - slice->pps->chromaQpOffset[COMP_Cr];
383
1.14k
    cbCrQP = Clip3 (-12, 12, cbCrQP + slice->pps->chromaQpOffset[COMP_JOINT_CbCr]) - slice->pps->chromaQpOffset[COMP_JOINT_CbCr];
384
1.14k
  }
385
386
1.14k
  slice->sliceChromaQpDelta[COMP_Cb] = Clip3 (-12, 12, cbQP);
387
1.14k
  slice->sliceChromaQpDelta[COMP_Cr] = Clip3 (-12, 12, crQP);
388
1.14k
  slice->sliceChromaQpDelta[COMP_JOINT_CbCr] = (slice->sps->jointCbCr ? Clip3 (-12, 12, cbCrQP) : 0);
389
390
1.14k
  for( auto& thrRsc : m_ThreadRsrc )
391
4.58k
  {
392
4.58k
    thrRsc->m_encCu.setUpLambda( *slice, dLambda, iQP, true, true );
393
4.58k
  }
394
395
1.14k
  slice->sliceQp            = iQP;
396
1.14k
  slice->chromaQpAdjEnabled = slice->pps->chromaQpOffsetListLen > 0;
397
1.14k
}
398
399
static const int highTL[6] = { -1, 0, 0, 2, 4, 5 };
400
401
int EncSlice::xGetQPForPicture( const Slice* slice )
402
1.14k
{
403
1.14k
  const int lumaQpBDOffset = slice->sps->qpBDOffset[ CH_L ];
404
1.14k
  int qp;
405
406
1.14k
  if ( m_pcEncCfg->m_costMode == VVENC_COST_LOSSLESS_CODING )
407
0
  {
408
0
    qp = LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP;
409
0
  }
410
1.14k
  else
411
1.14k
  {
412
1.14k
    qp = m_pcEncCfg->m_QP + slice->pic->gopAdaptedQP;
413
414
1.14k
    if (m_pcEncCfg->m_usePerceptQPA)
415
1.14k
    {
416
1.14k
      const int tlayer = slice->pic->gopEntry->m_vtl;
417
418
1.14k
      qp = (slice->isIntra() ? std::min (qp, ((qp - std::min (3, floorLog2 (m_pcEncCfg->m_GOPSize) - 4/*TODO 3 with JVET-AC0149?*/)) * 15 + 3) >> 4) : highTL[tlayer] + ((qp * (16 + std::min (2, tlayer))) >> 4) + 0/*TODO +-1?*/);
419
1.14k
    }
420
0
    else if( slice->isIntra() )
421
0
    {
422
0
      qp += m_pcEncCfg->m_intraQPOffset;
423
0
    }
424
0
    else
425
0
    {
426
0
      if( qp != -lumaQpBDOffset )
427
0
      {
428
0
        const GOPEntry &gopEntry = *(slice->pic->gopEntry);
429
        // adjust QP according to the QP offset for the GOP entry.
430
0
        qp += gopEntry.m_QPOffset;
431
432
        // adjust QP according to QPOffsetModel for the GOP entry.
433
0
        double dqpOffset = qp * gopEntry.m_QPOffsetModelScale + gopEntry.m_QPOffsetModelOffset + 0.5;
434
0
        int qpOffset = (int)floor( Clip3<double>( 0.0, 3.0, dqpOffset ) );
435
0
        qp += qpOffset;
436
0
      }
437
0
    }
438
439
1.14k
    if( m_pcEncCfg->m_blockImportanceMapping && !slice->pic->m_picShared->m_ctuBimQpOffset.empty() )
440
0
    {
441
0
      qp += slice->pic->m_picShared->m_picAuxQpOffset;
442
0
    }
443
1.14k
  }
444
1.14k
  qp = Clip3( -lumaQpBDOffset, MAX_QP, qp );
445
1.14k
  return qp;
446
1.14k
}
447
448
449
double EncSlice::xCalculateLambda( const Slice* slice,
450
                                   const int    depth, // slice GOP hierarchical depth.
451
                                   const double refQP, // initial slice-level QP
452
                                   const double dQP,   // initial double-precision QP
453
                                         int&   iQP )  // returned integer QP.
454
1.14k
{
455
1.14k
  const GOPEntry &gopEntry = *(slice->pic->gopEntry);
456
1.14k
  const int SHIFT_QP       = 12;
457
1.14k
  const int temporalId     = gopEntry.m_temporalId;
458
1.14k
  std::vector<double> intraLambdaModifiers;
459
1.14k
  for ( int i = 0; i < VVENC_MAX_TLAYER; i++ )
460
1.14k
  {
461
1.14k
    if( m_pcEncCfg->m_adIntraLambdaModifier[i] != 0.0 ) intraLambdaModifiers.push_back( m_pcEncCfg->m_adIntraLambdaModifier[i] );
462
1.14k
    else break;
463
1.14k
  }
464
465
1.14k
  int bitdepth_luma_qp_scale = 6
466
1.14k
                               * (slice->sps->bitDepths[ CH_L ] - 8
467
1.14k
                                  - DISTORTION_PRECISION_ADJUSTMENT(slice->sps->bitDepths[ CH_L ]));
468
1.14k
  double qp_temp = dQP + bitdepth_luma_qp_scale - SHIFT_QP;
469
  // Case #1: I or P-slices (key-frame)
470
1.14k
  double dQPFactor = gopEntry.m_QPFactor;
471
1.14k
  if( slice->sliceType == VVENC_I_SLICE )
472
1.14k
  {
473
1.14k
    if (m_pcEncCfg->m_dIntraQpFactor>=0.0 && gopEntry.m_sliceType != 'I')
474
0
    {
475
0
      dQPFactor = m_pcEncCfg->m_dIntraQpFactor;
476
0
    }
477
1.14k
    else
478
1.14k
    {
479
1.14k
      dQPFactor = 0.57;
480
1.14k
      if( ! m_pcEncCfg->m_lambdaFromQPEnable )
481
0
      {
482
0
        const int NumberBFrames = ( m_pcEncCfg->m_GOPSize - 1 );
483
0
        const double dLambda_scale = 1.0 - Clip3( 0.0, 0.5, 0.05 * (double)NumberBFrames );
484
0
        dQPFactor *= dLambda_scale;
485
0
      }
486
1.14k
    }
487
1.14k
  }
488
0
  else if( m_pcEncCfg->m_lambdaFromQPEnable )
489
0
  {
490
0
    dQPFactor=0.57;
491
0
  }
492
493
1.14k
  double dLambda = dQPFactor*pow( 2.0, qp_temp/3.0 );
494
495
1.14k
  if( !(m_pcEncCfg->m_lambdaFromQPEnable) && depth>0 )
496
0
  {
497
0
    double qp_temp_ref = refQP + bitdepth_luma_qp_scale - SHIFT_QP;
498
0
    dLambda *= Clip3(2.00, 4.00, (qp_temp_ref / 6.0));   // (j == B_SLICE && p_cur_frm->layer != 0 )
499
0
  }
500
501
  // if hadamard is used in ME process
502
1.14k
  if ( !m_pcEncCfg->m_bUseHADME && slice->sliceType != VVENC_I_SLICE )
503
0
  {
504
0
    dLambda *= 0.95;
505
0
  }
506
507
1.14k
  double lambdaModifier;
508
1.14k
  if( slice->sliceType != VVENC_I_SLICE || intraLambdaModifiers.empty())
509
1.14k
  {
510
1.14k
    lambdaModifier = m_pcEncCfg->m_adLambdaModifier[ temporalId ];
511
1.14k
  }
512
0
  else
513
0
  {
514
0
    lambdaModifier = intraLambdaModifiers[ (temporalId < intraLambdaModifiers.size()) ? temporalId : (intraLambdaModifiers.size()-1) ];
515
0
  }
516
1.14k
  dLambda *= lambdaModifier;
517
518
1.14k
  iQP = Clip3( -slice->sps->qpBDOffset[ CH_L ], MAX_QP, (int) floor( dQP + 0.5 ) );
519
520
1.14k
  if( m_pcEncCfg->m_DepQuantEnabled )
521
1.14k
  {
522
1.14k
    dLambda *= pow( 2.0, 0.25/3.0 ); // slight lambda adjustment for dependent quantization (due to different slope of quantizer)
523
1.14k
  }
524
525
  // NOTE: the lambda modifiers that are sometimes applied later might be best always applied in here.
526
1.14k
  return dLambda;
527
1.14k
}
528
529
530
// ====================================================================================================================
531
// Public member functions
532
// ====================================================================================================================
533
534
535
/** \param pic   picture class
536
 */
537
void EncSlice::compressSlice( Picture* pic )
538
1.14k
{
539
1.14k
  PROFILER_SCOPE_AND_STAGE( 1, g_timeProfiler, P_COMPRESS_SLICE );
540
1.14k
  CodingStructure& cs         = *pic->cs;
541
1.14k
  Slice* const slice          = cs.slice;
542
1.14k
  uint32_t  startCtuTsAddr    = slice->sliceMap.ctuAddrInSlice[0];
543
1.14k
  uint32_t  boundingCtuTsAddr = pic->cs->pcv->sizeInCtus;
544
545
1.14k
  cs.pcv      = slice->pps->pcv;
546
1.14k
  cs.fracBits = 0;
547
548
1.14k
  if( startCtuTsAddr == 0 )
549
1.14k
  {
550
1.14k
    cs.initStructData( slice->sliceQp );
551
1.14k
  }
552
553
1.14k
  for( auto* thrRsrc : m_ThreadRsrc )
554
4.58k
  {
555
4.58k
    thrRsrc->m_encCu.initSlice( slice );
556
4.58k
  }
557
558
1.14k
  for( auto* lnRsrc : m_TileLineEncRsrc )
559
2.03k
  {
560
2.03k
    lnRsrc->m_CABACEstimator    .initCtxModels( *slice );
561
2.03k
    lnRsrc->m_SaoCABACEstimator .initCtxModels( *slice );
562
2.03k
    lnRsrc->m_AlfCABACEstimator .initCtxModels( *slice );
563
2.03k
    lnRsrc->m_AffineProfList    .resetAffineMVList();
564
2.03k
    lnRsrc->m_BlkUniMvInfoBuffer.resetUniMvList();
565
2.03k
    lnRsrc->m_CachedBvs         .resetIbcBvCand();
566
567
2.03k
    if( slice->sps->saoEnabled && pic->useSAO )
568
2.03k
    {
569
2.03k
      lnRsrc->m_encSao          .initSlice( slice );
570
2.03k
    }
571
2.03k
  }
572
573
1.14k
  if( slice->sps->fpelMmvd && !slice->picHeader->disFracMMVD )
574
1.14k
  {
575
1.14k
    slice->picHeader->disFracMMVD = ( pic->lwidth() * pic->lheight() > 1920 * 1080 ) ? true : false;
576
1.14k
  }
577
578
1.14k
  xProcessCtus( pic, startCtuTsAddr, boundingCtuTsAddr );
579
1.14k
}
580
581
void setJointCbCrModes( CodingStructure& cs, const Position topLeftLuma, const Size sizeLuma )
582
1.14k
{
583
1.14k
  bool              sgnFlag = true;
584
585
1.14k
  if( isChromaEnabled( cs.picture->chromaFormat) )
586
1.14k
  {
587
1.14k
    const CompArea  cbArea  = CompArea( COMP_Cb, cs.picture->chromaFormat, Area(topLeftLuma,sizeLuma), true );
588
1.14k
    const CompArea  crArea  = CompArea( COMP_Cr, cs.picture->chromaFormat, Area(topLeftLuma,sizeLuma), true );
589
590
1.14k
    const CPelBuf   orgCb   = cs.picture->getFilteredOrigBuffer().valid() ? cs.picture->getFiltOrigBuf( cbArea ): cs.picture->getOrigBuf( cbArea );
591
1.14k
    const CPelBuf   orgCr   = cs.picture->getFilteredOrigBuffer().valid() ? cs.picture->getFiltOrigBuf( crArea ): cs.picture->getOrigBuf( crArea );
592
1.14k
    const int       x0      = ( cbArea.x > 0 ? 0 : 1 );
593
1.14k
    const int       y0      = ( cbArea.y > 0 ? 0 : 1 );
594
1.14k
    const int       x1      = ( cbArea.x + cbArea.width  < cs.picture->Cb().width  ? cbArea.width  : cbArea.width  - 1 );
595
1.14k
    const int       y1      = ( cbArea.y + cbArea.height < cs.picture->Cb().height ? cbArea.height : cbArea.height - 1 );
596
1.14k
    const int       cbs     = orgCb.stride;
597
1.14k
    const int       crs     = orgCr.stride;
598
1.14k
    const Pel*      pCb     = orgCb.buf + y0 * cbs;
599
1.14k
    const Pel*      pCr     = orgCr.buf + y0 * crs;
600
1.14k
    int64_t         sumCbCr = 0;
601
602
    // determine inter-chroma transform sign from correlation between high-pass filtered (i.e., zero-mean) Cb and Cr planes
603
86.8k
    for( int y = y0; y < y1; y++, pCb += cbs, pCr += crs )
604
85.6k
    {
605
6.61M
      for( int x = x0; x < x1; x++ )
606
6.52M
      {
607
6.52M
        int cb = ( 12*(int)pCb[x] - 2*((int)pCb[x-1] + (int)pCb[x+1] + (int)pCb[x-cbs] + (int)pCb[x+cbs]) - ((int)pCb[x-1-cbs] + (int)pCb[x+1-cbs] + (int)pCb[x-1+cbs] + (int)pCb[x+1+cbs]) );
608
6.52M
        int cr = ( 12*(int)pCr[x] - 2*((int)pCr[x-1] + (int)pCr[x+1] + (int)pCr[x-crs] + (int)pCr[x+crs]) - ((int)pCr[x-1-crs] + (int)pCr[x+1-crs] + (int)pCr[x-1+crs] + (int)pCr[x+1+crs]) );
609
6.52M
        sumCbCr += cb*cr;
610
6.52M
      }
611
85.6k
    }
612
613
1.14k
    sgnFlag = ( sumCbCr < 0 );
614
1.14k
  }
615
616
1.14k
  cs.slice->picHeader->jointCbCrSign = sgnFlag;
617
1.14k
}
618
619
struct CtuPos
620
{
621
  const int ctuPosX;
622
  const int ctuPosY;
623
  const int ctuRsAddr;
624
625
3.59k
  CtuPos( int _x, int _y, int _a ) : ctuPosX( _x ), ctuPosY( _y ), ctuRsAddr( _a ) {}
626
};
627
628
class CtuTsIterator
629
{
630
  private:
631
    const CodingStructure& cs;
632
    const int        m_startTsAddr;
633
    const int        m_endTsAddr;
634
    std::vector<int> m_ctuAddrMap;
635
          int        m_ctuTsAddr;
636
637
  private:
638
    int getNextTsAddr( const int _tsAddr ) const
639
3.59k
    {
640
3.59k
      const PreCalcValues& pcv  = *cs.pcv;
641
3.59k
      const int startSliceRsRow = m_startTsAddr / pcv.widthInCtus;
642
3.59k
      const int startSliceRsCol = m_startTsAddr % pcv.widthInCtus;
643
3.59k
      const int endSliceRsRow   = (m_endTsAddr - 1) / pcv.widthInCtus;
644
3.59k
      const int endSliceRsCol   = (m_endTsAddr - 1) % pcv.widthInCtus;
645
3.59k
            int ctuTsAddr = _tsAddr;
646
3.59k
      CHECK( ctuTsAddr > m_endTsAddr, "error: array index out of bounds" );
647
4.73k
      while( ctuTsAddr < m_endTsAddr )
648
3.59k
      {
649
3.59k
        ctuTsAddr++;
650
3.59k
        const int ctuRsAddr = ctuTsAddr; 
651
3.59k
        if( cs.slice->pps->rectSlice
652
3.59k
            && ( (ctuRsAddr / pcv.widthInCtus) < startSliceRsRow
653
3.59k
              || (ctuRsAddr / pcv.widthInCtus) > endSliceRsRow
654
2.44k
              || (ctuRsAddr % pcv.widthInCtus) < startSliceRsCol
655
2.44k
              || (ctuRsAddr % pcv.widthInCtus) > endSliceRsCol ) )
656
1.14k
          continue;
657
2.44k
        break;
658
3.59k
      }
659
3.59k
      return ctuTsAddr;
660
3.59k
    }
661
662
    int mapAddr( const int _addr ) const
663
3.59k
    {
664
3.59k
      if( _addr < 0 )
665
0
        return _addr;
666
3.59k
      if( _addr >= m_ctuAddrMap.size() )
667
0
        return _addr;
668
3.59k
      return m_ctuAddrMap[ _addr ];
669
3.59k
    }
670
671
  public:
672
1.14k
    CtuTsIterator( const CodingStructure& _cs, int _s, int _e,       std::vector<int>& _m         ) : cs( _cs ), m_startTsAddr( _s ), m_endTsAddr( _e ), m_ctuAddrMap( _m ), m_ctuTsAddr( _s ) {}
673
0
    CtuTsIterator( const CodingStructure& _cs, int _s, int _e, bool _wpp                          ) : cs( _cs ), m_startTsAddr( _s ), m_endTsAddr( _e ),                     m_ctuTsAddr( _s ) { if( _wpp ) setWppPattern(); }
674
0
    CtuTsIterator( const CodingStructure& _cs, int _s, int _e, const std::vector<int>& _m         ) : cs( _cs ), m_startTsAddr( _s ), m_endTsAddr( _e ), m_ctuAddrMap( _m ), m_ctuTsAddr( _s ) {}
675
1.14k
    CtuTsIterator( const CodingStructure& _cs, int _s, int _e, const std::vector<int>& _m, int _c ) : cs( _cs ), m_startTsAddr( _s ), m_endTsAddr( _e ), m_ctuAddrMap( _m ), m_ctuTsAddr( std::max( _s, _c ) ) {}
676
1.14k
    CtuTsIterator( const CodingStructure& _cs, int _s, int _e, const std::vector<int>* _m, bool _wpp ) : cs( _cs ), m_startTsAddr( _s ), m_endTsAddr( _e ), m_ctuTsAddr( _s ) {  if( _wpp ) m_ctuAddrMap = *_m;  }
677
678
8.17k
    virtual ~CtuTsIterator() { m_ctuAddrMap.clear(); }
679
680
3.59k
    CtuTsIterator& operator++()                { m_ctuTsAddr = getNextTsAddr( m_ctuTsAddr ); return *this; }
681
0
    CtuTsIterator  operator++(int)             { auto retval = *this; ++(*this); return retval; }
682
0
    bool operator==(CtuTsIterator other) const { return m_ctuTsAddr == other.m_ctuTsAddr; }
683
4.73k
    bool operator!=(CtuTsIterator other) const { return m_ctuTsAddr != other.m_ctuTsAddr; }
684
3.59k
    CtuPos operator*()                   const { const int ctuRsAddr = mapAddr( m_ctuTsAddr );  return CtuPos( ctuRsAddr % cs.pcv->widthInCtus, ctuRsAddr / cs.pcv->widthInCtus, ctuRsAddr ); }
685
686
1.14k
    CtuTsIterator begin() { return CtuTsIterator( cs, m_startTsAddr, m_endTsAddr, m_ctuAddrMap ); };
687
1.14k
    CtuTsIterator end()   { return CtuTsIterator( cs, m_startTsAddr, m_endTsAddr, m_ctuAddrMap, m_endTsAddr ); };
688
689
    using iterator_category = std::forward_iterator_tag;
690
    using value_type        = int;
691
    using pointer           = int*;
692
    using reference         = int&;
693
    using difference_type   = ptrdiff_t;
694
695
    void setWppPattern()
696
0
    {
697
0
      const PreCalcValues& pcv = *cs.pcv;
698
0
      m_ctuAddrMap.resize( pcv.sizeInCtus, 0 );
699
0
      int addr = 0;
700
0
      for( int i = 1; i < pcv.sizeInCtus; i++ )
701
0
      {
702
0
        int x = addr % pcv.widthInCtus;
703
0
        int y = addr / pcv.widthInCtus;
704
0
        x -= 1;
705
0
        y += 1;
706
0
        if( x < 0 || y >= pcv.heightInCtus )
707
0
        {
708
0
          x += 1 + y;
709
0
          y  = 0;
710
0
        }
711
0
        if( x >= pcv.widthInCtus )
712
0
        {
713
0
          y += ( x - pcv.widthInCtus ) + 1;
714
0
          x  = pcv.widthInCtus - 1;
715
0
        }
716
0
        addr = y * pcv.widthInCtus + x;
717
0
        m_ctuAddrMap[ i ] = addr;
718
0
      }
719
0
    }
720
};
721
722
void EncSlice::saoDisabledRate( CodingStructure& cs, SAOBlkParam* reconParams )
723
0
{
724
0
  EncSampleAdaptiveOffset::disabledRate( cs, m_saoDisabledRate, reconParams, m_pcEncCfg->m_saoEncodingRate, m_pcEncCfg->m_saoEncodingRateChroma, m_pcEncCfg->m_internChromaFormat );
725
0
}
726
727
void EncSlice::finishCompressSlice( Picture* pic, Slice& slice )
728
1.14k
{
729
1.14k
  CodingStructure& cs = *pic->cs;
730
731
  // finalize
732
1.14k
  if( slice.sps->saoEnabled && pic->useSAO )
733
1.14k
  {
734
    // store disabled statistics
735
1.14k
    if( !m_pcEncCfg->m_numThreads )
736
0
      saoDisabledRate( cs, &m_saoReconParams[ 0 ] );
737
738
    // set slice header flags
739
1.14k
    CHECK( m_saoEnabled[ COMP_Cb ] != m_saoEnabled[ COMP_Cr ], "Unspecified error");
740
1.14k
    for( auto s : pic->slices )
741
1.14k
    {
742
1.14k
      s->saoEnabled[ CH_L ] = m_saoEnabled[ COMP_Y  ];
743
1.14k
      s->saoEnabled[ CH_C ] = m_saoEnabled[ COMP_Cb ];
744
1.14k
    }
745
1.14k
  }
746
1.14k
}
747
748
void EncSlice::xProcessCtus( Picture* pic, const unsigned startCtuTsAddr, const unsigned boundingCtuTsAddr )
749
1.14k
{
750
1.14k
  PROFILER_SCOPE_TOP_LEVEL_EXT( 1, g_timeProfiler, P_IGNORE, pic->cs );
751
1.14k
  CodingStructure& cs      = *pic->cs;
752
1.14k
  Slice&           slice   = *cs.slice;
753
1.14k
  const PreCalcValues& pcv = *cs.pcv;
754
755
  // initialization
756
1.14k
  if( slice.sps->jointCbCr )
757
1.14k
  {
758
1.14k
    setJointCbCrModes( cs, Position(0, 0), cs.area.lumaSize() );
759
1.14k
  }
760
761
1.14k
  if( slice.sps->saoEnabled && pic->useSAO )
762
1.14k
  {
763
    // check SAO enabled or disabled
764
1.14k
    EncSampleAdaptiveOffset::decidePicParams( cs, m_saoDisabledRate, m_saoEnabled, m_pcEncCfg->m_saoEncodingRate, m_pcEncCfg->m_saoEncodingRateChroma, m_pcEncCfg->m_internChromaFormat );
765
766
1.14k
    m_saoAllDisabled = true;
767
4.58k
    for( int compIdx = 0; compIdx < getNumberValidComponents( pcv.chrFormat ); compIdx++ )
768
3.44k
    {
769
3.44k
      m_saoAllDisabled &= ! m_saoEnabled[ compIdx ];
770
3.44k
    }
771
772
1.14k
    std::fill( m_saoReconParams.begin(), m_saoReconParams.end(), SAOBlkParam() );
773
1.14k
  }
774
0
  else
775
0
  {
776
0
    m_saoAllDisabled = true;
777
0
  }
778
779
1.14k
  if( slice.sps->alfEnabled )
780
1.14k
  {
781
1.14k
    m_pALF->initEncProcess( slice );
782
1.14k
  }
783
784
1.14k
  std::fill( m_processStates.begin(), m_processStates.end(), CTU_ENCODE );
785
786
  // fill encoder parameter list
787
1.14k
  int idx = 0;
788
1.14k
  const std::vector<int> base = slice.sliceMap.ctuAddrInSlice;
789
1.14k
  auto ctuIter = CtuTsIterator( cs, startCtuTsAddr, boundingCtuTsAddr, &m_ctuAddrMap, m_pcEncCfg->m_numThreads > 0 );
790
1.14k
  for( auto ctuPos : ctuIter )
791
3.59k
  {
792
3.59k
    ctuEncParams[ idx ].pic       = pic;
793
3.59k
    ctuEncParams[ idx ].encSlice  = this;
794
3.59k
    ctuEncParams[ idx ].ctuRsAddr = ctuPos.ctuRsAddr;
795
3.59k
    ctuEncParams[ idx ].ctuPosX   = ctuPos.ctuPosX;
796
3.59k
    ctuEncParams[ idx ].ctuPosY   = ctuPos.ctuPosY;
797
3.59k
    ctuEncParams[ idx ].ctuArea   = UnitArea( pic->chromaFormat, slice.pps->pcv->getCtuArea( ctuPos.ctuPosX, ctuPos.ctuPosY ) );
798
799
3.59k
    if( m_pcEncCfg->m_numThreads > 0 )
800
3.59k
    {
801
3.59k
      ctuEncParams[idx].tileLineResIdx = slice.pps->getTileLineId( ctuPos.ctuPosX, ctuPos.ctuPosY );
802
3.59k
    }
803
0
    else
804
0
    {
805
0
      ctuEncParams[idx].tileLineResIdx = 0;
806
0
    }
807
3.59k
    idx++;
808
3.59k
  }
809
810
  //for( int i = 0; i < idx; i++ )
811
  //{
812
  //  for( int j = i; j < idx; j++ )
813
  //  {
814
  //    if( ctuEncParams[i].tileLineResIdx != ctuEncParams[j].tileLineResIdx ) continue;
815
  //
816
  //    CHECK( ctuEncParams[i].ctuPosY != ctuEncParams[j].ctuPosY, "Not the same CTU line!" );
817
  //    CHECK( slice.pps->getTileIdx( ctuEncParams[i].ctuPosX, ctuEncParams[i].ctuPosY ) != slice.pps->getTileIdx( ctuEncParams[j].ctuPosX, ctuEncParams[j].ctuPosY ), "Not the same tile!" );
818
  //  }
819
  //}
820
821
1.14k
  CHECK( idx != pcv.sizeInCtus, "array index out of bounds" );
822
823
  // process ctu's until last ctu is done
824
1.14k
  if( m_pcEncCfg->m_numThreads > 0 )
825
1.14k
  {
826
1.14k
    for( auto& ctuEncParam : ctuEncParams )
827
3.59k
    {
828
3.59k
      m_threadPool->addBarrierTask( EncSlice::xProcessCtuTask<false>,
829
3.59k
                                    &ctuEncParam,
830
3.59k
                                    m_ctuTasksDoneCounter,
831
3.59k
                                    nullptr,
832
3.59k
                                    {},
833
3.59k
                                    EncSlice::xProcessCtuTask<true> );
834
3.59k
    }
835
1.14k
  }
836
0
  else
837
0
  {
838
0
    do
839
0
    {
840
0
      for( auto& ctuEncParam : ctuEncParams )
841
0
      {
842
0
        if( m_processStates[ctuEncParam.ctuRsAddr] != PROCESS_DONE )
843
0
          EncSlice::xProcessCtuTask<false>( 0, &ctuEncParam );
844
0
      }
845
0
      DTRACE_PIC_COMP_COND( m_processStates[ 0 ] == SAO_FILTER && m_processStates[ boundingCtuTsAddr - 1 ] == SAO_FILTER, D_REC_CB_LUMA_LF,   cs, cs.getRecoBuf(), COMP_Y  );
846
0
      DTRACE_PIC_COMP_COND( m_processStates[ 0 ] == SAO_FILTER && m_processStates[ boundingCtuTsAddr - 1 ] == SAO_FILTER, D_REC_CB_CHROMA_LF, cs, cs.getRecoBuf(), COMP_Cb );
847
0
      DTRACE_PIC_COMP_COND( m_processStates[ 0 ] == SAO_FILTER && m_processStates[ boundingCtuTsAddr - 1 ] == SAO_FILTER, D_REC_CB_CHROMA_LF, cs, cs.getRecoBuf(), COMP_Cr );
848
0
      DTRACE_PIC_COMP_COND( m_processStates[ 0 ] == ALF_GET_STATISTICS && m_processStates[ boundingCtuTsAddr - 1 ] == ALF_GET_STATISTICS, D_REC_CB_LUMA_SAO,   cs, cs.getRecoBuf(), COMP_Y  );
849
0
      DTRACE_PIC_COMP_COND( m_processStates[ 0 ] == ALF_GET_STATISTICS && m_processStates[ boundingCtuTsAddr - 1 ] == ALF_GET_STATISTICS, D_REC_CB_CHROMA_SAO, cs, cs.getRecoBuf(), COMP_Cb );
850
0
      DTRACE_PIC_COMP_COND( m_processStates[ 0 ] == ALF_GET_STATISTICS && m_processStates[ boundingCtuTsAddr - 1 ] == ALF_GET_STATISTICS, D_REC_CB_CHROMA_SAO, cs, cs.getRecoBuf(), COMP_Cr );
851
0
    }
852
0
    while( m_processStates[ boundingCtuTsAddr - 1 ] != PROCESS_DONE );
853
0
  }
854
1.14k
}
855
856
inline bool checkCtuTaskNbTop( const PPS& pps, const int& ctuPosX, const int& ctuPosY, const int& ctuRsAddr, const ProcessCtuState* processStates, const TaskType tskType, bool override = false )
857
708k
{
858
708k
  return ctuPosY > 0 && ( override || pps.canFilterCtuBdry( ctuPosX, ctuPosY, 0, -1 ) ) && processStates[ ctuRsAddr - pps.pcv->widthInCtus ] <= tskType;
859
708k
}
860
861
inline bool checkCtuTaskNbBot( const PPS& pps, const int& ctuPosX, const int& ctuPosY, const int& ctuRsAddr, const ProcessCtuState* processStates, const TaskType tskType, bool override = false )
862
296k
{
863
296k
  return ctuPosY + 1 < pps.pcv->heightInCtus && ( override || pps.canFilterCtuBdry( ctuPosX, ctuPosY, 0, 1 ) ) && processStates[ ctuRsAddr     + pps.pcv->widthInCtus ] <= tskType;
864
296k
}
865
866
inline bool checkCtuTaskNbRgt( const PPS& pps, const int& ctuPosX, const int& ctuPosY, const int& ctuRsAddr, const ProcessCtuState* processStates, const TaskType tskType, bool override = false )
867
582k
{
868
582k
  return ctuPosX + 1 < pps.pcv->widthInCtus && ( override || pps.canFilterCtuBdry( ctuPosX, ctuPosY, 1, 0 ) ) && processStates[ ctuRsAddr + 1 ] <= tskType;
869
582k
}
870
871
inline bool checkCtuTaskNbTopRgt( const PPS& pps, const int& ctuPosX, const int& ctuPosY, const int& ctuRsAddr, const ProcessCtuState* processStates, const TaskType tskType, bool override = false )
872
234k
{
873
234k
  return ctuPosY > 0 && ctuPosX + 1 < pps.pcv->widthInCtus && ( override || pps.canFilterCtuBdry( ctuPosX, ctuPosY, 1, -1 ) ) && processStates[ ctuRsAddr - pps.pcv->widthInCtus + 1 ] <= tskType;
874
234k
}
875
876
inline bool checkCtuTaskNbBotRgt( const PPS& pps, const int& ctuPosX, const int& ctuPosY, const int& ctuRsAddr, const ProcessCtuState* processStates, const TaskType tskType, const int rightOffset = 1, bool override = false )
877
6.10M
{
878
6.10M
  return ctuPosX + rightOffset < pps.pcv->widthInCtus && ctuPosY + 1 < pps.pcv->heightInCtus && ( override || pps.canFilterCtuBdry( ctuPosX, ctuPosY, rightOffset, 1 ) ) && processStates[ ctuRsAddr + rightOffset + pps.pcv->widthInCtus ] <= tskType;
879
6.10M
}
880
881
template<bool checkReadyState>
882
bool EncSlice::xProcessCtuTask( int threadIdx, void* taskParam )
883
92.9M
{
884
92.9M
  CtuEncParam* ctuEncParam       = static_cast<CtuEncParam*>( taskParam );
885
92.9M
  Picture* pic                   = ctuEncParam->pic;
886
92.9M
  EncSlice* encSlice             = ctuEncParam->encSlice;
887
92.9M
  CodingStructure& cs            = *pic->cs;
888
92.9M
  Slice&           slice         = *cs.slice;
889
92.9M
  const PPS&       pps           = *slice.pps;
890
92.9M
  const PreCalcValues& pcv       = *cs.pcv;
891
92.9M
  const int ctuRsAddr            = ctuEncParam->ctuRsAddr;
892
92.9M
  const int ctuPosX              = ctuEncParam->ctuPosX;
893
92.9M
  const int ctuPosY              = ctuEncParam->ctuPosY;
894
92.9M
  const int x                    = ctuPosX << pcv.maxCUSizeLog2;
895
92.9M
  const int y                    = ctuPosY << pcv.maxCUSizeLog2;
896
92.9M
  const int width                = std::min( pcv.maxCUSize, pcv.lumaWidth  - x );
897
92.9M
  const int height               = std::min( pcv.maxCUSize, pcv.lumaHeight - y );
898
92.9M
  const int ctuStride            = pcv.widthInCtus;
899
92.9M
  const int lineIdx              = ctuEncParam->tileLineResIdx;
900
92.9M
  ProcessCtuState* processStates = encSlice->m_processStates.data();
901
92.9M
  const UnitArea& ctuArea        = ctuEncParam->ctuArea;
902
92.9M
  const bool wppSyncEnabled      = cs.sps->entropyCodingSyncEnabled;
903
92.9M
  const TaskType currState       = processStates[ ctuRsAddr ];
904
92.9M
  const unsigned syncLines       = encSlice->m_pcEncCfg->m_ifpLines;
905
906
92.9M
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "poc", cs.slice->poc ) );
907
92.9M
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "ctu", ctuRsAddr ) );
908
92.9M
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "final", processStates[ ctuRsAddr ] == CTU_ENCODE ? 0 : 1 ) );
909
910
  // process ctu's line wise from left to right
911
92.9M
  const bool tileParallel = encSlice->m_pcEncCfg->m_tileParallelCtuEnc;
912
92.9M
  if( tileParallel && currState == CTU_ENCODE && ctuPosX > 0 && slice.pps->getTileIdx( ctuPosX, ctuPosY ) != slice.pps->getTileIdx( ctuPosX - 1, ctuPosY ) )
913
0
    ; // for CTU_ENCODE on tile boundaries, allow parallel processing of tiles
914
92.9M
  else if( ctuPosX > 0 && processStates[ ctuRsAddr - 1 ] <= currState && currState < PROCESS_DONE )
915
51.3M
    return false;
916
917
41.6M
  switch( currState )
918
41.6M
  {
919
    // encode
920
21.1M
    case CTU_ENCODE:
921
21.1M
      {
922
        // CTU line-wise inter-frame parallel processing synchronization
923
21.1M
        if( syncLines )
924
0
        {
925
0
          const bool lineStart = ctuPosX == 0 || ( tileParallel && slice.pps->getTileIdx( ctuPosX, ctuPosY ) != slice.pps->getTileIdx( ctuPosX - 1, ctuPosY ) );
926
0
          if( lineStart && !refPicCtuLineReady( slice, ctuPosY + (int)syncLines, pcv ) )
927
0
          {
928
0
            return false;
929
0
          }
930
0
        }
931
932
        // general wpp conditions, top and top-right ctu have to be encoded
933
21.1M
        if( encSlice->m_pcEncCfg->m_tileParallelCtuEnc && ctuPosY > 0 && slice.pps->getTileIdx( ctuPosX, ctuPosY ) != slice.pps->getTileIdx( ctuPosX, ctuPosY - 1 ) )
934
0
          ; // allow parallel processing of CTU-encoding on independent tiles
935
21.1M
        else if( ctuPosY > 0                                  && processStates[ ctuRsAddr - ctuStride     ] <= CTU_ENCODE )
936
17.6M
          return false;
937
3.42M
        else if( ctuPosY > 0 && ctuPosX + 1 < pcv.widthInCtus && processStates[ ctuRsAddr - ctuStride + 1 ] <= CTU_ENCODE && !wppSyncEnabled )
938
3.41M
          return false;
939
        
940
7.12k
        if( checkReadyState )
941
3.58k
          return true;
942
943
#ifdef TRACE_ENABLE_ITT
944
        std::stringstream ss;
945
        ss << "Encode_" << slice.poc << "_CTU_" << ctuPosY << "_" << ctuPosX;
946
        __itt_string_handle* itt_handle_ctuEncode = __itt_string_handle_create( ss.str().c_str() );
947
#endif
948
3.54k
        ITT_TASKSTART( itt_domain_encode, itt_handle_ctuEncode );
949
950
3.54k
        TileLineEncRsrc* lineEncRsrc = encSlice->m_TileLineEncRsrc[ lineIdx ];
951
3.54k
        PerThreadRsrc* taskRsrc      = encSlice->m_ThreadRsrc[ threadIdx ];
952
3.54k
        EncCu& encCu                 = taskRsrc->m_encCu;
953
954
3.54k
        encCu.setCtuEncRsrc( &lineEncRsrc->m_CABACEstimator, &taskRsrc->m_CtxCache, &lineEncRsrc->m_ReuseUniMv, &lineEncRsrc->m_BlkUniMvInfoBuffer, &lineEncRsrc->m_AffineProfList, &lineEncRsrc->m_CachedBvs );
955
3.54k
        encCu.encodeCtu( pic, lineEncRsrc->m_prevQp, ctuPosX, ctuPosY );
956
957
        // cleanup line memory when last ctu in line done to reduce overall memory consumption
958
3.59k
        if( encSlice->m_pcEncCfg->m_ensureWppBitEqual && ( ctuPosX == pcv.widthInCtus - 1 || slice.pps->getTileIdx( ctuPosX, ctuPosY ) != slice.pps->getTileIdx( ctuPosX + 1, ctuPosY ) ) )
959
2.03k
        {
960
2.03k
          lineEncRsrc->m_AffineProfList    .resetAffineMVList();
961
2.03k
          lineEncRsrc->m_BlkUniMvInfoBuffer.resetUniMvList();
962
2.03k
          lineEncRsrc->m_ReuseUniMv        .resetReusedUniMvs();
963
2.03k
          lineEncRsrc->m_CachedBvs         .resetIbcBvCand();
964
2.03k
        }
965
966
3.54k
        DTRACE_UPDATE( g_trace_ctx, std::make_pair( "final", 1 ) );
967
3.54k
        ITT_TASKEND( itt_domain_encode, itt_handle_ctuEncode );
968
969
3.54k
        processStates[ ctuRsAddr ] = LF_VER;
970
3.54k
      }
971
0
      break;
972
973
    // vertical loopfilter
974
11.5M
    case LF_VER:
975
11.5M
      {
976
        // clip check to right tile border (CTU_ENCODE pre-processing delay due to IBC)
977
11.5M
        const int tileCol = slice.pps->ctuToTileCol[ctuPosX];
978
11.5M
        const int lastCtuPosXInTile = slice.pps->tileColBd[tileCol] + slice.pps->tileColWidth[tileCol] - 1;
979
11.5M
        const int checkRight = std::min<int>( encSlice->m_ctuEncDelay, lastCtuPosXInTile - ctuPosX );
980
981
11.5M
        const bool hasTiles = encSlice->m_pcEncCfg->m_tileParallelCtuEnc && slice.pps->getNumTiles() > 1;
982
983
        // need to check line above bcs of tiling, which allows CTU_ENCODE to run independently across tiles
984
11.5M
        if( hasTiles )
985
0
        {
986
0
          if( ctuPosY > 0 )
987
0
          {
988
0
            for( int i = -!!ctuPosX; i <= checkRight; i++ )
989
0
              if( pps.canFilterCtuBdry( ctuPosX, ctuPosY, i, -1 ) && processStates[ctuRsAddr - ctuStride + i] <= CTU_ENCODE )
990
0
                return false;
991
0
          }
992
0
        }
993
        
994
        // ensure all surrounding ctu's are encoded (intra pred requires non-reshaped and unfiltered residual, IBC requires unfiltered samples too)
995
        // check right with max offset (due to WPP condition above, this implies top-right has been already encoded)
996
17.6M
        for( int i = hasTiles ? -!!ctuPosX : checkRight; i <= checkRight; i++ )
997
11.5M
          if( pps.canFilterCtuBdry( ctuPosX, ctuPosY, i, 0 ) && processStates[ctuRsAddr + i] <= CTU_ENCODE )
998
5.48M
            return false;
999
1000
        // check bottom right with 1 CTU delay (this is only required for intra pred)
1001
        // at the right picture border this will check the bottom CTU
1002
6.08M
        const int checkBottomRight = std::min<int>( 1, lastCtuPosXInTile - ctuPosX );
1003
6.08M
        if( checkCtuTaskNbBotRgt( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, CTU_ENCODE, checkBottomRight ) ) 
1004
6.08M
          return false;
1005
1006
6.69k
        if( checkReadyState )
1007
3.57k
          return true;
1008
1009
3.12k
        ITT_TASKSTART( itt_domain_encode, itt_handle_rspLfVer );
1010
1011
        // loopfilter
1012
3.12k
        if( !cs.pps->deblockingFilterControlPresent || !cs.pps->deblockingFilterDisabled || cs.pps->deblockingFilterOverrideEnabled )
1013
3.58k
        {
1014
3.58k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_DEBLOCK_FILTER, &cs, CH_L );
1015
          // calculate filter strengths
1016
3.58k
          encSlice->m_pLoopFilter->calcFilterStrengthsCTU( cs, ctuArea, true );
1017
1018
          // vertical filter
1019
3.58k
          PelUnitBuf reco = cs.picture->getRecoBuf();
1020
3.58k
          encSlice->m_pLoopFilter->xDeblockArea<EDGE_VER>( cs, ctuArea, MAX_NUM_CH, reco );
1021
3.58k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1022
3.58k
        }
1023
1024
3.12k
        ITT_TASKEND( itt_domain_encode, itt_handle_rspLfVer );
1025
1026
3.12k
        processStates[ ctuRsAddr ] = LF_HOR;
1027
3.12k
      }
1028
0
      break;
1029
1030
    // horizontal loopfilter
1031
392k
    case LF_HOR:
1032
392k
      {
1033
        // ensure horizontal ordering (from top to bottom)
1034
392k
        if( checkCtuTaskNbTop   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_HOR ) )         
1035
110k
          return false;
1036
1037
        // ensure vertical loop filter of neighbor ctu's will not modify current residual
1038
        // check top, top-right and right ctu
1039
        // (top, top-right checked implicitly due to ordering check above)
1040
282k
        if( checkCtuTaskNbRgt   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_VER ) )
1041
275k
          return false;
1042
1043
6.89k
        if( checkReadyState )
1044
3.58k
          return true;
1045
1046
3.31k
        ITT_TASKSTART( itt_domain_encode, itt_handle_lfHor );
1047
1048
3.31k
        if( !cs.pps->deblockingFilterControlPresent || !cs.pps->deblockingFilterDisabled || cs.pps->deblockingFilterOverrideEnabled )
1049
3.58k
        {
1050
3.58k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_DEBLOCK_FILTER, &cs, CH_L );
1051
3.58k
          PelUnitBuf reco = cs.picture->getRecoBuf();
1052
3.58k
          encSlice->m_pLoopFilter->xDeblockArea<EDGE_HOR>( cs, ctuArea, MAX_NUM_CH, reco );
1053
3.58k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1054
3.58k
        }
1055
1056
3.31k
        ITT_TASKEND( itt_domain_encode, itt_handle_lfHor );
1057
1058
3.31k
        processStates[ ctuRsAddr ] = SAO_FILTER;
1059
3.31k
      }
1060
0
      break;
1061
1062
    // SAO filter
1063
311k
    case SAO_FILTER:
1064
311k
      {
1065
        // general wpp conditions, top and top-right ctu have to be filtered
1066
311k
        if( checkCtuTaskNbTop   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER, true ) ) return false;
1067
234k
        if( checkCtuTaskNbTopRgt( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER, true ) ) return false;
1068
1069
        // ensure loop filter of neighbor ctu's will not modify current residual
1070
        // sao processing dependents on +1 pixel to each side
1071
        // due to wpp condition above, only right, bottom and bottom-right ctu have to be checked
1072
205k
        if( checkCtuTaskNbRgt   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_HOR,    true ) ) return false;
1073
197k
        if( checkCtuTaskNbBot   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_HOR,    true ) ) return false;
1074
10.0k
        if( checkCtuTaskNbBotRgt( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_HOR, 1, true ) ) return false;
1075
1076
7.08k
        if( checkReadyState )
1077
3.58k
          return true;
1078
1079
3.50k
        ITT_TASKSTART( itt_domain_encode, itt_handle_sao );
1080
1081
        // SAO filter
1082
3.58k
        if( slice.sps->saoEnabled && pic->useSAO )
1083
3.58k
        {
1084
3.58k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_SAO, &cs, CH_L );
1085
3.58k
          TileLineEncRsrc* lineEncRsrc    = encSlice->m_TileLineEncRsrc[ lineIdx ];
1086
3.58k
          PerThreadRsrc* taskRsrc         = encSlice->m_ThreadRsrc[ threadIdx ];
1087
3.58k
          EncSampleAdaptiveOffset& encSao = lineEncRsrc->m_encSao;
1088
1089
3.58k
          encSao.setCtuEncRsrc( &lineEncRsrc->m_SaoCABACEstimator, &taskRsrc->m_CtxCache );
1090
3.58k
          encSao.storeCtuReco( cs, ctuArea, ctuPosX, ctuPosY );
1091
3.58k
          encSao.getCtuStatistics( cs, encSlice->m_saoStatData, ctuArea, ctuRsAddr );
1092
3.58k
          encSao.decideCtuParams( cs, encSlice->m_saoStatData, encSlice->m_saoEnabled, encSlice->m_saoAllDisabled, ctuArea, ctuRsAddr, &encSlice->m_saoReconParams[ 0 ], cs.picture->getSAO() );
1093
3.58k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1094
3.58k
        }
1095
1096
        // ALF border extension
1097
3.50k
        if( cs.sps->alfEnabled )
1098
3.59k
        {
1099
          // we have to do some kind of position aware boundary padding
1100
          // it's done here because the conditions are readable
1101
3.59k
          PelUnitBuf recoBuf = cs.picture->getRecoBuf();
1102
3.59k
          const int fltSize  = ( MAX_ALF_FILTER_LENGTH + 1 ) >> 1;
1103
3.59k
          const int xL       = ( ctuPosX == 0 )                 ? ( x-fltSize       ) : ( x );
1104
3.59k
          const int xR       = ( ctuPosX+1 == pcv.widthInCtus ) ? ( x+width+fltSize ) : ( x+width );
1105
1106
3.59k
          if( ctuPosX == 0 )                  recoBuf.extendBorderPelLft( y, height, fltSize );
1107
3.59k
          if( ctuPosX+1 == pcv.widthInCtus )  recoBuf.extendBorderPelRgt( y, height, fltSize );
1108
3.59k
          if( ctuPosY == 0 )                  recoBuf.extendBorderPelTop( xL, xR-xL, fltSize );
1109
3.59k
          if( ctuPosY+1 == pcv.heightInCtus ) recoBuf.extendBorderPelBot( xL, xR-xL, fltSize );
1110
1111
3.59k
          encSlice->m_pALF->copyCTUforALF(cs, ctuPosX, ctuPosY);
1112
3.59k
        }
1113
1114
        // DMVR refinement can be stored now
1115
3.59k
        if( slice.sps->DMVR && !slice.picHeader->disDmvrFlag )
1116
3.59k
        {
1117
3.59k
          CS::setRefinedMotionFieldCTU( cs, ctuPosX, ctuPosY );
1118
3.59k
        }
1119
3.50k
        ITT_TASKEND( itt_domain_encode, itt_handle_sao );
1120
1121
3.50k
        const int tileCol = slice.pps->ctuToTileCol[ctuPosX];
1122
3.50k
        const int lastCtuColInTileRow = slice.pps->tileColBd[tileCol] + slice.pps->tileColWidth[tileCol] - 1;
1123
3.50k
        if( ctuPosX == lastCtuColInTileRow )
1124
2.03k
        {
1125
2.03k
          processStates[ctuRsAddr] = ALF_GET_STATISTICS;
1126
2.03k
        }
1127
1.46k
        else
1128
1.46k
        {
1129
1.46k
          processStates[ctuRsAddr] = PROCESS_DONE;
1130
1.46k
          return true;
1131
1.46k
        }
1132
3.50k
      }
1133
2.03k
      break;
1134
1135
94.9k
    case ALF_GET_STATISTICS:
1136
94.9k
      {
1137
        // ensure all surrounding ctu's are filtered (ALF will use pixels of adjacent CTU's)
1138
        // due to wpp condition above in SAO_FILTER, only right, bottom and bottom-right ctu have to be checked
1139
94.9k
        if( checkCtuTaskNbRgt   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER ) ) return false;
1140
94.9k
        if( checkCtuTaskNbBot   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER ) ) return false;
1141
4.05k
        if( checkCtuTaskNbBotRgt( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER ) ) return false;
1142
1143
4.05k
        if( checkReadyState )
1144
2.02k
          return true;
1145
1146
2.03k
        ITT_TASKSTART( itt_domain_encode, itt_handle_alf_stat );
1147
1148
        // ALF pre-processing
1149
2.03k
        if( slice.sps->alfEnabled )
1150
2.02k
        {
1151
2.02k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_ALF, &cs, CH_L );
1152
2.02k
          PelUnitBuf recoBuf = cs.picture->getRecoBuf();
1153
2.02k
          const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1154
5.61k
          for( int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++ )
1155
3.58k
          {
1156
3.58k
            encSlice->m_pALF->getStatisticsCTU( *cs.picture, cs, recoBuf, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1157
3.58k
          }
1158
2.02k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1159
2.02k
        }
1160
1161
2.03k
        ITT_TASKEND( itt_domain_encode, itt_handle_alf_stat );
1162
1163
        // start alf filter derivation either for a sub-set of CTUs (syncLines mode) or for the whole picture (regular mode)
1164
2.03k
        const unsigned deriveFilterCtu = encSlice->m_alfDeriveCtu;
1165
2.03k
        processStates[ctuRsAddr] = (ctuRsAddr < deriveFilterCtu) ? ALF_RECONSTRUCT: ALF_DERIVE_FILTER;
1166
2.03k
      }
1167
0
      break;
1168
1169
1.24M
    case ALF_DERIVE_FILTER:
1170
1.24M
      {
1171
1.24M
        const unsigned deriveFilterCtu = encSlice->m_alfDeriveCtu;
1172
1.24M
        if( ctuRsAddr == deriveFilterCtu )
1173
1.24M
        {
1174
          // ensure statistics from all previous ctu's have been collected
1175
1.24M
          int numCheckLines = deriveFilterCtu / pcv.widthInCtus + 1;
1176
1.25M
          for( int y = 0; y < numCheckLines; y++ )
1177
1.25M
          {
1178
1.26M
            for( int tileCol = 0; tileCol < slice.pps->numTileCols; tileCol++ )
1179
1.25M
            {
1180
1.25M
              const int lastCtuInTileRow = y * pcv.widthInCtus + slice.pps->tileColBd[tileCol] + slice.pps->tileColWidth[tileCol] - 1;
1181
1.25M
              if( processStates[lastCtuInTileRow] <= ALF_GET_STATISTICS )
1182
1.24M
                return false;
1183
1.25M
            }
1184
1.25M
          }
1185
1.24M
        }
1186
0
        else if( syncLines )
1187
0
        {
1188
          // ALF bitstream coding dependency for the sub-sequent ctu-lines
1189
0
          if( processStates[deriveFilterCtu] < ALF_RECONSTRUCT || checkCtuTaskNbTop( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, ALF_DERIVE_FILTER ) ) 
1190
0
            return false;
1191
0
        }
1192
2.29k
        if( checkReadyState )
1193
1.14k
          return true;
1194
1195
1.14k
        ITT_TASKSTART( itt_domain_encode, itt_handle_alf_derive );
1196
        // ALF post-processing
1197
1.14k
        if( slice.sps->alfEnabled )
1198
1.14k
        {
1199
1.14k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_ALF, &cs, CH_L );
1200
1.14k
          if( ctuRsAddr == deriveFilterCtu )
1201
1.14k
          {
1202
1.14k
            encSlice->m_pALF->initDerivation( slice );
1203
1.14k
            encSlice->m_pALF->deriveFilter( *cs.picture, cs, slice.getLambdas(), deriveFilterCtu + 1 );
1204
1.14k
            encSlice->m_pALF->reconstructCoeffAPSs( cs, cs.slice->alfEnabled[COMP_Y], cs.slice->alfEnabled[COMP_Cb] || cs.slice->alfEnabled[COMP_Cr], false );
1205
1.14k
          }
1206
0
          else if( syncLines )
1207
0
          {
1208
            // in sync lines mode: derive/select filter for the remaining lines
1209
0
            TileLineEncRsrc* lineEncRsrc = encSlice->m_TileLineEncRsrc[ lineIdx ];
1210
0
            PerThreadRsrc*   taskRsrc    = encSlice->m_ThreadRsrc[ threadIdx ];
1211
0
            const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1212
0
            for(int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++)
1213
0
            {
1214
0
              encSlice->m_pALF->selectFilterForCTU( cs, &lineEncRsrc->m_AlfCABACEstimator, &taskRsrc->m_CtxCache, ctu );
1215
0
            }
1216
0
          }
1217
1.14k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1218
1.14k
        }
1219
1220
1.14k
        ITT_TASKEND( itt_domain_encode, itt_handle_alf_derive );
1221
1.14k
        processStates[ ctuRsAddr ] = ALF_RECONSTRUCT;
1222
1.14k
      }
1223
0
      break;
1224
1225
6.77M
    case ALF_RECONSTRUCT:
1226
6.77M
      {
1227
        // start alf filter derivation either for a sub-set of CTUs (syncLines mode) or for the whole picture (regular mode)
1228
6.77M
        const unsigned deriveFilterCtu = encSlice->m_alfDeriveCtu;
1229
6.77M
        if( processStates[deriveFilterCtu] < ALF_RECONSTRUCT )
1230
6.77M
          return false;
1231
4.05k
        else if( syncLines && ctuRsAddr > deriveFilterCtu && encSlice->m_pALF->getAsuHeightInCtus() > 1 )
1232
0
        {
1233
0
          const int asuHeightInCtus = encSlice->m_pALF->getAsuHeightInCtus();
1234
0
          const int botCtuLineInAsu = std::min( (( ctuPosY & ( ~(asuHeightInCtus - 1) ) ) + asuHeightInCtus - 1), (int)pcv.heightInCtus - 1 );
1235
0
          if( processStates[botCtuLineInAsu * ctuStride + ctuPosX] < ALF_RECONSTRUCT ) 
1236
0
            return false;
1237
0
        }
1238
1239
4.05k
        if( checkReadyState )
1240
2.01k
          return true;
1241
1242
2.04k
        ITT_TASKSTART( itt_domain_encode, itt_handle_alf_recon );
1243
1244
2.04k
        if( slice.sps->alfEnabled )
1245
2.02k
        {
1246
2.02k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_ALF, &cs, CH_L );
1247
2.02k
          const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1248
5.61k
          for( int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++ )
1249
3.58k
          {
1250
3.58k
            encSlice->m_pALF->reconstructCTU_MT( *cs.picture, cs, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1251
3.58k
          }
1252
2.02k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1253
2.02k
        }
1254
1255
2.04k
        ITT_TASKEND( itt_domain_encode, itt_handle_alf_recon );
1256
2.04k
        processStates[ctuRsAddr] = CCALF_GET_STATISTICS;
1257
2.04k
      }
1258
      // dont break, no additional deps, can continue straigt away!
1259
      //break;
1260
1261
5.41k
    case CCALF_GET_STATISTICS:
1262
5.41k
      {
1263
5.41k
        if( checkCtuTaskNbTop   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, ALF_RECONSTRUCT ) ) return false;
1264
3.68k
        if( checkCtuTaskNbBot   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, ALF_RECONSTRUCT ) ) return false;
1265
1266
2.79k
        if( checkReadyState )
1267
755
          return true;
1268
1269
2.04k
        ITT_TASKSTART( itt_domain_encode, itt_handle_ccalf_stat );
1270
1271
        // ALF pre-processing
1272
2.04k
        if( slice.sps->ccalfEnabled )
1273
2.02k
        {
1274
2.02k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_ALF, &cs, CH_L);
1275
2.02k
          const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1276
5.61k
          for( int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++ )
1277
3.59k
          {
1278
3.59k
            encSlice->m_pALF->deriveStatsForCcAlfFilteringCTU( cs, COMP_Cb, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1279
3.59k
            encSlice->m_pALF->deriveStatsForCcAlfFilteringCTU( cs, COMP_Cr, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1280
3.59k
          }
1281
2.02k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1282
2.02k
        }
1283
1284
2.04k
        ITT_TASKEND( itt_domain_encode, itt_handle_ccalf_stat );
1285
1286
        // start alf filter derivation either for a sub-set of CTUs (syncLines mode) or for the whole picture (regular mode)
1287
2.04k
        processStates[ctuRsAddr] = (ctuRsAddr < encSlice->m_ccalfDeriveCtu) ? CCALF_RECONSTRUCT: CCALF_DERIVE_FILTER;
1288
2.04k
      }
1289
0
      break;
1290
1291
144k
    case CCALF_DERIVE_FILTER:
1292
144k
      {
1293
        // synchronization dependencies
1294
144k
        const unsigned deriveFilterCtu = encSlice->m_ccalfDeriveCtu;
1295
144k
        if( ctuRsAddr == deriveFilterCtu )
1296
144k
        {
1297
          // ensure statistics from all previous ctu's have been collected
1298
144k
          int numCheckLines = deriveFilterCtu / pcv.widthInCtus + 1;
1299
149k
          for( int y = 0; y < numCheckLines; y++ )
1300
147k
          {
1301
153k
            for( int tileCol = 0; tileCol < slice.pps->numTileCols; tileCol++ )
1302
147k
            {
1303
147k
              const int lastCtuInTileRow = y * pcv.widthInCtus + slice.pps->tileColBd[tileCol] + slice.pps->tileColWidth[tileCol] - 1;
1304
147k
              if( processStates[lastCtuInTileRow] <= CCALF_GET_STATISTICS )
1305
142k
                return false;
1306
147k
            }
1307
147k
          }
1308
144k
        }
1309
0
        else if( syncLines )
1310
0
        {
1311
          // ALF bitstream coding dependency for the sub-sequent CTU-lines
1312
0
          if( processStates[deriveFilterCtu] < CCALF_RECONSTRUCT || checkCtuTaskNbTop( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, CCALF_DERIVE_FILTER ) ) 
1313
0
            return false;
1314
0
        }
1315
2.29k
        if( checkReadyState )
1316
1.14k
          return true;
1317
1318
1.14k
        ITT_TASKSTART( itt_domain_encode, itt_handle_ccalf_derive );
1319
1320
        // start task
1321
1.14k
        if( slice.sps->ccalfEnabled )
1322
1.14k
        {
1323
1.14k
          if( ctuRsAddr == deriveFilterCtu )
1324
1.14k
          {
1325
1.14k
            encSlice->m_pALF->deriveCcAlfFilter( *cs.picture, cs, encSlice->m_ccalfDeriveCtu + 1 );
1326
1.14k
          }
1327
0
          else if( syncLines )
1328
0
          {
1329
            // in sync lines mode: derive/select filter for the remaining lines
1330
0
            TileLineEncRsrc* lineEncRsrc = encSlice->m_TileLineEncRsrc[ lineIdx ];
1331
0
            PerThreadRsrc*   taskRsrc    = encSlice->m_ThreadRsrc[ threadIdx ];
1332
0
            const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1333
0
            encSlice->m_pALF->selectCcAlfFilterForCtuLine( cs, COMP_Cb, cs.getRecoBuf(), &lineEncRsrc->m_AlfCABACEstimator, &taskRsrc->m_CtxCache, firstCtuInRow, ctuRsAddr );
1334
0
            encSlice->m_pALF->selectCcAlfFilterForCtuLine( cs, COMP_Cr, cs.getRecoBuf(), &lineEncRsrc->m_AlfCABACEstimator, &taskRsrc->m_CtxCache, firstCtuInRow, ctuRsAddr );
1335
0
          }
1336
1.14k
        }
1337
1.14k
        ITT_TASKEND( itt_domain_encode, itt_handle_ccalf_derive );
1338
1339
1.14k
        processStates[ctuRsAddr] = CCALF_RECONSTRUCT;
1340
1.14k
      }
1341
0
      break;
1342
1343
8.61k
    case CCALF_RECONSTRUCT:
1344
8.61k
      {
1345
        // start ccalf filter derivation either for a sub-set of CTUs (syncLines mode) or for the whole picture (regular mode)
1346
8.61k
        const unsigned deriveFilterCtu = encSlice->m_ccalfDeriveCtu;
1347
8.61k
        if( processStates[deriveFilterCtu] < CCALF_RECONSTRUCT )
1348
4.55k
          return false;
1349
1350
4.05k
        if( syncLines )
1351
0
        {
1352
          // ensure line-by-line reconstruction due to line synchronization
1353
0
          if( checkCtuTaskNbTop( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, CCALF_RECONSTRUCT ) ) return false;
1354
          // check bottom due to rec. buffer usage in ccalf statistics
1355
0
          if( checkCtuTaskNbBot( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, CCALF_GET_STATISTICS ) ) return false;
1356
0
        }
1357
1358
4.05k
        if( checkReadyState )
1359
2.03k
          return true;
1360
1361
2.02k
        ITT_TASKSTART( itt_domain_encode, itt_handle_ccalf_recon );
1362
1363
2.02k
        if( slice.sps->ccalfEnabled )
1364
2.02k
        {
1365
2.02k
          const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1366
5.61k
          for( int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++ )
1367
3.58k
          {
1368
3.58k
            encSlice->m_pALF->applyCcAlfFilterCTU( cs, COMP_Cb, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1369
3.58k
            encSlice->m_pALF->applyCcAlfFilterCTU( cs, COMP_Cr, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1370
3.58k
          }
1371
2.02k
        }
1372
1373
2.02k
        ITT_TASKEND( itt_domain_encode, itt_handle_ccalf_recon );
1374
1375
        // extend pic border
1376
        // CCALF reconstruction stage is done per tile, ensure that all tiles in current CTU row are done  
1377
2.02k
        if( ++(pic->m_tileColsDone->at(ctuPosY)) >= pps.numTileCols )
1378
2.01k
        {
1379
2.01k
          PelUnitBuf recoBuf = cs.picture->getRecoBuf();
1380
2.01k
          const int margin = cs.picture->margin;
1381
2.01k
          recoBuf.extendBorderPelLft( y, height, margin );
1382
2.01k
          recoBuf.extendBorderPelRgt( y, height, margin );
1383
2.01k
          if(ctuPosY == 0)
1384
1.14k
            recoBuf.extendBorderPelTop( -margin, pcv.lumaWidth + 2 * margin, margin );
1385
2.01k
          if(ctuPosY + 1 == pcv.heightInCtus)
1386
1.14k
            recoBuf.extendBorderPelBot( -margin, pcv.lumaWidth + 2 * margin, margin );
1387
1388
          // for IFP lines synchro, do an additional increment signaling that CTU row is ready
1389
2.01k
          if( syncLines )
1390
0
            ++(pic->m_tileColsDone->at( ctuPosY ));
1391
2.01k
        }
1392
1393
        // perform finish only once for whole picture
1394
2.02k
        const unsigned finishCtu = pcv.sizeInCtus - 1;
1395
2.02k
        if( ctuRsAddr < finishCtu )
1396
884
        {
1397
884
          processStates[ctuRsAddr] = PROCESS_DONE;
1398
          // processing done => terminate thread
1399
884
          return true;
1400
884
        }
1401
1.14k
        processStates[ctuRsAddr] = FINISH_SLICE;
1402
1.14k
      }
1403
1404
13.4k
    case FINISH_SLICE:
1405
13.4k
      {
1406
13.4k
        CHECK( ctuRsAddr != pcv.sizeInCtus - 1, "invalid state, finish slice only once for last ctu" );
1407
1408
        // ensure all coding tasks have been done for all previous ctu's
1409
28.4k
        for( int i = 0; i < ctuRsAddr; i++ )
1410
26.7k
          if( processStates[ i ] < FINISH_SLICE )
1411
11.7k
            return false;
1412
1413
1.70k
        if( checkReadyState )
1414
564
          return true;
1415
1416
1.14k
        encSlice->finishCompressSlice( cs.picture, slice );
1417
1418
1.14k
        processStates[ ctuRsAddr ] = PROCESS_DONE;
1419
        // processing done => terminate thread
1420
1.14k
        return true;
1421
1.70k
      }
1422
1423
0
    case PROCESS_DONE:
1424
0
      CHECK( true, "process state is PROCESS_DONE, but thread is still running" );
1425
0
      return true;
1426
1427
0
    default:
1428
0
      CHECK( true, "unknown process state" );
1429
0
      return true;
1430
41.6M
  }
1431
1432
19.1k
  return false;
1433
41.6M
}
bool vvenc::EncSlice::xProcessCtuTask<false>(int, void*)
Line
Count
Source
883
24.0k
{
884
24.0k
  CtuEncParam* ctuEncParam       = static_cast<CtuEncParam*>( taskParam );
885
24.0k
  Picture* pic                   = ctuEncParam->pic;
886
24.0k
  EncSlice* encSlice             = ctuEncParam->encSlice;
887
24.0k
  CodingStructure& cs            = *pic->cs;
888
24.0k
  Slice&           slice         = *cs.slice;
889
24.0k
  const PPS&       pps           = *slice.pps;
890
24.0k
  const PreCalcValues& pcv       = *cs.pcv;
891
24.0k
  const int ctuRsAddr            = ctuEncParam->ctuRsAddr;
892
24.0k
  const int ctuPosX              = ctuEncParam->ctuPosX;
893
24.0k
  const int ctuPosY              = ctuEncParam->ctuPosY;
894
24.0k
  const int x                    = ctuPosX << pcv.maxCUSizeLog2;
895
24.0k
  const int y                    = ctuPosY << pcv.maxCUSizeLog2;
896
24.0k
  const int width                = std::min( pcv.maxCUSize, pcv.lumaWidth  - x );
897
24.0k
  const int height               = std::min( pcv.maxCUSize, pcv.lumaHeight - y );
898
24.0k
  const int ctuStride            = pcv.widthInCtus;
899
24.0k
  const int lineIdx              = ctuEncParam->tileLineResIdx;
900
24.0k
  ProcessCtuState* processStates = encSlice->m_processStates.data();
901
24.0k
  const UnitArea& ctuArea        = ctuEncParam->ctuArea;
902
24.0k
  const bool wppSyncEnabled      = cs.sps->entropyCodingSyncEnabled;
903
24.0k
  const TaskType currState       = processStates[ ctuRsAddr ];
904
24.0k
  const unsigned syncLines       = encSlice->m_pcEncCfg->m_ifpLines;
905
906
24.0k
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "poc", cs.slice->poc ) );
907
24.0k
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "ctu", ctuRsAddr ) );
908
24.0k
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "final", processStates[ ctuRsAddr ] == CTU_ENCODE ? 0 : 1 ) );
909
910
  // process ctu's line wise from left to right
911
24.0k
  const bool tileParallel = encSlice->m_pcEncCfg->m_tileParallelCtuEnc;
912
24.0k
  if( tileParallel && currState == CTU_ENCODE && ctuPosX > 0 && slice.pps->getTileIdx( ctuPosX, ctuPosY ) != slice.pps->getTileIdx( ctuPosX - 1, ctuPosY ) )
913
0
    ; // for CTU_ENCODE on tile boundaries, allow parallel processing of tiles
914
24.0k
  else if( ctuPosX > 0 && processStates[ ctuRsAddr - 1 ] <= currState && currState < PROCESS_DONE )
915
0
    return false;
916
917
24.0k
  switch( currState )
918
24.0k
  {
919
    // encode
920
3.59k
    case CTU_ENCODE:
921
3.59k
      {
922
        // CTU line-wise inter-frame parallel processing synchronization
923
3.59k
        if( syncLines )
924
0
        {
925
0
          const bool lineStart = ctuPosX == 0 || ( tileParallel && slice.pps->getTileIdx( ctuPosX, ctuPosY ) != slice.pps->getTileIdx( ctuPosX - 1, ctuPosY ) );
926
0
          if( lineStart && !refPicCtuLineReady( slice, ctuPosY + (int)syncLines, pcv ) )
927
0
          {
928
0
            return false;
929
0
          }
930
0
        }
931
932
        // general wpp conditions, top and top-right ctu have to be encoded
933
3.59k
        if( encSlice->m_pcEncCfg->m_tileParallelCtuEnc && ctuPosY > 0 && slice.pps->getTileIdx( ctuPosX, ctuPosY ) != slice.pps->getTileIdx( ctuPosX, ctuPosY - 1 ) )
934
0
          ; // allow parallel processing of CTU-encoding on independent tiles
935
3.59k
        else if( ctuPosY > 0                                  && processStates[ ctuRsAddr - ctuStride     ] <= CTU_ENCODE )
936
0
          return false;
937
3.59k
        else if( ctuPosY > 0 && ctuPosX + 1 < pcv.widthInCtus && processStates[ ctuRsAddr - ctuStride + 1 ] <= CTU_ENCODE && !wppSyncEnabled )
938
0
          return false;
939
        
940
3.59k
        if( checkReadyState )
941
0
          return true;
942
943
#ifdef TRACE_ENABLE_ITT
944
        std::stringstream ss;
945
        ss << "Encode_" << slice.poc << "_CTU_" << ctuPosY << "_" << ctuPosX;
946
        __itt_string_handle* itt_handle_ctuEncode = __itt_string_handle_create( ss.str().c_str() );
947
#endif
948
3.59k
        ITT_TASKSTART( itt_domain_encode, itt_handle_ctuEncode );
949
950
3.59k
        TileLineEncRsrc* lineEncRsrc = encSlice->m_TileLineEncRsrc[ lineIdx ];
951
3.59k
        PerThreadRsrc* taskRsrc      = encSlice->m_ThreadRsrc[ threadIdx ];
952
3.59k
        EncCu& encCu                 = taskRsrc->m_encCu;
953
954
3.59k
        encCu.setCtuEncRsrc( &lineEncRsrc->m_CABACEstimator, &taskRsrc->m_CtxCache, &lineEncRsrc->m_ReuseUniMv, &lineEncRsrc->m_BlkUniMvInfoBuffer, &lineEncRsrc->m_AffineProfList, &lineEncRsrc->m_CachedBvs );
955
3.59k
        encCu.encodeCtu( pic, lineEncRsrc->m_prevQp, ctuPosX, ctuPosY );
956
957
        // cleanup line memory when last ctu in line done to reduce overall memory consumption
958
3.59k
        if( encSlice->m_pcEncCfg->m_ensureWppBitEqual && ( ctuPosX == pcv.widthInCtus - 1 || slice.pps->getTileIdx( ctuPosX, ctuPosY ) != slice.pps->getTileIdx( ctuPosX + 1, ctuPosY ) ) )
959
2.03k
        {
960
2.03k
          lineEncRsrc->m_AffineProfList    .resetAffineMVList();
961
2.03k
          lineEncRsrc->m_BlkUniMvInfoBuffer.resetUniMvList();
962
2.03k
          lineEncRsrc->m_ReuseUniMv        .resetReusedUniMvs();
963
2.03k
          lineEncRsrc->m_CachedBvs         .resetIbcBvCand();
964
2.03k
        }
965
966
3.59k
        DTRACE_UPDATE( g_trace_ctx, std::make_pair( "final", 1 ) );
967
3.59k
        ITT_TASKEND( itt_domain_encode, itt_handle_ctuEncode );
968
969
3.59k
        processStates[ ctuRsAddr ] = LF_VER;
970
3.59k
      }
971
0
      break;
972
973
    // vertical loopfilter
974
3.59k
    case LF_VER:
975
3.59k
      {
976
        // clip check to right tile border (CTU_ENCODE pre-processing delay due to IBC)
977
3.59k
        const int tileCol = slice.pps->ctuToTileCol[ctuPosX];
978
3.59k
        const int lastCtuPosXInTile = slice.pps->tileColBd[tileCol] + slice.pps->tileColWidth[tileCol] - 1;
979
3.59k
        const int checkRight = std::min<int>( encSlice->m_ctuEncDelay, lastCtuPosXInTile - ctuPosX );
980
981
3.59k
        const bool hasTiles = encSlice->m_pcEncCfg->m_tileParallelCtuEnc && slice.pps->getNumTiles() > 1;
982
983
        // need to check line above bcs of tiling, which allows CTU_ENCODE to run independently across tiles
984
3.59k
        if( hasTiles )
985
0
        {
986
0
          if( ctuPosY > 0 )
987
0
          {
988
0
            for( int i = -!!ctuPosX; i <= checkRight; i++ )
989
0
              if( pps.canFilterCtuBdry( ctuPosX, ctuPosY, i, -1 ) && processStates[ctuRsAddr - ctuStride + i] <= CTU_ENCODE )
990
0
                return false;
991
0
          }
992
0
        }
993
        
994
        // ensure all surrounding ctu's are encoded (intra pred requires non-reshaped and unfiltered residual, IBC requires unfiltered samples too)
995
        // check right with max offset (due to WPP condition above, this implies top-right has been already encoded)
996
7.18k
        for( int i = hasTiles ? -!!ctuPosX : checkRight; i <= checkRight; i++ )
997
3.59k
          if( pps.canFilterCtuBdry( ctuPosX, ctuPosY, i, 0 ) && processStates[ctuRsAddr + i] <= CTU_ENCODE )
998
0
            return false;
999
1000
        // check bottom right with 1 CTU delay (this is only required for intra pred)
1001
        // at the right picture border this will check the bottom CTU
1002
3.59k
        const int checkBottomRight = std::min<int>( 1, lastCtuPosXInTile - ctuPosX );
1003
3.59k
        if( checkCtuTaskNbBotRgt( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, CTU_ENCODE, checkBottomRight ) ) 
1004
0
          return false;
1005
1006
3.59k
        if( checkReadyState )
1007
0
          return true;
1008
1009
3.59k
        ITT_TASKSTART( itt_domain_encode, itt_handle_rspLfVer );
1010
1011
        // loopfilter
1012
3.59k
        if( !cs.pps->deblockingFilterControlPresent || !cs.pps->deblockingFilterDisabled || cs.pps->deblockingFilterOverrideEnabled )
1013
3.58k
        {
1014
3.58k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_DEBLOCK_FILTER, &cs, CH_L );
1015
          // calculate filter strengths
1016
3.58k
          encSlice->m_pLoopFilter->calcFilterStrengthsCTU( cs, ctuArea, true );
1017
1018
          // vertical filter
1019
3.58k
          PelUnitBuf reco = cs.picture->getRecoBuf();
1020
3.58k
          encSlice->m_pLoopFilter->xDeblockArea<EDGE_VER>( cs, ctuArea, MAX_NUM_CH, reco );
1021
3.58k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1022
3.58k
        }
1023
1024
3.59k
        ITT_TASKEND( itt_domain_encode, itt_handle_rspLfVer );
1025
1026
3.59k
        processStates[ ctuRsAddr ] = LF_HOR;
1027
3.59k
      }
1028
0
      break;
1029
1030
    // horizontal loopfilter
1031
3.58k
    case LF_HOR:
1032
3.58k
      {
1033
        // ensure horizontal ordering (from top to bottom)
1034
3.58k
        if( checkCtuTaskNbTop   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_HOR ) )         
1035
0
          return false;
1036
1037
        // ensure vertical loop filter of neighbor ctu's will not modify current residual
1038
        // check top, top-right and right ctu
1039
        // (top, top-right checked implicitly due to ordering check above)
1040
3.58k
        if( checkCtuTaskNbRgt   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_VER ) )
1041
0
          return false;
1042
1043
3.58k
        if( checkReadyState )
1044
0
          return true;
1045
1046
3.58k
        ITT_TASKSTART( itt_domain_encode, itt_handle_lfHor );
1047
1048
3.58k
        if( !cs.pps->deblockingFilterControlPresent || !cs.pps->deblockingFilterDisabled || cs.pps->deblockingFilterOverrideEnabled )
1049
3.58k
        {
1050
3.58k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_DEBLOCK_FILTER, &cs, CH_L );
1051
3.58k
          PelUnitBuf reco = cs.picture->getRecoBuf();
1052
3.58k
          encSlice->m_pLoopFilter->xDeblockArea<EDGE_HOR>( cs, ctuArea, MAX_NUM_CH, reco );
1053
3.58k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1054
3.58k
        }
1055
1056
3.58k
        ITT_TASKEND( itt_domain_encode, itt_handle_lfHor );
1057
1058
3.58k
        processStates[ ctuRsAddr ] = SAO_FILTER;
1059
3.58k
      }
1060
0
      break;
1061
1062
    // SAO filter
1063
3.58k
    case SAO_FILTER:
1064
3.58k
      {
1065
        // general wpp conditions, top and top-right ctu have to be filtered
1066
3.58k
        if( checkCtuTaskNbTop   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER, true ) ) return false;
1067
3.58k
        if( checkCtuTaskNbTopRgt( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER, true ) ) return false;
1068
1069
        // ensure loop filter of neighbor ctu's will not modify current residual
1070
        // sao processing dependents on +1 pixel to each side
1071
        // due to wpp condition above, only right, bottom and bottom-right ctu have to be checked
1072
3.58k
        if( checkCtuTaskNbRgt   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_HOR,    true ) ) return false;
1073
3.58k
        if( checkCtuTaskNbBot   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_HOR,    true ) ) return false;
1074
3.58k
        if( checkCtuTaskNbBotRgt( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_HOR, 1, true ) ) return false;
1075
1076
3.58k
        if( checkReadyState )
1077
0
          return true;
1078
1079
3.58k
        ITT_TASKSTART( itt_domain_encode, itt_handle_sao );
1080
1081
        // SAO filter
1082
3.58k
        if( slice.sps->saoEnabled && pic->useSAO )
1083
3.58k
        {
1084
3.58k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_SAO, &cs, CH_L );
1085
3.58k
          TileLineEncRsrc* lineEncRsrc    = encSlice->m_TileLineEncRsrc[ lineIdx ];
1086
3.58k
          PerThreadRsrc* taskRsrc         = encSlice->m_ThreadRsrc[ threadIdx ];
1087
3.58k
          EncSampleAdaptiveOffset& encSao = lineEncRsrc->m_encSao;
1088
1089
3.58k
          encSao.setCtuEncRsrc( &lineEncRsrc->m_SaoCABACEstimator, &taskRsrc->m_CtxCache );
1090
3.58k
          encSao.storeCtuReco( cs, ctuArea, ctuPosX, ctuPosY );
1091
3.58k
          encSao.getCtuStatistics( cs, encSlice->m_saoStatData, ctuArea, ctuRsAddr );
1092
3.58k
          encSao.decideCtuParams( cs, encSlice->m_saoStatData, encSlice->m_saoEnabled, encSlice->m_saoAllDisabled, ctuArea, ctuRsAddr, &encSlice->m_saoReconParams[ 0 ], cs.picture->getSAO() );
1093
3.58k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1094
3.58k
        }
1095
1096
        // ALF border extension
1097
3.58k
        if( cs.sps->alfEnabled )
1098
3.59k
        {
1099
          // we have to do some kind of position aware boundary padding
1100
          // it's done here because the conditions are readable
1101
3.59k
          PelUnitBuf recoBuf = cs.picture->getRecoBuf();
1102
3.59k
          const int fltSize  = ( MAX_ALF_FILTER_LENGTH + 1 ) >> 1;
1103
3.59k
          const int xL       = ( ctuPosX == 0 )                 ? ( x-fltSize       ) : ( x );
1104
3.59k
          const int xR       = ( ctuPosX+1 == pcv.widthInCtus ) ? ( x+width+fltSize ) : ( x+width );
1105
1106
3.59k
          if( ctuPosX == 0 )                  recoBuf.extendBorderPelLft( y, height, fltSize );
1107
3.59k
          if( ctuPosX+1 == pcv.widthInCtus )  recoBuf.extendBorderPelRgt( y, height, fltSize );
1108
3.59k
          if( ctuPosY == 0 )                  recoBuf.extendBorderPelTop( xL, xR-xL, fltSize );
1109
3.59k
          if( ctuPosY+1 == pcv.heightInCtus ) recoBuf.extendBorderPelBot( xL, xR-xL, fltSize );
1110
1111
3.59k
          encSlice->m_pALF->copyCTUforALF(cs, ctuPosX, ctuPosY);
1112
3.59k
        }
1113
1114
        // DMVR refinement can be stored now
1115
3.59k
        if( slice.sps->DMVR && !slice.picHeader->disDmvrFlag )
1116
3.59k
        {
1117
3.59k
          CS::setRefinedMotionFieldCTU( cs, ctuPosX, ctuPosY );
1118
3.59k
        }
1119
3.58k
        ITT_TASKEND( itt_domain_encode, itt_handle_sao );
1120
1121
3.58k
        const int tileCol = slice.pps->ctuToTileCol[ctuPosX];
1122
3.58k
        const int lastCtuColInTileRow = slice.pps->tileColBd[tileCol] + slice.pps->tileColWidth[tileCol] - 1;
1123
3.58k
        if( ctuPosX == lastCtuColInTileRow )
1124
2.03k
        {
1125
2.03k
          processStates[ctuRsAddr] = ALF_GET_STATISTICS;
1126
2.03k
        }
1127
1.55k
        else
1128
1.55k
        {
1129
1.55k
          processStates[ctuRsAddr] = PROCESS_DONE;
1130
1.55k
          return true;
1131
1.55k
        }
1132
3.58k
      }
1133
2.03k
      break;
1134
1135
2.03k
    case ALF_GET_STATISTICS:
1136
2.03k
      {
1137
        // ensure all surrounding ctu's are filtered (ALF will use pixels of adjacent CTU's)
1138
        // due to wpp condition above in SAO_FILTER, only right, bottom and bottom-right ctu have to be checked
1139
2.03k
        if( checkCtuTaskNbRgt   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER ) ) return false;
1140
2.03k
        if( checkCtuTaskNbBot   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER ) ) return false;
1141
2.03k
        if( checkCtuTaskNbBotRgt( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER ) ) return false;
1142
1143
2.03k
        if( checkReadyState )
1144
0
          return true;
1145
1146
2.03k
        ITT_TASKSTART( itt_domain_encode, itt_handle_alf_stat );
1147
1148
        // ALF pre-processing
1149
2.03k
        if( slice.sps->alfEnabled )
1150
2.02k
        {
1151
2.02k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_ALF, &cs, CH_L );
1152
2.02k
          PelUnitBuf recoBuf = cs.picture->getRecoBuf();
1153
2.02k
          const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1154
5.61k
          for( int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++ )
1155
3.58k
          {
1156
3.58k
            encSlice->m_pALF->getStatisticsCTU( *cs.picture, cs, recoBuf, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1157
3.58k
          }
1158
2.02k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1159
2.02k
        }
1160
1161
2.03k
        ITT_TASKEND( itt_domain_encode, itt_handle_alf_stat );
1162
1163
        // start alf filter derivation either for a sub-set of CTUs (syncLines mode) or for the whole picture (regular mode)
1164
2.03k
        const unsigned deriveFilterCtu = encSlice->m_alfDeriveCtu;
1165
2.03k
        processStates[ctuRsAddr] = (ctuRsAddr < deriveFilterCtu) ? ALF_RECONSTRUCT: ALF_DERIVE_FILTER;
1166
2.03k
      }
1167
0
      break;
1168
1169
1.14k
    case ALF_DERIVE_FILTER:
1170
1.14k
      {
1171
1.14k
        const unsigned deriveFilterCtu = encSlice->m_alfDeriveCtu;
1172
1.14k
        if( ctuRsAddr == deriveFilterCtu )
1173
1.14k
        {
1174
          // ensure statistics from all previous ctu's have been collected
1175
1.14k
          int numCheckLines = deriveFilterCtu / pcv.widthInCtus + 1;
1176
3.17k
          for( int y = 0; y < numCheckLines; y++ )
1177
2.03k
          {
1178
4.06k
            for( int tileCol = 0; tileCol < slice.pps->numTileCols; tileCol++ )
1179
2.03k
            {
1180
2.03k
              const int lastCtuInTileRow = y * pcv.widthInCtus + slice.pps->tileColBd[tileCol] + slice.pps->tileColWidth[tileCol] - 1;
1181
2.03k
              if( processStates[lastCtuInTileRow] <= ALF_GET_STATISTICS )
1182
0
                return false;
1183
2.03k
            }
1184
2.03k
          }
1185
1.14k
        }
1186
0
        else if( syncLines )
1187
0
        {
1188
          // ALF bitstream coding dependency for the sub-sequent ctu-lines
1189
0
          if( processStates[deriveFilterCtu] < ALF_RECONSTRUCT || checkCtuTaskNbTop( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, ALF_DERIVE_FILTER ) ) 
1190
0
            return false;
1191
0
        }
1192
1.14k
        if( checkReadyState )
1193
0
          return true;
1194
1195
1.14k
        ITT_TASKSTART( itt_domain_encode, itt_handle_alf_derive );
1196
        // ALF post-processing
1197
1.14k
        if( slice.sps->alfEnabled )
1198
1.14k
        {
1199
1.14k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_ALF, &cs, CH_L );
1200
1.14k
          if( ctuRsAddr == deriveFilterCtu )
1201
1.14k
          {
1202
1.14k
            encSlice->m_pALF->initDerivation( slice );
1203
1.14k
            encSlice->m_pALF->deriveFilter( *cs.picture, cs, slice.getLambdas(), deriveFilterCtu + 1 );
1204
1.14k
            encSlice->m_pALF->reconstructCoeffAPSs( cs, cs.slice->alfEnabled[COMP_Y], cs.slice->alfEnabled[COMP_Cb] || cs.slice->alfEnabled[COMP_Cr], false );
1205
1.14k
          }
1206
0
          else if( syncLines )
1207
0
          {
1208
            // in sync lines mode: derive/select filter for the remaining lines
1209
0
            TileLineEncRsrc* lineEncRsrc = encSlice->m_TileLineEncRsrc[ lineIdx ];
1210
0
            PerThreadRsrc*   taskRsrc    = encSlice->m_ThreadRsrc[ threadIdx ];
1211
0
            const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1212
0
            for(int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++)
1213
0
            {
1214
0
              encSlice->m_pALF->selectFilterForCTU( cs, &lineEncRsrc->m_AlfCABACEstimator, &taskRsrc->m_CtxCache, ctu );
1215
0
            }
1216
0
          }
1217
1.14k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1218
1.14k
        }
1219
1220
1.14k
        ITT_TASKEND( itt_domain_encode, itt_handle_alf_derive );
1221
1.14k
        processStates[ ctuRsAddr ] = ALF_RECONSTRUCT;
1222
1.14k
      }
1223
0
      break;
1224
1225
2.03k
    case ALF_RECONSTRUCT:
1226
2.03k
      {
1227
        // start alf filter derivation either for a sub-set of CTUs (syncLines mode) or for the whole picture (regular mode)
1228
2.03k
        const unsigned deriveFilterCtu = encSlice->m_alfDeriveCtu;
1229
2.03k
        if( processStates[deriveFilterCtu] < ALF_RECONSTRUCT )
1230
0
          return false;
1231
2.03k
        else if( syncLines && ctuRsAddr > deriveFilterCtu && encSlice->m_pALF->getAsuHeightInCtus() > 1 )
1232
0
        {
1233
0
          const int asuHeightInCtus = encSlice->m_pALF->getAsuHeightInCtus();
1234
0
          const int botCtuLineInAsu = std::min( (( ctuPosY & ( ~(asuHeightInCtus - 1) ) ) + asuHeightInCtus - 1), (int)pcv.heightInCtus - 1 );
1235
0
          if( processStates[botCtuLineInAsu * ctuStride + ctuPosX] < ALF_RECONSTRUCT ) 
1236
0
            return false;
1237
0
        }
1238
1239
2.03k
        if( checkReadyState )
1240
0
          return true;
1241
1242
2.03k
        ITT_TASKSTART( itt_domain_encode, itt_handle_alf_recon );
1243
1244
2.03k
        if( slice.sps->alfEnabled )
1245
2.02k
        {
1246
2.02k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_ALF, &cs, CH_L );
1247
2.02k
          const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1248
5.61k
          for( int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++ )
1249
3.58k
          {
1250
3.58k
            encSlice->m_pALF->reconstructCTU_MT( *cs.picture, cs, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1251
3.58k
          }
1252
2.02k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1253
2.02k
        }
1254
1255
2.03k
        ITT_TASKEND( itt_domain_encode, itt_handle_alf_recon );
1256
2.03k
        processStates[ctuRsAddr] = CCALF_GET_STATISTICS;
1257
2.03k
      }
1258
      // dont break, no additional deps, can continue straigt away!
1259
      //break;
1260
1261
2.78k
    case CCALF_GET_STATISTICS:
1262
2.78k
      {
1263
2.78k
        if( checkCtuTaskNbTop   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, ALF_RECONSTRUCT ) ) return false;
1264
2.25k
        if( checkCtuTaskNbBot   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, ALF_RECONSTRUCT ) ) return false;
1265
1266
2.03k
        if( checkReadyState )
1267
0
          return true;
1268
1269
2.03k
        ITT_TASKSTART( itt_domain_encode, itt_handle_ccalf_stat );
1270
1271
        // ALF pre-processing
1272
2.03k
        if( slice.sps->ccalfEnabled )
1273
2.02k
        {
1274
2.02k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_ALF, &cs, CH_L);
1275
2.02k
          const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1276
5.61k
          for( int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++ )
1277
3.59k
          {
1278
3.59k
            encSlice->m_pALF->deriveStatsForCcAlfFilteringCTU( cs, COMP_Cb, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1279
3.59k
            encSlice->m_pALF->deriveStatsForCcAlfFilteringCTU( cs, COMP_Cr, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1280
3.59k
          }
1281
2.02k
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1282
2.02k
        }
1283
1284
2.03k
        ITT_TASKEND( itt_domain_encode, itt_handle_ccalf_stat );
1285
1286
        // start alf filter derivation either for a sub-set of CTUs (syncLines mode) or for the whole picture (regular mode)
1287
2.03k
        processStates[ctuRsAddr] = (ctuRsAddr < encSlice->m_ccalfDeriveCtu) ? CCALF_RECONSTRUCT: CCALF_DERIVE_FILTER;
1288
2.03k
      }
1289
0
      break;
1290
1291
1.14k
    case CCALF_DERIVE_FILTER:
1292
1.14k
      {
1293
        // synchronization dependencies
1294
1.14k
        const unsigned deriveFilterCtu = encSlice->m_ccalfDeriveCtu;
1295
1.14k
        if( ctuRsAddr == deriveFilterCtu )
1296
1.14k
        {
1297
          // ensure statistics from all previous ctu's have been collected
1298
1.14k
          int numCheckLines = deriveFilterCtu / pcv.widthInCtus + 1;
1299
3.17k
          for( int y = 0; y < numCheckLines; y++ )
1300
2.03k
          {
1301
4.06k
            for( int tileCol = 0; tileCol < slice.pps->numTileCols; tileCol++ )
1302
2.03k
            {
1303
2.03k
              const int lastCtuInTileRow = y * pcv.widthInCtus + slice.pps->tileColBd[tileCol] + slice.pps->tileColWidth[tileCol] - 1;
1304
2.03k
              if( processStates[lastCtuInTileRow] <= CCALF_GET_STATISTICS )
1305
0
                return false;
1306
2.03k
            }
1307
2.03k
          }
1308
1.14k
        }
1309
0
        else if( syncLines )
1310
0
        {
1311
          // ALF bitstream coding dependency for the sub-sequent CTU-lines
1312
0
          if( processStates[deriveFilterCtu] < CCALF_RECONSTRUCT || checkCtuTaskNbTop( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, CCALF_DERIVE_FILTER ) ) 
1313
0
            return false;
1314
0
        }
1315
1.14k
        if( checkReadyState )
1316
0
          return true;
1317
1318
1.14k
        ITT_TASKSTART( itt_domain_encode, itt_handle_ccalf_derive );
1319
1320
        // start task
1321
1.14k
        if( slice.sps->ccalfEnabled )
1322
1.14k
        {
1323
1.14k
          if( ctuRsAddr == deriveFilterCtu )
1324
1.14k
          {
1325
1.14k
            encSlice->m_pALF->deriveCcAlfFilter( *cs.picture, cs, encSlice->m_ccalfDeriveCtu + 1 );
1326
1.14k
          }
1327
0
          else if( syncLines )
1328
0
          {
1329
            // in sync lines mode: derive/select filter for the remaining lines
1330
0
            TileLineEncRsrc* lineEncRsrc = encSlice->m_TileLineEncRsrc[ lineIdx ];
1331
0
            PerThreadRsrc*   taskRsrc    = encSlice->m_ThreadRsrc[ threadIdx ];
1332
0
            const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1333
0
            encSlice->m_pALF->selectCcAlfFilterForCtuLine( cs, COMP_Cb, cs.getRecoBuf(), &lineEncRsrc->m_AlfCABACEstimator, &taskRsrc->m_CtxCache, firstCtuInRow, ctuRsAddr );
1334
0
            encSlice->m_pALF->selectCcAlfFilterForCtuLine( cs, COMP_Cr, cs.getRecoBuf(), &lineEncRsrc->m_AlfCABACEstimator, &taskRsrc->m_CtxCache, firstCtuInRow, ctuRsAddr );
1335
0
          }
1336
1.14k
        }
1337
1.14k
        ITT_TASKEND( itt_domain_encode, itt_handle_ccalf_derive );
1338
1339
1.14k
        processStates[ctuRsAddr] = CCALF_RECONSTRUCT;
1340
1.14k
      }
1341
0
      break;
1342
1343
2.03k
    case CCALF_RECONSTRUCT:
1344
2.03k
      {
1345
        // start ccalf filter derivation either for a sub-set of CTUs (syncLines mode) or for the whole picture (regular mode)
1346
2.03k
        const unsigned deriveFilterCtu = encSlice->m_ccalfDeriveCtu;
1347
2.03k
        if( processStates[deriveFilterCtu] < CCALF_RECONSTRUCT )
1348
0
          return false;
1349
1350
2.03k
        if( syncLines )
1351
0
        {
1352
          // ensure line-by-line reconstruction due to line synchronization
1353
0
          if( checkCtuTaskNbTop( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, CCALF_RECONSTRUCT ) ) return false;
1354
          // check bottom due to rec. buffer usage in ccalf statistics
1355
0
          if( checkCtuTaskNbBot( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, CCALF_GET_STATISTICS ) ) return false;
1356
0
        }
1357
1358
2.03k
        if( checkReadyState )
1359
0
          return true;
1360
1361
2.03k
        ITT_TASKSTART( itt_domain_encode, itt_handle_ccalf_recon );
1362
1363
2.03k
        if( slice.sps->ccalfEnabled )
1364
2.02k
        {
1365
2.02k
          const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1366
5.61k
          for( int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++ )
1367
3.58k
          {
1368
3.58k
            encSlice->m_pALF->applyCcAlfFilterCTU( cs, COMP_Cb, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1369
3.58k
            encSlice->m_pALF->applyCcAlfFilterCTU( cs, COMP_Cr, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1370
3.58k
          }
1371
2.02k
        }
1372
1373
2.03k
        ITT_TASKEND( itt_domain_encode, itt_handle_ccalf_recon );
1374
1375
        // extend pic border
1376
        // CCALF reconstruction stage is done per tile, ensure that all tiles in current CTU row are done  
1377
2.03k
        if( ++(pic->m_tileColsDone->at(ctuPosY)) >= pps.numTileCols )
1378
2.01k
        {
1379
2.01k
          PelUnitBuf recoBuf = cs.picture->getRecoBuf();
1380
2.01k
          const int margin = cs.picture->margin;
1381
2.01k
          recoBuf.extendBorderPelLft( y, height, margin );
1382
2.01k
          recoBuf.extendBorderPelRgt( y, height, margin );
1383
2.01k
          if(ctuPosY == 0)
1384
1.14k
            recoBuf.extendBorderPelTop( -margin, pcv.lumaWidth + 2 * margin, margin );
1385
2.01k
          if(ctuPosY + 1 == pcv.heightInCtus)
1386
1.14k
            recoBuf.extendBorderPelBot( -margin, pcv.lumaWidth + 2 * margin, margin );
1387
1388
          // for IFP lines synchro, do an additional increment signaling that CTU row is ready
1389
2.01k
          if( syncLines )
1390
0
            ++(pic->m_tileColsDone->at( ctuPosY ));
1391
2.01k
        }
1392
1393
        // perform finish only once for whole picture
1394
2.03k
        const unsigned finishCtu = pcv.sizeInCtus - 1;
1395
2.03k
        if( ctuRsAddr < finishCtu )
1396
884
        {
1397
884
          processStates[ctuRsAddr] = PROCESS_DONE;
1398
          // processing done => terminate thread
1399
884
          return true;
1400
884
        }
1401
1.14k
        processStates[ctuRsAddr] = FINISH_SLICE;
1402
1.14k
      }
1403
1404
1.71k
    case FINISH_SLICE:
1405
1.71k
      {
1406
1.71k
        CHECK( ctuRsAddr != pcv.sizeInCtus - 1, "invalid state, finish slice only once for last ctu" );
1407
1408
        // ensure all coding tasks have been done for all previous ctu's
1409
4.62k
        for( int i = 0; i < ctuRsAddr; i++ )
1410
3.48k
          if( processStates[ i ] < FINISH_SLICE )
1411
564
            return false;
1412
1413
1.14k
        if( checkReadyState )
1414
0
          return true;
1415
1416
1.14k
        encSlice->finishCompressSlice( cs.picture, slice );
1417
1418
1.14k
        processStates[ ctuRsAddr ] = PROCESS_DONE;
1419
        // processing done => terminate thread
1420
1.14k
        return true;
1421
1.14k
      }
1422
1423
0
    case PROCESS_DONE:
1424
0
      CHECK( true, "process state is PROCESS_DONE, but thread is still running" );
1425
0
      return true;
1426
1427
0
    default:
1428
0
      CHECK( true, "unknown process state" );
1429
0
      return true;
1430
24.0k
  }
1431
1432
19.1k
  return false;
1433
24.0k
}
bool vvenc::EncSlice::xProcessCtuTask<true>(int, void*)
Line
Count
Source
883
92.9M
{
884
92.9M
  CtuEncParam* ctuEncParam       = static_cast<CtuEncParam*>( taskParam );
885
92.9M
  Picture* pic                   = ctuEncParam->pic;
886
92.9M
  EncSlice* encSlice             = ctuEncParam->encSlice;
887
92.9M
  CodingStructure& cs            = *pic->cs;
888
92.9M
  Slice&           slice         = *cs.slice;
889
92.9M
  const PPS&       pps           = *slice.pps;
890
92.9M
  const PreCalcValues& pcv       = *cs.pcv;
891
92.9M
  const int ctuRsAddr            = ctuEncParam->ctuRsAddr;
892
92.9M
  const int ctuPosX              = ctuEncParam->ctuPosX;
893
92.9M
  const int ctuPosY              = ctuEncParam->ctuPosY;
894
92.9M
  const int x                    = ctuPosX << pcv.maxCUSizeLog2;
895
92.9M
  const int y                    = ctuPosY << pcv.maxCUSizeLog2;
896
92.9M
  const int width                = std::min( pcv.maxCUSize, pcv.lumaWidth  - x );
897
92.9M
  const int height               = std::min( pcv.maxCUSize, pcv.lumaHeight - y );
898
92.9M
  const int ctuStride            = pcv.widthInCtus;
899
92.9M
  const int lineIdx              = ctuEncParam->tileLineResIdx;
900
92.9M
  ProcessCtuState* processStates = encSlice->m_processStates.data();
901
92.9M
  const UnitArea& ctuArea        = ctuEncParam->ctuArea;
902
92.9M
  const bool wppSyncEnabled      = cs.sps->entropyCodingSyncEnabled;
903
92.9M
  const TaskType currState       = processStates[ ctuRsAddr ];
904
92.9M
  const unsigned syncLines       = encSlice->m_pcEncCfg->m_ifpLines;
905
906
92.9M
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "poc", cs.slice->poc ) );
907
92.9M
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "ctu", ctuRsAddr ) );
908
92.9M
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "final", processStates[ ctuRsAddr ] == CTU_ENCODE ? 0 : 1 ) );
909
910
  // process ctu's line wise from left to right
911
92.9M
  const bool tileParallel = encSlice->m_pcEncCfg->m_tileParallelCtuEnc;
912
92.9M
  if( tileParallel && currState == CTU_ENCODE && ctuPosX > 0 && slice.pps->getTileIdx( ctuPosX, ctuPosY ) != slice.pps->getTileIdx( ctuPosX - 1, ctuPosY ) )
913
0
    ; // for CTU_ENCODE on tile boundaries, allow parallel processing of tiles
914
92.9M
  else if( ctuPosX > 0 && processStates[ ctuRsAddr - 1 ] <= currState && currState < PROCESS_DONE )
915
51.3M
    return false;
916
917
41.6M
  switch( currState )
918
41.6M
  {
919
    // encode
920
21.1M
    case CTU_ENCODE:
921
21.1M
      {
922
        // CTU line-wise inter-frame parallel processing synchronization
923
21.1M
        if( syncLines )
924
0
        {
925
0
          const bool lineStart = ctuPosX == 0 || ( tileParallel && slice.pps->getTileIdx( ctuPosX, ctuPosY ) != slice.pps->getTileIdx( ctuPosX - 1, ctuPosY ) );
926
0
          if( lineStart && !refPicCtuLineReady( slice, ctuPosY + (int)syncLines, pcv ) )
927
0
          {
928
0
            return false;
929
0
          }
930
0
        }
931
932
        // general wpp conditions, top and top-right ctu have to be encoded
933
21.1M
        if( encSlice->m_pcEncCfg->m_tileParallelCtuEnc && ctuPosY > 0 && slice.pps->getTileIdx( ctuPosX, ctuPosY ) != slice.pps->getTileIdx( ctuPosX, ctuPosY - 1 ) )
934
0
          ; // allow parallel processing of CTU-encoding on independent tiles
935
21.1M
        else if( ctuPosY > 0                                  && processStates[ ctuRsAddr - ctuStride     ] <= CTU_ENCODE )
936
17.6M
          return false;
937
3.41M
        else if( ctuPosY > 0 && ctuPosX + 1 < pcv.widthInCtus && processStates[ ctuRsAddr - ctuStride + 1 ] <= CTU_ENCODE && !wppSyncEnabled )
938
3.41M
          return false;
939
        
940
3.53k
        if( checkReadyState )
941
3.58k
          return true;
942
943
#ifdef TRACE_ENABLE_ITT
944
        std::stringstream ss;
945
        ss << "Encode_" << slice.poc << "_CTU_" << ctuPosY << "_" << ctuPosX;
946
        __itt_string_handle* itt_handle_ctuEncode = __itt_string_handle_create( ss.str().c_str() );
947
#endif
948
18.4E
        ITT_TASKSTART( itt_domain_encode, itt_handle_ctuEncode );
949
950
18.4E
        TileLineEncRsrc* lineEncRsrc = encSlice->m_TileLineEncRsrc[ lineIdx ];
951
18.4E
        PerThreadRsrc* taskRsrc      = encSlice->m_ThreadRsrc[ threadIdx ];
952
18.4E
        EncCu& encCu                 = taskRsrc->m_encCu;
953
954
18.4E
        encCu.setCtuEncRsrc( &lineEncRsrc->m_CABACEstimator, &taskRsrc->m_CtxCache, &lineEncRsrc->m_ReuseUniMv, &lineEncRsrc->m_BlkUniMvInfoBuffer, &lineEncRsrc->m_AffineProfList, &lineEncRsrc->m_CachedBvs );
955
18.4E
        encCu.encodeCtu( pic, lineEncRsrc->m_prevQp, ctuPosX, ctuPosY );
956
957
        // cleanup line memory when last ctu in line done to reduce overall memory consumption
958
18.4E
        if( encSlice->m_pcEncCfg->m_ensureWppBitEqual && ( ctuPosX == pcv.widthInCtus - 1 || slice.pps->getTileIdx( ctuPosX, ctuPosY ) != slice.pps->getTileIdx( ctuPosX + 1, ctuPosY ) ) )
959
0
        {
960
0
          lineEncRsrc->m_AffineProfList    .resetAffineMVList();
961
0
          lineEncRsrc->m_BlkUniMvInfoBuffer.resetUniMvList();
962
0
          lineEncRsrc->m_ReuseUniMv        .resetReusedUniMvs();
963
0
          lineEncRsrc->m_CachedBvs         .resetIbcBvCand();
964
0
        }
965
966
18.4E
        DTRACE_UPDATE( g_trace_ctx, std::make_pair( "final", 1 ) );
967
18.4E
        ITT_TASKEND( itt_domain_encode, itt_handle_ctuEncode );
968
969
18.4E
        processStates[ ctuRsAddr ] = LF_VER;
970
18.4E
      }
971
0
      break;
972
973
    // vertical loopfilter
974
11.5M
    case LF_VER:
975
11.5M
      {
976
        // clip check to right tile border (CTU_ENCODE pre-processing delay due to IBC)
977
11.5M
        const int tileCol = slice.pps->ctuToTileCol[ctuPosX];
978
11.5M
        const int lastCtuPosXInTile = slice.pps->tileColBd[tileCol] + slice.pps->tileColWidth[tileCol] - 1;
979
11.5M
        const int checkRight = std::min<int>( encSlice->m_ctuEncDelay, lastCtuPosXInTile - ctuPosX );
980
981
11.5M
        const bool hasTiles = encSlice->m_pcEncCfg->m_tileParallelCtuEnc && slice.pps->getNumTiles() > 1;
982
983
        // need to check line above bcs of tiling, which allows CTU_ENCODE to run independently across tiles
984
11.5M
        if( hasTiles )
985
0
        {
986
0
          if( ctuPosY > 0 )
987
0
          {
988
0
            for( int i = -!!ctuPosX; i <= checkRight; i++ )
989
0
              if( pps.canFilterCtuBdry( ctuPosX, ctuPosY, i, -1 ) && processStates[ctuRsAddr - ctuStride + i] <= CTU_ENCODE )
990
0
                return false;
991
0
          }
992
0
        }
993
        
994
        // ensure all surrounding ctu's are encoded (intra pred requires non-reshaped and unfiltered residual, IBC requires unfiltered samples too)
995
        // check right with max offset (due to WPP condition above, this implies top-right has been already encoded)
996
17.6M
        for( int i = hasTiles ? -!!ctuPosX : checkRight; i <= checkRight; i++ )
997
11.5M
          if( pps.canFilterCtuBdry( ctuPosX, ctuPosY, i, 0 ) && processStates[ctuRsAddr + i] <= CTU_ENCODE )
998
5.48M
            return false;
999
1000
        // check bottom right with 1 CTU delay (this is only required for intra pred)
1001
        // at the right picture border this will check the bottom CTU
1002
6.08M
        const int checkBottomRight = std::min<int>( 1, lastCtuPosXInTile - ctuPosX );
1003
6.08M
        if( checkCtuTaskNbBotRgt( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, CTU_ENCODE, checkBottomRight ) ) 
1004
6.08M
          return false;
1005
1006
3.10k
        if( checkReadyState )
1007
3.57k
          return true;
1008
1009
18.4E
        ITT_TASKSTART( itt_domain_encode, itt_handle_rspLfVer );
1010
1011
        // loopfilter
1012
18.4E
        if( !cs.pps->deblockingFilterControlPresent || !cs.pps->deblockingFilterDisabled || cs.pps->deblockingFilterOverrideEnabled )
1013
0
        {
1014
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_DEBLOCK_FILTER, &cs, CH_L );
1015
          // calculate filter strengths
1016
0
          encSlice->m_pLoopFilter->calcFilterStrengthsCTU( cs, ctuArea, true );
1017
1018
          // vertical filter
1019
0
          PelUnitBuf reco = cs.picture->getRecoBuf();
1020
0
          encSlice->m_pLoopFilter->xDeblockArea<EDGE_VER>( cs, ctuArea, MAX_NUM_CH, reco );
1021
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1022
0
        }
1023
1024
18.4E
        ITT_TASKEND( itt_domain_encode, itt_handle_rspLfVer );
1025
1026
18.4E
        processStates[ ctuRsAddr ] = LF_HOR;
1027
18.4E
      }
1028
0
      break;
1029
1030
    // horizontal loopfilter
1031
388k
    case LF_HOR:
1032
388k
      {
1033
        // ensure horizontal ordering (from top to bottom)
1034
388k
        if( checkCtuTaskNbTop   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_HOR ) )         
1035
110k
          return false;
1036
1037
        // ensure vertical loop filter of neighbor ctu's will not modify current residual
1038
        // check top, top-right and right ctu
1039
        // (top, top-right checked implicitly due to ordering check above)
1040
278k
        if( checkCtuTaskNbRgt   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_VER ) )
1041
275k
          return false;
1042
1043
3.31k
        if( checkReadyState )
1044
3.58k
          return true;
1045
1046
18.4E
        ITT_TASKSTART( itt_domain_encode, itt_handle_lfHor );
1047
1048
18.4E
        if( !cs.pps->deblockingFilterControlPresent || !cs.pps->deblockingFilterDisabled || cs.pps->deblockingFilterOverrideEnabled )
1049
0
        {
1050
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_DEBLOCK_FILTER, &cs, CH_L );
1051
0
          PelUnitBuf reco = cs.picture->getRecoBuf();
1052
0
          encSlice->m_pLoopFilter->xDeblockArea<EDGE_HOR>( cs, ctuArea, MAX_NUM_CH, reco );
1053
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1054
0
        }
1055
1056
18.4E
        ITT_TASKEND( itt_domain_encode, itt_handle_lfHor );
1057
1058
18.4E
        processStates[ ctuRsAddr ] = SAO_FILTER;
1059
18.4E
      }
1060
0
      break;
1061
1062
    // SAO filter
1063
307k
    case SAO_FILTER:
1064
307k
      {
1065
        // general wpp conditions, top and top-right ctu have to be filtered
1066
307k
        if( checkCtuTaskNbTop   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER, true ) ) return false;
1067
230k
        if( checkCtuTaskNbTopRgt( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER, true ) ) return false;
1068
1069
        // ensure loop filter of neighbor ctu's will not modify current residual
1070
        // sao processing dependents on +1 pixel to each side
1071
        // due to wpp condition above, only right, bottom and bottom-right ctu have to be checked
1072
202k
        if( checkCtuTaskNbRgt   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_HOR,    true ) ) return false;
1073
194k
        if( checkCtuTaskNbBot   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_HOR,    true ) ) return false;
1074
6.48k
        if( checkCtuTaskNbBotRgt( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, LF_HOR, 1, true ) ) return false;
1075
1076
3.50k
        if( checkReadyState )
1077
3.58k
          return true;
1078
1079
18.4E
        ITT_TASKSTART( itt_domain_encode, itt_handle_sao );
1080
1081
        // SAO filter
1082
18.4E
        if( slice.sps->saoEnabled && pic->useSAO )
1083
0
        {
1084
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_SAO, &cs, CH_L );
1085
0
          TileLineEncRsrc* lineEncRsrc    = encSlice->m_TileLineEncRsrc[ lineIdx ];
1086
0
          PerThreadRsrc* taskRsrc         = encSlice->m_ThreadRsrc[ threadIdx ];
1087
0
          EncSampleAdaptiveOffset& encSao = lineEncRsrc->m_encSao;
1088
1089
0
          encSao.setCtuEncRsrc( &lineEncRsrc->m_SaoCABACEstimator, &taskRsrc->m_CtxCache );
1090
0
          encSao.storeCtuReco( cs, ctuArea, ctuPosX, ctuPosY );
1091
0
          encSao.getCtuStatistics( cs, encSlice->m_saoStatData, ctuArea, ctuRsAddr );
1092
0
          encSao.decideCtuParams( cs, encSlice->m_saoStatData, encSlice->m_saoEnabled, encSlice->m_saoAllDisabled, ctuArea, ctuRsAddr, &encSlice->m_saoReconParams[ 0 ], cs.picture->getSAO() );
1093
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1094
0
        }
1095
1096
        // ALF border extension
1097
18.4E
        if( cs.sps->alfEnabled )
1098
0
        {
1099
          // we have to do some kind of position aware boundary padding
1100
          // it's done here because the conditions are readable
1101
0
          PelUnitBuf recoBuf = cs.picture->getRecoBuf();
1102
0
          const int fltSize  = ( MAX_ALF_FILTER_LENGTH + 1 ) >> 1;
1103
0
          const int xL       = ( ctuPosX == 0 )                 ? ( x-fltSize       ) : ( x );
1104
0
          const int xR       = ( ctuPosX+1 == pcv.widthInCtus ) ? ( x+width+fltSize ) : ( x+width );
1105
1106
0
          if( ctuPosX == 0 )                  recoBuf.extendBorderPelLft( y, height, fltSize );
1107
0
          if( ctuPosX+1 == pcv.widthInCtus )  recoBuf.extendBorderPelRgt( y, height, fltSize );
1108
0
          if( ctuPosY == 0 )                  recoBuf.extendBorderPelTop( xL, xR-xL, fltSize );
1109
0
          if( ctuPosY+1 == pcv.heightInCtus ) recoBuf.extendBorderPelBot( xL, xR-xL, fltSize );
1110
1111
0
          encSlice->m_pALF->copyCTUforALF(cs, ctuPosX, ctuPosY);
1112
0
        }
1113
1114
        // DMVR refinement can be stored now
1115
18.4E
        if( slice.sps->DMVR && !slice.picHeader->disDmvrFlag )
1116
0
        {
1117
0
          CS::setRefinedMotionFieldCTU( cs, ctuPosX, ctuPosY );
1118
0
        }
1119
18.4E
        ITT_TASKEND( itt_domain_encode, itt_handle_sao );
1120
1121
18.4E
        const int tileCol = slice.pps->ctuToTileCol[ctuPosX];
1122
18.4E
        const int lastCtuColInTileRow = slice.pps->tileColBd[tileCol] + slice.pps->tileColWidth[tileCol] - 1;
1123
18.4E
        if( ctuPosX == lastCtuColInTileRow )
1124
0
        {
1125
0
          processStates[ctuRsAddr] = ALF_GET_STATISTICS;
1126
0
        }
1127
18.4E
        else
1128
18.4E
        {
1129
18.4E
          processStates[ctuRsAddr] = PROCESS_DONE;
1130
18.4E
          return true;
1131
18.4E
        }
1132
18.4E
      }
1133
0
      break;
1134
1135
92.8k
    case ALF_GET_STATISTICS:
1136
92.8k
      {
1137
        // ensure all surrounding ctu's are filtered (ALF will use pixels of adjacent CTU's)
1138
        // due to wpp condition above in SAO_FILTER, only right, bottom and bottom-right ctu have to be checked
1139
92.8k
        if( checkCtuTaskNbRgt   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER ) ) return false;
1140
92.8k
        if( checkCtuTaskNbBot   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER ) ) return false;
1141
2.02k
        if( checkCtuTaskNbBotRgt( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, SAO_FILTER ) ) return false;
1142
1143
2.02k
        if( checkReadyState )
1144
2.02k
          return true;
1145
1146
5
        ITT_TASKSTART( itt_domain_encode, itt_handle_alf_stat );
1147
1148
        // ALF pre-processing
1149
5
        if( slice.sps->alfEnabled )
1150
0
        {
1151
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_ALF, &cs, CH_L );
1152
0
          PelUnitBuf recoBuf = cs.picture->getRecoBuf();
1153
0
          const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1154
0
          for( int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++ )
1155
0
          {
1156
0
            encSlice->m_pALF->getStatisticsCTU( *cs.picture, cs, recoBuf, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1157
0
          }
1158
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1159
0
        }
1160
1161
5
        ITT_TASKEND( itt_domain_encode, itt_handle_alf_stat );
1162
1163
        // start alf filter derivation either for a sub-set of CTUs (syncLines mode) or for the whole picture (regular mode)
1164
5
        const unsigned deriveFilterCtu = encSlice->m_alfDeriveCtu;
1165
5
        processStates[ctuRsAddr] = (ctuRsAddr < deriveFilterCtu) ? ALF_RECONSTRUCT: ALF_DERIVE_FILTER;
1166
5
      }
1167
0
      break;
1168
1169
1.24M
    case ALF_DERIVE_FILTER:
1170
1.24M
      {
1171
1.24M
        const unsigned deriveFilterCtu = encSlice->m_alfDeriveCtu;
1172
1.24M
        if( ctuRsAddr == deriveFilterCtu )
1173
1.24M
        {
1174
          // ensure statistics from all previous ctu's have been collected
1175
1.24M
          int numCheckLines = deriveFilterCtu / pcv.widthInCtus + 1;
1176
1.25M
          for( int y = 0; y < numCheckLines; y++ )
1177
1.25M
          {
1178
1.26M
            for( int tileCol = 0; tileCol < slice.pps->numTileCols; tileCol++ )
1179
1.25M
            {
1180
1.25M
              const int lastCtuInTileRow = y * pcv.widthInCtus + slice.pps->tileColBd[tileCol] + slice.pps->tileColWidth[tileCol] - 1;
1181
1.25M
              if( processStates[lastCtuInTileRow] <= ALF_GET_STATISTICS )
1182
1.24M
                return false;
1183
1.25M
            }
1184
1.25M
          }
1185
1.24M
        }
1186
0
        else if( syncLines )
1187
0
        {
1188
          // ALF bitstream coding dependency for the sub-sequent ctu-lines
1189
0
          if( processStates[deriveFilterCtu] < ALF_RECONSTRUCT || checkCtuTaskNbTop( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, ALF_DERIVE_FILTER ) ) 
1190
0
            return false;
1191
0
        }
1192
1.14k
        if( checkReadyState )
1193
1.14k
          return true;
1194
1195
0
        ITT_TASKSTART( itt_domain_encode, itt_handle_alf_derive );
1196
        // ALF post-processing
1197
0
        if( slice.sps->alfEnabled )
1198
0
        {
1199
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_ALF, &cs, CH_L );
1200
0
          if( ctuRsAddr == deriveFilterCtu )
1201
0
          {
1202
0
            encSlice->m_pALF->initDerivation( slice );
1203
0
            encSlice->m_pALF->deriveFilter( *cs.picture, cs, slice.getLambdas(), deriveFilterCtu + 1 );
1204
0
            encSlice->m_pALF->reconstructCoeffAPSs( cs, cs.slice->alfEnabled[COMP_Y], cs.slice->alfEnabled[COMP_Cb] || cs.slice->alfEnabled[COMP_Cr], false );
1205
0
          }
1206
0
          else if( syncLines )
1207
0
          {
1208
            // in sync lines mode: derive/select filter for the remaining lines
1209
0
            TileLineEncRsrc* lineEncRsrc = encSlice->m_TileLineEncRsrc[ lineIdx ];
1210
0
            PerThreadRsrc*   taskRsrc    = encSlice->m_ThreadRsrc[ threadIdx ];
1211
0
            const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1212
0
            for(int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++)
1213
0
            {
1214
0
              encSlice->m_pALF->selectFilterForCTU( cs, &lineEncRsrc->m_AlfCABACEstimator, &taskRsrc->m_CtxCache, ctu );
1215
0
            }
1216
0
          }
1217
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1218
0
        }
1219
1220
0
        ITT_TASKEND( itt_domain_encode, itt_handle_alf_derive );
1221
0
        processStates[ ctuRsAddr ] = ALF_RECONSTRUCT;
1222
0
      }
1223
0
      break;
1224
1225
6.77M
    case ALF_RECONSTRUCT:
1226
6.77M
      {
1227
        // start alf filter derivation either for a sub-set of CTUs (syncLines mode) or for the whole picture (regular mode)
1228
6.77M
        const unsigned deriveFilterCtu = encSlice->m_alfDeriveCtu;
1229
6.77M
        if( processStates[deriveFilterCtu] < ALF_RECONSTRUCT )
1230
6.77M
          return false;
1231
2.02k
        else if( syncLines && ctuRsAddr > deriveFilterCtu && encSlice->m_pALF->getAsuHeightInCtus() > 1 )
1232
0
        {
1233
0
          const int asuHeightInCtus = encSlice->m_pALF->getAsuHeightInCtus();
1234
0
          const int botCtuLineInAsu = std::min( (( ctuPosY & ( ~(asuHeightInCtus - 1) ) ) + asuHeightInCtus - 1), (int)pcv.heightInCtus - 1 );
1235
0
          if( processStates[botCtuLineInAsu * ctuStride + ctuPosX] < ALF_RECONSTRUCT ) 
1236
0
            return false;
1237
0
        }
1238
1239
2.02k
        if( checkReadyState )
1240
2.01k
          return true;
1241
1242
9
        ITT_TASKSTART( itt_domain_encode, itt_handle_alf_recon );
1243
1244
9
        if( slice.sps->alfEnabled )
1245
0
        {
1246
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_ALF, &cs, CH_L );
1247
0
          const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1248
0
          for( int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++ )
1249
0
          {
1250
0
            encSlice->m_pALF->reconstructCTU_MT( *cs.picture, cs, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1251
0
          }
1252
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1253
0
        }
1254
1255
9
        ITT_TASKEND( itt_domain_encode, itt_handle_alf_recon );
1256
9
        processStates[ctuRsAddr] = CCALF_GET_STATISTICS;
1257
9
      }
1258
      // dont break, no additional deps, can continue straigt away!
1259
      //break;
1260
1261
2.63k
    case CCALF_GET_STATISTICS:
1262
2.63k
      {
1263
2.63k
        if( checkCtuTaskNbTop   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, ALF_RECONSTRUCT ) ) return false;
1264
1.42k
        if( checkCtuTaskNbBot   ( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, ALF_RECONSTRUCT ) ) return false;
1265
1266
764
        if( checkReadyState )
1267
755
          return true;
1268
1269
9
        ITT_TASKSTART( itt_domain_encode, itt_handle_ccalf_stat );
1270
1271
        // ALF pre-processing
1272
9
        if( slice.sps->ccalfEnabled )
1273
0
        {
1274
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_ALF, &cs, CH_L);
1275
0
          const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1276
0
          for( int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++ )
1277
0
          {
1278
0
            encSlice->m_pALF->deriveStatsForCcAlfFilteringCTU( cs, COMP_Cb, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1279
0
            encSlice->m_pALF->deriveStatsForCcAlfFilteringCTU( cs, COMP_Cr, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1280
0
          }
1281
0
          PROFILER_EXT_ACCUM_AND_START_NEW_SET( 1, _TPROF, P_IGNORE, &cs, CH_L );
1282
0
        }
1283
1284
9
        ITT_TASKEND( itt_domain_encode, itt_handle_ccalf_stat );
1285
1286
        // start alf filter derivation either for a sub-set of CTUs (syncLines mode) or for the whole picture (regular mode)
1287
9
        processStates[ctuRsAddr] = (ctuRsAddr < encSlice->m_ccalfDeriveCtu) ? CCALF_RECONSTRUCT: CCALF_DERIVE_FILTER;
1288
9
      }
1289
0
      break;
1290
1291
143k
    case CCALF_DERIVE_FILTER:
1292
143k
      {
1293
        // synchronization dependencies
1294
143k
        const unsigned deriveFilterCtu = encSlice->m_ccalfDeriveCtu;
1295
143k
        if( ctuRsAddr == deriveFilterCtu )
1296
143k
        {
1297
          // ensure statistics from all previous ctu's have been collected
1298
143k
          int numCheckLines = deriveFilterCtu / pcv.widthInCtus + 1;
1299
146k
          for( int y = 0; y < numCheckLines; y++ )
1300
145k
          {
1301
149k
            for( int tileCol = 0; tileCol < slice.pps->numTileCols; tileCol++ )
1302
145k
            {
1303
145k
              const int lastCtuInTileRow = y * pcv.widthInCtus + slice.pps->tileColBd[tileCol] + slice.pps->tileColWidth[tileCol] - 1;
1304
145k
              if( processStates[lastCtuInTileRow] <= CCALF_GET_STATISTICS )
1305
142k
                return false;
1306
145k
            }
1307
145k
          }
1308
143k
        }
1309
0
        else if( syncLines )
1310
0
        {
1311
          // ALF bitstream coding dependency for the sub-sequent CTU-lines
1312
0
          if( processStates[deriveFilterCtu] < CCALF_RECONSTRUCT || checkCtuTaskNbTop( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, CCALF_DERIVE_FILTER ) ) 
1313
0
            return false;
1314
0
        }
1315
1.14k
        if( checkReadyState )
1316
1.14k
          return true;
1317
1318
0
        ITT_TASKSTART( itt_domain_encode, itt_handle_ccalf_derive );
1319
1320
        // start task
1321
0
        if( slice.sps->ccalfEnabled )
1322
0
        {
1323
0
          if( ctuRsAddr == deriveFilterCtu )
1324
0
          {
1325
0
            encSlice->m_pALF->deriveCcAlfFilter( *cs.picture, cs, encSlice->m_ccalfDeriveCtu + 1 );
1326
0
          }
1327
0
          else if( syncLines )
1328
0
          {
1329
            // in sync lines mode: derive/select filter for the remaining lines
1330
0
            TileLineEncRsrc* lineEncRsrc = encSlice->m_TileLineEncRsrc[ lineIdx ];
1331
0
            PerThreadRsrc*   taskRsrc    = encSlice->m_ThreadRsrc[ threadIdx ];
1332
0
            const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1333
0
            encSlice->m_pALF->selectCcAlfFilterForCtuLine( cs, COMP_Cb, cs.getRecoBuf(), &lineEncRsrc->m_AlfCABACEstimator, &taskRsrc->m_CtxCache, firstCtuInRow, ctuRsAddr );
1334
0
            encSlice->m_pALF->selectCcAlfFilterForCtuLine( cs, COMP_Cr, cs.getRecoBuf(), &lineEncRsrc->m_AlfCABACEstimator, &taskRsrc->m_CtxCache, firstCtuInRow, ctuRsAddr );
1335
0
          }
1336
0
        }
1337
0
        ITT_TASKEND( itt_domain_encode, itt_handle_ccalf_derive );
1338
1339
0
        processStates[ctuRsAddr] = CCALF_RECONSTRUCT;
1340
0
      }
1341
0
      break;
1342
1343
6.58k
    case CCALF_RECONSTRUCT:
1344
6.58k
      {
1345
        // start ccalf filter derivation either for a sub-set of CTUs (syncLines mode) or for the whole picture (regular mode)
1346
6.58k
        const unsigned deriveFilterCtu = encSlice->m_ccalfDeriveCtu;
1347
6.58k
        if( processStates[deriveFilterCtu] < CCALF_RECONSTRUCT )
1348
4.55k
          return false;
1349
1350
2.02k
        if( syncLines )
1351
0
        {
1352
          // ensure line-by-line reconstruction due to line synchronization
1353
0
          if( checkCtuTaskNbTop( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, CCALF_RECONSTRUCT ) ) return false;
1354
          // check bottom due to rec. buffer usage in ccalf statistics
1355
0
          if( checkCtuTaskNbBot( pps, ctuPosX, ctuPosY, ctuRsAddr, processStates, CCALF_GET_STATISTICS ) ) return false;
1356
0
        }
1357
1358
2.02k
        if( checkReadyState )
1359
2.03k
          return true;
1360
1361
18.4E
        ITT_TASKSTART( itt_domain_encode, itt_handle_ccalf_recon );
1362
1363
18.4E
        if( slice.sps->ccalfEnabled )
1364
0
        {
1365
0
          const int firstCtuInRow = ctuRsAddr + 1 - slice.pps->tileColWidth[slice.pps->ctuToTileCol[ctuPosX]];
1366
0
          for( int ctu = firstCtuInRow; ctu <= ctuRsAddr; ctu++ )
1367
0
          {
1368
0
            encSlice->m_pALF->applyCcAlfFilterCTU( cs, COMP_Cb, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1369
0
            encSlice->m_pALF->applyCcAlfFilterCTU( cs, COMP_Cr, ctu, encSlice->m_ThreadRsrc[ threadIdx ]->m_alfTempCtuBuf );
1370
0
          }
1371
0
        }
1372
1373
18.4E
        ITT_TASKEND( itt_domain_encode, itt_handle_ccalf_recon );
1374
1375
        // extend pic border
1376
        // CCALF reconstruction stage is done per tile, ensure that all tiles in current CTU row are done  
1377
18.4E
        if( ++(pic->m_tileColsDone->at(ctuPosY)) >= pps.numTileCols )
1378
0
        {
1379
0
          PelUnitBuf recoBuf = cs.picture->getRecoBuf();
1380
0
          const int margin = cs.picture->margin;
1381
0
          recoBuf.extendBorderPelLft( y, height, margin );
1382
0
          recoBuf.extendBorderPelRgt( y, height, margin );
1383
0
          if(ctuPosY == 0)
1384
0
            recoBuf.extendBorderPelTop( -margin, pcv.lumaWidth + 2 * margin, margin );
1385
0
          if(ctuPosY + 1 == pcv.heightInCtus)
1386
0
            recoBuf.extendBorderPelBot( -margin, pcv.lumaWidth + 2 * margin, margin );
1387
1388
          // for IFP lines synchro, do an additional increment signaling that CTU row is ready
1389
0
          if( syncLines )
1390
0
            ++(pic->m_tileColsDone->at( ctuPosY ));
1391
0
        }
1392
1393
        // perform finish only once for whole picture
1394
18.4E
        const unsigned finishCtu = pcv.sizeInCtus - 1;
1395
18.4E
        if( ctuRsAddr < finishCtu )
1396
0
        {
1397
0
          processStates[ctuRsAddr] = PROCESS_DONE;
1398
          // processing done => terminate thread
1399
0
          return true;
1400
0
        }
1401
18.4E
        processStates[ctuRsAddr] = FINISH_SLICE;
1402
18.4E
      }
1403
1404
11.7k
    case FINISH_SLICE:
1405
11.7k
      {
1406
11.7k
        CHECK( ctuRsAddr != pcv.sizeInCtus - 1, "invalid state, finish slice only once for last ctu" );
1407
1408
        // ensure all coding tasks have been done for all previous ctu's
1409
23.8k
        for( int i = 0; i < ctuRsAddr; i++ )
1410
23.2k
          if( processStates[ i ] < FINISH_SLICE )
1411
11.1k
            return false;
1412
1413
563
        if( checkReadyState )
1414
564
          return true;
1415
1416
18.4E
        encSlice->finishCompressSlice( cs.picture, slice );
1417
1418
18.4E
        processStates[ ctuRsAddr ] = PROCESS_DONE;
1419
        // processing done => terminate thread
1420
18.4E
        return true;
1421
563
      }
1422
1423
0
    case PROCESS_DONE:
1424
0
      CHECK( true, "process state is PROCESS_DONE, but thread is still running" );
1425
0
      return true;
1426
1427
0
    default:
1428
0
      CHECK( true, "unknown process state" );
1429
0
      return true;
1430
41.6M
  }
1431
1432
0
  return false;
1433
41.6M
}
1434
1435
void EncSlice::encodeSliceData( Picture* pic )
1436
1.14k
{
1437
1.14k
  CodingStructure& cs              = *pic->cs;
1438
1.14k
  Slice* const slice               = cs.slice;
1439
1.14k
  const uint32_t startCtuTsAddr    = slice->sliceMap.ctuAddrInSlice[0];
1440
1.14k
  const uint32_t boundingCtuTsAddr = cs.pcv->sizeInCtus;
1441
1.14k
  const bool wavefrontsEnabled     = slice->sps->entropyCodingSyncEnabled;
1442
1443
  // this ensures that independently encoded bitstream chunks can be combined to bit-equal
1444
1.14k
  const SliceType cabacTableIdx = ! slice->pps->cabacInitPresent || slice->pendingRasInit ? slice->sliceType : m_encCABACTableIdx;
1445
1.14k
  slice->encCABACTableIdx = cabacTableIdx;
1446
1447
  // initialise entropy coder for the slice
1448
1.14k
  m_CABACWriter.initCtxModels( *slice );
1449
1450
1.14k
  DTRACE( g_trace_ctx, D_HEADER, "=========== POC: %d ===========\n", slice->poc );
1451
1452
1.14k
  int prevQP[MAX_NUM_CH];
1453
1.14k
  prevQP[0] = prevQP[1] = slice->sliceQp;
1454
1455
1.14k
  const PreCalcValues& pcv        = *cs.pcv;
1456
1.14k
  const uint32_t widthInCtus      = pcv.widthInCtus;
1457
1.14k
  uint32_t uiSubStrm              = 0;
1458
1.14k
  const int numSubstreamsColumns  = slice->pps->numTileCols;
1459
1.14k
  const int numSubstreamRows      = slice->sps->entropyCodingSyncEnabled ? pic->cs->pcv->heightInCtus : slice->pps->numTileRows;
1460
1.14k
  const int numSubstreams         = std::max<int>( numSubstreamRows * numSubstreamsColumns, 0/*(int)pic->brickMap->bricks.size()*/ );
1461
1.14k
  std::vector<OutputBitstream> substreamsOut( numSubstreams );
1462
1463
1.14k
  slice->clearSubstreamSizes();
1464
1465
4.73k
  for( uint32_t ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuTsAddr++ )
1466
3.59k
  {
1467
3.59k
    const uint32_t ctuRsAddr            = slice->sliceMap.ctuAddrInSlice[ctuTsAddr];
1468
3.59k
    const uint32_t ctuXPosInCtus        = ctuRsAddr % widthInCtus;
1469
3.59k
    const uint32_t ctuYPosInCtus        = ctuRsAddr / widthInCtus;
1470
3.59k
    const uint32_t tileXPosInCtus       = slice->pps->tileColBd[cs.pps->ctuToTileCol[ctuXPosInCtus]];
1471
3.59k
    const uint32_t tileYPosInCtus       = slice->pps->tileRowBd[cs.pps->ctuToTileRow[ctuYPosInCtus]];
1472
1473
3.59k
    DTRACE_UPDATE( g_trace_ctx, std::make_pair( "ctu", ctuRsAddr ) );
1474
1475
3.59k
    const Position pos (ctuXPosInCtus * pcv.maxCUSize, ctuYPosInCtus * pcv.maxCUSize);
1476
3.59k
    const UnitArea ctuArea (cs.area.chromaFormat, Area(pos.x, pos.y, pcv.maxCUSize, pcv.maxCUSize));
1477
3.59k
    CHECK( uiSubStrm >= numSubstreams, "array index out of bounds" );
1478
3.59k
    m_CABACWriter.initBitstream( &substreamsOut[ uiSubStrm ] );
1479
1480
    // set up CABAC contexts' state for this CTU
1481
3.59k
    if (ctuXPosInCtus == tileXPosInCtus && ctuYPosInCtus == tileYPosInCtus )
1482
1.14k
    {
1483
1.14k
      if (ctuTsAddr != startCtuTsAddr) // if it is the first CTU, then the entropy coder has already been reset
1484
0
      {
1485
0
        m_CABACWriter.initCtxModels( *slice );
1486
0
      }
1487
1.14k
      prevQP[0] = prevQP[1] = slice->sliceQp;
1488
1.14k
    }
1489
2.44k
    else if (ctuXPosInCtus == tileXPosInCtus && wavefrontsEnabled)
1490
0
    {
1491
      // Synchronize cabac probabilities with upper-right CTU if it's available and at the start of a line.
1492
0
      if (ctuTsAddr != startCtuTsAddr) // if it is the first CTU, then the entropy coder has already been reset
1493
0
      {
1494
0
        m_CABACWriter.initCtxModels( *slice );
1495
0
      }
1496
0
      if( cs.getCURestricted( pos.offset( 0, -1 ), pos, slice->independentSliceIdx, slice->pps->getTileIdx( ctuXPosInCtus, ctuYPosInCtus ), CH_L, TREE_D ) )
1497
0
      {
1498
        // Top-right is available, so use it.
1499
0
        m_CABACWriter.getCtx() = m_entropyCodingSyncContextState;
1500
0
      }
1501
0
      prevQP[0] = prevQP[1] = slice->sliceQp;
1502
0
    }
1503
1504
3.59k
    m_CABACWriter.coding_tree_unit( cs, ctuArea, prevQP, ctuRsAddr );
1505
1506
    // store probabilities of second CTU in line into buffer
1507
3.59k
    if( ctuXPosInCtus == tileXPosInCtus && wavefrontsEnabled )
1508
0
    {
1509
0
      m_entropyCodingSyncContextState = m_CABACWriter.getCtx();
1510
0
    }
1511
1512
    // terminate the sub-stream, if required (end of slice-segment, end of tile, end of wavefront-CTU-row):
1513
3.59k
    bool isMoreCTUsinSlice = ctuTsAddr != (boundingCtuTsAddr - 1);
1514
3.59k
    bool isLastCTUinTile   = isMoreCTUsinSlice && slice->pps->getTileIdx( ctuRsAddr ) != slice->pps->getTileIdx( slice->sliceMap.ctuAddrInSlice[ctuTsAddr+1] );
1515
3.59k
    bool isLastCTUinWPP    = wavefrontsEnabled && isMoreCTUsinSlice && !isLastCTUinTile && ( (slice->sliceMap.ctuAddrInSlice[ctuTsAddr+1] % widthInCtus) == cs.pps->tileColBd[cs.pps->ctuToTileCol[slice->sliceMap.ctuAddrInSlice[ctuTsAddr+1] % widthInCtus]] ); //TODO: adjust tile bound condition
1516
1517
3.59k
    if (isLastCTUinWPP || !isMoreCTUsinSlice || isLastCTUinTile )         // this the the last CTU of either tile/brick/WPP/slice
1518
1.14k
    {
1519
1.14k
      m_CABACWriter.end_of_slice();
1520
1521
      // Byte-alignment in slice_data() when new tile
1522
1.14k
      substreamsOut[ uiSubStrm ].writeByteAlignment();
1523
1524
1.14k
      if (isMoreCTUsinSlice) //Byte alignment only when it is not the last substream in the slice
1525
0
      {
1526
        // write sub-stream size
1527
0
        slice->addSubstreamSize( ( substreamsOut[ uiSubStrm ].getNumberOfWrittenBits() >> 3 ) + substreamsOut[ uiSubStrm ].countStartCodeEmulations() );
1528
0
      }
1529
1.14k
      uiSubStrm++;
1530
1.14k
    }
1531
3.59k
  } // CTU-loop
1532
1533
1.14k
  if(slice->pps->cabacInitPresent)
1534
0
  {
1535
0
    m_encCABACTableIdx = m_CABACWriter.getCtxInitId( *slice );
1536
0
  }
1537
1.14k
  else
1538
1.14k
  {
1539
1.14k
    m_encCABACTableIdx = slice->sliceType;
1540
1.14k
  }
1541
1542
  // concatenate substreams
1543
1.14k
  OutputBitstream& outStream = pic->sliceDataStreams[ 0/*slice->sliceIdx*/ ];
1544
2.29k
  for ( int i = 0; i < slice->getNumberOfSubstreamSizes() + 1; i++ )
1545
1.14k
  {
1546
1.14k
    outStream.addSubstream( &(substreamsOut[ i ]) );
1547
1.14k
  }
1548
1.14k
  pic->sliceDataNumBins += m_CABACWriter.getNumBins();
1549
1.14k
}
1550
1551
} // namespace vvenc
1552
1553
//! \}
1554