1 /*
2 * Copyright (c) 2020 - 2023, 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_superres.cpp
24 //! \brief Super-res feature
25 //!
26
27 #include "encode_av1_superres.h"
28 #include "encode_av1_tile.h"
29
30 namespace encode
31 {
Av1SuperRes(MediaFeatureManager * featureManager,EncodeAllocator * allocator,void * constSettings)32 Av1SuperRes::Av1SuperRes(MediaFeatureManager *featureManager,
33 EncodeAllocator *allocator,
34 void *constSettings):
35 MediaFeature(constSettings)
36 {
37 ENCODE_FUNC_CALL();
38
39 ENCODE_CHK_NULL_NO_STATUS_RETURN(featureManager);
40 m_featureManager = featureManager;
41 ENCODE_CHK_NULL_NO_STATUS_RETURN(m_featureManager);
42
43 m_allocator = allocator;
44 ENCODE_CHK_NULL_NO_STATUS_RETURN(m_allocator);
45 }
46
Init(void * setting)47 MOS_STATUS Av1SuperRes::Init(void *setting)
48 {
49 ENCODE_FUNC_CALL();
50 ENCODE_CHK_NULL_RETURN(setting);
51
52 m_basicFeature = dynamic_cast<Av1BasicFeature *>(m_featureManager->GetFeature(Av1FeatureIDs::basicFeature));
53 ENCODE_CHK_NULL_RETURN(m_basicFeature);
54
55 m_trackedBuf = m_basicFeature->m_trackedBuf;
56 ENCODE_CHK_NULL_RETURN(m_trackedBuf);
57
58 return MOS_STATUS_SUCCESS;
59 }
60
Update(void * params)61 MOS_STATUS Av1SuperRes::Update(void *params)
62 {
63 ENCODE_FUNC_CALL();
64
65 EncoderParams *encodeParams = (EncoderParams *)params;
66 ENCODE_CHK_NULL_RETURN(encodeParams);
67
68 auto av1SeqParams = static_cast<PCODEC_AV1_ENCODE_SEQUENCE_PARAMS>(encodeParams->pSeqParams);
69 ENCODE_CHK_NULL_RETURN(av1SeqParams);
70
71 auto av1PicParams = static_cast<PCODEC_AV1_ENCODE_PICTURE_PARAMS>(encodeParams->pPicParams);
72 ENCODE_CHK_NULL_RETURN(av1SeqParams);
73
74 m_oriFrameHeight = av1PicParams->frame_height_minus1 + 1;
75 m_oriAlignedFrameWidth = av1PicParams->frame_width_minus1 + 1;
76
77 uint16_t picHeightInMb = (uint16_t)CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_oriFrameHeight);
78 m_frameHeight = picHeightInMb * CODECHAL_MACROBLOCK_HEIGHT;
79
80 m_enabled = av1SeqParams->CodingToolFlags.fields.enable_superres;
81 m_useSuperRes = av1PicParams->PicFlags.fields.use_superres;
82
83 ENCODE_CHK_COND_RETURN(!m_enabled && m_useSuperRes == true, "Super-res disabled in SPS, but enabled in PPS!");
84 ENCODE_CHK_COND_RETURN(m_enabled && !m_useSuperRes && av1PicParams->superres_scale_denominator != av1ScaleNumerator, "Super-res not used in current frame, but scale denominator is not 8!");
85
86 if (m_enabled && m_useSuperRes)
87 {
88 m_superResDenom = av1PicParams->superres_scale_denominator;
89 ENCODE_CHK_COND_RETURN(m_superResDenom < 9 || m_superResDenom > 16, "Wrong value of super-res denominator, should be in range [9, 16]!");
90
91 // HW restriction of SuperRes denominator for SuperRes + LoopRestoration
92 ENCODE_CHK_COND_RETURN(av1SeqParams->CodingToolFlags.fields.enable_restoration && m_superResDenom % 2 == 1, "When both SuperRes and LoopRestoration are enabled, only valid SuperRes denominator values are 10, 12, 14 and 16");
93
94 m_frameWidthDs = ((m_oriAlignedFrameWidth << 3) + (m_superResDenom >> 1)) / m_superResDenom;
95
96 // update DDI width so that subsequent features will use downscaled width
97 av1PicParams->frame_width_minus1 = m_frameWidthDs - 1;
98 }
99 else
100 {
101 m_frameWidthDs = m_oriAlignedFrameWidth;
102 m_superResDenom = av1ScaleNumerator;
103 }
104
105 int8_t subsamplingX = /*SequenceChromaSubSamplingFormat != chromaIdc444 ? 1 : 0*/ 1;
106 m_subsamplingX[0] = 0;
107 m_subsamplingX[1] = subsamplingX;
108 m_subsamplingX[2] = subsamplingX;
109
110 ENCODE_CHK_STATUS_RETURN(m_basicFeature->m_ref.UpdateRefFrameSize(m_oriAlignedFrameWidth, av1PicParams->frame_height_minus1 + 1));
111
112 if (m_enabled)
113 {
114 m_basicFeature->m_ref.SetPostCdefAsEncRef(true);
115
116 m_widthChanged = m_prevDsWidth != av1PicParams->frame_width_minus1 + 1;
117
118 ENCODE_CHK_NULL_RETURN(encodeParams->psRawSurface);
119 m_raw.resource = encodeParams->psRawSurface;
120 m_allocator->GetSurfaceInfo(m_raw.resource);
121
122 ENCODE_CHK_STATUS_RETURN(PrepareRawSurface());
123
124 PrepareVeSfcDownscalingParam(m_raw, m_rawDs, m_downScalingParams);
125
126 m_prevDsWidth = m_frameWidthDs;
127 }
128
129 return MOS_STATUS_SUCCESS;
130 }
131
InitMMCState(EncodeMemComp * mmcState)132 MOS_STATUS Av1SuperRes::InitMMCState(EncodeMemComp *mmcState)
133 {
134 ENCODE_CHK_NULL_RETURN(mmcState);
135 m_mmcState = mmcState;
136 return MOS_STATUS_SUCCESS;
137 }
138
SetSurfaceMMCParams(EncodeMemComp & mmcState,MOS_SURFACE & surf)139 static inline MOS_STATUS SetSurfaceMMCParams(EncodeMemComp &mmcState, MOS_SURFACE &surf)
140 {
141 ENCODE_CHK_STATUS_RETURN(mmcState.SetSurfaceMmcMode(&surf));
142 ENCODE_CHK_STATUS_RETURN(mmcState.SetSurfaceMmcState(&surf));
143 ENCODE_CHK_STATUS_RETURN(mmcState.SetSurfaceMmcFormat(&surf));
144 surf.bIsCompressed = surf.CompressionMode != MOS_MMC_DISABLED;
145
146 return MOS_STATUS_SUCCESS;
147 }
148
PrepareRawSurface()149 MOS_STATUS Av1SuperRes::PrepareRawSurface()
150 {
151 ENCODE_FUNC_CALL();
152
153 if (m_enabled)
154 {
155 m_raw.unalignedWidth = GetUpscaledWidth();
156 m_raw.unalignedHeight = m_oriFrameHeight;
157
158 ENCODE_CHK_NULL_RETURN(m_mmcState);
159
160 if (m_widthChanged)
161 {
162 if (!Mos_ResourceIsNull(&m_rawDs.resource->OsResource))
163 {
164 m_allocator->DestroySurface(m_rawDs.resource);
165 }
166
167 MOS_ALLOC_GFXRES_PARAMS allocParamsForBuffer2D;
168 MOS_ZeroMemory(&allocParamsForBuffer2D, sizeof(MOS_ALLOC_GFXRES_PARAMS));
169
170 allocParamsForBuffer2D.Type = MOS_GFXRES_2D;
171 allocParamsForBuffer2D.TileType = MOS_TILE_Y;
172 allocParamsForBuffer2D.Format = m_raw.resource->Format;
173 allocParamsForBuffer2D.dwWidth = MOS_ALIGN_CEIL(m_frameWidthDs, av1SuperBlockWidth);
174 allocParamsForBuffer2D.dwHeight = MOS_ALIGN_CEIL(m_frameHeight, av1SuperBlockHeight);
175 allocParamsForBuffer2D.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_CACHE;
176 allocParamsForBuffer2D.pBufName = "superResEncRawSurface";
177
178 if (m_mmcState->IsMmcEnabled())
179 {
180 allocParamsForBuffer2D.CompressionMode = MOS_MMC_MC;
181 allocParamsForBuffer2D.bIsCompressible = true;
182 }
183
184 m_rawDs.resource = m_allocator->AllocateSurface(allocParamsForBuffer2D, false);
185 ENCODE_CHK_NULL_RETURN(m_rawDs.resource);
186 ENCODE_CHK_STATUS_RETURN(m_allocator->GetSurfaceInfo(m_rawDs.resource));
187
188 m_rawDs.unalignedWidth = m_frameWidthDs;
189 m_rawDs.unalignedHeight = m_oriFrameHeight;
190 }
191
192 if (m_mmcState->IsMmcEnabled())
193 {
194 SetSurfaceMMCParams(*m_mmcState, *m_raw.resource);
195 SetSurfaceMMCParams(*m_mmcState, *m_rawDs.resource);
196 }
197 }
198
199 return MOS_STATUS_SUCCESS;
200 }
201
PrepareVeSfcDownscalingParam(const SURFACE & inSurf,const SURFACE & outSurf,VEBOX_SFC_PARAMS & params)202 MOS_STATUS Av1SuperRes::PrepareVeSfcDownscalingParam(const SURFACE &inSurf, const SURFACE &outSurf, VEBOX_SFC_PARAMS ¶ms)
203 {
204 ENCODE_FUNC_CALL();
205
206 params.input.surface = inSurf.resource;
207 params.input.chromaSiting = 0;
208 params.input.rcSrc = {0, 0, (long)inSurf.unalignedWidth, (long)inSurf.unalignedHeight};
209 params.input.rotation = ROTATION_IDENTITY;
210
211 params.output.surface = outSurf.resource;
212 params.output.chromaSiting = 0;
213 params.output.rcDst = {0, 0, (long)outSurf.unalignedWidth, (long)outSurf.unalignedHeight};
214
215 switch (inSurf.resource->Format)
216 {
217 case Format_NV12:
218 case Format_P010:
219 params.input.colorSpace = CSpace_Any;
220 params.output.colorSpace = CSpace_Any;
221 break;
222 case Format_A8R8G8B8:
223 case Format_A8B8G8R8:
224 params.input.colorSpace = CSpace_sRGB;
225 params.output.colorSpace = CSpace_sRGB;
226 break;
227 default:
228 params.input.colorSpace = CSpace_Any;
229 params.output.colorSpace = CSpace_Any;
230 break;
231 }
232
233 return MOS_STATUS_SUCCESS;
234 }
235
MHW_SETPAR_DECL_SRC(AVP_PIC_STATE,Av1SuperRes)236 MHW_SETPAR_DECL_SRC(AVP_PIC_STATE, Av1SuperRes)
237 {
238 params.enableSuperres = m_useSuperRes;
239
240 return MOS_STATUS_SUCCESS;
241 }
242
243 static constexpr int32_t RS_SUBPEL_BITS = 6;
244 static constexpr int32_t RS_SCALE_SUBPEL_BITS = 14;
245 static constexpr int32_t RS_SCALE_EXTRA_BITS = RS_SCALE_SUBPEL_BITS - RS_SUBPEL_BITS;
246 static constexpr int32_t RS_SCALE_EXTRA_OFF = 1 << (RS_SCALE_EXTRA_BITS - 1);
247 static constexpr int32_t RS_SCALE_SUBPEL_MASK = (1 << RS_SCALE_SUBPEL_BITS) - 1;
248
GetUpscaleConvolveStep(int32_t inLength,int32_t outLength)249 static inline int32_t GetUpscaleConvolveStep(int32_t inLength, int32_t outLength)
250 {
251 return ((inLength << RS_SCALE_SUBPEL_BITS) + outLength / 2) / outLength;
252 }
253
GetUpscaleConvolveX0(int32_t inLength,int32_t outLength,int32_t xStepQn)254 static inline int32_t GetUpscaleConvolveX0(int32_t inLength, int32_t outLength, int32_t xStepQn)
255 {
256 const int32_t err = outLength * xStepQn - (inLength << RS_SCALE_SUBPEL_BITS);
257 const int32_t x0 = (-((outLength - inLength) << (RS_SCALE_SUBPEL_BITS - 1)) + outLength / 2) / outLength +
258 RS_SCALE_EXTRA_OFF - err / 2;
259
260 return static_cast<int32_t>(static_cast<uint32_t>(x0) & RS_SCALE_SUBPEL_MASK);
261 }
262
MHW_SETPAR_DECL_SRC(AVP_INLOOP_FILTER_STATE,Av1SuperRes)263 MHW_SETPAR_DECL_SRC(AVP_INLOOP_FILTER_STATE, Av1SuperRes)
264 {
265 params.superresUpscaledWidthMinus1 = m_oriAlignedFrameWidth - 1;
266 params.superresDenom = m_superResDenom;
267
268 int32_t xStepQn[3];
269 int32_t x0Qn[3];
270
271 if (m_enabled && m_useSuperRes)
272 {
273 for (int32_t plane = 0; plane < 2; plane++)
274 {
275 int32_t downscaledPlaneWidth = ROUND_POWER_OF_TWO(m_frameWidthDs, m_subsamplingX[plane]);
276 int32_t upscaledPlaneWidth = ROUND_POWER_OF_TWO(m_oriAlignedFrameWidth, m_subsamplingX[plane]);
277
278 xStepQn[plane] = GetUpscaleConvolveStep(downscaledPlaneWidth, upscaledPlaneWidth);
279 x0Qn[plane] = GetUpscaleConvolveX0(downscaledPlaneWidth, upscaledPlaneWidth, xStepQn[plane]);
280 }
281
282 xStepQn[2] = xStepQn[1];
283 x0Qn[2] = x0Qn[1];
284
285 params.lumaPlaneXStepQn = xStepQn[0];
286 params.chromaPlaneXStepQn = xStepQn[1];
287 }
288
289 auto tileFeature = dynamic_cast<Av1EncodeTile *>(m_featureManager->GetFeature(Av1FeatureIDs::encodeTile));
290 ENCODE_CHK_NULL_RETURN(tileFeature);
291
292 EncodeTileData tileData = {};
293 tileFeature->GetCurrentTile(tileData);
294
295 if (m_enabled && m_useSuperRes)
296 {
297 /* This calculation is the same with CModel but will cause hang issue for multi-tile tests on EMU
298 params.lumaPlaneX0Qn = x0Qn[0] + params.lumaPlaneXStepQn * lumaXPos * m_superResDenom / av1ScaleNumerator;
299 params.chromaPlaneX0Qn = x0Qn[1] + params.chromaPlaneXStepQn * chromaXPos * m_superResDenom / av1ScaleNumerator;
300 */
301 params.lumaPlaneX0Qn = x0Qn[0];
302 params.chromaPlaneX0Qn = x0Qn[1];
303 }
304
305 return MOS_STATUS_SUCCESS;
306 }
307 } // namespace encode
308