Coverage Report

Created: 2026-07-25 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vvdec/source/Lib/DecoderLib/DecLibRecon.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) 2018-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVdeC 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
/** \file     DecLibRecon.cpp
44
    \brief    decoder class
45
*/
46
47
#include "DecLib.h"
48
49
#include "CommonLib/TrQuant.h"
50
#if ENABLE_SIMD_TCOEFF_OPS
51
#include "CommonLib/TrQuant_EMT.h"
52
#endif
53
#include "CommonLib/InterPrediction.h"
54
#include "CommonLib/IntraPrediction.h"
55
#include "CommonLib/Unit.h"
56
#include "CommonLib/Buffer.h"
57
#include "CommonLib/UnitTools.h"
58
59
#include "CommonLib/dtrace_next.h"
60
#include "CommonLib/dtrace_buffer.h"
61
62
namespace vvdec
63
{
64
65
#ifdef TRACE_ENABLE_ITT
66
extern __itt_domain*              itt_domain_dec;
67
extern std::vector<__itt_domain*> itt_domain_decInst;
68
69
extern __itt_string_handle* itt_handle_alf;
70
extern __itt_string_handle* itt_handle_presao;
71
extern __itt_string_handle* itt_handle_sao;
72
extern __itt_string_handle* itt_handle_lfl;
73
extern __itt_string_handle* itt_handle_intra;
74
extern __itt_string_handle* itt_handle_inter;
75
extern __itt_string_handle* itt_handle_mider;
76
extern __itt_string_handle* itt_handle_lfcl;
77
extern __itt_string_handle* itt_handle_ext;
78
extern __itt_string_handle* itt_handle_dmvr;
79
extern __itt_string_handle* itt_handle_rsp;
80
81
extern __itt_string_handle* itt_handle_schedTasks;
82
extern __itt_string_handle* itt_handle_waitTasks;
83
84
// create global domain for DecLib
85
extern __itt_domain* itt_domain_glb;
86
// create a global counter
87
extern __itt_counter itt_frame_counter;
88
89
#define ITT_TASKSTART( d, t ) __itt_task_begin( ( d ), __itt_null, __itt_null, ( t ) )
90
#define ITT_TASKEND( d, t )   __itt_task_end  ( ( d ) )
91
#else
92
#define ITT_TASKSTART( d, t )
93
#define ITT_TASKEND( d, t )
94
#endif
95
96
//! \ingroup DecoderLib
97
//! \{
98
99
void CommonTaskParam::reset( CodingStructure& cs, TaskType ctuStartState, int tasksPerLine, bool _doALF )
100
713
{
101
713
  this->cs = &cs;
102
103
713
  const int heightInCtus = cs.pcv->heightInCtus;
104
713
  CHECKD( !ctuStates.empty() && std::any_of( ctuStates.begin(), ctuStates.end(), []( CtuState& s ) { return s != DONE; } ), "some CTUs of previous pic not done" );
105
713
  ctuStates = std::vector<CtuState>( heightInCtus * tasksPerLine );
106
713
  for( auto& ctu: ctuStates )
107
9.24k
  {
108
9.24k
    ctu.store( ctuStartState );
109
9.24k
  }
110
713
  perLineMiHist = std::vector<MotionHist>( heightInCtus );
111
713
  doALF         = _doALF;
112
713
}
113
114
DecLibRecon::DecLibRecon()
115
5.61k
{
116
5.61k
#if ENABLE_SIMD_OPT_BUFFER
117
5.61k
#  if defined( TARGET_SIMD_X86 )
118
5.61k
  g_pelBufOP.initPelBufOpsX86();
119
5.61k
#  endif
120
#  if defined( TARGET_SIMD_ARM )
121
  g_pelBufOP.initPelBufOpsARM();
122
#  endif
123
5.61k
#endif
124
5.61k
#if ENABLE_SIMD_TCOEFF_OPS && defined( TARGET_SIMD_X86 )
125
5.61k
  g_tCoeffOps.initTCoeffOpsX86();
126
5.61k
#endif
127
#if ENABLE_SIMD_TCOEFF_OPS && defined( TARGET_SIMD_ARM )
128
  g_tCoeffOps.initTCoeffOpsARM();
129
#endif
130
5.61k
}
131
132
void DecLibRecon::create( ThreadPool* threadPool, unsigned instanceId, bool upscaleOutputEnabled )
133
1.87k
{
134
  // run constructor again to ensure all variables, especially in DecLibParser have been reset
135
1.87k
  this->~DecLibRecon();
136
1.87k
  new( this ) DecLibRecon;
137
138
139
#if TRACE_ENABLE_ITT
140
  if( itt_domain_decInst.size() < instanceId + 1 )
141
  {
142
    std::string name( "DecLibRecon " + std::to_string( instanceId ) );
143
    itt_domain_decInst.push_back( __itt_domain_create( name.c_str() ) );
144
    itt_domain_decInst.back()->flags = 1;
145
146
    CHECK_FATAL( itt_domain_decInst.back() != itt_domain_decInst[instanceId], "current decLibRecon ITT-Domain is not the last in vector. Instances created in the wrong order?" );
147
  }
148
  m_itt_decInst = itt_domain_decInst[instanceId];
149
#endif
150
151
1.87k
  m_decodeThreadPool = threadPool;
152
1.87k
  m_numDecThreads    = std::max( 1, threadPool ? threadPool->numThreads() : 1 );
153
154
1.87k
  m_upscaleOutputEnabled = upscaleOutputEnabled;
155
1.87k
  m_predBufSize     = 0;
156
1.87k
  m_dmvrMvCacheSize = 0;
157
1.87k
  m_dmvrMvCache     = nullptr;
158
159
1.87k
  m_num4x4Elements   = 0;
160
1.87k
  m_loopFilterParam  = nullptr;
161
1.87k
  m_motionInfo       = nullptr;
162
163
1.87k
  m_pcThreadResource    = new PerThreadResource*[m_numDecThreads];
164
1.87k
  m_pcThreadResource[0] = new PerThreadResource();
165
59.8k
  for( int i = 1; i < m_numDecThreads; i++ )
166
57.9k
  {
167
57.9k
    m_pcThreadResource[i] = new PerThreadResource( m_pcThreadResource[0]->m_cTrQuant );
168
57.9k
  }
169
1.87k
}
170
171
void DecLibRecon::destroy()
172
1.87k
{
173
1.87k
  m_decodeThreadPool = nullptr;
174
175
1.87k
  if( m_predBuf )
176
713
  {
177
713
    m_predBuf.reset();
178
713
    m_predBufSize = 0;
179
713
  }
180
181
1.87k
  if( m_dmvrMvCache )
182
713
  {
183
713
    free( m_dmvrMvCache );
184
713
    m_dmvrMvCache = nullptr;
185
713
    m_dmvrMvCacheSize = 0;
186
713
  }
187
188
1.87k
  if( m_loopFilterParam )
189
713
  {
190
713
    free( m_loopFilterParam );
191
713
    m_loopFilterParam = nullptr;
192
713
  }
193
194
1.87k
  if( m_motionInfo )
195
713
  {
196
713
    free( m_motionInfo );
197
713
    m_motionInfo = nullptr;
198
713
  }
199
200
1.87k
  m_num4x4Elements = 0;
201
202
61.7k
  for( int i = 0; i < m_numDecThreads; i++ ) delete m_pcThreadResource[i];
203
1.87k
  delete[] m_pcThreadResource; m_pcThreadResource = nullptr;
204
1.87k
}
205
206
207
static void getCompatibleBuffer( const CodingStructure& cs, const CPelUnitBuf& srcBuf, PelStorage& destBuf, const UserAllocator* userAllocator )
208
713
{
209
713
  if( !destBuf.bufs.empty() )
210
0
  {
211
0
    bool compat = false;
212
0
    if( destBuf.chromaFormat == srcBuf.chromaFormat )
213
0
    {
214
0
      compat = true;
215
0
      const uint32_t numCh = getNumberValidComponents( srcBuf.chromaFormat );
216
0
      for( uint32_t i = 0; i < numCh; i++ )
217
0
      {
218
        // check this otherwise it would turn out to get very weird
219
0
        compat &= destBuf.get( ComponentID( i ) )         == srcBuf.get( ComponentID( i ) );
220
0
        compat &= destBuf.get( ComponentID( i ) ).stride  == srcBuf.get( ComponentID( i ) ).stride;
221
0
        compat &= destBuf.get( ComponentID( i ) ).width   == srcBuf.get( ComponentID( i ) ).width;
222
0
        compat &= destBuf.get( ComponentID( i ) ).height  == srcBuf.get( ComponentID( i ) ).height;
223
0
      }
224
0
    }
225
0
    if( !compat )
226
0
    {
227
0
      destBuf.destroy();
228
0
    }
229
0
  }
230
713
  if( destBuf.bufs.empty() )
231
713
  {
232
713
    destBuf.create( cs.picture->chromaFormat, cs.picture->lumaSize(), cs.pcv->maxCUWidth, cs.picture->margin, MEMORY_ALIGN_DEF_SIZE, true, userAllocator );
233
713
  }
234
713
}
235
236
void DecLibRecon::borderExtPic( Picture* pic, const Picture* currPic )
237
0
{
238
  // we block and wait here, so the exceptions from the reference pic don't propagate to the current picture
239
0
  pic->waitForAllTasks();
240
0
  if( pic->progress < Picture::reconstructed )   // an exception must have happended in the picture, so we need to clean it up
241
0
  {
242
0
    CHECK_FATAL( pic->progress < Picture::parsing, "Slice parsing should have started, so all structures are there" );
243
0
    try
244
0
    {
245
0
      pic->reconDone.checkAndRethrowException();
246
0
      pic->parseDone.checkAndRethrowException();  // when the error happened in the slice parsing tasks, there might not be an exception in recon done, so check parseDone also
247
0
    }
248
0
    catch( ... )
249
0
    {
250
0
      pic->error = true;
251
0
      pic->reconDone.clearException();
252
      // TODO: for now we set it on parseDone, so we can handle it outside:
253
0
      if( !pic->parseDone.hasException() )
254
0
      {
255
0
        pic->parseDone.setException( std::current_exception() );
256
0
      }
257
258
0
      pic->fillGrey( currPic->cs->sps.get() );
259
0
    }
260
0
  }
261
262
0
  pic->borderExtStarted = true;
263
264
0
  const bool wrapAround = pic->cs->sps->getUseWrapAround();
265
0
  if( wrapAround )
266
0
  {
267
    // copy reconstruction buffer to wrapAround buffer. All other border-extension tasks depend on this task.
268
0
    static auto copyTask = []( int, void* task_param )
269
0
    {
270
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
271
0
      Picture* picture = static_cast<Picture*>( task_param );
272
0
      picture->getRecoBuf( true ).copyFrom( picture->getRecoBuf() );
273
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
274
0
      return true;
275
0
    };
276
0
    pic->m_copyWrapBufDone.lock();
277
0
    m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string( currPic->poc ) + " copyTask Ref-POC:" + std::to_string( pic->poc ) )
278
0
                                        copyTask,
279
0
                                        pic,
280
0
                                        &pic->m_borderExtTaskCounter,
281
0
                                        &pic->m_copyWrapBufDone,
282
0
                                        { &pic->reconDone } );
283
0
  }
