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