1 /*
2 * Copyright © Microsoft 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 (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "d3d12_video_enc.h"
25 #include "d3d12_video_enc_hevc.h"
26 #include "util/u_video.h"
27 #include "d3d12_screen.h"
28 #include "d3d12_format.h"
29
30 #include <cmath>
31 #include <algorithm>
32 #include <numeric>
33
34 void
d3d12_video_encoder_update_current_rate_control_hevc(struct d3d12_video_encoder * pD3D12Enc,pipe_h265_enc_picture_desc * picture)35 d3d12_video_encoder_update_current_rate_control_hevc(struct d3d12_video_encoder *pD3D12Enc,
36 pipe_h265_enc_picture_desc *picture)
37 {
38 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc = {};
39 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_FrameRate.Numerator =
40 picture->rc.frame_rate_num;
41 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_FrameRate.Denominator =
42 picture->rc.frame_rate_den;
43 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
44
45 if (picture->roi.num > 0)
46 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
47 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP;
48
49 switch (picture->rc.rate_ctrl_method) {
50 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP:
51 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE:
52 {
53 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR;
54 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.TargetAvgBitRate =
55 picture->rc.target_bitrate;
56 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.PeakBitRate =
57 picture->rc.peak_bitrate;
58
59 if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
60 debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
61 ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate);
62 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
63 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
64 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity =
65 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate;
66 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.InitialVBVFullness =
67 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate;
68 } else if (picture->rc.app_requested_hrd_buffer) {
69 debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc HRD required by app,"
70 " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rc.vbv_buffer_size, picture->rc.vbv_buf_initial_size);
71 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
72 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
73 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.VBVCapacity =
74 picture->rc.vbv_buffer_size;
75 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.InitialVBVFullness =
76 picture->rc.vbv_buf_initial_size;
77 }
78
79 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.max_frame_size = picture->rc.max_au_size;
80 if (picture->rc.max_au_size > 0) {
81 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
82 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
83 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MaxFrameBitSize =
84 picture->rc.max_au_size;
85
86 debug_printf(
87 "[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
88 "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
89 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MaxFrameBitSize);
90 }
91
92 if (picture->rc.app_requested_qp_range) {
93 debug_printf(
94 "[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
95 "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
96 picture->rc.min_qp, picture->rc.max_qp);
97 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
98 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
99 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MinQP =
100 picture->rc.min_qp;
101 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MaxQP =
102 picture->rc.max_qp;
103 }
104
105 if (picture->quality_modes.level > 0) {
106 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
107 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
108 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
109 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
110
111 // Convert between D3D12 definition and PIPE definition
112 // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
113 // The lower the value, the fastest the encode operation
114 // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
115 // A lower value means higher quality, and a value of 1 represents the highest quality.
116 // The quality level setting is used as a trade-off between quality and speed/power
117 // consumption, with higher quality corresponds to lower speed and higher power consumption.
118
119 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR1.QualityVsSpeed =
120 pD3D12Enc->max_quality_levels - picture->quality_modes.level;
121 }
122
123 } break;
124 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_QUALITY_VARIABLE:
125 {
126 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR;
127 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.TargetAvgBitRate =
128 picture->rc.target_bitrate;
129 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.PeakBitRate =
130 picture->rc.peak_bitrate;
131 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.ConstantQualityTarget =
132 picture->rc.vbr_quality_factor;
133 if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
134 debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
135 ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate);
136 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
137 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
138 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
139 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
140 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.VBVCapacity =
141 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
142 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.InitialVBVFullness =
143 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
144 } else if (picture->rc.app_requested_hrd_buffer) {
145 debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc HRD required by app,"
146 " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rc.vbv_buffer_size, picture->rc.vbv_buf_initial_size);
147 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
148 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
149 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
150 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
151 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.VBVCapacity =
152 picture->rc.vbv_buffer_size;
153 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.InitialVBVFullness =
154 picture->rc.vbv_buf_initial_size;
155 }
156 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.max_frame_size = picture->rc.max_au_size;
157 if (picture->rc.max_au_size > 0) {
158 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
159 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
160 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MaxFrameBitSize =
161 picture->rc.max_au_size;
162
163 debug_printf(
164 "[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
165 "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
166 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MaxFrameBitSize);
167 }
168
169 if (picture->rc.app_requested_qp_range) {
170 debug_printf(
171 "[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
172 "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
173 picture->rc.min_qp, picture->rc.max_qp);
174 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
175 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
176 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MinQP =
177 picture->rc.min_qp;
178 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MaxQP =
179 picture->rc.max_qp;
180 }
181
182 if (picture->quality_modes.level > 0) {
183 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
184 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
185 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
186 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
187
188 // Convert between D3D12 definition and PIPE definition
189 // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
190 // The lower the value, the fastest the encode operation
191 // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
192 // A lower value means higher quality, and a value of 1 represents the highest quality.
193 // The quality level setting is used as a trade-off between quality and speed/power
194 // consumption, with higher quality corresponds to lower speed and higher power consumption.
195
196 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.QualityVsSpeed =
197 pD3D12Enc->max_quality_levels - picture->quality_modes.level;
198 }
199
200 } break;
201 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP:
202 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT:
203 {
204 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR;
205 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate =
206 picture->rc.target_bitrate;
207
208 /* For CBR mode, to guarantee bitrate of generated stream complies with
209 * target bitrate (e.g. no over +/-10%), vbv_buffer_size and initial capacity should be same
210 * as target bitrate. Controlled by OS env var D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE
211 */
212 if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
213 debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
214 ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate);
215 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
216 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
217 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity =
218 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate;
219 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.InitialVBVFullness =
220 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate;
221 } else if (picture->rc.app_requested_hrd_buffer) {
222 debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc HRD required by app,"
223 " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rc.vbv_buffer_size, picture->rc.vbv_buf_initial_size);
224 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
225 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
226 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity =
227 picture->rc.vbv_buffer_size;
228 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.InitialVBVFullness =
229 picture->rc.vbv_buf_initial_size;
230 }
231
232 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.max_frame_size = picture->rc.max_au_size;
233 if (picture->rc.max_au_size > 0) {
234 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
235 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
236 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.MaxFrameBitSize =
237 picture->rc.max_au_size;
238
239 debug_printf(
240 "[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
241 "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
242 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.MaxFrameBitSize);
243 }
244
245 if (picture->rc.app_requested_qp_range) {
246 debug_printf(
247 "[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
248 "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
249 picture->rc.min_qp, picture->rc.max_qp);
250 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
251 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
252 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.MinQP =
253 picture->rc.min_qp;
254 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.MaxQP =
255 picture->rc.max_qp;
256 }
257
258 if (picture->quality_modes.level > 0) {
259 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
260 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
261 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
262 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
263
264 // Convert between D3D12 definition and PIPE definition
265 // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
266 // The lower the value, the fastest the encode operation
267 // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
268 // A lower value means higher quality, and a value of 1 represents the highest quality.
269 // The quality level setting is used as a trade-off between quality and speed/power
270 // consumption, with higher quality corresponds to lower speed and higher power consumption.
271
272 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR1.QualityVsSpeed =
273 pD3D12Enc->max_quality_levels - picture->quality_modes.level;
274 }
275
276 } break;
277 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_DISABLE:
278 {
279 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
280 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
281 .ConstantQP_FullIntracodedFrame = picture->rc.quant_i_frames;
282 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
283 .ConstantQP_InterPredictedFrame_PrevRefOnly = picture->rc.quant_p_frames;
284 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
285 .ConstantQP_InterPredictedFrame_BiDirectionalRef = picture->rc.quant_b_frames;
286
287 if (picture->quality_modes.level > 0) {
288 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
289 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
290 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
291 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
292
293 // Convert between D3D12 definition and PIPE definition
294 // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
295 // The lower the value, the fastest the encode operation
296 // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
297 // A lower value means higher quality, and a value of 1 represents the highest quality.
298 // The quality level setting is used as a trade-off between quality and speed/power
299 // consumption, with higher quality corresponds to lower speed and higher power consumption.
300
301 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP1.QualityVsSpeed =
302 pD3D12Enc->max_quality_levels - picture->quality_modes.level;
303 }
304 } break;
305 default:
306 {
307 debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc invalid RC "
308 "config, using default RC CQP mode\n");
309 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
310 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
311 .ConstantQP_FullIntracodedFrame = 30;
312 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
313 .ConstantQP_InterPredictedFrame_PrevRefOnly = 30;
314 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
315 .ConstantQP_InterPredictedFrame_BiDirectionalRef = 30;
316 } break;
317 }
318 }
319
320 void
d3d12_video_encoder_update_current_frame_pic_params_info_hevc(struct d3d12_video_encoder * pD3D12Enc,struct pipe_video_buffer * srcTexture,struct pipe_picture_desc * picture,D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA & picParams,bool & bUsedAsReference)321 d3d12_video_encoder_update_current_frame_pic_params_info_hevc(struct d3d12_video_encoder *pD3D12Enc,
322 struct pipe_video_buffer *srcTexture,
323 struct pipe_picture_desc *picture,
324 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &picParams,
325 bool &bUsedAsReference)
326 {
327 struct pipe_h265_enc_picture_desc *hevcPic = (struct pipe_h265_enc_picture_desc *) picture;
328 d3d12_video_bitstream_builder_hevc *pHEVCBitstreamBuilder =
329 static_cast<d3d12_video_bitstream_builder_hevc *>(pD3D12Enc->m_upBitstreamBuilder.get());
330 assert(pHEVCBitstreamBuilder != nullptr);
331
332 bUsedAsReference = !hevcPic->not_referenced;
333
334 picParams.pHEVCPicData->slice_pic_parameter_set_id = pHEVCBitstreamBuilder->get_active_pps_id();
335 picParams.pHEVCPicData->FrameType = d3d12_video_encoder_convert_frame_type_hevc(hevcPic->picture_type);
336 picParams.pHEVCPicData->PictureOrderCountNumber = hevcPic->pic_order_cnt;
337
338 picParams.pHEVCPicData->List0ReferenceFramesCount = 0;
339 picParams.pHEVCPicData->pList0ReferenceFrames = nullptr;
340 picParams.pHEVCPicData->List1ReferenceFramesCount = 0;
341 picParams.pHEVCPicData->pList1ReferenceFrames = nullptr;
342
343 if (picParams.pHEVCPicData->FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_P_FRAME) {
344 picParams.pHEVCPicData->List0ReferenceFramesCount = hevcPic->num_ref_idx_l0_active_minus1 + 1;
345 picParams.pHEVCPicData->pList0ReferenceFrames = hevcPic->ref_idx_l0_list;
346 } else if (picParams.pHEVCPicData->FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_B_FRAME) {
347 picParams.pHEVCPicData->List0ReferenceFramesCount = hevcPic->num_ref_idx_l0_active_minus1 + 1;
348 picParams.pHEVCPicData->pList0ReferenceFrames = hevcPic->ref_idx_l0_list;
349 picParams.pHEVCPicData->List1ReferenceFramesCount = hevcPic->num_ref_idx_l1_active_minus1 + 1;
350 picParams.pHEVCPicData->pList1ReferenceFrames = hevcPic->ref_idx_l1_list;
351 }
352
353 if ((pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig.ConfigurationFlags
354 & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES) != 0)
355 picParams.pHEVCPicData->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_REQUEST_INTRA_CONSTRAINED_SLICES;
356
357 if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0)
358 {
359 // Use 8 bit qpmap array for HEVC picparams (-51, 51 range and int8_t pRateControlQPMap type)
360 const int32_t hevc_min_delta_qp = -51;
361 const int32_t hevc_max_delta_qp = 51;
362 d3d12_video_encoder_update_picparams_region_of_interest_qpmap(
363 pD3D12Enc,
364 &hevcPic->roi,
365 hevc_min_delta_qp,
366 hevc_max_delta_qp,
367 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap8Bit);
368 picParams.pHEVCPicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap8Bit.data();
369 picParams.pHEVCPicData->QPMapValuesCount = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap8Bit.size();
370 }
371 }
372
373 D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC
d3d12_video_encoder_convert_frame_type_hevc(enum pipe_h2645_enc_picture_type picType)374 d3d12_video_encoder_convert_frame_type_hevc(enum pipe_h2645_enc_picture_type picType)
375 {
376 switch (picType) {
377 case PIPE_H2645_ENC_PICTURE_TYPE_P:
378 {
379 return D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_P_FRAME;
380 } break;
381 case PIPE_H2645_ENC_PICTURE_TYPE_B:
382 {
383 return D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_B_FRAME;
384 } break;
385 case PIPE_H2645_ENC_PICTURE_TYPE_I:
386 {
387 return D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_I_FRAME;
388 } break;
389 case PIPE_H2645_ENC_PICTURE_TYPE_IDR:
390 {
391 return D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_IDR_FRAME;
392 } break;
393 default:
394 {
395 unreachable("Unsupported pipe_h2645_enc_picture_type");
396 } break;
397 }
398 }
399
400 ///
401 /// Tries to configurate the encoder using the requested slice configuration
402 /// or falls back to single slice encoding.
403 ///
404 bool
d3d12_video_encoder_negotiate_current_hevc_slices_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h265_enc_picture_desc * picture)405 d3d12_video_encoder_negotiate_current_hevc_slices_configuration(struct d3d12_video_encoder *pD3D12Enc,
406 pipe_h265_enc_picture_desc *picture)
407 {
408 ///
409 /// Initialize single slice by default
410 ///
411 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode =
412 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
413 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES requestedSlicesConfig = {};
414 requestedSlicesConfig.NumberOfSlicesPerFrame = 1;
415
416 ///
417 /// Try to see if can accomodate for multi-slice request by user
418 ///
419 if ((picture->slice_mode == PIPE_VIDEO_SLICE_MODE_BLOCKS) && (picture->num_slice_descriptors > 1)) {
420 /* Some apps send all same size slices minus 1 slice in any position in the descriptors */
421 /* Lets validate that there are at most 2 different slice sizes in all the descriptors */
422 std::vector<int> slice_sizes(picture->num_slice_descriptors);
423 for (uint32_t i = 0; i < picture->num_slice_descriptors; i++)
424 slice_sizes[i] = picture->slices_descriptors[i].num_ctu_in_slice;
425 std::sort(slice_sizes.begin(), slice_sizes.end());
426 bool bUniformSizeSlices = (std::unique(slice_sizes.begin(), slice_sizes.end()) - slice_sizes.begin()) <= 2;
427
428 uint32_t subregion_block_pixel_size = pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize;
429 uint32_t num_subregions_per_scanline =
430 DIV_ROUND_UP(pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width, subregion_block_pixel_size);
431
432 /* m_currentResolutionSupportCaps.SubregionBlockPixelsSize can be a multiple of MinCUSize to accomodate for HW requirements
433 So, if the allowed subregion (slice) pixel size partition is bigger (a multiple) than the CTU size, we have to adjust
434 num_subregions_per_slice by this factor respect from slices_descriptors[X].num_ctu_in_slice
435 */
436
437 /* This assert should always be true according to the spec
438 https://github.com/microsoft/DirectX-Specs/blob/master/d3d/D3D12VideoEncoding.md#3150-struct-d3d12_feature_data_video_encoder_resolution_support_limits
439 */
440 uint8_t minCUSize = d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig.MinLumaCodingUnitSize);
441 assert((pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize
442 % minCUSize) == 0);
443
444 uint32_t subregionsize_to_ctu_factor = pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize /
445 minCUSize;
446 uint32_t num_subregions_per_slice = picture->slices_descriptors[0].num_ctu_in_slice
447 * pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize
448 / (subregionsize_to_ctu_factor * subregionsize_to_ctu_factor);
449
450 bool bSliceAligned = ((num_subregions_per_slice % num_subregions_per_scanline) == 0);
451
452 if (bUniformSizeSlices &&
453 d3d12_video_encoder_check_subregion_mode_support(
454 pD3D12Enc,
455 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME)) {
456 requestedSlicesMode =
457 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
458 requestedSlicesConfig.NumberOfSlicesPerFrame = picture->num_slice_descriptors;
459 debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
460 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
461 "with %d slices per frame.\n",
462 requestedSlicesConfig.NumberOfSlicesPerFrame);
463 } else if (bUniformSizeSlices &&
464 d3d12_video_encoder_check_subregion_mode_support(
465 pD3D12Enc,
466 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED)) {
467 requestedSlicesMode =
468 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED;
469 requestedSlicesConfig.NumberOfCodingUnitsPerSlice = num_subregions_per_slice;
470 debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
471 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED "
472 "with %d NumberOfCodingUnitsPerSlice per frame.\n",
473 requestedSlicesConfig.NumberOfCodingUnitsPerSlice);
474
475 } else if (bUniformSizeSlices && bSliceAligned &&
476 d3d12_video_encoder_check_subregion_mode_support(
477 pD3D12Enc,
478 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION)) {
479
480 // Number of subregion block per slice is aligned to a scanline width, in which case we can
481 // use D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION
482 requestedSlicesMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION;
483 requestedSlicesConfig.NumberOfRowsPerSlice = (num_subregions_per_slice / num_subregions_per_scanline);
484 debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
485 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION with "
486 "%d subregion block rows (%d pix scanlines) per slice.\n",
487 requestedSlicesConfig.NumberOfRowsPerSlice,
488 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize);
489 } else {
490 debug_printf("[d3d12_video_encoder_hevc] Requested slice control mode is not supported: All slices must "
491 "have the same number of macroblocks.\n");
492 return false;
493 }
494 } else if(picture->slice_mode == PIPE_VIDEO_SLICE_MODE_MAX_SLICE_SIZE) {
495 if ((picture->max_slice_bytes > 0) &&
496 d3d12_video_encoder_check_subregion_mode_support(
497 pD3D12Enc,
498 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION )) {
499 requestedSlicesMode =
500 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION;
501 requestedSlicesConfig.MaxBytesPerSlice = picture->max_slice_bytes;
502 debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
503 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION "
504 "with %d MaxBytesPerSlice per frame.\n",
505 requestedSlicesConfig.MaxBytesPerSlice);
506 } else {
507 debug_printf("[d3d12_video_encoder_hevc] Requested slice control mode is not supported: All slices must "
508 "have the same number of macroblocks.\n");
509 return false;
510 }
511 } else {
512 requestedSlicesMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
513 requestedSlicesConfig.NumberOfSlicesPerFrame = 1;
514 debug_printf("[d3d12_video_encoder_hevc] Requested slice control mode is full frame. m_SlicesPartition_H264.NumberOfSlicesPerFrame = %d - m_encoderSliceConfigMode = %d \n",
515 requestedSlicesConfig.NumberOfSlicesPerFrame, requestedSlicesMode);
516 }
517
518 if (!d3d12_video_encoder_isequal_slice_config_hevc(
519 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
520 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC,
521 requestedSlicesMode,
522 requestedSlicesConfig)) {
523 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_slices;
524 }
525
526 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC = requestedSlicesConfig;
527 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode = requestedSlicesMode;
528
529 return true;
530 }
531
532 D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE
d3d12_video_encoder_convert_hevc_motion_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h265_enc_picture_desc * picture)533 d3d12_video_encoder_convert_hevc_motion_configuration(struct d3d12_video_encoder *pD3D12Enc,
534 pipe_h265_enc_picture_desc *picture)
535 {
536 return D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM;
537 }
538
539 bool
d3d12_video_encoder_update_hevc_gop_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h265_enc_picture_desc * picture)540 d3d12_video_encoder_update_hevc_gop_configuration(struct d3d12_video_encoder *pD3D12Enc,
541 pipe_h265_enc_picture_desc *picture)
542 {
543 // Only update GOP when it begins
544 // This triggers DPB/encoder/heap re-creation, so only check on IDR when a GOP might change
545 if ((picture->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR)
546 || (picture->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_I)) {
547 uint32_t GOPLength = picture->seq.intra_period;
548 uint32_t PPicturePeriod = picture->seq.ip_period;
549
550 const uint32_t max_pic_order_cnt_lsb = MAX2(16, util_next_power_of_two(GOPLength));
551 double log2_max_pic_order_cnt_lsb_minus4 = std::max(0.0, std::ceil(std::log2(max_pic_order_cnt_lsb)) - 4);
552 assert(log2_max_pic_order_cnt_lsb_minus4 < UCHAR_MAX);
553
554 // Set dirty flag if m_HEVCGroupOfPictures changed
555 auto previousGOPConfig = pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures;
556 pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures = {
557 GOPLength,
558 PPicturePeriod,
559 static_cast<uint8_t>(log2_max_pic_order_cnt_lsb_minus4)
560 };
561
562 if (memcmp(&previousGOPConfig,
563 &pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures,
564 sizeof(D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_HEVC)) != 0) {
565 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_gop;
566 }
567 }
568 return true;
569 }
570
571 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC
d3d12_video_encoder_convert_hevc_codec_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h265_enc_picture_desc * picture,bool & is_supported)572 d3d12_video_encoder_convert_hevc_codec_configuration(struct d3d12_video_encoder *pD3D12Enc,
573 pipe_h265_enc_picture_desc *picture,
574 bool&is_supported)
575 {
576 is_supported = true;
577 uint32_t min_cu_size = (1 << (picture->seq.log2_min_luma_coding_block_size_minus3 + 3));
578 uint32_t max_cu_size = (1 << (picture->seq.log2_min_luma_coding_block_size_minus3 + 3 + picture->seq.log2_diff_max_min_luma_coding_block_size));
579
580 uint32_t min_tu_size = (1 << (picture->seq.log2_min_transform_block_size_minus2 + 2));
581 uint32_t max_tu_size = (1 << (picture->seq.log2_min_transform_block_size_minus2 + 2 + picture->seq.log2_diff_max_min_transform_block_size));
582
583 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC config = {
584 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_NONE,
585 d3d12_video_encoder_convert_pixel_size_hevc_to_12cusize(min_cu_size),
586 d3d12_video_encoder_convert_pixel_size_hevc_to_12cusize(max_cu_size),
587 d3d12_video_encoder_convert_pixel_size_hevc_to_12tusize(min_tu_size),
588 d3d12_video_encoder_convert_pixel_size_hevc_to_12tusize(max_tu_size),
589 picture->seq.max_transform_hierarchy_depth_inter,
590 picture->seq.max_transform_hierarchy_depth_intra,
591 };
592
593 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps =
594 {
595 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE,
596 config.MinLumaCodingUnitSize,
597 config.MaxLumaCodingUnitSize,
598 config.MinLumaTransformUnitSize,
599 config.MaxLumaTransformUnitSize,
600 config.max_transform_hierarchy_depth_inter,
601 config.max_transform_hierarchy_depth_intra
602 };
603
604 D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = { };
605 capCodecConfigData.NodeIndex = pD3D12Enc->m_NodeIndex;
606 capCodecConfigData.Codec = D3D12_VIDEO_ENCODER_CODEC_HEVC;
607 D3D12_VIDEO_ENCODER_PROFILE_HEVC prof = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(pD3D12Enc->base.profile);
608 capCodecConfigData.Profile.pHEVCProfile = &prof;
609 capCodecConfigData.Profile.DataSize = sizeof(prof);
610 capCodecConfigData.CodecSupportLimits.pHEVCSupport = &pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps;
611 capCodecConfigData.CodecSupportLimits.DataSize = sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps);
612
613 if(FAILED(pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData)))
614 || !capCodecConfigData.IsSupported)
615 {
616 is_supported = false;
617
618 // Workaround for https://github.com/intel/libva/issues/641
619 if ( !capCodecConfigData.IsSupported
620 && ((picture->seq.max_transform_hierarchy_depth_inter == 0)
621 || (picture->seq.max_transform_hierarchy_depth_intra == 0)) )
622 {
623 // Try and see if the values where 4 and overflowed in the 2 bit fields
624 capCodecConfigData.CodecSupportLimits.pHEVCSupport->max_transform_hierarchy_depth_inter =
625 (picture->seq.max_transform_hierarchy_depth_inter == 0) ? 4 : picture->seq.max_transform_hierarchy_depth_inter;
626 capCodecConfigData.CodecSupportLimits.pHEVCSupport->max_transform_hierarchy_depth_intra =
627 (picture->seq.max_transform_hierarchy_depth_intra == 0) ? 4 : picture->seq.max_transform_hierarchy_depth_intra;
628
629 // Call the caps check again
630 if(SUCCEEDED(pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData)))
631 && capCodecConfigData.IsSupported)
632 {
633 // If this was the case, then update the config return variable with the overriden values too
634 is_supported = true;
635 config.max_transform_hierarchy_depth_inter =
636 capCodecConfigData.CodecSupportLimits.pHEVCSupport->max_transform_hierarchy_depth_inter;
637 config.max_transform_hierarchy_depth_intra =
638 capCodecConfigData.CodecSupportLimits.pHEVCSupport->max_transform_hierarchy_depth_intra;
639 }
640 }
641
642 if (!is_supported) {
643 debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - "
644 "Call to CheckFeatureCaps (D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, ...) returned failure "
645 "or not supported for Codec HEVC - MinLumaSize %d - MaxLumaSize %d - MinTransformSize %d - "
646 "MaxTransformSize %d - Depth_inter %d - Depth intra %d\n",
647 config.MinLumaCodingUnitSize,
648 config.MaxLumaCodingUnitSize,
649 config.MinLumaTransformUnitSize,
650 config.MaxLumaTransformUnitSize,
651 config.max_transform_hierarchy_depth_inter,
652 config.max_transform_hierarchy_depth_intra);
653
654 return config;
655 }
656 }
657
658 if (picture->seq.amp_enabled_flag)
659 config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
660
661 if (picture->seq.sample_adaptive_offset_enabled_flag)
662 config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER;
663
664 if (picture->pic.pps_loop_filter_across_slices_enabled_flag)
665 config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES;
666
667 if (picture->pic.transform_skip_enabled_flag)
668 config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING;
669
670 if (picture->pic.constrained_intra_pred_flag)
671 config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION;
672
673 if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES) != 0)
674 && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_DISABLING_LOOP_FILTER_ACROSS_SLICES_SUPPORT) == 0))
675 {
676 debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Disable deblocking across slice boundary mode not supported."
677 " Ignoring the request for this feature flag on this encode session\n");
678 // Disable it and keep going with a warning
679 config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES;
680 }
681
682 if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES) != 0)
683 && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_INTRA_SLICE_CONSTRAINED_ENCODING_SUPPORT) == 0))
684 {
685 debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Intra slice constrained mode not supported."
686 " Ignoring the request for this feature flag on this encode session\n");
687 // Disable it and keep going with a warning
688 config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES;
689 }
690
691 if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER) != 0)
692 && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_SAO_FILTER_SUPPORT) == 0))
693 {
694 debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - SAO Filter mode not supported."
695 " Ignoring the request for this feature flag on this encode session\n");
696 // Disable it and keep going with a warning
697 config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER;
698 }
699
700
701 if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION) != 0)
702 && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_SUPPORT) == 0))
703 {
704 debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Asymetric motion partition not supported."
705 " Ignoring the request for this feature flag on this encode session\n");
706 // Disable it and keep going with a warning
707 config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
708 }
709
710 if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION) == 0)
711 && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_REQUIRED) != 0))
712 {
713 debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Asymetric motion partition is required to be set."
714 " Enabling this HW required feature flag on this encode session\n");
715 // HW doesn't support otherwise, so set it
716 config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
717 }
718
719 if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING) != 0)
720 && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_SUPPORT) == 0))
721 {
722 debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Allow transform skipping is not supported."
723 " Ignoring the request for this feature flag on this encode session\n");
724 // Disable it and keep going with a warning
725 config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING;
726 }
727
728 if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION) != 0)
729 && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CONSTRAINED_INTRAPREDICTION_SUPPORT) == 0))
730 {
731 debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Constrained intra-prediction use is not supported."
732 " Ignoring the request for this feature flag on this encode session\n");
733 // Disable it and keep going with a warning
734 config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION;
735 }
736
737 return config;
738 }
739
740 static bool
d3d12_video_encoder_update_intra_refresh_hevc(struct d3d12_video_encoder * pD3D12Enc,D3D12_VIDEO_SAMPLE srcTextureDesc,struct pipe_h265_enc_picture_desc * picture)741 d3d12_video_encoder_update_intra_refresh_hevc(struct d3d12_video_encoder *pD3D12Enc,
742 D3D12_VIDEO_SAMPLE srcTextureDesc,
743 struct pipe_h265_enc_picture_desc * picture)
744 {
745 if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_NONE)
746 {
747 // D3D12 only supports row intra-refresh
748 if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_UNIT_ROWS)
749 {
750 debug_printf("[d3d12_video_encoder_update_intra_refresh_hevc] Unsupported INTRA_REFRESH_MODE %d\n", picture->intra_refresh.mode);
751 return false;
752 }
753
754 uint8_t ctbSize = d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(
755 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.MaxLumaCodingUnitSize);
756 uint32_t total_frame_blocks = static_cast<uint32_t>(std::ceil(srcTextureDesc.Height / ctbSize)) *
757 static_cast<uint32_t>(std::ceil(srcTextureDesc.Width / ctbSize));
758 D3D12_VIDEO_ENCODER_INTRA_REFRESH targetIntraRefresh = {
759 D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ROW_BASED,
760 total_frame_blocks / picture->intra_refresh.region_size,
761 };
762 double ir_wave_progress = (picture->intra_refresh.offset == 0) ? 0 :
763 picture->intra_refresh.offset / (double) total_frame_blocks;
764 pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex =
765 static_cast<uint32_t>(std::ceil(ir_wave_progress * targetIntraRefresh.IntraRefreshDuration));
766
767 // Set intra refresh state
768 pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = targetIntraRefresh;
769 // Need to send the sequence flag during all the IR duration
770 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_intra_refresh;
771 } else {
772 pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex = 0;
773 pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = {
774 D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
775 0,
776 };
777 }
778
779 return true;
780 }
781
782 bool
d3d12_video_encoder_update_current_encoder_config_state_hevc(struct d3d12_video_encoder * pD3D12Enc,D3D12_VIDEO_SAMPLE srcTextureDesc,struct pipe_picture_desc * picture)783 d3d12_video_encoder_update_current_encoder_config_state_hevc(struct d3d12_video_encoder *pD3D12Enc,
784 D3D12_VIDEO_SAMPLE srcTextureDesc,
785 struct pipe_picture_desc *picture)
786 {
787 struct pipe_h265_enc_picture_desc *hevcPic = (struct pipe_h265_enc_picture_desc *) picture;
788
789 // Reset reconfig dirty flags
790 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags = d3d12_video_encoder_config_dirty_flag_none;
791 // Reset sequence changes flags
792 pD3D12Enc->m_currentEncodeConfig.m_seqFlags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE;
793
794 // Set codec
795 if (pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc != D3D12_VIDEO_ENCODER_CODEC_HEVC) {
796 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec;
797 }
798 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc = D3D12_VIDEO_ENCODER_CODEC_HEVC;
799
800 // Set Sequence information
801 if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH265,
802 &hevcPic->seq,
803 sizeof(hevcPic->seq)) != 0) {
804 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sequence_info;
805 }
806 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH265 = hevcPic->seq;
807
808 if ((hevcPic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR) &&
809 (hevcPic->renew_headers_on_idr))
810 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sequence_info;
811
812 // Set input format
813 DXGI_FORMAT targetFmt = d3d12_convert_pipe_video_profile_to_dxgi_format(pD3D12Enc->base.profile);
814 if (pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format != targetFmt) {
815 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_input_format;
816 }
817
818 pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo = {};
819 pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format = targetFmt;
820 HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO,
821 &pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo,
822 sizeof(pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo));
823 if (FAILED(hr)) {
824 debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
825 return false;
826 }
827
828 // Set resolution
829 if ((pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width != srcTextureDesc.Width) ||
830 (pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height != srcTextureDesc.Height)) {
831 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_resolution;
832 }
833 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width = srcTextureDesc.Width;
834 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height = srcTextureDesc.Height;
835
836 // Set resolution codec dimensions (ie. cropping)
837 memset(&pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig, 0,
838 sizeof(pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig));
839 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.front = hevcPic->seq.pic_width_in_luma_samples;
840 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.back = hevcPic->seq.pic_height_in_luma_samples;
841 if (hevcPic->seq.conformance_window_flag) {
842 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.left = hevcPic->seq.conf_win_left_offset;
843 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.right = hevcPic->seq.conf_win_right_offset;
844 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.top = hevcPic->seq.conf_win_top_offset;
845 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.bottom = hevcPic->seq.conf_win_bottom_offset;
846 }
847 // Set profile
848 auto targetProfile = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(pD3D12Enc->base.profile);
849 if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile != targetProfile) {
850 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_profile;
851 }
852 pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile = targetProfile;
853
854 // Set level
855 auto targetLevel = d3d12_video_encoder_convert_level_hevc(hevcPic->seq.general_level_idc);
856 auto targetTier = (hevcPic->seq.general_tier_flag == 0) ? D3D12_VIDEO_ENCODER_TIER_HEVC_MAIN : D3D12_VIDEO_ENCODER_TIER_HEVC_HIGH;
857 if ( (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level != targetLevel)
858 || (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier != targetTier)) {
859 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_level;
860 }
861 pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier = targetTier;
862 pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level = targetLevel;
863
864 // Set codec config
865 bool is_supported = true;
866 auto targetCodecConfig = d3d12_video_encoder_convert_hevc_codec_configuration(pD3D12Enc, hevcPic, is_supported);
867 if(!is_supported) {
868 return false;
869 }
870
871 if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig,
872 &targetCodecConfig,
873 sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC)) != 0) {
874 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec_config;
875 }
876 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig = targetCodecConfig;
877
878 // Set rate control
879 d3d12_video_encoder_update_current_rate_control_hevc(pD3D12Enc, hevcPic);
880
881 ///
882 /// Check for video encode support detailed capabilities
883 ///
884
885 // Will call for d3d12 driver support based on the initial requested features, then
886 // try to fallback if any of them is not supported and return the negotiated d3d12 settings
887 D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 capEncoderSupportData1 = {};
888 // Get max number of slices per frame supported
889 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode =
890 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
891 if (!d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(pD3D12Enc, capEncoderSupportData1)) {
892 debug_printf("[d3d12_video_encoder_hevc] After negotiating caps, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1 "
893 "arguments are not supported - "
894 "ValidationFlags: 0x%x - SupportFlags: 0x%x\n",
895 capEncoderSupportData1.ValidationFlags,
896 capEncoderSupportData1.SupportFlags);
897 return false;
898 }
899
900 // Set slices config (configure before calling d3d12_video_encoder_calculate_max_slices_count_in_output)
901 if(!d3d12_video_encoder_negotiate_current_hevc_slices_configuration(pD3D12Enc, hevcPic)) {
902 debug_printf("d3d12_video_encoder_negotiate_current_hevc_slices_configuration failed!\n");
903 return false;
904 }
905
906 ///
907 // Calculate current settings based on the returned values from the caps query
908 //
909 pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput =
910 d3d12_video_encoder_calculate_max_slices_count_in_output(
911 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
912 &pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC,
913 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber,
914 pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
915 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize);
916
917 // Set GOP config
918 if(!d3d12_video_encoder_update_hevc_gop_configuration(pD3D12Enc, hevcPic)) {
919 debug_printf("d3d12_video_encoder_update_hevc_gop_configuration failed!\n");
920 return false;
921 }
922
923 // Set intra-refresh config
924 if(!d3d12_video_encoder_update_intra_refresh_hevc(pD3D12Enc, srcTextureDesc, hevcPic)) {
925 debug_printf("d3d12_video_encoder_update_intra_refresh_hevc failed!\n");
926 return false;
927 }
928
929 // m_currentEncodeConfig.m_encoderPicParamsDesc pic params are set in d3d12_video_encoder_reconfigure_encoder_objects
930 // after re-allocating objects if needed
931
932 // Set motion estimation config
933 auto targetMotionLimit = d3d12_video_encoder_convert_hevc_motion_configuration(pD3D12Enc, hevcPic);
934 if (pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit != targetMotionLimit) {
935 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |=
936 d3d12_video_encoder_config_dirty_flag_motion_precision_limit;
937 }
938 pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit = targetMotionLimit;
939
940 //
941 // Validate caps support returned values against current settings
942 //
943 if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile !=
944 pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_HEVCProfile) {
945 debug_printf("[d3d12_video_encoder_hevc] Warning: Requested D3D12_VIDEO_ENCODER_PROFILE_HEVC by upper layer: %d "
946 "mismatches UMD suggested D3D12_VIDEO_ENCODER_PROFILE_HEVC: %d\n",
947 pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile,
948 pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_HEVCProfile);
949 }
950
951 if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier !=
952 pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Tier) {
953 debug_printf("[d3d12_video_encoder_hevc] Warning: Requested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Tier by upper layer: %d "
954 "mismatches UMD suggested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Tier: %d\n",
955 pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier,
956 pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Tier);
957 }
958
959 if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level !=
960 pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Level) {
961 debug_printf("[d3d12_video_encoder_hevc] Warning: Requested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Level by upper layer: %d "
962 "mismatches UMD suggested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Level: %d\n",
963 pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level,
964 pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Level);
965 }
966
967 if (pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput >
968 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber) {
969 debug_printf("[d3d12_video_encoder_hevc] Desired number of subregions %d is not supported (higher than max "
970 "reported slice number %d in query caps) for current resolution (%d, %d)\n.",
971 pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput,
972 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber,
973 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width,
974 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height);
975 return false;
976 }
977 return true;
978 }
979
980 D3D12_VIDEO_ENCODER_PROFILE_HEVC
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(enum pipe_video_profile profile)981 d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(enum pipe_video_profile profile)
982 {
983 switch (profile) {
984 case PIPE_VIDEO_PROFILE_HEVC_MAIN:
985 {
986 return D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN;
987
988 } break;
989 case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
990 {
991 return D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10;
992 } break;
993 default:
994 {
995 unreachable("Unsupported pipe_video_profile");
996 } break;
997 }
998 }
999
1000 bool
d3d12_video_encoder_isequal_slice_config_hevc(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE targetMode,D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES targetConfig,D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE otherMode,D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES otherConfig)1001 d3d12_video_encoder_isequal_slice_config_hevc(
1002 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE targetMode,
1003 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES targetConfig,
1004 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE otherMode,
1005 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES otherConfig)
1006 {
1007 return (targetMode == otherMode) &&
1008 (memcmp(&targetConfig,
1009 &otherConfig,
1010 sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES)) == 0);
1011 }
1012
1013 uint32_t
d3d12_video_encoder_build_codec_headers_hevc(struct d3d12_video_encoder * pD3D12Enc,std::vector<uint64_t> & pWrittenCodecUnitsSizes)1014 d3d12_video_encoder_build_codec_headers_hevc(struct d3d12_video_encoder *pD3D12Enc,
1015 std::vector<uint64_t> &pWrittenCodecUnitsSizes)
1016 {
1017 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams =
1018 d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc);
1019
1020 auto profDesc = d3d12_video_encoder_get_current_profile_desc(pD3D12Enc);
1021 auto levelDesc = d3d12_video_encoder_get_current_level_desc(pD3D12Enc);
1022 auto codecConfigDesc = d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc);
1023 auto MaxDPBCapacity = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc);
1024
1025 pWrittenCodecUnitsSizes.clear();
1026 bool isFirstFrame = (pD3D12Enc->m_fenceValue == 1);
1027
1028 d3d12_video_bitstream_builder_hevc *pHEVCBitstreamBuilder =
1029 static_cast<d3d12_video_bitstream_builder_hevc *>(pD3D12Enc->m_upBitstreamBuilder.get());
1030 assert(pHEVCBitstreamBuilder);
1031
1032 uint32_t active_seq_parameter_set_id = pHEVCBitstreamBuilder->get_active_sps_id();
1033 uint32_t active_video_parameter_set_id = pHEVCBitstreamBuilder->get_active_vps_id();
1034
1035 bool writeNewVPS = isFirstFrame;
1036
1037 size_t writtenVPSBytesCount = 0;
1038 if (writeNewVPS) {
1039 bool gopHasBFrames = (pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures.PPicturePeriod > 1);
1040 pHEVCBitstreamBuilder->build_vps(*profDesc.pHEVCProfile,
1041 *levelDesc.pHEVCLevelSetting,
1042 pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
1043 MaxDPBCapacity, // max_num_ref_frames
1044 gopHasBFrames,
1045 active_video_parameter_set_id,
1046 pD3D12Enc->m_BitstreamHeadersBuffer,
1047 pD3D12Enc->m_BitstreamHeadersBuffer.begin(),
1048 writtenVPSBytesCount);
1049
1050 pWrittenCodecUnitsSizes.push_back(writtenVPSBytesCount);
1051 }
1052
1053 bool writeNewSPS = writeNewVPS // on new VPS written
1054 || ((pD3D12Enc->m_currentEncodeConfig.m_seqFlags & // also on resolution change
1055 D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_RESOLUTION_CHANGE) != 0)
1056 // Also on input format dirty flag for new SPS, VUI etc
1057 || (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_sequence_info);
1058
1059 size_t writtenSPSBytesCount = 0;
1060 if (writeNewSPS) {
1061 pHEVCBitstreamBuilder->build_sps(
1062 pHEVCBitstreamBuilder->get_latest_vps(),
1063 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH265,
1064 active_seq_parameter_set_id,
1065 pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
1066 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig,
1067 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize,
1068 pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
1069 *codecConfigDesc.pHEVCConfig,
1070 pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures,
1071 pD3D12Enc->m_BitstreamHeadersBuffer,
1072 pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenVPSBytesCount,
1073 writtenSPSBytesCount);
1074
1075 pWrittenCodecUnitsSizes.push_back(writtenSPSBytesCount);
1076 }
1077
1078 size_t writtenPPSBytesCount = 0;
1079 pHEVCBitstreamBuilder->build_pps(pHEVCBitstreamBuilder->get_latest_sps(),
1080 currentPicParams.pHEVCPicData->slice_pic_parameter_set_id,
1081 *codecConfigDesc.pHEVCConfig,
1082 *currentPicParams.pHEVCPicData,
1083 pD3D12Enc->m_StagingHeadersBuffer,
1084 pD3D12Enc->m_StagingHeadersBuffer.begin(),
1085 writtenPPSBytesCount);
1086
1087 std::vector<uint8_t>& active_pps = pHEVCBitstreamBuilder->get_active_pps();
1088 if (writeNewSPS ||
1089 (writtenPPSBytesCount != active_pps.size()) ||
1090 memcmp(pD3D12Enc->m_StagingHeadersBuffer.data(), active_pps.data(), writtenPPSBytesCount)) {
1091 active_pps = pD3D12Enc->m_StagingHeadersBuffer;
1092 pD3D12Enc->m_BitstreamHeadersBuffer.resize(writtenSPSBytesCount + writtenVPSBytesCount + writtenPPSBytesCount);
1093 memcpy(&pD3D12Enc->m_BitstreamHeadersBuffer.data()[(writtenSPSBytesCount + writtenVPSBytesCount)], pD3D12Enc->m_StagingHeadersBuffer.data(), writtenPPSBytesCount);
1094 pWrittenCodecUnitsSizes.push_back(writtenPPSBytesCount);
1095 } else {
1096 writtenPPSBytesCount = 0;
1097 debug_printf("Skipping PPS (same as active PPS) for fenceValue: %" PRIu64 "\n", pD3D12Enc->m_fenceValue);
1098 }
1099
1100 // Shrink buffer to fit the headers
1101 if (pD3D12Enc->m_BitstreamHeadersBuffer.size() > (writtenPPSBytesCount + writtenSPSBytesCount + writtenVPSBytesCount)) {
1102 pD3D12Enc->m_BitstreamHeadersBuffer.resize(writtenPPSBytesCount + writtenSPSBytesCount + writtenVPSBytesCount);
1103 }
1104
1105 assert(std::accumulate(pWrittenCodecUnitsSizes.begin(), pWrittenCodecUnitsSizes.end(), 0u) ==
1106 static_cast<uint64_t>(pD3D12Enc->m_BitstreamHeadersBuffer.size()));
1107 return pD3D12Enc->m_BitstreamHeadersBuffer.size();
1108 }
1109