284
285
  // start actual border extension tasks
286
0
  {
287
0
    static auto task = []( int, void* task_param )
288
0
    {
289
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
290
0
      Picture* picture = static_cast<Picture*>( task_param );
291
0
      picture->extendPicBorder( true, false, false, false );
292
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
293
0
      return true;
294
0
    };
295
0
    m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string(currPic->poc) + " borderExtTask T Ref-POC:" + std::to_string(pic->poc) )
296
0
                                        task,
297
0
                                        pic,
298
0
                                        &pic->m_borderExtTaskCounter,
299
0
                                        nullptr,
300
0
                                        { wrapAround ? &pic->m_copyWrapBufDone : &pic->reconDone } );
301
0
  }
302
303
0
  {
304
0
    static auto task = []( int, void* task_param )
305
0
    {
306
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
307
0
      Picture* picture = static_cast<Picture*>( task_param );
308
0
      picture->extendPicBorder( false, true, false, false );
309
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
310
0
      return true;
311
0
    };
312
0
    m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string(currPic->poc) + " borderExtTask B Ref-POC:" + std::to_string(pic->poc) )
313
0
                                        task,
314
0
                                        pic,
315
0
                                        &pic->m_borderExtTaskCounter,
316
0
                                        nullptr,
317
0
                                        { wrapAround ? &pic->m_copyWrapBufDone : &pic->reconDone } );
318
0
  }
319
320
0
  {
321
0
    static auto task = []( int, void* task_param )
322
0
    {
323
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
324
0
      Picture* picture = static_cast<Picture*>( task_param );
325
0
      picture->extendPicBorder( false, false, true, false, CH_L );
326
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
327
0
      return true;
328
0
    };
329
0
    m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string(currPic->poc) + " borderExtTask ltT Ref-POC:" + std::to_string(pic->poc) )
330
0
                                        task,
331
0
                                        pic,
332
0
                                        &pic->m_borderExtTaskCounter,
333
0
                                        nullptr,
334
0
                                        { wrapAround ? &pic->m_copyWrapBufDone : &pic->reconDone } );
335
0
  }
336
0
  {
337
0
    static auto task = []( int, void* task_param )
338
0
    {
339
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
340
0
      Picture* picture = static_cast<Picture*>( task_param );
341
0
      picture->extendPicBorder( false, false, false, true, CH_L );
342
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
343
0
      return true;
344
0
    };
345
0
    m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string(currPic->poc) + " borderExtTask lrB Y Ref-POC:" + std::to_string(pic->poc) )
346
0
                                        task,
347
0
                                        pic,
348
0
                                        &pic->m_borderExtTaskCounter,
349
0
                                        nullptr,
350
0
                                        { wrapAround ? &pic->m_copyWrapBufDone : &pic->reconDone } );
351
0
  }
352
353
0
  {
354
0
    static auto task = []( int, void* task_param )
355
0
    {
356
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
357
0
      Picture* picture = static_cast<Picture*>( task_param );
358
0
      picture->extendPicBorder( false, false, true, false, CH_C );
359
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
360
0
      return true;
361
0
    };
362
0
    m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string(currPic->poc) + " borderExtTask lrB UV Ref-POC:" + std::to_string(pic->poc) )
363
0
                                        task,
364
0
                                        pic,
365
0
                                        &pic->m_borderExtTaskCounter,
366
0
                                        nullptr,
367
0
                                        { wrapAround ? &pic->m_copyWrapBufDone : &pic->reconDone } );
368
0
  }
369
0
  {
370
0
    static auto task = []( int, void* task_param )
371
0
    {
372
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
373
0
      Picture* picture = static_cast<Picture*>( task_param );
374
0
      picture->extendPicBorder( false, false, false, true, CH_C );
375
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
376
0
      return true;
377
0
    };
378
0
    m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string(currPic->poc) + " borderExtTask lrB UV Ref-POC:" + std::to_string(pic->poc) )
379
0
                                        task,
380
0
                                        pic,
381
0
                                        &pic->m_borderExtTaskCounter,
382
0
                                        nullptr,
383
0
                                        { wrapAround ? &pic->m_copyWrapBufDone : &pic->reconDone } );
384
0
  }
385
0
}
386
387
void DecLibRecon::createSubPicRefBufs( Picture* pic, const Picture* currPic )
388
0
{
389
0
  pic->subPicExtStarted = true;
390
391
0
  const PPS* pps       = pic->cs->pps.get();
392
0
  const SPS* sps       = pic->cs->sps.get();
393
0
  const int  numSubPic = pps->getNumSubPics();
394
395
0
  pic->m_subPicRefBufs.resize( numSubPic );
396
0
  for( int i = 0; i < numSubPic; ++i )
397
0
  {
398
0
    const SubPic& currSubPic = pps->getSubPic( i );
399
0
    const Area    subPicArea( currSubPic.getSubPicLeft(),
400
0
                              currSubPic.getSubPicTop(),
401
0
                              currSubPic.getSubPicWidthInLumaSample(),
402
0
                              currSubPic.getSubPicHeightInLumaSample() );
403
404
0
    pic->m_subPicRefBufs[i].create( pic->chromaFormat, Size( subPicArea ), sps->getMaxCUWidth(), pic->margin, MEMORY_ALIGN_DEF_SIZE );
405
406
0
    static auto task = []( int, void* task_param )
407
0
    {
408
0
      SubPicExtTask* t = static_cast<SubPicExtTask*>( task_param );
409
0
      t->subPicBuf->copyFrom( t->picture->getRecoBuf().subBuf( t->subPicArea ) );
410
0
      t->picture->extendPicBorderBuf( *t->subPicBuf );
411
0
      return true;
412
0
    };
413
0
    m_subPicExtTasks.emplace_back( SubPicExtTask{ pic, &pic->m_subPicRefBufs[i], subPicArea } );
414
0
    m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string( currPic->poc ) + " subPicBorderExtTask refPOC:" + std::to_string( pic->poc ) )
415
0
                                        task,
416
0
                                        &m_subPicExtTasks.back(),
417
0
                                        &pic->m_borderExtTaskCounter,
418
0
                                        nullptr,
419
0
                                        { &pic->reconDone } );
420
0
  }
