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_h264.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_h264(struct d3d12_video_encoder * pD3D12Enc,pipe_h264_enc_picture_desc * picture)35 d3d12_video_encoder_update_current_rate_control_h264(struct d3d12_video_encoder *pD3D12Enc,
36 pipe_h264_enc_picture_desc *picture)
37 {
38 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc = {};
39 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_FrameRate.Numerator =
40 picture->rate_ctrl[0].frame_rate_num;
41 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_FrameRate.Denominator =
42 picture->rate_ctrl[0].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->rate_ctrl[0].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->rate_ctrl[0].target_bitrate;
56 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.PeakBitRate =
57 picture->rate_ctrl[0].peak_bitrate;
58
59 if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
60 debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 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->rate_ctrl[0].app_requested_hrd_buffer) {
69 debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 HRD required by app,"
70 " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rate_ctrl[0].vbv_buffer_size, picture->rate_ctrl[0].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->rate_ctrl[0].vbv_buffer_size;
75 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.InitialVBVFullness =
76 picture->rate_ctrl[0].vbv_buf_initial_size;
77 }
78
79 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.max_frame_size = picture->rate_ctrl[0].max_au_size;
80 if (picture->rate_ctrl[0].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->rate_ctrl[0].max_au_size;
85
86 debug_printf(
87 "[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
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->rate_ctrl[0].app_requested_qp_range) {
93 debug_printf(
94 "[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
95 "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
96 picture->rate_ctrl[0].min_qp, picture->rate_ctrl[0].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->rate_ctrl[0].min_qp;
101 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MaxQP =
102 picture->rate_ctrl[0].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->rate_ctrl[0].target_bitrate;
129 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.PeakBitRate =
130 picture->rate_ctrl[0].peak_bitrate;
131 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.ConstantQualityTarget =
132 picture->rate_ctrl[0].vbr_quality_factor;
133
134 if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
135 debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
136 ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate);
137 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
138 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
139 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
140 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
141 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.VBVCapacity =
142 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
143 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.InitialVBVFullness =
144 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
145 } else if (picture->rate_ctrl[0].app_requested_hrd_buffer) {
146 debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 HRD required by app,"
147 " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rate_ctrl[0].vbv_buffer_size, picture->rate_ctrl[0].vbv_buf_initial_size);
148 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
149 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
150 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
151 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
152 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.VBVCapacity =
153 picture->rate_ctrl[0].vbv_buffer_size;
154 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.InitialVBVFullness =
155 picture->rate_ctrl[0].vbv_buf_initial_size;
156 }
157 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.max_frame_size = picture->rate_ctrl[0].max_au_size;
158 if (picture->rate_ctrl[0].max_au_size > 0) {
159 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
160 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
161 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MaxFrameBitSize =
162 picture->rate_ctrl[0].max_au_size;
163
164 debug_printf(
165 "[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
166 "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
167 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MaxFrameBitSize);
168 }
169
170 if (picture->rate_ctrl[0].app_requested_qp_range) {
171 debug_printf(
172 "[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
173 "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
174 picture->rate_ctrl[0].min_qp, picture->rate_ctrl[0].max_qp);
175 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
176 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
177 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MinQP =
178 picture->rate_ctrl[0].min_qp;
179 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MaxQP =
180 picture->rate_ctrl[0].max_qp;
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 } break;
200 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP:
201 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT:
202 {
203 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR;
204 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate =
205 picture->rate_ctrl[0].target_bitrate;
206
207 /* For CBR mode, to guarantee bitrate of generated stream complies with
208 * target bitrate (e.g. no over +/-10%), vbv_buffer_size and initial capacity should be same
209 * as target bitrate. Controlled by OS env var D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE
210 */
211 if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
212 debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
213 ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate);
214 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
215 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
216 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity =
217 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate;
218 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.InitialVBVFullness =
219 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate;
220 } else if (picture->rate_ctrl[0].app_requested_hrd_buffer) {
221 debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 HRD required by app,"
222 " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rate_ctrl[0].vbv_buffer_size, picture->rate_ctrl[0].vbv_buf_initial_size);
223 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
224 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
225 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity =
226 picture->rate_ctrl[0].vbv_buffer_size;
227 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.InitialVBVFullness =
228 picture->rate_ctrl[0].vbv_buf_initial_size;
229 }
230
231 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.max_frame_size = picture->rate_ctrl[0].max_au_size;
232 if (picture->rate_ctrl[0].max_au_size > 0) {
233 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
234 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
235 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.MaxFrameBitSize =
236 picture->rate_ctrl[0].max_au_size;
237
238 debug_printf(
239 "[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
240 "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
241 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.MaxFrameBitSize);
242 }
243
244 if (picture->rate_ctrl[0].app_requested_qp_range) {
245 debug_printf(
246 "[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
247 "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
248 picture->rate_ctrl[0].min_qp, picture->rate_ctrl[0].max_qp);
249
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->rate_ctrl[0].min_qp;
254 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.MaxQP =
255 picture->rate_ctrl[0].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 } break;
276 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_DISABLE:
277 {
278 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
279 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
280 .ConstantQP_FullIntracodedFrame = picture->quant_i_frames;
281 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
282 .ConstantQP_InterPredictedFrame_PrevRefOnly = picture->quant_p_frames;
283 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
284 .ConstantQP_InterPredictedFrame_BiDirectionalRef = picture->quant_b_frames;
285 if (picture->quality_modes.level > 0) {
286 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
287 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
288 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
289 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
290
291 // Convert between D3D12 definition and PIPE definition
292 // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
293 // The lower the value, the fastest the encode operation
294 // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
295 // A lower value means higher quality, and a value of 1 represents the highest quality.
296 // The quality level setting is used as a trade-off between quality and speed/power
297 // consumption, with higher quality corresponds to lower speed and higher power consumption.
298
299 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP1.QualityVsSpeed =
300 pD3D12Enc->max_quality_levels - picture->quality_modes.level;
301 }
302 } break;
303 default:
304 {
305 debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 invalid RC "
306 "config, using default RC CQP mode\n");
307 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
308 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
309 .ConstantQP_FullIntracodedFrame = 30;
310 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
311 .ConstantQP_InterPredictedFrame_PrevRefOnly = 30;
312 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
313 .ConstantQP_InterPredictedFrame_BiDirectionalRef = 30;
314 } break;
315 }
316 }
317
318 void
d3d12_video_encoder_update_current_frame_pic_params_info_h264(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)319 d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video_encoder *pD3D12Enc,
320 struct pipe_video_buffer *srcTexture,
321 struct pipe_picture_desc *picture,
322 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &picParams,
323 bool &bUsedAsReference)
324 {
325 struct pipe_h264_enc_picture_desc *h264Pic = (struct pipe_h264_enc_picture_desc *) picture;
326 d3d12_video_bitstream_builder_h264 *pH264BitstreamBuilder =
327 static_cast<d3d12_video_bitstream_builder_h264 *>(pD3D12Enc->m_upBitstreamBuilder.get());
328 assert(pH264BitstreamBuilder != nullptr);
329
330 bUsedAsReference = !h264Pic->not_referenced;
331
332 picParams.pH264PicData->pic_parameter_set_id = pH264BitstreamBuilder->get_active_pps_id();
333 picParams.pH264PicData->idr_pic_id = h264Pic->idr_pic_id;
334 picParams.pH264PicData->FrameType = d3d12_video_encoder_convert_frame_type_h264(h264Pic->picture_type);
335 picParams.pH264PicData->PictureOrderCountNumber = h264Pic->pic_order_cnt;
336 picParams.pH264PicData->FrameDecodingOrderNumber = h264Pic->frame_num;
337
338 picParams.pH264PicData->List0ReferenceFramesCount = 0;
339 picParams.pH264PicData->pList0ReferenceFrames = nullptr;
340 picParams.pH264PicData->List1ReferenceFramesCount = 0;
341 picParams.pH264PicData->pList1ReferenceFrames = nullptr;
342
343 if (picParams.pH264PicData->FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME) {
344 picParams.pH264PicData->List0ReferenceFramesCount = h264Pic->num_ref_idx_l0_active_minus1 + 1;
345 picParams.pH264PicData->pList0ReferenceFrames = h264Pic->ref_idx_l0_list;
346 } else if (picParams.pH264PicData->FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME) {
347 picParams.pH264PicData->List0ReferenceFramesCount = h264Pic->num_ref_idx_l0_active_minus1 + 1;
348 picParams.pH264PicData->pList0ReferenceFrames = h264Pic->ref_idx_l0_list;
349 picParams.pH264PicData->List1ReferenceFramesCount = h264Pic->num_ref_idx_l1_active_minus1 + 1;
350 picParams.pH264PicData->pList1ReferenceFrames = h264Pic->ref_idx_l1_list;
351 }
352
353 if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0)
354 {
355 // Use 8 bit qpmap array for H264 picparams (-51, 51 range and int8_t pRateControlQPMap type)
356 const int32_t h264_min_delta_qp = -51;
357 const int32_t h264_max_delta_qp = 51;
358 d3d12_video_encoder_update_picparams_region_of_interest_qpmap(
359 pD3D12Enc,
360 &h264Pic->roi,
361 h264_min_delta_qp,
362 h264_max_delta_qp,
363 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap8Bit);
364 picParams.pH264PicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap8Bit.data();
365 picParams.pH264PicData->QPMapValuesCount = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap8Bit.size();
366 }
367 }
368
369 D3D12_VIDEO_ENCODER_FRAME_TYPE_H264
d3d12_video_encoder_convert_frame_type_h264(enum pipe_h2645_enc_picture_type picType)370 d3d12_video_encoder_convert_frame_type_h264(enum pipe_h2645_enc_picture_type picType)
371 {
372 switch (picType) {
373 case PIPE_H2645_ENC_PICTURE_TYPE_P:
374 {
375 return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME;
376 } break;
377 case PIPE_H2645_ENC_PICTURE_TYPE_B:
378 {
379 return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME;
380 } break;
381 case PIPE_H2645_ENC_PICTURE_TYPE_I:
382 {
383 return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME;
384 } break;
385 case PIPE_H2645_ENC_PICTURE_TYPE_IDR:
386 {
387 return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME;
388 } break;
389 default:
390 {
391 unreachable("Unsupported pipe_h2645_enc_picture_type");
392 } break;
393 }
394 }
395
396 ///
397 /// Tries to configurate the encoder using the requested slice configuration
398 /// or falls back to single slice encoding.
399 ///
400 bool
d3d12_video_encoder_negotiate_current_h264_slices_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h264_enc_picture_desc * picture)401 d3d12_video_encoder_negotiate_current_h264_slices_configuration(struct d3d12_video_encoder *pD3D12Enc,
402 pipe_h264_enc_picture_desc *picture)
403 {
404 ///
405 /// Initialize single slice by default
406 ///
407 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode =
408 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
409 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES requestedSlicesConfig = {};
410 requestedSlicesConfig.NumberOfSlicesPerFrame = 1;
411
412 ///
413 /// Try to see if can accomodate for multi-slice request by user
414 ///
415 if ((picture->slice_mode == PIPE_VIDEO_SLICE_MODE_BLOCKS) && (picture->num_slice_descriptors > 1)) {
416 /* Some apps send all same size slices minus 1 slice in any position in the descriptors */
417 /* Lets validate that there are at most 2 different slice sizes in all the descriptors */
418 std::vector<int> slice_sizes(picture->num_slice_descriptors);
419 for (uint32_t i = 0; i < picture->num_slice_descriptors; i++)
420 slice_sizes[i] = picture->slices_descriptors[i].num_macroblocks;
421 std::sort(slice_sizes.begin(), slice_sizes.end());
422 bool bUniformSizeSlices = (std::unique(slice_sizes.begin(), slice_sizes.end()) - slice_sizes.begin()) <= 2;
423
424 uint32_t mbPerScanline =
425 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width / D3D12_VIDEO_H264_MB_IN_PIXELS;
426 bool bSliceAligned = ((picture->slices_descriptors[0].num_macroblocks % mbPerScanline) == 0);
427
428 if (bUniformSizeSlices) {
429 if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_NONE) {
430 /*
431 * When intra-refresh is active, we must use D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME
432 */
433 if (d3d12_video_encoder_check_subregion_mode_support(
434 pD3D12Enc,
435 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME)) {
436 requestedSlicesMode =
437 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
438 requestedSlicesConfig.NumberOfSlicesPerFrame = picture->num_slice_descriptors;
439 debug_printf("[d3d12_video_encoder_h264] Intra-refresh is active and per DX12 spec it requires using multi slice encoding mode: "
440 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
441 "with %d slices per frame.\n",
442 requestedSlicesConfig.NumberOfSlicesPerFrame);
443 } else {
444 debug_printf("[d3d12_video_encoder_h264] Intra-refresh is active which requires "
445 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
446 "mode but there is HW support for such mode.\n");
447 return false;
448 }
449 } else if (bSliceAligned &&
450 d3d12_video_encoder_check_subregion_mode_support(
451 pD3D12Enc,
452 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION)) {
453
454 // Number of macroblocks per slice is aligned to a scanline width, in which case we can
455 // use D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION
456 requestedSlicesMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION;
457 requestedSlicesConfig.NumberOfRowsPerSlice = (picture->slices_descriptors[0].num_macroblocks / mbPerScanline);
458 debug_printf("[d3d12_video_encoder_h264] Using multi slice encoding mode: "
459 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION with "
460 "%d macroblocks rows per slice.\n",
461 requestedSlicesConfig.NumberOfRowsPerSlice);
462 } else if (d3d12_video_encoder_check_subregion_mode_support(
463 pD3D12Enc,
464 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME)) {
465 requestedSlicesMode =
466 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
467 requestedSlicesConfig.NumberOfSlicesPerFrame = picture->num_slice_descriptors;
468 debug_printf("[d3d12_video_encoder_h264] Using multi slice encoding mode: "
469 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
470 "with %d slices per frame.\n",
471 requestedSlicesConfig.NumberOfSlicesPerFrame);
472 } else if (d3d12_video_encoder_check_subregion_mode_support(
473 pD3D12Enc,
474 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED)) {
475 requestedSlicesMode =
476 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED;
477 requestedSlicesConfig.NumberOfCodingUnitsPerSlice = picture->slices_descriptors[0].num_macroblocks;
478 debug_printf("[d3d12_video_encoder_h264] Using multi slice encoding mode: "
479 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED "
480 "with %d NumberOfCodingUnitsPerSlice per frame.\n",
481 requestedSlicesConfig.NumberOfCodingUnitsPerSlice);
482 } else {
483 debug_printf("[d3d12_video_encoder_h264] Requested slice control mode is not supported by hardware: No HW support for "
484 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION or"
485 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME or"
486 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED.\n");
487 return false;
488 }
489 } else {
490 debug_printf("[d3d12_video_encoder_h264] 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_h264] 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_h264] Requested slice control mode is not supported: No HW support for "
508 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION.\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_h264] 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_compare_slice_config_h264_hevc(
519 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
520 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264,
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_H264 = 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_h264_motion_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h264_enc_picture_desc * picture)533 d3d12_video_encoder_convert_h264_motion_configuration(struct d3d12_video_encoder *pD3D12Enc,
534 pipe_h264_enc_picture_desc *picture)
535 {
536 return D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM;
537 }
538
539 D3D12_VIDEO_ENCODER_LEVELS_H264
d3d12_video_encoder_convert_level_h264(uint32_t h264SpecLevel)540 d3d12_video_encoder_convert_level_h264(uint32_t h264SpecLevel)
541 {
542 switch (h264SpecLevel) {
543 case 10:
544 {
545 return D3D12_VIDEO_ENCODER_LEVELS_H264_1;
546 } break;
547 case 11:
548 {
549 return D3D12_VIDEO_ENCODER_LEVELS_H264_11;
550 } break;
551 case 12:
552 {
553 return D3D12_VIDEO_ENCODER_LEVELS_H264_12;
554 } break;
555 case 13:
556 {
557 return D3D12_VIDEO_ENCODER_LEVELS_H264_13;
558 } break;
559 case 20:
560 {
561 return D3D12_VIDEO_ENCODER_LEVELS_H264_2;
562 } break;
563 case 21:
564 {
565 return D3D12_VIDEO_ENCODER_LEVELS_H264_21;
566 } break;
567 case 22:
568 {
569 return D3D12_VIDEO_ENCODER_LEVELS_H264_22;
570 } break;
571 case 30:
572 {
573 return D3D12_VIDEO_ENCODER_LEVELS_H264_3;
574 } break;
575 case 31:
576 {
577 return D3D12_VIDEO_ENCODER_LEVELS_H264_31;
578 } break;
579 case 32:
580 {
581 return D3D12_VIDEO_ENCODER_LEVELS_H264_32;
582 } break;
583 case 40:
584 {
585 return D3D12_VIDEO_ENCODER_LEVELS_H264_4;
586 } break;
587 case 41:
588 {
589 return D3D12_VIDEO_ENCODER_LEVELS_H264_41;
590 } break;
591 case 42:
592 {
593 return D3D12_VIDEO_ENCODER_LEVELS_H264_42;
594 } break;
595 case 50:
596 {
597 return D3D12_VIDEO_ENCODER_LEVELS_H264_5;
598 } break;
599 case 51:
600 {
601 return D3D12_VIDEO_ENCODER_LEVELS_H264_51;
602 } break;
603 case 52:
604 {
605 return D3D12_VIDEO_ENCODER_LEVELS_H264_52;
606 } break;
607 case 60:
608 {
609 return D3D12_VIDEO_ENCODER_LEVELS_H264_6;
610 } break;
611 case 61:
612 {
613 return D3D12_VIDEO_ENCODER_LEVELS_H264_61;
614 } break;
615 case 62:
616 {
617 return D3D12_VIDEO_ENCODER_LEVELS_H264_62;
618 } break;
619 default:
620 {
621 unreachable("Unsupported H264 level");
622 } break;
623 }
624 }
625
626 void
d3d12_video_encoder_convert_from_d3d12_level_h264(D3D12_VIDEO_ENCODER_LEVELS_H264 level12,uint32_t & specLevel)627 d3d12_video_encoder_convert_from_d3d12_level_h264(D3D12_VIDEO_ENCODER_LEVELS_H264 level12,
628 uint32_t &specLevel)
629 {
630 specLevel = 0;
631
632 switch (level12) {
633 case D3D12_VIDEO_ENCODER_LEVELS_H264_1:
634 {
635 specLevel = 10;
636 } break;
637 case D3D12_VIDEO_ENCODER_LEVELS_H264_1b:
638 {
639 specLevel = 11;
640 } break;
641 case D3D12_VIDEO_ENCODER_LEVELS_H264_11:
642 {
643 specLevel = 11;
644 } break;
645 case D3D12_VIDEO_ENCODER_LEVELS_H264_12:
646 {
647 specLevel = 12;
648 } break;
649 case D3D12_VIDEO_ENCODER_LEVELS_H264_13:
650 {
651 specLevel = 13;
652 } break;
653 case D3D12_VIDEO_ENCODER_LEVELS_H264_2:
654 {
655 specLevel = 20;
656 } break;
657 case D3D12_VIDEO_ENCODER_LEVELS_H264_21:
658 {
659 specLevel = 21;
660 } break;
661 case D3D12_VIDEO_ENCODER_LEVELS_H264_22:
662 {
663 specLevel = 22;
664 } break;
665 case D3D12_VIDEO_ENCODER_LEVELS_H264_3:
666 {
667 specLevel = 30;
668 } break;
669 case D3D12_VIDEO_ENCODER_LEVELS_H264_31:
670 {
671 specLevel = 31;
672 } break;
673 case D3D12_VIDEO_ENCODER_LEVELS_H264_32:
674 {
675 specLevel = 32;
676 } break;
677 case D3D12_VIDEO_ENCODER_LEVELS_H264_4:
678 {
679 specLevel = 40;
680 } break;
681 case D3D12_VIDEO_ENCODER_LEVELS_H264_41:
682 {
683 specLevel = 41;
684 } break;
685 case D3D12_VIDEO_ENCODER_LEVELS_H264_42:
686 {
687 specLevel = 42;
688 } break;
689 case D3D12_VIDEO_ENCODER_LEVELS_H264_5:
690 {
691 specLevel = 50;
692 } break;
693 case D3D12_VIDEO_ENCODER_LEVELS_H264_51:
694 {
695 specLevel = 51;
696 } break;
697 case D3D12_VIDEO_ENCODER_LEVELS_H264_52:
698 {
699 specLevel = 52;
700 } break;
701 case D3D12_VIDEO_ENCODER_LEVELS_H264_6:
702 {
703 specLevel = 60;
704 } break;
705 case D3D12_VIDEO_ENCODER_LEVELS_H264_61:
706 {
707 specLevel = 61;
708 } break;
709 case D3D12_VIDEO_ENCODER_LEVELS_H264_62:
710 {
711 specLevel = 62;
712 } break;
713 default:
714 {
715 unreachable("Unsupported D3D12_VIDEO_ENCODER_LEVELS_H264 value");
716 } break;
717 }
718 }
719
720 bool
d3d12_video_encoder_update_h264_gop_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h264_enc_picture_desc * picture)721 d3d12_video_encoder_update_h264_gop_configuration(struct d3d12_video_encoder *pD3D12Enc,
722 pipe_h264_enc_picture_desc *picture)
723 {
724 // Only update GOP when it begins
725 // Only update GOP when it begins
726 // This triggers DPB/encoder/heap re-creation, so only check on IDR when a GOP might change
727 if ((picture->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR)
728 || (picture->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_I)) {
729 uint32_t GOPLength = picture->intra_idr_period;
730 uint32_t PPicturePeriod = picture->ip_period;
731
732 if (picture->seq.pic_order_cnt_type == 1u) {
733 debug_printf("[d3d12_video_encoder_h264] Upper layer is requesting pic_order_cnt_type %d but D3D12 Video "
734 "only supports pic_order_cnt_type = 0 or pic_order_cnt_type = 2\n",
735 picture->seq.pic_order_cnt_type);
736 return false;
737 }
738
739 // Workaround: D3D12 needs to use the POC in the DPB to track reference frames
740 // even when there's no frame reordering (picture->seq.pic_order_cnt_type == 2)
741 // So in that case, derive an artificial log2_max_pic_order_cnt_lsb_minus4
742 // to avoid unexpected wrapping
743 if (picture->seq.pic_order_cnt_type == 2u) {
744 if (GOPLength == 0) // Use max frame num to wrap on infinite GOPs
745 GOPLength = 1 << (picture->seq.log2_max_frame_num_minus4 + 4);
746 const uint32_t max_pic_order_cnt_lsb = 2 * GOPLength;
747 picture->seq.log2_max_pic_order_cnt_lsb_minus4 = std::max(0.0, std::ceil(std::log2(max_pic_order_cnt_lsb)) - 4);
748 assert(picture->seq.log2_max_pic_order_cnt_lsb_minus4 < UCHAR_MAX);
749 }
750
751 assert(picture->seq.pic_order_cnt_type < UCHAR_MAX);
752
753 // Set dirty flag if m_H264GroupOfPictures changed
754 auto previousGOPConfig = pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures;
755 pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures = {
756 GOPLength,
757 PPicturePeriod,
758 static_cast<uint8_t>(picture->seq.pic_order_cnt_type),
759 static_cast<uint8_t>(picture->seq.log2_max_frame_num_minus4),
760 static_cast<uint8_t>(picture->seq.log2_max_pic_order_cnt_lsb_minus4)
761 };
762
763 if (memcmp(&previousGOPConfig,
764 &pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures,
765 sizeof(D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_H264)) != 0) {
766 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_gop;
767 }
768 }
769 return true;
770 }
771
772 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264
d3d12_video_encoder_convert_h264_codec_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h264_enc_picture_desc * picture,bool & is_supported)773 d3d12_video_encoder_convert_h264_codec_configuration(struct d3d12_video_encoder *pD3D12Enc,
774 pipe_h264_enc_picture_desc *picture,
775 bool &is_supported)
776 {
777 is_supported = true;
778 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 config = {
779 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_NONE,
780 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_DIRECT_MODES_DISABLED,
781 // Definition of D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_SLICES_DEBLOCKING_MODES matches disable_deblocking_filter_idc syntax
782 static_cast<D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_SLICES_DEBLOCKING_MODES>(picture->dbk.disable_deblocking_filter_idc),
783 };
784
785 if (picture->pic_ctrl.enc_cabac_enable) {
786 config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING;
787 }
788
789 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_H264CodecCaps =
790 {
791 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264_FLAG_NONE,
792 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_SLICES_DEBLOCKING_MODE_FLAG_NONE
793 };
794
795 D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = { };
796 capCodecConfigData.NodeIndex = pD3D12Enc->m_NodeIndex;
797 capCodecConfigData.Codec = D3D12_VIDEO_ENCODER_CODEC_H264;
798 D3D12_VIDEO_ENCODER_PROFILE_H264 prof = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(pD3D12Enc->base.profile);
799 capCodecConfigData.Profile.pH264Profile = &prof;
800 capCodecConfigData.Profile.DataSize = sizeof(prof);
801 capCodecConfigData.CodecSupportLimits.pH264Support = &pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_H264CodecCaps;
802 capCodecConfigData.CodecSupportLimits.DataSize = sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_H264CodecCaps);
803
804 if(FAILED(pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData))
805 || !capCodecConfigData.IsSupported))
806 {
807 debug_printf("D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT call failed.");
808 is_supported = false;
809 return config;
810 }
811
812 if(((1 << config.DisableDeblockingFilterConfig) & capCodecConfigData.CodecSupportLimits.pH264Support->DisableDeblockingFilterSupportedModes) == 0)
813 {
814 debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments not supported - DisableDeblockingFilterConfig (value %d) "
815 "not allowed by DisableDeblockingFilterSupportedModes 0x%x cap reporting.",
816 config.DisableDeblockingFilterConfig,
817 capCodecConfigData.CodecSupportLimits.pH264Support->DisableDeblockingFilterSupportedModes);
818 is_supported = false;
819 return config;
820 }
821
822 if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING) != 0)
823 && ((capCodecConfigData.CodecSupportLimits.pH264Support->SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264_FLAG_CABAC_ENCODING_SUPPORT) == 0))
824 {
825 debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - CABAC encoding mode not supported."
826 " Ignoring the request for this feature flag on this encode session");
827 // Disable it and keep going with a warning
828 config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING;
829 }
830
831 return config;
832 }
833
834 static bool
d3d12_video_encoder_update_intra_refresh_h264(struct d3d12_video_encoder * pD3D12Enc,D3D12_VIDEO_SAMPLE srcTextureDesc,struct pipe_h264_enc_picture_desc * picture)835 d3d12_video_encoder_update_intra_refresh_h264(struct d3d12_video_encoder *pD3D12Enc,
836 D3D12_VIDEO_SAMPLE srcTextureDesc,
837 struct pipe_h264_enc_picture_desc * picture)
838 {
839 if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_NONE)
840 {
841 // D3D12 only supports row intra-refresh
842 if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_UNIT_ROWS)
843 {
844 debug_printf("[d3d12_video_encoder_update_intra_refresh_h264] Unsupported INTRA_REFRESH_MODE %d\n", picture->intra_refresh.mode);
845 return false;
846 }
847
848 uint32_t total_frame_blocks = static_cast<uint32_t>(std::ceil(srcTextureDesc.Height / D3D12_VIDEO_H264_MB_IN_PIXELS)) *
849 static_cast<uint32_t>(std::ceil(srcTextureDesc.Width / D3D12_VIDEO_H264_MB_IN_PIXELS));
850 D3D12_VIDEO_ENCODER_INTRA_REFRESH targetIntraRefresh = {
851 D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ROW_BASED,
852 total_frame_blocks / picture->intra_refresh.region_size,
853 };
854 double ir_wave_progress = (picture->intra_refresh.offset == 0) ? 0 :
855 picture->intra_refresh.offset / (double) total_frame_blocks;
856 pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex =
857 static_cast<uint32_t>(std::ceil(ir_wave_progress * targetIntraRefresh.IntraRefreshDuration));
858
859 // Set intra refresh state
860 pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = targetIntraRefresh;
861 // Need to send the sequence flag during all the IR duration
862 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_intra_refresh;
863 } else {
864 pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex = 0;
865 pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = {
866 D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
867 0,
868 };
869 }
870
871 return true;
872 }
873
874 bool
d3d12_video_encoder_update_current_encoder_config_state_h264(struct d3d12_video_encoder * pD3D12Enc,D3D12_VIDEO_SAMPLE srcTextureDesc,struct pipe_picture_desc * picture)875 d3d12_video_encoder_update_current_encoder_config_state_h264(struct d3d12_video_encoder *pD3D12Enc,
876 D3D12_VIDEO_SAMPLE srcTextureDesc,
877 struct pipe_picture_desc *picture)
878 {
879 struct pipe_h264_enc_picture_desc *h264Pic = (struct pipe_h264_enc_picture_desc *) picture;
880
881 // Reset reconfig dirty flags
882 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags = d3d12_video_encoder_config_dirty_flag_none;
883 // Reset sequence changes flags
884 pD3D12Enc->m_currentEncodeConfig.m_seqFlags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE;
885
886 // Set codec
887 if (pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc != D3D12_VIDEO_ENCODER_CODEC_H264) {
888 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec;
889 }
890 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc = D3D12_VIDEO_ENCODER_CODEC_H264;
891
892 // Set Sequence information
893 if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH264,
894 &h264Pic->seq,
895 sizeof(h264Pic->seq)) != 0) {
896 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sequence_info;
897 }
898 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH264 = h264Pic->seq;
899
900 if ((h264Pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR) &&
901 (h264Pic->renew_headers_on_idr))
902 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sequence_info;
903
904 // Set input format
905 DXGI_FORMAT targetFmt = d3d12_convert_pipe_video_profile_to_dxgi_format(pD3D12Enc->base.profile);
906 if (pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format != targetFmt) {
907 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_input_format;
908 }
909
910 pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo = {};
911 pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format = targetFmt;
912 HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO,
913 &pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo,
914 sizeof(pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo));
915 if (FAILED(hr)) {
916 debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
917 return false;
918 }
919
920 // Set intra-refresh config
921 if(!d3d12_video_encoder_update_intra_refresh_h264(pD3D12Enc, srcTextureDesc, h264Pic)) {
922 debug_printf("d3d12_video_encoder_update_intra_refresh_h264 failed!\n");
923 return false;
924 }
925
926 // Set resolution
927 if ((pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width != srcTextureDesc.Width) ||
928 (pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height != srcTextureDesc.Height)) {
929 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_resolution;
930 }
931 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width = srcTextureDesc.Width;
932 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height = srcTextureDesc.Height;
933
934 // Set resolution codec dimensions (ie. cropping)
935 if (h264Pic->seq.enc_frame_cropping_flag) {
936 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.left = h264Pic->seq.enc_frame_crop_left_offset;
937 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.right = h264Pic->seq.enc_frame_crop_right_offset;
938 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.top = h264Pic->seq.enc_frame_crop_top_offset;
939 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.bottom =
940 h264Pic->seq.enc_frame_crop_bottom_offset;
941 } else {
942 memset(&pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig,
943 0,
944 sizeof(pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig));
945 }
946
947 // Set profile
948 auto targetProfile = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(pD3D12Enc->base.profile);
949 if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile != targetProfile) {
950 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_profile;
951 }
952 pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile = targetProfile;
953
954 // Set level
955 auto targetLevel = d3d12_video_encoder_convert_level_h264(pD3D12Enc->base.level);
956 if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting != targetLevel) {
957 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_level;
958 }
959 pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting = targetLevel;
960
961 // Set codec config
962 bool is_supported = false;
963 auto targetCodecConfig = d3d12_video_encoder_convert_h264_codec_configuration(pD3D12Enc, h264Pic, is_supported);
964 if (!is_supported) {
965 return false;
966 }
967
968 if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config,
969 &targetCodecConfig,
970 sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264)) != 0) {
971 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec_config;
972 }
973 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config = targetCodecConfig;
974
975 // Set rate control
976 d3d12_video_encoder_update_current_rate_control_h264(pD3D12Enc, h264Pic);
977
978 // Set slices config
979 if(!d3d12_video_encoder_negotiate_current_h264_slices_configuration(pD3D12Enc, h264Pic)) {
980 debug_printf("d3d12_video_encoder_negotiate_current_h264_slices_configuration failed!\n");
981 return false;
982 }
983
984 // Set GOP config
985 if(!d3d12_video_encoder_update_h264_gop_configuration(pD3D12Enc, h264Pic)) {
986 debug_printf("d3d12_video_encoder_update_h264_gop_configuration failed!\n");
987 return false;
988 }
989
990 // m_currentEncodeConfig.m_encoderPicParamsDesc pic params are set in d3d12_video_encoder_reconfigure_encoder_objects
991 // after re-allocating objects if needed
992
993 // Set motion estimation config
994 auto targetMotionLimit = d3d12_video_encoder_convert_h264_motion_configuration(pD3D12Enc, h264Pic);
995 if (pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit != targetMotionLimit) {
996 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |=
997 d3d12_video_encoder_config_dirty_flag_motion_precision_limit;
998 }
999 pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit = targetMotionLimit;
1000
1001 ///
1002 /// Check for video encode support detailed capabilities
1003 ///
1004
1005 // Will call for d3d12 driver support based on the initial requested features, then
1006 // try to fallback if any of them is not supported and return the negotiated d3d12 settings
1007 D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 capEncoderSupportData1 = {};
1008 if (!d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(pD3D12Enc, capEncoderSupportData1)) {
1009 debug_printf("[d3d12_video_encoder_h264] After negotiating caps, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1 "
1010 "arguments are not supported - "
1011 "ValidationFlags: 0x%x - SupportFlags: 0x%x\n",
1012 capEncoderSupportData1.ValidationFlags,
1013 capEncoderSupportData1.SupportFlags);
1014 return false;
1015 }
1016
1017 ///
1018 // Calculate current settings based on the returned values from the caps query
1019 //
1020 pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput =
1021 d3d12_video_encoder_calculate_max_slices_count_in_output(
1022 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
1023 &pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264,
1024 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber,
1025 pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
1026 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize);
1027
1028 //
1029 // Validate caps support returned values against current settings
1030 //
1031 if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile !=
1032 pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_H264Profile) {
1033 debug_printf("[d3d12_video_encoder_h264] Warning: Requested D3D12_VIDEO_ENCODER_PROFILE_H264 by upper layer: %d "
1034 "mismatches UMD suggested D3D12_VIDEO_ENCODER_PROFILE_H264: %d\n",
1035 pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile,
1036 pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_H264Profile);
1037 }
1038
1039 if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting !=
1040 pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting) {
1041 debug_printf("[d3d12_video_encoder_h264] Warning: Requested D3D12_VIDEO_ENCODER_LEVELS_H264 by upper layer: %d "
1042 "mismatches UMD suggested D3D12_VIDEO_ENCODER_LEVELS_H264: %d\n",
1043 pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting,
1044 pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting);
1045 }
1046
1047 if (pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput >
1048 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber) {
1049 debug_printf("[d3d12_video_encoder_h264] Desired number of subregions %d is not supported (higher than max "
1050 "reported slice number %d in query caps) for current resolution (%d, %d)\n.",
1051 pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput,
1052 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber,
1053 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width,
1054 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height);
1055 return false;
1056 }
1057 return true;
1058 }
1059
1060 D3D12_VIDEO_ENCODER_PROFILE_H264
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(enum pipe_video_profile profile)1061 d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(enum pipe_video_profile profile)
1062 {
1063 switch (profile) {
1064 case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
1065 case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
1066 {
1067 return D3D12_VIDEO_ENCODER_PROFILE_H264_MAIN;
1068
1069 } break;
1070 case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
1071 {
1072 return D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH;
1073 } break;
1074 case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
1075 {
1076 return D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH_10;
1077 } break;
1078 default:
1079 {
1080 unreachable("Unsupported pipe_video_profile");
1081 } break;
1082 }
1083 }
1084
1085 bool
d3d12_video_encoder_compare_slice_config_h264_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)1086 d3d12_video_encoder_compare_slice_config_h264_hevc(
1087 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE targetMode,
1088 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES targetConfig,
1089 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE otherMode,
1090 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES otherConfig)
1091 {
1092 return (targetMode == otherMode) &&
1093 (memcmp(&targetConfig,
1094 &otherConfig,
1095 sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES)) == 0);
1096 }
1097
1098 uint32_t
d3d12_video_encoder_build_codec_headers_h264(struct d3d12_video_encoder * pD3D12Enc,std::vector<uint64_t> & pWrittenCodecUnitsSizes)1099 d3d12_video_encoder_build_codec_headers_h264(struct d3d12_video_encoder *pD3D12Enc,
1100 std::vector<uint64_t> &pWrittenCodecUnitsSizes)
1101 {
1102 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams =
1103 d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc);
1104
1105 auto levelDesc = d3d12_video_encoder_get_current_level_desc(pD3D12Enc);
1106 auto codecConfigDesc = d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc);
1107 auto MaxDPBCapacity = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc);
1108
1109 d3d12_video_bitstream_builder_h264 *pH264BitstreamBuilder =
1110 static_cast<d3d12_video_bitstream_builder_h264 *>(pD3D12Enc->m_upBitstreamBuilder.get());
1111 assert(pH264BitstreamBuilder);
1112
1113 size_t writtenAUDBytesCount = 0;
1114 pWrittenCodecUnitsSizes.clear();
1115 if (pH264BitstreamBuilder->insert_aud_nalu_requested())
1116 {
1117 pH264BitstreamBuilder->write_aud(pD3D12Enc->m_BitstreamHeadersBuffer,
1118 pD3D12Enc->m_BitstreamHeadersBuffer.begin(),
1119 writtenAUDBytesCount);
1120 pWrittenCodecUnitsSizes.push_back(writtenAUDBytesCount);
1121 }
1122
1123 bool isFirstFrame = (pD3D12Enc->m_fenceValue == 1);
1124 bool writeNewSPS = isFirstFrame // on first frame
1125 || ((pD3D12Enc->m_currentEncodeConfig.m_seqFlags & // also on resolution change
1126 D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_RESOLUTION_CHANGE) != 0)
1127 // Also on input format dirty flag for new SPS, VUI etc
1128 || (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_sequence_info);
1129
1130 uint32_t active_seq_parameter_set_id = pH264BitstreamBuilder->get_active_sps_id();
1131
1132 size_t writtenSPSBytesCount = 0;
1133 if (writeNewSPS) {
1134 pH264BitstreamBuilder->build_sps(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH264,
1135 pD3D12Enc->base.profile,
1136 *levelDesc.pH264LevelSetting,
1137 pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
1138 *codecConfigDesc.pH264Config,
1139 pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures,
1140 active_seq_parameter_set_id,
1141 MaxDPBCapacity, // max_num_ref_frames
1142 pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
1143 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig,
1144 pD3D12Enc->m_BitstreamHeadersBuffer,
1145 pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenAUDBytesCount,
1146 writtenSPSBytesCount);
1147 pWrittenCodecUnitsSizes.push_back(writtenSPSBytesCount);
1148 }
1149
1150 size_t writtenPPSBytesCount = 0;
1151 pH264BitstreamBuilder->build_pps(pD3D12Enc->base.profile,
1152 *codecConfigDesc.pH264Config,
1153 *currentPicParams.pH264PicData,
1154 currentPicParams.pH264PicData->pic_parameter_set_id,
1155 active_seq_parameter_set_id,
1156 pD3D12Enc->m_StagingHeadersBuffer,
1157 pD3D12Enc->m_StagingHeadersBuffer.begin(),
1158 writtenPPSBytesCount);
1159
1160 std::vector<uint8_t>& active_pps = pH264BitstreamBuilder->get_active_pps();
1161 if (writeNewSPS ||
1162 (writtenPPSBytesCount != active_pps.size()) ||
1163 memcmp(pD3D12Enc->m_StagingHeadersBuffer.data(), active_pps.data(), writtenPPSBytesCount)) {
1164 active_pps = pD3D12Enc->m_StagingHeadersBuffer;
1165 pD3D12Enc->m_BitstreamHeadersBuffer.resize(writtenAUDBytesCount + writtenSPSBytesCount + writtenPPSBytesCount);
1166 memcpy(&pD3D12Enc->m_BitstreamHeadersBuffer.data()[writtenAUDBytesCount + writtenSPSBytesCount], pD3D12Enc->m_StagingHeadersBuffer.data(), writtenPPSBytesCount);
1167 pWrittenCodecUnitsSizes.push_back(writtenPPSBytesCount);
1168 } else {
1169 writtenPPSBytesCount = 0;
1170 debug_printf("Skipping PPS (same as active PPS) for fenceValue: %" PRIu64 "\n", pD3D12Enc->m_fenceValue);
1171 }
1172
1173 // Shrink buffer to fit the headers
1174 if (pD3D12Enc->m_BitstreamHeadersBuffer.size() > (writtenAUDBytesCount + writtenSPSBytesCount + writtenPPSBytesCount)) {
1175 pD3D12Enc->m_BitstreamHeadersBuffer.resize(writtenAUDBytesCount + writtenSPSBytesCount + writtenPPSBytesCount);
1176 }
1177
1178 assert(std::accumulate(pWrittenCodecUnitsSizes.begin(), pWrittenCodecUnitsSizes.end(), 0u) ==
1179 static_cast<uint64_t>(pD3D12Enc->m_BitstreamHeadersBuffer.size()));
1180 return pD3D12Enc->m_BitstreamHeadersBuffer.size();
1181 }
1182