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