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