421
0
}
422
423
void DecLibRecon::swapBufs( CodingStructure& cs )
424
3
{
425
3
  cs.picture->m_bufs[PIC_RECONSTRUCTION].swap( m_fltBuf );
426
3
  cs.rebindPicBufs();   // ensure the recon buf in the coding structure points to the correct buffer
427
3
}
428
429
void DecLibRecon::decompressPicture( Picture* pcPic )
430
713
{
431
713
  m_currDecompPic = pcPic;
432
433
713
  CodingStructure& cs = *pcPic->cs;
434
435
713
  pcPic->progress = Picture::reconstructing;
436
437
#ifdef TRACE_ENABLE_ITT
438
  // mark start of frame
439
    pcPic->m_itt_decLibInst = m_itt_decInst;
440
  __itt_frame_begin_v3( pcPic->m_itt_decLibInst, nullptr );
441
#endif
442
443
  // Initialise the various objects for the new set of settings
444
713
  const SPS * sps = cs.sps.get();
445
713
  const PPS * pps = cs.pps.get();
446
447
23.5k
  for( int i = 0; i < m_numDecThreads; i++ )
448
22.8k
  {
449
22.8k
    if( sps->getUseReshaper() )
450
4.67k
    {
451
4.67k
      m_pcThreadResource[i]->m_cReshaper.createDec( sps->getBitDepth() );
452
4.67k
      m_pcThreadResource[i]->m_cReshaper.initSlice( pcPic->slices[0]->getNalUnitLayerId(), *pcPic->slices[0]->getPicHeader(), pcPic->slices[0]->getVPS_nothrow() );
453
4.67k
    }
454
455
22.8k
    m_pcThreadResource[i]->m_cIntraPred.init( sps->getChromaFormatIdc(), sps->getBitDepth() );
456
22.8k
    m_pcThreadResource[i]->m_cInterPred.init( &m_cRdCost, sps->getChromaFormatIdc(), sps->getMaxCUHeight() );
457
458
    // Recursive structure
459
22.8k
    m_pcThreadResource[i]->m_cTrQuant.init( pcPic );
460
22.8k
    m_pcThreadResource[i]->m_cCuDecoder.init( &m_pcThreadResource[i]->m_cIntraPred, &m_pcThreadResource[i]->m_cInterPred, &m_pcThreadResource[i]->m_cReshaper, &m_pcThreadResource[i]->m_cTrQuant );
461
22.8k
  }
462
463
713
  getCompatibleBuffer( *pcPic->cs, pcPic->cs->getRecoBuf(), m_fltBuf, pcPic->getUserAllocator() );
464
465
713
  const uint32_t  log2SaoOffsetScale = (uint32_t) std::max(0, sps->getBitDepth() - MAX_SAO_TRUNCATED_BITDEPTH);
466
713
  const int maxDepth = getLog2(sps->getMaxCUWidth()) - pps->pcv->minCUWidthLog2;
467
713
  m_cSAO.create( pps->getPicWidthInLumaSamples(),
468
713
                 pps->getPicHeightInLumaSamples(),
469
713
                 sps->getChromaFormatIdc(),
470
713
                 sps->getMaxCUWidth(),
471
713
                 sps->getMaxCUHeight(),
472
713
                 maxDepth,
473
713
                 log2SaoOffsetScale,
474
713
                 m_fltBuf
475
713
               );
476
477
713
  if( sps->getUseALF() )
478
713
  {
479
713
    m_cALF.create( cs.picHeader.get(), sps, pps, m_numDecThreads, m_fltBuf );
480
713
  }
481
482
713
  const PreCalcValues* pcv = cs.pcv;
483
484
  // set reconstruction buffers in CodingStructure
485
713
  const ptrdiff_t ctuSampleSizeL = pcv->maxCUHeight * pcv->maxCUWidth;
486
713
  const ptrdiff_t ctuSampleSizeC = isChromaEnabled( pcv->chrFormat ) ? ( ctuSampleSizeL >> ( getChannelTypeScaleX( CH_C, pcv->chrFormat ) + getChannelTypeScaleY( CH_C, pcv->chrFormat ) ) ) : 0;
487
713
  const ptrdiff_t ctuSampleSize  = ctuSampleSizeL + 2 * ctuSampleSizeC;
488
713
  const size_t    predBufSize    = ctuSampleSize * pcv->sizeInCtus;
489
713
  if( predBufSize != m_predBufSize )
490
713
  {
491
713
    m_predBuf.reset( ( Pel* ) xMalloc( Pel, predBufSize ) );
492
713
    m_predBufSize = predBufSize;
493
713
  }
494
495
713
  pcPic->cs->m_predBuf = m_predBuf.get();
496
497
  // for the worst case of all PUs being 8x8 and using DMVR
498
713
  const size_t _maxNumDmvrMvs = pcv->num8x8CtuBlks * pcv->sizeInCtus;
499
713
  if( _maxNumDmvrMvs != m_dmvrMvCacheSize )
500
713
  {
501
713
    if( m_dmvrMvCache ) free( m_dmvrMvCache );
502
713
    m_dmvrMvCacheSize = _maxNumDmvrMvs;
503
713
    m_dmvrMvCache     = ( Mv* ) malloc( sizeof( Mv ) * _maxNumDmvrMvs );
504
713
  }
505
506
713
  pcPic->cs->m_dmvrMvCache = m_dmvrMvCache;
507
508
713
  if( m_num4x4Elements != cs.pcv->num4x4CtuBlks * cs.pcv->sizeInCtus )
509
713
  {
510
713
    if( m_loopFilterParam ) free( m_loopFilterParam );
511
713
    if( m_motionInfo      ) free( m_motionInfo );
512
513
713
    m_num4x4Elements = cs.pcv->num4x4CtuBlks * cs.pcv->sizeInCtus;
514
515
713
    m_loopFilterParam = ( LoopFilterParam* ) malloc( sizeof( LoopFilterParam ) * m_num4x4Elements * 2 );
516
713
    m_motionInfo      = ( MotionInfo* )      malloc( sizeof( MotionInfo      ) * m_num4x4Elements );
517
713
  }
518
  // finished
519
520
713
  const int widthInCtus  = cs.pcv->widthInCtus;
521
713
  const int heightInCtus = cs.pcv->heightInCtus;
522
523
713
  pcPic->startProcessingTimer();
524
525
713
  if( m_decodeThreadPool->numThreads() > 0 )
526
713
  {
527
713
    ITT_TASKSTART( itt_domain_dec, itt_handle_schedTasks );
528
713
  }
529
530
713
  picBarriers.clear();
531
713
#if ALLOW_MIDER_LF_DURING_PICEXT
532
713
  CBarrierVec  picExtBarriers;
533
#else
534
  CBarrierVec &picExtBarriers = picBarriers;
535
#endif
536
537
713
  const int numSubPic = cs.pps->getNumSubPics();
538
713
  if( numSubPic > 1 )
539
0
  {
540
0
    m_subPicExtTasks.clear();
541
0
    m_subPicExtTasks.reserve( pcPic->slices.size() * MAX_NUM_REF_PICS * numSubPic );
542
0
  }
543
544
713
  std::vector<Picture*> borderExtRefPics( pcPic->buildAllRefPicsVec() );
545
713
  for( Picture* refPic : borderExtRefPics )
546
0
  {
547
0
    if( !refPic->borderExtStarted )
548
0
    {
549
      // TODO: (GH) Can we bypass this border extension, when all subpics (>1) are treated as pics?
550
0
      borderExtPic( refPic, pcPic );
551
0
    }
552
553
0
    if( !refPic->subPicExtStarted && numSubPic > 1 && refPic->m_subPicRefBufs.size() != numSubPic )
554
0
    {
555
0
      CHECK( !refPic->m_subPicRefBufs.empty(), "Wrong number of subpics already present in reference picture" );
556
0
      CHECK( cs.sps->getUseWrapAround(), "Wraparound + subpics not implemented" );
557
558
0
      createSubPicRefBufs( refPic, pcPic );
559
0
    }
560
561
0
    if( refPic->m_borderExtTaskCounter.isBlocked() &&
562
0
        std::find( picExtBarriers.cbegin(), picExtBarriers.cend(), refPic->m_borderExtTaskCounter.donePtr() ) == picExtBarriers.cend() )
563
0
    {
564
0
      picExtBarriers.push_back( refPic->m_borderExtTaskCounter.donePtr() );
565
0
    }
566
0
  }
567
568
713
  if( m_decodeThreadPool->numThreads() == 0 && (
569
0
       std::any_of( picExtBarriers.cbegin(), picExtBarriers.cend(), []( const Barrier* b ) { return b->isBlocked(); } ) ||
570
0
       std::any_of( picBarriers   .cbegin(), picBarriers   .cend(), []( const Barrier* b ) { return b->isBlocked(); } ) ) )
571
0
  {
572
0
    m_decodeThreadPool->processTasksOnMainThread();
573
0
  }
574
575
713
  const bool isIntra = std::all_of( pcPic->slices.begin(), pcPic->slices.end(), []( const Slice* pcSlice ) { return pcSlice->isIntra(); } );
576
577
713
  const int numColPerTask = std::max( std::min( widthInCtus, ( widthInCtus / std::max( m_numDecThreads * ( isIntra ? 2 : 1 ), 1 ) ) + ( isIntra ? 0 : 1 ) ), 1 );
578
713
  const int numTasksPerLine = widthInCtus / numColPerTask + !!( widthInCtus % numColPerTask );
579
580
713
#if ALLOW_MIDER_LF_DURING_PICEXT
581
713
  pcPic->refPicExtDepBarriers = std::move( picExtBarriers );
582
713
#endif
583
#if !RECO_WHILE_PARSE
584
  picBarriers.push_back( &cs.picture->parseDone );
585
#endif
586
587
713
  const TaskType ctuStartState = MIDER;
588
713
  const bool     doALF         = cs.sps->getUseALF() && !AdaptiveLoopFilter::getAlfSkipPic( cs );
589
713
  commonTaskParam.reset( cs, ctuStartState, numTasksPerLine, doALF );
590
591
713
  tasksFinishMotion = std::vector<LineTaskParam>( heightInCtus, LineTaskParam{ commonTaskParam, -1 } );
592
713
  tasksCtu          = std::vector<CtuTaskParam >( heightInCtus * numTasksPerLine, CtuTaskParam{ commonTaskParam, -1, -1, {} } );
593
594
713
  pcPic->reconDone.lock();
595
596
#if 0
597
  // schedule in raster scan order
598
  for( int line = 0; line < heightInCtus; ++line )
599
  {
600
    for( int col = 0; col < widthInCtus;  ++col )
601
    {
602
#else
603
  // schedule in zig-zag scan order
604
5.52k
  for( int i = 0; i < numTasksPerLine + heightInCtus; ++i )
605
4.81k
  {
606
4.81k
    int line = 0;
607
25.6k
    for( int col = i; col >= 0; --col, ++line )
608
20.8k
    {
609
20.8k
#endif
610
20.8k
      if( line < heightInCtus && col < numTasksPerLine )
611
9.24k
      {
612
9.24k
        CBarrierVec ctuBarriers = picBarriers;
613
9.24k
        const int   ctuStart    = col * numColPerTask;
614
9.24k
        const int   ctuEnd      = std::min( ctuStart + numColPerTask, widthInCtus );
615
616
9.24k
#if RECO_WHILE_PARSE
617
9.24k
        if( pcPic->parseDone.isBlocked() )
618
9.22k
        {
619
          // wait for the last CTU in the current line to be parsed
620
9.22k
          ctuBarriers.push_back( &pcPic->ctuParsedBarrier[( line + 1 ) * widthInCtus - 1] );
621
9.22k
        }
622
623
9.24k
#endif
624
9.24k
        CtuTaskParam* param    = &tasksCtu[line * numTasksPerLine + col];
625
9.24k
        param->taskLine        = line;
626
9.24k
        param->taskCol         = col;
627
9.24k
        param->ctuEnd          = ctuEnd;
628
9.24k
        param->ctuStart        = ctuStart;
629
9.24k
        param->numColPerTask   = numColPerTask;
630
9.24k
        param->numTasksPerLine = numTasksPerLine;
631
632
9.24k
        m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string(pcPic->poc) + " ctuTask:" + std::to_string( col ) + "," + std::to_string( line ) )
633
9.24k
                                            ctuTask<false>,
634
9.24k
                                            param,
635
9.24k
                                            &pcPic->m_ctuTaskCounter,
636
9.24k
                                            nullptr,
637
9.24k
                                            std::move( ctuBarriers ),
638
9.24k
                                            ctuTask<true> );
639
9.24k
      }
640
20.8k
    }
641
4.81k
  }
642
643
713
  {
644
713
    static auto finishReconTask = []( int, void* task_param )
645
713
    {
646
3
      FinishPicTaskParam* param = static_cast<FinishPicTaskParam*>( task_param );
647
3
      CodingStructure& cs = *param->pic->cs;
648
649
3
      if( cs.sps->getUseALF() && !AdaptiveLoopFilter::getAlfSkipPic( cs ) )
650
3
      {
651
3
        param->decLib->swapBufs( cs );
652
3
      }
653
654
3
      cs.deallocTempInternals();
655
656
#ifdef TRACE_ENABLE_ITT
657
      // mark end of frame
658
      __itt_frame_end_v3( param->pic->m_itt_decLibInst, nullptr );
659
#endif
660
3
      param->pic->stopProcessingTimer();
661
662
3
      param->pic->progress = Picture::reconstructed;
663
3
      return true;
664
3
    };
665
666
713
    taskFinishPic = FinishPicTaskParam( this, pcPic );
667
713
    m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string( pcPic->poc ) + " finishPicTask" )
668
713
                                        finishReconTask,
669
713
                                        &taskFinishPic,
670
713
                                        &pcPic->m_divTasksCounter,
671
713
                                        &pcPic->reconDone,
672
713
                                        { pcPic->m_ctuTaskCounter.donePtr() } );
