Coverage Report

Created: 2026-10-17 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/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
0
{
101
0
  this->cs = &cs;
102
103
0
  const int heightInCtus = cs.pcv->heightInCtus;
104
0
  CHECKD( !ctuStates.empty() && std::any_of( ctuStates.begin(), ctuStates.end(), []( CtuState& s ) { return s != DONE; } ), "some CTUs of previous pic not done" );
105
0
  ctuStates = std::vector<CtuState>( heightInCtus * tasksPerLine );
106
0
  for( auto& ctu: ctuStates )
107
0
  {
108
0
    ctu.store( ctuStartState );
109
0
  }
110
0
  perLineMiHist = std::vector<MotionHist>( heightInCtus );
111
0
  doALF         = _doALF;
112
0
}
113
114
DecLibRecon::DecLibRecon()
115
1.13k
{
116
1.13k
#if ENABLE_SIMD_OPT_BUFFER
117
#  if defined( TARGET_SIMD_X86 )
118
  g_pelBufOP.initPelBufOpsX86();
119
#  endif
120
#  if defined( TARGET_SIMD_ARM )
121
  g_pelBufOP.initPelBufOpsARM();
122
#  endif
123
1.13k
#endif
124
#if ENABLE_SIMD_TCOEFF_OPS && defined( TARGET_SIMD_X86 )
125
  g_tCoeffOps.initTCoeffOpsX86();
126
#endif
127
#if ENABLE_SIMD_TCOEFF_OPS && defined( TARGET_SIMD_ARM )
128
  g_tCoeffOps.initTCoeffOpsARM();
129
#endif
130
1.13k
}
131
132
void DecLibRecon::create( ThreadPool* threadPool, unsigned instanceId, bool upscaleOutputEnabled )
133
378
{
134
  // run constructor again to ensure all variables, especially in DecLibParser have been reset
135
378
  this->~DecLibRecon();
136
378
  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
378
  m_decodeThreadPool = threadPool;
152
378
  m_numDecThreads    = std::max( 1, threadPool ? threadPool->numThreads() : 1 );
153
154
378
  m_upscaleOutputEnabled = upscaleOutputEnabled;
155
378
  m_predBufSize     = 0;
156
378
  m_dmvrMvCacheSize = 0;
157
378
  m_dmvrMvCache     = nullptr;
158
159
378
  m_num4x4Elements   = 0;
160
378
  m_loopFilterParam  = nullptr;
161
378
  m_motionInfo       = nullptr;
162
163
378
  m_pcThreadResource    = new PerThreadResource*[m_numDecThreads];
164
378
  m_pcThreadResource[0] = new PerThreadResource();
165
12.0k
  for( int i = 1; i < m_numDecThreads; i++ )
166
11.7k
  {
167
11.7k
    m_pcThreadResource[i] = new PerThreadResource( m_pcThreadResource[0]->m_cTrQuant );
168
11.7k
  }
169
378
}
170
171
void DecLibRecon::destroy()
172
378
{
173
378
  m_decodeThreadPool = nullptr;
174
175
378
  if( m_predBuf )
176
0
  {
177
0
    m_predBuf.reset();
178
0
    m_predBufSize = 0;
179
0
  }
180
181
378
  if( m_dmvrMvCache )
182
0
  {
183
0
    free( m_dmvrMvCache );
184
0
    m_dmvrMvCache = nullptr;
185
0
    m_dmvrMvCacheSize = 0;
186
0
  }
187
188
378
  if( m_loopFilterParam )
189
0
  {
190
0
    free( m_loopFilterParam );
191
0
    m_loopFilterParam = nullptr;
192
0
  }
193
194
378
  if( m_motionInfo )
195
0
  {
196
0
    free( m_motionInfo );
197
0
    m_motionInfo = nullptr;
198
0
  }
199
200
378
  m_num4x4Elements = 0;
201
202
12.4k
  for( int i = 0; i < m_numDecThreads; i++ ) delete m_pcThreadResource[i];
203
378
  delete[] m_pcThreadResource; m_pcThreadResource = nullptr;
204
378
}
205
206
207
static void getCompatibleBuffer( const CodingStructure& cs, const CPelUnitBuf& srcBuf, PelStorage& destBuf, const UserAllocator* userAllocator )
208
0
{
209
0
  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
0
  if( destBuf.bufs.empty() )
231
0
  {
232
0
    destBuf.create( cs.picture->chromaFormat, cs.picture->lumaSize(), cs.pcv->maxCUWidth, cs.picture->margin, MEMORY_ALIGN_DEF_SIZE, true, userAllocator );
233
0
  }
234
0
}
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
  pic->m_subPicExtTasks.resize( numSubPic );
397
0
  for( int i = 0; i < numSubPic; ++i )
