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