673
713
  }
674
675
713
  if( m_decodeThreadPool->numThreads() == 0 )
676
0
  {
677
0
  }
678
713
  else
679
713
  {
680
713
    ITT_TASKEND( itt_domain_dec, itt_handle_schedTasks );
681
713
  }
682
713
}
683
684
Picture* DecLibRecon::waitForPrevDecompressedPic()
685
2.54k
{
686
2.54k
  if( !m_currDecompPic )
687
1.83k
    return nullptr;
688
689
713
  ITT_TASKSTART( itt_domain_dec, itt_handle_waitTasks );
690
713
  try
691
713
  {
692
713
    if( m_decodeThreadPool->numThreads() == 0 )
693
0
    {
694
0
      /*bool stillTasksWaiting = */ m_decodeThreadPool->processTasksOnMainThread();
695
0
      CHECK_FATAL( m_currDecompPic->reconDone.isBlocked(), "can't make progress. some dependecy has not been finished" );
696
0
    }
697
698
713
    const Slice*   lastSlice           = m_currDecompPic->slices.back();
699
713
    const unsigned lastSliceLastCtuIdx = lastSlice->getCtuAddrInSlice( lastSlice->getNumCtuInSlice() - 1 );
700
713
    CHECK( lastSliceLastCtuIdx != m_currDecompPic->cs->pcv->sizeInCtus - 1, "Picture incomplete. A slice was probably lost." );
701
702
713
    m_currDecompPic->reconDone.wait();
703
713
  }
704
713
  catch( ... )
705
713
  {
706
710
    m_currDecompPic->error = true;
707
710
    m_currDecompPic->reconDone.setException( std::current_exception() );
708
710
  }
709
710
  // also check error flag, which can have been set earlier (e.g., when trying to use the picture as reference)
711
713
  if( m_currDecompPic->error || m_currDecompPic->reconDone.hasException() )
712
710
  {
713
    // ensure all tasks are cleared from declibRecon
714
710
    cleanupOnException();
715
710
  }
716
717
713
  ITT_TASKEND( itt_domain_dec, itt_handle_waitTasks );
718
719
713
  return std::exchange( m_currDecompPic, nullptr );
720
713
}
721
722
void DecLibRecon::cleanupOnException()
723
710
{
724
  // there was an exception anywhere in m_currDecompPic
725
  // => we need to wait for all tasks to be cleared from the thread pool
726
710
  m_currDecompPic->waitForAllTasks();
727
728
710
  commonTaskParam.ctuStates.clear();
729
710
}
730
731
template<bool onlyCheckReadyState>
732
bool DecLibRecon::ctuTask( int tid, void* task_param )
733
663k
{
734
663k
  CtuTaskParam* param = static_cast<CtuTaskParam*>( task_param );
735
736
663k
  const int       taskCol      = param->taskCol;
737
663k
  const int       line         = param->taskLine;
738
663k
  const int       col          = taskCol;
739
740
663k
  auto&           cs           = *param->common.cs;
741
663k
  auto&           decLib       = param->common.decLib;
742
663k
  const int       tasksPerLine = param->numTasksPerLine;
743
663k
  const int       heightInCtus = cs.pcv->heightInCtus;
744
745
663k
  CtuState&       thisCtuState =  param->common.ctuStates[line * tasksPerLine + taskCol];
746
663k
  const CtuState* thisLine     = &param->common.ctuStates[line * tasksPerLine];
747
663k
  const CtuState* lineAbove    = thisLine - tasksPerLine;
748
663k
  const CtuState* lineBelow    = thisLine + tasksPerLine;
749
750
663k
  const int       ctuStart     = param->ctuStart;
751
663k
  const int       ctuEnd       = param->ctuEnd;
752
753
663k
  if( cs.picture->m_ctuTaskCounter.hasException() )
754
3.46k
  {
755
3.46k
    std::rethrow_exception( cs.picture->m_ctuTaskCounter.getException() );
756
3.46k
  }
757
758
663k
  switch( thisCtuState.load() )
759
663k
  {
760
    // all case statements fall through to continue with next task, unless they return false due to unsatisfied preconditions
761
762
68.5k
  case MIDER:
763
68.5k
  {
764
68.5k
    if( col > 0 && thisLine[col - 1] <= MIDER_cont )
765
61.9k
      return false;
766
6.64k
    if( line > 0 )
767
2.44k
    {
768
2.44k
      if( col + 1 < tasksPerLine )
769
1.89k
      {
770
1.89k
        if( lineAbove[col + 1] <= MIDER )
771
5
          return false;
772
1.89k
      }
773
556
      else
774
556
      {
775
556
        if( lineAbove[col] <= MIDER_cont )
776
0
          return false;
777
556
      }
778
2.44k
    }
779
6.63k
    if( onlyCheckReadyState )
780
3.32k
      return true;
781
782
3.31k
    ITT_TASKSTART( itt_domain_dec, itt_handle_mider );
783
784
6.63k
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
785
3.32k
    {
786
3.32k
      const int ctuRsAddr = ctu + line * cs.pcv->widthInCtus;
787
3.32k
      CtuData& ctuData    = cs.getCtuData( ctuRsAddr );
788
3.32k
      ctuData.motion      = &decLib.m_motionInfo[cs.pcv->num4x4CtuBlks * ctuRsAddr];
789
790
3.32k
      if( !ctuData.slice->isIntra() || cs.sps->getIBCFlag() )
791
3.32k
      {
792
3.32k
        const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
793
3.32k
        decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskDeriveCtuMotionInfo( cs, ctuRsAddr, ctuArea, param->common.perLineMiHist[line] );
794
3.32k
      }
795
0
      else
796
0
      {
797
0
        memset( NO_WARNING_class_memaccess( ctuData.motion ), MI_NOT_VALID, sizeof( MotionInfo ) * cs.pcv->num4x4CtuBlks );
798
0
      }
799
800
3.32k
      thisCtuState = MIDER_cont;
801
3.32k
    }
802
803
3.31k
    thisCtuState = LF_INIT;
804
805
3.31k
    ITT_TASKEND( itt_domain_dec, itt_handle_mider );
806
3.31k
  }
807
808
3.31k
  case LF_INIT:
809
3.31k
  {
810
3.31k
    if( onlyCheckReadyState )
811
0
      return true;
812
813
3.31k
    ITT_TASKSTART( itt_domain_dec, itt_handle_lfcl );
814
815
6.63k
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
816
3.32k
    {
817
3.32k
      const int ctuRsAddr = ctu + line * cs.pcv->widthInCtus;
818
3.32k
      CtuData& ctuData    = cs.getCtuData( ctuRsAddr );
819
3.32k
      ctuData.lfParam[0]  = &decLib.m_loopFilterParam[cs.pcv->num4x4CtuBlks * ( 2 * ctuRsAddr + 0 )];
820
3.32k
      ctuData.lfParam[1]  = &decLib.m_loopFilterParam[cs.pcv->num4x4CtuBlks * ( 2 * ctuRsAddr + 1 )];
821
3.32k
      memset( ctuData.lfParam[0], 0, sizeof( LoopFilterParam ) * 2 * cs.pcv->num4x4CtuBlks );
822
823
3.32k
      decLib.m_cLoopFilter.calcFilterStrengthsCTU( cs, ctuRsAddr );
824
3.32k
    }
825
826
3.31k
    thisCtuState = INTER;
827
828
3.31k
    ITT_TASKEND( itt_domain_dec, itt_handle_lfcl );
829
3.31k
  }
830
831
24.9k
  case INTER:
832
24.9k
  {
833
24.9k
    if( std::all_of( cs.picture->slices.begin(), cs.picture->slices.end(), []( const Slice* pcSlice ) { return pcSlice->isIntra(); } ) )
vvdec::DecLibRecon::ctuTask<false>(int, void*)::{lambda(vvdec::Slice const*)#1}::operator()(vvdec::Slice const*) const
Line
Count
Source
833
3.55k
    if( std::all_of( cs.picture->slices.begin(), cs.picture->slices.end(), []( const Slice* pcSlice ) { return pcSlice->isIntra(); } ) )
vvdec::DecLibRecon::ctuTask<true>(int, void*)::{lambda(vvdec::Slice const*)#1}::operator()(vvdec::Slice const*) const
Line
Count
Source
833
21.3k
    if( std::all_of( cs.picture->slices.begin(), cs.picture->slices.end(), []( const Slice* pcSlice ) { return pcSlice->isIntra(); } ) )
834
24.9k
    {
835
      // not really necessary, but only for optimizing the wave-fronts
836
24.9k
      if( col > 1 && thisLine[col - 2] <= INTER )
837
21.3k
        return false;
838
3.57k
      if( line > 0 && lineAbove[col] <= INTER )
839
320
        return false;
840
3.57k
    }
841
842
3.25k
    if( std::any_of( cs.picture->refPicExtDepBarriers.cbegin(), cs.picture->refPicExtDepBarriers.cend(), []( const Barrier* b ) { return b->isBlocked(); } ) )
Unexecuted instantiation: vvdec::DecLibRecon::ctuTask<false>(int, void*)::{lambda(vvdec::Barrier const*)#1}::operator()(vvdec::Barrier const*) const
Unexecuted instantiation: vvdec::DecLibRecon::ctuTask<true>(int, void*)::{lambda(vvdec::Barrier const*)#1}::operator()(vvdec::Barrier const*) const
843
0
    {
844
0
      return false;
845
0
    }
846
847
3.25k
    if( onlyCheckReadyState )
848
240
      return true;
849
850
3.01k
    ITT_TASKSTART( itt_domain_dec, itt_handle_inter );
851
852
6.03k
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
853
3.01k
    {
854
3.01k
      const int ctuRsAddr    = ctu + line * cs.pcv->widthInCtus;
855
3.01k
      const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
856
3.01k
      const CtuData& ctuData = cs.getCtuData( ctuRsAddr );
857
858
3.01k
      decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskTrafoCtu( cs, ctuRsAddr, ctuArea );
859
860
3.01k
      if( !ctuData.slice->isIntra() )
861
0
      {
862
0
        decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskInterCtu( cs, ctuRsAddr, ctuArea );
863
864
0
        if( cs.picture->stillReferenced )
865
0
        {
866
0
          decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskFinishMotionInfo( cs, ctuRsAddr, ctu, line );
867
0
        }
868
0
      }
869
3.01k
    }
870
871
3.01k
    thisCtuState = INTRA;
872
873
3.01k
    ITT_TASKEND( itt_domain_dec, itt_handle_inter );
874
3.01k
  }
875
876
45.6k
  case INTRA:
877
45.6k
  {
878
45.6k
    if( col > 0 && thisLine[col - 1] <= INTRA_cont )
879
42.5k
      return false;
880
881
3.15k
    if( line > 0 )
882
1.16k
    {
883
1.16k
      if( col + 1 < tasksPerLine )
884
1.09k
      {
885
1.09k
        if( lineAbove[col + 1] <= INTRA )
886
531
          return false;
887
1.09k
      }
888
70
      else
889
70
      {
890
70
        if( lineAbove[col] <= INTRA_cont )
891
0
          return false;
892
70
      }
893
1.16k
    }
894
2.61k
    if( onlyCheckReadyState )
895
636
      return true;
896
897
1.98k
    ITT_TASKSTART( itt_domain_dec, itt_handle_intra );
898
899
3.96k
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
900
1.98k
    {
901
1.98k
      const int ctuRsAddr    = ctu + line * cs.pcv->widthInCtus;
902
1.98k
      const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
903
1.98k
      decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskCriticalIntraKernel( cs, ctuRsAddr, ctuArea );
904
905
1.98k
      thisCtuState = INTRA_cont;
906
1.98k
    }
907
908
1.98k
    thisCtuState = RSP;
909
910
1.98k
    ITT_TASKEND( itt_domain_dec, itt_handle_intra );
911
1.98k
  }
912
913
521k
  case RSP:
914
521k
  {
915
    // RIRZIIIII
916
    // IIIIIXXXX
917
    //
918
    // - Z can be reshaped when it is no more an intra prediction source for X in the next line
919
920
921
521k
    if     ( line + 1 < heightInCtus && col + 1 < tasksPerLine && lineBelow[col + 1] < INTRA_cont )
922
423k
      return false;
923
97.9k
    else if( line + 1 < heightInCtus &&                           lineBelow[col]     < RSP )
924
97.4k
      return false;
925
535
    else if(                            col + 1 < tasksPerLine && thisLine [col + 1] < INTRA_cont ) // need this for the last line
926
22
      return false;
927
928
513
    if( onlyCheckReadyState )
929
147
      return true;
930
931
366
    ITT_TASKSTART( itt_domain_dec, itt_handle_rsp );
932
933
515
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
934
149
    {
935
149
      decLib.m_pcThreadResource[tid]->m_cReshaper.rspCtuBcw( cs, ctu, line );
936
149
    }
937
938
366
    ITT_TASKEND( itt_domain_dec, itt_handle_rsp );
939
940
366
    thisCtuState = LF_V;
941
366
  }
942
943
389
  case LF_V:
944
389
  {
945
389
    if( col > 0 && thisLine[col - 1] < LF_V )
946
16
      return false;
947
373
    if( onlyCheckReadyState )
948
8
      return true;
949
950
365
    ITT_TASKSTART( itt_domain_dec, itt_handle_lfl );
951
952
513
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
953
148
    {
954
148
      decLib.m_cLoopFilter.loopFilterCTU( cs, MAX_NUM_CHANNEL_TYPE, ctu, line, EDGE_VER );
955
956
148
      thisCtuState = LF_V_cont;
957
148
    }
958
959
365
    thisCtuState = LF_H;
960
961
365
    ITT_TASKEND( itt_domain_dec, itt_handle_lfl );
962
365
  }
963
964
5.30k
  case LF_H:
965
5.30k
  {
966
5.30k
    if( line > 0 && lineAbove[col] < LF_H )
967
3
      return false;
968
969
5.30k
    if( line > 0 && col + 1 < tasksPerLine && lineAbove[col + 1] < LF_V_cont )
970
29
      return false;
971
972
5.27k
    if(             col + 1 < tasksPerLine && thisLine[col + 1] < LF_V_cont )
973
4.90k
      return false;
974
975
371
    if( onlyCheckReadyState )
976
57
      return true;
977
978
314
    ITT_TASKSTART( itt_domain_dec, itt_handle_lfl );
979
980
411
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
981
97
    {
982
97
      decLib.m_cLoopFilter.loopFilterCTU( cs, MAX_NUM_CHANNEL_TYPE, ctu, line, EDGE_HOR );
983
97
    }
984
985
314
    thisCtuState = PRESAO;
986
987
314
    ITT_TASKEND( itt_domain_dec, itt_handle_lfl );
988
314
  }
989
990
3.15k
  case PRESAO:
991
3.15k
  {
992
    // only last CTU processes full line
993
3.15k
    if( col == tasksPerLine - 1 )
994
406
    {
995
406
      if( line > 0 && lineAbove[col] <= PRESAO )
996
38
        return false;
997
998
513
      for( int c = 0; c < tasksPerLine; ++c )
999
503
      {
1000
503
        if( thisLine[c] < PRESAO )
1001
3
          return false;
1002
1003
500
        if( line + 1 < heightInCtus && lineBelow[c] < PRESAO )
1004
355
          return false;
1005
500
      }
1006
10
      if( onlyCheckReadyState )
1007
4
        return true;
1008
1009
6
      ITT_TASKSTART( itt_domain_dec, itt_handle_presao );
1010
1011
6
      if( cs.sps->getUseSAO() )
1012
6
      {
1013
6
        decLib.m_cSAO.SAOPrepareCTULine( cs, getLineArea( cs, line, true ) );
1014
6
      }
1015
1016
6
      ITT_TASKEND( itt_domain_dec, itt_handle_presao );
1017
6
    }
1018
2.75k
    else if( thisLine[tasksPerLine - 1] <= PRESAO )   // wait for last CTU to finish PRESAO
1019
2.51k
    {
1020
2.51k
      return false;
1021
2.51k
    }
1022
246
    if( onlyCheckReadyState )
1023
12
      return true;
1024
1025
234
    thisCtuState = SAO;
1026
234
  }
1027
1028
234
  case SAO:
1029
234
  {
1030
234
    if( onlyCheckReadyState )
1031
0
      return true;
1032
1033
    // only last CTU processes full line
1034
234
    if( cs.sps->getUseSAO() )
1035
18
    {
1036
18
      ITT_TASKSTART( itt_domain_dec, itt_handle_sao );
1037
1038
36
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1039
18
      {
1040
18
        const UnitArea  ctuArea = getCtuArea( cs, ctu, line, true );
1041
18
        decLib.m_cSAO.SAOProcessCTU( cs, ctuArea );
1042
18
      }
1043
1044
18
      ITT_TASKEND( itt_domain_dec, itt_handle_sao );
1045
18
    }
1046
234
    if( param->common.doALF )
1047
18
    {
1048
18
      ITT_TASKSTART( itt_domain_dec, itt_handle_alf );
1049
1050
36
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1051
18
      {
1052
18
        AdaptiveLoopFilter::prepareCTU( cs, ctu, line );
1053
1054
18
        thisCtuState = SAO_cont;
1055
18
      }
1056
1057
18
      ITT_TASKEND( itt_domain_dec, itt_handle_alf );
1058
18
    }
1059
1060
234
    thisCtuState = ALF;
1061
234
  }
1062
1063
722
  case ALF:
1064
722
  {
1065
722
    if( param->common.doALF )
1066
506
    {
1067
506
      const bool a = line > 0;
1068
506
      const bool b = line + 1 < heightInCtus;
1069
506
      const bool c = col > 0;
1070
506
      const bool d = col + 1 < tasksPerLine;
1071
1072
506
      if( a )
1073
329
      {
1074
329
        if( c && lineAbove[col - 1] < ALF ) return false;
1075
280
        if(      lineAbove[col    ] < ALF ) return false;
1076
196
        if( d && lineAbove[col + 1] < SAO_cont ) return false;
1077
196
      }
1078
1079
344
      if( b )
1080
298
      {
1081
298
        if( c && lineBelow[col - 1] < ALF ) return false;
1082
146
        if(      lineBelow[col    ] < ALF ) return false;
1083
98
        if( d && lineBelow[col + 1] < SAO_cont ) return false;
1084
98
      }
1085
1086
144
      if( c && thisLine[col - 1] < ALF ) return false;
1087
55
      if( d && thisLine[col + 1] < SAO_cont ) return false;
1088
1089
25
      if( onlyCheckReadyState )
1090
12
        return true;
1091
1092
13
      ITT_TASKSTART( itt_domain_dec, itt_handle_alf );
1093
31
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1094
18
      {
1095
18
        decLib.m_cALF.processCTU( cs, ctu, line, tid );
1096
18
      }
1097
13
      ITT_TASKEND( itt_domain_dec, itt_handle_alf );
1098
13
    }
1099
216
    else if( onlyCheckReadyState )
1100
0
      return true;
1101
1102
229
    thisCtuState = DONE;
1103
229
  }
1104
1105
229
  default:
1106
229
    CHECKD( thisCtuState != DONE, "Wrong CTU state" );
1107
663k
  }   // end switch
1108
1109
18
  return true;
1110
663k
}
bool vvdec::DecLibRecon::ctuTask<false>(int, void*)
Line
Count
Source
733
4.43k
{
734
4.43k
  CtuTaskParam* param = static_cast<CtuTaskParam*>( task_param );
735
736
4.43k
  const int       taskCol      = param->taskCol;
737
4.43k
  const int       line         = param->taskLine;
738
4.43k
  const int       col          = taskCol;
739
740
4.43k
  auto&           cs           = *param->common.cs;
741
4.43k
  auto&           decLib       = param->common.decLib;
742
4.43k
  const int       tasksPerLine = param->numTasksPerLine;
743
4.43k
  const int       heightInCtus = cs.pcv->heightInCtus;
744
745
4.43k
  CtuState&       thisCtuState =  param->common.ctuStates[line * tasksPerLine + taskCol];
746
4.43k
  const CtuState* thisLine     = &param->common.ctuStates[line * tasksPerLine];
747
4.43k
  const CtuState* lineAbove    = thisLine - tasksPerLine;
748
4.43k
  const CtuState* lineBelow    = thisLine + tasksPerLine;
749
750
4.43k
  const int       ctuStart     = param->ctuStart;
751
4.43k
  const int       ctuEnd       = param->ctuEnd;
752
753
4.43k
  if( cs.picture->m_ctuTaskCounter.hasException() )
754
5
  {
755
5
    std::rethrow_exception( cs.picture->m_ctuTaskCounter.getException() );
756
5
  }
757
758
4.43k
  switch( thisCtuState.load() )
759
4.43k
  {
760
    // all case statements fall through to continue with next task, unless they return false due to unsatisfied preconditions
761
762
3.32k
  case MIDER:
763
3.32k
  {
764
3.32k
    if( col > 0 && thisLine[col - 1] <= MIDER_cont )
765
0
      return false;
766
3.32k
    if( line > 0 )
767
1.22k
    {
768
1.22k
      if( col + 1 < tasksPerLine )
769
944
      {
770
944
        if( lineAbove[col + 1] <= MIDER )
771
0
          return false;
772
944
      }
773
278
      else
774
278
      {
775
278
        if( lineAbove[col] <= MIDER_cont )
776
0
          return false;
777
278
      }
778
1.22k
    }
779
3.32k
    if( onlyCheckReadyState )
780
0
      return true;
781
782
3.32k
    ITT_TASKSTART( itt_domain_dec, itt_handle_mider );
783
784
6.64k
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
785
3.32k
    {
786
3.32k
      const int ctuRsAddr = ctu + line * cs.pcv->widthInCtus;
787
3.32k
      CtuData& ctuData    = cs.getCtuData( ctuRsAddr );
788
3.32k
      ctuData.motion      = &decLib.m_motionInfo[cs.pcv->num4x4CtuBlks * ctuRsAddr];
789
790
3.32k
      if( !ctuData.slice->isIntra() || cs.sps->getIBCFlag() )
791
3.32k
      {
792
3.32k
        const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
793
3.32k
        decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskDeriveCtuMotionInfo( cs, ctuRsAddr, ctuArea, param->common.perLineMiHist[line] );
794
3.32k
      }
795
0
      else
796
0
      {
797
0
        memset( NO_WARNING_class_memaccess( ctuData.motion ), MI_NOT_VALID, sizeof( MotionInfo ) * cs.pcv->num4x4CtuBlks );
798
0
      }
799
800
3.32k
      thisCtuState = MIDER_cont;
801
3.32k
    }
802
803
3.32k
    thisCtuState = LF_INIT;
804
805
3.32k
    ITT_TASKEND( itt_domain_dec, itt_handle_mider );
806
3.32k
  }
807
808
3.32k
  case LF_INIT:
809
3.32k
  {
810
3.32k
    if( onlyCheckReadyState )
811
0
      return true;
812
813
3.32k
    ITT_TASKSTART( itt_domain_dec, itt_handle_lfcl );
814
815
6.64k
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
816
3.32k
    {
817
3.32k
      const int ctuRsAddr = ctu + line * cs.pcv->widthInCtus;
818
3.32k
      CtuData& ctuData    = cs.getCtuData( ctuRsAddr );
819
3.32k
      ctuData.lfParam[0]  = &decLib.m_loopFilterParam[cs.pcv->num4x4CtuBlks * ( 2 * ctuRsAddr + 0 )];
820
3.32k
      ctuData.lfParam[1]  = &decLib.m_loopFilterParam[cs.pcv->num4x4CtuBlks * ( 2 * ctuRsAddr + 1 )];
821
3.32k
      memset( ctuData.lfParam[0], 0, sizeof( LoopFilterParam ) * 2 * cs.pcv->num4x4CtuBlks );
822
823
3.32k
      decLib.m_cLoopFilter.calcFilterStrengthsCTU( cs, ctuRsAddr );
824
3.32k
    }
825
826
3.32k
    thisCtuState = INTER;
827
828
3.32k
    ITT_TASKEND( itt_domain_dec, itt_handle_lfcl );
829
3.32k
  }
830
831
3.55k
  case INTER:
832
3.55k
  {
833
3.55k
    if( std::all_of( cs.picture->slices.begin(), cs.picture->slices.end(), []( const Slice* pcSlice ) { return pcSlice->isIntra(); } ) )
834
3.55k
    {
835
      // not really necessary, but only for optimizing the wave-fronts
836
3.55k
      if( col > 1 && thisLine[col - 2] <= INTER )
837
513
        return false;
838
3.04k
      if( line > 0 && lineAbove[col] <= INTER )
839
26
        return false;
840
3.04k
    }
841
842
3.02k
    if( std::any_of( cs.picture->refPicExtDepBarriers.cbegin(), cs.picture->refPicExtDepBarriers.cend(), []( const Barrier* b ) { return b->isBlocked(); } ) )
843
0
    {
844
0
      return false;
845
0
    }
846
847
3.02k
    if( onlyCheckReadyState )
848
0
      return true;
849
850
3.02k
    ITT_TASKSTART( itt_domain_dec, itt_handle_inter );
851
852
6.03k
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
853
3.01k
    {
854
3.01k
      const int ctuRsAddr    = ctu + line * cs.pcv->widthInCtus;
855
3.01k
      const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
856
3.01k
      const CtuData& ctuData = cs.getCtuData( ctuRsAddr );
857
858
3.01k
      decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskTrafoCtu( cs, ctuRsAddr, ctuArea );
859
860
3.01k
      if( !ctuData.slice->isIntra() )
861
0
      {
862
0
        decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskInterCtu( cs, ctuRsAddr, ctuArea );
863
864
0
        if( cs.picture->stillReferenced )
865
0
        {
866
0
          decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskFinishMotionInfo( cs, ctuRsAddr, ctu, line );
867
0
        }
868
0
      }
869
3.01k
    }
870
871
3.02k
    thisCtuState = INTRA;
872
873
3.02k
    ITT_TASKEND( itt_domain_dec, itt_handle_inter );
874
3.02k
  }
875
876
3.65k
  case INTRA:
877
3.65k
  {
878
3.65k
    if( col > 0 && thisLine[col - 1] <= INTRA_cont )
879
1.60k
      return false;
880
881
2.05k
    if( line > 0 )
882
580
    {
883
580
      if( col + 1 < tasksPerLine )
884
543
      {
885
543
        if( lineAbove[col + 1] <= INTRA )
886
65
          return false;
887
543
      }
888
37
      else
889
37
      {
890
37
        if( lineAbove[col] <= INTRA_cont )
891
0
          return false;
892
37
      }
893
580
    }
894
1.98k
    if( onlyCheckReadyState )
895
0
      return true;
896
897
1.98k
    ITT_TASKSTART( itt_domain_dec, itt_handle_intra );
898
899
3.97k
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
900
1.98k
    {
901
1.98k
      const int ctuRsAddr    = ctu + line * cs.pcv->widthInCtus;
902
1.98k
      const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
903
1.98k
      decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskCriticalIntraKernel( cs, ctuRsAddr, ctuArea );
904
905
1.98k
      thisCtuState = INTRA_cont;
906
1.98k
    }
907
908
1.98k
    thisCtuState = RSP;
909
910
1.98k
    ITT_TASKEND( itt_domain_dec, itt_handle_intra );
911
1.98k
  }
912
913
2.13k
  case RSP:
914
2.13k
  {
915
    // RIRZIIIII
916
    // IIIIIXXXX
917
    //
918
    // - Z can be reshaped when it is no more an intra prediction source for X in the next line
919
920
921
2.13k
    if     ( line + 1 < heightInCtus && col + 1 < tasksPerLine && lineBelow[col + 1] < INTRA_cont )
922
1.37k
      return false;
923
755
    else if( line + 1 < heightInCtus &&                           lineBelow[col]     < RSP )
924
237
      return false;
925
518
    else if(                            col + 1 < tasksPerLine && thisLine [col + 1] < INTRA_cont ) // need this for the last line
926
3
      return false;
927
928
515
    if( onlyCheckReadyState )
929
0
      return true;
930
931
515
    ITT_TASKSTART( itt_domain_dec, itt_handle_rsp );
932
933
664
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
934
149
    {
935
149
      decLib.m_pcThreadResource[tid]->m_cReshaper.rspCtuBcw( cs, ctu, line );
936
149
    }
937
938
515
    ITT_TASKEND( itt_domain_dec, itt_handle_rsp );
939
940
515
    thisCtuState = LF_V;
941
515
  }
942
943
523
  case LF_V:
944
523
  {
945
523
    if( col > 0 && thisLine[col - 1] < LF_V )
946
9
      return false;
947
514
    if( onlyCheckReadyState )
948
0
      return true;
949
950
514
    ITT_TASKSTART( itt_domain_dec, itt_handle_lfl );
951
952
662
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
953
148
    {
954
148
      decLib.m_cLoopFilter.loopFilterCTU( cs, MAX_NUM_CHANNEL_TYPE, ctu, line, EDGE_VER );
955
956
148
      thisCtuState = LF_V_cont;
957
148
    }
958
959
514
    thisCtuState = LF_H;
960
961
514
    ITT_TASKEND( itt_domain_dec, itt_handle_lfl );
962
514
  }
963
964
570
  case LF_H:
965
570
  {
966
570
    if( line > 0 && lineAbove[col] < LF_H )
967
1
      return false;
968
969
569
    if( line > 0 && col + 1 < tasksPerLine && lineAbove[col + 1] < LF_V_cont )
970
2
      return false;
971
972
567
    if(             col + 1 < tasksPerLine && thisLine[col + 1] < LF_V_cont )
973
104
      return false;
974
975
463
    if( onlyCheckReadyState )
976
0
      return true;
977
978
463
    ITT_TASKSTART( itt_domain_dec, itt_handle_lfl );
979
980
560
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
981
97
    {
982
97
      decLib.m_cLoopFilter.loopFilterCTU( cs, MAX_NUM_CHANNEL_TYPE, ctu, line, EDGE_HOR );
983
97
    }
984
985
463
    thisCtuState = PRESAO;
986
987
463
    ITT_TASKEND( itt_domain_dec, itt_handle_lfl );
988
463
  }
989
990
479
  case PRESAO:
991
479
  {
992
    // only last CTU processes full line
993
479
    if( col == tasksPerLine - 1 )
994
34
    {
995
34
      if( line > 0 && lineAbove[col] <= PRESAO )
996
3
        return false;
997
998
49
      for( int c = 0; c < tasksPerLine; ++c )
999
43
      {
1000
43
        if( thisLine[c] < PRESAO )
1001
3
          return false;
1002
1003
40
        if( line + 1 < heightInCtus && lineBelow[c] < PRESAO )
1004
22
          return false;
1005
40
      }
1006
6
      if( onlyCheckReadyState )
1007
0
        return true;
1008
1009
6
      ITT_TASKSTART( itt_domain_dec, itt_handle_presao );
1010
1011
6
      if( cs.sps->getUseSAO() )
1012
6
      {
1013
6
        decLib.m_cSAO.SAOPrepareCTULine( cs, getLineArea( cs, line, true ) );
1014
6
      }
1015
1016
6
      ITT_TASKEND( itt_domain_dec, itt_handle_presao );
1017
6
    }
1018
445
    else if( thisLine[tasksPerLine - 1] <= PRESAO )   // wait for last CTU to finish PRESAO
1019
67
    {
1020
67
      return false;
1021
67
    }
1022
384
    if( onlyCheckReadyState )
1023
0
      return true;
1024
1025
384
    thisCtuState = SAO;
1026
384
  }
1027
1028
384
  case SAO:
1029
384
  {
1030
384
    if( onlyCheckReadyState )
1031
0
      return true;
1032
1033
    // only last CTU processes full line
1034
384
    if( cs.sps->getUseSAO() )
1035
18
    {
1036
18
      ITT_TASKSTART( itt_domain_dec, itt_handle_sao );
1037
1038
36
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1039
18
      {
1040
18
        const UnitArea  ctuArea = getCtuArea( cs, ctu, line, true );
1041
18
        decLib.m_cSAO.SAOProcessCTU( cs, ctuArea );
1042
18
      }
1043
1044
18
      ITT_TASKEND( itt_domain_dec, itt_handle_sao );
1045
18
    }
1046
384
    if( param->common.doALF )
1047
18
    {
1048
18
      ITT_TASKSTART( itt_domain_dec, itt_handle_alf );
1049
1050
36
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1051
18
      {
1052
18
        AdaptiveLoopFilter::prepareCTU( cs, ctu, line );
1053
1054
18
        thisCtuState = SAO_cont;
1055
18
      }
1056
1057
18
      ITT_TASKEND( itt_domain_dec, itt_handle_alf );
1058
18
    }
1059
1060
384
    thisCtuState = ALF;
1061
384
  }
1062
1063
396
  case ALF:
1064
396
  {
1065
396
    if( param->common.doALF )
1066
30
    {
1067
30
      const bool a = line > 0;
1068
30
      const bool b = line + 1 < heightInCtus;
1069
30
      const bool c = col > 0;
1070
30
      const bool d = col + 1 < tasksPerLine;
1071
1072
30
      if( a )
1073
22
      {
1074
22
        if( c && lineAbove[col - 1] < ALF ) return false;
1075
21
        if(      lineAbove[col    ] < ALF ) return false;
1076
19
        if( d && lineAbove[col + 1] < SAO_cont ) return false;
1077
19
      }
1078
1079
26
      if( b )
1080
18
      {
1081
18
        if( c && lineBelow[col - 1] < ALF ) return false;
1082
13
        if(      lineBelow[col    ] < ALF ) return false;
1083
12
        if( d && lineBelow[col + 1] < SAO_cont ) return false;
1084
12
      }
1085
1086
20
      if( c && thisLine[col - 1] < ALF ) return false;
1087
18
      if( d && thisLine[col + 1] < SAO_cont ) return false;
1088
1089
18
      if( onlyCheckReadyState )
1090
0
        return true;
1091
1092
18
      ITT_TASKSTART( itt_domain_dec, itt_handle_alf );
1093
36
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1094
18
      {
1095
18
        decLib.m_cALF.processCTU( cs, ctu, line, tid );
1096
18
      }
1097
18
      ITT_TASKEND( itt_domain_dec, itt_handle_alf );
1098
18
    }
1099
366
    else if( onlyCheckReadyState )
1100
0
      return true;
1101
1102
384
    thisCtuState = DONE;
1103
384
  }
1104
1105
384
  default:
1106
384
    CHECKD( thisCtuState != DONE, "Wrong CTU state" );
1107
4.43k
  }   // end switch
1108
1109
18
  return true;
1110
4.43k
}
bool vvdec::DecLibRecon::ctuTask<true>(int, void*)
Line
Count
Source
733
659k
{
734
659k
  CtuTaskParam* param = static_cast<CtuTaskParam*>( task_param );
735
736
659k
  const int       taskCol      = param->taskCol;
737
659k
  const int       line         = param->taskLine;
738
659k
  const int       col          = taskCol;
739
740
659k
  auto&           cs           = *param->common.cs;
741
659k
  auto&           decLib       = param->common.decLib;
742
659k
  const int       tasksPerLine = param->numTasksPerLine;
743
659k
  const int       heightInCtus = cs.pcv->heightInCtus;
744
745
659k
  CtuState&       thisCtuState =  param->common.ctuStates[line * tasksPerLine + taskCol];
746
659k
  const CtuState* thisLine     = &param->common.ctuStates[line * tasksPerLine];
747
659k
  const CtuState* lineAbove    = thisLine - tasksPerLine;
748
659k
  const CtuState* lineBelow    = thisLine + tasksPerLine;
749
750
659k
  const int       ctuStart     = param->ctuStart;
751
659k
  const int       ctuEnd       = param->ctuEnd;
752
753
659k
  if( cs.picture->m_ctuTaskCounter.hasException() )
754
3.46k
  {
755
3.46k
    std::rethrow_exception( cs.picture->m_ctuTaskCounter.getException() );
756
3.46k
  }
757
758
659k
  switch( thisCtuState.load() )
759
659k
  {
760
    // all case statements fall through to continue with next task, unless they return false due to unsatisfied preconditions
761
762
65.2k
  case MIDER:
763
65.2k
  {
764
65.2k
    if( col > 0 && thisLine[col - 1] <= MIDER_cont )
765
61.9k
      return false;
766
3.32k
    if( line > 0 )
767
1.22k
    {
768
1.22k
      if( col + 1 < tasksPerLine )
769
949
      {
770
949
        if( lineAbove[col + 1] <= MIDER )
771
5
          return false;
772
949
      }
773
278
      else
774
278
      {
775
278
        if( lineAbove[col] <= MIDER_cont )
776
0
          return false;
777
278
      }
778
1.22k
    }
779
3.31k
    if( onlyCheckReadyState )
780
3.32k
      return true;
781
782
18.4E
    ITT_TASKSTART( itt_domain_dec, itt_handle_mider );
783
784
18.4E
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
785
0
    {
786
0
      const int ctuRsAddr = ctu + line * cs.pcv->widthInCtus;
787
0
      CtuData& ctuData    = cs.getCtuData( ctuRsAddr );
788
0
      ctuData.motion      = &decLib.m_motionInfo[cs.pcv->num4x4CtuBlks * ctuRsAddr];
789
790
0
      if( !ctuData.slice->isIntra() || cs.sps->getIBCFlag() )
791
0
      {
792
0
        const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
793
0
        decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskDeriveCtuMotionInfo( cs, ctuRsAddr, ctuArea, param->common.perLineMiHist[line] );
794
0
      }
795
0
      else
796
0
      {
797
0
        memset( NO_WARNING_class_memaccess( ctuData.motion ), MI_NOT_VALID, sizeof( MotionInfo ) * cs.pcv->num4x4CtuBlks );
798
0
      }
799
800
0
      thisCtuState = MIDER_cont;
801
0
    }
802
803
18.4E
    thisCtuState = LF_INIT;
804
805
18.4E
    ITT_TASKEND( itt_domain_dec, itt_handle_mider );
806
18.4E
  }
807
808
18.4E
  case LF_INIT:
809
18.4E
  {
810
18.4E
    if( onlyCheckReadyState )
811
0
      return true;
812
813
18.4E
    ITT_TASKSTART( itt_domain_dec, itt_handle_lfcl );
814
815
18.4E
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
816
0
    {
817
0
      const int ctuRsAddr = ctu + line * cs.pcv->widthInCtus;
818
0
      CtuData& ctuData    = cs.getCtuData( ctuRsAddr );
819
0
      ctuData.lfParam[0]  = &decLib.m_loopFilterParam[cs.pcv->num4x4CtuBlks * ( 2 * ctuRsAddr + 0 )];
820
0
      ctuData.lfParam[1]  = &decLib.m_loopFilterParam[cs.pcv->num4x4CtuBlks * ( 2 * ctuRsAddr + 1 )];
821
0
      memset( ctuData.lfParam[0], 0, sizeof( LoopFilterParam ) * 2 * cs.pcv->num4x4CtuBlks );
822
823
0
      decLib.m_cLoopFilter.calcFilterStrengthsCTU( cs, ctuRsAddr );
824
0
    }
825
826
18.4E
    thisCtuState = INTER;
827
828
18.4E
    ITT_TASKEND( itt_domain_dec, itt_handle_lfcl );
829
18.4E
  }
830
831
21.3k
  case INTER:
832
21.3k
  {
833
21.3k
    if( std::all_of( cs.picture->slices.begin(), cs.picture->slices.end(), []( const Slice* pcSlice ) { return pcSlice->isIntra(); } ) )
834
21.3k
    {
835
      // not really necessary, but only for optimizing the wave-fronts
836
21.3k
      if( col > 1 && thisLine[col - 2] <= INTER )
837
20.8k
        return false;
838
530
      if( line > 0 && lineAbove[col] <= INTER )
839
294
        return false;
840
530
    }
841
842
239
    if( std::any_of( cs.picture->refPicExtDepBarriers.cbegin(), cs.picture->refPicExtDepBarriers.cend(), []( const Barrier* b ) { return b->isBlocked(); } ) )
843
0
    {
844
0
      return false;
845
0
    }
846
847
239
    if( onlyCheckReadyState )
848
240
      return true;
849
850
18.4E
    ITT_TASKSTART( itt_domain_dec, itt_handle_inter );
851
852
18.4E
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
853
0
    {
854
0
      const int ctuRsAddr    = ctu + line * cs.pcv->widthInCtus;
855
0
      const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
856
0
      const CtuData& ctuData = cs.getCtuData( ctuRsAddr );
857
858
0
      decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskTrafoCtu( cs, ctuRsAddr, ctuArea );
859
860
0
      if( !ctuData.slice->isIntra() )
861
0
      {
862
0
        decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskInterCtu( cs, ctuRsAddr, ctuArea );
863
864
0
        if( cs.picture->stillReferenced )
865
0
        {
866
0
          decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskFinishMotionInfo( cs, ctuRsAddr, ctu, line );
867
0
        }
868
0
      }
869
0
    }
870
871
18.4E
    thisCtuState = INTRA;
872
873
18.4E
    ITT_TASKEND( itt_domain_dec, itt_handle_inter );
874
18.4E
  }
875
876
42.0k
  case INTRA:
877
42.0k
  {
878
42.0k
    if( col > 0 && thisLine[col - 1] <= INTRA_cont )
879
40.9k
      return false;
880
881
1.10k
    if( line > 0 )
882
581
    {
883
581
      if( col + 1 < tasksPerLine )
884
548
      {
885
548
        if( lineAbove[col + 1] <= INTRA )
886
466
          return false;
887
548
      }
888
33
      else
889
33
      {
890
33
        if( lineAbove[col] <= INTRA_cont )
891
0
          return false;
892
33
      }
893
581
    }
894
634
    if( onlyCheckReadyState )
895
636
      return true;
896
897
18.4E
    ITT_TASKSTART( itt_domain_dec, itt_handle_intra );
898
899
18.4E
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
900
0
    {
901
0
      const int ctuRsAddr    = ctu + line * cs.pcv->widthInCtus;
902
0
      const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
903
0
      decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskCriticalIntraKernel( cs, ctuRsAddr, ctuArea );
904
905
0
      thisCtuState = INTRA_cont;
906
0
    }
907
908
18.4E
    thisCtuState = RSP;
909
910
18.4E
    ITT_TASKEND( itt_domain_dec, itt_handle_intra );
911
18.4E
  }
912
913
519k
  case RSP:
914
519k
  {
915
    // RIRZIIIII
916
    // IIIIIXXXX
917
    //
918
    // - Z can be reshaped when it is no more an intra prediction source for X in the next line
919
920
921
519k
    if     ( line + 1 < heightInCtus && col + 1 < tasksPerLine && lineBelow[col + 1] < INTRA_cont )
922
422k
      return false;
923
97.3k
    else if( line + 1 < heightInCtus &&                           lineBelow[col]     < RSP )
924
97.1k
      return false;
925
138
    else if(                            col + 1 < tasksPerLine && thisLine [col + 1] < INTRA_cont ) // need this for the last line
926
19
      return false;
927
928
18.4E
    if( onlyCheckReadyState )
929
147
      return true;
930
931
18.4E
    ITT_TASKSTART( itt_domain_dec, itt_handle_rsp );
932
933
18.4E
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
934
0
    {
935
0
      decLib.m_pcThreadResource[tid]->m_cReshaper.rspCtuBcw( cs, ctu, line );
936
0
    }
937
938
18.4E
    ITT_TASKEND( itt_domain_dec, itt_handle_rsp );
939
940
18.4E
    thisCtuState = LF_V;
941
18.4E
  }
942
943
18.4E
  case LF_V:
944
18.4E
  {
945
18.4E
    if( col > 0 && thisLine[col - 1] < LF_V )
946
7
      return false;
947
18.4E
    if( onlyCheckReadyState )
948
8
      return true;
949
950
18.4E
    ITT_TASKSTART( itt_domain_dec, itt_handle_lfl );
951
952
18.4E
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
953
0
    {
954
0
      decLib.m_cLoopFilter.loopFilterCTU( cs, MAX_NUM_CHANNEL_TYPE, ctu, line, EDGE_VER );
955
956
0
      thisCtuState = LF_V_cont;
957
0
    }
958
959
18.4E
    thisCtuState = LF_H;
960
961
18.4E
    ITT_TASKEND( itt_domain_dec, itt_handle_lfl );
962
18.4E
  }
963
964
4.73k
  case LF_H:
965
4.73k
  {
966
4.73k
    if( line > 0 && lineAbove[col] < LF_H )
967
2
      return false;
968
969
4.73k
    if( line > 0 && col + 1 < tasksPerLine && lineAbove[col + 1] < LF_V_cont )
970
27
      return false;
971
972
4.85k
    if(             col + 1 < tasksPerLine && thisLine[col + 1] < LF_V_cont )
973
4.80k
      return false;
974
975
18.4E
    if( onlyCheckReadyState )
976
57
      return true;
977
978
18.4E
    ITT_TASKSTART( itt_domain_dec, itt_handle_lfl );
979
980
18.4E
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
981
0
    {
982
0
      decLib.m_cLoopFilter.loopFilterCTU( cs, MAX_NUM_CHANNEL_TYPE, ctu, line, EDGE_HOR );
983
0
    }
984
985
18.4E
    thisCtuState = PRESAO;
986
987
18.4E
    ITT_TASKEND( itt_domain_dec, itt_handle_lfl );
988
18.4E
  }
989
990
2.67k
  case PRESAO:
991
2.67k
  {
992
    // only last CTU processes full line
993
2.67k
    if( col == tasksPerLine - 1 )
994
372
    {
995
372
      if( line > 0 && lineAbove[col] <= PRESAO )
996
35
        return false;
997
998
464
      for( int c = 0; c < tasksPerLine; ++c )
999
460
      {
1000
460
        if( thisLine[c] < PRESAO )
1001
0
          return false;
1002
1003
460
        if( line + 1 < heightInCtus && lineBelow[c] < PRESAO )
1004
333
          return false;
1005
460
      }
1006
4
      if( onlyCheckReadyState )
1007
4
        return true;
1008
1009
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_presao );
1010
1011
0
      if( cs.sps->getUseSAO() )
1012
0
      {
1013
0
        decLib.m_cSAO.SAOPrepareCTULine( cs, getLineArea( cs, line, true ) );
1014
0
      }
1015
1016
0
      ITT_TASKEND( itt_domain_dec, itt_handle_presao );
1017
0
    }
1018
2.30k
    else if( thisLine[tasksPerLine - 1] <= PRESAO )   // wait for last CTU to finish PRESAO
1019
2.44k
    {
1020
2.44k
      return false;
1021
2.44k
    }
1022
18.4E
    if( onlyCheckReadyState )
1023
12
      return true;
1024
1025
18.4E
    thisCtuState = SAO;
1026
18.4E
  }
1027
1028
18.4E
  case SAO:
1029
18.4E
  {
1030
18.4E
    if( onlyCheckReadyState )
1031
0
      return true;
1032
1033
    // only last CTU processes full line
1034
18.4E
    if( cs.sps->getUseSAO() )
1035
0
    {
1036
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_sao );
1037
1038
0
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1039
0
      {
1040
0
        const UnitArea  ctuArea = getCtuArea( cs, ctu, line, true );
1041
0
        decLib.m_cSAO.SAOProcessCTU( cs, ctuArea );
1042
0
      }
1043
1044
0
      ITT_TASKEND( itt_domain_dec, itt_handle_sao );
1045
0
    }
1046
18.4E
    if( param->common.doALF )
1047
0
    {
1048
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_alf );
1049
1050
0
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1051
0
      {
1052
0
        AdaptiveLoopFilter::prepareCTU( cs, ctu, line );
1053
1054
0
        thisCtuState = SAO_cont;
1055
0
      }
1056
1057
0
      ITT_TASKEND( itt_domain_dec, itt_handle_alf );
1058
0
    }
1059
1060
18.4E
    thisCtuState = ALF;
1061
18.4E
  }
1062
1063
326
  case ALF:
1064
326
  {
1065
326
    if( param->common.doALF )
1066
476
    {
1067
476
      const bool a = line > 0;
1068
476
      const bool b = line + 1 < heightInCtus;
1069
476
      const bool c = col > 0;
1070
476
      const bool d = col + 1 < tasksPerLine;
1071
1072
476
      if( a )
1073
307
      {
1074
307
        if( c && lineAbove[col - 1] < ALF ) return false;
1075
259
        if(      lineAbove[col    ] < ALF ) return false;
1076
177
        if( d && lineAbove[col + 1] < SAO_cont ) return false;
1077
177
      }
1078
1079
318
      if( b )
1080
280
      {
1081
280
        if( c && lineBelow[col - 1] < ALF ) return false;
1082
133
        if(      lineBelow[col    ] < ALF ) return false;
1083
86
        if( d && lineBelow[col + 1] < SAO_cont ) return false;
1084
86
      }
1085
1086
127
      if( c && thisLine[col - 1] < ALF ) return false;
1087
39
      if( d && thisLine[col + 1] < SAO_cont ) return false;
1088
1089
7
      if( onlyCheckReadyState )
1090
12
        return true;
1091
1092
18.4E
      ITT_TASKSTART( itt_domain_dec, itt_handle_alf );
1093
18.4E
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1094
0
      {
1095
0
        decLib.m_cALF.processCTU( cs, ctu, line, tid );
1096
0
      }
1097
18.4E
      ITT_TASKEND( itt_domain_dec, itt_handle_alf );
1098
18.4E
    }
1099
18.4E
    else if( onlyCheckReadyState )
1100
0
      return true;
1101
1102
18.4E
    thisCtuState = DONE;
1103
18.4E
  }
1104
1105
18.4E
  default:
1106
18.4E
    CHECKD( thisCtuState != DONE, "Wrong CTU state" );
1107
659k
  }   // end switch
1108
1109
0
  return true;
1110
659k
}
1111
1112
}