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