Coverage Report

Created: 2026-04-01 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vvenc/source/Lib/CommonLib/MatrixIntraPrediction.cpp
Line
Count
Source
1
/* -----------------------------------------------------------------------------
2
The copyright in this software is being made available under the Clear BSD
3
License, included below. No patent rights, trademark rights and/or 
4
other Intellectual Property Rights other than the copyrights concerning 
5
the Software are granted under this license.
6
7
The Clear BSD License
8
9
Copyright (c) 2019-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVenC Authors.
10
All rights reserved.
11
12
Redistribution and use in source and binary forms, with or without modification,
13
are permitted (subject to the limitations in the disclaimer below) provided that
14
the following conditions are met:
15
16
     * Redistributions of source code must retain the above copyright notice,
17
     this list of conditions and the following disclaimer.
18
19
     * Redistributions in binary form must reproduce the above copyright
20
     notice, this list of conditions and the following disclaimer in the
21
     documentation and/or other materials provided with the distribution.
22
23
     * Neither the name of the copyright holder nor the names of its
24
     contributors may be used to endorse or promote products derived from this
25
     software without specific prior written permission.
26
27
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
28
THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
29
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
31
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
32
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
36
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
POSSIBILITY OF SUCH DAMAGE.
39
40
41
------------------------------------------------------------------------------------------- */
42
43
44
/** \file     MatrixIntraPrediction.cpp
45
\brief    matrix-based intra prediction class
46
*/
47
48
49
#include "MatrixIntraPrediction.h"
50
#include "dtrace_next.h"
51
52
#include "UnitTools.h"
53
#include "MipData.h"
54
55
namespace vvenc {
56
57
static const int MIP_MAX_INPUT_SIZE             =  8;
58
static const int MIP_MAX_REDUCED_OUTPUT_SAMPLES = 64;
59
60
MatrixIntraPrediction::MatrixIntraPrediction()
61
0
  : m_reducedBoundary       (nullptr)
62
0
  , m_reducedBoundaryTransp (nullptr)
63
0
  , m_inputOffset           ( 0 )
64
0
  , m_inputOffsetTransp     ( 0 )
65
0
  , m_refSamplesTop         (nullptr)
66
0
  , m_refSamplesLeft        (nullptr)
67
0
  , m_blockSize             ( 0, 0 )
68
0
  , m_sizeId                ( 0 )
69
0
  , m_reducedBdrySize       ( 0 )
70
0
  , m_reducedPredSize       ( 0 )
71
0
  , m_upsmpFactorHor        ( 0 )
72
0
  , m_upsmpFactorVer        ( 0 )
73
0
{
74
0
  m_reducedBoundary       = (Pel*)xMalloc( Pel, MIP_MAX_INPUT_SIZE ); 
75
0
  m_reducedBoundaryTransp = (Pel*)xMalloc( Pel, MIP_MAX_INPUT_SIZE );
76
0
}
77
78
MatrixIntraPrediction::~MatrixIntraPrediction()
79
0
{
80
0
  xFree( m_reducedBoundary );       m_reducedBoundary = nullptr;
81
0
  xFree( m_reducedBoundaryTransp ); m_reducedBoundaryTransp = nullptr;
82
0
}
83
84
void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &pSrc, const Area& block, const int bitDepth)
85
0
{
86
  // Step 1: Save block size and calculate dependent values
87
0
  initPredBlockParams(block);
88
89
0
  m_refSamplesTop  = pSrc.bufAt(1, 0);
90
0
  m_refSamplesLeft = pSrc.bufAt(1, 1);
91
92
  // Step 3: Compute the reduced boundary via Haar-downsampling (input for the prediction)
93
0
  const int inputSize = 2 * m_reducedBdrySize;
94
95
0
  Pel* const topReduced = m_reducedBoundary;
96
0
  boundaryDownsampling1D( topReduced, m_refSamplesTop, block.width, m_reducedBdrySize );
97
98
0
  Pel* const leftReduced = m_reducedBoundary + m_reducedBdrySize;
99
0
  boundaryDownsampling1D( leftReduced, m_refSamplesLeft, block.height, m_reducedBdrySize );
100
101
0
  Pel* const leftReducedTransposed = m_reducedBoundaryTransp;
102
0
  Pel* const topReducedTransposed  = m_reducedBoundaryTransp + m_reducedBdrySize;
103
0
  for( int x = 0; x < m_reducedBdrySize; x++ )
104
0
  {
105
0
    topReducedTransposed[x] = topReduced[x];
106
0
  }
107
0
  for( int y = 0; y < m_reducedBdrySize; y++ )
108
0
  {
109
0
    leftReducedTransposed[y] = leftReduced[y];
110
0
  }
111
112
  // Step 4: Rebase the reduced boundary
113
0
  m_inputOffset       = m_reducedBoundary[0];
114
0
  m_inputOffsetTransp = m_reducedBoundaryTransp[0];
115
116
0
  const bool hasFirstCol = (m_sizeId < 2);
117
0
  m_reducedBoundary      [0] = hasFirstCol ? ((1 << (bitDepth - 1)) - m_inputOffset      ) : 0; // first column of matrix not needed for large blocks
118
0
  m_reducedBoundaryTransp[0] = hasFirstCol ? ((1 << (bitDepth - 1)) - m_inputOffsetTransp) : 0;
119
0
  for (int i = 1; i < inputSize; i++)
120
0
  {
121
0
    m_reducedBoundary      [i] -= m_inputOffset;
122
0
    m_reducedBoundaryTransp[i] -= m_inputOffsetTransp;
123
0
  }
124
0
}
125
126
void MatrixIntraPrediction::predBlock(Pel* const result, const int modeIdx, const bool transpose, const int bitDepth)
127
0
{
128
0
  ALIGN_DATA( MEMORY_ALIGN_DEF_SIZE, Pel bufReducedPred[MIP_MAX_REDUCED_OUTPUT_SAMPLES] );
129
130
0
  const bool       needUpsampling  = ( m_upsmpFactorHor > 1 ) || ( m_upsmpFactorVer > 1 );
131
0
  Pel* const       reducedPred     = needUpsampling ? bufReducedPred : result;
132
0
  const Pel* const reducedBoundary = transpose ? m_reducedBoundaryTransp : m_reducedBoundary;
133
134
0
  {
135
0
    const int outputSize = m_reducedPredSize;
136
0
    const int inputSize  = 2 * m_reducedBdrySize;
137
0
    const int offset     = transpose ? m_inputOffsetTransp : m_inputOffset;
138
0
    const int maxVal     = ( 1 << bitDepth ) - 1;
139
140
0
    if( outputSize == 8)
141
0
    {
142
0
      g_pelBufOP.mipMatrixMul_8_8( reducedPred, reducedBoundary, &mipMatrix16x16[modeIdx][0][0], maxVal, offset, transpose );
143
0
    }
144
0
    else
145
0
    {
146
0
      if( inputSize == 4)
147
0
      {
148
0
        g_pelBufOP.mipMatrixMul_4_4( reducedPred, reducedBoundary, &mipMatrix4x4[modeIdx][0][0], maxVal, offset, transpose );
149
0
      }
150
0
      else
151
0
      {
152
0
        g_pelBufOP.mipMatrixMul_8_4( reducedPred, reducedBoundary, &mipMatrix8x8[modeIdx][0][0], maxVal, offset, transpose );
153
0
      }
154
0
    }
155
0
  }
156
157
  // Reduced prediction is transposed if ( transpose && needUpsampling ).
158
0
  if( needUpsampling )
159
0
  {
160
0
    const Pel* verSrc   = reducedPred;
161
0
    SizeType verSrcStep = m_blockSize.width;
162
163
0
    if( m_upsmpFactorHor > 1 )
164
0
    {
165
0
      Pel* const horDst = result + (m_upsmpFactorVer - 1) * m_blockSize.width;
166
0
      verSrc = horDst;
167
0
      verSrcStep *= m_upsmpFactorVer;
168
169
0
      if( m_reducedPredSize == 4)
170
0
      {
171
0
        if( m_upsmpFactorHor == 2 )
172
0
          predictionUpsampling1DHor<4,1>( horDst, reducedPred, &m_refSamplesLeft[0], verSrcStep, m_upsmpFactorVer );
173
0
        else if( m_upsmpFactorHor == 4 )
174
0
          predictionUpsampling1DHor<4,2>( horDst, reducedPred, &m_refSamplesLeft[0], verSrcStep, m_upsmpFactorVer );
175
0
        else
176
0
          predictionUpsampling1DHor<4,3>( horDst, reducedPred, &m_refSamplesLeft[0], verSrcStep, m_upsmpFactorVer );
177
0
      }
178
0
      else
179
0
      {
180
0
        if( m_upsmpFactorHor == 2 )
181
0
          predictionUpsampling1DHor<8,1>( horDst, reducedPred, &m_refSamplesLeft[0], verSrcStep, m_upsmpFactorVer );
182
0
        else if( m_upsmpFactorHor == 4 )
183
0
          predictionUpsampling1DHor<8,2>( horDst, reducedPred, &m_refSamplesLeft[0], verSrcStep, m_upsmpFactorVer );
184
0
        else
185
0
          predictionUpsampling1DHor<8,3>( horDst, reducedPred, &m_refSamplesLeft[0], verSrcStep, m_upsmpFactorVer );
186
0
      }
187
0
    }
188
189
0
    if( m_upsmpFactorVer > 1 )
190
0
    {
191
0
      if( m_reducedPredSize == 4)
192
0
      {
193
0
        if( m_upsmpFactorVer == 2 )
194
0
          predictionUpsampling1DVer<4,1>( result, verSrc, &m_refSamplesTop[0], m_blockSize.width, verSrcStep );
195
0
        else if( m_upsmpFactorVer == 4 )
196
0
          predictionUpsampling1DVer<4,2>( result, verSrc, &m_refSamplesTop[0], m_blockSize.width, verSrcStep );
197
0
        else
198
0
          predictionUpsampling1DVer<4,3>( result, verSrc, &m_refSamplesTop[0], m_blockSize.width, verSrcStep );
199
0
      }
200
0
      else
201
0
      {
202
0
        if( m_upsmpFactorVer == 2 )
203
0
          predictionUpsampling1DVer<8,1>( result, verSrc, &m_refSamplesTop[0], m_blockSize.width, verSrcStep );
204
0
        else if( m_upsmpFactorVer == 4 )
205
0
          predictionUpsampling1DVer<8,2>( result, verSrc, &m_refSamplesTop[0], m_blockSize.width, verSrcStep );
206
0
        else
207
0
          predictionUpsampling1DVer<8,3>( result, verSrc, &m_refSamplesTop[0], m_blockSize.width, verSrcStep );
208
0
      }
209
0
    }
210
0
  }
211
0
}
212
213
void MatrixIntraPrediction::initPredBlockParams(const Size& block)
214
0
{
215
0
  m_blockSize = block;
216
  // init size index
217
0
  m_sizeId = getMipSizeId( m_blockSize );
218
219
  // init reduced boundary size
220
0
  m_reducedBdrySize = (m_sizeId == 0) ? 2 : 4;
221
222
  // init reduced prediction size
223
0
  m_reducedPredSize = ( m_sizeId < 2 ) ? 4 : 8;
224
225
  // init upsampling factors
226
0
  m_upsmpFactorHor = m_blockSize.width  / m_reducedPredSize;
227
0
  m_upsmpFactorVer = m_blockSize.height / m_reducedPredSize;
228
229
0
  CHECKD( (m_upsmpFactorHor < 1) || ((m_upsmpFactorHor & (m_upsmpFactorHor - 1)) != 0), "Need power of two horizontal upsampling factor." );
230
0
  CHECKD( (m_upsmpFactorVer < 1) || ((m_upsmpFactorVer & (m_upsmpFactorVer - 1)) != 0), "Need power of two vertical upsampling factor." );
231
0
}
232
233
void MatrixIntraPrediction::boundaryDownsampling1D(Pel* reducedDst, const Pel* const fullSrc, const SizeType srcLen, const SizeType dstLen)
234
0
{
235
0
  if (dstLen < srcLen)
236
0
  {
237
    // Create reduced boundary by downsampling
238
0
    const SizeType downsmpFactor = srcLen / dstLen;
239
0
    const int log2DownsmpFactor = floorLog2(downsmpFactor);
240
0
    const int roundingOffset = (1 << (log2DownsmpFactor - 1));
241
242
0
    SizeType srcIdx = 0;
243
0
    for( SizeType dstIdx = 0; dstIdx < dstLen; dstIdx++ )
244
0
    {
245
0
      int sum = 0;
246
0
      for( int k = 0; k < downsmpFactor; k++ )
247
0
      {
248
0
        sum += fullSrc[srcIdx++];
249
0
      }
250
0
      reducedDst[dstIdx] = (sum + roundingOffset) >> log2DownsmpFactor;
251
0
    }
252
0
  }
253
0
  else
254
0
  {
255
    // Copy boundary if no downsampling is needed
256
0
    for (SizeType i = 0; i < dstLen; ++i)
257
0
    {
258
0
      reducedDst[i] = fullSrc[i];
259
0
    }
260
0
  }
261
0
}
262
263
template< SizeType predPredSize, unsigned log2UpsmpFactor>
264
void MatrixIntraPrediction::predictionUpsampling1DHor(Pel* const dst, const Pel* const src, const Pel* const bndry, const SizeType dstStride, const SizeType bndryStep )
265
0
{
266
0
  const int roundingOffset   = 1 << (log2UpsmpFactor - 1);
267
0
  const SizeType upsmpFactor = 1 << log2UpsmpFactor;
268
269
0
        Pel* dstLine   = dst;
270
0
  const Pel* srcLine   = src;
271
0
  const Pel* bndryLine = bndry + bndryStep - 1;
272
273
0
  for( SizeType idxOrthDim = 0; idxOrthDim < predPredSize; idxOrthDim++ )
274
0
  {
275
0
    const Pel* before  = bndryLine;
276
0
    const Pel* behind  = srcLine;
277
0
          Pel* currDst = dstLine;
278
0
    for( SizeType idxUpsmpDim = 0; idxUpsmpDim < predPredSize; idxUpsmpDim++ )
279
0
    {
280
0
      const int valDiff   = *behind - *before;
281
0
            int scaledVal = ( ( *before ) << log2UpsmpFactor ) + roundingOffset;
282
0
      for( SizeType pos = 0; pos < upsmpFactor; pos++)
283
0
      {
284
0
        scaledVal += valDiff;
285
0
        *currDst   = scaledVal >> log2UpsmpFactor;
286
0
        currDst++;
287
0
      }
288
0
      before = behind;
289
0
      behind ++;
290
0
    }
291
292
0
    srcLine   += predPredSize;
293
0
    dstLine   += dstStride;
294
0
    bndryLine += bndryStep;
295
0
  }
296
0
}
Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DHor<4u, 1u>(short*, short const*, short const*, unsigned int, unsigned int)
Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DHor<4u, 2u>(short*, short const*, short const*, unsigned int, unsigned int)
Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DHor<4u, 3u>(short*, short const*, short const*, unsigned int, unsigned int)
Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DHor<8u, 1u>(short*, short const*, short const*, unsigned int, unsigned int)
Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DHor<8u, 2u>(short*, short const*, short const*, unsigned int, unsigned int)
Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DHor<8u, 3u>(short*, short const*, short const*, unsigned int, unsigned int)
297
298
template< SizeType inHeight, unsigned log2UpsmpFactor>
299
void MatrixIntraPrediction::predictionUpsampling1DVer(Pel* const dst, const Pel* const src, const Pel* const bndry, const SizeType outWidth, const SizeType srcStep  )
300
0
{
301
0
  const int roundingOffset   = 1 << (log2UpsmpFactor - 1);
302
0
  const SizeType upsmpFactor = 1 << log2UpsmpFactor;
303
304
0
        Pel* dstLine   = dst;
305
0
  const Pel* srcLine   = src;
306
0
  const Pel* bndryLine = bndry;
307
308
0
  for( SizeType idxOrthDim = 0; idxOrthDim < outWidth; idxOrthDim++ )
309
0
  {
310
0
    const Pel* before  = bndryLine;
311
0
    const Pel* behind  = srcLine;
312
0
          Pel* currDst = dstLine;
313
0
    for( SizeType idxUpsmpDim = 0; idxUpsmpDim < inHeight; idxUpsmpDim++ )
314
0
    {
315
0
      const int valDiff   = *behind - *before;
316
0
            int scaledVal = ( ( *before ) << log2UpsmpFactor ) + roundingOffset;
317
318
0
      for( SizeType pos = 0; pos < upsmpFactor; pos++)
319
0
      {
320
0
        scaledVal += valDiff;
321
0
        *currDst   = scaledVal >> log2UpsmpFactor;
322
0
        currDst += outWidth;
323
0
      }
324
0
      before = behind;
325
0
      behind += srcStep;
326
0
    }
327
328
0
    srcLine ++;
329
0
    dstLine ++;
330
0
    bndryLine ++;
331
0
  }
332
0
}
Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DVer<4u, 1u>(short*, short const*, short const*, unsigned int, unsigned int)
Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DVer<4u, 2u>(short*, short const*, short const*, unsigned int, unsigned int)
Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DVer<4u, 3u>(short*, short const*, short const*, unsigned int, unsigned int)
Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DVer<8u, 1u>(short*, short const*, short const*, unsigned int, unsigned int)
Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DVer<8u, 2u>(short*, short const*, short const*, unsigned int, unsigned int)
Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DVer<8u, 3u>(short*, short const*, short const*, unsigned int, unsigned int)
333
334
335
} // namespace vvenc
336
337
//! \}