398
0
  {
399
0
    const SubPic& currSubPic = pps->getSubPic( i );
400
0
    const Area    subPicArea( currSubPic.getSubPicLeft(),
401
0
                              currSubPic.getSubPicTop(),
402
0
                              currSubPic.getSubPicWidthInLumaSample(),
403
0
                              currSubPic.getSubPicHeightInLumaSample() );
404
405
0
    pic->m_subPicRefBufs[i].create( pic->chromaFormat, Size( subPicArea ), sps->getMaxCUWidth(), pic->margin, MEMORY_ALIGN_DEF_SIZE );
406
407
0
    static auto task = []( int, void* task_param )
408
0
    {
409
0
      SubPicExtTask* t = static_cast<SubPicExtTask*>( task_param );
410
0
      t->subPicBuf->copyFrom( t->picture->getRecoBuf().subBuf( t->subPicArea ) );
411
0
      t->picture->extendPicBorderBuf( *t->subPicBuf );
412
0
      return true;
413
0
    };
414
0
    pic->m_subPicExtTasks[i] = SubPicExtTask{ pic, &pic->m_subPicRefBufs[i], subPicArea };
415
0
    m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string( currPic->poc ) + " subPicBorderExtTask refPOC:" + std::to_string( pic->poc ) )
416
0
                                        task,
417
0
                                        &pic->m_subPicExtTasks[i],
418
0
                                        &pic->m_borderExtTaskCounter,
419
0
                                        nullptr,
420
0
                                        { &pic->reconDone } );
421
0
  }
422
0
}
423
424
void DecLibRecon::swapBufs( CodingStructure& cs )
425
0
{
426
0
  cs.picture->m_bufs[PIC_RECONSTRUCTION].swap( m_fltBuf );
427
0
  cs.rebindPicBufs();   // ensure the recon buf in the coding structure points to the correct buffer
428
0
}
429
430
void DecLibRecon::decompressPicture( Picture* pcPic )
431
0
{
432
0
  m_currDecompPic = pcPic;
433
434
0
  CodingStructure& cs = *pcPic->cs;
435
436
0
  pcPic->progress = Picture::reconstructing;
437
438
#ifdef TRACE_ENABLE_ITT
439
  // mark start of frame
440
    pcPic->m_itt_decLibInst = m_itt_decInst;
441
  __itt_frame_begin_v3( pcPic->m_itt_decLibInst, nullptr );
442
#endif
443
444
  // Initialise the various objects for the new set of settings
445
0
  const SPS * sps = cs.sps.get();
446
0
  const PPS * pps = cs.pps.get();
447
448
0
  for( int i = 0; i < m_numDecThreads; i++ )
449
0
  {
450
0
    if( sps->getUseReshaper() )
451
0
    {
452
0
      m_pcThreadResource[i]->m_cReshaper.createDec( sps->getBitDepth() );
453
0
      m_pcThreadResource[i]->m_cReshaper.initSlice( pcPic->slices[0]->getNalUnitLayerId(), *pcPic->slices[0]->getPicHeader(), pcPic->slices[0]->getVPS_nothrow() );
454
0
    }
455
456
0
    m_pcThreadResource[i]->m_cIntraPred.init( sps->getChromaFormatIdc(), sps->getBitDepth() );
457
0
    m_pcThreadResource[i]->m_cInterPred.init( &m_cRdCost, sps->getChromaFormatIdc(), sps->getMaxCUHeight() );
458
459
    // Recursive structure
460
0
    m_pcThreadResource[i]->m_cTrQuant.init( pcPic );
461
0
    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 );
462
0
  }
463
464
0
  getCompatibleBuffer( *pcPic->cs, pcPic->cs->getRecoBuf(), m_fltBuf, pcPic->getUserAllocator() );
465
466
0
  const uint32_t  log2SaoOffsetScale = (uint32_t) std::max(0, sps->getBitDepth() - MAX_SAO_TRUNCATED_BITDEPTH);
467
0
  const int maxDepth = getLog2(sps->getMaxCUWidth()) - pps->pcv->minCUWidthLog2;
468
0
  m_cSAO.create( pps->getPicWidthInLumaSamples(),
469
0
                 pps->getPicHeightInLumaSamples(),
470
0
                 sps->getChromaFormatIdc(),
471
0
                 sps->getMaxCUWidth(),
472
0
                 sps->getMaxCUHeight(),
473
0
                 maxDepth,
474
0
                 log2SaoOffsetScale,
475
0
                 m_fltBuf
476
0
               );
477
478
0
  if( sps->getUseALF() )
479
0
  {
480
0
    m_cALF.create( cs.picHeader.get(), sps, pps, m_numDecThreads, m_fltBuf );
481
0
  }
