1 /*
2 * Copyright (c) 2021, 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_hevc_cqp.cpp
24 //! \brief    Defines the common interface for hevc encode cqp features
25 //!
26 
27 #include "encode_hevc_basic_feature.h"
28 #include "encode_hevc_cqp.h"
29 #include "encode_hevc_vdenc_feature_manager.h"
30 #include "encode_hevc_vdenc_const_settings.h"
31 
32 using namespace mhw::vdbox;
33 namespace encode
34 {
HevcEncodeCqp(MediaFeatureManager * featureManager,EncodeAllocator * allocator,CodechalHwInterfaceNext * hwInterface,void * constSettings)35 HevcEncodeCqp::HevcEncodeCqp(
36     MediaFeatureManager *featureManager,
37     EncodeAllocator     *allocator,
38     CodechalHwInterfaceNext *hwInterface,
39     void                *constSettings) :
40     MediaFeature(constSettings, hwInterface ? hwInterface->GetOsInterface():nullptr),
41     m_allocator(allocator)
42 {
43     m_featureManager = featureManager;
44     ENCODE_CHK_NULL_NO_STATUS_RETURN(hwInterface);
45     m_mosCtx = hwInterface->GetOsInterface()->pOsContext;
46     // can be optimized after move encode parameter to feature manager.
47     auto encFeatureManager = dynamic_cast<EncodeHevcVdencFeatureManager *>(featureManager);
48     ENCODE_CHK_NULL_NO_STATUS_RETURN(encFeatureManager);
49 
50     m_basicFeature = dynamic_cast<EncodeBasicFeature *>(encFeatureManager->GetFeature(FeatureIDs::basicFeature));
51     ENCODE_CHK_NULL_NO_STATUS_RETURN(m_basicFeature);
52 
53     m_hcpItf = std::static_pointer_cast<mhw::vdbox::hcp::Itf>(hwInterface->GetHcpInterfaceNext());
54     ENCODE_CHK_NULL_NO_STATUS_RETURN(m_hcpItf);
55 }
56 
Init(void * settings)57 MOS_STATUS HevcEncodeCqp::Init(void *settings)
58 {
59     ENCODE_FUNC_CALL();
60 
61 #if (_DEBUG || _RELEASE_INTERNAL)
62     MediaUserSetting::Value outValue;
63     ReadUserSetting(
64         m_userSettingPtr,
65         outValue,
66         "HEVC RDOQ Enable",
67         MediaUserSetting::Group::Sequence);
68     m_rdoqEnable = outValue.Get<bool>();
69 #else
70     m_rdoqEnable = true;
71 #endif
72 
73     ENCODE_CHK_STATUS_RETURN(AllocateResources());
74 
75     return MOS_STATUS_SUCCESS;
76 }
77 
Update(void * params)78 MOS_STATUS HevcEncodeCqp::Update(void *params)
79 {
80     ENCODE_FUNC_CALL();
81     ENCODE_CHK_NULL_RETURN(params);
82 
83     EncoderParams *encodeParams = (EncoderParams *)params;
84 
85     PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS hevcSeqParams =
86         static_cast<PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS>(encodeParams->pSeqParams);
87     ENCODE_CHK_NULL_RETURN(hevcSeqParams);
88     PCODEC_HEVC_ENCODE_PICTURE_PARAMS hevcPicParams =
89         static_cast<PCODEC_HEVC_ENCODE_PICTURE_PARAMS>(encodeParams->pPicParams);
90     ENCODE_CHK_NULL_RETURN(hevcPicParams);
91 
92     ////Livia: Legacy driver won't care about PPS parameters for deblocking, it only care about slice parameter.
93     ////As it set pps_deblocking_filter_disabled_flag=0, it's ok for enable/disable all slices DB
94     ////But it maybe a potential issue with App set this as 1 and set enable/disable DB differently for each slices.
95     ////hevcPictureParams->deblocking_filter_override_enabled_flag;
96     ////hevcPictureParams->pps_deblocking_filter_disabled_flag;
97 
98     if (m_basicFeature->m_newSeq)
99     {
100         ENCODE_CHK_STATUS_RETURN(SetConstSettings());
101     }
102     m_picQPY              = hevcPicParams->QpY;
103     m_transformSkipEnable = hevcPicParams->transform_skip_enabled_flag;
104 
105     m_saoEnable = hevcSeqParams->SAO_enabled_flag;
106     if (m_saoEnable)
107     {
108         ENCODE_CHK_STATUS_RETURN(VerifySliceSAOState());
109     }
110 
111     UpdateRDOQCfg();
112 
113 #if (_DEBUG || _RELEASE_INTERNAL)
114     ReportUserSettingForDebug(
115         m_userSettingPtr,
116         "HEVC RDOQ Enable",
117         m_rdoqEnable,
118         MediaUserSetting::Group::Sequence);
119 #endif
120 
121     return MOS_STATUS_SUCCESS;
122 }
123 
UpdateRDOQCfg()124 void HevcEncodeCqp::UpdateRDOQCfg()
125 {
126     ENCODE_FUNC_CALL();
127 
128     // RDOQ disable for SCC palette mode
129     auto hevcFeature = dynamic_cast<HevcBasicFeature *>(m_basicFeature);
130     ENCODE_CHK_NULL_NO_STATUS_RETURN(hevcFeature);
131 
132     if (hevcFeature->m_hevcSeqParams->palette_mode_enabled_flag)
133     {
134         m_rdoqEnable = false;
135     }
136 
137     m_rdoqIntraTuThreshold = 0;
138     if (m_rdoqEnable)
139     {
140         if (1 == m_basicFeature->m_targetUsage || 2 == m_basicFeature->m_targetUsage || 4 == m_basicFeature->m_targetUsage || 6 == m_basicFeature->m_targetUsage)
141         {
142             m_rdoqIntraTuThreshold = 0xffff;
143         }
144         else if (7 == m_basicFeature->m_targetUsage)
145         {
146             uint32_t frameSize = m_basicFeature->m_oriFrameWidth * m_basicFeature->m_oriFrameHeight;
147             m_rdoqIntraTuThreshold = MOS_MIN(((frameSize * 30) / 100) >> 8, 0xffff);
148         }
149     }
150 }
151 
SetConstSettings()152 MOS_STATUS HevcEncodeCqp::SetConstSettings()
153 {
154     ENCODE_FUNC_CALL();
155     ENCODE_CHK_NULL_RETURN(m_basicFeature);
156     ENCODE_CHK_NULL_RETURN(m_constSettings);
157     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
158     auto       setting = static_cast<HevcVdencFeatureSettings *>(m_constSettings);
159     ENCODE_CHK_NULL_RETURN(setting);
160 
161     m_rdoqEnable = m_rdoqEnable ? (setting->rdoqEnable[m_basicFeature->m_targetUsage]) : m_rdoqEnable;
162 
163     return eStatus;
164 }
165 
AllocateResources()166 MOS_STATUS HevcEncodeCqp::AllocateResources()
167 {
168     ENCODE_FUNC_CALL();
169     ENCODE_CHK_NULL_RETURN(m_basicFeature);
170     MOS_STATUS                       eStatus = MOS_STATUS_SUCCESS;
171 
172     MOS_ALLOC_GFXRES_PARAMS allocParamsForBufferLinear;
173     MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS));
174     allocParamsForBufferLinear.Type     = MOS_GFXRES_BUFFER;
175     allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR;
176     allocParamsForBufferLinear.Format   = Format_Buffer;
177 
178     uint32_t              bufSize       = 0;
179     hcp::HcpBufferSizePar hcpBufSizePar = {};
180     hcpBufSizePar.ucMaxBitDepth  = m_basicFeature->m_bitDepth;
181     hcpBufSizePar.ucChromaFormat = m_basicFeature->m_chromaFormat;
182     // We should move the buffer allocation to picture level if the size is dependent on LCU size
183     hcpBufSizePar.dwCtbLog2SizeY = 6;  //assume Max LCU size
184     hcpBufSizePar.dwPicWidth     = MOS_ALIGN_CEIL(m_basicFeature->m_frameWidth, ((HevcBasicFeature *)m_basicFeature)->m_maxLCUSize);
185     hcpBufSizePar.dwPicHeight    = MOS_ALIGN_CEIL(m_basicFeature->m_frameHeight, ((HevcBasicFeature *)m_basicFeature)->m_maxLCUSize);
186 
187     auto AllocateResource = [&](PMOS_RESOURCE &res, const hcp::HCP_INTERNAL_BUFFER_TYPE bufferType, const char *bufferName, bool usecache) {
188         hcpBufSizePar.bufferType     = bufferType;
189         eStatus                      = m_hcpItf->GetHcpBufSize(hcpBufSizePar, bufSize);
190         if (eStatus != MOS_STATUS_SUCCESS)
191         {
192             ENCODE_ASSERTMESSAGE("Failed to get the size for Deblocking Filter Buffer.");
193             return eStatus;
194         }
195         allocParamsForBufferLinear.dwBytes  = bufSize;
196         allocParamsForBufferLinear.pBufName = bufferName;
197         if (usecache)
198         {
199             allocParamsForBufferLinear.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_CACHE;
200         }
201         else
202         {
203             allocParamsForBufferLinear.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_NOCACHE;
204         }
205         res = m_allocator->AllocateResource(allocParamsForBufferLinear, false);
206         return MOS_STATUS_SUCCESS;
207     };
208 
209     // Deblocking Filter Row Store Scratch data surface
210     ENCODE_CHK_STATUS_RETURN(AllocateResource(m_resDeblockingFilterRowStoreScratchBuffer, hcp::HCP_INTERNAL_BUFFER_TYPE::DBLK_LINE, "DeblockingScratchBuffer", true));
211     // Deblocking Filter Tile Row Store Scratch data surface
212     ENCODE_CHK_STATUS_RETURN(AllocateResource(m_resDeblockingFilterTileRowStoreScratchBuffer, hcp::HCP_INTERNAL_BUFFER_TYPE::DBLK_TILE_LINE, "DeblockingTileRowScratchBuffer", true));
213     // Deblocking Filter Column Row Store Scratch data surface
214     ENCODE_CHK_STATUS_RETURN(AllocateResource(m_resDeblockingFilterColumnRowStoreScratchBuffer, hcp::HCP_INTERNAL_BUFFER_TYPE::DBLK_TILE_COL, "DeblockingColumnScratchBuffer", true));
215 
216     // SAO Line buffer
217     ENCODE_CHK_STATUS_RETURN(AllocateResource(m_resSAOLineBuffer, hcp::HCP_INTERNAL_BUFFER_TYPE::SAO_LINE, "SaoLineBuffer", false));
218     // SAO Tile Line buffer
219     ENCODE_CHK_STATUS_RETURN(AllocateResource(m_resSAOTileLineBuffer, hcp::HCP_INTERNAL_BUFFER_TYPE::SAO_TILE_LINE, "SaoTileLineBuffer", false));
220 
221     // SAO Tile Column buffer
222     ENCODE_CHK_STATUS_RETURN(AllocateResource(m_resSAOTileColumnBuffer, hcp::HCP_INTERNAL_BUFFER_TYPE::SAO_TILE_COL, "SaoTileColumnBuffer", false));
223 
224     // SAO StreamOut buffer
225     uint32_t size = MOS_ALIGN_CEIL(((HevcBasicFeature *)m_basicFeature)->m_picWidthInMinLCU, 4) * m_hevcSAOStreamoutSizePerLCU;
226     //extra added size to cover tile enabled case, per tile width aligned to 4.  20: max tile column No.
227     size += 3 * 20 * m_hevcSAOStreamoutSizePerLCU;
228     allocParamsForBufferLinear.dwBytes  = size;
229     allocParamsForBufferLinear.pBufName = "SaoStreamOutBuffer";
230     allocParamsForBufferLinear.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_READ;
231     m_resSAOStreamOutBuffer             = m_allocator->AllocateResource(allocParamsForBufferLinear, false);
232 
233     const uint32_t minLCUSize        = 16;
234     const uint32_t picWidthInMinLCU  = MOS_ROUNDUP_DIVIDE(m_basicFeature->m_frameWidth, minLCUSize);   //assume smallest LCU to get max width
235     const uint32_t picHeightInMinLCU = MOS_ROUNDUP_DIVIDE(m_basicFeature->m_frameHeight, minLCUSize);  //assume smallest LCU to get max height
236     // Aligned to 4 for each tile column
237     uint32_t maxTileColumn              = MOS_ROUNDUP_DIVIDE(m_basicFeature->m_frameWidth, CODECHAL_HEVC_MIN_TILE_SIZE);
238     allocParamsForBufferLinear.dwBytes  = MOS_ALIGN_CEIL(picWidthInMinLCU + 3 * maxTileColumn, 4) * 16;
239     allocParamsForBufferLinear.pBufName = "SaoRowStoreBuffer";
240     allocParamsForBufferLinear.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_READ;
241     MOS_RESOURCE *allocatedresource = m_allocator->AllocateResource(allocParamsForBufferLinear, false);
242     ENCODE_CHK_NULL_RETURN(allocatedresource);
243     m_vdencSAORowStoreBuffer = *allocatedresource;
244     if (eStatus != MOS_STATUS_SUCCESS)
245     {
246         ENCODE_ASSERTMESSAGE("Failed to allocate SAO row store Buffer.");
247         return eStatus;
248     }
249 
250     return eStatus;
251 }
252 
VerifySliceSAOState()253 MOS_STATUS HevcEncodeCqp::VerifySliceSAOState()
254 {
255     ENCODE_FUNC_CALL();
256     ENCODE_CHK_NULL_RETURN(m_basicFeature);
257 
258     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
259 
260     if (m_saoEnable)
261     {
262         auto hevcFeature = dynamic_cast<HevcBasicFeature *>(m_basicFeature);
263         ENCODE_CHK_NULL_RETURN(hevcFeature);
264 
265         PCODEC_HEVC_ENCODE_SLICE_PARAMS hevcSliceParams = hevcFeature->m_hevcSliceParams;
266         ENCODE_CHK_NULL_RETURN(hevcSliceParams);
267 
268         uint32_t slcSaoLumaCount = 0, slcSaoChromaCount = 0;
269 
270         for (uint32_t slcCount = 0; slcCount < m_basicFeature->m_numSlices; slcCount++, hevcSliceParams++)
271         {
272             slcSaoLumaCount += hevcSliceParams->slice_sao_luma_flag;
273             slcSaoChromaCount += hevcSliceParams->slice_sao_chroma_flag;
274         }
275 
276         // For HCP_SLICE_STATE command, slices must have the same SAO setting within a picture for encoder.
277         // And SAO should be disabled in HCP_SLICE_STATE command if luma and chroma sao disabled.
278         if (((slcSaoLumaCount > 0) && (slcSaoLumaCount != m_basicFeature->m_numSlices)) ||
279             ((slcSaoChromaCount > 0) && (slcSaoChromaCount != m_basicFeature->m_numSlices)) ||
280             ((slcSaoLumaCount == 0) && (slcSaoChromaCount == 0)))
281         {
282             m_saoEnable = false;
283             ENCODE_ASSERTMESSAGE("Invalid SAO parameters in slice. All slices must have the same SAO setting within a picture.");
284         }
285     }
286 
287     return eStatus;
288 }
289 
MHW_SETPAR_DECL_SRC(HCP_PIC_STATE,HevcEncodeCqp)290 MHW_SETPAR_DECL_SRC(HCP_PIC_STATE, HevcEncodeCqp)
291 {
292     auto hevcFeature = dynamic_cast<HevcBasicFeature *>(m_basicFeature);
293     ENCODE_CHK_NULL_RETURN(hevcFeature);
294 
295     PCODEC_HEVC_ENCODE_PICTURE_PARAMS hevcPicParams = hevcFeature->m_hevcPicParams;
296     ENCODE_CHK_NULL_RETURN(hevcPicParams);
297 
298     params.transformSkipEnabled         = m_transformSkipEnable;
299     params.sampleAdaptiveOffsetEnabled  = m_saoEnable;
300     params.rdoqEnable                   = m_rdoqEnable;
301     params.rhodomainframelevelqp        = params.rhodomainRateControlEnable ? hevcPicParams->QpY : 0;
302     params.intratucountbasedrdoqdisable = m_rdoqEnable && (7 == m_basicFeature->m_targetUsage);
303     params.rdoqintratuthreshold         = (uint16_t)m_rdoqIntraTuThreshold;
304 
305     return MOS_STATUS_SUCCESS;
306 }
307 
MHW_SETPAR_DECL_SRC(HCP_PIPE_MODE_SELECT,HevcEncodeCqp)308 MHW_SETPAR_DECL_SRC(HCP_PIPE_MODE_SELECT, HevcEncodeCqp)
309 {
310     ENCODE_FUNC_CALL();
311 
312     params.bRdoqEnable   = m_rdoqEnable;
313 
314     return MOS_STATUS_SUCCESS;
315 }
316 
MHW_SETPAR_DECL_SRC(HCP_PIPE_BUF_ADDR_STATE,HevcEncodeCqp)317 MHW_SETPAR_DECL_SRC(HCP_PIPE_BUF_ADDR_STATE, HevcEncodeCqp)
318 {
319     ENCODE_FUNC_CALL();
320 
321     params.presDeblockingFilterTileRowStoreScratchBuffer   = m_resDeblockingFilterTileRowStoreScratchBuffer;
322     params.presDeblockingFilterColumnRowStoreScratchBuffer = m_resDeblockingFilterColumnRowStoreScratchBuffer;
323     params.presMfdDeblockingFilterRowStoreScratchBuffer    = m_resDeblockingFilterRowStoreScratchBuffer;
324 
325     params.presSaoLineBuffer       = m_resSAOLineBuffer;
326     params.presSaoTileLineBuffer   = m_resSAOTileLineBuffer;
327     params.presSaoTileColumnBuffer = m_resSAOTileColumnBuffer;
328     params.presSaoStreamOutBuffer  = m_resSAOStreamOutBuffer;
329     params.presSaoRowStoreBuffer   = const_cast<PMOS_RESOURCE>(&m_vdencSAORowStoreBuffer);
330 
331     return MOS_STATUS_SUCCESS;
332 }
333 
MHW_SETPAR_DECL_SRC(HCP_SLICE_STATE,HevcEncodeCqp)334 MHW_SETPAR_DECL_SRC(HCP_SLICE_STATE, HevcEncodeCqp)
335 {
336     auto hevcFeature = dynamic_cast<HevcBasicFeature *>(m_basicFeature);
337     ENCODE_CHK_NULL_RETURN(hevcFeature);
338 
339     PCODEC_HEVC_ENCODE_SLICE_PARAMS hevcSliceParams = hevcFeature->m_hevcSliceParams;
340     ENCODE_CHK_NULL_RETURN(hevcSliceParams);
341     PCODEC_HEVC_ENCODE_SLICE_PARAMS pEncodeHevcSliceParams = (CODEC_HEVC_ENCODE_SLICE_PARAMS *)&hevcSliceParams[hevcFeature->m_curNumSlices];
342     params.deblockingFilterDisable = pEncodeHevcSliceParams->slice_deblocking_filter_disable_flag;
343     params.tcOffsetDiv2            = pEncodeHevcSliceParams->tc_offset_div2;
344     params.betaOffsetDiv2          = pEncodeHevcSliceParams->beta_offset_div2;
345 
346     //SAO
347     params.saoLumaFlag   = (m_saoEnable) ? pEncodeHevcSliceParams->slice_sao_luma_flag : 0;
348     params.saoChromaFlag = (m_saoEnable) ? pEncodeHevcSliceParams->slice_sao_chroma_flag : 0;
349 
350     if (m_transformSkipEnable)
351     {
352         int slcQP = m_picQPY + pEncodeHevcSliceParams->slice_qp_delta;
353         ENCODE_ASSERT(slcQP >= 0 && slcQP < HevcBasicFeature::m_qpNum);
354 
355         int qpIdx                    = 0;
356         if (slcQP <= 22)
357         {
358             qpIdx = 0;
359         }
360         else if (slcQP <= 27)
361         {
362             qpIdx = 1;
363         }
364         else if (slcQP <= 32)
365         {
366             qpIdx = 2;
367         }
368         else
369         {
370             qpIdx = 3;
371         }
372 
373         auto setting = static_cast<HevcVdencFeatureSettings *>(m_constSettings);
374         ENCODE_CHK_NULL_RETURN(setting);
375 
376         params.transformskiplambda = setting->transformSkipLambdaTable[slcQP];
377 
378         if (m_basicFeature->m_pictureCodingType == I_TYPE)
379         {
380             params.transformskipNumzerocoeffsFactor0    = setting->transformSkipCoeffsTable[qpIdx][0][0][0][0];
381             params.transformskipNumzerocoeffsFactor1    = setting->transformSkipCoeffsTable[qpIdx][0][0][1][0];
382             params.transformskipNumnonzerocoeffsFactor0 = setting->transformSkipCoeffsTable[qpIdx][0][0][0][1] + 32;
383             params.transformskipNumnonzerocoeffsFactor1 = setting->transformSkipCoeffsTable[qpIdx][0][0][1][1] + 32;
384         }
385         else
386         {
387             params.transformskipNumzerocoeffsFactor0    = setting->transformSkipCoeffsTable[qpIdx][1][0][0][0];
388             params.transformskipNumzerocoeffsFactor1    = setting->transformSkipCoeffsTable[qpIdx][1][0][1][0];
389             params.transformskipNumnonzerocoeffsFactor0 = setting->transformSkipCoeffsTable[qpIdx][1][0][0][1] + 32;
390             params.transformskipNumnonzerocoeffsFactor1 = setting->transformSkipCoeffsTable[qpIdx][1][0][1][1] + 32;
391         }
392     }
393 
394     return MOS_STATUS_SUCCESS;
395 }
396 
397 }  // namespace encode
398