Coverage Report

Created: 2026-10-17 06:56

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