482
483
0
  const PreCalcValues* pcv = cs.pcv;
484
485
  // set reconstruction buffers in CodingStructure
486
0
  const ptrdiff_t ctuSampleSizeL = pcv->maxCUHeight * pcv->maxCUWidth;
487
0
  const ptrdiff_t ctuSampleSizeC = isChromaEnabled( pcv->chrFormat ) ? ( ctuSampleSizeL >> ( getChannelTypeScaleX( CH_C, pcv->chrFormat ) + getChannelTypeScaleY( CH_C, pcv->chrFormat ) ) ) : 0;
488
0
  const ptrdiff_t ctuSampleSize  = ctuSampleSizeL + 2 * ctuSampleSizeC;
489
0
  const size_t    predBufSize    = ctuSampleSize * pcv->sizeInCtus;
490
0
  if( predBufSize != m_predBufSize )
491
0
  {
492
0
    m_predBuf.reset( ( Pel* ) xMalloc( Pel, predBufSize ) );
493
0
    m_predBufSize = predBufSize;
494
0
  }
495
496
0
  pcPic->cs->m_predBuf = m_predBuf.get();
497
498
  // for the worst case of all PUs being 8x8 and using DMVR
499
0
  const size_t _maxNumDmvrMvs = pcv->num8x8CtuBlks * pcv->sizeInCtus;
500
0
  if( _maxNumDmvrMvs != m_dmvrMvCacheSize )
501
0
  {
502
0
    if( m_dmvrMvCache ) free( m_dmvrMvCache );
503
0
    m_dmvrMvCacheSize = _maxNumDmvrMvs;
504
0
    m_dmvrMvCache     = ( Mv* ) malloc( sizeof( Mv ) * _maxNumDmvrMvs );
505
0
  }
506
507
0
  pcPic->cs->m_dmvrMvCache = m_dmvrMvCache;
508
509
0
  if( m_num4x4Elements != cs.pcv->num4x4CtuBlks * cs.pcv->sizeInCtus )
510
0
  {
511
0
    if( m_loopFilterParam ) free( m_loopFilterParam );
512
0
    if( m_motionInfo      ) free( m_motionInfo );
513
514
0
    m_num4x4Elements = cs.pcv->num4x4CtuBlks * cs.pcv->sizeInCtus;
515
516
0
    m_loopFilterParam = ( LoopFilterParam* ) malloc( sizeof( LoopFilterParam ) * m_num4x4Elements * 2 );
517
0
    m_motionInfo      = ( MotionInfo* )      malloc( sizeof( MotionInfo      ) * m_num4x4Elements );
518
0
  }
519
  // finished
520
521
0
  const int widthInCtus  = cs.pcv->widthInCtus;
522
0
  const int heightInCtus = cs.pcv->heightInCtus;
523
524
0
  pcPic->startProcessingTimer();
525
526
0
  if( m_decodeThreadPool->numThreads() > 0 )
527
0
  {
528
0
    ITT_TASKSTART( itt_domain_dec, itt_handle_schedTasks );
529
0
  }
530
531
0
  picBarriers.clear();
532
0
#if ALLOW_MIDER_LF_DURING_PICEXT
533
0
  CBarrierVec  picExtBarriers;
534
#else
535
  CBarrierVec &picExtBarriers = picBarriers;
536
#endif
537
538
0
  const int numSubPic = cs.pps->getNumSubPics();
539
540
0
  std::vector<Picture*> borderExtRefPics( pcPic->buildAllRefPicsVec() );
541
0
  for( Picture* refPic : borderExtRefPics )
542
0
  {
543
0
    if( !refPic->borderExtStarted )
544
0
    {
545
      // TODO: (GH) Can we bypass this border extension, when all subpics (>1) are treated as pics?
546
0
      borderExtPic( refPic, pcPic );
547
0
    }
548
549
0
    if( !refPic->subPicExtStarted && numSubPic > 1 && refPic->m_subPicRefBufs.size() != numSubPic )
550
0
    {
551
0
      CHECK( !refPic->m_subPicRefBufs.empty(), "Wrong number of subpics already present in reference picture" );
552
0
      CHECK( cs.sps->getUseWrapAround(), "Wraparound + subpics not implemented" );
553
554
0
      createSubPicRefBufs( refPic, pcPic );
555
0
    }
556
557
0
    if( refPic->m_borderExtTaskCounter.isBlocked() &&
558
0
        std::find( picExtBarriers.cbegin(), picExtBarriers.cend(), refPic->m_borderExtTaskCounter.donePtr() ) == picExtBarriers.cend() )
559
0
    {
560
0
      picExtBarriers.push_back( refPic->m_borderExtTaskCounter.donePtr() );
561
0
    }
562
0
  }
