• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © Microsoft Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "d3d12_video_enc.h"
25 #include "d3d12_video_enc_h264.h"
26 #include "util/u_video.h"
27 #include "d3d12_screen.h"
28 #include "d3d12_format.h"
29 
30 #include <cmath>
31 #include <algorithm>
32 #include <numeric>
33 
34 void
d3d12_video_encoder_update_current_rate_control_h264(struct d3d12_video_encoder * pD3D12Enc,pipe_h264_enc_picture_desc * picture)35 d3d12_video_encoder_update_current_rate_control_h264(struct d3d12_video_encoder *pD3D12Enc,
36                                                      pipe_h264_enc_picture_desc *picture)
37 {
38    struct pipe_h264_enc_picture_desc *h264Pic = (struct pipe_h264_enc_picture_desc *) picture;
39 
40    assert(h264Pic->pic_ctrl.temporal_id < ARRAY_SIZE(pipe_h264_enc_picture_desc::rate_ctrl));
41    assert(h264Pic->pic_ctrl.temporal_id < std::max(1u, pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH264.num_temporal_layers));
42    assert(h264Pic->pic_ctrl.temporal_id < ARRAY_SIZE(D3D12EncodeConfiguration::m_encoderRateControlDesc));
43 
44    struct D3D12EncodeRateControlState m_prevRCState = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic_ctrl.temporal_id];
45    pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex = h264Pic->pic_ctrl.temporal_id;
46    pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id] = {};
47    pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_FrameRate.Numerator =
48       picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].frame_rate_num;
49    pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_FrameRate.Denominator =
50       picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].frame_rate_den;
51    pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
52 
53    if (picture->roi.num > 0)
54       pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
55          D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP;
56 
57    switch (picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].rate_ctrl_method) {
58       case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP:
59       case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE:
60       {
61          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR;
62          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_VBR.TargetAvgBitRate =
63             picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].target_bitrate;
64          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_VBR.PeakBitRate =
65             picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].peak_bitrate;
66 
67          if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
68             debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
69                        ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate);
70             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
71                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
72             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.VBVCapacity =
73                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate;
74             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.InitialVBVFullness =
75                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate;
76          } else if (picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].app_requested_hrd_buffer) {
77             debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 HRD required by app,"
78                        " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbv_buffer_size, picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbv_buf_initial_size);
79             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
80                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
81             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_VBR.VBVCapacity =
82                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbv_buffer_size;
83             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_VBR.InitialVBVFullness =
84                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbv_buf_initial_size;
85          }
86 
87          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].max_frame_size = picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_au_size;
88          if (picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_au_size > 0) {
89             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
90                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
91             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_VBR.MaxFrameBitSize =
92                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_au_size;
93 
94             debug_printf(
95                "[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
96                "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
97                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_VBR.MaxFrameBitSize);
98          }
99 
100          if (picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].app_requested_qp_range) {
101             debug_printf(
102                "[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
103                "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
104                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].min_qp, picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_qp);
105             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
106                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
107             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_VBR.MinQP =
108                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].min_qp;
109             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_VBR.MaxQP =
110                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_qp;
111          }
112 
113          if (picture->quality_modes.level > 0) {
114             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
115                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
116             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
117                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
118 
119             // Convert between D3D12 definition and PIPE definition
120             // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
121             // The lower the value, the fastest the encode operation
122             // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
123             // A lower value means higher quality, and a value of 1 represents the highest quality.
124             // The quality level setting is used as a trade-off between quality and speed/power
125             // consumption, with higher quality corresponds to lower speed and higher power consumption.
126 
127             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_VBR1.QualityVsSpeed =
128                pD3D12Enc->max_quality_levels - picture->quality_modes.level;
129          }
130 
131       } break;
132       case PIPE_H2645_ENC_RATE_CONTROL_METHOD_QUALITY_VARIABLE:
133       {
134          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR;
135          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR.TargetAvgBitRate =
136             picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].target_bitrate;
137          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR.PeakBitRate =
138             picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].peak_bitrate;
139             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR.ConstantQualityTarget =
140             picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbr_quality_factor;
141 
142          if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
143             debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
144                        ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR1.TargetAvgBitRate);
145             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
146                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
147             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
148                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
149             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR1.VBVCapacity =
150                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
151             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR1.InitialVBVFullness =
152                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
153          } else if (picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].app_requested_hrd_buffer) {
154             debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 HRD required by app,"
155                        " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbv_buffer_size, picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbv_buf_initial_size);
156             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
157                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
158             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
159                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
160             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR1.VBVCapacity =
161                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbv_buffer_size;
162             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR1.InitialVBVFullness =
163                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbv_buf_initial_size;
164          }
165       pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].max_frame_size = picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_au_size;
166       if (picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_au_size > 0) {
167             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
168                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
169             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR.MaxFrameBitSize =
170                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_au_size;
171 
172             debug_printf(
173                "[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
174                "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
175                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR.MaxFrameBitSize);
176          }
177 
178          if (picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].app_requested_qp_range) {
179             debug_printf(
180                "[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
181                "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
182                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].min_qp, picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_qp);
183             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
184                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
185             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR.MinQP =
186                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].min_qp;
187             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR.MaxQP =
188                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_qp;
189          }
190          if (picture->quality_modes.level > 0) {
191             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
192                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
193             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
194                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
195 
196             // Convert between D3D12 definition and PIPE definition
197             // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
198             // The lower the value, the fastest the encode operation
199             // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
200             // A lower value means higher quality, and a value of 1 represents the highest quality.
201             // The quality level setting is used as a trade-off between quality and speed/power
202             // consumption, with higher quality corresponds to lower speed and higher power consumption.
203 
204             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_QVBR1.QualityVsSpeed =
205                pD3D12Enc->max_quality_levels - picture->quality_modes.level;
206          }
207       } break;
208       case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP:
209       case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT:
210       {
211          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR;
212          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate =
213             picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].target_bitrate;
214 
215          /* For CBR mode, to guarantee bitrate of generated stream complies with
216           * target bitrate (e.g. no over +/-10%), vbv_buffer_size and initial capacity should be same
217           * as target bitrate. Controlled by OS env var D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE
218           */
219          if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
220             debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
221                        ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate);
222             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
223                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
224             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.VBVCapacity =
225                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate;
226             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.InitialVBVFullness =
227                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.TargetBitRate;
228          } else if (picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].app_requested_hrd_buffer) {
229             debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 HRD required by app,"
230                        " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbv_buffer_size, picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbv_buf_initial_size);
231             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
232                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
233             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.VBVCapacity =
234                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbv_buffer_size;
235             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.InitialVBVFullness =
236                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].vbv_buf_initial_size;
237          }
238 
239          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].max_frame_size = picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_au_size;
240          if (picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_au_size > 0) {
241             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
242                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
243             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.MaxFrameBitSize =
244                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_au_size;
245 
246             debug_printf(
247                "[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
248                "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
249                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.MaxFrameBitSize);
250          }
251 
252          if (picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].app_requested_qp_range) {
253             debug_printf(
254                "[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
255                "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
256                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].min_qp, picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_qp);
257 
258             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
259                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
260             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.MinQP =
261                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].min_qp;
262             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR.MaxQP =
263                picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].max_qp;
264          }
265 
266          if (picture->quality_modes.level > 0) {
267             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
268                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
269             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
270                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
271 
272             // Convert between D3D12 definition and PIPE definition
273             // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
274             // The lower the value, the fastest the encode operation
275             // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
276             // A lower value means higher quality, and a value of 1 represents the highest quality.
277             // The quality level setting is used as a trade-off between quality and speed/power
278             // consumption, with higher quality corresponds to lower speed and higher power consumption.
279 
280             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CBR1.QualityVsSpeed =
281                pD3D12Enc->max_quality_levels - picture->quality_modes.level;
282          }
283       } break;
284       case PIPE_H2645_ENC_RATE_CONTROL_METHOD_DISABLE:
285       {
286          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
287 
288          // Load previous RC state for all frames and only update the current frame
289          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CQP =
290                   m_prevRCState.m_Config.m_Configuration_CQP;
291          switch (picture->picture_type) {
292             case PIPE_H2645_ENC_PICTURE_TYPE_P:
293             {
294                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CQP
295                   .ConstantQP_InterPredictedFrame_PrevRefOnly = picture->quant_p_frames;
296             } break;
297             case PIPE_H2645_ENC_PICTURE_TYPE_B:
298             {
299                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CQP
300                   .ConstantQP_InterPredictedFrame_BiDirectionalRef = picture->quant_b_frames;
301             } break;
302             case PIPE_H2645_ENC_PICTURE_TYPE_I:
303             case PIPE_H2645_ENC_PICTURE_TYPE_IDR:
304             {
305                pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CQP
306                   .ConstantQP_FullIntracodedFrame = picture->quant_i_frames;
307             } break;
308             default:
309             {
310                unreachable("Unsupported pipe_h2645_enc_picture_type");
311             } break;
312          }
313 
314          if (picture->quality_modes.level > 0) {
315             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
316                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
317             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |=
318                D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
319 
320             // Convert between D3D12 definition and PIPE definition
321             // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
322             // The lower the value, the fastest the encode operation
323             // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
324             // A lower value means higher quality, and a value of 1 represents the highest quality.
325             // The quality level setting is used as a trade-off between quality and speed/power
326             // consumption, with higher quality corresponds to lower speed and higher power consumption.
327 
328             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CQP1.QualityVsSpeed =
329                pD3D12Enc->max_quality_levels - picture->quality_modes.level;
330          }
331       } break;
332       default:
333       {
334          debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 invalid RC "
335                        "config, using default RC CQP mode\n");
336          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
337          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CQP
338             .ConstantQP_FullIntracodedFrame = 30;
339          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CQP
340             .ConstantQP_InterPredictedFrame_PrevRefOnly = 30;
341          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Config.m_Configuration_CQP
342             .ConstantQP_InterPredictedFrame_BiDirectionalRef = 30;
343       } break;
344    }
345 }
346 
347 void
d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video_encoder * pD3D12Enc,struct pipe_video_buffer * srcTexture,struct pipe_picture_desc * picture,D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA & picParams,bool & bUsedAsReference)348 d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video_encoder *pD3D12Enc,
349                                                               struct pipe_video_buffer *srcTexture,
350                                                               struct pipe_picture_desc *picture,
351                                                               D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &picParams,
352                                                               bool &bUsedAsReference)
353 {
354    struct pipe_h264_enc_picture_desc *h264Pic = (struct pipe_h264_enc_picture_desc *) picture;
355    d3d12_video_bitstream_builder_h264 *pH264BitstreamBuilder =
356       static_cast<d3d12_video_bitstream_builder_h264 *>(pD3D12Enc->m_upBitstreamBuilder.get());
357    assert(pH264BitstreamBuilder != nullptr);
358 
359    pD3D12Enc->m_currentEncodeConfig.m_bUsedAsReference = !h264Pic->not_referenced;
360    bUsedAsReference = pD3D12Enc->m_currentEncodeConfig.m_bUsedAsReference;
361 
362    if (pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_H264CodecCaps.SupportFlags &
363        D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264_FLAG_NUM_REF_IDX_ACTIVE_OVERRIDE_FLAG_SLICE_SUPPORT)
364    {
365       picParams.pH264PicData->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_FLAG_REQUEST_NUM_REF_IDX_ACTIVE_OVERRIDE_FLAG_SLICE;
366    }
367 
368    //
369    // These need to be set here so they're available for SPS/PPS header building (reference manager updates after that, for slice header params)
370    //
371    picParams.pH264PicData->TemporalLayerIndex = h264Pic->pic_ctrl.temporal_id;
372    picParams.pH264PicData->pic_parameter_set_id = pH264BitstreamBuilder->get_active_pps().pic_parameter_set_id;
373    picParams.pH264PicData->List0ReferenceFramesCount = 0;
374    picParams.pH264PicData->List1ReferenceFramesCount = 0;
375    if ((h264Pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_P) ||
376        (h264Pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B))
377       picParams.pH264PicData->List0ReferenceFramesCount = h264Pic->num_ref_idx_l0_active_minus1 + 1;
378 
379    if (h264Pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B)
380       picParams.pH264PicData->List1ReferenceFramesCount = h264Pic->num_ref_idx_l1_active_minus1 + 1;
381 
382    if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0)
383    {
384       // Use 8 bit qpmap array for H264 picparams (-51, 51 range and int8_t pRateControlQPMap type)
385       const int32_t h264_min_delta_qp = -51;
386       const int32_t h264_max_delta_qp = 51;
387       d3d12_video_encoder_update_picparams_region_of_interest_qpmap(
388          pD3D12Enc,
389          &h264Pic->roi,
390          h264_min_delta_qp,
391          h264_max_delta_qp,
392          pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_pRateControlQPMap8Bit);
393       picParams.pH264PicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_pRateControlQPMap8Bit.data();
394       picParams.pH264PicData->QPMapValuesCount = static_cast<UINT>(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_pRateControlQPMap8Bit.size());
395    }
396 
397    pD3D12Enc->m_upDPBManager->begin_frame(picParams, bUsedAsReference, picture);
398    pD3D12Enc->m_upDPBManager->get_current_frame_picture_control_data(picParams);
399 
400    // Save state snapshot from record time to resolve headers at get_feedback time
401    size_t current_metadata_slot = static_cast<size_t>(pD3D12Enc->m_fenceValue % D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT);
402    pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeCapabilities =
403       pD3D12Enc->m_currentEncodeCapabilities;
404    pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig =
405       pD3D12Enc->m_currentEncodeConfig;
406 }
407 
408 ///
409 /// Tries to configurate the encoder using the requested slice configuration
410 /// or falls back to single slice encoding.
411 ///
412 bool
d3d12_video_encoder_negotiate_current_h264_slices_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h264_enc_picture_desc * picture)413 d3d12_video_encoder_negotiate_current_h264_slices_configuration(struct d3d12_video_encoder *pD3D12Enc,
414                                                                 pipe_h264_enc_picture_desc *picture)
415 {
416    ///
417    /// Initialize single slice by default
418    ///
419    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode =
420       D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
421    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES requestedSlicesConfig = {};
422    requestedSlicesConfig.NumberOfSlicesPerFrame = 1;
423 
424    ///
425    /// Try to see if can accomodate for multi-slice request by user
426    ///
427    if ((picture->slice_mode == PIPE_VIDEO_SLICE_MODE_BLOCKS) && (picture->num_slice_descriptors > 1)) {
428       /* Some apps send all same size slices minus 1 slice in any position in the descriptors */
429       /* Lets validate that there are at most 2 different slice sizes in all the descriptors */
430       std::vector<int> slice_sizes(picture->num_slice_descriptors);
431       for (uint32_t i = 0; i < picture->num_slice_descriptors; i++)
432          slice_sizes[i] = picture->slices_descriptors[i].num_macroblocks;
433       std::sort(slice_sizes.begin(), slice_sizes.end());
434       bool bUniformSizeSlices = (std::unique(slice_sizes.begin(), slice_sizes.end()) - slice_sizes.begin()) <= 2;
435 
436       uint32_t mbPerScanline =
437          pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width / D3D12_VIDEO_H264_MB_IN_PIXELS;
438       bool bSliceAligned = ((picture->slices_descriptors[0].num_macroblocks % mbPerScanline) == 0);
439 
440       if (bUniformSizeSlices) {
441          if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_NONE) {
442             /*
443             * When intra-refresh is active, we must use D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME
444             */
445             if (d3d12_video_encoder_check_subregion_mode_support(
446                      pD3D12Enc,
447                      D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME)) {
448                requestedSlicesMode =
449                   D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
450                requestedSlicesConfig.NumberOfSlicesPerFrame = picture->num_slice_descriptors;
451                debug_printf("[d3d12_video_encoder_h264] Intra-refresh is active and per DX12 spec it requires using multi slice encoding mode: "
452                               "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
453                               "with %d slices per frame.\n",
454                               requestedSlicesConfig.NumberOfSlicesPerFrame);
455             } else {
456                debug_printf("[d3d12_video_encoder_h264] Intra-refresh is active which requires "
457                               "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
458                               "mode but there is HW support for such mode.\n");
459                return false;
460             }
461          } else if (bSliceAligned &&
462                   d3d12_video_encoder_check_subregion_mode_support(
463                      pD3D12Enc,
464                      D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION)) {
465 
466             // Number of macroblocks per slice is aligned to a scanline width, in which case we can
467             // use D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION
468             requestedSlicesMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION;
469             requestedSlicesConfig.NumberOfRowsPerSlice = (picture->slices_descriptors[0].num_macroblocks / mbPerScanline);
470             debug_printf("[d3d12_video_encoder_h264] Using multi slice encoding mode: "
471                            "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION with "
472                            "%d macroblocks rows per slice.\n",
473                            requestedSlicesConfig.NumberOfRowsPerSlice);
474          } else if (d3d12_video_encoder_check_subregion_mode_support(
475                      pD3D12Enc,
476                      D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME)) {
477                requestedSlicesMode =
478                   D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
479                requestedSlicesConfig.NumberOfSlicesPerFrame = picture->num_slice_descriptors;
480                debug_printf("[d3d12_video_encoder_h264] Using multi slice encoding mode: "
481                               "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
482                               "with %d slices per frame.\n",
483                               requestedSlicesConfig.NumberOfSlicesPerFrame);
484          } else if (d3d12_video_encoder_check_subregion_mode_support(
485                      pD3D12Enc,
486                      D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED)) {
487                requestedSlicesMode =
488                   D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED;
489                requestedSlicesConfig.NumberOfCodingUnitsPerSlice = picture->slices_descriptors[0].num_macroblocks;
490                debug_printf("[d3d12_video_encoder_h264] Using multi slice encoding mode: "
491                               "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED "
492                               "with %d NumberOfCodingUnitsPerSlice per frame.\n",
493                               requestedSlicesConfig.NumberOfCodingUnitsPerSlice);
494          } else {
495             debug_printf("[d3d12_video_encoder_h264] Requested slice control mode is not supported by hardware: No HW support for "
496                            "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION or"
497                            "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME or"
498                            "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED.\n");
499             return false;
500          }
501       } else {
502          debug_printf("[d3d12_video_encoder_h264] Requested slice control mode is not supported: All slices must "
503                          "have the same number of macroblocks.\n");
504          return false;
505       }
506    } else if(picture->slice_mode == PIPE_VIDEO_SLICE_MODE_MAX_SLICE_SIZE) {
507       if ((picture->max_slice_bytes > 0) &&
508                  d3d12_video_encoder_check_subregion_mode_support(
509                     pD3D12Enc,
510                     D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION )) {
511             requestedSlicesMode =
512                D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION;
513             requestedSlicesConfig.MaxBytesPerSlice = picture->max_slice_bytes;
514             debug_printf("[d3d12_video_encoder_h264] Using multi slice encoding mode: "
515                            "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION  "
516                            "with %d MaxBytesPerSlice per frame.\n",
517                            requestedSlicesConfig.MaxBytesPerSlice);
518       } else {
519          debug_printf("[d3d12_video_encoder_h264] Requested slice control mode is not supported: No HW support for "
520                          "D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION.\n");
521          return false;
522       }
523    } else {
524       requestedSlicesMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
525       requestedSlicesConfig.NumberOfSlicesPerFrame = 1;
526       debug_printf("[d3d12_video_encoder_h264] Requested slice control mode is full frame. m_SlicesPartition_H264.NumberOfSlicesPerFrame = %d - m_encoderSliceConfigMode = %d \n",
527       requestedSlicesConfig.NumberOfSlicesPerFrame, requestedSlicesMode);
528    }
529 
530    if (!d3d12_video_encoder_compare_slice_config_h264_hevc(
531           pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
532           pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264,
533           requestedSlicesMode,
534           requestedSlicesConfig)) {
535       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_slices;
536    }
537 
538    pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264 = requestedSlicesConfig;
539    pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode = requestedSlicesMode;
540 
541    return true;
542 }
543 
544 D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE
d3d12_video_encoder_convert_h264_motion_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h264_enc_picture_desc * picture)545 d3d12_video_encoder_convert_h264_motion_configuration(struct d3d12_video_encoder *pD3D12Enc,
546                                                       pipe_h264_enc_picture_desc *picture)
547 {
548    return D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM;
549 }
550 
551 D3D12_VIDEO_ENCODER_LEVELS_H264
d3d12_video_encoder_convert_level_h264(uint32_t h264SpecLevel)552 d3d12_video_encoder_convert_level_h264(uint32_t h264SpecLevel)
553 {
554    switch (h264SpecLevel) {
555       case 10:
556       {
557          return D3D12_VIDEO_ENCODER_LEVELS_H264_1;
558       } break;
559       case 11:
560       {
561          return D3D12_VIDEO_ENCODER_LEVELS_H264_11;
562       } break;
563       case 12:
564       {
565          return D3D12_VIDEO_ENCODER_LEVELS_H264_12;
566       } break;
567       case 13:
568       {
569          return D3D12_VIDEO_ENCODER_LEVELS_H264_13;
570       } break;
571       case 20:
572       {
573          return D3D12_VIDEO_ENCODER_LEVELS_H264_2;
574       } break;
575       case 21:
576       {
577          return D3D12_VIDEO_ENCODER_LEVELS_H264_21;
578       } break;
579       case 22:
580       {
581          return D3D12_VIDEO_ENCODER_LEVELS_H264_22;
582       } break;
583       case 30:
584       {
585          return D3D12_VIDEO_ENCODER_LEVELS_H264_3;
586       } break;
587       case 31:
588       {
589          return D3D12_VIDEO_ENCODER_LEVELS_H264_31;
590       } break;
591       case 32:
592       {
593          return D3D12_VIDEO_ENCODER_LEVELS_H264_32;
594       } break;
595       case 40:
596       {
597          return D3D12_VIDEO_ENCODER_LEVELS_H264_4;
598       } break;
599       case 41:
600       {
601          return D3D12_VIDEO_ENCODER_LEVELS_H264_41;
602       } break;
603       case 42:
604       {
605          return D3D12_VIDEO_ENCODER_LEVELS_H264_42;
606       } break;
607       case 50:
608       {
609          return D3D12_VIDEO_ENCODER_LEVELS_H264_5;
610       } break;
611       case 51:
612       {
613          return D3D12_VIDEO_ENCODER_LEVELS_H264_51;
614       } break;
615       case 52:
616       {
617          return D3D12_VIDEO_ENCODER_LEVELS_H264_52;
618       } break;
619       case 60:
620       {
621          return D3D12_VIDEO_ENCODER_LEVELS_H264_6;
622       } break;
623       case 61:
624       {
625          return D3D12_VIDEO_ENCODER_LEVELS_H264_61;
626       } break;
627       case 62:
628       {
629          return D3D12_VIDEO_ENCODER_LEVELS_H264_62;
630       } break;
631       default:
632       {
633          unreachable("Unsupported H264 level");
634       } break;
635    }
636 }
637 
638 void
d3d12_video_encoder_convert_from_d3d12_level_h264(D3D12_VIDEO_ENCODER_LEVELS_H264 level12,uint32_t & specLevel)639 d3d12_video_encoder_convert_from_d3d12_level_h264(D3D12_VIDEO_ENCODER_LEVELS_H264 level12,
640                                                   uint32_t &specLevel)
641 {
642    specLevel = 0;
643 
644    switch (level12) {
645       case D3D12_VIDEO_ENCODER_LEVELS_H264_1:
646       {
647          specLevel = 10;
648       } break;
649       case D3D12_VIDEO_ENCODER_LEVELS_H264_1b:
650       {
651          specLevel = 11;
652       } break;
653       case D3D12_VIDEO_ENCODER_LEVELS_H264_11:
654       {
655          specLevel = 11;
656       } break;
657       case D3D12_VIDEO_ENCODER_LEVELS_H264_12:
658       {
659          specLevel = 12;
660       } break;
661       case D3D12_VIDEO_ENCODER_LEVELS_H264_13:
662       {
663          specLevel = 13;
664       } break;
665       case D3D12_VIDEO_ENCODER_LEVELS_H264_2:
666       {
667          specLevel = 20;
668       } break;
669       case D3D12_VIDEO_ENCODER_LEVELS_H264_21:
670       {
671          specLevel = 21;
672       } break;
673       case D3D12_VIDEO_ENCODER_LEVELS_H264_22:
674       {
675          specLevel = 22;
676       } break;
677       case D3D12_VIDEO_ENCODER_LEVELS_H264_3:
678       {
679          specLevel = 30;
680       } break;
681       case D3D12_VIDEO_ENCODER_LEVELS_H264_31:
682       {
683          specLevel = 31;
684       } break;
685       case D3D12_VIDEO_ENCODER_LEVELS_H264_32:
686       {
687          specLevel = 32;
688       } break;
689       case D3D12_VIDEO_ENCODER_LEVELS_H264_4:
690       {
691          specLevel = 40;
692       } break;
693       case D3D12_VIDEO_ENCODER_LEVELS_H264_41:
694       {
695          specLevel = 41;
696       } break;
697       case D3D12_VIDEO_ENCODER_LEVELS_H264_42:
698       {
699          specLevel = 42;
700       } break;
701       case D3D12_VIDEO_ENCODER_LEVELS_H264_5:
702       {
703          specLevel = 50;
704       } break;
705       case D3D12_VIDEO_ENCODER_LEVELS_H264_51:
706       {
707          specLevel = 51;
708       } break;
709       case D3D12_VIDEO_ENCODER_LEVELS_H264_52:
710       {
711          specLevel = 52;
712       } break;
713       case D3D12_VIDEO_ENCODER_LEVELS_H264_6:
714       {
715          specLevel = 60;
716       } break;
717       case D3D12_VIDEO_ENCODER_LEVELS_H264_61:
718       {
719          specLevel = 61;
720       } break;
721       case D3D12_VIDEO_ENCODER_LEVELS_H264_62:
722       {
723          specLevel = 62;
724       } break;
725       default:
726       {
727          unreachable("Unsupported D3D12_VIDEO_ENCODER_LEVELS_H264 value");
728       } break;
729    }
730 }
731 
732 bool
d3d12_video_encoder_update_h264_gop_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h264_enc_picture_desc * picture)733 d3d12_video_encoder_update_h264_gop_configuration(struct d3d12_video_encoder *pD3D12Enc,
734                                                   pipe_h264_enc_picture_desc *picture)
735 {
736    // Only update GOP when it begins
737    // Only update GOP when it begins
738    // This triggers DPB/encoder/heap re-creation, so only check on IDR when a GOP might change
739    if ((picture->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR)
740       || (picture->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_I)) {
741       uint32_t GOPLength = picture->intra_idr_period;
742       uint32_t PPicturePeriod = picture->ip_period;
743 
744       if (picture->seq.pic_order_cnt_type == 1u) {
745          debug_printf("[d3d12_video_encoder_h264] Upper layer is requesting pic_order_cnt_type %d but D3D12 Video "
746                          "only supports pic_order_cnt_type = 0 or pic_order_cnt_type = 2\n",
747                          picture->seq.pic_order_cnt_type);
748          return false;
749       }
750 
751       // Workaround: D3D12 needs to use the POC in the DPB to track reference frames
752       // even when there's no frame reordering (picture->seq.pic_order_cnt_type == 2)
753       // So in that case, derive an artificial log2_max_pic_order_cnt_lsb_minus4
754       // to avoid unexpected wrapping
755       if (picture->seq.pic_order_cnt_type == 2u) {
756          if (GOPLength == 0) // Use max frame num to wrap on infinite GOPs
757             GOPLength = 1 << (picture->seq.log2_max_frame_num_minus4 + 4);
758          const uint32_t max_pic_order_cnt_lsb = 2 * GOPLength;
759          picture->seq.log2_max_pic_order_cnt_lsb_minus4 = static_cast<unsigned int>(std::max(0.0, std::ceil(std::log2(max_pic_order_cnt_lsb)) - 4));
760          assert(picture->seq.log2_max_pic_order_cnt_lsb_minus4 < UCHAR_MAX);
761       }
762 
763       assert(picture->seq.pic_order_cnt_type < UCHAR_MAX);
764 
765       // Set dirty flag if m_H264GroupOfPictures changed
766       auto previousGOPConfig = pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures;
767       pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures = {
768          GOPLength,
769          PPicturePeriod,
770          static_cast<uint8_t>(picture->seq.pic_order_cnt_type),
771          static_cast<uint8_t>(picture->seq.log2_max_frame_num_minus4),
772          static_cast<uint8_t>(picture->seq.log2_max_pic_order_cnt_lsb_minus4)
773       };
774 
775       if (memcmp(&previousGOPConfig,
776                  &pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures,
777                  sizeof(D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_H264)) != 0) {
778          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_gop;
779       }
780    }
781    return true;
782 }
783 
784 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264
d3d12_video_encoder_convert_h264_codec_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_h264_enc_picture_desc * picture,bool & is_supported)785 d3d12_video_encoder_convert_h264_codec_configuration(struct d3d12_video_encoder *pD3D12Enc,
786                                                      pipe_h264_enc_picture_desc *picture,
787                                                      bool &is_supported)
788 {
789    is_supported = true;
790    D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 config = {
791       D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_NONE,
792       D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_DIRECT_MODES_DISABLED,
793       // Definition of D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_SLICES_DEBLOCKING_MODES matches disable_deblocking_filter_idc syntax
794       static_cast<D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_SLICES_DEBLOCKING_MODES>(picture->dbk.disable_deblocking_filter_idc),
795    };
796 
797    if (picture->pic_ctrl.enc_cabac_enable) {
798       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING;
799    }
800 
801    if (picture->pic_ctrl.constrained_intra_pred_flag) {
802       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_USE_CONSTRAINED_INTRAPREDICTION;
803    }
804 
805    if (picture->pic_ctrl.transform_8x8_mode_flag) {
806       config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_USE_ADAPTIVE_8x8_TRANSFORM;
807    }
808 
809    pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_H264CodecCaps =
810    {
811       D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264_FLAG_NONE,
812       D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_SLICES_DEBLOCKING_MODE_FLAG_NONE
813    };
814 
815    D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = { };
816    capCodecConfigData.NodeIndex = pD3D12Enc->m_NodeIndex;
817    capCodecConfigData.Codec = D3D12_VIDEO_ENCODER_CODEC_H264;
818    D3D12_VIDEO_ENCODER_PROFILE_H264 prof = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(pD3D12Enc->base.profile);
819    capCodecConfigData.Profile.pH264Profile = &prof;
820    capCodecConfigData.Profile.DataSize = sizeof(prof);
821    capCodecConfigData.CodecSupportLimits.pH264Support = &pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_H264CodecCaps;
822    capCodecConfigData.CodecSupportLimits.DataSize = sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_H264CodecCaps);
823 
824    if(FAILED(pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData)))
825       || !capCodecConfigData.IsSupported)
826    {
827          debug_printf("D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT call failed.");
828          is_supported = false;
829          return config;
830    }
831 
832    if(((1 << config.DisableDeblockingFilterConfig) & capCodecConfigData.CodecSupportLimits.pH264Support->DisableDeblockingFilterSupportedModes) == 0)
833    {
834          debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments not supported - DisableDeblockingFilterConfig (value %d) "
835                   "not allowed by DisableDeblockingFilterSupportedModes 0x%x cap reporting.",
836                   config.DisableDeblockingFilterConfig,
837                   capCodecConfigData.CodecSupportLimits.pH264Support->DisableDeblockingFilterSupportedModes);
838          is_supported = false;
839          return config;
840    }
841 
842    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING) != 0)
843       && ((capCodecConfigData.CodecSupportLimits.pH264Support->SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264_FLAG_CABAC_ENCODING_SUPPORT) == 0))
844    {
845       debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - CABAC encoding mode not supported."
846          " Ignoring the request for this feature flag on this encode session");
847          // Disable it and keep going with a warning
848          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING;
849    }
850 
851    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_USE_CONSTRAINED_INTRAPREDICTION) != 0)
852       && ((capCodecConfigData.CodecSupportLimits.pH264Support->SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264_FLAG_CONSTRAINED_INTRAPREDICTION_SUPPORT) == 0))
853    {
854       debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - constrained_intra_pred_flag not supported."
855          " Ignoring the request for this feature flag on this encode session");
856          // Disable it and keep going with a warning
857          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_USE_CONSTRAINED_INTRAPREDICTION;
858    }
859 
860    if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_USE_ADAPTIVE_8x8_TRANSFORM) != 0)
861       && ((capCodecConfigData.CodecSupportLimits.pH264Support->SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264_FLAG_ADAPTIVE_8x8_TRANSFORM_ENCODING_SUPPORT) == 0))
862    {
863       debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - transform_8x8_mode_flag not supported."
864          " Ignoring the request for this feature flag on this encode session");
865          // Disable it and keep going with a warning
866          config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_USE_ADAPTIVE_8x8_TRANSFORM;
867    }
868 
869    return config;
870 }
871 
872 static bool
d3d12_video_encoder_update_intra_refresh_h264(struct d3d12_video_encoder * pD3D12Enc,D3D12_VIDEO_SAMPLE srcTextureDesc,struct pipe_h264_enc_picture_desc * picture)873 d3d12_video_encoder_update_intra_refresh_h264(struct d3d12_video_encoder *pD3D12Enc,
874                                                         D3D12_VIDEO_SAMPLE srcTextureDesc,
875                                                         struct pipe_h264_enc_picture_desc *  picture)
876 {
877    if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_NONE)
878    {
879       // D3D12 only supports row intra-refresh
880       if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_UNIT_ROWS)
881       {
882          debug_printf("[d3d12_video_encoder_update_intra_refresh_h264] Unsupported INTRA_REFRESH_MODE %d\n", picture->intra_refresh.mode);
883          return false;
884       }
885 
886       uint32_t total_frame_blocks = static_cast<uint32_t>(std::ceil(srcTextureDesc.Height / D3D12_VIDEO_H264_MB_IN_PIXELS)) *
887                               static_cast<uint32_t>(std::ceil(srcTextureDesc.Width / D3D12_VIDEO_H264_MB_IN_PIXELS));
888       D3D12_VIDEO_ENCODER_INTRA_REFRESH targetIntraRefresh = {
889          D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ROW_BASED,
890          total_frame_blocks / picture->intra_refresh.region_size,
891       };
892       double ir_wave_progress = (picture->intra_refresh.offset == 0) ? 0 :
893          picture->intra_refresh.offset / (double) total_frame_blocks;
894       pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex =
895          static_cast<uint32_t>(std::ceil(ir_wave_progress * targetIntraRefresh.IntraRefreshDuration));
896 
897       // Set intra refresh state
898       pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = targetIntraRefresh;
899       // Need to send the sequence flag during all the IR duration
900       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_intra_refresh;
901    } else {
902       pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex = 0;
903       pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = {
904          D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
905          0,
906       };
907    }
908 
909    return true;
910 }
911 
912 bool
d3d12_video_encoder_update_current_encoder_config_state_h264(struct d3d12_video_encoder * pD3D12Enc,D3D12_VIDEO_SAMPLE srcTextureDesc,struct pipe_picture_desc * picture)913 d3d12_video_encoder_update_current_encoder_config_state_h264(struct d3d12_video_encoder *pD3D12Enc,
914                                                              D3D12_VIDEO_SAMPLE srcTextureDesc,
915                                                              struct pipe_picture_desc *picture)
916 {
917    struct pipe_h264_enc_picture_desc *h264Pic = (struct pipe_h264_enc_picture_desc *) picture;
918 
919    // Reset reconfig dirty flags
920    pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags = d3d12_video_encoder_config_dirty_flag_none;
921    // Reset sequence changes flags
922    pD3D12Enc->m_currentEncodeConfig.m_seqFlags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE;
923 
924    // Set codec
925    if (pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc != D3D12_VIDEO_ENCODER_CODEC_H264) {
926       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec;
927    }
928    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc = D3D12_VIDEO_ENCODER_CODEC_H264;
929 
930    // Set Sequence information
931    if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH264,
932               &h264Pic->seq,
933               sizeof(h264Pic->seq)) != 0) {
934       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sequence_header;
935    }
936    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH264 = h264Pic->seq;
937 
938    // Iterate over the headers the app requested and set flags to emit those for this frame
939    util_dynarray_foreach(&h264Pic->raw_headers, struct pipe_enc_raw_header, header) {
940       if (header->type == PIPE_H264_NAL_SPS)
941          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sequence_header;
942       else if (header->type == PIPE_H264_NAL_PPS)
943          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_picture_header;
944       else if (header->type == PIPE_H264_NAL_AUD)
945          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_aud_header;
946       else if (header->type == NAL_TYPE_SEI)
947          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sei_header;
948       else if (header->type == NAL_TYPE_PREFIX)
949          pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_svcprefix_slice_header;
950    }
951 
952    // Set input format
953    DXGI_FORMAT targetFmt = d3d12_convert_pipe_video_profile_to_dxgi_format(pD3D12Enc->base.profile);
954    if (pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format != targetFmt) {
955       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_input_format;
956    }
957 
958    pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo = {};
959    pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format = targetFmt;
960    HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO,
961                                                           &pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo,
962                                                           sizeof(pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo));
963    if (FAILED(hr)) {
964       debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
965       return false;
966    }
967 
968    // Set intra-refresh config
969    if(!d3d12_video_encoder_update_intra_refresh_h264(pD3D12Enc, srcTextureDesc, h264Pic)) {
970       debug_printf("d3d12_video_encoder_update_intra_refresh_h264 failed!\n");
971       return false;
972    }
973 
974    // Set resolution
975    if ((pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width != srcTextureDesc.Width) ||
976        (pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height != srcTextureDesc.Height)) {
977       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_resolution;
978    }
979    pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width = srcTextureDesc.Width;
980    pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height = srcTextureDesc.Height;
981 
982    // Set resolution codec dimensions (ie. cropping)
983    if (h264Pic->seq.enc_frame_cropping_flag) {
984       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.left = h264Pic->seq.enc_frame_crop_left_offset;
985       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.right = h264Pic->seq.enc_frame_crop_right_offset;
986       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.top = h264Pic->seq.enc_frame_crop_top_offset;
987       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.bottom =
988          h264Pic->seq.enc_frame_crop_bottom_offset;
989    } else {
990       memset(&pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig,
991              0,
992              sizeof(pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig));
993    }
994 
995    // Set profile
996    auto targetProfile = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(pD3D12Enc->base.profile);
997    if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile != targetProfile) {
998       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_profile;
999    }
1000    pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile = targetProfile;
1001 
1002    // Set level
1003    auto targetLevel = d3d12_video_encoder_convert_level_h264(h264Pic->seq.level_idc);
1004    if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting != targetLevel) {
1005       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_level;
1006    }
1007    pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting = targetLevel;
1008 
1009    // Set codec config
1010    bool is_supported = false;
1011    auto targetCodecConfig = d3d12_video_encoder_convert_h264_codec_configuration(pD3D12Enc, h264Pic, is_supported);
1012    if (!is_supported) {
1013       return false;
1014    }
1015 
1016    if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config,
1017               &targetCodecConfig,
1018               sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264)) != 0) {
1019       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec_config;
1020    }
1021    pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config = targetCodecConfig;
1022 
1023    // Set rate control
1024    d3d12_video_encoder_update_current_rate_control_h264(pD3D12Enc, h264Pic);
1025 
1026    // Set slices config
1027    if(!d3d12_video_encoder_negotiate_current_h264_slices_configuration(pD3D12Enc, h264Pic)) {
1028       debug_printf("d3d12_video_encoder_negotiate_current_h264_slices_configuration failed!\n");
1029       return false;
1030    }
1031 
1032    // Set GOP config
1033    if(!d3d12_video_encoder_update_h264_gop_configuration(pD3D12Enc, h264Pic)) {
1034       debug_printf("d3d12_video_encoder_update_h264_gop_configuration failed!\n");
1035       return false;
1036    }
1037 
1038    // m_currentEncodeConfig.m_encoderPicParamsDesc pic params are set in d3d12_video_encoder_reconfigure_encoder_objects
1039    // after re-allocating objects if needed
1040 
1041    // Set motion estimation config
1042    auto targetMotionLimit = d3d12_video_encoder_convert_h264_motion_configuration(pD3D12Enc, h264Pic);
1043    if (pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit != targetMotionLimit) {
1044       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |=
1045          d3d12_video_encoder_config_dirty_flag_motion_precision_limit;
1046    }
1047    pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit = targetMotionLimit;
1048 
1049    ///
1050    /// Check for video encode support detailed capabilities
1051    ///
1052 
1053    // Will call for d3d12 driver support based on the initial requested features, then
1054    // try to fallback if any of them is not supported and return the negotiated d3d12 settings
1055    D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 capEncoderSupportData1 = {};
1056    if (!d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(pD3D12Enc, capEncoderSupportData1)) {
1057       debug_printf("[d3d12_video_encoder_h264] After negotiating caps, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1 "
1058                       "arguments are not supported - "
1059                       "ValidationFlags: 0x%x - SupportFlags: 0x%x\n",
1060                       capEncoderSupportData1.ValidationFlags,
1061                       capEncoderSupportData1.SupportFlags);
1062       return false;
1063    }
1064 
1065    ///
1066    // Calculate current settings based on the returned values from the caps query
1067    //
1068    pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput =
1069       d3d12_video_encoder_calculate_max_slices_count_in_output(
1070          pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
1071          &pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264,
1072          pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber,
1073          pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
1074          pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize);
1075 
1076    //
1077    // Validate caps support returned values against current settings
1078    //
1079    if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile !=
1080        pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_H264Profile) {
1081       debug_printf("[d3d12_video_encoder_h264] Warning: Requested D3D12_VIDEO_ENCODER_PROFILE_H264 by upper layer: %d "
1082                     "mismatches UMD suggested D3D12_VIDEO_ENCODER_PROFILE_H264: %d\n",
1083                     pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile,
1084                     pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_H264Profile);
1085    }
1086 
1087    if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting !=
1088        pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting) {
1089       debug_printf("[d3d12_video_encoder_h264] Warning: Requested D3D12_VIDEO_ENCODER_LEVELS_H264 by upper layer: %d "
1090                     "mismatches UMD suggested D3D12_VIDEO_ENCODER_LEVELS_H264: %d\n",
1091                     pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting,
1092                     pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting);
1093    }
1094 
1095    if (pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput >
1096        pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber) {
1097       debug_printf("[d3d12_video_encoder_h264] Desired number of subregions %d is not supported (higher than max "
1098                       "reported slice number %d in query caps) for current resolution (%d, %d)\n.",
1099                       pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput,
1100                       pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber,
1101                       pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width,
1102                       pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height);
1103       return false;
1104    }
1105    return true;
1106 }
1107 
1108 D3D12_VIDEO_ENCODER_PROFILE_H264
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(enum pipe_video_profile profile)1109 d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(enum pipe_video_profile profile)
1110 {
1111    switch (profile) {
1112       case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
1113       case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
1114       case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
1115       {
1116          return D3D12_VIDEO_ENCODER_PROFILE_H264_MAIN;
1117 
1118       } break;
1119       case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
1120       {
1121          return D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH;
1122       } break;
1123       case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
1124       {
1125          return D3D12_VIDEO_ENCODER_PROFILE_H264_HIGH_10;
1126       } break;
1127       default:
1128       {
1129          unreachable("Unsupported pipe_video_profile");
1130       } break;
1131    }
1132 }
1133 
1134 bool
d3d12_video_encoder_compare_slice_config_h264_hevc(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE targetMode,D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES targetConfig,D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE otherMode,D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES otherConfig)1135 d3d12_video_encoder_compare_slice_config_h264_hevc(
1136    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE targetMode,
1137    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES targetConfig,
1138    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE otherMode,
1139    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES otherConfig)
1140 {
1141    return (targetMode == otherMode) &&
1142           (memcmp(&targetConfig,
1143                   &otherConfig,
1144                   sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES)) == 0);
1145 }
1146 
1147 static inline bool
d3d12_video_encoder_needs_new_pps_h264(struct d3d12_video_encoder * pD3D12Enc,bool writeNewSPS,H264_PPS & tentative_pps,const H264_PPS & active_pps)1148 d3d12_video_encoder_needs_new_pps_h264(struct d3d12_video_encoder *pD3D12Enc,
1149                                        bool writeNewSPS,
1150                                        H264_PPS &tentative_pps,
1151                                        const H264_PPS &active_pps)
1152 {
1153    bool bUseSliceL0L1Override = (pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_H264PicData.Flags &
1154                                  D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_FLAG_REQUEST_NUM_REF_IDX_ACTIVE_OVERRIDE_FLAG_SLICE);
1155 
1156    bool bDifferentL0L1Lists = !bUseSliceL0L1Override &&
1157          ((tentative_pps.num_ref_idx_l0_active_minus1 != active_pps.num_ref_idx_l0_active_minus1) ||
1158          (tentative_pps.num_ref_idx_l1_active_minus1 != active_pps.num_ref_idx_l1_active_minus1));
1159 
1160    bool bDidPPSChange =
1161       ((tentative_pps.constrained_intra_pred_flag != active_pps.constrained_intra_pred_flag) ||
1162        (tentative_pps.entropy_coding_mode_flag != active_pps.entropy_coding_mode_flag) ||
1163        bDifferentL0L1Lists ||
1164        (tentative_pps.pic_order_present_flag != active_pps.pic_order_present_flag) ||
1165        (tentative_pps.pic_parameter_set_id != active_pps.pic_parameter_set_id) ||
1166        (tentative_pps.seq_parameter_set_id != active_pps.seq_parameter_set_id) ||
1167        (tentative_pps.transform_8x8_mode_flag != active_pps.transform_8x8_mode_flag));
1168 
1169    return writeNewSPS || bDidPPSChange;
1170 }
1171 
1172 uint32_t
d3d12_video_encoder_build_codec_headers_h264(struct d3d12_video_encoder * pD3D12Enc,std::vector<uint64_t> & pWrittenCodecUnitsSizes)1173 d3d12_video_encoder_build_codec_headers_h264(struct d3d12_video_encoder *pD3D12Enc,
1174                                              std::vector<uint64_t> &pWrittenCodecUnitsSizes)
1175 {
1176    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams =
1177       d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc);
1178 
1179    auto levelDesc = d3d12_video_encoder_get_current_level_desc(pD3D12Enc);
1180    auto codecConfigDesc = d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc);
1181 
1182    d3d12_video_bitstream_builder_h264 *pH264BitstreamBuilder =
1183       static_cast<d3d12_video_bitstream_builder_h264 *>(pD3D12Enc->m_upBitstreamBuilder.get());
1184    assert(pH264BitstreamBuilder);
1185 
1186    size_t writtenAUDBytesCount = 0;
1187    pWrittenCodecUnitsSizes.clear();
1188 
1189    bool forceWriteAUD = (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_aud_header);
1190    if (forceWriteAUD)
1191    {
1192       pH264BitstreamBuilder->write_aud(pD3D12Enc->m_BitstreamHeadersBuffer,
1193                                        pD3D12Enc->m_BitstreamHeadersBuffer.begin(),
1194                                        writtenAUDBytesCount);
1195       pWrittenCodecUnitsSizes.push_back(writtenAUDBytesCount);
1196    }
1197 
1198    bool isFirstFrame = (pD3D12Enc->m_fenceValue == 1);
1199    bool forceWriteSPS = (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_sequence_header);
1200    bool writeNewSPS = isFirstFrame                                         // on first frame
1201                       || ((pD3D12Enc->m_currentEncodeConfig.m_seqFlags &   // also on resolution change
1202                            D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_RESOLUTION_CHANGE) != 0)
1203                       || forceWriteSPS;
1204 
1205    uint32_t active_seq_parameter_set_id = pH264BitstreamBuilder->get_active_sps().seq_parameter_set_id;
1206 
1207    size_t writtenSEIBytesCount = 0;
1208    bool forceWriteSEI = (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_sei_header);
1209    // We only support H264_SEI_SCALABILITY_INFO, so check num_temporal_layers > 1
1210    if (forceWriteSEI &&
1211       (pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH264.num_temporal_layers > 1))
1212    {
1213       std::vector<H264_SEI_MESSAGE> sei_messages;
1214       H264_SEI_MESSAGE scalability_info_sei = { };
1215       memset(&scalability_info_sei, 0, sizeof(scalability_info_sei));
1216       scalability_info_sei.payload_type = H264_SEI_SCALABILITY_INFO;
1217       scalability_info_sei.scalability_info.num_layers_minus1 = pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH264.num_temporal_layers - 1;
1218       // Only support Identity temporal_id for now
1219       for (uint32_t i = 0; i <= scalability_info_sei.scalability_info.num_layers_minus1; i++)
1220          scalability_info_sei.scalability_info.temporal_id[i] = i;
1221 
1222       sei_messages.push_back(scalability_info_sei);
1223       pH264BitstreamBuilder->write_sei_messages(sei_messages,
1224                                                 pD3D12Enc->m_BitstreamHeadersBuffer,
1225                                                 pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenAUDBytesCount,
1226                                                 writtenSEIBytesCount);
1227       pWrittenCodecUnitsSizes.push_back(writtenSEIBytesCount);
1228    }
1229 
1230    size_t writtenSPSBytesCount = 0;
1231    if (writeNewSPS) {
1232       H264_SPS sps = pH264BitstreamBuilder->build_sps(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificSequenceStateDescH264,
1233                                                       pD3D12Enc->base.profile,
1234                                                       *levelDesc.pH264LevelSetting,
1235                                                       pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
1236                                                       *codecConfigDesc.pH264Config,
1237                                                       pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures,
1238                                                       active_seq_parameter_set_id,
1239                                                       pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
1240                                                       pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig,
1241                                                       pD3D12Enc->m_BitstreamHeadersBuffer,
1242                                                       pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenAUDBytesCount + writtenSEIBytesCount,
1243                                                       writtenSPSBytesCount);
1244       pH264BitstreamBuilder->set_active_sps(sps);
1245       pWrittenCodecUnitsSizes.push_back(writtenSPSBytesCount);
1246    }
1247 
1248    size_t writtenPPSBytesCount = 0;
1249    H264_PPS tentative_pps = pH264BitstreamBuilder->build_pps(pD3D12Enc->base.profile,
1250                                                              *codecConfigDesc.pH264Config,
1251                                                              *currentPicParams.pH264PicData,
1252                                                              currentPicParams.pH264PicData->pic_parameter_set_id,
1253                                                              active_seq_parameter_set_id,
1254                                                              pD3D12Enc->m_StagingHeadersBuffer,
1255                                                              pD3D12Enc->m_StagingHeadersBuffer.begin(),
1256                                                              writtenPPSBytesCount);
1257 
1258    const H264_PPS &active_pps = pH264BitstreamBuilder->get_active_pps();
1259    bool forceWritePPS = (pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_picture_header);
1260    if (forceWritePPS || d3d12_video_encoder_needs_new_pps_h264(pD3D12Enc, writeNewSPS, tentative_pps, active_pps)) {
1261       pH264BitstreamBuilder->set_active_pps(tentative_pps);
1262       pD3D12Enc->m_BitstreamHeadersBuffer.resize(writtenAUDBytesCount + writtenSEIBytesCount + writtenSPSBytesCount + writtenPPSBytesCount);
1263       memcpy(&pD3D12Enc->m_BitstreamHeadersBuffer.data()[writtenAUDBytesCount + writtenSEIBytesCount + writtenSPSBytesCount], pD3D12Enc->m_StagingHeadersBuffer.data(), writtenPPSBytesCount);
1264       pWrittenCodecUnitsSizes.push_back(writtenPPSBytesCount);
1265    } else {
1266       writtenPPSBytesCount = 0;
1267       debug_printf("Skipping PPS (same as active PPS) for fenceValue: %" PRIu64 "\n", pD3D12Enc->m_fenceValue);
1268    }
1269 
1270    // Shrink buffer to fit the headers
1271    if (pD3D12Enc->m_BitstreamHeadersBuffer.size() > (writtenAUDBytesCount + writtenSEIBytesCount + writtenSPSBytesCount + writtenPPSBytesCount)) {
1272       pD3D12Enc->m_BitstreamHeadersBuffer.resize(writtenAUDBytesCount + writtenSEIBytesCount + writtenSPSBytesCount + writtenPPSBytesCount);
1273    }
1274 
1275    assert(std::accumulate(pWrittenCodecUnitsSizes.begin(), pWrittenCodecUnitsSizes.end(), 0ull) ==
1276       pD3D12Enc->m_BitstreamHeadersBuffer.size());
1277    return static_cast<uint32_t>(pD3D12Enc->m_BitstreamHeadersBuffer.size());
1278 }
1279 
1280 uint32_t
d3d12_video_encoder_build_slice_svc_prefix_nalu_h264(struct d3d12_video_encoder * pD3D12Enc,EncodedBitstreamResolvedMetadata & associatedMetadata,std::vector<uint8_t> & headerBitstream,std::vector<uint8_t>::iterator placingPositionStart,size_t & writtenSVCPrefixNalBytes)1281 d3d12_video_encoder_build_slice_svc_prefix_nalu_h264(struct d3d12_video_encoder *   pD3D12Enc,
1282                                                      EncodedBitstreamResolvedMetadata& associatedMetadata,
1283                                                      std::vector<uint8_t> &         headerBitstream,
1284                                                      std::vector<uint8_t>::iterator placingPositionStart,
1285                                                      size_t &                       writtenSVCPrefixNalBytes)
1286 {
1287    d3d12_video_bitstream_builder_h264 *pH264BitstreamBuilder =
1288       static_cast<d3d12_video_bitstream_builder_h264 *>(pD3D12Enc->m_upBitstreamBuilder.get());
1289    assert(pH264BitstreamBuilder);
1290 
1291    H264_SLICE_PREFIX_SVC nal_svc_prefix = {};
1292    memset(&nal_svc_prefix, 0, sizeof(nal_svc_prefix));
1293    nal_svc_prefix.idr_flag = (associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_H264PicData.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME) ? 1 : 0;
1294    nal_svc_prefix.no_inter_layer_pred_flag = 1;
1295    nal_svc_prefix.output_flag = 1;
1296    nal_svc_prefix.discardable_flag = 1;
1297    nal_svc_prefix.temporal_id = associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_H264PicData.TemporalLayerIndex;
1298    nal_svc_prefix.priority_id = nal_svc_prefix.temporal_id;
1299    nal_svc_prefix.nal_ref_idc = associatedMetadata.m_associatedEncodeConfig.m_bUsedAsReference ? NAL_REFIDC_REF : NAL_REFIDC_NONREF;
1300    pH264BitstreamBuilder->write_slice_svc_prefix(nal_svc_prefix,
1301                                                  headerBitstream,
1302                                                  placingPositionStart,
1303                                                  writtenSVCPrefixNalBytes);
1304 
1305    // Shrink buffer to fit the headers
1306    if (headerBitstream.size() > (writtenSVCPrefixNalBytes)) {
1307       headerBitstream.resize(writtenSVCPrefixNalBytes);
1308    }
1309 
1310    return static_cast<uint32_t>(headerBitstream.size());
1311 }
1312