Coverage Report

Created: 2026-10-28 06:18

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