xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/d3d12/d3d12_video_enc_hevc.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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    bUsedAsReference = !hevcPic->not_referenced;
358 
359    if (pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags &
360        D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NUM_REF_IDX_ACTIVE_OVERRIDE_FLAG_SLICE_SUPPORT)
361    {
362       picParams.pHEVCPicData->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_REQUEST_NUM_REF_IDX_ACTIVE_OVERRIDE_FLAG_SLICE;
363    }
364 
365    if (hevcPic->base.profile == PIPE_VIDEO_PROFILE_HEVC_MAIN_444)
366    {
367       assert(picParams.DataSize == sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1));
368 
369       //
370       // Copy from pipe params
371       //
372       {
373          picParams.pHEVCPicData1->diff_cu_chroma_qp_offset_depth = hevcPic->pic.pps_range_extension.diff_cu_chroma_qp_offset_depth;
374          picParams.pHEVCPicData1->log2_sao_offset_scale_luma = hevcPic->pic.pps_range_extension.log2_sao_offset_scale_luma;
375          picParams.pHEVCPicData1->log2_sao_offset_scale_chroma = hevcPic->pic.pps_range_extension.log2_sao_offset_scale_chroma;
376          picParams.pHEVCPicData1->log2_max_transform_skip_block_size_minus2 = hevcPic->pic.pps_range_extension.log2_max_transform_skip_block_size_minus2;
377          picParams.pHEVCPicData1->chroma_qp_offset_list_len_minus1 = hevcPic->pic.pps_range_extension.chroma_qp_offset_list_len_minus1;
378 
379          for (uint32_t i = 0; i < ARRAY_SIZE(picParams.pHEVCPicData1->cb_qp_offset_list) ; i++)
380          {
381             picParams.pHEVCPicData1->cb_qp_offset_list[i] = hevcPic->pic.pps_range_extension.cb_qp_offset_list[i];
382             picParams.pHEVCPicData1->cr_qp_offset_list[i] = hevcPic->pic.pps_range_extension.cr_qp_offset_list[i];
383          }
384 
385          if (hevcPic->pic.pps_range_extension.cross_component_prediction_enabled_flag)
386             picParams.pHEVCPicData1->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CROSS_COMPONENT_PREDICTION;
387 
388          if (hevcPic->pic.pps_range_extension.chroma_qp_offset_list_enabled_flag)
389             picParams.pHEVCPicData1->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CHROMA_QP_OFFSET_LIST;
390       }
391 
392       //
393       // Validate caps from copied params
394       //
395 
396       // Check for support of value with: (allowed_diff_cu_chroma_qp_offset_depth_values & (1 << value) != 0)
397       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)
398       {
399          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);
400          assert(false);
401       }
402 
403       if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.allowed_log2_sao_offset_scale_luma_values & (1 << picParams.pHEVCPicData1->log2_sao_offset_scale_luma)) == 0)
404       {
405          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);
406          assert(false);
407       }
408 
409       if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.allowed_log2_sao_offset_scale_chroma_values & (1 << picParams.pHEVCPicData1->log2_sao_offset_scale_chroma)) == 0)
410       {
411          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);
412          assert(false);
413       }
414 
415       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)
416       {
417          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);
418          assert(false);
419       }
420 
421       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)
422       {
423          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);
424          assert(false);
425       }
426 
427       if(((picParams.pHEVCPicData1->Flags & D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CROSS_COMPONENT_PREDICTION) != 0)
428             && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CROSS_COMPONENT_PREDICTION_ENABLED_FLAG_SUPPORT) == 0))
429       {
430             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."
431             " Ignoring the request for this feature flag on this encode session\n");
432             // Disable it and keep going with a warning
433             picParams.pHEVCPicData1->Flags &= ~D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CROSS_COMPONENT_PREDICTION;
434       }
435 
436       if(((picParams.pHEVCPicData1->Flags & D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CROSS_COMPONENT_PREDICTION) == 0)
437             && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CROSS_COMPONENT_PREDICTION_ENABLED_FLAG_REQUIRED) != 0))
438       {
439             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."
440             " Enabling this HW required feature flag on this encode session\n");
441             // HW doesn't support otherwise, so set it
442             picParams.pHEVCPicData1->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CROSS_COMPONENT_PREDICTION;
443       }
444 
445       if(((picParams.pHEVCPicData1->Flags & D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CHROMA_QP_OFFSET_LIST) != 0)
446             && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CHROMA_QP_OFFSET_LIST_ENABLED_FLAG_SUPPORT) == 0))
447       {
448             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."
449             " Ignoring the request for this feature flag on this encode session\n");
450             // Disable it and keep going with a warning
451             picParams.pHEVCPicData1->Flags &= ~D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CHROMA_QP_OFFSET_LIST;
452       }
453 
454       if(((picParams.pHEVCPicData1->Flags & D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CHROMA_QP_OFFSET_LIST) == 0)
455             && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CHROMA_QP_OFFSET_LIST_ENABLED_FLAG_REQUIRED) != 0))
456       {
457             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."
458             " Enabling this HW required feature flag on this encode session\n");
459             // HW doesn't support otherwise, so set it
460             picParams.pHEVCPicData1->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_CHROMA_QP_OFFSET_LIST;
461       }
462    }
463 
464    picParams.pHEVCPicData->slice_pic_parameter_set_id = pHEVCBitstreamBuilder->get_active_pps().pps_pic_parameter_set_id;
465 
466    //
467    // These need to be set here so they're available for SPS/PPS header building (reference manager updates after that, for slice header params)
468    //
469    picParams.pHEVCPicData->List0ReferenceFramesCount = 0;
470    picParams.pHEVCPicData->List1ReferenceFramesCount = 0;
471    if ((hevcPic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_P) ||
472        (hevcPic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B))
473       picParams.pHEVCPicData->List0ReferenceFramesCount = hevcPic->num_ref_idx_l0_active_minus1 + 1;
474    if (hevcPic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B)
475       picParams.pHEVCPicData->List1ReferenceFramesCount = hevcPic->num_ref_idx_l1_active_minus1 + 1;
476 
477    if ((pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig.ConfigurationFlags
478       & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES) != 0)
479       picParams.pHEVCPicData->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_REQUEST_INTRA_CONSTRAINED_SLICES;
480 
481    if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0)
482    {
483       // Use 8 bit qpmap array for HEVC picparams (-51, 51 range and int8_t pRateControlQPMap type)
484       const int32_t hevc_min_delta_qp = -51;
485       const int32_t hevc_max_delta_qp = 51;
486       d3d12_video_encoder_update_picparams_region_of_interest_qpmap(
487          pD3D12Enc,
488          &hevcPic->roi,
489          hevc_min_delta_qp,
490          hevc_max_delta_qp,
491          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_pRateControlQPMap8Bit);
492       picParams.pHEVCPicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_pRateControlQPMap8Bit.data();
493       picParams.pHEVCPicData->QPMapValuesCount = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_pRateControlQPMap8Bit.size();
494    }
495 }
496 
497 ///
498 /// Tries to configurate the encoder using the requested slice configuration
499 /// or falls back to single slice encoding.
500 ///
501 bool
d3d12_video_encoder_negotiate_current_hevc_slices_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h265_enc_picture_desc * picture)502 d3d12_video_encoder_negotiate_current_hevc_slices_configuration(struct d3d12_video_encoder *pD3D12Enc,
503                                                                 pipe_h265_enc_picture_desc *picture)
504 {
505    ///
506    /// Initialize single slice by default
507    ///
508    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode =
509       D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
510    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES requestedSlicesConfig = {};
511    requestedSlicesConfig.NumberOfSlicesPerFrame = 1;
512 
513    ///
514    /// Try to see if can accomodate for multi-slice request by user
515    ///
516    if ((picture->slice_mode == PIPE_VIDEO_SLICE_MODE_BLOCKS) && (picture->num_slice_descriptors > 1)) {
517       /* Some apps send all same size slices minus 1 slice in any position in the descriptors */
518       /* Lets validate that there are at most 2 different slice sizes in all the descriptors */
519       std::vector<int> slice_sizes(picture->num_slice_descriptors);
520       for (uint32_t i = 0; i < picture->num_slice_descriptors; i++)
521          slice_sizes[i] = picture->slices_descriptors[i].num_ctu_in_slice;
522       std::sort(slice_sizes.begin(), slice_sizes.end());
523       bool bUniformSizeSlices = (std::unique(slice_sizes.begin(), slice_sizes.end()) - slice_sizes.begin()) <= 2;
524 
525       uint32_t subregion_block_pixel_size = pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize;
526       uint32_t num_subregions_per_scanline =
527          DIV_ROUND_UP(pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width, subregion_block_pixel_size);
528 
529       /* m_currentResolutionSupportCaps.SubregionBlockPixelsSize can be a multiple of MinCUSize to accomodate for HW requirements
530          So, if the allowed subregion (slice) pixel size partition is bigger (a multiple) than the CTU size, we have to adjust
531          num_subregions_per_slice by this factor respect from slices_descriptors[X].num_ctu_in_slice
532       */
533 
534       /* This assert should always be true according to the spec
535          https://github.com/microsoft/DirectX-Specs/blob/master/d3d/D3D12VideoEncoding.md#3150-struct-d3d12_feature_data_video_encoder_resolution_support_limits
536        */
537       uint8_t minCUSize = d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig.MinLumaCodingUnitSize);
538       assert((pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize
539          % minCUSize) == 0);
540 
541       uint32_t subregionsize_to_ctu_factor = pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize /
542          minCUSize;
543       uint32_t num_subregions_per_slice = picture->slices_descriptors[0].num_ctu_in_slice
544                                                    * pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize
545                                                    / (subregionsize_to_ctu_factor * subregionsize_to_ctu_factor);
546 
547       bool bSliceAligned = ((num_subregions_per_slice % num_subregions_per_scanline) == 0);
548 
549       if (bUniformSizeSlices &&
550                  d3d12_video_encoder_check_subregion_mode_support(
551                     pD3D12Enc,
552                     D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME)) {
553             requestedSlicesMode =
554                D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
555             requestedSlicesConfig.NumberOfSlicesPerFrame = picture->num_slice_descriptors;
556             debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
557                            "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
558                            "with %d slices per frame.\n",
559                            requestedSlicesConfig.NumberOfSlicesPerFrame);
560       } else if (bUniformSizeSlices &&
561                  d3d12_video_encoder_check_subregion_mode_support(
562                     pD3D12Enc,
563                     D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED)) {
564             requestedSlicesMode =
565                D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED;
566             requestedSlicesConfig.NumberOfCodingUnitsPerSlice = num_subregions_per_slice;
567             debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
568                            "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED "
569                            "with %d NumberOfCodingUnitsPerSlice per frame.\n",
570                            requestedSlicesConfig.NumberOfCodingUnitsPerSlice);
571 
572       } else if (bUniformSizeSlices && bSliceAligned &&
573                  d3d12_video_encoder_check_subregion_mode_support(
574                     pD3D12Enc,
575                     D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION)) {
576 
577          // Number of subregion block per slice is aligned to a scanline width, in which case we can
578          // use D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION
579          requestedSlicesMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION;
580          requestedSlicesConfig.NumberOfRowsPerSlice = (num_subregions_per_slice / num_subregions_per_scanline);
581          debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
582                         "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION with "
583                         "%d subregion block rows (%d pix scanlines) per slice.\n",
584                         requestedSlicesConfig.NumberOfRowsPerSlice,
585                         pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize);
586       } else {
587          debug_printf("[d3d12_video_encoder_hevc] Requested slice control mode is not supported: All slices must "
588                          "have the same number of macroblocks.\n");
589          return false;
590       }
591    } else if(picture->slice_mode == PIPE_VIDEO_SLICE_MODE_MAX_SLICE_SIZE) {
592       if ((picture->max_slice_bytes > 0) &&
593                  d3d12_video_encoder_check_subregion_mode_support(
594                     pD3D12Enc,
595                     D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION )) {
596             requestedSlicesMode =
597                D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION;
598             requestedSlicesConfig.MaxBytesPerSlice = picture->max_slice_bytes;
599             debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
600                            "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION  "
601                            "with %d MaxBytesPerSlice per frame.\n",
602                            requestedSlicesConfig.MaxBytesPerSlice);
603       } else {
604          debug_printf("[d3d12_video_encoder_hevc] Requested slice control mode is not supported: All slices must "
605                          "have the same number of macroblocks.\n");
606          return false;
607       }
608    } else {
609       requestedSlicesMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
610       requestedSlicesConfig.NumberOfSlicesPerFrame = 1;
611       debug_printf("[d3d12_video_encoder_hevc] Requested slice control mode is full frame. m_SlicesPartition_H264.NumberOfSlicesPerFrame = %d - m_encoderSliceConfigMode = %d \n",
612       requestedSlicesConfig.NumberOfSlicesPerFrame, requestedSlicesMode);
613    }
614 
615    if (!d3d12_video_encoder_isequal_slice_config_hevc(
616           pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
617           pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC,
618           requestedSlicesMode,
619           requestedSlicesConfig)) {
620       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_slices;
621    }
622 
623    pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC = requestedSlicesConfig;
624    pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode = requestedSlicesMode;
625 
626    return true;
627 }
628 
629 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)630 d3d12_video_encoder_convert_hevc_motion_configuration(struct d3d12_video_encoder *pD3D12Enc,
631                                                       pipe_h265_enc_picture_desc *picture)
632 {
633    return D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM;
634 }
635 
636 bool
d3d12_video_encoder_update_hevc_gop_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h265_enc_picture_desc * picture)637 d3d12_video_encoder_update_hevc_gop_configuration(struct d3d12_video_encoder *pD3D12Enc,
638                                                   pipe_h265_enc_picture_desc *picture)
639 {
640    // Only update GOP when it begins
641    // This triggers DPB/encoder/heap re-creation, so only check on IDR when a GOP might change
642    if ((picture->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR)
643       || (picture->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_I)) {
644       uint32_t GOPLength = picture->seq.intra_period;
645       uint32_t PPicturePeriod = picture->seq.ip_period;
646 
647       const uint32_t max_pic_order_cnt_lsb = MAX2(16, util_next_power_of_two(GOPLength));
648       double log2_max_pic_order_cnt_lsb_minus4 = std::max(0.0, std::ceil(std::log2(max_pic_order_cnt_lsb)) - 4);
649       assert(log2_max_pic_order_cnt_lsb_minus4 < UCHAR_MAX);
650 
651       // Set dirty flag if m_HEVCGroupOfPictures changed
652       auto previousGOPConfig = pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures;
653       pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures = {
654          GOPLength,
655          PPicturePeriod,
656          static_cast<uint8_t>(log2_max_pic_order_cnt_lsb_minus4)
657       };
658 
659       if (memcmp(&previousGOPConfig,
660                  &pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures,
661                  sizeof(D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_HEVC)) != 0) {
662          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_gop;
663       }
664    }
665    return true;
666 }
667 
668 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT
ConvertHEVCSupportFromProfile(D3D12_VIDEO_ENCODER_PROFILE_HEVC profile,D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC1 * pSupport1)669 ConvertHEVCSupportFromProfile(D3D12_VIDEO_ENCODER_PROFILE_HEVC profile, D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC1* pSupport1)
670 {
671    D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = {};
672    if (profile <= D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10)
673    {
674       // Profiles defined up to D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10 use D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC
675       capCodecConfigData.DataSize = sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC);
676       // D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC1 binary-compatible with D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC
677       capCodecConfigData.pHEVCSupport = reinterpret_cast<D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC*>(pSupport1);
678    }
679    else
680    {
681       // 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
682       assert (profile <= D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN16_444);
683       capCodecConfigData.DataSize = sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC1);
684       capCodecConfigData.pHEVCSupport1 = pSupport1;
685    }
686    return capCodecConfigData;
687 }
688 
689 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA
ConvertHEVCPicParamsFromProfile(D3D12_VIDEO_ENCODER_PROFILE_HEVC profile,D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 * pPictureParams1)690 ConvertHEVCPicParamsFromProfile(D3D12_VIDEO_ENCODER_PROFILE_HEVC profile, D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1* pPictureParams1)
691 {
692    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curPicParamsData = {};
693    if (profile <= D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10)
694    {
695       // Profiles defined up to D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10 use D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC
696       curPicParamsData.pHEVCPicData  = reinterpret_cast<D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC*>(pPictureParams1);
697       // D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1 binary-compatible with D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC
698       curPicParamsData.DataSize      = sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC);
699    }
700    else
701    {
702       // 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
703       assert (profile <= D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN16_444);
704       curPicParamsData.pHEVCPicData1 = pPictureParams1;
705       curPicParamsData.DataSize      = sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC1);
706    }
707    return curPicParamsData;
708 }
709 
710 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)711 d3d12_video_encoder_convert_hevc_codec_configuration(struct d3d12_video_encoder *pD3D12Enc,
712                                                      pipe_h265_enc_picture_desc *picture,
713                                                      bool&is_supported)
714 {
715    is_supported = true;
716    uint32_t min_cu_size = (1 << (picture->seq.log2_min_luma_coding_block_size_minus3 + 3));
717    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));
718 
719    uint32_t min_tu_size = (1 << (picture->seq.log2_min_transform_block_size_minus2 + 2));
720    uint32_t max_tu_size = (1 << (picture->seq.log2_min_transform_block_size_minus2 + 2 + picture->seq.log2_diff_max_min_transform_block_size));
721 
722    D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC config = {
723       D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_NONE,
724       d3d12_video_encoder_convert_pixel_size_hevc_to_12cusize(min_cu_size),
725       d3d12_video_encoder_convert_pixel_size_hevc_to_12cusize(max_cu_size),
726       d3d12_video_encoder_convert_pixel_size_hevc_to_12tusize(min_tu_size),
727       d3d12_video_encoder_convert_pixel_size_hevc_to_12tusize(max_tu_size),
728       picture->seq.max_transform_hierarchy_depth_inter,
729       picture->seq.max_transform_hierarchy_depth_intra,
730    };
731 
732    pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps =
733    {
734          D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE,
735          config.MinLumaCodingUnitSize,
736          config.MaxLumaCodingUnitSize,
737          config.MinLumaTransformUnitSize,
738          config.MaxLumaTransformUnitSize,
739          config.max_transform_hierarchy_depth_inter,
740          config.max_transform_hierarchy_depth_intra
741    };
742 
743    D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = { };
744    capCodecConfigData.NodeIndex = pD3D12Enc->m_NodeIndex;
745    capCodecConfigData.Codec = D3D12_VIDEO_ENCODER_CODEC_HEVC;
746    D3D12_VIDEO_ENCODER_PROFILE_HEVC prof = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(pD3D12Enc->base.profile);
747    capCodecConfigData.Profile.pHEVCProfile = &prof;
748    capCodecConfigData.Profile.DataSize = sizeof(prof);
749 
750    capCodecConfigData.CodecSupportLimits = ConvertHEVCSupportFromProfile((*capCodecConfigData.Profile.pHEVCProfile),
751                                                                          &pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps);
752 
753    if(FAILED(pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData)))
754       || !capCodecConfigData.IsSupported)
755    {
756          is_supported = false;
757 
758          // Workaround for https://github.com/intel/libva/issues/641
759          if ( !capCodecConfigData.IsSupported
760             && ((picture->seq.max_transform_hierarchy_depth_inter == 0)
761                || (picture->seq.max_transform_hierarchy_depth_intra == 0)) )
762          {
763             // Try and see if the values where 4 and overflowed in the 2 bit fields
764             capCodecConfigData.CodecSupportLimits.pHEVCSupport->max_transform_hierarchy_depth_inter =
765                (picture->seq.max_transform_hierarchy_depth_inter == 0) ? 4 : picture->seq.max_transform_hierarchy_depth_inter;
766             capCodecConfigData.CodecSupportLimits.pHEVCSupport->max_transform_hierarchy_depth_intra =
767                (picture->seq.max_transform_hierarchy_depth_intra == 0) ? 4 : picture->seq.max_transform_hierarchy_depth_intra;
768 
769             // Call the caps check again
770             if(SUCCEEDED(pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData)))
771                && capCodecConfigData.IsSupported)
772             {
773                // If this was the case, then update the config return variable with the overriden values too
774                is_supported = true;
775                config.max_transform_hierarchy_depth_inter =
776                   capCodecConfigData.CodecSupportLimits.pHEVCSupport->max_transform_hierarchy_depth_inter;
777                config.max_transform_hierarchy_depth_intra =
778                   capCodecConfigData.CodecSupportLimits.pHEVCSupport->max_transform_hierarchy_depth_intra;
779             }
780          }
781 
782          if (!is_supported) {
783             debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - "
784                "Call to CheckFeatureCaps (D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, ...) returned failure "
785                "or not supported for Codec HEVC -  MinLumaSize %d - MaxLumaSize %d -  MinTransformSize %d - "
786                "MaxTransformSize %d - Depth_inter %d - Depth intra %d\n",
787                config.MinLumaCodingUnitSize,
788                config.MaxLumaCodingUnitSize,
789                config.MinLumaTransformUnitSize,
790                config.MaxLumaTransformUnitSize,
791                config.max_transform_hierarchy_depth_inter,
792                config.max_transform_hierarchy_depth_intra);
793 
794             return config;
795          }
796    }
797 
798    if (picture->seq.amp_enabled_flag)
799       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
800 
801    if (picture->seq.sample_adaptive_offset_enabled_flag)
802       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER;
803 
804    if (picture->pic.pps_loop_filter_across_slices_enabled_flag)
805       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES;
806 
807    if (picture->pic.transform_skip_enabled_flag)
808       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING;
809 
810    if (picture->pic.constrained_intra_pred_flag)
811       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION;
812 
813    if (picture->base.profile == PIPE_VIDEO_PROFILE_HEVC_MAIN_444)
814    {
815       if (picture->seq.sps_range_extension.transform_skip_rotation_enabled_flag)
816          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION;
817       if (picture->seq.sps_range_extension.transform_skip_context_enabled_flag)
818          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT;
819       if (picture->seq.sps_range_extension.implicit_rdpcm_enabled_flag)
820          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM;
821       if (picture->seq.sps_range_extension.explicit_rdpcm_enabled_flag)
822          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM;
823       if (picture->seq.sps_range_extension.extended_precision_processing_flag)
824          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING;
825       if (picture->seq.sps_range_extension.intra_smoothing_disabled_flag)
826          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED;
827       if (picture->seq.sps_range_extension.high_precision_offsets_enabled_flag)
828          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS;
829       if (picture->seq.sps_range_extension.persistent_rice_adaptation_enabled_flag)
830          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION;
831       if (picture->seq.sps_range_extension.cabac_bypass_alignment_enabled_flag)
832          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT;
833    }
834 
835    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES) != 0)
836          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_DISABLING_LOOP_FILTER_ACROSS_SLICES_SUPPORT) == 0))
837    {
838          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Disable deblocking across slice boundary mode not supported."
839          " Ignoring the request for this feature flag on this encode session\n");
840          // Disable it and keep going with a warning
841          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES;
842    }
843 
844    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES) != 0)
845          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_INTRA_SLICE_CONSTRAINED_ENCODING_SUPPORT) == 0))
846    {
847          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Intra slice constrained mode not supported."
848          " Ignoring the request for this feature flag on this encode session\n");
849          // Disable it and keep going with a warning
850          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES;
851    }
852 
853    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER) != 0)
854          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_SAO_FILTER_SUPPORT) == 0))
855    {
856          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - SAO Filter mode not supported."
857          " Ignoring the request for this feature flag on this encode session\n");
858          // Disable it and keep going with a warning
859          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER;
860    }
861 
862 
863    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION) != 0)
864          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_SUPPORT) == 0))
865    {
866          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Asymetric motion partition not supported."
867          " Ignoring the request for this feature flag on this encode session\n");
868          // Disable it and keep going with a warning
869          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
870    }
871 
872    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION) == 0)
873          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_REQUIRED) != 0))
874    {
875          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Asymetric motion partition is required to be set."
876          " Enabling this HW required feature flag on this encode session\n");
877          // HW doesn't support otherwise, so set it
878          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
879    }
880 
881    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING) != 0)
882          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_SUPPORT) == 0))
883    {
884          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Allow transform skipping is not supported."
885          " Ignoring the request for this feature flag on this encode session\n");
886          // Disable it and keep going with a warning
887          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING;
888    }
889 
890    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION) != 0)
891          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CONSTRAINED_INTRAPREDICTION_SUPPORT) == 0))
892    {
893          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Constrained intra-prediction use is not supported."
894          " Ignoring the request for this feature flag on this encode session\n");
895          // Disable it and keep going with a warning
896          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION;
897    }
898 
899    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION) != 0)
900          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_ROTATION_ENABLED_SUPPORT) == 0))
901    {
902          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION is not supported."
903          " Ignoring the request for this feature flag on this encode session\n");
904          // Disable it and keep going with a warning
905          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION;
906    }
907 
908    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION) == 0)
909          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_ROTATION_ENABLED_REQUIRED) != 0))
910    {
911          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."
912          " Enabling this HW required feature flag on this encode session\n");
913          // HW doesn't support otherwise, so set it
914          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_ROTATION;
915    }
916 
917    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT) != 0)
918          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT_ENABLED_SUPPORT) == 0))
919    {
920          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT is not supported."
921          " Ignoring the request for this feature flag on this encode session\n");
922          // Disable it and keep going with a warning
923          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT;
924    }
925 
926    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT) == 0)
927          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT_ENABLED_REQUIRED) != 0))
928    {
929          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."
930          " Enabling this HW required feature flag on this encode session\n");
931          // HW doesn't support otherwise, so set it
932          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_TRANSFORM_SKIP_CONTEXT;
933    }
934 
935    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM) != 0)
936          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_IMPLICIT_RDPCM_ENABLED_SUPPORT) == 0))
937    {
938          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM is not supported."
939          " Ignoring the request for this feature flag on this encode session\n");
940          // Disable it and keep going with a warning
941          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM;
942    }
943 
944    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM) == 0)
945          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_IMPLICIT_RDPCM_ENABLED_REQUIRED) != 0))
946    {
947          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."
948          " Enabling this HW required feature flag on this encode session\n");
949          // HW doesn't support otherwise, so set it
950          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_IMPLICIT_RDPCM;
951    }
952 
953    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM) != 0)
954          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_EXPLICIT_RDPCM_ENABLED_SUPPORT) == 0))
955    {
956          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM is not supported."
957          " Ignoring the request for this feature flag on this encode session\n");
958          // Disable it and keep going with a warning
959          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM;
960    }
961 
962    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM) == 0)
963          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_EXPLICIT_RDPCM_ENABLED_REQUIRED) != 0))
964    {
965          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."
966          " Enabling this HW required feature flag on this encode session\n");
967          // HW doesn't support otherwise, so set it
968          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXPLICIT_RDPCM;
969    }
970 
971    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING) != 0)
972          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING_SUPPORT) == 0))
973    {
974          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING is not supported."
975          " Ignoring the request for this feature flag on this encode session\n");
976          // Disable it and keep going with a warning
977          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING;
978    }
979 
980    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING) == 0)
981          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING_REQUIRED) != 0))
982    {
983          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."
984          " Enabling this HW required feature flag on this encode session\n");
985          // HW doesn't support otherwise, so set it
986          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_EXTENDED_PRECISION_PROCESSING;
987    }
988 
989    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED) != 0)
990          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_INTRA_SMOOTHING_DISABLED_SUPPORT) == 0))
991    {
992          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED is not supported."
993          " Ignoring the request for this feature flag on this encode session\n");
994          // Disable it and keep going with a warning
995          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED;
996    }
997 
998    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED) == 0)
999          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_INTRA_SMOOTHING_DISABLED_REQUIRED) != 0))
1000    {
1001          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."
1002          " Enabling this HW required feature flag on this encode session\n");
1003          // HW doesn't support otherwise, so set it
1004          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_INTRA_SMOOTHING_DISABLED;
1005    }
1006 
1007    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS) != 0)
1008          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_HIGH_PRECISION_OFFSETS_ENABLED_SUPPORT) == 0))
1009    {
1010          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS is not supported."
1011          " Ignoring the request for this feature flag on this encode session\n");
1012          // Disable it and keep going with a warning
1013          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS;
1014    }
1015 
1016    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS) == 0)
1017          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_HIGH_PRECISION_OFFSETS_ENABLED_REQUIRED) != 0))
1018    {
1019          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."
1020          " Enabling this HW required feature flag on this encode session\n");
1021          // HW doesn't support otherwise, so set it
1022          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_HIGH_PRECISION_OFFSETS;
1023    }
1024 
1025    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION) != 0)
1026          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION_ENABLED_SUPPORT) == 0))
1027    {
1028          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION is not supported."
1029          " Ignoring the request for this feature flag on this encode session\n");
1030          // Disable it and keep going with a warning
1031          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION;
1032    }
1033 
1034    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION) == 0)
1035          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION_ENABLED_REQUIRED) != 0))
1036    {
1037          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."
1038          " Enabling this HW required feature flag on this encode session\n");
1039          // HW doesn't support otherwise, so set it
1040          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_PERSISTENT_RICE_ADAPTATION;
1041    }
1042 
1043    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT) != 0)
1044          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT_ENABLED_SUPPORT) == 0))
1045    {
1046          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT is not supported."
1047          " Ignoring the request for this feature flag on this encode session\n");
1048          // Disable it and keep going with a warning
1049          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT;
1050    }
1051 
1052    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT) == 0)
1053          && ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT_ENABLED_REQUIRED) != 0))
1054    {
1055          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."
1056          " Enabling this HW required feature flag on this encode session\n");
1057          // HW doesn't support otherwise, so set it
1058          config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_CABAC_BYPASS_ALIGNMENT;
1059    }
1060 
1061    return config;
1062 }
1063 
1064 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)1065 d3d12_video_encoder_update_intra_refresh_hevc(struct d3d12_video_encoder *pD3D12Enc,
1066                                                         D3D12_VIDEO_SAMPLE srcTextureDesc,
1067                                                         struct pipe_h265_enc_picture_desc *  picture)
1068 {
1069    if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_NONE)
1070    {
1071       // D3D12 only supports row intra-refresh
1072       if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_UNIT_ROWS)
1073       {
1074          debug_printf("[d3d12_video_encoder_update_intra_refresh_hevc] Unsupported INTRA_REFRESH_MODE %d\n", picture->intra_refresh.mode);
1075          return false;
1076       }
1077 
1078       uint8_t ctbSize = d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(
1079          pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.MaxLumaCodingUnitSize);
1080       uint32_t total_frame_blocks = static_cast<uint32_t>(std::ceil(srcTextureDesc.Height / ctbSize)) *
1081                               static_cast<uint32_t>(std::ceil(srcTextureDesc.Width / ctbSize));
1082       D3D12_VIDEO_ENCODER_INTRA_REFRESH targetIntraRefresh = {
1083          D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ROW_BASED,
1084          total_frame_blocks / picture->intra_refresh.region_size,
1085       };
1086       double ir_wave_progress = (picture->intra_refresh.offset == 0) ? 0 :
1087          picture->intra_refresh.offset / (double) total_frame_blocks;
1088       pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex =
1089          static_cast<uint32_t>(std::ceil(ir_wave_progress * targetIntraRefresh.IntraRefreshDuration));
1090 
1091       // Set intra refresh state
1092       pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = targetIntraRefresh;
1093       // Need to send the sequence flag during all the IR duration
1094       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_intra_refresh;
1095    } else {
1096       pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex = 0;
1097       pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = {
1098          D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
1099          0,
1100       };
1101    }
1102 
1103    return true;
1104 }
1105 
1106 bool
d3d12_video_encoder_update_current_encoder_config_state_hevc(struct d3d12_video_encoder * pD3D12Enc,D3D12_VIDEO_SAMPLE srcTextureDesc,struct pipe_picture_desc * picture)1107 d3d12_video_encoder_update_current_encoder_config_state_hevc(struct d3d12_video_encoder *pD3D12Enc,
1108                                                              D3D12_VIDEO_SAMPLE srcTextureDesc,
1109                                                              struct pipe_picture_desc *picture)
1110 {
1111    struct pipe_h265_enc_picture_desc *hevcPic = (struct pipe_h265_enc_picture_desc *) picture;
1112 
1113    // Reset reconfig dirty flags
1114    pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags = d3d12_video_encoder_config_dirty_flag_none;
1115    // Reset sequence changes flags
1116    pD3D12Enc->m_currentEncodeConfig.m_seqFlags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE;
1117 
1118    // Set codec
1119    if (pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc != D3D12_VIDEO_ENCODER_CODEC_HEVC) {
1120       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec;
1121    }
1122    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc = D3D12_VIDEO_ENCODER_CODEC_HEVC;
1123 
1124    // Set VPS information
1125    if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificVideoStateDescH265,
1126               &hevcPic->vid,
1127               sizeof(hevcPic->vid)) != 0) {
1128       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_video_header;
1129    }
1130    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificVideoStateDescH265 = hevcPic->vid;
1131 
1132    // Set Sequence information
1133    if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH265,
1134               &hevcPic->seq,
1135               sizeof(hevcPic->seq)) != 0) {
1136       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sequence_header;
1137    }
1138    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH265 = hevcPic->seq;
1139    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificPictureStateDescH265 = hevcPic->pic;
1140 
1141    // Iterate over the headers the app requested and set flags to emit those for this frame
1142    util_dynarray_foreach(&hevcPic->raw_headers, struct pipe_enc_raw_header, header) {
1143       if (header->type == PIPE_H265_NAL_VPS)
1144          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_video_header;
1145       else if (header->type == PIPE_H265_NAL_SPS)
1146          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sequence_header;
1147       else if (header->type == PIPE_H265_NAL_PPS)
1148          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_picture_header;
1149       else if (header->type == PIPE_H265_NAL_AUD)
1150          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_aud_header;
1151    }
1152 
1153    // Set input format
1154    DXGI_FORMAT targetFmt = d3d12_convert_pipe_video_profile_to_dxgi_format(pD3D12Enc->base.profile);
1155    if (pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format != targetFmt) {
1156       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_input_format;
1157    }
1158 
1159    pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo = {};
1160    pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format = targetFmt;
1161    HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO,
1162                                                           &pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo,
1163                                                           sizeof(pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo));
1164    if (FAILED(hr)) {
1165       debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
1166       return false;
1167    }
1168 
1169    // Set resolution
1170    if ((pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width != srcTextureDesc.Width) ||
1171        (pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height != srcTextureDesc.Height)) {
1172       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_resolution;
1173    }
1174    pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width = srcTextureDesc.Width;
1175    pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height = srcTextureDesc.Height;
1176 
1177    // Set resolution codec dimensions (ie. cropping)
1178    memset(&pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig, 0,
1179          sizeof(pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig));
1180    pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.front = hevcPic->seq.pic_width_in_luma_samples;
1181    pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.back = hevcPic->seq.pic_height_in_luma_samples;
1182    if (hevcPic->seq.conformance_window_flag) {
1183       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.left = hevcPic->seq.conf_win_left_offset;
1184       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.right = hevcPic->seq.conf_win_right_offset;
1185       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.top = hevcPic->seq.conf_win_top_offset;
1186       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.bottom = hevcPic->seq.conf_win_bottom_offset;
1187    }
1188    // Set profile
1189    auto targetProfile = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(pD3D12Enc->base.profile);
1190    if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile != targetProfile) {
1191       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_profile;
1192    }
1193    pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile = targetProfile;
1194 
1195    // Set level
1196    auto targetLevel = d3d12_video_encoder_convert_level_hevc(hevcPic->seq.general_level_idc);
1197    auto targetTier = (hevcPic->seq.general_tier_flag == 0) ? D3D12_VIDEO_ENCODER_TIER_HEVC_MAIN : D3D12_VIDEO_ENCODER_TIER_HEVC_HIGH;
1198    if ( (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level != targetLevel)
1199       || (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier != targetTier)) {
1200       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_level;
1201    }
1202    pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier = targetTier;
1203    pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level = targetLevel;
1204 
1205    // Set codec config
1206    bool is_supported = true;
1207    auto targetCodecConfig = d3d12_video_encoder_convert_hevc_codec_configuration(pD3D12Enc, hevcPic, is_supported);
1208    if(!is_supported) {
1209       return false;
1210    }
1211 
1212    if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig,
1213               &targetCodecConfig,
1214               sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC)) != 0) {
1215       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec_config;
1216    }
1217    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig = targetCodecConfig;
1218 
1219    // Set rate control
1220    d3d12_video_encoder_update_current_rate_control_hevc(pD3D12Enc, hevcPic);
1221 
1222    // Set GOP config
1223    if(!d3d12_video_encoder_update_hevc_gop_configuration(pD3D12Enc, hevcPic)) {
1224       debug_printf("d3d12_video_encoder_update_hevc_gop_configuration failed!\n");
1225       return false;
1226    }
1227 
1228    ///
1229    /// Check for video encode support detailed capabilities
1230    ///
1231 
1232    // Will call for d3d12 driver support based on the initial requested features, then
1233    // try to fallback if any of them is not supported and return the negotiated d3d12 settings
1234    D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 capEncoderSupportData1 = {};
1235    // Get max number of slices per frame supported
1236    if (hevcPic->num_slice_descriptors > 1)
1237       pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode =
1238          D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
1239    else
1240       pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode =
1241          D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
1242 
1243    if (!d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(pD3D12Enc, capEncoderSupportData1)) {
1244       debug_printf("[d3d12_video_encoder_hevc] After negotiating caps, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1 "
1245                       "arguments are not supported - "
1246                       "ValidationFlags: 0x%x - SupportFlags: 0x%x\n",
1247                       capEncoderSupportData1.ValidationFlags,
1248                       capEncoderSupportData1.SupportFlags);
1249       return false;
1250    }
1251 
1252    // Set slices config  (configure before calling d3d12_video_encoder_calculate_max_slices_count_in_output)
1253    if(!d3d12_video_encoder_negotiate_current_hevc_slices_configuration(pD3D12Enc, hevcPic)) {
1254       debug_printf("d3d12_video_encoder_negotiate_current_hevc_slices_configuration failed!\n");
1255       return false;
1256    }
1257 
1258    ///
1259    // Calculate current settings based on the returned values from the caps query
1260    //
1261    pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput =
1262       d3d12_video_encoder_calculate_max_slices_count_in_output(
1263          pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
1264          &pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC,
1265          pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber,
1266          pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
1267          pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize);
1268 
1269    // Set intra-refresh config
1270    if(!d3d12_video_encoder_update_intra_refresh_hevc(pD3D12Enc, srcTextureDesc, hevcPic)) {
1271       debug_printf("d3d12_video_encoder_update_intra_refresh_hevc failed!\n");
1272       return false;
1273    }
1274 
1275    // m_currentEncodeConfig.m_encoderPicParamsDesc pic params are set in d3d12_video_encoder_reconfigure_encoder_objects
1276    // after re-allocating objects if needed
1277 
1278    // Set motion estimation config
1279    auto targetMotionLimit = d3d12_video_encoder_convert_hevc_motion_configuration(pD3D12Enc, hevcPic);
1280    if (pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit != targetMotionLimit) {
1281       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |=
1282          d3d12_video_encoder_config_dirty_flag_motion_precision_limit;
1283    }
1284    pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit = targetMotionLimit;
1285 
1286    //
1287    // Validate caps support returned values against current settings
1288    //
1289    if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile !=
1290        pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_HEVCProfile) {
1291       debug_printf("[d3d12_video_encoder_hevc] Warning: Requested D3D12_VIDEO_ENCODER_PROFILE_HEVC by upper layer: %d "
1292                     "mismatches UMD suggested D3D12_VIDEO_ENCODER_PROFILE_HEVC: %d\n",
1293                     pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile,
1294                     pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_HEVCProfile);
1295    }
1296 
1297    if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier !=
1298        pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Tier) {
1299       debug_printf("[d3d12_video_encoder_hevc] Warning: Requested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Tier by upper layer: %d "
1300                     "mismatches UMD suggested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Tier: %d\n",
1301                     pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier,
1302                     pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Tier);
1303    }
1304 
1305    if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level !=
1306        pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Level) {
1307       debug_printf("[d3d12_video_encoder_hevc] Warning: Requested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Level by upper layer: %d "
1308                     "mismatches UMD suggested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Level: %d\n",
1309                     pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level,
1310                     pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Level);
1311    }
1312 
1313    if (pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput >
1314        pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber) {
1315       debug_printf("[d3d12_video_encoder_hevc] Desired number of subregions %d is not supported (higher than max "
1316                       "reported slice number %d in query caps) for current resolution (%d, %d)\n.",
1317                       pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput,
1318                       pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber,
1319                       pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width,
1320                       pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height);
1321       return false;
1322    }
1323    return true;
1324 }
1325 
1326 D3D12_VIDEO_ENCODER_PROFILE_HEVC
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(enum pipe_video_profile profile)1327 d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(enum pipe_video_profile profile)
1328 {
1329    switch (profile) {
1330       case PIPE_VIDEO_PROFILE_HEVC_MAIN:
1331       {
1332          return D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN;
1333 
1334       } break;
1335       case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
1336       {
1337          return D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10;
1338       } break;
1339       case PIPE_VIDEO_PROFILE_HEVC_MAIN_444:
1340       {
1341          return D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN_444;
1342       } break;
1343       default:
1344       {
1345          unreachable("Unsupported pipe_video_profile");
1346       } break;
1347    }
1348 }
1349 
1350 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)1351 d3d12_video_encoder_isequal_slice_config_hevc(
1352    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE targetMode,
1353    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES targetConfig,
1354    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE otherMode,
1355    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES otherConfig)
1356 {
1357    return (targetMode == otherMode) &&
1358           (memcmp(&targetConfig,
1359                   &otherConfig,
1360                   sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES)) == 0);
1361 }
1362 
1363 static inline bool
d3d12_video_encoder_needs_new_pps_hevc(struct d3d12_video_encoder * pD3D12Enc,bool writeNewSPS,HevcPicParameterSet & tentative_pps,const HevcPicParameterSet & active_pps)1364 d3d12_video_encoder_needs_new_pps_hevc(struct d3d12_video_encoder *pD3D12Enc,
1365                                        bool writeNewSPS,
1366                                        HevcPicParameterSet &tentative_pps,
1367                                        const HevcPicParameterSet &active_pps)
1368 {
1369    bool bUseSliceL0L1Override = (pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_HEVCPicData.Flags &
1370                                  D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_REQUEST_NUM_REF_IDX_ACTIVE_OVERRIDE_FLAG_SLICE);
1371 
1372    bool bDifferentL0L1Lists = !bUseSliceL0L1Override &&
1373          ((tentative_pps.num_ref_idx_lx_default_active_minus1[0] != active_pps.num_ref_idx_lx_default_active_minus1[0]) ||
1374          (tentative_pps.num_ref_idx_lx_default_active_minus1[1] != active_pps.num_ref_idx_lx_default_active_minus1[1]));
1375 
1376    size_t offset_before_l0l1 = offsetof(HevcPicParameterSet, num_ref_idx_lx_default_active_minus1[0]);
1377    size_t offset_after_l0l1 = offset_before_l0l1 + sizeof(HevcPicParameterSet::num_ref_idx_lx_default_active_minus1);
1378    bool bDidPPSChange = memcmp(&tentative_pps, &active_pps, offset_before_l0l1) ||
1379                         bDifferentL0L1Lists ||
1380                         memcmp(reinterpret_cast<uint8_t*>(&tentative_pps) + offset_after_l0l1,
1381                                reinterpret_cast<const uint8_t*>(&active_pps) + offset_after_l0l1,
1382                                sizeof(HevcPicParameterSet) - offset_after_l0l1);
1383 
1384    return writeNewSPS || bDidPPSChange;
1385 }
1386 
1387 uint32_t
d3d12_video_encoder_build_codec_headers_hevc(struct d3d12_video_encoder * pD3D12Enc,std::vector<uint64_t> & pWrittenCodecUnitsSizes)1388 d3d12_video_encoder_build_codec_headers_hevc(struct d3d12_video_encoder *pD3D12Enc,
1389                                              std::vector<uint64_t> &pWrittenCodecUnitsSizes)
1390 {
1391    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams =
1392       d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc);
1393 
1394    auto profDesc = d3d12_video_encoder_get_current_profile_desc(pD3D12Enc);
1395    auto levelDesc = d3d12_video_encoder_get_current_level_desc(pD3D12Enc);
1396    auto codecConfigDesc = d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc);
1397 
1398    pWrittenCodecUnitsSizes.clear();
1399    bool isFirstFrame = (pD3D12Enc->m_fenceValue == 1);
1400 
1401    d3d12_video_bitstream_builder_hevc *pHEVCBitstreamBuilder =
1402       static_cast<d3d12_video_bitstream_builder_hevc *>(pD3D12Enc->m_upBitstreamBuilder.get());
1403    assert(pHEVCBitstreamBuilder);
1404 
1405    size_t writtenAUDBytesCount = 0;
1406    bool forceWriteAUD = (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_aud_header);
1407    if (forceWriteAUD)
1408    {
1409       pHEVCBitstreamBuilder->write_aud(pD3D12Enc->m_BitstreamHeadersBuffer,
1410                                        pD3D12Enc->m_BitstreamHeadersBuffer.begin(),
1411                                        currentPicParams.pHEVCPicData->FrameType,
1412                                        writtenAUDBytesCount);
1413       pWrittenCodecUnitsSizes.push_back(writtenAUDBytesCount);
1414    }
1415 
1416    uint32_t active_seq_parameter_set_id = pHEVCBitstreamBuilder->get_active_sps().sps_seq_parameter_set_id;
1417    uint32_t active_video_parameter_set_id = pHEVCBitstreamBuilder->get_active_vps().vps_video_parameter_set_id;
1418 
1419    bool writeNewVPS = isFirstFrame || (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_video_header);
1420 
1421    size_t writtenVPSBytesCount = 0;
1422    if (writeNewVPS) {
1423       bool gopHasBFrames = (pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures.PPicturePeriod > 1);
1424       HevcVideoParameterSet vps = pHEVCBitstreamBuilder->build_vps(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificVideoStateDescH265,
1425                                                                   *profDesc.pHEVCProfile,
1426                                                                    *levelDesc.pHEVCLevelSetting,
1427                                                                    pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
1428                                                                    gopHasBFrames,
1429                                                                    active_video_parameter_set_id,
1430                                                                    pD3D12Enc->m_BitstreamHeadersBuffer,
1431                                                                    pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenAUDBytesCount,
1432                                                                    writtenVPSBytesCount);
1433       pHEVCBitstreamBuilder->set_active_vps(vps);
1434       pWrittenCodecUnitsSizes.push_back(writtenVPSBytesCount);
1435    }
1436 
1437    bool forceWriteSPS = (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_sequence_header);
1438    bool writeNewSPS = writeNewVPS                                          // on new VPS written
1439                       || ((pD3D12Enc->m_currentEncodeConfig.m_seqFlags &   // also on resolution change
1440                            D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_RESOLUTION_CHANGE) != 0)
1441                       || forceWriteSPS;
1442 
1443    size_t writtenSPSBytesCount = 0;
1444    if (writeNewSPS) {
1445       HevcSeqParameterSet sps = pHEVCBitstreamBuilder->build_sps(pHEVCBitstreamBuilder->get_active_vps(),
1446                                                                  pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH265,
1447                                                                  active_seq_parameter_set_id,
1448                                                                  pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
1449                                                                  pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig,
1450                                                                  pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize,
1451                                                                  pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
1452                                                                  *codecConfigDesc.pHEVCConfig,
1453                                                                  pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures,
1454                                                                  pD3D12Enc->m_BitstreamHeadersBuffer,
1455                                                                  pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenAUDBytesCount + writtenVPSBytesCount,
1456                                                                  writtenSPSBytesCount);
1457       pHEVCBitstreamBuilder->set_active_sps(sps);
1458       pWrittenCodecUnitsSizes.push_back(writtenSPSBytesCount);
1459    }
1460 
1461    size_t writtenPPSBytesCount = 0;
1462    HevcPicParameterSet tentative_pps = pHEVCBitstreamBuilder->build_pps(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificPictureStateDescH265,
1463                                                                         pHEVCBitstreamBuilder->get_active_sps(),
1464                                                                         currentPicParams.pHEVCPicData->slice_pic_parameter_set_id,
1465                                                                         *codecConfigDesc.pHEVCConfig,
1466                                                                         *currentPicParams.pHEVCPicData1,
1467                                                                         pD3D12Enc->m_StagingHeadersBuffer,
1468                                                                         pD3D12Enc->m_StagingHeadersBuffer.begin(),
1469                                                                         writtenPPSBytesCount);
1470 
1471    const HevcPicParameterSet &active_pps = pHEVCBitstreamBuilder->get_active_pps();
1472    bool forceWritePPS = (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_picture_header);
1473    if (forceWritePPS || d3d12_video_encoder_needs_new_pps_hevc(pD3D12Enc, writeNewSPS, tentative_pps, active_pps)) {
1474       pHEVCBitstreamBuilder->set_active_pps(tentative_pps);
1475       pD3D12Enc->m_BitstreamHeadersBuffer.resize(writtenAUDBytesCount + writtenVPSBytesCount + writtenSPSBytesCount + writtenPPSBytesCount);
1476       memcpy(&pD3D12Enc->m_BitstreamHeadersBuffer.data()[(writtenAUDBytesCount + writtenVPSBytesCount + writtenSPSBytesCount)], pD3D12Enc->m_StagingHeadersBuffer.data(), writtenPPSBytesCount);
1477       pWrittenCodecUnitsSizes.push_back(writtenPPSBytesCount);
1478    } else {
1479       writtenPPSBytesCount = 0;
1480       debug_printf("Skipping PPS (same as active PPS) for fenceValue: %" PRIu64 "\n", pD3D12Enc->m_fenceValue);
1481    }
1482 
1483    // Shrink buffer to fit the headers
1484    if (pD3D12Enc->m_BitstreamHeadersBuffer.size() > (writtenAUDBytesCount + writtenVPSBytesCount + writtenSPSBytesCount + writtenPPSBytesCount)) {
1485       pD3D12Enc->m_BitstreamHeadersBuffer.resize(writtenAUDBytesCount + writtenVPSBytesCount + writtenSPSBytesCount + writtenPPSBytesCount);
1486    }
1487 
1488    assert(std::accumulate(pWrittenCodecUnitsSizes.begin(), pWrittenCodecUnitsSizes.end(), 0u) ==
1489       static_cast<uint64_t>(pD3D12Enc->m_BitstreamHeadersBuffer.size()));
1490    return pD3D12Enc->m_BitstreamHeadersBuffer.size();
1491 }
1492