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