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
32 void
d3d12_video_encoder_update_current_rate_control_h264(struct d3d12_video_encoder *pD3D12Enc, pipe_h264_enc_picture_desc *picture)33 d3d12_video_encoder_update_current_rate_control_h264(struct d3d12_video_encoder *pD3D12Enc,
34 pipe_h264_enc_picture_desc *picture)
35 {
36 auto previousConfig = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc;
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 switch (picture->rate_ctrl[0].rate_ctrl_method) {
46 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP:
47 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE:
48 {
49 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR;
50 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.TargetAvgBitRate =
51 picture->rate_ctrl[0].target_bitrate;
52 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.PeakBitRate =
53 picture->rate_ctrl[0].peak_bitrate;
54 } break;
55 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP:
56 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT:
57 {
58 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR;
59 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate =
60 picture->rate_ctrl[0].target_bitrate;
61
62 /* For CBR mode, to guarantee bitrate of generated stream complies with
63 * target bitrate (e.g. no over +/-10%), vbv_buffer_size should be same
64 * as target bitrate. Controlled by OS env var D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE
65 */
66 if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
67 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, "
68 ", forcing VBV Size = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate);
69 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
70 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
71 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity =
72 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate;
73 }
74
75 } break;
76 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_DISABLE:
77 {
78 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
79 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
80 .ConstantQP_FullIntracodedFrame = picture->quant_i_frames;
81 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
82 .ConstantQP_InterPredictedFrame_PrevRefOnly = picture->quant_p_frames;
83 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
84 .ConstantQP_InterPredictedFrame_BiDirectionalRef = picture->quant_b_frames;
85 } break;
86 default:
87 {
88 debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 invalid RC "
89 "config, using default RC CQP mode\n");
90 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
91 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
92 .ConstantQP_FullIntracodedFrame = 30;
93 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
94 .ConstantQP_InterPredictedFrame_PrevRefOnly = 30;
95 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
96 .ConstantQP_InterPredictedFrame_BiDirectionalRef = 30;
97 } break;
98 }
99
100 if (memcmp(&previousConfig,
101 &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc,
102 sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc)) != 0) {
103 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_rate_control;
104 }
105 }
106
107 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)108 d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video_encoder *pD3D12Enc,
109 struct pipe_video_buffer *srcTexture,
110 struct pipe_picture_desc *picture,
111 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &picParams,
112 bool &bUsedAsReference)
113 {
114 struct pipe_h264_enc_picture_desc *h264Pic = (struct pipe_h264_enc_picture_desc *) picture;
115 d3d12_video_bitstream_builder_h264 *pH264BitstreamBuilder =
116 static_cast<d3d12_video_bitstream_builder_h264 *>(pD3D12Enc->m_upBitstreamBuilder.get());
117 assert(pH264BitstreamBuilder != nullptr);
118
119 bUsedAsReference = !h264Pic->not_referenced;
120
121 picParams.pH264PicData->pic_parameter_set_id = pH264BitstreamBuilder->get_active_pps_id();
122 picParams.pH264PicData->idr_pic_id = h264Pic->idr_pic_id;
123 picParams.pH264PicData->FrameType = d3d12_video_encoder_convert_frame_type(h264Pic->picture_type);
124 picParams.pH264PicData->PictureOrderCountNumber = h264Pic->pic_order_cnt;
125 picParams.pH264PicData->FrameDecodingOrderNumber = h264Pic->frame_num;
126
127 picParams.pH264PicData->List0ReferenceFramesCount = 0;
128 picParams.pH264PicData->pList0ReferenceFrames = nullptr;
129 picParams.pH264PicData->List1ReferenceFramesCount = 0;
130 picParams.pH264PicData->pList1ReferenceFrames = nullptr;
131
132 if (picParams.pH264PicData->FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME) {
133 picParams.pH264PicData->List0ReferenceFramesCount = h264Pic->num_ref_idx_l0_active_minus1 + 1;
134 picParams.pH264PicData->pList0ReferenceFrames = h264Pic->ref_idx_l0_list;
135 } else if (picParams.pH264PicData->FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME) {
136 picParams.pH264PicData->List0ReferenceFramesCount = h264Pic->num_ref_idx_l0_active_minus1 + 1;
137 picParams.pH264PicData->pList0ReferenceFrames = h264Pic->ref_idx_l0_list;
138 picParams.pH264PicData->List1ReferenceFramesCount = h264Pic->num_ref_idx_l1_active_minus1 + 1;
139 picParams.pH264PicData->pList1ReferenceFrames = h264Pic->ref_idx_l1_list;
140 }
141 }
142
143 D3D12_VIDEO_ENCODER_FRAME_TYPE_H264
d3d12_video_encoder_convert_frame_type(enum pipe_h2645_enc_picture_type picType)144 d3d12_video_encoder_convert_frame_type(enum pipe_h2645_enc_picture_type picType)
145 {
146 switch (picType) {
147 case PIPE_H2645_ENC_PICTURE_TYPE_P:
148 {
149 return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME;
150 } break;
151 case PIPE_H2645_ENC_PICTURE_TYPE_B:
152 {
153 return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME;
154 } break;
155 case PIPE_H2645_ENC_PICTURE_TYPE_I:
156 {
157 return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME;
158 } break;
159 case PIPE_H2645_ENC_PICTURE_TYPE_IDR:
160 {
161 return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME;
162 } break;
163 default:
164 {
165 unreachable("Unsupported pipe_h2645_enc_picture_type");
166 } break;
167 }
168 }
169
170 ///
171 /// Tries to configurate the encoder using the requested slice configuration
172 /// or falls back to single slice encoding.
173 ///
174 bool
d3d12_video_encoder_negotiate_current_h264_slices_configuration(struct d3d12_video_encoder *pD3D12Enc, pipe_h264_enc_picture_desc *picture)175 d3d12_video_encoder_negotiate_current_h264_slices_configuration(struct d3d12_video_encoder *pD3D12Enc,
176 pipe_h264_enc_picture_desc *picture)
177 {
178 ///
179 /// Initialize single slice by default
180 ///
181 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode =
182 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
183 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES requestedSlicesConfig = {};
184 requestedSlicesConfig.NumberOfSlicesPerFrame = 1;
185
186 ///
187 /// Try to see if can accomodate for multi-slice request by user
188 ///
189 if (picture->num_slice_descriptors > 1) {
190 /* Last slice can be less for rounding frame size and leave some error for mb rounding */
191 bool bUniformSizeSlices = true;
192 const double rounding_delta = 1.0;
193 for (uint32_t sliceIdx = 1; (sliceIdx < picture->num_slice_descriptors - 1) && bUniformSizeSlices; sliceIdx++) {
194 int64_t curSlice = picture->slices_descriptors[sliceIdx].num_macroblocks;
195 int64_t prevSlice = picture->slices_descriptors[sliceIdx - 1].num_macroblocks;
196 bUniformSizeSlices = bUniformSizeSlices && (std::abs(curSlice - prevSlice) <= rounding_delta);
197 }
198
199 uint32_t mbPerScanline =
200 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width / D3D12_VIDEO_H264_MB_IN_PIXELS;
201 bool bSliceAligned = ((picture->slices_descriptors[0].num_macroblocks % mbPerScanline) == 0);
202
203 if (!bUniformSizeSlices &&
204 d3d12_video_encoder_check_subregion_mode_support(
205 pD3D12Enc,
206 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME)) {
207
208 if (D3D12_VIDEO_ENC_FALLBACK_SLICE_CONFIG) { // Check if fallback mode is enabled, or we should just fail
209 // without support
210 // Not supported to have custom slice sizes in D3D12 Video Encode fallback to uniform multi-slice
211 debug_printf(
212 "[d3d12_video_encoder_h264] WARNING: Requested slice control mode is not supported: All slices must "
213 "have the same number of macroblocks. Falling back to encoding uniform %d slices per frame.\n",
214 picture->num_slice_descriptors);
215 requestedSlicesMode =
216 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
217 requestedSlicesConfig.NumberOfSlicesPerFrame = picture->num_slice_descriptors;
218 debug_printf("[d3d12_video_encoder_h264] Using multi slice encoding mode: "
219 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
220 "with %d slices per frame.\n",
221 requestedSlicesConfig.NumberOfSlicesPerFrame);
222 } else {
223 debug_printf("[d3d12_video_encoder_h264] Requested slice control mode is not supported: All slices must "
224 "have the same number of macroblocks. To continue with uniform slices as a fallback, must "
225 "enable the OS environment variable D3D12_VIDEO_ENC_FALLBACK_SLICE_CONFIG");
226 return false;
227 }
228 } else if (bUniformSizeSlices && bSliceAligned &&
229 d3d12_video_encoder_check_subregion_mode_support(
230 pD3D12Enc,
231 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION)) {
232
233 // Number of macroblocks per slice is aligned to a scanline width, in which case we can
234 // use D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION
235 requestedSlicesMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION;
236 requestedSlicesConfig.NumberOfRowsPerSlice = (picture->slices_descriptors[0].num_macroblocks / mbPerScanline);
237 debug_printf("[d3d12_video_encoder_h264] Using multi slice encoding mode: "
238 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION with "
239 "%d macroblocks rows per slice.\n",
240 requestedSlicesConfig.NumberOfRowsPerSlice);
241 } else if (bUniformSizeSlices &&
242 d3d12_video_encoder_check_subregion_mode_support(
243 pD3D12Enc,
244 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME)) {
245 requestedSlicesMode =
246 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
247 requestedSlicesConfig.NumberOfSlicesPerFrame = picture->num_slice_descriptors;
248 debug_printf("[d3d12_video_encoder_h264] Using multi slice encoding mode: "
249 "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
250 "with %d slices per frame.\n",
251 requestedSlicesConfig.NumberOfSlicesPerFrame);
252 } else if (D3D12_VIDEO_ENC_FALLBACK_SLICE_CONFIG) { // Check if fallback mode is enabled, or we should just fail
253 // without support
254 // Fallback to single slice encoding (assigned by default when initializing variables requestedSlicesMode,
255 // requestedSlicesConfig)
256 debug_printf(
257 "[d3d12_video_encoder_h264] WARNING: Slice mode for %d slices with bUniformSizeSlices: %d - bSliceAligned "
258 "%d not supported by the D3D12 driver, falling back to encoding a single slice per frame.\n",
259 picture->num_slice_descriptors,
260 bUniformSizeSlices,
261 bSliceAligned);
262 } else {
263 debug_printf("[d3d12_video_encoder_h264] Requested slice control mode is not supported: All slices must "
264 "have the same number of macroblocks. To continue with uniform slices as a fallback, must "
265 "enable the OS environment variable D3D12_VIDEO_ENC_FALLBACK_SLICE_CONFIG");
266 return false;
267 }
268 }
269
270 if (!d3d12_video_encoder_compare_slice_config_h264_hevc(
271 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
272 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264,
273 requestedSlicesMode,
274 requestedSlicesConfig)) {
275 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_slices;
276 }
277
278 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264 = requestedSlicesConfig;
279 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode = requestedSlicesMode;
280
281 return true;
282 }
283
284 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)285 d3d12_video_encoder_convert_h264_motion_configuration(struct d3d12_video_encoder *pD3D12Enc,
286 pipe_h264_enc_picture_desc *picture)
287 {
288 return D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM;
289 }
290
291 D3D12_VIDEO_ENCODER_LEVELS_H264
d3d12_video_encoder_convert_level_h264(uint32_t h264SpecLevel)292 d3d12_video_encoder_convert_level_h264(uint32_t h264SpecLevel)
293 {
294 switch (h264SpecLevel) {
295 case 10:
296 {
297 return D3D12_VIDEO_ENCODER_LEVELS_H264_1;
298 } break;
299 case 11:
300 {
301 return D3D12_VIDEO_ENCODER_LEVELS_H264_11;
302 } break;
303 case 12:
304 {
305 return D3D12_VIDEO_ENCODER_LEVELS_H264_12;
306 } break;
307 case 13:
308 {
309 return D3D12_VIDEO_ENCODER_LEVELS_H264_13;
310 } break;
311 case 20:
312 {
313 return D3D12_VIDEO_ENCODER_LEVELS_H264_2;
314 } break;
315 case 21:
316 {
317 return D3D12_VIDEO_ENCODER_LEVELS_H264_21;
318 } break;
319 case 22:
320 {
321 return D3D12_VIDEO_ENCODER_LEVELS_H264_22;
322 } break;
323 case 30:
324 {
325 return D3D12_VIDEO_ENCODER_LEVELS_H264_3;
326 } break;
327 case 31:
328 {
329 return D3D12_VIDEO_ENCODER_LEVELS_H264_31;
330 } break;
331 case 32:
332 {
333 return D3D12_VIDEO_ENCODER_LEVELS_H264_32;
334 } break;
335 case 40:
336 {
337 return D3D12_VIDEO_ENCODER_LEVELS_H264_4;
338 } break;
339 case 41:
340 {
341 return D3D12_VIDEO_ENCODER_LEVELS_H264_41;
342 } break;
343 case 42:
344 {
345 return D3D12_VIDEO_ENCODER_LEVELS_H264_42;
346 } break;
347 case 50:
348 {
349 return D3D12_VIDEO_ENCODER_LEVELS_H264_5;
350 } break;
351 case 51:
352 {
353 return D3D12_VIDEO_ENCODER_LEVELS_H264_51;
354 } break;
355 case 52:
356 {
357 return D3D12_VIDEO_ENCODER_LEVELS_H264_52;
358 } break;
359 case 60:
360 {
361 return D3D12_VIDEO_ENCODER_LEVELS_H264_6;
362 } break;
363 case 61:
364 {
365 return D3D12_VIDEO_ENCODER_LEVELS_H264_61;
366 } break;
367 case 62:
368 {
369 return D3D12_VIDEO_ENCODER_LEVELS_H264_62;
370 } break;
371 default:
372 {
373 unreachable("Unsupported H264 level");
374 } break;
375 }
376 }
377
378 void
d3d12_video_encoder_convert_from_d3d12_level_h264(D3D12_VIDEO_ENCODER_LEVELS_H264 level12, uint32_t &specLevel, uint32_t &constraint_set3_flag)379 d3d12_video_encoder_convert_from_d3d12_level_h264(D3D12_VIDEO_ENCODER_LEVELS_H264 level12,
380 uint32_t &specLevel,
381 uint32_t &constraint_set3_flag)
382 {
383 specLevel = 0;
384 constraint_set3_flag = 0;
385
386 switch (level12) {
387 case D3D12_VIDEO_ENCODER_LEVELS_H264_1:
388 {
389 specLevel = 10;
390 } break;
391 case D3D12_VIDEO_ENCODER_LEVELS_H264_1b:
392 {
393 specLevel = 11;
394 constraint_set3_flag = 1;
395 } break;
396 case D3D12_VIDEO_ENCODER_LEVELS_H264_11:
397 {
398 specLevel = 11;
399 } break;
400 case D3D12_VIDEO_ENCODER_LEVELS_H264_12:
401 {
402 specLevel = 12;
403 } break;
404 case D3D12_VIDEO_ENCODER_LEVELS_H264_13:
405 {
406 specLevel = 13;
407 } break;
408 case D3D12_VIDEO_ENCODER_LEVELS_H264_2:
409 {
410 specLevel = 20;
411 } break;
412 case D3D12_VIDEO_ENCODER_LEVELS_H264_21:
413 {
414 specLevel = 21;
415 } break;
416 case D3D12_VIDEO_ENCODER_LEVELS_H264_22:
417 {
418 specLevel = 22;
419 } break;
420 case D3D12_VIDEO_ENCODER_LEVELS_H264_3:
421 {
422 specLevel = 30;
423 } break;
424 case D3D12_VIDEO_ENCODER_LEVELS_H264_31:
425 {
426 specLevel = 31;
427 } break;
428 case D3D12_VIDEO_ENCODER_LEVELS_H264_32:
429 {
430 specLevel = 32;
431 } break;
432 case D3D12_VIDEO_ENCODER_LEVELS_H264_4:
433 {
434 specLevel = 40;
435 } break;
436 case D3D12_VIDEO_ENCODER_LEVELS_H264_41:
437 {
438 specLevel = 41;
439 } break;
440 case D3D12_VIDEO_ENCODER_LEVELS_H264_42:
441 {
442 specLevel = 42;
443 } break;
444 case D3D12_VIDEO_ENCODER_LEVELS_H264_5:
445 {
446 specLevel = 50;
447 } break;
448 case D3D12_VIDEO_ENCODER_LEVELS_H264_51:
449 {
450 specLevel = 51;
451 } break;
452 case D3D12_VIDEO_ENCODER_LEVELS_H264_52:
453 {
454 specLevel = 52;
455 } break;
456 case D3D12_VIDEO_ENCODER_LEVELS_H264_6:
457 {
458 specLevel = 60;
459 } break;
460 case D3D12_VIDEO_ENCODER_LEVELS_H264_61:
461 {
462 specLevel = 61;
463 } break;
464 case D3D12_VIDEO_ENCODER_LEVELS_H264_62:
465 {
466 specLevel = 62;
467 } break;
468 default:
469 {
470 unreachable("Unsupported D3D12_VIDEO_ENCODER_LEVELS_H264 value");
471 } break;
472 }
473 }
474
475 bool
d3d12_video_encoder_update_h264_gop_configuration(struct d3d12_video_encoder *pD3D12Enc, pipe_h264_enc_picture_desc *picture)476 d3d12_video_encoder_update_h264_gop_configuration(struct d3d12_video_encoder *pD3D12Enc,
477 pipe_h264_enc_picture_desc *picture)
478 {
479 // Only update GOP when it begins
480 if (picture->gop_cnt == 1) {
481 uint32_t GOPCoeff = picture->i_remain;
482 uint32_t GOPLength = picture->gop_size / GOPCoeff;
483 uint32_t PPicturePeriod = std::ceil(GOPLength / (double) (picture->p_remain / GOPCoeff)) - 1;
484
485 if (picture->pic_order_cnt_type == 1u) {
486 debug_printf("[d3d12_video_encoder_h264] Upper layer is requesting pic_order_cnt_type %d but D3D12 Video "
487 "only supports pic_order_cnt_type = 0 or pic_order_cnt_type = 2\n",
488 picture->pic_order_cnt_type);
489 return false;
490 }
491
492 const uint32_t max_pic_order_cnt_lsb = 2 * GOPLength;
493 const uint32_t max_max_frame_num = GOPLength;
494 double log2_max_frame_num_minus4 = std::max(0.0, std::ceil(std::log2(max_max_frame_num)) - 4);
495 double log2_max_pic_order_cnt_lsb_minus4 = std::max(0.0, std::ceil(std::log2(max_pic_order_cnt_lsb)) - 4);
496 assert(log2_max_frame_num_minus4 < UCHAR_MAX);
497 assert(log2_max_pic_order_cnt_lsb_minus4 < UCHAR_MAX);
498 assert(picture->pic_order_cnt_type < UCHAR_MAX);
499
500 // Set dirty flag if m_H264GroupOfPictures changed
501 auto previousGOPConfig = pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures;
502 pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures = {
503 GOPLength,
504 PPicturePeriod,
505 static_cast<uint8_t>(picture->pic_order_cnt_type),
506 static_cast<uint8_t>(log2_max_frame_num_minus4),
507 static_cast<uint8_t>(log2_max_pic_order_cnt_lsb_minus4)
508 };
509
510 if (memcmp(&previousGOPConfig,
511 &pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures,
512 sizeof(D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_H264)) != 0) {
513 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_gop;
514 }
515 }
516 return true;
517 }
518
519 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264
520 d3d12_video_encoder_convert_h264_codec_configuration(struct d3d12_video_encoder *pD3D12Enc,
521 pipe_h264_enc_picture_desc *picture)
522 {
523 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 config = {
524 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_NONE,
525 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_DIRECT_MODES_DISABLED,
526 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_SLICES_DEBLOCKING_MODE_0_ALL_LUMA_CHROMA_SLICE_BLOCK_EDGES_ALWAYS_FILTERED,
527 };
528
529 if (picture->pic_ctrl.enc_cabac_enable) {
530 config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING;
531 }
532
533 return config;
534 }
535
536 bool
537 d3d12_video_encoder_update_current_encoder_config_state_h264(struct d3d12_video_encoder *pD3D12Enc,
538 struct pipe_video_buffer *srcTexture,
539 struct pipe_picture_desc *picture)
540 {
541 struct pipe_h264_enc_picture_desc *h264Pic = (struct pipe_h264_enc_picture_desc *) picture;
542
543 // Reset reconfig dirty flags
544 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags = d3d12_video_encoder_config_dirty_flag_none;
545 // Reset sequence changes flags
546 pD3D12Enc->m_currentEncodeConfig.m_seqFlags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE;
547
548 // Set codec
549 if (pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc != D3D12_VIDEO_ENCODER_CODEC_H264) {
550 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec;
551 }
552 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc = D3D12_VIDEO_ENCODER_CODEC_H264;
553
554 // Set input format
555 DXGI_FORMAT targetFmt = d3d12_convert_pipe_video_profile_to_dxgi_format(pD3D12Enc->base.profile);
556 if (pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format != targetFmt) {
557 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_input_format;
558 }
559
560 pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo = {};
561 pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format = targetFmt;
562 HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO,
563 &pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo,
564 sizeof(pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo));
565 if (FAILED(hr)) {
566 debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
567 return false;
568 }
569
570 // Set resolution
571 if ((pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width != srcTexture->width) ||
572 (pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height != srcTexture->height)) {
573 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_resolution;
574 }
575 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width = srcTexture->width;
576 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height = srcTexture->height;
577
578 // Set resolution codec dimensions (ie. cropping)
579 if (h264Pic->pic_ctrl.enc_frame_cropping_flag) {
580 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.left = h264Pic->pic_ctrl.enc_frame_crop_left_offset;
581 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.right = h264Pic->pic_ctrl.enc_frame_crop_right_offset;
582 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.top = h264Pic->pic_ctrl.enc_frame_crop_top_offset;
583 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.bottom =
584 h264Pic->pic_ctrl.enc_frame_crop_bottom_offset;
585 } else {
586 memset(&pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig,
587 0,
588 sizeof(pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig));
589 }
590
591 // Set profile
592 auto targetProfile = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(pD3D12Enc->base.profile);
593 if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile != targetProfile) {
594 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_profile;
595 }
596 pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile = targetProfile;
597
598 // Set level
599 auto targetLevel = d3d12_video_encoder_convert_level_h264(pD3D12Enc->base.level);
600 if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting != targetLevel) {
601 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_level;
602 }
603 pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting = targetLevel;
604
605 // Set codec config
606 auto targetCodecConfig = d3d12_video_encoder_convert_h264_codec_configuration(pD3D12Enc, h264Pic);
607 if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config,
608 &targetCodecConfig,
609 sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264)) != 0) {
610 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec_config;
611 }
612 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config = targetCodecConfig;
613
614 // Set rate control
615 d3d12_video_encoder_update_current_rate_control_h264(pD3D12Enc, h264Pic);
616
617 // Set slices config
618 if(!d3d12_video_encoder_negotiate_current_h264_slices_configuration(pD3D12Enc, h264Pic)) {
619 debug_printf("d3d12_video_encoder_negotiate_current_h264_slices_configuration failed!\n");
620 return false;
621 }
622
623 // Set GOP config
624 if(!d3d12_video_encoder_update_h264_gop_configuration(pD3D12Enc, h264Pic)) {
625 debug_printf("d3d12_video_encoder_update_h264_gop_configuration failed!\n");
626 return false;
627 }
628
629 // m_currentEncodeConfig.m_encoderPicParamsDesc pic params are set in d3d12_video_encoder_reconfigure_encoder_objects
630 // after re-allocating objects if needed
631
632 // Set motion estimation config
633 auto targetMotionLimit = d3d12_video_encoder_convert_h264_motion_configuration(pD3D12Enc, h264Pic);
634 if (pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit != targetMotionLimit) {
635 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |=
636 d3d12_video_encoder_config_dirty_flag_motion_precision_limit;
637 }
638 pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit = targetMotionLimit;
639
640 ///
641 /// Check for video encode support detailed capabilities
642 ///
643
644 // Will call for d3d12 driver support based on the initial requested features, then
645 // try to fallback if any of them is not supported and return the negotiated d3d12 settings
646 D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT capEncoderSupportData = {};
647 if (!d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(pD3D12Enc, capEncoderSupportData)) {
648 debug_printf("[d3d12_video_encoder_h264] After negotiating caps, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT "
649 "arguments are not supported - "
650 "ValidationFlags: 0x%x - SupportFlags: 0x%x\n",
651 capEncoderSupportData.ValidationFlags,
652 capEncoderSupportData.SupportFlags);
653 return false;
654 }
655
656 ///
657 // Calculate current settings based on the returned values from the caps query
658 //
659 pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput =
660 d3d12_video_encoder_calculate_max_slices_count_in_output(
661 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
662 &pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264,
663 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber,
664 pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
665 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize);
666
667 //
668 // Validate caps support returned values against current settings
669 //
670 if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile !=
671 pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_H264Profile) {
672 debug_printf("[d3d12_video_encoder_h264] Warning: Requested D3D12_VIDEO_ENCODER_PROFILE_H264 by upper layer: %d "
673 "mismatches UMD suggested D3D12_VIDEO_ENCODER_PROFILE_H264: %d\n",
674 pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile,
675 pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_H264Profile);
676 }
677
678 if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting !=
679 pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting) {
680 debug_printf("[d3d12_video_encoder_h264] Warning: Requested D3D12_VIDEO_ENCODER_LEVELS_H264 by upper layer: %d "
681 "mismatches UMD suggested D3D12_VIDEO_ENCODER_LEVELS_H264: %d\n",
682 pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting,
683 pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting);
684 }
685
686 if (pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput >
687 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber) {
688 debug_printf("[d3d12_video_encoder_h264] Desired number of subregions is not supported (higher than max "
689 "reported slice number in query caps)\n.");
690 return false;
691 }
692 return true;
693 }
694
695 D3D12_VIDEO_ENCODER_PROFILE_H264
696 d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(enum pipe_video_profile profile)
697 {
698 switch (profile) {
699 case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
700 case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
701 case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
702 {
703 return D3D12_VIDEO_ENCODER_PROFILE_H264_MAIN;
704
705 } break;
706 case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
707 {
708 return D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH;
709 } break;
710 case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
711 {
712 return D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH_10;
713 } break;
714 default:
715 {
716 unreachable("Unsupported pipe_video_profile");
717 } break;
718 }
719 }
720
721 D3D12_VIDEO_ENCODER_CODEC
722 d3d12_video_encoder_convert_codec_to_d3d12_enc_codec(enum pipe_video_profile profile)
723 {
724 switch (u_reduce_video_profile(profile)) {
725 case PIPE_VIDEO_FORMAT_MPEG4_AVC:
726 {
727 return D3D12_VIDEO_ENCODER_CODEC_H264;
728 } break;
729 case PIPE_VIDEO_FORMAT_HEVC:
730 {
731 return D3D12_VIDEO_ENCODER_CODEC_HEVC;
732 } break;
733 case PIPE_VIDEO_FORMAT_MPEG12:
734 case PIPE_VIDEO_FORMAT_MPEG4:
735 case PIPE_VIDEO_FORMAT_VC1:
736 case PIPE_VIDEO_FORMAT_JPEG:
737 case PIPE_VIDEO_FORMAT_VP9:
738 case PIPE_VIDEO_FORMAT_UNKNOWN:
739 default:
740 {
741 unreachable("Unsupported pipe_video_profile");
742 } break;
743 }
744 }
745
746 bool
747 d3d12_video_encoder_compare_slice_config_h264_hevc(
748 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE targetMode,
749 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES targetConfig,
750 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE otherMode,
751 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES otherConfig)
752 {
753 return (targetMode == otherMode) &&
754 (memcmp(&targetConfig,
755 &otherConfig,
756 sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES)) == 0);
757 }
758
759 uint32_t
760 d3d12_video_encoder_build_codec_headers_h264(struct d3d12_video_encoder *pD3D12Enc)
761 {
762 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams =
763 d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc);
764
765 auto profDesc = d3d12_video_encoder_get_current_profile_desc(pD3D12Enc);
766 auto levelDesc = d3d12_video_encoder_get_current_level_desc(pD3D12Enc);
767 auto codecConfigDesc = d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc);
768 auto MaxDPBCapacity = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc);
769
770 size_t writtenSPSBytesCount = 0;
771 bool isFirstFrame = (pD3D12Enc->m_fenceValue == 1);
772 bool writeNewSPS = isFirstFrame // on first frame
773 || ((pD3D12Enc->m_currentEncodeConfig.m_seqFlags & // also on resolution change
774 D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_RESOLUTION_CHANGE) != 0);
775
776 d3d12_video_bitstream_builder_h264 *pH264BitstreamBuilder =
777 static_cast<d3d12_video_bitstream_builder_h264 *>(pD3D12Enc->m_upBitstreamBuilder.get());
778 assert(pH264BitstreamBuilder);
779
780 uint32_t active_seq_parameter_set_id = pH264BitstreamBuilder->get_active_sps_id();
781
782 if (writeNewSPS) {
783 // For every new SPS for reconfiguration, increase the active_sps_id
784 if (!isFirstFrame) {
785 active_seq_parameter_set_id++;
786 pH264BitstreamBuilder->set_active_sps_id(active_seq_parameter_set_id);
787 }
788 pH264BitstreamBuilder->build_sps(*profDesc.pH264Profile,
789 *levelDesc.pH264LevelSetting,
790 pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
791 *codecConfigDesc.pH264Config,
792 pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures,
793 active_seq_parameter_set_id,
794 MaxDPBCapacity, // max_num_ref_frames
795 pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
796 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig,
797 pD3D12Enc->m_BitstreamHeadersBuffer,
798 pD3D12Enc->m_BitstreamHeadersBuffer.begin(),
799 writtenSPSBytesCount);
800 }
801
802 size_t writtenPPSBytesCount = 0;
803 pH264BitstreamBuilder->build_pps(*profDesc.pH264Profile,
804 *codecConfigDesc.pH264Config,
805 *currentPicParams.pH264PicData,
806 currentPicParams.pH264PicData->pic_parameter_set_id,
807 active_seq_parameter_set_id,
808 pD3D12Enc->m_BitstreamHeadersBuffer,
809 pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenSPSBytesCount,
810 writtenPPSBytesCount);
811
812 // Shrink buffer to fit the headers
813 if (pD3D12Enc->m_BitstreamHeadersBuffer.size() > (writtenPPSBytesCount + writtenSPSBytesCount)) {
814 pD3D12Enc->m_BitstreamHeadersBuffer.resize(writtenPPSBytesCount + writtenSPSBytesCount);
815 }
816
817 return pD3D12Enc->m_BitstreamHeadersBuffer.size();
818 }
819