563
564
0
  if( m_decodeThreadPool->numThreads() == 0 && (
565
0
       std::any_of( picExtBarriers.cbegin(), picExtBarriers.cend(), []( const Barrier* b ) { return b->isBlocked(); } ) ||
566
0
       std::any_of( picBarriers   .cbegin(), picBarriers   .cend(), []( const Barrier* b ) { return b->isBlocked(); } ) ) )
567
0
  {
568
0
    m_decodeThreadPool->processTasksOnMainThread();
569
0
  }
570
571
0
  const bool isIntra = std::all_of( pcPic->slices.begin(), pcPic->slices.end(), []( const Slice* pcSlice ) { return pcSlice->isIntra(); } );
572
573
0
  const int numColPerTask = std::max( std::min( widthInCtus, ( widthInCtus / std::max( m_numDecThreads * ( isIntra ? 2 : 1 ), 1 ) ) + ( isIntra ? 0 : 1 ) ), 1 );
574
0
  const int numTasksPerLine = widthInCtus / numColPerTask + !!( widthInCtus % numColPerTask );
575
576
0
#if ALLOW_MIDER_LF_DURING_PICEXT
577
0
  pcPic->refPicExtDepBarriers = std::move( picExtBarriers );
578
0
#endif
579
#if !RECO_WHILE_PARSE
580
  picBarriers.push_back( &cs.picture->parseDone );
581
#endif
582
583
0
  const TaskType ctuStartState = MIDER;
584
0
  const bool     doALF         = cs.sps->getUseALF() && !AdaptiveLoopFilter::getAlfSkipPic( cs );
585
0
  commonTaskParam.reset( cs, ctuStartState, numTasksPerLine, doALF );
586
587
0
  tasksFinishMotion = std::vector<LineTaskParam>( heightInCtus, LineTaskParam{ commonTaskParam, -1 } );
588
0
  tasksCtu          = std::vector<CtuTaskParam >( heightInCtus * numTasksPerLine, CtuTaskParam{ commonTaskParam, -1, -1, {} } );
589
590
0
  pcPic->reconDone.lock();
591
592
#if 0
593
  // schedule in raster scan order
594
  for( int line = 0; line < heightInCtus; ++line )
595
  {
596
    for( int col = 0; col < widthInCtus;  ++col )
597
    {
598
#else
599
  // schedule in zig-zag scan order
600
0
  for( int i = 0; i < numTasksPerLine + heightInCtus; ++i )
601
0
  {
602
0
    int line = 0;
603
0
    for( int col = i; col >= 0; --col, ++line )
604
0
    {
605
0
#endif
606
0
      if( line < heightInCtus && col < numTasksPerLine )
607
0
      {
608
0
        CBarrierVec ctuBarriers = picBarriers;
609
0
        const int   ctuStart    = col * numColPerTask;
610
0
        const int   ctuEnd      = std::min( ctuStart + numColPerTask, widthInCtus );
611
612
0
#if RECO_WHILE_PARSE
613
0
        if( pcPic->parseDone.isBlocked() )
614
0
        {
615
          // wait for the last CTU in the current line to be parsed
616
0
          ctuBarriers.push_back( &pcPic->ctuParsedBarrier[( line + 1 ) * widthInCtus - 1] );
617
0
        }
618
619
0
#endif
620
0
        CtuTaskParam* param    = &tasksCtu[line * numTasksPerLine + col];
621
0
        param->taskLine        = line;
622
0
        param->taskCol         = col;
623
0
        param->ctuEnd          = ctuEnd;
624
0
        param->ctuStart        = ctuStart;
625
0
        param->numColPerTask   = numColPerTask;
626
0
        param->numTasksPerLine = numTasksPerLine;
627
628
0
        m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string(pcPic->poc) + " ctuTask:" + std::to_string( col ) + "," + std::to_string( line ) )
629
0
                                            ctuTask<false>,
630
0
                                            param,
631
0
                                            &pcPic->m_ctuTaskCounter,
632
0
                                            nullptr,
633
0
                                            std::move( ctuBarriers ),
634
0
                                            ctuTask<true> );
635
0
      }
636
0
    }
637
0
  }
638
639
0
  {
640
0
    static auto finishReconTask = []( int, void* task_param )
641
0
    {
642
0
      FinishPicTaskParam* param = static_cast<FinishPicTaskParam*>( task_param );
643
0
      CodingStructure& cs = *param->pic->cs;
644
645
0
      if( cs.sps->getUseALF() && !AdaptiveLoopFilter::getAlfSkipPic( cs ) )
646
0
      {
647
0
        param->decLib->swapBufs( cs );
648
0
      }
649
650
0
      cs.deallocTempInternals();
651
652
#ifdef TRACE_ENABLE_ITT
653
      // mark end of frame
654
      __itt_frame_end_v3( param->pic->m_itt_decLibInst, nullptr );
655
#endif
656
0
      param->pic->stopProcessingTimer();
657
658
0
      param->pic->progress = Picture::reconstructed;
659
0
      return true;
660
0
    };
661
662
0
    taskFinishPic = FinishPicTaskParam( this, pcPic );
663
0
    m_decodeThreadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string( pcPic->poc ) + " finishPicTask" )
