1 /*
2 * Copyright (c) 2019-2022, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 //!
23 //! \file     decode_av1_tile_coding_g12.cpp
24 //! \brief    Defines the common interface for av1 decode tile coding
25 //!
26 
27 #include "decode_av1_tile_coding_g12.h"
28 #include "decode_av1_basic_feature_g12.h"
29 #include "codec_def_common.h"
30 #include "mhw_vdbox_avp_g12_X.h"
31 #include "decode_pipeline.h"
32 
33 namespace decode
34 {
~Av1DecodeTileG12()35     Av1DecodeTileG12::~Av1DecodeTileG12()
36     {
37         // tile descriptors
38         if (m_tileDesc)
39         {
40             free(m_tileDesc);
41             m_tileDesc = nullptr;
42         }
43     }
44 
Init(Av1BasicFeatureG12 * basicFeature,CodechalSetting * codecSettings)45     MOS_STATUS Av1DecodeTileG12::Init(Av1BasicFeatureG12 *basicFeature, CodechalSetting *codecSettings)
46     {
47         DECODE_FUNC_CALL();
48         DECODE_CHK_NULL(basicFeature);
49         DECODE_CHK_NULL(codecSettings);
50 
51         m_basicFeature = basicFeature;
52 
53         return MOS_STATUS_SUCCESS;
54     }
55 
Update(CodecAv1PicParams & picParams,CodecAv1TileParams * tileParams)56     MOS_STATUS Av1DecodeTileG12::Update(CodecAv1PicParams & picParams,
57                                         CodecAv1TileParams *tileParams)
58     {
59         DECODE_FUNC_CALL();
60 
61         // Initialize state params for multiple tiles
62         if (m_newFrameStart)
63         {
64             m_lastTileId        = -1;
65             m_curTile           = -1;
66             m_tileStartOffset   = 0;
67             m_firstTileInTg     = 0;
68             m_tileGroupId       = -1;
69             m_isTruncatedTile   = false;
70             m_decPassNum        = 1;
71             m_hasTileMissing    = false;
72             m_hasDuplicateTile  = false;
73         }
74 
75         if (m_numTiles > av1MaxTileNum)
76         {
77             DECODE_ASSERTMESSAGE("Tile number exceeds the max supported number %d!", av1MaxTileNum);
78             return MOS_STATUS_INVALID_PARAMETER;
79         }
80 
81         if (picParams.m_tileCols > av1MaxTileColumn || picParams.m_tileRows > av1MaxTileRow)
82         {
83             DECODE_NORMALMESSAGE("Invalid tile row/col.");
84             return MOS_STATUS_INVALID_PARAMETER;
85         }
86 
87         uint16_t tileNumLimit = (picParams.m_picInfoFlags.m_fields.m_largeScaleTile) ? av1MaxTileNum : (picParams.m_tileCols * picParams.m_tileRows);
88         if (nullptr != m_tileDesc)
89         {
90             if (m_prevFrmTileNum < tileNumLimit)
91             {
92                 free(m_tileDesc);
93                 m_tileDesc = nullptr;
94             }
95             else
96             {
97                 memset(m_tileDesc, 0, (sizeof(TileDesc) * m_prevFrmTileNum));
98             }
99         }
100         if (nullptr == m_tileDesc)
101         {
102             m_tileDesc = (TileDesc *)malloc(sizeof(TileDesc) * tileNumLimit);
103             if (nullptr != m_tileDesc)
104             {
105                 memset(m_tileDesc, 0, (sizeof(TileDesc) * tileNumLimit));
106             }
107         }
108         m_prevFrmTileNum = tileNumLimit;
109 
110         //Calculate tile info for max tile
111         DECODE_CHK_STATUS(CalcTileInfoMaxTile(picParams));
112 
113         return MOS_STATUS_SUCCESS;
114     }
115 
ErrorDetectAndConceal()116     MOS_STATUS Av1DecodeTileG12::ErrorDetectAndConceal()
117     {
118         DECODE_FUNC_CALL()
119         DECODE_CHK_NULL(m_tileDesc);
120         uint64_t datasize = 0;
121 
122         // detect if any tile missing
123         if (m_numTiles < m_totalTileNum)
124         {
125             if (!m_hasTileMissing)
126             {
127                 m_hasTileMissing = true;
128             }
129         }
130 
131         // make sure the last tile equals to m_totalTileNum-1
132         if (m_hasTileMissing)
133         {
134             if (m_lastTileId != m_totalTileNum - 1)
135             {
136                 m_lastTileId = m_totalTileNum - 1;
137                 m_newFrameStart = true;
138             }
139         }
140 
141         // Error Concealment for Tile size
142         // m_numTiles means the tile number from application
143         // m_totalTileNum means the total number of tile, m_lastTileId means the last tile index
144         for (uint32_t i = 0; i < m_totalTileNum; i++)
145         {
146             // m_tileDesc[i].m_size + m_tileDesc[i].m_offset could oversize the maximum of uint32_t
147             datasize = (uint64_t)m_tileDesc[i].m_size + (uint64_t)m_tileDesc[i].m_offset;
148             if (datasize > m_basicFeature->m_dataSize)
149             {
150                 if (i == m_lastTileId)
151                 {
152                     if (m_basicFeature->m_dataSize > m_tileDesc[i].m_offset)
153                     {
154                         m_tileDesc[i].m_size = m_basicFeature->m_dataSize - m_tileDesc[i].m_offset;
155                         DECODE_ASSERTMESSAGE("The last tile size is oversize, the remaining size is %d\n", m_tileDesc[i].m_size);
156                     }
157                     else
158                     {
159                         m_tileDesc[i].m_size = 0;
160                         DECODE_ASSERTMESSAGE("The last tile size is invalid, take current tile as missing tile and then set 4 byte dummy WL!!");
161                     }
162                 }
163                 else
164                 {
165                     m_tileDesc[i].m_size = 0;
166                     DECODE_ASSERTMESSAGE("The non-last tile size is oversize, take current tile as missing tile and then set 4 byte dummy WL!\n");
167                 }
168             }
169             // For tile missing scenario
170             if (m_tileDesc[i].m_size == 0)
171             {
172                 DECODE_ASSERTMESSAGE("The %d tile is missing, set 4 byte dummy WL!\n", i);
173                 m_tileDesc[i].m_size       = 4;
174                 m_tileDesc[i].m_offset     = 0;
175                 m_tileDesc[i].m_tileRow    = i / m_basicFeature->m_av1PicParams->m_tileCols;
176                 m_tileDesc[i].m_tileColumn = i % m_basicFeature->m_av1PicParams->m_tileCols;
177             }
178         }
179         return MOS_STATUS_SUCCESS;
180     }
181 
ParseTileInfo(const CodecAv1PicParams & picParams,CodecAv1TileParams * tileParams)182     MOS_STATUS Av1DecodeTileG12::ParseTileInfo(const CodecAv1PicParams & picParams, CodecAv1TileParams *tileParams)
183     {
184         DECODE_FUNC_CALL();
185 
186         DECODE_CHK_NULL(m_tileDesc);
187         m_totalTileNum      = (picParams.m_picInfoFlags.m_fields.m_largeScaleTile) ?
188             (picParams.m_tileCountMinus1 + 1) : picParams.m_tileRows * picParams.m_tileCols;
189 
190         int16_t tileId           = 0;
191         int16_t tileGroupId      = -1;
192         int16_t lastStartTileIdx = -1;
193         for (uint32_t i = 0; i < m_numTiles; i++)
194         {
195             DECODE_ASSERT(tileParams[i].m_badBSBufferChopping == 0);//this is to assume the whole tile is in one single bitstream buffer
196             DECODE_ASSERT(tileParams[i].m_bsTileBytesInBuffer == tileParams[i].m_bsTilePayloadSizeInBytes);//this is to assume the whole tile is in one single bitstream buffer
197 
198             // Check invalid tile column and tile row
199             if (tileParams[i].m_tileColumn > picParams.m_tileCols || tileParams[i].m_tileRow > picParams.m_tileRows)
200             {
201                 DECODE_ASSERTMESSAGE("Invalid tile column or tile row\n");
202                 return MOS_STATUS_INVALID_PARAMETER;
203             }
204 
205             if (!picParams.m_picInfoFlags.m_fields.m_largeScaleTile)
206             {
207                 //record info
208                 if (tileParams[i].m_startTileIdx != lastStartTileIdx)
209                 {
210                     tileGroupId++;
211                 }
212                 lastStartTileIdx = tileParams[i].m_startTileIdx;
213                 tileId = tileParams[i].m_tileColumn + tileParams[i].m_tileRow * picParams.m_tileCols;
214                 if (tileParams[i].m_badBSBufferChopping == 0 || tileParams[i].m_badBSBufferChopping == 2)//if all tile data received
215                 {
216                     m_lastTileId = tileId;//record the last tile ID whose bitstream is available for HW to decode
217                 }
218             }
219 
220             // check duplicate tile
221             auto index = (picParams.m_picInfoFlags.m_fields.m_largeScaleTile) ? i : tileId;
222             if (m_tileDesc[index].m_tileIndexCount > 0 )
223             {
224                 if (tileParams[i].m_bsTileBytesInBuffer > m_tileDesc[index].m_size)
225                 {
226                     m_tileDesc[index].m_offset = tileParams[i].m_bsTileDataLocation;
227                     m_tileDesc[index].m_size   = tileParams[i].m_bsTileBytesInBuffer;
228                 }
229                 m_tileDesc[index].m_tileIndexCount++;
230                 m_hasDuplicateTile = true;
231             }
232             else
233             {
234                 m_tileDesc[index].m_offset     = tileParams[i].m_bsTileDataLocation;
235                 m_tileDesc[index].m_size       = tileParams[i].m_bsTileBytesInBuffer;
236                 m_tileDesc[index].m_tileRow    = tileParams[i].m_tileRow;
237                 m_tileDesc[index].m_tileColumn = tileParams[i].m_tileColumn;
238                 m_tileDesc[index].m_tileIndexCount++;
239             }
240 
241             if (!picParams.m_picInfoFlags.m_fields.m_largeScaleTile)
242             {
243                 m_tileDesc[index].m_tileGroupId = (uint16_t)tileGroupId;
244                 m_tileDesc[index].m_lastInGroup = (tileId == tileParams[i].m_endTileIdx) ? true : false;
245                 m_tileDesc[index].m_tileNum     = tileId - tileParams[i].m_startTileIdx;
246             }
247             else
248             {
249                 //No TG for ext-tile, set TG related params to 0
250                 m_tileDesc[index].m_tileGroupId = 0;
251                 m_tileDesc[index].m_lastInGroup = 0;
252                 m_tileDesc[index].m_tileNum     = 0;
253 
254                 //ext-tile specific params
255                 m_tileDesc[index].m_tileIndex      = tileParams[i].m_tileIndex;
256                 m_tileDesc[index].m_anchorFrameIdx = tileParams[i].m_anchorFrameIdx.FrameIdx;
257             }
258         }
259 
260         if ((m_lastTileId + 1) == m_totalTileNum)
261         {
262             m_newFrameStart = true;
263         }
264         else
265         {
266             m_newFrameStart = false;
267         }
268 
269         // Do error detection and concealment
270         DECODE_CHK_STATUS(ErrorDetectAndConceal());
271 
272         return MOS_STATUS_SUCCESS;
273     }
274 
CalculateTileCols(CodecAv1PicParams & picParams)275     MOS_STATUS Av1DecodeTileG12::CalculateTileCols(CodecAv1PicParams & picParams)
276     {
277         DECODE_FUNC_CALL();
278 
279         int32_t mibSizeLog2 = picParams.m_seqInfoFlags.m_fields.m_use128x128Superblock ? av1MaxMibSizeLog2 : av1MinMibSizeLog2;
280         int32_t miCols = MOS_ALIGN_CEIL(m_miCols, 1 << mibSizeLog2);
281         int32_t sbCols = miCols >> mibSizeLog2;
282 
283         //calc tile col start for all the tiles except the last one
284         uint16_t i, start_sb = 0;
285         for (i = 0, start_sb = 0; i < picParams.m_tileCols - 1; i++)
286         {
287             m_tileColStartSb[i] = start_sb;//calc tile col start
288             start_sb += picParams.m_widthInSbsMinus1[i] + 1;
289         }
290 
291         //calc for the last tile
292         m_tileColStartSb[i] = start_sb;
293         DECODE_CHK_COND(sbCols < (start_sb + 1), "Invalid tile col start of the last tile");
294         picParams.m_widthInSbsMinus1[i] = sbCols - start_sb - 1;
295 
296         return MOS_STATUS_SUCCESS;
297     }
298 
CalculateTileRows(CodecAv1PicParams & picParams)299     MOS_STATUS Av1DecodeTileG12::CalculateTileRows(CodecAv1PicParams &picParams)
300     {
301         DECODE_FUNC_CALL();
302 
303         int32_t mibSizeLog2 = picParams.m_seqInfoFlags.m_fields.m_use128x128Superblock ? av1MaxMibSizeLog2 : av1MinMibSizeLog2;
304         int32_t miRows = MOS_ALIGN_CEIL(m_miRows, 1 << mibSizeLog2);
305         int32_t sbRows = miRows >> mibSizeLog2;
306 
307         //calc tile row start for all the tiles except the last one
308         uint16_t i, start_sb;
309         for (i = 0, start_sb = 0; i < picParams.m_tileRows - 1; i++)
310         {
311             m_tileRowStartSb[i] = start_sb;//calc tile Row start
312             start_sb += picParams.m_heightInSbsMinus1[i] + 1;
313         }
314 
315         //calc for the last tile
316         m_tileRowStartSb[i] = start_sb;
317         DECODE_CHK_COND(sbRows < (start_sb + 1), "Invalid tile row start of the last tile");
318         picParams.m_heightInSbsMinus1[i] = sbRows - start_sb - 1;
319 
320         return MOS_STATUS_SUCCESS;
321     }
322 
CalcTileInfoMaxTile(CodecAv1PicParams & picParams)323     MOS_STATUS Av1DecodeTileG12::CalcTileInfoMaxTile(CodecAv1PicParams &picParams)
324     {
325         DECODE_FUNC_CALL();
326 
327         m_miCols = MOS_ALIGN_CEIL(picParams.m_frameWidthMinus1 + 1, 8) >> av1MiSizeLog2;
328         m_miRows = MOS_ALIGN_CEIL(picParams.m_frameHeightMinus1 + 1, 8) >> av1MiSizeLog2;
329         DECODE_CHK_STATUS(CalculateTileCols(picParams));
330         DECODE_CHK_STATUS(CalculateTileRows(picParams));
331 
332         return MOS_STATUS_SUCCESS;
333     }
334 
CalcNumPass(const CodecAv1PicParams & picParams,CodecAv1TileParams * tileParams)335     MOS_STATUS Av1DecodeTileG12::CalcNumPass(const CodecAv1PicParams &picParams, CodecAv1TileParams *tileParams)
336     {
337         DECODE_FUNC_CALL();
338 
339         uint16_t passNum;
340         uint16_t startTile = m_lastTileId + 1;//record before parsing new bitstream portion
341 
342         DECODE_CHK_STATUS(ParseTileInfo(picParams, tileParams));
343 
344         if (picParams.m_picInfoFlags.m_fields.m_largeScaleTile)
345         {
346             passNum   = picParams.m_tileCountMinus1 + 1;
347             m_curTile = 0;
348         }
349         else
350         {
351             passNum   = m_lastTileId - startTile + 1;
352             m_curTile = startTile;
353         }
354 
355         // Check invalid tile num
356         if (passNum < 1)
357         {
358             DECODE_ASSERTMESSAGE("valid tile doesn't exist in bitstream\n");
359             return MOS_STATUS_MORE_DATA;
360         }
361 
362         m_decPassNum = passNum;
363         return MOS_STATUS_SUCCESS;
364     }
365 
GetUpscaleConvolveStepX0(const CodecAv1PicParams & picParams,bool isChroma)366     void Av1DecodeTileG12::GetUpscaleConvolveStepX0(const CodecAv1PicParams &picParams, bool isChroma)
367     {
368         DECODE_FUNC_CALL();
369 
370         int32_t ssX = isChroma && picParams.m_seqInfoFlags.m_fields.m_subsamplingX;
371         int32_t downscaledPlaneWidth    = ROUND_POWER_OF_TWO(picParams.m_frameWidthMinus1 + 1, ssX);
372         int32_t upscaledPlaneWidth      = ROUND_POWER_OF_TWO(picParams.m_superResUpscaledWidthMinus1 + 1, ssX);
373 
374         //calculate step
375         int32_t xStepQn = ((downscaledPlaneWidth << av1RsScaleSubpelBits) + upscaledPlaneWidth / 2) / upscaledPlaneWidth;
376         if (isChroma)
377         {
378             m_chromaXStepQn = xStepQn;
379         }
380         else
381         {
382             m_lumaXStepQn = xStepQn;
383         }
384 
385         //Calculate x0_qn for each tile column
386         int32_t err = upscaledPlaneWidth * xStepQn - (downscaledPlaneWidth << av1RsScaleSubpelBits);
387         int32_t x0 =
388             (-((upscaledPlaneWidth - downscaledPlaneWidth) << (av1RsScaleSubpelBits - 1)) +
389                 upscaledPlaneWidth / 2) /
390             upscaledPlaneWidth +
391             av1RsScaleExtraOff - err / 2;
392         x0 = (int32_t)((uint32_t)x0 & av1RsScaleSubpelMask);
393 
394         if (picParams.m_tileCols > 64)
395         {
396             DECODE_ASSERTMESSAGE("Array index exceeds upper bound.");
397             return;
398         }
399 
400         for (auto col = 0; col < picParams.m_tileCols; col++)
401         {
402             if (isChroma)
403             {
404                 m_chromaX0Qn[col] = x0;
405             }
406             else
407             {
408                 m_lumaX0Qn[col] = x0;
409             }
410 
411             int32_t tileColEndSb;
412             if (col < picParams.m_tileCols - 1)
413             {
414                 tileColEndSb = m_tileColStartSb[col + 1];
415             }
416             else
417             {
418                 tileColEndSb = m_tileColStartSb[picParams.m_tileCols - 1] + picParams.m_widthInSbsMinus1[picParams.m_tileCols - 1];
419 
420             }
421             int32_t mibSizeLog2 = picParams.m_seqInfoFlags.m_fields.m_use128x128Superblock ? av1MaxMibSizeLog2 : av1MinMibSizeLog2;
422 
423             int32_t miColEnd = tileColEndSb << mibSizeLog2;
424             miColEnd = AOMMIN(miColEnd, m_miCols);
425             int32_t downscaledX1    = miColEnd << (av1MiSizeLog2 - ssX);
426             int32_t downscaledX0    = m_tileColStartSb[col] << mibSizeLog2 << (av1MiSizeLog2 - ssX);
427 
428             int32_t srcWidth    = downscaledX1 - downscaledX0;
429             int32_t upscaledX0  = (downscaledX0 * picParams.m_superresScaleDenominator) / av1ScaleNumerator;
430             int32_t upscaledX1;
431             if (col == picParams.m_tileCols - 1)
432             {
433                 upscaledX1 = upscaledPlaneWidth;
434             }
435             else
436             {
437                 upscaledX1 = (downscaledX1 * picParams.m_superresScaleDenominator) / av1ScaleNumerator;
438             }
439             int32_t dstWidth = upscaledX1 - upscaledX0;
440 
441             // Update the fractional pixel offset to prepare for the next tile column.
442             x0 += (dstWidth * xStepQn) - (srcWidth << av1RsScaleSubpelBits);
443         }
444     }
445 
446 }   // namespace decode
447