1 /*
2 * Copyright (c) 2021-2024, 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     encode_av1_scc.cpp
24 //! \brief    SCC feature
25 //!
26 
27 #include "encode_av1_scc.h"
28 #include "encode_av1_vdenc_const_settings.h"
29 #include "encode_av1_tile.h"
30 #include "encode_av1_segmentation.h"
31 
32 namespace encode
33 {
34 
Av1Scc(EncodeAllocator * allocator,CodechalHwInterfaceNext * hwInterface,void * constSettings,MediaFeatureManager * featureManager)35     Av1Scc::Av1Scc(EncodeAllocator *allocator,
36         CodechalHwInterfaceNext *hwInterface,
37         void *constSettings,
38         MediaFeatureManager *featureManager)
39         : MediaFeature(constSettings, hwInterface ? hwInterface->GetOsInterface() : nullptr)
40     {
41         ENCODE_FUNC_CALL();
42 
43         ENCODE_CHK_NULL_NO_STATUS_RETURN(featureManager);
44         m_featureManager = featureManager;
45 
46         m_basicFeature = dynamic_cast<Av1BasicFeature *>(featureManager->GetFeature(Av1FeatureIDs::basicFeature));
47         ENCODE_CHK_NULL_NO_STATUS_RETURN(m_basicFeature);
48 
49         m_segmentation = dynamic_cast<Av1Segmentation *>(featureManager->GetFeature(Av1FeatureIDs::av1Segmentation));
50         ENCODE_CHK_NULL_NO_STATUS_RETURN(m_segmentation);
51 
52         m_allocator = allocator;
53 
54         if (hwInterface)
55         {
56             m_osInterface = hwInterface->GetOsInterface();
57         }
58     }
59 
~Av1Scc()60     Av1Scc::~Av1Scc()
61     {
62         ENCODE_FUNC_CALL();
63     }
64 
CheckIBCParams(const CODEC_AV1_ENCODE_PICTURE_PARAMS & picParams)65     inline MOS_STATUS CheckIBCParams(const CODEC_AV1_ENCODE_PICTURE_PARAMS &picParams)
66     {
67         if (picParams.PicFlags.fields.allow_intrabc)
68         {
69             const auto &lr = picParams.LoopRestorationFlags.fields;
70             if (!AV1_KEY_OR_INRA_FRAME(picParams.PicFlags.fields.frame_type)
71                 || picParams.filter_level[0] || picParams.filter_level[1]
72                 || picParams.cdef_bits
73                 || picParams.PicFlags.fields.use_superres
74                 || lr.yframe_restoration_type || lr.cbframe_restoration_type || lr.crframe_restoration_type)
75             {
76                 ENCODE_ASSERTMESSAGE("All loop filters MUST be disabled when IBC is enabled");
77                 return MOS_STATUS_INVALID_PARAMETER;
78             }
79         }
80 
81         return MOS_STATUS_SUCCESS;
82     }
83 
MakeCdfTrackedBufferLockable()84     MOS_STATUS Av1Scc::MakeCdfTrackedBufferLockable()
85     {
86         MOS_ALLOC_GFXRES_PARAMS allocParams;
87         MOS_ZeroMemory(&allocParams, sizeof(MOS_ALLOC_GFXRES_PARAMS));
88         allocParams.Type               = MOS_GFXRES_BUFFER;
89         allocParams.TileType           = MOS_TILE_LINEAR;
90         allocParams.Format             = Format_Buffer;
91         allocParams.Flags.bNotLockable = 0;
92 
93         allocParams.dwBytes  = MOS_ALIGN_CEIL(m_basicFeature->m_cdfMaxNumBytes, CODECHAL_PAGE_SIZE);
94         allocParams.pBufName = "bwdAdaptCdfBuffer";
95         allocParams.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_CACHE;
96         ENCODE_CHK_STATUS_RETURN(m_basicFeature->m_trackedBuf->RegisterParam(encode::BufferType::bwdAdaptCdfBuffer, allocParams));
97 
98         return MOS_STATUS_SUCCESS;
99     }
100 
ResetMvProbsToDefault()101     MOS_STATUS Av1Scc::ResetMvProbsToDefault()
102     {
103         PMOS_RESOURCE cdfTrackedBuf = m_basicFeature->m_trackedBuf->GetBuffer(BufferType::bwdAdaptCdfBuffer, 0);
104         ENCODE_CHK_NULL_RETURN(cdfTrackedBuf);
105 
106         auto data = (uint16_t *)m_allocator->LockResourceForWrite(cdfTrackedBuf);
107         ENCODE_CHK_NULL_RETURN(data);
108         ENCODE_CHK_STATUS_RETURN(InitDefaultFrameContextBuffer(data, 0, mvJointType, interintra));
109         ENCODE_CHK_STATUS_RETURN(m_allocator->UnLock(cdfTrackedBuf));
110 
111         m_resetMvProbs            = false;
112 
113         return MOS_STATUS_SUCCESS;
114     }
115 
Update(void * params)116     MOS_STATUS Av1Scc::Update(void *params)
117     {
118         ENCODE_FUNC_CALL();
119 
120         EncoderParams *encodeParams = (EncoderParams *)params;
121         ENCODE_CHK_NULL_RETURN(encodeParams);
122 
123         auto av1PicParams = static_cast<PCODEC_AV1_ENCODE_PICTURE_PARAMS>(encodeParams->pPicParams);
124         ENCODE_CHK_NULL_RETURN(av1PicParams);
125 
126         m_enablePalette = av1PicParams->PicFlags.fields.PaletteModeEnable;
127 
128         ENCODE_CHK_STATUS_RETURN(CheckIBCParams(*av1PicParams));
129 
130         m_enableIBC = av1PicParams->PicFlags.fields.allow_intrabc;
131         m_IBCPossible = m_IBCPossible || m_enableIBC;
132 
133         if (m_resetMvProbs)
134         {
135             ResetMvProbsToDefault();
136         }
137 
138         if (m_IBCPossible && m_basicFeature->m_resolutionChanged)
139         {
140             // Defines 2 sets of MV probabilities: set 0 for regular Inter blocks, set 1 for IBC blocks
141             // HW CDF table contains single set of MV probabilities instead of 2
142             // when IBC is enabled PAK will update MV probabilities during encoding of KEY frame
143             // Inter frame which follows KEY frame requires default (not updated) MV probabilities
144             // CPU-lockable CDF table tracked buffer is needed to reset MV probs back to defaults
145             // tracked buffer is forced to be CPU-lockable
146             ENCODE_CHK_STATUS_RETURN(MakeCdfTrackedBufferLockable());
147         }
148 
149         if (m_enableIBC)
150         {
151             // need to reset MV probs to default values after each KEY frame with IBC enabled
152             m_resetMvProbs = true;
153             if (m_intrabcReconSurface == nullptr)
154             {
155                 MOS_ALLOC_GFXRES_PARAMS allocParams;
156                 MOS_ZeroMemory(&allocParams, sizeof(MOS_ALLOC_GFXRES_PARAMS));
157                 allocParams.Type            = MOS_GFXRES_2D;
158                 allocParams.TileType        = MOS_TILE_Y;
159                 allocParams.Format          = (10 == m_basicFeature->m_bitDepth) ? Format_P010 : Format_NV12;
160                 allocParams.dwWidth         = MOS_ALIGN_CEIL(m_basicFeature->m_frameWidth, av1SuperBlockWidth);
161                 allocParams.dwHeight        = MOS_ALIGN_CEIL(m_basicFeature->m_frameHeight, av1SuperBlockHeight);
162                 allocParams.pBufName        = "Intra Block Copy output buffer";
163                 allocParams.bIsCompressible = false;
164                 allocParams.CompressionMode = MOS_MMC_DISABLED;
165 
166                 if (m_basicFeature->m_outputChromaFormat == AVP_CHROMA_FORMAT_YUV444)
167                 {
168                     if (!m_basicFeature->m_is10Bit)
169                     {
170                         allocParams.Format   = Format_AYUV;
171                         allocParams.dwWidth  = MOS_ALIGN_CEIL(allocParams.dwWidth, 512 / 4);
172                         allocParams.dwHeight = MOS_ALIGN_CEIL(allocParams.dwHeight * 3 / 4, 8);
173                     }
174                     else
175                     {
176                         allocParams.Format    = Format_Y410;
177                         //Y410Viriant surface is same as Y416Viriant
178                         allocParams.dwWidth   = MOS_ALIGN_CEIL(allocParams.dwWidth, 256 / 4);
179                         allocParams.dwHeight  = MOS_ALIGN_CEIL(allocParams.dwHeight * 3 / 2, 8);
180                     }
181                 }
182                 else if (m_basicFeature->m_outputChromaFormat == AVP_CHROMA_FORMAT_YUV422)
183                 {
184                     if (!m_basicFeature->m_is10Bit)
185                     {
186                         // allocated as YUY2, but used by HW as YUY2 Variant, which is
187                         // twice the height and half the width of the YUY2 source surface
188                         allocParams.Format   = Format_YUY2;
189                         allocParams.dwWidth  = MOS_ALIGN_CEIL(allocParams.dwWidth >> 1, 128);
190                         allocParams.dwHeight = MOS_ALIGN_CEIL(allocParams.dwHeight << 1, 8);
191                     }
192                     else
193                     {
194                         // allocated as Y210, but used by HW as Y210 Variant, which is
195                         // twice the height and half the width of the Y210 source surface
196                         allocParams.Format   = Format_Y210;
197                         allocParams.dwWidth  = MOS_ALIGN_CEIL(allocParams.dwWidth >> 1, 128 >> 1);  // HW requires 128 byte aligned width, 2 bytes per pixel
198                         allocParams.dwHeight = MOS_ALIGN_CEIL(allocParams.dwHeight << 1, 8);
199                     }
200                 }
201 
202                 m_intrabcReconSurface = m_allocator->AllocateSurface(allocParams, false, MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_CACHE);
203                 m_allocator->GetSurfaceInfo(m_intrabcReconSurface);
204             }
205         }
206 
207         ENCODE_CHK_STATUS_RETURN(UpdateIBCStatusForCurrentTile());
208 
209         return MOS_STATUS_SUCCESS;
210     }
211 
212     const uint32_t INTRABC_DELAY_SB64 = 4;
213 
UpdateIBCStatusForCurrentTile()214     MOS_STATUS Av1Scc::UpdateIBCStatusForCurrentTile()
215     {
216         uint32_t wSB64 = MOS_ROUNDUP_DIVIDE(m_basicFeature->m_frameWidth, 64);
217 
218         auto tileFeature = dynamic_cast<Av1EncodeTile *>(m_featureManager->GetFeature(Av1FeatureIDs::encodeTile));
219 
220         if (tileFeature)
221         {
222             Av1TileInfo tileInfo = {};
223             tileFeature->GetTileInfo(&tileInfo);
224 
225             wSB64 = tileInfo.tileWidthInSbMinus1 + 1;
226         }
227 
228         m_IBCEnabledForCurrentTile = m_enableIBC && (wSB64 > (INTRABC_DELAY_SB64 + 1));
229         return MOS_STATUS_SUCCESS;
230     }
231 
MHW_SETPAR_DECL_SRC(VDENC_HEVC_VP9_TILE_SLICE_STATE,Av1Scc)232     MHW_SETPAR_DECL_SRC(VDENC_HEVC_VP9_TILE_SLICE_STATE, Av1Scc)
233     {
234         bool m_is10Bit = m_basicFeature->m_is10Bit;
235         uint16_t qp    = (m_basicFeature->m_av1PicParams->base_qindex) / 4;
236 
237         uint8_t tableIdx = 0;
238         if (qp <= 12)
239             tableIdx = 0;
240         else if (qp > 12 && qp <= 17)
241             tableIdx = 1;
242         else if (qp > 17 && qp <= 22)
243             tableIdx = 2;
244         else if (qp > 22 && qp <= 27)
245             tableIdx = 3;
246         else if (qp > 27 && qp <= 32)
247             tableIdx = 4;
248         else if (qp > 32 && qp <= 37)
249             tableIdx = 5;
250         else if (qp > 37 && qp <= 42)
251             tableIdx = 6;
252         else if (qp > 42 && qp <= 47)
253             tableIdx = 7;
254         else if (qp > 47 && qp <= 49)
255             tableIdx = 8;
256         else
257             tableIdx = 9;
258 
259         if (m_enablePalette)
260         {
261             params.VdencHEVCVP9TileSlicePar8   = AV1table[tableIdx][0];
262             params.VdencHEVCVP9TileSlicePar9   = AV1table[tableIdx][1];
263             params.VdencHEVCVP9TileSlicePar5   = AV1table[tableIdx][2];
264             params.VdencHEVCVP9TileSlicePar22  = 64;
265             params.paletteModeEnable           = 1;
266 
267             if (m_is10Bit)
268             {
269                 params.VdencHEVCVP9TileSlicePar5 = AV1table[tableIdx][2] + 2;
270             }
271         }
272 
273         if (m_IBCEnabledForCurrentTile)
274         {
275             params.ibcControl                   = IBC_ENABLED;
276             params.VdencHEVCVP9TileSlicePar0    = 0;
277         }
278 
279         auto numTiles = m_basicFeature->m_av1PicParams->tile_rows * m_basicFeature->m_av1PicParams->tile_cols;
280         if (numTiles > 1)
281         {
282             auto waTable = m_osInterface->pfnGetWaTable(m_osInterface);
283             if (MEDIA_IS_WA(waTable, Wa_15014143531))
284             {
285                 params.ibcControl = IBC_DISABLED;
286             }
287         }
288 
289         return MOS_STATUS_SUCCESS;
290     }
291 
MHW_SETPAR_DECL_SRC(VDENC_CMD2,Av1Scc)292     MHW_SETPAR_DECL_SRC(VDENC_CMD2, Av1Scc)
293     {
294         if (m_IBCEnabledForCurrentTile)
295         {
296             params.frameIdxL0Ref0 = 0;
297         }
298 
299 #if _MEDIA_RESERVED
300         if (m_IBCEnabledForCurrentTile)
301         {
302             params.vdencCmd2Par3            = vdencCmd2Par3Value2;
303             params.vdencCmd2Par136          = vdencCmd2Par136Value1;
304             params.vdencCmd2Par102          = false;
305             params.vdencCmd2Par101          = false;
306 
307             if (params.vdencCmd2Par135[1] == vdencCmd2Par135Value2)
308             {
309                 params.vdencCmd2Par135[1] = vdencCmd2Par135Value1;
310             }
311         }
312 
313         if (m_segmentation->HasZeroSegmentQIndex())
314         {
315             params.vdencCmd2Par133 = false;
316         }
317 
318         if (m_enablePalette && (m_basicFeature->m_targetUsage == 7))
319         {
320             params.vdencCmd2Par134[1] = 1;
321         }
322 #else
323         params.extSettings.emplace_back(
324             [this](uint32_t *data) {
325                 if (m_IBCEnabledForCurrentTile)
326                 {
327                     data[2]   = data[2]  & 0xFFFFFFFC | 0x2;
328                     data[37]  = data[37] & 0xFFFFFF9F | 0x40;
329                     data[54] &= 0xFFFFFF3F;
330 
331                     if (((data[51] >> 10) & 0b11) == vdencCmd2Par135Value1)
332                     {
333                         data[51] = data[51] & 0xFFFFF3FF | 0x400;
334                     }
335                 }
336 
337                 if (m_segmentation->HasZeroSegmentQIndex())
338                 {
339                     data[2] &= 0xFFFFFFBF;
340                 }
341 
342                 if (m_enablePalette && (m_basicFeature->m_targetUsage == 7))
343                 {
344                     data[51] = data[51] & 0xFFFFFF3F | 0x40;
345                 }
346 
347                 return MOS_STATUS_SUCCESS;
348             });
349 #endif  // _MEDIA_RESERVED
350 
351         return MOS_STATUS_SUCCESS;
352     }
353 
MHW_SETPAR_DECL_SRC(VDENC_CMD1,Av1Scc)354     MHW_SETPAR_DECL_SRC(VDENC_CMD1, Av1Scc)
355     {
356         auto setting = static_cast<Av1VdencFeatureSettings*>(m_constSettings);
357         ENCODE_CHK_NULL_RETURN(setting);
358 
359         if (m_IBCEnabledForCurrentTile)
360         {
361 
362             std::fill_n(&params.vdencCmd1Par15[0], 4, (uint8_t)158);
363             std::fill_n(&params.vdencCmd1Par14[0], 4, (uint8_t)146);
364             std::fill_n(&params.vdencCmd1Par13[0], 4, (uint8_t)146);
365             std::fill_n(&params.vdencCmd1Par12[0], 4, (uint8_t)143);
366             std::fill_n(&params.vdencCmd1Par11[0], 4, (uint8_t)140);
367             std::fill_n(&params.vdencCmd1Par10[0], 4, (uint8_t)134);
368             std::fill_n(&params.vdencCmd1Par9[0],  4, (uint8_t)134);
369             std::fill_n(&params.vdencCmd1Par8[0],  4, (uint8_t)131);
370 
371             params.vdencCmd1Par5               = 8;
372             params.vdencCmd1Par6               = 4;
373             params.vdencCmd1Par7               = 12;
374 
375             params.vdencCmd1Par16              = 229;
376             params.vdencCmd1Par17              = 146;
377             params.vdencCmd1Par18              = 230;
378             params.vdencCmd1Par19              = 144;
379             params.vdencCmd1Par20              = 145;
380 
381             params.vdencCmd1Par90              = 0;
382             params.vdencCmd1Par91              = 0;
383             params.vdencCmd1Par92              = 0;
384             params.vdencCmd1Par94              = 24;
385         }
386 
387         return MOS_STATUS_SUCCESS;
388     }
389 
MHW_SETPAR_DECL_SRC(VDENC_PIPE_BUF_ADDR_STATE,Av1Scc)390     MHW_SETPAR_DECL_SRC(VDENC_PIPE_BUF_ADDR_STATE, Av1Scc)
391     {
392         if (m_enableIBC)
393         {
394             params.refs[0]         = &m_intrabcReconSurface->OsResource;
395             params.refsDsStage2[0] = nullptr;
396             params.refsDsStage1[0] = nullptr;
397 
398             params.numActiveRefL0 = 1;
399         }
400 
401         return MOS_STATUS_SUCCESS;
402     }
403 
MHW_SETPAR_DECL_SRC(AVP_PIC_STATE,Av1Scc)404     MHW_SETPAR_DECL_SRC(AVP_PIC_STATE, Av1Scc)
405     {
406         if (m_enableIBC || m_enablePalette)
407         {
408             params.allowScreenContentTools = true;
409             params.allowIntraBC = m_enableIBC;
410 
411             if (m_enableIBC)
412             {
413                 params.enableCDEF        = false;
414                 params.enableRestoration = false;
415             }
416         }
417 
418         return MOS_STATUS_SUCCESS;
419     }
420 
MHW_SETPAR_DECL_SRC(AVP_PIPE_BUF_ADDR_STATE,Av1Scc)421     MHW_SETPAR_DECL_SRC(AVP_PIPE_BUF_ADDR_STATE, Av1Scc)
422     {
423         if (m_enableIBC)
424         {
425             params.intrabcDecodedOutputFrameBuffer = &m_intrabcReconSurface->OsResource;
426         }
427 
428         return MOS_STATUS_SUCCESS;
429     }
430 
MHW_SETPAR_DECL_SRC(AVP_SURFACE_STATE,Av1Scc)431     MHW_SETPAR_DECL_SRC(AVP_SURFACE_STATE, Av1Scc)
432     {
433         MOS_MEMCOMP_STATE mmcState = {};
434         if (m_enableIBC && params.surfaceStateId == intrabcDecodedFrame)
435         {
436             if (m_basicFeature->m_outputChromaFormat == AVP_CHROMA_FORMAT_YUV420)
437             {
438                 params.pitch   = m_basicFeature->m_reconSurface.dwPitch;
439                 params.uOffset = m_basicFeature->m_reconSurface.YoffsetForUplane;
440                 params.vOffset = m_basicFeature->m_reconSurface.YoffsetForVplane;
441             }
442             else if (m_basicFeature->m_outputChromaFormat == AVP_CHROMA_FORMAT_YUV444)
443             {
444                 if (!m_basicFeature->m_is10Bit)
445                 {
446                     params.pitch   = m_basicFeature->m_reconSurface.dwPitch / 4;
447                     params.uOffset = (uint16_t)m_basicFeature->m_rawSurface.dwHeight;
448                     params.vOffset = (uint16_t)m_basicFeature->m_rawSurface.dwHeight << 1;
449                 }
450                 else
451                 {
452                     params.pitch   = m_basicFeature->m_reconSurface.dwPitch / 2;
453                     params.uOffset = (uint16_t)m_basicFeature->m_rawSurface.dwHeight;
454                     params.vOffset = (uint16_t)m_basicFeature->m_rawSurface.dwHeight << 1;
455                 }
456             }
457             else if (m_basicFeature->m_outputChromaFormat == AVP_CHROMA_FORMAT_YUV422)
458             {
459                 params.pitch   = m_basicFeature->m_reconSurface.dwPitch;
460                 params.uOffset = params.vOffset = m_basicFeature->m_rawSurface.dwHeight;
461             }
462 
463             m_basicFeature->GetSurfaceMmcInfo(m_intrabcReconSurface, mmcState, params.compressionFormat);
464             std::fill(std::begin(params.mmcState), std::end(params.mmcState), mmcState);
465         }
466         return MOS_STATUS_SUCCESS;
467     }
468 
469 }  // namespace encode
470