664
0
                                        finishReconTask,
665
0
                                        &taskFinishPic,
666
0
                                        &pcPic->m_divTasksCounter,
667
0
                                        &pcPic->reconDone,
668
0
                                        { pcPic->m_ctuTaskCounter.donePtr() } );
669
0
  }
670
671
0
  if( m_decodeThreadPool->numThreads() == 0 )
672
0
  {
673
0
  }
674
0
  else
675
0
  {
676
0
    ITT_TASKEND( itt_domain_dec, itt_handle_schedTasks );
677
0
  }
678
0
}
679
680
Picture* DecLibRecon::waitForPrevDecompressedPic()
681
376
{
682
376
  if( !m_currDecompPic )
683
376
    return nullptr;
684
685
0
  ITT_TASKSTART( itt_domain_dec, itt_handle_waitTasks );
686
0
  try
687
0
  {
688
0
    if( m_decodeThreadPool->numThreads() == 0 )
689
0
    {
690
0
      m_decodeThreadPool->processTasksOnMainThread();
691
0
      CHECK_FATAL( m_currDecompPic->reconDone.isBlocked(),
692
0
                   "can't make progress reconstructing POC " << m_currDecompPic->poc << ". some dependency has not been finished." );
693
0
    }
694
695
0
    const Slice*   lastSlice           = m_currDecompPic->slices.back();
696
0
    const unsigned lastSliceLastCtuIdx = lastSlice->getCtuAddrInSlice( lastSlice->getNumCtuInSlice() - 1 );
697
0
    CHECK( lastSliceLastCtuIdx != m_currDecompPic->cs->pcv->sizeInCtus - 1, "Picture incomplete. A slice was probably lost." );
698
699
0
    m_currDecompPic->reconDone.wait();
700
0
  }
701
0
  catch( ... )
702
0
  {
703
0
    m_currDecompPic->error = true;
704
0
    m_currDecompPic->reconDone.setException( std::current_exception() );
705
0
  }
706
707
  // also check error flag, which can have been set earlier (e.g., when trying to use the picture as reference)
708
0
  if( m_currDecompPic->error || m_currDecompPic->reconDone.hasException() )
709
0
  {
710
    // ensure all tasks are cleared from declibRecon
711
0
    cleanupOnException();
712
0
  }
713
714
0
  ITT_TASKEND( itt_domain_dec, itt_handle_waitTasks );
715
716
0
  return std::exchange( m_currDecompPic, nullptr );
717
0
}
718
719
void DecLibRecon::cleanupOnException()
720
0
{
721
0
  if( m_decodeThreadPool->numThreads() == 0 )
722
0
  {
723
0
    CHECK_FATAL( m_decodeThreadPool->processTasksOnMainThread() != true, "can't make progress: stuck tasks." );
724
0
  }
725
726
  // there was an exception anywhere in m_currDecompPic
727
  // => we need to wait for all tasks to be cleared from the thread pool
728
0
  m_currDecompPic->waitForAllTasks();
729
730
0
  commonTaskParam.ctuStates.clear();
731
0
}
732
733
template<bool onlyCheckReadyState>
734
bool DecLibRecon::ctuTask( int tid, void* task_param )
735
0
{
736
0
  CtuTaskParam* param = static_cast<CtuTaskParam*>( task_param );
737
738
0
  const int       taskCol      = param->taskCol;
739
0
  const int       line         = param->taskLine;
740
0
  const int       col          = taskCol;
741
742
0
  auto&           cs           = *param->common.cs;
743
0
  auto&           decLib       = param->common.decLib;
744
0
  const int       tasksPerLine = param->numTasksPerLine;
745
0
  const int       heightInCtus = cs.pcv->heightInCtus;
746
747
0
  CtuState&       thisCtuState =  param->common.ctuStates[line * tasksPerLine + taskCol];
748
0
  const CtuState* thisLine     = &param->common.ctuStates[line * tasksPerLine];
749
0
  const CtuState* lineAbove    = thisLine - tasksPerLine;
750
0
  const CtuState* lineBelow    = thisLine + tasksPerLine;
751
752
0
  const int       ctuStart     = param->ctuStart;
753
0
  const int       ctuEnd       = param->ctuEnd;
754
755
0
  if( cs.picture->m_ctuTaskCounter.hasException() )
756
0
  {
757
0
    std::rethrow_exception( cs.picture->m_ctuTaskCounter.getException() );
758
0
  }
759
760
0
  switch( thisCtuState.load() )
761
0
  {
762
    // all case statements fall through to continue with next task, unless they return false due to unsatisfied preconditions
763
764
0
  case MIDER:
765
0
  {
766
0
    if( col > 0 && thisLine[col - 1] <= MIDER_cont )
767
0
      return false;
768
0
    if( line > 0 )
769
0
    {
770
0
      if( col + 1 < tasksPerLine )
771
0
      {
772
0
        if( lineAbove[col + 1] <= MIDER )
773
0
          return false;
774
0
      }
775
0
      else
776
0
      {
777
0
        if( lineAbove[col] <= MIDER_cont )
778
0
          return false;
779
0
      }
780
0
    }
781
0
    if( onlyCheckReadyState )
782
0
      return true;
783
784
0
    ITT_TASKSTART( itt_domain_dec, itt_handle_mider );
785
786
0
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
787
0
    {
788
0
      const int ctuRsAddr = ctu + line * cs.pcv->widthInCtus;
789
0
      CtuData& ctuData    = cs.getCtuData( ctuRsAddr );
790
0
      ctuData.motion      = &decLib.m_motionInfo[cs.pcv->num4x4CtuBlks * ctuRsAddr];
791
792
0
      if( !ctuData.slice->isIntra() || cs.sps->getIBCFlag() )
793
0
      {
794
0
        const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
795
0
        decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskDeriveCtuMotionInfo( cs, ctuRsAddr, ctuArea, param->common.perLineMiHist[line] );
796
0
      }
797
0
      else
798
0
      {
799
0
        memset( NO_WARNING_class_memaccess( ctuData.motion ), MI_NOT_VALID, sizeof( MotionInfo ) * cs.pcv->num4x4CtuBlks );
800
0
      }
801
802
0
      thisCtuState = MIDER_cont;
803
0
    }
804
805
0
    thisCtuState = LF_INIT;
806
807
0
    ITT_TASKEND( itt_domain_dec, itt_handle_mider );
808
0
  }
809
810
0
  case LF_INIT:
811
0
  {
812
0
    if( onlyCheckReadyState )
813
0
      return true;
814
815
0
    ITT_TASKSTART( itt_domain_dec, itt_handle_lfcl );
816
817
0
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
818
0
    {
819
0
      const int ctuRsAddr = ctu + line * cs.pcv->widthInCtus;
820
0
      CtuData& ctuData    = cs.getCtuData( ctuRsAddr );
821
0
      ctuData.lfParam[0]  = &decLib.m_loopFilterParam[cs.pcv->num4x4CtuBlks * ( 2 * ctuRsAddr + 0 )];
822
0
      ctuData.lfParam[1]  = &decLib.m_loopFilterParam[cs.pcv->num4x4CtuBlks * ( 2 * ctuRsAddr + 1 )];
823
0
      memset( ctuData.lfParam[0], 0, sizeof( LoopFilterParam ) * 2 * cs.pcv->num4x4CtuBlks );
824
825
0
      decLib.m_cLoopFilter.calcFilterStrengthsCTU( cs, ctuRsAddr );
826
0
    }
827
828
0
    thisCtuState = INTER;
829
830
0
    ITT_TASKEND( itt_domain_dec, itt_handle_lfcl );
831
0
  }
832
833
0
  case INTER:
834
0
  {
835
0
    if( std::all_of( cs.picture->slices.begin(), cs.picture->slices.end(), []( const Slice* pcSlice ) { return pcSlice->isIntra(); } ) )
Unexecuted instantiation: vvdec::DecLibRecon::ctuTask<false>(int, void*)::{lambda(vvdec::Slice const*)#1}::operator()(vvdec::Slice const*) const
Unexecuted instantiation: vvdec::DecLibRecon::ctuTask<true>(int, void*)::{lambda(vvdec::Slice const*)#1}::operator()(vvdec::Slice const*) const
836
0
    {
837
      // not really necessary, but only for optimizing the wave-fronts
838
0
      if( col > 1 && thisLine[col - 2] <= INTER )
839
0
        return false;
840
0
      if( line > 0 && lineAbove[col] <= INTER )
841
0
        return false;
842
0
    }
843
844
0
    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
845
0
    {
846
0
      return false;
847
0
    }
848
849
0
    if( onlyCheckReadyState )
850
0
      return true;
851
852
0
    ITT_TASKSTART( itt_domain_dec, itt_handle_inter );
853
854
0
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
855
0
    {
856
0
      const int ctuRsAddr    = ctu + line * cs.pcv->widthInCtus;
857
0
      const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
858
0
      const CtuData& ctuData = cs.getCtuData( ctuRsAddr );
859
860
0
      decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskTrafoCtu( cs, ctuRsAddr, ctuArea );
861
862
0
      if( !ctuData.slice->isIntra() )
863
0
      {
864
0
        decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskInterCtu( cs, ctuRsAddr, ctuArea );
865
866
0
        if( cs.picture->stillReferenced )
867
0
        {
868
0
          decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskFinishMotionInfo( cs, ctuRsAddr, ctu, line );
869
0
        }
870
0
      }
871
0
    }
872
873
0
    thisCtuState = INTRA;
874
875
0
    ITT_TASKEND( itt_domain_dec, itt_handle_inter );
876
0
  }
877
878
0
  case INTRA:
879
0
  {
880
0
    if( col > 0 && thisLine[col - 1] <= INTRA_cont )
881
0
      return false;
882
883
0
    if( line > 0 )
884
0
    {
885
0
      if( col + 1 < tasksPerLine )
886
0
      {
887
0
        if( lineAbove[col + 1] <= INTRA )
888
0
          return false;
889
0
      }
890
0
      else
891
0
      {
892
0
        if( lineAbove[col] <= INTRA_cont )
893
0
          return false;
894
0
      }
895
0
    }
896
0
    if( onlyCheckReadyState )
897
0
      return true;
898
899
0
    ITT_TASKSTART( itt_domain_dec, itt_handle_intra );
900
901
0
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
902
0
    {
903
0
      const int ctuRsAddr    = ctu + line * cs.pcv->widthInCtus;
904
0
      const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
905
0
      decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskCriticalIntraKernel( cs, ctuRsAddr, ctuArea );
906
907
0
      thisCtuState = INTRA_cont;
908
0
    }
909
910
0
    thisCtuState = RSP;
911
912
0
    ITT_TASKEND( itt_domain_dec, itt_handle_intra );
913
0
  }
914
915
0
  case RSP:
916
0
  {
917
    // RIRZIIIII
918
    // IIIIIXXXX
919
    //
920
    // - Z can be reshaped when it is no more an intra prediction source for X in the next line
921
922
923
0
    if     ( line + 1 < heightInCtus && col + 1 < tasksPerLine && lineBelow[col + 1] < INTRA_cont )
924
0
      return false;
925
0
    else if( line + 1 < heightInCtus &&                           lineBelow[col]     < RSP )
926
0
      return false;
927
0
    else if(                            col + 1 < tasksPerLine && thisLine [col + 1] < INTRA_cont ) // need this for the last line
928
0
      return false;
929
930
0
    if( onlyCheckReadyState )
931
0
      return true;
932
933
0
    ITT_TASKSTART( itt_domain_dec, itt_handle_rsp );
934
935
0
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
936
0
    {
937
0
      decLib.m_pcThreadResource[tid]->m_cReshaper.rspCtuBcw( cs, ctu, line );
938
0
    }
939
940
0
    ITT_TASKEND( itt_domain_dec, itt_handle_rsp );
941
942
0
    thisCtuState = LF_V;
943
0
  }
944
945
0
  case LF_V:
946
0
  {
947
0
    if( col > 0 && thisLine[col - 1] < LF_V )
948
0
      return false;
949
0
    if( onlyCheckReadyState )
950
0
      return true;
951
952
0
    ITT_TASKSTART( itt_domain_dec, itt_handle_lfl );
953
954
0
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
955
0
    {
956
0
      decLib.m_cLoopFilter.loopFilterCTU( cs, MAX_NUM_CHANNEL_TYPE, ctu, line, EDGE_VER );
957
958
0
      thisCtuState = LF_V_cont;
959
0
    }
960
961
0
    thisCtuState = LF_H;
962
963
0
    ITT_TASKEND( itt_domain_dec, itt_handle_lfl );
964
0
  }
965
966
0
  case LF_H:
967
0
  {
968
0
    if( line > 0 && lineAbove[col] < LF_H )
969
0
      return false;
970
971
0
    if( line > 0 && col + 1 < tasksPerLine && lineAbove[col + 1] < LF_V_cont )
972
0
      return false;
973
974
0
    if(             col + 1 < tasksPerLine && thisLine[col + 1] < LF_V_cont )
975
0
      return false;
976
977
0
    if( onlyCheckReadyState )
978
0
      return true;
979
980
0
    ITT_TASKSTART( itt_domain_dec, itt_handle_lfl );
981
982
0
    for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
983
0
    {
984
0
      decLib.m_cLoopFilter.loopFilterCTU( cs, MAX_NUM_CHANNEL_TYPE, ctu, line, EDGE_HOR );
985
0
    }
986
987
0
    thisCtuState = PRESAO;
988
989
0
    ITT_TASKEND( itt_domain_dec, itt_handle_lfl );
990
0
  }
991
992
0
  case PRESAO:
993
0
  {
994
    // only last CTU processes full line
995
0
    if( col == tasksPerLine - 1 )
996
0
    {
997
0
      if( line > 0 && lineAbove[col] <= PRESAO )
998
0
        return false;
999
1000
0
      for( int c = 0; c < tasksPerLine; ++c )
1001
0
      {
1002
0
        if( thisLine[c] < PRESAO )
1003
0
          return false;
1004
1005
0
        if( line + 1 < heightInCtus && lineBelow[c] < PRESAO )
1006
0
          return false;
1007
0
      }
1008
0
      if( onlyCheckReadyState )
1009
0
        return true;
1010
1011
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_presao );
1012
1013
0
      if( cs.sps->getUseSAO() )
1014
0
      {
1015
0
        decLib.m_cSAO.SAOPrepareCTULine( cs, getLineArea( cs, line, true ) );
1016
0
      }
1017
1018
0
      ITT_TASKEND( itt_domain_dec, itt_handle_presao );
1019
0
    }
1020
0
    else if( thisLine[tasksPerLine - 1] <= PRESAO )   // wait for last CTU to finish PRESAO
1021
0
    {
1022
0
      return false;
1023
0
    }
1024
0
    if( onlyCheckReadyState )
1025
0
      return true;
1026
1027
0
    thisCtuState = SAO;
1028
0
  }
1029
1030
0
  case SAO:
1031
0
  {
1032
0
    if( onlyCheckReadyState )
1033
0
      return true;
1034
1035
    // only last CTU processes full line
1036
0
    if( cs.sps->getUseSAO() )
1037
0
    {
1038
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_sao );
1039
1040
0
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1041
0
      {
1042
0
        const UnitArea  ctuArea = getCtuArea( cs, ctu, line, true );
1043
0
        decLib.m_cSAO.SAOProcessCTU( cs, ctuArea );
1044
0
      }
1045
1046
0
      ITT_TASKEND( itt_domain_dec, itt_handle_sao );
1047
0
    }
1048
0
    if( param->common.doALF )
1049
0
    {
1050
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_alf );
1051
1052
0
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1053
0
      {
1054
0
        AdaptiveLoopFilter::prepareCTU( cs, ctu, line );
1055
1056
0
        thisCtuState = SAO_cont;
1057
0
      }
1058
1059
0
      ITT_TASKEND( itt_domain_dec, itt_handle_alf );
1060
0
    }
1061
1062
0
    thisCtuState = ALF;
1063
0
  }
1064
1065
0
  case ALF:
1066
0
  {
1067
0
    if( param->common.doALF )
1068
0
    {
1069
0
      const bool a = line > 0;
1070
0
      const bool b = line + 1 < heightInCtus;
1071
0
      const bool c = col > 0;
1072
0
      const bool d = col + 1 < tasksPerLine;
1073
1074
0
      if( a )
1075
0
      {
1076
0
        if( c && lineAbove[col - 1] < ALF ) return false;
1077
0
        if(      lineAbove[col    ] < ALF ) return false;
1078
0
        if( d && lineAbove[col + 1] < SAO_cont ) return false;
1079
0
      }
1080
1081
0
      if( b )
1082
0
      {
1083
0
        if( c && lineBelow[col - 1] < ALF ) return false;
1084
0
        if(      lineBelow[col    ] < ALF ) return false;
1085
0
        if( d && lineBelow[col + 1] < SAO_cont ) return false;
1086
0
      }
1087
1088
0
      if( c && thisLine[col - 1] < ALF ) return false;
1089
0
      if( d && thisLine[col + 1] < SAO_cont ) return false;
1090
1091
0
      if( onlyCheckReadyState )
1092
0
        return true;
1093
1094
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_alf );
1095
0
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1096
0
      {
1097
0
        decLib.m_cALF.processCTU( cs, ctu, line, tid );
1098
0
      }
1099
0
      ITT_TASKEND( itt_domain_dec, itt_handle_alf );
1100
0
    }
1101
0
    else if( onlyCheckReadyState )
1102
0
      return true;
1103
1104
0
    thisCtuState = DONE;
1105
0
  }
1106
1107
0
  default:
1108
0
    CHECKD( thisCtuState != DONE, "Wrong CTU state" );
1109
0
  }   // end switch
1110
1111
0
  return true;
1112
0
}
Unexecuted instantiation: bool vvdec::DecLibRecon::ctuTask<false>(int, void*)
Unexecuted instantiation: bool vvdec::DecLibRecon::ctuTask<true>(int, void*)
1113
1114
}