• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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