• 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    assert(picture->pic.temporal_id < ARRAY_SIZE(pipe_h265_enc_picture_desc::rc));
39    assert(picture->pic.temporal_id < std::max(static_cast<uint8_t>(1u), pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH265.sps_max_sub_layers_minus1));
40    assert(picture->pic.temporal_id < ARRAY_SIZE(D3D12EncodeConfiguration::m_encoderRateControlDesc));
41 
42    struct D3D12EncodeRateControlState m_prevRCState = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id];
43    pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex = picture->pic.temporal_id;
44    pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id] = {};
45    pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_FrameRate.Numerator =
46       picture->rc[picture->pic.temporal_id].frame_rate_num;
47    pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_FrameRate.Denominator =
48       picture->rc[picture->pic.temporal_id].frame_rate_den;
49    pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
50 
51    if (picture->roi.num > 0)
52       pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
53          D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP;
54 
55    switch (picture->rc[picture->pic.temporal_id].rate_ctrl_method) {
56       case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP:
57       case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE:
58       {
59          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR;
60          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_VBR.TargetAvgBitRate =
61             picture->rc[picture->pic.temporal_id].target_bitrate;
62          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_VBR.PeakBitRate =
63             picture->rc[picture->pic.temporal_id].peak_bitrate;
64 
65          if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
66             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, "
67                        ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate);
68             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
69                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
70             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.VBVCapacity =
71                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate;
72             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.InitialVBVFullness =
73                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate;
74          } else if (picture->rc[picture->pic.temporal_id].app_requested_hrd_buffer) {
75             debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc HRD required by app,"
76                        " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rc[picture->pic.temporal_id].vbv_buffer_size, picture->rc[picture->pic.temporal_id].vbv_buf_initial_size);
77             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
78                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
79             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_VBR.VBVCapacity =
80                picture->rc[picture->pic.temporal_id].vbv_buffer_size;
81             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_VBR.InitialVBVFullness =
82                picture->rc[picture->pic.temporal_id].vbv_buf_initial_size;
83          }
84 
85          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].max_frame_size = picture->rc[picture->pic.temporal_id].max_au_size;
86          if (picture->rc[picture->pic.temporal_id].max_au_size > 0) {
87             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
88                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
89             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_VBR.MaxFrameBitSize =
90                picture->rc[picture->pic.temporal_id].max_au_size;
91 
92             debug_printf(
93                "[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
94                "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
95                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_VBR.MaxFrameBitSize);
96          }
97 
98          if (picture->rc[picture->pic.temporal_id].app_requested_qp_range) {
99             debug_printf(
100                "[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
101                "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
102                picture->rc[picture->pic.temporal_id].min_qp, picture->rc[picture->pic.temporal_id].max_qp);
103             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
104                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
105             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_VBR.MinQP =
106                picture->rc[picture->pic.temporal_id].min_qp;
107             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_VBR.MaxQP =
108                picture->rc[picture->pic.temporal_id].max_qp;
109          }
110 
111          if (picture->quality_modes.level > 0) {
112             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
113                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
114             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
115                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
116 
117             // Convert between D3D12 definition and PIPE definition
118             // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
119             // The lower the value, the fastest the encode operation
120             // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
121             // A lower value means higher quality, and a value of 1 represents the highest quality.
122             // The quality level setting is used as a trade-off between quality and speed/power
123             // consumption, with higher quality corresponds to lower speed and higher power consumption.
124 
125             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_VBR1.QualityVsSpeed =
126                pD3D12Enc->max_quality_levels - picture->quality_modes.level;
127          }
128 
129       } break;
130       case PIPE_H2645_ENC_RATE_CONTROL_METHOD_QUALITY_VARIABLE:
131       {
132          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR;
133          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR.TargetAvgBitRate =
134             picture->rc[picture->pic.temporal_id].target_bitrate;
135          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR.PeakBitRate =
136             picture->rc[picture->pic.temporal_id].peak_bitrate;
137             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR.ConstantQualityTarget =
138             picture->rc[picture->pic.temporal_id].vbr_quality_factor;
139          if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
140             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, "
141                        ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR1.TargetAvgBitRate);
142             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
143                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
144             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
145                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
146             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR1.VBVCapacity =
147                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
148             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR1.InitialVBVFullness =
149                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
150          } else if (picture->rc[picture->pic.temporal_id].app_requested_hrd_buffer) {
151             debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc HRD required by app,"
152                        " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rc[picture->pic.temporal_id].vbv_buffer_size, picture->rc[picture->pic.temporal_id].vbv_buf_initial_size);
153             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
154                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
155             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
156                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
157             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR1.VBVCapacity =
158                picture->rc[picture->pic.temporal_id].vbv_buffer_size;
159             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR1.InitialVBVFullness =
160                picture->rc[picture->pic.temporal_id].vbv_buf_initial_size;
161          }
162          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].max_frame_size = picture->rc[picture->pic.temporal_id].max_au_size;
163          if (picture->rc[picture->pic.temporal_id].max_au_size > 0) {
164             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
165                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
166             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR.MaxFrameBitSize =
167                picture->rc[picture->pic.temporal_id].max_au_size;
168 
169             debug_printf(
170                "[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
171                "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
172                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR.MaxFrameBitSize);
173          }
174 
175          if (picture->rc[picture->pic.temporal_id].app_requested_qp_range) {
176             debug_printf(
177                "[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
178                "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
179                picture->rc[picture->pic.temporal_id].min_qp, picture->rc[picture->pic.temporal_id].max_qp);
180             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
181                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
182             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR.MinQP =
183                picture->rc[picture->pic.temporal_id].min_qp;
184             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR.MaxQP =
185                picture->rc[picture->pic.temporal_id].max_qp;
186          }
187 
188          if (picture->quality_modes.level > 0) {
189             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
190                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
191             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
192                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
193 
194             // Convert between D3D12 definition and PIPE definition
195             // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
196             // The lower the value, the fastest the encode operation
197             // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
198             // A lower value means higher quality, and a value of 1 represents the highest quality.
199             // The quality level setting is used as a trade-off between quality and speed/power
200             // consumption, with higher quality corresponds to lower speed and higher power consumption.
201 
202             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_QVBR1.QualityVsSpeed =
203                pD3D12Enc->max_quality_levels - picture->quality_modes.level;
204          }
205 
206       } break;
207       case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP:
208       case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT:
209       {
210          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR;
211          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate =
212             picture->rc[picture->pic.temporal_id].target_bitrate;
213 
214          /* For CBR mode, to guarantee bitrate of generated stream complies with
215           * target bitrate (e.g. no over +/-10%), vbv_buffer_size and initial capacity should be same
216           * as target bitrate. Controlled by OS env var D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE
217           */
218          if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
219             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, "
220                        ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate);
221             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
222                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
223             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.VBVCapacity =
224                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate;
225             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.InitialVBVFullness =
226                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate;
227          } else if (picture->rc[picture->pic.temporal_id].app_requested_hrd_buffer) {
228             debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc HRD required by app,"
229                        " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rc[picture->pic.temporal_id].vbv_buffer_size, picture->rc[picture->pic.temporal_id].vbv_buf_initial_size);
230             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
231                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
232             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.VBVCapacity =
233                picture->rc[picture->pic.temporal_id].vbv_buffer_size;
234             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.InitialVBVFullness =
235                picture->rc[picture->pic.temporal_id].vbv_buf_initial_size;
236          }
237 
238          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].max_frame_size = picture->rc[picture->pic.temporal_id].max_au_size;
239          if (picture->rc[picture->pic.temporal_id].max_au_size > 0) {
240             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
241                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
242             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.MaxFrameBitSize =
243                picture->rc[picture->pic.temporal_id].max_au_size;
244 
245             debug_printf(
246                "[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
247                "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
248                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.MaxFrameBitSize);
249          }
250 
251          if (picture->rc[picture->pic.temporal_id].app_requested_qp_range) {
252             debug_printf(
253                "[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
254                "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
255                picture->rc[picture->pic.temporal_id].min_qp, picture->rc[picture->pic.temporal_id].max_qp);
256             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
257                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
258             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.MinQP =
259                picture->rc[picture->pic.temporal_id].min_qp;
260             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR.MaxQP =
261                picture->rc[picture->pic.temporal_id].max_qp;
262          }
263 
264          if (picture->quality_modes.level > 0) {
265             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
266                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
267             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
268                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
269 
270             // Convert between D3D12 definition and PIPE definition
271             // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
272             // The lower the value, the fastest the encode operation
273             // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
274             // A lower value means higher quality, and a value of 1 represents the highest quality.
275             // The quality level setting is used as a trade-off between quality and speed/power
276             // consumption, with higher quality corresponds to lower speed and higher power consumption.
277 
278             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CBR1.QualityVsSpeed =
279                pD3D12Enc->max_quality_levels - picture->quality_modes.level;
280          }
281 
282       } break;
283       case PIPE_H2645_ENC_RATE_CONTROL_METHOD_DISABLE:
284       {
285          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
286          // Load previous RC state for all frames and only update the current frame
287          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CQP =
288                   m_prevRCState.m_Config.m_Configuration_CQP;
289          switch (picture->picture_type) {
290             case PIPE_H2645_ENC_PICTURE_TYPE_P:
291             {
292                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CQP
293                   .ConstantQP_InterPredictedFrame_PrevRefOnly = picture->rc[picture->pic.temporal_id].quant_p_frames;
294             } break;
295             case PIPE_H2645_ENC_PICTURE_TYPE_B:
296             {
297                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CQP
298                   .ConstantQP_InterPredictedFrame_BiDirectionalRef = picture->rc[picture->pic.temporal_id].quant_b_frames;
299             } break;
300             case PIPE_H2645_ENC_PICTURE_TYPE_I:
301             case PIPE_H2645_ENC_PICTURE_TYPE_IDR:
302             {
303                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CQP
304                   .ConstantQP_FullIntracodedFrame = picture->rc[picture->pic.temporal_id].quant_i_frames;
305             } break;
306             default:
307             {
308                unreachable("Unsupported pipe_h2645_enc_picture_type");
309             } break;
310          }
311 
312          if (picture->quality_modes.level > 0) {
313             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
314                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
315             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |=
316                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
317 
318             // Convert between D3D12 definition and PIPE definition
319             // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
320             // The lower the value, the fastest the encode operation
321             // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
322             // A lower value means higher quality, and a value of 1 represents the highest quality.
323             // The quality level setting is used as a trade-off between quality and speed/power
324             // consumption, with higher quality corresponds to lower speed and higher power consumption.
325 
326             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CQP1.QualityVsSpeed =
327                pD3D12Enc->max_quality_levels - picture->quality_modes.level;
328          }
329       } break;
330       default:
331       {
332          debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc invalid RC "
333                        "config, using default RC CQP mode\n");
334          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
335          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CQP
336             .ConstantQP_FullIntracodedFrame = 30;
337          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CQP
338             .ConstantQP_InterPredictedFrame_PrevRefOnly = 30;
339          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Config.m_Configuration_CQP
340             .ConstantQP_InterPredictedFrame_BiDirectionalRef = 30;
341       } break;
342    }
343 }
344 
345 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)346 d3d12_video_encoder_update_current_frame_pic_params_info_hevc(struct d3d12_video_encoder *pD3D12Enc,
347                                                               struct pipe_video_buffer *srcTexture,
348                                                               struct pipe_picture_desc *picture,
349                                                               D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &picParams,
350                                                               bool &bUsedAsReference)
351 {
352    struct pipe_h265_enc_picture_desc *hevcPic = (struct pipe_h265_enc_picture_desc *) picture;
353    d3d12_video_bitstream_builder_hevc *pHEVCBitstreamBuilder =
354       static_cast<d3d12_video_bitstream_builder_hevc *>(pD3D12Enc->m_upBitstreamBuilder.get());
355    assert(pHEVCBitstreamBuilder != nullptr);
356 
357    pD3D12Enc->m_currentEncodeConfig.m_bUsedAsReference = !hevcPic->not_referenced;
358    bUsedAsReference = pD3D12Enc->m_currentEncodeConfig.m_bUsedAsReference;
359 
360    if (pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags &
361        D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NUM_REF_IDX_ACTIVE_OVERRIDE_FLAG_SLICE_SUPPORT)
362    {
363       picParams.pHEVCPicData->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_REQUEST_NUM_REF_IDX_ACTIVE_OVERRIDE_FLAG_SLICE;
364    }
365 
366    if (hevcPic->base.profile == PIPE_VIDEO_PROFILE_HEVC_MAIN_444)
367    {
368       assert(picParams.DataSize == sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1));
369 
370       //
371       // Copy from pipe params
372       //
373       {
374          picParams.pHEVCPicData1->diff_cu_chroma_qp_offset_depth = static_cast<UCHAR>(hevcPic->pic.pps_range_extension.diff_cu_chroma_qp_offset_depth);
375          picParams.pHEVCPicData1->log2_sao_offset_scale_luma = static_cast<UCHAR>(hevcPic->pic.pps_range_extension.log2_sao_offset_scale_luma);
376          picParams.pHEVCPicData1->log2_sao_offset_scale_chroma = static_cast<UCHAR>(hevcPic->pic.pps_range_extension.log2_sao_offset_scale_chroma);
377          picParams.pHEVCPicData1->log2_max_transform_skip_block_size_minus2 = static_cast<CHAR>(hevcPic->pic.pps_range_extension.log2_max_transform_skip_block_size_minus2);
378          picParams.pHEVCPicData1->chroma_qp_offset_list_len_minus1 = static_cast<CHAR>(hevcPic->pic.pps_range_extension.chroma_qp_offset_list_len_minus1);
379 
380          for (uint32_t i = 0; i < ARRAY_SIZE(picParams.pHEVCPicData1->cb_qp_offset_list) ; i++)
381          {
382             picParams.pHEVCPicData1->cb_qp_offset_list[i] = static_cast<CHAR>(hevcPic->pic.pps_range_extension.cb_qp_offset_list[i]);
383             picParams.pHEVCPicData1->cr_qp_offset_list[i] = static_cast<CHAR>(hevcPic->pic.pps_range_extension.cr_qp_offset_list[i]);
384          }
385 
386          if (hevcPic->pic.pps_range_extension.cross_component_prediction_enabled_flag)
387             picParams.pHEVCPicData1->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CROSS_COMPONENT_PREDICTION;
388 
389          if (hevcPic->pic.pps_range_extension.chroma_qp_offset_list_enabled_flag)
390             picParams.pHEVCPicData1->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CHROMA_QP_OFFSET_LIST;
391       }
392 
393       //
394       // Validate caps from copied params
395       //
396 
397       // Check for support of value with: (allowed_diff_cu_chroma_qp_offset_depth_values & (1 << value) != 0)
398       if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.allowed_diff_cu_chroma_qp_offset_depth_values & (1 << picParams.pHEVCPicData1->diff_cu_chroma_qp_offset_depth)) == 0)
399       {
400          debug_printf("D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 arguments are not supported - diff_cu_chroma_qp_offset_depth %d is not supported.\n", picParams.pHEVCPicData1->diff_cu_chroma_qp_offset_depth);
401          assert(false);
402       }
403 
404       if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.allowed_log2_sao_offset_scale_luma_values & (1 << picParams.pHEVCPicData1->log2_sao_offset_scale_luma)) == 0)
405       {
406          debug_printf("D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 arguments are not supported - log2_sao_offset_scale_luma %d is not supported.\n", picParams.pHEVCPicData1->log2_sao_offset_scale_luma);
407          assert(false);
408       }
409 
410       if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.allowed_log2_sao_offset_scale_chroma_values & (1 << picParams.pHEVCPicData1->log2_sao_offset_scale_chroma)) == 0)
411       {
412          debug_printf("D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 arguments are not supported - log2_sao_offset_scale_chroma %d is not supported.\n", picParams.pHEVCPicData1->log2_sao_offset_scale_chroma);
413          assert(false);
414       }
415 
416       if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.allowed_log2_max_transform_skip_block_size_minus2_values & (1 << picParams.pHEVCPicData1->log2_max_transform_skip_block_size_minus2)) == 0)
417       {
418          debug_printf("D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 arguments are not supported - log2_max_transform_skip_block_size_minus2 %d is not supported.\n", picParams.pHEVCPicData1->log2_max_transform_skip_block_size_minus2);
419          assert(false);
420       }
421 
422       if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.allowed_chroma_qp_offset_list_len_minus1_values & (1 << picParams.pHEVCPicData1->chroma_qp_offset_list_len_minus1)) == 0)
423       {
424          debug_printf("D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 arguments are not supported - chroma_qp_offset_list_len_minus1 %d is not supported.\n", picParams.pHEVCPicData1->chroma_qp_offset_list_len_minus1);
425          assert(false);
426       }
427 
428       if(((picParams.pHEVCPicData1->Flags & D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CROSS_COMPONENT_PREDICTION) != 0)
429             && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CROSS_COMPONENT_PREDICTION_ENABLED_FLAG_SUPPORT) == 0))
430       {
431             debug_printf("D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 arguments are not supported - D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CROSS_COMPONENT_PREDICTION is not supported."
432             " Ignoring the request for this feature flag on this encode session\n");
433             // Disable it and keep going with a warning
434             picParams.pHEVCPicData1->Flags &= ~D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CROSS_COMPONENT_PREDICTION;
435       }
436 
437       if(((picParams.pHEVCPicData1->Flags & D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CROSS_COMPONENT_PREDICTION) == 0)
438             && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CROSS_COMPONENT_PREDICTION_ENABLED_FLAG_REQUIRED) != 0))
439       {
440             debug_printf("D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 arguments are not supported - D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CROSS_COMPONENT_PREDICTION is required to be set."
441             " Enabling this HW required feature flag on this encode session\n");
442             // HW doesn't support otherwise, so set it
443             picParams.pHEVCPicData1->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CROSS_COMPONENT_PREDICTION;
444       }
445 
446       if(((picParams.pHEVCPicData1->Flags & D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CHROMA_QP_OFFSET_LIST) != 0)
447             && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CHROMA_QP_OFFSET_LIST_ENABLED_FLAG_SUPPORT) == 0))
448       {
449             debug_printf("D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 arguments are not supported - D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CHROMA_QP_OFFSET_LIST is not supported."
450             " Ignoring the request for this feature flag on this encode session\n");
451             // Disable it and keep going with a warning
452             picParams.pHEVCPicData1->Flags &= ~D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CHROMA_QP_OFFSET_LIST;
453       }
454 
455       if(((picParams.pHEVCPicData1->Flags & D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CHROMA_QP_OFFSET_LIST) == 0)
456             && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CHROMA_QP_OFFSET_LIST_ENABLED_FLAG_REQUIRED) != 0))
457       {
458             debug_printf("D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 arguments are not supported - D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CHROMA_QP_OFFSET_LIST is required to be set."
459             " Enabling this HW required feature flag on this encode session\n");
460             // HW doesn't support otherwise, so set it
461             picParams.pHEVCPicData1->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CHROMA_QP_OFFSET_LIST;
462       }
463    }
464 
465    picParams.pHEVCPicData->slice_pic_parameter_set_id = pHEVCBitstreamBuilder->get_active_pps().pps_pic_parameter_set_id;
466 
467    //
468    // These need to be set here so they're available for SPS/PPS header building (reference manager updates after that, for slice header params)
469    //
470    picParams.pHEVCPicData->TemporalLayerIndex = hevcPic->pic.temporal_id;
471    picParams.pHEVCPicData->List0ReferenceFramesCount = 0;
472    picParams.pHEVCPicData->List1ReferenceFramesCount = 0;
473    if ((hevcPic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_P) ||
474        (hevcPic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B))
475       picParams.pHEVCPicData->List0ReferenceFramesCount = hevcPic->num_ref_idx_l0_active_minus1 + 1;
476    if (hevcPic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B)
477       picParams.pHEVCPicData->List1ReferenceFramesCount = hevcPic->num_ref_idx_l1_active_minus1 + 1;
478 
479    if ((pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig.ConfigurationFlags
480       & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES) != 0)
481       picParams.pHEVCPicData->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_REQUEST_INTRA_CONSTRAINED_SLICES;
482 
483    if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0)
484    {
485       // Use 8 bit qpmap array for HEVC picparams (-51, 51 range and int8_t pRateControlQPMap type)
486       const int32_t hevc_min_delta_qp = -51;
487       const int32_t hevc_max_delta_qp = 51;
488       d3d12_video_encoder_update_picparams_region_of_interest_qpmap(
489          pD3D12Enc,
490          &hevcPic->roi,
491          hevc_min_delta_qp,
492          hevc_max_delta_qp,
493          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_pRateControlQPMap8Bit);
494       picParams.pHEVCPicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_pRateControlQPMap8Bit.data();
495       picParams.pHEVCPicData->QPMapValuesCount = static_cast<UINT>(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_pRateControlQPMap8Bit.size());
496    }
497 
498    pD3D12Enc->m_upDPBManager->begin_frame(picParams, bUsedAsReference, picture);
499    pD3D12Enc->m_upDPBManager->get_current_frame_picture_control_data(picParams);
500 
501    // Save state snapshot from record time to resolve headers at get_feedback time
502    size_t current_metadata_slot = static_cast<size_t>(pD3D12Enc->m_fenceValue % D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT);
503    pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeCapabilities =
504       pD3D12Enc->m_currentEncodeCapabilities;
505    pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig =
506       pD3D12Enc->m_currentEncodeConfig;
507 }
508 
509 ///
510 /// Tries to configurate the encoder using the requested slice configuration
511 /// or falls back to single slice encoding.
512 ///
513 bool
d3d12_video_encoder_negotiate_current_hevc_slices_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h265_enc_picture_desc * picture)514 d3d12_video_encoder_negotiate_current_hevc_slices_configuration(struct d3d12_video_encoder *pD3D12Enc,
515                                                                 pipe_h265_enc_picture_desc *picture)
516 {
517    ///
518    /// Initialize single slice by default
519    ///
520    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode =
521       D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
522    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES requestedSlicesConfig = {};
523    requestedSlicesConfig.NumberOfSlicesPerFrame = 1;
524 
525    ///
526    /// Try to see if can accomodate for multi-slice request by user
527    ///
528    if ((picture->slice_mode == PIPE_VIDEO_SLICE_MODE_BLOCKS) && (picture->num_slice_descriptors > 1)) {
529       /* Some apps send all same size slices minus 1 slice in any position in the descriptors */
530       /* Lets validate that there are at most 2 different slice sizes in all the descriptors */
531       std::vector<int> slice_sizes(picture->num_slice_descriptors);
532       for (uint32_t i = 0; i < picture->num_slice_descriptors; i++)
533          slice_sizes[i] = picture->slices_descriptors[i].num_ctu_in_slice;
534       std::sort(slice_sizes.begin(), slice_sizes.end());
535       bool bUniformSizeSlices = (std::unique(slice_sizes.begin(), slice_sizes.end()) - slice_sizes.begin()) <= 2;
536 
537       uint32_t subregion_block_pixel_size = pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize;
538       uint32_t num_subregions_per_scanline =
539          DIV_ROUND_UP(pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width, subregion_block_pixel_size);
540 
541       /* m_currentResolutionSupportCaps.SubregionBlockPixelsSize can be a multiple of MinCUSize to accomodate for HW requirements
542          So, if the allowed subregion (slice) pixel size partition is bigger (a multiple) than the CTU size, we have to adjust
543          num_subregions_per_slice by this factor respect from slices_descriptors[X].num_ctu_in_slice
544       */
545 
546       /* This assert should always be true according to the spec
547          https://github.com/microsoft/DirectX-Specs/blob/master/d3d/D3D12VideoEncoding.md#3150-struct-d3d12_feature_data_video_encoder_resolution_support_limits
548        */
549       uint8_t minCUSize = d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig.MinLumaCodingUnitSize);
550       assert((pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize
551          % minCUSize) == 0);
552 
553       uint32_t subregionsize_to_ctu_factor = pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize /
554          minCUSize;
555       uint32_t num_subregions_per_slice = picture->slices_descriptors[0].num_ctu_in_slice
556                                                    * pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize
557                                                    / (subregionsize_to_ctu_factor * subregionsize_to_ctu_factor);
558 
559       bool bSliceAligned = ((num_subregions_per_slice % num_subregions_per_scanline) == 0);
560 
561       if (bUniformSizeSlices &&
562                  d3d12_video_encoder_check_subregion_mode_support(
563                     pD3D12Enc,
564                     D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME)) {
565             requestedSlicesMode =
566                D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
567             requestedSlicesConfig.NumberOfSlicesPerFrame = picture->num_slice_descriptors;
568             debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
569                            "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
570                            "with %d slices per frame.\n",
571                            requestedSlicesConfig.NumberOfSlicesPerFrame);
572       } else if (bUniformSizeSlices &&
573                  d3d12_video_encoder_check_subregion_mode_support(
574                     pD3D12Enc,
575                     D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED)) {
576             requestedSlicesMode =
577                D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED;
578             requestedSlicesConfig.NumberOfCodingUnitsPerSlice = num_subregions_per_slice;
579             debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
580                            "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED "
581                            "with %d NumberOfCodingUnitsPerSlice per frame.\n",
582                            requestedSlicesConfig.NumberOfCodingUnitsPerSlice);
583 
584       } else if (bUniformSizeSlices && bSliceAligned &&
585                  d3d12_video_encoder_check_subregion_mode_support(
586                     pD3D12Enc,
587                     D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION)) {
588 
589          // Number of subregion block per slice is aligned to a scanline width, in which case we can
590          // use D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION
591          requestedSlicesMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION;
592          requestedSlicesConfig.NumberOfRowsPerSlice = (num_subregions_per_slice / num_subregions_per_scanline);
593          debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
594                         "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION with "
595                         "%d subregion block rows (%d pix scanlines) per slice.\n",
596                         requestedSlicesConfig.NumberOfRowsPerSlice,
597                         pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize);
598       } else {
599          debug_printf("[d3d12_video_encoder_hevc] Requested slice control mode is not supported: All slices must "
600                          "have the same number of macroblocks.\n");
601          return false;
602       }
603    } else if(picture->slice_mode == PIPE_VIDEO_SLICE_MODE_MAX_SLICE_SIZE) {
604       if ((picture->max_slice_bytes > 0) &&
605                  d3d12_video_encoder_check_subregion_mode_support(
606                     pD3D12Enc,
607                     D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION )) {
608             requestedSlicesMode =
609                D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION;
610             requestedSlicesConfig.MaxBytesPerSlice = picture->max_slice_bytes;
611             debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
612                            "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION  "
613                            "with %d MaxBytesPerSlice per frame.\n",
614                            requestedSlicesConfig.MaxBytesPerSlice);
615       } else {
616          debug_printf("[d3d12_video_encoder_hevc] Requested slice control mode is not supported: All slices must "
617                          "have the same number of macroblocks.\n");
618          return false;
619       }
620    } else {
621       requestedSlicesMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
622       requestedSlicesConfig.NumberOfSlicesPerFrame = 1;
623       debug_printf("[d3d12_video_encoder_hevc] Requested slice control mode is full frame. m_SlicesPartition_H264.NumberOfSlicesPerFrame = %d - m_encoderSliceConfigMode = %d \n",
624       requestedSlicesConfig.NumberOfSlicesPerFrame, requestedSlicesMode);
625    }
626 
627    if (!d3d12_video_encoder_isequal_slice_config_hevc(
628           pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
629           pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC,
630           requestedSlicesMode,
631           requestedSlicesConfig)) {
632       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_slices;
633    }
634 
635    pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC = requestedSlicesConfig;
636    pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode = requestedSlicesMode;
637 
638    return true;
639 }
640 
641 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)642 d3d12_video_encoder_convert_hevc_motion_configuration(struct d3d12_video_encoder *pD3D12Enc,
643                                                       pipe_h265_enc_picture_desc *picture)
644 {
645    return D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM;
646 }
647 
648 bool
d3d12_video_encoder_update_hevc_gop_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h265_enc_picture_desc * picture)649 d3d12_video_encoder_update_hevc_gop_configuration(struct d3d12_video_encoder *pD3D12Enc,
650                                                   pipe_h265_enc_picture_desc *picture)
651 {
652    // Only update GOP when it begins
653    // This triggers DPB/encoder/heap re-creation, so only check on IDR when a GOP might change
654    if ((picture->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR)
655       || (picture->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_I)) {
656       uint32_t GOPLength = picture->seq.intra_period;
657       uint32_t PPicturePeriod = picture->seq.ip_period;
658 
659       const uint32_t max_pic_order_cnt_lsb = MAX2(16, util_next_power_of_two(GOPLength));
660       double log2_max_pic_order_cnt_lsb_minus4 = std::max(0.0, std::ceil(std::log2(max_pic_order_cnt_lsb)) - 4);
661       assert(log2_max_pic_order_cnt_lsb_minus4 < UCHAR_MAX);
662 
663       // Set dirty flag if m_HEVCGroupOfPictures changed
664       auto previousGOPConfig = pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures;
665       pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures = {
666          GOPLength,
667          PPicturePeriod,
668          static_cast<uint8_t>(log2_max_pic_order_cnt_lsb_minus4)
669       };
670 
671       if (memcmp(&previousGOPConfig,
672                  &pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures,
673                  sizeof(D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_HEVC)) != 0) {
674          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_gop;
675       }
676    }
677    return true;
678 }
679 
680 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT
ConvertHEVCSupportFromProfile(D3D12_VIDEO_ENCODER_PROFILE_HEVC profile,D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC1 * pSupport1)681 ConvertHEVCSupportFromProfile(D3D12_VIDEO_ENCODER_PROFILE_HEVC profile, D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC1* pSupport1)
682 {
683    D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = {};
684    if (profile <= D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10)
685    {
686       // Profiles defined up to D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10 use D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC
687       capCodecConfigData.DataSize = sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC);
688       // D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC1 binary-compatible with D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC
689       capCodecConfigData.pHEVCSupport = reinterpret_cast<D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC*>(pSupport1);
690    }
691    else
692    {
693       // Profiles defined between D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN12 and D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN16_444 use D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC1
694       assert (profile <= D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN16_444);
695       capCodecConfigData.DataSize = sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC1);
696       capCodecConfigData.pHEVCSupport1 = pSupport1;
697    }
698    return capCodecConfigData;
699 }
700 
701 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA
ConvertHEVCPicParamsFromProfile(D3D12_VIDEO_ENCODER_PROFILE_HEVC profile,D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 * pPictureParams1)702 ConvertHEVCPicParamsFromProfile(D3D12_VIDEO_ENCODER_PROFILE_HEVC profile, D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1* pPictureParams1)
703 {
704    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curPicParamsData = {};
705    if (profile <= D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10)
706    {
707       // Profiles defined up to D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10 use D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC
708       curPicParamsData.pHEVCPicData  = reinterpret_cast<D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC*>(pPictureParams1);
709       // D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 binary-compatible with D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC
710       curPicParamsData.DataSize      = sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC);
711    }
712    else
713    {
714       // Profiles defined between D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN12 and D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN16_444 use D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1
715       assert (profile <= D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN16_444);
716       curPicParamsData.pHEVCPicData1 = pPictureParams1;
717       curPicParamsData.DataSize      = sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1);
718    }
719    return curPicParamsData;
720 }
721 
722 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)723 d3d12_video_encoder_convert_hevc_codec_configuration(struct d3d12_video_encoder *pD3D12Enc,
724                                                      pipe_h265_enc_picture_desc *picture,
725                                                      bool&is_supported)
726 {
727    is_supported = true;
728    uint32_t min_cu_size = (1 << (picture->seq.log2_min_luma_coding_block_size_minus3 + 3));
729    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));
730 
731    uint32_t min_tu_size = (1 << (picture->seq.log2_min_transform_block_size_minus2 + 2));
732    uint32_t max_tu_size = (1 << (picture->seq.log2_min_transform_block_size_minus2 + 2 + picture->seq.log2_diff_max_min_transform_block_size));
733 
734    D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC config = {
735       D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_NONE,
736       d3d12_video_encoder_convert_pixel_size_hevc_to_12cusize(min_cu_size),
737       d3d12_video_encoder_convert_pixel_size_hevc_to_12cusize(max_cu_size),
738       d3d12_video_encoder_convert_pixel_size_hevc_to_12tusize(min_tu_size),
739       d3d12_video_encoder_convert_pixel_size_hevc_to_12tusize(max_tu_size),
740       picture->seq.max_transform_hierarchy_depth_inter,
741       picture->seq.max_transform_hierarchy_depth_intra,
742    };
743 
744    pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps =
745    {
746          D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE,
747          config.MinLumaCodingUnitSize,
748          config.MaxLumaCodingUnitSize,
749          config.MinLumaTransformUnitSize,
750          config.MaxLumaTransformUnitSize,
751          config.max_transform_hierarchy_depth_inter,
752          config.max_transform_hierarchy_depth_intra
753    };
754 
755    D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = { };
756    capCodecConfigData.NodeIndex = pD3D12Enc->m_NodeIndex;
757    capCodecConfigData.Codec = D3D12_VIDEO_ENCODER_CODEC_HEVC;
758    D3D12_VIDEO_ENCODER_PROFILE_HEVC prof = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(pD3D12Enc->base.profile);
759    capCodecConfigData.Profile.pHEVCProfile = &prof;
760    capCodecConfigData.Profile.DataSize = sizeof(prof);
761 
762    capCodecConfigData.CodecSupportLimits = ConvertHEVCSupportFromProfile((*capCodecConfigData.Profile.pHEVCProfile),
763                                                                          &pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps);
764 
765    if(FAILED(pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData)))
766       || !capCodecConfigData.IsSupported)
767    {
768          is_supported = false;
769 
770          // Workaround for https://github.com/intel/libva/issues/641
771          if ( !capCodecConfigData.IsSupported
772             && ((picture->seq.max_transform_hierarchy_depth_inter == 0)
773                || (picture->seq.max_transform_hierarchy_depth_intra == 0)) )
774          {
775             // Try and see if the values where 4 and overflowed in the 2 bit fields
776             capCodecConfigData.CodecSupportLimits.pHEVCSupport->max_transform_hierarchy_depth_inter =
777                (picture->seq.max_transform_hierarchy_depth_inter == 0) ? 4 : picture->seq.max_transform_hierarchy_depth_inter;
778             capCodecConfigData.CodecSupportLimits.pHEVCSupport->max_transform_hierarchy_depth_intra =
779                (picture->seq.max_transform_hierarchy_depth_intra == 0) ? 4 : picture->seq.max_transform_hierarchy_depth_intra;
780 
781             // Call the caps check again
782             if(SUCCEEDED(pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData)))
783                && capCodecConfigData.IsSupported)
784             {
785                // If this was the case, then update the config return variable with the overriden values too
786                is_supported = true;
787                config.max_transform_hierarchy_depth_inter =
788                   capCodecConfigData.CodecSupportLimits.pHEVCSupport->max_transform_hierarchy_depth_inter;
789                config.max_transform_hierarchy_depth_intra =
790                   capCodecConfigData.CodecSupportLimits.pHEVCSupport->max_transform_hierarchy_depth_intra;
791             }
792          }
793 
794          if (!is_supported) {
795             debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - "
796                "Call to CheckFeatureCaps (D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, ...) returned failure "
797                "or not supported for Codec HEVC -  MinLumaSize %d - MaxLumaSize %d -  MinTransformSize %d - "
798                "MaxTransformSize %d - Depth_inter %d - Depth intra %d\n",
799                config.MinLumaCodingUnitSize,
800                config.MaxLumaCodingUnitSize,
801                config.MinLumaTransformUnitSize,
802                config.MaxLumaTransformUnitSize,
803                config.max_transform_hierarchy_depth_inter,
804                config.max_transform_hierarchy_depth_intra);
805 
806             return config;
807          }
808    }
809 
810    if (picture->seq.amp_enabled_flag)
811       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
812 
813    if (picture->seq.sample_adaptive_offset_enabled_flag)
814       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER;
815 
816    if (picture->pic.pps_loop_filter_across_slices_enabled_flag)
817       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES;
818 
819    if (picture->pic.transform_skip_enabled_flag)
820       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING;
821 
822    if (picture->pic.constrained_intra_pred_flag)
823       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION;
824 
825    if (picture->base.profile == PIPE_VIDEO_PROFILE_HEVC_MAIN_444)
826    {
827       if (picture->seq.sps_range_extension.transform_skip_rotation_enabled_flag)
828          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION;
829       if (picture->seq.sps_range_extension.transform_skip_context_enabled_flag)
830          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT;
831       if (picture->seq.sps_range_extension.implicit_rdpcm_enabled_flag)
832          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM;
833       if (picture->seq.sps_range_extension.explicit_rdpcm_enabled_flag)
834          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM;
835       if (picture->seq.sps_range_extension.extended_precision_processing_flag)
836          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING;
837       if (picture->seq.sps_range_extension.intra_smoothing_disabled_flag)
838          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED;
839       if (picture->seq.sps_range_extension.high_precision_offsets_enabled_flag)
840          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS;
841       if (picture->seq.sps_range_extension.persistent_rice_adaptation_enabled_flag)
842          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION;
843       if (picture->seq.sps_range_extension.cabac_bypass_alignment_enabled_flag)
844          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT;
845    }
846 
847    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES) != 0)
848          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_DISABLING_LOOP_FILTER_ACROSS_SLICES_SUPPORT) == 0))
849    {
850          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Disable deblocking across slice boundary mode not supported."
851          " Ignoring the request for this feature flag on this encode session\n");
852          // Disable it and keep going with a warning
853          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES;
854    }
855 
856    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES) != 0)
857          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_INTRA_SLICE_CONSTRAINED_ENCODING_SUPPORT) == 0))
858    {
859          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Intra slice constrained mode not supported."
860          " Ignoring the request for this feature flag on this encode session\n");
861          // Disable it and keep going with a warning
862          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES;
863    }
864 
865    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER) != 0)
866          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_SAO_FILTER_SUPPORT) == 0))
867    {
868          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - SAO Filter mode not supported."
869          " Ignoring the request for this feature flag on this encode session\n");
870          // Disable it and keep going with a warning
871          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER;
872    }
873 
874 
875    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION) != 0)
876          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_SUPPORT) == 0))
877    {
878          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Asymetric motion partition not supported."
879          " Ignoring the request for this feature flag on this encode session\n");
880          // Disable it and keep going with a warning
881          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
882    }
883 
884    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION) == 0)
885          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_REQUIRED) != 0))
886    {
887          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Asymetric motion partition is required to be set."
888          " Enabling this HW required feature flag on this encode session\n");
889          // HW doesn't support otherwise, so set it
890          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
891    }
892 
893    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING) != 0)
894          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_SUPPORT) == 0))
895    {
896          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Allow transform skipping is not supported."
897          " Ignoring the request for this feature flag on this encode session\n");
898          // Disable it and keep going with a warning
899          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING;
900    }
901 
902    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION) != 0)
903          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CONSTRAINED_INTRAPREDICTION_SUPPORT) == 0))
904    {
905          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Constrained intra-prediction use is not supported."
906          " Ignoring the request for this feature flag on this encode session\n");
907          // Disable it and keep going with a warning
908          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION;
909    }
910 
911    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION) != 0)
912          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_ROTATION_ENABLED_SUPPORT) == 0))
913    {
914          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION is not supported."
915          " Ignoring the request for this feature flag on this encode session\n");
916          // Disable it and keep going with a warning
917          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION;
918    }
919 
920    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION) == 0)
921          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_ROTATION_ENABLED_REQUIRED) != 0))
922    {
923          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION is required to be set."
924          " Enabling this HW required feature flag on this encode session\n");
925          // HW doesn't support otherwise, so set it
926          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION;
927    }
928 
929    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT) != 0)
930          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT_ENABLED_SUPPORT) == 0))
931    {
932          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT is not supported."
933          " Ignoring the request for this feature flag on this encode session\n");
934          // Disable it and keep going with a warning
935          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT;
936    }
937 
938    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT) == 0)
939          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT_ENABLED_REQUIRED) != 0))
940    {
941          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT is required to be set."
942          " Enabling this HW required feature flag on this encode session\n");
943          // HW doesn't support otherwise, so set it
944          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT;
945    }
946 
947    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM) != 0)
948          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_IMPLICIT_RDPCM_ENABLED_SUPPORT) == 0))
949    {
950          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM is not supported."
951          " Ignoring the request for this feature flag on this encode session\n");
952          // Disable it and keep going with a warning
953          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM;
954    }
955 
956    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM) == 0)
957          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_IMPLICIT_RDPCM_ENABLED_REQUIRED) != 0))
958    {
959          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM is required to be set."
960          " Enabling this HW required feature flag on this encode session\n");
961          // HW doesn't support otherwise, so set it
962          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM;
963    }
964 
965    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM) != 0)
966          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_EXPLICIT_RDPCM_ENABLED_SUPPORT) == 0))
967    {
968          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM is not supported."
969          " Ignoring the request for this feature flag on this encode session\n");
970          // Disable it and keep going with a warning
971          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM;
972    }
973 
974    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM) == 0)
975          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_EXPLICIT_RDPCM_ENABLED_REQUIRED) != 0))
976    {
977          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM is required to be set."
978          " Enabling this HW required feature flag on this encode session\n");
979          // HW doesn't support otherwise, so set it
980          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM;
981    }
982 
983    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING) != 0)
984          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING_SUPPORT) == 0))
985    {
986          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING is not supported."
987          " Ignoring the request for this feature flag on this encode session\n");
988          // Disable it and keep going with a warning
989          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING;
990    }
991 
992    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING) == 0)
993          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING_REQUIRED) != 0))
994    {
995          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING is required to be set."
996          " Enabling this HW required feature flag on this encode session\n");
997          // HW doesn't support otherwise, so set it
998          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING;
999    }
1000 
1001    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED) != 0)
1002          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_INTRA_SMOOTHING_DISABLED_SUPPORT) == 0))
1003    {
1004          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED is not supported."
1005          " Ignoring the request for this feature flag on this encode session\n");
1006          // Disable it and keep going with a warning
1007          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED;
1008    }
1009 
1010    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED) == 0)
1011          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_INTRA_SMOOTHING_DISABLED_REQUIRED) != 0))
1012    {
1013          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED is required to be set."
1014          " Enabling this HW required feature flag on this encode session\n");
1015          // HW doesn't support otherwise, so set it
1016          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED;
1017    }
1018 
1019    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS) != 0)
1020          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_HIGH_PRECISION_OFFSETS_ENABLED_SUPPORT) == 0))
1021    {
1022          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS is not supported."
1023          " Ignoring the request for this feature flag on this encode session\n");
1024          // Disable it and keep going with a warning
1025          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS;
1026    }
1027 
1028    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS) == 0)
1029          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_HIGH_PRECISION_OFFSETS_ENABLED_REQUIRED) != 0))
1030    {
1031          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS is required to be set."
1032          " Enabling this HW required feature flag on this encode session\n");
1033          // HW doesn't support otherwise, so set it
1034          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS;
1035    }
1036 
1037    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION) != 0)
1038          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION_ENABLED_SUPPORT) == 0))
1039    {
1040          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION is not supported."
1041          " Ignoring the request for this feature flag on this encode session\n");
1042          // Disable it and keep going with a warning
1043          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION;
1044    }
1045 
1046    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION) == 0)
1047          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION_ENABLED_REQUIRED) != 0))
1048    {
1049          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION is required to be set."
1050          " Enabling this HW required feature flag on this encode session\n");
1051          // HW doesn't support otherwise, so set it
1052          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION;
1053    }
1054 
1055    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT) != 0)
1056          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT_ENABLED_SUPPORT) == 0))
1057    {
1058          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT is not supported."
1059          " Ignoring the request for this feature flag on this encode session\n");
1060          // Disable it and keep going with a warning
1061          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT;
1062    }
1063 
1064    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT) == 0)
1065          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT_ENABLED_REQUIRED) != 0))
1066    {
1067          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT is required to be set."
1068          " Enabling this HW required feature flag on this encode session\n");
1069          // HW doesn't support otherwise, so set it
1070          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT;
1071    }
1072 
1073    return config;
1074 }
1075 
1076 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)1077 d3d12_video_encoder_update_intra_refresh_hevc(struct d3d12_video_encoder *pD3D12Enc,
1078                                                         D3D12_VIDEO_SAMPLE srcTextureDesc,
1079                                                         struct pipe_h265_enc_picture_desc *  picture)
1080 {
1081    if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_NONE)
1082    {
1083       // D3D12 only supports row intra-refresh
1084       if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_UNIT_ROWS)
1085       {
1086          debug_printf("[d3d12_video_encoder_update_intra_refresh_hevc] Unsupported INTRA_REFRESH_MODE %d\n", picture->intra_refresh.mode);
1087          return false;
1088       }
1089 
1090       uint8_t ctbSize = d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(
1091          pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.MaxLumaCodingUnitSize);
1092       uint32_t total_frame_blocks = static_cast<uint32_t>(std::ceil(srcTextureDesc.Height / ctbSize)) *
1093                               static_cast<uint32_t>(std::ceil(srcTextureDesc.Width / ctbSize));
1094       D3D12_VIDEO_ENCODER_INTRA_REFRESH targetIntraRefresh = {
1095          D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ROW_BASED,
1096          total_frame_blocks / picture->intra_refresh.region_size,
1097       };
1098       double ir_wave_progress = (picture->intra_refresh.offset == 0) ? 0 :
1099          picture->intra_refresh.offset / (double) total_frame_blocks;
1100       pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex =
1101          static_cast<uint32_t>(std::ceil(ir_wave_progress * targetIntraRefresh.IntraRefreshDuration));
1102 
1103       // Set intra refresh state
1104       pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = targetIntraRefresh;
1105       // Need to send the sequence flag during all the IR duration
1106       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_intra_refresh;
1107    } else {
1108       pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex = 0;
1109       pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = {
1110          D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
1111          0,
1112       };
1113    }
1114 
1115    return true;
1116 }
1117 
1118 bool
d3d12_video_encoder_update_current_encoder_config_state_hevc(struct d3d12_video_encoder * pD3D12Enc,D3D12_VIDEO_SAMPLE srcTextureDesc,struct pipe_picture_desc * picture)1119 d3d12_video_encoder_update_current_encoder_config_state_hevc(struct d3d12_video_encoder *pD3D12Enc,
1120                                                              D3D12_VIDEO_SAMPLE srcTextureDesc,
1121                                                              struct pipe_picture_desc *picture)
1122 {
1123    struct pipe_h265_enc_picture_desc *hevcPic = (struct pipe_h265_enc_picture_desc *) picture;
1124 
1125    // Reset reconfig dirty flags
1126    pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags = d3d12_video_encoder_config_dirty_flag_none;
1127    // Reset sequence changes flags
1128    pD3D12Enc->m_currentEncodeConfig.m_seqFlags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE;
1129 
1130    // Set codec
1131    if (pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc != D3D12_VIDEO_ENCODER_CODEC_HEVC) {
1132       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec;
1133    }
1134    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc = D3D12_VIDEO_ENCODER_CODEC_HEVC;
1135 
1136    // Set VPS information
1137    if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificVideoStateDescH265,
1138               &hevcPic->vid,
1139               sizeof(hevcPic->vid)) != 0) {
1140       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_video_header;
1141    }
1142    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificVideoStateDescH265 = hevcPic->vid;
1143 
1144    // Set Sequence information
1145    if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH265,
1146               &hevcPic->seq,
1147               sizeof(hevcPic->seq)) != 0) {
1148       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sequence_header;
1149    }
1150    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH265 = hevcPic->seq;
1151    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificPictureStateDescH265 = hevcPic->pic;
1152 
1153    // Iterate over the headers the app requested and set flags to emit those for this frame
1154    util_dynarray_foreach(&hevcPic->raw_headers, struct pipe_enc_raw_header, header) {
1155       if (header->type == PIPE_H265_NAL_VPS)
1156          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_video_header;
1157       else if (header->type == PIPE_H265_NAL_SPS)
1158          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sequence_header;
1159       else if (header->type == PIPE_H265_NAL_PPS)
1160          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_picture_header;
1161       else if (header->type == PIPE_H265_NAL_AUD)
1162          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_aud_header;
1163    }
1164 
1165    // Set input format
1166    DXGI_FORMAT targetFmt = d3d12_convert_pipe_video_profile_to_dxgi_format(pD3D12Enc->base.profile);
1167    if (pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format != targetFmt) {
1168       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_input_format;
1169    }
1170 
1171    pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo = {};
1172    pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format = targetFmt;
1173    HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO,
1174                                                           &pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo,
1175                                                           sizeof(pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo));
1176    if (FAILED(hr)) {
1177       debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
1178       return false;
1179    }
1180 
1181    // Set resolution
1182    if ((pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width != srcTextureDesc.Width) ||
1183        (pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height != srcTextureDesc.Height)) {
1184       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_resolution;
1185    }
1186    pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width = srcTextureDesc.Width;
1187    pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height = srcTextureDesc.Height;
1188 
1189    // Set resolution codec dimensions (ie. cropping)
1190    memset(&pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig, 0,
1191          sizeof(pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig));
1192    pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.front = hevcPic->seq.pic_width_in_luma_samples;
1193    pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.back = hevcPic->seq.pic_height_in_luma_samples;
1194    if (hevcPic->seq.conformance_window_flag) {
1195       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.left = hevcPic->seq.conf_win_left_offset;
1196       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.right = hevcPic->seq.conf_win_right_offset;
1197       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.top = hevcPic->seq.conf_win_top_offset;
1198       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.bottom = hevcPic->seq.conf_win_bottom_offset;
1199    }
1200    // Set profile
1201    auto targetProfile = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(pD3D12Enc->base.profile);
1202    if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile != targetProfile) {
1203       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_profile;
1204    }
1205    pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile = targetProfile;
1206 
1207    // Set level
1208    auto targetLevel = d3d12_video_encoder_convert_level_hevc(hevcPic->seq.general_level_idc);
1209    auto targetTier = (hevcPic->seq.general_tier_flag == 0) ? D3D12_VIDEO_ENCODER_TIER_HEVC_MAIN : D3D12_VIDEO_ENCODER_TIER_HEVC_HIGH;
1210    if ( (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level != targetLevel)
1211       || (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier != targetTier)) {
1212       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_level;
1213    }
1214    pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier = targetTier;
1215    pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level = targetLevel;
1216 
1217    // Set codec config
1218    bool is_supported = true;
1219    auto targetCodecConfig = d3d12_video_encoder_convert_hevc_codec_configuration(pD3D12Enc, hevcPic, is_supported);
1220    if(!is_supported) {
1221       return false;
1222    }
1223 
1224    if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig,
1225               &targetCodecConfig,
1226               sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC)) != 0) {
1227       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec_config;
1228    }
1229    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig = targetCodecConfig;
1230 
1231    // Set rate control
1232    d3d12_video_encoder_update_current_rate_control_hevc(pD3D12Enc, hevcPic);
1233 
1234    // Set GOP config
1235    if(!d3d12_video_encoder_update_hevc_gop_configuration(pD3D12Enc, hevcPic)) {
1236       debug_printf("d3d12_video_encoder_update_hevc_gop_configuration failed!\n");
1237       return false;
1238    }
1239 
1240    ///
1241    /// Check for video encode support detailed capabilities
1242    ///
1243 
1244    // Will call for d3d12 driver support based on the initial requested features, then
1245    // try to fallback if any of them is not supported and return the negotiated d3d12 settings
1246    D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 capEncoderSupportData1 = {};
1247    // Get max number of slices per frame supported
1248    if (hevcPic->num_slice_descriptors > 1)
1249       pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode =
1250          D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
1251    else
1252       pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode =
1253          D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
1254 
1255    if (!d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(pD3D12Enc, capEncoderSupportData1)) {
1256       debug_printf("[d3d12_video_encoder_hevc] After negotiating caps, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1 "
1257                       "arguments are not supported - "
1258                       "ValidationFlags: 0x%x - SupportFlags: 0x%x\n",
1259                       capEncoderSupportData1.ValidationFlags,
1260                       capEncoderSupportData1.SupportFlags);
1261       return false;
1262    }
1263 
1264    // Set slices config  (configure before calling d3d12_video_encoder_calculate_max_slices_count_in_output)
1265    if(!d3d12_video_encoder_negotiate_current_hevc_slices_configuration(pD3D12Enc, hevcPic)) {
1266       debug_printf("d3d12_video_encoder_negotiate_current_hevc_slices_configuration failed!\n");
1267       return false;
1268    }
1269 
1270    ///
1271    // Calculate current settings based on the returned values from the caps query
1272    //
1273    pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput =
1274       d3d12_video_encoder_calculate_max_slices_count_in_output(
1275          pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
1276          &pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC,
1277          pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber,
1278          pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
1279          pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize);
1280 
1281    // Set intra-refresh config
1282    if(!d3d12_video_encoder_update_intra_refresh_hevc(pD3D12Enc, srcTextureDesc, hevcPic)) {
1283       debug_printf("d3d12_video_encoder_update_intra_refresh_hevc failed!\n");
1284       return false;
1285    }
1286 
1287    // m_currentEncodeConfig.m_encoderPicParamsDesc pic params are set in d3d12_video_encoder_reconfigure_encoder_objects
1288    // after re-allocating objects if needed
1289 
1290    // Set motion estimation config
1291    auto targetMotionLimit = d3d12_video_encoder_convert_hevc_motion_configuration(pD3D12Enc, hevcPic);
1292    if (pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit != targetMotionLimit) {
1293       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |=
1294          d3d12_video_encoder_config_dirty_flag_motion_precision_limit;
1295    }
1296    pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit = targetMotionLimit;
1297 
1298    //
1299    // Validate caps support returned values against current settings
1300    //
1301    if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile !=
1302        pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_HEVCProfile) {
1303       debug_printf("[d3d12_video_encoder_hevc] Warning: Requested D3D12_VIDEO_ENCODER_PROFILE_HEVC by upper layer: %d "
1304                     "mismatches UMD suggested D3D12_VIDEO_ENCODER_PROFILE_HEVC: %d\n",
1305                     pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile,
1306                     pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_HEVCProfile);
1307    }
1308 
1309    if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier !=
1310        pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Tier) {
1311       debug_printf("[d3d12_video_encoder_hevc] Warning: Requested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Tier by upper layer: %d "
1312                     "mismatches UMD suggested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Tier: %d\n",
1313                     pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier,
1314                     pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Tier);
1315    }
1316 
1317    if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level !=
1318        pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Level) {
1319       debug_printf("[d3d12_video_encoder_hevc] Warning: Requested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Level by upper layer: %d "
1320                     "mismatches UMD suggested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Level: %d\n",
1321                     pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level,
1322                     pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Level);
1323    }
1324 
1325    if (pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput >
1326        pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber) {
1327       debug_printf("[d3d12_video_encoder_hevc] Desired number of subregions %d is not supported (higher than max "
1328                       "reported slice number %d in query caps) for current resolution (%d, %d)\n.",
1329                       pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput,
1330                       pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber,
1331                       pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width,
1332                       pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height);
1333       return false;
1334    }
1335    return true;
1336 }
1337 
1338 D3D12_VIDEO_ENCODER_PROFILE_HEVC
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(enum pipe_video_profile profile)1339 d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(enum pipe_video_profile profile)
1340 {
1341    switch (profile) {
1342       case PIPE_VIDEO_PROFILE_HEVC_MAIN:
1343       {
1344          return D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN;
1345 
1346       } break;
1347       case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
1348       {
1349          return D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10;
1350       } break;
1351       case PIPE_VIDEO_PROFILE_HEVC_MAIN_444:
1352       {
1353          return D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN_444;
1354       } break;
1355       default:
1356       {
1357          unreachable("Unsupported pipe_video_profile");
1358       } break;
1359    }
1360 }
1361 
1362 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)1363 d3d12_video_encoder_isequal_slice_config_hevc(
1364    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE targetMode,
1365    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES targetConfig,
1366    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE otherMode,
1367    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES otherConfig)
1368 {
1369    return (targetMode == otherMode) &&
1370           (memcmp(&targetConfig,
1371                   &otherConfig,
1372                   sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES)) == 0);
1373 }
1374 
1375 static inline bool
d3d12_video_encoder_needs_new_pps_hevc(struct d3d12_video_encoder * pD3D12Enc,bool writeNewSPS,HevcPicParameterSet & tentative_pps,const HevcPicParameterSet & active_pps)1376 d3d12_video_encoder_needs_new_pps_hevc(struct d3d12_video_encoder *pD3D12Enc,
1377                                        bool writeNewSPS,
1378                                        HevcPicParameterSet &tentative_pps,
1379                                        const HevcPicParameterSet &active_pps)
1380 {
1381    bool bUseSliceL0L1Override = (pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_HEVCPicData.Flags &
1382                                  D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_REQUEST_NUM_REF_IDX_ACTIVE_OVERRIDE_FLAG_SLICE);
1383 
1384    bool bDifferentL0L1Lists = !bUseSliceL0L1Override &&
1385          ((tentative_pps.num_ref_idx_lx_default_active_minus1[0] != active_pps.num_ref_idx_lx_default_active_minus1[0]) ||
1386          (tentative_pps.num_ref_idx_lx_default_active_minus1[1] != active_pps.num_ref_idx_lx_default_active_minus1[1]));
1387 
1388    size_t offset_before_l0l1 = offsetof(HevcPicParameterSet, num_ref_idx_lx_default_active_minus1[0]);
1389    size_t offset_after_l0l1 = offset_before_l0l1 + sizeof(HevcPicParameterSet::num_ref_idx_lx_default_active_minus1);
1390    bool bDidPPSChange = memcmp(&tentative_pps, &active_pps, offset_before_l0l1) ||
1391                         bDifferentL0L1Lists ||
1392                         memcmp(reinterpret_cast<uint8_t*>(&tentative_pps) + offset_after_l0l1,
1393                                reinterpret_cast<const uint8_t*>(&active_pps) + offset_after_l0l1,
1394                                sizeof(HevcPicParameterSet) - offset_after_l0l1);
1395 
1396    return writeNewSPS || bDidPPSChange;
1397 }
1398 
1399 uint32_t
d3d12_video_encoder_build_codec_headers_hevc(struct d3d12_video_encoder * pD3D12Enc,std::vector<uint64_t> & pWrittenCodecUnitsSizes)1400 d3d12_video_encoder_build_codec_headers_hevc(struct d3d12_video_encoder *pD3D12Enc,
1401                                              std::vector<uint64_t> &pWrittenCodecUnitsSizes)
1402 {
1403    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams =
1404       d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc);
1405 
1406    auto profDesc = d3d12_video_encoder_get_current_profile_desc(pD3D12Enc);
1407    auto levelDesc = d3d12_video_encoder_get_current_level_desc(pD3D12Enc);
1408    auto codecConfigDesc = d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc);
1409 
1410    pWrittenCodecUnitsSizes.clear();
1411    bool isFirstFrame = (pD3D12Enc->m_fenceValue == 1);
1412 
1413    d3d12_video_bitstream_builder_hevc *pHEVCBitstreamBuilder =
1414       static_cast<d3d12_video_bitstream_builder_hevc *>(pD3D12Enc->m_upBitstreamBuilder.get());
1415    assert(pHEVCBitstreamBuilder);
1416 
1417    size_t writtenAUDBytesCount = 0;
1418    bool forceWriteAUD = (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_aud_header);
1419    if (forceWriteAUD)
1420    {
1421       pHEVCBitstreamBuilder->write_aud(pD3D12Enc->m_BitstreamHeadersBuffer,
1422                                        pD3D12Enc->m_BitstreamHeadersBuffer.begin(),
1423                                        currentPicParams.pHEVCPicData->FrameType,
1424                                        writtenAUDBytesCount);
1425       pWrittenCodecUnitsSizes.push_back(writtenAUDBytesCount);
1426    }
1427 
1428    uint8_t active_seq_parameter_set_id = pHEVCBitstreamBuilder->get_active_sps().sps_seq_parameter_set_id;
1429    uint8_t active_video_parameter_set_id = pHEVCBitstreamBuilder->get_active_vps().vps_video_parameter_set_id;
1430 
1431    bool writeNewVPS = isFirstFrame || (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_video_header);
1432 
1433    size_t writtenVPSBytesCount = 0;
1434    if (writeNewVPS) {
1435       bool gopHasBFrames = (pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures.PPicturePeriod > 1);
1436       HevcVideoParameterSet vps = pHEVCBitstreamBuilder->build_vps(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificVideoStateDescH265,
1437                                                                   *profDesc.pHEVCProfile,
1438                                                                    *levelDesc.pHEVCLevelSetting,
1439                                                                    pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
1440                                                                    gopHasBFrames,
1441                                                                    active_video_parameter_set_id,
1442                                                                    pD3D12Enc->m_BitstreamHeadersBuffer,
1443                                                                    pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenAUDBytesCount,
1444                                                                    writtenVPSBytesCount);
1445       pHEVCBitstreamBuilder->set_active_vps(vps);
1446       pWrittenCodecUnitsSizes.push_back(writtenVPSBytesCount);
1447    }
1448 
1449    bool forceWriteSPS = (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_sequence_header);
1450    bool writeNewSPS = writeNewVPS                                          // on new VPS written
1451                       || ((pD3D12Enc->m_currentEncodeConfig.m_seqFlags &   // also on resolution change
1452                            D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_RESOLUTION_CHANGE) != 0)
1453                       || forceWriteSPS;
1454 
1455    size_t writtenSPSBytesCount = 0;
1456    if (writeNewSPS) {
1457       HevcSeqParameterSet sps = pHEVCBitstreamBuilder->build_sps(pHEVCBitstreamBuilder->get_active_vps(),
1458                                                                  pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH265,
1459                                                                  active_seq_parameter_set_id,
1460                                                                  pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
1461                                                                  pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig,
1462                                                                  pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize,
1463                                                                  pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
1464                                                                  *codecConfigDesc.pHEVCConfig,
1465                                                                  pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures,
1466                                                                  pD3D12Enc->m_BitstreamHeadersBuffer,
1467                                                                  pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenAUDBytesCount + writtenVPSBytesCount,
1468                                                                  writtenSPSBytesCount);
1469       pHEVCBitstreamBuilder->set_active_sps(sps);
1470       pWrittenCodecUnitsSizes.push_back(writtenSPSBytesCount);
1471    }
1472 
1473    size_t writtenPPSBytesCount = 0;
1474    HevcPicParameterSet tentative_pps = pHEVCBitstreamBuilder->build_pps(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificPictureStateDescH265,
1475                                                                         pHEVCBitstreamBuilder->get_active_sps(),
1476                                                                         static_cast<uint8_t>(currentPicParams.pHEVCPicData->slice_pic_parameter_set_id),
1477                                                                         *codecConfigDesc.pHEVCConfig,
1478                                                                         *currentPicParams.pHEVCPicData1,
1479                                                                         pD3D12Enc->m_StagingHeadersBuffer,
1480                                                                         pD3D12Enc->m_StagingHeadersBuffer.begin(),
1481                                                                         writtenPPSBytesCount);
1482 
1483    const HevcPicParameterSet &active_pps = pHEVCBitstreamBuilder->get_active_pps();
1484    bool forceWritePPS = (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_picture_header);
1485    if (forceWritePPS || d3d12_video_encoder_needs_new_pps_hevc(pD3D12Enc, writeNewSPS, tentative_pps, active_pps)) {
1486       pHEVCBitstreamBuilder->set_active_pps(tentative_pps);
1487       pD3D12Enc->m_BitstreamHeadersBuffer.resize(writtenAUDBytesCount + writtenVPSBytesCount + writtenSPSBytesCount + writtenPPSBytesCount);
1488       memcpy(&pD3D12Enc->m_BitstreamHeadersBuffer.data()[(writtenAUDBytesCount + writtenVPSBytesCount + writtenSPSBytesCount)], pD3D12Enc->m_StagingHeadersBuffer.data(), writtenPPSBytesCount);
1489       pWrittenCodecUnitsSizes.push_back(writtenPPSBytesCount);
1490    } else {
1491       writtenPPSBytesCount = 0;
1492       debug_printf("Skipping PPS (same as active PPS) for fenceValue: %" PRIu64 "\n", pD3D12Enc->m_fenceValue);
1493    }
1494 
1495    // Shrink buffer to fit the headers
1496    if (pD3D12Enc->m_BitstreamHeadersBuffer.size() > (writtenAUDBytesCount + writtenVPSBytesCount + writtenSPSBytesCount + writtenPPSBytesCount)) {
1497       pD3D12Enc->m_BitstreamHeadersBuffer.resize(writtenAUDBytesCount + writtenVPSBytesCount + writtenSPSBytesCount + writtenPPSBytesCount);
1498    }
1499 
1500    assert(std::accumulate(pWrittenCodecUnitsSizes.begin(), pWrittenCodecUnitsSizes.end(), 0ull) ==
1501       pD3D12Enc->m_BitstreamHeadersBuffer.size());
1502    return static_cast<uint32_t>(pD3D12Enc->m_BitstreamHeadersBuffer.size());
1503 }
1504